Use a mainline U-Boot and non-signed kernels on Exynos Chromebooks

In a previous post, I explained how to boot a mainline Linux Kernel to use a standard distribution on a Samsung Chromebook by installing it in the unused KERN-C and ROOT-C partitions of the internal eMMC. The kernel binary was contained in a signed FIT image since the read-only vendor bootloader can only boot signed images.

The Many Ways to Boot Linux

This is only one of the approaches that can be used to boot a mainline kernel. Another technique is to boot a signed u-boot image instead of a kernel, this process is called chain loading since the bootloader loads another bootloader rather than an operating system kernel. Non-signed kernels can be booted by chain loading a signed u-boot; this makes development easier and is more aligned with the development process on ARM platforms that don’t require verified boot.

Another option would be to replace the stock vendor bootloader by disabling the SPI flash write protection and flash a mainline u-boot as explained in this Ach Linux forum thread. However, this is not recommended since flashing the wrong u-boot can brick the device, while keeping the read-only bootloader enables the ability to recover if things go wrong.

One final method this post will explain is installing a mainline u-boot, kernel and a Linux distribution in an external MMC/uSD card which is much safer since the internal eMMC that contains the stock ChromeOS doesn’t have to be modified.

For brevity, this article assumes you’ve already read the previous post because it  won’t cover background information about the Chromebook boot process, verified boot, and ChromeOS disk partition layout. It is highly recommended that you read the previous article if you are not already familiar with these concepts.

Enable Developer Mode to Boot From External Media

To boot the Chromebook from  external media, developer mode must be enabled.  Developer mode also gives access to a root shell which is needed for installation. The ChromiumOS wiki has instructions to enable developer mode for both Snow and Peach Pi/Pit.

Once the Chromebook is in developer mode, booting from external media must be enabled. This can be done by executing the following command in the ChromeOS root shell:

$ crossystem dev_boot_usb=1

Prepare the uSD Card

The first step is to format the SD card with a partition layout that meets the Chromebook’s boot process expectations. Create a GPT partition table using the fdisk utility:

$ sudo fdisk /dev/mmcblk0

Use the g command to create a new empty GPT partition table and then the w command to write the table to disk and exit.

The Chromebook boot process relies on custom attributes in the GPT table, so the next step is to use the cgpt tool to create the partitions. Use the following script to create 3 partitions to store u-boot, boot files (kernel, device tree, etc), and the root filesystem.


BOOT=1 # MiB
KERN=50 # MiB

# calculate partitions start sector and sizes
BOOT_SZ=$(($BOOT * 1024 * 2))
KERN_SZ=$(($KERN * 1024 * 2))

SGPT_START=$(cgpt show $DISK | grep "Sec GPT table" | awk '{print $1}')


# create partitions
cgpt add -t kernel -l uboot -b $BOOT_START -s $BOOT_SZ -S 1 -T 1 -P 15 $DISK
cgpt add -t data -l boot -b $KERN_START -s $KERN_SZ $DISK
cgpt add -t data -l rootfs -b $ROOT_START -s $ROOT_SZ $DISK

# inform the kernel about partition table changes
partprobe $DISK

# format the boot and rootfs partitions
mkfs.ext4 -L boot ${DISK}p2
mkfs.ext4 -L rootfs ${DISK}p3

The script takes the block device that will be used  as a parameter, and it must be run as root. Assuming the script is called, this is the command to execute:

$ sudo ./ /dev/mmcblk0

You can use cgpt show to make sure the partitioning was correctly completed:

$ sudo cgpt show /dev/mmcblk0

Build and Install U-boot

The next step is to build u-boot from source; clone the repo and checkout the latest tag, at the time of this article’s publication, the latest version is 2016.01:

$ git clone git://
$ cd u-boot
$ git checkout v2016.01

For each board u-boot supports, there is a default configuration available. For example, the default configuration for the Exynos5250 Snow and Exynos5420 Peach Pit Chromebooks are snow_defconfig and peach-pit_defconfig respectively.

For this post I’ll build a u-boot and kernel for the Exynos5800 Peach Pi, so peach-pi_defconfig will be used:

$ export CROSS_COMPILE="ccache arm-linux-gnueabihf-" ARCH=arm
$ make peach-pi_defconfig
$ make

Once the u-boot binary has been compiled, the next step is to generate a uImage that contains it. U-boot images have a header that contains the load and entry point addresses for the binary in the uImage payload, among other things. This should be set to the address of CONFIG_SYS_TEXT_BASE: the address against which u-boot is linked.

The address is platform or board dependent so the value has to be checked for the specific Chromebook. For the Exynos5800 Peach Pi:

$ git grep CONFIG_SYS_TEXT_BASE include/configs/peach-pi.h
include/configs/peach-pi.h:#define CONFIG_SYS_TEXT_BASE 0x23E00000

However, the Exynos5250 Snow (and in fact all Exynos5250 boards) has a different address:

$ git grep CONFIG_SYS_TEXT_BASE include/configs/exynos5250-common.h
include/configs/exynos5250-common.h:#define CONFIG_SYS_TEXT_BASE                0x43E00000

The mkimage tool is used to create a uImage for the u-boot binary and the correct load and entry addresses must be passed:

$ mkimage -A arm -O linux -T kernel -C none -e 0x23E00000 -a 0x23E00000 -d u-boot-dtb.bin uboot.img

Now, the uImage needs to be be signed so the verified boot will be able to load and execute it. Use the vbutil_kernel utility to sign the image:

$ echo 'Dummy configuration' >  /tmp/config 
$ vbutil_kernel --pack uboot.kpart --keyblock /usr/share/vboot/devkeys/kernel.keyblock --signprivate /usr/share/vboot/devkeys/kernel_data_key.vbprivk --version 1 --arch arm --config /tmp/config --vmlinuz uboot.img

The signed image in this example is uboot.kpart, and it must be flashed to the partition that has the highest priority attribute because the bootloader will try to get a signed image from there:

$ sudo dd if=uboot.kpart of=/dev/mmcblk0p1 bs=1M

Build and Install the Kernel

The next step is to build the Linux Kernel. At the time of this writing, the last version is v4.4 so download this version:

$ wget -c
$ xz -d linux-4.4.tar.xz
$ tar -xf linux-4.4.tar

Now configure it using the Exynos default configuration, and build the kernel and device tree binaries:

$ cd linux-4.4
$ export CROSS_COMPILE="ccache arm-linux-gnueabihf-" ARCH=arm
$ make exynos_defconfig
$ make -j4 zImage exynos5800-peach-pi.dtb

Mount the SD boot and rootfs partitions, and copy the kernel image and Exynos5800 Peach Pi DTB:

$ sudo mount /dev/mmcblk0p2 /media/boot
$ sudo cp arch/arm/boot/{zImage,dts/exynos5800-peach-pi.dtb} /media/boot

Install a Rootfs

Download an ARMv7 rootfs to install in the SD card. For example you can download a tarball from the Arch Linux distribution:

$ wget -c
$ sudo mount /dev/mmcblk0p3 /media/rootfs
$ sudo tar -zxvf ArchLinuxARM-peach-latest.tar.gz -C /media/rootfs
$ sudo umount /media/rootfs

Add a Boot Loader Spec File

Each board u-boot supports has a set of custom default boot commands and environment variables. This makes it challenging for distributions to have a standard image that can be used on different boards since each one has its own default configuration about where to fetch the kernel and dtb, the partition that’s as a root, etc.

Fortunately there has been some work to standardize the default boot commands and this effort is known as the u-boot distro commands. Basically, these are a set of standard commands and variables that can be used to search for bootable media and read a configuration files instead of having hardcoded values as defaults.

The configuration file follows mostly what is specified in the Freedesktop’s BootLoaderSpec. The u-boot documentation has a README.distro file that explains the distro commands in detail.

Copy the following BootLoaderSpec config file to the boot partition in a extlinux directory so the distro commands can fetch the kernel image and DTB that are stored in the boot partition:

DEFAULT primary
MENU TITLE Peach Pi MMC boot options
LABEL primary
      MENU LABEL v4.4 mainline kernel
      LINUX ../zImage
      FDT ../exynos5800-peach-pi.dtb
      APPEND console=tty root=/dev/mmcblk1p3 rw rootwait
$ sudo mkdir /media/boot/extlinux
$ sudo cp extlinux.conf /media/boot/extlinux
$ sudo umount /media/boot

The file has a single entry that specifies the path from which Linux and the DTB have to be loaded as well as the command line options that need to be appended to the bootargs variable so the kernel can use the rootfs partition as the root mount point.

The distro commands search for bootable partitions so mark the boot partition as bootable using the fdisk utility:

$ sudo fdisk /dev/mmcblk0

Use the x command to access to the extra functionality menu, then use the A command to toggle the legacy BIOS bootable flag and choose the boot partition number (2).

Next, press r to return to the main menu, and finally the w command to write the table to disk and exit.

Enjoy Mainline U-boot and Linux on your Chromebook

At this point the Chromebook should be able to boot both the mainline u-boot and Linux kernel. Insert the uSD card in the Chromebook and hit Ctrl + u, the mainline u-boot should be booted and the “Peach Pi MMC boot options” displayed for 20 seconds until the menu timeouts and the default entry “v4.4 mainline kernel” is used.

More boot options can be added by having different entries in the extlinux.conf file. This is very useful to test kernels during development but keep one that is known to work to make sure that the machine will always boot.

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.

7 thoughts on “Use a mainline U-Boot and non-signed kernels on Exynos Chromebooks”

  1. I am using vboot-utils on Arch Linux Arm on a snow chomebook (i.e. no chromeos). How do I make/get devkeys so I can run this command “vbutil_kernel –pack uboot.kpart –keyblock /usr/share/vboot/devkeys/kernel.keyblock –signprivate /usr/share/vboot/devkeys/kernel_data_key.vbprivk –version 1 –arch arm –config /tmp/config –vmlinuz uboot.img”

    1. Hello Michael,

      Sorry for not answering before. Probably you already know the answer by now but there should be a vboot-kernel-utils (or named similar) package in arch that contains the vbutil_kernel utility and developer keys to sign images. I’m not an Arch user but these are certainly packaged in other distros (i.e: Debian and Fedora).

  2. Another question, is there any reason I shouldn’t compile uboot on my chromebook itself. I compiles just fine but I can’t test it (see above). I’m using GCC 5.3.0. More info –

    Target: armv7l-unknown-linux-gnueabihf
    Configured with: /build/gcc/src/gcc-5-20160209/configure –prefix=/usr –libdir=/usr/lib –libexecdir=/usr/lib –mandir=/usr/share/man –infodir=/usr/share/info –with-bugurl= –enable-languages=c,c++,fortran,go,lto,objc,obj-c++ –enable-shared –enable-threads=posix –with-system-zlib –with-isl –enable-__cxa_atexit –disable-libunwind-exceptions –enable-clocale=gnu –disable-libstdcxx-pch –disable-libssp –enable-gnu-unique-object –enable-linker-build-id –enable-lto –enable-plugin –enable-install-libiberty –with-linker-hash-style=gnu –enable-gnu-indirect-function –disable-multilib –disable-werror –enable-checking=release –host=armv7l-unknown-linux-gnueabihf –build=armv7l-unknown-linux-gnueabihf –with-arch=armv7-a –with-float=hard –with-fpu=vfpv3-d16

    Thanks for the great post, sorry I didn’t mention in first time round – I was too obsessed with trying to get mainline uboot running! Something I have been trying for ages without success. Now if you wouldn’t mind explaining how to add the appropriate blobs so I can flash mainline uboot to the RO flash… ;) only joking… but I do really like to break things so maybe just PM me :)

    1. Hello Michael,

      I’m glad that you liked the post.

      No, there is no reason why you shouldn’t compile u-boot natively in the target platform. I always cross-compile because I find it easy for self contained projects like U-boot or Linux that doesn’t have external dependencies.

      About flashing U-boot, I don’t really recommend it since you can chain load a non-verified u-boot so the user experience is the same but you can keep the original verified u-boot in case things go wrong. That way the device will never be bricked.

      But if you really want to do it, then you need to remove the screw that is the SPI flash write protection, and the use flashrom to disable write protection and flash the u-boot to the SPI.

      There are many articles that explain the process, for example:

  3. Helo Javier,
    I followed your guide and installed everything. u-boot doesn’t boot kernel but instead write error message: ** Invalid partition 12 **
    Do you have any idea what is wrong and why u-boot want partition 12, or how can that be changed in the u-boot source. (I searched net but can’t find anything usefull about problem)
    I can boot linux from external and internal mmc following your previous post (guide)

    1. Hello Milan,

      The problem is that you seem to have previous default environment variables stored and have a boot command that tries to load from a partition 12.

      You can fix this by resetting the environment vars to the default and store that instead to overwrite the old ones.

      From the u-boot prompt execute the following commands:

      # env default -a
      # saveenv
      # boot

  4. Hi Javier,

    Thanks for your replies, and thanks again for the post as I have finally got mainline uboot on my chromebook :)

    You were right about the devkeys – I downloaded vboot-kernel-utils debian package and use the ones in there. The Arch Linux vboot package does not include the keys, and the vboot it provides also requires –bootloader to be passed as an option. This can just point to an empty file just like you do with –config .

Comments are closed.