mirror of
https://github.com/elliotnunn/mac-rom.git
synced 2024-12-28 01:29:20 +00:00
0ba83392d4
Resource forks are included only for .rsrc files. These are DeRezzed into their data fork. 'ckid' resources, from the Projector VCS, are not included. The Tools directory, containing mostly junk, is also excluded.
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
|
|
|