From: Atish Kumar Patra <atishp@rivosinc.com>
To: Weiwei Li <liweiwei@iscas.ac.cn>
Cc: qemu-devel@nongnu.org,
Alistair Francis <Alistair.Francis@wdc.com>,
Bin Meng <bin.meng@windriver.com>,
Palmer Dabbelt <palmer@dabbelt.com>,
qemu-riscv@nongnu.org
Subject: Re: [PATCH v8 3/3] target/riscv: Add vstimecmp support
Date: Tue, 9 Aug 2022 22:45:56 -0700 [thread overview]
Message-ID: <CAHBxVyGCv8h07FjO7-1GJq6SZDZ4URNr2STDV_ReU3PGRUJu2Q@mail.gmail.com> (raw)
In-Reply-To: <6d272bf2-325f-f87c-e55b-22731424c443@iscas.ac.cn>
[-- 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 --]
next prev parent reply other threads:[~2022-08-10 5:52 UTC|newest]
Thread overview: 13+ messages / expand[flat|nested] mbox.gz Atom feed top
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 [this message]
2022-08-10 13:53 ` Weiwei Li
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=CAHBxVyGCv8h07FjO7-1GJq6SZDZ4URNr2STDV_ReU3PGRUJu2Q@mail.gmail.com \
--to=atishp@rivosinc.com \
--cc=Alistair.Francis@wdc.com \
--cc=bin.meng@windriver.com \
--cc=liweiwei@iscas.ac.cn \
--cc=palmer@dabbelt.com \
--cc=qemu-devel@nongnu.org \
--cc=qemu-riscv@nongnu.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).