Codentium

On the topic of low-level programming.

Gentoo on the Chromebook (part I)

These are generalised instructions that can be used to get Gentoo up and running on the ARM Chromebooks, such as the Samsung Chromebook XE303C12 (snow), Samsung Chromebook XE503C32 (peach pi) and the Acer Chromebook CB5-311-T28J (nyan-big). Even though these instructions are mostly targeted at the ARM Chromebooks, they can be used for x86 Chromebooks as well, by simply downloading the stage3 tarball for x86-64 instead.

Developer mode

In order to get access to a shell, we'll have to switch the device to developer mode:

  • Turn off the laptop.
  • Whilst holding the Escape and the Refresh key, poke the Power key to invoke recovery mode.
  • Once the recovery screen appears, press the Control and D keys.
  • Confirm switching to developer mode by pressing the Enter key. The laptop will now reboot and prepare the system for developer mode. This process will take about ten to twenty minutes.

If all went well, developer mode should now be enabled. In order to boot ChromeOS, you'll now have to press the Control and D keys to confirm that you want to boot from the SSD.

Verification

The boot process of Chromebooks is somewhat more complicated than the boot process of x86 devices (BIOS and UEFI), and ARM devices (u-boot). Similar to these devices, some Chromebooks do use the same firmware and boot loaders, but in a more extensive fashion. Despite the fact that there are still some legacy Chromebooks that use a BIOS for x86, and u-boot for ARM, Coreboot seems to be the firmware of choice for most of the Chromebooks, including the Chromebooks based on the Venice 2 board with the Nvidia Tegra K1 (Tegra124).

One of Google's major considerations during the design of the boot process has been the concern of trust. When booting up the Chromebook, the first component that will be turned on is the CPU. The CPU will then load and execute the various boot loader stages that have been burnt into the ROM accompanying the CPU. The goal of these boot loader stages is to initiate certain parts of the CPU, and load the firmware from the ROM that has been soldered onto the motherboard. This ROM is split up into a read-only section and a read-write section, where the prior verifies the latter before loading and executing it. For most Chromebooks, this ROM will contain Coreboot, as well as some payload such as Depthcharge, or u-boot in the case of older Chromebooks. This payload will then determine what kernel to boot from the disk by inspecting the GPT partitions. Once a kernel has been chosen, it will be verified and loaded by the payload.

The verification process is part of the verified boot (vboot) specification and implementation. This process mostly relies on cryptography, where a private and a public key are used for signing (encrypting the kernel) and verification (decrypting the kernel) respectively. Fortunately, this verification process can be disabled, in which case the developer keys can be used to sign your own kernel images.

Let's disable this verification process:

  • Boot into ChromeOS and log into a session.
  • In the Chrome browser, while holding the Ctrl and Alt keys, press the T key to open up a crosh shell.
  • Type 'shell' to get into a bash shell.
  • Type 'sudo su' to become root.
  • Type 'crossystem dev_boot_usb=1 dev_boot_signed_only=0' to enable booting from external media, and to disable the boot verification process.
  • Reboot the system to allow the changes to take effect.

After the changes have taken effect, it should now be possible to boot from external media using the Ctrl + U keys.

Acquiring a kernel

There are two ways to acquire a kernel. The easy way is to use the kernel from the ChromeOS kernel partition and sign it using the developer keys. The more complicated way is to build one from the ChromiumOS kernel repository or the ChromiumOS kernel-next repository, but with the additional benefit that you can configure the kernel to your liking, and that you won't have to rely on ChromeOS any longer. We'll discuss this option in another journal entry.

In order to sign the kernel, we'll have to use vbutil_kernel. In case of an existing kernel, we can specify where to find that kernel (e.g. /dev/mmcblk0p4, which is the kernel B partition). Furthermore, vbutil_kernel allows us to embed a command line into the signed image to pass to the kernel. As an example, we'll sign an existing kernel that uses /dev/sda2 as the root partition:

echo "console=tty1 debug verbose root=/dev/sda2 rootfstype=ext4 rootwait rw lsm.module_locking=0" > kernel-config
vbutil_kernel \
	--oldblob /dev/mmcblk0p4 \
	--keyblock /usr/share/vboot/devkeys/kernel.keyblock \
	--signprivate /usr/share/vboot/devkeys/kernel_data_key.vbprivk \
	--arch arm \
	--version 1 \
	--config kernel-config \
	--repack kernel.kpart

The above will get us a kernel.kpart, that we can write to our kernel partition, once we have set up the partition lay-out.

Partition lay-out

At minimum, we'll only need a kernel partition and a rootfs partition. First, we'll reserve 64 kiB for the kernel partition using parted and cgpt. Then we'll write the kernel to this partition using dd:

parted /dev/sda mklabel gpt
cgpt create -z /dev/sda
cgpt create /dev/sda
export OFFSET=$(expr 8 \* 1024)
export SIZE=$(expr 64 \* 1024)
cgpt add -i 1 -t kernel -b $OFFSET -s $SIZE -l kernel -S 1 -T 5 -P 10 /dev/sda
dd if=kernel.kpart of=/dev/sda1

After the kernel partition has been set up, we'll reserve the remaining storage space for the root filesystem using gdisk:

  • Run "gdisk /dev/sda".
  • Press the N key to create a new partition.
  • Press the Enter key to use the default offset, default size and the default type.
  • Press the W key to the save the changes onto the disk.

Once the changes have been saved, we can format the partition as an Ext4-filesystem:

mkfs.ext4 /dev/sda2

Finally, we can mount the partition, and install the root filesystem and the Portage package manager by downloading and extracting the stage3 and Portage tarballs respectively. Furthermore, we'll also need the kernel modules:

mkdir -p /mnt/gentoo
mount /dev/sda2 /mnt/gentoo
wget -O - http://distfiles.gentoo.org/releases/arm/autobuilds/$(wget -O - http://distfiles.gentoo.org/releases/arm/autobuilds/latest-stage3-armv7a_hardfp.txt 2>/dev/zero | tail -n1) | tar xjp -C /mnt/gentoo/
wget -O - http://distfiles.gentoo.org/releases/snapshots/current/portage-latest.tar.bz2 | tar xjp -C /mnt/gentoo/usr/
cp -ax /lib/modules/ /mnt/gentoo/lib/modules
umount /mnt/gentoo

It should now be possible to boot Gentoo from your Chromebook. In the next part we'll be looking at the specific hardware components and what we'll need to get them to work.