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