Files
hp-chell/CLAUDE.md
T
ergosteurandClaude Opus 5.5 93f4eca05c Add install-flex-emmc.sh for a proper ChromeOS Flex install on eMMC
The earlier raw dd of the Flex recovery image left the installer layout
(2MB ROOT-B placeholder, fixed 6GB STATE), so Flex booted as live media
and couldn't A/B update. The script runs the image's own chromeos-install
against the eMMC from neon, chrooted into the image in a private mount
namespace with all other disks masked. Handles the cros_efi cmdline
requirement, udisks auto-mount interference, and unreliable exit status.
Tested end to end on hp-chell.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-27 12:20:08 -04:00

13 KiB

hp-chell project notes

Agent-accessible host

  • hp-chell (hp-chell.lan.1qaz.ca) — KDE neon (Debian-based) x86_64 laptop (Intel Core m7-6Y75, 4 cores, 15GiB RAM, 117GB disk, Intel HD Graphics 515), full sudo (nopasswd) account agent-user (uid 60123). Provisioned 2026-09-03.
    • Auth: SSH key preferred (this machine's ~/.ssh/id_ed25519.pub is already in the host's authorized_keys) — ssh agent-user@hp-chell.lan.1qaz.ca. When working on hp-chell itself as matt (no nopasswd sudo), matt's own ~/.ssh/id_ed25519.pub is also authorized (added 2026-09-27) — use ssh agent-user@localhost 'sudo ...' for root.
    • Fallback password: stored in local Bitwarden vault, item id 1db3b9f6-a82e-4692-846a-b4bb002a5be6 (name "agent-user@hp-chell.lan.1qaz.ca (SSH)") — fetch with bw get password 1db3b9f6-a82e-4692-846a-b4bb002a5be6 (vault must be unlocked; bw unlock).
    • Host inventory/specs: see ~/AGENT_INFO.md on the host itself. Original provisioning prompt saved at ~/AGENT_PROMPT.txt on the host.
    • Groups: adm,cdrom,sudo,dip,plugdev,lpadmin,sambashare,docker. Has docker, tailscale0 interface (not connected as of provisioning), python3.12, git, jq, rsync, tmux.

Hardware identity (confirmed via sudo dmidecode -t system -t baseboard -t bios)

This is a real HP Chromebook 13 G1 ("chell" board), converted from ChromeOS to a normal Linux boot via custom coreboot firmware (MrChromebox project) and now running KDE neon as its OS.

  • BIOS/firmware: coreboot, version MrChromebox-2606.1 (release date 07/14/2026) — confirms MrChromebox custom firmware, not stock ChromeOS firmware. (Was MrChromebox-2512.2 / 01/25/2026 as of initial provisioning 2026-09-03; updated via MrChromebox firmware utility same day — see note below.)
  • System: Manufacturer Google, Product Name Chell, Family Google_Glados, Serial 5CD732BLC9 — Chell/Glados is the Google Chrome OS board/reference codename for the HP Chromebook 13 G1.
  • Baseboard: Manufacturer Google, Product Name Chell, Serial PFYTU018J90043.
  • Implication: fanless Core m CPU, no way to add a fan — keep sustained-load expectations modest.
  • Storage correction (2026-09-04): sda (117GB, where / lives) is actually an external USB/SD card (lsblk shows TRAN=usb) — the whole KDE neon install boots from that external card, not from anything internal. The real internal eMMC (mmcblk0, ~29GB) was blank until 2026-09-04, when ChromeOS Flex was installed onto it — see "Dual boot" section below. (Superseded the original note here, which incorrectly assumed sda was internal.)

Kernel 7.x black-screen bug (diagnosed and fixed 2026-09-03)

Multiple kernels are installed: 6.17.0-42-generic (and -35) work fine at boot. 7.0.0-30-generic (and -14) hit a cold-boot display bug: the panel's backlight comes on but no image ever appears — looks like a dead screen.

Root cause: on a 7.x kernel, i915's very first modeset at boot (Xorg/ Weston auto-configuring the panel's native 3200x1800@60) leaves pipe A stuck — dmesg shows a CPU pipe A FIFO underrun right after Reducing the compressed framebuffer size.... Everything above that layer (DRM connector/plane/CRTC state, backlight sysfs, Xorg/Weston logs) reports fully healthy — eDP-1 connected/enabled/dpms=On, pipe active, plane visible with real framebuffer content — yet the panel shows nothing. A second modeset (any resolution change via xrandr) reliably un-sticks the pipe and it works perfectly afterward, including back at full native resolution and 12bpc color. This is a kernel/i915 bug, not specific to a display server — confirmed identical failure under both Xorg (sddm default) and Wayland (sddm + weston, via DisplayServer=wayland in sddm.conf.d, which needs the weston package or it silently falls back to X11).

Ruled out (each verified, none of these were the actual cause):

  • Dim/stale backlight (/var/lib/systemd/backlight/... restoring a low saved value) — this was a real but separate red herring encountered early in diagnosis; fixed by just adjusting brightness once logged in normally. Not the cause of the later, reproducible black-screen bug.
  • cros-ec-gpio: Failed to attach ACPI GPIO chip / EC:ENABLE_BACKLIGHT GPIO name collisions — present identically on working 6.17 boots too.
  • i915.nuclear_pageflip=0 boot param — was already present during the original failures; adding/removing it makes no difference (legacy atomic-modeset override, irrelevant on modern i915; also needlessly taints the kernel — removed from /etc/default/grub).
  • i915.enable_fbc=0, i915.enable_psr=0, i915.enable_sagv=0 — each tried individually via kernel cmdline, none fixed it.

Fix in place: /usr/share/sddm/scripts/Xsetup (SDDM's root-run hook, fires right after the X/Wayland server starts, before the greeter draws) detects a 7.* kernel via uname -r and runs xrandr --output eDP-1 --mode 1600x900 — a second modeset that un-sticks the pipe. 1600x900 was chosen (rather than cycling back to native) since it's an exact half of the panel's native 3200x1800 (clean 2x integer scaling) and it's only the greeter — the actual logged-in Plasma/Wayland session correctly renews the modeset itself and comes up at full native 3200x1800 with 125% scaling, confirmed working. No kernel cmdline workarounds are needed — /etc/default/grub's GRUB_CMDLINE_LINUX_DEFAULT is back to a clean 'splash'.

Confirmed reliable across multiple clean sudo systemctl poweroff / power-on cycles. The GRUB default entry (index 0, GRUB_DEFAULT=0) auto- selects the newest installed kernel, so 7.0.0-30-generic is what boots by default now; 6.17.0-42-generic remains available via the GRUB "Advanced options" submenu as a known-good fallback if ever needed.

2026-09-27, SDDM → Plasma Login: an apt upgrade (which also brought kernel 7.0.0-34-generic) switched the display manager to plasmalogin (/etc/X11/default-display-manager). Its greeter runs under kwin_wayland (user plasmalogin, uid 984, plasma-login*.service in its systemd user manager), so the SDDM Xsetup hook above no longer fires and the black screen came back. Findings:

  • A resolution change via kscreen-doctor (1600x900 and back) is not enough under KWin: the eDP panel fitter absorbs it (kernel adjusted mode stays native 3200x1800, no real pipe modeset). Going to 1600x900 and staying there would also be unusable anyway — KWin keeps the 1.85x scale, giving an 865x487 logical greeter.
  • A DPMS cycle (kscreen-doctor --dpms off then --dpms on) fully disables the CRTC (i915_display_info shows pipe A active=no) and its re-enable is a genuine full modeset — that un-sticks the pipe.
  • kscreen-doctor needs the greeter's session bus to apply changes (DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/984/bus, WAYLAND_DISPLAY=wayland-0); with KSCREEN_BACKEND_INPROCESS=1 it reads outputs fine but silently fails to set ("Cannot find output with id 1"). Mode specs must match exactly (1600x900@59.95, not @60) or use mode ids.
  • i915 debugfs is under /sys/kernel/debug/dri/1/ on this box (DRM minor 1), not dri/0.

Fix: /usr/local/libexec/hp-chell-i915-dpms-cycle (no-op unless kernel 7.* and user plasmalogin; waits for KWin, then cycles DPMS), run via /etc/systemd/user/plasma-login.service.d/10-i915-kernel7-dpms-cycle.conf as ExecStartPre (plasma-login.service is ordered after plasma-login-kwin_wayland.service, so KWin is already up).

Setup script for a fresh install: setup-i915-kernel7-fix.sh (in this repo) installs both the SDDM Xsetup fix and the Plasma Login drop-in, and sets GRUB_TIMEOUT=5 / GRUB_TIMEOUT_STYLE=menu so the boot menu is visible for 5s. Idempotent, safe to re-run.

2026-09-03, post firmware update: updated coreboot from MrChromebox-2512.2 to MrChromebox-2606.1 via the MrChromebox firmware utility, then rebooted. First boot after the flash appeared to hang after the Plymouth splash (same visual symptom: backlight on, no image) and required a forced power-off. The next boot after that came up clean at SDDM with the Xsetup fix applying normally (empty /tmp/xsetup- modeset.log, one FIFO underrun as expected, pipe un-stuck as usual) — so this looks like a one-off "settle in" hiccup from the fresh firmware flash itself, not a recurrence of the underlying i915 bug or a new problem. If it happens again right after a firmware update, try a forced power-off + power-on before assuming anything is actually broken.

Dual boot: KDE neon (USB) + ChromeOS Flex (internal eMMC)

2026-09-04: installed ChromeOS Flex onto the internal eMMC (/dev/mmcblk0), which was blank (see storage correction above — the KDE neon system boots from an external USB/SD card on sda, not from anything internal, so writing to the eMMC was safe to do live from the running system with zero risk to the neon install).

How it was installed: the Flex recovery image (chromeos_16640.57.0_reven_recovery_stable-channel_RevenMPKeys-v10.bin.zip, in matt's ~/Downloads) is a full raw GPT disk image — exactly what the normal "boot from USB, then Install CloudReady/Chrome OS Flex" flow dds onto the target disk. Since neon's root already lives on external media, that install flow was skipped entirely and the image was streamed straight onto the eMMC instead:

sudo sh -c 'unzip -p "<path to .zip>" <path to .bin inside the zip> \
  | dd of=/dev/mmcblk0 bs=4M status=progress conv=fsync'

Unzipped image is ~8.9GB; eMMC is 29GB. (Original note here claimed ChromeOS auto-expands the stateful partition on first boot — wrong, see the 2026-09-27 reinstall below.) eMMC write speed degraded over the transfer (~130MB/s at the start down to ~9MB/s by the end, total ~18 min for 8.9GB) — looks like the eMMC's SLC write cache exhausting partway through; expected/normal for eMMC of this class, not a fault.

2026-09-27: reinstalled properly with install-flex-emmc.sh. The raw dd above left the installer image layout: ROOT-B a 2MB placeholder, STATE a fixed 6GB, ~20.7GB unallocated. Flex's /usr/sbin/is_running_from_installer compares ROOT-A/ROOT-B sizes, so it booted as live media ("Install ChromeOS Flex / Try it first") and couldn't do A/B updates. There is no flag to flip; the fix is running the image's own chromeos-install (what the Install button runs) against the eMMC. install-flex-emmc.sh (in this repo) does that from neon: loop-attaches the .bin, chroots into its ROOT-A inside a private mount namespace with every other disk (incl. neon's sda) masked by /dev/null, and runs chromeos-install --dst /dev/mmcblk0 --payload_image ... --target_bios efi. Gotchas it handles:

  • chromeos_postinst needs a cros_efi flag on the kernel cmdline; faked via a bind over /proc/cmdline, plus a wrapper on the image's chroot because postinst re-chroots with a non-recursive /proc bind.
  • Plasma/udisks auto-mounts new eMMC partitions mid-install, making sfdisk refuse a busy disk — a temporary UDISKS_IGNORE udev rule in /run/udev/rules.d prevents it.
  • chromeos-install can exit 0 on failure and logs harmless ERROR lines on success — judge by its final Installation to ... complete. line. Log: /var/log/flex-install.log.
  • Whole run is only ~2.5 min (partitions copied at eMMC speed). Result: ROOT-A/ROOT-B 4GB each, STATE 20.6GB (fills disk), KERN-A successful=1. The ESP is copied from the image so its FS UUID stays CBE4-703E (script still re-points 40_custom in case it changes); UEFI boot entries/order untouched.

Boot selection — both OSes are reachable two ways:

  1. From GRUB (neon's own boot menu, visible for 5s per GRUB_TIMEOUT): a custom entry "ChromeOS Flex (internal eMMC)" was added to /etc/grub.d/40_custom, which chainloads the eMMC's own EFI bootloader:
    menuentry "ChromeOS Flex (internal eMMC)" {
        insmod part_gpt
        insmod fat
        insmod chain
        search --no-floppy --fs-uuid --set=root CBE4-703E
        chainloader /EFI/BOOT/BOOTX64.EFI
    }
    
    CBE4-703E is the FAT filesystem UUID of the eMMC's EFI-SYSTEM partition (mmcblk0p12); /EFI/BOOT/BOOTX64.EFI is Chrome OS's fallback UEFI loader (crdyboot) on that partition. Run sudo update-grub after editing 40_custom for changes to take effect.
  2. From the firmware's own UEFI boot picker (MrChromebox UEFI, typically Esc during POST) — efibootmgr -v shows both neon (Boot0005, on the USB stick) and Internal eMMC (Boot0001) as registered entries, BootOrder currently 0005,0001,0000,0003,0002 (neon first). If the USB stick is unplugged, firmware falls through past the missing neon entry straight to Internal eMMC and boots Flex automatically — no menu needed.