If the architecture supports an EFI stub launched version of DRTM, it can select the kconfig and provide the hooks under its architecture build.
Have the common code parse a drtm=enforce|auto|off kernel command line parameter to set the boot behavior. Support commas in the args list since there will be more options here down the road. efi_drtm_prepare() is called before doing any decompression or image relocation. It should figure out if DRTM is supported, policy-permitted, and how much memory efi_drtm_get_extra_size() should return. The image handling is revised to allocate extra_size at the end of the normal image. The architecture can use this to store any information needed for the DRTM flow. It is always contiguous with Image, which is a requirement of ARM's specification. efi_drtm_prepare_launch() is called while still in EFI boot services after Image is fully prepared in its final location. efi_drtm_launch() is called after exiting boot services and must jump into the kernel through the DRTM flow. If it returns, then the normal launch is tried (auto mode). The extra_size is allocated directly after the Image. Handle the trivial zboot flow now, and vmlinux in the following patch. Signed-off-by: Jason Gunthorpe <[email protected]> --- .../admin-guide/kernel-parameters.txt | 12 +++++++ drivers/firmware/efi/Kconfig | 30 ++++++++++++++++ drivers/firmware/efi/libstub/efi-stub-entry.c | 4 +++ .../firmware/efi/libstub/efi-stub-helper.c | 34 ++++++++++++++++++ drivers/firmware/efi/libstub/efistub.h | 36 +++++++++++++++++++ drivers/firmware/efi/libstub/fdt.c | 8 ++++- drivers/firmware/efi/libstub/zboot.c | 19 +++++++--- 7 files changed, 137 insertions(+), 6 deletions(-) diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt index 68647ff4bdd24b..a576e06bd43584 100644 --- a/Documentation/admin-guide/kernel-parameters.txt +++ b/Documentation/admin-guide/kernel-parameters.txt @@ -1373,6 +1373,18 @@ Kernel parameters data set with no connector name will be used for any connectors not explicitly specified. + drtm= [EFI,EARLY] + Format: { "off" | "auto" | "enforce" } + Control the EFI stub Dynamic Root of Trust for + Measurement (DRTM) launch policy. + off: do not attempt a DRTM launch. + auto: attempt a DRTM launch when supported, but fall + back to a normal boot if preparation or launch fails. + enforce: require a DRTM launch and refuse to fall back + to a normal boot if preparation or launch fails. + The default is selected by the EFI_STUB_DRTM_DEFAULT_* + configuration options. + dscc4.setup= [NET] dt_cpu_ftrs= [PPC,EARLY] diff --git a/drivers/firmware/efi/Kconfig b/drivers/firmware/efi/Kconfig index 3d6fb3ca2806ca..f77fa1ae716843 100644 --- a/drivers/firmware/efi/Kconfig +++ b/drivers/firmware/efi/Kconfig @@ -75,6 +75,36 @@ config EFI_GENERIC_STUB config EFI_STUB_IMAGE_INFO bool +config EFI_STUB_DRTM + bool + +choice + prompt "Default DRTM launch policy" + depends on EFI_STUB_DRTM + default EFI_STUB_DRTM_DEFAULT_OFF + help + Select the DRTM policy used when no drtm= option is present on the + kernel command line. The command-line option overrides this default. + +config EFI_STUB_DRTM_DEFAULT_OFF + bool "Off" + help + Do not attempt a DRTM launch unless it is requested explicitly. + +config EFI_STUB_DRTM_DEFAULT_AUTO + bool "Automatic with fallback" + help + Attempt a DRTM launch when the firmware supports it, but fall back to + normal boot if preparation or a returnable launch attempt fails. + +config EFI_STUB_DRTM_DEFAULT_ENFORCE + bool "Enforce" + help + Require a DRTM launch and refuse normal-boot fallback if preparation + or a returnable launch attempt fails. + +endchoice + config EFI_ZBOOT bool "Enable the generic EFI decompressor" depends on EFI_GENERIC_STUB && !ARM diff --git a/drivers/firmware/efi/libstub/efi-stub-entry.c b/drivers/firmware/efi/libstub/efi-stub-entry.c index 83fade2b0d3b84..5b356c4be78975 100644 --- a/drivers/firmware/efi/libstub/efi-stub-entry.c +++ b/drivers/firmware/efi/libstub/efi-stub-entry.c @@ -67,6 +67,10 @@ efi_status_t __efiapi efi_pe_entry(efi_handle_t handle, if (status != EFI_SUCCESS) return status; + status = efi_drtm_prepare(); + if (status != EFI_SUCCESS) + return status; + efi_info("Booting Linux Kernel...\n"); status = handle_kernel_image(&image_addr, &image_size, diff --git a/drivers/firmware/efi/libstub/efi-stub-helper.c b/drivers/firmware/efi/libstub/efi-stub-helper.c index f27f2e1f001997..2dd4a5ac916000 100644 --- a/drivers/firmware/efi/libstub/efi-stub-helper.c +++ b/drivers/firmware/efi/libstub/efi-stub-helper.c @@ -27,6 +27,37 @@ static bool efi_disable_pci_dma = IS_ENABLED(CONFIG_EFI_DISABLE_PCI_DMA); int efi_mem_encrypt; +#ifdef CONFIG_EFI_STUB_DRTM +enum efi_drtm_policy efi_drtm_policy = + IS_ENABLED(CONFIG_EFI_STUB_DRTM_DEFAULT_ENFORCE) ? EFI_DRTM_ENFORCE : + IS_ENABLED(CONFIG_EFI_STUB_DRTM_DEFAULT_AUTO) ? EFI_DRTM_AUTO : + EFI_DRTM_OFF; + +static void efi_drtm_parse_options(char *options) +{ + char *keyword; + + while (options) { + keyword = options; + while (*options && *options != ',') + options++; + if (*options) + *options++ = '\0'; + else + options = NULL; + + if (!strcmp(keyword, "off")) + efi_drtm_policy = EFI_DRTM_OFF; + else if (!strcmp(keyword, "auto")) + efi_drtm_policy = EFI_DRTM_AUTO; + else if (!strcmp(keyword, "enforce")) + efi_drtm_policy = EFI_DRTM_ENFORCE; + } +} +#else +static void efi_drtm_parse_options(char *options) {} +#endif + bool __pure __efi_soft_reserve_enabled(void) { return !efi_nosoftreserve; @@ -89,6 +120,9 @@ efi_status_t efi_parse_options(char const *cmdline) efi_mem_encrypt = 1; else if (parse_option_str(val, "off")) efi_mem_encrypt = -1; + } else if (IS_ENABLED(CONFIG_EFI_STUB_DRTM) && + !strcmp(param, "drtm") && val) { + efi_drtm_parse_options(val); } else if (!strcmp(param, "efi") && val) { efi_nochunk = parse_option_str(val, "nochunk"); efi_novamap |= parse_option_str(val, "novamap"); diff --git a/drivers/firmware/efi/libstub/efistub.h b/drivers/firmware/efi/libstub/efistub.h index da01d6005a62af..f3a6aefdc052ca 100644 --- a/drivers/firmware/efi/libstub/efistub.h +++ b/drivers/firmware/efi/libstub/efistub.h @@ -1078,6 +1078,42 @@ efi_status_t check_platform_features(void); void *get_efi_config_table(efi_guid_t guid); +enum efi_drtm_policy { + EFI_DRTM_OFF, + EFI_DRTM_AUTO, + EFI_DRTM_ENFORCE, +}; + +#ifdef CONFIG_EFI_STUB_DRTM +extern enum efi_drtm_policy efi_drtm_policy; +efi_status_t efi_drtm_prepare(void); +unsigned long efi_drtm_get_extra_size(void); +efi_status_t efi_drtm_prepare_launch(unsigned long image_base, + unsigned long fdt_addr); +void efi_drtm_launch(void); +#else +enum {efi_drtm_policy = EFI_DRTM_OFF}; +static inline efi_status_t efi_drtm_prepare(void) +{ + return EFI_SUCCESS; +} + +static inline unsigned long efi_drtm_get_extra_size(void) +{ + return 0; +} + +static inline efi_status_t +efi_drtm_prepare_launch(unsigned long image_base, unsigned long fdt_addr) +{ + return EFI_SUCCESS; +} + +static inline void efi_drtm_launch(void) +{ +} +#endif + /* NOTE: These functions do not print a trailing newline after the string */ void efi_char16_puts(efi_char16_t *); void efi_puts(const char *str); diff --git a/drivers/firmware/efi/libstub/fdt.c b/drivers/firmware/efi/libstub/fdt.c index 5b2dd709d7b151..15bb331f2dc56c 100644 --- a/drivers/firmware/efi/libstub/fdt.c +++ b/drivers/firmware/efi/libstub/fdt.c @@ -223,6 +223,7 @@ static efi_status_t allocate_new_fdt_and_exit_boot(void *handle, efi_loaded_image_t *image, unsigned long *new_fdt_addr, + unsigned long kernel_addr, char *cmdline_ptr) { unsigned long desc_size; @@ -289,6 +290,10 @@ efi_status_t allocate_new_fdt_and_exit_boot(void *handle, goto fail_free_new_fdt; } + status = efi_drtm_prepare_launch(kernel_addr, *new_fdt_addr); + if (status != EFI_SUCCESS) + goto fail_free_new_fdt; + priv.new_fdt_addr = (void *)*new_fdt_addr; status = efi_exit_boot_services(handle, &priv, exit_boot_func); @@ -350,7 +355,7 @@ efi_status_t efi_boot_kernel(void *handle, efi_loaded_image_t *image, efi_status_t status; status = allocate_new_fdt_and_exit_boot(handle, image, &fdt_addr, - cmdline_ptr); + kernel_addr, cmdline_ptr); if (status != EFI_SUCCESS) { efi_err("Failed to update FDT and exit boot services\n"); return status; @@ -359,6 +364,7 @@ efi_status_t efi_boot_kernel(void *handle, efi_loaded_image_t *image, if (IS_ENABLED(CONFIG_ARM)) efi_handle_post_ebs_state(); + efi_drtm_launch(); efi_enter_kernel(kernel_addr, fdt_addr, fdt_totalsize((void *)fdt_addr)); /* not reached */ } diff --git a/drivers/firmware/efi/libstub/zboot.c b/drivers/firmware/efi/libstub/zboot.c index 960a542881d875..6ca231ad593b20 100644 --- a/drivers/firmware/efi/libstub/zboot.c +++ b/drivers/firmware/efi/libstub/zboot.c @@ -35,7 +35,7 @@ asmlinkage efi_status_t __efiapi efi_zboot_entry(efi_handle_t handle, efi_system_table_t *systab) { char *cmdline_ptr __free(efi_pool) = NULL; - unsigned long image_base, alloc_size; + unsigned long image_base, image_size, alloc_size; efi_loaded_image_t *image; efi_status_t status; @@ -52,12 +52,17 @@ efi_zboot_entry(efi_handle_t handle, efi_system_table_t *systab) if (status != EFI_SUCCESS) return status; - efi_info("Decompressing Linux Kernel...\n"); - - status = efi_zboot_decompress_init(&alloc_size); + status = efi_drtm_prepare(); if (status != EFI_SUCCESS) return status; + efi_info("Decompressing Linux Kernel...\n"); + + status = efi_zboot_decompress_init(&image_size); + if (status != EFI_SUCCESS) + return status; + alloc_size = image_size + efi_drtm_get_extra_size(); + // If the architecture has a preferred address for the image, // try that first. image_base = alloc_preferred_address(alloc_size); @@ -92,8 +97,12 @@ efi_zboot_entry(efi_handle_t handle, efi_system_table_t *systab) } // Decompress the payload into the newly allocated buffer - status = efi_zboot_decompress((void *)image_base, alloc_size); + status = efi_zboot_decompress((void *)image_base, image_size); if (status == EFI_SUCCESS) { + /* + * Have to sync the entire allocation because the sync also + * remaps and changes the permissions. + */ efi_cache_sync_image(image_base, alloc_size); status = efi_stub_common(handle, image, image_base, cmdline_ptr); -- 2.43.0
