commit:     31e23ab264c3a1479d57261f49a6aa7411152619
Author:     Andrew Ammerlaan <andrewammerlaan <AT> gentoo <DOT> org>
AuthorDate: Tue Dec 19 08:03:22 2023 +0000
Commit:     Michał Górny <mgorny <AT> gentoo <DOT> org>
CommitDate: Sat Dec 23 17:35:08 2023 +0000
URL:        https://gitweb.gentoo.org/repo/gentoo.git/commit/?id=31e23ab2

kernel-{build,install}.eclass: add USE=generic-uki

- optionally build a generic unified kernel image
- only install this uki.efi in any binary generated binpkgs, this saves space
- extract the initrd and kernel image from the uki in pkg_postinst
- own image, initrd and uki install paths

Signed-off-by: Andrew Ammerlaan <andrewammerlaan <AT> gentoo.org>
Signed-off-by: Michał Górny <mgorny <AT> gentoo.org>

 eclass/kernel-build.eclass   |  99 +++++++++++++++++++-
 eclass/kernel-install.eclass | 212 +++++++++++++++++++++++++++++++++++++++++--
 2 files changed, 301 insertions(+), 10 deletions(-)

diff --git a/eclass/kernel-build.eclass b/eclass/kernel-build.eclass
index 7a041a8aacdf..2253f4d854d1 100644
--- a/eclass/kernel-build.eclass
+++ b/eclass/kernel-build.eclass
@@ -107,6 +107,12 @@ if [[ ${KERNEL_IUSE_MODULES_SIGN} ]]; then
        "
 fi
 
+if [[ ${KERNEL_IUSE_GENERIC_UKI} ]]; then
+       BDEPEND+="
+               generic-uki? ( ${!INITRD_PACKAGES[@]} )
+       "
+fi
+
 # @FUNCTION: kernel-build_pkg_setup
 # @DESCRIPTION:
 # Call python-any-r1 and secureboot pkg_setup
@@ -333,7 +339,8 @@ kernel-build_src_install() {
        # build/Module.symvers does not exist if CONFIG_MODULES is not set.
        [[ -f build/Module.symvers ]] && doins build/Module.symvers
        local image_path=$(dist-kernel_get_image_path)
-       cp -p "build/${image_path}" "${ED}${kernel_dir}/${image_path}" || die
+       local image=${ED}${kernel_dir}/${image_path}
+       cp -p "build/${image_path}" "${image}" || die
 
        # If a key was generated, copy it so external modules can be signed
        local suffix
@@ -366,7 +373,95 @@ kernel-build_src_install() {
        dosym "../../../${kernel_dir}" "/lib/modules/${module_ver}/source"
 
        if [[ ${KERNEL_IUSE_SECUREBOOT} ]]; then
-               secureboot_sign_efi_file "${ED}${kernel_dir}/${image_path}"
+               secureboot_sign_efi_file "${image}"
+       fi
+
+       if [[ ${KERNEL_IUSE_GENERIC_UKI} ]]; then
+               if use generic-uki; then
+                       # NB: if you pass a path that does not exist or is not 
a regular
+                       # file/directory, dracut will silently ignore it and 
use the default
+                       # https://github.com/dracutdevs/dracut/issues/1136
+                       > "${T}"/empty-file || die
+                       mkdir -p "${T}"/empty-directory || die
+
+                       local dracut_modules=(
+                               base bash btrfs cifs crypt crypt-gpg crypt-loop 
dbus dbus-daemon
+                               dm dmraid drm dracut-systemd fido2 i18n fs-lib 
kernel-modules
+                               kernel-network-modules kernel-modules-extra 
lunmask lvm nbd
+                               mdraid modsign network network-manager nfs 
nvdimm nvmf pcsc
+                               pkcs11 plymouth qemu qemu-net resume rngd 
rootfs-block shutdown
+                               systemd systemd-ac-power systemd-ask-password 
systemd-initrd
+                               systemd-integritysetup systemd-pcrphase 
systemd-sysusers
+                               systemd-udevd systemd-veritysetup terminfo 
tpm2-tss udev-rules
+                               uefi-lib usrmount virtiofs
+                       )
+
+                       local dracut_args=(
+                               --conf "${T}/empty-file"
+                               --confdir "${T}/empty-directory"
+                               --kernel-image "${image}"
+                               --kmoddir "${ED}/lib/modules/${dir_ver}"
+                               --kver "${dir_ver}"
+                               --verbose
+                               --no-hostonly
+                               --no-hostonly-cmdline
+                               --no-hostonly-i18n
+                               --no-machineid
+                               --nostrip
+                               --no-uefi
+                               --early-microcode
+                               --reproducible
+                               --ro-mnt
+                               --modules "${dracut_modules[*]}"
+                       )
+
+                       # Tries to update ld cache
+                       addpredict /etc/ld.so.cache~
+                       dracut "${dracut_args[@]}" "${image%/*}/initrd" ||
+                               die "Failed to generate initramfs"
+
+                       local ukify_args=(
+                               --linux="${image}"
+                               --initrd="${image%/*}/initrd"
+                               --cmdline="root=/dev/gpt-auto-root ro quiet 
splash"
+                               --uname="${dir_ver}"
+                               --output="${image%/*}/uki.efi"
+                       )
+
+                       if [[ ${KERNEL_IUSE_SECUREBOOT} ]] && use secureboot; 
then
+                               ukify_args+=(
+                                       --signtool=sbsign
+                                       
--secureboot-private-key="${SECUREBOOT_SIGN_KEY}"
+                                       
--secureboot-certificate="${SECUREBOOT_SIGN_CERT}"
+                               )
+                               if [[ ${SECUREBOOT_SIGN_KEY} == pkcs11:* ]]; 
then
+                                       ukify_args+=(
+                                               --signing-engine="pkcs11"
+                                       )
+                               else
+                                       # Sytemd-measure does not currently 
support pkcs11
+                                       ukify_args+=(
+                                               --measure
+                                               
--pcrpkey="${ED}${kernel_dir}/certs/signing_key.x509"
+                                               
--pcr-private-key="${SECUREBOOT_SIGN_KEY}"
+                                               --phases="enter-initrd"
+                                               
--pcr-private-key="${SECUREBOOT_SIGN_KEY}"
+                                               
--phases="enter-initrd:leave-initrd enter-initrd:leave-initrd:sysinit 
enter-initrd:leave-initrd:sysinit:ready"
+                                       )
+                               fi
+                       fi
+
+                       # systemd<255 does not install ukify in /usr/bin
+                       
PATH="${PATH}:${BROOT}/usr/lib/systemd:${BROOT}/lib/systemd" \
+                               ukify build "${ukify_args[@]}" || die "Failed 
to generate UKI"
+
+                       # Overwrite unnecessary image types to save space
+                       > "${image}" || die
+               else
+                       # Placeholders to ensure we own these files
+                       > "${image%/*}/uki.efi" || die
+               fi
+               > "${image%/*}/initrd" || die
        fi
 
        # unset to at least be out of the environment file in, e.g. shared 
binpkgs

diff --git a/eclass/kernel-install.eclass b/eclass/kernel-install.eclass
index c7118a720ba6..919a5d11fd84 100644
--- a/eclass/kernel-install.eclass
+++ b/eclass/kernel-install.eclass
@@ -21,6 +21,13 @@
 # Additionally, the inherited mount-boot eclass exports pkg_pretend.
 # It also stubs out pkg_preinst and pkg_prerm defined by mount-boot.
 
+# @ECLASS_VARIABLE: KERNEL_IUSE_GENERIC_UKI
+# @PRE_INHERIT
+# @DEFAULT_UNSET
+# @DESCRIPTION:
+# If set to a non-null value, adds IUSE=generic-uki and required
+# logic to install a generic unified kernel image.
+
 # @ECLASS_VARIABLE: KV_LOCALVERSION
 # @DEFAULT_UNSET
 # @DESCRIPTION:
@@ -28,6 +35,13 @@
 # Needs to be set only when installing binary kernels,
 # kernel-build.eclass obtains it from kernel config.
 
+# @ECLASS_VARIABLE: INITRD_PACKAGES
+# @INTERNAL
+# @DESCRIPTION:
+# Used with KERNEL_IUSE_GENERIC_UKI. The eclass sets this to an array of
+# packages to depend on for building the generic UKI and their licenses.
+# Used in kernel-build.eclass.
+
 if [[ ! ${_KERNEL_INSTALL_ECLASS} ]]; then
 _KERNEL_INSTALL_ECLASS=1
 
@@ -46,8 +60,7 @@ RESTRICT+="
        arm? ( test )
 "
 
-# note: we need installkernel with initramfs support!
-IDEPEND="
+_IDEPEND_BASE="
        !initramfs? (
                || (
                        sys-kernel/installkernel-gentoo
@@ -63,6 +76,146 @@ IDEPEND="
                )
        )
 "
+
+LICENSE="GPL-2"
+if [[ ${KERNEL_IUSE_GENERIC_UKI} ]]; then
+       IUSE+=" generic-uki"
+       # https://github.com/AndrewAmmerlaan/dist-kernel-log-to-licenses
+       # This script can help with generating the array below, keep in mind
+       # that it is not a fully automatic solution, i.e. use flags will
+       # still have to handled manually.
+       declare -gA INITRD_PACKAGES=(
+               ["app-alternatives/awk"]="CC0-1.0"
+               ["app-alternatives/gzip"]="CC0-1.0"
+               ["app-alternatives/sh"]="CC0-1.0"
+               ["app-arch/bzip2"]="BZIP2"
+               ["app-arch/gzip"]="GPL-3+"
+               ["app-arch/lz4"]="BSD-2 GPL-2"
+               ["app-arch/xz-utils"]="public-domain LGPL-2.1+ GPL-2+"
+               ["app-arch/zstd"]="|| ( BSD GPL-2 )"
+               ["app-crypt/argon2"]="|| ( Apache-2.0 CC0-1.0 )"
+               ["app-crypt/gnupg[smartcard,tpm(-)]"]="GPL-3+"
+               ["app-crypt/p11-kit"]="MIT"
+               ["app-crypt/tpm2-tools"]="BSD"
+               ["app-crypt/tpm2-tss"]="BSD-2"
+               ["app-misc/ddcutil"]="GPL-2"
+               ["app-misc/jq"]="MIT CC-BY-3.0"
+               ["app-shells/bash"]="GPL-3+"
+               ["dev-db/sqlite"]="public-domain"
+               ["dev-libs/cyrus-sasl"]="BSD-with-attribution"
+               ["dev-libs/expat"]="MIT"
+               ["dev-libs/glib"]="LGPL-2.1+"
+               ["dev-libs/hidapi"]="|| ( BSD GPL-3 HIDAPI )"
+               ["dev-libs/icu"]="BSD"
+               ["dev-libs/json-c"]="MIT"
+               ["dev-libs/libaio"]="LGPL-2"
+               ["dev-libs/libassuan"]="GPL-3 LGPL-2.1"
+               ["dev-libs/libevent"]="BSD"
+               ["dev-libs/libffi"]="MIT"
+               ["dev-libs/libgcrypt"]="LGPL-2.1 MIT"
+               ["dev-libs/libgpg-error"]="GPL-2 LGPL-2.1"
+               ["dev-libs/libp11"]="LGPL-2.1"
+               ["dev-libs/libpcre2"]="BSD"
+               ["dev-libs/libtasn1"]="LGPL-2.1+"
+               ["dev-libs/libunistring"]="|| ( LGPL-3+ GPL-2+ ) || ( FDL-1.2 
GPL-3+ )"
+               ["dev-libs/libusb"]="LGPL-2.1"
+               ["dev-libs/lzo"]="GPL-2+"
+               ["dev-libs/npth"]="LGPL-2.1+"
+               ["dev-libs/nss"]="|| ( MPL-2.0 GPL-2 LGPL-2.1 )"
+               ["dev-libs/oniguruma"]="BSD-2"
+               ["dev-libs/opensc"]="LGPL-2.1"
+               ["dev-libs/openssl"]="Apache-2.0"
+               ["dev-libs/userspace-rcu"]="LGPL-2.1"
+               ["media-libs/libmtp"]="LGPL-2.1"
+               ["media-libs/libpng"]="libpng2"
+               ["media-libs/libv4l"]="LGPL-2.1+"
+               ["net-dns/c-ares"]="MIT ISC"
+               ["net-dns/libidn2"]="|| ( GPL-2+ LGPL-3+ ) GPL-3+ unicode"
+               ["net-fs/cifs-utils"]="GPL-3"
+               ["net-fs/nfs-utils"]="GPL-2"
+               ["net-fs/samba"]="GPL-3"
+               ["net-libs/libmnl"]="LGPL-2.1"
+               ["net-libs/libndp"]="LGPL-2.1+"
+               ["net-libs/libtirpc"]="BSD BSD-2 BSD-4 LGPL-2.1+"
+               ["net-libs/nghttp2"]="MIT"
+               ["net-misc/curl"]="BSD curl ISC"
+               ["net-misc/networkmanager[iwd]"]="GPL-2+ LGPL-2.1+"
+               ["net-nds/openldap"]="OPENLDAP GPL-2"
+               ["net-wireless/bluez"]="GPL-2+ LGPL-2.1+"
+               ["net-wireless/iwd"]="GPL-2"
+               ["sys-apps/acl"]="LGPL-2.1"
+               ["sys-apps/attr"]="LGPL-2.1"
+               ["sys-apps/baselayout"]="GPL-2"
+               ["sys-apps/coreutils"]="GPL-3+"
+               ["sys-apps/dbus"]="|| ( AFL-2.1 GPL-2 )"
+               ["sys-apps/fwupd"]="LGPL-2.1+"
+               ["sys-apps/gawk"]="GPL-3+"
+               ["sys-apps/hwdata"]="GPL-2+"
+               ["sys-apps/iproute2"]="GPL-2"
+               ["sys-apps/kbd"]="GPL-2"
+               ["sys-apps/keyutils"]="GPL-2 LGPL-2.1"
+               ["sys-apps/kmod"]="LGPL-2"
+               ["sys-apps/less"]="|| ( GPL-3 BSD-2 )"
+               ["sys-apps/nvme-cli"]="GPL-2 GPL-2+"
+               ["sys-apps/pcsc-lite"]="BSD ISC MIT GPL-3+ GPL-2"
+               ["sys-apps/rng-tools"]="GPL-2"
+               ["sys-apps/sandbox"]="GPL-2"
+               ["sys-apps/sed"]="GPL-3+"
+               ["sys-apps/shadow"]="BSD GPL-2"
+               
["sys-apps/systemd[boot(-),cryptsetup,pkcs11,policykit,tpm,ukify(-)]"]="GPL-2 
LGPL-2.1 MIT public-domain"
+               ["sys-apps/util-linux"]="GPL-2 GPL-3 LGPL-2.1 BSD-4 MIT 
public-domain"
+               ["sys-auth/polkit"]="LGPL-2"
+               ["sys-block/nbd"]="GPL-2"
+               ["sys-block/open-isns"]="LGPL-2.1"
+               ["sys-boot/plymouth"]="GPL-2"
+               ["sys-devel/gcc"]="GPL-3+ LGPL-3+ || ( GPL-3+ libgcc libstdc++ 
gcc-runtime-library-exception-3.1 ) FDL-1.3+"
+               ["sys-fs/btrfs-progs"]="GPL-2"
+               ["sys-fs/cryptsetup"]="GPL-2+"
+               ["sys-fs/dmraid"]="GPL-2"
+               ["sys-fs/dosfstools"]="GPL-3"
+               ["sys-fs/e2fsprogs"]="GPL-2 BSD"
+               ["sys-fs/lvm2[lvm]"]="GPL-2"
+               ["sys-fs/mdadm"]="GPL-2"
+               ["sys-fs/multipath-tools"]="GPL-2"
+               ["sys-fs/xfsprogs"]="LGPL-2.1"
+               ["sys-kernel/dracut"]="GPL-2"
+               
["sys-kernel/linux-firmware[redistributable,-unknown-license]"]="GPL-2 GPL-2+ 
GPL-3 BSD MIT || ( MPL-1.1 GPL-2 ) linux-fw-redistributable BSD-2 BSD BSD-4 ISC 
MIT"
+               ["sys-libs/glibc"]="LGPL-2.1+ BSD HPND ISC inner-net rc PCRE"
+               ["sys-libs/libapparmor"]="GPL-2 LGPL-2.1"
+               ["sys-libs/libcap"]="|| ( GPL-2 BSD )"
+               ["sys-libs/libcap-ng"]="LGPL-2.1"
+               ["sys-libs/libnvme"]="LGPL-2.1+"
+               ["sys-libs/libseccomp"]="LGPL-2.1"
+               ["sys-libs/libxcrypt"]="LGPL-2.1+ public-domain BSD BSD-2"
+               ["sys-libs/ncurses"]="MIT"
+               ["sys-libs/pam"]="|| ( BSD GPL-2 )"
+               ["sys-libs/readline"]="GPL-3+"
+               ["sys-libs/zlib"]="ZLIB"
+               ["sys-process/procps"]="GPL-2+ LGPL-2+ LGPL-2.1+"
+               ["x11-libs/libdrm"]="MIT"
+               ["amd64? ( sys-firmware/intel-microcode )"]="amd64? ( 
intel-ucode )"
+               ["x86? ( sys-firmware/intel-microcode )"]="x86? ( intel-ucode )"
+       )
+       LICENSE+="
+               generic-uki? ( ${INITRD_PACKAGES[@]} )
+       "
+
+       IDEPEND="
+               generic-uki? (
+                       || (
+                               >=sys-kernel/installkernel-systemd-3
+                               
>=sys-kernel/installkernel-gentoo-8[-dracut(-),-ukify(-)]
+                       )
+               )
+               !generic-uki? (
+                       ${_IDEPEND_BASE}
+               )
+       "
+else
+       IDEPEND="${_IDEPEND_BASE}"
+fi
+unset _IDEPEND_BASE
+
 # needed by objtool that is installed along with the kernel and used
 # to build external modules
 # NB: linux-mod.eclass also adds this dep but it's cleaner to have
@@ -442,6 +595,21 @@ kernel-install_pkg_preinst() {
        fi
 }
 
+# @FUNCTION: kernel-install_extract_from_uki
+# @USAGE: <type> <input> <output>
+# @DESCRIPTION:
+# Extracts kernel image or initrd from an UKI.  <type> must be "linux"
+# or "initrd".
+kernel-install_extract_from_uki() {
+       [[ ${#} -eq 3 ]] || die "${FUNCNAME}: invalid arguments"
+       local extract_type=${1}
+       local uki=${2}
+       local out=${3}
+
+       $(tc-getOBJCOPY) -O binary "-j.${extract_type}" "${uki}" "${out}" ||
+               die "Failed to extract ${extract_type}"
+}
+
 # @FUNCTION: kernel-install_install_all
 # @USAGE: <ver>
 # @DESCRIPTION:
@@ -459,26 +627,41 @@ kernel-install_install_all() {
        local dir_ver=${1}
        local kernel_dir=${EROOT}/usr/src/linux-${dir_ver}
        local relfile=${kernel_dir}/include/config/kernel.release
+       local image_path=${kernel_dir}/$(dist-kernel_get_image_path)
+       local image_dir=${image_path%/*}
        local module_ver
        module_ver=$(<"${relfile}") || die
 
+       if [[ ${KERNEL_IUSE_GENERIC_UKI} ]]; then
+               if use generic-uki; then
+                       # Populate placeholders
+                       kernel-install_extract_from_uki linux \
+                               "${image_dir}"/uki.efi \
+                               "${image_path}"
+                       kernel-install_extract_from_uki initrd \
+                               "${image_dir}"/uki.efi \
+                               "${image_dir}"/initrd
+               else
+                       # Remove placeholders, -f because these have already 
been removed
+                       # when doing emerge --config.
+                       rm -f "${image_dir}"/{initrd,uki.efi} || die
+               fi
+       fi
+
        local success=
        # not an actual loop but allows error handling with 'break'
        while :; do
                nonfatal mount-boot_check_status || break
 
-               local image_path=$(dist-kernel_get_image_path)
                if use initramfs && has_version 
"<=sys-kernel/installkernel-gentoo-7"; then
                        # putting it alongside kernel image as 'initrd' makes
                        # kernel-install happier
                        nonfatal dist-kernel_build_initramfs \
-                               "${kernel_dir}/${image_path%/*}/initrd" \
-                               "${module_ver}" || break
+                               "${image_dir}/initrd" "${module_ver}" || break
                fi
 
                nonfatal dist-kernel_install_kernel "${module_ver}" \
-                       "${kernel_dir}/${image_path}" \
-                       "${kernel_dir}/System.map" || break
+                       "${image_path}" "${kernel_dir}/System.map" || break
 
                success=1
                break
@@ -508,6 +691,19 @@ kernel-install_pkg_postinst() {
        if [[ -z ${ROOT} ]]; then
                kernel-install_install_all "${dir_ver}"
        fi
+
+       if [[ ${KERNEL_IUSE_GENERIC_UKI} ]] && use generic-uki; then
+               ewarn "The prebuilt initramfs and unified kernel image are 
highly experimental!"
+               ewarn "These images may not work on your system. Please ensure 
that a working"
+               ewarn "alternative kernel(+initramfs) or UKI is also installed 
before rebooting!"
+               ewarn
+               ewarn "Note that when secureboot is enabled in the firmware 
settings any kernel"
+               ewarn "command line arguments supplied to the UKI by the 
bootloader are ignored."
+               ewarn "To ensure the root partition can be found, 
systemd-gpt-auto-generator must"
+               ewarn "be used. See [1] for more information."
+               ewarn
+               ewarn "[1]: 
https://wiki.gentoo.org/wiki/Systemd#Automatic_mounting_of_partitions_at_boot";
+       fi
 }
 
 # @FUNCTION: kernel-install_pkg_prerm
@@ -525,7 +721,7 @@ kernel-install_pkg_prerm() {
 kernel-install_pkg_postrm() {
        debug-print-function ${FUNCNAME} "${@}"
 
-       if [[ -z ${ROOT} ]] && use initramfs; then
+       if [[ -z ${ROOT} && ! ${KERNEL_IUSE_GENERIC_UKI} ]] && use initramfs; 
then
                local dir_ver=${PV}${KV_LOCALVERSION}
                local kernel_dir=${EROOT}/usr/src/linux-${dir_ver}
                local image_path=$(dist-kernel_get_image_path)

Reply via email to