summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKristian Klausen <kristian@klausen.dk>2021-09-28 14:44:16 +0200
committerRichard Purdie <richard.purdie@linuxfoundation.org>2021-10-04 15:03:53 +0100
commitb8c0f073f6a282f89fba7711ec168d0638749300 (patch)
treee5ab029e59753092968248f5d339d3b0dda83f1f
parent75b79d5c056b5abb44c546af773e3431d4c09476 (diff)
downloadpoky-b8c0f073f6a282f89fba7711ec168d0638749300.tar.gz
wic/bootimg-efi: Add Unified Kernel Image option
"A unified kernel image is a single EFI PE executable combining an EFI stub loader, a kernel image, an initramfs image, and the kernel command line. [...] Images of this type have the advantage that all metadata and payload that makes up the boot entry is monopolized in a single PE file that can be signed cryptographically as one for the purpose of EFI SecureBoot."[1] This commit adds a create-unified-kernel-image=true option to the bootimg-efi plugin for creating a Unified Kernel Image[1] and installing it into $BOOT/EFI/Linux/ with a .efi extension per the the Boot Loader Specification[1][2]. This is useful for implementing Secure Boot. systemd-boot is the only mainstream bootloader implementing the specification, but GRUB should be able to boot the EFI binary, this commit however doesn't implement the necessary changes to the GRUB config generation logic to boot the Unified Kernel Image. [1] https://systemd.io/BOOT_LOADER_SPECIFICATION/#type-2-efi-unified-kernel-images [2] https://systemd.io/BOOT_LOADER_SPECIFICATION/ (From OE-Core rev: b0573f240525df561ddef6e47cb285b217d38487) Signed-off-by: Kristian Klausen <kristian@klausen.dk> Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
-rw-r--r--meta-selftest/wic/test_efi_plugin.wks6
-rw-r--r--meta/classes/image_types_wic.bbclass5
-rw-r--r--meta/lib/oeqa/selftest/cases/wic.py29
-rw-r--r--scripts/lib/wic/plugins/source/bootimg-efi.py74
4 files changed, 102 insertions, 12 deletions
diff --git a/meta-selftest/wic/test_efi_plugin.wks b/meta-selftest/wic/test_efi_plugin.wks
new file mode 100644
index 0000000000..1603d6c4bb
--- /dev/null
+++ b/meta-selftest/wic/test_efi_plugin.wks
@@ -0,0 +1,6 @@
1# short-description: This file is used in oe-selftest wic module to test efi plugin
2
3part /boot --source bootimg-efi --sourceparams="loader=systemd-boot,create-unified-kernel-image=true,initrd=${INITRAMFS_IMAGE}-${MACHINE}.${INITRAMFS_FSTYPES}" --active --align 1024 --use-uuid
4part / --source rootfs --fstype=ext4 --align 1024 --use-uuid
5
6bootloader --timeout=0 --append="console=ttyS0,115200n8"
diff --git a/meta/classes/image_types_wic.bbclass b/meta/classes/image_types_wic.bbclass
index d561fb2636..e3863c88a9 100644
--- a/meta/classes/image_types_wic.bbclass
+++ b/meta/classes/image_types_wic.bbclass
@@ -27,6 +27,7 @@ WICVARS ?= "\
27 ROOTFS_SIZE \ 27 ROOTFS_SIZE \
28 STAGING_DATADIR \ 28 STAGING_DATADIR \
29 STAGING_DIR \ 29 STAGING_DIR \
30 STAGING_DIR_HOST \
30 STAGING_LIBDIR \ 31 STAGING_LIBDIR \
31 TARGET_SYS \ 32 TARGET_SYS \
32" 33"
@@ -84,8 +85,8 @@ do_image_wic[deptask] += "do_image_complete"
84WKS_FILE_DEPENDS_DEFAULT = '${@bb.utils.contains_any("BUILD_ARCH", [ 'x86_64', 'i686' ], "syslinux-native", "",d)}' 85WKS_FILE_DEPENDS_DEFAULT = '${@bb.utils.contains_any("BUILD_ARCH", [ 'x86_64', 'i686' ], "syslinux-native", "",d)}'
85WKS_FILE_DEPENDS_DEFAULT += "bmap-tools-native cdrtools-native btrfs-tools-native squashfs-tools-native e2fsprogs-native" 86WKS_FILE_DEPENDS_DEFAULT += "bmap-tools-native cdrtools-native btrfs-tools-native squashfs-tools-native e2fsprogs-native"
86WKS_FILE_DEPENDS_BOOTLOADERS = "" 87WKS_FILE_DEPENDS_BOOTLOADERS = ""
87WKS_FILE_DEPENDS_BOOTLOADERS:x86 = "syslinux grub-efi systemd-boot" 88WKS_FILE_DEPENDS_BOOTLOADERS:x86 = "syslinux grub-efi systemd-boot os-release"
88WKS_FILE_DEPENDS_BOOTLOADERS:x86-64 = "syslinux grub-efi systemd-boot" 89WKS_FILE_DEPENDS_BOOTLOADERS:x86-64 = "syslinux grub-efi systemd-boot os-release"
89WKS_FILE_DEPENDS_BOOTLOADERS:x86-x32 = "syslinux grub-efi" 90WKS_FILE_DEPENDS_BOOTLOADERS:x86-x32 = "syslinux grub-efi"
90 91
91WKS_FILE_DEPENDS ??= "${WKS_FILE_DEPENDS_DEFAULT} ${WKS_FILE_DEPENDS_BOOTLOADERS}" 92WKS_FILE_DEPENDS ??= "${WKS_FILE_DEPENDS_DEFAULT} ${WKS_FILE_DEPENDS_BOOTLOADERS}"
diff --git a/meta/lib/oeqa/selftest/cases/wic.py b/meta/lib/oeqa/selftest/cases/wic.py
index dc7b9e637e..5fc8e65142 100644
--- a/meta/lib/oeqa/selftest/cases/wic.py
+++ b/meta/lib/oeqa/selftest/cases/wic.py
@@ -1158,6 +1158,35 @@ class Wic2(WicTestCase):
1158 out = glob(self.resultdir + "%s-*.direct" % wksname) 1158 out = glob(self.resultdir + "%s-*.direct" % wksname)
1159 self.assertEqual(1, len(out)) 1159 self.assertEqual(1, len(out))
1160 1160
1161 @only_for_arch(['i586', 'i686', 'x86_64'])
1162 def test_efi_plugin_unified_kernel_image_qemu(self):
1163 """Test efi plugin's Unified Kernel Image feature in qemu"""
1164 config = 'IMAGE_FSTYPES = "wic"\n'\
1165 'INITRAMFS_IMAGE = "core-image-minimal-initramfs"\n'\
1166 'WKS_FILE = "test_efi_plugin.wks"\n'\
1167 'MACHINE_FEATURES:append = " efi"\n'
1168 self.append_config(config)
1169 self.assertEqual(0, bitbake('core-image-minimal core-image-minimal-initramfs ovmf').status)
1170 self.remove_config(config)
1171
1172 with runqemu('core-image-minimal', ssh=False,
1173 runqemuparams='ovmf', image_fstype='wic') as qemu:
1174 # Check that /boot has EFI bootx64.efi (required for EFI)
1175 cmd = "ls /boot/EFI/BOOT/bootx64.efi | wc -l"
1176 status, output = qemu.run_serial(cmd)
1177 self.assertEqual(1, status, 'Failed to run command "%s": %s' % (cmd, output))
1178 self.assertEqual(output, '1')
1179 # Check that /boot has EFI/Linux/linux.efi (required for Unified Kernel Images auto detection)
1180 cmd = "ls /boot/EFI/Linux/linux.efi | wc -l"
1181 status, output = qemu.run_serial(cmd)
1182 self.assertEqual(1, status, 'Failed to run command "%s": %s' % (cmd, output))
1183 self.assertEqual(output, '1')
1184 # Check that /boot doesn't have loader/entries/boot.conf (Unified Kernel Images are auto detected by the bootloader)
1185 cmd = "ls /boot/loader/entries/boot.conf 2&>/dev/null | wc -l"
1186 status, output = qemu.run_serial(cmd)
1187 self.assertEqual(1, status, 'Failed to run command "%s": %s' % (cmd, output))
1188 self.assertEqual(output, '0')
1189
1161 def test_fs_types(self): 1190 def test_fs_types(self):
1162 """Test filesystem types for empty and not empty partitions""" 1191 """Test filesystem types for empty and not empty partitions"""
1163 img = 'core-image-minimal' 1192 img = 'core-image-minimal'
diff --git a/scripts/lib/wic/plugins/source/bootimg-efi.py b/scripts/lib/wic/plugins/source/bootimg-efi.py
index cdc72543c2..0391aebdc8 100644
--- a/scripts/lib/wic/plugins/source/bootimg-efi.py
+++ b/scripts/lib/wic/plugins/source/bootimg-efi.py
@@ -12,6 +12,7 @@
12 12
13import logging 13import logging
14import os 14import os
15import tempfile
15import shutil 16import shutil
16import re 17import re
17 18
@@ -119,12 +120,13 @@ class BootimgEFIPlugin(SourcePlugin):
119 bootloader = creator.ks.bootloader 120 bootloader = creator.ks.bootloader
120 121
121 loader_conf = "" 122 loader_conf = ""
122 loader_conf += "default boot\n" 123 if source_params.get('create-unified-kernel-image') != "true":
124 loader_conf += "default boot\n"
123 loader_conf += "timeout %d\n" % bootloader.timeout 125 loader_conf += "timeout %d\n" % bootloader.timeout
124 126
125 initrd = source_params.get('initrd') 127 initrd = source_params.get('initrd')
126 128
127 if initrd: 129 if initrd and source_params.get('create-unified-kernel-image') != "true":
128 # obviously we need to have a common common deploy var 130 # obviously we need to have a common common deploy var
129 bootimg_dir = get_bitbake_var("DEPLOY_DIR_IMAGE") 131 bootimg_dir = get_bitbake_var("DEPLOY_DIR_IMAGE")
130 if not bootimg_dir: 132 if not bootimg_dir:
@@ -183,11 +185,12 @@ class BootimgEFIPlugin(SourcePlugin):
183 for rd in initrds: 185 for rd in initrds:
184 boot_conf += "initrd /%s\n" % rd 186 boot_conf += "initrd /%s\n" % rd
185 187
186 logger.debug("Writing systemd-boot config " 188 if source_params.get('create-unified-kernel-image') != "true":
187 "%s/hdd/boot/loader/entries/boot.conf", cr_workdir) 189 logger.debug("Writing systemd-boot config "
188 cfg = open("%s/hdd/boot/loader/entries/boot.conf" % cr_workdir, "w") 190 "%s/hdd/boot/loader/entries/boot.conf", cr_workdir)
189 cfg.write(boot_conf) 191 cfg = open("%s/hdd/boot/loader/entries/boot.conf" % cr_workdir, "w")
190 cfg.close() 192 cfg.write(boot_conf)
193 cfg.close()
191 194
192 195
193 @classmethod 196 @classmethod
@@ -288,9 +291,60 @@ class BootimgEFIPlugin(SourcePlugin):
288 kernel = "%s-%s.bin" % \ 291 kernel = "%s-%s.bin" % \
289 (get_bitbake_var("KERNEL_IMAGETYPE"), get_bitbake_var("INITRAMFS_LINK_NAME")) 292 (get_bitbake_var("KERNEL_IMAGETYPE"), get_bitbake_var("INITRAMFS_LINK_NAME"))
290 293
291 install_cmd = "install -m 0644 %s/%s %s/%s" % \ 294 if source_params.get('create-unified-kernel-image') == "true":
292 (staging_kernel_dir, kernel, hdddir, kernel) 295 initrd = source_params.get('initrd')
293 exec_cmd(install_cmd) 296 if not initrd:
297 raise WicError("initrd= must be specified when create-unified-kernel-image=true, exiting")
298
299 deploy_dir = get_bitbake_var("DEPLOY_DIR_IMAGE")
300 efi_stub = glob("%s/%s" % (deploy_dir, "linux*.efi.stub"))
301 if len(efi_stub) == 0:
302 raise WicError("Unified Kernel Image EFI stub not found, exiting")
303 efi_stub = efi_stub[0]
304
305 with tempfile.TemporaryDirectory() as tmp_dir:
306 label = source_params.get('label')
307 label_conf = "root=%s" % creator.rootdev
308 if label:
309 label_conf = "LABEL=%s" % label
310
311 bootloader = creator.ks.bootloader
312 cmdline = open("%s/cmdline" % tmp_dir, "w")
313 cmdline.write("%s %s" % (label_conf, bootloader.append))
314 cmdline.close()
315
316 initrds = initrd.split(';')
317 initrd = open("%s/initrd" % tmp_dir, "wb")
318 for f in initrds:
319 with open("%s/%s" % (deploy_dir, f), 'rb') as in_file:
320 shutil.copyfileobj(in_file, initrd)
321 initrd.close()
322
323 # Searched by systemd-boot:
324 # https://systemd.io/BOOT_LOADER_SPECIFICATION/#type-2-efi-unified-kernel-images
325 install_cmd = "install -d %s/EFI/Linux" % hdddir
326 exec_cmd(install_cmd)
327
328 staging_dir_host = get_bitbake_var("STAGING_DIR_HOST")
329
330 # https://www.freedesktop.org/software/systemd/man/systemd-stub.html
331 objcopy_cmd = "objcopy \
332 --add-section .osrel=%s --change-section-vma .osrel=0x20000 \
333 --add-section .cmdline=%s --change-section-vma .cmdline=0x30000 \
334 --add-section .linux=%s --change-section-vma .linux=0x2000000 \
335 --add-section .initrd=%s --change-section-vma .initrd=0x3000000 \
336 %s %s" % \
337 ("%s/usr/lib/os-release" % staging_dir_host,
338 cmdline.name,
339 "%s/%s" % (staging_kernel_dir, kernel),
340 initrd.name,
341 efi_stub,
342 "%s/EFI/Linux/linux.efi" % hdddir)
343 exec_cmd(objcopy_cmd)
344 else:
345 install_cmd = "install -m 0644 %s/%s %s/%s" % \
346 (staging_kernel_dir, kernel, hdddir, kernel)
347 exec_cmd(install_cmd)
294 348
295 if get_bitbake_var("IMAGE_EFI_BOOT_FILES"): 349 if get_bitbake_var("IMAGE_EFI_BOOT_FILES"):
296 for src_path, dst_path in cls.install_task: 350 for src_path, dst_path in cls.install_task: