Date: Mon, 14 Oct 2019 13:04:04 +0000 (UTC) From: Leandro Lupori <luporl@FreeBSD.org> To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r353489 - in head/sys: conf kern powerpc/aim powerpc/include powerpc/powerpc powerpc/pseries vm Message-ID: <201910141304.x9ED44nv010510@repo.freebsd.org>
next in thread | raw e-mail | index | archive | help
Author: luporl Date: Mon Oct 14 13:04:04 2019 New Revision: 353489 URL: https://svnweb.freebsd.org/changeset/base/353489 Log: [PPC64] Initial kernel minidump implementation Based on POWER9BSD implementation, with all POWER9 specific code removed and addition of new methods in PPC64 MMU interface, to isolate platform specific code. Currently, the new methods are implemented on pseries and PowerNV (D21643). Reviewed by: jhibbits Differential Revision: https://reviews.freebsd.org/D21551 Added: head/sys/powerpc/include/minidump.h (contents, props changed) head/sys/powerpc/powerpc/minidump_machdep.c (contents, props changed) Modified: head/sys/conf/files.powerpc head/sys/kern/kern_dump.c head/sys/powerpc/aim/mmu_oea64.c head/sys/powerpc/aim/mmu_oea64.h head/sys/powerpc/include/dump.h head/sys/powerpc/include/md_var.h head/sys/powerpc/include/pmap.h head/sys/powerpc/powerpc/mmu_if.m head/sys/powerpc/powerpc/pmap_dispatch.c head/sys/powerpc/powerpc/uma_machdep.c head/sys/powerpc/pseries/mmu_phyp.c head/sys/vm/vm_page.c Modified: head/sys/conf/files.powerpc ============================================================================== --- head/sys/conf/files.powerpc Mon Oct 14 13:02:49 2019 (r353488) +++ head/sys/conf/files.powerpc Mon Oct 14 13:04:04 2019 (r353489) @@ -224,6 +224,7 @@ powerpc/powerpc/intr_machdep.c standard powerpc/powerpc/iommu_if.m standard powerpc/powerpc/machdep.c standard powerpc/powerpc/mem.c optional mem +powerpc/powerpc/minidump_machdep.c optional powerpc64 powerpc/powerpc/mmu_if.m standard powerpc/powerpc/mp_machdep.c optional smp powerpc/powerpc/nexus.c standard Modified: head/sys/kern/kern_dump.c ============================================================================== --- head/sys/kern/kern_dump.c Mon Oct 14 13:02:49 2019 (r353488) +++ head/sys/kern/kern_dump.c Mon Oct 14 13:04:04 2019 (r353489) @@ -292,7 +292,7 @@ dumpsys_generic(struct dumperinfo *di) size_t hdrsz; int error; -#ifndef __powerpc__ +#if !defined(__powerpc__) || defined(__powerpc64__) if (do_minidump) return (minidumpsys(di)); #endif Modified: head/sys/powerpc/aim/mmu_oea64.c ============================================================================== --- head/sys/powerpc/aim/mmu_oea64.c Mon Oct 14 13:02:49 2019 (r353488) +++ head/sys/powerpc/aim/mmu_oea64.c Mon Oct 14 13:04:04 2019 (r353489) @@ -307,6 +307,8 @@ static int moea64_map_user_ptr(mmu_t mmu, pmap_t pm, volatile const void *uaddr, void **kaddr, size_t ulen, size_t *klen); static int moea64_decode_kernel_ptr(mmu_t mmu, vm_offset_t addr, int *is_user, vm_offset_t *decoded_addr); +static size_t moea64_scan_pmap(mmu_t mmu); +static void *moea64_dump_pmap_init(mmu_t mmu, unsigned blkpgs); static mmu_method_t moea64_methods[] = { @@ -356,6 +358,8 @@ static mmu_method_t moea64_methods[] = { MMUMETHOD(mmu_kenter_attr, moea64_kenter_attr), MMUMETHOD(mmu_dev_direct_mapped,moea64_dev_direct_mapped), MMUMETHOD(mmu_scan_init, moea64_scan_init), + MMUMETHOD(mmu_scan_pmap, moea64_scan_pmap), + MMUMETHOD(mmu_dump_pmap_init, moea64_dump_pmap_init), MMUMETHOD(mmu_dumpsys_map, moea64_dumpsys_map), MMUMETHOD(mmu_map_user_ptr, moea64_map_user_ptr), MMUMETHOD(mmu_decode_kernel_ptr, moea64_decode_kernel_ptr), @@ -798,6 +802,8 @@ moea64_early_bootstrap(mmu_t mmup, vm_offset_t kernels hwphyssz - physsz; physsz = hwphyssz; phys_avail_count++; + dump_avail[j] = phys_avail[j]; + dump_avail[j + 1] = phys_avail[j + 1]; } break; } @@ -805,6 +811,8 @@ moea64_early_bootstrap(mmu_t mmup, vm_offset_t kernels phys_avail[j + 1] = regions[i].mr_start + regions[i].mr_size; phys_avail_count++; physsz += regions[i].mr_size; + dump_avail[j] = phys_avail[j]; + dump_avail[j + 1] = phys_avail[j + 1]; } /* Check for overlap with the kernel and exception vectors */ @@ -982,7 +990,7 @@ moea64_late_bootstrap(mmu_t mmup, vm_offset_t kernelst * Set the start and end of kva. */ virtual_avail = VM_MIN_KERNEL_ADDRESS; - virtual_end = VM_MAX_SAFE_KERNEL_ADDRESS; + virtual_end = VM_MAX_SAFE_KERNEL_ADDRESS; /* * Map the entire KVA range into the SLB. We must not fault there. @@ -1056,6 +1064,9 @@ moea64_late_bootstrap(mmu_t mmup, vm_offset_t kernelst } dpcpu_init(dpcpu, curcpu); + crashdumpmap = (caddr_t)virtual_avail; + virtual_avail += MAXDUMPPGS * PAGE_SIZE; + /* * Allocate some things for page zeroing. We put this directly * in the page table and use MOEA64_PTE_REPLACE to avoid any @@ -2932,3 +2943,69 @@ moea64_scan_init(mmu_t mmu) } } +static size_t +moea64_scan_pmap(mmu_t mmu) +{ + struct pvo_entry *pvo; + vm_paddr_t pa, pa_end; + vm_offset_t va, pgva, kstart, kend, kstart_lp, kend_lp; + uint64_t lpsize; + + lpsize = moea64_large_page_size; + kstart = trunc_page((vm_offset_t)_etext); + kend = round_page((vm_offset_t)_end); + kstart_lp = kstart & ~moea64_large_page_mask; + kend_lp = (kend + moea64_large_page_mask) & ~moea64_large_page_mask; + + CTR4(KTR_PMAP, "moea64_scan_pmap: kstart=0x%016lx, kend=0x%016lx, " + "kstart_lp=0x%016lx, kend_lp=0x%016lx", + kstart, kend, kstart_lp, kend_lp); + + PMAP_LOCK(kernel_pmap); + RB_FOREACH(pvo, pvo_tree, &kernel_pmap->pmap_pvo) { + va = pvo->pvo_vaddr; + + if (va & PVO_DEAD) + continue; + + /* Skip DMAP (except kernel area) */ + if (va >= DMAP_BASE_ADDRESS && va <= DMAP_MAX_ADDRESS) { + if (va & PVO_LARGE) { + pgva = va & ~moea64_large_page_mask; + if (pgva < kstart_lp || pgva >= kend_lp) + continue; + } else { + pgva = trunc_page(va); + if (pgva < kstart || pgva >= kend) + continue; + } + } + + pa = pvo->pvo_pte.pa & LPTE_RPGN; + + if (va & PVO_LARGE) { + pa_end = pa + lpsize; + for (; pa < pa_end; pa += PAGE_SIZE) { + if (is_dumpable(pa)) + dump_add_page(pa); + } + } else { + if (is_dumpable(pa)) + dump_add_page(pa); + } + } + PMAP_UNLOCK(kernel_pmap); + + return (sizeof(struct lpte) * moea64_pteg_count * 8); +} + +static struct dump_context dump_ctx; + +static void * +moea64_dump_pmap_init(mmu_t mmu, unsigned blkpgs) +{ + dump_ctx.ptex = 0; + dump_ctx.ptex_end = moea64_pteg_count * 8; + dump_ctx.blksz = blkpgs * PAGE_SIZE; + return (&dump_ctx); +} Modified: head/sys/powerpc/aim/mmu_oea64.h ============================================================================== --- head/sys/powerpc/aim/mmu_oea64.h Mon Oct 14 13:02:49 2019 (r353488) +++ head/sys/powerpc/aim/mmu_oea64.h Mon Oct 14 13:04:04 2019 (r353489) @@ -34,6 +34,12 @@ #include <machine/mmuvar.h> +struct dump_context { + u_long ptex; + u_long ptex_end; + size_t blksz; +}; + extern mmu_def_t oea64_mmu; /* Modified: head/sys/powerpc/include/dump.h ============================================================================== --- head/sys/powerpc/include/dump.h Mon Oct 14 13:02:49 2019 (r353488) +++ head/sys/powerpc/include/dump.h Mon Oct 14 13:04:04 2019 (r353489) @@ -37,6 +37,9 @@ void dumpsys_pa_init(void); void dumpsys_unmap_chunk(vm_paddr_t, size_t, void *); +size_t dumpsys_scan_pmap(void); +void *dumpsys_dump_pmap_init(unsigned blkpgs); +void *dumpsys_dump_pmap(void *ctx, void *buf, u_long *nbytes); static inline struct dump_pa * dumpsys_pa_next(struct dump_pa *p) Modified: head/sys/powerpc/include/md_var.h ============================================================================== --- head/sys/powerpc/include/md_var.h Mon Oct 14 13:02:49 2019 (r353488) +++ head/sys/powerpc/include/md_var.h Mon Oct 14 13:04:04 2019 (r353489) @@ -41,6 +41,15 @@ extern int szsigcode32; #ifdef __powerpc64__ extern char sigcode64[], sigcode64_elfv2[]; extern int szsigcode64, szsigcode64_elfv2; + +extern uint64_t *vm_page_dump; +extern int vm_page_dump_size; + +struct dumperinfo; +int minidumpsys(struct dumperinfo *); +int is_dumpable(vm_paddr_t); +void dump_add_page(vm_paddr_t); +void dump_drop_page(vm_paddr_t); #endif extern long Maxmem; Added: head/sys/powerpc/include/minidump.h ============================================================================== --- /dev/null 00:00:00 1970 (empty, because file is newly added) +++ head/sys/powerpc/include/minidump.h Mon Oct 14 13:04:04 2019 (r353489) @@ -0,0 +1,52 @@ +/*- + * Copyright (c) 2006 Peter Wemm + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * From i386: FreeBSD: 157909 2006-04-21 04:28:43Z peter + * $FreeBSD$ + */ + +#ifndef _MACHINE_MINIDUMP_H_ +#define _MACHINE_MINIDUMP_H_ 1 + +#define MINIDUMP_MAGIC "minidump FreeBSD/powerpc64" +#define MINIDUMP_VERSION 1 + +struct minidumphdr { + char magic[32]; + char mmu_name[32]; + uint32_t version; + uint32_t msgbufsize; + uint32_t bitmapsize; + uint32_t pmapsize; + uint64_t kernbase; + uint64_t kernend; + uint64_t dmapbase; + uint64_t dmapend; + int hw_direct_map; + uint64_t startkernel; + uint64_t endkernel; +}; + +#endif /* _MACHINE_MINIDUMP_H_ */ Modified: head/sys/powerpc/include/pmap.h ============================================================================== --- head/sys/powerpc/include/pmap.h Mon Oct 14 13:02:49 2019 (r353488) +++ head/sys/powerpc/include/pmap.h Mon Oct 14 13:04:04 2019 (r353489) @@ -266,11 +266,13 @@ void pmap_deactivate(struct thread *); vm_paddr_t pmap_kextract(vm_offset_t); int pmap_dev_direct_mapped(vm_paddr_t, vm_size_t); boolean_t pmap_mmu_install(char *name, int prio); +const char *pmap_mmu_name(void); #define vtophys(va) pmap_kextract((vm_offset_t)(va)) extern vm_offset_t virtual_avail; extern vm_offset_t virtual_end; +extern caddr_t crashdumpmap; extern vm_offset_t msgbuf_phys; Added: head/sys/powerpc/powerpc/minidump_machdep.c ============================================================================== --- /dev/null 00:00:00 1970 (empty, because file is newly added) +++ head/sys/powerpc/powerpc/minidump_machdep.c Mon Oct 14 13:04:04 2019 (r353489) @@ -0,0 +1,442 @@ +/*- + * Copyright (c) 2019 Leandro Lupori + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * $FreeBSD$ + */ + +#include <sys/types.h> +#include <sys/param.h> + +#include <sys/cons.h> +#include <sys/kerneldump.h> +#include <sys/msgbuf.h> +#include <sys/proc.h> +#include <sys/sysctl.h> + +#include <vm/vm.h> +#include <vm/vm_param.h> +#include <vm/vm_page.h> +#include <vm/vm_phys.h> +#include <vm/pmap.h> + +#include <machine/atomic.h> +#include <machine/dump.h> +#include <machine/md_var.h> +#include <machine/minidump.h> + +/* + * bit to physical address + * + * bm - bitmap + * i - bitmap entry index + * bit - bit number + */ +#define BTOP(bm, i, bit) \ + (((uint64_t)(i) * sizeof(*(bm)) * NBBY + (bit)) * PAGE_SIZE) + +/* Debugging stuff */ +#define MINIDUMP_DEBUG 0 +#if MINIDUMP_DEBUG +#define dprintf(fmt, ...) printf(fmt, ## __VA_ARGS__) +#define DBG(...) __VA_ARGS__ +static size_t total, dumptotal; +static void dump_total(const char *id, size_t sz); +#else +#define dprintf(fmt, ...) +#define DBG(...) +#define dump_total(...) +#endif + + +extern vm_offset_t __startkernel, __endkernel; + +int vm_page_dump_size; +uint64_t *vm_page_dump; + +static int dump_retry_count = 5; +SYSCTL_INT(_machdep, OID_AUTO, dump_retry_count, CTLFLAG_RWTUN, + &dump_retry_count, 0, + "Number of times dump has to retry before bailing out"); + +static struct kerneldumpheader kdh; +static char pgbuf[PAGE_SIZE]; + +static struct { + int min_per; + int max_per; + int visited; +} progress_track[10] = { + { 0, 10, 0}, + { 10, 20, 0}, + { 20, 30, 0}, + { 30, 40, 0}, + { 40, 50, 0}, + { 50, 60, 0}, + { 60, 70, 0}, + { 70, 80, 0}, + { 80, 90, 0}, + { 90, 100, 0} +}; + +static size_t counter, dumpsize, progress; + +/* Handle chunked writes. */ +static size_t fragsz; + +void +dump_add_page(vm_paddr_t pa) +{ + int idx, bit; + + pa >>= PAGE_SHIFT; + idx = pa >> 6; /* 2^6 = 64 */ + bit = pa & 63; + atomic_set_long(&vm_page_dump[idx], 1ul << bit); +} + +void +dump_drop_page(vm_paddr_t pa) +{ + int idx, bit; + + pa >>= PAGE_SHIFT; + idx = pa >> 6; /* 2^6 = 64 */ + bit = pa & 63; + atomic_clear_long(&vm_page_dump[idx], 1ul << bit); +} + +int +is_dumpable(vm_paddr_t pa) +{ + vm_page_t m; + int i; + + if ((m = vm_phys_paddr_to_vm_page(pa)) != NULL) + return ((m->flags & PG_NODUMP) == 0); + for (i = 0; dump_avail[i] != 0 || dump_avail[i + 1] != 0; i += 2) { + if (pa >= dump_avail[i] && pa < dump_avail[i + 1]) + return (1); + } + return (0); +} + +static void +pmap_kenter_temporary(vm_offset_t va, vm_paddr_t pa) +{ + pmap_kremove(va); + pmap_kenter(va, pa); +} + +static void +report_progress(void) +{ + int sofar, i; + + sofar = 100 - ((progress * 100) / dumpsize); + for (i = 0; i < nitems(progress_track); i++) { + if (sofar < progress_track[i].min_per || + sofar > progress_track[i].max_per) + continue; + if (progress_track[i].visited) + return; + progress_track[i].visited = 1; + printf("..%d%%", sofar); + return; + } +} + +static int +blk_flush(struct dumperinfo *di) +{ + int error; + + if (fragsz == 0) + return (0); + + error = dump_append(di, crashdumpmap, 0, fragsz); + DBG(dumptotal += fragsz;) + fragsz = 0; + return (error); +} + +static int +blk_write(struct dumperinfo *di, char *ptr, vm_paddr_t pa, size_t sz) +{ + size_t len, maxdumpsz; + int error, i, c; + + maxdumpsz = MIN(di->maxiosize, MAXDUMPPGS * PAGE_SIZE); + if (maxdumpsz == 0) /* seatbelt */ + maxdumpsz = PAGE_SIZE; + error = 0; + if ((sz % PAGE_SIZE) != 0) { + printf("Size not page aligned\n"); + return (EINVAL); + } + if (ptr != NULL && pa != 0) { + printf("Can't have both va and pa!\n"); + return (EINVAL); + } + if ((pa % PAGE_SIZE) != 0) { + printf("Address not page aligned 0x%lx\n", pa); + return (EINVAL); + } + if (ptr != NULL) { + /* + * If we're doing a virtual dump, flush any pre-existing + * pa pages + */ + error = blk_flush(di); + if (error) + return (error); + } + while (sz) { + len = maxdumpsz - fragsz; + if (len > sz) + len = sz; + counter += len; + progress -= len; + if (counter >> 20) { + report_progress(); + counter &= (1<<20) - 1; + } + + if (ptr) { + error = dump_append(di, ptr, 0, len); + if (error) + return (error); + DBG(dumptotal += len;) + ptr += len; + } else { + for (i = 0; i < len; i += PAGE_SIZE) + pmap_kenter_temporary( + (vm_offset_t)crashdumpmap + fragsz + i, + pa + i); + + fragsz += len; + pa += len; + if (fragsz == maxdumpsz) { + error = blk_flush(di); + if (error) + return (error); + } + } + sz -= len; + + /* Check for user abort. */ + c = cncheckc(); + if (c == 0x03) + return (ECANCELED); + if (c != -1) + printf(" (CTRL-C to abort) "); + } + + return (0); +} + +static int +dump_pmap(struct dumperinfo *di) +{ + void *ctx; + char *buf; + u_long nbytes; + int error; + + ctx = dumpsys_dump_pmap_init(sizeof(pgbuf) / PAGE_SIZE); + + for (;;) { + buf = dumpsys_dump_pmap(ctx, pgbuf, &nbytes); + if (buf == NULL) + break; + error = blk_write(di, buf, 0, nbytes); + if (error) + return (error); + } + + return (0); +} + +int +minidumpsys(struct dumperinfo *di) +{ + vm_paddr_t pa; + int bit, error, i, retry_count; + uint32_t pmapsize; + uint64_t bits; + struct minidumphdr mdhdr; + + retry_count = 0; +retry: + retry_count++; + fragsz = 0; + DBG(total = dumptotal = 0;) + + /* Reset progress */ + counter = 0; + for (i = 0; i < nitems(progress_track); i++) + progress_track[i].visited = 0; + + /* Build set of dumpable pages from kernel pmap */ + pmapsize = dumpsys_scan_pmap(); + if (pmapsize % PAGE_SIZE != 0) { + printf("pmapsize not page aligned: 0x%x\n", pmapsize); + return (EINVAL); + } + + /* Calculate dump size */ + dumpsize = PAGE_SIZE; /* header */ + dumpsize += round_page(msgbufp->msg_size); + dumpsize += round_page(vm_page_dump_size); + dumpsize += pmapsize; + for (i = 0; i < vm_page_dump_size / sizeof(*vm_page_dump); i++) { + bits = vm_page_dump[i]; + /* TODO optimize with bit manipulation instructions */ + if (bits == 0) + continue; + for (bit = 0; bit < 64; bit++) { + if ((bits & (1ul<<bit)) == 0) + continue; + + pa = BTOP(vm_page_dump, i, bit); + /* Clear out undumpable pages now if needed */ + if (is_dumpable(pa)) + dumpsize += PAGE_SIZE; + else + dump_drop_page(pa); + } + } + progress = dumpsize; + + /* Initialize mdhdr */ + bzero(&mdhdr, sizeof(mdhdr)); + strcpy(mdhdr.magic, MINIDUMP_MAGIC); + strncpy(mdhdr.mmu_name, pmap_mmu_name(), sizeof(mdhdr.mmu_name) - 1); + mdhdr.version = MINIDUMP_VERSION; + mdhdr.msgbufsize = msgbufp->msg_size; + mdhdr.bitmapsize = vm_page_dump_size; + mdhdr.pmapsize = pmapsize; + mdhdr.kernbase = VM_MIN_KERNEL_ADDRESS; + mdhdr.kernend = VM_MAX_SAFE_KERNEL_ADDRESS; + mdhdr.dmapbase = DMAP_BASE_ADDRESS; + mdhdr.dmapend = DMAP_MAX_ADDRESS; + mdhdr.hw_direct_map = hw_direct_map; + mdhdr.startkernel = __startkernel; + mdhdr.endkernel = __endkernel; + + dump_init_header(di, &kdh, KERNELDUMPMAGIC, KERNELDUMP_POWERPC_VERSION, + dumpsize); + + error = dump_start(di, &kdh); + if (error) + goto fail; + + printf("Dumping %lu out of %ju MB:", dumpsize >> 20, + ptoa((uintmax_t)physmem) / 1048576); + + /* Dump minidump header */ + bzero(pgbuf, sizeof(pgbuf)); + memcpy(pgbuf, &mdhdr, sizeof(mdhdr)); + error = blk_write(di, pgbuf, 0, PAGE_SIZE); + if (error) + goto fail; + dump_total("header", PAGE_SIZE); + + /* Dump msgbuf up front */ + error = blk_write(di, (char *)msgbufp->msg_ptr, 0, + round_page(msgbufp->msg_size)); + dump_total("msgbuf", round_page(msgbufp->msg_size)); + + /* Dump bitmap */ + error = blk_write(di, (char *)vm_page_dump, 0, + round_page(vm_page_dump_size)); + if (error) + goto fail; + dump_total("bitmap", round_page(vm_page_dump_size)); + + /* Dump kernel page directory pages */ + error = dump_pmap(di); + if (error) + goto fail; + dump_total("pmap", pmapsize); + + /* Dump memory chunks */ + /* XXX cluster it up and use blk_dump() */ + for (i = 0; i < vm_page_dump_size / sizeof(*vm_page_dump); i++) { + bits = vm_page_dump[i]; + /* TODO optimize with bit manipulation instructions */ + if (bits == 0) + continue; + for (bit = 0; bit < 64; bit++) { + if ((bits & (1ul<<bit)) == 0) + continue; + + pa = BTOP(vm_page_dump, i, bit); + error = blk_write(di, 0, pa, PAGE_SIZE); + if (error) + goto fail; + } + } + + error = blk_flush(di); + if (error) + goto fail; + dump_total("mem_chunks", dumpsize - total); + + error = dump_finish(di, &kdh); + if (error) + goto fail; + + printf("\nDump complete\n"); + return (0); + +fail: + if (error < 0) + error = -error; + + printf("\n"); + if (error == ENOSPC) { + printf("Dump map grown while dumping. "); + if (retry_count < dump_retry_count) { + printf("Retrying...\n"); + goto retry; + } + printf("Dump failed.\n"); + } else if (error == ECANCELED) + printf("Dump aborted\n"); + else if (error == E2BIG) + printf("Dump failed. Partition too small.\n"); + else + printf("** DUMP FAILED (ERROR %d) **\n", error); + return (error); +} + +#if MINIDUMP_DEBUG +static void +dump_total(const char *id, size_t sz) +{ + total += sz; + dprintf("\n%s=%08lx/%08lx/%08lx\n", + id, sz, total, dumptotal); +} +#endif Modified: head/sys/powerpc/powerpc/mmu_if.m ============================================================================== --- head/sys/powerpc/powerpc/mmu_if.m Mon Oct 14 13:02:49 2019 (r353488) +++ head/sys/powerpc/powerpc/mmu_if.m Mon Oct 14 13:04:04 2019 (r353489) @@ -130,6 +130,22 @@ CODE { { return (0); } + + static size_t mmu_null_scan_pmap(mmu_t mmu) + { + return (0); + } + + static void *mmu_null_dump_pmap_init(mmu_t mmu, unsigned blkpgs) + { + return (NULL); + } + + static void * mmu_null_dump_pmap(mmu_t mmu, void *ctx, void *buf, + u_long *nbytes) + { + return (NULL); + } }; @@ -973,6 +989,51 @@ METHOD void dumpsys_unmap { METHOD void scan_init { mmu_t _mmu; }; + +/** + * @brief Scan kernel PMAP, adding mapped physical pages to dump. + * + * @retval pmap_size Number of bytes used by all PTE entries. + */ +METHOD size_t scan_pmap { + mmu_t _mmu; +} DEFAULT mmu_null_scan_pmap; + +/** + * @brief Initialize a PMAP dump. + * + * @param _blkpgs Size of a dump block, in pages. + * + * @retval ctx Dump context, used by dump_pmap. + */ +METHOD void * dump_pmap_init { + mmu_t _mmu; + unsigned _blkpgs; +} DEFAULT mmu_null_dump_pmap_init; + +/** + * @brief Dump a block of PTEs. + * The size of the dump block is specified in dump_pmap_init and + * the 'buf' argument must be big enough to hold a full block. + * If the page table resides in regular memory, then the 'buf' + * argument is ignored and a pointer to the specified dump block + * is returned instead, avoiding memory copy. Else, the buffer is + * filled with PTEs and the own buffer pointer is returned. + * In the end, the cursor in 'ctx' is adjusted to point to the next block. + * + * @param _ctx Dump context, retrieved from dump_pmap_init. + * @param _buf Buffer to hold the dump block contents. + * @param _nbytes Number of bytes dumped. + * + * @retval NULL No more blocks to dump. + * @retval buf Pointer to dumped data (may be different than _buf). + */ +METHOD void * dump_pmap { + mmu_t _mmu; + void *_ctx; + void *_buf; + u_long *_nbytes; +} DEFAULT mmu_null_dump_pmap; /** * @brief Create a temporary thread-local KVA mapping of a single page. Modified: head/sys/powerpc/powerpc/pmap_dispatch.c ============================================================================== --- head/sys/powerpc/powerpc/pmap_dispatch.c Mon Oct 14 13:02:49 2019 (r353488) +++ head/sys/powerpc/powerpc/pmap_dispatch.c Mon Oct 14 13:04:04 2019 (r353489) @@ -77,6 +77,7 @@ vm_offset_t msgbuf_phys; vm_offset_t kernel_vm_end; vm_offset_t virtual_avail; vm_offset_t virtual_end; +caddr_t crashdumpmap; int pmap_bootstrapped; @@ -567,6 +568,27 @@ dumpsys_pa_init(void) return (MMU_SCAN_INIT(mmu_obj)); } +size_t +dumpsys_scan_pmap(void) +{ + CTR1(KTR_PMAP, "%s()", __func__); + return (MMU_SCAN_PMAP(mmu_obj)); +} + +void * +dumpsys_dump_pmap_init(unsigned blkpgs) +{ + CTR1(KTR_PMAP, "%s()", __func__); + return (MMU_DUMP_PMAP_INIT(mmu_obj, blkpgs)); +} + +void * +dumpsys_dump_pmap(void *ctx, void *buf, u_long *nbytes) +{ + CTR1(KTR_PMAP, "%s()", __func__); + return (MMU_DUMP_PMAP(mmu_obj, ctx, buf, nbytes)); +} + vm_offset_t pmap_quick_enter_page(vm_page_t m) { @@ -616,6 +638,12 @@ pmap_mmu_install(char *name, int prio) } return (FALSE); +} + +const char * +pmap_mmu_name(void) +{ + return (mmu_obj->ops->cls->name); } int unmapped_buf_allowed; Modified: head/sys/powerpc/powerpc/uma_machdep.c ============================================================================== --- head/sys/powerpc/powerpc/uma_machdep.c Mon Oct 14 13:02:49 2019 (r353488) +++ head/sys/powerpc/powerpc/uma_machdep.c Mon Oct 14 13:04:04 2019 (r353489) @@ -71,6 +71,9 @@ uma_small_alloc(uma_zone_t zone, vm_size_t bytes, int if ((vm_offset_t)pa != pa) return (NULL); + if ((wait & M_NODUMP) == 0) + dump_add_page(pa); + if (!hw_direct_map) { pmap_kenter(pa, pa); va = (void *)(vm_offset_t)pa; @@ -100,6 +103,7 @@ uma_small_free(void *mem, vm_size_t size, u_int8_t fla m = PHYS_TO_VM_PAGE((vm_offset_t)mem); KASSERT(m != NULL, ("Freeing UMA block at %p with no associated page", mem)); + dump_add_page(VM_PAGE_TO_PHYS(m)); vm_page_unwire_noq(m); vm_page_free(m); atomic_subtract_int(&hw_uma_mdpages, 1); Modified: head/sys/powerpc/pseries/mmu_phyp.c ============================================================================== --- head/sys/powerpc/pseries/mmu_phyp.c Mon Oct 14 13:02:49 2019 (r353488) +++ head/sys/powerpc/pseries/mmu_phyp.c Mon Oct 14 13:04:04 2019 (r353489) @@ -78,6 +78,8 @@ static struct rmlock mphyp_eviction_lock; static void mphyp_bootstrap(mmu_t mmup, vm_offset_t kernelstart, vm_offset_t kernelend); static void mphyp_cpu_bootstrap(mmu_t mmup, int ap); +static void *mphyp_dump_pmap(mmu_t mmu, void *ctx, void *buf, + u_long *nbytes); static int64_t mphyp_pte_synch(mmu_t, struct pvo_entry *pvo); static int64_t mphyp_pte_clear(mmu_t, struct pvo_entry *pvo, uint64_t ptebit); static int64_t mphyp_pte_unset(mmu_t, struct pvo_entry *pvo); @@ -86,6 +88,7 @@ static int mphyp_pte_insert(mmu_t, struct pvo_entry *p static mmu_method_t mphyp_methods[] = { MMUMETHOD(mmu_bootstrap, mphyp_bootstrap), MMUMETHOD(mmu_cpu_bootstrap, mphyp_cpu_bootstrap), + MMUMETHOD(mmu_dump_pmap, mphyp_dump_pmap), MMUMETHOD(moea64_pte_synch, mphyp_pte_synch), MMUMETHOD(moea64_pte_clear, mphyp_pte_clear), @@ -505,3 +508,32 @@ mphyp_pte_insert(mmu_t mmu, struct pvo_entry *pvo) return (result); } +static void * +mphyp_dump_pmap(mmu_t mmu, void *ctx, void *buf, u_long *nbytes) +{ + struct dump_context *dctx; + struct lpte p, *pbuf; + int bufidx; + uint64_t junk; + u_long ptex, ptex_end; + + dctx = (struct dump_context *)ctx; + pbuf = (struct lpte *)buf; + bufidx = 0; + ptex = dctx->ptex; + ptex_end = ptex + dctx->blksz / sizeof(struct lpte); + ptex_end = MIN(ptex_end, dctx->ptex_end); + *nbytes = (ptex_end - ptex) * sizeof(struct lpte); + + if (*nbytes == 0) + return (NULL); + + for (; ptex < ptex_end; ptex++) { + phyp_pft_hcall(H_READ, 0, ptex, 0, 0, + &p.pte_hi, &p.pte_lo, &junk); + pbuf[bufidx++] = p; + } + + dctx->ptex = ptex; + return (buf); +} Modified: head/sys/vm/vm_page.c ============================================================================== --- head/sys/vm/vm_page.c Mon Oct 14 13:02:49 2019 (r353488) +++ head/sys/vm/vm_page.c Mon Oct 14 13:04:04 2019 (r353489) @@ -658,7 +658,8 @@ vm_page_startup(vm_offset_t vaddr) #endif #if defined(__aarch64__) || defined(__amd64__) || defined(__arm__) || \ - defined(__i386__) || defined(__mips__) || defined(__riscv) + defined(__i386__) || defined(__mips__) || defined(__riscv) || \ + defined(__powerpc64__) /* * Allocate a bitmap to indicate that a random physical page * needs to be included in a minidump. @@ -684,7 +685,7 @@ vm_page_startup(vm_offset_t vaddr) (void)last_pa; #endif #if defined(__aarch64__) || defined(__amd64__) || defined(__mips__) || \ - defined(__riscv) + defined(__riscv) || defined(__powerpc64__) /* * Include the UMA bootstrap pages, witness pages and vm_page_dump * in a crash dump. When pmap_map() uses the direct map, they are @@ -789,7 +790,7 @@ vm_page_startup(vm_offset_t vaddr) new_end = vm_reserv_startup(&vaddr, new_end); #endif #if defined(__aarch64__) || defined(__amd64__) || defined(__mips__) || \ - defined(__riscv) + defined(__riscv) || defined(__powerpc64__) /* * Include vm_page_array and vm_reserv_array in a crash dump. */
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201910141304.x9ED44nv010510>