/*	$NetBSD: h_execregs.S,v 1.2 2025/02/28 16:08:19 riastradh Exp $	*/

/*-
 * Copyright (c) 2025 The NetBSD Foundation, Inc.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

#define	_LOCORE

#include <sys/syscall.h>

#include <machine/asm.h>
#include <machine/vmparam.h>

#include "execregs.h"

_ENTRY(execregs_start)
	.callinfo frame=(NEXECREGS*4), calls
	.entry

	ldo	(NEXECREGS*4)(%sp), %sp		/* space for NEXECREGS */
	stw	%t1, (4*(0 - NEXECREGS))(%sp)	/* order matches execregs.h */
	stw	%t2, (4*(1 - NEXECREGS))(%sp)
	/* sp: stack pointer */
	stw	%t3, (4*(2 - NEXECREGS))(%sp)
	/* cr17/iisq_head: privileged */
	/* cr17/iisq_tail: privileged */
	/* cr18/iioq_head: privileged */
	/* cr18/iioq_tail: privileged */
	/* cr15/eiem: privileged */
	/* cr22/ipsw: privileged */
	/* sr3: privileged(?) */
	/* cr8/pidr1: privileged */
	/* cr20/isr: privileged */
	/* cr21/ior: privileged */
	/* cr19/iir: privileged */
	/* flags: N/A(?) */
	stw	%sar, (4*(3 - NEXECREGS))(%sp)
	stw	%r1, (4*(4 - NEXECREGS))(%sp)
	stw	%rp, (4*(5 - NEXECREGS))(%sp)
	/* r3: frame pointer (set to initial stack pointer) */
	stw	%r4, (4*(6 - NEXECREGS))(%sp)
	stw	%r5, (4*(7 - NEXECREGS))(%sp)
	stw	%r6, (4*(8 - NEXECREGS))(%sp)
	stw	%r7, (4*(9 - NEXECREGS))(%sp)
	stw	%r8, (4*(10 - NEXECREGS))(%sp)
	stw	%r9, (4*(11 - NEXECREGS))(%sp)
	stw	%r10, (4*(12 - NEXECREGS))(%sp)
	stw	%r11, (4*(13 - NEXECREGS))(%sp)
	stw	%r12, (4*(14 - NEXECREGS))(%sp)
	stw	%r13, (4*(15 - NEXECREGS))(%sp)
	stw	%r14, (4*(16 - NEXECREGS))(%sp)
	stw	%r15, (4*(17 - NEXECREGS))(%sp)
	stw	%r16, (4*(18 - NEXECREGS))(%sp)
	stw	%r17, (4*(19 - NEXECREGS))(%sp)
	stw	%r18, (4*(20 - NEXECREGS))(%sp)
	stw	%t4, (4*(21 - NEXECREGS))(%sp)
	stw	%arg3, (4*(22 - NEXECREGS))(%sp)
	stw	%arg2, (4*(23 - NEXECREGS))(%sp)
	stw	%arg1, (4*(24 - NEXECREGS))(%sp)
	/* arg0: ps_strings */
	stw	%dp, (4*(25 - NEXECREGS))(%sp)
	stw	%ret0, (4*(26 - NEXECREGS))(%sp)
	stw	%ret1, (4*(27 - NEXECREGS))(%sp)
	stw	%r31, (4*(28 - NEXECREGS))(%sp)
	/* sr0-sr7: space registers initialized by kernel */
	/* cr9/pidr2: privileged */
	/* cr12/pidr3: privileged */
	/* cr13/pidr4: privileged */
	/* cr0/rctr: privileged */
	/* cr10/ccr: privileged */
	/* cr23/eirr: privileged */
	/* cr24: privileged */
	/* cr25/vtop: privileged */
	/* cr26: ??? */
	stw	%cr27, (4*(29 - NEXECREGS))(%sp)
	stw	%cr28, (4*(30 - NEXECREGS))(%sp)
	/* cr30/fpregs: privileged */
	/* cr31: privileged */

	addc	%t1, %r0, %r0	/* t1 := PSW[C/B]{0} */
	zdep	%t1, 23, 8, %t1	/* t1 := PSW */
	stw	%t1, (4*(31 - NEXECREGS))(%sp)

	/* store the fp registers */
	ldo	(4*(32 - NEXECREGS))(%sp), %t1
	fstd,ma	%fr0, 8(%t1)
	fstd,ma	%fr1, 8(%t1)
	fstd,ma	%fr2, 8(%t1)
	fstd,ma	%fr3, 8(%t1)
	fstd,ma	%fr4, 8(%t1)
	fstd,ma	%fr5, 8(%t1)
	fstd,ma	%fr6, 8(%t1)
	fstd,ma	%fr7, 8(%t1)
	fstd,ma	%fr8, 8(%t1)
	fstd,ma	%fr9, 8(%t1)
	fstd,ma	%fr10, 8(%t1)
	fstd,ma	%fr11, 8(%t1)
	fstd,ma	%fr12, 8(%t1)
	fstd,ma	%fr13, 8(%t1)
	fstd,ma	%fr14, 8(%t1)
	fstd,ma	%fr15, 8(%t1)
	fstd,ma	%fr16, 8(%t1)
	fstd,ma	%fr17, 8(%t1)
	fstd,ma	%fr18, 8(%t1)
	fstd,ma	%fr19, 8(%t1)
	fstd,ma	%fr20, 8(%t1)
	fstd,ma	%fr21, 8(%t1)
	fstd,ma	%fr22, 8(%t1)
	fstd,ma	%fr23, 8(%t1)
	fstd,ma	%fr24, 8(%t1)
	fstd,ma	%fr25, 8(%t1)
	fstd,ma	%fr26, 8(%t1)
	fstd,ma	%fr27, 8(%t1)
	fstd,ma	%fr28, 8(%t1)
	fstd,ma	%fr29, 8(%t1)
	fstd,ma	%fr30, 8(%t1)
	fstd	%fr31, 0(%t1)

	/* call write(STDOUT_FILENO, regs, sizeof(regs)) */
	ldi	1, %arg0			/* arg0 := STDOUT_FILENO */
	ldo	-(4*NEXECREGS)(%sp), %arg1	/* arg1 := regs */
	ldi	(4*NEXECREGS), %arg2		/* arg2 := sizeof(regs) */
	ldil	L%SYSCALLGATE, %r1
	ble	4(%sr2, %r1)
	 ldi	SYS_write, %t1

	comb,<>,n	%r0, %t1, 2f		/* bail if write failed */
	ldi		(4*NEXECREGS), %t1	/* bail if wrong # bytes */
	comb,<>,n	%ret0, %t1, 2f

	/* call exit(0) */
	ldi	0, %arg0
1:	ldil	L%SYSCALLGATE, %r1
	ble	4(%sr2, %r1)
	 ldi	SYS_exit, %t1
	break	0, 0				/* paranoia */

2:	/* call exit(127) */
	b	1b
	 ldi	127, %arg0
EXIT(execregs_start)

/* main stub to simplify linking */
LEAF_ENTRY(main)
	break	0, 0				/* paranoia */
EXIT(main)