-----Original Message-----
1.) When I tested live system with "crash vmlinux
/proc/kcore" in kernel v5.7,
I met the following crash issue:
........................................
crash: seek error: kernel virtual address: ffff75e9fffff000 type: "pud
page"
........................................
2.) The root cause is the PTOV does not work correctly for some kernel,
and then arm64_vtop_4level_4k() does not work correctly too.
Why PTOV does not work?
The PHYS_OFFSET is just wrapper of memstart_addr.
...............................
#define PHYS_OFFSET ({ VM_BUG_ON(memstart_addr & 1); memstart_addr; })
...............................
Because memstart_addr is changed after physvirt_offset is initialized.
so the NUMBER(PHYS_OFFSET) does not return the correct value.
Hmm, it looks like arm64_PTOV() uses the physvirt_offset if available
(5.4 <= kernel < 5.10), I'm still not sure why it does not work correctly.
Would you please explain the issue in more detail?
Thanks,
Kazu
3.) How many kernel versions have this bug?
1) In kernel v5.4, the patch:
"5383cc6efed137 arm64: mm: Introduce vabits_actual"
makes the NUMBER(PHYS_OFFSET) do not work correctly.
2) In kernel v5.10, the patch:
"7bc1a0f9e17658 arm64: mm: use single quantity
to represent the PA to VA translation"
makes the NUMBER(PHYS_OFFSET) work again.
4.) What does this patch do?
This patch uses the same method as makedumpfile does:
Use the PT_LOAD segments to get the phys_offset.
Signed-off-by: Huang Shijie <shijie(a)os.amperecomputing.com>
---
arm64.c | 53 +++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 53 insertions(+)
diff --git a/arm64.c b/arm64.c
index e3fa316..d81c2b9 100644
--- a/arm64.c
+++ b/arm64.c
@@ -1426,6 +1426,51 @@ arm64_calc_physvirt_offset(void)
}
+/*
+ * Check if an virtual address is a linear address.
+ */
+#define PAGE_END (_PAGE_END(ms->VA_BITS_ACTUAL))
+static int arm64_is_linear_addr(struct machine_specific *ms,
+ unsigned long va)
+{
+ return (va - PAGE_OFFSET) < (PAGE_END - PAGE_OFFSET);
+}
+
+/*
+ * This function only works for kernel range: [5.4, 5.10).
+ *
+ * 1) In kernel v5.4, the patch:
+ * "5383cc6efed137 arm64: mm: Introduce vabits_actual"
+ *
+ * makes the NUMBER(PHYS_OFFSET) do not work correctly.
+ *
+ * 2) In kernel v5.10, the patch:
+ * "7bc1a0f9e17658 arm64: mm: use single quantity
+ * to represent the PA to VA translation"
+ *
+ * makes the NUMBER(PHYS_OFFSET) work again.
+ *
+ * This function tries to get the phys_offset from PT_LOAD segments.
+ * This method was originally used by the makedumpfile tool.
+ */
+static void arm64_get_phys_offset_by_pt_load(struct machine_specific *ms)
+{
+ int i;
+ Elf64_Phdr *h;
+ struct proc_kcore_data *pkd = arm64_get_pkd();
+
+ for (i = 0; i < pkd->segments; i++) {
+ h = &pkd->load64[i];
+
+ if (arm64_is_linear_addr(ms, h->p_vaddr)) {
+ ms->phys_offset = h->p_paddr - (h->p_vaddr & ~PAGE_OFFSET);
+ return;
+ }
+ }
+
+ error(FATAL, "We cannot get the correct phys_offset!\n");
+}
+
static void
arm64_calc_phys_offset(void)
{
@@ -1454,6 +1499,14 @@ arm64_calc_phys_offset(void)
if ((machdep->flags & NEW_VMEMMAP) &&
ms->kimage_voffset && (sp =
kernel_symbol_search("memstart_addr"))) {
if (pc->flags & PROC_KCORE) {
+ unsigned long v = arm64_get_kernel_version();
+
+ /* Do special operation for kernel [5.4, 5.10) */
+ if (LINUX(5, 4, 0) <= v && v < LINUX(5, 10, 0)) {
+ arm64_get_phys_offset_by_pt_load(ms);
+ return;
+ }
+
if ((string = pc->read_vmcoreinfo("NUMBER(PHYS_OFFSET)"))) {
ms->phys_offset = htol(string, QUIET, NULL);
free(string);
--
2.30.2