Sunday, August 17, 2014

Opening the Galileo Firmware Update Image

In the Galileo tool installation directory, under hardware/tools/x86/bin, there's a file named sysimage-galileo-1.0.2.cap, which looks awfully like the firmware update image.  The file size is little under 8MB, which is the size of the SPI flash part, and the filename seems to hint at this being the system image of some sort.  There's also script, which refers to sysimage files.

When I first opened the file in vim and used the handy xxd command to see the hexdump (:%!xxd, which also works magically on Windows), it felt a little disorienting.  However, there are certain things that I knew would be in the firmware update image.  Since the Galileo board is booting from the device, there has to be some sort of bootloader in there (grub legacy, as seen before) as well as the bootloader configuration information (grub.conf).  I also know that the Linux kernel image and the initramfs image must also be included.  In the bootlog, as Linux kernel boots, it helpfully prints the following which gives me the kernel and initramfs sizes.
[Linux-EFI SPI, setup=0x107f, size=0x1e0da0]
[Initrd SPI, addr=0xdb5f000, size=0x298a13]
That's more than enough to start some spelunking.  Since it's easiest to find strings, and I know grub.conf is a simple text file, I started by looking for the title of the boot targets like 'Clanton' and 'SVP' - Voila!  At 0x06a3990, you see the contents of grub.conf that corresponds to the boot menu that we see in the bootlog.
Claton SVP kernel!

Linux kernel image also has some unique features - I know that it'll start with "MZ" as its magic number and will have some blurb about needing a bootloader.  By looking for that string, I found what looks very much like the executable kernel image at 0x04be990.
Start of the Linux Kernel

As I was browsing around, I noticed a certain pattern appearing close to start of the two sections above.  The entire update image itself starts with header string with the string "HSC_", and this header appears 9 times throughout the file aligned at 16 byte boundaries.  More importantly, this appears exactly 1024 bytes before the two sections that I've found above.  Using this big hint, I looked at the different sections and tried to figure out what they might be - initramfs was easy, as it's the only region big enough to fit the file size above.  Grub EFI executable was also easy to determine, but the first sets of regions are a mystery for now.
0x0000000 (size 0x0021500) - ??? looks like some sort of table
0x0021500 (size 0x0062090) - ??? looks like an executable
0x0083590 (size 0x0040000) - ??? looks like an executable
0x00c3590 (size 0x0040000) - ??? looks like an executable
0x0103590 (size 0x0121000) - ??? looks like an executable
0x0224590 (size 0x029A000) - initramfs
0x04be590 (size 0x01E5000) - Kernel Image
0x06a3590 (size 0x0001000) - grub.conf
0x06a4590 (size 0x0051000) - grub.efi executable
Now that we have the regions, we can extract the kernel and initramfs filesystem with a simple dd commands
$ dd if=sysimage-galileo-1.0.2.cap of=initramfs.lzma bs=1 skip=2247056 count=2722323
$ dd if=sysimage-galileo-1.0.2.cap of=vmlinux bs=1 skip=4974992 count=1986560
 Extracting the rootfs from initramfs is pretty straight forward from this point
$ mkdir rootfs
$ cp initramfs.lzma rootfs/
$ cd rootfs
$ unxz initramfs.lzma
$ cpio -ivd < initramfs
And now you have the exact filesystem that you get within Galileo after Linux boots up. We can even see the firmware flashing code in opt/cln/galileo/!  And just for fun, let's try booting the Kernel and initramfs on QEMU :-)
$ qemu-system-i386 -kernel vmlinux -initrd initramfs.lzma -append ="root=/dev/ram0 console=uart earlyprintk=serial apic=debug rw"
After that, you need to switch QEMU to serial0 by pressing Ctrl + Alt + 3, but once done, you see the kernel booting on a completely different QEMU system!

It's booting up!
There are some issues - the final console never comes up, probably because init routines point the consoles elsewhere upon boot...  but it does shows that Galileo is basically a stripped down PC.  How amazing is it when you can take a random kernel and stick it on a completely different system and have it boot up?

No comments:

Post a Comment