summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorArd Biesheuvel <ardb@kernel.org>2020-09-10 17:09:45 +0300
committerArd Biesheuvel <ardb@kernel.org>2020-09-16 18:53:42 +0300
commit6208857b8f7ebdfe84e1be7573be4552a5896a0d (patch)
tree39ed3fecefb71f74bc9b30e3fa2eac17cf1ca115
parentf30f242fb1319e616fbcf94a43195a1c57db99b8 (diff)
efi/libstub: arm32: Base FDT and initrd placement on image address
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>
-rw-r--r--arch/arm/include/asm/efi.h23
-rw-r--r--arch/arm64/include/asm/efi.h5
-rw-r--r--drivers/firmware/efi/libstub/arm32-stub.c2
-rw-r--r--drivers/firmware/efi/libstub/efi-stub.c4
4 files changed, 16 insertions, 18 deletions
diff --git a/arch/arm/include/asm/efi.h b/arch/arm/include/asm/efi.h
index 5dcf3c6011b7..3ee4f4381985 100644
--- a/arch/arm/include/asm/efi.h
+++ b/arch/arm/include/asm/efi.h
@@ -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 {
diff --git a/arch/arm64/include/asm/efi.h b/arch/arm64/include/asm/efi.h
index d4ab3f73e7a3..973b14415271 100644
--- a/arch/arm64/include/asm/efi.h
+++ b/arch/arm64/include/asm/efi.h
@@ -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));
}
diff --git a/drivers/firmware/efi/libstub/arm32-stub.c b/drivers/firmware/efi/libstub/arm32-stub.c
index d08e5d55838c..bcf770c2ce02 100644
--- a/drivers/firmware/efi/libstub/arm32-stub.c
+++ b/drivers/firmware/efi/libstub/arm32-stub.c
@@ -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
diff --git a/drivers/firmware/efi/libstub/efi-stub.c b/drivers/firmware/efi/libstub/efi-stub.c
index a5a405d8ab44..65a0070010a1 100644
--- a/drivers/firmware/efi/libstub/efi-stub.c
+++ b/drivers/firmware/efi/libstub/efi-stub.c
@@ -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)