mirror of
https://github.com/elliotnunn/supermario.git
synced 2024-11-29 20:49:19 +00:00
192 lines
6.9 KiB
Plaintext
192 lines
6.9 KiB
Plaintext
|
;
|
|||
|
; File: PatchProtector.a
|
|||
|
;
|
|||
|
; Contains: a patch to SetTrapAddress and GetTrapAddress that “protects” come-from patches
|
|||
|
;
|
|||
|
; Written by: Darin Adler
|
|||
|
;
|
|||
|
; Copyright: © 1990-1991 by Apple Computer, Inc., all rights reserved.
|
|||
|
;
|
|||
|
; Change History (most recent first):
|
|||
|
;
|
|||
|
; <11> 8/28/91 JSM Cleanup header.
|
|||
|
; <10> 4/5/91 gbm dba: Exit via jCacheFlush when setting the trap address. This
|
|||
|
; makes it possible to use copy-back mode on '040's
|
|||
|
; <9> 4/3/91 dba kill the fun
|
|||
|
; <8> 3/25/91 dba VL: get rid of that stupid StripAddress
|
|||
|
; <7> 3/4/91 dba gbm: do a StripAddress for all the 24-bit slobs out there
|
|||
|
; <6> 12/18/90 gbm (dba) Use the noPatchProtector conditional to prevent two patch
|
|||
|
; protectors from getting upset at each other.
|
|||
|
; <5> 12/5/90 dba <gbm> disallow come-from patch headers except from people who
|
|||
|
; use the $CXXX form of SetTrapAddress; also check the address
|
|||
|
; passed to SetTrapAddress for validity, by reading the first long
|
|||
|
; word and looking for the come-from header
|
|||
|
; <4> 8/2/90 dba get rid of the MemTop and odd checks
|
|||
|
; <3> 5/30/90 dba add validation for the old address in GetTrapAddress
|
|||
|
; <2> 5/1/90 dba do nothing to this file, just touch it so that people will get
|
|||
|
; the LinkedPatchLib rebuilt
|
|||
|
; <1> 3/21/90 dba fixed some more bugs and checked in for general use
|
|||
|
; 2/1/90 dba fixed the bug that Ed found
|
|||
|
; 1/30/90 dba revamped, added [GS]etTrapWordAddress
|
|||
|
; 1/25/90 dba added a header
|
|||
|
;
|
|||
|
; To Do:
|
|||
|
; take into account the number of toolbox traps on each machine in [GS]etTrapWordAddress
|
|||
|
;
|
|||
|
; This is a patch to Get/SetTrapAddress that respects come-from patches with a special format.
|
|||
|
;
|
|||
|
; bra.s *+6
|
|||
|
; jmp OldTrapAddress
|
|||
|
;
|
|||
|
; Get and SetTrapAddress will notice patches that begin with this sequence and treat them as
|
|||
|
; “come-from” patches. Instead of changing the address of the trap in the trap table, instead
|
|||
|
; they will change the “old” address in the last come-from patch in the chain.
|
|||
|
;
|
|||
|
; This patch needs to be installed before any come-from patches are installed. This can be done
|
|||
|
; by linking it first in the first 'lpch' to be loaded.
|
|||
|
;
|
|||
|
; This patch also implements a new variant of [GS]etTrapAddress called [GS]etTrapWordAddress.
|
|||
|
; It takes a whole trap word, and does the right thing, removing the need for N[GS]etTrapAddress.
|
|||
|
;
|
|||
|
|
|||
|
print push,off
|
|||
|
load 'StandardEqu.d'
|
|||
|
include 'LinkedPatchMacros.a'
|
|||
|
print pop
|
|||
|
|
|||
|
; opcodes
|
|||
|
|
|||
|
kBranchOverJMPLOpcode equ $6006
|
|||
|
kJMPLOpcode equ $4EF9
|
|||
|
|
|||
|
kComeFromHeader equ (kBranchOverJMPLOpcode << 16) + kJMPLOpcode
|
|||
|
|
|||
|
; bits in trap numbers and Set/GetTrapAddress opcodes
|
|||
|
|
|||
|
TrapNumber record 0
|
|||
|
toolboxBit equ 11
|
|||
|
endr
|
|||
|
|
|||
|
TrapAddressOpcode record 0
|
|||
|
newBit equ 9
|
|||
|
toolboxBit equ 10
|
|||
|
endr
|
|||
|
|
|||
|
; The following patch has to use $A046 as the trap number instead of _GetTrapAddress.
|
|||
|
; This is because it is installed before these patches modify the behavior of [GS]etTrapAddress
|
|||
|
; to work properly for full trap words. The trap number is thus used as an “old-style” trap number.
|
|||
|
; $A046 is GetTrapAddress, but $A146 (the value of _GetTrapAddress) is interpreted as $A946.
|
|||
|
|
|||
|
ProtectGetTrap patchproc $A046,(Plus,SE,II,Portable,IIci,noPatchProtector)
|
|||
|
import TrapAddressBits
|
|||
|
export OldGetTrapAddress
|
|||
|
|
|||
|
jsr TrapAddressBits ; set bits in the trap word
|
|||
|
move sr,-(sp) ; would do a MOVE CCR, but it is not available on 68000
|
|||
|
bsr.s OldGetTrapAddress ; call the old GetTrapAddress
|
|||
|
move (sp)+,ccr ; get condition codes back
|
|||
|
bcs.s @done ; come-from patches bypass our trickery
|
|||
|
@next
|
|||
|
cmp.l #kComeFromHeader,(a0) ; does this have the come-from header?
|
|||
|
bne.s @done ; no we are done
|
|||
|
move.l 4(a0),a0 ; go on to the next
|
|||
|
bra.s @next
|
|||
|
@done
|
|||
|
moveq #0,d0 ; must zero the result code again
|
|||
|
rts
|
|||
|
|
|||
|
OldGetTrapAddress
|
|||
|
jmpOld
|
|||
|
|
|||
|
endproc
|
|||
|
|
|||
|
; Since SetTrapAddress looks at the first long word of the previous value of the trap’s address,
|
|||
|
; it can be dangerous to call SetTrapAddress on some random value. Later, a correct SetTrapAddress
|
|||
|
; might encounter a bus error or address error or some other problem. To avoid this, SetTrapAddress
|
|||
|
; looks at the first long word of the new trap address *before* setting the address in the trap table
|
|||
|
; or come-from chain. This ensures that the bus error will happen right away.
|
|||
|
|
|||
|
ProtectSetTrap patchproc _SetTrapAddress,(Plus,SE,II,Portable,IIci,noPatchProtector)
|
|||
|
import TrapAddressBits
|
|||
|
import OldGetTrapAddress
|
|||
|
|
|||
|
move.l (a0),d2 ; get header of trap, and check for bus errors <5>
|
|||
|
|
|||
|
jsr TrapAddressBits ; set bits in the trap word
|
|||
|
bcs.s OldSetTrapAddress ; come-from patches bypass our trickery
|
|||
|
|
|||
|
cmp.l #kComeFromHeader,d2 ; headers can only be used on come-from patches <5>
|
|||
|
beq.s @illegalHeader ; saw a header, so I must system error <5>
|
|||
|
|
|||
|
movem.l d0-d1/a0,-(sp) ; save trap address, number, and bits
|
|||
|
jsr OldGetTrapAddress ; call the old GetTrapAddress
|
|||
|
move.l #0,a1 ; no come-froms found yet
|
|||
|
@next
|
|||
|
cmp.l #kComeFromHeader,(a0)+ ; does this have the come-from header?
|
|||
|
bne.s @done ; no we are done
|
|||
|
move.l a0,a1 ; remember this address
|
|||
|
move.l (a0),a0 ; go on to the next
|
|||
|
bra.s @next
|
|||
|
@done
|
|||
|
movem.l (sp)+,d0-d1/a0 ; restore trap address, number, and bits
|
|||
|
|
|||
|
cmp.l #0,a1 ; any come-froms found?
|
|||
|
beq.s OldSetTrapAddress ; no, go do the real SetTrapAddress
|
|||
|
move.l a0,(a1) ; set the trap address
|
|||
|
move.l jCacheFlush,-(sp) ; get the cache flush vector <9>
|
|||
|
rts ; call it, and then return to the trap dispatcher <9>
|
|||
|
|
|||
|
@illegalHeader
|
|||
|
move.w #dsBadPatchHeader,d0 ; get error code <5>
|
|||
|
_SysError ; report it to the unsuspecting user <5>
|
|||
|
|
|||
|
OldSetTrapAddress
|
|||
|
jsrOld ; call so we can flush the cache when we return <9>
|
|||
|
move.l jCacheFlush,-(sp) ; get the cache flush vector <9>
|
|||
|
rts ; call it, and then return to the trap dispatcher <9>
|
|||
|
|
|||
|
endproc
|
|||
|
|
|||
|
TrapAddressBits proc
|
|||
|
|
|||
|
; TrapAddressBits
|
|||
|
;
|
|||
|
; In:
|
|||
|
; d0.w trap number
|
|||
|
; d1.w [GS]etTrapAddress trap word
|
|||
|
;
|
|||
|
; Out:
|
|||
|
; d1.w (modified) [GS]etTrapAddress trap word
|
|||
|
; ccr CC if it is not a come-from, CS if it is a come-from
|
|||
|
|
|||
|
btst #TrapAddressOpcode.newBit,d1 ; is this N[GS]etTrapAddress?
|
|||
|
bnz.s @notFullWord ; yes, don’t handle it
|
|||
|
btst #TrapAddressOpcode.toolboxBit,d1 ; is this normal [GS]etTrapAddress?
|
|||
|
bz.s @notFullWord ; yes, don’t handle it
|
|||
|
|
|||
|
@fullWord
|
|||
|
; adjust the trap bits
|
|||
|
|
|||
|
bset #TrapAddressOpcode.newBit,d1 ; is this NGetTrapAddress?
|
|||
|
btst #TrapNumber.toolboxBit,d0 ; is the trap a Toolbox trap?
|
|||
|
bnz.s @toolbox ; yes, leave the bit set
|
|||
|
bclr #TrapAddressOpcode.toolboxBit,d1 ; clear bit for OS
|
|||
|
@toolbox
|
|||
|
|
|||
|
cmp.w #$C000,d0 ; is this a come-from trap word?
|
|||
|
blo.s @notComeFrom ; no, it is not
|
|||
|
cmp.w #$D000,d0 ; is it a come-from trap word?
|
|||
|
bhs.s @notComeFrom ; no, it is not
|
|||
|
@comeFrom
|
|||
|
; oooh... carry is set for us, we can return
|
|||
|
rts
|
|||
|
|
|||
|
@notFullWord
|
|||
|
@notComeFrom
|
|||
|
and #$FE,ccr ; clear the carry bit
|
|||
|
rts
|
|||
|
|
|||
|
endproc
|
|||
|
|
|||
|
end
|