153111Smckusick /*- 253111Smckusick * Copyright (c) 1992 The Regents of the University of California. 353111Smckusick * All rights reserved. 453111Smckusick * 553111Smckusick * This code is derived from software developed by the Computer Systems 6*53294Sbostic * Engineering group at Lawrence Berkeley Laboratory under DARPA contract 7*53294Sbostic * BG 91-66 and contributed to Berkeley. 853111Smckusick * 953111Smckusick * %sccs.include.redist.c% 1053111Smckusick */ 1153111Smckusick 1253111Smckusick #if defined(LIBC_SCCS) && !defined(lint) 13*53294Sbostic static char sccsid[] = "@(#)kvm_sparc.c 5.2 (Berkeley) 04/29/92"; 1453111Smckusick #endif /* LIBC_SCCS and not lint */ 1553111Smckusick 1653111Smckusick /* 1753111Smckusick * Sparc machine dependent routines for kvm. Hopefully, the forthcoming 1853111Smckusick * vm code will one day obsolete this module. 1953111Smckusick */ 2053111Smckusick 2153111Smckusick #include <sys/param.h> 2253111Smckusick #include <sys/user.h> 2353111Smckusick #include <sys/proc.h> 2453111Smckusick #include <sys/stat.h> 2553111Smckusick #include <nlist.h> 2653111Smckusick #include <kvm.h> 2753111Smckusick 2853111Smckusick #include <vm/vm.h> 2953111Smckusick #include <vm/vm_param.h> 3053111Smckusick 3153111Smckusick #include <limits.h> 32*53294Sbostic #include <db.h> 3353111Smckusick 3453111Smckusick #include "kvm_private.h" 3553111Smckusick 3653111Smckusick #define NPMEG 128 3753111Smckusick 3853111Smckusick /* XXX from sparc/pmap.c */ 3953111Smckusick #define MAXMEM (128 * 1024 * 1024) /* no more than 128 MB phys mem */ 4053111Smckusick #define NPGBANK 16 /* 2^4 pages per bank (64K / bank) */ 4153111Smckusick #define BSHIFT 4 /* log2(NPGBANK) */ 4253111Smckusick #define BOFFSET (NPGBANK - 1) 4353111Smckusick #define BTSIZE (MAXMEM / NBPG / NPGBANK) 4453111Smckusick #define HWTOSW(pmap_stod, pg) (pmap_stod[(pg) >> BSHIFT] | ((pg) & BOFFSET)) 4553111Smckusick 4653111Smckusick struct vmstate { 4753111Smckusick pmeg_t segmap[NKSEG]; 4853111Smckusick int pmeg[NPMEG][NPTESG]; 4953111Smckusick int pmap_stod[BTSIZE]; /* dense to sparse */ 5053111Smckusick }; 5153111Smckusick 5253111Smckusick void 5353111Smckusick _kvm_freevtop(kd) 5453111Smckusick kvm_t *kd; 5553111Smckusick { 5653111Smckusick if (kd->vmst != 0) 5753111Smckusick free(kd->vmst); 5853111Smckusick } 5953111Smckusick 6053111Smckusick int 6153111Smckusick _kvm_initvtop(kd) 6253111Smckusick kvm_t *kd; 6353111Smckusick { 6453111Smckusick register int i; 6553111Smckusick register int off; 6653111Smckusick register struct vmstate *vm; 6753111Smckusick struct stat st; 6853111Smckusick struct nlist nlist[2]; 6953111Smckusick 7053111Smckusick vm = (struct vmstate *)_kvm_malloc(kd, sizeof(*vm)); 7153111Smckusick if (vm == 0) 7253111Smckusick return (-1); 7353111Smckusick 7453111Smckusick kd->vmst = vm; 7553111Smckusick 7653111Smckusick if (fstat(kd->pmfd, &st) < 0) 7753111Smckusick return (-1); 7853111Smckusick /* 7953111Smckusick * Read segment table. 8053111Smckusick */ 8153111Smckusick off = st.st_size - ctob(btoc(sizeof(vm->segmap))); 8253111Smckusick errno = 0; 8353111Smckusick if (lseek(kd->pmfd, (off_t)off, 0) == -1 && errno != 0 || 8453111Smckusick read(kd->pmfd, (char *)vm->segmap, sizeof(vm->segmap)) < 0) { 8553111Smckusick _kvm_err(kd, kd->program, "cannot read segment map"); 8653111Smckusick return (-1); 8753111Smckusick } 8853111Smckusick /* 8953111Smckusick * Read PMEGs. 9053111Smckusick */ 9153111Smckusick off = st.st_size - ctob(btoc(sizeof(vm->pmeg)) + 9253111Smckusick btoc(sizeof(vm->segmap))); 9353111Smckusick errno = 0; 9453111Smckusick if (lseek(kd->pmfd, (off_t)off, 0) == -1 && errno != 0 || 9553111Smckusick read(kd->pmfd, (char *)vm->pmeg, sizeof(vm->pmeg)) < 0) { 9653111Smckusick _kvm_err(kd, kd->program, "cannot read PMEG table"); 9753111Smckusick return (-1); 9853111Smckusick } 9953111Smckusick /* 10053111Smckusick * Make pmap_stod be an identity map so we can bootstrap it in. 10153111Smckusick * We assume it's in the first contiguous chunk of physical memory. 10253111Smckusick */ 10353111Smckusick for (i = 0; i < BTSIZE; ++i) 10453111Smckusick vm->pmap_stod[i] = i << 4; 10553111Smckusick 10653111Smckusick /* 10753111Smckusick * It's okay to do this nlist separately from the one kvm_getprocs() 10853111Smckusick * does, since the only time we could gain anything by combining 10953111Smckusick * them is if we do a kvm_getprocs() on a dead kernel, which is 11053111Smckusick * not too common. 11153111Smckusick */ 11253111Smckusick nlist[0].n_name = "_pmap_stod"; 11353111Smckusick nlist[1].n_name = 0; 11453111Smckusick if (kvm_nlist(kd, nlist) != 0) { 11553111Smckusick _kvm_err(kd, kd->program, "pmap_stod: no such symbol"); 11653111Smckusick return (-1); 11753111Smckusick } 11853111Smckusick if (kvm_read(kd, (u_long)nlist[0].n_value, 11953111Smckusick (char *)vm->pmap_stod, sizeof(vm->pmap_stod)) 12053111Smckusick != sizeof(vm->pmap_stod)) { 12153111Smckusick _kvm_err(kd, kd->program, "cannot read pmap_stod"); 12253111Smckusick return (-1); 12353111Smckusick } 12453111Smckusick return (0); 12553111Smckusick } 12653111Smckusick 12753111Smckusick #define VA_OFF(va) (va & (NBPG - 1)) 12853111Smckusick 12953111Smckusick /* 13053111Smckusick * Translate a user virtual address to a physical address. 13153111Smckusick */ 13253111Smckusick int 13353111Smckusick _kvm_uvatop(kd, p, va, pa) 13453111Smckusick kvm_t *kd; 13553111Smckusick const struct proc *p; 13653111Smckusick u_long va; 13753111Smckusick u_long *pa; 13853111Smckusick { 13953111Smckusick int kva, pte; 14053111Smckusick register int off, frame; 14153111Smckusick register struct vmspace *vms = p->p_vmspace; 14253111Smckusick 14353111Smckusick if ((u_long)vms < KERNBASE) { 14453111Smckusick _kvm_err(kd, kd->program, "_kvm_uvatop: corrupt proc"); 14553111Smckusick return (0); 14653111Smckusick } 14753111Smckusick if (va >= KERNBASE) 14853111Smckusick return (0); 14953111Smckusick /* 15053111Smckusick * Get the PTE. This takes two steps. We read the 15153111Smckusick * base address of the table, then we index it. 15253111Smckusick * Note that the index pte table is indexed by 15353111Smckusick * virtual segment rather than physical segment. 15453111Smckusick */ 15553111Smckusick kva = (u_long)&vms->vm_pmap.pm_rpte[VA_VSEG(va)]; 15653111Smckusick if (kvm_read(kd, kva, (char *)&kva, 4) != 4 || kva == 0) 15753111Smckusick goto invalid; 15853111Smckusick kva += sizeof(vms->vm_pmap.pm_rpte[0]) * VA_VPG(va); 15953111Smckusick if (kvm_read(kd, kva, (char *)&pte, 4) == 4 && (pte & PG_V)) { 16053111Smckusick off = VA_OFF(va); 16153111Smckusick /* 16253111Smckusick * /dev/mem adheres to the hardware model of physical memory 16353111Smckusick * (with holes in the address space), while crashdumps 16453111Smckusick * adhere to the contiguous software model. 16553111Smckusick */ 16653111Smckusick if (ISALIVE(kd)) 16753111Smckusick frame = pte & PG_PFNUM; 16853111Smckusick else 16953111Smckusick frame = HWTOSW(kd->vmst->pmap_stod, pte & PG_PFNUM); 17053111Smckusick *pa = (frame << PGSHIFT) | off; 17153111Smckusick return (NBPG - off); 17253111Smckusick } 17353111Smckusick invalid: 17453111Smckusick _kvm_err(kd, 0, "invalid address (%x)", va); 17553111Smckusick return (0); 17653111Smckusick } 17753111Smckusick 17853111Smckusick /* 17953111Smckusick * Translate a kernel virtual address to a physical address using the 18053111Smckusick * mapping information in kd->vm. Returns the result in pa, and returns 18153111Smckusick * the number of bytes that are contiguously available from this 18253111Smckusick * physical address. This routine is used only for crashdumps. 18353111Smckusick */ 18453111Smckusick int 18553111Smckusick _kvm_kvatop(kd, va, pa) 18653111Smckusick kvm_t *kd; 18753111Smckusick u_long va; 18853111Smckusick u_long *pa; 18953111Smckusick { 19053111Smckusick register struct vmstate *vm; 19153111Smckusick register int s; 19253111Smckusick register int pte; 19353111Smckusick register int off; 19453111Smckusick 19553111Smckusick if (va >= KERNBASE) { 19653111Smckusick vm = kd->vmst; 19753111Smckusick s = vm->segmap[VA_VSEG(va) - NUSEG]; 19853111Smckusick pte = vm->pmeg[s][VA_VPG(va)]; 19953111Smckusick if ((pte & PG_V) != 0) { 20053111Smckusick off = VA_OFF(va); 20153111Smckusick *pa = (HWTOSW(vm->pmap_stod, pte & PG_PFNUM) 20253111Smckusick << PGSHIFT) | off; 20353111Smckusick 20453111Smckusick return (NBPG - off); 20553111Smckusick } 20653111Smckusick } 20753111Smckusick _kvm_err(kd, 0, "invalid address (%x)", va); 20853111Smckusick return (0); 20953111Smckusick } 210