Files
c630/docs/install.md
rob thijssen 477d43aacd
Some checks failed
build image / build (push) Has been cancelled
Survive kernel updates on a /boot this small
A dnf upgrade to 7.1.8 installed the kernel rpm cleanly, then ran /boot out
of space. dracut wrote no initramfs, and because kernel-install stops at the
first failing plugin, 95-c630-devicetree never ran either — leaving a boot
entry with neither an initrd nor a devicetree line, which on this machine can
never boot. dnf reported success and nothing retried.

A kernel costs ~336 MiB here: a 210 MiB hostonly=no initramfs, a 98 MiB
dtb-<kver> directory carrying every board's device tree, plus vmlinuz and
System.map. Three of those cannot fit 1 GiB, so /boot goes to 2 GiB and
installonly_limit drops to 2.

Also fixes the quieter half of the same trap. snd-soc-wsa881x lives outside
the kernel package, so the speakers go silent after any kernel update with
nothing in the logs to explain it. c630-wsa881x rebuilds it and
96-c630-wsa881x.install calls it on each kernel-install add — always exiting
0, since a plugin failure is precisely what caused the damage above.

grub.cfg gains the next_entry one-shot block that has been carried by hand all
along, so testing a kernel costs a power cycle rather than a rescue.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011XgGF5wfxLDAybVnNz6eNQ
2026-08-14 16:17:52 +03:00

7.8 KiB

Installing on the Yoga C630

Before you start

Leave Windows in place. Lenovo ships firmware updates only through Windows, and the per-model Qualcomm blobs Linux needs live in that partition — wiping it means losing accelerated graphics, audio and the sensor hub permanently. Update everything through Lenovo Vantage first.

Disable Secure Boot. The image is not signed for it:

  • Press Fn+F2 during startup, go to Security → Secure Boot → Disabled, or
  • Settings → Update & Security → Recovery → Advanced startup → UEFI Firmware Settings

Write the image

zstd -d fedora-44-minimal-lenovo-yoga-c630-*.img.zst
sudo dd if=fedora-44-minimal-lenovo-yoga-c630-*.img of=/dev/sdX bs=4M status=progress oflag=direct conv=fsync

Check /dev/sdX twice. An 8 GiB stick is enough for minimal, 16 GiB for workstation; the root filesystem expands to fill whatever you use.

First boot

Insert the stick and power on holding Fn+F12 for the boot menu, or enter setup with Fn+F2 and put USB ahead of the internal drive.

GRUB should appear with one entry. It has already been told which device tree to load — the C630's UEFI does not supply one, which is the whole reason the devicetree line exists in the boot loader entry.

First boot does two slow things: it relabels the filesystem for SELinux and grows the root partition. Several minutes on a USB stick is normal. Log in as grenade / grenade — or whatever DEFAULT_USER and DEFAULT_PASSWORD in config/device.env were set to — and set a new password when prompted.

Extract the Qualcomm firmware

Accelerated graphics, audio, the sensor hub and video decode do not work until you do this:

sudo c630-firmware
sudo reboot

See firmware.md if it cannot find the Windows partition.

Installing to internal storage

Once the USB image is behaving, copy it onto the internal UFS. Boot from the USB stick and run, on the laptop:

sudo ./build/install-to-disk.sh --dry-run    # show the plan, touch nothing
sudo ./build/install-to-disk.sh              # do it

It partitions the disk, copies the running system across, and rewrites every UUID that has to change. Reboot afterwards and pick the internal drive from the boot menu (Fn+F12), or just pull the stick out.

This wipes the target disk. If you still have Windows and want to keep it, do not run this — shrink the Windows partition from within Windows first and adapt the steps by hand.

Two things about this machine make the obvious approaches fail, both of which the script handles:

You cannot dd the image onto the internal drive. The UFS reports 4096-byte logical sectors; the disk image is built with 512-byte sector geometry. Its GPT header and every partition offset would land in the wrong place. The disk has to be partitioned on the machine, at its own sector size.

efibootmgr does not work here. There are no EFI runtime variables — efibootmgr reports "EFI variables are not supported on this system" — so nothing can register a boot entry. GRUB therefore goes at the removable-media path, EFI/BOOT/BOOTAA64.EFI, where the firmware finds it unprompted.

If you would rather do it by hand, the sequence is: sgdisk an ESP, a /boot and a root partition; mkfs.vfat and mkfs.ext4 -O ^orphan_file,^metadata_csum_seed; copy /, /boot and the ESP separately (preserving xattrs, or SELinux labels are lost); then update /etc/fstab, /etc/kernel/cmdline, root=UUID= in /boot/loader/entries/*.conf, and the --fs-uuid in both /boot/grub2/grub.cfg and EFI/fedora/grub.cfg.

The clock, and why dnf lies about missing packages

This machine's RTC cannot be set — hwclock --systohc fails with ioctl(RTC_SET_TIME) to /dev/rtc0 to set the time failed: No such device — and it reads 1970 at every boot. systemd compensates by advancing the clock to its own build date, which is close enough to look right and wrong enough to break rpm.

The symptom is baffling if you have not seen it before:

$ sudo dnf install net-tools
Transaction failed: Rpm transaction failed.
  - systemd is needed by net-tools-2.0-0.77.20160912git.fc44.aarch64

systemd is plainly installed — the machine booted. But with the clock behind the package's signing date, rpm rejects the signature as not yet valid, skips that header entirely, and concludes the package is absent:

Signature 85b4 created at Sat Jul 25 18:33:30 2026 invalid: signature is not alive
  because: Not live until 2026-07-25T18:28:30Z
error: rpmdbNextIterator: skipping h#     282
package systemd is not installed

chrony is installed and enabled, and fixes this within a few seconds of the network coming up — check with timedatectl. The gap only matters if you run dnf before that, or on a machine with no network yet. Set it by hand in that case:

sudo date -u -s "2026-07-27 16:33:00"

Any roughly-correct time will do; it only has to be later than the packages were signed.

Kernel updates and a full /boot

A kernel costs about 336 MiB here — a ~210 MiB initramfs (built hostonly=no, so it carries the whole driver and firmware set), a ~98 MiB dtb-<kver> directory because kernel-core ships every board's device tree, plus vmlinuz and System.map. Three of those do not fit a 1 GiB /boot, which is why images now use 2 GiB and installonly_limit=2.

If /boot does fill up, the failure is quiet and genuinely dangerous:

  1. The kernel rpm installs fine — rpm -V is clean and the module tree is complete.
  2. 50-dracut.install then dies on ENOSPC, so no initramfs is written.
  3. kernel-install stops at the first failing plugin, so 95-c630-devicetree.install never runs and the boot entry gets no devicetree line — which on this machine means it can never boot, because the UEFI supplies no device tree.
  4. dnf reports success. Nothing retries, and later dnf upgrade runs look clean because they no longer touch the kernel.

So an update can leave a kernel that is installed, listed in the boot menu, and unbootable. To check whether it actually completed:

rpm -q kernel-core                       # what rpm thinks is installed
ls /boot/initramfs-*                     # one per kernel, or the update failed
sudo grep -L devicetree /boot/loader/entries/*.conf   # any output is unbootable

To repair it, free space first, then redo the two steps that were skipped:

sudo dnf remove kernel-core-<old-version>
sudo dracut --force --kver <kver> /boot/initramfs-<kver>.img
sudo /etc/kernel/install.d/95-c630-devicetree.install add <kver>

Both are idempotent. Test the result with a one-shot boot rather than by changing the default, so a kernel that hangs costs only a power cycle:

sudo grub2-editenv /boot/grub2/grubenv set next_entry=c630-<kver>
sudo reboot

Note that speakers go silent after a kernel update is the same event wearing a different hat — see c630-wsa881x in firmware.md.

If it does not boot

The kernel command line is the first thing to change. It lives in options in /boot/loader/entries/c630-*.conf, and GRUB lets you edit it for one boot by pressing e.

Symptom Try
Hangs immediately after GRUB, no kernel output Wrong or missing device tree — check the devicetree line points at a file that exists in /boot/dtb-*/qcom/
Boots then freezes partway Drop efi=noruntime, or add pd_ignore_unused if it is missing
USB dies during boot Add modprobe.blacklist=qcom_q6v5_pas
Cannot find root filesystem The initramfs is missing the UFS drivers — see overlay/etc/dracut.conf.d/10-c630.conf
90-second stall early in boot Add systemd.tpm2_wait=0
dnf says a package that is obviously installed is missing The clock is behind — see above

Adding earlycon and ignore_loglevel will tell you a great deal more about which of these it is.