* [PATCH 1/2] efi: add 'offset' param to efi_low_alloc()
2015-07-29 10:04 [PATCH 0/2] arm64/efi: fix kernel allocation at base of DRAM Ard Biesheuvel
@ 2015-07-29 10:04 ` Ard Biesheuvel
2015-07-30 14:01 ` Matt Fleming
2015-07-29 10:04 ` [PATCH 2/2] arm64/efi: use efi_low_alloc() with offset to allocate kernel Ard Biesheuvel
1 sibling, 1 reply; 5+ messages in thread
From: Ard Biesheuvel @ 2015-07-29 10:04 UTC (permalink / raw)
To: linux-arm-kernel
In some cases, e.g., when allocating memory for the arm64 kernel,
we need memory at a certain offset from an aligned boundary. So add
an offset parameter to efi_low_alloc(), and update the existing
callers to pass zero by default.
Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
---
arch/arm64/kernel/efi-stub.c | 2 +-
arch/x86/boot/compressed/eboot.c | 4 ++--
drivers/firmware/efi/libstub/efi-stub-helper.c | 20 +++++++++++++++-----
include/linux/efi.h | 2 +-
4 files changed, 19 insertions(+), 9 deletions(-)
diff --git a/arch/arm64/kernel/efi-stub.c b/arch/arm64/kernel/efi-stub.c
index f5374065ad53..d85a0b2098b3 100644
--- a/arch/arm64/kernel/efi-stub.c
+++ b/arch/arm64/kernel/efi-stub.c
@@ -29,7 +29,7 @@ efi_status_t __init handle_kernel_image(efi_system_table_t *sys_table,
if (*image_addr != (dram_base + TEXT_OFFSET)) {
kernel_memsize = kernel_size + (_end - _edata);
status = efi_low_alloc(sys_table, kernel_memsize + TEXT_OFFSET,
- SZ_2M, reserve_addr);
+ SZ_2M, 0, reserve_addr);
if (status != EFI_SUCCESS) {
pr_efi_err(sys_table, "Failed to relocate kernel\n");
return status;
diff --git a/arch/x86/boot/compressed/eboot.c b/arch/x86/boot/compressed/eboot.c
index 2c82bd150d43..33d1a72f4266 100644
--- a/arch/x86/boot/compressed/eboot.c
+++ b/arch/x86/boot/compressed/eboot.c
@@ -1077,7 +1077,7 @@ struct boot_params *make_boot_params(struct efi_config *c)
return NULL;
}
- status = efi_low_alloc(sys_table, 0x4000, 1,
+ status = efi_low_alloc(sys_table, 0x4000, 1, 0,
(unsigned long *)&boot_params);
if (status != EFI_SUCCESS) {
efi_printk(sys_table, "Failed to alloc lowmem for boot params\n");
@@ -1424,7 +1424,7 @@ struct boot_params *efi_main(struct efi_config *c,
}
gdt->size = 0x800;
- status = efi_low_alloc(sys_table, gdt->size, 8,
+ status = efi_low_alloc(sys_table, gdt->size, 8, 0,
(unsigned long *)&gdt->address);
if (status != EFI_SUCCESS) {
efi_printk(sys_table, "Failed to alloc mem for gdt\n");
diff --git a/drivers/firmware/efi/libstub/efi-stub-helper.c b/drivers/firmware/efi/libstub/efi-stub-helper.c
index f07d4a67fa76..67d1759781c5 100644
--- a/drivers/firmware/efi/libstub/efi-stub-helper.c
+++ b/drivers/firmware/efi/libstub/efi-stub-helper.c
@@ -226,7 +226,7 @@ fail:
*/
efi_status_t efi_low_alloc(efi_system_table_t *sys_table_arg,
unsigned long size, unsigned long align,
- unsigned long *addr)
+ unsigned long offset, unsigned long *addr)
{
unsigned long map_size, desc_size;
efi_memory_desc_t *map;
@@ -269,10 +269,19 @@ efi_status_t efi_low_alloc(efi_system_table_t *sys_table_arg,
* checks pointers against NULL. Skip the first 8
* bytes so we start at a nice even number.
*/
- if (start == 0x0)
+ if (start + offset == 0x0)
start += 8;
- start = round_up(start, align);
+ /*
+ * Check if the offset exceeds the misalignment of this region.
+ * In that case, we can round down instead of up, and the
+ * resulting start value will be correctly aligned and still
+ * point past the start of the region.
+ */
+ if (offset >= (start & (align - 1)))
+ start = round_down(start, align) + offset;
+ else
+ start = round_up(start, align) + offset;
if ((start + size) > end)
continue;
@@ -580,7 +589,7 @@ efi_status_t efi_relocate_kernel(efi_system_table_t *sys_table_arg,
* possible.
*/
if (status != EFI_SUCCESS) {
- status = efi_low_alloc(sys_table_arg, alloc_size, alignment,
+ status = efi_low_alloc(sys_table_arg, alloc_size, alignment, 0,
&new_addr);
}
if (status != EFI_SUCCESS) {
@@ -684,7 +693,8 @@ char *efi_convert_cmdline(efi_system_table_t *sys_table_arg,
options_bytes++; /* NUL termination */
- status = efi_low_alloc(sys_table_arg, options_bytes, 0, &cmdline_addr);
+ status = efi_low_alloc(sys_table_arg, options_bytes, 0, 0,
+ &cmdline_addr);
if (status != EFI_SUCCESS)
return NULL;
diff --git a/include/linux/efi.h b/include/linux/efi.h
index faafa1ad6ea7..e738e97632ba 100644
--- a/include/linux/efi.h
+++ b/include/linux/efi.h
@@ -1245,7 +1245,7 @@ efi_status_t efi_get_memory_map(efi_system_table_t *sys_table_arg,
efi_status_t efi_low_alloc(efi_system_table_t *sys_table_arg,
unsigned long size, unsigned long align,
- unsigned long *addr);
+ unsigned long offset, unsigned long *addr);
efi_status_t efi_high_alloc(efi_system_table_t *sys_table_arg,
unsigned long size, unsigned long align,
--
1.9.1
^ permalink raw reply related [flat|nested] 5+ messages in thread* [PATCH 2/2] arm64/efi: use efi_low_alloc() with offset to allocate kernel
2015-07-29 10:04 [PATCH 0/2] arm64/efi: fix kernel allocation at base of DRAM Ard Biesheuvel
2015-07-29 10:04 ` [PATCH 1/2] efi: add 'offset' param to efi_low_alloc() Ard Biesheuvel
@ 2015-07-29 10:04 ` Ard Biesheuvel
1 sibling, 0 replies; 5+ messages in thread
From: Ard Biesheuvel @ 2015-07-29 10:04 UTC (permalink / raw)
To: linux-arm-kernel
Now that efi_low_alloc() supports an offset parameter, we can use it
to allocate memory for the kernel at TEXT_OFFSET bytes above a 2 MB
aligned boundary directly. This prevents issues when the base of
DRAM is at 0x0, which efi_low_alloc() refuses to use as the address
of an allocation. It also helps when fewer than TEXT_OFFSET bytes are
occupied by the firmware at the base of DRAM, since efi_low_alloc()
will now do the rounding for us, and return 'base of DRAM + TEXT_OFFSET'
directly, regardless of whether any regions below it are in use.
Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
---
arch/arm64/kernel/efi-stub.c | 11 ++++++-----
1 file changed, 6 insertions(+), 5 deletions(-)
diff --git a/arch/arm64/kernel/efi-stub.c b/arch/arm64/kernel/efi-stub.c
index d85a0b2098b3..e3085b391570 100644
--- a/arch/arm64/kernel/efi-stub.c
+++ b/arch/arm64/kernel/efi-stub.c
@@ -23,21 +23,22 @@ efi_status_t __init handle_kernel_image(efi_system_table_t *sys_table,
{
efi_status_t status;
unsigned long kernel_size, kernel_memsize = 0;
+ unsigned long new_image_addr;
/* Relocate the image, if required. */
kernel_size = _edata - _text;
if (*image_addr != (dram_base + TEXT_OFFSET)) {
kernel_memsize = kernel_size + (_end - _edata);
- status = efi_low_alloc(sys_table, kernel_memsize + TEXT_OFFSET,
- SZ_2M, 0, reserve_addr);
+ status = efi_low_alloc(sys_table, kernel_memsize, SZ_2M,
+ TEXT_OFFSET, &new_image_addr);
if (status != EFI_SUCCESS) {
pr_efi_err(sys_table, "Failed to relocate kernel\n");
return status;
}
- memcpy((void *)*reserve_addr + TEXT_OFFSET, (void *)*image_addr,
+ memcpy((void *)new_image_addr, (void *)*image_addr,
kernel_size);
- *image_addr = *reserve_addr + TEXT_OFFSET;
- *reserve_size = kernel_memsize + TEXT_OFFSET;
+ *image_addr = new_image_addr;
+ *image_size = kernel_memsize;
}
--
1.9.1
^ permalink raw reply related [flat|nested] 5+ messages in thread