/* --- Copyright University of Sussex 1995. All rights reserved. ----------
 * File:	C.hppa/src/asignals.s
 * Purpose:	Signal handler for HP PA-RISC 1.1
 * Author:	Julian Clinton, December 1992 (see revisions)
 */


#_<

#_INCLUDE 'declare.ph'

section $-Sys;

constant procedure (
	Error_signal,
);

vars
	Extern$- _saved_sp,
;

endsection;

lconstant macro (
	_SAVED_SP	= [_SVB_OFFS(Sys$-Extern$- _saved_sp)],
	_SAVED_USP	= [_SVB_OFFS(Sys$-Extern$- _saved_usp)],
);

>_#

#_INCLUDE 'asm_macros.h'


/************************* wrapping structures ************************/

	.code
	.word	Lcode_end-Lcode_start, C_LAB(Sys$-objmod_pad_key)
Lcode_start
	.data
	.word	Ldata_end-Ldata_start, C_LAB(Sys$-objmod_pad_key)
Ldata_start

/**********************************************************************/


	.code

;;; -- CLEAN-UP ROUTINES --------------------------------------------------

;;; RESET_POP_ENVIRON:
;;;	Restore a safe environment for Poplog

;;; Registers used:
;;;	%t1	saved value of return address %r31
;;;	%t2	scratch

reset_pop_environ

	;;; Save return address
	copy		%r31, %t1

	;;; Restore environment
	STV32		0, __pop_in_user_extern		;;; just in case
	bl		reset_pop_reg_environ, %r31	;;; reset registers
	nop
	ldw		_SVB_OFFS(_userhi)(%svb), %usp	;;; clear user stack
	STV32		0, __pop_fpe_handler		;;; clear FPE handler
	ldw		_SAVED_SP(%svb), %t2		;;; get saved stack pointer

	;;; If saved stack pointer is non-zero, we're in an external call
	comb,=,n	0, %t2, L$1		;;; branch if zero
	copy		%t2, %sp
	stw		0, _SAVED_SP(%svb)	;;; zero saved stack pointer
	ldw		-4(%sp), %pb		;;; restore procedure base

L$1	bv		0(%t1)			;;; local return
	nop


;;; __POP_ERRSIG:
;;;	called by _pop_errsig_handler from "c_core.c" on receipt of any
;;;	serious error signal (i.e. not user trappable). Resets the Pop
;;;	register environment and calls Error_signal to clean up the stack.
;;;
;;; Prototype:
;;;	void __pop_errsig(unsigned _sp)
;;;
;;; Argument:
;;;	%arg0	(_sp) the stack pointer from the sigcontext structure
;;;             passed to _pop_errsig_handler: resetting %sp to this
;;;             value clears any signal handler stack frames before
;;;             control reaches Error_signal, so that %sp should point
;;;             to a Pop stack frame. NB: reset_pop_environ may further
;;;             reduce the stack if we're in an external call.

	.export		EXTERN_NAME(__pop_errsig), code
EXTERN_NAME(__pop_errsig)

	bl		reset_pop_environ, %r31
	copy		%arg0, %sp
	CHAINSYS	XC_LAB(Sys$-Error_signal)	;;; never returns
	nop


;;; -- SYSTEM CALL INTERFACE ----------------------------------------------

;;; _CALL_SYS:
;;;     Make a system call, transferring arguments from the user stack
;;;     to the system stack. The function argument is a PLABEL called
;;;     with $$dyncall. For system use only.

;;; Call:
;;;	_call_sys(_NARGS, _FNC_ADDR) -> _RES

;;; Register usage:
;;;	%t1	plabel of function
;;;	%t2	(1) argument count
;;;		(2) loop counter
;;;	%t3	address of instruction to load the last argument
;;;	%t4	(1) argument count in bytes (%t1 * 4)
;;;		(2) current argument (in loop)
;;;		(3) value of errno after calling the routine

;;; Memory usage:
;;;	_SAVED_SP
;;;		global variable which holds a pointer to the stack frame
;;;		of the calling procedure; used by _SIGNAL_HANDLER above.

DEF_C_LAB (_call_sys)

	;;; Save pointer to caller's stack frame in case of interrupts

	stw		%sp, _SAVED_SP(%svb)

	;;; Load routine address to %t1 and argument count to %t2

	ldwm		4(%usp), %t1
	ldwm		4(%usp), %t2

	;;; Argument load differs depending on whether the argument count
	;;; is greater or less than 4

	comib,<		4, %t2, L_args_n
	stwm		%r31, 4(%sp)

	;;; 4 or fewer arguments:
	;;; allocate the stack frame: 12 words, aligned on a 64-byte
	;;; boundary

	;;; Pop arguments to registers:
	;;; this is a switch on the argument count

	blr		%t2, 0
	ldo		63+12*4(%sp), %sp
	b		L_args_0
	dep		0, 31, 6, %sp
	b		L_args_1
	dep		0, 31, 6, %sp
	b		L_args_2
	dep		0, 31, 6, %sp
	b		L_args_3
	dep		0, 31, 6, %sp
	b		L_args_4
	dep		0, 31, 6, %sp

L_args_n

	;;; More than 4 arguments:
	;;; allocate (8 + N_ARGS) words for the stack frame, aligned on a
	;;; 64-byte boundary

	ldo		63+8*4(%sp), %sp
	sh2add		%t2, %sp, %sp
	dep		0, 31, 6, %sp

	;;; Compute a pointer to the low word of the argument save area

	ldo		-8*4(%sp), %t3
	sh2add		%t2, 0, %t4
	sub		%t3, %t4, %t3

	;;; Copy trailing arguments to the call stack

L_copy_args
	ldwm		4(%usp), %t4
	addi		-1, %t2, %t2
	comib,<		4, %t2, L_copy_args
	stwm		%t4, 4(%t3)

	;;; First four arguments go in registers

L_args_4
	ldwm		4(%usp), %arg3
L_args_3
	ldwm		4(%usp), %arg2
L_args_2
	ldwm		4(%usp), %arg1
L_args_1
	ldwm		4(%usp), %arg0
L_args_0

	;;; Make the call:
	;;; the target is a PLABEL called with $$dyncall. That expects its
	;;; argument in %t1 and its return address in %r31; we also copy
	;;; the return address to %rp for the routine itself.

	bl		$$dyncall, %r31
	copy		%r31, %rp

	;;; Push result and return, restoring the saved stack pointer
	stwm		%ret0, -4(%usp)
	ldw		_SAVED_SP(%svb), %t2
	stw		0, _SAVED_SP(%svb)
	ldw		(%t2), %r31
	RETE
	copy		%t2, %sp



;;; --- C-ACCESSIBLE VARIABLES, ETC ------------------------------------

	.data

	.export		__pop_fpe_handler, data
__pop_fpe_handler
	.word		0


	.code
	.import		C_LAB(Sys$-objmod_pad_key), data
	.import		XC_LAB(Sys$-Error_signal), data
	.import		EXTERN_NAME(errno:data), data
	.import		__pop_in_user_extern, data
	.import		reset_pop_reg_environ, code
	.import		$$dyncall, millicode


/***************** end labels for wrapping structures *****************/

	.code
	.align  8
Lcode_end
	.data
	.align  8
Ldata_end

/**********************************************************************/


/* --- Revision History ---------------------------------------------------
--- John Gibson, Mar 14 1995
	Removed _pop_m*alloc_exhausted (no longer needed)
--- John Gibson, Oct 25 1994
	Removed the C pointers to pop vars (now set up in initial.p)
--- Robert John Duncan, May 24 1994
	No longer needs to set _sys*error
 */
