qemu/target/xtensa/mmu_helper.c
<<
>>
Prefs
   1/*
   2 * Copyright (c) 2011 - 2019, 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 "qemu/main-loop.h"
  30#include "qemu/units.h"
  31#include "cpu.h"
  32#include "exec/helper-proto.h"
  33#include "qemu/host-utils.h"
  34#include "exec/exec-all.h"
  35#include "exec/cpu_ldst.h"
  36
  37void HELPER(itlb_hit_test)(CPUXtensaState *env, uint32_t vaddr)
  38{
  39    /*
  40     * Attempt the memory load; we don't care about the result but
  41     * only the side-effects (ie any MMU or other exception)
  42     */
  43    cpu_ldub_code_ra(env, vaddr, GETPC());
  44}
  45
  46void HELPER(wsr_rasid)(CPUXtensaState *env, uint32_t v)
  47{
  48    XtensaCPU *cpu = xtensa_env_get_cpu(env);
  49
  50    v = (v & 0xffffff00) | 0x1;
  51    if (v != env->sregs[RASID]) {
  52        env->sregs[RASID] = v;
  53        tlb_flush(CPU(cpu));
  54    }
  55}
  56
  57static uint32_t get_page_size(const CPUXtensaState *env,
  58                              bool dtlb, uint32_t way)
  59{
  60    uint32_t tlbcfg = env->sregs[dtlb ? DTLBCFG : ITLBCFG];
  61
  62    switch (way) {
  63    case 4:
  64        return (tlbcfg >> 16) & 0x3;
  65
  66    case 5:
  67        return (tlbcfg >> 20) & 0x1;
  68
  69    case 6:
  70        return (tlbcfg >> 24) & 0x1;
  71
  72    default:
  73        return 0;
  74    }
  75}
  76
  77/*!
  78 * Get bit mask for the virtual address bits translated by the TLB way
  79 */
  80uint32_t xtensa_tlb_get_addr_mask(const CPUXtensaState *env,
  81                                  bool dtlb, uint32_t way)
  82{
  83    if (xtensa_option_enabled(env->config, XTENSA_OPTION_MMU)) {
  84        bool varway56 = dtlb ?
  85            env->config->dtlb.varway56 :
  86            env->config->itlb.varway56;
  87
  88        switch (way) {
  89        case 4:
  90            return 0xfff00000 << get_page_size(env, dtlb, way) * 2;
  91
  92        case 5:
  93            if (varway56) {
  94                return 0xf8000000 << get_page_size(env, dtlb, way);
  95            } else {
  96                return 0xf8000000;
  97            }
  98
  99        case 6:
 100            if (varway56) {
 101                return 0xf0000000 << (1 - get_page_size(env, dtlb, way));
 102            } else {
 103                return 0xf0000000;
 104            }
 105
 106        default:
 107            return 0xfffff000;
 108        }
 109    } else {
 110        return REGION_PAGE_MASK;
 111    }
 112}
 113
 114/*!
 115 * Get bit mask for the 'VPN without index' field.
 116 * See ISA, 4.6.5.6, data format for RxTLB0
 117 */
 118static uint32_t get_vpn_mask(const CPUXtensaState *env, bool dtlb, uint32_t way)
 119{
 120    if (way < 4) {
 121        bool is32 = (dtlb ?
 122                env->config->dtlb.nrefillentries :
 123                env->config->itlb.nrefillentries) == 32;
 124        return is32 ? 0xffff8000 : 0xffffc000;
 125    } else if (way == 4) {
 126        return xtensa_tlb_get_addr_mask(env, dtlb, way) << 2;
 127    } else if (way <= 6) {
 128        uint32_t mask = xtensa_tlb_get_addr_mask(env, dtlb, way);
 129        bool varway56 = dtlb ?
 130            env->config->dtlb.varway56 :
 131            env->config->itlb.varway56;
 132
 133        if (varway56) {
 134            return mask << (way == 5 ? 2 : 3);
 135        } else {
 136            return mask << 1;
 137        }
 138    } else {
 139        return 0xfffff000;
 140    }
 141}
 142
 143/*!
 144 * Split virtual address into VPN (with index) and entry index
 145 * for the given TLB way
 146 */
 147void split_tlb_entry_spec_way(const CPUXtensaState *env, uint32_t v, bool dtlb,
 148        uint32_t *vpn, uint32_t wi, uint32_t *ei)
 149{
 150    bool varway56 = dtlb ?
 151        env->config->dtlb.varway56 :
 152        env->config->itlb.varway56;
 153
 154    if (!dtlb) {
 155        wi &= 7;
 156    }
 157
 158    if (wi < 4) {
 159        bool is32 = (dtlb ?
 160                env->config->dtlb.nrefillentries :
 161                env->config->itlb.nrefillentries) == 32;
 162        *ei = (v >> 12) & (is32 ? 0x7 : 0x3);
 163    } else {
 164        switch (wi) {
 165        case 4:
 166            {
 167                uint32_t eibase = 20 + get_page_size(env, dtlb, wi) * 2;
 168                *ei = (v >> eibase) & 0x3;
 169            }
 170            break;
 171
 172        case 5:
 173            if (varway56) {
 174                uint32_t eibase = 27 + get_page_size(env, dtlb, wi);
 175                *ei = (v >> eibase) & 0x3;
 176            } else {
 177                *ei = (v >> 27) & 0x1;
 178            }
 179            break;
 180
 181        case 6:
 182            if (varway56) {
 183                uint32_t eibase = 29 - get_page_size(env, dtlb, wi);
 184                *ei = (v >> eibase) & 0x7;
 185            } else {
 186                *ei = (v >> 28) & 0x1;
 187            }
 188            break;
 189
 190        default:
 191            *ei = 0;
 192            break;
 193        }
 194    }
 195    *vpn = v & xtensa_tlb_get_addr_mask(env, dtlb, wi);
 196}
 197
 198/*!
 199 * Split TLB address into TLB way, entry index and VPN (with index).
 200 * See ISA, 4.6.5.5 - 4.6.5.8 for the TLB addressing format
 201 */
 202static void split_tlb_entry_spec(CPUXtensaState *env, uint32_t v, bool dtlb,
 203        uint32_t *vpn, uint32_t *wi, uint32_t *ei)
 204{
 205    if (xtensa_option_enabled(env->config, XTENSA_OPTION_MMU)) {
 206        *wi = v & (dtlb ? 0xf : 0x7);
 207        split_tlb_entry_spec_way(env, v, dtlb, vpn, *wi, ei);
 208    } else {
 209        *vpn = v & REGION_PAGE_MASK;
 210        *wi = 0;
 211        *ei = (v >> 29) & 0x7;
 212    }
 213}
 214
 215static xtensa_tlb_entry *get_tlb_entry(CPUXtensaState *env,
 216        uint32_t v, bool dtlb, uint32_t *pwi)
 217{
 218    uint32_t vpn;
 219    uint32_t wi;
 220    uint32_t ei;
 221
 222    split_tlb_entry_spec(env, v, dtlb, &vpn, &wi, &ei);
 223    if (pwi) {
 224        *pwi = wi;
 225    }
 226    return xtensa_tlb_get_entry(env, dtlb, wi, ei);
 227}
 228
 229uint32_t HELPER(rtlb0)(CPUXtensaState *env, uint32_t v, uint32_t dtlb)
 230{
 231    if (xtensa_option_enabled(env->config, XTENSA_OPTION_MMU)) {
 232        uint32_t wi;
 233        const xtensa_tlb_entry *entry = get_tlb_entry(env, v, dtlb, &wi);
 234        return (entry->vaddr & get_vpn_mask(env, dtlb, wi)) | entry->asid;
 235    } else {
 236        return v & REGION_PAGE_MASK;
 237    }
 238}
 239
 240uint32_t HELPER(rtlb1)(CPUXtensaState *env, uint32_t v, uint32_t dtlb)
 241{
 242    const xtensa_tlb_entry *entry = get_tlb_entry(env, v, dtlb, NULL);
 243    return entry->paddr | entry->attr;
 244}
 245
 246void HELPER(itlb)(CPUXtensaState *env, uint32_t v, uint32_t dtlb)
 247{
 248    if (xtensa_option_enabled(env->config, XTENSA_OPTION_MMU)) {
 249        uint32_t wi;
 250        xtensa_tlb_entry *entry = get_tlb_entry(env, v, dtlb, &wi);
 251        if (entry->variable && entry->asid) {
 252            tlb_flush_page(CPU(xtensa_env_get_cpu(env)), entry->vaddr);
 253            entry->asid = 0;
 254        }
 255    }
 256}
 257
 258uint32_t HELPER(ptlb)(CPUXtensaState *env, uint32_t v, uint32_t dtlb)
 259{
 260    if (xtensa_option_enabled(env->config, XTENSA_OPTION_MMU)) {
 261        uint32_t wi;
 262        uint32_t ei;
 263        uint8_t ring;
 264        int res = xtensa_tlb_lookup(env, v, dtlb, &wi, &ei, &ring);
 265
 266        switch (res) {
 267        case 0:
 268            if (ring >= xtensa_get_ring(env)) {
 269                return (v & 0xfffff000) | wi | (dtlb ? 0x10 : 0x8);
 270            }
 271            break;
 272
 273        case INST_TLB_MULTI_HIT_CAUSE:
 274        case LOAD_STORE_TLB_MULTI_HIT_CAUSE:
 275            HELPER(exception_cause_vaddr)(env, env->pc, res, v);
 276            break;
 277        }
 278        return 0;
 279    } else {
 280        return (v & REGION_PAGE_MASK) | 0x1;
 281    }
 282}
 283
 284void xtensa_tlb_set_entry_mmu(const CPUXtensaState *env,
 285                              xtensa_tlb_entry *entry, bool dtlb,
 286                              unsigned wi, unsigned ei, uint32_t vpn,
 287                              uint32_t pte)
 288{
 289    entry->vaddr = vpn;
 290    entry->paddr = pte & xtensa_tlb_get_addr_mask(env, dtlb, wi);
 291    entry->asid = (env->sregs[RASID] >> ((pte >> 1) & 0x18)) & 0xff;
 292    entry->attr = pte & 0xf;
 293}
 294
 295void xtensa_tlb_set_entry(CPUXtensaState *env, bool dtlb,
 296                          unsigned wi, unsigned ei, uint32_t vpn, uint32_t pte)
 297{
 298    XtensaCPU *cpu = xtensa_env_get_cpu(env);
 299    CPUState *cs = CPU(cpu);
 300    xtensa_tlb_entry *entry = xtensa_tlb_get_entry(env, dtlb, wi, ei);
 301
 302    if (xtensa_option_enabled(env->config, XTENSA_OPTION_MMU)) {
 303        if (entry->variable) {
 304            if (entry->asid) {
 305                tlb_flush_page(cs, entry->vaddr);
 306            }
 307            xtensa_tlb_set_entry_mmu(env, entry, dtlb, wi, ei, vpn, pte);
 308            tlb_flush_page(cs, entry->vaddr);
 309        } else {
 310            qemu_log_mask(LOG_GUEST_ERROR,
 311                          "%s %d, %d, %d trying to set immutable entry\n",
 312                          __func__, dtlb, wi, ei);
 313        }
 314    } else {
 315        tlb_flush_page(cs, entry->vaddr);
 316        if (xtensa_option_enabled(env->config,
 317                    XTENSA_OPTION_REGION_TRANSLATION)) {
 318            entry->paddr = pte & REGION_PAGE_MASK;
 319        }
 320        entry->attr = pte & 0xf;
 321    }
 322}
 323
 324void HELPER(wtlb)(CPUXtensaState *env, uint32_t p, uint32_t v, uint32_t dtlb)
 325{
 326    uint32_t vpn;
 327    uint32_t wi;
 328    uint32_t ei;
 329    split_tlb_entry_spec(env, v, dtlb, &vpn, &wi, &ei);
 330    xtensa_tlb_set_entry(env, dtlb, wi, ei, vpn, p);
 331}
 332
 333hwaddr xtensa_cpu_get_phys_page_debug(CPUState *cs, vaddr addr)
 334{
 335    XtensaCPU *cpu = XTENSA_CPU(cs);
 336    uint32_t paddr;
 337    uint32_t page_size;
 338    unsigned access;
 339
 340    if (xtensa_get_physical_addr(&cpu->env, false, addr, 0, 0,
 341                &paddr, &page_size, &access) == 0) {
 342        return paddr;
 343    }
 344    if (xtensa_get_physical_addr(&cpu->env, false, addr, 2, 0,
 345                &paddr, &page_size, &access) == 0) {
 346        return paddr;
 347    }
 348    return ~0;
 349}
 350
 351static void reset_tlb_mmu_all_ways(CPUXtensaState *env,
 352                                   const xtensa_tlb *tlb,
 353                                   xtensa_tlb_entry entry[][MAX_TLB_WAY_SIZE])
 354{
 355    unsigned wi, ei;
 356
 357    for (wi = 0; wi < tlb->nways; ++wi) {
 358        for (ei = 0; ei < tlb->way_size[wi]; ++ei) {
 359            entry[wi][ei].asid = 0;
 360            entry[wi][ei].variable = true;
 361        }
 362    }
 363}
 364
 365static void reset_tlb_mmu_ways56(CPUXtensaState *env,
 366                                 const xtensa_tlb *tlb,
 367                                 xtensa_tlb_entry entry[][MAX_TLB_WAY_SIZE])
 368{
 369    if (!tlb->varway56) {
 370        static const xtensa_tlb_entry way5[] = {
 371            {
 372                .vaddr = 0xd0000000,
 373                .paddr = 0,
 374                .asid = 1,
 375                .attr = 7,
 376                .variable = false,
 377            }, {
 378                .vaddr = 0xd8000000,
 379                .paddr = 0,
 380                .asid = 1,
 381                .attr = 3,
 382                .variable = false,
 383            }
 384        };
 385        static const xtensa_tlb_entry way6[] = {
 386            {
 387                .vaddr = 0xe0000000,
 388                .paddr = 0xf0000000,
 389                .asid = 1,
 390                .attr = 7,
 391                .variable = false,
 392            }, {
 393                .vaddr = 0xf0000000,
 394                .paddr = 0xf0000000,
 395                .asid = 1,
 396                .attr = 3,
 397                .variable = false,
 398            }
 399        };
 400        memcpy(entry[5], way5, sizeof(way5));
 401        memcpy(entry[6], way6, sizeof(way6));
 402    } else {
 403        uint32_t ei;
 404        for (ei = 0; ei < 8; ++ei) {
 405            entry[6][ei].vaddr = ei << 29;
 406            entry[6][ei].paddr = ei << 29;
 407            entry[6][ei].asid = 1;
 408            entry[6][ei].attr = 3;
 409        }
 410    }
 411}
 412
 413static void reset_tlb_region_way0(CPUXtensaState *env,
 414                                  xtensa_tlb_entry entry[][MAX_TLB_WAY_SIZE])
 415{
 416    unsigned ei;
 417
 418    for (ei = 0; ei < 8; ++ei) {
 419        entry[0][ei].vaddr = ei << 29;
 420        entry[0][ei].paddr = ei << 29;
 421        entry[0][ei].asid = 1;
 422        entry[0][ei].attr = 2;
 423        entry[0][ei].variable = true;
 424    }
 425}
 426
 427void reset_mmu(CPUXtensaState *env)
 428{
 429    if (xtensa_option_enabled(env->config, XTENSA_OPTION_MMU)) {
 430        env->sregs[RASID] = 0x04030201;
 431        env->sregs[ITLBCFG] = 0;
 432        env->sregs[DTLBCFG] = 0;
 433        env->autorefill_idx = 0;
 434        reset_tlb_mmu_all_ways(env, &env->config->itlb, env->itlb);
 435        reset_tlb_mmu_all_ways(env, &env->config->dtlb, env->dtlb);
 436        reset_tlb_mmu_ways56(env, &env->config->itlb, env->itlb);
 437        reset_tlb_mmu_ways56(env, &env->config->dtlb, env->dtlb);
 438    } else {
 439        reset_tlb_region_way0(env, env->itlb);
 440        reset_tlb_region_way0(env, env->dtlb);
 441    }
 442}
 443
 444static unsigned get_ring(const CPUXtensaState *env, uint8_t asid)
 445{
 446    unsigned i;
 447    for (i = 0; i < 4; ++i) {
 448        if (((env->sregs[RASID] >> i * 8) & 0xff) == asid) {
 449            return i;
 450        }
 451    }
 452    return 0xff;
 453}
 454
 455/*!
 456 * Lookup xtensa TLB for the given virtual address.
 457 * See ISA, 4.6.2.2
 458 *
 459 * \param pwi: [out] way index
 460 * \param pei: [out] entry index
 461 * \param pring: [out] access ring
 462 * \return 0 if ok, exception cause code otherwise
 463 */
 464int xtensa_tlb_lookup(const CPUXtensaState *env, uint32_t addr, bool dtlb,
 465                      uint32_t *pwi, uint32_t *pei, uint8_t *pring)
 466{
 467    const xtensa_tlb *tlb = dtlb ?
 468        &env->config->dtlb : &env->config->itlb;
 469    const xtensa_tlb_entry (*entry)[MAX_TLB_WAY_SIZE] = dtlb ?
 470        env->dtlb : env->itlb;
 471
 472    int nhits = 0;
 473    unsigned wi;
 474
 475    for (wi = 0; wi < tlb->nways; ++wi) {
 476        uint32_t vpn;
 477        uint32_t ei;
 478        split_tlb_entry_spec_way(env, addr, dtlb, &vpn, wi, &ei);
 479        if (entry[wi][ei].vaddr == vpn && entry[wi][ei].asid) {
 480            unsigned ring = get_ring(env, entry[wi][ei].asid);
 481            if (ring < 4) {
 482                if (++nhits > 1) {
 483                    return dtlb ?
 484                        LOAD_STORE_TLB_MULTI_HIT_CAUSE :
 485                        INST_TLB_MULTI_HIT_CAUSE;
 486                }
 487                *pwi = wi;
 488                *pei = ei;
 489                *pring = ring;
 490            }
 491        }
 492    }
 493    return nhits ? 0 :
 494        (dtlb ? LOAD_STORE_TLB_MISS_CAUSE : INST_TLB_MISS_CAUSE);
 495}
 496
 497/*!
 498 * Convert MMU ATTR to PAGE_{READ,WRITE,EXEC} mask.
 499 * See ISA, 4.6.5.10
 500 */
 501static unsigned mmu_attr_to_access(uint32_t attr)
 502{
 503    unsigned access = 0;
 504
 505    if (attr < 12) {
 506        access |= PAGE_READ;
 507        if (attr & 0x1) {
 508            access |= PAGE_EXEC;
 509        }
 510        if (attr & 0x2) {
 511            access |= PAGE_WRITE;
 512        }
 513
 514        switch (attr & 0xc) {
 515        case 0:
 516            access |= PAGE_CACHE_BYPASS;
 517            break;
 518
 519        case 4:
 520            access |= PAGE_CACHE_WB;
 521            break;
 522
 523        case 8:
 524            access |= PAGE_CACHE_WT;
 525            break;
 526        }
 527    } else if (attr == 13) {
 528        access |= PAGE_READ | PAGE_WRITE | PAGE_CACHE_ISOLATE;
 529    }
 530    return access;
 531}
 532
 533/*!
 534 * Convert region protection ATTR to PAGE_{READ,WRITE,EXEC} mask.
 535 * See ISA, 4.6.3.3
 536 */
 537static unsigned region_attr_to_access(uint32_t attr)
 538{
 539    static const unsigned access[16] = {
 540         [0] = PAGE_READ | PAGE_WRITE             | PAGE_CACHE_WT,
 541         [1] = PAGE_READ | PAGE_WRITE | PAGE_EXEC | PAGE_CACHE_WT,
 542         [2] = PAGE_READ | PAGE_WRITE | PAGE_EXEC | PAGE_CACHE_BYPASS,
 543         [3] =                          PAGE_EXEC | PAGE_CACHE_WB,
 544         [4] = PAGE_READ | PAGE_WRITE | PAGE_EXEC | PAGE_CACHE_WB,
 545         [5] = PAGE_READ | PAGE_WRITE | PAGE_EXEC | PAGE_CACHE_WB,
 546        [14] = PAGE_READ | PAGE_WRITE             | PAGE_CACHE_ISOLATE,
 547    };
 548
 549    return access[attr & 0xf];
 550}
 551
 552/*!
 553 * Convert cacheattr to PAGE_{READ,WRITE,EXEC} mask.
 554 * See ISA, A.2.14 The Cache Attribute Register
 555 */
 556static unsigned cacheattr_attr_to_access(uint32_t attr)
 557{
 558    static const unsigned access[16] = {
 559         [0] = PAGE_READ | PAGE_WRITE             | PAGE_CACHE_WT,
 560         [1] = PAGE_READ | PAGE_WRITE | PAGE_EXEC | PAGE_CACHE_WT,
 561         [2] = PAGE_READ | PAGE_WRITE | PAGE_EXEC | PAGE_CACHE_BYPASS,
 562         [3] =                          PAGE_EXEC | PAGE_CACHE_WB,
 563         [4] = PAGE_READ | PAGE_WRITE | PAGE_EXEC | PAGE_CACHE_WB,
 564        [14] = PAGE_READ | PAGE_WRITE             | PAGE_CACHE_ISOLATE,
 565    };
 566
 567    return access[attr & 0xf];
 568}
 569
 570static bool is_access_granted(unsigned access, int is_write)
 571{
 572    switch (is_write) {
 573    case 0:
 574        return access & PAGE_READ;
 575
 576    case 1:
 577        return access & PAGE_WRITE;
 578
 579    case 2:
 580        return access & PAGE_EXEC;
 581
 582    default:
 583        return 0;
 584    }
 585}
 586
 587static bool get_pte(CPUXtensaState *env, uint32_t vaddr, uint32_t *pte);
 588
 589static int get_physical_addr_mmu(CPUXtensaState *env, bool update_tlb,
 590                                 uint32_t vaddr, int is_write, int mmu_idx,
 591                                 uint32_t *paddr, uint32_t *page_size,
 592                                 unsigned *access, bool may_lookup_pt)
 593{
 594    bool dtlb = is_write != 2;
 595    uint32_t wi;
 596    uint32_t ei;
 597    uint8_t ring;
 598    uint32_t vpn;
 599    uint32_t pte;
 600    const xtensa_tlb_entry *entry = NULL;
 601    xtensa_tlb_entry tmp_entry;
 602    int ret = xtensa_tlb_lookup(env, vaddr, dtlb, &wi, &ei, &ring);
 603
 604    if ((ret == INST_TLB_MISS_CAUSE || ret == LOAD_STORE_TLB_MISS_CAUSE) &&
 605        may_lookup_pt && get_pte(env, vaddr, &pte)) {
 606        ring = (pte >> 4) & 0x3;
 607        wi = 0;
 608        split_tlb_entry_spec_way(env, vaddr, dtlb, &vpn, wi, &ei);
 609
 610        if (update_tlb) {
 611            wi = ++env->autorefill_idx & 0x3;
 612            xtensa_tlb_set_entry(env, dtlb, wi, ei, vpn, pte);
 613            env->sregs[EXCVADDR] = vaddr;
 614            qemu_log_mask(CPU_LOG_MMU, "%s: autorefill(%08x): %08x -> %08x\n",
 615                          __func__, vaddr, vpn, pte);
 616        } else {
 617            xtensa_tlb_set_entry_mmu(env, &tmp_entry, dtlb, wi, ei, vpn, pte);
 618            entry = &tmp_entry;
 619        }
 620        ret = 0;
 621    }
 622    if (ret != 0) {
 623        return ret;
 624    }
 625
 626    if (entry == NULL) {
 627        entry = xtensa_tlb_get_entry(env, dtlb, wi, ei);
 628    }
 629
 630    if (ring < mmu_idx) {
 631        return dtlb ?
 632            LOAD_STORE_PRIVILEGE_CAUSE :
 633            INST_FETCH_PRIVILEGE_CAUSE;
 634    }
 635
 636    *access = mmu_attr_to_access(entry->attr) &
 637        ~(dtlb ? PAGE_EXEC : PAGE_READ | PAGE_WRITE);
 638    if (!is_access_granted(*access, is_write)) {
 639        return dtlb ?
 640            (is_write ?
 641             STORE_PROHIBITED_CAUSE :
 642             LOAD_PROHIBITED_CAUSE) :
 643            INST_FETCH_PROHIBITED_CAUSE;
 644    }
 645
 646    *paddr = entry->paddr | (vaddr & ~xtensa_tlb_get_addr_mask(env, dtlb, wi));
 647    *page_size = ~xtensa_tlb_get_addr_mask(env, dtlb, wi) + 1;
 648
 649    return 0;
 650}
 651
 652static bool get_pte(CPUXtensaState *env, uint32_t vaddr, uint32_t *pte)
 653{
 654    CPUState *cs = CPU(xtensa_env_get_cpu(env));
 655    uint32_t paddr;
 656    uint32_t page_size;
 657    unsigned access;
 658    uint32_t pt_vaddr =
 659        (env->sregs[PTEVADDR] | (vaddr >> 10)) & 0xfffffffc;
 660    int ret = get_physical_addr_mmu(env, false, pt_vaddr, 0, 0,
 661                                    &paddr, &page_size, &access, false);
 662
 663    if (ret == 0) {
 664        qemu_log_mask(CPU_LOG_MMU,
 665                      "%s: autorefill(%08x): PTE va = %08x, pa = %08x\n",
 666                      __func__, vaddr, pt_vaddr, paddr);
 667    } else {
 668        qemu_log_mask(CPU_LOG_MMU,
 669                      "%s: autorefill(%08x): PTE va = %08x, failed (%d)\n",
 670                      __func__, vaddr, pt_vaddr, ret);
 671    }
 672
 673    if (ret == 0) {
 674        MemTxResult result;
 675
 676        *pte = address_space_ldl(cs->as, paddr, MEMTXATTRS_UNSPECIFIED,
 677                                 &result);
 678        if (result != MEMTX_OK) {
 679            qemu_log_mask(CPU_LOG_MMU,
 680                          "%s: couldn't load PTE: transaction failed (%u)\n",
 681                          __func__, (unsigned)result);
 682            ret = 1;
 683        }
 684    }
 685    return ret == 0;
 686}
 687
 688static int get_physical_addr_region(CPUXtensaState *env,
 689                                    uint32_t vaddr, int is_write, int mmu_idx,
 690                                    uint32_t *paddr, uint32_t *page_size,
 691                                    unsigned *access)
 692{
 693    bool dtlb = is_write != 2;
 694    uint32_t wi = 0;
 695    uint32_t ei = (vaddr >> 29) & 0x7;
 696    const xtensa_tlb_entry *entry =
 697        xtensa_tlb_get_entry(env, dtlb, wi, ei);
 698
 699    *access = region_attr_to_access(entry->attr);
 700    if (!is_access_granted(*access, is_write)) {
 701        return dtlb ?
 702            (is_write ?
 703             STORE_PROHIBITED_CAUSE :
 704             LOAD_PROHIBITED_CAUSE) :
 705            INST_FETCH_PROHIBITED_CAUSE;
 706    }
 707
 708    *paddr = entry->paddr | (vaddr & ~REGION_PAGE_MASK);
 709    *page_size = ~REGION_PAGE_MASK + 1;
 710
 711    return 0;
 712}
 713
 714/*!
 715 * Convert virtual address to physical addr.
 716 * MMU may issue pagewalk and change xtensa autorefill TLB way entry.
 717 *
 718 * \return 0 if ok, exception cause code otherwise
 719 */
 720int xtensa_get_physical_addr(CPUXtensaState *env, bool update_tlb,
 721                             uint32_t vaddr, int is_write, int mmu_idx,
 722                             uint32_t *paddr, uint32_t *page_size,
 723                             unsigned *access)
 724{
 725    if (xtensa_option_enabled(env->config, XTENSA_OPTION_MMU)) {
 726        return get_physical_addr_mmu(env, update_tlb,
 727                                     vaddr, is_write, mmu_idx, paddr,
 728                                     page_size, access, true);
 729    } else if (xtensa_option_bits_enabled(env->config,
 730                XTENSA_OPTION_BIT(XTENSA_OPTION_REGION_PROTECTION) |
 731                XTENSA_OPTION_BIT(XTENSA_OPTION_REGION_TRANSLATION))) {
 732        return get_physical_addr_region(env, vaddr, is_write, mmu_idx,
 733                                        paddr, page_size, access);
 734    } else {
 735        *paddr = vaddr;
 736        *page_size = TARGET_PAGE_SIZE;
 737        *access = cacheattr_attr_to_access(env->sregs[CACHEATTR] >>
 738                                           ((vaddr & 0xe0000000) >> 27));
 739        return 0;
 740    }
 741}
 742
 743static void dump_tlb(FILE *f, fprintf_function cpu_fprintf,
 744                     CPUXtensaState *env, bool dtlb)
 745{
 746    unsigned wi, ei;
 747    const xtensa_tlb *conf =
 748        dtlb ? &env->config->dtlb : &env->config->itlb;
 749    unsigned (*attr_to_access)(uint32_t) =
 750        xtensa_option_enabled(env->config, XTENSA_OPTION_MMU) ?
 751        mmu_attr_to_access : region_attr_to_access;
 752
 753    for (wi = 0; wi < conf->nways; ++wi) {
 754        uint32_t sz = ~xtensa_tlb_get_addr_mask(env, dtlb, wi) + 1;
 755        const char *sz_text;
 756        bool print_header = true;
 757
 758        if (sz >= 0x100000) {
 759            sz /= MiB;
 760            sz_text = "MB";
 761        } else {
 762            sz /= KiB;
 763            sz_text = "KB";
 764        }
 765
 766        for (ei = 0; ei < conf->way_size[wi]; ++ei) {
 767            const xtensa_tlb_entry *entry =
 768                xtensa_tlb_get_entry(env, dtlb, wi, ei);
 769
 770            if (entry->asid) {
 771                static const char * const cache_text[8] = {
 772                    [PAGE_CACHE_BYPASS >> PAGE_CACHE_SHIFT] = "Bypass",
 773                    [PAGE_CACHE_WT >> PAGE_CACHE_SHIFT] = "WT",
 774                    [PAGE_CACHE_WB >> PAGE_CACHE_SHIFT] = "WB",
 775                    [PAGE_CACHE_ISOLATE >> PAGE_CACHE_SHIFT] = "Isolate",
 776                };
 777                unsigned access = attr_to_access(entry->attr);
 778                unsigned cache_idx = (access & PAGE_CACHE_MASK) >>
 779                    PAGE_CACHE_SHIFT;
 780
 781                if (print_header) {
 782                    print_header = false;
 783                    cpu_fprintf(f, "Way %u (%d %s)\n", wi, sz, sz_text);
 784                    cpu_fprintf(f,
 785                                "\tVaddr       Paddr       ASID  Attr RWX Cache\n"
 786                                "\t----------  ----------  ----  ---- --- -------\n");
 787                }
 788                cpu_fprintf(f,
 789                            "\t0x%08x  0x%08x  0x%02x  0x%02x %c%c%c %-7s\n",
 790                            entry->vaddr,
 791                            entry->paddr,
 792                            entry->asid,
 793                            entry->attr,
 794                            (access & PAGE_READ) ? 'R' : '-',
 795                            (access & PAGE_WRITE) ? 'W' : '-',
 796                            (access & PAGE_EXEC) ? 'X' : '-',
 797                            cache_text[cache_idx] ?
 798                            cache_text[cache_idx] : "Invalid");
 799            }
 800        }
 801    }
 802}
 803
 804void dump_mmu(FILE *f, fprintf_function cpu_fprintf, CPUXtensaState *env)
 805{
 806    if (xtensa_option_bits_enabled(env->config,
 807                XTENSA_OPTION_BIT(XTENSA_OPTION_REGION_PROTECTION) |
 808                XTENSA_OPTION_BIT(XTENSA_OPTION_REGION_TRANSLATION) |
 809                XTENSA_OPTION_BIT(XTENSA_OPTION_MMU))) {
 810
 811        cpu_fprintf(f, "ITLB:\n");
 812        dump_tlb(f, cpu_fprintf, env, false);
 813        cpu_fprintf(f, "\nDTLB:\n");
 814        dump_tlb(f, cpu_fprintf, env, true);
 815    } else {
 816        cpu_fprintf(f, "No TLB for this CPU core\n");
 817    }
 818}
 819