Architectures/ARM/Chromebook

From FedoraProject

Jump to: navigation, search

Contents

ARM Chromebooks

There's currently a number of ARM (currently all are ARMv7) based Chromebooks base on a few specific SoCs.

They are:

Samsung Exynos:

  • Snow (Exynos 5240)
  • Peach-pit CB2 (Exynos 5800, 1080p, microSD)
  • Peach-pi CB2 (Exynos 5420)

https://www.chromium.org/chromium-os/developer-information-for-chrome-os-devices/samsung-chromebook-2

NVIDIA Tegra K1:

  • Acer nyan-big (1080p HD version, and non-HD variant)
  • HP nyan-blaze (discontinued)

Rockchips:

  • Asus flip
  • Asus c201p - (RK3288 - 2GiB / 4GiB memory - 16GB eMMC - microSD slot - Mali T764 - 1366 x 768 - 3.14 factory kernel)

Preparing Fedora

Start by downloading your Fedora, here we use the XFCE variant, but you can choose another at the download site:

http://download.fedoraproject.org/pub/fedora/linux/releases/23/Images/armhfp/

$ cd /var/tmp

$ wget http://download.fedoraproject.org/pub/fedora/linux/releases/23/Images/armhfp/Fedora-Xfce-armhfp-23-10-sda.raw.xz

$ unxz -v Fedora-Xfce-armhfp-23-10-sda.raw.xz


Next you mount the raw disk image, and extract the rootfs. (Note the loop devices in the output)

$ sudo kpartx -av /var/tmp/Fedora-Xfce-armhfp-23-10-sda.raw

$ sudo dd if=/dev/mapper/loop0p3 of=/var/tmp/Fedora-23-Xfce-rootfs.ext4 conv=fsync status=progress

$ sudo kpartx -d /var/tmp/Fedora-Xfce-armhfp-23-10-sda.raw


At this point you may optionally shrink ext4 rootfs. (It will be expanded in a later step)

$ sudo e2fsck -f /var/tmp/Fedora-23-Xfce-rootfs.ext4

$ sudo resize2fs -fM /var/tmp/Fedora-23-Xfce-rootfs.ext4


Label the rootfs, and apply a new UUID

$ UUID=$(uuidgen)

$ sudo tune2fs -U "$UUID" -L "ROOTFS" /var/tmp/Fedora-23-Xfce-rootfs.ext4


Create the partitions (Note: You may want to change the size of boot and swap partitions.)

$ truncate --size=7GiB /var/tmp/chromebook-xfce.raw

$ sgdisk -a 8192 -n 1:0:+24M -t 1:7F00 -c 1:"KERN-A" -A 1:=:0x011F000000000000 \
                 -n 2:0:+24M -t 2:7F00 -c 2:"KERN-B" -A 2:=:0x011A000000000000 \
                 -n 3:0:+1G  -t 3:8300 -c 3:"BOOT"                             \
                 -n 4:0:+1G  -t 4:8200 -c 4:"SWAP"                             \
                 -n 5:0:0    -t 5:8300 -c 5:"ROOTFS" /var/tmp/chromebook-xfce.raw


Write the Xfce rootfs to the partition.

$ sudo kpartx -avg /var/tmp/chromebook-xfce.raw

$ sudo dd if=/var/tmp/Fedora-23-Xfce-rootfs.ext4 of=/dev/mapper/loop0p5 bs=2M conv=fsync status=progress

$ sudo e2fsck -fy /dev/mapper/loop0p5

$ sudo resize2fs -f /dev/mapper/loop0p5


Setup the swap device

$ UUID_SWAP=$(uuidgen)
$ sudo mkswap -U "$UUID_SWAP" -L 'SWAP' /dev/mapper/loop0p4


Setup the Fedora boot partition

$ UUID_BOOT=$(uuidgen)
$ sudo mkfs.ext4 -m0 -U "$UUID_BOOT" -L 'BOOT' /dev/mapper/loop0p3


Mount the filesystems

$ sudo mount /dev/mapper/loop0p5 /mnt

$ sudo mount /dev/mapper/loop0p3 /mnt/boot

Configure the filesystem table

su -c "cat <<-EOF > /mnt/etc/fstab
UUID=$UUID / ext4 defaults 1 1
UUID=$UUID_SWAP swap swap defaults 0 0
UUID=$UUID_BOOT /boot ext4 defaults 0 2
EOF"


Optionally chroot into the mounted rootfs. You may want to make configuration changes, or install packages. (Note: this requires you be operating from an ARMv7 system already) You should also remove x from the /etc/passwd file for the root user, that will allow us to fall into emergency shell if required.

$ sudo chroot /mnt bash

# dnf download vboot-utils

# vim /etc/passwd

# exit


Dis-mount the filesystems and teardown the loop device

$ sudo umount --recursive /mnt

$ sudo kpartx -dvg /var/tmp/chromebook-xfce.raw


Write the Fedora image to your SDcard (Note: for example purpose the fictional sdcard device is "/dev/sdz", and it will most certainly be different for you)

$ sudo dd if=/var/tmp/chromebook-xfce.raw of=/dev/sdz bs=2M conv=fsync

$ sudo partprobe /dev/sdz


Move the GPT backup header to the end of storage, expand the ROOTFS partition, and grow the rootfs within.

$ sudo sgdisk -a8192 -e -d5 -n5:0:0 -t5:8300 -c5:'ROOTFS' -p /dev/sdz

$ sudo e2fsck -f /dev/sdz5

$ sudo resize2fs /dev/sdz5

From within ChromeOS

  • Enable developer mode by simultaneously pressing 'POWER + REFRESH + ESC'
  • In the boot recovery screen press 'CTRL + D'
  • After an arbitrary amount of time passes you will reboot into developer mode
  • To boot into ChromeOS, Press 'CTRL + D' (or wait 30 seconds)
  • [Optionally, wait for ChromeOS to update it's kernel before proceeding.]
  • Once you have login to ChromeOS, open the terminal by pressing 'CTRL + ALT + T'
  • From the terminal, get root by typing 'shell' and then 'sudo -i'
  • Insert the prepared Fedora sdcard into the chromebook.


Re-pack the ChromeOS kernel

# cd /media/removable/BOOT/

# dd if=/dev/mmcblk0p2 of=/tmp/kern-a.blob conv=fsync

# eval $(blkid -o export /dev/mmcblk1p5)

# cat <<-EOF > /media/removable/BOOT/kcmdline
console=tty1 debug verbose root=PARTUUID=${PARTUUID} rootwait rw lsm.module_locking=0
EOF

##alg='4' # rsa2048sign/sha256sum
##alg='8' # rsa4096sign/sha512sum
##len=$((1<<(10+(alg/3))))

## Create RSA key pair.
# openssl genrsa -F4 -out fedora_2048.pem 2048

## Create self-signed certificate
# openssl req -batch -new -x509 -key fedora_2048.pem -out fedora_2048.crt

## Generate pre-processed RSA public key
# dumpRSAPublicKey -cert fedora_2048.crt > fedora_2048.keyb

## Wrap the public key
# vbutil_key      --pack fedora.vbpubk          --key fedora_2048.keyb --algorithm 4 --version 1

## Wrap the private key
# vbutil_key      --pack fedora.vbprivk         --key fedora_2048.pem  --algorithm 4

## Remove intermediate files
# rm -f fedora_2048.{pem,crt,keyb}

## Checksum the key block and give all flags
# vbutil_keyblock --pack fedora.keyblock --datapubkey fedora.vbpubk  --flags 15


# vbutil_kernel --oldblob     /tmp/kern-a.blob \
                --repack      /media/removable/BOOT/chromeos-kernel.img \
                --config      /media/removable/BOOT/kcmdline \
                --keyblock    /media/removable/BOOT/fedora.keyblock \
                --signprivate /media/removable/BOOT/fedora.vbprivk \
                --arch arm --version 1

## OR, use existing key block (not recommended)

# vbutil_kernel --oldblob     /tmp/kern-a.blob \
                --repack      /media/removable/BOOT/chromeos-kernel.img \
                --config      /media/removable/BOOT/kcmdline \
                --keyblock    /usr/share/vboot/devkeys/kernel.keyblock \
                --signprivate /usr/share/vboot/devkeys/kernel_data_key.vbprivk \
                --arch arm --version 1


# vbutil_kernel --verbose --verify /media/removable/BOOT/chromeos-kernel.img
. . .

# dd if=/media/removable/BOOT/chromeos-kernel.img of=/dev/mmcblk1p1 
# dd if=/media/removable/BOOT/chromeos-kernel.img of=/dev/mmcblk1p2 

Copy the firmware and kernel modules to the sdcard

# cp -r /lib/modules/*  /media/removable/ROOTFS/lib/modules/.

# cp -r /lib/firmware/* /media/removable/ROOTFS/lib/firmware/.

Enable USB boot

# crossystem dev_boot_usb=1

Booting Fedora

  • At the boot screen press 'CTRL + U'
  • The kernel partition with the highest priority will boot.
  • Using the ChromeOS kernel with Fedora user-space can sometimes be challenging, you may encounter problems.
  • If you're lucky you will boot into Xfce, and have wifi


Known issues

  • The output of lsmod is empty, no kernel modules loaded. Usually indicates the ChromeOS kernel booted without 'lsm.module_locking=0' You can verify the kernel cmdline, or rebuild the kernel without CONFIG_CHROMEOS_SECUIRTY.
  • systemd emergency mode, and /boot not mounted. A byproduct of some weird kernel security in the ChromeOS kernel. Simply 'mount /dev/mmcblk1p4 /boot' and exit the emergency shell.
  • wifi not working. Did you copy over the ChromeOS modules and firmware correctly? The Marvel mwifiex driver is a loadable module and it also loads a firmware blob.
  • Graphics not working. The ChromeOS kernel usually have a working frame buffer, verify your X11 configs in /etc/X11/. But if you have more serious problems or if you simply prefer console mode, you can repack your kernel with cmdline option 'systemd.unit=multi-user.target' or from inside Fedora by 'systemctl set-default multi-user.target
  • SElinux, Auditing, control groups, name spaces... systemd is not happy when modern Linux features are disabled, as they are in the ChromeOS kernels.


Rebuilding ChromeOS vendor Kernel

Start by cloning git

$ git clone https://chromium.googlesource.com/chromiumos/third_party/kernel
$ cd kernel


Chromebooks run different kernel versions depending on make/model. So you probably want to switch into the kernel version branch of corresponding to the ChromeOS kernel that is supported for your device. For this example we will choose the kernel that corosponds to what was supported at the time of this writing on the Samsung Chromebook2 featuring Exynos 5800 SoC.

$ git checkout chromeos-3.8

Actually if you want to be more precise, there are -release branches that you can checkout based on information you find from inside ChromeOS. Head into settings, and click "About ChromeOS". You will see information about Version, Platform, and Firmware that you can correlate to a git branch.


Prepare your kernel configuration file using scripts. It really depends on your hardware, so in this example we will use Exynos as the example.

$ ./chromeos/scripts/prepareconfig chromeos-exynos5

For the tegra use "chromeos-tegra124" instead.


At this point you should disable the ChromeOS security built-in their kernels.

  • Disable CONFIG_CHROMEOS_SECURITY


You will probably want to configure your kernel to be more Fedora friendly.

  • Enable SElinux
  • Enable Control Groups
  • Enable Namespaces
  • Enable Auditing
  • Enable NFS client/server
  • Enable EXT3/4 features such as ACL, quota, etc...
  • Anything else you want
$ make menuconfig


Then start building the kernel

 
$ make -j8

$ make modules_install

$ make firmware_install


Next you need to setup your Flattened Image Tree (aka FIT) format file. This is a modern variant of the traditional uImage format, it can contain many kernels, initrd, device-tree, and organize them into configuration groups. The boot-loader will scan the device-trees and look for a platform string that matches the device, and select the correct device-tree.

cat <<-EOF > /boot/exynos.its
/dts-v1/;

/ {
    description = "Exynos";
    #address-cells = <1>;
    images {
        kernel@1{
            description = "chromeos-3.8";
            data = /incbin/("arch/arm/boot/zImage");
            type = "kernel_noload";
            arch = "arm";
            os = "linux";
            compression = "none";
            load = <0>;
            entry = <0>;
        };
        fdt@1{
            description = "exynos5250-skate";
            data = /incbin/("arch/arm/boot/dts/exynos5250-skate.dtb");
            type = "flat_dt";
            arch = "arm";
            compression = "none";
        };
        fdt@2{
            description = "exynos5250-smdk5250";
            data = /incbin/("arch/arm/boot/dts/exynos5250-smdk5250.dtb");
            type = "flat_dt";
            arch = "arm";
            compression = "none";
        };
        fdt@3{
            description = "exynos5250-snow-rev4";
            data = /incbin/("arch/arm/boot/dts/exynos5250-snow-rev4.dtb");
            type = "flat_dt";
            arch = "arm";
            compression = "none";
        };
        fdt@4{
            description = "exynos5250-snow-rev5";
            data = /incbin/("arch/arm/boot/dts/exynos5250-snow-rev5.dtb");
            type = "flat_dt";
            arch = "arm";
            compression = "none";
        };
        fdt@5{
            description = "exynos5250-spring";
            data = /incbin/("arch/arm/boot/dts/exynos5250-spring.dtb");
            type = "flat_dt";
            arch = "arm";
            compression = "none";
        };
        fdt@6{
            description = "exynos5420-peach-kirby";
            data = /incbin/("arch/arm/boot/dts/exynos5420-peach-kirby.dtb");
            type = "flat_dt";
            arch = "arm";
            compression = "none";
        };
        fdt@7{
            description = "exynos5420-peach-pit";
            data = /incbin/("arch/arm/boot/dts/exynos5420-peach-pit.dtb");
            type = "flat_dt";
            arch = "arm";
            compression = "none";
        };
        fdt@8{
            description = "exynos5420-peach-pit-rev3_5";
            data = /incbin/("arch/arm/boot/dts/exynos5420-peach-pit-rev3_5.dtb");
            type = "flat_dt";
            arch = "arm";
            compression = "none";
        };
        fdt@9{
            description = "exynos5420-peach-pit-rev4";
            data = /incbin/("arch/arm/boot/dts/exynos5420-peach-pit-rev4.dtb");
            type = "flat_dt";
            arch = "arm";
            compression = "none";
        };
        fdt@10{
            description = "exynos5420-smdk5420";
            data = /incbin/("arch/arm/boot/dts/exynos5420-smdk5420.dtb");
            type = "flat_dt";
            arch = "arm";
            compression = "none";
        };
        fdt@11{
            description = "exynos5420-smdk5420-evt";
            data = /incbin/("arch/arm/boot/dts/exynos5420-smdk5420-evt0.dtb");
            type = "flat_dt";
            arch = "arm";
            compression = "none";
        };
        fdt@12{
            description = "exynos5422-peach-pi";
            data = /incbin/("arch/arm/boot/dts/exynos5422-peach-pi.dtb");
            type = "flat_dt";
            arch = "arm";
            compression = "none";
        };
        fdt@13{
            description = "exynos5440-ssdk5440";
            data = /incbin/("arch/arm/boot/dts/exynos5440-ssdk5440.dtb");
            type = "flat_dt";
            arch = "arm";
            compression = "none";
        };
    };
    configurations {
        default = "conf@1";
        conf@1{
            description = "exynos5250-snow-rev4 (2012 Samsung Chromebook)";
            kernel = "kernel@1";
            fdt = "fdt@3";
        };
        conf@2{
            description = "exynos5250-snow-rev5 (2012 Samsung Chromebook)";
            kernel = "kernel@1";
            fdt = "fdt@4";
        };
        conf@3{
            description = "exynos5250-spring";
            kernel = "kernel@1";
            fdt = "fdt@5";
        };
        conf@4{
            description = "exynos5420-peach-pit (2014 Samsung Chromebook2, 13 inch)";
            kernel = "kernel@1";
            fdt = "fdt@7";
        };
        conf@5{
            description = "exynos5420-peach-pit-rev3_5 (2014 Samsung Chromebook2, 13 inch)";
            kernel = "kernel@1";
            fdt = "fdt@8";
        };
        conf@6{
            description = "exynos5420-peach-pit-rev4 (2014 Samsung Chromebook2, 13 inch)";
            kernel = "kernel@1";
            fdt = "fdt@9";
        };
        conf@7{
            description = "exynos5422-peach-pi (2014 Samsung Chromebook2, 11 inch )";
            kernel = "kernel@1";
            fdt = "fdt@12";
        };
    };
};
EOF

Your specification of device-tree files, and configuration group combos can be as specific or broad as you choose. If you know the exact DTB that your device uses, you really only need to specify that one DTB, and setup a configuration to point at your kernel and DTB. However, if you want a multiplatform kernel and many different DTB choices then you should consider the broader approach with multiple config groups.


Then you compile the configuration to the binary FIT image

$ mkimage -vf exynos.it{s,b}


Next you sign and pack the FIT image

vbutil_kernel --pack        /boot/exynos5-kernel.img \
              --keyblock    /boot/fedora.keyblock    \
              --signprivate /boot/fedora.vbprivk     \
              --config      /boot/kcmdline           \
              --vmlinuz     exynos.itb               \
              --arch arm --version 1


Write the kernel image to one of the kernel partitions, and adjust kernel priority so that partition is selected first.

$ sudo dd if=/boot/exynos5-kernel.img of=/dev/mmcblk1p2
$ sudo sgdisk -A 2:=:0x011F000000000000 -A 1:=:0x011A000000000000 /dev/mmcblk1

## or if you have vboot-utils installed

$ sudo cgpt add -i2 -P15 /dev/mmcblk1
$ sudo cgpt add -i2 -P10 /dev/mmcblk1

Don't be scared by sgdisk attributes editing, it's just shown here to document the possible way to do that without installing Google's tool.


Now cross your fingers and see if the kernel boots. If you have any problems you can use chromeOS on the internal ssd to recover by chaning the boot priority back to the mmcblk1p1 KERN-A partition. It may take a few kernel compiles before you get a fully functional happy setup.

Building Mainline Kernel

(insert steps to build & install mainline on the chromebook)


Chain loading Das u-boot

You can chain load another instance of uboot if you want. There are some benefits by doing that:

  • You can use Fedora boot methods (aka a-b-c)
  • no more signing kernel images
  • no more Das u-boot kernel images, you can directly boot a zImage
  • HYP mode (aka hypervisor), you can then run Xen kernels.


Removing the security screw

You can open the laptop and remove the security screw washer. That is an electrically insulating washer that sperates a screw from the base board, and once removed allows the on-board coreboot to be replaced. This means you do not have to chain-load another instance of Das u-boot.

(to be continued)