libkvm - Add ability to access userspace from kgdb on cores
[dragonfly.git] / lib / libkvm / kvm_x86_64.c
CommitLineData
17030342
MD
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 $
17030342
MD
39 */
40
41/*
b2b3ffcd 42 * x86_64 machine dependent routines for kvm. Hopefully, the forthcoming
17030342
MD
43 * vm code will one day obsolete this module.
44 */
45
9f17b787 46#include <sys/user.h> /* MUST BE FIRST */
17030342 47#include <sys/param.h>
17030342
MD
48#include <sys/proc.h>
49#include <sys/stat.h>
78a7b07a
AH
50#include <sys/mman.h>
51#include <sys/elf_common.h>
17030342 52#include <stdlib.h>
78a7b07a 53#include <string.h>
17030342
MD
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
78a7b07a
AH
61#include <machine/elf.h>
62
17030342
MD
63#include <limits.h>
64
65#include "kvm_private.h"
66
67#ifndef btop
b2b3ffcd
SS
68#define btop(x) (x86_64_btop(x))
69#define ptob(x) (x86_64_ptob(x))
17030342
MD
70#endif
71
72struct vmstate {
78a7b07a
AH
73 int minidump; /* 1 = minidump mode */
74 void *mmapbase;
75 size_t mmapsize;
a60accf7 76 pml4_entry_t *PML4;
17030342
MD
77};
78
78a7b07a
AH
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 */
84static 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 */
113static 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
17030342
MD
136void
137_kvm_freevtop(kvm_t *kd)
138{
78a7b07a
AH
139 struct vmstate *vm = kd->vmst;
140
141 if (kd->vmst->minidump) {
142 _kvm_minidump_freevtop(kd);
143 return;
17030342 144 }
78a7b07a
AH
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;
17030342
MD
152}
153
154int
155_kvm_initvtop(kvm_t *kd)
156{
17030342
MD
157 struct nlist nlist[2];
158 u_long pa;
159 u_long kernbase;
a60accf7 160 pml4_entry_t *PML4;
78a7b07a
AH
161 Elf_Ehdr *ehdr;
162 size_t hdrsz;
163 char minihdr[8];
3f1be088 164 struct pcb dumppcb;
78a7b07a
AH
165
166 if (pread(kd->pmfd, &minihdr, 8, 0) == 8)
167 if (memcmp(&minihdr, "minidump", 8) == 0)
168 return (_kvm_minidump_initvtop(kd));
17030342 169
78a7b07a
AH
170 kd->vmst = (struct vmstate *)_kvm_malloc(kd, sizeof(*kd->vmst));
171 if (kd->vmst == 0) {
17030342
MD
172 _kvm_err(kd, kd->program, "cannot allocate vm");
173 return (-1);
174 }
78a7b07a
AH
175 kd->vmst->PML4 = 0;
176
177 if (_kvm_maphdrs(kd, sizeof(Elf_Ehdr)) == -1)
178 return (-1);
179 /*
3f1be088
MD
180 * Check if this is indeed an ELF header. If not, assume old style
181 *dump or memory layout.
78a7b07a
AH
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 }
17030342
MD
193
194 nlist[0].n_name = "kernbase";
195 nlist[1].n_name = 0;
196
a60accf7
MD
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;
17030342 202
3f1be088 203 nlist[0].n_name = "dumppcb";
17030342
MD
204 nlist[1].n_name = 0;
205
206 if (kvm_nlist(kd, nlist) != 0) {
3f1be088 207 _kvm_err(kd, kd->program, "bad namelist - no dumppcb");
17030342
MD
208 return (-1);
209 }
3f1be088
MD
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");
17030342
MD
213 return (-1);
214 }
3f1be088
MD
215 pa = dumppcb.pcb_cr3 & PG_FRAME;
216
a60accf7
MD
217 PML4 = _kvm_malloc(kd, PAGE_SIZE);
218 if (kvm_read(kd, pa, PML4, PAGE_SIZE) != PAGE_SIZE) {
3f1be088 219 _kvm_err(kd, kd->program, "cannot read dumppcb");
17030342
MD
220 return (-1);
221 }
78a7b07a 222 kd->vmst->PML4 = PML4;
17030342
MD
223 return (0);
224}
225
226static int
78a7b07a 227_kvm_vatop(kvm_t *kd, u_long va, off_t *pa)
17030342
MD
228{
229 struct vmstate *vm;
230 u_long offset;
a60accf7
MD
231 u_long pdpe_pa;
232 u_long pde_pa;
17030342 233 u_long pte_pa;
a60accf7
MD
234 pml4_entry_t pml4e;
235 pdp_entry_t pdpe;
17030342
MD
236 pd_entry_t pde;
237 pt_entry_t pte;
a60accf7
MD
238 u_long pml4eindex;
239 u_long pdpeindex;
17030342
MD
240 u_long pdeindex;
241 u_long pteindex;
78a7b07a
AH
242 u_long a;
243 off_t ofs;
244 size_t s;
17030342
MD
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 */
a60accf7 253 if (vm->PML4 == 0) {
78a7b07a
AH
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);
17030342
MD
261 }
262
a60accf7
MD
263 pml4eindex = (va >> PML4SHIFT) & (NPML4EPG - 1);
264 pml4e = vm->PML4[pml4eindex];
78a7b07a
AH
265 if (((u_long)pml4e & PG_V) == 0) {
266 _kvm_err(kd, kd->program, "_kvm_vatop: pml4e not valid");
a60accf7 267 goto invalid;
78a7b07a 268 }
a60accf7
MD
269
270 pdpeindex = (va >> PDPSHIFT) & (NPDPEPG-1);
78a7b07a
AH
271 pdpe_pa = ((u_long)pml4e & PG_FRAME) +
272 (pdpeindex * sizeof(pdp_entry_t));
a60accf7 273
78a7b07a 274 s = _kvm_pa2off(kd, pdpe_pa, &ofs);
3f1be088 275 if (s < sizeof pdpe) {
78a7b07a
AH
276 _kvm_err(kd, kd->program, "_kvm_vatop: pdpe_pa not found");
277 goto invalid;
278 }
279 if (lseek(kd->pmfd, ofs, 0) == -1) {
a60accf7
MD
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 }
78a7b07a
AH
287 if (((u_long)pdpe & PG_V) == 0) {
288 _kvm_err(kd, kd->program, "_kvm_vatop: pdpe not valid");
a60accf7 289 goto invalid;
78a7b07a 290 }
a60accf7 291
a60accf7
MD
292 pdeindex = (va >> PDRSHIFT) & (NPDEPG-1);
293 pde_pa = ((u_long)pdpe & PG_FRAME) + (pdeindex * sizeof(pd_entry_t));
294
78a7b07a 295 s = _kvm_pa2off(kd, pde_pa, &ofs);
3f1be088 296 if (s < sizeof pde) {
78a7b07a
AH
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");
a60accf7
MD
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 }
78a7b07a
AH
308 if (((u_long)pde & PG_V) == 0) {
309 _kvm_err(kd, kd->program, "_kvm_vatop: pde not valid");
17030342 310 goto invalid;
78a7b07a 311 }
17030342
MD
312
313 if ((u_long)pde & PG_PS) {
314 /*
a60accf7 315 * No final-level page table; ptd describes one 2MB page.
17030342 316 */
a60accf7
MD
317#define PAGE2M_MASK (NBPDR - 1)
318#define PG_FRAME2M (~PAGE2M_MASK)
78a7b07a
AH
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 }
17030342
MD
328 }
329
330 pteindex = (va >> PAGE_SHIFT) & (NPTEPG-1);
331 pte_pa = ((u_long)pde & PG_FRAME) + (pteindex * sizeof(pt_entry_t));
332
78a7b07a 333 s = _kvm_pa2off(kd, pte_pa, &ofs);
3f1be088 334 if (s < sizeof pte) {
78a7b07a
AH
335 _kvm_err(kd, kd->program, "_kvm_vatop: pte_pa not found");
336 goto invalid;
337 }
338 if (lseek(kd->pmfd, ofs, 0) == -1) {
17030342
MD
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 }
78a7b07a
AH
346 if (((u_long)pte & PG_V) == 0) {
347 _kvm_err(kd, kd->program, "_kvm_vatop: pte not valid");
17030342 348 goto invalid;
78a7b07a 349 }
17030342 350
78a7b07a
AH
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);
17030342
MD
358
359invalid:
78a7b07a 360 _kvm_err(kd, 0, "invalid address (0x%lx)", va);
17030342
MD
361 return (0);
362}
363
364int
78a7b07a 365_kvm_kvatop(kvm_t *kd, u_long va, off_t *pa)
17030342 366{
78a7b07a
AH
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
17030342
MD
375 return (_kvm_vatop(kd, va, pa));
376}