linux-arm-kernel.lists.infradead.org archive mirror
 help / color / mirror / Atom feed
* [RFC PATCH 00/10] arm64: boot BE kernels from UEFI
@ 2014-07-21 15:16 Ard Biesheuvel
  2014-07-21 15:16 ` [RFC PATCH 01/10] arm64/efi: efistub: jump to 'stext' directly, not through the header Ard Biesheuvel
                   ` (9 more replies)
  0 siblings, 10 replies; 17+ messages in thread
From: Ard Biesheuvel @ 2014-07-21 15:16 UTC (permalink / raw)
  To: linux-arm-kernel

This series adds support for booting BE kernels from UEFI. As UEFI is defined to
be strictly little endian, some workarounds are required to combine a little
endian EFI stub with a big endian kernel. Also, runtime services need to be
wrapped so they can be executed in little endian mode.

Patches #1 and #2 have been sent to the list before, but are included for
completeness.

Patch #3, #4 and #5 modify the PE/COFF header definition so it is always
emitted in little endian, regardless of the endianness of the kernel.

Patch #6 removes references to linker defined symbols like _text and _edata
from the stub, as the stub is now a standalone little endian binary that is
wrapped in a big endian object file, and _text and _edata are unavailable
or meaningless in that context.

Patch #7 adds the Makefile changes and some code to build the standalone stub
and wrap it.

Patch #8 updates the kernel code that references data in UEFI memory to byte
reverse it if required.

Patch #9 adds runtime services wrappers for the variable store services so they
can be called from the big endian kernel. Other runtime services are not
implemented for now.

Patch #10 enables everything by adding the Kconfig logic.

This is tested on Foundation model and FVP Base model. Booting works fine on
both, however, enumerating the variable store works only on FVP Base, and is
not debuggable on Foundation Model, so I would really appreciate any insights
into the code in patch #9 that may be causing this. There is some trickery
regarding en-/disabling caches and MMU and surely I have gotten something
wrong there.

Ard Biesheuvel (10):
  arm64/efi: efistub: jump to 'stext' directly, not through the header
  arm64/efi: efistub: cover entire static mem footprint in PE/COFF .text
  arm64: add macros to emit little endian ASM constants
  arm64: add EFI little endian constants to linker script
  arm64/efi: update the PE/COFF header to be endian agnostic
  arm64/efi: efistub: avoid using linker defined constants
  arm64/efi: efistub: add support for booting a BE kernel
  arm64/efi: use LE accessors to access UEFI data
  arm64/efi: enable minimal UEFI Runtime Services for big endian
  arm64: Kconfig: enable UEFI on BE kernels

 arch/arm64/Kconfig                          |  10 ++-
 arch/arm64/include/asm/assembler.h          |  18 +++++
 arch/arm64/include/asm/efi.h                |   2 +
 arch/arm64/kernel/Makefile                  |   7 +-
 arch/arm64/kernel/efi-be-call.S             |  55 +++++++++++++++
 arch/arm64/kernel/efi-be-runtime.c          | 104 ++++++++++++++++++++++++++++
 arch/arm64/kernel/efi-entry.S               |  41 ++++++++---
 arch/arm64/kernel/efi-stub.c                |  11 ++-
 arch/arm64/kernel/efi.c                     |  68 +++++++++++-------
 arch/arm64/kernel/efistub-le/Makefile       |  52 ++++++++++++++
 arch/arm64/kernel/efistub-le/efi-le-entry.S |  13 ++++
 arch/arm64/kernel/efistub-le/efistub-le.lds |  35 ++++++++++
 arch/arm64/kernel/efistub-le/le.h           |  12 ++++
 arch/arm64/kernel/efistub-le/strstr.c       |  20 ++++++
 arch/arm64/kernel/head.S                    |  50 +++++++------
 arch/arm64/kernel/image.h                   |  16 ++++-
 drivers/firmware/efi/efi.c                  |  26 ++++---
 drivers/firmware/efi/efivars.c              |   2 +-
 drivers/firmware/efi/libstub/fdt.c          |   4 ++
 19 files changed, 466 insertions(+), 80 deletions(-)
 create mode 100644 arch/arm64/kernel/efi-be-call.S
 create mode 100644 arch/arm64/kernel/efi-be-runtime.c
 create mode 100644 arch/arm64/kernel/efistub-le/Makefile
 create mode 100644 arch/arm64/kernel/efistub-le/efi-le-entry.S
 create mode 100644 arch/arm64/kernel/efistub-le/efistub-le.lds
 create mode 100644 arch/arm64/kernel/efistub-le/le.h
 create mode 100644 arch/arm64/kernel/efistub-le/strstr.c

-- 
1.8.3.2

^ permalink raw reply	[flat|nested] 17+ messages in thread

* [RFC PATCH 01/10] arm64/efi: efistub: jump to 'stext' directly, not through the header
  2014-07-21 15:16 [RFC PATCH 00/10] arm64: boot BE kernels from UEFI Ard Biesheuvel
@ 2014-07-21 15:16 ` Ard Biesheuvel
  2014-07-21 15:16 ` [RFC PATCH 02/10] arm64/efi: efistub: cover entire static mem footprint in PE/COFF .text Ard Biesheuvel
                   ` (8 subsequent siblings)
  9 siblings, 0 replies; 17+ messages in thread
From: Ard Biesheuvel @ 2014-07-21 15:16 UTC (permalink / raw)
  To: linux-arm-kernel

After the EFI stub has done its business, it jumps into the kernel by branching
to offset #0 of the loaded Image, which is where it expects to find the header
containing a 'branch to stext' instruction.

However, the header is not covered by any PE/COFF section, so the header may
not actually be loaded at the expected offset. So instead, jump to 'stext'
directly, which is at the base of the PE/COFF .text section, by supplying a
symbol 'stext_offset' to efi-entry.o which contains the relative offset of
stext into the Image. Also replace other open coded calculations of the same
value with a reference to 'stext_offset'

Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
---
 arch/arm64/kernel/efi-entry.S |  3 ++-
 arch/arm64/kernel/head.S      | 10 ++++++----
 2 files changed, 8 insertions(+), 5 deletions(-)

diff --git a/arch/arm64/kernel/efi-entry.S b/arch/arm64/kernel/efi-entry.S
index 619b1dd7bcde..a0016d3a17da 100644
--- a/arch/arm64/kernel/efi-entry.S
+++ b/arch/arm64/kernel/efi-entry.S
@@ -61,7 +61,8 @@ ENTRY(efi_stub_entry)
 	 */
 	mov	x20, x0		// DTB address
 	ldr	x0, [sp, #16]	// relocated _text address
-	mov	x21, x0
+	ldr	x21, =stext_offset
+	add	x21, x0, x21
 
 	/*
 	 * Flush dcache covering current runtime addresses
diff --git a/arch/arm64/kernel/head.S b/arch/arm64/kernel/head.S
index 69dafe9621fd..5cd1f3491df5 100644
--- a/arch/arm64/kernel/head.S
+++ b/arch/arm64/kernel/head.S
@@ -129,6 +129,8 @@ efi_head:
 #endif
 
 #ifdef CONFIG_EFI
+	.globl	stext_offset
+	.set	stext_offset, stext - efi_head
 	.align 3
 pe_header:
 	.ascii	"PE"
@@ -152,7 +154,7 @@ optional_header:
 	.long	0				// SizeOfInitializedData
 	.long	0				// SizeOfUninitializedData
 	.long	efi_stub_entry - efi_head	// AddressOfEntryPoint
-	.long	stext - efi_head		// BaseOfCode
+	.long	stext_offset			// BaseOfCode
 
 extra_header_fields:
 	.quad	0				// ImageBase
@@ -169,7 +171,7 @@ extra_header_fields:
 	.long	_edata - efi_head		// SizeOfImage
 
 	// Everything before the kernel image is considered part of the header
-	.long	stext - efi_head		// SizeOfHeaders
+	.long	stext_offset			// SizeOfHeaders
 	.long	0				// CheckSum
 	.short	0xa				// Subsystem (EFI application)
 	.short	0				// DllCharacteristics
@@ -214,9 +216,9 @@ section_table:
 	.byte	0
 	.byte	0        		// end of 0 padding of section name
 	.long	_edata - stext		// VirtualSize
-	.long	stext - efi_head	// VirtualAddress
+	.long	stext_offset		// VirtualAddress
 	.long	_edata - stext		// SizeOfRawData
-	.long	stext - efi_head	// PointerToRawData
+	.long	stext_offset		// PointerToRawData
 
 	.long	0		// PointerToRelocations (0 for executables)
 	.long	0		// PointerToLineNumbers (0 for executables)
-- 
1.8.3.2

^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [RFC PATCH 02/10] arm64/efi: efistub: cover entire static mem footprint in PE/COFF .text
  2014-07-21 15:16 [RFC PATCH 00/10] arm64: boot BE kernels from UEFI Ard Biesheuvel
  2014-07-21 15:16 ` [RFC PATCH 01/10] arm64/efi: efistub: jump to 'stext' directly, not through the header Ard Biesheuvel
@ 2014-07-21 15:16 ` Ard Biesheuvel
  2014-07-21 15:16 ` [RFC PATCH 03/10] arm64: add macros to emit little endian ASM constants Ard Biesheuvel
                   ` (7 subsequent siblings)
  9 siblings, 0 replies; 17+ messages in thread
From: Ard Biesheuvel @ 2014-07-21 15:16 UTC (permalink / raw)
  To: linux-arm-kernel

The static memory footprint of a kernel Image at boot is larger than the
Image file itself. Things like .bss data and initial page tables are allocated
statically but populated dynamically so their content is not contained in the
Image file.

However, if EFI has loaded the Image at precisely the desired offset of
base of DRAM + TEXT_OFFSET, the Image will be booted in place, and we have
to make sure that the allocation done by the EFI loader is large enough.

Fix this by growing the PE/COFF .text section to cover the entire static
memory footprint. The part of the section that is not covered by the payload
will be zero initialised by the EFI loader.

Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
---
 arch/arm64/kernel/head.S | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/arch/arm64/kernel/head.S b/arch/arm64/kernel/head.S
index 5cd1f3491df5..c63f44f20ae3 100644
--- a/arch/arm64/kernel/head.S
+++ b/arch/arm64/kernel/head.S
@@ -150,7 +150,7 @@ optional_header:
 	.short	0x20b				// PE32+ format
 	.byte	0x02				// MajorLinkerVersion
 	.byte	0x14				// MinorLinkerVersion
-	.long	_edata - stext			// SizeOfCode
+	.long	_end - stext			// SizeOfCode
 	.long	0				// SizeOfInitializedData
 	.long	0				// SizeOfUninitializedData
 	.long	efi_stub_entry - efi_head	// AddressOfEntryPoint
@@ -168,7 +168,7 @@ extra_header_fields:
 	.short	0				// MinorSubsystemVersion
 	.long	0				// Win32VersionValue
 
-	.long	_edata - efi_head		// SizeOfImage
+	.long	_end - efi_head			// SizeOfImage
 
 	// Everything before the kernel image is considered part of the header
 	.long	stext_offset			// SizeOfHeaders
@@ -215,7 +215,7 @@ section_table:
 	.byte	0
 	.byte	0
 	.byte	0        		// end of 0 padding of section name
-	.long	_edata - stext		// VirtualSize
+	.long	_end - stext		// VirtualSize
 	.long	stext_offset		// VirtualAddress
 	.long	_edata - stext		// SizeOfRawData
 	.long	stext_offset		// PointerToRawData
-- 
1.8.3.2

^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [RFC PATCH 03/10] arm64: add macros to emit little endian ASM constants
  2014-07-21 15:16 [RFC PATCH 00/10] arm64: boot BE kernels from UEFI Ard Biesheuvel
  2014-07-21 15:16 ` [RFC PATCH 01/10] arm64/efi: efistub: jump to 'stext' directly, not through the header Ard Biesheuvel
  2014-07-21 15:16 ` [RFC PATCH 02/10] arm64/efi: efistub: cover entire static mem footprint in PE/COFF .text Ard Biesheuvel
@ 2014-07-21 15:16 ` Ard Biesheuvel
  2014-07-21 15:16 ` [RFC PATCH 04/10] arm64: add EFI little endian constants to linker script Ard Biesheuvel
                   ` (6 subsequent siblings)
  9 siblings, 0 replies; 17+ messages in thread
From: Ard Biesheuvel @ 2014-07-21 15:16 UTC (permalink / raw)
  To: linux-arm-kernel

The Image header contains many constants that should be emitted in little
endian regardless of the endianness of the kernel. Add helper macros le16,
le32 and le64 to <asm/assembler.h> to aid with this.

Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
---
 arch/arm64/include/asm/assembler.h | 18 ++++++++++++++++++
 1 file changed, 18 insertions(+)

diff --git a/arch/arm64/include/asm/assembler.h b/arch/arm64/include/asm/assembler.h
index 5901480bfdca..7db7c946f73f 100644
--- a/arch/arm64/include/asm/assembler.h
+++ b/arch/arm64/include/asm/assembler.h
@@ -155,3 +155,21 @@ lr	.req	x30		// link register
 #endif
 	orr	\rd, \lbits, \hbits, lsl #32
 	.endm
+
+	/*
+	 * Define LE constants
+	 */
+	.macro		le16, x
+	.byte		\x & 0xff
+	.byte		(\x >> 8) & 0xff
+	.endm
+
+	.macro		le32, x
+	le16		\x
+	le16		\x >> 16
+	.endm
+
+	.macro		le64, x
+	le32		\x
+	le32		\x >> 32
+	.endm
-- 
1.8.3.2

^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [RFC PATCH 04/10] arm64: add EFI little endian constants to linker script
  2014-07-21 15:16 [RFC PATCH 00/10] arm64: boot BE kernels from UEFI Ard Biesheuvel
                   ` (2 preceding siblings ...)
  2014-07-21 15:16 ` [RFC PATCH 03/10] arm64: add macros to emit little endian ASM constants Ard Biesheuvel
@ 2014-07-21 15:16 ` Ard Biesheuvel
  2014-07-30 14:18   ` Matt Fleming
  2014-07-21 15:16 ` [RFC PATCH 05/10] arm64/efi: update the PE/COFF header to be endian agnostic Ard Biesheuvel
                   ` (5 subsequent siblings)
  9 siblings, 1 reply; 17+ messages in thread
From: Ard Biesheuvel @ 2014-07-21 15:16 UTC (permalink / raw)
  To: linux-arm-kernel

Similar to how text offset and kernel size are mangled to produce little
endian constants for the Image header regardless of the endianness of the
kernel, this adds a number of constants used in the EFI PE/COFF header which
can only be calculated (and byte swapped) by the linker.

Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
---
 arch/arm64/kernel/image.h | 16 +++++++++++++++-
 1 file changed, 15 insertions(+), 1 deletion(-)

diff --git a/arch/arm64/kernel/image.h b/arch/arm64/kernel/image.h
index 8fae0756e175..f5a2f298810d 100644
--- a/arch/arm64/kernel/image.h
+++ b/arch/arm64/kernel/image.h
@@ -37,8 +37,10 @@
 	 (((data) & 0x0000ff0000000000) >> 24) |	\
 	 (((data) & 0x00ff000000000000) >> 40) |	\
 	 (((data) & 0xff00000000000000) >> 56))
+#define DATA_LE32(data) (DATA_LE64(data) >> 32)
 #else
 #define DATA_LE64(data) ((data) & 0xffffffffffffffff)
+#define DATA_LE32(data) ((data) & 0xffffffff)
 #endif
 
 #ifdef CONFIG_CPU_BIG_ENDIAN
@@ -57,6 +59,18 @@
 #define HEAD_SYMBOLS						\
 	_kernel_size_le		= DATA_LE64(_end - _text);	\
 	_kernel_offset_le	= DATA_LE64(TEXT_OFFSET);	\
-	_kernel_flags_le	= DATA_LE64(__HEAD_FLAGS);
+	_kernel_flags_le	= DATA_LE64(__HEAD_FLAGS);	\
+	EFI_HEAD_SYMBOLS
+
+#ifdef CONFIG_EFI
+#define EFI_HEAD_SYMBOLS						    \
+	_efi_stext_offset_le	= DATA_LE32(stext_offset);		    \
+	_efi_code_virtsize_le	= DATA_LE32(_end - _text - stext_offset);   \
+	_efi_code_rawsize_le	= DATA_LE32(_edata - _text - stext_offset); \
+	_efi_image_size_le	= DATA_LE32(_end - _text);		    \
+	_efi_entry_point_le	= DATA_LE32(efi_stub_entry - _text);
+#else
+#define  EFI_HEAD_SYMBOLS
+#endif
 
 #endif /* __ASM_IMAGE_H */
-- 
1.8.3.2

^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [RFC PATCH 05/10] arm64/efi: update the PE/COFF header to be endian agnostic
  2014-07-21 15:16 [RFC PATCH 00/10] arm64: boot BE kernels from UEFI Ard Biesheuvel
                   ` (3 preceding siblings ...)
  2014-07-21 15:16 ` [RFC PATCH 04/10] arm64: add EFI little endian constants to linker script Ard Biesheuvel
@ 2014-07-21 15:16 ` Ard Biesheuvel
  2014-07-21 15:16 ` [RFC PATCH 06/10] arm64/efi: efistub: avoid using linker defined constants Ard Biesheuvel
                   ` (4 subsequent siblings)
  9 siblings, 0 replies; 17+ messages in thread
From: Ard Biesheuvel @ 2014-07-21 15:16 UTC (permalink / raw)
  To: linux-arm-kernel

Update the PE/COFF header to use explicit little endian constants and use
explicit little endian linker symbols so that the PE/COFF header is always
emitted in little endian regardless of the endiannes of the kernel.

Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
---
 arch/arm64/kernel/head.S | 48 ++++++++++++++++++++++++++----------------------
 1 file changed, 26 insertions(+), 22 deletions(-)

diff --git a/arch/arm64/kernel/head.S b/arch/arm64/kernel/head.S
index c63f44f20ae3..5179d3df1024 100644
--- a/arch/arm64/kernel/head.S
+++ b/arch/arm64/kernel/head.S
@@ -123,7 +123,10 @@ efi_head:
 	.byte	0x4d
 	.byte	0x64
 #ifdef CONFIG_EFI
-	.long	pe_header - efi_head		// Offset to the PE header.
+	.byte	pe_header - efi_head		// Offset to the PE header.
+	.byte	0
+	.byte	0
+	.byte	0
 #else
 	.word	0				// reserved
 #endif
@@ -136,30 +139,31 @@ pe_header:
 	.ascii	"PE"
 	.short 	0
 coff_header:
-	.short	0xaa64				// AArch64
-	.short	2				// nr_sections
+	le16	0xaa64				// AArch64
+	le16	2				// nr_sections
 	.long	0 				// TimeDateStamp
 	.long	0				// PointerToSymbolTable
-	.long	1				// NumberOfSymbols
-	.short	section_table - optional_header	// SizeOfOptionalHeader
-	.short	0x206				// Characteristics.
+	le32	1				// NumberOfSymbols
+	.byte	section_table - optional_header	// SizeOfOptionalHeader
+	.byte	0
+	le16	0x206				// Characteristics.
 						// IMAGE_FILE_DEBUG_STRIPPED |
 						// IMAGE_FILE_EXECUTABLE_IMAGE |
 						// IMAGE_FILE_LINE_NUMS_STRIPPED
 optional_header:
-	.short	0x20b				// PE32+ format
+	le16	0x20b				// PE32+ format
 	.byte	0x02				// MajorLinkerVersion
 	.byte	0x14				// MinorLinkerVersion
-	.long	_end - stext			// SizeOfCode
+	.long	_efi_code_virtsize_le		// SizeOfCode
 	.long	0				// SizeOfInitializedData
 	.long	0				// SizeOfUninitializedData
-	.long	efi_stub_entry - efi_head	// AddressOfEntryPoint
-	.long	stext_offset			// BaseOfCode
+	.long	_efi_entry_point_le		// AddressOfEntryPoint
+	.long	_efi_stext_offset_le		// BaseOfCode
 
 extra_header_fields:
 	.quad	0				// ImageBase
-	.long	0x20				// SectionAlignment
-	.long	0x8				// FileAlignment
+	le32	0x20				// SectionAlignment
+	le32	0x8				// FileAlignment
 	.short	0				// MajorOperatingSystemVersion
 	.short	0				// MinorOperatingSystemVersion
 	.short	0				// MajorImageVersion
@@ -168,19 +172,19 @@ extra_header_fields:
 	.short	0				// MinorSubsystemVersion
 	.long	0				// Win32VersionValue
 
-	.long	_end - efi_head			// SizeOfImage
+	.long	_efi_image_size_le		// SizeOfImage
 
 	// Everything before the kernel image is considered part of the header
-	.long	stext_offset			// SizeOfHeaders
+	.long	_efi_stext_offset_le		// SizeOfHeaders
 	.long	0				// CheckSum
-	.short	0xa				// Subsystem (EFI application)
+	le16	0xa				// Subsystem (EFI application)
 	.short	0				// DllCharacteristics
 	.quad	0				// SizeOfStackReserve
 	.quad	0				// SizeOfStackCommit
 	.quad	0				// SizeOfHeapReserve
 	.quad	0				// SizeOfHeapCommit
 	.long	0				// LoaderFlags
-	.long	0x6				// NumberOfRvaAndSizes
+	le32	0x6				// NumberOfRvaAndSizes
 
 	.quad	0				// ExportTable
 	.quad	0				// ImportTable
@@ -208,23 +212,23 @@ section_table:
 	.long	0			// PointerToLineNumbers
 	.short	0			// NumberOfRelocations
 	.short	0			// NumberOfLineNumbers
-	.long	0x42100040		// Characteristics (section flags)
+	le32	0x42100040		// Characteristics (section flags)
 
 
 	.ascii	".text"
 	.byte	0
 	.byte	0
 	.byte	0        		// end of 0 padding of section name
-	.long	_end - stext		// VirtualSize
-	.long	stext_offset		// VirtualAddress
-	.long	_edata - stext		// SizeOfRawData
-	.long	stext_offset		// PointerToRawData
+	.long	_efi_code_virtsize_le	// VirtualSize
+	.long	_efi_stext_offset_le	// VirtualAddress
+	.long	_efi_code_rawsize_le	// SizeOfRawData
+	.long	_efi_stext_offset_le	// PointerToRawData
 
 	.long	0		// PointerToRelocations (0 for executables)
 	.long	0		// PointerToLineNumbers (0 for executables)
 	.short	0		// NumberOfRelocations  (0 for executables)
 	.short	0		// NumberOfLineNumbers  (0 for executables)
-	.long	0xe0500020	// Characteristics (section flags)
+	le32	0xe0500020	// Characteristics (section flags)
 	.align 5
 #endif
 
-- 
1.8.3.2

^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [RFC PATCH 06/10] arm64/efi: efistub: avoid using linker defined constants
  2014-07-21 15:16 [RFC PATCH 00/10] arm64: boot BE kernels from UEFI Ard Biesheuvel
                   ` (4 preceding siblings ...)
  2014-07-21 15:16 ` [RFC PATCH 05/10] arm64/efi: update the PE/COFF header to be endian agnostic Ard Biesheuvel
@ 2014-07-21 15:16 ` Ard Biesheuvel
  2014-07-21 15:16 ` [RFC PATCH 07/10] arm64/efi: efistub: add support for booting a BE kernel Ard Biesheuvel
                   ` (3 subsequent siblings)
  9 siblings, 0 replies; 17+ messages in thread
From: Ard Biesheuvel @ 2014-07-21 15:16 UTC (permalink / raw)
  To: linux-arm-kernel

When we build the stub as a separate executable, we cannot refer to symbols
like _edata or _end to find out how large the kernel is. Use image->image_size
instead, this covers the entire static memory footprint including BSS.

Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
---
 arch/arm64/kernel/efi-stub.c | 11 ++++-------
 1 file changed, 4 insertions(+), 7 deletions(-)

diff --git a/arch/arm64/kernel/efi-stub.c b/arch/arm64/kernel/efi-stub.c
index 1317fef8dde9..8401d7795395 100644
--- a/arch/arm64/kernel/efi-stub.c
+++ b/arch/arm64/kernel/efi-stub.c
@@ -11,7 +11,6 @@
  */
 #include <linux/efi.h>
 #include <asm/efi.h>
-#include <asm/sections.h>
 
 efi_status_t handle_kernel_image(efi_system_table_t *sys_table,
 				 unsigned long *image_addr,
@@ -22,14 +21,12 @@ efi_status_t handle_kernel_image(efi_system_table_t *sys_table,
 				 efi_loaded_image_t *image)
 {
 	efi_status_t status;
-	unsigned long kernel_size, kernel_memsize = 0;
 
 	/* Relocate the image, if required. */
-	kernel_size = _edata - _text;
 	if (*image_addr != (dram_base + TEXT_OFFSET)) {
-		kernel_memsize = kernel_size + (_end - _edata);
 		status = efi_relocate_kernel(sys_table, image_addr,
-					     kernel_size, kernel_memsize,
+					     image->image_size,
+					     image->image_size,
 					     dram_base + TEXT_OFFSET,
 					     PAGE_SIZE);
 		if (status != EFI_SUCCESS) {
@@ -38,10 +35,10 @@ efi_status_t handle_kernel_image(efi_system_table_t *sys_table,
 		}
 		if (*image_addr != (dram_base + TEXT_OFFSET)) {
 			pr_efi_err(sys_table, "Failed to alloc kernel memory\n");
-			efi_free(sys_table, kernel_memsize, *image_addr);
+			efi_free(sys_table, image->image_size, *image_addr);
 			return EFI_LOAD_ERROR;
 		}
-		*image_size = kernel_memsize;
+		*image_size = image->image_size;
 	}
 
 
-- 
1.8.3.2

^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [RFC PATCH 07/10] arm64/efi: efistub: add support for booting a BE kernel
  2014-07-21 15:16 [RFC PATCH 00/10] arm64: boot BE kernels from UEFI Ard Biesheuvel
                   ` (5 preceding siblings ...)
  2014-07-21 15:16 ` [RFC PATCH 06/10] arm64/efi: efistub: avoid using linker defined constants Ard Biesheuvel
@ 2014-07-21 15:16 ` Ard Biesheuvel
  2014-07-21 15:16 ` [RFC PATCH 08/10] arm64/efi: use LE accessors to access UEFI data Ard Biesheuvel
                   ` (2 subsequent siblings)
  9 siblings, 0 replies; 17+ messages in thread
From: Ard Biesheuvel @ 2014-07-21 15:16 UTC (permalink / raw)
  To: linux-arm-kernel

This adds support to boot a big endian kernel from UEFI firmware, which is
always little endian. The EFI stub itself is built as little endian, and
embedded into a big endian kernel image.

To enable this, we need to build all the stub's dependencies as little endian,
including FDT parsing code and string functions. This is accomplished by
building little endian versions of those support files and link them into
a static library which is used by the inner stub build.

Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
---
 arch/arm64/kernel/Makefile                  |  7 +++-
 arch/arm64/kernel/efi-entry.S               | 42 +++++++++++++++++------
 arch/arm64/kernel/efistub-le/Makefile       | 52 +++++++++++++++++++++++++++++
 arch/arm64/kernel/efistub-le/efi-le-entry.S | 13 ++++++++
 arch/arm64/kernel/efistub-le/efistub-le.lds | 35 +++++++++++++++++++
 arch/arm64/kernel/efistub-le/le.h           | 12 +++++++
 arch/arm64/kernel/efistub-le/strstr.c       | 20 +++++++++++
 drivers/firmware/efi/libstub/fdt.c          |  4 +++
 8 files changed, 173 insertions(+), 12 deletions(-)
 create mode 100644 arch/arm64/kernel/efistub-le/Makefile
 create mode 100644 arch/arm64/kernel/efistub-le/efi-le-entry.S
 create mode 100644 arch/arm64/kernel/efistub-le/efistub-le.lds
 create mode 100644 arch/arm64/kernel/efistub-le/le.h
 create mode 100644 arch/arm64/kernel/efistub-le/strstr.c

diff --git a/arch/arm64/kernel/Makefile b/arch/arm64/kernel/Makefile
index afaeb734295a..942cd042e93e 100644
--- a/arch/arm64/kernel/Makefile
+++ b/arch/arm64/kernel/Makefile
@@ -27,7 +27,12 @@ arm64-obj-$(CONFIG_HAVE_HW_BREAKPOINT)	+= hw_breakpoint.o
 arm64-obj-$(CONFIG_ARM64_CPU_SUSPEND)	+= sleep.o suspend.o
 arm64-obj-$(CONFIG_JUMP_LABEL)		+= jump_label.o
 arm64-obj-$(CONFIG_KGDB)		+= kgdb.o
-arm64-obj-$(CONFIG_EFI)			+= efi.o efi-stub.o efi-entry.o
+
+arm64-efi-obj-y				:= efi.o
+arm64-efi-obj-$(CONFIG_EFI_STUB)	+= efi-stub.o efi-entry.o
+arm64-efi-obj-$(CONFIG_EFI_LE_STUB)	+= efistub-le/
+arm64-efi-obj-$(CONFIG_CPU_BIG_ENDIAN)	+= efi-be-runtime.o efi-be-call.o
+arm64-obj-$(CONFIG_EFI)			+= $(arm64-efi-obj-y)
 
 obj-y					+= $(arm64-obj-y) vdso/
 obj-m					+= $(arm64-obj-m)
diff --git a/arch/arm64/kernel/efi-entry.S b/arch/arm64/kernel/efi-entry.S
index a0016d3a17da..89f34bb86cfd 100644
--- a/arch/arm64/kernel/efi-entry.S
+++ b/arch/arm64/kernel/efi-entry.S
@@ -34,8 +34,34 @@ ENTRY(efi_stub_entry)
 	 * Create a stack frame to save FP/LR with extra space
 	 * for image_addr variable passed to efi_entry().
 	 */
-	stp	x29, x30, [sp, #-32]!
+	stp	x29, x30, [sp, #-48]!
+	stp	x22, x23, [sp, #32]
 
+#ifdef CONFIG_EFI_LE_STUB
+	adr	x4, efi_stub_entry
+	ldp	w8, w9, [x4, #-32]
+STUB_BE(rev	w8, w8		)
+STUB_BE(rev	w9, w9		)
+	add	x8, x4, w8, sxtw		// x8: base of Image
+	add	x9, x4, w9, sxtw		// x9: offset of linux_banner
+
+	ldp	x22, x23, [x4, #-24]		// x22: size of Image
+STUB_BE(rev	x23, x23	)		// x23: stext offset
+
+	/*
+	 * Get a pointer to linux_banner in the outer image and store it
+	 * in this image.
+	 */
+	adrp	x4, le_linux_banner
+	str	x9, [x4, #:lo12:le_linux_banner]
+#else
+	adrp	x8, _text
+	add	x8, x8, #:lo12:_text		// x8: base of Image
+	adrp	x9, _edata
+	add	x9, x9, #:lo12:_edata
+	sub	x22, x9, x8			// x22: size of Image
+	ldr	x23, =stext_offset		// x23: stext offset
+#endif
 	/*
 	 * Call efi_entry to do the real work.
 	 * x0 and x1 are already set up by firmware. Current runtime
@@ -45,8 +71,6 @@ ENTRY(efi_stub_entry)
 	 *                         efi_system_table_t *sys_table,
 	 *                         unsigned long *image_addr) ;
 	 */
-	adrp	x8, _text
-	add	x8, x8, #:lo12:_text
 	add	x2, sp, 16
 	str	x8, [x2]
 	bl	efi_entry
@@ -61,18 +85,13 @@ ENTRY(efi_stub_entry)
 	 */
 	mov	x20, x0		// DTB address
 	ldr	x0, [sp, #16]	// relocated _text address
-	ldr	x21, =stext_offset
-	add	x21, x0, x21
+	add	x21, x0, x23
 
 	/*
 	 * Flush dcache covering current runtime addresses
 	 * of kernel text/data. Then flush all of icache.
 	 */
-	adrp	x1, _text
-	add	x1, x1, #:lo12:_text
-	adrp	x2, _edata
-	add	x2, x2, #:lo12:_edata
-	sub	x1, x2, x1
+	mov	x1, x22
 
 	bl	__flush_dcache_area
 	ic	ialluis
@@ -103,7 +122,8 @@ ENTRY(efi_stub_entry)
 
 efi_load_fail:
 	mov	x0, #EFI_LOAD_ERROR
-	ldp	x29, x30, [sp], #32
+	ldp	x22, x23, [sp, #32]
+	ldp	x29, x30, [sp], #48
 	ret
 
 ENDPROC(efi_stub_entry)
diff --git a/arch/arm64/kernel/efistub-le/Makefile b/arch/arm64/kernel/efistub-le/Makefile
new file mode 100644
index 000000000000..38347b0633c8
--- /dev/null
+++ b/arch/arm64/kernel/efistub-le/Makefile
@@ -0,0 +1,52 @@
+
+#
+# Build a little endian EFI stub and wrap it into a single .o
+#
+
+# the LE objects making up the LE efi stub
+le-objs := efi-entry.o efi-stub.o strstr.o cache.o			\
+	   lib-memchr.o lib-memcmp.o lib-memcpy.o lib-memmove.o		\
+		lib-memset.o lib-strchr.o lib-strlen.o lib-strncmp.o	\
+	   fdt-fdt.o fdt-fdt_ro.o fdt-fdt_rw.o fdt-fdt_sw.o 		\
+		fdt-fdt_wip.o fdt-fdt_empty_tree.o 			\
+	   libstub-fdt.o libstub-arm-stub.o libstub-efi-stub-helper.o
+
+extra-y := efi-le-stub.bin efi-le-stub.elf $(le-objs)
+
+KBUILD_CFLAGS := $(subst -pg,,$(KBUILD_CFLAGS)) -fno-stack-protector	\
+		 -mlittle-endian -I$(srctree)/scripts/dtc/libfdt
+
+le-targets := $(addprefix $(obj)/, $(le-objs))
+$(le-targets): KBUILD_AFLAGS += -mlittle-endian -include $(srctree)/$(src)/le.h
+
+$(obj)/efi-entry.o: $(obj)/../efi-entry.S FORCE
+	$(call if_changed_dep,as_o_S)
+
+CFLAGS_efi-stub.o += -DTEXT_OFFSET=$(TEXT_OFFSET)
+$(obj)/efi-stub.o: $(obj)/../efi-stub.c FORCE
+	$(call if_changed_dep,cc_o_c)
+
+$(obj)/cache.o: $(src)/../../mm/cache.S FORCE
+	$(call if_changed_dep,as_o_S)
+
+$(obj)/lib-%.o: $(src)/../../lib/%.S FORCE
+	$(call if_changed_dep,as_o_S)
+
+$(obj)/fdt-%.o: $(srctree)/lib/%.c FORCE
+	$(call if_changed_dep,cc_o_c)
+
+$(obj)/libstub-%.o: $(srctree)/drivers/firmware/efi/libstub/%.c FORCE
+	$(call if_changed_dep,cc_o_c)
+
+$(obj)/efi-le-stub.elf: LDFLAGS=-EL -Map $@.map -T
+$(obj)/efi-le-stub.elf: $(src)/efistub-le.lds $(le-targets) FORCE
+	$(call if_changed,ld)
+
+$(obj)/efi-le-stub.bin: OBJCOPYFLAGS=-O binary
+$(obj)/efi-le-stub.bin: $(obj)/efi-le-stub.elf FORCE
+	$(call if_changed,objcopy)
+
+# the BE object containing the entire LE stub
+obj-y := efi-le-entry.o
+
+$(obj)/efi-le-entry.o: $(obj)/efi-le-stub.bin
diff --git a/arch/arm64/kernel/efistub-le/efi-le-entry.S b/arch/arm64/kernel/efistub-le/efi-le-entry.S
new file mode 100644
index 000000000000..f615430209e5
--- /dev/null
+++ b/arch/arm64/kernel/efistub-le/efi-le-entry.S
@@ -0,0 +1,13 @@
+
+#include <linux/linkage.h>
+
+	.text
+	.align		12
+	.long		_text - efi_stub_entry
+	.long		linux_banner - efi_stub_entry
+	.quad		_kernel_size_le
+	.quad		stext_offset
+	.quad		0
+ENTRY(efi_stub_entry)
+	.incbin		"arch/arm64/kernel/efistub-le/efi-le-stub.bin"
+ENDPROC(efi_stub_entry)
diff --git a/arch/arm64/kernel/efistub-le/efistub-le.lds b/arch/arm64/kernel/efistub-le/efistub-le.lds
new file mode 100644
index 000000000000..20361c43aa2e
--- /dev/null
+++ b/arch/arm64/kernel/efistub-le/efistub-le.lds
@@ -0,0 +1,35 @@
+
+ENTRY(efi_stub_entry)
+
+SECTIONS {
+	/*
+	 * The inner and outer alignment of this chunk of code need to be the
+	 * same so that PC relative references using adrp/add or adrp/ldr pairs
+	 * will work correctly.
+	 * Skip 32 bytes here, so we can put the binary blob at an offset of
+	 * 4k + 0x20 in the outer image, and use the gap to share constants
+	 * emitted by the outer linker but required in the stub.
+	 */
+	.text 0x20 : {
+		arch/arm64/kernel/efistub-le/efi-entry.o(.init.text)
+		*(.init.text)
+		*(.text)
+		*(.text*)
+	}
+	.rodata : {
+		. = ALIGN(16);
+		*(.rodata)
+		*(.rodata*)
+		*(.init.rodata)
+	}
+	.data : {
+		. = ALIGN(16);
+		*(.data)
+		*(.data*)
+		le_linux_banner = .;
+		. += 8;
+	}
+	/DISCARD/ : {
+		*(__ex_table)
+	}
+}
diff --git a/arch/arm64/kernel/efistub-le/le.h b/arch/arm64/kernel/efistub-le/le.h
new file mode 100644
index 000000000000..f4a28a5f6815
--- /dev/null
+++ b/arch/arm64/kernel/efistub-le/le.h
@@ -0,0 +1,12 @@
+
+/*
+ * This is a bit of a hack, but it is necessary to correctly compile .S files
+ * that contain CPU_LE()/CPU_BE() statements, as these are defined to depend on
+ * CONFIG_ symbols and not on the endianness of the compiler.
+ */
+#ifdef CONFIG_CPU_BIG_ENDIAN
+#define STUB_BE(code...)	code
+#else
+#define STUB_BE(code...)
+#endif
+#undef CONFIG_CPU_BIG_ENDIAN
diff --git a/arch/arm64/kernel/efistub-le/strstr.c b/arch/arm64/kernel/efistub-le/strstr.c
new file mode 100644
index 000000000000..daed0bbcc0c6
--- /dev/null
+++ b/arch/arm64/kernel/efistub-le/strstr.c
@@ -0,0 +1,20 @@
+
+#include <linux/types.h>
+#include <linux/string.h>
+
+char *strstr(const char *s1, const char *s2)
+{
+	size_t l1, l2;
+
+	l2 = strlen(s2);
+	if (!l2)
+		return (char *)s1;
+	l1 = strlen(s1);
+	while (l1 >= l2) {
+		l1--;
+		if (!memcmp(s1, s2, l2))
+			return (char *)s1;
+		s1++;
+	}
+	return NULL;
+}
diff --git a/drivers/firmware/efi/libstub/fdt.c b/drivers/firmware/efi/libstub/fdt.c
index a56bb3528755..651c639a8a18 100644
--- a/drivers/firmware/efi/libstub/fdt.c
+++ b/drivers/firmware/efi/libstub/fdt.c
@@ -22,6 +22,10 @@ efi_status_t update_fdt(efi_system_table_t *sys_table, void *orig_fdt,
 			unsigned long map_size, unsigned long desc_size,
 			u32 desc_ver)
 {
+#ifdef CONFIG_EFI_LE_STUB
+	extern char const *le_linux_banner;
+	char const *linux_banner = le_linux_banner;
+#endif
 	int node, prev;
 	int status;
 	u32 fdt_val32;
-- 
1.8.3.2

^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [RFC PATCH 08/10] arm64/efi: use LE accessors to access UEFI data
  2014-07-21 15:16 [RFC PATCH 00/10] arm64: boot BE kernels from UEFI Ard Biesheuvel
                   ` (6 preceding siblings ...)
  2014-07-21 15:16 ` [RFC PATCH 07/10] arm64/efi: efistub: add support for booting a BE kernel Ard Biesheuvel
@ 2014-07-21 15:16 ` Ard Biesheuvel
  2014-07-21 15:16 ` [RFC PATCH 09/10] arm64/efi: enable minimal UEFI Runtime Services for big endian Ard Biesheuvel
  2014-07-21 15:16 ` [RFC PATCH 10/10] arm64: Kconfig: enable UEFI on BE kernels Ard Biesheuvel
  9 siblings, 0 replies; 17+ messages in thread
From: Ard Biesheuvel @ 2014-07-21 15:16 UTC (permalink / raw)
  To: linux-arm-kernel

If we are running a BE kernel, we need to byte reverse all data that UEFI keeps,
as UEFI is strictly little endian.

Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
---
 arch/arm64/kernel/efi.c        | 53 +++++++++++++++++++++++-------------------
 drivers/firmware/efi/efi.c     | 26 ++++++++++++---------
 drivers/firmware/efi/efivars.c |  2 +-
 3 files changed, 45 insertions(+), 36 deletions(-)

diff --git a/arch/arm64/kernel/efi.c b/arch/arm64/kernel/efi.c
index e72f3100958f..96df58824189 100644
--- a/arch/arm64/kernel/efi.c
+++ b/arch/arm64/kernel/efi.c
@@ -42,7 +42,7 @@ early_param("uefi_debug", uefi_debug_setup);
 
 static int __init is_normal_ram(efi_memory_desc_t *md)
 {
-	if (md->attribute & EFI_MEMORY_WB)
+	if (le64_to_cpu(md->attribute) & EFI_MEMORY_WB)
 		return 1;
 	return 0;
 }
@@ -58,10 +58,11 @@ static void __init efi_setup_idmap(void)
 
 	/* map runtime io spaces */
 	for_each_efi_memory_desc(&memmap, md) {
-		if (!(md->attribute & EFI_MEMORY_RUNTIME) || is_normal_ram(md))
+		if (!(le64_to_cpu(md->attribute) & EFI_MEMORY_RUNTIME) ||
+		    is_normal_ram(md))
 			continue;
-		paddr = md->phys_addr;
-		npages = md->num_pages;
+		paddr = le64_to_cpu(md->phys_addr);
+		npages = le64_to_cpu(md->num_pages);
 		memrange_efi_to_native(&paddr, &npages);
 		size = npages << PAGE_SHIFT;
 		create_id_mapping(paddr, size, 1);
@@ -87,27 +88,27 @@ static int __init uefi_init(void)
 	/*
 	 * Verify the EFI Table
 	 */
-	if (efi.systab->hdr.signature != EFI_SYSTEM_TABLE_SIGNATURE) {
+	if (le64_to_cpu(efi.systab->hdr.signature) != EFI_SYSTEM_TABLE_SIGNATURE) {
 		pr_err("System table signature incorrect\n");
 		return -EINVAL;
 	}
-	if ((efi.systab->hdr.revision >> 16) < 2)
+	if ((le32_to_cpu(efi.systab->hdr.revision) >> 16) < 2)
 		pr_warn("Warning: EFI system table version %d.%02d, expected 2.00 or greater\n",
 			efi.systab->hdr.revision >> 16,
 			efi.systab->hdr.revision & 0xffff);
 
 	/* Show what we know for posterity */
-	c16 = early_memremap(efi.systab->fw_vendor,
+	c16 = early_memremap(le64_to_cpu(efi.systab->fw_vendor),
 			     sizeof(vendor));
 	if (c16) {
 		for (i = 0; i < (int) sizeof(vendor) - 1 && *c16; ++i)
-			vendor[i] = c16[i];
+			vendor[i] = le16_to_cpu(c16[i]);
 		vendor[i] = '\0';
 	}
 
 	pr_info("EFI v%u.%.02u by %s\n",
-		efi.systab->hdr.revision >> 16,
-		efi.systab->hdr.revision & 0xffff, vendor);
+		le32_to_cpu(efi.systab->hdr.revision) >> 16,
+		le32_to_cpu(efi.systab->hdr.revision) & 0xffff, vendor);
 
 	retval = efi_config_init(NULL);
 	if (retval == 0)
@@ -144,11 +145,11 @@ static __init int is_reserve_region(efi_memory_desc_t *md)
 	if (!is_normal_ram(md))
 		return 0;
 
-	if (md->attribute & EFI_MEMORY_RUNTIME)
+	if (le64_to_cpu(md->attribute) & EFI_MEMORY_RUNTIME)
 		return 1;
 
-	if (md->type == EFI_ACPI_RECLAIM_MEMORY ||
-	    md->type == EFI_RESERVED_TYPE)
+	if (le32_to_cpu(md->type) == EFI_ACPI_RECLAIM_MEMORY ||
+	    le32_to_cpu(md->type) == EFI_RESERVED_TYPE)
 		return 1;
 
 	return 0;
@@ -163,13 +164,15 @@ static __init void reserve_regions(void)
 		pr_info("Processing EFI memory map:\n");
 
 	for_each_efi_memory_desc(&memmap, md) {
-		paddr = md->phys_addr;
-		npages = md->num_pages;
+		u32 md_type = le32_to_cpu(md->type);
+
+		paddr = le64_to_cpu(md->phys_addr);
+		npages = le64_to_cpu(md->num_pages);
 
 		if (uefi_debug)
 			pr_info("  0x%012llx-0x%012llx [%s]",
 				paddr, paddr + (npages << EFI_PAGE_SHIFT) - 1,
-				memory_type_name[md->type]);
+				memory_type_name[md_type]);
 
 		memrange_efi_to_native(&paddr, &npages);
 		size = npages << PAGE_SHIFT;
@@ -178,8 +181,8 @@ static __init void reserve_regions(void)
 			early_init_dt_add_memory_arch(paddr, size);
 
 		if (is_reserve_region(md) ||
-		    md->type == EFI_BOOT_SERVICES_CODE ||
-		    md->type == EFI_BOOT_SERVICES_DATA) {
+		    md_type == EFI_BOOT_SERVICES_CODE ||
+		    md_type == EFI_BOOT_SERVICES_DATA) {
 			memblock_reserve(paddr, size);
 			if (uefi_debug)
 				pr_cont("*");
@@ -258,17 +261,18 @@ static void __init free_boot_services(void)
 			 */
 			if (free_start) {
 				/* adjust free_end then free region */
-				if (free_end > md->phys_addr)
+				if (free_end > le64_to_cpu(md->phys_addr))
 					free_end -= PAGE_SIZE;
 				total_freed += free_region(free_start, free_end);
 				free_start = 0;
 			}
-			keep_end = md->phys_addr + (md->num_pages << EFI_PAGE_SHIFT);
+			keep_end = le64_to_cpu(md->phys_addr) +
+				   (le64_to_cpu(md->num_pages) << EFI_PAGE_SHIFT);
 			continue;
 		}
 
-		if (md->type != EFI_BOOT_SERVICES_CODE &&
-		    md->type != EFI_BOOT_SERVICES_DATA) {
+		if (le32_to_cpu(md->type) != EFI_BOOT_SERVICES_CODE &&
+		    le32_to_cpu(md->type) != EFI_BOOT_SERVICES_DATA) {
 			/* no need to free this region */
 			continue;
 		}
@@ -276,8 +280,8 @@ static void __init free_boot_services(void)
 		/*
 		 * We want to free memory from this region.
 		 */
-		paddr = md->phys_addr;
-		npages = md->num_pages;
+		paddr = le64_to_cpu(md->phys_addr);
+		npages = le64_to_cpu(md->num_pages);
 		memrange_efi_to_native(&paddr, &npages);
 		size = npages << PAGE_SHIFT;
 
@@ -475,3 +479,4 @@ err_unmap:
 	return -1;
 }
 early_initcall(arm64_enter_virtual_mode);
+
diff --git a/drivers/firmware/efi/efi.c b/drivers/firmware/efi/efi.c
index 64ecbb501c50..24cb61b72d06 100644
--- a/drivers/firmware/efi/efi.c
+++ b/drivers/firmware/efi/efi.c
@@ -270,18 +270,23 @@ static __init int match_config_table(efi_guid_t *guid,
 int __init efi_config_init(efi_config_table_type_t *arch_tables)
 {
 	void *config_tables, *tablep;
-	int i, sz;
+	unsigned long __tables;
+	int i, sz, nr_tables;
 
-	if (efi_enabled(EFI_64BIT))
+	if (efi_enabled(EFI_64BIT)) {
 		sz = sizeof(efi_config_table_64_t);
-	else
+		nr_tables = le64_to_cpu((__force __le64)efi.systab->nr_tables);
+		__tables = le64_to_cpu((__force __le64)efi.systab->tables);
+	} else {
 		sz = sizeof(efi_config_table_32_t);
+		nr_tables = le32_to_cpu((__force __le32)efi.systab->nr_tables);
+		__tables = le32_to_cpu((__force __le32)efi.systab->tables);
+	}
 
 	/*
 	 * Let's see what config tables the firmware passed to us.
 	 */
-	config_tables = early_memremap(efi.systab->tables,
-				       efi.systab->nr_tables * sz);
+	config_tables = early_memremap(__tables, nr_tables * sz);
 	if (config_tables == NULL) {
 		pr_err("Could not map Configuration table!\n");
 		return -ENOMEM;
@@ -289,21 +294,20 @@ int __init efi_config_init(efi_config_table_type_t *arch_tables)
 
 	tablep = config_tables;
 	pr_info("");
-	for (i = 0; i < efi.systab->nr_tables; i++) {
+	for (i = 0; i < nr_tables; i++) {
 		efi_guid_t guid;
 		unsigned long table;
 
 		if (efi_enabled(EFI_64BIT)) {
 			u64 table64;
 			guid = ((efi_config_table_64_t *)tablep)->guid;
-			table64 = ((efi_config_table_64_t *)tablep)->table;
-			table = table64;
+			table = table64 = le64_to_cpu((__force __le64)
+				((efi_config_table_64_t *)tablep)->table);
 #ifndef CONFIG_64BIT
 			if (table64 >> 32) {
 				pr_cont("\n");
 				pr_err("Table located above 4GB, disabling EFI.\n");
-				early_memunmap(config_tables,
-					       efi.systab->nr_tables * sz);
+				early_memunmap(config_tables, nr_tables * sz);
 				return -EINVAL;
 			}
 #endif
@@ -318,7 +322,7 @@ int __init efi_config_init(efi_config_table_type_t *arch_tables)
 		tablep += sz;
 	}
 	pr_cont("\n");
-	early_memunmap(config_tables, efi.systab->nr_tables * sz);
+	early_memunmap(config_tables, nr_tables * sz);
 
 	set_bit(EFI_CONFIG_TABLES, &efi.flags);
 
diff --git a/drivers/firmware/efi/efivars.c b/drivers/firmware/efi/efivars.c
index f256ecd8a176..e33181a779ab 100644
--- a/drivers/firmware/efi/efivars.c
+++ b/drivers/firmware/efi/efivars.c
@@ -563,7 +563,7 @@ efivar_create_sysfs_entry(struct efivar_entry *new_var)
 	/* Convert Unicode to normal chars (assume top bits are 0),
 	   ala UTF-8 */
 	for (i=0; i < (int)(variable_name_size / sizeof(efi_char16_t)); i++) {
-		short_name[i] = variable_name[i] & 0xFF;
+		short_name[i] = le16_to_cpu((__force __le16)variable_name[i]);
 	}
 	/* This is ugly, but necessary to separate one vendor's
 	   private variables from another's.         */
-- 
1.8.3.2

^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [RFC PATCH 09/10] arm64/efi: enable minimal UEFI Runtime Services for big endian
  2014-07-21 15:16 [RFC PATCH 00/10] arm64: boot BE kernels from UEFI Ard Biesheuvel
                   ` (7 preceding siblings ...)
  2014-07-21 15:16 ` [RFC PATCH 08/10] arm64/efi: use LE accessors to access UEFI data Ard Biesheuvel
@ 2014-07-21 15:16 ` Ard Biesheuvel
  2014-07-23  9:34   ` Mark Rutland
  2014-07-21 15:16 ` [RFC PATCH 10/10] arm64: Kconfig: enable UEFI on BE kernels Ard Biesheuvel
  9 siblings, 1 reply; 17+ messages in thread
From: Ard Biesheuvel @ 2014-07-21 15:16 UTC (permalink / raw)
  To: linux-arm-kernel

This enables the UEFI Runtime Services needed to manipulate the
non-volatile variable store when running under a BE kernel.

Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
---
 arch/arm64/include/asm/efi.h       |   2 +
 arch/arm64/kernel/efi-be-call.S    |  55 ++++++++++++++++++++
 arch/arm64/kernel/efi-be-runtime.c | 104 +++++++++++++++++++++++++++++++++++++
 arch/arm64/kernel/efi.c            |  15 ++++++
 4 files changed, 176 insertions(+)
 create mode 100644 arch/arm64/kernel/efi-be-call.S
 create mode 100644 arch/arm64/kernel/efi-be-runtime.c

diff --git a/arch/arm64/include/asm/efi.h b/arch/arm64/include/asm/efi.h
index a34fd3b12e2b..44e642b6ab61 100644
--- a/arch/arm64/include/asm/efi.h
+++ b/arch/arm64/include/asm/efi.h
@@ -44,4 +44,6 @@ extern void efi_idmap_init(void);
 
 #define efi_call_early(f, ...) sys_table_arg->boottime->f(__VA_ARGS__)
 
+extern void efi_be_runtime_setup(void);
+
 #endif /* _ASM_EFI_H */
diff --git a/arch/arm64/kernel/efi-be-call.S b/arch/arm64/kernel/efi-be-call.S
new file mode 100644
index 000000000000..24c92a4c352b
--- /dev/null
+++ b/arch/arm64/kernel/efi-be-call.S
@@ -0,0 +1,55 @@
+
+#include <linux/linkage.h>
+
+	.text
+	.align		3
+ENTRY(efi_be_phys_call)
+	/*
+	 * Entered at physical address with 1:1 mapping enabled.
+	 */
+	stp	x29, x30, [sp, #-96]!
+	mov	x29, sp
+	str	x27, [sp, #16]
+
+	ldr	x8, =efi_be_phys_call	// virt address of this function
+	adr	x9, efi_be_phys_call	// phys address of this function
+	sub	x9, x8, x9		// calculate virt to phys offset in x9
+
+	/* preserve all inputs */
+	stp	x0, x1, [sp, #32]
+	stp	x2, x3, [sp, #48]
+	stp	x4, x5, [sp, #64]
+	stp	x6, x7, [sp, #80]
+
+	/* get phys address of stack */
+	sub	sp, sp, x9
+
+	/* switch to LE, disable MMU and D-cache but leave I-cache enabled */
+	mrs	x27, sctlr_el1
+	bic	x8, x27, #1 << 2	// clear SCTLR.C
+	msr	sctlr_el1, x8
+
+	bl	flush_cache_all
+
+	/* restore inputs but rotated by 1 register */
+	ldp	x7, x0, [sp, #32]
+	ldp	x1, x2, [sp, #48]
+	ldp	x3, x4, [sp, #64]
+	ldp	x5, x6, [sp, #80]
+
+	bic	x8, x27, #1 << 2	// clear SCTLR.C
+	bic	x8, x8, #1 << 0		// clear SCTLR.M
+	bic	x8, x8, #1 << 25	// clear SCTLR.EE
+	msr	sctlr_el1, x8
+	isb
+
+	blr	x7
+
+	/* switch back to BE and reenable MMU and D-cache */
+	msr	sctlr_el1, x27
+
+	mov	sp, x29
+	ldr	x27, [sp, #16]
+	ldp	x29, x30, [sp], #96
+	ret
+ENDPROC(efi_be_phys_call)
diff --git a/arch/arm64/kernel/efi-be-runtime.c b/arch/arm64/kernel/efi-be-runtime.c
new file mode 100644
index 000000000000..62e6c441b77b
--- /dev/null
+++ b/arch/arm64/kernel/efi-be-runtime.c
@@ -0,0 +1,104 @@
+
+#include <linux/efi.h>
+#include <linux/spinlock.h>
+#include <asm/efi.h>
+#include <asm/neon.h>
+#include <asm/tlbflush.h>
+
+static efi_runtime_services_t *runtime;
+static efi_status_t (*efi_be_call)(phys_addr_t func, ...);
+
+static DEFINE_SPINLOCK(efi_be_rt_lock);
+
+static unsigned long efi_be_call_pre(void)
+{
+	unsigned long flags;
+
+	kernel_neon_begin();
+	spin_lock_irqsave(&efi_be_rt_lock, flags);
+	cpu_switch_mm(idmap_pg_dir, &init_mm);
+	flush_tlb_all();
+	return flags;
+}
+
+static void efi_be_call_post(unsigned long flags)
+{
+	cpu_switch_mm(current, current->active_mm);
+	flush_tlb_all();
+	spin_unlock_irqrestore(&efi_be_rt_lock, flags);
+	kernel_neon_end();
+}
+
+static efi_status_t efi_be_get_variable(efi_char16_t *name,
+					efi_guid_t *vendor,
+					u32 *attr,
+					unsigned long *data_size,
+					void *data)
+{
+	unsigned long flags;
+	efi_status_t status;
+
+	*data_size = cpu_to_le64(*data_size);
+	flags = efi_be_call_pre();
+	status = efi_be_call(le64_to_cpu(runtime->get_variable),
+			     virt_to_phys(name), virt_to_phys(vendor),
+			     virt_to_phys(attr), virt_to_phys(data_size),
+			     virt_to_phys(data));
+	efi_be_call_post(flags);
+	*attr = le32_to_cpu(*attr);
+	*data_size = le64_to_cpu(*data_size);
+	return status;
+}
+
+static efi_status_t efi_be_get_next_variable(unsigned long *name_size,
+					     efi_char16_t *name,
+					     efi_guid_t *vendor)
+{
+	unsigned long flags;
+	efi_status_t status;
+
+	*name_size = cpu_to_le64(*name_size);
+	flags = efi_be_call_pre();
+	status = efi_be_call(le64_to_cpu(runtime->get_next_variable),
+			     virt_to_phys(name_size), virt_to_phys(name),
+			     virt_to_phys(vendor));
+	efi_be_call_post(flags);
+	*name_size = le64_to_cpu(*name_size);
+	return status;
+}
+
+static efi_status_t efi_be_set_variable(efi_char16_t *name,
+					efi_guid_t *vendor,
+					u32 attr,
+					unsigned long data_size,
+					void *data)
+{
+	unsigned long flags;
+	efi_status_t status;
+
+	flags = efi_be_call_pre();
+	status = efi_be_call(le64_to_cpu(runtime->set_variable),
+			     virt_to_phys(name), virt_to_phys(vendor),
+			     cpu_to_le32(attr), cpu_to_le64(data_size),
+			     virt_to_phys(data));
+	efi_be_call_post(flags);
+	return status;
+}
+
+void efi_be_runtime_setup(void)
+{
+	extern u8 efi_be_phys_call[];
+
+	runtime = ioremap_cache(le64_to_cpu(efi.systab->runtime),
+				sizeof(efi_runtime_services_t));
+	if (!runtime) {
+		pr_err("Failed to set up BE wrappers for UEFI Runtime Services!\n");
+		return;
+	}
+
+	efi_be_call = (void *)virt_to_phys(efi_be_phys_call);
+
+	efi.get_variable = efi_be_get_variable;
+	efi.get_next_variable = efi_be_get_next_variable;
+	efi.set_variable = efi_be_set_variable;
+}
diff --git a/arch/arm64/kernel/efi.c b/arch/arm64/kernel/efi.c
index 96df58824189..21e98810c5dd 100644
--- a/arch/arm64/kernel/efi.c
+++ b/arch/arm64/kernel/efi.c
@@ -406,6 +406,21 @@ static int __init arm64_enter_virtual_mode(void)
 
 	efi.memmap = &memmap;
 
+	if (IS_ENABLED(CONFIG_CPU_BIG_ENDIAN)) {
+		efi.systab = ioremap_cache(efi_system_table,
+					   sizeof(efi_system_table_t));
+		if (!efi.systab) {
+			pr_err("Failed to remap EFI system table!\n");
+			return -1;
+		}
+		free_boot_services();
+		efi_be_runtime_setup();
+
+		set_bit(EFI_SYSTEM_TABLES, &efi.flags);
+		set_bit(EFI_RUNTIME_SERVICES, &efi.flags);
+		return 0;
+	}
+
 	/* Map the runtime regions */
 	virtmap = kmalloc(mapsize, GFP_KERNEL);
 	if (!virtmap) {
-- 
1.8.3.2

^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [RFC PATCH 10/10] arm64: Kconfig: enable UEFI on BE kernels
  2014-07-21 15:16 [RFC PATCH 00/10] arm64: boot BE kernels from UEFI Ard Biesheuvel
                   ` (8 preceding siblings ...)
  2014-07-21 15:16 ` [RFC PATCH 09/10] arm64/efi: enable minimal UEFI Runtime Services for big endian Ard Biesheuvel
@ 2014-07-21 15:16 ` Ard Biesheuvel
  9 siblings, 0 replies; 17+ messages in thread
From: Ard Biesheuvel @ 2014-07-21 15:16 UTC (permalink / raw)
  To: linux-arm-kernel

This changes the Kconfig logic to allow EFI to be enabled on a BE kernel build.

Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
---
 arch/arm64/Kconfig | 10 +++++++---
 1 file changed, 7 insertions(+), 3 deletions(-)

diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
index e9d8af2fc389..9fa1383acbd3 100644
--- a/arch/arm64/Kconfig
+++ b/arch/arm64/Kconfig
@@ -301,16 +301,20 @@ config CMDLINE_FORCE
 config EFI_STUB
 	bool
 
+config EFI_LE_STUB
+	bool
+
 config EFI
 	bool "UEFI runtime support"
-	depends on OF && !CPU_BIG_ENDIAN
+	depends on OF
 	select LIBFDT
 	select UCS2_STRING
 	select EFI_PARAMS_FROM_FDT
 	select EFI_RUNTIME_WRAPPERS
-	select EFI_STUB
+	select EFI_STUB if !CPU_BIG_ENDIAN
+	select EFI_LE_STUB if CPU_BIG_ENDIAN
 	select EFI_ARMSTUB
-	default y
+	default y if !CPU_BIG_ENDIAN
 	help
 	  This option provides support for runtime services provided
 	  by UEFI firmware (such as non-volatile variables, realtime
-- 
1.8.3.2

^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [RFC PATCH 09/10] arm64/efi: enable minimal UEFI Runtime Services for big endian
  2014-07-21 15:16 ` [RFC PATCH 09/10] arm64/efi: enable minimal UEFI Runtime Services for big endian Ard Biesheuvel
@ 2014-07-23  9:34   ` Mark Rutland
  2014-07-23 10:59     ` Ard Biesheuvel
  0 siblings, 1 reply; 17+ messages in thread
From: Mark Rutland @ 2014-07-23  9:34 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Ard,

This is certainly a neat feature, and I definitely want to be able to
boot BE kernels via UEFI.

However, I'm wary of calling EFI in a physical (i.e. idmap with dcaches
off) context. I'm not sure anyone else does that, and I'm not sure
whether that's going to work (both because of the cache maintenance
requirements and the expectations of a given UEFI implementation w.r.t.
memory cacheability).

I'd hoped we'd be able to use a LE EL0 context to call the runtime
services in, but I'm not sure that's possible by the spec :(

As I understand it, we shouldn't need these runtime services to simply
boot a BE kernel.

On Mon, Jul 21, 2014 at 04:16:24PM +0100, Ard Biesheuvel wrote:
> This enables the UEFI Runtime Services needed to manipulate the
> non-volatile variable store when running under a BE kernel.
> 
> Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
> ---
>  arch/arm64/include/asm/efi.h       |   2 +
>  arch/arm64/kernel/efi-be-call.S    |  55 ++++++++++++++++++++
>  arch/arm64/kernel/efi-be-runtime.c | 104 +++++++++++++++++++++++++++++++++++++
>  arch/arm64/kernel/efi.c            |  15 ++++++
>  4 files changed, 176 insertions(+)
>  create mode 100644 arch/arm64/kernel/efi-be-call.S
>  create mode 100644 arch/arm64/kernel/efi-be-runtime.c
> 
> diff --git a/arch/arm64/include/asm/efi.h b/arch/arm64/include/asm/efi.h
> index a34fd3b12e2b..44e642b6ab61 100644
> --- a/arch/arm64/include/asm/efi.h
> +++ b/arch/arm64/include/asm/efi.h
> @@ -44,4 +44,6 @@ extern void efi_idmap_init(void);
>  
>  #define efi_call_early(f, ...) sys_table_arg->boottime->f(__VA_ARGS__)
>  
> +extern void efi_be_runtime_setup(void);
> +
>  #endif /* _ASM_EFI_H */
> diff --git a/arch/arm64/kernel/efi-be-call.S b/arch/arm64/kernel/efi-be-call.S
> new file mode 100644
> index 000000000000..24c92a4c352b
> --- /dev/null
> +++ b/arch/arm64/kernel/efi-be-call.S
> @@ -0,0 +1,55 @@
> +
> +#include <linux/linkage.h>
> +
> +	.text
> +	.align		3
> +ENTRY(efi_be_phys_call)
> +	/*
> +	 * Entered at physical address with 1:1 mapping enabled.
> +	 */
> +	stp	x29, x30, [sp, #-96]!
> +	mov	x29, sp
> +	str	x27, [sp, #16]
> +
> +	ldr	x8, =efi_be_phys_call	// virt address of this function
> +	adr	x9, efi_be_phys_call	// phys address of this function
> +	sub	x9, x8, x9		// calculate virt to phys offset in x9
> +
> +	/* preserve all inputs */
> +	stp	x0, x1, [sp, #32]
> +	stp	x2, x3, [sp, #48]
> +	stp	x4, x5, [sp, #64]
> +	stp	x6, x7, [sp, #80]
> +
> +	/* get phys address of stack */
> +	sub	sp, sp, x9
> +
> +	/* switch to LE, disable MMU and D-cache but leave I-cache enabled */
> +	mrs	x27, sctlr_el1
> +	bic	x8, x27, #1 << 2	// clear SCTLR.C
> +	msr	sctlr_el1, x8
> +
> +	bl	flush_cache_all

What is the cache flush for?

The only thing that flush_cache_all can do is empty the local
architected caches, and it can only do that when said caches are
disabled. Any other use is unsafe; we have no guarantee that the cache
is empty (or even clean), and we have no guarantee that prior writes
have made it to the PoC.

Even when the caches are disabled, flush_cache_all can only guarantee
that the local architected caches are empty. There is no guarantee that
the dirty data made it to the PoC.

> +
> +	/* restore inputs but rotated by 1 register */
> +	ldp	x7, x0, [sp, #32]
> +	ldp	x1, x2, [sp, #48]
> +	ldp	x3, x4, [sp, #64]
> +	ldp	x5, x6, [sp, #80]
> +
> +	bic	x8, x27, #1 << 2	// clear SCTLR.C
> +	bic	x8, x8, #1 << 0		// clear SCTLR.M
> +	bic	x8, x8, #1 << 25	// clear SCTLR.EE
> +	msr	sctlr_el1, x8
> +	isb
> +
> +	blr	x7

Is it safe to call EFI functions with the D-cache disabled?

Do the functions not care about the memory attributes for their own sue
(e.g. for exclusives)? 

Do they not care about IO? If IO to/from storage for variables is
cache-coherent EFI and the device won't have a coherent view of memory.

> +
> +	/* switch back to BE and reenable MMU and D-cache */
> +	msr	sctlr_el1, x27
> +

Missing ISB?

> +	mov	sp, x29
> +	ldr	x27, [sp, #16]
> +	ldp	x29, x30, [sp], #96
> +	ret
> +ENDPROC(efi_be_phys_call)
> diff --git a/arch/arm64/kernel/efi-be-runtime.c b/arch/arm64/kernel/efi-be-runtime.c
> new file mode 100644
> index 000000000000..62e6c441b77b
> --- /dev/null
> +++ b/arch/arm64/kernel/efi-be-runtime.c
> @@ -0,0 +1,104 @@
> +
> +#include <linux/efi.h>
> +#include <linux/spinlock.h>
> +#include <asm/efi.h>
> +#include <asm/neon.h>
> +#include <asm/tlbflush.h>
> +
> +static efi_runtime_services_t *runtime;
> +static efi_status_t (*efi_be_call)(phys_addr_t func, ...);
> +
> +static DEFINE_SPINLOCK(efi_be_rt_lock);
> +
> +static unsigned long efi_be_call_pre(void)
> +{
> +	unsigned long flags;
> +
> +	kernel_neon_begin();
> +	spin_lock_irqsave(&efi_be_rt_lock, flags);

At this point we might still have DA_F unmasked, and I don't think we
expect to be able to handle any of those when the CPU is in the wrong
endianness for the kernel.

> +	cpu_switch_mm(idmap_pg_dir, &init_mm);
> +	flush_tlb_all();
> +	return flags;
> +}
> +
> +static void efi_be_call_post(unsigned long flags)
> +{
> +	cpu_switch_mm(current, current->active_mm);
> +	flush_tlb_all();
> +	spin_unlock_irqrestore(&efi_be_rt_lock, flags);
> +	kernel_neon_end();
> +}
> +
> +static efi_status_t efi_be_get_variable(efi_char16_t *name,
> +					efi_guid_t *vendor,
> +					u32 *attr,
> +					unsigned long *data_size,
> +					void *data)
> +{
> +	unsigned long flags;
> +	efi_status_t status;
> +
> +	*data_size = cpu_to_le64(*data_size);
> +	flags = efi_be_call_pre();
> +	status = efi_be_call(le64_to_cpu(runtime->get_variable),
> +			     virt_to_phys(name), virt_to_phys(vendor),
> +			     virt_to_phys(attr), virt_to_phys(data_size),
> +			     virt_to_phys(data));
> +	efi_be_call_post(flags);
> +	*attr = le32_to_cpu(*attr);
> +	*data_size = le64_to_cpu(*data_size);
> +	return status;

No cache maintenance? EFI Could have written to a physical mapping which
could be shadowed by old cache entries. Similarly any buffers that we
pass to UEFI aren't guaranteed to have been hit the PoC, so UEFI might
read stale data.

I think that's true for all of the efi_be_* calls below.

> +}
> +
> +static efi_status_t efi_be_get_next_variable(unsigned long *name_size,
> +					     efi_char16_t *name,
> +					     efi_guid_t *vendor)
> +{
> +	unsigned long flags;
> +	efi_status_t status;
> +
> +	*name_size = cpu_to_le64(*name_size);
> +	flags = efi_be_call_pre();
> +	status = efi_be_call(le64_to_cpu(runtime->get_next_variable),
> +			     virt_to_phys(name_size), virt_to_phys(name),
> +			     virt_to_phys(vendor));
> +	efi_be_call_post(flags);
> +	*name_size = le64_to_cpu(*name_size);
> +	return status;
> +}
> +
> +static efi_status_t efi_be_set_variable(efi_char16_t *name,
> +					efi_guid_t *vendor,
> +					u32 attr,
> +					unsigned long data_size,
> +					void *data)
> +{
> +	unsigned long flags;
> +	efi_status_t status;
> +
> +	flags = efi_be_call_pre();
> +	status = efi_be_call(le64_to_cpu(runtime->set_variable),
> +			     virt_to_phys(name), virt_to_phys(vendor),
> +			     cpu_to_le32(attr), cpu_to_le64(data_size),
> +			     virt_to_phys(data));
> +	efi_be_call_post(flags);
> +	return status;
> +}
> +
> +void efi_be_runtime_setup(void)
> +{
> +	extern u8 efi_be_phys_call[];
> +
> +	runtime = ioremap_cache(le64_to_cpu(efi.systab->runtime),
> +				sizeof(efi_runtime_services_t));
> +	if (!runtime) {
> +		pr_err("Failed to set up BE wrappers for UEFI Runtime Services!\n");
> +		return;
> +	}

Might it be worth propagating the error code?

> +
> +	efi_be_call = (void *)virt_to_phys(efi_be_phys_call);
> +
> +	efi.get_variable = efi_be_get_variable;
> +	efi.get_next_variable = efi_be_get_next_variable;
> +	efi.set_variable = efi_be_set_variable;
> +}
> diff --git a/arch/arm64/kernel/efi.c b/arch/arm64/kernel/efi.c
> index 96df58824189..21e98810c5dd 100644
> --- a/arch/arm64/kernel/efi.c
> +++ b/arch/arm64/kernel/efi.c
> @@ -406,6 +406,21 @@ static int __init arm64_enter_virtual_mode(void)
>  
>  	efi.memmap = &memmap;
>  
> +	if (IS_ENABLED(CONFIG_CPU_BIG_ENDIAN)) {
> +		efi.systab = ioremap_cache(efi_system_table,
> +					   sizeof(efi_system_table_t));
> +		if (!efi.systab) {
> +			pr_err("Failed to remap EFI system table!\n");
> +			return -1;
> +		}
> +		free_boot_services();
> +		efi_be_runtime_setup();

We can fail here, but we'll still set the bits below, which doesn't seem
right.

> +
> +		set_bit(EFI_SYSTEM_TABLES, &efi.flags);
> +		set_bit(EFI_RUNTIME_SERVICES, &efi.flags);
> +		return 0;
> +	}
> +
>  	/* Map the runtime regions */
>  	virtmap = kmalloc(mapsize, GFP_KERNEL);
>  	if (!virtmap) {
> -- 
> 1.8.3.2

Cheers,
Mark.

^ permalink raw reply	[flat|nested] 17+ messages in thread

* [RFC PATCH 09/10] arm64/efi: enable minimal UEFI Runtime Services for big endian
  2014-07-23  9:34   ` Mark Rutland
@ 2014-07-23 10:59     ` Ard Biesheuvel
  2014-07-23 17:52       ` Ard Biesheuvel
  0 siblings, 1 reply; 17+ messages in thread
From: Ard Biesheuvel @ 2014-07-23 10:59 UTC (permalink / raw)
  To: linux-arm-kernel

On 23 July 2014 11:34, Mark Rutland <mark.rutland@arm.com> wrote:
> Hi Ard,
>
> This is certainly a neat feature, and I definitely want to be able to
> boot BE kernels via UEFI.
>

Good!

> However, I'm wary of calling EFI in a physical (i.e. idmap with dcaches
> off) context. I'm not sure anyone else does that, and I'm not sure
> whether that's going to work (both because of the cache maintenance
> requirements and the expectations of a given UEFI implementation w.r.t.
> memory cacheability).
>

I have developed an alternate version in the mean time that switches
to a LE idmap (so with D-cache enabled), but this is an imperfect
solution as well, as (like in the MMU off case), the vector base
virtual address cannot be resolved when the EE bit is cleared (as
TTBR1 points to a BE page table) so any exception taken locks the
machine hard. I am not sure if this can be solved in any way other
than changing exception levels. Or install an alternate vector table
for the duration of the runtime services call that flips the EE bit
back, restores VBAR to its original address, and jumps into it. None
of this is very sexy, though ...

> I'd hoped we'd be able to use a LE EL0 context to call the runtime
> services in, but I'm not sure that's possible by the spec :(
>

Nope, they should be called at the exception level UEFI was started in
(as Leif tells me)

> As I understand it, we shouldn't need these runtime services to simply
> boot a BE kernel.
>

Well, the significance of the variable store related Runtime Services
is that they are used by an installer (through efibootmgr) to program
the kernel command line. Hence the choice for just these services in
the minimal implementation.

-- 
Ard.


> On Mon, Jul 21, 2014 at 04:16:24PM +0100, Ard Biesheuvel wrote:
>> This enables the UEFI Runtime Services needed to manipulate the
>> non-volatile variable store when running under a BE kernel.
>>
>> Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
>> ---
>>  arch/arm64/include/asm/efi.h       |   2 +
>>  arch/arm64/kernel/efi-be-call.S    |  55 ++++++++++++++++++++
>>  arch/arm64/kernel/efi-be-runtime.c | 104 +++++++++++++++++++++++++++++++++++++
>>  arch/arm64/kernel/efi.c            |  15 ++++++
>>  4 files changed, 176 insertions(+)
>>  create mode 100644 arch/arm64/kernel/efi-be-call.S
>>  create mode 100644 arch/arm64/kernel/efi-be-runtime.c
>>
>> diff --git a/arch/arm64/include/asm/efi.h b/arch/arm64/include/asm/efi.h
>> index a34fd3b12e2b..44e642b6ab61 100644
>> --- a/arch/arm64/include/asm/efi.h
>> +++ b/arch/arm64/include/asm/efi.h
>> @@ -44,4 +44,6 @@ extern void efi_idmap_init(void);
>>
>>  #define efi_call_early(f, ...) sys_table_arg->boottime->f(__VA_ARGS__)
>>
>> +extern void efi_be_runtime_setup(void);
>> +
>>  #endif /* _ASM_EFI_H */
>> diff --git a/arch/arm64/kernel/efi-be-call.S b/arch/arm64/kernel/efi-be-call.S
>> new file mode 100644
>> index 000000000000..24c92a4c352b
>> --- /dev/null
>> +++ b/arch/arm64/kernel/efi-be-call.S
>> @@ -0,0 +1,55 @@
>> +
>> +#include <linux/linkage.h>
>> +
>> +     .text
>> +     .align          3
>> +ENTRY(efi_be_phys_call)
>> +     /*
>> +      * Entered at physical address with 1:1 mapping enabled.
>> +      */
>> +     stp     x29, x30, [sp, #-96]!
>> +     mov     x29, sp
>> +     str     x27, [sp, #16]
>> +
>> +     ldr     x8, =efi_be_phys_call   // virt address of this function
>> +     adr     x9, efi_be_phys_call    // phys address of this function
>> +     sub     x9, x8, x9              // calculate virt to phys offset in x9
>> +
>> +     /* preserve all inputs */
>> +     stp     x0, x1, [sp, #32]
>> +     stp     x2, x3, [sp, #48]
>> +     stp     x4, x5, [sp, #64]
>> +     stp     x6, x7, [sp, #80]
>> +
>> +     /* get phys address of stack */
>> +     sub     sp, sp, x9
>> +
>> +     /* switch to LE, disable MMU and D-cache but leave I-cache enabled */
>> +     mrs     x27, sctlr_el1
>> +     bic     x8, x27, #1 << 2        // clear SCTLR.C
>> +     msr     sctlr_el1, x8
>> +
>> +     bl      flush_cache_all
>
> What is the cache flush for?
>
> The only thing that flush_cache_all can do is empty the local
> architected caches, and it can only do that when said caches are
> disabled. Any other use is unsafe; we have no guarantee that the cache
> is empty (or even clean), and we have no guarantee that prior writes
> have made it to the PoC.
>
> Even when the caches are disabled, flush_cache_all can only guarantee
> that the local architected caches are empty. There is no guarantee that
> the dirty data made it to the PoC.
>
>> +
>> +     /* restore inputs but rotated by 1 register */
>> +     ldp     x7, x0, [sp, #32]
>> +     ldp     x1, x2, [sp, #48]
>> +     ldp     x3, x4, [sp, #64]
>> +     ldp     x5, x6, [sp, #80]
>> +
>> +     bic     x8, x27, #1 << 2        // clear SCTLR.C
>> +     bic     x8, x8, #1 << 0         // clear SCTLR.M
>> +     bic     x8, x8, #1 << 25        // clear SCTLR.EE
>> +     msr     sctlr_el1, x8
>> +     isb
>> +
>> +     blr     x7
>
> Is it safe to call EFI functions with the D-cache disabled?
>
> Do the functions not care about the memory attributes for their own sue
> (e.g. for exclusives)?
>
> Do they not care about IO? If IO to/from storage for variables is
> cache-coherent EFI and the device won't have a coherent view of memory.
>
>> +
>> +     /* switch back to BE and reenable MMU and D-cache */
>> +     msr     sctlr_el1, x27
>> +
>
> Missing ISB?
>
>> +     mov     sp, x29
>> +     ldr     x27, [sp, #16]
>> +     ldp     x29, x30, [sp], #96
>> +     ret
>> +ENDPROC(efi_be_phys_call)
>> diff --git a/arch/arm64/kernel/efi-be-runtime.c b/arch/arm64/kernel/efi-be-runtime.c
>> new file mode 100644
>> index 000000000000..62e6c441b77b
>> --- /dev/null
>> +++ b/arch/arm64/kernel/efi-be-runtime.c
>> @@ -0,0 +1,104 @@
>> +
>> +#include <linux/efi.h>
>> +#include <linux/spinlock.h>
>> +#include <asm/efi.h>
>> +#include <asm/neon.h>
>> +#include <asm/tlbflush.h>
>> +
>> +static efi_runtime_services_t *runtime;
>> +static efi_status_t (*efi_be_call)(phys_addr_t func, ...);
>> +
>> +static DEFINE_SPINLOCK(efi_be_rt_lock);
>> +
>> +static unsigned long efi_be_call_pre(void)
>> +{
>> +     unsigned long flags;
>> +
>> +     kernel_neon_begin();
>> +     spin_lock_irqsave(&efi_be_rt_lock, flags);
>
> At this point we might still have DA_F unmasked, and I don't think we
> expect to be able to handle any of those when the CPU is in the wrong
> endianness for the kernel.
>
>> +     cpu_switch_mm(idmap_pg_dir, &init_mm);
>> +     flush_tlb_all();
>> +     return flags;
>> +}
>> +
>> +static void efi_be_call_post(unsigned long flags)
>> +{
>> +     cpu_switch_mm(current, current->active_mm);
>> +     flush_tlb_all();
>> +     spin_unlock_irqrestore(&efi_be_rt_lock, flags);
>> +     kernel_neon_end();
>> +}
>> +
>> +static efi_status_t efi_be_get_variable(efi_char16_t *name,
>> +                                     efi_guid_t *vendor,
>> +                                     u32 *attr,
>> +                                     unsigned long *data_size,
>> +                                     void *data)
>> +{
>> +     unsigned long flags;
>> +     efi_status_t status;
>> +
>> +     *data_size = cpu_to_le64(*data_size);
>> +     flags = efi_be_call_pre();
>> +     status = efi_be_call(le64_to_cpu(runtime->get_variable),
>> +                          virt_to_phys(name), virt_to_phys(vendor),
>> +                          virt_to_phys(attr), virt_to_phys(data_size),
>> +                          virt_to_phys(data));
>> +     efi_be_call_post(flags);
>> +     *attr = le32_to_cpu(*attr);
>> +     *data_size = le64_to_cpu(*data_size);
>> +     return status;
>
> No cache maintenance? EFI Could have written to a physical mapping which
> could be shadowed by old cache entries. Similarly any buffers that we
> pass to UEFI aren't guaranteed to have been hit the PoC, so UEFI might
> read stale data.
>
> I think that's true for all of the efi_be_* calls below.
>
>> +}
>> +
>> +static efi_status_t efi_be_get_next_variable(unsigned long *name_size,
>> +                                          efi_char16_t *name,
>> +                                          efi_guid_t *vendor)
>> +{
>> +     unsigned long flags;
>> +     efi_status_t status;
>> +
>> +     *name_size = cpu_to_le64(*name_size);
>> +     flags = efi_be_call_pre();
>> +     status = efi_be_call(le64_to_cpu(runtime->get_next_variable),
>> +                          virt_to_phys(name_size), virt_to_phys(name),
>> +                          virt_to_phys(vendor));
>> +     efi_be_call_post(flags);
>> +     *name_size = le64_to_cpu(*name_size);
>> +     return status;
>> +}
>> +
>> +static efi_status_t efi_be_set_variable(efi_char16_t *name,
>> +                                     efi_guid_t *vendor,
>> +                                     u32 attr,
>> +                                     unsigned long data_size,
>> +                                     void *data)
>> +{
>> +     unsigned long flags;
>> +     efi_status_t status;
>> +
>> +     flags = efi_be_call_pre();
>> +     status = efi_be_call(le64_to_cpu(runtime->set_variable),
>> +                          virt_to_phys(name), virt_to_phys(vendor),
>> +                          cpu_to_le32(attr), cpu_to_le64(data_size),
>> +                          virt_to_phys(data));
>> +     efi_be_call_post(flags);
>> +     return status;
>> +}
>> +
>> +void efi_be_runtime_setup(void)
>> +{
>> +     extern u8 efi_be_phys_call[];
>> +
>> +     runtime = ioremap_cache(le64_to_cpu(efi.systab->runtime),
>> +                             sizeof(efi_runtime_services_t));
>> +     if (!runtime) {
>> +             pr_err("Failed to set up BE wrappers for UEFI Runtime Services!\n");
>> +             return;
>> +     }
>
> Might it be worth propagating the error code?
>
>> +
>> +     efi_be_call = (void *)virt_to_phys(efi_be_phys_call);
>> +
>> +     efi.get_variable = efi_be_get_variable;
>> +     efi.get_next_variable = efi_be_get_next_variable;
>> +     efi.set_variable = efi_be_set_variable;
>> +}
>> diff --git a/arch/arm64/kernel/efi.c b/arch/arm64/kernel/efi.c
>> index 96df58824189..21e98810c5dd 100644
>> --- a/arch/arm64/kernel/efi.c
>> +++ b/arch/arm64/kernel/efi.c
>> @@ -406,6 +406,21 @@ static int __init arm64_enter_virtual_mode(void)
>>
>>       efi.memmap = &memmap;
>>
>> +     if (IS_ENABLED(CONFIG_CPU_BIG_ENDIAN)) {
>> +             efi.systab = ioremap_cache(efi_system_table,
>> +                                        sizeof(efi_system_table_t));
>> +             if (!efi.systab) {
>> +                     pr_err("Failed to remap EFI system table!\n");
>> +                     return -1;
>> +             }
>> +             free_boot_services();
>> +             efi_be_runtime_setup();
>
> We can fail here, but we'll still set the bits below, which doesn't seem
> right.
>
>> +
>> +             set_bit(EFI_SYSTEM_TABLES, &efi.flags);
>> +             set_bit(EFI_RUNTIME_SERVICES, &efi.flags);
>> +             return 0;
>> +     }
>> +
>>       /* Map the runtime regions */
>>       virtmap = kmalloc(mapsize, GFP_KERNEL);
>>       if (!virtmap) {
>> --
>> 1.8.3.2
>
> Cheers,
> Mark.

^ permalink raw reply	[flat|nested] 17+ messages in thread

* [RFC PATCH 09/10] arm64/efi: enable minimal UEFI Runtime Services for big endian
  2014-07-23 10:59     ` Ard Biesheuvel
@ 2014-07-23 17:52       ` Ard Biesheuvel
  0 siblings, 0 replies; 17+ messages in thread
From: Ard Biesheuvel @ 2014-07-23 17:52 UTC (permalink / raw)
  To: linux-arm-kernel

On 07/23/2014 12:59 PM, Ard Biesheuvel wrote:
> On 23 July 2014 11:34, Mark Rutland <mark.rutland@arm.com> wrote:
>> Hi Ard,
>>
>> This is certainly a neat feature, and I definitely want to be able to
>> boot BE kernels via UEFI.
>>
> 
> Good!
> 
>> However, I'm wary of calling EFI in a physical (i.e. idmap with dcaches
>> off) context. I'm not sure anyone else does that, and I'm not sure
>> whether that's going to work (both because of the cache maintenance
>> requirements and the expectations of a given UEFI implementation w.r.t.
>> memory cacheability).
>>
> 
> I have developed an alternate version in the mean time that switches
> to a LE idmap (so with D-cache enabled), but this is an imperfect
> solution as well, as (like in the MMU off case), the vector base
> virtual address cannot be resolved when the EE bit is cleared (as
> TTBR1 points to a BE page table) so any exception taken locks the
> machine hard. I am not sure if this can be solved in any way other
> than changing exception levels. Or install an alternate vector table
> for the duration of the runtime services call that flips the EE bit
> back, restores VBAR to its original address, and jumps into it. None
> of this is very sexy, though ...
> 
>> I'd hoped we'd be able to use a LE EL0 context to call the runtime
>> services in, but I'm not sure that's possible by the spec :(
>>
> 
> Nope, they should be called at the exception level UEFI was started in
> (as Leif tells me)
> 
>> As I understand it, we shouldn't need these runtime services to simply
>> boot a BE kernel.
>>
> 
> Well, the significance of the variable store related Runtime Services
> is that they are used by an installer (through efibootmgr) to program
> the kernel command line. Hence the choice for just these services in
> the minimal implementation.
> 

The below patch is an alternate approach with a LE id mapping in
efi_pg_dir. (Patch that sets it up omitted).

This dodges all the concerns related to caching, hopefully, as the LE id
mapping and the BE id mapping in idmap_pg_dir should agree on the memory
attributes of all common mappings.

This also addresses the FIQ and exception concerns, although I fully
realise that this is likely too controversial. Suggestions for less
controversial approaches are highly appreciated. As said, booting a BE
kernel is useful by itself, but without being able to use efibootmgr it
is a bit crippled.

-- 
Ard.


diff --git a/arch/arm64/include/asm/efi.h b/arch/arm64/include/asm/efi.h
index a34fd3b12e2b..2eeae5ae55b2 100644
--- a/arch/arm64/include/asm/efi.h
+++ b/arch/arm64/include/asm/efi.h
@@ -44,4 +44,6 @@ extern void efi_idmap_init(void);

 #define efi_call_early(f, ...) sys_table_arg->boottime->f(__VA_ARGS__)

+extern int efi_be_runtime_setup(void);
+
 #endif /* _ASM_EFI_H */
diff --git a/arch/arm64/kernel/efi-be-call.S
b/arch/arm64/kernel/efi-be-call.S
new file mode 100644
index 000000000000..8da53a225fab
--- /dev/null
+++ b/arch/arm64/kernel/efi-be-call.S
@@ -0,0 +1,129 @@
+
+#include <linux/linkage.h>
+
+	.macro	flush_tlb_all
+	dsb	ishst
+	tlbi	vmalle1is
+	dsb	ish
+	isb
+	.endm
+
+	.text
+	/*
+	 * Alternate vector table so we can trap exceptions while in LE mode
+	 * and make the world sane again before letting the kernel handle the
+	 * exception as usual. Clobbers x30.
+	 */
+	.align	12
+.Lvectors:
+	.irpc	i, 0123456789abcdef
+	.align	7
+	/* switch back to BE and temporarily disable MMU */
+	mrs	x30, sctlr_el1
+	bic	x30, x30, #1 << 0	// clear SCTLR.M
+	orr	x30, x30, #1 << 25	// set SCTLR.EE
+	msr	sctlr_el1, x30
+	isb
+
+	/* needed as TLBs are permitted to cache the EE bit */
+	flush_tlb_all
+
+	/* re-install BE idmap */
+	adrp	x30, idmap_pg_dir
+	msr	ttbr0_el1, x30
+	mrs	x30, sctlr_el1
+	orr	x30, x30, #1 << 0	// set SCTLR.M
+	msr	sctlr_el1, x30		// re-enable MMU
+	isb
+
+	/*
+	 * Use the virtual and physical addresses of 'vectors' to restore the
+	 * virtual offset of sp.
+	 */
+	adrp	x30, vectors
+	add	x30, x30, #:lo12:vectors
+	sub	sp, sp, x30
+	ldr	x30, =vectors
+	add	sp, sp, x30
+
+	/* reinstall vector table */
+	msr	vbar_el1, x30		// restore VBAR to 'vectors'
+	isb
+
+	add	x30, x30, #(0x\i * 0x80) // jump to real vector
+	ret
+	.endr
+
+ENTRY(efi_be_phys_call)
+	/*
+	 * Entered@physical address with 1:1 mapping enabled and interrupts
+	 * disabled.
+	 */
+	stp	x29, x30, [sp, #-48]!
+	mov	x29, sp
+	stp	x25, x26, [sp, #16]
+	stp	x27, x28, [sp, #32]
+
+	ldr	x8, =efi_be_phys_call	// virt address of this function
+	adr	x9, efi_be_phys_call	// phys address of this function
+	sub	x9, x8, x9		// calculate virt to phys offset in x9
+
+	/* get phys address of stack */
+	sub	sp, sp, x9
+
+	/* mask FIQs */
+	mrs	x25, daif
+	msr	daifset, #8
+
+	/* install alternate vector table */
+	mrs	x28, vbar_el1
+	adrp	x8, .Lvectors
+	msr	vbar_el1, x8
+
+	/* switch to LE and temporarily disable MMU */
+	mrs	x27, sctlr_el1
+	bic	x8, x27, #1 << 25	// clear SCTLR.EE
+	bic	x9, x8, #1 << 0		// clear SCTLR.M
+	msr	sctlr_el1, x9
+	isb
+
+	/* needed as TLBs are permitted to cache the EE bit */
+	flush_tlb_all
+
+	/* install LE idmap */
+	adrp	x9, efi_pg_dir
+	msr	ttbr0_el1, x9
+	msr	sctlr_el1, x8		// re-enable MMU
+	isb
+
+	/* restore inputs but rotated by 1 register */
+	mov	x6, x0
+	mov	x0, x1
+	mov	x1, x2
+	mov	x2, x3
+	mov	x3, x4
+	mov	x4, x5
+	blr	x6
+
+	/* switch back to BE and temporarily disable MMU */
+	bic	x9, x27, #1 << 0	// clear SCTLR.M
+	msr	sctlr_el1, x9
+	isb
+
+	/* needed as TLBs are permitted to cache the EE bit */
+	flush_tlb_all
+
+	/* re-install BE idmap */
+	adrp	x8, idmap_pg_dir
+	msr	ttbr0_el1, x8
+	msr	sctlr_el1, x27		// re-enable MMU
+	msr	vbar_el1, x28		// restore VBAR
+	msr	daif, x25
+	isb
+
+	mov	sp, x29
+	ldp	x25, x26, [sp, #16]
+	ldp	x27, x28, [sp, #32]
+	ldp	x29, x30, [sp], #48
+	ret
+ENDPROC(efi_be_phys_call)
diff --git a/arch/arm64/kernel/efi-be-runtime.c
b/arch/arm64/kernel/efi-be-runtime.c
new file mode 100644
index 000000000000..abcc275481bd
--- /dev/null
+++ b/arch/arm64/kernel/efi-be-runtime.c
@@ -0,0 +1,105 @@
+
+#include <linux/efi.h>
+#include <linux/spinlock.h>
+#include <asm/efi.h>
+#include <asm/neon.h>
+#include <asm/tlbflush.h>
+
+static efi_runtime_services_t *runtime;
+static efi_status_t (*efi_be_call)(phys_addr_t func, ...);
+
+static DEFINE_SPINLOCK(efi_be_rt_lock);
+
+static unsigned long efi_be_call_pre(void)
+{
+	unsigned long flags;
+
+	kernel_neon_begin();
+	spin_lock_irqsave(&efi_be_rt_lock, flags);
+	cpu_switch_mm(idmap_pg_dir, &init_mm);
+	flush_tlb_all();
+	return flags;
+}
+
+static void efi_be_call_post(unsigned long flags)
+{
+	cpu_switch_mm(current, current->active_mm);
+	flush_tlb_all();
+	spin_unlock_irqrestore(&efi_be_rt_lock, flags);
+	kernel_neon_end();
+}
+
+static efi_status_t efi_be_get_variable(efi_char16_t *name,
+					efi_guid_t *vendor,
+					u32 *attr,
+					unsigned long *data_size,
+					void *data)
+{
+	unsigned long flags;
+	efi_status_t status;
+
+	*data_size = cpu_to_le64(*data_size);
+	flags = efi_be_call_pre();
+	status = efi_be_call(le64_to_cpu(runtime->get_variable),
+			     virt_to_phys(name), virt_to_phys(vendor),
+			     virt_to_phys(attr), virt_to_phys(data_size),
+			     virt_to_phys(data));
+	efi_be_call_post(flags);
+	*attr = le32_to_cpu(*attr);
+	*data_size = le64_to_cpu(*data_size);
+	return status;
+}
+
+static efi_status_t efi_be_get_next_variable(unsigned long *name_size,
+					     efi_char16_t *name,
+					     efi_guid_t *vendor)
+{
+	unsigned long flags;
+	efi_status_t status;
+
+	*name_size = cpu_to_le64(*name_size);
+	flags = efi_be_call_pre();
+	status = efi_be_call(le64_to_cpu(runtime->get_next_variable),
+			     virt_to_phys(name_size), virt_to_phys(name),
+			     virt_to_phys(vendor));
+	efi_be_call_post(flags);
+	*name_size = le64_to_cpu(*name_size);
+	return status;
+}
+
+static efi_status_t efi_be_set_variable(efi_char16_t *name,
+					efi_guid_t *vendor,
+					u32 attr,
+					unsigned long data_size,
+					void *data)
+{
+	unsigned long flags;
+	efi_status_t status;
+
+	flags = efi_be_call_pre();
+	status = efi_be_call(le64_to_cpu(runtime->set_variable),
+			     virt_to_phys(name), virt_to_phys(vendor),
+			     attr, data_size, virt_to_phys(data));
+	efi_be_call_post(flags);
+	return status;
+}
+
+int efi_be_runtime_setup(void)
+{
+	extern u8 efi_be_phys_call[];
+
+	runtime = ioremap_cache(le64_to_cpu(efi.systab->runtime),
+				sizeof(efi_runtime_services_t));
+	if (!runtime) {
+		pr_err("Failed to set up BE wrappers for UEFI Runtime Services!\n");
+		return -EFAULT;
+	}
+
+	efi_be_call = (void *)virt_to_phys(efi_be_phys_call);
+
+	efi.get_variable = efi_be_get_variable;
+	efi.get_next_variable = efi_be_get_next_variable;
+	efi.set_variable = efi_be_set_variable;
+
+	return 0;
+}
diff --git a/arch/arm64/kernel/efi.c b/arch/arm64/kernel/efi.c
index c65c6a50395d..3f28854e96a9 100644
--- a/arch/arm64/kernel/efi.c
+++ b/arch/arm64/kernel/efi.c
@@ -426,6 +426,20 @@ static int __init arm64_enter_virtual_mode(void)

 	efi.memmap = &memmap;

+	if (IS_ENABLED(CONFIG_CPU_BIG_ENDIAN)) {
+		efi.systab = ioremap_cache(efi_system_table,
+					   sizeof(efi_system_table_t));
+		if (!efi.systab) {
+			pr_err("Failed to remap EFI system table!\n");
+			return -1;
+		}
+		free_boot_services();
+		set_bit(EFI_SYSTEM_TABLES, &efi.flags);
+		if (efi_be_runtime_setup() == 0)
+			set_bit(EFI_RUNTIME_SERVICES, &efi.flags);
+		return 0;
+	}
+
 	/* Map the runtime regions */
 	virtmap = kmalloc(mapsize, GFP_KERNEL);
 	if (!virtmap) {

^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [RFC PATCH 04/10] arm64: add EFI little endian constants to linker script
  2014-07-21 15:16 ` [RFC PATCH 04/10] arm64: add EFI little endian constants to linker script Ard Biesheuvel
@ 2014-07-30 14:18   ` Matt Fleming
  2014-07-30 14:21     ` Ard Biesheuvel
  2014-07-30 14:22     ` Will Deacon
  0 siblings, 2 replies; 17+ messages in thread
From: Matt Fleming @ 2014-07-30 14:18 UTC (permalink / raw)
  To: linux-arm-kernel

On Mon, 21 Jul, at 05:16:19PM, Ard Biesheuvel wrote:
> Similar to how text offset and kernel size are mangled to produce little
> endian constants for the Image header regardless of the endianness of the
> kernel, this adds a number of constants used in the EFI PE/COFF header which
> can only be calculated (and byte swapped) by the linker.
> 
> Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
> ---
>  arch/arm64/kernel/image.h | 16 +++++++++++++++-
>  1 file changed, 15 insertions(+), 1 deletion(-)

Where is this file? I can't find it in Linus' tree.

-- 
Matt Fleming, Intel Open Source Technology Center

^ permalink raw reply	[flat|nested] 17+ messages in thread

* [RFC PATCH 04/10] arm64: add EFI little endian constants to linker script
  2014-07-30 14:18   ` Matt Fleming
@ 2014-07-30 14:21     ` Ard Biesheuvel
  2014-07-30 14:22     ` Will Deacon
  1 sibling, 0 replies; 17+ messages in thread
From: Ard Biesheuvel @ 2014-07-30 14:21 UTC (permalink / raw)
  To: linux-arm-kernel

On 30 July 2014 16:18, Matt Fleming <matt@console-pimps.org> wrote:
> On Mon, 21 Jul, at 05:16:19PM, Ard Biesheuvel wrote:
>> Similar to how text offset and kernel size are mangled to produce little
>> endian constants for the Image header regardless of the endianness of the
>> kernel, this adds a number of constants used in the EFI PE/COFF header which
>> can only be calculated (and byte swapped) by the linker.
>>
>> Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
>> ---
>>  arch/arm64/kernel/image.h | 16 +++++++++++++++-
>>  1 file changed, 15 insertions(+), 1 deletion(-)
>
> Where is this file? I can't find it in Linus' tree.
>

Apologies, I failed to mention that this series depends on arm64 for-next/core

https://git.kernel.org/cgit/linux/kernel/git/arm64/linux.git/log/?h=for-next/core

-- 
Ard.

^ permalink raw reply	[flat|nested] 17+ messages in thread

* [RFC PATCH 04/10] arm64: add EFI little endian constants to linker script
  2014-07-30 14:18   ` Matt Fleming
  2014-07-30 14:21     ` Ard Biesheuvel
@ 2014-07-30 14:22     ` Will Deacon
  1 sibling, 0 replies; 17+ messages in thread
From: Will Deacon @ 2014-07-30 14:22 UTC (permalink / raw)
  To: linux-arm-kernel

On Wed, Jul 30, 2014 at 03:18:05PM +0100, Matt Fleming wrote:
> On Mon, 21 Jul, at 05:16:19PM, Ard Biesheuvel wrote:
> > Similar to how text offset and kernel size are mangled to produce little
> > endian constants for the Image header regardless of the endianness of the
> > kernel, this adds a number of constants used in the EFI PE/COFF header which
> > can only be calculated (and byte swapped) by the linker.
> > 
> > Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
> > ---
> >  arch/arm64/kernel/image.h | 16 +++++++++++++++-
> >  1 file changed, 15 insertions(+), 1 deletion(-)
> 
> Where is this file? I can't find it in Linus' tree.

It's queued in the arm64 tree for 3.17 (should also appear in -next at the
moment).

See commit a2c1d73b94ed ("arm64: Update the Image header").

Will

^ permalink raw reply	[flat|nested] 17+ messages in thread

end of thread, other threads:[~2014-07-30 14:22 UTC | newest]

Thread overview: 17+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2014-07-21 15:16 [RFC PATCH 00/10] arm64: boot BE kernels from UEFI Ard Biesheuvel
2014-07-21 15:16 ` [RFC PATCH 01/10] arm64/efi: efistub: jump to 'stext' directly, not through the header Ard Biesheuvel
2014-07-21 15:16 ` [RFC PATCH 02/10] arm64/efi: efistub: cover entire static mem footprint in PE/COFF .text Ard Biesheuvel
2014-07-21 15:16 ` [RFC PATCH 03/10] arm64: add macros to emit little endian ASM constants Ard Biesheuvel
2014-07-21 15:16 ` [RFC PATCH 04/10] arm64: add EFI little endian constants to linker script Ard Biesheuvel
2014-07-30 14:18   ` Matt Fleming
2014-07-30 14:21     ` Ard Biesheuvel
2014-07-30 14:22     ` Will Deacon
2014-07-21 15:16 ` [RFC PATCH 05/10] arm64/efi: update the PE/COFF header to be endian agnostic Ard Biesheuvel
2014-07-21 15:16 ` [RFC PATCH 06/10] arm64/efi: efistub: avoid using linker defined constants Ard Biesheuvel
2014-07-21 15:16 ` [RFC PATCH 07/10] arm64/efi: efistub: add support for booting a BE kernel Ard Biesheuvel
2014-07-21 15:16 ` [RFC PATCH 08/10] arm64/efi: use LE accessors to access UEFI data Ard Biesheuvel
2014-07-21 15:16 ` [RFC PATCH 09/10] arm64/efi: enable minimal UEFI Runtime Services for big endian Ard Biesheuvel
2014-07-23  9:34   ` Mark Rutland
2014-07-23 10:59     ` Ard Biesheuvel
2014-07-23 17:52       ` Ard Biesheuvel
2014-07-21 15:16 ` [RFC PATCH 10/10] arm64: Kconfig: enable UEFI on BE kernels 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).