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-hash32.c (17434B)


      1/*
      2 *  PowerPC MMU, TLB and BAT emulation helpers for QEMU.
      3 *
      4 *  Copyright (c) 2003-2007 Jocelyn Mayer
      5 *  Copyright (c) 2013 David Gibson, IBM Corporation
      6 *
      7 * This library is free software; you can redistribute it and/or
      8 * modify it under the terms of the GNU Lesser General Public
      9 * License as published by the Free Software Foundation; either
     10 * version 2.1 of the License, or (at your option) any later version.
     11 *
     12 * This library is distributed in the hope that it will be useful,
     13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
     14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     15 * Lesser General Public License for more details.
     16 *
     17 * You should have received a copy of the GNU Lesser General Public
     18 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
     19 */
     20
     21#include "qemu/osdep.h"
     22#include "cpu.h"
     23#include "exec/exec-all.h"
     24#include "sysemu/kvm.h"
     25#include "kvm_ppc.h"
     26#include "internal.h"
     27#include "mmu-hash32.h"
     28#include "mmu-books.h"
     29#include "exec/log.h"
     30
     31/* #define DEBUG_BATS */
     32
     33#ifdef DEBUG_BATS
     34#  define LOG_BATS(...) qemu_log_mask(CPU_LOG_MMU, __VA_ARGS__)
     35#else
     36#  define LOG_BATS(...) do { } while (0)
     37#endif
     38
     39struct mmu_ctx_hash32 {
     40    hwaddr raddr;      /* Real address              */
     41    int prot;                      /* Protection bits           */
     42    int key;                       /* Access key                */
     43};
     44
     45static int ppc_hash32_pp_prot(int key, int pp, int nx)
     46{
     47    int prot;
     48
     49    if (key == 0) {
     50        switch (pp) {
     51        case 0x0:
     52        case 0x1:
     53        case 0x2:
     54            prot = PAGE_READ | PAGE_WRITE;
     55            break;
     56
     57        case 0x3:
     58            prot = PAGE_READ;
     59            break;
     60
     61        default:
     62            abort();
     63        }
     64    } else {
     65        switch (pp) {
     66        case 0x0:
     67            prot = 0;
     68            break;
     69
     70        case 0x1:
     71        case 0x3:
     72            prot = PAGE_READ;
     73            break;
     74
     75        case 0x2:
     76            prot = PAGE_READ | PAGE_WRITE;
     77            break;
     78
     79        default:
     80            abort();
     81        }
     82    }
     83    if (nx == 0) {
     84        prot |= PAGE_EXEC;
     85    }
     86
     87    return prot;
     88}
     89
     90static int ppc_hash32_pte_prot(int mmu_idx,
     91                               target_ulong sr, ppc_hash_pte32_t pte)
     92{
     93    unsigned pp, key;
     94
     95    key = !!(mmuidx_pr(mmu_idx) ? (sr & SR32_KP) : (sr & SR32_KS));
     96    pp = pte.pte1 & HPTE32_R_PP;
     97
     98    return ppc_hash32_pp_prot(key, pp, !!(sr & SR32_NX));
     99}
    100
    101static target_ulong hash32_bat_size(int mmu_idx,
    102                                    target_ulong batu, target_ulong batl)
    103{
    104    if ((mmuidx_pr(mmu_idx) && !(batu & BATU32_VP))
    105        || (!mmuidx_pr(mmu_idx) && !(batu & BATU32_VS))) {
    106        return 0;
    107    }
    108
    109    return BATU32_BEPI & ~((batu & BATU32_BL) << 15);
    110}
    111
    112static int hash32_bat_prot(PowerPCCPU *cpu,
    113                           target_ulong batu, target_ulong batl)
    114{
    115    int pp, prot;
    116
    117    prot = 0;
    118    pp = batl & BATL32_PP;
    119    if (pp != 0) {
    120        prot = PAGE_READ | PAGE_EXEC;
    121        if (pp == 0x2) {
    122            prot |= PAGE_WRITE;
    123        }
    124    }
    125    return prot;
    126}
    127
    128static target_ulong hash32_bat_601_size(PowerPCCPU *cpu,
    129                                target_ulong batu, target_ulong batl)
    130{
    131    if (!(batl & BATL32_601_V)) {
    132        return 0;
    133    }
    134
    135    return BATU32_BEPI & ~((batl & BATL32_601_BL) << 17);
    136}
    137
    138static int hash32_bat_601_prot(int mmu_idx,
    139                               target_ulong batu, target_ulong batl)
    140{
    141    int key, pp;
    142
    143    pp = batu & BATU32_601_PP;
    144    if (mmuidx_pr(mmu_idx) == 0) {
    145        key = !!(batu & BATU32_601_KS);
    146    } else {
    147        key = !!(batu & BATU32_601_KP);
    148    }
    149    return ppc_hash32_pp_prot(key, pp, 0);
    150}
    151
    152static hwaddr ppc_hash32_bat_lookup(PowerPCCPU *cpu, target_ulong ea,
    153                                    MMUAccessType access_type, int *prot,
    154                                    int mmu_idx)
    155{
    156    CPUPPCState *env = &cpu->env;
    157    target_ulong *BATlt, *BATut;
    158    bool ifetch = access_type == MMU_INST_FETCH;
    159    int i;
    160
    161    LOG_BATS("%s: %cBAT v " TARGET_FMT_lx "\n", __func__,
    162             ifetch ? 'I' : 'D', ea);
    163    if (ifetch) {
    164        BATlt = env->IBAT[1];
    165        BATut = env->IBAT[0];
    166    } else {
    167        BATlt = env->DBAT[1];
    168        BATut = env->DBAT[0];
    169    }
    170    for (i = 0; i < env->nb_BATs; i++) {
    171        target_ulong batu = BATut[i];
    172        target_ulong batl = BATlt[i];
    173        target_ulong mask;
    174
    175        if (unlikely(env->mmu_model == POWERPC_MMU_601)) {
    176            mask = hash32_bat_601_size(cpu, batu, batl);
    177        } else {
    178            mask = hash32_bat_size(mmu_idx, batu, batl);
    179        }
    180        LOG_BATS("%s: %cBAT%d v " TARGET_FMT_lx " BATu " TARGET_FMT_lx
    181                 " BATl " TARGET_FMT_lx "\n", __func__,
    182                 ifetch ? 'I' : 'D', i, ea, batu, batl);
    183
    184        if (mask && ((ea & mask) == (batu & BATU32_BEPI))) {
    185            hwaddr raddr = (batl & mask) | (ea & ~mask);
    186
    187            if (unlikely(env->mmu_model == POWERPC_MMU_601)) {
    188                *prot = hash32_bat_601_prot(mmu_idx, batu, batl);
    189            } else {
    190                *prot = hash32_bat_prot(cpu, batu, batl);
    191            }
    192
    193            return raddr & TARGET_PAGE_MASK;
    194        }
    195    }
    196
    197    /* No hit */
    198#if defined(DEBUG_BATS)
    199    if (qemu_log_enabled()) {
    200        target_ulong *BATu, *BATl;
    201        target_ulong BEPIl, BEPIu, bl;
    202
    203        LOG_BATS("no BAT match for " TARGET_FMT_lx ":\n", ea);
    204        for (i = 0; i < 4; i++) {
    205            BATu = &BATut[i];
    206            BATl = &BATlt[i];
    207            BEPIu = *BATu & BATU32_BEPIU;
    208            BEPIl = *BATu & BATU32_BEPIL;
    209            bl = (*BATu & 0x00001FFC) << 15;
    210            LOG_BATS("%s: %cBAT%d v " TARGET_FMT_lx " BATu " TARGET_FMT_lx
    211                     " BATl " TARGET_FMT_lx "\n\t" TARGET_FMT_lx " "
    212                     TARGET_FMT_lx " " TARGET_FMT_lx "\n",
    213                     __func__, ifetch ? 'I' : 'D', i, ea,
    214                     *BATu, *BATl, BEPIu, BEPIl, bl);
    215        }
    216    }
    217#endif
    218
    219    return -1;
    220}
    221
    222static bool ppc_hash32_direct_store(PowerPCCPU *cpu, target_ulong sr,
    223                                    target_ulong eaddr,
    224                                    MMUAccessType access_type,
    225                                    hwaddr *raddr, int *prot, int mmu_idx,
    226                                    bool guest_visible)
    227{
    228    CPUState *cs = CPU(cpu);
    229    CPUPPCState *env = &cpu->env;
    230    int key = !!(mmuidx_pr(mmu_idx) ? (sr & SR32_KP) : (sr & SR32_KS));
    231
    232    qemu_log_mask(CPU_LOG_MMU, "direct store...\n");
    233
    234    if ((sr & 0x1FF00000) >> 20 == 0x07f) {
    235        /*
    236         * Memory-forced I/O controller interface access
    237         *
    238         * If T=1 and BUID=x'07F', the 601 performs a memory access
    239         * to SR[28-31] LA[4-31], bypassing all protection mechanisms.
    240         */
    241        *raddr = ((sr & 0xF) << 28) | (eaddr & 0x0FFFFFFF);
    242        *prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
    243        return true;
    244    }
    245
    246    if (access_type == MMU_INST_FETCH) {
    247        /* No code fetch is allowed in direct-store areas */
    248        if (guest_visible) {
    249            cs->exception_index = POWERPC_EXCP_ISI;
    250            env->error_code = 0x10000000;
    251        }
    252        return false;
    253    }
    254
    255    /*
    256     * From ppc_cpu_get_phys_page_debug, env->access_type is not set.
    257     * Assume ACCESS_INT for that case.
    258     */
    259    switch (guest_visible ? env->access_type : ACCESS_INT) {
    260    case ACCESS_INT:
    261        /* Integer load/store : only access allowed */
    262        break;
    263    case ACCESS_FLOAT:
    264        /* Floating point load/store */
    265        cs->exception_index = POWERPC_EXCP_ALIGN;
    266        env->error_code = POWERPC_EXCP_ALIGN_FP;
    267        env->spr[SPR_DAR] = eaddr;
    268        return false;
    269    case ACCESS_RES:
    270        /* lwarx, ldarx or srwcx. */
    271        env->error_code = 0;
    272        env->spr[SPR_DAR] = eaddr;
    273        if (access_type == MMU_DATA_STORE) {
    274            env->spr[SPR_DSISR] = 0x06000000;
    275        } else {
    276            env->spr[SPR_DSISR] = 0x04000000;
    277        }
    278        return false;
    279    case ACCESS_CACHE:
    280        /*
    281         * dcba, dcbt, dcbtst, dcbf, dcbi, dcbst, dcbz, or icbi
    282         *
    283         * Should make the instruction do no-op.  As it already do
    284         * no-op, it's quite easy :-)
    285         */
    286        *raddr = eaddr;
    287        return true;
    288    case ACCESS_EXT:
    289        /* eciwx or ecowx */
    290        cs->exception_index = POWERPC_EXCP_DSI;
    291        env->error_code = 0;
    292        env->spr[SPR_DAR] = eaddr;
    293        if (access_type == MMU_DATA_STORE) {
    294            env->spr[SPR_DSISR] = 0x06100000;
    295        } else {
    296            env->spr[SPR_DSISR] = 0x04100000;
    297        }
    298        return false;
    299    default:
    300        cpu_abort(cs, "ERROR: insn should not need address translation\n");
    301    }
    302
    303    *prot = key ? PAGE_READ | PAGE_WRITE : PAGE_READ;
    304    if (*prot & prot_for_access_type(access_type)) {
    305        *raddr = eaddr;
    306        return true;
    307    }
    308
    309    if (guest_visible) {
    310        cs->exception_index = POWERPC_EXCP_DSI;
    311        env->error_code = 0;
    312        env->spr[SPR_DAR] = eaddr;
    313        if (access_type == MMU_DATA_STORE) {
    314            env->spr[SPR_DSISR] = 0x0a000000;
    315        } else {
    316            env->spr[SPR_DSISR] = 0x08000000;
    317        }
    318    }
    319    return false;
    320}
    321
    322hwaddr get_pteg_offset32(PowerPCCPU *cpu, hwaddr hash)
    323{
    324    target_ulong mask = ppc_hash32_hpt_mask(cpu);
    325
    326    return (hash * HASH_PTEG_SIZE_32) & mask;
    327}
    328
    329static hwaddr ppc_hash32_pteg_search(PowerPCCPU *cpu, hwaddr pteg_off,
    330                                     bool secondary, target_ulong ptem,
    331                                     ppc_hash_pte32_t *pte)
    332{
    333    hwaddr pte_offset = pteg_off;
    334    target_ulong pte0, pte1;
    335    int i;
    336
    337    for (i = 0; i < HPTES_PER_GROUP; i++) {
    338        pte0 = ppc_hash32_load_hpte0(cpu, pte_offset);
    339        /*
    340         * pte0 contains the valid bit and must be read before pte1,
    341         * otherwise we might see an old pte1 with a new valid bit and
    342         * thus an inconsistent hpte value
    343         */
    344        smp_rmb();
    345        pte1 = ppc_hash32_load_hpte1(cpu, pte_offset);
    346
    347        if ((pte0 & HPTE32_V_VALID)
    348            && (secondary == !!(pte0 & HPTE32_V_SECONDARY))
    349            && HPTE32_V_COMPARE(pte0, ptem)) {
    350            pte->pte0 = pte0;
    351            pte->pte1 = pte1;
    352            return pte_offset;
    353        }
    354
    355        pte_offset += HASH_PTE_SIZE_32;
    356    }
    357
    358    return -1;
    359}
    360
    361static void ppc_hash32_set_r(PowerPCCPU *cpu, hwaddr pte_offset, uint32_t pte1)
    362{
    363    target_ulong base = ppc_hash32_hpt_base(cpu);
    364    hwaddr offset = pte_offset + 6;
    365
    366    /* The HW performs a non-atomic byte update */
    367    stb_phys(CPU(cpu)->as, base + offset, ((pte1 >> 8) & 0xff) | 0x01);
    368}
    369
    370static void ppc_hash32_set_c(PowerPCCPU *cpu, hwaddr pte_offset, uint64_t pte1)
    371{
    372    target_ulong base = ppc_hash32_hpt_base(cpu);
    373    hwaddr offset = pte_offset + 7;
    374
    375    /* The HW performs a non-atomic byte update */
    376    stb_phys(CPU(cpu)->as, base + offset, (pte1 & 0xff) | 0x80);
    377}
    378
    379static hwaddr ppc_hash32_htab_lookup(PowerPCCPU *cpu,
    380                                     target_ulong sr, target_ulong eaddr,
    381                                     ppc_hash_pte32_t *pte)
    382{
    383    hwaddr pteg_off, pte_offset;
    384    hwaddr hash;
    385    uint32_t vsid, pgidx, ptem;
    386
    387    vsid = sr & SR32_VSID;
    388    pgidx = (eaddr & ~SEGMENT_MASK_256M) >> TARGET_PAGE_BITS;
    389    hash = vsid ^ pgidx;
    390    ptem = (vsid << 7) | (pgidx >> 10);
    391
    392    /* Page address translation */
    393    qemu_log_mask(CPU_LOG_MMU, "htab_base " TARGET_FMT_plx
    394            " htab_mask " TARGET_FMT_plx
    395            " hash " TARGET_FMT_plx "\n",
    396            ppc_hash32_hpt_base(cpu), ppc_hash32_hpt_mask(cpu), hash);
    397
    398    /* Primary PTEG lookup */
    399    qemu_log_mask(CPU_LOG_MMU, "0 htab=" TARGET_FMT_plx "/" TARGET_FMT_plx
    400            " vsid=%" PRIx32 " ptem=%" PRIx32
    401            " hash=" TARGET_FMT_plx "\n",
    402            ppc_hash32_hpt_base(cpu), ppc_hash32_hpt_mask(cpu),
    403            vsid, ptem, hash);
    404    pteg_off = get_pteg_offset32(cpu, hash);
    405    pte_offset = ppc_hash32_pteg_search(cpu, pteg_off, 0, ptem, pte);
    406    if (pte_offset == -1) {
    407        /* Secondary PTEG lookup */
    408        qemu_log_mask(CPU_LOG_MMU, "1 htab=" TARGET_FMT_plx "/" TARGET_FMT_plx
    409                " vsid=%" PRIx32 " api=%" PRIx32
    410                " hash=" TARGET_FMT_plx "\n", ppc_hash32_hpt_base(cpu),
    411                ppc_hash32_hpt_mask(cpu), vsid, ptem, ~hash);
    412        pteg_off = get_pteg_offset32(cpu, ~hash);
    413        pte_offset = ppc_hash32_pteg_search(cpu, pteg_off, 1, ptem, pte);
    414    }
    415
    416    return pte_offset;
    417}
    418
    419static hwaddr ppc_hash32_pte_raddr(target_ulong sr, ppc_hash_pte32_t pte,
    420                                   target_ulong eaddr)
    421{
    422    hwaddr rpn = pte.pte1 & HPTE32_R_RPN;
    423    hwaddr mask = ~TARGET_PAGE_MASK;
    424
    425    return (rpn & ~mask) | (eaddr & mask);
    426}
    427
    428bool ppc_hash32_xlate(PowerPCCPU *cpu, vaddr eaddr, MMUAccessType access_type,
    429                      hwaddr *raddrp, int *psizep, int *protp, int mmu_idx,
    430                      bool guest_visible)
    431{
    432    CPUState *cs = CPU(cpu);
    433    CPUPPCState *env = &cpu->env;
    434    target_ulong sr;
    435    hwaddr pte_offset;
    436    ppc_hash_pte32_t pte;
    437    int prot;
    438    int need_prot;
    439    hwaddr raddr;
    440
    441    /* There are no hash32 large pages. */
    442    *psizep = TARGET_PAGE_BITS;
    443
    444    /* 1. Handle real mode accesses */
    445    if (mmuidx_real(mmu_idx)) {
    446        /* Translation is off */
    447        *raddrp = eaddr;
    448        *protp = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
    449        return true;
    450    }
    451
    452    need_prot = prot_for_access_type(access_type);
    453
    454    /* 2. Check Block Address Translation entries (BATs) */
    455    if (env->nb_BATs != 0) {
    456        raddr = ppc_hash32_bat_lookup(cpu, eaddr, access_type, protp, mmu_idx);
    457        if (raddr != -1) {
    458            if (need_prot & ~*protp) {
    459                if (guest_visible) {
    460                    if (access_type == MMU_INST_FETCH) {
    461                        cs->exception_index = POWERPC_EXCP_ISI;
    462                        env->error_code = 0x08000000;
    463                    } else {
    464                        cs->exception_index = POWERPC_EXCP_DSI;
    465                        env->error_code = 0;
    466                        env->spr[SPR_DAR] = eaddr;
    467                        if (access_type == MMU_DATA_STORE) {
    468                            env->spr[SPR_DSISR] = 0x0a000000;
    469                        } else {
    470                            env->spr[SPR_DSISR] = 0x08000000;
    471                        }
    472                    }
    473                }
    474                return false;
    475            }
    476            *raddrp = raddr;
    477            return true;
    478        }
    479    }
    480
    481    /* 3. Look up the Segment Register */
    482    sr = env->sr[eaddr >> 28];
    483
    484    /* 4. Handle direct store segments */
    485    if (sr & SR32_T) {
    486        return ppc_hash32_direct_store(cpu, sr, eaddr, access_type,
    487                                       raddrp, protp, mmu_idx, guest_visible);
    488    }
    489
    490    /* 5. Check for segment level no-execute violation */
    491    if (access_type == MMU_INST_FETCH && (sr & SR32_NX)) {
    492        if (guest_visible) {
    493            cs->exception_index = POWERPC_EXCP_ISI;
    494            env->error_code = 0x10000000;
    495        }
    496        return false;
    497    }
    498
    499    /* 6. Locate the PTE in the hash table */
    500    pte_offset = ppc_hash32_htab_lookup(cpu, sr, eaddr, &pte);
    501    if (pte_offset == -1) {
    502        if (guest_visible) {
    503            if (access_type == MMU_INST_FETCH) {
    504                cs->exception_index = POWERPC_EXCP_ISI;
    505                env->error_code = 0x40000000;
    506            } else {
    507                cs->exception_index = POWERPC_EXCP_DSI;
    508                env->error_code = 0;
    509                env->spr[SPR_DAR] = eaddr;
    510                if (access_type == MMU_DATA_STORE) {
    511                    env->spr[SPR_DSISR] = 0x42000000;
    512                } else {
    513                    env->spr[SPR_DSISR] = 0x40000000;
    514                }
    515            }
    516        }
    517        return false;
    518    }
    519    qemu_log_mask(CPU_LOG_MMU,
    520                "found PTE at offset %08" HWADDR_PRIx "\n", pte_offset);
    521
    522    /* 7. Check access permissions */
    523
    524    prot = ppc_hash32_pte_prot(mmu_idx, sr, pte);
    525
    526    if (need_prot & ~prot) {
    527        /* Access right violation */
    528        qemu_log_mask(CPU_LOG_MMU, "PTE access rejected\n");
    529        if (guest_visible) {
    530            if (access_type == MMU_INST_FETCH) {
    531                cs->exception_index = POWERPC_EXCP_ISI;
    532                env->error_code = 0x08000000;
    533            } else {
    534                cs->exception_index = POWERPC_EXCP_DSI;
    535                env->error_code = 0;
    536                env->spr[SPR_DAR] = eaddr;
    537                if (access_type == MMU_DATA_STORE) {
    538                    env->spr[SPR_DSISR] = 0x0a000000;
    539                } else {
    540                    env->spr[SPR_DSISR] = 0x08000000;
    541                }
    542            }
    543        }
    544        return false;
    545    }
    546
    547    qemu_log_mask(CPU_LOG_MMU, "PTE access granted !\n");
    548
    549    /* 8. Update PTE referenced and changed bits if necessary */
    550
    551    if (!(pte.pte1 & HPTE32_R_R)) {
    552        ppc_hash32_set_r(cpu, pte_offset, pte.pte1);
    553    }
    554    if (!(pte.pte1 & HPTE32_R_C)) {
    555        if (access_type == MMU_DATA_STORE) {
    556            ppc_hash32_set_c(cpu, pte_offset, pte.pte1);
    557        } else {
    558            /*
    559             * Treat the page as read-only for now, so that a later write
    560             * will pass through this function again to set the C bit
    561             */
    562            prot &= ~PAGE_WRITE;
    563        }
    564     }
    565
    566    /* 9. Determine the real address from the PTE */
    567
    568    *raddrp = ppc_hash32_pte_raddr(sr, pte, eaddr);
    569    *protp = prot;
    570    return true;
    571}