cachepc-qemu

Fork of AMDESE/qemu with changes for cachepc side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-qemu
Log | Files | Refs | Submodules | LICENSE | sfeed.txt

mmu_helper.c (38361B)


      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/qemu-print.h"
     31#include "qemu/units.h"
     32#include "cpu.h"
     33#include "exec/helper-proto.h"
     34#include "qemu/host-utils.h"
     35#include "exec/exec-all.h"
     36#include "exec/cpu_ldst.h"
     37
     38#define XTENSA_MPU_SEGMENT_MASK 0x0000001f
     39#define XTENSA_MPU_ACC_RIGHTS_MASK 0x00000f00
     40#define XTENSA_MPU_ACC_RIGHTS_SHIFT 8
     41#define XTENSA_MPU_MEM_TYPE_MASK 0x001ff000
     42#define XTENSA_MPU_MEM_TYPE_SHIFT 12
     43#define XTENSA_MPU_ATTR_MASK 0x001fff00
     44
     45#define XTENSA_MPU_PROBE_B 0x40000000
     46#define XTENSA_MPU_PROBE_V 0x80000000
     47
     48#define XTENSA_MPU_SYSTEM_TYPE_DEVICE 0x0001
     49#define XTENSA_MPU_SYSTEM_TYPE_NC     0x0002
     50#define XTENSA_MPU_SYSTEM_TYPE_C      0x0003
     51#define XTENSA_MPU_SYSTEM_TYPE_MASK   0x0003
     52
     53#define XTENSA_MPU_TYPE_SYS_C     0x0010
     54#define XTENSA_MPU_TYPE_SYS_W     0x0020
     55#define XTENSA_MPU_TYPE_SYS_R     0x0040
     56#define XTENSA_MPU_TYPE_CPU_C     0x0100
     57#define XTENSA_MPU_TYPE_CPU_W     0x0200
     58#define XTENSA_MPU_TYPE_CPU_R     0x0400
     59#define XTENSA_MPU_TYPE_CPU_CACHE 0x0800
     60#define XTENSA_MPU_TYPE_B         0x1000
     61#define XTENSA_MPU_TYPE_INT       0x2000
     62
     63void HELPER(itlb_hit_test)(CPUXtensaState *env, uint32_t vaddr)
     64{
     65    /*
     66     * Probe the memory; we don't care about the result but
     67     * only the side-effects (ie any MMU or other exception)
     68     */
     69    probe_access(env, vaddr, 1, MMU_INST_FETCH,
     70                 cpu_mmu_index(env, true), GETPC());
     71}
     72
     73void HELPER(wsr_rasid)(CPUXtensaState *env, uint32_t v)
     74{
     75    v = (v & 0xffffff00) | 0x1;
     76    if (v != env->sregs[RASID]) {
     77        env->sregs[RASID] = v;
     78        tlb_flush(env_cpu(env));
     79    }
     80}
     81
     82static uint32_t get_page_size(const CPUXtensaState *env,
     83                              bool dtlb, uint32_t way)
     84{
     85    uint32_t tlbcfg = env->sregs[dtlb ? DTLBCFG : ITLBCFG];
     86
     87    switch (way) {
     88    case 4:
     89        return (tlbcfg >> 16) & 0x3;
     90
     91    case 5:
     92        return (tlbcfg >> 20) & 0x1;
     93
     94    case 6:
     95        return (tlbcfg >> 24) & 0x1;
     96
     97    default:
     98        return 0;
     99    }
    100}
    101
    102/*!
    103 * Get bit mask for the virtual address bits translated by the TLB way
    104 */
    105static uint32_t xtensa_tlb_get_addr_mask(const CPUXtensaState *env,
    106                                         bool dtlb, uint32_t way)
    107{
    108    if (xtensa_option_enabled(env->config, XTENSA_OPTION_MMU)) {
    109        bool varway56 = dtlb ?
    110            env->config->dtlb.varway56 :
    111            env->config->itlb.varway56;
    112
    113        switch (way) {
    114        case 4:
    115            return 0xfff00000 << get_page_size(env, dtlb, way) * 2;
    116
    117        case 5:
    118            if (varway56) {
    119                return 0xf8000000 << get_page_size(env, dtlb, way);
    120            } else {
    121                return 0xf8000000;
    122            }
    123
    124        case 6:
    125            if (varway56) {
    126                return 0xf0000000 << (1 - get_page_size(env, dtlb, way));
    127            } else {
    128                return 0xf0000000;
    129            }
    130
    131        default:
    132            return 0xfffff000;
    133        }
    134    } else {
    135        return REGION_PAGE_MASK;
    136    }
    137}
    138
    139/*!
    140 * Get bit mask for the 'VPN without index' field.
    141 * See ISA, 4.6.5.6, data format for RxTLB0
    142 */
    143static uint32_t get_vpn_mask(const CPUXtensaState *env, bool dtlb, uint32_t way)
    144{
    145    if (way < 4) {
    146        bool is32 = (dtlb ?
    147                env->config->dtlb.nrefillentries :
    148                env->config->itlb.nrefillentries) == 32;
    149        return is32 ? 0xffff8000 : 0xffffc000;
    150    } else if (way == 4) {
    151        return xtensa_tlb_get_addr_mask(env, dtlb, way) << 2;
    152    } else if (way <= 6) {
    153        uint32_t mask = xtensa_tlb_get_addr_mask(env, dtlb, way);
    154        bool varway56 = dtlb ?
    155            env->config->dtlb.varway56 :
    156            env->config->itlb.varway56;
    157
    158        if (varway56) {
    159            return mask << (way == 5 ? 2 : 3);
    160        } else {
    161            return mask << 1;
    162        }
    163    } else {
    164        return 0xfffff000;
    165    }
    166}
    167
    168/*!
    169 * Split virtual address into VPN (with index) and entry index
    170 * for the given TLB way
    171 */
    172static void split_tlb_entry_spec_way(const CPUXtensaState *env, uint32_t v,
    173                                     bool dtlb, uint32_t *vpn,
    174                                     uint32_t wi, uint32_t *ei)
    175{
    176    bool varway56 = dtlb ?
    177        env->config->dtlb.varway56 :
    178        env->config->itlb.varway56;
    179
    180    if (!dtlb) {
    181        wi &= 7;
    182    }
    183
    184    if (wi < 4) {
    185        bool is32 = (dtlb ?
    186                env->config->dtlb.nrefillentries :
    187                env->config->itlb.nrefillentries) == 32;
    188        *ei = (v >> 12) & (is32 ? 0x7 : 0x3);
    189    } else {
    190        switch (wi) {
    191        case 4:
    192            {
    193                uint32_t eibase = 20 + get_page_size(env, dtlb, wi) * 2;
    194                *ei = (v >> eibase) & 0x3;
    195            }
    196            break;
    197
    198        case 5:
    199            if (varway56) {
    200                uint32_t eibase = 27 + get_page_size(env, dtlb, wi);
    201                *ei = (v >> eibase) & 0x3;
    202            } else {
    203                *ei = (v >> 27) & 0x1;
    204            }
    205            break;
    206
    207        case 6:
    208            if (varway56) {
    209                uint32_t eibase = 29 - get_page_size(env, dtlb, wi);
    210                *ei = (v >> eibase) & 0x7;
    211            } else {
    212                *ei = (v >> 28) & 0x1;
    213            }
    214            break;
    215
    216        default:
    217            *ei = 0;
    218            break;
    219        }
    220    }
    221    *vpn = v & xtensa_tlb_get_addr_mask(env, dtlb, wi);
    222}
    223
    224/*!
    225 * Split TLB address into TLB way, entry index and VPN (with index).
    226 * See ISA, 4.6.5.5 - 4.6.5.8 for the TLB addressing format
    227 */
    228static void split_tlb_entry_spec(CPUXtensaState *env, uint32_t v, bool dtlb,
    229        uint32_t *vpn, uint32_t *wi, uint32_t *ei)
    230{
    231    if (xtensa_option_enabled(env->config, XTENSA_OPTION_MMU)) {
    232        *wi = v & (dtlb ? 0xf : 0x7);
    233        split_tlb_entry_spec_way(env, v, dtlb, vpn, *wi, ei);
    234    } else {
    235        *vpn = v & REGION_PAGE_MASK;
    236        *wi = 0;
    237        *ei = (v >> 29) & 0x7;
    238    }
    239}
    240
    241static xtensa_tlb_entry *xtensa_tlb_get_entry(CPUXtensaState *env, bool dtlb,
    242                                              unsigned wi, unsigned ei)
    243{
    244    return dtlb ?
    245        env->dtlb[wi] + ei :
    246        env->itlb[wi] + ei;
    247}
    248
    249static xtensa_tlb_entry *get_tlb_entry(CPUXtensaState *env,
    250        uint32_t v, bool dtlb, uint32_t *pwi)
    251{
    252    uint32_t vpn;
    253    uint32_t wi;
    254    uint32_t ei;
    255
    256    split_tlb_entry_spec(env, v, dtlb, &vpn, &wi, &ei);
    257    if (pwi) {
    258        *pwi = wi;
    259    }
    260    return xtensa_tlb_get_entry(env, dtlb, wi, ei);
    261}
    262
    263static void xtensa_tlb_set_entry_mmu(const CPUXtensaState *env,
    264                                     xtensa_tlb_entry *entry, bool dtlb,
    265                                     unsigned wi, unsigned ei, uint32_t vpn,
    266                                     uint32_t pte)
    267{
    268    entry->vaddr = vpn;
    269    entry->paddr = pte & xtensa_tlb_get_addr_mask(env, dtlb, wi);
    270    entry->asid = (env->sregs[RASID] >> ((pte >> 1) & 0x18)) & 0xff;
    271    entry->attr = pte & 0xf;
    272}
    273
    274static void xtensa_tlb_set_entry(CPUXtensaState *env, bool dtlb,
    275                                 unsigned wi, unsigned ei,
    276                                 uint32_t vpn, uint32_t pte)
    277{
    278    CPUState *cs = env_cpu(env);
    279    xtensa_tlb_entry *entry = xtensa_tlb_get_entry(env, dtlb, wi, ei);
    280
    281    if (xtensa_option_enabled(env->config, XTENSA_OPTION_MMU)) {
    282        if (entry->variable) {
    283            if (entry->asid) {
    284                tlb_flush_page(cs, entry->vaddr);
    285            }
    286            xtensa_tlb_set_entry_mmu(env, entry, dtlb, wi, ei, vpn, pte);
    287            tlb_flush_page(cs, entry->vaddr);
    288        } else {
    289            qemu_log_mask(LOG_GUEST_ERROR,
    290                          "%s %d, %d, %d trying to set immutable entry\n",
    291                          __func__, dtlb, wi, ei);
    292        }
    293    } else {
    294        tlb_flush_page(cs, entry->vaddr);
    295        if (xtensa_option_enabled(env->config,
    296                    XTENSA_OPTION_REGION_TRANSLATION)) {
    297            entry->paddr = pte & REGION_PAGE_MASK;
    298        }
    299        entry->attr = pte & 0xf;
    300    }
    301}
    302
    303hwaddr xtensa_cpu_get_phys_page_debug(CPUState *cs, vaddr addr)
    304{
    305    XtensaCPU *cpu = XTENSA_CPU(cs);
    306    uint32_t paddr;
    307    uint32_t page_size;
    308    unsigned access;
    309
    310    if (xtensa_get_physical_addr(&cpu->env, false, addr, 0, 0,
    311                &paddr, &page_size, &access) == 0) {
    312        return paddr;
    313    }
    314    if (xtensa_get_physical_addr(&cpu->env, false, addr, 2, 0,
    315                &paddr, &page_size, &access) == 0) {
    316        return paddr;
    317    }
    318    return ~0;
    319}
    320
    321static void reset_tlb_mmu_all_ways(CPUXtensaState *env,
    322                                   const xtensa_tlb *tlb,
    323                                   xtensa_tlb_entry entry[][MAX_TLB_WAY_SIZE])
    324{
    325    unsigned wi, ei;
    326
    327    for (wi = 0; wi < tlb->nways; ++wi) {
    328        for (ei = 0; ei < tlb->way_size[wi]; ++ei) {
    329            entry[wi][ei].asid = 0;
    330            entry[wi][ei].variable = true;
    331        }
    332    }
    333}
    334
    335static void reset_tlb_mmu_ways56(CPUXtensaState *env,
    336                                 const xtensa_tlb *tlb,
    337                                 xtensa_tlb_entry entry[][MAX_TLB_WAY_SIZE])
    338{
    339    if (!tlb->varway56) {
    340        static const xtensa_tlb_entry way5[] = {
    341            {
    342                .vaddr = 0xd0000000,
    343                .paddr = 0,
    344                .asid = 1,
    345                .attr = 7,
    346                .variable = false,
    347            }, {
    348                .vaddr = 0xd8000000,
    349                .paddr = 0,
    350                .asid = 1,
    351                .attr = 3,
    352                .variable = false,
    353            }
    354        };
    355        static const xtensa_tlb_entry way6[] = {
    356            {
    357                .vaddr = 0xe0000000,
    358                .paddr = 0xf0000000,
    359                .asid = 1,
    360                .attr = 7,
    361                .variable = false,
    362            }, {
    363                .vaddr = 0xf0000000,
    364                .paddr = 0xf0000000,
    365                .asid = 1,
    366                .attr = 3,
    367                .variable = false,
    368            }
    369        };
    370        memcpy(entry[5], way5, sizeof(way5));
    371        memcpy(entry[6], way6, sizeof(way6));
    372    } else {
    373        uint32_t ei;
    374        for (ei = 0; ei < 8; ++ei) {
    375            entry[6][ei].vaddr = ei << 29;
    376            entry[6][ei].paddr = ei << 29;
    377            entry[6][ei].asid = 1;
    378            entry[6][ei].attr = 3;
    379        }
    380    }
    381}
    382
    383static void reset_tlb_region_way0(CPUXtensaState *env,
    384                                  xtensa_tlb_entry entry[][MAX_TLB_WAY_SIZE])
    385{
    386    unsigned ei;
    387
    388    for (ei = 0; ei < 8; ++ei) {
    389        entry[0][ei].vaddr = ei << 29;
    390        entry[0][ei].paddr = ei << 29;
    391        entry[0][ei].asid = 1;
    392        entry[0][ei].attr = 2;
    393        entry[0][ei].variable = true;
    394    }
    395}
    396
    397void reset_mmu(CPUXtensaState *env)
    398{
    399    if (xtensa_option_enabled(env->config, XTENSA_OPTION_MMU)) {
    400        env->sregs[RASID] = 0x04030201;
    401        env->sregs[ITLBCFG] = 0;
    402        env->sregs[DTLBCFG] = 0;
    403        env->autorefill_idx = 0;
    404        reset_tlb_mmu_all_ways(env, &env->config->itlb, env->itlb);
    405        reset_tlb_mmu_all_ways(env, &env->config->dtlb, env->dtlb);
    406        reset_tlb_mmu_ways56(env, &env->config->itlb, env->itlb);
    407        reset_tlb_mmu_ways56(env, &env->config->dtlb, env->dtlb);
    408    } else if (xtensa_option_enabled(env->config, XTENSA_OPTION_MPU)) {
    409        unsigned i;
    410
    411        env->sregs[MPUENB] = 0;
    412        env->sregs[MPUCFG] = env->config->n_mpu_fg_segments;
    413        env->sregs[CACHEADRDIS] = 0;
    414        assert(env->config->n_mpu_bg_segments > 0 &&
    415               env->config->mpu_bg[0].vaddr == 0);
    416        for (i = 1; i < env->config->n_mpu_bg_segments; ++i) {
    417            assert(env->config->mpu_bg[i].vaddr >=
    418                   env->config->mpu_bg[i - 1].vaddr);
    419        }
    420    } else {
    421        env->sregs[CACHEATTR] = 0x22222222;
    422        reset_tlb_region_way0(env, env->itlb);
    423        reset_tlb_region_way0(env, env->dtlb);
    424    }
    425}
    426
    427static unsigned get_ring(const CPUXtensaState *env, uint8_t asid)
    428{
    429    unsigned i;
    430    for (i = 0; i < 4; ++i) {
    431        if (((env->sregs[RASID] >> i * 8) & 0xff) == asid) {
    432            return i;
    433        }
    434    }
    435    return 0xff;
    436}
    437
    438/*!
    439 * Lookup xtensa TLB for the given virtual address.
    440 * See ISA, 4.6.2.2
    441 *
    442 * \param pwi: [out] way index
    443 * \param pei: [out] entry index
    444 * \param pring: [out] access ring
    445 * \return 0 if ok, exception cause code otherwise
    446 */
    447static int xtensa_tlb_lookup(const CPUXtensaState *env,
    448                             uint32_t addr, bool dtlb,
    449                             uint32_t *pwi, uint32_t *pei, uint8_t *pring)
    450{
    451    const xtensa_tlb *tlb = dtlb ?
    452        &env->config->dtlb : &env->config->itlb;
    453    const xtensa_tlb_entry (*entry)[MAX_TLB_WAY_SIZE] = dtlb ?
    454        env->dtlb : env->itlb;
    455
    456    int nhits = 0;
    457    unsigned wi;
    458
    459    for (wi = 0; wi < tlb->nways; ++wi) {
    460        uint32_t vpn;
    461        uint32_t ei;
    462        split_tlb_entry_spec_way(env, addr, dtlb, &vpn, wi, &ei);
    463        if (entry[wi][ei].vaddr == vpn && entry[wi][ei].asid) {
    464            unsigned ring = get_ring(env, entry[wi][ei].asid);
    465            if (ring < 4) {
    466                if (++nhits > 1) {
    467                    return dtlb ?
    468                        LOAD_STORE_TLB_MULTI_HIT_CAUSE :
    469                        INST_TLB_MULTI_HIT_CAUSE;
    470                }
    471                *pwi = wi;
    472                *pei = ei;
    473                *pring = ring;
    474            }
    475        }
    476    }
    477    return nhits ? 0 :
    478        (dtlb ? LOAD_STORE_TLB_MISS_CAUSE : INST_TLB_MISS_CAUSE);
    479}
    480
    481uint32_t HELPER(rtlb0)(CPUXtensaState *env, uint32_t v, uint32_t dtlb)
    482{
    483    if (xtensa_option_enabled(env->config, XTENSA_OPTION_MMU)) {
    484        uint32_t wi;
    485        const xtensa_tlb_entry *entry = get_tlb_entry(env, v, dtlb, &wi);
    486        return (entry->vaddr & get_vpn_mask(env, dtlb, wi)) | entry->asid;
    487    } else {
    488        return v & REGION_PAGE_MASK;
    489    }
    490}
    491
    492uint32_t HELPER(rtlb1)(CPUXtensaState *env, uint32_t v, uint32_t dtlb)
    493{
    494    const xtensa_tlb_entry *entry = get_tlb_entry(env, v, dtlb, NULL);
    495    return entry->paddr | entry->attr;
    496}
    497
    498void HELPER(itlb)(CPUXtensaState *env, uint32_t v, uint32_t dtlb)
    499{
    500    if (xtensa_option_enabled(env->config, XTENSA_OPTION_MMU)) {
    501        uint32_t wi;
    502        xtensa_tlb_entry *entry = get_tlb_entry(env, v, dtlb, &wi);
    503        if (entry->variable && entry->asid) {
    504            tlb_flush_page(env_cpu(env), entry->vaddr);
    505            entry->asid = 0;
    506        }
    507    }
    508}
    509
    510uint32_t HELPER(ptlb)(CPUXtensaState *env, uint32_t v, uint32_t dtlb)
    511{
    512    if (xtensa_option_enabled(env->config, XTENSA_OPTION_MMU)) {
    513        uint32_t wi;
    514        uint32_t ei;
    515        uint8_t ring;
    516        int res = xtensa_tlb_lookup(env, v, dtlb, &wi, &ei, &ring);
    517
    518        switch (res) {
    519        case 0:
    520            if (ring >= xtensa_get_ring(env)) {
    521                return (v & 0xfffff000) | wi | (dtlb ? 0x10 : 0x8);
    522            }
    523            break;
    524
    525        case INST_TLB_MULTI_HIT_CAUSE:
    526        case LOAD_STORE_TLB_MULTI_HIT_CAUSE:
    527            HELPER(exception_cause_vaddr)(env, env->pc, res, v);
    528            break;
    529        }
    530        return 0;
    531    } else {
    532        return (v & REGION_PAGE_MASK) | 0x1;
    533    }
    534}
    535
    536void HELPER(wtlb)(CPUXtensaState *env, uint32_t p, uint32_t v, uint32_t dtlb)
    537{
    538    uint32_t vpn;
    539    uint32_t wi;
    540    uint32_t ei;
    541    split_tlb_entry_spec(env, v, dtlb, &vpn, &wi, &ei);
    542    xtensa_tlb_set_entry(env, dtlb, wi, ei, vpn, p);
    543}
    544
    545/*!
    546 * Convert MMU ATTR to PAGE_{READ,WRITE,EXEC} mask.
    547 * See ISA, 4.6.5.10
    548 */
    549static unsigned mmu_attr_to_access(uint32_t attr)
    550{
    551    unsigned access = 0;
    552
    553    if (attr < 12) {
    554        access |= PAGE_READ;
    555        if (attr & 0x1) {
    556            access |= PAGE_EXEC;
    557        }
    558        if (attr & 0x2) {
    559            access |= PAGE_WRITE;
    560        }
    561
    562        switch (attr & 0xc) {
    563        case 0:
    564            access |= PAGE_CACHE_BYPASS;
    565            break;
    566
    567        case 4:
    568            access |= PAGE_CACHE_WB;
    569            break;
    570
    571        case 8:
    572            access |= PAGE_CACHE_WT;
    573            break;
    574        }
    575    } else if (attr == 13) {
    576        access |= PAGE_READ | PAGE_WRITE | PAGE_CACHE_ISOLATE;
    577    }
    578    return access;
    579}
    580
    581/*!
    582 * Convert region protection ATTR to PAGE_{READ,WRITE,EXEC} mask.
    583 * See ISA, 4.6.3.3
    584 */
    585static unsigned region_attr_to_access(uint32_t attr)
    586{
    587    static const unsigned access[16] = {
    588         [0] = PAGE_READ | PAGE_WRITE             | PAGE_CACHE_WT,
    589         [1] = PAGE_READ | PAGE_WRITE | PAGE_EXEC | PAGE_CACHE_WT,
    590         [2] = PAGE_READ | PAGE_WRITE | PAGE_EXEC | PAGE_CACHE_BYPASS,
    591         [3] =                          PAGE_EXEC | PAGE_CACHE_WB,
    592         [4] = PAGE_READ | PAGE_WRITE | PAGE_EXEC | PAGE_CACHE_WB,
    593         [5] = PAGE_READ | PAGE_WRITE | PAGE_EXEC | PAGE_CACHE_WB,
    594        [14] = PAGE_READ | PAGE_WRITE             | PAGE_CACHE_ISOLATE,
    595    };
    596
    597    return access[attr & 0xf];
    598}
    599
    600/*!
    601 * Convert cacheattr to PAGE_{READ,WRITE,EXEC} mask.
    602 * See ISA, A.2.14 The Cache Attribute Register
    603 */
    604static unsigned cacheattr_attr_to_access(uint32_t attr)
    605{
    606    static const unsigned access[16] = {
    607         [0] = PAGE_READ | PAGE_WRITE             | PAGE_CACHE_WT,
    608         [1] = PAGE_READ | PAGE_WRITE | PAGE_EXEC | PAGE_CACHE_WT,
    609         [2] = PAGE_READ | PAGE_WRITE | PAGE_EXEC | PAGE_CACHE_BYPASS,
    610         [3] =                          PAGE_EXEC | PAGE_CACHE_WB,
    611         [4] = PAGE_READ | PAGE_WRITE | PAGE_EXEC | PAGE_CACHE_WB,
    612        [14] = PAGE_READ | PAGE_WRITE             | PAGE_CACHE_ISOLATE,
    613    };
    614
    615    return access[attr & 0xf];
    616}
    617
    618struct attr_pattern {
    619    uint32_t mask;
    620    uint32_t value;
    621};
    622
    623static int attr_pattern_match(uint32_t attr,
    624                              const struct attr_pattern *pattern,
    625                              size_t n)
    626{
    627    size_t i;
    628
    629    for (i = 0; i < n; ++i) {
    630        if ((attr & pattern[i].mask) == pattern[i].value) {
    631            return 1;
    632        }
    633    }
    634    return 0;
    635}
    636
    637static unsigned mpu_attr_to_cpu_cache(uint32_t attr)
    638{
    639    static const struct attr_pattern cpu_c[] = {
    640        { .mask = 0x18f, .value = 0x089 },
    641        { .mask = 0x188, .value = 0x080 },
    642        { .mask = 0x180, .value = 0x180 },
    643    };
    644
    645    unsigned type = 0;
    646
    647    if (attr_pattern_match(attr, cpu_c, ARRAY_SIZE(cpu_c))) {
    648        type |= XTENSA_MPU_TYPE_CPU_CACHE;
    649        if (attr & 0x10) {
    650            type |= XTENSA_MPU_TYPE_CPU_C;
    651        }
    652        if (attr & 0x20) {
    653            type |= XTENSA_MPU_TYPE_CPU_W;
    654        }
    655        if (attr & 0x40) {
    656            type |= XTENSA_MPU_TYPE_CPU_R;
    657        }
    658    }
    659    return type;
    660}
    661
    662static unsigned mpu_attr_to_type(uint32_t attr)
    663{
    664    static const struct attr_pattern device_type[] = {
    665        { .mask = 0x1f6, .value = 0x000 },
    666        { .mask = 0x1f6, .value = 0x006 },
    667    };
    668    static const struct attr_pattern sys_nc_type[] = {
    669        { .mask = 0x1fe, .value = 0x018 },
    670        { .mask = 0x1fe, .value = 0x01e },
    671        { .mask = 0x18f, .value = 0x089 },
    672    };
    673    static const struct attr_pattern sys_c_type[] = {
    674        { .mask = 0x1f8, .value = 0x010 },
    675        { .mask = 0x188, .value = 0x080 },
    676        { .mask = 0x1f0, .value = 0x030 },
    677        { .mask = 0x180, .value = 0x180 },
    678    };
    679    static const struct attr_pattern b[] = {
    680        { .mask = 0x1f7, .value = 0x001 },
    681        { .mask = 0x1f7, .value = 0x007 },
    682        { .mask = 0x1ff, .value = 0x019 },
    683        { .mask = 0x1ff, .value = 0x01f },
    684    };
    685
    686    unsigned type = 0;
    687
    688    attr = (attr & XTENSA_MPU_MEM_TYPE_MASK) >> XTENSA_MPU_MEM_TYPE_SHIFT;
    689    if (attr_pattern_match(attr, device_type, ARRAY_SIZE(device_type))) {
    690        type |= XTENSA_MPU_SYSTEM_TYPE_DEVICE;
    691        if (attr & 0x80) {
    692            type |= XTENSA_MPU_TYPE_INT;
    693        }
    694    }
    695    if (attr_pattern_match(attr, sys_nc_type, ARRAY_SIZE(sys_nc_type))) {
    696        type |= XTENSA_MPU_SYSTEM_TYPE_NC;
    697    }
    698    if (attr_pattern_match(attr, sys_c_type, ARRAY_SIZE(sys_c_type))) {
    699        type |= XTENSA_MPU_SYSTEM_TYPE_C;
    700        if (attr & 0x1) {
    701            type |= XTENSA_MPU_TYPE_SYS_C;
    702        }
    703        if (attr & 0x2) {
    704            type |= XTENSA_MPU_TYPE_SYS_W;
    705        }
    706        if (attr & 0x4) {
    707            type |= XTENSA_MPU_TYPE_SYS_R;
    708        }
    709    }
    710    if (attr_pattern_match(attr, b, ARRAY_SIZE(b))) {
    711        type |= XTENSA_MPU_TYPE_B;
    712    }
    713    type |= mpu_attr_to_cpu_cache(attr);
    714
    715    return type;
    716}
    717
    718static unsigned mpu_attr_to_access(uint32_t attr, unsigned ring)
    719{
    720    static const unsigned access[2][16] = {
    721        [0] = {
    722             [4] = PAGE_READ,
    723             [5] = PAGE_READ              | PAGE_EXEC,
    724             [6] = PAGE_READ | PAGE_WRITE,
    725             [7] = PAGE_READ | PAGE_WRITE | PAGE_EXEC,
    726             [8] =             PAGE_WRITE,
    727             [9] = PAGE_READ | PAGE_WRITE,
    728            [10] = PAGE_READ | PAGE_WRITE,
    729            [11] = PAGE_READ | PAGE_WRITE | PAGE_EXEC,
    730            [12] = PAGE_READ,
    731            [13] = PAGE_READ              | PAGE_EXEC,
    732            [14] = PAGE_READ | PAGE_WRITE,
    733            [15] = PAGE_READ | PAGE_WRITE | PAGE_EXEC,
    734        },
    735        [1] = {
    736             [8] =             PAGE_WRITE,
    737             [9] = PAGE_READ | PAGE_WRITE | PAGE_EXEC,
    738            [10] = PAGE_READ,
    739            [11] = PAGE_READ              | PAGE_EXEC,
    740            [12] = PAGE_READ,
    741            [13] = PAGE_READ              | PAGE_EXEC,
    742            [14] = PAGE_READ | PAGE_WRITE,
    743            [15] = PAGE_READ | PAGE_WRITE | PAGE_EXEC,
    744        },
    745    };
    746    unsigned rv;
    747    unsigned type;
    748
    749    type = mpu_attr_to_cpu_cache(attr);
    750    rv = access[ring != 0][(attr & XTENSA_MPU_ACC_RIGHTS_MASK) >>
    751        XTENSA_MPU_ACC_RIGHTS_SHIFT];
    752
    753    if (type & XTENSA_MPU_TYPE_CPU_CACHE) {
    754        rv |= (type & XTENSA_MPU_TYPE_CPU_C) ? PAGE_CACHE_WB : PAGE_CACHE_WT;
    755    } else {
    756        rv |= PAGE_CACHE_BYPASS;
    757    }
    758    return rv;
    759}
    760
    761static bool is_access_granted(unsigned access, int is_write)
    762{
    763    switch (is_write) {
    764    case 0:
    765        return access & PAGE_READ;
    766
    767    case 1:
    768        return access & PAGE_WRITE;
    769
    770    case 2:
    771        return access & PAGE_EXEC;
    772
    773    default:
    774        return 0;
    775    }
    776}
    777
    778static bool get_pte(CPUXtensaState *env, uint32_t vaddr, uint32_t *pte);
    779
    780static int get_physical_addr_mmu(CPUXtensaState *env, bool update_tlb,
    781                                 uint32_t vaddr, int is_write, int mmu_idx,
    782                                 uint32_t *paddr, uint32_t *page_size,
    783                                 unsigned *access, bool may_lookup_pt)
    784{
    785    bool dtlb = is_write != 2;
    786    uint32_t wi;
    787    uint32_t ei;
    788    uint8_t ring;
    789    uint32_t vpn;
    790    uint32_t pte;
    791    const xtensa_tlb_entry *entry = NULL;
    792    xtensa_tlb_entry tmp_entry;
    793    int ret = xtensa_tlb_lookup(env, vaddr, dtlb, &wi, &ei, &ring);
    794
    795    if ((ret == INST_TLB_MISS_CAUSE || ret == LOAD_STORE_TLB_MISS_CAUSE) &&
    796        may_lookup_pt && get_pte(env, vaddr, &pte)) {
    797        ring = (pte >> 4) & 0x3;
    798        wi = 0;
    799        split_tlb_entry_spec_way(env, vaddr, dtlb, &vpn, wi, &ei);
    800
    801        if (update_tlb) {
    802            wi = ++env->autorefill_idx & 0x3;
    803            xtensa_tlb_set_entry(env, dtlb, wi, ei, vpn, pte);
    804            env->sregs[EXCVADDR] = vaddr;
    805            qemu_log_mask(CPU_LOG_MMU, "%s: autorefill(%08x): %08x -> %08x\n",
    806                          __func__, vaddr, vpn, pte);
    807        } else {
    808            xtensa_tlb_set_entry_mmu(env, &tmp_entry, dtlb, wi, ei, vpn, pte);
    809            entry = &tmp_entry;
    810        }
    811        ret = 0;
    812    }
    813    if (ret != 0) {
    814        return ret;
    815    }
    816
    817    if (entry == NULL) {
    818        entry = xtensa_tlb_get_entry(env, dtlb, wi, ei);
    819    }
    820
    821    if (ring < mmu_idx) {
    822        return dtlb ?
    823            LOAD_STORE_PRIVILEGE_CAUSE :
    824            INST_FETCH_PRIVILEGE_CAUSE;
    825    }
    826
    827    *access = mmu_attr_to_access(entry->attr) &
    828        ~(dtlb ? PAGE_EXEC : PAGE_READ | PAGE_WRITE);
    829    if (!is_access_granted(*access, is_write)) {
    830        return dtlb ?
    831            (is_write ?
    832             STORE_PROHIBITED_CAUSE :
    833             LOAD_PROHIBITED_CAUSE) :
    834            INST_FETCH_PROHIBITED_CAUSE;
    835    }
    836
    837    *paddr = entry->paddr | (vaddr & ~xtensa_tlb_get_addr_mask(env, dtlb, wi));
    838    *page_size = ~xtensa_tlb_get_addr_mask(env, dtlb, wi) + 1;
    839
    840    return 0;
    841}
    842
    843static bool get_pte(CPUXtensaState *env, uint32_t vaddr, uint32_t *pte)
    844{
    845    CPUState *cs = env_cpu(env);
    846    uint32_t paddr;
    847    uint32_t page_size;
    848    unsigned access;
    849    uint32_t pt_vaddr =
    850        (env->sregs[PTEVADDR] | (vaddr >> 10)) & 0xfffffffc;
    851    int ret = get_physical_addr_mmu(env, false, pt_vaddr, 0, 0,
    852                                    &paddr, &page_size, &access, false);
    853
    854    if (ret == 0) {
    855        qemu_log_mask(CPU_LOG_MMU,
    856                      "%s: autorefill(%08x): PTE va = %08x, pa = %08x\n",
    857                      __func__, vaddr, pt_vaddr, paddr);
    858    } else {
    859        qemu_log_mask(CPU_LOG_MMU,
    860                      "%s: autorefill(%08x): PTE va = %08x, failed (%d)\n",
    861                      __func__, vaddr, pt_vaddr, ret);
    862    }
    863
    864    if (ret == 0) {
    865        MemTxResult result;
    866
    867        *pte = address_space_ldl(cs->as, paddr, MEMTXATTRS_UNSPECIFIED,
    868                                 &result);
    869        if (result != MEMTX_OK) {
    870            qemu_log_mask(CPU_LOG_MMU,
    871                          "%s: couldn't load PTE: transaction failed (%u)\n",
    872                          __func__, (unsigned)result);
    873            ret = 1;
    874        }
    875    }
    876    return ret == 0;
    877}
    878
    879static int get_physical_addr_region(CPUXtensaState *env,
    880                                    uint32_t vaddr, int is_write, int mmu_idx,
    881                                    uint32_t *paddr, uint32_t *page_size,
    882                                    unsigned *access)
    883{
    884    bool dtlb = is_write != 2;
    885    uint32_t wi = 0;
    886    uint32_t ei = (vaddr >> 29) & 0x7;
    887    const xtensa_tlb_entry *entry =
    888        xtensa_tlb_get_entry(env, dtlb, wi, ei);
    889
    890    *access = region_attr_to_access(entry->attr);
    891    if (!is_access_granted(*access, is_write)) {
    892        return dtlb ?
    893            (is_write ?
    894             STORE_PROHIBITED_CAUSE :
    895             LOAD_PROHIBITED_CAUSE) :
    896            INST_FETCH_PROHIBITED_CAUSE;
    897    }
    898
    899    *paddr = entry->paddr | (vaddr & ~REGION_PAGE_MASK);
    900    *page_size = ~REGION_PAGE_MASK + 1;
    901
    902    return 0;
    903}
    904
    905static int xtensa_mpu_lookup(const xtensa_mpu_entry *entry, unsigned n,
    906                             uint32_t vaddr, unsigned *segment)
    907{
    908    unsigned nhits = 0;
    909    unsigned i;
    910
    911    for (i = 0; i < n; ++i) {
    912        if (vaddr >= entry[i].vaddr &&
    913            (i == n - 1 || vaddr < entry[i + 1].vaddr)) {
    914            if (nhits++) {
    915                break;
    916            }
    917            *segment = i;
    918        }
    919    }
    920    return nhits;
    921}
    922
    923void HELPER(wsr_mpuenb)(CPUXtensaState *env, uint32_t v)
    924{
    925    v &= (2u << (env->config->n_mpu_fg_segments - 1)) - 1;
    926
    927    if (v != env->sregs[MPUENB]) {
    928        env->sregs[MPUENB] = v;
    929        tlb_flush(env_cpu(env));
    930    }
    931}
    932
    933void HELPER(wptlb)(CPUXtensaState *env, uint32_t p, uint32_t v)
    934{
    935    unsigned segment = p & XTENSA_MPU_SEGMENT_MASK;
    936
    937    if (segment < env->config->n_mpu_fg_segments) {
    938        env->mpu_fg[segment].vaddr = v & -env->config->mpu_align;
    939        env->mpu_fg[segment].attr = p & XTENSA_MPU_ATTR_MASK;
    940        env->sregs[MPUENB] = deposit32(env->sregs[MPUENB], segment, 1, v);
    941        tlb_flush(env_cpu(env));
    942    }
    943}
    944
    945uint32_t HELPER(rptlb0)(CPUXtensaState *env, uint32_t s)
    946{
    947    unsigned segment = s & XTENSA_MPU_SEGMENT_MASK;
    948
    949    if (segment < env->config->n_mpu_fg_segments) {
    950        return env->mpu_fg[segment].vaddr |
    951            extract32(env->sregs[MPUENB], segment, 1);
    952    } else {
    953        return 0;
    954    }
    955}
    956
    957uint32_t HELPER(rptlb1)(CPUXtensaState *env, uint32_t s)
    958{
    959    unsigned segment = s & XTENSA_MPU_SEGMENT_MASK;
    960
    961    if (segment < env->config->n_mpu_fg_segments) {
    962        return env->mpu_fg[segment].attr;
    963    } else {
    964        return 0;
    965    }
    966}
    967
    968uint32_t HELPER(pptlb)(CPUXtensaState *env, uint32_t v)
    969{
    970    unsigned nhits;
    971    unsigned segment = XTENSA_MPU_PROBE_B;
    972    unsigned bg_segment;
    973
    974    nhits = xtensa_mpu_lookup(env->mpu_fg, env->config->n_mpu_fg_segments,
    975                              v, &segment);
    976    if (nhits > 1) {
    977        HELPER(exception_cause_vaddr)(env, env->pc,
    978                                      LOAD_STORE_TLB_MULTI_HIT_CAUSE, v);
    979    } else if (nhits == 1 && (env->sregs[MPUENB] & (1u << segment))) {
    980        return env->mpu_fg[segment].attr | segment | XTENSA_MPU_PROBE_V;
    981    } else {
    982        xtensa_mpu_lookup(env->config->mpu_bg,
    983                          env->config->n_mpu_bg_segments,
    984                          v, &bg_segment);
    985        return env->config->mpu_bg[bg_segment].attr | segment;
    986    }
    987}
    988
    989static int get_physical_addr_mpu(CPUXtensaState *env,
    990                                 uint32_t vaddr, int is_write, int mmu_idx,
    991                                 uint32_t *paddr, uint32_t *page_size,
    992                                 unsigned *access)
    993{
    994    unsigned nhits;
    995    unsigned segment;
    996    uint32_t attr;
    997
    998    nhits = xtensa_mpu_lookup(env->mpu_fg, env->config->n_mpu_fg_segments,
    999                              vaddr, &segment);
   1000    if (nhits > 1) {
   1001        return is_write < 2 ?
   1002            LOAD_STORE_TLB_MULTI_HIT_CAUSE :
   1003            INST_TLB_MULTI_HIT_CAUSE;
   1004    } else if (nhits == 1 && (env->sregs[MPUENB] & (1u << segment))) {
   1005        attr = env->mpu_fg[segment].attr;
   1006    } else {
   1007        xtensa_mpu_lookup(env->config->mpu_bg,
   1008                          env->config->n_mpu_bg_segments,
   1009                          vaddr, &segment);
   1010        attr = env->config->mpu_bg[segment].attr;
   1011    }
   1012
   1013    *access = mpu_attr_to_access(attr, mmu_idx);
   1014    if (!is_access_granted(*access, is_write)) {
   1015        return is_write < 2 ?
   1016            (is_write ?
   1017             STORE_PROHIBITED_CAUSE :
   1018             LOAD_PROHIBITED_CAUSE) :
   1019            INST_FETCH_PROHIBITED_CAUSE;
   1020    }
   1021    *paddr = vaddr;
   1022    *page_size = env->config->mpu_align;
   1023    return 0;
   1024}
   1025
   1026/*!
   1027 * Convert virtual address to physical addr.
   1028 * MMU may issue pagewalk and change xtensa autorefill TLB way entry.
   1029 *
   1030 * \return 0 if ok, exception cause code otherwise
   1031 */
   1032int xtensa_get_physical_addr(CPUXtensaState *env, bool update_tlb,
   1033                             uint32_t vaddr, int is_write, int mmu_idx,
   1034                             uint32_t *paddr, uint32_t *page_size,
   1035                             unsigned *access)
   1036{
   1037    if (xtensa_option_enabled(env->config, XTENSA_OPTION_MMU)) {
   1038        return get_physical_addr_mmu(env, update_tlb,
   1039                                     vaddr, is_write, mmu_idx, paddr,
   1040                                     page_size, access, true);
   1041    } else if (xtensa_option_bits_enabled(env->config,
   1042                XTENSA_OPTION_BIT(XTENSA_OPTION_REGION_PROTECTION) |
   1043                XTENSA_OPTION_BIT(XTENSA_OPTION_REGION_TRANSLATION))) {
   1044        return get_physical_addr_region(env, vaddr, is_write, mmu_idx,
   1045                                        paddr, page_size, access);
   1046    } else if (xtensa_option_enabled(env->config, XTENSA_OPTION_MPU)) {
   1047        return get_physical_addr_mpu(env, vaddr, is_write, mmu_idx,
   1048                                     paddr, page_size, access);
   1049    } else {
   1050        *paddr = vaddr;
   1051        *page_size = TARGET_PAGE_SIZE;
   1052        *access = cacheattr_attr_to_access(env->sregs[CACHEATTR] >>
   1053                                           ((vaddr & 0xe0000000) >> 27));
   1054        return 0;
   1055    }
   1056}
   1057
   1058static void dump_tlb(CPUXtensaState *env, bool dtlb)
   1059{
   1060    unsigned wi, ei;
   1061    const xtensa_tlb *conf =
   1062        dtlb ? &env->config->dtlb : &env->config->itlb;
   1063    unsigned (*attr_to_access)(uint32_t) =
   1064        xtensa_option_enabled(env->config, XTENSA_OPTION_MMU) ?
   1065        mmu_attr_to_access : region_attr_to_access;
   1066
   1067    for (wi = 0; wi < conf->nways; ++wi) {
   1068        uint32_t sz = ~xtensa_tlb_get_addr_mask(env, dtlb, wi) + 1;
   1069        const char *sz_text;
   1070        bool print_header = true;
   1071
   1072        if (sz >= 0x100000) {
   1073            sz /= MiB;
   1074            sz_text = "MB";
   1075        } else {
   1076            sz /= KiB;
   1077            sz_text = "KB";
   1078        }
   1079
   1080        for (ei = 0; ei < conf->way_size[wi]; ++ei) {
   1081            const xtensa_tlb_entry *entry =
   1082                xtensa_tlb_get_entry(env, dtlb, wi, ei);
   1083
   1084            if (entry->asid) {
   1085                static const char * const cache_text[8] = {
   1086                    [PAGE_CACHE_BYPASS >> PAGE_CACHE_SHIFT] = "Bypass",
   1087                    [PAGE_CACHE_WT >> PAGE_CACHE_SHIFT] = "WT",
   1088                    [PAGE_CACHE_WB >> PAGE_CACHE_SHIFT] = "WB",
   1089                    [PAGE_CACHE_ISOLATE >> PAGE_CACHE_SHIFT] = "Isolate",
   1090                };
   1091                unsigned access = attr_to_access(entry->attr);
   1092                unsigned cache_idx = (access & PAGE_CACHE_MASK) >>
   1093                    PAGE_CACHE_SHIFT;
   1094
   1095                if (print_header) {
   1096                    print_header = false;
   1097                    qemu_printf("Way %u (%d %s)\n", wi, sz, sz_text);
   1098                    qemu_printf("\tVaddr       Paddr       ASID  Attr RWX Cache\n"
   1099                                "\t----------  ----------  ----  ---- --- -------\n");
   1100                }
   1101                qemu_printf("\t0x%08x  0x%08x  0x%02x  0x%02x %c%c%c %-7s\n",
   1102                            entry->vaddr,
   1103                            entry->paddr,
   1104                            entry->asid,
   1105                            entry->attr,
   1106                            (access & PAGE_READ) ? 'R' : '-',
   1107                            (access & PAGE_WRITE) ? 'W' : '-',
   1108                            (access & PAGE_EXEC) ? 'X' : '-',
   1109                            cache_text[cache_idx] ?
   1110                            cache_text[cache_idx] : "Invalid");
   1111            }
   1112        }
   1113    }
   1114}
   1115
   1116static void dump_mpu(CPUXtensaState *env,
   1117                     const xtensa_mpu_entry *entry, unsigned n)
   1118{
   1119    unsigned i;
   1120
   1121    qemu_printf("\t%s  Vaddr       Attr        Ring0  Ring1  System Type    CPU cache\n"
   1122                "\t%s  ----------  ----------  -----  -----  -------------  ---------\n",
   1123                env ? "En" : "  ",
   1124                env ? "--" : "  ");
   1125
   1126    for (i = 0; i < n; ++i) {
   1127        uint32_t attr = entry[i].attr;
   1128        unsigned access0 = mpu_attr_to_access(attr, 0);
   1129        unsigned access1 = mpu_attr_to_access(attr, 1);
   1130        unsigned type = mpu_attr_to_type(attr);
   1131        char cpu_cache = (type & XTENSA_MPU_TYPE_CPU_CACHE) ? '-' : ' ';
   1132
   1133        qemu_printf("\t %c  0x%08x  0x%08x   %c%c%c    %c%c%c   ",
   1134                    env ?
   1135                    ((env->sregs[MPUENB] & (1u << i)) ? '+' : '-') : ' ',
   1136                    entry[i].vaddr, attr,
   1137                    (access0 & PAGE_READ) ? 'R' : '-',
   1138                    (access0 & PAGE_WRITE) ? 'W' : '-',
   1139                    (access0 & PAGE_EXEC) ? 'X' : '-',
   1140                    (access1 & PAGE_READ) ? 'R' : '-',
   1141                    (access1 & PAGE_WRITE) ? 'W' : '-',
   1142                    (access1 & PAGE_EXEC) ? 'X' : '-');
   1143
   1144        switch (type & XTENSA_MPU_SYSTEM_TYPE_MASK) {
   1145        case XTENSA_MPU_SYSTEM_TYPE_DEVICE:
   1146            qemu_printf("Device %cB %3s\n",
   1147                        (type & XTENSA_MPU_TYPE_B) ? ' ' : 'n',
   1148                        (type & XTENSA_MPU_TYPE_INT) ? "int" : "");
   1149            break;
   1150        case XTENSA_MPU_SYSTEM_TYPE_NC:
   1151            qemu_printf("Sys NC %cB      %c%c%c\n",
   1152                        (type & XTENSA_MPU_TYPE_B) ? ' ' : 'n',
   1153                        (type & XTENSA_MPU_TYPE_CPU_R) ? 'r' : cpu_cache,
   1154                        (type & XTENSA_MPU_TYPE_CPU_W) ? 'w' : cpu_cache,
   1155                        (type & XTENSA_MPU_TYPE_CPU_C) ? 'c' : cpu_cache);
   1156            break;
   1157        case XTENSA_MPU_SYSTEM_TYPE_C:
   1158            qemu_printf("Sys  C %c%c%c     %c%c%c\n",
   1159                        (type & XTENSA_MPU_TYPE_SYS_R) ? 'R' : '-',
   1160                        (type & XTENSA_MPU_TYPE_SYS_W) ? 'W' : '-',
   1161                        (type & XTENSA_MPU_TYPE_SYS_C) ? 'C' : '-',
   1162                        (type & XTENSA_MPU_TYPE_CPU_R) ? 'r' : cpu_cache,
   1163                        (type & XTENSA_MPU_TYPE_CPU_W) ? 'w' : cpu_cache,
   1164                        (type & XTENSA_MPU_TYPE_CPU_C) ? 'c' : cpu_cache);
   1165            break;
   1166        default:
   1167            qemu_printf("Unknown\n");
   1168            break;
   1169        }
   1170    }
   1171}
   1172
   1173void dump_mmu(CPUXtensaState *env)
   1174{
   1175    if (xtensa_option_bits_enabled(env->config,
   1176                XTENSA_OPTION_BIT(XTENSA_OPTION_REGION_PROTECTION) |
   1177                XTENSA_OPTION_BIT(XTENSA_OPTION_REGION_TRANSLATION) |
   1178                XTENSA_OPTION_BIT(XTENSA_OPTION_MMU))) {
   1179
   1180        qemu_printf("ITLB:\n");
   1181        dump_tlb(env, false);
   1182        qemu_printf("\nDTLB:\n");
   1183        dump_tlb(env, true);
   1184    } else if (xtensa_option_enabled(env->config, XTENSA_OPTION_MPU)) {
   1185        qemu_printf("Foreground map:\n");
   1186        dump_mpu(env, env->mpu_fg, env->config->n_mpu_fg_segments);
   1187        qemu_printf("\nBackground map:\n");
   1188        dump_mpu(NULL, env->config->mpu_bg, env->config->n_mpu_bg_segments);
   1189    } else {
   1190        qemu_printf("No TLB for this CPU core\n");
   1191    }
   1192}