1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
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
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_csrrw(CPURISCVState *env, target_ulong src,
41 target_ulong csr)
42{
43 target_ulong val = 0;
44 RISCVException ret = riscv_csrrw(env, csr, &val, src, -1);
45
46 if (ret != RISCV_EXCP_NONE) {
47 riscv_raise_exception(env, ret, GETPC());
48 }
49 return val;
50}
51
52target_ulong helper_csrrs(CPURISCVState *env, target_ulong src,
53 target_ulong csr, target_ulong rs1_pass)
54{
55 target_ulong val = 0;
56 RISCVException ret = riscv_csrrw(env, csr, &val, -1, rs1_pass ? src : 0);
57
58 if (ret != RISCV_EXCP_NONE) {
59 riscv_raise_exception(env, ret, GETPC());
60 }
61 return val;
62}
63
64target_ulong helper_csrrc(CPURISCVState *env, target_ulong src,
65 target_ulong csr, target_ulong rs1_pass)
66{
67 target_ulong val = 0;
68 RISCVException ret = riscv_csrrw(env, csr, &val, 0, rs1_pass ? src : 0);
69
70 if (ret != RISCV_EXCP_NONE) {
71 riscv_raise_exception(env, ret, GETPC());
72 }
73 return val;
74}
75
76#ifndef CONFIG_USER_ONLY
77
78target_ulong helper_sret(CPURISCVState *env, target_ulong cpu_pc_deb)
79{
80 uint64_t mstatus;
81 target_ulong prev_priv, prev_virt;
82
83 if (!(env->priv >= PRV_S)) {
84 riscv_raise_exception(env, RISCV_EXCP_ILLEGAL_INST, GETPC());
85 }
86
87 target_ulong retpc = env->sepc;
88 if (!riscv_has_ext(env, RVC) && (retpc & 0x3)) {
89 riscv_raise_exception(env, RISCV_EXCP_INST_ADDR_MIS, GETPC());
90 }
91
92 if (get_field(env->mstatus, MSTATUS_TSR) && !(env->priv >= PRV_M)) {
93 riscv_raise_exception(env, RISCV_EXCP_ILLEGAL_INST, GETPC());
94 }
95
96 if (riscv_has_ext(env, RVH) && riscv_cpu_virt_enabled(env) &&
97 get_field(env->hstatus, HSTATUS_VTSR)) {
98 riscv_raise_exception(env, RISCV_EXCP_VIRT_INSTRUCTION_FAULT, GETPC());
99 }
100
101 mstatus = env->mstatus;
102
103 if (riscv_has_ext(env, RVH) && !riscv_cpu_virt_enabled(env)) {
104
105 target_ulong hstatus = env->hstatus;
106
107 prev_priv = get_field(mstatus, MSTATUS_SPP);
108 prev_virt = get_field(hstatus, HSTATUS_SPV);
109
110 hstatus = set_field(hstatus, HSTATUS_SPV, 0);
111 mstatus = set_field(mstatus, MSTATUS_SPP, 0);
112 mstatus = set_field(mstatus, SSTATUS_SIE,
113 get_field(mstatus, SSTATUS_SPIE));
114 mstatus = set_field(mstatus, SSTATUS_SPIE, 1);
115
116 env->mstatus = mstatus;
117 env->hstatus = hstatus;
118
119 if (prev_virt) {
120 riscv_cpu_swap_hypervisor_regs(env);
121 }
122
123 riscv_cpu_set_virt_enabled(env, prev_virt);
124 } else {
125 prev_priv = get_field(mstatus, MSTATUS_SPP);
126
127 mstatus = set_field(mstatus, MSTATUS_SIE,
128 get_field(mstatus, MSTATUS_SPIE));
129 mstatus = set_field(mstatus, MSTATUS_SPIE, 1);
130 mstatus = set_field(mstatus, MSTATUS_SPP, PRV_U);
131 env->mstatus = mstatus;
132 }
133
134 riscv_cpu_set_mode(env, prev_priv);
135
136 return retpc;
137}
138
139target_ulong helper_mret(CPURISCVState *env, target_ulong cpu_pc_deb)
140{
141 if (!(env->priv >= PRV_M)) {
142 riscv_raise_exception(env, RISCV_EXCP_ILLEGAL_INST, GETPC());
143 }
144
145 target_ulong retpc = env->mepc;
146 if (!riscv_has_ext(env, RVC) && (retpc & 0x3)) {
147 riscv_raise_exception(env, RISCV_EXCP_INST_ADDR_MIS, GETPC());
148 }
149
150 uint64_t mstatus = env->mstatus;
151 target_ulong prev_priv = get_field(mstatus, MSTATUS_MPP);
152
153 if (!pmp_get_num_rules(env) && (prev_priv != PRV_M)) {
154 riscv_raise_exception(env, RISCV_EXCP_ILLEGAL_INST, GETPC());
155 }
156
157 target_ulong prev_virt = get_field(env->mstatus, MSTATUS_MPV);
158 mstatus = set_field(mstatus, MSTATUS_MIE,
159 get_field(mstatus, MSTATUS_MPIE));
160 mstatus = set_field(mstatus, MSTATUS_MPIE, 1);
161 mstatus = set_field(mstatus, MSTATUS_MPP, PRV_U);
162 mstatus = set_field(mstatus, MSTATUS_MPV, 0);
163 env->mstatus = mstatus;
164 riscv_cpu_set_mode(env, prev_priv);
165
166 if (riscv_has_ext(env, RVH)) {
167 if (prev_virt) {
168 riscv_cpu_swap_hypervisor_regs(env);
169 }
170
171 riscv_cpu_set_virt_enabled(env, prev_virt);
172 }
173
174 return retpc;
175}
176
177void helper_wfi(CPURISCVState *env)
178{
179 CPUState *cs = env_cpu(env);
180 bool rvs = riscv_has_ext(env, RVS);
181 bool prv_u = env->priv == PRV_U;
182 bool prv_s = env->priv == PRV_S;
183
184 if (((prv_s || (!rvs && prv_u)) && get_field(env->mstatus, MSTATUS_TW)) ||
185 (rvs && prv_u && !riscv_cpu_virt_enabled(env))) {
186 riscv_raise_exception(env, RISCV_EXCP_ILLEGAL_INST, GETPC());
187 } else if (riscv_cpu_virt_enabled(env) && (prv_u ||
188 (prv_s && get_field(env->hstatus, HSTATUS_VTW)))) {
189 riscv_raise_exception(env, RISCV_EXCP_VIRT_INSTRUCTION_FAULT, GETPC());
190 } else {
191 cs->halted = 1;
192 cs->exception_index = EXCP_HLT;
193 cpu_loop_exit(cs);
194 }
195}
196
197void helper_tlb_flush(CPURISCVState *env)
198{
199 CPUState *cs = env_cpu(env);
200 if (!(env->priv >= PRV_S) ||
201 (env->priv == PRV_S &&
202 get_field(env->mstatus, MSTATUS_TVM))) {
203 riscv_raise_exception(env, RISCV_EXCP_ILLEGAL_INST, GETPC());
204 } else if (riscv_has_ext(env, RVH) && riscv_cpu_virt_enabled(env) &&
205 get_field(env->hstatus, HSTATUS_VTVM)) {
206 riscv_raise_exception(env, RISCV_EXCP_VIRT_INSTRUCTION_FAULT, GETPC());
207 } else {
208 tlb_flush(cs);
209 }
210}
211
212void helper_hyp_tlb_flush(CPURISCVState *env)
213{
214 CPUState *cs = env_cpu(env);
215
216 if (env->priv == PRV_S && riscv_cpu_virt_enabled(env)) {
217 riscv_raise_exception(env, RISCV_EXCP_VIRT_INSTRUCTION_FAULT, GETPC());
218 }
219
220 if (env->priv == PRV_M ||
221 (env->priv == PRV_S && !riscv_cpu_virt_enabled(env))) {
222 tlb_flush(cs);
223 return;
224 }
225
226 riscv_raise_exception(env, RISCV_EXCP_ILLEGAL_INST, GETPC());
227}
228
229void helper_hyp_gvma_tlb_flush(CPURISCVState *env)
230{
231 if (env->priv == PRV_S && !riscv_cpu_virt_enabled(env) &&
232 get_field(env->mstatus, MSTATUS_TVM)) {
233 riscv_raise_exception(env, RISCV_EXCP_ILLEGAL_INST, GETPC());
234 }
235
236 helper_hyp_tlb_flush(env);
237}
238
239target_ulong helper_hyp_hlvx_hu(CPURISCVState *env, target_ulong address)
240{
241 int mmu_idx = cpu_mmu_index(env, true) | TB_FLAGS_PRIV_HYP_ACCESS_MASK;
242
243 return cpu_lduw_mmuidx_ra(env, address, mmu_idx, GETPC());
244}
245
246target_ulong helper_hyp_hlvx_wu(CPURISCVState *env, target_ulong address)
247{
248 int mmu_idx = cpu_mmu_index(env, true) | TB_FLAGS_PRIV_HYP_ACCESS_MASK;
249
250 return cpu_ldl_mmuidx_ra(env, address, mmu_idx, GETPC());
251}
252
253#endif
254