Skip to content

Commit 6c42ffb

Browse files
committed
kernel-install.eclass: Install logic for dist-kernels
Introduce a new eclass that contains common logic needed to test and install distribution kernels. This is the eclass common both to kernels built from source and installed from binary packages. Signed-off-by: Michał Górny <[email protected]>
1 parent fa4f0a3 commit 6c42ffb

File tree

1 file changed

+309
-0
lines changed

1 file changed

+309
-0
lines changed

eclass/kernel-install.eclass

Lines changed: 309 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,309 @@
1+
# Copyright 2020 Gentoo Authors
2+
# Distributed under the terms of the GNU General Public License v2
3+
4+
# @ECLASS: kernel-install.eclass
5+
# @MAINTAINER:
6+
# Distribution Kernel Project <[email protected]>
7+
# @AUTHOR:
8+
# Michał Górny <[email protected]>
9+
# @SUPPORTED_EAPIS: 7
10+
# @BLURB: Installation mechanics for Distribution Kernels
11+
# @DESCRIPTION:
12+
# This eclass provides the logic needed to test and install different
13+
# kinds of Distribution Kernel packages, including both kernels built
14+
# from source and distributed as binaries. The eclass relies on the
15+
# ebuild installing a subset of built kernel tree into
16+
# /usr/src/linux-${PV} containing the kernel image in its standard
17+
# location and System.map.
18+
#
19+
# The eclass exports src_test, pkg_postinst and pkg_postrm.
20+
# Additionally, the inherited mount-boot eclass exports pkg_pretend.
21+
# It also stubs out pkg_preinst and pkg_prerm defined by mount-boot.
22+
23+
if [[ ! ${_KERNEL_INSTALL_ECLASS} ]]; then
24+
25+
case "${EAPI:-0}" in
26+
0|1|2|3|4|5|6)
27+
die "Unsupported EAPI=${EAPI:-0} (too old) for ${ECLASS}"
28+
;;
29+
7)
30+
;;
31+
*)
32+
die "Unsupported EAPI=${EAPI} (unknown) for ${ECLASS}"
33+
;;
34+
esac
35+
36+
inherit mount-boot
37+
38+
TCL_VER=10.1
39+
SRC_URI+="
40+
test? (
41+
amd64? (
42+
https://dev.gentoo.org/~mgorny/dist/tinycorelinux-${TCL_VER}-amd64.qcow2
43+
)
44+
x86? (
45+
https://dev.gentoo.org/~mgorny/dist/tinycorelinux-${TCL_VER}-x86.qcow2
46+
)
47+
)"
48+
49+
SLOT="${PV}"
50+
IUSE="+initramfs test"
51+
RESTRICT+=" !test? ( test ) test? ( userpriv )"
52+
53+
# install-DEPEND actually
54+
# note: we need installkernel with initramfs support!
55+
RDEPEND="
56+
|| (
57+
sys-kernel/installkernel-gentoo
58+
sys-kernel/installkernel-systemd-boot
59+
)
60+
initramfs? ( >=sys-kernel/dracut-049-r3 )"
61+
BDEPEND="
62+
test? (
63+
dev-tcltk/expect
64+
sys-kernel/dracut
65+
amd64? ( app-emulation/qemu[qemu_softmmu_targets_x86_64] )
66+
x86? ( app-emulation/qemu[qemu_softmmu_targets_i386] )
67+
)"
68+
69+
# @FUNCTION: kernel-install_build_initramfs
70+
# @USAGE: <output> <version>
71+
# @DESCRIPTION:
72+
# Build an initramfs for the kernel. <output> specifies the absolute
73+
# path where initramfs will be created, while <version> specifies
74+
# the kernel version, used to find modules.
75+
kernel-install_build_initramfs() {
76+
debug-print-function ${FUNCNAME} "${@}"
77+
78+
[[ ${#} -eq 2 ]] || die "${FUNCNAME}: invalid arguments"
79+
local output=${1}
80+
local version=${2}
81+
82+
ebegin "Building initramfs via dracut"
83+
dracut --force "${output}" "${version}"
84+
eend ${?} || die "Building initramfs failed"
85+
}
86+
87+
# @FUNCTION: kernel-install_get_image_path
88+
# @DESCRIPTION:
89+
# Get relative kernel image path specific to the current ${ARCH}.
90+
kernel-install_get_image_path() {
91+
case ${ARCH} in
92+
amd64|x86)
93+
echo arch/x86/boot/bzImage
94+
;;
95+
*)
96+
die "${FUNCNAME}: unsupported ARCH=${ARCH}"
97+
;;
98+
esac
99+
}
100+
101+
# @FUNCTION: kernel-install_install_kernel
102+
# @USAGE: <version> <image> <system.map>
103+
# @DESCRIPTION:
104+
# Install kernel using installkernel tool. <version> specifies
105+
# the kernel version, <image> full path to the image, <system.map>
106+
# full path to System.map.
107+
kernel-install_install_kernel() {
108+
debug-print-function ${FUNCNAME} "${@}"
109+
110+
[[ ${#} -eq 3 ]] || die "${FUNCNAME}: invalid arguments"
111+
local version=${1}
112+
local image=${2}
113+
local map=${3}
114+
115+
ebegin "Installing the kernel via installkernel"
116+
# note: .config is taken relatively to System.map;
117+
# initrd relatively to bzImage
118+
installkernel "${version}" "${image}" "${map}"
119+
eend ${?} || die "Installing the kernel failed"
120+
}
121+
122+
# @FUNCTION: kernel-install_update_symlink
123+
# @USAGE: <target> <version>
124+
# @DESCRIPTION:
125+
# Update the kernel source symlink at <target> (full path) with a link
126+
# to <target>-<version> if it's either missing or pointing out to
127+
# an older version of this package.
128+
kernel-install_update_symlink() {
129+
debug-print-function ${FUNCNAME} "${@}"
130+
131+
[[ ${#} -eq 2 ]] || die "${FUNCNAME}: invalid arguments"
132+
local target=${1}
133+
local version=${2}
134+
135+
if [[ ! -e ${target} ]]; then
136+
ebegin "Creating ${target} symlink"
137+
ln -f -n -s "${target##*/}-${version}" "${target}"
138+
eend ${?}
139+
else
140+
local symlink_target=$(readlink "${target}")
141+
local symlink_ver=${symlink_target#${target##*/}-}
142+
if [[ ${symlink_target} == ${target##*/}-* && \
143+
-z ${symlink_ver//[0-9.]/} ]]
144+
then
145+
local symlink_pkg=${CATEGORY}/${PN}-${symlink_ver}
146+
# if the current target is either being replaced, or still
147+
# installed (probably depclean candidate), update the symlink
148+
if has "${symlink_ver}" ${REPLACING_VERSIONS} ||
149+
has_version -r "~${symlink_pkg}"
150+
then
151+
ebegin "Updating ${target} symlink"
152+
ln -f -n -s "${target##*/}-${version}" "${target}"
153+
eend ${?}
154+
fi
155+
fi
156+
fi
157+
}
158+
159+
# @FUNCTION: kernel-install_get_qemu_arch
160+
# @DESCRIPTION:
161+
# Get appropriate qemu suffix for the current ${ARCH}.
162+
kernel-install_get_qemu_arch() {
163+
debug-print-function ${FUNCNAME} "${@}"
164+
165+
case ${ARCH} in
166+
amd64)
167+
echo x86_64
168+
;;
169+
x86)
170+
echo i386
171+
;;
172+
*)
173+
die "${FUNCNAME}: unsupported ARCH=${ARCH}"
174+
;;
175+
esac
176+
}
177+
178+
# @FUNCTION: kernel-install_test
179+
# @USAGE: <version> <image> <modules>
180+
# @DESCRIPTION:
181+
# Test that the kernel can successfully boot a minimal system image
182+
# in qemu. <version> is the kernel version, <image> path to the image,
183+
# <modules> path to module tree.
184+
kernel-install_test() {
185+
debug-print-function ${FUNCNAME} "${@}"
186+
187+
[[ ${#} -eq 3 ]] || die "${FUNCNAME}: invalid arguments"
188+
local version=${1}
189+
local image=${2}
190+
local modules=${3}
191+
192+
local qemu_arch=$(kernel-install_get_qemu_arch)
193+
194+
dracut \
195+
--conf /dev/null \
196+
--confdir /dev/null \
197+
--no-hostonly \
198+
--kmoddir "${modules}" \
199+
"${T}/initrd" "${version}" || die
200+
# get a read-write copy of the disk image
201+
cp "${DISTDIR}/tinycorelinux-${TCL_VER}-${ARCH}.qcow2" \
202+
"${T}/fs.qcow2" || die
203+
204+
cd "${T}" || die
205+
cat > run.sh <<-EOF || die
206+
#!/bin/sh
207+
exec qemu-system-${qemu_arch} \
208+
-m 256M \
209+
-display none \
210+
-no-reboot \
211+
-kernel '${image}' \
212+
-initrd '${T}/initrd' \
213+
-serial mon:stdio \
214+
-hda '${T}/fs.qcow2' \
215+
-append 'root=/dev/sda console=ttyS0,115200n8'
216+
EOF
217+
chmod +x run.sh || die
218+
# TODO: initramfs does not let core finish starting on some systems,
219+
# figure out how to make it better at that
220+
expect - <<-EOF || die "Booting kernel failed"
221+
set timeout 900
222+
spawn ./run.sh
223+
expect {
224+
"Kernel panic" {
225+
send_error "\n* Kernel panic"
226+
exit 1
227+
}
228+
"Entering emergency mode" {
229+
send_error "\n* Initramfs failed to start the system"
230+
exit 1
231+
}
232+
"Core 10.1" {
233+
send_error "\n* Booted successfully"
234+
exit 0
235+
}
236+
timeout {
237+
send_error "\n* Kernel boot timed out"
238+
exit 2
239+
}
240+
}
241+
EOF
242+
}
243+
244+
# @FUNCTION: kernel-install_src_test
245+
# @DESCRIPTION:
246+
# Boilerplate function to remind people to call the tests.
247+
kernel-install_src_test() {
248+
debug-print-function ${FUNCNAME} "${@}"
249+
250+
die "Please redefine src_test() and call kernel-install_test()."
251+
}
252+
253+
# @FUNCTION: kernel-install_pkg_preinst
254+
# @DESCRIPTION:
255+
# Stub out mount-boot.eclass.
256+
kernel-install_pkg_preinst() {
257+
debug-print-function ${FUNCNAME} "${@}"
258+
259+
# (no-op)
260+
}
261+
262+
# @FUNCTION: kernel-install_pkg_postinst
263+
# @DESCRIPTION:
264+
# Build an initramfs for the kernel, install it and update
265+
# the /usr/src/linux symlink.
266+
kernel-install_pkg_postinst() {
267+
debug-print-function ${FUNCNAME} "${@}"
268+
269+
if [[ -z ${ROOT} ]]; then
270+
mount-boot_pkg_preinst
271+
272+
if use initramfs; then
273+
# putting it alongside kernel image as 'initrd' makes
274+
# kernel-install happier
275+
kernel-install_build_initramfs \
276+
"${EROOT}/usr/src/linux-${PV}/initrd" "${PV}"
277+
fi
278+
279+
kernel-install_install_kernel "${PV}" \
280+
"${EROOT}/usr/src/linux-${PV}/$(kernel-install_get_image_path)" \
281+
"${EROOT}/usr/src/linux-${PV}/System.map"
282+
fi
283+
284+
kernel-install_update_symlink "${EROOT}/usr/src/linux" "${PV}"
285+
}
286+
287+
# @FUNCTION: kernel-install_pkg_prerm
288+
# @DESCRIPTION:
289+
# Stub out mount-boot.eclass.
290+
kernel-install_pkg_prerm() {
291+
debug-print-function ${FUNCNAME} "${@}"
292+
293+
# (no-op)
294+
}
295+
296+
# @FUNCTION: kernel-install_pkg_postrm
297+
# @DESCRIPTION:
298+
# No-op at the moment. Will be used to remove obsolete kernels
299+
# in the future.
300+
kernel-install_pkg_postrm() {
301+
debug-print-function ${FUNCNAME} "${@}"
302+
303+
# (no-op at the moment)
304+
}
305+
306+
_KERNEL_INSTALL_ECLASS=1
307+
fi
308+
309+
EXPORT_FUNCTIONS src_test pkg_preinst pkg_postinst pkg_prerm pkg_postrm

0 commit comments

Comments
 (0)