|
| 1 | +# Copyright 2020-2023 Gentoo Authors |
| 2 | +# Distributed under the terms of the GNU General Public License v2 |
| 3 | + |
| 4 | +# @ECLASS: dist-kernel-utils.eclass |
| 5 | +# @MAINTAINER: |
| 6 | +# Distribution Kernel Project <[email protected]> |
| 7 | +# @AUTHOR: |
| 8 | +# Michał Górny <[email protected]> |
| 9 | +# @SUPPORTED_EAPIS: 7 8 |
| 10 | +# @BLURB: Utility functions related to Distribution Kernels |
| 11 | +# @DESCRIPTION: |
| 12 | +# This eclass provides various utility functions related to Distribution |
| 13 | +# Kernels. |
| 14 | + |
| 15 | +# @ECLASS_VARIABLE: KERNEL_IUSE_SECUREBOOT |
| 16 | +# @PRE_INHERIT |
| 17 | +# @DEFAULT_UNSET |
| 18 | +# @DESCRIPTION: |
| 19 | +# If set to a non-null value, inherits secureboot.eclass |
| 20 | +# and allows signing of generated kernel images. |
| 21 | + |
| 22 | +if [[ ! ${_DIST_KERNEL_UTILS} ]]; then |
| 23 | + |
| 24 | +case ${EAPI} in |
| 25 | + 7|8) ;; |
| 26 | + *) die "${ECLASS}: EAPI ${EAPI:-0} not supported" ;; |
| 27 | +esac |
| 28 | + |
| 29 | +if [[ ${KERNEL_IUSE_SECUREBOOT} ]]; then |
| 30 | + inherit secureboot |
| 31 | +fi |
| 32 | + |
| 33 | +# @FUNCTION: dist-kernel_build_initramfs |
| 34 | +# @USAGE: <output> <version> |
| 35 | +# @DESCRIPTION: |
| 36 | +# Build an initramfs for the kernel. <output> specifies the absolute |
| 37 | +# path where initramfs will be created, while <version> specifies |
| 38 | +# the kernel version, used to find modules. |
| 39 | +# |
| 40 | +# Note: while this function uses dracut at the moment, other initramfs |
| 41 | +# variants may be supported in the future. |
| 42 | +dist-kernel_build_initramfs() { |
| 43 | + debug-print-function ${FUNCNAME} "${@}" |
| 44 | + |
| 45 | + [[ ${#} -eq 2 ]] || die "${FUNCNAME}: invalid arguments" |
| 46 | + local output=${1} |
| 47 | + local version=${2} |
| 48 | + |
| 49 | + local rel_image_path=$(dist-kernel_get_image_path) |
| 50 | + local image=${output%/*}/${rel_image_path##*/} |
| 51 | + |
| 52 | + local args=( |
| 53 | + --force |
| 54 | + # if uefi=yes is used, dracut needs to locate the kernel image |
| 55 | + --kernel-image "${image}" |
| 56 | + |
| 57 | + # positional arguments |
| 58 | + "${output}" "${version}" |
| 59 | + ) |
| 60 | + |
| 61 | + ebegin "Building initramfs via dracut" |
| 62 | + dracut "${args[@]}" |
| 63 | + eend ${?} || die -n "Building initramfs failed" |
| 64 | +} |
| 65 | + |
| 66 | +# @FUNCTION: dist-kernel_get_image_path |
| 67 | +# @DESCRIPTION: |
| 68 | +# Get relative kernel image path specific to the current ${ARCH}. |
| 69 | +dist-kernel_get_image_path() { |
| 70 | + case ${ARCH} in |
| 71 | + amd64|x86) |
| 72 | + echo arch/x86/boot/bzImage |
| 73 | + ;; |
| 74 | + arm64) |
| 75 | + echo arch/arm64/boot/Image.gz |
| 76 | + ;; |
| 77 | + arm) |
| 78 | + echo arch/arm/boot/zImage |
| 79 | + ;; |
| 80 | + hppa|ppc|ppc64|sparc) |
| 81 | + # https://www.kernel.org/doc/html/latest/powerpc/bootwrapper.html |
| 82 | + # ./ is required because of ${image_path%/*} |
| 83 | + # substitutions in the code |
| 84 | + echo ./vmlinux |
| 85 | + ;; |
| 86 | + riscv) |
| 87 | + echo arch/riscv/boot/Image.gz |
| 88 | + ;; |
| 89 | + *) |
| 90 | + die "${FUNCNAME}: unsupported ARCH=${ARCH}" |
| 91 | + ;; |
| 92 | + esac |
| 93 | +} |
| 94 | + |
| 95 | +# @FUNCTION: dist-kernel_install_kernel |
| 96 | +# @USAGE: <version> <image> <system.map> |
| 97 | +# @DESCRIPTION: |
| 98 | +# Install kernel using installkernel tool. <version> specifies |
| 99 | +# the kernel version, <image> full path to the image, <system.map> |
| 100 | +# full path to System.map. |
| 101 | +dist-kernel_install_kernel() { |
| 102 | + debug-print-function ${FUNCNAME} "${@}" |
| 103 | + |
| 104 | + [[ ${#} -eq 3 ]] || die "${FUNCNAME}: invalid arguments" |
| 105 | + local version=${1} |
| 106 | + local image=${2} |
| 107 | + local map=${3} |
| 108 | + |
| 109 | + # if dracut is used in uefi=yes mode, initrd will actually |
| 110 | + # be a combined kernel+initramfs UEFI executable. we can easily |
| 111 | + # recognize it by PE magic (vs cpio for a regular initramfs) |
| 112 | + local initrd=${image%/*}/initrd |
| 113 | + local magic |
| 114 | + [[ -s ${initrd} ]] && read -n 2 magic < "${initrd}" |
| 115 | + if [[ ${magic} == MZ ]]; then |
| 116 | + einfo "Combined UEFI kernel+initramfs executable found" |
| 117 | + # install the combined executable in place of kernel |
| 118 | + image=${initrd%/*}/uki.efi |
| 119 | + mv "${initrd}" "${image}" || die |
| 120 | + # We moved the generated initrd, prevent dracut from running again |
| 121 | + # https://github.com/dracutdevs/dracut/pull/2405 |
| 122 | + shopt -s nullglob |
| 123 | + local plugins=() |
| 124 | + for file in "${EROOT}"/etc/kernel/install.d/*.install; do |
| 125 | + plugins+=( "${file}" ) |
| 126 | + done |
| 127 | + for file in "${EROOT}"/usr/lib/kernel/install.d/*.install; do |
| 128 | + if ! has "${file##*/}" 50-dracut.install 51-dracut-rescue.install "${plugins[@]##*/}"; then |
| 129 | + plugins+=( "${file}" ) |
| 130 | + fi |
| 131 | + done |
| 132 | + shopt -u nullglob |
| 133 | + export KERNEL_INSTALL_PLUGINS="${KERNEL_INSTALL_PLUGINS} ${plugins[@]}" |
| 134 | + fi |
| 135 | + |
| 136 | + if [[ ${KERNEL_IUSE_SECUREBOOT} ]]; then |
| 137 | + # Kernel-install requires uki's are named uki.efi, sign in-place |
| 138 | + secureboot_sign_efi_file "${image}" "${image}" |
| 139 | + fi |
| 140 | + |
| 141 | + ebegin "Installing the kernel via installkernel" |
| 142 | + # note: .config is taken relatively to System.map; |
| 143 | + # initrd relatively to bzImage |
| 144 | + installkernel "${version}" "${image}" "${map}" |
| 145 | + eend ${?} || die -n "Installing the kernel failed" |
| 146 | +} |
| 147 | + |
| 148 | +# @FUNCTION: dist-kernel_reinstall_initramfs |
| 149 | +# @USAGE: <kv-dir> <kv-full> |
| 150 | +# @DESCRIPTION: |
| 151 | +# Rebuild and install initramfs for the specified dist-kernel. |
| 152 | +# <kv-dir> is the kernel source directory (${KV_DIR} from linux-info), |
| 153 | +# while <kv-full> is the full kernel version (${KV_FULL}). |
| 154 | +# The function will determine whether <kernel-dir> is actually |
| 155 | +# a dist-kernel, and whether initramfs was used. |
| 156 | +# |
| 157 | +# This function is to be used in pkg_postinst() of ebuilds installing |
| 158 | +# kernel modules that are included in the initramfs. |
| 159 | +dist-kernel_reinstall_initramfs() { |
| 160 | + debug-print-function ${FUNCNAME} "${@}" |
| 161 | + |
| 162 | + [[ ${#} -eq 2 ]] || die "${FUNCNAME}: invalid arguments" |
| 163 | + local kernel_dir=${1} |
| 164 | + local ver=${2} |
| 165 | + |
| 166 | + local image_path=${kernel_dir}/$(dist-kernel_get_image_path) |
| 167 | + local initramfs_path=${image_path%/*}/initrd |
| 168 | + if [[ ! -f ${image_path} ]]; then |
| 169 | + eerror "Kernel install missing, image not found:" |
| 170 | + eerror " ${image_path}" |
| 171 | + eerror "Initramfs will not be updated. Please reinstall your kernel." |
| 172 | + return |
| 173 | + fi |
| 174 | + if [[ ! -f ${initramfs_path} && ! -f ${initramfs_path%/*}/uki.efi ]]; then |
| 175 | + einfo "No initramfs or uki found at ${image_path}" |
| 176 | + return |
| 177 | + fi |
| 178 | + |
| 179 | + dist-kernel_build_initramfs "${initramfs_path}" "${ver}" |
| 180 | + dist-kernel_install_kernel "${ver}" "${image_path}" \ |
| 181 | + "${kernel_dir}/System.map" |
| 182 | +} |
| 183 | + |
| 184 | +# @FUNCTION: dist-kernel_PV_to_KV |
| 185 | +# @USAGE: <pv> |
| 186 | +# @DESCRIPTION: |
| 187 | +# Convert a Gentoo-style ebuild version to kernel "x.y.z[-rcN]" version. |
| 188 | +dist-kernel_PV_to_KV() { |
| 189 | + debug-print-function ${FUNCNAME} "${@}" |
| 190 | + |
| 191 | + [[ ${#} -ne 1 ]] && die "${FUNCNAME}: invalid arguments" |
| 192 | + local pv=${1} |
| 193 | + |
| 194 | + local kv=${pv%%_*} |
| 195 | + [[ -z $(ver_cut 3- "${kv}") ]] && kv+=".0" |
| 196 | + [[ ${pv} == *_* ]] && kv+=-${pv#*_} |
| 197 | + echo "${kv}" |
| 198 | +} |
| 199 | + |
| 200 | +_DIST_KERNEL_UTILS=1 |
| 201 | +fi |
0 commit comments