qemu/target/ppc/mmu_helper.c
<<
>>
Prefs
   1/*
   2 *  PowerPC MMU, TLB, SLB and BAT emulation helpers for QEMU.
   3 *
   4 *  Copyright (c) 2003-2007 Jocelyn Mayer
   5 *
   6 * This library is free software; you can redistribute it and/or
   7 * modify it under the terms of the GNU Lesser General Public
   8 * License as published by the Free Software Foundation; either
   9 * version 2 of the License, or (at your option) any later version.
  10 *
  11 * This library is distributed in the hope that it will be useful,
  12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  14 * Lesser General Public License for more details.
  15 *
  16 * You should have received a copy of the GNU Lesser General Public
  17 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
  18 */
  19#include "qemu/osdep.h"
  20#include "cpu.h"
  21#include "exec/helper-proto.h"
  22#include "sysemu/kvm.h"
  23#include "kvm_ppc.h"
  24#include "mmu-hash64.h"
  25#include "mmu-hash32.h"
  26#include "exec/exec-all.h"
  27#include "exec/cpu_ldst.h"
  28#include "exec/log.h"
  29#include "helper_regs.h"
  30#include "qemu/error-report.h"
  31#include "mmu-book3s-v3.h"
  32#include "mmu-radix64.h"
  33
  34//#define DEBUG_MMU
  35//#define DEBUG_BATS
  36//#define DEBUG_SOFTWARE_TLB
  37//#define DUMP_PAGE_TABLES
  38//#define FLUSH_ALL_TLBS
  39
  40#ifdef DEBUG_MMU
  41#  define LOG_MMU_STATE(cpu) log_cpu_state_mask(CPU_LOG_MMU, (cpu), 0)
  42#else
  43#  define LOG_MMU_STATE(cpu) do { } while (0)
  44#endif
  45
  46#ifdef DEBUG_SOFTWARE_TLB
  47#  define LOG_SWTLB(...) qemu_log_mask(CPU_LOG_MMU, __VA_ARGS__)
  48#else
  49#  define LOG_SWTLB(...) do { } while (0)
  50#endif
  51
  52#ifdef DEBUG_BATS
  53#  define LOG_BATS(...) qemu_log_mask(CPU_LOG_MMU, __VA_ARGS__)
  54#else
  55#  define LOG_BATS(...) do { } while (0)
  56#endif
  57
  58/*****************************************************************************/
  59/* PowerPC MMU emulation */
  60
  61/* Context used internally during MMU translations */
  62typedef struct mmu_ctx_t mmu_ctx_t;
  63struct mmu_ctx_t {
  64    hwaddr raddr;      /* Real address              */
  65    hwaddr eaddr;      /* Effective address         */
  66    int prot;                      /* Protection bits           */
  67    hwaddr hash[2];    /* Pagetable hash values     */
  68    target_ulong ptem;             /* Virtual segment ID | API  */
  69    int key;                       /* Access key                */
  70    int nx;                        /* Non-execute area          */
  71};
  72
  73/* Common routines used by software and hardware TLBs emulation */
  74static inline int pte_is_valid(target_ulong pte0)
  75{
  76    return pte0 & 0x80000000 ? 1 : 0;
  77}
  78
  79static inline void pte_invalidate(target_ulong *pte0)
  80{
  81    *pte0 &= ~0x80000000;
  82}
  83
  84#define PTE_PTEM_MASK 0x7FFFFFBF
  85#define PTE_CHECK_MASK (TARGET_PAGE_MASK | 0x7B)
  86
  87static int pp_check(int key, int pp, int nx)
  88{
  89    int access;
  90
  91    /* Compute access rights */
  92    access = 0;
  93    if (key == 0) {
  94        switch (pp) {
  95        case 0x0:
  96        case 0x1:
  97        case 0x2:
  98            access |= PAGE_WRITE;
  99            /* No break here */
 100        case 0x3:
 101            access |= PAGE_READ;
 102            break;
 103        }
 104    } else {
 105        switch (pp) {
 106        case 0x0:
 107            access = 0;
 108            break;
 109        case 0x1:
 110        case 0x3:
 111            access = PAGE_READ;
 112            break;
 113        case 0x2:
 114            access = PAGE_READ | PAGE_WRITE;
 115            break;
 116        }
 117    }
 118    if (nx == 0) {
 119        access |= PAGE_EXEC;
 120    }
 121
 122    return access;
 123}
 124
 125static int check_prot(int prot, int rw, int access_type)
 126{
 127    int ret;
 128
 129    if (access_type == ACCESS_CODE) {
 130        if (prot & PAGE_EXEC) {
 131            ret = 0;
 132        } else {
 133            ret = -2;
 134        }
 135    } else if (rw) {
 136        if (prot & PAGE_WRITE) {
 137            ret = 0;
 138        } else {
 139            ret = -2;
 140        }
 141    } else {
 142        if (prot & PAGE_READ) {
 143            ret = 0;
 144        } else {
 145            ret = -2;
 146        }
 147    }
 148
 149    return ret;
 150}
 151
 152static inline int ppc6xx_tlb_pte_check(mmu_ctx_t *ctx, target_ulong pte0,
 153                                       target_ulong pte1, int h, int rw, int type)
 154{
 155    target_ulong ptem, mmask;
 156    int access, ret, pteh, ptev, pp;
 157
 158    ret = -1;
 159    /* Check validity and table match */
 160    ptev = pte_is_valid(pte0);
 161    pteh = (pte0 >> 6) & 1;
 162    if (ptev && h == pteh) {
 163        /* Check vsid & api */
 164        ptem = pte0 & PTE_PTEM_MASK;
 165        mmask = PTE_CHECK_MASK;
 166        pp = pte1 & 0x00000003;
 167        if (ptem == ctx->ptem) {
 168            if (ctx->raddr != (hwaddr)-1ULL) {
 169                /* all matches should have equal RPN, WIMG & PP */
 170                if ((ctx->raddr & mmask) != (pte1 & mmask)) {
 171                    qemu_log_mask(CPU_LOG_MMU, "Bad RPN/WIMG/PP\n");
 172                    return -3;
 173                }
 174            }
 175            /* Compute access rights */
 176            access = pp_check(ctx->key, pp, ctx->nx);
 177            /* Keep the matching PTE informations */
 178            ctx->raddr = pte1;
 179            ctx->prot = access;
 180            ret = check_prot(ctx->prot, rw, type);
 181            if (ret == 0) {
 182                /* Access granted */
 183                qemu_log_mask(CPU_LOG_MMU, "PTE access granted !\n");
 184            } else {
 185                /* Access right violation */
 186                qemu_log_mask(CPU_LOG_MMU, "PTE access rejected\n");
 187            }
 188        }
 189    }
 190
 191    return ret;
 192}
 193
 194static int pte_update_flags(mmu_ctx_t *ctx, target_ulong *pte1p,
 195                            int ret, int rw)
 196{
 197    int store = 0;
 198
 199    /* Update page flags */
 200    if (!(*pte1p & 0x00000100)) {
 201        /* Update accessed flag */
 202        *pte1p |= 0x00000100;
 203        store = 1;
 204    }
 205    if (!(*pte1p & 0x00000080)) {
 206        if (rw == 1 && ret == 0) {
 207            /* Update changed flag */
 208            *pte1p |= 0x00000080;
 209            store = 1;
 210        } else {
 211            /* Force page fault for first write access */
 212            ctx->prot &= ~PAGE_WRITE;
 213        }
 214    }
 215
 216    return store;
 217}
 218
 219/* Software driven TLB helpers */
 220static inline int ppc6xx_tlb_getnum(CPUPPCState *env, target_ulong eaddr,
 221                                    int way, int is_code)
 222{
 223    int nr;
 224
 225    /* Select TLB num in a way from address */
 226    nr = (eaddr >> TARGET_PAGE_BITS) & (env->tlb_per_way - 1);
 227    /* Select TLB way */
 228    nr += env->tlb_per_way * way;
 229    /* 6xx have separate TLBs for instructions and data */
 230    if (is_code && env->id_tlbs == 1) {
 231        nr += env->nb_tlb;
 232    }
 233
 234    return nr;
 235}
 236
 237static inline void ppc6xx_tlb_invalidate_all(CPUPPCState *env)
 238{
 239    PowerPCCPU *cpu = ppc_env_get_cpu(env);
 240    ppc6xx_tlb_t *tlb;
 241    int nr, max;
 242
 243    /* LOG_SWTLB("Invalidate all TLBs\n"); */
 244    /* Invalidate all defined software TLB */
 245    max = env->nb_tlb;
 246    if (env->id_tlbs == 1) {
 247        max *= 2;
 248    }
 249    for (nr = 0; nr < max; nr++) {
 250        tlb = &env->tlb.tlb6[nr];
 251        pte_invalidate(&tlb->pte0);
 252    }
 253    tlb_flush(CPU(cpu));
 254}
 255
 256static inline void ppc6xx_tlb_invalidate_virt2(CPUPPCState *env,
 257                                               target_ulong eaddr,
 258                                               int is_code, int match_epn)
 259{
 260#if !defined(FLUSH_ALL_TLBS)
 261    CPUState *cs = CPU(ppc_env_get_cpu(env));
 262    ppc6xx_tlb_t *tlb;
 263    int way, nr;
 264
 265    /* Invalidate ITLB + DTLB, all ways */
 266    for (way = 0; way < env->nb_ways; way++) {
 267        nr = ppc6xx_tlb_getnum(env, eaddr, way, is_code);
 268        tlb = &env->tlb.tlb6[nr];
 269        if (pte_is_valid(tlb->pte0) && (match_epn == 0 || eaddr == tlb->EPN)) {
 270            LOG_SWTLB("TLB invalidate %d/%d " TARGET_FMT_lx "\n", nr,
 271                      env->nb_tlb, eaddr);
 272            pte_invalidate(&tlb->pte0);
 273            tlb_flush_page(cs, tlb->EPN);
 274        }
 275    }
 276#else
 277    /* XXX: PowerPC specification say this is valid as well */
 278    ppc6xx_tlb_invalidate_all(env);
 279#endif
 280}
 281
 282static inline void ppc6xx_tlb_invalidate_virt(CPUPPCState *env,
 283                                              target_ulong eaddr, int is_code)
 284{
 285    ppc6xx_tlb_invalidate_virt2(env, eaddr, is_code, 0);
 286}
 287
 288static void ppc6xx_tlb_store(CPUPPCState *env, target_ulong EPN, int way,
 289                             int is_code, target_ulong pte0, target_ulong pte1)
 290{
 291    ppc6xx_tlb_t *tlb;
 292    int nr;
 293
 294    nr = ppc6xx_tlb_getnum(env, EPN, way, is_code);
 295    tlb = &env->tlb.tlb6[nr];
 296    LOG_SWTLB("Set TLB %d/%d EPN " TARGET_FMT_lx " PTE0 " TARGET_FMT_lx
 297              " PTE1 " TARGET_FMT_lx "\n", nr, env->nb_tlb, EPN, pte0, pte1);
 298    /* Invalidate any pending reference in QEMU for this virtual address */
 299    ppc6xx_tlb_invalidate_virt2(env, EPN, is_code, 1);
 300    tlb->pte0 = pte0;
 301    tlb->pte1 = pte1;
 302    tlb->EPN = EPN;
 303    /* Store last way for LRU mechanism */
 304    env->last_way = way;
 305}
 306
 307static inline int ppc6xx_tlb_check(CPUPPCState *env, mmu_ctx_t *ctx,
 308                                   target_ulong eaddr, int rw, int access_type)
 309{
 310    ppc6xx_tlb_t *tlb;
 311    int nr, best, way;
 312    int ret;
 313
 314    best = -1;
 315    ret = -1; /* No TLB found */
 316    for (way = 0; way < env->nb_ways; way++) {
 317        nr = ppc6xx_tlb_getnum(env, eaddr, way,
 318                               access_type == ACCESS_CODE ? 1 : 0);
 319        tlb = &env->tlb.tlb6[nr];
 320        /* This test "emulates" the PTE index match for hardware TLBs */
 321        if ((eaddr & TARGET_PAGE_MASK) != tlb->EPN) {
 322            LOG_SWTLB("TLB %d/%d %s [" TARGET_FMT_lx " " TARGET_FMT_lx
 323                      "] <> " TARGET_FMT_lx "\n", nr, env->nb_tlb,
 324                      pte_is_valid(tlb->pte0) ? "valid" : "inval",
 325                      tlb->EPN, tlb->EPN + TARGET_PAGE_SIZE, eaddr);
 326            continue;
 327        }
 328        LOG_SWTLB("TLB %d/%d %s " TARGET_FMT_lx " <> " TARGET_FMT_lx " "
 329                  TARGET_FMT_lx " %c %c\n", nr, env->nb_tlb,
 330                  pte_is_valid(tlb->pte0) ? "valid" : "inval",
 331                  tlb->EPN, eaddr, tlb->pte1,
 332                  rw ? 'S' : 'L', access_type == ACCESS_CODE ? 'I' : 'D');
 333        switch (ppc6xx_tlb_pte_check(ctx, tlb->pte0, tlb->pte1, 0, rw, access_type)) {
 334        case -3:
 335            /* TLB inconsistency */
 336            return -1;
 337        case -2:
 338            /* Access violation */
 339            ret = -2;
 340            best = nr;
 341            break;
 342        case -1:
 343        default:
 344            /* No match */
 345            break;
 346        case 0:
 347            /* access granted */
 348            /* XXX: we should go on looping to check all TLBs consistency
 349             *      but we can speed-up the whole thing as the
 350             *      result would be undefined if TLBs are not consistent.
 351             */
 352            ret = 0;
 353            best = nr;
 354            goto done;
 355        }
 356    }
 357    if (best != -1) {
 358    done:
 359        LOG_SWTLB("found TLB at addr " TARGET_FMT_plx " prot=%01x ret=%d\n",
 360                  ctx->raddr & TARGET_PAGE_MASK, ctx->prot, ret);
 361        /* Update page flags */
 362        pte_update_flags(ctx, &env->tlb.tlb6[best].pte1, ret, rw);
 363    }
 364
 365    return ret;
 366}
 367
 368/* Perform BAT hit & translation */
 369static inline void bat_size_prot(CPUPPCState *env, target_ulong *blp,
 370                                 int *validp, int *protp, target_ulong *BATu,
 371                                 target_ulong *BATl)
 372{
 373    target_ulong bl;
 374    int pp, valid, prot;
 375
 376    bl = (*BATu & 0x00001FFC) << 15;
 377    valid = 0;
 378    prot = 0;
 379    if (((msr_pr == 0) && (*BATu & 0x00000002)) ||
 380        ((msr_pr != 0) && (*BATu & 0x00000001))) {
 381        valid = 1;
 382        pp = *BATl & 0x00000003;
 383        if (pp != 0) {
 384            prot = PAGE_READ | PAGE_EXEC;
 385            if (pp == 0x2) {
 386                prot |= PAGE_WRITE;
 387            }
 388        }
 389    }
 390    *blp = bl;
 391    *validp = valid;
 392    *protp = prot;
 393}
 394
 395static int get_bat_6xx_tlb(CPUPPCState *env, mmu_ctx_t *ctx,
 396                           target_ulong virtual, int rw, int type)
 397{
 398    target_ulong *BATlt, *BATut, *BATu, *BATl;
 399    target_ulong BEPIl, BEPIu, bl;
 400    int i, valid, prot;
 401    int ret = -1;
 402
 403    LOG_BATS("%s: %cBAT v " TARGET_FMT_lx "\n", __func__,
 404             type == ACCESS_CODE ? 'I' : 'D', virtual);
 405    switch (type) {
 406    case ACCESS_CODE:
 407        BATlt = env->IBAT[1];
 408        BATut = env->IBAT[0];
 409        break;
 410    default:
 411        BATlt = env->DBAT[1];
 412        BATut = env->DBAT[0];
 413        break;
 414    }
 415    for (i = 0; i < env->nb_BATs; i++) {
 416        BATu = &BATut[i];
 417        BATl = &BATlt[i];
 418        BEPIu = *BATu & 0xF0000000;
 419        BEPIl = *BATu & 0x0FFE0000;
 420        bat_size_prot(env, &bl, &valid, &prot, BATu, BATl);
 421        LOG_BATS("%s: %cBAT%d v " TARGET_FMT_lx " BATu " TARGET_FMT_lx
 422                 " BATl " TARGET_FMT_lx "\n", __func__,
 423                 type == ACCESS_CODE ? 'I' : 'D', i, virtual, *BATu, *BATl);
 424        if ((virtual & 0xF0000000) == BEPIu &&
 425            ((virtual & 0x0FFE0000) & ~bl) == BEPIl) {
 426            /* BAT matches */
 427            if (valid != 0) {
 428                /* Get physical address */
 429                ctx->raddr = (*BATl & 0xF0000000) |
 430                    ((virtual & 0x0FFE0000 & bl) | (*BATl & 0x0FFE0000)) |
 431                    (virtual & 0x0001F000);
 432                /* Compute access rights */
 433                ctx->prot = prot;
 434                ret = check_prot(ctx->prot, rw, type);
 435                if (ret == 0) {
 436                    LOG_BATS("BAT %d match: r " TARGET_FMT_plx " prot=%c%c\n",
 437                             i, ctx->raddr, ctx->prot & PAGE_READ ? 'R' : '-',
 438                             ctx->prot & PAGE_WRITE ? 'W' : '-');
 439                }
 440                break;
 441            }
 442        }
 443    }
 444    if (ret < 0) {
 445#if defined(DEBUG_BATS)
 446        if (qemu_log_enabled()) {
 447            LOG_BATS("no BAT match for " TARGET_FMT_lx ":\n", virtual);
 448            for (i = 0; i < 4; i++) {
 449                BATu = &BATut[i];
 450                BATl = &BATlt[i];
 451                BEPIu = *BATu & 0xF0000000;
 452                BEPIl = *BATu & 0x0FFE0000;
 453                bl = (*BATu & 0x00001FFC) << 15;
 454                LOG_BATS("%s: %cBAT%d v " TARGET_FMT_lx " BATu " TARGET_FMT_lx
 455                         " BATl " TARGET_FMT_lx "\n\t" TARGET_FMT_lx " "
 456                         TARGET_FMT_lx " " TARGET_FMT_lx "\n",
 457                         __func__, type == ACCESS_CODE ? 'I' : 'D', i, virtual,
 458                         *BATu, *BATl, BEPIu, BEPIl, bl);
 459            }
 460        }
 461#endif
 462    }
 463    /* No hit */
 464    return ret;
 465}
 466
 467/* Perform segment based translation */
 468static inline int get_segment_6xx_tlb(CPUPPCState *env, mmu_ctx_t *ctx,
 469                                      target_ulong eaddr, int rw, int type)
 470{
 471    PowerPCCPU *cpu = ppc_env_get_cpu(env);
 472    hwaddr hash;
 473    target_ulong vsid;
 474    int ds, pr, target_page_bits;
 475    int ret;
 476    target_ulong sr, pgidx;
 477
 478    pr = msr_pr;
 479    ctx->eaddr = eaddr;
 480
 481    sr = env->sr[eaddr >> 28];
 482    ctx->key = (((sr & 0x20000000) && (pr != 0)) ||
 483                ((sr & 0x40000000) && (pr == 0))) ? 1 : 0;
 484    ds = sr & 0x80000000 ? 1 : 0;
 485    ctx->nx = sr & 0x10000000 ? 1 : 0;
 486    vsid = sr & 0x00FFFFFF;
 487    target_page_bits = TARGET_PAGE_BITS;
 488    qemu_log_mask(CPU_LOG_MMU,
 489            "Check segment v=" TARGET_FMT_lx " %d " TARGET_FMT_lx
 490            " nip=" TARGET_FMT_lx " lr=" TARGET_FMT_lx
 491            " ir=%d dr=%d pr=%d %d t=%d\n",
 492            eaddr, (int)(eaddr >> 28), sr, env->nip, env->lr, (int)msr_ir,
 493            (int)msr_dr, pr != 0 ? 1 : 0, rw, type);
 494    pgidx = (eaddr & ~SEGMENT_MASK_256M) >> target_page_bits;
 495    hash = vsid ^ pgidx;
 496    ctx->ptem = (vsid << 7) | (pgidx >> 10);
 497
 498    qemu_log_mask(CPU_LOG_MMU,
 499            "pte segment: key=%d ds %d nx %d vsid " TARGET_FMT_lx "\n",
 500            ctx->key, ds, ctx->nx, vsid);
 501    ret = -1;
 502    if (!ds) {
 503        /* Check if instruction fetch is allowed, if needed */
 504        if (type != ACCESS_CODE || ctx->nx == 0) {
 505            /* Page address translation */
 506            qemu_log_mask(CPU_LOG_MMU, "htab_base " TARGET_FMT_plx
 507                    " htab_mask " TARGET_FMT_plx
 508                    " hash " TARGET_FMT_plx "\n",
 509                    ppc_hash32_hpt_base(cpu), ppc_hash32_hpt_mask(cpu), hash);
 510            ctx->hash[0] = hash;
 511            ctx->hash[1] = ~hash;
 512
 513            /* Initialize real address with an invalid value */
 514            ctx->raddr = (hwaddr)-1ULL;
 515            /* Software TLB search */
 516            ret = ppc6xx_tlb_check(env, ctx, eaddr, rw, type);
 517#if defined(DUMP_PAGE_TABLES)
 518            if (qemu_loglevel_mask(CPU_LOG_MMU)) {
 519                CPUState *cs = ENV_GET_CPU(env);
 520                hwaddr curaddr;
 521                uint32_t a0, a1, a2, a3;
 522
 523                qemu_log("Page table: " TARGET_FMT_plx " len " TARGET_FMT_plx
 524                         "\n", ppc_hash32_hpt_base(cpu),
 525                         ppc_hash32_hpt_mask(env) + 0x80);
 526                for (curaddr = ppc_hash32_hpt_base(cpu);
 527                     curaddr < (ppc_hash32_hpt_base(cpu)
 528                                + ppc_hash32_hpt_mask(cpu) + 0x80);
 529                     curaddr += 16) {
 530                    a0 = ldl_phys(cs->as, curaddr);
 531                    a1 = ldl_phys(cs->as, curaddr + 4);
 532                    a2 = ldl_phys(cs->as, curaddr + 8);
 533                    a3 = ldl_phys(cs->as, curaddr + 12);
 534                    if (a0 != 0 || a1 != 0 || a2 != 0 || a3 != 0) {
 535                        qemu_log(TARGET_FMT_plx ": %08x %08x %08x %08x\n",
 536                                 curaddr, a0, a1, a2, a3);
 537                    }
 538                }
 539            }
 540#endif
 541        } else {
 542            qemu_log_mask(CPU_LOG_MMU, "No access allowed\n");
 543            ret = -3;
 544        }
 545    } else {
 546        target_ulong sr;
 547
 548        qemu_log_mask(CPU_LOG_MMU, "direct store...\n");
 549        /* Direct-store segment : absolutely *BUGGY* for now */
 550
 551        /* Direct-store implies a 32-bit MMU.
 552         * Check the Segment Register's bus unit ID (BUID).
 553         */
 554        sr = env->sr[eaddr >> 28];
 555        if ((sr & 0x1FF00000) >> 20 == 0x07f) {
 556            /* Memory-forced I/O controller interface access */
 557            /* If T=1 and BUID=x'07F', the 601 performs a memory access
 558             * to SR[28-31] LA[4-31], bypassing all protection mechanisms.
 559             */
 560            ctx->raddr = ((sr & 0xF) << 28) | (eaddr & 0x0FFFFFFF);
 561            ctx->prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
 562            return 0;
 563        }
 564
 565        switch (type) {
 566        case ACCESS_INT:
 567            /* Integer load/store : only access allowed */
 568            break;
 569        case ACCESS_CODE:
 570            /* No code fetch is allowed in direct-store areas */
 571            return -4;
 572        case ACCESS_FLOAT:
 573            /* Floating point load/store */
 574            return -4;
 575        case ACCESS_RES:
 576            /* lwarx, ldarx or srwcx. */
 577            return -4;
 578        case ACCESS_CACHE:
 579            /* dcba, dcbt, dcbtst, dcbf, dcbi, dcbst, dcbz, or icbi */
 580            /* Should make the instruction do no-op.
 581             * As it already do no-op, it's quite easy :-)
 582             */
 583            ctx->raddr = eaddr;
 584            return 0;
 585        case ACCESS_EXT:
 586            /* eciwx or ecowx */
 587            return -4;
 588        default:
 589            qemu_log_mask(CPU_LOG_MMU, "ERROR: instruction should not need "
 590                          "address translation\n");
 591            return -4;
 592        }
 593        if ((rw == 1 || ctx->key != 1) && (rw == 0 || ctx->key != 0)) {
 594            ctx->raddr = eaddr;
 595            ret = 2;
 596        } else {
 597            ret = -2;
 598        }
 599    }
 600
 601    return ret;
 602}
 603
 604/* Generic TLB check function for embedded PowerPC implementations */
 605static int ppcemb_tlb_check(CPUPPCState *env, ppcemb_tlb_t *tlb,
 606                            hwaddr *raddrp,
 607                            target_ulong address, uint32_t pid, int ext,
 608                            int i)
 609{
 610    target_ulong mask;
 611
 612    /* Check valid flag */
 613    if (!(tlb->prot & PAGE_VALID)) {
 614        return -1;
 615    }
 616    mask = ~(tlb->size - 1);
 617    LOG_SWTLB("%s: TLB %d address " TARGET_FMT_lx " PID %u <=> " TARGET_FMT_lx
 618              " " TARGET_FMT_lx " %u %x\n", __func__, i, address, pid, tlb->EPN,
 619              mask, (uint32_t)tlb->PID, tlb->prot);
 620    /* Check PID */
 621    if (tlb->PID != 0 && tlb->PID != pid) {
 622        return -1;
 623    }
 624    /* Check effective address */
 625    if ((address & mask) != tlb->EPN) {
 626        return -1;
 627    }
 628    *raddrp = (tlb->RPN & mask) | (address & ~mask);
 629    if (ext) {
 630        /* Extend the physical address to 36 bits */
 631        *raddrp |= (uint64_t)(tlb->RPN & 0xF) << 32;
 632    }
 633
 634    return 0;
 635}
 636
 637/* Generic TLB search function for PowerPC embedded implementations */
 638static int ppcemb_tlb_search(CPUPPCState *env, target_ulong address,
 639                             uint32_t pid)
 640{
 641    ppcemb_tlb_t *tlb;
 642    hwaddr raddr;
 643    int i, ret;
 644
 645    /* Default return value is no match */
 646    ret = -1;
 647    for (i = 0; i < env->nb_tlb; i++) {
 648        tlb = &env->tlb.tlbe[i];
 649        if (ppcemb_tlb_check(env, tlb, &raddr, address, pid, 0, i) == 0) {
 650            ret = i;
 651            break;
 652        }
 653    }
 654
 655    return ret;
 656}
 657
 658/* Helpers specific to PowerPC 40x implementations */
 659static inline void ppc4xx_tlb_invalidate_all(CPUPPCState *env)
 660{
 661    PowerPCCPU *cpu = ppc_env_get_cpu(env);
 662    ppcemb_tlb_t *tlb;
 663    int i;
 664
 665    for (i = 0; i < env->nb_tlb; i++) {
 666        tlb = &env->tlb.tlbe[i];
 667        tlb->prot &= ~PAGE_VALID;
 668    }
 669    tlb_flush(CPU(cpu));
 670}
 671
 672static int mmu40x_get_physical_address(CPUPPCState *env, mmu_ctx_t *ctx,
 673                                       target_ulong address, int rw,
 674                                       int access_type)
 675{
 676    ppcemb_tlb_t *tlb;
 677    hwaddr raddr;
 678    int i, ret, zsel, zpr, pr;
 679
 680    ret = -1;
 681    raddr = (hwaddr)-1ULL;
 682    pr = msr_pr;
 683    for (i = 0; i < env->nb_tlb; i++) {
 684        tlb = &env->tlb.tlbe[i];
 685        if (ppcemb_tlb_check(env, tlb, &raddr, address,
 686                             env->spr[SPR_40x_PID], 0, i) < 0) {
 687            continue;
 688        }
 689        zsel = (tlb->attr >> 4) & 0xF;
 690        zpr = (env->spr[SPR_40x_ZPR] >> (30 - (2 * zsel))) & 0x3;
 691        LOG_SWTLB("%s: TLB %d zsel %d zpr %d rw %d attr %08x\n",
 692                    __func__, i, zsel, zpr, rw, tlb->attr);
 693        /* Check execute enable bit */
 694        switch (zpr) {
 695        case 0x2:
 696            if (pr != 0) {
 697                goto check_perms;
 698            }
 699            /* No break here */
 700        case 0x3:
 701            /* All accesses granted */
 702            ctx->prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
 703            ret = 0;
 704            break;
 705        case 0x0:
 706            if (pr != 0) {
 707                /* Raise Zone protection fault.  */
 708                env->spr[SPR_40x_ESR] = 1 << 22;
 709                ctx->prot = 0;
 710                ret = -2;
 711                break;
 712            }
 713            /* No break here */
 714        case 0x1:
 715        check_perms:
 716            /* Check from TLB entry */
 717            ctx->prot = tlb->prot;
 718            ret = check_prot(ctx->prot, rw, access_type);
 719            if (ret == -2) {
 720                env->spr[SPR_40x_ESR] = 0;
 721            }
 722            break;
 723        }
 724        if (ret >= 0) {
 725            ctx->raddr = raddr;
 726            LOG_SWTLB("%s: access granted " TARGET_FMT_lx " => " TARGET_FMT_plx
 727                      " %d %d\n", __func__, address, ctx->raddr, ctx->prot,
 728                      ret);
 729            return 0;
 730        }
 731    }
 732    LOG_SWTLB("%s: access refused " TARGET_FMT_lx " => " TARGET_FMT_plx
 733              " %d %d\n", __func__, address, raddr, ctx->prot, ret);
 734
 735    return ret;
 736}
 737
 738void store_40x_sler(CPUPPCState *env, uint32_t val)
 739{
 740    PowerPCCPU *cpu = ppc_env_get_cpu(env);
 741
 742    /* XXX: TO BE FIXED */
 743    if (val != 0x00000000) {
 744        cpu_abort(CPU(cpu), "Little-endian regions are not supported by now\n");
 745    }
 746    env->spr[SPR_405_SLER] = val;
 747}
 748
 749static inline int mmubooke_check_tlb(CPUPPCState *env, ppcemb_tlb_t *tlb,
 750                                     hwaddr *raddr, int *prot,
 751                                     target_ulong address, int rw,
 752                                     int access_type, int i)
 753{
 754    int ret, prot2;
 755
 756    if (ppcemb_tlb_check(env, tlb, raddr, address,
 757                         env->spr[SPR_BOOKE_PID],
 758                         !env->nb_pids, i) >= 0) {
 759        goto found_tlb;
 760    }
 761
 762    if (env->spr[SPR_BOOKE_PID1] &&
 763        ppcemb_tlb_check(env, tlb, raddr, address,
 764                         env->spr[SPR_BOOKE_PID1], 0, i) >= 0) {
 765        goto found_tlb;
 766    }
 767
 768    if (env->spr[SPR_BOOKE_PID2] &&
 769        ppcemb_tlb_check(env, tlb, raddr, address,
 770                         env->spr[SPR_BOOKE_PID2], 0, i) >= 0) {
 771        goto found_tlb;
 772    }
 773
 774    LOG_SWTLB("%s: TLB entry not found\n", __func__);
 775    return -1;
 776
 777found_tlb:
 778
 779    if (msr_pr != 0) {
 780        prot2 = tlb->prot & 0xF;
 781    } else {
 782        prot2 = (tlb->prot >> 4) & 0xF;
 783    }
 784
 785    /* Check the address space */
 786    if (access_type == ACCESS_CODE) {
 787        if (msr_ir != (tlb->attr & 1)) {
 788            LOG_SWTLB("%s: AS doesn't match\n", __func__);
 789            return -1;
 790        }
 791
 792        *prot = prot2;
 793        if (prot2 & PAGE_EXEC) {
 794            LOG_SWTLB("%s: good TLB!\n", __func__);
 795            return 0;
 796        }
 797
 798        LOG_SWTLB("%s: no PAGE_EXEC: %x\n", __func__, prot2);
 799        ret = -3;
 800    } else {
 801        if (msr_dr != (tlb->attr & 1)) {
 802            LOG_SWTLB("%s: AS doesn't match\n", __func__);
 803            return -1;
 804        }
 805
 806        *prot = prot2;
 807        if ((!rw && prot2 & PAGE_READ) || (rw && (prot2 & PAGE_WRITE))) {
 808            LOG_SWTLB("%s: found TLB!\n", __func__);
 809            return 0;
 810        }
 811
 812        LOG_SWTLB("%s: PAGE_READ/WRITE doesn't match: %x\n", __func__, prot2);
 813        ret = -2;
 814    }
 815
 816    return ret;
 817}
 818
 819static int mmubooke_get_physical_address(CPUPPCState *env, mmu_ctx_t *ctx,
 820                                         target_ulong address, int rw,
 821                                         int access_type)
 822{
 823    ppcemb_tlb_t *tlb;
 824    hwaddr raddr;
 825    int i, ret;
 826
 827    ret = -1;
 828    raddr = (hwaddr)-1ULL;
 829    for (i = 0; i < env->nb_tlb; i++) {
 830        tlb = &env->tlb.tlbe[i];
 831        ret = mmubooke_check_tlb(env, tlb, &raddr, &ctx->prot, address, rw,
 832                                 access_type, i);
 833        if (ret != -1) {
 834            break;
 835        }
 836    }
 837
 838    if (ret >= 0) {
 839        ctx->raddr = raddr;
 840        LOG_SWTLB("%s: access granted " TARGET_FMT_lx " => " TARGET_FMT_plx
 841                  " %d %d\n", __func__, address, ctx->raddr, ctx->prot,
 842                  ret);
 843    } else {
 844        LOG_SWTLB("%s: access refused " TARGET_FMT_lx " => " TARGET_FMT_plx
 845                  " %d %d\n", __func__, address, raddr, ctx->prot, ret);
 846    }
 847
 848    return ret;
 849}
 850
 851static void booke206_flush_tlb(CPUPPCState *env, int flags,
 852                               const int check_iprot)
 853{
 854    PowerPCCPU *cpu = ppc_env_get_cpu(env);
 855    int tlb_size;
 856    int i, j;
 857    ppcmas_tlb_t *tlb = env->tlb.tlbm;
 858
 859    for (i = 0; i < BOOKE206_MAX_TLBN; i++) {
 860        if (flags & (1 << i)) {
 861            tlb_size = booke206_tlb_size(env, i);
 862            for (j = 0; j < tlb_size; j++) {
 863                if (!check_iprot || !(tlb[j].mas1 & MAS1_IPROT)) {
 864                    tlb[j].mas1 &= ~MAS1_VALID;
 865                }
 866            }
 867        }
 868        tlb += booke206_tlb_size(env, i);
 869    }
 870
 871    tlb_flush(CPU(cpu));
 872}
 873
 874static hwaddr booke206_tlb_to_page_size(CPUPPCState *env,
 875                                        ppcmas_tlb_t *tlb)
 876{
 877    int tlbm_size;
 878
 879    tlbm_size = (tlb->mas1 & MAS1_TSIZE_MASK) >> MAS1_TSIZE_SHIFT;
 880
 881    return 1024ULL << tlbm_size;
 882}
 883
 884/* TLB check function for MAS based SoftTLBs */
 885static int ppcmas_tlb_check(CPUPPCState *env, ppcmas_tlb_t *tlb,
 886                            hwaddr *raddrp, target_ulong address,
 887                            uint32_t pid)
 888{
 889    hwaddr mask;
 890    uint32_t tlb_pid;
 891
 892    if (!msr_cm) {
 893        /* In 32bit mode we can only address 32bit EAs */
 894        address = (uint32_t)address;
 895    }
 896
 897    /* Check valid flag */
 898    if (!(tlb->mas1 & MAS1_VALID)) {
 899        return -1;
 900    }
 901
 902    mask = ~(booke206_tlb_to_page_size(env, tlb) - 1);
 903    LOG_SWTLB("%s: TLB ADDR=0x" TARGET_FMT_lx " PID=0x%x MAS1=0x%x MAS2=0x%"
 904              PRIx64 " mask=0x%" HWADDR_PRIx " MAS7_3=0x%" PRIx64 " MAS8=0x%"
 905              PRIx32 "\n", __func__, address, pid, tlb->mas1, tlb->mas2, mask,
 906              tlb->mas7_3, tlb->mas8);
 907
 908    /* Check PID */
 909    tlb_pid = (tlb->mas1 & MAS1_TID_MASK) >> MAS1_TID_SHIFT;
 910    if (tlb_pid != 0 && tlb_pid != pid) {
 911        return -1;
 912    }
 913
 914    /* Check effective address */
 915    if ((address & mask) != (tlb->mas2 & MAS2_EPN_MASK)) {
 916        return -1;
 917    }
 918
 919    if (raddrp) {
 920        *raddrp = (tlb->mas7_3 & mask) | (address & ~mask);
 921    }
 922
 923    return 0;
 924}
 925
 926static int mmubooke206_check_tlb(CPUPPCState *env, ppcmas_tlb_t *tlb,
 927                                 hwaddr *raddr, int *prot,
 928                                 target_ulong address, int rw,
 929                                 int access_type)
 930{
 931    int ret;
 932    int prot2 = 0;
 933
 934    if (ppcmas_tlb_check(env, tlb, raddr, address,
 935                         env->spr[SPR_BOOKE_PID]) >= 0) {
 936        goto found_tlb;
 937    }
 938
 939    if (env->spr[SPR_BOOKE_PID1] &&
 940        ppcmas_tlb_check(env, tlb, raddr, address,
 941                         env->spr[SPR_BOOKE_PID1]) >= 0) {
 942        goto found_tlb;
 943    }
 944
 945    if (env->spr[SPR_BOOKE_PID2] &&
 946        ppcmas_tlb_check(env, tlb, raddr, address,
 947                         env->spr[SPR_BOOKE_PID2]) >= 0) {
 948        goto found_tlb;
 949    }
 950
 951    LOG_SWTLB("%s: TLB entry not found\n", __func__);
 952    return -1;
 953
 954found_tlb:
 955
 956    if (msr_pr != 0) {
 957        if (tlb->mas7_3 & MAS3_UR) {
 958            prot2 |= PAGE_READ;
 959        }
 960        if (tlb->mas7_3 & MAS3_UW) {
 961            prot2 |= PAGE_WRITE;
 962        }
 963        if (tlb->mas7_3 & MAS3_UX) {
 964            prot2 |= PAGE_EXEC;
 965        }
 966    } else {
 967        if (tlb->mas7_3 & MAS3_SR) {
 968            prot2 |= PAGE_READ;
 969        }
 970        if (tlb->mas7_3 & MAS3_SW) {
 971            prot2 |= PAGE_WRITE;
 972        }
 973        if (tlb->mas7_3 & MAS3_SX) {
 974            prot2 |= PAGE_EXEC;
 975        }
 976    }
 977
 978    /* Check the address space and permissions */
 979    if (access_type == ACCESS_CODE) {
 980        if (msr_ir != ((tlb->mas1 & MAS1_TS) >> MAS1_TS_SHIFT)) {
 981            LOG_SWTLB("%s: AS doesn't match\n", __func__);
 982            return -1;
 983        }
 984
 985        *prot = prot2;
 986        if (prot2 & PAGE_EXEC) {
 987            LOG_SWTLB("%s: good TLB!\n", __func__);
 988            return 0;
 989        }
 990
 991        LOG_SWTLB("%s: no PAGE_EXEC: %x\n", __func__, prot2);
 992        ret = -3;
 993    } else {
 994        if (msr_dr != ((tlb->mas1 & MAS1_TS) >> MAS1_TS_SHIFT)) {
 995            LOG_SWTLB("%s: AS doesn't match\n", __func__);
 996            return -1;
 997        }
 998
 999        *prot = prot2;
1000        if ((!rw && prot2 & PAGE_READ) || (rw && (prot2 & PAGE_WRITE))) {
1001            LOG_SWTLB("%s: found TLB!\n", __func__);
1002            return 0;
1003        }
1004
1005        LOG_SWTLB("%s: PAGE_READ/WRITE doesn't match: %x\n", __func__, prot2);
1006        ret = -2;
1007    }
1008
1009    return ret;
1010}
1011
1012static int mmubooke206_get_physical_address(CPUPPCState *env, mmu_ctx_t *ctx,
1013                                            target_ulong address, int rw,
1014                                            int access_type)
1015{
1016    ppcmas_tlb_t *tlb;
1017    hwaddr raddr;
1018    int i, j, ret;
1019
1020    ret = -1;
1021    raddr = (hwaddr)-1ULL;
1022
1023    for (i = 0; i < BOOKE206_MAX_TLBN; i++) {
1024        int ways = booke206_tlb_ways(env, i);
1025
1026        for (j = 0; j < ways; j++) {
1027            tlb = booke206_get_tlbm(env, i, address, j);
1028            if (!tlb) {
1029                continue;
1030            }
1031            ret = mmubooke206_check_tlb(env, tlb, &raddr, &ctx->prot, address,
1032                                        rw, access_type);
1033            if (ret != -1) {
1034                goto found_tlb;
1035            }
1036        }
1037    }
1038
1039found_tlb:
1040
1041    if (ret >= 0) {
1042        ctx->raddr = raddr;
1043        LOG_SWTLB("%s: access granted " TARGET_FMT_lx " => " TARGET_FMT_plx
1044                  " %d %d\n", __func__, address, ctx->raddr, ctx->prot,
1045                  ret);
1046    } else {
1047        LOG_SWTLB("%s: access refused " TARGET_FMT_lx " => " TARGET_FMT_plx
1048                  " %d %d\n", __func__, address, raddr, ctx->prot, ret);
1049    }
1050
1051    return ret;
1052}
1053
1054static const char *book3e_tsize_to_str[32] = {
1055    "1K", "2K", "4K", "8K", "16K", "32K", "64K", "128K", "256K", "512K",
1056    "1M", "2M", "4M", "8M", "16M", "32M", "64M", "128M", "256M", "512M",
1057    "1G", "2G", "4G", "8G", "16G", "32G", "64G", "128G", "256G", "512G",
1058    "1T", "2T"
1059};
1060
1061static void mmubooke_dump_mmu(FILE *f, fprintf_function cpu_fprintf,
1062                                 CPUPPCState *env)
1063{
1064    ppcemb_tlb_t *entry;
1065    int i;
1066
1067    if (kvm_enabled() && !env->kvm_sw_tlb) {
1068        cpu_fprintf(f, "Cannot access KVM TLB\n");
1069        return;
1070    }
1071
1072    cpu_fprintf(f, "\nTLB:\n");
1073    cpu_fprintf(f, "Effective          Physical           Size PID   Prot     "
1074                "Attr\n");
1075
1076    entry = &env->tlb.tlbe[0];
1077    for (i = 0; i < env->nb_tlb; i++, entry++) {
1078        hwaddr ea, pa;
1079        target_ulong mask;
1080        uint64_t size = (uint64_t)entry->size;
1081        char size_buf[20];
1082
1083        /* Check valid flag */
1084        if (!(entry->prot & PAGE_VALID)) {
1085            continue;
1086        }
1087
1088        mask = ~(entry->size - 1);
1089        ea = entry->EPN & mask;
1090        pa = entry->RPN & mask;
1091        /* Extend the physical address to 36 bits */
1092        pa |= (hwaddr)(entry->RPN & 0xF) << 32;
1093        size /= 1024;
1094        if (size >= 1024) {
1095            snprintf(size_buf, sizeof(size_buf), "%3" PRId64 "M", size / 1024);
1096        } else {
1097            snprintf(size_buf, sizeof(size_buf), "%3" PRId64 "k", size);
1098        }
1099        cpu_fprintf(f, "0x%016" PRIx64 " 0x%016" PRIx64 " %s %-5u %08x %08x\n",
1100                    (uint64_t)ea, (uint64_t)pa, size_buf, (uint32_t)entry->PID,
1101                    entry->prot, entry->attr);
1102    }
1103
1104}
1105
1106static void mmubooke206_dump_one_tlb(FILE *f, fprintf_function cpu_fprintf,
1107                                     CPUPPCState *env, int tlbn, int offset,
1108                                     int tlbsize)
1109{
1110    ppcmas_tlb_t *entry;
1111    int i;
1112
1113    cpu_fprintf(f, "\nTLB%d:\n", tlbn);
1114    cpu_fprintf(f, "Effective          Physical           Size TID   TS SRWX"
1115                " URWX WIMGE U0123\n");
1116
1117    entry = &env->tlb.tlbm[offset];
1118    for (i = 0; i < tlbsize; i++, entry++) {
1119        hwaddr ea, pa, size;
1120        int tsize;
1121
1122        if (!(entry->mas1 & MAS1_VALID)) {
1123            continue;
1124        }
1125
1126        tsize = (entry->mas1 & MAS1_TSIZE_MASK) >> MAS1_TSIZE_SHIFT;
1127        size = 1024ULL << tsize;
1128        ea = entry->mas2 & ~(size - 1);
1129        pa = entry->mas7_3 & ~(size - 1);
1130
1131        cpu_fprintf(f, "0x%016" PRIx64 " 0x%016" PRIx64 " %4s %-5u %1u  S%c%c%c"
1132                    "U%c%c%c %c%c%c%c%c U%c%c%c%c\n",
1133                    (uint64_t)ea, (uint64_t)pa,
1134                    book3e_tsize_to_str[tsize],
1135                    (entry->mas1 & MAS1_TID_MASK) >> MAS1_TID_SHIFT,
1136                    (entry->mas1 & MAS1_TS) >> MAS1_TS_SHIFT,
1137                    entry->mas7_3 & MAS3_SR ? 'R' : '-',
1138                    entry->mas7_3 & MAS3_SW ? 'W' : '-',
1139                    entry->mas7_3 & MAS3_SX ? 'X' : '-',
1140                    entry->mas7_3 & MAS3_UR ? 'R' : '-',
1141                    entry->mas7_3 & MAS3_UW ? 'W' : '-',
1142                    entry->mas7_3 & MAS3_UX ? 'X' : '-',
1143                    entry->mas2 & MAS2_W ? 'W' : '-',
1144                    entry->mas2 & MAS2_I ? 'I' : '-',
1145                    entry->mas2 & MAS2_M ? 'M' : '-',
1146                    entry->mas2 & MAS2_G ? 'G' : '-',
1147                    entry->mas2 & MAS2_E ? 'E' : '-',
1148                    entry->mas7_3 & MAS3_U0 ? '0' : '-',
1149                    entry->mas7_3 & MAS3_U1 ? '1' : '-',
1150                    entry->mas7_3 & MAS3_U2 ? '2' : '-',
1151                    entry->mas7_3 & MAS3_U3 ? '3' : '-');
1152    }
1153}
1154
1155static void mmubooke206_dump_mmu(FILE *f, fprintf_function cpu_fprintf,
1156                                 CPUPPCState *env)
1157{
1158    int offset = 0;
1159    int i;
1160
1161    if (kvm_enabled() && !env->kvm_sw_tlb) {
1162        cpu_fprintf(f, "Cannot access KVM TLB\n");
1163        return;
1164    }
1165
1166    for (i = 0; i < BOOKE206_MAX_TLBN; i++) {
1167        int size = booke206_tlb_size(env, i);
1168
1169        if (size == 0) {
1170            continue;
1171        }
1172
1173        mmubooke206_dump_one_tlb(f, cpu_fprintf, env, i, offset, size);
1174        offset += size;
1175    }
1176}
1177
1178static void mmu6xx_dump_BATs(FILE *f, fprintf_function cpu_fprintf,
1179                             CPUPPCState *env, int type)
1180{
1181    target_ulong *BATlt, *BATut, *BATu, *BATl;
1182    target_ulong BEPIl, BEPIu, bl;
1183    int i;
1184
1185    switch (type) {
1186    case ACCESS_CODE:
1187        BATlt = env->IBAT[1];
1188        BATut = env->IBAT[0];
1189        break;
1190    default:
1191        BATlt = env->DBAT[1];
1192        BATut = env->DBAT[0];
1193        break;
1194    }
1195
1196    for (i = 0; i < env->nb_BATs; i++) {
1197        BATu = &BATut[i];
1198        BATl = &BATlt[i];
1199        BEPIu = *BATu & 0xF0000000;
1200        BEPIl = *BATu & 0x0FFE0000;
1201        bl = (*BATu & 0x00001FFC) << 15;
1202        cpu_fprintf(f, "%s BAT%d BATu " TARGET_FMT_lx
1203                    " BATl " TARGET_FMT_lx "\n\t" TARGET_FMT_lx " "
1204                    TARGET_FMT_lx " " TARGET_FMT_lx "\n",
1205                    type == ACCESS_CODE ? "code" : "data", i,
1206                    *BATu, *BATl, BEPIu, BEPIl, bl);
1207    }
1208}
1209
1210static void mmu6xx_dump_mmu(FILE *f, fprintf_function cpu_fprintf,
1211                            CPUPPCState *env)
1212{
1213    PowerPCCPU *cpu = ppc_env_get_cpu(env);
1214    ppc6xx_tlb_t *tlb;
1215    target_ulong sr;
1216    int type, way, entry, i;
1217
1218    cpu_fprintf(f, "HTAB base = 0x%"HWADDR_PRIx"\n", ppc_hash32_hpt_base(cpu));
1219    cpu_fprintf(f, "HTAB mask = 0x%"HWADDR_PRIx"\n", ppc_hash32_hpt_mask(cpu));
1220
1221    cpu_fprintf(f, "\nSegment registers:\n");
1222    for (i = 0; i < 32; i++) {
1223        sr = env->sr[i];
1224        if (sr & 0x80000000) {
1225            cpu_fprintf(f, "%02d T=%d Ks=%d Kp=%d BUID=0x%03x "
1226                        "CNTLR_SPEC=0x%05x\n", i,
1227                        sr & 0x80000000 ? 1 : 0, sr & 0x40000000 ? 1 : 0,
1228                        sr & 0x20000000 ? 1 : 0, (uint32_t)((sr >> 20) & 0x1FF),
1229                        (uint32_t)(sr & 0xFFFFF));
1230        } else {
1231            cpu_fprintf(f, "%02d T=%d Ks=%d Kp=%d N=%d VSID=0x%06x\n", i,
1232                        sr & 0x80000000 ? 1 : 0, sr & 0x40000000 ? 1 : 0,
1233                        sr & 0x20000000 ? 1 : 0, sr & 0x10000000 ? 1 : 0,
1234                        (uint32_t)(sr & 0x00FFFFFF));
1235        }
1236    }
1237
1238    cpu_fprintf(f, "\nBATs:\n");
1239    mmu6xx_dump_BATs(f, cpu_fprintf, env, ACCESS_INT);
1240    mmu6xx_dump_BATs(f, cpu_fprintf, env, ACCESS_CODE);
1241
1242    if (env->id_tlbs != 1) {
1243        cpu_fprintf(f, "ERROR: 6xx MMU should have separated TLB"
1244                    " for code and data\n");
1245    }
1246
1247    cpu_fprintf(f, "\nTLBs                       [EPN    EPN + SIZE]\n");
1248
1249    for (type = 0; type < 2; type++) {
1250        for (way = 0; way < env->nb_ways; way++) {
1251            for (entry = env->nb_tlb * type + env->tlb_per_way * way;
1252                 entry < (env->nb_tlb * type + env->tlb_per_way * (way + 1));
1253                 entry++) {
1254
1255                tlb = &env->tlb.tlb6[entry];
1256                cpu_fprintf(f, "%s TLB %02d/%02d way:%d %s ["
1257                            TARGET_FMT_lx " " TARGET_FMT_lx "]\n",
1258                            type ? "code" : "data", entry % env->nb_tlb,
1259                            env->nb_tlb, way,
1260                            pte_is_valid(tlb->pte0) ? "valid" : "inval",
1261                            tlb->EPN, tlb->EPN + TARGET_PAGE_SIZE);
1262            }
1263        }
1264    }
1265}
1266
1267void dump_mmu(FILE *f, fprintf_function cpu_fprintf, CPUPPCState *env)
1268{
1269    switch (POWERPC_MMU_VER(env->mmu_model)) {
1270    case POWERPC_MMU_BOOKE:
1271        mmubooke_dump_mmu(f, cpu_fprintf, env);
1272        break;
1273    case POWERPC_MMU_BOOKE206:
1274        mmubooke206_dump_mmu(f, cpu_fprintf, env);
1275        break;
1276    case POWERPC_MMU_SOFT_6xx:
1277    case POWERPC_MMU_SOFT_74xx:
1278        mmu6xx_dump_mmu(f, cpu_fprintf, env);
1279        break;
1280#if defined(TARGET_PPC64)
1281    case POWERPC_MMU_VER_64B:
1282    case POWERPC_MMU_VER_2_03:
1283    case POWERPC_MMU_VER_2_06:
1284    case POWERPC_MMU_VER_2_07:
1285        dump_slb(f, cpu_fprintf, ppc_env_get_cpu(env));
1286        break;
1287    case POWERPC_MMU_VER_3_00:
1288        if (ppc64_radix_guest(ppc_env_get_cpu(env))) {
1289            /* TODO - Unsupported */
1290        } else {
1291            dump_slb(f, cpu_fprintf, ppc_env_get_cpu(env));
1292            break;
1293        }
1294#endif
1295    default:
1296        qemu_log_mask(LOG_UNIMP, "%s: unimplemented\n", __func__);
1297    }
1298}
1299
1300static inline int check_physical(CPUPPCState *env, mmu_ctx_t *ctx,
1301                                 target_ulong eaddr, int rw)
1302{
1303    int in_plb, ret;
1304
1305    ctx->raddr = eaddr;
1306    ctx->prot = PAGE_READ | PAGE_EXEC;
1307    ret = 0;
1308    switch (env->mmu_model) {
1309    case POWERPC_MMU_SOFT_6xx:
1310    case POWERPC_MMU_SOFT_74xx:
1311    case POWERPC_MMU_SOFT_4xx:
1312    case POWERPC_MMU_REAL:
1313    case POWERPC_MMU_BOOKE:
1314        ctx->prot |= PAGE_WRITE;
1315        break;
1316
1317    case POWERPC_MMU_SOFT_4xx_Z:
1318        if (unlikely(msr_pe != 0)) {
1319            /* 403 family add some particular protections,
1320             * using PBL/PBU registers for accesses with no translation.
1321             */
1322            in_plb =
1323                /* Check PLB validity */
1324                (env->pb[0] < env->pb[1] &&
1325                 /* and address in plb area */
1326                 eaddr >= env->pb[0] && eaddr < env->pb[1]) ||
1327                (env->pb[2] < env->pb[3] &&
1328                 eaddr >= env->pb[2] && eaddr < env->pb[3]) ? 1 : 0;
1329            if (in_plb ^ msr_px) {
1330                /* Access in protected area */
1331                if (rw == 1) {
1332                    /* Access is not allowed */
1333                    ret = -2;
1334                }
1335            } else {
1336                /* Read-write access is allowed */
1337                ctx->prot |= PAGE_WRITE;
1338            }
1339        }
1340        break;
1341
1342    default:
1343        /* Caller's checks mean we should never get here for other models */
1344        abort();
1345        return -1;
1346    }
1347
1348    return ret;
1349}
1350
1351static int get_physical_address(CPUPPCState *env, mmu_ctx_t *ctx,
1352                                target_ulong eaddr, int rw, int access_type)
1353{
1354    PowerPCCPU *cpu = ppc_env_get_cpu(env);
1355    int ret = -1;
1356    bool real_mode = (access_type == ACCESS_CODE && msr_ir == 0)
1357        || (access_type != ACCESS_CODE && msr_dr == 0);
1358
1359#if 0
1360    qemu_log("%s\n", __func__);
1361#endif
1362
1363    switch (env->mmu_model) {
1364    case POWERPC_MMU_SOFT_6xx:
1365    case POWERPC_MMU_SOFT_74xx:
1366        if (real_mode) {
1367            ret = check_physical(env, ctx, eaddr, rw);
1368        } else {
1369            /* Try to find a BAT */
1370            if (env->nb_BATs != 0) {
1371                ret = get_bat_6xx_tlb(env, ctx, eaddr, rw, access_type);
1372            }
1373            if (ret < 0) {
1374                /* We didn't match any BAT entry or don't have BATs */
1375                ret = get_segment_6xx_tlb(env, ctx, eaddr, rw, access_type);
1376            }
1377        }
1378        break;
1379
1380    case POWERPC_MMU_SOFT_4xx:
1381    case POWERPC_MMU_SOFT_4xx_Z:
1382        if (real_mode) {
1383            ret = check_physical(env, ctx, eaddr, rw);
1384        } else {
1385            ret = mmu40x_get_physical_address(env, ctx, eaddr,
1386                                              rw, access_type);
1387        }
1388        break;
1389    case POWERPC_MMU_BOOKE:
1390        ret = mmubooke_get_physical_address(env, ctx, eaddr,
1391                                            rw, access_type);
1392        break;
1393    case POWERPC_MMU_BOOKE206:
1394        ret = mmubooke206_get_physical_address(env, ctx, eaddr, rw,
1395                                               access_type);
1396        break;
1397    case POWERPC_MMU_MPC8xx:
1398        /* XXX: TODO */
1399        cpu_abort(CPU(cpu), "MPC8xx MMU model is not implemented\n");
1400        break;
1401    case POWERPC_MMU_REAL:
1402        if (real_mode) {
1403            ret = check_physical(env, ctx, eaddr, rw);
1404        } else {
1405            cpu_abort(CPU(cpu), "PowerPC in real mode do not do any translation\n");
1406        }
1407        return -1;
1408    default:
1409        cpu_abort(CPU(cpu), "Unknown or invalid MMU model\n");
1410        return -1;
1411    }
1412#if 0
1413    qemu_log("%s address " TARGET_FMT_lx " => %d " TARGET_FMT_plx "\n",
1414             __func__, eaddr, ret, ctx->raddr);
1415#endif
1416
1417    return ret;
1418}
1419
1420hwaddr ppc_cpu_get_phys_page_debug(CPUState *cs, vaddr addr)
1421{
1422    PowerPCCPU *cpu = POWERPC_CPU(cs);
1423    CPUPPCState *env = &cpu->env;
1424    mmu_ctx_t ctx;
1425
1426    switch (POWERPC_MMU_VER(env->mmu_model)) {
1427#if defined(TARGET_PPC64)
1428    case POWERPC_MMU_VER_64B:
1429    case POWERPC_MMU_VER_2_03:
1430    case POWERPC_MMU_VER_2_06:
1431    case POWERPC_MMU_VER_2_07:
1432        return ppc_hash64_get_phys_page_debug(cpu, addr);
1433    case POWERPC_MMU_VER_3_00:
1434        if (ppc64_radix_guest(ppc_env_get_cpu(env))) {
1435            return ppc_radix64_get_phys_page_debug(cpu, addr);
1436        } else {
1437            return ppc_hash64_get_phys_page_debug(cpu, addr);
1438        }
1439        break;
1440#endif
1441
1442    case POWERPC_MMU_32B:
1443    case POWERPC_MMU_601:
1444        return ppc_hash32_get_phys_page_debug(cpu, addr);
1445
1446    default:
1447        ;
1448    }
1449
1450    if (unlikely(get_physical_address(env, &ctx, addr, 0, ACCESS_INT) != 0)) {
1451
1452        /* Some MMUs have separate TLBs for code and data. If we only try an
1453         * ACCESS_INT, we may not be able to read instructions mapped by code
1454         * TLBs, so we also try a ACCESS_CODE.
1455         */
1456        if (unlikely(get_physical_address(env, &ctx, addr, 0,
1457                                          ACCESS_CODE) != 0)) {
1458            return -1;
1459        }
1460    }
1461
1462    return ctx.raddr & TARGET_PAGE_MASK;
1463}
1464
1465static void booke206_update_mas_tlb_miss(CPUPPCState *env, target_ulong address,
1466                                     int rw)
1467{
1468    env->spr[SPR_BOOKE_MAS0] = env->spr[SPR_BOOKE_MAS4] & MAS4_TLBSELD_MASK;
1469    env->spr[SPR_BOOKE_MAS1] = env->spr[SPR_BOOKE_MAS4] & MAS4_TSIZED_MASK;
1470    env->spr[SPR_BOOKE_MAS2] = env->spr[SPR_BOOKE_MAS4] & MAS4_WIMGED_MASK;
1471    env->spr[SPR_BOOKE_MAS3] = 0;
1472    env->spr[SPR_BOOKE_MAS6] = 0;
1473    env->spr[SPR_BOOKE_MAS7] = 0;
1474
1475    /* AS */
1476    if (((rw == 2) && msr_ir) || ((rw != 2) && msr_dr)) {
1477        env->spr[SPR_BOOKE_MAS1] |= MAS1_TS;
1478        env->spr[SPR_BOOKE_MAS6] |= MAS6_SAS;
1479    }
1480
1481    env->spr[SPR_BOOKE_MAS1] |= MAS1_VALID;
1482    env->spr[SPR_BOOKE_MAS2] |= address & MAS2_EPN_MASK;
1483
1484    switch (env->spr[SPR_BOOKE_MAS4] & MAS4_TIDSELD_PIDZ) {
1485    case MAS4_TIDSELD_PID0:
1486        env->spr[SPR_BOOKE_MAS1] |= env->spr[SPR_BOOKE_PID] << MAS1_TID_SHIFT;
1487        break;
1488    case MAS4_TIDSELD_PID1:
1489        env->spr[SPR_BOOKE_MAS1] |= env->spr[SPR_BOOKE_PID1] << MAS1_TID_SHIFT;
1490        break;
1491    case MAS4_TIDSELD_PID2:
1492        env->spr[SPR_BOOKE_MAS1] |= env->spr[SPR_BOOKE_PID2] << MAS1_TID_SHIFT;
1493        break;
1494    }
1495
1496    env->spr[SPR_BOOKE_MAS6] |= env->spr[SPR_BOOKE_PID] << 16;
1497
1498    /* next victim logic */
1499    env->spr[SPR_BOOKE_MAS0] |= env->last_way << MAS0_ESEL_SHIFT;
1500    env->last_way++;
1501    env->last_way &= booke206_tlb_ways(env, 0) - 1;
1502    env->spr[SPR_BOOKE_MAS0] |= env->last_way << MAS0_NV_SHIFT;
1503}
1504
1505/* Perform address translation */
1506static int cpu_ppc_handle_mmu_fault(CPUPPCState *env, target_ulong address,
1507                                    int rw, int mmu_idx)
1508{
1509    CPUState *cs = CPU(ppc_env_get_cpu(env));
1510    PowerPCCPU *cpu = POWERPC_CPU(cs);
1511    mmu_ctx_t ctx;
1512    int access_type;
1513    int ret = 0;
1514
1515    if (rw == 2) {
1516        /* code access */
1517        rw = 0;
1518        access_type = ACCESS_CODE;
1519    } else {
1520        /* data access */
1521        access_type = env->access_type;
1522    }
1523    ret = get_physical_address(env, &ctx, address, rw, access_type);
1524    if (ret == 0) {
1525        tlb_set_page(cs, address & TARGET_PAGE_MASK,
1526                     ctx.raddr & TARGET_PAGE_MASK, ctx.prot,
1527                     mmu_idx, TARGET_PAGE_SIZE);
1528        ret = 0;
1529    } else if (ret < 0) {
1530        LOG_MMU_STATE(cs);
1531        if (access_type == ACCESS_CODE) {
1532            switch (ret) {
1533            case -1:
1534                /* No matches in page tables or TLB */
1535                switch (env->mmu_model) {
1536                case POWERPC_MMU_SOFT_6xx:
1537                    cs->exception_index = POWERPC_EXCP_IFTLB;
1538                    env->error_code = 1 << 18;
1539                    env->spr[SPR_IMISS] = address;
1540                    env->spr[SPR_ICMP] = 0x80000000 | ctx.ptem;
1541                    goto tlb_miss;
1542                case POWERPC_MMU_SOFT_74xx:
1543                    cs->exception_index = POWERPC_EXCP_IFTLB;
1544                    goto tlb_miss_74xx;
1545                case POWERPC_MMU_SOFT_4xx:
1546                case POWERPC_MMU_SOFT_4xx_Z:
1547                    cs->exception_index = POWERPC_EXCP_ITLB;
1548                    env->error_code = 0;
1549                    env->spr[SPR_40x_DEAR] = address;
1550                    env->spr[SPR_40x_ESR] = 0x00000000;
1551                    break;
1552                case POWERPC_MMU_BOOKE206:
1553                    booke206_update_mas_tlb_miss(env, address, 2);
1554                    /* fall through */
1555                case POWERPC_MMU_BOOKE:
1556                    cs->exception_index = POWERPC_EXCP_ITLB;
1557                    env->error_code = 0;
1558                    env->spr[SPR_BOOKE_DEAR] = address;
1559                    return -1;
1560                case POWERPC_MMU_MPC8xx:
1561                    /* XXX: TODO */
1562                    cpu_abort(cs, "MPC8xx MMU model is not implemented\n");
1563                    break;
1564                case POWERPC_MMU_REAL:
1565                    cpu_abort(cs, "PowerPC in real mode should never raise "
1566                              "any MMU exceptions\n");
1567                    return -1;
1568                default:
1569                    cpu_abort(cs, "Unknown or invalid MMU model\n");
1570                    return -1;
1571                }
1572                break;
1573            case -2:
1574                /* Access rights violation */
1575                cs->exception_index = POWERPC_EXCP_ISI;
1576                env->error_code = 0x08000000;
1577                break;
1578            case -3:
1579                /* No execute protection violation */
1580                if ((env->mmu_model == POWERPC_MMU_BOOKE) ||
1581                    (env->mmu_model == POWERPC_MMU_BOOKE206)) {
1582                    env->spr[SPR_BOOKE_ESR] = 0x00000000;
1583                }
1584                cs->exception_index = POWERPC_EXCP_ISI;
1585                env->error_code = 0x10000000;
1586                break;
1587            case -4:
1588                /* Direct store exception */
1589                /* No code fetch is allowed in direct-store areas */
1590                cs->exception_index = POWERPC_EXCP_ISI;
1591                env->error_code = 0x10000000;
1592                break;
1593            }
1594        } else {
1595            switch (ret) {
1596            case -1:
1597                /* No matches in page tables or TLB */
1598                switch (env->mmu_model) {
1599                case POWERPC_MMU_SOFT_6xx:
1600                    if (rw == 1) {
1601                        cs->exception_index = POWERPC_EXCP_DSTLB;
1602                        env->error_code = 1 << 16;
1603                    } else {
1604                        cs->exception_index = POWERPC_EXCP_DLTLB;
1605                        env->error_code = 0;
1606                    }
1607                    env->spr[SPR_DMISS] = address;
1608                    env->spr[SPR_DCMP] = 0x80000000 | ctx.ptem;
1609                tlb_miss:
1610                    env->error_code |= ctx.key << 19;
1611                    env->spr[SPR_HASH1] = ppc_hash32_hpt_base(cpu) +
1612                        get_pteg_offset32(cpu, ctx.hash[0]);
1613                    env->spr[SPR_HASH2] = ppc_hash32_hpt_base(cpu) +
1614                        get_pteg_offset32(cpu, ctx.hash[1]);
1615                    break;
1616                case POWERPC_MMU_SOFT_74xx:
1617                    if (rw == 1) {
1618                        cs->exception_index = POWERPC_EXCP_DSTLB;
1619                    } else {
1620                        cs->exception_index = POWERPC_EXCP_DLTLB;
1621                    }
1622                tlb_miss_74xx:
1623                    /* Implement LRU algorithm */
1624                    env->error_code = ctx.key << 19;
1625                    env->spr[SPR_TLBMISS] = (address & ~((target_ulong)0x3)) |
1626                        ((env->last_way + 1) & (env->nb_ways - 1));
1627                    env->spr[SPR_PTEHI] = 0x80000000 | ctx.ptem;
1628                    break;
1629                case POWERPC_MMU_SOFT_4xx:
1630                case POWERPC_MMU_SOFT_4xx_Z:
1631                    cs->exception_index = POWERPC_EXCP_DTLB;
1632                    env->error_code = 0;
1633                    env->spr[SPR_40x_DEAR] = address;
1634                    if (rw) {
1635                        env->spr[SPR_40x_ESR] = 0x00800000;
1636                    } else {
1637                        env->spr[SPR_40x_ESR] = 0x00000000;
1638                    }
1639                    break;
1640                case POWERPC_MMU_MPC8xx:
1641                    /* XXX: TODO */
1642                    cpu_abort(cs, "MPC8xx MMU model is not implemented\n");
1643                    break;
1644                case POWERPC_MMU_BOOKE206:
1645                    booke206_update_mas_tlb_miss(env, address, rw);
1646                    /* fall through */
1647                case POWERPC_MMU_BOOKE:
1648                    cs->exception_index = POWERPC_EXCP_DTLB;
1649                    env->error_code = 0;
1650                    env->spr[SPR_BOOKE_DEAR] = address;
1651                    env->spr[SPR_BOOKE_ESR] = rw ? ESR_ST : 0;
1652                    return -1;
1653                case POWERPC_MMU_REAL:
1654                    cpu_abort(cs, "PowerPC in real mode should never raise "
1655                              "any MMU exceptions\n");
1656                    return -1;
1657                default:
1658                    cpu_abort(cs, "Unknown or invalid MMU model\n");
1659                    return -1;
1660                }
1661                break;
1662            case -2:
1663                /* Access rights violation */
1664                cs->exception_index = POWERPC_EXCP_DSI;
1665                env->error_code = 0;
1666                if (env->mmu_model == POWERPC_MMU_SOFT_4xx
1667                    || env->mmu_model == POWERPC_MMU_SOFT_4xx_Z) {
1668                    env->spr[SPR_40x_DEAR] = address;
1669                    if (rw) {
1670                        env->spr[SPR_40x_ESR] |= 0x00800000;
1671                    }
1672                } else if ((env->mmu_model == POWERPC_MMU_BOOKE) ||
1673                           (env->mmu_model == POWERPC_MMU_BOOKE206)) {
1674                    env->spr[SPR_BOOKE_DEAR] = address;
1675                    env->spr[SPR_BOOKE_ESR] = rw ? ESR_ST : 0;
1676                } else {
1677                    env->spr[SPR_DAR] = address;
1678                    if (rw == 1) {
1679                        env->spr[SPR_DSISR] = 0x0A000000;
1680                    } else {
1681                        env->spr[SPR_DSISR] = 0x08000000;
1682                    }
1683                }
1684                break;
1685            case -4:
1686                /* Direct store exception */
1687                switch (access_type) {
1688                case ACCESS_FLOAT:
1689                    /* Floating point load/store */
1690                    cs->exception_index = POWERPC_EXCP_ALIGN;
1691                    env->error_code = POWERPC_EXCP_ALIGN_FP;
1692                    env->spr[SPR_DAR] = address;
1693                    break;
1694                case ACCESS_RES:
1695                    /* lwarx, ldarx or stwcx. */
1696                    cs->exception_index = POWERPC_EXCP_DSI;
1697                    env->error_code = 0;
1698                    env->spr[SPR_DAR] = address;
1699                    if (rw == 1) {
1700                        env->spr[SPR_DSISR] = 0x06000000;
1701                    } else {
1702                        env->spr[SPR_DSISR] = 0x04000000;
1703                    }
1704                    break;
1705                case ACCESS_EXT:
1706                    /* eciwx or ecowx */
1707                    cs->exception_index = POWERPC_EXCP_DSI;
1708                    env->error_code = 0;
1709                    env->spr[SPR_DAR] = address;
1710                    if (rw == 1) {
1711                        env->spr[SPR_DSISR] = 0x06100000;
1712                    } else {
1713                        env->spr[SPR_DSISR] = 0x04100000;
1714                    }
1715                    break;
1716                default:
1717                    printf("DSI: invalid exception (%d)\n", ret);
1718                    cs->exception_index = POWERPC_EXCP_PROGRAM;
1719                    env->error_code =
1720                        POWERPC_EXCP_INVAL | POWERPC_EXCP_INVAL_INVAL;
1721                    env->spr[SPR_DAR] = address;
1722                    break;
1723                }
1724                break;
1725            }
1726        }
1727#if 0
1728        printf("%s: set exception to %d %02x\n", __func__,
1729               cs->exception, env->error_code);
1730#endif
1731        ret = 1;
1732    }
1733
1734    return ret;
1735}
1736
1737/*****************************************************************************/
1738/* BATs management */
1739#if !defined(FLUSH_ALL_TLBS)
1740static inline void do_invalidate_BAT(CPUPPCState *env, target_ulong BATu,
1741                                     target_ulong mask)
1742{
1743    CPUState *cs = CPU(ppc_env_get_cpu(env));
1744    target_ulong base, end, page;
1745
1746    base = BATu & ~0x0001FFFF;
1747    end = base + mask + 0x00020000;
1748    LOG_BATS("Flush BAT from " TARGET_FMT_lx " to " TARGET_FMT_lx " ("
1749             TARGET_FMT_lx ")\n", base, end, mask);
1750    for (page = base; page != end; page += TARGET_PAGE_SIZE) {
1751        tlb_flush_page(cs, page);
1752    }
1753    LOG_BATS("Flush done\n");
1754}
1755#endif
1756
1757static inline void dump_store_bat(CPUPPCState *env, char ID, int ul, int nr,
1758                                  target_ulong value)
1759{
1760    LOG_BATS("Set %cBAT%d%c to " TARGET_FMT_lx " (" TARGET_FMT_lx ")\n", ID,
1761             nr, ul == 0 ? 'u' : 'l', value, env->nip);
1762}
1763
1764void helper_store_ibatu(CPUPPCState *env, uint32_t nr, target_ulong value)
1765{
1766    target_ulong mask;
1767#if defined(FLUSH_ALL_TLBS)
1768    PowerPCCPU *cpu = ppc_env_get_cpu(env);
1769#endif
1770
1771    dump_store_bat(env, 'I', 0, nr, value);
1772    if (env->IBAT[0][nr] != value) {
1773        mask = (value << 15) & 0x0FFE0000UL;
1774#if !defined(FLUSH_ALL_TLBS)
1775        do_invalidate_BAT(env, env->IBAT[0][nr], mask);
1776#endif
1777        /* When storing valid upper BAT, mask BEPI and BRPN
1778         * and invalidate all TLBs covered by this BAT
1779         */
1780        mask = (value << 15) & 0x0FFE0000UL;
1781        env->IBAT[0][nr] = (value & 0x00001FFFUL) |
1782            (value & ~0x0001FFFFUL & ~mask);
1783        env->IBAT[1][nr] = (env->IBAT[1][nr] & 0x0000007B) |
1784            (env->IBAT[1][nr] & ~0x0001FFFF & ~mask);
1785#if !defined(FLUSH_ALL_TLBS)
1786        do_invalidate_BAT(env, env->IBAT[0][nr], mask);
1787#else
1788        tlb_flush(CPU(cpu));
1789#endif
1790    }
1791}
1792
1793void helper_store_ibatl(CPUPPCState *env, uint32_t nr, target_ulong value)
1794{
1795    dump_store_bat(env, 'I', 1, nr, value);
1796    env->IBAT[1][nr] = value;
1797}
1798
1799void helper_store_dbatu(CPUPPCState *env, uint32_t nr, target_ulong value)
1800{
1801    target_ulong mask;
1802#if defined(FLUSH_ALL_TLBS)
1803    PowerPCCPU *cpu = ppc_env_get_cpu(env);
1804#endif
1805
1806    dump_store_bat(env, 'D', 0, nr, value);
1807    if (env->DBAT[0][nr] != value) {
1808        /* When storing valid upper BAT, mask BEPI and BRPN
1809         * and invalidate all TLBs covered by this BAT
1810         */
1811        mask = (value << 15) & 0x0FFE0000UL;
1812#if !defined(FLUSH_ALL_TLBS)
1813        do_invalidate_BAT(env, env->DBAT[0][nr], mask);
1814#endif
1815        mask = (value << 15) & 0x0FFE0000UL;
1816        env->DBAT[0][nr] = (value & 0x00001FFFUL) |
1817            (value & ~0x0001FFFFUL & ~mask);
1818        env->DBAT[1][nr] = (env->DBAT[1][nr] & 0x0000007B) |
1819            (env->DBAT[1][nr] & ~0x0001FFFF & ~mask);
1820#if !defined(FLUSH_ALL_TLBS)
1821        do_invalidate_BAT(env, env->DBAT[0][nr], mask);
1822#else
1823        tlb_flush(CPU(cpu));
1824#endif
1825    }
1826}
1827
1828void helper_store_dbatl(CPUPPCState *env, uint32_t nr, target_ulong value)
1829{
1830    dump_store_bat(env, 'D', 1, nr, value);
1831    env->DBAT[1][nr] = value;
1832}
1833
1834void helper_store_601_batu(CPUPPCState *env, uint32_t nr, target_ulong value)
1835{
1836    target_ulong mask;
1837#if defined(FLUSH_ALL_TLBS)
1838    PowerPCCPU *cpu = ppc_env_get_cpu(env);
1839    int do_inval;
1840#endif
1841
1842    dump_store_bat(env, 'I', 0, nr, value);
1843    if (env->IBAT[0][nr] != value) {
1844#if defined(FLUSH_ALL_TLBS)
1845        do_inval = 0;
1846#endif
1847        mask = (env->IBAT[1][nr] << 17) & 0x0FFE0000UL;
1848        if (env->IBAT[1][nr] & 0x40) {
1849            /* Invalidate BAT only if it is valid */
1850#if !defined(FLUSH_ALL_TLBS)
1851            do_invalidate_BAT(env, env->IBAT[0][nr], mask);
1852#else
1853            do_inval = 1;
1854#endif
1855        }
1856        /* When storing valid upper BAT, mask BEPI and BRPN
1857         * and invalidate all TLBs covered by this BAT
1858         */
1859        env->IBAT[0][nr] = (value & 0x00001FFFUL) |
1860            (value & ~0x0001FFFFUL & ~mask);
1861        env->DBAT[0][nr] = env->IBAT[0][nr];
1862        if (env->IBAT[1][nr] & 0x40) {
1863#if !defined(FLUSH_ALL_TLBS)
1864            do_invalidate_BAT(env, env->IBAT[0][nr], mask);
1865#else
1866            do_inval = 1;
1867#endif
1868        }
1869#if defined(FLUSH_ALL_TLBS)
1870        if (do_inval) {
1871            tlb_flush(CPU(cpu));
1872        }
1873#endif
1874    }
1875}
1876
1877void helper_store_601_batl(CPUPPCState *env, uint32_t nr, target_ulong value)
1878{
1879#if !defined(FLUSH_ALL_TLBS)
1880    target_ulong mask;
1881#else
1882    PowerPCCPU *cpu = ppc_env_get_cpu(env);
1883    int do_inval;
1884#endif
1885
1886    dump_store_bat(env, 'I', 1, nr, value);
1887    if (env->IBAT[1][nr] != value) {
1888#if defined(FLUSH_ALL_TLBS)
1889        do_inval = 0;
1890#endif
1891        if (env->IBAT[1][nr] & 0x40) {
1892#if !defined(FLUSH_ALL_TLBS)
1893            mask = (env->IBAT[1][nr] << 17) & 0x0FFE0000UL;
1894            do_invalidate_BAT(env, env->IBAT[0][nr], mask);
1895#else
1896            do_inval = 1;
1897#endif
1898        }
1899        if (value & 0x40) {
1900#if !defined(FLUSH_ALL_TLBS)
1901            mask = (value << 17) & 0x0FFE0000UL;
1902            do_invalidate_BAT(env, env->IBAT[0][nr], mask);
1903#else
1904            do_inval = 1;
1905#endif
1906        }
1907        env->IBAT[1][nr] = value;
1908        env->DBAT[1][nr] = value;
1909#if defined(FLUSH_ALL_TLBS)
1910        if (do_inval) {
1911            tlb_flush(CPU(cpu));
1912        }
1913#endif
1914    }
1915}
1916
1917/*****************************************************************************/
1918/* TLB management */
1919void ppc_tlb_invalidate_all(CPUPPCState *env)
1920{
1921    PowerPCCPU *cpu = ppc_env_get_cpu(env);
1922
1923#if defined(TARGET_PPC64)
1924    if (env->mmu_model & POWERPC_MMU_64) {
1925        env->tlb_need_flush = 0;
1926        tlb_flush(CPU(cpu));
1927    } else
1928#endif /* defined(TARGET_PPC64) */
1929    switch (env->mmu_model) {
1930    case POWERPC_MMU_SOFT_6xx:
1931    case POWERPC_MMU_SOFT_74xx:
1932        ppc6xx_tlb_invalidate_all(env);
1933        break;
1934    case POWERPC_MMU_SOFT_4xx:
1935    case POWERPC_MMU_SOFT_4xx_Z:
1936        ppc4xx_tlb_invalidate_all(env);
1937        break;
1938    case POWERPC_MMU_REAL:
1939        cpu_abort(CPU(cpu), "No TLB for PowerPC 4xx in real mode\n");
1940        break;
1941    case POWERPC_MMU_MPC8xx:
1942        /* XXX: TODO */
1943        cpu_abort(CPU(cpu), "MPC8xx MMU model is not implemented\n");
1944        break;
1945    case POWERPC_MMU_BOOKE:
1946        tlb_flush(CPU(cpu));
1947        break;
1948    case POWERPC_MMU_BOOKE206:
1949        booke206_flush_tlb(env, -1, 0);
1950        break;
1951    case POWERPC_MMU_32B:
1952    case POWERPC_MMU_601:
1953        env->tlb_need_flush = 0;
1954        tlb_flush(CPU(cpu));
1955        break;
1956    default:
1957        /* XXX: TODO */
1958        cpu_abort(CPU(cpu), "Unknown MMU model %x\n", env->mmu_model);
1959        break;
1960    }
1961}
1962
1963void ppc_tlb_invalidate_one(CPUPPCState *env, target_ulong addr)
1964{
1965#if !defined(FLUSH_ALL_TLBS)
1966    addr &= TARGET_PAGE_MASK;
1967#if defined(TARGET_PPC64)
1968    if (env->mmu_model & POWERPC_MMU_64) {
1969        /* tlbie invalidate TLBs for all segments */
1970        /* XXX: given the fact that there are too many segments to invalidate,
1971         *      and we still don't have a tlb_flush_mask(env, n, mask) in QEMU,
1972         *      we just invalidate all TLBs
1973         */
1974        env->tlb_need_flush |= TLB_NEED_LOCAL_FLUSH;
1975    } else
1976#endif /* defined(TARGET_PPC64) */
1977    switch (env->mmu_model) {
1978    case POWERPC_MMU_SOFT_6xx:
1979    case POWERPC_MMU_SOFT_74xx:
1980        ppc6xx_tlb_invalidate_virt(env, addr, 0);
1981        if (env->id_tlbs == 1) {
1982            ppc6xx_tlb_invalidate_virt(env, addr, 1);
1983        }
1984        break;
1985    case POWERPC_MMU_32B:
1986    case POWERPC_MMU_601:
1987        /* Actual CPUs invalidate entire congruence classes based on the
1988         * geometry of their TLBs and some OSes take that into account,
1989         * we just mark the TLB to be flushed later (context synchronizing
1990         * event or sync instruction on 32-bit).
1991         */
1992        env->tlb_need_flush |= TLB_NEED_LOCAL_FLUSH;
1993        break;
1994    default:
1995        /* Should never reach here with other MMU models */
1996        assert(0);
1997    }
1998#else
1999    ppc_tlb_invalidate_all(env);
2000#endif
2001}
2002
2003/*****************************************************************************/
2004/* Special registers manipulation */
2005void ppc_store_sdr1(CPUPPCState *env, target_ulong value)
2006{
2007    PowerPCCPU *cpu = ppc_env_get_cpu(env);
2008    qemu_log_mask(CPU_LOG_MMU, "%s: " TARGET_FMT_lx "\n", __func__, value);
2009    assert(!cpu->vhyp);
2010#if defined(TARGET_PPC64)
2011    if (env->mmu_model & POWERPC_MMU_64) {
2012        target_ulong sdr_mask = SDR_64_HTABORG | SDR_64_HTABSIZE;
2013        target_ulong htabsize = value & SDR_64_HTABSIZE;
2014
2015        if (value & ~sdr_mask) {
2016            error_report("Invalid bits 0x"TARGET_FMT_lx" set in SDR1",
2017                         value & ~sdr_mask);
2018            value &= sdr_mask;
2019        }
2020        if (htabsize > 28) {
2021            error_report("Invalid HTABSIZE 0x" TARGET_FMT_lx" stored in SDR1",
2022                         htabsize);
2023            return;
2024        }
2025    }
2026#endif /* defined(TARGET_PPC64) */
2027    /* FIXME: Should check for valid HTABMASK values in 32-bit case */
2028    env->spr[SPR_SDR1] = value;
2029}
2030
2031/* Segment registers load and store */
2032target_ulong helper_load_sr(CPUPPCState *env, target_ulong sr_num)
2033{
2034#if defined(TARGET_PPC64)
2035    if (env->mmu_model & POWERPC_MMU_64) {
2036        /* XXX */
2037        return 0;
2038    }
2039#endif
2040    return env->sr[sr_num];
2041}
2042
2043void helper_store_sr(CPUPPCState *env, target_ulong srnum, target_ulong value)
2044{
2045    qemu_log_mask(CPU_LOG_MMU,
2046            "%s: reg=%d " TARGET_FMT_lx " " TARGET_FMT_lx "\n", __func__,
2047            (int)srnum, value, env->sr[srnum]);
2048#if defined(TARGET_PPC64)
2049    if (env->mmu_model & POWERPC_MMU_64) {
2050        PowerPCCPU *cpu = ppc_env_get_cpu(env);
2051        uint64_t esid, vsid;
2052
2053        /* ESID = srnum */
2054        esid = ((uint64_t)(srnum & 0xf) << 28) | SLB_ESID_V;
2055
2056        /* VSID = VSID */
2057        vsid = (value & 0xfffffff) << 12;
2058        /* flags = flags */
2059        vsid |= ((value >> 27) & 0xf) << 8;
2060
2061        ppc_store_slb(cpu, srnum, esid, vsid);
2062    } else
2063#endif
2064    if (env->sr[srnum] != value) {
2065        env->sr[srnum] = value;
2066/* Invalidating 256MB of virtual memory in 4kB pages is way longer than
2067   flusing the whole TLB. */
2068#if !defined(FLUSH_ALL_TLBS) && 0
2069        {
2070            target_ulong page, end;
2071            /* Invalidate 256 MB of virtual memory */
2072            page = (16 << 20) * srnum;
2073            end = page + (16 << 20);
2074            for (; page != end; page += TARGET_PAGE_SIZE) {
2075                tlb_flush_page(CPU(cpu), page);
2076            }
2077        }
2078#else
2079        env->tlb_need_flush |= TLB_NEED_LOCAL_FLUSH;
2080#endif
2081    }
2082}
2083
2084/* TLB management */
2085void helper_tlbia(CPUPPCState *env)
2086{
2087    ppc_tlb_invalidate_all(env);
2088}
2089
2090void helper_tlbie(CPUPPCState *env, target_ulong addr)
2091{
2092    ppc_tlb_invalidate_one(env, addr);
2093}
2094
2095void helper_tlbiva(CPUPPCState *env, target_ulong addr)
2096{
2097    PowerPCCPU *cpu = ppc_env_get_cpu(env);
2098
2099    /* tlbiva instruction only exists on BookE */
2100    assert(env->mmu_model == POWERPC_MMU_BOOKE);
2101    /* XXX: TODO */
2102    cpu_abort(CPU(cpu), "BookE MMU model is not implemented\n");
2103}
2104
2105/* Software driven TLBs management */
2106/* PowerPC 602/603 software TLB load instructions helpers */
2107static void do_6xx_tlb(CPUPPCState *env, target_ulong new_EPN, int is_code)
2108{
2109    target_ulong RPN, CMP, EPN;
2110    int way;
2111
2112    RPN = env->spr[SPR_RPA];
2113    if (is_code) {
2114        CMP = env->spr[SPR_ICMP];
2115        EPN = env->spr[SPR_IMISS];
2116    } else {
2117        CMP = env->spr[SPR_DCMP];
2118        EPN = env->spr[SPR_DMISS];
2119    }
2120    way = (env->spr[SPR_SRR1] >> 17) & 1;
2121    (void)EPN; /* avoid a compiler warning */
2122    LOG_SWTLB("%s: EPN " TARGET_FMT_lx " " TARGET_FMT_lx " PTE0 " TARGET_FMT_lx
2123              " PTE1 " TARGET_FMT_lx " way %d\n", __func__, new_EPN, EPN, CMP,
2124              RPN, way);
2125    /* Store this TLB */
2126    ppc6xx_tlb_store(env, (uint32_t)(new_EPN & TARGET_PAGE_MASK),
2127                     way, is_code, CMP, RPN);
2128}
2129
2130void helper_6xx_tlbd(CPUPPCState *env, target_ulong EPN)
2131{
2132    do_6xx_tlb(env, EPN, 0);
2133}
2134
2135void helper_6xx_tlbi(CPUPPCState *env, target_ulong EPN)
2136{
2137    do_6xx_tlb(env, EPN, 1);
2138}
2139
2140/* PowerPC 74xx software TLB load instructions helpers */
2141static void do_74xx_tlb(CPUPPCState *env, target_ulong new_EPN, int is_code)
2142{
2143    target_ulong RPN, CMP, EPN;
2144    int way;
2145
2146    RPN = env->spr[SPR_PTELO];
2147    CMP = env->spr[SPR_PTEHI];
2148    EPN = env->spr[SPR_TLBMISS] & ~0x3;
2149    way = env->spr[SPR_TLBMISS] & 0x3;
2150    (void)EPN; /* avoid a compiler warning */
2151    LOG_SWTLB("%s: EPN " TARGET_FMT_lx " " TARGET_FMT_lx " PTE0 " TARGET_FMT_lx
2152              " PTE1 " TARGET_FMT_lx " way %d\n", __func__, new_EPN, EPN, CMP,
2153              RPN, way);
2154    /* Store this TLB */
2155    ppc6xx_tlb_store(env, (uint32_t)(new_EPN & TARGET_PAGE_MASK),
2156                     way, is_code, CMP, RPN);
2157}
2158
2159void helper_74xx_tlbd(CPUPPCState *env, target_ulong EPN)
2160{
2161    do_74xx_tlb(env, EPN, 0);
2162}
2163
2164void helper_74xx_tlbi(CPUPPCState *env, target_ulong EPN)
2165{
2166    do_74xx_tlb(env, EPN, 1);
2167}
2168
2169/*****************************************************************************/
2170/* PowerPC 601 specific instructions (POWER bridge) */
2171
2172target_ulong helper_rac(CPUPPCState *env, target_ulong addr)
2173{
2174    mmu_ctx_t ctx;
2175    int nb_BATs;
2176    target_ulong ret = 0;
2177
2178    /* We don't have to generate many instances of this instruction,
2179     * as rac is supervisor only.
2180     */
2181    /* XXX: FIX THIS: Pretend we have no BAT */
2182    nb_BATs = env->nb_BATs;
2183    env->nb_BATs = 0;
2184    if (get_physical_address(env, &ctx, addr, 0, ACCESS_INT) == 0) {
2185        ret = ctx.raddr;
2186    }
2187    env->nb_BATs = nb_BATs;
2188    return ret;
2189}
2190
2191static inline target_ulong booke_tlb_to_page_size(int size)
2192{
2193    return 1024 << (2 * size);
2194}
2195
2196static inline int booke_page_size_to_tlb(target_ulong page_size)
2197{
2198    int size;
2199
2200    switch (page_size) {
2201    case 0x00000400UL:
2202        size = 0x0;
2203        break;
2204    case 0x00001000UL:
2205        size = 0x1;
2206        break;
2207    case 0x00004000UL:
2208        size = 0x2;
2209        break;
2210    case 0x00010000UL:
2211        size = 0x3;
2212        break;
2213    case 0x00040000UL:
2214        size = 0x4;
2215        break;
2216    case 0x00100000UL:
2217        size = 0x5;
2218        break;
2219    case 0x00400000UL:
2220        size = 0x6;
2221        break;
2222    case 0x01000000UL:
2223        size = 0x7;
2224        break;
2225    case 0x04000000UL:
2226        size = 0x8;
2227        break;
2228    case 0x10000000UL:
2229        size = 0x9;
2230        break;
2231    case 0x40000000UL:
2232        size = 0xA;
2233        break;
2234#if defined(TARGET_PPC64)
2235    case 0x000100000000ULL:
2236        size = 0xB;
2237        break;
2238    case 0x000400000000ULL:
2239        size = 0xC;
2240        break;
2241    case 0x001000000000ULL:
2242        size = 0xD;
2243        break;
2244    case 0x004000000000ULL:
2245        size = 0xE;
2246        break;
2247    case 0x010000000000ULL:
2248        size = 0xF;
2249        break;
2250#endif
2251    default:
2252        size = -1;
2253        break;
2254    }
2255
2256    return size;
2257}
2258
2259/* Helpers for 4xx TLB management */
2260#define PPC4XX_TLB_ENTRY_MASK       0x0000003f  /* Mask for 64 TLB entries */
2261
2262#define PPC4XX_TLBHI_V              0x00000040
2263#define PPC4XX_TLBHI_E              0x00000020
2264#define PPC4XX_TLBHI_SIZE_MIN       0
2265#define PPC4XX_TLBHI_SIZE_MAX       7
2266#define PPC4XX_TLBHI_SIZE_DEFAULT   1
2267#define PPC4XX_TLBHI_SIZE_SHIFT     7
2268#define PPC4XX_TLBHI_SIZE_MASK      0x00000007
2269
2270#define PPC4XX_TLBLO_EX             0x00000200
2271#define PPC4XX_TLBLO_WR             0x00000100
2272#define PPC4XX_TLBLO_ATTR_MASK      0x000000FF
2273#define PPC4XX_TLBLO_RPN_MASK       0xFFFFFC00
2274
2275target_ulong helper_4xx_tlbre_hi(CPUPPCState *env, target_ulong entry)
2276{
2277    ppcemb_tlb_t *tlb;
2278    target_ulong ret;
2279    int size;
2280
2281    entry &= PPC4XX_TLB_ENTRY_MASK;
2282    tlb = &env->tlb.tlbe[entry];
2283    ret = tlb->EPN;
2284    if (tlb->prot & PAGE_VALID) {
2285        ret |= PPC4XX_TLBHI_V;
2286    }
2287    size = booke_page_size_to_tlb(tlb->size);
2288    if (size < PPC4XX_TLBHI_SIZE_MIN || size > PPC4XX_TLBHI_SIZE_MAX) {
2289        size = PPC4XX_TLBHI_SIZE_DEFAULT;
2290    }
2291    ret |= size << PPC4XX_TLBHI_SIZE_SHIFT;
2292    env->spr[SPR_40x_PID] = tlb->PID;
2293    return ret;
2294}
2295
2296target_ulong helper_4xx_tlbre_lo(CPUPPCState *env, target_ulong entry)
2297{
2298    ppcemb_tlb_t *tlb;
2299    target_ulong ret;
2300
2301    entry &= PPC4XX_TLB_ENTRY_MASK;
2302    tlb = &env->tlb.tlbe[entry];
2303    ret = tlb->RPN;
2304    if (tlb->prot & PAGE_EXEC) {
2305        ret |= PPC4XX_TLBLO_EX;
2306    }
2307    if (tlb->prot & PAGE_WRITE) {
2308        ret |= PPC4XX_TLBLO_WR;
2309    }
2310    return ret;
2311}
2312
2313void helper_4xx_tlbwe_hi(CPUPPCState *env, target_ulong entry,
2314                         target_ulong val)
2315{
2316    PowerPCCPU *cpu = ppc_env_get_cpu(env);
2317    CPUState *cs = CPU(cpu);
2318    ppcemb_tlb_t *tlb;
2319    target_ulong page, end;
2320
2321    LOG_SWTLB("%s entry %d val " TARGET_FMT_lx "\n", __func__, (int)entry,
2322              val);
2323    entry &= PPC4XX_TLB_ENTRY_MASK;
2324    tlb = &env->tlb.tlbe[entry];
2325    /* Invalidate previous TLB (if it's valid) */
2326    if (tlb->prot & PAGE_VALID) {
2327        end = tlb->EPN + tlb->size;
2328        LOG_SWTLB("%s: invalidate old TLB %d start " TARGET_FMT_lx " end "
2329                  TARGET_FMT_lx "\n", __func__, (int)entry, tlb->EPN, end);
2330        for (page = tlb->EPN; page < end; page += TARGET_PAGE_SIZE) {
2331            tlb_flush_page(cs, page);
2332        }
2333    }
2334    tlb->size = booke_tlb_to_page_size((val >> PPC4XX_TLBHI_SIZE_SHIFT)
2335                                       & PPC4XX_TLBHI_SIZE_MASK);
2336    /* We cannot handle TLB size < TARGET_PAGE_SIZE.
2337     * If this ever occurs, one should use the ppcemb target instead
2338     * of the ppc or ppc64 one
2339     */
2340    if ((val & PPC4XX_TLBHI_V) && tlb->size < TARGET_PAGE_SIZE) {
2341        cpu_abort(cs, "TLB size " TARGET_FMT_lu " < %u "
2342                  "are not supported (%d)\n",
2343                  tlb->size, TARGET_PAGE_SIZE, (int)((val >> 7) & 0x7));
2344    }
2345    tlb->EPN = val & ~(tlb->size - 1);
2346    if (val & PPC4XX_TLBHI_V) {
2347        tlb->prot |= PAGE_VALID;
2348        if (val & PPC4XX_TLBHI_E) {
2349            /* XXX: TO BE FIXED */
2350            cpu_abort(cs,
2351                      "Little-endian TLB entries are not supported by now\n");
2352        }
2353    } else {
2354        tlb->prot &= ~PAGE_VALID;
2355    }
2356    tlb->PID = env->spr[SPR_40x_PID]; /* PID */
2357    LOG_SWTLB("%s: set up TLB %d RPN " TARGET_FMT_plx " EPN " TARGET_FMT_lx
2358              " size " TARGET_FMT_lx " prot %c%c%c%c PID %d\n", __func__,
2359              (int)entry, tlb->RPN, tlb->EPN, tlb->size,
2360              tlb->prot & PAGE_READ ? 'r' : '-',
2361              tlb->prot & PAGE_WRITE ? 'w' : '-',
2362              tlb->prot & PAGE_EXEC ? 'x' : '-',
2363              tlb->prot & PAGE_VALID ? 'v' : '-', (int)tlb->PID);
2364    /* Invalidate new TLB (if valid) */
2365    if (tlb->prot & PAGE_VALID) {
2366        end = tlb->EPN + tlb->size;
2367        LOG_SWTLB("%s: invalidate TLB %d start " TARGET_FMT_lx " end "
2368                  TARGET_FMT_lx "\n", __func__, (int)entry, tlb->EPN, end);
2369        for (page = tlb->EPN; page < end; page += TARGET_PAGE_SIZE) {
2370            tlb_flush_page(cs, page);
2371        }
2372    }
2373}
2374
2375void helper_4xx_tlbwe_lo(CPUPPCState *env, target_ulong entry,
2376                         target_ulong val)
2377{
2378    ppcemb_tlb_t *tlb;
2379
2380    LOG_SWTLB("%s entry %i val " TARGET_FMT_lx "\n", __func__, (int)entry,
2381              val);
2382    entry &= PPC4XX_TLB_ENTRY_MASK;
2383    tlb = &env->tlb.tlbe[entry];
2384    tlb->attr = val & PPC4XX_TLBLO_ATTR_MASK;
2385    tlb->RPN = val & PPC4XX_TLBLO_RPN_MASK;
2386    tlb->prot = PAGE_READ;
2387    if (val & PPC4XX_TLBLO_EX) {
2388        tlb->prot |= PAGE_EXEC;
2389    }
2390    if (val & PPC4XX_TLBLO_WR) {
2391        tlb->prot |= PAGE_WRITE;
2392    }
2393    LOG_SWTLB("%s: set up TLB %d RPN " TARGET_FMT_plx " EPN " TARGET_FMT_lx
2394              " size " TARGET_FMT_lx " prot %c%c%c%c PID %d\n", __func__,
2395              (int)entry, tlb->RPN, tlb->EPN, tlb->size,
2396              tlb->prot & PAGE_READ ? 'r' : '-',
2397              tlb->prot & PAGE_WRITE ? 'w' : '-',
2398              tlb->prot & PAGE_EXEC ? 'x' : '-',
2399              tlb->prot & PAGE_VALID ? 'v' : '-', (int)tlb->PID);
2400}
2401
2402target_ulong helper_4xx_tlbsx(CPUPPCState *env, target_ulong address)
2403{
2404    return ppcemb_tlb_search(env, address, env->spr[SPR_40x_PID]);
2405}
2406
2407/* PowerPC 440 TLB management */
2408void helper_440_tlbwe(CPUPPCState *env, uint32_t word, target_ulong entry,
2409                      target_ulong value)
2410{
2411    PowerPCCPU *cpu = ppc_env_get_cpu(env);
2412    ppcemb_tlb_t *tlb;
2413    target_ulong EPN, RPN, size;
2414    int do_flush_tlbs;
2415
2416    LOG_SWTLB("%s word %d entry %d value " TARGET_FMT_lx "\n",
2417              __func__, word, (int)entry, value);
2418    do_flush_tlbs = 0;
2419    entry &= 0x3F;
2420    tlb = &env->tlb.tlbe[entry];
2421    switch (word) {
2422    default:
2423        /* Just here to please gcc */
2424    case 0:
2425        EPN = value & 0xFFFFFC00;
2426        if ((tlb->prot & PAGE_VALID) && EPN != tlb->EPN) {
2427            do_flush_tlbs = 1;
2428        }
2429        tlb->EPN = EPN;
2430        size = booke_tlb_to_page_size((value >> 4) & 0xF);
2431        if ((tlb->prot & PAGE_VALID) && tlb->size < size) {
2432            do_flush_tlbs = 1;
2433        }
2434        tlb->size = size;
2435        tlb->attr &= ~0x1;
2436        tlb->attr |= (value >> 8) & 1;
2437        if (value & 0x200) {
2438            tlb->prot |= PAGE_VALID;
2439        } else {
2440            if (tlb->prot & PAGE_VALID) {
2441                tlb->prot &= ~PAGE_VALID;
2442                do_flush_tlbs = 1;
2443            }
2444        }
2445        tlb->PID = env->spr[SPR_440_MMUCR] & 0x000000FF;
2446        if (do_flush_tlbs) {
2447            tlb_flush(CPU(cpu));
2448        }
2449        break;
2450    case 1:
2451        RPN = value & 0xFFFFFC0F;
2452        if ((tlb->prot & PAGE_VALID) && tlb->RPN != RPN) {
2453            tlb_flush(CPU(cpu));
2454        }
2455        tlb->RPN = RPN;
2456        break;
2457    case 2:
2458        tlb->attr = (tlb->attr & 0x1) | (value & 0x0000FF00);
2459        tlb->prot = tlb->prot & PAGE_VALID;
2460        if (value & 0x1) {
2461            tlb->prot |= PAGE_READ << 4;
2462        }
2463        if (value & 0x2) {
2464            tlb->prot |= PAGE_WRITE << 4;
2465        }
2466        if (value & 0x4) {
2467            tlb->prot |= PAGE_EXEC << 4;
2468        }
2469        if (value & 0x8) {
2470            tlb->prot |= PAGE_READ;
2471        }
2472        if (value & 0x10) {
2473            tlb->prot |= PAGE_WRITE;
2474        }
2475        if (value & 0x20) {
2476            tlb->prot |= PAGE_EXEC;
2477        }
2478        break;
2479    }
2480}
2481
2482target_ulong helper_440_tlbre(CPUPPCState *env, uint32_t word,
2483                              target_ulong entry)
2484{
2485    ppcemb_tlb_t *tlb;
2486    target_ulong ret;
2487    int size;
2488
2489    entry &= 0x3F;
2490    tlb = &env->tlb.tlbe[entry];
2491    switch (word) {
2492    default:
2493        /* Just here to please gcc */
2494    case 0:
2495        ret = tlb->EPN;
2496        size = booke_page_size_to_tlb(tlb->size);
2497        if (size < 0 || size > 0xF) {
2498            size = 1;
2499        }
2500        ret |= size << 4;
2501        if (tlb->attr & 0x1) {
2502            ret |= 0x100;
2503        }
2504        if (tlb->prot & PAGE_VALID) {
2505            ret |= 0x200;
2506        }
2507        env->spr[SPR_440_MMUCR] &= ~0x000000FF;
2508        env->spr[SPR_440_MMUCR] |= tlb->PID;
2509        break;
2510    case 1:
2511        ret = tlb->RPN;
2512        break;
2513    case 2:
2514        ret = tlb->attr & ~0x1;
2515        if (tlb->prot & (PAGE_READ << 4)) {
2516            ret |= 0x1;
2517        }
2518        if (tlb->prot & (PAGE_WRITE << 4)) {
2519            ret |= 0x2;
2520        }
2521        if (tlb->prot & (PAGE_EXEC << 4)) {
2522            ret |= 0x4;
2523        }
2524        if (tlb->prot & PAGE_READ) {
2525            ret |= 0x8;
2526        }
2527        if (tlb->prot & PAGE_WRITE) {
2528            ret |= 0x10;
2529        }
2530        if (tlb->prot & PAGE_EXEC) {
2531            ret |= 0x20;
2532        }
2533        break;
2534    }
2535    return ret;
2536}
2537
2538target_ulong helper_440_tlbsx(CPUPPCState *env, target_ulong address)
2539{
2540    return ppcemb_tlb_search(env, address, env->spr[SPR_440_MMUCR] & 0xFF);
2541}
2542
2543/* PowerPC BookE 2.06 TLB management */
2544
2545static ppcmas_tlb_t *booke206_cur_tlb(CPUPPCState *env)
2546{
2547    PowerPCCPU *cpu = ppc_env_get_cpu(env);
2548    uint32_t tlbncfg = 0;
2549    int esel = (env->spr[SPR_BOOKE_MAS0] & MAS0_ESEL_MASK) >> MAS0_ESEL_SHIFT;
2550    int ea = (env->spr[SPR_BOOKE_MAS2] & MAS2_EPN_MASK);
2551    int tlb;
2552
2553    tlb = (env->spr[SPR_BOOKE_MAS0] & MAS0_TLBSEL_MASK) >> MAS0_TLBSEL_SHIFT;
2554    tlbncfg = env->spr[SPR_BOOKE_TLB0CFG + tlb];
2555
2556    if ((tlbncfg & TLBnCFG_HES) && (env->spr[SPR_BOOKE_MAS0] & MAS0_HES)) {
2557        cpu_abort(CPU(cpu), "we don't support HES yet\n");
2558    }
2559
2560    return booke206_get_tlbm(env, tlb, ea, esel);
2561}
2562
2563void helper_booke_setpid(CPUPPCState *env, uint32_t pidn, target_ulong pid)
2564{
2565    PowerPCCPU *cpu = ppc_env_get_cpu(env);
2566
2567    env->spr[pidn] = pid;
2568    /* changing PIDs mean we're in a different address space now */
2569    tlb_flush(CPU(cpu));
2570}
2571
2572static inline void flush_page(CPUPPCState *env, ppcmas_tlb_t *tlb)
2573{
2574    PowerPCCPU *cpu = ppc_env_get_cpu(env);
2575
2576    if (booke206_tlb_to_page_size(env, tlb) == TARGET_PAGE_SIZE) {
2577        tlb_flush_page(CPU(cpu), tlb->mas2 & MAS2_EPN_MASK);
2578    } else {
2579        tlb_flush(CPU(cpu));
2580    }
2581}
2582
2583void helper_booke206_tlbwe(CPUPPCState *env)
2584{
2585    PowerPCCPU *cpu = ppc_env_get_cpu(env);
2586    uint32_t tlbncfg, tlbn;
2587    ppcmas_tlb_t *tlb;
2588    uint32_t size_tlb, size_ps;
2589    target_ulong mask;
2590
2591
2592    switch (env->spr[SPR_BOOKE_MAS0] & MAS0_WQ_MASK) {
2593    case MAS0_WQ_ALWAYS:
2594        /* good to go, write that entry */
2595        break;
2596    case MAS0_WQ_COND:
2597        /* XXX check if reserved */
2598        if (0) {
2599            return;
2600        }
2601        break;
2602    case MAS0_WQ_CLR_RSRV:
2603        /* XXX clear entry */
2604        return;
2605    default:
2606        /* no idea what to do */
2607        return;
2608    }
2609
2610    if (((env->spr[SPR_BOOKE_MAS0] & MAS0_ATSEL) == MAS0_ATSEL_LRAT) &&
2611        !msr_gs) {
2612        /* XXX we don't support direct LRAT setting yet */
2613        fprintf(stderr, "cpu: don't support LRAT setting yet\n");
2614        return;
2615    }
2616
2617    tlbn = (env->spr[SPR_BOOKE_MAS0] & MAS0_TLBSEL_MASK) >> MAS0_TLBSEL_SHIFT;
2618    tlbncfg = env->spr[SPR_BOOKE_TLB0CFG + tlbn];
2619
2620    tlb = booke206_cur_tlb(env);
2621
2622    if (!tlb) {
2623        raise_exception_err_ra(env, POWERPC_EXCP_PROGRAM,
2624                               POWERPC_EXCP_INVAL |
2625                               POWERPC_EXCP_INVAL_INVAL, GETPC());
2626    }
2627
2628    /* check that we support the targeted size */
2629    size_tlb = (env->spr[SPR_BOOKE_MAS1] & MAS1_TSIZE_MASK) >> MAS1_TSIZE_SHIFT;
2630    size_ps = booke206_tlbnps(env, tlbn);
2631    if ((env->spr[SPR_BOOKE_MAS1] & MAS1_VALID) && (tlbncfg & TLBnCFG_AVAIL) &&
2632        !(size_ps & (1 << size_tlb))) {
2633        raise_exception_err_ra(env, POWERPC_EXCP_PROGRAM,
2634                               POWERPC_EXCP_INVAL |
2635                               POWERPC_EXCP_INVAL_INVAL, GETPC());
2636    }
2637
2638    if (msr_gs) {
2639        cpu_abort(CPU(cpu), "missing HV implementation\n");
2640    }
2641
2642    if (tlb->mas1 & MAS1_VALID) {
2643        /* Invalidate the page in QEMU TLB if it was a valid entry.
2644         *
2645         * In "PowerPC e500 Core Family Reference Manual, Rev. 1",
2646         * Section "12.4.2 TLB Write Entry (tlbwe) Instruction":
2647         * (https://www.nxp.com/docs/en/reference-manual/E500CORERM.pdf)
2648         *
2649         * "Note that when an L2 TLB entry is written, it may be displacing an
2650         * already valid entry in the same L2 TLB location (a victim). If a
2651         * valid L1 TLB entry corresponds to the L2 MMU victim entry, that L1
2652         * TLB entry is automatically invalidated." */
2653        flush_page(env, tlb);
2654    }
2655
2656    tlb->mas7_3 = ((uint64_t)env->spr[SPR_BOOKE_MAS7] << 32) |
2657        env->spr[SPR_BOOKE_MAS3];
2658    tlb->mas1 = env->spr[SPR_BOOKE_MAS1];
2659
2660    if ((env->spr[SPR_MMUCFG] & MMUCFG_MAVN) == MMUCFG_MAVN_V2) {
2661        /* For TLB which has a fixed size TSIZE is ignored with MAV2 */
2662        booke206_fixed_size_tlbn(env, tlbn, tlb);
2663    } else {
2664        if (!(tlbncfg & TLBnCFG_AVAIL)) {
2665            /* force !AVAIL TLB entries to correct page size */
2666            tlb->mas1 &= ~MAS1_TSIZE_MASK;
2667            /* XXX can be configured in MMUCSR0 */
2668            tlb->mas1 |= (tlbncfg & TLBnCFG_MINSIZE) >> 12;
2669        }
2670    }
2671
2672    /* Make a mask from TLB size to discard invalid bits in EPN field */
2673    mask = ~(booke206_tlb_to_page_size(env, tlb) - 1);
2674    /* Add a mask for page attributes */
2675    mask |= MAS2_ACM | MAS2_VLE | MAS2_W | MAS2_I | MAS2_M | MAS2_G | MAS2_E;
2676
2677    if (!msr_cm) {
2678        /* Executing a tlbwe instruction in 32-bit mode will set
2679         * bits 0:31 of the TLB EPN field to zero.
2680         */
2681        mask &= 0xffffffff;
2682    }
2683
2684    tlb->mas2 = env->spr[SPR_BOOKE_MAS2] & mask;
2685
2686    if (!(tlbncfg & TLBnCFG_IPROT)) {
2687        /* no IPROT supported by TLB */
2688        tlb->mas1 &= ~MAS1_IPROT;
2689    }
2690
2691    flush_page(env, tlb);
2692}
2693
2694static inline void booke206_tlb_to_mas(CPUPPCState *env, ppcmas_tlb_t *tlb)
2695{
2696    int tlbn = booke206_tlbm_to_tlbn(env, tlb);
2697    int way = booke206_tlbm_to_way(env, tlb);
2698
2699    env->spr[SPR_BOOKE_MAS0] = tlbn << MAS0_TLBSEL_SHIFT;
2700    env->spr[SPR_BOOKE_MAS0] |= way << MAS0_ESEL_SHIFT;
2701    env->spr[SPR_BOOKE_MAS0] |= env->last_way << MAS0_NV_SHIFT;
2702
2703    env->spr[SPR_BOOKE_MAS1] = tlb->mas1;
2704    env->spr[SPR_BOOKE_MAS2] = tlb->mas2;
2705    env->spr[SPR_BOOKE_MAS3] = tlb->mas7_3;
2706    env->spr[SPR_BOOKE_MAS7] = tlb->mas7_3 >> 32;
2707}
2708
2709void helper_booke206_tlbre(CPUPPCState *env)
2710{
2711    ppcmas_tlb_t *tlb = NULL;
2712
2713    tlb = booke206_cur_tlb(env);
2714    if (!tlb) {
2715        env->spr[SPR_BOOKE_MAS1] = 0;
2716    } else {
2717        booke206_tlb_to_mas(env, tlb);
2718    }
2719}
2720
2721void helper_booke206_tlbsx(CPUPPCState *env, target_ulong address)
2722{
2723    ppcmas_tlb_t *tlb = NULL;
2724    int i, j;
2725    hwaddr raddr;
2726    uint32_t spid, sas;
2727
2728    spid = (env->spr[SPR_BOOKE_MAS6] & MAS6_SPID_MASK) >> MAS6_SPID_SHIFT;
2729    sas = env->spr[SPR_BOOKE_MAS6] & MAS6_SAS;
2730
2731    for (i = 0; i < BOOKE206_MAX_TLBN; i++) {
2732        int ways = booke206_tlb_ways(env, i);
2733
2734        for (j = 0; j < ways; j++) {
2735            tlb = booke206_get_tlbm(env, i, address, j);
2736
2737            if (!tlb) {
2738                continue;
2739            }
2740
2741            if (ppcmas_tlb_check(env, tlb, &raddr, address, spid)) {
2742                continue;
2743            }
2744
2745            if (sas != ((tlb->mas1 & MAS1_TS) >> MAS1_TS_SHIFT)) {
2746                continue;
2747            }
2748
2749            booke206_tlb_to_mas(env, tlb);
2750            return;
2751        }
2752    }
2753
2754    /* no entry found, fill with defaults */
2755    env->spr[SPR_BOOKE_MAS0] = env->spr[SPR_BOOKE_MAS4] & MAS4_TLBSELD_MASK;
2756    env->spr[SPR_BOOKE_MAS1] = env->spr[SPR_BOOKE_MAS4] & MAS4_TSIZED_MASK;
2757    env->spr[SPR_BOOKE_MAS2] = env->spr[SPR_BOOKE_MAS4] & MAS4_WIMGED_MASK;
2758    env->spr[SPR_BOOKE_MAS3] = 0;
2759    env->spr[SPR_BOOKE_MAS7] = 0;
2760
2761    if (env->spr[SPR_BOOKE_MAS6] & MAS6_SAS) {
2762        env->spr[SPR_BOOKE_MAS1] |= MAS1_TS;
2763    }
2764
2765    env->spr[SPR_BOOKE_MAS1] |= (env->spr[SPR_BOOKE_MAS6] >> 16)
2766        << MAS1_TID_SHIFT;
2767
2768    /* next victim logic */
2769    env->spr[SPR_BOOKE_MAS0] |= env->last_way << MAS0_ESEL_SHIFT;
2770    env->last_way++;
2771    env->last_way &= booke206_tlb_ways(env, 0) - 1;
2772    env->spr[SPR_BOOKE_MAS0] |= env->last_way << MAS0_NV_SHIFT;
2773}
2774
2775static inline void booke206_invalidate_ea_tlb(CPUPPCState *env, int tlbn,
2776                                              uint32_t ea)
2777{
2778    int i;
2779    int ways = booke206_tlb_ways(env, tlbn);
2780    target_ulong mask;
2781
2782    for (i = 0; i < ways; i++) {
2783        ppcmas_tlb_t *tlb = booke206_get_tlbm(env, tlbn, ea, i);
2784        if (!tlb) {
2785            continue;
2786        }
2787        mask = ~(booke206_tlb_to_page_size(env, tlb) - 1);
2788        if (((tlb->mas2 & MAS2_EPN_MASK) == (ea & mask)) &&
2789            !(tlb->mas1 & MAS1_IPROT)) {
2790            tlb->mas1 &= ~MAS1_VALID;
2791        }
2792    }
2793}
2794
2795void helper_booke206_tlbivax(CPUPPCState *env, target_ulong address)
2796{
2797    CPUState *cs;
2798
2799    if (address & 0x4) {
2800        /* flush all entries */
2801        if (address & 0x8) {
2802            /* flush all of TLB1 */
2803            booke206_flush_tlb(env, BOOKE206_FLUSH_TLB1, 1);
2804        } else {
2805            /* flush all of TLB0 */
2806            booke206_flush_tlb(env, BOOKE206_FLUSH_TLB0, 0);
2807        }
2808        return;
2809    }
2810
2811    if (address & 0x8) {
2812        /* flush TLB1 entries */
2813        booke206_invalidate_ea_tlb(env, 1, address);
2814        CPU_FOREACH(cs) {
2815            tlb_flush(cs);
2816        }
2817    } else {
2818        /* flush TLB0 entries */
2819        booke206_invalidate_ea_tlb(env, 0, address);
2820        CPU_FOREACH(cs) {
2821            tlb_flush_page(cs, address & MAS2_EPN_MASK);
2822        }
2823    }
2824}
2825
2826void helper_booke206_tlbilx0(CPUPPCState *env, target_ulong address)
2827{
2828    /* XXX missing LPID handling */
2829    booke206_flush_tlb(env, -1, 1);
2830}
2831
2832void helper_booke206_tlbilx1(CPUPPCState *env, target_ulong address)
2833{
2834    PowerPCCPU *cpu = ppc_env_get_cpu(env);
2835    int i, j;
2836    int tid = (env->spr[SPR_BOOKE_MAS6] & MAS6_SPID);
2837    ppcmas_tlb_t *tlb = env->tlb.tlbm;
2838    int tlb_size;
2839
2840    /* XXX missing LPID handling */
2841    for (i = 0; i < BOOKE206_MAX_TLBN; i++) {
2842        tlb_size = booke206_tlb_size(env, i);
2843        for (j = 0; j < tlb_size; j++) {
2844            if (!(tlb[j].mas1 & MAS1_IPROT) &&
2845                ((tlb[j].mas1 & MAS1_TID_MASK) == tid)) {
2846                tlb[j].mas1 &= ~MAS1_VALID;
2847            }
2848        }
2849        tlb += booke206_tlb_size(env, i);
2850    }
2851    tlb_flush(CPU(cpu));
2852}
2853
2854void helper_booke206_tlbilx3(CPUPPCState *env, target_ulong address)
2855{
2856    PowerPCCPU *cpu = ppc_env_get_cpu(env);
2857    int i, j;
2858    ppcmas_tlb_t *tlb;
2859    int tid = (env->spr[SPR_BOOKE_MAS6] & MAS6_SPID);
2860    int pid = tid >> MAS6_SPID_SHIFT;
2861    int sgs = env->spr[SPR_BOOKE_MAS5] & MAS5_SGS;
2862    int ind = (env->spr[SPR_BOOKE_MAS6] & MAS6_SIND) ? MAS1_IND : 0;
2863    /* XXX check for unsupported isize and raise an invalid opcode then */
2864    int size = env->spr[SPR_BOOKE_MAS6] & MAS6_ISIZE_MASK;
2865    /* XXX implement MAV2 handling */
2866    bool mav2 = false;
2867
2868    /* XXX missing LPID handling */
2869    /* flush by pid and ea */
2870    for (i = 0; i < BOOKE206_MAX_TLBN; i++) {
2871        int ways = booke206_tlb_ways(env, i);
2872
2873        for (j = 0; j < ways; j++) {
2874            tlb = booke206_get_tlbm(env, i, address, j);
2875            if (!tlb) {
2876                continue;
2877            }
2878            if ((ppcmas_tlb_check(env, tlb, NULL, address, pid) != 0) ||
2879                (tlb->mas1 & MAS1_IPROT) ||
2880                ((tlb->mas1 & MAS1_IND) != ind) ||
2881                ((tlb->mas8 & MAS8_TGS) != sgs)) {
2882                continue;
2883            }
2884            if (mav2 && ((tlb->mas1 & MAS1_TSIZE_MASK) != size)) {
2885                /* XXX only check when MMUCFG[TWC] || TLBnCFG[HES] */
2886                continue;
2887            }
2888            /* XXX e500mc doesn't match SAS, but other cores might */
2889            tlb->mas1 &= ~MAS1_VALID;
2890        }
2891    }
2892    tlb_flush(CPU(cpu));
2893}
2894
2895void helper_booke206_tlbflush(CPUPPCState *env, target_ulong type)
2896{
2897    int flags = 0;
2898
2899    if (type & 2) {
2900        flags |= BOOKE206_FLUSH_TLB1;
2901    }
2902
2903    if (type & 4) {
2904        flags |= BOOKE206_FLUSH_TLB0;
2905    }
2906
2907    booke206_flush_tlb(env, flags, 1);
2908}
2909
2910
2911void helper_check_tlb_flush_local(CPUPPCState *env)
2912{
2913    check_tlb_flush(env, false);
2914}
2915
2916void helper_check_tlb_flush_global(CPUPPCState *env)
2917{
2918    check_tlb_flush(env, true);
2919}
2920
2921/*****************************************************************************/
2922
2923/* try to fill the TLB and return an exception if error. If retaddr is
2924   NULL, it means that the function was called in C code (i.e. not
2925   from generated code or from helper.c) */
2926/* XXX: fix it to restore all registers */
2927void tlb_fill(CPUState *cs, target_ulong addr, int size,
2928              MMUAccessType access_type, int mmu_idx, uintptr_t retaddr)
2929{
2930    PowerPCCPU *cpu = POWERPC_CPU(cs);
2931    PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cs);
2932    CPUPPCState *env = &cpu->env;
2933    int ret;
2934
2935    if (pcc->handle_mmu_fault) {
2936        ret = pcc->handle_mmu_fault(cpu, addr, access_type, mmu_idx);
2937    } else {
2938        ret = cpu_ppc_handle_mmu_fault(env, addr, access_type, mmu_idx);
2939    }
2940    if (unlikely(ret != 0)) {
2941        raise_exception_err_ra(env, cs->exception_index, env->error_code,
2942                               retaddr);
2943    }
2944}
2945