File:  [Atari MiNT] / MiNT / src / syscall.spp
Revision 1.1.1.5 (vendor branch): download - view: text, annotated - select for diffs
Tue Apr 24 17:59:07 2018 UTC (8 years, 1 month ago) by root
Branches: mint, MAIN
CVS tags: mint112, HEAD
MiNT 1.12

; Copyright 1992 Eric R. Smith

; Copyright 1992,1993,1994 Atari Corporation

; All rights reserved.



%include "magic.i"

;

; 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

; _call_dosound: calls the XBIOS Dosound() function

; _do_usrcall: calls a user supplied function (e.g. for Supexec), with

;	       arguments supplied from global variables usrarg1, usrarg2, etc.

; _callout:    calls an external function, after first saving all registers,

;              and restores the registers afterward

;

; 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).

;

; _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.

;

; we also call certain BIOS functions directly if these are known not to

; require saving/restoring of context

;

	TEXT

	

	XDEF	_mint_bios,_mint_xbios

	XDEF	_mint_dos

	XDEF	_pc_valid_return

	XREF	_build_context

	XREF	_restore_context

	XREF	_proc_clock		; controls process' allocation of CPU time

	XREF	_enter_kernel

	XREF	_leave_kernel

	XREF	_preempt

	XREF	_unwound_stack



	XREF	_check_sigs



	XREF	_curproc

	XREF	_bios_tab,_bios_max

	XREF	_xbios_tab,_xbios_max,_old_xbios

	XREF	_dos_tab,_dos_max



	XREF	_bconbuf,_bconbsiz,_bconbdev

	XREF	_bflush



	XREF	_ubconstat,_do_bconin,_ubcostat,_kbshift

	

_mint_dos:

	clr.w	-(sp)			; no frame format needed

; NOTE: FOR NOW, WE PRESERVE A0 ACROSS GEMDOS CALLS. THIS WILL CHANGE

; SOMEDAY, DON'T RELY ON IT!!!

	move.l	_curproc,d0		; note: preserve all regs but d0

	addq.l	#4,d0			; for compatibility



	move.l	d0,-(sp)		; push pointer to syscall context save

	jsr	_build_context

	lea	_dos_tab,a5		; set syscall_tab

	move.w	_dos_max,d5		; set syscall_max

;

; copy parameters onto process stack. a0 and a1 were set by _build_context

;



	move.l	_curproc,a0

	move.l	(a0),sp			; this puts us in our private stack

	move.l	24(a1),-(sp)		; a1 was set by build_context

	move.l	20(a1),-(sp)

	move.l	16(a1),-(sp)

	move.l	12(a1),-(sp)

	move.l	8(a1),-(sp)

	move.l	4(a1),-(sp)

	move.l	(a1),-(sp)

	move.w	#1,-(sp)		; flag for in GEMDOS

	jsr	_enter_kernel		; set up vectors appropriately

	addq.w	#2,sp

	bra	_syscall



_mint_xbios:

;

; Kludge for Setscreen: under Falcon TOS, this

; calls a GEMDOS function (Srealloc) and so

; we must *not* change any of the vectors!!



	btst	#5,(sp)			; test for user/super mode

	beq.s	LX_usr

%ifdef ONLY030

	lea	8(sp),a1

%else

	lea	6(sp),a1		; supervisor mode: args on stack

	tst.w	($59e).w		; test longframe

	beq.s	LX_check

	addq.w	#2,a1			; stack is a bit bigger

%endif

	bra.s	LX_check

LX_usr:

	move.l	usp,a1			; user mode: args on user stack

LX_check:

	cmp.w	#5,(a1)			; check for Setscreen command

	beq.s	LX_screen		; no -- fall through



	clr.w	-(sp)			; no frame format needed

	move.l	_curproc,a0

	pea	4(a0)			; push pointer to syscall context save

	jsr	_build_context

	lea	_xbios_tab,a5		; set syscall_tab

	move.w	_xbios_max,d5		; set syscall_max

;

; copy parameters onto process stack. a0 and a1 were set by _build_context

;



	move.l	_curproc,a0

	move.l	(a0),sp			; this puts us in our private stack

	move.l	24(a1),-(sp)		; a1 was set by build_context

	move.l	20(a1),-(sp)

	move.l	16(a1),-(sp)

	move.l	12(a1),-(sp)

	move.l	8(a1),-(sp)

	move.l	4(a1),-(sp)

	move.l	(a1),-(sp)

%ifdef ONLY030

	clr.w	-(sp)			; flag: NOT GEMDOS

%else

	move.w	#0,-(sp)		; flag: NOT GEMDOS

%endif

	jsr	_enter_kernel		; set up vectors appropriately

	addq.w	#2,sp

	bra	_syscall

;

; For setscreen, jump directly to the ROM vector --

; this avoids all hazards (like changing the vectors)



LX_screen:

	move.l	_old_xbios+8,a0

	jmp	(a0)





_mint_bios:

;

; Entering the kernel can be very expensive; so, we take a short-cut

; if possible -- we try some BIOS functions out, and if they

; succeed without blocking then we're done; otherwise, we go

; through the long procedure for entering the kernel

;

; These shortcuts aren't done when we're called in supervisor mode,

; because TOS uses very tiny stacks (smaller than we want); the

; shortcuts operate on the user-supplied ssp, whereas the "full"

; BIOS code works on our (private) system stack

;

; the shortcuts are also turned off if BIOSBUF=n

;

%ifdef ONLY030

	clr.w	-(sp)			; flag: NOT a GEMDOS call

%else

	move.w	#0,-(sp)		; flag: NOT a GEMDOS call

%endif

	jsr	_enter_kernel		; set up BIOS vectors

	addq.w	#2,sp

	tst.w	_bconbdev		; is BIOS buffering on?

	bmi	L_bios			; no; skip all this



	btst	#5,(sp)			; test for user/super mode

	bne.s	L_bios			; if super, goto L_bios

	tst.w	_proc_clock		; are we about to be preempted?

	beq.s	L_bios



	move.l	usp,a1			; user mode: args on user stack

L_ubios:

	move.w	(a1),d0			; get command

	cmp.w	#3,d0			; Bconout?

	beq	do_bconout		; yes -- go do it

;

; most of the remaining functions require BIOS vectors to be properly

; set up

	tst.w	_bconbsiz		; is BIOS output waiting?

	bne.s	L_bios			; yes -- do regular code



; test for various BIOS functions

	cmp.w	#1,d0			; Bconstat?

	bne.s	L_00

	move.w	2(a1),-(sp)		; push arg

	jsr	_ubconstat

L_1out:

	addq.l	#2,sp

L_0out:

	move.l	d0,-(sp)		; save d0

	ori.w	#$0700,sr		; spl7()

	jsr	_leave_kernel

	move.l	(sp)+,d0		; retrieve value to be returned

	rte				; return to user

L_00:

	cmp.w	#2,d0			; Bconin?

	bne.s	L_01

	move.w	2(a1),-(sp)		; yes; push argument

	jsr	_do_bconin

	addq.w	#2,sp

	cmp.w	#$dead,d0		; would Bconin block?

	bne.s	L_0out			; no -- we're done

	bra.s	L_bios			; yes -- do the long stuff

L_01:

	cmp.w	#8,d0			; Bcostat?

	bne.s	L_02

	move.w	2(a1),-(sp)		; push device

	jsr	_ubcostat		; get status

	bra.s	L_1out

L_02:

	cmp.w	#11,d0			; Kbshift?

	bne.s	L_bios

	move.w	2(a1),-(sp)		; push arg

	jsr	_kbshift

	bra.s	L_1out



L_bios:

	clr.w	-(sp)			; no frame format needed

	move.l	_curproc,a0

	pea	4(a0)			; push pointer to syscall context save

	jsr	_build_context

	lea	_bios_tab,a5		; set syscall_tab

	move.w	_bios_max,d5		; set syscall_max

;

; copy parameters onto process stack. a0 and a1 were set by _build_context

;



	move.l	_curproc,a0

	move.l	(a0),sp			; this puts us in our private stack

	move.l	24(a1),-(sp)		; a1 was set by build_context

	move.l	20(a1),-(sp)

	move.l	16(a1),-(sp)

	move.l	12(a1),-(sp)

	move.l	8(a1),-(sp)

	move.l	4(a1),-(sp)

	move.l	(a1),-(sp)



_syscall:

;

; check here to see if we need to flush the Bconout() buffer

;

	tst.w	_bconbsiz		; characters in buffer?

	beq.s	L_noflush		; no: OK to proceed

;

; watch out, this could cause a context switch

;

	jsr	_bflush			; flush the buffer



L_noflush:

;

; figure out which routine to call

;

	move.w	(sp),d0

	cmp.w	#-1,d0			; trapping with -1 means return

	bne.s	check_max		; the corresponding system table

	move.l	a5,d0

	bra.s	out

check_max:

	cmp.w	d5,d0

	bcc	error

%ifdef ONLY030

	move.l	0(a5,d0.w*4),d0

%else

	add.w	d0,d0

	add.w	d0,d0			; multiply by 4

	move.l	0(a5,d0.w),d0		; d0 = syscall_tab[d0]

%endif

	beq	error			; null entry means invalid call

	addq.w	#2,sp			; pop function number off stack

	move.l	d0,a0

	jsr	(a0)			; go do the call

out:

	move.l	_curproc,a0

	move.l	d0,P_SYSCTXT+C_D0(a0)	; set d0 in the saved context

	move.w	P_SYSCTXT+C_SR(a0),d0	; get saved status register

	

	tst.l	P_PTRACER(a0)		; check curproc->ptracer, if not set

	beq.s	notrace			; then no pending trace; this ensures

	move.w	d0,d1			; we work with non-MiNT debuggers

	and.w	#$c000,d1		; are either of the trace bits set

	sne	P_SYSCTXT+C_PTRACE(a0)	; mark as trace pending/not

notrace:

	tst.w	_proc_clock		; has process exceeded time slice?

	bne.s	nosleep			; no -- continue

	btst	#13,d0			; caller in supervisor mode?

	bne.s	nosleep			; yes -- don't interrupt

	tst.w	($43e).w		; test floppy disk lock variable

	bne.s	nosleep			; if locked, can't switch

sleep:

	tst.l	_unwound_stack		; did we unwind sysstack?

	beq.s	noreload1

	move.l	_curproc,a0		; then reload it before

	move.l	(a0),sp			; doing anything further

noreload1:

	jsr	_preempt		; does a sleep(READY_Q)

nosleep:

	ori.w	#$0700,sr		; spl7()

	jsr	_leave_kernel		; restore vectors

	move.l	_curproc,a0

	pea	4(a0)

	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

; to figure out which trap we have to call, we use the system call

; table placed in a5 earlier



error:

	cmp.l	#_xbios_tab,a5

	bne.s	maybe_bios

	trap	#14

	bra	out

maybe_bios:

	cmp.l	#_dos_tab,a5

	beq.s	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:

;  -4(sp)      (long) sfmt

;    (sp)      (long) signal number -- was a parameter for user routine

;

	XDEF	_sig_return



_sig_return:

	addq.w	#8,sp			; pop signal number and sfmt

	move.w	#$11a,-(sp)		; Psigreturn() system call

	trap	#1

_pc_valid_return:

; we had better not come back; if we did, something terrible

; happened, and we might as well terminate

	move.w	#-998,-(sp)

	move.w	#$4c,-(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:

	tst.w	_bconbdev		; is BIOS buffering on?

	bmi	L_bios			; no buffering -- skip this code

	move.w	2(a1),d0		; what device is this for?

	beq	L_bios			; don't buffer the printer

	cmp.w	_bconbdev,d0		; same device as is buffered?

	bne.s	new_dev			; no -- maybe we can't do this

put_buf:

	move.w	4(a1),d0		; get the character to output

	move.w	_bconbsiz,d1		; get index into buffer table

	cmp.w	#255,d1			; buffer full?

	beq	L_bios			; yes -- flush it out

	lea	_bconbuf,a0

	add.w	d1,a0

	move.b	d0,(a0)			; store the character

	addq.w	#1,d1

	move.w	d1,_bconbsiz

	ori.w	#$0700,sr		; spl7()

	jsr	_leave_kernel		; restore vectors

	moveq.l	#-1,d0			; return character output OK

	rte



new_dev:

	tst.w	_bconbsiz		; characters already in buffer?

	bne	L_bios			; yes: we can't buffer this one

	move.w	d0,_bconbdev		; no: OK, we have a new device

	bra.s	put_buf



;

; _lineA0: MiNT calls this to get the address of the line A variables

;

	XDEF	_lineA0

_lineA0:

	movem.l	d2/a2,-(sp)	; save scratch registers

	dc.w	$a000		; call the line A initialization routine

	movem.l	(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

;

	XDEF	_call_aes

_call_aes:

	move.l	4(sp),d1	; fetch pointer to parameter block

	move.w	#$c8,d0		; magic number for AES

	movem.l	d2/a2,-(sp)	; save scratch registers

	trap	#2

	movem.l	(sp)+,d2/a2

	rts

;

; _call_dosound:

;

	XDEF	_call_dosound

_call_dosound:

	move.l	4(sp),-(sp)

	move.w	#32,-(sp)

	trap	#14

	addq.w	#6,sp

	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!

;

	XDEF	_callout

	XDEF	_callout1

	XDEF	_callout2

	XDEF	_callout6

	XDEF	_callout6spl7

;

; _callout is the general purpose one

;

_callout:

	lea	8(sp),a0		; pointer to args

	move.l	4(sp),a1		; pointer to pointer to function

	movem.l	d2-d7/a2-a6,-(sp)	; save registers

	movem.l	(a0),d0-d7		; copy parameters

	movem.l	d0-d7,-(sp)

	suba.l	a5,a5			; the BIOS expects 0 in a5

	jsr	(a1)			; go do it

	lea	32(sp),sp

	movem.l	(sp)+,d2-d7/a2-a6	; restore reggies

	rts

;

; _callout2 and _callout1 are for functions with just 1 or

; 2 16 bit parameters. We cheat and use the same code for

; both, since passing 32 bits isn't much more expensive than

; passing 16 bits (and since the called function will just

; ignore any extra arg)

;



_callout1:

_callout2:

	movem.l	4(sp),a0/a1		; get function ptr & args

	movem.l	d2-d7/a2-a6,-(sp)	; save reggies

	move.l	a1,-(sp)		; push args

	suba.l	a5,a5			; the BIOS expects 0 in a5

	jsr	(a0)			; do function

	addq.w	#4,sp

	movem.l	(sp)+,d2-d7/a2-a6	; restore reggies

	rts

;

; _callout6 passes 6 words, saving sr

;

_callout6:

	movem.l	d2-d7/a2-a6,-(sp)	; save registers

	movem.l	4+44(sp),a0-a3		; get function ptr & args

	move.w	sr,-(sp)

	movem.l	a1-a3,-(sp)		; copy args

	suba.l	a5,a5			; the BIOS expects 0 in a5

	jsr	(a0)			; go do it

	lea	12(sp),sp

	move.w	(sp)+,sr

	movem.l	(sp)+,d2-d7/a2-a6	; restore reggies

	rts

;

; _callout6spl7 passes 6 words at ipl7

;

_callout6spl7:

	movem.l	d2-d7/a2-a6,-(sp)	; save registers

	movem.l	4+44(sp),a0-a3		; get function ptr & args

	move.w	sr,-(sp)

	movem.l	a1-a3,-(sp)		; copy args

	suba.l	a5,a5			; the BIOS expects 0 in a5

	ori.w	#$0700,sr		; spl7()

	jsr	(a0)			; go do it

	lea	12(sp),sp

	move.w	(sp)+,sr

	movem.l	(sp)+,d2-d7/a2-a6	; restore reggies

	rts



;

; do_usrcall: call the user supplied function (*usrcall)(), with

; arguments given in the longwords usrarg1..usrarg5. Return value

; is placed in usrret. This function is used by the Supexec code

; in xbios.c.



	XDEF	_do_usrcall

	XREF	_usrret

	XREF	_usrcall

	XREF	_usrarg1,_usrarg2,_usrarg3,_usrarg4,_usrarg5



_do_usrcall:

	move.l	_usrarg5,-(sp)

	move.l	_usrarg4,-(sp)

	move.l	_usrarg3,-(sp)

	move.l	_usrarg2,-(sp)

	move.l	_usrarg1,-(sp)

	move.l	_usrcall,-(sp)	; the user expects to see this on the stack

	pea	ucret(pc)	; so rts puts us back here

	move.l	_usrcall,-(sp)	; this copy is for us to use

	rts			; to jump to (we don't want to use registers)

ucret:

	lea	24(sp),sp	; fix up stack

	move.l	d0,_usrret	; save returned value

	rts			; back to caller



	END


unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.