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