diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..c5bbf3e --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,8 @@ +{ + "files.watcherExclude": { + "**/build/cache/**": true, + "**/build/downloads/**": true, + "**/build/sstate-cache/**": true, + "**/build/tmp/**": true + } +} \ No newline at end of file diff --git a/coreos-init-build-env b/coreos-init-build-env index e5db2f8..4c9762e 100755 --- a/coreos-init-build-env +++ b/coreos-init-build-env @@ -83,3 +83,7 @@ coreos_path_add "${COREOS_ROOT}/scripts" # Add support for ##COREOS_LAYERSDIR## inside of bblayer template coreos-bblayers-envsub COREOS_LAYERSDIR "${COREOS_ROOT}/layers" + +# Generate the ${BUILDDIR}/key directory. The scripts doesn't generate anything it +# the directory already exist, so it's safe to call it everytime +coreos-keygen > /dev/null 2> /dev/null diff --git a/documentation/boot/bootflow-generic.dot b/documentation/boot/bootflow-generic.dot new file mode 100644 index 0000000..ffb9d22 --- /dev/null +++ b/documentation/boot/bootflow-generic.dot @@ -0,0 +1,10 @@ +digraph G { + fw [label = "Firmware";shape = rect;]; + + btl [label = "Bootloader";shape = rect;]; + + os [label = "Operating System";shape = rect;]; + + fw -> btl -> os [style = dashed;]; + fw -> os; +} \ No newline at end of file diff --git a/documentation/boot/bootflow-uboot.dot b/documentation/boot/bootflow-uboot.dot new file mode 100644 index 0000000..1e802a4 --- /dev/null +++ b/documentation/boot/bootflow-uboot.dot @@ -0,0 +1,9 @@ +digraph G { + rom [label = "CPU Rom Code";shape = rect;]; + + uboot [label = "u-boot with EFI/EBBR support";shape = rect;]; + + kernel [label = "OS (EFI Stub + Kernel + Initramfs";shape = rect;]; + + rom -> uboot -> kernel; +} \ No newline at end of file diff --git a/documentation/boot/index.rst b/documentation/boot/index.rst new file mode 100644 index 0000000..1eec9ba --- /dev/null +++ b/documentation/boot/index.rst @@ -0,0 +1,13 @@ + +============================== +Belden CoreOS Boot Concepts +============================== + +| + +.. toctree:: + :caption: Table of Contents + :numbered: + + overview + uboot diff --git a/documentation/boot/overview.rst b/documentation/boot/overview.rst new file mode 100644 index 0000000..37720c5 --- /dev/null +++ b/documentation/boot/overview.rst @@ -0,0 +1,142 @@ +****************** +Boot Flow Overview +****************** + +To ease the support and developement of CoreOS on multiple plateform, +we use the same boot flow mechanisums on all our supported machine. + +Glossary +======== + +In this document, the following terms have specific meanings: + +.. glossary:: + + Firmware + Program that implement the boot and runtime services as defined by the + :ext+uefi:ref:`UEFI specifications `. + + Application + Program written according to the UEFI specification that can be started + by the firmware. See :ext:ref:`UEFI Applications `. + + Bootloader + Application that allow to start other application based on user selection, + configuration or autodetection. + + Operating system + Application that include at least the Linux Kernel and the initial RAM + disk. + + +Generic Boot Flow +================= + +.. graphviz:: bootflow-generic.dot + +CoreOS use a standardized workflow: the firmware can start either an +optional bootloader or an operating system as an UEFI application. + +Firmware +======== + +CoreOS support two different use case: + +Using a CoreOS provided firmware +-------------------------------- + +The most common use case is to use a firmware image provided by CoreOS as part +of the board support package. + +Currently, the CoreOS provided firmware functionality is provided by `u-boot` + +Using CoreOS on third party machine +----------------------------------- + +As the interface between the firmware and the rest of the system is clearly +defined, we also support to run CoreOS on top of any standard UEFI complient +system. + +As an example, this is the case when using a CoreOS image inside a virtual +machine. + +Firmware requirements +--------------------- + + +ARM32 / AArch32 based machine +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The firmware for ARM32 should implement a subset of the UEFI specification, as +defined by the EBBR Specification. As this architecure is used on old hardware, +it's ok to use the part of the specification that are marked as deprecated or +legacy like: + +- MBR partitionning instead of GPT +- Fixed offsets to firmware data + +We require the firmware to provide a DeviceTree based system description and not +an ACPI based table (as allowed by the specification) + +We also require the firmware to implement the UEFI Secure Boot functionality. + +ARM64 / AArch64 based machine +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The firmware for ARM64 should implement a subset of the UEFI specification, as +defined by the EBBR Specification. The part of the specification marked as +legacy or deprecated must not be used. + +This means: +- Only GPT partionning disk are supported +- No fixed offsets to firmware data + +We require the firmware to provide a DeviceTree based system description and not +an ACPI based table (as allowed by the specification) + +We also require the firmware to implement the UEFI Secure Boot functionality. + + +AMD64 / x86_64 based machine +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The firmware for AMD64 should implement the UEFI specification. + +Bootloader +========== + +CoreOS only support `systemd-boot` as bootloader. The usage of the bootloader +is optional. It's primary use case is for system that don't use a firmware +provided by CoreOS. + + +Operating system +================ + +The operating system image is an UEFI application that contain the kernel. We +support two method to create this image: + +Unified Kernel Images (UKI) +--------------------------- + +This is the most secure method. The UEFI entry point is provided by +`systemd-stub` and the image contains the Linux Kernel, the boot arguments of +the kernel, the os-release file and an initrd ram disk. + +This allows to have all these part authenticated via UEFI secure boot. + +.. warning:: + UKI are not supported for ARM32 target at the moment, due to a bug in objcopy. + See https://sourceware.org/bugzilla/show_bug.cgi?id=26218 + +.. note:: + UKI has the advantages to be discoverable by the bootloader without any + configuration file, and doesn't need a firmware that is able to set the + kernel command line. + +Kernel built with the built-in EFI sub +-------------------------------------- + +This method use the EFI stub provided by the kernel. The initramfs image has to +be bundled with the Kernel, using `INITRAMFS_IMAGE_BUNDLE`, as otherwise it +will not be authenticated by UEFI secure boot. diff --git a/documentation/boot/uboot-dts-handling.dot b/documentation/boot/uboot-dts-handling.dot new file mode 100644 index 0000000..7718616 --- /dev/null +++ b/documentation/boot/uboot-dts-handling.dot @@ -0,0 +1,16 @@ +digraph G { + start [label = "boot";]; + + mb [label = "Detect the main board name";shape = rect;]; + + mbdts [label = "Load main board device tree";shape = rect;]; + + ext [label = "Detect the extension module name";shape = rect;]; + extdts [label = "Load a device tree overlay for each module";shape = rect;]; + + dtsprocess [label = "Add and remove device tree node as needed (DT Fixup)";shape = rect;]; + + stop [label = "Start UEFI application";]; + + start -> mb -> mbdts -> ext -> extdts -> dtsprocess -> stop; +} \ No newline at end of file diff --git a/documentation/boot/uboot.rst b/documentation/boot/uboot.rst new file mode 100644 index 0000000..2189552 --- /dev/null +++ b/documentation/boot/uboot.rst @@ -0,0 +1,107 @@ +************************ +Using U-Boot as Firmware +************************ + +U-boot can be configured to support the EBBR specification. This can be +enabled by enabling both `CONFIG_EFI_LOADER` and +`CONFIG_EFI_EBBR_2_0_CONFORMANCE`. + +As UEFI Secure Boot is optional in EBBR, that has to be activated seperatly with +`CONFIG_EFI_SECURE_BOOT` + +.. graphviz:: bootflow-uboot.dot + +UEFI Secure Boot +================ + +CoreOS build system bundle all the needed public key for secure boot inside the +u-boot binary at buildtime. UEFI variables needed by secure boot are not allowed +to be changed at runtime. + +Device tree handling +==================== + +As per the EBBR specification, the firmware is responsible to provide the +device tree to the kernel. + +This means that loading the main device tree and all the device tree overlay are +is the responsibility of the firmware. + +.. graphviz:: uboot-dts-handling.dot + +Features to implement per machine +================================= + +The u-boot provided by CoreOS should implement the following features for each +supported machine: + +board_fit_config_name_match +---------------------------- + +This allows u-boot to select the device tree to use dynamically using board +detection. See `README.multi-dtb-fit` + + +extension_board_scan +-------------------- + +The extension_board_scan function has to be implemented. This function should +return the list of add-ons board detected, with the filename of the +correspondig device-tree overlay. + +DT Fixup +-------- + +U-Boot can create, modify and remove node from the device tree dynamically +before starting the kernel. This can be used to pass dynamic information stored +inside a "board descriptor" eeprom or CPLD to the Kernel. + +Custom Features that are generic +================================ + +The u-boot provided by CoreOS should implement the following custom features: + +File authentication +------------------- + +In order to be able to authenticate device tree, device-tree overlay file or +other file needed by the firmware, we need a command to authenticate a file that +was previously loaded is the `load` command. + +.. note:: + + My proposal is to use the UEFI Capsule format, to reuse theses function from + u-boot: + + - **efi_capsule_authenticate**: Authenticate the UEFI capsule using a x509 + certificate built into u-boot + - **efi_remove_auth_hdr**: Can be used to point a pointer to the start of the + content of an authenticated capsule. + + An UEFI Capsule is a generic container that can be signed using a x.509 + private key. The public key is stored inside u-boot (it's not the same as + the keys used for UEFI secure-boot). See + https://u-boot.readthedocs.io/en/v2022.10/develop/uefi/uefi.html?highlight=capsule#enabling-capsule-authentication + + +extension_overlay_cmd +--------------------- + +A custom command should be made for `extension_overlay_cmd`. The extension +subsystem use the command defined as extension_overlay_cmd to load +the overlay `${extension_overlay_name}` into `extension_overlay_addr` + +This should reuse the file authentication mechanismus. + +.. note:: + + A concept on where and how to securly store device tree and overlay needed + by the kernel has to be written. + + My proposal is to use the UEFI Capsule format, to reuse theses function from + u-boot: + + - **efi_capsule_authenticate**: Authenticate the UEFI capsule using a x509 + certificate built into u-boot + - **efi_remove_auth_hdr**: Can be used to point a pointer to the start of the + content of an authenticated capsule. diff --git a/documentation/conf.py b/documentation/conf.py index 3d55a21..e6f0ecf 100644 --- a/documentation/conf.py +++ b/documentation/conf.py @@ -41,7 +41,10 @@ extensions = [ 'sphinx.ext.extlinks', 'sphinx.ext.intersphinx', 'sphinx.ext.todo', + 'sphinx.ext.graphviz', ] +# 'sphinxcontrib.plantuml', + # external links and substitutions extlinks = { @@ -70,6 +73,8 @@ yocto_version = "4.0.4" intersphinx_mapping = { 'bitbake': ('https://docs.yoctoproject.org/bitbake/' + bitbake_version, None), 'yocto': ('https://docs.yoctoproject.org/' + yocto_version, None), + 'uefi': ('https://uefi.org/specs/UEFI/2.10/', None), + 'ebbr': ('https://arm-software.github.io/ebbr/', None), } # Add any paths that contain templates here, relative to this directory. diff --git a/documentation/index.rst b/documentation/index.rst index f8bec68..63f1771 100644 --- a/documentation/index.rst +++ b/documentation/index.rst @@ -29,6 +29,7 @@ same structures. :caption: Manuals Reference Manual + Boot Concepts .. toctree:: :maxdepth: 1 diff --git a/documentation/quick-build.rst b/documentation/quick-build.rst index ce729eb..904a233 100644 --- a/documentation/quick-build.rst +++ b/documentation/quick-build.rst @@ -46,7 +46,7 @@ Theses packages are needed on your build machine: chrpath socat cpio python3 python3-pip python3-pexpect xz-utils \ debianutils iputils-ping python3-git python3-jinja2 libegl1-mesa \ libsdl1.2-dev pylint3 xterm python3-subunit mesa-common-dev zstd \ - liblz4-tool bmap-tools + liblz4-tool bmap-tools efitools openssl sbsign Use Git to clone CoreOS ######################## diff --git a/documentation/ref-manual/classes.rst b/documentation/ref-manual/classes.rst index 9dc50a7..769f48d 100644 --- a/documentation/ref-manual/classes.rst +++ b/documentation/ref-manual/classes.rst @@ -6,6 +6,31 @@ This chapter document the classes that are provided by Belden CoreOS. Classes provided by OpenEmbedded-Core are documented in the :external:doc:`Yocto Reference Manual `. +.. _ref-classes-coreos-efi-secureboot: +.. index:: coreos-efi-secureboot.bbclass + + +``coreos-efi-secureboot.bbclass`` +================================= + +The ``coreos-efi-secureboot`` class is a class made to be ihnerited in a global +configuration file. On the CoreOS distribution, this class is inherited inside +the CoreOS distrubtion configuration file. + +This class define the location of the Secure Boot keys directory and regroup +in one file all settings that are related to both secure boot and the machine +configuration. + +.. _ref-classes-coreos-efi-sbsign: +.. index:: coreos-efi-sbsign.bbclass + +``coreos-efi-sbsign.bbclass`` +================================= + +The ``coreos-efi-sbsign`` class provide helpers functions to sign an EFI +application. + + .. _ref-classes-coreos-metadata-scm: .. index:: coreos_metadata_scm.bbclass diff --git a/documentation/ref-manual/variables.rst b/documentation/ref-manual/variables.rst index d65d5ba..a5fa16e 100644 --- a/documentation/ref-manual/variables.rst +++ b/documentation/ref-manual/variables.rst @@ -28,4 +28,27 @@ Variables provided by OpenEmbedded-Core are documented in the :term:`COREOS_METADATA_REVISION` The revision currently checked out for the CoreOS project (path - determined by :term:`COREOS_ROOT`). \ No newline at end of file + determined by :term:`COREOS_ROOT`). + + :term:`COREOS_EFI_SECUREBOOT__KEYDIR` + + Path to the directory containing the private and public key used for + signing and authenticating UEFI binary. + + The `coreos-init-buildenv` will automatically generate the keys in + `build/keys`. The default variables of `COREOS_EFI_SECUREBOOT__KEYDIR` + default to use this directory. + + :term:`COREOS_EFI_SECUREBOOT_INSTALL_PUBKEY_IN_EFIDIR` + + If the distro or the machine configuration ihnerit the + `coreos-efi-secureboot` class, settings this variables to `"1"` inside + the machine configuration will automatically install all the public key + needed for secure boot in the EFI partition. + + This is intended to be use when using CoreOS on machine that already + come with a built-in EFI compliant firmware, to ease the import of + the needed certificate into the firmware. + + For machine that use a CoreOS provided firmware (u-boot), the public key + are already shipped inside the firmware binary. diff --git a/layers/meta-belden-coreos-bsp/COPYING.MIT b/layers/meta-belden-coreos-bsp/COPYING.MIT new file mode 100644 index 0000000..fb950dc --- /dev/null +++ b/layers/meta-belden-coreos-bsp/COPYING.MIT @@ -0,0 +1,17 @@ +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/layers/meta-belden-coreos-bsp/classes/coreos-efi-sbsign.bbclass b/layers/meta-belden-coreos-bsp/classes/coreos-efi-sbsign.bbclass new file mode 100644 index 0000000..273d042 --- /dev/null +++ b/layers/meta-belden-coreos-bsp/classes/coreos-efi-sbsign.bbclass @@ -0,0 +1,12 @@ +# This class contains the part of coreos-efi-secureboot.bbclass that shouldn't +# be included globally, but only on the recipes that need to sign binary + +# Normaly, coreos-efi-secureboot should be ihnerited globally, but we +# ihnerit it again here to be sure that it's included +inherit coreos-efi-secureboot + +coreos_efi_secureboot_sign_app() { + # Helper function to sign an UEFI binary in place + sbsign --key "${COREOS_EFI_SECUREBOOT_KEYDIR}/db.key" --cert "${COREOS_EFI_SECUREBOOT_KEYDIR}/db.crt" "$1" --output "$1" +} + diff --git a/layers/meta-belden-coreos-bsp/classes/coreos-efi-secureboot.bbclass b/layers/meta-belden-coreos-bsp/classes/coreos-efi-secureboot.bbclass new file mode 100644 index 0000000..ce55994 --- /dev/null +++ b/layers/meta-belden-coreos-bsp/classes/coreos-efi-secureboot.bbclass @@ -0,0 +1,59 @@ +# This class is ihnerited globally in the CoreOS distro + +# UEFI Secure boot configuration +# ============================================================================== + +COREOS_EFI_SECUREBOOT_KEYDIR ??= "${TOPDIR}/keys" +COREOS_EFI_SECUREBOOT_INSTALL_PUBKEY_IN_EFIDIR ??= "0" + +# If a bootloader is used, it should be systemd-boot and not grub-efi as set +# in packagegroup-core-boot by default. +EFI_PROVIDER ?= "systemd-boot" + +# UEFI Secure boot helpers +# ============================================================================== + +# Image are signed with sbsign, but sbsign is not availabe in OE-Core, let's +# use from the host. This only work if this class is inherited in a global +# configuration file, like it's the case in the CoreOS distro +HOSTTOOLS += "sbsign" + +# Ensure that the public keys are always deployed to the deploy directory +# before running wic +do_image_wic[depends] += "efi-secureboot-keys:do_deploy" + + +def get_coreos_secureboot_efi_boot_files(d): + """ + Return the list of pubkey file inside deploy if + COREOS_EFI_SECUREBOOT_INSTALL_PUBKEY_IN_EFIDIR is set or an empty string + otherwise + """ + if d.getVar('COREOS_EFI_SECUREBOOT_INSTALL_PUBKEY_IN_EFIDIR', True): + return "db.auth KEK.auth PK.auth db.esl KEK.esl PK.esl db.crt KEK.crt PK.crt db.der KEK.der PK.der" + return "" + +IMAGE_EFI_BOOT_FILES:append = " ${@get_coreos_secureboot_efi_boot_files(d)}" + +def get_coreos_secureboot_keydir_hash(d): + """ + Generate a space separate list, with a value for each file inside of + keydir. Fromat: :md5: + """ + import hashlib + + keydir = d.getVar('COREOS_EFI_SECUREBOOT_KEYDIR') + value = "" + + for filepath in os.listdir(keydir): + if os.path.isfile(filepath): + md5 = bb.utils.md5_file(filepath) + value += f"{filepath}:md5:{md5} " + + return value + +# The build system should detect if someone change one of the key inside +# COREOS_EFI_SECUREBOOT_KEYDIR and rebuild all the recipes and artifacts that +# depends on this directory +COREOS_EFI_SECUREBOOT_KEYDIR_HASH = "${@get_coreos_secureboot_keydir_hash(d)}" +COREOS_EFI_SECUREBOOT_KEYDIR[vardeps] += "COREOS_EFI_SECUREBOOT_KEYDIR_HASH" diff --git a/layers/meta-belden-coreos-bsp/conf/machine/beaglebone.conf b/layers/meta-belden-coreos-bsp/conf/machine/beaglebone.conf new file mode 100644 index 0000000..aa5c135 --- /dev/null +++ b/layers/meta-belden-coreos-bsp/conf/machine/beaglebone.conf @@ -0,0 +1,56 @@ +#@TYPE: Machine +#@NAME: Beaglebone-yocto machine +#@DESCRIPTION: Reference machine configuration for http://beagleboard.org/bone and http://beagleboard.org/black boards + +MACHINE_EXTRA_RRECOMMENDS = "kernel-modules kernel-devicetree" +EXTRA_IMAGEDEPENDS += "virtual/bootloader" + +DEFAULTTUNE ?= "cortexa8hf-neon" +include conf/machine/include/arm/armv7a/tune-cortexa8.inc + +IMAGE_FSTYPES += "wic wic.xz wic.bmap" +WKS_FILE ?= "beaglebone.wks.in" +MACHINE_ESSENTIAL_EXTRA_RDEPENDS += "kernel-image kernel-devicetree" +do_image_wic[depends] += "mtools-native:do_populate_sysroot dosfstools-native:do_populate_sysroot gptfdisk-native:do_populate_sysroot virtual/bootloader:do_deploy" +do_image_wic[recrdeptask] += "do_bootimg" + +SERIAL_CONSOLES ?= "115200;ttyS0 115200;ttyO0 115200;ttyAMA0" +SERIAL_CONSOLES_CHECK = "${SERIAL_CONSOLES}" + +PREFERRED_PROVIDER_virtual/kernel ?= "linux-yocto" +PREFERRED_VERSION_linux-yocto ?= "5.15%" + +KERNEL_IMAGETYPE = "zImage" +KERNEL_DEVICETREE = "am335x-bone.dtb am335x-boneblack.dtb am335x-bonegreen.dtb" +KERNEL_EXTRA_ARGS += "LOADADDR=${UBOOT_ENTRYPOINT}" + +PREFERRED_PROVIDER_virtual/bootloader ?= "u-boot" + +SPL_BINARY = "MLO" +UBOOT_SUFFIX = "img" +UBOOT_MACHINE = "am335x_evm_defconfig" +UBOOT_ENTRYPOINT = "0x80008000" +UBOOT_LOADADDRESS = "0x80008000" + +MACHINE_FEATURES = "usbgadget usbhost vfat alsa efi" + +IMAGE_BOOT_FILES ?= "u-boot.${UBOOT_SUFFIX} ${SPL_BINARY}" +# ${KERNEL_IMAGETYPE} ${KERNEL_DEVICETREE} +IMAGE_EFI_BOOT_FILES ?= "${KERNEL_DEVICETREE}" + +# support runqemu +EXTRA_IMAGEDEPENDS += "qemu-native qemu-helper-native" +IMAGE_CLASSES += "qemuboot" +QB_DEFAULT_FSTYPE = "wic" +QB_FSINFO = "wic:no-kernel-in-fs" +QB_KERNEL_ROOT = "/dev/vda2" +QB_SYSTEM_NAME = "qemu-system-arm" +QB_MACHINE = "-machine virt" +QB_CPU = "-cpu cortex-a15" +QB_KERNEL_CMDLINE_APPEND = "console=ttyAMA0 systemd.mask=systemd-networkd" +QB_OPT_APPEND = "-device virtio-rng-device" +QB_TAP_OPT = "-netdev tap,id=net0,ifname=@TAP@,script=no,downscript=no" +QB_NETWORK_DEVICE = "-device virtio-net-device,netdev=net0,mac=@MAC@" +QB_ROOTFS_OPT = "-drive id=disk0,file=@ROOTFS@,if=none,format=raw -device virtio-blk-device,drive=disk0" +QB_SERIAL_OPT = "" +QB_TCPSERIAL_OPT = "-device virtio-serial-device -chardev socket,id=virtcon,port=@PORT@,host=127.0.0.1 -device virtconsole,chardev=virtcon" diff --git a/layers/meta-belden-coreos-bsp/conf/machine/include/pc-common.inc b/layers/meta-belden-coreos-bsp/conf/machine/include/pc-common.inc index 54840a6..2c5745e 100644 --- a/layers/meta-belden-coreos-bsp/conf/machine/include/pc-common.inc +++ b/layers/meta-belden-coreos-bsp/conf/machine/include/pc-common.inc @@ -8,9 +8,12 @@ PREFERRED_PROVIDER_virtual/kernel ?= "linux-yocto" MACHINE_EXTRA_RRECOMMENDS += "kernel-modules linux-firmware" -IMAGE_FSTYPES += "ext4 wic wic.bmap wic.vmdk iso" +IMAGE_FSTYPES += "ext4 wic wic.xz wic.bmap wic.vmdk iso" WKS_FILE ?= "generic-uefi.wks.in" -EFI_PROVIDER ?= "systemd-boot" do_image_wic[depends] += "gptfdisk-native:do_populate_sysroot" do_image_wic[recrdeptask] += "do_bootimg" + +# CoreOS Specific Machine settings +# ============================================================================== +COREOS_EFI_SECUREBOOT_INSTALL_PUBKEY_IN_EFIDIR = "1" \ No newline at end of file diff --git a/layers/meta-belden-coreos-bsp/recipes-bsp/efi/efi-secureboot-keys.bb b/layers/meta-belden-coreos-bsp/recipes-bsp/efi/efi-secureboot-keys.bb new file mode 100644 index 0000000..7cde776 --- /dev/null +++ b/layers/meta-belden-coreos-bsp/recipes-bsp/efi/efi-secureboot-keys.bb @@ -0,0 +1,33 @@ +SUMMARY = "A recipe to deploy UEFI public keys update files" +LICENSE = "CLOSED" + + +INHIBIT_DEFAULT_DEPS = "1" +inherit nopackages + +inherit deploy +inherit coreos-efi-secureboot + +# Public key needed by firmware very depending on the implementation +# So we copy all type of public key (*.auth, *.esl, *.crt, *der) +addtask deploy after do_compile +do_deploy() { + install -D -m 644 ${COREOS_EFI_SECUREBOOT_KEYDIR}/KEK.auth ${DEPLOYDIR}/KEK.auth + install -D -m 644 ${COREOS_EFI_SECUREBOOT_KEYDIR}/db.auth ${DEPLOYDIR}/db.auth + install -D -m 644 ${COREOS_EFI_SECUREBOOT_KEYDIR}/PK.auth ${DEPLOYDIR}/PK.auth + + install -D -m 644 ${COREOS_EFI_SECUREBOOT_KEYDIR}/KEK.esl ${DEPLOYDIR}/KEK.esl + install -D -m 644 ${COREOS_EFI_SECUREBOOT_KEYDIR}/db.esl ${DEPLOYDIR}/db.esl + install -D -m 644 ${COREOS_EFI_SECUREBOOT_KEYDIR}/PK.esl ${DEPLOYDIR}/PK.esl + + install -D -m 644 ${COREOS_EFI_SECUREBOOT_KEYDIR}/KEK.crt ${DEPLOYDIR}/KEK.crt + install -D -m 644 ${COREOS_EFI_SECUREBOOT_KEYDIR}/db.crt ${DEPLOYDIR}/db.crt + install -D -m 644 ${COREOS_EFI_SECUREBOOT_KEYDIR}/PK.crt ${DEPLOYDIR}/PK.crt + + install -D -m 644 ${COREOS_EFI_SECUREBOOT_KEYDIR}/KEK.der ${DEPLOYDIR}/KEK.der + install -D -m 644 ${COREOS_EFI_SECUREBOOT_KEYDIR}/db.der ${DEPLOYDIR}/db.der + install -D -m 644 ${COREOS_EFI_SECUREBOOT_KEYDIR}/PK.der ${DEPLOYDIR}/PK.der + + # !SECURITY WARNING! + # .key file are not copied to DEPLOYDIR, as they contains the PRIVATE keys +} \ No newline at end of file diff --git a/layers/meta-belden-coreos-bsp/recipes-bsp/u-boot/u-boot-coreos-efi.inc b/layers/meta-belden-coreos-bsp/recipes-bsp/u-boot/u-boot-coreos-efi.inc new file mode 100644 index 0000000..3356a1e --- /dev/null +++ b/layers/meta-belden-coreos-bsp/recipes-bsp/u-boot/u-boot-coreos-efi.inc @@ -0,0 +1,22 @@ +inherit coreos-efi-secureboot + +SRC_URI += " \ + file://uefi.cfg \ + file://uefi-secureboot.cfg \ +" + +DEPENDS:append = " ${PYTHON_PN}-pyopenssl-native" + +# Generate a ubootefi.var file inside the build directory +# This file can be directly linked inside the u-boot binary to provide +# a default value for variables. By default, we add the variables needed for +# secure boot +addtask uboot_generate_efivar after do_configure before do_compile +do_uboot_generate_efivar() { + # Settings OPENSSL_MODULES is needed, otherwise efivar.py fail with + # DSO support routines::could not load the shared library + export OPENSSL_MODULES="${STAGING_LIBDIR_NATIVE}/ossl-modules" + python3 ${S}/tools/efivar.py set -i ${S}/ubootefi.var -n db -d ${COREOS_EFI_SECUREBOOT_KEYDIR}/db.esl -t file -a nv,bs,rt,at + python3 ${S}/tools/efivar.py set -i ${S}/ubootefi.var -n KEK -d ${COREOS_EFI_SECUREBOOT_KEYDIR}/KEK.esl -t file -a nv,bs,rt,at + python3 ${S}/tools/efivar.py set -i ${S}/ubootefi.var -n PK -d ${COREOS_EFI_SECUREBOOT_KEYDIR}/PK.esl -t file -a nv,bs,rt,at +} diff --git a/layers/meta-belden-coreos-bsp/recipes-bsp/u-boot/u-boot-coreos.inc b/layers/meta-belden-coreos-bsp/recipes-bsp/u-boot/u-boot-coreos.inc new file mode 100644 index 0000000..3e6ec36 --- /dev/null +++ b/layers/meta-belden-coreos-bsp/recipes-bsp/u-boot/u-boot-coreos.inc @@ -0,0 +1,8 @@ +# Main include file for u-boot to ensure CoreOS compatibility +# ============================================================================== + +SRC_URI += " \ + ${@bb.utils.contains("IMAGE_FEATURES", "debug-tweaks", "file://debug-tweaks.cfg", "", d)} \ +" + +require u-boot-coreos-efi.inc diff --git a/layers/meta-belden-coreos-bsp/recipes-bsp/u-boot/u-boot/debug-tweaks.cfg b/layers/meta-belden-coreos-bsp/recipes-bsp/u-boot/u-boot/debug-tweaks.cfg new file mode 100644 index 0000000..4e7ed3a --- /dev/null +++ b/layers/meta-belden-coreos-bsp/recipes-bsp/u-boot/u-boot/debug-tweaks.cfg @@ -0,0 +1,4 @@ +CONFIG_CMD_LOG=y +CONFIG_LOG_MAX_LEVEL=9 +CONFIG_LOG_DEFAULT_LEVEL=7 +CONFIG_CMD_BOOTEFI_SELFTEST=y \ No newline at end of file diff --git a/layers/meta-belden-coreos-bsp/recipes-bsp/u-boot/u-boot/uefi-secureboot.cfg b/layers/meta-belden-coreos-bsp/recipes-bsp/u-boot/u-boot/uefi-secureboot.cfg new file mode 100644 index 0000000..9641cde --- /dev/null +++ b/layers/meta-belden-coreos-bsp/recipes-bsp/u-boot/u-boot/uefi-secureboot.cfg @@ -0,0 +1,3 @@ +CONFIG_FIT_SIGNATURE=y +CONFIG_LEGACY_IMAGE_FORMAT=y +CONFIG_EFI_SECURE_BOOT=y \ No newline at end of file diff --git a/layers/meta-belden-coreos-bsp/recipes-bsp/u-boot/u-boot/uefi.cfg b/layers/meta-belden-coreos-bsp/recipes-bsp/u-boot/u-boot/uefi.cfg new file mode 100644 index 0000000..07bd100 --- /dev/null +++ b/layers/meta-belden-coreos-bsp/recipes-bsp/u-boot/u-boot/uefi.cfg @@ -0,0 +1,5 @@ +CONFIG_CMD_BOOTMENU=y +CONFIG_CMD_NVEDIT_EFI=y +CONFIG_CMD_EFIDEBUG=y +CONFIG_EFI_MEDIA=y +CONFIG_EFI_VARIABLES_PRESEED=y diff --git a/layers/meta-belden-coreos-bsp/recipes-bsp/u-boot/u-boot_2022.01.bbappend b/layers/meta-belden-coreos-bsp/recipes-bsp/u-boot/u-boot_2022.01.bbappend new file mode 100644 index 0000000..49e2351 --- /dev/null +++ b/layers/meta-belden-coreos-bsp/recipes-bsp/u-boot/u-boot_2022.01.bbappend @@ -0,0 +1,2 @@ +FILESEXTRAPATHS:prepend := "${THISDIR}/${PN}:" +require u-boot-coreos.inc diff --git a/layers/meta-belden-coreos-bsp/recipes-bsp/u-boot/u-boot_2022.10.bb b/layers/meta-belden-coreos-bsp/recipes-bsp/u-boot/u-boot_2022.10.bb new file mode 100644 index 0000000..5ae4b92 --- /dev/null +++ b/layers/meta-belden-coreos-bsp/recipes-bsp/u-boot/u-boot_2022.10.bb @@ -0,0 +1,8 @@ +require recipes-bsp/u-boot/u-boot-common.inc +require recipes-bsp/u-boot/u-boot.inc + +SRCREV = "4debc57a3da6c3f4d3f89a637e99206f4cea0a96" +DEPENDS += "bc-native dtc-native python3-setuptools-native" +LIC_FILES_CHKSUM = "file://Licenses/README;md5=2ca5f2c35c8cc335f0a19756634782f1" + +require u-boot-coreos.inc diff --git a/layers/meta-belden-coreos-bsp/recipes-core/systemd/systemd-boot_250.5.bbappend b/layers/meta-belden-coreos-bsp/recipes-core/systemd/systemd-boot_250.5.bbappend new file mode 100644 index 0000000..e2ee09e --- /dev/null +++ b/layers/meta-belden-coreos-bsp/recipes-core/systemd/systemd-boot_250.5.bbappend @@ -0,0 +1,11 @@ +# Add signature support + +inherit coreos-efi-sbsign + +do_install:append() { + coreos_efi_secureboot_sign_app "${D}${EFI_FILES_PATH}/${SYSTEMD_BOOT_IMAGE}" +} + +do_deploy:append() { + coreos_efi_secureboot_sign_app ${DEPLOYDIR}/systemd-${SYSTEMD_BOOT_IMAGE} +} \ No newline at end of file diff --git a/layers/meta-belden-coreos-bsp/recipes-kernel/linux/linux-yocto-coreos-efi.inc b/layers/meta-belden-coreos-bsp/recipes-kernel/linux/linux-yocto-coreos-efi.inc new file mode 100644 index 0000000..bd0132e --- /dev/null +++ b/layers/meta-belden-coreos-bsp/recipes-kernel/linux/linux-yocto-coreos-efi.inc @@ -0,0 +1,14 @@ + +inherit coreos-efi-sbsign + +# Ensure EFI STUB is enabled +KERNEL_FEATURES:append = " cfg/efi.scc cfg/efi-ext.scc" + +# Extend the kernel_do_deploy function from kernel.bbclass to sign the kernel +kernel_do_deploy:append() { + deployDir="${DEPLOYDIR}" + for imageType in ${KERNEL_IMAGETYPES} ; do + baseName=$imageType-${KERNEL_IMAGE_NAME} + coreos_efi_secureboot_sign_app $deployDir/$baseName${KERNEL_IMAGE_BIN_EXT} + done +} diff --git a/layers/meta-belden-coreos-bsp/recipes-kernel/linux/linux-yocto_5.15.bbappend b/layers/meta-belden-coreos-bsp/recipes-kernel/linux/linux-yocto_5.15.bbappend index ac23e17..440300d 100644 --- a/layers/meta-belden-coreos-bsp/recipes-kernel/linux/linux-yocto_5.15.bbappend +++ b/layers/meta-belden-coreos-bsp/recipes-kernel/linux/linux-yocto_5.15.bbappend @@ -3,3 +3,11 @@ COMPATIBLE_MACHINE:pc-x64 = "pc-x64" # Enable some kernel features related to virtualiuzation KERNEL_FEATURES:append:pc-x64=" cfg/virtio.scc cfg/paravirt_kvm.scc" + +KBRANCH:beaglebone = "v5.15/standard/beaglebone" +KMACHINE:beaglebone ?= "beaglebone" +SRCREV_machine:beaglebone ?= "9aabbaa89fcb21af7028e814c1f5b61171314d5a" +COMPATIBLE_MACHINE:beaglebone = "beaglebone" +LINUX_VERSION:beaglebone = "5.15.54" + +require linux-yocto-coreos-efi.inc diff --git a/layers/meta-belden-coreos-bsp/wic/beaglebone.wks.in b/layers/meta-belden-coreos-bsp/wic/beaglebone.wks.in new file mode 100644 index 0000000..9183034 --- /dev/null +++ b/layers/meta-belden-coreos-bsp/wic/beaglebone.wks.in @@ -0,0 +1,10 @@ +# short-description: Create SD card image for Beaglebone +# long-description: Creates a partitioned SD card image for Beaglebone. +# Boot files are located in the first vfat partition. + +# --sourceparams="loader=u-boot" +part /boot/uboot --source bootimg-partition --ondisk mmcblk0 --fstype=vfat --label boot --active --align 4 --fixed-size 32 +part /boot --source bootimg-efi --ondisk mmcblk0 --sourceparams="loader=${EFI_PROVIDER}" --align 1024 --system-id 0xef +#part /boot --source bootimg-efi --ondisk mmcblk0 --sourceparams="loader=uefi-kernel" --align 1024 --system-id 0xef +part / --source rootfs --ondisk mmcblk0 --fstype=ext4 --label root --align 4 +bootloader --timeout=5 --append="rootfstype=ext4 console=ttyS0,115200 rootwait" diff --git a/layers/meta-belden-coreos/classes/coreos-image.bbclass b/layers/meta-belden-coreos/classes/coreos-image.bbclass index 5d33ae7..82a8b45 100644 --- a/layers/meta-belden-coreos/classes/coreos-image.bbclass +++ b/layers/meta-belden-coreos/classes/coreos-image.bbclass @@ -33,6 +33,9 @@ COREOS_IMAGE_BASE_INSTALL = '\ packagegroup-core-boot \ packagegroup-base-extended \ \ + efibootmgr \ + efivar \ + os-release \ ${COREOS_IMAGE_EXTRA_INSTALL} \ ' diff --git a/layers/meta-belden-coreos/classes/coreos-sanity.bbclass b/layers/meta-belden-coreos/classes/coreos-sanity.bbclass index 894e7b8..4903c9c 100644 --- a/layers/meta-belden-coreos/classes/coreos-sanity.bbclass +++ b/layers/meta-belden-coreos/classes/coreos-sanity.bbclass @@ -1,6 +1,10 @@ # This class add some sanity checks to ensure that distribution based on # CoreOS only use the subset of openembedded-core that is supported by the # CoreOS team. +# +# This is also used to add some warnings to ensure to ensure a more common +# CoreOS developer Experience, by ensuring that some default distro and machine +# are set correctly SANITY_COREOS_COMPATIBLE ??= "0" @@ -9,6 +13,9 @@ addhandler check_coreos_sanity_eventhandler check_coreos_sanity_eventhandler[eventmask] = "bb.event.SanityCheck" python check_coreos_sanity_eventhandler() { + # Checks related to the distribution configuration files + # ========================================================================== + if e.data.getVar('SANITY_COREOS_COMPATIBLE') != "1": bb.fatal( "The CoreOS layer is only compatible with distribution based on " @@ -28,6 +35,24 @@ python check_coreos_sanity_eventhandler() { "glibc is not set as `TCLIBC`. " "Using glibc is mandatory on CoreOS based distribution" ) + + # Checks related to the machine configuration files + # ========================================================================== + + # Ensure that compressed image and bmap file are generated if wic is used + fs_types = e.data.getVar("IMAGE_FSTYPES").split() + if any(map(lambda x: x.startswith("wic"), fs_types)): + if not "wic.xz" in fs_types: + bb.warn( + "CoreOS recommands to use compressed wic image, please add " + "`wic.xz` to your machine `IMAGE_FSTYPES` variables" + ) + + if not "wic.bmap": + bb.warn( + "wic image should be flashed with bmaptools, but this require " + "to add `wic.bmap` to your machine `IMAGE_FSTYPES` variables" + ) return } diff --git a/layers/meta-belden-coreos/conf/distro/belden-coreos.conf b/layers/meta-belden-coreos/conf/distro/belden-coreos.conf index 2e1930e..ad4e696 100644 --- a/layers/meta-belden-coreos/conf/distro/belden-coreos.conf +++ b/layers/meta-belden-coreos/conf/distro/belden-coreos.conf @@ -13,7 +13,7 @@ DISTRO_CODENAME = "kirkstone" PACKAGE_CLASSES = "package_ipk" INIT_MANAGER = "systemd" -DISTRO_FEATURES_DEFAULT ?= "bluetooth usbhost pci ipv4 ipv6 wifi multiarch usrmerge ptest" +DISTRO_FEATURES_DEFAULT ?= "bluetooth usbhost pci ipv4 ipv6 wifi multiarch usrmerge ptest efi" DISTRO_FEATURES ?= "${DISTRO_FEATURES_DEFAULT}" DISTRO_FEATURES_BACKFILL_CONSIDERED = "pulseaudio gobject-introspection-data ldconfig" DISTRO_EXTRA_RDEPENDS += "packagegroup-core-boot" @@ -57,3 +57,8 @@ SDK_VERSION = "${DISTRO_VERSION}" SDK_VERSION[vardepvalue] = "${SDK_VERSION}" SDK_NAME = "${DISTRO}-${TCLIBC}-${SDKMACHINE}-${IMAGE_BASENAME}-${TUNE_PKGARCH}-${MACHINE}" SDKPATHINSTALL = "/opt/${DISTRO}/${SDK_VERSION}" + +# Secure boot +# ============================================================================== + +INHERIT += "coreos-efi-secureboot" diff --git a/layers/meta-belden-coreos/recipes-core/meta/wic-tools.bbappend b/layers/meta-belden-coreos/recipes-core/meta/wic-tools.bbappend new file mode 100644 index 0000000..b2634eb --- /dev/null +++ b/layers/meta-belden-coreos/recipes-core/meta/wic-tools.bbappend @@ -0,0 +1 @@ +DEPENDS:append:arm = " grub-efi systemd-boot" diff --git a/layers/meta-belden-coreos/recipes-core/systemd/systemd_250.5.bbappend b/layers/meta-belden-coreos/recipes-core/systemd/systemd_250.5.bbappend new file mode 100644 index 0000000..056448e --- /dev/null +++ b/layers/meta-belden-coreos/recipes-core/systemd/systemd_250.5.bbappend @@ -0,0 +1,17 @@ + +# Compile and install the bootctl command by default +#=============================================================================== + +# bootctl command is only built if the gnu-efi feature is enables +PACKAGECONFIG:append = " ${@bb.utils.contains('DISTRO_FEATURES', 'efi', 'gnu-efi', '', d)}" + +# Enabling gnu-efi does create stub file inside /usr/lib/systemd/boot/efi/ +# this generate some QA errors: +# ERROR: systemd-1_250.5-r0 do_package_qa: QA Issue: +# File /usr/lib/systemd/boot/efi/linuxarm.elf.stub in package systemd doesn't +# have GNU_HASH (didn't pass LDFLAGS?) [ldflags] +# +# Theses files are already by the systemd-boot recipes, so we can delete them +do_install:append() { + rm -r ${D}/${libdir}/systemd/boot +} diff --git a/layers/meta-belden-coreos/recipes-devtool/core-os/coreos-doc.bb b/layers/meta-belden-coreos/recipes-devtool/core-os/coreos-doc.bb index 44cb05a..46500e1 100644 --- a/layers/meta-belden-coreos/recipes-devtool/core-os/coreos-doc.bb +++ b/layers/meta-belden-coreos/recipes-devtool/core-os/coreos-doc.bb @@ -3,11 +3,24 @@ SECTION = "devtool" LICENSE = "CLOSED" PV = "0.0.1+git${METADATA_REVISION}" +# The documentation is embedded inside the CoreOS repository structure, so we +# use externsrc to built it inherit externalsrc +EXTERNALSRC := "${COREOS_ROOT}/documentation" + +# This recipe only produce an HTML output, so we need to tell bitbake that it's +# doesn't depends on the target architecture inherit allarch -EXTERNALSRC := "${COREOS_ROOT}/documentation" -DEPENDS += "python3-sphinx python3-sphinx-rtd-theme" +# By default bitbake has the host native python3 in the path, not the one built +# by bitbake, but we can change that by ihneriting python3native +inherit python3native + +# This recipes doesn't need a compiler, so we prevent the base.bbclass to add +# the default set of deps by settings the following variable to 1: +INHIBIT_DEFAULT_DEPS = "1" + +DEPENDS += "python3-sphinx-native python3-sphinx-rtd-theme-native" do_compile() { python3 -m sphinx.cmd.build -b html ${S} ${B} diff --git a/scripts/coreos-doc b/scripts/coreos-doc index 632d701..3f0ac97 100755 --- a/scripts/coreos-doc +++ b/scripts/coreos-doc @@ -1,4 +1,4 @@ #!/usr/bin/env sh -bitbake coreos-doc -xdg-open ${BBPATH}/tmp/deploy/documentation/index.html \ No newline at end of file +bitbake coreos-doc +xdg-open ${BBPATH}/tmp/deploy/documentation/index.html diff --git a/scripts/coreos-keygen b/scripts/coreos-keygen new file mode 100755 index 0000000..b269e3f --- /dev/null +++ b/scripts/coreos-keygen @@ -0,0 +1,53 @@ +#!/usr/bin/env bash + +if [ -z "$BUILDDIR" ]; then + echo "BUILDDIR is not defined" + exit 1 +fi + +KEYDIR="${BUILDDIR}/keys" + +if [ -d "${KEYDIR}" ]; then + echo "${KEYDIR} directory already is exist" + echo "Skipping generating keys" + exit 1 +fi + +mkdir "${KEYDIR}" +cd "${KEYDIR}" + +echo "Generating private/public keys in .key/.crt format for PK, KEK et db" + +openssl req -x509 -sha256 -newkey rsa:2048 -subj /CN=TEST_PK/ \ + -keyout PK.key -out PK.crt -nodes -days 365 + +openssl req -x509 -sha256 -newkey rsa:2048 -subj /CN=TEST_KEK/ \ + -keyout KEK.key -out KEK.crt -nodes -days 365 + +openssl req -x509 -sha256 -newkey rsa:2048 -subj /CN=TEST_db/ \ + -keyout db.key -out db.crt -nodes -days 365 + + +echo "Generatic EFI signature list file with PK, KEK et db public key" + +cert-to-efi-sig-list -g 11111111-2222-3333-4444-123456789abc \ + PK.crt PK.esl; + +cert-to-efi-sig-list -g 11111111-2222-3333-4444-123456789abc \ + KEK.crt KEK.esl + +cert-to-efi-sig-list -g 11111111-2222-3333-4444-123456789abc \ + db.crt db.esl + +echo "Generatic EFI AUTH file with PK, KEK et db public key" + +sign-efi-sig-list -c PK.crt -k PK.key PK PK.esl PK.auth +sign-efi-sig-list -c PK.crt -k PK.key KEK KEK.esl KEK.auth +sign-efi-sig-list -c KEK.crt -k KEK.key db db.esl db.auth + +echo "Generatic DER files with PK, KEK et db public key" + +# der certificate are need for OVMF based firmware (virtual machine) +openssl x509 -in PK.crt -outform der -out PK.der +openssl x509 -in KEK.crt -outform der -out KEK.der +openssl x509 -in db.crt -outform der -out db.der