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<newline>...
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:
- The boot rom examines the OCOTP fuses and determines it needs to boot from MBR
- The first 2048 bytes of the SD card are examined, and the boot image is located
- sdram_prep, clocks, power, and chumby_stub are all loaded from a Bootstream image into OCRAM
- sdram_pre, clocks, and power are all executed to set up registers and DRAM
- chumby_stub is executed
- chumby_stub loads chumby_boot from disk into DRAM
- chumby_stub jumps to chumby_boot
- chumby_boot checks for someone touching the screen
- chumby_boot sets up the LCD and draws a boot logo.
- chumby_boot waits 3 sec for the user to press a key to enter shell
- chumby_boot draws the appropriate "now booting" logo
- chumby_boot loads the Linux kernel from disk into DRAM
- chumby_boot sets up the Linux tags
- 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.