kvm_i386.c revision 147678
11602Srgrimes/*-
21602Srgrimes * Copyright (c) 1989, 1992, 1993
31602Srgrimes *	The Regents of the University of California.  All rights reserved.
41602Srgrimes *
51602Srgrimes * This code is derived from software developed by the Computer Systems
61602Srgrimes * Engineering group at Lawrence Berkeley Laboratory under DARPA contract
71602Srgrimes * BG 91-66 and contributed to Berkeley.
81602Srgrimes *
91602Srgrimes * Redistribution and use in source and binary forms, with or without
101602Srgrimes * modification, are permitted provided that the following conditions
111602Srgrimes * are met:
121602Srgrimes * 1. Redistributions of source code must retain the above copyright
131602Srgrimes *    notice, this list of conditions and the following disclaimer.
141602Srgrimes * 2. Redistributions in binary form must reproduce the above copyright
151602Srgrimes *    notice, this list of conditions and the following disclaimer in the
161602Srgrimes *    documentation and/or other materials provided with the distribution.
171602Srgrimes * 3. All advertising materials mentioning features or use of this software
181602Srgrimes *    must display the following acknowledgement:
191602Srgrimes *	This product includes software developed by the University of
201602Srgrimes *	California, Berkeley and its contributors.
211602Srgrimes * 4. Neither the name of the University nor the names of its contributors
221602Srgrimes *    may be used to endorse or promote products derived from this software
231602Srgrimes *    without specific prior written permission.
241602Srgrimes *
251602Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
261602Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
271602Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
281602Srgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
291602Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
301602Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
311602Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
321602Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
331602Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
341602Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
351602Srgrimes * SUCH DAMAGE.
361602Srgrimes */
371602Srgrimes
3883551Sdillon#include <sys/cdefs.h>
3983551Sdillon__FBSDID("$FreeBSD: head/lib/libkvm/kvm_i386.c 147678 2005-06-30 01:25:21Z ps $");
4083551Sdillon
411602Srgrimes#if defined(LIBC_SCCS) && !defined(lint)
4255127Speter#if 0
431602Srgrimesstatic char sccsid[] = "@(#)kvm_hp300.c	8.1 (Berkeley) 6/4/93";
4455127Speter#endif
451602Srgrimes#endif /* LIBC_SCCS and not lint */
461602Srgrimes
471602Srgrimes/*
488870Srgrimes * i386 machine dependent routines for kvm.  Hopefully, the forthcoming
491602Srgrimes * vm code will one day obsolete this module.
501602Srgrimes */
511602Srgrimes
521602Srgrimes#include <sys/param.h>
531602Srgrimes#include <sys/user.h>
541602Srgrimes#include <sys/proc.h>
551602Srgrimes#include <sys/stat.h>
56147672Speter#include <sys/mman.h>
5717141Sjkh#include <stdlib.h>
581602Srgrimes#include <unistd.h>
591602Srgrimes#include <nlist.h>
601602Srgrimes#include <kvm.h>
611602Srgrimes
621602Srgrimes#include <vm/vm.h>
631602Srgrimes#include <vm/vm_param.h>
641602Srgrimes
65147672Speter#include <machine/elf.h>
66147672Speter
671602Srgrimes#include <limits.h>
681602Srgrimes
691602Srgrimes#include "kvm_private.h"
701602Srgrimes
711602Srgrimes#ifndef btop
721603Srgrimes#define	btop(x)		(i386_btop(x))
731603Srgrimes#define	ptob(x)		(i386_ptob(x))
741602Srgrimes#endif
751602Srgrimes
76147672Speter#define	PG_FRAME_PAE	(~((uint64_t)PAGE_MASK))
77147672Speter#define	PDRSHIFT_PAE	21
78147672Speter#define	NPTEPG_PAE	(PAGE_SIZE/sizeof(uint64_t))
79147672Speter#define	NBPDR_PAE	(1<<PDRSHIFT_PAE)
80147672Speter
811602Srgrimesstruct vmstate {
82147672Speter	void		*mmapbase;
83147672Speter	size_t		mmapsize;
84147672Speter	void		*PTD;
85147672Speter	int		pae;
861602Srgrimes};
871602Srgrimes
88147672Speter/*
89147672Speter * Map the ELF headers into the process' address space. We do this in two
90147672Speter * steps: first the ELF header itself and using that information the whole
91147672Speter * set of headers. (Taken from kvm_ia64.c)
92147672Speter */
93147672Speterstatic int
94147672Speter_kvm_maphdrs(kvm_t *kd, size_t sz)
95147672Speter{
96147672Speter	struct vmstate *vm = kd->vmst;
97147672Speter
98147672Speter	/* munmap() previous mmap(). */
99147672Speter	if (vm->mmapbase != NULL) {
100147672Speter		munmap(vm->mmapbase, vm->mmapsize);
101147672Speter		vm->mmapbase = NULL;
102147672Speter	}
103147672Speter
104147672Speter	vm->mmapsize = sz;
105147672Speter	vm->mmapbase = mmap(NULL, sz, PROT_READ, MAP_PRIVATE, kd->pmfd, 0);
106147672Speter	if (vm->mmapbase == MAP_FAILED) {
107147672Speter		_kvm_err(kd, kd->program, "cannot mmap corefile");
108147672Speter		return (-1);
109147672Speter	}
110147672Speter	return (0);
111147672Speter}
112147672Speter
113147672Speter/*
114147672Speter * Translate a physical memory address to a file-offset in the crash-dump.
115147672Speter * (Taken from kvm_ia64.c)
116147672Speter */
117147672Speterstatic size_t
118147672Speter_kvm_pa2off(kvm_t *kd, uint64_t pa, off_t *ofs)
119147672Speter{
120147672Speter	Elf_Ehdr *e = kd->vmst->mmapbase;
121147672Speter	Elf_Phdr *p = (Elf_Phdr*)((char*)e + e->e_phoff);
122147672Speter	int n = e->e_phnum;
123147672Speter
124147672Speter	while (n && (pa < p->p_paddr || pa >= p->p_paddr + p->p_memsz))
125147672Speter		p++, n--;
126147672Speter	if (n == 0)
127147672Speter		return (0);
128147672Speter	*ofs = (pa - p->p_paddr) + p->p_offset;
129147672Speter	return (PAGE_SIZE - ((size_t)pa & PAGE_MASK));
130147672Speter}
131147672Speter
1321602Srgrimesvoid
13318798Speter_kvm_freevtop(kvm_t *kd)
13418798Speter{
135147672Speter	struct vmstate *vm = kd->vmst;
136147672Speter
137147672Speter	if (vm->mmapbase != NULL)
138147672Speter		munmap(vm->mmapbase, vm->mmapsize);
139147672Speter	if (vm->PTD)
140147672Speter		free(vm->PTD);
141147672Speter	free(vm);
142147672Speter	kd->vmst = NULL;
1431602Srgrimes}
1441602Srgrimes
1451602Srgrimesint
14618798Speter_kvm_initvtop(kvm_t *kd)
14718798Speter{
1481603Srgrimes	struct nlist nlist[2];
14918798Speter	u_long pa;
15082263Speter	u_long kernbase;
151147672Speter	char		*PTD;
152147672Speter	Elf_Ehdr	*ehdr;
153147672Speter	size_t		hdrsz;
154147672Speter	int		i;
1551602Srgrimes
156147672Speter	kd->vmst = (struct vmstate *)_kvm_malloc(kd, sizeof(*kd->vmst));
157147672Speter	if (kd->vmst == 0) {
1581603Srgrimes		_kvm_err(kd, kd->program, "cannot allocate vm");
1591602Srgrimes		return (-1);
1601603Srgrimes	}
161147672Speter	kd->vmst->PTD = 0;
1621602Srgrimes
163147672Speter	if (_kvm_maphdrs(kd, sizeof(Elf_Ehdr)) == -1)
164147672Speter		return (-1);
165147672Speter
166147672Speter	ehdr = kd->vmst->mmapbase;
167147672Speter	hdrsz = ehdr->e_phoff + ehdr->e_phentsize * ehdr->e_phnum;
168147672Speter	if (_kvm_maphdrs(kd, hdrsz) == -1)
169147672Speter		return (-1);
170147672Speter
17182263Speter	nlist[0].n_name = "kernbase";
1721603Srgrimes	nlist[1].n_name = 0;
1731602Srgrimes
17482263Speter	if (kvm_nlist(kd, nlist) != 0)
17582263Speter		kernbase = KERNBASE;	/* for old kernels */
17682263Speter	else
17782263Speter		kernbase = nlist[0].n_value;
17882263Speter
179147672Speter	nlist[0].n_name = "IdlePDPT";
18082263Speter	nlist[1].n_name = 0;
18182263Speter
182147672Speter	if (kvm_nlist(kd, nlist) == 0) {
183147672Speter		uint64_t pa64;
184147672Speter
185147672Speter		if (kvm_read(kd, (nlist[0].n_value - kernbase), &pa,
186147672Speter		    sizeof(pa)) != sizeof(pa)) {
187147672Speter			_kvm_err(kd, kd->program, "cannot read IdlePDPT");
188147672Speter			return (-1);
189147672Speter		}
190147672Speter		PTD = _kvm_malloc(kd, 4 * PAGE_SIZE);
191147672Speter		for (i = 0; i < 4; i++) {
192147672Speter			if (kvm_read(kd, pa + (i * sizeof(pa64)), &pa64,
193147672Speter			    sizeof(pa64)) != sizeof(pa64)) {
194147672Speter				_kvm_err(kd, kd->program, "Cannot read PDPT");
195147672Speter				free(PTD);
196147672Speter				return (-1);
197147672Speter			}
198147672Speter			if (kvm_read(kd, pa64 & PG_FRAME_PAE,
199147672Speter			    PTD + (i * PAGE_SIZE), PAGE_SIZE) != (PAGE_SIZE)) {
200147672Speter				_kvm_err(kd, kd->program, "cannot read PDPT");
201147672Speter				free(PTD);
202147672Speter				return (-1);
203147672Speter			}
204147672Speter		}
205147672Speter		kd->vmst->PTD = PTD;
206147672Speter		kd->vmst->pae = 1;
207147672Speter	} else {
208147672Speter		nlist[0].n_name = "IdlePTD";
209147672Speter		nlist[1].n_name = 0;
210147672Speter
211147672Speter		if (kvm_nlist(kd, nlist) != 0) {
212147672Speter			_kvm_err(kd, kd->program, "bad namelist");
213147672Speter			return (-1);
214147672Speter		}
215147672Speter		if (kvm_read(kd, (nlist[0].n_value - kernbase), &pa,
216147672Speter		    sizeof(pa)) != sizeof(pa)) {
217147672Speter			_kvm_err(kd, kd->program, "cannot read IdlePTD");
218147672Speter			return (-1);
219147672Speter		}
220147672Speter		PTD = _kvm_malloc(kd, PAGE_SIZE);
221147672Speter		if (kvm_read(kd, pa, PTD, PAGE_SIZE) != PAGE_SIZE) {
222147672Speter			_kvm_err(kd, kd->program, "cannot read PTD");
223147672Speter			return (-1);
224147672Speter		}
225147672Speter		kd->vmst->PTD = PTD;
226147672Speter		return (0);
227147672Speter		kd->vmst->pae = 0;
2281602Srgrimes	}
2291602Srgrimes	return (0);
2301602Srgrimes}
2311602Srgrimes
2321602Srgrimesstatic int
233147672Speter_kvm_vatop(kvm_t *kd, u_long va, off_t *pa)
23418798Speter{
23518798Speter	struct vmstate *vm;
23618798Speter	u_long offset;
23718798Speter	u_long pte_pa;
238147672Speter	u_long pde_pa;
23918798Speter	pd_entry_t pde;
24018798Speter	pt_entry_t pte;
24118798Speter	u_long pdeindex;
24218798Speter	u_long pteindex;
243147672Speter	size_t s;
244147672Speter	u_long a;
245147672Speter	off_t ofs;
246147672Speter	uint32_t *PTD;
2471602Srgrimes
24818798Speter	vm = kd->vmst;
249147672Speter	PTD = (uint32_t *)vm->PTD;
25018798Speter	offset = va & (PAGE_SIZE - 1);
25118798Speter
25218798Speter	/*
25318798Speter	 * If we are initializing (kernel page table descriptor pointer
25418798Speter	 * not yet set) then return pa == va to avoid infinite recursion.
25518798Speter	 */
256147672Speter	if (PTD == 0) {
257147672Speter		s = _kvm_pa2off(kd, va, pa);
258147672Speter		if (s == 0) {
259147672Speter			_kvm_err(kd, kd->program,
260147672Speter			    "_kvm_vatop: bootstrap data not in dump");
261147672Speter			goto invalid;
262147672Speter		} else
263147672Speter			return (PAGE_SIZE - offset);
26418798Speter	}
26518798Speter
26618798Speter	pdeindex = va >> PDRSHIFT;
267147672Speter	pde = PTD[pdeindex];
268147672Speter	if (((u_long)pde & PG_V) == 0) {
269147672Speter		_kvm_err(kd, kd->program, "_kvm_vatop: pde not valid");
27018798Speter		goto invalid;
271147672Speter	}
27218798Speter
27328318Stegge	if ((u_long)pde & PG_PS) {
27428318Stegge	      /*
27528318Stegge	       * No second-level page table; ptd describes one 4MB page.
27628318Stegge	       * (We assume that the kernel wouldn't set PG_PS without enabling
277147672Speter	       * it cr0).
27828318Stegge	       */
27928318Stegge#define	PAGE4M_MASK	(NBPDR - 1)
28028318Stegge#define	PG_FRAME4M	(~PAGE4M_MASK)
281147672Speter		pde_pa = ((u_long)pde & PG_FRAME4M) + (va & PAGE4M_MASK);
282147672Speter		s = _kvm_pa2off(kd, pde_pa, &ofs);
283147672Speter		if (s <= sizeof pde) {
284147672Speter			_kvm_syserr(kd, kd->program,
285147672Speter			    "_kvm_vatop: pde_pa not found");
286147672Speter			goto invalid;
287147672Speter		}
288147672Speter		*pa = ofs;
28928318Stegge		return (NBPDR - (va & PAGE4M_MASK));
29028318Stegge	}
29128318Stegge
29218798Speter	pteindex = (va >> PAGE_SHIFT) & (NPTEPG-1);
293147672Speter	pte_pa = ((u_long)pde & PG_FRAME) + (pteindex * sizeof(pde));
29418798Speter
295147672Speter	s = _kvm_pa2off(kd, pte_pa, &ofs);
296147672Speter	if (s <= sizeof pte) {
297147672Speter		_kvm_err(kd, kd->program, "_kvm_vatop: pdpe_pa not found");
298147672Speter		goto invalid;
299147672Speter	}
300147672Speter
30118798Speter	/* XXX This has to be a physical address read, kvm_read is virtual */
302147672Speter	if (lseek(kd->pmfd, ofs, 0) == -1) {
30318798Speter		_kvm_syserr(kd, kd->program, "_kvm_vatop: lseek");
30418798Speter		goto invalid;
30518798Speter	}
30618798Speter	if (read(kd->pmfd, &pte, sizeof pte) != sizeof pte) {
30718798Speter		_kvm_syserr(kd, kd->program, "_kvm_vatop: read");
30818798Speter		goto invalid;
30918798Speter	}
310147672Speter	if (((u_long)pte & PG_V) == 0) {
311147672Speter		_kvm_err(kd, kd->program, "_kvm_kvatop: pte not valid");
31218798Speter		goto invalid;
313147672Speter	}
31418798Speter
315147672Speter	a = ((u_long)pte & PG_FRAME) + offset;
316147672Speter	s =_kvm_pa2off(kd, a, pa);
317147672Speter	if (s == 0) {
318147672Speter		_kvm_err(kd, kd->program, "_kvm_vatop: address not in dump");
319147672Speter		goto invalid;
320147672Speter	} else
321147672Speter		return (PAGE_SIZE - offset);
32218798Speter
32318798Speterinvalid:
324147672Speter	_kvm_err(kd, 0, "invalid address (0x%lx)", va);
32518798Speter	return (0);
3261602Srgrimes}
3271602Srgrimes
328147672Speterstatic int
329147672Speter_kvm_vatop_pae(kvm_t *kd, u_long va, off_t *pa)
330147672Speter{
331147672Speter	struct vmstate *vm;
332147672Speter	uint64_t offset;
333147672Speter	uint64_t pte_pa;
334147672Speter	uint64_t pde_pa;
335147672Speter	uint64_t pde;
336147672Speter	uint64_t pte;
337147672Speter	u_long pdeindex;
338147672Speter	u_long pteindex;
339147672Speter	size_t s;
340147672Speter	uint64_t a;
341147672Speter	off_t ofs;
342147672Speter	uint64_t *PTD;
343147672Speter
344147672Speter	vm = kd->vmst;
345147672Speter	PTD = (uint64_t *)vm->PTD;
346147672Speter	offset = va & (PAGE_SIZE - 1);
347147672Speter
348147672Speter	/*
349147672Speter	 * If we are initializing (kernel page table descriptor pointer
350147672Speter	 * not yet set) then return pa == va to avoid infinite recursion.
351147672Speter	 */
352147672Speter	if (PTD == 0) {
353147672Speter		s = _kvm_pa2off(kd, va, pa);
354147672Speter		if (s == 0) {
355147672Speter			_kvm_err(kd, kd->program,
356147672Speter			    "_kvm_vatop_pae: bootstrap data not in dump");
357147672Speter			goto invalid;
358147672Speter		} else
359147672Speter			return (PAGE_SIZE - offset);
360147672Speter	}
361147672Speter
362147672Speter	pdeindex = va >> PDRSHIFT_PAE;
363147672Speter	pde = PTD[pdeindex];
364147672Speter	if (((u_long)pde & PG_V) == 0) {
365147672Speter		_kvm_err(kd, kd->program, "_kvm_kvatop_pae: pde not valid");
366147672Speter		goto invalid;
367147672Speter	}
368147672Speter
369147672Speter	if ((u_long)pde & PG_PS) {
370147672Speter	      /*
371147672Speter	       * No second-level page table; ptd describes one 2MB page.
372147672Speter	       * (We assume that the kernel wouldn't set PG_PS without enabling
373147672Speter	       * it cr0).
374147672Speter	       */
375147672Speter#define	PAGE2M_MASK	(NBPDR_PAE - 1)
376147672Speter#define	PG_FRAME2M	(~PAGE2M_MASK)
377147672Speter		pde_pa = ((u_long)pde & PG_FRAME2M) + (va & PAGE2M_MASK);
378147672Speter		s = _kvm_pa2off(kd, pde_pa, &ofs);
379147672Speter		if (s <= sizeof pde) {
380147672Speter			_kvm_syserr(kd, kd->program,
381147672Speter			    "_kvm_vatop_pae: pde_pa not found");
382147672Speter			goto invalid;
383147672Speter		}
384147672Speter		*pa = ofs;
385147672Speter		return (NBPDR_PAE - (va & PAGE2M_MASK));
386147672Speter	}
387147672Speter
388147672Speter	pteindex = (va >> PAGE_SHIFT) & (NPTEPG_PAE-1);
389147672Speter	pte_pa = ((uint64_t)pde & PG_FRAME_PAE) + (pteindex * sizeof(pde));
390147672Speter
391147672Speter	s = _kvm_pa2off(kd, pte_pa, &ofs);
392147672Speter	if (s <= sizeof pte) {
393147672Speter		_kvm_err(kd, kd->program, "_kvm_vatop_pae: pdpe_pa not found");
394147672Speter		goto invalid;
395147672Speter	}
396147672Speter
397147672Speter	/* XXX This has to be a physical address read, kvm_read is virtual */
398147672Speter	if (lseek(kd->pmfd, ofs, 0) == -1) {
399147672Speter		_kvm_syserr(kd, kd->program, "_kvm_vatop_pae: lseek");
400147672Speter		goto invalid;
401147672Speter	}
402147672Speter	if (read(kd->pmfd, &pte, sizeof pte) != sizeof pte) {
403147672Speter		_kvm_syserr(kd, kd->program, "_kvm_vatop_pae: read");
404147672Speter		goto invalid;
405147672Speter	}
406147672Speter	if (((uint64_t)pte & PG_V) == 0) {
407147672Speter		_kvm_err(kd, kd->program, "_kvm_vatop_pae: pte not valid");
408147672Speter		goto invalid;
409147672Speter	}
410147672Speter
411147672Speter	a = ((uint64_t)pte & PG_FRAME_PAE) + offset;
412147672Speter	s =_kvm_pa2off(kd, a, pa);
413147672Speter	if (s == 0) {
414147672Speter		_kvm_err(kd, kd->program,
415147672Speter		    "_kvm_vatop_pae: address not in dump");
416147672Speter		goto invalid;
417147672Speter	} else
418147672Speter		return (PAGE_SIZE - offset);
419147672Speter
420147672Speterinvalid:
421147672Speter	_kvm_err(kd, 0, "invalid address (0x%lx)", va);
422147672Speter	return (0);
423147672Speter}
424147672Speter
4251602Srgrimesint
426147678Sps_kvm_kvatop(kvm_t *kd, u_long va, off_t *pa)
42718798Speter{
428147672Speter
429147672Speter	if (ISALIVE(kd)) {
430147672Speter		_kvm_err(kd, 0, "vatop called in live kernel!");
431147672Speter		return (0);
432147672Speter	}
433147672Speter	if (kd->vmst->pae)
434147672Speter		return (_kvm_vatop_pae(kd, va, pa));
435147672Speter	else
436147672Speter		return (_kvm_vatop(kd, va, pa));
4371602Srgrimes}
438