kvm_sparc.c revision 1.9 1 1.9 cgd /* $NetBSD: kvm_sparc.c,v 1.9 1996/04/01 19:23:03 cgd Exp $ */
2 1.8 thorpej
3 1.1 cgd /*-
4 1.1 cgd * Copyright (c) 1992, 1993
5 1.1 cgd * The Regents of the University of California. All rights reserved.
6 1.1 cgd *
7 1.1 cgd * This code is derived from software developed by the Computer Systems
8 1.1 cgd * Engineering group at Lawrence Berkeley Laboratory under DARPA contract
9 1.1 cgd * BG 91-66 and contributed to Berkeley.
10 1.1 cgd *
11 1.1 cgd * Redistribution and use in source and binary forms, with or without
12 1.1 cgd * modification, are permitted provided that the following conditions
13 1.1 cgd * are met:
14 1.1 cgd * 1. Redistributions of source code must retain the above copyright
15 1.1 cgd * notice, this list of conditions and the following disclaimer.
16 1.1 cgd * 2. Redistributions in binary form must reproduce the above copyright
17 1.1 cgd * notice, this list of conditions and the following disclaimer in the
18 1.1 cgd * documentation and/or other materials provided with the distribution.
19 1.1 cgd * 3. All advertising materials mentioning features or use of this software
20 1.1 cgd * must display the following acknowledgement:
21 1.1 cgd * This product includes software developed by the University of
22 1.1 cgd * California, Berkeley and its contributors.
23 1.1 cgd * 4. Neither the name of the University nor the names of its contributors
24 1.1 cgd * may be used to endorse or promote products derived from this software
25 1.1 cgd * without specific prior written permission.
26 1.1 cgd *
27 1.1 cgd * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
28 1.1 cgd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
29 1.1 cgd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
30 1.1 cgd * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
31 1.1 cgd * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
32 1.1 cgd * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
33 1.1 cgd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
34 1.1 cgd * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
35 1.1 cgd * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
36 1.1 cgd * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
37 1.1 cgd * SUCH DAMAGE.
38 1.1 cgd */
39 1.1 cgd
40 1.1 cgd #if defined(LIBC_SCCS) && !defined(lint)
41 1.8 thorpej #if 0
42 1.1 cgd static char sccsid[] = "@(#)kvm_sparc.c 8.1 (Berkeley) 6/4/93";
43 1.8 thorpej #else
44 1.9 cgd static char *rcsid = "$NetBSD: kvm_sparc.c,v 1.9 1996/04/01 19:23:03 cgd Exp $";
45 1.8 thorpej #endif
46 1.1 cgd #endif /* LIBC_SCCS and not lint */
47 1.1 cgd
48 1.1 cgd /*
49 1.1 cgd * Sparc machine dependent routines for kvm. Hopefully, the forthcoming
50 1.1 cgd * vm code will one day obsolete this module.
51 1.1 cgd */
52 1.1 cgd
53 1.1 cgd #include <sys/param.h>
54 1.1 cgd #include <sys/user.h>
55 1.1 cgd #include <sys/proc.h>
56 1.1 cgd #include <sys/stat.h>
57 1.4 deraadt #include <sys/sysctl.h>
58 1.7 pk #include <sys/device.h>
59 1.1 cgd #include <unistd.h>
60 1.1 cgd #include <nlist.h>
61 1.1 cgd #include <kvm.h>
62 1.1 cgd
63 1.1 cgd #include <vm/vm.h>
64 1.1 cgd #include <vm/vm_param.h>
65 1.7 pk #include <machine/autoconf.h>
66 1.1 cgd
67 1.1 cgd #include <limits.h>
68 1.1 cgd #include <db.h>
69 1.1 cgd
70 1.1 cgd #include "kvm_private.h"
71 1.1 cgd
72 1.7 pk #define MA_SIZE 32 /* XXX */
73 1.1 cgd struct vmstate {
74 1.7 pk struct {
75 1.9 cgd int x_seginval; /* [sun4/sun4c] only */
76 1.7 pk int x_npmemarr;
77 1.7 pk struct memarr x_pmemarr[MA_SIZE];
78 1.7 pk struct segmap x_segmap_store[NKREG*NSEGRG];
79 1.7 pk } x;
80 1.7 pk #define seginval x.x_seginval
81 1.7 pk #define npmemarr x.x_npmemarr
82 1.7 pk #define pmemarr x.x_pmemarr
83 1.7 pk #define segmap_store x.x_segmap_store
84 1.9 cgd int *pte; /* [sun4/sun4c] only */
85 1.1 cgd };
86 1.7 pk #define NPMEG(vm) ((vm)->seginval+1)
87 1.1 cgd
88 1.4 deraadt static int cputyp = -1;
89 1.3 deraadt
90 1.3 deraadt static int pgshift, nptesg;
91 1.3 deraadt
92 1.9 cgd #define VA_VPG(va) ((cputyp == CPU_SUN4C || cputyp == CPU_SUN4M) \
93 1.9 cgd ? VA_SUN4C_VPG(va) \
94 1.9 cgd : VA_SUN4_VPG(va))
95 1.4 deraadt
96 1.9 cgd static int _kvm_mustinit __P((kvm_t *));
97 1.9 cgd
98 1.9 cgd #if 0
99 1.9 cgd static int
100 1.9 cgd getcputyp()
101 1.9 cgd {
102 1.9 cgd int mib[2];
103 1.9 cgd size_t size;
104 1.9 cgd
105 1.9 cgd mib[0] = CTL_HW;
106 1.9 cgd mib[1] = HW_CLASS;
107 1.9 cgd size = sizeof cputyp;
108 1.9 cgd if (sysctl(mib, 2, &cputyp, &size, NULL, 0) == -1)
109 1.9 cgd return (-1);
110 1.9 cgd }
111 1.9 cgd #endif
112 1.9 cgd
113 1.9 cgd static int
114 1.4 deraadt _kvm_mustinit(kd)
115 1.3 deraadt kvm_t *kd;
116 1.3 deraadt {
117 1.9 cgd static struct nlist nlist[2] = {
118 1.9 cgd # define X_CPUTYP 0
119 1.9 cgd { "_cputyp" },
120 1.9 cgd { NULL },
121 1.9 cgd };
122 1.9 cgd off_t foff;
123 1.9 cgd
124 1.4 deraadt if (cputyp != -1)
125 1.9 cgd return 0;
126 1.9 cgd
127 1.3 deraadt for (pgshift = 12; (1 << pgshift) != kd->nbpg; pgshift++)
128 1.3 deraadt ;
129 1.3 deraadt nptesg = NBPSG / kd->nbpg;
130 1.4 deraadt
131 1.9 cgd if (kvm_nlist(kd, nlist) != 0) {
132 1.9 cgd _kvm_err(kd, kd->program, "cannot find `cputyp' symbol");
133 1.9 cgd return (-1);
134 1.9 cgd }
135 1.9 cgd /* Assume kernel mappings are all within first memory bank. */
136 1.9 cgd foff = nlist[X_CPUTYP].n_value - KERNBASE;
137 1.9 cgd if (lseek(kd->pmfd, foff, 0) == -1 ||
138 1.9 cgd read(kd->pmfd, &cputyp, sizeof(cputyp)) < 0) {
139 1.9 cgd _kvm_err(kd, kd->program, "cannot read `cputyp");
140 1.9 cgd return (-1);
141 1.4 deraadt }
142 1.9 cgd if (cputyp != CPU_SUN4 &&
143 1.9 cgd cputyp != CPU_SUN4C &&
144 1.9 cgd cputyp != CPU_SUN4M)
145 1.9 cgd return (-1);
146 1.9 cgd
147 1.9 cgd return (0);
148 1.3 deraadt }
149 1.3 deraadt
150 1.1 cgd void
151 1.1 cgd _kvm_freevtop(kd)
152 1.1 cgd kvm_t *kd;
153 1.1 cgd {
154 1.3 deraadt if (kd->vmst != 0) {
155 1.7 pk if (kd->vmst->pte != 0)
156 1.7 pk free(kd->vmst->pte);
157 1.1 cgd free(kd->vmst);
158 1.4 deraadt kd->vmst = 0;
159 1.3 deraadt }
160 1.1 cgd }
161 1.1 cgd
162 1.7 pk /*
163 1.9 cgd * Translate a kernel virtual address to a physical address using the
164 1.9 cgd * mapping information in kd->vm. Returns the result in pa, and returns
165 1.9 cgd * the number of bytes that are contiguously available from this
166 1.9 cgd * physical address. This routine is used only for crashdumps.
167 1.9 cgd */
168 1.9 cgd int
169 1.9 cgd _kvm_kvatop(kd, va, pa)
170 1.9 cgd kvm_t *kd;
171 1.9 cgd u_long va;
172 1.9 cgd u_long *pa;
173 1.9 cgd {
174 1.9 cgd if (_kvm_mustinit(kd) != 0)
175 1.9 cgd return (-1);
176 1.9 cgd
177 1.9 cgd return ((cputyp == CPU_SUN4M)
178 1.9 cgd ? _kvm_kvatop4m(kd, va, pa)
179 1.9 cgd : _kvm_kvatop44c(kd, va, pa));
180 1.9 cgd }
181 1.9 cgd
182 1.9 cgd /*
183 1.7 pk * Prepare for translation of kernel virtual addresses into offsets
184 1.7 pk * into crash dump files. We use the MMU specific goop written at the
185 1.7 pk * and of crash dump by pmap_dumpmmu().
186 1.7 pk * (note: sun4/sun4c 2-level MMU specific)
187 1.7 pk */
188 1.1 cgd int
189 1.1 cgd _kvm_initvtop(kd)
190 1.1 cgd kvm_t *kd;
191 1.1 cgd {
192 1.9 cgd if (_kvm_mustinit(kd) != 0)
193 1.9 cgd return (-1);
194 1.9 cgd
195 1.9 cgd return ((cputyp == CPU_SUN4M)
196 1.9 cgd ? _kvm_initvtop4m(kd)
197 1.9 cgd : _kvm_initvtop44c(kd));
198 1.9 cgd }
199 1.9 cgd
200 1.9 cgd #define VA_OFF(va) (va & (kd->nbpg - 1))
201 1.9 cgd
202 1.9 cgd
203 1.9 cgd /*
204 1.9 cgd * We use the MMU specific goop written at the end of crash dump
205 1.9 cgd * by pmap_dumpmmu().
206 1.9 cgd * (note: sun4 3-level MMU not yet supported)
207 1.9 cgd */
208 1.9 cgd int
209 1.9 cgd _kvm_initvtop44c(kd)
210 1.9 cgd kvm_t *kd;
211 1.9 cgd {
212 1.9 cgd register struct vmstate *vm;
213 1.1 cgd register int i;
214 1.9 cgd off_t foff;
215 1.1 cgd struct stat st;
216 1.1 cgd
217 1.7 pk if ((vm = kd->vmst) == 0) {
218 1.7 pk kd->vmst = vm = (struct vmstate *)_kvm_malloc(kd, sizeof(*vm));
219 1.7 pk if (vm == 0)
220 1.4 deraadt return (-1);
221 1.4 deraadt }
222 1.1 cgd
223 1.1 cgd if (fstat(kd->pmfd, &st) < 0)
224 1.1 cgd return (-1);
225 1.1 cgd /*
226 1.1 cgd * Read segment table.
227 1.1 cgd */
228 1.7 pk
229 1.9 cgd foff = st.st_size - roundup(sizeof(vm->x), kd->nbpg);
230 1.1 cgd errno = 0;
231 1.9 cgd if (lseek(kd->pmfd, (off_t)foff, 0) == -1 && errno != 0 ||
232 1.7 pk read(kd->pmfd, (char *)&vm->x, sizeof(vm->x)) < 0) {
233 1.1 cgd _kvm_err(kd, kd->program, "cannot read segment map");
234 1.1 cgd return (-1);
235 1.1 cgd }
236 1.7 pk
237 1.7 pk vm->pte = (int *)_kvm_malloc(kd, NPMEG(vm) * nptesg * sizeof(int));
238 1.7 pk if (vm->pte == 0) {
239 1.7 pk free(kd->vmst);
240 1.7 pk kd->vmst = 0;
241 1.7 pk return (-1);
242 1.7 pk }
243 1.7 pk
244 1.1 cgd /*
245 1.1 cgd * Read PMEGs.
246 1.1 cgd */
247 1.9 cgd foff = st.st_size - roundup(sizeof(vm->x), kd->nbpg) -
248 1.7 pk roundup(NPMEG(vm) * nptesg * sizeof(int), kd->nbpg);
249 1.7 pk
250 1.1 cgd errno = 0;
251 1.9 cgd if (lseek(kd->pmfd, foff, 0) == -1 && errno != 0 ||
252 1.7 pk read(kd->pmfd, (char *)vm->pte, NPMEG(vm) * nptesg * sizeof(int)) < 0) {
253 1.1 cgd _kvm_err(kd, kd->program, "cannot read PMEG table");
254 1.1 cgd return (-1);
255 1.1 cgd }
256 1.3 deraadt
257 1.1 cgd return (0);
258 1.1 cgd }
259 1.1 cgd
260 1.1 cgd int
261 1.9 cgd _kvm_kvatop44c(kd, va, pa)
262 1.1 cgd kvm_t *kd;
263 1.1 cgd u_long va;
264 1.1 cgd u_long *pa;
265 1.1 cgd {
266 1.7 pk register int vr, vs, pte, off, nmem;
267 1.7 pk register struct vmstate *vm = kd->vmst;
268 1.7 pk struct regmap *rp;
269 1.7 pk struct segmap *sp;
270 1.7 pk struct memarr *mp;
271 1.1 cgd
272 1.7 pk if (va < KERNBASE)
273 1.7 pk goto err;
274 1.7 pk
275 1.7 pk vr = VA_VREG(va);
276 1.7 pk vs = VA_VSEG(va);
277 1.1 cgd
278 1.7 pk sp = &vm->segmap_store[(vr-NUREG)*NSEGRG + vs];
279 1.7 pk if (sp->sg_npte == 0)
280 1.7 pk goto err;
281 1.7 pk if (sp->sg_pmeg == vm->seginval)
282 1.7 pk goto err;
283 1.7 pk pte = vm->pte[sp->sg_pmeg * nptesg + VA_VPG(va)];
284 1.7 pk if ((pte & PG_V) != 0) {
285 1.7 pk register long p, dumpoff = 0;
286 1.7 pk
287 1.7 pk off = VA_OFF(va);
288 1.7 pk p = (pte & PG_PFNUM) << pgshift;
289 1.7 pk /* Translate (sparse) pfnum to (packed) dump offset */
290 1.7 pk for (mp = vm->pmemarr, nmem = vm->npmemarr; --nmem >= 0; mp++) {
291 1.7 pk if (mp->addr <= p && p < mp->addr + mp->len)
292 1.7 pk break;
293 1.7 pk dumpoff += mp->len;
294 1.1 cgd }
295 1.7 pk if (nmem < 0)
296 1.7 pk goto err;
297 1.7 pk *pa = (dumpoff + p - mp->addr) | off;
298 1.7 pk return (kd->nbpg - off);
299 1.1 cgd }
300 1.7 pk err:
301 1.1 cgd _kvm_err(kd, 0, "invalid address (%x)", va);
302 1.1 cgd return (0);
303 1.1 cgd }
304 1.4 deraadt
305 1.9 cgd /*
306 1.9 cgd * Prepare for translation of kernel virtual addresses into offsets
307 1.9 cgd * into crash dump files. Since the sun4m pagetables are all in memory,
308 1.9 cgd * we use nlist to bootstrap the translation tables. This assumes that
309 1.9 cgd * the kernel mappings all reside in the first physical memory bank.
310 1.9 cgd */
311 1.9 cgd int
312 1.9 cgd _kvm_initvtop4m(kd)
313 1.9 cgd kvm_t *kd;
314 1.4 deraadt {
315 1.9 cgd register int i;
316 1.9 cgd register off_t foff;
317 1.9 cgd register struct vmstate *vm;
318 1.9 cgd struct stat st;
319 1.9 cgd static struct nlist nlist[4] = {
320 1.9 cgd # define X_KSEGSTORE 0
321 1.9 cgd { "_kernel_segmap_store" },
322 1.9 cgd # define X_PMEMARR 1
323 1.9 cgd { "_pmemarr" },
324 1.9 cgd # define X_NPMEMARR 2
325 1.9 cgd { "_npmemarr" },
326 1.9 cgd { NULL },
327 1.9 cgd };
328 1.9 cgd
329 1.9 cgd if ((vm = kd->vmst) == 0) {
330 1.9 cgd kd->vmst = vm = (struct vmstate *)_kvm_malloc(kd, sizeof(*vm));
331 1.9 cgd if (vm == 0)
332 1.9 cgd return (-1);
333 1.9 cgd }
334 1.9 cgd
335 1.9 cgd if (kvm_nlist(kd, nlist) != 0) {
336 1.9 cgd _kvm_err(kd, kd->program, "cannot read symbols");
337 1.9 cgd return (-1);
338 1.9 cgd }
339 1.9 cgd
340 1.9 cgd /* Assume kernel mappings are all within first memory bank. */
341 1.9 cgd foff = nlist[X_KSEGSTORE].n_value - KERNBASE;
342 1.9 cgd if (lseek(kd->pmfd, foff, 0) == -1 ||
343 1.9 cgd read(kd->pmfd, vm->segmap_store, sizeof(vm->segmap_store)) < 0) {
344 1.9 cgd _kvm_err(kd, kd->program, "cannot read segment map");
345 1.9 cgd return (-1);
346 1.9 cgd }
347 1.9 cgd
348 1.9 cgd foff = nlist[X_PMEMARR].n_value - KERNBASE;
349 1.9 cgd if (lseek(kd->pmfd, foff, 0) == -1 ||
350 1.9 cgd read(kd->pmfd, vm->pmemarr, sizeof(vm->pmemarr)) < 0) {
351 1.9 cgd _kvm_err(kd, kd->program, "cannot read pmemarr");
352 1.9 cgd return (-1);
353 1.9 cgd }
354 1.4 deraadt
355 1.9 cgd foff = nlist[X_NPMEMARR].n_value - KERNBASE;
356 1.9 cgd if (lseek(kd->pmfd, foff, 0) == -1 ||
357 1.9 cgd read(kd->pmfd, &vm->npmemarr, sizeof(vm->npmemarr)) < 0) {
358 1.9 cgd _kvm_err(kd, kd->program, "cannot read npmemarr");
359 1.4 deraadt return (-1);
360 1.9 cgd }
361 1.9 cgd
362 1.9 cgd return (0);
363 1.9 cgd }
364 1.9 cgd
365 1.9 cgd int
366 1.9 cgd _kvm_kvatop4m(kd, va, pa)
367 1.9 cgd kvm_t *kd;
368 1.9 cgd u_long va;
369 1.9 cgd u_long *pa;
370 1.9 cgd {
371 1.9 cgd register struct vmstate *vm = kd->vmst;
372 1.9 cgd register int vr, vs, nmem, off;
373 1.9 cgd int pte;
374 1.9 cgd off_t foff;
375 1.9 cgd struct regmap *rp;
376 1.9 cgd struct segmap *sp;
377 1.9 cgd struct memarr *mp;
378 1.9 cgd
379 1.9 cgd if (va < KERNBASE)
380 1.9 cgd goto err;
381 1.9 cgd
382 1.9 cgd vr = VA_VREG(va);
383 1.9 cgd vs = VA_VSEG(va);
384 1.9 cgd
385 1.9 cgd sp = &vm->segmap_store[(vr-NUREG)*NSEGRG + vs];
386 1.9 cgd if (sp->sg_npte == 0)
387 1.9 cgd goto err;
388 1.9 cgd
389 1.9 cgd /* Assume kernel mappings are all within first memory bank. */
390 1.9 cgd foff = (long)&sp->sg_pte[VA_VPG(va)] - KERNBASE;
391 1.9 cgd if (lseek(kd->pmfd, foff, 0) == -1 ||
392 1.9 cgd read(kd->pmfd, (void *)&pte, sizeof(pte)) < 0) {
393 1.9 cgd _kvm_err(kd, kd->program, "cannot read pte");
394 1.9 cgd goto err;
395 1.9 cgd }
396 1.9 cgd
397 1.9 cgd if ((pte & SRMMU_TETYPE) == SRMMU_TEPTE) {
398 1.9 cgd register long p, dumpoff = 0;
399 1.9 cgd
400 1.9 cgd off = VA_OFF(va);
401 1.9 cgd p = (pte & SRMMU_PPNMASK) << SRMMU_PPNPASHIFT;
402 1.9 cgd /* Translate (sparse) pfnum to (packed) dump offset */
403 1.9 cgd for (mp = vm->pmemarr, nmem = vm->npmemarr; --nmem >= 0; mp++) {
404 1.9 cgd if (mp->addr <= p && p < mp->addr + mp->len)
405 1.9 cgd break;
406 1.9 cgd dumpoff += mp->len;
407 1.9 cgd }
408 1.9 cgd if (nmem < 0)
409 1.9 cgd goto err;
410 1.9 cgd *pa = (dumpoff + p - mp->addr) | off;
411 1.9 cgd return (kd->nbpg - off);
412 1.9 cgd }
413 1.9 cgd err:
414 1.9 cgd _kvm_err(kd, 0, "invalid address (%x)", va);
415 1.9 cgd return (0);
416 1.4 deraadt }
417