kvm_minidump_amd64.c revision 183985
1141104Sharti/*-
2141104Sharti * Copyright (c) 2006 Peter Wemm
3141104Sharti *
4141104Sharti * Redistribution and use in source and binary forms, with or without
5141104Sharti * modification, are permitted provided that the following conditions
6141104Sharti * are met:
7141104Sharti * 1. Redistributions of source code must retain the above copyright
8141104Sharti *    notice, this list of conditions and the following disclaimer.
9141104Sharti * 2. Redistributions in binary form must reproduce the above copyright
10141104Sharti *    notice, this list of conditions and the following disclaimer in the
11141104Sharti *    documentation and/or other materials provided with the distribution.
12141104Sharti *
13141104Sharti * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
14141104Sharti * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15141104Sharti * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16141104Sharti * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
17141104Sharti * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18141104Sharti * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
19141104Sharti * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
20141104Sharti * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
21141104Sharti * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22141104Sharti * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
23141104Sharti * SUCH DAMAGE.
24141104Sharti */
25141104Sharti
26141104Sharti#include <sys/cdefs.h>
27141104Sharti__FBSDID("$FreeBSD: head/lib/libkvm/kvm_minidump_amd64.c 183985 2008-10-17 20:09:00Z delphij $");
28141104Sharti
29141104Sharti/*
30141104Sharti * AMD64 machine dependent routines for kvm and minidumps.
31141104Sharti */
32141104Sharti
33141104Sharti#include <sys/param.h>
34141104Sharti#include <sys/user.h>
35141104Sharti#include <sys/proc.h>
36141104Sharti#include <sys/stat.h>
37141104Sharti#include <sys/mman.h>
38141104Sharti#include <sys/fnv_hash.h>
39141104Sharti#include <stdlib.h>
40141104Sharti#include <strings.h>
41141104Sharti#include <unistd.h>
42141104Sharti#include <nlist.h>
43141104Sharti#include <kvm.h>
44141104Sharti
45143414Sharti#include <vm/vm.h>
46141104Sharti#include <vm/vm_param.h>
47146177Sharti
48146177Sharti#include <machine/elf.h>
49146177Sharti#include <machine/cpufunc.h>
50146177Sharti#include <machine/minidump.h>
51146177Sharti
52146177Sharti#include <limits.h>
53146177Sharti
54146177Sharti#include "kvm_private.h"
55146177Sharti
56146177Shartistruct hpte {
57146177Sharti	struct hpte *next;
58141104Sharti	vm_paddr_t pa;
59141104Sharti	int64_t off;
60143414Sharti};
61143414Sharti
62143414Sharti#define HPT_SIZE 1024
63143414Sharti
64143414Sharti/* minidump must be the first item! */
65141104Shartistruct vmstate {
66141104Sharti	int minidump;		/* 1 = minidump mode */
67141104Sharti	struct minidumphdr hdr;
68141104Sharti	void *hpt_head[HPT_SIZE];
69141104Sharti	uint64_t *bitmap;
70141104Sharti	uint64_t *ptemap;
71141104Sharti};
72141104Sharti
73141104Shartistatic void
74141104Shartihpt_insert(kvm_t *kd, vm_paddr_t pa, int64_t off)
75141104Sharti{
76141104Sharti	struct hpte *hpte;
77141104Sharti	uint32_t fnv = FNV1_32_INIT;
78141104Sharti
79141104Sharti	fnv = fnv_32_buf(&pa, sizeof(pa), fnv);
80141104Sharti	fnv &= (HPT_SIZE - 1);
81141104Sharti	hpte = malloc(sizeof(*hpte));
82141104Sharti	hpte->pa = pa;
83141104Sharti	hpte->off = off;
84141104Sharti	hpte->next = kd->vmst->hpt_head[fnv];
85141104Sharti	kd->vmst->hpt_head[fnv] = hpte;
86141104Sharti}
87141104Sharti
88141104Shartistatic int64_t
89141104Shartihpt_find(kvm_t *kd, vm_paddr_t pa)
90143278Sharti{
91143278Sharti	struct hpte *hpte;
92143278Sharti	uint32_t fnv = FNV1_32_INIT;
93143278Sharti
94143278Sharti	fnv = fnv_32_buf(&pa, sizeof(pa), fnv);
95141104Sharti	fnv &= (HPT_SIZE - 1);
96141104Sharti	for (hpte = kd->vmst->hpt_head[fnv]; hpte != NULL; hpte = hpte->next) {
97141104Sharti		if (pa == hpte->pa)
98141104Sharti			return (hpte->off);
99144386Sharti	}
100144386Sharti	return (-1);
101144386Sharti}
102144386Sharti
103141104Shartistatic int
104143278Shartiinithash(kvm_t *kd, uint64_t *base, int len, off_t off)
105141104Sharti{
106143277Sharti	uint64_t idx;
107143277Sharti	uint64_t bit, bits;
108143277Sharti	vm_paddr_t pa;
109143277Sharti
110141104Sharti	for (idx = 0; idx < len / sizeof(*base); idx++) {
111141104Sharti		bits = base[idx];
112141104Sharti		while (bits) {
113141104Sharti			bit = bsfq(bits);
114146184Sharti			bits &= ~(1ul << bit);
115141104Sharti			pa = (idx * sizeof(*base) * NBBY + bit) * PAGE_SIZE;
116141104Sharti			hpt_insert(kd, pa, off);
117			off += PAGE_SIZE;
118		}
119	}
120	return (off);
121}
122
123void
124_kvm_minidump_freevtop(kvm_t *kd)
125{
126	struct vmstate *vm = kd->vmst;
127
128	if (vm->bitmap)
129		free(vm->bitmap);
130	if (vm->ptemap)
131		free(vm->ptemap);
132	free(vm);
133	kd->vmst = NULL;
134}
135
136int
137_kvm_minidump_initvtop(kvm_t *kd)
138{
139	u_long pa;
140	struct vmstate *vmst;
141	off_t off;
142
143	vmst = _kvm_malloc(kd, sizeof(*vmst));
144	if (vmst == 0) {
145		_kvm_err(kd, kd->program, "cannot allocate vm");
146		return (-1);
147	}
148	kd->vmst = vmst;
149	vmst->minidump = 1;
150	if (pread(kd->pmfd, &vmst->hdr, sizeof(vmst->hdr), 0) !=
151	    sizeof(vmst->hdr)) {
152		_kvm_err(kd, kd->program, "cannot read dump header");
153		return (-1);
154	}
155	if (strncmp(MINIDUMP_MAGIC, vmst->hdr.magic, sizeof(vmst->hdr.magic)) != 0) {
156		_kvm_err(kd, kd->program, "not a minidump for this platform");
157		return (-1);
158	}
159	if (vmst->hdr.version != MINIDUMP_VERSION) {
160		_kvm_err(kd, kd->program, "wrong minidump version. expected %d got %d",
161		    MINIDUMP_VERSION, vmst->hdr.version);
162		return (-1);
163	}
164
165	/* Skip header and msgbuf */
166	off = PAGE_SIZE + round_page(vmst->hdr.msgbufsize);
167
168	vmst->bitmap = _kvm_malloc(kd, vmst->hdr.bitmapsize);
169	if (vmst->bitmap == NULL) {
170		_kvm_err(kd, kd->program, "cannot allocate %d bytes for bitmap", vmst->hdr.bitmapsize);
171		return (-1);
172	}
173	if (pread(kd->pmfd, vmst->bitmap, vmst->hdr.bitmapsize, off) !=
174	    vmst->hdr.bitmapsize) {
175		_kvm_err(kd, kd->program, "cannot read %d bytes for page bitmap", vmst->hdr.bitmapsize);
176		return (-1);
177	}
178	off += round_page(vmst->hdr.bitmapsize);
179
180	vmst->ptemap = _kvm_malloc(kd, vmst->hdr.ptesize);
181	if (vmst->ptemap == NULL) {
182		_kvm_err(kd, kd->program, "cannot allocate %d bytes for ptemap", vmst->hdr.ptesize);
183		return (-1);
184	}
185	if (pread(kd->pmfd, vmst->ptemap, vmst->hdr.ptesize, off) !=
186	    vmst->hdr.ptesize) {
187		_kvm_err(kd, kd->program, "cannot read %d bytes for ptemap", vmst->hdr.ptesize);
188		return (-1);
189	}
190	off += vmst->hdr.ptesize;
191
192	/* build physical address hash table for sparse pages */
193	inithash(kd, vmst->bitmap, vmst->hdr.bitmapsize, off);
194
195	return (0);
196}
197
198static int
199_kvm_minidump_vatop(kvm_t *kd, u_long va, off_t *pa)
200{
201	struct vmstate *vm;
202	u_long offset;
203	pt_entry_t pte;
204	u_long pteindex;
205	int i;
206	u_long a;
207	off_t ofs;
208
209	vm = kd->vmst;
210	offset = va & (PAGE_SIZE - 1);
211
212	if (va >= vm->hdr.kernbase) {
213		pteindex = (va - vm->hdr.kernbase) >> PAGE_SHIFT;
214		pte = vm->ptemap[pteindex];
215		if (((u_long)pte & PG_V) == 0) {
216			_kvm_err(kd, kd->program, "_kvm_vatop: pte not valid");
217			goto invalid;
218		}
219		a = pte & PG_FRAME;
220		ofs = hpt_find(kd, a);
221		if (ofs == -1) {
222			_kvm_err(kd, kd->program, "_kvm_vatop: physical address 0x%lx not in minidump", a);
223			goto invalid;
224		}
225		*pa = ofs + offset;
226		return (PAGE_SIZE - offset);
227	} else if (va >= vm->hdr.dmapbase && va < vm->hdr.dmapend) {
228		a = (va - vm->hdr.dmapbase) & ~PAGE_MASK;
229		ofs = hpt_find(kd, a);
230		if (ofs == -1) {
231			_kvm_err(kd, kd->program, "_kvm_vatop: direct map address 0x%lx not in minidump", va);
232			goto invalid;
233		}
234		*pa = ofs + offset;
235		return (PAGE_SIZE - offset);
236	} else {
237		_kvm_err(kd, kd->program, "_kvm_vatop: virtual address 0x%lx not minidumped", va);
238		goto invalid;
239	}
240
241invalid:
242	_kvm_err(kd, 0, "invalid address (0x%lx)", va);
243	return (0);
244}
245
246int
247_kvm_minidump_kvatop(kvm_t *kd, u_long va, off_t *pa)
248{
249
250	if (ISALIVE(kd)) {
251		_kvm_err(kd, 0, "kvm_kvatop called in live kernel!");
252		return (0);
253	}
254	return (_kvm_minidump_vatop(kd, va, pa));
255}
256