Date: Thu, 27 Jun 2019 16:48:24 +0000 (UTC) From: Mark Johnston <markj@FreeBSD.org> To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-12@freebsd.org Subject: svn commit: r349463 - in stable/12: lib/libkvm sys/riscv/riscv sys/vm Message-ID: <201906271648.x5RGmOHO022405@repo.freebsd.org>
next in thread | raw e-mail | index | archive | help
Author: markj Date: Thu Jun 27 16:48:24 2019 New Revision: 349463 URL: https://svnweb.freebsd.org/changeset/base/349463 Log: MFC r344827-344830, r344845: Implement minidump support for RISC-V. Added: stable/12/lib/libkvm/kvm_minidump_riscv.c - copied unchanged from r344829, head/lib/libkvm/kvm_minidump_riscv.c stable/12/lib/libkvm/kvm_riscv.h - copied, changed from r344829, head/lib/libkvm/kvm_riscv.h Modified: stable/12/lib/libkvm/Makefile stable/12/sys/riscv/riscv/minidump_machdep.c stable/12/sys/riscv/riscv/pmap.c stable/12/sys/riscv/riscv/uma_machdep.c stable/12/sys/vm/vm_page.c Directory Properties: stable/12/ (props changed) Modified: stable/12/lib/libkvm/Makefile ============================================================================== --- stable/12/lib/libkvm/Makefile Thu Jun 27 16:30:25 2019 (r349462) +++ stable/12/lib/libkvm/Makefile Thu Jun 27 16:48:24 2019 (r349463) @@ -18,6 +18,7 @@ SRCS= kvm.c kvm_cptime.c kvm_getloadavg.c \ kvm_i386.c kvm_minidump_i386.c \ kvm_minidump_mips.c \ kvm_powerpc.c kvm_powerpc64.c \ + kvm_minidump_riscv.c \ kvm_sparc64.c INCS= kvm.h Copied: stable/12/lib/libkvm/kvm_minidump_riscv.c (from r344829, head/lib/libkvm/kvm_minidump_riscv.c) ============================================================================== --- /dev/null 00:00:00 1970 (empty, because file is newly added) +++ stable/12/lib/libkvm/kvm_minidump_riscv.c Thu Jun 27 16:48:24 2019 (r349463, copy of r344829, head/lib/libkvm/kvm_minidump_riscv.c) @@ -0,0 +1,288 @@ +/*- + * Copyright (c) 2006 Peter Wemm + * Copyright (c) 2019 Mitchell Horne + * + * 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 AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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: FreeBSD: src/lib/libkvm/kvm_minidump_amd64.c r261799 + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +/* + * RISC-V machine dependent routines for kvm and minidumps. + */ + +#include <sys/param.h> +#include <stdint.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <vm/vm.h> +#include <kvm.h> + +#include "../../sys/riscv/include/minidump.h" + +#include <limits.h> + +#include "kvm_private.h" +#include "kvm_riscv.h" + +#define riscv_round_page(x) roundup2((kvaddr_t)(x), RISCV_PAGE_SIZE) + +struct vmstate { + struct minidumphdr hdr; +}; + +static riscv_pt_entry_t +_riscv_pte_get(kvm_t *kd, u_long pteindex) +{ + riscv_pt_entry_t *pte = _kvm_pmap_get(kd, pteindex, sizeof(*pte)); + + return le64toh(*pte); +} + +static int +_riscv_minidump_probe(kvm_t *kd) +{ + + return (_kvm_probe_elf_kernel(kd, ELFCLASS64, EM_RISCV) && + _kvm_is_minidump(kd)); +} + +static void +_riscv_minidump_freevtop(kvm_t *kd) +{ + struct vmstate *vm = kd->vmst; + + free(vm); + kd->vmst = NULL; +} + +static int +_riscv_minidump_initvtop(kvm_t *kd) +{ + struct vmstate *vmst; + off_t off, sparse_off; + + vmst = _kvm_malloc(kd, sizeof(*vmst)); + if (vmst == NULL) { + _kvm_err(kd, kd->program, "cannot allocate vm"); + return (-1); + } + kd->vmst = vmst; + if (pread(kd->pmfd, &vmst->hdr, sizeof(vmst->hdr), 0) != + sizeof(vmst->hdr)) { + _kvm_err(kd, kd->program, "cannot read dump header"); + return (-1); + } + if (strncmp(MINIDUMP_MAGIC, vmst->hdr.magic, + sizeof(vmst->hdr.magic)) != 0) { + _kvm_err(kd, kd->program, "not a minidump for this platform"); + return (-1); + } + + vmst->hdr.version = le32toh(vmst->hdr.version); + if (vmst->hdr.version != MINIDUMP_VERSION) { + _kvm_err(kd, kd->program, "wrong minidump version. " + "Expected %d got %d", MINIDUMP_VERSION, vmst->hdr.version); + return (-1); + } + vmst->hdr.msgbufsize = le32toh(vmst->hdr.msgbufsize); + vmst->hdr.bitmapsize = le32toh(vmst->hdr.bitmapsize); + vmst->hdr.pmapsize = le32toh(vmst->hdr.pmapsize); + vmst->hdr.kernbase = le64toh(vmst->hdr.kernbase); + vmst->hdr.dmapphys = le64toh(vmst->hdr.dmapphys); + vmst->hdr.dmapbase = le64toh(vmst->hdr.dmapbase); + vmst->hdr.dmapend = le64toh(vmst->hdr.dmapend); + + /* Skip header and msgbuf */ + off = RISCV_PAGE_SIZE + riscv_round_page(vmst->hdr.msgbufsize); + + /* build physical address lookup table for sparse pages */ + sparse_off = off + riscv_round_page(vmst->hdr.bitmapsize) + + riscv_round_page(vmst->hdr.pmapsize); + if (_kvm_pt_init(kd, vmst->hdr.bitmapsize, off, sparse_off, + RISCV_PAGE_SIZE, sizeof(uint64_t)) == -1) { + return (-1); + } + off += riscv_round_page(vmst->hdr.bitmapsize); + + if (_kvm_pmap_init(kd, vmst->hdr.pmapsize, off) == -1) { + return (-1); + } + off += riscv_round_page(vmst->hdr.pmapsize); + + return (0); +} + +static int +_riscv_minidump_vatop(kvm_t *kd, kvaddr_t va, off_t *pa) +{ + struct vmstate *vm; + riscv_physaddr_t offset; + riscv_pt_entry_t l3; + kvaddr_t l3_index; + riscv_physaddr_t a; + off_t ofs; + + vm = kd->vmst; + offset = va & RISCV_PAGE_MASK; + + if (va >= vm->hdr.dmapbase && va < vm->hdr.dmapend) { + a = (va - vm->hdr.dmapbase + vm->hdr.dmapphys) & + ~RISCV_PAGE_MASK; + ofs = _kvm_pt_find(kd, a, RISCV_PAGE_SIZE); + if (ofs == -1) { + _kvm_err(kd, kd->program, "_riscv_minidump_vatop: " + "direct map address 0x%jx not in minidump", + (uintmax_t)va); + goto invalid; + } + *pa = ofs + offset; + return (RISCV_PAGE_SIZE - offset); + } else if (va >= vm->hdr.kernbase) { + l3_index = (va - vm->hdr.kernbase) >> RISCV_L3_SHIFT; + if (l3_index >= vm->hdr.pmapsize / sizeof(l3)) + goto invalid; + l3 = _riscv_pte_get(kd, l3_index); + if ((l3 & RISCV_PTE_V) == 0 || (l3 & RISCV_PTE_RWX) == 0) { + _kvm_err(kd, kd->program, + "_riscv_minidump_vatop: pte not valid"); + goto invalid; + } + a = (l3 >> RISCV_PTE_PPN0_S) << RISCV_L3_SHIFT; + ofs = _kvm_pt_find(kd, a, RISCV_PAGE_SIZE); + if (ofs == -1) { + _kvm_err(kd, kd->program, "_riscv_minidump_vatop: " + "physical address 0x%jx not in minidump", + (uintmax_t)a); + goto invalid; + } + *pa = ofs + offset; + return (RISCV_PAGE_SIZE - offset); + } else { + _kvm_err(kd, kd->program, + "_riscv_minidump_vatop: virtual address 0x%jx not minidumped", + (uintmax_t)va); + goto invalid; + } + +invalid: + _kvm_err(kd, 0, "invalid address (0x%jx)", (uintmax_t)va); + return (0); +} + +static int +_riscv_minidump_kvatop(kvm_t *kd, kvaddr_t va, off_t *pa) +{ + + if (ISALIVE(kd)) { + _kvm_err(kd, 0, + "_riscv_minidump_kvatop called in live kernel!"); + return (0); + } + return (_riscv_minidump_vatop(kd, va, pa)); +} + +static int +_riscv_native(kvm_t *kd __unused) +{ + +#ifdef __riscv + return (1); +#else + return (0); +#endif +} + +static vm_prot_t +_riscv_entry_to_prot(riscv_pt_entry_t pte) +{ + vm_prot_t prot = VM_PROT_READ; + + if ((pte & RISCV_PTE_W) != 0) + prot |= VM_PROT_WRITE; + if ((pte & RISCV_PTE_X) != 0) + prot |= VM_PROT_EXECUTE; + return prot; +} + +static int +_riscv_minidump_walk_pages(kvm_t *kd, kvm_walk_pages_cb_t *cb, void *arg) +{ + struct vmstate *vm = kd->vmst; + u_long nptes = vm->hdr.pmapsize / sizeof(riscv_pt_entry_t); + u_long bmindex, dva, pa, pteindex, va; + struct kvm_bitmap bm; + vm_prot_t prot; + int ret = 0; + + if (!_kvm_bitmap_init(&bm, vm->hdr.bitmapsize, &bmindex)) + return (0); + + for (pteindex = 0; pteindex < nptes; pteindex++) { + riscv_pt_entry_t pte = _riscv_pte_get(kd, pteindex); + + if (((pte & RISCV_PTE_V) == 0) || + ((pte & RISCV_PTE_RWX) == 0)) + continue; + + va = vm->hdr.kernbase + (pteindex << RISCV_L3_SHIFT); + pa = (pte >> RISCV_PTE_PPN0_S) << RISCV_L3_SHIFT; + dva = vm->hdr.dmapbase + pa; + if (!_kvm_visit_cb(kd, cb, arg, pa, va, dva, + _riscv_entry_to_prot(pte), RISCV_PAGE_SIZE, 0)) { + goto out; + } + } + + while (_kvm_bitmap_next(&bm, &bmindex)) { + pa = bmindex * RISCV_PAGE_SIZE; + dva = vm->hdr.dmapbase + pa; + if (vm->hdr.dmapend < (dva + RISCV_PAGE_SIZE)) + break; + va = 0; + prot = VM_PROT_READ | VM_PROT_WRITE; + if (!_kvm_visit_cb(kd, cb, arg, pa, va, dva, + prot, RISCV_PAGE_SIZE, 0)) { + goto out; + } + } + ret = 1; + +out: + _kvm_bitmap_deinit(&bm); + return (ret); +} + +static struct kvm_arch kvm_riscv_minidump = { + .ka_probe = _riscv_minidump_probe, + .ka_initvtop = _riscv_minidump_initvtop, + .ka_freevtop = _riscv_minidump_freevtop, + .ka_kvatop = _riscv_minidump_kvatop, + .ka_native = _riscv_native, + .ka_walk_pages = _riscv_minidump_walk_pages, +}; + +KVM_ARCH(kvm_riscv_minidump); Copied and modified: stable/12/lib/libkvm/kvm_riscv.h (from r344829, head/lib/libkvm/kvm_riscv.h) ============================================================================== --- head/lib/libkvm/kvm_riscv.h Tue Mar 5 23:59:55 2019 (r344829, copy source) +++ stable/12/lib/libkvm/kvm_riscv.h Thu Jun 27 16:48:24 2019 (r349463) @@ -1,7 +1,7 @@ /*- * Copyright (c) 2015 John H. Baldwin <jhb@FreeBSD.org> - * Copyright (c) 2019 Mitchell Horne * All rights reserved. + * Copyright (c) 2019 Mitchell Horne * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions Modified: stable/12/sys/riscv/riscv/minidump_machdep.c ============================================================================== --- stable/12/sys/riscv/riscv/minidump_machdep.c Thu Jun 27 16:30:25 2019 (r349462) +++ stable/12/sys/riscv/riscv/minidump_machdep.c Thu Jun 27 16:48:24 2019 (r349463) @@ -1,6 +1,8 @@ /*- * Copyright (c) 2006 Peter Wemm + * Copyright (c) 2015 The FreeBSD Foundation * All rights reserved. + * Copyright (c) 2019 Mitchell Horne * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -53,9 +55,381 @@ __FBSDID("$FreeBSD$"); CTASSERT(sizeof(struct kerneldumpheader) == 512); CTASSERT(sizeof(*vm_page_dump) == 8); +uint64_t *vm_page_dump; +int vm_page_dump_size; + +static struct kerneldumpheader kdh; + +/* Handle chunked writes. */ +static size_t fragsz; +static void *dump_va; +static size_t counter, progress, dumpsize; + +static uint64_t tmpbuffer[PAGE_SIZE / sizeof(uint64_t)]; + +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 void +report_progress(size_t progress, size_t dumpsize) +{ + 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 bool +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 (true); + } + return (false); +} + +static int +blk_flush(struct dumperinfo *di) +{ + int error; + + if (fragsz == 0) + return (0); + + error = dump_append(di, dump_va, 0, fragsz); + fragsz = 0; + return (error); +} + +/* + * Write a block of data to the dump file. + * + * Caller can provide data through a pointer or by specifying its + * physical address. + * + * XXX writes using pa should be no larger than PAGE_SIZE. + */ +static int +blk_write(struct dumperinfo *di, char *ptr, vm_paddr_t pa, size_t sz) +{ + size_t len; + int error, c; + u_int maxdumpsz; + + 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("cant have both va and pa!\n"); + return (EINVAL); + } + if ((((uintptr_t)pa) % PAGE_SIZE) != 0) { + printf("address not page aligned %#lx\n", (uintptr_t)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 != 0) + return (error); + } + while (sz) { + len = maxdumpsz - fragsz; + if (len > sz) + len = sz; + counter += len; + progress -= len; + if (counter >> 22) { + report_progress(progress, dumpsize); + counter &= (1 << 22) - 1; + } + + wdog_kern_pat(WD_LASTVAL); + + if (ptr) { + error = dump_append(di, ptr, 0, len); + if (error != 0) + return (error); + ptr += len; + sz -= len; + } else { + dump_va = (void *)PHYS_TO_DMAP(pa); + fragsz += len; + pa += len; + sz -= len; + error = blk_flush(di); + if (error != 0) + return (error); + } + + /* Check for user abort */ + c = cncheckc(); + if (c == 0x03) + return (ECANCELED); + if (c != -1) + printf(" (CTRL-C to abort) "); + } + + return (0); +} + int minidumpsys(struct dumperinfo *di) { + pd_entry_t *l1, *l2; + pt_entry_t *l3; + struct minidumphdr mdhdr; + uint32_t pmapsize; + vm_offset_t va; + vm_paddr_t pa; + int error; + uint64_t bits; + int i, bit; + int retry_count; - panic("minidumpsys"); + retry_count = 0; +retry: + retry_count++; + error = 0; + pmapsize = 0; + + /* Build set of dumpable pages from kernel pmap */ + for (va = VM_MIN_KERNEL_ADDRESS; va < kernel_vm_end; va += L2_SIZE) { + pmapsize += PAGE_SIZE; + if (!pmap_get_tables(pmap_kernel(), va, &l1, &l2, &l3)) + continue; + + /* We should always be using the l2 table for kvm */ + if (l2 == NULL) + continue; + + /* l2 may be a superpage */ + if ((*l2 & PTE_RWX) != 0) { + pa = (*l2 >> PTE_PPN1_S) << L2_SHIFT; + for (i = 0; i < Ln_ENTRIES; i++, pa += PAGE_SIZE) { + if (is_dumpable(pa)) + dump_add_page(pa); + } + } else { + for (i = 0; i < Ln_ENTRIES; i++) { + if ((l3[i] & PTE_V) == 0) + continue; + pa = (l3[i] >> PTE_PPN0_S) * PAGE_SIZE; + if (is_dumpable(pa)) + dump_add_page(pa); + } + } + } + + /* Calculate dump size */ + dumpsize = pmapsize; + dumpsize += round_page(msgbufp->msg_size); + dumpsize += round_page(vm_page_dump_size); + for (i = 0; i < vm_page_dump_size / sizeof(*vm_page_dump); i++) { + bits = vm_page_dump[i]; + while (bits) { + bit = ffsl(bits) - 1; + pa = (((uint64_t)i * sizeof(*vm_page_dump) * NBBY) + + bit) * PAGE_SIZE; + /* Clear out undumpable pages now if needed */ + if (is_dumpable(pa)) + dumpsize += PAGE_SIZE; + else + dump_drop_page(pa); + bits &= ~(1ul << bit); + } + } + dumpsize += PAGE_SIZE; + + progress = dumpsize; + + /* Initialize mdhdr */ + bzero(&mdhdr, sizeof(mdhdr)); + strcpy(mdhdr.magic, MINIDUMP_MAGIC); + mdhdr.version = MINIDUMP_VERSION; + mdhdr.msgbufsize = msgbufp->msg_size; + mdhdr.bitmapsize = vm_page_dump_size; + mdhdr.pmapsize = pmapsize; + mdhdr.kernbase = KERNBASE; + mdhdr.dmapphys = DMAP_MIN_PHYSADDR; + mdhdr.dmapbase = DMAP_MIN_ADDRESS; + mdhdr.dmapend = DMAP_MAX_ADDRESS; + + dump_init_header(di, &kdh, KERNELDUMPMAGIC, KERNELDUMP_RISCV_VERSION, + dumpsize); + + error = dump_start(di, &kdh); + if (error != 0) + goto fail; + + printf("Dumping %llu out of %ju MB:", (long long)dumpsize >> 20, + ptoa((uintmax_t)physmem) / 1048576); + + /* Dump minidump header */ + bzero(&tmpbuffer, sizeof(tmpbuffer)); + bcopy(&mdhdr, &tmpbuffer, sizeof(mdhdr)); + error = blk_write(di, (char *)&tmpbuffer, 0, PAGE_SIZE); + if (error) + goto fail; + + /* Dump msgbuf up front */ + error = blk_write(di, (char *)msgbufp->msg_ptr, 0, + round_page(msgbufp->msg_size)); + if (error) + goto fail; + + /* Dump bitmap */ + error = blk_write(di, (char *)vm_page_dump, 0, + round_page(vm_page_dump_size)); + if (error) + goto fail; + + /* Dump kernel page directory pages */ + bzero(&tmpbuffer, sizeof(tmpbuffer)); + for (va = VM_MIN_KERNEL_ADDRESS; va < kernel_vm_end; va += L2_SIZE) { + if (!pmap_get_tables(pmap_kernel(), va, &l1, &l2, &l3)) { + /* We always write a page, even if it is zero */ + error = blk_write(di, (char *)&tmpbuffer, 0, PAGE_SIZE); + if (error) + goto fail; + /* Flush, in case we reuse tmpbuffer in the same block */ + error = blk_flush(di); + if (error) + goto fail; + } else if ((*l2 & PTE_RWX) != 0) { + /* Generate fake l3 entries based on the l2 superpage */ + for (i = 0; i < Ln_ENTRIES; i++) { + tmpbuffer[i] = (*l2 | (i << PTE_PPN0_S)); + } + /* We always write a page, even if it is zero */ + error = blk_write(di, (char *)&tmpbuffer, 0, PAGE_SIZE); + if (error) + goto fail; + /* Flush, in case we reuse tmpbuffer in the same block */ + error = blk_flush(di); + if (error) + goto fail; + bzero(&tmpbuffer, sizeof(tmpbuffer)); + } else { + pa = (*l2 >> PTE_PPN0_S) * PAGE_SIZE; + + /* We always write a page, even if it is zero */ + error = blk_write(di, NULL, pa, PAGE_SIZE); + if (error) + goto fail; + } + } + + /* 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]; + while (bits) { + bit = ffsl(bits) - 1; + pa = (((uint64_t)i * sizeof(*vm_page_dump) * NBBY) + + bit) * PAGE_SIZE; + error = blk_write(di, 0, pa, PAGE_SIZE); + if (error) + goto fail; + bits &= ~(1ul << bit); + } + } + + error = blk_flush(di); + if (error) + goto fail; + + error = dump_finish(di, &kdh); + if (error != 0) + 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 < 5) { + 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); +} + +/* + * Add a page to the minidump bitmap. + */ +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); +} + +/* + * Remove page from the minidump bitmap. + */ +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); } Modified: stable/12/sys/riscv/riscv/pmap.c ============================================================================== --- stable/12/sys/riscv/riscv/pmap.c Thu Jun 27 16:30:25 2019 (r349462) +++ stable/12/sys/riscv/riscv/pmap.c Thu Jun 27 16:48:24 2019 (r349463) @@ -630,7 +630,7 @@ pmap_bootstrap(vm_offset_t l1pt, vm_paddr_t kernstart, pa = pmap_early_vtophys(l1pt, freemempos); - /* Initialize phys_avail. */ + /* Initialize phys_avail and dump_avail. */ for (avail_slot = map_slot = physmem = 0; map_slot < physmap_idx * 2; map_slot += 2) { start = physmap[map_slot]; @@ -638,6 +638,9 @@ pmap_bootstrap(vm_offset_t l1pt, vm_paddr_t kernstart, if (start == end) continue; + dump_avail[map_slot] = start; + dump_avail[map_slot + 1] = end; + if (start >= kernstart && end <= pa) continue; @@ -1644,9 +1647,7 @@ free_pv_chunk(struct pv_chunk *pc) PV_STAT(atomic_add_int(&pc_chunk_frees, 1)); /* entire chunk is free, return it */ m = PHYS_TO_VM_PAGE(DMAP_TO_PHYS((vm_offset_t)pc)); -#if 0 /* TODO: For minidump */ dump_drop_page(m->phys_addr); -#endif vm_page_unwire_noq(m); vm_page_free(m); } @@ -1708,9 +1709,7 @@ retry: } PV_STAT(atomic_add_int(&pc_chunk_count, 1)); PV_STAT(atomic_add_int(&pc_chunk_allocs, 1)); -#if 0 /* TODO: This is for minidump */ dump_add_page(m->phys_addr); -#endif pc = (void *)PHYS_TO_DMAP(m->phys_addr); pc->pc_pmap = pmap; pc->pc_map[0] = PC_FREE0 & ~1ul; /* preallocated bit 0 */ @@ -4429,4 +4428,41 @@ pmap_is_valid_memattr(pmap_t pmap __unused, vm_memattr { return (mode >= VM_MEMATTR_DEVICE && mode <= VM_MEMATTR_WRITE_BACK); +} + +bool +pmap_get_tables(pmap_t pmap, vm_offset_t va, pd_entry_t **l1, pd_entry_t **l2, + pt_entry_t **l3) +{ + pd_entry_t *l1p, *l2p; + + /* Get l1 directory entry. */ + l1p = pmap_l1(pmap, va); + *l1 = l1p; + + if (l1p == NULL || (pmap_load(l1p) & PTE_V) == 0) + return (false); + + if ((pmap_load(l1p) & PTE_RX) != 0) { + *l2 = NULL; + *l3 = NULL; + return (true); + } + + /* Get l2 directory entry. */ + l2p = pmap_l1_to_l2(l1p, va); + *l2 = l2p; + + if (l2p == NULL || (pmap_load(l2p) & PTE_V) == 0) + return (false); + + if ((pmap_load(l2p) & PTE_RX) != 0) { + *l3 = NULL; + return (true); + } + + /* Get l3 page table entry. */ + *l3 = pmap_l2_to_l3(l2p, va); + + return (true); } Modified: stable/12/sys/riscv/riscv/uma_machdep.c ============================================================================== --- stable/12/sys/riscv/riscv/uma_machdep.c Thu Jun 27 16:30:25 2019 (r349462) +++ stable/12/sys/riscv/riscv/uma_machdep.c Thu Jun 27 16:48:24 2019 (r349463) @@ -55,11 +55,8 @@ uma_small_alloc(uma_zone_t zone, vm_size_t bytes, int if (m == NULL) return (NULL); pa = m->phys_addr; -#if 0 - /* RISCVTODO: minidump */ if ((wait & M_NODUMP) == 0) dump_add_page(pa); -#endif va = (void *)PHYS_TO_DMAP(pa); if ((wait & M_ZERO) && (m->flags & PG_ZERO) == 0) bzero(va, PAGE_SIZE); @@ -73,10 +70,7 @@ uma_small_free(void *mem, vm_size_t size, u_int8_t fla vm_paddr_t pa; pa = DMAP_TO_PHYS((vm_offset_t)mem); -#if 0 - /* RISCVTODO: minidump */ dump_drop_page(pa); -#endif m = PHYS_TO_VM_PAGE(pa); vm_page_unwire_noq(m); vm_page_free(m); Modified: stable/12/sys/vm/vm_page.c ============================================================================== --- stable/12/sys/vm/vm_page.c Thu Jun 27 16:30:25 2019 (r349462) +++ stable/12/sys/vm/vm_page.c Thu Jun 27 16:48:24 2019 (r349463) @@ -612,7 +612,7 @@ vm_page_startup(vm_offset_t vaddr) #endif #if defined(__aarch64__) || defined(__amd64__) || defined(__arm__) || \ - defined(__i386__) || defined(__mips__) + defined(__i386__) || defined(__mips__) || defined(__riscv) /* * Allocate a bitmap to indicate that a random physical page * needs to be included in a minidump. @@ -637,7 +637,8 @@ vm_page_startup(vm_offset_t vaddr) #else (void)last_pa; #endif -#if defined(__aarch64__) || defined(__amd64__) || defined(__mips__) +#if defined(__aarch64__) || defined(__amd64__) || defined(__mips__) || \ + defined(__riscv) /* * Include the UMA bootstrap pages and vm_page_dump in a crash dump. * When pmap_map() uses the direct map, they are not automatically @@ -752,7 +753,8 @@ vm_page_startup(vm_offset_t vaddr) high_avail = new_end; new_end = vm_reserv_startup(&vaddr, new_end, high_avail); #endif -#if defined(__aarch64__) || defined(__amd64__) || defined(__mips__) +#if defined(__aarch64__) || defined(__amd64__) || defined(__mips__) || \ + defined(__riscv) /* * 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?201906271648.x5RGmOHO022405>