linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 0/5] kexec_file_load() for arm
       [not found] <CGME20200601142806eucas1p2680c5625411e7a695d8469760a926520@eucas1p2.samsung.com>
@ 2020-06-01 14:27 ` Łukasz Stelmach
       [not found]   ` <CGME20200601142810eucas1p1767585cf172d26aedb551d7453aa7402@eucas1p1.samsung.com>
                     ` (7 more replies)
  0 siblings, 8 replies; 35+ messages in thread
From: Łukasz Stelmach @ 2020-06-01 14:27 UTC (permalink / raw)
  To: Russell King, Masahiro Yamada, Nick Desaulniers, Thomas Gleixner,
	Enrico Weigelt, Kees Cook, Ingo Molnar, Ben Dooks,
	linux-arm-kernel, linux-kernel
  Cc: AKASHI Takahiro, Bartlomiej Zolnierkiewicz, Marek Szyprowski,
	Łukasz Stelmach

The following series of patches provides implementation of the
kexec_file_load() system call form the arm architecture. zImage and uImage
(legacy format) files are supported. Like on arm64, there is no
possibility of loading a new DTB and the currently loaded is reused.

Łukasz Stelmach (5):
  arm: decompressor: set malloc pool size for the decompressor
  arm: add image header definitions
  arm: decompressor: define a new zImage tag
  arm: Add kexec_image_info
  arm: kexec_file: load zImage or uImage, initrd and dtb

 arch/arm/Kconfig                       |  15 ++
 arch/arm/boot/compressed/Makefile      |   2 +
 arch/arm/boot/compressed/head.S        |   9 +-
 arch/arm/boot/compressed/vmlinux.lds.S |  22 +--
 arch/arm/include/asm/image.h           |  87 ++++++++++
 arch/arm/include/asm/kexec.h           |  14 ++
 arch/arm/kernel/Makefile               |   5 +-
 arch/arm/kernel/kexec_uimage.c         |  80 ++++++++++
 arch/arm/kernel/kexec_zimage.c         | 199 +++++++++++++++++++++++
 arch/arm/kernel/machine_kexec.c        |  39 ++++-
 arch/arm/kernel/machine_kexec_file.c   | 209 +++++++++++++++++++++++++
 11 files changed, 662 insertions(+), 19 deletions(-)
 create mode 100644 arch/arm/include/asm/image.h
 create mode 100644 arch/arm/kernel/kexec_uimage.c
 create mode 100644 arch/arm/kernel/kexec_zimage.c
 create mode 100644 arch/arm/kernel/machine_kexec_file.c

-- 
2.26.2


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

* [PATCH 1/5] arm: decompressor: set malloc pool size for the decompressor
       [not found]   ` <CGME20200601142810eucas1p1767585cf172d26aedb551d7453aa7402@eucas1p1.samsung.com>
@ 2020-06-01 14:27     ` Łukasz Stelmach
  2020-06-01 14:46       ` Russell King - ARM Linux admin
  0 siblings, 1 reply; 35+ messages in thread
From: Łukasz Stelmach @ 2020-06-01 14:27 UTC (permalink / raw)
  To: Russell King, Masahiro Yamada, Nick Desaulniers, Thomas Gleixner,
	Enrico Weigelt, Kees Cook, Ingo Molnar, Ben Dooks,
	linux-arm-kernel, linux-kernel
  Cc: AKASHI Takahiro, Bartlomiej Zolnierkiewicz, Marek Szyprowski,
	Łukasz Stelmach

Move the definition of malloc pool size of the decompressor to
a single place. This value will be exposed later for kexec_file loader.

Signed-off-by: Łukasz Stelmach <l.stelmach@samsung.com>
---
 arch/arm/boot/compressed/Makefile | 2 ++
 arch/arm/boot/compressed/head.S   | 6 ++++--
 2 files changed, 6 insertions(+), 2 deletions(-)

diff --git a/arch/arm/boot/compressed/Makefile b/arch/arm/boot/compressed/Makefile
index 9c11e7490292..b3594cd1588c 100644
--- a/arch/arm/boot/compressed/Makefile
+++ b/arch/arm/boot/compressed/Makefile
@@ -125,6 +125,8 @@ KBSS_SZ = $(shell echo $$(($$($(NM) $(obj)/../../../../vmlinux | \
 		sed -n -e 's/^\([^ ]*\) [AB] __bss_start$$/-0x\1/p' \
 		       -e 's/^\([^ ]*\) [AB] __bss_stop$$/+0x\1/p') )) )
 LDFLAGS_vmlinux = --defsym _kernel_bss_size=$(KBSS_SZ)
+# malloc pool size
+LDFLAGS_vmlinux += --defsym _malloc_size=0x10000
 # Supply ZRELADDR to the decompressor via a linker symbol.
 ifneq ($(CONFIG_AUTO_ZRELADDR),y)
 LDFLAGS_vmlinux += --defsym zreladdr=$(ZRELADDR)
diff --git a/arch/arm/boot/compressed/head.S b/arch/arm/boot/compressed/head.S
index e8e1c866e413..dcc1afa60fb9 100644
--- a/arch/arm/boot/compressed/head.S
+++ b/arch/arm/boot/compressed/head.S
@@ -309,7 +309,8 @@ restart:	adr	r0, LC0
 #ifndef CONFIG_ZBOOT_ROM
 		/* malloc space is above the relocated stack (64k max) */
 		add	sp, sp, r0
-		add	r10, sp, #0x10000
+		ldr	r10, =_malloc_size
+		add	r10, r10, sp
 #else
 		/*
 		 * With ZBOOT_ROM the bss/stack is non relocatable,
@@ -623,7 +624,8 @@ not_relocated:	mov	r0, #0
  */
 		mov	r0, r4
 		mov	r1, sp			@ malloc space above stack
-		add	r2, sp, #0x10000	@ 64k max
+		ldr	r2, =_malloc_size	@ 64k max
+		add	r2, r2, sp
 		mov	r3, r7
 		bl	decompress_kernel
 
-- 
2.26.2


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

* [PATCH 2/5] arm: add image header definitions
       [not found]   ` <CGME20200601142810eucas1p23056f7997a880ff7d676c64703f87115@eucas1p2.samsung.com>
@ 2020-06-01 14:27     ` Łukasz Stelmach
  0 siblings, 0 replies; 35+ messages in thread
From: Łukasz Stelmach @ 2020-06-01 14:27 UTC (permalink / raw)
  To: Russell King, Masahiro Yamada, Nick Desaulniers, Thomas Gleixner,
	Enrico Weigelt, Kees Cook, Ingo Molnar, Ben Dooks,
	linux-arm-kernel, linux-kernel
  Cc: AKASHI Takahiro, Bartlomiej Zolnierkiewicz, Marek Szyprowski,
	Łukasz Stelmach

This structure will be used later by kexec_file loader.

Signed-off-by: Łukasz Stelmach <l.stelmach@samsung.com>
---
 arch/arm/boot/compressed/head.S        |  3 +-
 arch/arm/boot/compressed/vmlinux.lds.S | 13 ++-----
 arch/arm/include/asm/image.h           | 48 ++++++++++++++++++++++++++
 3 files changed, 53 insertions(+), 11 deletions(-)
 create mode 100644 arch/arm/include/asm/image.h

diff --git a/arch/arm/boot/compressed/head.S b/arch/arm/boot/compressed/head.S
index dcc1afa60fb9..97e4cfcfc197 100644
--- a/arch/arm/boot/compressed/head.S
+++ b/arch/arm/boot/compressed/head.S
@@ -7,6 +7,7 @@
  */
 #include <linux/linkage.h>
 #include <asm/assembler.h>
+#include <asm/image.h>
 #include <asm/v7m.h>
 
 #include "efi-header.S"
@@ -211,7 +212,7 @@ start:
 		.word	_magic_start	@ absolute load/run zImage address
 		.word	_magic_end	@ zImage end address
 		.word	0x04030201	@ endianness flag
-		.word	0x45454545	@ another magic number to indicate
+		.word	ARM_ZIMAGE_MAGIC2 @ another magic number to indicate
 		.word	_magic_table	@ additional data table
 
 		__EFI_HEADER
diff --git a/arch/arm/boot/compressed/vmlinux.lds.S b/arch/arm/boot/compressed/vmlinux.lds.S
index f82b5962d97e..308e9cd6a897 100644
--- a/arch/arm/boot/compressed/vmlinux.lds.S
+++ b/arch/arm/boot/compressed/vmlinux.lds.S
@@ -3,14 +3,7 @@
  *  Copyright (C) 2000 Russell King
  */
 
-#ifdef CONFIG_CPU_ENDIAN_BE8
-#define ZIMAGE_MAGIC(x) ( (((x) >> 24) & 0x000000ff) | \
-			  (((x) >>  8) & 0x0000ff00) | \
-			  (((x) <<  8) & 0x00ff0000) | \
-			  (((x) << 24) & 0xff000000) )
-#else
-#define ZIMAGE_MAGIC(x) (x)
-#endif
+#include <asm/image.h>
 
 OUTPUT_ARCH(arm)
 ENTRY(_start)
@@ -43,7 +36,7 @@ SECTIONS
   .table : ALIGN(4) {
     _table_start = .;
     LONG(ZIMAGE_MAGIC(4))
-    LONG(ZIMAGE_MAGIC(0x5a534c4b))
+    LONG(ARM_ZIMAGE_MAGIC3)
     LONG(ZIMAGE_MAGIC(__piggy_size_addr - _start))
     LONG(ZIMAGE_MAGIC(_kernel_bss_size))
     LONG(0)
@@ -107,7 +100,7 @@ SECTIONS
     _edata_real = .;
   }
 
-  _magic_sig = ZIMAGE_MAGIC(0x016f2818);
+  _magic_sig = ARM_ZIMAGE_MAGIC1;
   _magic_start = ZIMAGE_MAGIC(_start);
   _magic_end = ZIMAGE_MAGIC(_edata);
   _magic_table = ZIMAGE_MAGIC(_table_start - _start);
diff --git a/arch/arm/include/asm/image.h b/arch/arm/include/asm/image.h
new file mode 100644
index 000000000000..d5c18a0f6a34
--- /dev/null
+++ b/arch/arm/include/asm/image.h
@@ -0,0 +1,48 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+#ifndef __ASM_IMAGE_H
+#define __ASM_IMAGE_H
+
+#ifdef CONFIG_CPU_ENDIAN_BE8
+#define ZIMAGE_MAGIC(x) ((((x) >> 24) & 0x000000ff) | \
+			 (((x) >>  8) & 0x0000ff00) |  \
+			 (((x) <<  8) & 0x00ff0000) |  \
+			 (((x) << 24) & 0xff000000))
+#else
+#define ZIMAGE_MAGIC(x) (x)
+#endif
+
+#define ARM_ZIMAGE_MAGIC1 ZIMAGE_MAGIC(0x016f2818)
+#define ARM_ZIMAGE_MAGIC2 (0x45454545)
+#define ARM_ZIMAGE_MAGIC3 ZIMAGE_MAGIC(0x5a534c4b)
+
+#ifndef __ASSEMBLY__
+
+#include <linux/types.h>
+#include <asm/setup.h>
+
+/* ARM zImage header format */
+struct arm_zimage_header {
+	__le32 code[9];
+	__le32 magic;
+	__le32 start;
+	__le32 end;
+	__le32 endian;
+	__le32 magic2;
+	__le32 extension_tag_offset;
+};
+
+struct arm_zimage_tag {
+	struct tag_header hdr;
+	union {
+#define ZIMAGE_TAG_KRNL_SIZE ARM_ZIMAGE_MAGIC3
+		struct zimage_krnl_size {
+			__le32 size_ptr;
+			__le32 bss_size;
+		} krnl_size;
+	} u;
+};
+
+#endif /* __ASSEMBLY__ */
+
+#endif /* __ASM_IMAGE_H */
-- 
2.26.2


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

* [PATCH 3/5] arm: decompressor: define a new zImage tag
       [not found]   ` <CGME20200601142810eucas1p1c42ff7c9b417f04bc506261726f08b4f@eucas1p1.samsung.com>
@ 2020-06-01 14:27     ` Łukasz Stelmach
  2020-06-01 14:55       ` Russell King - ARM Linux admin
  0 siblings, 1 reply; 35+ messages in thread
From: Łukasz Stelmach @ 2020-06-01 14:27 UTC (permalink / raw)
  To: Russell King, Masahiro Yamada, Nick Desaulniers, Thomas Gleixner,
	Enrico Weigelt, Kees Cook, Ingo Molnar, Ben Dooks,
	linux-arm-kernel, linux-kernel
  Cc: AKASHI Takahiro, Bartlomiej Zolnierkiewicz, Marek Szyprowski,
	Łukasz Stelmach

Add DCSZ tag which holds dynamic memory (stack, bss, malloc pool)
requirements of the decompressor code.

Signed-off-by: Łukasz Stelmach <l.stelmach@samsung.com>
---
 arch/arm/boot/compressed/vmlinux.lds.S |  9 ++++++++-
 arch/arm/include/asm/image.h           | 13 +++++++++++++
 2 files changed, 21 insertions(+), 1 deletion(-)

diff --git a/arch/arm/boot/compressed/vmlinux.lds.S b/arch/arm/boot/compressed/vmlinux.lds.S
index 308e9cd6a897..dcfdb3209c90 100644
--- a/arch/arm/boot/compressed/vmlinux.lds.S
+++ b/arch/arm/boot/compressed/vmlinux.lds.S
@@ -39,6 +39,11 @@ SECTIONS
     LONG(ARM_ZIMAGE_MAGIC3)
     LONG(ZIMAGE_MAGIC(__piggy_size_addr - _start))
     LONG(ZIMAGE_MAGIC(_kernel_bss_size))
+    LONG(ZIMAGE_MAGIC(5))
+    LONG(ARM_ZIMAGE_MAGIC4)
+    LONG(ZIMAGE_MAGIC(_end - __bss_start))
+    LONG(ZIMAGE_MAGIC(_stack_end - _stack_start))
+    LONG(ZIMAGE_MAGIC(_malloc_size))
     LONG(0)
     _table_end = .;
   }
@@ -108,10 +113,12 @@ SECTIONS
   . = BSS_START;
   __bss_start = .;
   .bss			: { *(.bss) }
+  . = ALIGN(8);		/* the stack must be 64-bit aligned and adjoin bss */
   _end = .;
 
-  . = ALIGN(8);		/* the stack must be 64-bit aligned */
+  _stack_start = .;
   .stack		: { *(.stack) }
+  _stack_end = .;
 
   PROVIDE(__pecoff_data_size = ALIGN(512) - ADDR(.data));
   PROVIDE(__pecoff_end = ALIGN(512));
diff --git a/arch/arm/include/asm/image.h b/arch/arm/include/asm/image.h
index d5c18a0f6a34..624438740f23 100644
--- a/arch/arm/include/asm/image.h
+++ b/arch/arm/include/asm/image.h
@@ -15,6 +15,7 @@
 #define ARM_ZIMAGE_MAGIC1 ZIMAGE_MAGIC(0x016f2818)
 #define ARM_ZIMAGE_MAGIC2 (0x45454545)
 #define ARM_ZIMAGE_MAGIC3 ZIMAGE_MAGIC(0x5a534c4b)
+#define ARM_ZIMAGE_MAGIC4 ZIMAGE_MAGIC(0x5a534344)
 
 #ifndef __ASSEMBLY__
 
@@ -43,6 +44,18 @@ struct arm_zimage_tag {
 	} u;
 };
 
+struct arm_zimage_tag_dc {
+	struct tag_header hdr;
+	union {
+#define ZIMAGE_TAG_DECOMP_SIZE ARM_ZIMAGE_MAGIC4
+		struct zimage_decomp_size {
+			__le32 bss_size;
+			__le32 stack_size;
+			__le32 malloc_size;
+		} decomp_size;
+	} u;
+};
+
 #endif /* __ASSEMBLY__ */
 
 #endif /* __ASM_IMAGE_H */
-- 
2.26.2


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

* [PATCH 4/5] arm: Add kexec_image_info
       [not found]   ` <CGME20200601142811eucas1p260e5a434ea7743eecdb37c4d975c5f05@eucas1p2.samsung.com>
@ 2020-06-01 14:27     ` Łukasz Stelmach
  2020-06-01 14:56       ` Russell King - ARM Linux admin
  0 siblings, 1 reply; 35+ messages in thread
From: Łukasz Stelmach @ 2020-06-01 14:27 UTC (permalink / raw)
  To: Russell King, Masahiro Yamada, Nick Desaulniers, Thomas Gleixner,
	Enrico Weigelt, Kees Cook, Ingo Molnar, Ben Dooks,
	linux-arm-kernel, linux-kernel
  Cc: AKASHI Takahiro, Bartlomiej Zolnierkiewicz, Marek Szyprowski,
	Łukasz Stelmach

Add kexec_image_info to print detailed information about a kexec image.

Signed-off-by: Łukasz Stelmach <l.stelmach@samsung.com>
---
 arch/arm/kernel/machine_kexec.c | 28 ++++++++++++++++++++++++++++
 1 file changed, 28 insertions(+)

diff --git a/arch/arm/kernel/machine_kexec.c b/arch/arm/kernel/machine_kexec.c
index 76300f3813e8..c10a2dfd53d1 100644
--- a/arch/arm/kernel/machine_kexec.c
+++ b/arch/arm/kernel/machine_kexec.c
@@ -31,6 +31,32 @@ extern unsigned long kexec_boot_atags;
 
 static atomic_t waiting_for_crash_ipi;
 
+/**
+ * kexec_image_info - For debugging output.
+ */
+#define kexec_image_info(_i) _kexec_image_info(__func__, __LINE__, _i)
+static void _kexec_image_info(const char *func, int line,
+	const struct kimage *kimage)
+{
+	unsigned long i;
+
+	pr_debug("%s:%d:\n", func, line);
+	pr_debug("  kexec kimage info:\n");
+	pr_debug("    type:        %d\n", kimage->type);
+	pr_debug("    start:       %lx\n", kimage->start);
+	pr_debug("    head:        %lx\n", kimage->head);
+	pr_debug("    nr_segments: %lu\n", kimage->nr_segments);
+
+	for (i = 0; i < kimage->nr_segments; i++) {
+		pr_debug("      segment[%lu]: %08lx - %08lx, 0x%x bytes, %lu pages\n",
+			i,
+			kimage->segment[i].mem,
+			kimage->segment[i].mem + kimage->segment[i].memsz,
+			kimage->segment[i].memsz,
+			kimage->segment[i].memsz /  PAGE_SIZE);
+	}
+}
+
 /*
  * Provide a dummy crash_notes definition while crash dump arrives to arm.
  * This prevents breakage of crash_notes attribute in kernel/ksysfs.c.
@@ -42,6 +68,8 @@ int machine_kexec_prepare(struct kimage *image)
 	__be32 header;
 	int i, err;
 
+	kexec_image_info(image);
+
 	image->arch.kernel_r2 = image->start - KEXEC_ARM_ZIMAGE_OFFSET
 				     + KEXEC_ARM_ATAGS_OFFSET;
 
-- 
2.26.2


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

* [PATCH 5/5] arm: kexec_file: load zImage or uImage, initrd and dtb
       [not found]   ` <CGME20200601142811eucas1p1604c8e6ca06c09f1ec821ea5e1918c53@eucas1p1.samsung.com>
@ 2020-06-01 14:27     ` Łukasz Stelmach
  2020-06-01 15:07       ` Russell King - ARM Linux admin
  0 siblings, 1 reply; 35+ messages in thread
From: Łukasz Stelmach @ 2020-06-01 14:27 UTC (permalink / raw)
  To: Russell King, Masahiro Yamada, Nick Desaulniers, Thomas Gleixner,
	Enrico Weigelt, Kees Cook, Ingo Molnar, Ben Dooks,
	linux-arm-kernel, linux-kernel
  Cc: AKASHI Takahiro, Bartlomiej Zolnierkiewicz, Marek Szyprowski,
	Łukasz Stelmach

This is kexec_file_load implementation for ARM. It loads zImage and
initrd from file descripters and resuses DTB.

Most code is derived from arm64 kexec_file_load implementation
and from kexec-tools.

Cc: AKASHI Takahiro <takahiro.akashi@linaro.org>
Signed-off-by: Łukasz Stelmach <l.stelmach@samsung.com>
---
 arch/arm/Kconfig                     |  15 ++
 arch/arm/include/asm/image.h         |  26 ++++
 arch/arm/include/asm/kexec.h         |  14 ++
 arch/arm/kernel/Makefile             |   5 +-
 arch/arm/kernel/kexec_uimage.c       |  80 ++++++++++
 arch/arm/kernel/kexec_zimage.c       | 199 +++++++++++++++++++++++++
 arch/arm/kernel/machine_kexec.c      |  11 +-
 arch/arm/kernel/machine_kexec_file.c | 209 +++++++++++++++++++++++++++
 8 files changed, 554 insertions(+), 5 deletions(-)
 create mode 100644 arch/arm/kernel/kexec_uimage.c
 create mode 100644 arch/arm/kernel/kexec_zimage.c
 create mode 100644 arch/arm/kernel/machine_kexec_file.c

diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index c77c93c485a0..6adb849cb304 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -1917,6 +1917,21 @@ config KEXEC
 	  is properly shutdown, so do not be surprised if this code does not
 	  initially work for you.
 
+config KEXEC_FILE
+	bool "Kexec file based system call (EXPERIMENTAL)"
+	depends on (!SMP || PM_SLEEP_SMP)
+	depends on USE_OF
+	select KEXEC_CORE
+	select CRC32
+	help
+	  This is new version of kexec system call. This system call is
+	  file based and takes file descriptors as system call argument
+	  for kernel and initramfs as opposed to list of segments as
+	  accepted by previous system call.
+
+	  The kernel to be loaded MUST support Flattened Device Tree
+	  (selected with CONFIG_USE_OF).
+
 config ATAGS_PROC
 	bool "Export atags in procfs"
 	depends on ATAGS && KEXEC
diff --git a/arch/arm/include/asm/image.h b/arch/arm/include/asm/image.h
index 624438740f23..95f23837b04f 100644
--- a/arch/arm/include/asm/image.h
+++ b/arch/arm/include/asm/image.h
@@ -8,8 +8,13 @@
 			 (((x) >>  8) & 0x0000ff00) |  \
 			 (((x) <<  8) & 0x00ff0000) |  \
 			 (((x) << 24) & 0xff000000))
+#define UIMAGE_MAGIC(x) (x)
 #else
 #define ZIMAGE_MAGIC(x) (x)
+#define UIMAGE_MAGIC(x) ((((x) >> 24) & 0x000000ff) | \
+			 (((x) >>  8) & 0x0000ff00) |  \
+			 (((x) <<  8) & 0x00ff0000) |  \
+			 (((x) << 24) & 0xff000000))
 #endif
 
 #define ARM_ZIMAGE_MAGIC1 ZIMAGE_MAGIC(0x016f2818)
@@ -17,6 +22,12 @@
 #define ARM_ZIMAGE_MAGIC3 ZIMAGE_MAGIC(0x5a534c4b)
 #define ARM_ZIMAGE_MAGIC4 ZIMAGE_MAGIC(0x5a534344)
 
+#define ARM_UIMAGE_MAGIC UIMAGE_MAGIC(0x27051956)
+#define ARM_UIMAGE_NAME_LEN		32
+#define ARM_UIMAGE_TYPE_KERNEL		2
+#define ARM_UIMAGE_TYPE_KERNEL_NOLOAD	14
+#define ARM_UIMAGE_ARCH_ARM		2
+
 #ifndef __ASSEMBLY__
 
 #include <linux/types.h>
@@ -33,6 +44,21 @@ struct arm_zimage_header {
 	__le32 extension_tag_offset;
 };
 
+struct arm_uimage_header {
+	__be32 magic;
+	__be32 hdr_crc;
+	__be32 time;
+	__be32 size;
+	__be32 load;
+	__be32 entry;
+	__be32 crc;
+	__u8   os;
+	__u8   arch;
+	__u8   type;
+	__u8   comp;
+	__u8   name[ARM_UIMAGE_NAME_LEN];
+};
+
 struct arm_zimage_tag {
 	struct tag_header hdr;
 	union {
diff --git a/arch/arm/include/asm/kexec.h b/arch/arm/include/asm/kexec.h
index 22751b5b5735..fda35afa7195 100644
--- a/arch/arm/include/asm/kexec.h
+++ b/arch/arm/include/asm/kexec.h
@@ -83,6 +83,20 @@ static inline struct page *boot_pfn_to_page(unsigned long boot_pfn)
 }
 #define boot_pfn_to_page boot_pfn_to_page
 
+#ifdef CONFIG_KEXEC_FILE
+
+extern const struct kexec_file_ops kexec_zimage_ops;
+extern const struct kexec_file_ops kexec_uimage_ops;
+
+struct kimage;
+
+extern int load_other_segments(struct kimage *image,
+		unsigned long kernel_load_addr, unsigned long kernel_size,
+		char *initrd, unsigned long initrd_len,
+		unsigned long initrd_offset, char *cmdline);
+
+#endif /* CONFIG_KEXEC_FILE */
+
 #endif /* __ASSEMBLY__ */
 
 #endif /* CONFIG_KEXEC */
diff --git a/arch/arm/kernel/Makefile b/arch/arm/kernel/Makefile
index 89e5d864e923..466c683bb551 100644
--- a/arch/arm/kernel/Makefile
+++ b/arch/arm/kernel/Makefile
@@ -3,6 +3,7 @@
 # Makefile for the linux kernel.
 #
 
+CFLAGS_kexec_zimage.o := -DTEXT_OFFSET=$(TEXT_OFFSET)
 CPPFLAGS_vmlinux.lds := -DTEXT_OFFSET=$(TEXT_OFFSET)
 AFLAGS_head.o        := -DTEXT_OFFSET=$(TEXT_OFFSET)
 
@@ -56,7 +57,9 @@ obj-$(CONFIG_FUNCTION_TRACER)	+= entry-ftrace.o
 obj-$(CONFIG_DYNAMIC_FTRACE)	+= ftrace.o insn.o patch.o
 obj-$(CONFIG_FUNCTION_GRAPH_TRACER)	+= ftrace.o insn.o patch.o
 obj-$(CONFIG_JUMP_LABEL)	+= jump_label.o insn.o patch.o
-obj-$(CONFIG_KEXEC)		+= machine_kexec.o relocate_kernel.o
+obj-$(CONFIG_KEXEC_CORE)	+= machine_kexec.o relocate_kernel.o
+obj-$(CONFIG_KEXEC_FILE)	+= machine_kexec_file.o kexec_zimage.o	\
+				   kexec_uimage.o
 # Main staffs in KPROBES are in arch/arm/probes/ .
 obj-$(CONFIG_KPROBES)		+= patch.o insn.o
 obj-$(CONFIG_OABI_COMPAT)	+= sys_oabi-compat.o
diff --git a/arch/arm/kernel/kexec_uimage.c b/arch/arm/kernel/kexec_uimage.c
new file mode 100644
index 000000000000..47033574e24e
--- /dev/null
+++ b/arch/arm/kernel/kexec_uimage.c
@@ -0,0 +1,80 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Kexec uImage loader
+ *
+ * Copyright (C) 2020 Samsung Electronics
+ * Author: Łukasz Stelmach <l.stelmach@samsung.com>
+ */
+
+#define pr_fmt(fmt)	"kexec_file(uImage): " fmt
+
+#include <asm/image.h>
+#include <linux/crc32.h>
+#include <linux/err.h>
+#include <linux/kexec.h>
+
+#define crc32_ones(crc, buf, len) \
+	(crc32(crc ^ 0xffffffff, buf, len) ^ 0xffffffff)
+
+static int uimage_probe(const char *uimage_buf, unsigned long uimage_len)
+{
+	const struct arm_uimage_header *h =
+		(struct arm_uimage_header *) uimage_buf;
+	struct arm_uimage_header uhdr;
+	unsigned long zoff = sizeof(struct arm_uimage_header);
+	uint32_t crc;
+
+	if (h->magic != ARM_UIMAGE_MAGIC)
+		return -EINVAL;
+
+	if (h->type != ARM_UIMAGE_TYPE_KERNEL &&
+	    h->type != ARM_UIMAGE_TYPE_KERNEL_NOLOAD){
+		pr_debug("Invalid image type: %d\n", h->type);
+		return -EINVAL;
+	}
+
+	if (h->arch != ARM_UIMAGE_ARCH_ARM) {
+		pr_debug("Invalidy image arch: %d\n", h->arch);
+		return -EINVAL;
+	}
+
+	memcpy((char *)&uhdr, h, sizeof(uhdr));
+	crc = be32_to_cpu(uhdr.hdr_crc);
+	uhdr.hdr_crc = 0;
+
+	if (crc32_ones(0, (char *)&uhdr, sizeof(uhdr)) != crc) {
+		pr_debug("Corrupt header, CRC do not match\n");
+		return -EINVAL;
+	}
+
+	crc = be32_to_cpu(uhdr.crc);
+	if (crc32_ones(0, uimage_buf + zoff, uimage_len - zoff) != crc) {
+		pr_debug("Corrupt zImage, CRC do not match\n");
+		return -EINVAL;
+	}
+
+	return kexec_zimage_ops.probe(uimage_buf + zoff,
+				      uimage_len - zoff);
+}
+
+static void *uimage_load(struct kimage *image,
+				char *uimage, unsigned long uimage_len,
+				char *initrd, unsigned long initrd_len,
+				char *cmdline, unsigned long cmdline_len)
+{
+	const struct arm_uimage_header *h =
+		(struct arm_uimage_header *) uimage;
+	unsigned long zimage_offset = sizeof(struct arm_uimage_header);
+
+	pr_debug("Loading uImage");
+	return kexec_zimage_ops.load(image,
+				     uimage + zimage_offset,
+				     uimage_len - zimage_offset,
+				     initrd, initrd_len,
+				     cmdline, cmdline_len);
+}
+
+const struct kexec_file_ops kexec_uimage_ops = {
+	.probe = uimage_probe,
+	.load = uimage_load,
+};
diff --git a/arch/arm/kernel/kexec_zimage.c b/arch/arm/kernel/kexec_zimage.c
new file mode 100644
index 000000000000..d09795fc9072
--- /dev/null
+++ b/arch/arm/kernel/kexec_zimage.c
@@ -0,0 +1,199 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Kexec zImage loader
+ *
+ * Copyright (C) 2020 Samsung Electronics
+ * Author: Łukasz Stelmach <l.stelmach@samsung.com>
+ */
+
+#define pr_fmt(fmt)	"kexec_file(zImage): " fmt
+
+#include <asm/image.h>
+#include <asm/unaligned.h>
+#include <linux/err.h>
+#include <linux/kexec.h>
+#include <linux/memblock.h>
+
+#define byte_size(t)    ((t)->hdr.size << 2)
+
+static const void *find_extension_tag(const char *buf,
+						       unsigned long len,
+						       uint32_t tag_id)
+{
+	const struct arm_zimage_header *h = (const struct arm_zimage_header *)buf;
+	const struct arm_zimage_tag *tag;
+	uint32_t offset, size;
+	uint32_t max = len - sizeof(struct tag_header);
+
+	if (len < sizeof(*h) ||
+	    h->magic != ARM_ZIMAGE_MAGIC1 ||
+	    h->magic2 != ARM_ZIMAGE_MAGIC2)
+		return NULL;
+
+	for (offset = h->extension_tag_offset;
+	     (tag = (void *)(buf + offset)) != NULL &&
+		     offset < max &&
+		     (size = le32_to_cpu(byte_size(tag))) != 0 &&
+		     offset + size < len;
+	     offset += size) {
+		pr_debug("  offset 0x%08x tag 0x%08x size %u\n",
+			  offset, le32_to_cpu(tag->hdr.tag), size);
+		if (tag->hdr.tag == tag_id)
+			return tag;
+	}
+
+	return NULL;
+}
+
+static int zimage_probe(const char *kernel_buf, unsigned long kernel_len)
+{
+	const struct arm_zimage_header *h =
+		(struct arm_zimage_header *)(kernel_buf);
+
+	if (!h || (kernel_len < sizeof(*h)))
+		return -EINVAL;
+
+	if ((h->magic != ARM_ZIMAGE_MAGIC1) ||
+	    (h->magic2 != ARM_ZIMAGE_MAGIC2))
+		return -EINVAL;
+
+	return 0;
+}
+
+
+#if defined(DEBUG)
+#define debug_offsets() ({			\
+	pr_debug("Image offsets:\n");		\
+	pr_debug("  kernel 0x%08lx 0x%08lx\n", kernel_offset, kernel_len); \
+	pr_debug("  zimage 0x%08lx 0x%08lx\n", zimage_offset, zimage_len); \
+	pr_debug("  initrd 0x%08lx 0x%08lx\n", initrd_offset, initrd_len); \
+})
+#else
+#define debug_offsets()
+#endif
+
+static void *zimage_load(struct kimage *image,
+				char *zimage, unsigned long zimage_len,
+				char *initrd, unsigned long initrd_len,
+				char *cmdline, unsigned long cmdline_len)
+{
+	struct arm_zimage_header *h;
+	struct kexec_buf kbuf;
+	struct kexec_segment *zimage_segment;
+	const struct arm_zimage_tag *klsz_tag;
+	const struct arm_zimage_tag_dc *dcsz_tag;
+	int ret = -EINVAL;
+
+	unsigned long zimage_mem = 0x20000; /* malloc 64kB + stack 4 kB + some bss */
+	unsigned long kernel_len = zimage_len * 4; /* 4:1 compression */
+	unsigned long kernel_offset = memblock_start_of_DRAM() +
+		ALIGN(TEXT_OFFSET, PAGE_SIZE);
+	unsigned long zimage_offset = kernel_offset +
+		ALIGN(kernel_len, PAGE_SIZE);
+	unsigned long initrd_offset = zimage_offset +
+		ALIGN(zimage_len + zimage_mem, PAGE_SIZE);
+
+	if (image->type == KEXEC_TYPE_CRASH) {
+		kernel_offset += crashk_res.start;
+		zimage_offset += crashk_res.start;
+		initrd_offset += crashk_res.start;
+	}
+	debug_offsets();
+
+	h = (struct arm_zimage_header *)zimage;
+
+	klsz_tag = find_extension_tag(zimage, zimage_len, ZIMAGE_TAG_KRNL_SIZE);
+	if (klsz_tag) {
+		uint32_t *p = (void *)zimage +
+			le32_to_cpu(klsz_tag->u.krnl_size.size_ptr);
+		uint32_t edata_size = le32_to_cpu(get_unaligned(p));
+		uint32_t bss_size = le32_to_cpu(klsz_tag->u.krnl_size.bss_size);
+
+		kernel_len = edata_size + bss_size;
+
+		pr_debug("Decompressed kernel sizes:\n");
+		pr_debug(" text+data 0x%08lx bss 0x%08lx total 0x%08lx\n",
+			 (unsigned long)edata_size,
+			 (unsigned long)bss_size,
+			 (unsigned long)kernel_len);
+
+		zimage_offset = kernel_offset + ALIGN(edata_size, PAGE_SIZE);
+		initrd_offset = zimage_offset +
+			max(ALIGN(zimage_len + 0x20000, PAGE_SIZE),
+			    ALIGN((unsigned long)bss_size, PAGE_SIZE));
+		debug_offsets();
+	}
+
+	dcsz_tag = find_extension_tag(zimage, zimage_len,
+				      ZIMAGE_TAG_DECOMP_SIZE);
+	if (dcsz_tag) {
+		uint32_t bss_size = le32_to_cpu(dcsz_tag->u.decomp_size.bss_size);
+		uint32_t stack_size = le32_to_cpu(dcsz_tag->u.decomp_size.stack_size);
+		uint32_t malloc_size = le32_to_cpu(dcsz_tag->u.decomp_size.malloc_size);
+
+		zimage_mem = bss_size + stack_size + malloc_size;
+
+		pr_debug("Decompressor memory requirements:\n");
+		pr_debug(" bss 0x%08lx stack 0x%08lx malloc 0x%08lx total 0x%08lx\n",
+			 (unsigned long)bss_size,
+			 (unsigned long)stack_size,
+			 (unsigned long)malloc_size,
+			 zimage_mem);
+
+		initrd_offset = max(ALIGN(zimage_offset + zimage_len +
+					  bss_size + stack_size +
+					  malloc_size, PAGE_SIZE),
+				    ALIGN(kernel_offset + kernel_len, PAGE_SIZE));
+		debug_offsets();
+	}
+
+	/*
+	 * zImage MUST be loaded into the first 128 MiB of physical
+	 * memory for proper memory detection. Should the uncompressed
+	 * kernel be larger than 128 MiB, zImage relocation becomes
+	 * unavoidable and it is best to rely on the relocation code.
+	 */
+	if (((zimage_offset - kernel_offset) + PAGE_SIZE + 0x8000) >= SZ_128M) {
+		pr_debug("The kernel is too big (%ld MiB) to avoid "
+			 "zImage relocation. Loading zimage at 0x%08lx\n",
+			 ((zimage_offset - kernel_offset) >> 20),
+			 kernel_offset);
+		zimage_offset = kernel_offset;
+	}
+
+	kbuf.image = image;
+	kbuf.top_down = false;
+
+	kbuf.buf_min = zimage_offset;
+	kbuf.buf_max = ULONG_MAX;
+	kbuf.buffer = zimage;
+	kbuf.bufsz = zimage_len;
+	kbuf.buf_align = PAGE_SIZE;
+
+	kbuf.mem = KEXEC_BUF_MEM_UNKNOWN;
+	kbuf.memsz = zimage_len;
+
+	ret = kexec_add_buffer(&kbuf);
+	if (ret)
+		return ERR_PTR(ret);
+
+	pr_debug("Loaded zImage at 0x%lx bufsz=0x%lx memsz=0x%lx\n",
+		 kbuf.mem, kbuf.bufsz, kbuf.memsz);
+
+	initrd_offset += kbuf.mem - zimage_offset;
+	debug_offsets();
+
+	zimage_segment = &image->segment[image->nr_segments - 1];
+	image->start = zimage_segment->mem;
+
+	ret = load_other_segments(image,
+				  zimage_segment->mem, zimage_segment->memsz,
+				  initrd, initrd_len, initrd_offset,
+				  cmdline);
+	return ERR_PTR(ret);
+}
+
+const struct kexec_file_ops kexec_zimage_ops = {
+	.probe = zimage_probe,
+	.load = zimage_load,
+};
diff --git a/arch/arm/kernel/machine_kexec.c b/arch/arm/kernel/machine_kexec.c
index c10a2dfd53d1..2e4780efabb4 100644
--- a/arch/arm/kernel/machine_kexec.c
+++ b/arch/arm/kernel/machine_kexec.c
@@ -93,10 +93,13 @@ int machine_kexec_prepare(struct kimage *image)
 					       current_segment->memsz))
 			return -EINVAL;
 
-		err = get_user(header, (__be32*)current_segment->buf);
-		if (err)
-			return err;
-
+		if (image->file_mode) {
+			header = *(__be32 *)current_segment->buf;
+		} else {
+			err = get_user(header, (__be32 *)current_segment->buf);
+			if (err)
+				return err;
+		}
 		if (header == cpu_to_be32(OF_DT_HEADER))
 			image->arch.kernel_r2 = current_segment->mem;
 	}
diff --git a/arch/arm/kernel/machine_kexec_file.c b/arch/arm/kernel/machine_kexec_file.c
new file mode 100644
index 000000000000..ead680f1e795
--- /dev/null
+++ b/arch/arm/kernel/machine_kexec_file.c
@@ -0,0 +1,209 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * kexec_file for arm
+ *
+ * Copyright (C) 2018 Linaro Limited
+ * Copyright (C) 2020 Samsung Electronics
+ * Authors:
+ *     AKASHI Takahiro <takahiro.akashi@linaro.org>
+ *     Łukasz Stelmach <l.stelmach@samsung.com>
+ *
+ */
+
+#define pr_fmt(fmt) "kexec_file: " fmt
+
+#include <linux/kexec.h>
+#include <linux/libfdt.h>
+#include <linux/of_fdt.h>
+#include <linux/random.h>
+
+/* relevant device tree properties */
+#define FDT_PROP_INITRD_START	"linux,initrd-start"
+#define FDT_PROP_INITRD_END	"linux,initrd-end"
+#define FDT_PROP_BOOTARGS	"bootargs"
+#define FDT_PROP_RNG_SEED	"rng-seed"
+
+static int setup_dtb(struct kimage *image,
+		     unsigned long initrd_load_addr, unsigned long initrd_len,
+		     char *cmdline, void *dtb)
+{
+	int off, ret;
+
+	ret = fdt_path_offset(dtb, "/chosen");
+	if (ret < 0)
+		goto out;
+
+	off = ret;
+
+	/* add bootargs */
+	if (cmdline) {
+		ret = fdt_setprop_string(dtb, off, FDT_PROP_BOOTARGS, cmdline);
+		if (ret)
+			goto out;
+	} else {
+		ret = fdt_delprop(dtb, off, FDT_PROP_BOOTARGS);
+		if (ret && (ret != -FDT_ERR_NOTFOUND))
+			goto out;
+	}
+
+	/* add initrd-* */
+	if (initrd_load_addr) {
+		ret = fdt_setprop_u64(dtb, off, FDT_PROP_INITRD_START,
+				      initrd_load_addr);
+		if (ret)
+			goto out;
+
+		ret = fdt_setprop_u64(dtb, off, FDT_PROP_INITRD_END,
+				      initrd_load_addr + initrd_len);
+		if (ret)
+			goto out;
+	} else {
+		ret = fdt_delprop(dtb, off, FDT_PROP_INITRD_START);
+		if (ret && (ret != -FDT_ERR_NOTFOUND))
+			goto out;
+
+		ret = fdt_delprop(dtb, off, FDT_PROP_INITRD_END);
+		if (ret && (ret != -FDT_ERR_NOTFOUND))
+			goto out;
+	}
+
+	/* add rng-seed */
+	if (rng_is_initialized()) {
+		char seed[128];
+		get_random_bytes(seed, sizeof(seed));
+
+		ret = fdt_setprop(dtb, off, FDT_PROP_RNG_SEED,
+				  seed, sizeof(seed));
+		if (ret)
+			goto out;
+	} else {
+		pr_notice("RNG is not initialised: omitting \"%s\" property\n",
+				FDT_PROP_RNG_SEED);
+		ret = 0;
+	}
+
+out:
+	if (ret)
+		return (ret == -FDT_ERR_NOSPACE) ? -ENOMEM : -EINVAL;
+
+	return 0;
+}
+/*
+ * More space needed so that we can add initrd, bootargs and kaslr-seed.
+ */
+#define DTB_EXTRA_SPACE 0x1000
+
+static int create_dtb(struct kimage *image,
+		      unsigned long initrd_load_addr, unsigned long initrd_len,
+		      char *cmdline, void **dtb)
+{
+	void *buf;
+	size_t buf_size;
+	size_t cmdline_len;
+	int ret;
+
+	cmdline_len = cmdline ? strlen(cmdline) : 0;
+	buf_size = fdt_totalsize(initial_boot_params)
+			+ cmdline_len + DTB_EXTRA_SPACE;
+
+	for (;;) {
+		buf = vmalloc(buf_size);
+		if (!buf)
+			return -ENOMEM;
+
+		/* duplicate a device tree blob */
+		ret = fdt_open_into(initial_boot_params, buf, buf_size);
+		if (ret)
+			return -EINVAL;
+
+		ret = setup_dtb(image, initrd_load_addr, initrd_len,
+				cmdline, buf);
+		if (ret) {
+			vfree(buf);
+			if (ret == -ENOMEM) {
+				/* unlikely, but just in case */
+				buf_size += DTB_EXTRA_SPACE;
+				continue;
+			} else {
+				return ret;
+			}
+		}
+
+		/* trim it */
+		fdt_pack(buf);
+		*dtb = buf;
+
+		return 0;
+	}
+}
+
+int load_other_segments(struct kimage *image,
+			unsigned long zimage_load_addr,
+			unsigned long zimage_len,
+			char *initrd,
+			unsigned long initrd_len,
+			unsigned long initrd_offset,
+			char *cmdline)
+{
+	struct kexec_buf kbuf;
+	void *dtb = NULL;
+	unsigned long initrd_load_addr = 0;
+	unsigned long dtb_len;
+	int ret = 0;
+
+	kbuf.image = image;
+	/* not allocate anything below the kernel */
+	kbuf.buf_min = initrd_offset;
+	if (initrd) {
+		kbuf.buffer = initrd;
+		kbuf.bufsz = initrd_len;
+		kbuf.mem = KEXEC_BUF_MEM_UNKNOWN;
+		kbuf.memsz = initrd_len;
+		kbuf.buf_align = PAGE_SIZE;
+		kbuf.buf_max = ULONG_MAX;
+		kbuf.top_down = false;
+
+		ret = kexec_add_buffer(&kbuf);
+		if (ret)
+			goto out_err;
+
+		pr_debug("Loaded initrd at 0x%lx bufsz=0x%lx memsz=0x%lx\n",
+				kbuf.mem, kbuf.bufsz, kbuf.memsz);
+
+		initrd_load_addr = kbuf.mem;
+		kbuf.buf_min = initrd_load_addr + kbuf.memsz;
+	}
+
+	/* load dtb */
+	ret = create_dtb(image, initrd_load_addr, initrd_len, cmdline, &dtb);
+	if (ret) {
+		pr_err("Preparing for new dtb failed\n");
+		goto out_err;
+	}
+
+	dtb_len = fdt_totalsize(dtb);
+	kbuf.buffer = dtb;
+	kbuf.bufsz = dtb_len;
+	kbuf.mem = KEXEC_BUF_MEM_UNKNOWN;
+	kbuf.memsz = dtb_len;
+	kbuf.buf_align = PAGE_SIZE;
+	kbuf.buf_max = ULONG_MAX;
+	kbuf.top_down = false;
+
+	ret = kexec_add_buffer(&kbuf);
+	if (ret)
+		goto out_err;
+
+	pr_debug("Loaded dtb at 0x%lx bufsz=0x%lx memsz=0x%lx\n",
+		 kbuf.mem, kbuf.bufsz, kbuf.memsz);
+	return 0;
+out_err:
+	vfree(dtb);
+	return ret;
+}
+
+const struct kexec_file_ops * const kexec_file_loaders[] = {
+	&kexec_uimage_ops,
+	&kexec_zimage_ops,
+	NULL
+};
-- 
2.26.2


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

* Re: [PATCH 1/5] arm: decompressor: set malloc pool size for the decompressor
  2020-06-01 14:27     ` [PATCH 1/5] arm: decompressor: set malloc pool size for the decompressor Łukasz Stelmach
@ 2020-06-01 14:46       ` Russell King - ARM Linux admin
       [not found]         ` <CGME20200601145652eucas1p11dcea1cea21824d0a6bfe6ab38c1cab7@eucas1p1.samsung.com>
  0 siblings, 1 reply; 35+ messages in thread
From: Russell King - ARM Linux admin @ 2020-06-01 14:46 UTC (permalink / raw)
  To: Łukasz Stelmach
  Cc: Masahiro Yamada, Nick Desaulniers, Thomas Gleixner,
	Enrico Weigelt, Kees Cook, Ingo Molnar, Ben Dooks,
	linux-arm-kernel, linux-kernel, AKASHI Takahiro,
	Bartlomiej Zolnierkiewicz, Marek Szyprowski

On Mon, Jun 01, 2020 at 04:27:50PM +0200, Łukasz Stelmach wrote:
> Move the definition of malloc pool size of the decompressor to
> a single place. This value will be exposed later for kexec_file loader.
> 
> Signed-off-by: Łukasz Stelmach <l.stelmach@samsung.com>
> ---
>  arch/arm/boot/compressed/Makefile | 2 ++
>  arch/arm/boot/compressed/head.S   | 6 ++++--
>  2 files changed, 6 insertions(+), 2 deletions(-)
> 
> diff --git a/arch/arm/boot/compressed/Makefile b/arch/arm/boot/compressed/Makefile
> index 9c11e7490292..b3594cd1588c 100644
> --- a/arch/arm/boot/compressed/Makefile
> +++ b/arch/arm/boot/compressed/Makefile
> @@ -125,6 +125,8 @@ KBSS_SZ = $(shell echo $$(($$($(NM) $(obj)/../../../../vmlinux | \
>  		sed -n -e 's/^\([^ ]*\) [AB] __bss_start$$/-0x\1/p' \
>  		       -e 's/^\([^ ]*\) [AB] __bss_stop$$/+0x\1/p') )) )
>  LDFLAGS_vmlinux = --defsym _kernel_bss_size=$(KBSS_SZ)
> +# malloc pool size
> +LDFLAGS_vmlinux += --defsym _malloc_size=0x10000
>  # Supply ZRELADDR to the decompressor via a linker symbol.
>  ifneq ($(CONFIG_AUTO_ZRELADDR),y)
>  LDFLAGS_vmlinux += --defsym zreladdr=$(ZRELADDR)
> diff --git a/arch/arm/boot/compressed/head.S b/arch/arm/boot/compressed/head.S
> index e8e1c866e413..dcc1afa60fb9 100644
> --- a/arch/arm/boot/compressed/head.S
> +++ b/arch/arm/boot/compressed/head.S
> @@ -309,7 +309,8 @@ restart:	adr	r0, LC0
>  #ifndef CONFIG_ZBOOT_ROM
>  		/* malloc space is above the relocated stack (64k max) */
>  		add	sp, sp, r0
> -		add	r10, sp, #0x10000
> +		ldr	r10, =_malloc_size
> +		add	r10, r10, sp

This says "locate _malloc_size in a literal pool somewhere, and load it
using a PC-relative offset".  Are you sure that the literal pool is
sensibly located?

Would it be better to use a definition for this?

-- 
RMK's Patch system: https://www.armlinux.org.uk/developer/patches/
FTTC for 0.8m (est. 1762m) line in suburbia: sync at 13.1Mbps down 424kbps up

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

* Re: [PATCH 3/5] arm: decompressor: define a new zImage tag
  2020-06-01 14:27     ` [PATCH 3/5] arm: decompressor: define a new zImage tag Łukasz Stelmach
@ 2020-06-01 14:55       ` Russell King - ARM Linux admin
       [not found]         ` <CGME20200601162002eucas1p28eb08a42de6f313458e9391bd5976e90@eucas1p2.samsung.com>
  0 siblings, 1 reply; 35+ messages in thread
From: Russell King - ARM Linux admin @ 2020-06-01 14:55 UTC (permalink / raw)
  To: Łukasz Stelmach
  Cc: Masahiro Yamada, Nick Desaulniers, Thomas Gleixner,
	Enrico Weigelt, Kees Cook, Ingo Molnar, Ben Dooks,
	linux-arm-kernel, linux-kernel, AKASHI Takahiro,
	Bartlomiej Zolnierkiewicz, Marek Szyprowski

On Mon, Jun 01, 2020 at 04:27:52PM +0200, Łukasz Stelmach wrote:
> Add DCSZ tag which holds dynamic memory (stack, bss, malloc pool)
> requirements of the decompressor code.

Why do we need to know the stack and BSS size, when the userspace
kexec tool doesn't need to know this to perform the same function.

> 
> Signed-off-by: Łukasz Stelmach <l.stelmach@samsung.com>
> ---
>  arch/arm/boot/compressed/vmlinux.lds.S |  9 ++++++++-
>  arch/arm/include/asm/image.h           | 13 +++++++++++++
>  2 files changed, 21 insertions(+), 1 deletion(-)
> 
> diff --git a/arch/arm/boot/compressed/vmlinux.lds.S b/arch/arm/boot/compressed/vmlinux.lds.S
> index 308e9cd6a897..dcfdb3209c90 100644
> --- a/arch/arm/boot/compressed/vmlinux.lds.S
> +++ b/arch/arm/boot/compressed/vmlinux.lds.S
> @@ -39,6 +39,11 @@ SECTIONS
>      LONG(ARM_ZIMAGE_MAGIC3)
>      LONG(ZIMAGE_MAGIC(__piggy_size_addr - _start))
>      LONG(ZIMAGE_MAGIC(_kernel_bss_size))
> +    LONG(ZIMAGE_MAGIC(5))
> +    LONG(ARM_ZIMAGE_MAGIC4)
> +    LONG(ZIMAGE_MAGIC(_end - __bss_start))
> +    LONG(ZIMAGE_MAGIC(_stack_end - _stack_start))
> +    LONG(ZIMAGE_MAGIC(_malloc_size))
>      LONG(0)
>      _table_end = .;
>    }
> @@ -108,10 +113,12 @@ SECTIONS
>    . = BSS_START;
>    __bss_start = .;
>    .bss			: { *(.bss) }
> +  . = ALIGN(8);		/* the stack must be 64-bit aligned and adjoin bss */
>    _end = .;
>  
> -  . = ALIGN(8);		/* the stack must be 64-bit aligned */
> +  _stack_start = .;
>    .stack		: { *(.stack) }
> +  _stack_end = .;
>  
>    PROVIDE(__pecoff_data_size = ALIGN(512) - ADDR(.data));
>    PROVIDE(__pecoff_end = ALIGN(512));
> diff --git a/arch/arm/include/asm/image.h b/arch/arm/include/asm/image.h
> index d5c18a0f6a34..624438740f23 100644
> --- a/arch/arm/include/asm/image.h
> +++ b/arch/arm/include/asm/image.h
> @@ -15,6 +15,7 @@
>  #define ARM_ZIMAGE_MAGIC1 ZIMAGE_MAGIC(0x016f2818)
>  #define ARM_ZIMAGE_MAGIC2 (0x45454545)
>  #define ARM_ZIMAGE_MAGIC3 ZIMAGE_MAGIC(0x5a534c4b)
> +#define ARM_ZIMAGE_MAGIC4 ZIMAGE_MAGIC(0x5a534344)
>  
>  #ifndef __ASSEMBLY__
>  
> @@ -43,6 +44,18 @@ struct arm_zimage_tag {
>  	} u;
>  };
>  
> +struct arm_zimage_tag_dc {
> +	struct tag_header hdr;
> +	union {
> +#define ZIMAGE_TAG_DECOMP_SIZE ARM_ZIMAGE_MAGIC4
> +		struct zimage_decomp_size {
> +			__le32 bss_size;
> +			__le32 stack_size;
> +			__le32 malloc_size;
> +		} decomp_size;
> +	} u;
> +};
> +
>  #endif /* __ASSEMBLY__ */
>  
>  #endif /* __ASM_IMAGE_H */
> -- 
> 2.26.2
> 
> 

-- 
RMK's Patch system: https://www.armlinux.org.uk/developer/patches/
FTTC for 0.8m (est. 1762m) line in suburbia: sync at 13.1Mbps down 424kbps up

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

* Re: [PATCH 4/5] arm: Add kexec_image_info
  2020-06-01 14:27     ` [PATCH 4/5] arm: Add kexec_image_info Łukasz Stelmach
@ 2020-06-01 14:56       ` Russell King - ARM Linux admin
       [not found]         ` <CGME20200601163034eucas1p1f9c726b605c18bf3944254cd83dd67b3@eucas1p1.samsung.com>
  0 siblings, 1 reply; 35+ messages in thread
From: Russell King - ARM Linux admin @ 2020-06-01 14:56 UTC (permalink / raw)
  To: Łukasz Stelmach
  Cc: Masahiro Yamada, Nick Desaulniers, Thomas Gleixner,
	Enrico Weigelt, Kees Cook, Ingo Molnar, Ben Dooks,
	linux-arm-kernel, linux-kernel, AKASHI Takahiro,
	Bartlomiej Zolnierkiewicz, Marek Szyprowski

On Mon, Jun 01, 2020 at 04:27:53PM +0200, Łukasz Stelmach wrote:
> Add kexec_image_info to print detailed information about a kexec image.

Isn't this already visible through kexec debugging?  Why do we need
to duplicate the same output in the kernel?  Do we think that the
kexec interfaces are that fragile that they don't work?

> 
> Signed-off-by: Łukasz Stelmach <l.stelmach@samsung.com>
> ---
>  arch/arm/kernel/machine_kexec.c | 28 ++++++++++++++++++++++++++++
>  1 file changed, 28 insertions(+)
> 
> diff --git a/arch/arm/kernel/machine_kexec.c b/arch/arm/kernel/machine_kexec.c
> index 76300f3813e8..c10a2dfd53d1 100644
> --- a/arch/arm/kernel/machine_kexec.c
> +++ b/arch/arm/kernel/machine_kexec.c
> @@ -31,6 +31,32 @@ extern unsigned long kexec_boot_atags;
>  
>  static atomic_t waiting_for_crash_ipi;
>  
> +/**
> + * kexec_image_info - For debugging output.
> + */
> +#define kexec_image_info(_i) _kexec_image_info(__func__, __LINE__, _i)
> +static void _kexec_image_info(const char *func, int line,
> +	const struct kimage *kimage)
> +{
> +	unsigned long i;
> +
> +	pr_debug("%s:%d:\n", func, line);
> +	pr_debug("  kexec kimage info:\n");
> +	pr_debug("    type:        %d\n", kimage->type);
> +	pr_debug("    start:       %lx\n", kimage->start);
> +	pr_debug("    head:        %lx\n", kimage->head);
> +	pr_debug("    nr_segments: %lu\n", kimage->nr_segments);
> +
> +	for (i = 0; i < kimage->nr_segments; i++) {
> +		pr_debug("      segment[%lu]: %08lx - %08lx, 0x%x bytes, %lu pages\n",
> +			i,
> +			kimage->segment[i].mem,
> +			kimage->segment[i].mem + kimage->segment[i].memsz,
> +			kimage->segment[i].memsz,
> +			kimage->segment[i].memsz /  PAGE_SIZE);
> +	}
> +}
> +
>  /*
>   * Provide a dummy crash_notes definition while crash dump arrives to arm.
>   * This prevents breakage of crash_notes attribute in kernel/ksysfs.c.
> @@ -42,6 +68,8 @@ int machine_kexec_prepare(struct kimage *image)
>  	__be32 header;
>  	int i, err;
>  
> +	kexec_image_info(image);
> +
>  	image->arch.kernel_r2 = image->start - KEXEC_ARM_ZIMAGE_OFFSET
>  				     + KEXEC_ARM_ATAGS_OFFSET;
>  
> -- 
> 2.26.2
> 
> 

-- 
RMK's Patch system: https://www.armlinux.org.uk/developer/patches/
FTTC for 0.8m (est. 1762m) line in suburbia: sync at 13.1Mbps down 424kbps up

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

* Re: [PATCH 1/5] arm: decompressor: set malloc pool size for the decompressor
       [not found]         ` <CGME20200601145652eucas1p11dcea1cea21824d0a6bfe6ab38c1cab7@eucas1p1.samsung.com>
@ 2020-06-01 14:56           ` Lukasz Stelmach
  2020-06-01 15:10             ` Russell King - ARM Linux admin
  0 siblings, 1 reply; 35+ messages in thread
From: Lukasz Stelmach @ 2020-06-01 14:56 UTC (permalink / raw)
  To: Russell King - ARM Linux admin
  Cc: Masahiro Yamada, Nick Desaulniers, Thomas Gleixner,
	Enrico Weigelt, Kees Cook, Ingo Molnar, Ben Dooks,
	linux-arm-kernel, linux-kernel, AKASHI Takahiro,
	Bartlomiej Zolnierkiewicz, Marek Szyprowski

[-- Attachment #1: Type: text/plain, Size: 2194 bytes --]

It was <2020-06-01 pon 15:46>, when Russell King - ARM Linux admin wrote:
> On Mon, Jun 01, 2020 at 04:27:50PM +0200, Łukasz Stelmach wrote:
>> Move the definition of malloc pool size of the decompressor to
>> a single place. This value will be exposed later for kexec_file loader.
>> 
>> Signed-off-by: Łukasz Stelmach <l.stelmach@samsung.com>
>> ---
>>  arch/arm/boot/compressed/Makefile | 2 ++
>>  arch/arm/boot/compressed/head.S   | 6 ++++--
>>  2 files changed, 6 insertions(+), 2 deletions(-)
>> 
>> diff --git a/arch/arm/boot/compressed/Makefile b/arch/arm/boot/compressed/Makefile
>> index 9c11e7490292..b3594cd1588c 100644
>> --- a/arch/arm/boot/compressed/Makefile
>> +++ b/arch/arm/boot/compressed/Makefile
>> @@ -125,6 +125,8 @@ KBSS_SZ = $(shell echo $$(($$($(NM) $(obj)/../../../../vmlinux | \
>>  		sed -n -e 's/^\([^ ]*\) [AB] __bss_start$$/-0x\1/p' \
>>  		       -e 's/^\([^ ]*\) [AB] __bss_stop$$/+0x\1/p') )) )
>>  LDFLAGS_vmlinux = --defsym _kernel_bss_size=$(KBSS_SZ)
>> +# malloc pool size
>> +LDFLAGS_vmlinux += --defsym _malloc_size=0x10000
>>  # Supply ZRELADDR to the decompressor via a linker symbol.
>>  ifneq ($(CONFIG_AUTO_ZRELADDR),y)
>>  LDFLAGS_vmlinux += --defsym zreladdr=$(ZRELADDR)
>> diff --git a/arch/arm/boot/compressed/head.S b/arch/arm/boot/compressed/head.S
>> index e8e1c866e413..dcc1afa60fb9 100644
>> --- a/arch/arm/boot/compressed/head.S
>> +++ b/arch/arm/boot/compressed/head.S
>> @@ -309,7 +309,8 @@ restart:	adr	r0, LC0
>>  #ifndef CONFIG_ZBOOT_ROM
>>  		/* malloc space is above the relocated stack (64k max) */
>>  		add	sp, sp, r0
>> -		add	r10, sp, #0x10000
>> +		ldr	r10, =_malloc_size
>> +		add	r10, r10, sp
>
> This says "locate _malloc_size in a literal pool somewhere, and load it
> using a PC-relative offset".  Are you sure that the literal pool is
> sensibly located?
>
> Would it be better to use a definition for this?

I've followed ZRELADDR way. I think both values should be handled the
same way (it makes it easier to comprehend IMHO). Is there any reason
not to?  Should I change ZRELADDR for v2 too?

-- 
Łukasz Stelmach
Samsung R&D Institute Poland
Samsung Electronics

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 487 bytes --]

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

* Re: [PATCH 5/5] arm: kexec_file: load zImage or uImage, initrd and dtb
  2020-06-01 14:27     ` [PATCH 5/5] arm: kexec_file: load zImage or uImage, initrd and dtb Łukasz Stelmach
@ 2020-06-01 15:07       ` Russell King - ARM Linux admin
  2020-06-01 15:14         ` Russell King - ARM Linux admin
       [not found]         ` <CGME20200601184829eucas1p1b06bfc130083f6248d624febed1de9fc@eucas1p1.samsung.com>
  0 siblings, 2 replies; 35+ messages in thread
From: Russell King - ARM Linux admin @ 2020-06-01 15:07 UTC (permalink / raw)
  To: Łukasz Stelmach
  Cc: Masahiro Yamada, Nick Desaulniers, Thomas Gleixner,
	Enrico Weigelt, Kees Cook, Ingo Molnar, Ben Dooks,
	linux-arm-kernel, linux-kernel, AKASHI Takahiro,
	Bartlomiej Zolnierkiewicz, Marek Szyprowski

On Mon, Jun 01, 2020 at 04:27:54PM +0200, Łukasz Stelmach wrote:
> This is kexec_file_load implementation for ARM. It loads zImage and
> initrd from file descripters and resuses DTB.
> 
> Most code is derived from arm64 kexec_file_load implementation
> and from kexec-tools.

Please make the uImage loader able to be configured out of the
kernel; it's a legacy image format now, and some of us just don't
use it anymore.  That way, those who wish to have it can, and
those who wish not to can have a smaller kernel.

> Cc: AKASHI Takahiro <takahiro.akashi@linaro.org>
> Signed-off-by: Łukasz Stelmach <l.stelmach@samsung.com>
> ---
>  arch/arm/Kconfig                     |  15 ++
>  arch/arm/include/asm/image.h         |  26 ++++
>  arch/arm/include/asm/kexec.h         |  14 ++
>  arch/arm/kernel/Makefile             |   5 +-
>  arch/arm/kernel/kexec_uimage.c       |  80 ++++++++++
>  arch/arm/kernel/kexec_zimage.c       | 199 +++++++++++++++++++++++++
>  arch/arm/kernel/machine_kexec.c      |  11 +-
>  arch/arm/kernel/machine_kexec_file.c | 209 +++++++++++++++++++++++++++
>  8 files changed, 554 insertions(+), 5 deletions(-)
>  create mode 100644 arch/arm/kernel/kexec_uimage.c
>  create mode 100644 arch/arm/kernel/kexec_zimage.c
>  create mode 100644 arch/arm/kernel/machine_kexec_file.c
> 
> diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
> index c77c93c485a0..6adb849cb304 100644
> --- a/arch/arm/Kconfig
> +++ b/arch/arm/Kconfig
> @@ -1917,6 +1917,21 @@ config KEXEC
>  	  is properly shutdown, so do not be surprised if this code does not
>  	  initially work for you.
>  
> +config KEXEC_FILE
> +	bool "Kexec file based system call (EXPERIMENTAL)"
> +	depends on (!SMP || PM_SLEEP_SMP)
> +	depends on USE_OF
> +	select KEXEC_CORE
> +	select CRC32
> +	help
> +	  This is new version of kexec system call. This system call is
> +	  file based and takes file descriptors as system call argument
> +	  for kernel and initramfs as opposed to list of segments as
> +	  accepted by previous system call.
> +
> +	  The kernel to be loaded MUST support Flattened Device Tree
> +	  (selected with CONFIG_USE_OF).
> +
>  config ATAGS_PROC
>  	bool "Export atags in procfs"
>  	depends on ATAGS && KEXEC
> diff --git a/arch/arm/include/asm/image.h b/arch/arm/include/asm/image.h
> index 624438740f23..95f23837b04f 100644
> --- a/arch/arm/include/asm/image.h
> +++ b/arch/arm/include/asm/image.h
> @@ -8,8 +8,13 @@
>  			 (((x) >>  8) & 0x0000ff00) |  \
>  			 (((x) <<  8) & 0x00ff0000) |  \
>  			 (((x) << 24) & 0xff000000))
> +#define UIMAGE_MAGIC(x) (x)
>  #else
>  #define ZIMAGE_MAGIC(x) (x)
> +#define UIMAGE_MAGIC(x) ((((x) >> 24) & 0x000000ff) | \
> +			 (((x) >>  8) & 0x0000ff00) |  \
> +			 (((x) <<  8) & 0x00ff0000) |  \
> +			 (((x) << 24) & 0xff000000))
>  #endif
>  
>  #define ARM_ZIMAGE_MAGIC1 ZIMAGE_MAGIC(0x016f2818)
> @@ -17,6 +22,12 @@
>  #define ARM_ZIMAGE_MAGIC3 ZIMAGE_MAGIC(0x5a534c4b)
>  #define ARM_ZIMAGE_MAGIC4 ZIMAGE_MAGIC(0x5a534344)
>  
> +#define ARM_UIMAGE_MAGIC UIMAGE_MAGIC(0x27051956)
> +#define ARM_UIMAGE_NAME_LEN		32
> +#define ARM_UIMAGE_TYPE_KERNEL		2
> +#define ARM_UIMAGE_TYPE_KERNEL_NOLOAD	14
> +#define ARM_UIMAGE_ARCH_ARM		2
> +
>  #ifndef __ASSEMBLY__
>  
>  #include <linux/types.h>
> @@ -33,6 +44,21 @@ struct arm_zimage_header {
>  	__le32 extension_tag_offset;
>  };
>  
> +struct arm_uimage_header {
> +	__be32 magic;
> +	__be32 hdr_crc;
> +	__be32 time;
> +	__be32 size;
> +	__be32 load;
> +	__be32 entry;
> +	__be32 crc;
> +	__u8   os;
> +	__u8   arch;
> +	__u8   type;
> +	__u8   comp;
> +	__u8   name[ARM_UIMAGE_NAME_LEN];
> +};
> +
>  struct arm_zimage_tag {
>  	struct tag_header hdr;
>  	union {
> diff --git a/arch/arm/include/asm/kexec.h b/arch/arm/include/asm/kexec.h
> index 22751b5b5735..fda35afa7195 100644
> --- a/arch/arm/include/asm/kexec.h
> +++ b/arch/arm/include/asm/kexec.h
> @@ -83,6 +83,20 @@ static inline struct page *boot_pfn_to_page(unsigned long boot_pfn)
>  }
>  #define boot_pfn_to_page boot_pfn_to_page
>  
> +#ifdef CONFIG_KEXEC_FILE
> +
> +extern const struct kexec_file_ops kexec_zimage_ops;
> +extern const struct kexec_file_ops kexec_uimage_ops;
> +
> +struct kimage;
> +
> +extern int load_other_segments(struct kimage *image,
> +		unsigned long kernel_load_addr, unsigned long kernel_size,
> +		char *initrd, unsigned long initrd_len,
> +		unsigned long initrd_offset, char *cmdline);
> +
> +#endif /* CONFIG_KEXEC_FILE */
> +
>  #endif /* __ASSEMBLY__ */
>  
>  #endif /* CONFIG_KEXEC */
> diff --git a/arch/arm/kernel/Makefile b/arch/arm/kernel/Makefile
> index 89e5d864e923..466c683bb551 100644
> --- a/arch/arm/kernel/Makefile
> +++ b/arch/arm/kernel/Makefile
> @@ -3,6 +3,7 @@
>  # Makefile for the linux kernel.
>  #
>  
> +CFLAGS_kexec_zimage.o := -DTEXT_OFFSET=$(TEXT_OFFSET)
>  CPPFLAGS_vmlinux.lds := -DTEXT_OFFSET=$(TEXT_OFFSET)
>  AFLAGS_head.o        := -DTEXT_OFFSET=$(TEXT_OFFSET)
>  
> @@ -56,7 +57,9 @@ obj-$(CONFIG_FUNCTION_TRACER)	+= entry-ftrace.o
>  obj-$(CONFIG_DYNAMIC_FTRACE)	+= ftrace.o insn.o patch.o
>  obj-$(CONFIG_FUNCTION_GRAPH_TRACER)	+= ftrace.o insn.o patch.o
>  obj-$(CONFIG_JUMP_LABEL)	+= jump_label.o insn.o patch.o
> -obj-$(CONFIG_KEXEC)		+= machine_kexec.o relocate_kernel.o
> +obj-$(CONFIG_KEXEC_CORE)	+= machine_kexec.o relocate_kernel.o
> +obj-$(CONFIG_KEXEC_FILE)	+= machine_kexec_file.o kexec_zimage.o	\
> +				   kexec_uimage.o
>  # Main staffs in KPROBES are in arch/arm/probes/ .
>  obj-$(CONFIG_KPROBES)		+= patch.o insn.o
>  obj-$(CONFIG_OABI_COMPAT)	+= sys_oabi-compat.o
> diff --git a/arch/arm/kernel/kexec_uimage.c b/arch/arm/kernel/kexec_uimage.c
> new file mode 100644
> index 000000000000..47033574e24e
> --- /dev/null
> +++ b/arch/arm/kernel/kexec_uimage.c
> @@ -0,0 +1,80 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Kexec uImage loader
> + *
> + * Copyright (C) 2020 Samsung Electronics
> + * Author: Łukasz Stelmach <l.stelmach@samsung.com>
> + */
> +
> +#define pr_fmt(fmt)	"kexec_file(uImage): " fmt
> +
> +#include <asm/image.h>
> +#include <linux/crc32.h>
> +#include <linux/err.h>
> +#include <linux/kexec.h>
> +
> +#define crc32_ones(crc, buf, len) \
> +	(crc32(crc ^ 0xffffffff, buf, len) ^ 0xffffffff)
> +
> +static int uimage_probe(const char *uimage_buf, unsigned long uimage_len)
> +{
> +	const struct arm_uimage_header *h =
> +		(struct arm_uimage_header *) uimage_buf;
> +	struct arm_uimage_header uhdr;
> +	unsigned long zoff = sizeof(struct arm_uimage_header);
> +	uint32_t crc;
> +
> +	if (h->magic != ARM_UIMAGE_MAGIC)
> +		return -EINVAL;
> +
> +	if (h->type != ARM_UIMAGE_TYPE_KERNEL &&
> +	    h->type != ARM_UIMAGE_TYPE_KERNEL_NOLOAD){
> +		pr_debug("Invalid image type: %d\n", h->type);
> +		return -EINVAL;
> +	}
> +
> +	if (h->arch != ARM_UIMAGE_ARCH_ARM) {
> +		pr_debug("Invalidy image arch: %d\n", h->arch);
> +		return -EINVAL;
> +	}
> +
> +	memcpy((char *)&uhdr, h, sizeof(uhdr));
> +	crc = be32_to_cpu(uhdr.hdr_crc);
> +	uhdr.hdr_crc = 0;
> +
> +	if (crc32_ones(0, (char *)&uhdr, sizeof(uhdr)) != crc) {
> +		pr_debug("Corrupt header, CRC do not match\n");
> +		return -EINVAL;
> +	}
> +
> +	crc = be32_to_cpu(uhdr.crc);
> +	if (crc32_ones(0, uimage_buf + zoff, uimage_len - zoff) != crc) {
> +		pr_debug("Corrupt zImage, CRC do not match\n");
> +		return -EINVAL;
> +	}
> +
> +	return kexec_zimage_ops.probe(uimage_buf + zoff,
> +				      uimage_len - zoff);
> +}
> +
> +static void *uimage_load(struct kimage *image,
> +				char *uimage, unsigned long uimage_len,
> +				char *initrd, unsigned long initrd_len,
> +				char *cmdline, unsigned long cmdline_len)
> +{
> +	const struct arm_uimage_header *h =
> +		(struct arm_uimage_header *) uimage;
> +	unsigned long zimage_offset = sizeof(struct arm_uimage_header);
> +
> +	pr_debug("Loading uImage");
> +	return kexec_zimage_ops.load(image,
> +				     uimage + zimage_offset,
> +				     uimage_len - zimage_offset,
> +				     initrd, initrd_len,
> +				     cmdline, cmdline_len);
> +}
> +
> +const struct kexec_file_ops kexec_uimage_ops = {
> +	.probe = uimage_probe,
> +	.load = uimage_load,
> +};
> diff --git a/arch/arm/kernel/kexec_zimage.c b/arch/arm/kernel/kexec_zimage.c
> new file mode 100644
> index 000000000000..d09795fc9072
> --- /dev/null
> +++ b/arch/arm/kernel/kexec_zimage.c
> @@ -0,0 +1,199 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Kexec zImage loader
> + *
> + * Copyright (C) 2020 Samsung Electronics
> + * Author: Łukasz Stelmach <l.stelmach@samsung.com>

Please credit me as part author of this - you have taken some of my
code from the userspace kexec tool (such as the contents of
find_extension_tag()) and copied it in here, so this is not all your
own work.

> + */
> +
> +#define pr_fmt(fmt)	"kexec_file(zImage): " fmt
> +
> +#include <asm/image.h>
> +#include <asm/unaligned.h>
> +#include <linux/err.h>
> +#include <linux/kexec.h>
> +#include <linux/memblock.h>
> +
> +#define byte_size(t)    ((t)->hdr.size << 2)
> +
> +static const void *find_extension_tag(const char *buf,
> +						       unsigned long len,
> +						       uint32_t tag_id)
> +{
> +	const struct arm_zimage_header *h = (const struct arm_zimage_header *)buf;
> +	const struct arm_zimage_tag *tag;
> +	uint32_t offset, size;
> +	uint32_t max = len - sizeof(struct tag_header);
> +
> +	if (len < sizeof(*h) ||
> +	    h->magic != ARM_ZIMAGE_MAGIC1 ||
> +	    h->magic2 != ARM_ZIMAGE_MAGIC2)
> +		return NULL;
> +
> +	for (offset = h->extension_tag_offset;
> +	     (tag = (void *)(buf + offset)) != NULL &&
> +		     offset < max &&
> +		     (size = le32_to_cpu(byte_size(tag))) != 0 &&
> +		     offset + size < len;
> +	     offset += size) {
> +		pr_debug("  offset 0x%08x tag 0x%08x size %u\n",
> +			  offset, le32_to_cpu(tag->hdr.tag), size);
> +		if (tag->hdr.tag == tag_id)
> +			return tag;
> +	}
> +
> +	return NULL;
> +}
> +
> +static int zimage_probe(const char *kernel_buf, unsigned long kernel_len)
> +{
> +	const struct arm_zimage_header *h =
> +		(struct arm_zimage_header *)(kernel_buf);
> +
> +	if (!h || (kernel_len < sizeof(*h)))
> +		return -EINVAL;
> +
> +	if ((h->magic != ARM_ZIMAGE_MAGIC1) ||
> +	    (h->magic2 != ARM_ZIMAGE_MAGIC2))
> +		return -EINVAL;
> +
> +	return 0;
> +}
> +
> +
> +#if defined(DEBUG)
> +#define debug_offsets() ({			\
> +	pr_debug("Image offsets:\n");		\
> +	pr_debug("  kernel 0x%08lx 0x%08lx\n", kernel_offset, kernel_len); \
> +	pr_debug("  zimage 0x%08lx 0x%08lx\n", zimage_offset, zimage_len); \
> +	pr_debug("  initrd 0x%08lx 0x%08lx\n", initrd_offset, initrd_len); \
> +})
> +#else
> +#define debug_offsets()
> +#endif
> +
> +static void *zimage_load(struct kimage *image,
> +				char *zimage, unsigned long zimage_len,
> +				char *initrd, unsigned long initrd_len,
> +				char *cmdline, unsigned long cmdline_len)
> +{
> +	struct arm_zimage_header *h;
> +	struct kexec_buf kbuf;
> +	struct kexec_segment *zimage_segment;
> +	const struct arm_zimage_tag *klsz_tag;
> +	const struct arm_zimage_tag_dc *dcsz_tag;
> +	int ret = -EINVAL;
> +
> +	unsigned long zimage_mem = 0x20000; /* malloc 64kB + stack 4 kB + some bss */
> +	unsigned long kernel_len = zimage_len * 4; /* 4:1 compression */

This has been proven wrong.

> +	unsigned long kernel_offset = memblock_start_of_DRAM() +
> +		ALIGN(TEXT_OFFSET, PAGE_SIZE);

TEXT_OFFSET is actually a property of the loaded kernel, not of the
currently running kernel.  I have a patch to add that into the zImage
tag.

> +	unsigned long zimage_offset = kernel_offset +
> +		ALIGN(kernel_len, PAGE_SIZE);
> +	unsigned long initrd_offset = zimage_offset +
> +		ALIGN(zimage_len + zimage_mem, PAGE_SIZE);

Since kernel_len is wrong, these will be wrong... please only fall
back to this if you don't find the extension tag - in other words,
declare the variables here, but don't initialise them, set them
lower down in the file if we fail to find the extension tag.

> +
> +	if (image->type == KEXEC_TYPE_CRASH) {
> +		kernel_offset += crashk_res.start;
> +		zimage_offset += crashk_res.start;
> +		initrd_offset += crashk_res.start;
> +	}
> +	debug_offsets();
> +
> +	h = (struct arm_zimage_header *)zimage;
> +
> +	klsz_tag = find_extension_tag(zimage, zimage_len, ZIMAGE_TAG_KRNL_SIZE);
> +	if (klsz_tag) {
> +		uint32_t *p = (void *)zimage +
> +			le32_to_cpu(klsz_tag->u.krnl_size.size_ptr);
> +		uint32_t edata_size = le32_to_cpu(get_unaligned(p));
> +		uint32_t bss_size = le32_to_cpu(klsz_tag->u.krnl_size.bss_size);
> +
> +		kernel_len = edata_size + bss_size;
> +
> +		pr_debug("Decompressed kernel sizes:\n");
> +		pr_debug(" text+data 0x%08lx bss 0x%08lx total 0x%08lx\n",
> +			 (unsigned long)edata_size,
> +			 (unsigned long)bss_size,
> +			 (unsigned long)kernel_len);
> +
> +		zimage_offset = kernel_offset + ALIGN(edata_size, PAGE_SIZE);
> +		initrd_offset = zimage_offset +
> +			max(ALIGN(zimage_len + 0x20000, PAGE_SIZE),
> +			    ALIGN((unsigned long)bss_size, PAGE_SIZE));
> +		debug_offsets();

This looks incorrect to me.  Please see the kexec tool - what its doing
in its corresponding section that you copied some of this code from is
carefully thought out and can't be simplified.  Ergo, I think this is
wrong.

> +	}
> +
> +	dcsz_tag = find_extension_tag(zimage, zimage_len,
> +				      ZIMAGE_TAG_DECOMP_SIZE);
> +	if (dcsz_tag) {
> +		uint32_t bss_size = le32_to_cpu(dcsz_tag->u.decomp_size.bss_size);
> +		uint32_t stack_size = le32_to_cpu(dcsz_tag->u.decomp_size.stack_size);
> +		uint32_t malloc_size = le32_to_cpu(dcsz_tag->u.decomp_size.malloc_size);
> +
> +		zimage_mem = bss_size + stack_size + malloc_size;
> +
> +		pr_debug("Decompressor memory requirements:\n");
> +		pr_debug(" bss 0x%08lx stack 0x%08lx malloc 0x%08lx total 0x%08lx\n",
> +			 (unsigned long)bss_size,
> +			 (unsigned long)stack_size,
> +			 (unsigned long)malloc_size,
> +			 zimage_mem);
> +
> +		initrd_offset = max(ALIGN(zimage_offset + zimage_len +
> +					  bss_size + stack_size +
> +					  malloc_size, PAGE_SIZE),
> +				    ALIGN(kernel_offset + kernel_len, PAGE_SIZE));
> +		debug_offsets();
> +	}
> +
> +	/*
> +	 * zImage MUST be loaded into the first 128 MiB of physical
> +	 * memory for proper memory detection. Should the uncompressed
> +	 * kernel be larger than 128 MiB, zImage relocation becomes
> +	 * unavoidable and it is best to rely on the relocation code.
> +	 */
> +	if (((zimage_offset - kernel_offset) + PAGE_SIZE + 0x8000) >= SZ_128M) {
> +		pr_debug("The kernel is too big (%ld MiB) to avoid "
> +			 "zImage relocation. Loading zimage at 0x%08lx\n",
> +			 ((zimage_offset - kernel_offset) >> 20),
> +			 kernel_offset);
> +		zimage_offset = kernel_offset;
> +	}
> +
> +	kbuf.image = image;
> +	kbuf.top_down = false;
> +
> +	kbuf.buf_min = zimage_offset;
> +	kbuf.buf_max = ULONG_MAX;
> +	kbuf.buffer = zimage;
> +	kbuf.bufsz = zimage_len;
> +	kbuf.buf_align = PAGE_SIZE;
> +
> +	kbuf.mem = KEXEC_BUF_MEM_UNKNOWN;
> +	kbuf.memsz = zimage_len;
> +
> +	ret = kexec_add_buffer(&kbuf);
> +	if (ret)
> +		return ERR_PTR(ret);
> +
> +	pr_debug("Loaded zImage at 0x%lx bufsz=0x%lx memsz=0x%lx\n",
> +		 kbuf.mem, kbuf.bufsz, kbuf.memsz);
> +
> +	initrd_offset += kbuf.mem - zimage_offset;
> +	debug_offsets();
> +
> +	zimage_segment = &image->segment[image->nr_segments - 1];
> +	image->start = zimage_segment->mem;
> +
> +	ret = load_other_segments(image,
> +				  zimage_segment->mem, zimage_segment->memsz,
> +				  initrd, initrd_len, initrd_offset,
> +				  cmdline);
> +	return ERR_PTR(ret);
> +}
> +
> +const struct kexec_file_ops kexec_zimage_ops = {
> +	.probe = zimage_probe,
> +	.load = zimage_load,
> +};
> diff --git a/arch/arm/kernel/machine_kexec.c b/arch/arm/kernel/machine_kexec.c
> index c10a2dfd53d1..2e4780efabb4 100644
> --- a/arch/arm/kernel/machine_kexec.c
> +++ b/arch/arm/kernel/machine_kexec.c
> @@ -93,10 +93,13 @@ int machine_kexec_prepare(struct kimage *image)
>  					       current_segment->memsz))
>  			return -EINVAL;
>  
> -		err = get_user(header, (__be32*)current_segment->buf);
> -		if (err)
> -			return err;
> -
> +		if (image->file_mode) {
> +			header = *(__be32 *)current_segment->buf;
> +		} else {
> +			err = get_user(header, (__be32 *)current_segment->buf);
> +			if (err)
> +				return err;
> +		}
>  		if (header == cpu_to_be32(OF_DT_HEADER))
>  			image->arch.kernel_r2 = current_segment->mem;
>  	}
> diff --git a/arch/arm/kernel/machine_kexec_file.c b/arch/arm/kernel/machine_kexec_file.c
> new file mode 100644
> index 000000000000..ead680f1e795
> --- /dev/null
> +++ b/arch/arm/kernel/machine_kexec_file.c
> @@ -0,0 +1,209 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * kexec_file for arm
> + *
> + * Copyright (C) 2018 Linaro Limited
> + * Copyright (C) 2020 Samsung Electronics
> + * Authors:
> + *     AKASHI Takahiro <takahiro.akashi@linaro.org>
> + *     Łukasz Stelmach <l.stelmach@samsung.com>
> + *
> + */
> +
> +#define pr_fmt(fmt) "kexec_file: " fmt
> +
> +#include <linux/kexec.h>
> +#include <linux/libfdt.h>
> +#include <linux/of_fdt.h>
> +#include <linux/random.h>
> +
> +/* relevant device tree properties */
> +#define FDT_PROP_INITRD_START	"linux,initrd-start"
> +#define FDT_PROP_INITRD_END	"linux,initrd-end"
> +#define FDT_PROP_BOOTARGS	"bootargs"
> +#define FDT_PROP_RNG_SEED	"rng-seed"
> +
> +static int setup_dtb(struct kimage *image,
> +		     unsigned long initrd_load_addr, unsigned long initrd_len,
> +		     char *cmdline, void *dtb)
> +{
> +	int off, ret;
> +
> +	ret = fdt_path_offset(dtb, "/chosen");
> +	if (ret < 0)
> +		goto out;
> +
> +	off = ret;
> +
> +	/* add bootargs */
> +	if (cmdline) {
> +		ret = fdt_setprop_string(dtb, off, FDT_PROP_BOOTARGS, cmdline);
> +		if (ret)
> +			goto out;
> +	} else {
> +		ret = fdt_delprop(dtb, off, FDT_PROP_BOOTARGS);
> +		if (ret && (ret != -FDT_ERR_NOTFOUND))
> +			goto out;
> +	}
> +
> +	/* add initrd-* */
> +	if (initrd_load_addr) {
> +		ret = fdt_setprop_u64(dtb, off, FDT_PROP_INITRD_START,
> +				      initrd_load_addr);
> +		if (ret)
> +			goto out;
> +
> +		ret = fdt_setprop_u64(dtb, off, FDT_PROP_INITRD_END,
> +				      initrd_load_addr + initrd_len);
> +		if (ret)
> +			goto out;
> +	} else {
> +		ret = fdt_delprop(dtb, off, FDT_PROP_INITRD_START);
> +		if (ret && (ret != -FDT_ERR_NOTFOUND))
> +			goto out;
> +
> +		ret = fdt_delprop(dtb, off, FDT_PROP_INITRD_END);
> +		if (ret && (ret != -FDT_ERR_NOTFOUND))
> +			goto out;
> +	}
> +
> +	/* add rng-seed */
> +	if (rng_is_initialized()) {
> +		char seed[128];
> +		get_random_bytes(seed, sizeof(seed));
> +
> +		ret = fdt_setprop(dtb, off, FDT_PROP_RNG_SEED,
> +				  seed, sizeof(seed));
> +		if (ret)
> +			goto out;
> +	} else {
> +		pr_notice("RNG is not initialised: omitting \"%s\" property\n",
> +				FDT_PROP_RNG_SEED);
> +		ret = 0;
> +	}
> +
> +out:
> +	if (ret)
> +		return (ret == -FDT_ERR_NOSPACE) ? -ENOMEM : -EINVAL;
> +
> +	return 0;
> +}
> +/*
> + * More space needed so that we can add initrd, bootargs and kaslr-seed.
> + */
> +#define DTB_EXTRA_SPACE 0x1000
> +
> +static int create_dtb(struct kimage *image,
> +		      unsigned long initrd_load_addr, unsigned long initrd_len,
> +		      char *cmdline, void **dtb)
> +{
> +	void *buf;
> +	size_t buf_size;
> +	size_t cmdline_len;
> +	int ret;
> +
> +	cmdline_len = cmdline ? strlen(cmdline) : 0;
> +	buf_size = fdt_totalsize(initial_boot_params)
> +			+ cmdline_len + DTB_EXTRA_SPACE;
> +
> +	for (;;) {
> +		buf = vmalloc(buf_size);
> +		if (!buf)
> +			return -ENOMEM;
> +
> +		/* duplicate a device tree blob */
> +		ret = fdt_open_into(initial_boot_params, buf, buf_size);
> +		if (ret)
> +			return -EINVAL;
> +
> +		ret = setup_dtb(image, initrd_load_addr, initrd_len,
> +				cmdline, buf);
> +		if (ret) {
> +			vfree(buf);
> +			if (ret == -ENOMEM) {
> +				/* unlikely, but just in case */
> +				buf_size += DTB_EXTRA_SPACE;
> +				continue;
> +			} else {
> +				return ret;
> +			}
> +		}
> +
> +		/* trim it */
> +		fdt_pack(buf);
> +		*dtb = buf;
> +
> +		return 0;
> +	}
> +}
> +
> +int load_other_segments(struct kimage *image,
> +			unsigned long zimage_load_addr,
> +			unsigned long zimage_len,
> +			char *initrd,
> +			unsigned long initrd_len,
> +			unsigned long initrd_offset,
> +			char *cmdline)
> +{
> +	struct kexec_buf kbuf;
> +	void *dtb = NULL;
> +	unsigned long initrd_load_addr = 0;
> +	unsigned long dtb_len;
> +	int ret = 0;
> +
> +	kbuf.image = image;
> +	/* not allocate anything below the kernel */
> +	kbuf.buf_min = initrd_offset;
> +	if (initrd) {
> +		kbuf.buffer = initrd;
> +		kbuf.bufsz = initrd_len;
> +		kbuf.mem = KEXEC_BUF_MEM_UNKNOWN;
> +		kbuf.memsz = initrd_len;
> +		kbuf.buf_align = PAGE_SIZE;
> +		kbuf.buf_max = ULONG_MAX;
> +		kbuf.top_down = false;
> +
> +		ret = kexec_add_buffer(&kbuf);
> +		if (ret)
> +			goto out_err;
> +
> +		pr_debug("Loaded initrd at 0x%lx bufsz=0x%lx memsz=0x%lx\n",
> +				kbuf.mem, kbuf.bufsz, kbuf.memsz);
> +
> +		initrd_load_addr = kbuf.mem;
> +		kbuf.buf_min = initrd_load_addr + kbuf.memsz;
> +	}
> +
> +	/* load dtb */
> +	ret = create_dtb(image, initrd_load_addr, initrd_len, cmdline, &dtb);
> +	if (ret) {
> +		pr_err("Preparing for new dtb failed\n");
> +		goto out_err;
> +	}
> +
> +	dtb_len = fdt_totalsize(dtb);
> +	kbuf.buffer = dtb;
> +	kbuf.bufsz = dtb_len;
> +	kbuf.mem = KEXEC_BUF_MEM_UNKNOWN;
> +	kbuf.memsz = dtb_len;
> +	kbuf.buf_align = PAGE_SIZE;
> +	kbuf.buf_max = ULONG_MAX;
> +	kbuf.top_down = false;
> +
> +	ret = kexec_add_buffer(&kbuf);
> +	if (ret)
> +		goto out_err;
> +
> +	pr_debug("Loaded dtb at 0x%lx bufsz=0x%lx memsz=0x%lx\n",
> +		 kbuf.mem, kbuf.bufsz, kbuf.memsz);
> +	return 0;
> +out_err:
> +	vfree(dtb);
> +	return ret;
> +}
> +
> +const struct kexec_file_ops * const kexec_file_loaders[] = {
> +	&kexec_uimage_ops,
> +	&kexec_zimage_ops,
> +	NULL
> +};
> -- 
> 2.26.2
> 
> 

-- 
RMK's Patch system: https://www.armlinux.org.uk/developer/patches/
FTTC for 0.8m (est. 1762m) line in suburbia: sync at 13.1Mbps down 424kbps up

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

* Re: [PATCH 1/5] arm: decompressor: set malloc pool size for the decompressor
  2020-06-01 14:56           ` Lukasz Stelmach
@ 2020-06-01 15:10             ` Russell King - ARM Linux admin
       [not found]               ` <CGME20200601165420eucas1p273e0cdb143312b9a621e2444c5daae9b@eucas1p2.samsung.com>
  0 siblings, 1 reply; 35+ messages in thread
From: Russell King - ARM Linux admin @ 2020-06-01 15:10 UTC (permalink / raw)
  To: Lukasz Stelmach
  Cc: Masahiro Yamada, Nick Desaulniers, Thomas Gleixner,
	Enrico Weigelt, Kees Cook, Ingo Molnar, Ben Dooks,
	linux-arm-kernel, linux-kernel, AKASHI Takahiro,
	Bartlomiej Zolnierkiewicz, Marek Szyprowski

On Mon, Jun 01, 2020 at 04:56:40PM +0200, Lukasz Stelmach wrote:
> It was <2020-06-01 pon 15:46>, when Russell King - ARM Linux admin wrote:
> > On Mon, Jun 01, 2020 at 04:27:50PM +0200, Łukasz Stelmach wrote:
> >> Move the definition of malloc pool size of the decompressor to
> >> a single place. This value will be exposed later for kexec_file loader.
> >> 
> >> Signed-off-by: Łukasz Stelmach <l.stelmach@samsung.com>
> >> ---
> >>  arch/arm/boot/compressed/Makefile | 2 ++
> >>  arch/arm/boot/compressed/head.S   | 6 ++++--
> >>  2 files changed, 6 insertions(+), 2 deletions(-)
> >> 
> >> diff --git a/arch/arm/boot/compressed/Makefile b/arch/arm/boot/compressed/Makefile
> >> index 9c11e7490292..b3594cd1588c 100644
> >> --- a/arch/arm/boot/compressed/Makefile
> >> +++ b/arch/arm/boot/compressed/Makefile
> >> @@ -125,6 +125,8 @@ KBSS_SZ = $(shell echo $$(($$($(NM) $(obj)/../../../../vmlinux | \
> >>  		sed -n -e 's/^\([^ ]*\) [AB] __bss_start$$/-0x\1/p' \
> >>  		       -e 's/^\([^ ]*\) [AB] __bss_stop$$/+0x\1/p') )) )
> >>  LDFLAGS_vmlinux = --defsym _kernel_bss_size=$(KBSS_SZ)
> >> +# malloc pool size
> >> +LDFLAGS_vmlinux += --defsym _malloc_size=0x10000
> >>  # Supply ZRELADDR to the decompressor via a linker symbol.
> >>  ifneq ($(CONFIG_AUTO_ZRELADDR),y)
> >>  LDFLAGS_vmlinux += --defsym zreladdr=$(ZRELADDR)
> >> diff --git a/arch/arm/boot/compressed/head.S b/arch/arm/boot/compressed/head.S
> >> index e8e1c866e413..dcc1afa60fb9 100644
> >> --- a/arch/arm/boot/compressed/head.S
> >> +++ b/arch/arm/boot/compressed/head.S
> >> @@ -309,7 +309,8 @@ restart:	adr	r0, LC0
> >>  #ifndef CONFIG_ZBOOT_ROM
> >>  		/* malloc space is above the relocated stack (64k max) */
> >>  		add	sp, sp, r0
> >> -		add	r10, sp, #0x10000
> >> +		ldr	r10, =_malloc_size
> >> +		add	r10, r10, sp
> >
> > This says "locate _malloc_size in a literal pool somewhere, and load it
> > using a PC-relative offset".  Are you sure that the literal pool is
> > sensibly located?
> >
> > Would it be better to use a definition for this?
> 
> I've followed ZRELADDR way. I think both values should be handled the
> same way (it makes it easier to comprehend IMHO). Is there any reason
> not to?  Should I change ZRELADDR for v2 too?

There's a good reason.  ZRELADDR can be a constant that does not fit
into the ARMs immediate constants (8 bits of significant data plus
a multiple of a 2-bit shift), whereas the size of the malloc space
is guaranteed to fit.  So, ZRELADDR has to use a literal load.
This doesn't.

-- 
RMK's Patch system: https://www.armlinux.org.uk/developer/patches/
FTTC for 0.8m (est. 1762m) line in suburbia: sync at 13.1Mbps down 424kbps up

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

* Re: [PATCH 5/5] arm: kexec_file: load zImage or uImage, initrd and dtb
  2020-06-01 15:07       ` Russell King - ARM Linux admin
@ 2020-06-01 15:14         ` Russell King - ARM Linux admin
       [not found]           ` <CGME20200601164700eucas1p2e30af458bae7e820ca55f7936ac3579a@eucas1p2.samsung.com>
       [not found]         ` <CGME20200601184829eucas1p1b06bfc130083f6248d624febed1de9fc@eucas1p1.samsung.com>
  1 sibling, 1 reply; 35+ messages in thread
From: Russell King - ARM Linux admin @ 2020-06-01 15:14 UTC (permalink / raw)
  To: Łukasz Stelmach
  Cc: Kees Cook, Bartlomiej Zolnierkiewicz, Masahiro Yamada,
	Nick Desaulniers, linux-kernel, AKASHI Takahiro, Ben Dooks,
	Thomas Gleixner, Enrico Weigelt, Ingo Molnar, linux-arm-kernel,
	Marek Szyprowski

On Mon, Jun 01, 2020 at 04:07:45PM +0100, Russell King - ARM Linux admin wrote:
> On Mon, Jun 01, 2020 at 04:27:54PM +0200, Łukasz Stelmach wrote:
> > diff --git a/arch/arm/kernel/kexec_zimage.c b/arch/arm/kernel/kexec_zimage.c
> > new file mode 100644
> > index 000000000000..d09795fc9072
> > --- /dev/null
> > +++ b/arch/arm/kernel/kexec_zimage.c
> > @@ -0,0 +1,199 @@
> > +// SPDX-License-Identifier: GPL-2.0
> > +/*
> > + * Kexec zImage loader
> > + *
> > + * Copyright (C) 2020 Samsung Electronics
> > + * Author: Łukasz Stelmach <l.stelmach@samsung.com>
> 
> Please credit me as part author of this - you have taken some of my
> code from the userspace kexec tool (such as the contents of
> find_extension_tag()) and copied it in here, so this is not all your
> own work.

It would also be a very good idea to indicate _where_ you copied some
of this code from.

-- 
RMK's Patch system: https://www.armlinux.org.uk/developer/patches/
FTTC for 0.8m (est. 1762m) line in suburbia: sync at 13.1Mbps down 424kbps up

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

* Re: [PATCH 3/5] arm: decompressor: define a new zImage tag
       [not found]         ` <CGME20200601162002eucas1p28eb08a42de6f313458e9391bd5976e90@eucas1p2.samsung.com>
@ 2020-06-01 16:19           ` Lukasz Stelmach
  2020-06-01 18:25             ` Russell King - ARM Linux admin
  0 siblings, 1 reply; 35+ messages in thread
From: Lukasz Stelmach @ 2020-06-01 16:19 UTC (permalink / raw)
  To: Russell King - ARM Linux admin
  Cc: Masahiro Yamada, Nick Desaulniers, Thomas Gleixner,
	Enrico Weigelt, Kees Cook, Ingo Molnar, Ben Dooks,
	linux-arm-kernel, linux-kernel, AKASHI Takahiro,
	Bartlomiej Zolnierkiewicz, Marek Szyprowski

[-- Attachment #1: Type: text/plain, Size: 3954 bytes --]

It was <2020-06-01 pon 15:55>, when Russell King - ARM Linux admin wrote:
> On Mon, Jun 01, 2020 at 04:27:52PM +0200, Łukasz Stelmach wrote:
>> Add DCSZ tag which holds dynamic memory (stack, bss, malloc pool)
>> requirements of the decompressor code.
>
> Why do we need to know the stack and BSS size, when the userspace
> kexec tool doesn't need to know this to perform the same function.


kexec-tools load zImage as low in DRAM as possible and rely on two
assumptions:

    + the zImage will copy itself to make enough room for the kernel,
    + sizeof(zImage+mem) < sizeof(kernel+mem), which is true because
      of compression.

       DRAM start
       + 0x8000

zImage    |-----------|-----|-------|
            text+data   bss   stack 

                 text+data           bss   
kernel    |---------------------|-------------------|


initrd                                              |-initrd-|-dtb-|


My code on the other hand tries to load the zImage high enough to make
room for the kernel without copying the zImage.


            text+data           bss   
kernel    |-----------|-------------------|

zImage                |-----------|-----|-------|
                        text+data   bss   stack 

initrd                                          |-initrd-|-dtb-|


In such case the second assumption would be

    sizeof(zImage+mem) < sizeof(kernel bss)

and I can't tell for sure it would always be true. That is why we need
detailed information about decompressor memory requirements.


>> 
>> Signed-off-by: Łukasz Stelmach <l.stelmach@samsung.com>
>> ---
>>  arch/arm/boot/compressed/vmlinux.lds.S |  9 ++++++++-
>>  arch/arm/include/asm/image.h           | 13 +++++++++++++
>>  2 files changed, 21 insertions(+), 1 deletion(-)
>> 
>> diff --git a/arch/arm/boot/compressed/vmlinux.lds.S b/arch/arm/boot/compressed/vmlinux.lds.S
>> index 308e9cd6a897..dcfdb3209c90 100644
>> --- a/arch/arm/boot/compressed/vmlinux.lds.S
>> +++ b/arch/arm/boot/compressed/vmlinux.lds.S
>> @@ -39,6 +39,11 @@ SECTIONS
>>      LONG(ARM_ZIMAGE_MAGIC3)
>>      LONG(ZIMAGE_MAGIC(__piggy_size_addr - _start))
>>      LONG(ZIMAGE_MAGIC(_kernel_bss_size))
>> +    LONG(ZIMAGE_MAGIC(5))
>> +    LONG(ARM_ZIMAGE_MAGIC4)
>> +    LONG(ZIMAGE_MAGIC(_end - __bss_start))
>> +    LONG(ZIMAGE_MAGIC(_stack_end - _stack_start))
>> +    LONG(ZIMAGE_MAGIC(_malloc_size))
>>      LONG(0)
>>      _table_end = .;
>>    }
>> @@ -108,10 +113,12 @@ SECTIONS
>>    . = BSS_START;
>>    __bss_start = .;
>>    .bss			: { *(.bss) }
>> +  . = ALIGN(8);		/* the stack must be 64-bit aligned and adjoin bss */
>>    _end = .;
>>  
>> -  . = ALIGN(8);		/* the stack must be 64-bit aligned */
>> +  _stack_start = .;
>>    .stack		: { *(.stack) }
>> +  _stack_end = .;
>>  
>>    PROVIDE(__pecoff_data_size = ALIGN(512) - ADDR(.data));
>>    PROVIDE(__pecoff_end = ALIGN(512));
>> diff --git a/arch/arm/include/asm/image.h b/arch/arm/include/asm/image.h
>> index d5c18a0f6a34..624438740f23 100644
>> --- a/arch/arm/include/asm/image.h
>> +++ b/arch/arm/include/asm/image.h
>> @@ -15,6 +15,7 @@
>>  #define ARM_ZIMAGE_MAGIC1 ZIMAGE_MAGIC(0x016f2818)
>>  #define ARM_ZIMAGE_MAGIC2 (0x45454545)
>>  #define ARM_ZIMAGE_MAGIC3 ZIMAGE_MAGIC(0x5a534c4b)
>> +#define ARM_ZIMAGE_MAGIC4 ZIMAGE_MAGIC(0x5a534344)
>>  
>>  #ifndef __ASSEMBLY__
>>  
>> @@ -43,6 +44,18 @@ struct arm_zimage_tag {
>>  	} u;
>>  };
>>  
>> +struct arm_zimage_tag_dc {
>> +	struct tag_header hdr;
>> +	union {
>> +#define ZIMAGE_TAG_DECOMP_SIZE ARM_ZIMAGE_MAGIC4
>> +		struct zimage_decomp_size {
>> +			__le32 bss_size;
>> +			__le32 stack_size;
>> +			__le32 malloc_size;
>> +		} decomp_size;
>> +	} u;
>> +};
>> +
>>  #endif /* __ASSEMBLY__ */
>>  
>>  #endif /* __ASM_IMAGE_H */
>> -- 
>> 2.26.2
>> 
>> 

-- 
Łukasz Stelmach
Samsung R&D Institute Poland
Samsung Electronics

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 487 bytes --]

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

* Re: [PATCH 4/5] arm: Add kexec_image_info
       [not found]         ` <CGME20200601163034eucas1p1f9c726b605c18bf3944254cd83dd67b3@eucas1p1.samsung.com>
@ 2020-06-01 16:30           ` Lukasz Stelmach
  0 siblings, 0 replies; 35+ messages in thread
From: Lukasz Stelmach @ 2020-06-01 16:30 UTC (permalink / raw)
  To: Russell King - ARM Linux admin
  Cc: Masahiro Yamada, Nick Desaulniers, Thomas Gleixner,
	Enrico Weigelt, Kees Cook, Ingo Molnar, Ben Dooks,
	linux-arm-kernel, linux-kernel, AKASHI Takahiro,
	Bartlomiej Zolnierkiewicz, Marek Szyprowski

[-- Attachment #1: Type: text/plain, Size: 2784 bytes --]

It was <2020-06-01 pon 15:56>, when Russell King - ARM Linux admin wrote:
> On Mon, Jun 01, 2020 at 04:27:53PM +0200, Łukasz Stelmach wrote:
>> Add kexec_image_info to print detailed information about a kexec image.
>
> Isn't this already visible through kexec debugging?  Why do we need
> to duplicate the same output in the kernel?  Do we think that the
> kexec interfaces are that fragile that they don't work?

Because:

    + kexec_image_info is required if we want to show information for an
      image loaded via kexec_file_load (with kexec-tools or any other
      tool e.g. u-root),
    + this is where both interfaces meet and it is easy to compare
      their results,
    + I consider showing results as close to the end of a code path as
      possible more reliable.

>> 
>> Signed-off-by: Łukasz Stelmach <l.stelmach@samsung.com>
>> ---
>>  arch/arm/kernel/machine_kexec.c | 28 ++++++++++++++++++++++++++++
>>  1 file changed, 28 insertions(+)
>> 
>> diff --git a/arch/arm/kernel/machine_kexec.c b/arch/arm/kernel/machine_kexec.c
>> index 76300f3813e8..c10a2dfd53d1 100644
>> --- a/arch/arm/kernel/machine_kexec.c
>> +++ b/arch/arm/kernel/machine_kexec.c
>> @@ -31,6 +31,32 @@ extern unsigned long kexec_boot_atags;
>>  
>>  static atomic_t waiting_for_crash_ipi;
>>  
>> +/**
>> + * kexec_image_info - For debugging output.
>> + */
>> +#define kexec_image_info(_i) _kexec_image_info(__func__, __LINE__, _i)
>> +static void _kexec_image_info(const char *func, int line,
>> +	const struct kimage *kimage)
>> +{
>> +	unsigned long i;
>> +
>> +	pr_debug("%s:%d:\n", func, line);
>> +	pr_debug("  kexec kimage info:\n");
>> +	pr_debug("    type:        %d\n", kimage->type);
>> +	pr_debug("    start:       %lx\n", kimage->start);
>> +	pr_debug("    head:        %lx\n", kimage->head);
>> +	pr_debug("    nr_segments: %lu\n", kimage->nr_segments);
>> +
>> +	for (i = 0; i < kimage->nr_segments; i++) {
>> +		pr_debug("      segment[%lu]: %08lx - %08lx, 0x%x bytes, %lu pages\n",
>> +			i,
>> +			kimage->segment[i].mem,
>> +			kimage->segment[i].mem + kimage->segment[i].memsz,
>> +			kimage->segment[i].memsz,
>> +			kimage->segment[i].memsz /  PAGE_SIZE);
>> +	}
>> +}
>> +
>>  /*
>>   * Provide a dummy crash_notes definition while crash dump arrives to arm.
>>   * This prevents breakage of crash_notes attribute in kernel/ksysfs.c.
>> @@ -42,6 +68,8 @@ int machine_kexec_prepare(struct kimage *image)
>>  	__be32 header;
>>  	int i, err;
>>  
>> +	kexec_image_info(image);
>> +
>>  	image->arch.kernel_r2 = image->start - KEXEC_ARM_ZIMAGE_OFFSET
>>  				     + KEXEC_ARM_ATAGS_OFFSET;
>>  
>> -- 
>> 2.26.2
>> 
>> 

-- 
Łukasz Stelmach
Samsung R&D Institute Poland
Samsung Electronics

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 487 bytes --]

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

* Re: [PATCH 5/5] arm: kexec_file: load zImage or uImage, initrd and dtb
       [not found]           ` <CGME20200601164700eucas1p2e30af458bae7e820ca55f7936ac3579a@eucas1p2.samsung.com>
@ 2020-06-01 16:46             ` Lukasz Stelmach
  0 siblings, 0 replies; 35+ messages in thread
From: Lukasz Stelmach @ 2020-06-01 16:46 UTC (permalink / raw)
  To: Russell King - ARM Linux admin
  Cc: Kees Cook, Bartlomiej Zolnierkiewicz, Masahiro Yamada,
	Nick Desaulniers, linux-kernel, AKASHI Takahiro, Ben Dooks,
	Thomas Gleixner, Enrico Weigelt, Ingo Molnar, linux-arm-kernel,
	Marek Szyprowski

[-- Attachment #1: Type: text/plain, Size: 1089 bytes --]

It was <2020-06-01 pon 16:14>, when Russell King - ARM Linux admin wrote:
> On Mon, Jun 01, 2020 at 04:07:45PM +0100, Russell King - ARM Linux admin wrote:
>> On Mon, Jun 01, 2020 at 04:27:54PM +0200, Łukasz Stelmach wrote:
>> > diff --git a/arch/arm/kernel/kexec_zimage.c b/arch/arm/kernel/kexec_zimage.c
>> > new file mode 100644
>> > index 000000000000..d09795fc9072
>> > --- /dev/null
>> > +++ b/arch/arm/kernel/kexec_zimage.c
>> > @@ -0,0 +1,199 @@
>> > +// SPDX-License-Identifier: GPL-2.0
>> > +/*
>> > + * Kexec zImage loader
>> > + *
>> > + * Copyright (C) 2020 Samsung Electronics
>> > + * Author: Łukasz Stelmach <l.stelmach@samsung.com>
>> 
>> Please credit me as part author of this - you have taken some of my
>> code from the userspace kexec tool (such as the contents of
>> find_extension_tag()) and copied it in here, so this is not all your
>> own work.
>
> It would also be a very good idea to indicate _where_ you copied some
> of this code from.

Sure thing. Done.

-- 
Łukasz Stelmach
Samsung R&D Institute Poland
Samsung Electronics

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 487 bytes --]

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

* Re: [PATCH 1/5] arm: decompressor: set malloc pool size for the decompressor
       [not found]               ` <CGME20200601165420eucas1p273e0cdb143312b9a621e2444c5daae9b@eucas1p2.samsung.com>
@ 2020-06-01 16:54                 ` Lukasz Stelmach
  0 siblings, 0 replies; 35+ messages in thread
From: Lukasz Stelmach @ 2020-06-01 16:54 UTC (permalink / raw)
  To: Russell King - ARM Linux admin
  Cc: Masahiro Yamada, Nick Desaulniers, Thomas Gleixner,
	Enrico Weigelt, Kees Cook, Ingo Molnar, Ben Dooks,
	linux-arm-kernel, linux-kernel, AKASHI Takahiro,
	Bartlomiej Zolnierkiewicz, Marek Szyprowski

[-- Attachment #1: Type: text/plain, Size: 2817 bytes --]

It was <2020-06-01 pon 16:10>, when Russell King - ARM Linux admin wrote:
> On Mon, Jun 01, 2020 at 04:56:40PM +0200, Lukasz Stelmach wrote:
>> It was <2020-06-01 pon 15:46>, when Russell King - ARM Linux admin wrote:
>> > On Mon, Jun 01, 2020 at 04:27:50PM +0200, Łukasz Stelmach wrote:
>> >> Move the definition of malloc pool size of the decompressor to
>> >> a single place. This value will be exposed later for kexec_file loader.
>> >> 
>> >> Signed-off-by: Łukasz Stelmach <l.stelmach@samsung.com>
>> >> ---
>> >>  arch/arm/boot/compressed/Makefile | 2 ++
>> >>  arch/arm/boot/compressed/head.S   | 6 ++++--
>> >>  2 files changed, 6 insertions(+), 2 deletions(-)
>> >> 
>> >> diff --git a/arch/arm/boot/compressed/Makefile b/arch/arm/boot/compressed/Makefile
>> >> index 9c11e7490292..b3594cd1588c 100644
>> >> --- a/arch/arm/boot/compressed/Makefile
>> >> +++ b/arch/arm/boot/compressed/Makefile
>> >> @@ -125,6 +125,8 @@ KBSS_SZ = $(shell echo $$(($$($(NM) $(obj)/../../../../vmlinux | \
>> >>  		sed -n -e 's/^\([^ ]*\) [AB] __bss_start$$/-0x\1/p' \
>> >>  		       -e 's/^\([^ ]*\) [AB] __bss_stop$$/+0x\1/p') )) )
>> >>  LDFLAGS_vmlinux = --defsym _kernel_bss_size=$(KBSS_SZ)
>> >> +# malloc pool size
>> >> +LDFLAGS_vmlinux += --defsym _malloc_size=0x10000
>> >>  # Supply ZRELADDR to the decompressor via a linker symbol.
>> >>  ifneq ($(CONFIG_AUTO_ZRELADDR),y)
>> >>  LDFLAGS_vmlinux += --defsym zreladdr=$(ZRELADDR)
>> >> diff --git a/arch/arm/boot/compressed/head.S b/arch/arm/boot/compressed/head.S
>> >> index e8e1c866e413..dcc1afa60fb9 100644
>> >> --- a/arch/arm/boot/compressed/head.S
>> >> +++ b/arch/arm/boot/compressed/head.S
>> >> @@ -309,7 +309,8 @@ restart:	adr	r0, LC0
>> >>  #ifndef CONFIG_ZBOOT_ROM
>> >>  		/* malloc space is above the relocated stack (64k max) */
>> >>  		add	sp, sp, r0
>> >> -		add	r10, sp, #0x10000
>> >> +		ldr	r10, =_malloc_size
>> >> +		add	r10, r10, sp
>> >
>> > This says "locate _malloc_size in a literal pool somewhere, and load it
>> > using a PC-relative offset".  Are you sure that the literal pool is
>> > sensibly located?
>> >
>> > Would it be better to use a definition for this?
>> 
>> I've followed ZRELADDR way. I think both values should be handled the
>> same way (it makes it easier to comprehend IMHO). Is there any reason
>> not to?  Should I change ZRELADDR for v2 too?
>
> There's a good reason.  ZRELADDR can be a constant that does not fit
> into the ARMs immediate constants (8 bits of significant data plus
> a multiple of a 2-bit shift), whereas the size of the malloc space
> is guaranteed to fit.  So, ZRELADDR has to use a literal load.
> This doesn't.

Indeed this is how TEXT_OFFSET works. Done.

-- 
Łukasz Stelmach
Samsung R&D Institute Poland
Samsung Electronics

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 487 bytes --]

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

* Re: [PATCH 3/5] arm: decompressor: define a new zImage tag
  2020-06-01 16:19           ` Lukasz Stelmach
@ 2020-06-01 18:25             ` Russell King - ARM Linux admin
       [not found]               ` <CGME20200601202757eucas1p11d380be9e0b2fe912a358d21e2d8dc2a@eucas1p1.samsung.com>
  0 siblings, 1 reply; 35+ messages in thread
From: Russell King - ARM Linux admin @ 2020-06-01 18:25 UTC (permalink / raw)
  To: Lukasz Stelmach
  Cc: Masahiro Yamada, Nick Desaulniers, Thomas Gleixner,
	Enrico Weigelt, Kees Cook, Ingo Molnar, Ben Dooks,
	linux-arm-kernel, linux-kernel, AKASHI Takahiro,
	Bartlomiej Zolnierkiewicz, Marek Szyprowski

On Mon, Jun 01, 2020 at 06:19:52PM +0200, Lukasz Stelmach wrote:
> It was <2020-06-01 pon 15:55>, when Russell King - ARM Linux admin wrote:
> > On Mon, Jun 01, 2020 at 04:27:52PM +0200, Łukasz Stelmach wrote:
> >> Add DCSZ tag which holds dynamic memory (stack, bss, malloc pool)
> >> requirements of the decompressor code.
> >
> > Why do we need to know the stack and BSS size, when the userspace
> > kexec tool doesn't need to know this to perform the same function.
> 
> 
> kexec-tools load zImage as low in DRAM as possible and rely on two
> assumptions:
> 
>     + the zImage will copy itself to make enough room for the kernel,
>     + sizeof(zImage+mem) < sizeof(kernel+mem), which is true because
>       of compression.
> 
>        DRAM start
>        + 0x8000
> 
> zImage    |-----------|-----|-------|
>             text+data   bss   stack 
> 
>                  text+data           bss   
> kernel    |---------------------|-------------------|
> 
> 
> initrd                                              |-initrd-|-dtb-|

This is actually incorrect, because the decompressor will self-
relocate itself to avoid the area that it is going to decompress
into.  So, while the decompressor runs, in the above situation it
ends up as:


ram    |------------------------------------------------------...
                 text+data           bss   
kernel    |---------------------|-------------------|
zImage                          |-----------|-----|-------|
                                  text+data   bss   stack+malloc

Where "text+data" is actually smaller than the image size that
was loaded - the part of the image that performs the relocation
is discarded (the first chunk of code up to "restart" - 200
bytes.)  The BSS is typically smaller than 200 bytes, so we've
been able to get away without knowing the actual BSS size so
far.


ram    |--|-----------------------------------------|---------...
       |<>| TEXT_OFFSET
kernel    |---------------------|-------------------|
          |<----edata_size----->|<-----bss_size---->|
          |<---------------kernel_size------------->|
zImage                          |-----------|-----|-------|
                                |<-------len------->| (initial)
				|<----------len------------>| (final)

The "final" len value is what the decompressor prints as the "zImage
requires" debugging value.

Hence, the size that the decompressed kernel requires is kernel_size.

The size that the decompressor requires is edata_size + len(final).

Now, if you intend to load the kernel to ram + TEXT_OFFSET + edata_size
then it isn't going to lose the first 200 bytes of code, so as you
correctly point out, we need to know the BSS size.

> >> +struct arm_zimage_tag_dc {
> >> +	struct tag_header hdr;
> >> +	union {
> >> +#define ZIMAGE_TAG_DECOMP_SIZE ARM_ZIMAGE_MAGIC4
> >> +		struct zimage_decomp_size {
> >> +			__le32 bss_size;
> >> +			__le32 stack_size;
> >> +			__le32 malloc_size;
> >> +		} decomp_size;

You certainly don't need to know all this.  All you need to know is
how much space the decompressor requires after the end of the image,
encompassing the BSS size, stack size and malloc size, which is one
value.

-- 
RMK's Patch system: https://www.armlinux.org.uk/developer/patches/
FTTC for 0.8m (est. 1762m) line in suburbia: sync at 13.1Mbps down 424kbps up

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

* Re: [PATCH 5/5] arm: kexec_file: load zImage or uImage, initrd and dtb
       [not found]         ` <CGME20200601184829eucas1p1b06bfc130083f6248d624febed1de9fc@eucas1p1.samsung.com>
@ 2020-06-01 18:48           ` Lukasz Stelmach
  0 siblings, 0 replies; 35+ messages in thread
From: Lukasz Stelmach @ 2020-06-01 18:48 UTC (permalink / raw)
  To: Russell King - ARM Linux admin
  Cc: Masahiro Yamada, Nick Desaulniers, Thomas Gleixner,
	Enrico Weigelt, Kees Cook, Ingo Molnar, Ben Dooks,
	linux-arm-kernel, linux-kernel, AKASHI Takahiro,
	Bartlomiej Zolnierkiewicz, Marek Szyprowski

[-- Attachment #1: Type: text/plain, Size: 14891 bytes --]

It was <2020-06-01 pon 16:07>, when Russell King - ARM Linux admin wrote:
> On Mon, Jun 01, 2020 at 04:27:54PM +0200, Łukasz Stelmach wrote:
>> This is kexec_file_load implementation for ARM. It loads zImage and
>> initrd from file descripters and resuses DTB.
>> 
>> Most code is derived from arm64 kexec_file_load implementation
>> and from kexec-tools.
>
> Please make the uImage loader able to be configured out of the
> kernel; it's a legacy image format now, and some of us just don't
> use it anymore.  That way, those who wish to have it can, and
> those who wish not to can have a smaller kernel.

The difference in size of arch/arm/boot/Image is 160 bytes, but
OK. Done.

>> Cc: AKASHI Takahiro <takahiro.akashi@linaro.org>
>> Signed-off-by: Łukasz Stelmach <l.stelmach@samsung.com>
>> ---
>>  arch/arm/Kconfig                     |  15 ++
>>  arch/arm/include/asm/image.h         |  26 ++++
>>  arch/arm/include/asm/kexec.h         |  14 ++
>>  arch/arm/kernel/Makefile             |   5 +-
>>  arch/arm/kernel/kexec_uimage.c       |  80 ++++++++++
>>  arch/arm/kernel/kexec_zimage.c       | 199 +++++++++++++++++++++++++
>>  arch/arm/kernel/machine_kexec.c      |  11 +-
>>  arch/arm/kernel/machine_kexec_file.c | 209 +++++++++++++++++++++++++++
>>  8 files changed, 554 insertions(+), 5 deletions(-)
>>  create mode 100644 arch/arm/kernel/kexec_uimage.c
>>  create mode 100644 arch/arm/kernel/kexec_zimage.c
>>  create mode 100644 arch/arm/kernel/machine_kexec_file.c
>> 
>> diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
>> index c77c93c485a0..6adb849cb304 100644
>> --- a/arch/arm/Kconfig
>> +++ b/arch/arm/Kconfig
>> @@ -1917,6 +1917,21 @@ config KEXEC
>>  	  is properly shutdown, so do not be surprised if this code does not
>>  	  initially work for you.
>>  
>> +config KEXEC_FILE
>> +	bool "Kexec file based system call (EXPERIMENTAL)"
>> +	depends on (!SMP || PM_SLEEP_SMP)
>> +	depends on USE_OF
>> +	select KEXEC_CORE
>> +	select CRC32
>> +	help
>> +	  This is new version of kexec system call. This system call is
>> +	  file based and takes file descriptors as system call argument
>> +	  for kernel and initramfs as opposed to list of segments as
>> +	  accepted by previous system call.
>> +
>> +	  The kernel to be loaded MUST support Flattened Device Tree
>> +	  (selected with CONFIG_USE_OF).
>> +
>>  config ATAGS_PROC
>>  	bool "Export atags in procfs"
>>  	depends on ATAGS && KEXEC
>> diff --git a/arch/arm/include/asm/image.h b/arch/arm/include/asm/image.h
>> index 624438740f23..95f23837b04f 100644
>> --- a/arch/arm/include/asm/image.h
>> +++ b/arch/arm/include/asm/image.h
>> @@ -8,8 +8,13 @@
>>  			 (((x) >>  8) & 0x0000ff00) |  \
>>  			 (((x) <<  8) & 0x00ff0000) |  \
>>  			 (((x) << 24) & 0xff000000))
>> +#define UIMAGE_MAGIC(x) (x)
>>  #else
>>  #define ZIMAGE_MAGIC(x) (x)
>> +#define UIMAGE_MAGIC(x) ((((x) >> 24) & 0x000000ff) | \
>> +			 (((x) >>  8) & 0x0000ff00) |  \
>> +			 (((x) <<  8) & 0x00ff0000) |  \
>> +			 (((x) << 24) & 0xff000000))
>>  #endif
>>  
>>  #define ARM_ZIMAGE_MAGIC1 ZIMAGE_MAGIC(0x016f2818)
>> @@ -17,6 +22,12 @@
>>  #define ARM_ZIMAGE_MAGIC3 ZIMAGE_MAGIC(0x5a534c4b)
>>  #define ARM_ZIMAGE_MAGIC4 ZIMAGE_MAGIC(0x5a534344)
>>  
>> +#define ARM_UIMAGE_MAGIC UIMAGE_MAGIC(0x27051956)
>> +#define ARM_UIMAGE_NAME_LEN		32
>> +#define ARM_UIMAGE_TYPE_KERNEL		2
>> +#define ARM_UIMAGE_TYPE_KERNEL_NOLOAD	14
>> +#define ARM_UIMAGE_ARCH_ARM		2
>> +
>>  #ifndef __ASSEMBLY__
>>  
>>  #include <linux/types.h>
>> @@ -33,6 +44,21 @@ struct arm_zimage_header {
>>  	__le32 extension_tag_offset;
>>  };
>>  
>> +struct arm_uimage_header {
>> +	__be32 magic;
>> +	__be32 hdr_crc;
>> +	__be32 time;
>> +	__be32 size;
>> +	__be32 load;
>> +	__be32 entry;
>> +	__be32 crc;
>> +	__u8   os;
>> +	__u8   arch;
>> +	__u8   type;
>> +	__u8   comp;
>> +	__u8   name[ARM_UIMAGE_NAME_LEN];
>> +};
>> +
>>  struct arm_zimage_tag {
>>  	struct tag_header hdr;
>>  	union {
>> diff --git a/arch/arm/include/asm/kexec.h b/arch/arm/include/asm/kexec.h
>> index 22751b5b5735..fda35afa7195 100644
>> --- a/arch/arm/include/asm/kexec.h
>> +++ b/arch/arm/include/asm/kexec.h
>> @@ -83,6 +83,20 @@ static inline struct page *boot_pfn_to_page(unsigned long boot_pfn)
>>  }
>>  #define boot_pfn_to_page boot_pfn_to_page
>>  
>> +#ifdef CONFIG_KEXEC_FILE
>> +
>> +extern const struct kexec_file_ops kexec_zimage_ops;
>> +extern const struct kexec_file_ops kexec_uimage_ops;
>> +
>> +struct kimage;
>> +
>> +extern int load_other_segments(struct kimage *image,
>> +		unsigned long kernel_load_addr, unsigned long kernel_size,
>> +		char *initrd, unsigned long initrd_len,
>> +		unsigned long initrd_offset, char *cmdline);
>> +
>> +#endif /* CONFIG_KEXEC_FILE */
>> +
>>  #endif /* __ASSEMBLY__ */
>>  
>>  #endif /* CONFIG_KEXEC */
>> diff --git a/arch/arm/kernel/Makefile b/arch/arm/kernel/Makefile
>> index 89e5d864e923..466c683bb551 100644
>> --- a/arch/arm/kernel/Makefile
>> +++ b/arch/arm/kernel/Makefile
>> @@ -3,6 +3,7 @@
>>  # Makefile for the linux kernel.
>>  #
>>  
>> +CFLAGS_kexec_zimage.o := -DTEXT_OFFSET=$(TEXT_OFFSET)
>>  CPPFLAGS_vmlinux.lds := -DTEXT_OFFSET=$(TEXT_OFFSET)
>>  AFLAGS_head.o        := -DTEXT_OFFSET=$(TEXT_OFFSET)
>>  
>> @@ -56,7 +57,9 @@ obj-$(CONFIG_FUNCTION_TRACER)	+= entry-ftrace.o
>>  obj-$(CONFIG_DYNAMIC_FTRACE)	+= ftrace.o insn.o patch.o
>>  obj-$(CONFIG_FUNCTION_GRAPH_TRACER)	+= ftrace.o insn.o patch.o
>>  obj-$(CONFIG_JUMP_LABEL)	+= jump_label.o insn.o patch.o
>> -obj-$(CONFIG_KEXEC)		+= machine_kexec.o relocate_kernel.o
>> +obj-$(CONFIG_KEXEC_CORE)	+= machine_kexec.o relocate_kernel.o
>> +obj-$(CONFIG_KEXEC_FILE)	+= machine_kexec_file.o kexec_zimage.o	\
>> +				   kexec_uimage.o
>>  # Main staffs in KPROBES are in arch/arm/probes/ .
>>  obj-$(CONFIG_KPROBES)		+= patch.o insn.o
>>  obj-$(CONFIG_OABI_COMPAT)	+= sys_oabi-compat.o
>> diff --git a/arch/arm/kernel/kexec_uimage.c b/arch/arm/kernel/kexec_uimage.c
>> new file mode 100644
>> index 000000000000..47033574e24e
>> --- /dev/null
>> +++ b/arch/arm/kernel/kexec_uimage.c
>> @@ -0,0 +1,80 @@
>> +// SPDX-License-Identifier: GPL-2.0
>> +/*
>> + * Kexec uImage loader
>> + *
>> + * Copyright (C) 2020 Samsung Electronics
>> + * Author: Łukasz Stelmach <l.stelmach@samsung.com>
>> + */
>> +
>> +#define pr_fmt(fmt)	"kexec_file(uImage): " fmt
>> +
>> +#include <asm/image.h>
>> +#include <linux/crc32.h>
>> +#include <linux/err.h>
>> +#include <linux/kexec.h>
>> +
>> +#define crc32_ones(crc, buf, len) \
>> +	(crc32(crc ^ 0xffffffff, buf, len) ^ 0xffffffff)
>> +
>> +static int uimage_probe(const char *uimage_buf, unsigned long uimage_len)
>> +{
>> +	const struct arm_uimage_header *h =
>> +		(struct arm_uimage_header *) uimage_buf;
>> +	struct arm_uimage_header uhdr;
>> +	unsigned long zoff = sizeof(struct arm_uimage_header);
>> +	uint32_t crc;
>> +
>> +	if (h->magic != ARM_UIMAGE_MAGIC)
>> +		return -EINVAL;
>> +
>> +	if (h->type != ARM_UIMAGE_TYPE_KERNEL &&
>> +	    h->type != ARM_UIMAGE_TYPE_KERNEL_NOLOAD){
>> +		pr_debug("Invalid image type: %d\n", h->type);
>> +		return -EINVAL;
>> +	}
>> +
>> +	if (h->arch != ARM_UIMAGE_ARCH_ARM) {
>> +		pr_debug("Invalidy image arch: %d\n", h->arch);
>> +		return -EINVAL;
>> +	}
>> +
>> +	memcpy((char *)&uhdr, h, sizeof(uhdr));
>> +	crc = be32_to_cpu(uhdr.hdr_crc);
>> +	uhdr.hdr_crc = 0;
>> +
>> +	if (crc32_ones(0, (char *)&uhdr, sizeof(uhdr)) != crc) {
>> +		pr_debug("Corrupt header, CRC do not match\n");
>> +		return -EINVAL;
>> +	}
>> +
>> +	crc = be32_to_cpu(uhdr.crc);
>> +	if (crc32_ones(0, uimage_buf + zoff, uimage_len - zoff) != crc) {
>> +		pr_debug("Corrupt zImage, CRC do not match\n");
>> +		return -EINVAL;
>> +	}
>> +
>> +	return kexec_zimage_ops.probe(uimage_buf + zoff,
>> +				      uimage_len - zoff);
>> +}
>> +
>> +static void *uimage_load(struct kimage *image,
>> +				char *uimage, unsigned long uimage_len,
>> +				char *initrd, unsigned long initrd_len,
>> +				char *cmdline, unsigned long cmdline_len)
>> +{
>> +	const struct arm_uimage_header *h =
>> +		(struct arm_uimage_header *) uimage;
>> +	unsigned long zimage_offset = sizeof(struct arm_uimage_header);
>> +
>> +	pr_debug("Loading uImage");
>> +	return kexec_zimage_ops.load(image,
>> +				     uimage + zimage_offset,
>> +				     uimage_len - zimage_offset,
>> +				     initrd, initrd_len,
>> +				     cmdline, cmdline_len);
>> +}
>> +
>> +const struct kexec_file_ops kexec_uimage_ops = {
>> +	.probe = uimage_probe,
>> +	.load = uimage_load,
>> +};
>> diff --git a/arch/arm/kernel/kexec_zimage.c b/arch/arm/kernel/kexec_zimage.c
>> new file mode 100644
>> index 000000000000..d09795fc9072
>> --- /dev/null
>> +++ b/arch/arm/kernel/kexec_zimage.c
>> @@ -0,0 +1,199 @@
>> +// SPDX-License-Identifier: GPL-2.0
>> +/*
>> + * Kexec zImage loader
>> + *
>> + * Copyright (C) 2020 Samsung Electronics
>> + * Author: Łukasz Stelmach <l.stelmach@samsung.com>
>
> Please credit me as part author of this - you have taken some of my
> code from the userspace kexec tool (such as the contents of
> find_extension_tag()) and copied it in here, so this is not all your
> own work.

Done.

>> + */
>> +
>> +#define pr_fmt(fmt)	"kexec_file(zImage): " fmt
>> +
>> +#include <asm/image.h>
>> +#include <asm/unaligned.h>
>> +#include <linux/err.h>
>> +#include <linux/kexec.h>
>> +#include <linux/memblock.h>
>> +
>> +#define byte_size(t)    ((t)->hdr.size << 2)
>> +
>> +static const void *find_extension_tag(const char *buf,
>> +						       unsigned long len,
>> +						       uint32_t tag_id)
>> +{
>> +	const struct arm_zimage_header *h = (const struct arm_zimage_header *)buf;
>> +	const struct arm_zimage_tag *tag;
>> +	uint32_t offset, size;
>> +	uint32_t max = len - sizeof(struct tag_header);
>> +
>> +	if (len < sizeof(*h) ||
>> +	    h->magic != ARM_ZIMAGE_MAGIC1 ||
>> +	    h->magic2 != ARM_ZIMAGE_MAGIC2)
>> +		return NULL;
>> +
>> +	for (offset = h->extension_tag_offset;
>> +	     (tag = (void *)(buf + offset)) != NULL &&
>> +		     offset < max &&
>> +		     (size = le32_to_cpu(byte_size(tag))) != 0 &&
>> +		     offset + size < len;
>> +	     offset += size) {
>> +		pr_debug("  offset 0x%08x tag 0x%08x size %u\n",
>> +			  offset, le32_to_cpu(tag->hdr.tag), size);
>> +		if (tag->hdr.tag == tag_id)
>> +			return tag;
>> +	}
>> +
>> +	return NULL;
>> +}
>> +
>> +static int zimage_probe(const char *kernel_buf, unsigned long kernel_len)
>> +{
>> +	const struct arm_zimage_header *h =
>> +		(struct arm_zimage_header *)(kernel_buf);
>> +
>> +	if (!h || (kernel_len < sizeof(*h)))
>> +		return -EINVAL;
>> +
>> +	if ((h->magic != ARM_ZIMAGE_MAGIC1) ||
>> +	    (h->magic2 != ARM_ZIMAGE_MAGIC2))
>> +		return -EINVAL;
>> +
>> +	return 0;
>> +}
>> +
>> +
>> +#if defined(DEBUG)
>> +#define debug_offsets() ({			\
>> +	pr_debug("Image offsets:\n");		\
>> +	pr_debug("  kernel 0x%08lx 0x%08lx\n", kernel_offset, kernel_len); \
>> +	pr_debug("  zimage 0x%08lx 0x%08lx\n", zimage_offset, zimage_len); \
>> +	pr_debug("  initrd 0x%08lx 0x%08lx\n", initrd_offset, initrd_len); \
>> +})
>> +#else
>> +#define debug_offsets()
>> +#endif
>> +
>> +static void *zimage_load(struct kimage *image,
>> +				char *zimage, unsigned long zimage_len,
>> +				char *initrd, unsigned long initrd_len,
>> +				char *cmdline, unsigned long cmdline_len)
>> +{
>> +	struct arm_zimage_header *h;
>> +	struct kexec_buf kbuf;
>> +	struct kexec_segment *zimage_segment;
>> +	const struct arm_zimage_tag *klsz_tag;
>> +	const struct arm_zimage_tag_dc *dcsz_tag;
>> +	int ret = -EINVAL;
>> +
>> +	unsigned long zimage_mem = 0x20000; /* malloc 64kB + stack 4 kB + some bss */
>> +	unsigned long kernel_len = zimage_len * 4; /* 4:1 compression */
>
> This has been proven wrong.

5:1? The comment and the code in kexec-tools are inconsisten in this
regard. The comment says 4:1, but the code multiplies by 5. Your
recommendation? This value is used as a fallback anyway in a very
unlikely case, when tags are missing (see below).

>> +	unsigned long kernel_offset = memblock_start_of_DRAM() +
>> +		ALIGN(TEXT_OFFSET, PAGE_SIZE);
>
> TEXT_OFFSET is actually a property of the loaded kernel, not of the
> currently running kernel.

Indeed.

> I have a patch to add that into the zImage tag.

I am afraid, I haven't seen it before. Where can I find it?

>> +	unsigned long zimage_offset = kernel_offset +
>> +		ALIGN(kernel_len, PAGE_SIZE);
>> +	unsigned long initrd_offset = zimage_offset +
>> +		ALIGN(zimage_len + zimage_mem, PAGE_SIZE);
>
> Since kernel_len is wrong, these will be wrong... please only fall
> back to this if you don't find the extension tag - in other words,
> declare the variables here, but don't initialise them, set them
> lower down in the file if we fail to find the extension tag.

That is how it works now. This is the structure I have taken from
kexec-tools: initialize and change if additional information is
available. If the tags are not available use these values as a fallback.

>> +
>> +	if (image->type == KEXEC_TYPE_CRASH) {
>> +		kernel_offset += crashk_res.start;
>> +		zimage_offset += crashk_res.start;
>> +		initrd_offset += crashk_res.start;
>> +	}
>> +	debug_offsets();
>> +
>> +	h = (struct arm_zimage_header *)zimage;
>> +
>> +	klsz_tag = find_extension_tag(zimage, zimage_len, ZIMAGE_TAG_KRNL_SIZE);
>> +	if (klsz_tag) {
>> +		uint32_t *p = (void *)zimage +
>> +			le32_to_cpu(klsz_tag->u.krnl_size.size_ptr);
>> +		uint32_t edata_size = le32_to_cpu(get_unaligned(p));
>> +		uint32_t bss_size = le32_to_cpu(klsz_tag->u.krnl_size.bss_size);
>> +
>> +		kernel_len = edata_size + bss_size;
>> +
>> +		pr_debug("Decompressed kernel sizes:\n");
>> +		pr_debug(" text+data 0x%08lx bss 0x%08lx total 0x%08lx\n",
>> +			 (unsigned long)edata_size,
>> +			 (unsigned long)bss_size,
>> +			 (unsigned long)kernel_len);
>> +
>> +		zimage_offset = kernel_offset + ALIGN(edata_size, PAGE_SIZE);
>> +		initrd_offset = zimage_offset +
>> +			max(ALIGN(zimage_len + 0x20000, PAGE_SIZE),
>> +			    ALIGN((unsigned long)bss_size, PAGE_SIZE));
>> +		debug_offsets();
>
> This looks incorrect to me.  Please see the kexec tool - what its doing
> in its corresponding section that you copied some of this code from is
> carefully thought out and can't be simplified.  Ergo, I think this is
> wrong.

As I explained in <dleftjwo4qsqqf.fsf%l.stelmach@samsung.com> my
approach is slightly different. I am trying to avoid copying zImage by
putting it hight enough in the first place.


Kind regards,
-- 
Łukasz Stelmach
Samsung R&D Institute Poland
Samsung Electronics

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 487 bytes --]

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

* Re: [PATCH 3/5] arm: decompressor: define a new zImage tag
       [not found]               ` <CGME20200601202757eucas1p11d380be9e0b2fe912a358d21e2d8dc2a@eucas1p1.samsung.com>
@ 2020-06-01 20:27                 ` Lukasz Stelmach
  2020-06-01 20:41                   ` Russell King - ARM Linux admin
  0 siblings, 1 reply; 35+ messages in thread
From: Lukasz Stelmach @ 2020-06-01 20:27 UTC (permalink / raw)
  To: Russell King - ARM Linux admin
  Cc: Masahiro Yamada, Nick Desaulniers, Thomas Gleixner,
	Enrico Weigelt, Kees Cook, Ingo Molnar, Ben Dooks,
	linux-arm-kernel, linux-kernel, AKASHI Takahiro,
	Bartlomiej Zolnierkiewicz, Marek Szyprowski

[-- Attachment #1: Type: text/plain, Size: 4504 bytes --]

It was <2020-06-01 pon 19:25>, when Russell King - ARM Linux admin wrote:
> On Mon, Jun 01, 2020 at 06:19:52PM +0200, Lukasz Stelmach wrote:
>> It was <2020-06-01 pon 15:55>, when Russell King - ARM Linux admin wrote:
>> > On Mon, Jun 01, 2020 at 04:27:52PM +0200, Łukasz Stelmach wrote:
>> >> Add DCSZ tag which holds dynamic memory (stack, bss, malloc pool)
>> >> requirements of the decompressor code.
>> >
>> > Why do we need to know the stack and BSS size, when the userspace
>> > kexec tool doesn't need to know this to perform the same function.
>> 
>> 
>> kexec-tools load zImage as low in DRAM as possible and rely on two
>> assumptions:
>> 
>>     + the zImage will copy itself to make enough room for the kernel,
>>     + sizeof(zImage+mem) < sizeof(kernel+mem), which is true because
>>       of compression.
>> 
>>        DRAM start
>>        + 0x8000
>> 
>> zImage    |-----------|-----|-------|
>>             text+data   bss   stack 
>> 
>>                  text+data           bss   
>> kernel    |---------------------|-------------------|
>> 
>> 
>> initrd                                              |-initrd-|-dtb-|
>
> This is actually incorrect, because the decompressor will self-
> relocate itself to avoid the area that it is going to decompress
> into.

I described the state right after kexec(8) invocation.

> So, while the decompressor runs, in the above situation it
> ends up as:
>
>
> ram    |------------------------------------------------------...
>                  text+data           bss   
> kernel    |---------------------|-------------------|
> zImage                          |-----------|-----|-------|
>                                   text+data   bss   stack+malloc

And I am trying to achieve this state before the decompressor starts so
it won't need to copy itself during boot. The only exception is (as we
discussed under a different patch) when edata_size >= 128-eps MiB because
loading zImage above 128 MiB prevents it from properly detecting
physical memory. In such unlikely case my code behaves like kexec-tools
and loads zImage low. That is why I suggested that passing detailed
information about memory layout to the decompressor would help.

> Where "text+data" is actually smaller than the image size that
> was loaded - the part of the image that performs the relocation
> is discarded (the first chunk of code up to "restart" - 200
> bytes.)  The BSS is typically smaller than 200 bytes, so we've
> been able to get away without knowing the actual BSS size so
> far.
>
>
> ram    |--|-----------------------------------------|---------...
>        |<>| TEXT_OFFSET
> kernel    |---------------------|-------------------|
>           |<----edata_size----->|<-----bss_size---->|
>           |<---------------kernel_size------------->|
> zImage                          |-----------|-----|-------|
>                                 |<-------len------->| (initial)
> 				|<----------len------------>| (final)
>
> The "final" len value is what the decompressor prints as the "zImage
> requires" debugging value.
>
> Hence, the size that the decompressed kernel requires is kernel_size.
>
> The size that the decompressor requires is edata_size + len(final).
>
> Now, if you intend to load the kernel to ram + TEXT_OFFSET + edata_size
> then it isn't going to lose the first 200 bytes of code, so as you
> correctly point out, we need to know the BSS size.

Formal note: can we keep using terms zImage and kernel as separate,
where zImage is what is loaded with kexec and kernel is the decompressed
code loaded at TEXT_OFFSET. I believe, it will help us avoid mistakes.

>> >> +struct arm_zimage_tag_dc {
>> >> +	struct tag_header hdr;
>> >> +	union {
>> >> +#define ZIMAGE_TAG_DECOMP_SIZE ARM_ZIMAGE_MAGIC4
>> >> +		struct zimage_decomp_size {
>> >> +			__le32 bss_size;
>> >> +			__le32 stack_size;
>> >> +			__le32 malloc_size;
>> >> +		} decomp_size;
>
> You certainly don't need to know all this.  All you need to know is
> how much space the decompressor requires after the end of the image,
> encompassing the BSS size, stack size and malloc size, which is one
> value.

I agree. However, since we are not fighting here for every single byte,
I'd rather add them as separate values and make the tag, even if only
slightly, more future-proof.

Kind regards,
-- 
Łukasz Stelmach
Samsung R&D Institute Poland
Samsung Electronics

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 487 bytes --]

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

* Re: [PATCH 3/5] arm: decompressor: define a new zImage tag
  2020-06-01 20:27                 ` Lukasz Stelmach
@ 2020-06-01 20:41                   ` Russell King - ARM Linux admin
       [not found]                     ` <CGME20200602161720eucas1p257e9e892ed4679ed1d168db34d089a82@eucas1p2.samsung.com>
  0 siblings, 1 reply; 35+ messages in thread
From: Russell King - ARM Linux admin @ 2020-06-01 20:41 UTC (permalink / raw)
  To: Lukasz Stelmach
  Cc: Masahiro Yamada, Nick Desaulniers, Thomas Gleixner,
	Enrico Weigelt, Kees Cook, Ingo Molnar, Ben Dooks,
	linux-arm-kernel, linux-kernel, AKASHI Takahiro,
	Bartlomiej Zolnierkiewicz, Marek Szyprowski

On Mon, Jun 01, 2020 at 10:27:45PM +0200, Lukasz Stelmach wrote:
> It was <2020-06-01 pon 19:25>, when Russell King - ARM Linux admin wrote:
> > On Mon, Jun 01, 2020 at 06:19:52PM +0200, Lukasz Stelmach wrote:
> >> It was <2020-06-01 pon 15:55>, when Russell King - ARM Linux admin wrote:
> >> > On Mon, Jun 01, 2020 at 04:27:52PM +0200, Łukasz Stelmach wrote:
> >> >> Add DCSZ tag which holds dynamic memory (stack, bss, malloc pool)
> >> >> requirements of the decompressor code.
> >> >
> >> > Why do we need to know the stack and BSS size, when the userspace
> >> > kexec tool doesn't need to know this to perform the same function.
> >> 
> >> 
> >> kexec-tools load zImage as low in DRAM as possible and rely on two
> >> assumptions:
> >> 
> >>     + the zImage will copy itself to make enough room for the kernel,
> >>     + sizeof(zImage+mem) < sizeof(kernel+mem), which is true because
> >>       of compression.
> >> 
> >>        DRAM start
> >>        + 0x8000
> >> 
> >> zImage    |-----------|-----|-------|
> >>             text+data   bss   stack 
> >> 
> >>                  text+data           bss   
> >> kernel    |---------------------|-------------------|
> >> 
> >> 
> >> initrd                                              |-initrd-|-dtb-|
> >
> > This is actually incorrect, because the decompressor will self-
> > relocate itself to avoid the area that it is going to decompress
> > into.
> 
> I described the state right after kexec(8) invocation.

Actually, you haven't, because this is _not_ how kexec(8) lays it
out, as I attempted to detail further down in my reply.

> > So, while the decompressor runs, in the above situation it
> > ends up as:
> >
> >
> > ram    |------------------------------------------------------...
> >                  text+data           bss   
> > kernel    |---------------------|-------------------|
> > zImage                          |-----------|-----|-------|
> >                                   text+data   bss   stack+malloc

Note here - if the initrd was placed as _you_ describe at the end
of where the zImage ends up including its BSS, it would be
corrupted by the stack and malloc space of the decompressor while
running.  Ergo, your description of how kexec(8) lays stuff out
is incorrect.

> > Where "text+data" is actually smaller than the image size that
> > was loaded - the part of the image that performs the relocation
> > is discarded (the first chunk of code up to "restart" - 200
> > bytes.)  The BSS is typically smaller than 200 bytes, so we've
> > been able to get away without knowing the actual BSS size so
> > far.
> >
> >
> > ram    |--|-----------------------------------------|---------...
> >        |<>| TEXT_OFFSET
> > kernel    |---------------------|-------------------|
> >           |<----edata_size----->|<-----bss_size---->|
> >           |<---------------kernel_size------------->|
> > zImage                          |-----------|-----|-------|
> >                                 |<-------len------->| (initial)
> > 				|<----------len------------>| (final)
> >
> > The "final" len value is what the decompressor prints as the "zImage
> > requires" debugging value.
> >
> > Hence, the size that the decompressed kernel requires is kernel_size.
> >
> > The size that the decompressor requires is edata_size + len(final).
> >
> > Now, if you intend to load the kernel to ram + TEXT_OFFSET + edata_size
> > then it isn't going to lose the first 200 bytes of code, so as you
> > correctly point out, we need to know the BSS size.
> 
> Formal note: can we keep using terms zImage and kernel as separate,
> where zImage is what is loaded with kexec and kernel is the decompressed
> code loaded at TEXT_OFFSET. I believe, it will help us avoid mistakes.
> 
> >> >> +struct arm_zimage_tag_dc {
> >> >> +	struct tag_header hdr;
> >> >> +	union {
> >> >> +#define ZIMAGE_TAG_DECOMP_SIZE ARM_ZIMAGE_MAGIC4
> >> >> +		struct zimage_decomp_size {
> >> >> +			__le32 bss_size;
> >> >> +			__le32 stack_size;
> >> >> +			__le32 malloc_size;
> >> >> +		} decomp_size;
> >
> > You certainly don't need to know all this.  All you need to know is
> > how much space the decompressor requires after the end of the image,
> > encompassing the BSS size, stack size and malloc size, which is one
> > value.
> 
> I agree. However, since we are not fighting here for every single byte,
> I'd rather add them as separate values and make the tag, even if only
> slightly, more future-proof.

It doesn't make it more future-proof.  What happens if we add something
else, do we need to list it separately, and then change the kernel to
accept the new value and maybe also kexec(8)?  Or do we just say "the
decompressor needs X many bytes after the image" and be done with it?
The latter sounds way more future-proof to me.

-- 
RMK's Patch system: https://www.armlinux.org.uk/developer/patches/
FTTC for 0.8m (est. 1762m) line in suburbia: sync at 13.1Mbps down 424kbps up

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

* Re: [PATCH 3/5] arm: decompressor: define a new zImage tag
       [not found]                     ` <CGME20200602161720eucas1p257e9e892ed4679ed1d168db34d089a82@eucas1p2.samsung.com>
@ 2020-06-02 16:17                       ` Lukasz Stelmach
  0 siblings, 0 replies; 35+ messages in thread
From: Lukasz Stelmach @ 2020-06-02 16:17 UTC (permalink / raw)
  To: Russell King - ARM Linux admin
  Cc: Masahiro Yamada, Nick Desaulniers, Thomas Gleixner,
	Enrico Weigelt, Kees Cook, Ingo Molnar, Ben Dooks,
	linux-arm-kernel, linux-kernel, AKASHI Takahiro,
	Bartlomiej Zolnierkiewicz, Marek Szyprowski

[-- Attachment #1: Type: text/plain, Size: 6059 bytes --]

It was <2020-06-01 pon 21:41>, when Russell King - ARM Linux admin wrote:
 > On Mon, Jun 01, 2020 at 10:27:45PM +0200, Lukasz Stelmach wrote:
>> It was <2020-06-01 pon 19:25>, when Russell King - ARM Linux admin wrote:
>>> On Mon, Jun 01, 2020 at 06:19:52PM +0200, Lukasz Stelmach wrote:
>>>> It was <2020-06-01 pon 15:55>, when Russell King - ARM Linux admin wrote:
>>>>> On Mon, Jun 01, 2020 at 04:27:52PM +0200, Łukasz Stelmach wrote:
>>>>>> Add DCSZ tag which holds dynamic memory (stack, bss, malloc pool)
>>>>>> requirements of the decompressor code.
>>>>>
>>>>> Why do we need to know the stack and BSS size, when the userspace
>>>>> kexec tool doesn't need to know this to perform the same function.
>>>> 
>>>> 
>>>> kexec-tools load zImage as low in DRAM as possible and rely on two
>>>> assumptions:
>>>> 
>>>>     + the zImage will copy itself to make enough room for the kernel,
>>>>     + sizeof(zImage+mem) < sizeof(kernel+mem), which is true because
>>>>       of compression.
>>>> 
>>>>        DRAM start
>>>>        + 0x8000
>>>> 
>>>> zImage    |-----------|-----|-------|
>>>>             text+data   bss   stack 
>>>> 
>>>>                  text+data           bss   
>>>> kernel    |---------------------|-------------------|
>>>> 
>>>> 
>>>> initrd                                              |-initrd-|-dtb-|
>>>
>>> This is actually incorrect, because the decompressor will self-
>>> relocate itself to avoid the area that it is going to decompress
>>> into.
>> 
>> I described the state right after kexec(8) invocation.
>
> Actually, you haven't, because this is _not_ how kexec(8) lays it
> out, as I attempted to detail further down in my reply.


Let me try to describe how I understand the code in kexec-tools
(commit 74c7c369).

--8<---------------cut here---------------start------------->8---
int zImage_arm_load(…, const char *buf, off_t len, …)
// buf - zImage
// len - size of zImage
        
unsigned int extra_size = 0x8000; /* TEXT_OFFSET */

kernel_mem_size = len + 4;

// locate a hole to fit zImage + 32kB as low as possible,
base = locate_hole(info, len + extra_size, 0, 0, ULONG_MAX, INT_MAX);

kernel_base = base + extra_size;

add_segment(info, buf, len, kernel_base, kernel_mem_size);
--8<---------------cut here---------------end--------------->8---

Therefore, zImage is loaded low and always requires relocation.
        
ram     |--------------------------------------------------------------
zImage     |----k_m_s----|
           ^
           |
           kernel_base — TEXT_OFFSET or higher

Next goes initrd

--8<---------------cut here---------------start------------->8---
kexec_arm_image_size = len * 5; // or passed on command line

// if the tag exists
kexec_arm_image_size = max(edata_size + bss_size,
                           edata_size + len); // len - zImage size + 64 kB 

initrd_base = kernel_base + _ALIGN(kexec_arm_image_size, page_size);

add_segment(info, ramdisk_buf, initrd_size, initrd_base, initrd_size);
--8<---------------cut here---------------end--------------->8---

above whatever is bigger (kernel + kernel bss) OR (kernel + zImage + zImage mem).


ram     |---------------------------------------------------------------
zImage     |----k_m_s----|                   Where kexec loads zImage @kernel_base

           |.............len * 5....................| Fallback
kernel     |.....edata.....|...bss...|       These are just calculations
zImage                     |.....len+....|   zImage will copy itself here WHEN it runs

initrd                                   |--initrd_size--|
dtb                                      ^               |---|
                                         |
                                 initrd_base

DTB, of course, goes next

    dtb_offset = initrd_base + initrd_size + page_size;


Stuff marked with "-" is actually loaded, "." are just calculations to
establish initrd_base.

>>> So, while the decompressor runs, in the above situation it
>>> ends up as:
>>>
>>>
>>> ram    |------------------------------------------------------...
>>>                  text+data           bss   
>>> kernel    |---------------------|-------------------|
>>> zImage                          |-----------|-----|-------|
>>>                                   text+data   bss   stack+malloc
>
> Note here - if the initrd was placed as _you_ describe at the end
> of where the zImage ends up including its BSS, it would be
> corrupted by the stack and malloc space of the decompressor while
> running.  Ergo, your description of how kexec(8) lays stuff out
> is incorrect.

Is my analysis above accurate now? Do I understand this?

As you noted, my intention is to load zImage after edata (dotted len+
above).

>>>>>> +struct arm_zimage_tag_dc {
>>>>>> +	struct tag_header hdr;
>>>>>> +	union {
>>>>>> +#define ZIMAGE_TAG_DECOMP_SIZE ARM_ZIMAGE_MAGIC4
>>>>>> +		struct zimage_decomp_size {
>>>>>> +			__le32 bss_size;
>>>>>> +			__le32 stack_size;
>>>>>> +			__le32 malloc_size;
>>>>>> +		} decomp_size;
>>>
>>> You certainly don't need to know all this.  All you need to know is
>>> how much space the decompressor requires after the end of the image,
>>> encompassing the BSS size, stack size and malloc size, which is one
>>> value.
>> 
>> I agree. However, since we are not fighting here for every single byte,
>> I'd rather add them as separate values and make the tag, even if only
>> slightly, more future-proof.
>
> It doesn't make it more future-proof.  What happens if we add something
> else, do we need to list it separately, and then change the kernel to
> accept the new value and maybe also kexec(8)?  Or do we just say "the
> decompressor needs X many bytes after the image" and be done with it?
> The latter sounds way more future-proof to me.

You are right. I changed it to a single value. Done.

-- 
Łukasz Stelmach
Samsung R&D Institute Poland
Samsung Electronics

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 487 bytes --]

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

* [PATCH v2 0/5] kexec_file_load() for arm
       [not found]   ` <CGME20200602161737eucas1p241dd0e0a9b5eea7c5d5774c46b3c570b@eucas1p2.samsung.com>
@ 2020-06-02 16:17     ` Łukasz Stelmach
       [not found]       ` <CGME20200602161737eucas1p2c83700f7c17296c4367ee3fda1c6e783@eucas1p2.samsung.com>
                         ` (4 more replies)
  0 siblings, 5 replies; 35+ messages in thread
From: Łukasz Stelmach @ 2020-06-02 16:17 UTC (permalink / raw)
  To: Russell King, Masahiro Yamada, Nick Desaulniers, Thomas Gleixner,
	Enrico Weigelt, Kees Cook, Ingo Molnar, Ben Dooks,
	linux-arm-kernel, linux-kernel
  Cc: AKASHI Takahiro, Bartlomiej Zolnierkiewicz, Marek Szyprowski,
	Łukasz Stelmach

The following series of patches provides implementation of the
kexec_file_load() system call form the arm architecture. zImage and uImage
(legacy format) files are supported. Like on arm64, there is no
possibility of loading a new DTB and the currently loaded is reused.

Changes in v2:
  - add CONFIG_KEXEC_FILE_UIMAGE for optional uImage support
  - MALLOC_SIZE as a define instead of a symbol
  - DCSZ tag holds combined dynamic memory requirements (bss+stack+malloc)
  - use union for a single tag structure
  - copyright notice includes Russell King

Łukasz Stelmach (5):
  arm: decompressor: set malloc pool size for the decompressor
  arm: add image header definitions
  arm: decompressor: define a new zImage tag
  arm: Add kexec_image_info
  arm: kexec_file: load zImage or uImage, initrd and dtb

 arch/arm/Kconfig                       |  25 +++
 arch/arm/boot/compressed/Makefile      |   7 +-
 arch/arm/boot/compressed/head.S        |   9 +-
 arch/arm/boot/compressed/vmlinux.lds.S |  22 +--
 arch/arm/include/asm/image.h           |  77 +++++++++
 arch/arm/include/asm/kexec.h           |  14 ++
 arch/arm/kernel/Makefile               |   5 +-
 arch/arm/kernel/kexec_uimage.c         |  80 ++++++++++
 arch/arm/kernel/kexec_zimage.c         | 194 +++++++++++++++++++++++
 arch/arm/kernel/machine_kexec.c        |  39 ++++-
 arch/arm/kernel/machine_kexec_file.c   | 211 +++++++++++++++++++++++++
 11 files changed, 662 insertions(+), 21 deletions(-)
 create mode 100644 arch/arm/include/asm/image.h
 create mode 100644 arch/arm/kernel/kexec_uimage.c
 create mode 100644 arch/arm/kernel/kexec_zimage.c
 create mode 100644 arch/arm/kernel/machine_kexec_file.c

-- 
2.26.2


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

* [PATCH v2 1/5] arm: decompressor: set malloc pool size for the decompressor
       [not found]       ` <CGME20200602161737eucas1p2c83700f7c17296c4367ee3fda1c6e783@eucas1p2.samsung.com>
@ 2020-06-02 16:17         ` Łukasz Stelmach
  0 siblings, 0 replies; 35+ messages in thread
From: Łukasz Stelmach @ 2020-06-02 16:17 UTC (permalink / raw)
  To: Russell King, Masahiro Yamada, Nick Desaulniers, Thomas Gleixner,
	Enrico Weigelt, Kees Cook, Ingo Molnar, Ben Dooks,
	linux-arm-kernel, linux-kernel
  Cc: AKASHI Takahiro, Bartlomiej Zolnierkiewicz, Marek Szyprowski,
	Łukasz Stelmach

Move the definition of malloc pool size of the decompressor to
a single place. This value will be exposed later for kexec_file loader.

Signed-off-by: Łukasz Stelmach <l.stelmach@samsung.com>
---
 arch/arm/boot/compressed/Makefile | 7 +++++--
 arch/arm/boot/compressed/head.S   | 6 ++++--
 2 files changed, 9 insertions(+), 4 deletions(-)

diff --git a/arch/arm/boot/compressed/Makefile b/arch/arm/boot/compressed/Makefile
index 9c11e7490292..c4195651e371 100644
--- a/arch/arm/boot/compressed/Makefile
+++ b/arch/arm/boot/compressed/Makefile
@@ -7,7 +7,9 @@
 
 OBJS		=
 
-AFLAGS_head.o += -DTEXT_OFFSET=$(TEXT_OFFSET)
+MALLOC_SIZE     =0x10000
+
+AFLAGS_head.o += -DTEXT_OFFSET=$(TEXT_OFFSET) -DMALLOC_SIZE=$(MALLOC_SIZE)
 HEAD	= head.o
 OBJS	+= misc.o decompress.o
 ifeq ($(CONFIG_DEBUG_UNCOMPRESS),y)
@@ -68,7 +70,8 @@ ZTEXTADDR	:= 0
 ZBSSADDR	:= ALIGN(8)
 endif
 
-CPPFLAGS_vmlinux.lds := -DTEXT_START="$(ZTEXTADDR)" -DBSS_START="$(ZBSSADDR)"
+CPPFLAGS_vmlinux.lds := -DTEXT_START="$(ZTEXTADDR)" -DBSS_START="$(ZBSSADDR)" \
+			-DMALLOC_SIZE="$(MALLOC_SIZE)"
 
 compress-$(CONFIG_KERNEL_GZIP) = gzip
 compress-$(CONFIG_KERNEL_LZO)  = lzo
diff --git a/arch/arm/boot/compressed/head.S b/arch/arm/boot/compressed/head.S
index e8e1c866e413..55758264e776 100644
--- a/arch/arm/boot/compressed/head.S
+++ b/arch/arm/boot/compressed/head.S
@@ -309,7 +309,8 @@ restart:	adr	r0, LC0
 #ifndef CONFIG_ZBOOT_ROM
 		/* malloc space is above the relocated stack (64k max) */
 		add	sp, sp, r0
-		add	r10, sp, #0x10000
+		mov	r10, #MALLOC_SIZE
+		add	r10, r10, sp
 #else
 		/*
 		 * With ZBOOT_ROM the bss/stack is non relocatable,
@@ -623,7 +624,8 @@ not_relocated:	mov	r0, #0
  */
 		mov	r0, r4
 		mov	r1, sp			@ malloc space above stack
-		add	r2, sp, #0x10000	@ 64k max
+		mov	r2, #MALLOC_SIZE	@ 64k max
+		add	r2, r2, sp
 		mov	r3, r7
 		bl	decompress_kernel
 
-- 
2.26.2


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

* [PATCH v2 2/5] arm: add image header definitions
       [not found]       ` <CGME20200602161738eucas1p27dfbe386bd76555598d5574faf4fdad3@eucas1p2.samsung.com>
@ 2020-06-02 16:17         ` Łukasz Stelmach
  0 siblings, 0 replies; 35+ messages in thread
From: Łukasz Stelmach @ 2020-06-02 16:17 UTC (permalink / raw)
  To: Russell King, Masahiro Yamada, Nick Desaulniers, Thomas Gleixner,
	Enrico Weigelt, Kees Cook, Ingo Molnar, Ben Dooks,
	linux-arm-kernel, linux-kernel
  Cc: AKASHI Takahiro, Bartlomiej Zolnierkiewicz, Marek Szyprowski,
	Łukasz Stelmach

This structure will be used later by kexec_file loader.

Signed-off-by: Łukasz Stelmach <l.stelmach@samsung.com>
---
 arch/arm/boot/compressed/head.S        |  3 +-
 arch/arm/boot/compressed/vmlinux.lds.S | 13 ++-----
 arch/arm/include/asm/image.h           | 48 ++++++++++++++++++++++++++
 3 files changed, 53 insertions(+), 11 deletions(-)
 create mode 100644 arch/arm/include/asm/image.h

diff --git a/arch/arm/boot/compressed/head.S b/arch/arm/boot/compressed/head.S
index 55758264e776..005b172d504f 100644
--- a/arch/arm/boot/compressed/head.S
+++ b/arch/arm/boot/compressed/head.S
@@ -7,6 +7,7 @@
  */
 #include <linux/linkage.h>
 #include <asm/assembler.h>
+#include <asm/image.h>
 #include <asm/v7m.h>
 
 #include "efi-header.S"
@@ -211,7 +212,7 @@ start:
 		.word	_magic_start	@ absolute load/run zImage address
 		.word	_magic_end	@ zImage end address
 		.word	0x04030201	@ endianness flag
-		.word	0x45454545	@ another magic number to indicate
+		.word	ARM_ZIMAGE_MAGIC2 @ another magic number to indicate
 		.word	_magic_table	@ additional data table
 
 		__EFI_HEADER
diff --git a/arch/arm/boot/compressed/vmlinux.lds.S b/arch/arm/boot/compressed/vmlinux.lds.S
index f82b5962d97e..308e9cd6a897 100644
--- a/arch/arm/boot/compressed/vmlinux.lds.S
+++ b/arch/arm/boot/compressed/vmlinux.lds.S
@@ -3,14 +3,7 @@
  *  Copyright (C) 2000 Russell King
  */
 
-#ifdef CONFIG_CPU_ENDIAN_BE8
-#define ZIMAGE_MAGIC(x) ( (((x) >> 24) & 0x000000ff) | \
-			  (((x) >>  8) & 0x0000ff00) | \
-			  (((x) <<  8) & 0x00ff0000) | \
-			  (((x) << 24) & 0xff000000) )
-#else
-#define ZIMAGE_MAGIC(x) (x)
-#endif
+#include <asm/image.h>
 
 OUTPUT_ARCH(arm)
 ENTRY(_start)
@@ -43,7 +36,7 @@ SECTIONS
   .table : ALIGN(4) {
     _table_start = .;
     LONG(ZIMAGE_MAGIC(4))
-    LONG(ZIMAGE_MAGIC(0x5a534c4b))
+    LONG(ARM_ZIMAGE_MAGIC3)
     LONG(ZIMAGE_MAGIC(__piggy_size_addr - _start))
     LONG(ZIMAGE_MAGIC(_kernel_bss_size))
     LONG(0)
@@ -107,7 +100,7 @@ SECTIONS
     _edata_real = .;
   }
 
-  _magic_sig = ZIMAGE_MAGIC(0x016f2818);
+  _magic_sig = ARM_ZIMAGE_MAGIC1;
   _magic_start = ZIMAGE_MAGIC(_start);
   _magic_end = ZIMAGE_MAGIC(_edata);
   _magic_table = ZIMAGE_MAGIC(_table_start - _start);
diff --git a/arch/arm/include/asm/image.h b/arch/arm/include/asm/image.h
new file mode 100644
index 000000000000..d5c18a0f6a34
--- /dev/null
+++ b/arch/arm/include/asm/image.h
@@ -0,0 +1,48 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+#ifndef __ASM_IMAGE_H
+#define __ASM_IMAGE_H
+
+#ifdef CONFIG_CPU_ENDIAN_BE8
+#define ZIMAGE_MAGIC(x) ((((x) >> 24) & 0x000000ff) | \
+			 (((x) >>  8) & 0x0000ff00) |  \
+			 (((x) <<  8) & 0x00ff0000) |  \
+			 (((x) << 24) & 0xff000000))
+#else
+#define ZIMAGE_MAGIC(x) (x)
+#endif
+
+#define ARM_ZIMAGE_MAGIC1 ZIMAGE_MAGIC(0x016f2818)
+#define ARM_ZIMAGE_MAGIC2 (0x45454545)
+#define ARM_ZIMAGE_MAGIC3 ZIMAGE_MAGIC(0x5a534c4b)
+
+#ifndef __ASSEMBLY__
+
+#include <linux/types.h>
+#include <asm/setup.h>
+
+/* ARM zImage header format */
+struct arm_zimage_header {
+	__le32 code[9];
+	__le32 magic;
+	__le32 start;
+	__le32 end;
+	__le32 endian;
+	__le32 magic2;
+	__le32 extension_tag_offset;
+};
+
+struct arm_zimage_tag {
+	struct tag_header hdr;
+	union {
+#define ZIMAGE_TAG_KRNL_SIZE ARM_ZIMAGE_MAGIC3
+		struct zimage_krnl_size {
+			__le32 size_ptr;
+			__le32 bss_size;
+		} krnl_size;
+	} u;
+};
+
+#endif /* __ASSEMBLY__ */
+
+#endif /* __ASM_IMAGE_H */
-- 
2.26.2


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

* [PATCH v2 3/5] arm: decompressor: define a new zImage tag
       [not found]       ` <CGME20200602161738eucas1p2151f88b526bb009c27820a4f290a961e@eucas1p2.samsung.com>
@ 2020-06-02 16:17         ` Łukasz Stelmach
  0 siblings, 0 replies; 35+ messages in thread
From: Łukasz Stelmach @ 2020-06-02 16:17 UTC (permalink / raw)
  To: Russell King, Masahiro Yamada, Nick Desaulniers, Thomas Gleixner,
	Enrico Weigelt, Kees Cook, Ingo Molnar, Ben Dooks,
	linux-arm-kernel, linux-kernel
  Cc: AKASHI Takahiro, Bartlomiej Zolnierkiewicz, Marek Szyprowski,
	Łukasz Stelmach

Add DCSZ tag which holds dynamic memory (stack, bss, malloc pool)
requirements of the decompressor code.

Signed-off-by: Łukasz Stelmach <l.stelmach@samsung.com>
---
 arch/arm/boot/compressed/vmlinux.lds.S | 9 ++++++++-
 arch/arm/include/asm/image.h           | 3 +++
 2 files changed, 11 insertions(+), 1 deletion(-)

diff --git a/arch/arm/boot/compressed/vmlinux.lds.S b/arch/arm/boot/compressed/vmlinux.lds.S
index 308e9cd6a897..d15c1269eb5d 100644
--- a/arch/arm/boot/compressed/vmlinux.lds.S
+++ b/arch/arm/boot/compressed/vmlinux.lds.S
@@ -39,6 +39,11 @@ SECTIONS
     LONG(ARM_ZIMAGE_MAGIC3)
     LONG(ZIMAGE_MAGIC(__piggy_size_addr - _start))
     LONG(ZIMAGE_MAGIC(_kernel_bss_size))
+    LONG(ZIMAGE_MAGIC(3))
+    LONG(ARM_ZIMAGE_MAGIC4)
+    LONG(ZIMAGE_MAGIC((_end - __bss_start) +
+                      (_stack_end - _stack_start) +
+                      MALLOC_SIZE))
     LONG(0)
     _table_end = .;
   }
@@ -108,10 +113,12 @@ SECTIONS
   . = BSS_START;
   __bss_start = .;
   .bss			: { *(.bss) }
+  . = ALIGN(8);		/* the stack must be 64-bit aligned and adjoin bss */
   _end = .;
 
-  . = ALIGN(8);		/* the stack must be 64-bit aligned */
+  _stack_start = .;
   .stack		: { *(.stack) }
+  _stack_end = .;
 
   PROVIDE(__pecoff_data_size = ALIGN(512) - ADDR(.data));
   PROVIDE(__pecoff_end = ALIGN(512));
diff --git a/arch/arm/include/asm/image.h b/arch/arm/include/asm/image.h
index d5c18a0f6a34..55b51faa6b7e 100644
--- a/arch/arm/include/asm/image.h
+++ b/arch/arm/include/asm/image.h
@@ -15,6 +15,7 @@
 #define ARM_ZIMAGE_MAGIC1 ZIMAGE_MAGIC(0x016f2818)
 #define ARM_ZIMAGE_MAGIC2 (0x45454545)
 #define ARM_ZIMAGE_MAGIC3 ZIMAGE_MAGIC(0x5a534c4b)
+#define ARM_ZIMAGE_MAGIC4 ZIMAGE_MAGIC(0x5a534344)
 
 #ifndef __ASSEMBLY__
 
@@ -40,6 +41,8 @@ struct arm_zimage_tag {
 			__le32 size_ptr;
 			__le32 bss_size;
 		} krnl_size;
+#define ZIMAGE_TAG_ZIMAGE_MEM ARM_ZIMAGE_MAGIC4
+		__le32 zimage_mem;
 	} u;
 };
 
-- 
2.26.2


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

* [PATCH v2 4/5] arm: Add kexec_image_info
       [not found]       ` <CGME20200602161738eucas1p2ccfaa7610dc6f76e209ba96d6278259e@eucas1p2.samsung.com>
@ 2020-06-02 16:17         ` Łukasz Stelmach
  0 siblings, 0 replies; 35+ messages in thread
From: Łukasz Stelmach @ 2020-06-02 16:17 UTC (permalink / raw)
  To: Russell King, Masahiro Yamada, Nick Desaulniers, Thomas Gleixner,
	Enrico Weigelt, Kees Cook, Ingo Molnar, Ben Dooks,
	linux-arm-kernel, linux-kernel
  Cc: AKASHI Takahiro, Bartlomiej Zolnierkiewicz, Marek Szyprowski,
	Łukasz Stelmach

Add kexec_image_info to print detailed information about a kexec image.

Signed-off-by: Łukasz Stelmach <l.stelmach@samsung.com>
---
 arch/arm/kernel/machine_kexec.c | 28 ++++++++++++++++++++++++++++
 1 file changed, 28 insertions(+)

diff --git a/arch/arm/kernel/machine_kexec.c b/arch/arm/kernel/machine_kexec.c
index 76300f3813e8..c10a2dfd53d1 100644
--- a/arch/arm/kernel/machine_kexec.c
+++ b/arch/arm/kernel/machine_kexec.c
@@ -31,6 +31,32 @@ extern unsigned long kexec_boot_atags;
 
 static atomic_t waiting_for_crash_ipi;
 
+/**
+ * kexec_image_info - For debugging output.
+ */
+#define kexec_image_info(_i) _kexec_image_info(__func__, __LINE__, _i)
+static void _kexec_image_info(const char *func, int line,
+	const struct kimage *kimage)
+{
+	unsigned long i;
+
+	pr_debug("%s:%d:\n", func, line);
+	pr_debug("  kexec kimage info:\n");
+	pr_debug("    type:        %d\n", kimage->type);
+	pr_debug("    start:       %lx\n", kimage->start);
+	pr_debug("    head:        %lx\n", kimage->head);
+	pr_debug("    nr_segments: %lu\n", kimage->nr_segments);
+
+	for (i = 0; i < kimage->nr_segments; i++) {
+		pr_debug("      segment[%lu]: %08lx - %08lx, 0x%x bytes, %lu pages\n",
+			i,
+			kimage->segment[i].mem,
+			kimage->segment[i].mem + kimage->segment[i].memsz,
+			kimage->segment[i].memsz,
+			kimage->segment[i].memsz /  PAGE_SIZE);
+	}
+}
+
 /*
  * Provide a dummy crash_notes definition while crash dump arrives to arm.
  * This prevents breakage of crash_notes attribute in kernel/ksysfs.c.
@@ -42,6 +68,8 @@ int machine_kexec_prepare(struct kimage *image)
 	__be32 header;
 	int i, err;
 
+	kexec_image_info(image);
+
 	image->arch.kernel_r2 = image->start - KEXEC_ARM_ZIMAGE_OFFSET
 				     + KEXEC_ARM_ATAGS_OFFSET;
 
-- 
2.26.2


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

* [PATCH v2 5/5] arm: kexec_file: load zImage or uImage, initrd and dtb
       [not found]       ` <CGME20200602161739eucas1p16a56ff590bf44e747d5ad6e178d57067@eucas1p1.samsung.com>
@ 2020-06-02 16:17         ` Łukasz Stelmach
  0 siblings, 0 replies; 35+ messages in thread
From: Łukasz Stelmach @ 2020-06-02 16:17 UTC (permalink / raw)
  To: Russell King, Masahiro Yamada, Nick Desaulniers, Thomas Gleixner,
	Enrico Weigelt, Kees Cook, Ingo Molnar, Ben Dooks,
	linux-arm-kernel, linux-kernel
  Cc: AKASHI Takahiro, Bartlomiej Zolnierkiewicz, Marek Szyprowski,
	Łukasz Stelmach

This is kexec_file_load implementation for ARM. It loads zImage and
initrd from file descripters and resuses DTB.

Most code is derived from arm64 kexec_file_load implementation
and from kexec-tools.

Cc: AKASHI Takahiro <takahiro.akashi@linaro.org>
Signed-off-by: Łukasz Stelmach <l.stelmach@samsung.com>
---
 arch/arm/Kconfig                     |  25 ++++
 arch/arm/include/asm/image.h         |  26 ++++
 arch/arm/include/asm/kexec.h         |  14 ++
 arch/arm/kernel/Makefile             |   5 +-
 arch/arm/kernel/kexec_uimage.c       |  80 ++++++++++
 arch/arm/kernel/kexec_zimage.c       | 194 ++++++++++++++++++++++++
 arch/arm/kernel/machine_kexec.c      |  11 +-
 arch/arm/kernel/machine_kexec_file.c | 211 +++++++++++++++++++++++++++
 8 files changed, 561 insertions(+), 5 deletions(-)
 create mode 100644 arch/arm/kernel/kexec_uimage.c
 create mode 100644 arch/arm/kernel/kexec_zimage.c
 create mode 100644 arch/arm/kernel/machine_kexec_file.c

diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index c77c93c485a0..c592c58e78f1 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -1917,6 +1917,31 @@ config KEXEC
 	  is properly shutdown, so do not be surprised if this code does not
 	  initially work for you.
 
+config KEXEC_FILE
+	bool "Kexec file based system call (EXPERIMENTAL)"
+	depends on (!SMP || PM_SLEEP_SMP)
+	depends on USE_OF
+	select KEXEC_CORE
+	select CRC32
+	help
+	  This is new version of kexec system call. This system call is
+	  file based and takes file descriptors as system call argument
+	  for kernel and initramfs as opposed to list of segments as
+	  accepted by previous system call.
+
+	  The kernel to be loaded MUST support Flattened Device Tree
+	  (selected with CONFIG_USE_OF).
+
+config KEXEC_FILE_UIMAGE
+	bool "Load legacy uImage files with kexec_file_load() (EXPERIMENTAL)"
+	depends on KEXEC_FILE
+	default n
+	help
+	  This options enables support for the legacy uImage files as
+	  created by mkimage. These are not the new FIT files.
+
+	  If unsure say N.
+
 config ATAGS_PROC
 	bool "Export atags in procfs"
 	depends on ATAGS && KEXEC
diff --git a/arch/arm/include/asm/image.h b/arch/arm/include/asm/image.h
index 55b51faa6b7e..596b32952958 100644
--- a/arch/arm/include/asm/image.h
+++ b/arch/arm/include/asm/image.h
@@ -8,8 +8,13 @@
 			 (((x) >>  8) & 0x0000ff00) |  \
 			 (((x) <<  8) & 0x00ff0000) |  \
 			 (((x) << 24) & 0xff000000))
+#define UIMAGE_MAGIC(x) (x)
 #else
 #define ZIMAGE_MAGIC(x) (x)
+#define UIMAGE_MAGIC(x) ((((x) >> 24) & 0x000000ff) | \
+			 (((x) >>  8) & 0x0000ff00) |  \
+			 (((x) <<  8) & 0x00ff0000) |  \
+			 (((x) << 24) & 0xff000000))
 #endif
 
 #define ARM_ZIMAGE_MAGIC1 ZIMAGE_MAGIC(0x016f2818)
@@ -17,6 +22,12 @@
 #define ARM_ZIMAGE_MAGIC3 ZIMAGE_MAGIC(0x5a534c4b)
 #define ARM_ZIMAGE_MAGIC4 ZIMAGE_MAGIC(0x5a534344)
 
+#define ARM_UIMAGE_MAGIC UIMAGE_MAGIC(0x27051956)
+#define ARM_UIMAGE_NAME_LEN		32
+#define ARM_UIMAGE_TYPE_KERNEL		2
+#define ARM_UIMAGE_TYPE_KERNEL_NOLOAD	14
+#define ARM_UIMAGE_ARCH_ARM		2
+
 #ifndef __ASSEMBLY__
 
 #include <linux/types.h>
@@ -33,6 +44,21 @@ struct arm_zimage_header {
 	__le32 extension_tag_offset;
 };
 
+struct arm_uimage_header {
+	__be32 magic;
+	__be32 hdr_crc;
+	__be32 time;
+	__be32 size;
+	__be32 load;
+	__be32 entry;
+	__be32 crc;
+	__u8   os;
+	__u8   arch;
+	__u8   type;
+	__u8   comp;
+	__u8   name[ARM_UIMAGE_NAME_LEN];
+};
+
 struct arm_zimage_tag {
 	struct tag_header hdr;
 	union {
diff --git a/arch/arm/include/asm/kexec.h b/arch/arm/include/asm/kexec.h
index 22751b5b5735..fda35afa7195 100644
--- a/arch/arm/include/asm/kexec.h
+++ b/arch/arm/include/asm/kexec.h
@@ -83,6 +83,20 @@ static inline struct page *boot_pfn_to_page(unsigned long boot_pfn)
 }
 #define boot_pfn_to_page boot_pfn_to_page
 
+#ifdef CONFIG_KEXEC_FILE
+
+extern const struct kexec_file_ops kexec_zimage_ops;
+extern const struct kexec_file_ops kexec_uimage_ops;
+
+struct kimage;
+
+extern int load_other_segments(struct kimage *image,
+		unsigned long kernel_load_addr, unsigned long kernel_size,
+		char *initrd, unsigned long initrd_len,
+		unsigned long initrd_offset, char *cmdline);
+
+#endif /* CONFIG_KEXEC_FILE */
+
 #endif /* __ASSEMBLY__ */
 
 #endif /* CONFIG_KEXEC */
diff --git a/arch/arm/kernel/Makefile b/arch/arm/kernel/Makefile
index 89e5d864e923..453ecf7305e2 100644
--- a/arch/arm/kernel/Makefile
+++ b/arch/arm/kernel/Makefile
@@ -3,6 +3,7 @@
 # Makefile for the linux kernel.
 #
 
+CFLAGS_kexec_zimage.o := -DTEXT_OFFSET=$(TEXT_OFFSET)
 CPPFLAGS_vmlinux.lds := -DTEXT_OFFSET=$(TEXT_OFFSET)
 AFLAGS_head.o        := -DTEXT_OFFSET=$(TEXT_OFFSET)
 
@@ -56,7 +57,9 @@ obj-$(CONFIG_FUNCTION_TRACER)	+= entry-ftrace.o
 obj-$(CONFIG_DYNAMIC_FTRACE)	+= ftrace.o insn.o patch.o
 obj-$(CONFIG_FUNCTION_GRAPH_TRACER)	+= ftrace.o insn.o patch.o
 obj-$(CONFIG_JUMP_LABEL)	+= jump_label.o insn.o patch.o
-obj-$(CONFIG_KEXEC)		+= machine_kexec.o relocate_kernel.o
+obj-$(CONFIG_KEXEC_CORE)	+= machine_kexec.o relocate_kernel.o
+obj-$(CONFIG_KEXEC_FILE)	+= machine_kexec_file.o kexec_zimage.o
+obj-$(CONFIG_KEXEC_FILE_UIMAGE)	+= kexec_uimage.o
 # Main staffs in KPROBES are in arch/arm/probes/ .
 obj-$(CONFIG_KPROBES)		+= patch.o insn.o
 obj-$(CONFIG_OABI_COMPAT)	+= sys_oabi-compat.o
diff --git a/arch/arm/kernel/kexec_uimage.c b/arch/arm/kernel/kexec_uimage.c
new file mode 100644
index 000000000000..47033574e24e
--- /dev/null
+++ b/arch/arm/kernel/kexec_uimage.c
@@ -0,0 +1,80 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Kexec uImage loader
+ *
+ * Copyright (C) 2020 Samsung Electronics
+ * Author: Łukasz Stelmach <l.stelmach@samsung.com>
+ */
+
+#define pr_fmt(fmt)	"kexec_file(uImage): " fmt
+
+#include <asm/image.h>
+#include <linux/crc32.h>
+#include <linux/err.h>
+#include <linux/kexec.h>
+
+#define crc32_ones(crc, buf, len) \
+	(crc32(crc ^ 0xffffffff, buf, len) ^ 0xffffffff)
+
+static int uimage_probe(const char *uimage_buf, unsigned long uimage_len)
+{
+	const struct arm_uimage_header *h =
+		(struct arm_uimage_header *) uimage_buf;
+	struct arm_uimage_header uhdr;
+	unsigned long zoff = sizeof(struct arm_uimage_header);
+	uint32_t crc;
+
+	if (h->magic != ARM_UIMAGE_MAGIC)
+		return -EINVAL;
+
+	if (h->type != ARM_UIMAGE_TYPE_KERNEL &&
+	    h->type != ARM_UIMAGE_TYPE_KERNEL_NOLOAD){
+		pr_debug("Invalid image type: %d\n", h->type);
+		return -EINVAL;
+	}
+
+	if (h->arch != ARM_UIMAGE_ARCH_ARM) {
+		pr_debug("Invalidy image arch: %d\n", h->arch);
+		return -EINVAL;
+	}
+
+	memcpy((char *)&uhdr, h, sizeof(uhdr));
+	crc = be32_to_cpu(uhdr.hdr_crc);
+	uhdr.hdr_crc = 0;
+
+	if (crc32_ones(0, (char *)&uhdr, sizeof(uhdr)) != crc) {
+		pr_debug("Corrupt header, CRC do not match\n");
+		return -EINVAL;
+	}
+
+	crc = be32_to_cpu(uhdr.crc);
+	if (crc32_ones(0, uimage_buf + zoff, uimage_len - zoff) != crc) {
+		pr_debug("Corrupt zImage, CRC do not match\n");
+		return -EINVAL;
+	}
+
+	return kexec_zimage_ops.probe(uimage_buf + zoff,
+				      uimage_len - zoff);
+}
+
+static void *uimage_load(struct kimage *image,
+				char *uimage, unsigned long uimage_len,
+				char *initrd, unsigned long initrd_len,
+				char *cmdline, unsigned long cmdline_len)
+{
+	const struct arm_uimage_header *h =
+		(struct arm_uimage_header *) uimage;
+	unsigned long zimage_offset = sizeof(struct arm_uimage_header);
+
+	pr_debug("Loading uImage");
+	return kexec_zimage_ops.load(image,
+				     uimage + zimage_offset,
+				     uimage_len - zimage_offset,
+				     initrd, initrd_len,
+				     cmdline, cmdline_len);
+}
+
+const struct kexec_file_ops kexec_uimage_ops = {
+	.probe = uimage_probe,
+	.load = uimage_load,
+};
diff --git a/arch/arm/kernel/kexec_zimage.c b/arch/arm/kernel/kexec_zimage.c
new file mode 100644
index 000000000000..586b623ed91d
--- /dev/null
+++ b/arch/arm/kernel/kexec_zimage.c
@@ -0,0 +1,194 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Kexec zImage loader
+ *
+ * Copyright (C) 2016-2018 Russel King
+ * Copyright (C) 2020 Samsung Electronics
+ * Authors:
+ *     Łukasz Stelmach <l.stelmach@samsung.com>
+ *     Russell King <rmk+kernel@armlinux.org.uk>
+ */
+
+#define pr_fmt(fmt)	"kexec_file(zImage): " fmt
+
+#include <asm/image.h>
+#include <asm/unaligned.h>
+#include <linux/err.h>
+#include <linux/kexec.h>
+#include <linux/memblock.h>
+
+#define byte_size(t)    ((t)->hdr.size << 2)
+
+/*
+ * This function and several pieces below have been taken from
+ * kexec-tools/kexec/arch/arm/kexec-zImage-arm.c
+ */
+static const void *find_extension_tag(const char *buf,
+						       unsigned long len,
+						       uint32_t tag_id)
+{
+	const struct arm_zimage_header *h = (const struct arm_zimage_header *)buf;
+	const struct arm_zimage_tag *tag;
+	uint32_t offset, size;
+	uint32_t max = len - sizeof(struct tag_header);
+
+	if (len < sizeof(*h) ||
+	    h->magic != ARM_ZIMAGE_MAGIC1 ||
+	    h->magic2 != ARM_ZIMAGE_MAGIC2)
+		return NULL;
+
+	for (offset = h->extension_tag_offset;
+	     (tag = (void *)(buf + offset)) != NULL &&
+		     offset < max &&
+		     (size = le32_to_cpu(byte_size(tag))) != 0 &&
+		     offset + size < len;
+	     offset += size) {
+		pr_debug("  offset 0x%08x tag 0x%08x size %u\n",
+			  offset, le32_to_cpu(tag->hdr.tag), size);
+		if (tag->hdr.tag == tag_id)
+			return tag;
+	}
+
+	return NULL;
+}
+
+static int zimage_probe(const char *kernel_buf, unsigned long kernel_len)
+{
+	const struct arm_zimage_header *h =
+		(struct arm_zimage_header *)(kernel_buf);
+
+	if (!h || (kernel_len < sizeof(*h)))
+		return -EINVAL;
+
+	if ((h->magic != ARM_ZIMAGE_MAGIC1) ||
+	    (h->magic2 != ARM_ZIMAGE_MAGIC2))
+		return -EINVAL;
+
+	return 0;
+}
+
+
+#if defined(DEBUG)
+#define debug_offsets() ({			\
+	pr_debug("Image offsets:\n");		\
+	pr_debug("  kernel 0x%08lx 0x%08lx\n", kernel_offset, kernel_len); \
+	pr_debug("  zimage 0x%08lx 0x%08lx\n", zimage_offset, zimage_len); \
+	pr_debug("  initrd 0x%08lx 0x%08lx\n", initrd_offset, initrd_len); \
+})
+#else
+#define debug_offsets()
+#endif
+
+static void *zimage_load(struct kimage *image,
+				char *zimage, unsigned long zimage_len,
+				char *initrd, unsigned long initrd_len,
+				char *cmdline, unsigned long cmdline_len)
+{
+	struct arm_zimage_header *h;
+	struct kexec_buf kbuf;
+	struct kexec_segment *zimage_segment;
+	const struct arm_zimage_tag *tag;
+	int ret = -EINVAL;
+
+	unsigned long zimage_mem = 0x20000; /* malloc 64kB + stack 4 kB + some bss */
+	unsigned long kernel_len = zimage_len * 5; /* 5:1 compression */
+	unsigned long kernel_offset = memblock_start_of_DRAM() +
+		ALIGN(TEXT_OFFSET, PAGE_SIZE);
+	unsigned long zimage_offset = kernel_offset +
+		ALIGN(kernel_len, PAGE_SIZE);
+	unsigned long initrd_offset = zimage_offset +
+		ALIGN(zimage_len + zimage_mem, PAGE_SIZE);
+
+	if (image->type == KEXEC_TYPE_CRASH) {
+		kernel_offset += crashk_res.start;
+		zimage_offset += crashk_res.start;
+		initrd_offset += crashk_res.start;
+	}
+	debug_offsets();
+
+	h = (struct arm_zimage_header *)zimage;
+
+	tag = find_extension_tag(zimage, zimage_len, ZIMAGE_TAG_KRNL_SIZE);
+	if (tag) {
+		uint32_t *p = (void *)zimage +
+			le32_to_cpu(tag->u.krnl_size.size_ptr);
+		uint32_t edata_size = le32_to_cpu(get_unaligned(p));
+		uint32_t bss_size = le32_to_cpu(tag->u.krnl_size.bss_size);
+
+		kernel_len = edata_size + bss_size;
+
+		pr_debug("Decompressed kernel sizes:\n");
+		pr_debug(" text+data 0x%08lx bss 0x%08lx total 0x%08lx\n",
+			 (unsigned long)edata_size,
+			 (unsigned long)bss_size,
+			 (unsigned long)kernel_len);
+
+		zimage_offset = kernel_offset + ALIGN(edata_size, PAGE_SIZE);
+		initrd_offset = zimage_offset +
+			max(ALIGN(zimage_len + 0x20000, PAGE_SIZE),
+			    ALIGN((unsigned long)bss_size, PAGE_SIZE));
+		debug_offsets();
+	}
+
+	tag = find_extension_tag(zimage, zimage_len,
+				 ZIMAGE_TAG_ZIMAGE_MEM);
+	if (tag) {
+		uint32_t zimage_mem = le32_to_cpu(tag->u.zimage_mem);
+
+		pr_debug("Decompressor requires %d bytes of memory\n", zimage_mem);
+
+		initrd_offset = max(ALIGN(zimage_offset + zimage_len + zimage_mem, PAGE_SIZE),
+				    ALIGN(kernel_offset + kernel_len, PAGE_SIZE));
+		debug_offsets();
+	}
+
+	/*
+	 * zImage MUST be loaded into the first 128 MiB of physical
+	 * memory for proper memory detection. Should the uncompressed
+	 * kernel be larger than 128 MiB, zImage relocation becomes
+	 * unavoidable and it is best to rely on the relocation code.
+	 */
+	if (((zimage_offset - kernel_offset) + PAGE_SIZE + 0x8000) >= SZ_128M) {
+		pr_debug("The kernel is too big (%ld MiB) to avoid "
+			 "zImage relocation. Loading zimage at 0x%08lx\n",
+			 ((zimage_offset - kernel_offset) >> 20),
+			 kernel_offset);
+		zimage_offset = kernel_offset;
+	}
+
+	kbuf.image = image;
+	kbuf.top_down = false;
+
+	kbuf.buf_min = zimage_offset;
+	kbuf.buf_max = ULONG_MAX;
+	kbuf.buffer = zimage;
+	kbuf.bufsz = zimage_len;
+	kbuf.buf_align = PAGE_SIZE;
+
+	kbuf.mem = KEXEC_BUF_MEM_UNKNOWN;
+	kbuf.memsz = zimage_len;
+
+	ret = kexec_add_buffer(&kbuf);
+	if (ret)
+		return ERR_PTR(ret);
+
+	pr_debug("Loaded zImage at 0x%lx bufsz=0x%lx memsz=0x%lx\n",
+		 kbuf.mem, kbuf.bufsz, kbuf.memsz);
+
+	initrd_offset += kbuf.mem - zimage_offset;
+	debug_offsets();
+
+	zimage_segment = &image->segment[image->nr_segments - 1];
+	image->start = zimage_segment->mem;
+
+	ret = load_other_segments(image,
+				  zimage_segment->mem, zimage_segment->memsz,
+				  initrd, initrd_len, initrd_offset,
+				  cmdline);
+	return ERR_PTR(ret);
+}
+
+const struct kexec_file_ops kexec_zimage_ops = {
+	.probe = zimage_probe,
+	.load = zimage_load,
+};
diff --git a/arch/arm/kernel/machine_kexec.c b/arch/arm/kernel/machine_kexec.c
index c10a2dfd53d1..2e4780efabb4 100644
--- a/arch/arm/kernel/machine_kexec.c
+++ b/arch/arm/kernel/machine_kexec.c
@@ -93,10 +93,13 @@ int machine_kexec_prepare(struct kimage *image)
 					       current_segment->memsz))
 			return -EINVAL;
 
-		err = get_user(header, (__be32*)current_segment->buf);
-		if (err)
-			return err;
-
+		if (image->file_mode) {
+			header = *(__be32 *)current_segment->buf;
+		} else {
+			err = get_user(header, (__be32 *)current_segment->buf);
+			if (err)
+				return err;
+		}
 		if (header == cpu_to_be32(OF_DT_HEADER))
 			image->arch.kernel_r2 = current_segment->mem;
 	}
diff --git a/arch/arm/kernel/machine_kexec_file.c b/arch/arm/kernel/machine_kexec_file.c
new file mode 100644
index 000000000000..a632d351602c
--- /dev/null
+++ b/arch/arm/kernel/machine_kexec_file.c
@@ -0,0 +1,211 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * kexec_file for arm
+ *
+ * Copyright (C) 2018 Linaro Limited
+ * Copyright (C) 2020 Samsung Electronics
+ * Authors:
+ *     AKASHI Takahiro <takahiro.akashi@linaro.org>
+ *     Łukasz Stelmach <l.stelmach@samsung.com>
+ *
+ */
+
+#define pr_fmt(fmt) "kexec_file: " fmt
+
+#include <linux/kexec.h>
+#include <linux/libfdt.h>
+#include <linux/of_fdt.h>
+#include <linux/random.h>
+
+/* relevant device tree properties */
+#define FDT_PROP_INITRD_START	"linux,initrd-start"
+#define FDT_PROP_INITRD_END	"linux,initrd-end"
+#define FDT_PROP_BOOTARGS	"bootargs"
+#define FDT_PROP_RNG_SEED	"rng-seed"
+
+static int setup_dtb(struct kimage *image,
+		     unsigned long initrd_load_addr, unsigned long initrd_len,
+		     char *cmdline, void *dtb)
+{
+	int off, ret;
+
+	ret = fdt_path_offset(dtb, "/chosen");
+	if (ret < 0)
+		goto out;
+
+	off = ret;
+
+	/* add bootargs */
+	if (cmdline) {
+		ret = fdt_setprop_string(dtb, off, FDT_PROP_BOOTARGS, cmdline);
+		if (ret)
+			goto out;
+	} else {
+		ret = fdt_delprop(dtb, off, FDT_PROP_BOOTARGS);
+		if (ret && (ret != -FDT_ERR_NOTFOUND))
+			goto out;
+	}
+
+	/* add initrd-* */
+	if (initrd_load_addr) {
+		ret = fdt_setprop_u64(dtb, off, FDT_PROP_INITRD_START,
+				      initrd_load_addr);
+		if (ret)
+			goto out;
+
+		ret = fdt_setprop_u64(dtb, off, FDT_PROP_INITRD_END,
+				      initrd_load_addr + initrd_len);
+		if (ret)
+			goto out;
+	} else {
+		ret = fdt_delprop(dtb, off, FDT_PROP_INITRD_START);
+		if (ret && (ret != -FDT_ERR_NOTFOUND))
+			goto out;
+
+		ret = fdt_delprop(dtb, off, FDT_PROP_INITRD_END);
+		if (ret && (ret != -FDT_ERR_NOTFOUND))
+			goto out;
+	}
+
+	/* add rng-seed */
+	if (rng_is_initialized()) {
+		char seed[128];
+		get_random_bytes(seed, sizeof(seed));
+
+		ret = fdt_setprop(dtb, off, FDT_PROP_RNG_SEED,
+				  seed, sizeof(seed));
+		if (ret)
+			goto out;
+	} else {
+		pr_notice("RNG is not initialised: omitting \"%s\" property\n",
+				FDT_PROP_RNG_SEED);
+		ret = 0;
+	}
+
+out:
+	if (ret)
+		return (ret == -FDT_ERR_NOSPACE) ? -ENOMEM : -EINVAL;
+
+	return 0;
+}
+/*
+ * More space needed so that we can add initrd, bootargs and kaslr-seed.
+ */
+#define DTB_EXTRA_SPACE 0x1000
+
+static int create_dtb(struct kimage *image,
+		      unsigned long initrd_load_addr, unsigned long initrd_len,
+		      char *cmdline, void **dtb)
+{
+	void *buf;
+	size_t buf_size;
+	size_t cmdline_len;
+	int ret;
+
+	cmdline_len = cmdline ? strlen(cmdline) : 0;
+	buf_size = fdt_totalsize(initial_boot_params)
+			+ cmdline_len + DTB_EXTRA_SPACE;
+
+	for (;;) {
+		buf = vmalloc(buf_size);
+		if (!buf)
+			return -ENOMEM;
+
+		/* duplicate a device tree blob */
+		ret = fdt_open_into(initial_boot_params, buf, buf_size);
+		if (ret)
+			return -EINVAL;
+
+		ret = setup_dtb(image, initrd_load_addr, initrd_len,
+				cmdline, buf);
+		if (ret) {
+			vfree(buf);
+			if (ret == -ENOMEM) {
+				/* unlikely, but just in case */
+				buf_size += DTB_EXTRA_SPACE;
+				continue;
+			} else {
+				return ret;
+			}
+		}
+
+		/* trim it */
+		fdt_pack(buf);
+		*dtb = buf;
+
+		return 0;
+	}
+}
+
+int load_other_segments(struct kimage *image,
+			unsigned long zimage_load_addr,
+			unsigned long zimage_len,
+			char *initrd,
+			unsigned long initrd_len,
+			unsigned long initrd_offset,
+			char *cmdline)
+{
+	struct kexec_buf kbuf;
+	void *dtb = NULL;
+	unsigned long initrd_load_addr = 0;
+	unsigned long dtb_len;
+	int ret = 0;
+
+	kbuf.image = image;
+	/* not allocate anything below the kernel */
+	kbuf.buf_min = initrd_offset;
+	if (initrd) {
+		kbuf.buffer = initrd;
+		kbuf.bufsz = initrd_len;
+		kbuf.mem = KEXEC_BUF_MEM_UNKNOWN;
+		kbuf.memsz = initrd_len;
+		kbuf.buf_align = PAGE_SIZE;
+		kbuf.buf_max = ULONG_MAX;
+		kbuf.top_down = false;
+
+		ret = kexec_add_buffer(&kbuf);
+		if (ret)
+			goto out_err;
+
+		pr_debug("Loaded initrd at 0x%lx bufsz=0x%lx memsz=0x%lx\n",
+				kbuf.mem, kbuf.bufsz, kbuf.memsz);
+
+		initrd_load_addr = kbuf.mem;
+		kbuf.buf_min = initrd_load_addr + kbuf.memsz;
+	}
+
+	/* load dtb */
+	ret = create_dtb(image, initrd_load_addr, initrd_len, cmdline, &dtb);
+	if (ret) {
+		pr_err("Preparing for new dtb failed\n");
+		goto out_err;
+	}
+
+	dtb_len = fdt_totalsize(dtb);
+	kbuf.buffer = dtb;
+	kbuf.bufsz = dtb_len;
+	kbuf.mem = KEXEC_BUF_MEM_UNKNOWN;
+	kbuf.memsz = dtb_len;
+	kbuf.buf_align = PAGE_SIZE;
+	kbuf.buf_max = ULONG_MAX;
+	kbuf.top_down = false;
+
+	ret = kexec_add_buffer(&kbuf);
+	if (ret)
+		goto out_err;
+
+	pr_debug("Loaded dtb at 0x%lx bufsz=0x%lx memsz=0x%lx\n",
+		 kbuf.mem, kbuf.bufsz, kbuf.memsz);
+	return 0;
+out_err:
+	vfree(dtb);
+	return ret;
+}
+
+const struct kexec_file_ops * const kexec_file_loaders[] = {
+#ifdef CONFIG_KEXEC_FILE_UIMAGE
+	&kexec_uimage_ops,
+#endif
+	&kexec_zimage_ops,
+	NULL
+};
-- 
2.26.2


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

* Re: [PATCH 0/5] kexec_file_load() for arm
  2020-06-01 14:27 ` [PATCH 0/5] kexec_file_load() for arm Łukasz Stelmach
                     ` (5 preceding siblings ...)
       [not found]   ` <CGME20200602161737eucas1p241dd0e0a9b5eea7c5d5774c46b3c570b@eucas1p2.samsung.com>
@ 2020-06-11 10:37   ` Dave Young
       [not found]   ` <CGME20200930183921eucas1p11a56f805421a614be67f869f5ed18b9b@eucas1p1.samsung.com>
  7 siblings, 0 replies; 35+ messages in thread
From: Dave Young @ 2020-06-11 10:37 UTC (permalink / raw)
  To: Łukasz Stelmach
  Cc: Russell King, Masahiro Yamada, Nick Desaulniers, Thomas Gleixner,
	Enrico Weigelt, Kees Cook, Ingo Molnar, Ben Dooks,
	linux-arm-kernel, linux-kernel, AKASHI Takahiro,
	Bartlomiej Zolnierkiewicz, Marek Szyprowski, kexec

Cc kexec list in case people may missed the pieces.
On 06/01/20 at 04:27pm, Łukasz Stelmach wrote:
> The following series of patches provides implementation of the
> kexec_file_load() system call form the arm architecture. zImage and uImage
> (legacy format) files are supported. Like on arm64, there is no
> possibility of loading a new DTB and the currently loaded is reused.
> 
> Łukasz Stelmach (5):
>   arm: decompressor: set malloc pool size for the decompressor
>   arm: add image header definitions
>   arm: decompressor: define a new zImage tag
>   arm: Add kexec_image_info
>   arm: kexec_file: load zImage or uImage, initrd and dtb
> 
>  arch/arm/Kconfig                       |  15 ++
>  arch/arm/boot/compressed/Makefile      |   2 +
>  arch/arm/boot/compressed/head.S        |   9 +-
>  arch/arm/boot/compressed/vmlinux.lds.S |  22 +--
>  arch/arm/include/asm/image.h           |  87 ++++++++++
>  arch/arm/include/asm/kexec.h           |  14 ++
>  arch/arm/kernel/Makefile               |   5 +-
>  arch/arm/kernel/kexec_uimage.c         |  80 ++++++++++
>  arch/arm/kernel/kexec_zimage.c         | 199 +++++++++++++++++++++++
>  arch/arm/kernel/machine_kexec.c        |  39 ++++-
>  arch/arm/kernel/machine_kexec_file.c   | 209 +++++++++++++++++++++++++
>  11 files changed, 662 insertions(+), 19 deletions(-)
>  create mode 100644 arch/arm/include/asm/image.h
>  create mode 100644 arch/arm/kernel/kexec_uimage.c
>  create mode 100644 arch/arm/kernel/kexec_zimage.c
>  create mode 100644 arch/arm/kernel/machine_kexec_file.c
> 
> -- 
> 2.26.2
> 


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

* [PATCH v3 0/4] kexec_file_load() for arm
       [not found]   ` <CGME20200930183921eucas1p11a56f805421a614be67f869f5ed18b9b@eucas1p1.samsung.com>
@ 2020-09-30 18:34     ` Łukasz Stelmach
       [not found]       ` <CGME20200930183923eucas1p2241d3e1b8d4d05a2228448ff8fc4bb74@eucas1p2.samsung.com>
                         ` (3 more replies)
  0 siblings, 4 replies; 35+ messages in thread
From: Łukasz Stelmach @ 2020-09-30 18:34 UTC (permalink / raw)
  To: Russell King, Masahiro Yamada, Nick Desaulniers, Thomas Gleixner,
	Enrico Weigelt, Kees Cook, Ingo Molnar, Ben Dooks,
	linux-arm-kernel, linux-kernel, AKASHI Takahiro, kexec,
	Dave Young
  Cc: Bartlomiej Zolnierkiewicz, Marek Szyprowski, Łukasz Stelmach

The following series of patches provides implementation of the                                                         
kexec_file_load() system call form the arm architecture. zImage and uImage                                             
(legacy format) files are supported. Like on arm64, there is no                                                        
possibility of loading a new DTB and the currently loaded is reused.                                                   

Changes in v3:
  - move the patchset to next-20200929
  - drop the first patch: set malloc pool size for the decompressor
    (replaced by adc5f70293760)  
  - use text_offset added in 83dfeedb6663e
  - add text_offset and malloc_size to struct zimage_krnl_size
  - add dependency on CONFIG_KEXEC_FILE in arch/arm/include/asm/kexec.h
    to enable compilation without CONFIG_KEXEC
  - add dependency on MMU in Kconfig

Changes in v2:                                                                                                         
  - add CONFIG_KEXEC_FILE_UIMAGE for optional uImage support                                                           
  - MALLOC_SIZE as a define instead of a symbol                                                                        
  - DCSZ tag holds combined dynamic memory requirements (bss+stack+malloc)                                             
  - use union for a single tag structure                                                                               
  - copyright notice includes Russell King                                                                             

Łukasz Stelmach (4):
  arm: add image header definitions
  arm: decompressor: define a new zImage tag
  arm: Add kexec_image_info
  arm: kexec_file: load zImage or uImage, initrd and dtb

 arch/arm/Kconfig                       |  26 +++
 arch/arm/boot/compressed/head.S        |   3 +-
 arch/arm/boot/compressed/vmlinux.lds.S |  22 +--
 arch/arm/include/asm/image.h           |  79 +++++++++
 arch/arm/include/asm/kexec.h           |  16 +-
 arch/arm/kernel/Makefile               |   5 +-
 arch/arm/kernel/kexec_uimage.c         |  80 ++++++++++
 arch/arm/kernel/kexec_zimage.c         | 197 +++++++++++++++++++++++
 arch/arm/kernel/machine_kexec.c        |  39 ++++-
 arch/arm/kernel/machine_kexec_file.c   | 211 +++++++++++++++++++++++++
 10 files changed, 660 insertions(+), 18 deletions(-)
 create mode 100644 arch/arm/include/asm/image.h
 create mode 100644 arch/arm/kernel/kexec_uimage.c
 create mode 100644 arch/arm/kernel/kexec_zimage.c
 create mode 100644 arch/arm/kernel/machine_kexec_file.c

-- 
2.26.2


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

* [PATCH v3 1/4] arm: add image header definitions
       [not found]       ` <CGME20200930183923eucas1p2241d3e1b8d4d05a2228448ff8fc4bb74@eucas1p2.samsung.com>
@ 2020-09-30 18:34         ` Łukasz Stelmach
  0 siblings, 0 replies; 35+ messages in thread
From: Łukasz Stelmach @ 2020-09-30 18:34 UTC (permalink / raw)
  To: Russell King, Masahiro Yamada, Nick Desaulniers, Thomas Gleixner,
	Enrico Weigelt, Kees Cook, Ingo Molnar, Ben Dooks,
	linux-arm-kernel, linux-kernel, AKASHI Takahiro, kexec,
	Dave Young
  Cc: Bartlomiej Zolnierkiewicz, Marek Szyprowski, Łukasz Stelmach

This structure will be used later by kexec_file loader.

Signed-off-by: Łukasz Stelmach <l.stelmach@samsung.com>
---
 arch/arm/boot/compressed/head.S        |  3 +-
 arch/arm/boot/compressed/vmlinux.lds.S | 13 ++-----
 arch/arm/include/asm/image.h           | 50 ++++++++++++++++++++++++++
 3 files changed, 55 insertions(+), 11 deletions(-)
 create mode 100644 arch/arm/include/asm/image.h

diff --git a/arch/arm/boot/compressed/head.S b/arch/arm/boot/compressed/head.S
index 2e04ec5b5446..3099002ad13a 100644
--- a/arch/arm/boot/compressed/head.S
+++ b/arch/arm/boot/compressed/head.S
@@ -7,6 +7,7 @@
  */
 #include <linux/linkage.h>
 #include <asm/assembler.h>
+#include <asm/image.h>
 #include <asm/v7m.h>
 
 #include "efi-header.S"
@@ -206,7 +207,7 @@ start:
 		.word	_magic_start	@ absolute load/run zImage address
 		.word	_magic_end	@ zImage end address
 		.word	0x04030201	@ endianness flag
-		.word	0x45454545	@ another magic number to indicate
+		.word	ARM_ZIMAGE_MAGIC2 @ another magic number to indicate
 		.word	_magic_table	@ additional data table
 
 		__EFI_HEADER
diff --git a/arch/arm/boot/compressed/vmlinux.lds.S b/arch/arm/boot/compressed/vmlinux.lds.S
index 1bcb68ac4b01..a6b151112ac5 100644
--- a/arch/arm/boot/compressed/vmlinux.lds.S
+++ b/arch/arm/boot/compressed/vmlinux.lds.S
@@ -4,14 +4,7 @@
  */
 #include <asm/vmlinux.lds.h>
 
-#ifdef CONFIG_CPU_ENDIAN_BE8
-#define ZIMAGE_MAGIC(x) ( (((x) >> 24) & 0x000000ff) | \
-			  (((x) >>  8) & 0x0000ff00) | \
-			  (((x) <<  8) & 0x00ff0000) | \
-			  (((x) << 24) & 0xff000000) )
-#else
-#define ZIMAGE_MAGIC(x) (x)
-#endif
+#include <asm/image.h>
 
 OUTPUT_ARCH(arm)
 ENTRY(_start)
@@ -45,7 +38,7 @@ SECTIONS
   .table : ALIGN(4) {
     _table_start = .;
     LONG(ZIMAGE_MAGIC(6))
-    LONG(ZIMAGE_MAGIC(0x5a534c4b))
+    LONG(ARM_ZIMAGE_MAGIC3)
     LONG(ZIMAGE_MAGIC(__piggy_size_addr - _start))
     LONG(ZIMAGE_MAGIC(_kernel_bss_size))
     LONG(ZIMAGE_MAGIC(TEXT_OFFSET))
@@ -116,7 +109,7 @@ SECTIONS
     _edata_real = .;
   }
 
-  _magic_sig = ZIMAGE_MAGIC(0x016f2818);
+  _magic_sig = ARM_ZIMAGE_MAGIC1;
   _magic_start = ZIMAGE_MAGIC(_start);
   _magic_end = ZIMAGE_MAGIC(_edata);
   _magic_table = ZIMAGE_MAGIC(_table_start - _start);
diff --git a/arch/arm/include/asm/image.h b/arch/arm/include/asm/image.h
new file mode 100644
index 000000000000..8150b9490e86
--- /dev/null
+++ b/arch/arm/include/asm/image.h
@@ -0,0 +1,50 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+#ifndef __ASM_IMAGE_H
+#define __ASM_IMAGE_H
+
+#ifdef CONFIG_CPU_ENDIAN_BE8
+#define ZIMAGE_MAGIC(x) ((((x) >> 24) & 0x000000ff) | \
+			 (((x) >>  8) & 0x0000ff00) |  \
+			 (((x) <<  8) & 0x00ff0000) |  \
+			 (((x) << 24) & 0xff000000))
+#else
+#define ZIMAGE_MAGIC(x) (x)
+#endif
+
+#define ARM_ZIMAGE_MAGIC1 ZIMAGE_MAGIC(0x016f2818)
+#define ARM_ZIMAGE_MAGIC2 (0x45454545)
+#define ARM_ZIMAGE_MAGIC3 ZIMAGE_MAGIC(0x5a534c4b)
+
+#ifndef __ASSEMBLY__
+
+#include <linux/types.h>
+#include <asm/setup.h>
+
+/* ARM zImage header format */
+struct arm_zimage_header {
+	__le32 code[9];
+	__le32 magic;
+	__le32 start;
+	__le32 end;
+	__le32 endian;
+	__le32 magic2;
+	__le32 extension_tag_offset;
+};
+
+struct arm_zimage_tag {
+	struct tag_header hdr;
+	union {
+#define ZIMAGE_TAG_KRNL_SIZE ARM_ZIMAGE_MAGIC3
+		struct zimage_krnl_size {
+			__le32 size_ptr;
+			__le32 bss_size;
+			__le32 text_offset;
+			__le32 malloc_size;
+		} krnl_size;
+	} u;
+};
+
+#endif /* __ASSEMBLY__ */
+
+#endif /* __ASM_IMAGE_H */
-- 
2.26.2


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

* [PATCH v3 2/4] arm: decompressor: define a new zImage tag
       [not found]       ` <CGME20200930183924eucas1p2869520cc28e705073cb08c37c1e2fc6d@eucas1p2.samsung.com>
@ 2020-09-30 18:34         ` Łukasz Stelmach
  0 siblings, 0 replies; 35+ messages in thread
From: Łukasz Stelmach @ 2020-09-30 18:34 UTC (permalink / raw)
  To: Russell King, Masahiro Yamada, Nick Desaulniers, Thomas Gleixner,
	Enrico Weigelt, Kees Cook, Ingo Molnar, Ben Dooks,
	linux-arm-kernel, linux-kernel, AKASHI Takahiro, kexec,
	Dave Young
  Cc: Bartlomiej Zolnierkiewicz, Marek Szyprowski, Łukasz Stelmach

Add DCSZ tag which holds dynamic memory (stack, bss, malloc pool)
requirements of the decompressor code.

Signed-off-by: Łukasz Stelmach <l.stelmach@samsung.com>
---
 arch/arm/boot/compressed/vmlinux.lds.S | 9 ++++++++-
 arch/arm/include/asm/image.h           | 3 +++
 2 files changed, 11 insertions(+), 1 deletion(-)

diff --git a/arch/arm/boot/compressed/vmlinux.lds.S b/arch/arm/boot/compressed/vmlinux.lds.S
index a6b151112ac5..3e7443b52f5b 100644
--- a/arch/arm/boot/compressed/vmlinux.lds.S
+++ b/arch/arm/boot/compressed/vmlinux.lds.S
@@ -43,6 +43,11 @@ SECTIONS
     LONG(ZIMAGE_MAGIC(_kernel_bss_size))
     LONG(ZIMAGE_MAGIC(TEXT_OFFSET))
     LONG(ZIMAGE_MAGIC(MALLOC_SIZE))
+    LONG(ZIMAGE_MAGIC(3))
+    LONG(ARM_ZIMAGE_MAGIC4)
+    LONG(ZIMAGE_MAGIC((_end - __bss_start) +
+                      (_stack_end - _stack_start) +
+                      MALLOC_SIZE))
     LONG(0)
     _table_end = .;
   }
@@ -117,10 +122,12 @@ SECTIONS
   . = BSS_START;
   __bss_start = .;
   .bss			: { *(.bss) }
+  . = ALIGN(8);		/* the stack must be 64-bit aligned and adjoin bss */
   _end = .;
 
-  . = ALIGN(8);		/* the stack must be 64-bit aligned */
+  _stack_start = .;
   .stack		: { *(.stack) }
+  _stack_end = .;
 
   PROVIDE(__pecoff_data_size = ALIGN(512) - ADDR(.data));
   PROVIDE(__pecoff_end = ALIGN(512));
diff --git a/arch/arm/include/asm/image.h b/arch/arm/include/asm/image.h
index 8150b9490e86..8be6dbc69fbb 100644
--- a/arch/arm/include/asm/image.h
+++ b/arch/arm/include/asm/image.h
@@ -15,6 +15,7 @@
 #define ARM_ZIMAGE_MAGIC1 ZIMAGE_MAGIC(0x016f2818)
 #define ARM_ZIMAGE_MAGIC2 (0x45454545)
 #define ARM_ZIMAGE_MAGIC3 ZIMAGE_MAGIC(0x5a534c4b)
+#define ARM_ZIMAGE_MAGIC4 ZIMAGE_MAGIC(0x5a534344)
 
 #ifndef __ASSEMBLY__
 
@@ -42,6 +43,8 @@ struct arm_zimage_tag {
 			__le32 text_offset;
 			__le32 malloc_size;
 		} krnl_size;
+#define ZIMAGE_TAG_ZIMAGE_MEM ARM_ZIMAGE_MAGIC4
+		__le32 zimage_mem;
 	} u;
 };
 
-- 
2.26.2


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

* [PATCH v3 3/4] arm: Add kexec_image_info
       [not found]       ` <CGME20200930183924eucas1p1eba72052e1723ce75e00cbadbe03b6fa@eucas1p1.samsung.com>
@ 2020-09-30 18:34         ` Łukasz Stelmach
  0 siblings, 0 replies; 35+ messages in thread
From: Łukasz Stelmach @ 2020-09-30 18:34 UTC (permalink / raw)
  To: Russell King, Masahiro Yamada, Nick Desaulniers, Thomas Gleixner,
	Enrico Weigelt, Kees Cook, Ingo Molnar, Ben Dooks,
	linux-arm-kernel, linux-kernel, AKASHI Takahiro, kexec,
	Dave Young
  Cc: Bartlomiej Zolnierkiewicz, Marek Szyprowski, Łukasz Stelmach

Add kexec_image_info to print detailed information about a kexec image.

Signed-off-by: Łukasz Stelmach <l.stelmach@samsung.com>
---
 arch/arm/kernel/machine_kexec.c | 28 ++++++++++++++++++++++++++++
 1 file changed, 28 insertions(+)

diff --git a/arch/arm/kernel/machine_kexec.c b/arch/arm/kernel/machine_kexec.c
index 5d84ad333f05..a0c229eec0b2 100644
--- a/arch/arm/kernel/machine_kexec.c
+++ b/arch/arm/kernel/machine_kexec.c
@@ -29,6 +29,32 @@ extern unsigned long kexec_boot_atags;
 
 static atomic_t waiting_for_crash_ipi;
 
+/**
+ * kexec_image_info - For debugging output.
+ */
+#define kexec_image_info(_i) _kexec_image_info(__func__, __LINE__, _i)
+static void _kexec_image_info(const char *func, int line,
+	const struct kimage *kimage)
+{
+	unsigned long i;
+
+	pr_debug("%s:%d:\n", func, line);
+	pr_debug("  kexec kimage info:\n");
+	pr_debug("    type:        %d\n", kimage->type);
+	pr_debug("    start:       %lx\n", kimage->start);
+	pr_debug("    head:        %lx\n", kimage->head);
+	pr_debug("    nr_segments: %lu\n", kimage->nr_segments);
+
+	for (i = 0; i < kimage->nr_segments; i++) {
+		pr_debug("      segment[%lu]: %08lx - %08lx, 0x%x bytes, %lu pages\n",
+			i,
+			kimage->segment[i].mem,
+			kimage->segment[i].mem + kimage->segment[i].memsz,
+			kimage->segment[i].memsz,
+			kimage->segment[i].memsz /  PAGE_SIZE);
+	}
+}
+
 /*
  * Provide a dummy crash_notes definition while crash dump arrives to arm.
  * This prevents breakage of crash_notes attribute in kernel/ksysfs.c.
@@ -40,6 +66,8 @@ int machine_kexec_prepare(struct kimage *image)
 	__be32 header;
 	int i, err;
 
+	kexec_image_info(image);
+
 	image->arch.kernel_r2 = image->start - KEXEC_ARM_ZIMAGE_OFFSET
 				     + KEXEC_ARM_ATAGS_OFFSET;
 
-- 
2.26.2


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

* [PATCH v3 4/4] arm: kexec_file: load zImage or uImage, initrd and dtb
       [not found]       ` <CGME20200930183924eucas1p281730f3d651fc2c78d6a95e47a2c5220@eucas1p2.samsung.com>
@ 2020-09-30 18:34         ` Łukasz Stelmach
  2020-10-01 10:09           ` kernel test robot
  0 siblings, 1 reply; 35+ messages in thread
From: Łukasz Stelmach @ 2020-09-30 18:34 UTC (permalink / raw)
  To: Russell King, Masahiro Yamada, Nick Desaulniers, Thomas Gleixner,
	Enrico Weigelt, Kees Cook, Ingo Molnar, Ben Dooks,
	linux-arm-kernel, linux-kernel, AKASHI Takahiro, kexec,
	Dave Young
  Cc: Bartlomiej Zolnierkiewicz, Marek Szyprowski, Łukasz Stelmach

This is kexec_file_load implementation for ARM. It loads zImage and
initrd from file descripters and resuses DTB.

Most code is derived from arm64 kexec_file_load implementation
and from kexec-tools.

Cc: AKASHI Takahiro <takahiro.akashi@linaro.org>
Signed-off-by: Łukasz Stelmach <l.stelmach@samsung.com>
---
 arch/arm/Kconfig                     |  26 ++++
 arch/arm/include/asm/image.h         |  26 ++++
 arch/arm/include/asm/kexec.h         |  16 +-
 arch/arm/kernel/Makefile             |   5 +-
 arch/arm/kernel/kexec_uimage.c       |  80 ++++++++++
 arch/arm/kernel/kexec_zimage.c       | 197 +++++++++++++++++++++++++
 arch/arm/kernel/machine_kexec.c      |  11 +-
 arch/arm/kernel/machine_kexec_file.c | 211 +++++++++++++++++++++++++++
 8 files changed, 566 insertions(+), 6 deletions(-)
 create mode 100644 arch/arm/kernel/kexec_uimage.c
 create mode 100644 arch/arm/kernel/kexec_zimage.c
 create mode 100644 arch/arm/kernel/machine_kexec_file.c

diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index fe2f17eb2b50..65e5540f3ed1 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -1873,6 +1873,32 @@ config KEXEC
 	  is properly shutdown, so do not be surprised if this code does not
 	  initially work for you.
 
+config KEXEC_FILE
+	bool "Kexec file based system call (EXPERIMENTAL)"
+	depends on (!SMP || PM_SLEEP_SMP)
+	depends on MMU
+	depends on USE_OF
+	select KEXEC_CORE
+	select CRC32
+	help
+	  This is a new version of kexec system call. This system call is
+	  file based and takes file descriptors as system call argument
+	  for kernel and initramfs as opposed to list of segments as
+	  accepted by previous system call.
+
+	  The kernel to be loaded MUST support Flattened Device Tree
+	  (selected with CONFIG_USE_OF).
+
+config KEXEC_FILE_UIMAGE
+	bool "Load legacy uImage files with kexec_file_load() (EXPERIMENTAL)"
+	depends on KEXEC_FILE
+	default n
+	help
+	  This options enables support for the legacy uImage files as
+	  created by mkimage. These are not the new FIT files.
+
+	  If unsure say N.
+
 config ATAGS_PROC
 	bool "Export atags in procfs"
 	depends on ATAGS && KEXEC
diff --git a/arch/arm/include/asm/image.h b/arch/arm/include/asm/image.h
index 8be6dbc69fbb..15c4fe031d90 100644
--- a/arch/arm/include/asm/image.h
+++ b/arch/arm/include/asm/image.h
@@ -8,8 +8,13 @@
 			 (((x) >>  8) & 0x0000ff00) |  \
 			 (((x) <<  8) & 0x00ff0000) |  \
 			 (((x) << 24) & 0xff000000))
+#define UIMAGE_MAGIC(x) (x)
 #else
 #define ZIMAGE_MAGIC(x) (x)
+#define UIMAGE_MAGIC(x) ((((x) >> 24) & 0x000000ff) | \
+			 (((x) >>  8) & 0x0000ff00) |  \
+			 (((x) <<  8) & 0x00ff0000) |  \
+			 (((x) << 24) & 0xff000000))
 #endif
 
 #define ARM_ZIMAGE_MAGIC1 ZIMAGE_MAGIC(0x016f2818)
@@ -17,6 +22,12 @@
 #define ARM_ZIMAGE_MAGIC3 ZIMAGE_MAGIC(0x5a534c4b)
 #define ARM_ZIMAGE_MAGIC4 ZIMAGE_MAGIC(0x5a534344)
 
+#define ARM_UIMAGE_MAGIC UIMAGE_MAGIC(0x27051956)
+#define ARM_UIMAGE_NAME_LEN		32
+#define ARM_UIMAGE_TYPE_KERNEL		2
+#define ARM_UIMAGE_TYPE_KERNEL_NOLOAD	14
+#define ARM_UIMAGE_ARCH_ARM		2
+
 #ifndef __ASSEMBLY__
 
 #include <linux/types.h>
@@ -33,6 +44,21 @@ struct arm_zimage_header {
 	__le32 extension_tag_offset;
 };
 
+struct arm_uimage_header {
+	__be32 magic;
+	__be32 hdr_crc;
+	__be32 time;
+	__be32 size;
+	__be32 load;
+	__be32 entry;
+	__be32 crc;
+	__u8   os;
+	__u8   arch;
+	__u8   type;
+	__u8   comp;
+	__u8   name[ARM_UIMAGE_NAME_LEN];
+};
+
 struct arm_zimage_tag {
 	struct tag_header hdr;
 	union {
diff --git a/arch/arm/include/asm/kexec.h b/arch/arm/include/asm/kexec.h
index 22751b5b5735..8e4d0d92269b 100644
--- a/arch/arm/include/asm/kexec.h
+++ b/arch/arm/include/asm/kexec.h
@@ -2,7 +2,7 @@
 #ifndef _ARM_KEXEC_H
 #define _ARM_KEXEC_H
 
-#ifdef CONFIG_KEXEC
+#if defined(CONFIG_KEXEC) || defined(CONFIG_KEXEC_FILE)
 
 /* Maximum physical address we can use pages from */
 #define KEXEC_SOURCE_MEMORY_LIMIT (-1UL)
@@ -83,6 +83,20 @@ static inline struct page *boot_pfn_to_page(unsigned long boot_pfn)
 }
 #define boot_pfn_to_page boot_pfn_to_page
 
+#ifdef CONFIG_KEXEC_FILE
+
+extern const struct kexec_file_ops kexec_zimage_ops;
+extern const struct kexec_file_ops kexec_uimage_ops;
+
+struct kimage;
+
+extern int load_other_segments(struct kimage *image,
+		unsigned long kernel_load_addr, unsigned long kernel_size,
+		char *initrd, unsigned long initrd_len,
+		unsigned long initrd_offset, char *cmdline);
+
+#endif /* CONFIG_KEXEC_FILE */
+
 #endif /* __ASSEMBLY__ */
 
 #endif /* CONFIG_KEXEC */
diff --git a/arch/arm/kernel/Makefile b/arch/arm/kernel/Makefile
index 89e5d864e923..453ecf7305e2 100644
--- a/arch/arm/kernel/Makefile
+++ b/arch/arm/kernel/Makefile
@@ -3,6 +3,7 @@
 # Makefile for the linux kernel.
 #
 
+CFLAGS_kexec_zimage.o := -DTEXT_OFFSET=$(TEXT_OFFSET)
 CPPFLAGS_vmlinux.lds := -DTEXT_OFFSET=$(TEXT_OFFSET)
 AFLAGS_head.o        := -DTEXT_OFFSET=$(TEXT_OFFSET)
 
@@ -56,7 +57,9 @@ obj-$(CONFIG_FUNCTION_TRACER)	+= entry-ftrace.o
 obj-$(CONFIG_DYNAMIC_FTRACE)	+= ftrace.o insn.o patch.o
 obj-$(CONFIG_FUNCTION_GRAPH_TRACER)	+= ftrace.o insn.o patch.o
 obj-$(CONFIG_JUMP_LABEL)	+= jump_label.o insn.o patch.o
-obj-$(CONFIG_KEXEC)		+= machine_kexec.o relocate_kernel.o
+obj-$(CONFIG_KEXEC_CORE)	+= machine_kexec.o relocate_kernel.o
+obj-$(CONFIG_KEXEC_FILE)	+= machine_kexec_file.o kexec_zimage.o
+obj-$(CONFIG_KEXEC_FILE_UIMAGE)	+= kexec_uimage.o
 # Main staffs in KPROBES are in arch/arm/probes/ .
 obj-$(CONFIG_KPROBES)		+= patch.o insn.o
 obj-$(CONFIG_OABI_COMPAT)	+= sys_oabi-compat.o
diff --git a/arch/arm/kernel/kexec_uimage.c b/arch/arm/kernel/kexec_uimage.c
new file mode 100644
index 000000000000..47033574e24e
--- /dev/null
+++ b/arch/arm/kernel/kexec_uimage.c
@@ -0,0 +1,80 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Kexec uImage loader
+ *
+ * Copyright (C) 2020 Samsung Electronics
+ * Author: Łukasz Stelmach <l.stelmach@samsung.com>
+ */
+
+#define pr_fmt(fmt)	"kexec_file(uImage): " fmt
+
+#include <asm/image.h>
+#include <linux/crc32.h>
+#include <linux/err.h>
+#include <linux/kexec.h>
+
+#define crc32_ones(crc, buf, len) \
+	(crc32(crc ^ 0xffffffff, buf, len) ^ 0xffffffff)
+
+static int uimage_probe(const char *uimage_buf, unsigned long uimage_len)
+{
+	const struct arm_uimage_header *h =
+		(struct arm_uimage_header *) uimage_buf;
+	struct arm_uimage_header uhdr;
+	unsigned long zoff = sizeof(struct arm_uimage_header);
+	uint32_t crc;
+
+	if (h->magic != ARM_UIMAGE_MAGIC)
+		return -EINVAL;
+
+	if (h->type != ARM_UIMAGE_TYPE_KERNEL &&
+	    h->type != ARM_UIMAGE_TYPE_KERNEL_NOLOAD){
+		pr_debug("Invalid image type: %d\n", h->type);
+		return -EINVAL;
+	}
+
+	if (h->arch != ARM_UIMAGE_ARCH_ARM) {
+		pr_debug("Invalidy image arch: %d\n", h->arch);
+		return -EINVAL;
+	}
+
+	memcpy((char *)&uhdr, h, sizeof(uhdr));
+	crc = be32_to_cpu(uhdr.hdr_crc);
+	uhdr.hdr_crc = 0;
+
+	if (crc32_ones(0, (char *)&uhdr, sizeof(uhdr)) != crc) {
+		pr_debug("Corrupt header, CRC do not match\n");
+		return -EINVAL;
+	}
+
+	crc = be32_to_cpu(uhdr.crc);
+	if (crc32_ones(0, uimage_buf + zoff, uimage_len - zoff) != crc) {
+		pr_debug("Corrupt zImage, CRC do not match\n");
+		return -EINVAL;
+	}
+
+	return kexec_zimage_ops.probe(uimage_buf + zoff,
+				      uimage_len - zoff);
+}
+
+static void *uimage_load(struct kimage *image,
+				char *uimage, unsigned long uimage_len,
+				char *initrd, unsigned long initrd_len,
+				char *cmdline, unsigned long cmdline_len)
+{
+	const struct arm_uimage_header *h =
+		(struct arm_uimage_header *) uimage;
+	unsigned long zimage_offset = sizeof(struct arm_uimage_header);
+
+	pr_debug("Loading uImage");
+	return kexec_zimage_ops.load(image,
+				     uimage + zimage_offset,
+				     uimage_len - zimage_offset,
+				     initrd, initrd_len,
+				     cmdline, cmdline_len);
+}
+
+const struct kexec_file_ops kexec_uimage_ops = {
+	.probe = uimage_probe,
+	.load = uimage_load,
+};
diff --git a/arch/arm/kernel/kexec_zimage.c b/arch/arm/kernel/kexec_zimage.c
new file mode 100644
index 000000000000..543229a42793
--- /dev/null
+++ b/arch/arm/kernel/kexec_zimage.c
@@ -0,0 +1,197 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Kexec zImage loader
+ *
+ * Copyright (C) 2020 Samsung Electronics
+ * Authors:
+ *     Łukasz Stelmach <l.stelmach@samsung.com>
+ *
+ * Based on earlier works for kexec-tools by
+ *     Russell King <rmk+kernel@armlinux.org.uk>
+ *
+ */
+
+#define pr_fmt(fmt)	"kexec_file(zImage): " fmt
+
+#include <asm/image.h>
+#include <asm/unaligned.h>
+#include <linux/err.h>
+#include <linux/kexec.h>
+#include <linux/memblock.h>
+
+#define byte_size(t)    ((t)->hdr.size << 2)
+
+/*
+ * This function and several pieces below have been taken from
+ * kexec-tools/kexec/arch/arm/kexec-zImage-arm.c
+ */
+static const void *find_extension_tag(const char *buf,
+						       unsigned long len,
+						       uint32_t tag_id)
+{
+	const struct arm_zimage_header *h = (const struct arm_zimage_header *)buf;
+	const struct arm_zimage_tag *tag;
+	uint32_t offset, size;
+	uint32_t max = len - sizeof(struct tag_header);
+
+	if (len < sizeof(*h) ||
+	    h->magic != ARM_ZIMAGE_MAGIC1 ||
+	    h->magic2 != ARM_ZIMAGE_MAGIC2)
+		return NULL;
+
+	for (offset = h->extension_tag_offset;
+	     (tag = (void *)(buf + offset)) != NULL &&
+		     offset < max &&
+		     (size = le32_to_cpu(byte_size(tag))) != 0 &&
+		     offset + size < len;
+	     offset += size) {
+		pr_debug("  offset 0x%08x tag 0x%08x size %u\n",
+			  offset, le32_to_cpu(tag->hdr.tag), size);
+		if (tag->hdr.tag == tag_id)
+			return tag;
+	}
+
+	return NULL;
+}
+
+static int zimage_probe(const char *kernel_buf, unsigned long kernel_len)
+{
+	const struct arm_zimage_header *h =
+		(struct arm_zimage_header *)(kernel_buf);
+
+	if (!h || (kernel_len < sizeof(*h)))
+		return -EINVAL;
+
+	if ((h->magic != ARM_ZIMAGE_MAGIC1) ||
+	    (h->magic2 != ARM_ZIMAGE_MAGIC2))
+		return -EINVAL;
+
+	return 0;
+}
+
+
+#if defined(DEBUG)
+#define debug_offsets() ({			\
+	pr_debug("Image offsets:\n");		\
+	pr_debug("  kernel 0x%08lx 0x%08lx\n", kernel_offset, kernel_len); \
+	pr_debug("  zimage 0x%08lx 0x%08lx\n", zimage_offset, zimage_len); \
+	pr_debug("  initrd 0x%08lx 0x%08lx\n", initrd_offset, initrd_len); \
+})
+#else
+#define debug_offsets()
+#endif
+
+static void *zimage_load(struct kimage *image,
+				char *zimage, unsigned long zimage_len,
+				char *initrd, unsigned long initrd_len,
+				char *cmdline, unsigned long cmdline_len)
+{
+	struct arm_zimage_header *h;
+	struct kexec_buf kbuf;
+	struct kexec_segment *zimage_segment;
+	const struct arm_zimage_tag *tag;
+	int ret = -EINVAL;
+
+	unsigned long zimage_mem = 0x20000; /* malloc 64kB + stack 4 kB + some bss */
+	unsigned long kernel_len = zimage_len * 5; /* 5:1 compression */
+	unsigned long kernel_offset = memblock_start_of_DRAM();
+	unsigned long zimage_offset = kernel_offset +
+		ALIGN(kernel_len, PAGE_SIZE);
+	unsigned long initrd_offset = zimage_offset +
+		ALIGN(zimage_len + zimage_mem, PAGE_SIZE);
+
+	if (image->type == KEXEC_TYPE_CRASH) {
+		kernel_offset += crashk_res.start;
+		zimage_offset += crashk_res.start;
+		initrd_offset += crashk_res.start;
+	}
+	debug_offsets();
+
+	h = (struct arm_zimage_header *)zimage;
+
+	tag = find_extension_tag(zimage, zimage_len, ZIMAGE_TAG_KRNL_SIZE);
+	if (tag) {
+		uint32_t *p = (void *)zimage +
+			le32_to_cpu(tag->u.krnl_size.size_ptr);
+		uint32_t edata_size = le32_to_cpu(get_unaligned(p));
+		uint32_t bss_size = le32_to_cpu(tag->u.krnl_size.bss_size);
+		uint32_t text_offset = le32_to_cpu(tag->u.krnl_size.text_offset);
+
+		kernel_offset += ALIGN(text_offset, PAGE_SIZE);
+		kernel_len = edata_size + bss_size;
+
+		pr_debug("Decompressed kernel sizes:\n");
+		pr_debug(" text+data 0x%08lx bss 0x%08lx total 0x%08lx\n",
+			 (unsigned long)edata_size,
+			 (unsigned long)bss_size,
+			 (unsigned long)kernel_len);
+
+		zimage_offset = kernel_offset + ALIGN(edata_size, PAGE_SIZE);
+		initrd_offset = zimage_offset +
+			max(ALIGN(zimage_len + 0x20000, PAGE_SIZE),
+			    ALIGN((unsigned long)bss_size, PAGE_SIZE));
+		debug_offsets();
+	}
+
+	tag = find_extension_tag(zimage, zimage_len,
+				 ZIMAGE_TAG_ZIMAGE_MEM);
+	if (tag) {
+		uint32_t zimage_mem = le32_to_cpu(tag->u.zimage_mem);
+
+		pr_debug("Decompressor requires %d bytes of memory\n", zimage_mem);
+
+		initrd_offset = max(ALIGN(zimage_offset + zimage_len + zimage_mem, PAGE_SIZE),
+				    ALIGN(kernel_offset + kernel_len, PAGE_SIZE));
+		debug_offsets();
+	}
+
+	/*
+	 * zImage MUST be loaded into the first 128 MiB of physical
+	 * memory for proper memory detection. Should the uncompressed
+	 * kernel be larger than 128 MiB, zImage relocation becomes
+	 * unavoidable and it is best to rely on the relocation code.
+	 */
+	if (((zimage_offset - kernel_offset) + PAGE_SIZE + 0x8000) >= SZ_128M) {
+		pr_debug("The kernel is too big (%ld MiB) to avoid "
+			 "zImage relocation. Loading zimage at 0x%08lx\n",
+			 ((zimage_offset - kernel_offset) >> 20),
+			 kernel_offset);
+		zimage_offset = kernel_offset;
+	}
+
+	kbuf.image = image;
+	kbuf.top_down = false;
+
+	kbuf.buf_min = zimage_offset;
+	kbuf.buf_max = ULONG_MAX;
+	kbuf.buffer = zimage;
+	kbuf.bufsz = zimage_len;
+	kbuf.buf_align = PAGE_SIZE;
+
+	kbuf.mem = KEXEC_BUF_MEM_UNKNOWN;
+	kbuf.memsz = zimage_len;
+
+	ret = kexec_add_buffer(&kbuf);
+	if (ret)
+		return ERR_PTR(ret);
+
+	pr_debug("Loaded zImage at 0x%lx bufsz=0x%lx memsz=0x%lx\n",
+		 kbuf.mem, kbuf.bufsz, kbuf.memsz);
+
+	initrd_offset += kbuf.mem - zimage_offset;
+	debug_offsets();
+
+	zimage_segment = &image->segment[image->nr_segments - 1];
+	image->start = zimage_segment->mem;
+
+	ret = load_other_segments(image,
+				  zimage_segment->mem, zimage_segment->memsz,
+				  initrd, initrd_len, initrd_offset,
+				  cmdline);
+	return ERR_PTR(ret);
+}
+
+const struct kexec_file_ops kexec_zimage_ops = {
+	.probe = zimage_probe,
+	.load = zimage_load,
+};
diff --git a/arch/arm/kernel/machine_kexec.c b/arch/arm/kernel/machine_kexec.c
index a0c229eec0b2..b349d6b8d18c 100644
--- a/arch/arm/kernel/machine_kexec.c
+++ b/arch/arm/kernel/machine_kexec.c
@@ -91,10 +91,13 @@ int machine_kexec_prepare(struct kimage *image)
 					       current_segment->memsz))
 			return -EINVAL;
 
-		err = get_user(header, (__be32*)current_segment->buf);
-		if (err)
-			return err;
-
+		if (image->file_mode) {
+			header = *(__be32 *)current_segment->buf;
+		} else {
+			err = get_user(header, (__be32 *)current_segment->buf);
+			if (err)
+				return err;
+		}
 		if (header == cpu_to_be32(OF_DT_HEADER))
 			image->arch.kernel_r2 = current_segment->mem;
 	}
diff --git a/arch/arm/kernel/machine_kexec_file.c b/arch/arm/kernel/machine_kexec_file.c
new file mode 100644
index 000000000000..a632d351602c
--- /dev/null
+++ b/arch/arm/kernel/machine_kexec_file.c
@@ -0,0 +1,211 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * kexec_file for arm
+ *
+ * Copyright (C) 2018 Linaro Limited
+ * Copyright (C) 2020 Samsung Electronics
+ * Authors:
+ *     AKASHI Takahiro <takahiro.akashi@linaro.org>
+ *     Łukasz Stelmach <l.stelmach@samsung.com>
+ *
+ */
+
+#define pr_fmt(fmt) "kexec_file: " fmt
+
+#include <linux/kexec.h>
+#include <linux/libfdt.h>
+#include <linux/of_fdt.h>
+#include <linux/random.h>
+
+/* relevant device tree properties */
+#define FDT_PROP_INITRD_START	"linux,initrd-start"
+#define FDT_PROP_INITRD_END	"linux,initrd-end"
+#define FDT_PROP_BOOTARGS	"bootargs"
+#define FDT_PROP_RNG_SEED	"rng-seed"
+
+static int setup_dtb(struct kimage *image,
+		     unsigned long initrd_load_addr, unsigned long initrd_len,
+		     char *cmdline, void *dtb)
+{
+	int off, ret;
+
+	ret = fdt_path_offset(dtb, "/chosen");
+	if (ret < 0)
+		goto out;
+
+	off = ret;
+
+	/* add bootargs */
+	if (cmdline) {
+		ret = fdt_setprop_string(dtb, off, FDT_PROP_BOOTARGS, cmdline);
+		if (ret)
+			goto out;
+	} else {
+		ret = fdt_delprop(dtb, off, FDT_PROP_BOOTARGS);
+		if (ret && (ret != -FDT_ERR_NOTFOUND))
+			goto out;
+	}
+
+	/* add initrd-* */
+	if (initrd_load_addr) {
+		ret = fdt_setprop_u64(dtb, off, FDT_PROP_INITRD_START,
+				      initrd_load_addr);
+		if (ret)
+			goto out;
+
+		ret = fdt_setprop_u64(dtb, off, FDT_PROP_INITRD_END,
+				      initrd_load_addr + initrd_len);
+		if (ret)
+			goto out;
+	} else {
+		ret = fdt_delprop(dtb, off, FDT_PROP_INITRD_START);
+		if (ret && (ret != -FDT_ERR_NOTFOUND))
+			goto out;
+
+		ret = fdt_delprop(dtb, off, FDT_PROP_INITRD_END);
+		if (ret && (ret != -FDT_ERR_NOTFOUND))
+			goto out;
+	}
+
+	/* add rng-seed */
+	if (rng_is_initialized()) {
+		char seed[128];
+		get_random_bytes(seed, sizeof(seed));
+
+		ret = fdt_setprop(dtb, off, FDT_PROP_RNG_SEED,
+				  seed, sizeof(seed));
+		if (ret)
+			goto out;
+	} else {
+		pr_notice("RNG is not initialised: omitting \"%s\" property\n",
+				FDT_PROP_RNG_SEED);
+		ret = 0;
+	}
+
+out:
+	if (ret)
+		return (ret == -FDT_ERR_NOSPACE) ? -ENOMEM : -EINVAL;
+
+	return 0;
+}
+/*
+ * More space needed so that we can add initrd, bootargs and kaslr-seed.
+ */
+#define DTB_EXTRA_SPACE 0x1000
+
+static int create_dtb(struct kimage *image,
+		      unsigned long initrd_load_addr, unsigned long initrd_len,
+		      char *cmdline, void **dtb)
+{
+	void *buf;
+	size_t buf_size;
+	size_t cmdline_len;
+	int ret;
+
+	cmdline_len = cmdline ? strlen(cmdline) : 0;
+	buf_size = fdt_totalsize(initial_boot_params)
+			+ cmdline_len + DTB_EXTRA_SPACE;
+
+	for (;;) {
+		buf = vmalloc(buf_size);
+		if (!buf)
+			return -ENOMEM;
+
+		/* duplicate a device tree blob */
+		ret = fdt_open_into(initial_boot_params, buf, buf_size);
+		if (ret)
+			return -EINVAL;
+
+		ret = setup_dtb(image, initrd_load_addr, initrd_len,
+				cmdline, buf);
+		if (ret) {
+			vfree(buf);
+			if (ret == -ENOMEM) {
+				/* unlikely, but just in case */
+				buf_size += DTB_EXTRA_SPACE;
+				continue;
+			} else {
+				return ret;
+			}
+		}
+
+		/* trim it */
+		fdt_pack(buf);
+		*dtb = buf;
+
+		return 0;
+	}
+}
+
+int load_other_segments(struct kimage *image,
+			unsigned long zimage_load_addr,
+			unsigned long zimage_len,
+			char *initrd,
+			unsigned long initrd_len,
+			unsigned long initrd_offset,
+			char *cmdline)
+{
+	struct kexec_buf kbuf;
+	void *dtb = NULL;
+	unsigned long initrd_load_addr = 0;
+	unsigned long dtb_len;
+	int ret = 0;
+
+	kbuf.image = image;
+	/* not allocate anything below the kernel */
+	kbuf.buf_min = initrd_offset;
+	if (initrd) {
+		kbuf.buffer = initrd;
+		kbuf.bufsz = initrd_len;
+		kbuf.mem = KEXEC_BUF_MEM_UNKNOWN;
+		kbuf.memsz = initrd_len;
+		kbuf.buf_align = PAGE_SIZE;
+		kbuf.buf_max = ULONG_MAX;
+		kbuf.top_down = false;
+
+		ret = kexec_add_buffer(&kbuf);
+		if (ret)
+			goto out_err;
+
+		pr_debug("Loaded initrd at 0x%lx bufsz=0x%lx memsz=0x%lx\n",
+				kbuf.mem, kbuf.bufsz, kbuf.memsz);
+
+		initrd_load_addr = kbuf.mem;
+		kbuf.buf_min = initrd_load_addr + kbuf.memsz;
+	}
+
+	/* load dtb */
+	ret = create_dtb(image, initrd_load_addr, initrd_len, cmdline, &dtb);
+	if (ret) {
+		pr_err("Preparing for new dtb failed\n");
+		goto out_err;
+	}
+
+	dtb_len = fdt_totalsize(dtb);
+	kbuf.buffer = dtb;
+	kbuf.bufsz = dtb_len;
+	kbuf.mem = KEXEC_BUF_MEM_UNKNOWN;
+	kbuf.memsz = dtb_len;
+	kbuf.buf_align = PAGE_SIZE;
+	kbuf.buf_max = ULONG_MAX;
+	kbuf.top_down = false;
+
+	ret = kexec_add_buffer(&kbuf);
+	if (ret)
+		goto out_err;
+
+	pr_debug("Loaded dtb at 0x%lx bufsz=0x%lx memsz=0x%lx\n",
+		 kbuf.mem, kbuf.bufsz, kbuf.memsz);
+	return 0;
+out_err:
+	vfree(dtb);
+	return ret;
+}
+
+const struct kexec_file_ops * const kexec_file_loaders[] = {
+#ifdef CONFIG_KEXEC_FILE_UIMAGE
+	&kexec_uimage_ops,
+#endif
+	&kexec_zimage_ops,
+	NULL
+};
-- 
2.26.2


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

* Re: [PATCH v3 4/4] arm: kexec_file: load zImage or uImage, initrd and dtb
  2020-09-30 18:34         ` [PATCH v3 4/4] arm: kexec_file: load zImage or uImage, initrd and dtb Łukasz Stelmach
@ 2020-10-01 10:09           ` kernel test robot
  0 siblings, 0 replies; 35+ messages in thread
From: kernel test robot @ 2020-10-01 10:09 UTC (permalink / raw)
  To: Łukasz Stelmach, Russell King, Masahiro Yamada,
	Nick Desaulniers, Thomas Gleixner, Enrico Weigelt, Kees Cook,
	Ingo Molnar, Ben Dooks, linux-arm-kernel, linux-kernel
  Cc: kbuild-all

[-- Attachment #1: Type: text/plain, Size: 5999 bytes --]

Hi "Łukasz,

I love your patch! Perhaps something to improve:

[auto build test WARNING on next-20200930]
[cannot apply to arm/for-next v5.9-rc7 v5.9-rc6 v5.9-rc5 v5.9-rc7]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch]

url:    https://github.com/0day-ci/linux/commits/ukasz-Stelmach/kexec_file_load-for-arm/20201001-024045
base:    de69ee6df1cfbf3c67787d8504fd21b59da39572
config: arm-allyesconfig (attached as .config)
compiler: arm-linux-gnueabi-gcc (GCC) 9.3.0
reproduce (this is a W=1 build):
        wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
        chmod +x ~/bin/make.cross
        # https://github.com/0day-ci/linux/commit/9a7741b76697140672aba84338463032c1fc9fb8
        git remote add linux-review https://github.com/0day-ci/linux
        git fetch --no-tags linux-review ukasz-Stelmach/kexec_file_load-for-arm/20201001-024045
        git checkout 9a7741b76697140672aba84338463032c1fc9fb8
        # save the attached .config to linux build tree
        COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-9.3.0 make.cross ARCH=arm 

If you fix the issue, kindly add following tag as appropriate
Reported-by: kernel test robot <lkp@intel.com>

All warnings (new ones prefixed by >>):

   arch/arm/kernel/kexec_zimage.c: In function 'zimage_load':
>> arch/arm/kernel/kexec_zimage.c:89:28: warning: variable 'h' set but not used [-Wunused-but-set-variable]
      89 |  struct arm_zimage_header *h;
         |                            ^

vim +/h +89 arch/arm/kernel/kexec_zimage.c

    83	
    84	static void *zimage_load(struct kimage *image,
    85					char *zimage, unsigned long zimage_len,
    86					char *initrd, unsigned long initrd_len,
    87					char *cmdline, unsigned long cmdline_len)
    88	{
  > 89		struct arm_zimage_header *h;
    90		struct kexec_buf kbuf;
    91		struct kexec_segment *zimage_segment;
    92		const struct arm_zimage_tag *tag;
    93		int ret = -EINVAL;
    94	
    95		unsigned long zimage_mem = 0x20000; /* malloc 64kB + stack 4 kB + some bss */
    96		unsigned long kernel_len = zimage_len * 5; /* 5:1 compression */
    97		unsigned long kernel_offset = memblock_start_of_DRAM();
    98		unsigned long zimage_offset = kernel_offset +
    99			ALIGN(kernel_len, PAGE_SIZE);
   100		unsigned long initrd_offset = zimage_offset +
   101			ALIGN(zimage_len + zimage_mem, PAGE_SIZE);
   102	
   103		if (image->type == KEXEC_TYPE_CRASH) {
   104			kernel_offset += crashk_res.start;
   105			zimage_offset += crashk_res.start;
   106			initrd_offset += crashk_res.start;
   107		}
   108		debug_offsets();
   109	
   110		h = (struct arm_zimage_header *)zimage;
   111	
   112		tag = find_extension_tag(zimage, zimage_len, ZIMAGE_TAG_KRNL_SIZE);
   113		if (tag) {
   114			uint32_t *p = (void *)zimage +
   115				le32_to_cpu(tag->u.krnl_size.size_ptr);
   116			uint32_t edata_size = le32_to_cpu(get_unaligned(p));
   117			uint32_t bss_size = le32_to_cpu(tag->u.krnl_size.bss_size);
   118			uint32_t text_offset = le32_to_cpu(tag->u.krnl_size.text_offset);
   119	
   120			kernel_offset += ALIGN(text_offset, PAGE_SIZE);
   121			kernel_len = edata_size + bss_size;
   122	
   123			pr_debug("Decompressed kernel sizes:\n");
   124			pr_debug(" text+data 0x%08lx bss 0x%08lx total 0x%08lx\n",
   125				 (unsigned long)edata_size,
   126				 (unsigned long)bss_size,
   127				 (unsigned long)kernel_len);
   128	
   129			zimage_offset = kernel_offset + ALIGN(edata_size, PAGE_SIZE);
   130			initrd_offset = zimage_offset +
   131				max(ALIGN(zimage_len + 0x20000, PAGE_SIZE),
   132				    ALIGN((unsigned long)bss_size, PAGE_SIZE));
   133			debug_offsets();
   134		}
   135	
   136		tag = find_extension_tag(zimage, zimage_len,
   137					 ZIMAGE_TAG_ZIMAGE_MEM);
   138		if (tag) {
   139			uint32_t zimage_mem = le32_to_cpu(tag->u.zimage_mem);
   140	
   141			pr_debug("Decompressor requires %d bytes of memory\n", zimage_mem);
   142	
   143			initrd_offset = max(ALIGN(zimage_offset + zimage_len + zimage_mem, PAGE_SIZE),
   144					    ALIGN(kernel_offset + kernel_len, PAGE_SIZE));
   145			debug_offsets();
   146		}
   147	
   148		/*
   149		 * zImage MUST be loaded into the first 128 MiB of physical
   150		 * memory for proper memory detection. Should the uncompressed
   151		 * kernel be larger than 128 MiB, zImage relocation becomes
   152		 * unavoidable and it is best to rely on the relocation code.
   153		 */
   154		if (((zimage_offset - kernel_offset) + PAGE_SIZE + 0x8000) >= SZ_128M) {
   155			pr_debug("The kernel is too big (%ld MiB) to avoid "
   156				 "zImage relocation. Loading zimage at 0x%08lx\n",
   157				 ((zimage_offset - kernel_offset) >> 20),
   158				 kernel_offset);
   159			zimage_offset = kernel_offset;
   160		}
   161	
   162		kbuf.image = image;
   163		kbuf.top_down = false;
   164	
   165		kbuf.buf_min = zimage_offset;
   166		kbuf.buf_max = ULONG_MAX;
   167		kbuf.buffer = zimage;
   168		kbuf.bufsz = zimage_len;
   169		kbuf.buf_align = PAGE_SIZE;
   170	
   171		kbuf.mem = KEXEC_BUF_MEM_UNKNOWN;
   172		kbuf.memsz = zimage_len;
   173	
   174		ret = kexec_add_buffer(&kbuf);
   175		if (ret)
   176			return ERR_PTR(ret);
   177	
   178		pr_debug("Loaded zImage at 0x%lx bufsz=0x%lx memsz=0x%lx\n",
   179			 kbuf.mem, kbuf.bufsz, kbuf.memsz);
   180	
   181		initrd_offset += kbuf.mem - zimage_offset;
   182		debug_offsets();
   183	
   184		zimage_segment = &image->segment[image->nr_segments - 1];
   185		image->start = zimage_segment->mem;
   186	
   187		ret = load_other_segments(image,
   188					  zimage_segment->mem, zimage_segment->memsz,
   189					  initrd, initrd_len, initrd_offset,
   190					  cmdline);
   191		return ERR_PTR(ret);
   192	}
   193	

---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/kbuild-all@lists.01.org

[-- Attachment #2: .config.gz --]
[-- Type: application/gzip, Size: 76676 bytes --]

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

end of thread, other threads:[~2020-10-01 10:10 UTC | newest]

Thread overview: 35+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
     [not found] <CGME20200601142806eucas1p2680c5625411e7a695d8469760a926520@eucas1p2.samsung.com>
2020-06-01 14:27 ` [PATCH 0/5] kexec_file_load() for arm Łukasz Stelmach
     [not found]   ` <CGME20200601142810eucas1p1767585cf172d26aedb551d7453aa7402@eucas1p1.samsung.com>
2020-06-01 14:27     ` [PATCH 1/5] arm: decompressor: set malloc pool size for the decompressor Łukasz Stelmach
2020-06-01 14:46       ` Russell King - ARM Linux admin
     [not found]         ` <CGME20200601145652eucas1p11dcea1cea21824d0a6bfe6ab38c1cab7@eucas1p1.samsung.com>
2020-06-01 14:56           ` Lukasz Stelmach
2020-06-01 15:10             ` Russell King - ARM Linux admin
     [not found]               ` <CGME20200601165420eucas1p273e0cdb143312b9a621e2444c5daae9b@eucas1p2.samsung.com>
2020-06-01 16:54                 ` Lukasz Stelmach
     [not found]   ` <CGME20200601142810eucas1p23056f7997a880ff7d676c64703f87115@eucas1p2.samsung.com>
2020-06-01 14:27     ` [PATCH 2/5] arm: add image header definitions Łukasz Stelmach
     [not found]   ` <CGME20200601142810eucas1p1c42ff7c9b417f04bc506261726f08b4f@eucas1p1.samsung.com>
2020-06-01 14:27     ` [PATCH 3/5] arm: decompressor: define a new zImage tag Łukasz Stelmach
2020-06-01 14:55       ` Russell King - ARM Linux admin
     [not found]         ` <CGME20200601162002eucas1p28eb08a42de6f313458e9391bd5976e90@eucas1p2.samsung.com>
2020-06-01 16:19           ` Lukasz Stelmach
2020-06-01 18:25             ` Russell King - ARM Linux admin
     [not found]               ` <CGME20200601202757eucas1p11d380be9e0b2fe912a358d21e2d8dc2a@eucas1p1.samsung.com>
2020-06-01 20:27                 ` Lukasz Stelmach
2020-06-01 20:41                   ` Russell King - ARM Linux admin
     [not found]                     ` <CGME20200602161720eucas1p257e9e892ed4679ed1d168db34d089a82@eucas1p2.samsung.com>
2020-06-02 16:17                       ` Lukasz Stelmach
     [not found]   ` <CGME20200601142811eucas1p260e5a434ea7743eecdb37c4d975c5f05@eucas1p2.samsung.com>
2020-06-01 14:27     ` [PATCH 4/5] arm: Add kexec_image_info Łukasz Stelmach
2020-06-01 14:56       ` Russell King - ARM Linux admin
     [not found]         ` <CGME20200601163034eucas1p1f9c726b605c18bf3944254cd83dd67b3@eucas1p1.samsung.com>
2020-06-01 16:30           ` Lukasz Stelmach
     [not found]   ` <CGME20200601142811eucas1p1604c8e6ca06c09f1ec821ea5e1918c53@eucas1p1.samsung.com>
2020-06-01 14:27     ` [PATCH 5/5] arm: kexec_file: load zImage or uImage, initrd and dtb Łukasz Stelmach
2020-06-01 15:07       ` Russell King - ARM Linux admin
2020-06-01 15:14         ` Russell King - ARM Linux admin
     [not found]           ` <CGME20200601164700eucas1p2e30af458bae7e820ca55f7936ac3579a@eucas1p2.samsung.com>
2020-06-01 16:46             ` Lukasz Stelmach
     [not found]         ` <CGME20200601184829eucas1p1b06bfc130083f6248d624febed1de9fc@eucas1p1.samsung.com>
2020-06-01 18:48           ` Lukasz Stelmach
     [not found]   ` <CGME20200602161737eucas1p241dd0e0a9b5eea7c5d5774c46b3c570b@eucas1p2.samsung.com>
2020-06-02 16:17     ` [PATCH v2 0/5] kexec_file_load() for arm Łukasz Stelmach
     [not found]       ` <CGME20200602161737eucas1p2c83700f7c17296c4367ee3fda1c6e783@eucas1p2.samsung.com>
2020-06-02 16:17         ` [PATCH v2 1/5] arm: decompressor: set malloc pool size for the decompressor Łukasz Stelmach
     [not found]       ` <CGME20200602161738eucas1p27dfbe386bd76555598d5574faf4fdad3@eucas1p2.samsung.com>
2020-06-02 16:17         ` [PATCH v2 2/5] arm: add image header definitions Łukasz Stelmach
     [not found]       ` <CGME20200602161738eucas1p2151f88b526bb009c27820a4f290a961e@eucas1p2.samsung.com>
2020-06-02 16:17         ` [PATCH v2 3/5] arm: decompressor: define a new zImage tag Łukasz Stelmach
     [not found]       ` <CGME20200602161738eucas1p2ccfaa7610dc6f76e209ba96d6278259e@eucas1p2.samsung.com>
2020-06-02 16:17         ` [PATCH v2 4/5] arm: Add kexec_image_info Łukasz Stelmach
     [not found]       ` <CGME20200602161739eucas1p16a56ff590bf44e747d5ad6e178d57067@eucas1p1.samsung.com>
2020-06-02 16:17         ` [PATCH v2 5/5] arm: kexec_file: load zImage or uImage, initrd and dtb Łukasz Stelmach
2020-06-11 10:37   ` [PATCH 0/5] kexec_file_load() for arm Dave Young
     [not found]   ` <CGME20200930183921eucas1p11a56f805421a614be67f869f5ed18b9b@eucas1p1.samsung.com>
2020-09-30 18:34     ` [PATCH v3 0/4] " Łukasz Stelmach
     [not found]       ` <CGME20200930183923eucas1p2241d3e1b8d4d05a2228448ff8fc4bb74@eucas1p2.samsung.com>
2020-09-30 18:34         ` [PATCH v3 1/4] arm: add image header definitions Łukasz Stelmach
     [not found]       ` <CGME20200930183924eucas1p2869520cc28e705073cb08c37c1e2fc6d@eucas1p2.samsung.com>
2020-09-30 18:34         ` [PATCH v3 2/4] arm: decompressor: define a new zImage tag Łukasz Stelmach
     [not found]       ` <CGME20200930183924eucas1p1eba72052e1723ce75e00cbadbe03b6fa@eucas1p1.samsung.com>
2020-09-30 18:34         ` [PATCH v3 3/4] arm: Add kexec_image_info Łukasz Stelmach
     [not found]       ` <CGME20200930183924eucas1p281730f3d651fc2c78d6a95e47a2c5220@eucas1p2.samsung.com>
2020-09-30 18:34         ` [PATCH v3 4/4] arm: kexec_file: load zImage or uImage, initrd and dtb Łukasz Stelmach
2020-10-01 10:09           ` kernel test robot

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).