]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - lib/libkvm/kvm_i386.c
Merge from HEAD
[FreeBSD/FreeBSD.git] / lib / libkvm / kvm_i386.c
1 /*-
2  * Copyright (c) 1989, 1992, 1993
3  *      The Regents of the University of California.  All rights reserved.
4  *
5  * This code is derived from software developed by the Computer Systems
6  * Engineering group at Lawrence Berkeley Laboratory under DARPA contract
7  * BG 91-66 and contributed to Berkeley.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  * 1. Redistributions of source code must retain the above copyright
13  *    notice, this list of conditions and the following disclaimer.
14  * 2. Redistributions in binary form must reproduce the above copyright
15  *    notice, this list of conditions and the following disclaimer in the
16  *    documentation and/or other materials provided with the distribution.
17  * 4. Neither the name of the University nor the names of its contributors
18  *    may be used to endorse or promote products derived from this software
19  *    without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31  * SUCH DAMAGE.
32  */
33
34 #include <sys/cdefs.h>
35 __FBSDID("$FreeBSD$");
36
37 #if defined(LIBC_SCCS) && !defined(lint)
38 #if 0
39 static char sccsid[] = "@(#)kvm_hp300.c 8.1 (Berkeley) 6/4/93";
40 #endif
41 #endif /* LIBC_SCCS and not lint */
42
43 /*
44  * i386 machine dependent routines for kvm.  Hopefully, the forthcoming
45  * vm code will one day obsolete this module.
46  */
47
48 #include <sys/param.h>
49 #include <sys/user.h>
50 #include <sys/proc.h>
51 #include <sys/stat.h>
52 #include <sys/mman.h>
53 #include <stdlib.h>
54 #include <string.h>
55 #include <unistd.h>
56 #include <nlist.h>
57 #include <kvm.h>
58
59 #include <vm/vm.h>
60 #include <vm/vm_param.h>
61
62 #include <machine/elf.h>
63
64 #include <limits.h>
65
66 #include "kvm_private.h"
67
68 #ifndef btop
69 #define btop(x)         (i386_btop(x))
70 #define ptob(x)         (i386_ptob(x))
71 #endif
72
73 #define PG_FRAME_PAE    (~((uint64_t)PAGE_MASK))
74 #define PDRSHIFT_PAE    21
75 #define NPTEPG_PAE      (PAGE_SIZE/sizeof(uint64_t))
76 #define NBPDR_PAE       (1<<PDRSHIFT_PAE)
77
78 /* minidump must be the first item! */
79 struct vmstate {
80         int             minidump;       /* 1 = minidump mode */
81         void            *mmapbase;
82         size_t          mmapsize;
83         void            *PTD;
84         int             pae;
85 };
86
87 /*
88  * Map the ELF headers into the process' address space. We do this in two
89  * steps: first the ELF header itself and using that information the whole
90  * set of headers.
91  */
92 static int
93 _kvm_maphdrs(kvm_t *kd, size_t sz)
94 {
95         struct vmstate *vm = kd->vmst;
96
97         /* munmap() previous mmap(). */
98         if (vm->mmapbase != NULL) {
99                 munmap(vm->mmapbase, vm->mmapsize);
100                 vm->mmapbase = NULL;
101         }
102
103         vm->mmapsize = sz;
104         vm->mmapbase = mmap(NULL, sz, PROT_READ, MAP_PRIVATE, kd->pmfd, 0);
105         if (vm->mmapbase == MAP_FAILED) {
106                 _kvm_err(kd, kd->program, "cannot mmap corefile");
107                 return (-1);
108         }
109         return (0);
110 }
111
112 /*
113  * Translate a physical memory address to a file-offset in the crash-dump.
114  */
115 static size_t
116 _kvm_pa2off(kvm_t *kd, uint64_t pa, off_t *ofs)
117 {
118         Elf_Ehdr *e = kd->vmst->mmapbase;
119         Elf_Phdr *p;
120         int n;
121
122         if (kd->rawdump) {
123                 *ofs = pa;
124                 return (PAGE_SIZE - ((size_t)pa & PAGE_MASK));
125         }
126
127         p = (Elf_Phdr*)((char*)e + e->e_phoff);
128         n = e->e_phnum;
129         while (n && (pa < p->p_paddr || pa >= p->p_paddr + p->p_memsz))
130                 p++, n--;
131         if (n == 0)
132                 return (0);
133         *ofs = (pa - p->p_paddr) + p->p_offset;
134         return (PAGE_SIZE - ((size_t)pa & PAGE_MASK));
135 }
136
137 void
138 _kvm_freevtop(kvm_t *kd)
139 {
140         struct vmstate *vm = kd->vmst;
141
142         if (kd->vmst->minidump)
143                 return (_kvm_minidump_freevtop(kd));
144         if (vm->mmapbase != NULL)
145                 munmap(vm->mmapbase, vm->mmapsize);
146         if (vm->PTD)
147                 free(vm->PTD);
148         free(vm);
149         kd->vmst = NULL;
150 }
151
152 int
153 _kvm_initvtop(kvm_t *kd)
154 {
155         struct nlist nl[2];
156         u_long pa;
157         u_long kernbase;
158         char            *PTD;
159         Elf_Ehdr        *ehdr;
160         size_t          hdrsz;
161         int             i;
162         char            minihdr[8];
163
164         if (!kd->rawdump && pread(kd->pmfd, &minihdr, 8, 0) == 8)
165                 if (memcmp(&minihdr, "minidump", 8) == 0)
166                         return (_kvm_minidump_initvtop(kd));
167
168         kd->vmst = (struct vmstate *)_kvm_malloc(kd, sizeof(*kd->vmst));
169         if (kd->vmst == 0) {
170                 _kvm_err(kd, kd->program, "cannot allocate vm");
171                 return (-1);
172         }
173         kd->vmst->PTD = 0;
174
175         if (kd->rawdump == 0) {
176                 if (_kvm_maphdrs(kd, sizeof(Elf_Ehdr)) == -1)
177                         return (-1);
178
179                 ehdr = kd->vmst->mmapbase;
180                 hdrsz = ehdr->e_phoff + ehdr->e_phentsize * ehdr->e_phnum;
181                 if (_kvm_maphdrs(kd, hdrsz) == -1)
182                         return (-1);
183         }
184
185         nl[0].n_name = "kernbase";
186         nl[1].n_name = 0;
187
188         if (kvm_nlist(kd, nl) != 0)
189                 kernbase = KERNBASE;    /* for old kernels */
190         else
191                 kernbase = nl[0].n_value;
192
193         nl[0].n_name = "IdlePDPT";
194         nl[1].n_name = 0;
195
196         if (kvm_nlist(kd, nl) == 0) {
197                 uint64_t pa64;
198
199                 if (kvm_read(kd, (nl[0].n_value - kernbase), &pa,
200                     sizeof(pa)) != sizeof(pa)) {
201                         _kvm_err(kd, kd->program, "cannot read IdlePDPT");
202                         return (-1);
203                 }
204                 PTD = _kvm_malloc(kd, 4 * PAGE_SIZE);
205                 for (i = 0; i < 4; i++) {
206                         if (kvm_read(kd, pa + (i * sizeof(pa64)), &pa64,
207                             sizeof(pa64)) != sizeof(pa64)) {
208                                 _kvm_err(kd, kd->program, "Cannot read PDPT");
209                                 free(PTD);
210                                 return (-1);
211                         }
212                         if (kvm_read(kd, pa64 & PG_FRAME_PAE,
213                             PTD + (i * PAGE_SIZE), PAGE_SIZE) != (PAGE_SIZE)) {
214                                 _kvm_err(kd, kd->program, "cannot read PDPT");
215                                 free(PTD);
216                                 return (-1);
217                         }
218                 }
219                 kd->vmst->PTD = PTD;
220                 kd->vmst->pae = 1;
221         } else {
222                 nl[0].n_name = "IdlePTD";
223                 nl[1].n_name = 0;
224
225                 if (kvm_nlist(kd, nl) != 0) {
226                         _kvm_err(kd, kd->program, "bad namelist");
227                         return (-1);
228                 }
229                 if (kvm_read(kd, (nl[0].n_value - kernbase), &pa,
230                     sizeof(pa)) != sizeof(pa)) {
231                         _kvm_err(kd, kd->program, "cannot read IdlePTD");
232                         return (-1);
233                 }
234                 PTD = _kvm_malloc(kd, PAGE_SIZE);
235                 if (kvm_read(kd, pa, PTD, PAGE_SIZE) != PAGE_SIZE) {
236                         _kvm_err(kd, kd->program, "cannot read PTD");
237                         return (-1);
238                 }
239                 kd->vmst->PTD = PTD;
240                 kd->vmst->pae = 0;
241         }
242         return (0);
243 }
244
245 static int
246 _kvm_vatop(kvm_t *kd, u_long va, off_t *pa)
247 {
248         struct vmstate *vm;
249         u_long offset;
250         u_long pte_pa;
251         u_long pde_pa;
252         pd_entry_t pde;
253         pt_entry_t pte;
254         u_long pdeindex;
255         u_long pteindex;
256         size_t s;
257         u_long a;
258         off_t ofs;
259         uint32_t *PTD;
260
261         vm = kd->vmst;
262         PTD = (uint32_t *)vm->PTD;
263         offset = va & (PAGE_SIZE - 1);
264
265         /*
266          * If we are initializing (kernel page table descriptor pointer
267          * not yet set) then return pa == va to avoid infinite recursion.
268          */
269         if (PTD == 0) {
270                 s = _kvm_pa2off(kd, va, pa);
271                 if (s == 0) {
272                         _kvm_err(kd, kd->program, 
273                             "_kvm_vatop: bootstrap data not in dump");
274                         goto invalid;
275                 } else
276                         return (PAGE_SIZE - offset);
277         }
278
279         pdeindex = va >> PDRSHIFT;
280         pde = PTD[pdeindex];
281         if (((u_long)pde & PG_V) == 0) {
282                 _kvm_err(kd, kd->program, "_kvm_vatop: pde not valid");
283                 goto invalid;
284         }
285
286         if ((u_long)pde & PG_PS) {
287               /*
288                * No second-level page table; ptd describes one 4MB page.
289                * (We assume that the kernel wouldn't set PG_PS without enabling
290                * it cr0).
291                */
292 #define PAGE4M_MASK     (NBPDR - 1)
293 #define PG_FRAME4M      (~PAGE4M_MASK)
294                 pde_pa = ((u_long)pde & PG_FRAME4M) + (va & PAGE4M_MASK);
295                 s = _kvm_pa2off(kd, pde_pa, &ofs);
296                 if (s == 0) {
297                         _kvm_err(kd, kd->program,
298                             "_kvm_vatop: 4MB page address not in dump");
299                         goto invalid;
300                 }
301                 *pa = ofs;
302                 return (NBPDR - (va & PAGE4M_MASK));
303         }
304
305         pteindex = (va >> PAGE_SHIFT) & (NPTEPG-1);
306         pte_pa = ((u_long)pde & PG_FRAME) + (pteindex * sizeof(pde));
307
308         s = _kvm_pa2off(kd, pte_pa, &ofs);
309         if (s < sizeof pte) {
310                 _kvm_err(kd, kd->program, "_kvm_vatop: pdpe_pa not found");
311                 goto invalid;
312         }
313
314         /* XXX This has to be a physical address read, kvm_read is virtual */
315         if (lseek(kd->pmfd, ofs, 0) == -1) {
316                 _kvm_syserr(kd, kd->program, "_kvm_vatop: lseek");
317                 goto invalid;
318         }
319         if (read(kd->pmfd, &pte, sizeof pte) != sizeof pte) {
320                 _kvm_syserr(kd, kd->program, "_kvm_vatop: read");
321                 goto invalid;
322         }
323         if (((u_long)pte & PG_V) == 0) {
324                 _kvm_err(kd, kd->program, "_kvm_kvatop: pte not valid");
325                 goto invalid;
326         }
327
328         a = ((u_long)pte & PG_FRAME) + offset;
329         s =_kvm_pa2off(kd, a, pa);
330         if (s == 0) {
331                 _kvm_err(kd, kd->program, "_kvm_vatop: address not in dump");
332                 goto invalid;
333         } else
334                 return (PAGE_SIZE - offset);
335
336 invalid:
337         _kvm_err(kd, 0, "invalid address (0x%lx)", va);
338         return (0);
339 }
340
341 static int
342 _kvm_vatop_pae(kvm_t *kd, u_long va, off_t *pa)
343 {
344         struct vmstate *vm;
345         uint64_t offset;
346         uint64_t pte_pa;
347         uint64_t pde_pa;
348         uint64_t pde;
349         uint64_t pte;
350         u_long pdeindex;
351         u_long pteindex;
352         size_t s;
353         uint64_t a;
354         off_t ofs;
355         uint64_t *PTD;
356
357         vm = kd->vmst;
358         PTD = (uint64_t *)vm->PTD;
359         offset = va & (PAGE_SIZE - 1);
360
361         /*
362          * If we are initializing (kernel page table descriptor pointer
363          * not yet set) then return pa == va to avoid infinite recursion.
364          */
365         if (PTD == 0) {
366                 s = _kvm_pa2off(kd, va, pa);
367                 if (s == 0) {
368                         _kvm_err(kd, kd->program, 
369                             "_kvm_vatop_pae: bootstrap data not in dump");
370                         goto invalid;
371                 } else
372                         return (PAGE_SIZE - offset);
373         }
374
375         pdeindex = va >> PDRSHIFT_PAE;
376         pde = PTD[pdeindex];
377         if (((u_long)pde & PG_V) == 0) {
378                 _kvm_err(kd, kd->program, "_kvm_kvatop_pae: pde not valid");
379                 goto invalid;
380         }
381
382         if ((u_long)pde & PG_PS) {
383               /*
384                * No second-level page table; ptd describes one 2MB page.
385                * (We assume that the kernel wouldn't set PG_PS without enabling
386                * it cr0).
387                */
388 #define PAGE2M_MASK     (NBPDR_PAE - 1)
389 #define PG_FRAME2M      (~PAGE2M_MASK)
390                 pde_pa = ((u_long)pde & PG_FRAME2M) + (va & PAGE2M_MASK);
391                 s = _kvm_pa2off(kd, pde_pa, &ofs);
392                 if (s == 0) {
393                         _kvm_err(kd, kd->program,
394                             "_kvm_vatop: 2MB page address not in dump");
395                         goto invalid;
396                 }
397                 *pa = ofs;
398                 return (NBPDR_PAE - (va & PAGE2M_MASK));
399         }
400
401         pteindex = (va >> PAGE_SHIFT) & (NPTEPG_PAE-1);
402         pte_pa = ((uint64_t)pde & PG_FRAME_PAE) + (pteindex * sizeof(pde));
403
404         s = _kvm_pa2off(kd, pte_pa, &ofs);
405         if (s < sizeof pte) {
406                 _kvm_err(kd, kd->program, "_kvm_vatop_pae: pdpe_pa not found");
407                 goto invalid;
408         }
409
410         /* XXX This has to be a physical address read, kvm_read is virtual */
411         if (lseek(kd->pmfd, ofs, 0) == -1) {
412                 _kvm_syserr(kd, kd->program, "_kvm_vatop_pae: lseek");
413                 goto invalid;
414         }
415         if (read(kd->pmfd, &pte, sizeof pte) != sizeof pte) {
416                 _kvm_syserr(kd, kd->program, "_kvm_vatop_pae: read");
417                 goto invalid;
418         }
419         if (((uint64_t)pte & PG_V) == 0) {
420                 _kvm_err(kd, kd->program, "_kvm_vatop_pae: pte not valid");
421                 goto invalid;
422         }
423
424         a = ((uint64_t)pte & PG_FRAME_PAE) + offset;
425         s =_kvm_pa2off(kd, a, pa);
426         if (s == 0) {
427                 _kvm_err(kd, kd->program,
428                     "_kvm_vatop_pae: address not in dump");
429                 goto invalid;
430         } else
431                 return (PAGE_SIZE - offset);
432
433 invalid:
434         _kvm_err(kd, 0, "invalid address (0x%lx)", va);
435         return (0);
436 }
437
438 int
439 _kvm_kvatop(kvm_t *kd, u_long va, off_t *pa)
440 {
441
442         if (kd->vmst->minidump)
443                 return (_kvm_minidump_kvatop(kd, va, pa));
444         if (ISALIVE(kd)) {
445                 _kvm_err(kd, 0, "vatop called in live kernel!");
446                 return (0);
447         }
448         if (kd->vmst->pae)
449                 return (_kvm_vatop_pae(kd, va, pa));
450         else
451                 return (_kvm_vatop(kd, va, pa));
452 }