Skip to content

Instantly share code, notes, and snippets.

@profi200
Created August 24, 2024 21:04
Show Gist options
  • Save profi200/c7fef99003fa5d07235d97296da23db3 to your computer and use it in GitHub Desktop.
Save profi200/c7fef99003fa5d07235d97296da23db3 to your computer and use it in GitHub Desktop.
GBA BIOS dumper abusing open bus behavior.
@ License: Do whatever you want.
.syntax unified
.cpu arm7tdmi
.fpu softvfp
@ Based on https://web.archive.org/web/20240111232601/https://gist.github.com/merryhime/797c523724e2dc02ada86a1cfadea3ee
@ Thanks to merryhime for discovering this trick.
@ void dumpBios(void)
.section .iwram.dumpBios, "ax", %progbits
.align 2
.thumb
.global dumpBios
.type dumpBios, %function
.func dumpBios
.cfi_sections .debug_frame
.cfi_startproc
dumpBios:
push {r4-r7}
movs r0, #0
subs r0, r0, #3 @ 0xFFFFFFFD open bus jump.
movs r1, #0 @ BIOS address.
ldr r2, =dumpBios_return + 1
movs r3, #0x0E
lsls r3, r3, #24 @ 0x0E000000 SRAM address.
@ Jump to open bus which contains the ldmia and bx instructions
@ that got prefetched by the CPU previously.
@ Because the CPU will prefetch 2 instructions ahead it will
@ fetch from address 0 which unlocks the BIOS for reading.
dumpBios_lp:
bx r0 @ Must be at an address with bit 1 set.
ldmia r1!, {r4-r7} @ Executed from open bus.
bx r2 @ Executed from open bus.
@ Write data to SRAM.
dumpBios_return:
strb r4, [r3, #0]
lsrs r4, r4, #8
strb r4, [r3, #1]
lsrs r4, r4, #8
strb r4, [r3, #2]
lsrs r4, r4, #8
strb r4, [r3, #3]
strb r5, [r3, #4]
lsrs r5, r5, #8
strb r5, [r3, #5]
lsrs r5, r5, #8
strb r5, [r3, #6]
lsrs r5, r5, #8
strb r5, [r3, #7]
strb r6, [r3, #8]
lsrs r6, r6, #8
strb r6, [r3, #9]
lsrs r6, r6, #8
strb r6, [r3, #10]
lsrs r6, r6, #8
strb r6, [r3, #11]
strb r7, [r3, #12]
lsrs r7, r7, #8
strb r7, [r3, #13]
lsrs r7, r7, #8
strb r7, [r3, #14]
lsrs r7, r7, #8
strb r7, [r3, #15]
@ Increment SRAM pointer.
@ Check if bit 14 of BIOS address is set. If yes we read 16 KiB.
adds r3, r3, #16
lsrs r4, r1, #14
beq dumpBios_lp
pop {r4-r7}
bx lr
.cfi_endproc
.endfunc
// License: Do whatever you want.
#include <gba_console.h>
#include <gba_interrupt.h>
#include <gba_systemcalls.h>
#include <stdio.h>
__attribute__((aligned(4)))
const char saveTypeStr[] = "SRAM_V123";
void dumpBios(void);
int main(void)
{
irqInit();
irqEnable(IRQ_VBLANK);
consoleDemoInit();
// Don't optimize out my save type string plox.
if(REG_IME == 0) puts(saveTypeStr);
REG_IME = 0;
dumpBios();
puts("BIOS dumped. Turn the system off and check the save file.");
REG_IME = 1;
while(1) VBlankIntrWait();
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment