!55 arm64: fix PAGE_OFFSET calc for flipped mm

From: @chenhaixaing 
Reviewed-by: @wangbin224 
Signed-off-by: @wangbin224
This commit is contained in:
openeuler-ci-bot 2022-08-25 01:37:24 +00:00 committed by Gitee
commit cea3e3628e
No known key found for this signature in database
GPG Key ID: 173E9B9CA92EEF8F
5 changed files with 475 additions and 1 deletions

View File

@ -0,0 +1,113 @@
From bde864387a104137ff3bd5f0871709846d5c7943 Mon Sep 17 00:00:00 2001
From: Pingfan Liu <piliu@redhat.com>
Date: Tue, 18 Jan 2022 15:48:10 +0800
Subject: [PATCH] arm64/crashdump: unify routine to get page_offset
There are two funcs to get page_offset:
get_kernel_page_offset()
get_page_offset()
Since get_kernel_page_offset() does not observe the kernel formula, and
remove it. Unify them in order to introduce 52-bits VA kernel more
easily in the coming patch.
Signed-off-by: Pingfan Liu <piliu@redhat.com>
Reviewed-by: Philipp Rudo <prudo@redhat.com>
Signed-off-by: Simon Horman <horms@verge.net.au>
Conflict:NA
Reference:https://git.kernel.org/pub/scm/utils/kernel/kexec/kexec-tools.git/commit/?id=bde864387a104137ff3bd5f0871709846d5c7943
---
kexec/arch/arm64/crashdump-arm64.c | 23 +----------------------
kexec/arch/arm64/kexec-arm64.c | 8 ++++----
kexec/arch/arm64/kexec-arm64.h | 1 +
3 files changed, 6 insertions(+), 26 deletions(-)
diff --git a/kexec/arch/arm64/crashdump-arm64.c b/kexec/arch/arm64/crashdump-arm64.c
index d0f2253..7beb1fb 100644
--- a/kexec/arch/arm64/crashdump-arm64.c
+++ b/kexec/arch/arm64/crashdump-arm64.c
@@ -46,27 +46,6 @@ static struct crash_elf_info elf_info = {
.machine = EM_AARCH64,
};
-/*
- * Note: The returned value is correct only if !CONFIG_RANDOMIZE_BASE.
- */
-static uint64_t get_kernel_page_offset(void)
-{
- int i;
-
- if (elf_info.kern_vaddr_start == UINT64_MAX)
- return UINT64_MAX;
-
- /* Current max virtual memory range is 48-bits. */
- for (i = 48; i > 0; i--)
- if (!(elf_info.kern_vaddr_start & (1UL << i)))
- break;
-
- if (i <= 0)
- return UINT64_MAX;
- else
- return UINT64_MAX << i;
-}
-
/*
* iomem_range_callback() - callback called for each iomem region
* @data: not used
@@ -203,7 +182,7 @@ int load_crashdump_segments(struct kexec_info *info)
if (err)
return EFAILED;
- elf_info.page_offset = get_kernel_page_offset();
+ get_page_offset(&elf_info.page_offset);
dbgprintf("%s: page_offset: %016llx\n", __func__,
elf_info.page_offset);
diff --git a/kexec/arch/arm64/kexec-arm64.c b/kexec/arch/arm64/kexec-arm64.c
index 9dc1d8f..0f8a768 100644
--- a/kexec/arch/arm64/kexec-arm64.c
+++ b/kexec/arch/arm64/kexec-arm64.c
@@ -928,7 +928,7 @@ static int get_va_bits(void)
* get_page_offset - Helper for getting PAGE_OFFSET
*/
-static int get_page_offset(void)
+int get_page_offset(unsigned long *page_offset)
{
int ret;
@@ -936,8 +936,8 @@ static int get_page_offset(void)
if (ret < 0)
return ret;
- page_offset = (0xffffffffffffffffUL) << (va_bits - 1);
- dbgprintf("page_offset : %lx\n", page_offset);
+ *page_offset = UINT64_MAX << (va_bits - 1);
+ dbgprintf("page_offset : %lx\n", *page_offset);
return 0;
}
@@ -973,7 +973,7 @@ int get_phys_base_from_pt_load(long *phys_offset)
unsigned long long phys_start;
unsigned long long virt_start;
- ret = get_page_offset();
+ ret = get_page_offset(&page_offset);
if (ret < 0)
return ret;
diff --git a/kexec/arch/arm64/kexec-arm64.h b/kexec/arch/arm64/kexec-arm64.h
index bfd4172..5eb9fc0 100644
--- a/kexec/arch/arm64/kexec-arm64.h
+++ b/kexec/arch/arm64/kexec-arm64.h
@@ -69,6 +69,7 @@ extern struct arm64_mem arm64_mem;
uint64_t get_phys_offset(void);
uint64_t get_vp_offset(void);
+int get_page_offset(unsigned long *offset);
static inline void reset_vp_offset(void)
{
--
2.33.0

View File

@ -0,0 +1,89 @@
From 95de9eccf413ece6a86ff6b5a8e47f9b16b64454 Mon Sep 17 00:00:00 2001
From: Kairui Song <kasong@tencent.com>
Date: Tue, 18 Jan 2022 15:48:12 +0800
Subject: [PATCH] arm64: fix PAGE_OFFSET calc for flipped mm
Since kernel commit 14c127c957c1 ('arm64: mm: Flip kernel VA space'),
the memory layout on arm64 have changed, and kexec-tools can no longer
get the the right PAGE_OFFSET based on _text symbol.
Prior to that, the kimage (_text) lays above PAGE_END with this layout:
0 -> VA_START : Usespace
VA_START -> VA_START + 256M : BPF JIT, Modules
VA_START + 256M -> PAGE_OFFSET - (~GB misc) : Vmalloc (KERNEL _text HERE)
PAGE_OFFSET -> ... : * Linear map *
And here we have:
VA_START = -1UL << VA_BITS
PAGE_OFFSET = -1UL << (VA_BITS - 1)
_text < -1UL << (VA_BITS - 1)
Kernel image lays somewhere between VA_START and PAGE_OFFSET, so we just
calc VA_BITS by getting the highest unset bit of _text symbol address,
and shift one less bit of VA_BITS to get page offset. This works as long
as KASLR don't put kernel in a too high location (which is commented inline).
And after that commit, kernel layout have changed:
0 -> PAGE_OFFSET : Userspace
PAGE_OFFSET -> PAGE_END : * Linear map *
PAGE_END -> PAGE_END + 128M : bpf jit region
PAGE_END + 128M -> PAGE_END + 256MB : modules
PAGE_END + 256M -> ... : vmalloc (KERNEL _text HERE)
Here we have:
PAGE_OFFSET = -1UL << VA_BITS
PAGE_END = -1UL << (VA_BITS - 1)
_text > -1UL << (VA_BITS - 1)
Kernel image now lays above PAGE_END, so we have to shift one more bit to
get the VA_BITS, and shift the exact VA_BITS for PAGE_OFFSET.
We can simply check if "_text > -1UL << (VA_BITS - 1)" is true to judge
which layout is being used and shift the page offset occordingly.
Signed-off-by: Kairui Song <kasong@tencent.com>
(rebased and stripped by Pingfan )
Signed-off-by: Pingfan Liu <piliu@redhat.com>
Reviewed-by: Philipp Rudo <prudo@redhat.com>
Signed-off-by: Simon Horman <horms@verge.net.au>
Conflict:NA
Reference:https://git.kernel.org/pub/scm/utils/kernel/kexec/kexec-tools.git/commit/?id=95de9eccf413ece6a86ff6b5a8e47f9b16b64454
---
kexec/arch/arm64/kexec-arm64.c | 14 +++++++++++++-
1 file changed, 13 insertions(+), 1 deletion(-)
diff --git a/kexec/arch/arm64/kexec-arm64.c b/kexec/arch/arm64/kexec-arm64.c
index e502be0..9dd072c 100644
--- a/kexec/arch/arm64/kexec-arm64.c
+++ b/kexec/arch/arm64/kexec-arm64.c
@@ -942,13 +942,25 @@ out:
int get_page_offset(unsigned long *page_offset)
{
+ unsigned long long text_sym_addr, kernel_va_mid;
int ret;
+ text_sym_addr = get_kernel_sym("_text");
+ if (text_sym_addr == 0) {
+ fprintf(stderr, "Can't get the symbol of _text to calculate page_offset.\n");
+ return -1;
+ }
+
ret = get_va_bits();
if (ret < 0)
return ret;
- if (va_bits < 52)
+ /* Since kernel 5.4, kernel image is put above
+ * UINT64_MAX << (va_bits - 1)
+ */
+ kernel_va_mid = UINT64_MAX << (va_bits - 1);
+ /* older kernel */
+ if (text_sym_addr < kernel_va_mid)
*page_offset = UINT64_MAX << (va_bits - 1);
else
*page_offset = UINT64_MAX << va_bits;
--
2.33.0

View File

@ -0,0 +1,124 @@
From 67ea2d99e1356352034dc9d9c7b5ec6dd6b722eb Mon Sep 17 00:00:00 2001
From: Pingfan Liu <piliu@redhat.com>
Date: Tue, 18 Jan 2022 15:48:09 +0800
Subject: [PATCH] arm64: make phys_offset signed
After kernel commit 7bc1a0f9e176 ("arm64: mm: use single quantity to
represent the PA to VA translation"), phys_offset can be negative if
running 52-bits kernel on 48-bits hardware.
So changing phys_offset from unsigned to signed.
Signed-off-by: Pingfan Liu <piliu@redhat.com>
Reviewed-by: Philipp Rudo <prudo@redhat.com>
Signed-off-by: Simon Horman <horms@verge.net.au>
Conflict:NA
Reference:https://git.kernel.org/pub/scm/utils/kernel/kexec/kexec-tools.git/commit/?id=67ea2d99e1356352034dc9d9c7b5ec6dd6b722eb
---
kexec/arch/arm64/kexec-arm64.c | 12 ++++++------
kexec/arch/arm64/kexec-arm64.h | 2 +-
util_lib/elf_info.c | 2 +-
util_lib/include/elf_info.h | 2 +-
4 files changed, 9 insertions(+), 9 deletions(-)
diff --git a/kexec/arch/arm64/kexec-arm64.c b/kexec/arch/arm64/kexec-arm64.c
index 44ca3db..9dc1d8f 100644
--- a/kexec/arch/arm64/kexec-arm64.c
+++ b/kexec/arch/arm64/kexec-arm64.c
@@ -878,7 +878,7 @@ void add_segment(struct kexec_info *info, const void *buf, size_t bufsz,
add_segment_phys_virt(info, buf, bufsz, base, memsz, 1);
}
-static inline void set_phys_offset(uint64_t v, char *set_method)
+static inline void set_phys_offset(int64_t v, char *set_method)
{
if (arm64_mem.phys_offset == arm64_mem_ngv
|| v < arm64_mem.phys_offset) {
@@ -947,7 +947,7 @@ static int get_page_offset(void)
* from VMCOREINFO note inside 'kcore'.
*/
-static int get_phys_offset_from_vmcoreinfo_pt_note(unsigned long *phys_offset)
+static int get_phys_offset_from_vmcoreinfo_pt_note(long *phys_offset)
{
int fd, ret = 0;
@@ -967,7 +967,7 @@ static int get_phys_offset_from_vmcoreinfo_pt_note(unsigned long *phys_offset)
* from PT_LOADs inside 'kcore'.
*/
-int get_phys_base_from_pt_load(unsigned long *phys_offset)
+int get_phys_base_from_pt_load(long *phys_offset)
{
int i, fd, ret;
unsigned long long phys_start;
@@ -1025,7 +1025,7 @@ static bool to_be_excluded(char *str, unsigned long long start, unsigned long lo
int get_memory_ranges(struct memory_range **range, int *ranges,
unsigned long kexec_flags)
{
- unsigned long phys_offset = UINT64_MAX;
+ long phys_offset = -1;
FILE *fp;
const char *iomem = proc_iomem();
char line[MAX_LINE], *str;
@@ -1047,7 +1047,7 @@ int get_memory_ranges(struct memory_range **range, int *ranges,
*/
ret = get_phys_offset_from_vmcoreinfo_pt_note(&phys_offset);
if (!ret) {
- if (phys_offset != UINT64_MAX)
+ if (phys_offset != -1)
set_phys_offset(phys_offset,
"vmcoreinfo pt_note");
} else {
@@ -1059,7 +1059,7 @@ int get_memory_ranges(struct memory_range **range, int *ranges,
*/
ret = get_phys_base_from_pt_load(&phys_offset);
if (!ret)
- if (phys_offset != UINT64_MAX)
+ if (phys_offset != -1)
set_phys_offset(phys_offset,
"pt_load");
}
diff --git a/kexec/arch/arm64/kexec-arm64.h b/kexec/arch/arm64/kexec-arm64.h
index ed447ac..bfd4172 100644
--- a/kexec/arch/arm64/kexec-arm64.h
+++ b/kexec/arch/arm64/kexec-arm64.h
@@ -58,7 +58,7 @@ extern off_t initrd_size;
*/
struct arm64_mem {
- uint64_t phys_offset;
+ int64_t phys_offset;
uint64_t text_offset;
uint64_t image_size;
uint64_t vp_offset;
diff --git a/util_lib/elf_info.c b/util_lib/elf_info.c
index 51d8b92..5574c7f 100644
--- a/util_lib/elf_info.c
+++ b/util_lib/elf_info.c
@@ -1236,7 +1236,7 @@ int read_elf(int fd)
return 0;
}
-int read_phys_offset_elf_kcore(int fd, unsigned long *phys_off)
+int read_phys_offset_elf_kcore(int fd, long *phys_off)
{
int ret;
diff --git a/util_lib/include/elf_info.h b/util_lib/include/elf_info.h
index 4bc9279..f550d86 100644
--- a/util_lib/include/elf_info.h
+++ b/util_lib/include/elf_info.h
@@ -28,7 +28,7 @@ int get_pt_load(int idx,
unsigned long long *phys_end,
unsigned long long *virt_start,
unsigned long long *virt_end);
-int read_phys_offset_elf_kcore(int fd, unsigned long *phys_off);
+int read_phys_offset_elf_kcore(int fd, long *phys_off);
int read_elf(int fd);
void dump_dmesg(int fd, void (*handler)(char*, unsigned int));
--
2.33.0

View File

@ -0,0 +1,137 @@
From 454395e18ff12d2728ee458695160e9ab4899e33 Mon Sep 17 00:00:00 2001
From: Pingfan Liu <piliu@redhat.com>
Date: Tue, 18 Jan 2022 15:48:11 +0800
Subject: [PATCH] arm64: read VA_BITS from kcore for 52-bits VA kernel
phys_to_virt() calculates virtual address. As a important factor,
page_offset is excepted to be accurate.
Since arm64 kernel exposes va_bits through vmcore, using it.
Signed-off-by: Pingfan Liu <piliu@redhat.com>
Reviewed-by: Philipp Rudo <prudo@redhat.com>
Signed-off-by: Simon Horman <horms@verge.net.au>
Conflict:NA
Reference:https://git.kernel.org/pub/scm/utils/kernel/kexec/kexec-tools.git/commit/?id=454395e18ff12d2728ee458695160e9ab4899e33
---
kexec/arch/arm64/kexec-arm64.c | 34 ++++++++++++++++++++++++++++++----
util_lib/elf_info.c | 5 +++++
util_lib/include/elf_info.h | 1 +
3 files changed, 36 insertions(+), 4 deletions(-)
diff --git a/kexec/arch/arm64/kexec-arm64.c b/kexec/arch/arm64/kexec-arm64.c
index 0f8a768..e502be0 100644
--- a/kexec/arch/arm64/kexec-arm64.c
+++ b/kexec/arch/arm64/kexec-arm64.c
@@ -54,7 +54,7 @@
static bool try_read_phys_offset_from_kcore = false;
/* Machine specific details. */
-static int va_bits;
+static int va_bits = -1;
static unsigned long page_offset;
/* Global varables the core kexec routines expect. */
@@ -895,7 +895,18 @@ static inline void set_phys_offset(int64_t v, char *set_method)
static int get_va_bits(void)
{
- unsigned long long stext_sym_addr = get_kernel_sym("_stext");
+ unsigned long long stext_sym_addr;
+
+ /*
+ * if already got from kcore
+ */
+ if (va_bits != -1)
+ goto out;
+
+
+ /* For kernel older than v4.19 */
+ fprintf(stderr, "Warning, can't get the VA_BITS from kcore\n");
+ stext_sym_addr = get_kernel_sym("_stext");
if (stext_sym_addr == 0) {
fprintf(stderr, "Can't get the symbol of _stext.\n");
@@ -919,6 +930,7 @@ static int get_va_bits(void)
return -1;
}
+out:
dbgprintf("va_bits : %d\n", va_bits);
return 0;
@@ -936,14 +948,27 @@ int get_page_offset(unsigned long *page_offset)
if (ret < 0)
return ret;
- *page_offset = UINT64_MAX << (va_bits - 1);
+ if (va_bits < 52)
+ *page_offset = UINT64_MAX << (va_bits - 1);
+ else
+ *page_offset = UINT64_MAX << va_bits;
+
dbgprintf("page_offset : %lx\n", *page_offset);
return 0;
}
+static void arm64_scan_vmcoreinfo(char *pos)
+{
+ const char *str;
+
+ str = "NUMBER(VA_BITS)=";
+ if (memcmp(str, pos, strlen(str)) == 0)
+ va_bits = strtoul(pos + strlen(str), NULL, 10);
+}
+
/**
- * get_phys_offset_from_vmcoreinfo_pt_note - Helper for getting PHYS_OFFSET
+ * get_phys_offset_from_vmcoreinfo_pt_note - Helper for getting PHYS_OFFSET (and va_bits)
* from VMCOREINFO note inside 'kcore'.
*/
@@ -956,6 +981,7 @@ static int get_phys_offset_from_vmcoreinfo_pt_note(long *phys_offset)
return EFAILED;
}
+ arch_scan_vmcoreinfo = arm64_scan_vmcoreinfo;
ret = read_phys_offset_elf_kcore(fd, phys_offset);
close(fd);
diff --git a/util_lib/elf_info.c b/util_lib/elf_info.c
index 5574c7f..d252eff 100644
--- a/util_lib/elf_info.c
+++ b/util_lib/elf_info.c
@@ -310,6 +310,8 @@ int get_pt_load(int idx,
#define NOT_FOUND_LONG_VALUE (-1)
+void (*arch_scan_vmcoreinfo)(char *pos);
+
void scan_vmcoreinfo(char *start, size_t size)
{
char *last = start + size - 1;
@@ -551,6 +553,9 @@ void scan_vmcoreinfo(char *start, size_t size)
}
}
+ if (arch_scan_vmcoreinfo != NULL)
+ (*arch_scan_vmcoreinfo)(pos);
+
if (last_line)
break;
}
diff --git a/util_lib/include/elf_info.h b/util_lib/include/elf_info.h
index f550d86..fdf4c3d 100644
--- a/util_lib/include/elf_info.h
+++ b/util_lib/include/elf_info.h
@@ -31,5 +31,6 @@ int get_pt_load(int idx,
int read_phys_offset_elf_kcore(int fd, long *phys_off);
int read_elf(int fd);
void dump_dmesg(int fd, void (*handler)(char*, unsigned int));
+extern void (*arch_scan_vmcoreinfo)(char *pos);
#endif /* ELF_INFO_H */
--
2.33.0

View File

@ -4,7 +4,7 @@
Name: kexec-tools
Version: 2.0.23
Release: 7
Release: 8
License: GPLv2
Summary: The kexec/kdump userspace component
URL: https://www.kernel.org/
@ -73,6 +73,10 @@ Patch0002: add-secure-compile-options-for-makedumpfile.patch
Patch0003: kexec-Add-quick-kexec-support.patch
Patch0004: kexec-Quick-kexec-implementation-for-arm64.patch
Patch0005: arm64-crashdump-deduce-paddr-of-_text-based-on-kerne.patch
Patch0006: arm64-make-phys_offset-signed.patch
Patch0007: arm64-crashdump-unify-routine-to-get-page_offset.patch
Patch0008: arm64-read-VA_BITS-from-kcore-for-52-bits-VA-kernel.patch
Patch0009: arm64-fix-PAGE_OFFSET-calc-for-flipped-mm.patch
%description
kexec-tools provides /sbin/kexec binary that facilitates a new
@ -104,6 +108,10 @@ tar -z -x -v -f %{SOURCE19}
%patch0004 -p1
%endif
%patch0005 -p1
%patch0006 -p1
%patch0007 -p1
%patch0008 -p1
%patch0009 -p1
%build
autoreconf
@ -288,6 +296,9 @@ done
%endif
%changelog
* Wed Aug 24 2022 chenhaixiang <chenhaixiang3@huawei.com> - 2.0.23-8
- arm64: fix PAGE_OFFSET calc for flipped mm
* Tue Aug 23 2022 chenhaixiang <chenhaixiang3@huawei.com> - 2.0.23-7
- kdumpctl:ignore deprecated and invalid kdump config option