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