All the mail mirrored from lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 0/4] arm64: simplify restrictions on bootloaders
@ 2014-05-16  9:50 Mark Rutland
  2014-05-16  9:50 ` [PATCH 1/4] arm64: head.S: remove unnecessary function alignment Mark Rutland
                   ` (4 more replies)
  0 siblings, 5 replies; 26+ messages in thread
From: Mark Rutland @ 2014-05-16  9:50 UTC (permalink / raw
  To: linux-arm-kernel

Currently bootloaders have an extremely difficult time protecting memory from
the kernel, as the kernel may clobber memory below TEXT_OFFSET with pagetables,
and above the end of the kernel binary with the BSS.

This series attempts to ameliorate matters by adding a mechanism for
bootloaders to discover the minimum runtime footprint of the kernel image,
including the BSS and any other dynamically initialised data, and moving the
initial page tables into this region.

The currently ill-described image load offset variable is coerced to always be
little-endian. This means that bootloader can actually make use of the field
for any kernel (wither LE or BE), and as the field does not yet seem to be used
anywhere taking endianness into account I hope this is not problematic.
Documentation is updated with recommendations on handling the field. To aid in
encouraging bootloader authors to respect the field, an option is added to
randomize the text_offset field at link time, which may be used in test and/or
distribution kernels. So as to not break existing (but arguably broken) loaders
immediately, this option is hidden under kernel hacking and disabled by
default.

The documentation is updated to cover how to use the new image_size field and
what to do if it is zero, and how to use the image_size field to determine
whether the text_offset field is guaranteed to be little-endian. The
recommended fallback reservation of 1MB is an arbitrary large value; for me
_end - _edata was ~190k for a defconfig build on v3.14 with patch 1 applied.
I'm happy to increase this to a larger arbitrary value if this seems too small.

A BE conditional 64-bit endianness swapping routine (DATA_LE64) is added to
vmlinux.lds.S, as the linker is the only place we can endianness swap a value
calulated from two symbols known only at link time. There are several existing
headers that do almost the same thing but due to use of C prototypes and/or
casts are not suitable for use in a linker script. A separate series may be
able to unify that.

This series applies to v3.15-rc5, and is not based on the EFI stub patches.
However I believe the field I've chosen to use is available even with the EFI
stub patches and shouldn't need to be moved around. I'm happy to rebase as
necessary.

I've given some light testing to text_offset fuzzing with an updated
bootwrapper [1] which reads the text_offset field at build time to ensure the
kernel gets loaded at the right address. Nothing else is yet moved however, so
this may explode if this location happens to overlap the bootwrapper code, DTB,
or spin-table mbox. I'll try to teach the bootwrapper how to deal with that
shortly.

Cheers,
Mark.

[1] http://linux-arm.org/git?p=boot-wrapper-aarch64.git;a=shortlog;h=refs/heads/unstable/text-offset

Mark Rutland (4):
  arm64: head.S: remove unnecessary function alignment
  arm64: place initial page tables above the kernel
  arm64: export effective Image size to bootloaders
  arm64: Enable TEXT_OFFSET fuzzing

 Documentation/arm64/booting.txt | 28 +++++++++++++++++++-----
 arch/arm64/Kconfig.debug        | 31 +++++++++++++++++++++++++++
 arch/arm64/Makefile             |  6 +++++-
 arch/arm64/include/asm/page.h   |  9 ++++++++
 arch/arm64/kernel/head.S        | 47 +++++++++++++++++++----------------------
 arch/arm64/kernel/vmlinux.lds.S | 40 +++++++++++++++++++++++++++++++++++
 arch/arm64/mm/init.c            | 12 ++++-------
 7 files changed, 134 insertions(+), 39 deletions(-)

-- 
1.9.1

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

* [PATCH 1/4] arm64: head.S: remove unnecessary function alignment
  2014-05-16  9:50 [PATCH 0/4] arm64: simplify restrictions on bootloaders Mark Rutland
@ 2014-05-16  9:50 ` Mark Rutland
  2014-05-16 13:04   ` Christopher Covington
  2014-05-20 16:20   ` Laura Abbott
  2014-05-16  9:50 ` [PATCH 2/4] arm64: place initial page tables above the kernel Mark Rutland
                   ` (3 subsequent siblings)
  4 siblings, 2 replies; 26+ messages in thread
From: Mark Rutland @ 2014-05-16  9:50 UTC (permalink / raw
  To: linux-arm-kernel

Currently __turn_mmu_on is aligned to 64 bytes to ensure that it doesn't
span any page boundary, which simplifies the idmap and spares us
requiring an additional page table to map half of the function. In
keeping with other important requirements in architecture code, this
fact is undocumented.

Additionally, as the function consists of three instructions totalling
12 bytes with no literal pool data, a smaller alignment of 16 bytes
would be sufficient.

This patch reduces the alignment to 16 bytes and documents the
underlying reason for the alignment. This reduces the required alignment
of the entire .head.text section from 64 bytes to 16 bytes, though it
may still be aligned to a larger value depending on TEXT_OFFSET.

Signed-off-by: Mark Rutland <mark.rutland@arm.com>
---
 arch/arm64/kernel/head.S | 7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)

diff --git a/arch/arm64/kernel/head.S b/arch/arm64/kernel/head.S
index 0fd5650..e8e9883 100644
--- a/arch/arm64/kernel/head.S
+++ b/arch/arm64/kernel/head.S
@@ -346,8 +346,13 @@ ENDPROC(__enable_mmu)
  *  x27 = *virtual* address to jump to upon completion
  *
  * other registers depend on the function called upon completion
+ *
+ * We align the entire function to the smallest power of two larger than it to
+ * ensure it fits within a single block map entry. Otherwise were PHYS_OFFSET
+ * close to the end of a 512MB or 1GB block we might require an additional
+ * table to map the entire function.
  */
-	.align	6
+	.align	4
 __turn_mmu_on:
 	msr	sctlr_el1, x0
 	isb
-- 
1.9.1

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

* [PATCH 2/4] arm64: place initial page tables above the kernel
  2014-05-16  9:50 [PATCH 0/4] arm64: simplify restrictions on bootloaders Mark Rutland
  2014-05-16  9:50 ` [PATCH 1/4] arm64: head.S: remove unnecessary function alignment Mark Rutland
@ 2014-05-16  9:50 ` Mark Rutland
  2014-05-20 16:21   ` Laura Abbott
  2014-05-16  9:50 ` [PATCH 3/4] arm64: export effective Image size to bootloaders Mark Rutland
                   ` (2 subsequent siblings)
  4 siblings, 1 reply; 26+ messages in thread
From: Mark Rutland @ 2014-05-16  9:50 UTC (permalink / raw
  To: linux-arm-kernel

Currently we place swapper_pg_dir and idmap_pg_dir below the kernel
image, between PHYS_OFFSET and (PHYS_OFFSET + TEXT_OFFSET). However,
bootloaders may use portions of this memory below the kernel and we do
not parse the memory reservation list until after the MMU has been
enabled. As such we may clobber some memory a bootloader wishes to have
preserved.

To enable the use of all of this memory by bootloaders (when the
required memory reservations are communicated to the kernel) it is
necessary to move our initial page tables elsewhere. As we currently
have an effectively unbound requirement for memory at the end of the
kernel image for .bss, we can place the page tables here.

This patch moves the initial page table to the end of the kernel image,
after the BSS. As they do not consist of any initialised data they will
be stripped from the kernel Image as with the BSS. The BSS clearing
routine is updated to stop at __bss_stop rather than _end so as to not
clobber the page tables, and memory reservations made redundant by the
new organisation are removed.

Signed-off-by: Mark Rutland <mark.rutland@arm.com>
---
 arch/arm64/include/asm/page.h   |  9 +++++++++
 arch/arm64/kernel/head.S        | 28 ++++++++--------------------
 arch/arm64/kernel/vmlinux.lds.S |  7 +++++++
 arch/arm64/mm/init.c            | 12 ++++--------
 4 files changed, 28 insertions(+), 28 deletions(-)

diff --git a/arch/arm64/include/asm/page.h b/arch/arm64/include/asm/page.h
index 46bf666..a6331e6 100644
--- a/arch/arm64/include/asm/page.h
+++ b/arch/arm64/include/asm/page.h
@@ -31,6 +31,15 @@
 /* We do define AT_SYSINFO_EHDR but don't use the gate mechanism */
 #define __HAVE_ARCH_GATE_AREA		1
 
+/*
+ * The idmap and swapper page tables need some space reserved in the kernel
+ * image. The idmap only requires a pgd and a next level table to (section) map
+ * the kernel, while the swapper also maps the FDT and requires an additional
+ * table to map an early UART. See __create_page_tables for more information.
+ */
+#define SWAPPER_DIR_SIZE	(3 * PAGE_SIZE)
+#define IDMAP_DIR_SIZE		(2 * PAGE_SIZE)
+
 #ifndef __ASSEMBLY__
 
 #ifdef CONFIG_ARM64_64K_PAGES
diff --git a/arch/arm64/kernel/head.S b/arch/arm64/kernel/head.S
index e8e9883..5dd8127 100644
--- a/arch/arm64/kernel/head.S
+++ b/arch/arm64/kernel/head.S
@@ -35,29 +35,17 @@
 #include <asm/page.h>
 #include <asm/virt.h>
 
-/*
- * swapper_pg_dir is the virtual address of the initial page table. We place
- * the page tables 3 * PAGE_SIZE below KERNEL_RAM_VADDR. The idmap_pg_dir has
- * 2 pages and is placed below swapper_pg_dir.
- */
 #define KERNEL_RAM_VADDR	(PAGE_OFFSET + TEXT_OFFSET)
 
 #if (KERNEL_RAM_VADDR & 0xfffff) != 0x80000
 #error KERNEL_RAM_VADDR must start at 0xXXX80000
 #endif
 
-#define SWAPPER_DIR_SIZE	(3 * PAGE_SIZE)
-#define IDMAP_DIR_SIZE		(2 * PAGE_SIZE)
-
-	.globl	swapper_pg_dir
-	.equ	swapper_pg_dir, KERNEL_RAM_VADDR - SWAPPER_DIR_SIZE
-
-	.globl	idmap_pg_dir
-	.equ	idmap_pg_dir, swapper_pg_dir - IDMAP_DIR_SIZE
-
-	.macro	pgtbl, ttb0, ttb1, phys
-	add	\ttb1, \phys, #TEXT_OFFSET - SWAPPER_DIR_SIZE
-	sub	\ttb0, \ttb1, #IDMAP_DIR_SIZE
+	.macro	pgtbl, ttb0, ttb1, virt_to_phys
+	ldr	\ttb1, =swapper_pg_dir
+	ldr	\ttb0, =idmap_pg_dir
+	add	\ttb1, \ttb1, \virt_to_phys
+	add	\ttb0, \ttb0, \virt_to_phys
 	.endm
 
 #ifdef CONFIG_ARM64_64K_PAGES
@@ -304,7 +292,7 @@ ENTRY(secondary_startup)
 	mov	x23, x0				// x23=current cpu_table
 	cbz	x23, __error_p			// invalid processor (x23=0)?
 
-	pgtbl	x25, x26, x24			// x25=TTBR0, x26=TTBR1
+	pgtbl	x25, x26, x28			// x25=TTBR0, x26=TTBR1
 	ldr	x12, [x23, #CPU_INFO_SETUP]
 	add	x12, x12, x28			// __virt_to_phys
 	blr	x12				// initialise processor
@@ -418,7 +406,7 @@ ENDPROC(__calc_phys_offset)
  *   - pgd entry for fixed mappings (TTBR1)
  */
 __create_page_tables:
-	pgtbl	x25, x26, x24			// idmap_pg_dir and swapper_pg_dir addresses
+	pgtbl	x25, x26, x28			// idmap_pg_dir and swapper_pg_dir addresses
 	mov	x27, lr
 
 	/*
@@ -507,7 +495,7 @@ ENDPROC(__create_page_tables)
 __switch_data:
 	.quad	__mmap_switched
 	.quad	__bss_start			// x6
-	.quad	_end				// x7
+	.quad	__bss_stop			// x7
 	.quad	processor_id			// x4
 	.quad	__fdt_pointer			// x5
 	.quad	memstart_addr			// x6
diff --git a/arch/arm64/kernel/vmlinux.lds.S b/arch/arm64/kernel/vmlinux.lds.S
index 4ba7a55..51258bc 100644
--- a/arch/arm64/kernel/vmlinux.lds.S
+++ b/arch/arm64/kernel/vmlinux.lds.S
@@ -104,6 +104,13 @@ SECTIONS
 	_edata = .;
 
 	BSS_SECTION(0, 0, 0)
+
+	. = ALIGN(PAGE_SIZE);
+	idmap_pg_dir = .;
+	. += IDMAP_DIR_SIZE;
+	swapper_pg_dir = .;
+	. += SWAPPER_DIR_SIZE;
+
 	_end = .;
 
 	STABS_DEBUG
diff --git a/arch/arm64/mm/init.c b/arch/arm64/mm/init.c
index 51d5352..cc3339d 100644
--- a/arch/arm64/mm/init.c
+++ b/arch/arm64/mm/init.c
@@ -128,20 +128,16 @@ void __init arm64_memblock_init(void)
 {
 	u64 *reserve_map, base, size;
 
-	/* Register the kernel text, kernel data and initrd with memblock */
+	/*
+	 * Register the kernel text, kernel data, initrd, and initial
+	 * pagetables with memblock.
+	 */
 	memblock_reserve(__pa(_text), _end - _text);
 #ifdef CONFIG_BLK_DEV_INITRD
 	if (initrd_start)
 		memblock_reserve(__virt_to_phys(initrd_start), initrd_end - initrd_start);
 #endif
 
-	/*
-	 * Reserve the page tables.  These are already in use,
-	 * and can only be in node 0.
-	 */
-	memblock_reserve(__pa(swapper_pg_dir), SWAPPER_DIR_SIZE);
-	memblock_reserve(__pa(idmap_pg_dir), IDMAP_DIR_SIZE);
-
 	/* Reserve the dtb region */
 	memblock_reserve(virt_to_phys(initial_boot_params),
 			 be32_to_cpu(initial_boot_params->totalsize));
-- 
1.9.1

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

* [PATCH 3/4] arm64: export effective Image size to bootloaders
  2014-05-16  9:50 [PATCH 0/4] arm64: simplify restrictions on bootloaders Mark Rutland
  2014-05-16  9:50 ` [PATCH 1/4] arm64: head.S: remove unnecessary function alignment Mark Rutland
  2014-05-16  9:50 ` [PATCH 2/4] arm64: place initial page tables above the kernel Mark Rutland
@ 2014-05-16  9:50 ` Mark Rutland
  2014-05-20 14:12   ` Tom Rini
                     ` (2 more replies)
  2014-05-16  9:50 ` [PATCH 4/4] arm64: Enable TEXT_OFFSET fuzzing Mark Rutland
  2014-05-20 11:31 ` [PATCH 0/4] arm64: simplify restrictions on bootloaders Ian Campbell
  4 siblings, 3 replies; 26+ messages in thread
From: Mark Rutland @ 2014-05-16  9:50 UTC (permalink / raw
  To: linux-arm-kernel

Currently the kernel Image is stripped of everything past the initial
stack, and at runtime the memory is initialised and used by the kernel.
This makes the effective minimum memory footprint of the kernel larger
than the size of the loaded binary, though bootloaders have no mechanism
to identify how large this minimum memory footprint is. This makes it
difficult to choose safe locations to place both the kernel and other
binaries required at boot (DTB, initrd, etc), such that the kernel won't
clobber said binaries or other reserved memory during initialisation.

Additionally when big endian support was added the image load offset was
overlooked, and is currently of an arbitrary endianness, which makes it
difficult for bootloaders to make use of it. It seems that bootloaders
aren't respecting the image load offset at present anyway, and are
assuming that offset 0x80000 will always be correct.

This patch adds an effective image size to the kernel header which
describes the amount of memory from the start of the kernel Image binary
which the kernel expects to use before detecting memory and handling any
memory reservations. This can be used by bootloaders to choose suitable
locations to load the kernel and/or other binaries such that the kernel
will not clobber any memory unexpectedly. As before, memory reservations
are required to prevent the kernel from clobbering these locations
later.

Both the image load offset and the effective image size are forced to be
little-endian regardless of the native endianness of the kernel to
enable bootloaders to load a kernel of arbitrary endianness. Bootloaders
which wish to make use of the load offset can inspect the effective
image size field for a non-zero value to determine if the offset is of a
known endianness.

The documentation is updated to clarify these details. To discourage
future assumptions regarding the value of text_offset, the value at this
point in time is removed from the main flow of the documentation (though
kept as a compatibility note).

Signed-off-by: Mark Rutland <mark.rutland@arm.com>
---
 Documentation/arm64/booting.txt | 28 +++++++++++++++++++++++-----
 arch/arm64/kernel/head.S        |  4 ++--
 arch/arm64/kernel/vmlinux.lds.S | 28 ++++++++++++++++++++++++++++
 3 files changed, 53 insertions(+), 7 deletions(-)

diff --git a/Documentation/arm64/booting.txt b/Documentation/arm64/booting.txt
index beb754e..0d8201c 100644
--- a/Documentation/arm64/booting.txt
+++ b/Documentation/arm64/booting.txt
@@ -72,8 +72,8 @@ The decompressed kernel image contains a 64-byte header as follows:
 
   u32 code0;			/* Executable code */
   u32 code1;			/* Executable code */
-  u64 text_offset;		/* Image load offset */
-  u64 res0	= 0;		/* reserved */
+  u64 text_offset;		/* Image load offset, little endian */
+  u64 image_size;		/* Effective Image size, little endian */
   u64 res1	= 0;		/* reserved */
   u64 res2	= 0;		/* reserved */
   u64 res3	= 0;		/* reserved */
@@ -86,9 +86,27 @@ Header notes:
 
 - code0/code1 are responsible for branching to stext.
 
-The image must be placed at the specified offset (currently 0x80000)
-from the start of the system RAM and called there. The start of the
-system RAM must be aligned to 2MB.
+- Older kernel versions did not define the endianness of text_offset.
+  In these cases image_size is zero and text_offset is 0x80000 in the
+  endianness of the kernel. Where image_size is non-zero image_size is
+  little-endian and must be respected.
+
+- When image_size is zero, a bootloader should attempt to keep as much
+  memory as possible free for use by the kernel immediately after the
+  end of the kernel image. Typically 1MB should be sufficient for this
+  case.
+
+The Image must be placed text_offset bytes from a 2MB aligned base
+address near the start of usable system RAM and called there. Memory
+below that base address is currently unusable by Linux, and therefore it
+is strongly recommended that this location is the start of system RAM.
+At least image_size bytes from the start of the image must be free for
+use by the kernel.
+
+Any memory described to the kernel (even that below the 2MB aligned base
+address) which is not marked as reserved from the kernel e.g. with a
+memreserve region in the device tree) will be considered as available to
+the kernel.
 
 Before jumping into the kernel, the following conditions must be met:
 
diff --git a/arch/arm64/kernel/head.S b/arch/arm64/kernel/head.S
index 5dd8127..542ca97 100644
--- a/arch/arm64/kernel/head.S
+++ b/arch/arm64/kernel/head.S
@@ -98,8 +98,8 @@
 	 */
 	b	stext				// branch to kernel start, magic
 	.long	0				// reserved
-	.quad	TEXT_OFFSET			// Image load offset from start of RAM
-	.quad	0				// reserved
+	.quad	_kernel_offset_le		// Image load offset from start of RAM, little-endian
+	.quad	_kernel_size_le			// Effective size of kernel image, little-endian
 	.quad	0				// reserved
 	.quad	0				// reserved
 	.quad	0				// reserved
diff --git a/arch/arm64/kernel/vmlinux.lds.S b/arch/arm64/kernel/vmlinux.lds.S
index 51258bc..21a8ad1 100644
--- a/arch/arm64/kernel/vmlinux.lds.S
+++ b/arch/arm64/kernel/vmlinux.lds.S
@@ -30,6 +30,25 @@ jiffies = jiffies_64;
 	*(.hyp.text)					\
 	VMLINUX_SYMBOL(__hyp_text_end) = .;
 
+/*
+ * There aren't any ELF relocations we can use to endian-swap values known only
+ * at link time (e.g. the subtraction of two symbol addresses), so we must get
+ * the linker to endian-swap certain values before emitting them.
+ */
+#ifdef CONFIG_CPU_BIG_ENDIAN
+#define DATA_LE64(data)					\
+	((((data) & 0x00000000000000ff) << 56) |	\
+	 (((data) & 0x000000000000ff00) << 40) |	\
+	 (((data) & 0x0000000000ff0000) << 24) |	\
+	 (((data) & 0x00000000ff000000) << 8)  |	\
+	 (((data) & 0x000000ff00000000) >> 8)  |	\
+	 (((data) & 0x0000ff0000000000) >> 24) |	\
+	 (((data) & 0x00ff000000000000) >> 40) |	\
+	 (((data) & 0xff00000000000000) >> 56))
+#else
+#define DATA_LE64(data) ((data) & 0xffffffffffffffff)
+#endif
+
 SECTIONS
 {
 	/*
@@ -114,6 +133,15 @@ SECTIONS
 	_end = .;
 
 	STABS_DEBUG
+
+	/*
+	 * These will output as part of the Image header, which should be
+	 * little-endian regardless of the endianness of the kernel. While
+	 * constant values could be endian swapped in head.S, all are done here
+	 * for consistency.
+	 */
+	_kernel_size_le = DATA_LE64(_end - _text);
+	_kernel_offset_le = DATA_LE64(TEXT_OFFSET);
 }
 
 /*
-- 
1.9.1

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

* [PATCH 4/4] arm64: Enable TEXT_OFFSET fuzzing
  2014-05-16  9:50 [PATCH 0/4] arm64: simplify restrictions on bootloaders Mark Rutland
                   ` (2 preceding siblings ...)
  2014-05-16  9:50 ` [PATCH 3/4] arm64: export effective Image size to bootloaders Mark Rutland
@ 2014-05-16  9:50 ` Mark Rutland
  2014-05-16 14:06   ` Catalin Marinas
  2014-05-20 11:31 ` [PATCH 0/4] arm64: simplify restrictions on bootloaders Ian Campbell
  4 siblings, 1 reply; 26+ messages in thread
From: Mark Rutland @ 2014-05-16  9:50 UTC (permalink / raw
  To: linux-arm-kernel

The arm64 Image header contains a text_offset field which bootloaders
are supposed to read to determine the offset (from a 2MB aligned "start
of memory" per booting.txt) at which to load the kernel. The offset is
not well respected by bootloaders at present, and due to the lack of
variation there is little incentive to support it. This is unfortunate
for the sake of future kernels where we may wish to vary the text offset
(even zeroing it).

This patch adds options to arm64 to enable fuzz-testing of text_offset.
CONFIG_ARM64_RANDOMIZE_TEXT_OFFSET forces the text offset to a random
value upon a build of the kernel, and CONFIG_ARM64_TEXT_OFFSET can be
used to set the text offset to a specific value (between 16B and 2MB).
It is recommended that distribution kernels enable randomization to test
bootloaders such that any compliance issues can be fixed early.

Signed-off-by: Mark Rutland <mark.rutland@arm.com>
---
 arch/arm64/Kconfig.debug        | 31 +++++++++++++++++++++++++++++++
 arch/arm64/Makefile             |  6 +++++-
 arch/arm64/kernel/head.S        |  8 ++++++--
 arch/arm64/kernel/vmlinux.lds.S |  5 +++++
 4 files changed, 47 insertions(+), 3 deletions(-)

diff --git a/arch/arm64/Kconfig.debug b/arch/arm64/Kconfig.debug
index d10ec33..471ef0d 100644
--- a/arch/arm64/Kconfig.debug
+++ b/arch/arm64/Kconfig.debug
@@ -37,4 +37,35 @@ config PID_IN_CONTEXTIDR
 	  instructions during context switch. Say Y here only if you are
 	  planning to use hardware trace tools with this kernel.
 
+config ARM64_RANDOMIZE_TEXT_OFFSET
+	bool "Randomize TEXT_OFFSET at build time (EXPERIMENTAL)"
+	default N
+	help
+	  Say Y here if you want the image load offset (AKA TEXT_OFFSET)
+	  of the kernel to be randomized at build-time. When selected,
+	  this option will cause TEXT_OFFSET to be randomized upon any
+	  build of the kernel, and the offset will be reflected in the
+	  text_offset field of the resulting Image. This can be used to
+	  fuzz-test bootloaders which respect text_offset.
+
+	  This option is intended for bootloader and/or kernel testing
+	  only. Bootloaders must make no assumptions regarding the value
+	  of TEXT_OFFSET and platforms must not require a specific
+	  value.
+
+config ARM64_TEXT_OFFSET
+	hex "Required image load offset"
+	depends on !ARM64_RANDOMIZE_TEXT_OFFSET
+	default "0x0000000000080000"
+	help
+	  The image load offset (AKA TEXT_OFFSET) of the kernel. The
+	  load offset will be reflected in the text_offset field of the
+	  Image. TEXT_OFFSET must be a 16-byte aligned value less than
+	  2MB.
+
+	  This option is intended for bootloader and/or kernel testing
+	  only. Bootloaders must make no assumptions regarding the value
+	  of TEXT_OFFSET and platforms must not require a specific
+	  value.
+
 endmenu
diff --git a/arch/arm64/Makefile b/arch/arm64/Makefile
index 2fceb71..a4962d5 100644
--- a/arch/arm64/Makefile
+++ b/arch/arm64/Makefile
@@ -38,7 +38,11 @@ CHECKFLAGS	+= -D__aarch64__
 head-y		:= arch/arm64/kernel/head.o
 
 # The byte offset of the kernel image in RAM from the start of RAM.
-TEXT_OFFSET := 0x00080000
+ifeq ($(CONFIG_ARM64_RANDOMIZE_TEXT_OFFSET), y)
+TEXT_OFFSET := $(shell awk 'BEGIN {srand(); printf "0x%05x\n", and(int(0xfffff * rand()), 0xffff0)}')
+else
+TEXT_OFFSET := $(CONFIG_ARM64_TEXT_OFFSET)
+endif
 
 export	TEXT_OFFSET GZFLAGS
 
diff --git a/arch/arm64/kernel/head.S b/arch/arm64/kernel/head.S
index 542ca97..1a731bc 100644
--- a/arch/arm64/kernel/head.S
+++ b/arch/arm64/kernel/head.S
@@ -37,8 +37,12 @@
 
 #define KERNEL_RAM_VADDR	(PAGE_OFFSET + TEXT_OFFSET)
 
-#if (KERNEL_RAM_VADDR & 0xfffff) != 0x80000
-#error KERNEL_RAM_VADDR must start at 0xXXX80000
+#if (TEXT_OFFSET & 0xf) != 0
+#error TEXT_OFFSET must be at least 16B aligned
+#elif (PAGE_OFFSET & 0xfffff) != 0
+#error PAGE_OFFSET must be at least 2MB aligned
+#elif TEXT_OFFSET > 0xfffff
+#error TEXT_OFFSET must be less than 2MB
 #endif
 
 	.macro	pgtbl, ttb0, ttb1, virt_to_phys
diff --git a/arch/arm64/kernel/vmlinux.lds.S b/arch/arm64/kernel/vmlinux.lds.S
index 21a8ad1..05fc047 100644
--- a/arch/arm64/kernel/vmlinux.lds.S
+++ b/arch/arm64/kernel/vmlinux.lds.S
@@ -149,3 +149,8 @@ SECTIONS
  */
 ASSERT(((__hyp_idmap_text_start + PAGE_SIZE) > __hyp_idmap_text_end),
        "HYP init code too big")
+
+/*
+ * If padding is applied before .head.text, virt<->phys conversions will fail.
+ */
+ASSERT(_text == (PAGE_OFFSET + TEXT_OFFSET), "HEAD is misaligned")
-- 
1.9.1

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

* [PATCH 1/4] arm64: head.S: remove unnecessary function alignment
  2014-05-16  9:50 ` [PATCH 1/4] arm64: head.S: remove unnecessary function alignment Mark Rutland
@ 2014-05-16 13:04   ` Christopher Covington
  2014-05-20 16:20   ` Laura Abbott
  1 sibling, 0 replies; 26+ messages in thread
From: Christopher Covington @ 2014-05-16 13:04 UTC (permalink / raw
  To: linux-arm-kernel

Hi Mark,

On 05/16/2014 05:50 AM, Mark Rutland wrote:
> Currently __turn_mmu_on is aligned to 64 bytes to ensure that it doesn't
> span any page boundary, which simplifies the idmap and spares us
> requiring an additional page table to map half of the function. In
> keeping with other important requirements in architecture code, this
> fact is undocumented.
> 
> Additionally, as the function consists of three instructions totalling
> 12 bytes with no literal pool data, a smaller alignment of 16 bytes
> would be sufficient.
> 
> This patch reduces the alignment to 16 bytes and documents the
> underlying reason for the alignment. This reduces the required alignment
> of the entire .head.text section from 64 bytes to 16 bytes, though it
> may still be aligned to a larger value depending on TEXT_OFFSET.
> 
> Signed-off-by: Mark Rutland <mark.rutland@arm.com>
> ---
>  arch/arm64/kernel/head.S | 7 ++++++-
>  1 file changed, 6 insertions(+), 1 deletion(-)
> 
> diff --git a/arch/arm64/kernel/head.S b/arch/arm64/kernel/head.S
> index 0fd5650..e8e9883 100644
> --- a/arch/arm64/kernel/head.S
> +++ b/arch/arm64/kernel/head.S
> @@ -346,8 +346,13 @@ ENDPROC(__enable_mmu)
>   *  x27 = *virtual* address to jump to upon completion
>   *
>   * other registers depend on the function called upon completion
> + *
> + * We align the entire function to the smallest power of two larger than it to
> + * ensure it fits within a single block map entry. Otherwise were PHYS_OFFSET
> + * close to the end of a 512MB or 1GB block we might require an additional
> + * table to map the entire function.
>   */
> -	.align	6
> +	.align	4
>  __turn_mmu_on:
>  	msr	sctlr_el1, x0
>  	isb

If you're feeling ambitious, this requirement could probably be enforced by
some kind of BUILD_BUG_ON((__turn_mmu_on_end - __turn_mmu_on) / 4 >
TURN_MMU_ON_ALIGN). I don't know if this code will really need to grow in
practice, but if it does, forgetting to update the alignment (in spite of your
helpful comment) seems like an easy mistake to make.

Christopher

-- 
Employee of Qualcomm Innovation Center, Inc.
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
hosted by the Linux Foundation.

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

* [PATCH 4/4] arm64: Enable TEXT_OFFSET fuzzing
  2014-05-16  9:50 ` [PATCH 4/4] arm64: Enable TEXT_OFFSET fuzzing Mark Rutland
@ 2014-05-16 14:06   ` Catalin Marinas
  2014-05-16 16:55     ` Mark Rutland
  0 siblings, 1 reply; 26+ messages in thread
From: Catalin Marinas @ 2014-05-16 14:06 UTC (permalink / raw
  To: linux-arm-kernel

On Fri, May 16, 2014 at 10:50:39AM +0100, Mark Rutland wrote:
> --- a/arch/arm64/Kconfig.debug
> +++ b/arch/arm64/Kconfig.debug
> @@ -37,4 +37,35 @@ config PID_IN_CONTEXTIDR
>  	  instructions during context switch. Say Y here only if you are
>  	  planning to use hardware trace tools with this kernel.
>  
> +config ARM64_RANDOMIZE_TEXT_OFFSET
> +	bool "Randomize TEXT_OFFSET at build time (EXPERIMENTAL)"
> +	default N

(nitpick: no need for default n)

I think that's good for testing. It would have been nice to be able to
set some limits for the random offset but I can't figure out an easy way
to do this via Kconfig (maybe with additional options).

> +config ARM64_TEXT_OFFSET
> +	hex "Required image load offset"
> +	depends on !ARM64_RANDOMIZE_TEXT_OFFSET
> +	default "0x0000000000080000"

I don't think we should include this. It encourages people to set
specific offsets for their SoCs.

-- 
Catalin

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

* [PATCH 4/4] arm64: Enable TEXT_OFFSET fuzzing
  2014-05-16 14:06   ` Catalin Marinas
@ 2014-05-16 16:55     ` Mark Rutland
  2014-05-20 14:11       ` Tom Rini
  0 siblings, 1 reply; 26+ messages in thread
From: Mark Rutland @ 2014-05-16 16:55 UTC (permalink / raw
  To: linux-arm-kernel

On Fri, May 16, 2014 at 03:06:07PM +0100, Catalin Marinas wrote:
> On Fri, May 16, 2014 at 10:50:39AM +0100, Mark Rutland wrote:
> > --- a/arch/arm64/Kconfig.debug
> > +++ b/arch/arm64/Kconfig.debug
> > @@ -37,4 +37,35 @@ config PID_IN_CONTEXTIDR
> >  	  instructions during context switch. Say Y here only if you are
> >  	  planning to use hardware trace tools with this kernel.
> >  
> > +config ARM64_RANDOMIZE_TEXT_OFFSET
> > +	bool "Randomize TEXT_OFFSET at build time (EXPERIMENTAL)"
> > +	default N
> 
> (nitpick: no need for default n)

Thanks for pointing that out, I'll remove it :)

> I think that's good for testing. It would have been nice to be able to
> set some limits for the random offset but I can't figure out an easy way
> to do this via Kconfig (maybe with additional options).

There are hard-coded limits implicit in the randomization -- between 0B
and 2MB in 16B increments:

TEXT_OFFSET := $(shell awk 'BEGIN {srand(); printf "0x%05x\n", and(int(0xfffff * rand()), 0xffff0)}')

The 16B increment is required due to some code in head.S (__turn_mmu_on)
requiring a minimum 16B alignment for the object.

The 2MB maximum comes from the fact we rely on the start of memory being
2MB aligned. I'm not sure there's a compelling reason to limit the
randomization if enabled at all -- either you can handle it or you
can't. Are we ever likely to want an offset larger than the memory
alignment?

> > +config ARM64_TEXT_OFFSET
> > +	hex "Required image load offset"
> > +	depends on !ARM64_RANDOMIZE_TEXT_OFFSET
> > +	default "0x0000000000080000"
> 
> I don't think we should include this. It encourages people to set
> specific offsets for their SoCs.

Sure, I was worried about potential abuse also (hence the warning in the
help text). I'll drop this portion.

Cheers,
Mark.

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

* [PATCH 0/4] arm64: simplify restrictions on bootloaders
  2014-05-16  9:50 [PATCH 0/4] arm64: simplify restrictions on bootloaders Mark Rutland
                   ` (3 preceding siblings ...)
  2014-05-16  9:50 ` [PATCH 4/4] arm64: Enable TEXT_OFFSET fuzzing Mark Rutland
@ 2014-05-20 11:31 ` Ian Campbell
  4 siblings, 0 replies; 26+ messages in thread
From: Ian Campbell @ 2014-05-20 11:31 UTC (permalink / raw
  To: linux-arm-kernel

On Fri, 2014-05-16 at 10:50 +0100, Mark Rutland wrote:
> Currently bootloaders have an extremely difficult time protecting memory from
> the kernel, as the kernel may clobber memory below TEXT_OFFSET with pagetables,
> and above the end of the kernel binary with the BSS.

I took a look through this partly with my Xen hat on (Xen effectively
contains a bootloader) and partly with my general noseybeak hat on and
it all looked pretty sensible to me. So I don't think this change will
cause any problems for Xen.

Cheers,
Ian.

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

* [PATCH 4/4] arm64: Enable TEXT_OFFSET fuzzing
  2014-05-16 16:55     ` Mark Rutland
@ 2014-05-20 14:11       ` Tom Rini
  2014-05-20 16:08         ` Mark Rutland
  0 siblings, 1 reply; 26+ messages in thread
From: Tom Rini @ 2014-05-20 14:11 UTC (permalink / raw
  To: linux-arm-kernel

On Fri, May 16, 2014 at 05:55:48PM +0100, Mark Rutland wrote:
> On Fri, May 16, 2014 at 03:06:07PM +0100, Catalin Marinas wrote:
> > On Fri, May 16, 2014 at 10:50:39AM +0100, Mark Rutland wrote:
> > > --- a/arch/arm64/Kconfig.debug
> > > +++ b/arch/arm64/Kconfig.debug
> > > @@ -37,4 +37,35 @@ config PID_IN_CONTEXTIDR
> > >  	  instructions during context switch. Say Y here only if you are
> > >  	  planning to use hardware trace tools with this kernel.
> > >  
> > > +config ARM64_RANDOMIZE_TEXT_OFFSET
> > > +	bool "Randomize TEXT_OFFSET at build time (EXPERIMENTAL)"
> > > +	default N
> > 
> > (nitpick: no need for default n)
> 
> Thanks for pointing that out, I'll remove it :)
> 
> > I think that's good for testing. It would have been nice to be able to
> > set some limits for the random offset but I can't figure out an easy way
> > to do this via Kconfig (maybe with additional options).
> 
> There are hard-coded limits implicit in the randomization -- between 0B
> and 2MB in 16B increments:
> 
> TEXT_OFFSET := $(shell awk 'BEGIN {srand(); printf "0x%05x\n", and(int(0xfffff * rand()), 0xffff0)}')

Note, is mawk expected to be able to be used for kernel building?  It
doesn't have 'and' as a function.

> The 16B increment is required due to some code in head.S (__turn_mmu_on)
> requiring a minimum 16B alignment for the object.
> 
> The 2MB maximum comes from the fact we rely on the start of memory being
> 2MB aligned. I'm not sure there's a compelling reason to limit the
> randomization if enabled at all -- either you can handle it or you
> can't. Are we ever likely to want an offset larger than the memory
> alignment?

A reason to limit the randomization is to make it easier on the
bootloaders to be able to rule of thumb initial loads.  It's not a big
deal with Image if it gets loaded lower than the offset, we can start
shifting data at the end.  But when we start looking at Image.gz (or xz
or ...), in some cases we'll get the whole image read into memory (network
booting for example), uncompress the first block so we can confirm a
good Image header and see about text_offset/image_size.  If we know that
text_offset is somewhere random inside of 2MB (or some other documented
max), we can then go with saying an initial load should be at say +32MB
(to mirror Documentation/arm/Booting).  If it can be anywhere, then
things get hard, or at least annoying (error out and tell the user to
re-load things because of a random value?  I can see testing frameworks
being annoyed about that).

And we should document the range of the offset in
Documentation/arm64/booting.txt as well.

-- 
Tom

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

* [PATCH 3/4] arm64: export effective Image size to bootloaders
  2014-05-16  9:50 ` [PATCH 3/4] arm64: export effective Image size to bootloaders Mark Rutland
@ 2014-05-20 14:12   ` Tom Rini
  2014-05-20 16:22   ` Laura Abbott
  2014-06-16 20:27   ` Geoff Levand
  2 siblings, 0 replies; 26+ messages in thread
From: Tom Rini @ 2014-05-20 14:12 UTC (permalink / raw
  To: linux-arm-kernel

On Fri, May 16, 2014 at 10:50:38AM +0100, Mark Rutland wrote:

> Currently the kernel Image is stripped of everything past the initial
> stack, and at runtime the memory is initialised and used by the kernel.
> This makes the effective minimum memory footprint of the kernel larger
> than the size of the loaded binary, though bootloaders have no mechanism
> to identify how large this minimum memory footprint is. This makes it
> difficult to choose safe locations to place both the kernel and other
> binaries required at boot (DTB, initrd, etc), such that the kernel won't
> clobber said binaries or other reserved memory during initialisation.
> 
> Additionally when big endian support was added the image load offset was
> overlooked, and is currently of an arbitrary endianness, which makes it
> difficult for bootloaders to make use of it. It seems that bootloaders
> aren't respecting the image load offset at present anyway, and are
> assuming that offset 0x80000 will always be correct.
> 
> This patch adds an effective image size to the kernel header which
> describes the amount of memory from the start of the kernel Image binary
> which the kernel expects to use before detecting memory and handling any
> memory reservations. This can be used by bootloaders to choose suitable
> locations to load the kernel and/or other binaries such that the kernel
> will not clobber any memory unexpectedly. As before, memory reservations
> are required to prevent the kernel from clobbering these locations
> later.
> 
> Both the image load offset and the effective image size are forced to be
> little-endian regardless of the native endianness of the kernel to
> enable bootloaders to load a kernel of arbitrary endianness. Bootloaders
> which wish to make use of the load offset can inspect the effective
> image size field for a non-zero value to determine if the offset is of a
> known endianness.
> 
> The documentation is updated to clarify these details. To discourage
> future assumptions regarding the value of text_offset, the value at this
> point in time is removed from the main flow of the documentation (though
> kept as a compatibility note).
> 
> Signed-off-by: Mark Rutland <mark.rutland@arm.com>

Putting on my U-Boot hat, this looks sensible and implementable so:
Acked-by: Tom Rini <trini@ti.com>

-- 
Tom

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

* [PATCH 4/4] arm64: Enable TEXT_OFFSET fuzzing
  2014-05-20 14:11       ` Tom Rini
@ 2014-05-20 16:08         ` Mark Rutland
  2014-05-21 10:18           ` Mark Rutland
  0 siblings, 1 reply; 26+ messages in thread
From: Mark Rutland @ 2014-05-20 16:08 UTC (permalink / raw
  To: linux-arm-kernel

On Tue, May 20, 2014 at 03:11:26PM +0100, Tom Rini wrote:
> On Fri, May 16, 2014 at 05:55:48PM +0100, Mark Rutland wrote:
> > On Fri, May 16, 2014 at 03:06:07PM +0100, Catalin Marinas wrote:
> > > On Fri, May 16, 2014 at 10:50:39AM +0100, Mark Rutland wrote:
> > > > --- a/arch/arm64/Kconfig.debug
> > > > +++ b/arch/arm64/Kconfig.debug
> > > > @@ -37,4 +37,35 @@ config PID_IN_CONTEXTIDR
> > > >  	  instructions during context switch. Say Y here only if you are
> > > >  	  planning to use hardware trace tools with this kernel.
> > > >  
> > > > +config ARM64_RANDOMIZE_TEXT_OFFSET
> > > > +	bool "Randomize TEXT_OFFSET at build time (EXPERIMENTAL)"
> > > > +	default N
> > > 
> > > (nitpick: no need for default n)
> > 
> > Thanks for pointing that out, I'll remove it :)
> > 
> > > I think that's good for testing. It would have been nice to be able to
> > > set some limits for the random offset but I can't figure out an easy way
> > > to do this via Kconfig (maybe with additional options).
> > 
> > There are hard-coded limits implicit in the randomization -- between 0B
> > and 2MB in 16B increments:
> > 
> > TEXT_OFFSET := $(shell awk 'BEGIN {srand(); printf "0x%05x\n", and(int(0xfffff * rand()), 0xffff0)}')
> 
> Note, is mawk expected to be able to be used for kernel building?  It
> doesn't have 'and' as a function.

Ouch. I hadn't realised this was gawk-only. My new local machine only
has mawk and builds the kernel fine otherwise, so it seems like we can't
just expect gawk. It also seems that mawk doesn't like inline hex
values...

The masking is only there to ensure the value is a multiple of 16 (i.e.
the last digit is 0), so we can just handle that in the print instead.
Then 0xffff is 65535, so:

TEXT_OFFSET := $(shell awk 'BEGIN {srand(); printf "0x%04x0\n", int(65535 * rand())}')

That seems to work in gawk and mawk.

> 
> > The 16B increment is required due to some code in head.S (__turn_mmu_on)
> > requiring a minimum 16B alignment for the object.
> > 
> > The 2MB maximum comes from the fact we rely on the start of memory being
> > 2MB aligned. I'm not sure there's a compelling reason to limit the
> > randomization if enabled at all -- either you can handle it or you
> > can't. Are we ever likely to want an offset larger than the memory
> > alignment?
> 
> A reason to limit the randomization is to make it easier on the
> bootloaders to be able to rule of thumb initial loads.  It's not a big
> deal with Image if it gets loaded lower than the offset, we can start
> shifting data at the end.  But when we start looking at Image.gz (or xz
> or ...), in some cases we'll get the whole image read into memory (network
> booting for example), uncompress the first block so we can confirm a
> good Image header and see about text_offset/image_size.  If we know that
> text_offset is somewhere random inside of 2MB (or some other documented
> max), we can then go with saying an initial load should be at say +32MB
> (to mirror Documentation/arm/Booting).  If it can be anywhere, then
> things get hard, or at least annoying (error out and tell the user to
> re-load things because of a random value?  I can see testing frameworks
> being annoyed about that).

Ouch, that is somewhat painful.

I don't think we expect to see a text_offset larger than 2MB, and I
can't immediately see why we'd care about any particular text offset
assuming the page tables are at the end of the runtime image. That said,
I'm not completely clear on the history of the text_offset.

> And we should document the range of the offset in
> Documentation/arm64/booting.txt as well.

As far as I am aware, we have a 64-bit field specifically to allow for
an arbitrarily large value, so placing limitations on that may be a
little difficult.

As stated above, I don't think there'd be a reason for having a
text_offset larger than our memory alignment restriction (2MB), but
there may be something I've missed. If others are reasonably confident
with an upper limit, I'd be happy to go with it.

Cheers,
Mark.

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

* [PATCH 1/4] arm64: head.S: remove unnecessary function alignment
  2014-05-16  9:50 ` [PATCH 1/4] arm64: head.S: remove unnecessary function alignment Mark Rutland
  2014-05-16 13:04   ` Christopher Covington
@ 2014-05-20 16:20   ` Laura Abbott
  1 sibling, 0 replies; 26+ messages in thread
From: Laura Abbott @ 2014-05-20 16:20 UTC (permalink / raw
  To: linux-arm-kernel

On 5/16/2014 2:50 AM, Mark Rutland wrote:
> Currently __turn_mmu_on is aligned to 64 bytes to ensure that it doesn't
> span any page boundary, which simplifies the idmap and spares us
> requiring an additional page table to map half of the function. In
> keeping with other important requirements in architecture code, this
> fact is undocumented.
> 
> Additionally, as the function consists of three instructions totalling
> 12 bytes with no literal pool data, a smaller alignment of 16 bytes
> would be sufficient.
> 
> This patch reduces the alignment to 16 bytes and documents the
> underlying reason for the alignment. This reduces the required alignment
> of the entire .head.text section from 64 bytes to 16 bytes, though it
> may still be aligned to a larger value depending on TEXT_OFFSET.
> 
> Signed-off-by: Mark Rutland <mark.rutland@arm.com>
> ---
>  arch/arm64/kernel/head.S | 7 ++++++-
>  1 file changed, 6 insertions(+), 1 deletion(-)
> 
> diff --git a/arch/arm64/kernel/head.S b/arch/arm64/kernel/head.S
> index 0fd5650..e8e9883 100644
> --- a/arch/arm64/kernel/head.S
> +++ b/arch/arm64/kernel/head.S
> @@ -346,8 +346,13 @@ ENDPROC(__enable_mmu)
>   *  x27 = *virtual* address to jump to upon completion
>   *
>   * other registers depend on the function called upon completion
> + *
> + * We align the entire function to the smallest power of two larger than it to
> + * ensure it fits within a single block map entry. Otherwise were PHYS_OFFSET
> + * close to the end of a 512MB or 1GB block we might require an additional
> + * table to map the entire function.
>   */
> -	.align	6
> +	.align	4
>  __turn_mmu_on:
>  	msr	sctlr_el1, x0
>  	isb
> 

Tested-by: Laura Abbott <lauraa@codeaurora.org>

Both 4K and 64K pages

-- 
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
hosted by The Linux Foundation

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

* [PATCH 2/4] arm64: place initial page tables above the kernel
  2014-05-16  9:50 ` [PATCH 2/4] arm64: place initial page tables above the kernel Mark Rutland
@ 2014-05-20 16:21   ` Laura Abbott
  0 siblings, 0 replies; 26+ messages in thread
From: Laura Abbott @ 2014-05-20 16:21 UTC (permalink / raw
  To: linux-arm-kernel

On 5/16/2014 2:50 AM, Mark Rutland wrote:
> Currently we place swapper_pg_dir and idmap_pg_dir below the kernel
> image, between PHYS_OFFSET and (PHYS_OFFSET + TEXT_OFFSET). However,
> bootloaders may use portions of this memory below the kernel and we do
> not parse the memory reservation list until after the MMU has been
> enabled. As such we may clobber some memory a bootloader wishes to have
> preserved.
> 
> To enable the use of all of this memory by bootloaders (when the
> required memory reservations are communicated to the kernel) it is
> necessary to move our initial page tables elsewhere. As we currently
> have an effectively unbound requirement for memory at the end of the
> kernel image for .bss, we can place the page tables here.
> 
> This patch moves the initial page table to the end of the kernel image,
> after the BSS. As they do not consist of any initialised data they will
> be stripped from the kernel Image as with the BSS. The BSS clearing
> routine is updated to stop at __bss_stop rather than _end so as to not
> clobber the page tables, and memory reservations made redundant by the
> new organisation are removed.
> 
> Signed-off-by: Mark Rutland <mark.rutland@arm.com>
> ---
>  arch/arm64/include/asm/page.h   |  9 +++++++++
>  arch/arm64/kernel/head.S        | 28 ++++++++--------------------
>  arch/arm64/kernel/vmlinux.lds.S |  7 +++++++
>  arch/arm64/mm/init.c            | 12 ++++--------
>  4 files changed, 28 insertions(+), 28 deletions(-)
> 
> diff --git a/arch/arm64/include/asm/page.h b/arch/arm64/include/asm/page.h
> index 46bf666..a6331e6 100644
> --- a/arch/arm64/include/asm/page.h
> +++ b/arch/arm64/include/asm/page.h
> @@ -31,6 +31,15 @@
>  /* We do define AT_SYSINFO_EHDR but don't use the gate mechanism */
>  #define __HAVE_ARCH_GATE_AREA		1
>  
> +/*
> + * The idmap and swapper page tables need some space reserved in the kernel
> + * image. The idmap only requires a pgd and a next level table to (section) map
> + * the kernel, while the swapper also maps the FDT and requires an additional
> + * table to map an early UART. See __create_page_tables for more information.
> + */
> +#define SWAPPER_DIR_SIZE	(3 * PAGE_SIZE)
> +#define IDMAP_DIR_SIZE		(2 * PAGE_SIZE)
> +
>  #ifndef __ASSEMBLY__
>  
>  #ifdef CONFIG_ARM64_64K_PAGES
> diff --git a/arch/arm64/kernel/head.S b/arch/arm64/kernel/head.S
> index e8e9883..5dd8127 100644
> --- a/arch/arm64/kernel/head.S
> +++ b/arch/arm64/kernel/head.S
> @@ -35,29 +35,17 @@
>  #include <asm/page.h>
>  #include <asm/virt.h>
>  
> -/*
> - * swapper_pg_dir is the virtual address of the initial page table. We place
> - * the page tables 3 * PAGE_SIZE below KERNEL_RAM_VADDR. The idmap_pg_dir has
> - * 2 pages and is placed below swapper_pg_dir.
> - */
>  #define KERNEL_RAM_VADDR	(PAGE_OFFSET + TEXT_OFFSET)
>  
>  #if (KERNEL_RAM_VADDR & 0xfffff) != 0x80000
>  #error KERNEL_RAM_VADDR must start at 0xXXX80000
>  #endif
>  
> -#define SWAPPER_DIR_SIZE	(3 * PAGE_SIZE)
> -#define IDMAP_DIR_SIZE		(2 * PAGE_SIZE)
> -
> -	.globl	swapper_pg_dir
> -	.equ	swapper_pg_dir, KERNEL_RAM_VADDR - SWAPPER_DIR_SIZE
> -
> -	.globl	idmap_pg_dir
> -	.equ	idmap_pg_dir, swapper_pg_dir - IDMAP_DIR_SIZE
> -
> -	.macro	pgtbl, ttb0, ttb1, phys
> -	add	\ttb1, \phys, #TEXT_OFFSET - SWAPPER_DIR_SIZE
> -	sub	\ttb0, \ttb1, #IDMAP_DIR_SIZE
> +	.macro	pgtbl, ttb0, ttb1, virt_to_phys
> +	ldr	\ttb1, =swapper_pg_dir
> +	ldr	\ttb0, =idmap_pg_dir
> +	add	\ttb1, \ttb1, \virt_to_phys
> +	add	\ttb0, \ttb0, \virt_to_phys
>  	.endm
>  
>  #ifdef CONFIG_ARM64_64K_PAGES
> @@ -304,7 +292,7 @@ ENTRY(secondary_startup)
>  	mov	x23, x0				// x23=current cpu_table
>  	cbz	x23, __error_p			// invalid processor (x23=0)?
>  
> -	pgtbl	x25, x26, x24			// x25=TTBR0, x26=TTBR1
> +	pgtbl	x25, x26, x28			// x25=TTBR0, x26=TTBR1
>  	ldr	x12, [x23, #CPU_INFO_SETUP]
>  	add	x12, x12, x28			// __virt_to_phys
>  	blr	x12				// initialise processor
> @@ -418,7 +406,7 @@ ENDPROC(__calc_phys_offset)
>   *   - pgd entry for fixed mappings (TTBR1)
>   */
>  __create_page_tables:
> -	pgtbl	x25, x26, x24			// idmap_pg_dir and swapper_pg_dir addresses
> +	pgtbl	x25, x26, x28			// idmap_pg_dir and swapper_pg_dir addresses
>  	mov	x27, lr
>  
>  	/*
> @@ -507,7 +495,7 @@ ENDPROC(__create_page_tables)
>  __switch_data:
>  	.quad	__mmap_switched
>  	.quad	__bss_start			// x6
> -	.quad	_end				// x7
> +	.quad	__bss_stop			// x7
>  	.quad	processor_id			// x4
>  	.quad	__fdt_pointer			// x5
>  	.quad	memstart_addr			// x6
> diff --git a/arch/arm64/kernel/vmlinux.lds.S b/arch/arm64/kernel/vmlinux.lds.S
> index 4ba7a55..51258bc 100644
> --- a/arch/arm64/kernel/vmlinux.lds.S
> +++ b/arch/arm64/kernel/vmlinux.lds.S
> @@ -104,6 +104,13 @@ SECTIONS
>  	_edata = .;
>  
>  	BSS_SECTION(0, 0, 0)
> +
> +	. = ALIGN(PAGE_SIZE);
> +	idmap_pg_dir = .;
> +	. += IDMAP_DIR_SIZE;
> +	swapper_pg_dir = .;
> +	. += SWAPPER_DIR_SIZE;
> +
>  	_end = .;
>  
>  	STABS_DEBUG
> diff --git a/arch/arm64/mm/init.c b/arch/arm64/mm/init.c
> index 51d5352..cc3339d 100644
> --- a/arch/arm64/mm/init.c
> +++ b/arch/arm64/mm/init.c
> @@ -128,20 +128,16 @@ void __init arm64_memblock_init(void)
>  {
>  	u64 *reserve_map, base, size;
>  
> -	/* Register the kernel text, kernel data and initrd with memblock */
> +	/*
> +	 * Register the kernel text, kernel data, initrd, and initial
> +	 * pagetables with memblock.
> +	 */
>  	memblock_reserve(__pa(_text), _end - _text);
>  #ifdef CONFIG_BLK_DEV_INITRD
>  	if (initrd_start)
>  		memblock_reserve(__virt_to_phys(initrd_start), initrd_end - initrd_start);
>  #endif
>  
> -	/*
> -	 * Reserve the page tables.  These are already in use,
> -	 * and can only be in node 0.
> -	 */
> -	memblock_reserve(__pa(swapper_pg_dir), SWAPPER_DIR_SIZE);
> -	memblock_reserve(__pa(idmap_pg_dir), IDMAP_DIR_SIZE);
> -
>  	/* Reserve the dtb region */
>  	memblock_reserve(virt_to_phys(initial_boot_params),
>  			 be32_to_cpu(initial_boot_params->totalsize));
> 

Tested-by: Laura Abbott <lauraa@codeaurora.org>

Both 4K and 64K pages

-- 
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
hosted by The Linux Foundation

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

* [PATCH 3/4] arm64: export effective Image size to bootloaders
  2014-05-16  9:50 ` [PATCH 3/4] arm64: export effective Image size to bootloaders Mark Rutland
  2014-05-20 14:12   ` Tom Rini
@ 2014-05-20 16:22   ` Laura Abbott
  2014-06-16 20:27   ` Geoff Levand
  2 siblings, 0 replies; 26+ messages in thread
From: Laura Abbott @ 2014-05-20 16:22 UTC (permalink / raw
  To: linux-arm-kernel

On 5/16/2014 2:50 AM, Mark Rutland wrote:
> Currently the kernel Image is stripped of everything past the initial
> stack, and at runtime the memory is initialised and used by the kernel.
> This makes the effective minimum memory footprint of the kernel larger
> than the size of the loaded binary, though bootloaders have no mechanism
> to identify how large this minimum memory footprint is. This makes it
> difficult to choose safe locations to place both the kernel and other
> binaries required at boot (DTB, initrd, etc), such that the kernel won't
> clobber said binaries or other reserved memory during initialisation.
> 
> Additionally when big endian support was added the image load offset was
> overlooked, and is currently of an arbitrary endianness, which makes it
> difficult for bootloaders to make use of it. It seems that bootloaders
> aren't respecting the image load offset at present anyway, and are
> assuming that offset 0x80000 will always be correct.
> 
> This patch adds an effective image size to the kernel header which
> describes the amount of memory from the start of the kernel Image binary
> which the kernel expects to use before detecting memory and handling any
> memory reservations. This can be used by bootloaders to choose suitable
> locations to load the kernel and/or other binaries such that the kernel
> will not clobber any memory unexpectedly. As before, memory reservations
> are required to prevent the kernel from clobbering these locations
> later.
> 
> Both the image load offset and the effective image size are forced to be
> little-endian regardless of the native endianness of the kernel to
> enable bootloaders to load a kernel of arbitrary endianness. Bootloaders
> which wish to make use of the load offset can inspect the effective
> image size field for a non-zero value to determine if the offset is of a
> known endianness.
> 
> The documentation is updated to clarify these details. To discourage
> future assumptions regarding the value of text_offset, the value at this
> point in time is removed from the main flow of the documentation (though
> kept as a compatibility note).
> 
> Signed-off-by: Mark Rutland <mark.rutland@arm.com>
> ---
>  Documentation/arm64/booting.txt | 28 +++++++++++++++++++++++-----
>  arch/arm64/kernel/head.S        |  4 ++--
>  arch/arm64/kernel/vmlinux.lds.S | 28 ++++++++++++++++++++++++++++
>  3 files changed, 53 insertions(+), 7 deletions(-)
> 
> diff --git a/Documentation/arm64/booting.txt b/Documentation/arm64/booting.txt
> index beb754e..0d8201c 100644
> --- a/Documentation/arm64/booting.txt
> +++ b/Documentation/arm64/booting.txt
> @@ -72,8 +72,8 @@ The decompressed kernel image contains a 64-byte header as follows:
>  
>    u32 code0;			/* Executable code */
>    u32 code1;			/* Executable code */
> -  u64 text_offset;		/* Image load offset */
> -  u64 res0	= 0;		/* reserved */
> +  u64 text_offset;		/* Image load offset, little endian */
> +  u64 image_size;		/* Effective Image size, little endian */
>    u64 res1	= 0;		/* reserved */
>    u64 res2	= 0;		/* reserved */
>    u64 res3	= 0;		/* reserved */
> @@ -86,9 +86,27 @@ Header notes:
>  
>  - code0/code1 are responsible for branching to stext.
>  
> -The image must be placed at the specified offset (currently 0x80000)
> -from the start of the system RAM and called there. The start of the
> -system RAM must be aligned to 2MB.
> +- Older kernel versions did not define the endianness of text_offset.
> +  In these cases image_size is zero and text_offset is 0x80000 in the
> +  endianness of the kernel. Where image_size is non-zero image_size is
> +  little-endian and must be respected.
> +
> +- When image_size is zero, a bootloader should attempt to keep as much
> +  memory as possible free for use by the kernel immediately after the
> +  end of the kernel image. Typically 1MB should be sufficient for this
> +  case.
> +
> +The Image must be placed text_offset bytes from a 2MB aligned base
> +address near the start of usable system RAM and called there. Memory
> +below that base address is currently unusable by Linux, and therefore it
> +is strongly recommended that this location is the start of system RAM.
> +At least image_size bytes from the start of the image must be free for
> +use by the kernel.
> +
> +Any memory described to the kernel (even that below the 2MB aligned base
> +address) which is not marked as reserved from the kernel e.g. with a
> +memreserve region in the device tree) will be considered as available to
> +the kernel.
>  
>  Before jumping into the kernel, the following conditions must be met:
>  
> diff --git a/arch/arm64/kernel/head.S b/arch/arm64/kernel/head.S
> index 5dd8127..542ca97 100644
> --- a/arch/arm64/kernel/head.S
> +++ b/arch/arm64/kernel/head.S
> @@ -98,8 +98,8 @@
>  	 */
>  	b	stext				// branch to kernel start, magic
>  	.long	0				// reserved
> -	.quad	TEXT_OFFSET			// Image load offset from start of RAM
> -	.quad	0				// reserved
> +	.quad	_kernel_offset_le		// Image load offset from start of RAM, little-endian
> +	.quad	_kernel_size_le			// Effective size of kernel image, little-endian
>  	.quad	0				// reserved
>  	.quad	0				// reserved
>  	.quad	0				// reserved
> diff --git a/arch/arm64/kernel/vmlinux.lds.S b/arch/arm64/kernel/vmlinux.lds.S
> index 51258bc..21a8ad1 100644
> --- a/arch/arm64/kernel/vmlinux.lds.S
> +++ b/arch/arm64/kernel/vmlinux.lds.S
> @@ -30,6 +30,25 @@ jiffies = jiffies_64;
>  	*(.hyp.text)					\
>  	VMLINUX_SYMBOL(__hyp_text_end) = .;
>  
> +/*
> + * There aren't any ELF relocations we can use to endian-swap values known only
> + * at link time (e.g. the subtraction of two symbol addresses), so we must get
> + * the linker to endian-swap certain values before emitting them.
> + */
> +#ifdef CONFIG_CPU_BIG_ENDIAN
> +#define DATA_LE64(data)					\
> +	((((data) & 0x00000000000000ff) << 56) |	\
> +	 (((data) & 0x000000000000ff00) << 40) |	\
> +	 (((data) & 0x0000000000ff0000) << 24) |	\
> +	 (((data) & 0x00000000ff000000) << 8)  |	\
> +	 (((data) & 0x000000ff00000000) >> 8)  |	\
> +	 (((data) & 0x0000ff0000000000) >> 24) |	\
> +	 (((data) & 0x00ff000000000000) >> 40) |	\
> +	 (((data) & 0xff00000000000000) >> 56))
> +#else
> +#define DATA_LE64(data) ((data) & 0xffffffffffffffff)
> +#endif
> +
>  SECTIONS
>  {
>  	/*
> @@ -114,6 +133,15 @@ SECTIONS
>  	_end = .;
>  
>  	STABS_DEBUG
> +
> +	/*
> +	 * These will output as part of the Image header, which should be
> +	 * little-endian regardless of the endianness of the kernel. While
> +	 * constant values could be endian swapped in head.S, all are done here
> +	 * for consistency.
> +	 */
> +	_kernel_size_le = DATA_LE64(_end - _text);
> +	_kernel_offset_le = DATA_LE64(TEXT_OFFSET);
>  }
>  
>  /*
> 

Tested-by: Laura Abbott <lauraa@codeaurora.org>

Both 4K and 64K pages

-- 
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
hosted by The Linux Foundation

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

* [PATCH 4/4] arm64: Enable TEXT_OFFSET fuzzing
  2014-05-20 16:08         ` Mark Rutland
@ 2014-05-21 10:18           ` Mark Rutland
  0 siblings, 0 replies; 26+ messages in thread
From: Mark Rutland @ 2014-05-21 10:18 UTC (permalink / raw
  To: linux-arm-kernel

On Tue, May 20, 2014 at 05:08:27PM +0100, Mark Rutland wrote:

[...]

> > > The 16B increment is required due to some code in head.S (__turn_mmu_on)
> > > requiring a minimum 16B alignment for the object.
> > > 
> > > The 2MB maximum comes from the fact we rely on the start of memory being
> > > 2MB aligned. I'm not sure there's a compelling reason to limit the
> > > randomization if enabled at all -- either you can handle it or you
> > > can't. Are we ever likely to want an offset larger than the memory
> > > alignment?
> > 
> > A reason to limit the randomization is to make it easier on the
> > bootloaders to be able to rule of thumb initial loads.  It's not a big
> > deal with Image if it gets loaded lower than the offset, we can start
> > shifting data at the end.  But when we start looking at Image.gz (or xz
> > or ...), in some cases we'll get the whole image read into memory (network
> > booting for example), uncompress the first block so we can confirm a
> > good Image header and see about text_offset/image_size.  If we know that
> > text_offset is somewhere random inside of 2MB (or some other documented
> > max), we can then go with saying an initial load should be at say +32MB
> > (to mirror Documentation/arm/Booting).  If it can be anywhere, then
> > things get hard, or at least annoying (error out and tell the user to
> > re-load things because of a random value?  I can see testing frameworks
> > being annoyed about that).
> 
> Ouch, that is somewhat painful.
> 
> I don't think we expect to see a text_offset larger than 2MB, and I
> can't immediately see why we'd care about any particular text offset
> assuming the page tables are at the end of the runtime image. That said,
> I'm not completely clear on the history of the text_offset.
> 
> > And we should document the range of the offset in
> > Documentation/arm64/booting.txt as well.
> 
> As far as I am aware, we have a 64-bit field specifically to allow for
> an arbitrarily large value, so placing limitations on that may be a
> little difficult.
> 
> As stated above, I don't think there'd be a reason for having a
> text_offset larger than our memory alignment restriction (2MB), but
> there may be something I've missed. If others are reasonably confident
> with an upper limit, I'd be happy to go with it.

Having thought about it a little more, the primary reason for having
text_offset is to allow for memory below the kernel to be addressable.
If we decouple the linear mapping from the kernel text mapping this
would not be a problem -- we'd be able to load the kernel at any
2MB-aligned address + text_offset and use memory below it.

So I think we could get away with limiting text_offset to 2MB.

Cheers,
Mark.

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

* [PATCH 3/4] arm64: export effective Image size to bootloaders
  2014-05-16  9:50 ` [PATCH 3/4] arm64: export effective Image size to bootloaders Mark Rutland
  2014-05-20 14:12   ` Tom Rini
  2014-05-20 16:22   ` Laura Abbott
@ 2014-06-16 20:27   ` Geoff Levand
  2014-06-18 16:49     ` Mark Rutland
  2 siblings, 1 reply; 26+ messages in thread
From: Geoff Levand @ 2014-06-16 20:27 UTC (permalink / raw
  To: linux-arm-kernel

Hi Mark,

Sorry for such a delay in my reply.

On Fri, 2014-05-16 at 10:50 +0100, Mark Rutland wrote:
> Both the image load offset and the effective image size are forced to be
> little-endian regardless of the native endianness of the kernel to
> enable bootloaders to load a kernel of arbitrary endianness. Bootloaders
> which wish to make use of the load offset can inspect the effective
> image size field for a non-zero value to determine if the offset is of a
> known endianness.

Doing this conversion in the linker script seems complicated.  My
thought was to just have an image header field that specifies the
byte order, in the same way that the EI_DATA part of the ELF
e_ident field does.

Another advantage of having the byte order in the header is that
tools other than a boot loader that need to know the byte order
can get that info from the header, otherwise they would need to
guess the order with some kind of inspection.

A patch I had planned to post for this is below.

> --- a/Documentation/arm64/booting.txt
> +++ b/Documentation/arm64/booting.txt
> @@ -72,8 +72,8 @@ The decompressed kernel image contains a 64-byte header as follows:
>  
>    u32 code0;			/* Executable code */
>    u32 code1;			/* Executable code */
> -  u64 text_offset;		/* Image load offset */
> -  u64 res0	= 0;		/* reserved */
> +  u64 text_offset;		/* Image load offset, little endian */
> +  u64 image_size;		/* Effective Image size, little endian */

It seems __le64 would be a better type to use here, if the
value is decided to be little endian.

>    u64 res1	= 0;		/* reserved */
>    u64 res2	= 0;		/* reserved */
>    u64 res3	= 0;		/* reserved */
> @@ -86,9 +86,27 @@ Header notes:


>From a63dd2f24105c55734238efaacdac5048bbedf39 Mon Sep 17 00:00:00 2001
From: Geoff Levand <geoff@infradead.org>
Date: Thu, 12 Jun 2014 11:23:23 -0700
Subject: [PATCH] arm64: Add byte order to image header

When working with a raw arm64 image one needs to know the byte order of the
image header to properly interpret the multi-byte values of the header.  Add
a character value to the image header indicating the byte order the image was
built with:

  1=LSB (little endian), 2=MSB (big endian), 0=no support.

A zero value will indicate a kernel that pre-dates this change.

Signed-off-by: Geoff Levand <geoff@infradead.org>
---
 arch/arm64/kernel/head.S | 6 +++++-
 1 file changed, 5 insertions(+), 1 deletion(-)

diff --git a/arch/arm64/kernel/head.S b/arch/arm64/kernel/head.S
index b96a732..70c3656 100644
--- a/arch/arm64/kernel/head.S
+++ b/arch/arm64/kernel/head.S
@@ -109,7 +109,11 @@
 	 * DO NOT MODIFY. Image header expected by Linux boot-loaders.
 	 */
 	b	stext				// branch to kernel start, magic
-	.long	0				// reserved
+	CPU_LE(.byte	1)			// 1=LSB (little endian)
+	CPU_BE(.byte	2)			// 2=MSB (big endian)
+	.byte	0				// reserved
+	.byte	0				// reserved
+	.byte	0				// reserved
 	.quad	TEXT_OFFSET			// Image load offset from start of RAM
 	.quad	0				// reserved
 	.quad	0				// reserved
-- 
1.9.1

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

* [PATCH 3/4] arm64: export effective Image size to bootloaders
  2014-06-16 20:27   ` Geoff Levand
@ 2014-06-18 16:49     ` Mark Rutland
  2014-06-18 18:27       ` Rob Herring
                         ` (3 more replies)
  0 siblings, 4 replies; 26+ messages in thread
From: Mark Rutland @ 2014-06-18 16:49 UTC (permalink / raw
  To: linux-arm-kernel

On Mon, Jun 16, 2014 at 09:27:12PM +0100, Geoff Levand wrote:
> Hi Mark,

Hi Geoff,

> Sorry for such a delay in my reply.
> 
> On Fri, 2014-05-16 at 10:50 +0100, Mark Rutland wrote:
> > Both the image load offset and the effective image size are forced to be
> > little-endian regardless of the native endianness of the kernel to
> > enable bootloaders to load a kernel of arbitrary endianness. Bootloaders
> > which wish to make use of the load offset can inspect the effective
> > image size field for a non-zero value to determine if the offset is of a
> > known endianness.
> 
> Doing this conversion in the linker script seems complicated.  My
> thought was to just have an image header field that specifies the
> byte order, in the same way that the EI_DATA part of the ELF
> e_ident field does.

While the conversion in the linker script is a little ugly, it does
work, and that complexity is hidden behind the macro I added.

While I initially considered having a field to specify byte order, it's
incredibly likely that bootloaders will not use it. Maintaining a fixed
endianness everywhere makes it simpler for bootloaders to do the right
thing, and matches what existing bootloaders are already doing. That's
less pain for loaders and less pain for the kernel, as things are less
likely to go wrong.

To me it makes more sense to ensure these fields have a consistent
endianness, rather than adding more room for possible mistakes.

> Another advantage of having the byte order in the header is that
> tools other than a boot loader that need to know the byte order
> can get that info from the header, otherwise they would need to
> guess the order with some kind of inspection.

What kind of tools do you envision which would need to know the
endianness of the kernel but would be looking at the Image rather than
the vmlinux?

Mark.

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

* [PATCH 3/4] arm64: export effective Image size to bootloaders
  2014-06-18 16:49     ` Mark Rutland
@ 2014-06-18 18:27       ` Rob Herring
  2014-06-18 18:41       ` Geoff Levand
                         ` (2 subsequent siblings)
  3 siblings, 0 replies; 26+ messages in thread
From: Rob Herring @ 2014-06-18 18:27 UTC (permalink / raw
  To: linux-arm-kernel

On Wed, Jun 18, 2014 at 11:49 AM, Mark Rutland <mark.rutland@arm.com> wrote:
> On Mon, Jun 16, 2014 at 09:27:12PM +0100, Geoff Levand wrote:
>> Hi Mark,
>
> Hi Geoff,
>
>> Sorry for such a delay in my reply.
>>
>> On Fri, 2014-05-16 at 10:50 +0100, Mark Rutland wrote:
>> > Both the image load offset and the effective image size are forced to be
>> > little-endian regardless of the native endianness of the kernel to
>> > enable bootloaders to load a kernel of arbitrary endianness. Bootloaders
>> > which wish to make use of the load offset can inspect the effective
>> > image size field for a non-zero value to determine if the offset is of a
>> > known endianness.
>>
>> Doing this conversion in the linker script seems complicated.  My
>> thought was to just have an image header field that specifies the
>> byte order, in the same way that the EI_DATA part of the ELF
>> e_ident field does.
>
> While the conversion in the linker script is a little ugly, it does
> work, and that complexity is hidden behind the macro I added.
>
> While I initially considered having a field to specify byte order, it's
> incredibly likely that bootloaders will not use it. Maintaining a fixed
> endianness everywhere makes it simpler for bootloaders to do the right
> thing, and matches what existing bootloaders are already doing. That's
> less pain for loaders and less pain for the kernel, as things are less
> likely to go wrong.
>
> To me it makes more sense to ensure these fields have a consistent
> endianness, rather than adding more room for possible mistakes.
>
>> Another advantage of having the byte order in the header is that
>> tools other than a boot loader that need to know the byte order
>> can get that info from the header, otherwise they would need to
>> guess the order with some kind of inspection.
>
> What kind of tools do you envision which would need to know the
> endianness of the kernel but would be looking at the Image rather than
> the vmlinux?

Seems like this has the same problem as being discussed for arm32:

http://permalink.gmane.org/gmane.linux.kernel/1727993

Rob

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

* [PATCH 3/4] arm64: export effective Image size to bootloaders
  2014-06-18 16:49     ` Mark Rutland
  2014-06-18 18:27       ` Rob Herring
@ 2014-06-18 18:41       ` Geoff Levand
  2014-06-19 10:25         ` Mark Rutland
  2014-06-18 18:56       ` Kevin Hilman
  2014-06-18 23:03       ` [PATCH] arm64: Add byte order to image header Geoff Levand
  3 siblings, 1 reply; 26+ messages in thread
From: Geoff Levand @ 2014-06-18 18:41 UTC (permalink / raw
  To: linux-arm-kernel

Hi Mark,

On Wed, 2014-06-18 at 17:49 +0100, Mark Rutland wrote:
> On Mon, Jun 16, 2014 at 09:27:12PM +0100, Geoff Levand wrote:
> While I initially considered having a field to specify byte order, it's
> incredibly likely that bootloaders will not use it. Maintaining a fixed
> endianness everywhere makes it simpler for bootloaders to do the right
> thing, and matches what existing bootloaders are already doing. That's
> less pain for loaders and less pain for the kernel, as things are less
> likely to go wrong.
> 
> To me it makes more sense to ensure these fields have a consistent
> endianness, rather than adding more room for possible mistakes.

I guess my view is that any software expected to support arm64 in both
big and little endian configurations should be tested with such, and
with this it is pretty simple to test and fix, so we shouldn't over
engineer it, but I don't really care how we fix it.

> > Another advantage of having the byte order in the header is that
> > tools other than a boot loader that need to know the byte order
> > can get that info from the header, otherwise they would need to
> > guess the order with some kind of inspection.
> 
> What kind of tools do you envision which would need to know the
> endianness of the kernel but would be looking at the Image rather than
> the vmlinux?

I have no idea, but I can imagine it may be of use to someone who is
trying to figure out why things don't work and would like to know what
kind of image they have.

-Geoff

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

* [PATCH 3/4] arm64: export effective Image size to bootloaders
  2014-06-18 16:49     ` Mark Rutland
  2014-06-18 18:27       ` Rob Herring
  2014-06-18 18:41       ` Geoff Levand
@ 2014-06-18 18:56       ` Kevin Hilman
  2014-06-18 23:03       ` [PATCH] arm64: Add byte order to image header Geoff Levand
  3 siblings, 0 replies; 26+ messages in thread
From: Kevin Hilman @ 2014-06-18 18:56 UTC (permalink / raw
  To: linux-arm-kernel

On Wed, Jun 18, 2014 at 9:49 AM, Mark Rutland <mark.rutland@arm.com> wrote:

> What kind of tools do you envision which would need to know the
> endianness of the kernel but would be looking at the Image rather than
> the vmlinux?

Automated boot infrastructure which has access to the [zu]Image but
not the vmlinux and wants to know which endian rootfs to pass to the
kernel.

Kevin

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

* [PATCH] arm64: Add byte order to image header
  2014-06-18 16:49     ` Mark Rutland
                         ` (2 preceding siblings ...)
  2014-06-18 18:56       ` Kevin Hilman
@ 2014-06-18 23:03       ` Geoff Levand
  2014-06-18 23:07         ` [PATCH] arm64: Add new file asm/image.h Geoff Levand
  3 siblings, 1 reply; 26+ messages in thread
From: Geoff Levand @ 2014-06-18 23:03 UTC (permalink / raw
  To: linux-arm-kernel

When working with a raw arm64 image one needs to know the byte order of the
image header to properly interpret the multi-byte values of the header.  Add
a character value to the image header indicating the byte order the image was
built with:

  1=LSB (little endian), 2=MSB (big endian), 0=no support.

A zero value will indicate a kernel that pre-dates this change.

Signed-off-by: Geoff Levand <geoff@infradead.org>
---
Hi,

I noticed there was a change to the image header for COFF compatibility
that conflicted with my old patch.  Here's an update that also changes
booting.txt.

I'll also post a patch that adds a new file asm/image.h to describe
the header.

-Geoff

 Documentation/arm64/booting.txt | 10 ++++++----
 arch/arm64/kernel/head.S        |  7 ++++++-
 2 files changed, 12 insertions(+), 5 deletions(-)

diff --git a/Documentation/arm64/booting.txt b/Documentation/arm64/booting.txt
index beb754e..525e37c 100644
--- a/Documentation/arm64/booting.txt
+++ b/Documentation/arm64/booting.txt
@@ -73,13 +73,15 @@ The decompressed kernel image contains a 64-byte header as follows:
   u32 code0;			/* Executable code */
   u32 code1;			/* Executable code */
   u64 text_offset;		/* Image load offset */
-  u64 res0	= 0;		/* reserved */
-  u64 res1	= 0;		/* reserved */
-  u64 res2	= 0;		/* reserved */
+  u8  byte_order;		/* 1=LSB (little endian), 2=MSB (big endian) */
+  u8[3] res1;			/* reserved */
+  u32 res2	= 0;		/* reserved */
   u64 res3	= 0;		/* reserved */
   u64 res4	= 0;		/* reserved */
+  u64 res5	= 0;		/* reserved */
+  u64 res6	= 0;		/* reserved */
   u32 magic	= 0x644d5241;	/* Magic number, little endian, "ARM\x64" */
-  u32 res5 = 0;      		/* reserved */
+  u32 res7 = 0;      		/* reserved */
 
 
 Header notes:
diff --git a/arch/arm64/kernel/head.S b/arch/arm64/kernel/head.S
index b96a732..08cd054 100644
--- a/arch/arm64/kernel/head.S
+++ b/arch/arm64/kernel/head.S
@@ -111,7 +111,12 @@
 	b	stext				// branch to kernel start, magic
 	.long	0				// reserved
 	.quad	TEXT_OFFSET			// Image load offset from start of RAM
-	.quad	0				// reserved
+	CPU_LE(.byte	1)			// 1=LSB (little endian)
+	CPU_BE(.byte	2)			// 2=MSB (big endian)
+	.byte	0				// reserved
+	.byte	0				// reserved
+	.byte	0				// reserved
+	.word	0				// reserved
 	.quad	0				// reserved
 	.quad	0				// reserved
 	.quad	0				// reserved
-- 
1.9.1

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

* [PATCH] arm64: Add new file asm/image.h
  2014-06-18 23:03       ` [PATCH] arm64: Add byte order to image header Geoff Levand
@ 2014-06-18 23:07         ` Geoff Levand
  0 siblings, 0 replies; 26+ messages in thread
From: Geoff Levand @ 2014-06-18 23:07 UTC (permalink / raw
  To: linux-arm-kernel

Add the new file asm/image.h that exports a structure arm64_image_header and
some constants to user space that describe the arm64 image header.

Signed-off-by: Geoff Levand <geoff@infradead.org>
---
 Documentation/arm64/booting.txt | 21 ++--------------
 arch/arm64/include/asm/Kbuild   |  2 ++
 arch/arm64/include/asm/image.h  | 53 +++++++++++++++++++++++++++++++++++++++++
 3 files changed, 57 insertions(+), 19 deletions(-)
 create mode 100644 arch/arm64/include/asm/image.h

diff --git a/Documentation/arm64/booting.txt b/Documentation/arm64/booting.txt
index 525e37c..55f246b 100644
--- a/Documentation/arm64/booting.txt
+++ b/Documentation/arm64/booting.txt
@@ -68,25 +68,8 @@ Image target is available instead.
 
 Requirement: MANDATORY
 
-The decompressed kernel image contains a 64-byte header as follows:
-
-  u32 code0;			/* Executable code */
-  u32 code1;			/* Executable code */
-  u64 text_offset;		/* Image load offset */
-  u8  byte_order;		/* 1=LSB (little endian), 2=MSB (big endian) */
-  u8[3] res1;			/* reserved */
-  u32 res2	= 0;		/* reserved */
-  u64 res3	= 0;		/* reserved */
-  u64 res4	= 0;		/* reserved */
-  u64 res5	= 0;		/* reserved */
-  u64 res6	= 0;		/* reserved */
-  u32 magic	= 0x644d5241;	/* Magic number, little endian, "ARM\x64" */
-  u32 res7 = 0;      		/* reserved */
-
-
-Header notes:
-
-- code0/code1 are responsible for branching to stext.
+The decompressed kernel image contains a 64-byte header as described in
+arch/arm64/include/asm/image.h.
 
 The image must be placed at the specified offset (currently 0x80000)
 from the start of the system RAM and called there. The start of the
diff --git a/arch/arm64/include/asm/Kbuild b/arch/arm64/include/asm/Kbuild
index 42c7eec..f73e67a 100644
--- a/arch/arm64/include/asm/Kbuild
+++ b/arch/arm64/include/asm/Kbuild
@@ -55,3 +55,5 @@ generic-y += unaligned.h
 generic-y += user.h
 generic-y += vga.h
 generic-y += xor.h
+
+header-y += image.h
diff --git a/arch/arm64/include/asm/image.h b/arch/arm64/include/asm/image.h
new file mode 100644
index 0000000..7d56872
--- /dev/null
+++ b/arch/arm64/include/asm/image.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2014 Linaro.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef __ASM_IMAGE_H
+#define __ASM_IMAGE_H
+
+#if !defined(__ASSEMBLY__)
+
+/**
+ * struct arm64_image_header - arm64 kernel image header.
+ *
+ * @branch_code: Reserved for instructions to branch to stext.
+ * @text_offset: Image load offset.
+ * @endian: Image byte order: 1=LSB (little endian), 2=MSB (big endian).
+ * @reserved_1: Reserved.
+ * @reserved_2: Reserved.
+ * @reserved_3: Reserved.
+ * @magic: Magic number, "ARM\x64".
+ * @reserved_4: Reserved.
+ **/
+
+struct arm64_image_header {
+	uint32_t branch_code[2];
+	uint64_t text_offset;
+	uint8_t endian;
+	uint8_t reserved_1[3];
+	uint32_t reserved_2;
+	uint64_t reserved_3[4];
+	uint8_t magic[4];
+	uint32_t reserved_4;
+};
+
+enum {arm64_image_le = 1, arm64_image_be = 2};
+
+static const uint8_t arm64_image_magic[4] = {'A', 'R', 'M', 0x64};
+static const uint32_t arm64_image_magic_lsb = 0x644d5241U;
+static const uint32_t arm64_image_magic_msb = 0x41524d64U;
+
+#endif /* !defined(__ASSEMBLY__) */
+
+#endif /* __ASM_IMAGE_H */
-- 
1.9.1

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

* [PATCH 3/4] arm64: export effective Image size to bootloaders
  2014-06-18 18:41       ` Geoff Levand
@ 2014-06-19 10:25         ` Mark Rutland
  2014-06-19 18:07           ` Geoff Levand
  0 siblings, 1 reply; 26+ messages in thread
From: Mark Rutland @ 2014-06-19 10:25 UTC (permalink / raw
  To: linux-arm-kernel

On Wed, Jun 18, 2014 at 07:41:42PM +0100, Geoff Levand wrote:
> Hi Mark,

Hi Geoff,

Thanks for raising the issue. I can see from Kevin's comments that the
kernel endianness is a useful piece of information, so I'll add a field
to the header to export that for v3.

> On Wed, 2014-06-18 at 17:49 +0100, Mark Rutland wrote:
> > On Mon, Jun 16, 2014 at 09:27:12PM +0100, Geoff Levand wrote:
> > While I initially considered having a field to specify byte order, it's
> > incredibly likely that bootloaders will not use it. Maintaining a fixed
> > endianness everywhere makes it simpler for bootloaders to do the right
> > thing, and matches what existing bootloaders are already doing. That's
> > less pain for loaders and less pain for the kernel, as things are less
> > likely to go wrong.
> > 
> > To me it makes more sense to ensure these fields have a consistent
> > endianness, rather than adding more room for possible mistakes.
> 
> I guess my view is that any software expected to support arm64 in both
> big and little endian configurations should be tested with such, and
> with this it is pretty simple to test and fix, so we shouldn't over
> engineer it, but I don't really care how we fix it.

I disagree that the bootloader _must_ have to deal with the endianness
of the kernel. If the user knows the endianness of the kernel and
provides a filesystem of the appropriate endianness, I don't see why the
bootloader should have to do anything differently. In most cases the
bootloader has no need to care.

IMO It's far better to export the fields in the kernel header in a
consistent endianness than it is to force every boot loader to inspect
the endianness of the kernel image.  I can imagine there are going to be
plenty of bootloaders which will not attempt to determine the endianness
and will blindly assume a particular case. Exporting the kernel
endianness does seem to make sense, but I think this should be in
addition to the information bootloaders require rather than being part
of the information bootloaders require.

Thanks,
Mark.

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

* [PATCH 3/4] arm64: export effective Image size to bootloaders
  2014-06-19 10:25         ` Mark Rutland
@ 2014-06-19 18:07           ` Geoff Levand
  2014-06-20 10:17             ` Mark Rutland
  0 siblings, 1 reply; 26+ messages in thread
From: Geoff Levand @ 2014-06-19 18:07 UTC (permalink / raw
  To: linux-arm-kernel

Hi Mark,

On Thu, 2014-06-19 at 11:25 +0100, Mark Rutland wrote:
> I disagree that the bootloader _must_ have to deal with the endianness
> of the kernel. If the user knows the endianness of the kernel and
> provides a filesystem of the appropriate endianness, I don't see why the
> bootloader should have to do anything differently. In most cases the
> bootloader has no need to care.

As I mentioned, I don't really care how this is fixed, but there will be
bootloaders built as both big and little endian (kexec based ones for
example), and so no matter what, bootloaders will need to deal with
converting values.

-Geoff

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

* [PATCH 3/4] arm64: export effective Image size to bootloaders
  2014-06-19 18:07           ` Geoff Levand
@ 2014-06-20 10:17             ` Mark Rutland
  0 siblings, 0 replies; 26+ messages in thread
From: Mark Rutland @ 2014-06-20 10:17 UTC (permalink / raw
  To: linux-arm-kernel

On Thu, Jun 19, 2014 at 07:07:48PM +0100, Geoff Levand wrote:
> Hi Mark,
> 
> On Thu, 2014-06-19 at 11:25 +0100, Mark Rutland wrote:
> > I disagree that the bootloader _must_ have to deal with the endianness
> > of the kernel. If the user knows the endianness of the kernel and
> > provides a filesystem of the appropriate endianness, I don't see why the
> > bootloader should have to do anything differently. In most cases the
> > bootloader has no need to care.
> 
> As I mentioned, I don't really care how this is fixed, but there will be
> bootloaders built as both big and little endian (kexec based ones for
> example), and so no matter what, bootloaders will need to deal with
> converting values.

Sure, bootloaders will need to convert values in some cases.

By having a fixed endian header format, whether or not you need to
byteswap values becomes a fixed property of the bootloader (i.e. whether
it is BE or not) rather than a dynamic property of the kernel Image. So
you only require a single path through your loader for BE and LE
kernels.

If you have constructs like LE64_TO_CPU available to your loader, then
it becomes trivial to write an endian-clean loader. The only pain is
having to test if image_size is non-zero first, but that test is
independent of endiannness.

Mark.

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

end of thread, other threads:[~2014-06-20 10:17 UTC | newest]

Thread overview: 26+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2014-05-16  9:50 [PATCH 0/4] arm64: simplify restrictions on bootloaders Mark Rutland
2014-05-16  9:50 ` [PATCH 1/4] arm64: head.S: remove unnecessary function alignment Mark Rutland
2014-05-16 13:04   ` Christopher Covington
2014-05-20 16:20   ` Laura Abbott
2014-05-16  9:50 ` [PATCH 2/4] arm64: place initial page tables above the kernel Mark Rutland
2014-05-20 16:21   ` Laura Abbott
2014-05-16  9:50 ` [PATCH 3/4] arm64: export effective Image size to bootloaders Mark Rutland
2014-05-20 14:12   ` Tom Rini
2014-05-20 16:22   ` Laura Abbott
2014-06-16 20:27   ` Geoff Levand
2014-06-18 16:49     ` Mark Rutland
2014-06-18 18:27       ` Rob Herring
2014-06-18 18:41       ` Geoff Levand
2014-06-19 10:25         ` Mark Rutland
2014-06-19 18:07           ` Geoff Levand
2014-06-20 10:17             ` Mark Rutland
2014-06-18 18:56       ` Kevin Hilman
2014-06-18 23:03       ` [PATCH] arm64: Add byte order to image header Geoff Levand
2014-06-18 23:07         ` [PATCH] arm64: Add new file asm/image.h Geoff Levand
2014-05-16  9:50 ` [PATCH 4/4] arm64: Enable TEXT_OFFSET fuzzing Mark Rutland
2014-05-16 14:06   ` Catalin Marinas
2014-05-16 16:55     ` Mark Rutland
2014-05-20 14:11       ` Tom Rini
2014-05-20 16:08         ` Mark Rutland
2014-05-21 10:18           ` Mark Rutland
2014-05-20 11:31 ` [PATCH 0/4] arm64: simplify restrictions on bootloaders Ian Campbell

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.