qemu

FORK: QEMU emulator
git clone https://git.neptards.moe/neptards/qemu.git
Log | Files | Refs | Submodules | LICENSE

op_helper.c (9462B)


      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 */
     27 G_NORETURN void 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 
     35 void helper_raise_exception(CPURISCVState *env, uint32_t exception)
     36 {
     37     riscv_raise_exception(env, exception, 0);
     38 }
     39 
     40 target_ulong helper_csrr(CPURISCVState *env, int csr)
     41 {
     42     /*
     43      * The seed CSR must be accessed with a read-write instruction. A
     44      * read-only instruction such as CSRRS/CSRRC with rs1=x0 or CSRRSI/
     45      * CSRRCI with uimm=0 will raise an illegal instruction exception.
     46      */
     47     if (csr == CSR_SEED) {
     48         riscv_raise_exception(env, RISCV_EXCP_ILLEGAL_INST, GETPC());
     49     }
     50 
     51     target_ulong val = 0;
     52     RISCVException ret = riscv_csrrw(env, csr, &val, 0, 0);
     53 
     54     if (ret != RISCV_EXCP_NONE) {
     55         riscv_raise_exception(env, ret, GETPC());
     56     }
     57     return val;
     58 }
     59 
     60 void helper_csrw(CPURISCVState *env, int csr, target_ulong src)
     61 {
     62     target_ulong mask = env->xl == MXL_RV32 ? UINT32_MAX : (target_ulong)-1;
     63     RISCVException ret = riscv_csrrw(env, csr, NULL, src, mask);
     64 
     65     if (ret != RISCV_EXCP_NONE) {
     66         riscv_raise_exception(env, ret, GETPC());
     67     }
     68 }
     69 
     70 target_ulong helper_csrrw(CPURISCVState *env, int csr,
     71                           target_ulong src, target_ulong write_mask)
     72 {
     73     target_ulong val = 0;
     74     RISCVException ret = riscv_csrrw(env, csr, &val, src, write_mask);
     75 
     76     if (ret != RISCV_EXCP_NONE) {
     77         riscv_raise_exception(env, ret, GETPC());
     78     }
     79     return val;
     80 }
     81 
     82 target_ulong helper_csrr_i128(CPURISCVState *env, int csr)
     83 {
     84     Int128 rv = int128_zero();
     85     RISCVException ret = riscv_csrrw_i128(env, csr, &rv,
     86                                           int128_zero(),
     87                                           int128_zero());
     88 
     89     if (ret != RISCV_EXCP_NONE) {
     90         riscv_raise_exception(env, ret, GETPC());
     91     }
     92 
     93     env->retxh = int128_gethi(rv);
     94     return int128_getlo(rv);
     95 }
     96 
     97 void helper_csrw_i128(CPURISCVState *env, int csr,
     98                       target_ulong srcl, target_ulong srch)
     99 {
    100     RISCVException ret = riscv_csrrw_i128(env, csr, NULL,
    101                                           int128_make128(srcl, srch),
    102                                           UINT128_MAX);
    103 
    104     if (ret != RISCV_EXCP_NONE) {
    105         riscv_raise_exception(env, ret, GETPC());
    106     }
    107 }
    108 
    109 target_ulong helper_csrrw_i128(CPURISCVState *env, int csr,
    110                        target_ulong srcl, target_ulong srch,
    111                        target_ulong maskl, target_ulong maskh)
    112 {
    113     Int128 rv = int128_zero();
    114     RISCVException ret = riscv_csrrw_i128(env, csr, &rv,
    115                                           int128_make128(srcl, srch),
    116                                           int128_make128(maskl, maskh));
    117 
    118     if (ret != RISCV_EXCP_NONE) {
    119         riscv_raise_exception(env, ret, GETPC());
    120     }
    121 
    122     env->retxh = int128_gethi(rv);
    123     return int128_getlo(rv);
    124 }
    125 
    126 #ifndef CONFIG_USER_ONLY
    127 
    128 target_ulong helper_sret(CPURISCVState *env)
    129 {
    130     uint64_t mstatus;
    131     target_ulong prev_priv, prev_virt;
    132 
    133     if (!(env->priv >= PRV_S)) {
    134         riscv_raise_exception(env, RISCV_EXCP_ILLEGAL_INST, GETPC());
    135     }
    136 
    137     target_ulong retpc = env->sepc;
    138     if (!riscv_has_ext(env, RVC) && (retpc & 0x3)) {
    139         riscv_raise_exception(env, RISCV_EXCP_INST_ADDR_MIS, GETPC());
    140     }
    141 
    142     if (get_field(env->mstatus, MSTATUS_TSR) && !(env->priv >= PRV_M)) {
    143         riscv_raise_exception(env, RISCV_EXCP_ILLEGAL_INST, GETPC());
    144     }
    145 
    146     if (riscv_has_ext(env, RVH) && riscv_cpu_virt_enabled(env) &&
    147         get_field(env->hstatus, HSTATUS_VTSR)) {
    148         riscv_raise_exception(env, RISCV_EXCP_VIRT_INSTRUCTION_FAULT, GETPC());
    149     }
    150 
    151     mstatus = env->mstatus;
    152 
    153     if (riscv_has_ext(env, RVH) && !riscv_cpu_virt_enabled(env)) {
    154         /* We support Hypervisor extensions and virtulisation is disabled */
    155         target_ulong hstatus = env->hstatus;
    156 
    157         prev_priv = get_field(mstatus, MSTATUS_SPP);
    158         prev_virt = get_field(hstatus, HSTATUS_SPV);
    159 
    160         hstatus = set_field(hstatus, HSTATUS_SPV, 0);
    161         mstatus = set_field(mstatus, MSTATUS_SPP, 0);
    162         mstatus = set_field(mstatus, SSTATUS_SIE,
    163                             get_field(mstatus, SSTATUS_SPIE));
    164         mstatus = set_field(mstatus, SSTATUS_SPIE, 1);
    165 
    166         env->mstatus = mstatus;
    167         env->hstatus = hstatus;
    168 
    169         if (prev_virt) {
    170             riscv_cpu_swap_hypervisor_regs(env);
    171         }
    172 
    173         riscv_cpu_set_virt_enabled(env, prev_virt);
    174     } else {
    175         prev_priv = get_field(mstatus, MSTATUS_SPP);
    176 
    177         mstatus = set_field(mstatus, MSTATUS_SIE,
    178                             get_field(mstatus, MSTATUS_SPIE));
    179         mstatus = set_field(mstatus, MSTATUS_SPIE, 1);
    180         mstatus = set_field(mstatus, MSTATUS_SPP, PRV_U);
    181         env->mstatus = mstatus;
    182     }
    183 
    184     riscv_cpu_set_mode(env, prev_priv);
    185 
    186     return retpc;
    187 }
    188 
    189 target_ulong helper_mret(CPURISCVState *env)
    190 {
    191     if (!(env->priv >= PRV_M)) {
    192         riscv_raise_exception(env, RISCV_EXCP_ILLEGAL_INST, GETPC());
    193     }
    194 
    195     target_ulong retpc = env->mepc;
    196     if (!riscv_has_ext(env, RVC) && (retpc & 0x3)) {
    197         riscv_raise_exception(env, RISCV_EXCP_INST_ADDR_MIS, GETPC());
    198     }
    199 
    200     uint64_t mstatus = env->mstatus;
    201     target_ulong prev_priv = get_field(mstatus, MSTATUS_MPP);
    202 
    203     if (riscv_feature(env, RISCV_FEATURE_PMP) &&
    204         !pmp_get_num_rules(env) && (prev_priv != PRV_M)) {
    205         riscv_raise_exception(env, RISCV_EXCP_ILLEGAL_INST, GETPC());
    206     }
    207 
    208     target_ulong prev_virt = get_field(env->mstatus, MSTATUS_MPV);
    209     mstatus = set_field(mstatus, MSTATUS_MIE,
    210                         get_field(mstatus, MSTATUS_MPIE));
    211     mstatus = set_field(mstatus, MSTATUS_MPIE, 1);
    212     mstatus = set_field(mstatus, MSTATUS_MPP, PRV_U);
    213     mstatus = set_field(mstatus, MSTATUS_MPV, 0);
    214     env->mstatus = mstatus;
    215     riscv_cpu_set_mode(env, prev_priv);
    216 
    217     if (riscv_has_ext(env, RVH)) {
    218         if (prev_virt) {
    219             riscv_cpu_swap_hypervisor_regs(env);
    220         }
    221 
    222         riscv_cpu_set_virt_enabled(env, prev_virt);
    223     }
    224 
    225     return retpc;
    226 }
    227 
    228 void helper_wfi(CPURISCVState *env)
    229 {
    230     CPUState *cs = env_cpu(env);
    231     bool rvs = riscv_has_ext(env, RVS);
    232     bool prv_u = env->priv == PRV_U;
    233     bool prv_s = env->priv == PRV_S;
    234 
    235     if (((prv_s || (!rvs && prv_u)) && get_field(env->mstatus, MSTATUS_TW)) ||
    236         (rvs && prv_u && !riscv_cpu_virt_enabled(env))) {
    237         riscv_raise_exception(env, RISCV_EXCP_ILLEGAL_INST, GETPC());
    238     } else if (riscv_cpu_virt_enabled(env) && (prv_u ||
    239         (prv_s && get_field(env->hstatus, HSTATUS_VTW)))) {
    240         riscv_raise_exception(env, RISCV_EXCP_VIRT_INSTRUCTION_FAULT, GETPC());
    241     } else {
    242         cs->halted = 1;
    243         cs->exception_index = EXCP_HLT;
    244         cpu_loop_exit(cs);
    245     }
    246 }
    247 
    248 void helper_tlb_flush(CPURISCVState *env)
    249 {
    250     CPUState *cs = env_cpu(env);
    251     if (!(env->priv >= PRV_S) ||
    252         (env->priv == PRV_S &&
    253          get_field(env->mstatus, MSTATUS_TVM))) {
    254         riscv_raise_exception(env, RISCV_EXCP_ILLEGAL_INST, GETPC());
    255     } else if (riscv_has_ext(env, RVH) && riscv_cpu_virt_enabled(env) &&
    256                get_field(env->hstatus, HSTATUS_VTVM)) {
    257         riscv_raise_exception(env, RISCV_EXCP_VIRT_INSTRUCTION_FAULT, GETPC());
    258     } else {
    259         tlb_flush(cs);
    260     }
    261 }
    262 
    263 void helper_hyp_tlb_flush(CPURISCVState *env)
    264 {
    265     CPUState *cs = env_cpu(env);
    266 
    267     if (env->priv == PRV_S && riscv_cpu_virt_enabled(env)) {
    268         riscv_raise_exception(env, RISCV_EXCP_VIRT_INSTRUCTION_FAULT, GETPC());
    269     }
    270 
    271     if (env->priv == PRV_M ||
    272         (env->priv == PRV_S && !riscv_cpu_virt_enabled(env))) {
    273         tlb_flush(cs);
    274         return;
    275     }
    276 
    277     riscv_raise_exception(env, RISCV_EXCP_ILLEGAL_INST, GETPC());
    278 }
    279 
    280 void helper_hyp_gvma_tlb_flush(CPURISCVState *env)
    281 {
    282     if (env->priv == PRV_S && !riscv_cpu_virt_enabled(env) &&
    283         get_field(env->mstatus, MSTATUS_TVM)) {
    284         riscv_raise_exception(env, RISCV_EXCP_ILLEGAL_INST, GETPC());
    285     }
    286 
    287     helper_hyp_tlb_flush(env);
    288 }
    289 
    290 target_ulong helper_hyp_hlvx_hu(CPURISCVState *env, target_ulong address)
    291 {
    292     int mmu_idx = cpu_mmu_index(env, true) | TB_FLAGS_PRIV_HYP_ACCESS_MASK;
    293 
    294     return cpu_lduw_mmuidx_ra(env, address, mmu_idx, GETPC());
    295 }
    296 
    297 target_ulong helper_hyp_hlvx_wu(CPURISCVState *env, target_ulong address)
    298 {
    299     int mmu_idx = cpu_mmu_index(env, true) | TB_FLAGS_PRIV_HYP_ACCESS_MASK;
    300 
    301     return cpu_ldl_mmuidx_ra(env, address, mmu_idx, GETPC());
    302 }
    303 
    304 #endif /* !CONFIG_USER_ONLY */