1 /* $NetBSD: kvm_sparc.c,v 1.25 2001/08/05 03:33:15 matt 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. All advertising materials mentioning features or use of this software 20 * must display the following acknowledgement: 21 * This product includes software developed by the University of 22 * California, Berkeley and its contributors. 23 * 4. Neither the name of the University nor the names of its contributors 24 * may be used to endorse or promote products derived from this software 25 * without specific prior written permission. 26 * 27 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 28 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 29 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 30 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 31 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 32 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 33 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 34 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 35 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 36 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 37 * SUCH DAMAGE. 38 */ 39 40 #include <sys/cdefs.h> 41 #if defined(LIBC_SCCS) && !defined(lint) 42 #if 0 43 static char sccsid[] = "@(#)kvm_sparc.c 8.1 (Berkeley) 6/4/93"; 44 #else 45 __RCSID("$NetBSD: kvm_sparc.c,v 1.25 2001/08/05 03:33:15 matt Exp $"); 46 #endif 47 #endif /* LIBC_SCCS and not lint */ 48 49 /* 50 * Sparc machine dependent routines for kvm. Hopefully, the forthcoming 51 * vm code will one day obsolete this module. 52 */ 53 54 #include <sys/param.h> 55 #include <sys/exec.h> 56 #include <sys/user.h> 57 #include <sys/proc.h> 58 #include <sys/stat.h> 59 #include <sys/core.h> 60 #include <sys/kcore.h> 61 #include <unistd.h> 62 #include <nlist.h> 63 #include <kvm.h> 64 65 #include <uvm/uvm_extern.h> 66 67 #include <machine/pmap.h> 68 #include <machine/kcore.h> 69 70 #include <limits.h> 71 #include <db.h> 72 73 #include "kvm_private.h" 74 75 76 static int cputyp = -1; 77 static int pgshift; 78 static int nptesg; /* [sun4/sun4c] only */ 79 80 #define VA_VPG(va) ((cputyp == CPU_SUN4C || cputyp == CPU_SUN4M) \ 81 ? VA_SUN4C_VPG(va) \ 82 : VA_SUN4_VPG(va)) 83 84 #define VA_OFF(va) (va & (kd->nbpg - 1)) 85 86 int _kvm_kvatop44c __P((kvm_t *, u_long, u_long *)); 87 int _kvm_kvatop4m __P((kvm_t *, u_long, u_long *)); 88 int _kvm_kvatop4u __P((kvm_t *, u_long, u_long *)); 89 90 /* 91 * XXX 92 * taken from /sys/arch/sparc64/include/kcore.h. 93 * this is the same as the sparc one, except for the kphys addition, 94 * so luckily we can use this here... 95 */ 96 typedef struct sparc64_cpu_kcore_hdr { 97 int cputype; /* CPU type associated with this dump */ 98 u_long kernbase; /* copy of KERNBASE goes here */ 99 int nmemseg; /* # of physical memory segments */ 100 u_long memsegoffset; /* start of memseg array (relative */ 101 /* to the start of this header) */ 102 int nsegmap; /* # of segmaps following */ 103 u_long segmapoffset; /* start of segmap array (relative */ 104 /* to the start of this header) */ 105 int npmeg; /* # of PMEGs; [sun4/sun4c] only */ 106 u_long pmegoffset; /* start of pmeg array (relative */ 107 /* to the start of this header) */ 108 /* SPARC64 stuff */ 109 paddr_t kphys; /* Physical address of 4MB locked TLB */ 110 } sparc64_cpu_kcore_hdr_t; 111 112 void 113 _kvm_freevtop(kd) 114 kvm_t *kd; 115 { 116 if (kd->vmst != 0) { 117 _kvm_err(kd, kd->program, "_kvm_freevtop: internal error"); 118 kd->vmst = 0; 119 } 120 } 121 122 /* 123 * Prepare for translation of kernel virtual addresses into offsets 124 * into crash dump files. We use the MMU specific goop written at the 125 * front of the crash dump by pmap_dumpmmu(). 126 */ 127 int 128 _kvm_initvtop(kd) 129 kvm_t *kd; 130 { 131 sparc64_cpu_kcore_hdr_t *cpup = kd->cpu_data; 132 133 switch (cputyp = cpup->cputype) { 134 case CPU_SUN4: 135 case CPU_SUN4U: 136 kd->nbpg = 8196; 137 pgshift = 13; 138 break; 139 case CPU_SUN4C: 140 case CPU_SUN4M: 141 kd->nbpg = 4096; 142 pgshift = 12; 143 break; 144 default: 145 _kvm_err(kd, kd->program, "Unsupported CPU type"); 146 return (-1); 147 } 148 nptesg = NBPSG / kd->nbpg; 149 return (0); 150 } 151 152 /* 153 * Translate a kernel virtual address to a physical address using the 154 * mapping information in kd->vm. Returns the result in pa, and returns 155 * the number of bytes that are contiguously available from this 156 * physical address. This routine is used only for crashdumps. 157 */ 158 int 159 _kvm_kvatop(kd, va, pa) 160 kvm_t *kd; 161 u_long va; 162 u_long *pa; 163 { 164 if (cputyp == -1) 165 if (_kvm_initvtop(kd) != 0) 166 return (-1); 167 168 switch (cputyp) { 169 case CPU_SUN4: 170 case CPU_SUN4C: 171 return _kvm_kvatop44c(kd, va, pa); 172 break; 173 case CPU_SUN4M: 174 return _kvm_kvatop4m(kd, va, pa); 175 break; 176 case CPU_SUN4U: 177 default: 178 return _kvm_kvatop4u(kd, va, pa); 179 } 180 } 181 182 /* 183 * (note: sun4 3-level MMU not yet supported) 184 */ 185 int 186 _kvm_kvatop44c(kd, va, pa) 187 kvm_t *kd; 188 u_long va; 189 u_long *pa; 190 { 191 int vr, vs, pte; 192 sparc64_cpu_kcore_hdr_t *cpup = kd->cpu_data; 193 struct segmap *sp, *segmaps; 194 int *ptes; 195 int nkreg, nureg; 196 u_long kernbase = cpup->kernbase; 197 198 if (va < kernbase) 199 goto err; 200 201 /* 202 * Layout of CPU segment: 203 * cpu_kcore_hdr_t; 204 * [alignment] 205 * phys_ram_seg_t[cpup->nmemseg]; 206 * segmap[cpup->nsegmap]; 207 * ptes[cpup->npmegs]; 208 */ 209 segmaps = (struct segmap *)((long)kd->cpu_data + cpup->segmapoffset); 210 ptes = (int *)((int)kd->cpu_data + cpup->pmegoffset); 211 nkreg = ((int)((-(unsigned)kernbase) / NBPRG)); 212 nureg = 256 - nkreg; 213 214 vr = VA_VREG(va); 215 vs = VA_VSEG(va); 216 217 sp = &segmaps[(vr-nureg)*NSEGRG + vs]; 218 if (sp->sg_npte == 0) 219 goto err; 220 if (sp->sg_pmeg == cpup->npmeg - 1) /* =seginval */ 221 goto err; 222 pte = ptes[sp->sg_pmeg * nptesg + VA_VPG(va)]; 223 if ((pte & PG_V) != 0) { 224 long p, off = VA_OFF(va); 225 226 p = (pte & PG_PFNUM) << pgshift; 227 *pa = p + off; 228 return (kd->nbpg - off); 229 } 230 err: 231 _kvm_err(kd, 0, "invalid address (%lx)", va); 232 return (0); 233 } 234 235 int 236 _kvm_kvatop4m(kd, va, pa) 237 kvm_t *kd; 238 u_long va; 239 u_long *pa; 240 { 241 sparc64_cpu_kcore_hdr_t *cpup = kd->cpu_data; 242 int vr, vs; 243 int pte; 244 off_t foff; 245 struct segmap *sp, *segmaps; 246 int nkreg, nureg; 247 u_long kernbase = cpup->kernbase; 248 249 if (va < kernbase) 250 goto err; 251 252 /* 253 * Layout of CPU segment: 254 * cpu_kcore_hdr_t; 255 * [alignment] 256 * phys_ram_seg_t[cpup->nmemseg]; 257 * segmap[cpup->nsegmap]; 258 */ 259 segmaps = (struct segmap *)((long)kd->cpu_data + cpup->segmapoffset); 260 nkreg = ((int)((-(unsigned)kernbase) / NBPRG)); 261 nureg = 256 - nkreg; 262 263 vr = VA_VREG(va); 264 vs = VA_VSEG(va); 265 266 sp = &segmaps[(vr-nureg)*NSEGRG + vs]; 267 if (sp->sg_npte == 0) 268 goto err; 269 270 /* XXX - assume page tables in initial kernel DATA or BSS. */ 271 foff = _kvm_pa2off(kd, (u_long)&sp->sg_pte[VA_VPG(va)] - kernbase); 272 if (foff == (off_t)-1) 273 return (0); 274 275 if (pread(kd->pmfd, &pte, sizeof(pte), foff) != sizeof(pte)) { 276 _kvm_syserr(kd, kd->program, "cannot read pte for %lx", va); 277 return (0); 278 } 279 280 if ((pte & SRMMU_TETYPE) == SRMMU_TEPTE) { 281 long p, off = VA_OFF(va); 282 283 p = (pte & SRMMU_PPNMASK) << SRMMU_PPNPASHIFT; 284 *pa = p + off; 285 return (kd->nbpg - off); 286 } 287 err: 288 _kvm_err(kd, 0, "invalid address (%lx)", va); 289 return (0); 290 } 291 292 /* 293 * sparc64 pmap's 32-bit page table format 294 */ 295 int 296 _kvm_kvatop4u(kd, va, pa) 297 kvm_t *kd; 298 u_long va; 299 u_long *pa; 300 { 301 sparc64_cpu_kcore_hdr_t *cpup = kd->cpu_data; 302 int64_t **segmaps; 303 int64_t *ptes; 304 int64_t pte; 305 int64_t kphys = cpup->kphys; 306 u_long kernbase = cpup->kernbase; 307 308 if (va < kernbase) 309 goto err; 310 311 /* 312 * Kernel layout: 313 * 314 * kernbase: 315 * 4MB locked TLB (text+data+BSS) 316 * Random other stuff. 317 */ 318 if (va >= kernbase && va < kernbase + 4*1024*1024) 319 return (va - kernbase) + kphys; 320 321 /* XXX: from sparc64/include/pmap.h */ 322 #define SPARC64_PTSZ (kd->nbpg/8) 323 #define SPARC64_STSZ (SPARC64_PTSZ) 324 #define SPARC64_PTMASK (SPARC64_PTSZ-1) 325 #define SPARC64_PTSHIFT (13) 326 #define SPARC64_PDSHIFT (10+SPARC64_PTSHIFT) 327 #define SPARC64_STSHIFT (10+SPARC64_PDSHIFT) 328 #define SPARC64_STMASK (SPARC64_STSZ-1) 329 #define sparc64_va_to_seg(v) (int)((((int64_t)(v))>>SPARC64_STSHIFT)&SPARC64_STMASK) 330 #define sparc64_va_to_pte(v) (int)((((int64_t)(v))>>SPARC64_PTSHIFT)&SPARC64_PTMASK) 331 332 /* XXX: from sparc64/include/pte.h */ 333 #define SPARC64_TLB_V 0x8000000000000000LL 334 #define SPARC64_TLB_PA_MASK 0x000001ffffffe000LL 335 336 /* 337 * Layout of CPU segment: 338 * cpu_kcore_hdr_t; 339 * [alignment] 340 * phys_ram_seg_t[cpup->nmemseg]; 341 * segmap[cpup->nsegmap]; 342 */ 343 segmaps = (int64_t **)((long)kd->cpu_data + cpup->segmapoffset); 344 /* XXX XXX XXX _kvm_pa2off takes u_long and returns off_t.. 345 should take off_t also!! */ 346 347 ptes = (int64_t *)(int)_kvm_pa2off(kd, (u_long)segmaps[sparc64_va_to_seg(va)]); 348 pte = ptes[sparc64_va_to_pte(va)]; 349 if ((pte & SPARC64_TLB_V) != 0) 350 return ((pte & SPARC64_TLB_PA_MASK) | (va & (kd->nbpg - 1))); 351 err: 352 _kvm_err(kd, 0, "invalid address (%lx)", va); 353 return (0); 354 } 355 356 357 /* 358 * Translate a physical address to a file-offset in the crash-dump. 359 */ 360 off_t 361 _kvm_pa2off(kd, pa) 362 kvm_t *kd; 363 u_long pa; 364 { 365 sparc64_cpu_kcore_hdr_t *cpup = kd->cpu_data; 366 phys_ram_seg_t *mp; 367 off_t off; 368 int nmem; 369 370 /* 371 * Layout of CPU segment: 372 * cpu_kcore_hdr_t; 373 * [alignment] 374 * phys_ram_seg_t[cpup->nmemseg]; 375 */ 376 mp = (phys_ram_seg_t *)((int)kd->cpu_data + cpup->memsegoffset); 377 off = 0; 378 379 /* Translate (sparse) pfnum to (packed) dump offset */ 380 for (nmem = cpup->nmemseg; --nmem >= 0; mp++) { 381 if (mp->start <= pa && pa < mp->start + mp->size) 382 break; 383 off += mp->size; 384 } 385 if (nmem < 0) { 386 _kvm_err(kd, 0, "invalid address (%lx)", pa); 387 return (-1); 388 } 389 390 return (kd->dump_off + off + pa - mp->start); 391 } 392 393 /* 394 * Machine-dependent initialization for ALL open kvm descriptors, 395 * not just those for a kernel crash dump. Some architectures 396 * have to deal with these NOT being constants! (i.e. m68k) 397 */ 398 int 399 _kvm_mdopen(kd) 400 kvm_t *kd; 401 { 402 u_long max_uva; 403 extern struct ps_strings *__ps_strings; 404 405 max_uva = (u_long) (__ps_strings + 1); 406 kd->usrstack = max_uva; 407 kd->max_uva = max_uva; 408 kd->min_uva = 0; 409 410 return (0); 411 } 412