1/*	$NetBSD: kvm_sparc.c,v 1.31 2010/09/19 02:07:00 jym Exp $	*/
2
3/*-
4 * Copyright (c) 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#if defined(LIBC_SCCS) && !defined(lint)
38#if 0
39static char sccsid[] = "@(#)kvm_sparc.c	8.1 (Berkeley) 6/4/93";
40#else
41__RCSID("$NetBSD: kvm_sparc.c,v 1.31 2010/09/19 02:07:00 jym Exp $");
42#endif
43#endif /* LIBC_SCCS and not lint */
44
45/*
46 * Sparc 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/exec.h>
52#include <sys/user.h>
53#include <sys/proc.h>
54#include <sys/stat.h>
55#include <sys/core.h>
56#include <sys/kcore.h>
57#include <unistd.h>
58#include <nlist.h>
59#include <kvm.h>
60
61#include <uvm/uvm_extern.h>
62
63#include <sparc/pmap.h>
64#include <sparc/kcore.h>
65
66#include <limits.h>
67#include <db.h>
68
69#include "kvm_private.h"
70
71
72static int cputyp = -1;
73static int pgshift;
74static int nptesg;	/* [sun4/sun4c] only */
75
76#undef VA_VPG
77#define VA_VPG(va)	((cputyp == CPU_SUN4C || cputyp == CPU_SUN4M) \
78				? VA_SUN4C_VPG(va) \
79				: VA_SUN4_VPG(va))
80
81#undef VA_OFF
82#define VA_OFF(va) (va & (kd->nbpg - 1))
83
84int _kvm_kvatop44c(kvm_t *, vaddr_t, paddr_t *);
85int _kvm_kvatop4m (kvm_t *, vaddr_t, paddr_t *);
86int _kvm_kvatop4u (kvm_t *, vaddr_t, paddr_t *);
87
88/*
89 * XXX
90 * taken from /sys/arch/sparc64/include/kcore.h.
91 * this is the same as the sparc one, except for the kphys addition,
92 * so luckily we can use this here...
93 */
94typedef struct sparc64_cpu_kcore_hdr {
95	int	cputype;		/* CPU type associated with this dump */
96	u_long	kernbase;		/* copy of KERNBASE goes here */
97	int	nmemseg;		/* # of physical memory segments */
98	u_long	memsegoffset;		/* start of memseg array (relative */
99					/*  to the start of this header) */
100	int	nsegmap;		/* # of segmaps following */
101	u_long	segmapoffset;		/* start of segmap array (relative */
102					/*  to the start of this header) */
103	int	npmeg;			/* # of PMEGs; [sun4/sun4c] only */
104	u_long	pmegoffset;		/* start of pmeg array (relative */
105					/*  to the start of this header) */
106/* SPARC64 stuff */
107	paddr_t	kphys;			/* Physical address of 4MB locked TLB */
108} sparc64_cpu_kcore_hdr_t;
109
110void
111_kvm_freevtop(kvm_t *kd)
112{
113	if (kd->vmst != 0) {
114		_kvm_err(kd, kd->program, "_kvm_freevtop: internal error");
115		kd->vmst = 0;
116	}
117}
118
119/*
120 * Prepare for translation of kernel virtual addresses into offsets
121 * into crash dump files. We use the MMU specific goop written at the
122 * front of the crash dump by pmap_dumpmmu().
123 */
124int
125_kvm_initvtop(kvm_t *kd)
126{
127	sparc64_cpu_kcore_hdr_t *cpup = kd->cpu_data;
128
129	switch (cputyp = cpup->cputype) {
130	case CPU_SUN4:
131	case CPU_SUN4U:
132		kd->nbpg = 8196;
133		pgshift = 13;
134		break;
135	case CPU_SUN4C:
136	case CPU_SUN4M:
137		kd->nbpg = 4096;
138		pgshift = 12;
139		break;
140	default:
141		_kvm_err(kd, kd->program, "Unsupported CPU type");
142		return (-1);
143	}
144	nptesg = NBPSG / kd->nbpg;
145	return (0);
146}
147
148/*
149 * Translate a kernel virtual address to a physical address using the
150 * mapping information in kd->vm.  Returns the result in pa, and returns
151 * the number of bytes that are contiguously available from this
152 * physical address.  This routine is used only for crash dumps.
153 */
154int
155_kvm_kvatop(kvm_t *kd, vaddr_t va, paddr_t *pa)
156{
157	if (cputyp == -1)
158		if (_kvm_initvtop(kd) != 0)
159			return (-1);
160
161	switch (cputyp) {
162	case CPU_SUN4:
163	case CPU_SUN4C:
164		return _kvm_kvatop44c(kd, va, pa);
165		break;
166	case CPU_SUN4M:
167		return _kvm_kvatop4m(kd, va, pa);
168		break;
169	case CPU_SUN4U:
170	default:
171		return _kvm_kvatop4u(kd, va, pa);
172	}
173}
174
175/*
176 * (note: sun4 3-level MMU not yet supported)
177 */
178int
179_kvm_kvatop44c(kvm_t *kd, vaddr_t va, paddr_t *pa)
180{
181	int vr, vs, pte;
182	sparc64_cpu_kcore_hdr_t *cpup = kd->cpu_data;
183	struct segmap *sp, *segmaps;
184	int *ptes;
185	int nkreg, nureg;
186	u_long kernbase = cpup->kernbase;
187
188	if (va < kernbase)
189		goto err;
190
191	/*
192	 * Layout of CPU segment:
193	 *	cpu_kcore_hdr_t;
194	 *	[alignment]
195	 *	phys_ram_seg_t[cpup->nmemseg];
196	 *	segmap[cpup->nsegmap];
197	 *	ptes[cpup->npmegs];
198	 */
199	segmaps = (struct segmap *)((long)kd->cpu_data + cpup->segmapoffset);
200	ptes = (int *)((int)kd->cpu_data + cpup->pmegoffset);
201	nkreg = ((int)((-(unsigned)kernbase) / NBPRG));
202	nureg = 256 - nkreg;
203
204	vr = VA_VREG(va);
205	vs = VA_VSEG(va);
206
207	sp = &segmaps[(vr-nureg)*NSEGRG + vs];
208	if (sp->sg_npte == 0)
209		goto err;
210	if (sp->sg_pmeg == cpup->npmeg - 1) /* =seginval */
211		goto err;
212	pte = ptes[sp->sg_pmeg * nptesg + VA_VPG(va)];
213	if ((pte & PG_V) != 0) {
214		paddr_t p, off = VA_OFF(va);
215
216		p = (pte & PG_PFNUM) << pgshift;
217		*pa = p + off;
218		return (kd->nbpg - off);
219	}
220err:
221	_kvm_err(kd, 0, "invalid address (%#"PRIxVADDR")", va);
222	return (0);
223}
224
225int
226_kvm_kvatop4m(kvm_t *kd, vaddr_t va, paddr_t *pa)
227{
228	sparc64_cpu_kcore_hdr_t *cpup = kd->cpu_data;
229	int vr, vs;
230	int pte;
231	off_t foff;
232	struct segmap *sp, *segmaps;
233	int nkreg, nureg;
234	u_long kernbase = cpup->kernbase;
235
236	if (va < kernbase)
237		goto err;
238
239	/*
240	 * Layout of CPU segment:
241	 *	cpu_kcore_hdr_t;
242	 *	[alignment]
243	 *	phys_ram_seg_t[cpup->nmemseg];
244	 *	segmap[cpup->nsegmap];
245	 */
246	segmaps = (struct segmap *)((long)kd->cpu_data + cpup->segmapoffset);
247	nkreg = ((int)((-(unsigned)kernbase) / NBPRG));
248	nureg = 256 - nkreg;
249
250	vr = VA_VREG(va);
251	vs = VA_VSEG(va);
252
253	sp = &segmaps[(vr-nureg)*NSEGRG + vs];
254	if (sp->sg_npte == 0)
255		goto err;
256
257	/* XXX - assume page tables in initial kernel DATA or BSS. */
258	foff = _kvm_pa2off(kd, (u_long)&sp->sg_pte[VA_VPG(va)] - kernbase);
259	if (foff == (off_t)-1)
260		return (0);
261
262	if (_kvm_pread(kd, kd->pmfd, &pte, sizeof(pte), foff) != sizeof(pte)) {
263		_kvm_syserr(kd, kd->program, "cannot read pte for "
264		    "%#" PRIxVADDR, va);
265		return (0);
266	}
267
268	if ((pte & SRMMU_TETYPE) == SRMMU_TEPTE) {
269		long p, off = VA_OFF(va);
270
271		p = (pte & SRMMU_PPNMASK) << SRMMU_PPNPASHIFT;
272		*pa = p + off;
273		return (kd->nbpg - off);
274	}
275err:
276	_kvm_err(kd, 0, "invalid address (%#"PRIxVADDR")", va);
277	return (0);
278}
279
280/*
281 * sparc64 pmap's 32-bit page table format
282 */
283int
284_kvm_kvatop4u(kvm_t *kd, vaddr_t va, paddr_t *pa)
285{
286	sparc64_cpu_kcore_hdr_t *cpup = kd->cpu_data;
287	int64_t **segmaps;
288	int64_t *ptes;
289	int64_t pte;
290	int64_t kphys = cpup->kphys;
291	u_long kernbase = cpup->kernbase;
292
293	if (va < kernbase)
294		goto err;
295
296	/*
297	 * Kernel layout:
298	 *
299	 * kernbase:
300	 *	4MB locked TLB (text+data+BSS)
301	 *	Random other stuff.
302	 */
303	if (va >= kernbase && va < kernbase + 4*1024*1024)
304		return (va - kernbase) + kphys;
305
306/* XXX: from sparc64/include/pmap.h */
307#define	SPARC64_PTSZ		(kd->nbpg/8)
308#define	SPARC64_STSZ		(SPARC64_PTSZ)
309#define	SPARC64_PTMASK		(SPARC64_PTSZ-1)
310#define	SPARC64_PTSHIFT		(13)
311#define	SPARC64_PDSHIFT		(10+SPARC64_PTSHIFT)
312#define	SPARC64_STSHIFT		(10+SPARC64_PDSHIFT)
313#define	SPARC64_STMASK		(SPARC64_STSZ-1)
314#define	sparc64_va_to_seg(v)	(int)((((int64_t)(v))>>SPARC64_STSHIFT)&SPARC64_STMASK)
315#define	sparc64_va_to_pte(v)	(int)((((int64_t)(v))>>SPARC64_PTSHIFT)&SPARC64_PTMASK)
316
317/* XXX: from sparc64/include/pte.h */
318#define	SPARC64_TLB_V			0x8000000000000000LL
319#define	SPARC64_TLB_PA_MASK		0x000001ffffffe000LL
320
321	/*
322	 * Layout of CPU segment:
323	 *	cpu_kcore_hdr_t;
324	 *	[alignment]
325	 *	phys_ram_seg_t[cpup->nmemseg];
326	 *	segmap[cpup->nsegmap];
327	 */
328	segmaps = (int64_t **)((long)kd->cpu_data + cpup->segmapoffset);
329	ptes = (int64_t *)(int)_kvm_pa2off(kd,
330	    (paddr_t)segmaps[sparc64_va_to_seg(va)]);
331	pte = ptes[sparc64_va_to_pte(va)];
332	if ((pte & SPARC64_TLB_V) != 0)
333		return ((pte & SPARC64_TLB_PA_MASK) | (va & (kd->nbpg - 1)));
334err:
335	_kvm_err(kd, 0, "invalid address (%#"PRIxVADDR")", va);
336	return (0);
337}
338
339
340/*
341 * Translate a physical address to a file-offset in the crash dump.
342 */
343off_t
344_kvm_pa2off(kvm_t *kd, paddr_t pa)
345{
346	sparc64_cpu_kcore_hdr_t *cpup = kd->cpu_data;
347	phys_ram_seg_t *mp;
348	off_t off;
349	int nmem;
350
351	/*
352	 * Layout of CPU segment:
353	 *	cpu_kcore_hdr_t;
354	 *	[alignment]
355	 *	phys_ram_seg_t[cpup->nmemseg];
356	 */
357	mp = (phys_ram_seg_t *)((int)kd->cpu_data + cpup->memsegoffset);
358	off = 0;
359
360	/* Translate (sparse) pfnum to (packed) dump offset */
361	for (nmem = cpup->nmemseg; --nmem >= 0; mp++) {
362		if (mp->start <= pa && pa < mp->start + mp->size)
363			break;
364		off += mp->size;
365	}
366	if (nmem < 0) {
367		_kvm_err(kd, 0, "invalid address (%lx)", pa);
368		return (-1);
369	}
370
371	return (kd->dump_off + off + pa - mp->start);
372}
373
374/*
375 * Machine-dependent initialization for ALL open kvm descriptors,
376 * not just those for a kernel crash dump.  Some architectures
377 * have to deal with these NOT being constants!  (i.e. m68k)
378 */
379int
380_kvm_mdopen(kvm_t *kd)
381{
382	u_long max_uva;
383	extern struct ps_strings *__ps_strings;
384
385	max_uva = (u_long) (__ps_strings + 1);
386	kd->usrstack = max_uva;
387	kd->max_uva  = max_uva;
388	kd->min_uva  = 0;
389
390	return (0);
391}
392