1 /* $NetBSD: kvm_powerpc.c,v 1.7 2005/02/17 02:31:27 briggs 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/bat.h> 90 #include <powerpc/oea/pte.h> 91 92 static int _kvm_match_601bat(kvm_t *kd, u_long va, u_long *pa, int *off); 93 static int _kvm_match_bat(kvm_t *kd, u_long va, u_long *pa, int *off); 94 static int _kvm_match_sr(kvm_t *kd, u_long va, u_long *pa, int *off); 95 static struct pte *_kvm_scan_pteg(struct pteg *pteg, uint32_t vsid, 96 uint32_t api, int secondary); 97 98 void 99 _kvm_freevtop(kd) 100 kvm_t *kd; 101 { 102 if (kd->vmst != 0) 103 free(kd->vmst); 104 } 105 106 /*ARGSUSED*/ 107 int 108 _kvm_initvtop(kd) 109 kvm_t *kd; 110 { 111 112 return 0; 113 } 114 115 #define BAT601_SIZE(b) ((((b) << 17) | ~BAT601_BLPI) + 1) 116 117 static int 118 _kvm_match_601bat(kd, va, pa, off) 119 kvm_t *kd; 120 u_long va; 121 u_long *pa; 122 int *off; 123 { 124 cpu_kcore_hdr_t *cpu_kh; 125 u_long pgoff; 126 size_t size; 127 int i, nbat; 128 129 cpu_kh = kd->cpu_data; 130 nbat = 4; 131 for (i=0 ; i<nbat ; i++) { 132 if (!BAT601_VALID_P(cpu_kh->dbatu[i])) 133 continue; 134 if (BAT601_VA_MATCH_P(cpu_kh->dbatu[i], cpu_kh->dbatl[i], va)) { 135 size = BAT601_SIZE(cpu_kh->dbatu[i] & BAT601_BSM); 136 pgoff = va & (size-1); 137 *pa = (cpu_kh->dbatl[i] & BAT601_PBN) + pgoff; 138 *off = size - pgoff; 139 return 1; 140 } 141 } 142 return 0; 143 } 144 145 #undef BAT601_SIZE 146 147 #define BAT_SIZE(b) ((((b) << 15) | ~BAT_EPI) + 1) 148 149 static int 150 _kvm_match_bat(kd, va, pa, off) 151 kvm_t *kd; 152 u_long va; 153 u_long *pa; 154 int *off; 155 { 156 cpu_kcore_hdr_t *cpu_kh; 157 u_long pgoff; 158 size_t size; 159 int i, nbat; 160 161 cpu_kh = kd->cpu_data; 162 /* 163 * Assume that we're looking for data and check only the dbats. 164 */ 165 nbat = 8; 166 for (i=0 ; i<nbat ; i++) { 167 if ( ((cpu_kh->dbatu[i] & BAT_Vs) != 0) 168 && (BAT_VA_MATCH_P(cpu_kh->dbatu[i], va))) { 169 size = BAT_SIZE(cpu_kh->dbatu[i] & BAT_BL); 170 pgoff = va & (size-1); 171 *pa = (cpu_kh->dbatl[i] & BAT_RPN) + pgoff; 172 *off = size - pgoff; 173 return 1; 174 } 175 } 176 return 0; 177 } 178 179 #undef BAT_SIZE 180 181 #define SR_VSID_HASH_MASK 0x0007ffff 182 183 static struct pte * 184 _kvm_scan_pteg(pteg, vsid, api, secondary) 185 struct pteg *pteg; 186 uint32_t vsid; 187 uint32_t api; 188 int secondary; 189 { 190 struct pte *pte; 191 u_long ptehi; 192 int i; 193 194 for (i=0 ; i<8 ; i++) { 195 pte = &pteg->pt[i]; 196 ptehi = (u_long) pte->pte_hi; 197 if ((ptehi & PTE_VALID) == 0) 198 continue; 199 if ((ptehi & PTE_HID) != secondary) 200 continue; 201 if (((ptehi & PTE_VSID) >> PTE_VSID_SHFT) != vsid) 202 continue; 203 if (((ptehi & PTE_API) >> PTE_API_SHFT) != api) 204 continue; 205 return pte; 206 } 207 return NULL; 208 } 209 210 #define HASH_MASK 0x0007ffff 211 212 static int 213 _kvm_match_sr(kd, va, pa, off) 214 kvm_t *kd; 215 u_long va; 216 u_long *pa; 217 int *off; 218 { 219 cpu_kcore_hdr_t *cpu_kh; 220 struct pteg pteg; 221 struct pte *pte; 222 uint32_t sr, pgoff, vsid, pgidx, api, hash; 223 uint32_t htaborg, htabmask, mhash; 224 u_long pteg_vaddr; 225 226 cpu_kh = kd->cpu_data; 227 228 sr = cpu_kh->sr[(va >> 28) & 0xf]; 229 if ((sr & SR_TYPE) != 0) { 230 /* Direct-store segment (shouldn't be) */ 231 return 0; 232 } 233 234 pgoff = va & ADDR_POFF; 235 vsid = sr & SR_VSID; 236 pgidx = (va & ADDR_PIDX) >> ADDR_PIDX_SHFT; 237 api = pgidx >> 10; 238 hash = (vsid & HASH_MASK) ^ pgidx; 239 240 htaborg = cpu_kh->sdr1 & 0xffff0000; 241 htabmask = cpu_kh->sdr1 & 0x1ff; 242 243 mhash = (hash >> 10) & htabmask; 244 245 pteg_vaddr = ( htaborg & 0xfe000000) | ((hash & 0x3ff) << 6) 246 | ((htaborg & 0x01ff0000) | (mhash << 16)); 247 248 if (pread(kd->pmfd, (void *) &pteg, sizeof(pteg), 249 _kvm_pa2off(kd, pteg_vaddr)) != sizeof(pteg)) { 250 _kvm_syserr(kd, 0, "could not read primary PTEG"); 251 return 0; 252 } 253 254 if ((pte = _kvm_scan_pteg(&pteg, vsid, api, 0)) != NULL) { 255 *pa = (pte->pte_lo & PTE_RPGN) | pgoff; 256 *off = NBPG - pgoff; 257 return 1; 258 } 259 260 hash = (~hash) & HASH_MASK; 261 mhash = (hash >> 10) & htabmask; 262 263 pteg_vaddr = ( htaborg & 0xfe000000) | ((hash & 0x3ff) << 6) 264 | ((htaborg & 0x01ff0000) | (mhash << 16)); 265 266 if (pread(kd->pmfd, (void *) &pteg, sizeof(pteg), 267 _kvm_pa2off(kd, pteg_vaddr)) != sizeof(pteg)) { 268 _kvm_syserr(kd, 0, "could not read secondary PTEG"); 269 return 0; 270 } 271 272 if ((pte = _kvm_scan_pteg(&pteg, vsid, api, 0)) != NULL) { 273 *pa = (pte->pte_lo & PTE_RPGN) | pgoff; 274 *off = NBPG - pgoff; 275 return 1; 276 } 277 278 return 0; 279 } 280 281 /* 282 * Translate a KVA to a PA 283 */ 284 int 285 _kvm_kvatop(kd, va, pa) 286 kvm_t *kd; 287 u_long va; 288 u_long *pa; 289 { 290 cpu_kcore_hdr_t *cpu_kh; 291 int offs; 292 uint32_t pvr; 293 294 if (ISALIVE(kd)) { 295 _kvm_err(kd, 0, "vatop called in live kernel!"); 296 return 0; 297 } 298 299 cpu_kh = kd->cpu_data; 300 301 pvr = (cpu_kh->pvr >> 16); 302 if (MPC745X_P(pvr)) 303 pvr = MPC7450; 304 305 switch (pvr) { 306 case MPC601: 307 /* Check for a BAT hit first */ 308 if (_kvm_match_601bat(kd, va, pa, &offs)) { 309 return offs; 310 } 311 312 /* No BAT hit; check page tables */ 313 if (_kvm_match_sr(kd, va, pa, &offs)) { 314 return offs; 315 } 316 break; 317 318 case MPC603: 319 case MPC603e: 320 case MPC603ev: 321 case MPC604: 322 case MPC604ev: 323 case MPC750: 324 case IBM750FX: 325 case MPC7400: 326 case MPC7450: 327 case MPC7410: 328 case MPC8240: 329 case MPC8245: 330 /* Check for a BAT hit first */ 331 if (_kvm_match_bat(kd, va, pa, &offs)) { 332 return offs; 333 } 334 335 /* No BAT hit; check page tables */ 336 if (_kvm_match_sr(kd, va, pa, &offs)) { 337 return offs; 338 } 339 break; 340 341 default: 342 _kvm_err(kd, 0, "Unsupported CPU type (pvr 0x%08lx)!", 343 (unsigned long) cpu_kh->pvr); 344 break; 345 } 346 347 /* No hit -- no translation */ 348 *pa = (u_long)~0UL; 349 return 0; 350 } 351 352 off_t 353 _kvm_pa2off(kd, pa) 354 kvm_t *kd; 355 u_long pa; 356 { 357 cpu_kcore_hdr_t *cpu_kh; 358 phys_ram_seg_t *ram; 359 off_t off; 360 void *e; 361 362 cpu_kh = kd->cpu_data; 363 e = (char *) kd->cpu_data + kd->cpu_dsize; 364 ram = (void *)((char *)(void *)cpu_kh + ALIGN(sizeof *cpu_kh)); 365 off = kd->dump_off; 366 do { 367 if (pa >= ram->start && (pa - ram->start) < ram->size) { 368 return off + (pa - ram->start); 369 } 370 ram++; 371 off += ram->size; 372 } while ((void *) ram < e && ram->size); 373 374 _kvm_err(kd, 0, "pa2off failed for pa 0x%08lx\n", pa); 375 return (off_t) -1; 376 } 377 378 /* 379 * Machine-dependent initialization for ALL open kvm descriptors, 380 * not just those for a kernel crash dump. Some architectures 381 * have to deal with these NOT being constants! (i.e. m68k) 382 */ 383 int 384 _kvm_mdopen(kd) 385 kvm_t *kd; 386 { 387 uintptr_t max_uva; 388 extern struct ps_strings *__ps_strings; 389 390 #if 0 /* XXX - These vary across powerpc machines... */ 391 kd->usrstack = USRSTACK; 392 kd->min_uva = VM_MIN_ADDRESS; 393 kd->max_uva = VM_MAXUSER_ADDRESS; 394 #endif 395 /* This is somewhat hack-ish, but it works. */ 396 max_uva = (uintptr_t) (__ps_strings + 1); 397 kd->usrstack = max_uva; 398 kd->max_uva = max_uva; 399 kd->min_uva = 0; 400 401 return (0); 402 } 403