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-radix64.c (19901B)


      1/*
      2 *  PowerPC Radix MMU mulation helpers for QEMU.
      3 *
      4 *  Copyright (c) 2016 Suraj Jitindar Singh, IBM Corporation
      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 "cpu.h"
     22#include "exec/exec-all.h"
     23#include "qemu/error-report.h"
     24#include "sysemu/kvm.h"
     25#include "kvm_ppc.h"
     26#include "exec/log.h"
     27#include "internal.h"
     28#include "mmu-radix64.h"
     29#include "mmu-book3s-v3.h"
     30
     31static bool ppc_radix64_get_fully_qualified_addr(const CPUPPCState *env,
     32                                                 vaddr eaddr,
     33                                                 uint64_t *lpid, uint64_t *pid)
     34{
     35    if (msr_hv) { /* MSR[HV] -> Hypervisor/bare metal */
     36        switch (eaddr & R_EADDR_QUADRANT) {
     37        case R_EADDR_QUADRANT0:
     38            *lpid = 0;
     39            *pid = env->spr[SPR_BOOKS_PID];
     40            break;
     41        case R_EADDR_QUADRANT1:
     42            *lpid = env->spr[SPR_LPIDR];
     43            *pid = env->spr[SPR_BOOKS_PID];
     44            break;
     45        case R_EADDR_QUADRANT2:
     46            *lpid = env->spr[SPR_LPIDR];
     47            *pid = 0;
     48            break;
     49        case R_EADDR_QUADRANT3:
     50            *lpid = 0;
     51            *pid = 0;
     52            break;
     53        default:
     54            g_assert_not_reached();
     55        }
     56    } else {  /* !MSR[HV] -> Guest */
     57        switch (eaddr & R_EADDR_QUADRANT) {
     58        case R_EADDR_QUADRANT0: /* Guest application */
     59            *lpid = env->spr[SPR_LPIDR];
     60            *pid = env->spr[SPR_BOOKS_PID];
     61            break;
     62        case R_EADDR_QUADRANT1: /* Illegal */
     63        case R_EADDR_QUADRANT2:
     64            return false;
     65        case R_EADDR_QUADRANT3: /* Guest OS */
     66            *lpid = env->spr[SPR_LPIDR];
     67            *pid = 0; /* pid set to 0 -> addresses guest operating system */
     68            break;
     69        default:
     70            g_assert_not_reached();
     71        }
     72    }
     73
     74    return true;
     75}
     76
     77static void ppc_radix64_raise_segi(PowerPCCPU *cpu, MMUAccessType access_type,
     78                                   vaddr eaddr)
     79{
     80    CPUState *cs = CPU(cpu);
     81    CPUPPCState *env = &cpu->env;
     82
     83    switch (access_type) {
     84    case MMU_INST_FETCH:
     85        /* Instruction Segment Interrupt */
     86        cs->exception_index = POWERPC_EXCP_ISEG;
     87        break;
     88    case MMU_DATA_STORE:
     89    case MMU_DATA_LOAD:
     90        /* Data Segment Interrupt */
     91        cs->exception_index = POWERPC_EXCP_DSEG;
     92        env->spr[SPR_DAR] = eaddr;
     93        break;
     94    default:
     95        g_assert_not_reached();
     96    }
     97    env->error_code = 0;
     98}
     99
    100static void ppc_radix64_raise_si(PowerPCCPU *cpu, MMUAccessType access_type,
    101                                 vaddr eaddr, uint32_t cause)
    102{
    103    CPUState *cs = CPU(cpu);
    104    CPUPPCState *env = &cpu->env;
    105
    106    switch (access_type) {
    107    case MMU_INST_FETCH:
    108        /* Instruction Storage Interrupt */
    109        cs->exception_index = POWERPC_EXCP_ISI;
    110        env->error_code = cause;
    111        break;
    112    case MMU_DATA_STORE:
    113        cause |= DSISR_ISSTORE;
    114        /* fall through */
    115    case MMU_DATA_LOAD:
    116        /* Data Storage Interrupt */
    117        cs->exception_index = POWERPC_EXCP_DSI;
    118        env->spr[SPR_DSISR] = cause;
    119        env->spr[SPR_DAR] = eaddr;
    120        env->error_code = 0;
    121        break;
    122    default:
    123        g_assert_not_reached();
    124    }
    125}
    126
    127static void ppc_radix64_raise_hsi(PowerPCCPU *cpu, MMUAccessType access_type,
    128                                  vaddr eaddr, hwaddr g_raddr, uint32_t cause)
    129{
    130    CPUState *cs = CPU(cpu);
    131    CPUPPCState *env = &cpu->env;
    132
    133    switch (access_type) {
    134    case MMU_INST_FETCH:
    135        /* H Instruction Storage Interrupt */
    136        cs->exception_index = POWERPC_EXCP_HISI;
    137        env->spr[SPR_ASDR] = g_raddr;
    138        env->error_code = cause;
    139        break;
    140    case MMU_DATA_STORE:
    141        cause |= DSISR_ISSTORE;
    142        /* fall through */
    143    case MMU_DATA_LOAD:
    144        /* H Data Storage Interrupt */
    145        cs->exception_index = POWERPC_EXCP_HDSI;
    146        env->spr[SPR_HDSISR] = cause;
    147        env->spr[SPR_HDAR] = eaddr;
    148        env->spr[SPR_ASDR] = g_raddr;
    149        env->error_code = 0;
    150        break;
    151    default:
    152        g_assert_not_reached();
    153    }
    154}
    155
    156static bool ppc_radix64_check_prot(PowerPCCPU *cpu, MMUAccessType access_type,
    157                                   uint64_t pte, int *fault_cause, int *prot,
    158                                   int mmu_idx, bool partition_scoped)
    159{
    160    CPUPPCState *env = &cpu->env;
    161    int need_prot;
    162
    163    /* Check Page Attributes (pte58:59) */
    164    if ((pte & R_PTE_ATT) == R_PTE_ATT_NI_IO && access_type == MMU_INST_FETCH) {
    165        /*
    166         * Radix PTE entries with the non-idempotent I/O attribute are treated
    167         * as guarded storage
    168         */
    169        *fault_cause |= SRR1_NOEXEC_GUARD;
    170        return true;
    171    }
    172
    173    /* Determine permissions allowed by Encoded Access Authority */
    174    if (!partition_scoped && (pte & R_PTE_EAA_PRIV) && msr_pr) {
    175        *prot = 0;
    176    } else if (mmuidx_pr(mmu_idx) || (pte & R_PTE_EAA_PRIV) ||
    177               partition_scoped) {
    178        *prot = ppc_radix64_get_prot_eaa(pte);
    179    } else { /* !msr_pr && !(pte & R_PTE_EAA_PRIV) && !partition_scoped */
    180        *prot = ppc_radix64_get_prot_eaa(pte);
    181        *prot &= ppc_radix64_get_prot_amr(cpu); /* Least combined permissions */
    182    }
    183
    184    /* Check if requested access type is allowed */
    185    need_prot = prot_for_access_type(access_type);
    186    if (need_prot & ~*prot) { /* Page Protected for that Access */
    187        *fault_cause |= DSISR_PROTFAULT;
    188        return true;
    189    }
    190
    191    return false;
    192}
    193
    194static void ppc_radix64_set_rc(PowerPCCPU *cpu, MMUAccessType access_type,
    195                               uint64_t pte, hwaddr pte_addr, int *prot)
    196{
    197    CPUState *cs = CPU(cpu);
    198    uint64_t npte;
    199
    200    npte = pte | R_PTE_R; /* Always set reference bit */
    201
    202    if (access_type == MMU_DATA_STORE) { /* Store/Write */
    203        npte |= R_PTE_C; /* Set change bit */
    204    } else {
    205        /*
    206         * Treat the page as read-only for now, so that a later write
    207         * will pass through this function again to set the C bit.
    208         */
    209        *prot &= ~PAGE_WRITE;
    210    }
    211
    212    if (pte ^ npte) { /* If pte has changed then write it back */
    213        stq_phys(cs->as, pte_addr, npte);
    214    }
    215}
    216
    217static int ppc_radix64_next_level(AddressSpace *as, vaddr eaddr,
    218                                  uint64_t *pte_addr, uint64_t *nls,
    219                                  int *psize, uint64_t *pte, int *fault_cause)
    220{
    221    uint64_t index, pde;
    222
    223    if (*nls < 5) { /* Directory maps less than 2**5 entries */
    224        *fault_cause |= DSISR_R_BADCONFIG;
    225        return 1;
    226    }
    227
    228    /* Read page <directory/table> entry from guest address space */
    229    pde = ldq_phys(as, *pte_addr);
    230    if (!(pde & R_PTE_VALID)) {         /* Invalid Entry */
    231        *fault_cause |= DSISR_NOPTE;
    232        return 1;
    233    }
    234
    235    *pte = pde;
    236    *psize -= *nls;
    237    if (!(pde & R_PTE_LEAF)) { /* Prepare for next iteration */
    238        *nls = pde & R_PDE_NLS;
    239        index = eaddr >> (*psize - *nls);       /* Shift */
    240        index &= ((1UL << *nls) - 1);           /* Mask */
    241        *pte_addr = (pde & R_PDE_NLB) + (index * sizeof(pde));
    242    }
    243    return 0;
    244}
    245
    246static int ppc_radix64_walk_tree(AddressSpace *as, vaddr eaddr,
    247                                 uint64_t base_addr, uint64_t nls,
    248                                 hwaddr *raddr, int *psize, uint64_t *pte,
    249                                 int *fault_cause, hwaddr *pte_addr)
    250{
    251    uint64_t index, pde, rpn , mask;
    252
    253    if (nls < 5) { /* Directory maps less than 2**5 entries */
    254        *fault_cause |= DSISR_R_BADCONFIG;
    255        return 1;
    256    }
    257
    258    index = eaddr >> (*psize - nls);    /* Shift */
    259    index &= ((1UL << nls) - 1);       /* Mask */
    260    *pte_addr = base_addr + (index * sizeof(pde));
    261    do {
    262        int ret;
    263
    264        ret = ppc_radix64_next_level(as, eaddr, pte_addr, &nls, psize, &pde,
    265                                     fault_cause);
    266        if (ret) {
    267            return ret;
    268        }
    269    } while (!(pde & R_PTE_LEAF));
    270
    271    *pte = pde;
    272    rpn = pde & R_PTE_RPN;
    273    mask = (1UL << *psize) - 1;
    274
    275    /* Or high bits of rpn and low bits to ea to form whole real addr */
    276    *raddr = (rpn & ~mask) | (eaddr & mask);
    277    return 0;
    278}
    279
    280static bool validate_pate(PowerPCCPU *cpu, uint64_t lpid, ppc_v3_pate_t *pate)
    281{
    282    CPUPPCState *env = &cpu->env;
    283
    284    if (!(pate->dw0 & PATE0_HR)) {
    285        return false;
    286    }
    287    if (lpid == 0 && !msr_hv) {
    288        return false;
    289    }
    290    if ((pate->dw0 & PATE1_R_PRTS) < 5) {
    291        return false;
    292    }
    293    /* More checks ... */
    294    return true;
    295}
    296
    297static int ppc_radix64_partition_scoped_xlate(PowerPCCPU *cpu,
    298                                              MMUAccessType access_type,
    299                                              vaddr eaddr, hwaddr g_raddr,
    300                                              ppc_v3_pate_t pate,
    301                                              hwaddr *h_raddr, int *h_prot,
    302                                              int *h_page_size, bool pde_addr,
    303                                              int mmu_idx, bool guest_visible)
    304{
    305    int fault_cause = 0;
    306    hwaddr pte_addr;
    307    uint64_t pte;
    308
    309    *h_page_size = PRTBE_R_GET_RTS(pate.dw0);
    310    /* No valid pte or access denied due to protection */
    311    if (ppc_radix64_walk_tree(CPU(cpu)->as, g_raddr, pate.dw0 & PRTBE_R_RPDB,
    312                              pate.dw0 & PRTBE_R_RPDS, h_raddr, h_page_size,
    313                              &pte, &fault_cause, &pte_addr) ||
    314        ppc_radix64_check_prot(cpu, access_type, pte,
    315                               &fault_cause, h_prot, mmu_idx, true)) {
    316        if (pde_addr) { /* address being translated was that of a guest pde */
    317            fault_cause |= DSISR_PRTABLE_FAULT;
    318        }
    319        if (guest_visible) {
    320            ppc_radix64_raise_hsi(cpu, access_type, eaddr, g_raddr, fault_cause);
    321        }
    322        return 1;
    323    }
    324
    325    if (guest_visible) {
    326        ppc_radix64_set_rc(cpu, access_type, pte, pte_addr, h_prot);
    327    }
    328
    329    return 0;
    330}
    331
    332static int ppc_radix64_process_scoped_xlate(PowerPCCPU *cpu,
    333                                            MMUAccessType access_type,
    334                                            vaddr eaddr, uint64_t pid,
    335                                            ppc_v3_pate_t pate, hwaddr *g_raddr,
    336                                            int *g_prot, int *g_page_size,
    337                                            int mmu_idx, bool guest_visible)
    338{
    339    CPUState *cs = CPU(cpu);
    340    CPUPPCState *env = &cpu->env;
    341    uint64_t offset, size, prtbe_addr, prtbe0, base_addr, nls, index, pte;
    342    int fault_cause = 0, h_page_size, h_prot;
    343    hwaddr h_raddr, pte_addr;
    344    int ret;
    345
    346    /* Index Process Table by PID to Find Corresponding Process Table Entry */
    347    offset = pid * sizeof(struct prtb_entry);
    348    size = 1ULL << ((pate.dw1 & PATE1_R_PRTS) + 12);
    349    if (offset >= size) {
    350        /* offset exceeds size of the process table */
    351        if (guest_visible) {
    352            ppc_radix64_raise_si(cpu, access_type, eaddr, DSISR_NOPTE);
    353        }
    354        return 1;
    355    }
    356    prtbe_addr = (pate.dw1 & PATE1_R_PRTB) + offset;
    357
    358    if (cpu->vhyp) {
    359        prtbe0 = ldq_phys(cs->as, prtbe_addr);
    360    } else {
    361        /*
    362         * Process table addresses are subject to partition-scoped
    363         * translation
    364         *
    365         * On a Radix host, the partition-scoped page table for LPID=0
    366         * is only used to translate the effective addresses of the
    367         * process table entries.
    368         */
    369        ret = ppc_radix64_partition_scoped_xlate(cpu, 0, eaddr, prtbe_addr,
    370                                                 pate, &h_raddr, &h_prot,
    371                                                 &h_page_size, true,
    372            /* mmu_idx is 5 because we're translating from hypervisor scope */
    373                                                 5, guest_visible);
    374        if (ret) {
    375            return ret;
    376        }
    377        prtbe0 = ldq_phys(cs->as, h_raddr);
    378    }
    379
    380    /* Walk Radix Tree from Process Table Entry to Convert EA to RA */
    381    *g_page_size = PRTBE_R_GET_RTS(prtbe0);
    382    base_addr = prtbe0 & PRTBE_R_RPDB;
    383    nls = prtbe0 & PRTBE_R_RPDS;
    384    if (msr_hv || cpu->vhyp) {
    385        /*
    386         * Can treat process table addresses as real addresses
    387         */
    388        ret = ppc_radix64_walk_tree(cs->as, eaddr & R_EADDR_MASK, base_addr,
    389                                    nls, g_raddr, g_page_size, &pte,
    390                                    &fault_cause, &pte_addr);
    391        if (ret) {
    392            /* No valid PTE */
    393            if (guest_visible) {
    394                ppc_radix64_raise_si(cpu, access_type, eaddr, fault_cause);
    395            }
    396            return ret;
    397        }
    398    } else {
    399        uint64_t rpn, mask;
    400
    401        index = (eaddr & R_EADDR_MASK) >> (*g_page_size - nls); /* Shift */
    402        index &= ((1UL << nls) - 1);                            /* Mask */
    403        pte_addr = base_addr + (index * sizeof(pte));
    404
    405        /*
    406         * Each process table address is subject to a partition-scoped
    407         * translation
    408         */
    409        do {
    410            ret = ppc_radix64_partition_scoped_xlate(cpu, 0, eaddr, pte_addr,
    411                                                     pate, &h_raddr, &h_prot,
    412                                                     &h_page_size, true,
    413            /* mmu_idx is 5 because we're translating from hypervisor scope */
    414                                                     5, guest_visible);
    415            if (ret) {
    416                return ret;
    417            }
    418
    419            ret = ppc_radix64_next_level(cs->as, eaddr & R_EADDR_MASK, &h_raddr,
    420                                         &nls, g_page_size, &pte, &fault_cause);
    421            if (ret) {
    422                /* No valid pte */
    423                if (guest_visible) {
    424                    ppc_radix64_raise_si(cpu, access_type, eaddr, fault_cause);
    425                }
    426                return ret;
    427            }
    428            pte_addr = h_raddr;
    429        } while (!(pte & R_PTE_LEAF));
    430
    431        rpn = pte & R_PTE_RPN;
    432        mask = (1UL << *g_page_size) - 1;
    433
    434        /* Or high bits of rpn and low bits to ea to form whole real addr */
    435        *g_raddr = (rpn & ~mask) | (eaddr & mask);
    436    }
    437
    438    if (ppc_radix64_check_prot(cpu, access_type, pte, &fault_cause,
    439                               g_prot, mmu_idx, false)) {
    440        /* Access denied due to protection */
    441        if (guest_visible) {
    442            ppc_radix64_raise_si(cpu, access_type, eaddr, fault_cause);
    443        }
    444        return 1;
    445    }
    446
    447    if (guest_visible) {
    448        ppc_radix64_set_rc(cpu, access_type, pte, pte_addr, g_prot);
    449    }
    450
    451    return 0;
    452}
    453
    454/*
    455 * Radix tree translation is a 2 steps translation process:
    456 *
    457 * 1. Process-scoped translation:   Guest Eff Addr  -> Guest Real Addr
    458 * 2. Partition-scoped translation: Guest Real Addr -> Host Real Addr
    459 *
    460 *                                  MSR[HV]
    461 *              +-------------+----------------+---------------+
    462 *              |             |     HV = 0     |     HV = 1    |
    463 *              +-------------+----------------+---------------+
    464 *              | Relocation  |    Partition   |      No       |
    465 *              | = Off       |     Scoped     |  Translation  |
    466 *  Relocation  +-------------+----------------+---------------+
    467 *              | Relocation  |   Partition &  |    Process    |
    468 *              | = On        | Process Scoped |    Scoped     |
    469 *              +-------------+----------------+---------------+
    470 */
    471bool ppc_radix64_xlate(PowerPCCPU *cpu, vaddr eaddr, MMUAccessType access_type,
    472                       hwaddr *raddr, int *psizep, int *protp, int mmu_idx,
    473                       bool guest_visible)
    474{
    475    CPUPPCState *env = &cpu->env;
    476    uint64_t lpid, pid;
    477    ppc_v3_pate_t pate;
    478    int psize, prot;
    479    hwaddr g_raddr;
    480    bool relocation;
    481
    482    assert(!(mmuidx_hv(mmu_idx) && cpu->vhyp));
    483
    484    relocation = !mmuidx_real(mmu_idx);
    485
    486    /* HV or virtual hypervisor Real Mode Access */
    487    if (!relocation && (mmuidx_hv(mmu_idx) || cpu->vhyp)) {
    488        /* In real mode top 4 effective addr bits (mostly) ignored */
    489        *raddr = eaddr & 0x0FFFFFFFFFFFFFFFULL;
    490
    491        /* In HV mode, add HRMOR if top EA bit is clear */
    492        if (mmuidx_hv(mmu_idx) || !env->has_hv_mode) {
    493            if (!(eaddr >> 63)) {
    494                *raddr |= env->spr[SPR_HRMOR];
    495           }
    496        }
    497        *protp = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
    498        *psizep = TARGET_PAGE_BITS;
    499        return true;
    500    }
    501
    502    /*
    503     * Check UPRT (we avoid the check in real mode to deal with
    504     * transitional states during kexec.
    505     */
    506    if (guest_visible && !ppc64_use_proc_tbl(cpu)) {
    507        qemu_log_mask(LOG_GUEST_ERROR,
    508                      "LPCR:UPRT not set in radix mode ! LPCR="
    509                      TARGET_FMT_lx "\n", env->spr[SPR_LPCR]);
    510    }
    511
    512    /* Virtual Mode Access - get the fully qualified address */
    513    if (!ppc_radix64_get_fully_qualified_addr(&cpu->env, eaddr, &lpid, &pid)) {
    514        if (guest_visible) {
    515            ppc_radix64_raise_segi(cpu, access_type, eaddr);
    516        }
    517        return false;
    518    }
    519
    520    /* Get Process Table */
    521    if (cpu->vhyp) {
    522        PPCVirtualHypervisorClass *vhc;
    523        vhc = PPC_VIRTUAL_HYPERVISOR_GET_CLASS(cpu->vhyp);
    524        vhc->get_pate(cpu->vhyp, &pate);
    525    } else {
    526        if (!ppc64_v3_get_pate(cpu, lpid, &pate)) {
    527            if (guest_visible) {
    528                ppc_radix64_raise_si(cpu, access_type, eaddr, DSISR_NOPTE);
    529            }
    530            return false;
    531        }
    532        if (!validate_pate(cpu, lpid, &pate)) {
    533            if (guest_visible) {
    534                ppc_radix64_raise_si(cpu, access_type, eaddr, DSISR_R_BADCONFIG);
    535            }
    536            return false;
    537        }
    538    }
    539
    540    *psizep = INT_MAX;
    541    *protp = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
    542
    543    /*
    544     * Perform process-scoped translation if relocation enabled.
    545     *
    546     * - Translates an effective address to a host real address in
    547     *   quadrants 0 and 3 when HV=1.
    548     *
    549     * - Translates an effective address to a guest real address.
    550     */
    551    if (relocation) {
    552        int ret = ppc_radix64_process_scoped_xlate(cpu, access_type, eaddr, pid,
    553                                                   pate, &g_raddr, &prot,
    554                                                   &psize, mmu_idx, guest_visible);
    555        if (ret) {
    556            return false;
    557        }
    558        *psizep = MIN(*psizep, psize);
    559        *protp &= prot;
    560    } else {
    561        g_raddr = eaddr & R_EADDR_MASK;
    562    }
    563
    564    if (cpu->vhyp) {
    565        *raddr = g_raddr;
    566    } else {
    567        /*
    568         * Perform partition-scoped translation if !HV or HV access to
    569         * quadrants 1 or 2. Translates a guest real address to a host
    570         * real address.
    571         */
    572        if (lpid || !mmuidx_hv(mmu_idx)) {
    573            int ret;
    574
    575            ret = ppc_radix64_partition_scoped_xlate(cpu, access_type, eaddr,
    576                                                     g_raddr, pate, raddr,
    577                                                     &prot, &psize, false,
    578                                                     mmu_idx, guest_visible);
    579            if (ret) {
    580                return false;
    581            }
    582            *psizep = MIN(*psizep, psize);
    583            *protp &= prot;
    584        } else {
    585            *raddr = g_raddr;
    586        }
    587    }
    588
    589    return true;
    590}