xref: /dragonfly/lib/libkvm/kvm_x86_64.c (revision 28832674)
1b2b3ffcdSSimon Schubert /*-
2b2b3ffcdSSimon Schubert  * Copyright (c) 1989, 1992, 1993
3b2b3ffcdSSimon Schubert  *	The Regents of the University of California.  All rights reserved.
4b2b3ffcdSSimon Schubert  *
5b2b3ffcdSSimon Schubert  * This code is derived from software developed by the Computer Systems
6b2b3ffcdSSimon Schubert  * Engineering group at Lawrence Berkeley Laboratory under DARPA contract
7b2b3ffcdSSimon Schubert  * BG 91-66 and contributed to Berkeley.
8b2b3ffcdSSimon Schubert  *
9b2b3ffcdSSimon Schubert  * Redistribution and use in source and binary forms, with or without
10b2b3ffcdSSimon Schubert  * modification, are permitted provided that the following conditions
11b2b3ffcdSSimon Schubert  * are met:
12b2b3ffcdSSimon Schubert  * 1. Redistributions of source code must retain the above copyright
13b2b3ffcdSSimon Schubert  *    notice, this list of conditions and the following disclaimer.
14b2b3ffcdSSimon Schubert  * 2. Redistributions in binary form must reproduce the above copyright
15b2b3ffcdSSimon Schubert  *    notice, this list of conditions and the following disclaimer in the
16b2b3ffcdSSimon Schubert  *    documentation and/or other materials provided with the distribution.
17dc71b7abSJustin C. Sherrill  * 3. Neither the name of the University nor the names of its contributors
18b2b3ffcdSSimon Schubert  *    may be used to endorse or promote products derived from this software
19b2b3ffcdSSimon Schubert  *    without specific prior written permission.
20b2b3ffcdSSimon Schubert  *
21b2b3ffcdSSimon Schubert  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22b2b3ffcdSSimon Schubert  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23b2b3ffcdSSimon Schubert  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24b2b3ffcdSSimon Schubert  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25b2b3ffcdSSimon Schubert  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26b2b3ffcdSSimon Schubert  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27b2b3ffcdSSimon Schubert  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28b2b3ffcdSSimon Schubert  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29b2b3ffcdSSimon Schubert  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30b2b3ffcdSSimon Schubert  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31b2b3ffcdSSimon Schubert  * SUCH DAMAGE.
32b2b3ffcdSSimon Schubert  *
33b2b3ffcdSSimon Schubert  * @(#)kvm_hp300.c	8.1 (Berkeley) 6/4/93
34b2b3ffcdSSimon Schubert  * $FreeBSD: src/lib/libkvm/kvm_amd64.c,v 1.16 2003/04/30 21:05:33 peter Exp $
35b2b3ffcdSSimon Schubert  */
36b2b3ffcdSSimon Schubert 
37b2b3ffcdSSimon Schubert /*
38b2b3ffcdSSimon Schubert  * x86_64 machine dependent routines for kvm.  Hopefully, the forthcoming
39b2b3ffcdSSimon Schubert  * vm code will one day obsolete this module.
40b2b3ffcdSSimon Schubert  */
41b2b3ffcdSSimon Schubert 
42b2b3ffcdSSimon Schubert #include <sys/user.h>	/* MUST BE FIRST */
43b2b3ffcdSSimon Schubert #include <sys/param.h>
44b2b3ffcdSSimon Schubert #include <sys/stat.h>
4578a7b07aSAlex Hornung #include <sys/mman.h>
4678a7b07aSAlex Hornung #include <sys/elf_common.h>
47b2b3ffcdSSimon Schubert #include <stdlib.h>
4878a7b07aSAlex Hornung #include <string.h>
49b2b3ffcdSSimon Schubert #include <unistd.h>
50b2b3ffcdSSimon Schubert #include <nlist.h>
51b2b3ffcdSSimon Schubert 
52*40209b5bSzrj #include <cpu/pmap.h>
53b2b3ffcdSSimon Schubert #include <vm/vm.h>
54b2b3ffcdSSimon Schubert #include <vm/vm_param.h>
55b2b3ffcdSSimon Schubert 
5678a7b07aSAlex Hornung #include <machine/elf.h>
5778a7b07aSAlex Hornung 
58b2b3ffcdSSimon Schubert #include <limits.h>
59b2b3ffcdSSimon Schubert 
609b52fe00Szrj #include "kvm.h"
61b2b3ffcdSSimon Schubert #include "kvm_private.h"
62b2b3ffcdSSimon Schubert 
63b2b3ffcdSSimon Schubert #ifndef btop
64b2b3ffcdSSimon Schubert #define	btop(x)		(x86_64_btop(x))
65b2b3ffcdSSimon Schubert #define	ptob(x)		(x86_64_ptob(x))
66b2b3ffcdSSimon Schubert #endif
67b2b3ffcdSSimon Schubert 
68b2b3ffcdSSimon Schubert struct vmstate {
6978a7b07aSAlex Hornung 	int             minidump;       /* 1 = minidump mode */
7078a7b07aSAlex Hornung 	void		*mmapbase;
7178a7b07aSAlex Hornung 	size_t		mmapsize;
72b2b3ffcdSSimon Schubert 	pml4_entry_t	*PML4;
73b2b3ffcdSSimon Schubert };
74b2b3ffcdSSimon Schubert 
7578a7b07aSAlex Hornung /*
7678a7b07aSAlex Hornung  * Map the ELF headers into the process' address space. We do this in two
7778a7b07aSAlex Hornung  * steps: first the ELF header itself and using that information the whole
7878a7b07aSAlex Hornung  * set of headers. (Taken from kvm_ia64.c)
7978a7b07aSAlex Hornung  */
8078a7b07aSAlex Hornung static int
_kvm_maphdrs(kvm_t * kd,size_t sz)8178a7b07aSAlex Hornung _kvm_maphdrs(kvm_t *kd, size_t sz)
8278a7b07aSAlex Hornung {
8378a7b07aSAlex Hornung 	struct vmstate *vm = kd->vmst;
8478a7b07aSAlex Hornung 
8578a7b07aSAlex Hornung 	if (kd->vmst->minidump) {
8678a7b07aSAlex Hornung 		_kvm_minidump_freevtop(kd);
8778a7b07aSAlex Hornung 		return (0);
8878a7b07aSAlex Hornung 	}
8978a7b07aSAlex Hornung 
9078a7b07aSAlex Hornung 	/* munmap() previous mmap(). */
9178a7b07aSAlex Hornung 	if (vm->mmapbase != NULL) {
9278a7b07aSAlex Hornung 		munmap(vm->mmapbase, vm->mmapsize);
9378a7b07aSAlex Hornung 		vm->mmapbase = NULL;
9478a7b07aSAlex Hornung 	}
9578a7b07aSAlex Hornung 
9678a7b07aSAlex Hornung 	vm->mmapsize = sz;
9778a7b07aSAlex Hornung 	vm->mmapbase = mmap(NULL, sz, PROT_READ, MAP_PRIVATE, kd->pmfd, 0);
9878a7b07aSAlex Hornung 	if (vm->mmapbase == MAP_FAILED) {
9978a7b07aSAlex Hornung 		_kvm_err(kd, kd->program, "cannot mmap corefile");
10078a7b07aSAlex Hornung 		return (-1);
10178a7b07aSAlex Hornung 	}
10278a7b07aSAlex Hornung 	return (0);
10378a7b07aSAlex Hornung }
10478a7b07aSAlex Hornung 
10578a7b07aSAlex Hornung /*
10678a7b07aSAlex Hornung  * Translate a physical memory address to a file-offset in the crash-dump.
10778a7b07aSAlex Hornung  * (Taken from kvm_ia64.c)
10878a7b07aSAlex Hornung  */
10978a7b07aSAlex Hornung static size_t
_kvm_pa2off(kvm_t * kd,uint64_t pa,off_t * ofs)11078a7b07aSAlex Hornung _kvm_pa2off(kvm_t *kd, uint64_t pa, off_t *ofs)
11178a7b07aSAlex Hornung {
11278a7b07aSAlex Hornung 	Elf_Ehdr *e = kd->vmst->mmapbase;
11378a7b07aSAlex Hornung 	Elf_Phdr *p;
11478a7b07aSAlex Hornung 	int n;
11578a7b07aSAlex Hornung 
11678a7b07aSAlex Hornung 	if (kd->rawdump) {
11778a7b07aSAlex Hornung 		*ofs = pa;
11878a7b07aSAlex Hornung 		return (PAGE_SIZE - ((size_t)pa & PAGE_MASK));
11978a7b07aSAlex Hornung 	}
12078a7b07aSAlex Hornung 
12178a7b07aSAlex Hornung 	p = (Elf_Phdr*)((char*)e + e->e_phoff);
12278a7b07aSAlex Hornung 	n = e->e_phnum;
12378a7b07aSAlex Hornung 
12478a7b07aSAlex Hornung 	while (n && (pa < p->p_paddr || pa >= p->p_paddr + p->p_memsz))
12578a7b07aSAlex Hornung 		p++, n--;
12678a7b07aSAlex Hornung 	if (n == 0)
12778a7b07aSAlex Hornung 		return (0);
12878a7b07aSAlex Hornung 	*ofs = (pa - p->p_paddr) + p->p_offset;
12978a7b07aSAlex Hornung 	return (PAGE_SIZE - ((size_t)pa & PAGE_MASK));
13078a7b07aSAlex Hornung }
13178a7b07aSAlex Hornung 
132b2b3ffcdSSimon Schubert void
_kvm_freevtop(kvm_t * kd)133b2b3ffcdSSimon Schubert _kvm_freevtop(kvm_t *kd)
134b2b3ffcdSSimon Schubert {
13578a7b07aSAlex Hornung 	struct vmstate *vm = kd->vmst;
13678a7b07aSAlex Hornung 
13778a7b07aSAlex Hornung 	if (kd->vmst->minidump) {
13878a7b07aSAlex Hornung 		_kvm_minidump_freevtop(kd);
13978a7b07aSAlex Hornung 		return;
140b2b3ffcdSSimon Schubert 	}
14178a7b07aSAlex Hornung 
14278a7b07aSAlex Hornung 	if (vm->mmapbase != NULL)
14378a7b07aSAlex Hornung 		munmap(vm->mmapbase, vm->mmapsize);
14478a7b07aSAlex Hornung 	if (vm->PML4)
14578a7b07aSAlex Hornung 		free(vm->PML4);
14678a7b07aSAlex Hornung 	free(vm);
14778a7b07aSAlex Hornung 	kd->vmst = NULL;
148b2b3ffcdSSimon Schubert }
149b2b3ffcdSSimon Schubert 
150b2b3ffcdSSimon Schubert int
_kvm_initvtop(kvm_t * kd)151b2b3ffcdSSimon Schubert _kvm_initvtop(kvm_t *kd)
152b2b3ffcdSSimon Schubert {
153f042963aSzrj 	struct nlist nlists[2];
154b2b3ffcdSSimon Schubert 	u_long pa;
155b2b3ffcdSSimon Schubert 	u_long kernbase;
156b2b3ffcdSSimon Schubert 	pml4_entry_t	*PML4;
15778a7b07aSAlex Hornung 	Elf_Ehdr *ehdr;
15878a7b07aSAlex Hornung 	size_t hdrsz;
15978a7b07aSAlex Hornung 	char	minihdr[8];
160c0202573SMatthew Dillon 	struct pcb dumppcb;
161b2b3ffcdSSimon Schubert 
16278a7b07aSAlex Hornung 	if (pread(kd->pmfd, &minihdr, 8, 0) == 8)
16378a7b07aSAlex Hornung 		if (memcmp(&minihdr, "minidump", 8) == 0)
16478a7b07aSAlex Hornung 			return (_kvm_minidump_initvtop(kd));
16578a7b07aSAlex Hornung 
16678a7b07aSAlex Hornung 	kd->vmst = (struct vmstate *)_kvm_malloc(kd, sizeof(*kd->vmst));
16778a7b07aSAlex Hornung 	if (kd->vmst == 0) {
168b2b3ffcdSSimon Schubert 		_kvm_err(kd, kd->program, "cannot allocate vm");
169b2b3ffcdSSimon Schubert 		return (-1);
170b2b3ffcdSSimon Schubert 	}
17178a7b07aSAlex Hornung 	kd->vmst->PML4 = 0;
17278a7b07aSAlex Hornung 
17378a7b07aSAlex Hornung 	if (_kvm_maphdrs(kd, sizeof(Elf_Ehdr)) == -1)
17478a7b07aSAlex Hornung 		return (-1);
17578a7b07aSAlex Hornung 	/*
176c0202573SMatthew Dillon 	 * Check if this is indeed an ELF header. If not, assume old style
177c0202573SMatthew Dillon 	  *dump or memory layout.
17878a7b07aSAlex Hornung 	 */
17978a7b07aSAlex Hornung 	ehdr = kd->vmst->mmapbase;
18078a7b07aSAlex Hornung 	if (!IS_ELF(*ehdr)) {
18178a7b07aSAlex Hornung 		kd->rawdump = 1;
18278a7b07aSAlex Hornung 		munmap(kd->vmst->mmapbase, kd->vmst->mmapsize);
18378a7b07aSAlex Hornung 		kd->vmst->mmapbase = NULL;
18478a7b07aSAlex Hornung 	} else {
18578a7b07aSAlex Hornung 		hdrsz = ehdr->e_phoff + ehdr->e_phentsize * ehdr->e_phnum;
18678a7b07aSAlex Hornung 		if (_kvm_maphdrs(kd, hdrsz) == -1)
18778a7b07aSAlex Hornung 			return (-1);
18878a7b07aSAlex Hornung 	}
189b2b3ffcdSSimon Schubert 
190f042963aSzrj 	nlists[0].n_name = "kernbase";
191f042963aSzrj 	nlists[1].n_name = 0;
192b2b3ffcdSSimon Schubert 
193f042963aSzrj 	if (kvm_nlist(kd, nlists) != 0) {
194b2b3ffcdSSimon Schubert 		_kvm_err(kd, kd->program, "bad namelist - no kernbase");
195b2b3ffcdSSimon Schubert 		return (-1);
196b2b3ffcdSSimon Schubert 	}
197f042963aSzrj 	kernbase = nlists[0].n_value;
198b2b3ffcdSSimon Schubert 
199f042963aSzrj 	nlists[0].n_name = "dumppcb";
200f042963aSzrj 	nlists[1].n_name = 0;
201b2b3ffcdSSimon Schubert 
202f042963aSzrj 	if (kvm_nlist(kd, nlists) != 0) {
203c0202573SMatthew Dillon 		_kvm_err(kd, kd->program, "bad namelist - no dumppcb");
204b2b3ffcdSSimon Schubert 		return (-1);
205b2b3ffcdSSimon Schubert 	}
206f042963aSzrj 	if (kvm_read(kd, (nlists[0].n_value - kernbase), &dumppcb,
207c0202573SMatthew Dillon 		     sizeof(dumppcb)) != sizeof(dumppcb)) {
208c0202573SMatthew Dillon 		_kvm_err(kd, kd->program, "cannot read dumppcb");
209b2b3ffcdSSimon Schubert 		return (-1);
210b2b3ffcdSSimon Schubert 	}
211c0202573SMatthew Dillon 	pa = dumppcb.pcb_cr3 & PG_FRAME;
212c0202573SMatthew Dillon 
213b2b3ffcdSSimon Schubert 	PML4 = _kvm_malloc(kd, PAGE_SIZE);
214b2b3ffcdSSimon Schubert 	if (kvm_read(kd, pa, PML4, PAGE_SIZE) != PAGE_SIZE) {
215c0202573SMatthew Dillon 		_kvm_err(kd, kd->program, "cannot read dumppcb");
216b2b3ffcdSSimon Schubert 		return (-1);
217b2b3ffcdSSimon Schubert 	}
21878a7b07aSAlex Hornung 	kd->vmst->PML4 = PML4;
219b2b3ffcdSSimon Schubert 	return (0);
220b2b3ffcdSSimon Schubert }
221b2b3ffcdSSimon Schubert 
222b2b3ffcdSSimon Schubert static int
_kvm_vatop(kvm_t * kd,u_long va,off_t * pa)22378a7b07aSAlex Hornung _kvm_vatop(kvm_t *kd, u_long va, off_t *pa)
224b2b3ffcdSSimon Schubert {
225b2b3ffcdSSimon Schubert 	struct vmstate *vm;
226b2b3ffcdSSimon Schubert 	u_long offset;
227b2b3ffcdSSimon Schubert 	u_long pdpe_pa;
228b2b3ffcdSSimon Schubert 	u_long pde_pa;
229b2b3ffcdSSimon Schubert 	u_long pte_pa;
230b2b3ffcdSSimon Schubert 	pml4_entry_t pml4e;
231b2b3ffcdSSimon Schubert 	pdp_entry_t pdpe;
232b2b3ffcdSSimon Schubert 	pd_entry_t pde;
233b2b3ffcdSSimon Schubert 	pt_entry_t pte;
234b2b3ffcdSSimon Schubert 	u_long pml4eindex;
235b2b3ffcdSSimon Schubert 	u_long pdpeindex;
236b2b3ffcdSSimon Schubert 	u_long pdeindex;
237b2b3ffcdSSimon Schubert 	u_long pteindex;
23878a7b07aSAlex Hornung 	u_long a;
23978a7b07aSAlex Hornung 	off_t ofs;
24078a7b07aSAlex Hornung 	size_t s;
241b2b3ffcdSSimon Schubert 
242b2b3ffcdSSimon Schubert 	vm = kd->vmst;
243b2b3ffcdSSimon Schubert 	offset = va & (PAGE_SIZE - 1);
244b2b3ffcdSSimon Schubert 
245b2b3ffcdSSimon Schubert 	/*
246b2b3ffcdSSimon Schubert 	 * If we are initializing (kernel page table descriptor pointer
247b2b3ffcdSSimon Schubert 	 * not yet set) then return pa == va to avoid infinite recursion.
248b2b3ffcdSSimon Schubert 	 */
249678e8cc6SSascha Wildner 	if (vm->PML4 == NULL) {
25078a7b07aSAlex Hornung 		s = _kvm_pa2off(kd, va, pa);
25178a7b07aSAlex Hornung 		if (s == 0) {
25278a7b07aSAlex Hornung 			_kvm_err(kd, kd->program,
25378a7b07aSAlex Hornung 			    "_kvm_vatop: bootstrap data not in dump");
25478a7b07aSAlex Hornung 			goto invalid;
25578a7b07aSAlex Hornung 		} else
256b2b3ffcdSSimon Schubert 			return (PAGE_SIZE - offset);
257b2b3ffcdSSimon Schubert 	}
258b2b3ffcdSSimon Schubert 
259b2b3ffcdSSimon Schubert 	pml4eindex = (va >> PML4SHIFT) & (NPML4EPG - 1);
260b2b3ffcdSSimon Schubert 	pml4e = vm->PML4[pml4eindex];
261a86ce0cdSMatthew Dillon 	if (((u_long)pml4e & X86_PG_V) == 0) {
26278a7b07aSAlex Hornung 		_kvm_err(kd, kd->program, "_kvm_vatop: pml4e not valid");
263b2b3ffcdSSimon Schubert 		goto invalid;
26478a7b07aSAlex Hornung 	}
265b2b3ffcdSSimon Schubert 
266b2b3ffcdSSimon Schubert 	pdpeindex = (va >> PDPSHIFT) & (NPDPEPG-1);
26778a7b07aSAlex Hornung 	pdpe_pa = ((u_long)pml4e & PG_FRAME) +
26878a7b07aSAlex Hornung 	    (pdpeindex * sizeof(pdp_entry_t));
269b2b3ffcdSSimon Schubert 
27078a7b07aSAlex Hornung 	s = _kvm_pa2off(kd, pdpe_pa, &ofs);
271c0202573SMatthew Dillon 	if (s < sizeof pdpe) {
27278a7b07aSAlex Hornung 		_kvm_err(kd, kd->program, "_kvm_vatop: pdpe_pa not found");
27378a7b07aSAlex Hornung 		goto invalid;
27478a7b07aSAlex Hornung 	}
27578a7b07aSAlex Hornung 	if (lseek(kd->pmfd, ofs, 0) == -1) {
276b2b3ffcdSSimon Schubert 		_kvm_syserr(kd, kd->program, "_kvm_vatop: lseek pdpe_pa");
277b2b3ffcdSSimon Schubert 		goto invalid;
278b2b3ffcdSSimon Schubert 	}
279b2b3ffcdSSimon Schubert 	if (read(kd->pmfd, &pdpe, sizeof pdpe) != sizeof pdpe) {
280b2b3ffcdSSimon Schubert 		_kvm_syserr(kd, kd->program, "_kvm_vatop: read pdpe");
281b2b3ffcdSSimon Schubert 		goto invalid;
282b2b3ffcdSSimon Schubert 	}
283a86ce0cdSMatthew Dillon 	if (((u_long)pdpe & X86_PG_V) == 0) {
28478a7b07aSAlex Hornung 		_kvm_err(kd, kd->program, "_kvm_vatop: pdpe not valid");
285b2b3ffcdSSimon Schubert 		goto invalid;
28678a7b07aSAlex Hornung 	}
287b2b3ffcdSSimon Schubert 
288b2b3ffcdSSimon Schubert 	pdeindex = (va >> PDRSHIFT) & (NPDEPG-1);
289b2b3ffcdSSimon Schubert 	pde_pa = ((u_long)pdpe & PG_FRAME) + (pdeindex * sizeof(pd_entry_t));
290b2b3ffcdSSimon Schubert 
29178a7b07aSAlex Hornung 	s = _kvm_pa2off(kd, pde_pa, &ofs);
292c0202573SMatthew Dillon 	if (s < sizeof pde) {
29378a7b07aSAlex Hornung 		_kvm_syserr(kd, kd->program, "_kvm_vatop: pde_pa not found");
29478a7b07aSAlex Hornung 		goto invalid;
29578a7b07aSAlex Hornung 	}
29678a7b07aSAlex Hornung 	if (lseek(kd->pmfd, ofs, 0) == -1) {
29778a7b07aSAlex Hornung 		_kvm_err(kd, kd->program, "_kvm_vatop: lseek pde_pa");
298b2b3ffcdSSimon Schubert 		goto invalid;
299b2b3ffcdSSimon Schubert 	}
300b2b3ffcdSSimon Schubert 	if (read(kd->pmfd, &pde, sizeof pde) != sizeof pde) {
301b2b3ffcdSSimon Schubert 		_kvm_syserr(kd, kd->program, "_kvm_vatop: read pde");
302b2b3ffcdSSimon Schubert 		goto invalid;
303b2b3ffcdSSimon Schubert 	}
304a86ce0cdSMatthew Dillon 	if (((u_long)pde & X86_PG_V) == 0) {
30578a7b07aSAlex Hornung 		_kvm_err(kd, kd->program, "_kvm_vatop: pde not valid");
306b2b3ffcdSSimon Schubert 		goto invalid;
30778a7b07aSAlex Hornung 	}
308b2b3ffcdSSimon Schubert 
309a86ce0cdSMatthew Dillon 	if ((u_long)pde & X86_PG_PS) {
310b2b3ffcdSSimon Schubert 	      /*
311b2b3ffcdSSimon Schubert 	       * No final-level page table; ptd describes one 2MB page.
312b2b3ffcdSSimon Schubert 	       */
313b2b3ffcdSSimon Schubert #define	PAGE2M_MASK	(NBPDR - 1)
314b2b3ffcdSSimon Schubert #define	PG_FRAME2M	(~PAGE2M_MASK)
31578a7b07aSAlex Hornung 		a = ((u_long)pde & PG_FRAME2M) + (va & PAGE2M_MASK);
31678a7b07aSAlex Hornung 		s = _kvm_pa2off(kd, a, pa);
31778a7b07aSAlex Hornung 		if (s == 0) {
31878a7b07aSAlex Hornung 			_kvm_err(kd, kd->program,
31978a7b07aSAlex Hornung 			    "_kvm_vatop: 2MB page address not in dump");
32078a7b07aSAlex Hornung 			goto invalid;
32178a7b07aSAlex Hornung 		} else {
322b2b3ffcdSSimon Schubert 			return (NBPDR - (va & PAGE2M_MASK));
323b2b3ffcdSSimon Schubert 		}
32478a7b07aSAlex Hornung 	}
325b2b3ffcdSSimon Schubert 
326b2b3ffcdSSimon Schubert 	pteindex = (va >> PAGE_SHIFT) & (NPTEPG-1);
327b2b3ffcdSSimon Schubert 	pte_pa = ((u_long)pde & PG_FRAME) + (pteindex * sizeof(pt_entry_t));
328b2b3ffcdSSimon Schubert 
32978a7b07aSAlex Hornung 	s = _kvm_pa2off(kd, pte_pa, &ofs);
330c0202573SMatthew Dillon 	if (s < sizeof pte) {
33178a7b07aSAlex Hornung 		_kvm_err(kd, kd->program, "_kvm_vatop: pte_pa not found");
33278a7b07aSAlex Hornung 		goto invalid;
33378a7b07aSAlex Hornung 	}
33478a7b07aSAlex Hornung 	if (lseek(kd->pmfd, ofs, 0) == -1) {
335b2b3ffcdSSimon Schubert 		_kvm_syserr(kd, kd->program, "_kvm_vatop: lseek");
336b2b3ffcdSSimon Schubert 		goto invalid;
337b2b3ffcdSSimon Schubert 	}
338b2b3ffcdSSimon Schubert 	if (read(kd->pmfd, &pte, sizeof pte) != sizeof pte) {
339b2b3ffcdSSimon Schubert 		_kvm_syserr(kd, kd->program, "_kvm_vatop: read");
340b2b3ffcdSSimon Schubert 		goto invalid;
341b2b3ffcdSSimon Schubert 	}
342a86ce0cdSMatthew Dillon 	if (((u_long)pte & X86_PG_V) == 0) {
34378a7b07aSAlex Hornung 		_kvm_err(kd, kd->program, "_kvm_vatop: pte not valid");
344b2b3ffcdSSimon Schubert 		goto invalid;
34578a7b07aSAlex Hornung 	}
346b2b3ffcdSSimon Schubert 
34778a7b07aSAlex Hornung 	a = ((u_long)pte & PG_FRAME) + offset;
34878a7b07aSAlex Hornung 	s = _kvm_pa2off(kd, a, pa);
34978a7b07aSAlex Hornung 	if (s == 0) {
35078a7b07aSAlex Hornung 		_kvm_err(kd, kd->program, "_kvm_vatop: address not in dump");
35178a7b07aSAlex Hornung 		goto invalid;
35278a7b07aSAlex Hornung 	} else
353b2b3ffcdSSimon Schubert 		return (PAGE_SIZE - offset);
354b2b3ffcdSSimon Schubert 
355b2b3ffcdSSimon Schubert invalid:
35678a7b07aSAlex Hornung 	_kvm_err(kd, 0, "invalid address (0x%lx)", va);
357b2b3ffcdSSimon Schubert 	return (0);
358b2b3ffcdSSimon Schubert }
359b2b3ffcdSSimon Schubert 
360b2b3ffcdSSimon Schubert int
_kvm_kvatop(kvm_t * kd,u_long va,off_t * pa)36178a7b07aSAlex Hornung _kvm_kvatop(kvm_t *kd, u_long va, off_t *pa)
362b2b3ffcdSSimon Schubert {
36378a7b07aSAlex Hornung 	if (kd->vmst->minidump)
36478a7b07aSAlex Hornung 		return (_kvm_minidump_kvatop(kd, va, pa));
36578a7b07aSAlex Hornung 
36678a7b07aSAlex Hornung 	if (kvm_ishost(kd)) {
36778a7b07aSAlex Hornung 		_kvm_err(kd, 0, "kvm_vatop called in live kernel!");
36878a7b07aSAlex Hornung 		return((off_t)0);
36978a7b07aSAlex Hornung 	}
37078a7b07aSAlex Hornung 
371b2b3ffcdSSimon Schubert 	return (_kvm_vatop(kd, va, pa));
372b2b3ffcdSSimon Schubert }
373