Commit 9302c1bb authored by Ard Biesheuvel's avatar Ard Biesheuvel

efi/libstub: Rewrite file I/O routine

The file I/O routine that is used to load initrd or dtb files from
the EFI system partition suffers from a few issues:
- it converts the u8[] command line back to a UTF-16 string, which is
  pointless since we only handle initrd or dtb arguments provided via
  the loaded image protocol anyway, which is where we got the UTF-16[]
  command line from in the first place when booting via the PE entry
  point,
- in the far majority of cases, only a single initrd= option is present,
  but it optimizes for multiple options, by going over the command line
  twice, allocating heap buffers for dynamically sized arrays, etc.
- the coding style is hard to follow, with few comments, and all logic
  including string parsing etc all combined in a single routine.

Let's fix this by rewriting most of it, based on the idea that in the
case of multiple initrds, we can just allocate a new, bigger buffer
and copy over the data before freeing the old one.
Signed-off-by: default avatarArd Biesheuvel <ardb@kernel.org>
parent 5193a33d
...@@ -154,7 +154,7 @@ efi_status_t efi_entry(efi_handle_t handle, efi_system_table_t *sys_table_arg) ...@@ -154,7 +154,7 @@ efi_status_t efi_entry(efi_handle_t handle, efi_system_table_t *sys_table_arg)
unsigned long dram_base; unsigned long dram_base;
/* addr/point and size pairs for memory management*/ /* addr/point and size pairs for memory management*/
unsigned long initrd_addr; unsigned long initrd_addr;
u64 initrd_size = 0; unsigned long initrd_size = 0;
unsigned long fdt_addr = 0; /* Original DTB */ unsigned long fdt_addr = 0; /* Original DTB */
unsigned long fdt_size = 0; unsigned long fdt_size = 0;
char *cmdline_ptr = NULL; char *cmdline_ptr = NULL;
...@@ -247,8 +247,7 @@ efi_status_t efi_entry(efi_handle_t handle, efi_system_table_t *sys_table_arg) ...@@ -247,8 +247,7 @@ efi_status_t efi_entry(efi_handle_t handle, efi_system_table_t *sys_table_arg)
if (strstr(cmdline_ptr, "dtb=")) if (strstr(cmdline_ptr, "dtb="))
pr_efi("Ignoring DTB from command line.\n"); pr_efi("Ignoring DTB from command line.\n");
} else { } else {
status = handle_cmdline_files(image, cmdline_ptr, "dtb=", status = efi_load_dtb(image, &fdt_addr, &fdt_size);
~0UL, &fdt_addr, &fdt_size);
if (status != EFI_SUCCESS) { if (status != EFI_SUCCESS) {
pr_efi_err("Failed to load device tree!\n"); pr_efi_err("Failed to load device tree!\n");
...@@ -268,11 +267,8 @@ efi_status_t efi_entry(efi_handle_t handle, efi_system_table_t *sys_table_arg) ...@@ -268,11 +267,8 @@ efi_status_t efi_entry(efi_handle_t handle, efi_system_table_t *sys_table_arg)
if (!fdt_addr) if (!fdt_addr)
pr_efi("Generating empty DTB\n"); pr_efi("Generating empty DTB\n");
status = handle_cmdline_files(image, cmdline_ptr, "initrd=", status = efi_load_initrd(image, &initrd_addr, &initrd_size,
efi_get_max_initrd_addr(dram_base, efi_get_max_initrd_addr(dram_base, image_addr));
image_addr),
(unsigned long *)&initrd_addr,
(unsigned long *)&initrd_size);
if (status != EFI_SUCCESS) if (status != EFI_SUCCESS)
pr_efi_err("Failed initrd from command line!\n"); pr_efi_err("Failed initrd from command line!\n");
......
...@@ -327,7 +327,7 @@ typedef struct { ...@@ -327,7 +327,7 @@ typedef struct {
efi_time_t last_access_time; efi_time_t last_access_time;
efi_time_t modification_time; efi_time_t modification_time;
__aligned_u64 attribute; __aligned_u64 attribute;
efi_char16_t filename[1]; efi_char16_t filename[];
} efi_file_info_t; } efi_file_info_t;
typedef struct efi_file_protocol efi_file_protocol_t; typedef struct efi_file_protocol efi_file_protocol_t;
...@@ -607,15 +607,18 @@ efi_status_t efi_relocate_kernel(unsigned long *image_addr, ...@@ -607,15 +607,18 @@ efi_status_t efi_relocate_kernel(unsigned long *image_addr,
unsigned long alignment, unsigned long alignment,
unsigned long min_addr); unsigned long min_addr);
efi_status_t handle_cmdline_files(efi_loaded_image_t *image,
char *cmd_line, char *option_string,
unsigned long max_addr,
unsigned long *load_addr,
unsigned long *load_size);
efi_status_t efi_parse_options(char const *cmdline); efi_status_t efi_parse_options(char const *cmdline);
efi_status_t efi_setup_gop(struct screen_info *si, efi_guid_t *proto, efi_status_t efi_setup_gop(struct screen_info *si, efi_guid_t *proto,
unsigned long size); unsigned long size);
efi_status_t efi_load_dtb(efi_loaded_image_t *image,
unsigned long *load_addr,
unsigned long *load_size);
efi_status_t efi_load_initrd(efi_loaded_image_t *image,
unsigned long *load_addr,
unsigned long *load_size,
unsigned long max_addr);
#endif #endif
This diff is collapsed.
...@@ -421,18 +421,14 @@ efi_status_t __efiapi efi_pe_entry(efi_handle_t handle, ...@@ -421,18 +421,14 @@ efi_status_t __efiapi efi_pe_entry(efi_handle_t handle,
if (status != EFI_SUCCESS) if (status != EFI_SUCCESS)
goto fail2; goto fail2;
status = handle_cmdline_files(image, status = efi_load_initrd(image, &ramdisk_addr, &ramdisk_size,
(char *)(unsigned long)hdr->cmd_line_ptr, hdr->initrd_addr_max);
"initrd=", hdr->initrd_addr_max,
&ramdisk_addr, &ramdisk_size);
if (status != EFI_SUCCESS && if (status != EFI_SUCCESS &&
hdr->xloadflags & XLF_CAN_BE_LOADED_ABOVE_4G) { hdr->xloadflags & XLF_CAN_BE_LOADED_ABOVE_4G) {
efi_printk("Trying to load files to higher address\n"); efi_printk("Trying to load files to higher address\n");
status = handle_cmdline_files(image, status = efi_load_initrd(image, &ramdisk_addr, &ramdisk_size,
(char *)(unsigned long)hdr->cmd_line_ptr, ULONG_MAX);
"initrd=", -1UL,
&ramdisk_addr, &ramdisk_size);
} }
if (status != EFI_SUCCESS) if (status != EFI_SUCCESS)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment