]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
efi/libstub: arm32: Base FDT and initrd placement on image address
authorArd Biesheuvel <ardb@kernel.org>
Thu, 10 Sep 2020 14:09:45 +0000 (17:09 +0300)
committerArd Biesheuvel <ardb@kernel.org>
Wed, 16 Sep 2020 15:53:42 +0000 (18:53 +0300)
The way we use the base of DRAM in the EFI stub is problematic as it
is ill defined what the base of DRAM actually means. There are some
restrictions on the placement of FDT and initrd which are defined in
terms of dram_base, but given that the placement of the kernel in
memory is what defines these boundaries (as on ARM, this is where the
linear region starts), it is better to use the image address in these
cases, and disregard dram_base altogether.

Reviewed-by: Maxim Uvarov <maxim.uvarov@linaro.org>
Tested-by: Maxim Uvarov <maxim.uvarov@linaro.org>
Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
arch/arm/include/asm/efi.h
arch/arm64/include/asm/efi.h
drivers/firmware/efi/libstub/arm32-stub.c
drivers/firmware/efi/libstub/efi-stub.c

index 5dcf3c6011b79109a623e90181fea45c76826c66..3ee4f43819850b3ad1e262f3ef02f0b16a0226ba 100644 (file)
@@ -66,25 +66,24 @@ static inline void efifb_setup_from_dmi(struct screen_info *si, const char *opt)
 #define MAX_UNCOMP_KERNEL_SIZE SZ_32M
 
 /*
- * The kernel zImage should preferably be located between 32 MB and 128 MB
- * from the base of DRAM. The min address leaves space for a maximal size
- * uncompressed image, and the max address is due to how the zImage decompressor
- * picks a destination address.
+ * phys-to-virt patching requires that the physical to virtual offset fits
+ * into the immediate field of an add/sub instruction, which comes down to the
+ * 24 least significant bits being zero, and so the offset should be a multiple
+ * of 16 MB. Since PAGE_OFFSET itself is a multiple of 16 MB, the physical
+ * base should be aligned to 16 MB as well.
  */
-#define ZIMAGE_OFFSET_LIMIT    SZ_128M
-#define MIN_ZIMAGE_OFFSET      MAX_UNCOMP_KERNEL_SIZE
+#define EFI_PHYS_ALIGN         SZ_16M
 
-/* on ARM, the FDT should be located in the first 128 MB of RAM */
-static inline unsigned long efi_get_max_fdt_addr(unsigned long dram_base)
+/* on ARM, the FDT should be located in a lowmem region */
+static inline unsigned long efi_get_max_fdt_addr(unsigned long image_addr)
 {
-       return dram_base + ZIMAGE_OFFSET_LIMIT;
+       return round_down(image_addr, EFI_PHYS_ALIGN) + SZ_512M;
 }
 
 /* on ARM, the initrd should be loaded in a lowmem region */
-static inline unsigned long efi_get_max_initrd_addr(unsigned long dram_base,
-                                                   unsigned long image_addr)
+static inline unsigned long efi_get_max_initrd_addr(unsigned long image_addr)
 {
-       return dram_base + SZ_512M;
+       return round_down(image_addr, EFI_PHYS_ALIGN) + SZ_512M;
 }
 
 struct efi_arm_entry_state {
index d4ab3f73e7a350810b148e849d227f70bdc305d7..973b144152711ace4bc6ee85c44926cebd253274 100644 (file)
@@ -65,7 +65,7 @@ efi_status_t __efi_rt_asm_wrapper(void *, const char *, ...);
        (SEGMENT_ALIGN > THREAD_ALIGN ? SEGMENT_ALIGN : THREAD_ALIGN)
 
 /* on arm64, the FDT may be located anywhere in system RAM */
-static inline unsigned long efi_get_max_fdt_addr(unsigned long dram_base)
+static inline unsigned long efi_get_max_fdt_addr(unsigned long image_addr)
 {
        return ULONG_MAX;
 }
@@ -80,8 +80,7 @@ static inline unsigned long efi_get_max_fdt_addr(unsigned long dram_base)
  * apply to other bootloaders, and are required for some kernel
  * configurations.
  */
-static inline unsigned long efi_get_max_initrd_addr(unsigned long dram_base,
-                                                   unsigned long image_addr)
+static inline unsigned long efi_get_max_initrd_addr(unsigned long image_addr)
 {
        return (image_addr & ~(SZ_1G - 1UL)) + (1UL << (VA_BITS_MIN - 1));
 }
index d08e5d55838c4d585526c29f108e99601866ae2f..bcf770c2ce02b344920f7868043cbe016c381e35 100644 (file)
@@ -252,7 +252,7 @@ efi_status_t handle_kernel_image(unsigned long *image_addr,
        efi_status_t status;
 
        /* use a 16 MiB aligned base for the decompressed kernel */
-       kernel_base = round_up(dram_base, SZ_16M) + TEXT_OFFSET;
+       kernel_base = round_up(dram_base, EFI_PHYS_ALIGN) + TEXT_OFFSET;
 
        /*
         * Note that some platforms (notably, the Raspberry Pi 2) put
index a5a405d8ab4447683b1f7e442d84a1f7056ae8f3..65a0070010a17b6953b1116753ecb62a4c2774de 100644 (file)
@@ -262,7 +262,7 @@ efi_status_t __efiapi efi_pe_entry(efi_handle_t handle,
                efi_info("Generating empty DTB\n");
 
        if (!efi_noinitrd) {
-               max_addr = efi_get_max_initrd_addr(dram_base, image_addr);
+               max_addr = efi_get_max_initrd_addr(image_addr);
                status = efi_load_initrd(image, &initrd_addr, &initrd_size,
                                         ULONG_MAX, max_addr);
                if (status != EFI_SUCCESS)
@@ -306,7 +306,7 @@ efi_status_t __efiapi efi_pe_entry(efi_handle_t handle,
        install_memreserve_table();
 
        status = allocate_new_fdt_and_exit_boot(handle, &fdt_addr,
-                                               efi_get_max_fdt_addr(dram_base),
+                                               efi_get_max_fdt_addr(image_addr),
                                                initrd_addr, initrd_size,
                                                cmdline_ptr, fdt_addr, fdt_size);
        if (status != EFI_SUCCESS)