mail archive of the barebox mailing list
 help / color / mirror / Atom feed
* [RFC PATCH 0/7] provide ELF/KEXEC support for MIPS ath79 and malta
@ 2018-04-29 13:09 Oleksij Rempel
  2018-04-29 13:09 ` [RFC PATCH 1/7] resource: add create_resource() helper function Oleksij Rempel
                   ` (6 more replies)
  0 siblings, 7 replies; 12+ messages in thread
From: Oleksij Rempel @ 2018-04-29 13:09 UTC (permalink / raw)
  To: barebox; +Cc: Oleksij Rempel

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

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 kernel and cmdline passing is supported. 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 (2):
  MIPS: ath79: add kexec support
  MIPS: configs: add KEXEC=y to atheros devices

 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 |   1 +
 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                            |   3 +
 arch/mips/lib/kexec-mips.c                        | 272 +++++++++
 arch/mips/lib/machine_kexec.h                     |  21 +
 arch/mips/lib/relocate_kernel.S                   | 108 ++++
 arch/mips/mach-ath79/Makefile                     |   1 +
 arch/mips/mach-ath79/reboot.c                     |  42 ++
 arch/mips/mach-malta/Makefile                     |   1 +
 arch/mips/mach-malta/reboot.c                     | 106 ++++
 commands/Kconfig                                  |   7 +
 common/Kconfig                                    |   3 +
 common/filetype.c                                 |   5 +
 common/resource.c                                 |  15 +
 include/bootm.h                                   |   3 +
 include/filetype.h                                |   1 +
 include/linux/ioport.h                            |   2 +
 include/linux/reboot.h                            |  14 +
 lib/Makefile                                      |   1 +
 lib/kexec/Makefile                                |   4 +
 lib/kexec/kexec-bootm-elf.c                       |  37 ++
 lib/kexec/kexec-elf-exec.c                        |  79 +++
 lib/kexec/kexec-elf.c                             | 678 ++++++++++++++++++++++
 lib/kexec/kexec-elf.h                             |  66 +++
 lib/kexec/kexec.c                                 | 281 +++++++++
 lib/kexec/kexec.h                                 |  92 +++
 31 files changed, 1856 insertions(+), 1 deletion(-)
 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 arch/mips/mach-ath79/reboot.c
 create mode 100644 arch/mips/mach-malta/reboot.c
 create mode 100644 include/linux/reboot.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-elf.h
 create mode 100644 lib/kexec/kexec.c
 create mode 100644 lib/kexec/kexec.h

-- 
2.14.1


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

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

* [RFC PATCH 1/7] resource: add create_resource() helper function
  2018-04-29 13:09 [RFC PATCH 0/7] provide ELF/KEXEC support for MIPS ath79 and malta Oleksij Rempel
@ 2018-04-29 13:09 ` Oleksij Rempel
  2018-04-29 13:09 ` [RFC PATCH 2/7] filetype: add ELF type Oleksij Rempel
                   ` (5 subsequent siblings)
  6 siblings, 0 replies; 12+ messages in thread
From: Oleksij Rempel @ 2018-04-29 13:09 UTC (permalink / raw)
  To: barebox

From: Antony Pavlov <antonynpavlov@gmail.com>

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] 12+ messages in thread

* [RFC PATCH 2/7] filetype: add ELF type
  2018-04-29 13:09 [RFC PATCH 0/7] provide ELF/KEXEC support for MIPS ath79 and malta Oleksij Rempel
  2018-04-29 13:09 ` [RFC PATCH 1/7] resource: add create_resource() helper function Oleksij Rempel
@ 2018-04-29 13:09 ` Oleksij Rempel
  2018-04-29 13:09 ` [RFC PATCH 3/7] bootm: add kexec ELF support Oleksij Rempel
                   ` (4 subsequent siblings)
  6 siblings, 0 replies; 12+ messages in thread
From: Oleksij Rempel @ 2018-04-29 13:09 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] 12+ messages in thread

* [RFC PATCH 3/7] bootm: add kexec ELF support
  2018-04-29 13:09 [RFC PATCH 0/7] provide ELF/KEXEC support for MIPS ath79 and malta Oleksij Rempel
  2018-04-29 13:09 ` [RFC PATCH 1/7] resource: add create_resource() helper function Oleksij Rempel
  2018-04-29 13:09 ` [RFC PATCH 2/7] filetype: add ELF type Oleksij Rempel
@ 2018-04-29 13:09 ` Oleksij Rempel
  2018-05-04  5:54   ` Sascha Hauer
  2018-04-29 13:09 ` [RFC PATCH 4/7] MIPS: add kexec ELF loading support Oleksij Rempel
                   ` (3 subsequent siblings)
  6 siblings, 1 reply; 12+ messages in thread
From: Oleksij Rempel @ 2018-04-29 13:09 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/linux/reboot.h      |  14 +
 lib/Makefile                |   1 +
 lib/kexec/Makefile          |   4 +
 lib/kexec/kexec-bootm-elf.c |  37 +++
 lib/kexec/kexec-elf-exec.c  |  79 ++++++
 lib/kexec/kexec-elf.c       | 678 ++++++++++++++++++++++++++++++++++++++++++++
 lib/kexec/kexec-elf.h       |  66 +++++
 lib/kexec/kexec.c           | 281 ++++++++++++++++++
 lib/kexec/kexec.h           |  92 ++++++
 12 files changed, 1265 insertions(+)
 create mode 100644 include/linux/reboot.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-elf.h
 create mode 100644 lib/kexec/kexec.c
 create mode 100644 lib/kexec/kexec.h

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/linux/reboot.h b/include/linux/reboot.h
new file mode 100644
index 000000000..1679070b4
--- /dev/null
+++ b/include/linux/reboot.h
@@ -0,0 +1,14 @@
+#ifndef _LINUX_REBOOT_H
+#define _LINUX_REBOOT_H
+
+/*
+ * Commands accepted by the _reboot() system call.
+ *
+ * KEXEC       Restart system using a previously loaded Linux kernel
+ */
+
+#define	LINUX_REBOOT_CMD_KEXEC		0x45584543
+
+extern int reboot(int cmd, void *opaque);
+
+#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..78c9f85cf
--- /dev/null
+++ b/lib/kexec/kexec-bootm-elf.c
@@ -0,0 +1,37 @@
+#include <bootm.h>
+#include <init.h>
+#include <binfmt.h>
+#include <errno.h>
+#include <linux/reboot.h>
+#include <environment.h>
+
+#include "kexec.h"
+
+static int do_bootm_elf(struct image_data *data)
+{
+	kexec_load_bootm_data(data);
+
+	reboot(LINUX_REBOOT_CMD_KEXEC, 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)
+{
+	register_image_handler(&elf_handler);
+	binfmt_register(&binfmt_elf_hook);
+
+	return 0;
+}
+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..094970e3b
--- /dev/null
+++ b/lib/kexec/kexec-elf-exec.c
@@ -0,0 +1,79 @@
+#include <common.h>
+#include <string.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <memory.h>
+#include <elf.h>
+#include "kexec.h"
+#include "kexec-elf.h"
+
+int build_elf_exec_info(const char *buf, off_t len, struct mem_ehdr *ehdr,
+				uint32_t flags)
+{
+	struct mem_phdr *phdr, *end_phdr;
+	int result;
+
+	result = build_elf_info(buf, len, ehdr, flags);
+	if (result < 0)
+		return result;
+
+	if (ehdr->e_type != ET_EXEC) {
+		printf("Not ELF type ET_EXEC\n");
+		return -1;
+	}
+
+	if (!ehdr->e_phdr) {
+		printf("No ELF program header\n");
+		return -1;
+	}
+
+	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) {
+			printf("Requires an ELF interpreter\n");
+			return -1;
+		}
+	}
+
+	return 0;
+}
+
+int elf_exec_load(struct mem_ehdr *ehdr, struct kexec_info *info)
+{
+	int result;
+	size_t i;
+
+	if (!ehdr->e_phdr) {
+		printf("No program header?\n");
+		result = -1;
+		goto out;
+	}
+
+	/* 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);
+	}
+
+	result = 0;
+ out:
+	return result;
+}
diff --git a/lib/kexec/kexec-elf.c b/lib/kexec/kexec-elf.c
new file mode 100644
index 000000000..44eb23288
--- /dev/null
+++ b/lib/kexec/kexec-elf.c
@@ -0,0 +1,678 @@
+#include <common.h>
+#include <string.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <malloc.h>
+#include <memory.h>
+#include <asm/io.h>
+#include "elf.h"
+#include "kexec.h"
+#include "kexec-elf.h"
+
+uint16_t elf16_to_cpu(const struct mem_ehdr *ehdr, uint16_t value)
+{
+	if (ehdr->ei_data == ELFDATA2LSB)
+		value = le16_to_cpu(value);
+	else if (ehdr->ei_data == ELFDATA2MSB)
+		value = be16_to_cpu(value);
+
+	return value;
+}
+
+uint32_t elf32_to_cpu(const struct mem_ehdr *ehdr, uint32_t value)
+{
+	if (ehdr->ei_data == ELFDATA2LSB)
+		value = le32_to_cpu(value);
+	else if (ehdr->ei_data == ELFDATA2MSB)
+		value = be32_to_cpu(value);
+
+	return value;
+}
+
+uint64_t elf64_to_cpu(const struct mem_ehdr *ehdr, uint64_t value)
+{
+	if (ehdr->ei_data == ELFDATA2LSB)
+		value = le64_to_cpu(value);
+	else if (ehdr->ei_data == ELFDATA2MSB)
+		value = be64_to_cpu(value);
+
+	return value;
+}
+
+static int build_mem_elf32_ehdr(const char *buf, off_t len,
+				struct mem_ehdr *ehdr)
+{
+	Elf32_Ehdr lehdr;
+
+	if ((size_t)len < sizeof(lehdr)) {
+		printf("Buffer is too small to hold ELF header\n");
+		return -1;
+	}
+
+	memcpy(&lehdr, buf, sizeof(lehdr));
+	if (elf16_to_cpu(ehdr, lehdr.e_ehsize) != sizeof(Elf32_Ehdr)) {
+		printf("Bad ELF header size\n");
+		return -1;
+	}
+
+	if (elf32_to_cpu(ehdr, lehdr.e_entry) > UINT32_MAX) {
+		printf("ELF e_entry is too large\n");
+		return -1;
+	}
+
+	if (elf32_to_cpu(ehdr, lehdr.e_phoff) > UINT32_MAX) {
+		printf("ELF e_phoff is too large\n");
+		return -1;
+	}
+
+	if (elf32_to_cpu(ehdr, lehdr.e_shoff) > UINT32_MAX) {
+		printf("ELF e_shoff is too large\n");
+		return -1;
+	}
+
+	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))) {
+		printf("ELF bad program header size\n");
+		return -1;
+	}
+
+	if ((ehdr->e_shnum > 0) &&
+		(elf16_to_cpu(ehdr, lehdr.e_shentsize) != sizeof(Elf32_Shdr))) {
+		printf("ELF bad section header size\n");
+		return -1;
+	}
+
+	return 0;
+}
+
+static int build_mem_elf64_ehdr(const char *buf, off_t len,
+				struct mem_ehdr *ehdr)
+{
+	Elf64_Ehdr lehdr;
+
+	if ((size_t)len < sizeof(lehdr)) {
+		printf("Buffer is too small to hold ELF header\n");
+		return -1;
+	}
+
+	memcpy(&lehdr, buf, sizeof(lehdr));
+	if (elf16_to_cpu(ehdr, lehdr.e_ehsize) != sizeof(Elf64_Ehdr)) {
+		printf("Bad ELF header size\n");
+		return -1;
+	}
+
+	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))) {
+		printf("ELF bad program header size\n");
+		return -1;
+	}
+
+	if ((ehdr->e_shnum > 0) &&
+		(elf16_to_cpu(ehdr, lehdr.e_shentsize) != sizeof(Elf64_Shdr))) {
+		printf("ELF bad section header size\n");
+		return -1;
+	}
+
+	return 0;
+}
+
+static int build_mem_ehdr(const char *buf, off_t len, struct mem_ehdr *ehdr)
+{
+	unsigned char e_ident[EI_NIDENT];
+	int result;
+
+	memset(ehdr, 0, sizeof(*ehdr));
+
+	if ((size_t)len < sizeof(e_ident)) {
+		printf("Buffer is too small to hold ELF e_ident\n");
+
+		return -1;
+	}
+
+	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)) {
+		printf("Not a supported ELF class\n");
+		return -1;
+	}
+
+	if ((ehdr->ei_data != ELFDATA2LSB) &&
+		(ehdr->ei_data != ELFDATA2MSB)) {
+		printf("Not a supported ELF data format\n");
+		return -1;
+	}
+
+	result = -1;
+	if (ehdr->ei_class == ELFCLASS32)
+		result = build_mem_elf32_ehdr(buf, len, ehdr);
+
+	if (ehdr->ei_class == ELFCLASS64)
+		result = build_mem_elf64_ehdr(buf, len, ehdr);
+
+	if (result < 0)
+		return result;
+
+	if ((e_ident[EI_VERSION] != EV_CURRENT) ||
+		(ehdr->e_version != EV_CURRENT)) {
+		printf("Unknown ELF version\n");
+		return -1;
+	}
+
+	return 0;
+}
+
+static int build_mem_elf32_phdr(const char *buf, struct mem_ehdr *ehdr, int idx)
+{
+	struct mem_phdr *phdr;
+	const char *pbuf;
+	Elf32_Phdr lphdr;
+
+	pbuf = buf + ehdr->e_phoff + (idx * sizeof(lphdr));
+	phdr = &ehdr->e_phdr[idx];
+	memcpy(&lphdr, pbuf, sizeof(lphdr));
+
+	if ((elf32_to_cpu(ehdr, lphdr.p_filesz) > UINT32_MAX) ||
+		(elf32_to_cpu(ehdr, lphdr.p_memsz)  > UINT32_MAX) ||
+		(elf32_to_cpu(ehdr, lphdr.p_offset) > UINT32_MAX) ||
+		(elf32_to_cpu(ehdr, lphdr.p_paddr)  > UINT32_MAX) ||
+		(elf32_to_cpu(ehdr, lphdr.p_vaddr)  > UINT32_MAX) ||
+		(elf32_to_cpu(ehdr, lphdr.p_align)  > UINT32_MAX)) {
+		printf("Program segment size out of range\n");
+		return -1;
+	}
+
+	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);
+
+	return 0;
+}
+
+static int build_mem_elf64_phdr(const char *buf, struct mem_ehdr *ehdr, int idx)
+{
+	struct mem_phdr *phdr;
+	const char *pbuf;
+	Elf64_Phdr lphdr;
+
+	pbuf = buf + ehdr->e_phoff + (idx * sizeof(lphdr));
+	phdr = &ehdr->e_phdr[idx];
+	memcpy(&lphdr, pbuf, sizeof(lphdr));
+	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);
+
+	return 0;
+}
+
+static int build_mem_phdrs(const char *buf, off_t len, struct mem_ehdr *ehdr,
+				uint32_t flags)
+{
+	size_t phdr_size, mem_phdr_size, i;
+
+	/* e_phnum is at most 65535 so calculating
+	 * the size of the program header cannot overflow.
+	 */
+	/* Is the program header in the file buffer? */
+	phdr_size = 0;
+	if (ehdr->ei_class == ELFCLASS32) {
+		phdr_size = sizeof(Elf32_Phdr);
+	} else if (ehdr->ei_class == ELFCLASS64) {
+		phdr_size = sizeof(Elf64_Phdr);
+	} else {
+		printf("Invalid ei_class?\n");
+		return -1;
+	}
+	phdr_size *= ehdr->e_phnum;
+
+	/* 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;
+		int result;
+
+		result = -1;
+		if (ehdr->ei_class == ELFCLASS32)
+			result = build_mem_elf32_phdr(buf, ehdr, i);
+
+		if (ehdr->ei_class == ELFCLASS64)
+			result = build_mem_elf64_phdr(buf, ehdr, i);
+
+		if (result < 0)
+			return result;
+
+		/* 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 */
+			printf("ELF address wrap around\n");
+			return -1;
+		}
+
+		/* 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;
+	const char *sbuf;
+	int size_ok;
+	Elf32_Shdr lshdr;
+
+	sbuf = buf + ehdr->e_shoff + (idx * sizeof(lshdr));
+	shdr = &ehdr->e_shdr[idx];
+	memcpy(&lshdr, sbuf, sizeof(lshdr));
+
+	if ((elf32_to_cpu(ehdr, lshdr.sh_flags)     > UINT32_MAX) ||
+		(elf32_to_cpu(ehdr, lshdr.sh_addr)      > UINT32_MAX) ||
+		(elf32_to_cpu(ehdr, lshdr.sh_offset)    > UINT32_MAX) ||
+		(elf32_to_cpu(ehdr, lshdr.sh_size)      > UINT32_MAX) ||
+		(elf32_to_cpu(ehdr, lshdr.sh_addralign) > UINT32_MAX) ||
+		(elf32_to_cpu(ehdr, lshdr.sh_entsize)   > UINT32_MAX)) {
+		printf("Program section size out of range\n");
+		return -1;
+	}
+
+	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) {
+		printf("Bad section header(%x) entsize: %lld\n",
+			shdr->sh_type, shdr->sh_entsize);
+		return -1;
+	}
+
+	return 0;
+}
+
+static int build_mem_elf64_shdr(const char *buf, struct mem_ehdr *ehdr, int idx)
+{
+	struct mem_shdr *shdr;
+	const char *sbuf;
+	int size_ok;
+	Elf64_Shdr lshdr;
+
+	sbuf = buf + ehdr->e_shoff + (idx * sizeof(lshdr));
+	shdr = &ehdr->e_shdr[idx];
+	memcpy(&lshdr, sbuf, sizeof(lshdr));
+	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) {
+		printf("Bad section header(%x) entsize: %lld\n",
+			shdr->sh_type, shdr->sh_entsize);
+		return -1;
+	}
+
+	return 0;
+}
+
+static int build_mem_shdrs(const char *buf, off_t len, struct mem_ehdr *ehdr,
+				uint32_t flags)
+{
+	size_t shdr_size, mem_shdr_size, i;
+
+	/* e_shnum is at most 65536 so calculating
+	 * the size of the section header cannot overflow.
+	 */
+	/* Is the program header in the file buffer? */
+	shdr_size = 0;
+	if (ehdr->ei_class == ELFCLASS32) {
+		shdr_size = sizeof(Elf32_Shdr);
+	} else if (ehdr->ei_class == ELFCLASS64) {
+		shdr_size = sizeof(Elf64_Shdr);
+	} else {
+		printf("Invalid ei_class?\n");
+		return -1;
+	}
+	shdr_size *= ehdr->e_shnum;
+
+	/* 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 result;
+
+		result = -1;
+		if (ehdr->ei_class == ELFCLASS32)
+			result = build_mem_elf32_shdr(buf, ehdr, i);
+
+		if (ehdr->ei_class == ELFCLASS64)
+			result = build_mem_elf64_shdr(buf, ehdr, i);
+
+		if (result < 0)
+			return result;
+
+		/* 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) {
+			printf("ELF address wrap around\n");
+			return -1;
+		}
+
+		/* 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, off_t len, struct mem_ehdr *ehdr,
+			uint32_t flags)
+{
+	int result;
+
+	result = build_mem_ehdr(buf, len, ehdr);
+	if (result < 0)
+		return result;
+
+	if ((ehdr->e_phoff > 0) && (ehdr->e_phnum > 0)) {
+		result = build_mem_phdrs(buf, len, ehdr, flags);
+		if (result < 0) {
+			free_elf_info(ehdr);
+			return result;
+		}
+	}
+
+	if ((ehdr->e_shoff > 0) && (ehdr->e_shnum > 0)) {
+		result = build_mem_shdrs(buf, len, ehdr, flags);
+		if (result < 0) {
+			free_elf_info(ehdr);
+			return result;
+		}
+	}
+
+	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) {
+			resource_size_t start, end;
+
+			res = bank->res;
+
+			start = virt_to_phys((void *)res->start);
+			end = virt_to_phys((void *)res->end);
+
+			if ((start <= r->start) && (end >= r->end)) {
+				got_bank = 1;
+				break;
+			}
+		}
+
+		if (!got_bank)
+			return -1;
+	}
+
+	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 (((rb->end >= ra->start) && (rb->end <= ra->end))
+			|| ((rb->start >= ra->start) && (rb->start <= ra->end))
+			|| ((rb->start >= ra->start) && (rb->end <= ra->end))
+			|| ((ra->start >= rb->start) && (ra->end <= rb->end))
+			|| (ra->start == rb->end + 1)
+			|| (rb->start == ra->end + 1)) {
+			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);
+
+	/* FIXME */
+	return r->start;
+}
diff --git a/lib/kexec/kexec-elf.h b/lib/kexec/kexec-elf.h
new file mode 100644
index 000000000..06826c44c
--- /dev/null
+++ b/lib/kexec/kexec-elf.h
@@ -0,0 +1,66 @@
+#ifndef KEXEC_ELF_H
+#define KEXEC_ELF_H
+
+struct kexec_info;
+
+struct mem_ehdr {
+	unsigned ei_class;
+	unsigned ei_data;
+	unsigned e_type;
+	unsigned e_machine;
+	unsigned e_version;
+	unsigned e_flags;
+	unsigned e_phnum;
+	unsigned e_shnum;
+	unsigned e_shstrndx;
+	unsigned long long e_entry;
+	unsigned long long e_phoff;
+	unsigned long long e_shoff;
+	struct mem_phdr *e_phdr;
+	struct mem_shdr *e_shdr;
+};
+
+struct mem_phdr {
+	unsigned long long p_paddr;
+	unsigned long long p_vaddr;
+	unsigned long long p_filesz;
+	unsigned long long p_memsz;
+	unsigned long long p_offset;
+	const char *p_data;
+	unsigned p_type;
+	unsigned p_flags;
+	unsigned long long p_align;
+};
+
+struct mem_shdr {
+	unsigned sh_name;
+	unsigned sh_type;
+	unsigned long long sh_flags;
+	unsigned long long sh_addr;
+	unsigned long long sh_offset;
+	unsigned long long sh_size;
+	unsigned sh_link;
+	unsigned sh_info;
+	unsigned long long sh_addralign;
+	unsigned long long sh_entsize;
+	const unsigned char *sh_data;
+};
+
+extern void free_elf_info(struct mem_ehdr *ehdr);
+extern int build_elf_info(const char *buf, off_t len, struct mem_ehdr *ehdr,
+				uint32_t flags);
+extern int build_elf_exec_info(const char *buf, off_t len,
+				struct mem_ehdr *ehdr, uint32_t flags);
+
+extern int elf_exec_load(struct mem_ehdr *ehdr, struct kexec_info *info);
+
+uint16_t elf16_to_cpu(const struct mem_ehdr *ehdr, uint16_t value);
+uint32_t elf32_to_cpu(const struct mem_ehdr *ehdr, uint32_t value);
+uint64_t elf64_to_cpu(const struct mem_ehdr *ehdr, uint64_t value);
+
+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 /* KEXEC_ELF_H */
diff --git a/lib/kexec/kexec.c b/lib/kexec/kexec.c
new file mode 100644
index 000000000..3a021173e
--- /dev/null
+++ b/lib/kexec/kexec.c
@@ -0,0 +1,281 @@
+/*
+ * 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
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation (version 2 of the License).
+ *
+ * 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.
+ *
+ */
+
+#define _GNU_SOURCE
+#include <common.h>
+#include <fs.h>
+#include <stdarg.h>
+#include <string.h>
+#include <stdlib.h>
+#include <asm/io.h>
+
+#include <boot.h>
+#include <libfile.h>
+
+#include "kexec.h"
+#include "kexec-elf.h"
+
+static int sort_segments(struct kexec_info *info)
+{
+	int i, j;
+	void *end;
+
+	/* 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 */
+	end = 0;
+	for (i = 0; i < info->nr_segments; i++) {
+		if (end > info->segment[i].mem) {
+			printf("Overlapping memory segments at %p\n",
+				end);
+			return -1;
+		}
+		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) {
+		printf("Warning: kernel segment limit reached. "
+			"This will likely fail\n");
+	}
+}
+
+static int kexec_load_one_file(struct kexec_info *info, char *fname,
+			       unsigned long kexec_flags)
+{
+	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) {
+		printf("Cannot determine the file type "
+				"of %s\n", fname);
+		return -1;
+	}
+
+	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 -1;
+
+	add_segment(info, buf, *fsize, base, *fsize);
+
+	return 0;
+}
+
+static int print_segments(struct kexec_info *info)
+{
+	int i;
+
+	printf("print_segments\n");
+	for (i = 0; i < info->nr_segments; i++) {
+		struct kexec_segment *seg = &info->segment[i];
+
+		printf("  %d. buf=%#08p bufsz=%#lx mem=%#08p memsz=%#lx\n", i,
+			seg->buf, seg->bufsz, seg->mem, seg->memsz);
+	}
+
+	return 0;
+}
+
+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;
+}
+
+#include <environment.h>
+
+int kexec_load_bootm_data(struct image_data *data)
+{
+	int result;
+	struct kexec_info info;
+	char *cmdline;
+	const char *t;
+	size_t tlen, klen;
+	size_t fsize;
+	char initrd_cmdline[40];
+	int padded = 0;
+
+	memset(&info, 0, sizeof(info));
+
+	initrd_cmdline[0] = 0;
+
+	result = kexec_load_one_file(&info, data->os_file, 0);
+	if (result < 0) {
+		printf("Cannot load %s\n", data->os_file);
+		return result;
+	}
+
+	if (data->oftree_file) {
+		unsigned long base = find_unused_base(&info, &padded);
+
+		base = ALIGN(base, 8);
+
+		result = kexec_load_binary_file(&info,
+				data->oftree_file, &fsize, base);
+		if (result < 0) {
+			printf("Cannot load %s\n", data->oftree_file);
+			return result;
+		}
+		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);
+
+		result = kexec_load_binary_file(&info,
+				data->initrd_file, &fsize, base);
+		if (result < 0) {
+			printf("Cannot load %s\n", data->initrd_file);
+			return result;
+		}
+		data->initrd_address = base;
+
+		if (bootm_verbose(data)) {
+			printf("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);
+	}
+
+	/* FIXME: we can snprintf to cmdline directly */
+	t = linux_bootargs_get();
+	if (t)
+		tlen = strlen(t);
+	else
+		tlen = 0;
+
+	klen = strlen("kexec ");
+	cmdline = xzalloc(tlen + sizeof(initrd_cmdline) + klen);
+	memcpy(cmdline, "kexec ", klen);
+	if (tlen)
+		memcpy(cmdline + klen, t, tlen);
+
+	memcpy(cmdline + klen + 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);
+
+		/* FIXME */
+		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 */
+	if (sort_segments(&info) < 0)
+		return -1;
+
+	return kexec_load(info.entry,
+		info.nr_segments, info.segment, info.kexec_flags);
+}
diff --git a/lib/kexec/kexec.h b/lib/kexec/kexec.h
new file mode 100644
index 000000000..527a36861
--- /dev/null
+++ b/lib/kexec/kexec.h
@@ -0,0 +1,92 @@
+#ifndef KEXEC_H
+#define KEXEC_H
+
+#include "kexec-elf.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 long kexec_load(void *entry, unsigned long nr_segments,
+		       struct kexec_segment *segments, unsigned long flags);
+
+#include <bootm.h>
+
+extern int kexec_load_bootm_data(struct image_data *data);
+
+/* Limits of integral types. */
+#ifndef INT8_MIN
+#define INT8_MIN               (-128)
+#endif
+#ifndef INT16_MIN
+#define INT16_MIN              (-32767-1)
+#endif
+#ifndef INT32_MIN
+#define INT32_MIN              (-2147483647-1)
+#endif
+#ifndef INT8_MAX
+#define INT8_MAX               (127)
+#endif
+#ifndef INT16_MAX
+#define INT16_MAX              (32767)
+#endif
+#ifndef INT32_MAX
+#define INT32_MAX              (2147483647)
+#endif
+#ifndef UINT8_MAX
+#define UINT8_MAX              (255U)
+#endif
+#ifndef UINT16_MAX
+#define UINT16_MAX             (65535U)
+#endif
+#ifndef UINT32_MAX
+#define UINT32_MAX             (4294967295U)
+#endif
+
+/* 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
+
+#endif /* KEXEC_H */
-- 
2.14.1


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

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

* [RFC PATCH 4/7] MIPS: add kexec ELF loading support
  2018-04-29 13:09 [RFC PATCH 0/7] provide ELF/KEXEC support for MIPS ath79 and malta Oleksij Rempel
                   ` (2 preceding siblings ...)
  2018-04-29 13:09 ` [RFC PATCH 3/7] bootm: add kexec ELF support Oleksij Rempel
@ 2018-04-29 13:09 ` Oleksij Rempel
  2018-04-29 13:09 ` [RFC PATCH 5/7] MIPS: ath79: add kexec support Oleksij Rempel
                   ` (2 subsequent siblings)
  6 siblings, 0 replies; 12+ messages in thread
From: Oleksij Rempel @ 2018-04-29 13:09 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          |   3 +
 arch/mips/lib/kexec-mips.c      | 272 ++++++++++++++++++++++++++++++++++++++++
 arch/mips/lib/machine_kexec.h   |  21 ++++
 arch/mips/lib/relocate_kernel.S | 108 ++++++++++++++++
 5 files changed, 411 insertions(+), 1 deletion(-)
 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..8dc498986 100644
--- a/arch/mips/lib/Makefile
+++ b/arch/mips/lib/Makefile
@@ -18,4 +18,7 @@ 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
+
 pbl-y	+= ashldi3.o
diff --git a/arch/mips/lib/kexec-mips.c b/arch/mips/lib/kexec-mips.c
new file mode 100644
index 000000000..656249db4
--- /dev/null
+++ b/arch/mips/lib/kexec-mips.c
@@ -0,0 +1,272 @@
+/*
+ * 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
+ *
+ * This source code is licensed under the GNU General Public License,
+ * Version 2.  See the file COPYING for more details.
+ */
+
+#include <linux/stddef.h>
+#include <stdio.h>
+#include <errno.h>
+#include <string.h>
+#include <asm/io.h>
+#include <asm/addrspace.h>
+#include <memory.h>
+#include <elf.h>
+#include "../../../lib/kexec/kexec.h"
+#include "machine_kexec.h"
+
+
+static int elf_mips_probe(const char *buf, off_t len)
+{
+	struct mem_ehdr ehdr;
+	int result;
+
+	result = build_elf_exec_info(buf, len, &ehdr, 0);
+	if (result < 0) {
+		goto out;
+	}
+
+	/* Verify the architecuture specific bits */
+	if (ehdr.e_machine != EM_MIPS) {
+		/* for a different architecture */
+		printf("Not for this architecture.\n");
+		result = -1;
+		goto out;
+	}
+	result = 0;
+
+ out:
+	free_elf_info(&ehdr);
+
+	return result;
+}
+
+static int elf_mips_load(const char *buf, off_t len, struct kexec_info *info)
+{
+	struct mem_ehdr ehdr;
+	int result;
+	size_t i;
+
+	result = build_elf_exec_info(buf, len, &ehdr, 0);
+	if (result < 0) {
+		printf("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((void *)phdr->p_paddr);
+		}
+	}
+
+	/* Load the ELF data */
+	result = elf_exec_load(&ehdr, info);
+	if (result < 0) {
+		printf("ELF exec load failed\n");
+		goto out;
+	}
+
+	info->entry = (void *)virt_to_phys((void *)ehdr.e_entry);
+
+out:
+	return result;
+}
+
+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(void)
+{
+	unsigned long argc = (int)kexec_args[0];
+	int i;
+
+	printf("kexec_args[0] (argc): %lu\n", argc);
+	printf("kexec_args[1] (argv): %p\n", (void *)kexec_args[1]);
+	printf("kexec_args[2] (env ): %p\n", (void *)kexec_args[2]);
+	printf("kexec_args[3] (desc): %p\n", (void *)kexec_args[3]);
+
+	for (i = 0; i < argc; i++) {
+		printf("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)
+		printf("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 int machine_kexec_prepare(struct kexec_segment *segments, unsigned long nr_segments)
+{
+	/*
+	 * Whenever arguments passed from kexec-tools, Init the arguments as
+	 * the original ones to try avoiding booting failure.
+	 */
+
+	machine_kexec_init_argv(segments, nr_segments);
+	machine_kexec_parse_argv();
+	machine_kexec_print_args();
+
+	return 0;
+}
+long kexec_load(void *entry, unsigned long nr_segments,
+		struct kexec_segment *segments, unsigned long flags)
+{
+	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)) {
+		printf("ELF can't be loaded!\n");
+		return 0;
+	}
+
+	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(segments, nr_segments);
+
+	return 1;
+}
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..8c79277a2
--- /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, 1
+	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] 12+ messages in thread

* [RFC PATCH 5/7] MIPS: ath79: add kexec support
  2018-04-29 13:09 [RFC PATCH 0/7] provide ELF/KEXEC support for MIPS ath79 and malta Oleksij Rempel
                   ` (3 preceding siblings ...)
  2018-04-29 13:09 ` [RFC PATCH 4/7] MIPS: add kexec ELF loading support Oleksij Rempel
@ 2018-04-29 13:09 ` Oleksij Rempel
  2018-04-29 13:09 ` [RFC PATCH 6/7] MIPS: malta: enable kexec Oleksij Rempel
  2018-04-29 13:09 ` [RFC PATCH 7/7] MIPS: configs: add KEXEC=y to atheros devices Oleksij Rempel
  6 siblings, 0 replies; 12+ messages in thread
From: Oleksij Rempel @ 2018-04-29 13:09 UTC (permalink / raw)
  To: barebox; +Cc: Oleksij Rempel

Signed-off-by: Oleksij Rempel <linux@rempel-privat.de>
---
 arch/mips/Kconfig             |  1 +
 arch/mips/mach-ath79/Makefile |  1 +
 arch/mips/mach-ath79/reboot.c | 42 ++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 44 insertions(+)
 create mode 100644 arch/mips/mach-ath79/reboot.c

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"
diff --git a/arch/mips/mach-ath79/Makefile b/arch/mips/mach-ath79/Makefile
index 3772daeba..9b8218dd6 100644
--- a/arch/mips/mach-ath79/Makefile
+++ b/arch/mips/mach-ath79/Makefile
@@ -1,2 +1,3 @@
 obj-y += reset.o
 obj-y += bbu.o
+obj-$(CONFIG_KEXEC) += reboot.o
diff --git a/arch/mips/mach-ath79/reboot.c b/arch/mips/mach-ath79/reboot.c
new file mode 100644
index 000000000..c207c58d3
--- /dev/null
+++ b/arch/mips/mach-ath79/reboot.c
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2018 Antony Pavlov <antonynpavlov@gmail.com>
+ *
+ * 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 <common.h>
+#include <init.h>
+#include <memory.h>
+#include <boot.h>
+#include <linux/reboot.h>
+#include <bootm.h>
+#include "../../../lib/kexec/kexec.h"
+#include <asm/io.h>
+
+int reboot(int cmd, void *opaque)
+{
+	if (cmd == LINUX_REBOOT_CMD_KEXEC) {
+		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();
+	}
+
+	return -1;
+}
+EXPORT_SYMBOL(reboot);
-- 
2.14.1


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

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

* [RFC PATCH 6/7] MIPS: malta: enable kexec
  2018-04-29 13:09 [RFC PATCH 0/7] provide ELF/KEXEC support for MIPS ath79 and malta Oleksij Rempel
                   ` (4 preceding siblings ...)
  2018-04-29 13:09 ` [RFC PATCH 5/7] MIPS: ath79: add kexec support Oleksij Rempel
@ 2018-04-29 13:09 ` Oleksij Rempel
  2018-04-29 13:09 ` [RFC PATCH 7/7] MIPS: configs: add KEXEC=y to atheros devices Oleksij Rempel
  6 siblings, 0 replies; 12+ messages in thread
From: Oleksij Rempel @ 2018-04-29 13:09 UTC (permalink / raw)
  To: barebox

From: Antony Pavlov <antonynpavlov@gmail.com>

Signed-off-by: Antony Pavlov <antonynpavlov@gmail.com>
---
 arch/mips/Kconfig             |   1 +
 arch/mips/mach-malta/Makefile |   1 +
 arch/mips/mach-malta/reboot.c | 106 ++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 108 insertions(+)
 create mode 100644 arch/mips/mach-malta/reboot.c

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"
diff --git a/arch/mips/mach-malta/Makefile b/arch/mips/mach-malta/Makefile
index 0c5a7018d..20d9204f3 100644
--- a/arch/mips/mach-malta/Makefile
+++ b/arch/mips/mach-malta/Makefile
@@ -1,2 +1,3 @@
 obj-y += reset.o
 obj-$(CONFIG_PCI) += pci.o
+obj-$(CONFIG_KEXEC) += reboot.o
diff --git a/arch/mips/mach-malta/reboot.c b/arch/mips/mach-malta/reboot.c
new file mode 100644
index 000000000..b4572fc1d
--- /dev/null
+++ b/arch/mips/mach-malta/reboot.c
@@ -0,0 +1,106 @@
+/*
+ * Copyright (C) 2014, 2016 Antony Pavlov <antonynpavlov@gmail.com>
+ *
+ * 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 <common.h>
+#include <init.h>
+#include <memory.h>
+#include <boot.h>
+#include <linux/reboot.h>
+#include <bootm.h>
+#include "../../../lib/kexec/kexec.h"
+#include <asm/io.h>
+
+#define ENVP_ADDR	0x80002000l
+#define ENVP_NB_ENTRIES	16
+#define ENVP_ENTRY_SIZE	256
+
+static int reserve_yamon_prom_env(void)
+{
+	request_sdram_region("yamon env",
+		(unsigned long)ENVP_ADDR,
+		ENVP_NB_ENTRIES * ENVP_ENTRY_SIZE);
+
+	return 0;
+}
+late_initcall(reserve_yamon_prom_env);
+
+static void prom_set(uint32_t *prom_buf, int index,
+			const char *string, ...)
+{
+	va_list ap;
+	int32_t table_addr;
+
+	if (index >= ENVP_NB_ENTRIES)
+		return;
+
+	if (string == NULL) {
+		prom_buf[index] = 0;
+		return;
+	}
+
+	table_addr = sizeof(int32_t) * ENVP_NB_ENTRIES + index * ENVP_ENTRY_SIZE;
+	prom_buf[index] = (ENVP_ADDR + table_addr);
+
+	va_start(ap, string);
+	vsnprintf((char *)prom_buf + table_addr, ENVP_ENTRY_SIZE, string, ap);
+	va_end(ap);
+}
+
+static inline void yamon_prom_set(char *fname)
+{
+	void *prom_buf;
+	long prom_size;
+	int prom_index = 0;
+
+	/* Setup prom parameters. */
+	prom_size = ENVP_NB_ENTRIES * (sizeof(int32_t) + ENVP_ENTRY_SIZE);
+	prom_buf = (void *)ENVP_ADDR;
+
+	prom_set(prom_buf, prom_index++, "%s", fname);
+	prom_set(prom_buf, prom_index++, "%s", linux_bootargs_get());
+
+	prom_set(prom_buf, prom_index++, "memsize");
+	prom_set(prom_buf, prom_index++, "%i", 256 << 20);
+	prom_set(prom_buf, prom_index++, "modetty0");
+	prom_set(prom_buf, prom_index++, "38400n8r");
+	prom_set(prom_buf, prom_index++, NULL);
+}
+
+int reboot(int cmd, void *opaque)
+{
+	if (cmd == LINUX_REBOOT_CMD_KEXEC) {
+		extern unsigned long reboot_code_buffer;
+		extern unsigned long kexec_args[4];
+		void (*kexec_code_buffer)(void);
+		struct image_data *data = opaque;
+
+		yamon_prom_set(data->os_file);
+
+		shutdown_barebox();
+
+		kexec_code_buffer = phys_to_virt(reboot_code_buffer);
+
+		kexec_args[0] = 2; /* number of arguments? */
+		kexec_args[1] = ENVP_ADDR;
+		kexec_args[2] = ENVP_ADDR + 8;
+		kexec_args[3] = 0x10000000; /* no matter */
+		kexec_code_buffer();
+	}
+
+	return -1;
+}
+EXPORT_SYMBOL(reboot);
-- 
2.14.1


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

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

* [RFC PATCH 7/7] MIPS: configs: add KEXEC=y to atheros devices
  2018-04-29 13:09 [RFC PATCH 0/7] provide ELF/KEXEC support for MIPS ath79 and malta Oleksij Rempel
                   ` (5 preceding siblings ...)
  2018-04-29 13:09 ` [RFC PATCH 6/7] MIPS: malta: enable kexec Oleksij Rempel
@ 2018-04-29 13:09 ` Oleksij Rempel
  6 siblings, 0 replies; 12+ messages in thread
From: Oleksij Rempel @ 2018-04-29 13:09 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] 12+ messages in thread

* Re: [RFC PATCH 3/7] bootm: add kexec ELF support
  2018-04-29 13:09 ` [RFC PATCH 3/7] bootm: add kexec ELF support Oleksij Rempel
@ 2018-05-04  5:54   ` Sascha Hauer
  2018-05-04 10:08     ` Antony Pavlov
  0 siblings, 1 reply; 12+ messages in thread
From: Sascha Hauer @ 2018-05-04  5:54 UTC (permalink / raw)
  To: Oleksij Rempel; +Cc: barebox

On Sun, Apr 29, 2018 at 03:09:03PM +0200, Oleksij Rempel wrote:
> +static int do_bootm_elf(struct image_data *data)
> +{
> +	kexec_load_bootm_data(data);
> +
> +	reboot(LINUX_REBOOT_CMD_KEXEC, data);
> +
> +	return -ERESTARTSYS;
> +}
> +

I can't really judge this series. This is the only thing I stumbled
upon: I see no reason to name the architecture specific kexec function
'reboot'. I would expect some kexec specific name, like arch_kexec or
similar.

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] 12+ messages in thread

* Re: [RFC PATCH 3/7] bootm: add kexec ELF support
  2018-05-04 10:08     ` Antony Pavlov
@ 2018-05-04  9:53       ` Oleksij Rempel
  2018-05-04 13:09         ` Antony Pavlov
  0 siblings, 1 reply; 12+ messages in thread
From: Oleksij Rempel @ 2018-05-04  9:53 UTC (permalink / raw)
  To: Antony Pavlov, Sascha Hauer; +Cc: barebox


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

Am 04.05.2018 um 12:08 schrieb Antony Pavlov:
> On Fri, 4 May 2018 07:54:08 +0200
> Sascha Hauer <s.hauer@pengutronix.de> wrote:
> 
>> On Sun, Apr 29, 2018 at 03:09:03PM +0200, Oleksij Rempel wrote:
>>> +static int do_bootm_elf(struct image_data *data)
>>> +{
>>> +	kexec_load_bootm_data(data);
>>> +
>>> +	reboot(LINUX_REBOOT_CMD_KEXEC, data);
>>> +
>>> +	return -ERESTARTSYS;
>>> +}
>>> +
>>
>> I can't really judge this series. This is the only thing I stumbled
>> upon: I see no reason to name the architecture specific kexec function
>> 'reboot'. I would expect some kexec specific name, like arch_kexec or
>> similar.
>>
> 
> This reboot function is copy-n-paste from linux kernel reboot syscall (see linux/kernel/reboot.c
> for details).
> At the moment there is only one constant for reboot()'s first argument (LINUX_REBOOT_CMD_KEXEC),
> so it's reasonable to elimenate this first argument and rename function to kexec_reboot().

amy be better to rename it to kexec_arch or kexec_mach. kexec_reboot is
kind if misleading

-- 
Regards,
Oleksij


[-- Attachment #1.2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 195 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] 12+ messages in thread

* Re: [RFC PATCH 3/7] bootm: add kexec ELF support
  2018-05-04  5:54   ` Sascha Hauer
@ 2018-05-04 10:08     ` Antony Pavlov
  2018-05-04  9:53       ` Oleksij Rempel
  0 siblings, 1 reply; 12+ messages in thread
From: Antony Pavlov @ 2018-05-04 10:08 UTC (permalink / raw)
  To: Sascha Hauer; +Cc: barebox, Oleksij Rempel

On Fri, 4 May 2018 07:54:08 +0200
Sascha Hauer <s.hauer@pengutronix.de> wrote:

> On Sun, Apr 29, 2018 at 03:09:03PM +0200, Oleksij Rempel wrote:
> > +static int do_bootm_elf(struct image_data *data)
> > +{
> > +	kexec_load_bootm_data(data);
> > +
> > +	reboot(LINUX_REBOOT_CMD_KEXEC, data);
> > +
> > +	return -ERESTARTSYS;
> > +}
> > +
> 
> I can't really judge this series. This is the only thing I stumbled
> upon: I see no reason to name the architecture specific kexec function
> 'reboot'. I would expect some kexec specific name, like arch_kexec or
> similar.
> 

This reboot function is copy-n-paste from linux kernel reboot syscall (see linux/kernel/reboot.c
for details).
At the moment there is only one constant for reboot()'s first argument (LINUX_REBOOT_CMD_KEXEC),
so it's reasonable to elimenate this first argument and rename function to kexec_reboot().

> 
> -- 
> 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


-- 
Best regards,
  Antony Pavlov

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

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

* Re: [RFC PATCH 3/7] bootm: add kexec ELF support
  2018-05-04  9:53       ` Oleksij Rempel
@ 2018-05-04 13:09         ` Antony Pavlov
  0 siblings, 0 replies; 12+ messages in thread
From: Antony Pavlov @ 2018-05-04 13:09 UTC (permalink / raw)
  To: Oleksij Rempel; +Cc: barebox

On Fri, 4 May 2018 11:53:48 +0200
Oleksij Rempel <linux@rempel-privat.de> wrote:

> Am 04.05.2018 um 12:08 schrieb Antony Pavlov:
> > On Fri, 4 May 2018 07:54:08 +0200
> > Sascha Hauer <s.hauer@pengutronix.de> wrote:
> > 
> >> On Sun, Apr 29, 2018 at 03:09:03PM +0200, Oleksij Rempel wrote:
> >>> +static int do_bootm_elf(struct image_data *data)
> >>> +{
> >>> +	kexec_load_bootm_data(data);
> >>> +
> >>> +	reboot(LINUX_REBOOT_CMD_KEXEC, data);
> >>> +
> >>> +	return -ERESTARTSYS;
> >>> +}
> >>> +
> >>
> >> I can't really judge this series. This is the only thing I stumbled
> >> upon: I see no reason to name the architecture specific kexec function
> >> 'reboot'. I would expect some kexec specific name, like arch_kexec or
> >> similar.
> >>
> > 
> > This reboot function is copy-n-paste from linux kernel reboot syscall (see linux/kernel/reboot.c
> > for details).
> > At the moment there is only one constant for reboot()'s first argument (LINUX_REBOOT_CMD_KEXEC),
> > so it's reasonable to elimenate this first argument and rename function to kexec_reboot().
> 
> amy be better to rename it to kexec_arch or kexec_mach. kexec_reboot is
> kind if misleading

Linux uses machine_kexec(struct kimage *image) in arch/mips/kernel/machine_kexec.c.

-- 
Best regards,
  Antony Pavlov

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

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

end of thread, other threads:[~2018-05-04 12:53 UTC | newest]

Thread overview: 12+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2018-04-29 13:09 [RFC PATCH 0/7] provide ELF/KEXEC support for MIPS ath79 and malta Oleksij Rempel
2018-04-29 13:09 ` [RFC PATCH 1/7] resource: add create_resource() helper function Oleksij Rempel
2018-04-29 13:09 ` [RFC PATCH 2/7] filetype: add ELF type Oleksij Rempel
2018-04-29 13:09 ` [RFC PATCH 3/7] bootm: add kexec ELF support Oleksij Rempel
2018-05-04  5:54   ` Sascha Hauer
2018-05-04 10:08     ` Antony Pavlov
2018-05-04  9:53       ` Oleksij Rempel
2018-05-04 13:09         ` Antony Pavlov
2018-04-29 13:09 ` [RFC PATCH 4/7] MIPS: add kexec ELF loading support Oleksij Rempel
2018-04-29 13:09 ` [RFC PATCH 5/7] MIPS: ath79: add kexec support Oleksij Rempel
2018-04-29 13:09 ` [RFC PATCH 6/7] MIPS: malta: enable kexec Oleksij Rempel
2018-04-29 13:09 ` [RFC PATCH 7/7] MIPS: configs: add KEXEC=y to atheros devices Oleksij Rempel

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