mirror of
https://github.com/elliotnunn/supermario.git
synced 2024-12-01 02:51:04 +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
|
|||
|
|