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

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

unix.superglobalmegacorp.com

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