fix: NVIDIA fix on Limine edits the existing cmdline line; early modules only when every kernel has them

Found by running it in a VM: the appended += line became literal text on the
kernel command line, and a kernel without the modules made limine-mkinitcpio
skip its boot entry.
This commit is contained in:
theupriser committed 2026-10-01 12:48:56 +02:00
1 parent ad6cf26521
commit 799f5abcca
4 files changed
+37 -8

No files matched your search

+1
View File
@@ -9,6 +9,7 @@ one per merged pull request.
- **feat: the SteamOS conversion fixes a corrupted gaming mode screen with an NVIDIA GPU: nvidia-drm.modeset=1 and fbdev=1 on the kernel command line, NVIDIA modules in the initramfs (lib/nvidia.sh)** - **feat: the SteamOS conversion fixes a corrupted gaming mode screen with an NVIDIA GPU: nvidia-drm.modeset=1 and fbdev=1 on the kernel command line, NVIDIA modules in the initramfs (lib/nvidia.sh)**
- **test: tests/nvidia-test.sh runs the NVIDIA fix against a fake RTX 5080 beside an iGPU, a stub modinfo and temp copies of the Limine, systemd-boot and GRUB files (no root, VM or hardware); NVIDIA_DRM_DIR points detection at a fake sysfs tree** - **test: tests/nvidia-test.sh runs the NVIDIA fix against a fake RTX 5080 beside an iGPU, a stub modinfo and temp copies of the Limine, systemd-boot and GRUB files (no root, VM or hardware); NVIDIA_DRM_DIR points detection at a fake sysfs tree**
- **fix: NVIDIA fix on Limine edits the KERNEL_CMDLINE[default] line (an appended += line ended up as literal text on the kernel command line, found in a VM); the modules are only loaded early when every installed kernel has them, and a Limine boot entry without the parameters is an error**
## 2.9.6 - 2026-09-30 ## 2.9.6 - 2026-09-30
+6 -1
View File
@@ -216,7 +216,12 @@ its driver installed (`lib/nvidia.sh`), the SteamOS conversion adds
systemd-boot or GRUB; the file is backed up first) and systemd-boot or GRUB; the file is backed up first) and
`/etc/mkinitcpio.conf.d/90-steamify-nvidia.conf` (`MODULES+=(nvidia `/etc/mkinitcpio.conf.d/90-steamify-nvidia.conf` (`MODULES+=(nvidia
nvidia_modeset nvidia_uvm nvidia_drm)`), then rebuilds the initramfs and boot nvidia_modeset nvidia_uvm nvidia_drm)`), then rebuilds the initramfs and boot
entries. Only what's missing is changed; it applies after a reboot. Turning entries. The early-load drop-in is only written when every installed kernel
has the NVIDIA modules (mkinitcpio fails on a missing module, and
`limine-mkinitcpio` then skips that kernel's boot entry, parameters included).
On Limine the parameters go into the existing `KERNEL_CMDLINE[default]="..."`
line: an extra appended `+=` line is pasted into the command line as text.
Only what's missing is changed; it applies after a reboot. Turning
the conversion off removes both. Untested on hardware so far. the conversion off removes both. Untested on hardware so far.
## HDMI-CEC ## HDMI-CEC
+23 -7
View File
@@ -9,7 +9,6 @@
NVIDIA_PARAMS="nvidia-drm.modeset=1 nvidia-drm.fbdev=1" NVIDIA_PARAMS="nvidia-drm.modeset=1 nvidia-drm.fbdev=1"
NVIDIA_INITRAMFS_CONF=/etc/mkinitcpio.conf.d/90-steamify-nvidia.conf NVIDIA_INITRAMFS_CONF=/etc/mkinitcpio.conf.d/90-steamify-nvidia.conf
NVIDIA_MARK="# steamify-nvidia"
# The DRM devices in sysfs; the tests point this at a fake tree. # The DRM devices in sysfs; the tests point this at a fake tree.
NVIDIA_DRM_DIR=${NVIDIA_DRM_DIR:-/sys/class/drm} NVIDIA_DRM_DIR=${NVIDIA_DRM_DIR:-/sys/class/drm}
@@ -46,6 +45,19 @@ nvidia_initramfs_ok() {
[[ -f "$NVIDIA_INITRAMFS_CONF" ]] || grep -qE '^MODULES=.*nvidia_drm' /etc/mkinitcpio.conf 2>/dev/null [[ -f "$NVIDIA_INITRAMFS_CONF" ]] || grep -qE '^MODULES=.*nvidia_drm' /etc/mkinitcpio.conf 2>/dev/null
} }
nvidia_modules_everywhere() {
# 0 when every installed kernel has the nvidia_drm module: mkinitcpio fails
# on a MODULES entry a kernel lacks, and limine-mkinitcpio then skips that
# kernel's initramfs and boot entry, so the parameters never reach it.
local k found=0
for k in "${NVIDIA_MODULES_DIR:-/usr/lib/modules}"/*/; do
[[ -f "$k/pkgbase" || -d "$k/kernel" || -d "$k/updates" || -d "$k/extramodules" ]] || continue
find "$k" -name 'nvidia-drm.ko*' -print -quit 2>/dev/null | grep -q . || return 1
found=1
done
[[ $found == 1 ]]
}
nvidia_rebuild_boot() { nvidia_rebuild_boot() {
local f; f="$(nvidia_boot_file)" local f; f="$(nvidia_boot_file)"
info "Rebuilding the initramfs and boot entries..." info "Rebuilding the initramfs and boot entries..."
@@ -68,7 +80,7 @@ nvidia_enable() {
backup_file "$f" backup_file "$f"
case "$f" in case "$f" in
*/limine) */limine)
printf 'KERNEL_CMDLINE[default]+=" %s" %s\n' "$NVIDIA_PARAMS" "$NVIDIA_MARK" | sudo tee -a "$f" >/dev/null ;; sudo sed -i -E "s/^(KERNEL_CMDLINE\[default\]=\"[^\"]*)\"/\1 $NVIDIA_PARAMS\"/" "$f" ;;
*/sdboot-manage.conf) */sdboot-manage.conf)
sudo sed -i -E "s/^(LINUX_OPTIONS=\"[^\"]*)\"/\1 $NVIDIA_PARAMS\"/" "$f" ;; sudo sed -i -E "s/^(LINUX_OPTIONS=\"[^\"]*)\"/\1 $NVIDIA_PARAMS\"/" "$f" ;;
*/grub) */grub)
@@ -77,13 +89,20 @@ nvidia_enable() {
changed=1 changed=1
fi fi
fi fi
if ! nvidia_initramfs_ok; then if ! nvidia_initramfs_ok && ! nvidia_modules_everywhere; then
warn "Not every installed kernel has the NVIDIA modules: skipping loading them early (the kernel parameters still apply)."
elif ! nvidia_initramfs_ok; then
info "Loading the NVIDIA modules early (initramfs)..." info "Loading the NVIDIA modules early (initramfs)..."
printf 'MODULES+=(nvidia nvidia_modeset nvidia_uvm nvidia_drm)\n' | printf 'MODULES+=(nvidia nvidia_modeset nvidia_uvm nvidia_drm)\n' |
sudo install -Dm644 /dev/stdin "$NVIDIA_INITRAMFS_CONF" && changed=1 sudo install -Dm644 /dev/stdin "$NVIDIA_INITRAMFS_CONF" && changed=1
fi fi
if [[ $changed == 1 ]]; then if [[ $changed == 1 ]]; then
nvidia_rebuild_boot || { err "Rebuilding the boot entries failed."; return 1; } nvidia_rebuild_boot || { err "Rebuilding the boot entries failed."; return 1; }
if [[ "$f" == */limine && -f "${NVIDIA_LIMINE_CONF:-/boot/limine.conf}" ]] &&
! grep -q 'nvidia-drm.modeset=1' "${NVIDIA_LIMINE_CONF:-/boot/limine.conf}"; then
err "The boot entries don't have the NVIDIA parameters: the initramfs build failed (see above)."
return 1
fi
ok "NVIDIA gaming mode fix applied; it takes effect after a reboot." ok "NVIDIA gaming mode fix applied; it takes effect after a reboot."
fi fi
return 0 return 0
@@ -92,10 +111,7 @@ nvidia_enable() {
nvidia_disable() { nvidia_disable() {
local f changed=0; f="$(nvidia_boot_file)" local f changed=0; f="$(nvidia_boot_file)"
if [[ -n "$f" ]] && grep -q "$NVIDIA_PARAMS" "$f" 2>/dev/null; then if [[ -n "$f" ]] && grep -q "$NVIDIA_PARAMS" "$f" 2>/dev/null; then
case "$f" in sudo sed -i "s/ \?$NVIDIA_PARAMS//" "$f"
*/limine) sudo sed -i "/$NVIDIA_MARK\$/d" "$f" ;;
*) sudo sed -i "s/ \?$NVIDIA_PARAMS//" "$f" ;;
esac
changed=1 changed=1
fi fi
[[ -f "$NVIDIA_INITRAMFS_CONF" ]] && { sudo rm -f "$NVIDIA_INITRAMFS_CONF"; changed=1; } [[ -f "$NVIDIA_INITRAMFS_CONF" ]] && { sudo rm -f "$NVIDIA_INITRAMFS_CONF"; changed=1; }
+7
View File
@@ -19,6 +19,8 @@ echo 0x8086 > "$T/drm/card0/device/vendor"; echo 0x030000 > "$T/drm/card0/device
echo 0x10de > "$T/drm/card1/device/vendor"; echo 0x030000 > "$T/drm/card1/device/class" echo 0x10de > "$T/drm/card1/device/vendor"; echo 0x030000 > "$T/drm/card1/device/class"
echo 0x2c02 > "$T/drm/card1/device/device" echo 0x2c02 > "$T/drm/card1/device/device"
NVIDIA_DRM_DIR="$T/drm" NVIDIA_DRM_DIR="$T/drm"
mkdir -p "$T/mods/6.1.0-cachyos/kernel"; : > "$T/mods/6.1.0-cachyos/kernel/nvidia-drm.ko.zst"
NVIDIA_MODULES_DIR="$T/mods"
FAKE_DRIVER=1; check "finds the NVIDIA card as card1 beside an iGPU" nvidia_present FAKE_DRIVER=1; check "finds the NVIDIA card as card1 beside an iGPU" nvidia_present
FAKE_DRIVER=0; check "skips when the driver isn't installed" '! nvidia_present' FAKE_DRIVER=0; check "skips when the driver isn't installed" '! nvidia_present'
@@ -43,6 +45,11 @@ for loader in limine sdboot grub; do
check "$loader: disable restores the file and drops the drop-in" '[[ "$(cat "$F")" == "$ORIG" && ! -f "$NVIDIA_INITRAMFS_CONF" ]]' check "$loader: disable restores the file and drops the drop-in" '[[ "$(cat "$F")" == "$ORIG" && ! -f "$NVIDIA_INITRAMFS_CONF" ]]'
done done
# A second kernel without the NVIDIA modules: no early-load drop-in, parameters still set.
mkdir -p "$T/mods/6.6.0-lts/kernel"; F="$T/sdboot-manage.conf"; printf 'LINUX_OPTIONS="quiet"\n' > "$F"
nvidia_boot_file() { echo "$F"; }; rm -f "$NVIDIA_INITRAMFS_CONF"; REBUILDS=0; nvidia_enable
check "kernel without nvidia modules: no drop-in, parameters set" '[[ ! -f "$NVIDIA_INITRAMFS_CONF" ]] && grep -q "nvidia-drm.fbdev=1" "$F"'
rm -rf "$T/mods/6.6.0-lts"
FAKE_DRIVER=0; printf 'LINUX_OPTIONS="quiet"\n' > "$T/sdboot"; F="$T/sdboot"; REBUILDS=0; nvidia_enable FAKE_DRIVER=0; printf 'LINUX_OPTIONS="quiet"\n' > "$T/sdboot"; F="$T/sdboot"; REBUILDS=0; nvidia_enable
check "no NVIDIA driver: nothing touched" '[[ "$(cat "$F")" == "LINUX_OPTIONS=\"quiet\"" && $REBUILDS == 0 ]]' check "no NVIDIA driver: nothing touched" '[[ "$(cat "$F")" == "LINUX_OPTIONS=\"quiet\"" && $REBUILDS == 0 ]]'
exit $fail exit $fail