qemu-riscv
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [PATCH v7 01/11] target/riscv: Combine set_mode and set_virt functio


From: Alistair Francis
Subject: Re: [PATCH v7 01/11] target/riscv: Combine set_mode and set_virt functions.
Date: Wed, 3 Jul 2024 11:07:14 +1000

On Thu, Jun 27, 2024 at 10:02 AM Atish Patra <atishp@rivosinc.com> wrote:
>
> From: Rajnesh Kanwal <rkanwal@rivosinc.com>
>
> Combining riscv_cpu_set_virt_enabled() and riscv_cpu_set_mode()
> functions. This is to make complete mode change information
> available through a single function.
>
> This allows to easily differentiate between HS->VS, VS->HS
> and VS->VS transitions when executing state update codes.
> For example: One use-case which inspired this change is
> to update mode-specific instruction and cycle counters
> which requires information of both prev mode and current
> mode.
>
> Signed-off-by: Rajnesh Kanwal <rkanwal@rivosinc.com>

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

Alistair

> ---
>  target/riscv/cpu.h        |  2 +-
>  target/riscv/cpu_helper.c | 57 
> +++++++++++++++++++++++------------------------
>  target/riscv/op_helper.c  | 17 +++++---------
>  3 files changed, 35 insertions(+), 41 deletions(-)
>
> diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h
> index 90b8f1b08f83..46faefd24e09 100644
> --- a/target/riscv/cpu.h
> +++ b/target/riscv/cpu.h
> @@ -544,7 +544,7 @@ void riscv_cpu_set_aia_ireg_rmw_fn(CPURISCVState *env, 
> uint32_t priv,
>  RISCVException smstateen_acc_ok(CPURISCVState *env, int index, uint64_t bit);
>  #endif /* !CONFIG_USER_ONLY */
>
> -void riscv_cpu_set_mode(CPURISCVState *env, target_ulong newpriv);
> +void riscv_cpu_set_mode(CPURISCVState *env, target_ulong newpriv, bool 
> virt_en);
>
>  void riscv_translate_init(void);
>  G_NORETURN void riscv_raise_exception(CPURISCVState *env,
> diff --git a/target/riscv/cpu_helper.c b/target/riscv/cpu_helper.c
> index 6709622dd3ab..10d3fdaed376 100644
> --- a/target/riscv/cpu_helper.c
> +++ b/target/riscv/cpu_helper.c
> @@ -619,30 +619,6 @@ void riscv_cpu_set_geilen(CPURISCVState *env, 
> target_ulong geilen)
>      env->geilen = geilen;
>  }
>
> -/* This function can only be called to set virt when RVH is enabled */
> -void riscv_cpu_set_virt_enabled(CPURISCVState *env, bool enable)
> -{
> -    /* Flush the TLB on all virt mode changes. */
> -    if (env->virt_enabled != enable) {
> -        tlb_flush(env_cpu(env));
> -    }
> -
> -    env->virt_enabled = enable;
> -
> -    if (enable) {
> -        /*
> -         * The guest external interrupts from an interrupt controller are
> -         * delivered only when the Guest/VM is running (i.e. V=1). This means
> -         * any guest external interrupt which is triggered while the Guest/VM
> -         * is not running (i.e. V=0) will be missed on QEMU resulting in 
> guest
> -         * with sluggish response to serial console input and other I/O 
> events.
> -         *
> -         * To solve this, we check and inject interrupt after setting V=1.
> -         */
> -        riscv_cpu_update_mip(env, 0, 0);
> -    }
> -}
> -
>  int riscv_cpu_claim_interrupts(RISCVCPU *cpu, uint64_t interrupts)
>  {
>      CPURISCVState *env = &cpu->env;
> @@ -715,7 +691,7 @@ void riscv_cpu_set_aia_ireg_rmw_fn(CPURISCVState *env, 
> uint32_t priv,
>      }
>  }
>
> -void riscv_cpu_set_mode(CPURISCVState *env, target_ulong newpriv)
> +void riscv_cpu_set_mode(CPURISCVState *env, target_ulong newpriv, bool 
> virt_en)
>  {
>      g_assert(newpriv <= PRV_M && newpriv != PRV_RESERVED);
>
> @@ -736,6 +712,28 @@ void riscv_cpu_set_mode(CPURISCVState *env, target_ulong 
> newpriv)
>       * preemptive context switch. As a result, do both.
>       */
>      env->load_res = -1;
> +
> +    if (riscv_has_ext(env, RVH)) {
> +        /* Flush the TLB on all virt mode changes. */
> +        if (env->virt_enabled != virt_en) {
> +            tlb_flush(env_cpu(env));
> +        }
> +
> +        env->virt_enabled = virt_en;
> +        if (virt_en) {
> +            /*
> +             * The guest external interrupts from an interrupt controller are
> +             * delivered only when the Guest/VM is running (i.e. V=1). This
> +             * means any guest external interrupt which is triggered while 
> the
> +             * Guest/VM is not running (i.e. V=0) will be missed on QEMU
> +             * resulting in guest with sluggish response to serial console
> +             * input and other I/O events.
> +             *
> +             * To solve this, we check and inject interrupt after setting 
> V=1.
> +             */
> +            riscv_cpu_update_mip(env, 0, 0);
> +        }
> +    }
>  }
>
>  /*
> @@ -1648,6 +1646,7 @@ void riscv_cpu_do_interrupt(CPUState *cs)
>  {
>      RISCVCPU *cpu = RISCV_CPU(cs);
>      CPURISCVState *env = &cpu->env;
> +    bool virt = env->virt_enabled;
>      bool write_gva = false;
>      uint64_t s;
>
> @@ -1778,7 +1777,7 @@ void riscv_cpu_do_interrupt(CPUState *cs)
>
>                  htval = env->guest_phys_fault_addr;
>
> -                riscv_cpu_set_virt_enabled(env, 0);
> +                virt = false;
>              } else {
>                  /* Trap into HS mode */
>                  env->hstatus = set_field(env->hstatus, HSTATUS_SPV, false);
> @@ -1799,7 +1798,7 @@ void riscv_cpu_do_interrupt(CPUState *cs)
>          env->htinst = tinst;
>          env->pc = (env->stvec >> 2 << 2) +
>                    ((async && (env->stvec & 3) == 1) ? cause * 4 : 0);
> -        riscv_cpu_set_mode(env, PRV_S);
> +        riscv_cpu_set_mode(env, PRV_S, virt);
>      } else {
>          /* handle the trap in M-mode */
>          if (riscv_has_ext(env, RVH)) {
> @@ -1815,7 +1814,7 @@ void riscv_cpu_do_interrupt(CPUState *cs)
>              mtval2 = env->guest_phys_fault_addr;
>
>              /* Trapping to M mode, virt is disabled */
> -            riscv_cpu_set_virt_enabled(env, 0);
> +            virt = false;
>          }
>
>          s = env->mstatus;
> @@ -1830,7 +1829,7 @@ void riscv_cpu_do_interrupt(CPUState *cs)
>          env->mtinst = tinst;
>          env->pc = (env->mtvec >> 2 << 2) +
>                    ((async && (env->mtvec & 3) == 1) ? cause * 4 : 0);
> -        riscv_cpu_set_mode(env, PRV_M);
> +        riscv_cpu_set_mode(env, PRV_M, virt);
>      }
>
>      /*
> diff --git a/target/riscv/op_helper.c b/target/riscv/op_helper.c
> index 2baf5bc3ca19..ec1408ba0fb1 100644
> --- a/target/riscv/op_helper.c
> +++ b/target/riscv/op_helper.c
> @@ -264,7 +264,7 @@ void helper_cbo_inval(CPURISCVState *env, target_ulong 
> address)
>  target_ulong helper_sret(CPURISCVState *env)
>  {
>      uint64_t mstatus;
> -    target_ulong prev_priv, prev_virt;
> +    target_ulong prev_priv, prev_virt = env->virt_enabled;
>
>      if (!(env->priv >= PRV_S)) {
>          riscv_raise_exception(env, RISCV_EXCP_ILLEGAL_INST, GETPC());
> @@ -307,11 +307,9 @@ target_ulong helper_sret(CPURISCVState *env)
>          if (prev_virt) {
>              riscv_cpu_swap_hypervisor_regs(env);
>          }
> -
> -        riscv_cpu_set_virt_enabled(env, prev_virt);
>      }
>
> -    riscv_cpu_set_mode(env, prev_priv);
> +    riscv_cpu_set_mode(env, prev_priv, prev_virt);
>
>      return retpc;
>  }
> @@ -347,16 +345,13 @@ target_ulong helper_mret(CPURISCVState *env)
>          mstatus = set_field(mstatus, MSTATUS_MPRV, 0);
>      }
>      env->mstatus = mstatus;
> -    riscv_cpu_set_mode(env, prev_priv);
> -
> -    if (riscv_has_ext(env, RVH)) {
> -        if (prev_virt) {
> -            riscv_cpu_swap_hypervisor_regs(env);
> -        }
>
> -        riscv_cpu_set_virt_enabled(env, prev_virt);
> +    if (riscv_has_ext(env, RVH) && prev_virt) {
> +        riscv_cpu_swap_hypervisor_regs(env);
>      }
>
> +    riscv_cpu_set_mode(env, prev_priv, prev_virt);
> +
>      return retpc;
>  }
>
>
> --
> 2.34.1
>
>



reply via email to

[Prev in Thread] Current Thread [Next in Thread]