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