summaryrefslogtreecommitdiffstats
path: root/scripts/lib/wic/plugins/source/bootimg-efi.py
diff options
context:
space:
mode:
Diffstat (limited to 'scripts/lib/wic/plugins/source/bootimg-efi.py')
-rw-r--r--scripts/lib/wic/plugins/source/bootimg-efi.py386
1 files changed, 305 insertions, 81 deletions
diff --git a/scripts/lib/wic/plugins/source/bootimg-efi.py b/scripts/lib/wic/plugins/source/bootimg-efi.py
index 8bc362254d..4b00913a70 100644
--- a/scripts/lib/wic/plugins/source/bootimg-efi.py
+++ b/scripts/lib/wic/plugins/source/bootimg-efi.py
@@ -1,21 +1,7 @@
-# ex:ts=4:sw=4:sts=4:et
-# -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*-
#
# Copyright (c) 2014, Intel Corporation.
-# All rights reserved.
#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License along
-# with this program; if not, write to the Free Software Foundation, Inc.,
-# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+# SPDX-License-Identifier: GPL-2.0-only
#
# DESCRIPTION
# This implements the 'bootimg-efi' source plugin class for 'wic'
@@ -24,25 +10,52 @@
# Tom Zanussi <tom.zanussi (at] linux.intel.com>
#
+import logging
import os
+import tempfile
import shutil
+import re
+
+from glob import glob
-from wic import msger
+from wic import WicError
+from wic.engine import get_custom_config
from wic.pluginbase import SourcePlugin
-from wic.utils.misc import get_custom_config
-from wic.utils.oe.misc import exec_cmd, exec_native_cmd, get_bitbake_var, \
- BOOTDD_EXTRA_SPACE
+from wic.misc import (exec_cmd, exec_native_cmd,
+ get_bitbake_var, BOOTDD_EXTRA_SPACE)
+
+logger = logging.getLogger('wic')
class BootimgEFIPlugin(SourcePlugin):
"""
Create EFI boot partition.
- This plugin supports GRUB 2 and gummiboot bootloaders.
+ This plugin supports GRUB 2 and systemd-boot bootloaders.
"""
name = 'bootimg-efi'
@classmethod
- def do_configure_grubefi(cls, hdddir, creator, cr_workdir):
+ def _copy_additional_files(cls, hdddir, initrd, dtb):
+ bootimg_dir = get_bitbake_var("DEPLOY_DIR_IMAGE")
+ if not bootimg_dir:
+ raise WicError("Couldn't find DEPLOY_DIR_IMAGE, exiting")
+
+ if initrd:
+ initrds = initrd.split(';')
+ for rd in initrds:
+ cp_cmd = "cp %s/%s %s" % (bootimg_dir, rd, hdddir)
+ exec_cmd(cp_cmd, True)
+ else:
+ logger.debug("Ignoring missing initrd")
+
+ if dtb:
+ if ';' in dtb:
+ raise WicError("Only one DTB supported, exiting")
+ cp_cmd = "cp %s/%s %s" % (bootimg_dir, dtb, hdddir)
+ exec_cmd(cp_cmd, True)
+
+ @classmethod
+ def do_configure_grubefi(cls, hdddir, creator, cr_workdir, source_params):
"""
Create loader-specific (grub-efi) config
"""
@@ -53,36 +66,62 @@ class BootimgEFIPlugin(SourcePlugin):
if custom_cfg:
# Use a custom configuration for grub
grubefi_conf = custom_cfg
- msger.debug("Using custom configuration file "
- "%s for grub.cfg" % configfile)
+ logger.debug("Using custom configuration file "
+ "%s for grub.cfg", configfile)
else:
- msger.error("configfile is specified but failed to "
- "get it from %s." % configfile)
+ raise WicError("configfile is specified but failed to "
+ "get it from %s." % configfile)
+
+ initrd = source_params.get('initrd')
+ dtb = source_params.get('dtb')
+
+ cls._copy_additional_files(hdddir, initrd, dtb)
if not custom_cfg:
# Create grub configuration using parameters from wks file
bootloader = creator.ks.bootloader
+ title = source_params.get('title')
grubefi_conf = ""
grubefi_conf += "serial --unit=0 --speed=115200 --word=8 --parity=no --stop=1\n"
grubefi_conf += "default=boot\n"
grubefi_conf += "timeout=%s\n" % bootloader.timeout
- grubefi_conf += "menuentry 'boot'{\n"
+ grubefi_conf += "menuentry '%s'{\n" % (title if title else "boot")
+
+ kernel = get_bitbake_var("KERNEL_IMAGETYPE")
+ if get_bitbake_var("INITRAMFS_IMAGE_BUNDLE") == "1":
+ if get_bitbake_var("INITRAMFS_IMAGE"):
+ kernel = "%s-%s.bin" % \
+ (get_bitbake_var("KERNEL_IMAGETYPE"), get_bitbake_var("INITRAMFS_LINK_NAME"))
- kernel = "/bzImage"
+ label = source_params.get('label')
+ label_conf = "root=%s" % creator.rootdev
+ if label:
+ label_conf = "LABEL=%s" % label
+
+ grubefi_conf += "linux /%s %s rootwait %s\n" \
+ % (kernel, label_conf, bootloader.append)
+
+ if initrd:
+ initrds = initrd.split(';')
+ grubefi_conf += "initrd"
+ for rd in initrds:
+ grubefi_conf += " /%s" % rd
+ grubefi_conf += "\n"
+
+ if dtb:
+ grubefi_conf += "devicetree /%s\n" % dtb
- grubefi_conf += "linux %s root=%s rootwait %s\n" \
- % (kernel, creator.rootdev, bootloader.append)
grubefi_conf += "}\n"
- msger.debug("Writing grubefi config %s/hdd/boot/EFI/BOOT/grub.cfg" \
- % cr_workdir)
+ logger.debug("Writing grubefi config %s/hdd/boot/EFI/BOOT/grub.cfg",
+ cr_workdir)
cfg = open("%s/hdd/boot/EFI/BOOT/grub.cfg" % cr_workdir, "w")
cfg.write(grubefi_conf)
cfg.close()
@classmethod
- def do_configure_gummiboot(cls, hdddir, creator, cr_workdir):
+ def do_configure_systemdboot(cls, hdddir, creator, cr_workdir, source_params):
"""
Create loader-specific systemd-boot/gummiboot config
"""
@@ -94,12 +133,21 @@ class BootimgEFIPlugin(SourcePlugin):
bootloader = creator.ks.bootloader
+ unified_image = source_params.get('create-unified-kernel-image') == "true"
+
loader_conf = ""
- loader_conf += "default boot\n"
+ if not unified_image:
+ loader_conf += "default boot\n"
loader_conf += "timeout %d\n" % bootloader.timeout
- msger.debug("Writing gummiboot config %s/hdd/boot/loader/loader.conf" \
- % cr_workdir)
+ initrd = source_params.get('initrd')
+ dtb = source_params.get('dtb')
+
+ if not unified_image:
+ cls._copy_additional_files(hdddir, initrd, dtb)
+
+ logger.debug("Writing systemd-boot config "
+ "%s/hdd/boot/loader/loader.conf", cr_workdir)
cfg = open("%s/hdd/boot/loader/loader.conf" % cr_workdir, "w")
cfg.write(loader_conf)
cfg.close()
@@ -109,29 +157,50 @@ class BootimgEFIPlugin(SourcePlugin):
if configfile:
custom_cfg = get_custom_config(configfile)
if custom_cfg:
- # Use a custom configuration for gummiboot
+ # Use a custom configuration for systemd-boot
boot_conf = custom_cfg
- msger.debug("Using custom configuration file "
- "%s for gummiboots's boot.conf" % configfile)
+ logger.debug("Using custom configuration file "
+ "%s for systemd-boots's boot.conf", configfile)
else:
- msger.error("configfile is specified but failed to "
- "get it from %s." % configfile)
+ raise WicError("configfile is specified but failed to "
+ "get it from %s.", configfile)
if not custom_cfg:
- # Create gummiboot configuration using parameters from wks file
- kernel = "/bzImage"
+ # Create systemd-boot configuration using parameters from wks file
+ kernel = get_bitbake_var("KERNEL_IMAGETYPE")
+ if get_bitbake_var("INITRAMFS_IMAGE_BUNDLE") == "1":
+ if get_bitbake_var("INITRAMFS_IMAGE"):
+ kernel = "%s-%s.bin" % \
+ (get_bitbake_var("KERNEL_IMAGETYPE"), get_bitbake_var("INITRAMFS_LINK_NAME"))
+
+ title = source_params.get('title')
boot_conf = ""
- boot_conf += "title boot\n"
- boot_conf += "linux %s\n" % kernel
- boot_conf += "options LABEL=Boot root=%s %s\n" % \
- (creator.rootdev, bootloader.append)
-
- msger.debug("Writing gummiboot config %s/hdd/boot/loader/entries/boot.conf" \
- % cr_workdir)
- cfg = open("%s/hdd/boot/loader/entries/boot.conf" % cr_workdir, "w")
- cfg.write(boot_conf)
- cfg.close()
+ boot_conf += "title %s\n" % (title if title else "boot")
+ boot_conf += "linux /%s\n" % kernel
+
+ label = source_params.get('label')
+ label_conf = "LABEL=Boot root=%s" % creator.rootdev
+ if label:
+ label_conf = "LABEL=%s" % label
+
+ boot_conf += "options %s %s\n" % \
+ (label_conf, bootloader.append)
+
+ if initrd:
+ initrds = initrd.split(';')
+ for rd in initrds:
+ boot_conf += "initrd /%s\n" % rd
+
+ if dtb:
+ boot_conf += "devicetree /%s\n" % dtb
+
+ if not unified_image:
+ logger.debug("Writing systemd-boot config "
+ "%s/hdd/boot/loader/entries/boot.conf", cr_workdir)
+ cfg = open("%s/hdd/boot/loader/entries/boot.conf" % cr_workdir, "w")
+ cfg.write(boot_conf)
+ cfg.close()
@classmethod
@@ -148,15 +217,67 @@ class BootimgEFIPlugin(SourcePlugin):
try:
if source_params['loader'] == 'grub-efi':
- cls.do_configure_grubefi(hdddir, creator, cr_workdir)
- elif source_params['loader'] == 'gummiboot' \
- or source_params['loader'] == 'systemd-boot':
- cls.do_configure_gummiboot(hdddir, creator, cr_workdir)
+ cls.do_configure_grubefi(hdddir, creator, cr_workdir, source_params)
+ elif source_params['loader'] == 'systemd-boot':
+ cls.do_configure_systemdboot(hdddir, creator, cr_workdir, source_params)
+ elif source_params['loader'] == 'uefi-kernel':
+ return
else:
- msger.error("unrecognized bootimg-efi loader: %s" % source_params['loader'])
+ raise WicError("unrecognized bootimg-efi loader: %s" % source_params['loader'])
except KeyError:
- msger.error("bootimg-efi requires a loader, none specified")
-
+ raise WicError("bootimg-efi requires a loader, none specified")
+
+ if get_bitbake_var("IMAGE_EFI_BOOT_FILES") is None:
+ logger.debug('No boot files defined in IMAGE_EFI_BOOT_FILES')
+ else:
+ boot_files = None
+ for (fmt, id) in (("_uuid-%s", part.uuid), ("_label-%s", part.label), (None, None)):
+ if fmt:
+ var = fmt % id
+ else:
+ var = ""
+
+ boot_files = get_bitbake_var("IMAGE_EFI_BOOT_FILES" + var)
+ if boot_files:
+ break
+
+ logger.debug('Boot files: %s', boot_files)
+
+ # list of tuples (src_name, dst_name)
+ deploy_files = []
+ for src_entry in re.findall(r'[\w;\-\./\*]+', boot_files):
+ if ';' in src_entry:
+ dst_entry = tuple(src_entry.split(';'))
+ if not dst_entry[0] or not dst_entry[1]:
+ raise WicError('Malformed boot file entry: %s' % src_entry)
+ else:
+ dst_entry = (src_entry, src_entry)
+
+ logger.debug('Destination entry: %r', dst_entry)
+ deploy_files.append(dst_entry)
+
+ cls.install_task = [];
+ for deploy_entry in deploy_files:
+ src, dst = deploy_entry
+ if '*' in src:
+ # by default install files under their basename
+ entry_name_fn = os.path.basename
+ if dst != src:
+ # unless a target name was given, then treat name
+ # as a directory and append a basename
+ entry_name_fn = lambda name: \
+ os.path.join(dst,
+ os.path.basename(name))
+
+ srcs = glob(os.path.join(kernel_dir, src))
+
+ logger.debug('Globbed sources: %s', ', '.join(srcs))
+ for entry in srcs:
+ src = os.path.relpath(entry, kernel_dir)
+ entry_dst_name = entry_name_fn(entry)
+ cls.install_task.append((src, entry_dst_name))
+ else:
+ cls.install_task.append((src, dst))
@classmethod
def do_prepare_partition(cls, part, source_params, creator, cr_workdir,
@@ -167,43 +288,143 @@ class BootimgEFIPlugin(SourcePlugin):
'prepares' the partition to be incorporated into the image.
In this case, prepare content for an EFI (grub) boot partition.
"""
- if not bootimg_dir:
- bootimg_dir = get_bitbake_var("HDDDIR")
- if not bootimg_dir:
- msger.error("Couldn't find HDDDIR, exiting\n")
- # just so the result notes display it
- creator.set_bootimg_dir(bootimg_dir)
+ if not kernel_dir:
+ kernel_dir = get_bitbake_var("DEPLOY_DIR_IMAGE")
+ if not kernel_dir:
+ raise WicError("Couldn't find DEPLOY_DIR_IMAGE, exiting")
staging_kernel_dir = kernel_dir
hdddir = "%s/hdd/boot" % cr_workdir
- install_cmd = "install -m 0644 %s/bzImage %s/bzImage" % \
- (staging_kernel_dir, hdddir)
- exec_cmd(install_cmd)
+ kernel = get_bitbake_var("KERNEL_IMAGETYPE")
+ if get_bitbake_var("INITRAMFS_IMAGE_BUNDLE") == "1":
+ if get_bitbake_var("INITRAMFS_IMAGE"):
+ kernel = "%s-%s.bin" % \
+ (get_bitbake_var("KERNEL_IMAGETYPE"), get_bitbake_var("INITRAMFS_LINK_NAME"))
+
+ if source_params.get('create-unified-kernel-image') == "true":
+ initrd = source_params.get('initrd')
+ if not initrd:
+ raise WicError("initrd= must be specified when create-unified-kernel-image=true, exiting")
+
+ deploy_dir = get_bitbake_var("DEPLOY_DIR_IMAGE")
+ efi_stub = glob("%s/%s" % (deploy_dir, "linux*.efi.stub"))
+ if len(efi_stub) == 0:
+ raise WicError("Unified Kernel Image EFI stub not found, exiting")
+ efi_stub = efi_stub[0]
+
+ with tempfile.TemporaryDirectory() as tmp_dir:
+ label = source_params.get('label')
+ label_conf = "root=%s" % creator.rootdev
+ if label:
+ label_conf = "LABEL=%s" % label
+
+ bootloader = creator.ks.bootloader
+ cmdline = open("%s/cmdline" % tmp_dir, "w")
+ cmdline.write("%s %s" % (label_conf, bootloader.append))
+ cmdline.close()
+
+ initrds = initrd.split(';')
+ initrd = open("%s/initrd" % tmp_dir, "wb")
+ for f in initrds:
+ with open("%s/%s" % (deploy_dir, f), 'rb') as in_file:
+ shutil.copyfileobj(in_file, initrd)
+ initrd.close()
+
+ dtb = source_params.get('dtb')
+ if dtb:
+ if ';' in dtb:
+ raise WicError("Only one DTB supported, exiting")
+ dtb_params = '--add-section .dtb=%s/%s --change-section-vma .dtb=0x40000' % \
+ (deploy_dir, dtb)
+ else:
+ dtb_params = ''
+
+ # Searched by systemd-boot:
+ # https://systemd.io/BOOT_LOADER_SPECIFICATION/#type-2-efi-unified-kernel-images
+ install_cmd = "install -d %s/EFI/Linux" % hdddir
+ exec_cmd(install_cmd)
+
+ staging_dir_host = get_bitbake_var("STAGING_DIR_HOST")
+ target_sys = get_bitbake_var("TARGET_SYS")
+
+ # https://www.freedesktop.org/software/systemd/man/systemd-stub.html
+ objcopy_cmd = "%s-objcopy" % target_sys
+ objcopy_cmd += " --add-section .osrel=%s/usr/lib/os-release" % staging_dir_host
+ objcopy_cmd += " --change-section-vma .osrel=0x20000"
+ objcopy_cmd += " --add-section .cmdline=%s" % cmdline.name
+ objcopy_cmd += " --change-section-vma .cmdline=0x30000"
+ objcopy_cmd += dtb_params
+ objcopy_cmd += " --add-section .linux=%s/%s" % (staging_kernel_dir, kernel)
+ objcopy_cmd += " --change-section-vma .linux=0x2000000"
+ objcopy_cmd += " --add-section .initrd=%s" % initrd.name
+ objcopy_cmd += " --change-section-vma .initrd=0x3000000"
+ objcopy_cmd += " %s %s/EFI/Linux/linux.efi" % (efi_stub, hdddir)
+ exec_native_cmd(objcopy_cmd, native_sysroot)
+ else:
+ install_cmd = "install -m 0644 %s/%s %s/%s" % \
+ (staging_kernel_dir, kernel, hdddir, kernel)
+ exec_cmd(install_cmd)
+
+ if get_bitbake_var("IMAGE_EFI_BOOT_FILES"):
+ for src_path, dst_path in cls.install_task:
+ install_cmd = "install -m 0644 -D %s %s" \
+ % (os.path.join(kernel_dir, src_path),
+ os.path.join(hdddir, dst_path))
+ exec_cmd(install_cmd)
try:
if source_params['loader'] == 'grub-efi':
shutil.copyfile("%s/hdd/boot/EFI/BOOT/grub.cfg" % cr_workdir,
"%s/grub.cfg" % cr_workdir)
- cp_cmd = "cp %s/EFI/BOOT/* %s/EFI/BOOT" % (bootimg_dir, hdddir)
- exec_cmd(cp_cmd, True)
+ for mod in [x for x in os.listdir(kernel_dir) if x.startswith("grub-efi-")]:
+ cp_cmd = "cp %s/%s %s/EFI/BOOT/%s" % (kernel_dir, mod, hdddir, mod[9:])
+ exec_cmd(cp_cmd, True)
shutil.move("%s/grub.cfg" % cr_workdir,
"%s/hdd/boot/EFI/BOOT/grub.cfg" % cr_workdir)
- elif source_params['loader'] == 'gummiboot' \
- or source_params['loader'] == 'systemd-boot':
- cp_cmd = "cp %s/EFI/BOOT/* %s/EFI/BOOT" % (bootimg_dir, hdddir)
- exec_cmd(cp_cmd, True)
+ elif source_params['loader'] == 'systemd-boot':
+ for mod in [x for x in os.listdir(kernel_dir) if x.startswith("systemd-")]:
+ cp_cmd = "cp %s/%s %s/EFI/BOOT/%s" % (kernel_dir, mod, hdddir, mod[8:])
+ exec_cmd(cp_cmd, True)
+ elif source_params['loader'] == 'uefi-kernel':
+ kernel = get_bitbake_var("KERNEL_IMAGETYPE")
+ if not kernel:
+ raise WicError("Empty KERNEL_IMAGETYPE %s\n" % target)
+ target = get_bitbake_var("TARGET_SYS")
+ if not target:
+ raise WicError("Unknown arch (TARGET_SYS) %s\n" % target)
+
+ if re.match("x86_64", target):
+ kernel_efi_image = "bootx64.efi"
+ elif re.match('i.86', target):
+ kernel_efi_image = "bootia32.efi"
+ elif re.match('aarch64', target):
+ kernel_efi_image = "bootaa64.efi"
+ elif re.match('arm', target):
+ kernel_efi_image = "bootarm.efi"
+ else:
+ raise WicError("UEFI stub kernel is incompatible with target %s" % target)
+
+ for mod in [x for x in os.listdir(kernel_dir) if x.startswith(kernel)]:
+ cp_cmd = "cp %s/%s %s/EFI/BOOT/%s" % (kernel_dir, mod, hdddir, kernel_efi_image)
+ exec_cmd(cp_cmd, True)
else:
- msger.error("unrecognized bootimg-efi loader: %s" % source_params['loader'])
+ raise WicError("unrecognized bootimg-efi loader: %s" %
+ source_params['loader'])
except KeyError:
- msger.error("bootimg-efi requires a loader, none specified")
+ raise WicError("bootimg-efi requires a loader, none specified")
- startup = os.path.join(bootimg_dir, "startup.nsh")
+ startup = os.path.join(kernel_dir, "startup.nsh")
if os.path.exists(startup):
cp_cmd = "cp %s %s/" % (startup, hdddir)
exec_cmd(cp_cmd, True)
+ for paths in part.include_path or []:
+ for path in paths:
+ cp_cmd = "cp -r %s %s/" % (path, hdddir)
+ exec_cmd(cp_cmd, True)
+
du_cmd = "du -bks %s" % hdddir
out = exec_cmd(du_cmd)
blocks = int(out.split()[0])
@@ -215,13 +436,16 @@ class BootimgEFIPlugin(SourcePlugin):
blocks += extra_blocks
- msger.debug("Added %d extra blocks to %s to get to %d total blocks" % \
- (extra_blocks, part.mountpoint, blocks))
+ logger.debug("Added %d extra blocks to %s to get to %d total blocks",
+ extra_blocks, part.mountpoint, blocks)
# dosfs image, created by mkdosfs
bootimg = "%s/boot.img" % cr_workdir
- dosfs_cmd = "mkdosfs -n efi -C %s %d" % (bootimg, blocks)
+ label = part.label if part.label else "ESP"
+
+ dosfs_cmd = "mkdosfs -n %s -i %s -C %s %d" % \
+ (label, part.fsuuid, bootimg, blocks)
exec_native_cmd(dosfs_cmd, native_sysroot)
mcopy_cmd = "mcopy -i %s -s %s/* ::/" % (bootimg, hdddir)
@@ -234,5 +458,5 @@ class BootimgEFIPlugin(SourcePlugin):
out = exec_cmd(du_cmd)
bootimg_size = out.split()[0]
- part.size = bootimg_size
+ part.size = int(bootimg_size)
part.source_file = bootimg