****     A Privilige Violation handler for the 68010 CPU               ****
****     To use for traping those MOVE SR,ea instructions I went to use ***
****     Decigel but found it would not survive a reboot. I needed this ***
****     for those copy protected programs that run from boot. The idea ***
****     for the Violation code is from Scott Turner's Decigel program. I *
****     added the code that will allow it to survive a warm boot.     ****
****     To remove the handler press the left mouse button while       ****
****     rebooting. The screen will flash red to let you know the code ****
****     has gone. It allocates a port so that if you try to install   ****
****     it again it will tell you it is already there.                ****
****     The other way to get rid of it is to type Decigel -q          ****
****     I am placing this into the public domain for use by anyone    ****
****     John Veldthuis
****     21 Ngatai Street
****     Manaia, Taranaki
****     New Zealand

****     Revision 1  3 April 1988
****     Added code to remove handler from Cli

****     Revision 2  20 September 1988
****     Changed from using the CoolCapture Vector to using RomTAGS
****     This is the proper way to survive a reboot.
****     Took awhile to work out how to use them though
****     Will work with other RomTAGS

****     Revision 3 23 September 1988
****     Changed memory allocation tactics when I found my program
****     got wiped out by an ADDMEM C00000 CFFFFF command



_LVOOpenLibrary   EQU   -$228
_LVOCloseLibrary  EQU   -$19E
_LVOFindPort      EQU   -$186
_LVOAddPort       EQU   -$162
_LVORemovePort    EQU   -$168
_LVOSumKickData   EQU   -$264
_LVOAllocMem      EQU   -$C6
_LVOAllocAbs      EQU   -$CC
_LVOFreeMem       EQU   -$D2
_LVOOutput        EQU   -$3C
_LVOWrite         EQU   -$30

Start:
         movem.l  d0/a0,-(sp)
         move.l   4,a6
         lea      DosName(pc),a1
         moveq.l  #0,d0
         jsr      _LVOOpenLibrary(a6)         ;open dos library
         tst.l    d0
         bne.s    1$
         moveq.l  #20,d0            ;error if no Dos
         rts
1$       lea      DosBase(pc),a5
         move.l   d0,(a5)
         move.l   d0,a6
         jsr      _LVOOutput(a6)
         move.l   d0,4(a5)
         movem.l  (sp)+,d0/a0       ;restore command line
         move.b   #0,0(a0,d0.w)   ;zero end of line
         move.l   4,a6
Loop     move.b   (a0)+,d0
         tst.b    d0
         beq      NoQuit            ;if no command install handler
         cmp.b    #'-',d0
         bne.s    Loop              ;look for -q
         move.b   (a0),d0           ;should now be a 'q'
         cmp.b    #'q',d0
         bne.s    Loop
         lea      PortName(pc),a1
         jsr      _LVOFindPort(a6)
         tst.l    d0
         bne.s    PortHere
         lea      NoHandler(pc),a1
         move.l   a1,d2
         move.l   4(a5),d1
         move.l   #23,d3
         move.l   (a5),a6
         bra      Q1
PortHere move.l   d0,a4             ;a4 = pointer to port
         move.l   -4(a4),d0         ;d0 = old exception handler
         lea      $20,a0
         move.l   d0,(a0)           ;put back old exception handler
         move.l   a4,a1
         jsr      _LVORemovePort(a6) ;remove port
         move.w   #$4000,$DFF09A     ;disable interupts
         addq.b   #1,$126(a6)        ;1 to disable count
         move.l   $2A(a4),$226(a6)   ;retsore old pointer
         beq.s    1$                 ;was there a pointer
         bclr     #7,$226(a6)        ;yes, restore extension bit
1$       jsr      _LVOSumKickData(a6)
         move.l   d0,$22A(a6)        ;restore new checksum
         subq.b   #1,$126(a6)        ;one off disable count
         bge.s    2$
         move.w   #-$4000,$DFF09A   ;restore interupts
2$       lea      -(Port1-Install)(a4),a1 ;Start of memory
         move.l   #EndProg-StartProg,d0   ;length of Memory
         jsr      _LVOFreeMem(a6)         ;free the memory
         lea      Remove(pc),a0
         move.l   a0,d2
         move.l   4(a5),d1
         move.l   #17,d3
         move.l   (a5),a6
         bra.s    Q1
NoQuit   move.l   4,a6
         lea      PortName(pc),a1
         jsr      _LVOFindPort(a6)         ;find port
         tst.l    d0
         beq.s    10$               ;if no port then go install handler
         move.l   (a5),a6        ;otherwise print that handler installed
         move.l   4(a5),d1
         lea      Mess3(pc),a0
         move.l   a0,d2
         move.l   #27,d3
         bra.s    Q1

10$      move.l   #EndProg-StartProg,d0   ;length of memory we need
         move.l   #$10003,d1              ;put it in Chip Memory + Clear Mem
         jsr      _LVOAllocMem(a6)
         tst.l    d0
         beq.s    MemErr
         bsr      MoveProg         ;move prog up into memory above normal
         move.l   (a5),a6
         lea      Mess2(pc),a0
         move.l   a0,d2
         move.l   4(a5),d1
         move.l   #29,d3
Q1       jsr      _LVOWrite(a6)    ;print installed message
Quit     move.l   a6,a1
         move.l   4,a6
         jsr      _LVOCloseLibrary(a6)      ;close dos.library
         moveq.l  #0,d0
         rts
MemErr   move.l   (a5),a6
         lea      MemMess(pc),a0
         move.l   a0,d2
         move.l   4(a5),d1
         move.l   #30,d3
         bra.s    Q1                ;print Message and exit


MoveProg:
         move.l   d0,a1               ;d0 holds our memory Allocation
         move.l   d0,a3
         lea      StartProg(pc),a0
         lea      EndProg(pc),a2
1$       move.b   (a0)+,(a1)+         ;move memory up
         cmp.l    a0,a2
         bne.s    1$
         jmp      (a3)                 ;jump to install routine

StartProg:
Install  bsr.s    Sub1
         bsr      Sub2
         rts
Sub1     move.w   #$4000,$DFF09A       ;Interupts off
         addq.b   #1,$126(a6)          ;add one to disable count
         lea      Block(pc),a0
         lea      8(a0),a1
         move.l   a1,(a0)              ;pointer to our RomTAG
         move.l   $226(a6),4(a0)       ;get old KickTagPtr
         beq.s    1$                   ;Nothing there 
         bset     #7,4(a0)             ;otherwise set bit to tell exec
1$       move.l   a0,$226(a6)          ;put our KickTagPtr in
         move.w   #$4AFC,(a1)          ;magic number
         move.l   a1,2(a1)             ;pointer to base of RomTAG
         lea      $1a(a1),a2
         move.l   a2,6(a1)             ;End of RomTAG
         move.b   #1,$a(a1)            ;Flags (run program on reboot)
         move.b   #$21,$b(a1)          ;version of the program
         move.b   #0,$c(a1)            ;Type of module
         move.b   #-$a,$d(a1)          ;pri of this program
         move.l   #0,$e(a1)            ;pointer to node name
         move.l   #0,$12(a1)           ;pointer to ID string
         lea      Init(pc),a3
         move.l   a3,$16(a1)           ;pointer to Init code (called at boot)
         jsr      _LVOSumKickData(a6)  ;redo checksum
         move.l   d0,$22a(a6)          ;put it into ExecBase
         subq.b   #1,$126(a6)          ;one off disable count
         bge.s    2$                   ;are we still disabled
         move.w   #-$4000,$DFF09A      ;enable interupts
2$       rts
Sub2:
         lea      Port1(pc),a0         ;Message port address
         moveq.l  #0,d0
         move.l   d0,(a0)              ;zero successor
         move.l   d0,4(a0)             ;zero predisessor
         move.w   #$0400,8(a0)         ;type = messageport, pri = 0
         move.w   d0,14(a0)            ;zero list header
         move.l   d0,16(a0)            ;zero list tail
         lea      PortName(pc),a1      ;name of this port
         move.l   a1,10(a0)            ;put it in structure
         lea      Port1(pc),a1         ;get port address
         jsr      _LVOAddPort(a6)   ;addport to let every know we are here
         lea      OpCode+2(pc),a0      ;get end of our patch code
         lea      $20,a1               ;get address of priv violation
         move.l   (a1),(A0)            ; Patch old vector into our handler
         lea      PivVi(pc),a2
         move.l   A2,(a1)              ; Patch us into the vector
         rts                           ; Back to AmigaDOS, no error

Init     movem.l  d0-d7/a0-a6,-(sp) ;RomTag calls Here
         move.l   4,a6
         btst     #6,$BFE001        ;Test left mouse button
         bne.s    2$
11$      lea      $DFF000,a5        ;custom chip base
         move.w   #$F00,$180(a5)    ;move red into color 0
         moveq    #$64,d0           ;delay loop
4$       cmpi.b   #0,6(a5)          ;flash screen to indicate
         bne.s    4$                ;handler removed
5$       cmpi.b   #0,6(a5)
         bne.s    5$
         dbf      d0,4$             ;delay for a bit
         move.w   #$00D,$180(a5)    ;put screen back to blue
         move.w   #$4000,$9A(a5)    ;disable interupts
         addq.b   #1,$126(a6)       ;1 to disable count
         lea      Tag2(pc),a0       ;get old TagPtr
         move.l   (a0),$226(a6)     ;restore pointer
         beq.s    10$
         bclr     #7,$226(a6)       ;reset continuation bit
10$      jsr      _LVOSumKickData(a6)
         move.l   d0,$22A(a6)       ;put new checksum in
         subq.b   #1,$126(a6)       ;1 from disable count
         bge.s    6$
         move.w   #-$4000,$9A(a5)   ;enable interupts
         bra.s    6$                ;return to kickstart routine
2$       lea      Install(pc),a1    ;start of our program
         move.l   #EndProg-StartProg,d0   ;number of byte to allocate
         jsr      _LVOAllocAbs(a6)        ;alloc memory
         tst.l    d0
         beq.s    11$               ;dont install it if no memory
         bsr      Sub2              ;addport and reset pointer to routine
6$       movem.l  (sp)+,d0-d7/a0-a6 ;restore regs for kickstart
         rts

PivVi    movem.l  D0/A0,-(SP)       ; Save registers
         move.l   8+2(SP),A0        ; Pointer to opcode
         move.w   (A0),D0           ; Pickup opcode
         andi.w   #~%111111,D0      ; Mask out EA field
         cmpi.w   #$40C0,D0         ; Is it a MOVE SR,ea?
         bne.s    NotOne
         bset     #1,(A0)           ; Convert it to MOVE CCR,ea
         movem.l  (SP)+,D0/A0       ; Restore regs
         rte                        ; Rerun new opcode

NotOne   movem.l  (SP)+,D0/A0       ; Restore regs
OpCode   jmp      $FC0000   ; To previous handler, patched by our install

Port1    dc.l     0              ;This is a message port structure
         dc.l     0
         dc.b     4              ;port type
         dc.b     0
         dc.l     0              ;port name
         dc.b     0
         dc.b     0
         dc.l     0
         ds.b     14
         dc.l     0
Block    dc.l     0              ;This is storage for the RomTag
Tag2     dc.l     0
         dc.l     0
         dc.l     0
         dc.l     0
         dc.l     0
         dc.l     0
         dc.l     0
         dc.l     0
         dc.l     0
         dc.l     0
         dc.l     0
         dc.l     0

DosBase  dc.l  0
StdOut   dc.l  0
DosName  dc.b  'dos.library',0
Mess2    dc.b  'Privilige Handler Installed',10,0
Mess3    dc.b  'Handler already Installed',10,0
NoHandler dc.b 'Handler not Installed',10,0
MemMess  dc.b  'Not Enough memory for Handler',10,0
Remove   dc.b  'Handler Removed',10,0
PortName dc.b  'PrivHandler',0
NAME     dc.b  'John Veldthuis',0
         dc.b  '21 Nagtai Steet',0
         dc.b  'Manaia, Taranaki',0
         dc.b  'New Zealand',0
EndProg:

      end

