1 /* $NetBSD: kvm_mips.c,v 1.20 2010/09/20 23:23:16 jym Exp $ */ 2 3 /* 4 * Copyright (c) 1994, 1995 Carnegie-Mellon University. 5 * All rights reserved. 6 * 7 * Author: Chris G. Demetriou 8 * 9 * Permission to use, copy, modify and distribute this software and 10 * its documentation is hereby granted, provided that both the copyright 11 * notice and this permission notice appear in all copies of the 12 * software, derivative works or modified versions, and any portions 13 * thereof, and that both notices appear in supporting documentation. 14 * 15 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" 16 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND 17 * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. 18 * 19 * Carnegie Mellon requests users of this software to return to 20 * 21 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU 22 * School of Computer Science 23 * Carnegie Mellon University 24 * Pittsburgh PA 15213-3890 25 * 26 * any improvements or extensions that they make and grant Carnegie the 27 * rights to redistribute these changes. 28 */ 29 30 /* 31 * Modified for NetBSD/mips by Jason R. Thorpe, Numerical Aerospace 32 * Simulation Facility, NASA Ames Research Center. 33 */ 34 35 #include <sys/cdefs.h> 36 #if defined(LIBC_SCCS) && !defined(lint) 37 __RCSID("$NetBSD: kvm_mips.c,v 1.20 2010/09/20 23:23:16 jym Exp $"); 38 #endif /* LIBC_SCCS and not lint */ 39 40 /* 41 * MIPS machine dependent routines for kvm. 42 */ 43 44 #include <sys/param.h> 45 #include <sys/user.h> 46 #include <sys/proc.h> 47 #include <sys/stat.h> 48 #include <sys/kcore.h> 49 #include <sys/types.h> 50 51 #include <machine/kcore.h> 52 53 #include <stdlib.h> 54 #include <unistd.h> 55 #include <nlist.h> 56 #include <kvm.h> 57 58 #include <uvm/uvm_extern.h> 59 60 #include <limits.h> 61 #include <db.h> 62 63 #include "kvm_private.h" 64 65 #include <mips/cpuregs.h> 66 #include <mips/vmparam.h> 67 68 void 69 _kvm_freevtop(kvm_t *kd) 70 { 71 72 /* Not actually used for anything right now, but safe. */ 73 if (kd->vmst != 0) 74 free(kd->vmst); 75 } 76 77 int 78 _kvm_initvtop(kvm_t *kd) 79 { 80 81 return (0); 82 } 83 84 /* 85 * Translate a kernel virtual address to a physical address. 86 */ 87 int 88 _kvm_kvatop(kvm_t *kd, vaddr_t va, paddr_t *pa) 89 { 90 cpu_kcore_hdr_t *cpu_kh; 91 int page_off; 92 u_int pte; 93 paddr_t pte_pa; 94 95 if (ISALIVE(kd)) { 96 _kvm_err(kd, 0, "vatop called in live kernel!"); 97 return((off_t)0); 98 } 99 100 cpu_kh = kd->cpu_data; 101 page_off = va & PGOFSET; 102 103 if (va < MIPS_KSEG0_START) { 104 /* 105 * KUSEG (user virtual address space) - invalid. 106 */ 107 _kvm_err(kd, 0, "invalid kernel virtual address"); 108 goto lose; 109 } 110 111 if (va >= MIPS_KSEG0_START && va < MIPS_KSEG1_START) { 112 /* 113 * Direct-mapped cached address: just convert it. 114 */ 115 *pa = MIPS_KSEG0_TO_PHYS(va); 116 return (NBPG - page_off); 117 } 118 119 if (va >= MIPS_KSEG1_START && va < MIPS_KSEG2_START) { 120 /* 121 * Direct-mapped uncached address: just convert it. 122 */ 123 *pa = MIPS_KSEG1_TO_PHYS(va); 124 return (NBPG - page_off); 125 } 126 127 /* 128 * We now know that we're a KSEG2 (kernel virtually mapped) 129 * address. Translate the address using the pmap's kernel 130 * page table. 131 */ 132 133 /* 134 * Step 1: Make sure the kernel page table has a translation 135 * for the address. 136 */ 137 if (va >= (MIPS_KSEG2_START + (cpu_kh->sysmapsize * NBPG))) { 138 _kvm_err(kd, 0, "invalid KSEG2 address"); 139 goto lose; 140 } 141 142 /* 143 * Step 2: Locate and read the PTE. 144 */ 145 pte_pa = cpu_kh->sysmappa + 146 (((va - MIPS_KSEG2_START) >> PGSHIFT) * sizeof(u_int)); 147 if (_kvm_pread(kd, kd->pmfd, &pte, sizeof(pte), 148 _kvm_pa2off(kd, pte_pa)) != sizeof(pte)) { 149 _kvm_syserr(kd, 0, "could not read PTE"); 150 goto lose; 151 } 152 153 /* 154 * Step 3: Validate the PTE and return the physical address. 155 */ 156 if ((pte & cpu_kh->pg_v) == 0) { 157 _kvm_err(kd, 0, "invalid translation (invalid PTE)"); 158 goto lose; 159 } 160 *pa = (((pte & cpu_kh->pg_frame) >> cpu_kh->pg_shift) << PGSHIFT) + 161 page_off; 162 return (NBPG - page_off); 163 164 lose: 165 *pa = -1; 166 return (0); 167 } 168 169 /* 170 * Translate a physical address to a file-offset in the crash dump. 171 */ 172 off_t 173 _kvm_pa2off(kvm_t *kd, paddr_t pa) 174 { 175 cpu_kcore_hdr_t *cpu_kh; 176 phys_ram_seg_t *ramsegs; 177 off_t off; 178 int i; 179 180 cpu_kh = kd->cpu_data; 181 ramsegs = (phys_ram_seg_t *)((char *)cpu_kh + ALIGN(sizeof *cpu_kh)); 182 183 off = 0; 184 for (i = 0; i < cpu_kh->nmemsegs; i++) { 185 if (pa >= ramsegs[i].start && 186 (pa - ramsegs[i].start) < ramsegs[i].size) { 187 off += (pa - ramsegs[i].start); 188 break; 189 } 190 off += ramsegs[i].size; 191 } 192 193 return (kd->dump_off + off); 194 } 195 196 /* 197 * Machine-dependent initialization for ALL open kvm descriptors, 198 * not just those for a kernel crash dump. Some architectures 199 * have to deal with these NOT being constants! (i.e. m68k) 200 */ 201 int 202 _kvm_mdopen(kvm_t *kd) 203 { 204 205 kd->usrstack = USRSTACK; 206 kd->min_uva = VM_MIN_ADDRESS; 207 kd->max_uva = VM_MAXUSER_ADDRESS; 208 209 return (0); 210 } 211