1 /* $NetBSD: kvm_powerpc.c,v 1.9 2010/02/25 23:35:29 matt Exp $ */ 2 3 /* 4 * Copyright (c) 2005 Wasabi Systems, Inc. 5 * All rights reserved. 6 * 7 * Written by Allen Briggs for Wasabi Systems, Inc. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 3. All advertising materials mentioning features or use of this software 18 * must display the following acknowledgement: 19 * This product includes software developed for the NetBSD Project by 20 * Wasabi Systems, Inc. 21 * 4. The name of Wasabi Systems, Inc. may not be used to endorse 22 * or promote products derived from this software without specific prior 23 * written permission. 24 * 25 * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND 26 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 27 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 28 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC 29 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 30 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 31 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 32 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 33 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 34 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 35 * POSSIBILITY OF SUCH DAMAGE. 36 */ 37 /*- 38 * Copyright (C) 1996 Wolfgang Solfrank. 39 * Copyright (C) 1996 TooLs GmbH. 40 * All rights reserved. 41 * 42 * Redistribution and use in source and binary forms, with or without 43 * modification, are permitted provided that the following conditions 44 * are met: 45 * 1. Redistributions of source code must retain the above copyright 46 * notice, this list of conditions and the following disclaimer. 47 * 2. Redistributions in binary form must reproduce the above copyright 48 * notice, this list of conditions and the following disclaimer in the 49 * documentation and/or other materials provided with the distribution. 50 * 3. All advertising materials mentioning features or use of this software 51 * must display the following acknowledgement: 52 * This product includes software developed by TooLs GmbH. 53 * 4. The name of TooLs GmbH may not be used to endorse or promote products 54 * derived from this software without specific prior written permission. 55 * 56 * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR 57 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 58 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 59 * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 60 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 61 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 62 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 63 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 64 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 65 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 66 */ 67 68 /* 69 * PowerPC machine dependent routines for kvm. 70 */ 71 72 #include <sys/param.h> 73 #include <sys/exec.h> 74 75 #include <uvm/uvm_extern.h> 76 77 #include <db.h> 78 #include <limits.h> 79 #include <kvm.h> 80 #include <stdlib.h> 81 #include <unistd.h> 82 83 #include "kvm_private.h" 84 85 #include <sys/kcore.h> 86 #include <machine/kcore.h> 87 88 #include <powerpc/spr.h> 89 #include <powerpc/oea/spr.h> 90 #include <powerpc/oea/bat.h> 91 #include <powerpc/oea/pte.h> 92 93 static int _kvm_match_601bat(kvm_t *kd, u_long va, u_long *pa, int *off); 94 static int _kvm_match_bat(kvm_t *kd, u_long va, u_long *pa, int *off); 95 static int _kvm_match_sr(kvm_t *kd, u_long va, u_long *pa, int *off); 96 static struct pte *_kvm_scan_pteg(struct pteg *pteg, uint32_t vsid, 97 uint32_t api, int secondary); 98 99 void 100 _kvm_freevtop(kd) 101 kvm_t *kd; 102 { 103 if (kd->vmst != 0) 104 free(kd->vmst); 105 } 106 107 /*ARGSUSED*/ 108 int 109 _kvm_initvtop(kd) 110 kvm_t *kd; 111 { 112 113 return 0; 114 } 115 116 #define BAT601_SIZE(b) ((((b) << 17) | ~BAT601_BLPI) + 1) 117 118 static int 119 _kvm_match_601bat(kd, va, pa, off) 120 kvm_t *kd; 121 u_long va; 122 u_long *pa; 123 int *off; 124 { 125 cpu_kcore_hdr_t *cpu_kh; 126 u_long pgoff; 127 size_t size; 128 int i, nbat; 129 130 cpu_kh = kd->cpu_data; 131 nbat = 4; 132 for (i=0 ; i<nbat ; i++) { 133 if (!BAT601_VALID_P(cpu_kh->dbatu[i])) 134 continue; 135 if (BAT601_VA_MATCH_P(cpu_kh->dbatu[i], cpu_kh->dbatl[i], va)) { 136 size = BAT601_SIZE(cpu_kh->dbatu[i] & BAT601_BSM); 137 pgoff = va & (size-1); 138 *pa = (cpu_kh->dbatl[i] & BAT601_PBN) + pgoff; 139 *off = size - pgoff; 140 return 1; 141 } 142 } 143 return 0; 144 } 145 146 #undef BAT601_SIZE 147 148 #define BAT_SIZE(b) ((((b) << 15) | ~BAT_EPI) + 1) 149 150 static int 151 _kvm_match_bat(kd, va, pa, off) 152 kvm_t *kd; 153 u_long va; 154 u_long *pa; 155 int *off; 156 { 157 cpu_kcore_hdr_t *cpu_kh; 158 u_long pgoff; 159 size_t size; 160 int i, nbat; 161 162 cpu_kh = kd->cpu_data; 163 /* 164 * Assume that we're looking for data and check only the dbats. 165 */ 166 nbat = 8; 167 for (i=0 ; i<nbat ; i++) { 168 if ( ((cpu_kh->dbatu[i] & BAT_Vs) != 0) 169 && (BAT_VA_MATCH_P(cpu_kh->dbatu[i], va))) { 170 size = BAT_SIZE(cpu_kh->dbatu[i] & BAT_BL); 171 pgoff = va & (size-1); 172 *pa = (cpu_kh->dbatl[i] & BAT_RPN) + pgoff; 173 *off = size - pgoff; 174 return 1; 175 } 176 } 177 return 0; 178 } 179 180 #undef BAT_SIZE 181 182 #define SR_VSID_HASH_MASK 0x0007ffff 183 184 static struct pte * 185 _kvm_scan_pteg(pteg, vsid, api, secondary) 186 struct pteg *pteg; 187 uint32_t vsid; 188 uint32_t api; 189 int secondary; 190 { 191 struct pte *pte; 192 u_long ptehi; 193 int i; 194 195 for (i=0 ; i<8 ; i++) { 196 pte = &pteg->pt[i]; 197 ptehi = (u_long) pte->pte_hi; 198 if ((ptehi & PTE_VALID) == 0) 199 continue; 200 if ((ptehi & PTE_HID) != secondary) 201 continue; 202 if (((ptehi & PTE_VSID) >> PTE_VSID_SHFT) != vsid) 203 continue; 204 if (((ptehi & PTE_API) >> PTE_API_SHFT) != api) 205 continue; 206 return pte; 207 } 208 return NULL; 209 } 210 211 #define HASH_MASK 0x0007ffff 212 213 static int 214 _kvm_match_sr(kd, va, pa, off) 215 kvm_t *kd; 216 u_long va; 217 u_long *pa; 218 int *off; 219 { 220 cpu_kcore_hdr_t *cpu_kh; 221 struct pteg pteg; 222 struct pte *pte; 223 uint32_t sr, pgoff, vsid, pgidx, api, hash; 224 uint32_t htaborg, htabmask, mhash; 225 u_long pteg_vaddr; 226 227 cpu_kh = kd->cpu_data; 228 229 sr = cpu_kh->sr[(va >> 28) & 0xf]; 230 if ((sr & SR_TYPE) != 0) { 231 /* Direct-store segment (shouldn't be) */ 232 return 0; 233 } 234 235 pgoff = va & ADDR_POFF; 236 vsid = sr & SR_VSID; 237 pgidx = (va & ADDR_PIDX) >> ADDR_PIDX_SHFT; 238 api = pgidx >> 10; 239 hash = (vsid & HASH_MASK) ^ pgidx; 240 241 htaborg = cpu_kh->sdr1 & 0xffff0000; 242 htabmask = cpu_kh->sdr1 & 0x1ff; 243 244 mhash = (hash >> 10) & htabmask; 245 246 pteg_vaddr = ( htaborg & 0xfe000000) | ((hash & 0x3ff) << 6) 247 | ((htaborg & 0x01ff0000) | (mhash << 16)); 248 249 if (_kvm_pread(kd, kd->pmfd, (void *) &pteg, sizeof(pteg), 250 _kvm_pa2off(kd, pteg_vaddr)) != sizeof(pteg)) { 251 _kvm_syserr(kd, 0, "could not read primary PTEG"); 252 return 0; 253 } 254 255 if ((pte = _kvm_scan_pteg(&pteg, vsid, api, 0)) != NULL) { 256 *pa = (pte->pte_lo & PTE_RPGN) | pgoff; 257 *off = NBPG - pgoff; 258 return 1; 259 } 260 261 hash = (~hash) & HASH_MASK; 262 mhash = (hash >> 10) & htabmask; 263 264 pteg_vaddr = ( htaborg & 0xfe000000) | ((hash & 0x3ff) << 6) 265 | ((htaborg & 0x01ff0000) | (mhash << 16)); 266 267 if (_kvm_pread(kd, kd->pmfd, (void *) &pteg, sizeof(pteg), 268 _kvm_pa2off(kd, pteg_vaddr)) != sizeof(pteg)) { 269 _kvm_syserr(kd, 0, "could not read secondary PTEG"); 270 return 0; 271 } 272 273 if ((pte = _kvm_scan_pteg(&pteg, vsid, api, 0)) != NULL) { 274 *pa = (pte->pte_lo & PTE_RPGN) | pgoff; 275 *off = NBPG - pgoff; 276 return 1; 277 } 278 279 return 0; 280 } 281 282 /* 283 * Translate a KVA to a PA 284 */ 285 int 286 _kvm_kvatop(kd, va, pa) 287 kvm_t *kd; 288 u_long va; 289 u_long *pa; 290 { 291 cpu_kcore_hdr_t *cpu_kh; 292 int offs; 293 uint32_t pvr; 294 295 if (ISALIVE(kd)) { 296 _kvm_err(kd, 0, "vatop called in live kernel!"); 297 return 0; 298 } 299 300 cpu_kh = kd->cpu_data; 301 302 pvr = (cpu_kh->pvr >> 16); 303 if (MPC745X_P(pvr)) 304 pvr = MPC7450; 305 306 switch (pvr) { 307 case MPC601: 308 /* Check for a BAT hit first */ 309 if (_kvm_match_601bat(kd, va, pa, &offs)) { 310 return offs; 311 } 312 313 /* No BAT hit; check page tables */ 314 if (_kvm_match_sr(kd, va, pa, &offs)) { 315 return offs; 316 } 317 break; 318 319 case MPC603: 320 case MPC603e: 321 case MPC603ev: 322 case MPC604: 323 case MPC604ev: 324 case MPC750: 325 case IBM750FX: 326 case MPC7400: 327 case MPC7450: 328 case MPC7410: 329 case MPC8240: 330 case MPC8245: 331 /* Check for a BAT hit first */ 332 if (_kvm_match_bat(kd, va, pa, &offs)) { 333 return offs; 334 } 335 336 /* No BAT hit; check page tables */ 337 if (_kvm_match_sr(kd, va, pa, &offs)) { 338 return offs; 339 } 340 break; 341 342 default: 343 _kvm_err(kd, 0, "Unsupported CPU type (pvr 0x%08lx)!", 344 (unsigned long) cpu_kh->pvr); 345 break; 346 } 347 348 /* No hit -- no translation */ 349 *pa = (u_long)~0UL; 350 return 0; 351 } 352 353 off_t 354 _kvm_pa2off(kd, pa) 355 kvm_t *kd; 356 u_long pa; 357 { 358 cpu_kcore_hdr_t *cpu_kh; 359 phys_ram_seg_t *ram; 360 off_t off; 361 void *e; 362 363 cpu_kh = kd->cpu_data; 364 e = (char *) kd->cpu_data + kd->cpu_dsize; 365 ram = (void *)((char *)(void *)cpu_kh + ALIGN(sizeof *cpu_kh)); 366 off = kd->dump_off; 367 do { 368 if (pa >= ram->start && (pa - ram->start) < ram->size) { 369 return off + (pa - ram->start); 370 } 371 ram++; 372 off += ram->size; 373 } while ((void *) ram < e && ram->size); 374 375 _kvm_err(kd, 0, "pa2off failed for pa 0x%08lx\n", pa); 376 return (off_t) -1; 377 } 378 379 /* 380 * Machine-dependent initialization for ALL open kvm descriptors, 381 * not just those for a kernel crash dump. Some architectures 382 * have to deal with these NOT being constants! (i.e. m68k) 383 */ 384 int 385 _kvm_mdopen(kd) 386 kvm_t *kd; 387 { 388 uintptr_t max_uva; 389 extern struct ps_strings *__ps_strings; 390 391 #if 0 /* XXX - These vary across powerpc machines... */ 392 kd->usrstack = USRSTACK; 393 kd->min_uva = VM_MIN_ADDRESS; 394 kd->max_uva = VM_MAXUSER_ADDRESS; 395 #endif 396 /* This is somewhat hack-ish, but it works. */ 397 max_uva = (uintptr_t) (__ps_strings + 1); 398 kd->usrstack = max_uva; 399 kd->max_uva = max_uva; 400 kd->min_uva = 0; 401 402 return (0); 403 } 404