/* --- Copyright University of Sussex 1995. All rights reserved. ----------
 * File:            C.mips/src/asignals.s
 * Purpose:         Signal handler for MIPS
 * Author:          Rob Duncan, Feb 12 1990 (see revisions)
 */


#_<

#_INCLUDE 'declare.ph'

section $-Sys;

constant procedure (
	Callstack_reset,
	Error_signal,
	Vfork_parent,
);

vars
	Extern$- _saved_sp,
;

endsection;

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

>_#

#_INCLUDE 'pop_regdef.h'


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

	.data
	.word	Ldata_size
	.word	C_LAB(Sys$-objmod_pad_key)
Ldata_start:

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


	.text

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

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

	.ent	reset_pop_environ
reset_pop_environ:

	;;; Save return address

	move	cr, ra

	;;; Restore environment

	sw	zero, EXTERN_NAME(__pop_in_user_extern)	;;; just in case
	jal	reset_pop_reg_environ			;;; reset registers
	lw	usp, _SVB_OFFS(_userhi)(svb)		;;; clear user stack

	;;; If saved stack pointer is non-zero, we're in an external call

	lw	t0, _SAVED_SP
	beqz	t0, 1f
	move	sp, t0				;;; reset stack pointer
	sw	zero, _SAVED_SP			;;; zero saved stack pointer
	lw	pb, (sp)			;;; restore procedure base

1:	j	cr				;;; return

	.end	reset_pop_environ


;;; __POP_ERRSIG:
;;;     Chained after error signals (e.g SEGV). The entry is
;;;     non-standard and the call register (t9) is unlikely to be
;;;     properly set up, so we have to set the context pointer
;;;     explicitly with a local branch and link.

	.globl	EXTERN_NAME(__pop_errsig)
	.ent	EXTERN_NAME(__pop_errsig)
EXTERN_NAME(__pop_errsig):
	.set	noreorder
	bal	1f
	nop
1:	CPLOAD	ra
	.set	reorder

	bal	reset_pop_environ
	jal	XC_LAB(Sys$-Error_signal)	;;; never returns

	.end	EXTERN_NAME(__pop_errsig)


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

;;; _CALL_SYS:
;;;     Make a system call, transferring arguments from the user stack
;;;     to the system stack. For system use only.

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

;;; Register usage:
;;;	t0	(1) argument count
;;;		(2) loop counter
;;;	t1	(1) argument count in bytes (t0 * 4)
;;; 		(2) argument copy pointer
;;;	t2	work
;;;	t9	function address
;;; 	np0	frame pointer

;;; Memory usage:
;;;	_SAVED_SP
;;;             a pointer to the stack frame of the calling (pop)
;;;             procedure

DEF_C_LAB (_call_sys)

	.ent	$call_sys
$call_sys:
	.set	noreorder
	CPLOAD	t9
	.set	reorder

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

	sw	sp, _SAVED_SP

	;;; Create a stack frame containing
	;;; 	return address
	;;; 	context pointer
	;;; 	special var block (caller-save register)
	;;; 	non-pop reg 0
	;;; plus an initial 4-word argument build area. This will be expanded
	;;; dynamically according to the number of arguments passed, so we
	;;; use np0 as a static frame pointer.

	.frame	np0, 32, ra
	.mask	0x91040000, -4
	subu	sp, 32
	sw	ra, 28(sp)
	sw	gp, 24(sp)
	sw	svb, 20(sp)
	sw	np0, 16(sp)
	move	np0, sp

	lw	t0, 4(usp)		;;; argument count
	sll	t1, t0, 2		;;; ... in bytes
	lw	t9, (usp)		;;; function address
	addu	usp, 8

	;;; If there are more than four arguments, branch to copy loop

	bgtu	t0, 4, 1f

	;;; Otherwise, the 4-word argument build area will be
	;;; sufficient. Copy arguments to registers and make the call by
	;;; switching on the argument count.

	addu	usp, t1			;;; clear arguments from user stack
	lw	t2, switch(t1)
	j	t2

1:	;;; More than four arguments: add an extra amount to the
	;;; stack frame and make it double-word aligned

	subu	sp, t1
	and	sp, ~7

	;;; Copy excess arguments from user stack to call stack

	addu	t1, sp
2:	lw	t2, (usp)
	addu	usp, 4
	subu	t1, 4
	sw	t2, (t1)
	subu	t0, 1
	bne	t0, 4, 2b

	;;; Copy last four arguments and make the call

	addu	usp, 16			;;; clear arguments from user stack

	.set	noreorder
$$4:	lw	a3, -16(usp)
$$3:	lw	a2, -12(usp)
$$2:	lw	a1,  -8(usp)
$$1:	lw	a0,  -4(usp)
$$0:	jal	t9
	nop
	.set	reorder

	move	sp, np0			;;; restore stack pointer
	lw	svb, 20(sp)		;;; restore special var block
	lw	gp, 24(sp) 		;;; restore context pointer

	;;; Push result from v0

	subu	usp, 4
	sw	v0, (usp)

	;;; Unwind stack frame and return

	lw	np0, 16(sp)
	lw	ra, 28(sp)
	addu	sp, 32
	sw	zero, _SAVED_SP		;;; no longer in external call
	j	ra

	.end	$call_sys

	.rdata
switch: ;;; jump table for 0-4 arguments
	.word	$$0
	.word	$$1
	.word	$$2
	.word	$$3
	.word	$$4
	.text


#_IF DEF BSD_VFORK and not(DEF PIC)

;;; _DO_VFORK:
;;;	Make VFORK system call

DEF_C_LAB(Sys$- _do_vfork)

	.ent	$do_vfork
$do_vfork:

	;;; Create stack frame

	.frame	sp, 8, ra
	.mask	0x81000000, -4
	subu	sp, 8
	sw	ra, 4(sp)
	sw	svb, 0(sp)

	;;; Do the system call

	jal	vfork
	bgtz	v0, 1f

	;;; Child or fail: return result from v0

	sw	v0, -4(usp)
	subu	usp, 4
	lw	svb, 0(sp)
	lw	ra, 4(sp)
	addu	sp, 8
	j	ra

1:	;;; Parent: chain -Vfork_parent- with child PID as argument

	la	svb, C_LAB(_special_var_block)	;;; can't trust the stack
	sw	zero, _SAVED_SP		;;; in case child in extern call
	sw	v0, -4(usp)
	la	t0, C_LAB(weakref Sys$-Vfork_parent)
	sw	t0, -8(usp)
	subu	usp, 8
	la	t9, XC_LAB(Sys$-Callstack_reset)
	j	t9

	.end	$do_vfork

#_ENDIF	;;; DEF BSD_VFORK and not(DEF PIC)


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

	.data
Ldata_end:
Ldata_size = 0 ##PATCH## Ldata_size Ldata_end Ldata_start

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


/* --- Revision History ---------------------------------------------------
--- John Gibson, Mar 14 1995
	Removed _pop_m*alloc_exhausted (no longer needed)
--- Robert John Duncan, Nov  2 1994
	Removed __pop_f*pe_handler (never used)
--- 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 has to set _sys*error
--- Robert John Duncan, Mar 22 1994
	Moved jump table for call_sys into the rdata section, because it
	simply doesn't work otherwise.
	Removed procedure assignments to a0 (again).
	Changed external jumps to go off t9.
--- Robert John Duncan, Mar 15 1994
	Removed the wrapping structure from the text section
--- Robert John Duncan, Mar 15 1994
	Pop calls must now set a0 to the procedure address
--- Robert John Duncan, Mar 11 1994
	Added save/restore of special var block in do_vfork and disabled it
	completely for position-independent code (too much bother getting
	the context pointer back). Made further corrections to stack frame
	size and alignment in call_sys and changed the way the jump table
	is organised.
--- Robert John Duncan, Mar 10 1994
	Made position-indpendent.
--- Robert John Duncan, Mar  8 1994
	Added .ent/.end directives
--- Robert John Duncan, Mar  7 1994
	Changed to use register $t9 for external call only.
--- Robert John Duncan, Jun 16 1993
	Removed .extern declaration for __pop_in_user_extern because the
	defining file "c_core.c" is now liable to be compiled -G 0.
--- Robert John Duncan, Jun 23 1992
	_do_vfork now conditional on definition of BSD_VFORK
--- Robert John Duncan, Nov 29 1991
	Removed reference to -vfork- for IRIX, which no longer supports it
--- John Gibson, Mar 14 1991
	Added __pop_in_X_call
--- Robert John Duncan, Jan 29 1991
	Actual signal handlers rewritten in C and moved to c_core.c (this
	file now contains only routines gone to on return from a signal).
	Added clearing of __pop_in_user_extern in reset_pop_environ.
	__pop_f*pe_handler now declared here
--- Robert John Duncan, Dec  4 1990
	Replaced _pop_a*dd_sig with _pop_add_ast taking ast type as 1st arg
--- Robert John Duncan, Nov 23 1990
	Moved _pop_xt_dummy_fd into the .sdata section;
	deleted local data for signal queue (no longer used).
--- Roger Evans, Nov 22 1990
	Added _pop_xt_dummy_fd
--- John Gibson, Nov 19 1990
	Grouped all C-accessible pointers and added
	__WEAK_pop_external_callback etc
--- Robert John Duncan, Nov 13 1990
	Replaced _m*alloc_use_external by _external_flags and
	_pop_malloc_use_external by pop_external_flags, etc.
--- Simon Nichols, Aug 29 1990
	Signal queue routines rewritten in C and put into malloc.c.
	These access the pop variable _trap via the constant pointer
	_pop_signals_pending.
--- Robert John Duncan, Jul  4 1990
	Added extern declarations for special vars
 */
