rob thijssen 2243166642
All checks were successful
build image / build (push) Successful in 23m57s
Boot fixes: drop the stock BLS entry, define load_video, set kernel cmdline
First boot on the hardware failed, returning to the GRUB menu with:

    can't find command 'load_video'
    file '/boot/vmlinuz-7.1.5-200.fc44.aarch64' not found
    you need to load the kernel first

The title in that message was the tell: "Fedora Linux (7.1.5-...) 44 (Forty
Four)" is Fedora's stock format, not ours. GRUB was booting an entry we did not
write. Confirmed by unpacking the published image and reading the boot
filesystem — /loader/entries held two files, and the one named after the
machine-id sorts before c630-*, so it won.

kernel-install wrote it during the dnf transaction, from inside the install
root where /boot is an ordinary directory rather than a partition. It was wrong
three ways: paths of /boot/vmlinuz-… that resolve nowhere once /boot is its own
filesystem; an empty options line, so no root= and no command line at all; and
no devicetree, so even had it loaded, the kernel would not have known what
machine it was on. Ours, sitting right beside it, was correct throughout.

So: delete any entry we did not write, and define load_video in grub.cfg —
blscfg emits menuentries that call it, and Fedora's generated config defines it
where a hand-written one must too.

Also write /etc/kernel/cmdline. That empty options line was not a build-time
quirk; it is what kernel-install produces when nothing tells it the command
line. The same gap would have bitten on the device at the first
`dnf update kernel`, writing an entry with no root= and no C630 quirks, and the
laptop would not have come back.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XWRjNJMistCy6ngXH5aJLS
2026-07-27 17:01:48 +03:00

Fedora for the Lenovo Yoga C630 13Q50

Builds a ready-to-write Fedora aarch64 disk image for the Lenovo Yoga C630 (model 81JL, Qualcomm SDM850), using Gitea Actions.

The approach is borrowed from aarch64-laptops/build, but the heavy lifting that project had to do in 2019 is now unnecessary: mainline Linux has carried sdm850-lenovo-yoga-c630.dts since 5.5, and Fedora ships it in kernel-core. There is no kernel to patch and no GRUB to compile. What is left is assembling a disk image that boots on hardware whose firmware hands Linux no device tree.

What you get

output/fedora-44-<variant>-lenovo-yoga-c630-<date>-<ref>.img.zst — a GPT disk image with an ESP, a /boot partition and an ext4 root. Decompress, write it to a USB stick or microSD card, and boot. The root filesystem grows to fill the medium on first boot.

Two variants:

Variant Size Contents
minimal 8 GiB Console, sshd, and enough tools to debug the machine
workstation 16 GiB GNOME desktop

Default login is fedora / fedora, and the password must be changed at first login. Root is locked.

Hardware status

Works out of the box Needs firmware from Windows Not supported
UFS storage, USB, keyboard, touchpad, touchscreen Graphics (Adreno 630 zap shader) LTE modem
WiFi + Bluetooth (ath10k WCN3990) Audio
Battery and charging Sensor hub — lid switch, accelerometer, auto-rotate
Display (unaccelerated) Hardware video decode (venus)

Fedora ships everything Qualcomm permits to be redistributed, which covers WiFi and Bluetooth outright. Graphics is the awkward case: the generic Adreno pieces (a630_gmu.bin, a630_sqe.fw) are packaged, but the C630's device tree asks for a model-signed zap shader, qcdxkmsuc850.mbn, which exists only in your machine's Windows partition — Fedora's generic sdm845/a630_zap.mbn is not what this device requests. Audio, sensors and video decode are the same story.

Run sudo c630-firmware once after installing — see docs/firmware.md for the full list and a manual fallback.

Building

CI does this on every push to main. To run it yourself:

./build/build-image.sh --variant minimal

You need podman and, on an x86_64 host, aarch64 emulation:

sudo dnf install -y qemu-user-static-aarch64
sudo systemctl restart systemd-binfmt

build/build-image.sh runs on the host and only sets up the container. build/stage2.sh runs inside an aarch64 Fedora container and does everything else: dnf --installroot, the overlay, dracut, and the disk assembly. It builds filesystems from directory trees with mke2fs -d and mcopy rather than mounting loop devices, so it does not need /dev/loop-control — which CI runners generally will not hand out.

Iterating

Every aarch64 binary runs under emulation, and the dnf transaction is essentially all of the cost — 500-odd packages' worth of rpm scriptlets for minimal, four times that for workstation. Everything after it takes minutes. Since getting this machine to boot will take a few attempts, the build is arranged so you only pay that once:

  • The post-dnf root filesystem is staged under <work>/base, keyed on a hash of the package lists, release and variant. Editing config/device.env, overlay/, or the bootloader config reuses it. Editing config/packages/ invalidates it automatically.
  • The working copy is made with cp --reflink=auto, so on btrfs or xfs it is a copy-on-write clone rather than a real copy.
  • Downloaded rpms live in .cache/dnf, outside the staged tree, so even --fresh re-runs the scriptlets without re-downloading.

In practice a kernel-command-line change rebuilds in a few minutes.

./build/build-image.sh --variant minimal            # reuses the staged base
./build/build-image.sh --variant minimal --fresh    # forces a reinstall
./build/build-image.sh --variant minimal --keep-rootfs   # keep the tree to poke at

CI points --work and --cache at /var/tmp/c630-build so both survive between jobs. That is per-runner, so the first build on a given runner is cold.

The build container defaults to git.lair.cafe/gongfoo/build-fedora-44-aarch64, which ships the assembly tooling so it does not have to be installed under emulation on every run. If that image is not reachable the build falls back to stock Fedora and installs the tooling itself — slower, but it works.

Repository layout

config/device.env            C630 parameters: DTB path, kernel command line, geometry
config/packages/*.pkgs       Package lists — base plus one file per variant
overlay/                     Files copied into the root filesystem (*.in are templated)
build/build-image.sh         Host driver: emulation checks, podman invocation
build/stage2.sh              The actual build, inside an aarch64 container
firmware/local/              Optional drop-in for firmware you extracted yourself (gitignored)
.gitea/workflows/            CI
docs/                        Installation, firmware, runner setup

Documentation

Caveats

The build has not yet been confirmed to boot on real hardware. The device tree, kernel command line and firmware layout are taken from Fedora's Snapdragon WoA documentation and the aarch64-laptops project; the parts specific to the C630's older SDM850 are reasoned from those rather than tested. Expect to spend a boot or two adjusting DEVICE_CMDLINE in config/device.env. Findings belong in this README.

Description
No description provided
Readme 399 KiB
Languages
Shell 100%