qemu/target/xtensa/helper.c
<<
>>
Prefs
   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 "qemu/osdep.h"
  29#include "cpu.h"
  30#include "exec/exec-all.h"
  31#include "exec/gdbstub.h"
  32#include "qemu/host-utils.h"
  33#if !defined(CONFIG_USER_ONLY)
  34#include "hw/loader.h"
  35#endif
  36
  37static struct XtensaConfigList *xtensa_cores;
  38
  39static void xtensa_core_class_init(ObjectClass *oc, void *data)
  40{
  41    CPUClass *cc = CPU_CLASS(oc);
  42    XtensaCPUClass *xcc = XTENSA_CPU_CLASS(oc);
  43    const XtensaConfig *config = data;
  44
  45    xcc->config = config;
  46
  47    /* Use num_core_regs to see only non-privileged registers in an unmodified
  48     * gdb. Use num_regs to see all registers. gdb modification is required
  49     * for that: reset bit 0 in the 'flags' field of the registers definitions
  50     * in the gdb/xtensa-config.c inside gdb source tree or inside gdb overlay.
  51     */
  52    cc->gdb_num_core_regs = config->gdb_regmap.num_regs;
  53}
  54
  55static void init_libisa(XtensaConfig *config)
  56{
  57    unsigned i, j;
  58    unsigned opcodes;
  59
  60    config->isa = xtensa_isa_init(config->isa_internal, NULL, NULL);
  61    assert(xtensa_isa_maxlength(config->isa) <= MAX_INSN_LENGTH);
  62    opcodes = xtensa_isa_num_opcodes(config->isa);
  63    config->opcode_ops = g_new(XtensaOpcodeOps *, opcodes);
  64
  65    for (i = 0; i < opcodes; ++i) {
  66        const char *opc_name = xtensa_opcode_name(config->isa, i);
  67        XtensaOpcodeOps *ops = NULL;
  68
  69        assert(xtensa_opcode_num_operands(config->isa, i) <= MAX_OPCODE_ARGS);
  70        if (!config->opcode_translators) {
  71            ops = xtensa_find_opcode_ops(&xtensa_core_opcodes, opc_name);
  72        } else {
  73            for (j = 0; !ops && config->opcode_translators[j]; ++j) {
  74                ops = xtensa_find_opcode_ops(config->opcode_translators[j],
  75                                             opc_name);
  76            }
  77        }
  78#ifdef DEBUG
  79        if (ops == NULL) {
  80            fprintf(stderr,
  81                    "opcode translator not found for %s's opcode '%s'\n",
  82                    config->name, opc_name);
  83        }
  84#endif
  85        config->opcode_ops[i] = ops;
  86    }
  87}
  88
  89void xtensa_finalize_config(XtensaConfig *config)
  90{
  91    if (config->isa_internal) {
  92        init_libisa(config);
  93    }
  94
  95    if (config->gdb_regmap.num_regs == 0 ||
  96        config->gdb_regmap.num_core_regs == 0) {
  97        unsigned i;
  98        unsigned n_regs = 0;
  99        unsigned n_core_regs = 0;
 100
 101        for (i = 0; config->gdb_regmap.reg[i].targno >= 0; ++i) {
 102            if (config->gdb_regmap.reg[i].type != 6) {
 103                ++n_regs;
 104                if ((config->gdb_regmap.reg[i].flags & 0x1) == 0) {
 105                    ++n_core_regs;
 106                }
 107            }
 108        }
 109        if (config->gdb_regmap.num_regs == 0) {
 110            config->gdb_regmap.num_regs = n_regs;
 111        }
 112        if (config->gdb_regmap.num_core_regs == 0) {
 113            config->gdb_regmap.num_core_regs = n_core_regs;
 114        }
 115    }
 116}
 117
 118void xtensa_register_core(XtensaConfigList *node)
 119{
 120    TypeInfo type = {
 121        .parent = TYPE_XTENSA_CPU,
 122        .class_init = xtensa_core_class_init,
 123        .class_data = (void *)node->config,
 124    };
 125
 126    node->next = xtensa_cores;
 127    xtensa_cores = node;
 128    type.name = g_strdup_printf(XTENSA_CPU_TYPE_NAME("%s"), node->config->name);
 129    type_register(&type);
 130    g_free((gpointer)type.name);
 131}
 132
 133static uint32_t check_hw_breakpoints(CPUXtensaState *env)
 134{
 135    unsigned i;
 136
 137    for (i = 0; i < env->config->ndbreak; ++i) {
 138        if (env->cpu_watchpoint[i] &&
 139                env->cpu_watchpoint[i]->flags & BP_WATCHPOINT_HIT) {
 140            return DEBUGCAUSE_DB | (i << DEBUGCAUSE_DBNUM_SHIFT);
 141        }
 142    }
 143    return 0;
 144}
 145
 146void xtensa_breakpoint_handler(CPUState *cs)
 147{
 148    XtensaCPU *cpu = XTENSA_CPU(cs);
 149    CPUXtensaState *env = &cpu->env;
 150
 151    if (cs->watchpoint_hit) {
 152        if (cs->watchpoint_hit->flags & BP_CPU) {
 153            uint32_t cause;
 154
 155            cs->watchpoint_hit = NULL;
 156            cause = check_hw_breakpoints(env);
 157            if (cause) {
 158                debug_exception_env(env, cause);
 159            }
 160            cpu_loop_exit_noexc(cs);
 161        }
 162    }
 163}
 164
 165void xtensa_cpu_list(FILE *f, fprintf_function cpu_fprintf)
 166{
 167    XtensaConfigList *core = xtensa_cores;
 168    cpu_fprintf(f, "Available CPUs:\n");
 169    for (; core; core = core->next) {
 170        cpu_fprintf(f, "  %s\n", core->config->name);
 171    }
 172}
 173
 174hwaddr xtensa_cpu_get_phys_page_debug(CPUState *cs, vaddr addr)
 175{
 176#ifndef CONFIG_USER_ONLY
 177    XtensaCPU *cpu = XTENSA_CPU(cs);
 178    uint32_t paddr;
 179    uint32_t page_size;
 180    unsigned access;
 181
 182    if (xtensa_get_physical_addr(&cpu->env, false, addr, 0, 0,
 183                &paddr, &page_size, &access) == 0) {
 184        return paddr;
 185    }
 186    if (xtensa_get_physical_addr(&cpu->env, false, addr, 2, 0,
 187                &paddr, &page_size, &access) == 0) {
 188        return paddr;
 189    }
 190    return ~0;
 191#else
 192    return addr;
 193#endif
 194}
 195
 196#ifndef CONFIG_USER_ONLY
 197
 198static uint32_t relocated_vector(CPUXtensaState *env, uint32_t vector)
 199{
 200    if (xtensa_option_enabled(env->config,
 201                XTENSA_OPTION_RELOCATABLE_VECTOR)) {
 202        return vector - env->config->vecbase + env->sregs[VECBASE];
 203    } else {
 204        return vector;
 205    }
 206}
 207
 208/*!
 209 * Handle penging IRQ.
 210 * For the high priority interrupt jump to the corresponding interrupt vector.
 211 * For the level-1 interrupt convert it to either user, kernel or double
 212 * exception with the 'level-1 interrupt' exception cause.
 213 */
 214static void handle_interrupt(CPUXtensaState *env)
 215{
 216    int level = env->pending_irq_level;
 217
 218    if (level > xtensa_get_cintlevel(env) &&
 219            level <= env->config->nlevel &&
 220            (env->config->level_mask[level] &
 221             env->sregs[INTSET] &
 222             env->sregs[INTENABLE])) {
 223        CPUState *cs = CPU(xtensa_env_get_cpu(env));
 224
 225        if (level > 1) {
 226            env->sregs[EPC1 + level - 1] = env->pc;
 227            env->sregs[EPS2 + level - 2] = env->sregs[PS];
 228            env->sregs[PS] =
 229                (env->sregs[PS] & ~PS_INTLEVEL) | level | PS_EXCM;
 230            env->pc = relocated_vector(env,
 231                    env->config->interrupt_vector[level]);
 232        } else {
 233            env->sregs[EXCCAUSE] = LEVEL1_INTERRUPT_CAUSE;
 234
 235            if (env->sregs[PS] & PS_EXCM) {
 236                if (env->config->ndepc) {
 237                    env->sregs[DEPC] = env->pc;
 238                } else {
 239                    env->sregs[EPC1] = env->pc;
 240                }
 241                cs->exception_index = EXC_DOUBLE;
 242            } else {
 243                env->sregs[EPC1] = env->pc;
 244                cs->exception_index =
 245                    (env->sregs[PS] & PS_UM) ? EXC_USER : EXC_KERNEL;
 246            }
 247            env->sregs[PS] |= PS_EXCM;
 248        }
 249        env->exception_taken = 1;
 250    }
 251}
 252
 253/* Called from cpu_handle_interrupt with BQL held */
 254void xtensa_cpu_do_interrupt(CPUState *cs)
 255{
 256    XtensaCPU *cpu = XTENSA_CPU(cs);
 257    CPUXtensaState *env = &cpu->env;
 258
 259    if (cs->exception_index == EXC_IRQ) {
 260        qemu_log_mask(CPU_LOG_INT,
 261                "%s(EXC_IRQ) level = %d, cintlevel = %d, "
 262                "pc = %08x, a0 = %08x, ps = %08x, "
 263                "intset = %08x, intenable = %08x, "
 264                "ccount = %08x\n",
 265                __func__, env->pending_irq_level, xtensa_get_cintlevel(env),
 266                env->pc, env->regs[0], env->sregs[PS],
 267                env->sregs[INTSET], env->sregs[INTENABLE],
 268                env->sregs[CCOUNT]);
 269        handle_interrupt(env);
 270    }
 271
 272    switch (cs->exception_index) {
 273    case EXC_WINDOW_OVERFLOW4:
 274    case EXC_WINDOW_UNDERFLOW4:
 275    case EXC_WINDOW_OVERFLOW8:
 276    case EXC_WINDOW_UNDERFLOW8:
 277    case EXC_WINDOW_OVERFLOW12:
 278    case EXC_WINDOW_UNDERFLOW12:
 279    case EXC_KERNEL:
 280    case EXC_USER:
 281    case EXC_DOUBLE:
 282    case EXC_DEBUG:
 283        qemu_log_mask(CPU_LOG_INT, "%s(%d) "
 284                "pc = %08x, a0 = %08x, ps = %08x, ccount = %08x\n",
 285                __func__, cs->exception_index,
 286                env->pc, env->regs[0], env->sregs[PS], env->sregs[CCOUNT]);
 287        if (env->config->exception_vector[cs->exception_index]) {
 288            env->pc = relocated_vector(env,
 289                    env->config->exception_vector[cs->exception_index]);
 290            env->exception_taken = 1;
 291        } else {
 292            qemu_log_mask(CPU_LOG_INT, "%s(pc = %08x) bad exception_index: %d\n",
 293                          __func__, env->pc, cs->exception_index);
 294        }
 295        break;
 296
 297    case EXC_IRQ:
 298        break;
 299
 300    default:
 301        qemu_log("%s(pc = %08x) unknown exception_index: %d\n",
 302                __func__, env->pc, cs->exception_index);
 303        break;
 304    }
 305    check_interrupts(env);
 306}
 307#else
 308void xtensa_cpu_do_interrupt(CPUState *cs)
 309{
 310}
 311#endif
 312
 313bool xtensa_cpu_exec_interrupt(CPUState *cs, int interrupt_request)
 314{
 315    if (interrupt_request & CPU_INTERRUPT_HARD) {
 316        cs->exception_index = EXC_IRQ;
 317        xtensa_cpu_do_interrupt(cs);
 318        return true;
 319    }
 320    return false;
 321}
 322
 323#ifdef CONFIG_USER_ONLY
 324
 325int xtensa_cpu_handle_mmu_fault(CPUState *cs, vaddr address, int size, int rw,
 326                                int mmu_idx)
 327{
 328    XtensaCPU *cpu = XTENSA_CPU(cs);
 329    CPUXtensaState *env = &cpu->env;
 330
 331    qemu_log_mask(CPU_LOG_INT,
 332                  "%s: rw = %d, address = 0x%08" VADDR_PRIx ", size = %d\n",
 333                  __func__, rw, address, size);
 334    env->sregs[EXCVADDR] = address;
 335    env->sregs[EXCCAUSE] = rw ? STORE_PROHIBITED_CAUSE : LOAD_PROHIBITED_CAUSE;
 336    cs->exception_index = EXC_USER;
 337    return 1;
 338}
 339
 340#else
 341
 342static void reset_tlb_mmu_all_ways(CPUXtensaState *env,
 343        const xtensa_tlb *tlb, xtensa_tlb_entry entry[][MAX_TLB_WAY_SIZE])
 344{
 345    unsigned wi, ei;
 346
 347    for (wi = 0; wi < tlb->nways; ++wi) {
 348        for (ei = 0; ei < tlb->way_size[wi]; ++ei) {
 349            entry[wi][ei].asid = 0;
 350            entry[wi][ei].variable = true;
 351        }
 352    }
 353}
 354
 355static void reset_tlb_mmu_ways56(CPUXtensaState *env,
 356        const xtensa_tlb *tlb, xtensa_tlb_entry entry[][MAX_TLB_WAY_SIZE])
 357{
 358    if (!tlb->varway56) {
 359        static const xtensa_tlb_entry way5[] = {
 360            {
 361                .vaddr = 0xd0000000,
 362                .paddr = 0,
 363                .asid = 1,
 364                .attr = 7,
 365                .variable = false,
 366            }, {
 367                .vaddr = 0xd8000000,
 368                .paddr = 0,
 369                .asid = 1,
 370                .attr = 3,
 371                .variable = false,
 372            }
 373        };
 374        static const xtensa_tlb_entry way6[] = {
 375            {
 376                .vaddr = 0xe0000000,
 377                .paddr = 0xf0000000,
 378                .asid = 1,
 379                .attr = 7,
 380                .variable = false,
 381            }, {
 382                .vaddr = 0xf0000000,
 383                .paddr = 0xf0000000,
 384                .asid = 1,
 385                .attr = 3,
 386                .variable = false,
 387            }
 388        };
 389        memcpy(entry[5], way5, sizeof(way5));
 390        memcpy(entry[6], way6, sizeof(way6));
 391    } else {
 392        uint32_t ei;
 393        for (ei = 0; ei < 8; ++ei) {
 394            entry[6][ei].vaddr = ei << 29;
 395            entry[6][ei].paddr = ei << 29;
 396            entry[6][ei].asid = 1;
 397            entry[6][ei].attr = 3;
 398        }
 399    }
 400}
 401
 402static void reset_tlb_region_way0(CPUXtensaState *env,
 403        xtensa_tlb_entry entry[][MAX_TLB_WAY_SIZE])
 404{
 405    unsigned ei;
 406
 407    for (ei = 0; ei < 8; ++ei) {
 408        entry[0][ei].vaddr = ei << 29;
 409        entry[0][ei].paddr = ei << 29;
 410        entry[0][ei].asid = 1;
 411        entry[0][ei].attr = 2;
 412        entry[0][ei].variable = true;
 413    }
 414}
 415
 416void reset_mmu(CPUXtensaState *env)
 417{
 418    if (xtensa_option_enabled(env->config, XTENSA_OPTION_MMU)) {
 419        env->sregs[RASID] = 0x04030201;
 420        env->sregs[ITLBCFG] = 0;
 421        env->sregs[DTLBCFG] = 0;
 422        env->autorefill_idx = 0;
 423        reset_tlb_mmu_all_ways(env, &env->config->itlb, env->itlb);
 424        reset_tlb_mmu_all_ways(env, &env->config->dtlb, env->dtlb);
 425        reset_tlb_mmu_ways56(env, &env->config->itlb, env->itlb);
 426        reset_tlb_mmu_ways56(env, &env->config->dtlb, env->dtlb);
 427    } else {
 428        reset_tlb_region_way0(env, env->itlb);
 429        reset_tlb_region_way0(env, env->dtlb);
 430    }
 431}
 432
 433static unsigned get_ring(const CPUXtensaState *env, uint8_t asid)
 434{
 435    unsigned i;
 436    for (i = 0; i < 4; ++i) {
 437        if (((env->sregs[RASID] >> i * 8) & 0xff) == asid) {
 438            return i;
 439        }
 440    }
 441    return 0xff;
 442}
 443
 444/*!
 445 * Lookup xtensa TLB for the given virtual address.
 446 * See ISA, 4.6.2.2
 447 *
 448 * \param pwi: [out] way index
 449 * \param pei: [out] entry index
 450 * \param pring: [out] access ring
 451 * \return 0 if ok, exception cause code otherwise
 452 */
 453int xtensa_tlb_lookup(const CPUXtensaState *env, uint32_t addr, bool dtlb,
 454        uint32_t *pwi, uint32_t *pei, uint8_t *pring)
 455{
 456    const xtensa_tlb *tlb = dtlb ?
 457        &env->config->dtlb : &env->config->itlb;
 458    const xtensa_tlb_entry (*entry)[MAX_TLB_WAY_SIZE] = dtlb ?
 459        env->dtlb : env->itlb;
 460
 461    int nhits = 0;
 462    unsigned wi;
 463
 464    for (wi = 0; wi < tlb->nways; ++wi) {
 465        uint32_t vpn;
 466        uint32_t ei;
 467        split_tlb_entry_spec_way(env, addr, dtlb, &vpn, wi, &ei);
 468        if (entry[wi][ei].vaddr == vpn && entry[wi][ei].asid) {
 469            unsigned ring = get_ring(env, entry[wi][ei].asid);
 470            if (ring < 4) {
 471                if (++nhits > 1) {
 472                    return dtlb ?
 473                        LOAD_STORE_TLB_MULTI_HIT_CAUSE :
 474                        INST_TLB_MULTI_HIT_CAUSE;
 475                }
 476                *pwi = wi;
 477                *pei = ei;
 478                *pring = ring;
 479            }
 480        }
 481    }
 482    return nhits ? 0 :
 483        (dtlb ? LOAD_STORE_TLB_MISS_CAUSE : INST_TLB_MISS_CAUSE);
 484}
 485
 486/*!
 487 * Convert MMU ATTR to PAGE_{READ,WRITE,EXEC} mask.
 488 * See ISA, 4.6.5.10
 489 */
 490static unsigned mmu_attr_to_access(uint32_t attr)
 491{
 492    unsigned access = 0;
 493
 494    if (attr < 12) {
 495        access |= PAGE_READ;
 496        if (attr & 0x1) {
 497            access |= PAGE_EXEC;
 498        }
 499        if (attr & 0x2) {
 500            access |= PAGE_WRITE;
 501        }
 502
 503        switch (attr & 0xc) {
 504        case 0:
 505            access |= PAGE_CACHE_BYPASS;
 506            break;
 507
 508        case 4:
 509            access |= PAGE_CACHE_WB;
 510            break;
 511
 512        case 8:
 513            access |= PAGE_CACHE_WT;
 514            break;
 515        }
 516    } else if (attr == 13) {
 517        access |= PAGE_READ | PAGE_WRITE | PAGE_CACHE_ISOLATE;
 518    }
 519    return access;
 520}
 521
 522/*!
 523 * Convert region protection ATTR to PAGE_{READ,WRITE,EXEC} mask.
 524 * See ISA, 4.6.3.3
 525 */
 526static unsigned region_attr_to_access(uint32_t attr)
 527{
 528    static const unsigned access[16] = {
 529         [0] = PAGE_READ | PAGE_WRITE             | PAGE_CACHE_WT,
 530         [1] = PAGE_READ | PAGE_WRITE | PAGE_EXEC | PAGE_CACHE_WT,
 531         [2] = PAGE_READ | PAGE_WRITE | PAGE_EXEC | PAGE_CACHE_BYPASS,
 532         [3] =                          PAGE_EXEC | PAGE_CACHE_WB,
 533         [4] = PAGE_READ | PAGE_WRITE | PAGE_EXEC | PAGE_CACHE_WB,
 534         [5] = PAGE_READ | PAGE_WRITE | PAGE_EXEC | PAGE_CACHE_WB,
 535        [14] = PAGE_READ | PAGE_WRITE             | PAGE_CACHE_ISOLATE,
 536    };
 537
 538    return access[attr & 0xf];
 539}
 540
 541/*!
 542 * Convert cacheattr to PAGE_{READ,WRITE,EXEC} mask.
 543 * See ISA, A.2.14 The Cache Attribute Register
 544 */
 545static unsigned cacheattr_attr_to_access(uint32_t attr)
 546{
 547    static const unsigned access[16] = {
 548         [0] = PAGE_READ | PAGE_WRITE             | PAGE_CACHE_WT,
 549         [1] = PAGE_READ | PAGE_WRITE | PAGE_EXEC | PAGE_CACHE_WT,
 550         [2] = PAGE_READ | PAGE_WRITE | PAGE_EXEC | PAGE_CACHE_BYPASS,
 551         [3] =                          PAGE_EXEC | PAGE_CACHE_WB,
 552         [4] = PAGE_READ | PAGE_WRITE | PAGE_EXEC | PAGE_CACHE_WB,
 553        [14] = PAGE_READ | PAGE_WRITE             | PAGE_CACHE_ISOLATE,
 554    };
 555
 556    return access[attr & 0xf];
 557}
 558
 559static bool is_access_granted(unsigned access, int is_write)
 560{
 561    switch (is_write) {
 562    case 0:
 563        return access & PAGE_READ;
 564
 565    case 1:
 566        return access & PAGE_WRITE;
 567
 568    case 2:
 569        return access & PAGE_EXEC;
 570
 571    default:
 572        return 0;
 573    }
 574}
 575
 576static int get_pte(CPUXtensaState *env, uint32_t vaddr, uint32_t *pte);
 577
 578static int get_physical_addr_mmu(CPUXtensaState *env, bool update_tlb,
 579        uint32_t vaddr, int is_write, int mmu_idx,
 580        uint32_t *paddr, uint32_t *page_size, unsigned *access,
 581        bool may_lookup_pt)
 582{
 583    bool dtlb = is_write != 2;
 584    uint32_t wi;
 585    uint32_t ei;
 586    uint8_t ring;
 587    uint32_t vpn;
 588    uint32_t pte;
 589    const xtensa_tlb_entry *entry = NULL;
 590    xtensa_tlb_entry tmp_entry;
 591    int ret = xtensa_tlb_lookup(env, vaddr, dtlb, &wi, &ei, &ring);
 592
 593    if ((ret == INST_TLB_MISS_CAUSE || ret == LOAD_STORE_TLB_MISS_CAUSE) &&
 594            may_lookup_pt && get_pte(env, vaddr, &pte) == 0) {
 595        ring = (pte >> 4) & 0x3;
 596        wi = 0;
 597        split_tlb_entry_spec_way(env, vaddr, dtlb, &vpn, wi, &ei);
 598
 599        if (update_tlb) {
 600            wi = ++env->autorefill_idx & 0x3;
 601            xtensa_tlb_set_entry(env, dtlb, wi, ei, vpn, pte);
 602            env->sregs[EXCVADDR] = vaddr;
 603            qemu_log_mask(CPU_LOG_MMU, "%s: autorefill(%08x): %08x -> %08x\n",
 604                          __func__, vaddr, vpn, pte);
 605        } else {
 606            xtensa_tlb_set_entry_mmu(env, &tmp_entry, dtlb, wi, ei, vpn, pte);
 607            entry = &tmp_entry;
 608        }
 609        ret = 0;
 610    }
 611    if (ret != 0) {
 612        return ret;
 613    }
 614
 615    if (entry == NULL) {
 616        entry = xtensa_tlb_get_entry(env, dtlb, wi, ei);
 617    }
 618
 619    if (ring < mmu_idx) {
 620        return dtlb ?
 621            LOAD_STORE_PRIVILEGE_CAUSE :
 622            INST_FETCH_PRIVILEGE_CAUSE;
 623    }
 624
 625    *access = mmu_attr_to_access(entry->attr) &
 626        ~(dtlb ? PAGE_EXEC : PAGE_READ | PAGE_WRITE);
 627    if (!is_access_granted(*access, is_write)) {
 628        return dtlb ?
 629            (is_write ?
 630             STORE_PROHIBITED_CAUSE :
 631             LOAD_PROHIBITED_CAUSE) :
 632            INST_FETCH_PROHIBITED_CAUSE;
 633    }
 634
 635    *paddr = entry->paddr | (vaddr & ~xtensa_tlb_get_addr_mask(env, dtlb, wi));
 636    *page_size = ~xtensa_tlb_get_addr_mask(env, dtlb, wi) + 1;
 637
 638    return 0;
 639}
 640
 641static int get_pte(CPUXtensaState *env, uint32_t vaddr, uint32_t *pte)
 642{
 643    CPUState *cs = CPU(xtensa_env_get_cpu(env));
 644    uint32_t paddr;
 645    uint32_t page_size;
 646    unsigned access;
 647    uint32_t pt_vaddr =
 648        (env->sregs[PTEVADDR] | (vaddr >> 10)) & 0xfffffffc;
 649    int ret = get_physical_addr_mmu(env, false, pt_vaddr, 0, 0,
 650            &paddr, &page_size, &access, false);
 651
 652    qemu_log_mask(CPU_LOG_MMU, "%s: trying autorefill(%08x) -> %08x\n",
 653                  __func__, vaddr, ret ? ~0 : paddr);
 654
 655    if (ret == 0) {
 656        *pte = ldl_phys(cs->as, paddr);
 657    }
 658    return ret;
 659}
 660
 661static int get_physical_addr_region(CPUXtensaState *env,
 662        uint32_t vaddr, int is_write, int mmu_idx,
 663        uint32_t *paddr, uint32_t *page_size, unsigned *access)
 664{
 665    bool dtlb = is_write != 2;
 666    uint32_t wi = 0;
 667    uint32_t ei = (vaddr >> 29) & 0x7;
 668    const xtensa_tlb_entry *entry =
 669        xtensa_tlb_get_entry(env, dtlb, wi, ei);
 670
 671    *access = region_attr_to_access(entry->attr);
 672    if (!is_access_granted(*access, is_write)) {
 673        return dtlb ?
 674            (is_write ?
 675             STORE_PROHIBITED_CAUSE :
 676             LOAD_PROHIBITED_CAUSE) :
 677            INST_FETCH_PROHIBITED_CAUSE;
 678    }
 679
 680    *paddr = entry->paddr | (vaddr & ~REGION_PAGE_MASK);
 681    *page_size = ~REGION_PAGE_MASK + 1;
 682
 683    return 0;
 684}
 685
 686/*!
 687 * Convert virtual address to physical addr.
 688 * MMU may issue pagewalk and change xtensa autorefill TLB way entry.
 689 *
 690 * \return 0 if ok, exception cause code otherwise
 691 */
 692int xtensa_get_physical_addr(CPUXtensaState *env, bool update_tlb,
 693        uint32_t vaddr, int is_write, int mmu_idx,
 694        uint32_t *paddr, uint32_t *page_size, unsigned *access)
 695{
 696    if (xtensa_option_enabled(env->config, XTENSA_OPTION_MMU)) {
 697        return get_physical_addr_mmu(env, update_tlb,
 698                vaddr, is_write, mmu_idx, paddr, page_size, access, true);
 699    } else if (xtensa_option_bits_enabled(env->config,
 700                XTENSA_OPTION_BIT(XTENSA_OPTION_REGION_PROTECTION) |
 701                XTENSA_OPTION_BIT(XTENSA_OPTION_REGION_TRANSLATION))) {
 702        return get_physical_addr_region(env, vaddr, is_write, mmu_idx,
 703                paddr, page_size, access);
 704    } else {
 705        *paddr = vaddr;
 706        *page_size = TARGET_PAGE_SIZE;
 707        *access = cacheattr_attr_to_access(
 708                env->sregs[CACHEATTR] >> ((vaddr & 0xe0000000) >> 27));
 709        return 0;
 710    }
 711}
 712
 713static void dump_tlb(FILE *f, fprintf_function cpu_fprintf,
 714        CPUXtensaState *env, bool dtlb)
 715{
 716    unsigned wi, ei;
 717    const xtensa_tlb *conf =
 718        dtlb ? &env->config->dtlb : &env->config->itlb;
 719    unsigned (*attr_to_access)(uint32_t) =
 720        xtensa_option_enabled(env->config, XTENSA_OPTION_MMU) ?
 721        mmu_attr_to_access : region_attr_to_access;
 722
 723    for (wi = 0; wi < conf->nways; ++wi) {
 724        uint32_t sz = ~xtensa_tlb_get_addr_mask(env, dtlb, wi) + 1;
 725        const char *sz_text;
 726        bool print_header = true;
 727
 728        if (sz >= 0x100000) {
 729            sz >>= 20;
 730            sz_text = "MB";
 731        } else {
 732            sz >>= 10;
 733            sz_text = "KB";
 734        }
 735
 736        for (ei = 0; ei < conf->way_size[wi]; ++ei) {
 737            const xtensa_tlb_entry *entry =
 738                xtensa_tlb_get_entry(env, dtlb, wi, ei);
 739
 740            if (entry->asid) {
 741                static const char * const cache_text[8] = {
 742                    [PAGE_CACHE_BYPASS >> PAGE_CACHE_SHIFT] = "Bypass",
 743                    [PAGE_CACHE_WT >> PAGE_CACHE_SHIFT] = "WT",
 744                    [PAGE_CACHE_WB >> PAGE_CACHE_SHIFT] = "WB",
 745                    [PAGE_CACHE_ISOLATE >> PAGE_CACHE_SHIFT] = "Isolate",
 746                };
 747                unsigned access = attr_to_access(entry->attr);
 748                unsigned cache_idx = (access & PAGE_CACHE_MASK) >>
 749                    PAGE_CACHE_SHIFT;
 750
 751                if (print_header) {
 752                    print_header = false;
 753                    cpu_fprintf(f, "Way %u (%d %s)\n", wi, sz, sz_text);
 754                    cpu_fprintf(f,
 755                            "\tVaddr       Paddr       ASID  Attr RWX Cache\n"
 756                            "\t----------  ----------  ----  ---- --- -------\n");
 757                }
 758                cpu_fprintf(f,
 759                        "\t0x%08x  0x%08x  0x%02x  0x%02x %c%c%c %-7s\n",
 760                        entry->vaddr,
 761                        entry->paddr,
 762                        entry->asid,
 763                        entry->attr,
 764                        (access & PAGE_READ) ? 'R' : '-',
 765                        (access & PAGE_WRITE) ? 'W' : '-',
 766                        (access & PAGE_EXEC) ? 'X' : '-',
 767                        cache_text[cache_idx] ? cache_text[cache_idx] :
 768                            "Invalid");
 769            }
 770        }
 771    }
 772}
 773
 774void dump_mmu(FILE *f, fprintf_function cpu_fprintf, CPUXtensaState *env)
 775{
 776    if (xtensa_option_bits_enabled(env->config,
 777                XTENSA_OPTION_BIT(XTENSA_OPTION_REGION_PROTECTION) |
 778                XTENSA_OPTION_BIT(XTENSA_OPTION_REGION_TRANSLATION) |
 779                XTENSA_OPTION_BIT(XTENSA_OPTION_MMU))) {
 780
 781        cpu_fprintf(f, "ITLB:\n");
 782        dump_tlb(f, cpu_fprintf, env, false);
 783        cpu_fprintf(f, "\nDTLB:\n");
 784        dump_tlb(f, cpu_fprintf, env, true);
 785    } else {
 786        cpu_fprintf(f, "No TLB for this CPU core\n");
 787    }
 788}
 789
 790void xtensa_runstall(CPUXtensaState *env, bool runstall)
 791{
 792    CPUState *cpu = CPU(xtensa_env_get_cpu(env));
 793
 794    env->runstall = runstall;
 795    cpu->halted = runstall;
 796    if (runstall) {
 797        cpu_interrupt(cpu, CPU_INTERRUPT_HALT);
 798    } else {
 799        cpu_reset_interrupt(cpu, CPU_INTERRUPT_HALT);
 800    }
 801}
 802#endif
 803