Re: [RFC PATCH] arm64/efi: efistub: reuse EFI mapping for Image if it is lower

2014-07-16 Thread Mark Rutland
Hi Ard,

On Tue, Jul 15, 2014 at 05:50:30PM +0100, Ard Biesheuvel wrote:
 The EFI loader may load Image at any available offset. This means Image may
 reside very close to or at the base of DRAM, in which case the relocation
 done by efi_entry() results in Image being moved up in memory, which is
 undesirable (memory below the kernel is currently not usable).

Rather than complicating this path I would prefer that we fixed not
being able to address memory below stext - TEXT_OFFSET. That would
simplify the bootloader's job regardless of UEFI, as any loader can then
simply place the kernel at a 2MB-aligned address + TEXT_OFFSET (the
kernel would have to not span a 512MB boundary to keep the initial page
tables simple, but that's still a weaker requirement than what we
currently need).

The approach taken in this patch seems sane for the current way the VA
space is laid out, but if we're not currently wasting an absurd amount
of memory I'd rather we got the VA layout fixed such that we can address
memory below the kernel image.

How much memory are we seeing wasted as a result of the existing
relocation code, and how often?

[...]

   /*
 +  * Check whether the original allocation done by the EFI loader is more
 +  * favorable (i.e., closer to the base of DRAM) than the new one created
 +  * by efi_entry(). If so, reuse the original one.
 +  */
 + adr x3, 0f
 + cmp x3, x0
 + bgt 1f  // this image is loaded higher, so just proceed normally
 +
 + /*
 +  * Jump into the relocated image so we can move the original Image to
 +  * a 2 MB boundary + TEXT_OFFSET inside the original mapping without
 +  * overwriting ourselves.
 +  */
 + sub x3, x3, x22 // subtract current base offset
 + add x3, x3, x0  // add base offset of relocated image
 + br  x3  // jump to next line, but in relocated image

At this point I don't believe the necessary icache maintenance + isb
have occurred to make the new image visible to the I-side and to ensure
we don't have any stale prefetched instructions in the pipeline. That
still seems to happen later. Have I missed something?

 +
 +0:   mov x1, x0  // copy from relocated Image
 + sub x0, x22, #1 // copy to base of original Image
 + orr x0, x0, #(SZ_2M - 1)// .. rounded up to 2 MB
 + ldr x3, =(TEXT_OFFSET + 1)  // .. plus TEXT_OFFSET
 + add x0, x0, x3
 + mov x2, x24 // copy 'size of Image' bytes
 + bl  memcpy
 + add x21, x0, x23// add stext_offset to entry point
 +1:
 + /*
* Flush dcache covering current runtime addresses
* of kernel text/data. Then flush all of icache.
*/
 - adrpx1, _text
 - add x1, x1, #:lo12:_text
 - adrpx2, _edata
 - add x2, x2, #:lo12:_edata
 - sub x1, x2, x1
 -
 + mov x1, x24 // size of Image
   bl  __flush_dcache_area
   ic  ialluis

Cheers,
Mark.
--
To unsubscribe from this list: send the line unsubscribe linux-efi in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: [RFC PATCH] arm64/efi: efistub: reuse EFI mapping for Image if it is lower

2014-07-16 Thread Mark Salter
On Tue, 2014-07-15 at 18:50 +0200, Ard Biesheuvel wrote:
 The EFI loader may load Image at any available offset. This means Image may
 reside very close to or at the base of DRAM, in which case the relocation
 done by efi_entry() results in Image being moved up in memory, which is
 undesirable (memory below the kernel is currently not usable).
 
 To work around this, we check in the stub whether the relocated offset is 
 higher
 than the original offset. If this is the case, the original and relocated 
 Images
 switch roles, and we move the original Image inside its original lower mapping
 while executing from the relocated Image.
 
 To ensure the original mapping has sufficient size, we add 2 megs + 
 TEXT_OFFSET
 of padding to the PE/COFF .text section, this should be sufficient to cover
 rounding and adding TEXT_OFFSET.
 
 Signed-off-by: Ard Biesheuvel ard.biesheu...@linaro.org
 ---
 
 This was tested on a Foundation Model using the patch below, which forces the
 Image to be loaded at 0x8000 (base of DRAM).
 
 diff --git a/arch/arm64/kernel/head.S b/arch/arm64/kernel/head.S
 index 2b7bd5eff776..eeadc073bad3 100644
 --- a/arch/arm64/kernel/head.S
 +++ b/arch/arm64/kernel/head.S
 @@ -138,12 +138,12 @@ pe_header:
   .short  0
  coff_header:
   .short  0xaa64  // AArch64
 - .short  2   // nr_sections
 + .short  1   // nr_sections
   .long   0   // TimeDateStamp
   .long   0   // PointerToSymbolTable
   .long   1   // NumberOfSymbols
   .short  section_table - optional_header // SizeOfOptionalHeader
 - .short  0x206   // Characteristics.
 + .short  0x207   // Characteristics.
   // IMAGE_FILE_DEBUG_STRIPPED |
   // IMAGE_FILE_EXECUTABLE_IMAGE |
   // IMAGE_FILE_LINE_NUMS_STRIPPED
 @@ -158,7 +158,7 @@ optional_header:
   .long   stext_offset// BaseOfCode
  
  extra_header_fields:
 - .quad   0   // ImageBase
 + .quad   0x8000  // ImageBase
   .long   0x20// SectionAlignment
   .long   0x8 // FileAlignment
   .short  0   // MajorOperatingSystemVersion
 @@ -193,6 +193,7 @@ extra_header_fields:
   // Section table
  section_table:
  
 +#if 0
   /*
* The EFI application loader requires a relocation section
* because EFI applications must be relocatable.  This is a
 @@ -212,6 +213,7 @@ section_table:
   .long   0x42100040  // Characteristics (section flags)
  
 
 +#endif
   .ascii  .text
   .byte   0
   .byte   0
 
 
  arch/arm64/kernel/Makefile|  1 +
  arch/arm64/kernel/efi-entry.S | 48 
 +--
  arch/arm64/kernel/head.S  |  7 ---
  3 files changed, 42 insertions(+), 14 deletions(-)
 
 diff --git a/arch/arm64/kernel/Makefile b/arch/arm64/kernel/Makefile
 index cdaedad3afe5..d55da3cd8a97 100644
 --- a/arch/arm64/kernel/Makefile
 +++ b/arch/arm64/kernel/Makefile
 @@ -6,6 +6,7 @@ CPPFLAGS_vmlinux.lds  := -DTEXT_OFFSET=$(TEXT_OFFSET)
  AFLAGS_head.o:= -DTEXT_OFFSET=$(TEXT_OFFSET)
  CFLAGS_efi-stub.o:= -DTEXT_OFFSET=$(TEXT_OFFSET) \
  -I$(src)/../../../scripts/dtc/libfdt
 +AFLAGS_efi-entry.o   := -DTEXT_OFFSET=$(TEXT_OFFSET)
  
  CFLAGS_REMOVE_ftrace.o = -pg
  CFLAGS_REMOVE_insn.o = -pg
 diff --git a/arch/arm64/kernel/efi-entry.S b/arch/arm64/kernel/efi-entry.S
 index a0016d3a17da..d154f3c73937 100644
 --- a/arch/arm64/kernel/efi-entry.S
 +++ b/arch/arm64/kernel/efi-entry.S
 @@ -11,6 +11,7 @@
   */
  #include linux/linkage.h
  #include linux/init.h
 +#include linux/sizes.h
  
  #include asm/assembler.h
  
 @@ -45,10 +46,13 @@ ENTRY(efi_stub_entry)
* efi_system_table_t *sys_table,
* unsigned long *image_addr) ;
*/
 - adrpx8, _text
 - add x8, x8, #:lo12:_text
 + adrpx22, _text
 + add x22, x22, #:lo12:_text  // x22: base of Image

Why change x8 to x22? Seems unnecessary. Not only that, it is
callee-saved, but you don't save it. This could cause a problem
if boot fails and we try to return to firmware.

 + adrpx24, _edata
 + add x24, x24, #:lo12:_edata
 + sub x24, x24, x22   // x24: size of Image

Should use a caller-saved register instead of x24.

   add x2, sp, 16
 - str x8, [x2]
 + str x22, [x2]
   bl  efi_entry
   cmn x0, #1
   b.eqefi_load_fail
 @@ -61,19 +65,41 @@ ENTRY(efi_stub_entry)
*/
   mov x20, x0  

Re: [RFC PATCH] arm64/efi: efistub: reuse EFI mapping for Image if it is lower

2014-07-16 Thread Ard Biesheuvel
On 16 July 2014 16:10, Mark Salter msal...@redhat.com wrote:
 On Tue, 2014-07-15 at 18:50 +0200, Ard Biesheuvel wrote:
 The EFI loader may load Image at any available offset. This means Image may
 reside very close to or at the base of DRAM, in which case the relocation
 done by efi_entry() results in Image being moved up in memory, which is
 undesirable (memory below the kernel is currently not usable).

 To work around this, we check in the stub whether the relocated offset is 
 higher
 than the original offset. If this is the case, the original and relocated 
 Images
 switch roles, and we move the original Image inside its original lower 
 mapping
 while executing from the relocated Image.

 To ensure the original mapping has sufficient size, we add 2 megs + 
 TEXT_OFFSET
 of padding to the PE/COFF .text section, this should be sufficient to cover
 rounding and adding TEXT_OFFSET.

 Signed-off-by: Ard Biesheuvel ard.biesheu...@linaro.org
 ---

 This was tested on a Foundation Model using the patch below, which forces the
 Image to be loaded at 0x8000 (base of DRAM).

 diff --git a/arch/arm64/kernel/head.S b/arch/arm64/kernel/head.S
 index 2b7bd5eff776..eeadc073bad3 100644
 --- a/arch/arm64/kernel/head.S
 +++ b/arch/arm64/kernel/head.S
 @@ -138,12 +138,12 @@ pe_header:
   .short  0
  coff_header:
   .short  0xaa64  // AArch64
 - .short  2   // nr_sections
 + .short  1   // nr_sections
   .long   0   // TimeDateStamp
   .long   0   // PointerToSymbolTable
   .long   1   // NumberOfSymbols
   .short  section_table - optional_header // SizeOfOptionalHeader
 - .short  0x206   // Characteristics.
 + .short  0x207   // Characteristics.
   // IMAGE_FILE_DEBUG_STRIPPED |
   // IMAGE_FILE_EXECUTABLE_IMAGE 
 |
   // 
 IMAGE_FILE_LINE_NUMS_STRIPPED
 @@ -158,7 +158,7 @@ optional_header:
   .long   stext_offset// BaseOfCode

  extra_header_fields:
 - .quad   0   // ImageBase
 + .quad   0x8000  // ImageBase
   .long   0x20// SectionAlignment
   .long   0x8 // FileAlignment
   .short  0   // MajorOperatingSystemVersion
 @@ -193,6 +193,7 @@ extra_header_fields:
   // Section table
  section_table:

 +#if 0
   /*
* The EFI application loader requires a relocation section
* because EFI applications must be relocatable.  This is a
 @@ -212,6 +213,7 @@ section_table:
   .long   0x42100040  // Characteristics (section flags)


 +#endif
   .ascii  .text
   .byte   0
   .byte   0


  arch/arm64/kernel/Makefile|  1 +
  arch/arm64/kernel/efi-entry.S | 48 
 +--
  arch/arm64/kernel/head.S  |  7 ---
  3 files changed, 42 insertions(+), 14 deletions(-)

 diff --git a/arch/arm64/kernel/Makefile b/arch/arm64/kernel/Makefile
 index cdaedad3afe5..d55da3cd8a97 100644
 --- a/arch/arm64/kernel/Makefile
 +++ b/arch/arm64/kernel/Makefile
 @@ -6,6 +6,7 @@ CPPFLAGS_vmlinux.lds  := -DTEXT_OFFSET=$(TEXT_OFFSET)
  AFLAGS_head.o:= -DTEXT_OFFSET=$(TEXT_OFFSET)
  CFLAGS_efi-stub.o:= -DTEXT_OFFSET=$(TEXT_OFFSET) \
  -I$(src)/../../../scripts/dtc/libfdt
 +AFLAGS_efi-entry.o   := -DTEXT_OFFSET=$(TEXT_OFFSET)

  CFLAGS_REMOVE_ftrace.o = -pg
  CFLAGS_REMOVE_insn.o = -pg
 diff --git a/arch/arm64/kernel/efi-entry.S b/arch/arm64/kernel/efi-entry.S
 index a0016d3a17da..d154f3c73937 100644
 --- a/arch/arm64/kernel/efi-entry.S
 +++ b/arch/arm64/kernel/efi-entry.S
 @@ -11,6 +11,7 @@
   */
  #include linux/linkage.h
  #include linux/init.h
 +#include linux/sizes.h

  #include asm/assembler.h

 @@ -45,10 +46,13 @@ ENTRY(efi_stub_entry)
* efi_system_table_t *sys_table,
* unsigned long *image_addr) ;
*/
 - adrpx8, _text
 - add x8, x8, #:lo12:_text
 + adrpx22, _text
 + add x22, x22, #:lo12:_text  // x22: base of Image

 Why change x8 to x22? Seems unnecessary. Not only that, it is
 callee-saved, but you don't save it. This could cause a problem
 if boot fails and we try to return to firmware.

 + adrpx24, _edata
 + add x24, x24, #:lo12:_edata
 + sub x24, x24, x22   // x24: size of Image

 Should use a caller-saved register instead of x24.


Yes, you are right, I moved it to x22 so I can reuse the value after
the call to efi_entry().
I will correct it when/if I do a v2, i.e., if there is any demand for this.


[RFC PATCH] arm64/efi: efistub: reuse EFI mapping for Image if it is lower

2014-07-15 Thread Ard Biesheuvel
The EFI loader may load Image at any available offset. This means Image may
reside very close to or at the base of DRAM, in which case the relocation
done by efi_entry() results in Image being moved up in memory, which is
undesirable (memory below the kernel is currently not usable).

To work around this, we check in the stub whether the relocated offset is higher
than the original offset. If this is the case, the original and relocated Images
switch roles, and we move the original Image inside its original lower mapping
while executing from the relocated Image.

To ensure the original mapping has sufficient size, we add 2 megs + TEXT_OFFSET
of padding to the PE/COFF .text section, this should be sufficient to cover
rounding and adding TEXT_OFFSET.

Signed-off-by: Ard Biesheuvel ard.biesheu...@linaro.org
---

This was tested on a Foundation Model using the patch below, which forces the
Image to be loaded at 0x8000 (base of DRAM).

diff --git a/arch/arm64/kernel/head.S b/arch/arm64/kernel/head.S
index 2b7bd5eff776..eeadc073bad3 100644
--- a/arch/arm64/kernel/head.S
+++ b/arch/arm64/kernel/head.S
@@ -138,12 +138,12 @@ pe_header:
.short  0
 coff_header:
.short  0xaa64  // AArch64
-   .short  2   // nr_sections
+   .short  1   // nr_sections
.long   0   // TimeDateStamp
.long   0   // PointerToSymbolTable
.long   1   // NumberOfSymbols
.short  section_table - optional_header // SizeOfOptionalHeader
-   .short  0x206   // Characteristics.
+   .short  0x207   // Characteristics.
// IMAGE_FILE_DEBUG_STRIPPED |
// IMAGE_FILE_EXECUTABLE_IMAGE |
// IMAGE_FILE_LINE_NUMS_STRIPPED
@@ -158,7 +158,7 @@ optional_header:
.long   stext_offset// BaseOfCode
 
 extra_header_fields:
-   .quad   0   // ImageBase
+   .quad   0x8000  // ImageBase
.long   0x20// SectionAlignment
.long   0x8 // FileAlignment
.short  0   // MajorOperatingSystemVersion
@@ -193,6 +193,7 @@ extra_header_fields:
// Section table
 section_table:
 
+#if 0
/*
 * The EFI application loader requires a relocation section
 * because EFI applications must be relocatable.  This is a
@@ -212,6 +213,7 @@ section_table:
.long   0x42100040  // Characteristics (section flags)
 
 
+#endif
.ascii  .text
.byte   0
.byte   0


 arch/arm64/kernel/Makefile|  1 +
 arch/arm64/kernel/efi-entry.S | 48 +--
 arch/arm64/kernel/head.S  |  7 ---
 3 files changed, 42 insertions(+), 14 deletions(-)

diff --git a/arch/arm64/kernel/Makefile b/arch/arm64/kernel/Makefile
index cdaedad3afe5..d55da3cd8a97 100644
--- a/arch/arm64/kernel/Makefile
+++ b/arch/arm64/kernel/Makefile
@@ -6,6 +6,7 @@ CPPFLAGS_vmlinux.lds:= -DTEXT_OFFSET=$(TEXT_OFFSET)
 AFLAGS_head.o  := -DTEXT_OFFSET=$(TEXT_OFFSET)
 CFLAGS_efi-stub.o  := -DTEXT_OFFSET=$(TEXT_OFFSET) \
   -I$(src)/../../../scripts/dtc/libfdt
+AFLAGS_efi-entry.o := -DTEXT_OFFSET=$(TEXT_OFFSET)
 
 CFLAGS_REMOVE_ftrace.o = -pg
 CFLAGS_REMOVE_insn.o = -pg
diff --git a/arch/arm64/kernel/efi-entry.S b/arch/arm64/kernel/efi-entry.S
index a0016d3a17da..d154f3c73937 100644
--- a/arch/arm64/kernel/efi-entry.S
+++ b/arch/arm64/kernel/efi-entry.S
@@ -11,6 +11,7 @@
  */
 #include linux/linkage.h
 #include linux/init.h
+#include linux/sizes.h
 
 #include asm/assembler.h
 
@@ -45,10 +46,13 @@ ENTRY(efi_stub_entry)
 * efi_system_table_t *sys_table,
 * unsigned long *image_addr) ;
 */
-   adrpx8, _text
-   add x8, x8, #:lo12:_text
+   adrpx22, _text
+   add x22, x22, #:lo12:_text  // x22: base of Image
+   adrpx24, _edata
+   add x24, x24, #:lo12:_edata
+   sub x24, x24, x22   // x24: size of Image
add x2, sp, 16
-   str x8, [x2]
+   str x22, [x2]
bl  efi_entry
cmn x0, #1
b.eqefi_load_fail
@@ -61,19 +65,41 @@ ENTRY(efi_stub_entry)
 */
mov x20, x0 // DTB address
ldr x0, [sp, #16]   // relocated _text address
-   ldr x21, =stext_offset
-   add x21, x0, x21
+   ldr x23, =stext_offset
+   add x21, x0, x23
 
/*
+* Check whether the original allocation done by the EFI loader is more
+*