1:orphan:
2
3.. _zephyr-audio-dsp-development-on-chromebooks:
4
5Zephyr Audio DSP Development on Chromebooks
6###########################################
7
8The Audio DSP on Intel Chromebooks is configured to use the SOF
9"Community" key for firmware signing, and can therefore accept
10arbitrary user-developed firmware like Zephyr applications (of which
11SOF is one), including the Zephyr samples and test suite.
12
13Initial TGL Chromebook Setup
14****************************
15
16(These instructions were written specifically to the Asus Flip CX5
17device code named "delbin".  But they should be reasonably applicable
18to any recent Intel device.)
19
20Power the device on and connect it to a wireless network.  It will
21likely want to download a firmware update (mine did).  Let this finish
22first, to ensure you have two working OS images.
23
24Enable Developer Mode
25=====================
26
27Power the device off (menu in lower right, or hold the power button
28on the side)
29
30Hold Esc + Refresh (the arrow-in-a-circle "reload" key above "3") and
31hit the power key to enter recovery mode.  Note: the touchscreen and
32pad don't work in recovery mode, use the arrow keys to navigate.
33
34Select "Advanced Options", then "Enable Developer Mode" and confirm
35that you really mean it.  Select "Boot from Internal Storage" at the
36bootloader screen.  You will see this screen every time the machine
37boots now, telling you that the boot is unverified.
38
39Wait while the device does the required data wipe.  My device takes
40about 15 minutes to completely write the stateful partition.  On
41reboot, select "Boot from Internal Storage" again and set it up
42(again) with Google account.
43
44Make a Recovery Drive
45=====================
46
47You will at some point wreck your device and need a recovery stick.
48Install the Chromebook Recovery Utility from the Google Web Store and
49make one.
50
51You can actually do this on any machine (and any OS) with Chrome
52installed, but it's easiest on the Chromebook because it knows its
53device ID (for example "DELBIN-XHVI D4B-H4D-G4G-Q9A-A9P" for the Asus
54Tiger Lake board).  Note that recovery, when it happens, will not
55affect developer mode or firmware settings but it **will wipe out the
56root filesystem and /usr/local customizations you have made**.  So
57plan on a strategy that can tolerate data loss on the device you're
58messing with!
59
60Make the root filesystem writable
61=================================
62
63For security, ChromeOS signs and cryptographically verifies (using
64Linux's dm-verity feature) all access to the read-only root
65filesystem.  Mucking with the rootfs (for example, to install modules
66for a custom kernel) requires that the dm-verity layer be turned off:
67
68First open a terminal with Ctrl-Alt-T.  Then at the "crosh> " prompt
69issue the "shell" command to get a shell running as the "chronos"
70user.  Finally (in developer mode) a simple "sudo su -" will get you a
71root prompt.
72
73.. code-block:: console
74
75    crosh> shell
76    chronos@localhost / $ sudo su -
77    localhost ~ #
78
79Now you need to turn of signature verification in the bootloader
80(because obviously we'll be breaking whatever signature existed).
81Note that signature verification is something done by the ROM
82bootloader, not the OS, and this setting is a (developer-mode-only)
83directive to that code:
84
85.. code-block:: console
86
87    cros# crossystem dev_boot_signed_only=0
88
89(*Note: for clarity, commands in this document entered at the ChromeOS
90core shell will be prefixed with a hostname of cros.*)
91
92Next you disable the validation step:
93
94.. code-block:: console
95
96    cros# /usr/share/vboot/bin/make_dev_ssd.sh --remove_rootfs_verification
97
98**THIS COMMAND WILL FAIL**, give you an error that you are changing
99the setting for the entire running system, and suggest an alternative
100"--partitions X" argument to use that modifies only the currently used
101partition.  Run that modified command, then reboot.
102
103After rebooting, you will notice that your chromebook boots with the
104raw storage device (e.g. /dev/nvme0n1p5) mounted as root and not the
105"dm-0" verity device, and that the rootfs is read-write.
106
107Note: What this command actually does is modify the command line of
108the installed kernel image (it saves a backup in
109/mnt/stateful_partition/cros_sign_backups) so that it specifies
110"root=<guid>" and not "root=dm-0".  It does seem to leave the other
111verity configuration in place though, it just doesn't try to mount the
112resulting (now-invalid!) partition.
113
114Metanote: The astute will note that we're probably going to throw this
115kernel out, and that we could probably have just edited the command
116line of the new kernel instead of flashing and rebooting into this
117modified one.  But that's too many balls to juggle at once for me.
118
119Enable ChromeOS SSH
120===================
121
122Once you are booted with a writable partition, you can turn on the
123built-in ssh server with:
124
125.. code-block:: console
126
127    cros# /usr/libexec/debugd/helpers/dev_features_ssh
128
129By default neither the "chronos" user nor root accounts have
130passwords, so unless you want to type a ssh key in by hand, you
131probably want to set a password for the first login (before you run
132ssh-copy-id, of course):
133
134.. code-block:: console
135
136    cros# passwd
137
138Now ssh into the chromebook and add your key to
139``.ssh/authorized_keys`` as you do for any Linux system.
140
141Install Crouton
142***************
143
144The Zephyr integration tools require a proper Linux environment and
145won't run on ChromeOS's minimal distro.  So we need to install a Linux
146personality.  **DO NOT** bother installing the "Linux Development
147Environment" (Crostini) from the ChromeOS Developer settings.  This
148personality runs inside a VM, where our tools need access to the real
149kernel running on the real hardware.  Instead install Crouton
150(https://github.com/dnschneid/crouton), which is a community
151chroot-based personality that preserves access to the real hardware
152sysfs and /dev filesystem.  These instructions install the "cli-extra"
153package list, there are X11-enabled ones available too if you prefer
154to work on the device screen directly.  See the project page, etc...
155
156At a root shell, grab the installer and run it (note: /usr/local is
157the only writable filesystem without noexec, you must place the binary
158there for it to run!):
159
160.. code-block:: console
161
162    cros# mkdir -p /usr/local/bin
163    cros# curl -L https://github.com/dnschneid/crouton/raw/master/installer/crouton \
164                  > /usr/local/bin/crouton
165    cros# chmod 755 /usr/local/bin/crouton
166    cros# crouton -r focal -t cli-extra
167
168Start the Crouton chroot environment:
169
170.. code-block:: console
171
172    cros# startcli
173
174Now you are typing commands into the Ubuntu environment.  Enable
175inbound ssh on Crouton, but on a port other than 22 (which is used for
176the native ChromeOS ssh server).  I'm using 222 here (which is easy to
177remember, and not a registered port in /etc/services):
178
179.. code-block:: console
180
181    crouton# apt install iptables openssh-server
182    crouton# echo "Port 222" >> /etc/ssh/sshd_config
183    crouton# mkdir /run/sshd
184    crouton# iptables -I INPUT -p tcp --dport 222 -j ACCEPT
185    crouton# /usr/sbin/sshd
186
187(*As above: note that we have introduced a hostname of "crouton" to
188refer to the separate Linux personality.*)
189
190NOTE: the mkdir, iptables and sshd commands need to be run every time
191the chroot is restarted.  You can put them in /etc/rc.local for
192convenience.  Crouton doesn't run systemd (because it can't -- it
193doesn't own the system!) so Ubuntu services like openssh-server don't
194know how to start themselves.
195
196Building and Installing a Custom Kernel
197***************************************
198
199On your build host, grab a copy of the ChromeOS kernel tree.  The
200shipping device is using a 5.4 kernel, but the 5.10 tree works for me
201and seems to have been backporting upstream drivers such that its main
202hardware is all quite recent (5-6 weeks behind mainline or so).  We
203place it in the home directory here for simplicity:
204
205.. code-block:: console
206
207    dev$ cd $HOME
208    dev$ git clone https://chromium.googlesource.com/chromiumos/third_party/kernel
209    dev$ cd kernel
210    dev$ git checkout chromeos-5.10
211
212(*Once again, we are typing into a different shell.  We introduce the
213hostname "dev" here to represent the development machine on which you
214are building kernels and Zephyr apps. It is possible to do this on the
215chromebook directly, but not advisable.  Remember the discussion above
216about requiring a drive wipe on system recovery!*)
217
218Note: you probably have an existing Linux tree somewhere already.  If
219you do it's much faster to add this as a remote there and just fetch
220the deltas -- ChromeOS tracks upstream closely.
221
222Now you need a .config file.  The Chromebook kernel ships with the
223"configs" module built which exposes this in the running kernel.  You
224just have to load the module and read the file.
225
226.. code-block:: console
227
228    dev$ cd /path/to/kernel
229    dev$ ssh root@cros modprobe configs
230    dev$ ssh root@cros zcat /proc/config.gz > .config
231
232You will need to set some custom configuration variables differently
233from ChromeOS defaults (you can edit .config directly, or use
234menuconfig, etc...):
235
236+ ``CONFIG_HUGETLBFS=y`` - The Zephyr loader tool requires this
237+ ``CONFIG_EXTRA_FIRMWARE_DIR=n`` - This refers to a build directory
238    in Google's build environment that we will not have.
239+ ``CONFIG_SECURITY_LOADPIN=n`` - Pins modules such that they will
240    only load from one filesystem.  Annoying restriction for custom
241    kernels.
242+ ``CONFIG_MODVERSIONS=n`` - Allow modules to be built and installed
243    from modified "dirty" build trees.
244
245Now build your kernel just as you would any other:
246
247.. code-block:: console
248
249    dev$ make olddefconfig     # Or otherwise update .config
250    dev$ make bzImage modules  # Probably want -j<whatever> for parallel build
251
252The modules you can copy directly to the (now writable) rootfs on the
253device.  Note that this filesystem has very limited space (it's
254intended to be read only), so the INSTALL_MOD_STRIP=1 is absolutely
255required, and you may find you need to regularly prune modules from
256older kernels to make space:
257
258.. code-block:: console
259
260    dev$ make INSTALL_MOD_PATH=mods INSTALL_MOD_STRIP=1 modules_install
261    dev$ (cd mods/lib/modules; tar cf - .) | ssh root@cros '(cd /lib/modules; tar xfv -)'
262
263Pack and Install ChromeOS Kernel Image
264======================================
265
266The kernel bzImage file itself needs to be signed and packaged into a
267ChromeOS vboot package and written directly to the kernel partition.
268Thankfully the tools to do this are shipped in Debian/Ubuntu
269repositories already:
270
271.. code-block:: console
272
273    $ sudo apt install vboot-utils vboot-kernel-utils
274
275Find the current kernel partition on the device.  You can get this by
276comparing the "kernel_guid" command line parameter (passed by the
277bootloader) with the partition table of the boot drive, for example:
278
279.. code-block:: console
280
281    dev$ KPART=`ssh root@cros 'fdisk -l -o UUID,Device /dev/nvme0n1 | \
282                               grep -i $(sed "s/.*kern_guid=//" /proc/cmdline \
283                                         | sed "s/ .*//") \
284                               | sed "s/.* //"'`
285    dev$ echo $KPART
286    /dev/nvme0n1p4
287
288Extract the command line from that image into a local file:
289
290.. code-block:: console
291
292    dev$ ssh root@cros vbutil_kernel --verify /dev/$KPART | tail -1 > cmdline.txt
293
294Now you can pack a new kernel image using the vboot tooling.  Most of
295these arguments are boilerplate and always the same.  The keys are
296there because the boot requires a valid signature, even though as
297configured it won't use it.  Note the cannot-actually-be-empty dummy
298file passed as a "bootloader", which is a holdover from previous ROM
299variants which needed an EFI stub.
300
301.. code-block:: console
302
303    dev$ echo dummy > dummy.efi
304    dev$ vbutil_kernel --pack kernel.img --config cmdline.txt \
305           --vmlinuz arch/x86_64/boot/bzImage \
306           --keyblock /usr/share/vboot/devkeys/kernel.keyblock \
307           --signprivate /usr/share/vboot/devkeys/kernel_data_key.vbprivk \
308           --version 1 --bootloader dummy.efi --arch x86_64
309
310You can verify this image if you like with "vbutil_kernel --verify".
311
312Now just copy up the file and write it to the partition on the device:
313
314.. code-block:: console
315
316    $ scp kernel.img root@cros:/tmp
317    $ ssh root@cros dd if=/tmp/kernel.img of=/dev/nvme0n1p4
318
319Now reboot, and if all goes well you will find yourself running in
320your new kernel.
321
322Wifi Firmware Fixup
323===================
324
325On the Tiger Lake Chromebook, the /lib/firmware tree is a bit stale
326relative to the current 5.10 kernel.  The iwlwifi driver requests a
327firmware file that doesn't exist, leading to a device with no network.
328It's a simple problem, but a catastrophic drawback if uncorrected.  It
329seems to be sufficient just to link the older version to the new name.
330(It would probably be better to copy the proper version from
331/lib/firmware from a recent kernel.org checkout.):
332
333.. code-block:: console
334
335    cros# cd /lib/firmware
336    cros# ln -s iwlwifi-QuZ-a0-hr-b0-62.ucode iwlwifi-QuZ-a0-hr-b0-64.ucode
337
338Build and Run a Zephyr Application
339**********************************
340
341Finally, with your new kernel booted, you are ready to run Zephyr
342code.
343
344Build rimage Signing Tool
345=========================
346
347First download and build a copy of the Sound Open Firmware "rimage"
348tool (these instructions put it in your home directory for clarity,
349but anywhere is acceptable):
350
351.. code-block:: console
352
353     dev$ cd $HOME
354     dev$ git clone https://github.com/thesofproject/rimage
355     dev$ cd rimage/
356     dev$ git submodule init
357     dev$ git submodule update
358     dev$ cmake .
359     dev$ make
360
361Copy Integration Scripting to Chromebook
362========================================
363
364There is a python scripts needed on the device, to be run inside
365the Crouton environment installed above.  Copy them:
366
367.. code-block:: console
368
369    dev$ scp soc/xtensa/intel_adsp/tools/cavstool.py user@crouton:
370
371Then start the service in the Crouton environment:
372
373.. code-block:: console
374
375    crouton$ sudo ./cavstool.py user@crouton:
376
377
378Build and Sign Zephyr App
379=========================
380
381Zephyr applications build conventionally for this platform, and are
382signed with "west flash" with just a few extra arguments.  Note that
383the key in use for the Tiger Lake DSP is the "3k" key from SOF, not
384the original that is used with older hardware.  The output artifact is
385a "zephyr.ri" file to be copied to the device.
386
387.. code-block:: console
388
389    dev$ west build -b intel_adsp_cavs25 samples/hello_world
390    dev$ west sign --tool-data=~/rimage/config -t ~/rimage/rimage -- \
391                -k $ZEPHYR_BASE/../modules/audio/sof/keys/otc_private_key_3k.pem
392
393Run it!
394=======
395
396The loader script takes the signed rimage file as its argument.  Once
397it reports success, the application begins running immediately and its
398console output (in the SOF shared memory trace buffer) can be read by
399the logging script.
400
401.. code-block:: console
402
403    dev$ west flash --remote-host crouton
404    Hello World! intel_adsp_cavs25
405
406Misc References
407***************
408
409Upstream documentation from which these instructions were drawn:
410
411This page has the best reference for the boot process:
412
413http://www.chromium.org/chromium-os/chromiumos-design-docs/disk-format
414
415This is great too, with an eye toward booting things other than ChromeOS:
416
417https://www.chromium.org/chromium-os/developer-information-for-chrome-os-devices/custom-firmware
418