[PATCH 3/7] RISC-V: Get memory ranges from iomem

Song Shuai songshuaishuai at tinylab.org
Thu Sep 14 20:50:09 PDT 2023


When booting with UEFI, Linux marks the Runtime Code/Data memory
as no-map and then exports it to "Reserved" iomem_resource.

Kexc-tools uses dtb_get_memory_ranges() function to get memory ranges
via parsing dtb, but it can't see the Reserved EFI Runtime memory.
That would corrupt EFI Runtime memory and fail the kexeced kernel to
deal EFI stuff.

In my test, the kexeced kernel warned "efi: System table signature incorrect!"
and then paniced at efi_call_rts() due to the null efi.runtime.

So we should use /proc/iomem to get memory ranges.

Signed-off-by: Song Shuai <songshuaishuai at tinylab.org>
---
 kexec/arch/riscv/iomem.h       | 10 +++++
 kexec/arch/riscv/kexec-riscv.c | 69 +++++++++++++++++++++-------------
 2 files changed, 53 insertions(+), 26 deletions(-)
 create mode 100644 kexec/arch/riscv/iomem.h

diff --git a/kexec/arch/riscv/iomem.h b/kexec/arch/riscv/iomem.h
new file mode 100644
index 0000000..7671e26
--- /dev/null
+++ b/kexec/arch/riscv/iomem.h
@@ -0,0 +1,10 @@
+#ifndef IOMEM_H
+#define IOMEM_H
+
+#define SYSTEM_RAM		"System RAM\n"
+#define KERNEL_CODE		"Kernel code\n"
+#define KERNEL_DATA		"Kernel data\n"
+#define CRASH_KERNEL		"Crash kernel\n"
+#define IOMEM_RESERVED		"Reserved\n"
+
+#endif
diff --git a/kexec/arch/riscv/kexec-riscv.c b/kexec/arch/riscv/kexec-riscv.c
index 5aea035..a6f1b6f 100644
--- a/kexec/arch/riscv/kexec-riscv.c
+++ b/kexec/arch/riscv/kexec-riscv.c
@@ -15,6 +15,7 @@
 #include <errno.h>		/* For EINVAL */
 #include <libfdt.h>		/* For DeviceTree handling */
 #include "kexec-riscv.h"
+#include "iomem.h"
 
 const struct arch_map_entry arches[] = {
 	{ "riscv32", KEXEC_ARCH_RISCV },
@@ -37,7 +38,6 @@ static const char riscv_opts_usage[] =
 
 static struct riscv_opts arch_options = {0};
 static struct fdt_image provided_fdt = {0};
-static struct memory_ranges sysmem_ranges = {0};
 
 /****************\
 * COMMON HELPERS *
@@ -313,40 +313,57 @@ void arch_reuse_initrd(void)
 int get_memory_ranges(struct memory_range **range, int *num_ranges,
 		      unsigned long kexec_flags)
 {
-	const struct fdt_image *fdt = &provided_fdt;
-	struct memory_ranges *extra_ranges = NULL;
-	int i = 0;
+	struct memory_ranges sysmem_ranges = {0};
 	int ret = 0;
 
-	if (arch_options.initrd_start && arch_options.initrd_end) {
-		int initrd_size = arch_options.initrd_end - arch_options.initrd_start;
-		dbgprintf("Marking current intird image as reserved\n");
-		ret = mem_regions_alloc_and_add(extra_ranges,
-						arch_options.initrd_start,
-						initrd_size,
-						RANGE_RESERVED);
-		if (ret)
-			return ret;
+	const char *iomem = proc_iomem();
+	char line[MAX_LINE], *str;
+	FILE *fp;
+	unsigned long long start, end;
+	int consumed, count;
+
+	fp = fopen(iomem, "r");
+	if (!fp) {
+		fprintf(stderr, "Cannot open %s: %s\n", iomem, strerror(errno));
+		return -1;
 	}
 
-	ret = dtb_get_memory_ranges(fdt->buf, &sysmem_ranges, extra_ranges);
-	if (ret) {
-		fprintf(stderr, "Could not get memory ranges from device tree (%i) !\n", ret);
-		return ret;
+	while (fgets(line, sizeof(line), fp) != 0) {
+		count = sscanf(line, "%llx-%llx : %n", &start, &end, &consumed);
+		if (count != 2)
+			continue;
+		str = line + consumed;
+
+		if (!strncmp(str, SYSTEM_RAM, strlen(SYSTEM_RAM))){
+			ret = mem_regions_alloc_and_add(&sysmem_ranges,
+					start, end - start + 1, RANGE_RAM);
+			if (ret) {
+				fprintf(stderr,
+					"Cannot allocate memory for ranges\n");
+				fclose(fp);
+				return -ENOMEM;
+			}
+
+		} else if (!strncmp(str, IOMEM_RESERVED, strlen(IOMEM_RESERVED))){
+			ret = mem_regions_alloc_and_add(&sysmem_ranges,
+					start, end - start + 1, RANGE_RESERVED);
+			if (ret) {
+				fprintf(stderr,
+					"Cannot allocate memory for ranges\n");
+				fclose(fp);
+				return -ENOMEM;
+			}
+		} else
+			continue;
 	}
 
+	fclose(fp);
+
 	*range = sysmem_ranges.ranges;
 	*num_ranges = sysmem_ranges.size;
 
-	dbgprintf("Memory regions:\n");
-	for (i = 0; i < sysmem_ranges.size; i++) {
-		dbgprintf("\t0x%llx - 0x%llx : %s (%i)\n",
-			  sysmem_ranges.ranges[i].start,
-			  sysmem_ranges.ranges[i].end,
-			  sysmem_ranges.ranges[i].type == RANGE_RESERVED ?
-			  "RANGE_RESERVED" : "RANGE_RAM",
-			  sysmem_ranges.ranges[i].type);
-	}
+	dbgprint_mem_range("System RAM ranges;",
+				sysmem_ranges.ranges, sysmem_ranges.size);
 
 	return 0;
 }
-- 
2.20.1




More information about the kexec mailing list