Files
Embedded-Hacking/WEEK03/WEEK03-01.md
2026-03-19 15:01:07 -04:00

3.9 KiB

Embedded Systems Reverse Engineering

Repository

Week 3

Embedded System Analysis: Understanding the RP2350 Architecture w/ Comprehensive Firmware Analysis

Non-Credit Practice Exercise 1: Trace a Reset

Objective

Single-step through the first 10 instructions of the reset handler to understand exactly what happens when the RP2350 powers on or resets.

Prerequisites

  • Raspberry Pi Pico 2 with debug probe connected
  • OpenOCD and arm-none-eabi-gdb available in your PATH
  • build\0x0001_hello-world.elf present and flashed to the board
  • Week 3 environment setup completed (OpenOCD running, GDB connected)

Task Description

You will set a breakpoint at the reset handler (0x1000015c), trigger a reset, and step through each instruction one at a time while documenting what each instruction does.

Step-by-Step Instructions

Step 1: Start OpenOCD
openocd ^
  -s "C:\Users\flare-vm\.pico-sdk\openocd\0.12.0+dev\scripts" ^
  -f interface/cmsis-dap.cfg ^
  -f target/rp2350.cfg ^
  -c "adapter speed 5000"
Step 2: Launch GDB
arm-none-eabi-gdb build\0x0001_hello-world.elf
Step 3: Connect to Target
(gdb) target extended-remote :3333
Step 4: Set Breakpoint at Reset Handler
(gdb) b *0x1000015c

What this does: Places a breakpoint at the very first instruction of the reset handler (the entry point after bootrom).

Step 5: Reset and Break
(gdb) monitor reset halt
(gdb) c

What this does:

  • monitor reset halt resets the chip and immediately halts it
  • c continues execution until the breakpoint at the reset handler is hit
Step 6: Single-Step Through Instructions

Now step through the first 10 instructions, one at a time:

(gdb) si
(gdb) disas $pc,+2
(gdb) info registers r0

Repeat si nine more times, examining each instruction.

Example of what you'll see:

Instruction 1:

0x1000015c <_reset_handler>: mov.w r0, #3489660928 @ 0xd0000000

What it does: Loads the SIO base address (0xd0000000) into r0

Instruction 2:

0x10000160 <_reset_handler+4>: ldr r0, [r0, #0]

What it does: Reads the CPUID register to determine which core is running

Instruction 3:

0x10000162 <_reset_handler+6>: cbz r0, 0x1000016a

What it does: If CPUID is 0 (Core 0), branch ahead to continue boot; otherwise handle Core 1

Step 7: Document Your Observations

For each of the 10 instructions:

  1. Write down the address
  2. Write down the assembly instruction
  3. Explain what it does
  4. Note any register changes using info registers

Expected Output

  • You should see the reset handler check which core is running
  • If you're on Core 0, you'll see it jump to the data copy section
  • Register r0 will contain CPUID value (should be 0)
  • PC (program counter) advances with each si command

Questions for Reflection

Question 1: Why does the reset handler check the CPUID before doing anything else?
Question 2: What would happen if Core 1 tried to run the same initialization code as Core 0?
Question 3: Which registers are used in the first 10 instructions, and why those specific ones?

Tips and Hints

  • Use disas $pc,+20 to see upcoming instructions without stepping through them
  • Use info registers to see all register values at any point
  • If you step past where you wanted to stop, just monitor reset halt and start over
  • Keep notes as you go—this is detective work!

Next Steps

  • Try stepping all the way through to the data copy loop
  • Set a breakpoint at 0x1000016c (the data copy loop) and continue there directly
  • Move on to Exercise 2 to calculate the stack size from the vector table

Additional Challenge

Set a breakpoint at 0x10000178 (the BSS clear phase) and continue execution to see how the reset handler transitions from data copying to BSS clearing.