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

op_helper.c (7669B)


      1/*
      2 * RISC-V Emulation Helpers for QEMU.
      3 *
      4 * Copyright (c) 2016-2017 Sagar Karandikar, sagark@eecs.berkeley.edu
      5 * Copyright (c) 2017-2018 SiFive, Inc.
      6 *
      7 * This program is free software; you can redistribute it and/or modify it
      8 * under the terms and conditions of the GNU General Public License,
      9 * version 2 or later, as published by the Free Software Foundation.
     10 *
     11 * This program is distributed in the hope it will be useful, but WITHOUT
     12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
     13 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
     14 * more details.
     15 *
     16 * You should have received a copy of the GNU General Public License along with
     17 * this program.  If not, see <http://www.gnu.org/licenses/>.
     18 */
     19
     20#include "qemu/osdep.h"
     21#include "cpu.h"
     22#include "qemu/main-loop.h"
     23#include "exec/exec-all.h"
     24#include "exec/helper-proto.h"
     25
     26/* Exceptions processing helpers */
     27void QEMU_NORETURN riscv_raise_exception(CPURISCVState *env,
     28                                          uint32_t exception, uintptr_t pc)
     29{
     30    CPUState *cs = env_cpu(env);
     31    cs->exception_index = exception;
     32    cpu_loop_exit_restore(cs, pc);
     33}
     34
     35void helper_raise_exception(CPURISCVState *env, uint32_t exception)
     36{
     37    riscv_raise_exception(env, exception, 0);
     38}
     39
     40target_ulong helper_csrr(CPURISCVState *env, int csr)
     41{
     42    target_ulong val = 0;
     43    RISCVException ret = riscv_csrrw(env, csr, &val, 0, 0);
     44
     45    if (ret != RISCV_EXCP_NONE) {
     46        riscv_raise_exception(env, ret, GETPC());
     47    }
     48    return val;
     49}
     50
     51void helper_csrw(CPURISCVState *env, int csr, target_ulong src)
     52{
     53    RISCVException ret = riscv_csrrw(env, csr, NULL, src, -1);
     54
     55    if (ret != RISCV_EXCP_NONE) {
     56        riscv_raise_exception(env, ret, GETPC());
     57    }
     58}
     59
     60target_ulong helper_csrrw(CPURISCVState *env, int csr,
     61                          target_ulong src, target_ulong write_mask)
     62{
     63    target_ulong val = 0;
     64    RISCVException ret = riscv_csrrw(env, csr, &val, src, write_mask);
     65
     66    if (ret != RISCV_EXCP_NONE) {
     67        riscv_raise_exception(env, ret, GETPC());
     68    }
     69    return val;
     70}
     71
     72#ifndef CONFIG_USER_ONLY
     73
     74target_ulong helper_sret(CPURISCVState *env, target_ulong cpu_pc_deb)
     75{
     76    uint64_t mstatus;
     77    target_ulong prev_priv, prev_virt;
     78
     79    if (!(env->priv >= PRV_S)) {
     80        riscv_raise_exception(env, RISCV_EXCP_ILLEGAL_INST, GETPC());
     81    }
     82
     83    target_ulong retpc = env->sepc;
     84    if (!riscv_has_ext(env, RVC) && (retpc & 0x3)) {
     85        riscv_raise_exception(env, RISCV_EXCP_INST_ADDR_MIS, GETPC());
     86    }
     87
     88    if (get_field(env->mstatus, MSTATUS_TSR) && !(env->priv >= PRV_M)) {
     89        riscv_raise_exception(env, RISCV_EXCP_ILLEGAL_INST, GETPC());
     90    }
     91
     92    if (riscv_has_ext(env, RVH) && riscv_cpu_virt_enabled(env) &&
     93        get_field(env->hstatus, HSTATUS_VTSR)) {
     94        riscv_raise_exception(env, RISCV_EXCP_VIRT_INSTRUCTION_FAULT, GETPC());
     95    }
     96
     97    mstatus = env->mstatus;
     98
     99    if (riscv_has_ext(env, RVH) && !riscv_cpu_virt_enabled(env)) {
    100        /* We support Hypervisor extensions and virtulisation is disabled */
    101        target_ulong hstatus = env->hstatus;
    102
    103        prev_priv = get_field(mstatus, MSTATUS_SPP);
    104        prev_virt = get_field(hstatus, HSTATUS_SPV);
    105
    106        hstatus = set_field(hstatus, HSTATUS_SPV, 0);
    107        mstatus = set_field(mstatus, MSTATUS_SPP, 0);
    108        mstatus = set_field(mstatus, SSTATUS_SIE,
    109                            get_field(mstatus, SSTATUS_SPIE));
    110        mstatus = set_field(mstatus, SSTATUS_SPIE, 1);
    111
    112        env->mstatus = mstatus;
    113        env->hstatus = hstatus;
    114
    115        if (prev_virt) {
    116            riscv_cpu_swap_hypervisor_regs(env);
    117        }
    118
    119        riscv_cpu_set_virt_enabled(env, prev_virt);
    120    } else {
    121        prev_priv = get_field(mstatus, MSTATUS_SPP);
    122
    123        mstatus = set_field(mstatus, MSTATUS_SIE,
    124                            get_field(mstatus, MSTATUS_SPIE));
    125        mstatus = set_field(mstatus, MSTATUS_SPIE, 1);
    126        mstatus = set_field(mstatus, MSTATUS_SPP, PRV_U);
    127        env->mstatus = mstatus;
    128    }
    129
    130    riscv_cpu_set_mode(env, prev_priv);
    131
    132    return retpc;
    133}
    134
    135target_ulong helper_mret(CPURISCVState *env, target_ulong cpu_pc_deb)
    136{
    137    if (!(env->priv >= PRV_M)) {
    138        riscv_raise_exception(env, RISCV_EXCP_ILLEGAL_INST, GETPC());
    139    }
    140
    141    target_ulong retpc = env->mepc;
    142    if (!riscv_has_ext(env, RVC) && (retpc & 0x3)) {
    143        riscv_raise_exception(env, RISCV_EXCP_INST_ADDR_MIS, GETPC());
    144    }
    145
    146    uint64_t mstatus = env->mstatus;
    147    target_ulong prev_priv = get_field(mstatus, MSTATUS_MPP);
    148
    149    if (!pmp_get_num_rules(env) && (prev_priv != PRV_M)) {
    150        riscv_raise_exception(env, RISCV_EXCP_ILLEGAL_INST, GETPC());
    151    }
    152
    153    target_ulong prev_virt = get_field(env->mstatus, MSTATUS_MPV);
    154    mstatus = set_field(mstatus, MSTATUS_MIE,
    155                        get_field(mstatus, MSTATUS_MPIE));
    156    mstatus = set_field(mstatus, MSTATUS_MPIE, 1);
    157    mstatus = set_field(mstatus, MSTATUS_MPP, PRV_U);
    158    mstatus = set_field(mstatus, MSTATUS_MPV, 0);
    159    env->mstatus = mstatus;
    160    riscv_cpu_set_mode(env, prev_priv);
    161
    162    if (riscv_has_ext(env, RVH)) {
    163        if (prev_virt) {
    164            riscv_cpu_swap_hypervisor_regs(env);
    165        }
    166
    167        riscv_cpu_set_virt_enabled(env, prev_virt);
    168    }
    169
    170    return retpc;
    171}
    172
    173void helper_wfi(CPURISCVState *env)
    174{
    175    CPUState *cs = env_cpu(env);
    176    bool rvs = riscv_has_ext(env, RVS);
    177    bool prv_u = env->priv == PRV_U;
    178    bool prv_s = env->priv == PRV_S;
    179
    180    if (((prv_s || (!rvs && prv_u)) && get_field(env->mstatus, MSTATUS_TW)) ||
    181        (rvs && prv_u && !riscv_cpu_virt_enabled(env))) {
    182        riscv_raise_exception(env, RISCV_EXCP_ILLEGAL_INST, GETPC());
    183    } else if (riscv_cpu_virt_enabled(env) && (prv_u ||
    184        (prv_s && get_field(env->hstatus, HSTATUS_VTW)))) {
    185        riscv_raise_exception(env, RISCV_EXCP_VIRT_INSTRUCTION_FAULT, GETPC());
    186    } else {
    187        cs->halted = 1;
    188        cs->exception_index = EXCP_HLT;
    189        cpu_loop_exit(cs);
    190    }
    191}
    192
    193void helper_tlb_flush(CPURISCVState *env)
    194{
    195    CPUState *cs = env_cpu(env);
    196    if (!(env->priv >= PRV_S) ||
    197        (env->priv == PRV_S &&
    198         get_field(env->mstatus, MSTATUS_TVM))) {
    199        riscv_raise_exception(env, RISCV_EXCP_ILLEGAL_INST, GETPC());
    200    } else if (riscv_has_ext(env, RVH) && riscv_cpu_virt_enabled(env) &&
    201               get_field(env->hstatus, HSTATUS_VTVM)) {
    202        riscv_raise_exception(env, RISCV_EXCP_VIRT_INSTRUCTION_FAULT, GETPC());
    203    } else {
    204        tlb_flush(cs);
    205    }
    206}
    207
    208void helper_hyp_tlb_flush(CPURISCVState *env)
    209{
    210    CPUState *cs = env_cpu(env);
    211
    212    if (env->priv == PRV_S && riscv_cpu_virt_enabled(env)) {
    213        riscv_raise_exception(env, RISCV_EXCP_VIRT_INSTRUCTION_FAULT, GETPC());
    214    }
    215
    216    if (env->priv == PRV_M ||
    217        (env->priv == PRV_S && !riscv_cpu_virt_enabled(env))) {
    218        tlb_flush(cs);
    219        return;
    220    }
    221
    222    riscv_raise_exception(env, RISCV_EXCP_ILLEGAL_INST, GETPC());
    223}
    224
    225void helper_hyp_gvma_tlb_flush(CPURISCVState *env)
    226{
    227    if (env->priv == PRV_S && !riscv_cpu_virt_enabled(env) &&
    228        get_field(env->mstatus, MSTATUS_TVM)) {
    229        riscv_raise_exception(env, RISCV_EXCP_ILLEGAL_INST, GETPC());
    230    }
    231
    232    helper_hyp_tlb_flush(env);
    233}
    234
    235target_ulong helper_hyp_hlvx_hu(CPURISCVState *env, target_ulong address)
    236{
    237    int mmu_idx = cpu_mmu_index(env, true) | TB_FLAGS_PRIV_HYP_ACCESS_MASK;
    238
    239    return cpu_lduw_mmuidx_ra(env, address, mmu_idx, GETPC());
    240}
    241
    242target_ulong helper_hyp_hlvx_wu(CPURISCVState *env, target_ulong address)
    243{
    244    int mmu_idx = cpu_mmu_index(env, true) | TB_FLAGS_PRIV_HYP_ACCESS_MASK;
    245
    246    return cpu_ldl_mmuidx_ra(env, address, mmu_idx, GETPC());
    247}
    248
    249#endif /* !CONFIG_USER_ONLY */