mirror of
https://github.com/elliotnunn/mac-rom.git
synced 2024-12-28 01:29:20 +00:00
4325cdcc78
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.
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
|