[E3-hacking] The boot process, revealed!
David Given
e3-hacking@earth.li
Sat, 19 Mar 2005 00:20:03 +0000
Well, I've managed to hack pblq into downloading the NAND flash. Some of
it, at least.
The secret is that PBL's checksum routine is very, very stupid, and
while it can checksum the flash, it can only checksum from the
*beginning* of the flash.
This means you can calulate the checksum of byte 0; or bytes 0 to 1; or
bytes 0 to 2; etc. Fortunately, I can work out byte n by calculating the
checksum of bytes 0..n and subtracting the checksum of bytes 0..(n-1).
Unfortunately this means the E2 is doing huge amounts of work, and the
further into the flash you want to read, the slower it gets.
Initial download speed: 66 Bps. Not brilliant.
Average download speed after reading 16kB: 40 Bps. Pathetic.
It would appear that the only way of getting an image of the flash would
be to download a custom program; and the only way to do that is to
reflash it. At least now I have two pages to play with.
This is what the first 128 bytes looks like:
00000000 51 3B 51 3B 00 00 71 16 6C 34 01 00 02 00 02 00 Q;Q;..q.l4......
00000010 01 00 34 00 42 4F 54 00 00 00 00 00 00 00 00 00 ..4.BOT.........
00000020 00 00 00 00 40 28 23 29 42 4F 54 20 56 32 2E 30 ....@(#)BOT V2.0
00000030 20 42 75 69 6C 64 3A 30 30 35 32 00 00 00 00 00 Build:0052.....
00000040 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00000050 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00000060 00 00 00 00 7C 00 04 00 13 B5 13 B5 00 00 04 00 ....|...........
00000070 02 00 00 00 DC 07 01 00 00 00 00 00 62 00 00 02 ............b...
The code that deals with this is in PBL near 0x25c0. After loading at
least some of the image at 0x410000 (I don't know how much yet), it
examines the following significant fields that I've found so far:
+0000: magic1, 0x3B513B51
+0008: headerlength
+0014: magic2, 0x00544F42 ("BOT")
+0064: execaddress
+0068: magic3, 0xB513B513
+006c: destination (0x04000000)
+0070: imagetype
0 == plain
2 == compressed
+0074: compressedlength
I've included what I think is a decompilation of the boot logic at the
end (because it's big and antisocial). Basically, PBL supports both
compressed and uncompressed images; the data is copied or decompressed
to the target destination and the execution address called. Couldn't be
simpler (although the code took me several hours to decipher... god,
this stuff is hard. I couldn't have done it without Ralph's crib sheet).
This should be dead easy to write code for.
Next order of business is to try and figure out how to reflash it, and
then I can give it a try...
---snip---
int16_t checksum(byte* start, offset)
{
byte checksum1 = 0;
byte checksum2 = 0;
while (offset--) /* not sure about this */
{
b = *start++;
checksum1 += b;
checksum2 += checksum1;
}
return (checksum1<<8) | (checksum);
}
if ((magic1 != 0x3B513B51) ||
(magic3 != 0xB513B513) ||
(magic2 != 0x00544F42)) /* PBL uses strcmp for this one */
goto error;
if (headerlength == 0)
goto error;
if (imagetype != plain)
{
/* If this is a compressed image, validate the compressed data
by checksumming it. I think. */
if (value1 > 0x30000)
goto error;
if (checksum(0x410000, value1) != 0)
{
/* This can never happen, surely? */
if (imagetype == plain)
goto error;
if (compressedlength > 0x30000)
goto error;
if (checksum(0x410000, compressedlength) != 0)
goto error;
}
}
if (imagetype == plain)
{
memcpy(destination, 0x410000, headerlength);
}
else if (imagetype == compressed)
{
memcpy(destination, 0x410000, 0x7c);
decompress_rx_packet(0x410000, destination+0x7c,
compressedlength-0x7C);
}
execaddress();
...
error:
/* I believe this might keep retrying every 8kB throughout the flash
until it finds a valid boot block. Useful if the first page on the flash
chip has died. */
---snip---
--
+- David Given --McQ-+ "I don't like the thought of her hearing what I'm
| dg@cowlark.com | thinking." "*No-one* likes the thought of hearing
| (dg@tao-group.com) | what you're thinking." --- Firefly, _Objects in
+- www.cowlark.com --+ Space_