diff options
-rw-r--r-- | eclass/kernel-install.eclass | 309 |
1 files changed, 309 insertions, 0 deletions
diff --git a/eclass/kernel-install.eclass b/eclass/kernel-install.eclass new file mode 100644 index 000000000000..f44fc3ebfa9b --- /dev/null +++ b/eclass/kernel-install.eclass @@ -0,0 +1,309 @@ +# Copyright 2020 Gentoo Authors +# Distributed under the terms of the GNU General Public License v2 + +# @ECLASS: kernel-install.eclass +# @MAINTAINER: +# Distribution Kernel Project <dist-kernel@gentoo.org> +# @AUTHOR: +# Michał Górny <mgorny@gentoo.org> +# @SUPPORTED_EAPIS: 7 +# @BLURB: Installation mechanics for Distribution Kernels +# @DESCRIPTION: +# This eclass provides the logic needed to test and install different +# kinds of Distribution Kernel packages, including both kernels built +# from source and distributed as binaries. The eclass relies on the +# ebuild installing a subset of built kernel tree into +# /usr/src/linux-${PV} containing the kernel image in its standard +# location and System.map. +# +# The eclass exports src_test, pkg_postinst and pkg_postrm. +# Additionally, the inherited mount-boot eclass exports pkg_pretend. +# It also stubs out pkg_preinst and pkg_prerm defined by mount-boot. + +if [[ ! ${_KERNEL_INSTALL_ECLASS} ]]; then + +case "${EAPI:-0}" in + 0|1|2|3|4|5|6) + die "Unsupported EAPI=${EAPI:-0} (too old) for ${ECLASS}" + ;; + 7) + ;; + *) + die "Unsupported EAPI=${EAPI} (unknown) for ${ECLASS}" + ;; +esac + +inherit mount-boot + +TCL_VER=10.1 +SRC_URI+=" + test? ( + amd64? ( + https://dev.gentoo.org/~mgorny/dist/tinycorelinux-${TCL_VER}-amd64.qcow2 + ) + x86? ( + https://dev.gentoo.org/~mgorny/dist/tinycorelinux-${TCL_VER}-x86.qcow2 + ) + )" + +SLOT="${PV}" +IUSE="+initramfs test" +RESTRICT+=" !test? ( test ) test? ( userpriv )" + +# install-DEPEND actually +# note: we need installkernel with initramfs support! +RDEPEND=" + || ( + sys-kernel/installkernel-gentoo + sys-kernel/installkernel-systemd-boot + ) + initramfs? ( >=sys-kernel/dracut-049-r3 )" +BDEPEND=" + test? ( + dev-tcltk/expect + sys-kernel/dracut + amd64? ( app-emulation/qemu[qemu_softmmu_targets_x86_64] ) + x86? ( app-emulation/qemu[qemu_softmmu_targets_i386] ) + )" + +# @FUNCTION: kernel-install_build_initramfs +# @USAGE: <output> <version> +# @DESCRIPTION: +# Build an initramfs for the kernel. <output> specifies the absolute +# path where initramfs will be created, while <version> specifies +# the kernel version, used to find modules. +kernel-install_build_initramfs() { + debug-print-function ${FUNCNAME} "${@}" + + [[ ${#} -eq 2 ]] || die "${FUNCNAME}: invalid arguments" + local output=${1} + local version=${2} + + ebegin "Building initramfs via dracut" + dracut --force "${output}" "${version}" + eend ${?} || die "Building initramfs failed" +} + +# @FUNCTION: kernel-install_get_image_path +# @DESCRIPTION: +# Get relative kernel image path specific to the current ${ARCH}. +kernel-install_get_image_path() { + case ${ARCH} in + amd64|x86) + echo arch/x86/boot/bzImage + ;; + *) + die "${FUNCNAME}: unsupported ARCH=${ARCH}" + ;; + esac +} + +# @FUNCTION: kernel-install_install_kernel +# @USAGE: <version> <image> <system.map> +# @DESCRIPTION: +# Install kernel using installkernel tool. <version> specifies +# the kernel version, <image> full path to the image, <system.map> +# full path to System.map. +kernel-install_install_kernel() { + debug-print-function ${FUNCNAME} "${@}" + + [[ ${#} -eq 3 ]] || die "${FUNCNAME}: invalid arguments" + local version=${1} + local image=${2} + local map=${3} + + ebegin "Installing the kernel via installkernel" + # note: .config is taken relatively to System.map; + # initrd relatively to bzImage + installkernel "${version}" "${image}" "${map}" + eend ${?} || die "Installing the kernel failed" +} + +# @FUNCTION: kernel-install_update_symlink +# @USAGE: <target> <version> +# @DESCRIPTION: +# Update the kernel source symlink at <target> (full path) with a link +# to <target>-<version> if it's either missing or pointing out to +# an older version of this package. +kernel-install_update_symlink() { + debug-print-function ${FUNCNAME} "${@}" + + [[ ${#} -eq 2 ]] || die "${FUNCNAME}: invalid arguments" + local target=${1} + local version=${2} + + if [[ ! -e ${target} ]]; then + ebegin "Creating ${target} symlink" + ln -f -n -s "${target##*/}-${version}" "${target}" + eend ${?} + else + local symlink_target=$(readlink "${target}") + local symlink_ver=${symlink_target#${target##*/}-} + if [[ ${symlink_target} == ${target##*/}-* && \ + -z ${symlink_ver//[0-9.]/} ]] + then + local symlink_pkg=${CATEGORY}/${PN}-${symlink_ver} + # if the current target is either being replaced, or still + # installed (probably depclean candidate), update the symlink + if has "${symlink_ver}" ${REPLACING_VERSIONS} || + has_version -r "~${symlink_pkg}" + then + ebegin "Updating ${target} symlink" + ln -f -n -s "${target##*/}-${version}" "${target}" + eend ${?} + fi + fi + fi +} + +# @FUNCTION: kernel-install_get_qemu_arch +# @DESCRIPTION: +# Get appropriate qemu suffix for the current ${ARCH}. +kernel-install_get_qemu_arch() { + debug-print-function ${FUNCNAME} "${@}" + + case ${ARCH} in + amd64) + echo x86_64 + ;; + x86) + echo i386 + ;; + *) + die "${FUNCNAME}: unsupported ARCH=${ARCH}" + ;; + esac +} + +# @FUNCTION: kernel-install_test +# @USAGE: <version> <image> <modules> +# @DESCRIPTION: +# Test that the kernel can successfully boot a minimal system image +# in qemu. <version> is the kernel version, <image> path to the image, +# <modules> path to module tree. +kernel-install_test() { + debug-print-function ${FUNCNAME} "${@}" + + [[ ${#} -eq 3 ]] || die "${FUNCNAME}: invalid arguments" + local version=${1} + local image=${2} + local modules=${3} + + local qemu_arch=$(kernel-install_get_qemu_arch) + + dracut \ + --conf /dev/null \ + --confdir /dev/null \ + --no-hostonly \ + --kmoddir "${modules}" \ + "${T}/initrd" "${version}" || die + # get a read-write copy of the disk image + cp "${DISTDIR}/tinycorelinux-${TCL_VER}-${ARCH}.qcow2" \ + "${T}/fs.qcow2" || die + + cd "${T}" || die + cat > run.sh <<-EOF || die + #!/bin/sh + exec qemu-system-${qemu_arch} \ + -m 256M \ + -display none \ + -no-reboot \ + -kernel '${image}' \ + -initrd '${T}/initrd' \ + -serial mon:stdio \ + -hda '${T}/fs.qcow2' \ + -append 'root=/dev/sda console=ttyS0,115200n8' + EOF + chmod +x run.sh || die + # TODO: initramfs does not let core finish starting on some systems, + # figure out how to make it better at that + expect - <<-EOF || die "Booting kernel failed" + set timeout 900 + spawn ./run.sh + expect { + "Kernel panic" { + send_error "\n* Kernel panic" + exit 1 + } + "Entering emergency mode" { + send_error "\n* Initramfs failed to start the system" + exit 1 + } + "Core 10.1" { + send_error "\n* Booted successfully" + exit 0 + } + timeout { + send_error "\n* Kernel boot timed out" + exit 2 + } + } + EOF +} + +# @FUNCTION: kernel-install_src_test +# @DESCRIPTION: +# Boilerplate function to remind people to call the tests. +kernel-install_src_test() { + debug-print-function ${FUNCNAME} "${@}" + + die "Please redefine src_test() and call kernel-install_test()." +} + +# @FUNCTION: kernel-install_pkg_preinst +# @DESCRIPTION: +# Stub out mount-boot.eclass. +kernel-install_pkg_preinst() { + debug-print-function ${FUNCNAME} "${@}" + + # (no-op) +} + +# @FUNCTION: kernel-install_pkg_postinst +# @DESCRIPTION: +# Build an initramfs for the kernel, install it and update +# the /usr/src/linux symlink. +kernel-install_pkg_postinst() { + debug-print-function ${FUNCNAME} "${@}" + + if [[ -z ${ROOT} ]]; then + mount-boot_pkg_preinst + + if use initramfs; then + # putting it alongside kernel image as 'initrd' makes + # kernel-install happier + kernel-install_build_initramfs \ + "${EROOT}/usr/src/linux-${PV}/initrd" "${PV}" + fi + + kernel-install_install_kernel "${PV}" \ + "${EROOT}/usr/src/linux-${PV}/$(kernel-install_get_image_path)" \ + "${EROOT}/usr/src/linux-${PV}/System.map" + fi + + kernel-install_update_symlink "${EROOT}/usr/src/linux" "${PV}" +} + +# @FUNCTION: kernel-install_pkg_prerm +# @DESCRIPTION: +# Stub out mount-boot.eclass. +kernel-install_pkg_prerm() { + debug-print-function ${FUNCNAME} "${@}" + + # (no-op) +} + +# @FUNCTION: kernel-install_pkg_postrm +# @DESCRIPTION: +# No-op at the moment. Will be used to remove obsolete kernels +# in the future. +kernel-install_pkg_postrm() { + debug-print-function ${FUNCNAME} "${@}" + + # (no-op at the moment) +} + +_KERNEL_INSTALL_ECLASS=1 +fi + +EXPORT_FUNCTIONS src_test pkg_preinst pkg_postinst pkg_prerm pkg_postrm |