home *** CD-ROM | disk | FTP | other *** search
- ; SafeGIRPort
- ; Patches ObtainGIRPort() to fix MagicMenu
- ; and CycleToMenu problem
- ;
- ; Based heavily on NewObtainGIRPort, but with
- ; fixes. Specifically, the caches weren't
- ; being cleared on removal. Plus, some speed
- ; improvements in the patch code. Hopefully
- ; it narrows the gap for someone locking the
- ; layer between the patch's unlock and original
- ; call.
-
- INCLUDE 'intuition/cghooks.i'
-
- ObtainGIRPort EQU -$22E
- DisplayBeep EQU -$60
-
- OpenLibrary EQU -$228
- CloseLibrary EQU -$19E
- SetFunction EQU -$1A4
- Forbid EQU -$84
- Permit EQU -$8A
- Wait EQU -$13E
- CacheClearU EQU -$27c
-
- Delay EQU -$C6
- PutStr EQU -$3B4
-
- AttemptLockLayerRom EQU -$28E
- UnlockLayerRom EQU -$1B6
-
- SIGBREAKF_CTRL_C EQU 1<<12
-
- section text,code
-
- _PatchOGR:
- moveq #20,d7
-
- ; Open libraries
- lea gfxname(pc),a1
- moveq #36,d0
- move.l 4.w,a6
- jsr OpenLibrary(a6)
- lea GfxBase(pc),a0
- move.l d0,(a0)
- beq fail1
-
- lea dosname(pc),a1
- moveq #36,d0
- jsr OpenLibrary(a6)
- move.l d0,d2 ; d2 gets DosBase
- beq fail2
-
- lea intuiname(pc),a1
- moveq #36,d0
- jsr OpenLibrary(a6)
- move.l d0,d3 ; d3 gets IntuitionBase
- beq fail3
-
- jsr Forbid(a6)
-
- ; Install patch
- move.l d0,a1
- lea newObtainGIRPort(pc),a0
- move.l a0,d0
- move.l #ObtainGIRPort,a0
- jsr SetFunction(a6)
- lea oldObtainGIRPort(pc),a0
- move.l d0,(a0)
-
- ; Clear CPU caches to flush data/instruction cache incoherence
- jsr CacheClearU(a6)
-
- loop:
- jsr Permit(a6)
-
- ; Wait for ctrl-C
- move.l #SIGBREAKF_CTRL_C,d0
- jsr Wait(a6)
-
- jsr Forbid(a6)
-
- ; Attempt to remove the patch
- move.l d3,a1 ; a1 gets IntuitionBase
- move.l oldObtainGIRPort(pc),d0
- move.l #ObtainGIRPort,a0
- jsr SetFunction(a6)
- lea newObtainGIRPort(pc),a0
- cmp.l a0,d0
- beq.s ok
-
- ; Oops, someone has patched over, put it back
- move.l d3,a1 ; a1 gets IntuitionBase
- move.l #ObtainGIRPort,a0
- jsr SetFunction(a6)
-
- ; We can't quit, so notify user with a beep
- exg d3,a6 ; a6 gets IntutionBase
- move.l #0,a0
- jsr DisplayBeep(a6) ; it's safe to call display beep inside Forbid()
- exg d3,a6 ; a6 gets ExecBase
-
- bra.s loop
-
- ok:
- ; Clear CPU caches to flush data/instruction cache incoherence
- jsr CacheClearU(a6)
- jsr Permit(a6)
-
- exg d2,a6 ; a6 gets DosBase
-
- ; Notify user of subsequent quit
- lea exitmsg(pc),a0
- move.l a0,d1
- jsr PutStr(a6)
-
- ; Wait a second to let other tasks exit from the patch code
- ; We can't be absolutely sure but this should be enough of a safeguard
- moveq #50,d1
- jsr Delay(a6)
-
- exg d2,a6 ; a6 gets ExecBase
-
- moveq #0,d7
-
- ; Close libraries and exit
- move.l d3,a1 ; a1 gets IntutionBase
- jsr CloseLibrary(a6)
-
- fail3:
- move.l d2,a1 ; a1 gets DosBase
- jsr CloseLibrary(a6)
-
- fail2:
- move.l GfxBase(pc),a1
- jsr CloseLibrary(a6)
-
- fail1:
- move.l d7,d0
- rts
-
- newObtainGIRPort:
- ; First we should check for valid input
- move.l a0,d0 ; effective compare
-
- ; We'll call ObtainGIPort anyway, even if the GadgetInfo is NULL..
- beq.s null2
-
- ; save some regs
- movem.l a0/a5/a6,-(sp)
-
- ; assume layer is valid (usually is)
- ; try to lock it
- move.l GfxBase(pc),a6
- move.l ggi_Layer(a0),a5 ; only one access of layer ptr
- move.l a5,d0 ; effective compare, faster than cmpi
- beq.s null1 ; We'll do old stuff if layer is NULL
- jsr AttemptLockLayerRom(a6)
- ext.l d0 ; effective compare, sets return value
- beq.s null3
-
- ; Got a lock, free it (layer already in a5, gfxbase in a6)
- jsr UnlockLayerRom(a6)
-
- null1:
- ; layer is null
- movem.l (sp)+,a0/a5/a6
-
- null2:
- ; call original function
- move.l oldObtainGIRPort(pc),a1
- jmp (a1)
-
- null3:
- ; Attempt to lock the layer failed, return NULL (set above)
- movem.l (sp)+,a0/a5/a6
- rts
-
- oldObtainGIRPort:
- dc.l 0
-
- GfxBase:
- dc.l 0
-
- dosname:
- dc.b "dos.library",0
-
- intuiname:
- dc.b "intuition.library",0
-
- gfxname:
- dc.b "graphics.library",0
-
- exitmsg:
- dc.b "SafeGIRPort gone",10,0
- dc.b "$VER: SafeGIRPort 1.0 (30.1.95)",0
-
- END
-