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 39 #if defined(LIBC_SCCS) && !defined(lint) 40 #if 0 41 static char sccsid[] = "@(#)kvm_hp300.c 8.1 (Berkeley) 6/4/93"; 42 #endif 43 #endif /* LIBC_SCCS and not lint */ 44 45 /* 46 * i386 machine dependent routines for kvm. Hopefully, the forthcoming 47 * vm code will one day obsolete this module. 48 */ 49 50 #include <sys/param.h> 51 #include <sys/endian.h> 52 #include <stdint.h> 53 #include <stdlib.h> 54 #include <string.h> 55 #include <unistd.h> 56 #include <vm/vm.h> 57 #include <kvm.h> 58 59 #ifdef __i386__ 60 #include <machine/vmparam.h> /* For KERNBASE. */ 61 #endif 62 63 #include <limits.h> 64 65 #include "kvm_private.h" 66 #include "kvm_i386.h" 67 68 struct vmstate { 69 void *PTD; 70 int pae; 71 size_t phnum; 72 GElf_Phdr *phdr; 73 }; 74 75 /* 76 * Translate a physical memory address to a file-offset in the crash-dump. 77 */ 78 static size_t 79 _kvm_pa2off(kvm_t *kd, uint64_t pa, off_t *ofs) 80 { 81 struct vmstate *vm = kd->vmst; 82 GElf_Phdr *p; 83 size_t n; 84 85 if (kd->rawdump) { 86 *ofs = pa; 87 return (I386_PAGE_SIZE - (pa & I386_PAGE_MASK)); 88 } 89 90 p = vm->phdr; 91 n = vm->phnum; 92 while (n && (pa < p->p_paddr || pa >= p->p_paddr + p->p_memsz)) 93 p++, n--; 94 if (n == 0) 95 return (0); 96 *ofs = (pa - p->p_paddr) + p->p_offset; 97 return (I386_PAGE_SIZE - (pa & I386_PAGE_MASK)); 98 } 99 100 static void 101 _i386_freevtop(kvm_t *kd) 102 { 103 struct vmstate *vm = kd->vmst; 104 105 if (vm->PTD) 106 free(vm->PTD); 107 free(vm->phdr); 108 free(vm); 109 kd->vmst = NULL; 110 } 111 112 static int 113 _i386_probe(kvm_t *kd) 114 { 115 116 return (_kvm_probe_elf_kernel(kd, ELFCLASS32, EM_386) && 117 !_kvm_is_minidump(kd)); 118 } 119 120 static int 121 _i386_initvtop(kvm_t *kd) 122 { 123 struct kvm_nlist nl[2]; 124 i386_physaddr_t pa; 125 kvaddr_t kernbase; 126 char *PTD; 127 int i; 128 129 kd->vmst = (struct vmstate *)_kvm_malloc(kd, sizeof(struct vmstate)); 130 if (kd->vmst == NULL) { 131 _kvm_err(kd, kd->program, "cannot allocate vm"); 132 return (-1); 133 } 134 kd->vmst->PTD = 0; 135 136 if (kd->rawdump == 0) { 137 if (_kvm_read_core_phdrs(kd, &kd->vmst->phnum, 138 &kd->vmst->phdr) == -1) 139 return (-1); 140 } 141 142 nl[0].n_name = "kernbase"; 143 nl[1].n_name = 0; 144 145 if (kvm_nlist2(kd, nl) != 0) { 146 #ifdef __i386__ 147 kernbase = KERNBASE; /* for old kernels */ 148 #else 149 _kvm_err(kd, kd->program, "cannot resolve kernbase"); 150 return (-1); 151 #endif 152 } else 153 kernbase = nl[0].n_value; 154 155 nl[0].n_name = "IdlePDPT"; 156 nl[1].n_name = 0; 157 158 if (kvm_nlist2(kd, nl) == 0) { 159 i386_physaddr_pae_t pa64; 160 161 if (kvm_read2(kd, (nl[0].n_value - kernbase), &pa, 162 sizeof(pa)) != sizeof(pa)) { 163 _kvm_err(kd, kd->program, "cannot read IdlePDPT"); 164 return (-1); 165 } 166 pa = le32toh(pa); 167 PTD = _kvm_malloc(kd, 4 * I386_PAGE_SIZE); 168 if (PTD == NULL) { 169 _kvm_err(kd, kd->program, "cannot allocate PTD"); 170 return (-1); 171 } 172 for (i = 0; i < 4; i++) { 173 if (kvm_read2(kd, pa + (i * sizeof(pa64)), &pa64, 174 sizeof(pa64)) != sizeof(pa64)) { 175 _kvm_err(kd, kd->program, "Cannot read PDPT"); 176 free(PTD); 177 return (-1); 178 } 179 pa64 = le64toh(pa64); 180 if (kvm_read2(kd, pa64 & I386_PG_FRAME_PAE, 181 PTD + (i * I386_PAGE_SIZE), I386_PAGE_SIZE) != 182 I386_PAGE_SIZE) { 183 _kvm_err(kd, kd->program, "cannot read PDPT"); 184 free(PTD); 185 return (-1); 186 } 187 } 188 kd->vmst->PTD = PTD; 189 kd->vmst->pae = 1; 190 } else { 191 nl[0].n_name = "IdlePTD"; 192 nl[1].n_name = 0; 193 194 if (kvm_nlist2(kd, nl) != 0) { 195 _kvm_err(kd, kd->program, "bad namelist"); 196 return (-1); 197 } 198 if (kvm_read2(kd, (nl[0].n_value - kernbase), &pa, 199 sizeof(pa)) != sizeof(pa)) { 200 _kvm_err(kd, kd->program, "cannot read IdlePTD"); 201 return (-1); 202 } 203 pa = le32toh(pa); 204 PTD = _kvm_malloc(kd, I386_PAGE_SIZE); 205 if (PTD == NULL) { 206 _kvm_err(kd, kd->program, "cannot allocate PTD"); 207 return (-1); 208 } 209 if (kvm_read2(kd, pa, PTD, I386_PAGE_SIZE) != I386_PAGE_SIZE) { 210 _kvm_err(kd, kd->program, "cannot read PTD"); 211 return (-1); 212 } 213 kd->vmst->PTD = PTD; 214 kd->vmst->pae = 0; 215 } 216 return (0); 217 } 218 219 static int 220 _i386_vatop(kvm_t *kd, kvaddr_t va, off_t *pa) 221 { 222 struct vmstate *vm; 223 i386_physaddr_t offset; 224 i386_physaddr_t pte_pa; 225 i386_pde_t pde; 226 i386_pte_t pte; 227 kvaddr_t pdeindex; 228 kvaddr_t pteindex; 229 size_t s; 230 i386_physaddr_t a; 231 off_t ofs; 232 i386_pde_t *PTD; 233 234 vm = kd->vmst; 235 PTD = (i386_pde_t *)vm->PTD; 236 offset = va & I386_PAGE_MASK; 237 238 /* 239 * If we are initializing (kernel page table descriptor pointer 240 * not yet set) then return pa == va to avoid infinite recursion. 241 */ 242 if (PTD == NULL) { 243 s = _kvm_pa2off(kd, va, pa); 244 if (s == 0) { 245 _kvm_err(kd, kd->program, 246 "_i386_vatop: bootstrap data not in dump"); 247 goto invalid; 248 } else 249 return (I386_PAGE_SIZE - offset); 250 } 251 252 pdeindex = va >> I386_PDRSHIFT; 253 pde = le32toh(PTD[pdeindex]); 254 if ((pde & I386_PG_V) == 0) { 255 _kvm_err(kd, kd->program, "_i386_vatop: pde not valid"); 256 goto invalid; 257 } 258 259 if (pde & I386_PG_PS) { 260 /* 261 * No second-level page table; ptd describes one 4MB 262 * page. (We assume that the kernel wouldn't set 263 * PG_PS without enabling it cr0). 264 */ 265 offset = va & I386_PAGE_PS_MASK; 266 a = (pde & I386_PG_PS_FRAME) + offset; 267 s = _kvm_pa2off(kd, a, pa); 268 if (s == 0) { 269 _kvm_err(kd, kd->program, 270 "_i386_vatop: 4MB page address not in dump"); 271 goto invalid; 272 } 273 return (I386_NBPDR - offset); 274 } 275 276 pteindex = (va >> I386_PAGE_SHIFT) & (I386_NPTEPG - 1); 277 pte_pa = (pde & I386_PG_FRAME) + (pteindex * sizeof(pte)); 278 279 s = _kvm_pa2off(kd, pte_pa, &ofs); 280 if (s < sizeof(pte)) { 281 _kvm_err(kd, kd->program, "_i386_vatop: pte_pa not found"); 282 goto invalid; 283 } 284 285 /* XXX This has to be a physical address read, kvm_read is virtual */ 286 if (pread(kd->pmfd, &pte, sizeof(pte), ofs) != sizeof(pte)) { 287 _kvm_syserr(kd, kd->program, "_i386_vatop: pread"); 288 goto invalid; 289 } 290 pte = le32toh(pte); 291 if ((pte & I386_PG_V) == 0) { 292 _kvm_err(kd, kd->program, "_kvm_kvatop: pte not valid"); 293 goto invalid; 294 } 295 296 a = (pte & I386_PG_FRAME) + offset; 297 s = _kvm_pa2off(kd, a, pa); 298 if (s == 0) { 299 _kvm_err(kd, kd->program, "_i386_vatop: address not in dump"); 300 goto invalid; 301 } else 302 return (I386_PAGE_SIZE - offset); 303 304 invalid: 305 _kvm_err(kd, 0, "invalid address (0x%jx)", (uintmax_t)va); 306 return (0); 307 } 308 309 static int 310 _i386_vatop_pae(kvm_t *kd, kvaddr_t va, off_t *pa) 311 { 312 struct vmstate *vm; 313 i386_physaddr_pae_t offset; 314 i386_physaddr_pae_t pte_pa; 315 i386_pde_pae_t pde; 316 i386_pte_pae_t pte; 317 kvaddr_t pdeindex; 318 kvaddr_t pteindex; 319 size_t s; 320 i386_physaddr_pae_t a; 321 off_t ofs; 322 i386_pde_pae_t *PTD; 323 324 vm = kd->vmst; 325 PTD = (i386_pde_pae_t *)vm->PTD; 326 offset = va & I386_PAGE_MASK; 327 328 /* 329 * If we are initializing (kernel page table descriptor pointer 330 * not yet set) then return pa == va to avoid infinite recursion. 331 */ 332 if (PTD == NULL) { 333 s = _kvm_pa2off(kd, va, pa); 334 if (s == 0) { 335 _kvm_err(kd, kd->program, 336 "_i386_vatop_pae: bootstrap data not in dump"); 337 goto invalid; 338 } else 339 return (I386_PAGE_SIZE - offset); 340 } 341 342 pdeindex = va >> I386_PDRSHIFT_PAE; 343 pde = le64toh(PTD[pdeindex]); 344 if ((pde & I386_PG_V) == 0) { 345 _kvm_err(kd, kd->program, "_kvm_kvatop_pae: pde not valid"); 346 goto invalid; 347 } 348 349 if (pde & I386_PG_PS) { 350 /* 351 * No second-level page table; ptd describes one 2MB 352 * page. (We assume that the kernel wouldn't set 353 * PG_PS without enabling it cr0). 354 */ 355 offset = va & I386_PAGE_PS_MASK_PAE; 356 a = (pde & I386_PG_PS_FRAME_PAE) + offset; 357 s = _kvm_pa2off(kd, a, pa); 358 if (s == 0) { 359 _kvm_err(kd, kd->program, 360 "_i386_vatop: 2MB page address not in dump"); 361 goto invalid; 362 } 363 return (I386_NBPDR_PAE - offset); 364 } 365 366 pteindex = (va >> I386_PAGE_SHIFT) & (I386_NPTEPG_PAE - 1); 367 pte_pa = (pde & I386_PG_FRAME_PAE) + (pteindex * sizeof(pde)); 368 369 s = _kvm_pa2off(kd, pte_pa, &ofs); 370 if (s < sizeof(pte)) { 371 _kvm_err(kd, kd->program, "_i386_vatop_pae: pdpe_pa not found"); 372 goto invalid; 373 } 374 375 /* XXX This has to be a physical address read, kvm_read is virtual */ 376 if (pread(kd->pmfd, &pte, sizeof(pte), ofs) != sizeof(pte)) { 377 _kvm_syserr(kd, kd->program, "_i386_vatop_pae: read"); 378 goto invalid; 379 } 380 pte = le64toh(pte); 381 if ((pte & I386_PG_V) == 0) { 382 _kvm_err(kd, kd->program, "_i386_vatop_pae: pte not valid"); 383 goto invalid; 384 } 385 386 a = (pte & I386_PG_FRAME_PAE) + offset; 387 s = _kvm_pa2off(kd, a, pa); 388 if (s == 0) { 389 _kvm_err(kd, kd->program, 390 "_i386_vatop_pae: address not in dump"); 391 goto invalid; 392 } else 393 return (I386_PAGE_SIZE - offset); 394 395 invalid: 396 _kvm_err(kd, 0, "invalid address (0x%jx)", (uintmax_t)va); 397 return (0); 398 } 399 400 static int 401 _i386_kvatop(kvm_t *kd, kvaddr_t va, off_t *pa) 402 { 403 404 if (ISALIVE(kd)) { 405 _kvm_err(kd, 0, "vatop called in live kernel!"); 406 return (0); 407 } 408 if (kd->vmst->pae) 409 return (_i386_vatop_pae(kd, va, pa)); 410 else 411 return (_i386_vatop(kd, va, pa)); 412 } 413 414 int 415 _i386_native(kvm_t *kd __unused) 416 { 417 418 #ifdef __i386__ 419 return (1); 420 #else 421 return (0); 422 #endif 423 } 424 425 static struct kvm_arch kvm_i386 = { 426 .ka_probe = _i386_probe, 427 .ka_initvtop = _i386_initvtop, 428 .ka_freevtop = _i386_freevtop, 429 .ka_kvatop = _i386_kvatop, 430 .ka_native = _i386_native, 431 }; 432 433 KVM_ARCH(kvm_i386); 434