|
|
1.1 ! root 1: /* ! 2: * Sparc MMU helpers ! 3: * ! 4: * Copyright (c) 2003-2005 Fabrice Bellard ! 5: * ! 6: * This library is free software; you can redistribute it and/or ! 7: * modify it under the terms of the GNU Lesser General Public ! 8: * License as published by the Free Software Foundation; either ! 9: * version 2 of the License, or (at your option) any later version. ! 10: * ! 11: * This library is distributed in the hope that it will be useful, ! 12: * but WITHOUT ANY WARRANTY; without even the implied warranty of ! 13: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ! 14: * Lesser General Public License for more details. ! 15: * ! 16: * You should have received a copy of the GNU Lesser General Public ! 17: * License along with this library; if not, see <http://www.gnu.org/licenses/>. ! 18: */ ! 19: ! 20: #include "cpu.h" ! 21: #include "trace.h" ! 22: ! 23: /* Sparc MMU emulation */ ! 24: ! 25: #if defined(CONFIG_USER_ONLY) ! 26: ! 27: int cpu_sparc_handle_mmu_fault(CPUState *env1, target_ulong address, int rw, ! 28: int mmu_idx) ! 29: { ! 30: if (rw & 2) { ! 31: env1->exception_index = TT_TFAULT; ! 32: } else { ! 33: env1->exception_index = TT_DFAULT; ! 34: } ! 35: return 1; ! 36: } ! 37: ! 38: #else ! 39: ! 40: #ifndef TARGET_SPARC64 ! 41: /* ! 42: * Sparc V8 Reference MMU (SRMMU) ! 43: */ ! 44: static const int access_table[8][8] = { ! 45: { 0, 0, 0, 0, 8, 0, 12, 12 }, ! 46: { 0, 0, 0, 0, 8, 0, 0, 0 }, ! 47: { 8, 8, 0, 0, 0, 8, 12, 12 }, ! 48: { 8, 8, 0, 0, 0, 8, 0, 0 }, ! 49: { 8, 0, 8, 0, 8, 8, 12, 12 }, ! 50: { 8, 0, 8, 0, 8, 0, 8, 0 }, ! 51: { 8, 8, 8, 0, 8, 8, 12, 12 }, ! 52: { 8, 8, 8, 0, 8, 8, 8, 0 } ! 53: }; ! 54: ! 55: static const int perm_table[2][8] = { ! 56: { ! 57: PAGE_READ, ! 58: PAGE_READ | PAGE_WRITE, ! 59: PAGE_READ | PAGE_EXEC, ! 60: PAGE_READ | PAGE_WRITE | PAGE_EXEC, ! 61: PAGE_EXEC, ! 62: PAGE_READ | PAGE_WRITE, ! 63: PAGE_READ | PAGE_EXEC, ! 64: PAGE_READ | PAGE_WRITE | PAGE_EXEC ! 65: }, ! 66: { ! 67: PAGE_READ, ! 68: PAGE_READ | PAGE_WRITE, ! 69: PAGE_READ | PAGE_EXEC, ! 70: PAGE_READ | PAGE_WRITE | PAGE_EXEC, ! 71: PAGE_EXEC, ! 72: PAGE_READ, ! 73: 0, ! 74: 0, ! 75: } ! 76: }; ! 77: ! 78: static int get_physical_address(CPUState *env, target_phys_addr_t *physical, ! 79: int *prot, int *access_index, ! 80: target_ulong address, int rw, int mmu_idx, ! 81: target_ulong *page_size) ! 82: { ! 83: int access_perms = 0; ! 84: target_phys_addr_t pde_ptr; ! 85: uint32_t pde; ! 86: int error_code = 0, is_dirty, is_user; ! 87: unsigned long page_offset; ! 88: ! 89: is_user = mmu_idx == MMU_USER_IDX; ! 90: ! 91: if ((env->mmuregs[0] & MMU_E) == 0) { /* MMU disabled */ ! 92: *page_size = TARGET_PAGE_SIZE; ! 93: /* Boot mode: instruction fetches are taken from PROM */ ! 94: if (rw == 2 && (env->mmuregs[0] & env->def->mmu_bm)) { ! 95: *physical = env->prom_addr | (address & 0x7ffffULL); ! 96: *prot = PAGE_READ | PAGE_EXEC; ! 97: return 0; ! 98: } ! 99: *physical = address; ! 100: *prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC; ! 101: return 0; ! 102: } ! 103: ! 104: *access_index = ((rw & 1) << 2) | (rw & 2) | (is_user ? 0 : 1); ! 105: *physical = 0xffffffffffff0000ULL; ! 106: ! 107: /* SPARC reference MMU table walk: Context table->L1->L2->PTE */ ! 108: /* Context base + context number */ ! 109: pde_ptr = (env->mmuregs[1] << 4) + (env->mmuregs[2] << 2); ! 110: pde = ldl_phys(pde_ptr); ! 111: ! 112: /* Ctx pde */ ! 113: switch (pde & PTE_ENTRYTYPE_MASK) { ! 114: default: ! 115: case 0: /* Invalid */ ! 116: return 1 << 2; ! 117: case 2: /* L0 PTE, maybe should not happen? */ ! 118: case 3: /* Reserved */ ! 119: return 4 << 2; ! 120: case 1: /* L0 PDE */ ! 121: pde_ptr = ((address >> 22) & ~3) + ((pde & ~3) << 4); ! 122: pde = ldl_phys(pde_ptr); ! 123: ! 124: switch (pde & PTE_ENTRYTYPE_MASK) { ! 125: default: ! 126: case 0: /* Invalid */ ! 127: return (1 << 8) | (1 << 2); ! 128: case 3: /* Reserved */ ! 129: return (1 << 8) | (4 << 2); ! 130: case 1: /* L1 PDE */ ! 131: pde_ptr = ((address & 0xfc0000) >> 16) + ((pde & ~3) << 4); ! 132: pde = ldl_phys(pde_ptr); ! 133: ! 134: switch (pde & PTE_ENTRYTYPE_MASK) { ! 135: default: ! 136: case 0: /* Invalid */ ! 137: return (2 << 8) | (1 << 2); ! 138: case 3: /* Reserved */ ! 139: return (2 << 8) | (4 << 2); ! 140: case 1: /* L2 PDE */ ! 141: pde_ptr = ((address & 0x3f000) >> 10) + ((pde & ~3) << 4); ! 142: pde = ldl_phys(pde_ptr); ! 143: ! 144: switch (pde & PTE_ENTRYTYPE_MASK) { ! 145: default: ! 146: case 0: /* Invalid */ ! 147: return (3 << 8) | (1 << 2); ! 148: case 1: /* PDE, should not happen */ ! 149: case 3: /* Reserved */ ! 150: return (3 << 8) | (4 << 2); ! 151: case 2: /* L3 PTE */ ! 152: page_offset = (address & TARGET_PAGE_MASK) & ! 153: (TARGET_PAGE_SIZE - 1); ! 154: } ! 155: *page_size = TARGET_PAGE_SIZE; ! 156: break; ! 157: case 2: /* L2 PTE */ ! 158: page_offset = address & 0x3ffff; ! 159: *page_size = 0x40000; ! 160: } ! 161: break; ! 162: case 2: /* L1 PTE */ ! 163: page_offset = address & 0xffffff; ! 164: *page_size = 0x1000000; ! 165: } ! 166: } ! 167: ! 168: /* check access */ ! 169: access_perms = (pde & PTE_ACCESS_MASK) >> PTE_ACCESS_SHIFT; ! 170: error_code = access_table[*access_index][access_perms]; ! 171: if (error_code && !((env->mmuregs[0] & MMU_NF) && is_user)) { ! 172: return error_code; ! 173: } ! 174: ! 175: /* update page modified and dirty bits */ ! 176: is_dirty = (rw & 1) && !(pde & PG_MODIFIED_MASK); ! 177: if (!(pde & PG_ACCESSED_MASK) || is_dirty) { ! 178: pde |= PG_ACCESSED_MASK; ! 179: if (is_dirty) { ! 180: pde |= PG_MODIFIED_MASK; ! 181: } ! 182: stl_phys_notdirty(pde_ptr, pde); ! 183: } ! 184: ! 185: /* the page can be put in the TLB */ ! 186: *prot = perm_table[is_user][access_perms]; ! 187: if (!(pde & PG_MODIFIED_MASK)) { ! 188: /* only set write access if already dirty... otherwise wait ! 189: for dirty access */ ! 190: *prot &= ~PAGE_WRITE; ! 191: } ! 192: ! 193: /* Even if large ptes, we map only one 4KB page in the cache to ! 194: avoid filling it too fast */ ! 195: *physical = ((target_phys_addr_t)(pde & PTE_ADDR_MASK) << 4) + page_offset; ! 196: return error_code; ! 197: } ! 198: ! 199: /* Perform address translation */ ! 200: int cpu_sparc_handle_mmu_fault(CPUState *env, target_ulong address, int rw, ! 201: int mmu_idx) ! 202: { ! 203: target_phys_addr_t paddr; ! 204: target_ulong vaddr; ! 205: target_ulong page_size; ! 206: int error_code = 0, prot, access_index; ! 207: ! 208: error_code = get_physical_address(env, &paddr, &prot, &access_index, ! 209: address, rw, mmu_idx, &page_size); ! 210: if (error_code == 0) { ! 211: vaddr = address & TARGET_PAGE_MASK; ! 212: paddr &= TARGET_PAGE_MASK; ! 213: #ifdef DEBUG_MMU ! 214: printf("Translate at " TARGET_FMT_lx " -> " TARGET_FMT_plx ", vaddr " ! 215: TARGET_FMT_lx "\n", address, paddr, vaddr); ! 216: #endif ! 217: tlb_set_page(env, vaddr, paddr, prot, mmu_idx, page_size); ! 218: return 0; ! 219: } ! 220: ! 221: if (env->mmuregs[3]) { /* Fault status register */ ! 222: env->mmuregs[3] = 1; /* overflow (not read before another fault) */ ! 223: } ! 224: env->mmuregs[3] |= (access_index << 5) | error_code | 2; ! 225: env->mmuregs[4] = address; /* Fault address register */ ! 226: ! 227: if ((env->mmuregs[0] & MMU_NF) || env->psret == 0) { ! 228: /* No fault mode: if a mapping is available, just override ! 229: permissions. If no mapping is available, redirect accesses to ! 230: neverland. Fake/overridden mappings will be flushed when ! 231: switching to normal mode. */ ! 232: vaddr = address & TARGET_PAGE_MASK; ! 233: prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC; ! 234: tlb_set_page(env, vaddr, paddr, prot, mmu_idx, TARGET_PAGE_SIZE); ! 235: return 0; ! 236: } else { ! 237: if (rw & 2) { ! 238: env->exception_index = TT_TFAULT; ! 239: } else { ! 240: env->exception_index = TT_DFAULT; ! 241: } ! 242: return 1; ! 243: } ! 244: } ! 245: ! 246: target_ulong mmu_probe(CPUState *env, target_ulong address, int mmulev) ! 247: { ! 248: target_phys_addr_t pde_ptr; ! 249: uint32_t pde; ! 250: ! 251: /* Context base + context number */ ! 252: pde_ptr = (target_phys_addr_t)(env->mmuregs[1] << 4) + ! 253: (env->mmuregs[2] << 2); ! 254: pde = ldl_phys(pde_ptr); ! 255: ! 256: switch (pde & PTE_ENTRYTYPE_MASK) { ! 257: default: ! 258: case 0: /* Invalid */ ! 259: case 2: /* PTE, maybe should not happen? */ ! 260: case 3: /* Reserved */ ! 261: return 0; ! 262: case 1: /* L1 PDE */ ! 263: if (mmulev == 3) { ! 264: return pde; ! 265: } ! 266: pde_ptr = ((address >> 22) & ~3) + ((pde & ~3) << 4); ! 267: pde = ldl_phys(pde_ptr); ! 268: ! 269: switch (pde & PTE_ENTRYTYPE_MASK) { ! 270: default: ! 271: case 0: /* Invalid */ ! 272: case 3: /* Reserved */ ! 273: return 0; ! 274: case 2: /* L1 PTE */ ! 275: return pde; ! 276: case 1: /* L2 PDE */ ! 277: if (mmulev == 2) { ! 278: return pde; ! 279: } ! 280: pde_ptr = ((address & 0xfc0000) >> 16) + ((pde & ~3) << 4); ! 281: pde = ldl_phys(pde_ptr); ! 282: ! 283: switch (pde & PTE_ENTRYTYPE_MASK) { ! 284: default: ! 285: case 0: /* Invalid */ ! 286: case 3: /* Reserved */ ! 287: return 0; ! 288: case 2: /* L2 PTE */ ! 289: return pde; ! 290: case 1: /* L3 PDE */ ! 291: if (mmulev == 1) { ! 292: return pde; ! 293: } ! 294: pde_ptr = ((address & 0x3f000) >> 10) + ((pde & ~3) << 4); ! 295: pde = ldl_phys(pde_ptr); ! 296: ! 297: switch (pde & PTE_ENTRYTYPE_MASK) { ! 298: default: ! 299: case 0: /* Invalid */ ! 300: case 1: /* PDE, should not happen */ ! 301: case 3: /* Reserved */ ! 302: return 0; ! 303: case 2: /* L3 PTE */ ! 304: return pde; ! 305: } ! 306: } ! 307: } ! 308: } ! 309: return 0; ! 310: } ! 311: ! 312: void dump_mmu(FILE *f, fprintf_function cpu_fprintf, CPUState *env) ! 313: { ! 314: target_ulong va, va1, va2; ! 315: unsigned int n, m, o; ! 316: target_phys_addr_t pde_ptr, pa; ! 317: uint32_t pde; ! 318: ! 319: pde_ptr = (env->mmuregs[1] << 4) + (env->mmuregs[2] << 2); ! 320: pde = ldl_phys(pde_ptr); ! 321: (*cpu_fprintf)(f, "Root ptr: " TARGET_FMT_plx ", ctx: %d\n", ! 322: (target_phys_addr_t)env->mmuregs[1] << 4, env->mmuregs[2]); ! 323: for (n = 0, va = 0; n < 256; n++, va += 16 * 1024 * 1024) { ! 324: pde = mmu_probe(env, va, 2); ! 325: if (pde) { ! 326: pa = cpu_get_phys_page_debug(env, va); ! 327: (*cpu_fprintf)(f, "VA: " TARGET_FMT_lx ", PA: " TARGET_FMT_plx ! 328: " PDE: " TARGET_FMT_lx "\n", va, pa, pde); ! 329: for (m = 0, va1 = va; m < 64; m++, va1 += 256 * 1024) { ! 330: pde = mmu_probe(env, va1, 1); ! 331: if (pde) { ! 332: pa = cpu_get_phys_page_debug(env, va1); ! 333: (*cpu_fprintf)(f, " VA: " TARGET_FMT_lx ", PA: " ! 334: TARGET_FMT_plx " PDE: " TARGET_FMT_lx "\n", ! 335: va1, pa, pde); ! 336: for (o = 0, va2 = va1; o < 64; o++, va2 += 4 * 1024) { ! 337: pde = mmu_probe(env, va2, 0); ! 338: if (pde) { ! 339: pa = cpu_get_phys_page_debug(env, va2); ! 340: (*cpu_fprintf)(f, " VA: " TARGET_FMT_lx ", PA: " ! 341: TARGET_FMT_plx " PTE: " ! 342: TARGET_FMT_lx "\n", ! 343: va2, pa, pde); ! 344: } ! 345: } ! 346: } ! 347: } ! 348: } ! 349: } ! 350: } ! 351: ! 352: /* Gdb expects all registers windows to be flushed in ram. This function handles ! 353: * reads (and only reads) in stack frames as if windows were flushed. We assume ! 354: * that the sparc ABI is followed. ! 355: */ ! 356: int target_memory_rw_debug(CPUState *env, target_ulong addr, ! 357: uint8_t *buf, int len, int is_write) ! 358: { ! 359: int i; ! 360: int len1; ! 361: int cwp = env->cwp; ! 362: ! 363: if (!is_write) { ! 364: for (i = 0; i < env->nwindows; i++) { ! 365: int off; ! 366: target_ulong fp = env->regbase[cwp * 16 + 22]; ! 367: ! 368: /* Assume fp == 0 means end of frame. */ ! 369: if (fp == 0) { ! 370: break; ! 371: } ! 372: ! 373: cwp = cpu_cwp_inc(env, cwp + 1); ! 374: ! 375: /* Invalid window ? */ ! 376: if (env->wim & (1 << cwp)) { ! 377: break; ! 378: } ! 379: ! 380: /* According to the ABI, the stack is growing downward. */ ! 381: if (addr + len < fp) { ! 382: break; ! 383: } ! 384: ! 385: /* Not in this frame. */ ! 386: if (addr > fp + 64) { ! 387: continue; ! 388: } ! 389: ! 390: /* Handle access before this window. */ ! 391: if (addr < fp) { ! 392: len1 = fp - addr; ! 393: if (cpu_memory_rw_debug(env, addr, buf, len1, is_write) != 0) { ! 394: return -1; ! 395: } ! 396: addr += len1; ! 397: len -= len1; ! 398: buf += len1; ! 399: } ! 400: ! 401: /* Access byte per byte to registers. Not very efficient but speed ! 402: * is not critical. ! 403: */ ! 404: off = addr - fp; ! 405: len1 = 64 - off; ! 406: ! 407: if (len1 > len) { ! 408: len1 = len; ! 409: } ! 410: ! 411: for (; len1; len1--) { ! 412: int reg = cwp * 16 + 8 + (off >> 2); ! 413: union { ! 414: uint32_t v; ! 415: uint8_t c[4]; ! 416: } u; ! 417: u.v = cpu_to_be32(env->regbase[reg]); ! 418: *buf++ = u.c[off & 3]; ! 419: addr++; ! 420: len--; ! 421: off++; ! 422: } ! 423: ! 424: if (len == 0) { ! 425: return 0; ! 426: } ! 427: } ! 428: } ! 429: return cpu_memory_rw_debug(env, addr, buf, len, is_write); ! 430: } ! 431: ! 432: #else /* !TARGET_SPARC64 */ ! 433: ! 434: /* 41 bit physical address space */ ! 435: static inline target_phys_addr_t ultrasparc_truncate_physical(uint64_t x) ! 436: { ! 437: return x & 0x1ffffffffffULL; ! 438: } ! 439: ! 440: /* ! 441: * UltraSparc IIi I/DMMUs ! 442: */ ! 443: ! 444: /* Returns true if TTE tag is valid and matches virtual address value ! 445: in context requires virtual address mask value calculated from TTE ! 446: entry size */ ! 447: static inline int ultrasparc_tag_match(SparcTLBEntry *tlb, ! 448: uint64_t address, uint64_t context, ! 449: target_phys_addr_t *physical) ! 450: { ! 451: uint64_t mask; ! 452: ! 453: switch (TTE_PGSIZE(tlb->tte)) { ! 454: default: ! 455: case 0x0: /* 8k */ ! 456: mask = 0xffffffffffffe000ULL; ! 457: break; ! 458: case 0x1: /* 64k */ ! 459: mask = 0xffffffffffff0000ULL; ! 460: break; ! 461: case 0x2: /* 512k */ ! 462: mask = 0xfffffffffff80000ULL; ! 463: break; ! 464: case 0x3: /* 4M */ ! 465: mask = 0xffffffffffc00000ULL; ! 466: break; ! 467: } ! 468: ! 469: /* valid, context match, virtual address match? */ ! 470: if (TTE_IS_VALID(tlb->tte) && ! 471: (TTE_IS_GLOBAL(tlb->tte) || tlb_compare_context(tlb, context)) ! 472: && compare_masked(address, tlb->tag, mask)) { ! 473: /* decode physical address */ ! 474: *physical = ((tlb->tte & mask) | (address & ~mask)) & 0x1ffffffe000ULL; ! 475: return 1; ! 476: } ! 477: ! 478: return 0; ! 479: } ! 480: ! 481: static int get_physical_address_data(CPUState *env, ! 482: target_phys_addr_t *physical, int *prot, ! 483: target_ulong address, int rw, int mmu_idx) ! 484: { ! 485: unsigned int i; ! 486: uint64_t context; ! 487: uint64_t sfsr = 0; ! 488: ! 489: int is_user = (mmu_idx == MMU_USER_IDX || ! 490: mmu_idx == MMU_USER_SECONDARY_IDX); ! 491: ! 492: if ((env->lsu & DMMU_E) == 0) { /* DMMU disabled */ ! 493: *physical = ultrasparc_truncate_physical(address); ! 494: *prot = PAGE_READ | PAGE_WRITE; ! 495: return 0; ! 496: } ! 497: ! 498: switch (mmu_idx) { ! 499: case MMU_USER_IDX: ! 500: case MMU_KERNEL_IDX: ! 501: context = env->dmmu.mmu_primary_context & 0x1fff; ! 502: sfsr |= SFSR_CT_PRIMARY; ! 503: break; ! 504: case MMU_USER_SECONDARY_IDX: ! 505: case MMU_KERNEL_SECONDARY_IDX: ! 506: context = env->dmmu.mmu_secondary_context & 0x1fff; ! 507: sfsr |= SFSR_CT_SECONDARY; ! 508: break; ! 509: case MMU_NUCLEUS_IDX: ! 510: sfsr |= SFSR_CT_NUCLEUS; ! 511: /* FALLTHRU */ ! 512: default: ! 513: context = 0; ! 514: break; ! 515: } ! 516: ! 517: if (rw == 1) { ! 518: sfsr |= SFSR_WRITE_BIT; ! 519: } else if (rw == 4) { ! 520: sfsr |= SFSR_NF_BIT; ! 521: } ! 522: ! 523: for (i = 0; i < 64; i++) { ! 524: /* ctx match, vaddr match, valid? */ ! 525: if (ultrasparc_tag_match(&env->dtlb[i], address, context, physical)) { ! 526: int do_fault = 0; ! 527: ! 528: /* access ok? */ ! 529: /* multiple bits in SFSR.FT may be set on TT_DFAULT */ ! 530: if (TTE_IS_PRIV(env->dtlb[i].tte) && is_user) { ! 531: do_fault = 1; ! 532: sfsr |= SFSR_FT_PRIV_BIT; /* privilege violation */ ! 533: trace_mmu_helper_dfault(address, context, mmu_idx, env->tl); ! 534: } ! 535: if (rw == 4) { ! 536: if (TTE_IS_SIDEEFFECT(env->dtlb[i].tte)) { ! 537: do_fault = 1; ! 538: sfsr |= SFSR_FT_NF_E_BIT; ! 539: } ! 540: } else { ! 541: if (TTE_IS_NFO(env->dtlb[i].tte)) { ! 542: do_fault = 1; ! 543: sfsr |= SFSR_FT_NFO_BIT; ! 544: } ! 545: } ! 546: ! 547: if (do_fault) { ! 548: /* faults above are reported with TT_DFAULT. */ ! 549: env->exception_index = TT_DFAULT; ! 550: } else if (!TTE_IS_W_OK(env->dtlb[i].tte) && (rw == 1)) { ! 551: do_fault = 1; ! 552: env->exception_index = TT_DPROT; ! 553: ! 554: trace_mmu_helper_dprot(address, context, mmu_idx, env->tl); ! 555: } ! 556: ! 557: if (!do_fault) { ! 558: *prot = PAGE_READ; ! 559: if (TTE_IS_W_OK(env->dtlb[i].tte)) { ! 560: *prot |= PAGE_WRITE; ! 561: } ! 562: ! 563: TTE_SET_USED(env->dtlb[i].tte); ! 564: ! 565: return 0; ! 566: } ! 567: ! 568: if (env->dmmu.sfsr & SFSR_VALID_BIT) { /* Fault status register */ ! 569: sfsr |= SFSR_OW_BIT; /* overflow (not read before ! 570: another fault) */ ! 571: } ! 572: ! 573: if (env->pstate & PS_PRIV) { ! 574: sfsr |= SFSR_PR_BIT; ! 575: } ! 576: ! 577: /* FIXME: ASI field in SFSR must be set */ ! 578: env->dmmu.sfsr = sfsr | SFSR_VALID_BIT; ! 579: ! 580: env->dmmu.sfar = address; /* Fault address register */ ! 581: ! 582: env->dmmu.tag_access = (address & ~0x1fffULL) | context; ! 583: ! 584: return 1; ! 585: } ! 586: } ! 587: ! 588: trace_mmu_helper_dmiss(address, context); ! 589: ! 590: /* ! 591: * On MMU misses: ! 592: * - UltraSPARC IIi: SFSR and SFAR unmodified ! 593: * - JPS1: SFAR updated and some fields of SFSR updated ! 594: */ ! 595: env->dmmu.tag_access = (address & ~0x1fffULL) | context; ! 596: env->exception_index = TT_DMISS; ! 597: return 1; ! 598: } ! 599: ! 600: static int get_physical_address_code(CPUState *env, ! 601: target_phys_addr_t *physical, int *prot, ! 602: target_ulong address, int mmu_idx) ! 603: { ! 604: unsigned int i; ! 605: uint64_t context; ! 606: ! 607: int is_user = (mmu_idx == MMU_USER_IDX || ! 608: mmu_idx == MMU_USER_SECONDARY_IDX); ! 609: ! 610: if ((env->lsu & IMMU_E) == 0 || (env->pstate & PS_RED) != 0) { ! 611: /* IMMU disabled */ ! 612: *physical = ultrasparc_truncate_physical(address); ! 613: *prot = PAGE_EXEC; ! 614: return 0; ! 615: } ! 616: ! 617: if (env->tl == 0) { ! 618: /* PRIMARY context */ ! 619: context = env->dmmu.mmu_primary_context & 0x1fff; ! 620: } else { ! 621: /* NUCLEUS context */ ! 622: context = 0; ! 623: } ! 624: ! 625: for (i = 0; i < 64; i++) { ! 626: /* ctx match, vaddr match, valid? */ ! 627: if (ultrasparc_tag_match(&env->itlb[i], ! 628: address, context, physical)) { ! 629: /* access ok? */ ! 630: if (TTE_IS_PRIV(env->itlb[i].tte) && is_user) { ! 631: /* Fault status register */ ! 632: if (env->immu.sfsr & SFSR_VALID_BIT) { ! 633: env->immu.sfsr = SFSR_OW_BIT; /* overflow (not read before ! 634: another fault) */ ! 635: } else { ! 636: env->immu.sfsr = 0; ! 637: } ! 638: if (env->pstate & PS_PRIV) { ! 639: env->immu.sfsr |= SFSR_PR_BIT; ! 640: } ! 641: if (env->tl > 0) { ! 642: env->immu.sfsr |= SFSR_CT_NUCLEUS; ! 643: } ! 644: ! 645: /* FIXME: ASI field in SFSR must be set */ ! 646: env->immu.sfsr |= SFSR_FT_PRIV_BIT | SFSR_VALID_BIT; ! 647: env->exception_index = TT_TFAULT; ! 648: ! 649: env->immu.tag_access = (address & ~0x1fffULL) | context; ! 650: ! 651: trace_mmu_helper_tfault(address, context); ! 652: ! 653: return 1; ! 654: } ! 655: *prot = PAGE_EXEC; ! 656: TTE_SET_USED(env->itlb[i].tte); ! 657: return 0; ! 658: } ! 659: } ! 660: ! 661: trace_mmu_helper_tmiss(address, context); ! 662: ! 663: /* Context is stored in DMMU (dmmuregs[1]) also for IMMU */ ! 664: env->immu.tag_access = (address & ~0x1fffULL) | context; ! 665: env->exception_index = TT_TMISS; ! 666: return 1; ! 667: } ! 668: ! 669: static int get_physical_address(CPUState *env, target_phys_addr_t *physical, ! 670: int *prot, int *access_index, ! 671: target_ulong address, int rw, int mmu_idx, ! 672: target_ulong *page_size) ! 673: { ! 674: /* ??? We treat everything as a small page, then explicitly flush ! 675: everything when an entry is evicted. */ ! 676: *page_size = TARGET_PAGE_SIZE; ! 677: ! 678: /* safety net to catch wrong softmmu index use from dynamic code */ ! 679: if (env->tl > 0 && mmu_idx != MMU_NUCLEUS_IDX) { ! 680: if (rw == 2) { ! 681: trace_mmu_helper_get_phys_addr_code(env->tl, mmu_idx, ! 682: env->dmmu.mmu_primary_context, ! 683: env->dmmu.mmu_secondary_context, ! 684: address); ! 685: } else { ! 686: trace_mmu_helper_get_phys_addr_data(env->tl, mmu_idx, ! 687: env->dmmu.mmu_primary_context, ! 688: env->dmmu.mmu_secondary_context, ! 689: address); ! 690: } ! 691: } ! 692: ! 693: if (rw == 2) { ! 694: return get_physical_address_code(env, physical, prot, address, ! 695: mmu_idx); ! 696: } else { ! 697: return get_physical_address_data(env, physical, prot, address, rw, ! 698: mmu_idx); ! 699: } ! 700: } ! 701: ! 702: /* Perform address translation */ ! 703: int cpu_sparc_handle_mmu_fault(CPUState *env, target_ulong address, int rw, ! 704: int mmu_idx) ! 705: { ! 706: target_ulong virt_addr, vaddr; ! 707: target_phys_addr_t paddr; ! 708: target_ulong page_size; ! 709: int error_code = 0, prot, access_index; ! 710: ! 711: error_code = get_physical_address(env, &paddr, &prot, &access_index, ! 712: address, rw, mmu_idx, &page_size); ! 713: if (error_code == 0) { ! 714: virt_addr = address & TARGET_PAGE_MASK; ! 715: vaddr = virt_addr + ((address & TARGET_PAGE_MASK) & ! 716: (TARGET_PAGE_SIZE - 1)); ! 717: ! 718: trace_mmu_helper_mmu_fault(address, paddr, mmu_idx, env->tl, ! 719: env->dmmu.mmu_primary_context, ! 720: env->dmmu.mmu_secondary_context); ! 721: ! 722: tlb_set_page(env, vaddr, paddr, prot, mmu_idx, page_size); ! 723: return 0; ! 724: } ! 725: /* XXX */ ! 726: return 1; ! 727: } ! 728: ! 729: void dump_mmu(FILE *f, fprintf_function cpu_fprintf, CPUState *env) ! 730: { ! 731: unsigned int i; ! 732: const char *mask; ! 733: ! 734: (*cpu_fprintf)(f, "MMU contexts: Primary: %" PRId64 ", Secondary: %" ! 735: PRId64 "\n", ! 736: env->dmmu.mmu_primary_context, ! 737: env->dmmu.mmu_secondary_context); ! 738: if ((env->lsu & DMMU_E) == 0) { ! 739: (*cpu_fprintf)(f, "DMMU disabled\n"); ! 740: } else { ! 741: (*cpu_fprintf)(f, "DMMU dump\n"); ! 742: for (i = 0; i < 64; i++) { ! 743: switch (TTE_PGSIZE(env->dtlb[i].tte)) { ! 744: default: ! 745: case 0x0: ! 746: mask = " 8k"; ! 747: break; ! 748: case 0x1: ! 749: mask = " 64k"; ! 750: break; ! 751: case 0x2: ! 752: mask = "512k"; ! 753: break; ! 754: case 0x3: ! 755: mask = " 4M"; ! 756: break; ! 757: } ! 758: if (TTE_IS_VALID(env->dtlb[i].tte)) { ! 759: (*cpu_fprintf)(f, "[%02u] VA: %" PRIx64 ", PA: %llx" ! 760: ", %s, %s, %s, %s, ctx %" PRId64 " %s\n", ! 761: i, ! 762: env->dtlb[i].tag & (uint64_t)~0x1fffULL, ! 763: TTE_PA(env->dtlb[i].tte), ! 764: mask, ! 765: TTE_IS_PRIV(env->dtlb[i].tte) ? "priv" : "user", ! 766: TTE_IS_W_OK(env->dtlb[i].tte) ? "RW" : "RO", ! 767: TTE_IS_LOCKED(env->dtlb[i].tte) ? ! 768: "locked" : "unlocked", ! 769: env->dtlb[i].tag & (uint64_t)0x1fffULL, ! 770: TTE_IS_GLOBAL(env->dtlb[i].tte) ? ! 771: "global" : "local"); ! 772: } ! 773: } ! 774: } ! 775: if ((env->lsu & IMMU_E) == 0) { ! 776: (*cpu_fprintf)(f, "IMMU disabled\n"); ! 777: } else { ! 778: (*cpu_fprintf)(f, "IMMU dump\n"); ! 779: for (i = 0; i < 64; i++) { ! 780: switch (TTE_PGSIZE(env->itlb[i].tte)) { ! 781: default: ! 782: case 0x0: ! 783: mask = " 8k"; ! 784: break; ! 785: case 0x1: ! 786: mask = " 64k"; ! 787: break; ! 788: case 0x2: ! 789: mask = "512k"; ! 790: break; ! 791: case 0x3: ! 792: mask = " 4M"; ! 793: break; ! 794: } ! 795: if (TTE_IS_VALID(env->itlb[i].tte)) { ! 796: (*cpu_fprintf)(f, "[%02u] VA: %" PRIx64 ", PA: %llx" ! 797: ", %s, %s, %s, ctx %" PRId64 " %s\n", ! 798: i, ! 799: env->itlb[i].tag & (uint64_t)~0x1fffULL, ! 800: TTE_PA(env->itlb[i].tte), ! 801: mask, ! 802: TTE_IS_PRIV(env->itlb[i].tte) ? "priv" : "user", ! 803: TTE_IS_LOCKED(env->itlb[i].tte) ? ! 804: "locked" : "unlocked", ! 805: env->itlb[i].tag & (uint64_t)0x1fffULL, ! 806: TTE_IS_GLOBAL(env->itlb[i].tte) ? ! 807: "global" : "local"); ! 808: } ! 809: } ! 810: } ! 811: } ! 812: ! 813: #endif /* TARGET_SPARC64 */ ! 814: ! 815: static int cpu_sparc_get_phys_page(CPUState *env, target_phys_addr_t *phys, ! 816: target_ulong addr, int rw, int mmu_idx) ! 817: { ! 818: target_ulong page_size; ! 819: int prot, access_index; ! 820: ! 821: return get_physical_address(env, phys, &prot, &access_index, addr, rw, ! 822: mmu_idx, &page_size); ! 823: } ! 824: ! 825: #if defined(TARGET_SPARC64) ! 826: target_phys_addr_t cpu_get_phys_page_nofault(CPUState *env, target_ulong addr, ! 827: int mmu_idx) ! 828: { ! 829: target_phys_addr_t phys_addr; ! 830: ! 831: if (cpu_sparc_get_phys_page(env, &phys_addr, addr, 4, mmu_idx) != 0) { ! 832: return -1; ! 833: } ! 834: return phys_addr; ! 835: } ! 836: #endif ! 837: ! 838: target_phys_addr_t cpu_get_phys_page_debug(CPUState *env, target_ulong addr) ! 839: { ! 840: target_phys_addr_t phys_addr; ! 841: int mmu_idx = cpu_mmu_index(env); ! 842: ! 843: if (cpu_sparc_get_phys_page(env, &phys_addr, addr, 2, mmu_idx) != 0) { ! 844: if (cpu_sparc_get_phys_page(env, &phys_addr, addr, 0, mmu_idx) != 0) { ! 845: return -1; ! 846: } ! 847: } ! 848: if (cpu_get_physical_page_desc(phys_addr) == IO_MEM_UNASSIGNED) { ! 849: return -1; ! 850: } ! 851: return phys_addr; ! 852: } ! 853: #endif
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.