Unverified Commit c6957248 authored by Anup Patel's avatar Anup Patel Committed by Palmer Dabbelt
Browse files

target/riscv: Emulate TIME CSRs for privileged mode



Currently, TIME CSRs are emulated only for user-only mode. This
patch add TIME CSRs emulation for privileged mode.

For privileged mode, the TIME CSRs will return value provided
by rdtime callback which is registered by QEMU machine/platform
emulation (i.e. CLINT emulation). If rdtime callback is not
available then the monitor (i.e. OpenSBI) will trap-n-emulate
TIME CSRs in software.

We see 25+% performance improvement in hackbench numbers when
TIME CSRs are not trap-n-emulated.

Signed-off-by: default avatarAnup Patel <anup.patel@wdc.com>
Reviewed-by: default avatarAlistair Francis <alistair.francis@wdc.com>
Signed-off-by: default avatarPalmer Dabbelt <palmerdabbelt@google.com>
parent acead54c
Loading
Loading
Loading
Loading
+5 −0
Original line number Diff line number Diff line
@@ -159,6 +159,7 @@ struct CPURISCVState {
    target_ulong htval;
    target_ulong htinst;
    target_ulong hgatp;
    uint64_t htimedelta;

    /* Virtual CSRs */
    target_ulong vsstatus;
@@ -201,6 +202,9 @@ struct CPURISCVState {
    /* physical memory protection */
    pmp_table_t pmp_state;

    /* machine specific rdtime callback */
    uint64_t (*rdtime_fn)(void);

    /* True if in debugger mode.  */
    bool debugger;
#endif
@@ -322,6 +326,7 @@ void riscv_cpu_swap_hypervisor_regs(CPURISCVState *env);
int riscv_cpu_claim_interrupts(RISCVCPU *cpu, uint32_t interrupts);
uint32_t riscv_cpu_update_mip(RISCVCPU *cpu, uint32_t mask, uint32_t value);
#define BOOL_TO_MASK(x) (-!!(x)) /* helper for riscv_cpu_update_mip value */
void riscv_cpu_set_rdtime_fn(CPURISCVState *env, uint64_t (*fn)(void));
#endif
void riscv_cpu_set_mode(CPURISCVState *env, target_ulong newpriv);

+5 −0
Original line number Diff line number Diff line
@@ -258,6 +258,11 @@ uint32_t riscv_cpu_update_mip(RISCVCPU *cpu, uint32_t mask, uint32_t value)
    return old;
}

void riscv_cpu_set_rdtime_fn(CPURISCVState *env, uint64_t (*fn)(void))
{
    env->rdtime_fn = fn;
}

void riscv_cpu_set_mode(CPURISCVState *env, target_ulong newpriv)
{
    if (newpriv > PRV_M) {
+82 −4
Original line number Diff line number Diff line
@@ -238,6 +238,32 @@ static int read_timeh(CPURISCVState *env, int csrno, target_ulong *val)

#else /* CONFIG_USER_ONLY */

static int read_time(CPURISCVState *env, int csrno, target_ulong *val)
{
    uint64_t delta = riscv_cpu_virt_enabled(env) ? env->htimedelta : 0;

    if (!env->rdtime_fn) {
        return -1;
    }

    *val = env->rdtime_fn() + delta;
    return 0;
}

#if defined(TARGET_RISCV32)
static int read_timeh(CPURISCVState *env, int csrno, target_ulong *val)
{
    uint64_t delta = riscv_cpu_virt_enabled(env) ? env->htimedelta : 0;

    if (!env->rdtime_fn) {
        return -1;
    }

    *val = (env->rdtime_fn() + delta) >> 32;
    return 0;
}
#endif

/* Machine constants */

#define M_MODE_INTERRUPTS  (MIP_MSIP | MIP_MTIP | MIP_MEIP)
@@ -930,6 +956,56 @@ static int write_hgatp(CPURISCVState *env, int csrno, target_ulong val)
    return 0;
}

static int read_htimedelta(CPURISCVState *env, int csrno, target_ulong *val)
{
    if (!env->rdtime_fn) {
        return -1;
    }

#if defined(TARGET_RISCV32)
    *val = env->htimedelta & 0xffffffff;
#else
    *val = env->htimedelta;
#endif
    return 0;
}

static int write_htimedelta(CPURISCVState *env, int csrno, target_ulong val)
{
    if (!env->rdtime_fn) {
        return -1;
    }

#if defined(TARGET_RISCV32)
    env->htimedelta = deposit64(env->htimedelta, 0, 32, (uint64_t)val);
#else
    env->htimedelta = val;
#endif
    return 0;
}

#if defined(TARGET_RISCV32)
static int read_htimedeltah(CPURISCVState *env, int csrno, target_ulong *val)
{
    if (!env->rdtime_fn) {
        return -1;
    }

    *val = env->htimedelta >> 32;
    return 0;
}

static int write_htimedeltah(CPURISCVState *env, int csrno, target_ulong val)
{
    if (!env->rdtime_fn) {
        return -1;
    }

    env->htimedelta = deposit64(env->htimedelta, 32, 32, (uint64_t)val);
    return 0;
}
#endif

/* Virtual CSR Registers */
static int read_vsstatus(CPURISCVState *env, int csrno, target_ulong *val)
{
@@ -1202,14 +1278,12 @@ static riscv_csr_operations csr_ops[CSR_TABLE_SIZE] = {
    [CSR_INSTRETH] =            { ctr,  read_instreth                       },
#endif

    /* User-level time CSRs are only available in linux-user
     * In privileged mode, the monitor emulates these CSRs */
#if defined(CONFIG_USER_ONLY)
    /* In privileged mode, the monitor will have to emulate TIME CSRs only if
     * rdtime callback is not provided by machine/platform emulation */
    [CSR_TIME] =                { ctr,  read_time                           },
#if defined(TARGET_RISCV32)
    [CSR_TIMEH] =               { ctr,  read_timeh                          },
#endif
#endif

#if !defined(CONFIG_USER_ONLY)
    /* Machine Timers and Counters */
@@ -1275,6 +1349,10 @@ static riscv_csr_operations csr_ops[CSR_TABLE_SIZE] = {
    [CSR_HTVAL] =               { hmode,   read_htval,       write_htval      },
    [CSR_HTINST] =              { hmode,   read_htinst,      write_htinst     },
    [CSR_HGATP] =               { hmode,   read_hgatp,       write_hgatp      },
    [CSR_HTIMEDELTA] =          { hmode,   read_htimedelta,  write_htimedelta },
#if defined(TARGET_RISCV32)
    [CSR_HTIMEDELTAH] =         { hmode,   read_htimedeltah, write_htimedeltah},
#endif

    [CSR_VSSTATUS] =            { hmode,   read_vsstatus,    write_vsstatus   },
    [CSR_VSIP] =                { hmode,   NULL,     NULL,     rmw_vsip       },