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 165 if (pread(kd->pmfd, &minihdr, 8, 0) == 8) 166 if (memcmp(&minihdr, "minidump", 8) == 0) 167 return (_kvm_minidump_initvtop(kd)); 168 169 kd->vmst = (struct vmstate *)_kvm_malloc(kd, sizeof(*kd->vmst)); 170 if (kd->vmst == 0) { 171 _kvm_err(kd, kd->program, "cannot allocate vm"); 172 return (-1); 173 } 174 kd->vmst->PML4 = 0; 175 176 if (_kvm_maphdrs(kd, sizeof(Elf_Ehdr)) == -1) 177 return (-1); 178 /* 179 * Check if this is indeed an ELF header. If not, assume old style dump or 180 * memory layout. 181 */ 182 ehdr = kd->vmst->mmapbase; 183 if (!IS_ELF(*ehdr)) { 184 kd->rawdump = 1; 185 munmap(kd->vmst->mmapbase, kd->vmst->mmapsize); 186 kd->vmst->mmapbase = NULL; 187 } else { 188 hdrsz = ehdr->e_phoff + ehdr->e_phentsize * ehdr->e_phnum; 189 if (_kvm_maphdrs(kd, hdrsz) == -1) 190 return (-1); 191 } 192 193 nlist[0].n_name = "kernbase"; 194 nlist[1].n_name = 0; 195 196 if (kvm_nlist(kd, nlist) != 0) { 197 _kvm_err(kd, kd->program, "bad namelist - no kernbase"); 198 return (-1); 199 } 200 kernbase = nlist[0].n_value; 201 202 nlist[0].n_name = "KPML4phys"; 203 nlist[1].n_name = 0; 204 205 if (kvm_nlist(kd, nlist) != 0) { 206 _kvm_err(kd, kd->program, "bad namelist - no KPML4phys"); 207 return (-1); 208 } 209 if (kvm_read(kd, (nlist[0].n_value - kernbase), &pa, sizeof(pa)) != 210 sizeof(pa)) { 211 _kvm_err(kd, kd->program, "cannot read KPML4phys"); 212 return (-1); 213 } 214 PML4 = _kvm_malloc(kd, PAGE_SIZE); 215 if (kvm_read(kd, pa, PML4, PAGE_SIZE) != PAGE_SIZE) { 216 _kvm_err(kd, kd->program, "cannot read KPML4phys"); 217 return (-1); 218 } 219 kd->vmst->PML4 = PML4; 220 return (0); 221 } 222 223 static int 224 _kvm_vatop(kvm_t *kd, u_long va, off_t *pa) 225 { 226 struct vmstate *vm; 227 u_long offset; 228 u_long pdpe_pa; 229 u_long pde_pa; 230 u_long pte_pa; 231 pml4_entry_t pml4e; 232 pdp_entry_t pdpe; 233 pd_entry_t pde; 234 pt_entry_t pte; 235 u_long pml4eindex; 236 u_long pdpeindex; 237 u_long pdeindex; 238 u_long pteindex; 239 u_long a; 240 off_t ofs; 241 size_t s; 242 243 vm = kd->vmst; 244 offset = va & (PAGE_SIZE - 1); 245 246 /* 247 * If we are initializing (kernel page table descriptor pointer 248 * not yet set) then return pa == va to avoid infinite recursion. 249 */ 250 if (vm->PML4 == 0) { 251 s = _kvm_pa2off(kd, va, pa); 252 if (s == 0) { 253 _kvm_err(kd, kd->program, 254 "_kvm_vatop: bootstrap data not in dump"); 255 goto invalid; 256 } else 257 return (PAGE_SIZE - offset); 258 } 259 260 pml4eindex = (va >> PML4SHIFT) & (NPML4EPG - 1); 261 pml4e = vm->PML4[pml4eindex]; 262 if (((u_long)pml4e & PG_V) == 0) { 263 _kvm_err(kd, kd->program, "_kvm_vatop: pml4e not valid"); 264 goto invalid; 265 } 266 267 pdpeindex = (va >> PDPSHIFT) & (NPDPEPG-1); 268 pdpe_pa = ((u_long)pml4e & PG_FRAME) + 269 (pdpeindex * sizeof(pdp_entry_t)); 270 271 s = _kvm_pa2off(kd, pdpe_pa, &ofs); 272 if (s <= sizeof pdpe) { 273 _kvm_err(kd, kd->program, "_kvm_vatop: pdpe_pa not found"); 274 goto invalid; 275 } 276 if (lseek(kd->pmfd, ofs, 0) == -1) { 277 _kvm_syserr(kd, kd->program, "_kvm_vatop: lseek pdpe_pa"); 278 goto invalid; 279 } 280 if (read(kd->pmfd, &pdpe, sizeof pdpe) != sizeof pdpe) { 281 _kvm_syserr(kd, kd->program, "_kvm_vatop: read pdpe"); 282 goto invalid; 283 } 284 if (((u_long)pdpe & PG_V) == 0) { 285 _kvm_err(kd, kd->program, "_kvm_vatop: pdpe not valid"); 286 goto invalid; 287 } 288 289 290 pdeindex = (va >> PDRSHIFT) & (NPDEPG-1); 291 pde_pa = ((u_long)pdpe & PG_FRAME) + (pdeindex * sizeof(pd_entry_t)); 292 293 s = _kvm_pa2off(kd, pde_pa, &ofs); 294 if (s <= sizeof pde) { 295 _kvm_syserr(kd, kd->program, "_kvm_vatop: pde_pa not found"); 296 goto invalid; 297 } 298 if (lseek(kd->pmfd, ofs, 0) == -1) { 299 _kvm_err(kd, kd->program, "_kvm_vatop: lseek pde_pa"); 300 goto invalid; 301 } 302 if (read(kd->pmfd, &pde, sizeof pde) != sizeof pde) { 303 _kvm_syserr(kd, kd->program, "_kvm_vatop: read pde"); 304 goto invalid; 305 } 306 if (((u_long)pde & PG_V) == 0) { 307 _kvm_err(kd, kd->program, "_kvm_vatop: pde not valid"); 308 goto invalid; 309 } 310 311 if ((u_long)pde & PG_PS) { 312 /* 313 * No final-level page table; ptd describes one 2MB page. 314 */ 315 #define PAGE2M_MASK (NBPDR - 1) 316 #define PG_FRAME2M (~PAGE2M_MASK) 317 a = ((u_long)pde & PG_FRAME2M) + (va & PAGE2M_MASK); 318 s = _kvm_pa2off(kd, a, pa); 319 if (s == 0) { 320 _kvm_err(kd, kd->program, 321 "_kvm_vatop: 2MB page address not in dump"); 322 goto invalid; 323 } else { 324 return (NBPDR - (va & PAGE2M_MASK)); 325 } 326 } 327 328 pteindex = (va >> PAGE_SHIFT) & (NPTEPG-1); 329 pte_pa = ((u_long)pde & PG_FRAME) + (pteindex * sizeof(pt_entry_t)); 330 331 s = _kvm_pa2off(kd, pte_pa, &ofs); 332 if (s <= sizeof pte) { 333 _kvm_err(kd, kd->program, "_kvm_vatop: pte_pa not found"); 334 goto invalid; 335 } 336 if (lseek(kd->pmfd, ofs, 0) == -1) { 337 _kvm_syserr(kd, kd->program, "_kvm_vatop: lseek"); 338 goto invalid; 339 } 340 if (read(kd->pmfd, &pte, sizeof pte) != sizeof pte) { 341 _kvm_syserr(kd, kd->program, "_kvm_vatop: read"); 342 goto invalid; 343 } 344 if (((u_long)pte & PG_V) == 0) { 345 _kvm_err(kd, kd->program, "_kvm_vatop: pte not valid"); 346 goto invalid; 347 } 348 349 a = ((u_long)pte & PG_FRAME) + offset; 350 s = _kvm_pa2off(kd, a, pa); 351 if (s == 0) { 352 _kvm_err(kd, kd->program, "_kvm_vatop: address not in dump"); 353 goto invalid; 354 } else 355 return (PAGE_SIZE - offset); 356 357 invalid: 358 _kvm_err(kd, 0, "invalid address (0x%lx)", va); 359 return (0); 360 } 361 362 int 363 _kvm_kvatop(kvm_t *kd, u_long va, off_t *pa) 364 { 365 if (kd->vmst->minidump) 366 return (_kvm_minidump_kvatop(kd, va, pa)); 367 368 if (kvm_ishost(kd)) { 369 _kvm_err(kd, 0, "kvm_vatop called in live kernel!"); 370 return((off_t)0); 371 } 372 373 return (_kvm_vatop(kd, va, pa)); 374 } 375