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.
2413 lines
96 KiB
Plaintext
2413 lines
96 KiB
Plaintext
;
|
||
; File: LinkedPatchLoader.a
|
||
;
|
||
; Contains: code to load linked patch resources
|
||
;
|
||
; Note that this patch loader is closely tied to the patch macros (LinkedPatchMacros.a)
|
||
; and patch linker (LinkPatch tool). Use care in changing one of these three without
|
||
; looking at the others.
|
||
;
|
||
; Written by: Darin Adler
|
||
;
|
||
; Copyright: © 1990Ñ1991 by Apple Computer, Inc., all rights reserved.
|
||
;
|
||
; Change History (most recent first):
|
||
;
|
||
; <63> 8/1/92 DTY Change a bsr.s to a bsr.w to keep this file building for linked
|
||
; patch INITs. (DonÕt ask me while it compiles differently for
|
||
; the two.)
|
||
; <62> 7/31/92 DTY Allow use of link patch debugging globals in linked patch INITs
|
||
; because we canÕt think of a good reason why this was
|
||
; conditionalized out in the first place. Also added comments to
|
||
; document which low mem globals to set to stop on a particular
|
||
; link patch entry, or set of entries on boot.
|
||
; <61> 7/7/92 JSM Add comment about 'ptbl' being passed in via A3, rename
|
||
; g.patchTable global to g.patchRangeTable to avoid terminology
|
||
; confusion, document format of patch range table in header of
|
||
; CheckPatchTableRange.
|
||
; <60> 6/3/92 DTY #1026928: If weÕre loading linked patches from ROM, ROMMapInsert
|
||
; needs to be set for all GetResource calls, not just the first
|
||
; one. Since CurMap gets reset for the ROM case, the value needs
|
||
; to be saved in a register before loading 'lpch' resources.
|
||
; <59> 4/30/92 DTY #1023455 <JSM>: The offset from change <51> should be $14, not
|
||
; #14.
|
||
; <58> 4/8/92 DTY #1026928,<FM>: Check CurMap before loading a 'lpch' resource. If
|
||
; itÕs 1, set ROMMapInsert to true to get linked patches from ROM.
|
||
; <57> 4/7/92 pvh Calculate end of boot globals using (a5+BootGlobals.size)
|
||
; <56> 4/6/92 DTY #1024666,<JSM>: Three lines were lumped into one of the NOT
|
||
; INITVERSION conditionals, breaking linked patch INITs. Fix this
|
||
; up, and added judicious comments which Fred was too whipped to
|
||
; do because his ride was here.
|
||
; <55> 4/4/92 FM #1024666: Made LinkedPatches more memory friendly by
|
||
; copying the 'lpch' resources up above the boot globals and
|
||
; releasing the resources. This was necessary because there wasn't
|
||
; enough room for Mac II class machines with 2 megs to load their
|
||
; linked patches. This copying over the boot globals isn't done
|
||
; with the init version.
|
||
; <54> 3/26/92 DTY #1024282,<gbm>: Doing a _MoveHHi isnÕt good enough, so just take
|
||
; it out. WeÕre going to load the Process Manager segments in
|
||
; BeforePatches.a ('PTCH' 0) so theyÕll be even lower, and theyÕll
|
||
; load before linked patches.
|
||
; <53> 3/25/92 DC FM - Heeeyyyy! somebody fogot to set up a0 to point to the
|
||
; 'ptbl' resource for the HLock call. As a result gPatchTable
|
||
; doesn't get set up and linked patch inits fail.
|
||
; <52> 3/16/92 DTY DonÕt try to release the patch range table for linked patch
|
||
; INITs, since we donÕt know whether it came from a resource or
|
||
; from the static table. Well, we do know, but itÕs a pain to
|
||
; figure out again.
|
||
; <51> 3/13/92 DTY #1023455: In CheckTerror, set hasTerror if this is a Horror ROM
|
||
; as well.
|
||
; <50> 3/10/92 DTY #1024282: Before locking the 'lpch' resources down, move them
|
||
; high so free block coalescing will be better. Among other
|
||
; things, this allows the Process Manager segments to load a
|
||
; little lower.
|
||
; <49> 2/27/92 DTY For linked patch inits, if a 'ptbl' resource couldnÕt be found,
|
||
; use the static patch range table at the end of the loader which
|
||
; causes all linked patches to load.
|
||
; <48> 2/12/92 DTY Using _GetResource to fetch 'lpch' resources would get 'lpch'
|
||
; resources from the System file if a Gibbly doesnÕt have that
|
||
; particular 'lpch' resource. Always use _Get1Resource now to get
|
||
; 'lpch's so this wonÕt happen.
|
||
; <47> 2/4/92 JSM (with FM) Move patchTable global above residentTop so we can use
|
||
; the same version of whip for 7.0 and CubeE.
|
||
; <46> 2/3/92 JSM (with FM) Add more comments so we wonÕt break the whip dcmd in
|
||
; the future.
|
||
; <45> 1/31/92 JSM Update comments on format of 'lpch' resources to show extra
|
||
; field thatÕs only in those resources for a single ROM.
|
||
; <44> 1/27/92 DTY Add some boundary conditions to CheckPatchTableRange: Provide a
|
||
; way out for empty range lists.
|
||
; <43> 1/6/92 DTY Linked patch INITs donÕt get passed a patch table, causing traps
|
||
; to point to wierd places, resident code not being there, and
|
||
; other strange things. If the loader is being built as part of an
|
||
; INIT, read in a 'ptbl' resource explicitly instead of expecting
|
||
; a pointer to one in A3.
|
||
; <42> 1/3/92 DTY Check the jump table entry number when making modules resident,
|
||
; so that entries that a Gibbly wants to skip will not be loaded.
|
||
; <41> 12/12/91 DTY Nick boo-booÕd in AllocateResidentBlock. D6 wasnÕt getting set
|
||
; up with the block pointer in the non-INIT case.
|
||
; <40> 12/12/91 ngk Use locked handle instead of pointer for code when compiling for
|
||
; INIT version. This is so MacsBug symbols show up.
|
||
; <39> 11/12/91 DTY Add support for patch table in InstallOrExecute. Check the
|
||
; routine number, and see if itÕs in a range specified in the
|
||
; patch table before installing the patch.
|
||
; <38> 10/28/91 SAM/KSM Rolled in Regatta changes:
|
||
; Adding hasC96 and hasPwrMgr conditionals and made hasTerror
|
||
; identify Zydeco ROM too.
|
||
; Added code for hasTERROR and notTERROR.
|
||
; <37> 8/14/91 JSM Completely remove debugging support for old version of whip,
|
||
; add/change lots and lots more comments, especially in the areas
|
||
; of ForPatchTable, ForAllReferences, and Find/MakeResident mess.
|
||
; <36> 8/12/91 JSM Add lots more comments, especially in the area of unpacking the
|
||
; jump table.
|
||
; <35> 8/8/91 FM Delete obsolete code and fixing up comments. Nuked 32-bitQD
|
||
; check, 'bnvs' resource, and HasSystem6LinkedPatches
|
||
; <34> 8/6/91 FM Fixed bug in recursion for Install Procs. Required splitting the
|
||
; jump table into two parts. Also made it possible for references
|
||
; to use the Òreal thingÓ if an island was out of range. Added
|
||
; some comments to help readability. Also added another field in
|
||
; the CurApName debug info that tells whip that the jump tables
|
||
; have changed in this version of the loader.
|
||
; <33> 4/2/91 dba KIP: add new hasEricksonSoundMgr conditional, correct
|
||
; notEricksonSoundMgr
|
||
; <32> 12/20/90 gbm (dba) Change so that debugging information is kept out of the
|
||
; way of people who check first long of CurApName to see if it is
|
||
; boot time.
|
||
; <31> 12/18/90 gbm (dba) Adding conditional for preventing loading of the patch
|
||
; protector twice. Check for 32-bit addressing with Gestalt
|
||
; instead of low memory.
|
||
; <30> 12/14/90 BBM (dba) add two conditionals for linked patching, using24BitHeaps,
|
||
; using32BitHeaps
|
||
; <29> 10/12/90 JDR (dba) turn off more of the debugging stuff in the INITVERSION
|
||
; <28> 10/8/90 JDR Add notVM, change hasPMMUNoVM to hasPMMU
|
||
; <27> 9/26/90 JDR Made pre-7.0 INITs save the current zone, since INITs would run
|
||
; in an application heap and not the System heap. (Darin told me
|
||
; what to do.)
|
||
; <26> 9/25/90 KIP (really dba) Added new conditional noEricksonSoundMgr.
|
||
; <25> 9/7/90 stb & vl. add conditional test for INIT builds
|
||
; <24> 8/31/90 stb conditionalize out debugger if building with -init
|
||
; <23> 8/21/90 csd Added code for hasMemoryDispatch condition.
|
||
; <22> 8/19/90 dba add six new loading conditions that were needed for Sony and MMU
|
||
; patching; add new debugging features that work through low
|
||
; memory globals $912-91B; fixed greater than one byte conditions
|
||
; case that is used now that we have eleven conditions total
|
||
; <21> 8/10/90 DTY (w/ dba) Make PatchProc take offsets into ExpandMem.
|
||
; <20> 8/2/90 MR Fix initversion bug in FlushInstructionCache to reload registers
|
||
; before rts
|
||
; <19> 7/31/90 DTY Check the vector at jCacheFlush to make sure itÕs an implemented
|
||
; routine before jumping to it for linked patch INITs.
|
||
; <18> 7/30/90 dnf (really dba) fix recursion for FindResident; this caused
|
||
; Òforce-residentÓ stuff to be ineffective, except in the topmost
|
||
; level of an InstallProc
|
||
; <17> 7/16/90 dba add support for counting the number of patches
|
||
; <16> 7/11/90 dba get dcImport to work
|
||
; <15> 7/10/90 DTY Test for presence of 32 Bit Color Quickdraw, and set not32BitCQD
|
||
; conditional flag appropriately. This flag is only defined for
|
||
; System 6 builds which have linked patches, or the patch is being
|
||
; built as an INIT.
|
||
; <14> 7/6/90 dba add a case for 32-bit references
|
||
; <13> 6/22/90 dba fix island case for LEA and PEA
|
||
; <12> 6/22/90 dba stuff the number of the patch being loaded into low memory so
|
||
; that we can debug more easily
|
||
; <11> 6/6/90 dba make code for islands
|
||
; <10> 5/1/90 BBM enable linked patches on 6.0 world
|
||
; <9> 4/15/90 dba delete unnecessary FlushInstructionCache from GetPatchAddress
|
||
; <8> 4/11/90 BBH remove flashmenu/sysbeep from INIT version
|
||
; <7> 4/10/90 dba make A5 world to pass to linked patches
|
||
; <6> 4/9/90 dba change so FlushInstructionCache does not trash registers
|
||
; <5> 4/9/90 BBH added compiler directive INITVERSION so that we can make a
|
||
; standalone INIT version of this code (see SysObj.make for build
|
||
; rules for LinkedPatchLoaderINIT.rsrc and the example
|
||
; CommToolboxPatchTest)
|
||
; <4> 4/9/90 dba make FlushInstructionCache routine that uses the jCacheFlush
|
||
; vector (not jFlushCache, which is for the file system cache)
|
||
; <3> 3/22/90 dba change name of loading routine; fix case with no lpchs
|
||
; <2> 3/21/90 dba fix range check so that it will work from -32768 to 32767
|
||
; <1> 3/9/90 KSM First checked in.
|
||
; 2/19/90 dba add judicious flushing of instruction cache
|
||
; 2/11/90 dba change so it loads a set of resources (for minimal install)
|
||
; 2/1/90 dba integrate changes from code review; move resident to high bit
|
||
; 1/30/90 dba patch and install in link order
|
||
; 1/25/90 dba added a header
|
||
;
|
||
; This file contains a patch loader that completes the linking begun by the LinkPatch tool.
|
||
; The code consists of a number of modules with entry points, references to other modules and
|
||
; entry points, and references to ROM addresses. The loader reads a table in the patch which
|
||
; specifies which patches and install routines should be executed on the machine. The routines
|
||
; which need to remain resident after patches are loaded are moved into a block in the system
|
||
; heap, and references within this block are changed to be PC-relative. The ROM references are
|
||
; fixed up to point to the appropriate ROM, and a jump table is built at A5 so that non-resident
|
||
; code can reference resident code (which may be more than 32K away). After that, all the patches
|
||
; are installed, and all of the install code is executed. Then the non-resident code and the jump
|
||
; table are deleted, and we return.
|
||
;
|
||
; ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ
|
||
; a note about conditions
|
||
; ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ
|
||
;
|
||
; A ÒROM setÓ is a bitmap of ROMs that a particular ROM bind applies to. It may occupy 1-4 bytes
|
||
; depending on the number of ROMs. The loader is reassembled if the number of ROMs changes
|
||
;
|
||
; A Òcondition setÓ is a ROM set combined with bits for other conditions. It too may occupy 1-4
|
||
; bytes (always at least as many as a ROM set). Each condition must have code in this loader to
|
||
; determine if the condition is true (at label GetNonROMConditions).
|
||
;
|
||
; ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ
|
||
; some of the limits
|
||
; ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ
|
||
;
|
||
; ROMs must be less than 2^23 bytes long (8M)
|
||
; we can patch up to 31 total different ROMs and conditions total
|
||
;
|
||
; ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ
|
||
; format of the 'lpch' resource
|
||
; ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ
|
||
;
|
||
; all references to ROM are linked through the code, but when the reference is a distance
|
||
; greater than 128K, there is an entry in the ROM reference exception table; the word following
|
||
; the link in the code contains the ROM table entry number; this is 0 for the first entry, 1 for
|
||
; the next, etc.
|
||
;
|
||
; all references within a module are linked in a list; the head of this list is encoded in
|
||
; the packed jump table; the low bit of the link is set to 1 for Òforce residentÓ references;
|
||
; if a Òforce residentÓ reference is encountered in install code, the referenced module is moved
|
||
; into resident space in the system heap
|
||
;
|
||
; 2 bytes number of 'lpch' resources for this ROM
|
||
; * 2 bytes number of entries in the bound ROM address table
|
||
; * 2 bytes number of entries in the jump table
|
||
; 4 bytes size of the code
|
||
; code
|
||
; 2 bytes first ROM table entry number (-1 means no packed ROM table entry)
|
||
; packed ROM table:
|
||
; 3 bytes per ROM ROM offset for each ROM (high bit set for end of table)
|
||
; ROM reference exception table:
|
||
; 3 bytes per exception 0 entry in code means exception (0 means end of table)
|
||
; packed jump table:
|
||
; 1 byte size
|
||
; 0-251 distance from current position in the code to next entry or
|
||
; module specified in the packed jump table, divided by 2 (i.e. 0-502 bytes)
|
||
; 252 means skip entries in the jump table
|
||
; 0 means end of packed jump table
|
||
; 1-254 means number of jump table entries to skip
|
||
; 255 means word follows with number of jump table entries to skip
|
||
; 253 means previous was reference list head for this module
|
||
; 254 means previous was an entry, not a new module
|
||
; 255 means word distance from current position in the code to next
|
||
; entry or module specified in the packed jump table follows
|
||
; * packed patch table (sorted in jump table order):
|
||
; * 1-4 bytes condition set for which the following patches/installs apply
|
||
; * 1 byte number of jump table entries to the next patch
|
||
; * 255 means word follows (0 word is end of table)
|
||
; * 254 means new condition set follows
|
||
; * 2 bytes trap number (0 means an install rather than a patch)
|
||
;
|
||
; - Means only in 'lpch' resources that are for a single ROM (e.g. those with resource id 1, 2, 4, 8, etc.)
|
||
; * - Means only in the universal 'lpch' resource. The universal 'lpch' resource is the
|
||
; resource that is loaded on all known ROMs, that is, its resource id has the bit for each ROM set to one.
|
||
;
|
||
; ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ
|
||
; thumbnail sketch of the code
|
||
; ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ
|
||
;
|
||
; LoadPatch
|
||
; load code from resource and detach it
|
||
; allocate A5 world and jump table and large block for resident code
|
||
; unpack ROM addresses into jump table
|
||
; fix ROM references to point to ROM (traverse long linked list of references)
|
||
; unpack real jump table (store size of routine and start of reference list for each proc)
|
||
; traverse patch table:
|
||
; for each triggered routine:
|
||
; FindResident or MakeResident (depending on whether it is a install routine or patch)
|
||
; cut back resident code
|
||
; traverse patch table:
|
||
; for each triggered patch routine (not install routine):
|
||
; traverse routine:
|
||
; put in old address wherever we see the magic cookie
|
||
; install patch
|
||
; for each triggered install routine:
|
||
; MakeNonResident
|
||
; execute
|
||
; dispose non-resident code and A5 world
|
||
;
|
||
; FindResident(entry)
|
||
; walk back the jump table until you reach a proc
|
||
; traverse linked list of references
|
||
; if the reference is marked resident:
|
||
; MakeResident(entry)
|
||
;
|
||
; MakeResident(entry)
|
||
; do nothing if this entry is already active
|
||
; walk back the jump table until you reach a proc
|
||
; allocate space in the resident area (size is in proc)
|
||
; copy routine to the resident area
|
||
; assign addresses to all items in the jump table up to the next proc
|
||
; traverse linked list of references
|
||
; MakeResident(entry)
|
||
; fix up that pesky reference
|
||
;
|
||
; MakeNonResident(entry)
|
||
; do nothing if this entry is already active
|
||
; walk back the jump table until you reach a proc
|
||
; assign addresses to all items in the jump table up to the next proc
|
||
; traverse linked list of references
|
||
; MakeNonResident(entry)
|
||
; fix up that pesky reference
|
||
;
|
||
|
||
print push,off
|
||
load 'StandardEqu.d'
|
||
include 'MMUEqu.a'
|
||
include 'BootEqu.a'
|
||
include 'GestaltEqu.a'
|
||
include 'HardwarePrivateEqu.a'
|
||
include 'UniversalEqu.a'
|
||
include 'Traps.a'
|
||
include 'LinkedPatchMacros.a'
|
||
print pop
|
||
|
||
_GetTrapWordAddress opword $A546 ; *** move into Traps.a
|
||
_SetTrapWordAddress opword $A447 ; *** move into Traps.a
|
||
|
||
dsLinkedPatchReferenceTooFar equ 97 ; *** move into SysErr.a
|
||
|
||
k32BitCQDTrap equ $AB03 ; trap number for 32-bit QuickDraw
|
||
kUnimplementedTrap equ $A89F ; trap number for unimplemented trap
|
||
kGestaltTrap equ $A0AD ; trap number for Gestalt
|
||
kMemoryDispatchTrap equ $A05C ; trap number for MemoryDispatch
|
||
|
||
if &type('INITVERSION') = 'UNDEFINED' then ; <5>
|
||
INITVERSION: equ 0
|
||
endif
|
||
|
||
;ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ
|
||
|
||
; special low-memory used in conjunction with the whip dcmd for debugging linked patches
|
||
LinkedPatchDebuggerPtr equ CurApName+8 ; call this routine so dcmd can snarf symbols
|
||
NewLoaderActive equ CurApName+$16 ; set to zero so that dcmd knows the new loader is active
|
||
|
||
; special low-memory used for debugging linked patches.
|
||
; loader will drop into debugger when about to load specified jump table entry or range of entries
|
||
StashJumpTableEntryNum equ CurApName+$10 ; place jump table entry number here as we go <32>
|
||
StopOnJumpTableEntryNum equ CurApName+$12 ; drop into debugger when loading this entry <32>
|
||
StopOnJumpTableEntryNumHighest equ CurApName+$14 ; or loading this range if this one is Âffff <32>
|
||
|
||
;ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ
|
||
|
||
; equates from the patch linker
|
||
|
||
kAbsoluteOpcode equ 15 ; this opcode means an absolute address
|
||
|
||
;ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ
|
||
|
||
; entry in the jump table
|
||
|
||
; note loader depends on the fact that both jump table and ParallelJumpTableEntryInfo
|
||
; are equal in size! The parallel jump table entry info is walked in step with the
|
||
; jump table. By keeping the records equal in size the parallel info will always be a fixed
|
||
; offset away from the corresponding jump table entry.
|
||
|
||
|
||
; This is the record for a jump table entry. It allows non-resident install code
|
||
; to call the resident patch proc routines. We also use the opcode field to
|
||
; indicate when a routine has been "nailed-down".
|
||
|
||
JumpTableEntry record 0 ; for each entry in the jump table:
|
||
opcode ds.w 1 ; initially 0 but becomes a JMP.L once this entry
|
||
; is nailed down.
|
||
address ds.l 1 ; address, in either resident non-resident block
|
||
size equ *
|
||
endr
|
||
|
||
; This is a record for additional information pertaining to each jump table entry.
|
||
; Keeping this extra information in a seperate record allows more jump table
|
||
; entries.
|
||
|
||
ParallelJumpTableEntryInfo record 0 ; Extra info for each entry in the jump table:
|
||
referenceListHead ds.w 1 ; head of list (even) or 1 for no list (odd) it
|
||
; is an offset into the code of the 'lpch' resource
|
||
flags ds.w 1 ; flags for indicating islands and for preventing
|
||
; cycles in FindResident and MakeResident recursion.
|
||
routineSize ds.w 1 ; size of the routine is here; 0 for entry point
|
||
size equ *
|
||
endr
|
||
|
||
; these bits are set in the flags field of the parallel info reord.
|
||
|
||
islandFlagBit equ 0 ; this is the bit that identifies an island
|
||
findSeenFlagBit equ 1 ; this is the bit set during FindResident
|
||
; to prevent cycles during the recursion
|
||
makeSeenFlagBit equ 2 ; this is the bit set during a MakeResident
|
||
; to prevent cycles during the recursion
|
||
|
||
; constants used in the manipulation of jump table information
|
||
|
||
kNailedDown equ $4EF9 ; A JMP instructiion. Stuck in the opcode field
|
||
; of a jump table entry when it is nailed-down
|
||
kInitialReferenceListHead equ 1 ; A good initial value because there cannot be
|
||
; an odd offset. CouldnÕt use zero cause thats a valid offset
|
||
kInitialRoutineSize equ -1 ; unused jump table entries (low bit clear)
|
||
|
||
|
||
;ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ
|
||
; All 'lpch' resources that need to be loaded are referenced by PatchResourceEntry records.
|
||
; The records are kept on the stack. The last record is followed by a 0 (i.e. endOfList is 0).
|
||
; Whenever we apply a function to all patches we can walk down the stack until we hit a 0.
|
||
|
||
PatchResourceEntry record 0 ; each entry on the stack
|
||
endOfList equ * ; list of entries is terminated by 0 on the stack
|
||
romSet ds.w 1 ; number of the ROM set
|
||
resourceHandle ds.l 1 ; handle to the 'lpch' resource
|
||
ptr ds.l 1 ; pointer into the resource (advances as we go)
|
||
codePtr ds.l 1 ; pointer to code in the resource
|
||
size equ *
|
||
endr
|
||
|
||
;ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ
|
||
; globals
|
||
|
||
g record {qdGlobalsPtr} ; an A5 world
|
||
start equ *
|
||
romNumber ds.w 1 ; ROM index number
|
||
ParallelJumpTableEntryInfoTableOffset ds.l 1 ; Offset to extra info for jump table entries
|
||
; normally held in register D3
|
||
nonROMConditions ds.l 1 ; other loading conditions (like VM, sound, etc.)
|
||
patchRangeTable ds.l 1 ; <39> Saved pointer to a patch range table ('ptbl')
|
||
|
||
; NOTE: whip depends on the location of residentTop
|
||
; if you add more globals, add them ¥before¥ here
|
||
|
||
residentTop ds.l 1 ; pointer to available space in resident block
|
||
; Bumped up as we go so we know how far to cut
|
||
; back the resident block when weÕre done.
|
||
|
||
offset equ *-start
|
||
qdGlobalsPtr ds.l 1 ; QuickDraw globals
|
||
romTable ds.b 0 ; place for ROM table to start
|
||
; NOTE: whip depends on the location of jumpTable
|
||
jumpTable ds.b 0 ; place for jump table to start
|
||
size equ *-start
|
||
endr
|
||
|
||
;ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ
|
||
|
||
LoadLinkedPatches proc export
|
||
|
||
; Load a patch from a resource.
|
||
;
|
||
; In:
|
||
; a3 pointer to patch range table ('ptbl') from 'boot' 3
|
||
; if this is a linked patch INIT, uses static table instead
|
||
;
|
||
; Out:
|
||
; can trash d0-d2/a0-a1
|
||
|
||
import ForPatchTable
|
||
import FindOrMakeResident
|
||
import InstallOrExecute
|
||
|
||
import ROMVersions
|
||
|
||
LoadLinkedPatchesRegisters reg d3-d7/a2-a5
|
||
|
||
movem.l LoadLinkedPatchesRegisters,-(sp)
|
||
|
||
GetROMNumber
|
||
; get the number of this ROM
|
||
|
||
moveq #NumROMs$-1,d3 ; ROM number counter
|
||
lea ROMVersions,a0 ; point to a table of ROM versions
|
||
move.l ROMBase,a1 ; get ROM version word from ROM
|
||
move.w 8(a1),d1 ; now we have the ROM version
|
||
@next
|
||
cmp.w (a0)+,d1 ; is this the version?
|
||
dbeq d3,@next ; keep looking
|
||
beq.s @ok ; yes, ROM found
|
||
moveq #dsNoPatch,d0
|
||
_SysError
|
||
@ok
|
||
|
||
;ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ
|
||
; There used to be essentially two copies of the linked patches in memory, one in the detached
|
||
; 'lpch' resources, and a copy of all the resident routines in the resident block. This is fine except
|
||
; that this doesnÕt leave enough memory to boot on 2 Meg machines. Fred was astute enough
|
||
; to realize that we have half of memory not being used sitting above MemTop/2 + 1K,
|
||
; so we now copy the 'lpch' resources into this area and disposes the detached resource
|
||
; handle. While we still have two copies around, one is not in the system heap,
|
||
; leaving more free space there for the patches themselves to load and waste memory.
|
||
|
||
LoadPatchResources
|
||
|
||
; load the patch resources
|
||
|
||
if NOT INITVERSION then
|
||
move.l MemTop,-(sp) ; <55>
|
||
|
||
; calculate end of boot globals in a1 (a5+BootGlobals.size)
|
||
|
||
move.l a5,a1 ; <57>
|
||
add.l #BootGlobals.size,a1 ; <57> Skip past globals
|
||
endif
|
||
|
||
moveq #0,d7 ; calculate the total size of resources
|
||
moveq #0,d4 ; count the number of resources
|
||
clr.w -(sp) ; mark end of PatchResourceEntries
|
||
|
||
; <60> Save CurMap in case itÕs 1 for the ROM map, since it will get set to
|
||
; SysMap by the Resource Manager when leaving a GetResource call.
|
||
|
||
move.w CurMap,d6 ; <60>
|
||
|
||
moveq #0,d1 ; start going through the resources
|
||
@next
|
||
addq.w #1,d1 ; advance to the next resource
|
||
btst #NumROMs$,d1 ; have we done all of the ROMs?
|
||
bnz.s @done
|
||
btst d3,d1 ; is this resource needed for this ROM?
|
||
bz.s @next ; no, go on
|
||
|
||
cmp.w #1,d6 ; <58> <60> Check if CurMap is 1.
|
||
bne.s @linkedPatchNotInROM ; <58> If itÕs not 1, itÕs a resource in a real file
|
||
move.w #MapTrue,ROMMapInsert ; <58> Set ROMMapInsert so the call to _Get1Resource will look in the ROM resource map for the 'lpch'
|
||
@linkedPatchNotInROM ; <58>
|
||
subq.l #4,sp ; make room for the resource
|
||
move.l #'lpch',-(sp)
|
||
move.w d1,-(sp)
|
||
_Get1Resource ; <5> BBH - Init Version does 1 deep search ONLY!
|
||
move.l (sp)+,d2
|
||
bnz.s @ok ; yes, enough memory to load the patch
|
||
|
||
subq.l #2,sp ; make room for error
|
||
_ResError ; check if the error is real
|
||
move.w (sp)+,d0 ; get the error code
|
||
bz.s @notFound ; no error is OK
|
||
cmp.w #resNotFound,d0 ; resNotFound?
|
||
beq.s @notFound ; yes, resNotFound is also OK
|
||
moveq #dsMemFullErr,d0
|
||
_SysError
|
||
@notFound
|
||
tst.w d4 ; is this the first resource (i.e. the one for this ROM only)?
|
||
bnz.s @next ; no, itÕs OK that it be missing
|
||
moveq #dsNoPatch,d0 ; yes, if it is missing there is an error
|
||
_SysError
|
||
@ok
|
||
addq.w #1,d4 ; count the resources
|
||
|
||
move.l d2,-(sp)
|
||
_DetachResource ; detach the resource
|
||
move.l d2,a0
|
||
_GetHandleSize ; add itÕs size in
|
||
add.l d0,d7 ; calculate total size of all resources
|
||
|
||
if NOT INITVERSION then
|
||
|
||
; Ensure that each copy of the linked patch data starts at an even address by copying
|
||
; an even number of bytes.
|
||
|
||
btst #0,d0 ; <56> Is the size of the 'lpch' resource odd?
|
||
bz.s @copyLinkedPatchAboveBootGlobals ; <56>
|
||
addq.l #1,d0 ; <55> If it is, make it even
|
||
|
||
; Copy the 'lpch' resource data up above the boot globals. A1 is set up
|
||
; to be the address where the data should be copied to. ItÕs initially MemTop/2 + 1K.
|
||
; After each _BlockMove, it gets bumped up, so the next 'lpch' is copied above this
|
||
; one.
|
||
;
|
||
; Before moving the data, we make space for a faked up handle to point to it:
|
||
;
|
||
; +------------------+
|
||
; + lpch +
|
||
; + data +
|
||
; +------------------+
|
||
; + ptr to lpch data +
|
||
; +------------------+
|
||
; + . +
|
||
; + . +
|
||
; + . +
|
||
; +------------------+
|
||
; + boot globals +
|
||
; +------------------+
|
||
|
||
@copyLinkedPatchAboveBootGlobals
|
||
addq.l #4,a1 ; <55> Leave space for a faked up handle
|
||
move.l d0,-(sp) ; <56> Save size of 'lpch' resource
|
||
move.l (a0),a0 ; <55> Get pointer to data
|
||
_BlockMove ; <55> Copy it above the boot globals
|
||
move.l (sp)+,d0 ; <56> Restore size.
|
||
lea -4(a1),a0 ; <55> Get longword we reserved for the fake handle
|
||
move.l a1,(a0) ; <55> And point it to the 'lpch' data
|
||
add.l d0,a1 ; <55> Bump A1 to the address the next 'lpch' resource should be copied to.
|
||
|
||
; Create the PatchResourceEntry record for this 'lpch' resource
|
||
|
||
subq.l #8,sp ; <55> make room for codePtr (used later)
|
||
move.l a0,-(sp) ; <55> push ÒHandleÓ
|
||
move.w d1,-(sp) ; <55> also push the romSet (same as resource ID)
|
||
move.l d2,a0 ; <56>
|
||
_DisposeHandle ; <56> Dispose of the handle to the 'lpch' resource (now that we have a copy)
|
||
else
|
||
subq.l #8,sp ; make room for codePtr and ptr (used later)
|
||
move.l d2,-(sp) ; push resourceHandle
|
||
move.w d1,-(sp) ; also push the romSet (same as resource ID)
|
||
endif
|
||
|
||
bra.s @next
|
||
@done
|
||
tst.w PatchResourceEntry.endOfList(sp) ; did we load any?
|
||
bz Done ; no, get out of here
|
||
|
||
; Inside Mac IV p. 257 states that BufPtr may not go lower than MemTop/2 + 1K. For the algebraically
|
||
; impaired, that means that MemTop = (minBufPtr - 1K) * 2. In case some linked patches change
|
||
; BufPtr, move MemTop higher so that patches that want to can move BufPtr down without trashing
|
||
; the 'lpch' data we copied above the boot globals.
|
||
|
||
if NOT INITVERSION then ; <56>
|
||
sub.w #1024,a1 ; <55> end of lpch data - 1024
|
||
add.l a1,a1 ; <55> 2*(end of lpch data - 1024) <30>
|
||
move.l a1,MemTop ; <55> MemTop := 2*(end of lpch data - 1024)
|
||
endif ; <56>
|
||
|
||
;ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ
|
||
|
||
AllocateResidentBlock
|
||
; allocate resident pointer the same size as all of patch resources *** better initial size?
|
||
|
||
move.l d7,d0
|
||
if INITVERSION then ; <40>
|
||
_NewHandle sys ; <40> alloc a locked handle instead of of pointer
|
||
bnz.s @allocErr ; <40> this is to get MacsBug to show labels
|
||
_HLock ; <40>
|
||
move.l (a0),a0 ; <41> Get pointer to block
|
||
bra.s @ok ; <40>
|
||
else
|
||
_NewPtr sys
|
||
bz.s @ok ; must succeed
|
||
endif
|
||
@allocErr
|
||
moveq #dsMemFullErr,d0
|
||
_SysError
|
||
@ok
|
||
move.l a0,d6 ; keep pointer to resident code in d6
|
||
|
||
|
||
;ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ
|
||
|
||
LockDownNonResidentPatches
|
||
|
||
; now we can lock down the non-resident part of the patches
|
||
|
||
move.l sp,a4 ; get first PatchResourceEntry
|
||
@next
|
||
tst.w (a4)+ ; end of table?
|
||
bz.s @done
|
||
move.l (a4)+,a0 ; now we can lock down each resource
|
||
if INITVERSION then
|
||
_HLock
|
||
move.l (a0),d0 ; dereference it (must be locked)
|
||
_StripAddress
|
||
else
|
||
move.l (a0),d0 ; <55> Dereference the fake handle to the 'lpch' data above the boot globals.
|
||
endif
|
||
move.l d0,(a4)+ ; store the dereferenced pointer in ptr
|
||
add.l #4,a4 ; skip over space for the codePtr
|
||
bra.s @next
|
||
@done
|
||
|
||
CheckForMissingResources
|
||
; now we check the number of 'lpch' resources stored in the first resource
|
||
; (which is the one used for just this ROM) to see if it is too low
|
||
|
||
lea -2-PatchResourceEntry.size+PatchResourceEntry.ptr(a4),a4 ; position at the ptr
|
||
move.l (a4),a0 ; get the pointer
|
||
cmp.w (a0)+,d4 ; is it the right number of resources?
|
||
beq.s @ok
|
||
moveq #dsBadPatch,d0 ; no, a resource was missing for this ROM
|
||
_SysError
|
||
@ok
|
||
move.l a0,(a4) ; advance past the count
|
||
|
||
;ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ
|
||
|
||
AllocateA5World
|
||
; get size of A5 world by looking at sizes at start of universal resource for all ROMs
|
||
; First we calculate how much space will be needed for the ROM table.
|
||
; Then we calculate how much will be needed for the patch proc and install
|
||
; proc jump table information. Since we use the same allocated space for both
|
||
; the larger of the two will determine the size of our non resident block
|
||
|
||
; we also set up the global offset into the jump tableÕs extra information
|
||
|
||
move.l PatchResourceEntry.ptr(sp),a0 ; point at start of universal resource
|
||
|
||
moveq #0,d0
|
||
move.w (a0)+,d0 ; calculate the size of the ROM table
|
||
lsl.l #2,d0 ; x4 (ROM table entries are 4 bytes)
|
||
|
||
moveq #0,d5
|
||
move.w (a0)+,d5 ; calculate the size of the jump table
|
||
move.l d5,d1
|
||
addq.l #1,d1 ; one extra entry for coding convenience
|
||
|
||
move.l d1,d2
|
||
lsl.l #3,d1 ; x8 (jump table entries are 6 bytes)
|
||
lsl.l #2,d2 ; x4 (jump table entries are 6 bytes)
|
||
add.l d2,d1 ; 8+4 = 12 ( 6 bytes per jump table entry
|
||
; 6 bytes parallel info per entry )
|
||
|
||
move.l a0,PatchResourceEntry.ptr(sp) ; now all resources point to their code size
|
||
|
||
cmp.l d0,d1 ; get the larger of the two
|
||
bls.s @gotLarger
|
||
move.l d1,d0
|
||
@gotLarger
|
||
moveq #g.size,d2
|
||
add.l d2,d0 ; larger table + globals = total size
|
||
_NewPtr ,Clear ; create the A5 block
|
||
bz.s @ok ; must succeed
|
||
moveq #dsMemFullErr,d0
|
||
_SysError
|
||
@ok
|
||
move.l (a5),g.qdGlobalsPtr+g.offset(a0) ; copy the QuickDraw globals pointer
|
||
lea g.offset(a0),a5 ; switch to the new A5
|
||
|
||
move.w d3,g.romNumber(a5)
|
||
move.l d6,g.residentTop(a5) ; none of the resident pointer is used yet
|
||
|
||
if INITVERSION then ; <43>
|
||
Import StaticRangeTable ; <49>
|
||
|
||
lea StaticRangeTable,a3 ; <49> Use a built in patch range table for linked patch INITs.
|
||
endif ; <43>
|
||
|
||
move.l a3,g.patchRangeTable(a5) ; <39> Save the pointer to the patch range table.
|
||
|
||
lsr.l #1,d1 ; d1 is the size of the Jump Table Entries plus
|
||
; the parallel info entries. halfway thru jump table
|
||
lea g.jumpTable(a5),a0 ; space is start of info table so set up the offset to
|
||
move.l d1,g.ParallelJumpTableEntryInfoTableOffset(a5) ; info table for later
|
||
|
||
|
||
;ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ
|
||
|
||
GetNonROMConditions
|
||
; figure out non-ROM conditions that apply
|
||
|
||
import MrGestalt,TrapImplemented
|
||
|
||
; condition evaluation can trash standard registers (d0-d2/a0-a1)
|
||
; condition bit should be set in the flags long-word, d3
|
||
|
||
moveq #0,d3 ; no flags
|
||
|
||
CheckC96 ; <3>
|
||
; hasC96
|
||
MOVE.L ROMBase,A0 ; Get base of ROM
|
||
CMPI.W #$067C,8(A0) ; Do we have universal tables?
|
||
BNE.S @no ; -> Nope, no C96
|
||
TestFor SCSI96_1Exists ; C96 SCSI chip?
|
||
BEQ.S @no ; -> Nope, no C96
|
||
@yes BSET.L #Condition$hasC96,D3 ; We have a C96 SCSI chip!
|
||
@no
|
||
|
||
CheckPowerMgr ; <3>
|
||
; hasPwrMgr
|
||
MOVE.W HwCfgFlags,D0 ; Get them Hardware Config Flags
|
||
BTST.L #hwCbPwrMgr,D0 ; Do we have a PowerMgr?
|
||
BEQ.S @no ; -> No.
|
||
@yes BSET.L #Condition$hasPwrMgr,D3 ; We have a PowerMgr chip!
|
||
@no
|
||
|
||
CheckTERROR ; <SAM>
|
||
; notTERROR
|
||
MOVE.L ROMBase,A0 ; Get base of ROM
|
||
CMPI.W #$067C,8(A0) ; Is the ROM major version 67C?
|
||
BNE.S @no ; -> Nope, say notTERROR
|
||
CMPI.B #$15,18(A0) ; Is the ROM minor version #$15?
|
||
BEQ.S @yes ; -> Yes, we have TERROR
|
||
CMPI.B #$17,18(A0) ; Is the ROM minor version #$17? <3>
|
||
BEQ.S @yes ; -> Yes, we have Zydeco ( == TERROR) <3>
|
||
btst #0,20(a0) ; <51> <59> Horror ROM?
|
||
bnz.s @yes ; <51> Yes. Load Terror patches for this ROM too.
|
||
@no
|
||
BSET.L #Condition$notTERROR,D3 ; We do NOT have TERROR
|
||
BRA.S @done
|
||
|
||
@yes BSET.L #Condition$hasTERROR,D3 ; We have a TERROR ROM
|
||
@done
|
||
|
||
CheckAUX
|
||
; notAUX
|
||
|
||
btst.b #hwCbAUX,HWCfgFlags ; are we under A/UX?
|
||
bnz.s @no ; yes, no flag to set
|
||
bset.l #Condition$notAUX,d3
|
||
@no
|
||
|
||
CheckVM
|
||
; notVM
|
||
|
||
move.l #gestaltVMAttr,d0 ; check for VM
|
||
jsr MrGestalt
|
||
btst #gestaltVMPresent,d0
|
||
bnz.s @done ; bit is set, we have VM, so donÕt set flag
|
||
@no
|
||
bset.l #Condition$notVM,d3
|
||
@done
|
||
|
||
CheckMMU
|
||
; hasHMMU
|
||
; hasPMMU
|
||
|
||
cmp.b #2,CPUFlag ; are we on a 68020 or better?
|
||
blo.s @done ; no, there is no MMU
|
||
move.b MMUType,d0 ; get the MMU type
|
||
cmp.b #HMMU,d0 ; is it an HMMU?
|
||
beq.s @HMMU ; yes, there is an HMMU
|
||
cmp.b #PMMU851,d0 ; is there some kind of PMMU?
|
||
blo.s @done ; no, there is no PMMU
|
||
bset.l #Condition$hasPMMU,d3
|
||
bra.s @done
|
||
@HMMU
|
||
bset.l #Condition$hasHMMU,d3
|
||
@done
|
||
|
||
CheckMemoryDispatch
|
||
; hasMemoryDispatch
|
||
|
||
move.w #kMemoryDispatchTrap,d0
|
||
_GetTrapAddress newOS ; get address of _MemoryDispatch
|
||
jsr TrapImplemented
|
||
beq.s @no ; no VM
|
||
bset.l #Condition$hasMemoryDispatch,d3
|
||
@no
|
||
|
||
CheckSonyDriverVersion
|
||
; has800KDriver/hasFDHDDriver
|
||
|
||
move.l UTableBase,a0 ; look at the Sony driverÕs DCE
|
||
move.l 16(a0),a0 ; get the DCE handle
|
||
move.l (a0),a0 ; dereference it
|
||
cmp.b #1,dCtlQueue+1(a0) ; is it the old 800K driver?
|
||
ble.s @800K
|
||
bset.l #Condition$hasFDHDDriver,d3
|
||
bra.s @done
|
||
@800K
|
||
bset.l #Condition$has800KDriver,d3
|
||
@done
|
||
|
||
CheckIWM
|
||
; hasIWM
|
||
|
||
move.l ROMBase,a0 ; get ROM version
|
||
cmp.w #$067C,8(a0) ; is this the IIci ROM family?
|
||
bne.s @yes
|
||
TestFor IWMExists ; are we running with an IOP?
|
||
bz.s @no ; yes, so we donÕt have an IWM
|
||
@yes
|
||
bset.l #Condition$hasIWM,d3
|
||
@no
|
||
|
||
CheckEricksonMistake
|
||
; hasEricksonOverpatchMistake
|
||
|
||
move.l ROMBase,a0 ; get ROM version
|
||
cmp.w #$067C,8(a0) ; is this the IIci ROM family?
|
||
bne.s @no
|
||
cmp.w #$12F1,18(a0) ; check sub-version for Erickson ROM
|
||
bne.s @no
|
||
bset.l #Condition$hasEricksonOverpatchMistake,d3 ; the Erickson ROM has 1-ROM-only bugs
|
||
@no
|
||
|
||
CheckEricksonSoundMgr
|
||
; hasEricksonSoundMgr
|
||
; notEricksonSoundMgr
|
||
|
||
move.l ROMBase,a0 ; get ROM version
|
||
cmp.w #$067C,8(a0) ; is this the IIci ROM family?
|
||
bne.s @no
|
||
cmp.w #$12F1,18(a0) ; check sub-version for Erickson ROM or newer
|
||
blo.s @no
|
||
bset.l #Condition$hasEricksonSoundMgr,d3 ; Erickson and newer ROMs have a new Sound Mgr.
|
||
bra.s @done
|
||
@no
|
||
bset.l #Condition$notEricksonSoundMgr,d3 ; older ROMs have the original IIci Sound Mgr.
|
||
@done
|
||
|
||
CheckHeapsMode ; <30><31>
|
||
; using24BitHeaps
|
||
; using32BitHeaps
|
||
|
||
move.l #gestaltAddressingModeAttr,d0 ; check attributes
|
||
jsr MrGestalt
|
||
btst #gestalt32BitAddressing,d0
|
||
bnz.s @32
|
||
bset.l #Condition$using24BitHeaps,d3 ; set the flag for the 24 bit heap
|
||
bra.s @done ; time for the next conditional check
|
||
@32
|
||
bset.l #Condition$using32BitHeaps,d3 ; set the flag for the 32 bit heap
|
||
@done ; <30><31>
|
||
|
||
CheckNoPatchProtector
|
||
; noPatchProtector ; <31>
|
||
|
||
move.w #$A800,d0 ; get address of first Toolbox trap
|
||
_GetTrapWordAddress ; using new patched version of GetTrapAddress
|
||
move.l a0,a1
|
||
moveq #0,d0 ; get address of first OS trap
|
||
_GetTrapAddress ; using standard GetTrapAddress
|
||
cmp.l a0,a1 ; did we get the same answer both times?
|
||
bne.s @no ; no, the patch protector is working
|
||
bset.l #Condition$noPatchProtector,d3 ; yes, there is no patch protector yet
|
||
@no ; <31>
|
||
|
||
; *** new conditions should be added here ***
|
||
|
||
StoreConditions
|
||
|
||
if NumConditions$ <= 8 then
|
||
move.b d3,g.nonROMConditions(a5) ; store all the flags
|
||
elseif NumConditions$ <= 16 then
|
||
move.w d3,g.nonROMConditions(a5) ; store all the flags
|
||
else
|
||
move.l d3,g.nonROMConditions(a5) ; store all the flags
|
||
endif
|
||
|
||
;ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ
|
||
|
||
UnpackROMTable
|
||
; advance through all the resources, unpacking the ROM address tables
|
||
; also initialize the codePtr field of the PatchResourceEntries
|
||
|
||
move.l sp,a4 ; get first PatchResourceEntry
|
||
|
||
@nextResource
|
||
move.w PatchResourceEntry.romSet(a4),d0 ; get the ROM set (same as endOfList)
|
||
bz.s @done ; no ROMs means we are done
|
||
|
||
move.l PatchResourceEntry.ptr(a4),a2 ; get pointer into resource (advance as we go)
|
||
move.l (a2)+,d1 ; get size of the code
|
||
move.l a2,PatchResourceEntry.codePtr(a4) ; store pointer to code
|
||
add.l d1,a2 ; point at ROM table
|
||
|
||
; unpack all of the items in the ROM table
|
||
|
||
moveq #0,d2
|
||
move.w (a2)+,d2 ; get the first ROM table entry number
|
||
bmi.s @doneResource ; -1 means no ROM references in this 'lpch'
|
||
lsl.l #2,d2 ; turn into offset into ROM table (ROM table enntries are 4 bytes)
|
||
lea g.romTable(a5,d2.l),a0 ; point at this entry in the ROM table
|
||
|
||
; each entry in the ROM table has a ROM bind for every ROM this 'lpch' applies to
|
||
; *** isnÕt the offset into each entry in the packed ROM table constant for the ROM weÕre loading on?
|
||
; *** if so, why not calculate it once instead of looping through NumROMs$ and bit testing each time?
|
||
; *** also, the size of each entry in the packed ROM table is constant, too (3 bytes * number of ROMs
|
||
; *** supported by this 'lpch')
|
||
|
||
@nextEntry
|
||
moveq #NumROMs$-1,d1 ; start with the last ROM
|
||
@loopROM
|
||
btst.l d1,d0 ; does this ROM have an entry for this 'lpch'?
|
||
bz.s @nextROM ; no, go on to the next ROM
|
||
cmp.w g.romNumber(a5),d1 ; is this the ROM we are loading for?
|
||
bne.s @skipEntry ; no, skip this entry in the packed ROM table
|
||
moveq #$7F,d2 ; yes, clear high bit (used as flag for end of table)
|
||
and.b (a2)+,d2 ; get the first byte
|
||
swap d2 ; move it up
|
||
move.b (a2)+,d2 ; get the second byte
|
||
lsl.w #8,d2 ; move it up
|
||
move.b (a2)+,d2 ; get the third byte
|
||
add.l ROMBase,d2 ; add offset to the ROMBase
|
||
bra.s @nextROM ; we have the ROM bind for this ROM,
|
||
; but we have to continue on to the end of this entry
|
||
@skipEntry
|
||
addq #3,a2 ; skip the offset *** define a constant for packed ROM table offset size
|
||
@nextROM
|
||
dbra d1,@loopROM ; move on to the next ROM
|
||
move.l d2,(a0)+ ; store the ROM address (or 0) *** why 0?
|
||
btst #7,-3(a2) ; test high bit of last entry
|
||
bz.s @nextEntry
|
||
@doneResource
|
||
move.l a2,PatchResourceEntry.ptr(a4) ; PatchResourceEntry.ptr now points to ROM reference exception table
|
||
lea PatchResourceEntry.size(a4),a4 ; advance to the PatchResourceEntry for the next resource
|
||
bra.s @nextResource
|
||
@done
|
||
|
||
;ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ
|
||
|
||
FixupROMReferences
|
||
; advance through all the resources, fixing up ROM references inside the code
|
||
|
||
move.l sp,a4 ; get first PatchResourceEntry
|
||
|
||
@nextResource
|
||
move.w PatchResourceEntry.romSet(a4),d0 ; get the ROM set (same as endOfList)
|
||
bz.s @done ; no ROMs means we are done
|
||
|
||
move.l PatchResourceEntry.ptr(a4),a2 ; get pointer to ROM reference exception table
|
||
|
||
; find the ROM references and fix them up
|
||
|
||
move.l PatchResourceEntry.codePtr(a4),a0 ; point at the start of the code
|
||
@nextTableOffset
|
||
moveq #0,d0
|
||
move.b (a2)+,d0 ; get high byte
|
||
swap d0
|
||
move.b (a2)+,d0 ; get middle byte
|
||
lsl.w #8,d0
|
||
move.b (a2)+,d0 ; get low byte
|
||
tst.l d0 ; check for end of table
|
||
bz.s @doneResource
|
||
@useOffset
|
||
add.l d0,a0 ; point at the ROM reference in code
|
||
moveq #0,d0
|
||
move.w (a0)+,d0 ; get the offset to the next ROM reference
|
||
moveq #0,d1
|
||
move.w (a0)+,d1 ; get the ROM table entry number for this ROM reference
|
||
lsl.l #2,d1 ; convert to ROM table offset
|
||
move.l g.romTable(a5,d1.l),-4(a0) ; jam the value into the code
|
||
add.l d0,d0 ; convert offset in words to offset in bytes
|
||
bnz.s @useOffset ; if valid, use the offset we just got from the code
|
||
bra.s @nextTableOffset ; otherwise, use a long offset from the ROM reference table
|
||
@doneResource
|
||
move.l a2,PatchResourceEntry.ptr(a4) ; PatchResourceEntry.ptr now points to packed jump table
|
||
lea PatchResourceEntry.size(a4),a4 ; advance to the resource
|
||
bra.s @nextResource
|
||
@done
|
||
|
||
;ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ
|
||
|
||
InitializeJumpTable
|
||
; Turns out things will work best if routineSizes are initialized to -1.
|
||
; This ensures that any unused entries will look like the beginning of a module, so
|
||
; we wonÕt loop past the end of a module that does not have another module after it.
|
||
; This includes one extra entry at the end of the jump table for that end case.
|
||
; Note that d5 contains the number of entries in the table, not counting the extra one.
|
||
|
||
move.l g.ParallelJumpTableEntryInfoTableOffset(a5),d3 ; Make d3 offset to parallel jump table entries
|
||
lea g.jumpTable(a5),a0 ; Make a0 the first jump table entry
|
||
moveq #kInitialRoutineSize,d0 ; a good routine size to initialize to
|
||
|
||
; loop through jump table and parallel jump table initializing values
|
||
|
||
move.w d5,d1 ; initialize loop counter with number of entries in jump table
|
||
@next
|
||
move.w d0,ParallelJumpTableEntryInfo.routineSize(a0,d3.l) ; jam in the routine size
|
||
clr.w ParallelJumpTableEntryInfo.flags(a0,d3.l) ; start off with no flags set
|
||
clr.w JumpTableEntry.opcode(a0) ; start off not nailed down (0 opcode)
|
||
addq.l #JumpTableEntry.size,a0 ; advance to the next entry
|
||
dbra d1,@next ; loop through the whole jump table
|
||
|
||
;ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ
|
||
|
||
UnpackJumpTable
|
||
; now, go through all the 'lpch' resources on the stack unpacking the jump table
|
||
;
|
||
; Some registers we use consistently:
|
||
;
|
||
; a0 = pointer to jump table entry in g.jumpTable for current entry point or module
|
||
; a1 = pointer to jump table entry in g.jumpTable for previous module
|
||
; a2 = pointer to current entry in the packed jump table
|
||
; a4 = pointer to current PatchResourceEntry on the stack
|
||
;
|
||
; d0 = pointer to current entry point or module in the 'lpch' code
|
||
; d1 = pointer to previous module in the 'lpch' code so we can calculate the size of modules
|
||
; (or -1 if there is no previous module)
|
||
; d2 = current size of special opcode from packed jump table
|
||
; d3 = g.ParallelJumpTableEntryInfoTableOffset, the offset into g.jumpTable of the parallel jump table
|
||
; d4 = boolean indicating whether we have a jump table entry for a pending module to fix up
|
||
|
||
move.l sp,a4 ; get first PatchResourceEntry
|
||
|
||
@nextResource
|
||
tst.w PatchResourceEntry.endOfList(a4) ; are we at the end ot the list?
|
||
bz @done ; zero means yes
|
||
|
||
move.l PatchResourceEntry.ptr(a4),a2 ; get pointer to packed jump table
|
||
|
||
; unpack the real jump table, trashing the ROM table
|
||
|
||
lea g.jumpTable(a5),a0 ; build the jump table here
|
||
move.l PatchResourceEntry.codePtr(a4),d0 ; keep the running address in d0
|
||
moveq #-1,d1 ; there is no previous module
|
||
|
||
; the main loop itself
|
||
;
|
||
; A reminder about the format of the packed jump table:
|
||
;
|
||
; 0-251 distance from current position in the code to next entry or
|
||
; module specified in the packed jump table, divided by 2 (i.e. 0-502 bytes)
|
||
; 252 means skip entries in the jump table
|
||
; 0 means end of packed jump table
|
||
; 1-254 means number of jump table entries to skip
|
||
; 255 means word follows with number of jump table entries to skip
|
||
; 253 means previous was reference list head for this module
|
||
; 254 means previous was an entry, not a new module
|
||
; 255 means word distance from current position in the code to next
|
||
; entry or module specified in the packed jump table follows
|
||
|
||
@pendingModule
|
||
moveq #1,d4 ; when we start, we have a pending module
|
||
|
||
@loop
|
||
moveq #0,d2
|
||
move.b (a2)+,d2 ; get the size of the routine
|
||
|
||
cmp.b #254,d2 ; check if it is a special opcode
|
||
bhi.s @word ; word length size follows, so get it
|
||
beq.s @doEntry ; we just got an entry (as opposed to a new module)
|
||
cmp.b #252,d2 ; check for other special opcodes
|
||
bhi.s @doReferenceList ; we just got a reference list head for the current module
|
||
beq.s @skipJumpTableEntries ; we should skip ahead some entries before the next module
|
||
; otherwise, not a special opcode
|
||
add.w d2,d2 ; quick sizes are stored as half, double it
|
||
|
||
@gotSize
|
||
tst.b d4 ; is there a pending module?
|
||
bz.s @noPending
|
||
; yes, so the size must be for the current module
|
||
bsr.s @finishModule ; put size in previous module jump table entry
|
||
bsr.s @emitEntry ; emit the entry
|
||
|
||
@noPending
|
||
add.l d2,d0 ; no pending module, advance code pointer by the size
|
||
bra.s @pendingModule
|
||
|
||
; emitEntry initializes the referenceListHead and routineSize in the parallel jump table entry,
|
||
; stores a pointer to the routine in the code in the address field of the jump table entry,
|
||
; and advances the pointer into g.jumpTable to the next entry
|
||
;
|
||
; a0 = pointer to jump table entry in g.jumpTable for current entry point or module
|
||
; d0 = pointer in the code to current entry point or module
|
||
|
||
@emitEntry
|
||
move.w #kInitialReferenceListHead,ParallelJumpTableEntryInfo.referenceListHead(a0,d3.l) ; real reference list head comes later I promise
|
||
move.l d0,JumpTableEntry.address(a0) ; put code pointer here (actual address calculated later)
|
||
clr.w ParallelJumpTableEntryInfo.routineSize(a0,d3.l) ; routine size goes here later for a module
|
||
addq.l #JumpTableEntry.size,a0 ; move to next entry!
|
||
rts
|
||
|
||
; finishModule stores the size of any previous module in the routineSize field of its parallel jump table entry,
|
||
; then updates the pointer to the last moduleÕs jump table entry and the pointer to the previous module
|
||
;
|
||
; a1 = pointer to jump table entry in g.jumpTable for last module
|
||
; d1 = pointer to previous module in the code
|
||
|
||
@finishModule
|
||
tst.l d1 ; first one?
|
||
bmi.s @noOld ; no, this is the first module
|
||
sub.l d0,d1 ; calculate length of previous module
|
||
neg.w d1 ; by subtracting from where we are now
|
||
move.w d1,ParallelJumpTableEntryInfo.routineSize(a1,d3.l) ; so we can store the size in the parallel info for
|
||
; this jump table entry
|
||
@noOld
|
||
move.l a0,a1 ; always keep pointer to jump table entry of the last module here
|
||
move.l d0,d1 ; keep pointer to the last module here
|
||
rts
|
||
|
||
; we got a special opcode saying that current entry in packed jump table is word length
|
||
@word
|
||
move.b (a2)+,d2 ; get high byte
|
||
lsl.w #8,d2 ; push it up
|
||
move.b (a2)+,d2 ; get low byte
|
||
bra.s @gotSize
|
||
|
||
@doEntry
|
||
bsr.s @emitEntry
|
||
; fall through
|
||
@noPendingModule
|
||
moveq #0,d4 ; no pending module
|
||
bra.s @loop
|
||
|
||
; we got a special opcode saying that current entry is the first reference inside this module
|
||
@doReferenceList
|
||
move.l d0,d2 ; calculate offset of reference list head by subtracting pointer to
|
||
sub.l d1,d2 ; first reference from the beginning of the module
|
||
move.w d2,ParallelJumpTableEntryInfo.referenceListHead(a1,d3.l); now the reference list head is fixed as promised earlier
|
||
bra.s @noPendingModule ; go back and loop
|
||
|
||
; we got a special opcode saying to skip some entries in the jump table
|
||
@skipJumpTableEntries
|
||
move.b (a2)+,d2 ; get number of entries to skip
|
||
bz.s @doneResource ; 0, that means end of table
|
||
cmp.b #255,d2 ; 255 means number is two bytes
|
||
bne.s @gotSkip ; otherwise, got number of entries to skip
|
||
|
||
move.b (a2)+,d2 ; number of entries to skip is a word
|
||
lsl.w #8,d2 ; push it up
|
||
move.b (a2)+,d2 ; get low byte
|
||
|
||
@gotSkip
|
||
lsl.l #2,d2 ; each jump table entry is 6 bytes, so multiply size * 4
|
||
add.l d2,a0 ; advance to a new place in the jump table
|
||
lsr.l #1,d2 ; and add size * 2
|
||
add.l d2,a0 ; advance to a new place in the jump table
|
||
bra.s @loop ; continue in the loop
|
||
|
||
@doneResource
|
||
bsr.s @finishModule ; finish the last module
|
||
|
||
move.l a2,PatchResourceEntry.ptr(a4) ; PatchResourceEntry.ptr now points to packed patch table
|
||
lea PatchResourceEntry.size(a4),a4 ; advance to the next resource
|
||
bra @nextResource
|
||
@done
|
||
|
||
;ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ
|
||
|
||
FindAllResidentCode
|
||
; find resident entries in install routines, make patches resident
|
||
; note that the packed patch table is only in the universal 'lpch' resource
|
||
|
||
move.l PatchResourceEntry.ptr(sp),a2 ; point at the packed patch table
|
||
lea FindOrMakeResident,a1
|
||
bsr ForPatchTable ; do that for each triggered entry in the table
|
||
|
||
;ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ
|
||
|
||
CutBackResidentCode
|
||
; cut back the block containing the resident code
|
||
|
||
if INITVERSION then
|
||
; in INIT version of loader, code block is a locked handle ; <40>
|
||
move.l d6,a0 ; <40> get the start of the resident code block
|
||
_RecoverHandle ; <40>
|
||
move.l g.residentTop(a5),d0 ; <40> get the end of the resident code block
|
||
sub.l d6,d0 ; <40> calculate the size of the resident code block
|
||
_SetHandleSize ; <40>
|
||
else
|
||
move.l g.residentTop(a5),d0 ; get the end of the resident code block
|
||
move.l d6,a0 ; get the start of the resident code block
|
||
sub.l a0,d0 ; calculate the size of the resident code block
|
||
_SetPtrSize
|
||
endif
|
||
|
||
;ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ
|
||
|
||
GetIslandsOutOfJumpTable
|
||
; get references to islands out of the jump table
|
||
; MakeResident creates the islands, and points the jump table at them.
|
||
|
||
lea g.jumpTable(a5),a0 ; point at jump table
|
||
move.l g.ParallelJumpTableEntryInfoTableOffset(a5),d3 ; offset to parallel jump table
|
||
|
||
move.w d5,d1 ; initialize loop counter with number of entries in jump table
|
||
@loop
|
||
bclr #islandFlagBit,ParallelJumpTableEntryInfo.flags(a0,d3.l); was this an island?
|
||
bz.s @next ; no, go on to the next
|
||
move.l JumpTableEntry.address(a0),a1 ; yes, we cleared the island bit, point at island
|
||
move.l JumpTableEntry.address(a1),JumpTableEntry.address(a0) ; jam in the real address found in the island
|
||
@next
|
||
addq.l #JumpTableEntry.size,a0 ; advance to the next jump table entry
|
||
dbra d1,@loop ; loop through the whole jump table
|
||
|
||
;ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ
|
||
|
||
TellDebuggerToLookAtJumpTable
|
||
|
||
; call the debugger if he is here, and notify him that we just nailed everything down
|
||
; debugger interface is:
|
||
; d5.w -> number of jump table entries
|
||
; d6.l -> pointer to patch block
|
||
; 4(a5) -> first jump table entry (jumpTable global)
|
||
; -4(a5) -> end of patch block (residentTop global)
|
||
|
||
clr.w NewLoaderActive ; tells whip new loader is active
|
||
move.l LinkedPatchDebuggerPtr,d0 ; is the debugger here?
|
||
bmi.s @done
|
||
move.l d0,a0
|
||
jsr (a0) ; call the debugger
|
||
@done
|
||
|
||
;ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ
|
||
|
||
InstallAndExecute
|
||
; run through installing all the patches and executing all of the install routines
|
||
|
||
move.l PatchResourceEntry.ptr(sp),a2 ; point at the packed patch table
|
||
lea InstallOrExecute,a1
|
||
bsr ForPatchTable ; install each triggered patch in the table
|
||
|
||
;ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ
|
||
|
||
Done
|
||
|
||
; dispose all the handles left on the stack
|
||
@next
|
||
tst.w PatchResourceEntry.endOfList(sp) ; is this the end?
|
||
bz.s @done
|
||
|
||
; The System version of the linked patch loader disposes of the 'lpch' handles
|
||
; after copying the data above the boot globals so that there would not be
|
||
; two copies of the linked patches floating around in the system heap.
|
||
|
||
if INITVERSION then ; <55> we only use handles for the Init Version
|
||
move.l PatchResourceEntry.resourceHandle(sp),a0 ; <55> get rid of the resource
|
||
_DisposeHandle
|
||
endif
|
||
lea PatchResourceEntry.size(sp),sp ; pop the rest of the entry
|
||
bra.s @next
|
||
|
||
@done
|
||
addq.l #2,sp ; pop off the word that flags end of table
|
||
|
||
lea -g.offset(a5),a0 ; get pointer to the jump table block
|
||
_DisposePtr ; dispose the jump table block
|
||
|
||
if NOT INITVERSION then
|
||
move.l (sp)+,d0 ; <55> Restore the original value of <55> FM ;restore MemTop
|
||
move.l d0,MemTop ; <55> MemTop that we saved earlier <55> FM
|
||
endif
|
||
|
||
movem.l (sp)+,LoadLinkedPatchesRegisters ; restore all of the registers
|
||
rts
|
||
|
||
endproc
|
||
|
||
;ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ
|
||
|
||
ROMVersions proc
|
||
|
||
macro
|
||
EmitROMVersions
|
||
lcla &index
|
||
|
||
; for each ROM, emit the version
|
||
|
||
&index: seta NumROMs$
|
||
while &index > 0 do
|
||
&index: seta &index - 1
|
||
dc.w ROMVersion$&index
|
||
endwhile
|
||
endm
|
||
|
||
EmitROMVersions
|
||
dc.w 0
|
||
|
||
endproc
|
||
|
||
;ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ
|
||
|
||
ForPatchTable proc
|
||
|
||
; Traverse the patch table, calling the passed function for each patch that is triggered.
|
||
;
|
||
; In:
|
||
; g.romNumber(a5) number of the ROM we are running on
|
||
; g.nonROMConditions(a5) mask of other conditions
|
||
;
|
||
; a2 start of the patch table
|
||
; a1 function to be called for each patch routine
|
||
; In:
|
||
; a0 pointer to jump table entry
|
||
; d0.w trap number
|
||
; ccr result of tst.w d0
|
||
; a5 globals
|
||
; Out:
|
||
; can trash d0-d7/a0-a6
|
||
; Out:
|
||
; a2 points right *after* the condition table
|
||
;
|
||
; trashes d0-d2/a0-a1
|
||
;
|
||
; A reminder about the format of the packed patch table:
|
||
;
|
||
; Patches are grouped in sets of patches which have the same loading conditions. Each
|
||
; set is preceded by the load condition (1 to 4 bytes), followed by offsets for each
|
||
; entry, with the following encoding:
|
||
;
|
||
; 0-253 number of entries until the next patch
|
||
; 254 end of this set of patches, new load condition and another set follows
|
||
; 255 two bytes follow with the number of entries until the next patch (0 for end of table)
|
||
;
|
||
; After each offset is the trap number, which is two bytes. A trap number of 0 indicates an install proc.
|
||
; The table ends with a 255 followed by two bytes of 0.
|
||
|
||
ForPatchTableRegisters reg d3-d7/a3-a4/a6
|
||
ForPatchTableFunctionRegisters reg d2/a0-a2/a5
|
||
|
||
movem.l ForPatchTableRegisters,-(sp)
|
||
|
||
lea g.jumpTable(a5),a0 ; start out pointer at first jump table entry
|
||
|
||
NextCondition
|
||
; for each condition, check if it is active and skip it if not
|
||
|
||
if NumConditions$ <= 8 then
|
||
move.b (a2)+,d0 ; get the conditions (1 byte)
|
||
elseif NumConditions$ <= 16 then
|
||
move.b (a2)+,d0 ; get the conditions (2 bytes)
|
||
lsl.w #8,d0 ; push it up
|
||
move.b (a2)+,d0 ; get the next byte
|
||
elseif NumConditions$ <= 24 then
|
||
move.b (a2)+,d0 ; get the conditions (3 bytes)
|
||
swap d0 ; push it up
|
||
move.b (a2)+,d0 ; get the next byte
|
||
lsl.w #8,d0 ; push it up
|
||
move.b (a2)+,d0 ; get the next byte
|
||
else
|
||
move.b (a2)+,d0 ; get the conditions (4 bytes)
|
||
lsl.w #8,d0 ; push it up
|
||
move.b (a2)+,d0 ; get the next byte
|
||
swap d0 ; push it up
|
||
move.b (a2)+,d0 ; get the next byte
|
||
lsl.w #8,d0 ; push it up
|
||
move.b (a2)+,d0 ; get the next byte
|
||
endif
|
||
|
||
; the ROM must be one of the ROMs specified in the mask
|
||
|
||
move.w g.romNumber(a5),d1 ; get the ROM number
|
||
btst.l d1,d0 ; is the condition true for this ROM?
|
||
bz.s ConditionFalse ; no, condition not met
|
||
|
||
; all conditions specified must be true
|
||
|
||
if NumConditions$ <= 8 then
|
||
and.b #NonROMConditionsMask$,d0 ; conditions that must be true (1 byte)
|
||
move.b g.nonROMConditions(a5),d1 ; conditions that are true
|
||
and.b d0,d1 ; donÕt care about conditions not in the check word
|
||
cmp.b d0,d1 ; if all are true, then we should load
|
||
elseif NumConditions$ <= 16 then
|
||
and.w #NonROMConditionsMask$,d0 ; conditions that must be true (2 bytes)
|
||
move.w g.nonROMConditions(a5),d1 ; conditions that are true
|
||
and.w d0,d1 ; donÕt care about conditions not in the check word
|
||
cmp.w d0,d1 ; if all are true, then we should load
|
||
else
|
||
and.l #NonROMConditionsMask$,d0 ; conditions that must be true (3 or 4 bytes)
|
||
move.l g.nonROMConditions(a5),d1 ; conditions that are true
|
||
and.l d0,d1 ; donÕt care about conditions not in the check word
|
||
cmp.l d0,d1 ; if all are true, then we should load
|
||
endif
|
||
beq.s ConditionTrue ; required conditions are all met, go load
|
||
|
||
ConditionFalse
|
||
moveq #0,d2 ; flag condition false
|
||
bra.s NextPatch
|
||
ConditionTrue
|
||
moveq #1,d2 ; flag condition true
|
||
|
||
NextPatch
|
||
moveq #0,d1 ; get number of jump table entries until next patch
|
||
move.b (a2)+,d1 ; from patch table
|
||
|
||
cmp.b #254,d1 ; check for special opcodes
|
||
bhi.s @word ; 255 means number of entries is word sized, get it
|
||
beq.s NextCondition ; 254 means end of this set of patches, get next condition
|
||
|
||
@gotDistance
|
||
add.w d1,d1 ; number of entries * 2
|
||
add.l d1,a0 ; advance in the jump table
|
||
add.w d1,d1 ; number of entries * 4
|
||
add.l d1,a0 ; advance in the jump table (entries are 6 bytes)
|
||
|
||
move.b (a2)+,d0 ; get high byte of trap number
|
||
lsl.w #8,d0 ; push it up
|
||
move.b (a2)+,d0 ; get low byte of trap number
|
||
|
||
tst.b d2 ; was condition true?
|
||
beq.s NextPatch ; no, continue with the next patch
|
||
|
||
tst.w d0 ; set up condition codes, testing for install proc
|
||
movem.l ForPatchTableFunctionRegisters,-(sp)
|
||
jsr (a1) ; call the function (can trash anything)
|
||
movem.l (sp)+,ForPatchTableFunctionRegisters
|
||
|
||
bra.s NextPatch ; continue with the next patch
|
||
|
||
; we got a special opcode saying that current entry in packed patch table is word length
|
||
@word
|
||
move.b (a2)+,d1 ; get high byte of word
|
||
lsl.w #8,d1 ; move into the high byte
|
||
move.b (a2)+,d1 ; get low byte of word
|
||
tst.w d1 ; test whole word
|
||
bz.s Done ; 0 means end of table
|
||
bra.s @gotDistance
|
||
|
||
Done
|
||
movem.l (sp)+,ForPatchTableRegisters
|
||
rts
|
||
|
||
endproc
|
||
|
||
;ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ
|
||
|
||
proc
|
||
|
||
entry FindOrMakeResident
|
||
entry MakeResident
|
||
entry MakeNonResident
|
||
entry FindResident
|
||
|
||
import CheckPatchTableRange
|
||
|
||
;ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ
|
||
|
||
MakeResidentConservative
|
||
|
||
; Fixes the routine down in resident space, only if all modules referenced
|
||
; in the routine can be nailed down first. Note that this will always happen,
|
||
; except when there are cycles in the reference graph.
|
||
|
||
moveq #0,d7 ; flag resident
|
||
moveq #0,d6 ; flag Make, not Find
|
||
moveq #1,d5 ; flag conservative
|
||
bra.s MakeFindResidentAnyPoliticsCommon
|
||
|
||
;ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ
|
||
|
||
FindOrMakeResident
|
||
|
||
; Do a FindResident if the CCs say zero, or a MakeResident otherwise.
|
||
;
|
||
; This comes in handy when iterating through jump table entries in the patch table, because the
|
||
; trap number is tested just before calling here, and a trap number of 0 means install code, which
|
||
; should be FoundResident, while any other trap number means a patch, which should be MadeResident.
|
||
|
||
bz.s FindResident
|
||
; fall into MakeResident
|
||
|
||
;ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ
|
||
|
||
MakeResident
|
||
|
||
; Fixes the routine down in resident space. No matter what (i.e. non-conservative)
|
||
; even if some of itÕs references arenÕt nailed down yet. This takes care of cycles
|
||
|
||
moveq #0,d7 ; flag resident
|
||
bra.s MakeResidentCommon
|
||
|
||
;ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ
|
||
|
||
MakeNonResident
|
||
|
||
; Fixes the routine down in non-resident space. No matter what (i.e. non-conservative)
|
||
; This is used by install routines for their non resident entries
|
||
|
||
moveq #1,d7 ; flag non-resident
|
||
; fall into MakeResidentCommon
|
||
|
||
;ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ
|
||
|
||
MakeResidentCommon
|
||
moveq #0,d6 ; flag Make, not Find
|
||
bra.s MakeFindResidentCommon
|
||
|
||
;ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ
|
||
|
||
FindResident
|
||
|
||
; Makes all ÒresidentÓ references in a routine resident.
|
||
|
||
moveq #0,d7 ; flag resident (when we get down a level)
|
||
moveq #1,d6 ; flag Find, not Make
|
||
; fall into MakeFindResidentCommon
|
||
|
||
;ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ
|
||
|
||
MakeFindResidentCommon
|
||
moveq #0,d5 ; not conservative
|
||
; fall into MakeFindResidentAnyPoliticsCommon
|
||
|
||
;ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ
|
||
|
||
MakeFindResidentAnyPoliticsCommon
|
||
|
||
; Now begins the one routine that does it all:
|
||
;
|
||
; Make/Find[Non]Resident[Conservative]
|
||
;
|
||
; or, to be more explicit:
|
||
;
|
||
; FindResident
|
||
; MakeResident
|
||
; MakeResidentConservative
|
||
; MakeNonResident
|
||
;
|
||
; In:
|
||
; g.jumpTable(a5) pointer to start of jump table
|
||
; g.residentTop(a5) pointer to next available resident code
|
||
;
|
||
; a0 pointer to jump table entry
|
||
; a5 globals
|
||
; d7 0 means resident, 1 means non-resident
|
||
; d6 0 means make, 1 means find
|
||
; d5 0 means non-conservative, 1 means conservative
|
||
;
|
||
; Out:
|
||
; g.residentTop(a5) pointer to next available resident code
|
||
;
|
||
; trashes d0-d7/a0-a3
|
||
;
|
||
; The algorithm for all these cases is similar. Here is a sketch:
|
||
;
|
||
; do nothing if this module is already nailed down (i.e. a jump instruction in its opcode field)
|
||
; do nothing if this module has its FindSeenFlagBit set AND we are doing a FindResident (to prevent cycles)
|
||
; do nothing if this module has its MakeSeenFlagBit set AND we are doing a Make[Non]Resident (to prevent cycles)
|
||
; walk back the jump table until you reach the beginning of the module
|
||
; if find
|
||
; set FindSeenFlagBit for this module and all the references in it to prevent cycles
|
||
; else (doing a make)
|
||
; if resident
|
||
; set MakeSeenFlagBit for this module and all the references in it to prevent cycles
|
||
; for each thing this module refers to, do a MakeResidentConservative
|
||
; unmark MakeSeenFlagBit for this module and all the references in it (it is no longer Òhalf-nailedÓ)
|
||
; if conservative
|
||
; if not all modules made themselves resident, return
|
||
; make space in resident area for routine
|
||
; FoundFinalRestingPlace:
|
||
; fix up all jump table entries, now that we have found a final resting place
|
||
; if resident
|
||
; for each thing this module refers to that is too far away, make an island
|
||
;
|
||
; (then for both make and find)
|
||
; FollowReferences:
|
||
; for each thing this module refers to,
|
||
; if make
|
||
; do a Make[Non]Resident
|
||
; fix up the reference
|
||
; if find
|
||
; if the reference is marked resident, do a MakeResident
|
||
|
||
; <42> Before an attempt is made to nail down this module, see if the entry number for
|
||
; the module is in a range specified by the GibblyÕs patch table range list. If
|
||
; itÕs not in any of the ranges specified by this list, donÕt nail it down.
|
||
;
|
||
|
||
CheckPatchNumber
|
||
move.l a0,d1 ; calculate jump table offset
|
||
sub.l a5,d1
|
||
subq.w #g.jumpTable,d1
|
||
divu.w #JumpTableEntry.size,d1 ; Ö6 jump table entries are 6 bytes
|
||
|
||
bsr CheckPatchTableRange ; See if patch is in range
|
||
tst.b d2 ; CheckPatchTableRange returns a condition in d2
|
||
bnz.s ShortCircuitActive ; ItÕs in a range. Try to nail it down.
|
||
move.l JumpTableEntry.address(a0),d2 ; get address
|
||
bra Done
|
||
|
||
ShortCircuitActive
|
||
; do nothing if this module is already nailed down or if we hit a cycle (findSeen and makeSeen flag bits)
|
||
|
||
move.w JumpTableEntry.opcode(a0),d1 ; get the opcode
|
||
move.l JumpTableEntry.address(a0),d2 ; get address
|
||
|
||
cmp.w #kNailedDown,d1 ; already nailed down (JMP instruction)?
|
||
beq Done ; yes, we are done
|
||
|
||
move.l g.ParallelJumpTableEntryInfoTableOffset(a5),d3 ; get offset to entry table
|
||
tst.b d6 ; doing make or find?
|
||
bz @doingMake
|
||
|
||
btst #FindSeenFlagBit,ParallelJumpTableEntryInfo.flags(a0,d3.l) ; prevent cycles in find
|
||
bnz Done
|
||
bra.s WalkBackToProc
|
||
|
||
@doingMake
|
||
btst #MakeSeenFlagBit,ParallelJumpTableEntryInfo.flags(a0,d3.l) ; prevent cycles in make
|
||
bnz Done
|
||
|
||
|
||
WalkBackToProc
|
||
; walk back the jump table until you reach the beginning of the module
|
||
|
||
moveq #0,d0 ; make module size a long word
|
||
@next
|
||
move.w ParallelJumpTableEntryInfo.routineSize(a0,d3.l),d0 ; the beginning of the module (non-0 size)?
|
||
bnz.s @gotBeginning ; yes, found beginning
|
||
subq #ParallelJumpTableEntryInfo.size,a0 ; go back one jump table entry
|
||
bra.s @next
|
||
|
||
@gotBeginning
|
||
move.l JumpTableEntry.address(a0),a1 ; get pointer to start of this module
|
||
move.l a0,a2 ; save jump table entry for start of this module
|
||
|
||
moveq #0,d1
|
||
move.w ParallelJumpTableEntryInfo.referenceListHead(a0,d3.l),d1 ; get pointer to first reference inside module
|
||
|
||
; Check whether we are doing a find or a make and set the appropriate flag to prevent cycles
|
||
; Setting these flags could be considered Òhalf-nailingÓ because we are trying to nail down
|
||
; the flagged entries but we canÕt finish until we have nailed down all the entryÕs references
|
||
|
||
MarkOurselvesHalfNailed
|
||
move.l a0,a3 ; go through our references
|
||
|
||
tst.b d6 ; find references?
|
||
bz @doingMake ; no, doing a make
|
||
|
||
|
||
; Set the FindSeenFlagBit for this module and all its entries so we wonÕt get into an infinite loop later
|
||
|
||
@nextFindReference
|
||
bset #FindSeenFlagBit, ParallelJumpTableEntryInfo.flags(a3,d3.l) ; prevent cycles in find
|
||
addq.l #ParallelJumpTableEntryInfo.size,a3 ; point to the next jump table entry
|
||
tst.w ParallelJumpTableEntryInfo.routineSize(a3,d3.l) ; is this a new module (non-0 size)?
|
||
bz.s @nextFindReference ; no, still an entry within the current module
|
||
bra FollowReferences ; yes, check to see which of these references
|
||
; are marked resident
|
||
@doingMake
|
||
tst.b d7 ; resident or non-resident?
|
||
bnz.s FoundFinalRestingPlace ; non-resident, no need to move it out of the 'lpch'
|
||
|
||
; Set the MakeSeenFlagBit for this module and all its entries so we wonÕt get into an infinite loop later
|
||
|
||
@next
|
||
bset #MakeSeenFlagBit, ParallelJumpTableEntryInfo.flags(a3,d3.l) ; prevent cycles in make
|
||
addq.l #ParallelJumpTableEntryInfo.size,a3 ; point to the next jump table entry
|
||
tst.w ParallelJumpTableEntryInfo.routineSize(a3,d3.l) ; is this a new module (non-0 size)?
|
||
bz.s @next ; no, still an entry within the current module
|
||
|
||
LureInTheConservatives
|
||
; for each thing this module refers to, do a MakeResidentConservative
|
||
; also keep track to see that all is nailed down. If a referenced entry
|
||
; is not nailed down we return an error by clearing d4
|
||
|
||
moveq #1,d4 ; assume for now that all will be nailed down
|
||
|
||
lea @doOne,a3 ; letÕs go makinÕ
|
||
bsr ForAllReferences ; get those evil right wingers in memory
|
||
bra.s @continue
|
||
|
||
; LureInTheConservatives iterator
|
||
; this routine is iterated over each entry referenced by the current module
|
||
; it attempts to nail down as many of the references as possible by calling MakeResidentConservative
|
||
@doOne
|
||
movem.l d4/a0,-(sp) ; remember him
|
||
bsr.s MakeResidentConservative ; go lock him in
|
||
movem.l (sp)+,d4/a0
|
||
cmp.w #kNailedDown,JumpTableEntry.opcode(a0) ; did he get nailed?
|
||
beq.s @ok
|
||
clr.b d4 ; nope, we have a cycle in the graph, gentlemen
|
||
@ok
|
||
rts
|
||
|
||
@continue
|
||
|
||
|
||
MarkOurselvesNotHalfNailed
|
||
; we can clear our MakeSeenFlagBit now that we are done luring in the conservatives
|
||
; we MIGHT end up recursing later in ÒMakeIslandsÓ but by that time we will be nailed
|
||
; down and the protection of the MakeSeenFlagBit will be unecessary
|
||
|
||
move.l a0,a3 ; go through our references
|
||
move.l g.ParallelJumpTableEntryInfoTableOffset(a5),d3 ; offset to parallel info list
|
||
@next
|
||
bclr #MakeSeenFlagBit, ParallelJumpTableEntryInfo.flags(a3,d3.l) ; clear the flag bit
|
||
addq.l #ParallelJumpTableEntryInfo.size,a3 ; point to the next entry
|
||
tst.w ParallelJumpTableEntryInfo.routineSize(a3,d3.l) ; is this a new module (non-0 size)?
|
||
bz.s @next ; no, still an entry within the current module
|
||
|
||
ExitIfConservativeFailure
|
||
; if weÕre conservative, and we couldn't make all our references resident, then fail
|
||
|
||
tst.b d5 ; are we conservative?
|
||
bz.s @survive ; no, we survive no matter what
|
||
|
||
; if not all modules made themselves resident, return
|
||
|
||
tst.b d4 ; anyone blow it?
|
||
bnz @survive ; no, continue
|
||
bra Done
|
||
@survive
|
||
|
||
MoveResident
|
||
; make space in resident area for routine, and move it there
|
||
|
||
move.l a1,a0 ; point to the module
|
||
move.l g.residentTop(a5),a1 ; get place to put it in resident area
|
||
add.l d0,g.residentTop(a5) ; advance past it
|
||
_BlockMove
|
||
|
||
FoundFinalRestingPlace
|
||
; fix up all jump table entries, now that we have found a final resting place
|
||
; this is either in the resident block or in the code of the 'lpch' if non-resident
|
||
|
||
move.l g.ParallelJumpTableEntryInfoTableOffset(a5),d3 ; offset to parallel jump table
|
||
move.l a1,d0 ; calculate fixup
|
||
sub.l JumpTableEntry.address(a2),d0 ; by subtracting offset of start of module
|
||
add.l d0,d2 ; save away the resident address for the entry
|
||
; weÕre looking at (we return this later)
|
||
@next
|
||
add.l d0,JumpTableEntry.address(a2) ; convert address in non-resident space to a real address
|
||
move.w #kNailedDown,JumpTableEntry.opcode(a2) ; mark as nailed down (this is a JMP opcode)
|
||
addq.l #JumpTableEntry.size,a2 ; point to the next entry
|
||
tst.w ParallelJumpTableEntryInfo.routineSize(a2,d3.l) ; is this a new module (non-0 size)?
|
||
bz.s @next ; no, keep looping
|
||
|
||
MakeIslands
|
||
; if module is resident, for each thing the module refers to that is too far away, make an island
|
||
|
||
tst.b d7 ; resident or non-resident?
|
||
bnz.s FollowReferences ; non-resident, no need for islands
|
||
|
||
lea @doOne,a3 ; letÕs go to the islands
|
||
bsr ForAllReferences ; make Õem
|
||
bra.s @continue
|
||
|
||
; MakeIslands iterator
|
||
; This routine is iterated over each entry referenced by the current module.
|
||
; It attempts to make an island in the resident block for references more than 32k away.
|
||
; Note that an island is the same as a nailed down jump table entry, i.e. JMP address.
|
||
@doOne
|
||
cmp.b #kAbsoluteOpcode*2,d0 ; never make islands for absolute references
|
||
beq.s @done
|
||
|
||
cmp.w #kNailedDown,JumpTableEntry.opcode(a0) ; a backward reference (already nailed)?
|
||
beq.s @backRef ; yes, can only make an island for backward refs.
|
||
bra @done
|
||
|
||
@backRef
|
||
move.l g.ParallelJumpTableEntryInfoTableOffset(a5),d3 ; offset to parallel info list
|
||
move.l JumpTableEntry.address(a0),a4 ; get address of routine
|
||
move.l a4,a2
|
||
sub.l a1,a2 ; get offset from here to routine
|
||
cmpa.w a2,a2 ; is it in range? (warning! 68000 hack!)
|
||
beq.s @done ; yes, no need for an island
|
||
|
||
; mark as island, and if we already had an island, get real address from the island itself
|
||
|
||
bset #islandFlagBit,ParallelJumpTableEntryInfo.flags(a0,d3.l)
|
||
bz.s @gotAddress ; island flag wasnÕt set, we have the real address
|
||
move.l 2(a4),a4 ; extract the address from the island itself
|
||
; weÕll be making an island to an island
|
||
|
||
@gotAddress
|
||
; lay down the island, and point jump table at it
|
||
|
||
move.l g.residentTop(a5),a2 ; point to new place for island
|
||
|
||
move.l a2,JumpTableEntry.address(a0) ; store island address in the jump table
|
||
|
||
move.w #kNailedDown,JumpTableEntry.opcode(a2) ; lay down a jump
|
||
move.l a4,JumpTableEntry.address(a2) ; to the real routine address
|
||
addq.l #JumpTableEntry.size,a2
|
||
move.l a2,g.residentTop(a5) ; island is allocated now
|
||
@done
|
||
rts
|
||
|
||
@continue
|
||
|
||
; executed for both finds and makes
|
||
|
||
FollowReferences
|
||
; Recurse calling FindResident or MakeResident for each entry referenced by the current module.
|
||
|
||
lea @doOne,a3 ; recurse over the references
|
||
bsr ForAllReferences
|
||
tst.b d6 ; doing find?
|
||
bz @continue ; no, itÕs a make
|
||
|
||
; if we were doing a find we need to clear our FindSeenFlagBit now
|
||
move.l a0,a3 ; yes, go through our references
|
||
move.l g.ParallelJumpTableEntryInfoTableOffset(a5),d3 ; offset to parallel info list
|
||
@next
|
||
bclr #FindSeenFlagBit, ParallelJumpTableEntryInfo.flags(a3,d3.l) ; clear the flag bit
|
||
addq.l #ParallelJumpTableEntryInfo.size,a3 ; point to the next entry
|
||
tst.w ParallelJumpTableEntryInfo.routineSize(a3,d3.l) ; is this a new module (non-0 size)?
|
||
bz.s @next ; no, still an entry within the current module
|
||
|
||
bra.w @continue
|
||
|
||
; FollowReferences iterator
|
||
; This routine is iterated over each entry referenced by the current module.
|
||
; Recurses doing a FindResident or MakeResident on each entry.
|
||
; Finally, we fix up the reference inside the code itself.
|
||
|
||
@doOne
|
||
; recurse with either FindResident or MakeResident
|
||
|
||
movea.l a0,a3 ; save address of jump table entry (keep carry flag)
|
||
|
||
@registers reg d0/d2/d3/d6/a1/a3
|
||
|
||
; if we are doing a FindResident, and this is a force-resident reference
|
||
; we have found something that we want to MakeResident, so recurse with a MakeResident
|
||
; on it instead of recursing with a FindResident
|
||
|
||
movem.l @registers,-(sp) ; keep carry flag
|
||
bcc.s @noForce ; reference not marked force-resident, skip over this
|
||
moveq #0,d6 ; force use to make resident, instead of just finding
|
||
@noForce
|
||
bsr MakeFindResidentCommon ; make this resident, or find more resident references
|
||
movem.l (sp)+,@registers
|
||
|
||
; in find case, do nothing else
|
||
|
||
tst.b d6 ; is this a find (not make)?
|
||
bnz.s @done ; yes, our job is done
|
||
|
||
; now, let us fix up the reference (at long last)
|
||
|
||
move.l g.ParallelJumpTableEntryInfoTableOffset(a5),d3 ; offset to parallel info list
|
||
|
||
cmp.b #kAbsoluteOpcode*2,d0 ; is it a 32-bit reference?
|
||
beq.s @32Bit
|
||
|
||
tst.b d7 ; non-resident?
|
||
bnz.s @nonResident ; yes, go handle it that way
|
||
|
||
; take special case of LEA or PEA to island into account (need address, not JMP opcode)
|
||
|
||
btst #islandFlagBit,ParallelJumpTableEntryInfo.flags(a3,d3.l)
|
||
bz.s @noOffset ; some island opcodes need offsets
|
||
add.w IslandOffsets(d0.w),a0 ; point to address instead of to JMP in island
|
||
|
||
@noOffset
|
||
|
||
; now check the distance
|
||
|
||
move.l a0,a2 ; get address of routine
|
||
sub.l a1,a2 ; get offset from here to routine
|
||
cmpa.w a2,a2 ; is it in range? (warning! 68000 hack!)
|
||
beq.s @ok ; yes, everything is OK
|
||
|
||
; Sometimes we can use the real thing instead of the island and it wonÕt be out of range.
|
||
|
||
btst #islandFlagBit,ParallelJumpTableEntryInfo.flags(a3,d3.l)
|
||
bz.s @notOK ; if not island then we canÕt try indirection
|
||
|
||
move.l 2(a0),a0 ; get what the island points to
|
||
move.l a0,a2 ; get address of routine
|
||
sub.l a1,a2 ; get offset from here to routine
|
||
cmpa.w a2,a2 ; is it in range? (warning! 68000 hack!)
|
||
bne.s @notOk ; no, everything is notOK
|
||
move.w a2,(a1) ; store the offset
|
||
bra.s @notIsland ; continue with a non-island address
|
||
|
||
@notOk
|
||
moveq #dsLinkedPatchReferenceTooFar,d0 ; yes, big problem
|
||
_SysError
|
||
@ok
|
||
|
||
; now store the offset, and then the opcode
|
||
|
||
move.w a2,(a1) ; store the offset
|
||
|
||
btst #islandFlagBit,ParallelJumpTableEntryInfo.flags(a3,d3.l)
|
||
bnz.s @island ; yes, go handle it
|
||
|
||
@notIsland
|
||
move.w PCRelativeOpcodes(d0.w),-(a1) ; store the opcode
|
||
@done
|
||
rts
|
||
|
||
@island
|
||
move.w IslandOpcodes(d0.w),-(a1) ; store the opcode (use MOVE instead of LEA)
|
||
rts
|
||
|
||
@nonResident
|
||
add.w A5RelativeOffsets(d0.w),d2 ; turn jump table offset into A5 offset
|
||
move.w d2,(a1) ; store the offset
|
||
move.w A5RelativeOpcodes(d0.w),-(a1) ; store the opcode
|
||
rts
|
||
|
||
@32Bit
|
||
btst #islandFlagBit,ParallelJumpTableEntryInfo.flags(a3,d3.l)
|
||
bz.s @noIsland ; donÕt have to follow the island
|
||
move.l 2(a0),a0 ; get address of real thing from the island
|
||
@noIsland
|
||
move.l a0,-2(a1) ; store the address as a long absolute
|
||
rts
|
||
|
||
@continue
|
||
|
||
Done
|
||
; we are done, return the resident address
|
||
|
||
move.l d2,a0 ; result
|
||
rts
|
||
|
||
IslandOffsets
|
||
dcb.w 9,2 ; address for MOVE.L
|
||
dcb.w 2,0 ; opcode for JSR, JMP
|
||
|
||
PCRelativeOpcodes
|
||
dc.w $41FA,$43FA,$45FA,$47FA,$49FA,$4BFA,$4DFA,$4FFA,$487A ; LEA A0-A7, PEA
|
||
dc.w $4EBA,$4EFA ; JSR, JMP
|
||
|
||
IslandOpcodes
|
||
dc.w $207A,$227A,$247A,$267A,$287A,$2A7A,$2C7A,$2E7A,$2F3A ; MOVEA.L A0-A7, -(SP)
|
||
dc.w $4EBA,$4EFA ; JSR, JMP
|
||
|
||
|
||
A5RelativeOpcodes
|
||
dc.w $206D,$226D,$246D,$266D,$286D,$2A6D,$2C6D,$2E6D,$2F2D ; MOVEA.L A0-A7, -(SP)
|
||
dc.w $4EAD,$4EED ; JSR, JMP
|
||
|
||
A5RelativeOffsets
|
||
dcb.w 9,g.jumpTable+JumpTableEntry.address ; address for MOVE.L
|
||
dcb.w 2,g.jumpTable+JumpTableEntry.opcode ; opcode for JSR, JMP
|
||
|
||
;ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ
|
||
|
||
ForAllReferences
|
||
|
||
; Traverse the reference list, calling the passed function for each reference.
|
||
;
|
||
; In:
|
||
; a5 pointer to the globals (including the jump table)
|
||
; d1.l reference list head (offset into routine); 1 means do nothing
|
||
; a1 pointer to beginning of module
|
||
; d4/d6 values to be passed through
|
||
; a3 function to be called repeatedly
|
||
; In:
|
||
; a0 jump table entry of this reference
|
||
; d0.w opcode, expressed as an offset into a table of words
|
||
; a1 pointer to code (after opcode)
|
||
; d2.w jump table offset
|
||
; ccr carry set if this is a Òforce-residentÓ reference
|
||
; d4 passed through (in and out)
|
||
; d5-d7 passed through
|
||
; trashes d0-d7/a0-a4
|
||
;
|
||
; trashes d4
|
||
;
|
||
; A reminder about the format of references within modules:
|
||
;
|
||
; Before they are fixed up, references are 4 bytes as follows.
|
||
;
|
||
; +---------------------------------
|
||
; 2 bytes | F | offset to next reference |
|
||
; +---------------------------------
|
||
; +---------------------------------
|
||
; 2 bytes | OPCD | jump table entry number |
|
||
; +---------------------------------
|
||
;
|
||
; The first two bytes consist of a flag (F) in the first bit (1 for force-resident, 0 otherwise),
|
||
; followed by the offset to the next reference in the module, in words.
|
||
;
|
||
; The second two bytes consist of 4 bits (OPCD) corresponding to the opcode number, followed by
|
||
; 12 bits corresponding to the jump table entry number for this reference (limiting the number
|
||
; of jump table entries to 4096 max).
|
||
;
|
||
|
||
ForAllReferencesRegisters reg d0-d3/a0-a2/a4
|
||
ForAllReferencesFunctionRegisters reg d1/d5-d7/a1/a3
|
||
|
||
|
||
movem.l ForAllReferencesRegisters,-(sp)
|
||
|
||
bclr #0,d1 ; head of list can be 0 (1 means no references)
|
||
bz.s @skipTest ; if low bit is clear, skip the check
|
||
|
||
@next
|
||
tst.w d1 ; 0 means the end of the reference list
|
||
bz.s @done
|
||
@skipTest
|
||
|
||
add.l d1,a1 ; advance to item in reference list
|
||
move.w (a1),d1 ; get offset to next reference in module
|
||
move.w 2(a1),d0 ; get opcode number and jump table entry number
|
||
|
||
lea g.jumpTable(a5),a0 ; point to jump table
|
||
|
||
move.w d0,d2 ; calculate jump table entry number
|
||
lsl.w #4,d2 ; clear high 4 bits (opcode number)
|
||
lsr.w #3,d2 ; x2 (jump table entries are 6 bytes)
|
||
add.w d2,a0 ; advance in the jump table
|
||
move.w d2,d3 ; d3 = entry number * 2
|
||
add.w d2,d2 ; x4 (jump table entries are 6 bytes)
|
||
add.w d2,a0 ; advance in the jump table
|
||
add.w d3,d2 ; d3 = entry number * 6 for function call
|
||
|
||
lsr.w #8,d0 ; calculate offset into opcode table
|
||
lsr.w #4,d0 ; shift by 12 (roll high 4 bits down to the bottom)
|
||
add.w d0,d0 ; make into opcode table offset
|
||
|
||
add.w d1,d1 ; calculate offset to next reference (which was in words)
|
||
; and test the high bit (force-resident flag)
|
||
movem.l ForAllReferencesFunctionRegisters,-(sp)
|
||
addq #2,a1 ; point after opcode, before operand
|
||
jsr (a3) ; call the iterator
|
||
movem.l (sp)+,ForAllReferencesFunctionRegisters
|
||
|
||
bra.s @next
|
||
|
||
@done
|
||
movem.l (sp)+,ForAllReferencesRegisters
|
||
rts
|
||
|
||
endproc
|
||
|
||
;ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ
|
||
|
||
proc
|
||
|
||
export InstallOrExecute
|
||
|
||
import MakeNonResident
|
||
|
||
import GetPatchAddress
|
||
import SetPatchAddress
|
||
|
||
import FlushInstructionCache
|
||
import CheckPatchTableRange
|
||
|
||
InstallOrExecute
|
||
|
||
; Installs a patch or executes an install routine.
|
||
;
|
||
; In:
|
||
; a0 pointer to jump table entry
|
||
; d0.w trap number
|
||
; ccr z for install routine, nz for patch
|
||
;
|
||
; trashes d0-d7/a0-a6
|
||
|
||
; debugging code to break before installing specified jump table entries
|
||
;
|
||
; <62> This code used to be turned off for linked patch INITs, and we couldnÕt figure out
|
||
; why so we turned it on. If someone figures out why this was turned off for INITs,
|
||
; change it back, then come yell at us for not knowing any better.
|
||
|
||
move.l a0,d1 ; calculate jump table offset
|
||
sub.l a5,d1
|
||
subq.w #g.jumpTable,d1
|
||
divu.w #JumpTableEntry.size,d1 ; Ö6 jump table entries are 6 bytes
|
||
move.w d1,StashJumpTableEntryNum ; stash the jump table entry number
|
||
|
||
; <39> The conditions for this patch have been met. Check the patch number against the ranges
|
||
; in the patch table to determine if it should be installed or not.
|
||
|
||
bsr CheckPatchTableRange ; <39> See if patch is in range
|
||
tst.b d2 ; <39> CheckPatchTableRange returns a condition in d2
|
||
bz.s Done ; <39> Zero means donÕt load the patch.
|
||
|
||
; Chris, Greg and I always have trouble how to use these globals, so IÕm adding comments
|
||
; about it so we donÕt have to do this by trial and error any more.
|
||
;
|
||
; To stop on a particular linked patch entry:
|
||
; StopOnJumpTableEntryNum ($922) = linked patch entry to stop on
|
||
; StopOnJumpTableEntryNumHighest ($924) = -1
|
||
;
|
||
; To stop on a range of linked patch entries
|
||
; StopOnJumpTableEntryNum ($922) = lower end of range of entries to break on
|
||
; StopOnJumpTableEntryNumHighest ($924) = upper end of range of entries to break on
|
||
|
||
tst.w StopOnJumpTableEntryNumHighest ; should we test a range?
|
||
bmi.s @notRange
|
||
|
||
cmp.w StopOnJumpTableEntryNum,d1
|
||
bhs.s @stop ; stop if we are <= target
|
||
cmp.w StopOnJumpTableEntryNumHighest,d1
|
||
bls.s @stop ; stop if we are >= target
|
||
bra.s @dontStop
|
||
@notRange
|
||
cmp.w StopOnJumpTableEntryNum,d1
|
||
bne.s @dontStop ; stop if we hit the target entry <31>
|
||
@stop
|
||
_Debugger
|
||
@dontStop
|
||
|
||
tst.w d0
|
||
|
||
; end of debugging code (have to do the tst.w since we screwed up the condition codes)
|
||
|
||
bnz.s InstallPatch ; itÕs a patch, go install it
|
||
|
||
ExecuteInstallRoutine
|
||
; execute an install routine
|
||
|
||
bsr MakeNonResident ; nail down install routine and references
|
||
bsr FlushInstructionCache ; this better not trash a0
|
||
if INITVERSION then
|
||
move.l TheZone,-(sp) ; save the current zone
|
||
move.l SysZone,TheZone ; set to the System heap
|
||
jsr (a0) ; call it
|
||
move.l (sp)+,TheZone ; restore the zone
|
||
rts
|
||
else
|
||
jmp (a0) ; call it
|
||
endif
|
||
|
||
InstallPatch
|
||
; install a patch
|
||
|
||
move.l g.ParallelJumpTableEntryInfoTableOffset(a5),d3 ; parallel entry table offset in d3
|
||
move.l a0,a1 ; keep jump table pointer here
|
||
move.w d0,d6 ; save trap number
|
||
|
||
FixOld
|
||
; find magic cookies and replace them with the old patch address
|
||
|
||
bsr.s GetPatchAddress ; get the old address of this patch
|
||
move.l a0,d4 ; keep it here to fix up
|
||
move.l JumpTableEntry.address(a1),a0 ; get the address of the patch routine
|
||
move.l a0,a2 ; and get ready to traverse it
|
||
move.w ParallelJumpTableEntryInfo.routineSize(a1,d3.l),d1 ; get the size of the patch routine
|
||
lsr.w #1,d1 ; turn the size into a DBRA count (words)
|
||
subq.w #2,d1 ; 1 for DBRA, 1 for last word (cookie is long)
|
||
blo.s @done ; routine very small
|
||
|
||
move.w #(OldTrapAddressMagicCookie >> 16),d2 ; look for high word of magic cookie
|
||
move.w #(OldTrapAddressMagicCookie and $FFFF),d3 ; look for low word of magic cookie
|
||
@next
|
||
cmp.w (a2)+,d2 ; did we find it?
|
||
@compared
|
||
dbeq d1,@next ; go until we do
|
||
bne.s @done
|
||
|
||
cmp.w (a2),d3 ; look for the low word
|
||
bne.s @compared ; nope, keep going
|
||
|
||
move.l d4,-2(a2) ; do a fixup right here
|
||
bra.s @compared ; keep going
|
||
@done
|
||
|
||
SetNew
|
||
; point at the new patch address
|
||
|
||
move.w d6,d0
|
||
bsr.w SetPatchAddress ; point at the new address of this patch
|
||
|
||
Done
|
||
rts
|
||
|
||
endproc
|
||
|
||
;ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ
|
||
|
||
GetPatchAddress proc
|
||
|
||
; Get the address of a trap or vector. (Similar interface to GetTrapAddress.)
|
||
;
|
||
; In:
|
||
; d0.w trap number (or vector number)
|
||
; Out:
|
||
; a0 address of trap or vector
|
||
;
|
||
; trashes d0/a0
|
||
|
||
cmp.w #$A000,d0 ; is it a trap?
|
||
blo.s @notTrap
|
||
_GetTrapWordAddress
|
||
rts
|
||
|
||
@notTrap
|
||
move.w d0,a0 ; get vector address in address register
|
||
cmp.w #$4000,a0 ; are we getting a vector, or ExpandMem offset?
|
||
blo.s @vector ; getting vector
|
||
|
||
@expandMem
|
||
sub.w #$4000,a0 ; change into an offset
|
||
add.l ExpandMem,a0 ; point to place within the ExpaneMem block
|
||
|
||
@vector
|
||
move.l (a0),a0 ; get old value from vector
|
||
rts
|
||
|
||
endproc
|
||
|
||
;ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ
|
||
|
||
SetPatchAddress proc
|
||
|
||
import FlushInstructionCache
|
||
|
||
; Set the address of a trap or vector. (Similar interface to SetTrapAddress.)
|
||
;
|
||
; In:
|
||
; d0.w trap number (or vector number)
|
||
; a0 address to set to
|
||
;
|
||
; trashes d0/a0
|
||
|
||
cmp.w #$A000,d0 ; is it a trap?
|
||
blo.s @notTrap
|
||
_SetTrapWordAddress
|
||
rts
|
||
|
||
@notTrap
|
||
ext.l d0 ; make vector address long
|
||
exg d0,a0 ; put vector address in address register
|
||
cmp.w #$4000,a0 ; are we setting a vector, or ExpandMem offset?
|
||
blo.s @vector ; setting vector
|
||
|
||
@expandMem
|
||
sub.w #$4000,a0 ; change into an offset
|
||
add.l ExpandMem,a0 ; point to place within the ExpaneMem block
|
||
|
||
@vector
|
||
move.l d0,(a0) ; put new address into vector
|
||
exg d0,a0 ; put everything back
|
||
bsr.s FlushInstructionCache ; this better not trash a0
|
||
rts
|
||
|
||
endproc
|
||
|
||
;ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ
|
||
|
||
FlushInstructionCache proc
|
||
|
||
; Flush the instruction cache, if there is one.
|
||
; This must be called after code that is modified in RAM.
|
||
;
|
||
; trashes no registers
|
||
|
||
movem.l d0-d2/a0-a1,-(sp)
|
||
|
||
if INITVERSION then
|
||
|
||
; *** we really only need to check if CacheFlush is implemented for pre-7.0 systems
|
||
; *** someday, we wonÕt have to support these systems even with linked patch INITs
|
||
|
||
move.w #$9f,d0
|
||
_GetTrapAddress ; Get _Unimplemented
|
||
cmp.l jCacheFlush,a0 ; is CacheFlush implemented?
|
||
beq.s @exitFlushInstructionCache ; No, return.
|
||
endif
|
||
|
||
move.l jCacheFlush,a0 ; call through this vector
|
||
jsr (a0)
|
||
|
||
@exitFlushInstructionCache ; <20> mrr
|
||
movem.l (sp)+,d0-d2/a0-a1
|
||
rts
|
||
|
||
endproc
|
||
|
||
;ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ
|
||
|
||
CheckPatchTableRange Proc Export
|
||
|
||
;
|
||
; <39> Check the patch count index against the ranges stored in the patch range table. DonÕt load the
|
||
; patch if it isnÕt in one of the ranges.
|
||
;
|
||
; In: D1: Jump table entry number
|
||
;
|
||
; Out: D2: Zero if entry is in a range, non zero if not.
|
||
;
|
||
; Format of the patch range table (pointed to by g.patchRangeTable) is:
|
||
;
|
||
; 2 bytes version
|
||
; 2 bytes number of ranges that follow - 1
|
||
;
|
||
; for each range:
|
||
;
|
||
; 2 bytes entry number of first patch count index to load
|
||
; 2 bytes entry number of last patch count index to load
|
||
;
|
||
; note: ranges must be sorted in ascending order
|
||
;
|
||
|
||
movem.l a0/d0-d1,-(sp) ; Save off registers that are used
|
||
move.l g.patchRangeTable(a5),a0 ; Get pointer to patch table ranges
|
||
addq #2,a0 ; Skip past version
|
||
move.w (a0)+,d0 ; Get range count
|
||
bmi.s @dontLoadPatch ; <44> If negative, there are no ranges in this list.
|
||
moveq #1,d2 ; Assume patch should be loaded
|
||
@checkRangeLoop
|
||
cmp.w (a0)+,d1 ; Check against lower bound
|
||
blt.s @dontLoadPatch ; If lower, donÕt load
|
||
cmp.w (a0)+,d1 ; Check against upper bound
|
||
bls.s @loadPatch ; Patch should be loaded
|
||
dbra d0,@checkRangeLoop ; Loop through all the ranges
|
||
@dontLoadPatch
|
||
moveq #0,d2 ; If patch was not in any range, donÕt load it
|
||
@loadPatch
|
||
movem.l (sp)+,a0/d0-d1 ; Restore everything that was used except for D2
|
||
rts
|
||
EndProc
|
||
|
||
;ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ
|
||
|
||
TrapImplemented proc ; <31>
|
||
|
||
; Pass in a trap address in a0 and figure out whether it is implemented.
|
||
; If eq, the trap is not implemented.
|
||
; Trashes no registers.
|
||
|
||
movem.l d0/a0-a1,-(sp)
|
||
move.l a0,a1
|
||
move.w #kUnimplementedTrap,d0 ; get address of unimplemented trap
|
||
_GetTrapAddress
|
||
cmp.l a0,a1 ; see if trap is implemented
|
||
movem.l (sp)+,d0/a0-a1
|
||
rts
|
||
|
||
endproc
|
||
|
||
;ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ
|
||
|
||
MrGestalt proc ; <31>
|
||
|
||
; Call Gestalt, and get the result into d0.
|
||
; Return 0 for result if Gestalt or selector is unknown.
|
||
; This wonÕt work for all Gestalt selectors, but it will for most.
|
||
; Trashes d0 only.
|
||
|
||
move.l a0,-(sp)
|
||
move.l d0,-(sp)
|
||
move.w #kGestaltTrap,d0
|
||
_GetTrapAddress newOS ; get address of Gestalt
|
||
jsr TrapImplemented
|
||
beq.s @dropStackReturn0 ; no Gestalt, return 0
|
||
move.l (sp)+,d0 ; avoid trashing the condition codes
|
||
_Gestalt
|
||
bne.s @return0 ; on error, return 0
|
||
move.l a0,d0 ; put result into d0
|
||
bra.s @done
|
||
@dropStackReturn0
|
||
addq #4,sp ; drop value of selector
|
||
@return0
|
||
move.l #0,d0 ; always use 0 for result
|
||
@done
|
||
movea.l (sp)+,a0 ; avoid trashing the condition codes
|
||
rts
|
||
|
||
endproc
|
||
|
||
;ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ
|
||
;
|
||
; <49> For linked patch INITs trying to run on Systems before Cube-E, keep this patch range
|
||
; table around in case they donÕt have a 'ptbl' resource handy.
|
||
;
|
||
|
||
if INITVERSION then ; <49>
|
||
StaticRangeTable Proc Export ; <49>
|
||
dc.w $0001 ; <49> Version
|
||
dc.w $0000 ; <49> Range count - 1
|
||
dc.w $0000 ; <49> First linked patch entry in range to load
|
||
dc.w $FFFF ; <49> Last entry to load
|
||
EndProc ; <49>
|
||
endif ; <49>
|
||
end
|