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.1 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
  20#include "qemu/osdep.h"
  21#include "qemu/units.h"
  22#include "cpu.h"
  23#include "sysemu/kvm.h"
  24#include "kvm_ppc.h"
  25#include "mmu-hash64.h"
  26#include "mmu-hash32.h"
  27#include "exec/exec-all.h"
  28#include "exec/log.h"
  29#include "helper_regs.h"
  30#include "qemu/error-report.h"
  31#include "qemu/main-loop.h"
  32#include "qemu/qemu-print.h"
  33#include "internal.h"
  34#include "mmu-book3s-v3.h"
  35#include "mmu-radix64.h"
  36#include "exec/helper-proto.h"
  37#include "exec/cpu_ldst.h"
  38
  39/* #define DEBUG_BATS */
  40/* #define DEBUG_SOFTWARE_TLB */
  41/* #define DUMP_PAGE_TABLES */
  42/* #define FLUSH_ALL_TLBS */
  43
  44#ifdef DEBUG_SOFTWARE_TLB
  45#  define LOG_SWTLB(...) qemu_log_mask(CPU_LOG_MMU, __VA_ARGS__)
  46#else
  47#  define LOG_SWTLB(...) do { } while (0)
  48#endif
  49
  50#ifdef DEBUG_BATS
  51#  define LOG_BATS(...) qemu_log_mask(CPU_LOG_MMU, __VA_ARGS__)
  52#else
  53#  define LOG_BATS(...) do { } while (0)
  54#endif
  55
  56/*****************************************************************************/
  57/* PowerPC MMU emulation */
  58
  59/* Software driven TLB helpers */
  60static inline void ppc6xx_tlb_invalidate_all(CPUPPCState *env)
  61{
  62    ppc6xx_tlb_t *tlb;
  63    int nr, max;
  64
  65    /* LOG_SWTLB("Invalidate all TLBs\n"); */
  66    /* Invalidate all defined software TLB */
  67    max = env->nb_tlb;
  68    if (env->id_tlbs == 1) {
  69        max *= 2;
  70    }
  71    for (nr = 0; nr < max; nr++) {
  72        tlb = &env->tlb.tlb6[nr];
  73        pte_invalidate(&tlb->pte0);
  74    }
  75    tlb_flush(env_cpu(env));
  76}
  77
  78static inline void ppc6xx_tlb_invalidate_virt2(CPUPPCState *env,
  79                                               target_ulong eaddr,
  80                                               int is_code, int match_epn)
  81{
  82#if !defined(FLUSH_ALL_TLBS)
  83    CPUState *cs = env_cpu(env);
  84    ppc6xx_tlb_t *tlb;
  85    int way, nr;
  86
  87    /* Invalidate ITLB + DTLB, all ways */
  88    for (way = 0; way < env->nb_ways; way++) {
  89        nr = ppc6xx_tlb_getnum(env, eaddr, way, is_code);
  90        tlb = &env->tlb.tlb6[nr];
  91        if (pte_is_valid(tlb->pte0) && (match_epn == 0 || eaddr == tlb->EPN)) {
  92            LOG_SWTLB("TLB invalidate %d/%d " TARGET_FMT_lx "\n", nr,
  93                      env->nb_tlb, eaddr);
  94            pte_invalidate(&tlb->pte0);
  95            tlb_flush_page(cs, tlb->EPN);
  96        }
  97    }
  98#else
  99    /* XXX: PowerPC specification say this is valid as well */
 100    ppc6xx_tlb_invalidate_all(env);
 101#endif
 102}
 103
 104static inline void ppc6xx_tlb_invalidate_virt(CPUPPCState *env,
 105                                              target_ulong eaddr, int is_code)
 106{
 107    ppc6xx_tlb_invalidate_virt2(env, eaddr, is_code, 0);
 108}
 109
 110static void ppc6xx_tlb_store(CPUPPCState *env, target_ulong EPN, int way,
 111                             int is_code, target_ulong pte0, target_ulong pte1)
 112{
 113    ppc6xx_tlb_t *tlb;
 114    int nr;
 115
 116    nr = ppc6xx_tlb_getnum(env, EPN, way, is_code);
 117    tlb = &env->tlb.tlb6[nr];
 118    LOG_SWTLB("Set TLB %d/%d EPN " TARGET_FMT_lx " PTE0 " TARGET_FMT_lx
 119              " PTE1 " TARGET_FMT_lx "\n", nr, env->nb_tlb, EPN, pte0, pte1);
 120    /* Invalidate any pending reference in QEMU for this virtual address */
 121    ppc6xx_tlb_invalidate_virt2(env, EPN, is_code, 1);
 122    tlb->pte0 = pte0;
 123    tlb->pte1 = pte1;
 124    tlb->EPN = EPN;
 125    /* Store last way for LRU mechanism */
 126    env->last_way = way;
 127}
 128
 129/* Generic TLB search function for PowerPC embedded implementations */
 130static int ppcemb_tlb_search(CPUPPCState *env, target_ulong address,
 131                             uint32_t pid)
 132{
 133    ppcemb_tlb_t *tlb;
 134    hwaddr raddr;
 135    int i, ret;
 136
 137    /* Default return value is no match */
 138    ret = -1;
 139    for (i = 0; i < env->nb_tlb; i++) {
 140        tlb = &env->tlb.tlbe[i];
 141        if (ppcemb_tlb_check(env, tlb, &raddr, address, pid, 0, i) == 0) {
 142            ret = i;
 143            break;
 144        }
 145    }
 146
 147    return ret;
 148}
 149
 150/* Helpers specific to PowerPC 40x implementations */
 151static inline void ppc4xx_tlb_invalidate_all(CPUPPCState *env)
 152{
 153    ppcemb_tlb_t *tlb;
 154    int i;
 155
 156    for (i = 0; i < env->nb_tlb; i++) {
 157        tlb = &env->tlb.tlbe[i];
 158        tlb->prot &= ~PAGE_VALID;
 159    }
 160    tlb_flush(env_cpu(env));
 161}
 162
 163static void booke206_flush_tlb(CPUPPCState *env, int flags,
 164                               const int check_iprot)
 165{
 166    int tlb_size;
 167    int i, j;
 168    ppcmas_tlb_t *tlb = env->tlb.tlbm;
 169
 170    for (i = 0; i < BOOKE206_MAX_TLBN; i++) {
 171        if (flags & (1 << i)) {
 172            tlb_size = booke206_tlb_size(env, i);
 173            for (j = 0; j < tlb_size; j++) {
 174                if (!check_iprot || !(tlb[j].mas1 & MAS1_IPROT)) {
 175                    tlb[j].mas1 &= ~MAS1_VALID;
 176                }
 177            }
 178        }
 179        tlb += booke206_tlb_size(env, i);
 180    }
 181
 182    tlb_flush(env_cpu(env));
 183}
 184
 185static int get_physical_address(CPUPPCState *env, mmu_ctx_t *ctx,
 186                                target_ulong eaddr, MMUAccessType access_type,
 187                                int type)
 188{
 189    return get_physical_address_wtlb(env, ctx, eaddr, access_type, type, 0);
 190}
 191
 192
 193
 194/*****************************************************************************/
 195/* BATs management */
 196#if !defined(FLUSH_ALL_TLBS)
 197static inline void do_invalidate_BAT(CPUPPCState *env, target_ulong BATu,
 198                                     target_ulong mask)
 199{
 200    CPUState *cs = env_cpu(env);
 201    target_ulong base, end, page;
 202
 203    base = BATu & ~0x0001FFFF;
 204    end = base + mask + 0x00020000;
 205    if (((end - base) >> TARGET_PAGE_BITS) > 1024) {
 206        /* Flushing 1024 4K pages is slower than a complete flush */
 207        LOG_BATS("Flush all BATs\n");
 208        tlb_flush(cs);
 209        LOG_BATS("Flush done\n");
 210        return;
 211    }
 212    LOG_BATS("Flush BAT from " TARGET_FMT_lx " to " TARGET_FMT_lx " ("
 213             TARGET_FMT_lx ")\n", base, end, mask);
 214    for (page = base; page != end; page += TARGET_PAGE_SIZE) {
 215        tlb_flush_page(cs, page);
 216    }
 217    LOG_BATS("Flush done\n");
 218}
 219#endif
 220
 221static inline void dump_store_bat(CPUPPCState *env, char ID, int ul, int nr,
 222                                  target_ulong value)
 223{
 224    LOG_BATS("Set %cBAT%d%c to " TARGET_FMT_lx " (" TARGET_FMT_lx ")\n", ID,
 225             nr, ul == 0 ? 'u' : 'l', value, env->nip);
 226}
 227
 228void helper_store_ibatu(CPUPPCState *env, uint32_t nr, target_ulong value)
 229{
 230    target_ulong mask;
 231
 232    dump_store_bat(env, 'I', 0, nr, value);
 233    if (env->IBAT[0][nr] != value) {
 234        mask = (value << 15) & 0x0FFE0000UL;
 235#if !defined(FLUSH_ALL_TLBS)
 236        do_invalidate_BAT(env, env->IBAT[0][nr], mask);
 237#endif
 238        /*
 239         * When storing valid upper BAT, mask BEPI and BRPN and
 240         * invalidate all TLBs covered by this BAT
 241         */
 242        mask = (value << 15) & 0x0FFE0000UL;
 243        env->IBAT[0][nr] = (value & 0x00001FFFUL) |
 244            (value & ~0x0001FFFFUL & ~mask);
 245        env->IBAT[1][nr] = (env->IBAT[1][nr] & 0x0000007B) |
 246            (env->IBAT[1][nr] & ~0x0001FFFF & ~mask);
 247#if !defined(FLUSH_ALL_TLBS)
 248        do_invalidate_BAT(env, env->IBAT[0][nr], mask);
 249#else
 250        tlb_flush(env_cpu(env));
 251#endif
 252    }
 253}
 254
 255void helper_store_ibatl(CPUPPCState *env, uint32_t nr, target_ulong value)
 256{
 257    dump_store_bat(env, 'I', 1, nr, value);
 258    env->IBAT[1][nr] = value;
 259}
 260
 261void helper_store_dbatu(CPUPPCState *env, uint32_t nr, target_ulong value)
 262{
 263    target_ulong mask;
 264
 265    dump_store_bat(env, 'D', 0, nr, value);
 266    if (env->DBAT[0][nr] != value) {
 267        /*
 268         * When storing valid upper BAT, mask BEPI and BRPN and
 269         * invalidate all TLBs covered by this BAT
 270         */
 271        mask = (value << 15) & 0x0FFE0000UL;
 272#if !defined(FLUSH_ALL_TLBS)
 273        do_invalidate_BAT(env, env->DBAT[0][nr], mask);
 274#endif
 275        mask = (value << 15) & 0x0FFE0000UL;
 276        env->DBAT[0][nr] = (value & 0x00001FFFUL) |
 277            (value & ~0x0001FFFFUL & ~mask);
 278        env->DBAT[1][nr] = (env->DBAT[1][nr] & 0x0000007B) |
 279            (env->DBAT[1][nr] & ~0x0001FFFF & ~mask);
 280#if !defined(FLUSH_ALL_TLBS)
 281        do_invalidate_BAT(env, env->DBAT[0][nr], mask);
 282#else
 283        tlb_flush(env_cpu(env));
 284#endif
 285    }
 286}
 287
 288void helper_store_dbatl(CPUPPCState *env, uint32_t nr, target_ulong value)
 289{
 290    dump_store_bat(env, 'D', 1, nr, value);
 291    env->DBAT[1][nr] = value;
 292}
 293
 294void helper_store_601_batu(CPUPPCState *env, uint32_t nr, target_ulong value)
 295{
 296    target_ulong mask;
 297#if defined(FLUSH_ALL_TLBS)
 298    int do_inval;
 299#endif
 300
 301    dump_store_bat(env, 'I', 0, nr, value);
 302    if (env->IBAT[0][nr] != value) {
 303#if defined(FLUSH_ALL_TLBS)
 304        do_inval = 0;
 305#endif
 306        mask = (env->IBAT[1][nr] << 17) & 0x0FFE0000UL;
 307        if (env->IBAT[1][nr] & 0x40) {
 308            /* Invalidate BAT only if it is valid */
 309#if !defined(FLUSH_ALL_TLBS)
 310            do_invalidate_BAT(env, env->IBAT[0][nr], mask);
 311#else
 312            do_inval = 1;
 313#endif
 314        }
 315        /*
 316         * When storing valid upper BAT, mask BEPI and BRPN and
 317         * invalidate all TLBs covered by this BAT
 318         */
 319        env->IBAT[0][nr] = (value & 0x00001FFFUL) |
 320            (value & ~0x0001FFFFUL & ~mask);
 321        env->DBAT[0][nr] = env->IBAT[0][nr];
 322        if (env->IBAT[1][nr] & 0x40) {
 323#if !defined(FLUSH_ALL_TLBS)
 324            do_invalidate_BAT(env, env->IBAT[0][nr], mask);
 325#else
 326            do_inval = 1;
 327#endif
 328        }
 329#if defined(FLUSH_ALL_TLBS)
 330        if (do_inval) {
 331            tlb_flush(env_cpu(env));
 332        }
 333#endif
 334    }
 335}
 336
 337void helper_store_601_batl(CPUPPCState *env, uint32_t nr, target_ulong value)
 338{
 339#if !defined(FLUSH_ALL_TLBS)
 340    target_ulong mask;
 341#else
 342    int do_inval;
 343#endif
 344
 345    dump_store_bat(env, 'I', 1, nr, value);
 346    if (env->IBAT[1][nr] != value) {
 347#if defined(FLUSH_ALL_TLBS)
 348        do_inval = 0;
 349#endif
 350        if (env->IBAT[1][nr] & 0x40) {
 351#if !defined(FLUSH_ALL_TLBS)
 352            mask = (env->IBAT[1][nr] << 17) & 0x0FFE0000UL;
 353            do_invalidate_BAT(env, env->IBAT[0][nr], mask);
 354#else
 355            do_inval = 1;
 356#endif
 357        }
 358        if (value & 0x40) {
 359#if !defined(FLUSH_ALL_TLBS)
 360            mask = (value << 17) & 0x0FFE0000UL;
 361            do_invalidate_BAT(env, env->IBAT[0][nr], mask);
 362#else
 363            do_inval = 1;
 364#endif
 365        }
 366        env->IBAT[1][nr] = value;
 367        env->DBAT[1][nr] = value;
 368#if defined(FLUSH_ALL_TLBS)
 369        if (do_inval) {
 370            tlb_flush(env_cpu(env));
 371        }
 372#endif
 373    }
 374}
 375
 376/*****************************************************************************/
 377/* TLB management */
 378void ppc_tlb_invalidate_all(CPUPPCState *env)
 379{
 380#if defined(TARGET_PPC64)
 381    if (mmu_is_64bit(env->mmu_model)) {
 382        env->tlb_need_flush = 0;
 383        tlb_flush(env_cpu(env));
 384    } else
 385#endif /* defined(TARGET_PPC64) */
 386    switch (env->mmu_model) {
 387    case POWERPC_MMU_SOFT_6xx:
 388    case POWERPC_MMU_SOFT_74xx:
 389        ppc6xx_tlb_invalidate_all(env);
 390        break;
 391    case POWERPC_MMU_SOFT_4xx:
 392    case POWERPC_MMU_SOFT_4xx_Z:
 393        ppc4xx_tlb_invalidate_all(env);
 394        break;
 395    case POWERPC_MMU_REAL:
 396        cpu_abort(env_cpu(env), "No TLB for PowerPC 4xx in real mode\n");
 397        break;
 398    case POWERPC_MMU_MPC8xx:
 399        /* XXX: TODO */
 400        cpu_abort(env_cpu(env), "MPC8xx MMU model is not implemented\n");
 401        break;
 402    case POWERPC_MMU_BOOKE:
 403        tlb_flush(env_cpu(env));
 404        break;
 405    case POWERPC_MMU_BOOKE206:
 406        booke206_flush_tlb(env, -1, 0);
 407        break;
 408    case POWERPC_MMU_32B:
 409    case POWERPC_MMU_601:
 410        env->tlb_need_flush = 0;
 411        tlb_flush(env_cpu(env));
 412        break;
 413    default:
 414        /* XXX: TODO */
 415        cpu_abort(env_cpu(env), "Unknown MMU model %x\n", env->mmu_model);
 416        break;
 417    }
 418}
 419
 420void ppc_tlb_invalidate_one(CPUPPCState *env, target_ulong addr)
 421{
 422#if !defined(FLUSH_ALL_TLBS)
 423    addr &= TARGET_PAGE_MASK;
 424#if defined(TARGET_PPC64)
 425    if (mmu_is_64bit(env->mmu_model)) {
 426        /* tlbie invalidate TLBs for all segments */
 427        /*
 428         * XXX: given the fact that there are too many segments to invalidate,
 429         *      and we still don't have a tlb_flush_mask(env, n, mask) in QEMU,
 430         *      we just invalidate all TLBs
 431         */
 432        env->tlb_need_flush |= TLB_NEED_LOCAL_FLUSH;
 433    } else
 434#endif /* defined(TARGET_PPC64) */
 435    switch (env->mmu_model) {
 436    case POWERPC_MMU_SOFT_6xx:
 437    case POWERPC_MMU_SOFT_74xx:
 438        ppc6xx_tlb_invalidate_virt(env, addr, 0);
 439        if (env->id_tlbs == 1) {
 440            ppc6xx_tlb_invalidate_virt(env, addr, 1);
 441        }
 442        break;
 443    case POWERPC_MMU_32B:
 444    case POWERPC_MMU_601:
 445        /*
 446         * Actual CPUs invalidate entire congruence classes based on
 447         * the geometry of their TLBs and some OSes take that into
 448         * account, we just mark the TLB to be flushed later (context
 449         * synchronizing event or sync instruction on 32-bit).
 450         */
 451        env->tlb_need_flush |= TLB_NEED_LOCAL_FLUSH;
 452        break;
 453    default:
 454        /* Should never reach here with other MMU models */
 455        assert(0);
 456    }
 457#else
 458    ppc_tlb_invalidate_all(env);
 459#endif
 460}
 461
 462/*****************************************************************************/
 463/* Special registers manipulation */
 464
 465/* Segment registers load and store */
 466target_ulong helper_load_sr(CPUPPCState *env, target_ulong sr_num)
 467{
 468#if defined(TARGET_PPC64)
 469    if (mmu_is_64bit(env->mmu_model)) {
 470        /* XXX */
 471        return 0;
 472    }
 473#endif
 474    return env->sr[sr_num];
 475}
 476
 477void helper_store_sr(CPUPPCState *env, target_ulong srnum, target_ulong value)
 478{
 479    qemu_log_mask(CPU_LOG_MMU,
 480            "%s: reg=%d " TARGET_FMT_lx " " TARGET_FMT_lx "\n", __func__,
 481            (int)srnum, value, env->sr[srnum]);
 482#if defined(TARGET_PPC64)
 483    if (mmu_is_64bit(env->mmu_model)) {
 484        PowerPCCPU *cpu = env_archcpu(env);
 485        uint64_t esid, vsid;
 486
 487        /* ESID = srnum */
 488        esid = ((uint64_t)(srnum & 0xf) << 28) | SLB_ESID_V;
 489
 490        /* VSID = VSID */
 491        vsid = (value & 0xfffffff) << 12;
 492        /* flags = flags */
 493        vsid |= ((value >> 27) & 0xf) << 8;
 494
 495        ppc_store_slb(cpu, srnum, esid, vsid);
 496    } else
 497#endif
 498    if (env->sr[srnum] != value) {
 499        env->sr[srnum] = value;
 500        /*
 501         * Invalidating 256MB of virtual memory in 4kB pages is way
 502         * longer than flushing the whole TLB.
 503         */
 504#if !defined(FLUSH_ALL_TLBS) && 0
 505        {
 506            target_ulong page, end;
 507            /* Invalidate 256 MB of virtual memory */
 508            page = (16 << 20) * srnum;
 509            end = page + (16 << 20);
 510            for (; page != end; page += TARGET_PAGE_SIZE) {
 511                tlb_flush_page(env_cpu(env), page);
 512            }
 513        }
 514#else
 515        env->tlb_need_flush |= TLB_NEED_LOCAL_FLUSH;
 516#endif
 517    }
 518}
 519
 520/* TLB management */
 521void helper_tlbia(CPUPPCState *env)
 522{
 523    ppc_tlb_invalidate_all(env);
 524}
 525
 526void helper_tlbie(CPUPPCState *env, target_ulong addr)
 527{
 528    ppc_tlb_invalidate_one(env, addr);
 529}
 530
 531void helper_tlbiva(CPUPPCState *env, target_ulong addr)
 532{
 533    /* tlbiva instruction only exists on BookE */
 534    assert(env->mmu_model == POWERPC_MMU_BOOKE);
 535    /* XXX: TODO */
 536    cpu_abort(env_cpu(env), "BookE MMU model is not implemented\n");
 537}
 538
 539/* Software driven TLBs management */
 540/* PowerPC 602/603 software TLB load instructions helpers */
 541static void do_6xx_tlb(CPUPPCState *env, target_ulong new_EPN, int is_code)
 542{
 543    target_ulong RPN, CMP, EPN;
 544    int way;
 545
 546    RPN = env->spr[SPR_RPA];
 547    if (is_code) {
 548        CMP = env->spr[SPR_ICMP];
 549        EPN = env->spr[SPR_IMISS];
 550    } else {
 551        CMP = env->spr[SPR_DCMP];
 552        EPN = env->spr[SPR_DMISS];
 553    }
 554    way = (env->spr[SPR_SRR1] >> 17) & 1;
 555    (void)EPN; /* avoid a compiler warning */
 556    LOG_SWTLB("%s: EPN " TARGET_FMT_lx " " TARGET_FMT_lx " PTE0 " TARGET_FMT_lx
 557              " PTE1 " TARGET_FMT_lx " way %d\n", __func__, new_EPN, EPN, CMP,
 558              RPN, way);
 559    /* Store this TLB */
 560    ppc6xx_tlb_store(env, (uint32_t)(new_EPN & TARGET_PAGE_MASK),
 561                     way, is_code, CMP, RPN);
 562}
 563
 564void helper_6xx_tlbd(CPUPPCState *env, target_ulong EPN)
 565{
 566    do_6xx_tlb(env, EPN, 0);
 567}
 568
 569void helper_6xx_tlbi(CPUPPCState *env, target_ulong EPN)
 570{
 571    do_6xx_tlb(env, EPN, 1);
 572}
 573
 574/* PowerPC 74xx software TLB load instructions helpers */
 575static void do_74xx_tlb(CPUPPCState *env, target_ulong new_EPN, int is_code)
 576{
 577    target_ulong RPN, CMP, EPN;
 578    int way;
 579
 580    RPN = env->spr[SPR_PTELO];
 581    CMP = env->spr[SPR_PTEHI];
 582    EPN = env->spr[SPR_TLBMISS] & ~0x3;
 583    way = env->spr[SPR_TLBMISS] & 0x3;
 584    (void)EPN; /* avoid a compiler warning */
 585    LOG_SWTLB("%s: EPN " TARGET_FMT_lx " " TARGET_FMT_lx " PTE0 " TARGET_FMT_lx
 586              " PTE1 " TARGET_FMT_lx " way %d\n", __func__, new_EPN, EPN, CMP,
 587              RPN, way);
 588    /* Store this TLB */
 589    ppc6xx_tlb_store(env, (uint32_t)(new_EPN & TARGET_PAGE_MASK),
 590                     way, is_code, CMP, RPN);
 591}
 592
 593void helper_74xx_tlbd(CPUPPCState *env, target_ulong EPN)
 594{
 595    do_74xx_tlb(env, EPN, 0);
 596}
 597
 598void helper_74xx_tlbi(CPUPPCState *env, target_ulong EPN)
 599{
 600    do_74xx_tlb(env, EPN, 1);
 601}
 602
 603/*****************************************************************************/
 604/* PowerPC 601 specific instructions (POWER bridge) */
 605
 606target_ulong helper_rac(CPUPPCState *env, target_ulong addr)
 607{
 608    mmu_ctx_t ctx;
 609    int nb_BATs;
 610    target_ulong ret = 0;
 611
 612    /*
 613     * We don't have to generate many instances of this instruction,
 614     * as rac is supervisor only.
 615     *
 616     * XXX: FIX THIS: Pretend we have no BAT
 617     */
 618    nb_BATs = env->nb_BATs;
 619    env->nb_BATs = 0;
 620    if (get_physical_address(env, &ctx, addr, 0, ACCESS_INT) == 0) {
 621        ret = ctx.raddr;
 622    }
 623    env->nb_BATs = nb_BATs;
 624    return ret;
 625}
 626
 627static inline target_ulong booke_tlb_to_page_size(int size)
 628{
 629    return 1024 << (2 * size);
 630}
 631
 632static inline int booke_page_size_to_tlb(target_ulong page_size)
 633{
 634    int size;
 635
 636    switch (page_size) {
 637    case 0x00000400UL:
 638        size = 0x0;
 639        break;
 640    case 0x00001000UL:
 641        size = 0x1;
 642        break;
 643    case 0x00004000UL:
 644        size = 0x2;
 645        break;
 646    case 0x00010000UL:
 647        size = 0x3;
 648        break;
 649    case 0x00040000UL:
 650        size = 0x4;
 651        break;
 652    case 0x00100000UL:
 653        size = 0x5;
 654        break;
 655    case 0x00400000UL:
 656        size = 0x6;
 657        break;
 658    case 0x01000000UL:
 659        size = 0x7;
 660        break;
 661    case 0x04000000UL:
 662        size = 0x8;
 663        break;
 664    case 0x10000000UL:
 665        size = 0x9;
 666        break;
 667    case 0x40000000UL:
 668        size = 0xA;
 669        break;
 670#if defined(TARGET_PPC64)
 671    case 0x000100000000ULL:
 672        size = 0xB;
 673        break;
 674    case 0x000400000000ULL:
 675        size = 0xC;
 676        break;
 677    case 0x001000000000ULL:
 678        size = 0xD;
 679        break;
 680    case 0x004000000000ULL:
 681        size = 0xE;
 682        break;
 683    case 0x010000000000ULL:
 684        size = 0xF;
 685        break;
 686#endif
 687    default:
 688        size = -1;
 689        break;
 690    }
 691
 692    return size;
 693}
 694
 695/* Helpers for 4xx TLB management */
 696#define PPC4XX_TLB_ENTRY_MASK       0x0000003f  /* Mask for 64 TLB entries */
 697
 698#define PPC4XX_TLBHI_V              0x00000040
 699#define PPC4XX_TLBHI_E              0x00000020
 700#define PPC4XX_TLBHI_SIZE_MIN       0
 701#define PPC4XX_TLBHI_SIZE_MAX       7
 702#define PPC4XX_TLBHI_SIZE_DEFAULT   1
 703#define PPC4XX_TLBHI_SIZE_SHIFT     7
 704#define PPC4XX_TLBHI_SIZE_MASK      0x00000007
 705
 706#define PPC4XX_TLBLO_EX             0x00000200
 707#define PPC4XX_TLBLO_WR             0x00000100
 708#define PPC4XX_TLBLO_ATTR_MASK      0x000000FF
 709#define PPC4XX_TLBLO_RPN_MASK       0xFFFFFC00
 710
 711target_ulong helper_4xx_tlbre_hi(CPUPPCState *env, target_ulong entry)
 712{
 713    ppcemb_tlb_t *tlb;
 714    target_ulong ret;
 715    int size;
 716
 717    entry &= PPC4XX_TLB_ENTRY_MASK;
 718    tlb = &env->tlb.tlbe[entry];
 719    ret = tlb->EPN;
 720    if (tlb->prot & PAGE_VALID) {
 721        ret |= PPC4XX_TLBHI_V;
 722    }
 723    size = booke_page_size_to_tlb(tlb->size);
 724    if (size < PPC4XX_TLBHI_SIZE_MIN || size > PPC4XX_TLBHI_SIZE_MAX) {
 725        size = PPC4XX_TLBHI_SIZE_DEFAULT;
 726    }
 727    ret |= size << PPC4XX_TLBHI_SIZE_SHIFT;
 728    env->spr[SPR_40x_PID] = tlb->PID;
 729    return ret;
 730}
 731
 732target_ulong helper_4xx_tlbre_lo(CPUPPCState *env, target_ulong entry)
 733{
 734    ppcemb_tlb_t *tlb;
 735    target_ulong ret;
 736
 737    entry &= PPC4XX_TLB_ENTRY_MASK;
 738    tlb = &env->tlb.tlbe[entry];
 739    ret = tlb->RPN;
 740    if (tlb->prot & PAGE_EXEC) {
 741        ret |= PPC4XX_TLBLO_EX;
 742    }
 743    if (tlb->prot & PAGE_WRITE) {
 744        ret |= PPC4XX_TLBLO_WR;
 745    }
 746    return ret;
 747}
 748
 749void helper_4xx_tlbwe_hi(CPUPPCState *env, target_ulong entry,
 750                         target_ulong val)
 751{
 752    CPUState *cs = env_cpu(env);
 753    ppcemb_tlb_t *tlb;
 754    target_ulong page, end;
 755
 756    LOG_SWTLB("%s entry %d val " TARGET_FMT_lx "\n", __func__, (int)entry,
 757              val);
 758    entry &= PPC4XX_TLB_ENTRY_MASK;
 759    tlb = &env->tlb.tlbe[entry];
 760    /* Invalidate previous TLB (if it's valid) */
 761    if (tlb->prot & PAGE_VALID) {
 762        end = tlb->EPN + tlb->size;
 763        LOG_SWTLB("%s: invalidate old TLB %d start " TARGET_FMT_lx " end "
 764                  TARGET_FMT_lx "\n", __func__, (int)entry, tlb->EPN, end);
 765        for (page = tlb->EPN; page < end; page += TARGET_PAGE_SIZE) {
 766            tlb_flush_page(cs, page);
 767        }
 768    }
 769    tlb->size = booke_tlb_to_page_size((val >> PPC4XX_TLBHI_SIZE_SHIFT)
 770                                       & PPC4XX_TLBHI_SIZE_MASK);
 771    /*
 772     * We cannot handle TLB size < TARGET_PAGE_SIZE.
 773     * If this ever occurs, we should implement TARGET_PAGE_BITS_VARY
 774     */
 775    if ((val & PPC4XX_TLBHI_V) && tlb->size < TARGET_PAGE_SIZE) {
 776        cpu_abort(cs, "TLB size " TARGET_FMT_lu " < %u "
 777                  "are not supported (%d)\n"
 778                  "Please implement TARGET_PAGE_BITS_VARY\n",
 779                  tlb->size, TARGET_PAGE_SIZE, (int)((val >> 7) & 0x7));
 780    }
 781    tlb->EPN = val & ~(tlb->size - 1);
 782    if (val & PPC4XX_TLBHI_V) {
 783        tlb->prot |= PAGE_VALID;
 784        if (val & PPC4XX_TLBHI_E) {
 785            /* XXX: TO BE FIXED */
 786            cpu_abort(cs,
 787                      "Little-endian TLB entries are not supported by now\n");
 788        }
 789    } else {
 790        tlb->prot &= ~PAGE_VALID;
 791    }
 792    tlb->PID = env->spr[SPR_40x_PID]; /* PID */
 793    LOG_SWTLB("%s: set up TLB %d RPN " TARGET_FMT_plx " EPN " TARGET_FMT_lx
 794              " size " TARGET_FMT_lx " prot %c%c%c%c PID %d\n", __func__,
 795              (int)entry, tlb->RPN, tlb->EPN, tlb->size,
 796              tlb->prot & PAGE_READ ? 'r' : '-',
 797              tlb->prot & PAGE_WRITE ? 'w' : '-',
 798              tlb->prot & PAGE_EXEC ? 'x' : '-',
 799              tlb->prot & PAGE_VALID ? 'v' : '-', (int)tlb->PID);
 800    /* Invalidate new TLB (if valid) */
 801    if (tlb->prot & PAGE_VALID) {
 802        end = tlb->EPN + tlb->size;
 803        LOG_SWTLB("%s: invalidate TLB %d start " TARGET_FMT_lx " end "
 804                  TARGET_FMT_lx "\n", __func__, (int)entry, tlb->EPN, end);
 805        for (page = tlb->EPN; page < end; page += TARGET_PAGE_SIZE) {
 806            tlb_flush_page(cs, page);
 807        }
 808    }
 809}
 810
 811void helper_4xx_tlbwe_lo(CPUPPCState *env, target_ulong entry,
 812                         target_ulong val)
 813{
 814    ppcemb_tlb_t *tlb;
 815
 816    LOG_SWTLB("%s entry %i val " TARGET_FMT_lx "\n", __func__, (int)entry,
 817              val);
 818    entry &= PPC4XX_TLB_ENTRY_MASK;
 819    tlb = &env->tlb.tlbe[entry];
 820    tlb->attr = val & PPC4XX_TLBLO_ATTR_MASK;
 821    tlb->RPN = val & PPC4XX_TLBLO_RPN_MASK;
 822    tlb->prot = PAGE_READ;
 823    if (val & PPC4XX_TLBLO_EX) {
 824        tlb->prot |= PAGE_EXEC;
 825    }
 826    if (val & PPC4XX_TLBLO_WR) {
 827        tlb->prot |= PAGE_WRITE;
 828    }
 829    LOG_SWTLB("%s: set up TLB %d RPN " TARGET_FMT_plx " EPN " TARGET_FMT_lx
 830              " size " TARGET_FMT_lx " prot %c%c%c%c PID %d\n", __func__,
 831              (int)entry, tlb->RPN, tlb->EPN, tlb->size,
 832              tlb->prot & PAGE_READ ? 'r' : '-',
 833              tlb->prot & PAGE_WRITE ? 'w' : '-',
 834              tlb->prot & PAGE_EXEC ? 'x' : '-',
 835              tlb->prot & PAGE_VALID ? 'v' : '-', (int)tlb->PID);
 836}
 837
 838target_ulong helper_4xx_tlbsx(CPUPPCState *env, target_ulong address)
 839{
 840    return ppcemb_tlb_search(env, address, env->spr[SPR_40x_PID]);
 841}
 842
 843/* PowerPC 440 TLB management */
 844void helper_440_tlbwe(CPUPPCState *env, uint32_t word, target_ulong entry,
 845                      target_ulong value)
 846{
 847    ppcemb_tlb_t *tlb;
 848    target_ulong EPN, RPN, size;
 849    int do_flush_tlbs;
 850
 851    LOG_SWTLB("%s word %d entry %d value " TARGET_FMT_lx "\n",
 852              __func__, word, (int)entry, value);
 853    do_flush_tlbs = 0;
 854    entry &= 0x3F;
 855    tlb = &env->tlb.tlbe[entry];
 856    switch (word) {
 857    default:
 858        /* Just here to please gcc */
 859    case 0:
 860        EPN = value & 0xFFFFFC00;
 861        if ((tlb->prot & PAGE_VALID) && EPN != tlb->EPN) {
 862            do_flush_tlbs = 1;
 863        }
 864        tlb->EPN = EPN;
 865        size = booke_tlb_to_page_size((value >> 4) & 0xF);
 866        if ((tlb->prot & PAGE_VALID) && tlb->size < size) {
 867            do_flush_tlbs = 1;
 868        }
 869        tlb->size = size;
 870        tlb->attr &= ~0x1;
 871        tlb->attr |= (value >> 8) & 1;
 872        if (value & 0x200) {
 873            tlb->prot |= PAGE_VALID;
 874        } else {
 875            if (tlb->prot & PAGE_VALID) {
 876                tlb->prot &= ~PAGE_VALID;
 877                do_flush_tlbs = 1;
 878            }
 879        }
 880        tlb->PID = env->spr[SPR_440_MMUCR] & 0x000000FF;
 881        if (do_flush_tlbs) {
 882            tlb_flush(env_cpu(env));
 883        }
 884        break;
 885    case 1:
 886        RPN = value & 0xFFFFFC0F;
 887        if ((tlb->prot & PAGE_VALID) && tlb->RPN != RPN) {
 888            tlb_flush(env_cpu(env));
 889        }
 890        tlb->RPN = RPN;
 891        break;
 892    case 2:
 893        tlb->attr = (tlb->attr & 0x1) | (value & 0x0000FF00);
 894        tlb->prot = tlb->prot & PAGE_VALID;
 895        if (value & 0x1) {
 896            tlb->prot |= PAGE_READ << 4;
 897        }
 898        if (value & 0x2) {
 899            tlb->prot |= PAGE_WRITE << 4;
 900        }
 901        if (value & 0x4) {
 902            tlb->prot |= PAGE_EXEC << 4;
 903        }
 904        if (value & 0x8) {
 905            tlb->prot |= PAGE_READ;
 906        }
 907        if (value & 0x10) {
 908            tlb->prot |= PAGE_WRITE;
 909        }
 910        if (value & 0x20) {
 911            tlb->prot |= PAGE_EXEC;
 912        }
 913        break;
 914    }
 915}
 916
 917target_ulong helper_440_tlbre(CPUPPCState *env, uint32_t word,
 918                              target_ulong entry)
 919{
 920    ppcemb_tlb_t *tlb;
 921    target_ulong ret;
 922    int size;
 923
 924    entry &= 0x3F;
 925    tlb = &env->tlb.tlbe[entry];
 926    switch (word) {
 927    default:
 928        /* Just here to please gcc */
 929    case 0:
 930        ret = tlb->EPN;
 931        size = booke_page_size_to_tlb(tlb->size);
 932        if (size < 0 || size > 0xF) {
 933            size = 1;
 934        }
 935        ret |= size << 4;
 936        if (tlb->attr & 0x1) {
 937            ret |= 0x100;
 938        }
 939        if (tlb->prot & PAGE_VALID) {
 940            ret |= 0x200;
 941        }
 942        env->spr[SPR_440_MMUCR] &= ~0x000000FF;
 943        env->spr[SPR_440_MMUCR] |= tlb->PID;
 944        break;
 945    case 1:
 946        ret = tlb->RPN;
 947        break;
 948    case 2:
 949        ret = tlb->attr & ~0x1;
 950        if (tlb->prot & (PAGE_READ << 4)) {
 951            ret |= 0x1;
 952        }
 953        if (tlb->prot & (PAGE_WRITE << 4)) {
 954            ret |= 0x2;
 955        }
 956        if (tlb->prot & (PAGE_EXEC << 4)) {
 957            ret |= 0x4;
 958        }
 959        if (tlb->prot & PAGE_READ) {
 960            ret |= 0x8;
 961        }
 962        if (tlb->prot & PAGE_WRITE) {
 963            ret |= 0x10;
 964        }
 965        if (tlb->prot & PAGE_EXEC) {
 966            ret |= 0x20;
 967        }
 968        break;
 969    }
 970    return ret;
 971}
 972
 973target_ulong helper_440_tlbsx(CPUPPCState *env, target_ulong address)
 974{
 975    return ppcemb_tlb_search(env, address, env->spr[SPR_440_MMUCR] & 0xFF);
 976}
 977
 978/* PowerPC BookE 2.06 TLB management */
 979
 980static ppcmas_tlb_t *booke206_cur_tlb(CPUPPCState *env)
 981{
 982    uint32_t tlbncfg = 0;
 983    int esel = (env->spr[SPR_BOOKE_MAS0] & MAS0_ESEL_MASK) >> MAS0_ESEL_SHIFT;
 984    int ea = (env->spr[SPR_BOOKE_MAS2] & MAS2_EPN_MASK);
 985    int tlb;
 986
 987    tlb = (env->spr[SPR_BOOKE_MAS0] & MAS0_TLBSEL_MASK) >> MAS0_TLBSEL_SHIFT;
 988    tlbncfg = env->spr[SPR_BOOKE_TLB0CFG + tlb];
 989
 990    if ((tlbncfg & TLBnCFG_HES) && (env->spr[SPR_BOOKE_MAS0] & MAS0_HES)) {
 991        cpu_abort(env_cpu(env), "we don't support HES yet\n");
 992    }
 993
 994    return booke206_get_tlbm(env, tlb, ea, esel);
 995}
 996
 997void helper_booke_setpid(CPUPPCState *env, uint32_t pidn, target_ulong pid)
 998{
 999    env->spr[pidn] = pid;
1000    /* changing PIDs mean we're in a different address space now */
1001    tlb_flush(env_cpu(env));
1002}
1003
1004void helper_booke_set_eplc(CPUPPCState *env, target_ulong val)
1005{
1006    env->spr[SPR_BOOKE_EPLC] = val & EPID_MASK;
1007    tlb_flush_by_mmuidx(env_cpu(env), 1 << PPC_TLB_EPID_LOAD);
1008}
1009void helper_booke_set_epsc(CPUPPCState *env, target_ulong val)
1010{
1011    env->spr[SPR_BOOKE_EPSC] = val & EPID_MASK;
1012    tlb_flush_by_mmuidx(env_cpu(env), 1 << PPC_TLB_EPID_STORE);
1013}
1014
1015static inline void flush_page(CPUPPCState *env, ppcmas_tlb_t *tlb)
1016{
1017    if (booke206_tlb_to_page_size(env, tlb) == TARGET_PAGE_SIZE) {
1018        tlb_flush_page(env_cpu(env), tlb->mas2 & MAS2_EPN_MASK);
1019    } else {
1020        tlb_flush(env_cpu(env));
1021    }
1022}
1023
1024void helper_booke206_tlbwe(CPUPPCState *env)
1025{
1026    uint32_t tlbncfg, tlbn;
1027    ppcmas_tlb_t *tlb;
1028    uint32_t size_tlb, size_ps;
1029    target_ulong mask;
1030
1031
1032    switch (env->spr[SPR_BOOKE_MAS0] & MAS0_WQ_MASK) {
1033    case MAS0_WQ_ALWAYS:
1034        /* good to go, write that entry */
1035        break;
1036    case MAS0_WQ_COND:
1037        /* XXX check if reserved */
1038        if (0) {
1039            return;
1040        }
1041        break;
1042    case MAS0_WQ_CLR_RSRV:
1043        /* XXX clear entry */
1044        return;
1045    default:
1046        /* no idea what to do */
1047        return;
1048    }
1049
1050    if (((env->spr[SPR_BOOKE_MAS0] & MAS0_ATSEL) == MAS0_ATSEL_LRAT) &&
1051        !msr_gs) {
1052        /* XXX we don't support direct LRAT setting yet */
1053        fprintf(stderr, "cpu: don't support LRAT setting yet\n");
1054        return;
1055    }
1056
1057    tlbn = (env->spr[SPR_BOOKE_MAS0] & MAS0_TLBSEL_MASK) >> MAS0_TLBSEL_SHIFT;
1058    tlbncfg = env->spr[SPR_BOOKE_TLB0CFG + tlbn];
1059
1060    tlb = booke206_cur_tlb(env);
1061
1062    if (!tlb) {
1063        raise_exception_err_ra(env, POWERPC_EXCP_PROGRAM,
1064                               POWERPC_EXCP_INVAL |
1065                               POWERPC_EXCP_INVAL_INVAL, GETPC());
1066    }
1067
1068    /* check that we support the targeted size */
1069    size_tlb = (env->spr[SPR_BOOKE_MAS1] & MAS1_TSIZE_MASK) >> MAS1_TSIZE_SHIFT;
1070    size_ps = booke206_tlbnps(env, tlbn);
1071    if ((env->spr[SPR_BOOKE_MAS1] & MAS1_VALID) && (tlbncfg & TLBnCFG_AVAIL) &&
1072        !(size_ps & (1 << size_tlb))) {
1073        raise_exception_err_ra(env, POWERPC_EXCP_PROGRAM,
1074                               POWERPC_EXCP_INVAL |
1075                               POWERPC_EXCP_INVAL_INVAL, GETPC());
1076    }
1077
1078    if (msr_gs) {
1079        cpu_abort(env_cpu(env), "missing HV implementation\n");
1080    }
1081
1082    if (tlb->mas1 & MAS1_VALID) {
1083        /*
1084         * Invalidate the page in QEMU TLB if it was a valid entry.
1085         *
1086         * In "PowerPC e500 Core Family Reference Manual, Rev. 1",
1087         * Section "12.4.2 TLB Write Entry (tlbwe) Instruction":
1088         * (https://www.nxp.com/docs/en/reference-manual/E500CORERM.pdf)
1089         *
1090         * "Note that when an L2 TLB entry is written, it may be displacing an
1091         * already valid entry in the same L2 TLB location (a victim). If a
1092         * valid L1 TLB entry corresponds to the L2 MMU victim entry, that L1
1093         * TLB entry is automatically invalidated."
1094         */
1095        flush_page(env, tlb);
1096    }
1097
1098    tlb->mas7_3 = ((uint64_t)env->spr[SPR_BOOKE_MAS7] << 32) |
1099        env->spr[SPR_BOOKE_MAS3];
1100    tlb->mas1 = env->spr[SPR_BOOKE_MAS1];
1101
1102    if ((env->spr[SPR_MMUCFG] & MMUCFG_MAVN) == MMUCFG_MAVN_V2) {
1103        /* For TLB which has a fixed size TSIZE is ignored with MAV2 */
1104        booke206_fixed_size_tlbn(env, tlbn, tlb);
1105    } else {
1106        if (!(tlbncfg & TLBnCFG_AVAIL)) {
1107            /* force !AVAIL TLB entries to correct page size */
1108            tlb->mas1 &= ~MAS1_TSIZE_MASK;
1109            /* XXX can be configured in MMUCSR0 */
1110            tlb->mas1 |= (tlbncfg & TLBnCFG_MINSIZE) >> 12;
1111        }
1112    }
1113
1114    /* Make a mask from TLB size to discard invalid bits in EPN field */
1115    mask = ~(booke206_tlb_to_page_size(env, tlb) - 1);
1116    /* Add a mask for page attributes */
1117    mask |= MAS2_ACM | MAS2_VLE | MAS2_W | MAS2_I | MAS2_M | MAS2_G | MAS2_E;
1118
1119    if (!msr_cm) {
1120        /*
1121         * Executing a tlbwe instruction in 32-bit mode will set bits
1122         * 0:31 of the TLB EPN field to zero.
1123         */
1124        mask &= 0xffffffff;
1125    }
1126
1127    tlb->mas2 = env->spr[SPR_BOOKE_MAS2] & mask;
1128
1129    if (!(tlbncfg & TLBnCFG_IPROT)) {
1130        /* no IPROT supported by TLB */
1131        tlb->mas1 &= ~MAS1_IPROT;
1132    }
1133
1134    flush_page(env, tlb);
1135}
1136
1137static inline void booke206_tlb_to_mas(CPUPPCState *env, ppcmas_tlb_t *tlb)
1138{
1139    int tlbn = booke206_tlbm_to_tlbn(env, tlb);
1140    int way = booke206_tlbm_to_way(env, tlb);
1141
1142    env->spr[SPR_BOOKE_MAS0] = tlbn << MAS0_TLBSEL_SHIFT;
1143    env->spr[SPR_BOOKE_MAS0] |= way << MAS0_ESEL_SHIFT;
1144    env->spr[SPR_BOOKE_MAS0] |= env->last_way << MAS0_NV_SHIFT;
1145
1146    env->spr[SPR_BOOKE_MAS1] = tlb->mas1;
1147    env->spr[SPR_BOOKE_MAS2] = tlb->mas2;
1148    env->spr[SPR_BOOKE_MAS3] = tlb->mas7_3;
1149    env->spr[SPR_BOOKE_MAS7] = tlb->mas7_3 >> 32;
1150}
1151
1152void helper_booke206_tlbre(CPUPPCState *env)
1153{
1154    ppcmas_tlb_t *tlb = NULL;
1155
1156    tlb = booke206_cur_tlb(env);
1157    if (!tlb) {
1158        env->spr[SPR_BOOKE_MAS1] = 0;
1159    } else {
1160        booke206_tlb_to_mas(env, tlb);
1161    }
1162}
1163
1164void helper_booke206_tlbsx(CPUPPCState *env, target_ulong address)
1165{
1166    ppcmas_tlb_t *tlb = NULL;
1167    int i, j;
1168    hwaddr raddr;
1169    uint32_t spid, sas;
1170
1171    spid = (env->spr[SPR_BOOKE_MAS6] & MAS6_SPID_MASK) >> MAS6_SPID_SHIFT;
1172    sas = env->spr[SPR_BOOKE_MAS6] & MAS6_SAS;
1173
1174    for (i = 0; i < BOOKE206_MAX_TLBN; i++) {
1175        int ways = booke206_tlb_ways(env, i);
1176
1177        for (j = 0; j < ways; j++) {
1178            tlb = booke206_get_tlbm(env, i, address, j);
1179
1180            if (!tlb) {
1181                continue;
1182            }
1183
1184            if (ppcmas_tlb_check(env, tlb, &raddr, address, spid)) {
1185                continue;
1186            }
1187
1188            if (sas != ((tlb->mas1 & MAS1_TS) >> MAS1_TS_SHIFT)) {
1189                continue;
1190            }
1191
1192            booke206_tlb_to_mas(env, tlb);
1193            return;
1194        }
1195    }
1196
1197    /* no entry found, fill with defaults */
1198    env->spr[SPR_BOOKE_MAS0] = env->spr[SPR_BOOKE_MAS4] & MAS4_TLBSELD_MASK;
1199    env->spr[SPR_BOOKE_MAS1] = env->spr[SPR_BOOKE_MAS4] & MAS4_TSIZED_MASK;
1200    env->spr[SPR_BOOKE_MAS2] = env->spr[SPR_BOOKE_MAS4] & MAS4_WIMGED_MASK;
1201    env->spr[SPR_BOOKE_MAS3] = 0;
1202    env->spr[SPR_BOOKE_MAS7] = 0;
1203
1204    if (env->spr[SPR_BOOKE_MAS6] & MAS6_SAS) {
1205        env->spr[SPR_BOOKE_MAS1] |= MAS1_TS;
1206    }
1207
1208    env->spr[SPR_BOOKE_MAS1] |= (env->spr[SPR_BOOKE_MAS6] >> 16)
1209        << MAS1_TID_SHIFT;
1210
1211    /* next victim logic */
1212    env->spr[SPR_BOOKE_MAS0] |= env->last_way << MAS0_ESEL_SHIFT;
1213    env->last_way++;
1214    env->last_way &= booke206_tlb_ways(env, 0) - 1;
1215    env->spr[SPR_BOOKE_MAS0] |= env->last_way << MAS0_NV_SHIFT;
1216}
1217
1218static inline void booke206_invalidate_ea_tlb(CPUPPCState *env, int tlbn,
1219                                              vaddr ea)
1220{
1221    int i;
1222    int ways = booke206_tlb_ways(env, tlbn);
1223    target_ulong mask;
1224
1225    for (i = 0; i < ways; i++) {
1226        ppcmas_tlb_t *tlb = booke206_get_tlbm(env, tlbn, ea, i);
1227        if (!tlb) {
1228            continue;
1229        }
1230        mask = ~(booke206_tlb_to_page_size(env, tlb) - 1);
1231        if (((tlb->mas2 & MAS2_EPN_MASK) == (ea & mask)) &&
1232            !(tlb->mas1 & MAS1_IPROT)) {
1233            tlb->mas1 &= ~MAS1_VALID;
1234        }
1235    }
1236}
1237
1238void helper_booke206_tlbivax(CPUPPCState *env, target_ulong address)
1239{
1240    CPUState *cs;
1241
1242    if (address & 0x4) {
1243        /* flush all entries */
1244        if (address & 0x8) {
1245            /* flush all of TLB1 */
1246            booke206_flush_tlb(env, BOOKE206_FLUSH_TLB1, 1);
1247        } else {
1248            /* flush all of TLB0 */
1249            booke206_flush_tlb(env, BOOKE206_FLUSH_TLB0, 0);
1250        }
1251        return;
1252    }
1253
1254    if (address & 0x8) {
1255        /* flush TLB1 entries */
1256        booke206_invalidate_ea_tlb(env, 1, address);
1257        CPU_FOREACH(cs) {
1258            tlb_flush(cs);
1259        }
1260    } else {
1261        /* flush TLB0 entries */
1262        booke206_invalidate_ea_tlb(env, 0, address);
1263        CPU_FOREACH(cs) {
1264            tlb_flush_page(cs, address & MAS2_EPN_MASK);
1265        }
1266    }
1267}
1268
1269void helper_booke206_tlbilx0(CPUPPCState *env, target_ulong address)
1270{
1271    /* XXX missing LPID handling */
1272    booke206_flush_tlb(env, -1, 1);
1273}
1274
1275void helper_booke206_tlbilx1(CPUPPCState *env, target_ulong address)
1276{
1277    int i, j;
1278    int tid = (env->spr[SPR_BOOKE_MAS6] & MAS6_SPID);
1279    ppcmas_tlb_t *tlb = env->tlb.tlbm;
1280    int tlb_size;
1281
1282    /* XXX missing LPID handling */
1283    for (i = 0; i < BOOKE206_MAX_TLBN; i++) {
1284        tlb_size = booke206_tlb_size(env, i);
1285        for (j = 0; j < tlb_size; j++) {
1286            if (!(tlb[j].mas1 & MAS1_IPROT) &&
1287                ((tlb[j].mas1 & MAS1_TID_MASK) == tid)) {
1288                tlb[j].mas1 &= ~MAS1_VALID;
1289            }
1290        }
1291        tlb += booke206_tlb_size(env, i);
1292    }
1293    tlb_flush(env_cpu(env));
1294}
1295
1296void helper_booke206_tlbilx3(CPUPPCState *env, target_ulong address)
1297{
1298    int i, j;
1299    ppcmas_tlb_t *tlb;
1300    int tid = (env->spr[SPR_BOOKE_MAS6] & MAS6_SPID);
1301    int pid = tid >> MAS6_SPID_SHIFT;
1302    int sgs = env->spr[SPR_BOOKE_MAS5] & MAS5_SGS;
1303    int ind = (env->spr[SPR_BOOKE_MAS6] & MAS6_SIND) ? MAS1_IND : 0;
1304    /* XXX check for unsupported isize and raise an invalid opcode then */
1305    int size = env->spr[SPR_BOOKE_MAS6] & MAS6_ISIZE_MASK;
1306    /* XXX implement MAV2 handling */
1307    bool mav2 = false;
1308
1309    /* XXX missing LPID handling */
1310    /* flush by pid and ea */
1311    for (i = 0; i < BOOKE206_MAX_TLBN; i++) {
1312        int ways = booke206_tlb_ways(env, i);
1313
1314        for (j = 0; j < ways; j++) {
1315            tlb = booke206_get_tlbm(env, i, address, j);
1316            if (!tlb) {
1317                continue;
1318            }
1319            if ((ppcmas_tlb_check(env, tlb, NULL, address, pid) != 0) ||
1320                (tlb->mas1 & MAS1_IPROT) ||
1321                ((tlb->mas1 & MAS1_IND) != ind) ||
1322                ((tlb->mas8 & MAS8_TGS) != sgs)) {
1323                continue;
1324            }
1325            if (mav2 && ((tlb->mas1 & MAS1_TSIZE_MASK) != size)) {
1326                /* XXX only check when MMUCFG[TWC] || TLBnCFG[HES] */
1327                continue;
1328            }
1329            /* XXX e500mc doesn't match SAS, but other cores might */
1330            tlb->mas1 &= ~MAS1_VALID;
1331        }
1332    }
1333    tlb_flush(env_cpu(env));
1334}
1335
1336void helper_booke206_tlbflush(CPUPPCState *env, target_ulong type)
1337{
1338    int flags = 0;
1339
1340    if (type & 2) {
1341        flags |= BOOKE206_FLUSH_TLB1;
1342    }
1343
1344    if (type & 4) {
1345        flags |= BOOKE206_FLUSH_TLB0;
1346    }
1347
1348    booke206_flush_tlb(env, flags, 1);
1349}
1350
1351
1352void helper_check_tlb_flush_local(CPUPPCState *env)
1353{
1354    check_tlb_flush(env, false);
1355}
1356
1357void helper_check_tlb_flush_global(CPUPPCState *env)
1358{
1359    check_tlb_flush(env, true);
1360}
1361
1362
1363bool ppc_cpu_tlb_fill(CPUState *cs, vaddr eaddr, int size,
1364                      MMUAccessType access_type, int mmu_idx,
1365                      bool probe, uintptr_t retaddr)
1366{
1367    PowerPCCPU *cpu = POWERPC_CPU(cs);
1368    hwaddr raddr;
1369    int page_size, prot;
1370
1371    if (ppc_xlate(cpu, eaddr, access_type, &raddr,
1372                  &page_size, &prot, mmu_idx, !probe)) {
1373        tlb_set_page(cs, eaddr & TARGET_PAGE_MASK, raddr & TARGET_PAGE_MASK,
1374                     prot, mmu_idx, 1UL << page_size);
1375        return true;
1376    }
1377    if (probe) {
1378        return false;
1379    }
1380    raise_exception_err_ra(&cpu->env, cs->exception_index,
1381                           cpu->env.error_code, retaddr);
1382}
1383