commit 8618ddd817621c40c1f44f0ab6df7c7805234416 Author: Dave Anderson Date: Fri Feb 1 15:01:29 2019 -0500 First phase of support for ARM64 kernels that are configured with CONFIG_ARM64_USER_VA_BITS_52, which causes the PTRS_PER_PGD count to increase from 64 to 1024. Without the patch, "WARNING: cannot access vmalloc'd module memory" will be displayed during session initialization, and the translation of any mapped kernel virtual address that requires a page table walk will fail, leading to a myriad of other errors. (anderson@redhat.com) diff --git a/arm64.c b/arm64.c index 45c7313..2308612 100644 --- a/arm64.c +++ b/arm64.c @@ -1,8 +1,8 @@ /* * arm64.c - core analysis suite * - * Copyright (C) 2012-2018 David Anderson - * Copyright (C) 2012-2018 Red Hat, Inc. All rights reserved. + * Copyright (C) 2012-2019 David Anderson + * Copyright (C) 2012-2019 Red Hat, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -209,6 +209,8 @@ arm64_init(int when) ms->page_offset = ARM64_PAGE_OFFSET; machdep->identity_map_base = ARM64_PAGE_OFFSET; machdep->kvbase = ARM64_VA_START; + machdep->is_kvaddr = generic_is_kvaddr; + machdep->kvtop = arm64_kvtop; ms->userspace_top = ARM64_USERSPACE_TOP; if (machdep->flags & NEW_VMEMMAP) { struct syment *sp; @@ -262,11 +264,17 @@ arm64_init(int when) break; case 65536: + if (kernel_symbol_exists("idmap_ptrs_per_pgd") && + readmem(symbol_value("idmap_ptrs_per_pgd"), KVADDR, + &value, sizeof(ulong), "idmap_ptrs_per_pgd", RETURN_ON_ERROR)) + machdep->ptrs_per_pgd = value; + if (machdep->machspec->VA_BITS > PGDIR_SHIFT_L3_64K) { machdep->flags |= VM_L3_64K; - machdep->ptrs_per_pgd = PTRS_PER_PGD_L3_64K; + if (!machdep->ptrs_per_pgd) + machdep->ptrs_per_pgd = PTRS_PER_PGD_L3_64K; if ((machdep->pgd = - (char *)malloc(PTRS_PER_PGD_L3_64K * 8)) == NULL) + (char *)malloc(machdep->ptrs_per_pgd * 8)) == NULL) error(FATAL, "cannot malloc pgd space."); if ((machdep->pmd = (char *)malloc(PTRS_PER_PMD_L3_64K * 8)) == NULL) @@ -276,9 +284,10 @@ arm64_init(int when) error(FATAL, "cannot malloc ptbl space."); } else { machdep->flags |= VM_L2_64K; - machdep->ptrs_per_pgd = PTRS_PER_PGD_L2_64K; + if (!machdep->ptrs_per_pgd) + machdep->ptrs_per_pgd = PTRS_PER_PGD_L2_64K; if ((machdep->pgd = - (char *)malloc(PTRS_PER_PGD_L2_64K * 8)) == NULL) + (char *)malloc(machdep->ptrs_per_pgd * 8)) == NULL) error(FATAL, "cannot malloc pgd space."); if ((machdep->ptbl = (char *)malloc(PTRS_PER_PTE_L2_64K * 8)) == NULL) @@ -306,9 +315,11 @@ arm64_init(int when) machdep->flags |= VMEMMAP; machdep->uvtop = arm64_uvtop; - machdep->kvtop = arm64_kvtop; - machdep->is_kvaddr = generic_is_kvaddr; machdep->is_uvaddr = arm64_is_uvaddr; + if (kernel_symbol_exists("vabits_user") && + readmem(symbol_value("vabits_user"), KVADDR, + &value, sizeof(ulong), "vabits_user", RETURN_ON_ERROR)) + machdep->machspec->vabits_user = value; machdep->eframe_search = arm64_eframe_search; machdep->back_trace = arm64_back_trace_cmd; machdep->in_alternate_stack = arm64_in_alternate_stack; @@ -350,10 +361,14 @@ arm64_init(int when) case POST_GDB: arm64_calc_virtual_memory_ranges(); machdep->section_size_bits = _SECTION_SIZE_BITS; - if (THIS_KERNEL_VERSION >= LINUX(3,17,0)) - machdep->max_physmem_bits = _MAX_PHYSMEM_BITS_3_17; - else - machdep->max_physmem_bits = _MAX_PHYSMEM_BITS; + if (!machdep->max_physmem_bits) { + if (machdep->machspec->VA_BITS == 52) /* guess */ + machdep->max_physmem_bits = _MAX_PHYSMEM_BITS_52; + else if (THIS_KERNEL_VERSION >= LINUX(3,17,0)) + machdep->max_physmem_bits = _MAX_PHYSMEM_BITS_3_17; + else + machdep->max_physmem_bits = _MAX_PHYSMEM_BITS; + } ms = machdep->machspec; if (THIS_KERNEL_VERSION >= LINUX(4,0,0)) { @@ -601,6 +616,11 @@ arm64_dump_machdep_table(ulong arg) fprintf(fp, " machspec: %lx\n", (ulong)ms); fprintf(fp, " VA_BITS: %ld\n", ms->VA_BITS); + fprintf(fp, " vabits_user: "); + if (ms->vabits_user) + fprintf(fp, "%ld\n", ms->vabits_user); + else + fprintf(fp, "(unused)\n"); fprintf(fp, " userspace_top: %016lx\n", ms->userspace_top); fprintf(fp, " page_offset: %016lx\n", ms->page_offset); fprintf(fp, " vmalloc_start_addr: %016lx\n", ms->vmalloc_start_addr); @@ -691,6 +711,8 @@ arm64_parse_machdep_arg_l(char *argstring, char *param, ulong *value) *value = dtol(p, flags, &err); if (!err) *value = MEGABYTES(*value); + } else if (STRNEQ(argstring, "max_physmem_bits")) { + *value = dtol(p, flags, &err); } else { *value = htol(p, flags, &err); } @@ -750,6 +772,12 @@ arm64_parse_cmdline_args(void) "setting kimage_voffset to: 0x%lx\n\n", machdep->machspec->kimage_voffset); continue; + } else if (arm64_parse_machdep_arg_l(arglist[i], "max_physmem_bits", + &machdep->max_physmem_bits)) { + error(NOTE, + "setting max_physmem_bits to: %ld\n\n", + machdep->max_physmem_bits); + continue; } error(WARNING, "ignoring --machdep option: %s\n", @@ -1065,8 +1093,8 @@ arm64_vtop_2level_64k(ulong pgd, ulong vaddr, physaddr_t *paddr, int verbose) fprintf(fp, "PAGE DIRECTORY: %lx\n", pgd); pgd_base = (ulong *)pgd; - FILL_PGD(pgd_base, KVADDR, PTRS_PER_PGD_L2_64K * sizeof(ulong)); - pgd_ptr = pgd_base + (((vaddr) >> PGDIR_SHIFT_L2_64K) & (PTRS_PER_PGD_L2_64K - 1)); + FILL_PGD(pgd_base, KVADDR, machdep->ptrs_per_pgd * sizeof(ulong)); + pgd_ptr = pgd_base + (((vaddr) >> PGDIR_SHIFT_L2_64K) & (machdep->ptrs_per_pgd - 1)); pgd_val = ULONG(machdep->pgd + PAGEOFFSET(pgd_ptr)); if (verbose) fprintf(fp, " PGD: %lx => %lx\n", (ulong)pgd_ptr, pgd_val); @@ -1129,8 +1157,8 @@ arm64_vtop_3level_64k(ulong pgd, ulong vaddr, physaddr_t *paddr, int verbose) fprintf(fp, "PAGE DIRECTORY: %lx\n", pgd); pgd_base = (ulong *)pgd; - FILL_PGD(pgd_base, KVADDR, PTRS_PER_PGD_L3_64K * sizeof(ulong)); - pgd_ptr = pgd_base + (((vaddr) >> PGDIR_SHIFT_L3_64K) & (PTRS_PER_PGD_L3_64K - 1)); + FILL_PGD(pgd_base, KVADDR, machdep->ptrs_per_pgd * sizeof(ulong)); + pgd_ptr = pgd_base + (((vaddr) >> PGDIR_SHIFT_L3_64K) & (machdep->ptrs_per_pgd - 1)); pgd_val = ULONG(machdep->pgd + PGDIR_OFFSET_L3_64K(pgd_ptr)); if (verbose) fprintf(fp, " PGD: %lx => %lx\n", (ulong)pgd_ptr, pgd_val); diff --git a/crash.8 b/crash.8 index 8c11615..f9de36d 100644 --- a/crash.8 +++ b/crash.8 @@ -278,6 +278,7 @@ ARM: ARM64: phys_offset= kimage_voffset= + max_physmem_bits= X86: page_offset= .fi diff --git a/defs.h b/defs.h index b473972..05f2d17 100644 --- a/defs.h +++ b/defs.h @@ -3049,7 +3049,7 @@ typedef signed int s32; #define PMD_SHIFT_L3_64K (29) #define PMD_SIZE_L3_64K (1UL << PMD_SHIFT_L3_64K) #define PMD_MASK_L3_64K (~(PMD_SIZE_L3_64K-1)) -#define PGDIR_OFFSET_L3_64K(X) (((ulong)(X)) & ((PTRS_PER_PGD_L3_64K * 8) - 1)) +#define PGDIR_OFFSET_L3_64K(X) (((ulong)(X)) & ((machdep->ptrs_per_pgd * 8) - 1)) /* * 2-levels / 64K pages @@ -3136,6 +3136,7 @@ typedef signed int s32; #define _SECTION_SIZE_BITS 30 #define _MAX_PHYSMEM_BITS 40 #define _MAX_PHYSMEM_BITS_3_17 48 +#define _MAX_PHYSMEM_BITS_52 52 typedef unsigned long long __u64; typedef unsigned long long u64; @@ -3215,6 +3216,7 @@ struct machine_specific { ulong kern_eframe_offset; ulong machine_kexec_start; ulong machine_kexec_end; + ulong vabits_user; }; struct arm64_stackframe { diff --git a/help.c b/help.c index ff0c80b..ba15dec 100644 --- a/help.c +++ b/help.c @@ -179,6 +179,7 @@ char *program_usage_info[] = { " ARM64:", " phys_offset=", " kimage_voffset=", + " max_physmem_bits=", " X86:", " page_offset=", "",