]> git.ipfire.org Git - people/ms/u-boot.git/commitdiff
ARMv8: add optional Linux kernel image header
authorStephen Warren <swarren@nvidia.com>
Wed, 3 Jan 2018 21:31:51 +0000 (14:31 -0700)
committerTom Warren <twarren@nvidia.com>
Fri, 12 Jan 2018 16:52:11 +0000 (09:52 -0700)
Allow placing a Linux kernel image header at the start of the U-Boot
binary. This is useful since the image header reports the amount of memory
(BSS and similar) that U-Boot needs to use, but that isn't part of the
binary size. This can be used by the code that loads U-Boot into memory to
determine where to load U-Boot, based on other users of memory.

Signed-off-by: Stephen Warren <swarren@nvidia.com>
Signed-off-by: Tom Warren <twarren@nvidia.com>
arch/arm/Kconfig
arch/arm/cpu/armv8/linux-kernel-image-header-vars.h [new file with mode: 0644]
arch/arm/cpu/armv8/start.S
arch/arm/cpu/armv8/u-boot.lds
arch/arm/include/asm/boot0-linux-kernel-header.h [new file with mode: 0644]

index c15acdf85c5bc6fc824a3111cc5ffceba5fa7a8c..001ece3cf140815f3f7c69f3938e463f1dabc123 100644 (file)
@@ -32,6 +32,23 @@ config SYS_INIT_SP_BSS_OFFSET
          calculate the stack pointer. This offset should be large enough so
          that the early malloc region, global data (gd), and early stack usage
          do not overlap any appended DTB.
+
+config LINUX_KERNEL_IMAGE_HEADER
+       bool
+       help
+         Place a Linux kernel image header at the start of the U-Boot binary.
+         The format of the header is described in the Linux kernel source at
+         Documentation/arm64/booting.txt. This feature is useful since the
+         image header reports the amount of memory (BSS and similar) that
+         U-Boot needs to use, but which isn't part of the binary.
+
+if LINUX_KERNEL_IMAGE_HEADER
+config LNX_KRNL_IMG_TEXT_OFFSET_BASE
+       hex
+       help
+         The value subtracted from CONFIG_SYS_TEXT_BASE to calculate the
+         TEXT_OFFSET value written in to the Linux kernel image header.
+endif
 endif
 
 config STATIC_RELA
diff --git a/arch/arm/cpu/armv8/linux-kernel-image-header-vars.h b/arch/arm/cpu/armv8/linux-kernel-image-header-vars.h
new file mode 100644 (file)
index 0000000..3e72093
--- /dev/null
@@ -0,0 +1,86 @@
+/*
+ * (C) Copyright 2017 NVIDIA Corporation <www.nvidia.com>
+ *
+ * Derived from Linux kernel v4.14 files:
+ *
+ * arch/arm64/include/asm/assembler.h:
+ * Based on arch/arm/include/asm/assembler.h, arch/arm/mm/proc-macros.S
+ * Copyright (C) 1996-2000 Russell King
+ * Copyright (C) 2012 ARM Ltd.
+ *
+ * arch/arm64/kernel/head.S:
+ * Based on arch/arm/kernel/head.S
+ * Copyright (C) 1994-2002 Russell King
+ * Copyright (C) 2003-2012 ARM Ltd.
+ * Authors:    Catalin Marinas <catalin.marinas@arm.com>
+ *             Will Deacon <will.deacon@arm.com>
+ *
+ * arch/arm64/kernel/image.h:
+ * Copyright (C) 2014 ARM Ltd.
+ *
+ * SPDX-License-Identifier:     GPL-2.0
+ */
+
+/*
+ * 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.
+ *
+ * Note that, in order for this to work when building the ELF64 PIE executable
+ * (for KASLR), these values should not be referenced via R_AARCH64_ABS64
+ * relocations, since these are fixed up at runtime rather than at build time
+ * when PIE is in effect. So we need to split them up in 32-bit high and low
+ * words.
+ */
+#ifdef CONFIG_CPU_BIG_ENDIAN
+#define DATA_LE32(data)                                \
+       ((((data) & 0x000000ff) << 24) |        \
+        (((data) & 0x0000ff00) << 8)  |        \
+        (((data) & 0x00ff0000) >> 8)  |        \
+        (((data) & 0xff000000) >> 24))
+#else
+#define DATA_LE32(data) ((data) & 0xffffffff)
+#endif
+
+#define DEFINE_IMAGE_LE64(sym, data)                           \
+       sym##_lo32 = DATA_LE32((data) & 0xffffffff);            \
+       sym##_hi32 = DATA_LE32((data) >> 32)
+
+#define __MAX(a, b)            (((a) > (b)) ? (a) : (b))
+#define __CODE_DATA_SIZE       (__bss_start - _start)
+#define __BSS_SIZE             (__bss_end - __bss_start)
+#ifdef CONFIG_SYS_INIT_SP_BSS_OFFSET
+#define __MAX_EXTRA_RAM_USAGE  __MAX(__BSS_SIZE, CONFIG_SYS_INIT_SP_BSS_OFFSET)
+#else
+#define __MAX_EXTRA_RAM_USAGE  __BSS_SIZE
+#endif
+#define __MEM_USAGE            (__CODE_DATA_SIZE + __MAX_EXTRA_RAM_USAGE)
+
+#ifdef CONFIG_CPU_BIG_ENDIAN
+#define __HEAD_FLAG_BE         1
+#else
+#define __HEAD_FLAG_BE         0
+#endif
+
+#define __HEAD_FLAG_PAGE_SIZE  1 /* 4K hard-coded */
+
+#define __HEAD_FLAG_PHYS_BASE  1
+
+#define __HEAD_FLAGS           ((__HEAD_FLAG_BE << 0) |        \
+                                (__HEAD_FLAG_PAGE_SIZE << 1) | \
+                                (__HEAD_FLAG_PHYS_BASE << 3))
+
+#define TEXT_OFFSET (CONFIG_SYS_TEXT_BASE - \
+                       CONFIG_LNX_KRNL_IMG_TEXT_OFFSET_BASE)
+
+/*
+ * 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.
+ */
+#define HEAD_SYMBOLS                                           \
+       DEFINE_IMAGE_LE64(_kernel_size_le, __MEM_USAGE);        \
+       DEFINE_IMAGE_LE64(_kernel_offset_le, TEXT_OFFSET);      \
+       DEFINE_IMAGE_LE64(_kernel_flags_le, __HEAD_FLAGS);
+
+       HEAD_SYMBOLS
index f385ed40e1a39bc20d3505a365d58ac80dd03fc6..7a98a1c95d24af2caddfba824182e30268ceb562 100644 (file)
@@ -19,7 +19,9 @@
 
 .globl _start
 _start:
-#ifdef CONFIG_ENABLE_ARM_SOC_BOOT0_HOOK
+#if defined(LINUX_KERNEL_IMAGE_HEADER)
+#include <asm/boot0-linux-kernel-header.h>
+#elif defined(CONFIG_ENABLE_ARM_SOC_BOOT0_HOOK)
 /*
  * Various SoCs need something special and SoC-specific up front in
  * order to boot, allow them to set that in their boot0.h file and then
index 22195b8834b52c063f3f94406dffba221c3a04d7..7b76e0f9f08e26b30584b42f5336099e7e1f5197 100644 (file)
@@ -159,4 +159,8 @@ SECTIONS
        /DISCARD/ : { *(.plt*) }
        /DISCARD/ : { *(.interp*) }
        /DISCARD/ : { *(.gnu*) }
+
+#ifdef CONFIG_LINUX_KERNEL_IMAGE_HEADER
+#include "linux-kernel-image-header-vars.h"
+#endif
 }
diff --git a/arch/arm/include/asm/boot0-linux-kernel-header.h b/arch/arm/include/asm/boot0-linux-kernel-header.h
new file mode 100644 (file)
index 0000000..ca28780
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+ * (C) Copyright 2017 NVIDIA Corporation <www.nvidia.com>
+ *
+ * Derived from Linux kernel v4.14 files:
+ *
+ * arch/arm64/include/asm/assembler.h:
+ * Based on arch/arm/include/asm/assembler.h, arch/arm/mm/proc-macros.S
+ * Copyright (C) 1996-2000 Russell King
+ * Copyright (C) 2012 ARM Ltd.
+ *
+ * arch/arm64/kernel/head.S:
+ * Based on arch/arm/kernel/head.S
+ * Copyright (C) 1994-2002 Russell King
+ * Copyright (C) 2003-2012 ARM Ltd.
+ * Authors:    Catalin Marinas <catalin.marinas@arm.com>
+ *             Will Deacon <will.deacon@arm.com>
+ *
+ * arch/arm64/kernel/image.h:
+ * Copyright (C) 2014 ARM Ltd.
+ *
+ * SPDX-License-Identifier:     GPL-2.0
+ */
+
+       /*
+        * Emit a 64-bit absolute little endian symbol reference in a way that
+        * ensures that it will be resolved at build time, even when building a
+        * PIE binary. This requires cooperation from the linker script, which
+        * must emit the lo32/hi32 halves individually.
+        */
+       .macro  le64sym, sym
+       .long   \sym\()_lo32
+       .long   \sym\()_hi32
+       .endm
+
+.globl _start
+_start:
+       /*
+        * DO NOT MODIFY. Image header expected by Linux boot-loaders.
+        */
+       b       reset                           /* branch to kernel start, magic */
+       .long   0                               /* reserved */
+       le64sym _kernel_offset_le               /* Image load offset from start of RAM, little-endian */
+       le64sym _kernel_size_le                 /* Effective size of kernel image, little-endian */
+       le64sym _kernel_flags_le                /* Informative flags, little-endian */
+       .quad   0                               /* reserved */
+       .quad   0                               /* reserved */
+       .quad   0                               /* reserved */
+       .ascii  "ARM\x64"                       /* Magic number */
+       .long   0                               /* reserved */