cachepc-qemu

Fork of AMDESE/qemu with changes for cachepc side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-qemu
Log | Files | Refs | Submodules | LICENSE | sfeed.txt

mmu_helper.c (40400B)


      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                                              uint32_t 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}