* [PATCH v2] arm64/efi: prefer AllocatePages() over efi_low_alloc() for vmlinux
@ 2015-07-24 11:38 Ard Biesheuvel
[not found] ` <1437737907-10477-1-git-send-email-ard.biesheuvel-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
0 siblings, 1 reply; 8+ messages in thread
From: Ard Biesheuvel @ 2015-07-24 11:38 UTC (permalink / raw)
To: linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
mark.rutland-5wv7dgnIgG8, msalter-H+wXaHxf7aLQT0dZR+AlfA,
linux-efi-u79uwXL29TY76Z2rM5mHXA,
matt.fleming-ral2JQCrhuEAvxtiuMwx3w, will.deacon-5wv7dgnIgG8
Cc: Ard Biesheuvel
When allocating memory for the kernel image, try the AllocatePages()
boot service to obtain memory at the preferred offset of
'dram_base + TEXT_OFFSET', and only revert to efi_low_alloc() if that
fails. This is the only way to allocate at the base of DRAM if DRAM
starts at 0x0, since efi_low_alloc() refuses to allocate at 0x0.
Tested-by: Haojian Zhuang <haojian.zhuang-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
Signed-off-by: Ard Biesheuvel <ard.biesheuvel-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
---
v2:
- reshuffle code flow to make it more logical, and have only a single
memcpy() invocation at the end of the function
---
arch/arm64/kernel/efi-stub.c | 41 ++++++++++++++++++++++++++++++++---------
1 file changed, 32 insertions(+), 9 deletions(-)
diff --git a/arch/arm64/kernel/efi-stub.c b/arch/arm64/kernel/efi-stub.c
index f5374065ad53..816120ece6bc 100644
--- a/arch/arm64/kernel/efi-stub.c
+++ b/arch/arm64/kernel/efi-stub.c
@@ -13,7 +13,7 @@
#include <asm/efi.h>
#include <asm/sections.h>
-efi_status_t __init handle_kernel_image(efi_system_table_t *sys_table,
+efi_status_t __init handle_kernel_image(efi_system_table_t *sys_table_arg,
unsigned long *image_addr,
unsigned long *image_size,
unsigned long *reserve_addr,
@@ -23,21 +23,44 @@ 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 nr_pages;
+ void *old_image_addr = (void *)*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, reserve_addr);
+
+ /*
+ * First, try a straight allocation at the preferred offset.
+ * This will work around the issue where, if dram_base == 0x0,
+ * efi_low_alloc() refuses to allocate at 0x0 (to prevent the
+ * address of the allocation to be mistaken for a FAIL return
+ * value or a NULL pointer). It will also ensure that, on
+ * platforms where the [dram_base, dram_base + TEXT_OFFSET)
+ * interval is partially occupied by the firmware (like on APM
+ * Mustang), we can still place the kernel at the address
+ * 'dram_base + TEXT_OFFSET'.
+ */
+ *image_addr = *reserve_addr = dram_base + TEXT_OFFSET;
+ nr_pages = round_up(kernel_memsize, EFI_ALLOC_ALIGN) /
+ EFI_PAGE_SIZE;
+ status = efi_call_early(allocate_pages, EFI_ALLOCATE_ADDRESS,
+ EFI_LOADER_DATA, nr_pages,
+ (efi_physical_addr_t *)reserve_addr);
if (status != EFI_SUCCESS) {
- pr_efi_err(sys_table, "Failed to relocate kernel\n");
- return status;
+ kernel_memsize += TEXT_OFFSET;
+ status = efi_low_alloc(sys_table_arg, kernel_memsize,
+ SZ_2M, reserve_addr);
+
+ if (status != EFI_SUCCESS) {
+ pr_efi_err(sys_table_arg, "Failed to relocate kernel\n");
+ return status;
+ }
+ *image_addr = *reserve_addr + TEXT_OFFSET;
}
- memcpy((void *)*reserve_addr + TEXT_OFFSET, (void *)*image_addr,
- kernel_size);
- *image_addr = *reserve_addr + TEXT_OFFSET;
- *reserve_size = kernel_memsize + TEXT_OFFSET;
+ memcpy((void *)*image_addr, old_image_addr, kernel_size);
+ *reserve_size = kernel_memsize;
}
--
1.9.1
^ permalink raw reply related [flat|nested] 8+ messages in thread[parent not found: <1437737907-10477-1-git-send-email-ard.biesheuvel-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>]
* Re: [PATCH v2] arm64/efi: prefer AllocatePages() over efi_low_alloc() for vmlinux [not found] ` <1437737907-10477-1-git-send-email-ard.biesheuvel-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org> @ 2015-07-24 13:04 ` Mark Rutland 2015-07-28 21:17 ` Matt Fleming 2015-10-27 21:15 ` Timur Tabi 2 siblings, 0 replies; 8+ messages in thread From: Mark Rutland @ 2015-07-24 13:04 UTC (permalink / raw) To: Ard Biesheuvel Cc: linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r@public.gmane.org, msalter-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org, linux-efi-u79uwXL29TY76Z2rM5mHXA@public.gmane.org, matt.fleming-ral2JQCrhuEAvxtiuMwx3w@public.gmane.org, Will Deacon On Fri, Jul 24, 2015 at 12:38:27PM +0100, Ard Biesheuvel wrote: > When allocating memory for the kernel image, try the AllocatePages() > boot service to obtain memory at the preferred offset of > 'dram_base + TEXT_OFFSET', and only revert to efi_low_alloc() if that > fails. This is the only way to allocate at the base of DRAM if DRAM > starts at 0x0, since efi_low_alloc() refuses to allocate at 0x0. > > Tested-by: Haojian Zhuang <haojian.zhuang-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org> > Signed-off-by: Ard Biesheuvel <ard.biesheuvel-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org> Reviewed-by: Mark Rutland <mark.rutland-5wv7dgnIgG8@public.gmane.org> Mark. > --- > v2: > - reshuffle code flow to make it more logical, and have only a single > memcpy() invocation at the end of the function > --- > arch/arm64/kernel/efi-stub.c | 41 ++++++++++++++++++++++++++++++++--------- > 1 file changed, 32 insertions(+), 9 deletions(-) > > diff --git a/arch/arm64/kernel/efi-stub.c b/arch/arm64/kernel/efi-stub.c > index f5374065ad53..816120ece6bc 100644 > --- a/arch/arm64/kernel/efi-stub.c > +++ b/arch/arm64/kernel/efi-stub.c > @@ -13,7 +13,7 @@ > #include <asm/efi.h> > #include <asm/sections.h> > > -efi_status_t __init handle_kernel_image(efi_system_table_t *sys_table, > +efi_status_t __init handle_kernel_image(efi_system_table_t *sys_table_arg, > unsigned long *image_addr, > unsigned long *image_size, > unsigned long *reserve_addr, > @@ -23,21 +23,44 @@ 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 nr_pages; > + void *old_image_addr = (void *)*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, reserve_addr); > + > + /* > + * First, try a straight allocation at the preferred offset. > + * This will work around the issue where, if dram_base == 0x0, > + * efi_low_alloc() refuses to allocate at 0x0 (to prevent the > + * address of the allocation to be mistaken for a FAIL return > + * value or a NULL pointer). It will also ensure that, on > + * platforms where the [dram_base, dram_base + TEXT_OFFSET) > + * interval is partially occupied by the firmware (like on APM > + * Mustang), we can still place the kernel at the address > + * 'dram_base + TEXT_OFFSET'. > + */ > + *image_addr = *reserve_addr = dram_base + TEXT_OFFSET; > + nr_pages = round_up(kernel_memsize, EFI_ALLOC_ALIGN) / > + EFI_PAGE_SIZE; > + status = efi_call_early(allocate_pages, EFI_ALLOCATE_ADDRESS, > + EFI_LOADER_DATA, nr_pages, > + (efi_physical_addr_t *)reserve_addr); > if (status != EFI_SUCCESS) { > - pr_efi_err(sys_table, "Failed to relocate kernel\n"); > - return status; > + kernel_memsize += TEXT_OFFSET; > + status = efi_low_alloc(sys_table_arg, kernel_memsize, > + SZ_2M, reserve_addr); > + > + if (status != EFI_SUCCESS) { > + pr_efi_err(sys_table_arg, "Failed to relocate kernel\n"); > + return status; > + } > + *image_addr = *reserve_addr + TEXT_OFFSET; > } > - memcpy((void *)*reserve_addr + TEXT_OFFSET, (void *)*image_addr, > - kernel_size); > - *image_addr = *reserve_addr + TEXT_OFFSET; > - *reserve_size = kernel_memsize + TEXT_OFFSET; > + memcpy((void *)*image_addr, old_image_addr, kernel_size); > + *reserve_size = kernel_memsize; > } > > > -- > 1.9.1 > ^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH v2] arm64/efi: prefer AllocatePages() over efi_low_alloc() for vmlinux [not found] ` <1437737907-10477-1-git-send-email-ard.biesheuvel-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org> 2015-07-24 13:04 ` Mark Rutland @ 2015-07-28 21:17 ` Matt Fleming [not found] ` <20150728211752.GE2773-mF/unelCI9GS6iBeEJttW/XRex20P6io@public.gmane.org> 2015-10-27 21:15 ` Timur Tabi 2 siblings, 1 reply; 8+ messages in thread From: Matt Fleming @ 2015-07-28 21:17 UTC (permalink / raw) To: Ard Biesheuvel Cc: linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r, mark.rutland-5wv7dgnIgG8, msalter-H+wXaHxf7aLQT0dZR+AlfA, linux-efi-u79uwXL29TY76Z2rM5mHXA, matt.fleming-ral2JQCrhuEAvxtiuMwx3w, will.deacon-5wv7dgnIgG8 On Fri, 24 Jul, at 01:38:27PM, Ard Biesheuvel wrote: > When allocating memory for the kernel image, try the AllocatePages() > boot service to obtain memory at the preferred offset of > 'dram_base + TEXT_OFFSET', and only revert to efi_low_alloc() if that > fails. This is the only way to allocate at the base of DRAM if DRAM > starts at 0x0, since efi_low_alloc() refuses to allocate at 0x0. > > Tested-by: Haojian Zhuang <haojian.zhuang-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org> > Signed-off-by: Ard Biesheuvel <ard.biesheuvel-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org> > --- > v2: > - reshuffle code flow to make it more logical, and have only a single > memcpy() invocation at the end of the function > --- > arch/arm64/kernel/efi-stub.c | 41 ++++++++++++++++++++++++++++++++--------- > 1 file changed, 32 insertions(+), 9 deletions(-) Would it be easier if we allow efi_low_alloc() to return 0x0 for some uses? If you don't need the preference for low allocations, probably not, but I don't want to see us working around limitations in efi_low_alloc() instead of just fixing it. -- Matt Fleming, Intel Open Source Technology Center ^ permalink raw reply [flat|nested] 8+ messages in thread
[parent not found: <20150728211752.GE2773-mF/unelCI9GS6iBeEJttW/XRex20P6io@public.gmane.org>]
* Re: [PATCH v2] arm64/efi: prefer AllocatePages() over efi_low_alloc() for vmlinux [not found] ` <20150728211752.GE2773-mF/unelCI9GS6iBeEJttW/XRex20P6io@public.gmane.org> @ 2015-07-28 21:24 ` Ard Biesheuvel [not found] ` <CAKv+Gu_EtOV8wannMLG87ai_x3ARu4rUSo9D6w2DQ+Kb5Kjn-A-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org> 0 siblings, 1 reply; 8+ messages in thread From: Ard Biesheuvel @ 2015-07-28 21:24 UTC (permalink / raw) To: Matt Fleming Cc: linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r@public.gmane.org, Mark Rutland, Mark Salter, linux-efi-u79uwXL29TY76Z2rM5mHXA@public.gmane.org, Matt Fleming, Will Deacon On 28 July 2015 at 23:17, Matt Fleming <matt-mF/unelCI9GS6iBeEJttW/XRex20P6io@public.gmane.org> wrote: > On Fri, 24 Jul, at 01:38:27PM, Ard Biesheuvel wrote: >> When allocating memory for the kernel image, try the AllocatePages() >> boot service to obtain memory at the preferred offset of >> 'dram_base + TEXT_OFFSET', and only revert to efi_low_alloc() if that >> fails. This is the only way to allocate at the base of DRAM if DRAM >> starts at 0x0, since efi_low_alloc() refuses to allocate at 0x0. >> >> Tested-by: Haojian Zhuang <haojian.zhuang-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org> >> Signed-off-by: Ard Biesheuvel <ard.biesheuvel-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org> >> --- >> v2: >> - reshuffle code flow to make it more logical, and have only a single >> memcpy() invocation at the end of the function >> --- >> arch/arm64/kernel/efi-stub.c | 41 ++++++++++++++++++++++++++++++++--------- >> 1 file changed, 32 insertions(+), 9 deletions(-) > > Would it be easier if we allow efi_low_alloc() to return 0x0 for some > uses? If you don't need the preference for low allocations, probably > not, but I don't want to see us working around limitations in > efi_low_alloc() instead of just fixing it. > This workaround fixes another issue as well: the arm64 kernel needs to be loaded 512 KB above a 2MB aligned boundary, and using efi_low_alloc() as we do loses (2 MB - 512 KB) at the bottom if part of that 512 KB is occupied, since efi_low_alloc() is not aware of the fact that the first 512 KB will remain unused. What would be most helpful is if efi_low_alloc() could take an offset param in addition to the alignment, i.e., alignment == 2MB and offset == 512 KB. The offset would default to 0, reverting to the original behavior. If you'd be ok with such a change, I can propose it instead, and wire it up into this function. -- Ard. ^ permalink raw reply [flat|nested] 8+ messages in thread
[parent not found: <CAKv+Gu_EtOV8wannMLG87ai_x3ARu4rUSo9D6w2DQ+Kb5Kjn-A-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>]
* Re: [PATCH v2] arm64/efi: prefer AllocatePages() over efi_low_alloc() for vmlinux [not found] ` <CAKv+Gu_EtOV8wannMLG87ai_x3ARu4rUSo9D6w2DQ+Kb5Kjn-A-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org> @ 2015-07-28 22:06 ` Matt Fleming 2015-07-29 10:27 ` Will Deacon 1 sibling, 0 replies; 8+ messages in thread From: Matt Fleming @ 2015-07-28 22:06 UTC (permalink / raw) To: Ard Biesheuvel Cc: linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r@public.gmane.org, Mark Rutland, Mark Salter, linux-efi-u79uwXL29TY76Z2rM5mHXA@public.gmane.org, Matt Fleming, Will Deacon On Tue, 28 Jul, at 11:24:23PM, Ard Biesheuvel wrote: > > This workaround fixes another issue as well: the arm64 kernel needs to > be loaded 512 KB above a 2MB aligned boundary, and using > efi_low_alloc() as we do loses (2 MB - 512 KB) at the bottom if part > of that 512 KB is occupied, since efi_low_alloc() is not aware of the > fact that the first 512 KB will remain unused. > > What would be most helpful is if efi_low_alloc() could take an offset > param in addition to the alignment, i.e., alignment == 2MB and offset > == 512 KB. The offset would default to 0, reverting to the original > behavior. > > If you'd be ok with such a change, I can propose it instead, and wire > it up into this function. It's probably because it's late but I'm having trouble thinking this change through fully. If it's not too much work, sure, please go ahead and propose a patch, even the untested, uncompiled "this is what I'm thinking" type. -- Matt Fleming, Intel Open Source Technology Center ^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH v2] arm64/efi: prefer AllocatePages() over efi_low_alloc() for vmlinux [not found] ` <CAKv+Gu_EtOV8wannMLG87ai_x3ARu4rUSo9D6w2DQ+Kb5Kjn-A-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org> 2015-07-28 22:06 ` Matt Fleming @ 2015-07-29 10:27 ` Will Deacon 1 sibling, 0 replies; 8+ messages in thread From: Will Deacon @ 2015-07-29 10:27 UTC (permalink / raw) To: Ard Biesheuvel Cc: Matt Fleming, linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r@public.gmane.org, Mark Rutland, msalter-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org, linux-efi-u79uwXL29TY76Z2rM5mHXA@public.gmane.org, Matt Fleming On Tue, Jul 28, 2015 at 10:24:23PM +0100, Ard Biesheuvel wrote: > On 28 July 2015 at 23:17, Matt Fleming <matt-mF/unelCI9GS6iBeEJttW/XRex20P6io@public.gmane.org> wrote: > > On Fri, 24 Jul, at 01:38:27PM, Ard Biesheuvel wrote: > >> When allocating memory for the kernel image, try the AllocatePages() > >> boot service to obtain memory at the preferred offset of > >> 'dram_base + TEXT_OFFSET', and only revert to efi_low_alloc() if that > >> fails. This is the only way to allocate at the base of DRAM if DRAM > >> starts at 0x0, since efi_low_alloc() refuses to allocate at 0x0. > >> > >> Tested-by: Haojian Zhuang <haojian.zhuang-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org> > >> Signed-off-by: Ard Biesheuvel <ard.biesheuvel-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org> > >> --- > >> v2: > >> - reshuffle code flow to make it more logical, and have only a single > >> memcpy() invocation at the end of the function > >> --- > >> arch/arm64/kernel/efi-stub.c | 41 ++++++++++++++++++++++++++++++++--------- > >> 1 file changed, 32 insertions(+), 9 deletions(-) > > > > Would it be easier if we allow efi_low_alloc() to return 0x0 for some > > uses? If you don't need the preference for low allocations, probably > > not, but I don't want to see us working around limitations in > > efi_low_alloc() instead of just fixing it. > > > > This workaround fixes another issue as well: the arm64 kernel needs to > be loaded 512 KB above a 2MB aligned boundary, and using > efi_low_alloc() as we do loses (2 MB - 512 KB) at the bottom if part > of that 512 KB is occupied, since efi_low_alloc() is not aware of the > fact that the first 512 KB will remain unused. > > What would be most helpful is if efi_low_alloc() could take an offset > param in addition to the alignment, i.e., alignment == 2MB and offset > == 512 KB. The offset would default to 0, reverting to the original > behavior. > > If you'd be ok with such a change, I can propose it instead, and wire > it up into this function. I already merged the original patch, so if you propose anything extra, please do it on top of that! Will ^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH v2] arm64/efi: prefer AllocatePages() over efi_low_alloc() for vmlinux [not found] ` <1437737907-10477-1-git-send-email-ard.biesheuvel-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org> 2015-07-24 13:04 ` Mark Rutland 2015-07-28 21:17 ` Matt Fleming @ 2015-10-27 21:15 ` Timur Tabi 2 siblings, 0 replies; 8+ messages in thread From: Timur Tabi @ 2015-10-27 21:15 UTC (permalink / raw) To: Ard Biesheuvel Cc: linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r@public.gmane.org, Mark Rutland, msalter-H+wXaHxf7aLQT0dZR+AlfA, linux-efi-u79uwXL29TY76Z2rM5mHXA, matt.fleming-ral2JQCrhuEAvxtiuMwx3w, Will Deacon On Fri, Jul 24, 2015 at 6:38 AM, Ard Biesheuvel <ard.biesheuvel-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org> wrote: > > + /* > + * First, try a straight allocation at the preferred offset. > + * This will work around the issue where, if dram_base == 0x0, > + * efi_low_alloc() refuses to allocate at 0x0 (to prevent the > + * address of the allocation to be mistaken for a FAIL return > + * value or a NULL pointer). It will also ensure that, on > + * platforms where the [dram_base, dram_base + TEXT_OFFSET) > + * interval is partially occupied by the firmware (like on APM > + * Mustang), we can still place the kernel at the address > + * 'dram_base + TEXT_OFFSET'. > + */ > + *image_addr = *reserve_addr = dram_base + TEXT_OFFSET; > + nr_pages = round_up(kernel_memsize, EFI_ALLOC_ALIGN) / > + EFI_PAGE_SIZE; > + status = efi_call_early(allocate_pages, EFI_ALLOCATE_ADDRESS, > + EFI_LOADER_DATA, nr_pages, > + (efi_physical_addr_t *)reserve_addr); This causes our kernel to crash, because on our system, dram_base is not 2MB aligned. I'll be posting a patch soon that fixes this. -- Qualcomm Innovation Center, Inc. The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project. ^ permalink raw reply [flat|nested] 8+ messages in thread
[parent not found: <55B0D4E4.9030403@redhat.com>]
[parent not found: <55B0D4E4.9030403-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>]
* [PATCH v2] arm64/efi: prefer AllocatePages() over efi_low_alloc() for vmlinux [not found] ` <55B0D4E4.9030403-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org> @ 2015-07-23 13:23 ` Ard Biesheuvel 0 siblings, 0 replies; 8+ messages in thread From: Ard Biesheuvel @ 2015-07-23 13:23 UTC (permalink / raw) To: lersek-H+wXaHxf7aLQT0dZR+AlfA, matt.fleming-ral2JQCrhuEAvxtiuMwx3w, leif.lindholm-QSEj5FYQhm4dnm+yROfE0A, haojian.zhuang-QSEj5FYQhm4dnm+yROfE0A, edk2-devel-hn68Rpc1hR1g9hUCZPvPmw Cc: linux-efi-u79uwXL29TY76Z2rM5mHXA, Ard Biesheuvel Hello Haojian, Could you please try this version instead? -- Ard. -------8<--------- When allocating memory for the kernel image, try the AllocatePages() boot service to obtain memory at the preferred offset of 'dram_base + TEXT_OFFSET', and only revert to efi_low_alloc() if that fails. This is the only way to allocate at the base of DRAM if DRAM starts at 0x0, since efi_low_alloc() refuses to allocate at 0x0. Signed-off-by: Ard Biesheuvel <ard.biesheuvel-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org> --- v2: - set *reserve_addr before calling AllocatePages() arch/arm64/kernel/efi-stub.c | 45 ++++++++++++++++---- 1 file changed, 37 insertions(+), 8 deletions(-) diff --git a/arch/arm64/kernel/efi-stub.c b/arch/arm64/kernel/efi-stub.c index f5374065ad53..894cad555955 100644 --- a/arch/arm64/kernel/efi-stub.c +++ b/arch/arm64/kernel/efi-stub.c @@ -13,7 +13,7 @@ #include <asm/efi.h> #include <asm/sections.h> -efi_status_t __init handle_kernel_image(efi_system_table_t *sys_table, +efi_status_t __init handle_kernel_image(efi_system_table_t *sys_table_arg, unsigned long *image_addr, unsigned long *image_size, unsigned long *reserve_addr, @@ -23,21 +23,50 @@ 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 pgnum; /* 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, reserve_addr); + + // + // First, try a straight allocation at the preferred offset. + // This will work around the issue where, if dram_base == 0x0, + // efi_low_alloc() refuses to allocate at 0x0 (to prevent the + // address of the allocation to be mistaken for a FAIL return + // value or a NULL pointer). It will also ensure that, on + // platforms where the [dram_base, dram_base + TEXT_OFFSET) + // interval is partially occupied by the firmware (like on APM + // Mustang), we can still place the kernel at the address + // 'dram_base + TEXT_OFFSET'. + // + pgnum = round_up(kernel_memsize, EFI_PAGE_SIZE) / EFI_PAGE_SIZE; + status = efi_call_early(allocate_pages, EFI_ALLOCATE_ADDRESS, + EFI_LOADER_DATA, pgnum, + (efi_physical_addr_t *)reserve_addr); + if (status == EFI_SUCCESS) { + memcpy((void *)*reserve_addr, (void *)*image_addr, + kernel_size); + *image_addr = *reserve_addr; + *reserve_size = kernel_memsize; + } else { + status = efi_low_alloc(sys_table_arg, + kernel_memsize + TEXT_OFFSET, + SZ_2M, reserve_addr); + + if (status == EFI_SUCCESS) { + memcpy((void *)*reserve_addr + TEXT_OFFSET, + (void *)*image_addr, + kernel_size); + *image_addr = *reserve_addr + TEXT_OFFSET; + *reserve_size = kernel_memsize + TEXT_OFFSET; + } + } if (status != EFI_SUCCESS) { - pr_efi_err(sys_table, "Failed to relocate kernel\n"); + pr_efi_err(sys_table_arg, "Failed to relocate kernel\n"); return status; } - memcpy((void *)*reserve_addr + TEXT_OFFSET, (void *)*image_addr, - kernel_size); - *image_addr = *reserve_addr + TEXT_OFFSET; - *reserve_size = kernel_memsize + TEXT_OFFSET; } -- 1.9.1 ^ permalink raw reply related [flat|nested] 8+ messages in thread
end of thread, other threads:[~2015-10-27 21:15 UTC | newest]
Thread overview: 8+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2015-07-24 11:38 [PATCH v2] arm64/efi: prefer AllocatePages() over efi_low_alloc() for vmlinux Ard Biesheuvel
[not found] ` <1437737907-10477-1-git-send-email-ard.biesheuvel-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
2015-07-24 13:04 ` Mark Rutland
2015-07-28 21:17 ` Matt Fleming
[not found] ` <20150728211752.GE2773-mF/unelCI9GS6iBeEJttW/XRex20P6io@public.gmane.org>
2015-07-28 21:24 ` Ard Biesheuvel
[not found] ` <CAKv+Gu_EtOV8wannMLG87ai_x3ARu4rUSo9D6w2DQ+Kb5Kjn-A-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2015-07-28 22:06 ` Matt Fleming
2015-07-29 10:27 ` Will Deacon
2015-10-27 21:15 ` Timur Tabi
[not found] <55B0D4E4.9030403@redhat.com>
[not found] ` <55B0D4E4.9030403-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
2015-07-23 13:23 ` Ard Biesheuvel
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for NNTP newsgroup(s).