1286953Sandrew/*- 2286953Sandrew * Copyright (c) 2006 Peter Wemm 3286953Sandrew * 4286953Sandrew * Redistribution and use in source and binary forms, with or without 5286953Sandrew * modification, are permitted provided that the following conditions 6286953Sandrew * are met: 7286953Sandrew * 1. Redistributions of source code must retain the above copyright 8286953Sandrew * notice, this list of conditions and the following disclaimer. 9286953Sandrew * 2. Redistributions in binary form must reproduce the above copyright 10286953Sandrew * notice, this list of conditions and the following disclaimer in the 11286953Sandrew * documentation and/or other materials provided with the distribution. 12286953Sandrew * 13286953Sandrew * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 14286953Sandrew * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15286953Sandrew * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 16286953Sandrew * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 17286953Sandrew * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 18286953Sandrew * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 19286953Sandrew * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 20286953Sandrew * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 21286953Sandrew * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 22286953Sandrew * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 23286953Sandrew * SUCH DAMAGE. 24286953Sandrew * 25286953Sandrew * From: FreeBSD: src/lib/libkvm/kvm_minidump_amd64.c r261799 26286953Sandrew */ 27286953Sandrew 28286953Sandrew#include <sys/cdefs.h> 29286953Sandrew__FBSDID("$FreeBSD: releng/11.0/lib/libkvm/kvm_minidump_aarch64.c 298485 2016-04-22 18:05:34Z ngie $"); 30286953Sandrew 31286953Sandrew/* 32291372Sjhb * ARM64 (AArch64) machine dependent routines for kvm and minidumps. 33286953Sandrew */ 34286953Sandrew 35286953Sandrew#include <sys/param.h> 36291406Sjhb#include <stdint.h> 37286953Sandrew#include <stdlib.h> 38286953Sandrew#include <string.h> 39286953Sandrew#include <unistd.h> 40286953Sandrew#include <kvm.h> 41286953Sandrew 42291406Sjhb#include "../../sys/arm64/include/minidump.h" 43286953Sandrew 44286953Sandrew#include <limits.h> 45286953Sandrew 46286953Sandrew#include "kvm_private.h" 47291406Sjhb#include "kvm_aarch64.h" 48286953Sandrew 49291406Sjhb#define aarch64_round_page(x) roundup2((kvaddr_t)(x), AARCH64_PAGE_SIZE) 50286953Sandrew 51286953Sandrewstruct vmstate { 52286953Sandrew struct minidumphdr hdr; 53291406Sjhb struct hpt hpt; 54286953Sandrew uint64_t *page_map; 55286953Sandrew}; 56286953Sandrew 57286953Sandrewstatic int 58291406Sjhb_aarch64_minidump_probe(kvm_t *kd) 59286953Sandrew{ 60286953Sandrew 61291406Sjhb return (_kvm_probe_elf_kernel(kd, ELFCLASS64, EM_AARCH64) && 62291406Sjhb _kvm_is_minidump(kd)); 63286953Sandrew} 64286953Sandrew 65291406Sjhbstatic void 66291406Sjhb_aarch64_minidump_freevtop(kvm_t *kd) 67286953Sandrew{ 68286953Sandrew struct vmstate *vm = kd->vmst; 69286953Sandrew 70291406Sjhb _kvm_hpt_free(&vm->hpt); 71286953Sandrew free(vm->page_map); 72286953Sandrew free(vm); 73286953Sandrew kd->vmst = NULL; 74286953Sandrew} 75286953Sandrew 76291406Sjhbstatic int 77291406Sjhb_aarch64_minidump_initvtop(kvm_t *kd) 78286953Sandrew{ 79286953Sandrew struct vmstate *vmst; 80291406Sjhb uint64_t *bitmap; 81286953Sandrew off_t off; 82286953Sandrew 83286953Sandrew vmst = _kvm_malloc(kd, sizeof(*vmst)); 84298485Sngie if (vmst == NULL) { 85286953Sandrew _kvm_err(kd, kd->program, "cannot allocate vm"); 86286953Sandrew return (-1); 87286953Sandrew } 88286953Sandrew kd->vmst = vmst; 89286953Sandrew if (pread(kd->pmfd, &vmst->hdr, sizeof(vmst->hdr), 0) != 90286953Sandrew sizeof(vmst->hdr)) { 91286953Sandrew _kvm_err(kd, kd->program, "cannot read dump header"); 92286953Sandrew return (-1); 93286953Sandrew } 94286953Sandrew if (strncmp(MINIDUMP_MAGIC, vmst->hdr.magic, 95286953Sandrew sizeof(vmst->hdr.magic)) != 0) { 96286953Sandrew _kvm_err(kd, kd->program, "not a minidump for this platform"); 97286953Sandrew return (-1); 98286953Sandrew } 99286953Sandrew 100291406Sjhb vmst->hdr.version = le32toh(vmst->hdr.version); 101291406Sjhb if (vmst->hdr.version != MINIDUMP_VERSION) { 102286953Sandrew _kvm_err(kd, kd->program, "wrong minidump version. " 103286953Sandrew "Expected %d got %d", MINIDUMP_VERSION, vmst->hdr.version); 104286953Sandrew return (-1); 105286953Sandrew } 106291406Sjhb vmst->hdr.msgbufsize = le32toh(vmst->hdr.msgbufsize); 107291406Sjhb vmst->hdr.bitmapsize = le32toh(vmst->hdr.bitmapsize); 108291406Sjhb vmst->hdr.pmapsize = le32toh(vmst->hdr.pmapsize); 109291406Sjhb vmst->hdr.kernbase = le64toh(vmst->hdr.kernbase); 110291406Sjhb vmst->hdr.dmapphys = le64toh(vmst->hdr.dmapphys); 111291406Sjhb vmst->hdr.dmapbase = le64toh(vmst->hdr.dmapbase); 112291406Sjhb vmst->hdr.dmapend = le64toh(vmst->hdr.dmapend); 113286953Sandrew 114286953Sandrew /* Skip header and msgbuf */ 115291406Sjhb off = AARCH64_PAGE_SIZE + aarch64_round_page(vmst->hdr.msgbufsize); 116286953Sandrew 117291406Sjhb bitmap = _kvm_malloc(kd, vmst->hdr.bitmapsize); 118291406Sjhb if (bitmap == NULL) { 119286953Sandrew _kvm_err(kd, kd->program, 120286953Sandrew "cannot allocate %d bytes for bitmap", 121286953Sandrew vmst->hdr.bitmapsize); 122286953Sandrew return (-1); 123286953Sandrew } 124291406Sjhb if (pread(kd->pmfd, bitmap, vmst->hdr.bitmapsize, off) != 125291406Sjhb (ssize_t)vmst->hdr.bitmapsize) { 126286953Sandrew _kvm_err(kd, kd->program, 127286953Sandrew "cannot read %d bytes for page bitmap", 128286953Sandrew vmst->hdr.bitmapsize); 129291406Sjhb free(bitmap); 130286953Sandrew return (-1); 131286953Sandrew } 132291406Sjhb off += aarch64_round_page(vmst->hdr.bitmapsize); 133286953Sandrew 134286953Sandrew vmst->page_map = _kvm_malloc(kd, vmst->hdr.pmapsize); 135286953Sandrew if (vmst->page_map == NULL) { 136286953Sandrew _kvm_err(kd, kd->program, 137286953Sandrew "cannot allocate %d bytes for page_map", 138286953Sandrew vmst->hdr.pmapsize); 139291406Sjhb free(bitmap); 140286953Sandrew return (-1); 141286953Sandrew } 142286953Sandrew /* This is the end of the dump, savecore may have truncated it. */ 143291406Sjhb /* 144291406Sjhb * XXX: This doesn't make sense. The pmap is not at the end, 145291406Sjhb * and if it is truncated we don't have any actual data (it's 146291406Sjhb * all stored after the bitmap and pmap. -- jhb 147291406Sjhb */ 148286953Sandrew if (pread(kd->pmfd, vmst->page_map, vmst->hdr.pmapsize, off) < 149291406Sjhb AARCH64_PAGE_SIZE) { 150286953Sandrew _kvm_err(kd, kd->program, "cannot read %d bytes for page_map", 151286953Sandrew vmst->hdr.pmapsize); 152291406Sjhb free(bitmap); 153291406Sjhb return (-1); 154286953Sandrew } 155286953Sandrew off += vmst->hdr.pmapsize; 156286953Sandrew 157286953Sandrew /* build physical address hash table for sparse pages */ 158291406Sjhb _kvm_hpt_init(kd, &vmst->hpt, bitmap, vmst->hdr.bitmapsize, off, 159291406Sjhb AARCH64_PAGE_SIZE, sizeof(*bitmap)); 160291406Sjhb free(bitmap); 161286953Sandrew 162286953Sandrew return (0); 163286953Sandrew} 164286953Sandrew 165286953Sandrewstatic int 166291406Sjhb_aarch64_minidump_vatop(kvm_t *kd, kvaddr_t va, off_t *pa) 167286953Sandrew{ 168286953Sandrew struct vmstate *vm; 169291406Sjhb aarch64_physaddr_t offset; 170291406Sjhb aarch64_pte_t l3; 171291406Sjhb kvaddr_t l3_index; 172291406Sjhb aarch64_physaddr_t a; 173286953Sandrew off_t ofs; 174286953Sandrew 175286953Sandrew vm = kd->vmst; 176291406Sjhb offset = va & AARCH64_PAGE_MASK; 177286953Sandrew 178286953Sandrew if (va >= vm->hdr.dmapbase && va < vm->hdr.dmapend) { 179291406Sjhb a = (va - vm->hdr.dmapbase + vm->hdr.dmapphys) & 180291406Sjhb ~AARCH64_PAGE_MASK; 181291406Sjhb ofs = _kvm_hpt_find(&vm->hpt, a); 182286953Sandrew if (ofs == -1) { 183291406Sjhb _kvm_err(kd, kd->program, "_aarch64_minidump_vatop: " 184291406Sjhb "direct map address 0x%jx not in minidump", 185291406Sjhb (uintmax_t)va); 186286953Sandrew goto invalid; 187286953Sandrew } 188286953Sandrew *pa = ofs + offset; 189291406Sjhb return (AARCH64_PAGE_SIZE - offset); 190286953Sandrew } else if (va >= vm->hdr.kernbase) { 191291406Sjhb l3_index = (va - vm->hdr.kernbase) >> AARCH64_L3_SHIFT; 192286953Sandrew if (l3_index >= vm->hdr.pmapsize / sizeof(*vm->page_map)) 193286953Sandrew goto invalid; 194291406Sjhb l3 = le64toh(vm->page_map[l3_index]); 195291406Sjhb if ((l3 & AARCH64_ATTR_DESCR_MASK) != AARCH64_L3_PAGE) { 196291406Sjhb _kvm_err(kd, kd->program, 197291406Sjhb "_aarch64_minidump_vatop: pde not valid"); 198286953Sandrew goto invalid; 199286953Sandrew } 200291406Sjhb a = l3 & ~AARCH64_ATTR_MASK; 201291406Sjhb ofs = _kvm_hpt_find(&vm->hpt, a); 202286953Sandrew if (ofs == -1) { 203291406Sjhb _kvm_err(kd, kd->program, "_aarch64_minidump_vatop: " 204291406Sjhb "physical address 0x%jx not in minidump", 205291406Sjhb (uintmax_t)a); 206286953Sandrew goto invalid; 207286953Sandrew } 208286953Sandrew *pa = ofs + offset; 209291406Sjhb return (AARCH64_PAGE_SIZE - offset); 210286953Sandrew } else { 211286953Sandrew _kvm_err(kd, kd->program, 212291406Sjhb "_aarch64_minidump_vatop: virtual address 0x%jx not minidumped", 213291406Sjhb (uintmax_t)va); 214286953Sandrew goto invalid; 215286953Sandrew } 216286953Sandrew 217286953Sandrewinvalid: 218291406Sjhb _kvm_err(kd, 0, "invalid address (0x%jx)", (uintmax_t)va); 219286953Sandrew return (0); 220286953Sandrew} 221286953Sandrew 222291406Sjhbstatic int 223291406Sjhb_aarch64_minidump_kvatop(kvm_t *kd, kvaddr_t va, off_t *pa) 224286953Sandrew{ 225286953Sandrew 226286953Sandrew if (ISALIVE(kd)) { 227291406Sjhb _kvm_err(kd, 0, 228291406Sjhb "_aarch64_minidump_kvatop called in live kernel!"); 229286953Sandrew return (0); 230286953Sandrew } 231291406Sjhb return (_aarch64_minidump_vatop(kd, va, pa)); 232286953Sandrew} 233291406Sjhb 234291406Sjhbstatic int 235291406Sjhb_aarch64_native(kvm_t *kd) 236291406Sjhb{ 237291406Sjhb 238291406Sjhb#ifdef __aarch64__ 239291406Sjhb return (1); 240291406Sjhb#else 241291406Sjhb return (0); 242291406Sjhb#endif 243291406Sjhb} 244291406Sjhb 245291406Sjhbstruct kvm_arch kvm_aarch64_minidump = { 246291406Sjhb .ka_probe = _aarch64_minidump_probe, 247291406Sjhb .ka_initvtop = _aarch64_minidump_initvtop, 248291406Sjhb .ka_freevtop = _aarch64_minidump_freevtop, 249291406Sjhb .ka_kvatop = _aarch64_minidump_kvatop, 250291406Sjhb .ka_native = _aarch64_native, 251291406Sjhb}; 252291406Sjhb 253291406SjhbKVM_ARCH(kvm_aarch64_minidump); 254