You are not logged in.

#1 2025-08-15 07:34:31

gtnq
Member
Registered: 2025-08-15
Posts: 1

Custom hooks for i915, nvidia-open firmware pruning

Hi, I wrote two hooks to limit the firmware included in the initramfs if you're using early KMS with i915 or nvidia-open. I have both enabled because of quirks with my laptop. They decreased the size of generated UKIs from 118 MiB to 55 MiB (both zstd compressed). Boot times according to systemd-analyze went down by about eight seconds. The large change is because of secure boot, I think. This continued working with the new Nvidia driver 580 update.

This should continue to work till Nvidia or Intel change their firmware naming schemes. Intel's is probably stable. I think Nvidia is only likely to when they release new GPUs.

nvidia-open-kms

#!/usr/bin/env bash

build() {
   local nvidia_modules=(nvidia nvidia_modeset nvidia_drm nvidia_uvm)

   # If autodetect isn't set, pull in all firmware
   if [ -z "${mkinitcpio_autodetect}" ]; then
      map add_module "${nvidia_modules[@]}"
      return
   fi

   # using add_module on dependencies that are not nvidia*. This will recursively pull in all needed .ko files.
   map add_module \
      $(modinfo -k $KERNELVERSION -F depends "${nvidia_modules[@]}" | tr "\n," "\n" | grep -v nvidia)

   # gsp_tu10x.bin for TU1XX and GA100, gsp_ga10x.bin for newer cards that work with nvidia-open
   # See open-gpu-kernel-modules/kernel-open/common/inc/nv-firmware.h (580.76.05)
   local ADD_GSP_TU=0
   local ADD_GSP_GA=0

   while IFS= read -r line; do
      echo $line | grep -qE ' (TU1[0-9]{2})|(GA100)' && ADD_GSP_TU=1 || ADD_GSP_GA=1
   done < <(lspci -d '10de:*:0300') # 10de for NVIDIA, 0300 for graphics controllers

   if [ "$ADD_GSP_GA" -eq 0 ] && [ "$ADD_GSP_TU" -eq 0 ]; then
      warning "Unrecognized GPUs. Including all firmware."
      map add_module "${nvidia_modules[@]}"
      return 0
   fi

   local fw_dir=$(modinfo -k $KERNELVERSION -F firmware nvidia | head -n1 | cut -d/ -f1-2)
   if [ "$ADD_GSP_TU" -eq 1 ]; then
      add_firmware "${fw_dir}/gsp_tu10x.bin"
   fi
   if [ "$ADD_GSP_GA" -eq 1 ]; then
      add_firmware "${fw_dir}/gsp_ga10x.bin"
   fi

   # using install_modules here to avoid automatic firmware inclusion
   install_modules $(modinfo -k $KERNELVERSION -F filename "${nvidia_modules[@]}")
}

help() {
   cat <<HELPEOF
Adds nvidia modules for early KMS, and includes only the right firmware files for
your cards when autodetect is active.
HELPEOF
}

i915-kms

#!/usr/bin/env bash

build() {
   # If autodetect isn't set, pull in all firmware
   if [ -z "${mkinitcpio_autodetect}" ]; then
      add_module i915
      return
   fi

   # There should be a line showing the firmware loaded, at least with loglevel >=3.
   # Extracting the family, like tgl, cml, adlp. Relying on the firmware names being consistent
   # across kernel versions
   local fw_family=$(journalctl -kg 'i915.*Finished loading DMC' | grep -oP '[a-z0-9_]+\.bin' | cut '-d_' -f1) 
   if [ -z "${fw_family}" ]; then
      warning "Unable to parse the log to determine the chip family. Adding all i915 firmware."
      add_module i915
      return 0
   fi

   # Manually adding dependencies. This will pull in firmware for those.
   local dependencies=$(modinfo -k $KERNELVERSION -F depends i915 | tr ',' ' ')
   map add_module $dependencies

   # A DMC file was found in the log. This should be sufficient for early KMS.
   # Using install_modules to sidestep the automatic firmware inclusion.
   local fw_file=$(modinfo -k $KERNELVERSION -F firmware i915 | sort -u | \
      grep -E "${fw_family}_dmc.*")
   map add_firmware ${fw_file}
   install_modules "$(modinfo -k $KERNELVERSION -F filename i915)"
}

help() {
   cat <<HELPEOF
Adds i915 for early KMS, includes only necessary firmware when autodetect is active.
HELPEOF
}

Tested to ensure no modules are excluded using

comm -3 <(lsinitcpio /tmp/old.uki | sort -u) <(lsinitcpio /tmp/new.uki | sort -u)

usr/lib/firmware/i915/adlp_dmc.bin
usr/lib/firmware/i915/adlp_dmc_ver2_16.bin
usr/lib/firmware/i915/adlp_guc_69.0.3.bin
usr/lib/firmware/i915/adlp_guc_70.1.1.bin
usr/lib/firmware/i915/adlp_guc_70.bin
usr/lib/firmware/i915/adls_dmc_ver2_01.bin
usr/lib/firmware/i915/bmg_dmc.bin
usr/lib/firmware/i915/bxt_dmc_ver1_07.bin
usr/lib/firmware/i915/bxt_guc_70.1.1.bin
usr/lib/firmware/i915/bxt_huc_2.0.0.bin
usr/lib/firmware/i915/cml_guc_70.1.1.bin
usr/lib/firmware/i915/cml_huc_4.0.0.bin
usr/lib/firmware/i915/dg1_dmc_ver2_02.bin
usr/lib/firmware/i915/dg1_guc_70.bin
usr/lib/firmware/i915/dg1_huc.bin
usr/lib/firmware/i915/dg2_dmc_ver2_08.bin
usr/lib/firmware/i915/dg2_guc_70.bin
usr/lib/firmware/i915/dg2_huc_gsc.bin
usr/lib/firmware/i915/ehl_guc_70.1.1.bin
usr/lib/firmware/i915/ehl_huc_9.0.0.bin
usr/lib/firmware/i915/glk_dmc_ver1_04.bin
usr/lib/firmware/i915/glk_guc_70.1.1.bin
usr/lib/firmware/i915/glk_huc_4.0.0.bin
usr/lib/firmware/i915/icl_dmc_ver1_09.bin
usr/lib/firmware/i915/icl_guc_70.1.1.bin
usr/lib/firmware/i915/icl_huc_9.0.0.bin
usr/lib/firmware/i915/kbl_guc_70.1.1.bin
usr/lib/firmware/i915/kbl_huc_4.0.0.bin
usr/lib/firmware/i915/mtl_dmc.bin
usr/lib/firmware/i915/mtl_gsc_1.bin
usr/lib/firmware/i915/mtl_guc_70.bin
usr/lib/firmware/i915/mtl_huc_gsc.bin
usr/lib/firmware/i915/rkl_dmc_ver2_03.bin
usr/lib/firmware/i915/skl_dmc_ver1_27.bin
usr/lib/firmware/i915/skl_guc_70.1.1.bin
usr/lib/firmware/i915/skl_huc_2.0.0.bin
usr/lib/firmware/i915/tgl_dmc_ver2_12.bin
usr/lib/firmware/i915/tgl_guc_69.0.3.bin
usr/lib/firmware/i915/tgl_guc_70.1.1.bin
usr/lib/firmware/i915/tgl_guc_70.bin
usr/lib/firmware/i915/tgl_huc_7.9.3.bin
usr/lib/firmware/i915/tgl_huc.bin
usr/lib/firmware/i915/xe2lpd_dmc.bin
usr/lib/firmware/i915/xe3lpd_dmc.bin
usr/lib/firmware/nvidia/580.76.05/gsp_ga10x.bin

Diff between the old and new mkinitcpio .conf files:

7c7
< MODULES=(i915 nvidia nvidia_drm nvidia_modeset nvidia_uvm)
---
> MODULES=()
53c53
< HOOKS=(base udev autodetect block keyboard microcode modconf encrypt filesystems fsck)
---
> HOOKS=(base udev autodetect block keyboard microcode modconf encrypt filesystems fsck nvidia-open-kms i915-kms)

Final sanity check to ensure firmware and modules were included:

lsinitcpio /tmp/new.uki | grep -E 'i915|nvidia'

etc/modprobe.d/nvidia.conf
usr/lib/firmware/i915/
usr/lib/firmware/i915/kbl_dmc_ver1_04.bin
usr/lib/firmware/nvidia/
usr/lib/firmware/nvidia/580.76.05/
usr/lib/firmware/nvidia/580.76.05/gsp_tu10x.bin
usr/lib/modprobe.d/nvidia-sleep.conf
usr/lib/modprobe.d/nvidia-utils.conf
usr/lib/modules/6.16.0-arch2-1/extramodules/nvidia-drm.ko
usr/lib/modules/6.16.0-arch2-1/extramodules/nvidia-modeset.ko
usr/lib/modules/6.16.0-arch2-1/extramodules/nvidia-uvm.ko
usr/lib/modules/6.16.0-arch2-1/extramodules/nvidia.ko
usr/lib/modules/6.16.0-arch2-1/kernel/drivers/gpu/drm/i915/
usr/lib/modules/6.16.0-arch2-1/kernel/drivers/gpu/drm/i915/i915.ko

If you'd like to try this out, create a new directory, like:

test/install

Copy your mkinitcpio.conf to test/, the two hooks above to test/install. Modify test/mkinitcpio.conf to remove i915 and the nvidia modules from the MODULES array, then generate a new UKI or initramfs with mkinitcpio: (use -g instead of -U if you're not using a UKI)

mkinitcpio -c test/mkinitcpio.conf -D /usr/lib/initcpio -D test/ -U /tmp/new.uki

Finally you can run the tests above to see if the right modules and firmware were copied to the initramfs: the comm -3 output should show no new files in the new image, and lsinitcpio + grep should show at least one XXX_dmc.... file for i915, and at least one of gsp_tu10x.bin and gsp_ga10x.bin if you're using nvidia-open.

Let me know if you found this useful, thanks.

Last edited by gtnq (2025-08-15 07:43:38)

Offline

Board footer

Powered by FluxBB