在 2021年04月07日 17:16, Pingfan Liu 写道:
Crash encounters a bug like the following:
...
License GPLv3+: GNU GPL version 3 or later <
http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law. Type "show copying"
and "show warranty" for details.
This GDB was configured as "aarch64-unknown-linux-gnu"...
crash: read error: kernel virtual address: ffff000f789c0050 type: "IRQ stack
pointer"
crash: read error: kernel virtual address: ffff000f78a60050 type: "IRQ stack
pointer"
crash: read error: kernel virtual address: ffff000f78b00050 type: "IRQ stack
pointer"
...
This bug connects with kernel commit 7bc1a0f9e176 ("arm64: mm: use
single quantity to represent the PA to VA translation"), memstart_addr
can be negative, which makes it different from real phys_offset.
In crash utility, PTOV() needs memstart_addr to calculate VA from PA,
while getting PFN offset in a dumpfile, phys_offset is required.
To serve the different purpose, using phys_offset_nominal and
phys_offset to store them.
Signed-off-by: Pingfan Liu <piliu(a)redhat.com>
Cc: HAGIO KAZUHITO <k-hagio-ab(a)nec.com>
Cc: Lianbo Jiang <lijiang(a)redhat.com>
Cc: Bhupesh Sharma <bhupesh.sharma(a)linaro.org>
Cc: Mark Salter <msalter(a)redhat.com>
Cc: Mark Langsdorf <mlangsdo(a)redhat.com>
Cc: Jeremy Linton <jlinton(a)redhat.com>
To: crash-utility(a)redhat.com
---
v2 -> v3:
rename ms->memstart_addr as ms->phys_offset_nominal ( I keep the name
as phys_offset* since it is in accordance with other platform
conventions)
---
arm64.c | 25 ++++++++++++++++++++++---
defs.h | 3 +++
2 files changed, 25 insertions(+), 3 deletions(-)
diff --git a/arm64.c b/arm64.c
index 37aed07..5e567ca 100644
--- a/arm64.c
+++ b/arm64.c
@@ -24,6 +24,9 @@
#define NOT_IMPLEMENTED(X) error((X), "%s: function not implemented\n",
__func__)
+#define MEMSTART_ADDR_OFFSET \
+ (0xffffffffffffffff << 48 - 0xffffffffffffffff << 56)
+
Since the micro 'MEMSTART_ADDR_OFFSET' is only used in the
arm64_calc_phys_offset(),
can we define the micro in the arm64_calc_phys_offset() as below and easily use it
in this function?
static void
arm64_calc_phys_offset(void)
{
+ /*
+ * sources: arch/arm64/include/asm/memory.h
+ */
+ #define _PAGE_OFFSET(va) (-(UL(1) << (va)))
......
+ ms->phys_offset = ms->phys_offset_nominal + (_PAGE_OFFSET(48) -
_PAGE_OFFSET(56));
......
}
Thanks.
Lianbo
static struct machine_specific arm64_machine_specific = { 0 };
static int arm64_verify_symbol(const char *, ulong, char);
static void arm64_parse_cmdline_args(void);
@@ -687,6 +690,7 @@ arm64_dump_machdep_table(ulong arg)
fprintf(fp, " kimage_voffset: %016lx\n", ms->kimage_voffset);
}
fprintf(fp, " phys_offset: %lx\n", ms->phys_offset);
+ fprintf(fp, " phys_offset_nominal: %lx\n", ms->phys_offset_nominal);
fprintf(fp, "__exception_text_start: %lx\n", ms->__exception_text_start);
fprintf(fp, " __exception_text_end: %lx\n", ms->__exception_text_end);
fprintf(fp, " __irqentry_text_start: %lx\n", ms->__irqentry_text_start);
@@ -987,7 +991,7 @@ arm64_calc_physvirt_offset(void)
ulong physvirt_offset;
struct syment *sp;
- ms->physvirt_offset = ms->phys_offset - ms->page_offset;
+ ms->physvirt_offset = ms->phys_offset_nominal - ms->page_offset;
if ((sp = kernel_symbol_search("physvirt_offset")) &&
machdep->machspec->kimage_voffset) {
@@ -1028,7 +1032,11 @@ arm64_calc_phys_offset(void)
ms->kimage_voffset && (sp =
kernel_symbol_search("memstart_addr"))) {
if (pc->flags & PROC_KCORE) {
if ((string = pc->read_vmcoreinfo("NUMBER(PHYS_OFFSET)"))) {
- ms->phys_offset = htol(string, QUIET, NULL);
+ ms->phys_offset_nominal = htol(string, QUIET, NULL);
+ if (ms->phys_offset_nominal < 0)
+ ms->phys_offset = ms->phys_offset_nominal + MEMSTART_ADDR_OFFSET;
+ else
+ ms->phys_offset = ms->phys_offset_nominal;
free(string);
return;
}
@@ -1080,7 +1088,18 @@ arm64_calc_phys_offset(void)
} else if (DISKDUMP_DUMPFILE() && diskdump_phys_base(&phys_offset)) {
ms->phys_offset = phys_offset;
} else if (KDUMP_DUMPFILE() && arm64_kdump_phys_base(&phys_offset)) {
- ms->phys_offset = phys_offset;
+ /*
+ * When running a 52bits kernel on 48bits hardware. Kernel plays a trick:
+ * if (IS_ENABLED(CONFIG_ARM64_VA_BITS_52) && (vabits_actual != 52))
+ * memstart_addr -= _PAGE_OFFSET(48) - _PAGE_OFFSET(52);
+ *
+ * In crash, this should be detected to get a real physical start address.
+ */
+ ms->phys_offset_nominal = phys_offset;
+ if ((long)phys_offset < 0)
+ ms->phys_offset = phys_offset + MEMSTART_ADDR_OFFSET;
+ else
+ ms->phys_offset = phys_offset;
} else {
error(WARNING,
"phys_offset cannot be determined from the dumpfile.\n");
diff --git a/defs.h b/defs.h
index 35b983a..09d58e0 100644
--- a/defs.h
+++ b/defs.h
@@ -3289,7 +3289,10 @@ struct machine_specific {
ulong vmemmap_end;
ulong modules_vaddr;
ulong modules_end;
+ /* real physical offset */
ulong phys_offset;
+ /* read from kernel symbol memstart_addr */
+ long phys_offset_nominal;
ulong __exception_text_start;
ulong __exception_text_end;
struct arm64_pt_regs *panic_task_regs;