Index: head/lib/libkvm/kvm_aarch64.c =================================================================== --- head/lib/libkvm/kvm_aarch64.c (revision 286952) +++ head/lib/libkvm/kvm_aarch64.c (revision 286953) @@ -1,64 +1,105 @@ /*- - * Copyright (c) 2014 The FreeBSD Foundation + * Copyright (C) 2006 Bruce M. Simpson. + * Copyright (c) 2015 The FreeBSD Foundation * All rights reserved. * * This software was developed by Andrew Turner under * sponsorship from the FreeBSD Foundation. * * 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. */ +/* + * arm64 (AArch64) machine dependent routines for kvm. + */ + #include __FBSDID("$FreeBSD$"); #include +#include +#include +#include +#include + +#include + #include #include -#include #include +#include +#include #include "kvm_private.h" +/* minidump must be the first item! */ +struct vmstate { + int minidump; /* 1 = minidump mode */ + void *mmapbase; + size_t mmapsize; +}; + void _kvm_freevtop(kvm_t *kd) { - printf("_kvm_freevtop\n"); - abort(); + if (kd->vmst != 0) { + if (kd->vmst->minidump) + return (_kvm_minidump_freevtop(kd)); + if (kd->vmst->mmapbase != NULL) + munmap(kd->vmst->mmapbase, kd->vmst->mmapsize); + free(kd->vmst); + kd->vmst = NULL; + } } int _kvm_initvtop(kvm_t *kd) { + char minihdr[8]; - printf("_kvm_initvtop\n"); - abort(); + if (!kd->rawdump) { + if (pread(kd->pmfd, &minihdr, 8, 0) == 8) { + if (memcmp(&minihdr, "minidump", 8) == 0) + return (_kvm_minidump_initvtop(kd)); + } else { + _kvm_err(kd, kd->program, "cannot read header"); + return (-1); + } + } + + _kvm_err(kd, 0, "_kvm_initvtop: Unsupported image type"); + return (-1); } int _kvm_kvatop(kvm_t *kd, u_long va, off_t *pa) { - printf("_kvm_kvatop\n"); - abort(); + if (kd->vmst->minidump) + return _kvm_minidump_kvatop(kd, va, pa); + + + _kvm_err(kd, 0, "_kvm_kvatop: Unsupported image type"); + return (0); } Index: head/lib/libkvm/kvm_minidump_aarch64.c =================================================================== --- head/lib/libkvm/kvm_minidump_aarch64.c (nonexistent) +++ head/lib/libkvm/kvm_minidump_aarch64.c (revision 286953) @@ -0,0 +1,269 @@ +/*- + * Copyright (c) 2006 Peter Wemm + * + * 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 +__FBSDID("$FreeBSD$"); + +/* + * ARM64 (AArch64) machine dependent routines for kvm and minidumps. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include + +#include +#include + +#include "kvm_private.h" + +struct hpte { + struct hpte *next; + vm_paddr_t pa; + int64_t off; +}; + +#define HPT_SIZE 1024 + +/* minidump must be the first item! */ +struct vmstate { + int minidump; /* 1 = minidump mode */ + struct minidumphdr hdr; + void *hpt_head[HPT_SIZE]; + uint64_t *bitmap; + uint64_t *page_map; +}; + +static void +hpt_insert(kvm_t *kd, vm_paddr_t pa, int64_t off) +{ + struct hpte *hpte; + uint32_t fnv = FNV1_32_INIT; + + fnv = fnv_32_buf(&pa, sizeof(pa), fnv); + fnv &= (HPT_SIZE - 1); + hpte = malloc(sizeof(*hpte)); + hpte->pa = pa; + hpte->off = off; + hpte->next = kd->vmst->hpt_head[fnv]; + kd->vmst->hpt_head[fnv] = hpte; +} + +static int64_t +hpt_find(kvm_t *kd, vm_paddr_t pa) +{ + struct hpte *hpte; + uint32_t fnv = FNV1_32_INIT; + + fnv = fnv_32_buf(&pa, sizeof(pa), fnv); + fnv &= (HPT_SIZE - 1); + for (hpte = kd->vmst->hpt_head[fnv]; hpte != NULL; hpte = hpte->next) { + if (pa == hpte->pa) + return (hpte->off); + } + return (-1); +} + +static int +inithash(kvm_t *kd, uint64_t *base, int len, off_t off) +{ + uint64_t idx; + uint64_t bit, bits; + vm_paddr_t pa; + + for (idx = 0; idx < len / sizeof(*base); idx++) { + bits = base[idx]; + while (bits) { + bit = ffsl(bits) - 1; + bits &= ~(1ul << bit); + pa = (idx * sizeof(*base) * NBBY + bit) * PAGE_SIZE; + hpt_insert(kd, pa, off); + off += PAGE_SIZE; + } + } + return (off); +} + +void +_kvm_minidump_freevtop(kvm_t *kd) +{ + struct vmstate *vm = kd->vmst; + + free(vm->bitmap); + free(vm->page_map); + free(vm); + kd->vmst = NULL; +} + +int +_kvm_minidump_initvtop(kvm_t *kd) +{ + struct vmstate *vmst; + off_t off; + + vmst = _kvm_malloc(kd, sizeof(*vmst)); + if (vmst == 0) { + _kvm_err(kd, kd->program, "cannot allocate vm"); + return (-1); + } + kd->vmst = vmst; + vmst->minidump = 1; + 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); + } + + if (vmst->hdr.version != MINIDUMP_VERSION && vmst->hdr.version != 1) { + _kvm_err(kd, kd->program, "wrong minidump version. " + "Expected %d got %d", MINIDUMP_VERSION, vmst->hdr.version); + return (-1); + } + + /* Skip header and msgbuf */ + off = PAGE_SIZE + round_page(vmst->hdr.msgbufsize); + + vmst->bitmap = _kvm_malloc(kd, vmst->hdr.bitmapsize); + if (vmst->bitmap == NULL) { + _kvm_err(kd, kd->program, + "cannot allocate %d bytes for bitmap", + vmst->hdr.bitmapsize); + return (-1); + } + if (pread(kd->pmfd, vmst->bitmap, vmst->hdr.bitmapsize, off) != + vmst->hdr.bitmapsize) { + _kvm_err(kd, kd->program, + "cannot read %d bytes for page bitmap", + vmst->hdr.bitmapsize); + return (-1); + } + off += round_page(vmst->hdr.bitmapsize); + + vmst->page_map = _kvm_malloc(kd, vmst->hdr.pmapsize); + if (vmst->page_map == NULL) { + _kvm_err(kd, kd->program, + "cannot allocate %d bytes for page_map", + vmst->hdr.pmapsize); + return (-1); + } + /* This is the end of the dump, savecore may have truncated it. */ + if (pread(kd->pmfd, vmst->page_map, vmst->hdr.pmapsize, off) < + PAGE_SIZE) { + _kvm_err(kd, kd->program, "cannot read %d bytes for page_map", + vmst->hdr.pmapsize); + } + off += vmst->hdr.pmapsize; + + /* build physical address hash table for sparse pages */ + inithash(kd, vmst->bitmap, vmst->hdr.bitmapsize, off); + + return (0); +} + +static int +_kvm_minidump_vatop(kvm_t *kd, u_long va, off_t *pa) +{ + struct vmstate *vm; + u_long offset; + pt_entry_t l3; + u_long l3_index; + u_long a; + off_t ofs; + + vm = kd->vmst; + offset = va & PAGE_MASK; + + if (va >= vm->hdr.dmapbase && va < vm->hdr.dmapend) { + a = (va - vm->hdr.dmapbase + vm->hdr.dmapphys) & ~PAGE_MASK; + ofs = hpt_find(kd, a); + if (ofs == -1) { + _kvm_err(kd, kd->program, "_kvm_vatop: " + "direct map address 0x%lx not in minidump", va); + goto invalid; + } + *pa = ofs + offset; + return (PAGE_SIZE - offset); + } else if (va >= vm->hdr.kernbase) { + l3_index = (va - vm->hdr.kernbase) >> L3_SHIFT; + if (l3_index >= vm->hdr.pmapsize / sizeof(*vm->page_map)) + goto invalid; + l3 = vm->page_map[l3_index]; + if ((l3 & ATTR_DESCR_MASK) != L3_PAGE) { + _kvm_err(kd, kd->program, "_kvm_vatop: pde not valid"); + goto invalid; + } + a = l3 & ~ATTR_MASK; + ofs = hpt_find(kd, a); + if (ofs == -1) { + _kvm_err(kd, kd->program, "_kvm_vatop: " + "physical address 0x%lx not in minidump", a); + goto invalid; + } + *pa = ofs + offset; + return (PAGE_SIZE - offset); + } else { + _kvm_err(kd, kd->program, + "_kvm_vatop: virtual address 0x%lx not minidumped", va); + goto invalid; + } + +invalid: + _kvm_err(kd, 0, "invalid address (0x%lx)", va); + return (0); +} + +int +_kvm_minidump_kvatop(kvm_t *kd, u_long va, off_t *pa) +{ + + if (ISALIVE(kd)) { + _kvm_err(kd, 0, "kvm_kvatop called in live kernel!"); + return (0); + } + return (_kvm_minidump_vatop(kd, va, pa)); +} Property changes on: head/lib/libkvm/kvm_minidump_aarch64.c ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: head/lib/libkvm/kvm_private.h =================================================================== --- head/lib/libkvm/kvm_private.h (revision 286952) +++ head/lib/libkvm/kvm_private.h (revision 286953) @@ -1,112 +1,112 @@ /*- * Copyright (c) 1992, 1993 * The Regents of the University of California. All rights reserved. * * This code is derived from software developed by the Computer Systems * Engineering group at Lawrence Berkeley Laboratory under DARPA contract * BG 91-66 and contributed to Berkeley. * * 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. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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. * * @(#)kvm_private.h 8.1 (Berkeley) 6/4/93 * $FreeBSD$ */ struct __kvm { /* * a string to be prepended to error messages * provided for compatibility with sun's interface * if this value is null, errors are saved in errbuf[] */ const char *program; char *errp; /* XXX this can probably go away */ char errbuf[_POSIX2_LINE_MAX]; #define ISALIVE(kd) ((kd)->vmfd >= 0) int pmfd; /* physical memory file (or crashdump) */ int vmfd; /* virtual memory file (-1 if crashdump) */ int unused; /* was: swap file (e.g., /dev/drum) */ int nlfd; /* namelist file (e.g., /kernel) */ struct kinfo_proc *procbase; char *argspc; /* (dynamic) storage for argv strings */ int arglen; /* length of the above */ char **argv; /* (dynamic) storage for argv pointers */ int argc; /* length of above (not actual # present) */ char *argbuf; /* (dynamic) temporary storage */ /* * Kernel virtual address translation state. This only gets filled * in for dead kernels; otherwise, the running kernel (i.e. kmem) * will do the translations for us. It could be big, so we * only allocate it if necessary. */ struct vmstate *vmst; int rawdump; /* raw dump format */ int vnet_initialized; /* vnet fields set up */ uintptr_t vnet_start; /* start of kernel's vnet region */ uintptr_t vnet_stop; /* stop of kernel's vnet region */ uintptr_t vnet_current; /* vnet we're working with */ uintptr_t vnet_base; /* vnet base of current vnet */ /* * Dynamic per-CPU kernel memory. We translate symbols, on-demand, * to the data associated with dpcpu_curcpu, set with * kvm_dpcpu_setcpu(). */ int dpcpu_initialized; /* dpcpu fields set up */ uintptr_t dpcpu_start; /* start of kernel's dpcpu region */ uintptr_t dpcpu_stop; /* stop of kernel's dpcpu region */ u_int dpcpu_maxcpus; /* size of base array */ uintptr_t *dpcpu_off; /* base array, indexed by CPU ID */ u_int dpcpu_curcpu; /* CPU we're currently working with */ uintptr_t dpcpu_curoff; /* dpcpu base of current CPU */ }; /* * Functions used internally by kvm, but across kvm modules. */ void _kvm_err(kvm_t *kd, const char *program, const char *fmt, ...) __printflike(3, 4); void _kvm_freeprocs(kvm_t *kd); void _kvm_freevtop(kvm_t *); int _kvm_initvtop(kvm_t *); int _kvm_kvatop(kvm_t *, u_long, off_t *); void *_kvm_malloc(kvm_t *kd, size_t); int _kvm_nlist(kvm_t *, struct nlist *, int); void *_kvm_realloc(kvm_t *kd, void *, size_t); void _kvm_syserr (kvm_t *kd, const char *program, const char *fmt, ...) __printflike(3, 4); int _kvm_uvatop(kvm_t *, const struct proc *, u_long, u_long *); int _kvm_vnet_selectpid(kvm_t *, pid_t); int _kvm_vnet_initialized(kvm_t *, int); uintptr_t _kvm_vnet_validaddr(kvm_t *, uintptr_t); int _kvm_dpcpu_initialized(kvm_t *, int); uintptr_t _kvm_dpcpu_validaddr(kvm_t *, uintptr_t); -#if defined(__amd64__) || defined(__i386__) || defined(__arm__) || \ - defined(__mips__) +#if defined(__aarch64__) || defined(__amd64__) || defined(__arm__) || \ + defined(__i386__) || defined(__mips__) void _kvm_minidump_freevtop(kvm_t *); int _kvm_minidump_initvtop(kvm_t *); int _kvm_minidump_kvatop(kvm_t *, u_long, off_t *); #endif