Skip to content

Commit

Permalink
arm64: implement switchable PTOV()/VTOP() for kernels >= 5.10
Browse files Browse the repository at this point in the history
Crash encounters a bug like the following:
    ...
    SECTION_SIZE_BITS: 30
    CONFIG_ARM64_VA_BITS: 52
          VA_BITS_ACTUAL: 48
    (calculated) VA_BITS: 48
     PAGE_OFFSET: ffff000000000000
        VA_START: ffff800000000000
         modules: ffff800008000000 - ffff80000fffffff
         vmalloc: ffff800010000000 - ffffffdfdffeffff
    kernel image: ffff800010000000 - ffff800012750000
         vmemmap: ffffffdfffe00000 - ffffffffffffffff

    <readmem: ffff800011c53bc8, KVADDR, "nr_irqs", 4, (FOE), b47bdc>
    <read_kdump: addr: ffff800011c53bc8 paddr: eb453bc8 cnt: 4>
    read_netdump: addr: ffff800011c53bc8 paddr: eb453bc8 cnt: 4 offset: 1c73bc8
    irq_stack_ptr:
      type: 1, TYPE_CODE_PTR
      target_typecode: 8, TYPE_CODE_INT
      target_length: 8
      length: 8
    GNU_GET_DATATYPE[thread_union]: returned via gdb_error_hook
    <readmem: ffff000b779c0050, KVADDR, "IRQ stack pointer", 8, (ROE), 3a37bea0>
    <read_kdump: addr: ffff000b779c0050 paddr: fff1000bf79c0050 cnt: 8>
    read_netdump: READ_ERROR: offset not found for paddr: fff1000bf79c0050
    crash: read error: kernel virtual address: ffff000b779c0050  type: "IRQ stack pointer"
    ...

Apparently, for a normal system, the 'paddr: fff1000bf79c0050' is
unreasonable.

This bug connects with kernel commit 7bc1a0f9e176 ("arm64: mm: use
single quantity to represent the PA to VA translation"), which removed
physvirt_offset kernel variable and changed the PTOV()/VTOP() formulas.

Implement switchable PTOV()/VTOP() to cope with different kernel
version.

Signed-off-by: Pingfan Liu <piliu@redhat.com>
  • Loading branch information
Pingfan Liu authored and k-hagio committed Jul 5, 2021
1 parent bf1379a commit f53b73e
Show file tree
Hide file tree
Showing 2 changed files with 37 additions and 9 deletions.
37 changes: 33 additions & 4 deletions arm64.c
Expand Up @@ -994,17 +994,20 @@ arm64_calc_physvirt_offset(void)
ulong physvirt_offset;
struct syment *sp;

ms->physvirt_offset = ms->phys_offset - ms->page_offset;

if ((sp = kernel_symbol_search("physvirt_offset")) &&
machdep->machspec->kimage_voffset) {
if (READMEM(pc->mfd, &physvirt_offset, sizeof(physvirt_offset),
sp->value, sp->value -
machdep->machspec->kimage_voffset) > 0) {
machdep->flags |= HAS_PHYSVIRT_OFFSET;
ms->physvirt_offset = physvirt_offset;
return;
}
}

/* Useless if no symbol 'physvirt_offset', just keep semantics */
ms->physvirt_offset = ms->phys_offset - ms->page_offset;

}

static void
Expand Down Expand Up @@ -1051,6 +1054,7 @@ arm64_calc_phys_offset(void)
if (READMEM(pc->mfd, &phys_offset, sizeof(phys_offset),
vaddr, paddr) > 0) {
ms->phys_offset = phys_offset;

return;
}
}
Expand Down Expand Up @@ -1178,6 +1182,21 @@ arm64_init_kernel_pgd(void)
vt->kernel_pgd[i] = value;
}

ulong arm64_PTOV(ulong paddr)
{
struct machine_specific *ms = machdep->machspec;

/*
* Either older kernel before kernel has 'physvirt_offset' or newer
* kernel which removes 'physvirt_offset' has the same formula:
* #define __phys_to_virt(x) ((unsigned long)((x) - PHYS_OFFSET) | PAGE_OFFSET)
*/
if (!(machdep->flags & HAS_PHYSVIRT_OFFSET))
return (paddr - ms->phys_offset) | PAGE_OFFSET;
else
return paddr - ms->physvirt_offset;
}

ulong
arm64_VTOP(ulong addr)
{
Expand All @@ -1188,8 +1207,18 @@ arm64_VTOP(ulong addr)
return addr - machdep->machspec->kimage_voffset;
}

if (addr >= machdep->machspec->page_offset)
return addr + machdep->machspec->physvirt_offset;
if (addr >= machdep->machspec->page_offset) {
if (machdep->flags & HAS_PHYSVIRT_OFFSET) {
return addr + machdep->machspec->physvirt_offset;
} else {
/*
* Either older kernel before kernel has 'physvirt_offset' or newer
* kernel which removes 'physvirt_offset' has the same formula:
* #define __lm_to_phys(addr) (((addr) & ~PAGE_OFFSET) + PHYS_OFFSET)
*/
return (addr & ~PAGE_OFFSET) + machdep->machspec->phys_offset;
}
}
else if (machdep->machspec->kimage_voffset)
return addr - machdep->machspec->kimage_voffset;
else /* no randomness */
Expand Down
9 changes: 4 additions & 5 deletions defs.h
Expand Up @@ -3092,11 +3092,6 @@ typedef u64 pte_t;
#define _64BIT_
#define MACHINE_TYPE "ARM64"

#define PTOV(X) \
((unsigned long)(X) - (machdep->machspec->physvirt_offset))

#define VTOP(X) arm64_VTOP((ulong)(X))

#define USERSPACE_TOP (machdep->machspec->userspace_top)
#define PAGE_OFFSET (machdep->machspec->page_offset)
#define VMALLOC_START (machdep->machspec->vmalloc_start_addr)
Expand All @@ -3106,6 +3101,9 @@ typedef u64 pte_t;
#define MODULES_VADDR (machdep->machspec->modules_vaddr)
#define MODULES_END (machdep->machspec->modules_end)

#define PTOV(X) arm64_PTOV((ulong)(X))
#define VTOP(X) arm64_VTOP((ulong)(X))

#define IS_VMALLOC_ADDR(X) arm64_IS_VMALLOC_ADDR((ulong)(X))

#define PAGEBASE(X) (((ulong)(X)) & (ulong)machdep->pagemask)
Expand Down Expand Up @@ -5910,6 +5908,7 @@ void unwind_backtrace(struct bt_info *);
void arm64_init(int);
void arm64_dump_machdep_table(ulong);
ulong arm64_VTOP(ulong);
ulong arm64_PTOV(ulong);
int arm64_IS_VMALLOC_ADDR(ulong);
ulong arm64_swp_type(ulong);
ulong arm64_swp_offset(ulong);
Expand Down

0 comments on commit f53b73e

Please sign in to comment.