Blame SOURCES/0004-arm64-implement-switchable-PTOV-VTOP-for-kernels-5.1.patch

3e5f3d
From f53b73e8380bca054cebd2b61ff118c46609429b Mon Sep 17 00:00:00 2001
3e5f3d
From: Pingfan Liu <piliu@redhat.com>
3e5f3d
Date: Fri, 2 Jul 2021 10:14:24 +0800
3e5f3d
Subject: [PATCH 4/4] arm64: implement switchable PTOV()/VTOP() for kernels >=
3e5f3d
 5.10
3e5f3d
3e5f3d
Crash encounters a bug like the following:
3e5f3d
    ...
3e5f3d
    SECTION_SIZE_BITS: 30
3e5f3d
    CONFIG_ARM64_VA_BITS: 52
3e5f3d
          VA_BITS_ACTUAL: 48
3e5f3d
    (calculated) VA_BITS: 48
3e5f3d
     PAGE_OFFSET: ffff000000000000
3e5f3d
        VA_START: ffff800000000000
3e5f3d
         modules: ffff800008000000 - ffff80000fffffff
3e5f3d
         vmalloc: ffff800010000000 - ffffffdfdffeffff
3e5f3d
    kernel image: ffff800010000000 - ffff800012750000
3e5f3d
         vmemmap: ffffffdfffe00000 - ffffffffffffffff
3e5f3d
3e5f3d
    <readmem: ffff800011c53bc8, KVADDR, "nr_irqs", 4, (FOE), b47bdc>
3e5f3d
    <read_kdump: addr: ffff800011c53bc8 paddr: eb453bc8 cnt: 4>
3e5f3d
    read_netdump: addr: ffff800011c53bc8 paddr: eb453bc8 cnt: 4 offset: 1c73bc8
3e5f3d
    irq_stack_ptr:
3e5f3d
      type: 1, TYPE_CODE_PTR
3e5f3d
      target_typecode: 8, TYPE_CODE_INT
3e5f3d
      target_length: 8
3e5f3d
      length: 8
3e5f3d
    GNU_GET_DATATYPE[thread_union]: returned via gdb_error_hook
3e5f3d
    <readmem: ffff000b779c0050, KVADDR, "IRQ stack pointer", 8, (ROE), 3a37bea0>
3e5f3d
    <read_kdump: addr: ffff000b779c0050 paddr: fff1000bf79c0050 cnt: 8>
3e5f3d
    read_netdump: READ_ERROR: offset not found for paddr: fff1000bf79c0050
3e5f3d
    crash: read error: kernel virtual address: ffff000b779c0050  type: "IRQ stack pointer"
3e5f3d
    ...
3e5f3d
3e5f3d
Apparently, for a normal system, the 'paddr: fff1000bf79c0050' is
3e5f3d
unreasonable.
3e5f3d
3e5f3d
This bug connects with kernel commit 7bc1a0f9e176 ("arm64: mm: use
3e5f3d
single quantity to represent the PA to VA translation"), which removed
3e5f3d
physvirt_offset kernel variable and changed the PTOV()/VTOP() formulas.
3e5f3d
3e5f3d
Implement switchable PTOV()/VTOP() to cope with different kernel
3e5f3d
version.
3e5f3d
3e5f3d
Signed-off-by: Pingfan Liu <piliu@redhat.com>
3e5f3d
---
3e5f3d
 arm64.c | 37 +++++++++++++++++++++++++++++++++----
3e5f3d
 defs.h  |  9 ++++-----
3e5f3d
 2 files changed, 37 insertions(+), 9 deletions(-)
3e5f3d
3e5f3d
diff --git a/arm64.c b/arm64.c
3e5f3d
index b04369f..d73d5c5 100644
3e5f3d
--- a/arm64.c
3e5f3d
+++ b/arm64.c
3e5f3d
@@ -994,8 +994,6 @@ arm64_calc_physvirt_offset(void)
3e5f3d
 	ulong physvirt_offset;
3e5f3d
 	struct syment *sp;
3e5f3d
 
3e5f3d
-	ms->physvirt_offset = ms->phys_offset - ms->page_offset;
3e5f3d
-
3e5f3d
 	if ((sp = kernel_symbol_search("physvirt_offset")) &&
3e5f3d
 			machdep->machspec->kimage_voffset) {
3e5f3d
 		if (READMEM(pc->mfd, &physvirt_offset, sizeof(physvirt_offset),
3e5f3d
@@ -1003,8 +1001,13 @@ arm64_calc_physvirt_offset(void)
3e5f3d
 			machdep->machspec->kimage_voffset) > 0) {
3e5f3d
 				machdep->flags |= HAS_PHYSVIRT_OFFSET;
3e5f3d
 				ms->physvirt_offset = physvirt_offset;
3e5f3d
+				return;
3e5f3d
 		}
3e5f3d
 	}
3e5f3d
+
3e5f3d
+	/* Useless if no symbol 'physvirt_offset', just keep semantics */
3e5f3d
+	ms->physvirt_offset = ms->phys_offset - ms->page_offset;
3e5f3d
+
3e5f3d
 }
3e5f3d
 
3e5f3d
 static void
3e5f3d
@@ -1051,6 +1054,7 @@ arm64_calc_phys_offset(void)
3e5f3d
 			if (READMEM(pc->mfd, &phys_offset, sizeof(phys_offset),
3e5f3d
 			    vaddr, paddr) > 0) {
3e5f3d
 				ms->phys_offset = phys_offset;
3e5f3d
+
3e5f3d
 				return;
3e5f3d
 			}
3e5f3d
 		}
3e5f3d
@@ -1178,6 +1182,21 @@ arm64_init_kernel_pgd(void)
3e5f3d
                 vt->kernel_pgd[i] = value;
3e5f3d
 }
3e5f3d
 
3e5f3d
+ulong arm64_PTOV(ulong paddr)
3e5f3d
+{
3e5f3d
+	struct machine_specific *ms = machdep->machspec;
3e5f3d
+
3e5f3d
+	/*
3e5f3d
+	 * Either older kernel before kernel has 'physvirt_offset' or newer
3e5f3d
+	 * kernel which removes 'physvirt_offset' has the same formula:
3e5f3d
+	 * #define __phys_to_virt(x)   ((unsigned long)((x) - PHYS_OFFSET) | PAGE_OFFSET)
3e5f3d
+	 */
3e5f3d
+	if (!(machdep->flags & HAS_PHYSVIRT_OFFSET))
3e5f3d
+		return (paddr - ms->phys_offset) | PAGE_OFFSET;
3e5f3d
+	else
3e5f3d
+		return paddr - ms->physvirt_offset;
3e5f3d
+}
3e5f3d
+
3e5f3d
 ulong
3e5f3d
 arm64_VTOP(ulong addr)
3e5f3d
 {
3e5f3d
@@ -1188,8 +1207,18 @@ arm64_VTOP(ulong addr)
3e5f3d
 			return addr - machdep->machspec->kimage_voffset;
3e5f3d
 		}
3e5f3d
 
3e5f3d
-		if (addr >= machdep->machspec->page_offset)
3e5f3d
-			return addr + machdep->machspec->physvirt_offset;
3e5f3d
+		if (addr >= machdep->machspec->page_offset) {
3e5f3d
+			if (machdep->flags & HAS_PHYSVIRT_OFFSET) {
3e5f3d
+				return addr + machdep->machspec->physvirt_offset;
3e5f3d
+			} else {
3e5f3d
+				/*
3e5f3d
+				 * Either older kernel before kernel has 'physvirt_offset' or newer
3e5f3d
+				 * kernel which removes 'physvirt_offset' has the same formula:
3e5f3d
+				 * #define __lm_to_phys(addr)	(((addr) & ~PAGE_OFFSET) + PHYS_OFFSET)
3e5f3d
+				 */
3e5f3d
+				return (addr & ~PAGE_OFFSET) + machdep->machspec->phys_offset;
3e5f3d
+			}
3e5f3d
+		}
3e5f3d
 		else if (machdep->machspec->kimage_voffset)
3e5f3d
 			return addr - machdep->machspec->kimage_voffset;
3e5f3d
 		else /* no randomness */
3e5f3d
diff --git a/defs.h b/defs.h
3e5f3d
index eca145c..c91177a 100644
3e5f3d
--- a/defs.h
3e5f3d
+++ b/defs.h
3e5f3d
@@ -3092,11 +3092,6 @@ typedef u64 pte_t;
3e5f3d
 #define _64BIT_
3e5f3d
 #define MACHINE_TYPE       "ARM64"    
3e5f3d
 
3e5f3d
-#define PTOV(X) \
3e5f3d
-	((unsigned long)(X) - (machdep->machspec->physvirt_offset))
3e5f3d
-
3e5f3d
-#define VTOP(X)               arm64_VTOP((ulong)(X))
3e5f3d
-
3e5f3d
 #define USERSPACE_TOP   (machdep->machspec->userspace_top)
3e5f3d
 #define PAGE_OFFSET     (machdep->machspec->page_offset)
3e5f3d
 #define VMALLOC_START   (machdep->machspec->vmalloc_start_addr)
3e5f3d
@@ -3106,6 +3101,9 @@ typedef u64 pte_t;
3e5f3d
 #define MODULES_VADDR   (machdep->machspec->modules_vaddr)
3e5f3d
 #define MODULES_END     (machdep->machspec->modules_end)
3e5f3d
 
3e5f3d
+#define PTOV(X)	arm64_PTOV((ulong)(X))
3e5f3d
+#define VTOP(X)	arm64_VTOP((ulong)(X))
3e5f3d
+
3e5f3d
 #define IS_VMALLOC_ADDR(X)    arm64_IS_VMALLOC_ADDR((ulong)(X))
3e5f3d
 
3e5f3d
 #define PAGEBASE(X)     (((ulong)(X)) & (ulong)machdep->pagemask)
3e5f3d
@@ -5910,6 +5908,7 @@ void unwind_backtrace(struct bt_info *);
3e5f3d
 void arm64_init(int);
3e5f3d
 void arm64_dump_machdep_table(ulong);
3e5f3d
 ulong arm64_VTOP(ulong);
3e5f3d
+ulong arm64_PTOV(ulong);
3e5f3d
 int arm64_IS_VMALLOC_ADDR(ulong);
3e5f3d
 ulong arm64_swp_type(ulong);
3e5f3d
 ulong arm64_swp_offset(ulong);
3e5f3d
-- 
3e5f3d
2.29.2
3e5f3d