efi/libstub: Take soft and hard memory limits into account for initrd loading
authorArd Biesheuvel <ardb@kernel.org>
Mon, 10 Feb 2020 16:02:45 +0000 (17:02 +0100)
committerArd Biesheuvel <ardb@kernel.org>
Sun, 23 Feb 2020 20:57:15 +0000 (21:57 +0100)
On x86, the preferred load address of the initrd is still below 4 GB,
even though in some cases, we can cope with an initrd that is loaded
above that.

To simplify the code, and to make it more straightforward to introduce
other ways to load the initrd, pass the soft and hard memory limits at
the same time, and let the code handling the initrd= command line option
deal with this.

Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
drivers/firmware/efi/libstub/arm-stub.c
drivers/firmware/efi/libstub/efistub.h
drivers/firmware/efi/libstub/file.c
drivers/firmware/efi/libstub/x86-stub.c

index ad44783ae1287f2b1862978c60a078a5e20a09ff..a11257a90dd051a5a5fcbb836b990e77237458f8 100644 (file)
@@ -267,7 +267,7 @@ 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,
+       status = efi_load_initrd(image, &initrd_addr, &initrd_size, ULONG_MAX,
                                 efi_get_max_initrd_addr(dram_base, image_addr));
        if (status != EFI_SUCCESS)
                pr_efi_err("Failed initrd from command line!\n");
index 60d929469b8bae5e6c63ef9bd3d7bb1f894b8fde..d282d907cd332ce2bd8419896b47b1c941abb7a0 100644 (file)
@@ -619,6 +619,7 @@ efi_status_t efi_load_dtb(efi_loaded_image_t *image,
 efi_status_t efi_load_initrd(efi_loaded_image_t *image,
                             unsigned long *load_addr,
                             unsigned long *load_size,
-                            unsigned long max_addr);
+                            unsigned long soft_limit,
+                            unsigned long hard_limit);
 
 #endif
index 0d67432ed0678efbc23b688bb4ee72f33299bc77..be78f64f8d80467f49a5c2ddbfc05fa29b95be0d 100644 (file)
@@ -123,7 +123,8 @@ static int find_file_option(const efi_char16_t *cmdline, int cmdline_len,
 static efi_status_t handle_cmdline_files(efi_loaded_image_t *image,
                                         const efi_char16_t *optstr,
                                         int optstr_size,
-                                        unsigned long max_addr,
+                                        unsigned long soft_limit,
+                                        unsigned long hard_limit,
                                         unsigned long *load_addr,
                                         unsigned long *load_size)
 {
@@ -179,8 +180,15 @@ static efi_status_t handle_cmdline_files(efi_loaded_image_t *image,
                    round_up(alloc_size, EFI_ALLOC_ALIGN)) {
                        unsigned long old_addr = alloc_addr;
 
-                       status = efi_allocate_pages(alloc_size + size, &alloc_addr,
-                                                   max_addr);
+                       status = EFI_OUT_OF_RESOURCES;
+                       if (soft_limit < hard_limit)
+                               status = efi_allocate_pages(alloc_size + size,
+                                                           &alloc_addr,
+                                                           soft_limit);
+                       if (status == EFI_OUT_OF_RESOURCES)
+                               status = efi_allocate_pages(alloc_size + size,
+                                                           &alloc_addr,
+                                                           hard_limit);
                        if (status != EFI_SUCCESS) {
                                pr_efi_err("Failed to reallocate memory for files\n");
                                goto err_close_file;
@@ -236,14 +244,15 @@ efi_status_t efi_load_dtb(efi_loaded_image_t *image,
                          unsigned long *load_size)
 {
        return handle_cmdline_files(image, L"dtb=", sizeof(L"dtb=") - 2,
-                                   ULONG_MAX, load_addr, load_size);
+                                   ULONG_MAX, ULONG_MAX, load_addr, 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)
+                            unsigned long soft_limit,
+                            unsigned long hard_limit)
 {
        return handle_cmdline_files(image, L"initrd=", sizeof(L"initrd=") - 2,
-                                   max_addr, load_addr, load_size);
+                                   soft_limit, hard_limit, load_addr, load_size);
 }
index 39d04735f1c5e4fccc2c2f46b9aefacb90112a11..52a1a2df2071b80ff41cb31dc39ee6eba9805f48 100644 (file)
@@ -422,15 +422,8 @@ efi_status_t __efiapi efi_pe_entry(efi_handle_t handle,
                goto fail2;
 
        status = efi_load_initrd(image, &ramdisk_addr, &ramdisk_size,
-                                hdr->initrd_addr_max);
-
-       if (status != EFI_SUCCESS &&
-           hdr->xloadflags & XLF_CAN_BE_LOADED_ABOVE_4G) {
-               efi_printk("Trying to load files to higher address\n");
-               status = efi_load_initrd(image, &ramdisk_addr, &ramdisk_size,
-                                        ULONG_MAX);
-       }
-
+                                hdr->initrd_addr_max,
+                                above4g ? ULONG_MAX : hdr->initrd_addr_max);
        if (status != EFI_SUCCESS)
                goto fail2;
        hdr->ramdisk_image = ramdisk_addr & 0xffffffff;