nrelease - fix/improve livecd
[dragonfly.git] / lib / libkvm / kvm_minidump_x86_64.c
1 /*-
2  * Copyright (c) 2006 Peter Wemm
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
14  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
17  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
19  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
20  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
21  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
23  * SUCH DAMAGE.
24  */
25
26 /*
27  * AMD64 machine dependent routines for kvm and minidumps.
28  */
29
30 #include <sys/user.h>      /* MUST BE FIRST */
31 #include <sys/param.h>
32 #include <sys/stat.h>
33 #include <sys/mman.h>
34 #include <sys/fnv_hash.h>
35 #include <strings.h>
36 #include <string.h>
37 #include <stdlib.h>
38 #include <unistd.h>
39 #include <nlist.h>
40
41 #include <cpu/pmap.h>
42 #include <vm/vm.h>
43 #include <vm/vm_param.h>
44
45 #include <machine/elf.h>
46 #include <machine/cpufunc.h>
47 #include <machine/minidump.h>
48
49 #include <limits.h>
50
51 #include "kvm.h"
52 #include "kvm_private.h"
53
54 struct hpte {
55         struct hpte *next;
56         vm_paddr_t pa;
57         int64_t off;
58 };
59
60 #define HPT_SIZE 1024
61
62 /* minidump must be the first item! */
63 struct vmstate {
64         int minidump;           /* 1 = minidump mode */
65         int pgtable;            /* pagetable mode */
66         void *hpt_head[HPT_SIZE];
67         uint64_t *bitmap;
68         uint64_t *ptemap;
69         uint64_t kernbase;
70         uint64_t dmapbase;
71         uint64_t dmapend;
72         uint64_t bitmapsize;
73 };
74
75 static void
76 hpt_insert(kvm_t *kd, vm_paddr_t pa, int64_t off)
77 {
78         struct hpte *hpte;
79         uint32_t fnv = FNV1_32_INIT;
80
81         fnv = fnv_32_buf(&pa, sizeof(pa), fnv);
82         fnv &= (HPT_SIZE - 1);
83         hpte = malloc(sizeof(*hpte));
84         hpte->pa = pa;
85         hpte->off = off;
86         hpte->next = kd->vmst->hpt_head[fnv];
87         kd->vmst->hpt_head[fnv] = hpte;
88 }
89
90 static int64_t
91 hpt_find(kvm_t *kd, vm_paddr_t pa)
92 {
93         struct hpte *hpte;
94         uint32_t fnv = FNV1_32_INIT;
95
96         fnv = fnv_32_buf(&pa, sizeof(pa), fnv);
97         fnv &= (HPT_SIZE - 1);
98         for (hpte = kd->vmst->hpt_head[fnv]; hpte != NULL; hpte = hpte->next) {
99                 if (pa == hpte->pa)
100                         return (hpte->off);
101         }
102         return (-1);
103 }
104
105 static int
106 inithash(kvm_t *kd, uint64_t *base, int len, off_t off)
107 {
108         uint64_t idx;
109         uint64_t bit, bits;
110         vm_paddr_t pa;
111
112         for (idx = 0; idx < len / sizeof(*base); idx++) {
113                 bits = base[idx];
114                 while (bits) {
115                         bit = bsfq(bits);
116                         bits &= ~(1ul << bit);
117                         pa = (idx * sizeof(*base) * NBBY + bit) * PAGE_SIZE;
118                         hpt_insert(kd, pa, off);
119                         off += PAGE_SIZE;
120                 }
121         }
122         return (off);
123 }
124
125 void
126 _kvm_minidump_freevtop(kvm_t *kd)
127 {
128         struct vmstate *vm = kd->vmst;
129
130         if (vm->bitmap)
131                 free(vm->bitmap);
132         if (vm->ptemap)
133                 free(vm->ptemap);
134         free(vm);
135         kd->vmst = NULL;
136 }
137
138 static int _kvm_minidump_init_hdr1(kvm_t *kd, struct vmstate *vmst,
139                         struct minidumphdr1 *hdr);
140 static int _kvm_minidump_init_hdr2(kvm_t *kd, struct vmstate *vmst,
141                         struct minidumphdr2 *hdr);
142
143 int
144 _kvm_minidump_initvtop(kvm_t *kd)
145 {
146         struct vmstate *vmst;
147         int error;
148         union {
149                 struct minidumphdr1 hdr1;
150                 struct minidumphdr2 hdr2;
151         } u;
152
153         vmst = _kvm_malloc(kd, sizeof(*vmst));
154         if (vmst == NULL) {
155                 _kvm_err(kd, kd->program, "cannot allocate vm");
156                 return (-1);
157         }
158         kd->vmst = vmst;
159         bzero(vmst, sizeof(*vmst));
160         vmst->minidump = 1;
161
162         if (pread(kd->pmfd, &u, sizeof(u), 0) != sizeof(u)) {
163                 _kvm_err(kd, kd->program, "cannot read dump header");
164                 return (-1);
165         }
166         if (strncmp(MINIDUMP1_MAGIC, u.hdr1.magic, sizeof(u.hdr1.magic)) == 0 &&
167             u.hdr1.version == MINIDUMP1_VERSION) {
168                 error = _kvm_minidump_init_hdr1(kd, vmst, &u.hdr1);
169         } else
170         if (strncmp(MINIDUMP2_MAGIC, u.hdr1.magic, sizeof(u.hdr1.magic)) == 0 &&
171             u.hdr2.version == MINIDUMP2_VERSION) {
172                 error = _kvm_minidump_init_hdr2(kd, vmst, &u.hdr2);
173         } else {
174                 _kvm_err(kd, kd->program, "not a minidump for this platform");
175                 error = -1;
176         }
177         return error;
178 }
179
180 static
181 int
182 _kvm_minidump_init_hdr1(kvm_t *kd, struct vmstate *vmst,
183                         struct minidumphdr1 *hdr)
184 {
185         off_t off;
186
187         /* Skip header and msgbuf */
188         off = PAGE_SIZE + round_page(hdr->msgbufsize);
189
190         vmst->bitmap = _kvm_malloc(kd, hdr->bitmapsize);
191         if (vmst->bitmap == NULL) {
192                 _kvm_err(kd, kd->program,
193                          "cannot allocate %jd bytes for bitmap",
194                          (intmax_t)hdr->bitmapsize);
195                 return (-1);
196         }
197         if (pread(kd->pmfd, vmst->bitmap, hdr->bitmapsize, off) !=
198             hdr->bitmapsize) {
199                 _kvm_err(kd, kd->program,
200                          "cannot read %jd bytes for page bitmap",
201                          (intmax_t)hdr->bitmapsize);
202                 return (-1);
203         }
204         off += round_page(vmst->bitmapsize);
205
206         vmst->ptemap = _kvm_malloc(kd, hdr->ptesize);
207         if (vmst->ptemap == NULL) {
208                 _kvm_err(kd, kd->program,
209                          "cannot allocate %jd bytes for ptemap",
210                          (intmax_t)hdr->ptesize);
211                 return (-1);
212         }
213         if (pread(kd->pmfd, vmst->ptemap, hdr->ptesize, off) !=
214             hdr->ptesize) {
215                 _kvm_err(kd, kd->program,
216                          "cannot read %jd bytes for ptemap",
217                          (intmax_t)hdr->ptesize);
218                 return (-1);
219         }
220         off += hdr->ptesize;
221
222         vmst->kernbase = hdr->kernbase;
223         vmst->dmapbase = hdr->dmapbase;
224         vmst->dmapend = hdr->dmapend;
225         vmst->bitmapsize = hdr->bitmapsize;
226         vmst->pgtable = 0;
227
228         /* build physical address hash table for sparse pages */
229         inithash(kd, vmst->bitmap, hdr->bitmapsize, off);
230
231         return (0);
232 }
233
234 static
235 int
236 _kvm_minidump_init_hdr2(kvm_t *kd, struct vmstate *vmst,
237                         struct minidumphdr2 *hdr)
238 {
239         off_t off;
240
241         /* Skip header and msgbuf */
242         off = PAGE_SIZE + round_page(hdr->msgbufsize);
243
244         vmst->bitmap = _kvm_malloc(kd, hdr->bitmapsize);
245         if (vmst->bitmap == NULL) {
246                 _kvm_err(kd, kd->program,
247                          "cannot allocate %jd bytes for bitmap",
248                          (intmax_t)hdr->bitmapsize);
249                 return (-1);
250         }
251         if (pread(kd->pmfd, vmst->bitmap, hdr->bitmapsize, off) !=
252             (intmax_t)hdr->bitmapsize) {
253                 _kvm_err(kd, kd->program,
254                          "cannot read %jd bytes for page bitmap",
255                          (intmax_t)hdr->bitmapsize);
256                 return (-1);
257         }
258         off += round_page(hdr->bitmapsize);
259
260         vmst->ptemap = _kvm_malloc(kd, hdr->ptesize);
261         if (vmst->ptemap == NULL) {
262                 _kvm_err(kd, kd->program,
263                          "cannot allocate %jd bytes for ptemap",
264                          (intmax_t)hdr->ptesize);
265                 return (-1);
266         }
267         if (pread(kd->pmfd, vmst->ptemap, hdr->ptesize, off) !=
268             (intmax_t)hdr->ptesize) {
269                 _kvm_err(kd, kd->program,
270                          "cannot read %jd bytes for ptemap",
271                          (intmax_t)hdr->ptesize);
272                 return (-1);
273         }
274         off += hdr->ptesize;
275
276         vmst->kernbase = hdr->kernbase;
277         vmst->dmapbase = hdr->dmapbase;
278         vmst->bitmapsize = hdr->bitmapsize;
279         vmst->pgtable = 1;
280
281         /* build physical address hash table for sparse pages */
282         inithash(kd, vmst->bitmap, hdr->bitmapsize, off);
283
284         return (0);
285 }
286
287 static int
288 _kvm_minidump_vatop(kvm_t *kd, u_long va, off_t *pa)
289 {
290         struct vmstate *vm;
291         u_long offset;
292         pt_entry_t pte;
293         u_long pteindex;
294         u_long a;
295         off_t ofs;
296
297         vm = kd->vmst;
298         offset = va & (PAGE_SIZE - 1);
299         va -= offset;                   /* put va on page boundary */
300
301         if (va >= vm->kernbase) {
302                 switch (vm->pgtable) {
303                 case 0:
304                         /*
305                          * Page tables are specifically dumped (old style)
306                          */
307                         pteindex = (va - vm->kernbase) >> PAGE_SHIFT;
308                         pte = vm->ptemap[pteindex];
309                         if (((u_long)pte & X86_PG_V) == 0) {
310                                 _kvm_err(kd, kd->program,
311                                          "_kvm_vatop: pte not valid");
312                                 goto invalid;
313                         }
314                         a = pte & PG_FRAME;
315                         break;
316                 case 1:
317                         /*
318                          * Kernel page table pages are included in the
319                          * sparse map.  We only dump the contents of
320                          * the PDs (zero-filling any empty entries).
321                          *
322                          * Index of PD entry in PDP & PDP in PML4E together.
323                          *
324                          * First shift by 30 (1GB) - gives us an index
325                          * into PD entries.  We do not PDP entries in the
326                          * PML4E, so there are 512 * 512 PD entries possible.
327                          */
328                         pteindex = (va >> PDPSHIFT) & (512 * 512 - 1);
329                         pte = vm->ptemap[pteindex];
330                         if ((pte & X86_PG_V) == 0) {
331                                 _kvm_err(kd, kd->program,
332                                          "_kvm_vatop: pd not valid");
333                                 goto invalid;
334                         }
335                         if (pte & X86_PG_PS) {          /* 1GB pages */
336                                 a = (pte & PG_PS_FRAME) +
337                                     (va & (1024 * 1024 * 1024 - 1));
338                                 break;
339                         }
340                                                         /* PD page */
341                         ofs = hpt_find(kd, pte & PG_FRAME);
342                         if (ofs == -1) {
343                                 _kvm_err(kd, kd->program,
344                                          "_kvm_vatop: no phys page for pd");
345                                 goto invalid;
346                         }
347
348                         /*
349                          * Index of PT entry in PD
350                          */
351                         pteindex = (va >> PDRSHIFT) & 511;
352                         if (pread(kd->pmfd, &pte, sizeof(pte),
353                               ofs + pteindex * sizeof(pte)) != sizeof(pte)) {
354                                 _kvm_err(kd, kd->program,
355                                          "_kvm_vatop: pd lookup not valid");
356                                 goto invalid;
357                         }
358                         if ((pte & X86_PG_V) == 0) {
359                                 _kvm_err(kd, kd->program,
360                                          "_kvm_vatop: pt not valid");
361                                 goto invalid;
362                         }
363                         if (pte & X86_PG_PS) {          /* 2MB pages */
364                                 a = (pte & PG_PS_FRAME) +
365                                     (va & (2048 * 1024 - 1));
366                                 break;
367                         }
368                         ofs = hpt_find(kd, pte & PG_FRAME);
369                         if (ofs == -1) {
370                                 _kvm_err(kd, kd->program,
371                                          "_kvm_vatop: no phys page for pt");
372                                 goto invalid;
373                         }
374
375                         /*
376                          * Index of pte entry in PT
377                          */
378                         pteindex = (va >> PAGE_SHIFT) & 511;
379                         if (pread(kd->pmfd, &pte, sizeof(pte),
380                               ofs + pteindex * sizeof(pte)) != sizeof(pte)) {
381                                 _kvm_err(kd, kd->program,
382                                          "_kvm_vatop: pte lookup not valid");
383                                 goto invalid;
384                         }
385
386                         /*
387                          * Calculate end page
388                          */
389                         a = pte & PG_FRAME;
390                         break;
391                 default:
392                         _kvm_err(kd, kd->program,
393                                  "_kvm_vatop: bad pgtable mode ");
394                         goto invalid;
395                 }
396                 ofs = hpt_find(kd, a);
397                 if (ofs == -1) {
398                         _kvm_err(kd, kd->program, "_kvm_vatop: physical address 0x%lx not in minidump", a);
399                         goto invalid;
400                 }
401                 *pa = ofs + offset;
402                 return (PAGE_SIZE - offset);
403         } else if (va >= vm->dmapbase && va < vm->dmapend) {
404                 a = (va - vm->dmapbase) & ~PAGE_MASK;
405                 ofs = hpt_find(kd, a);
406                 if (ofs == -1) {
407                         _kvm_err(kd, kd->program, "_kvm_vatop: direct map address 0x%lx not in minidump", va);
408                         goto invalid;
409                 }
410                 *pa = ofs + offset;
411                 return (PAGE_SIZE - offset);
412         } else {
413                 _kvm_err(kd, kd->program, "_kvm_vatop: virtual address 0x%lx not minidumped", va);
414                 goto invalid;
415         }
416
417 invalid:
418         _kvm_err(kd, 0, "invalid address (0x%lx)", va);
419         return (0);
420 }
421
422 int
423 _kvm_minidump_kvatop(kvm_t *kd, u_long va, off_t *pa)
424 {
425         if (kvm_ishost(kd)) {
426                 _kvm_err(kd, 0, "kvm_vatop called in live kernel!");
427                 return((off_t)0);
428         }
429
430         return (_kvm_minidump_vatop(kd, va, pa));
431 }