|
|
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
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.