kvm_sparc64.c revision 108300
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 * 3. All advertising materials mentioning features or use of this software
18 *    must display the following acknowledgement:
19 *	This product includes software developed by the University of
20 *	California, Berkeley and its contributors.
21 * 4. Neither the name of the University nor the names of its contributors
22 *    may be used to endorse or promote products derived from this software
23 *    without specific prior written permission.
24 *
25 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
26 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
28 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
29 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
30 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
31 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
32 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
33 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
34 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35 * SUCH DAMAGE.
36 *
37 *	from: FreeBSD: src/lib/libkvm/kvm_i386.c,v 1.15 2001/10/10 17:48:43
38 */
39
40#include <sys/cdefs.h>
41__FBSDID("$FreeBSD: head/lib/libkvm/kvm_sparc64.c 108300 2002-12-27 01:45:05Z jake $");
42
43#if defined(LIBC_SCCS) && !defined(lint)
44#if 0
45static char sccsid[] = "@(#)kvm_hp300.c	8.1 (Berkeley) 6/4/93";
46#endif
47#endif /* LIBC_SCCS and not lint */
48
49/*
50 * sparc64 machine dependent routines for kvm.
51 */
52
53#include <sys/param.h>
54#include <sys/user.h>
55#include <sys/proc.h>
56#include <sys/stat.h>
57#include <stdlib.h>
58#include <unistd.h>
59#include <nlist.h>
60#include <kvm.h>
61
62#include <vm/vm.h>
63#include <vm/vm_param.h>
64
65#include <machine/kerneldump.h>
66#include <machine/tte.h>
67#include <machine/tlb.h>
68#include <machine/tsb.h>
69
70#include <limits.h>
71
72#include "kvm_private.h"
73
74#ifndef btop
75#define	btop(x)		(sparc64_btop(x))
76#define	ptob(x)		(sparc64_ptob(x))
77#endif
78
79struct vmstate {
80	off_t		vm_tsb_off;
81	vm_size_t	vm_tsb_mask;
82	int		vm_nregions;
83	struct sparc64_dump_reg	*vm_regions;
84};
85
86void
87_kvm_freevtop(kvm_t *kd)
88{
89	if (kd->vmst != 0) {
90		free(kd->vmst->vm_regions);
91		free(kd->vmst);
92	}
93}
94
95static int
96_kvm_read_phys(kvm_t *kd, off_t pos, void *buf, size_t size)
97{
98
99	/* XXX This has to be a raw file read, kvm_read is virtual. */
100	if (lseek(kd->pmfd, pos, SEEK_SET) == -1) {
101		_kvm_syserr(kd, kd->program, "_kvm_read_phys: lseek");
102		return (0);
103	}
104	if (read(kd->pmfd, buf, size) != size) {
105		_kvm_syserr(kd, kd->program, "_kvm_read_phys: read");
106		return (0);
107	}
108	return (1);
109}
110
111static int
112_kvm_reg_cmp(const void *a, const void *b)
113{
114	const struct sparc64_dump_reg *ra, *rb;
115
116	ra = a;
117	rb = b;
118	if (ra->dr_pa < rb->dr_pa)
119		return (-1);
120	else if (ra->dr_pa >= rb->dr_pa + rb->dr_size)
121		return (1);
122	else
123		return (0);
124}
125
126#define	KVM_OFF_NOTFOUND	0
127
128static off_t
129_kvm_find_off(struct vmstate *vm, vm_offset_t pa, vm_size_t size)
130{
131	struct sparc64_dump_reg *reg, key;
132	vm_offset_t o;
133
134	key.dr_pa = pa;
135	reg = bsearch(&key, vm->vm_regions, vm->vm_nregions,
136	    sizeof(*vm->vm_regions), _kvm_reg_cmp);
137	if (reg == NULL)
138		return (KVM_OFF_NOTFOUND);
139	o = pa - reg->dr_pa;
140	if (o + size > reg->dr_size)
141		return (KVM_OFF_NOTFOUND);
142	return (reg->dr_offs + o);
143}
144
145int
146_kvm_initvtop(kvm_t *kd)
147{
148	struct sparc64_dump_hdr hdr;
149	struct sparc64_dump_reg	*regs;
150	struct vmstate *vm;
151	size_t regsz;
152	vm_offset_t pa;
153	vm_size_t mask;
154
155	vm = (struct vmstate *)_kvm_malloc(kd, sizeof(*vm));
156	if (vm == NULL) {
157		_kvm_err(kd, kd->program, "cannot allocate vm");
158		return (-1);
159	}
160	kd->vmst = vm;
161
162	if (!_kvm_read_phys(kd, 0, &hdr, sizeof(hdr)))
163		goto fail_vm;
164	pa = hdr.dh_tsb_pa;
165
166	regsz = hdr.dh_nregions * sizeof(*regs);
167	regs = _kvm_malloc(kd, regsz);
168	if (regs == NULL) {
169		_kvm_err(kd, kd->program, "cannot allocate regions");
170		goto fail_vm;
171	}
172	if (!_kvm_read_phys(kd, sizeof(hdr), regs, regsz))
173		goto fail_regs;
174	qsort(regs, hdr.dh_nregions, sizeof(*regs), _kvm_reg_cmp);
175
176	vm->vm_tsb_mask = hdr.dh_tsb_mask;
177	vm->vm_regions = regs;
178	vm->vm_nregions = hdr.dh_nregions;
179	vm->vm_tsb_off = _kvm_find_off(vm, hdr.dh_tsb_pa, hdr.dh_tsb_size);
180	if (vm->vm_tsb_off == KVM_OFF_NOTFOUND) {
181		_kvm_err(kd, kd->program, "tsb not found in dump");
182		goto fail_regs;
183	}
184	return (0);
185
186fail_regs:
187	free(regs);
188fail_vm:
189	free(vm);
190	return (-1);
191}
192
193int
194_kvm_kvatop(kvm_t *kd, u_long va, u_long *pa)
195{
196	struct vmstate *vm;
197	struct tte tte;
198	off_t tte_off, pa_off;
199	u_long pg_off, vpn;
200	int rest;
201
202	pg_off = va & PAGE_MASK;
203	if (va >= VM_MIN_DIRECT_ADDRESS)
204		pa_off = TLB_DIRECT_TO_PHYS(va) & ~PAGE_MASK;
205	else {
206		vpn = btop(va);
207		tte_off = kd->vmst->vm_tsb_off +
208		    ((vpn & kd->vmst->vm_tsb_mask) << TTE_SHIFT);
209		if (!_kvm_read_phys(kd, tte_off, &tte, sizeof(tte)))
210			goto invalid;
211		if (!tte_match(&tte, va))
212			goto invalid;
213		pa_off = TTE_GET_PA(&tte);
214	}
215	rest = PAGE_SIZE - pg_off;
216	pa_off = _kvm_find_off(kd->vmst, pa_off, rest);
217	if (pa_off == KVM_OFF_NOTFOUND)
218		goto invalid;
219	*pa = pa_off + pg_off;
220	return (rest);
221
222invalid:
223	_kvm_err(kd, 0, "invalid address (%x)", va);
224	return (0);
225}
226