mirror of
https://github.com/elliotnunn/supermario.git
synced 2024-11-29 05:49:19 +00:00
1763 lines
72 KiB
Plaintext
1763 lines
72 KiB
Plaintext
;
|
||
; File: ProcessMgrMisc.a
|
||
;
|
||
; Contains: Routines which support the Process Manager that could not be
|
||
; coded in C.
|
||
;
|
||
; Written by: Phil Goldman
|
||
;
|
||
; Copyright: © 1986-1992 by Apple Computer, Inc., all rights reserved.
|
||
;
|
||
; Change History (most recent first):
|
||
;
|
||
; <19> 11/25/92 DRF Add a conditional patch inside a_hfsdispatch to save and restore
|
||
; A2 across calls the the real _HFSDispatch. This is a temporary
|
||
; fix until the PowerPC trap glue follows the proper register
|
||
; saving conventions. Code is conditionalized under “PsychicTV”
|
||
; and will be removed at the earliest possibility.
|
||
; <18> 9/25/92 DRF Get rid of MyGestalt, since inline glue exists
|
||
; <17> 3/30/92 DTY #1025416,<DDG>: Add gestaltSkiaGlobalsSwitched to the list of
|
||
; attributes for gestaltOSAttr.
|
||
; <16> 11/25/91 DTY Call GetParallelFCBFromRefNum in the _OpenRF patch to nail the
|
||
; PSN in the parallel FCB for printer drivers, if it they have the
|
||
; “MultiFinder compatible” bit set. This prevents the driver from
|
||
; being closed out from under other applications which happen to
|
||
; be using it at the same time.
|
||
; <15> 11/4/91 DTY Of course, keeping your own copy of an interface macro tends to
|
||
; screw things up when the selectors change…
|
||
; <14> 11/1/91 DTY Don’t assume SysMapHndl really has a handle to the system
|
||
; resource map, as it will have a handle to an override map when
|
||
; ROMMapInsert is true. Call _IsThisASystemResourceMap to
|
||
; determine whether it is or not instead.
|
||
; <13> 10/23/91 DTY Take GetTopSystemOverrideMap out of this file and hang it off of
|
||
; _ResourceDispatch.
|
||
; <12> 10/20/91 DTY Add GetTopSystemOverrideMap. This returns a handle to the first
|
||
; system override map in the resource chain to NewProcess so that
|
||
; new resource chains will have system override maps too.
|
||
; <11> 4/12/91 DFH TES, #86777 : Change _Close patch to just call through when trap
|
||
; was made async. Our “shared printer file” check can not be made
|
||
; safely at interrupt time. Fortunately, it is not necessary for
|
||
; it to be done on async Close's, since the printer files are
|
||
; closed by the Print Manager synchronously. First found in
|
||
; HyperCard testing.
|
||
; <10> 3/5/91 DFH dnf, #84115: Added support for new forced _Unmount (ignore
|
||
; result of notification proc).
|
||
; <9> 2/21/91 DFH JWM,WS#DFH-910221a: Fix gross register eating in c_zeroscrap and
|
||
; c_putscrap across call to DisposeOrphanedScrap.
|
||
; <7> 12/18/90 DFH Added GetScrap patch to return memFullErr when most recent
|
||
; MoveScrap() failed for lack of memory.
|
||
; <6> 12/17/90 DFH ZeroScrap and PutScrap now call DisposeOrphanedScrap.
|
||
; <5> 12/17/90 DFH Fixed RecoverHandle patch to preserve d0, as per Inside Mac,
|
||
; Volume II, page 35.
|
||
; <4> 12/3/90 DFH Changed CloseWD patch to return noErr in the error case. This
|
||
; is because error is not useful, and TOPS has an assert that it
|
||
; is zero.
|
||
; <3> 11/9/90 DFH Wakes up front process before calling dsForcedQuit SysError, so
|
||
; that front process promptly makes the event call that will clean
|
||
; up the confirmation dialog.
|
||
; <2> 11/9/90 DFH Added re-entrancy prevention in "forced quit" handling. Note
|
||
; that this means user can not "force quit" out of a hung SysError
|
||
; of any kind.
|
||
; <0> x/xx/86 PYG New Today.
|
||
;
|
||
;--------------------------------------------------------------------
|
||
|
||
CASE OBJECT
|
||
LOAD 'ProcessMgrIncludes.D'
|
||
INCLUDE 'Data.a'
|
||
include 'FileMgrPrivate.a'
|
||
include 'GestaltPrivateEqu.a'
|
||
STRING PASCAL
|
||
|
||
;-------------------------------------------------------------------------------
|
||
;
|
||
; This mega-box comment was extracted 18 April 1989 from the ROM dispatch.a source,
|
||
; mainly as a compatibility guideline.
|
||
;
|
||
; Of course, we strategically violate the register eating manners for particular
|
||
; traps that don't REALLY need the regs.
|
||
;
|
||
;
|
||
; EMT1010 -- MacIntosh Operating System Dispatcher
|
||
;
|
||
; The following code receives all Line 1010 emulator traps and transfers
|
||
; control to the appropriate system code to interpret the trap. Two 32-bit/entry
|
||
; RAM-based dispatch tables are used to derive the addresses to which to dispatch.
|
||
; Since this table is patchable, a system or application program can patch in
|
||
; and intercept any system call to fix bugs, etc.
|
||
;
|
||
; An A-line trap has the form: 1010 tabc nnnn nnnn
|
||
;
|
||
; t=1 ==> Toolbox; t=0 ==> OS. They differ mainly in register saving conventions.
|
||
;
|
||
; ToolBox:
|
||
; These calls follow Pascal parameter-passing conventions, receiving and
|
||
; returning values on the stack, and saving all but D0-D2/A0-A1.
|
||
; All registers are preserved up to the time the target routine is reached;
|
||
; the stack is as though a JSR had been executed.
|
||
;
|
||
; a=1 ==> an extra return address was on the stack when the trap was executed
|
||
;
|
||
; (e.g. a dumb compiler required a JSR to the A-line trap). This superfluous
|
||
; address will be removed by the dispatcher.
|
||
; bcnnnnnnnn = trap number
|
||
;
|
||
; OS:
|
||
; All parameters are passed in registers. Routine must follow Pascal
|
||
; conventions about D3-D7/A2-A7. D0/A0-A1 are passed through to the
|
||
; routine unchanged. D1.W is the actual A-line instruction.
|
||
;
|
||
; c=1 ==> D1-D2/A1 are preserved by the dispatcher (so values can
|
||
; be returned in D0/A0).
|
||
; c=0 ==> D1-D2/A0-A1 are preserved by the dispatcher (so D0 can be returned).
|
||
; a,b = don't care, but are used by the traps to indicate, say, SYS/APPL,
|
||
; SYNC/ASYNC, DIACRITICALS/NOT, . . .
|
||
; nnnnnnnn = trap number
|
||
;
|
||
; Dispatch addresses are maintained in two tables of long words, ToolTable with
|
||
; 512 entries, and OSTable with 256 entries. (They used to be rolled into one
|
||
; table of 512 word entries.)
|
||
; For backward compatibility, the GetTrapAddress and SetTrapAddress routines use
|
||
; the original trap numbering scheme, that is traps $00-$4F, $54, and $57 are OS
|
||
; traps, and the rest are Tool traps.
|
||
;
|
||
; The expanded routines GetTrapAddress and SetTrapAddress routines use bits #10
|
||
; to specify Tool=1/OS=0 and #9 to specify New=1/Old=0 numbering. Bit #10 is
|
||
; ignored when bit #9 is 0.
|
||
;
|
||
; A few things to remember. Although toolbox routines use pascal register
|
||
; saving conventions, the trap dispatcher must preserve all registers when
|
||
; dispatching a toolbox trap, since there are some routines which are
|
||
; documented as saving all registers (_Debugger, _LoadSeg, _FP68K, …).
|
||
;
|
||
; Even though the OS trap dispatcher saves A0-A2/D1-D2 for the user, it
|
||
; may not modify A0 or A1 before calling the OS routine, since routines
|
||
; like _BlockMove expect paramaters in A0/A1/D0. Additionally, register
|
||
; D1 must contain a copy of the A-Trap word, since that is how routines
|
||
; read the additional trap bits (eg. _NewPtr ,SYS,CLEAR).
|
||
;
|
||
; Although the register save order, and format of the stack frame for an
|
||
; OS trap is undocumented, Microsoft does a SetTrapAddress on _GetHandleSize
|
||
; and and their new routine calls the ROM GetHandleSize, and then restores
|
||
; the registers that the trap dispatcher saved, and does a TST.L on D0.
|
||
; Because of this, register save order must be maintained for compatibility,
|
||
; since we may never get back to restore them.
|
||
;
|
||
; For machines with CPUs earlier than the 68020, we include 3 versions of the
|
||
; trap dispatcher in ROM, 68000, 68010, and 68020/030. At startup time we
|
||
; determine which CPU we are running on, and install the correct dispatcher.
|
||
; We also modify the dispatch addresses for GetTrapAddress, SetTrapAddress,
|
||
; and BlockMove to use cache flushing versions when the CPU is a 68020 or later.
|
||
; On systems with 68020/030 cpus, we only provode the 020/030 versions.
|
||
;_______________________________________________________________________
|
||
|
||
; For resource maps, entries
|
||
mapForceSysHeap EQU 0
|
||
RAttr EQU 4
|
||
RHndl EQU 8
|
||
|
||
mNext equ 16
|
||
MRefNum EQU 20
|
||
MAttr EQU 22
|
||
|
||
;---------------------------------------------------------------------------------------
|
||
; generic_glue. Routine to make up for the fact that the C compiler is too
|
||
; brain-damaged to handle pointers to pascal functions. This is a pascal-type
|
||
; routine with the last parameter being the address of the routine to call.
|
||
generic_glue PROC EXPORT
|
||
move.l 4(sp),a0 ; get address of real routine
|
||
move.l (sp)+,(sp) ; move return address on top of routine address
|
||
jmp (a0) ; go do the routine
|
||
|
||
ENDPROC
|
||
|
||
;---------------------------------------------------------------------------------------
|
||
; settrapaddress_glue. This is glue to call the original SetTrapAddress.
|
||
; The C prototype is:
|
||
;
|
||
; pascal void
|
||
; settrapaddress_glue(Ptr trapAddr, short trapNum, short setTrapAddressNum, Ptr oldtrap)
|
||
;
|
||
; Eats a0, d0-d2 before calling trap
|
||
SETTRAPADDRESS_GLUE PROC EXPORT
|
||
move.l (sp)+,d2 ; save return address
|
||
move.l (sp)+,a1 ; get old settrapaddress addr
|
||
move.w (sp)+,d1 ; get settrapaddress (full) trap number
|
||
move.w (sp)+,d0 ; d0 <- trap number
|
||
move.l (sp)+,a0 ; a0 <- trap address
|
||
move.l d2,-(sp) ; restore return address
|
||
jmp (a1) ; go do routine
|
||
|
||
ENDPROC
|
||
|
||
;---------------------------------------------------------------------------------------
|
||
; OverlayRecoverHandle. The following is to get Works to live up to its name. Works
|
||
; assumes that if the ,SYS bit is not set then the handle must be in the App Heap.
|
||
; The only problem with this is if the handle belongs in SysZone. Therefore the patch
|
||
; forces ,SYS in this case.
|
||
OverlayRecoverHandle PROC EXPORT
|
||
IMPORT GetOverlayRecoverHandleOldTrap:CODE
|
||
SYSBITON EQU $0400
|
||
|
||
movem.l d0-d1/a0,-(sp) ; save working registers
|
||
move.l a0,d0 ; get ptr in parameter reg
|
||
_StripAddress ; strip!
|
||
move.l d0,a0 ; for unsigned compare
|
||
move.l SysZone,a1 ; ptr to system zone descriptor
|
||
cmpa.l bkLim(a1),a0 ; Ptr < SysZone->bkLim?
|
||
bcc.s ORH_done ; if not, branch
|
||
ORH_force_comma_sys
|
||
or.l #SYSBITON,4(sp) ; force ,SYS bit on for Works to see
|
||
ORH_done
|
||
jsr GetOverlayRecoverHandleOldTrap ; Get the actual value from the PCB
|
||
move.l d0,a1 ; and get it into an address register
|
||
movem.l (sp)+,d0-d1/a0 ; restore working registers
|
||
jmp (a1) ; and do it
|
||
|
||
ENDPROC
|
||
|
||
;---------------------------------------------------------------------------------------
|
||
; pascal long ProcessMgr_GZProc_Glue(long cbNeeded)
|
||
|
||
; The ROM memory manager keeps the "working zone" address in A6 wherever it
|
||
; travels. If our growzone changes the zone address (a unique experience!),
|
||
; we must be sure to keep the memory manager up to date for the remainder of
|
||
; his operation. The A6 is (handily) on our caller's stack frame. Yuck.
|
||
; NOTE: This is a massive hack! Fix this if at all possible.
|
||
; NOTE: This GZProc can be called from places other than the ROM CallGZProc (like our
|
||
; own routine, HiNewHandle), so checking for SavedA6 == oldProcessMgrZone is required.
|
||
;
|
||
; Here are the regs saved by CallGZProc in Sources:OS:MemoryMgr:HeapGuts.a
|
||
GZPROCREGS_SIZE EQU (14*4) ; d0-d1/d3-d7/a0-a6
|
||
GZPROCREGS_A6OFFSET EQU (GZPROCREGS_SIZE-4) ; GZPROCREGS_SIZE up to a6
|
||
|
||
; Here is how much we have on the stack when we need to access the saved a6
|
||
OURTEMPSTACKUSAGE EQU 16 ; a couple regs, etc.
|
||
|
||
; Here is how far we have to go from our stack pointer to the saved a6
|
||
SavedA6 EQU OURTEMPSTACKUSAGE + GZPROCREGS_A6OFFSET
|
||
|
||
PROCESSMGR_GZPROC_GLUE PROC EXPORT
|
||
IMPORT PROCESSMGRGZPROC:CODE
|
||
IMPORT (oldProcessMgrZone, newProcessMgrZone):DATA
|
||
|
||
move.l a5,-(sp) ; save old a5
|
||
movea.l ProcessMgrGlobals,a5 ; set up our a5
|
||
|
||
; clear the indicator of actual zone movement
|
||
clr.l oldProcessMgrZone ; zero is impossible address
|
||
|
||
; now call real grow zone procedure
|
||
clr.l -(sp) ; clear out ret value
|
||
move.l 12(sp),-(sp) ; push arg again
|
||
jsr PROCESSMGRGZPROC ; do it
|
||
move.l (sp)+,12(sp) ; save ret val
|
||
|
||
; did the zone header move?
|
||
tst.l oldProcessMgrZone ; has oldProcessMgrZone been set?
|
||
beq.s StackIsOK ; if not, branch
|
||
|
||
; are we being called from the Memory Manager? If so, fix up the a6 saved on the stack.
|
||
move.l SavedA6(sp),d0 ; get a6 value on stack (welcome to system software)
|
||
cmp.l oldProcessMgrZone,d0 ; is the same as mem mgr zone ptr?
|
||
bne.s StackIsOK ; if not, there is no fix to do
|
||
move.l newProcessMgrZone,SavedA6(sp) ; give Memory Mgr a new a6
|
||
StackIsOK
|
||
move.l (sp)+,a5 ; restore a5
|
||
move.l (sp)+,a0 ; get ret addr
|
||
addq.w #4,sp ; skip argument
|
||
jmp (a0) ; and return
|
||
|
||
ENDPROC
|
||
|
||
;---------------------------------------------------------------------------------------
|
||
; a_settrapaddress. Our patch to SetTrapAddress. Just calls our C function.
|
||
a_settrapaddress PROC EXPORT
|
||
|
||
IMPORT c_settrapaddress:CODE
|
||
|
||
; WARNING: This is dependent on new ROM trap dispatch routine (D1 has
|
||
; no meaning on old ROMs)
|
||
|
||
move.l d1,-(sp) ; pass the trap call
|
||
move.l d0,-(sp) ; pass the trap number
|
||
move.l a0,-(sp) ; pass the routine address
|
||
jsr c_settrapaddress
|
||
lea 12(sp),sp ; get past my C parameters
|
||
|
||
; Help out MS File by clearing d0 here. They are about to call _BlockMove without
|
||
; setting the top word of d0.
|
||
moveq.l #noErr, d0 ; clear this for MS File
|
||
rts
|
||
|
||
ENDPROC
|
||
|
||
;---------------------------------------------------------------------------------------
|
||
IF (&TYPE('MM_DEBUG') <> 'UNDEFINED') THEN
|
||
; CheckParam. For memory manager debugging. Checks that passed handle is valid.
|
||
CheckParam PROC
|
||
movem.l d0-d7/a0-a6,-(sp) ; save work registers
|
||
move.l a0,-(sp) ; push handle
|
||
jsr CheckBadHandle ; check if bad
|
||
addq.w #4,sp ; get rid of parameter
|
||
rts ; return
|
||
|
||
ENDPROC
|
||
ENDIF
|
||
|
||
;---------------------------------------------------------------------------------------
|
||
; a_newhandle. Our patch to NewHandle. Specially prepares for allocations
|
||
; from either the Process Mgr zone or the System zone.
|
||
MIN_SYS_HEAP_FREE_SPACE EQU $2000
|
||
|
||
a_newhandle PROC EXPORT
|
||
|
||
IMPORT ProcessMgrHMakeMoreMasters:CODE
|
||
IMPORT ProcessMgrZone:DATA, patchtraps:DATA
|
||
SaveRegs REG d0-d1/d3
|
||
|
||
; Check for needing more master pointers in the Process Mgr heap
|
||
movem.l SaveRegs,-(sp) ; save work regs
|
||
movea.l ProcessMgrGlobals,a0 ; get address of our globals
|
||
exg a0,a5 ; a0 <- orig a5, a5 <- our a5
|
||
move.l patchtraps+RomAllPatchTable.Rom75Patches.NEWHANDLE.oldtrap,d3 ; d3 <- old _NewHandle routine
|
||
move.l ProcessMgrZone,a5 ; get Process Mgr zone
|
||
exg a0,a5 ; a5 <- orig a5, a0 <- ProcessMgrZone
|
||
move.l TheZone,a1 ; a1 <- TheZone
|
||
cmp.l SysZone,a1 ; is this the sys zone?
|
||
beq.s DoSysCode ; if so, branch
|
||
btst #10,d1 ; is it sys heap override?
|
||
bne.s DoSysCode ; if so, do sys heap handling
|
||
cmp.l a1,a0 ; is this the ProcessMgrZone?
|
||
bne.s DoOldCode ; if not, branch
|
||
|
||
; Using Process Mgr zone. Make sure our moreMasters routine is used.
|
||
move.l hFstFree(a0),d0 ; get next MP
|
||
bne.s DoOldCode ; if not nil, branch
|
||
move.l a5, -(sp) ; save a5
|
||
movea.l ProcessMgrGlobals,a5 ; get our a5 for intersegment call
|
||
jsr ProcessMgrHMakeMoreMasters ; try for more masters
|
||
move.l (sp)+, a5 ; restore a5
|
||
tst.l d0 ; did we get them?
|
||
bpl.s DoOldCode ; if so, branch
|
||
NHErr
|
||
addq.w #4,sp ; skip over old d0
|
||
move.l (sp)+,d1 ; restore d1
|
||
move.l (sp)+,d3 ; restore d3
|
||
rts
|
||
|
||
; getting memory from the system heap. See if we should grow the zone right now.
|
||
DoSysCode
|
||
move.l SysZone,a0 ; get the sys zone header
|
||
move.l #MIN_SYS_HEAP_FREE_SPACE,d1 ; get min free in d1
|
||
cmp.l d0,d1 ; is it smaller than min
|
||
bcc.s GetMoreSpace ; if so, branch
|
||
move.l d0,d1 ; if not, substitute it
|
||
GetMoreSpace
|
||
sub.l zcbFree(a0),d1 ; are there at least this many bytes free?
|
||
bls.s MaybeEnoughRoom ; if so, branch
|
||
|
||
; requested size is greater than total free space, call the GZ proc, if any
|
||
move.l gzProc(a0),d0 ; get grow zone proc address
|
||
beq.s DoOldCode ; can't call it if it doesn't exist!
|
||
movem.l a0-a1/d3,-(sp) ; save still more work regs
|
||
subq.w #4,sp ; save room for function result
|
||
move.l d1,-(sp) ; push the desired handle size as bytes needed
|
||
movea.l d0,a0 ; put GZ proc address in address register
|
||
jsr (a0) ; try to grow
|
||
addq.w #4,sp ; trash function result
|
||
movem.l (sp)+,a0-a1/d3 ; restore still more work regs
|
||
MaybeEnoughRoom
|
||
DoOldCode
|
||
move.l d3,a0 ; a0 <- old _NewHandle routine
|
||
movem.l (sp)+,SaveRegs ; restore work regs
|
||
jmp (a0) ; tail recursion (if not from NHErr)
|
||
|
||
ENDPROC
|
||
|
||
;---------------------------------------------------------------------------------------
|
||
; Patch to HandleZone. If handle is purged temp memory, return ProcessMgrZone directly.
|
||
a_handlezone PROC EXPORT
|
||
IMPORT ProcessMgrZone:DATA,patchtraps:DATA
|
||
IMPORT InCurrTempMem:CODE
|
||
|
||
; a0 == handle
|
||
move.l a5,a1 ; save current a5
|
||
movea.l ProcessMgrGlobals,a5 ; get address of our globals
|
||
move.l a0,d0 ; nil handle?
|
||
beq.s CallOld ; if so, let memory manager give error
|
||
move.l (a0),d0 ; dereference it, check for purged
|
||
bne.s CallOld ; if not purged, let memory manager find zone
|
||
|
||
; handle is purged, must check for it in current temp memory
|
||
movem.l d1/a0-a1,-(sp) ; save working registers
|
||
move.l a0,-(sp) ; pass supposed handle (as HListElem)
|
||
jsr InCurrTempMem ; try to locate it
|
||
addq.w #4,sp ; dump stack param
|
||
tst.w d0 ; was handle really temp memory?
|
||
movem.l (sp)+,d1/a0-a1 ; restore working registers
|
||
bne.s CallOld ; jump if block was not registered
|
||
|
||
; purged handle was ours, return ProcessMgrZone (d0 already equals noErr)
|
||
move.w d0,MemErr ; agree in lomem
|
||
move.l ProcessMgrZone,a0 ; return our zone address
|
||
move.l a1,a5 ; restore old a5
|
||
rts
|
||
|
||
; retrieve old trap address from table, and call it
|
||
CallOld
|
||
IF (&TYPE('MM_DEBUG') <> 'UNDEFINED') THEN
|
||
jsr CheckParam ; ensure handle and MP lists OK
|
||
ENDIF
|
||
move.l patchtraps+RomAllPatchTable.Rom75Patches.HANDLEZONE.oldtrap,-(sp)
|
||
move.l a1,a5 ; restore old a5
|
||
rts
|
||
|
||
ENDPROC
|
||
|
||
;---------------------------------------------------------------------------------------
|
||
; a_recoverhandle, Our patch to RecoverHandle. Make sure we find temp memory handles,
|
||
; too. Requires proper setting of TheZone, because real handle is determined by adding
|
||
; it to the relative handle in the block header. We try to find the pointer in temp
|
||
; handle allocations for the current process and system.
|
||
; IN: a0 == Ptr
|
||
; OUT: a0 = handle
|
||
; NOTE: We must preserve caller's D0, since Inside Mac, volume II, page 35 says so.
|
||
|
||
a_recoverhandle PROC EXPORT
|
||
IMPORT patchtraps:DATA
|
||
IMPORT RecoverCurrTempHdl:CODE
|
||
SaveRegs REG d0-d1/a0-a1
|
||
|
||
move.l a5,a1 ; a1 <- orig a5
|
||
movea.l ProcessMgrGlobals,a5 ; get address of our globals
|
||
move.l patchtraps+RomAllPatchTable.Rom75Patches.RECOVERHANDLE.oldtrap,-(sp) ; -(sp) <- old _NewHandle routine
|
||
movem.l SaveRegs,-(sp) ; save working registers
|
||
move.l a0,-(sp) ; pass supposed master pointer
|
||
jsr RecoverCurrTempHdl ; try to locate it
|
||
addq.w #4,sp ; dump stack param
|
||
move.l d0,d2 ; did we find it in temp memory?
|
||
movem.l (sp)+,SaveRegs ; restore registers (CCs unchanged)
|
||
beq.s Return ; return to old trap if block not known
|
||
|
||
; pointer was temp block, so no need to call old trap
|
||
movea.l d2,a0 ; put handle in output register
|
||
clr.w MemErr ; set AOK lomem error code
|
||
addq.w #4,sp ; dump old trap address
|
||
Return
|
||
move.l a1,a5 ; a5 <- orig a5
|
||
rts
|
||
|
||
ENDPROC
|
||
|
||
;---------------------------------------------------------------------------------------
|
||
; a_reallochandle. Our patch to ReallocHandle. Make sure memory comes from correct
|
||
; place. If that's the system heap, call the growzone procedure if the free space
|
||
; is getting low. If the handle is Process Mgr temporary memory, use the ProcessMgrZone.
|
||
; NOTE: Our save/restore of THEZONE assumes that the current zone is not ProcessMgrZone
|
||
; if the handle is from temp memory, since call-through could change ProcessMgrZone.
|
||
a_reallochandle PROC EXPORT
|
||
|
||
IMPORT patchtraps:DATA, ProcessMgrZone:DATA
|
||
IMPORT InCurrTempMem:CODE
|
||
|
||
; IN: a0 == handle, d0 == requested size, d1 == trap word
|
||
; OUT: d0 == result code (long)
|
||
move.l a5,a1 ; a1 <- orig a5
|
||
movea.l ProcessMgrGlobals,a5 ; get address of our globals
|
||
move.l patchtraps+RomAllPatchTable.Rom75Patches.REALLOCHANDLE.oldtrap,-(sp) ; -(sp) <- old _NewHandle routine
|
||
move.l a1,a5 ; a5 <- orig a5
|
||
move.l SysZone,a1 ; a1 <- TheZone
|
||
cmp.l TheZone,a1 ; is this the sys zone?
|
||
beq.s DoSysCode ; if so, branch
|
||
btst #10,d1 ; is it sys heap override?
|
||
bne.s DoSysCode ; if so, branch
|
||
|
||
; Handle being reallocated from current heap. Adjust THEZONE if the handle
|
||
; was registered as Process Mgr temp memory for the current process.
|
||
; NOTE: We could skip check if TheZone already equals ProcessMgrZone, but this
|
||
; is unlikely since Process Mgr doesn't use purgeable blocks.
|
||
movem.l d0-d1/a0/a5,-(sp) ; save working registers
|
||
movea.l ProcessMgrGlobals,a5 ; get address of our globals
|
||
move.l a0,-(sp) ; pass supposed handle (as HListElem)
|
||
jsr InCurrTempMem ; try to locate it
|
||
addq.w #4,sp ; dump stack param
|
||
move.l ProcessMgrZone,a1 ; in case we need it
|
||
tst.w d0 ; was handle really temp memory?
|
||
movem.l (sp)+,d0-d1/a0/a5 ; restore working registers
|
||
bne.s DoOldCode ; jump if block was not registered
|
||
|
||
; block was MF temp memory, switch zones around call
|
||
move.l TheZone,-(sp) ; save current zone
|
||
move.l a1,TheZone ; switch to ProcessMgrZone
|
||
move.l 4(sp),a1 ; old trap address
|
||
jsr (a1) ; call it
|
||
move.l (sp)+,TheZone ; restore the zone
|
||
addq.w #4,sp ; dump trap address
|
||
bra.s ByeNow ; leave
|
||
|
||
; getting memory from system heap
|
||
DoSysCode
|
||
IF (&TYPE('MM_DEBUG') <> 'UNDEFINED') THEN
|
||
jsr CheckParam ; ensure handle and MP lists OK
|
||
ENDIF
|
||
move.l #MIN_SYS_HEAP_FREE_SPACE,d2 ; get min free in d2
|
||
cmp.l d0,d2 ; is requested smaller than min
|
||
bcc.s GetMoreSpace ; if so, branch
|
||
move.l d0,d2 ; if not, substitute it
|
||
GetMoreSpace
|
||
sub.l zcbFree(a1),d2 ; are there at least this many bytes free?
|
||
bls.s ProbablyEnoughRoom ; if so, branch
|
||
movem.l d0-d1/a0,-(sp) ; save still more work regs
|
||
subq.w #4,sp ; save room for function result
|
||
move.l d2,-(sp) ; push the desired handle size as bytes needed
|
||
move.l gzProc(a1),a1 ; get grow zone proc address
|
||
jsr (a1) ; try to grow
|
||
addq.w #4,sp ; trash function result
|
||
movem.l (sp)+,d0-d1/a0 ; restore still more work regs
|
||
ProbablyEnoughRoom
|
||
|
||
DoOldCode
|
||
IF (&TYPE('MM_DEBUG') <> 'UNDEFINED') THEN
|
||
jsr CheckParam ; ensure handle and MP lists OK
|
||
ENDIF
|
||
ByeNow
|
||
rts
|
||
|
||
ENDPROC
|
||
|
||
;---------------------------------------------------------------------------------------
|
||
; a_disposhandle. Our patch to DisposHandle. If handle is temp memory, remove it
|
||
; from the registry and switch to ProcessMgrZone around actual disposal. Just make sure
|
||
; the ProcessMgrZone doesn't end up with a master pointer from another heap in its free
|
||
; list. This would happen if someone disposed a purged handle, and we accidently
|
||
; switched zones. Tried to streamline the no-find case, because this trap is in even
|
||
; when no temp memory is allocated.
|
||
; NOTE: Getting an error while freeing a block we thought was temp mem is bad news.
|
||
; It probably means the block was already freed, but by a process other than the
|
||
; one that allocated it. This should be relatively harmless, though. What I am more
|
||
; concerned about is that this sort of thing is happening, and that it may lead to
|
||
; freeing a master pointer has since been reallocated.
|
||
; FURTHER NOTE: We'll be lucky beyond belief if the Memory Manager is ever smart
|
||
; enough to return error from DisposHandle.
|
||
|
||
PROC
|
||
IMPORT ProcessMgrZone:DATA,patchtraps:DATA
|
||
IMPORT RemoveCurrTempMem:CODE
|
||
EXPORT a_disposhandle:CODE
|
||
|
||
a_disposhandle
|
||
move.l a5,d0 ; save current a5
|
||
movea.l ProcessMgrGlobals,a5 ; get address of our globals
|
||
move.l patchtraps+RomAllPatchTable.Rom75Patches.DISPOSHANDLE.oldtrap,-(sp)
|
||
movem.l d0-d1/a0,-(sp) ; save registers that might perish
|
||
move.l a0,-(sp) ; pass supposed handle (as HListElem)
|
||
jsr RemoveCurrTempMem ; try to deregister it
|
||
addq.w #4,sp ; dump stack params
|
||
tst.w d0 ; was handle really temp memory?
|
||
movem.l (sp)+,d0-d1/a0 ; restore registers (no touch CC)
|
||
bne.s NoSwitch ; jump if block wasn't registered
|
||
|
||
; awkward code only executed when freeing temporary memory
|
||
; (sp) contains old trap address
|
||
move.l TheZone,-(sp) ; push orig heap ptr
|
||
move.l ProcessMgrZone,TheZone ; force into Process Mgr zone for good form
|
||
move.l d0,a5 ; restore a5
|
||
move.l 4(sp),a1 ; get old trap address
|
||
jsr (a1) ; call old trap
|
||
IF (&TYPE('DEBUG') <> 'UNDEFINED') THEN
|
||
cmp.w #noErr,d0 ; check result
|
||
beq.s WentOK ; jump if no error
|
||
_Debugger ; block didn't dispose (registry bad??)
|
||
move.w MemErr,d0 ; restore condition codes
|
||
WentOK
|
||
ENDIF
|
||
move.l (sp)+,TheZone ; restore orig heap
|
||
addq.w #4,sp ; dump old trap address
|
||
rts ; return to programmer
|
||
|
||
NoSwitch
|
||
IF (&TYPE('MM_DEBUG') <> 'UNDEFINED') THEN
|
||
jsr CheckParam ; ensure handle and MP lists OK
|
||
ENDIF
|
||
move.l d0,a5 ; restore a5
|
||
rts ; make old call w/o switching zones
|
||
|
||
ENDPROC
|
||
|
||
;---------------------------------------------------------------------------------------
|
||
; a_handtohand. On numac ROM, put the synthesized fonts in the system heap. We
|
||
; detect them because the numac Font Mgr does a _HandToHand(FMOutHandle) into the app
|
||
; heap to get the new font, and then does a _SetHandleSize to grow it to its final
|
||
; immensity.
|
||
; NOTE: The zone save/restore below can only work if TheZone != ProcessMgrZone originally, since we
|
||
; may cause the sys heap to grow.
|
||
; NOTE: Can't save/restore TheZone across call for all calls because _HandToHand is patched to
|
||
; fix some CQD bug and of course it looks up the stack.
|
||
;
|
||
a_handtohand PROC EXPORT
|
||
IMPORT patchtraps:DATA
|
||
|
||
move.l a5,d0 ; d0 <- orig a5
|
||
movea.l ProcessMgrGlobals,a5 ; get address of our globals
|
||
move.l patchtraps+RomAllPatchTable.Rom78Patches.HANDTOHAND.oldtrap,a1
|
||
move.l d0,a5 ; a5 <- orig a5
|
||
|
||
cmp.l FMgrOutRec+fmOutFontH,a0 ; is it the orig strike?
|
||
bne.s DoOldH2H ; if not, branch
|
||
|
||
HandleSynFont
|
||
move.l TheZone,-(sp) ; save orig heap ptr on stack
|
||
move.l SysZone,TheZone ; else force into sys zone
|
||
jsr (a1) ; do it
|
||
move.l (sp)+,TheZone ; restore orig heap
|
||
rts
|
||
|
||
DoOldH2H
|
||
jmp (a1) ; do it
|
||
|
||
ENDPROC
|
||
|
||
;---------------------------------------------------------------------------------------
|
||
; a_open. Our patch to the file system Open. Several reasons for this:
|
||
; (1) If .Print, make sure the _Open goes thru IOCore
|
||
; (2) Check if the file name is the same as the clipboard name. If so, then
|
||
; force vrefnum to be BootDrive. This is done for MacPaint 1.5. When
|
||
; 1.5 goes away, so should this patch.
|
||
; (3) Call old routine
|
||
;
|
||
; NOTE: Clean up register usage
|
||
a_open PROC EXPORT
|
||
IMPORT patchtraps:DATA
|
||
IMPORT pCurrentProcess:DATA
|
||
|
||
OpenPatchRegs REG d1/a0/a5 ; trap word, param block, and a5
|
||
SavedA0 EQU 4 ; NOTE: This depends on d1/a0/a5 on the stack!
|
||
PrintSlotNo EQU 2
|
||
|
||
movem.l OpenPatchRegs,-(sp) ; save registers
|
||
movea.l ProcessMgrGlobals,a5 ; get address of our globals
|
||
|
||
; check for print driver open
|
||
lea printname,a1 ; point at print name
|
||
move.l ioFileName(a0),a0 ; point at openee...
|
||
clr.l d0
|
||
move.b (a0)+,d0 ; get length
|
||
swap d0 ; into high word
|
||
move.b (a1)+,d0 ; length into low word
|
||
_CmpString ; are they the same?
|
||
move.l SavedA0(sp),a0 ; restore a0 (doesn't change cond codes)
|
||
bne.s NotDotPrint ; not .Print
|
||
|
||
; ah! the print driver IS being opened!
|
||
move.l UTableBase,a1 ; address of unit table
|
||
move.l PrintSlotNo*4(a1),d0 ; get the dce handle for .Print from fixed location
|
||
beq.s CallOldOpen ; if none, no need to force permission
|
||
move.l d0,a1 ; get it back into an addr register
|
||
move.l (a1),d0 ; hdl -> ptr
|
||
beq.s CallOldOpen ; if purged, no need to force permission
|
||
move.l d0,a1 ; get it back into an addr register
|
||
btst #drvrActive,dCtlFlags+1(a1) ; is it active
|
||
bne.s CallOldOpen ; if so, branch (don't force -- IOCore can't handle it)
|
||
move.b #$40,ioPermssn(a0) ; set permissions to 40 to open again...
|
||
bra.s CallOldOpen ; now call through
|
||
|
||
; it's not the print driver, is it MacPaint opening the scrapbook file?
|
||
NotDotPrint
|
||
move.l pCurrentProcess,a1 ; get current app ptr
|
||
move.l 8(a1),d0 ; get current app's signature
|
||
; NOTE: Assumes this offset correct in PEntry!
|
||
cmp.l #'MPNT',d0 ; is it MacPaint?
|
||
bne.s CallOldOpen ; if not, restore regs and do normal trap
|
||
move.l ioFileName(a0),a0 ; get file name
|
||
lea ScrapTag,a1 ; get scrap file name
|
||
clr.l d0
|
||
move.b (a0),d0 ; get length
|
||
swap d0 ; into high word
|
||
move.b (a1),d0 ; length into low word
|
||
_CmpString ; are they the same?
|
||
bne.s CallOldOpen ; if not, don't change the refnum
|
||
|
||
move.l SavedA0(sp),a0 ; restore a0 pointing to iopb
|
||
IF (&TYPE('DEBUG') <> 'UNDEFINED') THEN
|
||
; Check whether MacPaint 2.0 still needs the hack. We officially no longer support 1.5
|
||
; Added this check on 9 Oct 1990.
|
||
move.w BootDrive, d0 ; value of BootDrive
|
||
cmp.w ioDrvNum(a0),d0 ; already set to BootDrive??
|
||
beq.s CallOldOpen ; if so, skip debugger message
|
||
pea MacPaintMsg ; message to show
|
||
_DebugStr ; use power of suggestion on testers
|
||
ENDIF
|
||
move.w BootDrive,ioDrvNum(a0) ; force boot drive to be vrefnum
|
||
|
||
; All done fooling around, so get the darn thing open
|
||
CallOldOpen
|
||
move.l patchtraps+RomAllPatchTable.Rom75Patches.OPEN.oldtrap,a1
|
||
movem.l (sp)+,OpenPatchRegs ; restore registers
|
||
jmp (a1) ; jump down the patch chain
|
||
|
||
IF (&TYPE('DEBUG') <> 'UNDEFINED') THEN
|
||
MacPaintMsg
|
||
dc.b 'This MacPaint still needs our fix (GO will be OK)'
|
||
ENDIF
|
||
|
||
printname
|
||
dc.b '.Print'
|
||
|
||
ENDPROC
|
||
|
||
;---------------------------------------------------------------------------------------
|
||
; GetMapHdlFromRefNum. A utility routine (similar to GetMap() in ROM) that
|
||
; searches the resource map chain whose topHandle is passed on the stack for the
|
||
; refNum on stack. If it finds it, it returns with non-zero in D0. It preserves
|
||
; all registers except D0. Its a C function in that it doesn't strip its parameters.
|
||
;
|
||
; Handle GetMapHdlFromRefNum(short refNum, Handle topMapHdl)
|
||
;
|
||
|
||
GetMapHdlFromRefNum PROC EXPORT
|
||
GetMapRegs REG a0/d1
|
||
moveq.l #0,d0 ; set default return value
|
||
movem.l GetMapRegs,-(sp) ; save registers
|
||
move.w 14(sp),d1 ; get ref num
|
||
bmi.s DoneFindRef ; negative refnum means no maps open
|
||
bne.s GotRefNum ; zero refnum means...
|
||
move.w SysMap,d1 ; ...change it to sys ref num
|
||
GotRefNum
|
||
move.l 16(sp),d0 ; get starting point
|
||
beq.s DoneFindRef ; make sure we can start
|
||
FindRefLoop
|
||
move.l d0,a0 ; put current suspect in a-reg
|
||
move.l (a0),a0 ; dereference handle to pointer
|
||
cmp.w 20(a0),d1 ; does map refnum match target?
|
||
beq.s DoneFindRef ; if so, we're done
|
||
move.l 16(a0),d0 ; get link handle
|
||
bne.s FindRefLoop ; if not nil, try again
|
||
|
||
DoneFindRef
|
||
movem.l (sp)+,GetMapRegs ; restore registers
|
||
rts
|
||
|
||
ENDPROC
|
||
|
||
;---------------------------------------------------------------------------------------
|
||
; a_openrf. OpenRF patch. Override an opWrErr (file already open) if the file is
|
||
; open in another process and the mapForceSysHeap bit is set in the resource map.
|
||
|
||
a_openrf PROC EXPORT
|
||
OpenRFPatchRegs REG a0-a1/a5/d1-d2
|
||
IMPORT patchtraps:DATA
|
||
IMPORT GetMapHdlFromRefNum:CODE
|
||
IMPORT GetMapHdlInOtherChainFromRefNum:CODE
|
||
|
||
; call the original routine, leave immediately if it worked or error wasn't opWrErr
|
||
movea.l ProcessMgrGlobals,a1 ; get address of our globals
|
||
exg.l a5,a1 ; a5 <- our a5, a1 <- old a5
|
||
move.l patchtraps+RomAllPatchTable.Rom75Patches.OPENRF.oldtrap,a5
|
||
exg.l a5,a1 ; a5 <- old a5, old trap addr
|
||
jsr (a1) ; do old guy
|
||
beq.s rf_done ; if no error, done
|
||
cmp.w #opWrErr,d0 ; is it being opened again?
|
||
bne.s rf_done ; if some other error, done
|
||
|
||
; can't override if the file is open by the current fellow
|
||
movem.l OpenRFPatchRegs,-(sp) ; save working registers
|
||
move.l TopMapHndl,-(sp) ; pass top most handle
|
||
moveq #0,d0 ; clear out top word
|
||
move.w ioRefNum(a0),d0 ; get ref num
|
||
move.l d0,-(sp) ; and push on stack as C parameter
|
||
jsr GetMapHdlFromRefNum
|
||
addq #8,sp ; pop off topHandle, ref num
|
||
tst.l d0 ; find it?
|
||
bne.s ORFLeaveErr ; if so, return error
|
||
|
||
; locate map in another process' chain, give error if not found
|
||
movea.l ProcessMgrGlobals,a5 ; get address of our globals
|
||
move.w ioRefNum(a0),d0 ; get ref num (we know d0 is 0 coming in here)
|
||
move.l d0,-(sp) ; push ref num
|
||
jsr GetMapHdlInOtherChainFromRefNum
|
||
addq #4,sp ; ditch argument
|
||
tst.l d0 ; is it in other chain?
|
||
beq.s ORFLeaveErr ; if not, branch
|
||
|
||
; finally, check whether others' map allows sharing (d0 = maphandle)
|
||
move.l d0,a0 ; get hdl into address register
|
||
moveq #0,d0 ; clear out return code
|
||
move.l (a0),a0 ; hdl -> ptr
|
||
btst.b #mapForceSysHeap,MAttr(a0) ; is sharing bit set?
|
||
beq.s ORFLeaveErr ; if not, leave with original error
|
||
|
||
; now, fix up HFS's table so ExitToShell by app that originally opened the file will not
|
||
; close the FCB out from under the other users of the file. That is, untag the FCB in
|
||
; the parallel array.
|
||
|
||
movea.l 8(sp),a0 ; <16> get iopb
|
||
move.l ioFDirIndex(a0),-(sp) ; <16> GetParallelFCB uses ioMisc
|
||
_GetParallelFCBFromRefNum ; <16> Get the parallel FCB
|
||
bnz.s ORFRestore ; <16> Bad refnum, bail out
|
||
move.l ioFDirIndex(a0),a1 ; <16> Get pointer to it
|
||
clr.l (a1)+ ; <16> clear high long of PSN
|
||
clr.l (a1)+ ; <16> clear low long of PSN
|
||
move.l (sp)+,ioFDirIndex(a0) ; <16> Restore ioMisc
|
||
bra.s ORFRestore ; <16> if so, branch (zero out error)
|
||
ORFLeaveErr
|
||
moveq #opWrErr,d0 ; return original error
|
||
ORFRestore
|
||
movem.l (sp)+,OpenRFPatchRegs ; restore working registers
|
||
rf_done
|
||
rts
|
||
|
||
ENDPROC
|
||
|
||
;---------------------------------------------------------------------------------------
|
||
; a_close. Our patch to file system Close. Keeps shared files from being closed out
|
||
; from under the other apps resource chain.
|
||
; Implemented by scanning the resource map chains in all active partitions for the
|
||
; refNum. If we find it and the file is a "Process Mgr compatible print driver", we
|
||
; don't close the file.
|
||
a_close PROC EXPORT
|
||
ClosePatchRegs REG d1-d3/a0-a2
|
||
|
||
IMPORT patchtraps:DATA
|
||
IMPORT GetMapHdlInOtherChainFromRefNum:CODE
|
||
|
||
movem.l ClosePatchRegs,-(sp) ; save working registers
|
||
|
||
move.l a5,a2 ; a2 <- old a5
|
||
movea.l ProcessMgrGlobals,a5 ; get address of our globals
|
||
move.l patchtraps+RomAllPatchTable.Rom75Patches.CLOSE.oldtrap,d3
|
||
|
||
; do even try if call is async. Our structures are not safe, and it is not even necessary
|
||
; to check, since the print drivers are always closed synchronously.
|
||
andi.w #async,d1 ; is this an asynchronous call?
|
||
bne.s ReallyClose ; if so, just let it go
|
||
|
||
; check for "Process Mgr compatible print driver"
|
||
move.w ioRefNum(a0),d0 ; get ref num
|
||
bmi.s ReallyClose ; if driver, branch
|
||
|
||
ext.l d0 ; clear out high word
|
||
move.l d0,-(sp) ; push ref num
|
||
jsr GetMapHdlInOtherChainFromRefNum ; file open elsewhere, too?
|
||
addq #4,sp ; ditch argument
|
||
tst.l d0 ; well, is it?
|
||
beq.s ReallyClose ; if not, branch
|
||
move.l d0,a0 ; get in address register
|
||
move.l (a0),a0 ; hdl -> ptr
|
||
btst.b #mapForceSysHeap,MAttr(a0) ; is sharing bit set?
|
||
bne.s DontReallyClose ; if so, branch
|
||
|
||
ReallyClose
|
||
move.l d3,d0 ; d0 <- old trap addr
|
||
movea.l a2,a5 ; a5 <- old a5
|
||
movem.l (sp)+,ClosePatchRegs ; restore working registers
|
||
move.l d0,-(sp) ; push old trap address
|
||
rts
|
||
|
||
DontReallyClose
|
||
move.l a2,a5 ; a5 <- old a5
|
||
movem.l (sp)+,ClosePatchRegs ; restore working registers
|
||
moveq #noErr,d0 ; everything a-ok
|
||
rts
|
||
|
||
ENDPROC
|
||
|
||
;---------------------------------------------------------------------------------------
|
||
; a_hfsdispatch. Patch CloseWD to not close the WD if it is the one the application was
|
||
; launched into. Patch GetVol, GetVolInfo, and HFSDispatch to compensate for bug in
|
||
; the Mac SE HFS that checks ioNamePtr for validity against MemTop. This part of the
|
||
; patch should be in the system, and for SEs only.
|
||
|
||
PROC
|
||
|
||
IMPORT (patchtraps, initMemTop):DATA
|
||
IMPORT CHECKIFBACKINGWD:CODE
|
||
|
||
EXPORT a_hfsdispatch, a_getvol, a_getvolinfo:CODE
|
||
|
||
HFSPatchRegs REG d0-d2/a0/a5
|
||
a_getvol
|
||
move #RomAllPatchTable.Rom75Patches.GETVOL.oldtrap,d2
|
||
bra.s DoOldCall ; call through
|
||
|
||
a_getvolinfo
|
||
move #RomAllPatchTable.Rom75Patches.GETVOLINFO.oldtrap,d2
|
||
bra.s DoOldCall ; call through
|
||
|
||
a_hfsdispatch
|
||
move #RomAllPatchTable.Rom75Patches.HFSDISPATCH.oldtrap,d2
|
||
cmpi.w #2,d0 ; is call _CloseWD?
|
||
beq.s HandleCloseWD ; if so, branch
|
||
|
||
; call through to the original trap address
|
||
DoOldCall
|
||
move.l a5,a1 ; a1 <- old a5
|
||
movea.l ProcessMgrGlobals,a5 ; get address of our globals
|
||
move.l MemTop, -(sp) ; save current memtop
|
||
move.l initMemTop, MemTop ; this is high enough
|
||
lea patchtraps, a5 ; get patch array address
|
||
move.l (a5,d2.w),a5 ; get old routine
|
||
exg.l a1,a5 ; restore a5, a1 <- old trap
|
||
|
||
if (PsychicTV) then
|
||
move.l a2,-(sp) ; <19>
|
||
endif
|
||
jsr (a1) ; call old trap
|
||
|
||
if (PsychicTV) then
|
||
move.l (sp)+,a2 ; <19>
|
||
endif
|
||
|
||
move.l (sp)+,MemTop ; restore memtop
|
||
rts ; and return to it
|
||
|
||
; it IS _CloseWD, so make our check
|
||
; NOTE: For awhile this code return fBsyErr in the error case. Unfortunately, the
|
||
; released version of the TOPS application actually has an assert that the ioResult
|
||
; of CloseWD is noErr. We roll over on this one, since seeing an error is of little
|
||
; value here anyway (what can the caller do to recover?).
|
||
HandleCloseWD
|
||
movem.l HFSPatchRegs,-(sp) ; save registers
|
||
movea.l ProcessMgrGlobals,a5 ; get address of our globals
|
||
subq.w #2,sp ; make room for ret val
|
||
move.w ioVRefNum(a0),-(sp) ; pass the wd refnum
|
||
jsr CHECKIFBACKINGWD ; can't close this one
|
||
tst.b (sp)+ ; check if uncloseable
|
||
movem.l (sp)+,HFSPatchRegs ; restore regs
|
||
beq.s DoOldCall ; if not, branch
|
||
moveq.l #noErr,d0 ; say it worked
|
||
move.w d0,ioResult(a0) ; and here too
|
||
rts
|
||
|
||
ENDPROC
|
||
|
||
;---------------------------------------------------------------------------------------
|
||
; Volume notification. These patches take care of notifying our list of registered
|
||
; volume aficionados. We patch MountVol, Eject, Offline, and UnmountVol. The patches
|
||
; use identical stacks so they can share the exit and error paths.
|
||
;---------------------------------------------------------------------------------------
|
||
PROC
|
||
|
||
EXPORT a_mountvol, a_eject, a_offline, a_unmountvol:CODE
|
||
IMPORT NotifyVolumeGoodbye, NotifyVolumeAction:CODE
|
||
IMPORT patchtraps:DATA
|
||
|
||
; Get the real refnum here by calling _GetVolInfo. We have to use a new param block
|
||
; because although _UnmountVol theoretically requires the same param block size as
|
||
; _GetVolInfo, it is possible to get away with illegally sending a shorter block to
|
||
; _Unmount, as it does not read or modify the fields at higher offsets. It is not known
|
||
; whether any apps do this, but if we can hypothesize about such a violation then some
|
||
; app has done it. If GetVolInfo returns an error we return -1.
|
||
;
|
||
; On entry: a0 points to HFS volume parameter block
|
||
; On exit: d0 = error code, d1 = vrefnum or -1, CC = tst.w d0
|
||
; Eats: a0, a4, d0, d1
|
||
GetRealRefNum
|
||
lea -ioVQElSize(sp),sp ; save room for new iopb
|
||
move.w #-1,ioVolIndex(sp) ; meaning: use name and vrefnum
|
||
moveq.l #0,d1 ; assume no file name
|
||
move.l ioFileName(a0),ioFileName(sp) ; use same name
|
||
beq.s @0 ; if none, branch
|
||
move.l ioFileName(a0),a4 ; get (good) name ptr
|
||
move.b (a4),d1 ; save length
|
||
@0
|
||
move.w ioVRefnum(a0),ioVRefnum(sp) ; use same vrefnum
|
||
move.l sp,a0 ; point a0 to new block
|
||
_GetVolInfo ; get info
|
||
bmi.s Error ; if err, branch
|
||
tst.b d1 ; was there a (non-zero) file name?
|
||
beq.s @1 ; if not, branch
|
||
move.b d1,(a4) ; otherwise, restore correct length
|
||
@1
|
||
moveq #0,d1 ; clear d1
|
||
move.w ioVRefNum(sp),d1 ; get "real" vrefnum in d1
|
||
doneExit
|
||
tst.w d0 ; restore condition codes
|
||
lea ioVQElSize(sp),sp ; restore room from new iopb
|
||
rts
|
||
|
||
Error
|
||
moveq #-1,d1 ; give impossible refnum
|
||
bra.s doneExit ; and return
|
||
|
||
; a_mountvol. A patch to _MountVol so that we notify the interested parties.
|
||
; NOTE: Special-cases the volOnLinErr error, since this is what happens for AppleShare
|
||
; volumes (MountVol is called via diskinserted event AFTER VCB as been created).
|
||
a_mountvol
|
||
move.l a5,a1 ; save a5
|
||
movea.l ProcessMgrGlobals,a5 ; get address of our globals
|
||
move.l patchtraps+RomAllPatchTable.Rom75Patches.MOUNTVOL.oldtrap,a5 ; get old _MountVol routine
|
||
exg.l a1,a5 ; a1 = trap address, a5 = olda5
|
||
move.l a0,-(sp) ; save param block
|
||
jsr (a1) ; mount that volume!
|
||
move.l (sp)+,a0 ; retrieve param block
|
||
move.w d0,d0 ; test OSErr result
|
||
beq.s mounted ; jump if mounted
|
||
cmp #volOnLinErr,d0 ; is it an acceptable error?
|
||
bne.s leave ; jump if drive failed to mount
|
||
|
||
; mount worked, try to inform everyone
|
||
mounted
|
||
moveq #VNMounted,d1 ; get notification code
|
||
moveq #0,d2 ; clear the air
|
||
move.w ioVRefNum(a0),d2 ; get refnum
|
||
bra.s haveRefNum ; continue
|
||
|
||
; d0 == result of trap
|
||
haveNotice
|
||
move.l (sp)+,d2 ; get vrefnum again
|
||
bmi.s leave ; jump if vrefnum not known
|
||
haveRefNum
|
||
move.l d0,-(sp) ; save result
|
||
move.l a5,-(sp) ; save a5 again
|
||
movea.l ProcessMgrGlobals,a5 ; get address of our globals
|
||
pea $0 ; push nil for stopper
|
||
move.l d0,-(sp) ; push result
|
||
move.l d1,-(sp) ; push notice
|
||
move.l d2,-(sp) ; pass refnum as a param to the C routine
|
||
jsr NotifyVolumeAction ; notify everyone of the result
|
||
lea 16(sp),sp ; get rid of C params
|
||
|
||
move.l (sp)+,a5 ; restore a5 again
|
||
move.l (sp)+,d0 ; get result
|
||
leave
|
||
rts
|
||
|
||
SaveNotifyRegs REG d1-d3/a0/a4/a5
|
||
|
||
; a_offline. Our patch to _Offline sends out notification before and after the trap.
|
||
a_offline
|
||
movem.l SaveNotifyRegs,-(sp) ; save regs we'll use
|
||
movea.l ProcessMgrGlobals,a5 ; get address of our globals
|
||
move.l patchtraps+RomAllPatchTable.Rom75Patches.OFFLINE.oldtrap,d3 ; get old _Offline routine
|
||
bra.s shareOfflineEject
|
||
|
||
; a_eject. Our patch to _Eject sends out notification before and after the trap (note
|
||
; that we can send no notification if the volume has already been unmounted, but then
|
||
; we shouldn't have to!).
|
||
a_eject
|
||
movem.l SaveNotifyRegs,-(sp) ; save regs we'll use
|
||
movea.l ProcessMgrGlobals,a5 ; get address of our globals
|
||
move.l patchtraps+RomAllPatchTable.Rom75Patches.EJECT.oldtrap,d3 ; get old _Offline routine
|
||
|
||
shareOfflineEject
|
||
jsr GetRealRefNum ; get the real vrefnum in d1
|
||
bmi.s doOldCall1 ; jump if error
|
||
|
||
; send out notification of intent
|
||
move.l d1,-(sp) ; save refnum for later
|
||
clr.l -(sp) ; pass false for forced parameter
|
||
moveq #VNOffline,d0 ; secondary notice if aborted
|
||
move.l d0,-(sp) ; push it
|
||
moveq #VNAboutToGoOffline,d0 ; primary notice to send
|
||
move.l d0,-(sp) ; push it
|
||
move.l d1,-(sp) ; pass refnum as a param to the C routine
|
||
jsr NotifyVolumeGoodbye ; let everyone know
|
||
lea 16(sp),sp ; get rid of C params
|
||
move.l (sp)+,d1 ; get refnum back
|
||
move.w d0,d0 ; test OSErr result
|
||
bne.s allDone ; jump if someone complained
|
||
|
||
; got the high sign
|
||
doOldCall1
|
||
move.l d1,d0 ; copy refnum to safe reg
|
||
move.l d3,a1 ; get trap address
|
||
movem.l (sp)+,SaveNotifyRegs ; restore regs we used
|
||
move.l d0,-(sp) ; save refnum
|
||
jsr (a1) ; do old routine
|
||
|
||
; send out the result notification
|
||
moveq #VNOffline,d1 ; notification code
|
||
bra.s haveNotice ; share code
|
||
|
||
; unusual exit
|
||
allDone
|
||
movem.l (sp)+,SaveNotifyRegs ; restore trap word, iopb ptr, scratch addr reg, old a5
|
||
bra.s leave ; use common exit
|
||
|
||
; _UnmountVol. Our patch to _UnmountVol sends out notification before and after the
|
||
; actual unmount.
|
||
a_unmountvol
|
||
movem.l SaveNotifyRegs,-(sp) ; save regs we'll use
|
||
movea.l ProcessMgrGlobals,a5 ; get address of our globals
|
||
|
||
btst #HFSBit,d1 ; is this _Unmount forced?
|
||
sne d3 ; save answer for later parameter
|
||
jsr GetRealRefNum ; get the real vrefnum in d1
|
||
bmi.s doOldCall2 ; jump if error
|
||
|
||
; send out notification of intent
|
||
move.l d1,-(sp) ; save refnum for later
|
||
move.l d3,-(sp) ; say whether goodbye is forced
|
||
moveq #VNUnmount,d0 ; secondary notice if aborted
|
||
move.l d0,-(sp) ; push it
|
||
moveq #VNAboutToUnmount,d0 ; primary notice to send
|
||
move.l d0,-(sp) ; push it
|
||
move.l d1,-(sp) ; pass refnum as a param to the C routine
|
||
jsr NotifyVolumeGoodbye ; let everyone know
|
||
lea 16(sp),sp ; get rid of C params
|
||
move.l (sp)+,d1 ; get refnum back
|
||
move.w d0,d0 ; test OSErr result
|
||
bne.s allDone ; jump if someone complained
|
||
|
||
; got the high sign to unmount
|
||
doOldCall2
|
||
move.l d1,d0 ; copy refnum to safe reg
|
||
move.l patchtraps+RomAllPatchTable.Rom75Patches.UNMOUNTVOL.oldtrap,a1 ; get old _UnmountVol routine
|
||
movem.l (sp)+,SaveNotifyRegs ; restore regs we used
|
||
move.l d0,-(sp) ; save refnum
|
||
jsr (a1) ; do old routine
|
||
|
||
; send out the result notifications
|
||
moveq #VNUnmount,d1 ; notification code
|
||
bra haveNotice ; share code
|
||
|
||
ENDPROC
|
||
|
||
;---------------------------------------------------------------------------------------
|
||
; a_getscrap. Prevent call-through and return memFullErr if the current SCRAPINFO is
|
||
; not valid for the current process. Use our handy C routine since it can look better
|
||
; at the structures.
|
||
a_getscrap PROC EXPORT
|
||
IMPORT IsScrapOwnedByCurrentProcess:CODE
|
||
IMPORT patchtraps:DATA
|
||
GETSCRAPPARAMSIZE EQU (3*4)
|
||
|
||
move.l a5,-(sp) ; save callers a5
|
||
movea.l ProcessMgrGlobals,a5 ; get address of our globals
|
||
jsr IsScrapOwnedByCurrentProcess ; ask C routine what to do
|
||
move.l patchtraps+RomAllPatchTable.Rom75Patches.GETSCRAP.oldtrap,a0
|
||
movea.l (sp)+,a5 ; restore caller's a5
|
||
tst.w d0 ; check Boolean result
|
||
bne.s CallThrough ; jump if scrap OK to get
|
||
|
||
DontCallThrough
|
||
movea.l (sp)+,a0 ; get return address
|
||
lea GETSCRAPPARAMSIZE(sp),sp ; dump params
|
||
move.l #memFullErr,(sp) ; set OSErr function result
|
||
CallThrough
|
||
jmp (a0) ; return to caller
|
||
|
||
ENDPROC
|
||
|
||
;---------------------------------------------------------------------------------------
|
||
; a_zeroscrap and a_putscrap. Increment global counter so that next foreground switch
|
||
; will cause scrap to migrate to new front app. We call DisposeOrphanedScrap since the
|
||
; orphaned scrap will no longer be needed (the caller is building a new scrap).
|
||
PROC
|
||
|
||
EXPORT a_zeroscrap, a_putscrap:CODE
|
||
IMPORT (patchtraps, cutCopyCount):DATA
|
||
IMPORT DisposeOrphanedScrap:CODE
|
||
|
||
a_zeroscrap
|
||
move.w #RomAllPatchTable.Rom75Patches.ZEROSCRAP.oldtrap,d0
|
||
bra.s shareInc ; share code
|
||
|
||
a_putscrap
|
||
move.w #RomAllPatchTable.Rom75Patches.PUTSCRAP.oldtrap,d0
|
||
shareInc
|
||
move.l a5,a1 ; save a5
|
||
movea.l ProcessMgrGlobals,a5 ; get address of our globals
|
||
lea patchtraps,a0 ; get patch array address
|
||
move.l (a0,d0.w),-(sp) ; push old routine for later RTS
|
||
move.l a1,-(sp) ; save old a5 across call
|
||
addq.w #1,cutCopyCount ; inc word-sized counter (overflow OK)
|
||
jsr DisposeOrphanedScrap ; orphaned scrap is no longer needed
|
||
movea.l (sp)+,a5 ; restore a5
|
||
rts ; return to original trap
|
||
|
||
ENDPROC
|
||
|
||
;---------------------------------------------------------------------------------------
|
||
; a_pack3. Patch StandardFile to sneak in a puppet string file specification.
|
||
a_pack3 PROC EXPORT
|
||
IMPORT IsForcedOpen:CODE
|
||
IMPORT patchtraps:DATA
|
||
|
||
; Offsets from selector param to given param in _SFGetFile (_SFPGetFile must add 6)
|
||
OFFSET_SFREPLY EQU 0
|
||
OFFSET_DLGHOOK EQU 4
|
||
OFFSET_TYPELIST EQU 8
|
||
OFFSET_NUMTYPES EQU 12
|
||
OFFSET_FILEFILTER EQU 14
|
||
|
||
SF_PARAMS_LEN EQU 28 ; size of parameters for SFGetFile
|
||
SFP_PARAMS_LEN EQU 34 ; size of parameters for SFPGetFile
|
||
|
||
move.w 4(sp),d0 ; get routine selector
|
||
cmp.w #sfGetFile,d0 ; is it _SFGetFile?
|
||
beq.s CheckSFGetFile ; if so, branch
|
||
cmp.w #sfPGetFile,d0 ; is it _SFGetFile?
|
||
bne.s NormalPack3 ; if not, jump to old
|
||
|
||
lea 6+4(sp),a0 ; point past ret addr, selector, and extra param
|
||
move.w (a0)+,d0 ; get the dialog res ID
|
||
ext.l d0 ; and make it a long for C call
|
||
move.w #SFP_PARAMS_LEN,-(sp) ; put length of params on stack
|
||
bra.s CheckBothGetFiles ; and branch to merge point
|
||
|
||
CheckSFGetFile
|
||
lea 6(sp),a0 ; point past ret addr and selector
|
||
move.w #SF_PARAMS_LEN,-(sp) ; put length of params on stack
|
||
move.l #getDlgID,d0 ; just use standard dialog res ID
|
||
CheckBothGetFiles
|
||
move.l d0,-(sp) ; push the dialog ID
|
||
move.l OFFSET_SFREPLY(a0),-(sp) ; push pSFReply
|
||
move.l OFFSET_TYPELIST(a0),-(sp) ; push sfTypeList
|
||
move.l OFFSET_DLGHOOK(a0),-(sp) ; push dlgHook
|
||
move.w OFFSET_NUMTYPES(a0),d0 ; get numTypes
|
||
ext.l d0 ; extend numTypes
|
||
move.l d0,-(sp) ; push extended numTypes
|
||
move.l OFFSET_FILEFILTER(a0),-(sp) ; push fileFilterFnc
|
||
jsr IsForcedOpen ; check if we should force the result
|
||
|
||
; NOTE: register d2 is still valid here because the above is a C routine
|
||
lea 24(sp),sp ; ditch the params
|
||
move.w (sp)+,d2 ; get the size passed to this guy back into d2
|
||
tst.b d0 ; is it forced open?
|
||
beq.s NormalPack3 ; if not, jump to old
|
||
move.l (sp)+,a0 ; grab the ret addr
|
||
add.w d2,sp ; ditch the args (d2 holds size of them)
|
||
jmp (a0) ; and return
|
||
|
||
; False alarm. Call the old trap.
|
||
NormalPack3
|
||
move.l a5,a0 ; save old a5
|
||
movea.l ProcessMgrGlobals,a5 ; get address of our globals
|
||
move.l patchtraps+RomAllPatchTable.Rom75Patches.PACK3.oldtrap,a1 ; get old trap routine
|
||
exg.l a0,a5 ; a5 <- old a5
|
||
jmp (a1) ; and go do it
|
||
|
||
ENDPROC
|
||
|
||
;---------------------------------------------------------------------------------------
|
||
; a_drawmenubar. Patch to make sure that the menu is only drawn by the foreground
|
||
; application, or the application coming to the foreground.
|
||
CS_GENERATE_DEACTIVATE1 EQU 3
|
||
CS_GENERATE_DEACTIVATE2 EQU 4
|
||
a_drawmenubar PROC EXPORT
|
||
IMPORT (patchtraps, pCurrentProcess, pFrontProcess, coercionState):DATA
|
||
|
||
move.l a5,a0 ; save a5
|
||
movea.l ProcessMgrGlobals,a5 ; get address of our globals
|
||
move.l pCurrentProcess, d0 ; pointer to PEntry of current process
|
||
cmp.l pFrontProcess, d0 ; is current same as front?
|
||
bne.s DontCallOld ; if not, we can't do it!
|
||
move.w coercionState, d0 ; get global coercion state
|
||
cmp.w #CS_GENERATE_DEACTIVATE1, d0 ; are we deactivating?
|
||
beq.s DontCallOld
|
||
cmp.w #CS_GENERATE_DEACTIVATE2, d0 ; are we deactivating?
|
||
beq.s DontCallOld
|
||
move.l patchtraps+RomAllPatchTable.Rom75Patches.DRAWMENUBAR.oldtrap,-(sp) ; get old trap routine
|
||
DontCallOld
|
||
movea.l a0,a5 ; restore a5
|
||
rts ; return
|
||
|
||
ENDPROC
|
||
|
||
;---------------------------------------------------------------------------------------
|
||
; a_postevent. Our patch to PostEvent to catch users trying to break from the current
|
||
; application. The two possibilities are high-level debugger and the ExitToShell.
|
||
ESC_KEYCODE EQU $35
|
||
BACKTICK_KEYCODE EQU $32
|
||
a_postevent PROC EXPORT
|
||
IMPORT (patchtraps, pCurrentProcess, pDebugProcess, debugControlKeyCode, debugKeyTryCount, MachineHasMacPlusKbd):DATA
|
||
|
||
move.l a5,d2 ; save old a5
|
||
movea.l ProcessMgrGlobals,a5 ; get address of our globals
|
||
move.l patchtraps+RomAllPatchTable.Rom75Patches.POSTEVENT.oldtrap,a1 ; get old trap routine
|
||
|
||
; look for keydown event with specific modifier combo
|
||
cmp.w #keyDwnEvt,a0 ; is it really a keydown?
|
||
bne.s CallOldTrap ; if not, branch
|
||
btst.b #7,KeyMap+6 ; check for cmd key
|
||
beq.s CallOldTrap ; if not down, branch
|
||
btst.b #2,KeyMap+7 ; check for option key
|
||
beq.s CallOldTrap ; if not down, branch
|
||
|
||
; we're close… is it the "break" key?
|
||
move.l d0,-(sp) ; save old d0 on stack
|
||
lsr.w #8,d0 ; put key code in lowest byte
|
||
tst.w MachineHasMacPlusKbd ; older keyboard?
|
||
bne.s NotADB ; jump if so (it can't have escape key)
|
||
cmp.b #ESC_KEYCODE,d0 ; is this the right key?
|
||
bne.s NotBreakKey ; if not, branch
|
||
KillCurrentProcess
|
||
tst.l pCurrentProcess ; is there an app running?
|
||
beq.s FixStackAndGoOlds ; if not, branch
|
||
|
||
; SysError handler is not re-entrant, so we must prevent it
|
||
move.b MacJmpFlag,d1 ; get possible debugger flag word
|
||
cmp.b #UNIMP,d1 ; is this an implemented flag byte?
|
||
bne.s HaveFlags ; if so, use it
|
||
move.b MacJmp,d1 ; else, use traditional flag
|
||
HaveFlags
|
||
btst #7,d1 ; already in?
|
||
bne.s FixStackAndGoOlds ; if so, ignore this key
|
||
|
||
; make sure foreground process is alert enough to remove the confirmation dialog
|
||
subq.l #8,sp ; allocate storage
|
||
clr.w -(sp) ; allocate OSErr result
|
||
pea 2(sp) ; push address of PSN
|
||
_GetFrontProcess ; find out who's singing
|
||
move.w (sp),d0 ; anyone?
|
||
bne.s DoneWaking ; jump if error
|
||
pea 2(sp) ; push address of PSN
|
||
_WakeupProcess ; roust the front process
|
||
DoneWaking
|
||
add.l #10,sp ; clean up the parms
|
||
|
||
; confirm our emergency cleanup with the user
|
||
move.l d2,(sp) ; save old a5 on stack (where d0 was)
|
||
move.l #dsForcedQuit,d0 ; call SysError to confirm the kill
|
||
_SysError
|
||
|
||
; shared exit when SysError was called
|
||
AfterSysError
|
||
moveq #evtNotEnb,d0 ; tell caller no event was posted!
|
||
move.l (sp)+,a5 ; get old a5 back
|
||
rts ; and return w/out ever calling old routine
|
||
|
||
; shared exit when false alarm, just call the old trap
|
||
FixStackAndGoOlds
|
||
move.l (sp)+,d0 ; restore d0
|
||
CallOldTrap
|
||
move.l d2,a5 ; a5 <- old a5
|
||
jmp (a1) ; go do it
|
||
|
||
; using older keyboard without escape key, so check for alternate key
|
||
NotADB
|
||
cmp.b #BACKTICK_KEYCODE,d0 ; is it the right key?
|
||
beq.s KillCurrentProcess ; jump if so
|
||
|
||
; is it the debugger key?
|
||
NotBreakKey
|
||
tst.l pDebugProcess ; does debugger exist?
|
||
beq.s FixStackAndGoOlds ; if not, debugControlKeyCode is invalid
|
||
cmp.b debugControlKeyCode,d0 ; is this the right key?
|
||
bne.s FixStackAndGoOlds ; if not, branch
|
||
add.w #1,debugKeyTryCount ; bump key counter
|
||
ble.s FixStackAndGoOlds ; if hit 1 then we can't get in from _WNE
|
||
|
||
moveq #-1,d0
|
||
move.w d0,debugKeyTryCount ; reset it to -1
|
||
move.l d2,(sp) ; save old a5 on stack (where d0 was)
|
||
moveq.l #enterDebugger,d0 ; call SysError to enter debugger
|
||
_SysError
|
||
bra.s AfterSysError ; share code
|
||
|
||
ENDPROC
|
||
|
||
;---------------------------------------------------------------------------------------
|
||
; a_launch. Our patch to Launch. Just calls the C routine.
|
||
; NOTE: The C routine ios
|
||
a_launch PROC EXPORT
|
||
|
||
IMPORT C_LAUNCH:CODE
|
||
|
||
clr.l -(sp) ; allocate return storage
|
||
move.l a0,-(sp) ; pass c_launch the pointer
|
||
jsr C_LAUNCH ; call the C routine
|
||
move.l (sp)+,d0 ; put result in output register
|
||
rts
|
||
|
||
ENDPROC
|
||
|
||
SEG 'kernel_segment'
|
||
|
||
;---------------------------------------------------------------------------------------
|
||
; a_exittoshell. Glue to call C routine, but using our own stack.
|
||
a_exittoshell PROC EXPORT
|
||
IMPORT BeginKernelStack, C_EXITTOSHELL:CODE
|
||
|
||
move.l a5,d1 ; save current a5
|
||
movea.l ProcessMgrGlobals,a5 ; get address of our globals
|
||
jsr BeginKernelStack ; switch to our stack
|
||
movea.l d1,a5 ; restore a5 for C routine to use
|
||
jsr C_EXITTOSHELL ; make call that don't come back!
|
||
move.l #dsLoadErr,d0 ; oh no!
|
||
_SysError ; we returned from ExitToShell!!
|
||
rts
|
||
|
||
ENDPROC
|
||
|
||
SEG 'Main'
|
||
|
||
;---------------------------------------------------------------------------------------
|
||
; a_osreserved. Implement the do-nothing trap. Here for future use/removal.
|
||
a_osreserved PROC EXPORT
|
||
rts
|
||
|
||
ENDPROC
|
||
|
||
;---------------------------------------------------------------------------------------
|
||
; a_wakeup. Our patch to Wakeup. Just calls the C routine.
|
||
a_wakeup PROC EXPORT
|
||
|
||
IMPORT c_Wakeup:CODE
|
||
|
||
move.l d0,-(sp) ; pass c_Wakeup the pid
|
||
jsr c_Wakeup ; call the C routine
|
||
addq.w #4,sp ; get past my C parameter
|
||
rts
|
||
|
||
ENDPROC
|
||
|
||
;---------------------------------------------------------------------------------------
|
||
; MyPrefixRelString. Glue to call RelString and make it appear that the second
|
||
; string is the same length as the first string.
|
||
; The C prototype is:
|
||
;
|
||
; short MyPrefixRelString(StringPtr pStr1, StringPtr pStr2);
|
||
;
|
||
MyPrefixRelString PROC EXPORT
|
||
move.l 4(sp),a0 ; get first string in a0
|
||
move.l 8(sp),a1 ; get second string in a1
|
||
moveq.l #0,d0 ; clear out d0
|
||
move.b (a0),d0 ; d0.w <- length of first string
|
||
swap d0
|
||
move.b (a0)+,d0 ; d0.w <- length of first string
|
||
addq.w #1,a1 ; pass by length byte of str2
|
||
_RelString ; call it
|
||
rts ; return value already in d0
|
||
|
||
ENDPROC
|
||
|
||
;---------------------------------------------------------------------------------------
|
||
; MyRelString. Glue to call RelString since args are in registers.
|
||
; The C prototype is:
|
||
;
|
||
; short MyRelString(StringPtr pStr1, StringPtr pStr2);
|
||
;
|
||
MyRelString PROC EXPORT
|
||
move.l 4(sp),a0 ; get first string in a0
|
||
move.l 8(sp),a1 ; get second string in a1
|
||
moveq.l #0,d0 ; clear out d0
|
||
move.b (a0)+,d0 ; d0.w <- length of first string
|
||
swap d0
|
||
move.b (a1)+,d0 ; d0.w <- length of second string
|
||
_RelString ; call it
|
||
rts ; return value already in d0
|
||
|
||
ENDPROC
|
||
|
||
;---------------------------------------------------------------------------------------
|
||
; a_checkload. Catch CheckLoad before entry and force all system resources into the
|
||
; system heap by setting the ResSysHeap bit.
|
||
; NOTE: An improvement here would be to have the CheckLoad patch just set & restore
|
||
; THEZONE = SYSZONE around calling through to the original CheckLoad. This way you
|
||
; could avoid setting and hiding attribute bits. It is rumored that system pieces
|
||
; besides the Resource Mgr use the resSysHeap bit to figure out whether the resource is
|
||
; in the system heap. Haven't seen it myself. RsrcZoneInit does it, but RsrcZoneInit
|
||
; is not called under Process Mgr.
|
||
; Input : a2 = pointer to resource entry
|
||
; a4 = handle to resource map
|
||
; Eats a0
|
||
|
||
; <14> This macro is here because including ResourceMgrPriv.a confuses
|
||
; a lot of things.
|
||
|
||
Macro
|
||
_IsThisASystemResourceMap
|
||
selectIsThisASystemResourceMap: equ -1
|
||
DoDispatch _ResourceDispatch,selectIsThisASystemResourceMap
|
||
EndM
|
||
|
||
a_checkload PROC EXPORT
|
||
EXPORT SetOldCheckLoad:CODE
|
||
|
||
subq #2,sp
|
||
move.l a4,-(sp)
|
||
_IsThisASystemResourceMap ; Is this the system map or system override?
|
||
tst.b (sp)+
|
||
bne.s system_rsrc ; if so, branch
|
||
move.l (a4),a0 ; a0 <- ptr to map
|
||
btst.b #mapForceSysHeap,MAttr(a0) ; should all entries in map go in system heap?
|
||
beq.s jumptoold ; if not, branch
|
||
system_rsrc
|
||
bset #ResSysHeap,RAttr(a2) ; get into the system heap (and stay there!)
|
||
bne.s jumptoold ; branch if was already set
|
||
bset #ResSysRef,RAttr(a2) ; mark that shouldn't be permanent
|
||
jumptoold
|
||
move.l old_checkload,-(sp) ; get address of old routine
|
||
rts ; and go there
|
||
|
||
old_checkload dc.l 0 ; address of old CheckLoad vector
|
||
|
||
; SetOldCheckLoad. Save the specified value as the chain address of CheckLoad.
|
||
; I think this is just to save loading A5 to look in the patchtraps table. Brilliant!
|
||
SetOldCheckLoad
|
||
lea old_checkload,a0
|
||
move.l 4(sp),(a0) ; parameter is address of old checkload
|
||
rts
|
||
|
||
ENDPROC
|
||
|
||
;---------------------------------------------------------------------------------------
|
||
; These routines have been moved out of rsrc_common to allow for their reentrancy,
|
||
; which is mandated by the MPW shell, which can get a grow zone request in
|
||
; _UpdateResFile, which might cause it to call _OpenResFile, which leads to
|
||
; _UpdateResFile. Although this is really an MPW bug, they claim it's the
|
||
; cornerstone of their memory management. Hmmm...
|
||
|
||
; a_updateresfile. Call the patch written in C.
|
||
a_updateresfile PROC EXPORT
|
||
IMPORT C_UPDATERESFILE:CODE
|
||
|
||
movem.l d0-d2/a1,-(sp) ; save regs
|
||
move.w 20(sp),-(sp) ; push the refnum
|
||
jsr C_UPDATERESFILE ; do it
|
||
movem.l (sp)+,d0-d2/a1 ; restore regs
|
||
move.l (sp)+,a0 ; get ret addr
|
||
addq.w #2,sp ; get rid of refnum
|
||
jmp (a0) ; and return
|
||
|
||
ENDPROC
|
||
|
||
; a_getresattrs. Call the patch written in C.
|
||
a_getresattrs PROC EXPORT
|
||
IMPORT C_GETRESATTRS:CODE
|
||
|
||
movem.l d0-d2/a1,-(sp) ; save regs
|
||
subq.w #2,sp ; make room for the result
|
||
move.l 22(sp),-(sp) ; push the handle
|
||
jsr C_GETRESATTRS ; do it
|
||
move.w (sp)+,24(sp) ; set real ret val from ours
|
||
movem.l (sp)+,d0-d2/a1 ; restore regs
|
||
move.l (sp)+,a0 ; get ret addr
|
||
addq.w #4,sp ; get rid of handle
|
||
jmp (a0) ; and return
|
||
|
||
ENDPROC
|
||
|
||
; a_releaseresource. Call the patch written in C.
|
||
a_releaseresource PROC EXPORT
|
||
IMPORT C_RELEASERESOURCE:CODE
|
||
|
||
movem.l d0-d2/a1,-(sp) ; save regs
|
||
move.l 20(sp),-(sp) ; push the handle
|
||
jsr C_RELEASERESOURCE ; do it
|
||
movem.l (sp)+,d0-d2/a1 ; restore regs
|
||
move.l (sp)+,a0 ; get ret addr
|
||
addq.w #4,sp ; get rid of handle
|
||
jmp (a0) ; and return
|
||
|
||
ENDPROC
|
||
|
||
; a_getnamedresource. Call the patch written in C.
|
||
a_getnamedresource PROC EXPORT
|
||
IMPORT C_GETNAMEDRESOURCE:CODE
|
||
|
||
movem.l d0-d2/a1,-(sp) ; save regs
|
||
subq.w #4,sp ; make room for our result
|
||
move.l 28(sp),-(sp) ; push the type
|
||
move.l 28(sp),-(sp) ; push the name ptr
|
||
jsr C_GETNAMEDRESOURCE ; do it
|
||
move.l (sp)+,28(sp) ; put our retval in real one
|
||
movem.l (sp)+,d0-d2/a1 ; restore regs
|
||
move.l (sp)+,a0 ; get ret addr
|
||
addq.w #8,sp ; get rid of params
|
||
jmp (a0) ; and return
|
||
|
||
ENDPROC
|
||
|
||
; a_sizersrc. Call the patch written in C.
|
||
a_sizersrc PROC EXPORT
|
||
IMPORT C_SIZERSRC:CODE
|
||
|
||
movem.l d0-d2/a1,-(sp) ; save regs
|
||
subq.w #4,sp ; make room for the result
|
||
move.l 24(sp),-(sp) ; push the handle
|
||
jsr C_SIZERSRC ; do it
|
||
move.l (sp)+,24(sp) ; set real ret val from ours
|
||
movem.l (sp)+,d0-d2/a1 ; restore regs
|
||
move.l (sp)+,a0 ; get ret addr
|
||
addq.w #4,sp ; get rid of handle
|
||
jmp (a0) ; and return
|
||
|
||
ENDPROC
|
||
|
||
;---------------------------------------------------------------------------------------
|
||
; a_getresource. Patch GetResource to get correct PDEF. This has to be assembler
|
||
; because System 4.1 and 4.2 _GetResource patches look at return addresses on the stack.
|
||
a_getresource PROC EXPORT
|
||
IMPORT MyRelString:CODE
|
||
IMPORT patchtraps:DATA
|
||
|
||
moveq.l #0,d0
|
||
move.b 5(sp),d0 ; get res id
|
||
move.l 6(sp),a0 ; get res type
|
||
move.l a5,-(sp) ; save old a5 on stack
|
||
movea.l ProcessMgrGlobals,a5 ; get address of our globals
|
||
|
||
; patch to get correct print driver based on current printer assignments
|
||
cmp.l #'PDEF',a0 ; is this a potential print entry point?
|
||
bne.s DoRealCall ; if not, branch
|
||
move.w 8(sp),d0 ; get res id (whole word)
|
||
cmp.w #7+1,d0 ; is it 0-7?
|
||
bcc.s DoRealCall ; if not, branch to real call
|
||
|
||
movem.l d1-d2/a1,-(sp) ; save work regs
|
||
lea -10(sp),sp ; room for 2 pointers + return value (on bottom)
|
||
pea 6(sp) ; push ptr to one ptr
|
||
pea 6(sp) ; push ptr to the other ptr
|
||
_MFGetPrTypeStrings ; get local and global ref nums
|
||
moveq.l #0,d0 ; assume pr types the same
|
||
tst.b (sp)+ ; is pr type locked for this guy?
|
||
beq.s @0 ; if so, branch (treat as strings equal)
|
||
jsr MyRelString ; are they the same?
|
||
move.l 4(sp),d2 ; save local name
|
||
|
||
; get here with condition codes saying whether the types are the same
|
||
@0
|
||
addq.w #8,sp ; get rid of the 2 string ptrs
|
||
tst.w d0 ; are they the same?
|
||
beq.s GotoPDEF ; if equal, branch
|
||
|
||
; Set the printer type for the current process, give a _Close call to the .Print driver, and
|
||
; then give it an _Open call. If the driver is not in yet, _Close will return an error which
|
||
; we ignore. If it is in, it simple passes it along to the appropriate .XPrint.
|
||
subq.w #2,sp ; room for return result
|
||
move.l d2,-(sp) ; push local name
|
||
move.w BootDrive,-(sp) ; has to be in sys folder
|
||
move.b #fsCurPerm,-(sp) ; default arg (need to r/w probably)
|
||
_OpenRFPerm ; bring to front (already opened)
|
||
move.w (sp)+,d2 ; save the refnum
|
||
_PrDrvrOpen ; Open new driver, thus closing old one
|
||
move.w d2,-(sp) ; push refnum of (old) local pr type name
|
||
_CloseResFile ; close old driver's res file
|
||
move.l TopMapHndl,a0 ; get top map
|
||
move.l (a0),a0 ; hdl -> ptr
|
||
move.l MRefNum(a0),CurMap ; force new guy (who is at top) to be current
|
||
GotoPDEF
|
||
movem.l (sp)+,d1-d2/a1 ; restore work regs
|
||
|
||
; enough of this! call the real routine!
|
||
DoRealCall
|
||
move.l patchtraps+RomAllPatchTable.Rom75Patches.GETRESOURCE.oldtrap,a0
|
||
move.l (sp)+,a5 ; restore old a5
|
||
jmp (a0) ; and go to old routine
|
||
|
||
PrintName dc.b '.Print'
|
||
|
||
ENDPROC
|
||
|
||
;---------------------------------------------------------------------------------------
|
||
; a_setgrowzone. Our patch to SetGrowZone. Calls a C routine to act on it. That routine
|
||
; returns an address we should call through to. Nil if we shouldn't. We, rather than
|
||
; the C routine, need to do the call, since it requires register setup.
|
||
a_setgrowzone PROC EXPORT
|
||
IMPORT SafeSetGrowZone:CODE
|
||
SGZPatchRegs REG d1-d2/a0-a1 ; volatile regs in C routine
|
||
|
||
movem.l SGZPatchRegs,-(sp) ; save registers
|
||
move.l a0,-(sp) ; put proc ptr as only arg
|
||
jsr SafeSetGrowZone ; and do it
|
||
addq.w #4,sp ; get rid of c param
|
||
movem.l (sp)+,SGZPatchRegs ; restore registers
|
||
tst.l d0 ; check for chain-through address
|
||
beq.s SGZDone ; exit if none (BTW: d0.w == noErr!!)
|
||
move.l d0,-(sp) ; push chain address for RTS
|
||
SGZDone
|
||
rts ; return to caller or old trap
|
||
|
||
ENDPROC
|
||
|
||
;---------------------------------------------------------------------------------------
|
||
; GetSysHeapString. Get a copy of the given string in the system heap.
|
||
; The C prototype is:
|
||
;
|
||
; StringPtr GetSysHeapString(StringPtr pStr);
|
||
;
|
||
GetSysHeapString PROC EXPORT
|
||
|
||
clr.l -(sp) ; assume retval is failure
|
||
move.l 8(sp),a0 ; param is src
|
||
moveq.l #1,d0 ; add 1 to...
|
||
add.b (a0),d0 ; ...string length to get block len
|
||
move.l d0,d1 ; save length
|
||
move.l a0,a1 ; save ptr
|
||
_NewPtr sys ; get space in system heap
|
||
bne.s GSHSDone ; if failure, branch
|
||
exg.l a0,a1 ; switch src/dest
|
||
move.l a1,(sp) ; and do the return value
|
||
move.l d1,d0 ; save length
|
||
_BlockMove
|
||
GSHSDone
|
||
move.l (sp)+,d0 ; pop retval into d0
|
||
rts
|
||
|
||
ENDPROC
|
||
|
||
|
||
SEG 'Main'
|
||
|
||
;------------------------------------------------------------------------------------
|
||
; Process Mgr implements the gestaltOSAttr selector. Below are the definitions, the
|
||
; selector routine, and the code to install it. The selector routine is supposed to
|
||
; sit in the system heap so it can be executed directly by applications. The installer
|
||
; copies the routine there, and was written in assembler to ensure that the effective
|
||
; address we pass is that of the routine itself, rather than its jump table address
|
||
; (which wouldn't be in the system heap).
|
||
;------------------------------------------------------------------------------------
|
||
|
||
OurGestaltValue EQU (1 << gestaltSysZoneGrowable) + \
|
||
(1 << gestaltLaunchCanReturn) + \
|
||
(1 << gestaltLaunchFullFileSpec) + \
|
||
(1 << gestaltLaunchControl) + \
|
||
(1 << gestaltTempMemSupport) + \
|
||
(1 << gestaltRealTempMemory) + \
|
||
(1 << gestaltTempMemTracked) + \
|
||
(1 << gestaltIPCSupport) + \
|
||
(1 << gestaltSysDebuggerSupport) + \
|
||
(1 << gestaltSkiaGlobalsSwitched)
|
||
|
||
PROC
|
||
|
||
EXPORT MyNewGestalt:CODE
|
||
|
||
;---------------------------------------------------------------------------------------
|
||
; gestaltOSAttrProc. The function we tell Gestalt to call when getting OS attributes.
|
||
; This is a Pascal style function looking like --
|
||
;
|
||
; FUNCTION gestaltOSAttrProc(selector : OSType; VAR result : LONGINT) : OSErr;
|
||
;
|
||
; Stack: (sp) return address
|
||
; 4(sp) address for Gestalt return value (long)
|
||
; 8(sp) Gestalt selector (long)
|
||
; 0A(sp) storage for result code (word)
|
||
|
||
gestaltOSAttrProc
|
||
move.l (sp)+,a0 ; move return address
|
||
move.l (sp)+,a1 ; get return value address
|
||
move.l (sp)+,d0 ; get selector
|
||
cmp.l #gestaltOSAttr,d0 ; is it our selector?
|
||
bne.s gOSAPError ; jump if not
|
||
move.l #OurGestaltValue,(a1) ; place the value
|
||
clr.w (sp) ; give good error code
|
||
gOSAPExit
|
||
jmp (a0) ; return
|
||
|
||
; we were called with a selector we don't understand (this should never be needed)
|
||
gOSAPError
|
||
move.w #gestaltUndefSelectorErr,(sp) ; set error code
|
||
bra.s gOSAPExit ; return
|
||
|
||
;---------------------------------------------------------------------------------------
|
||
; MyNewGestalt. Calls _NewGestalt to install the routine to handle the selector for
|
||
; which we are responsible (gestaltOSAttr).
|
||
MyNewGestalt
|
||
MNGSaveRegs REG d0-d1/a0-a2 ; working registers
|
||
|
||
movem.l MNGSaveRegs,-(sp) ; save working registers
|
||
lea gestaltOSAttrProc,a0 ; address of routine in our segment
|
||
move.l #gestaltOSAttr,d0 ; routine selector
|
||
_NewGestalt ; install our routine
|
||
movem.l (sp)+,MNGSaveRegs ; restore working registers
|
||
rts ; leave
|
||
|
||
ENDPROC
|
||
|
||
END
|