qemu-riscv
[Top][All Lists]
Advanced

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

Re: [PATCH v1 2/4] target/riscv: Add itrigger support when icount is ena


From: Alistair Francis
Subject: Re: [PATCH v1 2/4] target/riscv: Add itrigger support when icount is enabled
Date: Thu, 10 Nov 2022 08:50:04 +1000

On Thu, Oct 13, 2022 at 4:43 PM LIU Zhiwei <zhiwei_liu@linux.alibaba.com> wrote:
>
> The max count in itrigger can be 0x3FFF, which will cause a no trivial
> translation and execution overload.
>
> When icount is enabled, QEMU provides API that can fetch guest
> instruction number. Thus, we can set an timer for itrigger with
> the count as deadline.
>
> Only when timer expires or priviledge mode changes, do lazy update
> to count.
>
> Signed-off-by: LIU Zhiwei <zhiwei_liu@linux.alibaba.com>

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

Alistair

> ---
>  target/riscv/cpu.h        |  2 ++
>  target/riscv/cpu_helper.c |  3 ++
>  target/riscv/debug.c      | 59 +++++++++++++++++++++++++++++++++++++++
>  target/riscv/debug.h      |  1 +
>  4 files changed, 65 insertions(+)
>
> diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h
> index 24bafda27d..13ca0f20ae 100644
> --- a/target/riscv/cpu.h
> +++ b/target/riscv/cpu.h
> @@ -329,6 +329,8 @@ struct CPUArchState {
>      target_ulong tdata3[RV_MAX_TRIGGERS];
>      struct CPUBreakpoint *cpu_breakpoint[RV_MAX_TRIGGERS];
>      struct CPUWatchpoint *cpu_watchpoint[RV_MAX_TRIGGERS];
> +    QEMUTimer *itrigger_timer[RV_MAX_TRIGGERS];
> +    int64_t last_icount;
>
>      /* machine specific rdtime callback */
>      uint64_t (*rdtime_fn)(void *);
> diff --git a/target/riscv/cpu_helper.c b/target/riscv/cpu_helper.c
> index 263282f230..7d8089b218 100644
> --- a/target/riscv/cpu_helper.c
> +++ b/target/riscv/cpu_helper.c
> @@ -676,6 +676,9 @@ void riscv_cpu_set_mode(CPURISCVState *env, target_ulong 
> newpriv)
>      if (newpriv == PRV_H) {
>          newpriv = PRV_U;
>      }
> +    if (icount_enabled() && newpriv != env->priv) {
> +        riscv_itrigger_update_priv(env);
> +    }
>      /* tlb_flush is unnecessary as mode is contained in mmu_idx */
>      env->priv = newpriv;
>      env->xl = cpu_recompute_xl(env);
> diff --git a/target/riscv/debug.c b/target/riscv/debug.c
> index 45a3537d5c..5ff70430a1 100644
> --- a/target/riscv/debug.c
> +++ b/target/riscv/debug.c
> @@ -30,6 +30,7 @@
>  #include "trace.h"
>  #include "exec/exec-all.h"
>  #include "exec/helper-proto.h"
> +#include "sysemu/cpu-timers.h"
>
>  /*
>   * The following M-mode trigger CSRs are implemented:
> @@ -569,6 +570,62 @@ void helper_itrigger_match(CPURISCVState *env)
>      }
>  }
>
> +static void riscv_itrigger_update_count(CPURISCVState *env)
> +{
> +    int count, executed;
> +    /*
> +     * Record last icount, so that we can evaluate the executed instructions
> +     * since last priviledge mode change or timer expire.
> +     */
> +    int64_t last_icount = env->last_icount, current_icount;
> +    current_icount = env->last_icount = icount_get_raw();
> +
> +    for (int i = 0; i < RV_MAX_TRIGGERS; i++) {
> +        if (get_trigger_type(env, i) != TRIGGER_TYPE_INST_CNT) {
> +            continue;
> +        }
> +        count = itrigger_get_count(env, i);
> +        if (!count) {
> +            continue;
> +        }
> +        /*
> +         * Only when priviledge is changed or itrigger timer expires,
> +         * the count field in itrigger tdata1 register is updated.
> +         * And the count field in itrigger only contains remaining value.
> +         */
> +        if (check_itrigger_priv(env, i)) {
> +            /*
> +             * If itrigger enabled in this priviledge mode, the number of
> +             * executed instructions since last priviledge change
> +             * should be reduced from current itrigger count.
> +             */
> +            executed = current_icount - last_icount;
> +            itrigger_set_count(env, i, count - executed);
> +            if (count == executed) {
> +                do_trigger_action(env, i);
> +            }
> +        } else {
> +            /*
> +             * If itrigger is not enabled in this priviledge mode,
> +             * the number of executed instructions will be discard and
> +             * the count field in itrigger will not change.
> +             */
> +            timer_mod(env->itrigger_timer[i],
> +                      current_icount + count);
> +        }
> +    }
> +}
> +
> +static void riscv_itrigger_timer_cb(void *opaque)
> +{
> +    riscv_itrigger_update_count((CPURISCVState *)opaque);
> +}
> +
> +void riscv_itrigger_update_priv(CPURISCVState *env)
> +{
> +    riscv_itrigger_update_count(env);
> +}
> +
>  target_ulong tdata_csr_read(CPURISCVState *env, int tdata_index)
>  {
>      switch (tdata_index) {
> @@ -798,5 +855,7 @@ void riscv_trigger_init(CPURISCVState *env)
>          env->tdata3[i] = 0;
>          env->cpu_breakpoint[i] = NULL;
>          env->cpu_watchpoint[i] = NULL;
> +        env->itrigger_timer[i] = timer_new_ns(QEMU_CLOCK_VIRTUAL,
> +                                              riscv_itrigger_timer_cb, env);
>      }
>  }
> diff --git a/target/riscv/debug.h b/target/riscv/debug.h
> index cc3358e69b..c471748d5a 100644
> --- a/target/riscv/debug.h
> +++ b/target/riscv/debug.h
> @@ -146,4 +146,5 @@ bool riscv_cpu_debug_check_watchpoint(CPUState *cs, 
> CPUWatchpoint *wp);
>  void riscv_trigger_init(CPURISCVState *env);
>
>  bool riscv_itrigger_enabled(CPURISCVState *env);
> +void riscv_itrigger_update_priv(CPURISCVState *env);
>  #endif /* RISCV_DEBUG_H */
> --
> 2.17.1
>
>



reply via email to

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