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