All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v8  0/3] Implement Sstc extension
@ 2022-08-04  1:42 Atish Patra
  2022-08-04  1:42 ` [PATCH v8 1/3] hw/intc: Move mtimer/mtimecmp to aclint Atish Patra
                   ` (2 more replies)
  0 siblings, 3 replies; 13+ messages in thread
From: Atish Patra @ 2022-08-04  1:42 UTC (permalink / raw)
  To: qemu-devel
  Cc: Atish Patra, Alistair Francis, Bin Meng, Palmer Dabbelt, qemu-riscv

This series implements Sstc extension[1] which was ratified recently.

The first patch is a prepartory patches while PATCH 2 adds stimecmp
support while PATCH 3 adds vstimecmp support. This series is based on
on top of upstream commit (faee5441a038).

The series can also be found at
https://github.com/atishp04/qemu/tree/sstc_v8

It is tested on RV32 & RV64 with latest OpenSBI & Linux kernel[2]
patches.

Changes from v7->v8:
1. Removed redundant blank lines.
2. Invoke smode & hmode predicate function from sstc related predicate
   functions.

Changes from v6->v7:
1. Replaced g_malloc0 with g_new0.
2. Removed the over allocation for the timers.

Changes from v5->v6:
1. Rebased on top of the latest HEAD commit.

Changes from v4->v5:
1. Removed any ordering related flags and emulate the hardware more
   closely. 

Changes from v3->v4:
1. Added [v]stimecmp_wr_done to the corresponding vmstate strucuture.

Changes from v2->v3:
1. Dropped generic migration code improvement patches.
2. Removed the order constraints while updating stimecmp/vstimecmp.

Changes from v1->v2:
1. Rebased on the latest upstream commit.
2. Replaced PATCH 1 with another patch where mtimer/timecmp is
   moved from CPU to ACLINT.
3. Added ACLINT migration support.

[1] https://drive.google.com/file/d/1m84Re2yK8m_vbW7TspvevCDR82MOBaSX/view
[2] https://github.com/atishp04/linux/tree/sstc_v8

Atish Patra (3):
hw/intc: Move mtimer/mtimecmp to aclint
target/riscv: Add stimecmp support
target/riscv: Add vstimecmp support

hw/intc/riscv_aclint.c         |  41 +++++---
hw/timer/ibex_timer.c          |  18 ++--
include/hw/intc/riscv_aclint.h |   2 +
include/hw/timer/ibex_timer.h  |   2 +
target/riscv/cpu.c             |   9 ++
target/riscv/cpu.h             |  11 ++-
target/riscv/cpu_bits.h        |   8 ++
target/riscv/cpu_helper.c      |  11 ++-
target/riscv/csr.c             | 175 +++++++++++++++++++++++++++++++++
target/riscv/machine.c         |   7 +-
target/riscv/meson.build       |   3 +-
target/riscv/time_helper.c     | 114 +++++++++++++++++++++
target/riscv/time_helper.h     |  30 ++++++
13 files changed, 399 insertions(+), 32 deletions(-)
create mode 100644 target/riscv/time_helper.c
create mode 100644 target/riscv/time_helper.h

--
2.25.1



^ permalink raw reply	[flat|nested] 13+ messages in thread

* [PATCH v8  1/3] hw/intc: Move mtimer/mtimecmp to aclint
  2022-08-04  1:42 [PATCH v8 0/3] Implement Sstc extension Atish Patra
@ 2022-08-04  1:42 ` Atish Patra
  2022-08-04  1:42 ` [PATCH v8 2/3] target/riscv: Add stimecmp support Atish Patra
  2022-08-04  1:42 ` [PATCH v8 3/3] target/riscv: Add vstimecmp support Atish Patra
  2 siblings, 0 replies; 13+ messages in thread
From: Atish Patra @ 2022-08-04  1:42 UTC (permalink / raw)
  To: qemu-devel
  Cc: Atish Patra, Anup Patel, Alistair Francis, Andrew Jones,
	Alistair Francis, Bin Meng, Palmer Dabbelt, qemu-riscv

Historically, The mtime/mtimecmp has been part of the CPU because
they are per hart entities. However, they actually belong to aclint
which is a MMIO device.

Move them to the ACLINT device. This also emulates the real hardware
more closely.

Reviewed-by: Anup Patel <anup@brainfault.org>
Reviewed-by: Alistair Francis <alistair.francis@wdc.com>
Reviewed-by: Andrew Jones <ajones@ventanamicro.com>
Signed-off-by: Atish Patra <atishp@rivosinc.com>
---
 hw/intc/riscv_aclint.c         | 41 ++++++++++++++++++++++++----------
 hw/timer/ibex_timer.c          | 18 ++++++---------
 include/hw/intc/riscv_aclint.h |  2 ++
 include/hw/timer/ibex_timer.h  |  2 ++
 target/riscv/cpu.h             |  2 --
 target/riscv/machine.c         |  5 ++---
 6 files changed, 42 insertions(+), 28 deletions(-)

diff --git a/hw/intc/riscv_aclint.c b/hw/intc/riscv_aclint.c
index e7942c4e5a32..a125c73d535c 100644
--- a/hw/intc/riscv_aclint.c
+++ b/hw/intc/riscv_aclint.c
@@ -32,6 +32,7 @@
 #include "hw/intc/riscv_aclint.h"
 #include "qemu/timer.h"
 #include "hw/irq.h"
+#include "migration/vmstate.h"
 
 typedef struct riscv_aclint_mtimer_callback {
     RISCVAclintMTimerState *s;
@@ -65,8 +66,8 @@ static void riscv_aclint_mtimer_write_timecmp(RISCVAclintMTimerState *mtimer,
 
     uint64_t rtc_r = cpu_riscv_read_rtc(mtimer);
 
-    cpu->env.timecmp = value;
-    if (cpu->env.timecmp <= rtc_r) {
+    mtimer->timecmp[hartid] = value;
+    if (mtimer->timecmp[hartid] <= rtc_r) {
         /*
          * If we're setting an MTIMECMP value in the "past",
          * immediately raise the timer interrupt
@@ -77,7 +78,7 @@ static void riscv_aclint_mtimer_write_timecmp(RISCVAclintMTimerState *mtimer,
 
     /* otherwise, set up the future timer interrupt */
     qemu_irq_lower(mtimer->timer_irqs[hartid - mtimer->hartid_base]);
-    diff = cpu->env.timecmp - rtc_r;
+    diff = mtimer->timecmp[hartid] - rtc_r;
     /* back to ns (note args switched in muldiv64) */
     uint64_t ns_diff = muldiv64(diff, NANOSECONDS_PER_SECOND, timebase_freq);
 
@@ -102,7 +103,7 @@ static void riscv_aclint_mtimer_write_timecmp(RISCVAclintMTimerState *mtimer,
         next = MIN(next, INT64_MAX);
     }
 
-    timer_mod(cpu->env.timer, next);
+    timer_mod(mtimer->timers[hartid], next);
 }
 
 /*
@@ -133,11 +134,11 @@ static uint64_t riscv_aclint_mtimer_read(void *opaque, hwaddr addr,
                           "aclint-mtimer: invalid hartid: %zu", hartid);
         } else if ((addr & 0x7) == 0) {
             /* timecmp_lo for RV32/RV64 or timecmp for RV64 */
-            uint64_t timecmp = env->timecmp;
+            uint64_t timecmp = mtimer->timecmp[hartid];
             return (size == 4) ? (timecmp & 0xFFFFFFFF) : timecmp;
         } else if ((addr & 0x7) == 4) {
             /* timecmp_hi */
-            uint64_t timecmp = env->timecmp;
+            uint64_t timecmp = mtimer->timecmp[hartid];
             return (timecmp >> 32) & 0xFFFFFFFF;
         } else {
             qemu_log_mask(LOG_UNIMP,
@@ -177,7 +178,7 @@ static void riscv_aclint_mtimer_write(void *opaque, hwaddr addr,
         } else if ((addr & 0x7) == 0) {
             if (size == 4) {
                 /* timecmp_lo for RV32/RV64 */
-                uint64_t timecmp_hi = env->timecmp >> 32;
+                uint64_t timecmp_hi = mtimer->timecmp[hartid] >> 32;
                 riscv_aclint_mtimer_write_timecmp(mtimer, RISCV_CPU(cpu), hartid,
                     timecmp_hi << 32 | (value & 0xFFFFFFFF));
             } else {
@@ -188,7 +189,7 @@ static void riscv_aclint_mtimer_write(void *opaque, hwaddr addr,
         } else if ((addr & 0x7) == 4) {
             if (size == 4) {
                 /* timecmp_hi for RV32/RV64 */
-                uint64_t timecmp_lo = env->timecmp;
+                uint64_t timecmp_lo = mtimer->timecmp[hartid];
                 riscv_aclint_mtimer_write_timecmp(mtimer, RISCV_CPU(cpu), hartid,
                     value << 32 | (timecmp_lo & 0xFFFFFFFF));
             } else {
@@ -234,7 +235,7 @@ static void riscv_aclint_mtimer_write(void *opaque, hwaddr addr,
             }
             riscv_aclint_mtimer_write_timecmp(mtimer, RISCV_CPU(cpu),
                                               mtimer->hartid_base + i,
-                                              env->timecmp);
+                                              mtimer->timecmp[i]);
         }
         return;
     }
@@ -284,6 +285,8 @@ static void riscv_aclint_mtimer_realize(DeviceState *dev, Error **errp)
     s->timer_irqs = g_new(qemu_irq, s->num_harts);
     qdev_init_gpio_out(dev, s->timer_irqs, s->num_harts);
 
+    s->timers = g_new0(QEMUTimer *, s->num_harts);
+    s->timecmp = g_new0(uint64_t, s->num_harts);
     /* Claim timer interrupt bits */
     for (i = 0; i < s->num_harts; i++) {
         RISCVCPU *cpu = RISCV_CPU(qemu_get_cpu(s->hartid_base + i));
@@ -310,6 +313,18 @@ static void riscv_aclint_mtimer_reset_enter(Object *obj, ResetType type)
     riscv_aclint_mtimer_write(mtimer, mtimer->time_base, 0, 8);
 }
 
+static const VMStateDescription vmstate_riscv_mtimer = {
+    .name = "riscv_mtimer",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .fields = (VMStateField[]) {
+            VMSTATE_VARRAY_UINT32(timecmp, RISCVAclintMTimerState,
+                                  num_harts, 0,
+                                  vmstate_info_uint64, uint64_t),
+            VMSTATE_END_OF_LIST()
+        }
+};
+
 static void riscv_aclint_mtimer_class_init(ObjectClass *klass, void *data)
 {
     DeviceClass *dc = DEVICE_CLASS(klass);
@@ -317,6 +332,7 @@ static void riscv_aclint_mtimer_class_init(ObjectClass *klass, void *data)
     device_class_set_props(dc, riscv_aclint_mtimer_properties);
     ResettableClass *rc = RESETTABLE_CLASS(klass);
     rc->phases.enter = riscv_aclint_mtimer_reset_enter;
+    dc->vmsd = &vmstate_riscv_mtimer;
 }
 
 static const TypeInfo riscv_aclint_mtimer_info = {
@@ -336,6 +352,7 @@ DeviceState *riscv_aclint_mtimer_create(hwaddr addr, hwaddr size,
 {
     int i;
     DeviceState *dev = qdev_new(TYPE_RISCV_ACLINT_MTIMER);
+    RISCVAclintMTimerState *s = RISCV_ACLINT_MTIMER(dev);
 
     assert(num_harts <= RISCV_ACLINT_MAX_HARTS);
     assert(!(addr & 0x7));
@@ -366,11 +383,11 @@ DeviceState *riscv_aclint_mtimer_create(hwaddr addr, hwaddr size,
             riscv_cpu_set_rdtime_fn(env, cpu_riscv_read_rtc, dev);
         }
 
-        cb->s = RISCV_ACLINT_MTIMER(dev);
+        cb->s = s;
         cb->num = i;
-        env->timer = timer_new_ns(QEMU_CLOCK_VIRTUAL,
+        s->timers[i] = timer_new_ns(QEMU_CLOCK_VIRTUAL,
                                   &riscv_aclint_mtimer_cb, cb);
-        env->timecmp = 0;
+        s->timecmp[i] = 0;
 
         qdev_connect_gpio_out(dev, i,
                               qdev_get_gpio_in(DEVICE(rvcpu), IRQ_M_TIMER));
diff --git a/hw/timer/ibex_timer.c b/hw/timer/ibex_timer.c
index 8c2ca364daab..d8b8e4e1f602 100644
--- a/hw/timer/ibex_timer.c
+++ b/hw/timer/ibex_timer.c
@@ -60,8 +60,6 @@ static uint64_t cpu_riscv_read_rtc(uint32_t timebase_freq)
 
 static void ibex_timer_update_irqs(IbexTimerState *s)
 {
-    CPUState *cs = qemu_get_cpu(0);
-    RISCVCPU *cpu = RISCV_CPU(cs);
     uint64_t value = s->timer_compare_lower0 |
                          ((uint64_t)s->timer_compare_upper0 << 32);
     uint64_t next, diff;
@@ -73,9 +71,9 @@ static void ibex_timer_update_irqs(IbexTimerState *s)
     }
 
     /* Update the CPUs mtimecmp */
-    cpu->env.timecmp = value;
+    s->mtimecmp = value;
 
-    if (cpu->env.timecmp <= now) {
+    if (s->mtimecmp <= now) {
         /*
          * If the mtimecmp was in the past raise the interrupt now.
          */
@@ -91,7 +89,7 @@ static void ibex_timer_update_irqs(IbexTimerState *s)
     qemu_irq_lower(s->m_timer_irq);
     qemu_set_irq(s->irq, false);
 
-    diff = cpu->env.timecmp - now;
+    diff = s->mtimecmp - now;
     next = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) +
                                  muldiv64(diff,
                                           NANOSECONDS_PER_SECOND,
@@ -99,9 +97,9 @@ static void ibex_timer_update_irqs(IbexTimerState *s)
 
     if (next < qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL)) {
         /* We overflowed the timer, just set it as large as we can */
-        timer_mod(cpu->env.timer, 0x7FFFFFFFFFFFFFFF);
+        timer_mod(s->mtimer, 0x7FFFFFFFFFFFFFFF);
     } else {
-        timer_mod(cpu->env.timer, next);
+        timer_mod(s->mtimer, next);
     }
 }
 
@@ -120,11 +118,9 @@ static void ibex_timer_reset(DeviceState *dev)
 {
     IbexTimerState *s = IBEX_TIMER(dev);
 
-    CPUState *cpu = qemu_get_cpu(0);
-    CPURISCVState *env = cpu->env_ptr;
-    env->timer = timer_new_ns(QEMU_CLOCK_VIRTUAL,
+    s->mtimer = timer_new_ns(QEMU_CLOCK_VIRTUAL,
                               &ibex_timer_cb, s);
-    env->timecmp = 0;
+    s->mtimecmp = 0;
 
     s->timer_ctrl = 0x00000000;
     s->timer_cfg0 = 0x00010000;
diff --git a/include/hw/intc/riscv_aclint.h b/include/hw/intc/riscv_aclint.h
index 26d4048687fb..693415eb6def 100644
--- a/include/hw/intc/riscv_aclint.h
+++ b/include/hw/intc/riscv_aclint.h
@@ -32,6 +32,8 @@ typedef struct RISCVAclintMTimerState {
     /*< private >*/
     SysBusDevice parent_obj;
     uint64_t time_delta;
+    uint64_t *timecmp;
+    QEMUTimer **timers;
 
     /*< public >*/
     MemoryRegion mmio;
diff --git a/include/hw/timer/ibex_timer.h b/include/hw/timer/ibex_timer.h
index 1a0a28d5fab5..41f5c82a920b 100644
--- a/include/hw/timer/ibex_timer.h
+++ b/include/hw/timer/ibex_timer.h
@@ -33,6 +33,8 @@ OBJECT_DECLARE_SIMPLE_TYPE(IbexTimerState, IBEX_TIMER)
 struct IbexTimerState {
     /* <private> */
     SysBusDevice parent_obj;
+    uint64_t mtimecmp;
+    QEMUTimer *mtimer; /* Internal timer for M-mode interrupt */
 
     /* <public> */
     MemoryRegion mmio;
diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h
index 4be4b82a837d..0fae1569945c 100644
--- a/target/riscv/cpu.h
+++ b/target/riscv/cpu.h
@@ -308,7 +308,6 @@ struct CPUArchState {
     /* temporary htif regs */
     uint64_t mfromhost;
     uint64_t mtohost;
-    uint64_t timecmp;
 
     /* physical memory protection */
     pmp_table_t pmp_state;
@@ -363,7 +362,6 @@ struct CPUArchState {
     float_status fp_status;
 
     /* Fields from here on are preserved across CPU reset. */
-    QEMUTimer *timer; /* Internal timer */
 
     hwaddr kernel_addr;
     hwaddr fdt_addr;
diff --git a/target/riscv/machine.c b/target/riscv/machine.c
index dc182ca81119..b508b042cb73 100644
--- a/target/riscv/machine.c
+++ b/target/riscv/machine.c
@@ -307,8 +307,8 @@ static const VMStateDescription vmstate_pmu_ctr_state = {
 
 const VMStateDescription vmstate_riscv_cpu = {
     .name = "cpu",
-    .version_id = 3,
-    .minimum_version_id = 3,
+    .version_id = 4,
+    .minimum_version_id = 4,
     .post_load = riscv_cpu_post_load,
     .fields = (VMStateField[]) {
         VMSTATE_UINTTL_ARRAY(env.gpr, RISCVCPU, 32),
@@ -359,7 +359,6 @@ const VMStateDescription vmstate_riscv_cpu = {
         VMSTATE_UINTTL(env.mscratch, RISCVCPU),
         VMSTATE_UINT64(env.mfromhost, RISCVCPU),
         VMSTATE_UINT64(env.mtohost, RISCVCPU),
-        VMSTATE_UINT64(env.timecmp, RISCVCPU),
 
         VMSTATE_END_OF_LIST()
     },
-- 
2.25.1



^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH v8  2/3] target/riscv: Add stimecmp support
  2022-08-04  1:42 [PATCH v8 0/3] Implement Sstc extension Atish Patra
  2022-08-04  1:42 ` [PATCH v8 1/3] hw/intc: Move mtimer/mtimecmp to aclint Atish Patra
@ 2022-08-04  1:42 ` Atish Patra
  2022-08-07 23:44   ` Alistair Francis
  2022-08-04  1:42 ` [PATCH v8 3/3] target/riscv: Add vstimecmp support Atish Patra
  2 siblings, 1 reply; 13+ messages in thread
From: Atish Patra @ 2022-08-04  1:42 UTC (permalink / raw)
  To: qemu-devel
  Cc: Atish Patra, Alistair Francis, Bin Meng, Palmer Dabbelt, qemu-riscv

stimecmp allows the supervisor mode to update stimecmp CSR directly
to program the next timer interrupt. This CSR is part of the Sstc
extension which was ratified recently.

Signed-off-by: Atish Patra <atishp@rivosinc.com>
---
 target/riscv/cpu.c         |  9 ++++
 target/riscv/cpu.h         |  5 ++
 target/riscv/cpu_bits.h    |  4 ++
 target/riscv/csr.c         | 77 ++++++++++++++++++++++++++++++
 target/riscv/machine.c     |  1 +
 target/riscv/meson.build   |  3 +-
 target/riscv/time_helper.c | 98 ++++++++++++++++++++++++++++++++++++++
 target/riscv/time_helper.h | 30 ++++++++++++
 8 files changed, 226 insertions(+), 1 deletion(-)
 create mode 100644 target/riscv/time_helper.c
 create mode 100644 target/riscv/time_helper.h

diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c
index d4635c7df46b..2498b93105fd 100644
--- a/target/riscv/cpu.c
+++ b/target/riscv/cpu.c
@@ -23,6 +23,7 @@
 #include "qemu/log.h"
 #include "cpu.h"
 #include "internals.h"
+#include "time_helper.h"
 #include "exec/exec-all.h"
 #include "qapi/error.h"
 #include "qemu/error-report.h"
@@ -99,6 +100,7 @@ static const struct isa_ext_data isa_edata_arr[] = {
     ISA_EXT_DATA_ENTRY(zve64f, true, PRIV_VERSION_1_12_0, ext_zve64f),
     ISA_EXT_DATA_ENTRY(zhinx, true, PRIV_VERSION_1_12_0, ext_zhinx),
     ISA_EXT_DATA_ENTRY(zhinxmin, true, PRIV_VERSION_1_12_0, ext_zhinxmin),
+    ISA_EXT_DATA_ENTRY(sstc, true, PRIV_VERSION_1_12_0, ext_sstc),
     ISA_EXT_DATA_ENTRY(svinval, true, PRIV_VERSION_1_12_0, ext_svinval),
     ISA_EXT_DATA_ENTRY(svnapot, true, PRIV_VERSION_1_12_0, ext_svnapot),
     ISA_EXT_DATA_ENTRY(svpbmt, true, PRIV_VERSION_1_12_0, ext_svpbmt),
@@ -675,6 +677,12 @@ static void riscv_cpu_realize(DeviceState *dev, Error **errp)
 
     set_resetvec(env, cpu->cfg.resetvec);
 
+#ifndef CONFIG_USER_ONLY
+    if (cpu->cfg.ext_sstc) {
+        riscv_timer_init(cpu);
+    }
+#endif /* CONFIG_USER_ONLY */
+
     /* Validate that MISA_MXL is set properly. */
     switch (env->misa_mxl_max) {
 #ifdef TARGET_RISCV64
@@ -995,6 +1003,7 @@ static Property riscv_cpu_extensions[] = {
     DEFINE_PROP_BOOL("Zve64f", RISCVCPU, cfg.ext_zve64f, false),
     DEFINE_PROP_BOOL("mmu", RISCVCPU, cfg.mmu, true),
     DEFINE_PROP_BOOL("pmp", RISCVCPU, cfg.pmp, true),
+    DEFINE_PROP_BOOL("sstc", RISCVCPU, cfg.ext_sstc, true),
 
     DEFINE_PROP_STRING("priv_spec", RISCVCPU, cfg.priv_spec),
     DEFINE_PROP_STRING("vext_spec", RISCVCPU, cfg.vext_spec),
diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h
index 0fae1569945c..4cda2905661e 100644
--- a/target/riscv/cpu.h
+++ b/target/riscv/cpu.h
@@ -309,6 +309,9 @@ struct CPUArchState {
     uint64_t mfromhost;
     uint64_t mtohost;
 
+    /* Sstc CSRs */
+    uint64_t stimecmp;
+
     /* physical memory protection */
     pmp_table_t pmp_state;
     target_ulong mseccfg;
@@ -362,6 +365,7 @@ struct CPUArchState {
     float_status fp_status;
 
     /* Fields from here on are preserved across CPU reset. */
+    QEMUTimer *stimer; /* Internal timer for S-mode interrupt */
 
     hwaddr kernel_addr;
     hwaddr fdt_addr;
@@ -425,6 +429,7 @@ struct RISCVCPUConfig {
     bool ext_ifencei;
     bool ext_icsr;
     bool ext_zihintpause;
+    bool ext_sstc;
     bool ext_svinval;
     bool ext_svnapot;
     bool ext_svpbmt;
diff --git a/target/riscv/cpu_bits.h b/target/riscv/cpu_bits.h
index 6be5a9e9f046..ac17cf1515c0 100644
--- a/target/riscv/cpu_bits.h
+++ b/target/riscv/cpu_bits.h
@@ -206,6 +206,10 @@
 #define CSR_STVAL           0x143
 #define CSR_SIP             0x144
 
+/* Sstc supervisor CSRs */
+#define CSR_STIMECMP        0x14D
+#define CSR_STIMECMPH       0x15D
+
 /* Supervisor Protection and Translation */
 #define CSR_SPTBR           0x180
 #define CSR_SATP            0x180
diff --git a/target/riscv/csr.c b/target/riscv/csr.c
index 0fb042b2fd0f..e18b000700e4 100644
--- a/target/riscv/csr.c
+++ b/target/riscv/csr.c
@@ -22,6 +22,7 @@
 #include "qemu/timer.h"
 #include "cpu.h"
 #include "pmu.h"
+#include "time_helper.h"
 #include "qemu/main-loop.h"
 #include "exec/exec-all.h"
 #include "sysemu/cpu-timers.h"
@@ -803,6 +804,72 @@ static RISCVException read_timeh(CPURISCVState *env, int csrno,
     return RISCV_EXCP_NONE;
 }
 
+static RISCVException sstc(CPURISCVState *env, int csrno)
+{
+    CPUState *cs = env_cpu(env);
+    RISCVCPU *cpu = RISCV_CPU(cs);
+
+    if (!cpu->cfg.ext_sstc || !env->rdtime_fn) {
+        return RISCV_EXCP_ILLEGAL_INST;
+    }
+
+    if (env->priv == PRV_M) {
+        return RISCV_EXCP_NONE;
+    }
+
+    /*
+     * No need of separate function for rv32 as menvcfg stores both menvcfg
+     * menvcfgh for RV32.
+     */
+    if (!(get_field(env->mcounteren, COUNTEREN_TM) &&
+          get_field(env->menvcfg, MENVCFG_STCE))) {
+        return RISCV_EXCP_ILLEGAL_INST;
+    }
+
+    return smode(env, csrno);
+}
+
+static RISCVException read_stimecmp(CPURISCVState *env, int csrno,
+                                    target_ulong *val)
+{
+    *val = env->stimecmp;
+    return RISCV_EXCP_NONE;
+}
+
+static RISCVException read_stimecmph(CPURISCVState *env, int csrno,
+                                    target_ulong *val)
+{
+    *val = env->stimecmp >> 32;
+    return RISCV_EXCP_NONE;
+}
+
+static RISCVException write_stimecmp(CPURISCVState *env, int csrno,
+                                    target_ulong val)
+{
+    RISCVCPU *cpu = env_archcpu(env);
+
+    if (riscv_cpu_mxl(env) == MXL_RV32) {
+        env->stimecmp = deposit64(env->stimecmp, 0, 32, (uint64_t)val);
+    } else {
+        env->stimecmp = val;
+    }
+
+    riscv_timer_write_timecmp(cpu, env->stimer, env->stimecmp, 0, MIP_STIP);
+
+    return RISCV_EXCP_NONE;
+}
+
+static RISCVException write_stimecmph(CPURISCVState *env, int csrno,
+                                    target_ulong val)
+{
+    RISCVCPU *cpu = env_archcpu(env);
+
+    env->stimecmp = deposit64(env->stimecmp, 32, 32, (uint64_t)val);
+    riscv_timer_write_timecmp(cpu, env->stimer, env->stimecmp, 0, MIP_STIP);
+
+    return RISCV_EXCP_NONE;
+}
+
 /* Machine constants */
 
 #define M_MODE_INTERRUPTS  ((uint64_t)(MIP_MSIP | MIP_MTIP | MIP_MEIP))
@@ -1719,6 +1786,12 @@ static RISCVException rmw_mip64(CPURISCVState *env, int csrno,
         new_val |= env->external_seip * MIP_SEIP;
     }
 
+    if (cpu->cfg.ext_sstc && (env->priv == PRV_M) &&
+        get_field(env->menvcfg, MENVCFG_STCE)) {
+        /* sstc extension forbids STIP & VSTIP to be writeable in mip */
+        mask = mask & ~(MIP_STIP | MIP_VSTIP);
+    }
+
     if (mask) {
         old_mip = riscv_cpu_update_mip(cpu, mask, (new_val & mask));
     } else {
@@ -3584,6 +3657,10 @@ riscv_csr_operations csr_ops[CSR_TABLE_SIZE] = {
     [CSR_SCAUSE]   = { "scause",   smode, read_scause,   write_scause   },
     [CSR_STVAL]    = { "stval",    smode, read_stval,    write_stval    },
     [CSR_SIP]      = { "sip",      smode, NULL,    NULL, rmw_sip        },
+    [CSR_STIMECMP] = { "stimecmp", sstc, read_stimecmp, write_stimecmp,
+                                          .min_priv_ver = PRIV_VERSION_1_12_0 },
+    [CSR_STIMECMPH] = { "stimecmph", sstc, read_stimecmph, write_stimecmph,
+                                          .min_priv_ver = PRIV_VERSION_1_12_0 },
 
     /* Supervisor Protection and Translation */
     [CSR_SATP]     = { "satp",     smode, read_satp,     write_satp     },
diff --git a/target/riscv/machine.c b/target/riscv/machine.c
index b508b042cb73..622fface484e 100644
--- a/target/riscv/machine.c
+++ b/target/riscv/machine.c
@@ -359,6 +359,7 @@ const VMStateDescription vmstate_riscv_cpu = {
         VMSTATE_UINTTL(env.mscratch, RISCVCPU),
         VMSTATE_UINT64(env.mfromhost, RISCVCPU),
         VMSTATE_UINT64(env.mtohost, RISCVCPU),
+        VMSTATE_UINT64(env.stimecmp, RISCVCPU),
 
         VMSTATE_END_OF_LIST()
     },
diff --git a/target/riscv/meson.build b/target/riscv/meson.build
index 2c1975e72c4e..24893c614ee4 100644
--- a/target/riscv/meson.build
+++ b/target/riscv/meson.build
@@ -31,7 +31,8 @@ riscv_softmmu_ss.add(files(
   'debug.c',
   'monitor.c',
   'machine.c',
-  'pmu.c'
+  'pmu.c',
+  'time_helper.c'
 ))
 
 target_arch += {'riscv': riscv_ss}
diff --git a/target/riscv/time_helper.c b/target/riscv/time_helper.c
new file mode 100644
index 000000000000..f3fb5eac7b7b
--- /dev/null
+++ b/target/riscv/time_helper.c
@@ -0,0 +1,98 @@
+/*
+ * RISC-V timer helper implementation.
+ *
+ * Copyright (c) 2022 Rivos Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2 or later, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "qemu/osdep.h"
+#include "qemu/log.h"
+#include "cpu_bits.h"
+#include "time_helper.h"
+#include "hw/intc/riscv_aclint.h"
+
+static void riscv_stimer_cb(void *opaque)
+{
+    RISCVCPU *cpu = opaque;
+    riscv_cpu_update_mip(cpu, MIP_STIP, BOOL_TO_MASK(1));
+}
+
+/*
+ * Called when timecmp is written to update the QEMU timer or immediately
+ * trigger timer interrupt if mtimecmp <= current timer value.
+ */
+void riscv_timer_write_timecmp(RISCVCPU *cpu, QEMUTimer *timer,
+                               uint64_t timecmp, uint64_t delta,
+                               uint32_t timer_irq)
+{
+    uint64_t diff, ns_diff, next;
+    CPURISCVState *env = &cpu->env;
+    RISCVAclintMTimerState *mtimer = env->rdtime_fn_arg;
+    uint32_t timebase_freq = mtimer->timebase_freq;
+    uint64_t rtc_r = env->rdtime_fn(env->rdtime_fn_arg) + delta;
+
+    if (timecmp <= rtc_r) {
+        /*
+         * If we're setting an stimecmp value in the "past",
+         * immediately raise the timer interrupt
+         */
+        riscv_cpu_update_mip(cpu, timer_irq, BOOL_TO_MASK(1));
+        return;
+    }
+
+    /* Clear the [V]STIP bit in mip */
+    riscv_cpu_update_mip(cpu, timer_irq, BOOL_TO_MASK(0));
+
+    /* otherwise, set up the future timer interrupt */
+    diff = timecmp - rtc_r;
+    /* back to ns (note args switched in muldiv64) */
+    ns_diff = muldiv64(diff, NANOSECONDS_PER_SECOND, timebase_freq);
+
+    /*
+     * check if ns_diff overflowed and check if the addition would potentially
+     * overflow
+     */
+    if ((NANOSECONDS_PER_SECOND > timebase_freq && ns_diff < diff) ||
+        ns_diff > INT64_MAX) {
+        next = INT64_MAX;
+    } else {
+        /*
+         * as it is very unlikely qemu_clock_get_ns will return a value
+         * greater than INT64_MAX, no additional check is needed for an
+         * unsigned integer overflow.
+         */
+        next = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + ns_diff;
+        /*
+         * if ns_diff is INT64_MAX next may still be outside the range
+         * of a signed integer.
+         */
+        next = MIN(next, INT64_MAX);
+    }
+
+    timer_mod(timer, next);
+}
+
+void riscv_timer_init(RISCVCPU *cpu)
+{
+    CPURISCVState *env;
+
+    if (!cpu) {
+        return;
+    }
+
+    env = &cpu->env;
+    env->stimer = timer_new_ns(QEMU_CLOCK_VIRTUAL, &riscv_stimer_cb, cpu);
+    env->stimecmp = 0;
+
+}
diff --git a/target/riscv/time_helper.h b/target/riscv/time_helper.h
new file mode 100644
index 000000000000..7b3cdcc35020
--- /dev/null
+++ b/target/riscv/time_helper.h
@@ -0,0 +1,30 @@
+/*
+ * RISC-V timer header file.
+ *
+ * Copyright (c) 2022 Rivos Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2 or later, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef RISCV_TIME_HELPER_H
+#define RISCV_TIME_HELPER_H
+
+#include "cpu.h"
+#include "qemu/timer.h"
+
+void riscv_timer_write_timecmp(RISCVCPU *cpu, QEMUTimer *timer,
+                               uint64_t timecmp, uint64_t delta,
+                               uint32_t timer_irq);
+void riscv_timer_init(RISCVCPU *cpu);
+
+#endif
-- 
2.25.1



^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH v8  3/3] target/riscv: Add vstimecmp support
  2022-08-04  1:42 [PATCH v8 0/3] Implement Sstc extension Atish Patra
  2022-08-04  1:42 ` [PATCH v8 1/3] hw/intc: Move mtimer/mtimecmp to aclint Atish Patra
  2022-08-04  1:42 ` [PATCH v8 2/3] target/riscv: Add stimecmp support Atish Patra
@ 2022-08-04  1:42 ` Atish Patra
  2022-08-08  0:01   ` Alistair Francis
  2022-08-08  1:49   ` Weiwei Li
  2 siblings, 2 replies; 13+ messages in thread
From: Atish Patra @ 2022-08-04  1:42 UTC (permalink / raw)
  To: qemu-devel
  Cc: Atish Patra, Alistair Francis, Bin Meng, Palmer Dabbelt, qemu-riscv

vstimecmp CSR allows the guest OS or to program the next guest timer
interrupt directly. Thus, hypervisor no longer need to inject the
timer interrupt to the guest if vstimecmp is used. This was ratified
as a part of the Sstc extension.

Signed-off-by: Atish Patra <atishp@rivosinc.com>
---
 target/riscv/cpu.h         |   4 ++
 target/riscv/cpu_bits.h    |   4 ++
 target/riscv/cpu_helper.c  |  11 ++--
 target/riscv/csr.c         | 102 ++++++++++++++++++++++++++++++++++++-
 target/riscv/machine.c     |   1 +
 target/riscv/time_helper.c |  16 ++++++
 6 files changed, 133 insertions(+), 5 deletions(-)

diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h
index 4cda2905661e..1fd382b2717f 100644
--- a/target/riscv/cpu.h
+++ b/target/riscv/cpu.h
@@ -312,6 +312,8 @@ struct CPUArchState {
     /* Sstc CSRs */
     uint64_t stimecmp;
 
+    uint64_t vstimecmp;
+
     /* physical memory protection */
     pmp_table_t pmp_state;
     target_ulong mseccfg;
@@ -366,6 +368,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;
diff --git a/target/riscv/cpu_bits.h b/target/riscv/cpu_bits.h
index ac17cf1515c0..095dab19f512 100644
--- a/target/riscv/cpu_bits.h
+++ b/target/riscv/cpu_bits.h
@@ -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
 
diff --git a/target/riscv/cpu_helper.c b/target/riscv/cpu_helper.c
index 650574accf0a..1e4faa84e839 100644
--- a/target/riscv/cpu_helper.c
+++ b/target/riscv/cpu_helper.c
@@ -345,8 +345,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)
@@ -605,7 +606,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)) {
@@ -613,6 +614,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();
@@ -620,7 +625,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);
diff --git a/target/riscv/csr.c b/target/riscv/csr.c
index e18b000700e4..9da4d6515e7b 100644
--- a/target/riscv/csr.c
+++ b/target/riscv/csr.c
@@ -829,17 +829,100 @@ static RISCVException sstc(CPURISCVState *env, int csrno)
     return smode(env, csrno);
 }
 
+static RISCVException sstc_hmode(CPURISCVState *env, int csrno)
+{
+    CPUState *cs = env_cpu(env);
+    RISCVCPU *cpu = RISCV_CPU(cs);
+
+    if (!cpu->cfg.ext_sstc || !env->rdtime_fn) {
+        return RISCV_EXCP_ILLEGAL_INST;
+    }
+
+    if (env->priv == PRV_M) {
+        return RISCV_EXCP_NONE;
+    }
+
+    if (!(get_field(env->mcounteren, COUNTEREN_TM) &
+          get_field(env->menvcfg, MENVCFG_STCE))) {
+        return RISCV_EXCP_ILLEGAL_INST;
+    }
+
+    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;
+        }
+    }
+
+    return hmode(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;
 }
 
@@ -848,6 +931,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 {
@@ -864,6 +951,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);
 
@@ -1801,6 +1892,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) {
@@ -3661,6 +3753,12 @@ riscv_csr_operations csr_ops[CSR_TABLE_SIZE] = {
                                           .min_priv_ver = PRIV_VERSION_1_12_0 },
     [CSR_STIMECMPH] = { "stimecmph", sstc, read_stimecmph, write_stimecmph,
                                           .min_priv_ver = PRIV_VERSION_1_12_0 },
+    [CSR_VSTIMECMP] = { "vstimecmp", sstc_hmode, read_vstimecmp,
+                                          write_vstimecmp,
+                                          .min_priv_ver = PRIV_VERSION_1_12_0 },
+    [CSR_VSTIMECMPH] = { "vstimecmph", sstc_hmode, read_vstimecmph,
+                                          write_vstimecmph,
+                                          .min_priv_ver = PRIV_VERSION_1_12_0 },
 
     /* Supervisor Protection and Translation */
     [CSR_SATP]     = { "satp",     smode, read_satp,     write_satp     },
diff --git a/target/riscv/machine.c b/target/riscv/machine.c
index 622fface484e..4ba55705d147 100644
--- a/target/riscv/machine.c
+++ b/target/riscv/machine.c
@@ -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),
diff --git a/target/riscv/time_helper.c b/target/riscv/time_helper.c
index f3fb5eac7b7b..8cce667dfd47 100644
--- a/target/riscv/time_helper.c
+++ b/target/riscv/time_helper.c
@@ -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;
 }
-- 
2.25.1



^ permalink raw reply related	[flat|nested] 13+ messages in thread

* Re: [PATCH v8 2/3] target/riscv: Add stimecmp support
  2022-08-04  1:42 ` [PATCH v8 2/3] target/riscv: Add stimecmp support Atish Patra
@ 2022-08-07 23:44   ` Alistair Francis
  0 siblings, 0 replies; 13+ messages in thread
From: Alistair Francis @ 2022-08-07 23:44 UTC (permalink / raw)
  To: Atish Patra
  Cc: qemu-devel@nongnu.org Developers, Alistair Francis, Bin Meng,
	Palmer Dabbelt, open list:RISC-V

On Thu, Aug 4, 2022 at 11:47 AM Atish Patra <atishp@rivosinc.com> wrote:
>
> stimecmp allows the supervisor mode to update stimecmp CSR directly
> to program the next timer interrupt. This CSR is part of the Sstc
> extension which was ratified recently.
>
> Signed-off-by: Atish Patra <atishp@rivosinc.com>

Reviewed-by: Alistair Francis <alistair.francis@wdc.com>

Alistair

> ---
>  target/riscv/cpu.c         |  9 ++++
>  target/riscv/cpu.h         |  5 ++
>  target/riscv/cpu_bits.h    |  4 ++
>  target/riscv/csr.c         | 77 ++++++++++++++++++++++++++++++
>  target/riscv/machine.c     |  1 +
>  target/riscv/meson.build   |  3 +-
>  target/riscv/time_helper.c | 98 ++++++++++++++++++++++++++++++++++++++
>  target/riscv/time_helper.h | 30 ++++++++++++
>  8 files changed, 226 insertions(+), 1 deletion(-)
>  create mode 100644 target/riscv/time_helper.c
>  create mode 100644 target/riscv/time_helper.h
>
> diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c
> index d4635c7df46b..2498b93105fd 100644
> --- a/target/riscv/cpu.c
> +++ b/target/riscv/cpu.c
> @@ -23,6 +23,7 @@
>  #include "qemu/log.h"
>  #include "cpu.h"
>  #include "internals.h"
> +#include "time_helper.h"
>  #include "exec/exec-all.h"
>  #include "qapi/error.h"
>  #include "qemu/error-report.h"
> @@ -99,6 +100,7 @@ static const struct isa_ext_data isa_edata_arr[] = {
>      ISA_EXT_DATA_ENTRY(zve64f, true, PRIV_VERSION_1_12_0, ext_zve64f),
>      ISA_EXT_DATA_ENTRY(zhinx, true, PRIV_VERSION_1_12_0, ext_zhinx),
>      ISA_EXT_DATA_ENTRY(zhinxmin, true, PRIV_VERSION_1_12_0, ext_zhinxmin),
> +    ISA_EXT_DATA_ENTRY(sstc, true, PRIV_VERSION_1_12_0, ext_sstc),
>      ISA_EXT_DATA_ENTRY(svinval, true, PRIV_VERSION_1_12_0, ext_svinval),
>      ISA_EXT_DATA_ENTRY(svnapot, true, PRIV_VERSION_1_12_0, ext_svnapot),
>      ISA_EXT_DATA_ENTRY(svpbmt, true, PRIV_VERSION_1_12_0, ext_svpbmt),
> @@ -675,6 +677,12 @@ static void riscv_cpu_realize(DeviceState *dev, Error **errp)
>
>      set_resetvec(env, cpu->cfg.resetvec);
>
> +#ifndef CONFIG_USER_ONLY
> +    if (cpu->cfg.ext_sstc) {
> +        riscv_timer_init(cpu);
> +    }
> +#endif /* CONFIG_USER_ONLY */
> +
>      /* Validate that MISA_MXL is set properly. */
>      switch (env->misa_mxl_max) {
>  #ifdef TARGET_RISCV64
> @@ -995,6 +1003,7 @@ static Property riscv_cpu_extensions[] = {
>      DEFINE_PROP_BOOL("Zve64f", RISCVCPU, cfg.ext_zve64f, false),
>      DEFINE_PROP_BOOL("mmu", RISCVCPU, cfg.mmu, true),
>      DEFINE_PROP_BOOL("pmp", RISCVCPU, cfg.pmp, true),
> +    DEFINE_PROP_BOOL("sstc", RISCVCPU, cfg.ext_sstc, true),
>
>      DEFINE_PROP_STRING("priv_spec", RISCVCPU, cfg.priv_spec),
>      DEFINE_PROP_STRING("vext_spec", RISCVCPU, cfg.vext_spec),
> diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h
> index 0fae1569945c..4cda2905661e 100644
> --- a/target/riscv/cpu.h
> +++ b/target/riscv/cpu.h
> @@ -309,6 +309,9 @@ struct CPUArchState {
>      uint64_t mfromhost;
>      uint64_t mtohost;
>
> +    /* Sstc CSRs */
> +    uint64_t stimecmp;
> +
>      /* physical memory protection */
>      pmp_table_t pmp_state;
>      target_ulong mseccfg;
> @@ -362,6 +365,7 @@ struct CPUArchState {
>      float_status fp_status;
>
>      /* Fields from here on are preserved across CPU reset. */
> +    QEMUTimer *stimer; /* Internal timer for S-mode interrupt */
>
>      hwaddr kernel_addr;
>      hwaddr fdt_addr;
> @@ -425,6 +429,7 @@ struct RISCVCPUConfig {
>      bool ext_ifencei;
>      bool ext_icsr;
>      bool ext_zihintpause;
> +    bool ext_sstc;
>      bool ext_svinval;
>      bool ext_svnapot;
>      bool ext_svpbmt;
> diff --git a/target/riscv/cpu_bits.h b/target/riscv/cpu_bits.h
> index 6be5a9e9f046..ac17cf1515c0 100644
> --- a/target/riscv/cpu_bits.h
> +++ b/target/riscv/cpu_bits.h
> @@ -206,6 +206,10 @@
>  #define CSR_STVAL           0x143
>  #define CSR_SIP             0x144
>
> +/* Sstc supervisor CSRs */
> +#define CSR_STIMECMP        0x14D
> +#define CSR_STIMECMPH       0x15D
> +
>  /* Supervisor Protection and Translation */
>  #define CSR_SPTBR           0x180
>  #define CSR_SATP            0x180
> diff --git a/target/riscv/csr.c b/target/riscv/csr.c
> index 0fb042b2fd0f..e18b000700e4 100644
> --- a/target/riscv/csr.c
> +++ b/target/riscv/csr.c
> @@ -22,6 +22,7 @@
>  #include "qemu/timer.h"
>  #include "cpu.h"
>  #include "pmu.h"
> +#include "time_helper.h"
>  #include "qemu/main-loop.h"
>  #include "exec/exec-all.h"
>  #include "sysemu/cpu-timers.h"
> @@ -803,6 +804,72 @@ static RISCVException read_timeh(CPURISCVState *env, int csrno,
>      return RISCV_EXCP_NONE;
>  }
>
> +static RISCVException sstc(CPURISCVState *env, int csrno)
> +{
> +    CPUState *cs = env_cpu(env);
> +    RISCVCPU *cpu = RISCV_CPU(cs);
> +
> +    if (!cpu->cfg.ext_sstc || !env->rdtime_fn) {
> +        return RISCV_EXCP_ILLEGAL_INST;
> +    }
> +
> +    if (env->priv == PRV_M) {
> +        return RISCV_EXCP_NONE;
> +    }
> +
> +    /*
> +     * No need of separate function for rv32 as menvcfg stores both menvcfg
> +     * menvcfgh for RV32.
> +     */
> +    if (!(get_field(env->mcounteren, COUNTEREN_TM) &&
> +          get_field(env->menvcfg, MENVCFG_STCE))) {
> +        return RISCV_EXCP_ILLEGAL_INST;
> +    }
> +
> +    return smode(env, csrno);
> +}
> +
> +static RISCVException read_stimecmp(CPURISCVState *env, int csrno,
> +                                    target_ulong *val)
> +{
> +    *val = env->stimecmp;
> +    return RISCV_EXCP_NONE;
> +}
> +
> +static RISCVException read_stimecmph(CPURISCVState *env, int csrno,
> +                                    target_ulong *val)
> +{
> +    *val = env->stimecmp >> 32;
> +    return RISCV_EXCP_NONE;
> +}
> +
> +static RISCVException write_stimecmp(CPURISCVState *env, int csrno,
> +                                    target_ulong val)
> +{
> +    RISCVCPU *cpu = env_archcpu(env);
> +
> +    if (riscv_cpu_mxl(env) == MXL_RV32) {
> +        env->stimecmp = deposit64(env->stimecmp, 0, 32, (uint64_t)val);
> +    } else {
> +        env->stimecmp = val;
> +    }
> +
> +    riscv_timer_write_timecmp(cpu, env->stimer, env->stimecmp, 0, MIP_STIP);
> +
> +    return RISCV_EXCP_NONE;
> +}
> +
> +static RISCVException write_stimecmph(CPURISCVState *env, int csrno,
> +                                    target_ulong val)
> +{
> +    RISCVCPU *cpu = env_archcpu(env);
> +
> +    env->stimecmp = deposit64(env->stimecmp, 32, 32, (uint64_t)val);
> +    riscv_timer_write_timecmp(cpu, env->stimer, env->stimecmp, 0, MIP_STIP);
> +
> +    return RISCV_EXCP_NONE;
> +}
> +
>  /* Machine constants */
>
>  #define M_MODE_INTERRUPTS  ((uint64_t)(MIP_MSIP | MIP_MTIP | MIP_MEIP))
> @@ -1719,6 +1786,12 @@ static RISCVException rmw_mip64(CPURISCVState *env, int csrno,
>          new_val |= env->external_seip * MIP_SEIP;
>      }
>
> +    if (cpu->cfg.ext_sstc && (env->priv == PRV_M) &&
> +        get_field(env->menvcfg, MENVCFG_STCE)) {
> +        /* sstc extension forbids STIP & VSTIP to be writeable in mip */
> +        mask = mask & ~(MIP_STIP | MIP_VSTIP);
> +    }
> +
>      if (mask) {
>          old_mip = riscv_cpu_update_mip(cpu, mask, (new_val & mask));
>      } else {
> @@ -3584,6 +3657,10 @@ riscv_csr_operations csr_ops[CSR_TABLE_SIZE] = {
>      [CSR_SCAUSE]   = { "scause",   smode, read_scause,   write_scause   },
>      [CSR_STVAL]    = { "stval",    smode, read_stval,    write_stval    },
>      [CSR_SIP]      = { "sip",      smode, NULL,    NULL, rmw_sip        },
> +    [CSR_STIMECMP] = { "stimecmp", sstc, read_stimecmp, write_stimecmp,
> +                                          .min_priv_ver = PRIV_VERSION_1_12_0 },
> +    [CSR_STIMECMPH] = { "stimecmph", sstc, read_stimecmph, write_stimecmph,
> +                                          .min_priv_ver = PRIV_VERSION_1_12_0 },
>
>      /* Supervisor Protection and Translation */
>      [CSR_SATP]     = { "satp",     smode, read_satp,     write_satp     },
> diff --git a/target/riscv/machine.c b/target/riscv/machine.c
> index b508b042cb73..622fface484e 100644
> --- a/target/riscv/machine.c
> +++ b/target/riscv/machine.c
> @@ -359,6 +359,7 @@ const VMStateDescription vmstate_riscv_cpu = {
>          VMSTATE_UINTTL(env.mscratch, RISCVCPU),
>          VMSTATE_UINT64(env.mfromhost, RISCVCPU),
>          VMSTATE_UINT64(env.mtohost, RISCVCPU),
> +        VMSTATE_UINT64(env.stimecmp, RISCVCPU),
>
>          VMSTATE_END_OF_LIST()
>      },
> diff --git a/target/riscv/meson.build b/target/riscv/meson.build
> index 2c1975e72c4e..24893c614ee4 100644
> --- a/target/riscv/meson.build
> +++ b/target/riscv/meson.build
> @@ -31,7 +31,8 @@ riscv_softmmu_ss.add(files(
>    'debug.c',
>    'monitor.c',
>    'machine.c',
> -  'pmu.c'
> +  'pmu.c',
> +  'time_helper.c'
>  ))
>
>  target_arch += {'riscv': riscv_ss}
> diff --git a/target/riscv/time_helper.c b/target/riscv/time_helper.c
> new file mode 100644
> index 000000000000..f3fb5eac7b7b
> --- /dev/null
> +++ b/target/riscv/time_helper.c
> @@ -0,0 +1,98 @@
> +/*
> + * RISC-V timer helper implementation.
> + *
> + * Copyright (c) 2022 Rivos Inc.
> + *
> + * This program is free software; you can redistribute it and/or modify it
> + * under the terms and conditions of the GNU General Public License,
> + * version 2 or later, as published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope it will be useful, but WITHOUT
> + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
> + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
> + * more details.
> + *
> + * You should have received a copy of the GNU General Public License along with
> + * this program.  If not, see <http://www.gnu.org/licenses/>.
> + */
> +
> +#include "qemu/osdep.h"
> +#include "qemu/log.h"
> +#include "cpu_bits.h"
> +#include "time_helper.h"
> +#include "hw/intc/riscv_aclint.h"
> +
> +static void riscv_stimer_cb(void *opaque)
> +{
> +    RISCVCPU *cpu = opaque;
> +    riscv_cpu_update_mip(cpu, MIP_STIP, BOOL_TO_MASK(1));
> +}
> +
> +/*
> + * Called when timecmp is written to update the QEMU timer or immediately
> + * trigger timer interrupt if mtimecmp <= current timer value.
> + */
> +void riscv_timer_write_timecmp(RISCVCPU *cpu, QEMUTimer *timer,
> +                               uint64_t timecmp, uint64_t delta,
> +                               uint32_t timer_irq)
> +{
> +    uint64_t diff, ns_diff, next;
> +    CPURISCVState *env = &cpu->env;
> +    RISCVAclintMTimerState *mtimer = env->rdtime_fn_arg;
> +    uint32_t timebase_freq = mtimer->timebase_freq;
> +    uint64_t rtc_r = env->rdtime_fn(env->rdtime_fn_arg) + delta;
> +
> +    if (timecmp <= rtc_r) {
> +        /*
> +         * If we're setting an stimecmp value in the "past",
> +         * immediately raise the timer interrupt
> +         */
> +        riscv_cpu_update_mip(cpu, timer_irq, BOOL_TO_MASK(1));
> +        return;
> +    }
> +
> +    /* Clear the [V]STIP bit in mip */
> +    riscv_cpu_update_mip(cpu, timer_irq, BOOL_TO_MASK(0));
> +
> +    /* otherwise, set up the future timer interrupt */
> +    diff = timecmp - rtc_r;
> +    /* back to ns (note args switched in muldiv64) */
> +    ns_diff = muldiv64(diff, NANOSECONDS_PER_SECOND, timebase_freq);
> +
> +    /*
> +     * check if ns_diff overflowed and check if the addition would potentially
> +     * overflow
> +     */
> +    if ((NANOSECONDS_PER_SECOND > timebase_freq && ns_diff < diff) ||
> +        ns_diff > INT64_MAX) {
> +        next = INT64_MAX;
> +    } else {
> +        /*
> +         * as it is very unlikely qemu_clock_get_ns will return a value
> +         * greater than INT64_MAX, no additional check is needed for an
> +         * unsigned integer overflow.
> +         */
> +        next = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + ns_diff;
> +        /*
> +         * if ns_diff is INT64_MAX next may still be outside the range
> +         * of a signed integer.
> +         */
> +        next = MIN(next, INT64_MAX);
> +    }
> +
> +    timer_mod(timer, next);
> +}
> +
> +void riscv_timer_init(RISCVCPU *cpu)
> +{
> +    CPURISCVState *env;
> +
> +    if (!cpu) {
> +        return;
> +    }
> +
> +    env = &cpu->env;
> +    env->stimer = timer_new_ns(QEMU_CLOCK_VIRTUAL, &riscv_stimer_cb, cpu);
> +    env->stimecmp = 0;
> +
> +}
> diff --git a/target/riscv/time_helper.h b/target/riscv/time_helper.h
> new file mode 100644
> index 000000000000..7b3cdcc35020
> --- /dev/null
> +++ b/target/riscv/time_helper.h
> @@ -0,0 +1,30 @@
> +/*
> + * RISC-V timer header file.
> + *
> + * Copyright (c) 2022 Rivos Inc.
> + *
> + * This program is free software; you can redistribute it and/or modify it
> + * under the terms and conditions of the GNU General Public License,
> + * version 2 or later, as published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope it will be useful, but WITHOUT
> + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
> + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
> + * more details.
> + *
> + * You should have received a copy of the GNU General Public License along with
> + * this program.  If not, see <http://www.gnu.org/licenses/>.
> + */
> +
> +#ifndef RISCV_TIME_HELPER_H
> +#define RISCV_TIME_HELPER_H
> +
> +#include "cpu.h"
> +#include "qemu/timer.h"
> +
> +void riscv_timer_write_timecmp(RISCVCPU *cpu, QEMUTimer *timer,
> +                               uint64_t timecmp, uint64_t delta,
> +                               uint32_t timer_irq);
> +void riscv_timer_init(RISCVCPU *cpu);
> +
> +#endif
> --
> 2.25.1
>
>


^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH v8 3/3] target/riscv: Add vstimecmp support
  2022-08-04  1:42 ` [PATCH v8 3/3] target/riscv: Add vstimecmp support Atish Patra
@ 2022-08-08  0:01   ` Alistair Francis
  2022-08-08  1:49   ` Weiwei Li
  1 sibling, 0 replies; 13+ messages in thread
From: Alistair Francis @ 2022-08-08  0:01 UTC (permalink / raw)
  To: Atish Patra
  Cc: qemu-devel@nongnu.org Developers, Alistair Francis, Bin Meng,
	Palmer Dabbelt, open list:RISC-V

On Thu, Aug 4, 2022 at 11:47 AM Atish Patra <atishp@rivosinc.com> wrote:
>
> vstimecmp CSR allows the guest OS or to program the next guest timer
> interrupt directly. Thus, hypervisor no longer need to inject the
> timer interrupt to the guest if vstimecmp is used. This was ratified
> as a part of the Sstc extension.
>
> Signed-off-by: Atish Patra <atishp@rivosinc.com>

Reviewed-by: Alistair Francis <alistair.francis@wdc.com>

Alistair

> ---
>  target/riscv/cpu.h         |   4 ++
>  target/riscv/cpu_bits.h    |   4 ++
>  target/riscv/cpu_helper.c  |  11 ++--
>  target/riscv/csr.c         | 102 ++++++++++++++++++++++++++++++++++++-
>  target/riscv/machine.c     |   1 +
>  target/riscv/time_helper.c |  16 ++++++
>  6 files changed, 133 insertions(+), 5 deletions(-)
>
> diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h
> index 4cda2905661e..1fd382b2717f 100644
> --- a/target/riscv/cpu.h
> +++ b/target/riscv/cpu.h
> @@ -312,6 +312,8 @@ struct CPUArchState {
>      /* Sstc CSRs */
>      uint64_t stimecmp;
>
> +    uint64_t vstimecmp;
> +
>      /* physical memory protection */
>      pmp_table_t pmp_state;
>      target_ulong mseccfg;
> @@ -366,6 +368,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;
> diff --git a/target/riscv/cpu_bits.h b/target/riscv/cpu_bits.h
> index ac17cf1515c0..095dab19f512 100644
> --- a/target/riscv/cpu_bits.h
> +++ b/target/riscv/cpu_bits.h
> @@ -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
>
> diff --git a/target/riscv/cpu_helper.c b/target/riscv/cpu_helper.c
> index 650574accf0a..1e4faa84e839 100644
> --- a/target/riscv/cpu_helper.c
> +++ b/target/riscv/cpu_helper.c
> @@ -345,8 +345,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)
> @@ -605,7 +606,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)) {
> @@ -613,6 +614,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();
> @@ -620,7 +625,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);
> diff --git a/target/riscv/csr.c b/target/riscv/csr.c
> index e18b000700e4..9da4d6515e7b 100644
> --- a/target/riscv/csr.c
> +++ b/target/riscv/csr.c
> @@ -829,17 +829,100 @@ static RISCVException sstc(CPURISCVState *env, int csrno)
>      return smode(env, csrno);
>  }
>
> +static RISCVException sstc_hmode(CPURISCVState *env, int csrno)
> +{
> +    CPUState *cs = env_cpu(env);
> +    RISCVCPU *cpu = RISCV_CPU(cs);
> +
> +    if (!cpu->cfg.ext_sstc || !env->rdtime_fn) {
> +        return RISCV_EXCP_ILLEGAL_INST;
> +    }
> +
> +    if (env->priv == PRV_M) {
> +        return RISCV_EXCP_NONE;
> +    }
> +
> +    if (!(get_field(env->mcounteren, COUNTEREN_TM) &
> +          get_field(env->menvcfg, MENVCFG_STCE))) {
> +        return RISCV_EXCP_ILLEGAL_INST;
> +    }
> +
> +    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;
> +        }
> +    }
> +
> +    return hmode(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;
>  }
>
> @@ -848,6 +931,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 {
> @@ -864,6 +951,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);
>
> @@ -1801,6 +1892,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) {
> @@ -3661,6 +3753,12 @@ riscv_csr_operations csr_ops[CSR_TABLE_SIZE] = {
>                                            .min_priv_ver = PRIV_VERSION_1_12_0 },
>      [CSR_STIMECMPH] = { "stimecmph", sstc, read_stimecmph, write_stimecmph,
>                                            .min_priv_ver = PRIV_VERSION_1_12_0 },
> +    [CSR_VSTIMECMP] = { "vstimecmp", sstc_hmode, read_vstimecmp,
> +                                          write_vstimecmp,
> +                                          .min_priv_ver = PRIV_VERSION_1_12_0 },
> +    [CSR_VSTIMECMPH] = { "vstimecmph", sstc_hmode, read_vstimecmph,
> +                                          write_vstimecmph,
> +                                          .min_priv_ver = PRIV_VERSION_1_12_0 },
>
>      /* Supervisor Protection and Translation */
>      [CSR_SATP]     = { "satp",     smode, read_satp,     write_satp     },
> diff --git a/target/riscv/machine.c b/target/riscv/machine.c
> index 622fface484e..4ba55705d147 100644
> --- a/target/riscv/machine.c
> +++ b/target/riscv/machine.c
> @@ -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),
> diff --git a/target/riscv/time_helper.c b/target/riscv/time_helper.c
> index f3fb5eac7b7b..8cce667dfd47 100644
> --- a/target/riscv/time_helper.c
> +++ b/target/riscv/time_helper.c
> @@ -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;
>  }
> --
> 2.25.1
>
>


^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH v8 3/3] target/riscv: Add vstimecmp support
  2022-08-04  1:42 ` [PATCH v8 3/3] target/riscv: Add vstimecmp support Atish Patra
  2022-08-08  0:01   ` Alistair Francis
@ 2022-08-08  1:49   ` Weiwei Li
  2022-08-08 17:20     ` Atish Kumar Patra
  1 sibling, 1 reply; 13+ messages in thread
From: Weiwei Li @ 2022-08-08  1:49 UTC (permalink / raw)
  To: Atish Patra, qemu-devel
  Cc: Alistair Francis, Bin Meng, Palmer Dabbelt, qemu-riscv


在 2022/8/4 上午9:42, Atish Patra 写道:
> vstimecmp CSR allows the guest OS or to program the next guest timer
> interrupt directly. Thus, hypervisor no longer need to inject the
> timer interrupt to the guest if vstimecmp is used. This was ratified
> as a part of the Sstc extension.
>
> Signed-off-by: Atish Patra <atishp@rivosinc.com>
> ---
>   target/riscv/cpu.h         |   4 ++
>   target/riscv/cpu_bits.h    |   4 ++
>   target/riscv/cpu_helper.c  |  11 ++--
>   target/riscv/csr.c         | 102 ++++++++++++++++++++++++++++++++++++-
>   target/riscv/machine.c     |   1 +
>   target/riscv/time_helper.c |  16 ++++++
>   6 files changed, 133 insertions(+), 5 deletions(-)
>
> diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h
> index 4cda2905661e..1fd382b2717f 100644
> --- a/target/riscv/cpu.h
> +++ b/target/riscv/cpu.h
> @@ -312,6 +312,8 @@ struct CPUArchState {
>       /* Sstc CSRs */
>       uint64_t stimecmp;
>   
> +    uint64_t vstimecmp;
> +
>       /* physical memory protection */
>       pmp_table_t pmp_state;
>       target_ulong mseccfg;
> @@ -366,6 +368,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;
> diff --git a/target/riscv/cpu_bits.h b/target/riscv/cpu_bits.h
> index ac17cf1515c0..095dab19f512 100644
> --- a/target/riscv/cpu_bits.h
> +++ b/target/riscv/cpu_bits.h
> @@ -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
>   
> diff --git a/target/riscv/cpu_helper.c b/target/riscv/cpu_helper.c
> index 650574accf0a..1e4faa84e839 100644
> --- a/target/riscv/cpu_helper.c
> +++ b/target/riscv/cpu_helper.c
> @@ -345,8 +345,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)
> @@ -605,7 +606,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)) {
> @@ -613,6 +614,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();
> @@ -620,7 +625,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);
> diff --git a/target/riscv/csr.c b/target/riscv/csr.c
> index e18b000700e4..9da4d6515e7b 100644
> --- a/target/riscv/csr.c
> +++ b/target/riscv/csr.c
> @@ -829,17 +829,100 @@ static RISCVException sstc(CPURISCVState *env, int csrno)
>       return smode(env, csrno);
>   }
>   
> +static RISCVException sstc_hmode(CPURISCVState *env, int csrno)
> +{
> +    CPUState *cs = env_cpu(env);
> +    RISCVCPU *cpu = RISCV_CPU(cs);
> +
> +    if (!cpu->cfg.ext_sstc || !env->rdtime_fn) {
> +        return RISCV_EXCP_ILLEGAL_INST;
> +    }
> +
> +    if (env->priv == PRV_M) {
> +        return RISCV_EXCP_NONE;
> +    }
> +
> +    if (!(get_field(env->mcounteren, COUNTEREN_TM) &
> +          get_field(env->menvcfg, MENVCFG_STCE))) {
> +        return RISCV_EXCP_ILLEGAL_INST;
> +    }
> +
> +    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;
> +        }
> +    }
> +

I think this check on hcounteren and henvcfg should be added to sstc 
predicate, not here.

Even though hcounteren and henvcfg finally controls the access of  
vstimecmp, however

it controls it via stimecmp.

> +    return hmode(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;
>   }
>   
> @@ -848,6 +931,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 {
> @@ -864,6 +951,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);
>   
> @@ -1801,6 +1892,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) {
> @@ -3661,6 +3753,12 @@ riscv_csr_operations csr_ops[CSR_TABLE_SIZE] = {
>                                             .min_priv_ver = PRIV_VERSION_1_12_0 },
>       [CSR_STIMECMPH] = { "stimecmph", sstc, read_stimecmph, write_stimecmph,
>                                             .min_priv_ver = PRIV_VERSION_1_12_0 },
> +    [CSR_VSTIMECMP] = { "vstimecmp", sstc_hmode, read_vstimecmp,
> +                                          write_vstimecmp,

Please align with last line. The same to other similar lines.

Regards,

Weiwei Li

> +                                          .min_priv_ver = PRIV_VERSION_1_12_0 },
> +    [CSR_VSTIMECMPH] = { "vstimecmph", sstc_hmode, read_vstimecmph,
> +                                          write_vstimecmph,
> +                                          .min_priv_ver = PRIV_VERSION_1_12_0 },
>   
>       /* Supervisor Protection and Translation */
>       [CSR_SATP]     = { "satp",     smode, read_satp,     write_satp     },
> diff --git a/target/riscv/machine.c b/target/riscv/machine.c
> index 622fface484e..4ba55705d147 100644
> --- a/target/riscv/machine.c
> +++ b/target/riscv/machine.c
> @@ -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),
> diff --git a/target/riscv/time_helper.c b/target/riscv/time_helper.c
> index f3fb5eac7b7b..8cce667dfd47 100644
> --- a/target/riscv/time_helper.c
> +++ b/target/riscv/time_helper.c
> @@ -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;
>   }



^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH v8 3/3] target/riscv: Add vstimecmp support
  2022-08-08  1:49   ` Weiwei Li
@ 2022-08-08 17:20     ` Atish Kumar Patra
  2022-08-09  7:00       ` Weiwei Li
  0 siblings, 1 reply; 13+ messages in thread
From: Atish Kumar Patra @ 2022-08-08 17:20 UTC (permalink / raw)
  To: Weiwei Li
  Cc: qemu-devel, Alistair Francis, Bin Meng, Palmer Dabbelt, qemu-riscv

[-- Attachment #1: Type: text/plain, Size: 12501 bytes --]

On Sun, Aug 7, 2022 at 6:50 PM Weiwei Li <liweiwei@iscas.ac.cn> wrote:

>
> 在 2022/8/4 上午9:42, Atish Patra 写道:
> > vstimecmp CSR allows the guest OS or to program the next guest timer
> > interrupt directly. Thus, hypervisor no longer need to inject the
> > timer interrupt to the guest if vstimecmp is used. This was ratified
> > as a part of the Sstc extension.
> >
> > Signed-off-by: Atish Patra <atishp@rivosinc.com>
> > ---
> >   target/riscv/cpu.h         |   4 ++
> >   target/riscv/cpu_bits.h    |   4 ++
> >   target/riscv/cpu_helper.c  |  11 ++--
> >   target/riscv/csr.c         | 102 ++++++++++++++++++++++++++++++++++++-
> >   target/riscv/machine.c     |   1 +
> >   target/riscv/time_helper.c |  16 ++++++
> >   6 files changed, 133 insertions(+), 5 deletions(-)
> >
> > diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h
> > index 4cda2905661e..1fd382b2717f 100644
> > --- a/target/riscv/cpu.h
> > +++ b/target/riscv/cpu.h
> > @@ -312,6 +312,8 @@ struct CPUArchState {
> >       /* Sstc CSRs */
> >       uint64_t stimecmp;
> >
> > +    uint64_t vstimecmp;
> > +
> >       /* physical memory protection */
> >       pmp_table_t pmp_state;
> >       target_ulong mseccfg;
> > @@ -366,6 +368,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;
> > diff --git a/target/riscv/cpu_bits.h b/target/riscv/cpu_bits.h
> > index ac17cf1515c0..095dab19f512 100644
> > --- a/target/riscv/cpu_bits.h
> > +++ b/target/riscv/cpu_bits.h
> > @@ -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
> >
> > diff --git a/target/riscv/cpu_helper.c b/target/riscv/cpu_helper.c
> > index 650574accf0a..1e4faa84e839 100644
> > --- a/target/riscv/cpu_helper.c
> > +++ b/target/riscv/cpu_helper.c
> > @@ -345,8 +345,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)
> > @@ -605,7 +606,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)) {
> > @@ -613,6 +614,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();
> > @@ -620,7 +625,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);
> > diff --git a/target/riscv/csr.c b/target/riscv/csr.c
> > index e18b000700e4..9da4d6515e7b 100644
> > --- a/target/riscv/csr.c
> > +++ b/target/riscv/csr.c
> > @@ -829,17 +829,100 @@ static RISCVException sstc(CPURISCVState *env,
> int csrno)
> >       return smode(env, csrno);
> >   }
> >
> > +static RISCVException sstc_hmode(CPURISCVState *env, int csrno)
> > +{
> > +    CPUState *cs = env_cpu(env);
> > +    RISCVCPU *cpu = RISCV_CPU(cs);
> > +
> > +    if (!cpu->cfg.ext_sstc || !env->rdtime_fn) {
> > +        return RISCV_EXCP_ILLEGAL_INST;
> > +    }
> > +
> > +    if (env->priv == PRV_M) {
> > +        return RISCV_EXCP_NONE;
> > +    }
> > +
> > +    if (!(get_field(env->mcounteren, COUNTEREN_TM) &
> > +          get_field(env->menvcfg, MENVCFG_STCE))) {
> > +        return RISCV_EXCP_ILLEGAL_INST;
> > +    }
> > +
> > +    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;
> > +        }
> > +    }
> > +
>
> I think this check on hcounteren and henvcfg should be added to sstc
> predicate, not here.
>
> Even though hcounteren and henvcfg finally controls the access of
> vstimecmp, however
>
>
We don't need to check hcounteren while accessing scountern. Thus it will
be an unnecessary
check there. Predicate function check should do the required sanity check
required only for that specific CSR.
That's why, I think it is the correct place.


> it controls it via stimecmp.
>
> > +    return hmode(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;
> >   }
> >
> > @@ -848,6 +931,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 {
> > @@ -864,6 +951,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);
> >
> > @@ -1801,6 +1892,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) {
> > @@ -3661,6 +3753,12 @@ riscv_csr_operations csr_ops[CSR_TABLE_SIZE] = {
> >                                             .min_priv_ver =
> PRIV_VERSION_1_12_0 },
> >       [CSR_STIMECMPH] = { "stimecmph", sstc, read_stimecmph,
> write_stimecmph,
> >                                             .min_priv_ver =
> PRIV_VERSION_1_12_0 },
> > +    [CSR_VSTIMECMP] = { "vstimecmp", sstc_hmode, read_vstimecmp,
> > +                                          write_vstimecmp,
>
> Please align with last line. The same to other similar lines.
>
>
Sure. I will fix that.


> Regards,
>
> Weiwei Li
>
> > +                                          .min_priv_ver =
> PRIV_VERSION_1_12_0 },
> > +    [CSR_VSTIMECMPH] = { "vstimecmph", sstc_hmode, read_vstimecmph,
> > +                                          write_vstimecmph,
> > +                                          .min_priv_ver =
> PRIV_VERSION_1_12_0 },
> >
> >       /* Supervisor Protection and Translation */
> >       [CSR_SATP]     = { "satp",     smode, read_satp,     write_satp
>  },
> > diff --git a/target/riscv/machine.c b/target/riscv/machine.c
> > index 622fface484e..4ba55705d147 100644
> > --- a/target/riscv/machine.c
> > +++ b/target/riscv/machine.c
> > @@ -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),
> > diff --git a/target/riscv/time_helper.c b/target/riscv/time_helper.c
> > index f3fb5eac7b7b..8cce667dfd47 100644
> > --- a/target/riscv/time_helper.c
> > +++ b/target/riscv/time_helper.c
> > @@ -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;
> >   }
>
>

[-- Attachment #2: Type: text/html, Size: 16080 bytes --]

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH v8 3/3] target/riscv: Add vstimecmp support
  2022-08-08 17:20     ` Atish Kumar Patra
@ 2022-08-09  7:00       ` Weiwei Li
  2022-08-09 19:34         ` Atish Kumar Patra
  0 siblings, 1 reply; 13+ messages in thread
From: Weiwei Li @ 2022-08-09  7:00 UTC (permalink / raw)
  To: Atish Kumar Patra
  Cc: qemu-devel, Alistair Francis, Bin Meng, Palmer Dabbelt, qemu-riscv

[-- Attachment #1: Type: text/plain, Size: 15245 bytes --]


在 2022/8/9 上午1:20, Atish Kumar Patra 写道:
>
>
> On Sun, Aug 7, 2022 at 6:50 PM Weiwei Li <liweiwei@iscas.ac.cn 
> <mailto:liweiwei@iscas.ac.cn>> wrote:
>
>
>     在 2022/8/4 上午9:42, Atish Patra 写道:
>     > vstimecmp CSR allows the guest OS or to program the next guest timer
>     > interrupt directly. Thus, hypervisor no longer need to inject the
>     > timer interrupt to the guest if vstimecmp is used. This was ratified
>     > as a part of the Sstc extension.
>     >
>     > Signed-off-by: Atish Patra <atishp@rivosinc.com
>     <mailto:atishp@rivosinc.com>>
>     > ---
>     >   target/riscv/cpu.h         |   4 ++
>     >   target/riscv/cpu_bits.h    |   4 ++
>     >   target/riscv/cpu_helper.c  |  11 ++--
>     >   target/riscv/csr.c         | 102
>     ++++++++++++++++++++++++++++++++++++-
>     >   target/riscv/machine.c     |   1 +
>     >   target/riscv/time_helper.c |  16 ++++++
>     >   6 files changed, 133 insertions(+), 5 deletions(-)
>     >
>     > diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h
>     > index 4cda2905661e..1fd382b2717f 100644
>     > --- a/target/riscv/cpu.h
>     > +++ b/target/riscv/cpu.h
>     > @@ -312,6 +312,8 @@ struct CPUArchState {
>     >       /* Sstc CSRs */
>     >       uint64_t stimecmp;
>     >
>     > +    uint64_t vstimecmp;
>     > +
>     >       /* physical memory protection */
>     >       pmp_table_t pmp_state;
>     >       target_ulong mseccfg;
>     > @@ -366,6 +368,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;
>     > diff --git a/target/riscv/cpu_bits.h b/target/riscv/cpu_bits.h
>     > index ac17cf1515c0..095dab19f512 100644
>     > --- a/target/riscv/cpu_bits.h
>     > +++ b/target/riscv/cpu_bits.h
>     > @@ -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
>     >
>     > diff --git a/target/riscv/cpu_helper.c b/target/riscv/cpu_helper.c
>     > index 650574accf0a..1e4faa84e839 100644
>     > --- a/target/riscv/cpu_helper.c
>     > +++ b/target/riscv/cpu_helper.c
>     > @@ -345,8 +345,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)
>     > @@ -605,7 +606,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)) {
>     > @@ -613,6 +614,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();
>     > @@ -620,7 +625,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);
>     > diff --git a/target/riscv/csr.c b/target/riscv/csr.c
>     > index e18b000700e4..9da4d6515e7b 100644
>     > --- a/target/riscv/csr.c
>     > +++ b/target/riscv/csr.c
>     > @@ -829,17 +829,100 @@ static RISCVException sstc(CPURISCVState
>     *env, int csrno)
>     >       return smode(env, csrno);
>     >   }
>     >
>     > +static RISCVException sstc_hmode(CPURISCVState *env, int csrno)
>     > +{
>     > +    CPUState *cs = env_cpu(env);
>     > +    RISCVCPU *cpu = RISCV_CPU(cs);
>     > +
>     > +    if (!cpu->cfg.ext_sstc || !env->rdtime_fn) {
>     > +        return RISCV_EXCP_ILLEGAL_INST;
>     > +    }
>     > +
>     > +    if (env->priv == PRV_M) {
>     > +        return RISCV_EXCP_NONE;
>     > +    }
>     > +
>     > +    if (!(get_field(env->mcounteren, COUNTEREN_TM) &
>     > +          get_field(env->menvcfg, MENVCFG_STCE))) {
>     > +        return RISCV_EXCP_ILLEGAL_INST;
>     > +    }
>     > +
>     > +    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;
>     > +        }
>     > +    }
>     > +
>
>     I think this check on hcounteren and henvcfg should be added to sstc
>     predicate, not here.
>
>     Even though hcounteren and henvcfg finally controls the access of
>     vstimecmp, however
>
>
> We don't need to check hcounteren while accessing scountern. Thus it 
> will be an unnecessary
> check there. Predicate function check should do the required sanity 
> check required only for that specific CSR.
> That's why, I think it is the correct place.

Sorry. It seems have no relationship with "check hcounteren while 
accessing scountern".

As the sstc spec (Section 2.2 and Chapter 3) states:

/"In addition, when the TM bit in the hcounteren register is clear, 
attempts to access the vstimecmp register (//*via*//*
*//*stimecmp*//) while executing in VS-mode will cause a virtual 
instruction exception if the same bit in mcounteren is//
//1. When this bit is set, access to the vstimecmp register (if 
implemented) is permitted in VS-mode."/

/"When STCE in menvcfg is one but STCE in henvcfg is zero, an attempt to 
//*access stimecmp *//(really vstimecmp)//
//when V = 1 raises a virtual instruction exception, and VSTIP in hip 
reverts to its defined behavior as if this//
//extension is not implemented."/

Both of them have stated the control is for stimecmp even though the 
final access is for vstimecmp just like

your following modification for read/write_stimecmp.

 From the  other hand,  direct access for VS CSRs (including vstimecmp) 
from VS/VU mode is never allowed,

which is checked in riscv_csrrw_check.

Regards,

Weiwei Li

>     it controls it via stimecmp.
>
>     > +    return hmode(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;
>     >   }
>     >
>     > @@ -848,6 +931,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 {
>     > @@ -864,6 +951,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);
>     >
>     > @@ -1801,6 +1892,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) {
>     > @@ -3661,6 +3753,12 @@ riscv_csr_operations
>     csr_ops[CSR_TABLE_SIZE] = {
>     >  .min_priv_ver = PRIV_VERSION_1_12_0 },
>     >       [CSR_STIMECMPH] = { "stimecmph", sstc, read_stimecmph,
>     write_stimecmph,
>     >  .min_priv_ver = PRIV_VERSION_1_12_0 },
>     > +    [CSR_VSTIMECMP] = { "vstimecmp", sstc_hmode, read_vstimecmp,
>     > + write_vstimecmp,
>
>     Please align with last line. The same to other similar lines.
>
>
> Sure. I will fix that.
>
>     Regards,
>
>     Weiwei Li
>
>     > + .min_priv_ver = PRIV_VERSION_1_12_0 },
>     > +    [CSR_VSTIMECMPH] = { "vstimecmph", sstc_hmode, read_vstimecmph,
>     > + write_vstimecmph,
>     > + .min_priv_ver = PRIV_VERSION_1_12_0 },
>     >
>     >       /* Supervisor Protection and Translation */
>     >       [CSR_SATP]     = { "satp",     smode, read_satp,  
>      write_satp     },
>     > diff --git a/target/riscv/machine.c b/target/riscv/machine.c
>     > index 622fface484e..4ba55705d147 100644
>     > --- a/target/riscv/machine.c
>     > +++ b/target/riscv/machine.c
>     > @@ -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),
>     > diff --git a/target/riscv/time_helper.c b/target/riscv/time_helper.c
>     > index f3fb5eac7b7b..8cce667dfd47 100644
>     > --- a/target/riscv/time_helper.c
>     > +++ b/target/riscv/time_helper.c
>     > @@ -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;
>     >   }
>

[-- Attachment #2: Type: text/html, Size: 22575 bytes --]

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH v8 3/3] target/riscv: Add vstimecmp support
  2022-08-09  7:00       ` Weiwei Li
@ 2022-08-09 19:34         ` Atish Kumar Patra
  2022-08-10  1:32           ` Weiwei Li
  0 siblings, 1 reply; 13+ messages in thread
From: Atish Kumar Patra @ 2022-08-09 19:34 UTC (permalink / raw)
  To: Weiwei Li
  Cc: qemu-devel, Alistair Francis, Bin Meng, Palmer Dabbelt, qemu-riscv

[-- Attachment #1: Type: text/plain, Size: 14330 bytes --]

On Tue, Aug 9, 2022 at 12:01 AM Weiwei Li <liweiwei@iscas.ac.cn> wrote:

>
> 在 2022/8/9 上午1:20, Atish Kumar Patra 写道:
>
>
>
> On Sun, Aug 7, 2022 at 6:50 PM Weiwei Li <liweiwei@iscas.ac.cn> wrote:
>
>>
>> 在 2022/8/4 上午9:42, Atish Patra 写道:
>> > vstimecmp CSR allows the guest OS or to program the next guest timer
>> > interrupt directly. Thus, hypervisor no longer need to inject the
>> > timer interrupt to the guest if vstimecmp is used. This was ratified
>> > as a part of the Sstc extension.
>> >
>> > Signed-off-by: Atish Patra <atishp@rivosinc.com>
>> > ---
>> >   target/riscv/cpu.h         |   4 ++
>> >   target/riscv/cpu_bits.h    |   4 ++
>> >   target/riscv/cpu_helper.c  |  11 ++--
>> >   target/riscv/csr.c         | 102 ++++++++++++++++++++++++++++++++++++-
>> >   target/riscv/machine.c     |   1 +
>> >   target/riscv/time_helper.c |  16 ++++++
>> >   6 files changed, 133 insertions(+), 5 deletions(-)
>> >
>> > diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h
>> > index 4cda2905661e..1fd382b2717f 100644
>> > --- a/target/riscv/cpu.h
>> > +++ b/target/riscv/cpu.h
>> > @@ -312,6 +312,8 @@ struct CPUArchState {
>> >       /* Sstc CSRs */
>> >       uint64_t stimecmp;
>> >
>> > +    uint64_t vstimecmp;
>> > +
>> >       /* physical memory protection */
>> >       pmp_table_t pmp_state;
>> >       target_ulong mseccfg;
>> > @@ -366,6 +368,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;
>> > diff --git a/target/riscv/cpu_bits.h b/target/riscv/cpu_bits.h
>> > index ac17cf1515c0..095dab19f512 100644
>> > --- a/target/riscv/cpu_bits.h
>> > +++ b/target/riscv/cpu_bits.h
>> > @@ -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
>> >
>> > diff --git a/target/riscv/cpu_helper.c b/target/riscv/cpu_helper.c
>> > index 650574accf0a..1e4faa84e839 100644
>> > --- a/target/riscv/cpu_helper.c
>> > +++ b/target/riscv/cpu_helper.c
>> > @@ -345,8 +345,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)
>> > @@ -605,7 +606,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)) {
>> > @@ -613,6 +614,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();
>> > @@ -620,7 +625,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);
>> > diff --git a/target/riscv/csr.c b/target/riscv/csr.c
>> > index e18b000700e4..9da4d6515e7b 100644
>> > --- a/target/riscv/csr.c
>> > +++ b/target/riscv/csr.c
>> > @@ -829,17 +829,100 @@ static RISCVException sstc(CPURISCVState *env,
>> int csrno)
>> >       return smode(env, csrno);
>> >   }
>> >
>> > +static RISCVException sstc_hmode(CPURISCVState *env, int csrno)
>> > +{
>> > +    CPUState *cs = env_cpu(env);
>> > +    RISCVCPU *cpu = RISCV_CPU(cs);
>> > +
>> > +    if (!cpu->cfg.ext_sstc || !env->rdtime_fn) {
>> > +        return RISCV_EXCP_ILLEGAL_INST;
>> > +    }
>> > +
>> > +    if (env->priv == PRV_M) {
>> > +        return RISCV_EXCP_NONE;
>> > +    }
>> > +
>> > +    if (!(get_field(env->mcounteren, COUNTEREN_TM) &
>> > +          get_field(env->menvcfg, MENVCFG_STCE))) {
>> > +        return RISCV_EXCP_ILLEGAL_INST;
>> > +    }
>> > +
>> > +    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;
>> > +        }
>> > +    }
>> > +
>>
>> I think this check on hcounteren and henvcfg should be added to sstc
>> predicate, not here.
>>
>> Even though hcounteren and henvcfg finally controls the access of
>> vstimecmp, however
>>
>>
> We don't need to check hcounteren while accessing scountern. Thus it will
> be an unnecessary
> check there. Predicate function check should do the required sanity check
> required only for that specific CSR.
> That's why, I think it is the correct place.
>
> Sorry. It seems have no relationship with "check hcounteren while
> accessing scountern".
>
>


> As the sstc spec (Section 2.2 and Chapter 3) states:
>
> *"In addition, when the TM bit in the hcounteren register is clear,
> attempts to access the vstimecmp register (**via*
> *stimecmp**) while executing in VS-mode will cause a virtual instruction
> exception if the same bit in mcounteren is*
> *1. When this bit is set, access to the vstimecmp register (if
> implemented) is permitted in VS-mode."*
>
> *"When STCE in menvcfg is one but STCE in henvcfg is zero, an attempt to **access
> stimecmp **(really vstimecmp)*
> *when V = 1 raises a virtual instruction exception, and VSTIP in hip
> reverts to its defined behavior as if this*
> *extension is not implemented."*
>
> Both of them have stated the control is for stimecmp even though the final
> access is for vstimecmp just like
>
> your following modification for read/write_stimecmp.
>

We can further simplify to remove sstc_hmode completely. After moving this
bit to sstc predicate function, it is enough for vstimecmp as well.


>
> From the  other hand,  direct access for VS CSRs (including vstimecmp)
> from VS/VU mode is never allowed,
>
> which is checked in riscv_csrrw_check.
>
Regards,
>
> Weiwei Li
>
>
>
>> it controls it via stimecmp.
>>
>> > +    return hmode(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;
>> >   }
>> >
>> > @@ -848,6 +931,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 {
>> > @@ -864,6 +951,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);
>> >
>> > @@ -1801,6 +1892,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) {
>> > @@ -3661,6 +3753,12 @@ riscv_csr_operations csr_ops[CSR_TABLE_SIZE] = {
>> >                                             .min_priv_ver =
>> PRIV_VERSION_1_12_0 },
>> >       [CSR_STIMECMPH] = { "stimecmph", sstc, read_stimecmph,
>> write_stimecmph,
>> >                                             .min_priv_ver =
>> PRIV_VERSION_1_12_0 },
>> > +    [CSR_VSTIMECMP] = { "vstimecmp", sstc_hmode, read_vstimecmp,
>> > +                                          write_vstimecmp,
>>
>> Please align with last line. The same to other similar lines.
>>
>>
> Sure. I will fix that.
>
>
>> Regards,
>>
>> Weiwei Li
>>
>> > +                                          .min_priv_ver =
>> PRIV_VERSION_1_12_0 },
>> > +    [CSR_VSTIMECMPH] = { "vstimecmph", sstc_hmode, read_vstimecmph,
>> > +                                          write_vstimecmph,
>> > +                                          .min_priv_ver =
>> PRIV_VERSION_1_12_0 },
>> >
>> >       /* Supervisor Protection and Translation */
>> >       [CSR_SATP]     = { "satp",     smode, read_satp,     write_satp
>>    },
>> > diff --git a/target/riscv/machine.c b/target/riscv/machine.c
>> > index 622fface484e..4ba55705d147 100644
>> > --- a/target/riscv/machine.c
>> > +++ b/target/riscv/machine.c
>> > @@ -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),
>> > diff --git a/target/riscv/time_helper.c b/target/riscv/time_helper.c
>> > index f3fb5eac7b7b..8cce667dfd47 100644
>> > --- a/target/riscv/time_helper.c
>> > +++ b/target/riscv/time_helper.c
>> > @@ -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;
>> >   }
>>
>>

[-- Attachment #2: Type: text/html, Size: 23938 bytes --]

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH v8 3/3] target/riscv: Add vstimecmp support
  2022-08-09 19:34         ` Atish Kumar Patra
@ 2022-08-10  1:32           ` Weiwei Li
  2022-08-10  5:45             ` Atish Kumar Patra
  0 siblings, 1 reply; 13+ messages in thread
From: Weiwei Li @ 2022-08-10  1:32 UTC (permalink / raw)
  To: Atish Kumar Patra
  Cc: qemu-devel, Alistair Francis, Bin Meng, Palmer Dabbelt, qemu-riscv

[-- Attachment #1: Type: text/plain, Size: 17620 bytes --]


在 2022/8/10 上午3:34, Atish Kumar Patra 写道:
>
>
>
> On Tue, Aug 9, 2022 at 12:01 AM Weiwei Li <liweiwei@iscas.ac.cn 
> <mailto:liweiwei@iscas.ac.cn>> wrote:
>
>
>     在 2022/8/9 上午1:20, Atish Kumar Patra 写道:
>>
>>
>>     On Sun, Aug 7, 2022 at 6:50 PM Weiwei Li <liweiwei@iscas.ac.cn
>>     <mailto:liweiwei@iscas.ac.cn>> wrote:
>>
>>
>>         在 2022/8/4 上午9:42, Atish Patra 写道:
>>         > vstimecmp CSR allows the guest OS or to program the next
>>         guest timer
>>         > interrupt directly. Thus, hypervisor no longer need to
>>         inject the
>>         > timer interrupt to the guest if vstimecmp is used. This was
>>         ratified
>>         > as a part of the Sstc extension.
>>         >
>>         > Signed-off-by: Atish Patra <atishp@rivosinc.com
>>         <mailto:atishp@rivosinc.com>>
>>         > ---
>>         >   target/riscv/cpu.h         |   4 ++
>>         >   target/riscv/cpu_bits.h    |   4 ++
>>         >   target/riscv/cpu_helper.c  |  11 ++--
>>         >   target/riscv/csr.c         | 102
>>         ++++++++++++++++++++++++++++++++++++-
>>         >   target/riscv/machine.c     |   1 +
>>         >   target/riscv/time_helper.c |  16 ++++++
>>         >   6 files changed, 133 insertions(+), 5 deletions(-)
>>         >
>>         > diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h
>>         > index 4cda2905661e..1fd382b2717f 100644
>>         > --- a/target/riscv/cpu.h
>>         > +++ b/target/riscv/cpu.h
>>         > @@ -312,6 +312,8 @@ struct CPUArchState {
>>         >       /* Sstc CSRs */
>>         >       uint64_t stimecmp;
>>         >
>>         > +    uint64_t vstimecmp;
>>         > +
>>         >       /* physical memory protection */
>>         >       pmp_table_t pmp_state;
>>         >       target_ulong mseccfg;
>>         > @@ -366,6 +368,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;
>>         > diff --git a/target/riscv/cpu_bits.h b/target/riscv/cpu_bits.h
>>         > index ac17cf1515c0..095dab19f512 100644
>>         > --- a/target/riscv/cpu_bits.h
>>         > +++ b/target/riscv/cpu_bits.h
>>         > @@ -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
>>         >
>>         > diff --git a/target/riscv/cpu_helper.c
>>         b/target/riscv/cpu_helper.c
>>         > index 650574accf0a..1e4faa84e839 100644
>>         > --- a/target/riscv/cpu_helper.c
>>         > +++ b/target/riscv/cpu_helper.c
>>         > @@ -345,8 +345,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)
>>         > @@ -605,7 +606,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)) {
>>         > @@ -613,6 +614,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();
>>         > @@ -620,7 +625,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);
>>         > diff --git a/target/riscv/csr.c b/target/riscv/csr.c
>>         > index e18b000700e4..9da4d6515e7b 100644
>>         > --- a/target/riscv/csr.c
>>         > +++ b/target/riscv/csr.c
>>         > @@ -829,17 +829,100 @@ static RISCVException
>>         sstc(CPURISCVState *env, int csrno)
>>         >       return smode(env, csrno);
>>         >   }
>>         >
>>         > +static RISCVException sstc_hmode(CPURISCVState *env, int
>>         csrno)
>>         > +{
>>         > +    CPUState *cs = env_cpu(env);
>>         > +    RISCVCPU *cpu = RISCV_CPU(cs);
>>         > +
>>         > +    if (!cpu->cfg.ext_sstc || !env->rdtime_fn) {
>>         > +        return RISCV_EXCP_ILLEGAL_INST;
>>         > +    }
>>         > +
>>         > +    if (env->priv == PRV_M) {
>>         > +        return RISCV_EXCP_NONE;
>>         > +    }
>>         > +
>>         > +    if (!(get_field(env->mcounteren, COUNTEREN_TM) &
>>         > +          get_field(env->menvcfg, MENVCFG_STCE))) {
>>         > +        return RISCV_EXCP_ILLEGAL_INST;
>>         > +    }
>>         > +
>>         > +    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;
>>         > +        }
>>         > +    }
>>         > +
>>
>>         I think this check on hcounteren and henvcfg should be added
>>         to sstc
>>         predicate, not here.
>>
>>         Even though hcounteren and henvcfg finally controls the
>>         access of
>>         vstimecmp, however
>>
>>
>>     We don't need to check hcounteren while accessing scountern. Thus
>>     it will be an unnecessary
>>     check there. Predicate function check should do the required
>>     sanity check required only for that specific CSR.
>>     That's why, I think it is the correct place.
>
>     Sorry. It seems have no relationship with "check hcounteren while
>     accessing scountern".
>
>
>
>     As the sstc spec (Section 2.2 and Chapter 3) states:
>
>     /"In addition, when the TM bit in the hcounteren register is
>     clear, attempts to access the vstimecmp register (//*via*//*
>     *//*stimecmp*//) while executing in VS-mode will cause a virtual
>     instruction exception if the same bit in mcounteren is//
>     //1. When this bit is set, access to the vstimecmp register (if
>     implemented) is permitted in VS-mode."/
>
>     /"When STCE in menvcfg is one but STCE in henvcfg is zero, an
>     attempt to //*access stimecmp *//(really vstimecmp)//
>     //when V = 1 raises a virtual instruction exception, and VSTIP in
>     hip reverts to its defined behavior as if this//
>     //extension is not implemented."/
>
>     Both of them have stated the control is for stimecmp even though
>     the final access is for vstimecmp just like
>
>     your following modification for read/write_stimecmp.
>
>
> We can further simplify to remove sstc_hmode completely. After moving 
> this bit to sstc predicate function, it is enough for vstimecmp as well.

Sorry. I cannot get your idea. Do you mean they share the same 
predicate? They seem different:

Vstimecmp is under is control of menvcfg and mcounteren. And stimecmp is 
additionally controlled by senvcfg and scuonteren.

On the other hand, Vstimecmp is a Hypervisor CSR(checked by hmode), 
stimecmp is Supervisor CSR(checked by smode).

Regards,

Weiwei Li

>
>     From the  other hand,  direct access for VS CSRs (including
>     vstimecmp) from VS/VU mode is never allowed,
>
>     which is checked in riscv_csrrw_check.
>
>     Regards,
>
>     Weiwei Li
>
>>         it controls it via stimecmp.
>>
>>         > +    return hmode(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;
>>         >   }
>>         >
>>         > @@ -848,6 +931,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 {
>>         > @@ -864,6 +951,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);
>>         >
>>         > @@ -1801,6 +1892,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) {
>>         > @@ -3661,6 +3753,12 @@ riscv_csr_operations
>>         csr_ops[CSR_TABLE_SIZE] = {
>>         >  .min_priv_ver = PRIV_VERSION_1_12_0 },
>>         >       [CSR_STIMECMPH] = { "stimecmph", sstc,
>>         read_stimecmph, write_stimecmph,
>>         >  .min_priv_ver = PRIV_VERSION_1_12_0 },
>>         > +    [CSR_VSTIMECMP] = { "vstimecmp", sstc_hmode,
>>         read_vstimecmp,
>>         > + write_vstimecmp,
>>
>>         Please align with last line. The same to other similar lines.
>>
>>
>>     Sure. I will fix that.
>>
>>         Regards,
>>
>>         Weiwei Li
>>
>>         > + .min_priv_ver = PRIV_VERSION_1_12_0 },
>>         > +    [CSR_VSTIMECMPH] = { "vstimecmph", sstc_hmode,
>>         read_vstimecmph,
>>         > + write_vstimecmph,
>>         > + .min_priv_ver = PRIV_VERSION_1_12_0 },
>>         >
>>         >       /* Supervisor Protection and Translation */
>>         >       [CSR_SATP]     = { "satp",     smode, read_satp,   
>>          write_satp     },
>>         > diff --git a/target/riscv/machine.c b/target/riscv/machine.c
>>         > index 622fface484e..4ba55705d147 100644
>>         > --- a/target/riscv/machine.c
>>         > +++ b/target/riscv/machine.c
>>         > @@ -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),
>>         > diff --git a/target/riscv/time_helper.c
>>         b/target/riscv/time_helper.c
>>         > index f3fb5eac7b7b..8cce667dfd47 100644
>>         > --- a/target/riscv/time_helper.c
>>         > +++ b/target/riscv/time_helper.c
>>         > @@ -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;
>>         >   }
>>

[-- Attachment #2: Type: text/html, Size: 31515 bytes --]

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH v8 3/3] target/riscv: Add vstimecmp support
  2022-08-10  1:32           ` Weiwei Li
@ 2022-08-10  5:45             ` Atish Kumar Patra
  2022-08-10 13:53               ` Weiwei Li
  0 siblings, 1 reply; 13+ messages in thread
From: Atish Kumar Patra @ 2022-08-10  5:45 UTC (permalink / raw)
  To: Weiwei Li
  Cc: qemu-devel, Alistair Francis, Bin Meng, Palmer Dabbelt, qemu-riscv

[-- Attachment #1: Type: text/plain, Size: 15990 bytes --]

On Tue, Aug 9, 2022 at 6:33 PM Weiwei Li <liweiwei@iscas.ac.cn> wrote:

>
> 在 2022/8/10 上午3:34, Atish Kumar Patra 写道:
>
>
>
>
> On Tue, Aug 9, 2022 at 12:01 AM Weiwei Li <liweiwei@iscas.ac.cn> wrote:
>
>>
>> 在 2022/8/9 上午1:20, Atish Kumar Patra 写道:
>>
>>
>>
>> On Sun, Aug 7, 2022 at 6:50 PM Weiwei Li <liweiwei@iscas.ac.cn> wrote:
>>
>>>
>>> 在 2022/8/4 上午9:42, Atish Patra 写道:
>>> > vstimecmp CSR allows the guest OS or to program the next guest timer
>>> > interrupt directly. Thus, hypervisor no longer need to inject the
>>> > timer interrupt to the guest if vstimecmp is used. This was ratified
>>> > as a part of the Sstc extension.
>>> >
>>> > Signed-off-by: Atish Patra <atishp@rivosinc.com>
>>> > ---
>>> >   target/riscv/cpu.h         |   4 ++
>>> >   target/riscv/cpu_bits.h    |   4 ++
>>> >   target/riscv/cpu_helper.c  |  11 ++--
>>> >   target/riscv/csr.c         | 102
>>> ++++++++++++++++++++++++++++++++++++-
>>> >   target/riscv/machine.c     |   1 +
>>> >   target/riscv/time_helper.c |  16 ++++++
>>> >   6 files changed, 133 insertions(+), 5 deletions(-)
>>> >
>>> > diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h
>>> > index 4cda2905661e..1fd382b2717f 100644
>>> > --- a/target/riscv/cpu.h
>>> > +++ b/target/riscv/cpu.h
>>> > @@ -312,6 +312,8 @@ struct CPUArchState {
>>> >       /* Sstc CSRs */
>>> >       uint64_t stimecmp;
>>> >
>>> > +    uint64_t vstimecmp;
>>> > +
>>> >       /* physical memory protection */
>>> >       pmp_table_t pmp_state;
>>> >       target_ulong mseccfg;
>>> > @@ -366,6 +368,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;
>>> > diff --git a/target/riscv/cpu_bits.h b/target/riscv/cpu_bits.h
>>> > index ac17cf1515c0..095dab19f512 100644
>>> > --- a/target/riscv/cpu_bits.h
>>> > +++ b/target/riscv/cpu_bits.h
>>> > @@ -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
>>> >
>>> > diff --git a/target/riscv/cpu_helper.c b/target/riscv/cpu_helper.c
>>> > index 650574accf0a..1e4faa84e839 100644
>>> > --- a/target/riscv/cpu_helper.c
>>> > +++ b/target/riscv/cpu_helper.c
>>> > @@ -345,8 +345,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)
>>> > @@ -605,7 +606,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)) {
>>> > @@ -613,6 +614,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();
>>> > @@ -620,7 +625,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);
>>> > diff --git a/target/riscv/csr.c b/target/riscv/csr.c
>>> > index e18b000700e4..9da4d6515e7b 100644
>>> > --- a/target/riscv/csr.c
>>> > +++ b/target/riscv/csr.c
>>> > @@ -829,17 +829,100 @@ static RISCVException sstc(CPURISCVState *env,
>>> int csrno)
>>> >       return smode(env, csrno);
>>> >   }
>>> >
>>> > +static RISCVException sstc_hmode(CPURISCVState *env, int csrno)
>>> > +{
>>> > +    CPUState *cs = env_cpu(env);
>>> > +    RISCVCPU *cpu = RISCV_CPU(cs);
>>> > +
>>> > +    if (!cpu->cfg.ext_sstc || !env->rdtime_fn) {
>>> > +        return RISCV_EXCP_ILLEGAL_INST;
>>> > +    }
>>> > +
>>> > +    if (env->priv == PRV_M) {
>>> > +        return RISCV_EXCP_NONE;
>>> > +    }
>>> > +
>>> > +    if (!(get_field(env->mcounteren, COUNTEREN_TM) &
>>> > +          get_field(env->menvcfg, MENVCFG_STCE))) {
>>> > +        return RISCV_EXCP_ILLEGAL_INST;
>>> > +    }
>>> > +
>>> > +    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;
>>> > +        }
>>> > +    }
>>> > +
>>>
>>> I think this check on hcounteren and henvcfg should be added to sstc
>>> predicate, not here.
>>>
>>> Even though hcounteren and henvcfg finally controls the access of
>>> vstimecmp, however
>>>
>>>
>> We don't need to check hcounteren while accessing scountern. Thus it will
>> be an unnecessary
>> check there. Predicate function check should do the required sanity check
>> required only for that specific CSR.
>> That's why, I think it is the correct place.
>>
>> Sorry. It seems have no relationship with "check hcounteren while
>> accessing scountern".
>>
>>
>
>
>> As the sstc spec (Section 2.2 and Chapter 3) states:
>>
>> *"In addition, when the TM bit in the hcounteren register is clear,
>> attempts to access the vstimecmp register (**via*
>> *stimecmp**) while executing in VS-mode will cause a virtual instruction
>> exception if the same bit in mcounteren is*
>> *1. When this bit is set, access to the vstimecmp register (if
>> implemented) is permitted in VS-mode."*
>>
>> *"When STCE in menvcfg is one but STCE in henvcfg is zero, an attempt to **access
>> stimecmp **(really vstimecmp)*
>> *when V = 1 raises a virtual instruction exception, and VSTIP in hip
>> reverts to its defined behavior as if this*
>> *extension is not implemented."*
>>
>> Both of them have stated the control is for stimecmp even though the
>> final access is for vstimecmp just like
>>
>> your following modification for read/write_stimecmp.
>>
>
> We can further simplify to remove sstc_hmode completely. After moving this
> bit to sstc predicate function, it is enough for vstimecmp as well.
>
> Sorry. I cannot get your idea. Do you mean they share the same predicate?
> They seem different:
>
> Vstimecmp is under is control of menvcfg and mcounteren. And stimecmp is
> additionally controlled by senvcfg and scuonteren.
>

stimecmp is under control of menvcfg & mcounteren while vstimecmp is
controlled by henvcfg & hcountern. senvcfg doesn't have a STCE bit.
so vstimecmp predicate function should do the following things:

- hmode check
- sstc extension availability
- menvcfg/mcounteren

As vstimecmp can be accessed by HS mode/M mode only while VS mode access
stimecmp (which is translated to vstimecmp if V=1)

Thus stimecmp predicate function will do the following things:
- smode check
- sstc extension availability
- menvcfg/mcounteren
- henvcfg/hcountern (if V=1)

That's why I was suggesting that we can simplify two predicate functions
where only mode check will be different (based on CSR value).

> On the other hand, Vstimecmp is a Hypervisor CSR(checked by hmode),
> stimecmp is Supervisor CSR(checked by smode).
>
> Regards,
>
> Weiwei Li
>
>
>
>>
>> From the  other hand,  direct access for VS CSRs (including vstimecmp)
>> from VS/VU mode is never allowed,
>>
>> which is checked in riscv_csrrw_check.
>>
> Regards,
>>
>> Weiwei Li
>>
>>
>>
>>> it controls it via stimecmp.
>>>
>>> > +    return hmode(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;
>>> >   }
>>> >
>>> > @@ -848,6 +931,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 {
>>> > @@ -864,6 +951,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);
>>> >
>>> > @@ -1801,6 +1892,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) {
>>> > @@ -3661,6 +3753,12 @@ riscv_csr_operations csr_ops[CSR_TABLE_SIZE] = {
>>> >                                             .min_priv_ver =
>>> PRIV_VERSION_1_12_0 },
>>> >       [CSR_STIMECMPH] = { "stimecmph", sstc, read_stimecmph,
>>> write_stimecmph,
>>> >                                             .min_priv_ver =
>>> PRIV_VERSION_1_12_0 },
>>> > +    [CSR_VSTIMECMP] = { "vstimecmp", sstc_hmode, read_vstimecmp,
>>> > +                                          write_vstimecmp,
>>>
>>> Please align with last line. The same to other similar lines.
>>>
>>>
>> Sure. I will fix that.
>>
>>
>>> Regards,
>>>
>>> Weiwei Li
>>>
>>> > +                                          .min_priv_ver =
>>> PRIV_VERSION_1_12_0 },
>>> > +    [CSR_VSTIMECMPH] = { "vstimecmph", sstc_hmode, read_vstimecmph,
>>> > +                                          write_vstimecmph,
>>> > +                                          .min_priv_ver =
>>> PRIV_VERSION_1_12_0 },
>>> >
>>> >       /* Supervisor Protection and Translation */
>>> >       [CSR_SATP]     = { "satp",     smode, read_satp,     write_satp
>>>    },
>>> > diff --git a/target/riscv/machine.c b/target/riscv/machine.c
>>> > index 622fface484e..4ba55705d147 100644
>>> > --- a/target/riscv/machine.c
>>> > +++ b/target/riscv/machine.c
>>> > @@ -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),
>>> > diff --git a/target/riscv/time_helper.c b/target/riscv/time_helper.c
>>> > index f3fb5eac7b7b..8cce667dfd47 100644
>>> > --- a/target/riscv/time_helper.c
>>> > +++ b/target/riscv/time_helper.c
>>> > @@ -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;
>>> >   }
>>>
>>>

[-- Attachment #2: Type: text/html, Size: 33157 bytes --]

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH v8 3/3] target/riscv: Add vstimecmp support
  2022-08-10  5:45             ` Atish Kumar Patra
@ 2022-08-10 13:53               ` Weiwei Li
  0 siblings, 0 replies; 13+ messages in thread
From: Weiwei Li @ 2022-08-10 13:53 UTC (permalink / raw)
  To: Atish Kumar Patra
  Cc: qemu-devel, Alistair Francis, Bin Meng, Palmer Dabbelt, qemu-riscv

[-- Attachment #1: Type: text/plain, Size: 20752 bytes --]


在 2022/8/10 下午1:45, Atish Kumar Patra 写道:
>
>
> On Tue, Aug 9, 2022 at 6:33 PM Weiwei Li <liweiwei@iscas.ac.cn 
> <mailto:liweiwei@iscas.ac.cn>> wrote:
>
>
>     在 2022/8/10 上午3:34, Atish Kumar Patra 写道:
>>
>>
>>
>>     On Tue, Aug 9, 2022 at 12:01 AM Weiwei Li <liweiwei@iscas.ac.cn
>>     <mailto:liweiwei@iscas.ac.cn>> wrote:
>>
>>
>>         在 2022/8/9 上午1:20, Atish Kumar Patra 写道:
>>>
>>>
>>>         On Sun, Aug 7, 2022 at 6:50 PM Weiwei Li
>>>         <liweiwei@iscas.ac.cn <mailto:liweiwei@iscas.ac.cn>> wrote:
>>>
>>>
>>>             在 2022/8/4 上午9:42, Atish Patra 写道:
>>>             > vstimecmp CSR allows the guest OS or to program the
>>>             next guest timer
>>>             > interrupt directly. Thus, hypervisor no longer need to
>>>             inject the
>>>             > timer interrupt to the guest if vstimecmp is used.
>>>             This was ratified
>>>             > as a part of the Sstc extension.
>>>             >
>>>             > Signed-off-by: Atish Patra <atishp@rivosinc.com
>>>             <mailto:atishp@rivosinc.com>>
>>>             > ---
>>>             >   target/riscv/cpu.h         |  4 ++
>>>             >   target/riscv/cpu_bits.h    |  4 ++
>>>             >   target/riscv/cpu_helper.c  | 11 ++--
>>>             >   target/riscv/csr.c         | 102
>>>             ++++++++++++++++++++++++++++++++++++-
>>>             >   target/riscv/machine.c     |  1 +
>>>             >   target/riscv/time_helper.c | 16 ++++++
>>>             >   6 files changed, 133 insertions(+), 5 deletions(-)
>>>             >
>>>             > diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h
>>>             > index 4cda2905661e..1fd382b2717f 100644
>>>             > --- a/target/riscv/cpu.h
>>>             > +++ b/target/riscv/cpu.h
>>>             > @@ -312,6 +312,8 @@ struct CPUArchState {
>>>             >       /* Sstc CSRs */
>>>             >       uint64_t stimecmp;
>>>             >
>>>             > +    uint64_t vstimecmp;
>>>             > +
>>>             >       /* physical memory protection */
>>>             >       pmp_table_t pmp_state;
>>>             >       target_ulong mseccfg;
>>>             > @@ -366,6 +368,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;
>>>             > diff --git a/target/riscv/cpu_bits.h
>>>             b/target/riscv/cpu_bits.h
>>>             > index ac17cf1515c0..095dab19f512 100644
>>>             > --- a/target/riscv/cpu_bits.h
>>>             > +++ b/target/riscv/cpu_bits.h
>>>             > @@ -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
>>>             >
>>>             > diff --git a/target/riscv/cpu_helper.c
>>>             b/target/riscv/cpu_helper.c
>>>             > index 650574accf0a..1e4faa84e839 100644
>>>             > --- a/target/riscv/cpu_helper.c
>>>             > +++ b/target/riscv/cpu_helper.c
>>>             > @@ -345,8 +345,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)
>>>             > @@ -605,7 +606,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)) {
>>>             > @@ -613,6 +614,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();
>>>             > @@ -620,7 +625,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);
>>>             > diff --git a/target/riscv/csr.c b/target/riscv/csr.c
>>>             > index e18b000700e4..9da4d6515e7b 100644
>>>             > --- a/target/riscv/csr.c
>>>             > +++ b/target/riscv/csr.c
>>>             > @@ -829,17 +829,100 @@ static RISCVException
>>>             sstc(CPURISCVState *env, int csrno)
>>>             >       return smode(env, csrno);
>>>             >   }
>>>             >
>>>             > +static RISCVException sstc_hmode(CPURISCVState *env,
>>>             int csrno)
>>>             > +{
>>>             > +    CPUState *cs = env_cpu(env);
>>>             > +    RISCVCPU *cpu = RISCV_CPU(cs);
>>>             > +
>>>             > +    if (!cpu->cfg.ext_sstc || !env->rdtime_fn) {
>>>             > +        return RISCV_EXCP_ILLEGAL_INST;
>>>             > +    }
>>>             > +
>>>             > +    if (env->priv == PRV_M) {
>>>             > +        return RISCV_EXCP_NONE;
>>>             > +    }
>>>             > +
>>>             > +    if (!(get_field(env->mcounteren, COUNTEREN_TM) &
>>>             > + get_field(env->menvcfg, MENVCFG_STCE))) {
>>>             > +        return RISCV_EXCP_ILLEGAL_INST;
>>>             > +    }
>>>             > +
>>>             > +    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;
>>>             > +        }
>>>             > +    }
>>>             > +
>>>
>>>             I think this check on hcounteren and henvcfg should be
>>>             added to sstc
>>>             predicate, not here.
>>>
>>>             Even though hcounteren and henvcfg finally controls the
>>>             access of
>>>             vstimecmp, however
>>>
>>>
>>>         We don't need to check hcounteren while accessing scountern.
>>>         Thus it will be an unnecessary
>>>         check there. Predicate function check should do the required
>>>         sanity check required only for that specific CSR.
>>>         That's why, I think it is the correct place.
>>
>>         Sorry. It seems have no relationship with "check hcounteren
>>         while accessing scountern".
>>
>>
>>
>>         As the sstc spec (Section 2.2 and Chapter 3) states:
>>
>>         /"In addition, when the TM bit in the hcounteren register is
>>         clear, attempts to access the vstimecmp register (//*via*//*
>>         *//*stimecmp*//) while executing in VS-mode will cause a
>>         virtual instruction exception if the same bit in mcounteren is//
>>         //1. When this bit is set, access to the vstimecmp register
>>         (if implemented) is permitted in VS-mode."/
>>
>>         /"When STCE in menvcfg is one but STCE in henvcfg is zero, an
>>         attempt to //*access stimecmp *//(really vstimecmp)//
>>         //when V = 1 raises a virtual instruction exception, and
>>         VSTIP in hip reverts to its defined behavior as if this//
>>         //extension is not implemented."/
>>
>>         Both of them have stated the control is for stimecmp even
>>         though the final access is for vstimecmp just like
>>
>>         your following modification for read/write_stimecmp.
>>
>>
>>     We can further simplify to remove sstc_hmode completely. After
>>     moving this bit to sstc predicate function, it is enough for
>>     vstimecmp as well.
>
>     Sorry. I cannot get your idea. Do you mean they share the same
>     predicate? They seem different:
>
>     Vstimecmp is under is control of menvcfg and mcounteren. And
>     stimecmp is additionally controlled by senvcfg and scuonteren.
>
>
> stimecmp is under control of menvcfg & mcounteren while vstimecmp is 
> controlled by henvcfg & hcountern. senvcfg doesn't have a STCE bit.
> so vstimecmp predicate function should do the following things:
>
> - hmode check
> - sstc extension availability
> - menvcfg/mcounteren
> As vstimecmp can be accessed by HS mode/M mode only while VS mode 
> access stimecmp (which is translated to vstimecmp if V=1)
>
> Thus stimecmp predicate function will do the following things:
> - smode check
> - sstc extension availability
> - menvcfg/mcounteren
> - henvcfg/hcountern (if V=1)
>
> That's why I was suggesting that we can simplify two predicate 
> functions where only mode check will be different (based on CSR value).

Yeah, I agree.  It's acceptable to me to share the same predicate(by 
return hmode() or smode() based on csrno) if you insist.

Regards,

Weiwei Li

>     On the other hand, Vstimecmp is a Hypervisor CSR(checked by
>     hmode), stimecmp is Supervisor CSR(checked by smode).
>
>     Regards,
>
>     Weiwei Li
>
>>
>>         From the  other hand,  direct access for VS CSRs (including
>>         vstimecmp) from VS/VU mode is never allowed,
>>
>>         which is checked in riscv_csrrw_check.
>>
>>         Regards,
>>
>>         Weiwei Li
>>
>>>             it controls it via stimecmp.
>>>
>>>             > +    return hmode(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;
>>>             >   }
>>>             >
>>>             > @@ -848,6 +931,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 {
>>>             > @@ -864,6 +951,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);
>>>             >
>>>             > @@ -1801,6 +1892,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) {
>>>             > @@ -3661,6 +3753,12 @@ riscv_csr_operations
>>>             csr_ops[CSR_TABLE_SIZE] = {
>>>             >            .min_priv_ver = PRIV_VERSION_1_12_0 },
>>>             >       [CSR_STIMECMPH] = { "stimecmph", sstc,
>>>             read_stimecmph, write_stimecmph,
>>>             >            .min_priv_ver = PRIV_VERSION_1_12_0 },
>>>             > +    [CSR_VSTIMECMP] = { "vstimecmp", sstc_hmode,
>>>             read_vstimecmp,
>>>             > +           write_vstimecmp,
>>>
>>>             Please align with last line. The same to other similar
>>>             lines.
>>>
>>>
>>>         Sure. I will fix that.
>>>
>>>             Regards,
>>>
>>>             Weiwei Li
>>>
>>>             > +           .min_priv_ver = PRIV_VERSION_1_12_0 },
>>>             > +    [CSR_VSTIMECMPH] = { "vstimecmph", sstc_hmode,
>>>             read_vstimecmph,
>>>             > +           write_vstimecmph,
>>>             > +           .min_priv_ver = PRIV_VERSION_1_12_0 },
>>>             >
>>>             >       /* Supervisor Protection and Translation */
>>>             >       [CSR_SATP]     = { "satp",    smode, read_satp, 
>>>                write_satp  },
>>>             > diff --git a/target/riscv/machine.c
>>>             b/target/riscv/machine.c
>>>             > index 622fface484e..4ba55705d147 100644
>>>             > --- a/target/riscv/machine.c
>>>             > +++ b/target/riscv/machine.c
>>>             > @@ -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),
>>>             > diff --git a/target/riscv/time_helper.c
>>>             b/target/riscv/time_helper.c
>>>             > index f3fb5eac7b7b..8cce667dfd47 100644
>>>             > --- a/target/riscv/time_helper.c
>>>             > +++ b/target/riscv/time_helper.c
>>>             > @@ -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;
>>>             >   }
>>>

[-- Attachment #2: Type: text/html, Size: 43367 bytes --]

^ permalink raw reply	[flat|nested] 13+ messages in thread

end of thread, other threads:[~2022-08-10 14:21 UTC | newest]

Thread overview: 13+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-08-04  1:42 [PATCH v8 0/3] Implement Sstc extension Atish Patra
2022-08-04  1:42 ` [PATCH v8 1/3] hw/intc: Move mtimer/mtimecmp to aclint Atish Patra
2022-08-04  1:42 ` [PATCH v8 2/3] target/riscv: Add stimecmp support Atish Patra
2022-08-07 23:44   ` Alistair Francis
2022-08-04  1:42 ` [PATCH v8 3/3] target/riscv: Add vstimecmp support Atish Patra
2022-08-08  0:01   ` Alistair Francis
2022-08-08  1:49   ` Weiwei Li
2022-08-08 17:20     ` Atish Kumar Patra
2022-08-09  7:00       ` Weiwei Li
2022-08-09 19:34         ` Atish Kumar Patra
2022-08-10  1:32           ` Weiwei Li
2022-08-10  5:45             ` Atish Kumar Patra
2022-08-10 13:53               ` Weiwei Li

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.