10c3e702aSMichael Clark /* 20c3e702aSMichael Clark * RISC-V Emulation Helpers for QEMU. 30c3e702aSMichael Clark * 40c3e702aSMichael Clark * Copyright (c) 2016-2017 Sagar Karandikar, sagark@eecs.berkeley.edu 50c3e702aSMichael Clark * Copyright (c) 2017-2018 SiFive, Inc. 60c3e702aSMichael Clark * 70c3e702aSMichael Clark * This program is free software; you can redistribute it and/or modify it 80c3e702aSMichael Clark * under the terms and conditions of the GNU General Public License, 90c3e702aSMichael Clark * version 2 or later, as published by the Free Software Foundation. 100c3e702aSMichael Clark * 110c3e702aSMichael Clark * This program is distributed in the hope it will be useful, but WITHOUT 120c3e702aSMichael Clark * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 130c3e702aSMichael Clark * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 140c3e702aSMichael Clark * more details. 150c3e702aSMichael Clark * 160c3e702aSMichael Clark * You should have received a copy of the GNU General Public License along with 170c3e702aSMichael Clark * this program. If not, see <http://www.gnu.org/licenses/>. 180c3e702aSMichael Clark */ 190c3e702aSMichael Clark 200c3e702aSMichael Clark #include "qemu/osdep.h" 210c3e702aSMichael Clark #include "qemu/log.h" 220c3e702aSMichael Clark #include "cpu.h" 230c3e702aSMichael Clark #include "qemu/main-loop.h" 240c3e702aSMichael Clark #include "exec/exec-all.h" 250c3e702aSMichael Clark #include "exec/helper-proto.h" 260c3e702aSMichael Clark 270c3e702aSMichael Clark /* Exceptions processing helpers */ 28fb738839SMichael Clark void QEMU_NORETURN riscv_raise_exception(CPURISCVState *env, 290c3e702aSMichael Clark uint32_t exception, uintptr_t pc) 300c3e702aSMichael Clark { 31*3109cd98SRichard Henderson CPUState *cs = env_cpu(env); 320c3e702aSMichael Clark qemu_log_mask(CPU_LOG_INT, "%s: %d\n", __func__, exception); 330c3e702aSMichael Clark cs->exception_index = exception; 340c3e702aSMichael Clark cpu_loop_exit_restore(cs, pc); 350c3e702aSMichael Clark } 360c3e702aSMichael Clark 370c3e702aSMichael Clark void helper_raise_exception(CPURISCVState *env, uint32_t exception) 380c3e702aSMichael Clark { 39fb738839SMichael Clark riscv_raise_exception(env, exception, 0); 400c3e702aSMichael Clark } 410c3e702aSMichael Clark 420c3e702aSMichael Clark target_ulong helper_csrrw(CPURISCVState *env, target_ulong src, 430c3e702aSMichael Clark target_ulong csr) 440c3e702aSMichael Clark { 45c7b95171SMichael Clark target_ulong val = 0; 46c7b95171SMichael Clark if (riscv_csrrw(env, csr, &val, src, -1) < 0) { 47fb738839SMichael Clark riscv_raise_exception(env, RISCV_EXCP_ILLEGAL_INST, GETPC()); 48c7b95171SMichael Clark } 49c7b95171SMichael Clark return val; 500c3e702aSMichael Clark } 510c3e702aSMichael Clark 520c3e702aSMichael Clark target_ulong helper_csrrs(CPURISCVState *env, target_ulong src, 530c3e702aSMichael Clark target_ulong csr, target_ulong rs1_pass) 540c3e702aSMichael Clark { 55c7b95171SMichael Clark target_ulong val = 0; 56c7b95171SMichael Clark if (riscv_csrrw(env, csr, &val, -1, rs1_pass ? src : 0) < 0) { 57fb738839SMichael Clark riscv_raise_exception(env, RISCV_EXCP_ILLEGAL_INST, GETPC()); 580c3e702aSMichael Clark } 59c7b95171SMichael Clark return val; 600c3e702aSMichael Clark } 610c3e702aSMichael Clark 620c3e702aSMichael Clark target_ulong helper_csrrc(CPURISCVState *env, target_ulong src, 630c3e702aSMichael Clark target_ulong csr, target_ulong rs1_pass) 640c3e702aSMichael Clark { 65c7b95171SMichael Clark target_ulong val = 0; 66c7b95171SMichael Clark if (riscv_csrrw(env, csr, &val, 0, rs1_pass ? src : 0) < 0) { 67fb738839SMichael Clark riscv_raise_exception(env, RISCV_EXCP_ILLEGAL_INST, GETPC()); 680c3e702aSMichael Clark } 69c7b95171SMichael Clark return val; 700c3e702aSMichael Clark } 710c3e702aSMichael Clark 720c3e702aSMichael Clark #ifndef CONFIG_USER_ONLY 730c3e702aSMichael Clark 740c3e702aSMichael Clark target_ulong helper_sret(CPURISCVState *env, target_ulong cpu_pc_deb) 750c3e702aSMichael Clark { 760c3e702aSMichael Clark if (!(env->priv >= PRV_S)) { 77fb738839SMichael Clark riscv_raise_exception(env, RISCV_EXCP_ILLEGAL_INST, GETPC()); 780c3e702aSMichael Clark } 790c3e702aSMichael Clark 800c3e702aSMichael Clark target_ulong retpc = env->sepc; 810c3e702aSMichael Clark if (!riscv_has_ext(env, RVC) && (retpc & 0x3)) { 82fb738839SMichael Clark riscv_raise_exception(env, RISCV_EXCP_INST_ADDR_MIS, GETPC()); 830c3e702aSMichael Clark } 840c3e702aSMichael Clark 857f2b5ff1SMichael Clark if (env->priv_ver >= PRIV_VERSION_1_10_0 && 867f2b5ff1SMichael Clark get_field(env->mstatus, MSTATUS_TSR)) { 87fb738839SMichael Clark riscv_raise_exception(env, RISCV_EXCP_ILLEGAL_INST, GETPC()); 887f2b5ff1SMichael Clark } 897f2b5ff1SMichael Clark 900c3e702aSMichael Clark target_ulong mstatus = env->mstatus; 910c3e702aSMichael Clark target_ulong prev_priv = get_field(mstatus, MSTATUS_SPP); 920c3e702aSMichael Clark mstatus = set_field(mstatus, 930c3e702aSMichael Clark env->priv_ver >= PRIV_VERSION_1_10_0 ? 940c3e702aSMichael Clark MSTATUS_SIE : MSTATUS_UIE << prev_priv, 950c3e702aSMichael Clark get_field(mstatus, MSTATUS_SPIE)); 960c3e702aSMichael Clark mstatus = set_field(mstatus, MSTATUS_SPIE, 0); 970c3e702aSMichael Clark mstatus = set_field(mstatus, MSTATUS_SPP, PRV_U); 98fb738839SMichael Clark riscv_cpu_set_mode(env, prev_priv); 99c7b95171SMichael Clark env->mstatus = mstatus; 1000c3e702aSMichael Clark 1010c3e702aSMichael Clark return retpc; 1020c3e702aSMichael Clark } 1030c3e702aSMichael Clark 1040c3e702aSMichael Clark target_ulong helper_mret(CPURISCVState *env, target_ulong cpu_pc_deb) 1050c3e702aSMichael Clark { 1060c3e702aSMichael Clark if (!(env->priv >= PRV_M)) { 107fb738839SMichael Clark riscv_raise_exception(env, RISCV_EXCP_ILLEGAL_INST, GETPC()); 1080c3e702aSMichael Clark } 1090c3e702aSMichael Clark 1100c3e702aSMichael Clark target_ulong retpc = env->mepc; 1110c3e702aSMichael Clark if (!riscv_has_ext(env, RVC) && (retpc & 0x3)) { 112fb738839SMichael Clark riscv_raise_exception(env, RISCV_EXCP_INST_ADDR_MIS, GETPC()); 1130c3e702aSMichael Clark } 1140c3e702aSMichael Clark 1150c3e702aSMichael Clark target_ulong mstatus = env->mstatus; 1160c3e702aSMichael Clark target_ulong prev_priv = get_field(mstatus, MSTATUS_MPP); 1170c3e702aSMichael Clark mstatus = set_field(mstatus, 1180c3e702aSMichael Clark env->priv_ver >= PRIV_VERSION_1_10_0 ? 1190c3e702aSMichael Clark MSTATUS_MIE : MSTATUS_UIE << prev_priv, 1200c3e702aSMichael Clark get_field(mstatus, MSTATUS_MPIE)); 1210c3e702aSMichael Clark mstatus = set_field(mstatus, MSTATUS_MPIE, 0); 1220c3e702aSMichael Clark mstatus = set_field(mstatus, MSTATUS_MPP, PRV_U); 123fb738839SMichael Clark riscv_cpu_set_mode(env, prev_priv); 124c7b95171SMichael Clark env->mstatus = mstatus; 1250c3e702aSMichael Clark 1260c3e702aSMichael Clark return retpc; 1270c3e702aSMichael Clark } 1280c3e702aSMichael Clark 1290c3e702aSMichael Clark void helper_wfi(CPURISCVState *env) 1300c3e702aSMichael Clark { 131*3109cd98SRichard Henderson CPUState *cs = env_cpu(env); 1320c3e702aSMichael Clark 1337f2b5ff1SMichael Clark if (env->priv == PRV_S && 1347f2b5ff1SMichael Clark env->priv_ver >= PRIV_VERSION_1_10_0 && 1357f2b5ff1SMichael Clark get_field(env->mstatus, MSTATUS_TW)) { 136fb738839SMichael Clark riscv_raise_exception(env, RISCV_EXCP_ILLEGAL_INST, GETPC()); 1377f2b5ff1SMichael Clark } else { 1380c3e702aSMichael Clark cs->halted = 1; 1390c3e702aSMichael Clark cs->exception_index = EXCP_HLT; 1400c3e702aSMichael Clark cpu_loop_exit(cs); 1410c3e702aSMichael Clark } 1427f2b5ff1SMichael Clark } 1430c3e702aSMichael Clark 1440c3e702aSMichael Clark void helper_tlb_flush(CPURISCVState *env) 1450c3e702aSMichael Clark { 146*3109cd98SRichard Henderson CPUState *cs = env_cpu(env); 147b86f4167SJonathan Behrens if (!(env->priv >= PRV_S) || 148b86f4167SJonathan Behrens (env->priv == PRV_S && 1497f2b5ff1SMichael Clark env->priv_ver >= PRIV_VERSION_1_10_0 && 150b86f4167SJonathan Behrens get_field(env->mstatus, MSTATUS_TVM))) { 151fb738839SMichael Clark riscv_raise_exception(env, RISCV_EXCP_ILLEGAL_INST, GETPC()); 1527f2b5ff1SMichael Clark } else { 1530c3e702aSMichael Clark tlb_flush(cs); 1540c3e702aSMichael Clark } 1557f2b5ff1SMichael Clark } 1560c3e702aSMichael Clark 1570c3e702aSMichael Clark #endif /* !CONFIG_USER_ONLY */ 158