mail archive of the barebox mailing list
 help / color / mirror / Atom feed
* [PATCH v1 00/10] provide ELF/KEXEC support for MIPS ath79 and malta
@ 2018-05-16 16:42 Oleksij Rempel
  2018-05-16 16:42 ` [PATCH v1 01/10] resource: add create_resource() helper function Oleksij Rempel
                   ` (9 more replies)
  0 siblings, 10 replies; 18+ messages in thread
From: Oleksij Rempel @ 2018-05-16 16:42 UTC (permalink / raw)
  To: barebox; +Cc: Oleksij Rempel

This patch set is a squashed and rebased patch set of work primely done by:
Antony Pavlov, Peter Mamonov and Yegor Yefremov.

I did some clean-ups and updates.

This code suppose provide kernel start support for some MIPS machines.
For example ath79 (Atheros) and malta should be able to work with it.

So far only two UHI boot protocols are supported:
- second argument is command line
- second argument is address to devicetree

Some work should be done to start using barebox internal devicetree patching to provide
cmdline over patched devicetree.

ARM and other arches would probably work with some more or less work.

Antony Pavlov (5):
  resource: add create_resource() helper function
  filetype: add ELF type
  bootm: add kexec ELF support
  MIPS: add kexec ELF loading support
  MIPS: malta: enable kexec

Oleksij Rempel (5):
  port resource_overlaps() from kernel
  MIPS: ath79: enable kexec
  MIPS: configs: add KEXEC=y to atheros devices
  MIPS: configs: dptechnics-dpt-module: enable watchdog poller
  MIPS: malta: update malta qemu defconfig

 arch/mips/Kconfig                                 |   2 +
 arch/mips/configs/8devices-lima_defconfig         |   1 +
 arch/mips/configs/black-swift_defconfig           |   1 +
 arch/mips/configs/dptechnics-dpt-module_defconfig |   2 +
 arch/mips/configs/qemu-malta_defconfig            |  13 +-
 arch/mips/configs/tplink-mr3020_defconfig         |   1 +
 arch/mips/configs/tplink-wdr4300_defconfig        |   1 +
 arch/mips/include/asm/elf.h                       |   8 +-
 arch/mips/lib/Makefile                            |   4 +
 arch/mips/lib/kexec-mach-generic.c                |  21 +
 arch/mips/lib/kexec-mips.c                        | 307 ++++++++++++
 arch/mips/lib/machine_kexec.h                     |  21 +
 arch/mips/lib/relocate_kernel.S                   | 108 +++++
 commands/Kconfig                                  |   7 +
 common/Kconfig                                    |   3 +
 common/filetype.c                                 |   5 +
 common/resource.c                                 |  15 +
 include/bootm.h                                   |   3 +
 include/filetype.h                                |   1 +
 include/kexec.h                                   | 118 +++++
 include/linux/ioport.h                            |   8 +
 lib/Makefile                                      |   1 +
 lib/kexec/Makefile                                |   4 +
 lib/kexec/kexec-bootm-elf.c                       |  42 ++
 lib/kexec/kexec-elf-exec.c                        |  70 +++
 lib/kexec/kexec-elf.c                             | 565 ++++++++++++++++++++++
 lib/kexec/kexec.c                                 | 255 ++++++++++
 27 files changed, 1583 insertions(+), 4 deletions(-)
 create mode 100644 arch/mips/lib/kexec-mach-generic.c
 create mode 100644 arch/mips/lib/kexec-mips.c
 create mode 100644 arch/mips/lib/machine_kexec.h
 create mode 100644 arch/mips/lib/relocate_kernel.S
 create mode 100644 include/kexec.h
 create mode 100644 lib/kexec/Makefile
 create mode 100644 lib/kexec/kexec-bootm-elf.c
 create mode 100644 lib/kexec/kexec-elf-exec.c
 create mode 100644 lib/kexec/kexec-elf.c
 create mode 100644 lib/kexec/kexec.c

-- 
2.14.1


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

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

* [PATCH v1 01/10] resource: add create_resource() helper function
  2018-05-16 16:42 [PATCH v1 00/10] provide ELF/KEXEC support for MIPS ath79 and malta Oleksij Rempel
@ 2018-05-16 16:42 ` Oleksij Rempel
  2018-05-16 16:42 ` [PATCH v1 02/10] port resource_overlaps() from kernel Oleksij Rempel
                   ` (8 subsequent siblings)
  9 siblings, 0 replies; 18+ messages in thread
From: Oleksij Rempel @ 2018-05-16 16:42 UTC (permalink / raw)
  To: barebox

From: Antony Pavlov <antonynpavlov@gmail.com>

needed for kexec support

Signed-off-by: Antony Pavlov <antonynpavlov@gmail.com>
---
 common/resource.c      | 15 +++++++++++++++
 include/linux/ioport.h |  2 ++
 2 files changed, 17 insertions(+)

diff --git a/common/resource.c b/common/resource.c
index e4bbe15fd..fa9ffd084 100644
--- a/common/resource.c
+++ b/common/resource.c
@@ -150,3 +150,18 @@ struct resource *request_ioport_region(const char *name,
 
 	return res;
 }
+
+struct resource *create_resource(const char *name,
+	resource_size_t start, resource_size_t end)
+{
+	struct resource *t;
+
+	t = xzalloc(sizeof *t);
+	INIT_LIST_HEAD(&t->children);
+	t->parent = NULL;
+	t->name = xstrdup(name);
+	t->start = start;
+	t->end = end;
+
+	return t;
+}
diff --git a/include/linux/ioport.h b/include/linux/ioport.h
index 3d375a874..2a944cc73 100644
--- a/include/linux/ioport.h
+++ b/include/linux/ioport.h
@@ -140,6 +140,8 @@ struct resource *__request_region(struct resource *parent,
 		resource_size_t size);
 
 int release_region(struct resource *res);
+struct resource *create_resource(const char *name,
+	resource_size_t start, resource_size_t end);
 
 extern struct resource iomem_resource;
 extern struct resource ioport_resource;
-- 
2.14.1


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

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

* [PATCH v1 02/10] port resource_overlaps() from kernel
  2018-05-16 16:42 [PATCH v1 00/10] provide ELF/KEXEC support for MIPS ath79 and malta Oleksij Rempel
  2018-05-16 16:42 ` [PATCH v1 01/10] resource: add create_resource() helper function Oleksij Rempel
@ 2018-05-16 16:42 ` Oleksij Rempel
  2018-05-16 16:42 ` [PATCH v1 03/10] filetype: add ELF type Oleksij Rempel
                   ` (7 subsequent siblings)
  9 siblings, 0 replies; 18+ messages in thread
From: Oleksij Rempel @ 2018-05-16 16:42 UTC (permalink / raw)
  To: barebox; +Cc: Oleksij Rempel

needed for kexec support

Signed-off-by: Oleksij Rempel <linux@rempel-privat.de>
---
 include/linux/ioport.h | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/include/linux/ioport.h b/include/linux/ioport.h
index 2a944cc73..f05937ead 100644
--- a/include/linux/ioport.h
+++ b/include/linux/ioport.h
@@ -130,6 +130,12 @@ static inline unsigned long resource_type(const struct resource *res)
 	return res->flags & IORESOURCE_TYPE_BITS;
 }
 
+/* True if any part of r1 overlaps r2 */
+static inline bool resource_overlaps(struct resource *r1, struct resource *r2)
+{
+       return (r1->start <= r2->end && r1->end >= r2->start);
+}
+
 struct resource *request_iomem_region(const char *name,
 		resource_size_t start, resource_size_t end);
 struct resource *request_ioport_region(const char *name,
-- 
2.14.1


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

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

* [PATCH v1 03/10] filetype: add ELF type
  2018-05-16 16:42 [PATCH v1 00/10] provide ELF/KEXEC support for MIPS ath79 and malta Oleksij Rempel
  2018-05-16 16:42 ` [PATCH v1 01/10] resource: add create_resource() helper function Oleksij Rempel
  2018-05-16 16:42 ` [PATCH v1 02/10] port resource_overlaps() from kernel Oleksij Rempel
@ 2018-05-16 16:42 ` Oleksij Rempel
  2018-05-16 16:42 ` [PATCH v1 04/10] bootm: add kexec ELF support Oleksij Rempel
                   ` (6 subsequent siblings)
  9 siblings, 0 replies; 18+ messages in thread
From: Oleksij Rempel @ 2018-05-16 16:42 UTC (permalink / raw)
  To: barebox

From: Antony Pavlov <antonynpavlov@gmail.com>

Signed-off-by: Antony Pavlov <antonynpavlov@gmail.com>
---
 common/filetype.c  | 5 +++++
 include/filetype.h | 1 +
 2 files changed, 6 insertions(+)

diff --git a/common/filetype.c b/common/filetype.c
index 444ec14cc..77cf9a105 100644
--- a/common/filetype.c
+++ b/common/filetype.c
@@ -27,6 +27,7 @@
 #include <envfs.h>
 #include <disks.h>
 #include <image-sparse.h>
+#include <elf.h>
 
 struct filetype_str {
 	const char *name;	/* human readable filetype */
@@ -68,6 +69,7 @@ static const struct filetype_str filetype_str[] = {
 	[filetype_kwbimage_v1] = { "MVEBU kwbimage (v1)", "kwb" },
 	[filetype_android_sparse] = { "Android sparse image", "sparse" },
 	[filetype_arm64_linux_image] = { "ARM aarch64 Linux image", "aarch64-linux" },
+	[filetype_elf] = { "ELF", "elf" },
 };
 
 const char *file_type_to_string(enum filetype f)
@@ -344,6 +346,9 @@ enum filetype file_detect_type(const void *_buf, size_t bufsize)
 		buf[7] == 0x47530000)
 		return filetype_ch_image_be;
 
+	if (strncmp(buf8, ELFMAG, 4) == 0)
+		return filetype_elf;
+
 	return filetype_unknown;
 }
 
diff --git a/include/filetype.h b/include/filetype.h
index 9986938dd..3b930bf94 100644
--- a/include/filetype.h
+++ b/include/filetype.h
@@ -41,6 +41,7 @@ enum filetype {
 	filetype_kwbimage_v1,
 	filetype_android_sparse,
 	filetype_arm64_linux_image,
+	filetype_elf,
 	filetype_max,
 };
 
-- 
2.14.1


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

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

* [PATCH v1 04/10] bootm: add kexec ELF support
  2018-05-16 16:42 [PATCH v1 00/10] provide ELF/KEXEC support for MIPS ath79 and malta Oleksij Rempel
                   ` (2 preceding siblings ...)
  2018-05-16 16:42 ` [PATCH v1 03/10] filetype: add ELF type Oleksij Rempel
@ 2018-05-16 16:42 ` Oleksij Rempel
  2018-05-16 21:34   ` Peter Mamonov
  2018-05-16 16:42 ` [PATCH v1 05/10] MIPS: add kexec ELF loading support Oleksij Rempel
                   ` (5 subsequent siblings)
  9 siblings, 1 reply; 18+ messages in thread
From: Oleksij Rempel @ 2018-05-16 16:42 UTC (permalink / raw)
  To: barebox

From: Antony Pavlov <antonynpavlov@gmail.com>

Also introduce reboot() for starting already loaded
via kexec ELF segments.

Signed-off-by: Antony Pavlov <antonynpavlov@gmail.com>
---
 commands/Kconfig            |   7 +
 common/Kconfig              |   3 +
 include/bootm.h             |   3 +
 include/kexec.h             | 118 +++++++++
 lib/Makefile                |   1 +
 lib/kexec/Makefile          |   4 +
 lib/kexec/kexec-bootm-elf.c |  42 ++++
 lib/kexec/kexec-elf-exec.c  |  70 ++++++
 lib/kexec/kexec-elf.c       | 565 ++++++++++++++++++++++++++++++++++++++++++++
 lib/kexec/kexec.c           | 255 ++++++++++++++++++++
 10 files changed, 1068 insertions(+)
 create mode 100644 include/kexec.h
 create mode 100644 lib/kexec/Makefile
 create mode 100644 lib/kexec/kexec-bootm-elf.c
 create mode 100644 lib/kexec/kexec-elf-exec.c
 create mode 100644 lib/kexec/kexec-elf.c
 create mode 100644 lib/kexec/kexec.c

diff --git a/commands/Kconfig b/commands/Kconfig
index 951a86963..a49928ad1 100644
--- a/commands/Kconfig
+++ b/commands/Kconfig
@@ -476,6 +476,13 @@ config CMD_SAVES
 
 	  Save S-Record file to serial line with offset OFFS and length LEN.
 
+config KEXEC
+	bool
+	prompt "bootm ELF image support"
+	depends on CMD_BOOTM && HAS_KEXEC
+	help
+	  Support using ELF Images.
+
 config CMD_UIMAGE
 	select UIMAGE
 	tristate
diff --git a/common/Kconfig b/common/Kconfig
index b7000c4d7..d40c79dbc 100644
--- a/common/Kconfig
+++ b/common/Kconfig
@@ -1218,3 +1218,6 @@ config HAS_DEBUG_LL
 config DDR_SPD
 	bool
 	select CRC16
+
+config HAS_KEXEC
+	bool
diff --git a/include/bootm.h b/include/bootm.h
index 62951d605..3a642fe70 100644
--- a/include/bootm.h
+++ b/include/bootm.h
@@ -72,6 +72,9 @@ struct image_data {
 
 	char *oftree_file;
 	char *oftree_part;
+	unsigned long oftree_address;
+
+	unsigned long cmdline_address;
 
 	const void *fit_kernel;
 	unsigned long fit_kernel_size;
diff --git a/include/kexec.h b/include/kexec.h
new file mode 100644
index 000000000..675658b38
--- /dev/null
+++ b/include/kexec.h
@@ -0,0 +1,118 @@
+#ifndef _LINUX_REBOOT_H
+#define _LINUX_REBOOT_H
+
+#include <bootm.h>
+
+struct kexec_segment {
+	const void *buf;
+	size_t bufsz;
+	const void *mem;
+	size_t memsz;
+};
+
+struct kexec_info {
+	struct kexec_segment *segment;
+	int nr_segments;
+	void *entry;
+	unsigned long kexec_flags;
+};
+
+typedef int (probe_t)(const char *kernel_buf, off_t kernel_size);
+typedef int (load_t)(const char *kernel_buf, off_t kernel_size,
+	struct kexec_info *info);
+struct kexec_file_type {
+	const char *name;
+	probe_t *probe;
+	load_t  *load;
+};
+
+extern struct kexec_file_type kexec_file_type[];
+extern int kexec_file_types;
+
+extern void add_segment(struct kexec_info *info,
+	const void *buf, size_t bufsz, unsigned long base, size_t memsz);
+extern void add_segment_phys_virt(struct kexec_info *info,
+	const void *buf, size_t bufsz, unsigned long base, size_t memsz,
+	int phys);
+
+extern int kexec_load(struct image_data *data, void *entry,
+		      unsigned long nr_segments,
+		      struct kexec_segment *segments);
+
+extern void kexec_arch(void *opaque);
+
+extern int kexec_load_bootm_data(struct image_data *data);
+
+/* These values match the ELF architecture values.
+ * Unless there is a good reason that should continue to be the case.
+ */
+#define KEXEC_ARCH_DEFAULT	(0 << 16)
+#define KEXEC_ARCH_386		(3 << 16)
+#define KEXEC_ARCH_X86_64	(62 << 16)
+#define KEXEC_ARCH_PPC		(20 << 16)
+#define KEXEC_ARCH_PPC64	(21 << 16)
+#define KEXEC_ARCH_IA_64	(50 << 16)
+#define KEXEC_ARCH_ARM		(40 << 16)
+#define KEXEC_ARCH_S390		(22 << 16)
+#define KEXEC_ARCH_SH		(42 << 16)
+#define KEXEC_ARCH_MIPS_LE	(10 << 16)
+#define KEXEC_ARCH_MIPS		(8 << 16)
+#define KEXEC_ARCH_CRIS		(76 << 16)
+
+#define KEXEC_MAX_SEGMENTS 16
+
+struct mem_phdr {
+	u64 p_paddr;
+	u64 p_vaddr;
+	u64 p_filesz;
+	u64 p_memsz;
+	u64 p_offset;
+	const char *p_data;
+	u32 p_type;
+	u32 p_flags;
+	u64 p_align;
+};
+
+struct mem_shdr {
+	u32 sh_name;
+	u32 sh_type;
+	u64 sh_flags;
+	u64 sh_addr;
+	u64 sh_offset;
+	u64 sh_size;
+	u32 sh_link;
+	u32 sh_info;
+	u64 sh_addralign;
+	u64 sh_entsize;
+	const unsigned char *sh_data;
+};
+
+struct mem_ehdr {
+	u32 ei_class;
+	u32 ei_data;
+	u32 e_type;
+	u32 e_machine;
+	u32 e_version;
+	u32 e_flags;
+	u32 e_phnum;
+	u32 e_shnum;
+	u32 e_shstrndx;
+	u64 e_entry;
+	u64 e_phoff;
+	u64 e_shoff;
+	struct mem_phdr *e_phdr;
+	struct mem_shdr *e_shdr;
+};
+
+void free_elf_info(struct mem_ehdr *ehdr);
+int build_elf_info(const char *buf, size_t len, struct mem_ehdr *ehdr);
+int build_elf_exec_info(const char *buf, off_t len, struct mem_ehdr *ehdr);
+
+int elf_exec_load(struct mem_ehdr *ehdr, struct kexec_info *info);
+
+unsigned long elf_max_addr(const struct mem_ehdr *ehdr);
+int check_room_for_elf(struct list_head *elf_segments);
+resource_size_t dcheck_res(struct list_head *elf_segments);
+void list_add_used_region(struct list_head *new, struct list_head *head);
+
+#endif /* _LINUX_REBOOT_H */
diff --git a/lib/Makefile b/lib/Makefile
index a7498288a..eebaf3488 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -65,3 +65,4 @@ obj-y			+= int_sqrt.o
 obj-y			+= parseopt.o
 obj-y			+= clz_ctz.o
 obj-$(CONFIG_CRC_CCITT) += crc-ccitt.o
+obj-$(CONFIG_KEXEC)	+= kexec/
diff --git a/lib/kexec/Makefile b/lib/kexec/Makefile
new file mode 100644
index 000000000..2f3dc1dd3
--- /dev/null
+++ b/lib/kexec/Makefile
@@ -0,0 +1,4 @@
+obj-y	+= kexec.o
+obj-y	+= kexec-elf.o
+obj-y	+= kexec-elf-exec.o
+obj-y	+= kexec-bootm-elf.o
diff --git a/lib/kexec/kexec-bootm-elf.c b/lib/kexec/kexec-bootm-elf.c
new file mode 100644
index 000000000..2530466a5
--- /dev/null
+++ b/lib/kexec/kexec-bootm-elf.c
@@ -0,0 +1,42 @@
+// SPDX-License-Identifier: GPL-2.0+
+
+#include <binfmt.h>
+#include <bootm.h>
+#include <init.h>
+#include <kexec.h>
+
+static int do_bootm_elf(struct image_data *data)
+{
+	int ret;
+
+	ret = kexec_load_bootm_data(data);
+	if (IS_ERR_VALUE(ret))
+		return ret;
+	
+	kexec_arch(data);
+
+	return -ERESTARTSYS;
+}
+
+static struct image_handler elf_handler = {
+	.name = "ELF",
+	.bootm = do_bootm_elf,
+	.filetype = filetype_elf,
+};
+
+static struct binfmt_hook binfmt_elf_hook = {
+	.type = filetype_elf,
+	.exec = "bootm",
+};
+
+static int elf_register_image_handler(void)
+{
+	int ret;
+
+	ret = register_image_handler(&elf_handler);
+	if (IS_ERR_VALUE(ret))
+		return ret;
+	
+	return binfmt_register(&binfmt_elf_hook);
+}
+late_initcall(elf_register_image_handler);
diff --git a/lib/kexec/kexec-elf-exec.c b/lib/kexec/kexec-elf-exec.c
new file mode 100644
index 000000000..e910c4ea0
--- /dev/null
+++ b/lib/kexec/kexec-elf-exec.c
@@ -0,0 +1,70 @@
+// SPDX-License-Identifier: GPL-2.0+
+
+#include <common.h>
+#include <kexec.h>
+
+int build_elf_exec_info(const char *buf, off_t len, struct mem_ehdr *ehdr)
+{
+	struct mem_phdr *phdr, *end_phdr;
+	int ret;
+
+	ret = build_elf_info(buf, len, ehdr);
+	if (IS_ERR_VALUE(ret))
+		return ret;
+
+	if (ehdr->e_type != ET_EXEC) {
+		pr_err("Not ELF type ET_EXEC\n");
+		return -ENOEXEC;
+	}
+
+	if (!ehdr->e_phdr) {
+		pr_err("No ELF program header\n");
+		return -ENOEXEC;
+	}
+
+	end_phdr = &ehdr->e_phdr[ehdr->e_phnum];
+	for (phdr = ehdr->e_phdr; phdr != end_phdr; phdr++) {
+		/* Kexec does not support loading interpreters.
+		 * In addition this check keeps us from attempting
+		 * to kexec ordinay executables.
+		 */
+		if (phdr->p_type == PT_INTERP) {
+			pr_err("Requires an ELF interpreter\n");
+			return -ENOEXEC;
+		}
+	}
+
+	return 0;
+}
+
+int elf_exec_load(struct mem_ehdr *ehdr, struct kexec_info *info)
+{
+	size_t i;
+
+	if (!ehdr->e_phdr) {
+		pr_err("No program header?\n");
+		return -ENOENT;
+	}
+
+	/* Read in the PT_LOAD segments */
+	for (i = 0; i < ehdr->e_phnum; i++) {
+		struct mem_phdr *phdr;
+		size_t size;
+
+		phdr = &ehdr->e_phdr[i];
+
+		if (phdr->p_type != PT_LOAD)
+			continue;
+
+		size = phdr->p_filesz;
+
+		if (size > phdr->p_memsz)
+			size = phdr->p_memsz;
+
+		add_segment(info,
+			phdr->p_data, size,
+			phdr->p_paddr, phdr->p_memsz);
+	}
+
+	return 0;
+}
diff --git a/lib/kexec/kexec-elf.c b/lib/kexec/kexec-elf.c
new file mode 100644
index 000000000..a66ac4c66
--- /dev/null
+++ b/lib/kexec/kexec-elf.c
@@ -0,0 +1,565 @@
+// SPDX-License-Identifier: GPL-2.0+
+
+#include <asm/io.h>
+#include <common.h>
+#include <kexec.h>
+#include <memory.h>
+
+static u16 elf16_to_cpu(const struct mem_ehdr *ehdr, u16 val)
+{
+	return ehdr->ei_data == ELFDATA2LSB ? le16_to_cpu(val)
+		   : be16_to_cpu(val);
+}
+
+static u32 elf32_to_cpu(const struct mem_ehdr *ehdr, u32 val)
+{
+	return ehdr->ei_data == ELFDATA2LSB ? le32_to_cpu(val)
+		   : be32_to_cpu(val);
+}
+
+static u64 elf64_to_cpu(const struct mem_ehdr *ehdr, u64 val)
+{
+	return ehdr->ei_data == ELFDATA2LSB ? le64_to_cpu(val)
+		   : be64_to_cpu(val);
+}
+
+static int build_mem_elf32_ehdr(const void *buf, size_t len,
+				struct mem_ehdr *ehdr)
+{
+	const Elf32_Ehdr *lehdr = buf;
+
+	if (len < sizeof(Elf32_Ehdr)) {
+		pr_err("Buffer is too small to hold ELF header\n");
+		return -ENOEXEC;
+	}
+
+	if (elf16_to_cpu(ehdr, lehdr->e_ehsize) != sizeof(Elf32_Ehdr)) {
+		pr_err("Bad ELF header size\n");
+		return -ENOEXEC;
+	}
+
+	ehdr->e_type      = elf16_to_cpu(ehdr, lehdr->e_type);
+	ehdr->e_machine   = elf16_to_cpu(ehdr, lehdr->e_machine);
+	ehdr->e_version   = elf32_to_cpu(ehdr, lehdr->e_version);
+	ehdr->e_entry     = elf32_to_cpu(ehdr, lehdr->e_entry);
+	ehdr->e_phoff     = elf32_to_cpu(ehdr, lehdr->e_phoff);
+	ehdr->e_shoff     = elf32_to_cpu(ehdr, lehdr->e_shoff);
+	ehdr->e_flags     = elf32_to_cpu(ehdr, lehdr->e_flags);
+	ehdr->e_phnum     = elf16_to_cpu(ehdr, lehdr->e_phnum);
+	ehdr->e_shnum     = elf16_to_cpu(ehdr, lehdr->e_shnum);
+	ehdr->e_shstrndx  = elf16_to_cpu(ehdr, lehdr->e_shstrndx);
+
+	if ((ehdr->e_phnum > 0) &&
+		(elf16_to_cpu(ehdr, lehdr->e_phentsize) != sizeof(Elf32_Phdr))) {
+		pr_err("ELF bad program header size\n");
+		return -ENOEXEC;
+	}
+
+	if ((ehdr->e_shnum > 0) &&
+		(elf16_to_cpu(ehdr, lehdr->e_shentsize) != sizeof(Elf32_Shdr))) {
+		pr_err("ELF bad section header size\n");
+		return -ENOEXEC;
+	}
+
+	return 0;
+}
+
+static int build_mem_elf64_ehdr(const void *buf, size_t len,
+				struct mem_ehdr *ehdr)
+{
+	const Elf64_Ehdr *lehdr = buf;
+
+	if (len < sizeof(Elf64_Ehdr)) {
+		pr_err("Buffer is too small to hold ELF header\n");
+		return -ENOEXEC;
+	}
+
+	if (elf16_to_cpu(ehdr, lehdr->e_ehsize) != sizeof(Elf64_Ehdr)) {
+		pr_err("Bad ELF header size\n");
+		return -ENOEXEC;
+	}
+
+	ehdr->e_type      = elf16_to_cpu(ehdr, lehdr->e_type);
+	ehdr->e_machine   = elf16_to_cpu(ehdr, lehdr->e_machine);
+	ehdr->e_version   = elf32_to_cpu(ehdr, lehdr->e_version);
+	ehdr->e_entry     = elf64_to_cpu(ehdr, lehdr->e_entry);
+	ehdr->e_phoff     = elf64_to_cpu(ehdr, lehdr->e_phoff);
+	ehdr->e_shoff     = elf64_to_cpu(ehdr, lehdr->e_shoff);
+	ehdr->e_flags     = elf32_to_cpu(ehdr, lehdr->e_flags);
+	ehdr->e_phnum     = elf16_to_cpu(ehdr, lehdr->e_phnum);
+	ehdr->e_shnum     = elf16_to_cpu(ehdr, lehdr->e_shnum);
+	ehdr->e_shstrndx  = elf16_to_cpu(ehdr, lehdr->e_shstrndx);
+
+	if ((ehdr->e_phnum > 0) &&
+		(elf16_to_cpu(ehdr, lehdr->e_phentsize) != sizeof(Elf64_Phdr))) {
+		pr_err("ELF bad program header size\n");
+		return -ENOEXEC;
+	}
+
+	if ((ehdr->e_shnum > 0) &&
+		(elf16_to_cpu(ehdr, lehdr->e_shentsize) != sizeof(Elf64_Shdr))) {
+		pr_err("ELF bad section header size\n");
+		return -ENOEXEC;
+	}
+
+	return 0;
+}
+
+static int build_mem_ehdr(const void *buf, size_t len, struct mem_ehdr *ehdr)
+{
+	unsigned char e_ident[EI_NIDENT];
+	int ret;
+
+	memset(ehdr, 0, sizeof(*ehdr));
+
+	if (len < sizeof(e_ident)) {
+		pr_err("Buffer is too small to hold ELF e_ident\n");
+		return -ENOEXEC;
+	}
+
+	memcpy(e_ident, buf, sizeof(e_ident));
+
+	ehdr->ei_class   = e_ident[EI_CLASS];
+	ehdr->ei_data    = e_ident[EI_DATA];
+	if ((ehdr->ei_class != ELFCLASS32) &&
+		(ehdr->ei_class != ELFCLASS64)) {
+		pr_err("Not a supported ELF class\n");
+		return -ENOEXEC;
+	}
+
+	if ((ehdr->ei_data != ELFDATA2LSB) &&
+		(ehdr->ei_data != ELFDATA2MSB)) {
+		pr_err("Not a supported ELF data format\n");
+		return -ENOEXEC;
+	}
+
+	if (ehdr->ei_class == ELFCLASS32)
+		ret = build_mem_elf32_ehdr(buf, len, ehdr);
+	else
+		ret = build_mem_elf64_ehdr(buf, len, ehdr);
+
+	if (IS_ERR_VALUE(ret))
+		return ret;
+
+	if ((e_ident[EI_VERSION] != EV_CURRENT) ||
+		(ehdr->e_version != EV_CURRENT)) {
+		pr_err("Unknown ELF version\n");
+		return -ENOEXEC;
+	}
+
+	return 0;
+}
+
+static void build_mem_elf32_phdr(const char *buf, struct mem_ehdr *ehdr, int idx)
+{
+	struct mem_phdr *phdr;
+	const Elf32_Phdr *lphdr;
+
+	lphdr = (const Elf32_Phdr *)(buf + ehdr->e_phoff + (idx * sizeof(Elf32_Phdr)));
+	phdr = &ehdr->e_phdr[idx];
+
+	phdr->p_type   = elf32_to_cpu(ehdr, lphdr->p_type);
+	phdr->p_paddr  = elf32_to_cpu(ehdr, lphdr->p_paddr);
+	phdr->p_vaddr  = elf32_to_cpu(ehdr, lphdr->p_vaddr);
+	phdr->p_filesz = elf32_to_cpu(ehdr, lphdr->p_filesz);
+	phdr->p_memsz  = elf32_to_cpu(ehdr, lphdr->p_memsz);
+	phdr->p_offset = elf32_to_cpu(ehdr, lphdr->p_offset);
+	phdr->p_flags  = elf32_to_cpu(ehdr, lphdr->p_flags);
+	phdr->p_align  = elf32_to_cpu(ehdr, lphdr->p_align);
+}
+
+static void build_mem_elf64_phdr(const char *buf, struct mem_ehdr *ehdr, int idx)
+{
+	struct mem_phdr *phdr;
+	const Elf64_Phdr *lphdr;
+
+	lphdr = (const Elf64_Phdr *)(buf + ehdr->e_phoff + (idx * sizeof(Elf64_Phdr)));
+	phdr = &ehdr->e_phdr[idx];
+
+	phdr->p_type   = elf32_to_cpu(ehdr, lphdr->p_type);
+	phdr->p_paddr  = elf64_to_cpu(ehdr, lphdr->p_paddr);
+	phdr->p_vaddr  = elf64_to_cpu(ehdr, lphdr->p_vaddr);
+	phdr->p_filesz = elf64_to_cpu(ehdr, lphdr->p_filesz);
+	phdr->p_memsz  = elf64_to_cpu(ehdr, lphdr->p_memsz);
+	phdr->p_offset = elf64_to_cpu(ehdr, lphdr->p_offset);
+	phdr->p_flags  = elf32_to_cpu(ehdr, lphdr->p_flags);
+	phdr->p_align  = elf64_to_cpu(ehdr, lphdr->p_align);
+}
+
+static int build_mem_phdrs(const char *buf, struct mem_ehdr *ehdr)
+{
+	size_t mem_phdr_size, i;
+
+	/* e_phnum is at most 65535 so calculating
+	 * the size of the program header cannot overflow.
+	 */
+
+	/* Allocate the e_phdr array */
+	mem_phdr_size = sizeof(ehdr->e_phdr[0]) * ehdr->e_phnum;
+	ehdr->e_phdr = xmalloc(mem_phdr_size);
+
+	for (i = 0; i < ehdr->e_phnum; i++) {
+		struct mem_phdr *phdr;
+
+		if (ehdr->ei_class == ELFCLASS32)
+			build_mem_elf32_phdr(buf, ehdr, i);
+		else
+			build_mem_elf64_phdr(buf, ehdr, i);
+
+		/* Check the program headers to be certain
+		 * they are safe to use.
+		 */
+		phdr = &ehdr->e_phdr[i];
+		if ((phdr->p_paddr + phdr->p_memsz) < phdr->p_paddr) {
+			/* The memory address wraps */
+			pr_err("ELF address wrap around\n");
+			return -ENOEXEC;
+		}
+
+		/* Remember where the segment lives in the buffer */
+		phdr->p_data = buf + phdr->p_offset;
+	}
+
+	return 0;
+}
+
+static int build_mem_elf32_shdr(const char *buf, struct mem_ehdr *ehdr, int idx)
+{
+	struct mem_shdr *shdr;
+	int size_ok;
+	const Elf32_Shdr *lshdr;
+
+	lshdr = (const Elf32_Shdr *)(buf + ehdr->e_shoff + (idx * sizeof(Elf32_Shdr)));
+	shdr = &ehdr->e_shdr[idx];
+	shdr->sh_name      = elf32_to_cpu(ehdr, lshdr->sh_name);
+	shdr->sh_type      = elf32_to_cpu(ehdr, lshdr->sh_type);
+	shdr->sh_flags     = elf32_to_cpu(ehdr, lshdr->sh_flags);
+	shdr->sh_addr      = elf32_to_cpu(ehdr, lshdr->sh_addr);
+	shdr->sh_offset    = elf32_to_cpu(ehdr, lshdr->sh_offset);
+	shdr->sh_size      = elf32_to_cpu(ehdr, lshdr->sh_size);
+	shdr->sh_link      = elf32_to_cpu(ehdr, lshdr->sh_link);
+	shdr->sh_info      = elf32_to_cpu(ehdr, lshdr->sh_info);
+	shdr->sh_addralign = elf32_to_cpu(ehdr, lshdr->sh_addralign);
+	shdr->sh_entsize   = elf32_to_cpu(ehdr, lshdr->sh_entsize);
+
+	/* Now verify sh_entsize */
+	size_ok = 0;
+	switch (shdr->sh_type) {
+	case SHT_SYMTAB:
+		size_ok = shdr->sh_entsize == sizeof(Elf32_Sym);
+		break;
+	case SHT_RELA:
+		size_ok = shdr->sh_entsize == sizeof(Elf32_Rela);
+		break;
+	case SHT_DYNAMIC:
+		size_ok = shdr->sh_entsize == sizeof(Elf32_Dyn);
+		break;
+	case SHT_REL:
+		size_ok = shdr->sh_entsize == sizeof(Elf32_Rel);
+		break;
+	case SHT_NOTE:
+	case SHT_NULL:
+	case SHT_PROGBITS:
+	case SHT_HASH:
+	case SHT_NOBITS:
+	default:
+		/* This is a section whose entsize requirements
+		 * I don't care about.  If I don't know about
+		 * the section I can't care about it's entsize
+		 * requirements.
+		 */
+		size_ok = 1;
+		break;
+	}
+
+	if (size_ok)
+		return 0;
+
+	pr_err("Bad section header(%x) entsize: %lld\n",
+		shdr->sh_type, shdr->sh_entsize);
+	return -ENOEXEC;
+}
+
+static int build_mem_elf64_shdr(const char *buf, struct mem_ehdr *ehdr, int idx)
+{
+	struct mem_shdr *shdr;
+	int size_ok;
+	const Elf64_Shdr *lshdr;
+
+	lshdr = (const Elf64_Shdr *)(buf + ehdr->e_shoff + (idx * sizeof(Elf64_Shdr)));
+	shdr = &ehdr->e_shdr[idx];
+	shdr->sh_name      = elf32_to_cpu(ehdr, lshdr->sh_name);
+	shdr->sh_type      = elf32_to_cpu(ehdr, lshdr->sh_type);
+	shdr->sh_flags     = elf64_to_cpu(ehdr, lshdr->sh_flags);
+	shdr->sh_addr      = elf64_to_cpu(ehdr, lshdr->sh_addr);
+	shdr->sh_offset    = elf64_to_cpu(ehdr, lshdr->sh_offset);
+	shdr->sh_size      = elf64_to_cpu(ehdr, lshdr->sh_size);
+	shdr->sh_link      = elf32_to_cpu(ehdr, lshdr->sh_link);
+	shdr->sh_info      = elf32_to_cpu(ehdr, lshdr->sh_info);
+	shdr->sh_addralign = elf64_to_cpu(ehdr, lshdr->sh_addralign);
+	shdr->sh_entsize   = elf64_to_cpu(ehdr, lshdr->sh_entsize);
+
+	/* Now verify sh_entsize */
+	size_ok = 0;
+	switch (shdr->sh_type) {
+	case SHT_SYMTAB:
+		size_ok = shdr->sh_entsize == sizeof(Elf64_Sym);
+		break;
+	case SHT_RELA:
+		size_ok = shdr->sh_entsize == sizeof(Elf64_Rela);
+		break;
+	case SHT_DYNAMIC:
+		size_ok = shdr->sh_entsize == sizeof(Elf64_Dyn);
+		break;
+	case SHT_REL:
+		size_ok = shdr->sh_entsize == sizeof(Elf64_Rel);
+		break;
+	case SHT_NOTE:
+	case SHT_NULL:
+	case SHT_PROGBITS:
+	case SHT_HASH:
+	case SHT_NOBITS:
+	default:
+		/* This is a section whose entsize requirements
+		 * I don't care about.  If I don't know about
+		 * the section I can't care about it's entsize
+		 * requirements.
+		 */
+		size_ok = 1;
+		break;
+	}
+
+	if (size_ok)
+		return 0;
+
+	pr_err("Bad section header(%x) entsize: %lld\n",
+		shdr->sh_type, shdr->sh_entsize);
+	return -ENOEXEC;
+}
+
+static int build_mem_shdrs(const void *buf, struct mem_ehdr *ehdr)
+{
+	size_t mem_shdr_size, i;
+
+	/* Allocate the e_shdr array */
+	mem_shdr_size = sizeof(ehdr->e_shdr[0]) * ehdr->e_shnum;
+	ehdr->e_shdr = xmalloc(mem_shdr_size);
+
+	for (i = 0; i < ehdr->e_shnum; i++) {
+		struct mem_shdr *shdr;
+		int ret;
+
+		if (ehdr->ei_class == ELFCLASS32)
+			ret = build_mem_elf32_shdr(buf, ehdr, i);
+		else
+			ret = build_mem_elf64_shdr(buf, ehdr, i);
+
+		if (IS_ERR_VALUE(ret))
+			return ret;
+
+		/* Check the section headers to be certain
+		 * they are safe to use.
+		 */
+		shdr = &ehdr->e_shdr[i];
+		if ((shdr->sh_addr + shdr->sh_size) < shdr->sh_addr) {
+			pr_err("ELF address wrap around\n");
+			return -ENOEXEC;
+		}
+
+		/* Remember where the section lives in the buffer */
+		shdr->sh_data = (unsigned char *)(buf + shdr->sh_offset);
+	}
+
+	return 0;
+}
+
+void free_elf_info(struct mem_ehdr *ehdr)
+{
+	free(ehdr->e_phdr);
+	free(ehdr->e_shdr);
+	memset(ehdr, 0, sizeof(*ehdr));
+}
+
+int build_elf_info(const char *buf, size_t len, struct mem_ehdr *ehdr)
+{
+	int ret;
+
+	ret = build_mem_ehdr(buf, len, ehdr);
+	if (IS_ERR_VALUE(ret))
+		return ret;
+
+	if ((ehdr->e_phoff > 0) && (ehdr->e_phnum > 0)) {
+		ret = build_mem_phdrs(buf, ehdr);
+		if (IS_ERR_VALUE(ret)) {
+			free_elf_info(ehdr);
+			return ret;
+		}
+	}
+
+	if ((ehdr->e_shoff > 0) && (ehdr->e_shnum > 0)) {
+		ret = build_mem_shdrs(buf, ehdr);
+		if (IS_ERR_VALUE(ret)) {
+			free_elf_info(ehdr);
+			return ret;
+		}
+	}
+
+	return 0;
+}
+
+int check_room_for_elf(struct list_head *elf_segments)
+{
+	struct memory_bank *bank;
+	struct resource *res, *r;
+
+	list_for_each_entry(r, elf_segments, sibling) {
+		int got_bank;
+
+		got_bank = 0;
+		for_each_memory_bank(bank) {
+			unsigned long start, end;
+
+			res = bank->res;
+
+			start = virt_to_phys((const void *)res->start);
+			end = virt_to_phys((const void *)res->end);
+
+			if ((start <= r->start) && (end >= r->end)) {
+				got_bank = 1;
+				break;
+			}
+		}
+
+		if (!got_bank)
+			return -ENOSPC;
+	}
+
+	return 0;
+}
+
+/* sort by size */
+static int compare(struct list_head *a, struct list_head *b)
+{
+	struct resource *ra = (struct resource *)list_entry(a,
+					struct resource, sibling);
+	struct resource *rb = (struct resource *)list_entry(b,
+					struct resource, sibling);
+	resource_size_t sa, sb;
+
+	sa = ra->end - ra->start;
+	sb = rb->end - rb->start;
+
+	if (sa > sb)
+		return -1;
+	if (sa < sb)
+		return 1;
+	return 0;
+}
+
+void list_add_used_region(struct list_head *new, struct list_head *head)
+{
+	struct list_head *pos, *insert = head;
+	struct resource *rb =
+		(struct resource *)list_entry(new, struct resource, sibling);
+	struct list_head *n;
+
+	/* rb --- new region */
+	list_for_each_safe(pos, n, head) {
+		struct resource *ra = (struct resource *)list_entry(pos,
+						struct resource, sibling);
+
+		if (resource_overlaps(ra, rb)) {
+			rb->start = min(ra->start, rb->start);
+			rb->end = max(ra->end, rb->end);
+			rb->name = "join";
+			list_del(pos);
+		}
+	}
+
+	list_for_each(pos, head) {
+		struct resource *ra = (struct resource *)list_entry(pos,
+						struct resource, sibling);
+
+		if (ra->start < rb->start)
+			continue;
+
+		insert = pos;
+		break;
+	}
+
+	list_add_tail(new, insert);
+}
+
+resource_size_t dcheck_res(struct list_head *elf_segments)
+{
+	struct memory_bank *bank;
+	struct resource *res, *r, *t;
+
+	LIST_HEAD(elf_relocate_banks);
+	LIST_HEAD(elf_relocate_banks_size_sorted);
+	LIST_HEAD(used_regions);
+
+	for_each_memory_bank(bank) {
+		res = bank->res;
+
+		list_for_each_entry(r, &res->children, sibling) {
+			t = create_resource("tmp",
+				virt_to_phys((void *)r->start),
+				virt_to_phys((void *)r->end));
+			list_add_used_region(&t->sibling, &used_regions);
+		}
+	}
+
+	list_for_each_entry(r, elf_segments, sibling) {
+		t = create_resource(r->name, r->start, r->end);
+		list_add_used_region(&t->sibling, &used_regions);
+	}
+
+	for_each_memory_bank(bank) {
+		resource_size_t start;
+
+		res = bank->res;
+		res = create_resource("tmp",
+				virt_to_phys((void *)res->start),
+				virt_to_phys((void *)res->end));
+		start = res->start;
+
+		list_for_each_entry(r, &used_regions, sibling) {
+			if (res->start > r->end)
+				continue;
+
+			if (res->end < r->start)
+				continue;
+
+			if (r->start - start) {
+				struct resource *t;
+
+				t = create_resource("ELF buffer", start,
+						    r->start - 1);
+				list_add_used_region(&t->sibling,
+						     &elf_relocate_banks);
+			}
+			start = r->end + 1;
+		}
+
+		if (res->end - start) {
+			struct resource *t;
+
+			t = create_resource("ELF buffer", start, res->end);
+			list_add_used_region(&t->sibling, &elf_relocate_banks);
+		}
+	}
+
+	list_for_each_entry(r, &elf_relocate_banks, sibling) {
+		struct resource *t;
+
+		t = create_resource("ELF buffer", r->start, r->end);
+		list_add_sort(&t->sibling,
+			&elf_relocate_banks_size_sorted, compare);
+	}
+
+	r = list_first_entry(&elf_relocate_banks_size_sorted, struct resource,
+			     sibling);
+
+	return r->start;
+}
diff --git a/lib/kexec/kexec.c b/lib/kexec/kexec.c
new file mode 100644
index 000000000..585371c65
--- /dev/null
+++ b/lib/kexec/kexec.c
@@ -0,0 +1,255 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * kexec: Linux boots Linux
+ *
+ * Copyright (C) 2003-2005  Eric Biederman (ebiederm@xmission.com)
+ * Modified (2007-05-15) by Francesco Chiechi to rudely handle mips platform
+ *
+ */
+
+#include <asm/io.h>
+#include <boot.h>
+#include <common.h>
+#include <environment.h>
+#include <kexec.h>
+#include <libfile.h>
+
+static int sort_segments(struct kexec_info *info)
+{
+	int i, j;
+	void *end = NULL;
+
+	/* Do a stupid insertion sort... */
+	for (i = 0; i < info->nr_segments; i++) {
+		int tidx;
+		struct kexec_segment temp;
+		tidx = i;
+		for (j = i + 1; j < info->nr_segments; j++) {
+			if (info->segment[j].mem < info->segment[tidx].mem)
+				tidx = j;
+		}
+		if (tidx != i) {
+			temp = info->segment[tidx];
+			info->segment[tidx] = info->segment[i];
+			info->segment[i] = temp;
+		}
+	}
+
+	/* Now see if any of the segments overlap */
+	for (i = 0; i < info->nr_segments; i++) {
+		if (end > info->segment[i].mem) {
+			pr_err("Overlapping memory segments at %p\n",
+				end);
+			return -EBUSY;
+		}
+		end = ((char *)info->segment[i].mem) + info->segment[i].memsz;
+	}
+
+	return 0;
+}
+
+void add_segment_phys_virt(struct kexec_info *info,
+	const void *buf, size_t bufsz,
+	unsigned long base, size_t memsz, int phys)
+{
+	size_t size;
+	int pagesize;
+
+	if (bufsz > memsz)
+		bufsz = memsz;
+
+	/* Forget empty segments */
+	if (!memsz)
+		return;
+
+	/* Round memsz up to a multiple of pagesize */
+	pagesize = 4096;
+	memsz = (memsz + (pagesize - 1)) & ~(pagesize - 1);
+
+	if (phys)
+		base = virt_to_phys((void *)base);
+
+	size = (info->nr_segments + 1) * sizeof(info->segment[0]);
+	info->segment = xrealloc(info->segment, size);
+	info->segment[info->nr_segments].buf   = buf;
+	info->segment[info->nr_segments].bufsz = bufsz;
+	info->segment[info->nr_segments].mem   = (void *)base;
+	info->segment[info->nr_segments].memsz = memsz;
+	info->nr_segments++;
+	if (info->nr_segments > KEXEC_MAX_SEGMENTS) {
+		pr_warn("Warning: kernel segment limit reached. "
+			"This will likely fail\n");
+	}
+}
+
+static int kexec_load_one_file(struct kexec_info *info, char *fname)
+{
+	char *buf;
+	size_t fsize;
+	int i = 0;
+
+	buf = read_file(fname, &fsize);
+
+	/* FIXME: check buf */
+
+	for (i = 0; i < kexec_file_types; i++) {
+		if (kexec_file_type[i].probe(buf, fsize) >= 0)
+			break;
+	}
+
+	if (i == kexec_file_types) {
+		pr_err("Cannot determine the file type "
+				"of %s\n", fname);
+		return -ENOEXEC;
+	}
+
+	return kexec_file_type[i].load(buf, fsize, info);
+}
+
+static int kexec_load_binary_file(struct kexec_info *info, char *fname,
+					size_t *fsize, unsigned long base)
+{
+	char *buf;
+
+	buf = read_file(fname, fsize);
+	if (!buf)
+		return -ENOENT;
+
+	add_segment(info, buf, *fsize, base, *fsize);
+
+	return 0;
+}
+
+static void print_segments(struct kexec_info *info)
+{
+	int i;
+
+	pr_info("print_segments\n");
+	for (i = 0; i < info->nr_segments; i++) {
+		struct kexec_segment *seg = &info->segment[i];
+
+		pr_info("  %d. buf=%#08p bufsz=%#lx mem=%#08p memsz=%#lx\n", i,
+			seg->buf, seg->bufsz, seg->mem, seg->memsz);
+	}
+}
+
+static unsigned long find_unused_base(struct kexec_info *info, int *padded)
+{
+	unsigned long base = 0;
+
+	if (info->nr_segments) {
+		int i = info->nr_segments - 1;
+		struct kexec_segment *seg = &info->segment[i];
+
+		base = (unsigned long)seg->mem + seg->memsz;
+	}
+
+	if (!*padded) {
+		/*
+		 * Pad it; the kernel scribbles over memory
+		 * beyond its load address.
+		 * see grub-core/loader/mips/linux.c
+		 */
+		base += 0x100000;
+		*padded = 1;
+	}
+
+	return base;
+}
+
+int kexec_load_bootm_data(struct image_data *data)
+{
+	int ret;
+	struct kexec_info info;
+	char *cmdline;
+	const char *t;
+	size_t tlen;
+	size_t fsize;
+	char initrd_cmdline[40];
+	int padded = 0;
+
+	memset(&info, 0, sizeof(info));
+
+	initrd_cmdline[0] = 0;
+
+	ret = kexec_load_one_file(&info, data->os_file);
+	if (IS_ERR_VALUE(ret)) {
+		pr_err("Cannot load %s\n", data->os_file);
+		return ret;
+	}
+
+	if (data->oftree_file) {
+		unsigned long base = find_unused_base(&info, &padded);
+
+		base = ALIGN(base, 8);
+
+		ret = kexec_load_binary_file(&info,
+				data->oftree_file, &fsize, base);
+		if (IS_ERR_VALUE(ret)) {
+			pr_err("Cannot load %s\n", data->oftree_file);
+			return ret;
+		}
+		data->oftree_address = base;
+	}
+
+	if (data->initrd_file) {
+		unsigned long base = find_unused_base(&info, &padded);
+
+		/*
+		 * initrd start must be page aligned,
+		 * max page size for mips is 64k.
+		 */
+		base = ALIGN(base, 0x10000);
+
+		ret = kexec_load_binary_file(&info,
+				data->initrd_file, &fsize, base);
+		if (IS_ERR_VALUE(ret)) {
+			pr_err("Cannot load %s\n", data->initrd_file);
+			return ret;
+		}
+		data->initrd_address = base;
+
+		if (bootm_verbose(data)) {
+			pr_info("initrd: rd_start=0x%08x rd_size=0x%08x\n",
+					data->initrd_address, fsize);
+		}
+		snprintf(initrd_cmdline, sizeof(initrd_cmdline),
+				" rd_start=0x%08x rd_size=0x%08x",
+					phys_to_virt(data->initrd_address),
+					fsize);
+	}
+
+	t = linux_bootargs_get();
+	if (t)
+		tlen = strlen(t);
+	else
+		tlen = 0;
+
+	cmdline = xzalloc(tlen + sizeof(initrd_cmdline));
+	if (tlen)
+		memcpy(cmdline, t, tlen);
+
+	memcpy(cmdline + tlen, initrd_cmdline, sizeof(initrd_cmdline));
+
+	if (cmdline) {
+		int cmdlinelen = strlen(cmdline) + 1;
+		unsigned long base = find_unused_base(&info, &padded);
+
+		base = ALIGN(base, 8);
+
+		add_segment(&info, cmdline, cmdlinelen, base, cmdlinelen);
+		data->cmdline_address = base;
+	}
+
+	if (bootm_verbose(data))
+		print_segments(&info);
+
+	/* Verify all of the segments load to a valid location in memory */
+
+	/* Sort the segments and verify we don't have overlaps */
+	ret = sort_segments(&info);
+	if (IS_ERR_VALUE(ret))
+		return ret;
+
+	return kexec_load(data, info.entry, info.nr_segments, info.segment);
+}
-- 
2.14.1


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

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

* [PATCH v1 05/10] MIPS: add kexec ELF loading support
  2018-05-16 16:42 [PATCH v1 00/10] provide ELF/KEXEC support for MIPS ath79 and malta Oleksij Rempel
                   ` (3 preceding siblings ...)
  2018-05-16 16:42 ` [PATCH v1 04/10] bootm: add kexec ELF support Oleksij Rempel
@ 2018-05-16 16:42 ` Oleksij Rempel
  2018-05-17  9:56   ` Sascha Hauer
  2018-05-16 16:42 ` [PATCH v1 06/10] MIPS: ath79: enable kexec Oleksij Rempel
                   ` (4 subsequent siblings)
  9 siblings, 1 reply; 18+ messages in thread
From: Oleksij Rempel @ 2018-05-16 16:42 UTC (permalink / raw)
  To: barebox; +Cc: Peter Mamonov

From: Antony Pavlov <antonynpavlov@gmail.com>

Signed-off-by: Antony Pavlov <antonynpavlov@gmail.com>
Signed-off-by: Peter Mamonov <pmamonov@gmail.com>
---
 arch/mips/include/asm/elf.h        |   8 +-
 arch/mips/lib/Makefile             |   4 +
 arch/mips/lib/kexec-mach-generic.c |  21 +++
 arch/mips/lib/kexec-mips.c         | 307 +++++++++++++++++++++++++++++++++++++
 arch/mips/lib/machine_kexec.h      |  21 +++
 arch/mips/lib/relocate_kernel.S    | 108 +++++++++++++
 6 files changed, 468 insertions(+), 1 deletion(-)
 create mode 100644 arch/mips/lib/kexec-mach-generic.c
 create mode 100644 arch/mips/lib/kexec-mips.c
 create mode 100644 arch/mips/lib/machine_kexec.h
 create mode 100644 arch/mips/lib/relocate_kernel.S

diff --git a/arch/mips/include/asm/elf.h b/arch/mips/include/asm/elf.h
index b8b82191c..bf974f521 100644
--- a/arch/mips/include/asm/elf.h
+++ b/arch/mips/include/asm/elf.h
@@ -17,12 +17,18 @@
 
 #ifndef ELF_ARCH
 
+/* Legal values for e_machine (architecture).  */
+
+#define EM_MIPS		 8		/* MIPS R3000 big-endian */
+#define EM_MIPS_RS4_BE	10		/* MIPS R4000 big-endian */
+
 #ifdef CONFIG_32BIT
 
 /*
  * This is used to ensure we don't load something for the wrong architecture.
  */
-#define elf_check_arch(hdr)						\
+#define elf_check_arch(x) ((x)->e_machine == EM_MIPS)
+
 /*
  * These are used to set parameters in the core dumps.
  */
diff --git a/arch/mips/lib/Makefile b/arch/mips/lib/Makefile
index d25d0969f..29f6581b0 100644
--- a/arch/mips/lib/Makefile
+++ b/arch/mips/lib/Makefile
@@ -18,4 +18,8 @@ obj-$(CONFIG_CPU_MIPS64) += c-r4k.o
 obj-$(CONFIG_CMD_MIPS_CPUINFO) += cpuinfo.o
 obj-$(CONFIG_CMD_BOOTM)	+= bootm.o
 
+obj-$(CONFIG_KEXEC) += kexec-mips.o
+obj-$(CONFIG_KEXEC) += relocate_kernel.o
+obj-$(CONFIG_KEXEC) += kexec-mach-generic.o
+
 pbl-y	+= ashldi3.o
diff --git a/arch/mips/lib/kexec-mach-generic.c b/arch/mips/lib/kexec-mach-generic.c
new file mode 100644
index 000000000..def38cbc0
--- /dev/null
+++ b/arch/mips/lib/kexec-mach-generic.c
@@ -0,0 +1,21 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2018 Antony Pavlov <antonynpavlov@gmail.com>
+ */
+
+#include <asm/io.h>
+#include <common.h>
+#include <kexec.h>
+
+void kexec_arch(void *opaque)
+{
+	extern unsigned long reboot_code_buffer;
+	void (*kexec_code_buffer)(void);
+
+	shutdown_barebox();
+
+	kexec_code_buffer = phys_to_virt(reboot_code_buffer);
+
+	kexec_code_buffer();
+}
+EXPORT_SYMBOL(kexec_arch);
diff --git a/arch/mips/lib/kexec-mips.c b/arch/mips/lib/kexec-mips.c
new file mode 100644
index 000000000..781552f01
--- /dev/null
+++ b/arch/mips/lib/kexec-mips.c
@@ -0,0 +1,307 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * kexec-mips.c - kexec for mips
+ * Copyright (C) 2007 Francesco Chiechi, Alessandro Rubini
+ * Copyright (C) 2007 Tvblob s.r.l.
+ *
+ * derived from ../ppc/kexec-mips.c
+ * Copyright (C) 2004, 2005 Albert Herranz
+ *
+ */
+
+#include <asm/io.h>
+#include <common.h>
+#include <elf.h>
+#include <environment.h>
+#include <globalvar.h>
+#include <init.h>
+#include <kexec.h>
+#include <magicvar.h>
+#include <memory.h>
+#include "machine_kexec.h"
+
+static unsigned int mips_boot_protocol;
+
+enum mips_boot_names {
+	MIPS_BOOT_FDT,
+	MIPS_BOOT_LEGACY,
+};
+
+static int elf_mips_probe(const char *buf, off_t len)
+{
+	struct mem_ehdr ehdr;
+	int ret;
+
+	ret = build_elf_exec_info(buf, len, &ehdr);
+	if (IS_ERR_VALUE(ret)) {
+		goto out;
+	}
+
+	if (ehdr.e_machine != EM_MIPS) {
+		pr_err("Not for this architecture.\n");
+		ret = -EFAULT;
+		goto out;
+	}
+
+ out:
+	free_elf_info(&ehdr);
+
+	return ret;
+}
+
+static int elf_mips_load(const char *buf, off_t len, struct kexec_info *info)
+{
+	struct mem_ehdr ehdr;
+	int ret;
+	size_t i;
+
+	ret = build_elf_exec_info(buf, len, &ehdr);
+	if (IS_ERR_VALUE(ret)) {
+		pr_err("ELF exec parse failed\n");
+		goto out;
+	}
+
+	/* Read in the PT_LOAD segments and remove CKSEG0 mask from address */
+	for (i = 0; i < ehdr.e_phnum; i++) {
+		struct mem_phdr *phdr;
+		phdr = &ehdr.e_phdr[i];
+		if (phdr->p_type == PT_LOAD) {
+			phdr->p_paddr = virt_to_phys((const void *)phdr->p_paddr);
+		}
+	}
+
+	/* Load the ELF data */
+	ret = elf_exec_load(&ehdr, info);
+	if (IS_ERR_VALUE(ret)) {
+		pr_err("ELF exec load failed\n");
+		goto out;
+	}
+
+	info->entry = (void *)virt_to_phys((void *)ehdr.e_entry);
+
+out:
+	return ret;
+}
+
+struct kexec_file_type kexec_file_type[] = {
+	{"elf-mips", elf_mips_probe, elf_mips_load },
+};
+int kexec_file_types = sizeof(kexec_file_type) / sizeof(kexec_file_type[0]);
+
+/*
+ * add_segment() should convert base to a physical address on mips,
+ * while the default is just to work with base as is */
+void add_segment(struct kexec_info *info, const void *buf, size_t bufsz,
+		 unsigned long base, size_t memsz)
+{
+	add_segment_phys_virt(info, buf, bufsz,
+		virt_to_phys((void *)base), memsz, 1);
+}
+
+/* relocator parameters */
+extern unsigned long relocate_new_kernel;
+extern unsigned long relocate_new_kernel_size;
+extern unsigned long kexec_start_address;
+extern unsigned long kexec_segments;
+extern unsigned long kexec_nr_segments;
+
+unsigned long reboot_code_buffer;
+
+static void machine_kexec_print_args(bool have_argv)
+{
+	unsigned long argc = (int)kexec_args[0];
+	int i;
+
+	pr_info("kexec_args[0] (argc): %lu\n", argc);
+	pr_info("kexec_args[1] (argv): %p\n", (void *)kexec_args[1]);
+	pr_info("kexec_args[2] (env ): %p\n", (void *)kexec_args[2]);
+	pr_info("kexec_args[3] (desc): %p\n", (void *)kexec_args[3]);
+
+	if (!have_argv)
+		return;
+
+	for (i = 0; i < argc; i++) {
+		pr_info("kexec_argv[%d] = %p, %s\n",
+				i, kexec_argv[i], kexec_argv[i]);
+	}
+}
+
+static void machine_kexec_init_argv(struct kexec_segment *segments, unsigned long nr_segments)
+{
+	const void __user *buf = NULL;
+	size_t bufsz;
+	size_t size;
+	int i;
+
+	bufsz = 0;
+	for (i = 0; i < nr_segments; i++) {
+		struct kexec_segment *seg;
+
+		seg = &segments[i];
+		if (seg->bufsz < 6)
+			continue;
+
+		if (strncmp((char *) seg->buf, "kexec ", 6)) {
+			continue;
+		}
+
+		buf = seg->buf + 6;
+		bufsz = seg->bufsz - 6;
+		break;
+	}
+
+	if (!buf)
+		return;
+
+	size = KEXEC_COMMAND_LINE_SIZE;
+	size = min(size, bufsz);
+	if (size < bufsz)
+		pr_warn("kexec command line truncated to %zu bytes\n", size);
+
+	/* Copy to kernel space */
+	memcpy(kexec_argv_buf, buf, size);
+	kexec_argv_buf[size - 1] = 0;
+}
+
+static void machine_kexec_parse_argv(void)
+{
+	char *ptr;
+	int argc;
+
+	ptr = kexec_argv_buf;
+	argc = 1;
+
+	/*
+	 * convert command line string to array of parameters
+	 * (as bootloader does).
+	 */
+	while (ptr && *ptr && (KEXEC_MAX_ARGC > argc)) {
+		if (*ptr == ' ') {
+			*ptr++ = '\0';
+			continue;
+		}
+
+		kexec_argv[argc++] = ptr;
+		ptr = strchr(ptr, ' ');
+	}
+
+	if (!argc)
+		return;
+
+	kexec_args[0] = argc;
+	kexec_args[1] = (unsigned long)kexec_argv;
+	kexec_args[2] = 0;
+	kexec_args[3] = 0;
+}
+
+static void machine_kexec_fdt(struct image_data *data)
+{
+	kexec_args[0] = -2;
+	kexec_args[1] = (unsigned long)data->oftree_address;
+	kexec_args[2] = 0;
+	kexec_args[3] = 0;
+}
+
+
+static int machine_kexec_prepare(struct image_data *data,
+				 struct kexec_segment *segments,
+				 unsigned long nr_segments)
+{
+	if (mips_boot_protocol == MIPS_BOOT_FDT) {
+		machine_kexec_fdt(data);
+		machine_kexec_print_args(0);
+	} else {
+		machine_kexec_init_argv(segments, nr_segments);
+		machine_kexec_parse_argv();
+		machine_kexec_print_args(1);
+	}
+
+	return 0;
+}
+
+int kexec_load(struct image_data *data, void *entry,
+	       unsigned long nr_segments,
+	       struct kexec_segment *segments)
+{
+	int i;
+	struct resource *elf;
+	resource_size_t start;
+	LIST_HEAD(elf_segments);
+
+	for (i = 0; i < nr_segments; i++) {
+		resource_size_t mem = (resource_size_t)segments[i].mem;
+
+		elf = create_resource("elf segment",
+			mem, mem + segments[i].memsz - 1);
+
+		list_add_used_region(&elf->sibling, &elf_segments);
+	}
+
+	if (check_room_for_elf(&elf_segments)) {
+		pr_err("ELF can't be loaded!\n");
+		return -ENOSPC;
+	}
+
+	start = dcheck_res(&elf_segments);
+
+	/* relocate_new_kernel() copy by register (4 or 8 bytes)
+	   so start address must be aligned to 4/8 */
+	start = (start + 15) & 0xfffffff0;
+
+	for (i = 0; i < nr_segments; i++) {
+		segments[i].mem = (void *)(phys_to_virt((unsigned long)segments[i].mem));
+		memcpy(phys_to_virt(start), segments[i].buf, segments[i].bufsz);
+		request_sdram_region("kexec relocatable segment",
+			(unsigned long)phys_to_virt(start),
+			(unsigned long)segments[i].bufsz);
+
+		/* relocate_new_kernel() copy by register (4 or 8 bytes)
+		   so bufsz must be aligned to 4/8 */
+		segments[i].bufsz = (segments[i].bufsz + 15) & 0xfffffff0;
+		segments[i].buf = phys_to_virt(start);
+		start = start + segments[i].bufsz;
+	}
+
+	start = (start + 15) & 0xfffffff0;
+
+	reboot_code_buffer = start;
+
+	memcpy(phys_to_virt(start), &relocate_new_kernel,
+		relocate_new_kernel_size);
+	request_sdram_region("kexec relocator",
+		(unsigned long)phys_to_virt(start),
+		(unsigned long)relocate_new_kernel_size);
+
+	start = start + relocate_new_kernel_size;
+	start = (start + 15) & 0xfffffff0;
+
+	kexec_start_address = (unsigned long)phys_to_virt((unsigned long)entry);
+	kexec_segments = (unsigned long)phys_to_virt((unsigned long)start);
+	kexec_nr_segments = nr_segments;
+
+	memcpy(phys_to_virt(start), segments, nr_segments * sizeof(*segments));
+	request_sdram_region("kexec control segments",
+		(unsigned long)phys_to_virt(start),
+		(unsigned long)nr_segments * sizeof(*segments));
+
+	machine_kexec_prepare(data, segments, nr_segments);
+
+	return 0;
+}
+
+static const char *mips_boot_names[] = {
+	"fdt", "legacy"
+};
+
+static int mips_kexec_globalvars_init(void)
+{
+	globalvar_add_simple_enum("bootm.mips.boot_protocol",
+				   &mips_boot_protocol, mips_boot_names,
+				   ARRAY_SIZE(mips_boot_names));
+	return 0;
+}
+device_initcall(mips_kexec_globalvars_init);
+
+BAREBOX_MAGICVAR_NAMED(global_bootm_mips_boot_protocol,
+		       global_bootm_mips_boot_protocol,
+		       "bootm.mips.boot_protocol: boot protocol used to start kernel");
diff --git a/arch/mips/lib/machine_kexec.h b/arch/mips/lib/machine_kexec.h
new file mode 100644
index 000000000..b495d15c2
--- /dev/null
+++ b/arch/mips/lib/machine_kexec.h
@@ -0,0 +1,21 @@
+#ifndef _MACHINE_KEXEC_H
+#define _MACHINE_KEXEC_H
+
+#ifndef __ASSEMBLY__
+extern const unsigned char kexec_relocate_new_kernel[];
+extern unsigned long kexec_relocate_new_kernel_end;
+extern unsigned long kexec_start_address;
+extern unsigned long kexec_indirection_page;
+
+extern unsigned long kexec_args[4];
+extern char kexec_argv_buf[];
+extern char *kexec_argv[];
+
+#define KEXEC_RELOCATE_NEW_KERNEL_SIZE	((unsigned long)&kexec_relocate_new_kernel_end - (unsigned long)kexec_relocate_new_kernel)
+#endif /* !__ASSEMBLY__ */
+
+#define KEXEC_COMMAND_LINE_SIZE		256
+#define KEXEC_ARGV_SIZE			(KEXEC_COMMAND_LINE_SIZE / 16)
+#define KEXEC_MAX_ARGC			(KEXEC_ARGV_SIZE / sizeof(long))
+
+#endif
diff --git a/arch/mips/lib/relocate_kernel.S b/arch/mips/lib/relocate_kernel.S
new file mode 100644
index 000000000..d9a61353a
--- /dev/null
+++ b/arch/mips/lib/relocate_kernel.S
@@ -0,0 +1,108 @@
+/*
+ * Copyright (C) 2012, 2016 Antony Pavlov <antonynpavlov@gmail.com>
+ *
+ * based on relocate_kernel.S for kexec
+ * Created by <nschichan@corp.free.fr> on Thu Oct 12 17:49:57 2006
+ *
+ * This file is part of barebox.
+ * See file CREDITS for list of people who contributed to this project.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <asm/asm.h>
+#include <asm/regdef.h>
+#include <asm/mipsregs.h>
+#include <asm/addrspace.h>
+#include "machine_kexec.h"
+
+LEAF(relocate_new_kernel)
+	.set	push
+	.set	reorder
+	PTR_L		a0, arg0
+	PTR_L		a1, arg1
+	PTR_L		a2, arg2
+	PTR_L		a3, arg3
+
+	PTR_L		s0, kexec_segments
+	PTR_L		s1, kexec_nr_segments
+	PTR_L		s2, kexec_start_address
+
+process_segment:
+	PTR_L		s4, (s0) /* buf */
+	PTR_L		s5, SZREG (s0) /* bufsz */
+	PTR_L		s6, 2*SZREG (s0) /* mem */
+
+copy_segment:
+	/* copy segment word by word */
+	REG_L		s7, (s4)
+	REG_S		s7, (s6)
+	PTR_ADD		s4, s4, SZREG
+	PTR_ADD		s6, s6, SZREG
+	LONG_SUB	s5, s5, SZREG
+	bne		s5, zero, copy_segment
+
+	LONG_SUB	s1, s1, 1
+	beq		s1, zero, done
+
+	PTR_ADD		s0, s0, 4*SZREG
+
+	b		process_segment
+
+done:
+	/* jump to kexec_start_address */
+	j		s2
+	END(relocate_new_kernel)
+
+/* All parameters to new kernel are passed in registers a0-a3.
+ * kexec_args[0..3] are uses to prepare register values.
+ */
+
+kexec_args:
+	EXPORT(kexec_args)
+arg0:	PTR		0x0
+arg1:	PTR		0x0
+arg2:	PTR		0x0
+arg3:	PTR		0x0
+	.size	kexec_args,PTRSIZE*4
+
+kexec_start_address:
+	EXPORT(kexec_start_address)
+	PTR		0x0
+	.size		kexec_start_address, PTRSIZE
+
+kexec_argv_buf:
+	EXPORT(kexec_argv_buf)
+	.skip		KEXEC_COMMAND_LINE_SIZE
+	.size		kexec_argv_buf, KEXEC_COMMAND_LINE_SIZE
+
+kexec_argv:
+	EXPORT(kexec_argv)
+	.skip		KEXEC_ARGV_SIZE
+	.size		kexec_argv, KEXEC_ARGV_SIZE
+
+kexec_segments:
+	EXPORT(kexec_segments)
+	PTR		0x0
+	.size		kexec_segments, PTRSIZE
+
+kexec_nr_segments:
+	EXPORT(kexec_nr_segments)
+	PTR		0x0
+	.size		kexec_nr_segments, PTRSIZE
+
+relocate_new_kernel_end:
+
+relocate_new_kernel_size:
+	EXPORT(relocate_new_kernel_size)
+	PTR		relocate_new_kernel_end - relocate_new_kernel
+	.size		relocate_new_kernel_size, PTRSIZE
+	.set	pop
-- 
2.14.1


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

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

* [PATCH v1 06/10] MIPS: ath79: enable kexec
  2018-05-16 16:42 [PATCH v1 00/10] provide ELF/KEXEC support for MIPS ath79 and malta Oleksij Rempel
                   ` (4 preceding siblings ...)
  2018-05-16 16:42 ` [PATCH v1 05/10] MIPS: add kexec ELF loading support Oleksij Rempel
@ 2018-05-16 16:42 ` Oleksij Rempel
  2018-05-16 16:42 ` [PATCH v1 07/10] MIPS: malta: " Oleksij Rempel
                   ` (3 subsequent siblings)
  9 siblings, 0 replies; 18+ messages in thread
From: Oleksij Rempel @ 2018-05-16 16:42 UTC (permalink / raw)
  To: barebox; +Cc: Oleksij Rempel

Signed-off-by: Oleksij Rempel <linux@rempel-privat.de>
---
 arch/mips/Kconfig | 1 +
 1 file changed, 1 insertion(+)

diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig
index c2c555dc3..2b549373a 100644
--- a/arch/mips/Kconfig
+++ b/arch/mips/Kconfig
@@ -73,6 +73,7 @@ config MACH_MIPS_ATH79
 	select CLKDEV_LOOKUP
 	select OFTREE
 	select GPIOLIB
+	select HAS_KEXEC
 
 config MACH_MIPS_BCM47XX
 	bool "Broadcom BCM47xx-based boards"
-- 
2.14.1


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

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

* [PATCH v1 07/10] MIPS: malta: enable kexec
  2018-05-16 16:42 [PATCH v1 00/10] provide ELF/KEXEC support for MIPS ath79 and malta Oleksij Rempel
                   ` (5 preceding siblings ...)
  2018-05-16 16:42 ` [PATCH v1 06/10] MIPS: ath79: enable kexec Oleksij Rempel
@ 2018-05-16 16:42 ` Oleksij Rempel
  2018-05-16 16:42 ` [PATCH v1 08/10] MIPS: configs: add KEXEC=y to atheros devices Oleksij Rempel
                   ` (2 subsequent siblings)
  9 siblings, 0 replies; 18+ messages in thread
From: Oleksij Rempel @ 2018-05-16 16:42 UTC (permalink / raw)
  To: barebox

From: Antony Pavlov <antonynpavlov@gmail.com>

Signed-off-by: Antony Pavlov <antonynpavlov@gmail.com>
---
 arch/mips/Kconfig | 1 +
 1 file changed, 1 insertion(+)

diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig
index 2b549373a..ab5a05e0d 100644
--- a/arch/mips/Kconfig
+++ b/arch/mips/Kconfig
@@ -51,6 +51,7 @@ config MACH_MIPS_MALTA
 	select HAS_DEBUG_LL
 	select GPIOLIB
 	select HW_HAS_PCI
+	select HAS_KEXEC
 
 config MACH_MIPS_AR231X
 	bool "Atheros ar231x-based boards"
-- 
2.14.1


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

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

* [PATCH v1 08/10] MIPS: configs: add KEXEC=y to atheros devices
  2018-05-16 16:42 [PATCH v1 00/10] provide ELF/KEXEC support for MIPS ath79 and malta Oleksij Rempel
                   ` (6 preceding siblings ...)
  2018-05-16 16:42 ` [PATCH v1 07/10] MIPS: malta: " Oleksij Rempel
@ 2018-05-16 16:42 ` Oleksij Rempel
  2018-05-16 16:42 ` [PATCH v1 09/10] MIPS: configs: dptechnics-dpt-module: enable watchdog poller Oleksij Rempel
  2018-05-16 16:42 ` [PATCH v1 10/10] MIPS: malta: update malta qemu defconfig Oleksij Rempel
  9 siblings, 0 replies; 18+ messages in thread
From: Oleksij Rempel @ 2018-05-16 16:42 UTC (permalink / raw)
  To: barebox; +Cc: Oleksij Rempel

currently kexec is the only way we can boot linux kernel on this
devices. So enable it in configs per default.

Signed-off-by: Oleksij Rempel <linux@rempel-privat.de>
---
 arch/mips/configs/8devices-lima_defconfig         | 1 +
 arch/mips/configs/black-swift_defconfig           | 1 +
 arch/mips/configs/dptechnics-dpt-module_defconfig | 1 +
 arch/mips/configs/tplink-mr3020_defconfig         | 1 +
 arch/mips/configs/tplink-wdr4300_defconfig        | 1 +
 5 files changed, 5 insertions(+)

diff --git a/arch/mips/configs/8devices-lima_defconfig b/arch/mips/configs/8devices-lima_defconfig
index 446369a54..107d6c5cf 100644
--- a/arch/mips/configs/8devices-lima_defconfig
+++ b/arch/mips/configs/8devices-lima_defconfig
@@ -20,6 +20,7 @@ CONFIG_CMD_GO=y
 CONFIG_CMD_LOADB=y
 CONFIG_CMD_LOADY=y
 CONFIG_CMD_RESET=y
+CONFIG_KEXEC=y
 CONFIG_CMD_EXPORT=y
 CONFIG_CMD_DEFAULTENV=y
 CONFIG_CMD_LOADENV=y
diff --git a/arch/mips/configs/black-swift_defconfig b/arch/mips/configs/black-swift_defconfig
index 1a72cfbd7..71a4f5963 100644
--- a/arch/mips/configs/black-swift_defconfig
+++ b/arch/mips/configs/black-swift_defconfig
@@ -25,6 +25,7 @@ CONFIG_CMD_GO=y
 CONFIG_CMD_LOADB=y
 CONFIG_CMD_LOADY=y
 CONFIG_CMD_RESET=y
+CONFIG_KEXEC=y
 CONFIG_CMD_PARTITION=y
 CONFIG_CMD_GLOBAL=y
 CONFIG_CMD_SHA1SUM=y
diff --git a/arch/mips/configs/dptechnics-dpt-module_defconfig b/arch/mips/configs/dptechnics-dpt-module_defconfig
index c01b22b98..33049164c 100644
--- a/arch/mips/configs/dptechnics-dpt-module_defconfig
+++ b/arch/mips/configs/dptechnics-dpt-module_defconfig
@@ -22,6 +22,7 @@ CONFIG_CMD_GO=y
 CONFIG_CMD_LOADB=y
 CONFIG_CMD_LOADY=y
 CONFIG_CMD_RESET=y
+CONFIG_KEXEC=y
 CONFIG_CMD_EXPORT=y
 CONFIG_CMD_DEFAULTENV=y
 CONFIG_CMD_LOADENV=y
diff --git a/arch/mips/configs/tplink-mr3020_defconfig b/arch/mips/configs/tplink-mr3020_defconfig
index 4193bd628..84753650b 100644
--- a/arch/mips/configs/tplink-mr3020_defconfig
+++ b/arch/mips/configs/tplink-mr3020_defconfig
@@ -19,6 +19,7 @@ CONFIG_CMD_GO=y
 CONFIG_CMD_LOADB=y
 CONFIG_CMD_LOADY=y
 CONFIG_CMD_RESET=y
+CONFIG_KEXEC=y
 CONFIG_CMD_EXPORT=y
 CONFIG_CMD_DEFAULTENV=y
 CONFIG_CMD_LOADENV=y
diff --git a/arch/mips/configs/tplink-wdr4300_defconfig b/arch/mips/configs/tplink-wdr4300_defconfig
index 46093d243..1ba799d27 100644
--- a/arch/mips/configs/tplink-wdr4300_defconfig
+++ b/arch/mips/configs/tplink-wdr4300_defconfig
@@ -20,6 +20,7 @@ CONFIG_CMD_GO=y
 CONFIG_CMD_LOADB=y
 CONFIG_CMD_LOADY=y
 CONFIG_CMD_RESET=y
+CONFIG_KEXEC=y
 CONFIG_CMD_EXPORT=y
 CONFIG_CMD_DEFAULTENV=y
 CONFIG_CMD_LOADENV=y
-- 
2.14.1


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

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

* [PATCH v1 09/10] MIPS: configs: dptechnics-dpt-module: enable watchdog poller
  2018-05-16 16:42 [PATCH v1 00/10] provide ELF/KEXEC support for MIPS ath79 and malta Oleksij Rempel
                   ` (7 preceding siblings ...)
  2018-05-16 16:42 ` [PATCH v1 08/10] MIPS: configs: add KEXEC=y to atheros devices Oleksij Rempel
@ 2018-05-16 16:42 ` Oleksij Rempel
  2018-05-16 16:42 ` [PATCH v1 10/10] MIPS: malta: update malta qemu defconfig Oleksij Rempel
  9 siblings, 0 replies; 18+ messages in thread
From: Oleksij Rempel @ 2018-05-16 16:42 UTC (permalink / raw)
  To: barebox; +Cc: Oleksij Rempel

Signed-off-by: Oleksij Rempel <linux@rempel-privat.de>
---
 arch/mips/configs/dptechnics-dpt-module_defconfig | 1 +
 1 file changed, 1 insertion(+)

diff --git a/arch/mips/configs/dptechnics-dpt-module_defconfig b/arch/mips/configs/dptechnics-dpt-module_defconfig
index 33049164c..4ba1bb238 100644
--- a/arch/mips/configs/dptechnics-dpt-module_defconfig
+++ b/arch/mips/configs/dptechnics-dpt-module_defconfig
@@ -82,6 +82,7 @@ CONFIG_LED_GPIO=y
 CONFIG_LED_GPIO_OF=y
 CONFIG_LED_TRIGGERS=y
 CONFIG_WATCHDOG=y
+CONFIG_WATCHDOG_POLLER=y
 CONFIG_WATCHDOG_AR9344=y
 CONFIG_FS_TFTP=y
 CONFIG_FS_NFS=y
-- 
2.14.1


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

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

* [PATCH v1 10/10] MIPS: malta: update malta qemu defconfig
  2018-05-16 16:42 [PATCH v1 00/10] provide ELF/KEXEC support for MIPS ath79 and malta Oleksij Rempel
                   ` (8 preceding siblings ...)
  2018-05-16 16:42 ` [PATCH v1 09/10] MIPS: configs: dptechnics-dpt-module: enable watchdog poller Oleksij Rempel
@ 2018-05-16 16:42 ` Oleksij Rempel
  9 siblings, 0 replies; 18+ messages in thread
From: Oleksij Rempel @ 2018-05-16 16:42 UTC (permalink / raw)
  To: barebox; +Cc: Oleksij Rempel

Signed-off-by: Oleksij Rempel <linux@rempel-privat.de>
---
 arch/mips/configs/qemu-malta_defconfig | 13 ++++++++++---
 1 file changed, 10 insertions(+), 3 deletions(-)

diff --git a/arch/mips/configs/qemu-malta_defconfig b/arch/mips/configs/qemu-malta_defconfig
index 9671e93dc..f7d30ba17 100644
--- a/arch/mips/configs/qemu-malta_defconfig
+++ b/arch/mips/configs/qemu-malta_defconfig
@@ -1,8 +1,10 @@
 CONFIG_BUILTIN_DTB=y
 CONFIG_BUILTIN_DTB_NAME="qemu-malta"
 CONFIG_PBL_IMAGE=y
-CONFIG_BAREBOX_MAX_IMAGE_SIZE=0x400000
+CONFIG_MMU=y
+CONFIG_TEXT_BASE=0x84000000
 CONFIG_STACK_SIZE=0x7000
+CONFIG_MALLOC_SIZE=0x2000000
 CONFIG_EXPERIMENTAL=y
 CONFIG_BAUDRATE=38400
 CONFIG_HUSH_FANCY_PROMPT=y
@@ -11,7 +13,9 @@ CONFIG_AUTO_COMPLETE=y
 CONFIG_MENU=y
 CONFIG_BOOTM_SHOW_TYPE=y
 CONFIG_PARTITION=y
-# CONFIG_DEFAULT_ENVIRONMENT is not set
+CONFIG_DEFAULT_COMPRESSION_GZIP=y
+CONFIG_DEFAULT_ENVIRONMENT_GENERIC_NEW=y
+CONFIG_DEFAULT_ENVIRONMENT_PATH="arch/mips/boards/qemu-malta/env"
 CONFIG_POLLER=y
 CONFIG_DEBUG_INFO=y
 CONFIG_LONGHELP=y
@@ -22,16 +26,19 @@ CONFIG_CMD_GO=y
 CONFIG_CMD_LOADB=y
 CONFIG_CMD_LOADY=y
 CONFIG_CMD_RESET=y
+CONFIG_KEXEC=y
 CONFIG_CMD_PARTITION=y
 CONFIG_CMD_EXPORT=y
+CONFIG_CMD_DEFAULTENV=y
 CONFIG_CMD_LOADENV=y
 CONFIG_CMD_PRINTENV=y
+CONFIG_CMD_MAGICVAR=y
+CONFIG_CMD_MAGICVAR_HELP=y
 CONFIG_CMD_SAVEENV=y
 CONFIG_CMD_MD5SUM=y
 CONFIG_CMD_SHA1SUM=y
 CONFIG_CMD_SHA256SUM=y
 CONFIG_CMD_UNCOMPRESS=y
-CONFIG_CMD_GETOPT=y
 CONFIG_CMD_SLEEP=y
 CONFIG_CMD_DHCP=y
 CONFIG_CMD_MIITOOL=y
-- 
2.14.1


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

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

* Re: [PATCH v1 04/10] bootm: add kexec ELF support
  2018-05-16 16:42 ` [PATCH v1 04/10] bootm: add kexec ELF support Oleksij Rempel
@ 2018-05-16 21:34   ` Peter Mamonov
  2018-05-17  4:52     ` Oleksij Rempel
  0 siblings, 1 reply; 18+ messages in thread
From: Peter Mamonov @ 2018-05-16 21:34 UTC (permalink / raw)
  To: Oleksij Rempel; +Cc: barebox

Hi!

On Wed, May 16, 2018 at 06:42:27PM +0200, Oleksij Rempel wrote:
> From: Antony Pavlov <antonynpavlov@gmail.com>
> 
> Also introduce reboot() for starting already loaded
> via kexec ELF segments.
> 
> Signed-off-by: Antony Pavlov <antonynpavlov@gmail.com>
> ---
>  commands/Kconfig            |   7 +
>  common/Kconfig              |   3 +
>  include/bootm.h             |   3 +
>  include/kexec.h             | 118 +++++++++
>  lib/Makefile                |   1 +
>  lib/kexec/Makefile          |   4 +
>  lib/kexec/kexec-bootm-elf.c |  42 ++++
>  lib/kexec/kexec-elf-exec.c  |  70 ++++++
>  lib/kexec/kexec-elf.c       | 565 ++++++++++++++++++++++++++++++++++++++++++++
>  lib/kexec/kexec.c           | 255 ++++++++++++++++++++
>  10 files changed, 1068 insertions(+)
>  create mode 100644 include/kexec.h
>  create mode 100644 lib/kexec/Makefile
>  create mode 100644 lib/kexec/kexec-bootm-elf.c
>  create mode 100644 lib/kexec/kexec-elf-exec.c
>  create mode 100644 lib/kexec/kexec-elf.c
>  create mode 100644 lib/kexec/kexec.c
> 
> diff --git a/commands/Kconfig b/commands/Kconfig
> index 951a86963..a49928ad1 100644
> --- a/commands/Kconfig
> +++ b/commands/Kconfig
> @@ -476,6 +476,13 @@ config CMD_SAVES
>  
>  	  Save S-Record file to serial line with offset OFFS and length LEN.
>  
> +config KEXEC
> +	bool
> +	prompt "bootm ELF image support"
> +	depends on CMD_BOOTM && HAS_KEXEC
> +	help
> +	  Support using ELF Images.
> +
>  config CMD_UIMAGE
>  	select UIMAGE
>  	tristate
> diff --git a/common/Kconfig b/common/Kconfig
> index b7000c4d7..d40c79dbc 100644
> --- a/common/Kconfig
> +++ b/common/Kconfig
> @@ -1218,3 +1218,6 @@ config HAS_DEBUG_LL
>  config DDR_SPD
>  	bool
>  	select CRC16
> +
> +config HAS_KEXEC
> +	bool
> diff --git a/include/bootm.h b/include/bootm.h
> index 62951d605..3a642fe70 100644
> --- a/include/bootm.h
> +++ b/include/bootm.h
> @@ -72,6 +72,9 @@ struct image_data {
>  
>  	char *oftree_file;
>  	char *oftree_part;
> +	unsigned long oftree_address;
> +
> +	unsigned long cmdline_address;
>  
>  	const void *fit_kernel;
>  	unsigned long fit_kernel_size;
> diff --git a/include/kexec.h b/include/kexec.h
> new file mode 100644
> index 000000000..675658b38
> --- /dev/null
> +++ b/include/kexec.h
> @@ -0,0 +1,118 @@
> +#ifndef _LINUX_REBOOT_H
> +#define _LINUX_REBOOT_H
> +
> +#include <bootm.h>
> +
> +struct kexec_segment {
> +	const void *buf;
> +	size_t bufsz;
> +	const void *mem;
> +	size_t memsz;
> +};
> +
> +struct kexec_info {
> +	struct kexec_segment *segment;
> +	int nr_segments;
> +	void *entry;
> +	unsigned long kexec_flags;
> +};
> +
> +typedef int (probe_t)(const char *kernel_buf, off_t kernel_size);
> +typedef int (load_t)(const char *kernel_buf, off_t kernel_size,
> +	struct kexec_info *info);
> +struct kexec_file_type {
> +	const char *name;
> +	probe_t *probe;
> +	load_t  *load;
> +};
> +
> +extern struct kexec_file_type kexec_file_type[];
> +extern int kexec_file_types;
> +
> +extern void add_segment(struct kexec_info *info,
> +	const void *buf, size_t bufsz, unsigned long base, size_t memsz);
> +extern void add_segment_phys_virt(struct kexec_info *info,
> +	const void *buf, size_t bufsz, unsigned long base, size_t memsz,
> +	int phys);
> +
> +extern int kexec_load(struct image_data *data, void *entry,
> +		      unsigned long nr_segments,
> +		      struct kexec_segment *segments);
> +
> +extern void kexec_arch(void *opaque);
> +
> +extern int kexec_load_bootm_data(struct image_data *data);
> +
> +/* These values match the ELF architecture values.
> + * Unless there is a good reason that should continue to be the case.
> + */
> +#define KEXEC_ARCH_DEFAULT	(0 << 16)
> +#define KEXEC_ARCH_386		(3 << 16)
> +#define KEXEC_ARCH_X86_64	(62 << 16)
> +#define KEXEC_ARCH_PPC		(20 << 16)
> +#define KEXEC_ARCH_PPC64	(21 << 16)
> +#define KEXEC_ARCH_IA_64	(50 << 16)
> +#define KEXEC_ARCH_ARM		(40 << 16)
> +#define KEXEC_ARCH_S390		(22 << 16)
> +#define KEXEC_ARCH_SH		(42 << 16)
> +#define KEXEC_ARCH_MIPS_LE	(10 << 16)
> +#define KEXEC_ARCH_MIPS		(8 << 16)
> +#define KEXEC_ARCH_CRIS		(76 << 16)
> +
> +#define KEXEC_MAX_SEGMENTS 16
> +
> +struct mem_phdr {
> +	u64 p_paddr;
> +	u64 p_vaddr;
> +	u64 p_filesz;
> +	u64 p_memsz;
> +	u64 p_offset;
> +	const char *p_data;
> +	u32 p_type;
> +	u32 p_flags;
> +	u64 p_align;
> +};
> +
> +struct mem_shdr {
> +	u32 sh_name;
> +	u32 sh_type;
> +	u64 sh_flags;
> +	u64 sh_addr;
> +	u64 sh_offset;
> +	u64 sh_size;
> +	u32 sh_link;
> +	u32 sh_info;
> +	u64 sh_addralign;
> +	u64 sh_entsize;
> +	const unsigned char *sh_data;
> +};
> +
> +struct mem_ehdr {
> +	u32 ei_class;
> +	u32 ei_data;
> +	u32 e_type;
> +	u32 e_machine;
> +	u32 e_version;
> +	u32 e_flags;
> +	u32 e_phnum;
> +	u32 e_shnum;
> +	u32 e_shstrndx;
> +	u64 e_entry;
> +	u64 e_phoff;
> +	u64 e_shoff;
> +	struct mem_phdr *e_phdr;
> +	struct mem_shdr *e_shdr;
> +};
> +
> +void free_elf_info(struct mem_ehdr *ehdr);
> +int build_elf_info(const char *buf, size_t len, struct mem_ehdr *ehdr);
> +int build_elf_exec_info(const char *buf, off_t len, struct mem_ehdr *ehdr);
> +
> +int elf_exec_load(struct mem_ehdr *ehdr, struct kexec_info *info);
> +
> +unsigned long elf_max_addr(const struct mem_ehdr *ehdr);
> +int check_room_for_elf(struct list_head *elf_segments);
> +resource_size_t dcheck_res(struct list_head *elf_segments);
> +void list_add_used_region(struct list_head *new, struct list_head *head);
> +
> +#endif /* _LINUX_REBOOT_H */
> diff --git a/lib/Makefile b/lib/Makefile
> index a7498288a..eebaf3488 100644
> --- a/lib/Makefile
> +++ b/lib/Makefile
> @@ -65,3 +65,4 @@ obj-y			+= int_sqrt.o
>  obj-y			+= parseopt.o
>  obj-y			+= clz_ctz.o
>  obj-$(CONFIG_CRC_CCITT) += crc-ccitt.o
> +obj-$(CONFIG_KEXEC)	+= kexec/
> diff --git a/lib/kexec/Makefile b/lib/kexec/Makefile
> new file mode 100644
> index 000000000..2f3dc1dd3
> --- /dev/null
> +++ b/lib/kexec/Makefile
> @@ -0,0 +1,4 @@
> +obj-y	+= kexec.o
> +obj-y	+= kexec-elf.o
> +obj-y	+= kexec-elf-exec.o
> +obj-y	+= kexec-bootm-elf.o
> diff --git a/lib/kexec/kexec-bootm-elf.c b/lib/kexec/kexec-bootm-elf.c
> new file mode 100644
> index 000000000..2530466a5
> --- /dev/null
> +++ b/lib/kexec/kexec-bootm-elf.c
> @@ -0,0 +1,42 @@
> +// SPDX-License-Identifier: GPL-2.0+
> +
> +#include <binfmt.h>
> +#include <bootm.h>
> +#include <init.h>
> +#include <kexec.h>
> +
> +static int do_bootm_elf(struct image_data *data)
> +{
> +	int ret;
> +
> +	ret = kexec_load_bootm_data(data);
> +	if (IS_ERR_VALUE(ret))
> +		return ret;
> +	
> +	kexec_arch(data);
> +
> +	return -ERESTARTSYS;
> +}
> +
> +static struct image_handler elf_handler = {
> +	.name = "ELF",
> +	.bootm = do_bootm_elf,
> +	.filetype = filetype_elf,
> +};
> +
> +static struct binfmt_hook binfmt_elf_hook = {
> +	.type = filetype_elf,
> +	.exec = "bootm",
> +};
> +
> +static int elf_register_image_handler(void)
> +{
> +	int ret;
> +
> +	ret = register_image_handler(&elf_handler);
> +	if (IS_ERR_VALUE(ret))
> +		return ret;
> +	
> +	return binfmt_register(&binfmt_elf_hook);
> +}
> +late_initcall(elf_register_image_handler);
> diff --git a/lib/kexec/kexec-elf-exec.c b/lib/kexec/kexec-elf-exec.c
> new file mode 100644
> index 000000000..e910c4ea0
> --- /dev/null
> +++ b/lib/kexec/kexec-elf-exec.c
> @@ -0,0 +1,70 @@
> +// SPDX-License-Identifier: GPL-2.0+
> +
> +#include <common.h>
> +#include <kexec.h>
> +
> +int build_elf_exec_info(const char *buf, off_t len, struct mem_ehdr *ehdr)
> +{
> +	struct mem_phdr *phdr, *end_phdr;
> +	int ret;
> +
> +	ret = build_elf_info(buf, len, ehdr);
> +	if (IS_ERR_VALUE(ret))
> +		return ret;
> +
> +	if (ehdr->e_type != ET_EXEC) {
> +		pr_err("Not ELF type ET_EXEC\n");
> +		return -ENOEXEC;
> +	}
> +
> +	if (!ehdr->e_phdr) {
> +		pr_err("No ELF program header\n");
> +		return -ENOEXEC;
> +	}
> +
> +	end_phdr = &ehdr->e_phdr[ehdr->e_phnum];
> +	for (phdr = ehdr->e_phdr; phdr != end_phdr; phdr++) {
> +		/* Kexec does not support loading interpreters.
> +		 * In addition this check keeps us from attempting
> +		 * to kexec ordinay executables.
> +		 */
> +		if (phdr->p_type == PT_INTERP) {
> +			pr_err("Requires an ELF interpreter\n");
> +			return -ENOEXEC;
> +		}
> +	}
> +
> +	return 0;
> +}
> +
> +int elf_exec_load(struct mem_ehdr *ehdr, struct kexec_info *info)
> +{
> +	size_t i;
> +
> +	if (!ehdr->e_phdr) {
> +		pr_err("No program header?\n");
> +		return -ENOENT;
> +	}
> +
> +	/* Read in the PT_LOAD segments */
> +	for (i = 0; i < ehdr->e_phnum; i++) {
> +		struct mem_phdr *phdr;
> +		size_t size;
> +
> +		phdr = &ehdr->e_phdr[i];
> +
> +		if (phdr->p_type != PT_LOAD)
> +			continue;
> +
> +		size = phdr->p_filesz;
> +
> +		if (size > phdr->p_memsz)
> +			size = phdr->p_memsz;
> +
> +		add_segment(info,
> +			phdr->p_data, size,
> +			phdr->p_paddr, phdr->p_memsz);
> +	}
> +
> +	return 0;
> +}
> diff --git a/lib/kexec/kexec-elf.c b/lib/kexec/kexec-elf.c
> new file mode 100644
> index 000000000..a66ac4c66
> --- /dev/null
> +++ b/lib/kexec/kexec-elf.c
> @@ -0,0 +1,565 @@
> +// SPDX-License-Identifier: GPL-2.0+
> +
> +#include <asm/io.h>
> +#include <common.h>
> +#include <kexec.h>
> +#include <memory.h>
> +
> +static u16 elf16_to_cpu(const struct mem_ehdr *ehdr, u16 val)
> +{
> +	return ehdr->ei_data == ELFDATA2LSB ? le16_to_cpu(val)
> +		   : be16_to_cpu(val);
> +}
> +
> +static u32 elf32_to_cpu(const struct mem_ehdr *ehdr, u32 val)
> +{
> +	return ehdr->ei_data == ELFDATA2LSB ? le32_to_cpu(val)
> +		   : be32_to_cpu(val);
> +}
> +
> +static u64 elf64_to_cpu(const struct mem_ehdr *ehdr, u64 val)
> +{
> +	return ehdr->ei_data == ELFDATA2LSB ? le64_to_cpu(val)
> +		   : be64_to_cpu(val);
> +}
> +
> +static int build_mem_elf32_ehdr(const void *buf, size_t len,
> +				struct mem_ehdr *ehdr)
> +{
> +	const Elf32_Ehdr *lehdr = buf;
> +
> +	if (len < sizeof(Elf32_Ehdr)) {
> +		pr_err("Buffer is too small to hold ELF header\n");
> +		return -ENOEXEC;
> +	}
> +
> +	if (elf16_to_cpu(ehdr, lehdr->e_ehsize) != sizeof(Elf32_Ehdr)) {
> +		pr_err("Bad ELF header size\n");
> +		return -ENOEXEC;
> +	}
> +
> +	ehdr->e_type      = elf16_to_cpu(ehdr, lehdr->e_type);
> +	ehdr->e_machine   = elf16_to_cpu(ehdr, lehdr->e_machine);
> +	ehdr->e_version   = elf32_to_cpu(ehdr, lehdr->e_version);
> +	ehdr->e_entry     = elf32_to_cpu(ehdr, lehdr->e_entry);
> +	ehdr->e_phoff     = elf32_to_cpu(ehdr, lehdr->e_phoff);
> +	ehdr->e_shoff     = elf32_to_cpu(ehdr, lehdr->e_shoff);
> +	ehdr->e_flags     = elf32_to_cpu(ehdr, lehdr->e_flags);
> +	ehdr->e_phnum     = elf16_to_cpu(ehdr, lehdr->e_phnum);
> +	ehdr->e_shnum     = elf16_to_cpu(ehdr, lehdr->e_shnum);
> +	ehdr->e_shstrndx  = elf16_to_cpu(ehdr, lehdr->e_shstrndx);
> +
> +	if ((ehdr->e_phnum > 0) &&
> +		(elf16_to_cpu(ehdr, lehdr->e_phentsize) != sizeof(Elf32_Phdr))) {
> +		pr_err("ELF bad program header size\n");
> +		return -ENOEXEC;
> +	}
> +
> +	if ((ehdr->e_shnum > 0) &&
> +		(elf16_to_cpu(ehdr, lehdr->e_shentsize) != sizeof(Elf32_Shdr))) {
> +		pr_err("ELF bad section header size\n");
> +		return -ENOEXEC;
> +	}
> +
> +	return 0;
> +}
> +
> +static int build_mem_elf64_ehdr(const void *buf, size_t len,
> +				struct mem_ehdr *ehdr)
> +{
> +	const Elf64_Ehdr *lehdr = buf;
> +
> +	if (len < sizeof(Elf64_Ehdr)) {
> +		pr_err("Buffer is too small to hold ELF header\n");
> +		return -ENOEXEC;
> +	}
> +
> +	if (elf16_to_cpu(ehdr, lehdr->e_ehsize) != sizeof(Elf64_Ehdr)) {
> +		pr_err("Bad ELF header size\n");
> +		return -ENOEXEC;
> +	}
> +
> +	ehdr->e_type      = elf16_to_cpu(ehdr, lehdr->e_type);
> +	ehdr->e_machine   = elf16_to_cpu(ehdr, lehdr->e_machine);
> +	ehdr->e_version   = elf32_to_cpu(ehdr, lehdr->e_version);
> +	ehdr->e_entry     = elf64_to_cpu(ehdr, lehdr->e_entry);
> +	ehdr->e_phoff     = elf64_to_cpu(ehdr, lehdr->e_phoff);
> +	ehdr->e_shoff     = elf64_to_cpu(ehdr, lehdr->e_shoff);
> +	ehdr->e_flags     = elf32_to_cpu(ehdr, lehdr->e_flags);
> +	ehdr->e_phnum     = elf16_to_cpu(ehdr, lehdr->e_phnum);
> +	ehdr->e_shnum     = elf16_to_cpu(ehdr, lehdr->e_shnum);
> +	ehdr->e_shstrndx  = elf16_to_cpu(ehdr, lehdr->e_shstrndx);
> +
> +	if ((ehdr->e_phnum > 0) &&
> +		(elf16_to_cpu(ehdr, lehdr->e_phentsize) != sizeof(Elf64_Phdr))) {
> +		pr_err("ELF bad program header size\n");
> +		return -ENOEXEC;
> +	}
> +
> +	if ((ehdr->e_shnum > 0) &&
> +		(elf16_to_cpu(ehdr, lehdr->e_shentsize) != sizeof(Elf64_Shdr))) {
> +		pr_err("ELF bad section header size\n");
> +		return -ENOEXEC;
> +	}
> +
> +	return 0;
> +}
> +
> +static int build_mem_ehdr(const void *buf, size_t len, struct mem_ehdr *ehdr)
> +{
> +	unsigned char e_ident[EI_NIDENT];
> +	int ret;
> +
> +	memset(ehdr, 0, sizeof(*ehdr));
> +
> +	if (len < sizeof(e_ident)) {
> +		pr_err("Buffer is too small to hold ELF e_ident\n");
> +		return -ENOEXEC;
> +	}
> +
> +	memcpy(e_ident, buf, sizeof(e_ident));
> +
> +	ehdr->ei_class   = e_ident[EI_CLASS];
> +	ehdr->ei_data    = e_ident[EI_DATA];
> +	if ((ehdr->ei_class != ELFCLASS32) &&
> +		(ehdr->ei_class != ELFCLASS64)) {
> +		pr_err("Not a supported ELF class\n");
> +		return -ENOEXEC;
> +	}
> +
> +	if ((ehdr->ei_data != ELFDATA2LSB) &&
> +		(ehdr->ei_data != ELFDATA2MSB)) {
> +		pr_err("Not a supported ELF data format\n");
> +		return -ENOEXEC;
> +	}
> +
> +	if (ehdr->ei_class == ELFCLASS32)
> +		ret = build_mem_elf32_ehdr(buf, len, ehdr);
> +	else
> +		ret = build_mem_elf64_ehdr(buf, len, ehdr);
> +
> +	if (IS_ERR_VALUE(ret))
> +		return ret;
> +
> +	if ((e_ident[EI_VERSION] != EV_CURRENT) ||
> +		(ehdr->e_version != EV_CURRENT)) {
> +		pr_err("Unknown ELF version\n");
> +		return -ENOEXEC;
> +	}
> +
> +	return 0;
> +}
> +
> +static void build_mem_elf32_phdr(const char *buf, struct mem_ehdr *ehdr, int idx)
> +{
> +	struct mem_phdr *phdr;
> +	const Elf32_Phdr *lphdr;
> +
> +	lphdr = (const Elf32_Phdr *)(buf + ehdr->e_phoff + (idx * sizeof(Elf32_Phdr)));
> +	phdr = &ehdr->e_phdr[idx];
> +
> +	phdr->p_type   = elf32_to_cpu(ehdr, lphdr->p_type);
> +	phdr->p_paddr  = elf32_to_cpu(ehdr, lphdr->p_paddr);
> +	phdr->p_vaddr  = elf32_to_cpu(ehdr, lphdr->p_vaddr);
> +	phdr->p_filesz = elf32_to_cpu(ehdr, lphdr->p_filesz);
> +	phdr->p_memsz  = elf32_to_cpu(ehdr, lphdr->p_memsz);
> +	phdr->p_offset = elf32_to_cpu(ehdr, lphdr->p_offset);
> +	phdr->p_flags  = elf32_to_cpu(ehdr, lphdr->p_flags);
> +	phdr->p_align  = elf32_to_cpu(ehdr, lphdr->p_align);
> +}
> +
> +static void build_mem_elf64_phdr(const char *buf, struct mem_ehdr *ehdr, int idx)
> +{
> +	struct mem_phdr *phdr;
> +	const Elf64_Phdr *lphdr;
> +
> +	lphdr = (const Elf64_Phdr *)(buf + ehdr->e_phoff + (idx * sizeof(Elf64_Phdr)));
> +	phdr = &ehdr->e_phdr[idx];
> +
> +	phdr->p_type   = elf32_to_cpu(ehdr, lphdr->p_type);
> +	phdr->p_paddr  = elf64_to_cpu(ehdr, lphdr->p_paddr);
> +	phdr->p_vaddr  = elf64_to_cpu(ehdr, lphdr->p_vaddr);
> +	phdr->p_filesz = elf64_to_cpu(ehdr, lphdr->p_filesz);
> +	phdr->p_memsz  = elf64_to_cpu(ehdr, lphdr->p_memsz);
> +	phdr->p_offset = elf64_to_cpu(ehdr, lphdr->p_offset);
> +	phdr->p_flags  = elf32_to_cpu(ehdr, lphdr->p_flags);
> +	phdr->p_align  = elf64_to_cpu(ehdr, lphdr->p_align);
> +}
> +
> +static int build_mem_phdrs(const char *buf, struct mem_ehdr *ehdr)
> +{
> +	size_t mem_phdr_size, i;
> +
> +	/* e_phnum is at most 65535 so calculating
> +	 * the size of the program header cannot overflow.
> +	 */
> +
> +	/* Allocate the e_phdr array */
> +	mem_phdr_size = sizeof(ehdr->e_phdr[0]) * ehdr->e_phnum;
> +	ehdr->e_phdr = xmalloc(mem_phdr_size);
> +
> +	for (i = 0; i < ehdr->e_phnum; i++) {
> +		struct mem_phdr *phdr;
> +
> +		if (ehdr->ei_class == ELFCLASS32)
> +			build_mem_elf32_phdr(buf, ehdr, i);
> +		else
> +			build_mem_elf64_phdr(buf, ehdr, i);
> +
> +		/* Check the program headers to be certain
> +		 * they are safe to use.
> +		 */
> +		phdr = &ehdr->e_phdr[i];
> +		if ((phdr->p_paddr + phdr->p_memsz) < phdr->p_paddr) {
> +			/* The memory address wraps */
> +			pr_err("ELF address wrap around\n");
> +			return -ENOEXEC;
> +		}
> +
> +		/* Remember where the segment lives in the buffer */
> +		phdr->p_data = buf + phdr->p_offset;
> +	}
> +
> +	return 0;
> +}
> +
> +static int build_mem_elf32_shdr(const char *buf, struct mem_ehdr *ehdr, int idx)
> +{
> +	struct mem_shdr *shdr;
> +	int size_ok;
> +	const Elf32_Shdr *lshdr;
> +
> +	lshdr = (const Elf32_Shdr *)(buf + ehdr->e_shoff + (idx * sizeof(Elf32_Shdr)));
> +	shdr = &ehdr->e_shdr[idx];
> +	shdr->sh_name      = elf32_to_cpu(ehdr, lshdr->sh_name);
> +	shdr->sh_type      = elf32_to_cpu(ehdr, lshdr->sh_type);
> +	shdr->sh_flags     = elf32_to_cpu(ehdr, lshdr->sh_flags);
> +	shdr->sh_addr      = elf32_to_cpu(ehdr, lshdr->sh_addr);
> +	shdr->sh_offset    = elf32_to_cpu(ehdr, lshdr->sh_offset);
> +	shdr->sh_size      = elf32_to_cpu(ehdr, lshdr->sh_size);
> +	shdr->sh_link      = elf32_to_cpu(ehdr, lshdr->sh_link);
> +	shdr->sh_info      = elf32_to_cpu(ehdr, lshdr->sh_info);
> +	shdr->sh_addralign = elf32_to_cpu(ehdr, lshdr->sh_addralign);
> +	shdr->sh_entsize   = elf32_to_cpu(ehdr, lshdr->sh_entsize);
> +
> +	/* Now verify sh_entsize */
> +	size_ok = 0;
> +	switch (shdr->sh_type) {
> +	case SHT_SYMTAB:
> +		size_ok = shdr->sh_entsize == sizeof(Elf32_Sym);
> +		break;
> +	case SHT_RELA:
> +		size_ok = shdr->sh_entsize == sizeof(Elf32_Rela);
> +		break;
> +	case SHT_DYNAMIC:
> +		size_ok = shdr->sh_entsize == sizeof(Elf32_Dyn);
> +		break;
> +	case SHT_REL:
> +		size_ok = shdr->sh_entsize == sizeof(Elf32_Rel);
> +		break;
> +	case SHT_NOTE:
> +	case SHT_NULL:
> +	case SHT_PROGBITS:
> +	case SHT_HASH:
> +	case SHT_NOBITS:
> +	default:
> +		/* This is a section whose entsize requirements
> +		 * I don't care about.  If I don't know about
> +		 * the section I can't care about it's entsize
> +		 * requirements.
> +		 */
> +		size_ok = 1;
> +		break;
> +	}
> +
> +	if (size_ok)
> +		return 0;
> +
> +	pr_err("Bad section header(%x) entsize: %lld\n",
> +		shdr->sh_type, shdr->sh_entsize);
> +	return -ENOEXEC;
> +}
> +
> +static int build_mem_elf64_shdr(const char *buf, struct mem_ehdr *ehdr, int idx)
> +{
> +	struct mem_shdr *shdr;
> +	int size_ok;
> +	const Elf64_Shdr *lshdr;
> +
> +	lshdr = (const Elf64_Shdr *)(buf + ehdr->e_shoff + (idx * sizeof(Elf64_Shdr)));
> +	shdr = &ehdr->e_shdr[idx];
> +	shdr->sh_name      = elf32_to_cpu(ehdr, lshdr->sh_name);
> +	shdr->sh_type      = elf32_to_cpu(ehdr, lshdr->sh_type);
> +	shdr->sh_flags     = elf64_to_cpu(ehdr, lshdr->sh_flags);
> +	shdr->sh_addr      = elf64_to_cpu(ehdr, lshdr->sh_addr);
> +	shdr->sh_offset    = elf64_to_cpu(ehdr, lshdr->sh_offset);
> +	shdr->sh_size      = elf64_to_cpu(ehdr, lshdr->sh_size);
> +	shdr->sh_link      = elf32_to_cpu(ehdr, lshdr->sh_link);
> +	shdr->sh_info      = elf32_to_cpu(ehdr, lshdr->sh_info);
> +	shdr->sh_addralign = elf64_to_cpu(ehdr, lshdr->sh_addralign);
> +	shdr->sh_entsize   = elf64_to_cpu(ehdr, lshdr->sh_entsize);
> +
> +	/* Now verify sh_entsize */
> +	size_ok = 0;
> +	switch (shdr->sh_type) {
> +	case SHT_SYMTAB:
> +		size_ok = shdr->sh_entsize == sizeof(Elf64_Sym);
> +		break;
> +	case SHT_RELA:
> +		size_ok = shdr->sh_entsize == sizeof(Elf64_Rela);
> +		break;
> +	case SHT_DYNAMIC:
> +		size_ok = shdr->sh_entsize == sizeof(Elf64_Dyn);
> +		break;
> +	case SHT_REL:
> +		size_ok = shdr->sh_entsize == sizeof(Elf64_Rel);
> +		break;
> +	case SHT_NOTE:
> +	case SHT_NULL:
> +	case SHT_PROGBITS:
> +	case SHT_HASH:
> +	case SHT_NOBITS:
> +	default:
> +		/* This is a section whose entsize requirements
> +		 * I don't care about.  If I don't know about
> +		 * the section I can't care about it's entsize
> +		 * requirements.
> +		 */
> +		size_ok = 1;
> +		break;
> +	}
> +
> +	if (size_ok)
> +		return 0;
> +
> +	pr_err("Bad section header(%x) entsize: %lld\n",
> +		shdr->sh_type, shdr->sh_entsize);
> +	return -ENOEXEC;
> +}
> +
> +static int build_mem_shdrs(const void *buf, struct mem_ehdr *ehdr)
> +{
> +	size_t mem_shdr_size, i;
> +
> +	/* Allocate the e_shdr array */
> +	mem_shdr_size = sizeof(ehdr->e_shdr[0]) * ehdr->e_shnum;
> +	ehdr->e_shdr = xmalloc(mem_shdr_size);
> +
> +	for (i = 0; i < ehdr->e_shnum; i++) {
> +		struct mem_shdr *shdr;
> +		int ret;
> +
> +		if (ehdr->ei_class == ELFCLASS32)
> +			ret = build_mem_elf32_shdr(buf, ehdr, i);
> +		else
> +			ret = build_mem_elf64_shdr(buf, ehdr, i);
> +
> +		if (IS_ERR_VALUE(ret))
> +			return ret;
> +
> +		/* Check the section headers to be certain
> +		 * they are safe to use.
> +		 */
> +		shdr = &ehdr->e_shdr[i];
> +		if ((shdr->sh_addr + shdr->sh_size) < shdr->sh_addr) {
> +			pr_err("ELF address wrap around\n");
> +			return -ENOEXEC;
> +		}
> +
> +		/* Remember where the section lives in the buffer */
> +		shdr->sh_data = (unsigned char *)(buf + shdr->sh_offset);
> +	}
> +
> +	return 0;
> +}
> +
> +void free_elf_info(struct mem_ehdr *ehdr)
> +{
> +	free(ehdr->e_phdr);
> +	free(ehdr->e_shdr);
> +	memset(ehdr, 0, sizeof(*ehdr));
> +}
> +
> +int build_elf_info(const char *buf, size_t len, struct mem_ehdr *ehdr)
> +{
> +	int ret;
> +
> +	ret = build_mem_ehdr(buf, len, ehdr);
> +	if (IS_ERR_VALUE(ret))
> +		return ret;
> +
> +	if ((ehdr->e_phoff > 0) && (ehdr->e_phnum > 0)) {
> +		ret = build_mem_phdrs(buf, ehdr);
> +		if (IS_ERR_VALUE(ret)) {
> +			free_elf_info(ehdr);
> +			return ret;
> +		}
> +	}
> +
> +	if ((ehdr->e_shoff > 0) && (ehdr->e_shnum > 0)) {
> +		ret = build_mem_shdrs(buf, ehdr);
> +		if (IS_ERR_VALUE(ret)) {
> +			free_elf_info(ehdr);
> +			return ret;
> +		}
> +	}
> +
> +	return 0;
> +}
> +
> +int check_room_for_elf(struct list_head *elf_segments)
> +{
> +	struct memory_bank *bank;
> +	struct resource *res, *r;
> +
> +	list_for_each_entry(r, elf_segments, sibling) {
> +		int got_bank;
> +
> +		got_bank = 0;
> +		for_each_memory_bank(bank) {
> +			unsigned long start, end;
> +
> +			res = bank->res;
> +
> +			start = virt_to_phys((const void *)res->start);
> +			end = virt_to_phys((const void *)res->end);
> +
> +			if ((start <= r->start) && (end >= r->end)) {
> +				got_bank = 1;
> +				break;
> +			}
> +		}
> +
> +		if (!got_bank)
> +			return -ENOSPC;
> +	}
> +
> +	return 0;
> +}
> +
> +/* sort by size */
> +static int compare(struct list_head *a, struct list_head *b)
> +{
> +	struct resource *ra = (struct resource *)list_entry(a,
> +					struct resource, sibling);
> +	struct resource *rb = (struct resource *)list_entry(b,
> +					struct resource, sibling);
> +	resource_size_t sa, sb;
> +
> +	sa = ra->end - ra->start;
> +	sb = rb->end - rb->start;
> +
> +	if (sa > sb)
> +		return -1;
> +	if (sa < sb)
> +		return 1;
> +	return 0;
> +}
> +
> +void list_add_used_region(struct list_head *new, struct list_head *head)
> +{
> +	struct list_head *pos, *insert = head;
> +	struct resource *rb =
> +		(struct resource *)list_entry(new, struct resource, sibling);
> +	struct list_head *n;
> +
> +	/* rb --- new region */
> +	list_for_each_safe(pos, n, head) {
> +		struct resource *ra = (struct resource *)list_entry(pos,
> +						struct resource, sibling);
> +
> +		if (resource_overlaps(ra, rb)) {
> +			rb->start = min(ra->start, rb->start);
> +			rb->end = max(ra->end, rb->end);
> +			rb->name = "join";
> +			list_del(pos);
> +		}
> +	}
> +
> +	list_for_each(pos, head) {
> +		struct resource *ra = (struct resource *)list_entry(pos,
> +						struct resource, sibling);
> +
> +		if (ra->start < rb->start)
> +			continue;
> +
> +		insert = pos;
> +		break;
> +	}
> +
> +	list_add_tail(new, insert);
> +}
> +
> +resource_size_t dcheck_res(struct list_head *elf_segments)
> +{
> +	struct memory_bank *bank;
> +	struct resource *res, *r, *t;
> +
> +	LIST_HEAD(elf_relocate_banks);
> +	LIST_HEAD(elf_relocate_banks_size_sorted);
> +	LIST_HEAD(used_regions);
> +
> +	for_each_memory_bank(bank) {
> +		res = bank->res;
> +
> +		list_for_each_entry(r, &res->children, sibling) {
> +			t = create_resource("tmp",
> +				virt_to_phys((void *)r->start),
> +				virt_to_phys((void *)r->end));
> +			list_add_used_region(&t->sibling, &used_regions);
> +		}
> +	}
> +
> +	list_for_each_entry(r, elf_segments, sibling) {
> +		t = create_resource(r->name, r->start, r->end);
> +		list_add_used_region(&t->sibling, &used_regions);
> +	}
> +
> +	for_each_memory_bank(bank) {
> +		resource_size_t start;
> +
> +		res = bank->res;
> +		res = create_resource("tmp",
> +				virt_to_phys((void *)res->start),
> +				virt_to_phys((void *)res->end));
> +		start = res->start;
> +
> +		list_for_each_entry(r, &used_regions, sibling) {
> +			if (res->start > r->end)
> +				continue;
> +
> +			if (res->end < r->start)
> +				continue;
> +
> +			if (r->start - start) {
> +				struct resource *t;
> +
> +				t = create_resource("ELF buffer", start,
> +						    r->start - 1);
> +				list_add_used_region(&t->sibling,
> +						     &elf_relocate_banks);
> +			}
> +			start = r->end + 1;
> +		}
> +
> +		if (res->end - start) {
> +			struct resource *t;
> +
> +			t = create_resource("ELF buffer", start, res->end);
> +			list_add_used_region(&t->sibling, &elf_relocate_banks);
> +		}
> +	}
> +
> +	list_for_each_entry(r, &elf_relocate_banks, sibling) {
> +		struct resource *t;
> +
> +		t = create_resource("ELF buffer", r->start, r->end);
> +		list_add_sort(&t->sibling,
> +			&elf_relocate_banks_size_sorted, compare);
> +	}
> +
> +	r = list_first_entry(&elf_relocate_banks_size_sorted, struct resource,
> +			     sibling);
> +
> +	return r->start;
> +}
> diff --git a/lib/kexec/kexec.c b/lib/kexec/kexec.c
> new file mode 100644
> index 000000000..585371c65
> --- /dev/null
> +++ b/lib/kexec/kexec.c
> @@ -0,0 +1,255 @@
> +// SPDX-License-Identifier: GPL-2.0+
> +/*
> + * kexec: Linux boots Linux
> + *
> + * Copyright (C) 2003-2005  Eric Biederman (ebiederm@xmission.com)
> + * Modified (2007-05-15) by Francesco Chiechi to rudely handle mips platform
> + *
> + */
> +
> +#include <asm/io.h>
> +#include <boot.h>
> +#include <common.h>
> +#include <environment.h>
> +#include <kexec.h>
> +#include <libfile.h>
> +
> +static int sort_segments(struct kexec_info *info)
> +{
> +	int i, j;
> +	void *end = NULL;
> +
> +	/* Do a stupid insertion sort... */
> +	for (i = 0; i < info->nr_segments; i++) {
> +		int tidx;
> +		struct kexec_segment temp;
> +		tidx = i;
> +		for (j = i + 1; j < info->nr_segments; j++) {
> +			if (info->segment[j].mem < info->segment[tidx].mem)
> +				tidx = j;
> +		}
> +		if (tidx != i) {
> +			temp = info->segment[tidx];
> +			info->segment[tidx] = info->segment[i];
> +			info->segment[i] = temp;
> +		}
> +	}
> +
> +	/* Now see if any of the segments overlap */
> +	for (i = 0; i < info->nr_segments; i++) {
> +		if (end > info->segment[i].mem) {
> +			pr_err("Overlapping memory segments at %p\n",
> +				end);
> +			return -EBUSY;
> +		}
> +		end = ((char *)info->segment[i].mem) + info->segment[i].memsz;
> +	}
> +
> +	return 0;
> +}
> +
> +void add_segment_phys_virt(struct kexec_info *info,
> +	const void *buf, size_t bufsz,
> +	unsigned long base, size_t memsz, int phys)
> +{
> +	size_t size;
> +	int pagesize;
> +
> +	if (bufsz > memsz)
> +		bufsz = memsz;
> +
> +	/* Forget empty segments */
> +	if (!memsz)
> +		return;
> +
> +	/* Round memsz up to a multiple of pagesize */
> +	pagesize = 4096;
> +	memsz = (memsz + (pagesize - 1)) & ~(pagesize - 1);
> +
> +	if (phys)
> +		base = virt_to_phys((void *)base);
> +
> +	size = (info->nr_segments + 1) * sizeof(info->segment[0]);
> +	info->segment = xrealloc(info->segment, size);
> +	info->segment[info->nr_segments].buf   = buf;
> +	info->segment[info->nr_segments].bufsz = bufsz;
> +	info->segment[info->nr_segments].mem   = (void *)base;
> +	info->segment[info->nr_segments].memsz = memsz;
> +	info->nr_segments++;
> +	if (info->nr_segments > KEXEC_MAX_SEGMENTS) {
> +		pr_warn("Warning: kernel segment limit reached. "
> +			"This will likely fail\n");
> +	}
> +}
> +
> +static int kexec_load_one_file(struct kexec_info *info, char *fname)
> +{
> +	char *buf;
> +	size_t fsize;
> +	int i = 0;
> +
> +	buf = read_file(fname, &fsize);
> +
> +	/* FIXME: check buf */
> +
> +	for (i = 0; i < kexec_file_types; i++) {
> +		if (kexec_file_type[i].probe(buf, fsize) >= 0)
> +			break;
> +	}
> +
> +	if (i == kexec_file_types) {
> +		pr_err("Cannot determine the file type "
> +				"of %s\n", fname);
> +		return -ENOEXEC;
> +	}
> +
> +	return kexec_file_type[i].load(buf, fsize, info);
> +}
> +
> +static int kexec_load_binary_file(struct kexec_info *info, char *fname,
> +					size_t *fsize, unsigned long base)
> +{
> +	char *buf;
> +
> +	buf = read_file(fname, fsize);
> +	if (!buf)
> +		return -ENOENT;
> +
> +	add_segment(info, buf, *fsize, base, *fsize);
> +
> +	return 0;
> +}
> +
> +static void print_segments(struct kexec_info *info)
> +{
> +	int i;
> +
> +	pr_info("print_segments\n");
> +	for (i = 0; i < info->nr_segments; i++) {
> +		struct kexec_segment *seg = &info->segment[i];
> +
> +		pr_info("  %d. buf=%#08p bufsz=%#lx mem=%#08p memsz=%#lx\n", i,
> +			seg->buf, seg->bufsz, seg->mem, seg->memsz);
> +	}
> +}
> +
> +static unsigned long find_unused_base(struct kexec_info *info, int *padded)
> +{
> +	unsigned long base = 0;
> +
> +	if (info->nr_segments) {
> +		int i = info->nr_segments - 1;
> +		struct kexec_segment *seg = &info->segment[i];
> +
> +		base = (unsigned long)seg->mem + seg->memsz;
> +	}
> +
> +	if (!*padded) {
> +		/*
> +		 * Pad it; the kernel scribbles over memory
> +		 * beyond its load address.
> +		 * see grub-core/loader/mips/linux.c
> +		 */
> +		base += 0x100000;
> +		*padded = 1;
> +	}
> +
> +	return base;
> +}
> +
> +int kexec_load_bootm_data(struct image_data *data)
> +{
> +	int ret;
> +	struct kexec_info info;
> +	char *cmdline;
> +	const char *t;
> +	size_t tlen;
> +	size_t fsize;
> +	char initrd_cmdline[40];
> +	int padded = 0;
> +
> +	memset(&info, 0, sizeof(info));
> +
> +	initrd_cmdline[0] = 0;
> +
> +	ret = kexec_load_one_file(&info, data->os_file);
> +	if (IS_ERR_VALUE(ret)) {
> +		pr_err("Cannot load %s\n", data->os_file);
> +		return ret;
> +	}

There is a potential problem here, which I actually hit some time ago. The 
following code places kernel arguments right after os image. This is perfectly 
fine in case of vmlinuX. However, if one boots a vmlinuZ image, there is no 
easily available knowledge of where the decompressed image will reside. In my 
case vmlinux' BSS overlapped with DTB and kernel cmdline segments and was 
zeroed at linux startup. This was fixed by adding an empty 4k segment at 128M, 
so further segments were allocated beyond 128M, far enough from the kernel 
lair:

	+       /* FIXME: allocate 4k segment @ 0x8000000 (128M), so further
	+        * segments will be allocated beyond this address.  This prevents
	+        * kernel parameters from being overwritten by the kernel startup code.
	+        */
	+       add_segment(&info, (void *)CKSEG0ADDR(0), 4 << 10, 0x8000000, 4 << 10);

However this is an ad-hoc solution and, probably, find_unused_base() may take 
care of such cases.

Regards,
Peter

> +
> +	if (data->oftree_file) {
> +		unsigned long base = find_unused_base(&info, &padded);
> +
> +		base = ALIGN(base, 8);
> +
> +		ret = kexec_load_binary_file(&info,
> +				data->oftree_file, &fsize, base);
> +		if (IS_ERR_VALUE(ret)) {
> +			pr_err("Cannot load %s\n", data->oftree_file);
> +			return ret;
> +		}
> +		data->oftree_address = base;
> +	}
> +
> +	if (data->initrd_file) {
> +		unsigned long base = find_unused_base(&info, &padded);
> +
> +		/*
> +		 * initrd start must be page aligned,
> +		 * max page size for mips is 64k.
> +		 */
> +		base = ALIGN(base, 0x10000);
> +
> +		ret = kexec_load_binary_file(&info,
> +				data->initrd_file, &fsize, base);
> +		if (IS_ERR_VALUE(ret)) {
> +			pr_err("Cannot load %s\n", data->initrd_file);
> +			return ret;
> +		}
> +		data->initrd_address = base;
> +
> +		if (bootm_verbose(data)) {
> +			pr_info("initrd: rd_start=0x%08x rd_size=0x%08x\n",
> +					data->initrd_address, fsize);
> +		}
> +		snprintf(initrd_cmdline, sizeof(initrd_cmdline),
> +				" rd_start=0x%08x rd_size=0x%08x",
> +					phys_to_virt(data->initrd_address),
> +					fsize);
> +	}
> +
> +	t = linux_bootargs_get();
> +	if (t)
> +		tlen = strlen(t);
> +	else
> +		tlen = 0;
> +
> +	cmdline = xzalloc(tlen + sizeof(initrd_cmdline));
> +	if (tlen)
> +		memcpy(cmdline, t, tlen);
> +
> +	memcpy(cmdline + tlen, initrd_cmdline, sizeof(initrd_cmdline));
> +
> +	if (cmdline) {
> +		int cmdlinelen = strlen(cmdline) + 1;
> +		unsigned long base = find_unused_base(&info, &padded);
> +
> +		base = ALIGN(base, 8);
> +
> +		add_segment(&info, cmdline, cmdlinelen, base, cmdlinelen);
> +		data->cmdline_address = base;
> +	}
> +
> +	if (bootm_verbose(data))
> +		print_segments(&info);
> +
> +	/* Verify all of the segments load to a valid location in memory */
> +
> +	/* Sort the segments and verify we don't have overlaps */
> +	ret = sort_segments(&info);
> +	if (IS_ERR_VALUE(ret))
> +		return ret;
> +
> +	return kexec_load(data, info.entry, info.nr_segments, info.segment);
> +}
> -- 
> 2.14.1
> 
> 
> _______________________________________________
> barebox mailing list
> barebox@lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/barebox

_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

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

* Re: [PATCH v1 04/10] bootm: add kexec ELF support
  2018-05-16 21:34   ` Peter Mamonov
@ 2018-05-17  4:52     ` Oleksij Rempel
  2018-05-17  7:01       ` Sascha Hauer
  0 siblings, 1 reply; 18+ messages in thread
From: Oleksij Rempel @ 2018-05-17  4:52 UTC (permalink / raw)
  To: Peter Mamonov; +Cc: barebox


[-- Attachment #1.1.1: Type: text/plain, Size: 33331 bytes --]

Am 16.05.2018 um 23:34 schrieb Peter Mamonov:
> Hi!
> 
> On Wed, May 16, 2018 at 06:42:27PM +0200, Oleksij Rempel wrote:
>> From: Antony Pavlov <antonynpavlov@gmail.com>
>>
>> Also introduce reboot() for starting already loaded
>> via kexec ELF segments.
>>
>> Signed-off-by: Antony Pavlov <antonynpavlov@gmail.com>
>> ---
>>  commands/Kconfig            |   7 +
>>  common/Kconfig              |   3 +
>>  include/bootm.h             |   3 +
>>  include/kexec.h             | 118 +++++++++
>>  lib/Makefile                |   1 +
>>  lib/kexec/Makefile          |   4 +
>>  lib/kexec/kexec-bootm-elf.c |  42 ++++
>>  lib/kexec/kexec-elf-exec.c  |  70 ++++++
>>  lib/kexec/kexec-elf.c       | 565 ++++++++++++++++++++++++++++++++++++++++++++
>>  lib/kexec/kexec.c           | 255 ++++++++++++++++++++
>>  10 files changed, 1068 insertions(+)
>>  create mode 100644 include/kexec.h
>>  create mode 100644 lib/kexec/Makefile
>>  create mode 100644 lib/kexec/kexec-bootm-elf.c
>>  create mode 100644 lib/kexec/kexec-elf-exec.c
>>  create mode 100644 lib/kexec/kexec-elf.c
>>  create mode 100644 lib/kexec/kexec.c
>>
>> diff --git a/commands/Kconfig b/commands/Kconfig
>> index 951a86963..a49928ad1 100644
>> --- a/commands/Kconfig
>> +++ b/commands/Kconfig
>> @@ -476,6 +476,13 @@ config CMD_SAVES
>>  
>>  	  Save S-Record file to serial line with offset OFFS and length LEN.
>>  
>> +config KEXEC
>> +	bool
>> +	prompt "bootm ELF image support"
>> +	depends on CMD_BOOTM && HAS_KEXEC
>> +	help
>> +	  Support using ELF Images.
>> +
>>  config CMD_UIMAGE
>>  	select UIMAGE
>>  	tristate
>> diff --git a/common/Kconfig b/common/Kconfig
>> index b7000c4d7..d40c79dbc 100644
>> --- a/common/Kconfig
>> +++ b/common/Kconfig
>> @@ -1218,3 +1218,6 @@ config HAS_DEBUG_LL
>>  config DDR_SPD
>>  	bool
>>  	select CRC16
>> +
>> +config HAS_KEXEC
>> +	bool
>> diff --git a/include/bootm.h b/include/bootm.h
>> index 62951d605..3a642fe70 100644
>> --- a/include/bootm.h
>> +++ b/include/bootm.h
>> @@ -72,6 +72,9 @@ struct image_data {
>>  
>>  	char *oftree_file;
>>  	char *oftree_part;
>> +	unsigned long oftree_address;
>> +
>> +	unsigned long cmdline_address;
>>  
>>  	const void *fit_kernel;
>>  	unsigned long fit_kernel_size;
>> diff --git a/include/kexec.h b/include/kexec.h
>> new file mode 100644
>> index 000000000..675658b38
>> --- /dev/null
>> +++ b/include/kexec.h
>> @@ -0,0 +1,118 @@
>> +#ifndef _LINUX_REBOOT_H
>> +#define _LINUX_REBOOT_H
>> +
>> +#include <bootm.h>
>> +
>> +struct kexec_segment {
>> +	const void *buf;
>> +	size_t bufsz;
>> +	const void *mem;
>> +	size_t memsz;
>> +};
>> +
>> +struct kexec_info {
>> +	struct kexec_segment *segment;
>> +	int nr_segments;
>> +	void *entry;
>> +	unsigned long kexec_flags;
>> +};
>> +
>> +typedef int (probe_t)(const char *kernel_buf, off_t kernel_size);
>> +typedef int (load_t)(const char *kernel_buf, off_t kernel_size,
>> +	struct kexec_info *info);
>> +struct kexec_file_type {
>> +	const char *name;
>> +	probe_t *probe;
>> +	load_t  *load;
>> +};
>> +
>> +extern struct kexec_file_type kexec_file_type[];
>> +extern int kexec_file_types;
>> +
>> +extern void add_segment(struct kexec_info *info,
>> +	const void *buf, size_t bufsz, unsigned long base, size_t memsz);
>> +extern void add_segment_phys_virt(struct kexec_info *info,
>> +	const void *buf, size_t bufsz, unsigned long base, size_t memsz,
>> +	int phys);
>> +
>> +extern int kexec_load(struct image_data *data, void *entry,
>> +		      unsigned long nr_segments,
>> +		      struct kexec_segment *segments);
>> +
>> +extern void kexec_arch(void *opaque);
>> +
>> +extern int kexec_load_bootm_data(struct image_data *data);
>> +
>> +/* These values match the ELF architecture values.
>> + * Unless there is a good reason that should continue to be the case.
>> + */
>> +#define KEXEC_ARCH_DEFAULT	(0 << 16)
>> +#define KEXEC_ARCH_386		(3 << 16)
>> +#define KEXEC_ARCH_X86_64	(62 << 16)
>> +#define KEXEC_ARCH_PPC		(20 << 16)
>> +#define KEXEC_ARCH_PPC64	(21 << 16)
>> +#define KEXEC_ARCH_IA_64	(50 << 16)
>> +#define KEXEC_ARCH_ARM		(40 << 16)
>> +#define KEXEC_ARCH_S390		(22 << 16)
>> +#define KEXEC_ARCH_SH		(42 << 16)
>> +#define KEXEC_ARCH_MIPS_LE	(10 << 16)
>> +#define KEXEC_ARCH_MIPS		(8 << 16)
>> +#define KEXEC_ARCH_CRIS		(76 << 16)
>> +
>> +#define KEXEC_MAX_SEGMENTS 16
>> +
>> +struct mem_phdr {
>> +	u64 p_paddr;
>> +	u64 p_vaddr;
>> +	u64 p_filesz;
>> +	u64 p_memsz;
>> +	u64 p_offset;
>> +	const char *p_data;
>> +	u32 p_type;
>> +	u32 p_flags;
>> +	u64 p_align;
>> +};
>> +
>> +struct mem_shdr {
>> +	u32 sh_name;
>> +	u32 sh_type;
>> +	u64 sh_flags;
>> +	u64 sh_addr;
>> +	u64 sh_offset;
>> +	u64 sh_size;
>> +	u32 sh_link;
>> +	u32 sh_info;
>> +	u64 sh_addralign;
>> +	u64 sh_entsize;
>> +	const unsigned char *sh_data;
>> +};
>> +
>> +struct mem_ehdr {
>> +	u32 ei_class;
>> +	u32 ei_data;
>> +	u32 e_type;
>> +	u32 e_machine;
>> +	u32 e_version;
>> +	u32 e_flags;
>> +	u32 e_phnum;
>> +	u32 e_shnum;
>> +	u32 e_shstrndx;
>> +	u64 e_entry;
>> +	u64 e_phoff;
>> +	u64 e_shoff;
>> +	struct mem_phdr *e_phdr;
>> +	struct mem_shdr *e_shdr;
>> +};
>> +
>> +void free_elf_info(struct mem_ehdr *ehdr);
>> +int build_elf_info(const char *buf, size_t len, struct mem_ehdr *ehdr);
>> +int build_elf_exec_info(const char *buf, off_t len, struct mem_ehdr *ehdr);
>> +
>> +int elf_exec_load(struct mem_ehdr *ehdr, struct kexec_info *info);
>> +
>> +unsigned long elf_max_addr(const struct mem_ehdr *ehdr);
>> +int check_room_for_elf(struct list_head *elf_segments);
>> +resource_size_t dcheck_res(struct list_head *elf_segments);
>> +void list_add_used_region(struct list_head *new, struct list_head *head);
>> +
>> +#endif /* _LINUX_REBOOT_H */
>> diff --git a/lib/Makefile b/lib/Makefile
>> index a7498288a..eebaf3488 100644
>> --- a/lib/Makefile
>> +++ b/lib/Makefile
>> @@ -65,3 +65,4 @@ obj-y			+= int_sqrt.o
>>  obj-y			+= parseopt.o
>>  obj-y			+= clz_ctz.o
>>  obj-$(CONFIG_CRC_CCITT) += crc-ccitt.o
>> +obj-$(CONFIG_KEXEC)	+= kexec/
>> diff --git a/lib/kexec/Makefile b/lib/kexec/Makefile
>> new file mode 100644
>> index 000000000..2f3dc1dd3
>> --- /dev/null
>> +++ b/lib/kexec/Makefile
>> @@ -0,0 +1,4 @@
>> +obj-y	+= kexec.o
>> +obj-y	+= kexec-elf.o
>> +obj-y	+= kexec-elf-exec.o
>> +obj-y	+= kexec-bootm-elf.o
>> diff --git a/lib/kexec/kexec-bootm-elf.c b/lib/kexec/kexec-bootm-elf.c
>> new file mode 100644
>> index 000000000..2530466a5
>> --- /dev/null
>> +++ b/lib/kexec/kexec-bootm-elf.c
>> @@ -0,0 +1,42 @@
>> +// SPDX-License-Identifier: GPL-2.0+
>> +
>> +#include <binfmt.h>
>> +#include <bootm.h>
>> +#include <init.h>
>> +#include <kexec.h>
>> +
>> +static int do_bootm_elf(struct image_data *data)
>> +{
>> +	int ret;
>> +
>> +	ret = kexec_load_bootm_data(data);
>> +	if (IS_ERR_VALUE(ret))
>> +		return ret;
>> +	
>> +	kexec_arch(data);
>> +
>> +	return -ERESTARTSYS;
>> +}
>> +
>> +static struct image_handler elf_handler = {
>> +	.name = "ELF",
>> +	.bootm = do_bootm_elf,
>> +	.filetype = filetype_elf,
>> +};
>> +
>> +static struct binfmt_hook binfmt_elf_hook = {
>> +	.type = filetype_elf,
>> +	.exec = "bootm",
>> +};
>> +
>> +static int elf_register_image_handler(void)
>> +{
>> +	int ret;
>> +
>> +	ret = register_image_handler(&elf_handler);
>> +	if (IS_ERR_VALUE(ret))
>> +		return ret;
>> +	
>> +	return binfmt_register(&binfmt_elf_hook);
>> +}
>> +late_initcall(elf_register_image_handler);
>> diff --git a/lib/kexec/kexec-elf-exec.c b/lib/kexec/kexec-elf-exec.c
>> new file mode 100644
>> index 000000000..e910c4ea0
>> --- /dev/null
>> +++ b/lib/kexec/kexec-elf-exec.c
>> @@ -0,0 +1,70 @@
>> +// SPDX-License-Identifier: GPL-2.0+
>> +
>> +#include <common.h>
>> +#include <kexec.h>
>> +
>> +int build_elf_exec_info(const char *buf, off_t len, struct mem_ehdr *ehdr)
>> +{
>> +	struct mem_phdr *phdr, *end_phdr;
>> +	int ret;
>> +
>> +	ret = build_elf_info(buf, len, ehdr);
>> +	if (IS_ERR_VALUE(ret))
>> +		return ret;
>> +
>> +	if (ehdr->e_type != ET_EXEC) {
>> +		pr_err("Not ELF type ET_EXEC\n");
>> +		return -ENOEXEC;
>> +	}
>> +
>> +	if (!ehdr->e_phdr) {
>> +		pr_err("No ELF program header\n");
>> +		return -ENOEXEC;
>> +	}
>> +
>> +	end_phdr = &ehdr->e_phdr[ehdr->e_phnum];
>> +	for (phdr = ehdr->e_phdr; phdr != end_phdr; phdr++) {
>> +		/* Kexec does not support loading interpreters.
>> +		 * In addition this check keeps us from attempting
>> +		 * to kexec ordinay executables.
>> +		 */
>> +		if (phdr->p_type == PT_INTERP) {
>> +			pr_err("Requires an ELF interpreter\n");
>> +			return -ENOEXEC;
>> +		}
>> +	}
>> +
>> +	return 0;
>> +}
>> +
>> +int elf_exec_load(struct mem_ehdr *ehdr, struct kexec_info *info)
>> +{
>> +	size_t i;
>> +
>> +	if (!ehdr->e_phdr) {
>> +		pr_err("No program header?\n");
>> +		return -ENOENT;
>> +	}
>> +
>> +	/* Read in the PT_LOAD segments */
>> +	for (i = 0; i < ehdr->e_phnum; i++) {
>> +		struct mem_phdr *phdr;
>> +		size_t size;
>> +
>> +		phdr = &ehdr->e_phdr[i];
>> +
>> +		if (phdr->p_type != PT_LOAD)
>> +			continue;
>> +
>> +		size = phdr->p_filesz;
>> +
>> +		if (size > phdr->p_memsz)
>> +			size = phdr->p_memsz;
>> +
>> +		add_segment(info,
>> +			phdr->p_data, size,
>> +			phdr->p_paddr, phdr->p_memsz);
>> +	}
>> +
>> +	return 0;
>> +}
>> diff --git a/lib/kexec/kexec-elf.c b/lib/kexec/kexec-elf.c
>> new file mode 100644
>> index 000000000..a66ac4c66
>> --- /dev/null
>> +++ b/lib/kexec/kexec-elf.c
>> @@ -0,0 +1,565 @@
>> +// SPDX-License-Identifier: GPL-2.0+
>> +
>> +#include <asm/io.h>
>> +#include <common.h>
>> +#include <kexec.h>
>> +#include <memory.h>
>> +
>> +static u16 elf16_to_cpu(const struct mem_ehdr *ehdr, u16 val)
>> +{
>> +	return ehdr->ei_data == ELFDATA2LSB ? le16_to_cpu(val)
>> +		   : be16_to_cpu(val);
>> +}
>> +
>> +static u32 elf32_to_cpu(const struct mem_ehdr *ehdr, u32 val)
>> +{
>> +	return ehdr->ei_data == ELFDATA2LSB ? le32_to_cpu(val)
>> +		   : be32_to_cpu(val);
>> +}
>> +
>> +static u64 elf64_to_cpu(const struct mem_ehdr *ehdr, u64 val)
>> +{
>> +	return ehdr->ei_data == ELFDATA2LSB ? le64_to_cpu(val)
>> +		   : be64_to_cpu(val);
>> +}
>> +
>> +static int build_mem_elf32_ehdr(const void *buf, size_t len,
>> +				struct mem_ehdr *ehdr)
>> +{
>> +	const Elf32_Ehdr *lehdr = buf;
>> +
>> +	if (len < sizeof(Elf32_Ehdr)) {
>> +		pr_err("Buffer is too small to hold ELF header\n");
>> +		return -ENOEXEC;
>> +	}
>> +
>> +	if (elf16_to_cpu(ehdr, lehdr->e_ehsize) != sizeof(Elf32_Ehdr)) {
>> +		pr_err("Bad ELF header size\n");
>> +		return -ENOEXEC;
>> +	}
>> +
>> +	ehdr->e_type      = elf16_to_cpu(ehdr, lehdr->e_type);
>> +	ehdr->e_machine   = elf16_to_cpu(ehdr, lehdr->e_machine);
>> +	ehdr->e_version   = elf32_to_cpu(ehdr, lehdr->e_version);
>> +	ehdr->e_entry     = elf32_to_cpu(ehdr, lehdr->e_entry);
>> +	ehdr->e_phoff     = elf32_to_cpu(ehdr, lehdr->e_phoff);
>> +	ehdr->e_shoff     = elf32_to_cpu(ehdr, lehdr->e_shoff);
>> +	ehdr->e_flags     = elf32_to_cpu(ehdr, lehdr->e_flags);
>> +	ehdr->e_phnum     = elf16_to_cpu(ehdr, lehdr->e_phnum);
>> +	ehdr->e_shnum     = elf16_to_cpu(ehdr, lehdr->e_shnum);
>> +	ehdr->e_shstrndx  = elf16_to_cpu(ehdr, lehdr->e_shstrndx);
>> +
>> +	if ((ehdr->e_phnum > 0) &&
>> +		(elf16_to_cpu(ehdr, lehdr->e_phentsize) != sizeof(Elf32_Phdr))) {
>> +		pr_err("ELF bad program header size\n");
>> +		return -ENOEXEC;
>> +	}
>> +
>> +	if ((ehdr->e_shnum > 0) &&
>> +		(elf16_to_cpu(ehdr, lehdr->e_shentsize) != sizeof(Elf32_Shdr))) {
>> +		pr_err("ELF bad section header size\n");
>> +		return -ENOEXEC;
>> +	}
>> +
>> +	return 0;
>> +}
>> +
>> +static int build_mem_elf64_ehdr(const void *buf, size_t len,
>> +				struct mem_ehdr *ehdr)
>> +{
>> +	const Elf64_Ehdr *lehdr = buf;
>> +
>> +	if (len < sizeof(Elf64_Ehdr)) {
>> +		pr_err("Buffer is too small to hold ELF header\n");
>> +		return -ENOEXEC;
>> +	}
>> +
>> +	if (elf16_to_cpu(ehdr, lehdr->e_ehsize) != sizeof(Elf64_Ehdr)) {
>> +		pr_err("Bad ELF header size\n");
>> +		return -ENOEXEC;
>> +	}
>> +
>> +	ehdr->e_type      = elf16_to_cpu(ehdr, lehdr->e_type);
>> +	ehdr->e_machine   = elf16_to_cpu(ehdr, lehdr->e_machine);
>> +	ehdr->e_version   = elf32_to_cpu(ehdr, lehdr->e_version);
>> +	ehdr->e_entry     = elf64_to_cpu(ehdr, lehdr->e_entry);
>> +	ehdr->e_phoff     = elf64_to_cpu(ehdr, lehdr->e_phoff);
>> +	ehdr->e_shoff     = elf64_to_cpu(ehdr, lehdr->e_shoff);
>> +	ehdr->e_flags     = elf32_to_cpu(ehdr, lehdr->e_flags);
>> +	ehdr->e_phnum     = elf16_to_cpu(ehdr, lehdr->e_phnum);
>> +	ehdr->e_shnum     = elf16_to_cpu(ehdr, lehdr->e_shnum);
>> +	ehdr->e_shstrndx  = elf16_to_cpu(ehdr, lehdr->e_shstrndx);
>> +
>> +	if ((ehdr->e_phnum > 0) &&
>> +		(elf16_to_cpu(ehdr, lehdr->e_phentsize) != sizeof(Elf64_Phdr))) {
>> +		pr_err("ELF bad program header size\n");
>> +		return -ENOEXEC;
>> +	}
>> +
>> +	if ((ehdr->e_shnum > 0) &&
>> +		(elf16_to_cpu(ehdr, lehdr->e_shentsize) != sizeof(Elf64_Shdr))) {
>> +		pr_err("ELF bad section header size\n");
>> +		return -ENOEXEC;
>> +	}
>> +
>> +	return 0;
>> +}
>> +
>> +static int build_mem_ehdr(const void *buf, size_t len, struct mem_ehdr *ehdr)
>> +{
>> +	unsigned char e_ident[EI_NIDENT];
>> +	int ret;
>> +
>> +	memset(ehdr, 0, sizeof(*ehdr));
>> +
>> +	if (len < sizeof(e_ident)) {
>> +		pr_err("Buffer is too small to hold ELF e_ident\n");
>> +		return -ENOEXEC;
>> +	}
>> +
>> +	memcpy(e_ident, buf, sizeof(e_ident));
>> +
>> +	ehdr->ei_class   = e_ident[EI_CLASS];
>> +	ehdr->ei_data    = e_ident[EI_DATA];
>> +	if ((ehdr->ei_class != ELFCLASS32) &&
>> +		(ehdr->ei_class != ELFCLASS64)) {
>> +		pr_err("Not a supported ELF class\n");
>> +		return -ENOEXEC;
>> +	}
>> +
>> +	if ((ehdr->ei_data != ELFDATA2LSB) &&
>> +		(ehdr->ei_data != ELFDATA2MSB)) {
>> +		pr_err("Not a supported ELF data format\n");
>> +		return -ENOEXEC;
>> +	}
>> +
>> +	if (ehdr->ei_class == ELFCLASS32)
>> +		ret = build_mem_elf32_ehdr(buf, len, ehdr);
>> +	else
>> +		ret = build_mem_elf64_ehdr(buf, len, ehdr);
>> +
>> +	if (IS_ERR_VALUE(ret))
>> +		return ret;
>> +
>> +	if ((e_ident[EI_VERSION] != EV_CURRENT) ||
>> +		(ehdr->e_version != EV_CURRENT)) {
>> +		pr_err("Unknown ELF version\n");
>> +		return -ENOEXEC;
>> +	}
>> +
>> +	return 0;
>> +}
>> +
>> +static void build_mem_elf32_phdr(const char *buf, struct mem_ehdr *ehdr, int idx)
>> +{
>> +	struct mem_phdr *phdr;
>> +	const Elf32_Phdr *lphdr;
>> +
>> +	lphdr = (const Elf32_Phdr *)(buf + ehdr->e_phoff + (idx * sizeof(Elf32_Phdr)));
>> +	phdr = &ehdr->e_phdr[idx];
>> +
>> +	phdr->p_type   = elf32_to_cpu(ehdr, lphdr->p_type);
>> +	phdr->p_paddr  = elf32_to_cpu(ehdr, lphdr->p_paddr);
>> +	phdr->p_vaddr  = elf32_to_cpu(ehdr, lphdr->p_vaddr);
>> +	phdr->p_filesz = elf32_to_cpu(ehdr, lphdr->p_filesz);
>> +	phdr->p_memsz  = elf32_to_cpu(ehdr, lphdr->p_memsz);
>> +	phdr->p_offset = elf32_to_cpu(ehdr, lphdr->p_offset);
>> +	phdr->p_flags  = elf32_to_cpu(ehdr, lphdr->p_flags);
>> +	phdr->p_align  = elf32_to_cpu(ehdr, lphdr->p_align);
>> +}
>> +
>> +static void build_mem_elf64_phdr(const char *buf, struct mem_ehdr *ehdr, int idx)
>> +{
>> +	struct mem_phdr *phdr;
>> +	const Elf64_Phdr *lphdr;
>> +
>> +	lphdr = (const Elf64_Phdr *)(buf + ehdr->e_phoff + (idx * sizeof(Elf64_Phdr)));
>> +	phdr = &ehdr->e_phdr[idx];
>> +
>> +	phdr->p_type   = elf32_to_cpu(ehdr, lphdr->p_type);
>> +	phdr->p_paddr  = elf64_to_cpu(ehdr, lphdr->p_paddr);
>> +	phdr->p_vaddr  = elf64_to_cpu(ehdr, lphdr->p_vaddr);
>> +	phdr->p_filesz = elf64_to_cpu(ehdr, lphdr->p_filesz);
>> +	phdr->p_memsz  = elf64_to_cpu(ehdr, lphdr->p_memsz);
>> +	phdr->p_offset = elf64_to_cpu(ehdr, lphdr->p_offset);
>> +	phdr->p_flags  = elf32_to_cpu(ehdr, lphdr->p_flags);
>> +	phdr->p_align  = elf64_to_cpu(ehdr, lphdr->p_align);
>> +}
>> +
>> +static int build_mem_phdrs(const char *buf, struct mem_ehdr *ehdr)
>> +{
>> +	size_t mem_phdr_size, i;
>> +
>> +	/* e_phnum is at most 65535 so calculating
>> +	 * the size of the program header cannot overflow.
>> +	 */
>> +
>> +	/* Allocate the e_phdr array */
>> +	mem_phdr_size = sizeof(ehdr->e_phdr[0]) * ehdr->e_phnum;
>> +	ehdr->e_phdr = xmalloc(mem_phdr_size);
>> +
>> +	for (i = 0; i < ehdr->e_phnum; i++) {
>> +		struct mem_phdr *phdr;
>> +
>> +		if (ehdr->ei_class == ELFCLASS32)
>> +			build_mem_elf32_phdr(buf, ehdr, i);
>> +		else
>> +			build_mem_elf64_phdr(buf, ehdr, i);
>> +
>> +		/* Check the program headers to be certain
>> +		 * they are safe to use.
>> +		 */
>> +		phdr = &ehdr->e_phdr[i];
>> +		if ((phdr->p_paddr + phdr->p_memsz) < phdr->p_paddr) {
>> +			/* The memory address wraps */
>> +			pr_err("ELF address wrap around\n");
>> +			return -ENOEXEC;
>> +		}
>> +
>> +		/* Remember where the segment lives in the buffer */
>> +		phdr->p_data = buf + phdr->p_offset;
>> +	}
>> +
>> +	return 0;
>> +}
>> +
>> +static int build_mem_elf32_shdr(const char *buf, struct mem_ehdr *ehdr, int idx)
>> +{
>> +	struct mem_shdr *shdr;
>> +	int size_ok;
>> +	const Elf32_Shdr *lshdr;
>> +
>> +	lshdr = (const Elf32_Shdr *)(buf + ehdr->e_shoff + (idx * sizeof(Elf32_Shdr)));
>> +	shdr = &ehdr->e_shdr[idx];
>> +	shdr->sh_name      = elf32_to_cpu(ehdr, lshdr->sh_name);
>> +	shdr->sh_type      = elf32_to_cpu(ehdr, lshdr->sh_type);
>> +	shdr->sh_flags     = elf32_to_cpu(ehdr, lshdr->sh_flags);
>> +	shdr->sh_addr      = elf32_to_cpu(ehdr, lshdr->sh_addr);
>> +	shdr->sh_offset    = elf32_to_cpu(ehdr, lshdr->sh_offset);
>> +	shdr->sh_size      = elf32_to_cpu(ehdr, lshdr->sh_size);
>> +	shdr->sh_link      = elf32_to_cpu(ehdr, lshdr->sh_link);
>> +	shdr->sh_info      = elf32_to_cpu(ehdr, lshdr->sh_info);
>> +	shdr->sh_addralign = elf32_to_cpu(ehdr, lshdr->sh_addralign);
>> +	shdr->sh_entsize   = elf32_to_cpu(ehdr, lshdr->sh_entsize);
>> +
>> +	/* Now verify sh_entsize */
>> +	size_ok = 0;
>> +	switch (shdr->sh_type) {
>> +	case SHT_SYMTAB:
>> +		size_ok = shdr->sh_entsize == sizeof(Elf32_Sym);
>> +		break;
>> +	case SHT_RELA:
>> +		size_ok = shdr->sh_entsize == sizeof(Elf32_Rela);
>> +		break;
>> +	case SHT_DYNAMIC:
>> +		size_ok = shdr->sh_entsize == sizeof(Elf32_Dyn);
>> +		break;
>> +	case SHT_REL:
>> +		size_ok = shdr->sh_entsize == sizeof(Elf32_Rel);
>> +		break;
>> +	case SHT_NOTE:
>> +	case SHT_NULL:
>> +	case SHT_PROGBITS:
>> +	case SHT_HASH:
>> +	case SHT_NOBITS:
>> +	default:
>> +		/* This is a section whose entsize requirements
>> +		 * I don't care about.  If I don't know about
>> +		 * the section I can't care about it's entsize
>> +		 * requirements.
>> +		 */
>> +		size_ok = 1;
>> +		break;
>> +	}
>> +
>> +	if (size_ok)
>> +		return 0;
>> +
>> +	pr_err("Bad section header(%x) entsize: %lld\n",
>> +		shdr->sh_type, shdr->sh_entsize);
>> +	return -ENOEXEC;
>> +}
>> +
>> +static int build_mem_elf64_shdr(const char *buf, struct mem_ehdr *ehdr, int idx)
>> +{
>> +	struct mem_shdr *shdr;
>> +	int size_ok;
>> +	const Elf64_Shdr *lshdr;
>> +
>> +	lshdr = (const Elf64_Shdr *)(buf + ehdr->e_shoff + (idx * sizeof(Elf64_Shdr)));
>> +	shdr = &ehdr->e_shdr[idx];
>> +	shdr->sh_name      = elf32_to_cpu(ehdr, lshdr->sh_name);
>> +	shdr->sh_type      = elf32_to_cpu(ehdr, lshdr->sh_type);
>> +	shdr->sh_flags     = elf64_to_cpu(ehdr, lshdr->sh_flags);
>> +	shdr->sh_addr      = elf64_to_cpu(ehdr, lshdr->sh_addr);
>> +	shdr->sh_offset    = elf64_to_cpu(ehdr, lshdr->sh_offset);
>> +	shdr->sh_size      = elf64_to_cpu(ehdr, lshdr->sh_size);
>> +	shdr->sh_link      = elf32_to_cpu(ehdr, lshdr->sh_link);
>> +	shdr->sh_info      = elf32_to_cpu(ehdr, lshdr->sh_info);
>> +	shdr->sh_addralign = elf64_to_cpu(ehdr, lshdr->sh_addralign);
>> +	shdr->sh_entsize   = elf64_to_cpu(ehdr, lshdr->sh_entsize);
>> +
>> +	/* Now verify sh_entsize */
>> +	size_ok = 0;
>> +	switch (shdr->sh_type) {
>> +	case SHT_SYMTAB:
>> +		size_ok = shdr->sh_entsize == sizeof(Elf64_Sym);
>> +		break;
>> +	case SHT_RELA:
>> +		size_ok = shdr->sh_entsize == sizeof(Elf64_Rela);
>> +		break;
>> +	case SHT_DYNAMIC:
>> +		size_ok = shdr->sh_entsize == sizeof(Elf64_Dyn);
>> +		break;
>> +	case SHT_REL:
>> +		size_ok = shdr->sh_entsize == sizeof(Elf64_Rel);
>> +		break;
>> +	case SHT_NOTE:
>> +	case SHT_NULL:
>> +	case SHT_PROGBITS:
>> +	case SHT_HASH:
>> +	case SHT_NOBITS:
>> +	default:
>> +		/* This is a section whose entsize requirements
>> +		 * I don't care about.  If I don't know about
>> +		 * the section I can't care about it's entsize
>> +		 * requirements.
>> +		 */
>> +		size_ok = 1;
>> +		break;
>> +	}
>> +
>> +	if (size_ok)
>> +		return 0;
>> +
>> +	pr_err("Bad section header(%x) entsize: %lld\n",
>> +		shdr->sh_type, shdr->sh_entsize);
>> +	return -ENOEXEC;
>> +}
>> +
>> +static int build_mem_shdrs(const void *buf, struct mem_ehdr *ehdr)
>> +{
>> +	size_t mem_shdr_size, i;
>> +
>> +	/* Allocate the e_shdr array */
>> +	mem_shdr_size = sizeof(ehdr->e_shdr[0]) * ehdr->e_shnum;
>> +	ehdr->e_shdr = xmalloc(mem_shdr_size);
>> +
>> +	for (i = 0; i < ehdr->e_shnum; i++) {
>> +		struct mem_shdr *shdr;
>> +		int ret;
>> +
>> +		if (ehdr->ei_class == ELFCLASS32)
>> +			ret = build_mem_elf32_shdr(buf, ehdr, i);
>> +		else
>> +			ret = build_mem_elf64_shdr(buf, ehdr, i);
>> +
>> +		if (IS_ERR_VALUE(ret))
>> +			return ret;
>> +
>> +		/* Check the section headers to be certain
>> +		 * they are safe to use.
>> +		 */
>> +		shdr = &ehdr->e_shdr[i];
>> +		if ((shdr->sh_addr + shdr->sh_size) < shdr->sh_addr) {
>> +			pr_err("ELF address wrap around\n");
>> +			return -ENOEXEC;
>> +		}
>> +
>> +		/* Remember where the section lives in the buffer */
>> +		shdr->sh_data = (unsigned char *)(buf + shdr->sh_offset);
>> +	}
>> +
>> +	return 0;
>> +}
>> +
>> +void free_elf_info(struct mem_ehdr *ehdr)
>> +{
>> +	free(ehdr->e_phdr);
>> +	free(ehdr->e_shdr);
>> +	memset(ehdr, 0, sizeof(*ehdr));
>> +}
>> +
>> +int build_elf_info(const char *buf, size_t len, struct mem_ehdr *ehdr)
>> +{
>> +	int ret;
>> +
>> +	ret = build_mem_ehdr(buf, len, ehdr);
>> +	if (IS_ERR_VALUE(ret))
>> +		return ret;
>> +
>> +	if ((ehdr->e_phoff > 0) && (ehdr->e_phnum > 0)) {
>> +		ret = build_mem_phdrs(buf, ehdr);
>> +		if (IS_ERR_VALUE(ret)) {
>> +			free_elf_info(ehdr);
>> +			return ret;
>> +		}
>> +	}
>> +
>> +	if ((ehdr->e_shoff > 0) && (ehdr->e_shnum > 0)) {
>> +		ret = build_mem_shdrs(buf, ehdr);
>> +		if (IS_ERR_VALUE(ret)) {
>> +			free_elf_info(ehdr);
>> +			return ret;
>> +		}
>> +	}
>> +
>> +	return 0;
>> +}
>> +
>> +int check_room_for_elf(struct list_head *elf_segments)
>> +{
>> +	struct memory_bank *bank;
>> +	struct resource *res, *r;
>> +
>> +	list_for_each_entry(r, elf_segments, sibling) {
>> +		int got_bank;
>> +
>> +		got_bank = 0;
>> +		for_each_memory_bank(bank) {
>> +			unsigned long start, end;
>> +
>> +			res = bank->res;
>> +
>> +			start = virt_to_phys((const void *)res->start);
>> +			end = virt_to_phys((const void *)res->end);
>> +
>> +			if ((start <= r->start) && (end >= r->end)) {
>> +				got_bank = 1;
>> +				break;
>> +			}
>> +		}
>> +
>> +		if (!got_bank)
>> +			return -ENOSPC;
>> +	}
>> +
>> +	return 0;
>> +}
>> +
>> +/* sort by size */
>> +static int compare(struct list_head *a, struct list_head *b)
>> +{
>> +	struct resource *ra = (struct resource *)list_entry(a,
>> +					struct resource, sibling);
>> +	struct resource *rb = (struct resource *)list_entry(b,
>> +					struct resource, sibling);
>> +	resource_size_t sa, sb;
>> +
>> +	sa = ra->end - ra->start;
>> +	sb = rb->end - rb->start;
>> +
>> +	if (sa > sb)
>> +		return -1;
>> +	if (sa < sb)
>> +		return 1;
>> +	return 0;
>> +}
>> +
>> +void list_add_used_region(struct list_head *new, struct list_head *head)
>> +{
>> +	struct list_head *pos, *insert = head;
>> +	struct resource *rb =
>> +		(struct resource *)list_entry(new, struct resource, sibling);
>> +	struct list_head *n;
>> +
>> +	/* rb --- new region */
>> +	list_for_each_safe(pos, n, head) {
>> +		struct resource *ra = (struct resource *)list_entry(pos,
>> +						struct resource, sibling);
>> +
>> +		if (resource_overlaps(ra, rb)) {
>> +			rb->start = min(ra->start, rb->start);
>> +			rb->end = max(ra->end, rb->end);
>> +			rb->name = "join";
>> +			list_del(pos);
>> +		}
>> +	}
>> +
>> +	list_for_each(pos, head) {
>> +		struct resource *ra = (struct resource *)list_entry(pos,
>> +						struct resource, sibling);
>> +
>> +		if (ra->start < rb->start)
>> +			continue;
>> +
>> +		insert = pos;
>> +		break;
>> +	}
>> +
>> +	list_add_tail(new, insert);
>> +}
>> +
>> +resource_size_t dcheck_res(struct list_head *elf_segments)
>> +{
>> +	struct memory_bank *bank;
>> +	struct resource *res, *r, *t;
>> +
>> +	LIST_HEAD(elf_relocate_banks);
>> +	LIST_HEAD(elf_relocate_banks_size_sorted);
>> +	LIST_HEAD(used_regions);
>> +
>> +	for_each_memory_bank(bank) {
>> +		res = bank->res;
>> +
>> +		list_for_each_entry(r, &res->children, sibling) {
>> +			t = create_resource("tmp",
>> +				virt_to_phys((void *)r->start),
>> +				virt_to_phys((void *)r->end));
>> +			list_add_used_region(&t->sibling, &used_regions);
>> +		}
>> +	}
>> +
>> +	list_for_each_entry(r, elf_segments, sibling) {
>> +		t = create_resource(r->name, r->start, r->end);
>> +		list_add_used_region(&t->sibling, &used_regions);
>> +	}
>> +
>> +	for_each_memory_bank(bank) {
>> +		resource_size_t start;
>> +
>> +		res = bank->res;
>> +		res = create_resource("tmp",
>> +				virt_to_phys((void *)res->start),
>> +				virt_to_phys((void *)res->end));
>> +		start = res->start;
>> +
>> +		list_for_each_entry(r, &used_regions, sibling) {
>> +			if (res->start > r->end)
>> +				continue;
>> +
>> +			if (res->end < r->start)
>> +				continue;
>> +
>> +			if (r->start - start) {
>> +				struct resource *t;
>> +
>> +				t = create_resource("ELF buffer", start,
>> +						    r->start - 1);
>> +				list_add_used_region(&t->sibling,
>> +						     &elf_relocate_banks);
>> +			}
>> +			start = r->end + 1;
>> +		}
>> +
>> +		if (res->end - start) {
>> +			struct resource *t;
>> +
>> +			t = create_resource("ELF buffer", start, res->end);
>> +			list_add_used_region(&t->sibling, &elf_relocate_banks);
>> +		}
>> +	}
>> +
>> +	list_for_each_entry(r, &elf_relocate_banks, sibling) {
>> +		struct resource *t;
>> +
>> +		t = create_resource("ELF buffer", r->start, r->end);
>> +		list_add_sort(&t->sibling,
>> +			&elf_relocate_banks_size_sorted, compare);
>> +	}
>> +
>> +	r = list_first_entry(&elf_relocate_banks_size_sorted, struct resource,
>> +			     sibling);
>> +
>> +	return r->start;
>> +}
>> diff --git a/lib/kexec/kexec.c b/lib/kexec/kexec.c
>> new file mode 100644
>> index 000000000..585371c65
>> --- /dev/null
>> +++ b/lib/kexec/kexec.c
>> @@ -0,0 +1,255 @@
>> +// SPDX-License-Identifier: GPL-2.0+
>> +/*
>> + * kexec: Linux boots Linux
>> + *
>> + * Copyright (C) 2003-2005  Eric Biederman (ebiederm@xmission.com)
>> + * Modified (2007-05-15) by Francesco Chiechi to rudely handle mips platform
>> + *
>> + */
>> +
>> +#include <asm/io.h>
>> +#include <boot.h>
>> +#include <common.h>
>> +#include <environment.h>
>> +#include <kexec.h>
>> +#include <libfile.h>
>> +
>> +static int sort_segments(struct kexec_info *info)
>> +{
>> +	int i, j;
>> +	void *end = NULL;
>> +
>> +	/* Do a stupid insertion sort... */
>> +	for (i = 0; i < info->nr_segments; i++) {
>> +		int tidx;
>> +		struct kexec_segment temp;
>> +		tidx = i;
>> +		for (j = i + 1; j < info->nr_segments; j++) {
>> +			if (info->segment[j].mem < info->segment[tidx].mem)
>> +				tidx = j;
>> +		}
>> +		if (tidx != i) {
>> +			temp = info->segment[tidx];
>> +			info->segment[tidx] = info->segment[i];
>> +			info->segment[i] = temp;
>> +		}
>> +	}
>> +
>> +	/* Now see if any of the segments overlap */
>> +	for (i = 0; i < info->nr_segments; i++) {
>> +		if (end > info->segment[i].mem) {
>> +			pr_err("Overlapping memory segments at %p\n",
>> +				end);
>> +			return -EBUSY;
>> +		}
>> +		end = ((char *)info->segment[i].mem) + info->segment[i].memsz;
>> +	}
>> +
>> +	return 0;
>> +}
>> +
>> +void add_segment_phys_virt(struct kexec_info *info,
>> +	const void *buf, size_t bufsz,
>> +	unsigned long base, size_t memsz, int phys)
>> +{
>> +	size_t size;
>> +	int pagesize;
>> +
>> +	if (bufsz > memsz)
>> +		bufsz = memsz;
>> +
>> +	/* Forget empty segments */
>> +	if (!memsz)
>> +		return;
>> +
>> +	/* Round memsz up to a multiple of pagesize */
>> +	pagesize = 4096;
>> +	memsz = (memsz + (pagesize - 1)) & ~(pagesize - 1);
>> +
>> +	if (phys)
>> +		base = virt_to_phys((void *)base);
>> +
>> +	size = (info->nr_segments + 1) * sizeof(info->segment[0]);
>> +	info->segment = xrealloc(info->segment, size);
>> +	info->segment[info->nr_segments].buf   = buf;
>> +	info->segment[info->nr_segments].bufsz = bufsz;
>> +	info->segment[info->nr_segments].mem   = (void *)base;
>> +	info->segment[info->nr_segments].memsz = memsz;
>> +	info->nr_segments++;
>> +	if (info->nr_segments > KEXEC_MAX_SEGMENTS) {
>> +		pr_warn("Warning: kernel segment limit reached. "
>> +			"This will likely fail\n");
>> +	}
>> +}
>> +
>> +static int kexec_load_one_file(struct kexec_info *info, char *fname)
>> +{
>> +	char *buf;
>> +	size_t fsize;
>> +	int i = 0;
>> +
>> +	buf = read_file(fname, &fsize);
>> +
>> +	/* FIXME: check buf */
>> +
>> +	for (i = 0; i < kexec_file_types; i++) {
>> +		if (kexec_file_type[i].probe(buf, fsize) >= 0)
>> +			break;
>> +	}
>> +
>> +	if (i == kexec_file_types) {
>> +		pr_err("Cannot determine the file type "
>> +				"of %s\n", fname);
>> +		return -ENOEXEC;
>> +	}
>> +
>> +	return kexec_file_type[i].load(buf, fsize, info);
>> +}
>> +
>> +static int kexec_load_binary_file(struct kexec_info *info, char *fname,
>> +					size_t *fsize, unsigned long base)
>> +{
>> +	char *buf;
>> +
>> +	buf = read_file(fname, fsize);
>> +	if (!buf)
>> +		return -ENOENT;
>> +
>> +	add_segment(info, buf, *fsize, base, *fsize);
>> +
>> +	return 0;
>> +}
>> +
>> +static void print_segments(struct kexec_info *info)
>> +{
>> +	int i;
>> +
>> +	pr_info("print_segments\n");
>> +	for (i = 0; i < info->nr_segments; i++) {
>> +		struct kexec_segment *seg = &info->segment[i];
>> +
>> +		pr_info("  %d. buf=%#08p bufsz=%#lx mem=%#08p memsz=%#lx\n", i,
>> +			seg->buf, seg->bufsz, seg->mem, seg->memsz);
>> +	}
>> +}
>> +
>> +static unsigned long find_unused_base(struct kexec_info *info, int *padded)
>> +{
>> +	unsigned long base = 0;
>> +
>> +	if (info->nr_segments) {
>> +		int i = info->nr_segments - 1;
>> +		struct kexec_segment *seg = &info->segment[i];
>> +
>> +		base = (unsigned long)seg->mem + seg->memsz;
>> +	}
>> +
>> +	if (!*padded) {
>> +		/*
>> +		 * Pad it; the kernel scribbles over memory
>> +		 * beyond its load address.
>> +		 * see grub-core/loader/mips/linux.c
>> +		 */
>> +		base += 0x100000;
>> +		*padded = 1;
>> +	}
>> +
>> +	return base;
>> +}
>> +
>> +int kexec_load_bootm_data(struct image_data *data)
>> +{
>> +	int ret;
>> +	struct kexec_info info;
>> +	char *cmdline;
>> +	const char *t;
>> +	size_t tlen;
>> +	size_t fsize;
>> +	char initrd_cmdline[40];
>> +	int padded = 0;
>> +
>> +	memset(&info, 0, sizeof(info));
>> +
>> +	initrd_cmdline[0] = 0;
>> +
>> +	ret = kexec_load_one_file(&info, data->os_file);
>> +	if (IS_ERR_VALUE(ret)) {
>> +		pr_err("Cannot load %s\n", data->os_file);
>> +		return ret;
>> +	}
> 
> There is a potential problem here, which I actually hit some time ago. The 
> following code places kernel arguments right after os image. This is perfectly 
> fine in case of vmlinuX. However, if one boots a vmlinuZ image, there is no 
> easily available knowledge of where the decompressed image will reside. In my 
> case vmlinux' BSS overlapped with DTB and kernel cmdline segments and was 
> zeroed at linux startup. This was fixed by adding an empty 4k segment at 128M, 
> so further segments were allocated beyond 128M, far enough from the kernel 
> lair:
> 
> 	+       /* FIXME: allocate 4k segment @ 0x8000000 (128M), so further
> 	+        * segments will be allocated beyond this address.  This prevents
> 	+        * kernel parameters from being overwritten by the kernel startup code.
> 	+        */
> 	+       add_segment(&info, (void *)CKSEG0ADDR(0), 4 << 10, 0x8000000, 4 << 10);
> 
> However this is an ad-hoc solution and, probably, find_unused_base() may take 
> care of such cases.

Yes, correct. This and some other issues would be fixed by porting this
part of the code to bootm_load_devicetree() + find_unused_base(). Since
my time budget is on the limit, I would prefer to mainline current state
of the code ("works for me" TM) and provide platform for testing and
cooperation.

-- 
Regards,
Oleksij


[-- Attachment #1.2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 455 bytes --]

[-- Attachment #2: Type: text/plain, Size: 149 bytes --]

_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

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

* Re: [PATCH v1 04/10] bootm: add kexec ELF support
  2018-05-17  4:52     ` Oleksij Rempel
@ 2018-05-17  7:01       ` Sascha Hauer
  2018-05-17  9:51         ` Peter Mamonov
  0 siblings, 1 reply; 18+ messages in thread
From: Sascha Hauer @ 2018-05-17  7:01 UTC (permalink / raw)
  To: Oleksij Rempel; +Cc: barebox, Peter Mamonov

On Thu, May 17, 2018 at 06:52:10AM +0200, Oleksij Rempel wrote:
> Am 16.05.2018 um 23:34 schrieb Peter Mamonov:
> > Hi!
> > 
> > On Wed, May 16, 2018 at 06:42:27PM +0200, Oleksij Rempel wrote:
> >> From: Antony Pavlov <antonynpavlov@gmail.com>
> >>
> >> +int kexec_load_bootm_data(struct image_data *data)
> >> +{
> >> +	int ret;
> >> +	struct kexec_info info;
> >> +	char *cmdline;
> >> +	const char *t;
> >> +	size_t tlen;
> >> +	size_t fsize;
> >> +	char initrd_cmdline[40];
> >> +	int padded = 0;
> >> +
> >> +	memset(&info, 0, sizeof(info));
> >> +
> >> +	initrd_cmdline[0] = 0;
> >> +
> >> +	ret = kexec_load_one_file(&info, data->os_file);
> >> +	if (IS_ERR_VALUE(ret)) {
> >> +		pr_err("Cannot load %s\n", data->os_file);
> >> +		return ret;
> >> +	}
> > 
> > There is a potential problem here, which I actually hit some time ago. The 
> > following code places kernel arguments right after os image. This is perfectly 
> > fine in case of vmlinuX. However, if one boots a vmlinuZ image, there is no 
> > easily available knowledge of where the decompressed image will reside. In my 
> > case vmlinux' BSS overlapped with DTB and kernel cmdline segments and was 
> > zeroed at linux startup. This was fixed by adding an empty 4k segment at 128M, 
> > so further segments were allocated beyond 128M, far enough from the kernel 
> > lair:
> > 
> > 	+       /* FIXME: allocate 4k segment @ 0x8000000 (128M), so further
> > 	+        * segments will be allocated beyond this address.  This prevents
> > 	+        * kernel parameters from being overwritten by the kernel startup code.
> > 	+        */
> > 	+       add_segment(&info, (void *)CKSEG0ADDR(0), 4 << 10, 0x8000000, 4 << 10);
> > 
> > However this is an ad-hoc solution and, probably, find_unused_base() may take 
> > care of such cases.
> 
> Yes, correct. This and some other issues would be fixed by porting this
> part of the code to bootm_load_devicetree() + find_unused_base(). Since
> my time budget is on the limit, I would prefer to mainline current state
> of the code ("works for me" TM) and provide platform for testing and
> cooperation.

Can we at least detect that the image is a compressed one and bail out
with an error? It would be a pity when someone else has to figure out
this bug the hard way now that we already know that it exists.

Sascha

-- 
Pengutronix e.K.                           |                             |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |
Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |

_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

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

* Re: [PATCH v1 04/10] bootm: add kexec ELF support
  2018-05-17  7:01       ` Sascha Hauer
@ 2018-05-17  9:51         ` Peter Mamonov
  0 siblings, 0 replies; 18+ messages in thread
From: Peter Mamonov @ 2018-05-17  9:51 UTC (permalink / raw)
  To: Sascha Hauer; +Cc: barebox, Oleksij Rempel

On Thu, May 17, 2018 at 09:01:06AM +0200, Sascha Hauer wrote:
> On Thu, May 17, 2018 at 06:52:10AM +0200, Oleksij Rempel wrote:
> > Am 16.05.2018 um 23:34 schrieb Peter Mamonov:
> > > Hi!
> > > 
> > > On Wed, May 16, 2018 at 06:42:27PM +0200, Oleksij Rempel wrote:
> > >> From: Antony Pavlov <antonynpavlov@gmail.com>
> > >>
> > >> +int kexec_load_bootm_data(struct image_data *data)
> > >> +{
> > >> +	int ret;
> > >> +	struct kexec_info info;
> > >> +	char *cmdline;
> > >> +	const char *t;
> > >> +	size_t tlen;
> > >> +	size_t fsize;
> > >> +	char initrd_cmdline[40];
> > >> +	int padded = 0;
> > >> +
> > >> +	memset(&info, 0, sizeof(info));
> > >> +
> > >> +	initrd_cmdline[0] = 0;
> > >> +
> > >> +	ret = kexec_load_one_file(&info, data->os_file);
> > >> +	if (IS_ERR_VALUE(ret)) {
> > >> +		pr_err("Cannot load %s\n", data->os_file);
> > >> +		return ret;
> > >> +	}
> > > 
> > > There is a potential problem here, which I actually hit some time ago. The 
> > > following code places kernel arguments right after os image. This is perfectly 
> > > fine in case of vmlinuX. However, if one boots a vmlinuZ image, there is no 
> > > easily available knowledge of where the decompressed image will reside. In my 
> > > case vmlinux' BSS overlapped with DTB and kernel cmdline segments and was 
> > > zeroed at linux startup. This was fixed by adding an empty 4k segment at 128M, 
> > > so further segments were allocated beyond 128M, far enough from the kernel 
> > > lair:
> > > 
> > > 	+       /* FIXME: allocate 4k segment @ 0x8000000 (128M), so further
> > > 	+        * segments will be allocated beyond this address.  This prevents
> > > 	+        * kernel parameters from being overwritten by the kernel startup code.
> > > 	+        */
> > > 	+       add_segment(&info, (void *)CKSEG0ADDR(0), 4 << 10, 0x8000000, 4 << 10);
> > > 
> > > However this is an ad-hoc solution and, probably, find_unused_base() may take 
> > > care of such cases.
> > 
> > Yes, correct. This and some other issues would be fixed by porting this
> > part of the code to bootm_load_devicetree() + find_unused_base(). Since
> > my time budget is on the limit, I would prefer to mainline current state
> > of the code ("works for me" TM) and provide platform for testing and
> > cooperation.
> 
> Can we at least detect that the image is a compressed one and bail out
> with an error? It would be a pity when someone else has to figure out
> this bug the hard way now that we already know that it exists.

I suggest to print a warning message, containing relevant addresses.  Something 
like this:

	ACHTUNG: booting vmlinuZ image. Beware of overlaps of kernel arguments 
	and vmlinuX sections. List of kernel arguments:
		cmdline @ XXXXXXXX-XXXXXXXX
		dtb @ XXXXXXXX-XXXXXXXX

However I'm not sure if it is possible to distinguish vmlinuz from vmlinux 
reliably, since both are just ELFs, though vmlinuz has only one section.  
Moreover, I guess this issue applies to any form of compressed OS image, not 
only vmlinuz. So, probably linux should take care about its arguments in 
arch/mips/boot/compressed/head.S.

Regards,
Peter

> 
> Sascha
> 
> -- 
> Pengutronix e.K.                           |                             |
> Industrial Linux Solutions                 | http://www.pengutronix.de/  |
> Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0    |
> Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |

_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

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

* Re: [PATCH v1 05/10] MIPS: add kexec ELF loading support
  2018-05-16 16:42 ` [PATCH v1 05/10] MIPS: add kexec ELF loading support Oleksij Rempel
@ 2018-05-17  9:56   ` Sascha Hauer
  2018-05-17 10:07     ` Oleksij Rempel
  0 siblings, 1 reply; 18+ messages in thread
From: Sascha Hauer @ 2018-05-17  9:56 UTC (permalink / raw)
  To: Oleksij Rempel; +Cc: barebox, Peter Mamonov

On Wed, May 16, 2018 at 06:42:28PM +0200, Oleksij Rempel wrote:
> From: Antony Pavlov <antonynpavlov@gmail.com>
> 
> Signed-off-by: Antony Pavlov <antonynpavlov@gmail.com>
> Signed-off-by: Peter Mamonov <pmamonov@gmail.com>
> ---
>  arch/mips/include/asm/elf.h        |   8 +-
>  arch/mips/lib/Makefile             |   4 +
>  arch/mips/lib/kexec-mach-generic.c |  21 +++
>  arch/mips/lib/kexec-mips.c         | 307 +++++++++++++++++++++++++++++++++++++
>  arch/mips/lib/machine_kexec.h      |  21 +++
>  arch/mips/lib/relocate_kernel.S    | 108 +++++++++++++
>  6 files changed, 468 insertions(+), 1 deletion(-)
>  create mode 100644 arch/mips/lib/kexec-mach-generic.c
>  create mode 100644 arch/mips/lib/kexec-mips.c
>  create mode 100644 arch/mips/lib/machine_kexec.h
>  create mode 100644 arch/mips/lib/relocate_kernel.S
> 
> +int kexec_load(struct image_data *data, void *entry,
> +	       unsigned long nr_segments,
> +	       struct kexec_segment *segments)
> +{
> +	int i;
> +	struct resource *elf;
> +	resource_size_t start;
> +	LIST_HEAD(elf_segments);
> +
> +	for (i = 0; i < nr_segments; i++) {
> +		resource_size_t mem = (resource_size_t)segments[i].mem;
> +
> +		elf = create_resource("elf segment",
> +			mem, mem + segments[i].memsz - 1);
> +
> +		list_add_used_region(&elf->sibling, &elf_segments);
> +	}
> +
> +	if (check_room_for_elf(&elf_segments)) {
> +		pr_err("ELF can't be loaded!\n");
> +		return -ENOSPC;
> +	}
> +
> +	start = dcheck_res(&elf_segments);
> +
> +	/* relocate_new_kernel() copy by register (4 or 8 bytes)
> +	   so start address must be aligned to 4/8 */
> +	start = (start + 15) & 0xfffffff0;
> +
> +	for (i = 0; i < nr_segments; i++) {
> +		segments[i].mem = (void *)(phys_to_virt((unsigned long)segments[i].mem));
> +		memcpy(phys_to_virt(start), segments[i].buf, segments[i].bufsz);
> +		request_sdram_region("kexec relocatable segment",
> +			(unsigned long)phys_to_virt(start),
> +			(unsigned long)segments[i].bufsz);

The return value of request_sdram_region should be checked and of course
the resource should be used after having checked the return value, not
before. Same for the other calls to request_sdram_region.

Sascha

-- 
Pengutronix e.K.                           |                             |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |
Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |

_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

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

* Re: [PATCH v1 05/10] MIPS: add kexec ELF loading support
  2018-05-17  9:56   ` Sascha Hauer
@ 2018-05-17 10:07     ` Oleksij Rempel
  2018-05-18  5:46       ` Sascha Hauer
  0 siblings, 1 reply; 18+ messages in thread
From: Oleksij Rempel @ 2018-05-17 10:07 UTC (permalink / raw)
  To: Sascha Hauer; +Cc: barebox, Peter Mamonov


[-- Attachment #1.1.1: Type: text/plain, Size: 2402 bytes --]

Am 17.05.2018 um 11:56 schrieb Sascha Hauer:
> On Wed, May 16, 2018 at 06:42:28PM +0200, Oleksij Rempel wrote:
>> From: Antony Pavlov <antonynpavlov@gmail.com>
>>
>> Signed-off-by: Antony Pavlov <antonynpavlov@gmail.com>
>> Signed-off-by: Peter Mamonov <pmamonov@gmail.com>
>> ---
>>  arch/mips/include/asm/elf.h        |   8 +-
>>  arch/mips/lib/Makefile             |   4 +
>>  arch/mips/lib/kexec-mach-generic.c |  21 +++
>>  arch/mips/lib/kexec-mips.c         | 307 +++++++++++++++++++++++++++++++++++++
>>  arch/mips/lib/machine_kexec.h      |  21 +++
>>  arch/mips/lib/relocate_kernel.S    | 108 +++++++++++++
>>  6 files changed, 468 insertions(+), 1 deletion(-)
>>  create mode 100644 arch/mips/lib/kexec-mach-generic.c
>>  create mode 100644 arch/mips/lib/kexec-mips.c
>>  create mode 100644 arch/mips/lib/machine_kexec.h
>>  create mode 100644 arch/mips/lib/relocate_kernel.S
>>
>> +int kexec_load(struct image_data *data, void *entry,
>> +	       unsigned long nr_segments,
>> +	       struct kexec_segment *segments)
>> +{
>> +	int i;
>> +	struct resource *elf;
>> +	resource_size_t start;
>> +	LIST_HEAD(elf_segments);
>> +
>> +	for (i = 0; i < nr_segments; i++) {
>> +		resource_size_t mem = (resource_size_t)segments[i].mem;
>> +
>> +		elf = create_resource("elf segment",
>> +			mem, mem + segments[i].memsz - 1);
>> +
>> +		list_add_used_region(&elf->sibling, &elf_segments);
>> +	}
>> +
>> +	if (check_room_for_elf(&elf_segments)) {
>> +		pr_err("ELF can't be loaded!\n");
>> +		return -ENOSPC;
>> +	}
>> +
>> +	start = dcheck_res(&elf_segments);
>> +
>> +	/* relocate_new_kernel() copy by register (4 or 8 bytes)
>> +	   so start address must be aligned to 4/8 */
>> +	start = (start + 15) & 0xfffffff0;
>> +
>> +	for (i = 0; i < nr_segments; i++) {
>> +		segments[i].mem = (void *)(phys_to_virt((unsigned long)segments[i].mem));
>> +		memcpy(phys_to_virt(start), segments[i].buf, segments[i].bufsz);
>> +		request_sdram_region("kexec relocatable segment",
>> +			(unsigned long)phys_to_virt(start),
>> +			(unsigned long)segments[i].bufsz);
> 
> The return value of request_sdram_region should be checked and of course
> the resource should be used after having checked the return value, not
> before. Same for the other calls to request_sdram_region.

Will it be enough for initial inclusion?

-- 
Regards,
Oleksij


[-- Attachment #1.2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 455 bytes --]

[-- Attachment #2: Type: text/plain, Size: 149 bytes --]

_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

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

* Re: [PATCH v1 05/10] MIPS: add kexec ELF loading support
  2018-05-17 10:07     ` Oleksij Rempel
@ 2018-05-18  5:46       ` Sascha Hauer
  0 siblings, 0 replies; 18+ messages in thread
From: Sascha Hauer @ 2018-05-18  5:46 UTC (permalink / raw)
  To: Oleksij Rempel; +Cc: barebox, Peter Mamonov

On Thu, May 17, 2018 at 12:07:29PM +0200, Oleksij Rempel wrote:
> Am 17.05.2018 um 11:56 schrieb Sascha Hauer:
> > On Wed, May 16, 2018 at 06:42:28PM +0200, Oleksij Rempel wrote:
> >> From: Antony Pavlov <antonynpavlov@gmail.com>
> >>
> >> Signed-off-by: Antony Pavlov <antonynpavlov@gmail.com>
> >> Signed-off-by: Peter Mamonov <pmamonov@gmail.com>
> >> ---
> >>  arch/mips/include/asm/elf.h        |   8 +-
> >>  arch/mips/lib/Makefile             |   4 +
> >>  arch/mips/lib/kexec-mach-generic.c |  21 +++
> >>  arch/mips/lib/kexec-mips.c         | 307 +++++++++++++++++++++++++++++++++++++
> >>  arch/mips/lib/machine_kexec.h      |  21 +++
> >>  arch/mips/lib/relocate_kernel.S    | 108 +++++++++++++
> >>  6 files changed, 468 insertions(+), 1 deletion(-)
> >>  create mode 100644 arch/mips/lib/kexec-mach-generic.c
> >>  create mode 100644 arch/mips/lib/kexec-mips.c
> >>  create mode 100644 arch/mips/lib/machine_kexec.h
> >>  create mode 100644 arch/mips/lib/relocate_kernel.S
> >>
> >> +int kexec_load(struct image_data *data, void *entry,
> >> +	       unsigned long nr_segments,
> >> +	       struct kexec_segment *segments)
> >> +{
> >> +	int i;
> >> +	struct resource *elf;
> >> +	resource_size_t start;
> >> +	LIST_HEAD(elf_segments);
> >> +
> >> +	for (i = 0; i < nr_segments; i++) {
> >> +		resource_size_t mem = (resource_size_t)segments[i].mem;
> >> +
> >> +		elf = create_resource("elf segment",
> >> +			mem, mem + segments[i].memsz - 1);
> >> +
> >> +		list_add_used_region(&elf->sibling, &elf_segments);
> >> +	}
> >> +
> >> +	if (check_room_for_elf(&elf_segments)) {
> >> +		pr_err("ELF can't be loaded!\n");
> >> +		return -ENOSPC;
> >> +	}
> >> +
> >> +	start = dcheck_res(&elf_segments);
> >> +
> >> +	/* relocate_new_kernel() copy by register (4 or 8 bytes)
> >> +	   so start address must be aligned to 4/8 */
> >> +	start = (start + 15) & 0xfffffff0;
> >> +
> >> +	for (i = 0; i < nr_segments; i++) {
> >> +		segments[i].mem = (void *)(phys_to_virt((unsigned long)segments[i].mem));
> >> +		memcpy(phys_to_virt(start), segments[i].buf, segments[i].bufsz);
> >> +		request_sdram_region("kexec relocatable segment",
> >> +			(unsigned long)phys_to_virt(start),
> >> +			(unsigned long)segments[i].bufsz);
> > 
> > The return value of request_sdram_region should be checked and of course
> > the resource should be used after having checked the return value, not
> > before. Same for the other calls to request_sdram_region.
> 
> Will it be enough for initial inclusion?

No, to merge it I need the feeling that this code is understood, not in
the works-for-me state.

Sascha

-- 
Pengutronix e.K.                           |                             |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |
Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |

_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

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

end of thread, other threads:[~2018-05-18  5:46 UTC | newest]

Thread overview: 18+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2018-05-16 16:42 [PATCH v1 00/10] provide ELF/KEXEC support for MIPS ath79 and malta Oleksij Rempel
2018-05-16 16:42 ` [PATCH v1 01/10] resource: add create_resource() helper function Oleksij Rempel
2018-05-16 16:42 ` [PATCH v1 02/10] port resource_overlaps() from kernel Oleksij Rempel
2018-05-16 16:42 ` [PATCH v1 03/10] filetype: add ELF type Oleksij Rempel
2018-05-16 16:42 ` [PATCH v1 04/10] bootm: add kexec ELF support Oleksij Rempel
2018-05-16 21:34   ` Peter Mamonov
2018-05-17  4:52     ` Oleksij Rempel
2018-05-17  7:01       ` Sascha Hauer
2018-05-17  9:51         ` Peter Mamonov
2018-05-16 16:42 ` [PATCH v1 05/10] MIPS: add kexec ELF loading support Oleksij Rempel
2018-05-17  9:56   ` Sascha Hauer
2018-05-17 10:07     ` Oleksij Rempel
2018-05-18  5:46       ` Sascha Hauer
2018-05-16 16:42 ` [PATCH v1 06/10] MIPS: ath79: enable kexec Oleksij Rempel
2018-05-16 16:42 ` [PATCH v1 07/10] MIPS: malta: " Oleksij Rempel
2018-05-16 16:42 ` [PATCH v1 08/10] MIPS: configs: add KEXEC=y to atheros devices Oleksij Rempel
2018-05-16 16:42 ` [PATCH v1 09/10] MIPS: configs: dptechnics-dpt-module: enable watchdog poller Oleksij Rempel
2018-05-16 16:42 ` [PATCH v1 10/10] MIPS: malta: update malta qemu defconfig Oleksij Rempel

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox