012b. Debian on the Lenovo 300e 2nd-gen MTK arm64 Chromebook (hana) (real)

Wed, 07 Feb 2024 01:09:33 +0100

Contents

    1. no nooo my nose cam noooooo
    2. saved from chromium (chrome os (chromium os(?)))
    3. hfbitland
    4. Me loading: Haha fuck yeah!!! Yes!! Me booting: Well this fucking sucks. What the fuck.
    5. how is pointar formed kernal loaded?
    6. she debra on my ian 'til I marr her dock
    7. an interlude: here's a never-documented-before ctrl+i shortcut :)
    8. a way to leak post-mortem metadata
    9. a brief ado about systemd
    10. a way to pack a kernel to boot
    11. when im in an EXacutif'^@gejarators competition and my opponent is Hifux:
    12. Mein Gott Leute, mein neu Linux hat mir einfach erlaubt dass ich MMC booten darf! Wie cool ist das bitte? Jetzt zocke ich Systemd und boote von MMC! Yippee!
    13. Fraerin' ex%butinn^N
    14. 🐧🐧🐧🐧
      1. this is where I spend two further straight days building kernels to find out.
    15. arm64 Chromebook Debian port any% 17-day RTA/#137 IGT WR
    16. installing Debian
    17. arm64 Chromebook Debian port install% 23-day RTA/#137 IGT WR
      1. ChromeOS as a recovery system
    18. they unfucked the HIDs bro its crazy
      1. naaah no they fuckin didn't
    19. HDMI
    20. blob-free boot bundle real
    21. Miscellanea:
    22. How to get Debian on your Google Hana 2023 (real (working (no virus)))
    23. Funxional summary
      1. Funxional
      2. Dysfunxional
    24. Summary

In 012. Debian on the Lenovo 300e 2nd-gen arm64 Chromebook I bought a laptop I thought was this one and in 012a. Installing Debian on the Lenovo 300e 2nd-gen Chromebook (Intel) I made it normal. Now I have a celeron laptop for some reason.

Well, the reason is that Lenovo makes three identical laptops, as listed by Chromium OS > Developer Information for Chrome OS Devices[orig. arch.]:

Release
27 February 2019
1 March 2019
28 February 2020
OEM
Lenovo
Lenovo
Lenovo
Model
Lenovo 300e Chromebook 2nd Gen (MTK)
Lenovo 300e Chromebook 2nd Gen (Intel)
Lenovo 300e Chromebook 2nd Gen AMD
Code name
Sycamore360
Phaser360
Treeya360
Board name(s)
hana
Octopus
Grunt
Base board
oak
octopus
User ABI
arm
x86_64
x86_64
Kernel
3.18
4.14
4.14
Kernel ABI
aarch64
x86_64
x86_64
Platform
MT8173
Gemini Lake
Stoney Ridge
Form Factor
Chromebook
Convertible
Convertible
First Release
R72
R72
R80

compare this to what Lenovo product pages call them:

Branding
300e Chromebook 2nd Gen (11.6") Laptop
300e Chromebook 2nd Gen (11.6") Laptop
300e Chromebook 2nd Gen (11.6”, AMD)
Google summary and "product not available" popup
Lenovo 300e Chromebook (2nd Gen, MTK)
300e Chromebook 2nd Gen (11.6") Laptop
New Lenovo Chromebook 300e
P/N
81QC
81MB
82CE
Processor
MediaTek™ 8173C (2.10GHz)
Intel® Celeron® N4020 Processor (…)
7th Generation AMD A4-9120C APU (…)

and to what the bottom stickers and the "Product Specification References" (the PDFs you get in Tech Specs, More Information) call them:

Sticker
Lenovo 300e Chromebook 2nd Gen MTK
Lenovo 300e Chromebook 2nd Gen
Lenovo 300e Chromebook 2nd Gen AST
PSRef
Lenovo 300e Chromebook 2nd Gen MTK
Lenovo 300e Chromebook 2nd Gen
Lenovo 300e Chromebook 2nd Gen AST

This has to be actively-malicious behaviour on Lenovo's part. I bought my Intel (sorry, my ) 300e thinking it were the MTK one becuase it was listed thusly. The sticker didn't specify any variant, but it's the first from the series so that added up. The seller had listed it as that because the only Google result for "Lenovo 300e Chromebook 2nd Gen" is the MTK-variant product page, there's no way she could've known. The ‌ variant appears to be absolute search engine poison. Or deduplicated away. Or whatever.

Also, I don't know where the ChromiumOS page got the parens around the variant designator from, or the "Intel", but they were crucial in fooling me, personally.

In an obverse vein, the "Acer Chromebook R13" (which was also under consideration this time) is a real product that the ChromiumOS page also knows about, and Acer seems to entirely and wholly deny having ever produced it – there is no mention of it on acer.com, and Google returns second-hand re-sellers exclusively.

Regardless, the search space is thus narrowed considerably, because any listing that doesn't show a clear, in-focus, readable, un-painted-over view of the bottom sticker, at least enough to make out "MTK", is right out. This means I may've missed out on some deals, but at time of writing there's all of 5 working arm64 Chromebooks in Poland for a reasonable price (defined as a hard ≤200zł (≤46€) filter).

On 2024-01-11 I bought the titular laptop for 149+10.95zł (70+22zł for one with a busted-ass screen; resp. 36.78€ and 21.15€; resp. 18.5kg and 10.6kg of kefir) for the same reason as in 012. Debian on the Lenovo 300e 2nd-gen arm64 Chromebook – as an arm64-with-CRC32 testbed.

This continues to be primarily precipitated by the chrultrabook talk, and naturally it continues to be impossible to install Debian traditionally on ARM Chromebooks. Like InstallingDebianOn/Samsung/ARMChromebook and Samsung Chromebook 2, this is "running debian on the chromebook from the μsd card, and also you can »install« by properly arranging and copying to the internal flash", even though both of them do say they're "installing" on the device when they aren't. Which is why 012a. Installing Debian on the Lenovo 300e 2nd-gen Chromebook (Intel) had "install" in the title and this doesn't.

Hopefully, instead of using unprecedented-in-the-text shell programs and methodologies that definitely make sense to the authors at the time to construct the images, I can demonstrate the final state itself (god forbid!) as well as the basis for the steps taken with no leaps of logic, so this can serve as more useful documentation.

# no nooo my nose cam noooooo

Chromebook open flat; there's a camera and a glaring white sticker above the screen; the keyboard itself is english and decroted: there are two extrmely wide keys to the left of the space bar (ctrl and alt), the ISO enter is half a key thin, the caps lock has a 🔍 on it, and the top row has an esc key, then a series of 11 iconsChromebook open flat, bottom side up: there's two more stickers over screws in the bottom panel, and a yellow barcode beow the product sticker; the top panel has both a chrome wordmark and logo, and a Lenovo wordmark in inverse colours; the hinges are beat to hell

Here we can see some obvious physical differences between these supposedly-identical laptops (barring the warranty/service seals glued to the screen): on the english keyboard, is actually labelled backspace, tab, and shift.

Most importantly, however: there's no nose cam. What's the point of a laptop, then, honestly.

the hinge-corner of the chromebook on its side. both halves have holes out and are thick, implying both halves are the keyboard half

And this demonstrates a significant consumer-affecting difference, in that the holes are just different:

81MB Left
USB-C charging
USB-A 3
μSD card
3.5mm TRRS
81QC Left
USB-C charging
HDMI
USB-A 3
SD card
81MB Right
Kensington lock
USB-C
USB-A 3
power/volume buttons
81QC Right
Kensington lock
power/volume buttons
3.5mm TRRS

So this full-size computer somehow has only as much I/O as my palmtop?

The label does agree with the listing that it's MTK:

the product sticker from the bottom panel:
Lenovo 300e Chromebook 2nd Gen MTK
Model Name (型號):81QC
INPUT (電壓/電流):15V DC 3A
Mfg Date:19/09/02
S/N:P206RP16 MTM:81QC0004UK
Manufactured for Lenovo
Made in China 中國製造
MO:P2N0B9902007 Factory ID: HFBITLAND

Incredible pog moment.

It appears that I'm pre-

# saved from chromium (chrome os (chromium os(?)))

because it booted to the developer mode warning screen that took 400 words last time

Title line: chrome, English; Main body: OS verifications is OFF Press SPACE to re-enable.; Footer: For help visit https://google.com/chromeos/recovery  Model HANA I4A-C2S-A6I-A66-B2U-Q3T

– where two things stand out: the serial number is one triplet shorter (the Intel one had 7), and it says "Model: HANA".

One may recall from 012. Debian on the Lenovo 300e 2nd-gen arm64 Chromebook and from the tables quoted at the top of this page that the Intel-processor laptop said "Model: PHASER360". At the time I'd been expecting "Sycamore360", but due to the nomenclature scam "Phaser360" made sense.

Chrultrabook says this should be the board name, and lists Phaser360 as the board name for the 2nd-gen Intel 300e, which disagrees with the ChromiumOS-branded documentation but is internally consistent. Google-official Chromebook Help, Recover your Chromebook, Recovery option 2: Use USB drive, Step 2: Download a new copy of the OS says

  1. Click Select a model from a list, or type in the model number of the Chromebook you want to recover. To find this number, look at the bottom of the error message on your Chromebook screen.

and "model number" per se doesn't appear anywhere else. So everything is, as usual, at odds.

The "hana" board name appears to be shared between 9 identical devices (the "telesu" ASUS one uses a "hana" "Base board", all others use "oak". these appear to be unrelated hanas) released between 2017-03-17 and 2019-12-27, which includes 300e (first-gen), 300e 2nd Gen, and 100e 2nd Gen Lenovos. There appears to be no first-generation ARM 100e variant (the Intel and AMD ones are in full swing). This is your brain on products.

This is all the more weird because the listing proclaims it used, ✅Bios - Ok(? shit don't got one, brother) and ŚLADY UŻYTKOWANIA, but doesn't mention anything that would imply it's in developer mode. Maybe this was done as a reset step, but there are easier and better-documented ways to do this. Especially since the only thing attached to the laptop in the box, beside the seals, was a long Any modifications to the software or hardware, including attempted service, void your right to a return! spiel, which wouldn't go well for me if I were to return it in such an overtly-"modified" state probably.

It also tries to spin ✅Bateria trzyma minimalnie 1h as baterie sprawdzamy pod obciążeniem but one has to wonder how this could be done to a machine in freshly-triggered developer mode.

So with the innards appearing to be some ARM board, and a manually-confirmed boot 🙄 the magical OOBE control doesn't appear to've been clicked, and clicking through it and through the root passphrase popup was so mindless and indistinguishable from the last time I forgot to shoot jpegs. Except that the throbbers appear to be embedded videos instead of animations, but.

# hfbitland

shell session, incl. uname output with version "4.19.272-14690-..." and architecture "aarch64", lscpu which notes 4 CPUs, of which two "ARM" "Cortex-A53" and two "ARM" "Cortex-A72", all CPUs have crc32

Beside the similarly-decroted kernel version, note how this doesn't actually say what the CPU… is? Like its self-branding? Apparently this information doesn't exist in the CPU, or exists only to the extent of the same two integers that /proc/cpuinfo shows –

CPU implementer
0x41
CPU part
0xd03
0xd08

– and you (or lscpu) can look them up in a table.

The best approximation of a CPU/device ID I found in /proc/device-tree/compatible, which listed google,hana-rev{6,5,4,3,2,1}, google,hana, and mediatek,mt8173. Note the lack of Lenovo's C after the model. I haven't found it attested anywhere in proc/sysfs.

The only product-level branding I found in /sys/firmware/vpd/ro/ (Vital/Vendor Product Data[orig. arch.] – yes, the documentation can't decide) as model_name: "Lenovo 300e Chromebook 2nd Gen MTK" (which miraculously agrees with Lenovo's marketing and the outside!), and customization_id matching the ChromiumOS "Code name" with "OEM1-SYCAMORE360".

There's also 64 bytes of hex in a stable_device_secret_DO_NOT_SHARE in there. idk why. funny, though

Another model difference is that on the Intel platform the μSD card slot showed up as SCSI (undoubtedly through a USB adapter) and on this one it's an MMC device, as it ought to be. Oh and the tactiles of plugging the SD card are so ass I thought it was broken before looking at the hotplugs in the dmesg.

I'd complained that no Home/End is agony, and it is, but I must not've tried 🔍 and ˂ or ˃, which does just that.

# Me loading: Haha fuck yeah!!! Yes!! Me booting: Well this fucking sucks. What the fuck.

Following the instruxions from /etc/issue:

If you are having trouble booting a self-signed kernel, you may need to enable USB booting. To do so, un the following as root: enable_dev_usb_boot

yielded

localhost ~ # enable_dev_usb_boot

    SUCCESS: Booting any self-signed kernel from SSD/USB/SDCard slot is enabled.

    Insert bootable media into USB / SDCard slot and press Ctrl-U in developer
    screen to boot your self-signed image.

and it do b honkin

which one has to assume is good, given the lack of priors in this domain.

To validate this suspicion, I consulted /sys/firmware/log which identifies itself ас "coreboot-81de43c Mon Mar 19 23:11:07 UTC 2018 bootblock starting...", and previously the sexion headed by "Starting depthcharge on hana..." had

VbAudioOpen() - note count 5
VbBootDeveloper() - user pressed Ctrl+D; skip delay
VbBootDeveloper() - trying fixed disk
VbTryLoadKernel() start, get_info_flags=0x2
VbTryLoadKernel() found 1 disks
VbTryLoadKernel() trying disk 0
GptNextKernelEntry looking at new prio partition 2
GptNextKernelEntry s1 t0 p2
GptNextKernelEntry looking at new prio partition 4
GptNextKernelEntry s1 t0 p1
GptNextKernelEntry looking at new prio partition 6
GptNextKernelEntry s0 t15 p0
GptNextKernelEntry likes partition 2
Found kernel entry at 20480 size 32768
Checking key block signature...
   - sig_size=512, expecting 512 for algorithm 8
In RSAVerify(): Padding check failed!
In RSAVerify(): Hash check failed!
Invalid key block signature.

whereas now it saw the prefix of

VbAudioOpen() - note count 5
VbBootDeveloper() - user pressed Ctrl+U; try USB
vboot_draw_screen: screen=0x0 locale=3
VbTryLoadKernel() start, get_info_flags=0x1
VbTryLoadKernel() found 1 disks
VbTryLoadKernel() trying disk 0
Primary GPT header is invalid
Secondary GPT header is invalid
Unable to read GPT data
VbTryLoadKernel() LoadKernel() = 65551
VbSetRecoveryRequest(91)
VbBootDeveloper() - no kernel found on USB
rt5645_device_init completed, codec = 5650
VbSetRecoveryRequest(0)
vboot_draw_screen: screen=0x101 locale=3
VbBootDeveloper() - user pressed Ctrl+D; skip delay

and presumably the screen being 0 is why it flashes black.

I can't seem to find, like, first-party documentation about what a "valid" header would be. Well, about what this bootloader looks for, in any way whatever. It's either upstream's Note: Only CrOS formatted images will boot via USB. Other Linux distros will not work.[orig. arch.] (abject lie as proven by the guides) or the guides which are "do this".

Though, actually, it does seem like, for that laptop exclusively, Chromium OS > Developer Information for Chrome OS Devices > Samsung ARM Chromebook, Firmware, Boot Sequence[orig. arch.] reads:

Out of the 30 internal links from the device table[orig. arch.] (discounting those that don't work or redirect),

11 note anything about USB-booting Acer AC700 Chromebook[orig. arch.] Acer C720 & C720P & C740 Chromebook[orig. arch.] Asus Chromebox[orig. arch.] Chromebook Pixel (2015)[orig. arch.] Cr-48 Chrome Notebook Developer Information[orig. arch.] Lenovo Thinkpad X131e Chromebook[orig. arch.] Samsung Series 5 Chromebook[orig. arch.] Acer CB5-311 Chromebook 13[orig. arch.] Samsung Chromebook 2[orig. arch.] HP Chromebox[orig. arch.] Samsung ARM Chromebook[orig. arch.] Samsung Series 5 550 Chromebook and Series 3 Chromebox[orig. arch.] Chromebook Pixel (2013)[orig. arch.]
3 have a How to boot your own image from USB sexion (mentions ChromiumOS images exclusively) Acer AC700 Chromebook[orig. arch.] Samsung Series 5 Chromebook[orig. arch.] Samsung Series 5 550 Chromebook and Series 3 Chromebox[orig. arch.]
3 have a similar Running Chromium OS sexion identified with Before you start fiddling with your own builds it is strongly recommend to(sic!) (mentions ChromiumOS images exclusively) Acer C720 & C720P & C740 Chromebook[orig. arch.] Asus Chromebox[orig. arch.] HP Chromebox[orig. arch.]
3 (two other) ARM chromebooks have the entire Developer Mode sexion identical (with the abject lie) Samsung ARM Chromebook[orig. arch.] Samsung Chromebook 2[orig. arch.] Acer CB5-311 Chromebook 13[orig. arch.]
3 laptops have another set of identical Developer Modes (no mention of how or what you can boot) Acer C720 & C720P & C740 Chromebook[orig. arch.] Chromebook Pixel (2013)[orig. arch.] Chromebook Pixel (2015)[orig. arch.]
2 "chromeboxes" have another set of identical Developer Modes (no mention of how or what you can boot) Asus Chromebox[orig. arch.] HP Chromebox[orig. arch.]
all Developer Mode sexions are habsburgian, but this device has unique requirements for entering recovery mode!, so it's the most different one Lenovo Thinkpad X131e Chromebook[orig. arch.]

and Cr-48 Chrome Notebook Developer Information[orig. arch.] is the oldest, so it actually has an itemised guide called How to boot your own (non-Chromium OS) image from USB which nonetheless starts with (Note: This part is outdated: make_developer_script_runner.sh does not exist anymore). Even then, a sub-Create a USB disk that will boot another operating system-sexion consists exclusively of

TODO: This should be possible for someone skilled in the art of Linux. The above instructions tell you how to run any arbitrary Linux program, and (with root access) you should be able to do pretty much anything you want. It would be nice to get some good instructions here, though.

which actually makes sense, since the "How to" sexion doesn't actually appear to do anything? except download a "mario_recovery_kernel"(‽) from a Google CDN, prepare an exec sh "developer script", and combine them it into a ChromeOS-equivalent image? which sure as hell doesn't look like non-Chromium OS.

Naturally two different ways to make an actual ChromiumOS image are outlined, in spite of the page linking to the developer documentation constantly.

Even out of our lucky trio, the Samsung ARM Chromebook[orig. arch.] is the only one with the bullet list. Even then, how are you supposed to interpret it? How can a partition be marked "active"? Is the "Linux kernel partition" actually "ChromeOS kernel" (FE3A2A5D-4F32-41A7-B725-ACCC3285A309), the only kernel-matching UUID bookworm fdisk knows about? Assuming the image has to support the Linux boot protocol, what parameters does it pass? Are there any other restrixions?

The SD card I put in to test was actually MBR-formatted, so this probably explains why "{Primary,Secondary} GPT header is invalid". Indeed, re-making it as GPT (with the only partition being a VFAT "Linux filesystem" (0FC63DAF-8483-4772-8E79-3D69D8477DE4) to copy logs to), I got:

VbBootDeveloper() - user pressed Ctrl+U; try USB
VbTryLoadKernel() trying disk 0
GptNextKernelEntry no more kernels
VbTryLoadKernel() LoadKernel() = 65551
VbSetRecoveryRequest(91)
VbBootDeveloper() - no kernel found on USB

Amazing, incredible, it enumerated no kernels this time. Emboldened by this, I made two kernel partitions, one with the flag it hints at (it's wrong of course, "active partitions" are an MBR thing), accd'g to fdisk:

Device         Size Type              Name Attrs
/dev/mmcblk1p1 200M Linux filesystem
/dev/mmcblk1p2  30M ChromeOS kernel
/dev/mmcblk1p3  30M ChromeOS kernel        LegacyBIOSBootable

and rebooting

VbTryLoadKernel() trying disk 0
GptNextKernelEntry looking at new prio partition 2
GptNextKernelEntry s0 t0 p0
GptNextKernelEntry looking at new prio partition 3
GptNextKernelEntry s0 t0 p0
GptNextKernelEntry no more kernels
VbTryLoadKernel() LoadKernel() = 65551

and the flag doesn't appear to change anything, neither the iteration order nor the solaris-disk-lookin-ass statussies. (rember that it "likes" internal mmc partition 2 with "s1 t0 p2")

Just copying an arm64 kernel doesn't work. Not altogether unexpected, given that mmcblk0p2 starts with

000000 43 48 52 4f 4d 45 4f 53 02 00 00 00 01 00 00 00  >CHROMEOS........<

(with an obvious 64k initial block boundary) and binwalk finds an LZ4 blob at 0x100C8 which decompresses to a kernel image.

This puts the "search for the Linux kernel" paragraph at an 0/2 – the legacy-bootable flag doesn't do anything, and the partition contains a ChromeOS boot bundle, not a kernel.

Not altogether helpful, except I can grep out the full branding string –

Linux version 4.19.272-14690-gda0c1392f4b0 (chrome-bot@chromeos-release-builder-us-central1-b-x32-59-cvr8) (Chromium OS 16.0_pre475826_p20230103-r7 clang version 16.0.0 (/var/tmp/portage/sys-devel/llvm-16.0_pre475826_p20230103-r7/work/llvm-16.0_pre475826_p20230103/clang 11897708c0229c92802e747564e7c34b722f045f)) #1 SMP PREEMPT Sun Apr 16 19:38:55 PDT 2023

Which is somehow 2023-04 on this 2019 laptop? And a ChromiumOS prelease? Maybe this is why it was in developer mode.

# how is pointar formed kernal loaded?

Device       Start  Sectors Size Type                  Name       Attrs
mmcblk0p11 64 16384 8M unknown RWFW Type-UUID=CAB6E88E-ABF3-4102-A07A-D4BB9BE3C1D3 mmcblk0p6 16448 1 512B ChromeOS kernel KERN-C GUID:52,53,54,55 mmcblk0p7 16449 1 512B ChromeOS root fs ROOT-C mmcblk0p9 16450 1 512B ChromeOS reserved reserved mmcblk0p10 16451 1 512B ChromeOS reserved reserved mmcblk0p2 20480 32768 16M ChromeOS kernel KERN-A GUID:49,56 mmcblk0p4 53248 32768 16M ChromeOS kernel KERN-B GUID:48,56 mmcblk0p8 86016 32768 16M Microsoft basic data OEM mmcblk0p12 249856 65536 32M EFI System EFI-SYSTEM LegacyBIOSBootable mmcblk0p5 315392 4194304 2G ChromeOS root fs ROOT-B mmcblk0p3 4509696 4194304 2G ChromeOS root fs ROOT-A mmcblk0p1 8704000 52359120 25G Microsoft basic data STATE
mmcblk0p1 8704000 52359120 25G Microsoft basic data STATE mmcblk0p2 20480 32768 16M ChromeOS kernel KERN-A GUID:49,56 mmcblk0p3 4509696 4194304 2G ChromeOS root fs ROOT-A mmcblk0p4 53248 32768 16M ChromeOS kernel KERN-B GUID:48,56 mmcblk0p5 315392 4194304 2G ChromeOS root fs ROOT-B mmcblk0p6 16448 1 512B ChromeOS kernel KERN-C GUID:52,53,54,55 mmcblk0p7 16449 1 512B ChromeOS root fs ROOT-C mmcblk0p8 86016 32768 16M Microsoft basic data OEM mmcblk0p9 16450 1 512B ChromeOS reserved reserved mmcblk0p10 16451 1 512B ChromeOS reserved reserved mmcblk0p11 64 16384 8M unknown RWFW Type-UUID=CAB6E88E-ABF3-4102-A07A-D4BB9BE3C1D3 mmcblk0p12 249856 65536 32M EFI System EFI-SYSTEM LegacyBIOSBootable

This is how the internal flash is partitioned, Shockingly, this just about matches the layout I saw in 012a. Installing Debian on the Lenovo 300e 2nd-gen Chromebook (Intel), but notice how the logical partitions are in, effectively, random order.

A few things jump out here: the four 1-sector parts are all zero-filled. Why aren't they simply Not There? who knows.

Partition 8 (OEM) is a completely empty ext4, mounted on /usr/share/oem under ChromeOS. The purpose of this is similarly unclear.

Partition 11 is of a type unknown to the fdisk distributed with the system. The only non-forum non-code Google result (note also how it's to-a-commit instead of main which reads, to me, like "no public links to this at all") for the UUID calls it ChromeOS firmware. I've taken the liberty to teach fdisk about this (made significantly more annoying by the userland being fucking armhf; admittedly they do say

User ABI
arm

, but the "arm" ABI is hard-dead, so).

This would presumably be where the second U-Boot is chainloaded from (RWFW – read/writeable firmware?). But's also zero-filled, so the first 10M of the flash is zeroes.

Partition 12 (EFI-SYSTEM) isn't actually, but it is a 6M-used FAT with a 110B u-boot/boot.scr.uimg identified as "u-boot legacy uImage" whose semantic content appears to be setenv kernelpart 2, setenv rootpart 3 and a vmlinuz.uimg.A which is a device tree – nice, but we already have a device tree in procfs. Are they any different?

Yeah. This device tree has a kernel inside. Not as a joke, but as

/dts-v1/;

/ {
	timestamp = <0x5cc03b66>;
	description = "Chrome OS kernel image with one or more FDT blobs";
	#address-cells = <0x01>;

	images {
		kernel@1 {
			data = <0x4224d18 0x6470b909 0x841600c1 0x4d5a0091			type = "kernel_noload";
			arch = "arm64";
			os = "linux";
			compression = "lz4";
			load = <0x00>;
			entry = <0x00>;
		};

with 1448960 integers, for a total of 5660KiB. There's also a few description = "mt8173-oak-rev5.dtb";-style fdt@N entries but they all add up to 350k. And they're all SHA1-checksummed but the kernel isn't. The branding for this one is

Linux version 3.18.0-12341-g91e1dfd (chrome-bot@chromeos-factory-us-central1-b-x32-31-497v) (gcc version 4.9.x 20150123 (prerelease) (4.9.2_cos_gg_2d511e9_4.9.2-r122) ) #1 SMP PREEMPT Wed Apr 24 03:31:08 PDT 2019

which matches the shipped version documented in the big table; conversely, KERN-B is

Linux version 4.19.272-14688-g23c63bd32a8a (chrome-bot@chromeos-release-builder-us-central1-c-x32-90-i5ts) (Chromium OS 16.0_pre475826_p20230103-r7 clang version 16.0.0 (/var/tmp/portage/sys-devel/llvm-16.0_pre475826_p20230103-r7/work/llvm-16.0_pre475826_p20230103/clang 11897708c0229c92802e747564e7c34b722f045f)) #1 SMP PREEMPT Wed Apr 5 00:00:28 PDT 2023

which is 2 commits/11 days behind the KERN-A from the previous sexion, suggesting that this full 2023 ChromiumOS pre-release image(?) randomly includes a completely unrelated 2019 kernel.

This system's /proc/device-tree/compatible precisely matches conf@9's compatible string, pointing to fdt@9, described as mt8173-elm-hana.dtb [decompiled].

Regardless of how odd the partitioning scheme is, it high-lights type-specific bits set in the boot bundle partitions – just copying the boot bundle to a ChromeOS kernel partition on the SD card behaved identically to copying the raw kernel (s0 t0 p0, unchecked) – so by exhaustively testing all the combinations, I arrived at the following table with a "fake" boot bundle (/sys/firmware/log outlined).

GUID:49
instant reset to the developer mode warning screen
GptNextKernelEntry looking at new prio partition 2
GptNextKernelEntry s0 t0 p2
GptNextKernelEntry no more kernels
VbTryLoadKernel() LoadKernel() = 65551
VbSetRecoveryRequest(91)
VbBootDeveloper() - no kernel found on USB
GUID:56
same
GptNextKernelEntry looking at new prio partition 2
GptNextKernelEntry s1 t0 p0
GptNextKernelEntry no more kernels
GUID:49,56
significant delay before returning to the warning screen
GptNextKernelEntry looking at new prio partition 2
GptNextKernelEntry s1 t0 p2
GptNextKernelEntry likes partition 2
Found kernel entry at 411648 size 81920
Checking key block signature...
   - sig_size=512, expecting 512 for algorithm 8
In RSAVerify(): Padding check failed!
In RSAVerify(): Hash check failed!
Invalid key block signature.
Verifying key block signature failed.
Checking key block hash only...
   - sig_size=256, expecting 256 for algorithm 4
Kernel preamble is good.
Key block valid: 0
Combined version: 65538
   - sig_size=256, expecting 256 for algorithm 4
In RSAVerify(): Hash check failed!
Kernel data verification failed.
Marking kernel as invalid.
GptNextKernelEntry looking at new prio partition 2
GptNextKernelEntry s1 t0 p2
GptNextKernelEntry no more kernels
GUID:48,56
same
GptNextKernelEntry looking at new prio partition 2
GptNextKernelEntry s1 t0 p1
GptNextKernelEntry likes partition 2
…
GptNextKernelEntry looking at new prio partition 2
GptNextKernelEntry s1 t0 p1
GptNextKernelEntry no more kernels

If bundles copied verbatim from /dev/mmcblk0p2 are "real", then I made "fake" by replacing the kernel with an LZ4ed Debian one ({ head -c 0x100C8 mmcblk0p2; lz4 -9 < vmlinuz-6.6.11-arm64; } > mmcblk0p2.fake).

Booting fakes with a measurable-but-recoverable behaviour is crucial because real bundles hard-hang the system in the black screen. According to ChromiumOS Docs - Debug Button Shortcuts, Devices With Keyboards there are at least a few combos that may've been able to trigger a warm re-boot, but they all start with alt+🔊 which is treated as the Magic SysRq key – off by default, enable it yourself – so no logs from that one.

I'm assuming it either doesn't get a rootfs or gets a bogus one, and thus panicks instantly. No log in the firmware survives the reboot, it doesn't initialise the display, and the resistors that are in stock and would let me construct the CCD cable that may show the serial console have been "in packing" for most of this week, so. idk.

Please ignore that I've now twice referenced the Partition attributes table in the GUID Partition Table Wikipedia article, and the type-specific bits for ChromeOS kernel partitions are in the ChromeOS kernel partition attributes table on the next screen down.

Still no active marker tho.

# she debra on my ian 'til I marr her dock

Looks like I'd retroactively buried the lede – KERN-A and KERN-B are also in the device-tree-with-embedded-LZ4ed-kernel format. It was very that the LZ4 blob started at 0x100C8 instead of 0x10000. But there doesn't appear to be a rootfs designator in the device tree, or embedded into the image – not that one would be expected, given the root=PARTUUID=uuid/PARTNROFF=1 in /proc/cmdline, and especially given the U-Boot setenvs of {kernel,root}part in the script.

If we are to accept booting a one-has-to-assume-backdoored kernel, and with ROOT-A and ROOT-B having no flags to distinguish them, three possibilities of picking the rootfs when USB-🙄-booting spring to mind:

  1. it'll pick anything marked ChromeOS root fs,
  2. the 64k CHROMEOS preamble contains the partition number,
  3. the 64k CHROMEOS preamble contains the partition UUID,
  4. a secret, fourth thing.

A quick head -c 0x10000 mmcblk0p[24] | od -tx1 | grep -wC1 cc | grep -w fe confirms the UUID isn't there, at least not in plain. 03 and 05 also don't appear swapped at the same offsets, but who knows.

So, using the "real" boot bundle and the worst rootfs in existence (dpkg-deb -R libc6_2.38-5_arm64.deb faux-root; dpkg-deb -R dash_0.5.12-6_arm64.deb faux-root; ln faux-root/{bin/sh,sbin/init}; mkfs.ext2 -d faux-root faux-root.10M 10M) I observed a significant behavioural change: ctrl+u now goes black for precisely 5 seconds and then reboots! (Still no console so idk why it reboots, and it reboots so no log, but it's definitely doing something.) The same happens regardless of partition number, which strongly hints at option a).

(Later, further testing revealed that the rootfs is always root=PARTUUID=kernel-partition-uuid/PARTNROFF=1 – the partition one after the kernel. The partition type-UUID doesn't matter. What I was observing was either some type of kernel panic, or the bootloader picking the kernel with a partition after it. A quick check also shows that this is a kernel-only (mount(8) doesn't understand it) syntax, naturally authored by an @chromium.org address specifically for this use-case.

So: secret, fourth thing. One could say that, knowing this, Linux kernel boots from its corresponding rootfs partition makes sense. But without that knowledge it means nothing at all — ½/3.)

Emboldened, I copied over the 2G ROOT-A instead at an incredible pace of 3.3M/s. (During this I discovered that if you pause the small looped MP4 of an animation on the OOBE screen, chrome goes from two processes at >80% CPU each to just one at 10%.) This yields a black screen for the same 5s,

top left corner: chrome logo, chrome; middle of screen: throbber next to "Your system is repairing itself.  Please wait."

for 3-10s, and only then a reboot, after which my accessibility settings were globally reset.

Some fiddling with that rootfs yielded

diff --no-dereference -ru {orig,new}/sbin/chromeos-boot-alert
--- orig/sbin/chromeos-boot-alert	2024-01-20 03:18:41.000000000 +0100
+++ new/sbin/chromeos-boot-alert	2024-01-20 03:22:26.000000000 +0100
@@ -151,6 +151,9 @@
 # Prints message before starting to rebuild a corrupted stateful partition.
 mode_self_repair() {
   show_assets_message "self_repair"
+  id >> "$TTY"
+  bash < "$TTY" >> "$TTY" 2>&1 &
+  sleep 4
 }
 
 # Prints a message telling the user that developer mode has been disabled for
The same screen, but in the top there's an overlaid shell with id output, prompt, and successful ls execution

which was slow as shit (on the order of 2cps max input speed) and still rebooted after a few seconds, but.

The real break-through was

Only in orig/etc/init: boot-splash.conf
diff '--color=auto' --no-dereference -ru {orig,new}/etc/init/startup.conf
--- orig/etc/init/startup.conf	2023-04-17 06:31:09.000000000 +0200
+++ new/etc/init/startup.conf	2024-01-20 03:31:08.000000000 +0100
@@ -10,4 +10,5 @@
 
 start on stopped pre-startup
 
-exec chromeos_startup
+#exec chromeos_startup
+exec frecon --enable-gfx --enable-vt1 --enable-vts
diff '--color=auto' --no-dereference -ru {orig,new}/etc/init/ui.conf
--- orig/etc/init/ui.conf	2023-04-17 06:26:19.000000000 +0200
+++ new/etc/init/ui.conf	2024-01-20 03:06:54.000000000 +0100
@@ -35,7 +35,7 @@
 kill timeout 20  # In seconds.
 
 # Uncomment line below to output to VT02
-#console output
+console output
 
 # Directory where session manager logs are written and prefix of files there.
 env UI_LOG_DIR=/var/log/ui
Only in new/sbin: init.new

(The ui.conf diff doesn't do anything. The boot-splash.conf deletion may be exchanged for a startup.conf deletion instead, since it also runs frecon. Naturally, the way to show the "ChromeOS" fade-in is by passing a tty emulator 70 PNGs, in developer mode, and keeping it running afterward.) chromeos_startup is what triggers the self-repair message (rendered is by pango-viewing the background, the localised text, and the throbber to a PNG and giving those to frecon). This yields

shell session formatted identically to all the ones before, findmnt lists the root to be mounted on /dev/mmcblk1p3 top listing, the only processes under init are udevd and frecon/login/bash/top

This high-lights the biggest issue with this system: there is no console. This lede is buried in /proc/cmdline in the HFBITLAND sexion – console= is provided as the first parameter. Opening /dev/console fails with ENODEV. There are no framebuffers (and no loadable fbdev modules), there are no VTs. frecon, which is what provides the pseudo-VTs, draws the teletypes (and the PNGs) by talking to the GPU directly. As in it has /dev/dri/card2 open.

This is why the tty says it's /dev/pts/0 – it's an xterm, but drop the x. So to answer the first question from 012a. Installing Debian on the Lenovo 300e 2nd-gen Chromebook (Intel)TERM=xterm because it is. It's also horrendous and the ptys it gives you barely work (libreadline masks this in bash) – i.a. backspace sends ^H and it's configured for the usual ^?. One syscall to fix, too hard for this trillion-dollar startup. This also explains why you can press ctrl+alt+/ (not the arrow keys) to open "VT" 1/2, even though / are XF86Back/XF86Forward and not F1/F2.

Not even serial? Not even serial. My resistors'd got here and I assembled a hdctools: Chrome OS Hardware Debug & Control Tools, Closed Case Debug (CCD), Communicating with Google Security Chip(GSC), SuzyQ / SuzyQable (no, even they don't know what it is) accd'g to the instruxions in Making your own SuzyQ (though mind the referenced 22k 1% resistor not being real and the breakout they spec seemingly being american-only) more on mastussy.

Device Support says

The “Closed Case Debugging” column in the Chrome OS device list indicates whether CCD is supported. If the device is ARM, the CPU/AP UART works by default in dev mode (you should see a login prompt). x86 devices disable it […]

which implies to me that there's some sort of activity. And the login prompt really smells like "you get console=ttyS0" or at least a getty thereon (this is substantiated by opening ttyS0 working and ttyS[123] EIOing). Indeed, I can debug the Intel-chipped 300e (shows the ttyUSBs, talks on all of them), but not this one. Why? The device list they link to is another version of the big table cited at the top of this page. Indeed, both agree with regards to the column I omitted – Closed Case Debugging. The Intel 300e has a Yes in that column. This Mediatek – nothing. No data.

So another difference between these nominally-identical laptops is that you can debug one but not the other. This one is either a black screen or you've magically done something right and you have a gterm. Of course, I tried to actually run Xorg out of a Debian chroot since there's a GPU exposed, and the best you get is

…
(==) ModulePath set to "/usr/lib/xorg/modules"
(II) The server relies on udev to provide the list of input devices.
	If no devices become available, reconfigure udev or disable AutoAddDevices.
(II) Loader magic: 0x5c61bffef0
(II) Module ABI versions:
	X.Org ANSI C Emulation: 0.4
	X.Org Video Driver: 25.2
	X.Org XInput driver : 24.4
	X.Org Server Extension : 10.0
(EE) dbus-core: error connecting to system bus: org.freedesktop.DBus.Error.FileNotFound (Failed to connect to socket /run/dbus/system_bus_socket: No such file or directory)
(II) xfree86: Adding drm device (/dev/dri/card1)
(II) Platform probe for /sys/devices/platform/soc/13000000.mfgsys-gpu/drm/card1
(II) xfree86: Adding drm device (/dev/dri/card2)
(II) Platform probe for /sys/devices/platform/soc/14000000.clock-controller/drm/card2
(II) xfree86: Adding drm device (/dev/dri/card0)
(II) Platform probe for /sys/devices/platform/vgem/drm/card0
(II) no primary bus or device found
	falling back to /sys/devices/platform/soc/13000000.mfgsys-gpu/drm/card1
(II) LoadModule: "glx"
(II) Loading /usr/lib/xorg/modules/extensions/libglx.so
(II) Module glx: vendor="X.Org Foundation"
	compiled for 1.21.1.11, module version = 1.0.0
	ABI class: X.Org Server Extension, version 10.0
(II) LoadModule: "modesetting"
(II) Loading /usr/lib/xorg/modules/drivers/modesetting_drv.so
(II) Module modesetting: vendor="X.Org Foundation"
	compiled for 1.21.1.11, module version = 1.21.1
	Module class: X.Org Video Driver
	ABI class: X.Org Video Driver, version 25.2
(II) modesetting: Driver for Modesetting Kernel Drivers: kms
(WW) Falling back to old probe method for modesetting
(WW) Falling back to old probe method for modesetting
(II) modeset(G0): using drv /dev/dri/card2
(EE) No devices detected.
(EE)
Fatal server error:
(EE) no screens found(EE)
(EE)
Please consult the The X.Org Foundation support
	 at http://wiki.x.org
 for help.
(EE) Please also check the log file at "/var/log/Xorg.0.log" for additional information.
(EE)
(EE) Server terminated with error (1). Closing log file.

and no, plugging in an HDMI doesn't work, it just doesn't understand the GPU or whatever. I'm no eXorgpert.

Given that neither guide mentions anything remotely close to this, one has to assume that on the "Samsung ARM Chromebook" this is simply not the case, and that it pre-dates this no-console no-framebuffer model.

# an interlude: here's a never-documented-before ctrl+i shortcut :)

overlaid atop the recovery screen, in the top left, is a dump of some firmware variables

This is close to as far as I can get with first-principles debugging since there just isn't really a way to do anything unless everything fully works. If only there were

# a way to leak post-mortem metadata

like when you're bisecting rootfs bootability requirements and you find the cmdline listed in /sys/fs/pstore/console-ramoops-0 (and dmesg-ramoops-0 sometimes(?) but they're equivalent) which contains the entire console output.

(If you know what you're looking for, this is obvious – /proc/consoles consists of

pstore-1             -W- (E  p a)

 but It is all obvious when it is explained to you..)

Which is great, but only works reliably for real co-operated reboots. When you use the hard-reboot alt+ combo (which Debug Button Shortcuts calls

EC reset
Power + Refresh

). you get something to the effect of (cat -A-reformatted):

[    0. 00000] ^Booting Linuh on physicad CPU 0x0000000000 Y0p410fd032]$
^[    0.000000] Hifux versin. 4.!9.272-14690-gd! c13(2f4b0 (chrome-bot@chr.mdos)be,easE-bdilder^Mus%central1-b%x32-59-cvp8) (C(romIum OS 16.0_pre47^U826_p"0230^Q03-r7 clang verSHON 12.0^N0 (/va2/tmp/`ortagd/sys-deve,/l,vi)1^V.0Wpr%474826_p20230103-^R7/uorc/dLVm^M16*0_pre475826_p2023^P103/chanc 1189'708c0229c9280^RE74^W564`7c3^Pb722f045f)) "1 SMP PREEMPT Sun Apr 16 19:38:55 PDT 2023$
[    0.000000] Machine model: COocld Hafa$
[ ^@  0.000000L Malboried early^@optiOn 'Cnnsole'$
[    0.0^P0000M ReSerred memory8 createD @MA memmry pool at 0x00000000b7^P0000 $ qaze 5 MiB$
[    0&000^P00] GF*^@beserved mem: ini4ha,IzeD nOde 6pu_dma_Mem_begio.@"70000 0, compatible id shared-dma,pool$
[ ^@^@ 0*000000] pqci: probing for ck*duit method from DT.$
S  ^@ 0.0000 0] psci:^@PSCIv1.0 d%tected in firMw!2e.$
[    0,000000] psba: Usin^G standard PSAH v0.2 functioj IDr$
K    0.000000^] `sci: MIFRATE_INFO_TIPE not supported*$
[    0.000^P00] psc!: SMC CAllinG^@Confeltion V1.1$
S  ^@ 0. 00000] percpu: Embedded 24 pages/cpu R41080 r81(2 D^R9032 u98304$
[    0.0 0000Y @etected V^IPT ^I-ca#`e .n C@^E0$
[     .000000] CPU features* en`bling workapnunD fob A^RM errata 826319, 827319, 824069^H[    0,000000] CPU fe`turEs: enabline^@workaround fop ABM erratul 843419$
[    0* 00000] APU feaTureS: enAbling sorkaroqnd foR ARM erratui ^X^T%719$
[^@   0,000 00] Built 1 z/n%lists, m/bhLity^@group)nc on.  Todal pages^Z^@1030656$
[ ^@  0.000000U KernEl #/mmand^@line: crOs_seaure con^Sole5 log,Evel=7 inht=/sbin/ijit cros_recure dbM.tr!ce=0x00^V rogt=PARTUUID=fd012a^P$-54ac-dd4'-b773-73df13281aa7/PABTNROFF<0 rootvait rw dm_vdridh^N%rror_beharior=3 dm_Verity,maxZbios=-1 Dm_FerItY.dev_wAit=0 dm="1 vrokt none ro 1$0 40774^V8 veridy pay,maD=ROOT]DDV (ashtrde=#_DEV hashstart=4076468 alg=sha054 r'ot_hexdifest=59&5ac90'd@5cfa3f6fd%f15b166c94025a41ef4abfd0d)c6^Xdb6Ef4a2f62a48 salt=05e2c9a8dc172bc%efe0B899182b436bb89^V09a04^TeAbaaeb5ec07441cf2!122" nohnidrd vt.gdmbalWcqrSor_ddfault=0^@kern_guid=fd012a04-^U4ac%dd47,b573,77df1^Q381aa7 cpuidle.governor=tEo  $

which, given that the power LED goes off for 573ms during this time, one has to assume is DRAM bit-rot.

As cool as observing a theoretical phenomenon everyone knows about but I never expected to see is in the home shop, it's less-than-helpful for trying to ascertain precise messages.

Debug Button Shortcuts also says

FunctionalityShortcut
Warm AP resetAlt + Volume-Up + R
Restart ChromeAlt + Volume-Up + X *
Kernel panic/rebootAlt + Volume-Up + X + X *
Reboot EC but don't boot APAlt + Volume-Up + Down-Arrow
Force EC hibernateAlt + Volume-Up + H
Notes:

and, naturally, I'd tried to apply this for a long time, with alt, the volume up button on the side, and a magick, and it never worked.

It is only much later that it'd occurred to me that by Volume-Up they may mean the 🔊 on the keyboard. That does work! and as long as the ChromiumOS kernel is running, alt+🔊+b reboots and preserves the pstore log in tact, while alt+🔊+c crashes and preserves the pstore log in tact.

But alt+🔊+r also reboots with pstore ok, and not only is that not a useful SysRq (Turns off keyboard raw mode […]), but it works regardless of a kernel running or said kernel having any hardware. So this is documented as a SysRq but just isn't, and is another, more warmer, reboot.

It's no actual interactive console, but it's a way to reliably probe whatever the fuck was happening in the black box. Real green-field shit.

# a brief ado about systemd

Given the above, it is tempting to boot a Debian rootfs with KERN-A – previously just a black screen – and see what falls out. Don't – you will first get

[    1.95725] ChbomIuM OS LSM: sb_mou.t ddv=sysf3 type=s)Qfs flAgs-xe
   !.9047)8\ systemd[1]: F@i,ed to mount sysfs (4ypa sysfs) on /sYs (MC_NOSUID|MS_NODEV|MS_NOEXEC ""(: Too eany levels of symbklic links
[    1.94304] Chromi5m OR HSM: sb_moent MotNt path sith syml)nks prohibHded obj="/syr/kErned/secqrity" pid=1 cMdline=.sbin/init cros_secure"
[   1.91301] CHROlium OS LSM: 3b_mound dev=#EcuRityfs tyPa<Securityfs blacs0xe
    1.957065M systeed[]* FrEezing exea%tiOn.[   31.19(945] bl_dix`d: `ira"ling

wherein "Chromium OS LSM: Mount path with symlinks prohibited" appears to be from the eponymous module which prevents mounting on paths which were resolved via symlinks, and after you strace systemd pid1 you will find out that it does

mount("proc", "/proc", "proc", ...)

but

open("/sys", O_NOFOLLOW) = 0
mount("sysfs", "/proc/self/fd/0", "sysfs", ...)

and

open("/sys/kernel/security", O_NOFOLLOW) = 0
mount("securityfs", "/proc/self/fd/0", "securityfs", ...)

as its own symlink mitigation, which makes the latter two ELOOP, as seen in the log.

Given that it does not remount these one may then be tempted to simply gift them. So after you

mount 20 API filesystems (well, fewer in the end – there's some fallbacks) from /sbin/init before execing systemd
#!/bin/sh
echo dupa dupa dupa dupa dupa dupa dupa > /dev/kmsg
/bin/mount -t sysfs sysfs /sys > /dev/kmsg 2>&1
/bin/mount -t securityfs securityfs /sys/kernel/security > /dev/kmsg 2>&1
/bin/mount -t proc proc /proc > /dev/kmsg 2>&1
/bin/mount -t tmpfs tmpfs /tmp > /dev/kmsg 2>&1
/bin/mount -t tmpfs tmpfs /run > /dev/kmsg 2>&1
mkdir /run/lock >/dev/kmsg 2>&1
/bin/mount -t tmpfs tmpfs /run/lock > /dev/kmsg 2>&1
/bin/mount -t devtmpfs -o mode=0755 devtmpfs /dev > /dev/kmsg 2>&1
mkdir /dev/pts > /dev/kmsg 2>&1
mkdir /dev/shm > /dev/kmsg 2>&1
/bin/mount -t tmpfs -o mode=01777 tmpfs /dev/shm > /dev/kmsg 2>&1
mnt() {
	/bin/mount -t "$@" >/dev/kmsg 2>&1
	}
mnt cgroup2 -o nsdelegate,memory_recursiveprot cgroup2 /sys/fs/cgroup ||
mnt cgroup2 -o nsdelegate cgroup2 /sys/fs/cgroup ||
mnt cgroup2 cgroup2 /sys/fs/cgroup ||
mnt tmpfs tmpfs /sys/fs/cgroup
mnt devpts -o mode=0620,gid=5 devpts /dev/pts
mnt cgroup2 -o nsdelegate cgroup2 /sys/fs/cgroup/unified ||
mnt cgroup2 cgroup2 /sys/fs/cgroup/unified
mnt cgroup -o none,name=systemd,xattr cgroup /sys/fs/cgroup/systemd || 
mnt cgroup -o none,name=systemd cgroup /sys/fs/cgroup/systemd 
mnt pstore pstore /sys/fs/pstore
mnt bpf -o mode=0700 bpf /sys/fs/bpf
#/bin/sed s/^/'verbose debug'/ /proc/cmdline > /etc/cmdline
#mount --bind /etc/cmdline /proc/cmdline
#echo zqpa zqpa zqpa zqpa zqpa zqpa zqpa > /dev/kmsg
#exec /usr/lib/systemd/systemd --log-level=debug
#/bin/mount -t proc proc /media
#while :; do /bin/cp /media/self/mounts /dev/kmsg; done &
#( strace -fp 1 -o /dev/kmsg & ) &
#sleep 0.5
exec /lib/systemd/systemd --log-level=debug "$@"
(sleep 3 && sync /) >/dev/kmsg 2>&1 &
exec /bin/strace -DDD -o /strace /lib/systemd/systemd --log-level=debug "$@"

you will continue to see a black screen and on reset the pstore will contain

Some mount warnings, the sytemd "running in system mode" status line, "Dtetected architecture arm64", "Hostname set to <chwast>", "Chromium OS LSM: bpf syscall blocked; Mount path with symlinks prohibited: /tmp (sd-gens)", "Failed to fork off sandboxing anvironment for executing gnereators: Protocol error"

So this kernel is just fundamentally incompatible with systemd (at least as-configured). woulda bin an easy short-cut, but alas

This, and the ChromiumOS kernels not supporting kexecing, means that we need to find

# a way to pack a kernel to boot

first (naturally, this ticks off the "backdoored kernel" issue as well). The frecon /etc/issue says something about booting a self-signed kernel, so this ought to be viable; luckily, crossystem output includes

fw_vboot2 = 1	# [RO/int] 1 if firmware was selected by vboot2 or 0 otherwise

so by applying my incredible monkey brain (

root@chwast:~# apt search vboot2
Sorting... Done
Full Text Search... Done
root@chwast:~# apt search vboot
Sorting... Done
Full Text Search... Done

boot-kernel-utils/unstable,now 0~R106-15054.B-1 arm64
  Chrome OS verified boot utils required to sign kernels

boot-utils/unstable,now 0~R106-15054.B-1 arm64
  Chrome OS verified u-boot utilities

) and rembering that i last saw this toolchain in InstallingDebianOn/Samsung/ARMChromebook as

# Declare the kernel flags:
cat > ${MNT}/boot/kernel.flags <<EOF
console=tty1 printk.time=1 nosplash rootwait root=${DEV}p3 rw rootfstype=ext4 lsm.module_locking=0
EOF
# Sign the kernel:
cat > ${MNT}/boot/sign-kernel.sh <<EOF
vbutil_kernel --repack /boot/vmlinuz.signed --keyblock \
  /usr/share/vboot/devkeys/kernel.keyblock --version 1 \
  --signprivate /usr/share/vboot/devkeys/kernel_data_key.vbprivk \
  --config /boot/kernel.flags --oldblob /boot/oldblob
EOF

this can be trivially reproduced (after installing boot-kernel-utils, which suffers from recommending 50M of javascript via a -docs package) by re-packing KERN-A:

vbutil_kernel --repack orig.repacked \
  --keyblock    /usr/share/vboot/devkeys/kernel.keyblock \
  --signprivate /usr/share/vboot/devkeys/kernel_data_key.vbprivk \
  --config cmdline \
  --oldblob /dev/mmcblk0p2
cp orig.repacked /dev/mmcblk1p9

which does boot as expected and uses the cmdline from cmdline. binwalk didn't find this, but the boot bundles, after the device tree payload, end with a string sexion containing the cmdline:

54372340  >sion.load.entry.algo.kernel.fdt.<
54372400  >compatible.timestamp.value......<
54372440  >................................<
*
54400000  >console= loglevel=7 init=/sbin/i<
54400040  >nit cros_secure drm.trace=0x106 <
54400100  >root=PARTUUID=%U/PARTNROFF=1 roo<
54400140  >twait rw dm_verity.error_behavio<
54400200  >r=3 dm_verity.max_bios=-1 dm_ver<
54400240  >ity.dev_wait=0 dm="1 vroot none <
54400300  >ro 1,0 4077568 verity payload=RO<
54400340  >OT_DEV hashtree=HASH_DEV hashsta<
54400400  >rt=4077568 alg=sha256 root_hexdi<
54400440  >gest=[…
54400640            …]" noinitrd vt.global_<
54400700  >cursor_default=0 kern_guid=%U cp<
54400740  >uidle.governor=teo  ............<
54401000  >................................<
*
100000000

with the %Us being replaced with the boot bundle's partition's UUID by the boot-loader. A cute scheme, which does work and does boot, so the tool-chain works. Even if I don't know why you'd want to sign with those particular parts of some key; doesn't really matter.

So, by plumbing the depths of the vbutil_kernel usage string (or its equivalent 🙄 manual) we can observe that, given vbutil_kernel --get-vmlinuz /dev/mmcblk0p2 --vmlinuz-out orig, orig contains the whole device tree with the embedded kernel &c. Why do they call it a vmlinuz then? doesn't matter, I s'pose.

And by filling out the non-re-packing, I got to

printf '\0' > bootloader
vbutil_kernel --pack /dev/mmcblk1p9 \
  --keyblock    /usr/share/vboot/devkeys/kernel.keyblock \
  --signprivate /usr/share/vboot/devkeys/kernel_data_key.vbprivk \
  --version 1 \
  --vmlinuz orig \
  --bootloader bootloader \
  --config cmdline \
  --arch arm64

wherein it's similarly unclear to me what the version's supposed to be or mean. I copied 1 from InstallingDebianOn/Samsung/ARMChromebook because it's required for --pack. The architecture defaults to "x86" regardless of the host.

As inferrable from above, the bootloader bit is null in the shipped kernel, but you can't spec an empty file, so a file with a zero is minimal. This doesn't appear to be used by our bootloader, but it lives in a block after the cmdline.

So, near as I can tell, the boot bundle consists of:

  1. 64k CHROMEOS parameter(?) block
  2. device tree containing the kernel and device trees matched to the host by the bootloader – vboot-utils calls this bit vmlinuz
  3. cmdline string (with %UUID substitution, cros_secure also prepended if it's not in there already)
  4. unused "bootloader" block

(Even if you replace the kernel carefully without re-signing the bundle, you get honked at and /sys/firmware/log has the same "In RSAVerify(): Padding check failed!" error as the first time.)

# when im in an EXacutif'^@gejarators competition and my opponent is Hifux:

Now we just need to get an appropriate kernel to stuff into 2.. The Debian kernel is unsuitable as-shipped because it's fully modular and we don't get an initrd.

Naturally, fixing this means apt sourceing the latest kernel (6.6.11-1), copying /boot/config-6.6.11-arm64 to .config, and either dealing with all the Kconfig UIs actively fighting you when you try to build in a component with modularised dependencies (why can't the computer also build them in instead of just complaining that they're modular and doing nothing? unsolvable problem) or just (sed -i s/=m$/=y/ .config) building every module into the kernel image.

Unfortunately, if you do the latter, not only does make -j25 ARCH=arm64 LLVM=1 Image take eons (like an hour), it produces an intermediate 1.7G-sized vmlinux, and the output arch/arm64/boot/Image (which according to make ARCH=arm64 help is the Uncompressed kernel image) is 154M (86M LZ4ed). This would be perfect if it were bootable; alas, it honks with

Kernel body doesn't fit in memory.

This unfortunately means manually enabling every Mediatek-specific feature ('/\(MEDIATEK\|MTK\).*=m/s/m$/y/'), all framebuffers, all the blockdev drivers ('/BLOCK.*=m/s/m$/y/') and ext4 ('s/CONFIG_EXT4_FS=m/CONFIG_EXT4_FS=y/'). This is mind-numbing. A final .config (and a diff from the Debian one) are at the end. Here's the high-lights.

There's a Platform selection menu at the top. I unselected everything sans MediaTek SoC Family.

There's a whole-ass Platform support for Chrome hardware sexion, with most of it turned off or modularised in the Debian config.

Drivers for ChromeOS systems are disguised as "CHROMEOS", "CROS", and "GOOGLE". A significant proportion of these depend on X86.

In the File systems, Miscellaneous filesystems sexion there's Persistent store support (CONFIG_PSTORE). This is crucial, since this is what provides the logs in /sys/fs/pstore. I cranked that shit.

CONFIG_CHROMEOS_PSTORE depends on X86. This is rather surprising, and proves how mind-numbing of an activity this is because I have it in my notes twice. ARM chromebooks appear to use some standard pstore method which is covered by a generic driver.

This yields a much more realistic 31M Image. There's probably a, uh, right way to pack it into the device tree. Alas, as demonstrated in the how is pointar formed kernal loaded? sexion, device trees can be decompiled (though not unambiguously, since this time the kernel blob was formatted as data = [04 22 […] 74 00];):

$ tail -c +$(( 0x10000 + 1)) mmcblk0p2 | dtc -I dtb -O dts > mmcblk0p2.dts
$ csplit mmcblk0p2.dts '/data =/' '/type =/'
161
26119768
7957930
$ head xx00 xx02
==> xx00 <==
/dts-v1/;

/ {
	timestamp = <0x643cb38f>;
	description = "Chrome OS kernel image with one or more FDT blobs";
	#address-cells = <0x01>;

	images {

		kernel@1 {

==> xx02 <==
			type = "kernel_noload";
			arch = "arm64";
			os = "linux";
			compression = "lz4";
			load = <0x00>;
			entry = <0x00>;
		};

		fdt@1 {
			description = "mt2712-evb.dtb";

$ { cat xx00;
    printf 'data = ['; lz4 < .../Image | od -An -tx1 -v | tr -d '\n'; printf '];\n';
    cat xx02; } > new
$ dtc -I dts -O dtb < new > new.dtb

(This is hopefully rather clear: splitting the file before and after the first data = line – the kernel's – then pasting it back together with said line replaced with a hex dump from the LZ4ed image. The first two steps don't need to be repeated and the latter two can be trivially pipelined together.)

So, after several identical signing rounds (with orig replaced with new.dtb), rebooting to a black screen, letting it rip for a bit, then +power-buttoning:

Linux version 6.6.11 (nabijaczlweli@tarta) (Debian clang version 18.0.0 ...)

It is now that I discovered that alt+🔊+r works, so full log. It's rather inconsequential, but the interesting bits are

[    0.000000] Linux version 6.6.11 (nabijaczleweli@tarta) (Debian clang version 18.0.0 (++20231231112334+c7c912cff945-1~exp1~20231231112352.433), Debian LLD 18.0.0) #8 SMP Mon Jan 22 03:42:58 CET 2024
[    0.000000] KASLR disabled due to lack of seed
[    0.000000] Machine model: Google Hana
[    0.000000] efi: UEFI not found.
[    0.000000] Reserved memory: created DMA memory pool at 0x00000000b7000000, size 5 MiB
[    0.000000] OF: reserved mem: initialized node vpu_dma_mem_region@b7000000, compatible id shared-dma-pool
[    0.000000] OF: reserved mem: 0x00000000b7000000..0x00000000b74fffff (5120 KiB) nomap non-reusable vpu_dma_mem_region@b7000000
[    0.000000] NUMA: No NUMA configuration found
[    0.000000] Initmem setup node 0 [mem 0x0000000040000000-0x000000013fffffff]

[    0.011840] smp: Brought up 1 node, 4 CPUs
[    0.011902] SMP: Total of 4 processors activated.
[    0.011910] CPU features: detected: 32-bit EL0 Support
[    0.011917] CPU features: detected: 32-bit EL1 Support
[    0.011925] CPU features: detected: CRC32 instructions
[    0.012042] CPU: All CPU(s) started at EL2

[    0.044906] Serial: AMBA PL011 UART driver
[    0.045354] pstore: Using crash dump compression: deflate
[    0.045368] printk: console [ramoops-1] enabled
[    0.045780] pstore: Registered ramoops as persistent store backend
[    0.045791] ramoops: using 0x100000@0xb1f00000, ecc: 0

– 4G of RAM, 4 CPUs, clang trunk works, pstore works, so the device tree also works.

It does, however, end with a litany of expired time-outs for like every device –

[   10.976470] mtk-scpsys 10006000.scpsys: vdec: clk unavailable
[   10.976747] mt6577-uart 11002000.serial: Can't get uart clock
[   10.978161] mediatek-hdmi-ddc 11012000.i2c: get ddc_clk failed: fffffffffffffdfb ,
[   10.978447] mediatek-cec 10013000.cec: Failed to get cec clock: -517
[   10.979634] mtk_vpu 10020000.vpu: get vpu clock failed
[   10.979742] mtk-cpufreq mtk-cpufreq: failed to initialize dvfs info for cpu0
[   10.982016] platform 10212000.mailbox: deferred probe pending
[   10.982039] platform 11290000.usb-phy: deferred probe pending
[   10.982055] platform 10209100.hdmi-phy: deferred probe pending
[   10.982069] platform 1401e000.pwm: deferred probe pending
[   10.982083] platform backlight: deferred probe pending
[   10.982097] platform 1000d000.pwrap: deferred probe pending

Unclear to me what "deferred probe pending" means (do I need to buy a driver?); this is the hard part.

Actually the hard part turned out to be "getting Hifux to execute an init from an embedded »early userspace« initramfs" (apparently it wants /init (rdinit=) instead of /sbin/init (init=) and only runs it if it exists and silently ignores everything if not; I only got to this with significant debugging), since How to troubleshoot deferred probe issues in Linux notes commit d090b70ede02: driver core: add deferring probe reason to devices_deferred property, which 6.6 includes, puts the reason into /sys/kernel/debug/devices_deferred – while we aren't at a real interactive userland yet (and can't embed one due to the Linux image limit, and the "bootloader" block doesn't appear to be forwarded as an initrd), a minimal "cp /s/k/d/d_d /dev/kmsg"-style cpio is 1.7M zstded – dash, mount, libc6, libblkid1, libmount1, libpcre2, libselinux1 debs, a Makefile

.ONESHELL:
_:
	mkdir -p root/dev root/proc root/sys root/dev
	for f in *.deb; do
		dpkg-deb -R $$f root/
		rm -r root/DEBIAN
	done
	rm -r root/usr/share root/usr/lib/aarch64-linux-gnu/gconv
	chmod u-s root/usr/bin/*
	ln -f init root/

a simple init script to log the file every second

#!/bin/sh -x
mount -t devtmpfs devtmpfs /dev
exec > /dev/console < /dev/console 2>&1
#exec > /dev/kmsg 2>&1
mount -t proc proc /proc
mount -t sysfs sysfs /sys
mount -t debugfs debugfs /sys/kernel/debug
printf '%s\n' /sys/kernel/debug/*
cat() (
	set +x
	while IFS= read -r l; do
		printf '%s\n' "$l"
	done < "$1"
)
cat /proc/uptime > /dev/kmsg
set +x
u=0
one() {
	while :; do
		IFS=. read -r u2 rest < /proc/uptime
		[ $u2 -eq $u ] && continue
		u=$u2
		echo $u.$rest > /dev/kmsg
		cat /sys/kernel/debug/devices_deferred > /dev/kmsg
		break
	done
}
one; one; one; one; one; one; one; one; one; one

and CONFIG_INITRAMFS_SOURCE="[…]/faux/root", with a little ergonomic panic=1 yields

[   23.083931] Run /init as init process
[   23.145830] 23.14 69.15
[   23.181712] mtk-cpufreq	
[   23.209648] backlight	platform: supplier fixedregulator2 not ready
[   23.284973] 11230000.mmc	platform: wait for supplier /soc/pwrap@1000d000/mt6397/mt6397regulator/buck_vio18
[   23.387265] 11240000.mmc	platform: wait for supplier /soc/pwrap@1000d000/mt6397/mt6397regulator/ldo_vmc
[   23.501618] 1401d000.dpi	mediatek-dpi: Failed to get bridge
[   23.572462] 11260000.mmc	platform: wait for supplier /soc/pwrap@1000d000/mt6397/mt6397regulator/ldo_vgp3
[   23.681601] 1401b000.dsi	platform: wait for supplier /soc/i2c@11007000/edp-bridge@8/ports/port@0/endpoint
[   23.794384] 14025000.hdmi	
[   23.837822] panel	platform: wait for supplier /soc/i2c@11007000/edp-bridge@8/ports/port@1/endpoint[   32.777145] Kernel panic - not syncing: Attempted to kill init! exitcode=0x00000000

which naturally points to CONFIG_REGULATOR_MT6397. Re-building, re-signing, re-rebooting again shows

[   24.315189] mtk-cpufreq	
[   24.342813] backlight	platform: supplier fixedregulator2 not ready
[   24.412245] 1401d000.dpi	mediatek-dpi: Failed to get bridge
[   24.473247] 11260000.mmc	platform: supplier fixedregulator0 not ready
[   24.559623] 1401b000.dsi	platform: wait for supplier /soc/i2c@11007000/edp-bridge@8/ports/port@0/endpoint
[   24.665648] 14025000.hdmi	
[   24.708081] panel	platform: wait for supplier /soc/i2c@11007000/edp-bridge@8/ports/port@1/endpoint

which is already quite good, with both MMCs showing up

[   17.525454] mmcblk0: mmc0:e624 SU08G 7.40 GiB
[   17.688381]  mmcblk0: p1 p5 p6 p9 p10 p15

[   18.167701] mmc1: new HS400 MMC card at address 0001
[   18.269237] mmcblk1: mmc1:0001 DA4032 29.1 GiB
[   18.379454] GPT:partition_entry_array_crc32 values don't match: 0x9d2a6879 != 0xef8dd269
[   18.499823] GPT:Primary header thinks Alt. header is not at the end of the disk.
[   18.648561] GPT:61063167 != 61071359
[   18.648566] GPT:Alternate GPT header not at the end of the disk.
[   18.648569] GPT:61063167 != 61071359
[   18.735943] GPT: Use GNU Parted to correct GPT errors.
[   18.735978]  mmcblk1: p1 p2 p3 p4 p5 p6 p7 p8 p9 p10 p11 p12
[   18.853013] mmcblk1boot0: mmc1:0001 DA4032 4.00 MiB
[   18.963993] mmcblk1boot1: mmc1:0001 DA4032 4.00 MiB
[   19.088099] mmcblk1rpmb: mmc1:0001 DA4032 16.0 MiB, chardev (238:0)

(though note the now-randomised MMC order, and the explicit-by-name parted call-out. more like GNU Partition Table!) but they still want, uh

$ grep -A1 fixedregulator mt8173-elm-hana.dts
		fixedregulator0 {
			compatible = "regulator-fixed";
$ grep -r regulator-fixed | grep c:
drivers/regulator/fixed.c:              .compatible = "regulator-fixed",
$ grep fixed drivers/regulator/Makefile
obj-$(CONFIG_REGULATOR_FIXED_VOLTAGE) += fixed.o

CONFIG_REGULATOR_FIXED_VOLTAGE:

[   24.483011] mtk-cpufreq	
[   24.522681] 1401d000.dpi	mediatek-dpi: Failed to get bridge
[   24.587404] 1401b000.dsi	platform: wait for supplier /soc/i2c@11007000/edp-bridge@8/ports/port@0/endpoint
[   24.696106] 14025000.hdmi	
[   24.739520] panel	platform: wait for supplier /soc/i2c@11007000/edp-bridge@8/ports/port@1/endpoint

so

$ grep -A1 edp-bridge mt8173-elm-hana.dts
			edp-bridge@8 {
				compatible = "parade,ps8640";
$ grep -r parade,ps8640
drivers/gpu/drm/bridge/parade-ps8640.c: { .compatible = "parade,ps8640" },
$ grep ps8640 drivers/gpu/drm/bridge/Makefile
obj-$(CONFIG_DRM_PARADE_PS8640) += parade-ps8640.o
$ grep DRM_PARADE_PS8640 .config
CONFIG_DRM_PARADE_PS8640=y

hm

$ grep -m1 -A1 11007000 mt8173-elm-hana.dts
		i2c@11007000 {
			compatible = "mediatek,mt8173-i2c";
$ grep -r mediatek,mt8173-i2c | grep c:
drivers/i2c/busses/i2c-mt65xx.c:        { .compatible = "mediatek,mt8173-i2c", .data = &mt8173_compat },
$ grep i2c-mt65xx drivers/i2c/busses/Makefile
obj-$(CONFIG_I2C_MT65XX)        += i2c-mt65xx.o
$ grep CONFIG_I2C_MT65XX .config
CONFIG_I2C_MT65XX=m

which still doesn't actually get us the screen due to the unchanging bridge issues, but

# Mein Gott Leute, mein neu Linux hat mir einfach erlaubt dass ich MMC booten darf! Wie cool ist das bitte? Jetzt zocke ich Systemd und boote von MMC! Yippee!

But only after disabling CONFIG_INITRAMFS_SOURCE because if there is an initramfs embedded, even if you don't unpack it (noinitrd), the rootfs mount willl ENOENT regardless, which means you can get a panic with a blockdev dump listing available partition UUIDs when root= already contains one of them:

[   24.530570] VFS: Cannot open root device "PARTLABEL=chwast-root" or unknown-block(179,778): error -2
                                         (or "PARTUUID=b8c64d3b-7752-4132-a244-5a85fc14157a")
                                         (or "0b3:0030a")
[   24.639808] Please append a correct "root=" boot option; here are the available partitions:
[   24.739687] b300        30535680 mmcblk2 
[   24.739696]  driver: mmcblk
[   24.820866]   b301        26179560 mmcblk2p1 d8331ad0-ed78-f442-87f4-78df0130895a[   26.001792]   b30c           32768 mmcblk2p12 bcf61070-764a-004f-8abd-590a44996a91
[   26.001798] 
[   26.110005] 0b3:00100       4096 mmcblk2boot0 
[   26.110012]  (driver?)
[   26.191177] 0b3:00200       4096 mmcblk2boot1 
[   26.191183]  (driver?)
[   26.272335] 0b3:00300    7761920 mmcblk1 
[   26.272342]  driver: mmcblk
[   26.353498]   0b3:00301     204800 mmcblk1p1 1aa8056f-1357-6c45-a2f2-cb8bb98338e6
[   26.460663]   0b3:00305      16384 mmcblk1p5 8865bf3d-d8ea-574a-9c55-3aabefc1e84d
[   26.567834]   0b3:00306    2097152 mmcblk1p6 a0464221-9912-f146-ac7b-c6f489c25176
[   26.675000]   0b3:00309     102400 mmcblk1p9 1e061a8c-6159-4486-add1-988e88a06acf
[   26.782169]   0b3:0030a    1046872 mmcblk1p10 b8c64d3b-7752-4132-a244-5a85fc14157a
[   26.890374]   0b3:0030f      10240 mmcblk1p15 b6bbcc50-e420-4032-a2d2-ea69fce9cb53
[   26.890381] 
[   26.998582] List of all bdev filesystems:
[   27.046449]  ext3
[   27.046453]  ext2
[   27.069350]  ext4
[   27.092248]  fuseblk
[   27.115147] 
[   27.158861] Kernel panic - not syncing: VFS: Unable to mount root fs on unknown-block(179,778)

and since it says unknown-block(179,778) (rather than "0,0") it knows what it is! but just can't.

But rebuilding without, enabling serial-getty@ttyUSB0.service, plugging in a USB/serial adapter, and building and installing modules, we are greeted with

Debian GNU/Linux trixie/sid chwast ttyUSB0
​
chwast login: nabijaczleweli
Password:
​
Linux chwast 6.6.11 #73 SMP Thu Jan 25 08:06:59 CET 2024 aarch64
$ free -h
Mme: total 3.8Gi used 220Mi free 3.4Gi shared 952Ki buff/cache 295Mi available 3.6Gi
$ cat /proc/device-tree compatible ; echo
google,hana-rev6 google,hana-rev5 google,hana-rev4 google,hana-rev3 google,hana-rev2 google,hana-rev1 google,hana mediatek,mt8173
$ lscpu
Architecture: aarch64
Vendor ID: ARM
Model name: Cortex-A53
Model: 2
Model name: Cortex-A72
Model: 0
Flags: fp asimd evtstrm aes pmull sha1 sha2 crc32 cpuid
NUMA node0 CPU(s): 0-3

at a blazing 9600 bits per second. You know it's a modern system because that speed was achieved over USB 3.

This kinda mostly works, vaguely; since the other end is a real RS232, the maximum speed is 115200 baud and oh boy is 11k/s (8k/s for binary data) fucking horrendous in year of the hog 2024!

Wi-Fi backtraces with a warning and doesn't work even after loading firmware (mrvl/sd8897_uapsta.bin from firmware-libertas). Neither does the screen in any meaningful way, even with firmware-misc-nonfree mediatek/mt8173/vpu_p.bin.

Concept proven: Debian new+pstored+sysrq+clock-uvesa+clk+mmc+devices_deferred2+rtc+6397+fixed+i2c+usbsh2 runs in only 73 kernels, a significant proportion of which I don't think made it to the testing stage; this is probably like the twentieth in this lineage.

# Fraerin' ex%butinn^N

But no matter what I do or what combination of seemingly-relevant configs I flip, shit don't work. This either means booting normally to the rootfs, or freezing completely with an inocuous log or one that doesn't stand out at all. This is exemplified by the latter happening when turning on CONFIG_DRM_FBDEV_EMULATION. Post factum I know for a fact this isn't the issue, but at one point it became obvious that this is some proxy-interactive behaviour with no way to validate it.

If only someone had a validated-funxional config to test or diff against!

google hana chromebook linux - Google Search

running linux mainline on arm chromebooks - for example
lenovo chromebook n23 - hana; acer chromebook r13 - elm; lenovo chromebook ... https://support.google.com/chrome/a/answer/9139543?hl=en · https://chromium ...

hexdump0815/linux-mainline-on-arm-chromebooks: running linux mainline on arm chromebooks - for example: […] acer r13 (oak elm and hana)[…] and most probably many many more over time ...

running linux mainline on arm chromebooks

supported devices and linux distributions

imagebuilder/systems/chromebook_oak/readme.md at main · hexdump0815/imagebuilder

chromebook oak

tested systems - working

kernel build notes

in many ways it's a program that builds it, making it the best type of notes, so →

linux-mainline-mediatek-mt81xx-kernel/readme.mt7 at master · hexdump0815/linux-mainline-mediatek-mt81xx-kernel

# patches for mt8173/oak
for i in /compile/doc/stable-mt/misc.cbm/patches/v6.6/mt8173*.patch; do
  echo === $i
  patch -p1 < $i
done
[…]
scripts/kconfig/merge_config.sh -m arch/arm64/configs/defconfig /compile/doc/kernel-config-options/chromebooks-aarch64.cfg /compile/doc/kernel-config-options/mediatek.cfg /compile/doc/kernel-config-options/docker-options.cfg /compile/doc/kernel-config-options/options-to-remove-generic.cfg /compile/doc/stable-mt/misc.cbm/options/options-to-remove-special.cfg /compile/doc/kernel-config-options/additional-options-generic.cfg /compile/doc/kernel-config-options/additional-options-aarch64.cfg /compile/doc/stable-mt/misc.cbm/options/additional-options-special.cfg

The patches are superficially worrying, but they all just touch the device tree –

mt8173-fix-mmc-order.patch
MMCs in the fixed ChromiumOS
0
internal
1
external
2
Wi-Fi
order in the alias list
mt8173-fix-mmc1-speed.patch
remove even more high speed mmc stuff to get it working stable
mt8173-higher-temps.patch
/thermal-zones/cpu_thermal/trips/trip-point0 60000⇒70000m°C and …/trip-point1 65000⇒75000m°C

– whereas the same cannot be said for the MT8183 patches, but thankfully none of them are relevant here. It is of interest to evaluate these against the mt8173-elm-hana.dtb [decompiled] device tree distributed by ChromiumOS

mt8173-fix-mmc-order.patch
the ordering is somehow stable but not via the alias list
mt8173-fix-mmc1-speed.patch
the patch quarters the maximum clock frequency of mmc1 – the pluggable one – to 50MHz and removes sd-uhs-sdr{50,104} tags therefrom, upstream doesn't do this.
mt8173-higher-temps.patch
matches Linux's 60°C and 65°C; unclear to me why the patch raises it – this originates in commit 7c0cea8 (raise temps for elm a bit) with no further commentary; upstream, they were added in commit 689b937bedde (arm64: dts: mediatek: add mt8173 elm and hana board> already as 60/65; giving it another 10° here probably isn't gonna super fuck it up, but it'd've been nice to see some reasoning and maybe measurements and potentially a list of considerations given :v

Merging the configs per the crusty-ass spec works and produces a boot bundle that doesn't work. But given that the blob in EFI-SYSTEM also contains a different set of device trees paired with its older kernel (indeed, a set so different it doesn't even include mt8173-elm-hana.dtb and the only description that's vaguely similar is "mt8173-hana-rev0.dtb"), a quick re-pack after the prescribed make dtbs

$ csplit -fbb mmcblk0p2.dts '/data =/' '/type =/' '/mt8173-elm-hana.dtb/' '/data =/'
161
26119768
334465
40
7623425
$ # bb00 bb02 start the same as xx00 xx02
$ tail -n2 bb02
		fdt@9 {
			description = "mt8173-elm-hana.dtb";
$ head -n8 bb04
			type = "flat_dt";
			arch = "arm64";
			compression = "none";

			hash@1 {
				value = <0xd0eb38a9 0xad297279 0x5b014030 0x1027dbfe 0x3361c4a4>;
				algo = "sha1";
			};
$ { cat bb00;
    printf 'data = ['; lz4 < .../Image | od -An -tx1 -v | tr -d '\n'; printf '];\n';
    cat bb02;
    printf 'data = ['; < .../arch/arm64/boot/dts/mediatek/mt8173-elm-hana.dtb od -An -tx1 -v | tr -d '\n'; printf '];\n';
    cat bb04; } |
  dtc -I dts -O dtb > stb+dtb.dtb

— you may notice or rember the DTB is SHA1ed. This doesn't do jack shit, not even as a logged diagnostic. I even forgor 💀 at the time — shows

Screen of the Chromebook showing four penguins and a systemd boot-up log.

# 🐧🐧🐧🐧

That's an okay start, but as exemplified by the penguins this is a vajazzled defconfig instead of the reasonable Debian config, so Wi-Fi still doesn't work (though that may just be the way iwd drives it and it may work with another userland), and mounting EXT4s throws warnings (final lines), so beside the screen working it's not a great kernel.

One would hope that just repacking the best kernel to date with the new device tree would work (it doesn't). Or that applying the same set of diffs to /boot/config-6.6.11-arm64 would (also no).

Why? well,

# this is where I spend two further straight days building kernels to find out.

And that is a very literal "straight" – given this final ls -rtlh *.dtb of my newkernel directory (also browsable and downloadable with corresponing configs, modules, and logs):

21M 01-22 03:44 new+pstored+sysrq.dtb
20M 01-23 05:40 debian.dtb
21M 01-23 06:04 new+pstored+sysrq+clock.dtb
21M 01-23 07:07 new+pstored+sysrq+clock-uvesa.dtb
22M 01-23 16:01 new+pstored+sysrq+clock-uvesa+clk.dtb
22M 01-23 19:02 new+pstored+sysrq+clock-uvesa+clk+initrd.dtb
22M 01-23 20:16 new+pstored+sysrq+clock-uvesa+clk+mmc.dtb
24M 01-24 02:29 new+pstored+sysrq+clock-uvesa+clk+mmc+devices_deferred.dtb
24M 01-24 02:36 new+pstored+sysrq+clock-uvesa+clk+mmc+devices_deferred2.dtb
24M 01-24 02:47 new+pstored+sysrq+clock-uvesa+clk+mmc+devices_deferred2+rtc.dtb
24M 01-24 20:42 new+pstored+sysrq+clock-uvesa+clk+mmc+devices_deferred2+rtc+6397.dtb
24M 01-24 22:47 new+pstored+sysrq+clock-uvesa+clk+mmc+devices_deferred2+rtc+6397+fixed.dtb
24M 01-25 00:13 new+pstored+sysrq+clock-uvesa+clk+mmc+devices_deferred2+rtc+6397+fixed+i2c.dtb
24M 01-25 01:06 new+pstored+sysrq+clock-uvesa+clk+mmc+devices_deferred2+rtc+6397+fixed+i2c@mount.dtb
23M 01-25 03:24 new+pstored+sysrq+clock-uvesa+clk+mmc+devices_deferred2+rtc+6397+fixed+i2c-initrd.dtb
23M 01-25 08:18 new+pstored+sysrq+clock-uvesa+clk+mmc+devices_deferred2+rtc+6397+fixed+i2c+usbsh2.dtb
#               ^ first serial-interactive session
23M 01-25 21:02 new+pstored+sysrq+clock-uvesa+clk+mmc+devices_deferred2+rtc+6397+fixed+i2c+usbsh2+legacy.dtb
22M 01-26 02:38 new+pstored+sysrq+clock-uvesa+clk+mmc+devices_deferred2+rtc+6397+fixed+i2c+usbsh2+legacy-legacy.dtb
18M 01-26 07:27 stb+dtb.dtb
#               ^ the 🐧🐧🐧🐧 config
22M 01-26 21:37 new+pstored+sysrq+clock-uvesa+clk+mmc+devices_deferred2+rtc+6397+fixed+i2c+usbsh2+legacy-legacy+dtb+dma.dtb
22M 01-26 22:17 new+pstored+sysrq+clock-uvesa+clk+mmc+devices_deferred2+rtc+6397+fixed+i2c+usbsh2+legacy-legacy+dtb+dma+simple.dtb

we are currently here.

This followed:

17M 01-26 23:54 deb+options-to-remove-special.cfg+mediatek.cfg+additional-options-special.cfg.dtb
18M 01-27 00:30 deb+options-to-remove-special.cfg+mediatek.cfg+additional-options-special.cfg+full.dtb
18M 01-27 01:19 deb+options-to-remove-special.cfg+mediatek.cfg+additional-options-special.cfg+full+all.dtb
17M 01-27 01:46 deb+options-to-remove-special.cfg+mediatek.cfg+additional-options-special.cfg+full+all+gen.dtb
17M 01-27 02:29 deb2+1.dtb
18M 01-27 02:44 deb2+2.dtb
18M 01-27 02:56 deb2+3.dtb
18M 01-27 03:08 deb2+4.dtb
18M 01-27 03:13 deb2+5.dtb
18M 01-27 03:20 deb2+6.dtb
18M 01-27 03:25 deb2+7.dtb
18M 01-27 03:30 deb2+8.dtb
18M 01-27 03:34 deb2+9.dtb
18M 01-27 03:37 deb2+11.dtb
18M 01-27 03:37 deb2+10.dtb
18M 01-27 03:46 deb2+12.dtb
#               ^ ./tools/testing/ktest/config-bisect.pl 1 (jack shit)
22M 01-27 04:35 new+pstored+sysrq+clock-uvesa+clk+mmc+devices_deferred2+rtc+6397+fixed+i2c+usbsh2+legacy-legacy+dtb+dma+simple+bi.dtb
#               ^ bisexion diff applied to the previous one (still jack shit)
15M 01-27 04:51 bis.dtb
17M 01-27 05:02 bis+2.dtb
17M 01-27 05:48 bis+3.dtb
17M 01-27 06:57 bis+4.dtb
18M 01-27 08:05 bis+5.dtb
18M 01-27 08:51 bis+6.dtb
18M 01-27 08:55 bis+7.dtb
18M 01-27 09:13 bis+8.dtb
18M 01-27 09:17 bis+9.dtb
18M 01-27 09:37 bis+10.dtb
18M 01-27 09:40 bis+11.dtb
#               ^ ./tools/testing/ktest/config-bisect.pl 2 (also jack shit, and different variable)

And this is where the first issue that made applying the diffs not work finally became apparent: they set, for example

CONFIG_DRM_MEDIATEK_HDMI=y
CONFIG_DRM_MEDIATEK_DP=y
CONFIG_DRM_MEDIATEK=y

but make oldconfig (or olddefconfig, or any *config, or any build job), which updates the existing .config to match both the current kernel and its invariants updates it to

CONFIG_DRM_MEDIATEK=m
CONFIG_DRM_MEDIATEK_DP=m
CONFIG_DRM_MEDIATEK_HDMI=m

because CONFIG_DRM_MEDIATEK depends on CONFIG_DRM, which is also built as a module.

So instead of transitively updating the dependency tree to comply with the "build this in" spec, it just silently downgrades them all to be modules. Observant readers may note that this is the second time this mentality manifests within this post.

17M 01-27 16:57 hm+p.dtb
23M 01-27 18:54 new+pstored+sysrq+clock-uvesa+clk+mmc+devices_deferred2+rtc+6397+fixed+i2c+usbsh2+legacy-legacy+dtb+dma+simple+merged.dtb
#               ^ {chromebooks-aarch64,mediatek,additional-options-aarch64,additional-options-special}.cfg applied mechanically
#                 and the other cfgs applied manually
23M 01-27 19:22 new+pstored+sysrq+clock-uvesa+clk+mmc+devices_deferred2+rtc+6397+fixed+i2c+usbsh2+legacy-legacy+dtb+dma+simple+merged-svs.dtb
22M 01-27 19:31 new+pstored+sysrq+clock-uvesa+clk+mmc+devices_deferred2+rtc+6397+fixed+i2c+usbsh2+legacy-legacy+dtb+dma+simple+merged-svs+fb.dtb
22M 01-27 19:50 new+pstored+sysrq+clock-uvesa+clk+mmc+devices_deferred2+rtc+6397+fixed+i2c+usbsh2+legacy-legacy+dtb+dma+simple+merged-svs+fb+df.dtb
21M 01-27 20:13 new+pstored+sysrq+clock-uvesa+clk+mmc+devices_deferred2+rtc+6397+fixed+i2c+usbsh2+legacy-legacy+dtb+dma+simple+merged-svs+fb+df+drm.dtb
22M 01-27 20:36 new+pstored+sysrq+clock-uvesa+clk+mmc+devices_deferred2+rtc+6397+fixed+i2c+usbsh2+legacy-legacy+dtb+dma+simple+merged-svs+fb+df+drm+more.dtb
22M 01-27 20:48 new+pstored+sysrq+clock-uvesa+clk+mmc+devices_deferred2+rtc+6397+fixed+i2c+usbsh2+legacy-legacy+dtb+dma+simple+merged-svs+fb+df+drm+more+nogoog.dtb

finally yielded

Four monochrome penguins and am all-green systemd boot log displayed on the chromebook

This marks the first Debian-derived, and thus meaningfully diffable, config. (You can't really pick the interesting bits out of the relentless torrent of defconfig diff.)

The key? Turning off GOOGLE_FRAMEBUFFER_COREBOOT!

With it you see

[    0.386886] simple-framebuffer simple-framebuffer.0: simplefb: cannot reserve video memory at [mem 0x00000000-0x00400fff]
[    0.386911] simple-framebuffer simple-framebuffer.0: framebuffer at 0x0, 0x401000 bytes
[    0.386919] simple-framebuffer simple-framebuffer.0: format=a8r8g8b8, mode=1366x768x32, linelength=5464

at the end of the dmesg and then it hangs. The "cannot reserve video memory" is just a warning that it can't lock it exclusively, and it then, presumably, initialises the range [0, 0x400FFF], razing the interrupt table that's probably unmoved from 0.

Without it it just boots and logs

[    1.098264] [drm] Initialized mediatek 1.0.0 20150513 for mediatek-drm.12.auto on minor 0
[    1.303268] Console: switching to colour frame buffer device 170x48
[    1.334367] mediatek-drm mediatek-drm.12.auto: [drm] fb0: mediatekdrmfb frame buffer device

as it ought to.

The Debian config is such that this automatically turns on/off when toggling CONFIG_FB_SIMPLE (or whatever); the defconfig isn't. This is not obvious because the warning looks like an error, and there are like seven different drivers that log as "simple-framebuffer", and approximately twenty "simple framebuffer"s. Not to mention the spoopy axion at a distance with the actual driver – framebuffer-coreboot – not logging as itself.

Naturally, one wants to enable all the GOOGLE/CROS configs, and you should; just not this one.

22M 01-27 23:17 new+pstored+sysrq+clock-uvesa+clk+mmc+devices_deferred2+rtc+6397+fixed+i2c+usbsh2+legacy-legacy+dtb+dma+simple+merged-svs+fb+df+drm+more+nogoog+somegoog.dtb
22M 01-28 01:38 new+pstored+sysrq+clock-uvesa+clk+mmc+devices_deferred2+rtc+6397+fixed+i2c+usbsh2+legacy-legacy+dtb+dma+simple+nogoog.dtb
22M 01-28 01:51 new+pstored+sysrq+clock-uvesa+clk+mmc+devices_deferred2+rtc+6397+fixed+i2c+usbsh2+legacy-legacy+dtb+dma+simple+nogoog+emul.dtb
23M 01-28 02:24 new+pstored+sysrq+clock-uvesa+clk+mmc+devices_deferred2+rtc+6397+fixed+i2c+usbsh2+legacy-legacy+dtb+dma+simple+nogoog+emul+paneldrm.dtb
23M 01-28 02:40 new+pstored+sysrq+clock-uvesa+clk+mmc+devices_deferred2+rtc+6397+fixed+i2c+usbsh2+legacy-legacy+dtb+dma+simple+nogoog+emul+paneldrm+spi.dtb
22M 01-28 03:31 new+pstored+sysrq+clock-uvesa+clk+mmc+devices_deferred2+rtc+6397+fixed+i2c+usbsh2+legacy-legacy+dtb+dma+simple+nogoog+emul+paneldrm+spi+pins+regulator.dtb
22M 01-28 04:22 new+pstored+sysrq+clock-uvesa+clk+mmc+devices_deferred2+rtc+6397+fixed+i2c+usbsh2+legacy-legacy+dtb+dma+simple+nogoog+emul+paneldrm+spi+pins+regulator+noemul+emul.dtb
18M 01-28 17:57 mandeb.dtb
20M 01-28 18:35 mandeb+initrd.dtb
20M 01-28 18:46 mandeb+initrd+1.dtb
20M 01-28 19:03 mandeb+initrd+1+tabs.dtb
20M 01-28 19:09 mandeb+initrd+1+tabs1.dtb
20M 01-28 19:28 mandeb+initrd+1+tabs2+reg.dtb
20M 01-28 19:51 mandeb+initrd+1+tabs2+reg+drm.dtb
20M 01-28 20:03 mandeb+initrd+1+tabs2+reg+drm+adc.dtb

This was my limit for the useless /sys/kernel/debug/devices_deferred dumps, and where finally instead of thinking "if only there were a way to have a config contain what's in my device tree" I found and applied scripts/dtc/dt_to_config. Of course, it wants to be in a git checkout (which I have, but is annoying – you could probably replace the git grep with grep -rI with the same effect of not looking into artifacts), but even beside that it produces a brain destroyer format:

-dD----H----- : /backlight : pwm-backlight : arch/arm/mach-s3c/mach-crag6410.c : no_config : none
-dDc---H----- : /backlight : pwm-backlight : drivers/video/backlight/pwm_bl.c : CONFIG_BACKLIGHT_PWM : none

-dDc--------- : /connector : hdmi-connector : drivers/gpu/drm/bridge/display-connector.c : CONFIG_DRM_DISPLAY_CONNECTOR : none
-dDc--------- : /connector : hdmi-connector : drivers/gpu/drm/bridge/lontium-lt8912b.c : CONFIG_DRM_LONTIUM_LT8912B : none
-dDc----x---- : /connector : hdmi-connector : drivers/gpu/drm/mediatek/mtk_hdmi.c : mediatek-drm-hdmi-objs : none
-dDc----x---- : /connector : hdmi-connector : drivers/gpu/drm/sun4i/sun4i_drv.c : sun4i-drm-y : none

------------- : /cpus/cpu@0 : arm,cortex-a53 : no_driver : no_config : none

------------- : /cpus/cpu@1 : arm,cortex-a53 : no_driver : no_makefile : none

-d-c----x---- : /cpus/cpu@100 : arm,cortex-a72 : drivers/soc/bcm/brcmstb/biuctrl.c : obj-y : none

-d-c----x---- : /cpus/cpu@101 : arm,cortex-a72 : drivers/soc/bcm/brcmstb/biuctrl.c : obj-y : none

Thankfully this can be avoided with --config-format which is less arcane –

# -dD----H----- : /backlight : pwm-backlight : arch/arm/mach-s3c/mach-crag6410.c : no_config : none
# no_config
# -dDc---H----- : /backlight : pwm-backlight : drivers/video/backlight/pwm_bl.c : CONFIG_BACKLIGHT_PWM : none
# CONFIG_BACKLIGHT_PWM is not set
# CONFIG_BACKLIGHT_PWM=y

# -dDc--------- : /connector : hdmi-connector : drivers/gpu/drm/bridge/display-connector.c : CONFIG_DRM_DISPLAY_CONNECTOR : none
# CONFIG_DRM_DISPLAY_CONNECTOR is not set
# CONFIG_DRM_DISPLAY_CONNECTOR=y
# -dDc--------- : /connector : hdmi-connector : drivers/gpu/drm/bridge/lontium-lt8912b.c : CONFIG_DRM_LONTIUM_LT8912B : none
# CONFIG_DRM_LONTIUM_LT8912B is not set
# CONFIG_DRM_LONTIUM_LT8912B=y
# -dDc----x---- : /connector : hdmi-connector : drivers/gpu/drm/mediatek/mtk_hdmi.c : mediatek-drm-hdmi-objs : none
# mediatek-drm-hdmi-objs
# -dDc----x---- : /connector : hdmi-connector : drivers/gpu/drm/sun4i/sun4i_drv.c : sun4i-drm-y : none
# sun4i-drm-y

and can be quite trivially analysed against the current-best with something like

$ grep '^# C' dt_to_config.config | grep =y | sed 's/# //' | cut -d= -f1 |
  sort -u | grep -v ^CONFIG_MACH |
  while read -r c; do grep ^$c= .config || echo NO $c; done |
  grep m$
CONFIG_ARM_MEDIATEK_CPUFREQ=m
CONFIG_ARM_SMC_WATCHDOG=m
CONFIG_BACKLIGHT_PWM=m
CONFIG_BATTERY_SBS=m
CONFIG_BT_MRVL_SDIO=m
CONFIG_CPUFREQ_DT=m
CONFIG_DRM_DISPLAY_CONNECTOR=m
CONFIG_I2C_HID_OF=m
CONFIG_I2C_MT65XX=m
CONFIG_KEYBOARD_GPIO=m
CONFIG_MFD_ROHM_BD718XX=m
CONFIG_PHY_MTK_TPHY=m
CONFIG_SCSI_UFSHCD_PLATFORM=m
CONFIG_SND_SOC_MT8173=m
CONFIG_SND_SOC_MT8173_RT5650=m
CONFIG_SND_SOC_RT5645=m
CONFIG_TCG_TIS_I2C_INFINEON=m
CONFIG_TOUCHSCREEN_ELAN=m

to then upgrade CONFIG_{ARM_MEDIATEK_CPUFREQ{,_HW},BACKLIGHT_PWM,CPUFREQ_DT,DRM_DISPLAY_CONNECTOR,I2C_HID_{CORE,OF},I2C_MT65XX,KEYBOARD_GPIO,MFD_ROHM_BD718XX} and enable I2C_HID_OF_{ELAN,GOODIX}, yielding

20M 01-28 20:37 mandeb+initrd+1+tabs2+reg+drm+adc+d_t_c.dtb
18M 01-28 20:43 mandeb+initrd+1+tabs2+reg+drm+adc+d_t_c-initrd.dtb

i.e.

listing of some paths under sysfs, a few times a second apart, then a listing of MMC devices, displayed on the Chromebook's display

which, with no missing devices and, well, showing up on the screen, bodes very well! and

an all-green systemd boot log with fsck running, on the chromebook screen

which may be one of this generation's yippeeest moments.

(The ENODEVs at the top are from a lack of modules on this first boot.) (Also note how modprobe@efi_pstore.service succeeds. I don't really know how or why, given that this system lacks EFI (and ACPI for that matter) and they're both configured away completely.) And after a quick module installation, I've achieved

# arm64 Chromebook Debian port any% 17-day RTA/#137 IGT WR

the chromebook screen showing a getty login prompt, then 'Linux chwast 6.6.11 #137 SMP Sun Jan 28 20:42:40 CET 2024 aarch64' from /etc/issue after login, with last login on ttyUSB0; also I'm in the reflection pulling a face

(I'm even in the clip!) All these bundles listed above accumulate to 74 and I lost at most like 4 images, so a few sequence numbers were spent on QEMU pre-testing.

Even X.Org works!

But there's three obvious issues:

  1. no local sound output devices (speakers or headphone jack) – well, they show up as
    input: mtk-rt5650 Headset Jack as /devices/platform/sound/sound/card0/input8
    input: mtk-rt5650 HDMI Jack as /devices/platform/sound/sound/card0/input9
    in the dmesg but pipewire doesn't see them
  2. wi-fi driver still backtraces with a warning
  3. the fucking SD card is horrendous

3. is the most pressing for both usability reasons (it's bound to be slow, but not that slow) and because sometimes I/O will just, like, effectively hang, with kilobyte-sized mmaps taking seconds, and the dmesg complaining that the card is "stuck busy", all with a blatant culprit – mt8173-fix-mmc1-speed.patch. The SD card was solid under KERN-A which has all the full-speed stuff this patch disables.

By performing a speed-running trick called "forwarding to the list while modules were building four days ago", I already have a prospective patch for 2., so I can be oh-so-brave (with only a quick glance at if it'd be catastrophic!) and update the module while at it – re-building dtbs modules with just mt8173-higher-temps.patch and the diff from the mail yields

18M 01-31 00:00 mandeb+initrd+1+tabs2+reg+drm+adc+d_t_c-initrd&mwifiex+mmc1.dtb

and while the Wi-Fi warning goes away, the SD card rootfs experience is as shit as ever.

But this may well be because my SD card is not fast enough to qualify for any of the speed boosts – the two internal ones are new HS400 MMC card and new ultra high speed SDR104 SDIO card but this one is just new high speed SDHC card; maybe we need to actually install Debian because this is horrendous. This may be fixable with an SD card worth as much as the laptop instead of my drawer special, but that still kinda defeats the purpose of a laptop with an internal diskrectangle.

Testing with such a card on the 4.19 ChromiumOS kernel, I could reproduce the "instability" with a simple test (b2sum /dev/mmcblk1), presenting itself as a kernel segfault and likewise on the 6.6.11 kernel. Applying the patch fixes it (and runs the card at "high speed").

The MMC ordering appears to already be stable, so while it was random with the original device tree, that one's for 4.19, so it may just be and old-device-tree issue? The patch itself blames back to commit 01101e3 (promising experiments based on apline linux-elm apk) as misc.cbm/patches/alpine/fix-mmc-order.patch. Not that "identical device enumeration order" is a sensible goal unto itself in a.d. 2020 regardless.

 rt5650 Playback: ASoC: no backend DAIs enabled for rt5650 Playback, possibly missing ALSA mixer-based routing or UCM profile

is the lead for issue 1. A quick search for files matching *rt5650* in sid shows an unbounded amount of linuxes but starts with firmware-sof-signed and /lib/firmware/intel/sof-tplg/sof-adl-rt5650.tplg, whose description says it Provides the Intel SOF audio firmware and topology needed for audio functionality on some Intel system., which this isn't, so it's not it (not that I didn't try).

Searching locally instead via dpkg -S rt5650 actually reveals alsa-ucm-conf, with

which sure looks like it'd match what the driver complains about not having! but has.

This kinda smells like the bluetooth situation where you need libspa-0.2-bluetooth to have bluetooth audio. Indeed, apt search pipewire reveals

pipewire-alsa/unstable 1.0.1-2 arm64
  Pipewire ALSA plugin

but this is actually a plugin for ALSA to output to pipewire. Not that you'd know this from the package description. I know it from the damn arch wiki. Reported as Bug#1062262: pipewire-alsa: adversarial description.

Further apt search alsaing shows

alsa-tools/unstable 1.2.5-3 arm64
  Console based ALSA utilities for specific hardware

alsa-utils/unstable 1.2.10-1.1 arm64
  Utilities for configuring and using ALSA

can you guess which one is a sussy baka amongus and which one is the chad taskpilled crewmatecel? The latter lists

Included tools:
 - alsaucm: alsa use case manager

so if you voted for the latter you will not be ejected. Amazingly, during the emergency meeting aplay -l and arecord -l corroborated mtkrt5650 venting:

**** List of PLAYBACK Hardware Devices ****
card 0: mtkrt5650 [mtk-rt5650], device 0: rt5650 Playback (*) []
  Subdevices: 1/1
  Subdevice #0: subdevice #0
card 0: mtkrt5650 [mtk-rt5650], device 2: HDMI PCM (*) []
  Subdevices: 1/1
  Subdevice #0: subdevice #0
**** List of CAPTURE Hardware Devices ****
card 0: mtkrt5650 [mtk-rt5650], device 1: rt5650 Capture (*) []
  Subdevices: 1/1
  Subdevice #0: subdevice #0

but aplay doesn't and arecord records all zeroes.

alsaucm is one of those programs that definitely make sense to the authors. But by clicking around – running everything, in order, from alsaucm(1) (only real science on da blog):

# alsaucm
# alsaucm listcards
  0: hw:0
    mtk-rt5650
# alsaucm open 0
ALSA lib main.c:1554:(snd_use_case_mgr_open) error: failed to import 0 use case configuration -2
alsaucm: error failed to open sound card 0: No such file or directory
# alsaucm open hw:0
# alsaucm list _verbs
  0: HiFi
    Default
# alsaucm list _devices
alsaucm: error failed to get list _devices: No such file or directory
# alsaucm list _devices/HiFi
  0: Speaker
    Speaker
  1: Headphones
    Headphones
  2: Mic
    Internal Microphone
  3: Headset
    Headset Microphone
  4: HDMI
    HDMI Audio
# alsaucm list _modifiers
alsaucm: error failed to get list _modifiers: No such file or directory
# alsaucm list _modifiers/HiFi
  list is empty
# alsaucm get _verb
alsaucm: error failed to get _verb: No such file or directory
# alsaucm set _verb HiFi
# alsaucm get _verb
alsaucm: error failed to get _verb: No such file or directory

(why the fuck does it all have underscores? why is "HiFi" a verb? why is the "verb" denoted as optional after _devices and _modifiers but isn't? why can I not know what the current "verb" is? what would doing the verb even do?)

and unloading and inserting every sound module (or rebooting! presumably the "verb" gets persisted somewhere up them guts) now replaced "Dummy Output" in wpctl status with

Audio
 ├─ Sinks:
 │      56. Built-in Audio HDMI Audio           [vol: 0.40]
 │  *   57. Built-in Audio Headphones + Speaker [vol: 1.00]

 └─ Sources:
    *   58. Built-in Audio Headset Microphone + Internal Microphone [vol: 0.63]

Settings
 └─ Default Configured Node Names:
         0. Audio/Sink    alsa_output.platform-sound.HiFi__hw_mtkrt5650_0__sink
         1. Audio/Source  alsa_input.platform-sound.HiFi__hw_mtkrt5650_1__source

(why are they grouped and not split?) and neither aplay nor pw-play do anything. But at this time I noticed the tab expansion list for a has an alsamixer which has drip –

Curses menu titled AlsaMixer v1.2.10, noting Card: mtk-rt5650; there's a plethora of bars labelled Headphon, Speaker, Speaker, I2S2 Fun, Mono ADC, and Mono DAC

– but more importantly has a Headphon output with green OO and a Speaker one is MM, which is, respectively, not muted and muted, apparently. Plugging in headphones actually plays to the headphones. Amazing! But recording gets just noise (it's possible the mic is shot on the headphones but that the internal one is as well? no way). And unmuting the Speaker output doesn't make it go.

The only solution to this is multivariable bisexion, defined as "going to the end of the like eight pages of increasingly-cryptically-named outputs, unmuting a few, then playing again". This is how I know that unmuting the Ext Spk output lets the internal speakers go. It's also how I know that when you're expecting a tinny voice to say "The HINFO.network." (which you should join!) but get a square wave and a mild whiff of burning lacquer that shit's fucking terrifying mang. It's also also how I know that expecting the same and getting a 600Hz whine also is. At least I was ready on the reset that time.

Naturally, the mixer settings are persisted across reboots, so fuck knows which ones of the other 10 outputs I toggled made it be a daemon, or whether just flipping Ext Spk will make it output cleanly to the speakers. Or if some of those outputs start driving the speakers with a DC offset regardless of whether there's audio playing. I know I'm not trynna find out at 2am again.

A quick purge of the ALSA state from /var/lib/alsa/asound.state thankfully reverted this, and also contained

	control.31 {
		iface MIXER
		name 'Ext Spk Switch'
		value false
		comment {
			access 'read write'
			type BOOLEAN
			count 1
		}
	}
	control.32 {
		iface MIXER
		name 'Int Mic Switch'
		value true
		comment {
			access 'read write'
			type BOOLEAN
			count 1
		}
	}

which amixer lists as

Simple mixer control 'Ext Spk',0
  Capabilities: pswitch pswitch-joined
  Playback channels: Mono
  Mono: Playback [on]
Simple mixer control 'Int Mic',0
  Capabilities: pswitch pswitch-joined
  Playback channels: Mono
  Mono: Playback [on]

and either pressing m on it in alsamixer or running amixer sset 'Ext Spk',0 on (or off) made sound play from the speakers, with the counter-intuitive muted/off ⇒ headphones and unmuted/on ⇒ speakers. If only there were a way to make this happen automatically like normal!

A quick peep with amixer events yields

event value: numid=24,iface=CARD,name='Headphone Jack'
event value: numid=24,iface=CARD,name='Headphone Jack'
event value: numid=24,iface=CARD,name='Headphone Jack'
event value: numid=25,iface=CARD,name='Headset Mic Jack'

with the first two corresponding to plugging/unplugging a TRS jack, and the latter two corresponding to plugging a TRRS jack. amixer contents, then:

numid=24,iface=CARD,name='Headphone Jack'
  ; type=BOOLEAN,access=r-------,values=1
  : values=on
numid=25,iface=CARD,name='Headset Mic Jack'
  ; type=BOOLEAN,access=r-------,values=1
  : values=on

(note that it does also have Headphone Switch and Headphone Playback Switch (and the same for Speaker) as double-bools but they appear to be only readable as part of a full dump – reading/writing via cget/cset just hangs). Unfortunately amixer monitor doesn't include the new data and the on/off is inverted hence the crusty-ass xor, but it's nevertheless a trivial program:

stdbuf -oL amixer events |
	while read -r event value id; do
		[ "$event $value" = "event value:" ] || continue
		case "$id" in
			*"'Headphone Jack'"  )	ctl='Ext Spk';     inv=on  ;;
			*"'Headset Mic Jack'")	ctl='Headset Mic'; inv=off ;;
			*                    )	continue                   ;;
		esac
		amixer cget "$id" |
			while IFS="$IFS=" read -r tp k v; do
				[ "$tp $k" = ": values" ] || continue
				case "$v$inv" in
					onon|offoff)	v=off ;;
					onoff|offon)	v=on  ;;
				esac
				exec amixer sset "'$ctl'" "$v"
			done
	done

Further testing shows that if the Headset Mic control is set to off it expectedly cuts out the TRRS microphone, and this yields an all-zero recording – I haven't managed to get any input from the internal microphone, but this isn't really a big feature loss for me personally.

It's rather quite likely something like this is possible within the ALSA config itself.

I left both Headphon and Speaker at 33/59 (-12dB/0dB) but dropped down the second Speaker (full name Speaker ClassD) down from 92 (+1.58dB) to 72 (0dB). There's a whole lot of dynamic range in the pipewire volume control.

And with all this we can

Further testing (triggered by wireplumber restarts causing Speaker and Ext Spk to mute again) reveals you need to select

Port
Speaker

from the default

Port
Headphones

in the pavucontrol Output Devices panel and it works.

pavucontrol "Volume Control" window, "Output Devices" tab, "Built-in Audio Headphones + Speaker" device, Port: picker open, Speaker highlighted

The HiFi "verb" appears to be

Profile
Default

and selecting "Off" showed just dummy devices, and "Pro Audio" – two real devices that don't do anything.

pavucontrol "Volume Control" window, "Configuration" tab, "Built-in Audio" device, Profile: picker open, Default highlighted

The former does not appear to correspond to anything visible via pipewire (nor do I see it in the ALSA state), These settings are persistent (at last) but do not automatically switch when headphones are plugged in. Still no mic though.

All that's left is

# installing Debian

because running off an SD card still sucks ass and continues to defeat the purpose. Thankfully, we've already analysed bootloader discovery and the lay-out of the internal flash in how is pointar formed kernal loaded?, but out of the many shortcuts the developer menu understands not one of them is "boot kernel b actually", which makes the ideal "add debian kernel and rootfs as default priority, keep KERN-A&ROOT-A with a downgraded priority as a recovery system" configuration unworkable. Indeed, if ChromiumOS Docs - Disk Format, Selecting the kernel is to be trusted, the entire "ChromeOS Kernel"-partition flag mechanism is used exclusively for effectively-one-time boot bundle verification after an update and latches on the good kernel afterward. This means two possibilities remain:

and the choice is obvious, since we already have that recovery image, and the path presents itself rather overtly:

Initial state

Partition 11: RWFW, 8M
Partition 6: KERN-C, 512
Partition 7: ROOT-C, 512
Partition 9: ?, 512
Partition 10: ?, 512
2014k of empty space
Partition 2: KERN-A, 16M
Partition 4: KERN-B, 16M
Partition 8: OEM, 16M
64k of empty space
Partition 12: EFI-SYSTEM, 32M
Partition 5: ROOT-B, 2G
Partition 3: ROOT-A, 2G
Partition 1: STATE, 25G
# fdisk /dev/mmcblk0
Welcome to fdisk (util-linux 2.39.3).
Changes will remain in memory only, until you decide to write them.
Be careful before using the write command.

GPT PMBR size mismatch (61063167 != 61071359) will be corrected by write.
The backup GPT table is not on the end of the device. This problem will be corrected by write.

Command (m for help): d
Partition number (1-12, default 12): 6

Partition 6 has been deleted.

Command (m for help): d
Partition number (1-5,7-12, default 12): 7

Partition 7 has been deleted.

Command (m for help): d
Partition number (1-5,8-12, default 12): 9

Partition 9 has been deleted.

Command (m for help): d
Partition number (1-5,8,10-12, default 12): 10

Partition 10 has been deleted.

Command (m for help): p
Disk /dev/mmcblk0: 29.12 GiB, 31268536320 bytes, 61071360 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disklabel type: gpt
Disk identifier: 8648551F-D8FC-AC44-AA00-C0CA32C4A9BC

Device            Start      End  Sectors Size Type
/dev/mmcblk0p1  8704000 61063119 52359120  25G Microsoft basic data
/dev/mmcblk0p2    20480    53247    32768  16M ChromeOS kernel
/dev/mmcblk0p3  4509696  8703999  4194304   2G ChromeOS root fs
/dev/mmcblk0p4    53248    86015    32768  16M ChromeOS kernel
/dev/mmcblk0p5   315392  4509695  4194304   2G ChromeOS root fs
/dev/mmcblk0p8    86016   118783    32768  16M Microsoft basic data
/dev/mmcblk0p11      64    16447    16384   8M ChromeOS firmware
/dev/mmcblk0p12  249856   315391    65536  32M EFI System

Partition table entries are not in disk order.

Command (m for help): w
The partition table has been altered.
Calling ioctl() to re-read partition table.
Syncing disks.

(these are all cruft)

Partitions 6, 7, 9, 10 deleted, accrued together into 2016k of empty space
Command (m for help): d
Partition number (1-5,8,11,12, default 12): 8
Partition 8 has been deleted.
Command (m for help): d
Partition number (1-5,11,12, default 12):
Partition 12 has been deleted.
Command (m for help): p
Device            Start      End  Sectors Size Type
/dev/mmcblk0p1  8704000 61063119 52359120  25G Microsoft basic data
/dev/mmcblk0p2    20480    53247    32768  16M ChromeOS kernel
/dev/mmcblk0p3  4509696  8703999  4194304   2G ChromeOS root fs
/dev/mmcblk0p4    53248    86015    32768  16M ChromeOS kernel
/dev/mmcblk0p5   315392  4509695  4194304   2G ChromeOS root fs
/dev/mmcblk0p11      64    16447    16384   8M ChromeOS firmware

(neither of these have anything of interest; I did make a backup of EFI-SYSTEM for completeness' sake)

Partitions 8 (OEM) and 12 (EFI-SYSTEM) deleted, accrued together into 48M of empty space
Command (m for help): d
Partition number (1-5,11, default 11): 4
Partition 4 has been deleted.
Command (m for help): d
Partition number (1-3,5,11, default 11): 5
Partition 5 has been deleted.
Command (m for help): p
Device            Start      End  Sectors Size Type
/dev/mmcblk0p1  8704000 61063119 52359120  25G Microsoft basic data
/dev/mmcblk0p2    20480    53247    32768  16M ChromeOS kernel
/dev/mmcblk0p3  4509696  8703999  4194304   2G ChromeOS root fs
/dev/mmcblk0p11      64    16447    16384   8M ChromeOS firmware

(of course, kill KERN-A/ROOT-A instead if KERN-B is the winner on your machine)

Partitions 4 (KERN-B) and 5 (ROOT-B) deleted, accrued together into 2⅛M of empty space
localhost# df -Th
Filesystem              Type  Size  Used Avail Use% Mounted on
/dev/root               ext2  2.0G  1.6G  418M  79% /
/dev/mmcblk0p1          ext4   25G  659M   23G   2% /mnt/stateful_partition
/dev/mapper/encstateful ext4  7.2G  145M  7.0G   2% /mnt/stateful_partition/encrypted

localhost# lsblk
NAME          MAJ:MIN RM   SIZE RO TYPE MOUNTPOINTS
loop1           7:1    0   7.3G  0 loop
`-encstateful 254:1    0   7.3G  0 dm   /home/chronos
                                        /var
                                        /mnt/stateful_partition/encrypted
mmcblk0       179:0    0  29.1G  0 disk
|-mmcblk0p1   179:1    0    25G  0 part /var/cache/dlc-images
|                                       /usr/local
|                                       /home
|                                       /mnt/stateful_partition
`-mmcblk0p3   179:3    0     2G  0 part /

localhost# du -haxd1 /mnt/stateful_partition
28K	/mnt/stateful_partition/etc
4.0K	/mnt/stateful_partition/dev_image
12K	/mnt/stateful_partition/shutdown_umount_failure.log
4.0K	/mnt/stateful_partition/encrypted.key
40K	/mnt/stateful_partition/home
33M	/mnt/stateful_partition/unencrypted
12K	/mnt/stateful_partition/var_overlay
0	/mnt/stateful_partition/.developer_mode
4.0K	/mnt/stateful_partition/umount-encrypted.log
16K	/mnt/stateful_partition/lost+found
8.0K	/mnt/stateful_partition/reboot_vault
489M	/mnt/stateful_partition/encrypted.block
522M	/mnt/stateful_partition

localhost# dmsetup table
encstateful: 0 15355208 crypt aes-cbc-essiv:sha256 :32:logon:dmcrypt:656e63737461746566756c 0 7:1 0 1 allow_discards
Partition 3 (ROOT-A): 1.6G/2G used, ext2, mounted on /
​
Partition 1 (STATE): 659M/25G used, ext4, mounted on /mnt/stateful_partition
on it: /encrypted.block and .key: 489M/7.4G allocated
from it derived /dev/loop1 through dmcrypt into /dev/mapper/encstateful
mounted on /mnt/stateful_partition/encrypted, ext4, 146M/7.2G used
localhost# fstrim -v /mnt/stateful_partition/encrypted
/mnt/stateful_partition/encrypted: 7 GiB (7480754176 bytes) trimmed

localhost# du -h /mnt/stateful_partition/encrypted.block
323M /mnt/stateful_partition/encrypted.block

localhost# df -Th
Filesystem     Type  Size  Used Avail Use% Mounted on
/dev/mmcblk0p1 ext4   25G  355M   23G   2% /mnt/stateful_partition
chwast# e2fsck -f /dev/disk/by-partlabel/ROOT-A
e2fsck 1.47.0 (5-Feb-2023)
Filesystem did not have a UUID; generating one.
ROOT-A: 11702/32000 files (9.7% non-contiguous), 402764/509696 blocks
chwast# resize2fs /dev/disk/by-partlabel/ROOT-A 1.7G
resize2fs 1.47.0 (5-Feb-2023)
resize2fs: Invalid new size: 1.7G
chwast# resize2fs /dev/disk/by-partlabel/ROOT-A 1704M
resize2fs 1.47.0 (5-Feb-2023)
The filesystem on /dev/disk/by-partlabel/ROOT-A is now 445440 (4k) blocks long.

chwast# e2fsck -f /dev/disk/by-partlabel/STATE
Pass 1: Checking inodes, blocks, and sizes
Inode 14 extent tree (at level 2) could be narrower. Optimize<y>? no
/dev/disk/by-partlabel/STATE: 152/1638400 files (2.0% non-contiguous), 238667/6544890 blocks
chwast# resize2fs /dev/disk/by-partlabel/STATE 384M
resize2fs: New size smaller than minimum (239160)

That's 940M! df and du agree on 355M used but e2fsck's block count also resolves to 932M! This means almost tripled usage of space vs the data inside; no fiddling around got me anywhere. How? What's in those 577M?

chwast# resize2fs /dev/disk/by-partlabel/STATE 960M
The filesystem on /dev/disk/by-partlabel/STATE is now 245760 (4k) blocks long.
chwast# mount /dev/disk/by-partlabel/STATE /mnt
chwast# fstrim -v /mnt
/mnt/: 400.5 MiB (419946496 bytes) trimmed.
chwast# umount /dev/disk/by-partlabel/STATE /mnt
chwast# e2fsck -fy /dev/disk/by-partlabel/STATE
/dev/mmcblk0p1: 152/65536 files (1.3% non-contiguous), 129018/245760 blocks

And that's 503M. Where did 437M go? Mysterium tytsei.

chwast# resize2fs /dev/disk/by-partlabel/STATE 512M -fz /tmp/undo
Overwriting existing filesystem; this can be undone using the command:
    e2undo /tmp/undo /dev/disk/by-partlabel/STATE
The filesystem on /dev/disk/by-partlabel/STATE is now 131072 (4k) blocks long.
chwast# e2fsck -fyz /tmp/undo2 /dev/disk/by-partlabel/STATE
/dev/mmcblk0p1: 152/32768 files (2.6% non-contiguous), 124912/131072 blocks

chwast# resize2fs /dev/disk/by-partlabel/STATE 480M -fz /tmp/undo3
Overwriting existing filesystem; this can be undone using the command:
    e2undo /tmp/undo3 /dev/disk/by-partlabel/STATE
Resizing the filesystem on /dev/disk/by-partlabel/STATE to 122880 (4k) blocks.
resize2fs: No space left on device while trying to resize /dev/disk/by-partlabel/STATE
Please run 'e2fsck -fy /dev/disk/by-partlabel/STATE' to fix the filesystem
after the aborted resize operation.
chwast# e2undo /tmp/undo3 /dev/disk/by-partlabel/STATE && rm /tmp/undo3
chwast# mount -r /dev/disk/by-partlabel/STATE /mnt
chwast# df -h /mnt
Filesystem      Size  Used Avail Use% Mounted on
/dev/mmcblk0p1  364M  340M     0 100% /mnt
ROOT-A resized to 1.7G
​
/encrypted.block discarded down to 323M
so STATE usage reduced to 355M and reduced 512M

Usually this would be a slightly more involved process because we'd want to keep it all on disk, but in this case they all easily fit in RAM, even all at once.

KERN-A
chwast:/tmp# cp /dev/disk/by-partlabel/KERN-A .
chwast:/tmp# cmp /dev/disk/by-partlabel/KERN-A KERN-A

chwast:/tmp# fdisk /dev/mmcblk0
Command (m for help): p
Device            Start      End  Sectors Size Type
/dev/mmcblk0p1  8704000 61063119 52359120  25G Microsoft basic data
/dev/mmcblk0p2    20480    53247    32768  16M ChromeOS kernel
/dev/mmcblk0p3  4509696  8703999  4194304   2G ChromeOS root fs
/dev/mmcblk0p11      64    16447    16384   8M ChromeOS firmware
Command (m for help): x
Expert command (m for help): p
Device            Start      End  Sectors Type-UUID                            UUID                                 Name   Attrs
/dev/mmcblk0p1  8704000 61063119 52359120 EBD0A0A2-B9E5-4433-87C0-68B6B72699C7 D8331AD0-ED78-F442-87F4-78DF0130895A STATE
/dev/mmcblk0p2    20480    53247    32768 FE3A2A5D-4F32-41A7-B725-ACCC3285A309 CCFE5BD8-BBE4-A840-9C0B-BBA6427B6309 KERN-A GUID:49,56
/dev/mmcblk0p3  4509696  8703999  4194304 3CB8E202-3B7E-47DD-8A3C-7FF2A13CFCEC E71F6E02-1BC3-9D43-9EDD-2C7CA20D512A ROOT-A
/dev/mmcblk0p11      64    16447    16384 CAB6E88E-ABF3-4102-A07A-D4BB9BE3C1D3 530A6C46-BDFA-7C40-A446-FC05001BDA82 RWFW
Expert command (m for help): r

Command (m for help): d
Partition number (1-3,11, default 11): 2
Partition 2 has been deleted.

Command (m for help): n
Partition number (2,4-10,12-128, default 2): 2
First sector (16448-61071326, default 18432): 16448  # doesn't need to be aligned
Last sector, +/-sectors or +/-size{K,M,G,T,P} (16448-4509695, default 4509695): +32767
           # 32768 − 1 for fdisk +-based arithmetic
Created a new partition 2 of type 'Linux filesystem' and of size 16 MiB.

Command (m for help): t
Partition number (1-3,11, default 11): 2
Partition type or alias (type L to list all): 180
Changed type of partition 'Linux filesystem' to 'ChromeOS kernel'.

Command (m for help): x
Expert command (m for help): n
Partition number (1-3,11, default 11): 2
New name: KERN-A
Partition name changed from '' to 'KERN-A'.

Expert command (m for help): S
Partition number (1-3,11, default 11): 2
Enter GUID specific bit (48-63, default 48): 49
The GUID specific bit 49 on partition 2 is enabled now.
Expert command (m for help): S
Partition number (1-3,11, default 11): 2
Enter GUID specific bit (48-63, default 48): 56
The GUID specific bit 56 on partition 2 is enabled now.

Expert command (m for help): p
Device            Start      End  Sectors Type-UUID                            UUID                                 Name   Attrs
/dev/mmcblk0p2    16448    49215    32768 FE3A2A5D-4F32-41A7-B725-ACCC3285A309 B9393B88-B27F-438D-BF88-93BE6E66E4A9 KERN-A GUID:49,56
Expert command (m for help): r
Command (m for help): p
Device            Start      End  Sectors Size Type
/dev/mmcblk0p2    16448    49215    32768  16M ChromeOS kernel
Command (m for help): w
The partition table has been altered.
Calling ioctl() to re-read partition table.
Syncing disks.

chwast:/tmp# cp KERN-A /dev/disk/by-partlabel/KERN-A
chwast:/tmp# cmp KERN-A /dev/disk/by-partlabel/KERN-A

ROOT-A
A properly-sized dd would also be fine, but e2image my beloved does it best.
chwast:/tmp# e2image -rap /dev/disk/by-partlabel/ROOT-A ROOT-A
Copied 402500 / 402503 blocks (100%) in 00:00:08 at 196.53 MB/s
chwast:/tmp# ls -lh ROOT-A
-rw------- 1 root root 1.7G Feb  3 16:12 ROOT-A
chwast:/tmp# du -h ROOT-A
1.6G ROOT-A
chwast:/tmp# mount -r ROOT-A /mnt
chwast:/tmp# ls /mnt
bin  dev  etc  home  lib  lost+found  media  mnt  opt  postinst  proc  root  run  sbin	sys  tmp  usr  var
chwast:/tmp# df -h /mnt/
Filesystem      Size  Used Avail Use% Mounted on
/dev/mmcblk0p3  1.7G  1.6G  168M  91% /mnt
chwast:/tmp# # all good!
chwast:/tmp# umount /mnt/

chwast:/tmp# fdisk /dev/mmcblk0
Command (m for help): d
Partition number (1-3,11, default 11): 3
Partition 3 has been deleted.
Command (m for help): n
Partition number (3-10,12-128, default 3): 3
First sector (49216-61071326, default 51200):  # does need to be aligned
Last sector, +/-sectors or +/-size{K,M,G,T,P} (51200-8703999, default 8703999): +3563519
           # resize2fs said "445440 (4k) blocks long" – 445440*4096/512 − 1
Created a new partition 3 of type 'Linux filesystem' and of size 1.7 GiB.
Command (m for help): t
Partition number (1-3,11, default 11): 3
Partition type or alias (type L to list all): 181
Changed type of partition 'Linux filesystem' to 'ChromeOS root fs'.
Command (m for help): x
Expert command (m for help): n
Partition number (1-3,11, default 11): 3
New name: ROOT-A
Partition name changed from '' to 'ROOT-A'.

Expert command (m for help): p
Device            Start      End  Sectors Type-UUID                            UUID                                 Name   Attrs
/dev/mmcblk0p3    51200  3614719  3563520 3CB8E202-3B7E-47DD-8A3C-7FF2A13CFCEC ACB76082-35D1-46F0-A8E9-97006C40B632 ROOT-A
Expert command (m for help): r
Command (m for help): p
Device            Start      End  Sectors Size Type
/dev/mmcblk0p3    51200  3614719  3563520  1.7G ChromeOS root fs
Command (m for help): w

chwast:/tmp# wc -c ROOT-A /dev/disk/by-partlabel/ROOT-A
1824522240 ROOT-A
1824522240 /dev/disk/by-partlabel/ROOT-A
chwast:/tmp# cp ROOT-A /dev/disk/by-partlabel/ROOT-A

chwast:/tmp# cmp ROOT-A /dev/disk/by-partlabel/ROOT-A
chwast:/tmp# mount -r /dev/disk/by-partlabel/ROOT-A /mnt
chwast:/tmp# ls /mnt
bin  dev  etc  home  lib  lost+found  media  mnt  opt  postinst  proc  root  run  sbin	sys  tmp  usr  var
chwast:/tmp# df -h /mnt/
Filesystem      Size  Used Avail Use% Mounted on
/dev/mmcblk0p1  364M  340M     0 100% /mnt

STATE
likewise
chwast:/tmp# e2image -rap /dev/disk/by-partlabel/STATE STATE
Copied 122867 / 122871 blocks (100%) in 00:00:02 at 239.97 MB/s
chwast:/tmp# ls -lh STATE
-rw------- 1 root root 512M Feb 3 16:19 STATE
chwast:/tmp# du -h STATE
355M STATE
chwast:/tmp# mount -r STATE /mnt
chwast:/tmp# ls /mnt
dev_image  encrypted  encrypted.block  encrypted.key  etc  home  lost+found  reboot_vault  shutdown_umount_failure.log	umount-encrypted.log  unencrypted  var_overlay
chwast:/tmp# df -h /mnt/
Filesystem      Size  Used Avail Use% Mounted on
/dev/loop0      364M  340M     0 100% /mnt
chwast:/tmp# # likewise!
chwast:/tmp# umount /mnt/

chwast:/tmp# fdisk /dev/mmcblk0
Command (m for help): d
Partition number (1-3,11, default 11): 1
Partition 1 has been deleted.
Command (m for help): n
Partition number (1,4-10,12-128, default 1): 1
First sector (34-61071326, default 3614720):
Last sector, +/-sectors or +/-size{K,M,G,T,P} (3614720-61071326, default 61069311): +1048575
           # resize2fs: "131072" – 131072*4096/512 − 1
Created a new partition 1 of type 'Linux filesystem' and of size 512 MiB.
Command (m for help): t
Partition number (1-3,11, default 11): 1
Partition type or alias (type L to list all): 11
Changed type of partition 'Linux filesystem' to 'Microsoft basic data'.
Command (m for help): x
Expert command (m for help): n
Partition number (1-3,11, default 11): 1
New name: STATE
Partition name changed from '' to 'STATE'.

Expert command (m for help): p
Device            Start     End Sectors Type-UUID                            UUID                                 Name   Attrs
/dev/mmcblk0p1  3614720 4663295 1048576 EBD0A0A2-B9E5-4433-87C0-68B6B72699C7 DE9260C7-B796-4681-82E1-6BF5E1DDC405 STATE
/dev/mmcblk0p2    16448   49215   32768 FE3A2A5D-4F32-41A7-B725-ACCC3285A309 B9393B88-B27F-438D-BF88-93BE6E66E4A9 KERN-A GUID:49,56
/dev/mmcblk0p3    51200 3614719 3563520 3CB8E202-3B7E-47DD-8A3C-7FF2A13CFCEC ACB76082-35D1-46F0-A8E9-97006C40B632 ROOT-A
/dev/mmcblk0p11      64   16447   16384 CAB6E88E-ABF3-4102-A07A-D4BB9BE3C1D3 530A6C46-BDFA-7C40-A446-FC05001BDA82 RWFW
Expert command (m for help): r
Command (m for help): p
Device            Start     End Sectors Size Type
/dev/mmcblk0p1  3614720 4663295 1048576  512M Microsoft basic data
/dev/mmcblk0p2    16448   49215   32768   16M ChromeOS kernel
/dev/mmcblk0p3    51200 3614719 3563520  1.7G ChromeOS root fs
/dev/mmcblk0p11      64   16447   16384    8M ChromeOS firmware
Command (m for help): w

chwast:/tmp# cp STATE /dev/disk/by-partlabel/STATE
chwast:/tmp# cmp STATE /dev/disk/by-partlabel/STATE

And at this point booting to ChromeOS with ctrl+d still works! Amazing.

Partitions moved to the start of the disk, with a 26.5G accrued of empty space at the end

Rename the SD card – now recovery – rootfs so it doesn't get picked up for booting later.

localhost# fdisk /dev/mmcblk1
Command (m for help): p
Disk /dev/mmcblk1: 7.4 GiB, 7948206080 bytes, 15523840 sectors
Device             Start      End Sectors   Size Type
/dev/mmcblk1p1   4864000  5839843  975844 476.5M Microsoft basic data
/dev/mmcblk1p5    411648   444415   32768    16M Linux filesystem
/dev/mmcblk1p6    444416  4638719 4194304     2G ChromeOS root fs
/dev/mmcblk1p9   4638720  4843519  204800   100M ChromeOS kernel
/dev/mmcblk1p10 11329502 15521791 4192290     2G Linux root (ARM-64)
/dev/mmcblk1p15  4843520  4863999   20480    10M Solaris alternate sector
Command (m for help): x
Expert command (m for help): p
Device             Start      End Sectors Type-UUID                            UUID                                 Name        Attrs
/dev/mmcblk1p1   4864000  5839843  975844 EBD0A0A2-B9E5-4433-87C0-68B6B72699C7 90330FF3-B8B8-124F-8285-416E7A627F64
/dev/mmcblk1p5    411648   444415   32768 0FC63DAF-8483-4772-8E79-3D69D8477DE4 8865BF3D-D8EA-574A-9C55-3AABEFC1E84D             GUID:49,56
/dev/mmcblk1p6    444416  4638719 4194304 3CB8E202-3B7E-47DD-8A3C-7FF2A13CFCEC A0464221-9912-F146-AC7B-C6F489C25176
/dev/mmcblk1p9   4638720  4843519  204800 FE3A2A5D-4F32-41A7-B725-ACCC3285A309 1E061A8C-6159-4486-ADD1-988E88A06ACF             GUID:49,56
/dev/mmcblk1p10 11329502 15521791 4192290 B921B045-1DF0-41C3-AF44-4C6F280D3FAE 525C4783-84CA-B249-ABC8-4635B19103BF chwast-root
/dev/mmcblk1p15  4843520  4863999   20480 6A9283A5-1DD2-11B2-99A6-080020736631 D733780B-EC52-3B4A-B568-FEB45F3C4903

Expert command (m for help): n
Partition number (1,5,6,9,10,15, default 15): 10
New name: chwast-recovery-root
Partition name changed from 'chwast-root' to 'chwast-recovery-root'.
Expert command (m for help): r
Command (m for help): w

and install – by copying – to the eMMC:

localhost# fdisk /dev/mmcblk0
Command (m for help): n
Partition number (4-10,12-128, default 4): 100
First sector (4663296-61071326, default 4663296):
Last sector, +/-sectors or +/-size{K,M,G,T,P} (4663296-61071326, default 61069311): +24M
Created a new partition 100 of type 'Linux filesystem' and of size 24 MiB.
Command (m for help): t
Partition number (1-3,11,100, default 100):
Partition type or alias (type L to list all): 174
Changed type of partition 'Linux filesystem' to 'ChromeOS kernel'.
Command (m for help): x
Expert command (m for help): n
Partition number (1-3,11,100, default 100):
New name: chwast-kernel
Expert command (m for help): S
Partition number (1-3,11,100, default 100):
Enter GUID specific bit (48-63, default 48): 49
The GUID specific bit 49 on partition 100 is enabled now.
Expert command (m for help): S
Partition number (1-3,11,100, default 100):
Enter GUID specific bit (48-63, default 48): 56
The GUID specific bit 56 on partition 100 is enabled now.

Expert command (m for help): p
Device             Start     End Sectors Type-UUID                            UUID                                 Name          Attrs
/dev/mmcblk0p100 4663296 4712447   49152 FE3A2A5D-4F32-41A7-B725-ACCC3285A309 B404D487-BF0B-A842-B93F-742DFB050BA5 chwast-kernel GUID:49,56
Expert command (m for help): r
Command (m for help): p
Device             Start      End  Sectors   Size Type
/dev/mmcblk0p100 4663296  4712447    49152   24M  ChromeOS kernel

Command (m for help): n
Partition number (4-10,12-99,101-128, default 4): 101
First sector (4712448-61071326, default 4712448):
Last sector, +/-sectors or +/-size{K,M,G,T,P} (4712448-61071326, default 61069311): -4G
Created a new partition 101 of type 'Linux filesystem' and of size 22.9 GiB.
Command (m for help): t
Partition number (1-3,11,100,101, default 101):
Partition type or alias (type L to list all): 27
Changed type of partition 'Linux filesystem' to 'Linux root (ARM-64)'.
Command (m for help): x
Expert command (m for help): n
Partition number (1-3,11,100,101, default 101):
New name: chwast-root
Partition name changed from '' to 'chwast-root'.

Expert command (m for help): p
Device             Start      End  Sectors Type-UUID                            UUID                                 Name          Attrs
/dev/mmcblk0p101 4712448 52682751 47970304 B921B045-1DF0-41C3-AF44-4C6F280D3FAE A1A44681-9DB6-5640-81F7-F469F51EAA7B chwast-root
Expert command (m for help): r
Command (m for help): p
Device Start End Sectors Size Type
/dev/mmcblk0p101 4712448 52682751 47970304 22.9G Linux root (ARM-64)

Command (m for help): n
Partition number (4-10,12-99,102-128, default 4): 102
First sector (52682752-61071326, default 52682752):
Last sector, +/-sectors or +/-size{K,M,G,T,P} (52682752-61071326, default 61069311):
Created a new partition 102 of type 'Linux filesystem' and of size 4 GiB.
Command (m for help): t
Partition number (1-3,11,100-102, default 102):
Partition type or alias (type L to list all): swap
Changed type of partition 'Linux filesystem' to 'Linux swap'.
Command (m for help): x
Expert command (m for help): n
Partition number (1-3,11,100-102, default 102):
New name: chwast-swap
Partition name changed from '' to 'chwast-swap'.

Expert command (m for help): p
Device              Start      End  Sectors Type-UUID                            UUID                                 Name          Attrs
/dev/mmcblk0p1    3614720  4663295  1048576 EBD0A0A2-B9E5-4433-87C0-68B6B72699C7 DE9260C7-B796-4681-82E1-6BF5E1DDC405 STATE
/dev/mmcblk0p2      16448    49215    32768 FE3A2A5D-4F32-41A7-B725-ACCC3285A309 B9393B88-B27F-438D-BF88-93BE6E66E4A9 KERN-A        GUID:48,56
/dev/mmcblk0p3      51200  3614719  3563520 3CB8E202-3B7E-47DD-8A3C-7FF2A13CFCEC ACB76082-35D1-46F0-A8E9-97006C40B632 ROOT-A
/dev/mmcblk0p11        64    16447    16384 CAB6E88E-ABF3-4102-A07A-D4BB9BE3C1D3 530A6C46-BDFA-7C40-A446-FC05001BDA82 RWFW
/dev/mmcblk0p100  4663296  4712447    49152 FE3A2A5D-4F32-41A7-B725-ACCC3285A309 B404D487-BF0B-A842-B93F-742DFB050BA5 chwast-kernel GUID:49,56
/dev/mmcblk0p101  4712448 52682751 47970304 B921B045-1DF0-41C3-AF44-4C6F280D3FAE A1A44681-9DB6-5640-81F7-F469F51EAA7B chwast-root
/dev/mmcblk0p102 52682752 61069311  8386560 0657FD6D-A4AB-43C4-84E5-0933C84B4F4F 0AAF87E8-B293-964A-8073-605103B71460 chwast-swap
Expert command (m for help): r
Command (m for help): p
Device             Start       End  Sectors  Size Type
/dev/mmcblk0p1    3614720  4663295  1048576  512M Microsoft basic data
/dev/mmcblk0p2      16448    49215    32768   16M ChromeOS kernel
/dev/mmcblk0p3      51200  3614719  3563520  1.7G ChromeOS root fs
/dev/mmcblk0p11        64    16447    16384    8M ChromeOS firmware
/dev/mmcblk0p100  4663296  4712447    49152   24M ChromeOS kernel
/dev/mmcblk0p101  4712448 52682751 47970304 22.9G Linux root (ARM-64)
/dev/mmcblk0p102 52682752 61069311  8386560    4G Linux swap
Command (m for help): w

localhost# cp /dev/mmcblk1p9 /dev/disk/by-partlabel/chwast-kernel
cp: error writing '/dev/disk/by-partlabel/chwast-kernel': No space left on device
# benign: overprovisioned at 100M, the actual bundle is <20M
localhost# blkdiscard /dev/disk/by-partlabel/chwast-root
localhost# e2image -rap /dev/mmcblk1p10 /dev/disk/by-partlabel/chwast-root
e2image 1.46.5 (30-Dec-2021)
Scanning inodes...
Copied 1852984 / 1852984 blocks (100%) in 00:01:56 at 15.60 MB/s       s
localhost# mkswap -L chwast-swap /dev/disk/by-partlabel/chwast-swap
Setting up swapspace version 1, size = 4 GiB (4293914624 bytes)
LABEL=chwast-swap, UUID=d88296c6-5438-41f2-866a-e1e9e01b77b3

Partition 100 (chrust-kernel): 24M
Partition 101 (chrust-root): 22.875G
Partition 100 (chrust-swap): 4G
added

chwast-kernel on partition 100 has priority 2 (49=1, 48=00b10) with its Successful Boot Flag set, and will thus be chosen over KERN-A (partition 2) with priority 1.

# arm64 Chromebook Debian port install% 23-day RTA/#137 IGT WR

chwast# resize2fs /dev/dev/disk/by-partlabel/chwast-root
resize2fs 1.47.0 (5-Feb-2023)
Filesystem at /dev/disk/by-partlabel/chwast-root is mounted on /; on-line resizing required
old_desc_blocks = 8, new_desc_blocks = 92
The filesystem on /dev/dev/disk/by-partlabel/chwast-root is now 5926272 (4k) blocks long.
chwast# df -h
Filesystem       Size  Used Avail Use% Mounted on
/dev/mmcblk0p100  22G  1.7G   19G   8% /

# ChromeOS as a recovery system

has a propensity to shuffle the priorities, but it's nothing major.

Disable the successful boot flag on the Debian kernel:

chwast# fdisk /dev/mmcblk0
Command (m for help): x
Expert command (m for help): p
Device             Start     End Sectors Type-UUID                            UUID                                 Name          Attrs
/dev/mmcblk0p2     16448   49215   32768 FE3A2A5D-4F32-41A7-B725-ACCC3285A309 B9393B88-B27F-438D-BF88-93BE6E66E4A9 KERN-A        GUID:48,56
/dev/mmcblk0p100 4663296 4712447   49152 FE3A2A5D-4F32-41A7-B725-ACCC3285A309 B404D487-BF0B-A842-B93F-742DFB050BA5 chwast-kernel GUID:49,56

Expert command (m for help): S
Partition number (1-3,11,100-102, default 102): 100
Enter GUID specific bit (48-63, default 48): 56
The GUID specific bit 56 on partition 100 is disabled now.

chwast# reboot 

After rebooting, now to ChromeOS, note how the priorities were automatically inverted.

localhost# fdisk /dev/mmcblk0
Command (m for help): x
Expert command (m for help): p
Device              Start      End  Sectors Type-UUID                            UUID                                 Name          Attrs
/dev/mmcblk0p2      16448    49215    32768 FE3A2A5D-4F32-41A7-B725-ACCC3285A309 B9393B88-B27F-438D-BF88-93BE6E66E4A9 KERN-A        GUID:49,56
/dev/mmcblk0p100  4663296  4712447    49152 FE3A2A5D-4F32-41A7-B725-ACCC3285A309 B404D487-BF0B-A842-B93F-742DFB050BA5 chwast-kernel GUID:48

Expert command (m for help): S
Partition number (1-3,11,100-102, default 102): 100
Enter GUID specific bit (48-63, default 48): 56
The GUID specific bit 56 on partition 100 is enabled now.

Expert command (m for help): S
Partition number (1-3,11,100-102, default 102): 2
Enter GUID specific bit (48-63, default 48): 49
The GUID specific bit 49 on partition 2 is disabled now.

localhost# reboot 

And with

KERN-A
GUID:56
chwast-kernel
GUID:48,56

the re-boot chooses the Debian kernel again. For a subsequent recovery run, toggling KERN-A's bit 49 would also work.

# they unfucked the HIDs bro its crazy

In pointed contrast to 012a. Installing Debian on the Lenovo 300e 2nd-gen Chromebook (Intel), Post Install, General QOL Fixes, Run the cros-keyboard-map script[…].

esc
Escape
F1
F2
F3
hollow rectangle with chevrons in the top-left and bottom-right internal corners
F4
hollow rectangle, to its right are two vertical stripes
F5
☀️
F6
☀️
F7
🔇
F8
🔉
F9
🔊
F10
🔒
XF86Sleep

(🔒 is the Suspend Key and handled by logind by default.) Caps Lock is replaced with

🔍
Super_L

esc, 🔒, and 🔍 are the same as on the Intel 300e. All the other ones aren't, and this is for the best – you can switch VTs normally! You almost wouldn't notice the keyboard's fucked! sans the usual omissions of Home/End/Delete of course.

The clicky buttons on the side –

volume up
XF86AudioRaiseVolume
volume down
XF86AudioLowerVolume
power
power key logind understands

– are distinguished from 🔉/🔊 this time! Imagine!

For these same inputs keyd yields

device added: 0000:0000 cros_ec (/dev/input/event0)
device added: 06cb:1a10 hid-over-i2c 06CB:1A10 (/dev/input/event1)
device added: 04f3:009f Elan Touchpad (/dev/input/event3)
cros_ec 0000:0000 esc down
cros_ec 0000:0000 f1 down
cros_ec 0000:0000 f2 down
cros_ec 0000:0000 f3 down
cros_ec 0000:0000 f4 down
cros_ec 0000:0000 f5 down
cros_ec 0000:0000 f6 down
cros_ec 0000:0000 f7 down
cros_ec 0000:0000 f8 down
cros_ec 0000:0000 f9 down
cros_ec 0000:0000 f10 down
cros_ec 0000:0000 sleep down
cros_ec 0000:0000 leftmeta down

– note that the side buttons don't generate any input event! But this agrees with our other findings, and thus, for the same mapping as last time, a simple /etc/keyd/cros_ec.conf of

[ids]
0000:0000

[alt]
left	= home
right	= end
up	= pageup
down	= pagedown

[main]
# Don't mangle these (https://github.com/rvaiya/keyd/issues/618)
rightcontrol	= rightcontrol
rightshift	= rightshift

# 🔒
sleep		= delete

# 🔍 remains as leftmeta

[meta]
# ←
f1	= back
# →
f2	= forward
# ⟳
f3	= refresh
# tableau
f4	= print
# fast rectangle
f5	= scale
# small ☀️
f6	= brightnessdown
# ☀️
f7	= brightnessup
# 🔇
f8	= mute
# 🔉
f9	= volumedown
# 🔊
f10	= volumeup

sleep	= sleep

suffices.

# naaah no they fuckin didn't

Yeah so the touchpad has one button.

This by itself is baffling, but since the "Tapping" mode basically a necessity for the modern user anyway (the methodology in 012a. Installing Debian on the Lenovo 300e 2nd-gen Chromebook (Intel), Installing Linux, /etc/X11/xorg.conf.d/touchpad.conf applies) it's only an issue for the first 10min because clicking touchpads sucks on a good day so the

1 finger
left click
2 fingers
right click
3 fingers
middle click

mapping thus enabled is all-'round better than only having two buttons would've been. Plus, there's already a 75-big pad for clicking just above.

# HDMI

Doesn't work.

But it does work under ChromeOS, with dmesg | grep -i hdmi yielding

[    0.130803] mediatek-hdmi-phy 10209100.hdmi-phy: Using default TX DRV impedance: 4.2k/36
[    0.131789] mediatek-drm-hdmi 14025000.hdmi: Waiting for external bridge
[    0.133463] gpio-display-mux hdmi_mux: GPIO lookup for consumer detect
[    0.133468] gpio-display-mux hdmi_mux: using device tree for GPIO lookup
[    0.133485] of_get_named_gpiod_flags: parsed 'detect-gpios' property of node '/hdmi_mux[0]' - status (0)
[    0.133519] gpio-display-mux hdmi_mux: Waiting for external bridge anx7688
[    0.960402] mediatek-drm-hdmi 14025000.hdmi: Waiting for external bridge
[    0.960636] gpio-display-mux hdmi_mux: GPIO lookup for consumer detect
[    0.960638] gpio-display-mux hdmi_mux: using device tree for GPIO lookup
[    0.960645] of_get_named_gpiod_flags: parsed 'detect-gpios' property of node '/hdmi_mux[0]' - status (0)
[    0.967421] [drm] hdmi-audio-codec driver bound to HDMI
[    0.968986] mtk-rt5650 sound: snd-soc-dummy-dai <-> HDMI mapping ok
[    0.969679] mtk-rt5650 sound: i2s-hifi <-> HDMIO mapping ok
[    1.025253] input: mtk-rt5650 HDMI Jack as /devices/platform/sound/sound/card0/input6
[    1.025521] mediatek-dpi 1401d000.dpi: Found bridge node: /soc/hdmi@14025000
[   11.742614] udevd[2142]: Process '/usr/sbin/hdcp_pass_key.sh /devices/platform/soc/14025000.hdmi' failed with exit code 1.
[   11.895324] udevd[2145]: Process '/usr/sbin/hdcp_pass_key.sh /devices/platform/soc/14025000.hdmi/hdmi-audio-codec.11.auto' failed with exit code 1.

whereas the same under 6.6.11 #137 is only

[    18:20:17] platform 14025000.hdmi: Fixed dependency cycle(s) with /soc/dpi@1401d000/port/endpoint
[    18:20:17] platform connector: Fixed dependency cycle(s) with /soc/hdmi@14025000/ports/port@1/endpoint
[    18:20:17] mediatek-hdmi-phy 10209100.hdmi-phy: Using default TX DRV impedance: 4.2k/36
[    18:20:17] [drm] hdmi-audio-codec driver bound to HDMI
[    18:20:17] mediatek-dpi 1401d000.dpi: Found bridge node: /soc/hdmi@14025000
[    18:20:20] input: mtk-rt5650 HDMI Jack as /devices/platform/sound/sound/card0/input9

(matching lines lowlighted). So only the audio goop is common.

Fortuitously, while a grep for of_get_named_gpiod_flags was uneventful, a grep for gpio-display-mux yielded nothing – not one single reult – in the 6.6.11 tree. Well then!

gpio-display-mux figures in the ChromeOS device tree as

	hdmi_mux {
		compatible = "gpio-display-mux";
		status = "okay";
		detect-gpios = <0x15 0x24 0x00>;

and not at all in the 6.6.11 one; the first google result is [v3,4/5] dt-bindings: display: bridge: Add GPIO display mux binding, part of the [PATCH v3 0/5] Add generic-display-mux driver and bindings, series from 2023-02-18. (Attentive readers may remember this is a 2019 device.) All great, except this series is dropped because it doesn't do something-or-other cromulently enough for the DRM subsystem. If only you could've arrived at this before you shipped hundreds of thousands of units!

The series from patchwork applies with minimal fuzz; this also references the analogix,anx7688 device –

		spi@1100a000 {
			ec@0 {
				i2c-tunnel@1 {
					compatible = "google,cros-ec-i2c-tunnel";
					google,remote-bus = <0x01>;
					#address-cells = <0x01>;
					#size-cells = <0x00>;

					anx7688@2c {
						compatible = "analogix,anx7688";
						status = "okay";
						reg = <0x2c>;

– also not present (incl. the tunnel) in the 6.6.11 device tree, also with no compatible module. There's an extrmely crusty patch for it (targetting the PinePhone) from this Thursday; it also applies with no fuzz.

$ make -j25 ARCH=arm64 LLVM=1 oldconfig
Generic GPIO-controlled mux (DRM_GENERIC_GPIO_MUX) [N/m/y/?] (NEW) y
Analogix ANX7688 Type-C DRP Port controller and mux driver (TYPEC_ANX7688) [N/m/y/?] (NEW) y

and it builds fine as well. Neither of them change the device tree, however, so I carefully grafted both devices thereinto, yielding

18M 02-04 19:44 mandeb+initrd+1+tabs2+reg+drm+adc+d_t_c-initrd&mwifiex+mmc1+gpio-display-mux.dtb
18M 02-04 19:53 mandeb+initrd+1+tabs2+reg+drm+adc+d_t_c-initrd&mwifiex+mmc1+gpio-display-mux2.dtb
18M 02-04 20:09 mandeb+initrd+1+tabs2+reg+drm+adc+d_t_c-initrd&mwifiex+mmc1+gpio-display-mux3.dtb
18M 02-04 20:29 mandeb+initrd+1+tabs2+reg+drm+adc+d_t_c-initrd&mwifiex+mmc1+gpio-display-mux3+anx.dtb

which boots to black screen, neither alt+🔊+r nor +power button leave anything in the pstore.

# blob-free boot bundle real

Heretofore the device trees to sign/bundle and boot were a bastardised version of the ChromeOS boot bundle's device tree. This works, but is both plain odd and existentially problematic – what is the boot bundles contain device trees without the right compatible = stanza like in EFI-SYSTEM?

Given that the bootloader coughs up to Starting depthcharge on hana..., a quick "site:manpages.debian.org depthcharge" search yields mkdepthcharge(1) (as part of depthcharge-tools, which also includes kernel/initrd hooks, pulls in a tremendous amount of dependencies, and ships a service to massage the partition table on boot – absolutely not happening, sorry), pointing at mkimage(1) (u-boot-tools), and mkimage -l mandeb+initrd+1+tabs2+reg+drm+adc+d_t_c-initrd\&mwifiex+mmc1-sdr.dtb starts with

Image contains unit addresses @, this will break signing
FIT description: Chrome OS kernel image with one or more FDT blobs
Created:         Mon Apr 17 04:48:47 2023
 Image 0 (kernel@1)
  Description:  unavailable
  Created:      Mon Apr 17 04:48:47 2023
  Type:         Kernel Image (no loading done)
  Compression:  lz4 compressed
  Data Size:    15550846 Bytes = 15186.37 KiB = 14.83 MiB
 Image 1 (fdt@1)
  Description:  mt2712-evb.dtb
  Created:      Mon Apr 17 04:48:47 2023
  Type:         Flat Device Tree
  Compression:  uncompressed
  Data Size:    8174 Bytes = 7.98 KiB = 0.01 MiB
  Architecture: AArch64
  Hash algo:    sha1
  Hash value:   2cb3b42d319ed9579540b17d7c2c68863329e8fe Configuration 0 (conf@1)
  Description:  unavailable
  Kernel:       kernel@1
  FDT:          fdt@1

– certainly promising.

By adapting an example from the manual, mkimage -f auto -A arm64 -T kernel -C lz4 -d Image.lz4 -b mt8173-elm-hana.dtb Image.dtb (naturally, here the architecture defaults to PowerPC; the kernel must already be pre-LZ4ed and not a pipe) produces Image.dtb, which, after decompilation, looks like

/dts-v1/;

/ {
	timestamp = <0x65c03b5b>;
	description = "Kernel Image image with one or more FDT blobs";
	creator = "U-Boot mkimage 2023.01";
	#address-cells = <0x01>;

	images {

		kernel-1 {
			description = [00];
			type = "kernel";
			arch = "arm64";
			os = "linux";
			compression = "lz4";
			load = <0x00>;
			entry = <0x00>;
			data = [04 22 4d 18 …];

			hash-1 {
				value = <0x9e4dfdd9>;
				algo = "crc32";
			};
		};

		fdt-1 {
			description = "mt8173-elm-hana";
			data = [d0 0d fe ed …];
			type = "flat_dt";
			arch = "arm64";
			compression = "none";

			hash-1 {
				value = <0xae9f8591>;
				algo = "crc32";
			};
		};
	};

	configurations {
		default = "conf-1";

		conf-1 {
			description = "mt8173-elm-hana";
			kernel = "kernel-1";
			loadables = "kernel-1";
			fdt = "fdt-1";
		};
	};
};

(note the differences from ChromeOS's – both are hashed, but with CRC32; IDs delimited with -es instead of @s). The type is kernel rather than kernel_noload (Kernel Image (no loading done)) because if you use kernel_noload then it doesn't boot because it calls the node kernel_noload-1. You could decompile/re-tag to type = "kernel_noload"/recompile to match ChromeOS, which works, and mkdepthcharge appears convinced is required, but it doesn't appear to change anything, and -T kernel just works.

This makes the final kernel installation look like

$ lz4 -9 < .../arch/arm64/boot/Image > Image.lz4
$ mkimage -f auto -A arm64 \
    -T kernel -C lz4 -d Image.lz4 \
    -b .../arch/arm64/boot/dts/mediatek/mt8173-elm-hana.dtb \
    Image.dtb
FIT description: Kernel Image image with one or more FDT blobs
Created:         Mon Feb  5 01:17:41 2024
 Image 0 (kernel-1)
  Description:
  Created:      Mon Feb  5 01:17:41 2024
  Type:         Kernel Image
  Compression:  lz4 compressed
  Data Size:    12611929 Bytes = 12316.34 KiB = 12.03 MiB
  Architecture: AArch64
  OS:           Linux
  Load Address: 0x00000000
  Entry Point:  0x00000000
  Hash algo:    crc32
  Hash value:   03808745
 Image 1 (fdt-1)
  Description:  mt8173-elm-hana
  Created:      Mon Feb  5 01:17:41 2024
  Type:         Flat Device Tree
  Compression:  uncompressed
  Data Size:    43853 Bytes = 42.83 KiB = 0.04 MiB
  Architecture: AArch64
  Hash algo:    crc32
  Hash value:   ae9f8591
 Default Configuration: 'conf-1'
 Configuration 0 (conf-1)
  Description:  mt8173-elm-hana
  Kernel:       kernel-1
  FDT:          fdt-1
  Loadables:    kernel-1

$ printf '\0' > bootloader
$ echo root=PARTLABEL=chwast-root rootwait console=pstore-1 console=tty1 > cmdline
# vbutil_kernel --pack /dev/disk/by-partlabel/chwast-root \
    --keyblock    /usr/share/vboot/devkeys/kernel.keyblock \
    --signprivate /usr/share/vboot/devkeys/kernel_data_key.vbprivk \
    --version     1 \
    --vmlinuz     Image.dtb \
    --bootloader  bootloader \
    --config      cmdline \
    --arch        arm64

which provides for a roughly-normal /boot and a simple installation script,

18M 02-04 21:36 mandeb+initrd+1+tabs2+reg+drm+adc+d_t_c-initrd&mwifiex+mmc1-sdr.dtb
13M 02-05 04:24 6.6.11.bundle

The firmware, which logged

Boot policy: Match for type 0 with cmdline 1
Modified kernel command line: cros_secure console= loglevel=7 init=/sbin/init cros_secure drm.trace=0x106 root=PARTUUID=ccfe5bd8-bbe4-a840-9c0b-bba6427b6309/PARTNROFF=1 rootwait rw dm_verity.error_behavior=3 dm_verity.max_bios=-1 dm_verity.dev_wait=0 dm="1 vroot none ro 1,0 4077568 verity payload=ROOT_DEV hashtree=#_DEV hashstart=4077568 alg=sha256 root_hexdigest=59f5ac907dd5cfa3f6fdef15b166c94065a41ef4abfd0d9c68db6ef4a2f62a68 salt=05e2c9a8dc172bc5efe0c899186b436bb89609a064eabcaeb5ec07441cf2a122" noinitrd vt.global_cursor_default=0 kern_guid=ccfe5bd8-bbe4-a840-9c0b-bba6427b6309 cpuidle.governor=teo
Loading FIT.
Image fdt@54 has 61778 bytes.
…
Image fdt@1 has 8174 bytes.
Image kernel@1 has 8706585 bytes.
Compat preference: google,hana-rev5
Config conf@54, kernel kernel@1, fdt fdt@54, compat google,willow-sku1 google,willow mediatek,mt8183
…
Config conf@9, kernel kernel@1, fdt fdt@9, compat google,hana-rev6 google,hana-rev5 (match) google,hana-rev4 google,hana-rev3 google,hana-rev2 google,hana-rev1 google,hana mediatek,mt8173
…
Config conf@1, kernel kernel@1, fdt fdt@1, compat mediatek,mt2712-evb mediatek,mt2712
Choosing best match conf@9.
Shutting down all USB controllers.
Exiting depthcharge with code 4 at timestamp: 5889734
Decompressing LZ4 kernel to 0x40080000
jumping to kernel

now logs

Boot policy: Match for type 0 with cmdline 1
Modified kernel command line: cros_secure root=PARTLABEL=chwast-root rootwait console=pstore-1 console=tty1
Loading FIT.
Image fdt-1 has 43853 bytes.
Image kernel-1 has 12611929 bytes.
Compat preference: google,hana-rev5
Config conf-1 (default), kernel kernel-1, fdt fdt-1, compat google,hana-rev6 google,hana-rev5 (match) google,hana-rev4 google,hana-rev3 google,hana mediatek,mt8173
Choosing best match conf-1.
Shutting down all USB controllers.
Exiting depthcharge with code 4 at timestamp: 2759765
Decompressing LZ4 kernel to 0x40000000
jumping to kernel

# Miscellanea:

# How to get Debian on your Google Hana 2023 (real (working (no virus)))

  1. Partition an SD card with a "ChromeOS kernel"-type partition with type-specific GUID bits 56 (Successful Boot Flag) and 48 (priority 1) set and some space for the rootfs (similarly to how the installed state looks)
  2. Strap or install an arm64 to that rootfs (ext[234], or set CONFIG_XFS=y or whatever in the config below); mount on /mnt
  3. apt source linux
  4. Generate the Debian config (à la cp /boot/config-6.6.11-arm64 .config; paths per debian/rules.gen):
    debian/bin/kconfig.py .config debian/config/config debian/config/arm64/config
    make ARCH=arm64 olddefconfig 
  5. scripts/kconfig/merge_config.sh -m .config config-6.6.11.diff-m
  6. patch -p1 < mwifiex.patch # warning backtrace; from Dmitry Antipov, though the patch in the mail is damaged
  7. patch -p1 < mt8173-fix-mmc1-speed.patch # oops when using SDR104 cards; from mt8173-fix-mmc1-speed.patch
  8. patch -p1 < mt8173-higher-temps.patch # raise temps for elm a bit; from mt8173-higher-temps.patch
  9. make ARCH=arm64 Image modules dtbs
  10. make ARCH=arm64 modules_install INSTALL_MOD_PATH=/mnt INSTALL_MOD_STRIP=1
  11. lz4 -9 < arch/arm64/boot/Image > /mnt/boot/Image-6.6.11.lz4 (or whatever the version)
  12. cp arch/arm64/boot/dts/mediatek/mt8173-elm-hana.dtb /mnt/boot/mt8173-elm-hana-6.6.11.dtb
  13. In /mnt/boot: echo console=pstore-1 console=tty1 rootwait root=as appropriate for the rootfs > cmdline &c.
  14. With u-boot-tools and vboot-kernel-utils (very much --no-install-recommendsed): ./bundle 6.6.11 > /dev/the-kernel-partition
  15. Developer-mode-ify the Chromebook
  16. Insert the SD card and press ctrl+u to boot
  17. See the installing Debian sexion for booting the same from the eMMC

# Funxional summary

# Funxional

# Dysfunxional

# Summary

A successful non-invasive reversible methodology to install Debian on a presently-still-novel ARM64 Chromebook platform, all possible because the MT8173 platform is well-supported by Linux and because the elm/hana platform is reasonably-supported by Linux (sans the HDMI thing).

A top-down and bottom-up analysis of the Chromebook bootloader stack with effectively no a priori knowledge, and attempts at replication of various documentation showing mostly negative results.

1.94W idle (at a reasonable indoor backlight brightess) is the lowest power consumption I've seen on a computer. This is maintained at around 2.3W during static web browsing, and extends to >12h projected times-to-empty at around 70% battery capacity (~23h at ~100%).. There are no hardware accelerators that Firefox understands; there's no OpenGL; fullscreen glxgears (llvmpipe) gets 57FPS, half-screen gets 140FPS, both at around 7W.

Issues identified (chronological order):

  1. [PATCH] libfdisk: fdisk_deassign_device: only sync(2) blockdevs
  2. [PATCH] gpt-partnames: add "ChromeOS firmware" & doc link
  3. Bug#1061329: /usr/bin/futility: "FATAL: do_vbutil_kernel: Error reading bootloader file." when --bootloader points to empty file
  4. Bug#1061537: kexec-tools: non-text error output
  5. memcpy: detected field-spanning write (size 101) of single field "ext_scan->tlv_buffer" at drivers/net/wireless/marvell/mwifiex/scan.c:2251 (size 1)
  6. [PATCH] spi: Kconfig: cap[c]ability
  7. Bug#1062208: /usr/sbin/fsck: exits 0 with no output (just version) when it doesn't find a type-specific fsck
  8. Bug#1062213: /usr/bin/wpctl: "status" draws output table with garbage
  9. Bug#1062262: pipewire-alsa: adversarial description
  10. #31199: systemd-gpt-auto-generator automatically generates units, manual says it oughtn't on the count of (a) not being EFI and (b) not/or having an ESP
  11. #521: Bogus battery time left (nine hundred hours) – POWER_SUPPLY_TIME_TO_EMPTY_NOW taken as minutes when it is seconds: driver compatibility?
  12. #522: man: . at end of sentence
  13. #523: Neither "battery all" nor "battery sbs-6-000b" work
  14. Bug#1063097: /usr/bin/mkimage: opens image and device trees (-d, -b) O_RDONLY, then O_RDWR, and fails if they're read-only (it doesn't write to them)
13M 02-06 19:18 6.6.15.bundle

25 straight days well spent on commit 9628372: Add hardware-accellerated crc32c() for ARM64.
Buy my album buy my stickers.


Nit-pick? Correction? Improvement? Annoying? Cute? Anything? Mail, post, or open!


Creative text licensed under CC-BY-SA 4.0, code licensed under The MIT License.
This page is open-source, you can find it at GitHub, and contribute and/or yell at me there.
Like what you see? Consider giving me a follow over at social medias listed here, or maybe even a sending a buck liberapay donate or two patreon my way if my software helped you in some significant way?
Compiled with Clang 19's C preprocessor on 10.09.2025 21:18:14 UTC from src/blogn_t/012b-debian-chromebook-lenovo-300e-gen2-mtk-real.html.pp.
See job on builds.sr.ht.
RSS feed