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>
201 lines
13 KiB
Markdown
201 lines
13 KiB
Markdown
# 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
|
|
`dd`s 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.
|