summaryrefslogtreecommitdiff
path: root/README
blob: edfbe11561788f2cb42d910b76062a9eb68d6e8f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
Debian on ASUS C101PA Chromebook
===============================


Overview
--------

This document contains instructions to install the Debian Linux distribution
on the internal eMMC of the ASUS C101PA Chromebook. It concerns the stable
distribution at the time of this writing (9.0 stretch), but that can easily
be changed to testing or unstable.

It is assumed the device still runs the ChromeOS operating system. The
procedure erases all data on the internal eMMC, so save any relevant files
before starting.

The installation steps are :
 - Enable boot from external device
 - Prepare rootfs image
 - Build Linux kernel packages
 - Create bootable external device as rescue (DESTRUCTIVE)
 - Deploy to internal eMMC (DESTRUCTIVE)

Hardware required :
 - x86 machine running Debian
 - Bootable device (USB drive or microSD card)
 - Networking (wireless / USB-Ethernet adapter)

This procedure is destructive and intended for advanced users. Be very careful
not to destroy your own data by mistake. Make back-up copies if unsure.

The kernel configuration in this repository was crafted to be close to the
original Debian kernel configuration, without modules which may not ever
be useful on the Chromebook, and with more specific options targetting
a low latency laptop with energy saving needs. It also works around some
defects in the ChromeOS branch, such as modules that must be built in the
kernel instead of as loadable modules.

The procedure is intended to get a system as close to Debian as possible.
In particular, with actual kernel packages and a careful kernel configuration,
it's very easy to get additional features such as an encrypted root file
system, because Debian handles the generation of the initramfs image.

The kernel/deploy.sh script, installed at /root/kernel/deploy.sh and
linked at /etc/kernel/postinst.d/zz-deploy, is run when updating the kernel
or adding packages that trigger a regeneration of the initramfs. It's the
responsibility of the user to understand what this script does, and adjust
it, as well as the files it uses, as necessary.


Enable boot from external device
--------------------------------

First, enable Developer Mode : while the laptop is off, hold down the ESC and
Refresh (F3) keys and start it.

From now on, the firmware presents a recovery screen saying "OS verification
is OFF". Press Ctrl-D to boot from the internal eMMC or Ctrl-U to boot from
an external USB drive / microSD card. Until the external "rescue" bootable
system is available, you can only boot ChromeOS from the internal eMMC.

Once in ChromeOS :
 - Press Ctrl-Alt-T to open the crosh shell
 - Type the "shell" command to start a real Unix shell
 - Type "sudo -s" to gain root privileges
 - Type "crossystem dev_boot_usb=1 dev_boot_signed_only=0" to enable booting
   from an external device


Prepare rootfs image
--------------------

There are several ways to do this, notably with the debootstrap tool, but
this procedure uses a fully emulated Qemu virtual machine to achieve it. The
idea is to use the arm64 Debian installer in the virtual machine, and
extract the resulting root file system from it. Note that, because it's
currently required to completely emulate the arm64 machine, this method is
quite long. Reserve around an hour for it, depending on your host hardware
and your Internet connection.

First, prepare a disk image. This image can be the same for both the rescue
device as well as the internal eMMC. It is suggested to use a small disk
size, and resize later to the maximum size permitted by the device. Run
the following command :

qemu-img create disk.img 4G

The procedure also requires the Debian installer, which you can find on any
Debian mirror, such as http://ftp.fr.debian.org/. The two files required are
the kernel image, named "linux", and the initrd containing the installer,
named "initrd.gz". Those files are in the netboot directory of the installer
of the version you want to install. Here is an example URL for the stretch
stable release :

http://ftp.fr.debian.org/debian/dists/stretch/main/installer-arm64/current/images/netboot/debian-installer/arm64

Move those files next to the disk image, then run the following command
to start the installation in the virtual machine :

qemu-system-aarch64 \
    -nographic \
    -M virt \
    -m 1G \
    -cpu cortex-a53 \
    -kernel linux \
    -initrd initrd.gz \
    -drive media=disk,if=virtio,index=0,format=raw,file=disk.img

These installation instructions assume the default single-partition guided
format, with no swap and no /boot partition. Once installed, the root file
system can be extracted by mounting the disk image as a loop device, and
simply copying the relevant partition into a new file.

As root, on the host :

# Allocate a loop device, attach the disk image to it, and probe partitions
losetup -f -P disk.img

# Identify the root file system device
losetup -a
lsblk

# This assumes the allocated device is /dev/loop0 and the root file system
# is in the second partition
dd if=/dev/loop0p2 of=rootfs.img bs=1M

# Once done, detach the disk image.
losetup -d /dev/loop0


Build Linux kernel packages
---------------------------

Before starting this procedure, make sure the git submodule(s) are up to date.

The kernel packages are pretty easy to build, thanks to the deb-pkg make
target built in the Linux build system. While it's possible to build the
kernel on the Chromebook, this procedure cross-compiles them from the x86
host system, mostly for better performance.

As root, on the host :

# Install build dependencies
apt build-dep linux

# Install the AArch64 GCC toolchain
# XXX This seems to be in conflict with gcc-multilib
apt install gcc-aarch64-linux-gnu

As a non-privileged user, on the host :

# Prepare the kernel build
cp linux_config chromeos-kernel/.config
cd chromeos-kernel
make ARCH=arm64 oldconfig

# Build the kernel
# Replace -j6 with the number of processors on your machine
make ARCH=arm64 -j6 deb-pkg

The two packages required on the Chromebook are :
 - linux-image
 - linux-firmware-image


Create bootable external device as rescue
-----------------------------------------

For this, you need a USB drive or a microSD card. This procedure assumes a
USB drive at /dev/sdc on the host, and /dev/sda on the target. Locating the
USB drive on both the x86 host and the Chromebook is the responsibility of
the user. Use a combination of lsblk and dmesg to make sure you're accessing
the correct device, hereafter called the "rescue device".

The idea is to create a ChromeOS-compatible GPT partition table on the
rescue device, with two entries (one for the "kernel" and another for the
root file system), and then write the kernel and the root file system into
their respective partitions. Creating the partitions and writing the root
file system is done from the host system, whereas installing the kernel
and copying it to the kernel partition is done from the target system,
either the original ChromeOS on the Chromebook (easier) or a QEMU virtual
machine.

Note that the Linux framebuffer console apparently suffers from a small bug
that freezes it after input inactivity.

As root, on the host :

# Install partitioning tools
apt install parted cgpt

# Create the partition table
parted --script /dev/sdc mklabel gpt

# You may check your partition table at any time with
cgpt show /dev/sdc

# Create the kernel partition
#
# This line names the partition "kernel" (-l is label) starting at
# sector 64 with a size of 131072 sectors (1 sector == 512 bytes,
# making the partition size 64M).
cgpt add -t kernel -l kernel -b 64 -s 131072 /dev/sdc

# Set priority and "successful" counters for the kernel partition
# This is required by the boot loader. Refer to the documentation of
# cgpt for more details.
cgpt add -i 1 -P 10 -S 1 /dev/sdc

# Create the root file system partition
#
# After creating the kernel partition, print the partition table, and look
# for a line similar to :
#     15261663          32          Sec GPT table
# The first value on this line is the last sector. To maximize your root
# file system partition size, subtract its first sector from this size.
# The first sector is the last sector of the kernel partition, so in
# this example, it's 64 + 131072, so 131136, and 15261663 - 131136 is
# 15130527.
cgpt add -t data -l / -b 131136 -s 15130527 /dev/sdc

# Write the root file system into the root file system partition
dd if=rootfs.img of=/dev/sdc2 bs=1M

    ---- These steps are similar for the deployment on the      ----
    ---- internal eMMC, with /dev/mmcblk0p1 as the kernel       ----
    ---- partition and /dev/mmcblk0p2 as the root file system   ----
    ---- partition.                                             ----

# Extend the root file system to the maximum available size
e2fsck -fp /dev/sdc2
resize2fs /dev/sdc2

# Mount the root file system
mount /dev/sdc2 /mnt

# Copy the required kernel packages to the root file system
cp <linux-firmware-pkg> <linux-image-pkg> /mnt/root

# Copy the files used to generated a signed kernel image from this repository
# to the rescue device
cp -r kernel /mnt/root

# Unmount the root file system
umount /mnt

Installing the kernel is done on the target device, either the original
ChromeOS system, or a QEMU virtual machine. Refer to enabling developer mode
for a procedure to gain root privileges on ChromeOS.

With QEMU, make the rescue device available to the virtual machine using a
line such as -drive media=disk,if=virtio,index=1,format=raw,file=/dev/sdc to
the qemu-system-aarch64 command line used when preparing the root file system.
From the installer, when asked for the root password, select "Go back", then
select "Detect disks", and then start a root shell in the environment of the
installer.

# Once you have a root shell on the target system, with networking configured,
# mount the root file system, and chroot into it. If using ChromeOS, unmount
# the device if it was automatically mounted before proceeding.
mount /dev/sda2 /mnt
chroot /mnt
mount -t proc none /proc
mount -t sysfs none /sys
mount -t devtmpfs none /dev

# Copy the host /etc/resolv.conf to the chroot if needed

# Install the packages required for partitioning and generating the kernel
# image in the format expected by the boot loader
apt install parted cgpt vboot-utils vboot-kernel-utils u-boot-tools

# Copy the firmware blobs to /lib/firmware
mkdir -p /lib/firmware
cp -a /root/kernel/firmware/* /lib/firmware

# Adjust the kernel image generation files in /root/kernel to refer to the
# correct kernel partition (the relevant files are deploy.sh and kernel args).
# One the Chromebook, the USB drive is /dev/sda, whereas the external microSD
# card is /dev/mmcblk1. The files to adjust are deploys.sh and kernel.args.

# Create a link to the deploy.sh script so that every time a kernel is
# installed, a signed kernel image is generated and written to the kernel
# partition (note that the link must not end with .sh for this to work).
ln -s /root/kernel/deploy.sh /etc/kernel/postinst.d/zz-deploy

# Install the kernel packages
dpkg -i <linux-firmware-pkg> <linux-image-pkg>

# Depending on how you installed Debian, the previous operation may fail
# because it can't find a symlink to the kernel. Solve this with the
# linux-update-symlinks command, e.g.
linux-update-symlinks install 4.4.121-c101pa+ /boot/vmlinuz-4.4.121-c101pa+

# Once done, you may remove the Debian kernel
apt purge linux-image-4.9.0-6-arm64 linux-image-arm64

# It's recommended to install software to configure wireless networking,
# such as wicd
apt install wicd-curses

# Don't forget to properly unmount after leaving chroot, as this makes
# sure all the written data is actually on disk afterwards.
umount /mnt/dev
umount /mnt/sys
umount /mnt/proc
umount /mnt


Deploy to internal eMMC
-----------------------

Once the rescue device boots, deploying to the internal eMMC is quite simple.
Make sure not to leave any data of value on the Chromebook since this is a
destructive operation. Also, make sure to set up networking on the rescue
device so that additional software can easily be installed.

The idea is to boot from the rescue device (Ctrl-U from the boot screen),
repartition the internal eMMC, write the root file system to the data
partition, mount it and chroot inside, and install the kernel from there.

Depending on the rescue device capacity, you may store the root file system
image and kernel packages and generation files inside, on an additional
USB drive (if booting from a microSD card) or microSD card (if booting from
a USB drive), or you may fetch them through the network.

As root, on the target, after booting on the rescue device :

# Create the partition table
parted --script /dev/mmcblk0 mklabel gpt

# Create the kernel partition
cgpt add -t kernel -l kernel -P 10 -S 1 -b 64 -s 131072 /dev/mmcblk0

# Create the root file system partition
# Compute the sizes from cgpt show /dev/mmcblk0 as for the rescue device
cgpt add -t data -l / -b 131136 -s 30646175 /dev/mmcblk0

# Write the root file system into the root file system partition

The rest is very similar to the rescue device, with the exception that
the target device is /dev/mmcblk0, with /dev/mmcblk0p1 being the kernel
partition and /dev/mmcblk0p2 the root file system partition.

Once done, boot from the internal eMMC with Ctrl-D from the boot screen.