Files
c630/docs/install.md
rob thijssen fc4d7d7ceb
All checks were successful
build image / build (push) Successful in 39m19s
Stop kernel upgrades writing entries that cannot boot
Simulating an upgrade — running kernel-core's %posttrans command by hand —
turned up two faults that had nothing to do with the full /boot, and would
have broken every future kernel install on their own.

95-c630-devicetree trusted $KERNEL_INSTALL_BOOT_ROOT. `kernel-install inspect`
reports "Layout: other, Boot Root: /boot/efi" here, because the ESP is all it
recognises, while Fedora's 20-grub.install writes BLS entries to
/boot/loader/entries regardless. So the hook looked for the device tree on the
ESP, did not find it, and skipped the patch — leaving an entry with no
devicetree line, which on this machine cannot boot. Paths in a BLS entry are
relative to the filesystem holding the entry, so the only correct boot root is
the one carrying both loader/entries and dtb-<kver>. Search for that instead.

dracut-config-rescue sets dracut_rescue_image=yes, so each install also built
a second ~210 MiB initramfs, which is what refilled /boot straight after it
was cleared. That image cannot boot this machine either: the rescue entry is
<machine-id>-0-rescue.conf, carrying no kernel version, so the devicetree hook
never matches it. Turned off.

Verified by rerunning the simulation: both kernels now have a devicetree line
and a present initrd, no rescue image is generated, snd-soc-wsa881x is rebuilt
automatically, and /boot holds at 72%.

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

215 lines
9.0 KiB
Markdown

# 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
```sh
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:
```sh
sudo c630-firmware
sudo reboot
```
See [firmware.md](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:
```sh
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:
```sh
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 — `kernel-install` is invoked from kernel-core's
`%posttrans` as `... || exit 0`, which swallows the failure. Nothing
retries, and later `dnf upgrade` runs look clean because they no longer
touch the kernel.
Two things made that worse, both fixed, both worth knowing if you are reading
an older image:
**The devicetree hook used to skip silently even with space to spare.** It
trusted `$KERNEL_INSTALL_BOOT_ROOT`, and on this machine `kernel-install
inspect` reports `Layout: other, Boot Root: /boot/efi` — it recognises only
the ESP. Fedora's `20-grub.install` ignores that and writes entries to
`/boot/loader/entries` anyway, so the hook went looking for the device tree on
the ESP, did not find it, and left the entry alone. The paths inside a BLS
entry are relative to the filesystem holding the entry, so the hook now
searches for the root that has both `loader/entries` and `dtb-<kver>` instead
of being told.
**The rescue image refilled `/boot` after every cleanup.** `dracut-config-rescue`
sets `dracut_rescue_image=yes`, so each kernel install built a *second*
~210 MiB initramfs. It could never boot this machine either: the rescue entry
is named `<machine-id>-0-rescue.conf` and carries no kernel version, so the
devicetree hook does not match it. `dracut_rescue_image="no"` in
`/etc/dracut.conf.d/10-c630.conf` turns it off.
So an update can leave a kernel that is installed, listed in the boot menu, and
unbootable. To check whether it actually completed:
```sh
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:
```sh
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:
```sh
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](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.