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