#MIT License #Copyright (c) 2010-2017 Nuke, brkirch, Y.S, Kenobi, gamemasterplc #Permission is hereby granted, free of charge, to any person obtaining a copy #of this software and associated documentation files (the "Software"), to deal #in the Software without restriction, including without limitation the rights #to use, copy, modify, merge, publish, distribute, sublicense, and/or sell #copies of the Software, and to permit persons to whom the Software is #furnished to do so, subject to the following conditions: #The above copyright notice and this permission notice shall be included in all #copies or substantial portions of the Software. #THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR #IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, #FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE #AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER #LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, #OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE #SOFTWARE. # Based off of codehandleronly.s from Gecko OS source code. # Example command to build: # powerpc-elf-gcc -mpowerpc -mpaired -mbig codehandler.s -nostartfiles -nodefaultlibs -nostdlib -T codehandler.ld -o codehandler.bin .text #Register Defines .set r0,0; .set r1,1; .set r2,2; .set r3,3; .set r4,4 .set r5,5; .set r6,6; .set r7,7; .set r8,8; .set r9,9 .set r10,10; .set r11,11; .set r12,12; .set r13,13; .set r14,14 .set r15,15; .set r16,16; .set r17,17; .set r18,18; .set r19,19 .set r20,20; .set r21,21; .set r22,22; .set r23,23; .set r24,24 .set r25,25; .set r26,26; .set r27,27; .set r28,28; .set r29,29 .set r30,30; .set r31,31; .set f0,0; .set f2,2; .set f3,3 .globl _start gameid: .long 0,0 cheatdata: .long frozenvalue .space 39*4 _start: stwu r1,-172(r1) # stores sp stw r0,8(r1) # stores r0 mflr r0 stw r0,176(r1) # stores lr mfcr r0 stw r0,12(r1) # stores cr mfctr r0 stw r0,16(r1) # stores ctr mfxer r0 stw r0,20(r1) # stores xer stmw r3,24(r1) # saves r3-r31 mfmsr r25 stw r25,168(r1) # save msr ori r26,r25,0x2000 #enable floating point ? andi. r26,r26,0xF9FF mtmsr r26 stfd f2,152(r1) # stores f2 stfd f3,160(r1) # stores f3 lis r31,cheatdata@h #0x8000 lis r20, 0xCC00 lhz r28, 0x4010(r20) ori r21, r28, 0xFF sth r21, 0x4010(r20) # disable MP3 memory protection lis r15, codelist@h ori r15, r15, codelist@l ori r7, r31, cheatdata@l # set pointer for storing data (before the codelist) lis r6,0x8000 # default base address = 0x80000000 (code handler) mr r16,r6 # default pointer =0x80000000 (code handler) li r8,0 # code execution status set to true (code handler) lis r3,0x00D0 ori r3,r3,0xC0DE lwz r4,0(r15) cmpw r3,r4 bne- _exitcodehandler lwz r4,4(r15) cmpw r3,r4 bne- _exitcodehandler # lf no code list skip code handler addi r15,r15,8 b _readcodes _exitcodehandler: sth r28,0x4010(r20) # restore memory protection value lfd f2,152(r1) # loads f2 lfd f3,160(r1) # loads f3 lwz r25,168(r1) mtmsr r25 lwz r0,176(r1) mtlr r0 # restores lr lwz r0,12(r1) mtcr r0 # restores cr lwz r0,16(r1) mtctr r0 # restores ctr lwz r0,20(r1) mtxer r0 # restores xer lmw r3,24(r1) # restores r3-r31 lwz r0,8(r1) # loads r0 addi r1,r1,172 isync blr # return back to game _readcodes: lwz r3,0(r15) #load code address lwz r4,4(r15) #load code value addi r15,r15,8 #r15 points to next code andi. r9,r8,1 cmpwi cr7,r9,0 #check code execution status in cr7. eq = true, ne = false li r9,0 #Clears r9 rlwinm r10,r3,3,29,31 #r10 = extract code type, 3 bits rlwinm r5,r3,7,29,31 #r5 = extract sub code type 3 bits andis. r11,r3,0x1000 #test pointer rlwinm r3,r3,0,7,31 #r3 = extract address in r3 (code type 0/1/2) #0x01FFFFFF bne +12 #jump lf the pointer is used rlwinm r12,r6,0,0,6 #lf pointer is not used, address = base address b +8 mr r12,r16 #lf pointer is used, address = pointer cmpwi cr4,r5,0 #compares sub code type with 0 in cr4 cmpwi r10,1 blt+ _write #code type 0 : write beq+ _conditional #code type 1 : conditional cmpwi r10,3 blt+ _ba_pointer #Code type 2 : base address operation beq- _repeat_goto #Code type 3 : Repeat & goto cmpwi r10,5 blt- _operation_rN #Code type 4 : rN Operation beq+ _compare16_NM_counter #Code type 5 : compare [rN] with [rM] cmpwi r10,7 blt+ _hook_execute #Code type 6 : hook, execute code b _terminator_onoff_ #code type 7 : End of code list #CT0============================================================================= #write 8bits (0): 00XXXXXX YYYY00ZZ #write 16bits (1): 02XXXXXX YYYYZZZZ #write 32bits (2): 04XXXXXX ZZZZZZZZ #string code (3): 06XXXXXX YYYYYYYY, d1d1d1d1 d2d2d2d2, d3d3d3d3 .... #Serial Code (4): 08XXXXXX YYYYYYYY TNNNZZZZ VVVVVVVV _write: add r12,r12,r3 #address = (ba/po)+(XXXXXX) cmpwi r5,3 beq- _write_string #r5 == 3, goto string code bgt- _write_serial #r5 >= 4, goto serial code bne- cr7,_readcodes #lf code execution set to false skip code cmpwi cr4,r5,1 #compares sub code type and 1 in cr4 bgt- cr4,_write32 #lf sub code type == 2, goto write32 #lf sub code type = 0 or 1 (8/16bits) rlwinm r10,r4,16,16,31 #r10 = extract number of times to write (16bits value) _write816: beq cr4,+32 #lf r5 = 1 then 16 bits write stbx r4,r9,r12 #write byte add r21, r9, r12 icbi r0, r21 sync isync addi r9,r9,1 b +28 sthx r4,r9,r12 #write halfword add r21, r9, r12 #Get Real Memory Offset icbi r0, r21 #Invalidate Icache around real memory offset sync isync addi r9,r9,2 subic. r10,r10,1 #number of times to write -1 bge- _write816 b _readcodes _write32: rlwinm r12,r12,0,0,29 #32bits align adress stw r4,0(r12) #write word to address icbi r0, r12 #Invalidate icache around address sync isync b _readcodes _write_string: #endianess ? mr r9,r4 bne- cr7,_skip_and_align #lf code execution is false, skip string code data _stb: subic. r9,r9,1 #r9 -= 1 (and compares r9 with 0) blt- _skip_and_align #lf r9 < 0 then exit lbzx r5,r9,r15 stbx r5,r9,r12 #loop until all the data has been written add r21, r9, r12 #Get Real Memory Offset icbi r0, r21 #Invalidate Icache around real memory offset sync isync b _stb _write_serial: addi r15,r15,8 #r15 points to the code after the serial code bne- cr7,_readcodes #lf code execution is false, skip serial code lwz r5,-8(r15) #load TNNNZZZZ lwz r11,-4(r15) #r11 = load VVVVVVVV rlwinm r17,r5,0,16,31 #r17 = ZZZZ rlwinm r10,r5,16,20,31 #r10 = NNN (# of times to write -1) rlwinm r5,r5,4,28,31 #r5 = T (0:8bits/1:16bits/2:32bits) _loop_serial: cmpwi cr5,r5,1 beq- cr5,+16 #lf 16bits bgt+ cr5,+20 #lf 32bits stbx r4,r9,r12 #write serial byte (CT04,T=0) b +16 sthx r4,r9,r12 #write serial halfword (CT04,T=1) b +8 stwx r4,r9,r12 #write serial word (CT04,T>=2) add r21, r9, r12 #Get Real Memory Offset icbi r0, r21 #Invalidate Icache around real memory offset sync isync add r4,r4,r11 #value +=VVVVVVVV add r9,r9,r17 #address +=ZZZZ subic. r10,r10,1 bge+ _loop_serial #loop until all the data has been written b _readcodes #CT1============================================================================= #32bits conditional (0,1,2,3): 20XXXXXX YYYYYYYY #16bits conditional (4,5,6,7): 28XXXXXX ZZZZYYYY #PS : 31 bit of address = endlf. _conditional: rlwinm. r9,r3,0,31,31 #r10 = (bit31 & 1) (endlf enabled?) beq +16 #jump lf endlf is not enabled rlwinm r8,r8,31,1,31 #Endlf (r8>>1) andi. r9,r8,1 #r9=code execution status cmpwi cr7,r9,0 #check code execution status in cr7 cmpwi cr5,r5,4 #compares sub code type and 4 in cr5 cmpwi cr3,r10,5 #compares code type and 5 in cr3 rlwimi r8,r8,1,0,30 #r8<<1 and current execution status = old execution status bne- cr7,_true_end #lf code execution is set to false -> exit bgt cr3,_addresscheck2 #lf code type==6 -> address check add r12,r12,r3 #address = (ba/po)+(XXXXXX) blt cr3,+12 #jump lf code type <5 (==1) blt cr5,_condition_sub #compare [rN][rM] b _conditional16_2 #counter compare bge cr5,_conditional16 #lf sub code type>=4 -> 16 bits conditional _conditional32: rlwinm r12,r12,0,0,29 #32bits align lwz r11,0(r12) b _condition_sub _conditional16: rlwinm r12,r12,0,0,30 #16bits align lhz r11,0(r12) _conditional16_2: nor r9,r4,r4 rlwinm r9,r9,16,16,31 #r9 = extract mask and r11,r11,r9 #r11 &= r9 rlwinm r4,r4,0,16,31 #r4 = extract data to check against _condition_sub: cmpl cr6,r11,r4 #Unsigned compare. r11=data at address, r4=YYYYYYYY andi. r9,r5,3 beq _skip_NE #lf sub code (type & 3) == 0 cmpwi r9,2 beq _skip_LE #lf sub code (type & 3) == 2 bgt _skip_GE #lf sub code (type & 3) == 3 _skip_EQ:#1 bne- cr6,_true_end #CT21, CT25, CT29 or CT2D (lf !=) b _skip _skip_NE:#0 beq- cr6,_true_end #CT20, CT24, CT28 or CT2C (lf==) b _skip _skip_LE:#2 bgt- cr6,_true_end #CT22, CT26, CT2A or CT2E (lf r4>[]) b _skip _skip_GE:#3 blt- cr6,_true_end #CT23, CT27, CT2B or CT2F (lf r4 5 blt cr5,_readcodes lwz r11,-8(r15) #load counter bne cr7,_clearcounter #lf previous code execution false clear counter andi. r12,r3,0x8 #else lf clear counter bit not set increase counter beq _increase_counter andi. r12,r8,0x1 #else lf.. code result true clear counter beq _clearcounter _increase_counter: addi r12,r11,0x10 #else increase the counter rlwimi r11,r12,0,12,27 #update counter b _savecounter _clearcounter: rlwinm r11,r11,0,28,11 #clear the counter _savecounter: stw r11,-8(r15) #save counter b _readcodes #CT2============================================================================ #load base adress (0): 40TYZ00N XXXXXXXX = (load/add:T) ba from [(ba/po:Y)+XXXXXXXX(+rN:Z)] #set base address (1): 42TYZ00N XXXXXXXX = (set/add:T) ba to (ba/po:Y)+XXXXXXXX(+rN:Z) #store base address (2): 440Y0000 XXXXXXXX = store base address to [(ba/po)+XXXXXXXX] #set base address to (3): 4600XXXX 00000000 = set base address to code address+XXXXXXXX #load pointer (4): 48TYZ00N XXXXXXXX = (load/add:T) po from [(ba/po:Y)+XXXXXXXX(+rN:Z)] #set pointer (5): 4ATYZ00N XXXXXXXX = (set/add:T) po to (ba/po:Y)+XXXXXXXX(+rN:Y) #store pointer (6): 4C0Y0000 XXXXXXXX = store pointer to [(ba/po)+XXXXXXXX] #set pointer to (7): 4E00XXXX 00000000 = set pointer to code address+XXXXXXXX _ba_pointer: bne- cr7,_readcodes rlwinm r9,r3,2,26,29 #r9 = extract N, makes N*4 rlwinm r14,r3,16,31,31 #r3 = add ba/po flag bit (Y) cmpwi cr3,r14,0 cmpwi cr4,r5,4 #cr4 = compare sub code type with 4 (ba/po) andi. r14,r5,3 #r14 = sub code type and 3 cmpwi cr5,r14,2 #compares sub code type and 2 blt- cr5,_p01 beq- cr5,_p2 #sub code type 2 _p3: extsh r4,r3 add r4,r4,r15 #r4=XXXXXXXX+r15 (code location in memory) b _pend _p01: rlwinm. r5,r3,20,31,31 #r3 = rN use bit (Z) beq +12 #flag is not set(=0), address = XXXXXXXX lwzx r9,r7,r9 #r9 = load register N add r4,r4,r9 #flag is set (=1), address = XXXXXXXX+rN beq cr3,+8 #(Y) flag is not set(=0), address = XXXXXXXX (+rN) add r4,r12,r4 #address = XXXXXXXX (+rN) + (ba/po) cmpwi cr5,r14,1 beq cr5,+8 #address = (ba/po)+XXXXXXXX(+rN) lwz r4,0(r4) #address = [(ba/po)+XXXXXXXX(+rN)] rlwinm. r3,r3,12,31,31 #r5 = add/replace flag (T) beq _pend #flag is not set (=0), (ba/po)= XXXXXXXX (+rN) + (ba/po) bge cr4,+12 add r4,r4,r6 #ba += XXXXXXXX (+rN) + (ba/po) b _pend add r4,r4,r16 #po += XXXXXXXX (+rN) + (ba/po) b _pend _p2: rlwinm. r5,r3,20,31,31 #r3 = rN use bit (Z) beq +12 #flag is not set(=0), address = XXXXXXXX lwzx r9,r7,r9 #r9 = load register N add r4,r4,r9 #flag is set (=1), address = XXXXXXXX+rN bge cr4,+12 stwx r6,r12,r4 #[(ba/po)+XXXXXXXX] = base address b _readcodes stwx r16,r12,r4 #[(ba/po)+XXXXXXXX] = pointer b _readcodes _pend: bge cr4,+12 mr r6,r4 #store result to base address b _readcodes mr r16,r4 #store result to pointer b _readcodes #CT3============================================================================ #set repeat (0): 6000ZZZZ 0000000P = set repeat #execute repeat (1): 62000000 0000000P = execute repeat #return (2): 64S00000 0000000P = return (lf true/false/always) #goto (3): 66S0XXXX 00000000 = goto (lf true/false/always) #gosub (4): 68S0XXXX 0000000P = gosub (lf true/false/always) _repeat_goto: rlwinm r9,r4,3,25,28 #r9 = extract P, makes P*8 addi r9,r9,0x40 #offset that points to block P's cmpwi r5,2 #compares sub code type with 2 blt- _repeat rlwinm. r11,r3,10,0,1 #extract (S&3) beq +20 #S=0, skip lf true, don't skip lf false bgt +8 b _b_bl_blr_nocheck #S=2/3, always skip (code exec status turned to true) beq- cr7,_readcodes #S=1, skip lf false, don't skip lf true b _b_bl_blr_nocheck _b_bl_blr: bne- cr7,_readcodes #lf code execution set to false skip code _b_bl_blr_nocheck: cmpwi r5,3 bgt- _bl #sub code type >=4, bl beq+ _b #sub code type ==3, b _blr: lwzx r15,r7,r9 #loads the next code address b _readcodes _bl: stwx r15,r7,r9 #stores the next code address in block P's address _b: extsh r4,r3 #XXXX becomes signed rlwinm r4,r4,3,9,28 add r15,r15,r4 #next code address +/-=line XXXX b _readcodes _repeat: bne- cr7,_readcodes #lf code execution set to false skip code add r5,r7,r9 #r5 points to P address bne- cr4,_execute_repeat #branch lf sub code type == 1 _set_repeat: rlwinm r4,r3,0,16,31 #r4 = extract NNNNN stw r15,0(r5) #store current code address to [bP's address] stw r4,4(r5) #store NNNN to [bP's address+4] b _readcodes _execute_repeat: lwz r9,4(r5) #load NNNN from [M+4] cmpwi r9,0 beq- _readcodes subi r9,r9,1 stw r9,4(r5) #saves (NNNN-1) to [bP's address+4] lwz r15,0(r5) #load next code address from [bP's address] b _readcodes #CT4============================================================================ #set/add to rN(0) : 80SY000N XXXXXXXX = rN = (ba/po) + XXXXXXXX #load rN (1) : 82UY000N XXXXXXXX = rN = [XXXXXXXX] (offset support) (U:8/16/32) #store rN (2) : 84UYZZZN XXXXXXXX = store rN in [XXXXXXXX] (offset support) (8/16/32) #operation 1 (3) : 86TY000N XXXXXXXX = operation rN?XXXXXXXX ([rN]?XXXXXXXX) #operation 2 (4) : 88TY000N 0000000M = operation rN?rM ([rN]?rM, rN?[rM], [rN]?[rM]) #copy1 (5) : 8AYYYYNM XXXXXXXX = copy YYYY bytes from [rN] to ([rM]+)XXXXXXXX #copy2 (6) : 8CYYYYNM XXXXXXXX = copy YYYY bytes from ([rN]+)XXXXXX to [rM] #for copy1/copy2, lf register == 0xF, base address is used. #of course, sub codes types 0/1, 2/3 and 4/5 can be put together lf we need more subtypes. _operation_rN: bne- cr7,_readcodes rlwinm r11,r3,2,26,29 #r11 = extract N, makes N*4 add r26,r7,r11 #1st value address = rN's address lwz r9,0(r26) #r9 = rN rlwinm r14,r3,12,30,31 #extracts S, U, T (3bits) beq- cr4,_op0 #lf sub code type = 0 cmpwi cr4,r5,5 bge- cr4,_op56 #lf sub code type = 5/6 cmpwi cr4,r5,3 bge- cr4,_op34 #lf sub code type = 3/4 cmpwi cr4,r5,1 _op12: #load/store rlwinm. r5,r3,16,31,31 #+(ba/po) flag : Y beq +8 #address = XXXXXXXX add r4,r12,r4 cmpwi cr6,r14,1 bne- cr4,_store _load: bgt+ cr6,+24 beq- cr6,+12 lbz r4,0(r4) #load byte at address b _store_reg lhz r4,0(r4) #load halfword at address b _store_reg lwz r4,0(r4) #load word at address b _store_reg _store: rlwinm r19,r3,28,20,31 #r9=r3 ror 12 (N84UYZZZ) _storeloop: bgt+ cr6,+32 beq- cr6,+16 stb r9,0(r4) #store byte at address addi r4,r4,1 b _storeloopend sth r9,0(r4) #store byte at address addi r4,r4,2 b _storeloopend stw r9,0(r4) #store byte at address icbi r0, r4 #Invalidate at offset given by storing gecko register sync isync addi r4,r4,4 _storeloopend: subic. r19,r19,1 bge _storeloop b _readcodes _op0: rlwinm. r5,r3,16,31,31 #+(ba/po) flag : Y beq +8 #value = XXXXXXXX add r4,r4,r12 #value = XXXXXXXX+(ba/po) andi. r5,r14,1 #add flag : S beq _store_reg #add flag not set (=0), rN=value add r4,r4,r9 #add flag set (=1), rN=rN+value b _store_reg _op34: #operation 1 & 2 rlwinm r10,r3,16,30,31 #extracts Y rlwinm r14,r4,2,26,29 #r14 = extract M (in r4), makes M*=4 add r19,r7,r14 #2nd value address = rM's address bne cr4,+8 subi r19,r15,4 #lf CT3, 2nd value address = XXXXXXXX's address lwz r4,0(r26) #1st value = rN lwz r9,0(r19) #2nd value = rM/XXXXXXXX andi. r11,r10,1 #lf [] for 1st value beq +8 mr r26,r4 andi. r11,r10,2 #lf [] for 2nd value beq +16 mr r19,r9 bne+ cr4,+8 add r19,r12,r19 #lf CT3, 2nd value address = XXXXXXXX+(ba/op) rlwinm. r5,r3,12,28,31 #operation # flag : T cmpwi r5,9 bge _op_float _operation_bl: bl _operation_bl_return _op450: add r4,r9,r4 #N + M b _store_reg _op451: mullw r4,r9,r4 #N * M b _store_reg _op452: or r4,r9,r4 #N | M b _store_reg _op453: and r4,r9,r4 #N & M b _store_reg _op454: xor r4,r9,r4 #N ^ M b _store_reg _op455: slw r4,r9,r4 #N << M b _store_reg _op456: srw r4,r9,r4 #N >> M b _store_reg _op457: rlwnm r4,r9,r4,0,31 #N rol M b _store_reg _op458: sraw r4,r9,r4 #N asr M _store_reg: stw r4,0(r26) #Store result in rN/[rN] b _readcodes _op_float: cmpwi r5,0xA bgt _readcodes lfs f2,0(r26) #f2 = load 1st value lfs f3,0(r19) #f3 = load 2nd value beq- _op45A _op459: fadds f2,f3,f2 #N = N + M (float) b _store_float _op45A: fmuls f2,f3,f2 #N = N * M (float) _store_float: stfs f2,0(r26) #Store result in rN/[rN] b _readcodes _operation_bl_return: mflr r10 rlwinm r5,r5,3,25,28 #r5 = T*8 add r10,r10,r5 #jumps to _op5: + r5 lwz r4,0(r26) #load [rN] lwz r9,0(r19) #2nd value address = rM/XXXXXXXX mtlr r10 blr #copy1 (5) : 8AYYYYNM XXXXXXXX = copy YYYY bytes from [rN] to ([rM]+)XXXXXXXX #copy2 (6) : 8CYYYYNM XXXXXXXX = copy YYYY bytes from ([rN]+)XXXXXX to [rM] _op56: bne- cr7,_readcodes #lf code execution set to false skip code rlwinm r9,r3,24,0,31 #r9=r3 ror 8 (NM8AYYYY, NM8CYYYY) mr r14,r12 #r14=(ba/po) bl _load_NM beq- cr4,+12 add r17,r17,r4 #lf sub code type==0 then source+=XXXXXXXX b +8 add r9,r9,r4 #lf sub code type==1 then destination+=XXXXXXXX rlwinm. r4,r3,24,16,31 #Extracts YYYY, compares it with 0 li r5,0 _copy_loop: beq _readcodes #Loop until all bytes have been copied. lbzx r10,r5,r17 stbx r10,r5,r9 addi r5,r5,1 cmpw r5,r4 b _copy_loop #=============================================================================== #This is a routine called by _memory_copy and _compare_NM_16 _load_NM: cmpwi cr5,r10,4 #compare code type and 4(rn Operations) in cr5 rlwinm r17,r9,6,26,29 #Extracts N*4 cmpwi r17,0x3C lwzx r17,r7,r17 #Loads rN value in r17 bne +8 mr r17,r14 #lf N==0xF then source address=(ba/po)(+XXXXXXXX, CT5) beq cr5,+8 lhz r17,0(r17) #...and lf CT5 then N = 16 bits at [XXXXXX+base address] rlwinm r9,r9,10,26,29 #Extracts M*4 cmpwi r9,0x3C lwzx r9,r7,r9 #Loads rM value in r9 bne +8 mr r9,r14 #lf M==0xF then dest address=(ba/po)(+XXXXXXXX, CT5) beq cr5,+8 lhz r9,0(r9) #...and lf CT5 then M = 16 bits at [XXXXXX+base address] blr #CT5============================================================================ #16bits conditional (0,1,2,3): A0XXXXXX NM00YYYY (unknown values) #16bits conditional (4,5,6,7): A8XXXXXX ZZZZYYYY (counter) #sub codes types 0,1,2,3 compare [rN] with [rM] (both 16bits values) #lf register == 0xF, the value at [base address+XXXXXXXX] is used. _compare16_NM_counter: cmpwi r5,4 bge _compare16_counter _compare16_NM: mr r9,r4 #r9=NM00YYYY add r14,r3,r12 #r14 = XXXXXXXX+(ba/po) rlwinm r14,r14,0,0,30 #16bits align (base address+XXXXXXXX) bl _load_NM #r17 = N's value, r9 = M's value nor r4,r4,r4 #r4=!r4 rlwinm r4,r4,0,16,31 #Extracts !YYYY and r11,r9,r4 #r3 = (M AND !YYYY) and r4,r17,r4 #r4 = (N AND !YYYY) b _conditional _compare16_counter: rlwinm r11,r3,28,16,31 #extract counter value from r3 in r11 b _conditional #=============================================================================== #execute (0) : C0000000 NNNNNNNN = execute #hook1 (2) : C4XXXXXX NNNNNNNN = insert instructions at XXXXXX #hook2 (3) : C6XXXXXX YYYYYYYY = branch from XXXXXX to YYYYYY #on/off (6) : CC000000 00000000 = on/off switch #range check (7) : CE000000 XXXXYYYY = is ba/po in XXXX0000-YYYY0000 _hook_execute: mr r26,r4 #r18 = 0YYYYYYY rlwinm r4,r4,3,0,28 #r4 = NNNNNNNN*8 = number of lines (and not number of bytes) bne- cr4,_hook_addresscheck #lf sub code type != 0 bne- cr7,_skip_and_align _execute: mtlr r15 blrl _skip_and_align: add r15,r4,r15 addi r15,r15,7 rlwinm r15,r15,0,0,28 #align 64-bit b _readcodes _hook_addresscheck: cmpwi cr4,r5,3 bgt- cr4,_addresscheck1 #lf sub code type ==6 or 7 lis r5,0x4800 add r12,r3,r12 rlwinm r12,r12,0,0,29 #align address bne- cr4,_hook1 #lf sub code type ==2 _hook2: bne- cr7,_readcodes rlwinm r4,r26,0,0,29 #address &=0x01FFFFFC sub r4,r4,r12 #r4 = to-from rlwimi r5,r4,0,6,29 #r5 = (r4 AND 0x03FFFFFC) OR 0x48000000 rlwimi r5,r3,0,31,31 #restore lr bit stw r5,0(r12) #store opcode icbi r0, r12 #Invalidate at branch sync isync b _readcodes _hook1: bne- cr7,_skip_and_align sub r9,r15,r12 #r9 = to-from rlwimi r5,r9,0,6,29 #r5 = (r9 AND 0x03FFFFFC) OR 0x48000000 stw r5,0(r12) #stores b at the hook place (over original instruction) icbi r0, r12 #Invalidate at hook location sync isync addi r12,r12,4 add r11,r15,r4 subi r11,r11,4 #r11 = address of the last word of the hook1 code sub r9,r12,r11 rlwimi r5,r9,0,6,29 #r5 = (r9 AND 0x03FFFFFC) OR 0x48000000 stw r5,0(r11) #stores b at the last word of the hook1 code icbi r0, r12 #Invalidate at last instruction of hook sync isync b _skip_and_align _addresscheck1: cmpwi cr4,r5,6 beq cr4,_onoff b _conditional _addresscheck2: rlwinm r12,r12,16,16,31 rlwinm r4,r26,16,16,31 rlwinm r26,r26,0,16,31 cmpw r12,r4 blt _skip cmpw r12,r26 bge _skip b _readcodes _onoff: rlwinm r5,r26,31,31,31 #extracts old exec status (x b a) xori r5,r5,1 andi. r3,r8,1 #extracts current exec status cmpw r5,r3 beq _onoff_end rlwimi r26,r8,1,30,30 xori r26,r26,2 rlwinm. r5,r26,31,31,31 #extracts b beq +8 xori r26,r26,1 stw r26,-4(r15) #updates the code value in the code list _onoff_end: rlwimi r8,r26,0,31,31 #current execution status = a b _readcodes #=============================================================================== #Full terminator (0) = E0000000 XXXXXXXX = full terminator #Endlfs/Else (1) = E2T000VV XXXXXXXX = endlfs (+else) #End code handler = F0000000 00000000 _terminator_onoff_: cmpwi r11,0 #lf code type = 0xF beq _notTerminator cmpwi r5,1 beq _asmTypeba cmpwi r5,2 beq _asmTypepo cmpwi r5,3 beq _patchType b _exitcodehandler _asmTypeba: rlwinm r12,r6,0,0,6 # use base address _asmTypepo: rlwinm r23,r4,8,24,31 # extract number of half words to XOR rlwinm r24,r4,24,16,31 # extract XOR checksum rlwinm r4,r4,0,24,31 # set code value to number of ASM lines only bne cr7,_goBackToHandler #skip code if code execution is set to false rlwinm. r25,r23,0,24,24 # check for negative number of half words mr r26,r12 # copy ba/po address add r26,r3,r26 # add code offset to ba/po code address rlwinm r26,r26,0,0,29 # clear last two bits to align address to 32-bit beq _positiveOffset # if number of half words is negative, extra setup needs to be done extsb r23,r23 neg r23,r23 mulli r25,r23,2 addi r25,r25,4 subf r26,r25,r26 _positiveOffset: cmpwi r23,0 beq _endXORLoop li r25,0 mtctr r23 _XORLoop: lhz r27,4(r26) xor r25,r27,r25 addi r26,r26,2 bdnz _XORLoop _endXORLoop: cmpw r24,r25 bne _goBackToHandler b _hook_execute _patchType: rlwimi r8,r8,1,0,30 #r8<<1 and current execution status = old execution status bne cr7,_exitpatch #lf code execution is set to false -> exit rlwinm. r23,r3,22,0,1 bgt _patchfail blt _copytopo _runpatch: rlwinm r30,r3,0,24,31 mulli r30,r30,2 rlwinm r23,r4,0,0,15 xoris r24,r23,0x8000 cmpwi r24,0 bne- _notincodehandler ori r23,r23,0x3000 _notincodehandler: rlwinm r24,r4,16,0,15 mulli r25,r30,4 subf r24,r25,r24 _patchloop: li r25,0 _patchloopnext: mulli r26,r25,4 lwzx r27,r15,r26 lwzx r26,r23,r26 addi r25,r25,1 cmplw r23,r24 bgt _failpatchloop cmpw r25,r30 bgt _foundaddress cmpw r26,r27 beq _patchloopnext addi r23,r23,4 b _patchloop _foundaddress: lwz r3,-8(r15) ori r3,r3,0x300 stw r3,-8(r15) stw r23,-4(r15) mr r16,r23 b _exitpatch _failpatchloop: lwz r3,-8(r15) ori r3,r3,0x100 stw r3,-8(r15) _patchfail: ori r8,r8,1 #r8|=1 (execution status set to false) b _exitpatch _copytopo: mr r16,r4 _exitpatch: rlwinm r4,r3,0,24,31 # set code to number of lines only _goBackToHandler: mulli r4,r4,8 add r15,r4,r15 # skip the lines of the code b _readcodes _notTerminator: _terminator: bne cr4,+12 #check lf sub code type == 0 li r8,0 #clear whole code execution status lf T=0 b +20 rlwinm. r9,r3,0,27,31 #extract VV # bne +8 #lf VV!=0 # bne- cr7,+16 rlwinm r5,r3,12,31,31 #extract "else" bit srw r8,r8,r9 #r8>>VV, meaning endlf VV lfs rlwinm. r23,r8,31,31,31 bne +8 # execution is false if code execution >>, so don't invert code status xor r8,r8,r5 #lf 'else' is set then invert current code status _load_baseaddress: rlwinm. r5,r4,0,0,15 beq +8 mr r6,r5 #base address = r4 rlwinm. r5,r4,16,0,15 beq +8 mr r16,r5 #pointer = r4 b _readcodes #=============================================================================== frozenvalue: #frozen value, then LR .long 0,0 dwordbuffer: .long 0,0 rem: .long 0 bpbuffer: .long 0 #int address to bp on .long 0 #data address to bp on .long 0 #alignement check .long 0 #counter for alignement regbuffer: .space 72*4 .align 3 codelist: .space 2*4 .end