@@ -311,6 +311,8 @@ struct CPUArchState {
/* Sstc CSRs */
uint64_t stimecmp;
+ uint64_t vstimecmp;
+
/* physical memory protection */
pmp_table_t pmp_state;
target_ulong mseccfg;
@@ -365,6 +367,8 @@ struct CPUArchState {
/* Fields from here on are preserved across CPU reset. */
QEMUTimer *stimer; /* Internal timer for S-mode interrupt */
+ QEMUTimer *vstimer; /* Internal timer for VS-mode interrupt */
+ bool vstime_irq;
hwaddr kernel_addr;
hwaddr fdt_addr;
@@ -257,6 +257,10 @@
#define CSR_VSIP 0x244
#define CSR_VSATP 0x280
+/* Sstc virtual CSRs */
+#define CSR_VSTIMECMP 0x24D
+#define CSR_VSTIMECMPH 0x25D
+
#define CSR_MTINST 0x34a
#define CSR_MTVAL2 0x34b
@@ -346,8 +346,9 @@ uint64_t riscv_cpu_all_pending(CPURISCVState *env)
{
uint32_t gein = get_field(env->hstatus, HSTATUS_VGEIN);
uint64_t vsgein = (env->hgeip & (1ULL << gein)) ? MIP_VSEIP : 0;
+ uint64_t vstip = (env->vstime_irq) ? MIP_VSTIP : 0;
- return (env->mip | vsgein) & env->mie;
+ return (env->mip | vsgein | vstip) & env->mie;
}
int riscv_cpu_mirq_pending(CPURISCVState *env)
@@ -606,7 +607,7 @@ uint64_t riscv_cpu_update_mip(RISCVCPU *cpu, uint64_t mask, uint64_t value)
{
CPURISCVState *env = &cpu->env;
CPUState *cs = CPU(cpu);
- uint64_t gein, vsgein = 0, old = env->mip;
+ uint64_t gein, vsgein = 0, vstip = 0, old = env->mip;
bool locked = false;
if (riscv_cpu_virt_enabled(env)) {
@@ -614,6 +615,10 @@ uint64_t riscv_cpu_update_mip(RISCVCPU *cpu, uint64_t mask, uint64_t value)
vsgein = (env->hgeip & (1ULL << gein)) ? MIP_VSEIP : 0;
}
+ /* No need to update mip for VSTIP */
+ mask = ((mask == MIP_VSTIP) && env->vstime_irq) ? 0 : mask;
+ vstip = env->vstime_irq ? MIP_VSTIP : 0;
+
if (!qemu_mutex_iothread_locked()) {
locked = true;
qemu_mutex_lock_iothread();
@@ -621,7 +626,7 @@ uint64_t riscv_cpu_update_mip(RISCVCPU *cpu, uint64_t mask, uint64_t value)
env->mip = (env->mip & ~mask) | (value & mask);
- if (env->mip | vsgein) {
+ if (env->mip | vsgein | vstip) {
cpu_interrupt(cs, CPU_INTERRUPT_HARD);
} else {
cpu_reset_interrupt(cs, CPU_INTERRUPT_HARD);
@@ -820,6 +820,7 @@ static RISCVException sstc(CPURISCVState *env, int csrno)
{
CPUState *cs = env_cpu(env);
RISCVCPU *cpu = RISCV_CPU(cs);
+ bool hmode_check = false;
if (!cpu->cfg.ext_sstc || !env->rdtime_fn) {
return RISCV_EXCP_ILLEGAL_INST;
@@ -838,7 +839,18 @@ static RISCVException sstc(CPURISCVState *env, int csrno)
return RISCV_EXCP_ILLEGAL_INST;
}
- return smode(env, csrno);
+ if (riscv_cpu_virt_enabled(env)) {
+ if (!(get_field(env->hcounteren, COUNTEREN_TM) &
+ get_field(env->henvcfg, HENVCFG_STCE))) {
+ return RISCV_EXCP_VIRT_INSTRUCTION_FAULT;
+ }
+ }
+
+ if ((csrno == CSR_VSTIMECMP) || (csrno == CSR_VSTIMECMPH)) {
+ hmode_check = true;
+ }
+
+ return hmode_check ? hmode(env, csrno) : smode(env, csrno);
}
static RISCVException sstc_32(CPURISCVState *env, int csrno)
@@ -850,17 +862,72 @@ static RISCVException sstc_32(CPURISCVState *env, int csrno)
return sstc(env, csrno);
}
+static RISCVException read_vstimecmp(CPURISCVState *env, int csrno,
+ target_ulong *val)
+{
+ *val = env->vstimecmp;
+
+ return RISCV_EXCP_NONE;
+}
+
+static RISCVException read_vstimecmph(CPURISCVState *env, int csrno,
+ target_ulong *val)
+{
+ *val = env->vstimecmp >> 32;
+
+ return RISCV_EXCP_NONE;
+}
+
+static RISCVException write_vstimecmp(CPURISCVState *env, int csrno,
+ target_ulong val)
+{
+ RISCVCPU *cpu = env_archcpu(env);
+
+ if (riscv_cpu_mxl(env) == MXL_RV32) {
+ env->vstimecmp = deposit64(env->vstimecmp, 0, 32, (uint64_t)val);
+ } else {
+ env->vstimecmp = val;
+ }
+
+ riscv_timer_write_timecmp(cpu, env->vstimer, env->vstimecmp,
+ env->htimedelta, MIP_VSTIP);
+
+ return RISCV_EXCP_NONE;
+}
+
+static RISCVException write_vstimecmph(CPURISCVState *env, int csrno,
+ target_ulong val)
+{
+ RISCVCPU *cpu = env_archcpu(env);
+
+ env->vstimecmp = deposit64(env->vstimecmp, 32, 32, (uint64_t)val);
+ riscv_timer_write_timecmp(cpu, env->vstimer, env->vstimecmp,
+ env->htimedelta, MIP_VSTIP);
+
+ return RISCV_EXCP_NONE;
+}
+
static RISCVException read_stimecmp(CPURISCVState *env, int csrno,
target_ulong *val)
{
- *val = env->stimecmp;
+ if (riscv_cpu_virt_enabled(env)) {
+ *val = env->vstimecmp;
+ } else {
+ *val = env->stimecmp;
+ }
+
return RISCV_EXCP_NONE;
}
static RISCVException read_stimecmph(CPURISCVState *env, int csrno,
target_ulong *val)
{
- *val = env->stimecmp >> 32;
+ if (riscv_cpu_virt_enabled(env)) {
+ *val = env->vstimecmp >> 32;
+ } else {
+ *val = env->stimecmp >> 32;
+ }
+
return RISCV_EXCP_NONE;
}
@@ -869,6 +936,10 @@ static RISCVException write_stimecmp(CPURISCVState *env, int csrno,
{
RISCVCPU *cpu = env_archcpu(env);
+ if (riscv_cpu_virt_enabled(env)) {
+ return write_vstimecmp(env, csrno, val);
+ }
+
if (riscv_cpu_mxl(env) == MXL_RV32) {
env->stimecmp = deposit64(env->stimecmp, 0, 32, (uint64_t)val);
} else {
@@ -885,6 +956,10 @@ static RISCVException write_stimecmph(CPURISCVState *env, int csrno,
{
RISCVCPU *cpu = env_archcpu(env);
+ if (riscv_cpu_virt_enabled(env)) {
+ return write_vstimecmph(env, csrno, val);
+ }
+
env->stimecmp = deposit64(env->stimecmp, 32, 32, (uint64_t)val);
riscv_timer_write_timecmp(cpu, env->stimer, env->stimecmp, 0, MIP_STIP);
@@ -1814,6 +1889,7 @@ static RISCVException rmw_mip64(CPURISCVState *env, int csrno,
if (csrno != CSR_HVIP) {
gin = get_field(env->hstatus, HSTATUS_VGEIN);
old_mip |= (env->hgeip & ((target_ulong)1 << gin)) ? MIP_VSEIP : 0;
+ old_mip |= env->vstime_irq ? MIP_VSTIP : 0;
}
if (ret_val) {
@@ -3680,6 +3756,12 @@ riscv_csr_operations csr_ops[CSR_TABLE_SIZE] = {
.min_priv_ver = PRIV_VERSION_1_12_0 },
[CSR_STIMECMPH] = { "stimecmph", sstc_32, read_stimecmph, write_stimecmph,
.min_priv_ver = PRIV_VERSION_1_12_0 },
+ [CSR_VSTIMECMP] = { "vstimecmp", sstc, read_vstimecmp,
+ write_vstimecmp,
+ .min_priv_ver = PRIV_VERSION_1_12_0 },
+ [CSR_VSTIMECMPH] = { "vstimecmph", sstc_32, read_vstimecmph,
+ write_vstimecmph,
+ .min_priv_ver = PRIV_VERSION_1_12_0 },
/* Supervisor Protection and Translation */
[CSR_SATP] = { "satp", smode, read_satp, write_satp },
@@ -92,6 +92,7 @@ static const VMStateDescription vmstate_hyper = {
VMSTATE_UINTTL(env.hgeie, RISCVCPU),
VMSTATE_UINTTL(env.hgeip, RISCVCPU),
VMSTATE_UINT64(env.htimedelta, RISCVCPU),
+ VMSTATE_UINT64(env.vstimecmp, RISCVCPU),
VMSTATE_UINTTL(env.hvictl, RISCVCPU),
VMSTATE_UINT8_ARRAY(env.hviprio, RISCVCPU, 64),
@@ -22,6 +22,14 @@
#include "time_helper.h"
#include "hw/intc/riscv_aclint.h"
+static void riscv_vstimer_cb(void *opaque)
+{
+ RISCVCPU *cpu = opaque;
+ CPURISCVState *env = &cpu->env;
+ env->vstime_irq = 1;
+ riscv_cpu_update_mip(cpu, MIP_VSTIP, BOOL_TO_MASK(1));
+}
+
static void riscv_stimer_cb(void *opaque)
{
RISCVCPU *cpu = opaque;
@@ -47,10 +55,16 @@ void riscv_timer_write_timecmp(RISCVCPU *cpu, QEMUTimer *timer,
* If we're setting an stimecmp value in the "past",
* immediately raise the timer interrupt
*/
+ if (timer_irq == MIP_VSTIP) {
+ env->vstime_irq = 1;
+ }
riscv_cpu_update_mip(cpu, timer_irq, BOOL_TO_MASK(1));
return;
}
+ if (timer_irq == MIP_VSTIP) {
+ env->vstime_irq = 0;
+ }
/* Clear the [V]STIP bit in mip */
riscv_cpu_update_mip(cpu, timer_irq, BOOL_TO_MASK(0));
@@ -95,4 +109,6 @@ void riscv_timer_init(RISCVCPU *cpu)
env->stimer = timer_new_ns(QEMU_CLOCK_VIRTUAL, &riscv_stimer_cb, cpu);
env->stimecmp = 0;
+ env->vstimer = timer_new_ns(QEMU_CLOCK_VIRTUAL, &riscv_vstimer_cb, cpu);
+ env->vstimecmp = 0;
}