diff --git a/man/systemd-measure.xml b/man/systemd-measure.xml
index 1707e0c7f3..8ea667426e 100644
--- a/man/systemd-measure.xml
+++ b/man/systemd-measure.xml
@@ -75,9 +75,9 @@
Pre-calculate the expected values seen in PCR register 11 after boot-up of a unified
kernel image consisting of the components specified with ,
, , ,
- , , ,
- , see below. Only is
- mandatory. (Alternatively, specify to use the current values of PCR
+ , , ,
+ , , see below.
+ Only is mandatory. (Alternatively, specify to use the current values of PCR
register 11 instead.)
@@ -118,6 +118,7 @@
+
diff --git a/man/systemd-stub.xml b/man/systemd-stub.xml
index 6a65ac33f8..e7e8a42a6d 100644
--- a/man/systemd-stub.xml
+++ b/man/systemd-stub.xml
@@ -70,6 +70,9 @@
An .initrd section with the initrd.
+ A .ucode section with an initrd containing microcode, to be handed
+ to the kernel before any other initrd. This initrd must not be compressed.
+
A .splash section with an image (in the Windows
.BMP format) to show on screen before invoking the kernel.
@@ -233,7 +236,7 @@
core kernel, the embedded initrd and kernel command line (see above for a full list).
Also note that the Linux kernel will measure all initrds it receives into TPM PCR 9. This means
- every type of initrd will be measured two or three times: the initrd embedded in the kernel image will be
+ every type of initrd will be measured two or three times: the initrds embedded in the kernel image will be
measured to PCR 4, PCR 9 and PCR 11; the initrd synthesized from credentials (and the one synthesized
from configuration extensions) will be measured to both PCR 9 and PCR 12; the initrd synthesized from
system extensions will be measured to both PCR 4 and PCR 9. Let's summarize the OS resources and the PCRs
@@ -274,6 +277,11 @@
4 + 9 + 11
+
+ Microcode initrd (embedded in unified PE binary)
+ 4 + 9 + 11
+
+
Default kernel command line (embedded in unified PE binary)
4 + 11
diff --git a/man/ukify.xml b/man/ukify.xml
index a81cbcb47b..a9034bc511 100644
--- a/man/ukify.xml
+++ b/man/ukify.xml
@@ -67,6 +67,7 @@
Additional sections will be inserted into the UKI, either automatically or only if a specific
option is provided. See the discussions of
+ Microcode=/,
Cmdline=/,
OSRelease=/,
DeviceTree=/,
@@ -302,6 +303,16 @@
+
+ Microcode=UCODE
+
+
+ Path to initrd containing microcode updates. If not specified, the section
+ will not be present.
+
+
+
+
Cmdline=TEXT|@PATH
diff --git a/src/boot/efi/stub.c b/src/boot/efi/stub.c
index 3511e2c999..9aa605b756 100644
--- a/src/boot/efi/stub.c
+++ b/src/boot/efi/stub.c
@@ -26,28 +26,27 @@ DECLARE_NOALLOC_SECTION(".sdmagic", "#### LoaderInfo: systemd-stub " GIT_VERSION
DECLARE_SBAT(SBAT_STUB_SECTION_TEXT);
-static EFI_STATUS combine_initrd(
- EFI_PHYSICAL_ADDRESS initrd_base, size_t initrd_size,
- const void * const extra_initrds[], const size_t extra_initrd_sizes[], size_t n_extra_initrds,
+/* Combine initrds by concatenation in memory */
+static EFI_STATUS combine_initrds(
+ const void * const initrds[], const size_t initrd_sizes[], size_t n_initrds,
Pages *ret_initr_pages, size_t *ret_initrd_size) {
- size_t n;
+ size_t n = 0;
assert(ret_initr_pages);
assert(ret_initrd_size);
- /* Combines four initrds into one, by simple concatenation in memory */
-
- n = ALIGN4(initrd_size); /* main initrd might not be padded yet */
-
- for (size_t i = 0; i < n_extra_initrds; i++) {
- if (!extra_initrds[i])
+ for (size_t i = 0; i < n_initrds; i++) {
+ if (!initrds[i])
continue;
- if (n > SIZE_MAX - extra_initrd_sizes[i])
+ /* some initrds (the ones from UKI sections) need padding,
+ * pad all to be safe */
+ size_t initrd_size = ALIGN4(initrd_sizes[i]);
+ if (n > SIZE_MAX - initrd_size)
return EFI_OUT_OF_RESOURCES;
- n += extra_initrd_sizes[i];
+ n += initrd_size;
}
_cleanup_pages_ Pages pages = xmalloc_pages(
@@ -56,27 +55,21 @@ static EFI_STATUS combine_initrd(
EFI_SIZE_TO_PAGES(n),
UINT32_MAX /* Below 4G boundary. */);
uint8_t *p = PHYSICAL_ADDRESS_TO_POINTER(pages.addr);
- if (initrd_base != 0) {
+ for (size_t i = 0; i < n_initrds; i++) {
+ if (!initrds[i])
+ continue;
+
size_t pad;
- /* Order matters, the real initrd must come first, since it might include microcode updates
- * which the kernel only looks for in the first cpio archive */
- p = mempcpy(p, PHYSICAL_ADDRESS_TO_POINTER(initrd_base), initrd_size);
+ p = mempcpy(p, initrds[i], initrd_sizes[i]);
- pad = ALIGN4(initrd_size) - initrd_size;
+ pad = ALIGN4(initrd_sizes[i]) - initrd_sizes[i];
if (pad > 0) {
memzero(p, pad);
p += pad;
}
}
- for (size_t i = 0; i < n_extra_initrds; i++) {
- if (!extra_initrds[i])
- continue;
-
- p = mempcpy(p, extra_initrds[i], extra_initrd_sizes[i]);
- }
-
assert(PHYSICAL_ADDRESS_TO_POINTER(pages.addr + n) == p);
*ret_initr_pages = pages;
@@ -503,8 +496,8 @@ static EFI_STATUS run(EFI_HANDLE image) {
void **dt_bases_addons_global = NULL, **dt_bases_addons_uki = NULL;
char16_t **dt_filenames_addons_global = NULL, **dt_filenames_addons_uki = NULL;
_cleanup_free_ size_t *dt_sizes_addons_global = NULL, *dt_sizes_addons_uki = NULL;
- size_t linux_size, initrd_size, dt_size, n_dts_addons_global = 0, n_dts_addons_uki = 0;
- EFI_PHYSICAL_ADDRESS linux_base, initrd_base, dt_base;
+ size_t linux_size, initrd_size, ucode_size, dt_size, n_dts_addons_global = 0, n_dts_addons_uki = 0;
+ EFI_PHYSICAL_ADDRESS linux_base, initrd_base, ucode_base, dt_base;
_cleanup_(devicetree_cleanup) struct devicetree_state dt_state = {};
EFI_LOADED_IMAGE_PROTOCOL *loaded_image;
size_t addrs[_UNIFIED_SECTION_MAX] = {}, szs[_UNIFIED_SECTION_MAX] = {};
@@ -792,12 +785,18 @@ static EFI_STATUS run(EFI_HANDLE image) {
initrd_size = szs[UNIFIED_SECTION_INITRD];
initrd_base = initrd_size != 0 ? POINTER_TO_PHYSICAL_ADDRESS(loaded_image->ImageBase) + addrs[UNIFIED_SECTION_INITRD] : 0;
+ ucode_size = szs[UNIFIED_SECTION_UCODE];
+ ucode_base = ucode_size != 0 ? POINTER_TO_PHYSICAL_ADDRESS(loaded_image->ImageBase) + addrs[UNIFIED_SECTION_UCODE] : 0;
+
_cleanup_pages_ Pages initrd_pages = {};
- if (credential_initrd || global_credential_initrd || sysext_initrd || confext_initrd || pcrsig_initrd || pcrpkey_initrd) {
- /* If we have generated initrds dynamically, let's combine them with the built-in initrd. */
- err = combine_initrd(
- initrd_base, initrd_size,
+ if (ucode_base || credential_initrd || global_credential_initrd || sysext_initrd || confext_initrd || pcrsig_initrd || pcrpkey_initrd) {
+ /* If we have generated initrds dynamically or there is a microcode initrd, combine them with the built-in initrd. */
+ err = combine_initrds(
(const void*const[]) {
+ /* Microcode must always be first as kernel only scans uncompressed cpios
+ * and later initrds might be compressed. */
+ PHYSICAL_ADDRESS_TO_POINTER(ucode_base),
+ PHYSICAL_ADDRESS_TO_POINTER(initrd_base),
credential_initrd,
global_credential_initrd,
sysext_initrd,
@@ -806,6 +805,8 @@ static EFI_STATUS run(EFI_HANDLE image) {
pcrpkey_initrd,
},
(const size_t[]) {
+ ucode_size,
+ initrd_size,
credential_initrd_size,
global_credential_initrd_size,
sysext_initrd_size,
@@ -813,7 +814,7 @@ static EFI_STATUS run(EFI_HANDLE image) {
pcrsig_initrd_size,
pcrpkey_initrd_size,
},
- 6,
+ 8,
&initrd_pages, &initrd_size);
if (err != EFI_SUCCESS)
return err;
diff --git a/src/boot/measure.c b/src/boot/measure.c
index 789a3deb8c..41fcd5a91a 100644
--- a/src/boot/measure.c
+++ b/src/boot/measure.c
@@ -92,6 +92,7 @@ static int help(int argc, char *argv[], void *userdata) {
" --osrel=PATH Path to os-release file %7$s .osrel\n"
" --cmdline=PATH Path to file with kernel command line %7$s .cmdline\n"
" --initrd=PATH Path to initrd image file %7$s .initrd\n"
+ " --ucode=PATH Path to microcode image file %7$s .ucode\n"
" --splash=PATH Path to splash bitmap file %7$s .splash\n"
" --dtb=PATH Path to Devicetree file %7$s .dtb\n"
" --uname=PATH Path to 'uname -r' file %7$s .uname\n"
@@ -133,6 +134,7 @@ static int parse_argv(int argc, char *argv[]) {
ARG_OSREL,
ARG_CMDLINE,
ARG_INITRD,
+ ARG_UCODE,
ARG_SPLASH,
ARG_DTB,
ARG_UNAME,
@@ -159,6 +161,7 @@ static int parse_argv(int argc, char *argv[]) {
{ "osrel", required_argument, NULL, ARG_OSREL },
{ "cmdline", required_argument, NULL, ARG_CMDLINE },
{ "initrd", required_argument, NULL, ARG_INITRD },
+ { "ucode", required_argument, NULL, ARG_UCODE },
{ "splash", required_argument, NULL, ARG_SPLASH },
{ "dtb", required_argument, NULL, ARG_DTB },
{ "uname", required_argument, NULL, ARG_UNAME },
diff --git a/src/fundamental/uki.c b/src/fundamental/uki.c
index b1fa044813..3887bf5702 100644
--- a/src/fundamental/uki.c
+++ b/src/fundamental/uki.c
@@ -13,6 +13,7 @@ const char* const unified_sections[_UNIFIED_SECTION_MAX + 1] = {
[UNIFIED_SECTION_OSREL] = ".osrel",
[UNIFIED_SECTION_CMDLINE] = ".cmdline",
[UNIFIED_SECTION_INITRD] = ".initrd",
+ [UNIFIED_SECTION_UCODE] = ".ucode",
[UNIFIED_SECTION_SPLASH] = ".splash",
[UNIFIED_SECTION_DTB] = ".dtb",
[UNIFIED_SECTION_UNAME] = ".uname",
diff --git a/src/fundamental/uki.h b/src/fundamental/uki.h
index ffa960f01b..8ab742dd58 100644
--- a/src/fundamental/uki.h
+++ b/src/fundamental/uki.h
@@ -10,6 +10,7 @@ typedef enum UnifiedSection {
UNIFIED_SECTION_OSREL,
UNIFIED_SECTION_CMDLINE,
UNIFIED_SECTION_INITRD,
+ UNIFIED_SECTION_UCODE,
UNIFIED_SECTION_SPLASH,
UNIFIED_SECTION_DTB,
UNIFIED_SECTION_UNAME,
diff --git a/src/ukify/ukify.py b/src/ukify/ukify.py
index 686377200f..50d921b7a8 100755
--- a/src/ukify/ukify.py
+++ b/src/ukify/ukify.py
@@ -303,6 +303,7 @@ class Uname:
DEFAULT_SECTIONS_TO_SHOW = {
'.linux' : 'binary',
'.initrd' : 'binary',
+ '.ucode' : 'binary',
'.splash' : 'binary',
'.dtb' : 'binary',
'.cmdline' : 'text',
@@ -855,6 +856,7 @@ def make_uki(opts):
('.splash', opts.splash, True ),
('.pcrpkey', pcrpkey, True ),
('.initrd', initrd, True ),
+ ('.ucode', opts.microcode, True ),
# linux shall be last to leave breathing room for decompression.
# We'll add it later.
@@ -1279,6 +1281,14 @@ CONFIG_ITEMS = [
config_push = ConfigItem.config_list_prepend,
),
+ ConfigItem(
+ '--microcode',
+ metavar = 'UCODE',
+ type = pathlib.Path,
+ help = 'microcode file [.ucode section]',
+ config_key = 'UKI/Microcode',
+ ),
+
ConfigItem(
('--config', '-c'),
metavar = 'PATH',