From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 1D508C00140 for ; Mon, 8 Aug 2022 17:23:30 +0000 (UTC) Received: from localhost ([::1]:54930 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1oL6TR-0007LQ-4d for qemu-devel@archiver.kernel.org; Mon, 08 Aug 2022 13:23:29 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:33258) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1oL6RC-0004yZ-To for qemu-devel@nongnu.org; Mon, 08 Aug 2022 13:21:11 -0400 Received: from mail-pj1-x102a.google.com ([2607:f8b0:4864:20::102a]:56014) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1oL6R8-0004hL-W9 for qemu-devel@nongnu.org; Mon, 08 Aug 2022 13:21:10 -0400 Received: by mail-pj1-x102a.google.com with SMTP id a8so9388871pjg.5 for ; Mon, 08 Aug 2022 10:21:06 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=rivosinc-com.20210112.gappssmtp.com; s=20210112; h=cc:to:subject:message-id:date:from:in-reply-to:references :mime-version:from:to:cc; bh=tViUXqtVlEtIcRhKVxunCcBkR6Y/V7elu9ceNg5z3UE=; b=1m2j6Rcw7Ch9aZd+Wq1pzJkm7h3QJ1ZiutTWd/GAioMisdfzeE6e0c7+rAr6gP8Q/C jZdVuorUq07KLsrDf5xdFzQtcSjLasslYCkUwInRnLVU98gX4gWgE1trmbuYnQMLMWzH njI+LJfyyy9cQZsRDAiEAgGno7TwKkZ6jywFItzWZUP9XuRRwct8jAdeyfNtVh8nuPD4 HJ8rQj9ec7CazZbgzCEiIkOabA04xHDjOVBKmg3xRBlmG57YMicm/yj5DKJoVISX9PJO XTCmgh6V1HsCtZLkwH87XJlYvEEhUaDW7gT0M0TR3HcyQCQn9I4hzi3wN3e+BQmBD3gb g2Tg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=cc:to:subject:message-id:date:from:in-reply-to:references :mime-version:x-gm-message-state:from:to:cc; bh=tViUXqtVlEtIcRhKVxunCcBkR6Y/V7elu9ceNg5z3UE=; b=WTg8VkSjG0l3waiI05ggmg4SqB0bpPmBU25aBa+yci1Zmte/tmS3oaiab3xGrAIJcz 1286uYiDsQDRwm2oioL8cOcLYKPdQT29CPdO50BJL6D7x7NDnPfx/GMkEsgyTCm75mpo j4wSeU3aXdAuBXq9JkoI1xhV4CH/Xo0HP3jX9TUAdqw4tZMSYHr7PKEiCLOUxodzkCvN +KBDwSZiC0LCUll/QbxP+xI+E9DsfWNN1yoCC9czQai2t6KrLWuKm0N6YEJ5wMn5qWss euDrp/E9kJCNkMf9dYdVb5OYpRlMeDM/5gL0266q1uDS3wWpoyv6WstF3jOOxcWiFiz4 gabA== X-Gm-Message-State: ACgBeo0JmezOk9GD5TgdLDMXOONsJDzQaVL7ggJQJxveW01NkdpYxpw5 kcgJFdJWiCdd3hKj2YQJuwgrTrFF3SAg+V7vt2P3/w== X-Google-Smtp-Source: AA6agR49asHQQIvrfgSw+MCVcbJtuOj6YXc+A5HGkTrsBGPU+23Mi9bvbIqKV6v11XHuIpj6V+7S2SG+5t1kJ/ggVQA= X-Received: by 2002:a17:902:7845:b0:16e:ea31:3354 with SMTP id e5-20020a170902784500b0016eea313354mr19153697pln.17.1659979265134; Mon, 08 Aug 2022 10:21:05 -0700 (PDT) MIME-Version: 1.0 References: <20220804014240.2514957-1-atishp@rivosinc.com> <20220804014240.2514957-4-atishp@rivosinc.com> In-Reply-To: From: Atish Kumar Patra Date: Mon, 8 Aug 2022 10:20:54 -0700 Message-ID: Subject: Re: [PATCH v8 3/3] target/riscv: Add vstimecmp support To: Weiwei Li Cc: qemu-devel@nongnu.org, Alistair Francis , Bin Meng , Palmer Dabbelt , qemu-riscv@nongnu.org Content-Type: multipart/alternative; boundary="0000000000006ee78405e5be0a71" Received-SPF: pass client-ip=2607:f8b0:4864:20::102a; envelope-from=atishp@rivosinc.com; helo=mail-pj1-x102a.google.com X-Spam_score_int: -18 X-Spam_score: -1.9 X-Spam_bar: - X-Spam_report: (-1.9 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, HTML_MESSAGE=0.001, RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001, T_SCC_BODY_TEXT_LINE=-0.01 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Sender: "Qemu-devel" --0000000000006ee78405e5be0a71 Content-Type: text/plain; charset="UTF-8" Content-Transfer-Encoding: quoted-printable On Sun, Aug 7, 2022 at 6:50 PM Weiwei Li wrote: > > =E5=9C=A8 2022/8/4 =E4=B8=8A=E5=8D=889:42, Atish Patra =E5=86=99=E9=81=93= : > > 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 > > --- > > 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 =3D get_field(env->hstatus, HSTATUS_VGEIN); > > uint64_t vsgein =3D (env->hgeip & (1ULL << gein)) ? MIP_VSEIP : 0= ; > > + uint64_t vstip =3D (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 =3D &cpu->env; > > CPUState *cs =3D CPU(cpu); > > - uint64_t gein, vsgein =3D 0, old =3D env->mip; > > + uint64_t gein, vsgein =3D 0, vstip =3D 0, old =3D env->mip; > > bool locked =3D 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 =3D (env->hgeip & (1ULL << gein)) ? MIP_VSEIP : 0; > > } > > > > + /* No need to update mip for VSTIP */ > > + mask =3D ((mask =3D=3D MIP_VSTIP) && env->vstime_irq) ? 0 : mask; > > + vstip =3D env->vstime_irq ? MIP_VSTIP : 0; > > + > > if (!qemu_mutex_iothread_locked()) { > > locked =3D 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 =3D (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 =3D env_cpu(env); > > + RISCVCPU *cpu =3D RISCV_CPU(cs); > > + > > + if (!cpu->cfg.ext_sstc || !env->rdtime_fn) { > > + return RISCV_EXCP_ILLEGAL_INST; > > + } > > + > > + if (env->priv =3D=3D 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 =3D env->vstimecmp; > > + > > + return RISCV_EXCP_NONE; > > +} > > + > > +static RISCVException read_vstimecmph(CPURISCVState *env, int csrno, > > + target_ulong *val) > > +{ > > + *val =3D env->vstimecmp >> 32; > > + > > + return RISCV_EXCP_NONE; > > +} > > + > > +static RISCVException write_vstimecmp(CPURISCVState *env, int csrno, > > + target_ulong val) > > +{ > > + RISCVCPU *cpu =3D env_archcpu(env); > > + > > + if (riscv_cpu_mxl(env) =3D=3D MXL_RV32) { > > + env->vstimecmp =3D deposit64(env->vstimecmp, 0, 32, > (uint64_t)val); > > + } else { > > + env->vstimecmp =3D 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 =3D env_archcpu(env); > > + > > + env->vstimecmp =3D 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 =3D env->stimecmp; > > + if (riscv_cpu_virt_enabled(env)) { > > + *val =3D env->vstimecmp; > > + } else { > > + *val =3D env->stimecmp; > > + } > > + > > return RISCV_EXCP_NONE; > > } > > > > static RISCVException read_stimecmph(CPURISCVState *env, int csrno, > > target_ulong *val) > > { > > - *val =3D env->stimecmp >> 32; > > + if (riscv_cpu_virt_enabled(env)) { > > + *val =3D env->vstimecmp >> 32; > > + } else { > > + *val =3D env->stimecmp >> 32; > > + } > > + > > return RISCV_EXCP_NONE; > > } > > > > @@ -848,6 +931,10 @@ static RISCVException write_stimecmp(CPURISCVState > *env, int csrno, > > { > > RISCVCPU *cpu =3D env_archcpu(env); > > > > + if (riscv_cpu_virt_enabled(env)) { > > + return write_vstimecmp(env, csrno, val); > > + } > > + > > if (riscv_cpu_mxl(env) =3D=3D MXL_RV32) { > > env->stimecmp =3D deposit64(env->stimecmp, 0, 32, (uint64_t)v= al); > > } else { > > @@ -864,6 +951,10 @@ static RISCVException write_stimecmph(CPURISCVStat= e > *env, int csrno, > > { > > RISCVCPU *cpu =3D env_archcpu(env); > > > > + if (riscv_cpu_virt_enabled(env)) { > > + return write_vstimecmph(env, csrno, val); > > + } > > + > > env->stimecmp =3D 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 !=3D CSR_HVIP) { > > gin =3D get_field(env->hstatus, HSTATUS_VGEIN); > > old_mip |=3D (env->hgeip & ((target_ulong)1 << gin)) ? MIP_VS= EIP > : 0; > > + old_mip |=3D env->vstime_irq ? MIP_VSTIP : 0; > > } > > > > if (ret_val) { > > @@ -3661,6 +3753,12 @@ riscv_csr_operations csr_ops[CSR_TABLE_SIZE] =3D= { > > .min_priv_ver =3D > PRIV_VERSION_1_12_0 }, > > [CSR_STIMECMPH] =3D { "stimecmph", sstc, read_stimecmph, > write_stimecmph, > > .min_priv_ver =3D > PRIV_VERSION_1_12_0 }, > > + [CSR_VSTIMECMP] =3D { "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 =3D > PRIV_VERSION_1_12_0 }, > > + [CSR_VSTIMECMPH] =3D { "vstimecmph", sstc_hmode, read_vstimecmph, > > + write_vstimecmph, > > + .min_priv_ver =3D > PRIV_VERSION_1_12_0 }, > > > > /* Supervisor Protection and Translation */ > > [CSR_SATP] =3D { "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 =3D { > > 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 =3D opaque; > > + CPURISCVState *env =3D &cpu->env; > > + env->vstime_irq =3D 1; > > + riscv_cpu_update_mip(cpu, MIP_VSTIP, BOOL_TO_MASK(1)); > > +} > > + > > static void riscv_stimer_cb(void *opaque) > > { > > RISCVCPU *cpu =3D 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 =3D=3D MIP_VSTIP) { > > + env->vstime_irq =3D 1; > > + } > > riscv_cpu_update_mip(cpu, timer_irq, BOOL_TO_MASK(1)); > > return; > > } > > > > + if (timer_irq =3D=3D MIP_VSTIP) { > > + env->vstime_irq =3D 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 =3D timer_new_ns(QEMU_CLOCK_VIRTUAL, &riscv_stimer_cb= , > cpu); > > env->stimecmp =3D 0; > > > > + env->vstimer =3D timer_new_ns(QEMU_CLOCK_VIRTUAL, &riscv_vstimer_c= b, > cpu); > > + env->vstimecmp =3D 0; > > } > > --0000000000006ee78405e5be0a71 Content-Type: text/html; charset="UTF-8" Content-Transfer-Encoding: quoted-printable


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

=E5=9C=A8 2022/8/4 =E4=B8=8A=E5=8D=889:42, Atish Patra =E5=86=99=E9=81=93:<= br> > 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>
> ---
>=C2=A0 =C2=A0target/riscv/cpu.h=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0|=C2= =A0 =C2=A04 ++
>=C2=A0 =C2=A0target/riscv/cpu_bits.h=C2=A0 =C2=A0 |=C2=A0 =C2=A04 ++ >=C2=A0 =C2=A0target/riscv/cpu_helper.c=C2=A0 |=C2=A0 11 ++--
>=C2=A0 =C2=A0target/riscv/csr.c=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0| 102 = ++++++++++++++++++++++++++++++++++++-
>=C2=A0 =C2=A0target/riscv/machine.c=C2=A0 =C2=A0 =C2=A0|=C2=A0 =C2=A01 = +
>=C2=A0 =C2=A0target/riscv/time_helper.c |=C2=A0 16 ++++++
>=C2=A0 =C2=A06 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 {
>=C2=A0 =C2=A0 =C2=A0 =C2=A0/* Sstc CSRs */
>=C2=A0 =C2=A0 =C2=A0 =C2=A0uint64_t stimecmp;
>=C2=A0 =C2=A0
> +=C2=A0 =C2=A0 uint64_t vstimecmp;
> +
>=C2=A0 =C2=A0 =C2=A0 =C2=A0/* physical memory protection */
>=C2=A0 =C2=A0 =C2=A0 =C2=A0pmp_table_t pmp_state;
>=C2=A0 =C2=A0 =C2=A0 =C2=A0target_ulong mseccfg;
> @@ -366,6 +368,8 @@ struct CPUArchState {
>=C2=A0 =C2=A0
>=C2=A0 =C2=A0 =C2=A0 =C2=A0/* Fields from here on are preserved across = CPU reset. */
>=C2=A0 =C2=A0 =C2=A0 =C2=A0QEMUTimer *stimer; /* Internal timer for S-m= ode interrupt */
> +=C2=A0 =C2=A0 QEMUTimer *vstimer; /* Internal timer for VS-mode inter= rupt */
> +=C2=A0 =C2=A0 bool vstime_irq;
>=C2=A0 =C2=A0
>=C2=A0 =C2=A0 =C2=A0 =C2=A0hwaddr kernel_addr;
>=C2=A0 =C2=A0 =C2=A0 =C2=A0hwaddr 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 @@
>=C2=A0 =C2=A0#define CSR_VSIP=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = 0x244
>=C2=A0 =C2=A0#define CSR_VSATP=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= 0x280
>=C2=A0 =C2=A0
> +/* Sstc virtual CSRs */
> +#define CSR_VSTIMECMP=C2=A0 =C2=A0 =C2=A0 =C2=A00x24D
> +#define CSR_VSTIMECMPH=C2=A0 =C2=A0 =C2=A0 0x25D
> +
>=C2=A0 =C2=A0#define CSR_MTINST=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 0x34a=
>=C2=A0 =C2=A0#define CSR_MTVAL2=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 0x34b=
>=C2=A0 =C2=A0
> 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)=
>=C2=A0 =C2=A0{
>=C2=A0 =C2=A0 =C2=A0 =C2=A0uint32_t gein =3D get_field(env->hstatus,= HSTATUS_VGEIN);
>=C2=A0 =C2=A0 =C2=A0 =C2=A0uint64_t vsgein =3D (env->hgeip & (1U= LL << gein)) ? MIP_VSEIP : 0;
> +=C2=A0 =C2=A0 uint64_t vstip =3D (env->vstime_irq) ? MIP_VSTIP : 0= ;
>=C2=A0 =C2=A0
> -=C2=A0 =C2=A0 return (env->mip | vsgein) & env->mie;
> +=C2=A0 =C2=A0 return (env->mip | vsgein | vstip) & env->mie= ;
>=C2=A0 =C2=A0}
>=C2=A0 =C2=A0
>=C2=A0 =C2=A0int riscv_cpu_mirq_pending(CPURISCVState *env)
> @@ -605,7 +606,7 @@ uint64_t riscv_cpu_update_mip(RISCVCPU *cpu, uint6= 4_t mask, uint64_t value)
>=C2=A0 =C2=A0{
>=C2=A0 =C2=A0 =C2=A0 =C2=A0CPURISCVState *env =3D &cpu->env;
>=C2=A0 =C2=A0 =C2=A0 =C2=A0CPUState *cs =3D CPU(cpu);
> -=C2=A0 =C2=A0 uint64_t gein, vsgein =3D 0, old =3D env->mip;
> +=C2=A0 =C2=A0 uint64_t gein, vsgein =3D 0, vstip =3D 0, old =3D env-&= gt;mip;
>=C2=A0 =C2=A0 =C2=A0 =C2=A0bool locked =3D false;
>=C2=A0 =C2=A0
>=C2=A0 =C2=A0 =C2=A0 =C2=A0if (riscv_cpu_virt_enabled(env)) {
> @@ -613,6 +614,10 @@ uint64_t riscv_cpu_update_mip(RISCVCPU *cpu, uint= 64_t mask, uint64_t value)
>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0vsgein =3D (env->hgeip &= ; (1ULL << gein)) ? MIP_VSEIP : 0;
>=C2=A0 =C2=A0 =C2=A0 =C2=A0}
>=C2=A0 =C2=A0
> +=C2=A0 =C2=A0 /* No need to update mip for VSTIP */
> +=C2=A0 =C2=A0 mask =3D ((mask =3D=3D MIP_VSTIP) && env->vs= time_irq) ? 0 : mask;
> +=C2=A0 =C2=A0 vstip =3D env->vstime_irq ? MIP_VSTIP : 0;
> +
>=C2=A0 =C2=A0 =C2=A0 =C2=A0if (!qemu_mutex_iothread_locked()) {
>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0locked =3D true;
>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0qemu_mutex_lock_iothread(); > @@ -620,7 +625,7 @@ uint64_t riscv_cpu_update_mip(RISCVCPU *cpu, uint6= 4_t mask, uint64_t value)
>=C2=A0 =C2=A0
>=C2=A0 =C2=A0 =C2=A0 =C2=A0env->mip =3D (env->mip & ~mask) | = (value & mask);
>=C2=A0 =C2=A0
> -=C2=A0 =C2=A0 if (env->mip | vsgein) {
> +=C2=A0 =C2=A0 if (env->mip | vsgein | vstip) {
>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0cpu_interrupt(cs, CPU_INTERRUP= T_HARD);
>=C2=A0 =C2=A0 =C2=A0 =C2=A0} else {
>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0cpu_reset_interrupt(cs, CPU_IN= TERRUPT_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)
>=C2=A0 =C2=A0 =C2=A0 =C2=A0return smode(env, csrno);
>=C2=A0 =C2=A0}
>=C2=A0 =C2=A0
> +static RISCVException sstc_hmode(CPURISCVState *env, int csrno)
> +{
> +=C2=A0 =C2=A0 CPUState *cs =3D env_cpu(env);
> +=C2=A0 =C2=A0 RISCVCPU *cpu =3D RISCV_CPU(cs);
> +
> +=C2=A0 =C2=A0 if (!cpu->cfg.ext_sstc || !env->rdtime_fn) {
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 return RISCV_EXCP_ILLEGAL_INST;
> +=C2=A0 =C2=A0 }
> +
> +=C2=A0 =C2=A0 if (env->priv =3D=3D PRV_M) {
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 return RISCV_EXCP_NONE;
> +=C2=A0 =C2=A0 }
> +
> +=C2=A0 =C2=A0 if (!(get_field(env->mcounteren, COUNTEREN_TM) &=
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 get_field(env->menvcfg, MENVCFG= _STCE))) {
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 return RISCV_EXCP_ILLEGAL_INST;
> +=C2=A0 =C2=A0 }
> +
> +=C2=A0 =C2=A0 if (riscv_cpu_virt_enabled(env)) {
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 if (!(get_field(env->hcounteren, COUNT= EREN_TM) &
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 get_field(env->he= nvcfg, HENVCFG_STCE))) {
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 return RISCV_EXCP_VIRT_INST= RUCTION_FAULT;
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 }
> +=C2=A0 =C2=A0 }
> +

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=C2=A0 vstimecmp, however


We don't need to check hcounteren = while accessing scountern. Thus it will be an unnecessary
check t= here. Predicate function check should do the required sanity check required= only for that specific CSR.
That's why, I think it is the co= rrect place.
=C2=A0
it controls it via stimecmp.

> +=C2=A0 =C2=A0 return hmode(env, csrno);
> +}
> +
> +static RISCVException read_vstimecmp(CPURISCVState *env, int csrno, > +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 target_ulong *val)=
> +{
> +=C2=A0 =C2=A0 *val =3D env->vstimecmp;
> +
> +=C2=A0 =C2=A0 return RISCV_EXCP_NONE;
> +}
> +
> +static RISCVException read_vstimecmph(CPURISCVState *env, int csrno,<= br> > +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 target_ulong *val)=
> +{
> +=C2=A0 =C2=A0 *val =3D env->vstimecmp >> 32;
> +
> +=C2=A0 =C2=A0 return RISCV_EXCP_NONE;
> +}
> +
> +static RISCVException write_vstimecmp(CPURISCVState *env, int csrno,<= br> > +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 target_ulong val)<= br> > +{
> +=C2=A0 =C2=A0 RISCVCPU *cpu =3D env_archcpu(env);
> +
> +=C2=A0 =C2=A0 if (riscv_cpu_mxl(env) =3D=3D MXL_RV32) {
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 env->vstimecmp =3D deposit64(env->v= stimecmp, 0, 32, (uint64_t)val);
> +=C2=A0 =C2=A0 } else {
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 env->vstimecmp =3D val;
> +=C2=A0 =C2=A0 }
> +
> +=C2=A0 =C2=A0 riscv_timer_write_timecmp(cpu, env->vstimer, env->= ;vstimecmp,
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 env->htimedelta, MIP_VSTIP);
> +
> +=C2=A0 =C2=A0 return RISCV_EXCP_NONE;
> +}
> +
> +static RISCVException write_vstimecmph(CPURISCVState *env, int csrno,=
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 target_ulong val)<= br> > +{
> +=C2=A0 =C2=A0 RISCVCPU *cpu =3D env_archcpu(env);
> +
> +=C2=A0 =C2=A0 env->vstimecmp =3D deposit64(env->vstimecmp, 32, = 32, (uint64_t)val);
> +=C2=A0 =C2=A0 riscv_timer_write_timecmp(cpu, env->vstimer, env->= ;vstimecmp,
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 env->htimedelta, MIP_VSTIP);
> +
> +=C2=A0 =C2=A0 return RISCV_EXCP_NONE;
> +}
> +
>=C2=A0 =C2=A0static RISCVException read_stimecmp(CPURISCVState *env, in= t csrno,
>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0target= _ulong *val)
>=C2=A0 =C2=A0{
> -=C2=A0 =C2=A0 *val =3D env->stimecmp;
> +=C2=A0 =C2=A0 if (riscv_cpu_virt_enabled(env)) {
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 *val =3D env->vstimecmp;
> +=C2=A0 =C2=A0 } else {
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 *val =3D env->stimecmp;
> +=C2=A0 =C2=A0 }
> +
>=C2=A0 =C2=A0 =C2=A0 =C2=A0return RISCV_EXCP_NONE;
>=C2=A0 =C2=A0}
>=C2=A0 =C2=A0
>=C2=A0 =C2=A0static RISCVException read_stimecmph(CPURISCVState *env, i= nt csrno,
>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0target= _ulong *val)
>=C2=A0 =C2=A0{
> -=C2=A0 =C2=A0 *val =3D env->stimecmp >> 32;
> +=C2=A0 =C2=A0 if (riscv_cpu_virt_enabled(env)) {
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 *val =3D env->vstimecmp >> 32; > +=C2=A0 =C2=A0 } else {
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 *val =3D env->stimecmp >> 32; > +=C2=A0 =C2=A0 }
> +
>=C2=A0 =C2=A0 =C2=A0 =C2=A0return RISCV_EXCP_NONE;
>=C2=A0 =C2=A0}
>=C2=A0 =C2=A0
> @@ -848,6 +931,10 @@ static RISCVException write_stimecmp(CPURISCVStat= e *env, int csrno,
>=C2=A0 =C2=A0{
>=C2=A0 =C2=A0 =C2=A0 =C2=A0RISCVCPU *cpu =3D env_archcpu(env);
>=C2=A0 =C2=A0
> +=C2=A0 =C2=A0 if (riscv_cpu_virt_enabled(env)) {
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 return write_vstimecmp(env, csrno, val);<= br> > +=C2=A0 =C2=A0 }
> +
>=C2=A0 =C2=A0 =C2=A0 =C2=A0if (riscv_cpu_mxl(env) =3D=3D MXL_RV32) { >=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0env->stimecmp =3D deposit64= (env->stimecmp, 0, 32, (uint64_t)val);
>=C2=A0 =C2=A0 =C2=A0 =C2=A0} else {
> @@ -864,6 +951,10 @@ static RISCVException write_stimecmph(CPURISCVSta= te *env, int csrno,
>=C2=A0 =C2=A0{
>=C2=A0 =C2=A0 =C2=A0 =C2=A0RISCVCPU *cpu =3D env_archcpu(env);
>=C2=A0 =C2=A0
> +=C2=A0 =C2=A0 if (riscv_cpu_virt_enabled(env)) {
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 return write_vstimecmph(env, csrno, val);=
> +=C2=A0 =C2=A0 }
> +
>=C2=A0 =C2=A0 =C2=A0 =C2=A0env->stimecmp =3D deposit64(env->stime= cmp, 32, 32, (uint64_t)val);
>=C2=A0 =C2=A0 =C2=A0 =C2=A0riscv_timer_write_timecmp(cpu, env->stime= r, env->stimecmp, 0, MIP_STIP);
>=C2=A0 =C2=A0
> @@ -1801,6 +1892,7 @@ static RISCVException rmw_mip64(CPURISCVState *e= nv, int csrno,
>=C2=A0 =C2=A0 =C2=A0 =C2=A0if (csrno !=3D CSR_HVIP) {
>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0gin =3D get_field(env->hsta= tus, HSTATUS_VGEIN);
>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0old_mip |=3D (env->hgeip &a= mp; ((target_ulong)1 << gin)) ? MIP_VSEIP : 0;
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 old_mip |=3D env->vstime_irq ? MIP_VST= IP : 0;
>=C2=A0 =C2=A0 =C2=A0 =C2=A0}
>=C2=A0 =C2=A0
>=C2=A0 =C2=A0 =C2=A0 =C2=A0if (ret_val) {
> @@ -3661,6 +3753,12 @@ riscv_csr_operations csr_ops[CSR_TABLE_SIZE] = =3D {
>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0.min_priv_ver =3D PRIV_VERSION_1_12_0 },
>=C2=A0 =C2=A0 =C2=A0 =C2=A0[CSR_STIMECMPH] =3D { "stimecmph",= sstc, read_stimecmph, write_stimecmph,
>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0.min_priv_ver =3D PRIV_VERSION_1_12_0 },
> +=C2=A0 =C2=A0 [CSR_VSTIMECMP] =3D { "vstimecmp", sstc_hmode= , read_vstimecmp,
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 write_vstimecmp,

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


Sure. I will fix that.
=C2= =A0
Regards,

Weiwei Li

> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 .min_priv_ver =3D PRIV_VERSION_1_12_0 },
> +=C2=A0 =C2=A0 [CSR_VSTIMECMPH] =3D { "vstimecmph", sstc_hmo= de, read_vstimecmph,
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 write_vstimecmph,
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 .min_priv_ver =3D PRIV_VERSION_1_12_0 },
>=C2=A0 =C2=A0
>=C2=A0 =C2=A0 =C2=A0 =C2=A0/* Supervisor Protection and Translation */<= br> >=C2=A0 =C2=A0 =C2=A0 =C2=A0[CSR_SATP]=C2=A0 =C2=A0 =C2=A0=3D { "sa= tp",=C2=A0 =C2=A0 =C2=A0smode, read_satp,=C2=A0 =C2=A0 =C2=A0write_sat= p=C2=A0 =C2=A0 =C2=A0},
> 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 =3D {<= br> >=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0VMSTATE_UINTTL(env.hgeie, RISC= VCPU),
>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0VMSTATE_UINTTL(env.hgeip, RISC= VCPU),
>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0VMSTATE_UINT64(env.htimedelta,= RISCVCPU),
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 VMSTATE_UINT64(env.vstimecmp, RISCVCPU),<= br> >=C2=A0 =C2=A0
>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0VMSTATE_UINTTL(env.hvictl, RIS= CVCPU),
>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0VMSTATE_UINT8_ARRAY(env.hvipri= o, 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 @@
>=C2=A0 =C2=A0#include "time_helper.h"
>=C2=A0 =C2=A0#include "hw/intc/riscv_aclint.h"
>=C2=A0 =C2=A0
> +static void riscv_vstimer_cb(void *opaque)
> +{
> +=C2=A0 =C2=A0 RISCVCPU *cpu =3D opaque;
> +=C2=A0 =C2=A0 CPURISCVState *env =3D &cpu->env;
> +=C2=A0 =C2=A0 env->vstime_irq =3D 1;
> +=C2=A0 =C2=A0 riscv_cpu_update_mip(cpu, MIP_VSTIP, BOOL_TO_MASK(1));<= br> > +}
> +
>=C2=A0 =C2=A0static void riscv_stimer_cb(void *opaque)
>=C2=A0 =C2=A0{
>=C2=A0 =C2=A0 =C2=A0 =C2=A0RISCVCPU *cpu =3D opaque;
> @@ -47,10 +55,16 @@ void riscv_timer_write_timecmp(RISCVCPU *cpu, QEMU= Timer *timer,
>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 * If we're setting an sti= mecmp value in the "past",
>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 * immediately raise the timer= interrupt
>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 */
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 if (timer_irq =3D=3D MIP_VSTIP) {
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 env->vstime_irq =3D 1; > +=C2=A0 =C2=A0 =C2=A0 =C2=A0 }
>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0riscv_cpu_update_mip(cpu, time= r_irq, BOOL_TO_MASK(1));
>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0return;
>=C2=A0 =C2=A0 =C2=A0 =C2=A0}
>=C2=A0 =C2=A0
> +=C2=A0 =C2=A0 if (timer_irq =3D=3D MIP_VSTIP) {
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 env->vstime_irq =3D 0;
> +=C2=A0 =C2=A0 }
>=C2=A0 =C2=A0 =C2=A0 =C2=A0/* Clear the [V]STIP bit in mip */
>=C2=A0 =C2=A0 =C2=A0 =C2=A0riscv_cpu_update_mip(cpu, timer_irq, BOOL_TO= _MASK(0));
>=C2=A0 =C2=A0
> @@ -95,4 +109,6 @@ void riscv_timer_init(RISCVCPU *cpu)
>=C2=A0 =C2=A0 =C2=A0 =C2=A0env->stimer =3D timer_new_ns(QEMU_CLOCK_V= IRTUAL, &riscv_stimer_cb, cpu);
>=C2=A0 =C2=A0 =C2=A0 =C2=A0env->stimecmp =3D 0;
>=C2=A0 =C2=A0
> +=C2=A0 =C2=A0 env->vstimer =3D timer_new_ns(QEMU_CLOCK_VIRTUAL, &a= mp;riscv_vstimer_cb, cpu);
> +=C2=A0 =C2=A0 env->vstimecmp =3D 0;
>=C2=A0 =C2=A0}

--0000000000006ee78405e5be0a71--