How to Install a Linux Mainline Kernel and Distro on Exynos Chromebooks

Over the last year I spent some time improving the mainline support for the Exynos based Chromebooks. This blog post explains how to install a Linux mainline kernel and distribution on these machines. The first half covers some background information that explains what needs to be done to the Chromebook to make this happen, and the second half is a step-by-step guide to complete the process.

A Bit of Background Information

Chromebooks use a fairly unique boot system to improve reliability during upgrades and provide better hardware security. This makes the process of installing a different Linux distro on the device a bit more challenging than most consumer devices.

ChromeOS Verified Boot

Chromebooks use a technique called verified boot (vboot) to ensure all binaries are safe to be executed. The Chromebook comes with firmware (a vendor u-boot in the case of Samsung Chromebooks) that has vboot support and is composed of a read-only and a read / write part. The firmware expects a signed Flattened Image Tree (FIT) image to load.

For ChromeOS, this FIT image contains a kernel image and a Flattened Device Tree (FDT). But it can also contain a u-boot image which should be able to load and execute non-signed kernels. This process of making an u-boot to load another u-boot instead of a kernel is known as u-boot chain loading.

Google provides the keys that allow developers to sign their own binaries by using the vbutil_kernel tool, but Chromebooks can only boot binaries signed with this key when are in developer mode. In normal mode, they can only boot binaries signed by the vendor.

ChromeOS disk partition layout and special GPT flags

Bootable media for Chromebooks require a GUID Partition Table (GPT). This is because the GUID Partition Entry Array has an Attributes field in which some bits are reserved to be used by partitions of any given type.

The “ChromeOS kernel” partition type has the following attribute flags stored in these bits:

  • Priority: the order in which the firmware needs to look for a kernel.
  • Tries: the number of times the firmware should try booting from this.
  • Successful: this partition is known to be a good one so the tries flag is omitted.

These flags can be modified using the cgpt tool that is a GPT manipulation util that has support for the ChromeOS extensions.

More information about the ChromeOS disk format, its custom partition types and flags can be found in the ChromiumOS wiki.

ChromeOS boot process

The Chromebook firmware tries to load a FIT image from the partition with the highest priority by reading the GPT priority flags for each partition. Priority is a 4-bit flag so the maximum priority is 15 and the minimum is 1. A priority of 0 means that the partition is not bootable. The firmware tries to boot the number of times specified in the tries flag and each time it fails, decrements that field until is 0 and gives up and tries to boot the partition with the next highest priority.

If a partition with higher priority is marked as successful equal to 1, the firmware will omit the tries and will always try to boot that partition. Which means that if the kernel in that partition does not boot, the machine won’t boot again and will need to be recovered. So it is always a good idea to first mark as successful equal to 0 and only mark the partition as successful equal to 1 once it was verified that the kernel booted correctly. This is exactly what ChromeOS does and why that flag exists in the first place.

Step-by-Step Process

There are many approaches to install a mainline kernel and a Linux distro using the stock firmware and so not voiding the warranty. In this post I will walk you through the installation of a v4.2 kernel and a Fedora root filesystem into partitions of the internal eMMC and use a signed FIT image format that is the one expected by the Chromebook stock firmware. With this method, both Fedora and ChromeOS can be available for boot by changing the partition’s boot priority.

Other options include chain loading a mainline u-boot or installing the Linux distro and the mainline kernel into a removable media but those can be explained in following posts.The commands in this post are to install a Fedora root filesystem and a v4.2 kernel on an Exynos5250 Snow (Chromebook1) and an Exynos5800 Peach Pi (Chromebook2) but the process is general enough that can be used for most ARM based Chromebooks.

Prerequisites

To follow this article, an ARMv7 hard float toolchain is needed and also the mkimage and vbutil_kernel tools. How to install these will depend on your Linux distribution so follow the installation instructions of your distribution to install them.

Enable Developer Mode

Self-signed FIT images can only be booted when the machine is in developer mode so the first step is to enable developer mode on the Chromebook. Additionally, Developer mode also gives access to a root shell that is needed for this installation. The ChromiumOS wiki has instructions to enable developer mode for both Snow and Peach Pi/Pit.

WARNING: Enabling developer mode will wipe your user data.

Resize the KERN-C and ROOT-C Partitions

ChromeOS has an interesting partition scheme that consists of 2 rootfs and 2 kernel partitions, but only one pair is active at any time. When ChromeOS is updated, the new rootfs and kernel are written to the inactive partitions. Then, the priorities are changed and the machine is rebooted. Next, the new kernel is booted and is only checked once to see if it boots correctly. After a successful boot, the new kernel partition is marked as boot successful and the old partitions becomes inactive. With this method, there is always a pair that is known to be good that can be used to roll back if something goes wrong as a result of the update.

This is possible because ROOT-{A,B} are mounted as read-only and all the writable user data is in a different partition labeled as STATE and mounted in /mnt/stateful_partition. However, there is a third pair of partitions that are not used and have a size of 1 sector. These can be used to install a custom kernel and rootfs without affecting ChromeOS, but first these need to be resized by stealing some space from the STATE partition.

You can check the partition layout by using the cgpt tool. For example in the Peach Pi:

$ cgpt show /dev/mmcblk0
       start        size    part  contents
           0           1          PMBR (Boot GUID: C266F3D7-E926-804A-8F56-E72CBC05DA74)
           1           1          Pri GPT header
           2          32          Pri GPT table
     8671232    21295104       1  Label: "STATE"
                                  Type: Linux data
                                  UUID: AC4A5003-545B-4043-8219-15F694CC1CC9
       20480       32768       2  Label: "KERN-A"
                                  Type: ChromeOS kernel
                                  UUID: A03E3AF2-9574-2C4C-BEF3-AB0B649762DC
                                  Attr: priority=2 tries=0 successful=1
     4476928     4194304       3  Label: "ROOT-A"
                                  Type: ChromeOS rootfs
                                  UUID: DC780C9F-FF94-D94B-8AEB-62353E729098
       53248       32768       4  Label: "KERN-B"
                                  Type: ChromeOS kernel
                                  UUID: DBBFEE45-6901-D549-B2F6-B6829866C261
                                  Attr: priority=1 tries=0 successful=1
      282624     4194304       5  Label: "ROOT-B"
                                  Type: ChromeOS rootfs
                                  UUID: 731A33FC-1572-2F41-8845-1194F5ADA02F
       16448           1       6  Label: "KERN-C"
                                  Type: ChromeOS kernel
                                  UUID: B8E72E60-117E-C240-9029-9A3688C85C23
                                  Attr: priority=0 tries=15 successful=0
       16449           1       7  Label: "ROOT-C"
                                  Type: ChromeOS rootfs
                                  UUID: 4C839F5B-4AD6-C445-A360-8E1373483A2D
       86016       32768       8  Label: "OEM"
                                  Type: Linux data
                                  UUID: 2A6A70FA-E16A-594D-9FBA-5EAEBF1DA5CC
       16450           1       9  Label: "reserved"
                                  Type: ChromeOS reserved
                                  UUID: BD1BF5DD-0BCB-C34A-B631-AF6BBDF1303F
       16451           1      10  Label: "reserved"
                                  Type: ChromeOS reserved
                                  UUID: F5C21B54-6EB8-BE47-B23F-B4D8561334E6
          64       16384      11  Label: "RWFW"
                                  Type: ChromeOS firmware
                                  UUID: 6A046A26-B8E3-2340-A5E1-D2700AEEF3B6
      249856       32768      12  Label: "EFI-SYSTEM"
                                  Type: EFI System Partition
                                  UUID: C266F3D7-E926-804A-8F56-E72CBC05DA74
    30535647          32          Sec GPT table
    30535679           1          Sec GPT header

The partition sizes are in 512 byte disk sectors. So the STATE partition size in the ChromeOS of my Peach Pi is 21295105 sectors (a little less than 10 GiB). This partition size can be reduced so 10 MiB can be taken for KERN-C and 8 GiB for ROOT-C.

Save the script in the Chromebook and execute it. It will resize the partitions, update the GPT table and reboot.

WARNING: running this script will wipe all the data in your user partition!

#!/bin/sh

KERN=10 # MiB
ROOT=8 # GiB
DISK=$(rootdev -d -s)

# calculate partitions sizes
KERN_C_SZ=$(($KERN * 1024 * 2))
ROOT_C_SZ=$(($ROOT * 1024 * 1024 * 2))
STATE_SZ=$(cgpt show -i 1 -n -s -q $DISK)
STATE_SZ=$(($STATE_SZ - $KERN_C_SZ - $ROOT_C_SZ))

# calculate partitions start sector
STATE_START=$(cgpt show -i 1 -n -b -q $DISK)
KERN_C_START=$(($STATE_START + $STATE_SZ))
ROOT_C_START=$(($KERN_C_START + KERN_C_SZ))

umount -A -l /dev/mmcblk0p1

# modify GPT table
cgpt add -i 1 -b $STATE_START -s $STATE_SZ -l STATE $DISK
cgpt add -i 6 -b $KERN_C_START -s $KERN_C_SZ -l KERN-C $DISK
cgpt add -i 7 -b $ROOT_C_START -s $ROOT_C_SZ -l ROOT-C $DISK

# destroy STATE partition to prevent startup script to erase using old size
STATE_SEEK=$(($STATE_START / 1024 / 2))
STATE_COUNT=$(($STATE_SZ / 1024 / 2))
dd if=/dev/zero of=$DISK bs=1048576 seek=$STATE_SEEK count=$STATE_COUNT

reboot

This script is based on commands from this ChromiumOS wiki page.

On boot, the startup script will create all the files in the stateful partition again. This will take considerable time and then the machine will reboot into ChromeOS.

Copy the Fedora root Filesystem to the ROOT-C Partition

The next step it to take an ARMv7 hard float Fedora image and copy it to a removable media since the stateful partition on the Chromebook most likely won’t have enough space for the image as most of the space is taken by ROOT-C.

$ wget -c http://ftp.cica.es/fedora/linux/releases/22/Images/armhfp/Fedora-Xfce-armhfp-22-3-sda.raw.xz
$ xz -d Fedora-Xfce-armhfp-22-3-sda.raw.xz
$ cp Fedora-Xfce-armhfp-22-3-sda.raw /media

Then, on the Chromebook check the partitions and offsets of the Fedora image:

$ fdisk -l Fedora-Xfce-armhfp-22-3-sda.raw
Disk Fedora-Xfce-armhfp-22-3-sda.raw: 4.4 GiB, 4743757824 bytes, 9265152 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disklabel type: dos
Disk identifier: 0xb970bb39

Device                           Boot   Start     End Sectors   Size Id Type
Fedora-Xfce-armhfp-22-3-sda.raw1         2048 1001471  999424   488M 83 Linux
Fedora-Xfce-armhfp-22-3-sda.raw2      1001472 2001953 1000482 488.5M 83 Linux
Fedora-Xfce-armhfp-22-3-sda.raw3      2001954 8837890 6835937   3.3G 83 Linux

The third partition is the rootfs, so associate a loop device with the file at the offset of the rootfs partition and do a raw copy to the ROOT-C partition. Since the size is in 512 bytes sector, multiply it to get the offset in bytes:

$ losetup /dev/loop1 Fedora-Xfce-armhfp-22-3-sda.raw -o $((2001954 * 512))
$ dd if=/dev/loop1 of=/dev/mmcblk0p7 bs=4M
$ losetup -d /dev/loop1

Build a Kernel and Copy to KERN-C Partition

Download the latest stable kernel (v4.2.1 at the time of this article):

$ wget -c https://www.kernel.org/pub/linux/kernel/v4.x/linux-4.2.1.tar.xz
$ xz -d linux-4.2.1.tar.xz
$ tar -xf linux-4.2.1.tar

Configure using the Exynos default configuration but enable the WiFi driver as a module since we are going to boot without an initramfs and the driver needs to load a firmware from the rootfs on probe. Enabling it as a module ensures its driver is probed after the rootfs containing the firmware is mounted.

$ cd linux-4.2.1
$ export CROSS_COMPILE="arm-linux-gnueabihf-" ARCH=arm
$ make exynos_defconfig
$ ./scripts/config --module CONFIG_MWIFIEX

Build the kernel image, modules and device trees:

$ make prepare modules_prepare
$ make -j4 bzImage modules dtbs

Install the modules in a removable media so these can be copied to the Fedora rootfs in the Chromebook:

$ make modules_install INSTALL_MOD_PATH=/media/

The next step is to create a signed FIT image so it can be copied to the KERN-C partition of the Chromebook eMMC. To create a FIT image, there is a need of a FIT source file that contains configurations, one or more kernel binaries and one or more FDT.

The following FIT source for example will add support for both Snow and Peach Pi in the same FIT image. The firmware has its own FDT blob with a compatible string so it picks the FDT that has a compatible string that matches the one in the firmware. That way the same FIT image can be used to boot either Snow or Peach Pi since each firmware will choose the correct FDT.

So create a kernel.its file with the following content:

/dts-v1/;

/ {
    description = "Chrome OS kernel image with one or more FDT blobs";
    #address-cells = <1>;
    images {
        kernel@1{
	    description = "kernel";
            data = /incbin/("arch/arm/boot/zImage");
            type = "kernel_noload";
            arch = "arm";
            os = "linux";
            compression = "none";
            load = <0>;
            entry = <0>;
        };
        fdt@1{
            description = "exynos5250-snow.dtb";
            data = /incbin/("arch/arm/boot/dts/exynos5250-snow.dtb");
            type = "flat_dt";
            arch = "arm";
            compression = "none";
            hash@1{
                algo = "sha1";
            };
        };
        fdt@2{
            description = "exynos5800-peach-pi.dtb";
            data = /incbin/("arch/arm/boot/dts/exynos5800-peach-pi.dtb");
            type = "flat_dt";
            arch = "arm";
            compression = "none";
            hash@1{
                algo = "sha1";
            };
        };
    };
    configurations {
        default = "conf@1";
        conf@1{
            kernel = "kernel@1";
            fdt = "fdt@1";
        };
        conf@2{
            kernel = "kernel@1";
            fdt = "fdt@2";
        };
    };
};

The FIT image has the kernel command line embedded on it so first create a config for it:

$ echo "console=tty0 root=/dev/mmcblk0p7 rootwait rw" > config.txt

Then create the FIT image and sign it:

$ mkimage -f kernel.its kernel.itb
$ vbutil_kernel --version 1 --arch arm --keyblock /usr/share/vboot/devkeys/kernel.keyblock --signprivate /usr/share/vboot/devkeys/kernel_data_key.vbprivk --vmlinuz kernel.itb --config config.txt --pack kernel.kpart

Copy the kernel.kpart to the removable media

$ cp kernel.kpart /media

On the Chromebook, mount the media device and the Fedora rootfs partitions, copy the modules to the rootfs and the kernel to the KERN-C partition:

$ mount /dev/mmcblk0p7 /tmp/fedora
$ cd /media
$ cp -R lib/modules /tmp/fedora/lib
$ dd if=kernel.kpart of=/dev/mmcblk0p6

Copy the cgpt binary to the Fedora rootfs so the ChromeOS kernel partition priority can be bumped from Fedora. There is a package for cgpt but it is still good to have the binary in case things go wrong and for example networking is not working to install the package.

$ cp /usr/bin/cgpt /tmp/fedora/usr/bin

Remove stale entries from Fedora’s /etc/fstab and only keep the entry for the root partition. This is how my fstab looks for example:

UUID=5c99cba3-b2ea-4b65-a39a-58b09cae5edf  / ext4    defaults,noatime 0 0

Finally unmount the Fedora rootfs partition:

$ umount /tmp/fedora

At this point the Fedora rootfs and the mainline kernel are installed but the Chromebook will still boot ChromeOS so bump KERN-C priority and set tries flag to 1 but leave successful to 0 until you are sure that the kernel can boot correctly:

$ cgpt add -i 6 -P 15 -T 1 -S 0 /dev/mmcblk0

Reboot, when the machine is booted again, it should boot the mainline kernel and should mount the Fedora partition as rootfs.

If everything goes well and the mainline kernel booted correctly, mark the boot as successful:

$ cgpt add -i 6 -P 15 -S 1 /dev/mmcblk0

Now the Chromebook should be able to boot either Fedora or ChromeOS. To boot ChromeOS again, just switch the priorities for both KERN-A and KERN-C partitions from Fedora:

$ cgpt add -i 2 -P 15 -S 1 /dev/mmcblk0
$ cgpt add -i 6 -P 1 -S 1 /dev/mmcblk0

And to boot again into Fedora, do the opposite from ChromeOS:

$ cgpt add -i 2 -P 1 -S 1 /dev/mmcblk0
$ cgpt add -i 6 -P 15 -S 1 /dev/mmcblk0

Enjoy Linux on Your Chromebook

This guide specifically outlines this process for Fedora, but you should be able to get just about any Linux distro running on your Exynos Chromebook using similar steps. If you encounter any differences for other distros, or have questions, feel free to post a comment.

Happy hacking!

Author: Javier Martinez

Javier Martinez Canillas was a Senior Linux Kernel Developer for the Samsung Open Source Group with a focus working on ARM and Exynos SoC support.

21 thoughts on “How to Install a Linux Mainline Kernel and Distro on Exynos Chromebooks”

  1. Thanks for your good material, but I got some questions in step-by-step processes,
    wish you could share some helps :)

    1. About ” Copy the Fedora root Filesystem to the ROOT-C Partition” step:
    Is there any way to setup mainline kernel with ChromeOS itself ?

    2. About “Build a Kernel and Copy to KERN-C Partition” step:
    As my hardware is Peach Pit, guess I should replace the “exynos5250-snow” with
    “exynos5420-peach-pit” in kernel.its file, is it right ?
    %s/exynos5250-snow/exynos5420-peach-pit/

    And I failed at vbutil_kernel step, note I move the mainline kernel into chroot env,
    the vbutil_kernel remind me that missing bootloader file,
    (cr) (20150918|REBASE-i 1/18) yakir@server ~/trunk/src/linux-next $ vbutil_kernel –version 1 –arch arm –keyblock /usr/share/vboot/devkeys/kernel.keyblock –signprivate /usr/share/vboot/devkeys/kernel_data_key.vbprivk –vmlinuz kernel.itb –config config.txt –pack kernel.kpart
    ERROR: Missing required bootloader file.

    1. Hello Yakir,

      We already talked in the mailing lists but I’ll answer your questions here for completeness and other people reference.

      1) Yes, you can copy any rootfs, the blog uses Fedora just as an example. I haven’t booted ChromeOS in a while but last time I tried about a year ago, it expected 3D HW acceleration to be working which is not supported in mainline and also the ChromiumOS tree has features (i.e: dark resume) that are not present in mainline and are used ChromeOS user-space programs.

      2) Yes, you have to use the exynos5420-peach-pit FDT for Peach Pit.

      I haven’t seen that vbutil_kernel error before but since you mentioned in the mainling list that were able to boot mainline in your Peach Pit and Snow, I assume you sorted it out.

      Best regards,
      Javier

  2. First of all great write up! I am trying to get a Chromebook 2 (peach pit – XE503C12) to boot mainline Linux. I already have it booting a custom 3.8 Chromium kernel but whenever I try mainline I just get a blank screen. Any ideas?

      1. Hello Andrew,

        Yes, the kernel.its in the article is an example to show how to have two Exynos Chromebooks (5250 Snow and 5800 Peach Pi) supported by a single FIT image. But you should use the correct Device Tree for your device. Glad that you figured out and have it working!

  3. Can you write a guide how to build & flash mainline uboot for the chromebooks?

    Also, is there any way to recover bricked chromebooks?

    1. Yes, I’ll write a guide on how to build and install a mainline u-boot for Chomebooks so it can be chain loaded from the verified boot firmware.

      You can always recover a Chromebook to its original factory state by reinstalling ChromeOS (more info at http://google.com/chromeos/recovery).

      Now if by bricked you mean that the write protection was removed and a broken bootloader was flashed in the originally read-only flash, then I’m afraid that I don’t know how that could be recovered.

      1. Thanks Javier! Chain loading uboot is a start. What I would like to do is to replace the original uboot on the SPI flash.

        As for debricking method then I could simply flash directly to the SPI via buspirate or something :)

      2. Hello Luka,

        Yes you could replace the original u-boot on the SPI flash but I wouldn’t recommend it since I don’t see the advantage while you risk to brick your device.

        If you find having to press Ctrl + d, waiting 30 secs or the beep annoying, you can change the Google Binary Block (GBB) flags and set GBB_FLAG_DEV_SCREEN_SHORT_DELAY.

        The arch wiki page has information on how to do it: https://wiki.archlinux.org/index.php/Chrome_OS_devices but you need to disable the flash write-protect for that.

        And yes, I guess that you could use buspirate or something to write to the SPI flash but I never tried it.

  4. You can fix the ” Missing required bootloader file” error by creating an empty file (eg dummy.txt) and passing –bootloader dummy.txt. This seems to vary depending on vbutil version use. I was using vboot tools from the Arch Linux alarm respository i think…

    Many thanks for the great article, I’d love to see one on mainline uboot! Explaining how to create an image to flash to the SPI would be awesome too cos I would love to finally get there after trying so many times… but I can totally see that it just isn’t worth it. At the moment I would just like to get mainline kernel on my snow again :)

    I flashed nv_uboot (without simplefb but, i think, without some fixes to the bootloader that have happened since then) to the SPI flash a long time ago and wasn’t ever able to get a mainline kernel to boot. I have only recently discovered that the ChromeOS recovery seemed to flash verified uboot again :) Clever google, wish I had tried it sooner. Arch linux package a mainline kernel for exynos chromebooks which did work for me but has broken with the latest release (just blank screen).

    Now I am uncertain again –
    Did the ChromeOS recovery give me the lastest, standard firmware? It says something about daisy-test during boot and so could it be developer firmware?? Maybe it picked up on the fact thatthe write-protection on the SPI was disabled?

    1. About the “ERROR: Missing required bootloader file.”, the dummy file must have at least one line, i.e. no touch dummy.txt, you need to:
      $ cat <dummy.txt

      EOF

      ;)

  5. I fixed that by booting form sd and using gpart to use unallocated space, so have the full 8gb available now.

  6. Hi

    running
    mkfs.ext4 /dev/mmcblk0p7
    before
    dd if=/dev/loop1 of=/dev/mmcblk0p7 bs=4M
    prepares the full 8gb file system.

    Not sure if I messed up the module bit of the tutorial, but there are very few modules available (no usb storage or bluetooth) on boot. Have a missed something?

    Once you have a working system, is it possible to build the kernel on the the system itself rather than cross compile?

    I’m not familiar with fedora but I had problems installing httpd, cpio error on install. I think that is related to SELinux setup.

  7. Thanks for this guide! with it I’ve managed to get a Vanilla 4.4 kernel up and running on an existing Chrubuntu OS install. (First gen Snow chromebook for what it’s worth)

    Unfortunately, I can’t get the audio to play back. Alsa sees a Snow-I2S-MAX98095 device and presents the mixer for it, but unlike on the older 3.8 series kernel, unmuting the “Left Speaker Mixer Left DAC1” and “Right Speaker Mixer Right DAC1” channels doesn’t seem to help.

    Does the audio work on your end, and if so did you have to do anything special to it?

    1. Hello,

      I’m glad that 4.4 worked for you.

      Yes, audio not working reliable on Snow and Peach boards is a known issue and hopefully will be fixed soon.

      1. Hello Javier,
        I installed Debian Jessie on the external SD card with vanila kernel 4.4 (with some tweaks) on C32 (Peach) and everything works without problem i.e. audio, wifi, camera, USB, brigtness control, suspend, touchpad with double taps (no nedd to press lower corners, what I find iritating). It works so good that I now think to use it as main work device but I have to learn how to install Mali driver (kernel and X11). Although it works quite well even without Mali drivers (but I will try to install if I found time).
        BTW, thank you for your article which is really clearly written and helped me a lot to install Linux on this quite fine piece of hardware.

  8. So, six months on and still no DAISY / peach sound device in main line kernels (at least on Arch 4.6.3). A regression against kernel 3.8.
    Is it still the plan that this “hopefully will be fixed soon”? Any more definite time scales?

    1. Hello Jonathan,

      Unfortunately there isn’t a time scale for this. I spent some time to get sound working properly but it seems that’s not trivial.

      Keep in mind that the 3.8 kernel that is shipped in the Chromebooks and mainline are two completely different things, so this is not a regression against 3.8 but rather a missing functionality in the Daisy/Peachs upstream support.

Comments are closed.