----- Original Message ----- > In my next version of kdump patch, the following VMCOREINFO will be > added: > NUMBER(VA_BITS) > NUMBER(kimage_voffset) > NUMBER(PHYS_OFFSET) > KERNELOFFSET > > I think that those will also satisfy mkdumpfile requirements. > -> Pratyush > > Thanks, > -Takahiro AKASHI
Hi Takahiro, This patch looks good. From my end, I'm pretty much ready to check it in, notwithstanding the lack of live system KASLR support. And even in that case, a live system with KASLR enabled could be brought up with --machdep arguments for now. One minor nit: $ make warn ... arm64.c: In function 'arm64_kdump_phys_base': arm64.c:814:2: warning: suggest parentheses around assignment used as truth value [-Wparentheses] if (string = pc->read_vmcoreinfo("NUMBER(PHYS_OFFSET)")) { ^ ... And speaking of arm64_kdump_phys_base(), I do have a question about the 3 FALSE returns: @@ -720,7 +807,32 @@ arm64_calc_phys_offset(void) static int arm64_kdump_phys_base(ulong *phys_offset) { - return arm_kdump_phys_base(phys_offset); + char *string; + struct syment *sp; + physaddr_t paddr; + + if (string = pc->read_vmcoreinfo("NUMBER(PHYS_OFFSET)")) { + *phys_offset = htol(string, QUIET, NULL); + free(string); + return TRUE; + } + + if (machdep->flags & NEW_VMEMMAP) { + if (!(sp = kernel_symbol_search("memstart_addr"))) + return FALSE; + + /* sanity check */ + if (!machdep->machspec->kimage_voffset) + return FALSE; How could NEW_VMEMMAP possibly be set if !machdep->machspec->kimage_voffset? + + paddr = sp->value - machdep->machspec->kimage_voffset; + if (READMEM(-1, phys_offset, sizeof(*phys_offset), + sp->value, paddr) > 0) + return TRUE; + else + return FALSE; + } else + return arm_kdump_phys_base(phys_offset); } But regardless whether the "sanity check" needs to be made, shouldn't all 3 of the FALSE returns above alternatively allow arm_kdump_phys_base() to go ahead with its PT_LOAD segment check? In any case, do you have anything else you would like to add to it? Thanks, Dave > changes in v5: > * Calcs PHYS_OFFSET by reading VMCOREINFO, "NUMBER(PHYS_OFFSET)" > "memstart_addr"-based routine was also moved into arm64_calc_phys_base(). > > changes in v4: > * Fixed VA_BITS calculation for v4.5 or earlier > * Added 4-level address translation with 4KB page size > * Removed "fix a renaming of a member of struct page, _count to _refcount" > > Chnages in v3: > * Refined KASLR handling > hopefully the tool works even on a live system if CONFIG_RANDOMIZE_RAM is > not configured > * Fixed a renaming of a member of struct page > * Removed a commit message regarding an issue of backtracing a panic'ed task > because this is not a bug in this tool, but my kdump patch's. > * Reported "kmem <vmalloc addr>" issue in a commit message > > changes in v2: > * Fixed build warnings > * Moved ARM64_NEW_VMEMMAP to machdep->flags > * Show additional kaslr-related parameters in arm64_dump_machdep_table() > * Handle a VMCOREINFO, "NUMBER(kimage_voffset)" > > ======8<====== > >From a6dd9d73120dcc3f2d68dbe9a8f2d16a128c4002 Mon Sep 17 00:00:00 2001 > From: AKASHI Takahiro <takahiro.aka...@linaro.org> > Date: Mon, 16 May 2016 17:31:55 +0900 > Subject: [PATCH v5] arm64: fix kernel memory map handling for kaslr-enabled > kernel > > In kernel v4.6, Kernel ASLR (KASLR) is supported on arm64, and the start > address of the kernel image can be randomized if CONFIG_RANDOMIZE_BASE is > enabled. > Even worse, the kernel image is no more mapped in the linear mapping, but > in vmalloc area (i.e. below PAGE_OFFSET). > > Now, according to the kernel's memory.h, converting a virtual address to > a physical address should be done like below: > > phys_addr_t __x = (phys_addr_t)(x); \ > __x & BIT(VA_BITS - 1) ? (__x & ~PAGE_OFFSET) + PHYS_OFFSET : \ > (__x - kimage_voffset); }) > > Please note that PHYS_OFFSET is no more equal to the start address of > the first usable memory block in SYSTEM RAM due to the fact mentioned > above. > > This patch addresses this change and allows the crash utility to access > memory contents with correct addresses. > > * On a live system, crash with this patch won't work, especially > with CONFIG_RANDOMIZE_BASE configured, because we currently have no way > to know kimage_voffset. > > * For a core dump file, we can do simply: > $ crash <vmlinux> <vmcore> > as long as the file has "NUMBER(kimage_voffset)" > (RELOC_AUTO|KASLR is automatically set.) > > Signed-off-by: AKASHI Takahiro <takahiro.aka...@linaro.org> > --- > arm64.c | 232 > ++++++++++++++++++++++++++++++++++++++++++++++++-------------- > defs.h | 26 ++++--- > main.c | 7 +- > symbols.c | 12 ++-- > 4 files changed, 211 insertions(+), 66 deletions(-) > > diff --git a/arm64.c b/arm64.c > index 86ec348..37524c8 100644 > --- a/arm64.c > +++ b/arm64.c > @@ -73,6 +73,23 @@ static int arm64_get_crash_notes(void); > static void arm64_calc_VA_BITS(void); > static int arm64_is_uvaddr(ulong, struct task_context *); > > +ulong > +arm64_VTOP(ulong addr) > +{ > + if (machdep->flags & NEW_VMEMMAP) { > + if (addr >= machdep->machspec->page_offset) > + return machdep->machspec->phys_offset > + + (addr - machdep->machspec->page_offset); > + else if (machdep->machspec->kimage_voffset) > + return addr - machdep->machspec->kimage_voffset; > + else /* no randomness */ > + return machdep->machspec->phys_offset > + + (addr - > machdep->machspec->vmalloc_start_addr); > + } else { > + return machdep->machspec->phys_offset > + + (addr - machdep->machspec->page_offset); > + } > +} > > /* > * Do all necessary machine-specific setup here. This is called several > times > @@ -82,6 +99,7 @@ void > arm64_init(int when) > { > ulong value; > + char *string; > struct machine_specific *ms; > > #if defined(__x86_64__) > @@ -103,9 +121,32 @@ arm64_init(int when) > if (machdep->cmdline_args[0]) > arm64_parse_cmdline_args(); > machdep->flags |= MACHDEP_BT_TEXT; > + > + ms = machdep->machspec; > + if (!ms->kimage_voffset && > + (string = pc->read_vmcoreinfo("NUMBER(kimage_voffset)"))) { > + ms->kimage_voffset = htol(string, QUIET, NULL); > + free(string); > + } > + > + if (ms->kimage_voffset) { > + machdep->flags |= NEW_VMEMMAP; > + > + /* > + * Even if CONFIG_RANDOMIZE_BASE is not configured, > + * derive_kaslr_offset() should work and set > + * kt->relocate to 0 > + */ > + if (!kt->relocate && !(kt->flags2 & (RELOC_AUTO|KASLR))) > + kt->flags2 |= (RELOC_AUTO|KASLR); > + } > + > break; > > case PRE_GDB: > + if (kernel_symbol_exists("kimage_voffset")) > + machdep->flags |= NEW_VMEMMAP; > + > if (!machdep->pagesize) { > /* > * Kerneldoc Documentation/arm64/booting.txt describes > @@ -161,16 +202,34 @@ arm64_init(int when) > machdep->pagemask = ~((ulonglong)machdep->pageoffset); > > arm64_calc_VA_BITS(); > - machdep->machspec->page_offset = ARM64_PAGE_OFFSET; > + ms = machdep->machspec; > + ms->page_offset = ARM64_PAGE_OFFSET; > machdep->identity_map_base = ARM64_PAGE_OFFSET; > - machdep->machspec->userspace_top = ARM64_USERSPACE_TOP; > - machdep->machspec->modules_vaddr = ARM64_MODULES_VADDR; > - machdep->machspec->modules_end = ARM64_MODULES_END; > - machdep->machspec->vmalloc_start_addr = ARM64_VMALLOC_START; > - machdep->machspec->vmalloc_end = ARM64_VMALLOC_END; > - machdep->kvbase = ARM64_VMALLOC_START; > - machdep->machspec->vmemmap_vaddr = ARM64_VMEMMAP_VADDR; > - machdep->machspec->vmemmap_end = ARM64_VMEMMAP_END; > + machdep->kvbase = ARM64_VA_START; > + ms->userspace_top = ARM64_USERSPACE_TOP; > + if (machdep->flags & NEW_VMEMMAP) { > + struct syment *sp; > + > + sp = kernel_symbol_search("_text"); > + ms->kimage_text = (sp ? sp->value : 0); > + sp = kernel_symbol_search("_end"); > + ms->kimage_end = (sp ? sp->value : 0); > + > + ms->modules_vaddr = ARM64_VA_START; > + if (kernel_symbol_exists("kasan_init")) > + ms->modules_vaddr += ARM64_KASAN_SHADOW_SIZE; > + ms->modules_end = ms->modules_vaddr > + + ARM64_MODULES_VSIZE -1; > + > + ms->vmalloc_start_addr = ms->modules_end + 1; > + } else { > + ms->modules_vaddr = ARM64_PAGE_OFFSET - MEGABYTES(64); > + ms->modules_end = ARM64_PAGE_OFFSET - 1; > + ms->vmalloc_start_addr = ARM64_VA_START; > + } > + ms->vmalloc_end = ARM64_VMALLOC_END; > + ms->vmemmap_vaddr = ARM64_VMEMMAP_VADDR; > + ms->vmemmap_end = ARM64_VMEMMAP_END; > > switch (machdep->pagesize) > { > @@ -241,8 +300,6 @@ arm64_init(int when) > machdep->stacksize = ARM64_STACK_SIZE; > machdep->flags |= VMEMMAP; > > - arm64_calc_phys_offset(); > - > machdep->uvtop = arm64_uvtop; > machdep->kvtop = arm64_kvtop; > machdep->is_kvaddr = generic_is_kvaddr; > @@ -271,6 +328,10 @@ arm64_init(int when) > machdep->dumpfile_init = NULL; > machdep->verify_line_number = NULL; > machdep->init_kernel_pgd = arm64_init_kernel_pgd; > + > + /* use machdep parameters */ > + arm64_calc_phys_offset(); > + > break; > > case POST_GDB: > @@ -420,6 +481,8 @@ arm64_dump_machdep_table(ulong arg) > fprintf(fp, "%sIRQ_STACKS", others++ ? "|" : ""); > if (machdep->flags & MACHDEP_BT_TEXT) > fprintf(fp, "%sMACHDEP_BT_TEXT", others++ ? "|" : ""); > + if (machdep->flags & NEW_VMEMMAP) > + fprintf(fp, "%sNEW_VMEMMAP", others++ ? "|" : ""); > fprintf(fp, ")\n"); > > fprintf(fp, " kvbase: %lx\n", machdep->kvbase); > @@ -524,6 +587,11 @@ arm64_dump_machdep_table(ulong arg) > fprintf(fp, " modules_end: %016lx\n", ms->modules_end); > fprintf(fp, " vmemmap_vaddr: %016lx\n", ms->vmemmap_vaddr); > fprintf(fp, " vmemmap_end: %016lx\n", ms->vmemmap_end); > + if (machdep->flags & NEW_VMEMMAP) { > + fprintf(fp, " kimage_text: %016lx\n", > ms->kimage_text); > + fprintf(fp, " kimage_end: %016lx\n", ms->kimage_end); > + fprintf(fp, " kimage_voffset: %016lx\n", > ms->kimage_voffset); > + } > fprintf(fp, " phys_offset: %lx\n", ms->phys_offset); > fprintf(fp, "__exception_text_start: %lx\n", > ms->__exception_text_start); > fprintf(fp, " __exception_text_end: %lx\n", ms->__exception_text_end); > @@ -566,6 +634,42 @@ arm64_dump_machdep_table(ulong arg) > } > } > > +static int > +arm64_parse_machdep_arg_l(char *argstring, char *param, ulong *value) > +{ > + int len; > + int megabytes = FALSE; > + char *p; > + > + len = strlen(param); > + if (!STRNEQ(argstring, param) || (argstring[len] != '=')) > + return FALSE; > + > + if ((LASTCHAR(argstring) == 'm') || > + (LASTCHAR(argstring) == 'M')) { > + LASTCHAR(argstring) = NULLCHAR; > + megabytes = TRUE; > + } > + > + p = argstring + len + 1; > + if (strlen(p)) { > + int flags = RETURN_ON_ERROR | QUIET; > + int err = 0; > + > + if (megabytes) { > + *value = dtol(p, flags, &err); > + if (!err) > + *value = MEGABYTES(*value); > + } else { > + *value = htol(p, flags, &err); > + } > + > + if (!err) > + return TRUE; > + } > + > + return FALSE; > +} > > /* > * Parse machine dependent command line arguments. > @@ -577,11 +681,10 @@ arm64_dump_machdep_table(ulong arg) > static void > arm64_parse_cmdline_args(void) > { > - int index, i, c, err; > + int index, i, c; > char *arglist[MAXARGS]; > char buf[BUFSIZE]; > char *p; > - ulong value = 0; > > for (index = 0; index < MAX_MACHDEP_ARGS; index++) { > if (!machdep->cmdline_args[index]) > @@ -603,39 +706,23 @@ arm64_parse_cmdline_args(void) > c = parse_line(buf, arglist); > > for (i = 0; i < c; i++) { > - err = 0; > - > - if (STRNEQ(arglist[i], "phys_offset=")) { > - int megabytes = FALSE; > - int flags = RETURN_ON_ERROR | QUIET; > - > - if ((LASTCHAR(arglist[i]) == 'm') || > - (LASTCHAR(arglist[i]) == 'M')) { > - LASTCHAR(arglist[i]) = NULLCHAR; > - megabytes = TRUE; > - } > - > - p = arglist[i] + strlen("phys_offset="); > - if (strlen(p)) { > - if (megabytes) > - value = dtol(p, flags, &err); > - else > - value = htol(p, flags, &err); > - } > - > - if (!err) { > - if (megabytes) > - value = MEGABYTES(value); > - > - machdep->machspec->phys_offset = value; > - > - error(NOTE, > - "setting phys_offset to: 0x%lx\n\n", > - machdep->machspec->phys_offset); > + if (arm64_parse_machdep_arg_l(arglist[i], > + "phys_offset", > + &machdep->machspec->phys_offset)) { > + error(NOTE, > + "setting phys_offset to: 0x%lx\n\n", > + machdep->machspec->phys_offset); > + > + machdep->flags |= PHYS_OFFSET; > + continue; > + } else if (arm64_parse_machdep_arg_l(arglist[i], > + "kimage_voffset", > + &machdep->machspec->kimage_voffset)) { > + error(NOTE, > + "setting kimage_voffset to: 0x%lx\n\n", > + machdep->machspec->kimage_voffset); > > - machdep->flags |= PHYS_OFFSET; > - continue; > - } > + continue; > } > > error(WARNING, "ignoring --machdep option: %s\n", > @@ -720,7 +807,32 @@ arm64_calc_phys_offset(void) > static int > arm64_kdump_phys_base(ulong *phys_offset) > { > - return arm_kdump_phys_base(phys_offset); > + char *string; > + struct syment *sp; > + physaddr_t paddr; > + > + if (string = pc->read_vmcoreinfo("NUMBER(PHYS_OFFSET)")) { > + *phys_offset = htol(string, QUIET, NULL); > + free(string); > + return TRUE; > + } > + > + if (machdep->flags & NEW_VMEMMAP) { > + if (!(sp = kernel_symbol_search("memstart_addr"))) > + return FALSE; > + > + /* sanity check */ > + if (!machdep->machspec->kimage_voffset) > + return FALSE; > + > + paddr = sp->value - machdep->machspec->kimage_voffset; > + if (READMEM(-1, phys_offset, sizeof(*phys_offset), > + sp->value, paddr) > 0) > + return TRUE; > + else > + return FALSE; > + } else > + return arm_kdump_phys_base(phys_offset); > } > > static void > @@ -2509,6 +2621,11 @@ arm64_IS_VMALLOC_ADDR(ulong vaddr) > { > struct machine_specific *ms = machdep->machspec; > > + if ((machdep->flags & NEW_VMEMMAP) && > + (vaddr >= machdep->machspec->kimage_text) && > + (vaddr <= machdep->machspec->kimage_end)) > + return FALSE; > + > return ((vaddr >= ms->vmalloc_start_addr && vaddr <= > ms->vmalloc_end) || > ((machdep->flags & VMEMMAP) && > (vaddr >= ms->vmemmap_vaddr && vaddr <= ms->vmemmap_end)) > || > @@ -2539,7 +2656,10 @@ arm64_calc_VA_BITS(void) > > for (bitval = highest_bit_long(value); bitval; bitval--) { > if ((value & (1UL << bitval)) == 0) { > - machdep->machspec->VA_BITS = bitval + 2; > + if (machdep->flags & NEW_VMEMMAP) > + machdep->machspec->VA_BITS = bitval + 1; > + else > + machdep->machspec->VA_BITS = bitval + 2; > break; > } > } > @@ -2593,10 +2713,22 @@ arm64_calc_virtual_memory_ranges(void) > break; > } > > - vmemmap_size = ALIGN((1UL << (ms->VA_BITS - machdep->pageshift)) * > SIZE(page), PUD_SIZE); > + if (machdep->flags & NEW_VMEMMAP) > +#define STRUCT_PAGE_MAX_SHIFT 6 > + vmemmap_size = 1UL << (ms->VA_BITS - machdep->pageshift - 1 > + + STRUCT_PAGE_MAX_SHIFT); > + else > + vmemmap_size = ALIGN((1UL << (ms->VA_BITS - > machdep->pageshift)) * > SIZE(page), PUD_SIZE); > + > vmalloc_end = (ms->page_offset - PUD_SIZE - vmemmap_size - SZ_64K); > - vmemmap_start = vmalloc_end + SZ_64K; > - vmemmap_end = vmemmap_start + vmemmap_size; > + > + if (machdep->flags & NEW_VMEMMAP) { > + vmemmap_start = ms->page_offset - vmemmap_size; > + vmemmap_end = ms->page_offset; > + } else { > + vmemmap_start = vmalloc_end + SZ_64K; > + vmemmap_end = vmemmap_start + vmemmap_size; > + } > > ms->vmalloc_end = vmalloc_end - 1; > ms->vmemmap_vaddr = vmemmap_start; > diff --git a/defs.h b/defs.h > index 8eb601b..d6f719c 100644 > --- a/defs.h > +++ b/defs.h > @@ -2846,8 +2846,8 @@ typedef u64 pte_t; > > #define PTOV(X) \ > ((unsigned > > long)(X)-(machdep->machspec->phys_offset)+(machdep->machspec->page_offset)) > -#define VTOP(X) \ > - ((unsigned > long)(X)-(machdep->machspec->page_offset)+(machdep->machspec->phys_offset)) > + > +#define VTOP(X) arm64_VTOP((ulong)(X)) > > #define USERSPACE_TOP (machdep->machspec->userspace_top) > #define PAGE_OFFSET (machdep->machspec->page_offset) > @@ -2962,19 +2962,24 @@ typedef signed int s32; > #define VM_L3_4K (0x10) > #define KDUMP_ENABLED (0x20) > #define IRQ_STACKS (0x40) > -#define VM_L4_4K (0x80) > +#define NEW_VMEMMAP (0x80) > +#define VM_L4_4K (0x100) > > /* > * sources: Documentation/arm64/memory.txt > * arch/arm64/include/asm/memory.h > * arch/arm64/include/asm/pgtable.h > */ > - > -#define ARM64_PAGE_OFFSET ((0xffffffffffffffffUL) << > (machdep->machspec->VA_BITS - 1)) > +#define ARM64_VA_START ((0xffffffffffffffffUL) \ > + << machdep->machspec->VA_BITS) > +#define ARM64_PAGE_OFFSET ((0xffffffffffffffffUL) \ > + << (machdep->machspec->VA_BITS - 1)) > #define ARM64_USERSPACE_TOP ((1UL) << machdep->machspec->VA_BITS) > -#define ARM64_MODULES_VADDR (ARM64_PAGE_OFFSET - MEGABYTES(64)) > -#define ARM64_MODULES_END (ARM64_PAGE_OFFSET - 1) > -#define ARM64_VMALLOC_START ((0xffffffffffffffffUL) << > machdep->machspec->VA_BITS) > + > +/* only used for v4.6 or later */ > +#define ARM64_MODULES_VSIZE MEGABYTES(128) > +#define ARM64_KASAN_SHADOW_SIZE (1UL << (machdep->machspec->VA_BITS - 3)) > + > /* > * The following 3 definitions are the original values, but are obsolete > * for 3.17 and later kernels because they are now build-time calculations. > @@ -3055,6 +3060,10 @@ struct machine_specific { > ulong *irq_stacks; > ulong __irqentry_text_start; > ulong __irqentry_text_end; > + /* only needed for v4.6 or later kernel */ > + ulong kimage_voffset; > + ulong kimage_text; > + ulong kimage_end; > }; > > struct arm64_stackframe { > @@ -5412,6 +5421,7 @@ void unwind_backtrace(struct bt_info *); > #ifdef ARM64 > void arm64_init(int); > void arm64_dump_machdep_table(ulong); > +ulong arm64_VTOP(ulong); > int arm64_IS_VMALLOC_ADDR(ulong); > ulong arm64_swp_type(ulong); > ulong arm64_swp_offset(ulong); > diff --git a/main.c b/main.c > index 05787f0..4065e9a 100644 > --- a/main.c > +++ b/main.c > @@ -227,9 +227,10 @@ main(int argc, char **argv) > optarg); > } > } else if (STREQ(long_options[option_index].name, > "kaslr")) { > - if (!machine_type("X86_64")) > - error(INFO, "--kaslr only valid " > - "with X86_64 machine type.\n"); > + if (!machine_type("X86_64") && > + !machine_type("ARM64")) > + error(INFO, "--kaslr not valid " > + "with this machine type.\n"); > else if (STREQ(optarg, "auto")) > kt->flags2 |= (RELOC_AUTO|KASLR); > else { > diff --git a/symbols.c b/symbols.c > index a8d3563..b0a6461 100644 > --- a/symbols.c > +++ b/symbols.c > @@ -593,7 +593,8 @@ kaslr_init(void) > { > char *string; > > - if (!machine_type("X86_64") || (kt->flags & RELOC_SET)) > + if ((!machine_type("X86_64") && !machine_type("ARM64")) || > + (kt->flags & RELOC_SET)) > return; > > /* > @@ -712,7 +713,7 @@ store_symbols(bfd *abfd, int dynamic, void *minisyms, > long symcount, > if (machine_type("X86")) { > if (!(kt->flags & RELOC_SET)) > kt->flags |= RELOC_FORCE; > - } else if (machine_type("X86_64")) { > + } else if (machine_type("X86_64") || machine_type("ARM64")) { > if ((kt->flags2 & RELOC_AUTO) && !(kt->flags & RELOC_SET)) > derive_kaslr_offset(abfd, dynamic, from, > fromend, size, store); > @@ -783,7 +784,8 @@ store_sysmap_symbols(void) > error(FATAL, "symbol table namespace malloc: %s\n", > strerror(errno)); > > - if (!machine_type("X86") && !machine_type("X86_64")) > + if (!machine_type("X86") && !machine_type("X86_64") && > + !machine_type("ARM64")) > kt->flags &= ~RELOC_SET; > > first = 0; > @@ -833,7 +835,7 @@ store_sysmap_symbols(void) > } > > /* > - * Handle x86 kernels configured such that the vmlinux symbols > + * Handle x86/arm64 kernels configured such that the vmlinux symbols > * are not as loaded into the kernel (not unity-mapped). > */ > static ulong > @@ -4681,7 +4683,7 @@ value_search(ulong value, ulong *offset) > if ((sp = machdep->value_to_symbol(value, offset))) > return sp; > > - if (IS_VMALLOC_ADDR(value)) > + if (IS_VMALLOC_ADDR(value)) > goto check_modules; > > if ((sp = symval_hash_search(value)) == NULL) > -- > 2.8.1 > > -- > Crash-utility mailing list > Crash-utility@redhat.com > https://www.redhat.com/mailman/listinfo/crash-utility > -- Crash-utility mailing list Crash-utility@redhat.com https://www.redhat.com/mailman/listinfo/crash-utility