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 #ifndef CONFIG_USER_ONLY
29 #if defined(TARGET_RISCV32)
30 static const char valid_vm_1_09
[16] = {
34 static const char valid_vm_1_10
[16] = {
38 #elif defined(TARGET_RISCV64)
39 static const char valid_vm_1_09
[16] = {
44 static const char valid_vm_1_10
[16] = {
52 static int validate_vm(CPURISCVState
*env
, target_ulong vm
)
54 return (env
->priv_ver
>= PRIV_VERSION_1_10_0
) ?
55 valid_vm_1_10
[vm
& 0xf] : valid_vm_1_09
[vm
& 0xf];
60 /* Exceptions processing helpers */
61 void QEMU_NORETURN
do_raise_exception_err(CPURISCVState
*env
,
62 uint32_t exception
, uintptr_t pc
)
64 CPUState
*cs
= CPU(riscv_env_get_cpu(env
));
65 qemu_log_mask(CPU_LOG_INT
, "%s: %d\n", __func__
, exception
);
66 cs
->exception_index
= exception
;
67 cpu_loop_exit_restore(cs
, pc
);
70 void helper_raise_exception(CPURISCVState
*env
, uint32_t exception
)
72 do_raise_exception_err(env
, exception
, 0);
75 static void validate_mstatus_fs(CPURISCVState
*env
, uintptr_t ra
)
77 #ifndef CONFIG_USER_ONLY
78 if (!(env
->mstatus
& MSTATUS_FS
)) {
79 do_raise_exception_err(env
, RISCV_EXCP_ILLEGAL_INST
, ra
);
85 * Handle writes to CSRs and any resulting special behavior
87 * Adapted from Spike's processor_t::set_csr
89 void csr_write_helper(CPURISCVState
*env
, target_ulong val_to_write
,
92 #ifndef CONFIG_USER_ONLY
93 uint64_t delegable_ints
= MIP_SSIP
| MIP_STIP
| MIP_SEIP
| (1 << IRQ_X_COP
);
94 uint64_t all_ints
= delegable_ints
| MIP_MSIP
| MIP_MTIP
;
99 validate_mstatus_fs(env
, GETPC());
100 cpu_riscv_set_fflags(env
, val_to_write
& (FSR_AEXC
>> FSR_AEXC_SHIFT
));
103 validate_mstatus_fs(env
, GETPC());
104 env
->frm
= val_to_write
& (FSR_RD
>> FSR_RD_SHIFT
);
107 validate_mstatus_fs(env
, GETPC());
108 env
->frm
= (val_to_write
& FSR_RD
) >> FSR_RD_SHIFT
;
109 cpu_riscv_set_fflags(env
, (val_to_write
& FSR_AEXC
) >> FSR_AEXC_SHIFT
);
111 #ifndef CONFIG_USER_ONLY
113 target_ulong mstatus
= env
->mstatus
;
114 target_ulong mask
= 0;
115 target_ulong mpp
= get_field(val_to_write
, MSTATUS_MPP
);
117 /* flush tlb on mstatus fields that affect VM */
118 if (env
->priv_ver
<= PRIV_VERSION_1_09_1
) {
119 if ((val_to_write
^ mstatus
) & (MSTATUS_MXR
| MSTATUS_MPP
|
120 MSTATUS_MPRV
| MSTATUS_SUM
| MSTATUS_VM
)) {
121 helper_tlb_flush(env
);
123 mask
= MSTATUS_SIE
| MSTATUS_SPIE
| MSTATUS_MIE
| MSTATUS_MPIE
|
124 MSTATUS_SPP
| MSTATUS_FS
| MSTATUS_MPRV
| MSTATUS_SUM
|
125 MSTATUS_MPP
| MSTATUS_MXR
|
126 (validate_vm(env
, get_field(val_to_write
, MSTATUS_VM
)) ?
129 if (env
->priv_ver
>= PRIV_VERSION_1_10_0
) {
130 if ((val_to_write
^ mstatus
) & (MSTATUS_MXR
| MSTATUS_MPP
|
131 MSTATUS_MPRV
| MSTATUS_SUM
)) {
132 helper_tlb_flush(env
);
134 mask
= MSTATUS_SIE
| MSTATUS_SPIE
| MSTATUS_MIE
| MSTATUS_MPIE
|
135 MSTATUS_SPP
| MSTATUS_FS
| MSTATUS_MPRV
| MSTATUS_SUM
|
136 MSTATUS_MPP
| MSTATUS_MXR
;
139 /* silenty discard mstatus.mpp writes for unsupported modes */
141 (!riscv_has_ext(env
, RVS
) && mpp
== PRV_S
) ||
142 (!riscv_has_ext(env
, RVU
) && mpp
== PRV_U
)) {
143 mask
&= ~MSTATUS_MPP
;
146 mstatus
= (mstatus
& ~mask
) | (val_to_write
& mask
);
148 /* Note: this is a workaround for an issue where mstatus.FS
149 does not report dirty after floating point operations
150 that modify floating point state. This workaround is
151 technically compliant with the RISC-V Privileged
152 specification as it is legal to return only off, or dirty.
153 at the expense of extra floating point save/restore. */
155 /* FP is always dirty or off */
156 if (mstatus
& MSTATUS_FS
) {
157 mstatus
|= MSTATUS_FS
;
160 int dirty
= ((mstatus
& MSTATUS_FS
) == MSTATUS_FS
) |
161 ((mstatus
& MSTATUS_XS
) == MSTATUS_XS
);
162 mstatus
= set_field(mstatus
, MSTATUS_SD
, dirty
);
163 env
->mstatus
= mstatus
;
168 * Since the writeable bits in MIP are not set asynchrously by the
169 * CLINT, no additional locking is needed for read-modifiy-write
172 qemu_mutex_lock_iothread();
173 RISCVCPU
*cpu
= riscv_env_get_cpu(env
);
174 riscv_set_local_interrupt(cpu
, MIP_SSIP
,
175 (val_to_write
& MIP_SSIP
) != 0);
176 riscv_set_local_interrupt(cpu
, MIP_STIP
,
177 (val_to_write
& MIP_STIP
) != 0);
179 * csrs, csrc on mip.SEIP is not decomposable into separate read and
180 * write steps, so a different implementation is needed
182 qemu_mutex_unlock_iothread();
186 env
->mie
= (env
->mie
& ~all_ints
) |
187 (val_to_write
& all_ints
);
191 env
->mideleg
= (env
->mideleg
& ~delegable_ints
)
192 | (val_to_write
& delegable_ints
);
195 target_ulong mask
= 0;
196 mask
|= 1ULL << (RISCV_EXCP_INST_ADDR_MIS
);
197 mask
|= 1ULL << (RISCV_EXCP_INST_ACCESS_FAULT
);
198 mask
|= 1ULL << (RISCV_EXCP_ILLEGAL_INST
);
199 mask
|= 1ULL << (RISCV_EXCP_BREAKPOINT
);
200 mask
|= 1ULL << (RISCV_EXCP_LOAD_ADDR_MIS
);
201 mask
|= 1ULL << (RISCV_EXCP_LOAD_ACCESS_FAULT
);
202 mask
|= 1ULL << (RISCV_EXCP_STORE_AMO_ADDR_MIS
);
203 mask
|= 1ULL << (RISCV_EXCP_STORE_AMO_ACCESS_FAULT
);
204 mask
|= 1ULL << (RISCV_EXCP_U_ECALL
);
205 mask
|= 1ULL << (RISCV_EXCP_S_ECALL
);
206 mask
|= 1ULL << (RISCV_EXCP_H_ECALL
);
207 mask
|= 1ULL << (RISCV_EXCP_M_ECALL
);
208 mask
|= 1ULL << (RISCV_EXCP_INST_PAGE_FAULT
);
209 mask
|= 1ULL << (RISCV_EXCP_LOAD_PAGE_FAULT
);
210 mask
|= 1ULL << (RISCV_EXCP_STORE_PAGE_FAULT
);
211 env
->medeleg
= (env
->medeleg
& ~mask
)
212 | (val_to_write
& mask
);
216 qemu_log_mask(LOG_UNIMP
, "CSR_MINSTRET: write not implemented");
219 qemu_log_mask(LOG_UNIMP
, "CSR_MCYCLE: write not implemented");
222 qemu_log_mask(LOG_UNIMP
, "CSR_MINSTRETH: write not implemented");
225 qemu_log_mask(LOG_UNIMP
, "CSR_MCYCLEH: write not implemented");
227 case CSR_MUCOUNTEREN
:
228 env
->mucounteren
= val_to_write
;
230 case CSR_MSCOUNTEREN
:
231 env
->mscounteren
= val_to_write
;
234 target_ulong ms
= env
->mstatus
;
235 target_ulong mask
= SSTATUS_SIE
| SSTATUS_SPIE
| SSTATUS_UIE
236 | SSTATUS_UPIE
| SSTATUS_SPP
| SSTATUS_FS
| SSTATUS_XS
237 | SSTATUS_SUM
| SSTATUS_MXR
| SSTATUS_SD
;
238 ms
= (ms
& ~mask
) | (val_to_write
& mask
);
239 csr_write_helper(env
, ms
, CSR_MSTATUS
);
243 qemu_mutex_lock_iothread();
244 target_ulong next_mip
= (env
->mip
& ~env
->mideleg
)
245 | (val_to_write
& env
->mideleg
);
246 qemu_mutex_unlock_iothread();
247 csr_write_helper(env
, next_mip
, CSR_MIP
);
251 target_ulong next_mie
= (env
->mie
& ~env
->mideleg
)
252 | (val_to_write
& env
->mideleg
);
253 csr_write_helper(env
, next_mie
, CSR_MIE
);
256 case CSR_SATP
: /* CSR_SPTBR */ {
257 if (!riscv_feature(env
, RISCV_FEATURE_MMU
)) {
260 if (env
->priv_ver
<= PRIV_VERSION_1_09_1
&& (val_to_write
^ env
->sptbr
))
262 helper_tlb_flush(env
);
263 env
->sptbr
= val_to_write
& (((target_ulong
)
264 1 << (TARGET_PHYS_ADDR_SPACE_BITS
- PGSHIFT
)) - 1);
266 if (env
->priv_ver
>= PRIV_VERSION_1_10_0
&&
267 validate_vm(env
, get_field(val_to_write
, SATP_MODE
)) &&
268 ((val_to_write
^ env
->satp
) & (SATP_MODE
| SATP_ASID
| SATP_PPN
)))
270 helper_tlb_flush(env
);
271 env
->satp
= val_to_write
;
276 env
->sepc
= val_to_write
;
279 if (val_to_write
& 1) {
280 qemu_log_mask(LOG_UNIMP
, "CSR_STVEC: vectored traps not supported");
283 env
->stvec
= val_to_write
>> 2 << 2;
286 env
->scounteren
= val_to_write
;
289 env
->sscratch
= val_to_write
;
292 env
->scause
= val_to_write
;
295 env
->sbadaddr
= val_to_write
;
298 env
->mepc
= val_to_write
;
301 if (val_to_write
& 1) {
302 qemu_log_mask(LOG_UNIMP
, "CSR_MTVEC: vectored traps not supported");
305 env
->mtvec
= val_to_write
>> 2 << 2;
308 env
->mcounteren
= val_to_write
;
311 env
->mscratch
= val_to_write
;
314 env
->mcause
= val_to_write
;
317 env
->mbadaddr
= val_to_write
;
320 qemu_log_mask(LOG_UNIMP
, "CSR_MISA: misa writes not supported");
327 pmpcfg_csr_write(env
, csrno
- CSR_PMPCFG0
, val_to_write
);
345 pmpaddr_csr_write(env
, csrno
- CSR_PMPADDR0
, val_to_write
);
350 do_raise_exception_err(env
, RISCV_EXCP_ILLEGAL_INST
, GETPC());
355 * Handle reads to CSRs and any resulting special behavior
357 * Adapted from Spike's processor_t::get_csr
359 target_ulong
csr_read_helper(CPURISCVState
*env
, target_ulong csrno
)
361 #ifndef CONFIG_USER_ONLY
362 target_ulong ctr_en
= env
->priv
== PRV_U
? env
->mucounteren
:
363 env
->priv
== PRV_S
? env
->mscounteren
: -1U;
365 target_ulong ctr_en
= -1;
367 target_ulong ctr_ok
= (ctr_en
>> (csrno
& 31)) & 1;
369 if (csrno
>= CSR_HPMCOUNTER3
&& csrno
<= CSR_HPMCOUNTER31
) {
374 #if defined(TARGET_RISCV32)
375 if (csrno
>= CSR_HPMCOUNTER3H
&& csrno
<= CSR_HPMCOUNTER31H
) {
381 if (csrno
>= CSR_MHPMCOUNTER3
&& csrno
<= CSR_MHPMCOUNTER31
) {
384 #if defined(TARGET_RISCV32)
385 if (csrno
>= CSR_MHPMCOUNTER3
&& csrno
<= CSR_MHPMCOUNTER31
) {
389 if (csrno
>= CSR_MHPMEVENT3
&& csrno
<= CSR_MHPMEVENT31
) {
395 validate_mstatus_fs(env
, GETPC());
396 return cpu_riscv_get_fflags(env
);
398 validate_mstatus_fs(env
, GETPC());
401 validate_mstatus_fs(env
, GETPC());
402 return (cpu_riscv_get_fflags(env
) << FSR_AEXC_SHIFT
)
403 | (env
->frm
<< FSR_RD_SHIFT
);
404 /* rdtime/rdtimeh is trapped and emulated by bbl in system mode */
405 #ifdef CONFIG_USER_ONLY
407 return cpu_get_host_ticks();
408 #if defined(TARGET_RISCV32)
410 return cpu_get_host_ticks() >> 32;
416 return cpu_get_host_ticks();
419 #if defined(TARGET_RISCV32)
423 return cpu_get_host_ticks() >> 32;
427 #ifndef CONFIG_USER_ONLY
430 return cpu_get_host_ticks();
433 #if defined(TARGET_RISCV32)
434 return cpu_get_host_ticks() >> 32;
437 case CSR_MUCOUNTEREN
:
438 return env
->mucounteren
;
439 case CSR_MSCOUNTEREN
:
440 return env
->mscounteren
;
442 target_ulong mask
= SSTATUS_SIE
| SSTATUS_SPIE
| SSTATUS_UIE
443 | SSTATUS_UPIE
| SSTATUS_SPP
| SSTATUS_FS
| SSTATUS_XS
444 | SSTATUS_SUM
| SSTATUS_SD
;
445 if (env
->priv_ver
>= PRIV_VERSION_1_10_0
) {
448 return env
->mstatus
& mask
;
451 qemu_mutex_lock_iothread();
452 target_ulong tmp
= env
->mip
& env
->mideleg
;
453 qemu_mutex_unlock_iothread();
457 return env
->mie
& env
->mideleg
;
461 return env
->sbadaddr
;
465 return env
->scounteren
;
469 if (env
->priv_ver
>= PRIV_VERSION_1_10_0
) {
475 return env
->sscratch
;
479 qemu_mutex_lock_iothread();
480 target_ulong tmp
= env
->mip
;
481 qemu_mutex_unlock_iothread();
489 return env
->mscratch
;
493 return env
->mbadaddr
;
497 return 0; /* as spike does */
499 return 0; /* as spike does */
501 return 0; /* as spike does */
507 return env
->mcounteren
;
516 return pmpcfg_csr_read(env
, csrno
- CSR_PMPCFG0
);
533 return pmpaddr_csr_read(env
, csrno
- CSR_PMPADDR0
);
536 /* used by e.g. MTIME read */
537 do_raise_exception_err(env
, RISCV_EXCP_ILLEGAL_INST
, GETPC());
541 * Check that CSR access is allowed.
543 * Adapted from Spike's decode.h:validate_csr
545 static void validate_csr(CPURISCVState
*env
, uint64_t which
,
546 uint64_t write
, uintptr_t ra
)
548 #ifndef CONFIG_USER_ONLY
549 unsigned csr_priv
= get_field((which
), 0x300);
550 unsigned csr_read_only
= get_field((which
), 0xC00) == 3;
551 if (((write
) && csr_read_only
) || (env
->priv
< csr_priv
)) {
552 do_raise_exception_err(env
, RISCV_EXCP_ILLEGAL_INST
, ra
);
557 target_ulong
helper_csrrw(CPURISCVState
*env
, target_ulong src
,
560 validate_csr(env
, csr
, 1, GETPC());
561 uint64_t csr_backup
= csr_read_helper(env
, csr
);
562 csr_write_helper(env
, src
, csr
);
566 target_ulong
helper_csrrs(CPURISCVState
*env
, target_ulong src
,
567 target_ulong csr
, target_ulong rs1_pass
)
569 validate_csr(env
, csr
, rs1_pass
!= 0, GETPC());
570 uint64_t csr_backup
= csr_read_helper(env
, csr
);
572 csr_write_helper(env
, src
| csr_backup
, csr
);
577 target_ulong
helper_csrrc(CPURISCVState
*env
, target_ulong src
,
578 target_ulong csr
, target_ulong rs1_pass
)
580 validate_csr(env
, csr
, rs1_pass
!= 0, GETPC());
581 uint64_t csr_backup
= csr_read_helper(env
, csr
);
583 csr_write_helper(env
, (~src
) & csr_backup
, csr
);
588 #ifndef CONFIG_USER_ONLY
590 /* iothread_mutex must be held */
591 void riscv_set_local_interrupt(RISCVCPU
*cpu
, target_ulong mask
, int value
)
593 target_ulong old_mip
= cpu
->env
.mip
;
594 cpu
->env
.mip
= (old_mip
& ~mask
) | (value
? mask
: 0);
596 if (cpu
->env
.mip
&& !old_mip
) {
597 cpu_interrupt(CPU(cpu
), CPU_INTERRUPT_HARD
);
598 } else if (!cpu
->env
.mip
&& old_mip
) {
599 cpu_reset_interrupt(CPU(cpu
), CPU_INTERRUPT_HARD
);
603 void riscv_set_mode(CPURISCVState
*env
, target_ulong newpriv
)
605 if (newpriv
> PRV_M
) {
606 g_assert_not_reached();
608 if (newpriv
== PRV_H
) {
611 /* tlb_flush is unnecessary as mode is contained in mmu_idx */
615 target_ulong
helper_sret(CPURISCVState
*env
, target_ulong cpu_pc_deb
)
617 if (!(env
->priv
>= PRV_S
)) {
618 do_raise_exception_err(env
, RISCV_EXCP_ILLEGAL_INST
, GETPC());
621 target_ulong retpc
= env
->sepc
;
622 if (!riscv_has_ext(env
, RVC
) && (retpc
& 0x3)) {
623 do_raise_exception_err(env
, RISCV_EXCP_INST_ADDR_MIS
, GETPC());
626 target_ulong mstatus
= env
->mstatus
;
627 target_ulong prev_priv
= get_field(mstatus
, MSTATUS_SPP
);
628 mstatus
= set_field(mstatus
,
629 env
->priv_ver
>= PRIV_VERSION_1_10_0
?
630 MSTATUS_SIE
: MSTATUS_UIE
<< prev_priv
,
631 get_field(mstatus
, MSTATUS_SPIE
));
632 mstatus
= set_field(mstatus
, MSTATUS_SPIE
, 0);
633 mstatus
= set_field(mstatus
, MSTATUS_SPP
, PRV_U
);
634 riscv_set_mode(env
, prev_priv
);
635 csr_write_helper(env
, mstatus
, CSR_MSTATUS
);
640 target_ulong
helper_mret(CPURISCVState
*env
, target_ulong cpu_pc_deb
)
642 if (!(env
->priv
>= PRV_M
)) {
643 do_raise_exception_err(env
, RISCV_EXCP_ILLEGAL_INST
, GETPC());
646 target_ulong retpc
= env
->mepc
;
647 if (!riscv_has_ext(env
, RVC
) && (retpc
& 0x3)) {
648 do_raise_exception_err(env
, RISCV_EXCP_INST_ADDR_MIS
, GETPC());
651 target_ulong mstatus
= env
->mstatus
;
652 target_ulong prev_priv
= get_field(mstatus
, MSTATUS_MPP
);
653 mstatus
= set_field(mstatus
,
654 env
->priv_ver
>= PRIV_VERSION_1_10_0
?
655 MSTATUS_MIE
: MSTATUS_UIE
<< prev_priv
,
656 get_field(mstatus
, MSTATUS_MPIE
));
657 mstatus
= set_field(mstatus
, MSTATUS_MPIE
, 0);
658 mstatus
= set_field(mstatus
, MSTATUS_MPP
, PRV_U
);
659 riscv_set_mode(env
, prev_priv
);
660 csr_write_helper(env
, mstatus
, CSR_MSTATUS
);
666 void helper_wfi(CPURISCVState
*env
)
668 CPUState
*cs
= CPU(riscv_env_get_cpu(env
));
671 cs
->exception_index
= EXCP_HLT
;
675 void helper_tlb_flush(CPURISCVState
*env
)
677 RISCVCPU
*cpu
= riscv_env_get_cpu(env
);
678 CPUState
*cs
= CPU(cpu
);
682 #endif /* !CONFIG_USER_ONLY */