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