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