Annotation of qemu/target-xtensa/helper.c, revision 1.1.1.2

1.1       root        1: /*
                      2:  * Copyright (c) 2011, Max Filippov, Open Source and Linux Lab.
                      3:  * All rights reserved.
                      4:  *
                      5:  * Redistribution and use in source and binary forms, with or without
                      6:  * modification, are permitted provided that the following conditions are met:
                      7:  *     * Redistributions of source code must retain the above copyright
                      8:  *       notice, this list of conditions and the following disclaimer.
                      9:  *     * Redistributions in binary form must reproduce the above copyright
                     10:  *       notice, this list of conditions and the following disclaimer in the
                     11:  *       documentation and/or other materials provided with the distribution.
                     12:  *     * Neither the name of the Open Source and Linux Lab nor the
                     13:  *       names of its contributors may be used to endorse or promote products
                     14:  *       derived from this software without specific prior written permission.
                     15:  *
                     16:  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
                     17:  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
                     18:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
                     19:  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
                     20:  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
                     21:  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
                     22:  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
                     23:  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
                     24:  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
                     25:  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
                     26:  */
                     27: 
                     28: #include "cpu.h"
                     29: #include "exec-all.h"
                     30: #include "gdbstub.h"
                     31: #include "host-utils.h"
                     32: #if !defined(CONFIG_USER_ONLY)
                     33: #include "hw/loader.h"
                     34: #endif
                     35: 
1.1.1.2 ! root       36: void cpu_state_reset(CPUXtensaState *env)
1.1       root       37: {
1.1.1.2 ! root       38:     cpu_reset(ENV_GET_CPU(env));
1.1       root       39: }
                     40: 
                     41: static struct XtensaConfigList *xtensa_cores;
                     42: 
                     43: void xtensa_register_core(XtensaConfigList *node)
                     44: {
                     45:     node->next = xtensa_cores;
                     46:     xtensa_cores = node;
                     47: }
                     48: 
1.1.1.2 ! root       49: static uint32_t check_hw_breakpoints(CPUXtensaState *env)
        !            50: {
        !            51:     unsigned i;
        !            52: 
        !            53:     for (i = 0; i < env->config->ndbreak; ++i) {
        !            54:         if (env->cpu_watchpoint[i] &&
        !            55:                 env->cpu_watchpoint[i]->flags & BP_WATCHPOINT_HIT) {
        !            56:             return DEBUGCAUSE_DB | (i << DEBUGCAUSE_DBNUM_SHIFT);
        !            57:         }
        !            58:     }
        !            59:     return 0;
        !            60: }
        !            61: 
        !            62: static CPUDebugExcpHandler *prev_debug_excp_handler;
        !            63: 
        !            64: static void breakpoint_handler(CPUXtensaState *env)
        !            65: {
        !            66:     if (env->watchpoint_hit) {
        !            67:         if (env->watchpoint_hit->flags & BP_CPU) {
        !            68:             uint32_t cause;
        !            69: 
        !            70:             env->watchpoint_hit = NULL;
        !            71:             cause = check_hw_breakpoints(env);
        !            72:             if (cause) {
        !            73:                 debug_exception_env(env, cause);
        !            74:             }
        !            75:             cpu_resume_from_signal(env, NULL);
        !            76:         }
        !            77:     }
        !            78:     if (prev_debug_excp_handler) {
        !            79:         prev_debug_excp_handler(env);
        !            80:     }
        !            81: }
        !            82: 
1.1       root       83: CPUXtensaState *cpu_xtensa_init(const char *cpu_model)
                     84: {
                     85:     static int tcg_inited;
1.1.1.2 ! root       86:     static int debug_handler_inited;
        !            87:     XtensaCPU *cpu;
1.1       root       88:     CPUXtensaState *env;
                     89:     const XtensaConfig *config = NULL;
                     90:     XtensaConfigList *core = xtensa_cores;
                     91: 
                     92:     for (; core; core = core->next)
                     93:         if (strcmp(core->config->name, cpu_model) == 0) {
                     94:             config = core->config;
                     95:             break;
                     96:         }
                     97: 
                     98:     if (config == NULL) {
                     99:         return NULL;
                    100:     }
                    101: 
1.1.1.2 ! root      102:     cpu = XTENSA_CPU(object_new(TYPE_XTENSA_CPU));
        !           103:     env = &cpu->env;
1.1       root      104:     env->config = config;
                    105: 
                    106:     if (!tcg_inited) {
                    107:         tcg_inited = 1;
                    108:         xtensa_translate_init();
                    109:     }
                    110: 
1.1.1.2 ! root      111:     if (!debug_handler_inited && tcg_enabled()) {
        !           112:         debug_handler_inited = 1;
        !           113:         prev_debug_excp_handler =
        !           114:             cpu_set_debug_excp_handler(breakpoint_handler);
        !           115:     }
        !           116: 
1.1       root      117:     xtensa_irq_init(env);
                    118:     qemu_init_vcpu(env);
                    119:     return env;
                    120: }
                    121: 
                    122: 
                    123: void xtensa_cpu_list(FILE *f, fprintf_function cpu_fprintf)
                    124: {
                    125:     XtensaConfigList *core = xtensa_cores;
                    126:     cpu_fprintf(f, "Available CPUs:\n");
                    127:     for (; core; core = core->next) {
                    128:         cpu_fprintf(f, "  %s\n", core->config->name);
                    129:     }
                    130: }
                    131: 
1.1.1.2 ! root      132: target_phys_addr_t cpu_get_phys_page_debug(CPUXtensaState *env, target_ulong addr)
1.1       root      133: {
                    134:     uint32_t paddr;
                    135:     uint32_t page_size;
                    136:     unsigned access;
                    137: 
1.1.1.2 ! root      138:     if (xtensa_get_physical_addr(env, false, addr, 0, 0,
1.1       root      139:                 &paddr, &page_size, &access) == 0) {
                    140:         return paddr;
                    141:     }
1.1.1.2 ! root      142:     if (xtensa_get_physical_addr(env, false, addr, 2, 0,
1.1       root      143:                 &paddr, &page_size, &access) == 0) {
                    144:         return paddr;
                    145:     }
                    146:     return ~0;
                    147: }
                    148: 
1.1.1.2 ! root      149: static uint32_t relocated_vector(CPUXtensaState *env, uint32_t vector)
1.1       root      150: {
                    151:     if (xtensa_option_enabled(env->config,
                    152:                 XTENSA_OPTION_RELOCATABLE_VECTOR)) {
                    153:         return vector - env->config->vecbase + env->sregs[VECBASE];
                    154:     } else {
                    155:         return vector;
                    156:     }
                    157: }
                    158: 
                    159: /*!
                    160:  * Handle penging IRQ.
                    161:  * For the high priority interrupt jump to the corresponding interrupt vector.
                    162:  * For the level-1 interrupt convert it to either user, kernel or double
                    163:  * exception with the 'level-1 interrupt' exception cause.
                    164:  */
1.1.1.2 ! root      165: static void handle_interrupt(CPUXtensaState *env)
1.1       root      166: {
                    167:     int level = env->pending_irq_level;
                    168: 
                    169:     if (level > xtensa_get_cintlevel(env) &&
                    170:             level <= env->config->nlevel &&
                    171:             (env->config->level_mask[level] &
                    172:              env->sregs[INTSET] &
                    173:              env->sregs[INTENABLE])) {
                    174:         if (level > 1) {
                    175:             env->sregs[EPC1 + level - 1] = env->pc;
                    176:             env->sregs[EPS2 + level - 2] = env->sregs[PS];
                    177:             env->sregs[PS] =
                    178:                 (env->sregs[PS] & ~PS_INTLEVEL) | level | PS_EXCM;
                    179:             env->pc = relocated_vector(env,
                    180:                     env->config->interrupt_vector[level]);
                    181:         } else {
                    182:             env->sregs[EXCCAUSE] = LEVEL1_INTERRUPT_CAUSE;
                    183: 
                    184:             if (env->sregs[PS] & PS_EXCM) {
                    185:                 if (env->config->ndepc) {
                    186:                     env->sregs[DEPC] = env->pc;
                    187:                 } else {
                    188:                     env->sregs[EPC1] = env->pc;
                    189:                 }
                    190:                 env->exception_index = EXC_DOUBLE;
                    191:             } else {
                    192:                 env->sregs[EPC1] = env->pc;
                    193:                 env->exception_index =
                    194:                     (env->sregs[PS] & PS_UM) ? EXC_USER : EXC_KERNEL;
                    195:             }
                    196:             env->sregs[PS] |= PS_EXCM;
                    197:         }
                    198:         env->exception_taken = 1;
                    199:     }
                    200: }
                    201: 
1.1.1.2 ! root      202: void do_interrupt(CPUXtensaState *env)
1.1       root      203: {
                    204:     if (env->exception_index == EXC_IRQ) {
                    205:         qemu_log_mask(CPU_LOG_INT,
                    206:                 "%s(EXC_IRQ) level = %d, cintlevel = %d, "
                    207:                 "pc = %08x, a0 = %08x, ps = %08x, "
                    208:                 "intset = %08x, intenable = %08x, "
                    209:                 "ccount = %08x\n",
                    210:                 __func__, env->pending_irq_level, xtensa_get_cintlevel(env),
                    211:                 env->pc, env->regs[0], env->sregs[PS],
                    212:                 env->sregs[INTSET], env->sregs[INTENABLE],
                    213:                 env->sregs[CCOUNT]);
                    214:         handle_interrupt(env);
                    215:     }
                    216: 
                    217:     switch (env->exception_index) {
                    218:     case EXC_WINDOW_OVERFLOW4:
                    219:     case EXC_WINDOW_UNDERFLOW4:
                    220:     case EXC_WINDOW_OVERFLOW8:
                    221:     case EXC_WINDOW_UNDERFLOW8:
                    222:     case EXC_WINDOW_OVERFLOW12:
                    223:     case EXC_WINDOW_UNDERFLOW12:
                    224:     case EXC_KERNEL:
                    225:     case EXC_USER:
                    226:     case EXC_DOUBLE:
1.1.1.2 ! root      227:     case EXC_DEBUG:
1.1       root      228:         qemu_log_mask(CPU_LOG_INT, "%s(%d) "
                    229:                 "pc = %08x, a0 = %08x, ps = %08x, ccount = %08x\n",
                    230:                 __func__, env->exception_index,
                    231:                 env->pc, env->regs[0], env->sregs[PS], env->sregs[CCOUNT]);
                    232:         if (env->config->exception_vector[env->exception_index]) {
                    233:             env->pc = relocated_vector(env,
                    234:                     env->config->exception_vector[env->exception_index]);
                    235:             env->exception_taken = 1;
                    236:         } else {
                    237:             qemu_log("%s(pc = %08x) bad exception_index: %d\n",
                    238:                     __func__, env->pc, env->exception_index);
                    239:         }
                    240:         break;
                    241: 
                    242:     case EXC_IRQ:
                    243:         break;
                    244: 
                    245:     default:
                    246:         qemu_log("%s(pc = %08x) unknown exception_index: %d\n",
                    247:                 __func__, env->pc, env->exception_index);
                    248:         break;
                    249:     }
                    250:     check_interrupts(env);
                    251: }
                    252: 
1.1.1.2 ! root      253: static void reset_tlb_mmu_all_ways(CPUXtensaState *env,
1.1       root      254:         const xtensa_tlb *tlb, xtensa_tlb_entry entry[][MAX_TLB_WAY_SIZE])
                    255: {
                    256:     unsigned wi, ei;
                    257: 
                    258:     for (wi = 0; wi < tlb->nways; ++wi) {
                    259:         for (ei = 0; ei < tlb->way_size[wi]; ++ei) {
                    260:             entry[wi][ei].asid = 0;
                    261:             entry[wi][ei].variable = true;
                    262:         }
                    263:     }
                    264: }
                    265: 
1.1.1.2 ! root      266: static void reset_tlb_mmu_ways56(CPUXtensaState *env,
1.1       root      267:         const xtensa_tlb *tlb, xtensa_tlb_entry entry[][MAX_TLB_WAY_SIZE])
                    268: {
                    269:     if (!tlb->varway56) {
                    270:         static const xtensa_tlb_entry way5[] = {
                    271:             {
                    272:                 .vaddr = 0xd0000000,
                    273:                 .paddr = 0,
                    274:                 .asid = 1,
                    275:                 .attr = 7,
                    276:                 .variable = false,
                    277:             }, {
                    278:                 .vaddr = 0xd8000000,
                    279:                 .paddr = 0,
                    280:                 .asid = 1,
                    281:                 .attr = 3,
                    282:                 .variable = false,
                    283:             }
                    284:         };
                    285:         static const xtensa_tlb_entry way6[] = {
                    286:             {
                    287:                 .vaddr = 0xe0000000,
                    288:                 .paddr = 0xf0000000,
                    289:                 .asid = 1,
                    290:                 .attr = 7,
                    291:                 .variable = false,
                    292:             }, {
                    293:                 .vaddr = 0xf0000000,
                    294:                 .paddr = 0xf0000000,
                    295:                 .asid = 1,
                    296:                 .attr = 3,
                    297:                 .variable = false,
                    298:             }
                    299:         };
                    300:         memcpy(entry[5], way5, sizeof(way5));
                    301:         memcpy(entry[6], way6, sizeof(way6));
                    302:     } else {
                    303:         uint32_t ei;
                    304:         for (ei = 0; ei < 8; ++ei) {
                    305:             entry[6][ei].vaddr = ei << 29;
                    306:             entry[6][ei].paddr = ei << 29;
                    307:             entry[6][ei].asid = 1;
                    308:             entry[6][ei].attr = 3;
                    309:         }
                    310:     }
                    311: }
                    312: 
1.1.1.2 ! root      313: static void reset_tlb_region_way0(CPUXtensaState *env,
1.1       root      314:         xtensa_tlb_entry entry[][MAX_TLB_WAY_SIZE])
                    315: {
                    316:     unsigned ei;
                    317: 
                    318:     for (ei = 0; ei < 8; ++ei) {
                    319:         entry[0][ei].vaddr = ei << 29;
                    320:         entry[0][ei].paddr = ei << 29;
                    321:         entry[0][ei].asid = 1;
                    322:         entry[0][ei].attr = 2;
                    323:         entry[0][ei].variable = true;
                    324:     }
                    325: }
                    326: 
1.1.1.2 ! root      327: void reset_mmu(CPUXtensaState *env)
1.1       root      328: {
                    329:     if (xtensa_option_enabled(env->config, XTENSA_OPTION_MMU)) {
                    330:         env->sregs[RASID] = 0x04030201;
                    331:         env->sregs[ITLBCFG] = 0;
                    332:         env->sregs[DTLBCFG] = 0;
                    333:         env->autorefill_idx = 0;
                    334:         reset_tlb_mmu_all_ways(env, &env->config->itlb, env->itlb);
                    335:         reset_tlb_mmu_all_ways(env, &env->config->dtlb, env->dtlb);
                    336:         reset_tlb_mmu_ways56(env, &env->config->itlb, env->itlb);
                    337:         reset_tlb_mmu_ways56(env, &env->config->dtlb, env->dtlb);
                    338:     } else {
                    339:         reset_tlb_region_way0(env, env->itlb);
                    340:         reset_tlb_region_way0(env, env->dtlb);
                    341:     }
                    342: }
                    343: 
1.1.1.2 ! root      344: static unsigned get_ring(const CPUXtensaState *env, uint8_t asid)
1.1       root      345: {
                    346:     unsigned i;
                    347:     for (i = 0; i < 4; ++i) {
                    348:         if (((env->sregs[RASID] >> i * 8) & 0xff) == asid) {
                    349:             return i;
                    350:         }
                    351:     }
                    352:     return 0xff;
                    353: }
                    354: 
                    355: /*!
                    356:  * Lookup xtensa TLB for the given virtual address.
                    357:  * See ISA, 4.6.2.2
                    358:  *
                    359:  * \param pwi: [out] way index
                    360:  * \param pei: [out] entry index
                    361:  * \param pring: [out] access ring
                    362:  * \return 0 if ok, exception cause code otherwise
                    363:  */
1.1.1.2 ! root      364: int xtensa_tlb_lookup(const CPUXtensaState *env, uint32_t addr, bool dtlb,
1.1       root      365:         uint32_t *pwi, uint32_t *pei, uint8_t *pring)
                    366: {
                    367:     const xtensa_tlb *tlb = dtlb ?
                    368:         &env->config->dtlb : &env->config->itlb;
                    369:     const xtensa_tlb_entry (*entry)[MAX_TLB_WAY_SIZE] = dtlb ?
                    370:         env->dtlb : env->itlb;
                    371: 
                    372:     int nhits = 0;
                    373:     unsigned wi;
                    374: 
                    375:     for (wi = 0; wi < tlb->nways; ++wi) {
                    376:         uint32_t vpn;
                    377:         uint32_t ei;
                    378:         split_tlb_entry_spec_way(env, addr, dtlb, &vpn, wi, &ei);
                    379:         if (entry[wi][ei].vaddr == vpn && entry[wi][ei].asid) {
                    380:             unsigned ring = get_ring(env, entry[wi][ei].asid);
                    381:             if (ring < 4) {
                    382:                 if (++nhits > 1) {
                    383:                     return dtlb ?
                    384:                         LOAD_STORE_TLB_MULTI_HIT_CAUSE :
                    385:                         INST_TLB_MULTI_HIT_CAUSE;
                    386:                 }
                    387:                 *pwi = wi;
                    388:                 *pei = ei;
                    389:                 *pring = ring;
                    390:             }
                    391:         }
                    392:     }
                    393:     return nhits ? 0 :
                    394:         (dtlb ? LOAD_STORE_TLB_MISS_CAUSE : INST_TLB_MISS_CAUSE);
                    395: }
                    396: 
                    397: /*!
                    398:  * Convert MMU ATTR to PAGE_{READ,WRITE,EXEC} mask.
                    399:  * See ISA, 4.6.5.10
                    400:  */
                    401: static unsigned mmu_attr_to_access(uint32_t attr)
                    402: {
                    403:     unsigned access = 0;
                    404:     if (attr < 12) {
                    405:         access |= PAGE_READ;
                    406:         if (attr & 0x1) {
                    407:             access |= PAGE_EXEC;
                    408:         }
                    409:         if (attr & 0x2) {
                    410:             access |= PAGE_WRITE;
                    411:         }
                    412:     } else if (attr == 13) {
                    413:         access |= PAGE_READ | PAGE_WRITE;
                    414:     }
                    415:     return access;
                    416: }
                    417: 
                    418: /*!
                    419:  * Convert region protection ATTR to PAGE_{READ,WRITE,EXEC} mask.
                    420:  * See ISA, 4.6.3.3
                    421:  */
                    422: static unsigned region_attr_to_access(uint32_t attr)
                    423: {
                    424:     unsigned access = 0;
                    425:     if ((attr < 6 && attr != 3) || attr == 14) {
                    426:         access |= PAGE_READ | PAGE_WRITE;
                    427:     }
                    428:     if (attr > 0 && attr < 6) {
                    429:         access |= PAGE_EXEC;
                    430:     }
                    431:     return access;
                    432: }
                    433: 
                    434: static bool is_access_granted(unsigned access, int is_write)
                    435: {
                    436:     switch (is_write) {
                    437:     case 0:
                    438:         return access & PAGE_READ;
                    439: 
                    440:     case 1:
                    441:         return access & PAGE_WRITE;
                    442: 
                    443:     case 2:
                    444:         return access & PAGE_EXEC;
                    445: 
                    446:     default:
                    447:         return 0;
                    448:     }
                    449: }
                    450: 
1.1.1.2 ! root      451: static int get_pte(CPUXtensaState *env, uint32_t vaddr, uint32_t *pte);
1.1       root      452: 
1.1.1.2 ! root      453: static int get_physical_addr_mmu(CPUXtensaState *env, bool update_tlb,
1.1       root      454:         uint32_t vaddr, int is_write, int mmu_idx,
1.1.1.2 ! root      455:         uint32_t *paddr, uint32_t *page_size, unsigned *access,
        !           456:         bool may_lookup_pt)
1.1       root      457: {
                    458:     bool dtlb = is_write != 2;
                    459:     uint32_t wi;
                    460:     uint32_t ei;
                    461:     uint8_t ring;
1.1.1.2 ! root      462:     uint32_t vpn;
        !           463:     uint32_t pte;
        !           464:     const xtensa_tlb_entry *entry = NULL;
        !           465:     xtensa_tlb_entry tmp_entry;
1.1       root      466:     int ret = xtensa_tlb_lookup(env, vaddr, dtlb, &wi, &ei, &ring);
                    467: 
                    468:     if ((ret == INST_TLB_MISS_CAUSE || ret == LOAD_STORE_TLB_MISS_CAUSE) &&
1.1.1.2 ! root      469:             may_lookup_pt && get_pte(env, vaddr, &pte) == 0) {
        !           470:         ring = (pte >> 4) & 0x3;
        !           471:         wi = 0;
        !           472:         split_tlb_entry_spec_way(env, vaddr, dtlb, &vpn, wi, &ei);
        !           473: 
        !           474:         if (update_tlb) {
        !           475:             wi = ++env->autorefill_idx & 0x3;
        !           476:             xtensa_tlb_set_entry(env, dtlb, wi, ei, vpn, pte);
        !           477:             env->sregs[EXCVADDR] = vaddr;
        !           478:             qemu_log("%s: autorefill(%08x): %08x -> %08x\n",
        !           479:                     __func__, vaddr, vpn, pte);
        !           480:         } else {
        !           481:             xtensa_tlb_set_entry_mmu(env, &tmp_entry, dtlb, wi, ei, vpn, pte);
        !           482:             entry = &tmp_entry;
        !           483:         }
1.1       root      484:         ret = 0;
                    485:     }
                    486:     if (ret != 0) {
                    487:         return ret;
                    488:     }
                    489: 
1.1.1.2 ! root      490:     if (entry == NULL) {
        !           491:         entry = xtensa_tlb_get_entry(env, dtlb, wi, ei);
        !           492:     }
1.1       root      493: 
                    494:     if (ring < mmu_idx) {
                    495:         return dtlb ?
                    496:             LOAD_STORE_PRIVILEGE_CAUSE :
                    497:             INST_FETCH_PRIVILEGE_CAUSE;
                    498:     }
                    499: 
                    500:     *access = mmu_attr_to_access(entry->attr);
                    501:     if (!is_access_granted(*access, is_write)) {
                    502:         return dtlb ?
                    503:             (is_write ?
                    504:              STORE_PROHIBITED_CAUSE :
                    505:              LOAD_PROHIBITED_CAUSE) :
                    506:             INST_FETCH_PROHIBITED_CAUSE;
                    507:     }
                    508: 
                    509:     *paddr = entry->paddr | (vaddr & ~xtensa_tlb_get_addr_mask(env, dtlb, wi));
                    510:     *page_size = ~xtensa_tlb_get_addr_mask(env, dtlb, wi) + 1;
                    511: 
                    512:     return 0;
                    513: }
                    514: 
1.1.1.2 ! root      515: static int get_pte(CPUXtensaState *env, uint32_t vaddr, uint32_t *pte)
1.1       root      516: {
                    517:     uint32_t paddr;
                    518:     uint32_t page_size;
                    519:     unsigned access;
                    520:     uint32_t pt_vaddr =
                    521:         (env->sregs[PTEVADDR] | (vaddr >> 10)) & 0xfffffffc;
1.1.1.2 ! root      522:     int ret = get_physical_addr_mmu(env, false, pt_vaddr, 0, 0,
        !           523:             &paddr, &page_size, &access, false);
1.1       root      524: 
                    525:     qemu_log("%s: trying autorefill(%08x) -> %08x\n", __func__,
                    526:             vaddr, ret ? ~0 : paddr);
                    527: 
                    528:     if (ret == 0) {
1.1.1.2 ! root      529:         *pte = ldl_phys(paddr);
1.1       root      530:     }
                    531:     return ret;
                    532: }
                    533: 
1.1.1.2 ! root      534: static int get_physical_addr_region(CPUXtensaState *env,
1.1       root      535:         uint32_t vaddr, int is_write, int mmu_idx,
                    536:         uint32_t *paddr, uint32_t *page_size, unsigned *access)
                    537: {
                    538:     bool dtlb = is_write != 2;
                    539:     uint32_t wi = 0;
                    540:     uint32_t ei = (vaddr >> 29) & 0x7;
                    541:     const xtensa_tlb_entry *entry =
                    542:         xtensa_tlb_get_entry(env, dtlb, wi, ei);
                    543: 
                    544:     *access = region_attr_to_access(entry->attr);
                    545:     if (!is_access_granted(*access, is_write)) {
                    546:         return dtlb ?
                    547:             (is_write ?
                    548:              STORE_PROHIBITED_CAUSE :
                    549:              LOAD_PROHIBITED_CAUSE) :
                    550:             INST_FETCH_PROHIBITED_CAUSE;
                    551:     }
                    552: 
                    553:     *paddr = entry->paddr | (vaddr & ~REGION_PAGE_MASK);
                    554:     *page_size = ~REGION_PAGE_MASK + 1;
                    555: 
                    556:     return 0;
                    557: }
                    558: 
                    559: /*!
                    560:  * Convert virtual address to physical addr.
                    561:  * MMU may issue pagewalk and change xtensa autorefill TLB way entry.
                    562:  *
                    563:  * \return 0 if ok, exception cause code otherwise
                    564:  */
1.1.1.2 ! root      565: int xtensa_get_physical_addr(CPUXtensaState *env, bool update_tlb,
1.1       root      566:         uint32_t vaddr, int is_write, int mmu_idx,
                    567:         uint32_t *paddr, uint32_t *page_size, unsigned *access)
                    568: {
                    569:     if (xtensa_option_enabled(env->config, XTENSA_OPTION_MMU)) {
1.1.1.2 ! root      570:         return get_physical_addr_mmu(env, update_tlb,
        !           571:                 vaddr, is_write, mmu_idx, paddr, page_size, access, true);
1.1       root      572:     } else if (xtensa_option_bits_enabled(env->config,
                    573:                 XTENSA_OPTION_BIT(XTENSA_OPTION_REGION_PROTECTION) |
                    574:                 XTENSA_OPTION_BIT(XTENSA_OPTION_REGION_TRANSLATION))) {
                    575:         return get_physical_addr_region(env, vaddr, is_write, mmu_idx,
                    576:                 paddr, page_size, access);
                    577:     } else {
                    578:         *paddr = vaddr;
                    579:         *page_size = TARGET_PAGE_SIZE;
                    580:         *access = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
                    581:         return 0;
                    582:     }
                    583: }
1.1.1.2 ! root      584: 
        !           585: static void dump_tlb(FILE *f, fprintf_function cpu_fprintf,
        !           586:         CPUXtensaState *env, bool dtlb)
        !           587: {
        !           588:     unsigned wi, ei;
        !           589:     const xtensa_tlb *conf =
        !           590:         dtlb ? &env->config->dtlb : &env->config->itlb;
        !           591:     unsigned (*attr_to_access)(uint32_t) =
        !           592:         xtensa_option_enabled(env->config, XTENSA_OPTION_MMU) ?
        !           593:         mmu_attr_to_access : region_attr_to_access;
        !           594: 
        !           595:     for (wi = 0; wi < conf->nways; ++wi) {
        !           596:         uint32_t sz = ~xtensa_tlb_get_addr_mask(env, dtlb, wi) + 1;
        !           597:         const char *sz_text;
        !           598:         bool print_header = true;
        !           599: 
        !           600:         if (sz >= 0x100000) {
        !           601:             sz >>= 20;
        !           602:             sz_text = "MB";
        !           603:         } else {
        !           604:             sz >>= 10;
        !           605:             sz_text = "KB";
        !           606:         }
        !           607: 
        !           608:         for (ei = 0; ei < conf->way_size[wi]; ++ei) {
        !           609:             const xtensa_tlb_entry *entry =
        !           610:                 xtensa_tlb_get_entry(env, dtlb, wi, ei);
        !           611: 
        !           612:             if (entry->asid) {
        !           613:                 unsigned access = attr_to_access(entry->attr);
        !           614: 
        !           615:                 if (print_header) {
        !           616:                     print_header = false;
        !           617:                     cpu_fprintf(f, "Way %u (%d %s)\n", wi, sz, sz_text);
        !           618:                     cpu_fprintf(f,
        !           619:                             "\tVaddr       Paddr       ASID  Attr RWX\n"
        !           620:                             "\t----------  ----------  ----  ---- ---\n");
        !           621:                 }
        !           622:                 cpu_fprintf(f,
        !           623:                         "\t0x%08x  0x%08x  0x%02x  0x%02x %c%c%c\n",
        !           624:                         entry->vaddr,
        !           625:                         entry->paddr,
        !           626:                         entry->asid,
        !           627:                         entry->attr,
        !           628:                         (access & PAGE_READ) ? 'R' : '-',
        !           629:                         (access & PAGE_WRITE) ? 'W' : '-',
        !           630:                         (access & PAGE_EXEC) ? 'X' : '-');
        !           631:             }
        !           632:         }
        !           633:     }
        !           634: }
        !           635: 
        !           636: void dump_mmu(FILE *f, fprintf_function cpu_fprintf, CPUXtensaState *env)
        !           637: {
        !           638:     if (xtensa_option_bits_enabled(env->config,
        !           639:                 XTENSA_OPTION_BIT(XTENSA_OPTION_REGION_PROTECTION) |
        !           640:                 XTENSA_OPTION_BIT(XTENSA_OPTION_REGION_TRANSLATION) |
        !           641:                 XTENSA_OPTION_BIT(XTENSA_OPTION_MMU))) {
        !           642: 
        !           643:         cpu_fprintf(f, "ITLB:\n");
        !           644:         dump_tlb(f, cpu_fprintf, env, false);
        !           645:         cpu_fprintf(f, "\nDTLB:\n");
        !           646:         dump_tlb(f, cpu_fprintf, env, true);
        !           647:     } else {
        !           648:         cpu_fprintf(f, "No TLB for this CPU core\n");
        !           649:     }
        !           650: }

unix.superglobalmegacorp.com