From 4d08e9803fe68d2b1f26e310fd7aa479affddc48 Mon Sep 17 00:00:00 2001
From: Julian Winkler <julian.winkler1@web.de>
Date: Sat, 18 Feb 2023 21:48:51 +0100
Subject: [PATCH] add devicetree support on x86

Since linux kernel has dropped support for simple firmware interface
(SFI), the only way of boot newer versions on intel MID platform is
using devicetree
---
 kexec/arch/i386/include/arch/options.h |  4 +++-
 kexec/arch/i386/kexec-beoboot-x86.c    |  2 +-
 kexec/arch/i386/kexec-bzImage.c        | 21 ++++++++++++++++++++-
 kexec/arch/i386/kexec-x86.h            |  1 +
 kexec/arch/i386/x86-linux-setup.c      | 15 +++++++++++++++
 kexec/arch/i386/x86-linux-setup.h      |  2 ++
 kexec/arch/x86_64/kexec-bzImage64.c    |  2 +-
 7 files changed, 43 insertions(+), 4 deletions(-)

diff --git a/kexec/arch/i386/include/arch/options.h b/kexec/arch/i386/include/arch/options.h
index 0e57951..89e0a95 100644
--- a/kexec/arch/i386/include/arch/options.h
+++ b/kexec/arch/i386/include/arch/options.h
@@ -33,6 +33,7 @@
 #define OPT_PASS_MEMMAP_CMDLINE	(OPT_ARCH_MAX+11)
 #define OPT_NOEFI		(OPT_ARCH_MAX+12)
 #define OPT_REUSE_VIDEO_TYPE	(OPT_ARCH_MAX+13)
+#define OPT_DTB			(OPT_ARCH_MAX+14)
 
 /* Options relevant to the architecture (excluding loader-specific ones): */
 #define KEXEC_ARCH_OPTIONS \
@@ -76,7 +77,8 @@
 	{ "args-none",		0, NULL, OPT_ARGS_NONE },	\
 	{ "module",		1, 0, OPT_MOD },		\
 	{ "real-mode",		0, NULL, OPT_REAL_MODE },	\
-	{ "entry-32bit",	0, NULL, OPT_ENTRY_32BIT },
+	{ "entry-32bit",	0, NULL, OPT_ENTRY_32BIT },	\
+	{ "dtb",		1, NULL, OPT_DTB },
 
 #define KEXEC_ALL_OPT_STR KEXEC_ARCH_OPT_STR
 
diff --git a/kexec/arch/i386/kexec-beoboot-x86.c b/kexec/arch/i386/kexec-beoboot-x86.c
index b121834..d949ab8 100644
--- a/kexec/arch/i386/kexec-beoboot-x86.c
+++ b/kexec/arch/i386/kexec-beoboot-x86.c
@@ -125,7 +125,7 @@ int beoboot_load(int argc, char **argv, const char *buf, off_t UNUSED(len),
 		kernel,        bb_header.kernel_size,
 		command_line,  bb_header.cmdline_size,
 		initrd,        bb_header.initrd_size,
-		real_mode_entry);
+		0, 0, real_mode_entry);
 
 	return result;
 }
diff --git a/kexec/arch/i386/kexec-bzImage.c b/kexec/arch/i386/kexec-bzImage.c
index df8985d..1b8f20c 100644
--- a/kexec/arch/i386/kexec-bzImage.c
+++ b/kexec/arch/i386/kexec-bzImage.c
@@ -95,6 +95,7 @@ void bzImage_usage(void)
 		"    --reuse-cmdline       Use kernel command line from running system.\n"
 		"    --initrd=FILE         Use FILE as the kernel's initial ramdisk.\n"
 		"    --ramdisk=FILE        Use FILE as the kernel's initial ramdisk.\n"
+		"    --dtb=FILE            Use FILE as devicetree.\n"
 		);
        
 }
@@ -103,6 +104,7 @@ int do_bzImage_load(struct kexec_info *info,
 	const char *kernel, off_t kernel_len,
 	const char *command_line, off_t command_line_len,
 	const char *initrd, off_t initrd_len,
+	const char *dtb, off_t dtb_len,
 	int real_mode_entry)
 {
 	struct x86_linux_header setup_header;
@@ -373,6 +375,10 @@ int do_bzImage_load(struct kexec_info *info,
 		setup_linux_system_parameters(info, real_mode);
 	}
 
+	if (dtb) {
+		setup_linux_dtb(info, real_mode, dtb, dtb_len);
+	}
+
 	return 0;
 }
 	
@@ -381,13 +387,15 @@ int bzImage_load(int argc, char **argv, const char *buf, off_t len,
 {
 	char *command_line = NULL;
 	char *tmp_cmdline = NULL;
-	const char *ramdisk, *append = NULL;
+	const char *ramdisk, *append = NULL, *dtb;
 	char *ramdisk_buf;
 	off_t ramdisk_length;
 	int command_line_len;
 	int real_mode_entry;
 	int opt;
 	int result;
+	char *dtb_buf;
+	off_t dtb_length;
 
 	/* See options.h -- add any more there, too. */
 	static const struct option options[] = {
@@ -398,6 +406,7 @@ int bzImage_load(int argc, char **argv, const char *buf, off_t len,
 		{ "initrd",		1, 0, OPT_RAMDISK },
 		{ "ramdisk",		1, 0, OPT_RAMDISK },
 		{ "real-mode",		0, 0, OPT_REAL_MODE },
+		{ "dtb",		1, 0, OPT_DTB },
 		{ 0, 			0, 0, 0 },
 	};
 	static const char short_options[] = KEXEC_ARCH_OPT_STR "d";
@@ -405,6 +414,8 @@ int bzImage_load(int argc, char **argv, const char *buf, off_t len,
 	real_mode_entry = 0;
 	ramdisk = 0;
 	ramdisk_length = 0;
+	dtb = 0;
+	dtb_length = 0;
 	while((opt = getopt_long(argc, argv, short_options, options, 0)) != -1) {
 		switch(opt) {
 		default:
@@ -424,6 +435,9 @@ int bzImage_load(int argc, char **argv, const char *buf, off_t len,
 		case OPT_REAL_MODE:
 			real_mode_entry = 1;
 			break;
+		case OPT_DTB:
+			dtb = optarg;
+			break;
 		}
 	}
 	command_line = concat_cmdline(tmp_cmdline, append);
@@ -441,10 +455,15 @@ int bzImage_load(int argc, char **argv, const char *buf, off_t len,
 	if (ramdisk) {
 		ramdisk_buf = slurp_file(ramdisk, &ramdisk_length);
 	}
+	dtb_buf = 0;
+	if (dtb) {
+		dtb_buf = slurp_file(dtb, &dtb_length);
+	}
 	result = do_bzImage_load(info,
 		buf, len,
 		command_line, command_line_len,
 		ramdisk_buf, ramdisk_length,
+		dtb_buf, dtb_length,
 		real_mode_entry);
 
 	free(command_line);
diff --git a/kexec/arch/i386/kexec-x86.h b/kexec/arch/i386/kexec-x86.h
index 71e4329..46e2898 100644
--- a/kexec/arch/i386/kexec-x86.h
+++ b/kexec/arch/i386/kexec-x86.h
@@ -79,6 +79,7 @@ int do_bzImage_load(struct kexec_info *info,
 	const char *kernel, off_t kernel_len,
 	const char *command_line, off_t command_line_len,
 	const char *initrd, off_t initrd_len,
+	const char *dtb, off_t dtb_len,
 	int real_mode_entry);
 
 int beoboot_probe(const char *buf, off_t len);
diff --git a/kexec/arch/i386/x86-linux-setup.c b/kexec/arch/i386/x86-linux-setup.c
index 14263b0..9a281dc 100644
--- a/kexec/arch/i386/x86-linux-setup.c
+++ b/kexec/arch/i386/x86-linux-setup.c
@@ -954,3 +954,18 @@ void setup_linux_system_parameters(struct kexec_info *info,
 	/* Always try to fill acpi_rsdp_addr */
 	real_mode->acpi_rsdp_addr = get_acpi_rsdp();
 }
+
+void setup_linux_dtb(struct kexec_info *info, struct x86_linux_param_header *real_mode,
+				   const char *dtb_buf, int dtb_len)
+{
+	struct setup_data *sd;
+
+	sd = xmalloc(sizeof(struct setup_data) + dtb_len);
+	sd->next = 0;
+	sd->len = dtb_len;
+	sd->type = SETUP_DTB;
+	memcpy(sd->data, dtb_buf, dtb_len);
+
+
+	add_setup_data(info, real_mode, sd);
+}
diff --git a/kexec/arch/i386/x86-linux-setup.h b/kexec/arch/i386/x86-linux-setup.h
index 0c651e5..b5e1ad5 100644
--- a/kexec/arch/i386/x86-linux-setup.h
+++ b/kexec/arch/i386/x86-linux-setup.h
@@ -21,6 +21,8 @@ static inline void setup_linux_bootloader_parameters(
 }
 void setup_linux_system_parameters(struct kexec_info *info,
 	struct x86_linux_param_header *real_mode);
+void setup_linux_dtb(struct kexec_info *info, struct x86_linux_param_header *real_mode,
+				   const char *dtb_buf, int dtb_len);
 int get_bootparam(void *buf, off_t offset, size_t size);
 
 
diff --git a/kexec/arch/x86_64/kexec-bzImage64.c b/kexec/arch/x86_64/kexec-bzImage64.c
index ba8dc48..aba4e3b 100644
--- a/kexec/arch/x86_64/kexec-bzImage64.c
+++ b/kexec/arch/x86_64/kexec-bzImage64.c
@@ -386,7 +386,7 @@ int bzImage64_load(int argc, char **argv, const char *buf, off_t len,
 	if (entry_16bit || entry_32bit)
 		result = do_bzImage_load(info, buf, len, command_line,
 					command_line_len, ramdisk_buf,
-					ramdisk_length, entry_16bit);
+					ramdisk_length, 0, 0, entry_16bit);
 	else
 		result = do_bzImage64_load(info, buf, len, command_line,
 					command_line_len, ramdisk_buf,
-- 
2.39.1

