mirror of
https://github.com/elliotnunn/supermario.git
synced 2024-11-29 05:49:19 +00:00
209 lines
8.2 KiB
Plaintext
209 lines
8.2 KiB
Plaintext
;
|
||
; File: OSDispatch.a
|
||
;
|
||
; Contains: Assembler code which receives control when OSDispatch is called.
|
||
; Kernel data addressing is established, and the requested routine is
|
||
; called. The kernel routine returns here, and we restore user data
|
||
; addressing and return to him.
|
||
;
|
||
; Written by: Erich Ringewald
|
||
;
|
||
; Copyright: © 1986-1991 by Apple Computer, Inc., all rights reserved.
|
||
;
|
||
; Change History (most recent first):
|
||
;
|
||
; <2> 12/14/90 DFH BeginKernelStack switches to user mode if that was mode we
|
||
; started up in.
|
||
; <0> x/xx/86 ELR New Today.
|
||
;
|
||
;--------------------------------------------------------------------
|
||
|
||
LOAD 'ProcessMgrIncludes.D'
|
||
INCLUDE 'data.a'
|
||
|
||
CASE OBJECT
|
||
|
||
;-------------------------------------------------------------------------------
|
||
; BeginKernelStack. Utility routine to switch the stack pointer to the Process Mgr
|
||
; stack. This is most useful when creating or destroying applications. EndKernelStack
|
||
; is the antidote.
|
||
; NOTE: QuickDraw assumes abutment of the stack and heap. Older QDs look at HeapEnd,
|
||
; newer ones look at HiHeapMark, so we manage both.
|
||
; WARNING: This routine changes HiHeapMark and HeapEnd. Beware of traps! Some will
|
||
; work *because* we change them… others may break because we change them.
|
||
; NOTE: Assumes A5 == ProcessMgrGlobals
|
||
;
|
||
; Eats: d0, a0-a1
|
||
; Returns: a0 = original stack frame pointer
|
||
;
|
||
BeginKernelStack PROC EXPORT
|
||
IMPORT (kernelMode, kernelbusy, kernelstack, kernelstackbase):DATA
|
||
|
||
addq.w #1,kernelbusy ; mark us in
|
||
move.l StkLowPt,d0 ; temporary holder
|
||
clr.l StkLowPt ; disable stack sniffing
|
||
movea.l (sp)+,a1 ; get return address
|
||
move.l sp,a0 ; get frame pointer
|
||
tst.l kernelstack ; do we want use a new stack?
|
||
beq.s @usestack ; if not, branch
|
||
|
||
; Switch to user mode, if that was what we were in when we started, to keep us
|
||
; from setting the supervisor stack pointer up into our stack area. Only an issue
|
||
; under VM (currently), since VM is the only way there is a user/supervisor
|
||
; dichotomy.
|
||
; NOTE: EndKernelStack does not restore supervisor mode. The general solution is
|
||
; quite thorny. However, since the only time we'll be switching to user mode here is
|
||
; on an ExitToShell made in supervisor mode, we're never going to call EndKernelStack
|
||
; anyway. This means that an ExitToShell in supervisor mode orphans the current depth
|
||
; of the supervisor stack. This could be remedied (e.g. set ISP back to its stackbase?).
|
||
tst.w kernelMode ; were we started in supervisor mode?
|
||
bne.s @modeOK ; if so, we can keep current mode
|
||
andi.w #$DFFF,sr ; otherwise, switch to user mode
|
||
@modeOK
|
||
move.l kernelstack,sp ; switch to kernel stack
|
||
|
||
; save stack and heap info on kernel stack
|
||
@usestack
|
||
move.l a0,-(sp) ; save frame pointer
|
||
move.l HiHeapMark,-(sp) ; save HiHeapMark
|
||
move.l d0,-(sp) ; save StkLowPt
|
||
|
||
; Set heap info that we can deal with. StackSpace, InitZone, et al memory mgr routines
|
||
; are wont to compare the stack pointer to HiHeapMark or HeapEnd, which would give very
|
||
; inappropriate answers given our new value of SP. We hack their values to prevent
|
||
; confusion. Cross your fingers!
|
||
move.l kernelstackbase,HeapEnd ; should be called STACKLIMIT
|
||
move.l kernelstackbase,HiHeapMark ; higher than any APPLZONE
|
||
jmp (a1) ; return to caller (a0 == frame)
|
||
|
||
ENDPROC ; BeginKernelStack
|
||
|
||
;-------------------------------------------------------------------------------
|
||
; EndKernelStack. Switch back to stack saved by BeginKernelStack.
|
||
; NOTE: Assumes A5 == ProcessMgrGlobals
|
||
;
|
||
; Eats: a0, d0
|
||
; Returns: a7 = original stack pointer
|
||
;
|
||
EndKernelStack PROC EXPORT
|
||
IMPORT (kernelbusy, kernelstack, kernelstackbase):DATA
|
||
|
||
move.l ApplZone,a0 ; get application zone so we can…
|
||
move.l bkLim(a0),HeapEnd ; restore HeapEnd
|
||
|
||
movea.l (sp)+,a0 ; get return address
|
||
move.l (sp)+,d0 ; get StkLowPt
|
||
move.l (sp)+,HiHeapMark ; restore HiHeapMark
|
||
move.l (sp)+,sp ; restore user's stack
|
||
move.l d0,StkLowPt ; restore stack sniffing
|
||
|
||
subq.w #1,kernelbusy ; count me out!
|
||
jmp (a0) ; return to caller
|
||
|
||
ENDPROC ; EndKernelStack
|
||
|
||
;-------------------------------------------------------------------------------
|
||
; a_osdispatch. Wherein we implement the _OSDispatch trap. Mostly just locate the
|
||
; correct routine for the particular selector. In the case of _KernelLaunch, switch to the
|
||
; kernel stack to avoid problems with the stack sniffer and QuickDraw.
|
||
a_osdispatch PROC EXPORT
|
||
|
||
IMPORT kernelbusy:DATA
|
||
IMPORT OSDispatchTable:DATA
|
||
Selector EQU 4 ; bytes from caller's stack top to selector
|
||
ParamStart EQU 6 ; bytes from caller's stack top to params
|
||
|
||
SaveRegs REG d1/a2-a3 ; registers we save
|
||
|
||
WITH OSDispatchEntry
|
||
move.l a5,d1 ; save old a5
|
||
move.l ProcessMgrGlobals,a5 ; establish data seg
|
||
|
||
; only this one selector needs "kernel addressing"
|
||
cmpi.w #KERNELLAUNCHID,4(sp) ; look at selector word.
|
||
bne.s @UseCallersSpace ; mostly never switch stacks (except launch)
|
||
tst.w kernelbusy ; are we here already?
|
||
bne.s @UseCallersSpace ; don't switch
|
||
|
||
; switch to the kernel stack
|
||
bsr.s BeginKernelStack ; switch to Process Mgr's stack area
|
||
movem.l SaveRegs,-(sp) ; save some registers
|
||
movea.l a0,a3 ; copy frame ptr to usable register
|
||
|
||
; allocate output parameter storage on kernel stack
|
||
move.w Selector(a3),d0 ; get selector
|
||
mulu.w #SizeOfElem,d0 ; calc offset of entry in table
|
||
lea OSDispatchTable,a1 ; table address
|
||
lea (a1,d0.w),a2 ; OSDispatchEntry address
|
||
move.w dispatchRetSize(a2),d0 ; get return value byte size
|
||
lsr #1,d0 ; get word size
|
||
bra.s @endMakeSpaceLoop ; jump into loop at its end
|
||
|
||
@makeSpaceLoop
|
||
clr.w -(sp) ; allocate and clear another word
|
||
@endMakeSpaceLoop
|
||
dbra d0,@makeSpaceLoop ; loop for next, or fall through
|
||
|
||
; copy input parameters from caller's stack to kernel stack
|
||
move.w dispatchDepth(a2),d0 ; get stack depth
|
||
lea ParamStart(a3,d0.w),a1 ; here is top of parameters
|
||
lsr.w #1,d0 ; turn size into words
|
||
bra.s @copyInLoopEnd ; and dbra
|
||
|
||
@copyInLoop
|
||
move.w -(a1),-(sp) ; copy another word
|
||
@copyInLoopEnd
|
||
dbra d0,@copyInLoop ; do 'em all
|
||
|
||
; fetch the dispatch address, and call it with a JSR
|
||
move.l dispatchAddr(a2),d0 ; fetch routine address
|
||
beq.s @fncdone ; if none, branch (should check for out of bounds descr)
|
||
move.l d0,a0 ; put in addr reg
|
||
jsr (a0) ; call the routine
|
||
|
||
; Kernel routine has completed. Copy output parameters back to caller's stack.
|
||
@fncdone
|
||
move.w dispatchDepth(a2),d0 ; get stack depth of caller
|
||
lea ParamStart(a3,d0.w),a0 ; address of output storage
|
||
move.w dispatchRetSize(a2),d0 ; size of output storage
|
||
lsr #1,d0 ; (convert to word count)
|
||
bra.s @endCopyOutLoop ; jump into loop end
|
||
|
||
@copyOutLoop
|
||
move.w (sp)+,(a0)+ ; copy another return value
|
||
@endCopyOutLoop
|
||
dbra d0,@copyOutLoop ; loop for next, or fall through
|
||
|
||
; switch back to the caller's stack
|
||
move.l a2,a1 ; use a1 for OSDispatchEntry later
|
||
movem.l (sp)+,SaveRegs ; restore registers
|
||
bsr EndKernelStack ; switch back to caller's stack area
|
||
movea.l d1,a5 ; restore caller's a5
|
||
|
||
; clean up and return to the caller
|
||
move.l (sp)+,a0 ; fetch return address
|
||
moveq.l #2,d0 ; calculate sizeof(selector) …
|
||
add.w dispatchDepth(a1),d0 ; … plus stack depth
|
||
add.w d0,sp ; skip parameters
|
||
jmp (a0) ; return to caller
|
||
|
||
; No need to switch stacks, just extract the selector and RTS to the handler
|
||
@UseCallersSpace
|
||
move.l (sp)+,a0 ; get return address
|
||
move.w (sp)+,d0 ; routine selector
|
||
move.l a0,-(sp) ; replace return address
|
||
|
||
lea OSDispatchTable,a0 ; point at array top
|
||
mulu.w #SizeOfElem,d0 ; multiply array index
|
||
move.l dispatchAddr(a0,d0.w),-(sp) ; put routine address on stack
|
||
|
||
move.l d1,a5 ; restore old a5
|
||
rts ; jmp over to routine
|
||
|
||
ENDWITH ; OSDispatchEntry template
|
||
|
||
ENDPROC ; a_osdispatch
|
||
|
||
END
|
||
|