Back to post index

Installing stock Debian on the Samsung ARM Chromebook
Tags: [debian] [chromebook] [arm]
Published: 07 Jun 2014 09:34

Post Summary

This post explains how to install Debian wheezy onto an SD card for use with the Samsung ARM Chromebook (model number XE303C12), and how to compile Linux 3.15-rc7 so that the Chromebook boots with a (mostly) stock Linux kernel.


Table of contents:


Motivation

An ARM Chromebook running stock Linux would be a great travel workstation:

Unfortunately, it is not straight forward to boot stock Debian with a stock Linux kernel on this device. It does not have a standard BIOS or bootloader.

This post explains how I set up my Chromebook. At the end, you should have a (mostly) stock Linux kernel booting a stock Debian distribution:

However, there are still some things that do not work (more on that later).

Process summary

See https://github.com/jmpesp/debian-on-arm-chromebook for each of the linked scripts here.

Warning

Be careful, these scripts are dangerous to run if you don’t know what you’re doing. Be sure to check that the device targets and mount points are sane for your setup.

Preparing the Chromebook

First, I followed the instructions at the debian.org ARMChromebook page.

Specifically:

The Chromebook will boot from a SD card.

Setting up the SD card

Partitioning

The following script 00-partition-sd-card.sh sets up the SD card partitions:

#!/bin/bash

# On a Linux workstation

DEV=/dev/sdb
MNT=/mnt

set -x

# Zero out current partition table
dd if=/dev/zero of=${DEV} bs=512 count=1

# Partitioning the device:
parted --script ${DEV} mklabel gpt

cgpt create ${DEV}

cgpt boot -p ${DEV}

# from https://plus.google.com/+OlofJohansson/posts/bQpzEGG15G8
#
# Partition 1: Kernel partition, regular Chrome OS kernel for whatever need you might have (i.e. same as previous instructions)
# Partition 2: Another kernel partition with nv-u-boot on it at higher priority
# Partition 3: Ext2 filesystem for /boot (important, should be ext2)
# Partition 4: rootfs for Linux, ext4 or whatever you prefer
# plus:
# Partition 5: home partition, encrypted

# cgpt expects 512-byte blocks:
let "max=`blockdev --getsz ${DEV}`"

let "offs=512"
let "size=1280"
cgpt add -b ${offs} -s ${size} -t kernel -P 2 -S 1 -l CHROMEOS ${DEV}

let "offs = offs + size"
let "size=128000"
cgpt add -b ${offs} -s ${size} -t kernel -P 3 -S 0 -T 10 -l NVUBOOT ${DEV}

let "offs = offs + size"
let "size=1280000"
# size = 625 MiB
# >>> 1280000.0 * 512 / 1024 / 1024
# 625.0
cgpt add -b ${offs} -s ${size} -t rootfs -P 1 -S 1 -l BOOT ${DEV}

let "offs = offs + size"
let "size = (max - offs) / 4"
cgpt add -b ${offs} -s ${size} -t rootfs -P 1 -S 1 -l ROOT ${DEV}

let "offs = offs + size"
let "size = max - offs - 1024"
cgpt add -b ${offs} -s ${size} -t rootfs -P 1 -S 1 -l HOME ${DEV}

cgpt show ${DEV}

exit 0

Be sure to edit this script by changing the following lines:

DEV=/dev/sdb

As root, plug in your SD card and run 00-partition-sd-card.sh.

A tool like gparted will display the partition layout of the SD card visually.

The reason for this partition layout is that the nv-uboot (non-verifying UBoot) that Google supplies expects this partition layout, according to https://plus.google.com/+OlofJohansson/posts/bQpzEGG15G8

Installing the bootloader

Download nv_uboot-snow-simplefb.kpart from http://www.chromium.org/chromium-os/u-boot-porting-guide/using-nv-u-boot-on-the-samsung-arm-chromebook :

wget -O - http://commondatastorage.googleapis.com/chromeos-localmirror/distfiles/nv_uboot-snow-simplefb.kpart.bz2 | bunzip2 > nv_uboot-snow-simplefb.kpart

The bootloader should be written to partition 2. From your Linux workstation, run 01-install-bootloader.sh as root:

#!/bin/bash

# On a Linux workstation

DEV=/dev/sdb

set -x

dd if=nv_uboot-snow-simplefb.kpart of=${DEV}2

exit 0

Remember again to modify the DEV variable!

Creating other filesystems

Three of the other partitions hold target filesystems:

The reason that /home is separated is that I encrypted this partition. I did this because being a travel workstation, the probability of loss or theft is higher than a normal workstation. I want to have the peace of mind that comes with not worrying what a theft could mean for my data.

Running 02-create-filesystems.sh as root creates the filesystems:

#!/bin/bash

# On a Linux workstation

DEV=/dev/sdb

set -x

blockdev --rereadpt ${DEV}

# BOOT: /boot
mkfs.ext2 ${DEV}3

# ROOT: /, where debian root goes
mkfs.ext4 ${DEV}4

# HOME: luks encrypt
cryptsetup luksFormat ${DEV}5

exit 0

Remember again to modify the DEV variable!

If the following is seen:

+ mkfs.ext2 /dev/sdb3
mke2fs 1.42.10 (18-May-2014)
mkfs.ext2: Device size reported to be zero.  Invalid partition specified, or
        partition table wasn't reread after running fdisk, due to
        a modified partition being busy and in use.  You may need to reboot
        to re-read your partition table.

then remove and insert your SD card and try again. If that doesn’t work, you might need to write zeroes to the whole SD card and try again. This happened to me when I used my USB SD card reader and writing zeroes to the whole SD card worked for me.

debootstrap Debian wheezy

This is a two stage Debian bootstrap:

The commands are simple. First, as root, run 03-debootstrap-stage-1.sh to start the first debootstrap stage targeting wheezy:

#!/bin/bash

# On a Linux workstation

DEV=/dev/sdb
MNT=/mnt

set -x

# mount ROOT (/), and debootstrap into it
mount ${DEV}4 ${MNT}

debootstrap --arch=armhf --foreign wheezy ${MNT} ftp://ftp.ca.debian.org/debian

umount ${MNT}

exit 0

Next, on the Chromebook, boot into ChromeOS and switch over to the root shell with Ctrl-Alt-F2 (right arrow on esc row). This will only be possible if the Chromebook was switched into developer mode. Connect the Chromebook to the internet, change into /usr/local/, and then save and run 04-debootstrap-stage-2.sh:

#!/bin/bash

# On the Chromebook

DEV=/dev/mmcblk1
MNT=/mnt

# Chroot into the SD card, and perform the second debootstrap stage

umount ${DEV}p[1-5]

mount ${DEV}p4 ${MNT}
[[ ${?} -eq 0 ]] || exit 1;

# Bind the following special filesystems for use in the chroot
mount --bind /dev/ ${MNT}/dev/
[[ ${?} -eq 0 ]] || exit 1;
mount --bind /proc/ ${MNT}/proc/
[[ ${?} -eq 0 ]] || exit 1;
mount --bind /sys/ ${MNT}/sys/
[[ ${?} -eq 0 ]] || exit 1;

chroot ${MNT} /debootstrap/debootstrap --second-stage
[[ ${?} -eq 0 ]] || exit 1;

# Setup /etc/fstab for the two unencrypted partitions

cat > ${MNT}/etc/fstab <<EOF
${DEV}p4 / ext4 errors=remount-ro 0 1
${DEV}p3 /boot/ ext2 errors=remount-ro 0 1
EOF

# Populate the /etc/apt/sources.list with target = wheezy

cat > ${MNT}/etc/apt/sources.list <<EOF
deb http://ftp.ca.debian.org/debian wheezy main non-free contrib
deb-src http://ftp.ca.debian.org/debian wheezy main non-free contrib
EOF

# Update the packages

chroot ${MNT} apt-get update
[[ ${?} -eq 0 ]] || exit 1;

chroot ${MNT} apt-get upgrade
[[ ${?} -eq 0 ]] || exit 1;

# Install useful packages
chroot ${MNT} apt-get install wpasupplicant iw upower cryptsetup

echo "yourhostname" > ${MNT}/etc/hostname

# Set the root password
passwd

# Copy over built-in wireless firmware
mkdir ${MNT}/lib/firmware/mrvl/
cp /lib/firmware/mrvl/* ${MNT}/lib/firmware/mrvl/

umount ${MNT}/dev/
umount ${MNT}/proc/
umount ${MNT}/sys/
umount ${MNT}

exit 0

I chose tal as a hostname.

The Debian distribution is now installed onto the SD card - test with

chroot ${MNT}

to get into the bash shell.

Compiling the Chromebook’s Linux kernel

Set up cross compilation toolchain

I used crosstool-ng with the following configuration:

Paths and misc options  --->
(${HOME}/dl) Local tarballs directory
Target options  --->
    Target Architecture (arm)  --->
(v7) Suffix to the arch-part
    Endianness: (Little endian)  --->
    Bitness: (32-bit)  --->
    Floating point: (hardware (FPU))  --->
Operating System  --->
    Target OS (linux)  --->
    Linux kernel version (3.12)  --->

Download and compile Linux 3.15-rc7

Get the Linux kernel source from The Linux Kernel Archives. Linux 3.15-rc7 is available at the time of this article’s writing.

$ gpg --verify linux-3.15-rc7.tar.sign
gpg: Signature made Sun 25 May 2014 07:08:30 PM EDT using RSA key ID 00411886
gpg: Good signature from "Linus Torvalds <torvalds@linux-foundation.org>"
gpg: WARNING: This key is not certified with a trusted signature!
gpg:          There is no indication that the signature belongs to the owner.
Primary key fingerprint: ABAF 11C6 5A29 70B1 30AB  E3C4 79BE 3E43 0041 1886

From within the linux-3.15-rc7 directory created from un-tarring linux-3.15-rc7.tar.xz, call 05-make-kernel-config.sh.

#!/bin/bash

export PATH="${HOME}/x-tools/armv7-unknown-linux-gnueabi/bin/:${PATH}"

# from http://www.gentoo.org/proj/en/base/embedded/handbook/?part=1&chap=4
#
# ARCH            ?= arm
# CROSS_COMPILE   ?= arm-unknown-linux-gnu-

export ARCH=arm
export CROSS_COMPILE=armv7-unknown-linux-gnueabi-

makeopts="ARCH=${ARCH} CROSS_COMPILE=${CROSS_COMPILE}"

set -x
make ${makeopts} clean distclean mrproper
rc=${?}
set +x

if [[ ${rc} -ne 0 ]];
then
    echo "make clean distclean returned ${rc}!";
    exit ${rc};
fi;

set -x
make ${makeopts} exynos_defconfig
rc=${?}
set +x

if [[ ${rc} -ne 0 ]];
then
    echo "make exynos_defconfig returned ${rc}!";
    exit ${rc};
fi;

exit 0;

Patching the kernel for built-in wireless support

I needed to apply the following patches from https://github.com/virtualopensystems/linux-kvm-arm/ for the built-in wireless networking to work:

Grab 06-built-in-wireless.patch and :

patch -p0 < 06-built-in-wireless.patch

Kernel configuration

This was the tricky part for me. Until the Chromebook worked, I had never booted successfully from a Linux kernel I compiled myself.

My process for figuring out which configuration options to choose involved every modification to the kernel configuration being saved into config_good, which was versioned with git. I used the iFixit teardown of the Chromebook as a reference for the components on the motherboard, and found those in the kernel configuration file.

This seemed strange - why wasn’t there a program that would look at my system and select the appropriate kernel configuration options? Turns out that there is:

`make localmodconfig`

Before making this blog post, I had a working Chromebook with Debian on it. So, I scp’ed the linux-3.15-rc7.tar.xz over to the Chromebook, and performed the localmodconfig to get a .config file for the Chromebook automatically! But it didn’t work.

Here are the menuconfig options I changed:

General setup  --->
    [*] Control Group support  --->

CPU Power Management  --->
    CPU Frequency scaling  --->
        [*] CPU Frequency scaling
              Default CPUFreq governor (ondemand)  --->
        <*>   'powersave' governor
    CPU Idle  --->
        [*] CPU idle PM support

[*] Networking support  --->
    -*-   Wireless  --->
        <*>   cfg80211 - wireless configuration API
        [*]     cfg80211 wireless extensions compatibility
        <*>   Generic IEEE 802.11 Networking Stack (mac80211)

Device Drivers  --->
    [*] Network device support  --->
        [*]   Wireless LAN  --->
            <*>   Marvell WiFi-Ex Driver
            <*>     Marvell WiFi-Ex Driver for SD8786/SD8787/SD8797/SD8897
    Character devices  --->
        <*> EXYNOS HW random number generator support
    [*] Power supply class support  --->
        <*>   SBS Compliant gas gauge
        <*>   TPS65090 battery charger driver
        [*]   Board level reset or power off  --->
            [*]   GPIO power-off driver
        [*]   Restart power-off driver
    Graphics support  --->
        [*] Backlight & LCD device support  --->
            <M>     Backlight Driver for ADP8860/ADP8861/ADP8863 using WLED
            <M>     Backlight Driver for ADP8870 using WLED
            <M>     Backlight Driver for LM3630A
            <M>     Backlight Driver for LM3639
            <M>     Backlight driver for TI LP855X
            <M>     Generic GPIO based Backlight Driver
            <M>     Sanyo LV5207LP Backlight
            <M>     Rohm BD6107 Backlight
    [*] Real Time Clock  --->
        <*>   Maxim MAX77686
    [*] Pulse-Width Modulation (PWM) Support  --->
        <*>   Samsung PWM support

-*- Cryptographic API  --->
    <*>   XTS support
    <*>   AES cipher algorithms (ARM-asm)

Using 07-chromebook-kernel-config.patch:

cp .config config_good
patch -p0 < 07-chromebook-kernel-config.patch
cp config_good .config

Then, run 08-build-kernel-and-modules.sh:

#!/bin/bash

export PATH="${HOME}/x-tools/armv7-unknown-linux-gnueabi/bin/:${PATH}"

# from http://www.gentoo.org/proj/en/base/embedded/handbook/?part=1&chap=4
#
# ARCH            ?= arm
# CROSS_COMPILE   ?= arm-unknown-linux-gnu-

export ARCH=arm
export CROSS_COMPILE=armv7-unknown-linux-gnueabi-

makeopts="ARCH=${ARCH} CROSS_COMPILE=${CROSS_COMPILE}"

set -x
make ${makeopts} uImage dtbs -j5
rc=${?}
set +x

if [[ ${rc} -ne 0 ]];
then
    echo "make returned ${rc}!";
    exit ${rc};
fi;

# make modules

make -j5

mkdir dist/
make modules_install INSTALL_MOD_PATH=${PWD}/dist/

exit 0;

As root, install the new kernel uImage and dtb exynos5250-snow.dtb to your SD card with 09-install-kernel-and-modules.sh:

#!/bin/bash

# On a Linux workstation

DEV=/dev/sdb
MNT=/mnt

set -x

# Mount / and /boot/, then copy over compiled kernel and modules

mount ${DEV}4 ${MNT}
mount ${DEV}3 ${MNT}/boot/

cp arch/arm/boot/uImage arch/arm/boot/dts/exynos5250-snow.dtb ${MNT}/boot/

rm -rf ${MNT}/lib/modules/*

rsync -avAX dist/ ${MNT}/

umount ${MNT}/boot/
umount ${MNT}

exit 0

If the cross-compilation toolchain is correct, then the Chromebook should boot into Linux 3.15-rc7 without trouble:

If not,

If all that doesn’t help, then I recommend either asking questions in #debian-arm on irc.oftc.net, or email me at jwm @ this domain and I will try to help.

A note about UBoot environment variables

If Linux will not boot, check the UBoot environment variables.

After pressing Ctrl-u, hold space to stop UBoot’s booting process. This drops you into a shell, where you can use commands like printenv and setenv to view and modify environment variables.

nv_uboot-snow-simplefb ships with different environment variables than the non-simplefb version also available from Google. Before using the simplefb version, I used the non-simplefb version. At some point, I must have modified the non-simplefb version’s environment variables and then executed saveenv, saving these to some internal flash.

I had problems until I installed nv_uboot-snow-simplefb and reset the saved environment to what ships with nv_uboot-snow-simplefb:

env default -f
saveenv

Final steps

Encrypting the home partition

No regular user has been created yet. Before creating your day-to-day user id, set up the encrypted home partition.

As root:

cryptsetup luksOpen /dev/mmcblk1p5 sdenc
mkfs.ext4 /dev/mapper/sdenc
mount /dev/mapper/sdenc /home/

After this you can add a regular user with the adduser command.

To close the encrypted home partition:

umount /home/
cryptsetup luksClose sdenc

I wrapped the creation and closing of the home partition into two bash scripts.

extra packages

apt-get install openbox tint2 iceweasel
apt-get install xterm
apt-get install xcompmgr
apt-get install vim
apt-get install ntp
apt-get install build-essential

configuring a better touchpad

I modified 10-synaptics-chromebook.conf from the ChromeOS partition.

Summary

What works

What doesn’t work

Acknowledgements

Thanks to Aardvark and hrw on #debian-arm for answering my questions and helping me debug problems.