Which registers are safe to use in an ASM code using the C0 code type, and which registers will need their contents saved before being overwritten due to being used by the code handler itself? I'm interested in making a C0 code that sets r3 and r12, and then branches to the exireceivebuffer or exisendbuffer routines that the code handler contains. The effect would be a code that could read/write custom data on the USB Gecko, which would sometimes be nice for debugging (e.g. press a button combination in the game, and a portion of RAM will dump itself without having to click something on the PC side). So the ASM code would affect r3, r12, and whatever registers exireceivebuffer and exisendbuffer write to.
Is this safe, or will I need to save/restore some registers?
(FYI, my ASM knowledge is somewhat limited, so n00b-friendly replies would be excellent.)
Thanks!
For reference, here are the routines:
#***************************************************************************
# subroutine: exireceivebyte:
# Return 1(r3) lf byte receive, 0(r3) lf no byte
# Command byte is stored at 0x800027ff
#***************************************************************************
exireceivebyte:
mflr r30
lis r3, 0xA000 # EXI read command
bl checkexisend
andis. r3, r16, 0x800
rlwinm r29,r16,16,24,31
mtlr r30
blr
#***************************************************************************
# subroutine: checkexisend:
#
#***************************************************************************
checkexisend:
stw r23, 0x6814(r24) # 32mhz Port B
stw r3, 0x6824(r24)
stw r22, 0x6820(r24) # 0xCC006820 (Channel 1 Control Register)
exicheckreceivewait:
lwz r5, 0x6820(r24)
andi. r5, r5, 1
bne exicheckreceivewait # while((exi_chan1cr)&1);
lwz r16, 0x6824(r24)
stw r5, 0x6814(r24)
blr
#***************************************************************************
# subroutine: exireceivebuffer:
# r3 byte counter, r12 points to buffer, r3 gets copied as gets destroyed
#***************************************************************************
exireceivebuffer:
mflr r10 # save link register
mtctr r3 # counter
li r14,0
bufferloop:
bl exicheckreceive
bl exicheckreceive
bl exireceivebyte
beq bufferloop # r3 returns 1 or 0, one for byte received ok
stbx r29, r14,r12 # store byte into buffer
addi r14, r14, 1 # increase buffer by 1
bdnz bufferloop
mtlr r10 # retore link register
blr # return to command check
#***************************************************************************
# exisendbuffer:
# r3 byte counter, r12 points to buffer, r3 gets copied as gets destroyed
#***************************************************************************
exisendbuffer:
mflr r10 # save link register
mtctr r3 # r3->counter
li r14,0
sendloop:
lbzx r3, r12,r14
bl exisendbyte
beq sendloop
addi r14, r14, 1 # increase buffer
bdnz sendloop
mtlr r10 # restore link register
blr
#***************************************************************************
# exisendbyte:12345678
# r3 byte to send, returns 1 lf sent, 0 lf fail (!!! called by breakpoint)
#***************************************************************************
exisendbyteAA:
li r3,0xAA
exisendbyte: # r3, send value
mflr r30
slwi r3, r3, 20 # (sendbyte<<20);
oris r3, r3, 0xB000 # 0xB0000000 | (OR)
li r22,0x19
li r23,0xD0
lis r24,0xCD00
bl checkexisend
extrwi. r3, r16, 1,5 # returns either 0 or 1, one for byte received ok
mtlr r30
blr
#***************************************************************************
# subroutine: exicheckrecieve:
# Return 1(r3) lf byte receive, 0(r3) lf no byte
#***************************************************************************
exicheckreceive:
mflr r30
exicheckreceive2:
lis r3, 0xD000 # EXI check status command
bl checkexisend
rlwinm. r3,r16,6,31,31 # returns either 0 or 1 for r3
beq exicheckreceive2
mtlr r30
blr
You should assume that there aren't any safe registers. The code handler uses different registers in different versions to hold the po, ba, etc. They can also change in future releases of the code handler. There's a stmw (STore Multiple Words) instruction that makes pushing/popping multiple registers easier.
Check this thread for a wealth of info on C0. http://wiird.l0nk.org/forum/index.php/topic,4810.0.html
FYI, your idea would require a customized application on the host side. WiiRDGUI or Gecko.NET would have to be re-programmed to have a mode which receives unexpected data.
Quote from: dcx2 on May 08, 2010, 10:49:39 PM
You should assume that there aren't any safe registers. The code handler uses different registers in different versions to hold the po, ba, etc. They can also change in future releases of the code handler. There's a stmw (STore Multiple Words) instruction that makes pushing/popping multiple registers easier.
Check this thread for a wealth of info on C0. http://wiird.l0nk.org/forum/index.php/topic,4810.0.html
FYI, your idea would require a customized application on the host side. WiiRDGUI or Gecko.NET would have to be re-programmed to have a mode which receives unexpected data.
Ah, thank you, that information helps a lot. stmw looks like it would save me a great deal of effort. And yes, my uses for this concept would involve a custom PC app.
One more question... if I want to save all of the registers from r3 upwards (rather than r14 upwards as Link's example uses), would I be likely to run out of stack? Or should that not be a likely problem?
Thanks again for the info (and the speedy reply)!
I doubt you'd run out of stack. But you probably shouldn't push 20+ registers...just push as many as you need and use the ones at the end. If you absolutely must use r3, push r3 separately from stmw'ing.
fyi, found this.
http://wiird.l0nk.org/forum/index.php/topic,1733.msg30364.html#msg30364
However, that post is for the old code handler. Newer versions of the code handler are slightly different. So, if you write a C0 code that relies on the po register, you should make a note about what version of Gecko OS your C0 code will require.
Register safety may change, too. So if you want to future-proof your C0 code you should probably make a stack frame and store some registers.
r0 safe
r1 Stack pointer
r2 Table of Contents (TOC) pointer
r3 safe
r4 not safe
r5 safe
r6 ba
r7 gr addresses
r8 code execution status
r9 safe
r10 safe
r11 safe
r12 safe
r13 not safe (reserved)
r14 not safe
r15 code line address
r16 po
r17-31 unknown
Thanks!
I would like to stress something.
That listing, for register safety, applies ONLY TO THE C0 CODE TYPE! Do NOT use that list with ANY C2 CODES EVER! To determine what registers are safe for a C2 code, you will need to read my post on the safety of registers (http://wiird.l0nk.org/forum/index.php/topic,6555.msg55745.html#msg55745)
Quote from: dcx2 on August 02, 2010, 09:10:04 PM
fyi, found this.
http://wiird.l0nk.org/forum/index.php/topic,1733.msg30364.html#msg30364
r0 safe
r1 Stack pointer
r2 Table of Contents (TOC) pointer
r3 safe
r4 not safe
r5 safe
r6 ba
r7 gr addresses
r8 code execution status
r9 safe
r10 safe
r11 safe
r12 safe
r13 not safe (reserved)
r14 safe
r15 code line address
r16 not used
r17 safe
r18 safe
r19 safe
r20 po
r21-r31 unknown
FYI, this list is from early 2009, and some of the registers appear to have changed in recent versions of the code handler. A recent version I have (from the source code of NeoGamma r9 beta 30, which I assume is identical to the latest GeckoOS) uses r16 for po, instead of r20. So hackers who are relying on registers being safe should double-check on a current code handler, or better, construct a stack frame so that it works on all versions of the code handler.
Constructing a stack frame isn't going to fix the problem with the PO changing registers. :( And the funny thing is that I said this same thing back in the second post.
I should have added that if one chooses to use that list of safe registers, they should note the version of Gecko OS that it runs on. Besides, during debugging it would become obvious that something is amiss...assuming you bother trying to debug C0 codes.
I just double-checked the C0 code with the current code handler. You're right, po moved from r20 to r16.
On the bright side, the safety of the registers through r12 is still valid. I wouldn't trust anything above r12, though.
Also, in case anyone was wondering, despite the fact that the C0 code ends with a blr, it does not follow PPC convention regarding volatile registers. Specifically, I believe r4 is holding the number of bytes of ASM in the C0 code, so that they can be added to the current code line address to avoid reading the ASM as if it were a WiiRD code.