;TI-89/92+/V200 Hardware 2.00 AMS 2.0x TSR support v.1.12 ;This is thought ONLY for Hardware 2.00 AMS 2.0x without HW2Patch. ;It is NOT needed on any other configuration (and will refuse to install). ;Copyright (C) Kevin Kofler, 2001-2004 ;please read the readme file before using this file ;Please DO NOT distribute modified versions without my ;permission! include "OS.h" ;You need the version included with TIGCC. xdef _nostub ;no kernel required xdef _ti89 ;This is for the TI-89. xdef _ti92plus ;This is also for the TI-92+. _v200: xdef _v200 ;This is also for the V200. xdef _main ;This is a program, not a library. _main: movem.l a2-a6/d3-d7,-(a7) ;save all registers ;detect the hardware version ;Thanks to Julien Muchembled for the C version listed in the TI-GCC FAQ. ;Converted to assembly by Kevin Kofler move.l $c8,d0 and.l #$E00000,d0 ;get the ROM base move.l d0,a0 move.l 260(a0),a1 ;get the pointer to the hardware parameter block add.l #$10000,a0 cmp.l a0,a1 ;check if the hardware parameter block is near enough bcc hw1 ;if it is too far, it is HW1 cmp.w #22,(a1) ;check if the parameter block contains the hardware version bls hw1 ;if it is too small, it is HW1 cmp.l #1,22(a1) ;check the hardware version beq hw1 ;if 1, it is HW1 cmp.l #2,22(a1) ;check the hardware version bne hw3 ;if not 2, it is an unsupported hardware version ;end of hardware version detection routine move.l $c8,a0 cmp.l #1000,-4(a0) ;check if more than 1000 entries bcs ams1 ;if no, it is AMS 1.xx ROM_CALL2 EX_stoBCD tst.w 92(a4) ;check for HW2Patch (ROM resident) beq patched ;if it is installed, refuse installation cmp.l #$100,$ac ;check for HW2Patch (RAM resident) beq patched ;if it is installed, refuse installation clr.b d4 ;set to "first install" mode bsr enter_the_ghost_space ;unprotect and enter the ghost space cmp.l #$200000,$ac ;check if trap #$b points to the ROM bcs already ;if no, it is already installed cmp.l #$200000,$90 ;check if trap #4 points to the ROM bcs trap4_already ;if no, it is already hooked continue: move.l $ac,oldtrapb ;save the old trap #$B and call it from the new one move.l $90,oldtrap4 ;save the old trap #$4 and call it from the new one move.l #(endtrap4-newtrapb),-(a7) ROM_CALL HeapAllocHigh ;allocate a handle for the new trap #$B addq.l #2,a7 tst.w d0 ;check if NULL handle beq nomem ;if yes, display "no mem" error message move.w d0,(a7) ROM_CALL HeapDeref ;get ("dereference") the address move.l a0,a3 ;save the address to a3 for further use subq.l #2,a7 move.l #(endtrap4-newtrapb),(a7) pea.l newtrapb(PC) move.l a0,-(a7) ROM_CALL memcpy ;copy the trap #$B routine to the handle lea.l 12(a7),a7 ;shorter as add(a).l #12,a7 move.l $c8,a0 cmp.l #$607,-4(a0) ;check if more than $607 entries bcs ams200to205 ;if no, it is not AMS 2.07 lea.l ams207patch1-newtrapb(a3),a0 move.w #$4e69,(a0) ;move.l usp,a1 move.l #$b1e90008,2(a0) ;cmp.l 8(a1),a0 move.w #$ca9,ams207patch2-ams207patch1(a0) ;cmpi.l #imm,d(a1) move.w #8,ams207patch2-ams207patch1+6(a0) ;d=8 move.w #$6a9,ams207patch3-ams207patch1(a0) ;addi.l #imm,d(a1) move.w #8,ams207patch3-ams207patch1+6(a0) ;d=8 move.l #$22690008,ams207patch4-ams207patch1(a0) ;move.l 8(a1),a1 move.l #$3029fffe,ams207patch4-ams207patch1+4(a0) ;move.w -2(a1),d0 move.w #$d089,ams207patch4-ams207patch1+8(a0) ;add.l a1,d0 move.w #$2f09,ams207patch5-ams207patch1(a0) ;move.l a1,-(a7) ams200to205: add.l #$40008,a3 ;add: - $40000 for HW2 AMS 2.0x without ; HW2Patch ; - $8 to skip the uninstall ; information (need the start of ; the executable code here) move.l a3,$400ac ;install the trap #$B adda.w #newtrap4-newtrapb,a3 ;new trap #$4 move.l a3,$40090 ;install the trap #$4 tst.b d4 ;check if update mode bne update ;if yes, show "updated" message pea.l installedST(PC) ;show "installed" message showmsg: ROM_CALL ST_helpMsg addq.l #4,a7 movem.l (a7)+,a2-a6/d3-d7 ;restore all registers rts ;return update: pea.l updatedST(PC) ;show "updated" message bra showmsg hw1: pea.l hw1ST(PC) ;show "HW1" error message bra showmsg ams1: pea.l ams1ST(PC) ;show "AMS 1" error message bra showmsg patched: pea.l patchedST(PC) ;show "patched" error message bra showmsg hw3: pea.l hw3ST(PC) ;show "unsupported HW version" error message bra showmsg already: move.l $ac,a0 ;check for previous h220xTSR installation cmp.l #$40000,a0 ;if <$40000, it is not h220xTSR (because that would not work bcs already5 ;reliably on HW2) sub.l #$40008,a0 ;remove: * $40000 for HW2 AMS 2.0x without HW2Patch ; * $8 to get the beginning of the handle (if ; compatible) cmp.l #'2TSR',(a0) ;check signature bne already2 ;if it is not the old one, check for version 1.03-1.05a cmp.l #'2Tsr',$6e(a0) ;check for version 1.03/4 (trap 4 signature) beq already3 ;if it is 2Tsr, it is h220xTSR 1.03/1.04 with a broken signature cmp.l #$200000,$90 ;check if trap #4 points to the ROM bcs trap4_already ;if no, it is already hooked already4: st.b d4 ;set to update mode move.l 4(a0),$400ac ;restore old trap #$b move.l a0,-(a7) ROM_CALL HeapPtrToHandle ;get the handle number addq.l #2,a7 move.w d0,(a7) ROM_CALL HeapFree ;free (unallocate) the handle addq.l #2,a7 bra continue ;continue the installation already3: move.l #'2Tsr',(a0) ;fix signature st.b d4 ;set to update mode already2: cmp.l #'2Tsr',(a0) ;check signature bne already5 ;if it is not the new one, it is not h220xTSR not_trap4_yet: ;look for the second signature (trap 4 hook) addq.l #2,a0 ;only search word for word, as code is word-aligned cmp.l #'2Tsr',(a0) ;check signature bne not_trap4_yet ;otherwise continue searching cmp.w #$5111,-2(a0) ;check for versions older than 1.11 bcc already5 ;if no, do not update move.l $90,a0 ;check for other trap 4 hook cmp.l #$40000,a0 ;if <$40000, it is not h220xTSR (because that would not work bcs trap4_already ;reliably on HW2) sub.l #$40008,a0 ;remove: * $40000 for HW2 AMS 2.0x without HW2Patch ; * $8 to get the beginning of the handle (if ; compatible) cmp.l #'2Tsr',(a0) ;check signature bne trap4_already ;if it is not the new one, it is not h220xTSR cmp.w #$5111,-2(a0) ;check for versions older than 1.11 bcc already5 ;if no, do not update move.l 4(a0),$40090 ;restore old trap #4 move.l $ac,a0 ;get trap #$B address again sub.l #$40008,a0 ;remove: * $40000 for HW2 AMS 2.0x without HW2Patch ; * $8 to get the beginning of the handle (if ; compatible) bra already4 already5: pea.l alreadyST(PC) ;show "already installed" error message bra showmsg trap4_already: move.l #$10000,-(a7) pea.l trap4DL(PC) pea.l trap4ST(PC) ;"trap 4 already hooked" error message move.l $c8,a4 move.l DlgMessage*4(a4),a0 ;display error dialog jsr (a0) move.l ST_helpMsg*4(a4),a0 ;display error message jsr (a0) lea.l 12(a7),a7 ;restore the stack movem.l (a7)+,a2-a6/d3-d7 ;restore all registers rts ;return nomem: addq.l #2,a7 ;adjust the stack pea.l nomemST(PC) ;show "no mem" message bra showmsg ;Thanks to Zeljko Juric for the following function: ;(I have slightly adapted it to fit my needs, and fixed a few minor glitches. The ;fixes have been submitted to TIGCC, of which I am now a team member, as well.) enter_the_ghost_space: bsr.w \ghost_space_0 ;push the current PC on the stack \ghost_space_0: move.l (a7)+,d0 ;pop it to d0 cmpi.l #$40000,d0 ;check if it is in the ghost space bcc.s \ghost_space_2 ;if it is, skip movem.l d3-d7/a2-a6,-(a7) ;save non-call-clobbered registers lea -20(a7),a7 ;allocate some space on the stack move.l #$3e000,a3 ;address of the zone to unprotect ($3e000) for the trap #$b move.l $c8,d0 ;get the address of the jump table andi.l #$E00000,d0 ;use it to compute ROM_base ;($200000 on the TI89, $400000 on the TI92+) addi.l #$20000,d0 ;now d0 points to somewhere in the AMS move.l d0,12(a7) ;fool the routine into believing that it is called from AMS move.l d0,16(a7) trap #$c ;enter supervisor mode move.w #$2700,sr ;disable all interrupts (while staying in supervisor mode) move.l #$f,d3 ;function number ($f) for the trap #$b pea.l \ghost_space_1(pc) ;push the return PC for the indirect trap #$b call bset.b #2,1(a7) ;make it point to ghost space (same as or.l #$40000,(a7)) clr.w -(a7) ;push the return SR (0 = ints enabled, user mode) for the trap #$b move.l $ac,a0 ;get the vector for the trap #$B jmp (a0) ;enter into the trap #$B indirectly ; Now, trap #$B will unprotect the 8K/24K area starting from $3E000. ; This includes the last page of the RAM too, so executing from the ; the ghost space is enabled too. The stack is set up on such way, ; that when the trap #$B is finished, the "rte" will transfer ; execution to the address \ghost_space_1+$40000, so the execution ; continues at the label "\ghost_space_1", now in the "ghost space": \ghost_space_1: lea 20(a7),a7 ;free the allocated stack space movem.l (a7)+,d3-d7/a2-a6 ;restore non-call-clobbered registers \ghost_space_2: move.l (a7)+,d0 ;pick up the return address bset.l #18,d0 ;make it point to ghost space (same as or.l #$40000,d0) move.l d0,a0 ;move it to a0 jmp (a0) ;jump to it (return, but now in the ghost space) newtrapb: dc.b '2Tsr' ;signature oldtrapb: dc.l 0 ;This is a placeholder for the original trap #$B address. cmp.l #$f,d3 ;check if function $f bne callold ;if no, just call the original trap #$B cmp.l #$200000,2(a7) ;check if enter_ghost_space bcs alreadyghost ;if yes, do nothing (program execution will be at PC+$80000) ;which is still in the ghost space (ghost of ghost) ams207patch1: nop nop cmp.l a2,a0 ;check if Exec command ;For AMS 2.07: ;move.l usp,a1 ;cmp.l 8(a1),a0 ;check if Exec command bne exec ;if yes, special treatement ;The address of the program to execute is stored in a2 by AMS 2.0x. ams207patch2: cmp.l #$40000,a2 ;check if already in the ghost space nop ;For AMS 2.07: ;cmp.l #$40000,8(a1) ;check if already in the ghost space bcc alreadyghost ;if yes, do nothing ams207patch3: add.l #$40000,a2 ;add $40000 to a2 if it is not already in the ghost space nop ;For AMS 2.07: ;add.l #$40000,8(a1) ;add $40000 to 8(a1) if it is not already in the ghost space moveq.l #0,d0 ;get the end of the program ams207patch4: nop nop move.w -2(a2),d0 add.l a2,d0 ;For AMS 2.07: ;move.l 8(a1),a1 ;move.w -2(a1),d0 ;add.l a1,d0 subq.l #1,d0 move.l d0,-(a7) ams207patch5: move.l a2,-(a7) ;For AMS 2.07: ;move.l a1,-(a7) common: ;common for ASM and Exec move.l $C8,a0 move.l EX_patch*4(a0),a0 ;relocate the program again: jsr (a0) ;call EX_patch without destroying a4 addq.l #8,a7 alreadyghost: rte exec: cmp.l a5,a0 ;check if really Exec command bne alreadyghost ;if no, do nothing!!! ;The address of the STR_TAG of the exec string is stored in a2 by AMS 2.0x. ;The program address is stored in a5 by AMS 2.0x. add.l #$40000,a5 ;add $40000 to a5 if it is not already in the ghost space moveq.l #0,d0 ;get the end of the program lea.l -1(a2),a1 ;not to change a2 in order to respect the calling convention execnext: addq.l #1,d0 tst.b -(a1) bne execnext lsr.l #1,d0 add.l a5,d0 move.l d0,-(a7) move.l a5,-(a7) bra common callold: move.l oldtrapb(PC),-(a7) ;get the original trap #$B address (on the stack) rts ;jump to it (from the stack, in order not to destroy any registers) ;Version identification: This is the best place to hide it so that older versions ; of UnIn2TSR won't get confused. ;This will mean less detection work for future updaters. dc.w $5112 ;5 = signature (to make it bigger than $4e75=rts which was there in ; previous versions) ;112 = version 1.12 ;Changes in the memory resident part will ALWAYS induce a version number increase. ;Only changes which do not touch the memory resident part get lettered numbers ;(such as "1.05a"). This was always my policy. newtrap4: dc.b '2Tsr' ;signature oldtrap4: dc.l 0 ;This is a placeholder for the original trap #$4 address. movem.l d0-d7/a0-a6,-(a7) ;save destroyed registers move.l $ac,-(a7) ;save the new trap #$B lea.l reenter_ghost_space-finishtrap4(a7),a7 ;save unprotected zone to the stack pea.l finishtrap4-reenter_ghost_space pea.l $5fc0 pea.l 8(a7) move.l $c8,a0 move.l memcpy*4(a0),a0 jsr (a0) ;call memcpy without destroying a4 lea.l 12(a7),a7 ;restore a7 pea.l finishtrap4(PC) ;push end of routine to the stack move.w #$2700,-(a7) ;push SR for end of routine to the stack move.l oldtrapb(PC),$400ac ;reset the trap #$B to the original value pea.l finishtrap4-reenter_ghost_space pea.l reenter_ghost_space(PC) ;copy middle of routine to pea.l $5fc0 ;unprotected zone move.l $c8,a0 move.l memcpy*4(a0),a0 jsr (a0) ;call memcpy without destroying a4 lea.l 12(a7),a7 pea.l $5fc0 ;push address of middle of routine to the stack move.w #$2700,-(a7) ;push SR for middle of routine to the stack move.l oldtrap4(PC),-(a7) ;get the original trap #$4 address (on the stack) rts ;jump to it (from the stack, in order not to destroy any registers) reenter_ghost_space: ;This will be in supervisor mode! It will be at $5fc0! ;This is again an adaptation of Zeljko Juric's routine. move.l usp,a0 lea -20(a0),a0 ;make some space on stack move.l $C8,d0 ;TIOS jump table in d0 andi.l #$E00000,d0 ;=$200000 for TI89, =$400000 for TI92+ addi.l #$20000,d0 ;now d0 points somewhere in TIOS move.l d0,12(a0) ;fool the routine to believe that it is move.l d0,16(a0) ;called somewhere from TIOS move.l a0,usp move.l #$F,d3 ;prepare for calling trap #$B indirectly move.l #$3e000,a3 ;pass $3e000 to the trap #$B move.l $AC,a0 ;the vector for trap #$B jmp (a0) ;enter into trap #$B indirectly finishtrap4: ;This will be in supervisor mode! move.l usp,a0 lea.l 20(a0),a0 ;free the stack space of reenter_ghost_space move.l a0,usp pea.l finishtrap4-reenter_ghost_space ;restore the unprotected zone pea.l 4(a7) pea.l $5fc0 move.l $c8,a0 move.l memcpy*4(a0),a0 jsr (a0) ;call memcpy without destroying a4 lea.l finishtrap4-reenter_ghost_space+12(a7),a7 ;clean the stack up move.l (a7)+,$400ac ;restore the new trap #$B movem.l (a7)+,d0-d7/a0-a6 ;restore destroyed registers rte ;return endtrap4: ;error and success messages: hw3ST: dc.b 'ERROR: Unsupported hardware version',0 hw1ST: dc.b 'ERROR: h220xTSR not needed on HW1',0 ams1ST: dc.b 'ERROR: h220xTSR not needed on AMS1',0 patchedST: dc.b 'ERROR: h220xTSR useless on patched HW2',0 alreadyST: dc.b 'ERROR: h220xTSR already installed',0 trap4DL: dc.b 'Please temporarily uninstall any memory resident keyboard ' dc.b 'auto-repeat accelerators or password programs before ' dc.b 'installing or updating h220xTSR.',0 trap4ST: dc.b 'ERROR: Trap 4 already hooked',0 nomemST: dc.b 'ERROR: Not enough memory',0 installedST: dc.b 'h220xTSR 1.12 by Kevin Kofler installed',0 updatedST: dc.b 'h220xTSR by Kevin Kofler updated',22,'v1.12',0 END