|
| syscall: interface for system calls. The following entry points are
|    defined:
| _mint_bios:  entry point for the BIOS calls (trap #13)
| _mint_xbios: entry point for XBIOS calls (trap #14)
| _mint_dos:   entry point for GEMDOS calls (trap #1)
| _sig_return: user signal handlers return to this routine (see signal.c)
|              it is responsible for restoring the kernel's old context
|              via the Psigreturn() system call
| _lineA0:     calls the line A initialize routine
| _call_aes:   calls the GEM AES
| _callout:    call an external function, after first making sure that all
|              registers are saved
|
| external variables referenced:
| _bios_tab, _bios_max:
|    table of entry points for BIOS routines, max # of routine
| _xbios_tab, _xbios_max:
|    ditto for XBIOS
| _dos_tab, _dos_max:
|    ditto for GEMDOS
| _curproc:
|    pointer to current process table entry, and hence to save area for
|    context (this is always the first entry in the PROC table).
| _valid_return:
|    used to indicate to the kernel that a valid return from user mode
|    is taking place
|
| _bconbuf, _bconbsiz, _bconbdev:
|    256 byte buffer for Bconout() output. If _bconbsiz is non-zero,
|    there are that many bytes in _bconbuf waiting to be flushed. The
|    output is for device _bconbdev.
|
| The C function enter_kernel() is called on entry to the kernel, and the
| function leave_kernel() is called on exit. These functions are responsible
| for saving and restoring the various trap vectors, so that MiNT can trap
| out to TOS directly, but programs can only trap to MiNT.
|
	.globl  _mint_bios, _mint_xbios
	.globl	_mint_dos
	.globl	_build_context
	.globl	_restore_context

	.globl	_curproc
	.globl	_bios_tab, _bios_max
	.globl  _xbios_tab, _xbios_max
	.globl	_dos_tab, _dos_max
	.globl	_bconbuf, _bconbsiz, _bconbdev
	.globl	_bflush

	.data
	.comm	syscall_tab, 4		| set to which table to use for the call
	.comm	syscall_max, 4		| maximum valid number for this call

	.text
	.even

_mint_dos:
	movel	#_dos_tab, syscall_tab
	movew	_dos_max, syscall_max
	bra	_syscall

_mint_xbios:
	movel	#_xbios_tab, syscall_tab
	movew	_xbios_max, syscall_max
	bra	_syscall

_mint_bios:
|
| Bconout() is noticeably slower under MiNT, so we do a bit of a kludge
| and special case Bconout() so that it doesn't take so long. We
| do this by buffering Bconout calls until either another kind of
| system call or a context switch happens.
|
	tstw	_bconbdev		| buffering on?
	bmi	L_bios			| if bconbdev < 0, no buffering
	btst	#13, sp@		| test for user/super mode
	beq	L_usr			| 
	lea	sp@(6), a1		| supervisor mode: args on stack
	tstw	0x59e			| test longframe
	beq	L_check
	addql	#2, a1			| stack is a bit bigger
	bra	L_check
L_usr:
	movel	usp, a1			| user mode: args on user stack
L_check:
	movew	a1@, d0			| check command
	cmpw	#3, d0			| Bconout?
	beq	do_bconout		| yes -- take some shortcuts
					| no -- fall through to the normal code
L_bios:
	movel	#_bios_tab, syscall_tab
	movew	_bios_max, syscall_max

_syscall:
	movel	_curproc, d0
	addql	#4, d0
	movel	d0, sp@-		| push pointer to syscall context save
	jsr	_build_context
|
| copy parameters onto process stack. a1 was set by _build_context
|
L_copy:
	movel	_curproc, a0
	movel	a0@, a0			| fetch system call stack pointer
	lea	a0@(-28), sp		| this puts us in our private stack
	moveml	a1@, d1-d7		| copy parameters from user stack
	moveml	d1-d7, sp@		| to ours (build_context set a1)
|
	jsr	_enter_kernel		| set up vectors appropriately
|
| check here to see if we need to flush the Bconout() buffers
|
	tstw	_bconbsiz		| characters in buffer?
	beq	L_noflush		| nope: OK to proceed
|
| make sure we save syscall_tab and syscall_max
|
	movel	syscall_tab, sp@-
	movew	syscall_max, sp@-
	jsr	_bflush			| flush the buffer
	movew	sp@+, syscall_max
	movel	sp@+, syscall_tab

L_noflush:
|
| figure out which routine to call
|
	clrl	d0
	movew	sp@, d0
	cmpw	#-1, d0			| trapping with -1 means return
	bne	check_max		| the corresponding system table
	movel	syscall_tab, d0
	bra	out
check_max:
	cmpw	syscall_max, d0
	bge	error
	addl	d0,d0
	addl	d0,d0			| multiply by 4
	movel	syscall_tab, a0
	addl	d0, a0
	movel	a0@, a0
	cmpl	#0, a0			| null entry means invalid call
	beq	error
	addql	#2, sp			| pop function number off stack
	jsr	a0@			| go do the call
out:
	movel	_curproc, a0
	movel	d0, a0@(4)		| set d0 in the saved context
	tstw	_proc_clock		| has process exceeded time slice?
	bne	nosleep			| no -- continue
	movew	a0@(68), d0		| get saved status register
	btst	#13, d0			| caller in supervisor mode?
	bne	nosleep			| yes -- don't interrupt
sleep:
	jsr	_preempt		| does a sleep(READY_Q)
nosleep:
	oriw	#0x0700, sr		| spl7()
	jsr	_leave_kernel		| restore vectors
	movel	_curproc, a0
	pea	a0@(4)
	jsr	_restore_context	| never returns

|
| we handle errors by calling through to GEMDOS or the BIOS/XBIOS,
| as appropriate, and letting them handle it -- that way, if the underlying
| system has functions we don't know about, they still work
|

error:
	movel	syscall_tab, a0
	cmpl	#_xbios_tab, a0
	bne	maybe_dos
	trap	#14
	bra	out
maybe_dos:
	cmpl	#_dos_tab, a0
	beq	trap_1
	trap	#13
	bra	out
trap_1:
	trap	#1
	bra	out

|
| sig_return: user signal handlers return to us. At that point, the
| stack looks like this:
|    (sp)      (long) signal number -- was a parameter for user routine
|
	.globl	_sig_return
	.globl	_valid_return
_sig_return:
	addql	#4, sp			| pop signal number
	movew	#0x11a, sp@-		| Psigreturn() system call
	movew	#1, _valid_return	| tell kernel it's us!
	trap	#1
| we had better not come back; if we did, something terrible
| happened, and we might as well terminate
	movew	#-998, sp@-
	movew	#0x4c, sp@-		| Pterm()
	trap	#1

|
| bconout special code: on entry, a1 points to the stack the user
| was using. If possible, we just buffer the output until later.
|

do_bconout:
	movew	a1@(2), d0		| what device is this for?
	beq	L_bios			| don't buffer the printer
	cmpw	_bconbdev, d0		| same device as is buffered?
	bne	new_dev			| no -- maybe we can't do this
put_buf:
	movew	a1@(4), d0		| get the character to output
	movew	_bconbsiz, d1		| get index into buffer table
	cmpw	#255, d1		| buffer full?
	beq	L_bios			| yes -- flush it out
	lea	_bconbuf, a0
	addw	d1, a0
	moveb	d0, a0@			| store the character
	addqw	#1, d1
	movew	d1, _bconbsiz
	moveql	#-1, d0			| return character output OK
	rte

new_dev:
	tstw	_bconbsiz		| characters already in buffer?
	bne	L_bios			| yes: we can't buffer this one
	movew	d0, _bconbdev		| no: OK, we have a new device
	bra	put_buf
|
|
| _lineA0: MiNT calls this to get the address of the line A variables
|
	.globl	_lineA0
_lineA0:
	moveml	d2/a2, sp@-	| save scratch registers
	.word	0xa000		| call the line A initialization routine
	moveml	sp@+, d2/a2
	rts

|
| _call_aes: calls the GEM AES, using the control block passed as
|            a parameter. Used only for doing appl_init(), to see
|	     if the AES is active yet
|
	.globl	_call_aes
_call_aes:
	movel	sp@(4), d1	| fetch pointer to parameter block
	movew	#0xc8, d0	| magic number for AES
	moveml	d2/a2, sp@-	| save scratch registers
	trap	#2
	moveml	sp@+, d2/a2
	rts


|
| _callout: Call an external function, passing <32 bytes of arguments,
| and return the value from the function. NOTE: we must be careful
| to save all registers here!
|
	.globl	_callout
_callout:
	lea	sp@(8), a0		| pointer to args
	movel	sp@(4), a1		| pointer to function
	moveml	d2-d7/a2-a6, sp@-	| save registers
	moveml	a0@, d0-d7		| copy parameters
	lea	sp@(-32), sp		| NOTE: moveml auto-decrement
	moveml	d0-d7, sp@		|    changes the order of things
	movel	a1@, a0			| get function address
	jsr	a0@			| go do it
	addl	#32, sp
	moveml	sp@+, d2-d7/a2-a6	| restore reggies
	rts
