diff --git a/documentation/boot/bootflow-generic.dot b/documentation/boot/bootflow-generic.dot deleted file mode 100644 index ffb9d22..0000000 --- a/documentation/boot/bootflow-generic.dot +++ /dev/null @@ -1,10 +0,0 @@ -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-generic.plantuml b/documentation/boot/bootflow-generic.plantuml new file mode 100644 index 0000000..b3d0a09 --- /dev/null +++ b/documentation/boot/bootflow-generic.plantuml @@ -0,0 +1,23 @@ +@startuml +!theme cloudscape-design +start +:**Firmware**; +note right + Implement a subset of the UEFI specification + Usually implemented by u-boot +end note +:**Bootloader** +efibootguard; +note right + The bootloader is responsible to find and load the Operating System + It's an UEFI application that can be signed +end note +:**Operating System** +Unified Kernel Image; +note right + The Operating System is a single UEFI application that can be signed + This application has to call the ExitBootService UEFI protocol + This application contains at least the Linux Kernel +end note +end +@enduml diff --git a/documentation/boot/bootflow-uboot.dot b/documentation/boot/bootflow-uboot.dot index 1e802a4..f6e2488 100644 --- a/documentation/boot/bootflow-uboot.dot +++ b/documentation/boot/bootflow-uboot.dot @@ -3,7 +3,7 @@ digraph G { uboot [label = "u-boot with EFI/EBBR support";shape = rect;]; - kernel [label = "OS (EFI Stub + Kernel + Initramfs";shape = rect;]; + kernel [label = "UKI (EFI Stub + Kernel + DTS + Initramfs";shape = rect;]; rom -> uboot -> kernel; } \ No newline at end of file diff --git a/documentation/boot/disk.rst b/documentation/boot/disk.rst new file mode 100644 index 0000000..bda605c --- /dev/null +++ b/documentation/boot/disk.rst @@ -0,0 +1,48 @@ +*********** +Disk Layout +*********** + +Standard Disk Layout +==================== + + + +Disk Layout using GPT +====================== + +Modern product use a GPT partionning disk with at least 5 partitions: + +- EFI +- PLATFORM0 +- PLATFORM1 +- BOOT0 +- BOOT1 + +Order and position of theses partitions doesn't matter as long as the +right partition label, partition label and filesystem are used. + +.. image:: disk/disk-layout.png + +Partitions +========== + +EFI +--- + +The EFI partition contains the bootloader (efibootguard). + +.. image:: disk/part-efi.png + +BOOT0 and BOOT1 +--------------- + +The BOOT0 and BOOT1 partition contains a kernel and a configuration files. + +.. image:: disk/part-boot0.png + +PLATFORM0 and PLATFORM1 +----------------------- + +The PLATFORM0 and PLATFORM1 partitions contains a Linux root filesystem. + +.. image:: disk/part-platform0.png diff --git a/documentation/boot/disk/disk-layout.png b/documentation/boot/disk/disk-layout.png new file mode 100644 index 0000000..d7731b6 Binary files /dev/null and b/documentation/boot/disk/disk-layout.png differ diff --git a/documentation/boot/disk/part-boot0.png b/documentation/boot/disk/part-boot0.png new file mode 100644 index 0000000..155373a Binary files /dev/null and b/documentation/boot/disk/part-boot0.png differ diff --git a/documentation/boot/disk/part-efi.png b/documentation/boot/disk/part-efi.png new file mode 100644 index 0000000..8f5f7c5 Binary files /dev/null and b/documentation/boot/disk/part-efi.png differ diff --git a/documentation/boot/disk/part-platform0.png b/documentation/boot/disk/part-platform0.png new file mode 100644 index 0000000..daa9f79 Binary files /dev/null and b/documentation/boot/disk/part-platform0.png differ diff --git a/documentation/boot/efibootguard.rst b/documentation/boot/efibootguard.rst new file mode 100644 index 0000000..073beb3 --- /dev/null +++ b/documentation/boot/efibootguard.rst @@ -0,0 +1,100 @@ +************************ +Bootloader: efibootguard +************************ + +Efibootguard is the default bootloader of CoreOS. It's an open source +bootloader based on UEFI made by Siemens and released under GPLv2, that +implement the A/B booting scheme. + +Efibootguard allow us to have a redondant boot partition that contain a +configuration file for efibootguard and a signed Unified Kernel Image + +A/B Switch +========== + +Two partition are used to store two diffrent configuration. The first partition +is called boot0 and the second one boot1. + +At boot, efibootguard find the configuration file stored inside each boot +partition and load it. Inside the configuration, the field "revision" is used +to select the configuration to use to boot the board. It will be the one +with the highest revision + +.. uml:: + + @startuml + !theme cloudscape-design + start + partition A/B selector { + + :read boot0 configuration; + :read boot1 configuration; + + if (boot0.revision > boot1.revision") then (yes) + :select boot0; + else (no) + :select boot1; + endif + } + + end + @enduml + +State checking +============== + +After having selecting the configuration to use, efibootguard will use the +state field to determine is the configuration is already know to work or not. + +Theses states are possible: + +- ok: the configuration is known to be working +- installed: the configuration was just updated and was never booted +- testing: the configuration was just updated and was already booted once +- failed: the configuration is not working + +.. uml:: + + @startuml + !theme cloudscape-design + start + partition state checking { + switch (state?) + case ( ok ) + :set state to ok; + case ( installed ) + :set state to testing; + case ( testing ) + :set state to failed; + :set revision to 0; + :reboot; + stop + case ( failed ) + :set revision to 0; + :reboot; + stop + endswitch + } + end + @enduml + +Image loading +============== + +The last part of the boot process just consist of reading kernel image +from the selected boot partition and then calling the load_image EFI function +to let the EFI firmware start the given image. The firmware will then first +check the signature of the kernel before starting it. + +.. uml:: + + @startuml + !theme cloudscape-design + start + partition kernel loading { + : read unified kernel image from boot partition; + : load image to memory; + } + : call EFI load_image(); + end + @enduml diff --git a/documentation/boot/index.rst b/documentation/boot/index.rst index 1eec9ba..2a934d2 100644 --- a/documentation/boot/index.rst +++ b/documentation/boot/index.rst @@ -11,3 +11,6 @@ Belden CoreOS Boot Concepts overview uboot + efibootguard + uki + disk \ No newline at end of file diff --git a/documentation/boot/overview.rst b/documentation/boot/overview.rst index 37720c5..38fbe48 100644 --- a/documentation/boot/overview.rst +++ b/documentation/boot/overview.rst @@ -13,8 +13,8 @@ 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 `. + Program that implement some of the boot and runtime services defined by + the :ext+uefi:ref:`UEFI specifications `. Application Program written according to the UEFI specification that can be started @@ -25,17 +25,26 @@ In this document, the following terms have specific meanings: configuration or autodetection. Operating system - Application that include at least the Linux Kernel and the initial RAM - disk. + Application that include at least the Linux Kernel. + + Unified Kernel Image + Application that include the Linux kernel and the command line to pass to + the kernel and optionaly one or more device trees and a RAM disk Generic Boot Flow ================= -.. graphviz:: bootflow-generic.dot +.. uml:: bootflow-generic.plantuml + +CoreOS use a standardized workflow based on UEFI: the firmware automatically +start the bootloader. The bootloader is stored inside the EFI partition, under: +`/EFI/BOOT/BOOT.EFI` where `` is: + +- ARM for Arm32 CPU +- A64 for Aarch64 CPU +- X64 for Amd64 CPU -CoreOS use a standardized workflow: the firmware can start either an -optional bootloader or an operating system as an UEFI application. Firmware ======== @@ -88,6 +97,7 @@ 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 @@ -105,38 +115,36 @@ 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. +CoreOS only support `efibootguard` as bootloader. Operating system ================ -The operating system image is an UEFI application that contain the kernel. We -support two method to create this image: +The operating system image is an UEFI application that contain the kernel. + +Two ways can be used to generate this application: + +Kernel built with the built-in EFI stub +--------------------------------------- + +This method use the EFI stub provided by the kernel. + 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. +`efibootguard/stub` and the image contains the Linux Kernel with it's built-in +EFI stub, the boot arguments of the kernel and optionaly multiple device trees +and an initial RAM disk. -This allows to have all these part authenticated via UEFI secure boot. +This allows to have all these part authenticated via UEFI secure boot just by +signing the UKI. -.. 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 +.. important:: -.. 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. + Only the Unified Kernel Image methods is supported by the CoreOS teams. Using + the kernel directly should be used only for new hardware bring-up. By default + we only sign UKI to ensure that it's the only method used for hardware that + ship with secure boot enabled. diff --git a/documentation/boot/uboot-dts-handling.dot b/documentation/boot/uboot-dts-handling.dot deleted file mode 100644 index 7718616..0000000 --- a/documentation/boot/uboot-dts-handling.dot +++ /dev/null @@ -1,16 +0,0 @@ -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 index 2189552..09c6841 100644 --- a/documentation/boot/uboot.rst +++ b/documentation/boot/uboot.rst @@ -1,6 +1,6 @@ -************************ -Using U-Boot as Firmware -************************ +**************** +Firmware: U-Boot +**************** U-boot can be configured to support the EBBR specification. This can be enabled by enabling both `CONFIG_EFI_LOADER` and @@ -21,13 +21,21 @@ to be changed at runtime. Device tree handling ==================== -As per the EBBR specification, the firmware is responsible to provide the +As per the EBBR specification, the firmware is responsible to provide a basic 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. +This means that we have to build u-boot with an embedded device tree. On a +machine configuration, this mean settings the `UBOOT_BUILDENV_DEVICE_TREE` +variables. + +The kernel can then override the built-in device-tree to use another. + +.. important:: + + The `compatible` field of the device-tree embedded inside `u-boot` has to + match with the one used inside the kernel. This allow us to automatically + load the right `device-tree` inside the unified kernel image (UKI). -.. graphviz:: uboot-dts-handling.dot Features to implement per machine ================================= @@ -35,73 +43,12 @@ 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. +An EFI application like a UKI can overwrite the built-in device tree with a +custom one. The DT Fixup Protocol allow an application to ask the firmware to +some runtime fix to the new device tree, like enabling or removing node. -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. +This can be used to pass dynamic information stored inside a "board descriptor" +eeprom or CPLD to the Kernel. diff --git a/documentation/boot/uki.rst b/documentation/boot/uki.rst new file mode 100644 index 0000000..4620a80 --- /dev/null +++ b/documentation/boot/uki.rst @@ -0,0 +1,4 @@ +****************************** +OS: Unified Kernel Image (UKI) +****************************** + diff --git a/documentation/conf.py b/documentation/conf.py index e6f0ecf..2b5e09e 100644 --- a/documentation/conf.py +++ b/documentation/conf.py @@ -42,8 +42,8 @@ extensions = [ 'sphinx.ext.intersphinx', 'sphinx.ext.todo', 'sphinx.ext.graphviz', + 'sphinxcontrib.plantuml', ] -# 'sphinxcontrib.plantuml', # external links and substitutions