mac-rom/LinkedPatches/PatchProtector.a

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