1 /*- 2 * Copyright (c) 1989, 1992, 1993 3 * The Regents of the University of California. All rights reserved. 4 * 5 * This code is derived from software developed by the Computer Systems 6 * Engineering group at Lawrence Berkeley Laboratory under DARPA contract 7 * BG 91-66 and contributed to Berkeley. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 3. Neither the name of the University nor the names of its contributors 18 * may be used to endorse or promote products derived from this software 19 * without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 * SUCH DAMAGE. 32 */ 33 34 #include <sys/cdefs.h> 35 __FBSDID("$FreeBSD$"); 36 37 #if defined(LIBC_SCCS) && !defined(lint) 38 #if 0 39 static char sccsid[] = "@(#)kvm_hp300.c 8.1 (Berkeley) 6/4/93"; 40 #endif 41 #endif /* LIBC_SCCS and not lint */ 42 43 /* 44 * i386 machine dependent routines for kvm. Hopefully, the forthcoming 45 * vm code will one day obsolete this module. 46 */ 47 48 #include <sys/param.h> 49 #include <sys/endian.h> 50 #include <stdint.h> 51 #include <stdlib.h> 52 #include <string.h> 53 #include <unistd.h> 54 #include <vm/vm.h> 55 #include <kvm.h> 56 57 #ifdef __i386__ 58 #include <machine/vmparam.h> /* For KERNBASE. */ 59 #endif 60 61 #include <limits.h> 62 63 #include "kvm_private.h" 64 #include "kvm_i386.h" 65 66 struct vmstate { 67 void *PTD; 68 int pae; 69 size_t phnum; 70 GElf_Phdr *phdr; 71 }; 72 73 /* 74 * Translate a physical memory address to a file-offset in the crash-dump. 75 */ 76 static size_t 77 _kvm_pa2off(kvm_t *kd, uint64_t pa, off_t *ofs) 78 { 79 struct vmstate *vm = kd->vmst; 80 GElf_Phdr *p; 81 size_t n; 82 83 if (kd->rawdump) { 84 *ofs = pa; 85 return (I386_PAGE_SIZE - (pa & I386_PAGE_MASK)); 86 } 87 88 p = vm->phdr; 89 n = vm->phnum; 90 while (n && (pa < p->p_paddr || pa >= p->p_paddr + p->p_memsz)) 91 p++, n--; 92 if (n == 0) 93 return (0); 94 *ofs = (pa - p->p_paddr) + p->p_offset; 95 return (I386_PAGE_SIZE - (pa & I386_PAGE_MASK)); 96 } 97 98 static void 99 _i386_freevtop(kvm_t *kd) 100 { 101 struct vmstate *vm = kd->vmst; 102 103 if (vm->PTD) 104 free(vm->PTD); 105 free(vm->phdr); 106 free(vm); 107 kd->vmst = NULL; 108 } 109 110 static int 111 _i386_probe(kvm_t *kd) 112 { 113 114 return (_kvm_probe_elf_kernel(kd, ELFCLASS32, EM_386) && 115 !_kvm_is_minidump(kd)); 116 } 117 118 static int 119 _i386_initvtop(kvm_t *kd) 120 { 121 struct kvm_nlist nl[2]; 122 i386_physaddr_t pa; 123 kvaddr_t kernbase; 124 char *PTD; 125 int i; 126 127 kd->vmst = (struct vmstate *)_kvm_malloc(kd, sizeof(struct vmstate)); 128 if (kd->vmst == NULL) { 129 _kvm_err(kd, kd->program, "cannot allocate vm"); 130 return (-1); 131 } 132 kd->vmst->PTD = 0; 133 134 if (kd->rawdump == 0) { 135 if (_kvm_read_core_phdrs(kd, &kd->vmst->phnum, 136 &kd->vmst->phdr) == -1) 137 return (-1); 138 } 139 140 nl[0].n_name = "kernbase"; 141 nl[1].n_name = 0; 142 143 if (kvm_nlist2(kd, nl) != 0) { 144 #ifdef __i386__ 145 kernbase = KERNBASE; /* for old kernels */ 146 #else 147 _kvm_err(kd, kd->program, "cannot resolve kernbase"); 148 return (-1); 149 #endif 150 } else 151 kernbase = nl[0].n_value; 152 153 nl[0].n_name = "IdlePDPT"; 154 nl[1].n_name = 0; 155 156 if (kvm_nlist2(kd, nl) == 0) { 157 i386_physaddr_pae_t pa64; 158 159 if (kvm_read2(kd, (nl[0].n_value - kernbase), &pa, 160 sizeof(pa)) != sizeof(pa)) { 161 _kvm_err(kd, kd->program, "cannot read IdlePDPT"); 162 return (-1); 163 } 164 pa = le32toh(pa); 165 PTD = _kvm_malloc(kd, 4 * I386_PAGE_SIZE); 166 if (PTD == NULL) { 167 _kvm_err(kd, kd->program, "cannot allocate PTD"); 168 return (-1); 169 } 170 for (i = 0; i < 4; i++) { 171 if (kvm_read2(kd, pa + (i * sizeof(pa64)), &pa64, 172 sizeof(pa64)) != sizeof(pa64)) { 173 _kvm_err(kd, kd->program, "Cannot read PDPT"); 174 free(PTD); 175 return (-1); 176 } 177 pa64 = le64toh(pa64); 178 if (kvm_read2(kd, pa64 & I386_PG_FRAME_PAE, 179 PTD + (i * I386_PAGE_SIZE), I386_PAGE_SIZE) != 180 I386_PAGE_SIZE) { 181 _kvm_err(kd, kd->program, "cannot read PDPT"); 182 free(PTD); 183 return (-1); 184 } 185 } 186 kd->vmst->PTD = PTD; 187 kd->vmst->pae = 1; 188 } else { 189 nl[0].n_name = "IdlePTD"; 190 nl[1].n_name = 0; 191 192 if (kvm_nlist2(kd, nl) != 0) { 193 _kvm_err(kd, kd->program, "bad namelist"); 194 return (-1); 195 } 196 if (kvm_read2(kd, (nl[0].n_value - kernbase), &pa, 197 sizeof(pa)) != sizeof(pa)) { 198 _kvm_err(kd, kd->program, "cannot read IdlePTD"); 199 return (-1); 200 } 201 pa = le32toh(pa); 202 PTD = _kvm_malloc(kd, I386_PAGE_SIZE); 203 if (PTD == NULL) { 204 _kvm_err(kd, kd->program, "cannot allocate PTD"); 205 return (-1); 206 } 207 if (kvm_read2(kd, pa, PTD, I386_PAGE_SIZE) != I386_PAGE_SIZE) { 208 _kvm_err(kd, kd->program, "cannot read PTD"); 209 return (-1); 210 } 211 kd->vmst->PTD = PTD; 212 kd->vmst->pae = 0; 213 } 214 return (0); 215 } 216 217 static int 218 _i386_vatop(kvm_t *kd, kvaddr_t va, off_t *pa) 219 { 220 struct vmstate *vm; 221 i386_physaddr_t offset; 222 i386_physaddr_t pte_pa; 223 i386_pde_t pde; 224 i386_pte_t pte; 225 kvaddr_t pdeindex; 226 kvaddr_t pteindex; 227 size_t s; 228 i386_physaddr_t a; 229 off_t ofs; 230 i386_pde_t *PTD; 231 232 vm = kd->vmst; 233 PTD = (i386_pde_t *)vm->PTD; 234 offset = va & I386_PAGE_MASK; 235 236 /* 237 * If we are initializing (kernel page table descriptor pointer 238 * not yet set) then return pa == va to avoid infinite recursion. 239 */ 240 if (PTD == NULL) { 241 s = _kvm_pa2off(kd, va, pa); 242 if (s == 0) { 243 _kvm_err(kd, kd->program, 244 "_i386_vatop: bootstrap data not in dump"); 245 goto invalid; 246 } else 247 return (I386_PAGE_SIZE - offset); 248 } 249 250 pdeindex = va >> I386_PDRSHIFT; 251 pde = le32toh(PTD[pdeindex]); 252 if ((pde & I386_PG_V) == 0) { 253 _kvm_err(kd, kd->program, "_i386_vatop: pde not valid"); 254 goto invalid; 255 } 256 257 if (pde & I386_PG_PS) { 258 /* 259 * No second-level page table; ptd describes one 4MB 260 * page. (We assume that the kernel wouldn't set 261 * PG_PS without enabling it cr0). 262 */ 263 offset = va & I386_PAGE_PS_MASK; 264 a = (pde & I386_PG_PS_FRAME) + offset; 265 s = _kvm_pa2off(kd, a, pa); 266 if (s == 0) { 267 _kvm_err(kd, kd->program, 268 "_i386_vatop: 4MB page address not in dump"); 269 goto invalid; 270 } 271 return (I386_NBPDR - offset); 272 } 273 274 pteindex = (va >> I386_PAGE_SHIFT) & (I386_NPTEPG - 1); 275 pte_pa = (pde & I386_PG_FRAME) + (pteindex * sizeof(pte)); 276 277 s = _kvm_pa2off(kd, pte_pa, &ofs); 278 if (s < sizeof(pte)) { 279 _kvm_err(kd, kd->program, "_i386_vatop: pte_pa not found"); 280 goto invalid; 281 } 282 283 /* XXX This has to be a physical address read, kvm_read is virtual */ 284 if (pread(kd->pmfd, &pte, sizeof(pte), ofs) != sizeof(pte)) { 285 _kvm_syserr(kd, kd->program, "_i386_vatop: pread"); 286 goto invalid; 287 } 288 pte = le32toh(pte); 289 if ((pte & I386_PG_V) == 0) { 290 _kvm_err(kd, kd->program, "_kvm_kvatop: pte not valid"); 291 goto invalid; 292 } 293 294 a = (pte & I386_PG_FRAME) + offset; 295 s = _kvm_pa2off(kd, a, pa); 296 if (s == 0) { 297 _kvm_err(kd, kd->program, "_i386_vatop: address not in dump"); 298 goto invalid; 299 } else 300 return (I386_PAGE_SIZE - offset); 301 302 invalid: 303 _kvm_err(kd, 0, "invalid address (0x%jx)", (uintmax_t)va); 304 return (0); 305 } 306 307 static int 308 _i386_vatop_pae(kvm_t *kd, kvaddr_t va, off_t *pa) 309 { 310 struct vmstate *vm; 311 i386_physaddr_pae_t offset; 312 i386_physaddr_pae_t pte_pa; 313 i386_pde_pae_t pde; 314 i386_pte_pae_t pte; 315 kvaddr_t pdeindex; 316 kvaddr_t pteindex; 317 size_t s; 318 i386_physaddr_pae_t a; 319 off_t ofs; 320 i386_pde_pae_t *PTD; 321 322 vm = kd->vmst; 323 PTD = (i386_pde_pae_t *)vm->PTD; 324 offset = va & I386_PAGE_MASK; 325 326 /* 327 * If we are initializing (kernel page table descriptor pointer 328 * not yet set) then return pa == va to avoid infinite recursion. 329 */ 330 if (PTD == NULL) { 331 s = _kvm_pa2off(kd, va, pa); 332 if (s == 0) { 333 _kvm_err(kd, kd->program, 334 "_i386_vatop_pae: bootstrap data not in dump"); 335 goto invalid; 336 } else 337 return (I386_PAGE_SIZE - offset); 338 } 339 340 pdeindex = va >> I386_PDRSHIFT_PAE; 341 pde = le64toh(PTD[pdeindex]); 342 if ((pde & I386_PG_V) == 0) { 343 _kvm_err(kd, kd->program, "_kvm_kvatop_pae: pde not valid"); 344 goto invalid; 345 } 346 347 if (pde & I386_PG_PS) { 348 /* 349 * No second-level page table; ptd describes one 2MB 350 * page. (We assume that the kernel wouldn't set 351 * PG_PS without enabling it cr0). 352 */ 353 offset = va & I386_PAGE_PS_MASK_PAE; 354 a = (pde & I386_PG_PS_FRAME_PAE) + offset; 355 s = _kvm_pa2off(kd, a, pa); 356 if (s == 0) { 357 _kvm_err(kd, kd->program, 358 "_i386_vatop: 2MB page address not in dump"); 359 goto invalid; 360 } 361 return (I386_NBPDR_PAE - offset); 362 } 363 364 pteindex = (va >> I386_PAGE_SHIFT) & (I386_NPTEPG_PAE - 1); 365 pte_pa = (pde & I386_PG_FRAME_PAE) + (pteindex * sizeof(pde)); 366 367 s = _kvm_pa2off(kd, pte_pa, &ofs); 368 if (s < sizeof(pte)) { 369 _kvm_err(kd, kd->program, "_i386_vatop_pae: pdpe_pa not found"); 370 goto invalid; 371 } 372 373 /* XXX This has to be a physical address read, kvm_read is virtual */ 374 if (pread(kd->pmfd, &pte, sizeof(pte), ofs) != sizeof(pte)) { 375 _kvm_syserr(kd, kd->program, "_i386_vatop_pae: read"); 376 goto invalid; 377 } 378 pte = le64toh(pte); 379 if ((pte & I386_PG_V) == 0) { 380 _kvm_err(kd, kd->program, "_i386_vatop_pae: pte not valid"); 381 goto invalid; 382 } 383 384 a = (pte & I386_PG_FRAME_PAE) + offset; 385 s = _kvm_pa2off(kd, a, pa); 386 if (s == 0) { 387 _kvm_err(kd, kd->program, 388 "_i386_vatop_pae: address not in dump"); 389 goto invalid; 390 } else 391 return (I386_PAGE_SIZE - offset); 392 393 invalid: 394 _kvm_err(kd, 0, "invalid address (0x%jx)", (uintmax_t)va); 395 return (0); 396 } 397 398 static int 399 _i386_kvatop(kvm_t *kd, kvaddr_t va, off_t *pa) 400 { 401 402 if (ISALIVE(kd)) { 403 _kvm_err(kd, 0, "vatop called in live kernel!"); 404 return (0); 405 } 406 if (kd->vmst->pae) 407 return (_i386_vatop_pae(kd, va, pa)); 408 else 409 return (_i386_vatop(kd, va, pa)); 410 } 411 412 int 413 _i386_native(kvm_t *kd __unused) 414 { 415 416 #ifdef __i386__ 417 return (1); 418 #else 419 return (0); 420 #endif 421 } 422 423 static struct kvm_arch kvm_i386 = { 424 .ka_probe = _i386_probe, 425 .ka_initvtop = _i386_initvtop, 426 .ka_freevtop = _i386_freevtop, 427 .ka_kvatop = _i386_kvatop, 428 .ka_native = _i386_native, 429 }; 430 431 KVM_ARCH(kvm_i386); 432