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 * 4. 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/user.h> 50 #include <sys/proc.h> 51 #include <sys/stat.h> 52 #include <sys/mman.h> 53 #include <stdlib.h> 54 #include <unistd.h> 55 #include <nlist.h> 56 #include <kvm.h> 57 58 #include <vm/vm.h> 59 #include <vm/vm_param.h> 60 61 #include <machine/elf.h> 62 63 #include <limits.h> 64 65 #include "kvm_private.h" 66 67 #ifndef btop 68 #define btop(x) (i386_btop(x)) 69 #define ptob(x) (i386_ptob(x)) 70 #endif 71 72 #define PG_FRAME_PAE (~((uint64_t)PAGE_MASK)) 73 #define PDRSHIFT_PAE 21 74 #define NPTEPG_PAE (PAGE_SIZE/sizeof(uint64_t)) 75 #define NBPDR_PAE (1<<PDRSHIFT_PAE) 76 77 /* minidump must be the first item! */ 78 struct vmstate { 79 int minidump; /* 1 = minidump mode */ 80 void *mmapbase; 81 size_t mmapsize; 82 void *PTD; 83 int pae; 84 }; 85 86 /* 87 * Map the ELF headers into the process' address space. We do this in two 88 * steps: first the ELF header itself and using that information the whole 89 * set of headers. (Taken from kvm_ia64.c) 90 */ 91 static int 92 _kvm_maphdrs(kvm_t *kd, size_t sz) 93 { 94 struct vmstate *vm = kd->vmst; 95 96 /* munmap() previous mmap(). */ 97 if (vm->mmapbase != NULL) { 98 munmap(vm->mmapbase, vm->mmapsize); 99 vm->mmapbase = NULL; 100 } 101 102 vm->mmapsize = sz; 103 vm->mmapbase = mmap(NULL, sz, PROT_READ, MAP_PRIVATE, kd->pmfd, 0); 104 if (vm->mmapbase == MAP_FAILED) { 105 _kvm_err(kd, kd->program, "cannot mmap corefile"); 106 return (-1); 107 } 108 return (0); 109 } 110 111 /* 112 * Translate a physical memory address to a file-offset in the crash-dump. 113 * (Taken from kvm_ia64.c) 114 */ 115 static size_t 116 _kvm_pa2off(kvm_t *kd, uint64_t pa, off_t *ofs) 117 { 118 Elf_Ehdr *e = kd->vmst->mmapbase; 119 Elf_Phdr *p = (Elf_Phdr*)((char*)e + e->e_phoff); 120 int n = e->e_phnum; 121 122 while (n && (pa < p->p_paddr || pa >= p->p_paddr + p->p_memsz)) 123 p++, n--; 124 if (n == 0) 125 return (0); 126 *ofs = (pa - p->p_paddr) + p->p_offset; 127 return (PAGE_SIZE - ((size_t)pa & PAGE_MASK)); 128 } 129 130 void 131 _kvm_freevtop(kvm_t *kd) 132 { 133 struct vmstate *vm = kd->vmst; 134 135 if (kd->vmst->minidump) 136 return (_kvm_minidump_freevtop(kd)); 137 if (vm->mmapbase != NULL) 138 munmap(vm->mmapbase, vm->mmapsize); 139 if (vm->PTD) 140 free(vm->PTD); 141 free(vm); 142 kd->vmst = NULL; 143 } 144 145 int 146 _kvm_initvtop(kvm_t *kd) 147 { 148 struct nlist nlist[2]; 149 u_long pa; 150 u_long kernbase; 151 char *PTD; 152 Elf_Ehdr *ehdr; 153 size_t hdrsz; 154 int i; 155 char minihdr[8]; 156 157 if (pread(kd->pmfd, &minihdr, 8, 0) == 8) 158 if (memcmp(&minihdr, "minidump", 8) == 0) 159 return (_kvm_minidump_initvtop(kd)); 160 161 kd->vmst = (struct vmstate *)_kvm_malloc(kd, sizeof(*kd->vmst)); 162 if (kd->vmst == 0) { 163 _kvm_err(kd, kd->program, "cannot allocate vm"); 164 return (-1); 165 } 166 kd->vmst->PTD = 0; 167 168 if (_kvm_maphdrs(kd, sizeof(Elf_Ehdr)) == -1) 169 return (-1); 170 171 ehdr = kd->vmst->mmapbase; 172 hdrsz = ehdr->e_phoff + ehdr->e_phentsize * ehdr->e_phnum; 173 if (_kvm_maphdrs(kd, hdrsz) == -1) 174 return (-1); 175 176 nlist[0].n_name = "kernbase"; 177 nlist[1].n_name = 0; 178 179 if (kvm_nlist(kd, nlist) != 0) 180 kernbase = KERNBASE; /* for old kernels */ 181 else 182 kernbase = nlist[0].n_value; 183 184 nlist[0].n_name = "IdlePDPT"; 185 nlist[1].n_name = 0; 186 187 if (kvm_nlist(kd, nlist) == 0) { 188 uint64_t pa64; 189 190 if (kvm_read(kd, (nlist[0].n_value - kernbase), &pa, 191 sizeof(pa)) != sizeof(pa)) { 192 _kvm_err(kd, kd->program, "cannot read IdlePDPT"); 193 return (-1); 194 } 195 PTD = _kvm_malloc(kd, 4 * PAGE_SIZE); 196 for (i = 0; i < 4; i++) { 197 if (kvm_read(kd, pa + (i * sizeof(pa64)), &pa64, 198 sizeof(pa64)) != sizeof(pa64)) { 199 _kvm_err(kd, kd->program, "Cannot read PDPT"); 200 free(PTD); 201 return (-1); 202 } 203 if (kvm_read(kd, pa64 & PG_FRAME_PAE, 204 PTD + (i * PAGE_SIZE), PAGE_SIZE) != (PAGE_SIZE)) { 205 _kvm_err(kd, kd->program, "cannot read PDPT"); 206 free(PTD); 207 return (-1); 208 } 209 } 210 kd->vmst->PTD = PTD; 211 kd->vmst->pae = 1; 212 } else { 213 nlist[0].n_name = "IdlePTD"; 214 nlist[1].n_name = 0; 215 216 if (kvm_nlist(kd, nlist) != 0) { 217 _kvm_err(kd, kd->program, "bad namelist"); 218 return (-1); 219 } 220 if (kvm_read(kd, (nlist[0].n_value - kernbase), &pa, 221 sizeof(pa)) != sizeof(pa)) { 222 _kvm_err(kd, kd->program, "cannot read IdlePTD"); 223 return (-1); 224 } 225 PTD = _kvm_malloc(kd, PAGE_SIZE); 226 if (kvm_read(kd, pa, PTD, PAGE_SIZE) != PAGE_SIZE) { 227 _kvm_err(kd, kd->program, "cannot read PTD"); 228 return (-1); 229 } 230 kd->vmst->PTD = PTD; 231 return (0); 232 kd->vmst->pae = 0; 233 } 234 return (0); 235 } 236 237 static int 238 _kvm_vatop(kvm_t *kd, u_long va, off_t *pa) 239 { 240 struct vmstate *vm; 241 u_long offset; 242 u_long pte_pa; 243 u_long pde_pa; 244 pd_entry_t pde; 245 pt_entry_t pte; 246 u_long pdeindex; 247 u_long pteindex; 248 size_t s; 249 u_long a; 250 off_t ofs; 251 uint32_t *PTD; 252 253 vm = kd->vmst; 254 PTD = (uint32_t *)vm->PTD; 255 offset = va & (PAGE_SIZE - 1); 256 257 /* 258 * If we are initializing (kernel page table descriptor pointer 259 * not yet set) then return pa == va to avoid infinite recursion. 260 */ 261 if (PTD == 0) { 262 s = _kvm_pa2off(kd, va, pa); 263 if (s == 0) { 264 _kvm_err(kd, kd->program, 265 "_kvm_vatop: bootstrap data not in dump"); 266 goto invalid; 267 } else 268 return (PAGE_SIZE - offset); 269 } 270 271 pdeindex = va >> PDRSHIFT; 272 pde = PTD[pdeindex]; 273 if (((u_long)pde & PG_V) == 0) { 274 _kvm_err(kd, kd->program, "_kvm_vatop: pde not valid"); 275 goto invalid; 276 } 277 278 if ((u_long)pde & PG_PS) { 279 /* 280 * No second-level page table; ptd describes one 4MB page. 281 * (We assume that the kernel wouldn't set PG_PS without enabling 282 * it cr0). 283 */ 284 #define PAGE4M_MASK (NBPDR - 1) 285 #define PG_FRAME4M (~PAGE4M_MASK) 286 pde_pa = ((u_long)pde & PG_FRAME4M) + (va & PAGE4M_MASK); 287 s = _kvm_pa2off(kd, pde_pa, &ofs); 288 if (s < sizeof pde) { 289 _kvm_syserr(kd, kd->program, 290 "_kvm_vatop: pde_pa not found"); 291 goto invalid; 292 } 293 *pa = ofs; 294 return (NBPDR - (va & PAGE4M_MASK)); 295 } 296 297 pteindex = (va >> PAGE_SHIFT) & (NPTEPG-1); 298 pte_pa = ((u_long)pde & PG_FRAME) + (pteindex * sizeof(pde)); 299 300 s = _kvm_pa2off(kd, pte_pa, &ofs); 301 if (s < sizeof pte) { 302 _kvm_err(kd, kd->program, "_kvm_vatop: pdpe_pa not found"); 303 goto invalid; 304 } 305 306 /* XXX This has to be a physical address read, kvm_read is virtual */ 307 if (lseek(kd->pmfd, ofs, 0) == -1) { 308 _kvm_syserr(kd, kd->program, "_kvm_vatop: lseek"); 309 goto invalid; 310 } 311 if (read(kd->pmfd, &pte, sizeof pte) != sizeof pte) { 312 _kvm_syserr(kd, kd->program, "_kvm_vatop: read"); 313 goto invalid; 314 } 315 if (((u_long)pte & PG_V) == 0) { 316 _kvm_err(kd, kd->program, "_kvm_kvatop: pte not valid"); 317 goto invalid; 318 } 319 320 a = ((u_long)pte & PG_FRAME) + offset; 321 s =_kvm_pa2off(kd, a, pa); 322 if (s == 0) { 323 _kvm_err(kd, kd->program, "_kvm_vatop: address not in dump"); 324 goto invalid; 325 } else 326 return (PAGE_SIZE - offset); 327 328 invalid: 329 _kvm_err(kd, 0, "invalid address (0x%lx)", va); 330 return (0); 331 } 332 333 static int 334 _kvm_vatop_pae(kvm_t *kd, u_long va, off_t *pa) 335 { 336 struct vmstate *vm; 337 uint64_t offset; 338 uint64_t pte_pa; 339 uint64_t pde_pa; 340 uint64_t pde; 341 uint64_t pte; 342 u_long pdeindex; 343 u_long pteindex; 344 size_t s; 345 uint64_t a; 346 off_t ofs; 347 uint64_t *PTD; 348 349 vm = kd->vmst; 350 PTD = (uint64_t *)vm->PTD; 351 offset = va & (PAGE_SIZE - 1); 352 353 /* 354 * If we are initializing (kernel page table descriptor pointer 355 * not yet set) then return pa == va to avoid infinite recursion. 356 */ 357 if (PTD == 0) { 358 s = _kvm_pa2off(kd, va, pa); 359 if (s == 0) { 360 _kvm_err(kd, kd->program, 361 "_kvm_vatop_pae: bootstrap data not in dump"); 362 goto invalid; 363 } else 364 return (PAGE_SIZE - offset); 365 } 366 367 pdeindex = va >> PDRSHIFT_PAE; 368 pde = PTD[pdeindex]; 369 if (((u_long)pde & PG_V) == 0) { 370 _kvm_err(kd, kd->program, "_kvm_kvatop_pae: pde not valid"); 371 goto invalid; 372 } 373 374 if ((u_long)pde & PG_PS) { 375 /* 376 * No second-level page table; ptd describes one 2MB page. 377 * (We assume that the kernel wouldn't set PG_PS without enabling 378 * it cr0). 379 */ 380 #define PAGE2M_MASK (NBPDR_PAE - 1) 381 #define PG_FRAME2M (~PAGE2M_MASK) 382 pde_pa = ((u_long)pde & PG_FRAME2M) + (va & PAGE2M_MASK); 383 s = _kvm_pa2off(kd, pde_pa, &ofs); 384 if (s < sizeof pde) { 385 _kvm_syserr(kd, kd->program, 386 "_kvm_vatop_pae: pde_pa not found"); 387 goto invalid; 388 } 389 *pa = ofs; 390 return (NBPDR_PAE - (va & PAGE2M_MASK)); 391 } 392 393 pteindex = (va >> PAGE_SHIFT) & (NPTEPG_PAE-1); 394 pte_pa = ((uint64_t)pde & PG_FRAME_PAE) + (pteindex * sizeof(pde)); 395 396 s = _kvm_pa2off(kd, pte_pa, &ofs); 397 if (s < sizeof pte) { 398 _kvm_err(kd, kd->program, "_kvm_vatop_pae: pdpe_pa not found"); 399 goto invalid; 400 } 401 402 /* XXX This has to be a physical address read, kvm_read is virtual */ 403 if (lseek(kd->pmfd, ofs, 0) == -1) { 404 _kvm_syserr(kd, kd->program, "_kvm_vatop_pae: lseek"); 405 goto invalid; 406 } 407 if (read(kd->pmfd, &pte, sizeof pte) != sizeof pte) { 408 _kvm_syserr(kd, kd->program, "_kvm_vatop_pae: read"); 409 goto invalid; 410 } 411 if (((uint64_t)pte & PG_V) == 0) { 412 _kvm_err(kd, kd->program, "_kvm_vatop_pae: pte not valid"); 413 goto invalid; 414 } 415 416 a = ((uint64_t)pte & PG_FRAME_PAE) + offset; 417 s =_kvm_pa2off(kd, a, pa); 418 if (s == 0) { 419 _kvm_err(kd, kd->program, 420 "_kvm_vatop_pae: address not in dump"); 421 goto invalid; 422 } else 423 return (PAGE_SIZE - offset); 424 425 invalid: 426 _kvm_err(kd, 0, "invalid address (0x%lx)", va); 427 return (0); 428 } 429 430 int 431 _kvm_kvatop(kvm_t *kd, u_long va, off_t *pa) 432 { 433 434 if (kd->vmst->minidump) 435 return (_kvm_minidump_kvatop(kd, va, pa)); 436 if (ISALIVE(kd)) { 437 _kvm_err(kd, 0, "vatop called in live kernel!"); 438 return (0); 439 } 440 if (kd->vmst->pae) 441 return (_kvm_vatop_pae(kd, va, pa)); 442 else 443 return (_kvm_vatop(kd, va, pa)); 444 } 445