1*104ea677Schristos /* $NetBSD: kvm_sparc.c,v 1.36 2022/01/10 19:51:30 christos Exp $ */
2346e67f8Sthorpej
30215cc7dScgd /*-
40215cc7dScgd * Copyright (c) 1992, 1993
50215cc7dScgd * The Regents of the University of California. All rights reserved.
60215cc7dScgd *
70215cc7dScgd * This code is derived from software developed by the Computer Systems
80215cc7dScgd * Engineering group at Lawrence Berkeley Laboratory under DARPA contract
90215cc7dScgd * BG 91-66 and contributed to Berkeley.
100215cc7dScgd *
110215cc7dScgd * Redistribution and use in source and binary forms, with or without
120215cc7dScgd * modification, are permitted provided that the following conditions
130215cc7dScgd * are met:
140215cc7dScgd * 1. Redistributions of source code must retain the above copyright
150215cc7dScgd * notice, this list of conditions and the following disclaimer.
160215cc7dScgd * 2. Redistributions in binary form must reproduce the above copyright
170215cc7dScgd * notice, this list of conditions and the following disclaimer in the
180215cc7dScgd * documentation and/or other materials provided with the distribution.
19eb7c1594Sagc * 3. Neither the name of the University nor the names of its contributors
200215cc7dScgd * may be used to endorse or promote products derived from this software
210215cc7dScgd * without specific prior written permission.
220215cc7dScgd *
230215cc7dScgd * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
240215cc7dScgd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
250215cc7dScgd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
260215cc7dScgd * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
270215cc7dScgd * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
280215cc7dScgd * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
290215cc7dScgd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
300215cc7dScgd * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
310215cc7dScgd * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
320215cc7dScgd * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
330215cc7dScgd * SUCH DAMAGE.
340215cc7dScgd */
350215cc7dScgd
36b4119f6bSmikel #include <sys/cdefs.h>
370215cc7dScgd #if defined(LIBC_SCCS) && !defined(lint)
38346e67f8Sthorpej #if 0
390215cc7dScgd static char sccsid[] = "@(#)kvm_sparc.c 8.1 (Berkeley) 6/4/93";
40346e67f8Sthorpej #else
41*104ea677Schristos __RCSID("$NetBSD: kvm_sparc.c,v 1.36 2022/01/10 19:51:30 christos Exp $");
42346e67f8Sthorpej #endif
430215cc7dScgd #endif /* LIBC_SCCS and not lint */
440215cc7dScgd
450215cc7dScgd /*
460215cc7dScgd * Sparc machine dependent routines for kvm. Hopefully, the forthcoming
470215cc7dScgd * vm code will one day obsolete this module.
480215cc7dScgd */
490215cc7dScgd
500215cc7dScgd #include <sys/param.h>
517dad7db4Spk #include <sys/exec.h>
520215cc7dScgd #include <sys/proc.h>
530215cc7dScgd #include <sys/stat.h>
549cb162ceSpk #include <sys/core.h>
559cb162ceSpk #include <sys/kcore.h>
560215cc7dScgd #include <unistd.h>
570215cc7dScgd #include <nlist.h>
580215cc7dScgd #include <kvm.h>
590215cc7dScgd
603b8ac18dSmrg #include <uvm/uvm_extern.h>
6110a6db97Smrg
62ed79731bSmrg #include <sparc/pmap.h>
63ed79731bSmrg #include <sparc/kcore.h>
640215cc7dScgd
650215cc7dScgd #include <limits.h>
660215cc7dScgd #include <db.h>
670215cc7dScgd
680215cc7dScgd #include "kvm_private.h"
690215cc7dScgd
700215cc7dScgd
7112e0db7fSderaadt static int cputyp = -1;
729cb162ceSpk static int pgshift;
739cb162ceSpk static int nptesg; /* [sun4/sun4c] only */
74fdf894abSderaadt
7588199bcbSmrg #undef VA_VPG
7682501b60Scgd #define VA_VPG(va) ((cputyp == CPU_SUN4C || cputyp == CPU_SUN4M) \
7782501b60Scgd ? VA_SUN4C_VPG(va) \
7882501b60Scgd : VA_SUN4_VPG(va))
7912e0db7fSderaadt
8088199bcbSmrg #undef VA_OFF
819cb162ceSpk #define VA_OFF(va) (va & (kd->nbpg - 1))
8282501b60Scgd
83962a341dSjym int _kvm_kvatop44c(kvm_t *, vaddr_t, paddr_t *);
84962a341dSjym int _kvm_kvatop4m (kvm_t *, vaddr_t, paddr_t *);
85962a341dSjym int _kvm_kvatop4u (kvm_t *, vaddr_t, paddr_t *);
862998626fSmrg
872998626fSmrg /*
882998626fSmrg * XXX
892998626fSmrg * taken from /sys/arch/sparc64/include/kcore.h.
902998626fSmrg * this is the same as the sparc one, except for the kphys addition,
912998626fSmrg * so luckily we can use this here...
922998626fSmrg */
932998626fSmrg typedef struct sparc64_cpu_kcore_hdr {
942998626fSmrg int cputype; /* CPU type associated with this dump */
952998626fSmrg u_long kernbase; /* copy of KERNBASE goes here */
962998626fSmrg int nmemseg; /* # of physical memory segments */
972998626fSmrg u_long memsegoffset; /* start of memseg array (relative */
982998626fSmrg /* to the start of this header) */
992998626fSmrg int nsegmap; /* # of segmaps following */
1002998626fSmrg u_long segmapoffset; /* start of segmap array (relative */
1012998626fSmrg /* to the start of this header) */
1022998626fSmrg int npmeg; /* # of PMEGs; [sun4/sun4c] only */
1032998626fSmrg u_long pmegoffset; /* start of pmeg array (relative */
1042998626fSmrg /* to the start of this header) */
1052998626fSmrg /* SPARC64 stuff */
1062998626fSmrg paddr_t kphys; /* Physical address of 4MB locked TLB */
1072998626fSmrg } sparc64_cpu_kcore_hdr_t;
108fdf894abSderaadt
1090215cc7dScgd void
_kvm_freevtop(kvm_t * kd)1106dc46b92Sjym _kvm_freevtop(kvm_t *kd)
1110215cc7dScgd {
112fdf894abSderaadt if (kd->vmst != 0) {
1139cb162ceSpk _kvm_err(kd, kd->program, "_kvm_freevtop: internal error");
11412e0db7fSderaadt kd->vmst = 0;
1150215cc7dScgd }
116fdf894abSderaadt }
1170215cc7dScgd
11816e30a94Spk /*
1199cb162ceSpk * Prepare for translation of kernel virtual addresses into offsets
1209cb162ceSpk * into crash dump files. We use the MMU specific goop written at the
1219cb162ceSpk * front of the crash dump by pmap_dumpmmu().
1229cb162ceSpk */
1239cb162ceSpk int
_kvm_initvtop(kvm_t * kd)1246dc46b92Sjym _kvm_initvtop(kvm_t *kd)
1259cb162ceSpk {
1262998626fSmrg sparc64_cpu_kcore_hdr_t *cpup = kd->cpu_data;
1279cb162ceSpk
1289cb162ceSpk switch (cputyp = cpup->cputype) {
1299cb162ceSpk case CPU_SUN4:
130d2aa2f50Seeh case CPU_SUN4U:
1319cb162ceSpk kd->nbpg = 8196;
1329cb162ceSpk pgshift = 13;
1339cb162ceSpk break;
1349cb162ceSpk case CPU_SUN4C:
1359cb162ceSpk case CPU_SUN4M:
1369cb162ceSpk kd->nbpg = 4096;
1379cb162ceSpk pgshift = 12;
1389cb162ceSpk break;
1399cb162ceSpk default:
1409cb162ceSpk _kvm_err(kd, kd->program, "Unsupported CPU type");
1419cb162ceSpk return (-1);
1429cb162ceSpk }
1439cb162ceSpk nptesg = NBPSG / kd->nbpg;
1449cb162ceSpk return (0);
1459cb162ceSpk }
1469cb162ceSpk
1479cb162ceSpk /*
14882501b60Scgd * Translate a kernel virtual address to a physical address using the
14982501b60Scgd * mapping information in kd->vm. Returns the result in pa, and returns
15082501b60Scgd * the number of bytes that are contiguously available from this
15182501b60Scgd * physical address. This routine is used only for crash dumps.
15282501b60Scgd */
15382501b60Scgd int
_kvm_kvatop(kvm_t * kd,vaddr_t va,paddr_t * pa)154962a341dSjym _kvm_kvatop(kvm_t *kd, vaddr_t va, paddr_t *pa)
15582501b60Scgd {
1569cb162ceSpk if (cputyp == -1)
1579cb162ceSpk if (_kvm_initvtop(kd) != 0)
15882501b60Scgd return (-1);
15982501b60Scgd
160d2aa2f50Seeh switch (cputyp) {
161d2aa2f50Seeh case CPU_SUN4:
162d2aa2f50Seeh case CPU_SUN4C:
163d2aa2f50Seeh return _kvm_kvatop44c(kd, va, pa);
164d2aa2f50Seeh break;
165d2aa2f50Seeh case CPU_SUN4M:
166d2aa2f50Seeh return _kvm_kvatop4m(kd, va, pa);
167d2aa2f50Seeh break;
168d2aa2f50Seeh case CPU_SUN4U:
169d2aa2f50Seeh default:
170d2aa2f50Seeh return _kvm_kvatop4u(kd, va, pa);
171d2aa2f50Seeh }
17282501b60Scgd }
17382501b60Scgd
17482501b60Scgd /*
17582501b60Scgd * (note: sun4 3-level MMU not yet supported)
17682501b60Scgd */
17782501b60Scgd int
_kvm_kvatop44c(kvm_t * kd,vaddr_t va,paddr_t * pa)178962a341dSjym _kvm_kvatop44c(kvm_t *kd, vaddr_t va, paddr_t *pa)
1790215cc7dScgd {
1800b7831a3Sperry int vr, vs, pte;
1812998626fSmrg sparc64_cpu_kcore_hdr_t *cpup = kd->cpu_data;
1827dad7db4Spk struct segmap *sp, *segmaps;
1839cb162ceSpk int *ptes;
1847dad7db4Spk int nkreg, nureg;
1857dad7db4Spk u_long kernbase = cpup->kernbase;
1860215cc7dScgd
1877dad7db4Spk if (va < kernbase)
18816e30a94Spk goto err;
1890215cc7dScgd
1909cb162ceSpk /*
1919cb162ceSpk * Layout of CPU segment:
1929cb162ceSpk * cpu_kcore_hdr_t;
1939cb162ceSpk * [alignment]
1949cb162ceSpk * phys_ram_seg_t[cpup->nmemseg];
1957dad7db4Spk * segmap[cpup->nsegmap];
1969cb162ceSpk * ptes[cpup->npmegs];
1979cb162ceSpk */
1987dad7db4Spk segmaps = (struct segmap *)((long)kd->cpu_data + cpup->segmapoffset);
1999cb162ceSpk ptes = (int *)((int)kd->cpu_data + cpup->pmegoffset);
2007dad7db4Spk nkreg = ((int)((-(unsigned)kernbase) / NBPRG));
2017dad7db4Spk nureg = 256 - nkreg;
2029cb162ceSpk
20316e30a94Spk vr = VA_VREG(va);
20416e30a94Spk vs = VA_VSEG(va);
20516e30a94Spk
2067dad7db4Spk sp = &segmaps[(vr-nureg)*NSEGRG + vs];
20716e30a94Spk if (sp->sg_npte == 0)
20816e30a94Spk goto err;
2090b0b9b77Spk if (sp->sg_pmeg == cpup->npmeg - 1) /* =seginval */
21016e30a94Spk goto err;
2119cb162ceSpk pte = ptes[sp->sg_pmeg * nptesg + VA_VPG(va)];
21216e30a94Spk if ((pte & PG_V) != 0) {
213962a341dSjym paddr_t p, off = VA_OFF(va);
21416e30a94Spk
21516e30a94Spk p = (pte & PG_PFNUM) << pgshift;
2169cb162ceSpk *pa = p + off;
217fdf894abSderaadt return (kd->nbpg - off);
2180215cc7dScgd }
21916e30a94Spk err:
220962a341dSjym _kvm_err(kd, 0, "invalid address (%#"PRIxVADDR")", va);
2210215cc7dScgd return (0);
2220215cc7dScgd }
22312e0db7fSderaadt
22482501b60Scgd int
_kvm_kvatop4m(kvm_t * kd,vaddr_t va,paddr_t * pa)225962a341dSjym _kvm_kvatop4m(kvm_t *kd, vaddr_t va, paddr_t *pa)
22682501b60Scgd {
2272998626fSmrg sparc64_cpu_kcore_hdr_t *cpup = kd->cpu_data;
2280b7831a3Sperry int vr, vs;
22982501b60Scgd int pte;
23082501b60Scgd off_t foff;
2317dad7db4Spk struct segmap *sp, *segmaps;
2327dad7db4Spk int nkreg, nureg;
2337dad7db4Spk u_long kernbase = cpup->kernbase;
23482501b60Scgd
2357dad7db4Spk if (va < kernbase)
23682501b60Scgd goto err;
23782501b60Scgd
2389cb162ceSpk /*
2399cb162ceSpk * Layout of CPU segment:
2409cb162ceSpk * cpu_kcore_hdr_t;
2419cb162ceSpk * [alignment]
2429cb162ceSpk * phys_ram_seg_t[cpup->nmemseg];
2437dad7db4Spk * segmap[cpup->nsegmap];
2449cb162ceSpk */
2457dad7db4Spk segmaps = (struct segmap *)((long)kd->cpu_data + cpup->segmapoffset);
2467dad7db4Spk nkreg = ((int)((-(unsigned)kernbase) / NBPRG));
2477dad7db4Spk nureg = 256 - nkreg;
2489cb162ceSpk
24982501b60Scgd vr = VA_VREG(va);
25082501b60Scgd vs = VA_VSEG(va);
25182501b60Scgd
2527dad7db4Spk sp = &segmaps[(vr-nureg)*NSEGRG + vs];
25382501b60Scgd if (sp->sg_npte == 0)
25482501b60Scgd goto err;
25582501b60Scgd
2569cb162ceSpk /* XXX - assume page tables in initial kernel DATA or BSS. */
2577dad7db4Spk foff = _kvm_pa2off(kd, (u_long)&sp->sg_pte[VA_VPG(va)] - kernbase);
2589cb162ceSpk if (foff == (off_t)-1)
2599cb162ceSpk return (0);
2609cb162ceSpk
261a7a2d171Sad if (_kvm_pread(kd, kd->pmfd, &pte, sizeof(pte), foff) != sizeof(pte)) {
262962a341dSjym _kvm_syserr(kd, kd->program, "cannot read pte for "
263962a341dSjym "%#" PRIxVADDR, va);
2649cb162ceSpk return (0);
26582501b60Scgd }
26682501b60Scgd
26782501b60Scgd if ((pte & SRMMU_TETYPE) == SRMMU_TEPTE) {
2680b7831a3Sperry long p, off = VA_OFF(va);
26982501b60Scgd
27082501b60Scgd p = (pte & SRMMU_PPNMASK) << SRMMU_PPNPASHIFT;
2719cb162ceSpk *pa = p + off;
27282501b60Scgd return (kd->nbpg - off);
27382501b60Scgd }
27482501b60Scgd err:
275962a341dSjym _kvm_err(kd, 0, "invalid address (%#"PRIxVADDR")", va);
27682501b60Scgd return (0);
27782501b60Scgd }
2789cb162ceSpk
2799cb162ceSpk /*
2802998626fSmrg * sparc64 pmap's 32-bit page table format
281d2aa2f50Seeh */
282d2aa2f50Seeh int
_kvm_kvatop4u(kvm_t * kd,vaddr_t va,paddr_t * pa)283962a341dSjym _kvm_kvatop4u(kvm_t *kd, vaddr_t va, paddr_t *pa)
284d2aa2f50Seeh {
2852998626fSmrg sparc64_cpu_kcore_hdr_t *cpup = kd->cpu_data;
286d2aa2f50Seeh int64_t **segmaps;
287d2aa2f50Seeh int64_t *ptes;
288d2aa2f50Seeh int64_t pte;
289d2aa2f50Seeh int64_t kphys = cpup->kphys;
2902998626fSmrg u_long kernbase = cpup->kernbase;
291d2aa2f50Seeh
292d2aa2f50Seeh if (va < kernbase)
293d2aa2f50Seeh goto err;
294d2aa2f50Seeh
295d2aa2f50Seeh /*
296d2aa2f50Seeh * Kernel layout:
297d2aa2f50Seeh *
298d2aa2f50Seeh * kernbase:
299d2aa2f50Seeh * 4MB locked TLB (text+data+BSS)
300d2aa2f50Seeh * Random other stuff.
301d2aa2f50Seeh */
3022998626fSmrg if (va >= kernbase && va < kernbase + 4*1024*1024)
303d2aa2f50Seeh return (va - kernbase) + kphys;
304d2aa2f50Seeh
3052998626fSmrg /* XXX: from sparc64/include/pmap.h */
3062998626fSmrg #define SPARC64_PTSZ (kd->nbpg/8)
3072998626fSmrg #define SPARC64_STSZ (SPARC64_PTSZ)
3082998626fSmrg #define SPARC64_PTMASK (SPARC64_PTSZ-1)
3092998626fSmrg #define SPARC64_PTSHIFT (13)
3102998626fSmrg #define SPARC64_PDSHIFT (10+SPARC64_PTSHIFT)
3112998626fSmrg #define SPARC64_STSHIFT (10+SPARC64_PDSHIFT)
3122998626fSmrg #define SPARC64_STMASK (SPARC64_STSZ-1)
3132998626fSmrg #define sparc64_va_to_seg(v) (int)((((int64_t)(v))>>SPARC64_STSHIFT)&SPARC64_STMASK)
3142998626fSmrg #define sparc64_va_to_pte(v) (int)((((int64_t)(v))>>SPARC64_PTSHIFT)&SPARC64_PTMASK)
3152998626fSmrg
3162998626fSmrg /* XXX: from sparc64/include/pte.h */
3172998626fSmrg #define SPARC64_TLB_V 0x8000000000000000LL
3182998626fSmrg #define SPARC64_TLB_PA_MASK 0x000001ffffffe000LL
3192998626fSmrg
320d2aa2f50Seeh /*
321d2aa2f50Seeh * Layout of CPU segment:
322d2aa2f50Seeh * cpu_kcore_hdr_t;
323d2aa2f50Seeh * [alignment]
324d2aa2f50Seeh * phys_ram_seg_t[cpup->nmemseg];
325d2aa2f50Seeh * segmap[cpup->nsegmap];
326d2aa2f50Seeh */
3272998626fSmrg segmaps = (int64_t **)((long)kd->cpu_data + cpup->segmapoffset);
32859db503aSmartin ptes = (int64_t *)(intptr_t)_kvm_pa2off(kd,
32959db503aSmartin (paddr_t)(intptr_t)segmaps[sparc64_va_to_seg(va)]);
3302998626fSmrg pte = ptes[sparc64_va_to_pte(va)];
3312998626fSmrg if ((pte & SPARC64_TLB_V) != 0)
3322998626fSmrg return ((pte & SPARC64_TLB_PA_MASK) | (va & (kd->nbpg - 1)));
333d2aa2f50Seeh err:
334962a341dSjym _kvm_err(kd, 0, "invalid address (%#"PRIxVADDR")", va);
335d2aa2f50Seeh return (0);
336d2aa2f50Seeh }
337d2aa2f50Seeh
338d2aa2f50Seeh
339d2aa2f50Seeh /*
340b976c559Swiz * Translate a physical address to a file-offset in the crash dump.
3419cb162ceSpk */
3429cb162ceSpk off_t
_kvm_pa2off(kvm_t * kd,paddr_t pa)343962a341dSjym _kvm_pa2off(kvm_t *kd, paddr_t pa)
3449cb162ceSpk {
3452998626fSmrg sparc64_cpu_kcore_hdr_t *cpup = kd->cpu_data;
3469cb162ceSpk phys_ram_seg_t *mp;
3479cb162ceSpk off_t off;
3489cb162ceSpk int nmem;
3499cb162ceSpk
3509cb162ceSpk /*
3519cb162ceSpk * Layout of CPU segment:
3529cb162ceSpk * cpu_kcore_hdr_t;
3539cb162ceSpk * [alignment]
3549cb162ceSpk * phys_ram_seg_t[cpup->nmemseg];
3559cb162ceSpk */
3569cb162ceSpk mp = (phys_ram_seg_t *)((int)kd->cpu_data + cpup->memsegoffset);
3579cb162ceSpk off = 0;
3589cb162ceSpk
3599cb162ceSpk /* Translate (sparse) pfnum to (packed) dump offset */
3609cb162ceSpk for (nmem = cpup->nmemseg; --nmem >= 0; mp++) {
3619cb162ceSpk if (mp->start <= pa && pa < mp->start + mp->size)
3629cb162ceSpk break;
3639cb162ceSpk off += mp->size;
3649cb162ceSpk }
3659cb162ceSpk if (nmem < 0) {
36613217c03Snakayama _kvm_err(kd, 0, "invalid address (%#"PRIxPADDR")", pa);
3679cb162ceSpk return (-1);
3689cb162ceSpk }
3699cb162ceSpk
3709cb162ceSpk return (kd->dump_off + off + pa - mp->start);
3719cb162ceSpk }
372f6385749Sgwr
373f6385749Sgwr /*
374f6385749Sgwr * Machine-dependent initialization for ALL open kvm descriptors,
375f6385749Sgwr * not just those for a kernel crash dump. Some architectures
376f6385749Sgwr * have to deal with these NOT being constants! (i.e. m68k)
377f6385749Sgwr */
378f6385749Sgwr int
_kvm_mdopen(kvm_t * kd)3796dc46b92Sjym _kvm_mdopen(kvm_t *kd)
380f6385749Sgwr {
3817dad7db4Spk u_long max_uva;
3827dad7db4Spk extern struct ps_strings *__ps_strings;
383f6385749Sgwr
3847dad7db4Spk max_uva = (u_long) (__ps_strings + 1);
3857dad7db4Spk kd->max_uva = max_uva;
3867dad7db4Spk kd->min_uva = 0;
387f6385749Sgwr
388f6385749Sgwr return (0);
389f6385749Sgwr }
390