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