]> CyberLeo.Net >> Repos - FreeBSD/releng/10.2.git/blob - lib/libkvm/kvm_ia64.c
- Copy stable/10@285827 to releng/10.2 in preparation for 10.2-RC1
[FreeBSD/releng/10.2.git] / lib / libkvm / kvm_ia64.c
1 /* $FreeBSD$ */
2 /*      $NetBSD: kvm_alpha.c,v 1.7.2.1 1997/11/02 20:34:26 mellon Exp $ */
3
4 /*
5  * Copyright (c) 1994, 1995 Carnegie-Mellon University.
6  * All rights reserved.
7  *
8  * Author: Chris G. Demetriou
9  * 
10  * Permission to use, copy, modify and distribute this software and
11  * its documentation is hereby granted, provided that both the copyright
12  * notice and this permission notice appear in all copies of the
13  * software, derivative works or modified versions, and any portions
14  * thereof, and that both notices appear in supporting documentation.
15  * 
16  * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" 
17  * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND 
18  * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
19  * 
20  * Carnegie Mellon requests users of this software to return to
21  *
22  *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
23  *  School of Computer Science
24  *  Carnegie Mellon University
25  *  Pittsburgh PA 15213-3890
26  *
27  * any improvements or extensions that they make and grant Carnegie the
28  * rights to redistribute these changes.
29  */
30
31 #include <sys/types.h>
32 #include <sys/elf64.h>
33 #include <sys/mman.h>
34
35 #ifndef CROSS_LIBKVM
36 #include <machine/atomic.h>
37 #include <machine/bootinfo.h>
38 #include <machine/elf.h>
39 #include <machine/pte.h>
40 #else
41 #include "../../sys/ia64/include/atomic.h"
42 #include "../../sys/ia64/include/bootinfo.h"
43 #include "../../sys/ia64/include/elf.h"
44 #include "../../sys/ia64/include/pte.h"
45 #endif
46
47 #include <kvm.h>
48 #include <limits.h>
49 #include <stdint.h>
50 #include <stdlib.h>
51 #include <unistd.h>
52
53 #include "kvm_private.h"
54
55 #define REGION_BASE(n)          (((uint64_t)(n)) << 61)
56 #define REGION_ADDR(x)          ((x) & ((1LL<<61)-1LL))
57
58 #define NKPTEPG(ps)             ((ps) / sizeof(struct ia64_lpte))
59 #define NKPTEDIR(ps)            ((ps) >> 3)
60 #define KPTE_PTE_INDEX(va,ps)   (((va)/(ps)) % NKPTEPG(ps))
61 #define KPTE_DIR0_INDEX(va,ps)  ((((va)/(ps)) / NKPTEPG(ps)) / NKPTEDIR(ps))
62 #define KPTE_DIR1_INDEX(va,ps)  ((((va)/(ps)) / NKPTEPG(ps)) % NKPTEDIR(ps))
63
64 #define PBVM_BASE               0x9ffc000000000000UL
65 #define PBVM_PGSZ               (64 * 1024)
66
67 typedef size_t (a2p_f)(kvm_t *, uint64_t, off_t *);
68
69 struct vmstate {
70         void    *mmapbase;
71         size_t  mmapsize;
72         size_t  pagesize;
73         u_long  kptdir;
74         u_long  *pbvm_pgtbl;
75         u_int   pbvm_pgtblsz;
76         a2p_f   *kvatop;
77 };
78
79 /*
80  * Map the ELF headers into the process' address space. We do this in two
81  * steps: first the ELF header itself and using that information the whole
82  * set of headers.
83  */
84 static int
85 ia64_maphdrs(kvm_t *kd, size_t sz)
86 {
87         struct vmstate *vm = kd->vmst;
88
89         /* munmap() previous mmap(). */
90         if (vm->mmapbase != NULL) {
91                 munmap(vm->mmapbase, vm->mmapsize);
92                 vm->mmapbase = NULL;
93         }
94
95         vm->mmapsize = sz;
96         vm->mmapbase = mmap(NULL, sz, PROT_READ, MAP_PRIVATE, kd->pmfd, 0);
97         if (vm->mmapbase == MAP_FAILED) {
98                 _kvm_err(kd, kd->program, "cannot mmap corefile");
99                 return (-1);
100         }
101
102         return (0);
103 }
104
105 /*
106  * Physical core support.
107  */
108
109 static size_t
110 phys_addr2off(kvm_t *kd, uint64_t pa, off_t *ofs, size_t pgsz)
111 {
112         Elf64_Ehdr *e;
113         Elf64_Phdr *p;
114         int n;
115
116         if (pa != REGION_ADDR(pa))
117                 goto fail;
118
119         e = (Elf64_Ehdr *)(kd->vmst->mmapbase);
120         n = e->e_phnum;
121         p = (Elf64_Phdr *)(void *)((uintptr_t)(void *)e + e->e_phoff);
122         while (n && (pa < p->p_paddr || pa >= p->p_paddr + p->p_memsz))
123                 p++, n--;
124         if (n == 0)
125                 goto fail;
126
127         *ofs = (pa - p->p_paddr) + p->p_offset;
128         if (pgsz == 0)
129                 return (p->p_memsz - (pa - p->p_paddr));
130         return (pgsz - ((size_t)pa & (pgsz - 1)));
131
132  fail:
133         _kvm_err(kd, kd->program, "invalid physical address %#jx",
134             (uintmax_t)pa);
135         return (0);
136 }
137
138 static size_t
139 phys_kvatop(kvm_t *kd, uint64_t va, off_t *ofs)
140 {
141         struct ia64_lpte pte;
142         uint64_t pa, pgaddr, pt0addr, pt1addr;
143         size_t pgno, pgsz, pt0no, pt1no;
144
145         if (va >= REGION_BASE(6)) {
146                 /* Regions 6 and 7: direct mapped. */
147                 pa = REGION_ADDR(va);
148                 return (phys_addr2off(kd, pa, ofs, 0));
149         } else if (va >= REGION_BASE(5)) {
150                 /* Region 5: Kernel Virtual Memory. */
151                 va = REGION_ADDR(va);
152                 pgsz = kd->vmst->pagesize;
153                 pt0no = KPTE_DIR0_INDEX(va, pgsz);
154                 pt1no = KPTE_DIR1_INDEX(va, pgsz);
155                 pgno = KPTE_PTE_INDEX(va, pgsz);
156                 if (pt0no >= NKPTEDIR(pgsz))
157                         goto fail;
158                 pt0addr = kd->vmst->kptdir + (pt0no << 3);
159                 if (kvm_read(kd, pt0addr, &pt1addr, 8) != 8)
160                         goto fail;
161                 if (pt1addr == 0)
162                         goto fail;
163                 pt1addr += pt1no << 3;
164                 if (kvm_read(kd, pt1addr, &pgaddr, 8) != 8)
165                         goto fail;
166                 if (pgaddr == 0)
167                         goto fail;
168                 pgaddr += pgno * sizeof(pte);
169                 if (kvm_read(kd, pgaddr, &pte, sizeof(pte)) != sizeof(pte))
170                         goto fail;
171                 if (!(pte.pte & PTE_PRESENT))
172                         goto fail;
173                 pa = (pte.pte & PTE_PPN_MASK) + (va & (pgsz - 1));
174                 return (phys_addr2off(kd, pa, ofs, pgsz));
175         } else if (va >= PBVM_BASE) {
176                 /* Region 4: Pre-Boot Virtual Memory (PBVM). */
177                 va -= PBVM_BASE;
178                 pgsz = PBVM_PGSZ;
179                 pt0no = va / pgsz;
180                 if (pt0no >= (kd->vmst->pbvm_pgtblsz >> 3))
181                         goto fail;
182                 pt0addr = kd->vmst->pbvm_pgtbl[pt0no];
183                 if (!(pt0addr & PTE_PRESENT))
184                         goto fail;
185                 pa = (pt0addr & PTE_PPN_MASK) + va % pgsz;
186                 return (phys_addr2off(kd, pa, ofs, pgsz));
187         }
188
189  fail:
190         _kvm_err(kd, kd->program, "invalid kernel virtual address %#jx",
191             (uintmax_t)va);
192         *ofs = -1;
193         return (0);
194 }
195
196 static ssize_t
197 phys_read(kvm_t *kd, uint64_t pa, void *buf, size_t bufsz)
198 {
199         off_t ofs;
200         size_t sz;
201
202         sz = phys_addr2off(kd, pa, &ofs, 0);
203         if (sz < bufsz)
204                 return ((ssize_t)sz);
205
206         if (lseek(kd->pmfd, ofs, 0) == -1)
207                 return (-1);
208         return (read(kd->pmfd, buf, bufsz));
209 }
210
211 /*
212  * Virtual core support (aka minidump).
213  */
214
215 static size_t
216 virt_addr2off(kvm_t *kd, uint64_t va, off_t *ofs, size_t pgsz)
217 {
218         Elf64_Ehdr *e;
219         Elf64_Phdr *p;
220         int n;
221
222         if (va < REGION_BASE(4))
223                 goto fail;
224
225         e = (Elf64_Ehdr *)(kd->vmst->mmapbase);
226         n = e->e_phnum;
227         p = (Elf64_Phdr *)(void *)((uintptr_t)(void *)e + e->e_phoff); 
228         while (n && (va < p->p_vaddr || va >= p->p_vaddr + p->p_memsz))
229                 p++, n--;
230         if (n == 0)
231                 goto fail;
232
233         *ofs = (va - p->p_vaddr) + p->p_offset;
234         if (pgsz == 0)
235                 return (p->p_memsz - (va - p->p_vaddr));
236         return (pgsz - ((size_t)va & (pgsz - 1)));
237
238  fail:
239         _kvm_err(kd, kd->program, "invalid virtual address %#jx",
240             (uintmax_t)va);
241         return (0);
242 }
243
244 static size_t
245 virt_kvatop(kvm_t *kd, uint64_t va, off_t *ofs)
246 {
247
248         return (virt_addr2off(kd, va, ofs, 0));
249 }
250
251 /*
252  * KVM architecture support functions.
253  */
254
255 void
256 _kvm_freevtop(kvm_t *kd)
257 {
258         struct vmstate *vm = kd->vmst;
259
260         if (vm->pbvm_pgtbl != NULL)
261                 free(vm->pbvm_pgtbl);
262         if (vm->mmapbase != NULL)
263                 munmap(vm->mmapbase, vm->mmapsize);
264         free(vm);
265         kd->vmst = NULL;
266 }
267
268 int
269 _kvm_initvtop(kvm_t *kd)
270 {
271         struct bootinfo bi;
272         struct nlist nl[2];
273         uint64_t va;
274         Elf64_Ehdr *ehdr;
275         size_t hdrsz;
276         ssize_t sz;
277
278         kd->vmst = (struct vmstate *)_kvm_malloc(kd, sizeof(*kd->vmst));
279         if (kd->vmst == NULL) {
280                 _kvm_err(kd, kd->program, "cannot allocate vm");
281                 return (-1);
282         }
283
284 #ifndef CROSS_LIBKVM
285         kd->vmst->pagesize = getpagesize();
286 #else
287         kd->vmst->pagesize = 8192;
288 #endif
289
290         if (ia64_maphdrs(kd, sizeof(Elf64_Ehdr)) == -1)
291                 return (-1);
292
293         ehdr = kd->vmst->mmapbase;
294         hdrsz = ehdr->e_phoff + ehdr->e_phentsize * ehdr->e_phnum;
295         if (ia64_maphdrs(kd, hdrsz) == -1)
296                 return (-1);
297
298         kd->vmst->kvatop = (ehdr->e_flags & EF_IA_64_ABSOLUTE) ?
299             phys_kvatop : virt_kvatop;
300
301         /*
302          * Load the PBVM page table. We need this to resolve PBVM addresses.
303          * The PBVM page table is obtained from the bootinfo structure, of
304          * which the address is given to us in e_entry. If e_entry is 0, then
305          * this is assumed to be a pre-PBVM kernel.
306          * Note that the address of the bootinfo structure is either physical
307          * or virtual, depending on whether the core is physical or virtual.
308          */
309         if (ehdr->e_entry != 0 && (ehdr->e_flags & EF_IA_64_ABSOLUTE) != 0) {
310                 sz = phys_read(kd, ehdr->e_entry, &bi, sizeof(bi));
311                 if (sz != sizeof(bi)) {
312                         _kvm_err(kd, kd->program,
313                             "cannot read bootinfo at physical address %#jx",
314                             (uintmax_t)ehdr->e_entry);
315                         return (-1);
316                 }
317                 if (bi.bi_magic != BOOTINFO_MAGIC) {
318                         _kvm_err(kd, kd->program, "invalid bootinfo");
319                         return (-1);
320                 }
321                 kd->vmst->pbvm_pgtbl = _kvm_malloc(kd, bi.bi_pbvm_pgtblsz);
322                 if (kd->vmst->pbvm_pgtbl == NULL) {
323                         _kvm_err(kd, kd->program, "cannot allocate page table");
324                         return (-1);
325                 }
326                 kd->vmst->pbvm_pgtblsz = bi.bi_pbvm_pgtblsz;
327                 sz = phys_read(kd, bi.bi_pbvm_pgtbl, kd->vmst->pbvm_pgtbl,
328                     bi.bi_pbvm_pgtblsz);
329                 if (sz != bi.bi_pbvm_pgtblsz) {
330                         _kvm_err(kd, kd->program,
331                             "cannot read page table at physical address %#jx",
332                             (uintmax_t)bi.bi_pbvm_pgtbl);
333                         return (-1);
334                 }
335         } else {
336                 kd->vmst->pbvm_pgtbl = NULL;
337                 kd->vmst->pbvm_pgtblsz = 0;
338         }
339
340         /*
341          * At this point we've got enough information to use kvm_read() for
342          * direct mapped (ie region 6 and region 7) address, such as symbol
343          * addresses/values.
344          */
345
346         nl[0].n_name = "ia64_kptdir";
347         nl[1].n_name = 0;
348
349         if (kvm_nlist(kd, nl) != 0) {
350                 _kvm_err(kd, kd->program, "bad namelist");
351                 return (-1);
352         }
353
354         if (kvm_read(kd, (nl[0].n_value), &va, sizeof(va)) != sizeof(va)) {
355                 _kvm_err(kd, kd->program, "cannot read kptdir");
356                 return (-1);
357         }
358
359         if (va == REGION_BASE(5)) {
360                 _kvm_err(kd, kd->program, "kptdir is itself virtual");
361                 return (-1);
362         }
363
364         kd->vmst->kptdir = va;
365         return (0);
366 }
367
368 int
369 _kvm_kvatop(kvm_t *kd, u_long va, off_t *ofs)
370 {
371         size_t sz;
372
373         sz = kd->vmst->kvatop(kd, va, ofs);
374         return ((sz > INT_MAX) ? INT_MAX : sz);
375 }