Skip to content

Instantly share code, notes, and snippets.

@bodil
Created March 16, 2015 23:52
Show Gist options
  • Save bodil/b14a398189e5643ee03e to your computer and use it in GitHub Desktop.
Save bodil/b14a398189e5643ee03e to your computer and use it in GitHub Desktop.

How to put a GNU/Linux installation on your Chromebook

DISCLAIMER: This could all quite plausibly brick your Chromebook, and I take no responsibility for any damage you might inflict on it or yourself. Follow along at your own risk.

Most Chromebooks can run some flavour of GNU/Linux using the Chrubuntu method, running off the kernel that comes with ChromeOS. I found, however, that the ChromeOS kernel didn’t play well with recent X.org versions, and would refuse to recover from suspend, and not deal very well at all with having an external screen attached to it.

I also wanted to replace ChromeOS entirely with Arch on my Chromebook, because only 16 gigabytes of eMMC isn’t very convenient for dual booting. To accomplish this, I needed an external installation medium.

First of all, you’ll need to get your Chromebook into developer mode if you haven’t already. This is model specific, although for most recent models holding the Escape and Reload keys while booting should do the trick. If not, ask Google.

Making a bootable USB drive

You’ll need to be able to boot into a system that isn’t running off the internal eMMC drive in order to rewrite it. We’ll be making a USB drive with ChromeOS on it for this purpose.

Follow the instructions here to accomplish this. I recommend you also install some flavour of Chrubuntu on it, or you’ll have to somehow get a build environment sufficient to compile a Linux kernel onto your ChromeOS installation on your own. I recommend installing Arch, as it provides the vboot-utils package that you’ll need for building the kernel image, but you should be able to compile this from source on any system.

Boot into your USB drive system by pressing Ctrl+U at the firmware screen.

Building a kernel

The ChromeOS firmware looks for disk partitions of type 7f00 (“ChromeOS kernel”), and generally picks the partition with the highest priority as the boot partition. This partition should contain a signed bootable kernel image, which you can make from a compiled kernel, a bootloader and the appropriate signing keys.

You’ll need to install the VBoot tools first. You can get the source from Google:

$ git clone https://chromium.googlesource.com/chromiumos/platform/vboot_reference

If you’re on Arch with AUR set up, you can just install the vboot-utils package instead. This is what I did, so building it from source is left as an exercise for the reader. Either way, at the end you should have the vbutil_kernel command available, and you should have the developer keys installed somewhere, which I’ll assume to be /usr/share/vboot/devkeys.

Next, you need to build the bootloader. Check out the repo from Google:

$ git clone http://git.chromium.org/chromiumos/third_party/bootstub.git

Compiling it should be straightforward. It comes with a plain makefile, and if you’re not cross-compiling you should invoke it like this:

$ make PREFIX=""

This should result in a file called bootstub.efi. This is your bootloader; put it somewhere you can find it.

Next, compile your kernel. Ideally, you should use your Chromebook’s original kernel config as a starting point. It’ll be at /proc/config.gz when running ChromeOS or a Chrubuntu setup. Just gunzip that, copy it to .config in your kernel tree, and do make oldconfig or something.

Make a file called config.txt containing the kernel command line you want to use. Whatever you’re using for Chrubuntu should work, just make sure you get your root filesystem right.

Now, to get from a kernel image to a signed kernel with bootloader, run this from the root of your kernel tree, adjusting for devkeys and bootstub locations, and arch, as appropriate.

$ vbutil_kernel --pack ./new_kern.bin --keyblock /usr/share/vboot/devkeys/kernel.keyblock --signprivate /usr/share/vboot/devkeys/kernel_data_key.vbprivk --version 1 --config ./config.txt --vmlinuz ./arch/x86/boot/bzImage --bootloader /usr/src/bootstub/bootstub.efi

This should produce the file new_kern.bin, which is your bootable kernel partition image. You can just dd this directly onto your kernel partition.

You relly, really want to test this on a system running off a USB drive before trusting your internal drive with your new kernel. On a Chrubuntu install, pull out cgdisk and examine the partition table: the Chrubuntu kernel partition should be the one labelled KERN-C. Simply dd if=./new_kern.bin of=/dev/whatever-it-is and reboot (remembering to make modules_install first). If that doesn’t brick your Chrubuntu, it should be safe for use on your internal drive too.

Partitioning your internal drive

First, figure out what your internal drive is called. Mine is /dev/mmcblk0, although it could also be something like /dev/sda. If in doubt, boot ChromeOS on it and run rootdev -s -d in a shell. This should print the name of the device. I’ll assume it’s /dev/mmcblk0 from here on; substitute accordingly.

I used cgdisk to make the partitions, but you could also use the cgpt tool that comes with the VBoot package. You’ll need cgpt to set the boot partition priority in either case.

Running cgdisk /dev/mmcblk0 should show you the current list of partitions. You’ll need to keep the R/W firmware partition (I’m assuming). It should be labeled as such (“RWFW”), and it’s partition 11 on my computer, but this may vary. cgdisk reported it as the first partition in physical order. You’ll want to keep this, but delete the rest.

Create two kernel partitions, each with a size of 16Mb, and type 7f00 (“ChromeOS kernel”). Label the first one KERN-A, and the second KERN-B.

Partition your system as you please otherwise. I just made one big root partition, but you might want a swap partition as well if you can spare the disk space. I made my root partition of type 7f01 (“ChromeOS root”), but I don’t think this is necessary with a custom kernel.

You’ll have to update your config.txt file with the correct root partition and rebuild the kernel boot image, then dd it onto both of your kernel partitions. Keep the KERN-B partition as a known working backup, and put your updated kernels only on KERN-A from now on.

In order to tell the firmware to boot off KERN-A, run the following command (assuming KERN-A is partition number 1, otherwise adjust the -i parameter accordingly):

$ cgpt add -i 1 -S 1 -P 5 /dev/mmcblk0

Now, install your system on the rest of the disk as you like - I just mounted my root filesystem, extracted an Arch base tarball into it, and went with the regular Arch install process from there, but you could also use debootstral to install any Debian based system, etc. Make sure you don’t install Grub or any other kind of bootloader in the process, you don’t need any of those.

Reboot and hope for the best. If it doesn’t work, don’t panic, you’ve still got your USB drive to figure it out. Worst case, you can use a ChromeOS recovery image to get your ChromeOS back.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment