doc(bootflow): adapt bootflow doc to efibootguard and swupdate

This commit is contained in:
Samuel Dolt 2023-01-25 14:11:02 +01:00
parent f275e7e499
commit 162c0098b8
15 changed files with 237 additions and 130 deletions

View File

@ -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;
}

View File

@ -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

View File

@ -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;
}

View File

@ -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

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

View File

@ -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

View File

@ -11,3 +11,6 @@ Belden CoreOS Boot Concepts
overview
uboot
efibootguard
uki
disk

View File

@ -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 <maincontent>`.
Program that implement some of the boot and runtime services defined by
the :ext+uefi:ref:`UEFI specifications <maincontent>`.
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<ARCH>.EFI` where `<ARCH>` 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.

View File

@ -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;
}

View File

@ -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.

View File

@ -0,0 +1,4 @@
******************************
OS: Unified Kernel Image (UKI)
******************************

View File

@ -42,8 +42,8 @@ extensions = [
'sphinx.ext.intersphinx',
'sphinx.ext.todo',
'sphinx.ext.graphviz',
'sphinxcontrib.plantuml',
]
# 'sphinxcontrib.plantuml',
# external links and substitutions