[HTC Pico (Explorer)] no.human.being:
The kernel image is the code that it runs. I would use a "concatenated chainloader + HBOOT" for this, but of course the plain binary only, not an Android boot image. We don't know to which "physical address" it loads the kernel image though. This is probably not the 0x12c08000 that we'd expect on an Android phone.

I tried the following on an MSM7227 HBOOT.

qemu-system-arm -cpu arm1136 -m 512 -kernel chain_109.bin -initrd initrd

Only displays a black window though. For the MSM7225A you'd probably want to specify "-cpu cortex-a8". The MSM7225A is actually a Cortex A5 but that is not available on QEMU so I'd go to the next "higher" model as they are usually backwards compatible. The "-m 512" specifies that we want the "virtual ARM" to have 512 MiB of RAM. The "-kernel" option specifies the kernel image and the "-initrd" option the initial ramdisk image.

There are two more interesting options. Using "-mtdblock" you can specify an image file to be used as "virtual NAND". Using "-sd" you can specify an image file to be used as virtual SD card.

Some problems I see with this emulation stuff:

- We don't know if and how we can specify the address where the kernel is loaded and we don't know where it gets loaded by default.

- QEMU for ARM emulates no framebuffer controller. We don't know how the HBOOT's going to react to that. If it runs, we probably won't see any output.

- QEMU for ARM emulates no "hardware buttons" (Power, Vol-Up, Vol-Down, capacitive buttons) and HBOOT will only go into the menu when Vol-Down is pressed.

- How can we debug code running inside the emulator?

EDIT3: Yeah I got it (principally). I built two chainloaders, an "outer" and an "inner", then concatenated them as "cat loader_outer.bin loader_inner.bin hboot_109.img > qemu_109.bin". The "outer" chainloader moves the "inner loader + HBOOT" to the place where on an actual phone the HBOOT would move the exploit that is loaded by Fastboot (so to 0x12c08000) and then the "inner" chainloader (that's the actual exploit code that would also run on an actual phone) runs from there and moves HBOOT to physical page zero, then jumps into it. They were configured as follows.

Outer chainloader:

- load_addr: 0x00010088 (0x00010000 address where kernel is loaded by QEMU, plus 0x88 size of outer chainloader exploit code in bytes)

- execute_addr: 0x12c08000 (on a phone this would be the "kernel_addr" in the boot image)

- length: 0x00080088 (length of the "inner kernel image", which is size of HBOOT, 0x00080000 for the WFS, plus 0x88, size of the "inner" chainloader exploit in byte)

Inner chainloader:

- load_addr: 0x12c08088 (0x12c08000 address where the "inner kernel image" is loaded by the "outer chainloader", plus 0x88 size of the inner chainloader exploit code in bytes)

- execute_addr: 0x00000000 (bootloaders always run from physical page zero)

- length 0x00080000 (length of the actual "payload", so size of WFS HBOOT, which is 0x00080000)

Open up a terminal and let the ARM emulator run.

$ qemu-system-arm -nographic -cpu arm1136 -m 512 -kernel qemu_109.bin -initrd initrd -S -s

Fire up an instance of the GNU Debugger (gdb) for ARM and connect it to the ARM emulator for remote debugging.

$ ./arm-none-eabi-gdb
(gdb) target remote localhost:1234
Remote debugging using localhost:1234
0x00000000 in ?? ()
(gdb)

Verify that no code has been executed yet and the program counter is still at zero.

(gdb) info registers pc
pc 0x0	0
(gdb)

Make the debugger always show the instruction that was fetched, but not yet executed by the processor (emulator).

(gdb) display/i $pc
1: x/i $pc
=> 0x0:	mov	r0, #0
(gdb)

In the beginning, the emulator will run its own initialization code (much like the PBL, SBL, OEMSBL, etc. stuff on the actual phone). We may even intervene with this code using the debugger, much like we could also do on the real target if we had JTAG, but we're not interested. So we set a breakpoint at address 0x10000 and then let the emulator run. The breakpoint will halt the processor (emulator) as soon as the first instruction of the "outer" chainloader is fetched (but not yet executed - the processor always stops between the fetch and decode process).

(gdb) break *0x10000
Breakpoint 1 at 0x10000
(gdb) continue
Continuing.

Breakpoint 1, 0x00010000 in ?? ()
1: x/i $pc
=> 0x10000:	b	0x10010
(gdb)

The breakpoint has been hit and the instruction that was fetched (but not yet executed) is an unconditional branch to 0x10010 physical. This is actually the first instruction of the outer chainloader exploit, which begins with an unconditional branch instruction. When we let the outer chainloader run, it will load the inner chainloader to 0x12c08000 physical and then jump to it, so let's set a breakpoint at that address so that we can let the outer chainloader run and the processor stops as soon as the first instruction of the inner chainloader was fetched.

(gdb) break *0x12c08000
Breakpoint 2 at 0x12c08000
(gdb) continue
Continuing.

Breakpoint 2, 0x12c08000 in ?? ()
1: x/i $pc
=> 0x12c08000:	b	0x12c08010
(gdb)

So the inner chainloader got successfully moved to 0x12c08000 by the outer chainloader and is now about to be executed. It will move the actual HBOOT code to physical zero and then jump to it. So let's set a breakpoint at physical zero and run the code until it's hit.

(gdb) break *0x0
Breakpoint 3 at 0x0
(gdb) continue
Continuing.

Breakpoint 3, 0x00000000 in ?? ()
1: x/i $pc
=> 0x0:	b	0x50
(gdb)

So now we have an instruction that was fetched from physical zero. This should be the first instruction of our HBOOT. It is an unconditional branch to 0x50 physical and HBOOT images actually begin with an unconditional branch to that address. But let's use the debugger to disassemble a bit more of the code following the current location of our instruction pointer to verify that it's indeed the code of an HBOOT. Let's disassemble 8 instructions relative to our program counter. We do this using an "x" (for eXamine) directive to GDB.

(gdb) x/8xi $pc
=> 0x0:	b	0x50
0x4:	ldmdbcc	r0!, {r0, r4, r5, r9, r10, r11, sp}
0x8:	ldmdbcc	r0!, {r1, r2, r3, r5, r12, sp}
0xc:	andeq	r0, r0, r9, lsr r0
0x10:	; <UNDEFINED> instruction: 0x37323237
0x14:	mrrcmi	3, 2, r5, r0, cr0
0x18:	andeq	r0, r0, r0
0x1c:	nop	; (mov r0, r0)
(gdb)

Now let's compare this to an HBOOT disassembly created using "objdump".

0:	ea000012	b	0x50
4:	39302e31	ldmdbcc	r0!, {r0, r4, r5, r9, sl, fp, sp}
8:	3930302e	ldmdbcc	r0!, {r1, r2, r3, r5, ip, sp}
c:	00000039	andeq	r0, r0, r9, lsr r0
10:	37323237	; <UNDEFINED> instruction: 0x37323237
14:	4c505320	ldclmi	3, cr5, [r0], {32}
18:	00000000	andeq	r0, r0, r0
1c:	e1a00000	nop	; (mov r0, r0)

Looks good, doesn't it? Now as you can see, the disassembly is not exactly the same, however the following register names are equivalent.

r10 = sl (stack limit)
r11 = fp (frame pointer)
r12 = ip (this one's a bit misleading - "ip" does not mean "instruction pointer", but "intra procedure")
r13 = sp (stack pointer)
r14 = lr (link register)
r15 = pc (program counter - this is the actual "instruction pointer")

So execution actually reaches the HBOOT code and we finally have at least some sort of debugging facility now.