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