2 * RISC-V Emulation Helpers for QEMU.
4 * Copyright (c) 2016-2017 Sagar Karandikar, sagark@eecs.berkeley.edu
5 * Copyright (c) 2017-2018 SiFive, Inc.
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.
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
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/>.
20 #include "qemu/osdep.h"
23 #include "qemu/main-loop.h"
24 #include "exec/exec-all.h"
25 #include "exec/helper-proto.h"
27 /* Exceptions processing helpers */
28 void QEMU_NORETURN
riscv_raise_exception(CPURISCVState
*env
,
29 uint32_t exception
, uintptr_t pc
)
31 CPUState
*cs
= env_cpu(env
);
32 cs
->exception_index
= exception
;
33 cpu_loop_exit_restore(cs
, pc
);
36 void helper_raise_exception(CPURISCVState
*env
, uint32_t exception
)
38 riscv_raise_exception(env
, exception
, 0);
41 target_ulong
helper_csrrw(CPURISCVState
*env
, target_ulong src
,
45 int ret
= riscv_csrrw(env
, csr
, &val
, src
, -1);
48 riscv_raise_exception(env
, -ret
, GETPC());
53 target_ulong
helper_csrrs(CPURISCVState
*env
, target_ulong src
,
54 target_ulong csr
, target_ulong rs1_pass
)
57 int ret
= riscv_csrrw(env
, csr
, &val
, -1, rs1_pass
? src
: 0);
60 riscv_raise_exception(env
, -ret
, GETPC());
65 target_ulong
helper_csrrc(CPURISCVState
*env
, target_ulong src
,
66 target_ulong csr
, target_ulong rs1_pass
)
69 int ret
= riscv_csrrw(env
, csr
, &val
, 0, rs1_pass
? src
: 0);
72 riscv_raise_exception(env
, -ret
, GETPC());
77 #ifndef CONFIG_USER_ONLY
79 target_ulong
helper_sret(CPURISCVState
*env
, target_ulong cpu_pc_deb
)
81 target_ulong prev_priv
, prev_virt
, mstatus
;
83 if (!(env
->priv
>= PRV_S
)) {
84 riscv_raise_exception(env
, RISCV_EXCP_ILLEGAL_INST
, GETPC());
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());
92 if (get_field(env
->mstatus
, MSTATUS_TSR
) && !(env
->priv
>= PRV_M
)) {
93 riscv_raise_exception(env
, RISCV_EXCP_ILLEGAL_INST
, GETPC());
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());
101 mstatus
= env
->mstatus
;
103 if (riscv_has_ext(env
, RVH
) && !riscv_cpu_virt_enabled(env
)) {
104 /* We support Hypervisor extensions and virtulisation is disabled */
105 target_ulong hstatus
= env
->hstatus
;
107 prev_priv
= get_field(mstatus
, MSTATUS_SPP
);
108 prev_virt
= get_field(hstatus
, HSTATUS_SPV
);
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);
116 env
->mstatus
= mstatus
;
117 env
->hstatus
= hstatus
;
120 riscv_cpu_swap_hypervisor_regs(env
);
123 riscv_cpu_set_virt_enabled(env
, prev_virt
);
125 prev_priv
= get_field(mstatus
, MSTATUS_SPP
);
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
;
134 riscv_cpu_set_mode(env
, prev_priv
);
139 target_ulong
helper_mret(CPURISCVState
*env
, target_ulong cpu_pc_deb
)
141 if (!(env
->priv
>= PRV_M
)) {
142 riscv_raise_exception(env
, RISCV_EXCP_ILLEGAL_INST
, GETPC());
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());
150 target_ulong mstatus
= env
->mstatus
;
151 target_ulong prev_priv
= get_field(mstatus
, MSTATUS_MPP
);
152 target_ulong prev_virt
= MSTATUS_MPV_ISSET(env
);
153 mstatus
= set_field(mstatus
, MSTATUS_MIE
,
154 get_field(mstatus
, MSTATUS_MPIE
));
155 mstatus
= set_field(mstatus
, MSTATUS_MPIE
, 1);
156 mstatus
= set_field(mstatus
, MSTATUS_MPP
, PRV_U
);
157 #ifdef TARGET_RISCV32
158 env
->mstatush
= set_field(env
->mstatush
, MSTATUS_MPV
, 0);
160 mstatus
= set_field(mstatus
, MSTATUS_MPV
, 0);
162 env
->mstatus
= mstatus
;
163 riscv_cpu_set_mode(env
, prev_priv
);
165 if (riscv_has_ext(env
, RVH
)) {
167 riscv_cpu_swap_hypervisor_regs(env
);
170 riscv_cpu_set_virt_enabled(env
, prev_virt
);
176 void helper_wfi(CPURISCVState
*env
)
178 CPUState
*cs
= env_cpu(env
);
180 if ((env
->priv
== PRV_S
&&
181 get_field(env
->mstatus
, MSTATUS_TW
)) ||
182 riscv_cpu_virt_enabled(env
)) {
183 riscv_raise_exception(env
, RISCV_EXCP_VIRT_INSTRUCTION_FAULT
, GETPC());
186 cs
->exception_index
= EXCP_HLT
;
191 void helper_tlb_flush(CPURISCVState
*env
)
193 CPUState
*cs
= env_cpu(env
);
194 if (!(env
->priv
>= PRV_S
) ||
195 (env
->priv
== PRV_S
&&
196 get_field(env
->mstatus
, MSTATUS_TVM
))) {
197 riscv_raise_exception(env
, RISCV_EXCP_ILLEGAL_INST
, GETPC());
198 } else if (riscv_has_ext(env
, RVH
) && riscv_cpu_virt_enabled(env
) &&
199 get_field(env
->hstatus
, HSTATUS_VTVM
)) {
200 riscv_raise_exception(env
, RISCV_EXCP_VIRT_INSTRUCTION_FAULT
, GETPC());
206 void helper_hyp_tlb_flush(CPURISCVState
*env
)
208 CPUState
*cs
= env_cpu(env
);
210 if (env
->priv
== PRV_S
&& riscv_cpu_virt_enabled(env
)) {
211 riscv_raise_exception(env
, RISCV_EXCP_VIRT_INSTRUCTION_FAULT
, GETPC());
214 if (env
->priv
== PRV_M
||
215 (env
->priv
== PRV_S
&& !riscv_cpu_virt_enabled(env
))) {
220 riscv_raise_exception(env
, RISCV_EXCP_ILLEGAL_INST
, GETPC());
223 void helper_hyp_gvma_tlb_flush(CPURISCVState
*env
)
225 if (env
->priv
== PRV_S
&& !riscv_cpu_virt_enabled(env
) &&
226 get_field(env
->mstatus
, MSTATUS_TVM
)) {
227 riscv_raise_exception(env
, RISCV_EXCP_ILLEGAL_INST
, GETPC());
230 helper_hyp_tlb_flush(env
);
233 target_ulong
helper_hyp_load(CPURISCVState
*env
, target_ulong address
,
234 target_ulong attrs
, target_ulong memop
)
236 if (env
->priv
== PRV_M
||
237 (env
->priv
== PRV_S
&& !riscv_cpu_virt_enabled(env
)) ||
238 (env
->priv
== PRV_U
&& !riscv_cpu_virt_enabled(env
) &&
239 get_field(env
->hstatus
, HSTATUS_HU
))) {
242 riscv_cpu_set_two_stage_lookup(env
, true);
246 pte
= cpu_ldsb_data_ra(env
, address
, GETPC());
249 pte
= cpu_ldub_data_ra(env
, address
, GETPC());
252 pte
= cpu_ldsw_data_ra(env
, address
, GETPC());
255 pte
= cpu_lduw_data_ra(env
, address
, GETPC());
258 pte
= cpu_ldl_data_ra(env
, address
, GETPC());
261 pte
= cpu_ldl_data_ra(env
, address
, GETPC());
264 pte
= cpu_ldq_data_ra(env
, address
, GETPC());
267 g_assert_not_reached();
270 riscv_cpu_set_two_stage_lookup(env
, false);
275 if (riscv_cpu_virt_enabled(env
)) {
276 riscv_raise_exception(env
, RISCV_EXCP_VIRT_INSTRUCTION_FAULT
, GETPC());
278 riscv_raise_exception(env
, RISCV_EXCP_ILLEGAL_INST
, GETPC());
283 void helper_hyp_store(CPURISCVState
*env
, target_ulong address
,
284 target_ulong val
, target_ulong attrs
, target_ulong memop
)
286 if (env
->priv
== PRV_M
||
287 (env
->priv
== PRV_S
&& !riscv_cpu_virt_enabled(env
)) ||
288 (env
->priv
== PRV_U
&& !riscv_cpu_virt_enabled(env
) &&
289 get_field(env
->hstatus
, HSTATUS_HU
))) {
290 riscv_cpu_set_two_stage_lookup(env
, true);
295 cpu_stb_data_ra(env
, address
, val
, GETPC());
299 cpu_stw_data_ra(env
, address
, val
, GETPC());
303 cpu_stl_data_ra(env
, address
, val
, GETPC());
306 cpu_stq_data_ra(env
, address
, val
, GETPC());
309 g_assert_not_reached();
312 riscv_cpu_set_two_stage_lookup(env
, false);
317 if (riscv_cpu_virt_enabled(env
)) {
318 riscv_raise_exception(env
, RISCV_EXCP_VIRT_INSTRUCTION_FAULT
, GETPC());
320 riscv_raise_exception(env
, RISCV_EXCP_ILLEGAL_INST
, GETPC());
324 target_ulong
helper_hyp_x_load(CPURISCVState
*env
, target_ulong address
,
325 target_ulong attrs
, target_ulong memop
)
327 if (env
->priv
== PRV_M
||
328 (env
->priv
== PRV_S
&& !riscv_cpu_virt_enabled(env
)) ||
329 (env
->priv
== PRV_U
&& !riscv_cpu_virt_enabled(env
) &&
330 get_field(env
->hstatus
, HSTATUS_HU
))) {
333 riscv_cpu_set_two_stage_lookup(env
, true);
337 pte
= cpu_lduw_data_ra(env
, address
, GETPC());
340 pte
= cpu_ldl_data_ra(env
, address
, GETPC());
343 g_assert_not_reached();
346 riscv_cpu_set_two_stage_lookup(env
, false);
351 if (riscv_cpu_virt_enabled(env
)) {
352 riscv_raise_exception(env
, RISCV_EXCP_VIRT_INSTRUCTION_FAULT
, GETPC());
354 riscv_raise_exception(env
, RISCV_EXCP_ILLEGAL_INST
, GETPC());
359 #endif /* !CONFIG_USER_ONLY */