Blame SOURCES/kexec-tools-2.0.20-arm64-kexec-allocate-memory-space-avoiding-reserved-.patch

f4cf83
From f736104f533290b4ce6fbfbca74abde9ffd3888c Mon Sep 17 00:00:00 2001
f4cf83
From: AKASHI Takahiro <takahiro.akashi@linaro.org>
f4cf83
Date: Wed, 18 Dec 2019 11:42:31 -0500
f4cf83
Subject: [PATCH 2/3] arm64: kexec: allocate memory space avoiding reserved
f4cf83
 regions
f4cf83
f4cf83
On UEFI/ACPI-only system, some memory regions, including but not limited
f4cf83
to UEFI memory map and ACPI tables, must be preserved across kexec'ing.
f4cf83
Otherwise, they can be corrupted and result in early failure in booting
f4cf83
a new kernel.
f4cf83
f4cf83
In recent kernels, /proc/iomem now has an extended file format like:
f4cf83
f4cf83
 40000000-5871ffff : System RAM
f4cf83
   41800000-426affff : Kernel code
f4cf83
   426b0000-42aaffff : reserved
f4cf83
   42ab0000-42c64fff : Kernel data
f4cf83
   54400000-583fffff : Crash kernel
f4cf83
   58590000-585effff : reserved
f4cf83
   58700000-5871ffff : reserved
f4cf83
 58720000-58b5ffff : reserved
f4cf83
 58b60000-5be3ffff : System RAM
f4cf83
   58b61000-58b61fff : reserved
f4cf83
f4cf83
where the "reserved" entries at the top level or under System RAM (and
f4cf83
its descendant resources) are ones of such kind and should not be regarded
f4cf83
as usable memory ranges where several free spaces for loading kexec data
f4cf83
will be allocated.
f4cf83
f4cf83
With this patch, get_memory_ranges() will handle this format of file
f4cf83
correctly. Note that, for safety, unknown regions, in addition to
f4cf83
"reserved" ones, will also be excluded.
f4cf83
f4cf83
Signed-off-by: AKASHI Takahiro <takahiro.akashi@linaro.org>
f4cf83
Tested-by: Bhupesh Sharma <bhsharma@redhat.com>
f4cf83
Tested-by: Masayoshi Mizuma <m.mizuma@jp.fujitsu.com>
f4cf83
Signed-off-by: Simon Horman <horms@verge.net.au>
f4cf83
---
f4cf83
 kexec/arch/arm64/kexec-arm64.c | 153 +++++++++++++++++++++++++----------------
f4cf83
 1 file changed, 94 insertions(+), 59 deletions(-)
f4cf83
f4cf83
diff --git a/kexec/arch/arm64/kexec-arm64.c b/kexec/arch/arm64/kexec-arm64.c
f4cf83
index 6ad3b0a134b3..45ebc54a9b6f 100644
f4cf83
--- a/kexec/arch/arm64/kexec-arm64.c
f4cf83
+++ b/kexec/arch/arm64/kexec-arm64.c
f4cf83
@@ -10,7 +10,9 @@
f4cf83
 #include <inttypes.h>
f4cf83
 #include <libfdt.h>
f4cf83
 #include <limits.h>
f4cf83
+#include <stdio.h>
f4cf83
 #include <stdlib.h>
f4cf83
+#include <string.h>
f4cf83
 #include <sys/stat.h>
f4cf83
 #include <linux/elf-em.h>
f4cf83
 #include <elf.h>
f4cf83
@@ -29,6 +31,7 @@
f4cf83
 #include "fs2dt.h"
f4cf83
 #include "iomem.h"
f4cf83
 #include "kexec-syscall.h"
f4cf83
+#include "mem_regions.h"
f4cf83
 #include "arch/options.h"
f4cf83
 
f4cf83
 #define ROOT_NODE_ADDR_CELLS_DEFAULT 1
f4cf83
@@ -905,19 +908,33 @@ int get_phys_base_from_pt_load(unsigned long *phys_offset)
f4cf83
 	return 0;
f4cf83
 }
f4cf83
 
f4cf83
+static bool to_be_excluded(char *str)
f4cf83
+{
f4cf83
+	if (!strncmp(str, SYSTEM_RAM, strlen(SYSTEM_RAM)) ||
f4cf83
+	    !strncmp(str, KERNEL_CODE, strlen(KERNEL_CODE)) ||
f4cf83
+	    !strncmp(str, KERNEL_DATA, strlen(KERNEL_DATA)) ||
f4cf83
+	    !strncmp(str, CRASH_KERNEL, strlen(CRASH_KERNEL)))
f4cf83
+		return false;
f4cf83
+	else
f4cf83
+		return true;
f4cf83
+}
f4cf83
+
f4cf83
 /**
f4cf83
- * get_memory_ranges_iomem_cb - Helper for get_memory_ranges_iomem.
f4cf83
+ * get_memory_ranges - Try to get the memory ranges from
f4cf83
+ * /proc/iomem.
f4cf83
  */
f4cf83
-
f4cf83
-static int get_memory_ranges_iomem_cb(void *data, int nr, char *str,
f4cf83
-	unsigned long long base, unsigned long long length)
f4cf83
+int get_memory_ranges(struct memory_range **range, int *ranges,
f4cf83
+	unsigned long kexec_flags)
f4cf83
 {
f4cf83
-	int ret;
f4cf83
 	unsigned long phys_offset = UINT64_MAX;
f4cf83
-	struct memory_range *r;
f4cf83
-
f4cf83
-	if (nr >= KEXEC_SEGMENT_MAX)
f4cf83
-		return -1;
f4cf83
+	FILE *fp;
f4cf83
+	const char *iomem = proc_iomem();
f4cf83
+	char line[MAX_LINE], *str;
f4cf83
+	unsigned long long start, end;
f4cf83
+	int n, consumed;
f4cf83
+	struct memory_ranges memranges;
f4cf83
+	struct memory_range *last, excl_range;
f4cf83
+	int ret;
f4cf83
 
f4cf83
 	if (!try_read_phys_offset_from_kcore) {
f4cf83
 		/* Since kernel version 4.19, 'kcore' contains
f4cf83
@@ -951,17 +968,72 @@ static int get_memory_ranges_iomem_cb(void *data, int nr, char *str,
f4cf83
 		try_read_phys_offset_from_kcore = true;
f4cf83
 	}
f4cf83
 
f4cf83
-	r = (struct memory_range *)data + nr;
f4cf83
+	fp = fopen(iomem, "r");
f4cf83
+	if (!fp)
f4cf83
+		die("Cannot open %s\n", iomem);
f4cf83
+
f4cf83
+	memranges.ranges = NULL;
f4cf83
+	memranges.size = memranges.max_size  = 0;
f4cf83
+
f4cf83
+	while (fgets(line, sizeof(line), fp) != 0) {
f4cf83
+		n = sscanf(line, "%llx-%llx : %n", &start, &end, &consumed);
f4cf83
+		if (n != 2)
f4cf83
+			continue;
f4cf83
+		str = line + consumed;
f4cf83
+
f4cf83
+		if (!strncmp(str, SYSTEM_RAM, strlen(SYSTEM_RAM))) {
f4cf83
+			ret = mem_regions_alloc_and_add(&memranges,
f4cf83
+					start, end - start + 1, RANGE_RAM);
f4cf83
+			if (ret) {
f4cf83
+				fprintf(stderr,
f4cf83
+					"Cannot allocate memory for ranges\n");
f4cf83
+				fclose(fp);
f4cf83
+				return -ENOMEM;
f4cf83
+			}
f4cf83
 
f4cf83
-	if (!strncmp(str, SYSTEM_RAM, strlen(SYSTEM_RAM)))
f4cf83
-		r->type = RANGE_RAM;
f4cf83
-	else if (!strncmp(str, IOMEM_RESERVED, strlen(IOMEM_RESERVED)))
f4cf83
-		r->type = RANGE_RESERVED;
f4cf83
-	else
f4cf83
-		return 1;
f4cf83
+			dbgprintf("%s:+[%d] %016llx - %016llx\n", __func__,
f4cf83
+				memranges.size - 1,
f4cf83
+				memranges.ranges[memranges.size - 1].start,
f4cf83
+				memranges.ranges[memranges.size - 1].end);
f4cf83
+		} else if (to_be_excluded(str)) {
f4cf83
+			if (!memranges.size)
f4cf83
+				continue;
f4cf83
+
f4cf83
+			/*
f4cf83
+			 * Note: mem_regions_exclude() doesn't guarantee
f4cf83
+			 * that the ranges are sorted out, but as long as
f4cf83
+			 * we cope with /proc/iomem, we only operate on
f4cf83
+			 * the last entry and so it is safe.
f4cf83
+			 */
f4cf83
 
f4cf83
-	r->start = base;
f4cf83
-	r->end = base + length - 1;
f4cf83
+			/* The last System RAM range */
f4cf83
+			last = &memranges.ranges[memranges.size - 1];
f4cf83
+
f4cf83
+			if (last->end < start)
f4cf83
+				/* New resource outside of System RAM */
f4cf83
+				continue;
f4cf83
+			if (end < last->start)
f4cf83
+				/* Already excluded by parent resource */
f4cf83
+				continue;
f4cf83
+
f4cf83
+			excl_range.start = start;
f4cf83
+			excl_range.end = end;
f4cf83
+			ret = mem_regions_alloc_and_exclude(&memranges, &excl_range);
f4cf83
+			if (ret) {
f4cf83
+				fprintf(stderr,
f4cf83
+					"Cannot allocate memory for ranges (exclude)\n");
f4cf83
+				fclose(fp);
f4cf83
+				return -ENOMEM;
f4cf83
+			}
f4cf83
+			dbgprintf("%s:-      %016llx - %016llx\n",
f4cf83
+					__func__, start, end);
f4cf83
+		}
f4cf83
+	}
f4cf83
+
f4cf83
+	fclose(fp);
f4cf83
+
f4cf83
+	*range = memranges.ranges;
f4cf83
+	*ranges = memranges.size;
f4cf83
 
f4cf83
 	/* As a fallback option, we can try determining the PHYS_OFFSET
f4cf83
 	 * value from the '/proc/iomem' entries as well.
f4cf83
@@ -982,52 +1054,15 @@ static int get_memory_ranges_iomem_cb(void *data, int nr, char *str,
f4cf83
 	 * between the user-space and kernel space 'PHYS_OFFSET'
f4cf83
 	 * value.
f4cf83
 	 */
f4cf83
-	set_phys_offset(r->start, "iomem");
f4cf83
-
f4cf83
-	dbgprintf("%s: %016llx - %016llx : %s", __func__, r->start,
f4cf83
-		r->end, str);
f4cf83
-
f4cf83
-	return 0;
f4cf83
-}
f4cf83
-
f4cf83
-/**
f4cf83
- * get_memory_ranges_iomem - Try to get the memory ranges from
f4cf83
- * /proc/iomem.
f4cf83
- */
f4cf83
+	if (memranges.size)
f4cf83
+		set_phys_offset(memranges.ranges[0].start, "iomem");
f4cf83
 
f4cf83
-static int get_memory_ranges_iomem(struct memory_range *array,
f4cf83
-	unsigned int *count)
f4cf83
-{
f4cf83
-	*count = kexec_iomem_for_each_line(NULL,
f4cf83
-		get_memory_ranges_iomem_cb, array);
f4cf83
-
f4cf83
-	if (!*count) {
f4cf83
-		dbgprintf("%s: failed: No RAM found.\n", __func__);
f4cf83
-		return EFAILED;
f4cf83
-	}
f4cf83
+	dbgprint_mem_range("System RAM ranges;",
f4cf83
+				memranges.ranges, memranges.size);
f4cf83
 
f4cf83
 	return 0;
f4cf83
 }
f4cf83
 
f4cf83
-/**
f4cf83
- * get_memory_ranges - Try to get the memory ranges some how.
f4cf83
- */
f4cf83
-
f4cf83
-int get_memory_ranges(struct memory_range **range, int *ranges,
f4cf83
-	unsigned long kexec_flags)
f4cf83
-{
f4cf83
-	static struct memory_range array[KEXEC_SEGMENT_MAX];
f4cf83
-	unsigned int count;
f4cf83
-	int result;
f4cf83
-
f4cf83
-	result = get_memory_ranges_iomem(array, &count);
f4cf83
-
f4cf83
-	*range = result ? NULL : array;
f4cf83
-	*ranges = result ? 0 : count;
f4cf83
-
f4cf83
-	return result;
f4cf83
-}
f4cf83
-
f4cf83
 int arch_compat_trampoline(struct kexec_info *info)
f4cf83
 {
f4cf83
 	return 0;
f4cf83
-- 
f4cf83
2.7.4
f4cf83