Falconwing boot

The Falconwing image has four to six partitions, depending on how you count them and when you're looking at them. A fresh Falconwing image has a boot partition, rfsA, rfsB, an extended partition marker, and psp. Upon first boot, it will expand the extended partition marker, rewrite psp, and create a new /mnt/storage partition as the sixth partition.

Boot partition overview
Falconwing uses the on-chip bootstream bootloader from Freescale. This uses encrypted images, which need to be encrypted either using the otp key, or a key distributed in the elftosb2 package. Their code assumes one Linux kernel, which does not conform to what Chumby needs.

Because of this, we've come up with the following partition layout that lives within the first DOS partition of the boot image:

Start End Size Name Purpose 0x00000000 0x00000800 0x00000800 reserved This area is ignored. 0x00000800 0x00008000 0x00007800 blbs Chumby boot blobs 0x0000c000 0x00010000 0x00004000 cnfg Config block 0x00010000 0x00044800 0x00034800 boot Chumby bootloader 0x00044800 0x0006a000 0x00025800 img1 Boot graphic 0x0006a000 0x0008f800 0x00025800 img2 Boot graphic 0x0008f800 0x000b5000 0x00025800 img3 Boot graphic 0x000b5000 0x000da800 0x00025800 img4 Boot graphic 0x000da800 0x00100000 0x00025800 img5 Boot graphic 0x00100000 0x00500000 0x00400000 krnA First boot kernel 0x00500000 0x00900000 0x00400000 krnB Second boot kernel 0x00900000 0x00e00000 0x00500000 krnC Unused recovery kernel.

Configuration Partition
The configuration partition contains settings that describe the current state of the Chumby, as well as defining the layout for the remainder of the boot partition. It's laid out in 16-byte chunks, with the first few chunks representing global configuration data, and each subsequent chunk representing a partition. Many fields are left empty in the currently-shipping devices. Its layout on disk begins at 0xc800, and looks like this:

typedef struct _config_area { char sig[4];                   // 'C','f','g','*' unsigned char area_version[4]; // 1,0,0,0 unsigned char active_index[4]; // element 0 is 0 if krnA active, 1 if krnB; elements 1-3 are padding unsigned char updating[4];     // element 0 is 1 if update in progress; elements 1-3 are padding char last_update[16];          // NULL-terminated version of last successful update, e.g. "1.7.1892" unsigned int p1_offset;        // Offset in bytes from start of device to start of partition 1 char factory_data[220];        // Data recorded in manufacturing in format KEY=VALUE ...     char configname[128];           // NULL-terminated CONFIGNAME of current build, e.g. "silvermoon_sd" unsigned char unused2[128]; unsigned char mbr_backup[512]; // Backup copy of MBR block_def block_table[64];     // Block table entries ending with offset==0xffffffff unsigned char unused3[0]; } config_area;

A partition structure, which describes each of the fields mentioned above, looks like:

typedef struct _block_def { unsigned int offset;       // Offset from start of partition 1; if 0xffffffff, end of block table unsigned int length;       // Length of block in bytes unsigned char block_ver[4]; // Version of this block data, e.g. 1,0,0,0 char name[4];              // Name of block, e.g. "krnA" (not NULL-terminated, a-z, A-Z, 0-9 and non-escape symbols allowed) } block_def;

The last partition is defined as one that has an offset of 0xffffffff bytes, as that points into a reserved area of the bootloader.

Kernel updates
Kernel updates should only be performed through scripts, which will write to the appropriate offsets on /dev/mmcblk0p1. These updates should ensure that the writes are sized appropriately.

Normal updates will modify either k1 or k2, depending on which partition the user is currently NOT booted into. Updates will write update-state-information to the config partition.

Updates should NEVER modify the blob section, unless we get new blobs from Freescale. Adventurous users could modify boot, but they shouldn't really have to.

Boot process
The following steps take place when the Falconwing boots:


 * 1) The boot rom examines the OCOTP fuses and determines it needs to boot from MBR
 * 2) The first 2048 bytes of the SD card are examined, and the boot image is located
 * 3) sdram_prep, clocks, power, and chumby_stub are all loaded from a Bootstream image into OCRAM
 * 4) sdram_pre, clocks, and power are all executed to set up registers and DRAM
 * 5) chumby_stub is executed
 * 6) chumby_stub loads chumby_boot from disk into DRAM
 * 7) chumby_stub jumps to chumby_boot
 * 8) chumby_boot checks for someone touching the screen
 * 9) chumby_boot sets up the LCD and draws a boot logo.
 * 10) chumby_boot waits 3 sec for the user to press a key to enter shell
 * 11) chumby_boot draws the appropriate "now booting" logo
 * 12) chumby_boot loads the Linux kernel from disk into DRAM
 * 13) chumby_boot sets up the Linux tags
 * 14) chumby_boot jumps to the Linux kernel

Code that's executed from OCRAM (namely chumby_stub) are limited to 32k of RAM. There is no such limitation for code executing from DRAM.

Loading a new kernel
If you've compiled a kernel, you can pull it out of arch/arm/boot/zImage, copy it to e.g. /mnt/storage, and install it by running (assuming you're booted into krnA): config_util --cmd=putblock --dev=/dev/mmcblk0p1 --block=krnA < /mnt/storage/zImage You'll know if you're in krnA because /proc/cmdline says "root=/dev/mmcblk0p2". You're in krnB if it says "root=/dev/mmcblk0p3". config_util --cmd=putblock --dev=/dev/mmcblk0p1 --block=krnB < /mnt/storage/zImage

If kernel symbols have changed, you'll need to replace kernel modules as well. Because of this, it may make sense to statically-link USB and network drivers, so that you won't need to worry about being unable to access peripherals.