xref: /trueos/lib/libkvm/kvm_ia64.c (revision 031a36aa28612b41a2f8e8bb5bee7bef905bf21c)
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
ia64_maphdrs(kvm_t * kd,size_t sz)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
phys_addr2off(kvm_t * kd,uint64_t pa,off_t * ofs,size_t pgsz)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
phys_kvatop(kvm_t * kd,uint64_t va,off_t * ofs)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
phys_read(kvm_t * kd,uint64_t pa,void * buf,size_t bufsz)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
virt_addr2off(kvm_t * kd,uint64_t va,off_t * ofs,size_t pgsz)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
virt_kvatop(kvm_t * kd,uint64_t va,off_t * ofs)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
_kvm_freevtop(kvm_t * kd)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
_kvm_initvtop(kvm_t * kd)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
_kvm_kvatop(kvm_t * kd,u_long va,off_t * ofs)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 }
376