#31352 - BeeWarloc - Fri Dec 10, 2004 9:34 am
Hi..
I'm currently looking at the possibilities of a gdb stub or some other kind of drop-in monitor for the gba (duh..).
On PC ,at least oldschool 16bit realmode, setting a breakpoint is simple. You just replace the opcode at the breakpoint address with the one-byte opcode INT3.
Looking through the available gba docs I can't see any simple way to generate a similar one-opcode user controllable interrupt on the gba. As I understand it, the gba BIOS is read only, and the low level interrupt handler hardcoded. That the BIOS is mirrored in RAM is probably too much to hope for (and I still would have to find an exploit to write to it).
Another idea is to try to trick various SWI to jump into outer space, and then my function, but again I believe this is pretty waste of time, since an exploit like that would have been found by now, right?
So, are there any neat tricks I've missed here?
#31360 - ampz - Fri Dec 10, 2004 12:29 pm
Breakpoints can be done with a regular bl instruction.
#31361 - BeeWarloc - Fri Dec 10, 2004 2:14 pm
True, but although it can jump +-32mB in ARM mode, it's only capable of jumping 2kB when in THUMB mode, which means that a longer jump + pointer would have to be placed somewhere in each 4kB block, if the debugger was supposed to work for all locations (as I want it to be).
I've done a bit more research, and I'm close to making the conclusion that this is the only option.
There are a few problems with it though, especially when debugging existing code (without source code), in finding suitable places to replace instructions with transport bl's (or just b as we don't want to save the link register for each jump).
..
I still have a small hope that there's an easier way. :)
#31363 - Lupin - Fri Dec 10, 2004 2:41 pm
do a divide by 0 with swi =)
I think it will jump to some place in bios...
_________________
Team Pokeme
My blog and PM ASM tutorials
#31367 - Touchstone - Fri Dec 10, 2004 3:59 pm
What about the breakpoint instruction? BKPT <immediate>
It will raise a prefetch abort exception so install your exception handler on the prefetch abort vector. (Called Data Abort in the GBATEK document)
I haven't done this myself so I don't know for sure that the prefetch abort vector is mapped to somewhere accessible.
_________________
You can't beat our meat
#31383 - ampz - Fri Dec 10, 2004 7:13 pm
Replace two words and use the THUMB "long branch with link" instruction.
#31554 - Joat - Sun Dec 12, 2004 5:51 am
If you have a 256 mbit flash cart (or one with programmable mirroring), there are a few bits you can set in the header to unlock the debugging functionality in the BIOS. Undefined opcode traps, FIQ handler, and the memory exceptions (which AFAIK cannot be generated on a GBA) normally reboot the machine, but after unlocking (I think its two different bits in the GBA logo that are ignored during logo decompression), the GBA branhces to 0x09FE0000 instead. This is how the pro debuggers work (they use the FIQ pin to take control, and a 1 mbit ROM handles all the debugger stuff like copying debug messages out of RAM to the PC and vis versa, and setting breakpoints). I dunno if they use an undefined opcode or a long branch tho, since I don't actually have one :(
Another option is using an undefined SWI. The SWI table lookup code doesn't do range checking, and IIRC there are a few opcodes after the table that work out to an address in EXWRAM, so you can lock down your debugger at this point in RAM and just use SWI's as the patchup.
BKPT is not an ARM7 opcode, and it still trips the undefined opcode handler on v5 arch IIRC, which puts you back in the same boat: got to unlock the BIOS first. It's more of a defined bit pattern for true hardware debuggers to look for, rather than a real opcode.
I don't remember any divide by zero checking in the BIOS, and if there is any, its just an early exit out of the SWI, no fancy handling.
_________________
Joat
http://www.bottledlight.com
#31555 - Joat - Sun Dec 12, 2004 6:02 am
I guess I should read the thread before posting. BeeWarloc asked about SWIs in the original post. There certainly are some useful ones into EXWRAM or mirrors of EXWRAM, but I really don't feel like finding my old notes :) Disasm the BIOS and look for the branch table, its around 0x160 or so, should be ~0x30 legit addresses, followed by a few zeros I think, and then more code. Just scan through the code after that for words of the form 0x02xxxxxx, subtract the table start addy from your address, divide by 4 and you've got your thumb SWI parameter, shift left by 16 to get the ARM parameter (their SWI handler really is minimalist, total cheeze, I'm suprised that they didn't specify parameters as word multiples to avoid the shift).
And Touchstone is right, BKPT causes a prefetch abort (not undefined instr trap) on v5 and SA/x-scale, but doesn't do the GBA any good :D
_________________
Joat
http://www.bottledlight.com
#31574 - sasq - Sun Dec 12, 2004 12:11 pm
Heh, I have disassembled the bios some time ago and found out exactly the stuff you posted (allthough I was thinking about how to make fast emulation with dynamic recompilation so I needed a breakpoint for unconverted opcodes) - annoying when I was so sure I would have some new and interesting stuff to reply with on this topic :)
I've also been thinking on how to singlestep in code in ROM - setting a timer-interrupt that occurs at once may do the trick but I'm not sure how many cycles they take to trigger and if you might execute more than one opcode at times...
#31580 - tepples - Sun Dec 12, 2004 5:29 pm
Can your "breakpoint" be a jump back into the recompiler core?
_________________
-- Where is he?
-- Who?
-- You know, the human.
-- I think he moved to Tilwick.
#31635 - sasq - Mon Dec 13, 2004 8:59 am
Preferably (since SWI is slow) but it can also only be one opcode long so it couldnt be a long jump. Depending on the processor it might be possible to reserve one register to hold the adress to jump to.
#31646 - BeeWarloc - Mon Dec 13, 2004 2:10 pm
Thanks for all the feedback and help!
I did as Joat suggested, and analyzed the bios a bit..
After some major confusion, I observed that there's actually only one hardware SWI vector address, but that it's bios code which branches it further through a vector table, which seems to be put at different locations in the two BIOS'es I posess (0x1C4 in the one I'm looking at now). Not at address zero which I first believed..
I just hope that this piece of code don't mess up any flags.. (haven't bothered analyzing that yet, a bit tired today).
Roughly looking through the available random addresses I have a few more questions at hand (to keep the constructive discussion going :):
The gba ignores the highest 4 bit, right? So for example jumping to 0x42000000 would actually jump to 0x02000000.. (this would make finding a suitable unused SWI much easier)..
If not, can the gba execute code from VRAM? (there are a few 0x060xxxxx adresses in there)
And to Joat: I'm very interested in getting more info about how the hardware debuggers do this, and where you got this info (about the 0x09FE0000 address).
#31661 - BeeWarloc - Mon Dec 13, 2004 3:58 pm
Hmm, according to the gbatek doc, accessing addresses >= 0x10000000 does not mirror 0x00000000 > 0x0FFFFFFF, so assuming that's right leaves
me with these possible addresses to theoretically put a debug handler:
CARTRIDGE (can this be the origininal debug ROM addresses?):
SWI 0x02c: 0x09fe2000
SWI 0x02d: 0x09ffc000
VRAM (it is mirrored, but I don't think it will run code)
SWI 0x030: 0x06242404
SWI 0x031: 0x062d2505
SWI 0x032: 0x06362606
EWRAM (alternatives when 256mbit of ROM is unavailable?):
SWI 0x03d: 0x02c01400 (-> 0x02001400)
SWI 0x054: 0x02021001 (-> 0x02021001)
SWI 0x0d5: 0x02002040 (-> 0x02002040)
SWI 0x0db: 0x02362640 (-> 0x02022640)
IWRAM:
SWI 0x0d8: 0x03921c02 (-> 0x03001c02)
SWI 0x0d9: 0x039b1c0b (-> 0x03001c0b)
As far as I can see by this, the best SWI to exploit would be 0x02c or 0x02d..
Btw, this is only certain for the BIOS version on my gba, not quite sure which it (it's bought in holland).
MD5 sum of BIOS:
a860e8c0b6d573d191e4ec7db1b1e4f6 *mybios.gba
#31679 - gb_feedback - Mon Dec 13, 2004 7:09 pm
AFAIK. There are 2 bios's in circulation. One is from the commercial product, the other is a leaked early developers bios. i.e. All the GBA's sold have the same bios.
_________________
http://www.bookreader.co.uk/
#31755 - BeeWarloc - Tue Dec 14, 2004 8:29 am
It could be interesting to get this verified though, if people could post their BIOS'es MD5 sum here.. :)
(for those who don't know, a bios dumper can be found here: http://darkfader.net/gba/main.html
#177843 - WriteASM - Sat Apr 06, 2013 12:40 pm
I know it's been 9 years since the last post here, but I thought I'd at least make one followup post.
After unsuccessfully trying out the "undocumented SWI" ideas, I spent a couple hours one morning wrestling with "C" coding (I still don't like it), eventually getting the DevKitPRO "biosdumper" example compiled, and then modified to output the data over RS-232 at 57600 baud. Presto...I had a BIOS file. (I don't have a DS, and I haven't found any documentation saying how to connect an SD card to the link port on a GBA.)
When studying it, however, I ended up with the following table:
Calculation: SWI# = (Address-$1C8)/4
$2B (not $2C) $09FE2000
$2C (not $2D) $09FFC000
VRAM (Haven't tried running ASM from here...yet)
$2F (not $30) $06242404
$30 (not $31) $062D2505 <--You'll end up in THUMB, as the handler uses "BX R12". $62D2504
$31 (not $32) $06362606 <--Not usable: not LONG aligned, or THUMB
EXTRAM
$3C (not $3D) $02C01400 --> $2001400
$53 (not $54) $02021001 <--End up in THUMB at $2021000
$D4 (not $D5) $02002040
$DA (not $DB) $02362640 --> $2022640
IWRAM
$D7 (not $D8) $03921C02 --> $3001C02 <--Useless: not LONG aligned, nor THUMB destination
$D8 (not $D9) $039B1C0B --> $3001C0B <--This will get you in THUMB mode at $3001C0A
I picked "SWI #0x3C0000", and it worked PERFECTLY on a real GBASP. If you give VisualBoyAdvance a BIOS file, it'll also work. Interestingly, I had to tell the ".org" directive to compile at 0x1144 to put code at 0x1400.
Here's a quick paraphrase of the SWI handler:
Code: |
push {r11, r12, lr} @ Save R11,R12,LR.
...R12 modified; jump table code
mrs r11, spsr_fsxc
push {r11} @ Save SPSR to stack. If the call came from System/Supervisor mode, that would be why.
and r11, r11, #0x80 @ Save only "IRQ" disable bit, if set.
orr r11, r11, #0x1F @ Specify SYSTEM mode. (May have been called in Supervisor)
msr cpsr_fc, r11 @ Set CPU mode, clear flags
push {r2, lr} @ Save more stack, in System mode
add lr, pc, #0 @ Set return address
bx r12 @ See, you CAN get THUMB...this the only instruction to do that!
-----------------------
...user code runs in System mode. Return with BX LR. R2, R11, R12 saved.
-----------------------
pop {r2, lr}
mov r12, #0xD3 @ FIQ,IRQ disable,(ARM mode), Supervisor CPU mode
msr cpsr_fc, r12 @ Set CPU mode, clear flags
pop {r11} @ Get SPSR
msr spsr_fc, r11 @ Set it
pop {r11, r12, lr}
movs pc, lr @ Return, restores PC,CPSR
|
In my case, I can clearly see that if I don't "BX LR" back, the Supervisor and System stacks need some attention.
One question: I tried making my own BIOS dumper (in ASM), but it returned uselessly garbled-up data...which is why I ended up using the DevKitPRO C-based example.
In the following C source code, what does "(WaveData *)(i-4)" do/return?
Code: |
u32 a = MidiKey2Freq((WaveData *)(i-4), 180-12, 0) * 2; |
Is it a pointer to a memory address with "i-4" stored there? Typecasted 32-bit variable? "I<<16"?
A look at the "gba_sound.h" DevKitPRO file shows that "WaveData" is a 34-byte type. If "*" indicates a pointer, where in the type does "i-4" get stored?
For the record, the MD5 sum of my U.S.A. GBASP "AGS-101" BIOS dump is: a860e8c0b6d573d191e4ec7db1b1e4f6. Looks the same to me...
_________________
"Finally, brethren, whatever is true, whatever is honorable, whatever is right, whatever is pure, whatever is lovely, whatever is of good repute, if there is any excellence and if anything worthy of praise, dwell on these things." (Philippians 4:8)
#177844 - Dwedit - Sat Apr 06, 2013 2:23 pm
"movs pc, xx" will set ARM/THUMB mode properly, and set the correct CPU mode, so don't worry about that.
Looks like the type cast is only there to satisfy the expected data type of the function argument, it doesn't affect the value of i-4 at all.
_________________
"We are merely sprites that dance at the beck and call of our button pressing overlord."
#177851 - Dwedit - Sun Apr 07, 2013 1:50 pm
From the ARM7TDMI manual:
The table for how to return from the various exception types (like SWI, IRQ, FIQ, etc...)
Code: |
3.9.3 Exception entry/exit summary
*Table 3-2: Exception entry/exit summarises the PC value preserved in the relevant
R14 on exception entry, and the recommended instruction for exiting the exception
handler.
Return Instruction Previous State Notes
ARM THUMB
R14_x R14_x
BL MOV PC, R14 PC + 4 PC + 2 1
SWI MOVS PC, R14_svc PC + 4 PC + 2 1
UDEF MOVS PC, R14_und PC + 4 PC + 2 1
FIQ SUBS PC, R14_fiq, #4 PC + 4 PC + 4 2
IRQ SUBS PC, R14_irq, #4 PC + 4 PC + 4 2
PABT SUBS PC, R14_abt, #4 PC + 4 PC + 4 1
DABT SUBS PC, R14_abt, #8 PC + 8 PC + 8 3
RESET NA - - 4
Notes
1 Where PC is the address of the BL/SWI/Undefined Instruction fetch which had
the prefetch abort.
2 Where PC is the address of the instruction which did not get executed since
the FIQ or IRQ took priority.
3 Where PC is the address of the Load or Store instruction which generated the
data abort.
4 The value saved in R14_svc upon reset is unpredictable.
|
The explanation of how to return from supervisor mode:
Code: |
4.13.1 Return from the supervisor
The PC is saved in R14_svc upon entering the software interrupt trap, with the PC
adjusted to point to the word after the SWI instruction. MOVS PC,R14_svc will return
to the calling program and restore the CPSR.
Note that the link mechanism is not re-entrant, so if the supervisor code wishes to use
software interrupts within itself it must first save a copy of the return address and
SPSR.
|
Some random example code:
Code: |
MOVS PC,R14 ; Return from exception and restore CPSR
; from SPSR_mode.
|
The explanation of what "movs pc,xx" or "subs pc,xx" does:
Code: |
4.5.4 Writing to R15
When Rd is a register other than R15, the condition code flags in the CPSR may be
updated from the ALU flags as described above.
When Rd is R15 and the S flag in the instruction is not set the result of the operation
is placed in R15 and the CPSR is unaffected.
When Rd is R15 and the S flag is set the result of the operation is placed in R15 and
the SPSR corresponding to the current mode is moved to the CPSR. This allows state
changes which atomically restore both PC and CPSR. This form of instruction should
not be used in User mode.
|
_________________
"We are merely sprites that dance at the beck and call of our button pressing overlord."