Annotation of qemu/target-sparc/mmu_helper.c, revision 1.1.1.2

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"
1.1.1.2 ! root       22: #include "exec-memory.h"
1.1       root       23: 
                     24: /* Sparc MMU emulation */
                     25: 
                     26: #if defined(CONFIG_USER_ONLY)
                     27: 
1.1.1.2 ! root       28: int cpu_sparc_handle_mmu_fault(CPUSPARCState *env1, target_ulong address, int rw,
1.1       root       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:  */
                     45: static 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: 
                     56: static 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: 
1.1.1.2 ! root       79: static int get_physical_address(CPUSPARCState *env, target_phys_addr_t *physical,
1.1       root       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:     target_phys_addr_t 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 */
1.1.1.2 ! root      153:                     page_offset = 0;
1.1       root      154:                 }
                    155:                 *page_size = TARGET_PAGE_SIZE;
                    156:                 break;
                    157:             case 2: /* L2 PTE */
1.1.1.2 ! root      158:                 page_offset = address & 0x3f000;
1.1       root      159:                 *page_size = 0x40000;
                    160:             }
                    161:             break;
                    162:         case 2: /* L1 PTE */
1.1.1.2 ! root      163:             page_offset = address & 0xfff000;
1.1       root      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 */
1.1.1.2 ! root      200: int cpu_sparc_handle_mmu_fault(CPUSPARCState *env, target_ulong address, int rw,
1.1       root      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: 
1.1.1.2 ! root      208:     address &= TARGET_PAGE_MASK;
1.1       root      209:     error_code = get_physical_address(env, &paddr, &prot, &access_index,
                    210:                                       address, rw, mmu_idx, &page_size);
1.1.1.2 ! root      211:     vaddr = address;
1.1       root      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: 
1.1.1.2 ! root      245: target_ulong mmu_probe(CPUSPARCState *env, target_ulong address, int mmulev)
1.1       root      246: {
                    247:     target_phys_addr_t pde_ptr;
                    248:     uint32_t pde;
                    249: 
                    250:     /* Context base + context number */
                    251:     pde_ptr = (target_phys_addr_t)(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: 
1.1.1.2 ! root      311: void dump_mmu(FILE *f, fprintf_function cpu_fprintf, CPUSPARCState *env)
1.1       root      312: {
                    313:     target_ulong va, va1, va2;
                    314:     unsigned int n, m, o;
                    315:     target_phys_addr_t 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:                    (target_phys_addr_t)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:  */
1.1.1.2 ! root      355: int target_memory_rw_debug(CPUSPARCState *env, target_ulong addr,
1.1       root      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 */
                    434: static inline target_phys_addr_t 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 */
                    446: static inline int ultrasparc_tag_match(SparcTLBEntry *tlb,
                    447:                                        uint64_t address, uint64_t context,
                    448:                                        target_phys_addr_t *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: 
1.1.1.2 ! root      480: static int get_physical_address_data(CPUSPARCState *env,
1.1       root      481:                                      target_phys_addr_t *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: 
1.1.1.2 ! root      599: static int get_physical_address_code(CPUSPARCState *env,
1.1       root      600:                                      target_phys_addr_t *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: 
1.1.1.2 ! root      668: static int get_physical_address(CPUSPARCState *env, target_phys_addr_t *physical,
1.1       root      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 */
1.1.1.2 ! root      702: int cpu_sparc_handle_mmu_fault(CPUSPARCState *env, target_ulong address, int rw,
1.1       root      703:                                int mmu_idx)
                    704: {
1.1.1.2 ! root      705:     target_ulong vaddr;
1.1       root      706:     target_phys_addr_t paddr;
                    707:     target_ulong page_size;
                    708:     int error_code = 0, prot, access_index;
                    709: 
1.1.1.2 ! root      710:     address &= TARGET_PAGE_MASK;
1.1       root      711:     error_code = get_physical_address(env, &paddr, &prot, &access_index,
                    712:                                       address, rw, mmu_idx, &page_size);
                    713:     if (error_code == 0) {
1.1.1.2 ! root      714:         vaddr = address;
1.1       root      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: 
1.1.1.2 ! root      727: void dump_mmu(FILE *f, fprintf_function cpu_fprintf, CPUSPARCState *env)
1.1       root      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: 
1.1.1.2 ! root      813: static int cpu_sparc_get_phys_page(CPUSPARCState *env, target_phys_addr_t *phys,
1.1       root      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)
1.1.1.2 ! root      824: target_phys_addr_t cpu_get_phys_page_nofault(CPUSPARCState *env, target_ulong addr,
1.1       root      825:                                            int mmu_idx)
                    826: {
                    827:     target_phys_addr_t 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: 
1.1.1.2 ! root      836: target_phys_addr_t cpu_get_phys_page_debug(CPUSPARCState *env, target_ulong addr)
1.1       root      837: {
                    838:     target_phys_addr_t phys_addr;
                    839:     int mmu_idx = cpu_mmu_index(env);
1.1.1.2 ! root      840:     MemoryRegionSection section;
1.1       root      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:     }
1.1.1.2 ! root      847:     section = memory_region_find(get_system_memory(), phys_addr, 1);
        !           848:     if (!section.size) {
1.1       root      849:         return -1;
                    850:     }
                    851:     return phys_addr;
                    852: }
                    853: #endif

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.