kvm_ia64.c revision 85478
1/* $FreeBSD: head/lib/libkvm/kvm_ia64.c 85478 2001-10-25 09:08:21Z dfr $ */
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/param.h>
32#include <sys/lock.h>
33#include <sys/mutex.h>
34#include <sys/user.h>
35#include <sys/proc.h>
36#include <sys/stat.h>
37#include <sys/types.h>
38#include <sys/uio.h>
39#include <unistd.h>
40#include <nlist.h>
41#include <kvm.h>
42
43#include <vm/vm.h>
44#include <vm/vm_param.h>
45
46#include <limits.h>
47#include <stdlib.h>
48#include <machine/pmap.h>
49#include "kvm_private.h"
50
51static off_t   _kvm_pa2off(kvm_t *kd, u_long pa);
52
53struct vmstate {
54	u_int64_t       kptdir;		/* PA of page table directory */
55        u_int64_t	page_size;	/* Page size */
56};
57
58void
59_kvm_freevtop(kvm_t *kd)
60{
61
62	/* Not actually used for anything right now, but safe. */
63	if (kd->vmst != 0)
64		free(kd->vmst);
65}
66
67int
68_kvm_initvtop(kvm_t *kd)
69{
70	struct vmstate *vm;
71	struct nlist nlist[2];
72	u_int64_t va;
73
74	vm = (struct vmstate *)_kvm_malloc(kd, sizeof(*vm));
75	if (vm == 0) {
76		_kvm_err(kd, kd->program, "cannot allocate vm");
77		return (-1);
78	}
79	kd->vmst = vm;
80	vm->page_size = getpagesize(); /* XXX wrong for crashdumps */
81
82	nlist[0].n_name = "kptdir";
83	nlist[1].n_name = 0;
84
85	if (kvm_nlist(kd, nlist) != 0) {
86		_kvm_err(kd, kd->program, "bad namelist");
87		return (-1);
88	}
89
90	if(!ISALIVE(kd)) {
91		if (kvm_read(kd, (nlist[0].n_value), &va, sizeof(va)) != sizeof(va)) {
92			_kvm_err(kd, kd->program, "cannot read kptdir");
93			return (-1);
94		}
95	} else
96		if (kvm_read(kd, (nlist[0].n_value), &va, sizeof(va)) != sizeof(va)) {
97			_kvm_err(kd, kd->program, "cannot read kptdir");
98			return (-1);
99		}
100	vm->kptdir = IA64_RR_MASK(va);
101	return (0);
102
103}
104
105int
106_kvm_kvatop(kvm_t *kd, u_long va, u_long *pa)
107{
108	u_int64_t	kptdir;			/* PA of kptdir */
109        u_int64_t	page_size;
110	int		rv, page_off;
111	struct ia64_lpte pte;
112	off_t		pteoff;
113	struct vmstate	*vm;
114
115	vm = kd->vmst;
116
117        if (ISALIVE(kd)) {
118                _kvm_err(kd, 0, "vatop called in live kernel!");
119                return(0);
120        }
121	kptdir = vm->kptdir;
122	page_size = vm->page_size;
123
124	page_off = va & (page_size - 1);
125	if (va >= IA64_RR_BASE(6) && va <= IA64_RR_BASE(7) + ((1L<<61)-1)) {
126		/*
127		 * Direct-mapped address: just convert it.
128		 */
129
130		*pa = IA64_RR_MASK(va);
131		rv = page_size - page_off;
132	} else if (va >= IA64_RR_BASE(5) && va < IA64_RR_BASE(6)) {
133		/*
134		 * Real kernel virtual address: do the translation.
135		 */
136#define KPTE_DIR_INDEX(va, ps) \
137	(IA64_RR_MASK(va) / ((ps) * (ps) * sizeof(struct ia64_lpte)))
138#define KPTE_PTE_INDEX(va, ps) \
139	(((va) / (ps)) % (ps / sizeof(struct ia64_lpte)))
140
141		int maxpt = page_size / sizeof(u_int64_t);
142		int ptno = KPTE_DIR_INDEX(va, page_size);
143		int pgno = KPTE_PTE_INDEX(va, page_size);
144		u_int64_t ptoff, pgoff;
145
146		if (ptno >= maxpt) {
147			_kvm_err(kd, 0, "invalid translation (va too large)");
148			goto lose;
149		}
150		ptoff = kptdir + ptno * sizeof(u_int64_t);
151		if (lseek(kd->pmfd, _kvm_pa2off(kd, ptoff), 0) == -1 ||
152		    read(kd->pmfd, &pgoff, sizeof(pgoff)) != sizeof(pgoff)) {
153			_kvm_syserr(kd, 0, "could not read page table address");
154			goto lose;
155		}
156		pgoff = IA64_RR_MASK(pgoff);
157		if (!pgoff) {
158			_kvm_err(kd, 0, "invalid translation (no page table)");
159			goto lose;
160		}
161		if (lseek(kd->pmfd, _kvm_pa2off(kd, pgoff), 0) == -1 ||
162		    read(kd->pmfd, &pte, sizeof(pte)) != sizeof(pte)) {
163			_kvm_syserr(kd, 0, "could not read PTE");
164			goto lose;
165		}
166		if (!pte.pte_p) {
167			_kvm_err(kd, 0, "invalid translation (invalid PTE)");
168			goto lose;
169		}
170		*pa = pte.pte_ppn << 12;
171		rv = page_size - page_off;
172	} else {
173		/*
174		 * Bogus address (not in KV space): punt.
175		 */
176
177		_kvm_err(kd, 0, "invalid kernel virtual address");
178lose:
179		*pa = -1;
180		rv = 0;
181	}
182
183	return (rv);
184}
185
186/*
187 * Translate a physical address to a file-offset in the crash-dump.
188 */
189off_t
190_kvm_pa2off(kd, pa)
191	kvm_t *kd;
192	u_long pa;
193{
194	return IA64_PHYS_TO_RR7(pa);
195}
196
197