We want to make as few modifications to the upstream kernel as possible, ideally none. U-Boot Both ARM and recent x86 devices use U-Boot as their bootloader. On x86 we use Coreboot to set up RAM and load U-Boot. You can find an overview of the verified boot process in the. U-Boot still uses the EFI partition table described below. This consists of 440 bytes of real-mode code, 6 ignored bytes, 4 instances of 16-byte primary partition records, and 2 signature bytes, 0x55 and 0xAA. BIOS copies this block into RAM and starts executing the first byte. This all happens in x86 Real Mode. It searches the four partition table entries, finds a partition flagged as bootable, copies the first 512 bytes from that partition the so-called Volume Boot Record or VBR into RAM, and jumps there. That code then continues the boot process in some unspecified way -- typically that VBR code as well as the MBR code is generated by and installed by grub, lilo, syslinux, or some similar bootloader. After the zeropage table is filled in, a pointer to it is placed in the ESI register and execution continues with the first part of the kernel. At this point, the CPU is still running in Real Mode. The first part of the kernel then switches to protected mode and jumps to the kernel's 32-bit entry point, passing along the pointer to the zeropage table. Legacy BIOSes will continue to boot Chromium OS from the MBR. The Chromium OS build process places GPT-aware boot sector code from syslinux in the MBR. That code can specify one GPT partition to boot, indentified by a matching UniquePartitionGUID field in the Partition Entry Array. We use partition 12 for this purpose. We have a tool and scripts that can change the boot partition GUID in the MBR when we need to select an alternate boot path. Virtualized systems vmware, qemu, etc. While not enthusiastically embraced by the Linux kernel developers, it offers some advantages over legacy BIOS and is becoming more widely used, especially for 64-bit x86 systems. Each GPT partition is identified by two GUIDs: a type and a unique ID. The bootloader queries the BIOS for system information using a set of registered function calls and creates the zeropage table for the kernel. It then locates the kernel, tells the BIOS that it can free any memory that won't be needed later, switches down to 32-bit mode, and jumps to the kernel at the kernel's 32-bit protected-mode entry point the same place where the legacy Real Mode code used to jump to. It is possible to also install a 32-bit bootloader in the same partition, but we currently do not do that. To change the boot partition, we just need to edit the grub. Note that different EFI BIOSes may have different requirements for the pathname of the bootloader. Instead of a separate bootloader and kernel, there is one binary blob contained in its own GPT partition. That blob is cryptographically signed and the signature is verified before booting. There should be two image A and image B. Attribute bits within each partition table entry select which of the two is the most recent or valid one. Following that is the 32-bit part of the kernel, a few data structures, and our bootloader stub. BIOS verifies the signature, loads the rest of kernel stuff into memory, and invokes the bootloader stub. It sets up any tables the kernel needs in order to continue booting, and jumps to the kernel's 32-bit entry point. The Chromium OS build process creates signed kernel images needed by the Chrome OS BIOS and installs them in their own partitions. They are signed with test keys that are found in the source tree. Official releases will of course be signed with private Google keys. For any booting x86 configuration, there are at least three separate kernels along with their command lines on the disk image. Legacy BIOS will use syslinux, which uses its own copy of the chosen kernel that's kept in partition 12. ChromeOS BIOS uses the signed kernel embedded in its own partition. Our build and update process is carefully crafted to try to keep all three of these kernels in sync. However, if you're fiddling with the kernel and commandline, you may find that your changes are being ignored. This is usually an indication that you're modifying the wrong one. These identify which method the kernel used to boot and that's all they do - we don't use them for any run-time decisions AFAIK. Drive contents Bootable Chromium OS drives removable or not share a common drive format. Although the UEFI specs allow for disk sectors of other sizes, in practice 512 bytes is the norm. We do not use the old Cylinder-Head-Sector addresses at all. Protective master boot record The master boot record is the first sector on the hard drive LBA 0. As mentioned above, legacy BIOSes will boot from this sector. To protect the GUID partitions on the drive from legacy OSes, the MBR partition table normally contains a single partition entry of type 0xEE, filling the entire drive. GUID Partition Table GPT The second sector LBA 1 contains the primary GPT header, followed immediately by 16K 32 sectors of the primary GUID Partition Entry Array. In conformance with the EFI spec, another copy of these data should be located at the end of the disk as well, with the secondary GPT header in the last accessible sector and the secondary GUID Partition Entry Array immediately preceding it. Drive partitions GPT allows a large number of partitions on a drive. In an attempt to reduce the effect that later partitioning changes might have on deployed systems, we are trying to enumerate the known partitions first, while leaving room for future growth. There are rare cases where a third partition could help us avoid recovery mode AU in progress + random corruption on boot partition + system crash. We decided it's not worth the space in V1, but that may change. Same reasons as above. Note that the reserved partitions will actually be present on the image, so that the partition numbering remains constant from now on. Each minimal-size partition including the C kernel and C rootfs is only 512 bytes, and is shoved into some space lost to filesystem alignment between the primary partition table and the stateful partition. Bootable USB keys have the same layout, except that kernel B and rootfs B are minimal-size, and partition 1 is limited to 720M. The total USB image size is around 1. When the USB image is installed on a fixed drive, the B image is duplicated from the A image, and partition 1 is made as large as possible so that the entire disk is in use. The exact sizes and layouts are managed by a json file. See the page for more information. Partition types Each GPT Partition Entry contains a PartitionTypeGUID to identify the purpose of the partition, a UniquePartitionGUID which is specific to an individual partition on an individual drive, a PartitionName not the same as the filesystem's label, and apparently unused by the Linux kernel or userspace , and some Attributes bits that the Chrome OS BIOS will use to select the bootable image. There are several standard PartitionTypeGUIDs. Type GUID Linux data standard ebd0a0a2-b9e5-4433-87c0-68b6b72699c7 EFI System Partition standard c12a7328-f81f-11d2-ba4b-00a0c93ec93b ChromeOS kernel fe3a2a5d-4f32-41a7-b725-accc3285a309 ChromeOS rootfs 3cb8e202-3b7e-47dd-8a3c-7ff2a13cfcec ChromeOS firmware cab6e88e-abf3-4102-a07a-d4bb9be3c1d3 ChromeOS future use 2e0a753d-9e48-43b0-8337-b15192cb1b5e Partition names At various times, Linux has used a number of means to refer to disk partitions. Typically using the UUID notation requires starting udev in an initramfs, which takes extra time. This must be specified in the bootloader config file. The Chrome OS BIOS and bootstub passes an additional argument on the kernel command line: Partition alignment The filesystem and kernel partitions are all 2MB aligned and sized. However, in the future we may move down to 1MB to be in sync with what other are doing. Layout on disk The physical layout of the partitions does not have to match their order in the partition table. In fact, there are reasons why it might be advantageous that it doesn't. For example it may be necessary to resize some partitions, which is made much easier with certain physical layouts. Refer to the document for details. Once the firmware has been validated, we will continue the boot process by reading the kernel from the disk. Trusting the GPT It is not possible to sign the GPT using public key encryption. The contents of the GPT in particular, the partition-dependent attributes fields for the kernel GPT entries will change as autoupdate applies updates and devices reboot and attempt to use newly updated partitions. Since the GPT is not signed and thus cannot be trusted, all firmware or software that accesses the GPT must pass security review. Firmware needs to sanity-check all GPT values before using them. Most forms of corrupted or damaged partition tables will just cause the firmware to read a portion of the drive that doesn't contain a valid kernel signature header, in which case the firmware initiates recovery mode. Selecting the kernel There are at least two kernel partitions, to support autoupdate and accidental corruption. Each kernel partition is paired with a rootfs partition; kernel A should only boot rootfs A, kernel B should only boot rootfs B, etc. This allows using more exotic filesystems for rootfs in the future. The kernel is verified using a single signature header; rootfs uses a more complex block-based algorithm. The GPT Partition Entry contains a 64-bit Attributes field. Bits 48-63 are available for use by a partition of any given type. Used only when the Successful Boot Flag is 0. Since it has higher priority than the active kernel, it will be attempted next boot. This was a kernel that failed its last boot try. We can edit the other attribute fields manually if we need to change the primary boot partition. The kernel blob consists of the 32-bit part of the Linux kernel, a config file just the kernel command line string at the moment , a mostly-complete zeropage table, and our bootloader stub to complete the transition from BIOS to kernel. Once the verification is complete, the bootloader stub is invoked, which finishes initializing the params table and jumps to the kernel. Quick development Developers may want to do a rapid turnaround of the kernel only. This suggested procedure may help: 1. Install some image onto the hard disk. It should boot the kernel from partition 4 and mount the rootfs from partition 5, but it could also use partitions 2 and 3, respectively. Check this from a console by running 4. Build the new kernel using emerge-x86-generic kernel or similar. You'll need the bzImage aka vmlinuz file to create the signed kernel partition image. You'll also need a config. The full path to the key file is required, of course. Then verify things look OK:.