1 /*- 2 * SPDX-License-Identifier: BSD-3-Clause 3 * 4 * Copyright (c) 1989, 1992, 1993 5 * The Regents of the University of California. All rights reserved. 6 * 7 * This code is derived from software developed by the Computer Systems 8 * Engineering group at Lawrence Berkeley Laboratory under DARPA contract 9 * BG 91-66 and contributed to Berkeley. 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted provided that the following conditions 13 * are met: 14 * 1. Redistributions of source code must retain the above copyright 15 * notice, this list of conditions and the following disclaimer. 16 * 2. Redistributions in binary form must reproduce the above copyright 17 * notice, this list of conditions and the following disclaimer in the 18 * documentation and/or other materials provided with the distribution. 19 * 3. Neither the name of the University nor the names of its contributors 20 * may be used to endorse or promote products derived from this software 21 * without specific prior written permission. 22 * 23 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33 * SUCH DAMAGE. 34 */ 35 36 #include <sys/cdefs.h> 37 __FBSDID("$FreeBSD$"); 38 __SCCSID("@(#)kvm_hp300.c 8.1 (Berkeley) 6/4/93"); 39 40 /* 41 * AMD64 machine dependent routines for kvm. Hopefully, the forthcoming 42 * vm code will one day obsolete this module. 43 */ 44 45 #include <sys/param.h> 46 #include <sys/endian.h> 47 #include <stdint.h> 48 #include <stdlib.h> 49 #include <string.h> 50 #include <unistd.h> 51 #include <vm/vm.h> 52 #include <kvm.h> 53 54 #include <limits.h> 55 56 #include "kvm_private.h" 57 #include "kvm_amd64.h" 58 59 struct vmstate { 60 size_t phnum; 61 GElf_Phdr *phdr; 62 amd64_pml4e_t *PML4; 63 }; 64 65 /* 66 * Translate a physical memory address to a file-offset in the crash-dump. 67 */ 68 static size_t 69 _kvm_pa2off(kvm_t *kd, uint64_t pa, off_t *ofs) 70 { 71 struct vmstate *vm = kd->vmst; 72 GElf_Phdr *p; 73 size_t n; 74 75 if (kd->rawdump) { 76 *ofs = pa; 77 return (AMD64_PAGE_SIZE - (pa & AMD64_PAGE_MASK)); 78 } 79 80 p = vm->phdr; 81 n = vm->phnum; 82 while (n && (pa < p->p_paddr || pa >= p->p_paddr + p->p_memsz)) 83 p++, n--; 84 if (n == 0) 85 return (0); 86 *ofs = (pa - p->p_paddr) + p->p_offset; 87 return (AMD64_PAGE_SIZE - (pa & AMD64_PAGE_MASK)); 88 } 89 90 static void 91 _amd64_freevtop(kvm_t *kd) 92 { 93 struct vmstate *vm = kd->vmst; 94 95 if (vm->PML4) 96 free(vm->PML4); 97 free(vm->phdr); 98 free(vm); 99 kd->vmst = NULL; 100 } 101 102 static int 103 _amd64_probe(kvm_t *kd) 104 { 105 106 return (_kvm_probe_elf_kernel(kd, ELFCLASS64, EM_X86_64) && 107 !_kvm_is_minidump(kd)); 108 } 109 110 static int 111 _amd64_initvtop(kvm_t *kd) 112 { 113 struct kvm_nlist nl[2]; 114 amd64_physaddr_t pa; 115 kvaddr_t kernbase; 116 amd64_pml4e_t *PML4; 117 118 kd->vmst = (struct vmstate *)_kvm_malloc(kd, sizeof(*kd->vmst)); 119 if (kd->vmst == NULL) { 120 _kvm_err(kd, kd->program, "cannot allocate vm"); 121 return (-1); 122 } 123 kd->vmst->PML4 = 0; 124 125 if (kd->rawdump == 0) { 126 if (_kvm_read_core_phdrs(kd, &kd->vmst->phnum, 127 &kd->vmst->phdr) == -1) 128 return (-1); 129 } 130 131 nl[0].n_name = "kernbase"; 132 nl[1].n_name = 0; 133 134 if (kvm_nlist2(kd, nl) != 0) { 135 _kvm_err(kd, kd->program, "bad namelist - no kernbase"); 136 return (-1); 137 } 138 kernbase = nl[0].n_value; 139 140 nl[0].n_name = "KPML4phys"; 141 nl[1].n_name = 0; 142 143 if (kvm_nlist2(kd, nl) != 0) { 144 _kvm_err(kd, kd->program, "bad namelist - no KPML4phys"); 145 return (-1); 146 } 147 if (kvm_read2(kd, (nl[0].n_value - kernbase), &pa, sizeof(pa)) != 148 sizeof(pa)) { 149 _kvm_err(kd, kd->program, "cannot read KPML4phys"); 150 return (-1); 151 } 152 pa = le64toh(pa); 153 PML4 = _kvm_malloc(kd, AMD64_PAGE_SIZE); 154 if (PML4 == NULL) { 155 _kvm_err(kd, kd->program, "cannot allocate PML4"); 156 return (-1); 157 } 158 if (kvm_read2(kd, pa, PML4, AMD64_PAGE_SIZE) != AMD64_PAGE_SIZE) { 159 _kvm_err(kd, kd->program, "cannot read KPML4phys"); 160 free(PML4); 161 return (-1); 162 } 163 kd->vmst->PML4 = PML4; 164 return (0); 165 } 166 167 static int 168 _amd64_vatop(kvm_t *kd, kvaddr_t va, off_t *pa) 169 { 170 struct vmstate *vm; 171 amd64_physaddr_t offset; 172 amd64_physaddr_t pdpe_pa; 173 amd64_physaddr_t pde_pa; 174 amd64_physaddr_t pte_pa; 175 amd64_pml4e_t pml4e; 176 amd64_pdpe_t pdpe; 177 amd64_pde_t pde; 178 amd64_pte_t pte; 179 kvaddr_t pml4eindex; 180 kvaddr_t pdpeindex; 181 kvaddr_t pdeindex; 182 kvaddr_t pteindex; 183 amd64_physaddr_t a; 184 off_t ofs; 185 size_t s; 186 187 vm = kd->vmst; 188 offset = va & AMD64_PAGE_MASK; 189 190 /* 191 * If we are initializing (kernel page table descriptor pointer 192 * not yet set) then return pa == va to avoid infinite recursion. 193 */ 194 if (vm->PML4 == NULL) { 195 s = _kvm_pa2off(kd, va, pa); 196 if (s == 0) { 197 _kvm_err(kd, kd->program, 198 "_amd64_vatop: bootstrap data not in dump"); 199 goto invalid; 200 } else 201 return (AMD64_PAGE_SIZE - offset); 202 } 203 204 pml4eindex = (va >> AMD64_PML4SHIFT) & (AMD64_NPML4EPG - 1); 205 pml4e = le64toh(vm->PML4[pml4eindex]); 206 if ((pml4e & AMD64_PG_V) == 0) { 207 _kvm_err(kd, kd->program, "_amd64_vatop: pml4e not valid"); 208 goto invalid; 209 } 210 211 pdpeindex = (va >> AMD64_PDPSHIFT) & (AMD64_NPDPEPG - 1); 212 pdpe_pa = (pml4e & AMD64_PG_FRAME) + (pdpeindex * sizeof(amd64_pdpe_t)); 213 214 s = _kvm_pa2off(kd, pdpe_pa, &ofs); 215 if (s < sizeof(pdpe)) { 216 _kvm_err(kd, kd->program, "_amd64_vatop: pdpe_pa not found"); 217 goto invalid; 218 } 219 if (pread(kd->pmfd, &pdpe, sizeof(pdpe), ofs) != sizeof(pdpe)) { 220 _kvm_syserr(kd, kd->program, "_amd64_vatop: read pdpe"); 221 goto invalid; 222 } 223 pdpe = le64toh(pdpe); 224 if ((pdpe & AMD64_PG_V) == 0) { 225 _kvm_err(kd, kd->program, "_amd64_vatop: pdpe not valid"); 226 goto invalid; 227 } 228 229 if (pdpe & AMD64_PG_PS) { 230 /* 231 * No next-level page table; pdpe describes one 1GB page. 232 */ 233 a = (pdpe & AMD64_PG_1GB_FRAME) + (va & AMD64_PDPMASK); 234 s = _kvm_pa2off(kd, a, pa); 235 if (s == 0) { 236 _kvm_err(kd, kd->program, 237 "_amd64_vatop: 1GB page address not in dump"); 238 goto invalid; 239 } else 240 return (AMD64_NBPDP - (va & AMD64_PDPMASK)); 241 } 242 243 pdeindex = (va >> AMD64_PDRSHIFT) & (AMD64_NPDEPG - 1); 244 pde_pa = (pdpe & AMD64_PG_FRAME) + (pdeindex * sizeof(amd64_pde_t)); 245 246 s = _kvm_pa2off(kd, pde_pa, &ofs); 247 if (s < sizeof(pde)) { 248 _kvm_syserr(kd, kd->program, "_amd64_vatop: pde_pa not found"); 249 goto invalid; 250 } 251 if (pread(kd->pmfd, &pde, sizeof(pde), ofs) != sizeof(pde)) { 252 _kvm_syserr(kd, kd->program, "_amd64_vatop: read pde"); 253 goto invalid; 254 } 255 pde = le64toh(pde); 256 if ((pde & AMD64_PG_V) == 0) { 257 _kvm_err(kd, kd->program, "_amd64_vatop: pde not valid"); 258 goto invalid; 259 } 260 261 if (pde & AMD64_PG_PS) { 262 /* 263 * No final-level page table; pde describes one 2MB page. 264 */ 265 a = (pde & AMD64_PG_PS_FRAME) + (va & AMD64_PDRMASK); 266 s = _kvm_pa2off(kd, a, pa); 267 if (s == 0) { 268 _kvm_err(kd, kd->program, 269 "_amd64_vatop: 2MB page address not in dump"); 270 goto invalid; 271 } else 272 return (AMD64_NBPDR - (va & AMD64_PDRMASK)); 273 } 274 275 pteindex = (va >> AMD64_PAGE_SHIFT) & (AMD64_NPTEPG - 1); 276 pte_pa = (pde & AMD64_PG_FRAME) + (pteindex * sizeof(amd64_pte_t)); 277 278 s = _kvm_pa2off(kd, pte_pa, &ofs); 279 if (s < sizeof(pte)) { 280 _kvm_err(kd, kd->program, "_amd64_vatop: pte_pa not found"); 281 goto invalid; 282 } 283 if (pread(kd->pmfd, &pte, sizeof(pte), ofs) != sizeof(pte)) { 284 _kvm_syserr(kd, kd->program, "_amd64_vatop: read"); 285 goto invalid; 286 } 287 if ((pte & AMD64_PG_V) == 0) { 288 _kvm_err(kd, kd->program, "_amd64_vatop: pte not valid"); 289 goto invalid; 290 } 291 292 a = (pte & AMD64_PG_FRAME) + offset; 293 s = _kvm_pa2off(kd, a, pa); 294 if (s == 0) { 295 _kvm_err(kd, kd->program, "_amd64_vatop: address not in dump"); 296 goto invalid; 297 } else 298 return (AMD64_PAGE_SIZE - offset); 299 300 invalid: 301 _kvm_err(kd, 0, "invalid address (0x%jx)", (uintmax_t)va); 302 return (0); 303 } 304 305 static int 306 _amd64_kvatop(kvm_t *kd, kvaddr_t va, off_t *pa) 307 { 308 309 if (ISALIVE(kd)) { 310 _kvm_err(kd, 0, "kvm_kvatop called in live kernel!"); 311 return (0); 312 } 313 return (_amd64_vatop(kd, va, pa)); 314 } 315 316 int 317 _amd64_native(kvm_t *kd __unused) 318 { 319 320 #ifdef __amd64__ 321 return (1); 322 #else 323 return (0); 324 #endif 325 } 326 327 static struct kvm_arch kvm_amd64 = { 328 .ka_probe = _amd64_probe, 329 .ka_initvtop = _amd64_initvtop, 330 .ka_freevtop = _amd64_freevtop, 331 .ka_kvatop = _amd64_kvatop, 332 .ka_native = _amd64_native, 333 }; 334 335 KVM_ARCH(kvm_amd64); 336