summaryrefslogtreecommitdiffstats
path: root/drivers/firmware/efi/libstub/arm-stub.c
diff options
context:
space:
mode:
authorArd Biesheuvel <ardb@kernel.org>2020-02-03 23:45:14 +0000
committerArd Biesheuvel <ardb@kernel.org>2020-02-23 21:59:42 +0100
commitec93fc371f014a6fb483e3556061ecad4b40735c (patch)
treed537b75ace86a3c80588c5b1f05297d6a25e850e /drivers/firmware/efi/libstub/arm-stub.c
parentdb8952e7094fde3a397321240d5d57ec111258d8 (diff)
downloadlinux-ec93fc371f014a6fb483e3556061ecad4b40735c.tar.bz2
efi/libstub: Add support for loading the initrd from a device path
There are currently two ways to specify the initrd to be passed to the Linux kernel when booting via the EFI stub: - it can be passed as a initrd= command line option when doing a pure PE boot (as opposed to the EFI handover protocol that exists for x86) - otherwise, the bootloader or firmware can load the initrd into memory, and pass the address and size via the bootparams struct (x86) or device tree (ARM) In the first case, we are limited to loading from the same file system that the kernel was loaded from, and it is also problematic in a trusted boot context, given that we cannot easily protect the command line from tampering without either adding complicated white/blacklisting of boot arguments or locking down the command line altogether. In the second case, we force the bootloader to duplicate knowledge about the boot protocol which is already encoded in the stub, and which may be subject to change over time, e.g., bootparams struct definitions, memory allocation/alignment requirements for the placement of the initrd etc etc. In the ARM case, it also requires the bootloader to modify the hardware description provided by the firmware, as it is passed in the same file. On systems where the initrd is measured after loading, it creates a time window where the initrd contents might be manipulated in memory before handing over to the kernel. Address these concerns by adding support for loading the initrd into memory by invoking the EFI LoadFile2 protocol installed on a vendor GUIDed device path that specifically designates a Linux initrd. This addresses the above concerns, by putting the EFI stub in charge of placement in memory and of passing the base and size to the kernel proper (via whatever means it desires) while still leaving it up to the firmware or bootloader to obtain the file contents, potentially from other file systems than the one the kernel itself was loaded from. On platforms that implement measured boot, it permits the firmware to take the measurement right before the kernel actually consumes the contents. Acked-by: Laszlo Ersek <lersek@redhat.com> Tested-by: Ilias Apalodimas <ilias.apalodimas@linaro.org> Acked-by: Ilias Apalodimas <ilias.apalodimas@linaro.org> Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
Diffstat (limited to 'drivers/firmware/efi/libstub/arm-stub.c')
-rw-r--r--drivers/firmware/efi/libstub/arm-stub.c15
1 files changed, 12 insertions, 3 deletions
diff --git a/drivers/firmware/efi/libstub/arm-stub.c b/drivers/firmware/efi/libstub/arm-stub.c
index a11257a90dd0..11c673a7e95b 100644
--- a/drivers/firmware/efi/libstub/arm-stub.c
+++ b/drivers/firmware/efi/libstub/arm-stub.c
@@ -165,6 +165,7 @@ efi_status_t efi_entry(efi_handle_t handle, efi_system_table_t *sys_table_arg)
enum efi_secureboot_mode secure_boot;
struct screen_info *si;
efi_properties_table_t *prop_tbl;
+ unsigned long max_addr;
sys_table = sys_table_arg;
@@ -267,10 +268,18 @@ efi_status_t efi_entry(efi_handle_t handle, efi_system_table_t *sys_table_arg)
if (!fdt_addr)
pr_efi("Generating empty DTB\n");
- status = efi_load_initrd(image, &initrd_addr, &initrd_size, ULONG_MAX,
- efi_get_max_initrd_addr(dram_base, image_addr));
+ max_addr = efi_get_max_initrd_addr(dram_base, image_addr);
+ status = efi_load_initrd_dev_path(&initrd_addr, &initrd_size, max_addr);
+ if (status == EFI_SUCCESS) {
+ pr_efi("Loaded initrd from LINUX_EFI_INITRD_MEDIA_GUID device path\n");
+ } else if (status == EFI_NOT_FOUND) {
+ status = efi_load_initrd(image, &initrd_addr, &initrd_size,
+ ULONG_MAX, max_addr);
+ if (status == EFI_SUCCESS)
+ pr_efi("Loaded initrd from command line option\n");
+ }
if (status != EFI_SUCCESS)
- pr_efi_err("Failed initrd from command line!\n");
+ pr_efi_err("Failed to load initrd!\n");
efi_random_get_seed();