11602Srgrimes/*- 21602Srgrimes * Copyright (c) 1989, 1992, 1993 31602Srgrimes * The Regents of the University of California. All rights reserved. 41602Srgrimes * 51602Srgrimes * This code is derived from software developed by the Computer Systems 61602Srgrimes * Engineering group at Lawrence Berkeley Laboratory under DARPA contract 71602Srgrimes * BG 91-66 and contributed to Berkeley. 81602Srgrimes * 91602Srgrimes * Redistribution and use in source and binary forms, with or without 101602Srgrimes * modification, are permitted provided that the following conditions 111602Srgrimes * are met: 121602Srgrimes * 1. Redistributions of source code must retain the above copyright 131602Srgrimes * notice, this list of conditions and the following disclaimer. 141602Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 151602Srgrimes * notice, this list of conditions and the following disclaimer in the 161602Srgrimes * documentation and/or other materials provided with the distribution. 171602Srgrimes * 4. Neither the name of the University nor the names of its contributors 181602Srgrimes * may be used to endorse or promote products derived from this software 191602Srgrimes * without specific prior written permission. 201602Srgrimes * 211602Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 221602Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 231602Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 241602Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 251602Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 261602Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 271602Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 281602Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 291602Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 301602Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 311602Srgrimes * SUCH DAMAGE. 321602Srgrimes */ 331602Srgrimes 3483551Sdillon#include <sys/cdefs.h> 3583551Sdillon__FBSDID("$FreeBSD: stable/11/lib/libkvm/kvm_amd64.c 316126 2017-03-29 07:30:59Z ngie $"); 3683551Sdillon 371602Srgrimes#if defined(LIBC_SCCS) && !defined(lint) 3855127Speter#if 0 391602Srgrimesstatic char sccsid[] = "@(#)kvm_hp300.c 8.1 (Berkeley) 6/4/93"; 4055127Speter#endif 411602Srgrimes#endif /* LIBC_SCCS and not lint */ 421602Srgrimes 431602Srgrimes/* 44114330Speter * AMD64 machine dependent routines for kvm. Hopefully, the forthcoming 451602Srgrimes * vm code will one day obsolete this module. 461602Srgrimes */ 471602Srgrimes 481602Srgrimes#include <sys/param.h> 49291406Sjhb#include <sys/endian.h> 50291406Sjhb#include <stdint.h> 5117141Sjkh#include <stdlib.h> 52194186Sed#include <string.h> 531602Srgrimes#include <unistd.h> 541602Srgrimes#include <kvm.h> 551602Srgrimes 561602Srgrimes#include <limits.h> 571602Srgrimes 581602Srgrimes#include "kvm_private.h" 59291406Sjhb#include "kvm_amd64.h" 601602Srgrimes 611602Srgrimesstruct vmstate { 62291406Sjhb size_t phnum; 63291406Sjhb GElf_Phdr *phdr; 64291406Sjhb amd64_pml4e_t *PML4; 651602Srgrimes}; 661602Srgrimes 67147672Speter/* 68147672Speter * Translate a physical memory address to a file-offset in the crash-dump. 69147672Speter */ 70147672Speterstatic size_t 71147672Speter_kvm_pa2off(kvm_t *kd, uint64_t pa, off_t *ofs) 72147672Speter{ 73291406Sjhb struct vmstate *vm = kd->vmst; 74291406Sjhb GElf_Phdr *p; 75291406Sjhb size_t n; 76147672Speter 77170772Ssimokawa if (kd->rawdump) { 78170772Ssimokawa *ofs = pa; 79291406Sjhb return (AMD64_PAGE_SIZE - (pa & AMD64_PAGE_MASK)); 80170772Ssimokawa } 81170772Ssimokawa 82291406Sjhb p = vm->phdr; 83291406Sjhb n = vm->phnum; 84147672Speter while (n && (pa < p->p_paddr || pa >= p->p_paddr + p->p_memsz)) 85147672Speter p++, n--; 86147672Speter if (n == 0) 87147672Speter return (0); 88147672Speter *ofs = (pa - p->p_paddr) + p->p_offset; 89291406Sjhb return (AMD64_PAGE_SIZE - (pa & AMD64_PAGE_MASK)); 90147672Speter} 91147672Speter 92291406Sjhbstatic void 93291406Sjhb_amd64_freevtop(kvm_t *kd) 9418798Speter{ 95147672Speter struct vmstate *vm = kd->vmst; 96147672Speter 97147672Speter if (vm->PML4) 98147672Speter free(vm->PML4); 99291406Sjhb free(vm->phdr); 100147672Speter free(vm); 101147672Speter kd->vmst = NULL; 1021602Srgrimes} 1031602Srgrimes 104291406Sjhbstatic int 105291406Sjhb_amd64_probe(kvm_t *kd) 10618798Speter{ 1071602Srgrimes 108291406Sjhb return (_kvm_probe_elf_kernel(kd, ELFCLASS64, EM_X86_64) && 109291406Sjhb !_kvm_is_minidump(kd)); 110291406Sjhb} 111157911Speter 112291406Sjhbstatic int 113291406Sjhb_amd64_initvtop(kvm_t *kd) 114291406Sjhb{ 115291406Sjhb struct kvm_nlist nl[2]; 116291406Sjhb amd64_physaddr_t pa; 117291406Sjhb kvaddr_t kernbase; 118291406Sjhb amd64_pml4e_t *PML4; 119291406Sjhb 120147672Speter kd->vmst = (struct vmstate *)_kvm_malloc(kd, sizeof(*kd->vmst)); 121298485Sngie if (kd->vmst == NULL) { 1221603Srgrimes _kvm_err(kd, kd->program, "cannot allocate vm"); 1231602Srgrimes return (-1); 1241603Srgrimes } 125147672Speter kd->vmst->PML4 = 0; 1261602Srgrimes 127170772Ssimokawa if (kd->rawdump == 0) { 128291406Sjhb if (_kvm_read_core_phdrs(kd, &kd->vmst->phnum, 129291406Sjhb &kd->vmst->phdr) == -1) 130170772Ssimokawa return (-1); 131170772Ssimokawa } 132147672Speter 133217744Suqs nl[0].n_name = "kernbase"; 134217744Suqs nl[1].n_name = 0; 1351602Srgrimes 136291406Sjhb if (kvm_nlist2(kd, nl) != 0) { 137129452Speter _kvm_err(kd, kd->program, "bad namelist - no kernbase"); 138129452Speter return (-1); 139129452Speter } 140217744Suqs kernbase = nl[0].n_value; 14182263Speter 142217744Suqs nl[0].n_name = "KPML4phys"; 143217744Suqs nl[1].n_name = 0; 14482263Speter 145291406Sjhb if (kvm_nlist2(kd, nl) != 0) { 146129452Speter _kvm_err(kd, kd->program, "bad namelist - no KPML4phys"); 1471602Srgrimes return (-1); 1481602Srgrimes } 149291406Sjhb if (kvm_read2(kd, (nl[0].n_value - kernbase), &pa, sizeof(pa)) != 15082263Speter sizeof(pa)) { 151129452Speter _kvm_err(kd, kd->program, "cannot read KPML4phys"); 1521602Srgrimes return (-1); 1531602Srgrimes } 154291406Sjhb pa = le64toh(pa); 155291406Sjhb PML4 = _kvm_malloc(kd, AMD64_PAGE_SIZE); 156298485Sngie if (PML4 == NULL) { 157298485Sngie _kvm_err(kd, kd->program, "cannot allocate PML4"); 158298485Sngie return (-1); 159298485Sngie } 160291406Sjhb if (kvm_read2(kd, pa, PML4, AMD64_PAGE_SIZE) != AMD64_PAGE_SIZE) { 161129452Speter _kvm_err(kd, kd->program, "cannot read KPML4phys"); 162298842Sngie free(PML4); 1631602Srgrimes return (-1); 1641602Srgrimes } 165147672Speter kd->vmst->PML4 = PML4; 1661602Srgrimes return (0); 1671602Srgrimes} 1681602Srgrimes 1691602Srgrimesstatic int 170291406Sjhb_amd64_vatop(kvm_t *kd, kvaddr_t va, off_t *pa) 17118798Speter{ 17218798Speter struct vmstate *vm; 173291406Sjhb amd64_physaddr_t offset; 174291406Sjhb amd64_physaddr_t pdpe_pa; 175291406Sjhb amd64_physaddr_t pde_pa; 176291406Sjhb amd64_physaddr_t pte_pa; 177291406Sjhb amd64_pml4e_t pml4e; 178291406Sjhb amd64_pdpe_t pdpe; 179291406Sjhb amd64_pde_t pde; 180291406Sjhb amd64_pte_t pte; 181291406Sjhb kvaddr_t pml4eindex; 182291406Sjhb kvaddr_t pdpeindex; 183291406Sjhb kvaddr_t pdeindex; 184291406Sjhb kvaddr_t pteindex; 185291406Sjhb amd64_physaddr_t a; 186147672Speter off_t ofs; 187147672Speter size_t s; 1881602Srgrimes 18918798Speter vm = kd->vmst; 190291406Sjhb offset = va & AMD64_PAGE_MASK; 19118798Speter 19218798Speter /* 19318798Speter * If we are initializing (kernel page table descriptor pointer 19418798Speter * not yet set) then return pa == va to avoid infinite recursion. 19518798Speter */ 196298485Sngie if (vm->PML4 == NULL) { 197147672Speter s = _kvm_pa2off(kd, va, pa); 198147672Speter if (s == 0) { 199147672Speter _kvm_err(kd, kd->program, 200291406Sjhb "_amd64_vatop: bootstrap data not in dump"); 201147672Speter goto invalid; 202147672Speter } else 203291406Sjhb return (AMD64_PAGE_SIZE - offset); 20418798Speter } 20518798Speter 206291406Sjhb pml4eindex = (va >> AMD64_PML4SHIFT) & (AMD64_NPML4EPG - 1); 207291406Sjhb pml4e = le64toh(vm->PML4[pml4eindex]); 208291406Sjhb if ((pml4e & AMD64_PG_V) == 0) { 209291406Sjhb _kvm_err(kd, kd->program, "_amd64_vatop: pml4e not valid"); 210129452Speter goto invalid; 211147672Speter } 212129452Speter 213291406Sjhb pdpeindex = (va >> AMD64_PDPSHIFT) & (AMD64_NPDPEPG - 1); 214291406Sjhb pdpe_pa = (pml4e & AMD64_PG_FRAME) + (pdpeindex * sizeof(amd64_pdpe_t)); 215129452Speter 216147672Speter s = _kvm_pa2off(kd, pdpe_pa, &ofs); 217291406Sjhb if (s < sizeof(pdpe)) { 218291406Sjhb _kvm_err(kd, kd->program, "_amd64_vatop: pdpe_pa not found"); 219147672Speter goto invalid; 220147672Speter } 221291406Sjhb if (pread(kd->pmfd, &pdpe, sizeof(pdpe), ofs) != sizeof(pdpe)) { 222291406Sjhb _kvm_syserr(kd, kd->program, "_amd64_vatop: read pdpe"); 223129452Speter goto invalid; 224129452Speter } 225291406Sjhb pdpe = le64toh(pdpe); 226291406Sjhb if ((pdpe & AMD64_PG_V) == 0) { 227291406Sjhb _kvm_err(kd, kd->program, "_amd64_vatop: pdpe not valid"); 228129452Speter goto invalid; 229129452Speter } 230291406Sjhb 231291406Sjhb if (pdpe & AMD64_PG_PS) { 232291406Sjhb /* 233291406Sjhb * No next-level page table; pdpe describes one 1GB page. 234291406Sjhb */ 235297359Sjhb a = (pdpe & AMD64_PG_1GB_FRAME) + (va & AMD64_PDPMASK); 236291406Sjhb s = _kvm_pa2off(kd, a, pa); 237291406Sjhb if (s == 0) { 238291406Sjhb _kvm_err(kd, kd->program, 239291406Sjhb "_amd64_vatop: 1GB page address not in dump"); 240291406Sjhb goto invalid; 241291406Sjhb } else 242291406Sjhb return (AMD64_NBPDP - (va & AMD64_PDPMASK)); 243147672Speter } 244129452Speter 245291406Sjhb pdeindex = (va >> AMD64_PDRSHIFT) & (AMD64_NPDEPG - 1); 246291406Sjhb pde_pa = (pdpe & AMD64_PG_FRAME) + (pdeindex * sizeof(amd64_pde_t)); 247129452Speter 248147672Speter s = _kvm_pa2off(kd, pde_pa, &ofs); 249291406Sjhb if (s < sizeof(pde)) { 250291406Sjhb _kvm_syserr(kd, kd->program, "_amd64_vatop: pde_pa not found"); 251129452Speter goto invalid; 252129452Speter } 253291406Sjhb if (pread(kd->pmfd, &pde, sizeof(pde), ofs) != sizeof(pde)) { 254291406Sjhb _kvm_syserr(kd, kd->program, "_amd64_vatop: read pde"); 255147672Speter goto invalid; 256147672Speter } 257291406Sjhb pde = le64toh(pde); 258291406Sjhb if ((pde & AMD64_PG_V) == 0) { 259291406Sjhb _kvm_err(kd, kd->program, "_amd64_vatop: pde not valid"); 260129452Speter goto invalid; 261129452Speter } 26218798Speter 263291406Sjhb if (pde & AMD64_PG_PS) { 264291406Sjhb /* 265291406Sjhb * No final-level page table; pde describes one 2MB page. 266291406Sjhb */ 267291406Sjhb a = (pde & AMD64_PG_PS_FRAME) + (va & AMD64_PDRMASK); 268147672Speter s = _kvm_pa2off(kd, a, pa); 269147672Speter if (s == 0) { 270147672Speter _kvm_err(kd, kd->program, 271291406Sjhb "_amd64_vatop: 2MB page address not in dump"); 272147672Speter goto invalid; 273147672Speter } else 274291406Sjhb return (AMD64_NBPDR - (va & AMD64_PDRMASK)); 27528318Stegge } 27628318Stegge 277291406Sjhb pteindex = (va >> AMD64_PAGE_SHIFT) & (AMD64_NPTEPG - 1); 278291406Sjhb pte_pa = (pde & AMD64_PG_FRAME) + (pteindex * sizeof(amd64_pte_t)); 27918798Speter 280147672Speter s = _kvm_pa2off(kd, pte_pa, &ofs); 281291406Sjhb if (s < sizeof(pte)) { 282291406Sjhb _kvm_err(kd, kd->program, "_amd64_vatop: pte_pa not found"); 283147672Speter goto invalid; 284147672Speter } 285291406Sjhb if (pread(kd->pmfd, &pte, sizeof(pte), ofs) != sizeof(pte)) { 286291406Sjhb _kvm_syserr(kd, kd->program, "_amd64_vatop: read"); 28718798Speter goto invalid; 28818798Speter } 289291406Sjhb if ((pte & AMD64_PG_V) == 0) { 290291406Sjhb _kvm_err(kd, kd->program, "_amd64_vatop: pte not valid"); 29118798Speter goto invalid; 29218798Speter } 29318798Speter 294291406Sjhb a = (pte & AMD64_PG_FRAME) + offset; 295147672Speter s = _kvm_pa2off(kd, a, pa); 296147672Speter if (s == 0) { 297291406Sjhb _kvm_err(kd, kd->program, "_amd64_vatop: address not in dump"); 298147672Speter goto invalid; 299147672Speter } else 300291406Sjhb return (AMD64_PAGE_SIZE - offset); 30118798Speter 30218798Speterinvalid: 303291406Sjhb _kvm_err(kd, 0, "invalid address (0x%jx)", (uintmax_t)va); 30418798Speter return (0); 3051602Srgrimes} 3061602Srgrimes 307291406Sjhbstatic int 308291406Sjhb_amd64_kvatop(kvm_t *kd, kvaddr_t va, off_t *pa) 30918798Speter{ 310147672Speter 311147672Speter if (ISALIVE(kd)) { 312147672Speter _kvm_err(kd, 0, "kvm_kvatop called in live kernel!"); 313147672Speter return (0); 314147672Speter } 315291406Sjhb return (_amd64_vatop(kd, va, pa)); 3161602Srgrimes} 317291406Sjhb 318291406Sjhbint 319316126Sngie_amd64_native(kvm_t *kd __unused) 320291406Sjhb{ 321291406Sjhb 322291406Sjhb#ifdef __amd64__ 323291406Sjhb return (1); 324291406Sjhb#else 325291406Sjhb return (0); 326291406Sjhb#endif 327291406Sjhb} 328291406Sjhb 329316126Sngiestatic struct kvm_arch kvm_amd64 = { 330291406Sjhb .ka_probe = _amd64_probe, 331291406Sjhb .ka_initvtop = _amd64_initvtop, 332291406Sjhb .ka_freevtop = _amd64_freevtop, 333291406Sjhb .ka_kvatop = _amd64_kvatop, 334291406Sjhb .ka_native = _amd64_native, 335291406Sjhb}; 336291406Sjhb 337291406SjhbKVM_ARCH(kvm_amd64); 338