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 * 4. Neither the name of the University nor the names of its contributors
181602Srgrimes *    may be used to endorse or promote products derived from this software
191602Srgrimes *    without specific prior written permission.
201602Srgrimes *
211602Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
221602Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
231602Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
241602Srgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
251602Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
261602Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
271602Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
281602Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
291602Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
301602Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
311602Srgrimes * SUCH DAMAGE.
321602Srgrimes */
331602Srgrimes
3483551Sdillon#include <sys/cdefs.h>
3583551Sdillon__FBSDID("$FreeBSD$");
3683551Sdillon
371602Srgrimes#if defined(LIBC_SCCS) && !defined(lint)
3855127Speter#if 0
391602Srgrimesstatic char sccsid[] = "@(#)kvm_hp300.c	8.1 (Berkeley) 6/4/93";
4055127Speter#endif
411602Srgrimes#endif /* LIBC_SCCS and not lint */
421602Srgrimes
431602Srgrimes/*
448870Srgrimes * i386 machine dependent routines for kvm.  Hopefully, the forthcoming
451602Srgrimes * vm code will one day obsolete this module.
461602Srgrimes */
471602Srgrimes
481602Srgrimes#include <sys/param.h>
491602Srgrimes#include <sys/user.h>
501602Srgrimes#include <sys/proc.h>
511602Srgrimes#include <sys/stat.h>
52147672Speter#include <sys/mman.h>
5317141Sjkh#include <stdlib.h>
54194186Sed#include <string.h>
551602Srgrimes#include <unistd.h>
561602Srgrimes#include <nlist.h>
571602Srgrimes#include <kvm.h>
581602Srgrimes
591602Srgrimes#include <vm/vm.h>
601602Srgrimes#include <vm/vm_param.h>
611602Srgrimes
62147672Speter#include <machine/elf.h>
63147672Speter
641602Srgrimes#include <limits.h>
651602Srgrimes
661602Srgrimes#include "kvm_private.h"
671602Srgrimes
681602Srgrimes#ifndef btop
691603Srgrimes#define	btop(x)		(i386_btop(x))
701603Srgrimes#define	ptob(x)		(i386_ptob(x))
711602Srgrimes#endif
721602Srgrimes
73147672Speter#define	PG_FRAME_PAE	(~((uint64_t)PAGE_MASK))
74147672Speter#define	PDRSHIFT_PAE	21
75147672Speter#define	NPTEPG_PAE	(PAGE_SIZE/sizeof(uint64_t))
76147672Speter#define	NBPDR_PAE	(1<<PDRSHIFT_PAE)
77147672Speter
78157911Speter/* minidump must be the first item! */
791602Srgrimesstruct vmstate {
80157911Speter	int		minidump;	/* 1 = minidump mode */
81147672Speter	void		*mmapbase;
82147672Speter	size_t		mmapsize;
83147672Speter	void		*PTD;
84147672Speter	int		pae;
851602Srgrimes};
861602Srgrimes
87147672Speter/*
88147672Speter * Map the ELF headers into the process' address space. We do this in two
89147672Speter * steps: first the ELF header itself and using that information the whole
90147672Speter * set of headers. (Taken from kvm_ia64.c)
91147672Speter */
92147672Speterstatic int
93147672Speter_kvm_maphdrs(kvm_t *kd, size_t sz)
94147672Speter{
95147672Speter	struct vmstate *vm = kd->vmst;
96147672Speter
97147672Speter	/* munmap() previous mmap(). */
98147672Speter	if (vm->mmapbase != NULL) {
99147672Speter		munmap(vm->mmapbase, vm->mmapsize);
100147672Speter		vm->mmapbase = NULL;
101147672Speter	}
102147672Speter
103147672Speter	vm->mmapsize = sz;
104147672Speter	vm->mmapbase = mmap(NULL, sz, PROT_READ, MAP_PRIVATE, kd->pmfd, 0);
105147672Speter	if (vm->mmapbase == MAP_FAILED) {
106147672Speter		_kvm_err(kd, kd->program, "cannot mmap corefile");
107147672Speter		return (-1);
108147672Speter	}
109147672Speter	return (0);
110147672Speter}
111147672Speter
112147672Speter/*
113147672Speter * Translate a physical memory address to a file-offset in the crash-dump.
114147672Speter * (Taken from kvm_ia64.c)
115147672Speter */
116147672Speterstatic size_t
117147672Speter_kvm_pa2off(kvm_t *kd, uint64_t pa, off_t *ofs)
118147672Speter{
119147672Speter	Elf_Ehdr *e = kd->vmst->mmapbase;
120170772Ssimokawa	Elf_Phdr *p;
121170772Ssimokawa	int n;
122147672Speter
123170772Ssimokawa	if (kd->rawdump) {
124170772Ssimokawa		*ofs = pa;
125170772Ssimokawa		return (PAGE_SIZE - ((size_t)pa & PAGE_MASK));
126170772Ssimokawa	}
127170772Ssimokawa
128170772Ssimokawa	p = (Elf_Phdr*)((char*)e + e->e_phoff);
129170772Ssimokawa	n = e->e_phnum;
130147672Speter	while (n && (pa < p->p_paddr || pa >= p->p_paddr + p->p_memsz))
131147672Speter		p++, n--;
132147672Speter	if (n == 0)
133147672Speter		return (0);
134147672Speter	*ofs = (pa - p->p_paddr) + p->p_offset;
135147672Speter	return (PAGE_SIZE - ((size_t)pa & PAGE_MASK));
136147672Speter}
137147672Speter
1381602Srgrimesvoid
13918798Speter_kvm_freevtop(kvm_t *kd)
14018798Speter{
141147672Speter	struct vmstate *vm = kd->vmst;
142147672Speter
143157911Speter	if (kd->vmst->minidump)
144157911Speter		return (_kvm_minidump_freevtop(kd));
145147672Speter	if (vm->mmapbase != NULL)
146147672Speter		munmap(vm->mmapbase, vm->mmapsize);
147147672Speter	if (vm->PTD)
148147672Speter		free(vm->PTD);
149147672Speter	free(vm);
150147672Speter	kd->vmst = NULL;
1511602Srgrimes}
1521602Srgrimes
1531602Srgrimesint
15418798Speter_kvm_initvtop(kvm_t *kd)
15518798Speter{
156217744Suqs	struct nlist nl[2];
15718798Speter	u_long pa;
15882263Speter	u_long kernbase;
159147672Speter	char		*PTD;
160147672Speter	Elf_Ehdr	*ehdr;
161147672Speter	size_t		hdrsz;
162147672Speter	int		i;
163157911Speter	char		minihdr[8];
1641602Srgrimes
165170772Ssimokawa	if (!kd->rawdump && pread(kd->pmfd, &minihdr, 8, 0) == 8)
166157911Speter		if (memcmp(&minihdr, "minidump", 8) == 0)
167157911Speter			return (_kvm_minidump_initvtop(kd));
168157911Speter
169147672Speter	kd->vmst = (struct vmstate *)_kvm_malloc(kd, sizeof(*kd->vmst));
170147672Speter	if (kd->vmst == 0) {
1711603Srgrimes		_kvm_err(kd, kd->program, "cannot allocate vm");
1721602Srgrimes		return (-1);
1731603Srgrimes	}
174147672Speter	kd->vmst->PTD = 0;
1751602Srgrimes
176170772Ssimokawa	if (kd->rawdump == 0) {
177170772Ssimokawa		if (_kvm_maphdrs(kd, sizeof(Elf_Ehdr)) == -1)
178170772Ssimokawa			return (-1);
179147672Speter
180170772Ssimokawa		ehdr = kd->vmst->mmapbase;
181170772Ssimokawa		hdrsz = ehdr->e_phoff + ehdr->e_phentsize * ehdr->e_phnum;
182170772Ssimokawa		if (_kvm_maphdrs(kd, hdrsz) == -1)
183170772Ssimokawa			return (-1);
184170772Ssimokawa	}
185147672Speter
186217744Suqs	nl[0].n_name = "kernbase";
187217744Suqs	nl[1].n_name = 0;
1881602Srgrimes
189217744Suqs	if (kvm_nlist(kd, nl) != 0)
19082263Speter		kernbase = KERNBASE;	/* for old kernels */
19182263Speter	else
192217744Suqs		kernbase = nl[0].n_value;
19382263Speter
194217744Suqs	nl[0].n_name = "IdlePDPT";
195217744Suqs	nl[1].n_name = 0;
19682263Speter
197217744Suqs	if (kvm_nlist(kd, nl) == 0) {
198147672Speter		uint64_t pa64;
199147672Speter
200217744Suqs		if (kvm_read(kd, (nl[0].n_value - kernbase), &pa,
201147672Speter		    sizeof(pa)) != sizeof(pa)) {
202147672Speter			_kvm_err(kd, kd->program, "cannot read IdlePDPT");
203147672Speter			return (-1);
204147672Speter		}
205147672Speter		PTD = _kvm_malloc(kd, 4 * PAGE_SIZE);
206147672Speter		for (i = 0; i < 4; i++) {
207147672Speter			if (kvm_read(kd, pa + (i * sizeof(pa64)), &pa64,
208147672Speter			    sizeof(pa64)) != sizeof(pa64)) {
209147672Speter				_kvm_err(kd, kd->program, "Cannot read PDPT");
210147672Speter				free(PTD);
211147672Speter				return (-1);
212147672Speter			}
213147672Speter			if (kvm_read(kd, pa64 & PG_FRAME_PAE,
214147672Speter			    PTD + (i * PAGE_SIZE), PAGE_SIZE) != (PAGE_SIZE)) {
215147672Speter				_kvm_err(kd, kd->program, "cannot read PDPT");
216147672Speter				free(PTD);
217147672Speter				return (-1);
218147672Speter			}
219147672Speter		}
220147672Speter		kd->vmst->PTD = PTD;
221147672Speter		kd->vmst->pae = 1;
222147672Speter	} else {
223217744Suqs		nl[0].n_name = "IdlePTD";
224217744Suqs		nl[1].n_name = 0;
225147672Speter
226217744Suqs		if (kvm_nlist(kd, nl) != 0) {
227147672Speter			_kvm_err(kd, kd->program, "bad namelist");
228147672Speter			return (-1);
229147672Speter		}
230217744Suqs		if (kvm_read(kd, (nl[0].n_value - kernbase), &pa,
231147672Speter		    sizeof(pa)) != sizeof(pa)) {
232147672Speter			_kvm_err(kd, kd->program, "cannot read IdlePTD");
233147672Speter			return (-1);
234147672Speter		}
235147672Speter		PTD = _kvm_malloc(kd, PAGE_SIZE);
236147672Speter		if (kvm_read(kd, pa, PTD, PAGE_SIZE) != PAGE_SIZE) {
237147672Speter			_kvm_err(kd, kd->program, "cannot read PTD");
238147672Speter			return (-1);
239147672Speter		}
240147672Speter		kd->vmst->PTD = PTD;
241147672Speter		kd->vmst->pae = 0;
2421602Srgrimes	}
2431602Srgrimes	return (0);
2441602Srgrimes}
2451602Srgrimes
2461602Srgrimesstatic int
247147672Speter_kvm_vatop(kvm_t *kd, u_long va, off_t *pa)
24818798Speter{
24918798Speter	struct vmstate *vm;
25018798Speter	u_long offset;
25118798Speter	u_long pte_pa;
252147672Speter	u_long pde_pa;
25318798Speter	pd_entry_t pde;
25418798Speter	pt_entry_t pte;
25518798Speter	u_long pdeindex;
25618798Speter	u_long pteindex;
257147672Speter	size_t s;
258147672Speter	u_long a;
259147672Speter	off_t ofs;
260147672Speter	uint32_t *PTD;
2611602Srgrimes
26218798Speter	vm = kd->vmst;
263147672Speter	PTD = (uint32_t *)vm->PTD;
26418798Speter	offset = va & (PAGE_SIZE - 1);
26518798Speter
26618798Speter	/*
26718798Speter	 * If we are initializing (kernel page table descriptor pointer
26818798Speter	 * not yet set) then return pa == va to avoid infinite recursion.
26918798Speter	 */
270147672Speter	if (PTD == 0) {
271147672Speter		s = _kvm_pa2off(kd, va, pa);
272147672Speter		if (s == 0) {
273147672Speter			_kvm_err(kd, kd->program,
274147672Speter			    "_kvm_vatop: bootstrap data not in dump");
275147672Speter			goto invalid;
276147672Speter		} else
277147672Speter			return (PAGE_SIZE - offset);
27818798Speter	}
27918798Speter
28018798Speter	pdeindex = va >> PDRSHIFT;
281147672Speter	pde = PTD[pdeindex];
282147672Speter	if (((u_long)pde & PG_V) == 0) {
283147672Speter		_kvm_err(kd, kd->program, "_kvm_vatop: pde not valid");
28418798Speter		goto invalid;
285147672Speter	}
28618798Speter
28728318Stegge	if ((u_long)pde & PG_PS) {
28828318Stegge	      /*
28928318Stegge	       * No second-level page table; ptd describes one 4MB page.
29028318Stegge	       * (We assume that the kernel wouldn't set PG_PS without enabling
291147672Speter	       * it cr0).
29228318Stegge	       */
29328318Stegge#define	PAGE4M_MASK	(NBPDR - 1)
29428318Stegge#define	PG_FRAME4M	(~PAGE4M_MASK)
295147672Speter		pde_pa = ((u_long)pde & PG_FRAME4M) + (va & PAGE4M_MASK);
296147672Speter		s = _kvm_pa2off(kd, pde_pa, &ofs);
297198986Sjhb		if (s == 0) {
298198986Sjhb			_kvm_err(kd, kd->program,
299198986Sjhb			    "_kvm_vatop: 4MB page address not in dump");
300147672Speter			goto invalid;
301147672Speter		}
302147672Speter		*pa = ofs;
30328318Stegge		return (NBPDR - (va & PAGE4M_MASK));
30428318Stegge	}
30528318Stegge
30618798Speter	pteindex = (va >> PAGE_SHIFT) & (NPTEPG-1);
307147672Speter	pte_pa = ((u_long)pde & PG_FRAME) + (pteindex * sizeof(pde));
30818798Speter
309147672Speter	s = _kvm_pa2off(kd, pte_pa, &ofs);
310151492Speter	if (s < sizeof pte) {
311147672Speter		_kvm_err(kd, kd->program, "_kvm_vatop: pdpe_pa not found");
312147672Speter		goto invalid;
313147672Speter	}
314147672Speter
31518798Speter	/* XXX This has to be a physical address read, kvm_read is virtual */
316147672Speter	if (lseek(kd->pmfd, ofs, 0) == -1) {
31718798Speter		_kvm_syserr(kd, kd->program, "_kvm_vatop: lseek");
31818798Speter		goto invalid;
31918798Speter	}
32018798Speter	if (read(kd->pmfd, &pte, sizeof pte) != sizeof pte) {
32118798Speter		_kvm_syserr(kd, kd->program, "_kvm_vatop: read");
32218798Speter		goto invalid;
32318798Speter	}
324147672Speter	if (((u_long)pte & PG_V) == 0) {
325147672Speter		_kvm_err(kd, kd->program, "_kvm_kvatop: pte not valid");
32618798Speter		goto invalid;
327147672Speter	}
32818798Speter
329147672Speter	a = ((u_long)pte & PG_FRAME) + offset;
330147672Speter	s =_kvm_pa2off(kd, a, pa);
331147672Speter	if (s == 0) {
332147672Speter		_kvm_err(kd, kd->program, "_kvm_vatop: address not in dump");
333147672Speter		goto invalid;
334147672Speter	} else
335147672Speter		return (PAGE_SIZE - offset);
33618798Speter
33718798Speterinvalid:
338147672Speter	_kvm_err(kd, 0, "invalid address (0x%lx)", va);
33918798Speter	return (0);
3401602Srgrimes}
3411602Srgrimes
342147672Speterstatic int
343147672Speter_kvm_vatop_pae(kvm_t *kd, u_long va, off_t *pa)
344147672Speter{
345147672Speter	struct vmstate *vm;
346147672Speter	uint64_t offset;
347147672Speter	uint64_t pte_pa;
348147672Speter	uint64_t pde_pa;
349147672Speter	uint64_t pde;
350147672Speter	uint64_t pte;
351147672Speter	u_long pdeindex;
352147672Speter	u_long pteindex;
353147672Speter	size_t s;
354147672Speter	uint64_t a;
355147672Speter	off_t ofs;
356147672Speter	uint64_t *PTD;
357147672Speter
358147672Speter	vm = kd->vmst;
359147672Speter	PTD = (uint64_t *)vm->PTD;
360147672Speter	offset = va & (PAGE_SIZE - 1);
361147672Speter
362147672Speter	/*
363147672Speter	 * If we are initializing (kernel page table descriptor pointer
364147672Speter	 * not yet set) then return pa == va to avoid infinite recursion.
365147672Speter	 */
366147672Speter	if (PTD == 0) {
367147672Speter		s = _kvm_pa2off(kd, va, pa);
368147672Speter		if (s == 0) {
369147672Speter			_kvm_err(kd, kd->program,
370147672Speter			    "_kvm_vatop_pae: bootstrap data not in dump");
371147672Speter			goto invalid;
372147672Speter		} else
373147672Speter			return (PAGE_SIZE - offset);
374147672Speter	}
375147672Speter
376147672Speter	pdeindex = va >> PDRSHIFT_PAE;
377147672Speter	pde = PTD[pdeindex];
378147672Speter	if (((u_long)pde & PG_V) == 0) {
379147672Speter		_kvm_err(kd, kd->program, "_kvm_kvatop_pae: pde not valid");
380147672Speter		goto invalid;
381147672Speter	}
382147672Speter
383147672Speter	if ((u_long)pde & PG_PS) {
384147672Speter	      /*
385147672Speter	       * No second-level page table; ptd describes one 2MB page.
386147672Speter	       * (We assume that the kernel wouldn't set PG_PS without enabling
387147672Speter	       * it cr0).
388147672Speter	       */
389147672Speter#define	PAGE2M_MASK	(NBPDR_PAE - 1)
390147672Speter#define	PG_FRAME2M	(~PAGE2M_MASK)
391147672Speter		pde_pa = ((u_long)pde & PG_FRAME2M) + (va & PAGE2M_MASK);
392147672Speter		s = _kvm_pa2off(kd, pde_pa, &ofs);
393198986Sjhb		if (s == 0) {
394198986Sjhb			_kvm_err(kd, kd->program,
395198986Sjhb			    "_kvm_vatop: 2MB page address not in dump");
396147672Speter			goto invalid;
397147672Speter		}
398147672Speter		*pa = ofs;
399147672Speter		return (NBPDR_PAE - (va & PAGE2M_MASK));
400147672Speter	}
401147672Speter
402147672Speter	pteindex = (va >> PAGE_SHIFT) & (NPTEPG_PAE-1);
403147672Speter	pte_pa = ((uint64_t)pde & PG_FRAME_PAE) + (pteindex * sizeof(pde));
404147672Speter
405147672Speter	s = _kvm_pa2off(kd, pte_pa, &ofs);
406151492Speter	if (s < sizeof pte) {
407147672Speter		_kvm_err(kd, kd->program, "_kvm_vatop_pae: pdpe_pa not found");
408147672Speter		goto invalid;
409147672Speter	}
410147672Speter
411147672Speter	/* XXX This has to be a physical address read, kvm_read is virtual */
412147672Speter	if (lseek(kd->pmfd, ofs, 0) == -1) {
413147672Speter		_kvm_syserr(kd, kd->program, "_kvm_vatop_pae: lseek");
414147672Speter		goto invalid;
415147672Speter	}
416147672Speter	if (read(kd->pmfd, &pte, sizeof pte) != sizeof pte) {
417147672Speter		_kvm_syserr(kd, kd->program, "_kvm_vatop_pae: read");
418147672Speter		goto invalid;
419147672Speter	}
420147672Speter	if (((uint64_t)pte & PG_V) == 0) {
421147672Speter		_kvm_err(kd, kd->program, "_kvm_vatop_pae: pte not valid");
422147672Speter		goto invalid;
423147672Speter	}
424147672Speter
425147672Speter	a = ((uint64_t)pte & PG_FRAME_PAE) + offset;
426147672Speter	s =_kvm_pa2off(kd, a, pa);
427147672Speter	if (s == 0) {
428147672Speter		_kvm_err(kd, kd->program,
429147672Speter		    "_kvm_vatop_pae: address not in dump");
430147672Speter		goto invalid;
431147672Speter	} else
432147672Speter		return (PAGE_SIZE - offset);
433147672Speter
434147672Speterinvalid:
435147672Speter	_kvm_err(kd, 0, "invalid address (0x%lx)", va);
436147672Speter	return (0);
437147672Speter}
438147672Speter
4391602Srgrimesint
440147678Sps_kvm_kvatop(kvm_t *kd, u_long va, off_t *pa)
44118798Speter{
442147672Speter
443157911Speter	if (kd->vmst->minidump)
444157911Speter		return (_kvm_minidump_kvatop(kd, va, pa));
445147672Speter	if (ISALIVE(kd)) {
446147672Speter		_kvm_err(kd, 0, "vatop called in live kernel!");
447147672Speter		return (0);
448147672Speter	}
449147672Speter	if (kd->vmst->pae)
450147672Speter		return (_kvm_vatop_pae(kd, va, pa));
451147672Speter	else
452147672Speter		return (_kvm_vatop(kd, va, pa));
4531602Srgrimes}
454