Skip to content

Commit

Permalink
efi: libstub: remove DT dependency from generic stub
Browse files Browse the repository at this point in the history
Refactor the generic EFI stub entry code so that all the dependencies on
device tree are abstracted and hidden behind a generic efi_boot_kernel()
routine that can also be implemented in other ways. This allows users of
the generic stub to avoid using FDT for passing information to the core
kernel.

Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
  • Loading branch information
Ard Biesheuvel committed Sep 27, 2022
1 parent f4dc7ff commit 4fc8e73
Show file tree
Hide file tree
Showing 3 changed files with 60 additions and 61 deletions.
53 changes: 1 addition & 52 deletions drivers/firmware/efi/libstub/efi-stub.c
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@
*/

#include <linux/efi.h>
#include <linux/libfdt.h>
#include <asm/efi.h>

#include "efistub.h"
Expand Down Expand Up @@ -132,14 +131,11 @@ efi_status_t __efiapi efi_pe_entry(efi_handle_t handle,
unsigned long image_addr;
unsigned long image_size = 0;
/* addr/point and size pairs for memory management*/
unsigned long fdt_addr = 0; /* Original DTB */
unsigned long fdt_size = 0;
char *cmdline_ptr = NULL;
int cmdline_size = 0;
efi_guid_t loaded_image_proto = LOADED_IMAGE_PROTOCOL_GUID;
unsigned long reserve_addr = 0;
unsigned long reserve_size = 0;
enum efi_secureboot_mode secure_boot;
struct screen_info *si;
efi_properties_table_t *prop_tbl;

Expand Down Expand Up @@ -215,38 +211,6 @@ efi_status_t __efiapi efi_pe_entry(efi_handle_t handle,
/* Ask the firmware to clear memory on unclean shutdown */
efi_enable_reset_attack_mitigation();

secure_boot = efi_get_secureboot();

/*
* Unauthenticated device tree data is a security hazard, so ignore
* 'dtb=' unless UEFI Secure Boot is disabled. We assume that secure
* boot is enabled if we can't determine its state.
*/
if (!IS_ENABLED(CONFIG_EFI_ARMSTUB_DTB_LOADER) ||
secure_boot != efi_secureboot_mode_disabled) {
if (strstr(cmdline_ptr, "dtb="))
efi_err("Ignoring DTB from command line.\n");
} else {
status = efi_load_dtb(image, &fdt_addr, &fdt_size);

if (status != EFI_SUCCESS && status != EFI_NOT_READY) {
efi_err("Failed to load device tree!\n");
goto fail_free_image;
}
}

if (fdt_addr) {
efi_info("Using DTB from command line\n");
} else {
/* Look for a device tree configuration table entry. */
fdt_addr = (uintptr_t)get_fdt(&fdt_size);
if (fdt_addr)
efi_info("Using DTB from configuration table\n");
}

if (!fdt_addr)
efi_info("Generating empty DTB\n");

efi_load_initrd(image, ULONG_MAX, efi_get_max_initrd_addr(image_addr),
NULL);

Expand Down Expand Up @@ -290,23 +254,8 @@ efi_status_t __efiapi efi_pe_entry(efi_handle_t handle,

install_memreserve_table();

status = allocate_new_fdt_and_exit_boot(handle, &fdt_addr, cmdline_ptr,
fdt_addr, fdt_size);
if (status != EFI_SUCCESS)
goto fail_free_fdt;

if (IS_ENABLED(CONFIG_ARM))
efi_handle_post_ebs_state();

efi_enter_kernel(image_addr, fdt_addr, fdt_totalsize((void *)fdt_addr));
/* not reached */

fail_free_fdt:
efi_err("Failed to update FDT and exit boot services\n");

efi_free(fdt_size, fdt_addr);
status = efi_boot_kernel(handle, image, image_addr, cmdline_ptr);

fail_free_image:
efi_free(image_size, image_addr);
efi_free(reserve_size, reserve_addr);
fail_free_screeninfo:
Expand Down
7 changes: 2 additions & 5 deletions drivers/firmware/efi/libstub/efistub.h
Original file line number Diff line number Diff line change
Expand Up @@ -844,11 +844,8 @@ typedef efi_status_t (*efi_exit_boot_map_processing)(
efi_status_t efi_exit_boot_services(void *handle, void *priv,
efi_exit_boot_map_processing priv_func);

efi_status_t allocate_new_fdt_and_exit_boot(void *handle,
unsigned long *new_fdt_addr,
char *cmdline_ptr,
unsigned long fdt_addr,
unsigned long fdt_size);
efi_status_t efi_boot_kernel(void *handle, efi_loaded_image_t *image,
unsigned long kernel_addr, char *cmdline_ptr);

void *get_fdt(unsigned long *fdt_size);

Expand Down
61 changes: 57 additions & 4 deletions drivers/firmware/efi/libstub/fdt.c
Original file line number Diff line number Diff line change
Expand Up @@ -219,17 +219,18 @@ static efi_status_t exit_boot_func(struct efi_boot_memmap *map, void *priv)
* exit_boot_services() call, so the exiting of boot services is very tightly
* tied to the creation of the FDT with the final memory map in it.
*/

static
efi_status_t allocate_new_fdt_and_exit_boot(void *handle,
efi_loaded_image_t *image,
unsigned long *new_fdt_addr,
char *cmdline_ptr,
unsigned long fdt_addr,
unsigned long fdt_size)
char *cmdline_ptr)
{
unsigned long desc_size;
u32 desc_ver;
efi_status_t status;
struct exit_boot_struct priv;
unsigned long fdt_addr = 0;
unsigned long fdt_size = 0;

if (!efi_novamap) {
status = efi_alloc_virtmap(&priv.runtime_map, &desc_size,
Expand All @@ -240,6 +241,36 @@ efi_status_t allocate_new_fdt_and_exit_boot(void *handle,
}
}

/*
* Unauthenticated device tree data is a security hazard, so ignore
* 'dtb=' unless UEFI Secure Boot is disabled. We assume that secure
* boot is enabled if we can't determine its state.
*/
if (!IS_ENABLED(CONFIG_EFI_ARMSTUB_DTB_LOADER) ||
efi_get_secureboot() != efi_secureboot_mode_disabled) {
if (strstr(cmdline_ptr, "dtb="))
efi_err("Ignoring DTB from command line.\n");
} else {
status = efi_load_dtb(image, &fdt_addr, &fdt_size);

if (status != EFI_SUCCESS && status != EFI_NOT_READY) {
efi_err("Failed to load device tree!\n");
goto fail;
}
}

if (fdt_addr) {
efi_info("Using DTB from command line\n");
} else {
/* Look for a device tree configuration table entry. */
fdt_addr = (uintptr_t)get_fdt(&fdt_size);
if (fdt_addr)
efi_info("Using DTB from configuration table\n");
}

if (!fdt_addr)
efi_info("Generating empty DTB\n");

efi_info("Exiting boot services...\n");

status = efi_allocate_pages(MAX_FDT_SIZE, new_fdt_addr, ULONG_MAX);
Expand Down Expand Up @@ -303,11 +334,33 @@ efi_status_t allocate_new_fdt_and_exit_boot(void *handle,
efi_free(MAX_FDT_SIZE, *new_fdt_addr);

fail:
efi_free(fdt_size, fdt_addr);

efi_bs_call(free_pool, priv.runtime_map);

return EFI_LOAD_ERROR;
}

efi_status_t efi_boot_kernel(void *handle, efi_loaded_image_t *image,
unsigned long kernel_addr, char *cmdline_ptr)
{
unsigned long fdt_addr;
efi_status_t status;

status = allocate_new_fdt_and_exit_boot(handle, image, &fdt_addr,
cmdline_ptr);
if (status != EFI_SUCCESS) {
efi_err("Failed to update FDT and exit boot services\n");
return status;
}

if (IS_ENABLED(CONFIG_ARM))
efi_handle_post_ebs_state();

efi_enter_kernel(kernel_addr, fdt_addr, fdt_totalsize((void *)fdt_addr));
/* not reached */
}

void *get_fdt(unsigned long *fdt_size)
{
void *fdt;
Expand Down

0 comments on commit 4fc8e73

Please sign in to comment.