[meta-intel] [PATCH RFC 4/4] classes: Add uefi-comboapp bbclass
California Sullivan
california.l.sullivan at intel.com
Fri Jun 9 18:30:56 PDT 2017
This bbclass pulls in the portion of code that builds a UEFI combo
application from meta-refkit to meta-intel. The combo app contains an
EFI stub from systemd, which allows you to boot a kernel directly, a
kernel, an initramfs, and a command line.
This class is intended to be used as an EFI_PROVIDER or a target for
wic, and does not include the entire _dsk type image creation seen in
meta-refkit.
Signed-off-by: California Sullivan <california.l.sullivan at intel.com>
---
classes/uefi-comboapp.bbclass | 196 ++++++++++++++++++++++++++++++++++++++++++
1 file changed, 196 insertions(+)
create mode 100644 classes/uefi-comboapp.bbclass
diff --git a/classes/uefi-comboapp.bbclass b/classes/uefi-comboapp.bbclass
new file mode 100644
index 0000000..f0aced3
--- /dev/null
+++ b/classes/uefi-comboapp.bbclass
@@ -0,0 +1,196 @@
+# This class brings a more generic version of the UEFI combo app from refkit to meta-intel.
+# It uses a combo file, containing kernel, initramfs and
+# command line, presented to the BIOS as UEFI application, by prepending
+# it with the efi stub obtained from systemd-boot.
+# Needed to use native python libraries
+
+inherit pythonnative
+
+# Don't add syslinux or build an ISO
+PCBIOS_forcevariable = "0"
+NOISO_forcevariable = "1"
+
+# We use the initrd as the source of our initramfs
+INITRD_IMAGE ??= "core-image-minimal-initramfs"
+
+do_uefiapp[depends] += " \
+ systemd-boot:do_deploy \
+ virtual/kernel:do_deploy \
+ ${INITRD_IMAGE}:do_image_complete \
+ "
+
+# Always ensure that the INITRD_IMAGE gets added to the initramfs .cpio.
+# This needs to be done even when the actual .dsk image format is inactive,
+# because the .cpio file gets copied into the rootfs, and that rootfs
+# must be consistent regardless of the image format. This became relevant
+# when adding swupd bundle support, because there virtual images
+# without active .dsk are used to generate the rootfs for other
+# images with .dsk format.
+INITRD_LIVE_append = " ${@ ('${DEPLOY_DIR_IMAGE}/' + d.getVar('INITRD_IMAGE', expand=True) + '-${MACHINE}.cpio.gz') if d.getVar('INITRD_IMAGE', True) else ''}"
+
+PACKAGES = " "
+EXCLUDE_FROM_WORLD = "1"
+
+inherit deploy
+
+# UEFIAPP_BUILDERS variable is used to create one or more combo apps.
+# The following format is used: "UUID1;extra-cmdline1;suffix1 UUID2:extra-cmdline2:suffix2" and so on
+# The extra command line and suffix fields are not necessary, but without the suffix field a combo app may get overwritten
+# To reduce complication, the extra commandline section can currently only add one value
+UEFIAPP_BUILDERS ??= "${REMOVABLE_MEDIA_ROOTFS_PARTUUID_VALUE};;"
+
+# The image does without traditional bootloader.
+# In its place, instead, it uses a single UEFI executable binary, which is
+# composed by:
+# - an UEFI stub
+# The linux kernel can generate a UEFI stub, however the one from systemd-boot can fetch
+# the command line from a separate section of the EFI application, avoiding the need to
+# rebuild the kernel.
+# - the kernel
+# - the initramfs
+# There is a catch: all of these binary components must have the same word size as the BIOS:
+# either 32 or 64 bit.
+python do_uefiapp() {
+ import string, shutil, glob
+ from subprocess import check_call
+
+ uefiapp_partuuids = []
+ uefiapp_cmdlines = []
+ uefiapp_suffixes = []
+
+ uefiapp_buildstrings = d.getVar('UEFIAPP_BUILDERS', True)
+
+ if uefiapp_buildstrings is "":
+ bb.fatal("UEFIAPP_BUILDERS is empty")
+
+ for buildstring in uefiapp_buildstrings.split():
+ sections = buildstring.split(';')
+ if len(sections) < 3:
+ uefiapp_suffixes.append("")
+ else:
+ uefiapp_suffixes.append(sections[2])
+ if len(sections) < 2:
+ uefiapp_cmdlines.append("")
+ else:
+ uefiapp_cmdlines.append(sections[1])
+ uefiapp_partuuids.append(sections[0])
+
+ if os.path.exists(d.expand('${B}/initrd')):
+ os.remove(d.expand('${B}/initrd'))
+ # initrd is a concatenation of compressed cpio archives
+ # (initramfs, microcode, etc.)
+ with open(d.expand('${B}/initrd'), 'wb') as dst:
+ for cpio in d.getVar('INITRD_LIVE', True).split():
+ with open(cpio, 'rb') as src:
+ dst.write(src.read())
+ with open(d.expand('${B}/machine.txt'), 'w') as f:
+ f.write(d.expand('${MACHINE}'))
+ if '64' in d.getVar('MACHINE', True):
+ executable = 'bootx64.efi'
+ else:
+ executable = 'bootia32.efi'
+
+ def generate_app(partuuid, cmdline, suffix):
+ with open(d.expand('${B}/cmdline' + suffix + '.txt'), 'w') as f:
+ f.write(d.expand('${APPEND} root=PARTUUID=%s %s' % \
+ (partuuid, cmdline)))
+ check_call(d.expand('objcopy ' +
+ '--add-section .osrel=${B}/machine.txt ' +
+ '--change-section-vma .osrel=0x20000 ' +
+ '--add-section .cmdline=${B}/cmdline' + suffix + '.txt ' +
+ '--change-section-vma .cmdline=0x30000 ' +
+ '--add-section .linux=${DEPLOY_DIR_IMAGE}/bzImage ' +
+ '--change-section-vma .linux=0x40000 ' +
+ '--add-section .initrd=${B}/initrd ' +
+ '--change-section-vma .initrd=0x3000000 ' +
+ glob.glob(d.expand('${DEPLOY_DIR_IMAGE}/linux*.efi.stub'))[0] +
+ ' ${B}/' + executable + suffix
+ ).split())
+ if not os.path.exists(d.expand('${DEPLOYDIR}/EFI' + suffix + '/BOOT')):
+ os.makedirs(d.expand('${DEPLOYDIR}/EFI' + suffix + '/BOOT'))
+ shutil.copyfile(d.expand('${B}/' + executable + suffix), d.expand('${DEPLOYDIR}/EFI' + suffix + '/BOOT/' + executable))
+
+ for i in range(len(uefiapp_partuuids)):
+ generate_app(uefiapp_partuuids[i], uefiapp_cmdlines[i], uefiapp_suffixes[i])
+}
+
+DEPLOYDIR = "${WORKDIR}/uefiapp-${PN}"
+SSTATETASKS += "do_uefiapp"
+do_uefiapp[dirs] = "${DEPLOYDIR} ${B}"
+do_uefiapp[vardeps] += " APPEND UEFIAPP_BUILDERS"
+do_uefiapp[sstate-inputdirs] = "${DEPLOYDIR}"
+do_uefiapp[sstate-outputdirs] = "${DEPLOY_DIR_IMAGE}/${IMAGE_NAME}-uefiapp"
+
+addtask do_uefiapp before do_rootfs
+
+python do_uefiapp_setscene () {
+ sstate_setscene(d)
+}
+
+uefiapp_sign() {
+ if [ -f ${UEFIAPP_SIGNING_KEY} ] && [ -f ${UEFIAPP_SIGNING_CERT} ]; then
+ for i in `find ${DEPLOYDIR} -name '*.efi'`; do
+ sbsign --key ${UEFIAPP_SIGNING_KEY} --cert ${UEFIAPP_SIGNING_CERT} $i
+ sbverify --cert ${UEFIAPP_SIGNING_CERT} $i.signed
+ mv $i.signed $i
+ done
+ fi
+}
+
+uefiapp_deploy() {
+ # Let's make sure that only what is needed stays in the /boot dir
+ rm -rf ${IMAGE_ROOTFS}/boot/*
+ cp --preserve=timestamps -r ${DEPLOYDIR}/* ${IMAGE_ROOTFS}/boot/
+ chown -R root:root ${IMAGE_ROOTFS}/boot
+}
+
+addtask do_uefiapp_setscene
+
+# Re-run do_rootfs (and signing) if the key content changes. The name is irrelevant.
+# Also checks that the variables are set at parse time instead of failing during image building.
+do_rootfs[vardeps] += '${@bb.utils.contains('IMAGE_FEATURES','secureboot','UEFIAPP_SIGNING_CERT_HASH UEFIAPP_SIGNING_KEY_HASH','',d)}'
+python () {
+ import os
+ import hashlib
+
+ if bb.utils.contains('IMAGE_FEATURES', 'secureboot', True, False, d):
+ for varname in ('UEFIAPP_SIGNING_CERT', 'UEFIAPP_SIGNING_KEY'):
+ filename = d.getVar(varname)
+ if filename is None:
+ bb.fatal('%s is not set.' % varname)
+ if not os.path.isfile(filename):
+ bb.fatal('%s=%s is not a file.' % (varname, filename))
+ with open(filename, 'rb') as f:
+ data = f.read()
+ hash = hashlib.sha256(data).hexdigest()
+ d.setVar('%s_HASH' % varname, hash)
+
+ # Must reparse and thus rehash on file changes.
+ bb.parse.mark_dependency(d, filename)
+}
+
+do_rootfs[depends] += '${@bb.utils.contains('IMAGE_FEATURES','secureboot','sbsigntool-native:do_populate_sysroot','',d)}'
+
+efi_hddimg_populate() {
+ DEST=$1
+ cp --preserve=timestamps -r ${DEPLOYDIR}/* ${DEST}/
+}
+
+build_efi_cfg() {
+ # The command line is built into the combo app, so this is a null op
+ :
+}
+
+populate_kernel_append() {
+ # The kernel and initrd are built into the app, so we don't need these
+ if [ -f $dest/initrd ]; then
+ rm $dest/initrd
+ fi
+ if [ -f $dest/vmlinuz ]; then
+ rm $dest/vmlinuz
+ fi
+}
+
+IMAGE_FEATURES[validitems] += "secureboot"
+ROOTFS_POSTPROCESS_COMMAND += " ${@bb.utils.contains('IMAGE_FEATURES','secureboot','uefiapp_sign;','',d)} "
+ROOTFS_POSTPROCESS_COMMAND += " uefiapp_deploy; "
--
2.5.5
More information about the meta-intel
mailing list