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. All advertising materials mentioning features or use of this software 18 * must display the following acknowledgement: 19 * This product includes software developed by the University of 20 * California, Berkeley and its contributors. 21 * 4. Neither the name of the University nor the names of its contributors 22 * may be used to endorse or promote products derived from this software 23 * without specific prior written permission. 24 * 25 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 26 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 27 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 28 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 29 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 30 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 31 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 32 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 33 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 34 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 35 * SUCH DAMAGE. 36 * 37 * @(#)kvm_hp300.c 8.1 (Berkeley) 6/4/93 38 * $FreeBSD: src/lib/libkvm/kvm_amd64.c,v 1.16 2003/04/30 21:05:33 peter Exp $ 39 */ 40 41 /* 42 * x86_64 machine dependent routines for kvm. Hopefully, the forthcoming 43 * vm code will one day obsolete this module. 44 */ 45 46 #include <sys/user.h> /* MUST BE FIRST */ 47 #include <sys/param.h> 48 #include <sys/proc.h> 49 #include <sys/stat.h> 50 #include <sys/mman.h> 51 #include <sys/elf_common.h> 52 #include <stdlib.h> 53 #include <string.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) (x86_64_btop(x)) 69 #define ptob(x) (x86_64_ptob(x)) 70 #endif 71 72 struct vmstate { 73 int minidump; /* 1 = minidump mode */ 74 void *mmapbase; 75 size_t mmapsize; 76 pml4_entry_t *PML4; 77 }; 78 79 /* 80 * Map the ELF headers into the process' address space. We do this in two 81 * steps: first the ELF header itself and using that information the whole 82 * set of headers. (Taken from kvm_ia64.c) 83 */ 84 static int 85 _kvm_maphdrs(kvm_t *kd, size_t sz) 86 { 87 struct vmstate *vm = kd->vmst; 88 89 if (kd->vmst->minidump) { 90 _kvm_minidump_freevtop(kd); 91 return (0); 92 } 93 94 /* munmap() previous mmap(). */ 95 if (vm->mmapbase != NULL) { 96 munmap(vm->mmapbase, vm->mmapsize); 97 vm->mmapbase = NULL; 98 } 99 100 vm->mmapsize = sz; 101 vm->mmapbase = mmap(NULL, sz, PROT_READ, MAP_PRIVATE, kd->pmfd, 0); 102 if (vm->mmapbase == MAP_FAILED) { 103 _kvm_err(kd, kd->program, "cannot mmap corefile"); 104 return (-1); 105 } 106 return (0); 107 } 108 109 /* 110 * Translate a physical memory address to a file-offset in the crash-dump. 111 * (Taken from kvm_ia64.c) 112 */ 113 static size_t 114 _kvm_pa2off(kvm_t *kd, uint64_t pa, off_t *ofs) 115 { 116 Elf_Ehdr *e = kd->vmst->mmapbase; 117 Elf_Phdr *p; 118 int n; 119 120 if (kd->rawdump) { 121 *ofs = pa; 122 return (PAGE_SIZE - ((size_t)pa & PAGE_MASK)); 123 } 124 125 p = (Elf_Phdr*)((char*)e + e->e_phoff); 126 n = e->e_phnum; 127 128 while (n && (pa < p->p_paddr || pa >= p->p_paddr + p->p_memsz)) 129 p++, n--; 130 if (n == 0) 131 return (0); 132 *ofs = (pa - p->p_paddr) + p->p_offset; 133 return (PAGE_SIZE - ((size_t)pa & PAGE_MASK)); 134 } 135 136 void 137 _kvm_freevtop(kvm_t *kd) 138 { 139 struct vmstate *vm = kd->vmst; 140 141 if (kd->vmst->minidump) { 142 _kvm_minidump_freevtop(kd); 143 return; 144 } 145 146 if (vm->mmapbase != NULL) 147 munmap(vm->mmapbase, vm->mmapsize); 148 if (vm->PML4) 149 free(vm->PML4); 150 free(vm); 151 kd->vmst = NULL; 152 } 153 154 int 155 _kvm_initvtop(kvm_t *kd) 156 { 157 struct nlist nlist[2]; 158 u_long pa; 159 u_long kernbase; 160 pml4_entry_t *PML4; 161 Elf_Ehdr *ehdr; 162 size_t hdrsz; 163 char minihdr[8]; 164 struct pcb dumppcb; 165 166 if (pread(kd->pmfd, &minihdr, 8, 0) == 8) 167 if (memcmp(&minihdr, "minidump", 8) == 0) 168 return (_kvm_minidump_initvtop(kd)); 169 170 kd->vmst = (struct vmstate *)_kvm_malloc(kd, sizeof(*kd->vmst)); 171 if (kd->vmst == 0) { 172 _kvm_err(kd, kd->program, "cannot allocate vm"); 173 return (-1); 174 } 175 kd->vmst->PML4 = 0; 176 177 if (_kvm_maphdrs(kd, sizeof(Elf_Ehdr)) == -1) 178 return (-1); 179 /* 180 * Check if this is indeed an ELF header. If not, assume old style 181 *dump or memory layout. 182 */ 183 ehdr = kd->vmst->mmapbase; 184 if (!IS_ELF(*ehdr)) { 185 kd->rawdump = 1; 186 munmap(kd->vmst->mmapbase, kd->vmst->mmapsize); 187 kd->vmst->mmapbase = NULL; 188 } else { 189 hdrsz = ehdr->e_phoff + ehdr->e_phentsize * ehdr->e_phnum; 190 if (_kvm_maphdrs(kd, hdrsz) == -1) 191 return (-1); 192 } 193 194 nlist[0].n_name = "kernbase"; 195 nlist[1].n_name = 0; 196 197 if (kvm_nlist(kd, nlist) != 0) { 198 _kvm_err(kd, kd->program, "bad namelist - no kernbase"); 199 return (-1); 200 } 201 kernbase = nlist[0].n_value; 202 203 nlist[0].n_name = "dumppcb"; 204 nlist[1].n_name = 0; 205 206 if (kvm_nlist(kd, nlist) != 0) { 207 _kvm_err(kd, kd->program, "bad namelist - no dumppcb"); 208 return (-1); 209 } 210 if (kvm_read(kd, (nlist[0].n_value - kernbase), &dumppcb, 211 sizeof(dumppcb)) != sizeof(dumppcb)) { 212 _kvm_err(kd, kd->program, "cannot read dumppcb"); 213 return (-1); 214 } 215 pa = dumppcb.pcb_cr3 & PG_FRAME; 216 217 PML4 = _kvm_malloc(kd, PAGE_SIZE); 218 if (kvm_read(kd, pa, PML4, PAGE_SIZE) != PAGE_SIZE) { 219 _kvm_err(kd, kd->program, "cannot read dumppcb"); 220 return (-1); 221 } 222 kd->vmst->PML4 = PML4; 223 return (0); 224 } 225 226 static int 227 _kvm_vatop(kvm_t *kd, u_long va, off_t *pa) 228 { 229 struct vmstate *vm; 230 u_long offset; 231 u_long pdpe_pa; 232 u_long pde_pa; 233 u_long pte_pa; 234 pml4_entry_t pml4e; 235 pdp_entry_t pdpe; 236 pd_entry_t pde; 237 pt_entry_t pte; 238 u_long pml4eindex; 239 u_long pdpeindex; 240 u_long pdeindex; 241 u_long pteindex; 242 u_long a; 243 off_t ofs; 244 size_t s; 245 246 vm = kd->vmst; 247 offset = va & (PAGE_SIZE - 1); 248 249 /* 250 * If we are initializing (kernel page table descriptor pointer 251 * not yet set) then return pa == va to avoid infinite recursion. 252 */ 253 if (vm->PML4 == NULL) { 254 s = _kvm_pa2off(kd, va, pa); 255 if (s == 0) { 256 _kvm_err(kd, kd->program, 257 "_kvm_vatop: bootstrap data not in dump"); 258 goto invalid; 259 } else 260 return (PAGE_SIZE - offset); 261 } 262 263 pml4eindex = (va >> PML4SHIFT) & (NPML4EPG - 1); 264 pml4e = vm->PML4[pml4eindex]; 265 if (((u_long)pml4e & PG_V) == 0) { 266 _kvm_err(kd, kd->program, "_kvm_vatop: pml4e not valid"); 267 goto invalid; 268 } 269 270 pdpeindex = (va >> PDPSHIFT) & (NPDPEPG-1); 271 pdpe_pa = ((u_long)pml4e & PG_FRAME) + 272 (pdpeindex * sizeof(pdp_entry_t)); 273 274 s = _kvm_pa2off(kd, pdpe_pa, &ofs); 275 if (s < sizeof pdpe) { 276 _kvm_err(kd, kd->program, "_kvm_vatop: pdpe_pa not found"); 277 goto invalid; 278 } 279 if (lseek(kd->pmfd, ofs, 0) == -1) { 280 _kvm_syserr(kd, kd->program, "_kvm_vatop: lseek pdpe_pa"); 281 goto invalid; 282 } 283 if (read(kd->pmfd, &pdpe, sizeof pdpe) != sizeof pdpe) { 284 _kvm_syserr(kd, kd->program, "_kvm_vatop: read pdpe"); 285 goto invalid; 286 } 287 if (((u_long)pdpe & PG_V) == 0) { 288 _kvm_err(kd, kd->program, "_kvm_vatop: pdpe not valid"); 289 goto invalid; 290 } 291 292 pdeindex = (va >> PDRSHIFT) & (NPDEPG-1); 293 pde_pa = ((u_long)pdpe & PG_FRAME) + (pdeindex * sizeof(pd_entry_t)); 294 295 s = _kvm_pa2off(kd, pde_pa, &ofs); 296 if (s < sizeof pde) { 297 _kvm_syserr(kd, kd->program, "_kvm_vatop: pde_pa not found"); 298 goto invalid; 299 } 300 if (lseek(kd->pmfd, ofs, 0) == -1) { 301 _kvm_err(kd, kd->program, "_kvm_vatop: lseek pde_pa"); 302 goto invalid; 303 } 304 if (read(kd->pmfd, &pde, sizeof pde) != sizeof pde) { 305 _kvm_syserr(kd, kd->program, "_kvm_vatop: read pde"); 306 goto invalid; 307 } 308 if (((u_long)pde & PG_V) == 0) { 309 _kvm_err(kd, kd->program, "_kvm_vatop: pde not valid"); 310 goto invalid; 311 } 312 313 if ((u_long)pde & PG_PS) { 314 /* 315 * No final-level page table; ptd describes one 2MB page. 316 */ 317 #define PAGE2M_MASK (NBPDR - 1) 318 #define PG_FRAME2M (~PAGE2M_MASK) 319 a = ((u_long)pde & PG_FRAME2M) + (va & PAGE2M_MASK); 320 s = _kvm_pa2off(kd, a, pa); 321 if (s == 0) { 322 _kvm_err(kd, kd->program, 323 "_kvm_vatop: 2MB page address not in dump"); 324 goto invalid; 325 } else { 326 return (NBPDR - (va & PAGE2M_MASK)); 327 } 328 } 329 330 pteindex = (va >> PAGE_SHIFT) & (NPTEPG-1); 331 pte_pa = ((u_long)pde & PG_FRAME) + (pteindex * sizeof(pt_entry_t)); 332 333 s = _kvm_pa2off(kd, pte_pa, &ofs); 334 if (s < sizeof pte) { 335 _kvm_err(kd, kd->program, "_kvm_vatop: pte_pa not found"); 336 goto invalid; 337 } 338 if (lseek(kd->pmfd, ofs, 0) == -1) { 339 _kvm_syserr(kd, kd->program, "_kvm_vatop: lseek"); 340 goto invalid; 341 } 342 if (read(kd->pmfd, &pte, sizeof pte) != sizeof pte) { 343 _kvm_syserr(kd, kd->program, "_kvm_vatop: read"); 344 goto invalid; 345 } 346 if (((u_long)pte & PG_V) == 0) { 347 _kvm_err(kd, kd->program, "_kvm_vatop: pte not valid"); 348 goto invalid; 349 } 350 351 a = ((u_long)pte & PG_FRAME) + offset; 352 s = _kvm_pa2off(kd, a, pa); 353 if (s == 0) { 354 _kvm_err(kd, kd->program, "_kvm_vatop: address not in dump"); 355 goto invalid; 356 } else 357 return (PAGE_SIZE - offset); 358 359 invalid: 360 _kvm_err(kd, 0, "invalid address (0x%lx)", va); 361 return (0); 362 } 363 364 int 365 _kvm_kvatop(kvm_t *kd, u_long va, off_t *pa) 366 { 367 if (kd->vmst->minidump) 368 return (_kvm_minidump_kvatop(kd, va, pa)); 369 370 if (kvm_ishost(kd)) { 371 _kvm_err(kd, 0, "kvm_vatop called in live kernel!"); 372 return((off_t)0); 373 } 374 375 return (_kvm_vatop(kd, va, pa)); 376 } 377