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
);
147 int dirty
= (mstatus
& MSTATUS_FS
) == MSTATUS_FS
;
148 dirty
|= (mstatus
& MSTATUS_XS
) == MSTATUS_XS
;
149 mstatus
= set_field(mstatus
, MSTATUS_SD
, dirty
);
150 env
->mstatus
= mstatus
;
155 * Since the writeable bits in MIP are not set asynchrously by the
156 * CLINT, no additional locking is needed for read-modifiy-write
159 qemu_mutex_lock_iothread();
160 RISCVCPU
*cpu
= riscv_env_get_cpu(env
);
161 riscv_set_local_interrupt(cpu
, MIP_SSIP
,
162 (val_to_write
& MIP_SSIP
) != 0);
163 riscv_set_local_interrupt(cpu
, MIP_STIP
,
164 (val_to_write
& MIP_STIP
) != 0);
166 * csrs, csrc on mip.SEIP is not decomposable into separate read and
167 * write steps, so a different implementation is needed
169 qemu_mutex_unlock_iothread();
173 env
->mie
= (env
->mie
& ~all_ints
) |
174 (val_to_write
& all_ints
);
178 env
->mideleg
= (env
->mideleg
& ~delegable_ints
)
179 | (val_to_write
& delegable_ints
);
182 target_ulong mask
= 0;
183 mask
|= 1ULL << (RISCV_EXCP_INST_ADDR_MIS
);
184 mask
|= 1ULL << (RISCV_EXCP_INST_ACCESS_FAULT
);
185 mask
|= 1ULL << (RISCV_EXCP_ILLEGAL_INST
);
186 mask
|= 1ULL << (RISCV_EXCP_BREAKPOINT
);
187 mask
|= 1ULL << (RISCV_EXCP_LOAD_ADDR_MIS
);
188 mask
|= 1ULL << (RISCV_EXCP_LOAD_ACCESS_FAULT
);
189 mask
|= 1ULL << (RISCV_EXCP_STORE_AMO_ADDR_MIS
);
190 mask
|= 1ULL << (RISCV_EXCP_STORE_AMO_ACCESS_FAULT
);
191 mask
|= 1ULL << (RISCV_EXCP_U_ECALL
);
192 mask
|= 1ULL << (RISCV_EXCP_S_ECALL
);
193 mask
|= 1ULL << (RISCV_EXCP_H_ECALL
);
194 mask
|= 1ULL << (RISCV_EXCP_M_ECALL
);
195 mask
|= 1ULL << (RISCV_EXCP_INST_PAGE_FAULT
);
196 mask
|= 1ULL << (RISCV_EXCP_LOAD_PAGE_FAULT
);
197 mask
|= 1ULL << (RISCV_EXCP_STORE_PAGE_FAULT
);
198 env
->medeleg
= (env
->medeleg
& ~mask
)
199 | (val_to_write
& mask
);
203 qemu_log_mask(LOG_UNIMP
, "CSR_MINSTRET: write not implemented");
206 qemu_log_mask(LOG_UNIMP
, "CSR_MCYCLE: write not implemented");
209 qemu_log_mask(LOG_UNIMP
, "CSR_MINSTRETH: write not implemented");
212 qemu_log_mask(LOG_UNIMP
, "CSR_MCYCLEH: write not implemented");
214 case CSR_MUCOUNTEREN
:
215 env
->mucounteren
= val_to_write
;
217 case CSR_MSCOUNTEREN
:
218 env
->mscounteren
= val_to_write
;
221 target_ulong ms
= env
->mstatus
;
222 target_ulong mask
= SSTATUS_SIE
| SSTATUS_SPIE
| SSTATUS_UIE
223 | SSTATUS_UPIE
| SSTATUS_SPP
| SSTATUS_FS
| SSTATUS_XS
224 | SSTATUS_SUM
| SSTATUS_MXR
| SSTATUS_SD
;
225 ms
= (ms
& ~mask
) | (val_to_write
& mask
);
226 csr_write_helper(env
, ms
, CSR_MSTATUS
);
230 qemu_mutex_lock_iothread();
231 target_ulong next_mip
= (env
->mip
& ~env
->mideleg
)
232 | (val_to_write
& env
->mideleg
);
233 qemu_mutex_unlock_iothread();
234 csr_write_helper(env
, next_mip
, CSR_MIP
);
238 target_ulong next_mie
= (env
->mie
& ~env
->mideleg
)
239 | (val_to_write
& env
->mideleg
);
240 csr_write_helper(env
, next_mie
, CSR_MIE
);
243 case CSR_SATP
: /* CSR_SPTBR */ {
244 if (!riscv_feature(env
, RISCV_FEATURE_MMU
)) {
247 if (env
->priv_ver
<= PRIV_VERSION_1_09_1
&& (val_to_write
^ env
->sptbr
))
249 helper_tlb_flush(env
);
250 env
->sptbr
= val_to_write
& (((target_ulong
)
251 1 << (TARGET_PHYS_ADDR_SPACE_BITS
- PGSHIFT
)) - 1);
253 if (env
->priv_ver
>= PRIV_VERSION_1_10_0
&&
254 validate_vm(env
, get_field(val_to_write
, SATP_MODE
)) &&
255 ((val_to_write
^ env
->satp
) & (SATP_MODE
| SATP_ASID
| SATP_PPN
)))
257 helper_tlb_flush(env
);
258 env
->satp
= val_to_write
;
263 env
->sepc
= val_to_write
;
266 if (val_to_write
& 1) {
267 qemu_log_mask(LOG_UNIMP
, "CSR_STVEC: vectored traps not supported");
270 env
->stvec
= val_to_write
>> 2 << 2;
273 env
->scounteren
= val_to_write
;
276 env
->sscratch
= val_to_write
;
279 env
->scause
= val_to_write
;
282 env
->sbadaddr
= val_to_write
;
285 env
->mepc
= val_to_write
;
288 if (val_to_write
& 1) {
289 qemu_log_mask(LOG_UNIMP
, "CSR_MTVEC: vectored traps not supported");
292 env
->mtvec
= val_to_write
>> 2 << 2;
295 env
->mcounteren
= val_to_write
;
298 env
->mscratch
= val_to_write
;
301 env
->mcause
= val_to_write
;
304 env
->mbadaddr
= val_to_write
;
307 qemu_log_mask(LOG_UNIMP
, "CSR_MISA: misa writes not supported");
314 pmpcfg_csr_write(env
, csrno
- CSR_PMPCFG0
, val_to_write
);
332 pmpaddr_csr_write(env
, csrno
- CSR_PMPADDR0
, val_to_write
);
337 do_raise_exception_err(env
, RISCV_EXCP_ILLEGAL_INST
, GETPC());
342 * Handle reads to CSRs and any resulting special behavior
344 * Adapted from Spike's processor_t::get_csr
346 target_ulong
csr_read_helper(CPURISCVState
*env
, target_ulong csrno
)
348 #ifndef CONFIG_USER_ONLY
349 target_ulong ctr_en
= env
->priv
== PRV_U
? env
->mucounteren
:
350 env
->priv
== PRV_S
? env
->mscounteren
: -1U;
352 target_ulong ctr_en
= -1;
354 target_ulong ctr_ok
= (ctr_en
>> (csrno
& 31)) & 1;
356 if (csrno
>= CSR_HPMCOUNTER3
&& csrno
<= CSR_HPMCOUNTER31
) {
361 #if defined(TARGET_RISCV32)
362 if (csrno
>= CSR_HPMCOUNTER3H
&& csrno
<= CSR_HPMCOUNTER31H
) {
368 if (csrno
>= CSR_MHPMCOUNTER3
&& csrno
<= CSR_MHPMCOUNTER31
) {
371 #if defined(TARGET_RISCV32)
372 if (csrno
>= CSR_MHPMCOUNTER3
&& csrno
<= CSR_MHPMCOUNTER31
) {
376 if (csrno
>= CSR_MHPMEVENT3
&& csrno
<= CSR_MHPMEVENT31
) {
382 validate_mstatus_fs(env
, GETPC());
383 return cpu_riscv_get_fflags(env
);
385 validate_mstatus_fs(env
, GETPC());
388 validate_mstatus_fs(env
, GETPC());
389 return (cpu_riscv_get_fflags(env
) << FSR_AEXC_SHIFT
)
390 | (env
->frm
<< FSR_RD_SHIFT
);
391 /* rdtime/rdtimeh is trapped and emulated by bbl in system mode */
392 #ifdef CONFIG_USER_ONLY
394 return cpu_get_host_ticks();
395 #if defined(TARGET_RISCV32)
397 return cpu_get_host_ticks() >> 32;
403 return cpu_get_host_ticks();
406 #if defined(TARGET_RISCV32)
410 return cpu_get_host_ticks() >> 32;
414 #ifndef CONFIG_USER_ONLY
417 return cpu_get_host_ticks();
420 #if defined(TARGET_RISCV32)
421 return cpu_get_host_ticks() >> 32;
424 case CSR_MUCOUNTEREN
:
425 return env
->mucounteren
;
426 case CSR_MSCOUNTEREN
:
427 return env
->mscounteren
;
429 target_ulong mask
= SSTATUS_SIE
| SSTATUS_SPIE
| SSTATUS_UIE
430 | SSTATUS_UPIE
| SSTATUS_SPP
| SSTATUS_FS
| SSTATUS_XS
431 | SSTATUS_SUM
| SSTATUS_SD
;
432 if (env
->priv_ver
>= PRIV_VERSION_1_10_0
) {
435 return env
->mstatus
& mask
;
438 qemu_mutex_lock_iothread();
439 target_ulong tmp
= env
->mip
& env
->mideleg
;
440 qemu_mutex_unlock_iothread();
444 return env
->mie
& env
->mideleg
;
448 return env
->sbadaddr
;
452 return env
->scounteren
;
456 if (env
->priv_ver
>= PRIV_VERSION_1_10_0
) {
462 return env
->sscratch
;
466 qemu_mutex_lock_iothread();
467 target_ulong tmp
= env
->mip
;
468 qemu_mutex_unlock_iothread();
476 return env
->mscratch
;
480 return env
->mbadaddr
;
484 return 0; /* as spike does */
486 return 0; /* as spike does */
488 return 0; /* as spike does */
494 return env
->mcounteren
;
503 return pmpcfg_csr_read(env
, csrno
- CSR_PMPCFG0
);
520 return pmpaddr_csr_read(env
, csrno
- CSR_PMPADDR0
);
523 /* used by e.g. MTIME read */
524 do_raise_exception_err(env
, RISCV_EXCP_ILLEGAL_INST
, GETPC());
528 * Check that CSR access is allowed.
530 * Adapted from Spike's decode.h:validate_csr
532 static void validate_csr(CPURISCVState
*env
, uint64_t which
,
533 uint64_t write
, uintptr_t ra
)
535 #ifndef CONFIG_USER_ONLY
536 unsigned csr_priv
= get_field((which
), 0x300);
537 unsigned csr_read_only
= get_field((which
), 0xC00) == 3;
538 if (((write
) && csr_read_only
) || (env
->priv
< csr_priv
)) {
539 do_raise_exception_err(env
, RISCV_EXCP_ILLEGAL_INST
, ra
);
544 target_ulong
helper_csrrw(CPURISCVState
*env
, target_ulong src
,
547 validate_csr(env
, csr
, 1, GETPC());
548 uint64_t csr_backup
= csr_read_helper(env
, csr
);
549 csr_write_helper(env
, src
, csr
);
553 target_ulong
helper_csrrs(CPURISCVState
*env
, target_ulong src
,
554 target_ulong csr
, target_ulong rs1_pass
)
556 validate_csr(env
, csr
, rs1_pass
!= 0, GETPC());
557 uint64_t csr_backup
= csr_read_helper(env
, csr
);
559 csr_write_helper(env
, src
| csr_backup
, csr
);
564 target_ulong
helper_csrrc(CPURISCVState
*env
, target_ulong src
,
565 target_ulong csr
, target_ulong rs1_pass
)
567 validate_csr(env
, csr
, rs1_pass
!= 0, GETPC());
568 uint64_t csr_backup
= csr_read_helper(env
, csr
);
570 csr_write_helper(env
, (~src
) & csr_backup
, csr
);
575 #ifndef CONFIG_USER_ONLY
577 /* iothread_mutex must be held */
578 void riscv_set_local_interrupt(RISCVCPU
*cpu
, target_ulong mask
, int value
)
580 target_ulong old_mip
= cpu
->env
.mip
;
581 cpu
->env
.mip
= (old_mip
& ~mask
) | (value
? mask
: 0);
583 if (cpu
->env
.mip
&& !old_mip
) {
584 cpu_interrupt(CPU(cpu
), CPU_INTERRUPT_HARD
);
585 } else if (!cpu
->env
.mip
&& old_mip
) {
586 cpu_reset_interrupt(CPU(cpu
), CPU_INTERRUPT_HARD
);
590 void riscv_set_mode(CPURISCVState
*env
, target_ulong newpriv
)
592 if (newpriv
> PRV_M
) {
593 g_assert_not_reached();
595 if (newpriv
== PRV_H
) {
598 /* tlb_flush is unnecessary as mode is contained in mmu_idx */
602 target_ulong
helper_sret(CPURISCVState
*env
, target_ulong cpu_pc_deb
)
604 if (!(env
->priv
>= PRV_S
)) {
605 do_raise_exception_err(env
, RISCV_EXCP_ILLEGAL_INST
, GETPC());
608 target_ulong retpc
= env
->sepc
;
609 if (!riscv_has_ext(env
, RVC
) && (retpc
& 0x3)) {
610 do_raise_exception_err(env
, RISCV_EXCP_INST_ADDR_MIS
, GETPC());
613 target_ulong mstatus
= env
->mstatus
;
614 target_ulong prev_priv
= get_field(mstatus
, MSTATUS_SPP
);
615 mstatus
= set_field(mstatus
,
616 env
->priv_ver
>= PRIV_VERSION_1_10_0
?
617 MSTATUS_SIE
: MSTATUS_UIE
<< prev_priv
,
618 get_field(mstatus
, MSTATUS_SPIE
));
619 mstatus
= set_field(mstatus
, MSTATUS_SPIE
, 0);
620 mstatus
= set_field(mstatus
, MSTATUS_SPP
, PRV_U
);
621 riscv_set_mode(env
, prev_priv
);
622 csr_write_helper(env
, mstatus
, CSR_MSTATUS
);
627 target_ulong
helper_mret(CPURISCVState
*env
, target_ulong cpu_pc_deb
)
629 if (!(env
->priv
>= PRV_M
)) {
630 do_raise_exception_err(env
, RISCV_EXCP_ILLEGAL_INST
, GETPC());
633 target_ulong retpc
= env
->mepc
;
634 if (!riscv_has_ext(env
, RVC
) && (retpc
& 0x3)) {
635 do_raise_exception_err(env
, RISCV_EXCP_INST_ADDR_MIS
, GETPC());
638 target_ulong mstatus
= env
->mstatus
;
639 target_ulong prev_priv
= get_field(mstatus
, MSTATUS_MPP
);
640 mstatus
= set_field(mstatus
,
641 env
->priv_ver
>= PRIV_VERSION_1_10_0
?
642 MSTATUS_MIE
: MSTATUS_UIE
<< prev_priv
,
643 get_field(mstatus
, MSTATUS_MPIE
));
644 mstatus
= set_field(mstatus
, MSTATUS_MPIE
, 0);
645 mstatus
= set_field(mstatus
, MSTATUS_MPP
, PRV_U
);
646 riscv_set_mode(env
, prev_priv
);
647 csr_write_helper(env
, mstatus
, CSR_MSTATUS
);
653 void helper_wfi(CPURISCVState
*env
)
655 CPUState
*cs
= CPU(riscv_env_get_cpu(env
));
658 cs
->exception_index
= EXCP_HLT
;
662 void helper_tlb_flush(CPURISCVState
*env
)
664 RISCVCPU
*cpu
= riscv_env_get_cpu(env
);
665 CPUState
*cs
= CPU(cpu
);
669 #endif /* !CONFIG_USER_ONLY */