summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--hw/riscv/boot.c4
-rw-r--r--target/riscv/cpu.c17
-rw-r--r--target/riscv/cpu.h24
-rw-r--r--target/riscv/cpu_bits.h30
-rw-r--r--target/riscv/cpu_helper.c134
-rw-r--r--target/riscv/csr.c857
-rw-r--r--target/riscv/insn_trans/trans_privileged.c.inc4
-rw-r--r--target/riscv/insn_trans/trans_rvh.c.inc2
-rw-r--r--target/riscv/insn_trans/trans_rvi.c.inc10
-rw-r--r--target/riscv/machine.c25
-rw-r--r--target/riscv/meson.build3
-rw-r--r--target/riscv/pmp.c3
-rw-r--r--target/riscv/pmu.c32
-rw-r--r--target/riscv/pmu.h28
-rw-r--r--target/riscv/translate.c31
-rw-r--r--tests/tcg/riscv64/Makefile.softmmu-target21
-rw-r--r--tests/tcg/riscv64/issue1060.S53
-rw-r--r--tests/tcg/riscv64/semihost.ld21
18 files changed, 843 insertions, 456 deletions
diff --git a/hw/riscv/boot.c b/hw/riscv/boot.c
index 2d80f40b31..06b4fc5ac3 100644
--- a/hw/riscv/boot.c
+++ b/hw/riscv/boot.c
@@ -227,11 +227,11 @@ uint64_t riscv_load_fdt(hwaddr dram_base, uint64_t mem_size, void *fdt)
/*
* We should put fdt as far as possible to avoid kernel/initrd overwriting
* its content. But it should be addressable by 32 bit system as well.
- * Thus, put it at an 16MB aligned address that less than fdt size from the
+ * Thus, put it at an 2MB aligned address that less than fdt size from the
* end of dram or 3GB whichever is lesser.
*/
temp = (dram_base < 3072 * MiB) ? MIN(dram_end, 3072 * MiB) : dram_end;
- fdt_addr = QEMU_ALIGN_DOWN(temp - fdtsize, 16 * MiB);
+ fdt_addr = QEMU_ALIGN_DOWN(temp - fdtsize, 2 * MiB);
ret = fdt_pack(fdt);
/* Should only fail if we've built a corrupted tree */
diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c
index 05e6521351..1bb3973806 100644
--- a/target/riscv/cpu.c
+++ b/target/riscv/cpu.c
@@ -173,6 +173,8 @@ static void rv64_base_cpu_init(Object *obj)
/* We set this in the realise function */
set_misa(env, MXL_RV64, 0);
register_cpu_props(DEVICE(obj));
+ /* Set latest version of privileged specification */
+ set_priv_version(env, PRIV_VERSION_1_12_0);
}
static void rv64_sifive_u_cpu_init(Object *obj)
@@ -204,6 +206,8 @@ static void rv128_base_cpu_init(Object *obj)
/* We set this in the realise function */
set_misa(env, MXL_RV128, 0);
register_cpu_props(DEVICE(obj));
+ /* Set latest version of privileged specification */
+ set_priv_version(env, PRIV_VERSION_1_12_0);
}
#else
static void rv32_base_cpu_init(Object *obj)
@@ -212,6 +216,8 @@ static void rv32_base_cpu_init(Object *obj)
/* We set this in the realise function */
set_misa(env, MXL_RV32, 0);
register_cpu_props(DEVICE(obj));
+ /* Set latest version of privileged specification */
+ set_priv_version(env, PRIV_VERSION_1_12_0);
}
static void rv32_sifive_u_cpu_init(Object *obj)
@@ -237,7 +243,7 @@ static void rv32_ibex_cpu_init(Object *obj)
RISCVCPU *cpu = RISCV_CPU(obj);
set_misa(env, MXL_RV32, RVI | RVM | RVC | RVU);
- set_priv_version(env, PRIV_VERSION_1_10_0);
+ set_priv_version(env, PRIV_VERSION_1_11_0);
cpu->cfg.mmu = false;
cpu->cfg.epmp = true;
}
@@ -524,7 +530,7 @@ static void riscv_cpu_realize(DeviceState *dev, Error **errp)
CPURISCVState *env = &cpu->env;
RISCVCPUClass *mcc = RISCV_CPU_GET_CLASS(dev);
CPUClass *cc = CPU_CLASS(mcc);
- int priv_version = 0;
+ int priv_version = -1;
Error *local_err = NULL;
cpu_exec_realizefn(cs, &local_err);
@@ -548,10 +554,8 @@ static void riscv_cpu_realize(DeviceState *dev, Error **errp)
}
}
- if (priv_version) {
+ if (priv_version >= PRIV_VERSION_1_10_0) {
set_priv_version(env, priv_version);
- } else if (!env->priv_ver) {
- set_priv_version(env, PRIV_VERSION_1_12_0);
}
if (cpu->cfg.mmu) {
@@ -851,7 +855,6 @@ static void riscv_cpu_init(Object *obj)
{
RISCVCPU *cpu = RISCV_CPU(obj);
- cpu->cfg.ext_counters = true;
cpu->cfg.ext_ifencei = true;
cpu->cfg.ext_icsr = true;
cpu->cfg.mmu = true;
@@ -879,7 +882,7 @@ static Property riscv_cpu_extensions[] = {
DEFINE_PROP_BOOL("u", RISCVCPU, cfg.ext_u, true),
DEFINE_PROP_BOOL("v", RISCVCPU, cfg.ext_v, false),
DEFINE_PROP_BOOL("h", RISCVCPU, cfg.ext_h, true),
- DEFINE_PROP_BOOL("Counters", RISCVCPU, cfg.ext_counters, true),
+ DEFINE_PROP_UINT8("pmu-num", RISCVCPU, cfg.pmu_num, 16),
DEFINE_PROP_BOOL("Zifencei", RISCVCPU, cfg.ext_ifencei, true),
DEFINE_PROP_BOOL("Zicsr", RISCVCPU, cfg.ext_icsr, true),
DEFINE_PROP_BOOL("Zfh", RISCVCPU, cfg.ext_zfh, false),
diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h
index 7d6397acdf..5c7acc055a 100644
--- a/target/riscv/cpu.h
+++ b/target/riscv/cpu.h
@@ -117,6 +117,8 @@ typedef struct CPUArchState CPURISCVState;
#endif
#define RV_VLEN_MAX 1024
+#define RV_MAX_MHPMEVENTS 32
+#define RV_MAX_MHPMCOUNTERS 32
FIELD(VTYPE, VLMUL, 0, 3)
FIELD(VTYPE, VSEW, 3, 3)
@@ -125,6 +127,18 @@ FIELD(VTYPE, VMA, 7, 1)
FIELD(VTYPE, VEDIV, 8, 2)
FIELD(VTYPE, RESERVED, 10, sizeof(target_ulong) * 8 - 11)
+typedef struct PMUCTRState {
+ /* Current value of a counter */
+ target_ulong mhpmcounter_val;
+ /* Current value of a counter in RV32*/
+ target_ulong mhpmcounterh_val;
+ /* Snapshot values of counter */
+ target_ulong mhpmcounter_prev;
+ /* Snapshort value of a counter in RV32 */
+ target_ulong mhpmcounterh_prev;
+ bool started;
+} PMUCTRState;
+
struct CPUArchState {
target_ulong gpr[32];
target_ulong gprh[32]; /* 64 top bits of the 128-bit registers */
@@ -275,6 +289,14 @@ struct CPUArchState {
target_ulong scounteren;
target_ulong mcounteren;
+ target_ulong mcountinhibit;
+
+ /* PMU counter state */
+ PMUCTRState pmu_ctrs[RV_MAX_MHPMCOUNTERS];
+
+ /* PMU event selector configured values. First three are unused*/
+ target_ulong mhpmevent_val[RV_MAX_MHPMEVENTS];
+
target_ulong sscratch;
target_ulong mscratch;
@@ -397,7 +419,6 @@ struct RISCVCPUConfig {
bool ext_zksed;
bool ext_zksh;
bool ext_zkt;
- bool ext_counters;
bool ext_ifencei;
bool ext_icsr;
bool ext_svinval;
@@ -421,6 +442,7 @@ struct RISCVCPUConfig {
/* Vendor-specific custom extensions */
bool ext_XVentanaCondOps;
+ uint8_t pmu_num;
char *priv_spec;
char *user_spec;
char *bext_spec;
diff --git a/target/riscv/cpu_bits.h b/target/riscv/cpu_bits.h
index 4d04b20d06..6be5a9e9f0 100644
--- a/target/riscv/cpu_bits.h
+++ b/target/riscv/cpu_bits.h
@@ -174,14 +174,8 @@
#define CSR_MIREG 0x351
/* Machine-Level Interrupts (AIA) */
-#define CSR_MTOPI 0xfb0
-
-/* Machine-Level IMSIC Interface (AIA) */
-#define CSR_MSETEIPNUM 0x358
-#define CSR_MCLREIPNUM 0x359
-#define CSR_MSETEIENUM 0x35a
-#define CSR_MCLREIENUM 0x35b
#define CSR_MTOPEI 0x35c
+#define CSR_MTOPI 0xfb0
/* Virtual Interrupts for Supervisor Level (AIA) */
#define CSR_MVIEN 0x308
@@ -221,14 +215,8 @@
#define CSR_SIREG 0x151
/* Supervisor-Level Interrupts (AIA) */
-#define CSR_STOPI 0xdb0
-
-/* Supervisor-Level IMSIC Interface (AIA) */
-#define CSR_SSETEIPNUM 0x158
-#define CSR_SCLREIPNUM 0x159
-#define CSR_SSETEIENUM 0x15a
-#define CSR_SCLREIENUM 0x15b
#define CSR_STOPEI 0x15c
+#define CSR_STOPI 0xdb0
/* Supervisor-Level High-Half CSRs (AIA) */
#define CSR_SIEH 0x114
@@ -279,14 +267,8 @@
#define CSR_VSIREG 0x251
/* VS-Level Interrupts (H-extension with AIA) */
-#define CSR_VSTOPI 0xeb0
-
-/* VS-Level IMSIC Interface (H-extension with AIA) */
-#define CSR_VSSETEIPNUM 0x258
-#define CSR_VSCLREIPNUM 0x259
-#define CSR_VSSETEIENUM 0x25a
-#define CSR_VSCLREIENUM 0x25b
#define CSR_VSTOPEI 0x25c
+#define CSR_VSTOPI 0xeb0
/* Hypervisor and VS-Level High-Half CSRs (H-extension with AIA) */
#define CSR_HIDELEGH 0x613
@@ -367,6 +349,10 @@
#define CSR_MHPMCOUNTER29 0xb1d
#define CSR_MHPMCOUNTER30 0xb1e
#define CSR_MHPMCOUNTER31 0xb1f
+
+/* Machine counter-inhibit register */
+#define CSR_MCOUNTINHIBIT 0x320
+
#define CSR_MHPMEVENT3 0x323
#define CSR_MHPMEVENT4 0x324
#define CSR_MHPMEVENT5 0x325
@@ -788,7 +774,7 @@ typedef enum RISCVException {
#define IPRIO_IRQ_BITS 8
#define IPRIO_MMAXIPRIO 255
#define IPRIO_DEFAULT_UPPER 4
-#define IPRIO_DEFAULT_MIDDLE (IPRIO_DEFAULT_UPPER + 24)
+#define IPRIO_DEFAULT_MIDDLE (IPRIO_DEFAULT_UPPER + 12)
#define IPRIO_DEFAULT_M IPRIO_DEFAULT_MIDDLE
#define IPRIO_DEFAULT_S (IPRIO_DEFAULT_M + 3)
#define IPRIO_DEFAULT_SGEXT (IPRIO_DEFAULT_S + 3)
diff --git a/target/riscv/cpu_helper.c b/target/riscv/cpu_helper.c
index be28615e23..59b3680b1b 100644
--- a/target/riscv/cpu_helper.c
+++ b/target/riscv/cpu_helper.c
@@ -168,17 +168,17 @@ void riscv_cpu_update_mask(CPURISCVState *env)
* 14 "
* 15 "
* 16 "
- * 18 Debug/trace interrupt
- * 20 (Reserved interrupt)
+ * 17 "
+ * 18 "
+ * 19 "
+ * 20 "
+ * 21 "
* 22 "
- * 24 "
- * 26 "
- * 28 "
- * 30 (Reserved for standard reporting of bus or system errors)
+ * 23 "
*/
static const int hviprio_index2irq[] = {
- 0, 1, 4, 5, 8, 13, 14, 15, 16, 18, 20, 22, 24, 26, 28, 30 };
+ 0, 1, 4, 5, 8, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23 };
static const int hviprio_index2rdzero[] = {
1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
@@ -207,50 +207,60 @@ int riscv_cpu_hviprio_index2irq(int index, int *out_irq, int *out_rdzero)
* Default |
* Priority | Major Interrupt Numbers
* ----------------------------------------------------------------
- * Highest | 63 (3f), 62 (3e), 31 (1f), 30 (1e), 61 (3d), 60 (3c),
- * | 59 (3b), 58 (3a), 29 (1d), 28 (1c), 57 (39), 56 (38),
- * | 55 (37), 54 (36), 27 (1b), 26 (1a), 53 (35), 52 (34),
- * | 51 (33), 50 (32), 25 (19), 24 (18), 49 (31), 48 (30)
+ * Highest | 47, 23, 46, 45, 22, 44,
+ * | 43, 21, 42, 41, 20, 40
* |
* | 11 (0b), 3 (03), 7 (07)
* | 9 (09), 1 (01), 5 (05)
* | 12 (0c)
* | 10 (0a), 2 (02), 6 (06)
* |
- * | 47 (2f), 46 (2e), 23 (17), 22 (16), 45 (2d), 44 (2c),
- * | 43 (2b), 42 (2a), 21 (15), 20 (14), 41 (29), 40 (28),
- * | 39 (27), 38 (26), 19 (13), 18 (12), 37 (25), 36 (24),
- * Lowest | 35 (23), 34 (22), 17 (11), 16 (10), 33 (21), 32 (20)
+ * | 39, 19, 38, 37, 18, 36,
+ * Lowest | 35, 17, 34, 33, 16, 32
* ----------------------------------------------------------------
*/
static const uint8_t default_iprio[64] = {
- [63] = IPRIO_DEFAULT_UPPER,
- [62] = IPRIO_DEFAULT_UPPER + 1,
- [31] = IPRIO_DEFAULT_UPPER + 2,
- [30] = IPRIO_DEFAULT_UPPER + 3,
- [61] = IPRIO_DEFAULT_UPPER + 4,
- [60] = IPRIO_DEFAULT_UPPER + 5,
-
- [59] = IPRIO_DEFAULT_UPPER + 6,
- [58] = IPRIO_DEFAULT_UPPER + 7,
- [29] = IPRIO_DEFAULT_UPPER + 8,
- [28] = IPRIO_DEFAULT_UPPER + 9,
- [57] = IPRIO_DEFAULT_UPPER + 10,
- [56] = IPRIO_DEFAULT_UPPER + 11,
-
- [55] = IPRIO_DEFAULT_UPPER + 12,
- [54] = IPRIO_DEFAULT_UPPER + 13,
- [27] = IPRIO_DEFAULT_UPPER + 14,
- [26] = IPRIO_DEFAULT_UPPER + 15,
- [53] = IPRIO_DEFAULT_UPPER + 16,
- [52] = IPRIO_DEFAULT_UPPER + 17,
-
- [51] = IPRIO_DEFAULT_UPPER + 18,
- [50] = IPRIO_DEFAULT_UPPER + 19,
- [25] = IPRIO_DEFAULT_UPPER + 20,
- [24] = IPRIO_DEFAULT_UPPER + 21,
- [49] = IPRIO_DEFAULT_UPPER + 22,
- [48] = IPRIO_DEFAULT_UPPER + 23,
+ /* Custom interrupts 48 to 63 */
+ [63] = IPRIO_MMAXIPRIO,
+ [62] = IPRIO_MMAXIPRIO,
+ [61] = IPRIO_MMAXIPRIO,
+ [60] = IPRIO_MMAXIPRIO,
+ [59] = IPRIO_MMAXIPRIO,
+ [58] = IPRIO_MMAXIPRIO,
+ [57] = IPRIO_MMAXIPRIO,
+ [56] = IPRIO_MMAXIPRIO,
+ [55] = IPRIO_MMAXIPRIO,
+ [54] = IPRIO_MMAXIPRIO,
+ [53] = IPRIO_MMAXIPRIO,
+ [52] = IPRIO_MMAXIPRIO,
+ [51] = IPRIO_MMAXIPRIO,
+ [50] = IPRIO_MMAXIPRIO,
+ [49] = IPRIO_MMAXIPRIO,
+ [48] = IPRIO_MMAXIPRIO,
+
+ /* Custom interrupts 24 to 31 */
+ [31] = IPRIO_MMAXIPRIO,
+ [30] = IPRIO_MMAXIPRIO,
+ [29] = IPRIO_MMAXIPRIO,
+ [28] = IPRIO_MMAXIPRIO,
+ [27] = IPRIO_MMAXIPRIO,
+ [26] = IPRIO_MMAXIPRIO,
+ [25] = IPRIO_MMAXIPRIO,
+ [24] = IPRIO_MMAXIPRIO,
+
+ [47] = IPRIO_DEFAULT_UPPER,
+ [23] = IPRIO_DEFAULT_UPPER + 1,
+ [46] = IPRIO_DEFAULT_UPPER + 2,
+ [45] = IPRIO_DEFAULT_UPPER + 3,
+ [22] = IPRIO_DEFAULT_UPPER + 4,
+ [44] = IPRIO_DEFAULT_UPPER + 5,
+
+ [43] = IPRIO_DEFAULT_UPPER + 6,
+ [21] = IPRIO_DEFAULT_UPPER + 7,
+ [42] = IPRIO_DEFAULT_UPPER + 8,
+ [41] = IPRIO_DEFAULT_UPPER + 9,
+ [20] = IPRIO_DEFAULT_UPPER + 10,
+ [40] = IPRIO_DEFAULT_UPPER + 11,
[11] = IPRIO_DEFAULT_M,
[3] = IPRIO_DEFAULT_M + 1,
@@ -266,33 +276,19 @@ static const uint8_t default_iprio[64] = {
[2] = IPRIO_DEFAULT_VS + 1,
[6] = IPRIO_DEFAULT_VS + 2,
- [47] = IPRIO_DEFAULT_LOWER,
- [46] = IPRIO_DEFAULT_LOWER + 1,
- [23] = IPRIO_DEFAULT_LOWER + 2,
- [22] = IPRIO_DEFAULT_LOWER + 3,
- [45] = IPRIO_DEFAULT_LOWER + 4,
- [44] = IPRIO_DEFAULT_LOWER + 5,
-
- [43] = IPRIO_DEFAULT_LOWER + 6,
- [42] = IPRIO_DEFAULT_LOWER + 7,
- [21] = IPRIO_DEFAULT_LOWER + 8,
- [20] = IPRIO_DEFAULT_LOWER + 9,
- [41] = IPRIO_DEFAULT_LOWER + 10,
- [40] = IPRIO_DEFAULT_LOWER + 11,
-
- [39] = IPRIO_DEFAULT_LOWER + 12,
- [38] = IPRIO_DEFAULT_LOWER + 13,
- [19] = IPRIO_DEFAULT_LOWER + 14,
- [18] = IPRIO_DEFAULT_LOWER + 15,
- [37] = IPRIO_DEFAULT_LOWER + 16,
- [36] = IPRIO_DEFAULT_LOWER + 17,
-
- [35] = IPRIO_DEFAULT_LOWER + 18,
- [34] = IPRIO_DEFAULT_LOWER + 19,
- [17] = IPRIO_DEFAULT_LOWER + 20,
- [16] = IPRIO_DEFAULT_LOWER + 21,
- [33] = IPRIO_DEFAULT_LOWER + 22,
- [32] = IPRIO_DEFAULT_LOWER + 23,
+ [39] = IPRIO_DEFAULT_LOWER,
+ [19] = IPRIO_DEFAULT_LOWER + 1,
+ [38] = IPRIO_DEFAULT_LOWER + 2,
+ [37] = IPRIO_DEFAULT_LOWER + 3,
+ [18] = IPRIO_DEFAULT_LOWER + 4,
+ [36] = IPRIO_DEFAULT_LOWER + 5,
+
+ [35] = IPRIO_DEFAULT_LOWER + 6,
+ [17] = IPRIO_DEFAULT_LOWER + 7,
+ [34] = IPRIO_DEFAULT_LOWER + 8,
+ [33] = IPRIO_DEFAULT_LOWER + 9,
+ [16] = IPRIO_DEFAULT_LOWER + 10,
+ [32] = IPRIO_DEFAULT_LOWER + 11,
};
uint8_t riscv_cpu_default_priority(int irq)
diff --git a/target/riscv/csr.c b/target/riscv/csr.c
index 6dbe9b541f..235f2a011e 100644
--- a/target/riscv/csr.c
+++ b/target/riscv/csr.c
@@ -21,6 +21,7 @@
#include "qemu/log.h"
#include "qemu/timer.h"
#include "cpu.h"
+#include "pmu.h"
#include "qemu/main-loop.h"
#include "exec/exec-all.h"
#include "sysemu/cpu-timers.h"
@@ -72,12 +73,72 @@ static RISCVException ctr(CPURISCVState *env, int csrno)
#if !defined(CONFIG_USER_ONLY)
CPUState *cs = env_cpu(env);
RISCVCPU *cpu = RISCV_CPU(cs);
+ int ctr_index;
+ int base_csrno = CSR_HPMCOUNTER3;
+ bool rv32 = riscv_cpu_mxl(env) == MXL_RV32 ? true : false;
- if (!cpu->cfg.ext_counters) {
- /* The Counters extensions is not enabled */
+ if (rv32 && csrno >= CSR_CYCLEH) {
+ /* Offset for RV32 hpmcounternh counters */
+ base_csrno += 0x80;
+ }
+ ctr_index = csrno - base_csrno;
+
+ if (!cpu->cfg.pmu_num || ctr_index >= (cpu->cfg.pmu_num)) {
+ /* No counter is enabled in PMU or the counter is out of range */
return RISCV_EXCP_ILLEGAL_INST;
}
+ if (env->priv == PRV_S) {
+ switch (csrno) {
+ case CSR_CYCLE:
+ if (!get_field(env->mcounteren, COUNTEREN_CY)) {
+ return RISCV_EXCP_ILLEGAL_INST;
+ }
+ break;
+ case CSR_TIME:
+ if (!get_field(env->mcounteren, COUNTEREN_TM)) {
+ return RISCV_EXCP_ILLEGAL_INST;
+ }
+ break;
+ case CSR_INSTRET:
+ if (!get_field(env->mcounteren, COUNTEREN_IR)) {
+ return RISCV_EXCP_ILLEGAL_INST;
+ }
+ break;
+ case CSR_HPMCOUNTER3...CSR_HPMCOUNTER31:
+ ctr_index = csrno - CSR_CYCLE;
+ if (!get_field(env->mcounteren, 1 << ctr_index)) {
+ return RISCV_EXCP_ILLEGAL_INST;
+ }
+ break;
+ }
+ if (rv32) {
+ switch (csrno) {
+ case CSR_CYCLEH:
+ if (!get_field(env->mcounteren, COUNTEREN_CY)) {
+ return RISCV_EXCP_ILLEGAL_INST;
+ }
+ break;
+ case CSR_TIMEH:
+ if (!get_field(env->mcounteren, COUNTEREN_TM)) {
+ return RISCV_EXCP_ILLEGAL_INST;
+ }
+ break;
+ case CSR_INSTRETH:
+ if (!get_field(env->mcounteren, COUNTEREN_IR)) {
+ return RISCV_EXCP_ILLEGAL_INST;
+ }
+ break;
+ case CSR_HPMCOUNTER3H...CSR_HPMCOUNTER31H:
+ ctr_index = csrno - CSR_CYCLEH;
+ if (!get_field(env->mcounteren, 1 << ctr_index)) {
+ return RISCV_EXCP_ILLEGAL_INST;
+ }
+ break;
+ }
+ }
+ }
+
if (riscv_cpu_virt_enabled(env)) {
switch (csrno) {
case CSR_CYCLE:
@@ -99,13 +160,14 @@ static RISCVException ctr(CPURISCVState *env, int csrno)
}
break;
case CSR_HPMCOUNTER3...CSR_HPMCOUNTER31:
- if (!get_field(env->hcounteren, 1 << (csrno - CSR_HPMCOUNTER3)) &&
- get_field(env->mcounteren, 1 << (csrno - CSR_HPMCOUNTER3))) {
+ ctr_index = csrno - CSR_CYCLE;
+ if (!get_field(env->hcounteren, 1 << ctr_index) &&
+ get_field(env->mcounteren, 1 << ctr_index)) {
return RISCV_EXCP_VIRT_INSTRUCTION_FAULT;
}
break;
}
- if (riscv_cpu_mxl(env) == MXL_RV32) {
+ if (rv32) {
switch (csrno) {
case CSR_CYCLEH:
if (!get_field(env->hcounteren, COUNTEREN_CY) &&
@@ -126,8 +188,9 @@ static RISCVException ctr(CPURISCVState *env, int csrno)
}
break;
case CSR_HPMCOUNTER3H...CSR_HPMCOUNTER31H:
- if (!get_field(env->hcounteren, 1 << (csrno - CSR_HPMCOUNTER3H)) &&
- get_field(env->mcounteren, 1 << (csrno - CSR_HPMCOUNTER3H))) {
+ ctr_index = csrno - CSR_CYCLEH;
+ if (!get_field(env->hcounteren, 1 << ctr_index) &&
+ get_field(env->mcounteren, 1 << ctr_index)) {
return RISCV_EXCP_VIRT_INSTRUCTION_FAULT;
}
break;
@@ -148,6 +211,35 @@ static RISCVException ctr32(CPURISCVState *env, int csrno)
}
#if !defined(CONFIG_USER_ONLY)
+static RISCVException mctr(CPURISCVState *env, int csrno)
+{
+ CPUState *cs = env_cpu(env);
+ RISCVCPU *cpu = RISCV_CPU(cs);
+ int ctr_index;
+ int base_csrno = CSR_MHPMCOUNTER3;
+
+ if ((riscv_cpu_mxl(env) == MXL_RV32) && csrno >= CSR_MCYCLEH) {
+ /* Offset for RV32 mhpmcounternh counters */
+ base_csrno += 0x80;
+ }
+ ctr_index = csrno - base_csrno;
+ if (!cpu->cfg.pmu_num || ctr_index >= cpu->cfg.pmu_num) {
+ /* The PMU is not enabled or counter is out of range*/
+ return RISCV_EXCP_ILLEGAL_INST;
+ }
+
+ return RISCV_EXCP_NONE;
+}
+
+static RISCVException mctr32(CPURISCVState *env, int csrno)
+{
+ if (riscv_cpu_mxl(env) != MXL_RV32) {
+ return RISCV_EXCP_ILLEGAL_INST;
+ }
+
+ return mctr(env, csrno);
+}
+
static RISCVException any(CPURISCVState *env, int csrno)
{
return RISCV_EXCP_NONE;
@@ -506,34 +598,28 @@ static int write_vcsr(CPURISCVState *env, int csrno, target_ulong val)
}
/* User Timers and Counters */
-static RISCVException read_instret(CPURISCVState *env, int csrno,
- target_ulong *val)
+static target_ulong get_ticks(bool shift)
{
+ int64_t val;
+ target_ulong result;
+
#if !defined(CONFIG_USER_ONLY)
if (icount_enabled()) {
- *val = icount_get();
+ val = icount_get();
} else {
- *val = cpu_get_host_ticks();
+ val = cpu_get_host_ticks();
}
#else
- *val = cpu_get_host_ticks();
+ val = cpu_get_host_ticks();
#endif
- return RISCV_EXCP_NONE;
-}
-static RISCVException read_instreth(CPURISCVState *env, int csrno,
- target_ulong *val)
-{
-#if !defined(CONFIG_USER_ONLY)
- if (icount_enabled()) {
- *val = icount_get() >> 32;
+ if (shift) {
+ result = val >> 32;
} else {
- *val = cpu_get_host_ticks() >> 32;
+ result = val;
}
-#else
- *val = cpu_get_host_ticks() >> 32;
-#endif
- return RISCV_EXCP_NONE;
+
+ return result;
}
#if defined(CONFIG_USER_ONLY)
@@ -551,8 +637,139 @@ static RISCVException read_timeh(CPURISCVState *env, int csrno,
return RISCV_EXCP_NONE;
}
+static int read_hpmcounter(CPURISCVState *env, int csrno, target_ulong *val)
+{
+ *val = get_ticks(false);
+ return RISCV_EXCP_NONE;
+}
+
+static int read_hpmcounterh(CPURISCVState *env, int csrno, target_ulong *val)
+{
+ *val = get_ticks(true);
+ return RISCV_EXCP_NONE;
+}
+
#else /* CONFIG_USER_ONLY */
+static int read_mhpmevent(CPURISCVState *env, int csrno, target_ulong *val)
+{
+ int evt_index = csrno - CSR_MCOUNTINHIBIT;
+
+ *val = env->mhpmevent_val[evt_index];
+
+ return RISCV_EXCP_NONE;
+}
+
+static int write_mhpmevent(CPURISCVState *env, int csrno, target_ulong val)
+{
+ int evt_index = csrno - CSR_MCOUNTINHIBIT;
+
+ env->mhpmevent_val[evt_index] = val;
+
+ return RISCV_EXCP_NONE;
+}
+
+static int write_mhpmcounter(CPURISCVState *env, int csrno, target_ulong val)
+{
+ int ctr_idx = csrno - CSR_MCYCLE;
+ PMUCTRState *counter = &env->pmu_ctrs[ctr_idx];
+
+ counter->mhpmcounter_val = val;
+ if (riscv_pmu_ctr_monitor_cycles(env, ctr_idx) ||
+ riscv_pmu_ctr_monitor_instructions(env, ctr_idx)) {
+ counter->mhpmcounter_prev = get_ticks(false);
+ } else {
+ /* Other counters can keep incrementing from the given value */
+ counter->mhpmcounter_prev = val;
+ }
+
+ return RISCV_EXCP_NONE;
+}
+
+static int write_mhpmcounterh(CPURISCVState *env, int csrno, target_ulong val)
+{
+ int ctr_idx = csrno - CSR_MCYCLEH;
+ PMUCTRState *counter = &env->pmu_ctrs[ctr_idx];
+
+ counter->mhpmcounterh_val = val;
+ if (riscv_pmu_ctr_monitor_cycles(env, ctr_idx) ||
+ riscv_pmu_ctr_monitor_instructions(env, ctr_idx)) {
+ counter->mhpmcounterh_prev = get_ticks(true);
+ } else {
+ counter->mhpmcounterh_prev = val;
+ }
+
+ return RISCV_EXCP_NONE;
+}
+
+static RISCVException riscv_pmu_read_ctr(CPURISCVState *env, target_ulong *val,
+ bool upper_half, uint32_t ctr_idx)
+{
+ PMUCTRState counter = env->pmu_ctrs[ctr_idx];
+ target_ulong ctr_prev = upper_half ? counter.mhpmcounterh_prev :
+ counter.mhpmcounter_prev;
+ target_ulong ctr_val = upper_half ? counter.mhpmcounterh_val :
+ counter.mhpmcounter_val;
+
+ if (get_field(env->mcountinhibit, BIT(ctr_idx))) {
+ /**
+ * Counter should not increment if inhibit bit is set. We can't really
+ * stop the icount counting. Just return the counter value written by
+ * the supervisor to indicate that counter was not incremented.
+ */
+ if (!counter.started) {
+ *val = ctr_val;
+ return RISCV_EXCP_NONE;
+ } else {
+ /* Mark that the counter has been stopped */
+ counter.started = false;
+ }
+ }
+
+ /**
+ * The kernel computes the perf delta by subtracting the current value from
+ * the value it initialized previously (ctr_val).
+ */
+ if (riscv_pmu_ctr_monitor_cycles(env, ctr_idx) ||
+ riscv_pmu_ctr_monitor_instructions(env, ctr_idx)) {
+ *val = get_ticks(upper_half) - ctr_prev + ctr_val;
+ } else {
+ *val = ctr_val;
+ }
+
+ return RISCV_EXCP_NONE;
+}
+
+static int read_hpmcounter(CPURISCVState *env, int csrno, target_ulong *val)
+{
+ uint16_t ctr_index;
+
+ if (csrno >= CSR_MCYCLE && csrno <= CSR_MHPMCOUNTER31) {
+ ctr_index = csrno - CSR_MCYCLE;
+ } else if (csrno >= CSR_CYCLE && csrno <= CSR_HPMCOUNTER31) {
+ ctr_index = csrno - CSR_CYCLE;
+ } else {
+ return RISCV_EXCP_ILLEGAL_INST;
+ }
+
+ return riscv_pmu_read_ctr(env, val, false, ctr_index);
+}
+
+static int read_hpmcounterh(CPURISCVState *env, int csrno, target_ulong *val)
+{
+ uint16_t ctr_index;
+
+ if (csrno >= CSR_MCYCLEH && csrno <= CSR_MHPMCOUNTER31H) {
+ ctr_index = csrno - CSR_MCYCLEH;
+ } else if (csrno >= CSR_CYCLEH && csrno <= CSR_HPMCOUNTER31H) {
+ ctr_index = csrno - CSR_CYCLEH;
+ } else {
+ return RISCV_EXCP_ILLEGAL_INST;
+ }
+
+ return riscv_pmu_read_ctr(env, val, true, ctr_index);
+}
+
static RISCVException read_time(CPURISCVState *env, int csrno,
target_ulong *val)
{
@@ -1040,14 +1257,6 @@ static int aia_xlate_vs_csrno(CPURISCVState *env, int csrno)
return CSR_VSISELECT;
case CSR_SIREG:
return CSR_VSIREG;
- case CSR_SSETEIPNUM:
- return CSR_VSSETEIPNUM;
- case CSR_SCLREIPNUM:
- return CSR_VSCLREIPNUM;
- case CSR_SSETEIENUM:
- return CSR_VSSETEIENUM;
- case CSR_SCLREIENUM:
- return CSR_VSCLREIENUM;
case CSR_STOPEI:
return CSR_VSTOPEI;
default:
@@ -1202,124 +1411,6 @@ done:
return RISCV_EXCP_NONE;
}
-static int rmw_xsetclreinum(CPURISCVState *env, int csrno, target_ulong *val,
- target_ulong new_val, target_ulong wr_mask)
-{
- int ret = -EINVAL;
- bool set, pend, virt;
- target_ulong priv, isel, vgein, xlen, nval, wmask;
-
- /* Translate CSR number for VS-mode */
- csrno = aia_xlate_vs_csrno(env, csrno);
-
- /* Decode register details from CSR number */
- virt = set = pend = false;
- switch (csrno) {
- case CSR_MSETEIPNUM:
- priv = PRV_M;
- set = true;
- pend = true;
- break;
- case CSR_MCLREIPNUM:
- priv = PRV_M;
- pend = true;
- break;
- case CSR_MSETEIENUM:
- priv = PRV_M;
- set = true;
- break;
- case CSR_MCLREIENUM:
- priv = PRV_M;
- break;
- case CSR_SSETEIPNUM:
- priv = PRV_S;
- set = true;
- pend = true;
- break;
- case CSR_SCLREIPNUM:
- priv = PRV_S;
- pend = true;
- break;
- case CSR_SSETEIENUM:
- priv = PRV_S;
- set = true;
- break;
- case CSR_SCLREIENUM:
- priv = PRV_S;
- break;
- case CSR_VSSETEIPNUM:
- priv = PRV_S;
- virt = true;
- set = true;
- pend = true;
- break;
- case CSR_VSCLREIPNUM:
- priv = PRV_S;
- virt = true;
- pend = true;
- break;
- case CSR_VSSETEIENUM:
- priv = PRV_S;
- virt = true;
- set = true;
- break;
- case CSR_VSCLREIENUM:
- priv = PRV_S;
- virt = true;
- break;
- default:
- goto done;
- };
-
- /* IMSIC CSRs only available when machine implements IMSIC. */
- if (!env->aia_ireg_rmw_fn[priv]) {
- goto done;
- }
-
- /* Find the selected guest interrupt file */
- vgein = (virt) ? get_field(env->hstatus, HSTATUS_VGEIN) : 0;
-
- /* Selected guest interrupt file should be valid */
- if (virt && (!vgein || env->geilen < vgein)) {
- goto done;
- }
-
- /* Set/Clear CSRs always read zero */
- if (val) {
- *val = 0;
- }
-
- if (wr_mask) {
- /* Get interrupt number */
- new_val &= wr_mask;
-
- /* Find target interrupt pending/enable register */
- xlen = riscv_cpu_mxl_bits(env);
- isel = (new_val / xlen);
- isel *= (xlen / IMSIC_EIPx_BITS);
- isel += (pend) ? ISELECT_IMSIC_EIP0 : ISELECT_IMSIC_EIE0;
-
- /* Find the interrupt bit to be set/clear */
- wmask = ((target_ulong)1) << (new_val % xlen);
- nval = (set) ? wmask : 0;
-
- /* Call machine specific IMSIC register emulation */
- ret = env->aia_ireg_rmw_fn[priv](env->aia_ireg_rmw_fn_arg[priv],
- AIA_MAKE_IREG(isel, priv, virt,
- vgein, xlen),
- NULL, nval, wmask);
- } else {
- ret = 0;
- }
-
-done:
- if (ret) {
- return (riscv_cpu_virt_enabled(env) && virt) ?
- RISCV_EXCP_VIRT_INSTRUCTION_FAULT : RISCV_EXCP_ILLEGAL_INST;
- }
- return RISCV_EXCP_NONE;
-}
-
static int rmw_xtopei(CPURISCVState *env, int csrno, target_ulong *val,
target_ulong new_val, target_ulong wr_mask)
{
@@ -1393,6 +1484,40 @@ static RISCVException write_mtvec(CPURISCVState *env, int csrno,
return RISCV_EXCP_NONE;
}
+static RISCVException read_mcountinhibit(CPURISCVState *env, int csrno,
+ target_ulong *val)
+{
+ if (env->priv_ver < PRIV_VERSION_1_11_0) {
+ return RISCV_EXCP_ILLEGAL_INST;
+ }
+
+ *val = env->mcountinhibit;
+ return RISCV_EXCP_NONE;
+}
+
+static RISCVException write_mcountinhibit(CPURISCVState *env, int csrno,
+ target_ulong val)
+{
+ int cidx;
+ PMUCTRState *counter;
+
+ if (env->priv_ver < PRIV_VERSION_1_11_0) {
+ return RISCV_EXCP_ILLEGAL_INST;
+ }
+
+ env->mcountinhibit = val;
+
+ /* Check if any other counter is also monitoring cycles/instructions */
+ for (cidx = 0; cidx < RV_MAX_MHPMCOUNTERS; cidx++) {
+ if (!get_field(env->mcountinhibit, BIT(cidx))) {
+ counter = &env->pmu_ctrs[cidx];
+ counter->started = true;
+ }
+ }
+
+ return RISCV_EXCP_NONE;
+}
+
static RISCVException read_mcounteren(CPURISCVState *env, int csrno,
target_ulong *val)
{
@@ -3351,10 +3476,10 @@ riscv_csr_operations csr_ops[CSR_TABLE_SIZE] = {
[CSR_VLENB] = { "vlenb", vs, read_vlenb,
.min_priv_ver = PRIV_VERSION_1_12_0 },
/* User Timers and Counters */
- [CSR_CYCLE] = { "cycle", ctr, read_instret },
- [CSR_INSTRET] = { "instret", ctr, read_instret },
- [CSR_CYCLEH] = { "cycleh", ctr32, read_instreth },
- [CSR_INSTRETH] = { "instreth", ctr32, read_instreth },
+ [CSR_CYCLE] = { "cycle", ctr, read_hpmcounter },
+ [CSR_INSTRET] = { "instret", ctr, read_hpmcounter },
+ [CSR_CYCLEH] = { "cycleh", ctr32, read_hpmcounterh },
+ [CSR_INSTRETH] = { "instreth", ctr32, read_hpmcounterh },
/*
* In privileged mode, the monitor will have to emulate TIME CSRs only if
@@ -3368,10 +3493,10 @@ riscv_csr_operations csr_ops[CSR_TABLE_SIZE] = {
#if !defined(CONFIG_USER_ONLY)
/* Machine Timers and Counters */
- [CSR_MCYCLE] = { "mcycle", any, read_instret },
- [CSR_MINSTRET] = { "minstret", any, read_instret },
- [CSR_MCYCLEH] = { "mcycleh", any32, read_instreth },
- [CSR_MINSTRETH] = { "minstreth", any32, read_instreth },
+ [CSR_MCYCLE] = { "mcycle", any, read_hpmcounter, write_mhpmcounter},
+ [CSR_MINSTRET] = { "minstret", any, read_hpmcounter, write_mhpmcounter},
+ [CSR_MCYCLEH] = { "mcycleh", any32, read_hpmcounterh, write_mhpmcounterh},
+ [CSR_MINSTRETH] = { "minstreth", any32, read_hpmcounterh, write_mhpmcounterh},
/* Machine Information Registers */
[CSR_MVENDORID] = { "mvendorid", any, read_mvendorid },
@@ -3407,14 +3532,8 @@ riscv_csr_operations csr_ops[CSR_TABLE_SIZE] = {
[CSR_MIREG] = { "mireg", aia_any, NULL, NULL, rmw_xireg },
/* Machine-Level Interrupts (AIA) */
- [CSR_MTOPI] = { "mtopi", aia_any, read_mtopi },
-
- /* Machine-Level IMSIC Interface (AIA) */
- [CSR_MSETEIPNUM] = { "mseteipnum", aia_any, NULL, NULL, rmw_xsetclreinum },
- [CSR_MCLREIPNUM] = { "mclreipnum", aia_any, NULL, NULL, rmw_xsetclreinum },
- [CSR_MSETEIENUM] = { "mseteienum", aia_any, NULL, NULL, rmw_xsetclreinum },
- [CSR_MCLREIENUM] = { "mclreienum", aia_any, NULL, NULL, rmw_xsetclreinum },
[CSR_MTOPEI] = { "mtopei", aia_any, NULL, NULL, rmw_xtopei },
+ [CSR_MTOPI] = { "mtopi", aia_any, read_mtopi },
/* Virtual Interrupts for Supervisor Level (AIA) */
[CSR_MVIEN] = { "mvien", aia_any, read_zero, write_ignore },
@@ -3462,14 +3581,8 @@ riscv_csr_operations csr_ops[CSR_TABLE_SIZE] = {
[CSR_SIREG] = { "sireg", aia_smode, NULL, NULL, rmw_xireg },
/* Supervisor-Level Interrupts (AIA) */
- [CSR_STOPI] = { "stopi", aia_smode, read_stopi },
-
- /* Supervisor-Level IMSIC Interface (AIA) */
- [CSR_SSETEIPNUM] = { "sseteipnum", aia_smode, NULL, NULL, rmw_xsetclreinum },
- [CSR_SCLREIPNUM] = { "sclreipnum", aia_smode, NULL, NULL, rmw_xsetclreinum },
- [CSR_SSETEIENUM] = { "sseteienum", aia_smode, NULL, NULL, rmw_xsetclreinum },
- [CSR_SCLREIENUM] = { "sclreienum", aia_smode, NULL, NULL, rmw_xsetclreinum },
[CSR_STOPEI] = { "stopei", aia_smode, NULL, NULL, rmw_xtopei },
+ [CSR_STOPI] = { "stopi", aia_smode, read_stopi },
/* Supervisor-Level High-Half CSRs (AIA) */
[CSR_SIEH] = { "sieh", aia_smode32, NULL, NULL, rmw_sieh },
@@ -3541,14 +3654,8 @@ riscv_csr_operations csr_ops[CSR_TABLE_SIZE] = {
[CSR_VSIREG] = { "vsireg", aia_hmode, NULL, NULL, rmw_xireg },
/* VS-Level Interrupts (H-extension with AIA) */
- [CSR_VSTOPI] = { "vstopi", aia_hmode, read_vstopi },
-
- /* VS-Level IMSIC Interface (H-extension with AIA) */
- [CSR_VSSETEIPNUM] = { "vsseteipnum", aia_hmode, NULL, NULL, rmw_xsetclreinum },
- [CSR_VSCLREIPNUM] = { "vsclreipnum", aia_hmode, NULL, NULL, rmw_xsetclreinum },
- [CSR_VSSETEIENUM] = { "vsseteienum", aia_hmode, NULL, NULL, rmw_xsetclreinum },
- [CSR_VSCLREIENUM] = { "vsclreienum", aia_hmode, NULL, NULL, rmw_xsetclreinum },
[CSR_VSTOPEI] = { "vstopei", aia_hmode, NULL, NULL, rmw_xtopei },
+ [CSR_VSTOPI] = { "vstopi", aia_hmode, read_vstopi },
/* Hypervisor and VS-Level High-Half CSRs (H-extension with AIA) */
[CSR_HIDELEGH] = { "hidelegh", aia_hmode32, NULL, NULL, rmw_hidelegh },
@@ -3561,7 +3668,7 @@ riscv_csr_operations csr_ops[CSR_TABLE_SIZE] = {
/* Physical Memory Protection */
[CSR_MSECCFG] = { "mseccfg", epmp, read_mseccfg, write_mseccfg,
- .min_priv_ver = PRIV_VERSION_1_12_0 },
+ .min_priv_ver = PRIV_VERSION_1_11_0 },
[CSR_PMPCFG0] = { "pmpcfg0", pmp, read_pmpcfg, write_pmpcfg },
[CSR_PMPCFG1] = { "pmpcfg1", pmp, read_pmpcfg, write_pmpcfg },
[CSR_PMPCFG2] = { "pmpcfg2", pmp, read_pmpcfg, write_pmpcfg },
@@ -3603,154 +3710,244 @@ riscv_csr_operations csr_ops[CSR_TABLE_SIZE] = {
[CSR_SPMBASE] = { "spmbase", pointer_masking, read_spmbase, write_spmbase },
/* Performance Counters */
- [CSR_HPMCOUNTER3] = { "hpmcounter3", ctr, read_zero },
- [CSR_HPMCOUNTER4] = { "hpmcounter4", ctr, read_zero },
- [CSR_HPMCOUNTER5] = { "hpmcounter5", ctr, read_zero },
- [CSR_HPMCOUNTER6] = { "hpmcounter6", ctr, read_zero },
- [CSR_HPMCOUNTER7] = { "hpmcounter7", ctr, read_zero },
- [CSR_HPMCOUNTER8] = { "hpmcounter8", ctr, read_zero },
- [CSR_HPMCOUNTER9] = { "hpmcounter9", ctr, read_zero },
- [CSR_HPMCOUNTER10] = { "hpmcounter10", ctr, read_zero },
- [CSR_HPMCOUNTER11] = { "hpmcounter11", ctr, read_zero },
- [CSR_HPMCOUNTER12] = { "hpmcounter12", ctr, read_zero },
- [CSR_HPMCOUNTER13] = { "hpmcounter13", ctr, read_zero },
- [CSR_HPMCOUNTER14] = { "hpmcounter14", ctr, read_zero },
- [CSR_HPMCOUNTER15] = { "hpmcounter15", ctr, read_zero },
- [CSR_HPMCOUNTER16] = { "hpmcounter16", ctr, read_zero },
- [CSR_HPMCOUNTER17] = { "hpmcounter17", ctr, read_zero },
- [CSR_HPMCOUNTER18] = { "hpmcounter18", ctr, read_zero },
- [CSR_HPMCOUNTER19] = { "hpmcounter19", ctr, read_zero },
- [CSR_HPMCOUNTER20] = { "hpmcounter20", ctr, read_zero },
- [CSR_HPMCOUNTER21] = { "hpmcounter21", ctr, read_zero },
- [CSR_HPMCOUNTER22] = { "hpmcounter22", ctr, read_zero },
- [CSR_HPMCOUNTER23] = { "hpmcounter23", ctr, read_zero },
- [CSR_HPMCOUNTER24] = { "hpmcounter24", ctr, read_zero },
- [CSR_HPMCOUNTER25] = { "hpmcounter25", ctr, read_zero },
- [CSR_HPMCOUNTER26] = { "hpmcounter26", ctr, read_zero },
- [CSR_HPMCOUNTER27] = { "hpmcounter27", ctr, read_zero },
- [CSR_HPMCOUNTER28] = { "hpmcounter28", ctr, read_zero },
- [CSR_HPMCOUNTER29] = { "hpmcounter29", ctr, read_zero },
- [CSR_HPMCOUNTER30] = { "hpmcounter30", ctr, read_zero },
- [CSR_HPMCOUNTER31] = { "hpmcounter31", ctr, read_zero },
-
- [CSR_MHPMCOUNTER3] = { "mhpmcounter3", any, read_zero },
- [CSR_MHPMCOUNTER4] = { "mhpmcounter4", any, read_zero },
- [CSR_MHPMCOUNTER5] = { "mhpmcounter5", any, read_zero },
- [CSR_MHPMCOUNTER6] = { "mhpmcounter6", any, read_zero },
- [CSR_MHPMCOUNTER7] = { "mhpmcounter7", any, read_zero },
- [CSR_MHPMCOUNTER8] = { "mhpmcounter8", any, read_zero },
- [CSR_MHPMCOUNTER9] = { "mhpmcounter9", any, read_zero },
- [CSR_MHPMCOUNTER10] = { "mhpmcounter10", any, read_zero },
- [CSR_MHPMCOUNTER11] = { "mhpmcounter11", any, read_zero },
- [CSR_MHPMCOUNTER12] = { "mhpmcounter12", any, read_zero },
- [CSR_MHPMCOUNTER13] = { "mhpmcounter13", any, read_zero },
- [CSR_MHPMCOUNTER14] = { "mhpmcounter14", any, read_zero },
- [CSR_MHPMCOUNTER15] = { "mhpmcounter15", any, read_zero },
- [CSR_MHPMCOUNTER16] = { "mhpmcounter16", any, read_zero },
- [CSR_MHPMCOUNTER17] = { "mhpmcounter17", any, read_zero },
- [CSR_MHPMCOUNTER18] = { "mhpmcounter18", any, read_zero },
- [CSR_MHPMCOUNTER19] = { "mhpmcounter19", any, read_zero },
- [CSR_MHPMCOUNTER20] = { "mhpmcounter20", any, read_zero },
- [CSR_MHPMCOUNTER21] = { "mhpmcounter21", any, read_zero },
- [CSR_MHPMCOUNTER22] = { "mhpmcounter22", any, read_zero },
- [CSR_MHPMCOUNTER23] = { "mhpmcounter23", any, read_zero },
- [CSR_MHPMCOUNTER24] = { "mhpmcounter24", any, read_zero },
- [CSR_MHPMCOUNTER25] = { "mhpmcounter25", any, read_zero },
- [CSR_MHPMCOUNTER26] = { "mhpmcounter26", any, read_zero },
- [CSR_MHPMCOUNTER27] = { "mhpmcounter27", any, read_zero },
- [CSR_MHPMCOUNTER28] = { "mhpmcounter28", any, read_zero },
- [CSR_MHPMCOUNTER29] = { "mhpmcounter29", any, read_zero },
- [CSR_MHPMCOUNTER30] = { "mhpmcounter30", any, read_zero },
- [CSR_MHPMCOUNTER31] = { "mhpmcounter31", any, read_zero },
-
- [CSR_MHPMEVENT3] = { "mhpmevent3", any, read_zero },
- [CSR_MHPMEVENT4] = { "mhpmevent4", any, read_zero },
- [CSR_MHPMEVENT5] = { "mhpmevent5", any, read_zero },
- [CSR_MHPMEVENT6] = { "mhpmevent6", any, read_zero },
- [CSR_MHPMEVENT7] = { "mhpmevent7", any, read_zero },
- [CSR_MHPMEVENT8] = { "mhpmevent8", any, read_zero },
- [CSR_MHPMEVENT9] = { "mhpmevent9", any, read_zero },
- [CSR_MHPMEVENT10] = { "mhpmevent10", any, read_zero },
- [CSR_MHPMEVENT11] = { "mhpmevent11", any, read_zero },
- [CSR_MHPMEVENT12] = { "mhpmevent12", any, read_zero },
- [CSR_MHPMEVENT13] = { "mhpmevent13", any, read_zero },
- [CSR_MHPMEVENT14] = { "mhpmevent14", any, read_zero },
- [CSR_MHPMEVENT15] = { "mhpmevent15", any, read_zero },
- [CSR_MHPMEVENT16] = { "mhpmevent16", any, read_zero },
- [CSR_MHPMEVENT17] = { "mhpmevent17", any, read_zero },
- [CSR_MHPMEVENT18] = { "mhpmevent18", any, read_zero },
- [CSR_MHPMEVENT19] = { "mhpmevent19", any, read_zero },
- [CSR_MHPMEVENT20] = { "mhpmevent20", any, read_zero },
- [CSR_MHPMEVENT21] = { "mhpmevent21", any, read_zero },
- [CSR_MHPMEVENT22] = { "mhpmevent22", any, read_zero },
- [CSR_MHPMEVENT23] = { "mhpmevent23", any, read_zero },
- [CSR_MHPMEVENT24] = { "mhpmevent24", any, read_zero },
- [CSR_MHPMEVENT25] = { "mhpmevent25", any, read_zero },
- [CSR_MHPMEVENT26] = { "mhpmevent26", any, read_zero },
- [CSR_MHPMEVENT27] = { "mhpmevent27", any, read_zero },
- [CSR_MHPMEVENT28] = { "mhpmevent28", any, read_zero },
- [CSR_MHPMEVENT29] = { "mhpmevent29", any, read_zero },
- [CSR_MHPMEVENT30] = { "mhpmevent30", any, read_zero },
- [CSR_MHPMEVENT31] = { "mhpmevent31", any, read_zero },
-
- [CSR_HPMCOUNTER3H] = { "hpmcounter3h", ctr32, read_zero },
- [CSR_HPMCOUNTER4H] = { "hpmcounter4h", ctr32, read_zero },
- [CSR_HPMCOUNTER5H] = { "hpmcounter5h", ctr32, read_zero },
- [CSR_HPMCOUNTER6H] = { "hpmcounter6h", ctr32, read_zero },
- [CSR_HPMCOUNTER7H] = { "hpmcounter7h", ctr32, read_zero },
- [CSR_HPMCOUNTER8H] = { "hpmcounter8h", ctr32, read_zero },
- [CSR_HPMCOUNTER9H] = { "hpmcounter9h", ctr32, read_zero },
- [CSR_HPMCOUNTER10H] = { "hpmcounter10h", ctr32, read_zero },
- [CSR_HPMCOUNTER11H] = { "hpmcounter11h", ctr32, read_zero },
- [CSR_HPMCOUNTER12H] = { "hpmcounter12h", ctr32, read_zero },
- [CSR_HPMCOUNTER13H] = { "hpmcounter13h", ctr32, read_zero },
- [CSR_HPMCOUNTER14H] = { "hpmcounter14h", ctr32, read_zero },
- [CSR_HPMCOUNTER15H] = { "hpmcounter15h", ctr32, read_zero },
- [CSR_HPMCOUNTER16H] = { "hpmcounter16h", ctr32, read_zero },
- [CSR_HPMCOUNTER17H] = { "hpmcounter17h", ctr32, read_zero },
- [CSR_HPMCOUNTER18H] = { "hpmcounter18h", ctr32, read_zero },
- [CSR_HPMCOUNTER19H] = { "hpmcounter19h", ctr32, read_zero },
- [CSR_HPMCOUNTER20H] = { "hpmcounter20h", ctr32, read_zero },
- [CSR_HPMCOUNTER21H] = { "hpmcounter21h", ctr32, read_zero },
- [CSR_HPMCOUNTER22H] = { "hpmcounter22h", ctr32, read_zero },
- [CSR_HPMCOUNTER23H] = { "hpmcounter23h", ctr32, read_zero },
- [CSR_HPMCOUNTER24H] = { "hpmcounter24h", ctr32, read_zero },
- [CSR_HPMCOUNTER25H] = { "hpmcounter25h", ctr32, read_zero },
- [CSR_HPMCOUNTER26H] = { "hpmcounter26h", ctr32, read_zero },
- [CSR_HPMCOUNTER27H] = { "hpmcounter27h", ctr32, read_zero },
- [CSR_HPMCOUNTER28H] = { "hpmcounter28h", ctr32, read_zero },
- [CSR_HPMCOUNTER29H] = { "hpmcounter29h", ctr32, read_zero },
- [CSR_HPMCOUNTER30H] = { "hpmcounter30h", ctr32, read_zero },
- [CSR_HPMCOUNTER31H] = { "hpmcounter31h", ctr32, read_zero },
-
- [CSR_MHPMCOUNTER3H] = { "mhpmcounter3h", any32, read_zero },
- [CSR_MHPMCOUNTER4H] = { "mhpmcounter4h", any32, read_zero },
- [CSR_MHPMCOUNTER5H] = { "mhpmcounter5h", any32, read_zero },
- [CSR_MHPMCOUNTER6H] = { "mhpmcounter6h", any32, read_zero },
- [CSR_MHPMCOUNTER7H] = { "mhpmcounter7h", any32, read_zero },
- [CSR_MHPMCOUNTER8H] = { "mhpmcounter8h", any32, read_zero },
- [CSR_MHPMCOUNTER9H] = { "mhpmcounter9h", any32, read_zero },
- [CSR_MHPMCOUNTER10H] = { "mhpmcounter10h", any32, read_zero },
- [CSR_MHPMCOUNTER11H] = { "mhpmcounter11h", any32, read_zero },
- [CSR_MHPMCOUNTER12H] = { "mhpmcounter12h", any32, read_zero },
- [CSR_MHPMCOUNTER13H] = { "mhpmcounter13h", any32, read_zero },
- [CSR_MHPMCOUNTER14H] = { "mhpmcounter14h", any32, read_zero },
- [CSR_MHPMCOUNTER15H] = { "mhpmcounter15h", any32, read_zero },
- [CSR_MHPMCOUNTER16H] = { "mhpmcounter16h", any32, read_zero },
- [CSR_MHPMCOUNTER17H] = { "mhpmcounter17h", any32, read_zero },
- [CSR_MHPMCOUNTER18H] = { "mhpmcounter18h", any32, read_zero },
- [CSR_MHPMCOUNTER19H] = { "mhpmcounter19h", any32, read_zero },
- [CSR_MHPMCOUNTER20H] = { "mhpmcounter20h", any32, read_zero },
- [CSR_MHPMCOUNTER21H] = { "mhpmcounter21h", any32, read_zero },
- [CSR_MHPMCOUNTER22H] = { "mhpmcounter22h", any32, read_zero },
- [CSR_MHPMCOUNTER23H] = { "mhpmcounter23h", any32, read_zero },
- [CSR_MHPMCOUNTER24H] = { "mhpmcounter24h", any32, read_zero },
- [CSR_MHPMCOUNTER25H] = { "mhpmcounter25h", any32, read_zero },
- [CSR_MHPMCOUNTER26H] = { "mhpmcounter26h", any32, read_zero },
- [CSR_MHPMCOUNTER27H] = { "mhpmcounter27h", any32, read_zero },
- [CSR_MHPMCOUNTER28H] = { "mhpmcounter28h", any32, read_zero },
- [CSR_MHPMCOUNTER29H] = { "mhpmcounter29h", any32, read_zero },
- [CSR_MHPMCOUNTER30H] = { "mhpmcounter30h", any32, read_zero },
- [CSR_MHPMCOUNTER31H] = { "mhpmcounter31h", any32, read_zero },
+ [CSR_HPMCOUNTER3] = { "hpmcounter3", ctr, read_hpmcounter },
+ [CSR_HPMCOUNTER4] = { "hpmcounter4", ctr, read_hpmcounter },
+ [CSR_HPMCOUNTER5] = { "hpmcounter5", ctr, read_hpmcounter },
+ [CSR_HPMCOUNTER6] = { "hpmcounter6", ctr, read_hpmcounter },
+ [CSR_HPMCOUNTER7] = { "hpmcounter7", ctr, read_hpmcounter },
+ [CSR_HPMCOUNTER8] = { "hpmcounter8", ctr, read_hpmcounter },
+ [CSR_HPMCOUNTER9] = { "hpmcounter9", ctr, read_hpmcounter },
+ [CSR_HPMCOUNTER10] = { "hpmcounter10", ctr, read_hpmcounter },
+ [CSR_HPMCOUNTER11] = { "hpmcounter11", ctr, read_hpmcounter },
+ [CSR_HPMCOUNTER12] = { "hpmcounter12", ctr, read_hpmcounter },
+ [CSR_HPMCOUNTER13] = { "hpmcounter13", ctr, read_hpmcounter },
+ [CSR_HPMCOUNTER14] = { "hpmcounter14", ctr, read_hpmcounter },
+ [CSR_HPMCOUNTER15] = { "hpmcounter15", ctr, read_hpmcounter },
+ [CSR_HPMCOUNTER16] = { "hpmcounter16", ctr, read_hpmcounter },
+ [CSR_HPMCOUNTER17] = { "hpmcounter17", ctr, read_hpmcounter },
+ [CSR_HPMCOUNTER18] = { "hpmcounter18", ctr, read_hpmcounter },
+ [CSR_HPMCOUNTER19] = { "hpmcounter19", ctr, read_hpmcounter },
+ [CSR_HPMCOUNTER20] = { "hpmcounter20", ctr, read_hpmcounter },
+ [CSR_HPMCOUNTER21] = { "hpmcounter21", ctr, read_hpmcounter },
+ [CSR_HPMCOUNTER22] = { "hpmcounter22", ctr, read_hpmcounter },
+ [CSR_HPMCOUNTER23] = { "hpmcounter23", ctr, read_hpmcounter },
+ [CSR_HPMCOUNTER24] = { "hpmcounter24", ctr, read_hpmcounter },
+ [CSR_HPMCOUNTER25] = { "hpmcounter25", ctr, read_hpmcounter },
+ [CSR_HPMCOUNTER26] = { "hpmcounter26", ctr, read_hpmcounter },
+ [CSR_HPMCOUNTER27] = { "hpmcounter27", ctr, read_hpmcounter },
+ [CSR_HPMCOUNTER28] = { "hpmcounter28", ctr, read_hpmcounter },
+ [CSR_HPMCOUNTER29] = { "hpmcounter29", ctr, read_hpmcounter },
+ [CSR_HPMCOUNTER30] = { "hpmcounter30", ctr, read_hpmcounter },
+ [CSR_HPMCOUNTER31] = { "hpmcounter31", ctr, read_hpmcounter },
+
+ [CSR_MHPMCOUNTER3] = { "mhpmcounter3", mctr, read_hpmcounter,
+ write_mhpmcounter },
+ [CSR_MHPMCOUNTER4] = { "mhpmcounter4", mctr, read_hpmcounter,
+ write_mhpmcounter },
+ [CSR_MHPMCOUNTER5] = { "mhpmcounter5", mctr, read_hpmcounter,
+ write_mhpmcounter },
+ [CSR_MHPMCOUNTER6] = { "mhpmcounter6", mctr, read_hpmcounter,
+ write_mhpmcounter },
+ [CSR_MHPMCOUNTER7] = { "mhpmcounter7", mctr, read_hpmcounter,
+ write_mhpmcounter },
+ [CSR_MHPMCOUNTER8] = { "mhpmcounter8", mctr, read_hpmcounter,
+ write_mhpmcounter },
+ [CSR_MHPMCOUNTER9] = { "mhpmcounter9", mctr, read_hpmcounter,
+ write_mhpmcounter },
+ [CSR_MHPMCOUNTER10] = { "mhpmcounter10", mctr, read_hpmcounter,
+ write_mhpmcounter },
+ [CSR_MHPMCOUNTER11] = { "mhpmcounter11", mctr, read_hpmcounter,
+ write_mhpmcounter },
+ [CSR_MHPMCOUNTER12] = { "mhpmcounter12", mctr, read_hpmcounter,
+ write_mhpmcounter },
+ [CSR_MHPMCOUNTER13] = { "mhpmcounter13", mctr, read_hpmcounter,
+ write_mhpmcounter },
+ [CSR_MHPMCOUNTER14] = { "mhpmcounter14", mctr, read_hpmcounter,
+ write_mhpmcounter },
+ [CSR_MHPMCOUNTER15] = { "mhpmcounter15", mctr, read_hpmcounter,
+ write_mhpmcounter },
+ [CSR_MHPMCOUNTER16] = { "mhpmcounter16", mctr, read_hpmcounter,
+ write_mhpmcounter },
+ [CSR_MHPMCOUNTER17] = { "mhpmcounter17", mctr, read_hpmcounter,
+ write_mhpmcounter },
+ [CSR_MHPMCOUNTER18] = { "mhpmcounter18", mctr, read_hpmcounter,
+ write_mhpmcounter },
+ [CSR_MHPMCOUNTER19] = { "mhpmcounter19", mctr, read_hpmcounter,
+ write_mhpmcounter },
+ [CSR_MHPMCOUNTER20] = { "mhpmcounter20", mctr, read_hpmcounter,
+ write_mhpmcounter },
+ [CSR_MHPMCOUNTER21] = { "mhpmcounter21", mctr, read_hpmcounter,
+ write_mhpmcounter },
+ [CSR_MHPMCOUNTER22] = { "mhpmcounter22", mctr, read_hpmcounter,
+ write_mhpmcounter },
+ [CSR_MHPMCOUNTER23] = { "mhpmcounter23", mctr, read_hpmcounter,
+ write_mhpmcounter },
+ [CSR_MHPMCOUNTER24] = { "mhpmcounter24", mctr, read_hpmcounter,
+ write_mhpmcounter },
+ [CSR_MHPMCOUNTER25] = { "mhpmcounter25", mctr, read_hpmcounter,
+ write_mhpmcounter },
+ [CSR_MHPMCOUNTER26] = { "mhpmcounter26", mctr, read_hpmcounter,
+ write_mhpmcounter },
+ [CSR_MHPMCOUNTER27] = { "mhpmcounter27", mctr, read_hpmcounter,
+ write_mhpmcounter },
+ [CSR_MHPMCOUNTER28] = { "mhpmcounter28", mctr, read_hpmcounter,
+ write_mhpmcounter },
+ [CSR_MHPMCOUNTER29] = { "mhpmcounter29", mctr, read_hpmcounter,
+ write_mhpmcounter },
+ [CSR_MHPMCOUNTER30] = { "mhpmcounter30", mctr, read_hpmcounter,
+ write_mhpmcounter },
+ [CSR_MHPMCOUNTER31] = { "mhpmcounter31", mctr, read_hpmcounter,
+ write_mhpmcounter },
+
+ [CSR_MCOUNTINHIBIT] = { "mcountinhibit", any, read_mcountinhibit,
+ write_mcountinhibit, .min_priv_ver = PRIV_VERSION_1_11_0 },
+
+ [CSR_MHPMEVENT3] = { "mhpmevent3", any, read_mhpmevent,
+ write_mhpmevent },
+ [CSR_MHPMEVENT4] = { "mhpmevent4", any, read_mhpmevent,
+ write_mhpmevent },
+ [CSR_MHPMEVENT5] = { "mhpmevent5", any, read_mhpmevent,
+ write_mhpmevent },
+ [CSR_MHPMEVENT6] = { "mhpmevent6", any, read_mhpmevent,
+ write_mhpmevent },
+ [CSR_MHPMEVENT7] = { "mhpmevent7", any, read_mhpmevent,
+ write_mhpmevent },
+ [CSR_MHPMEVENT8] = { "mhpmevent8", any, read_mhpmevent,
+ write_mhpmevent },
+ [CSR_MHPMEVENT9] = { "mhpmevent9", any, read_mhpmevent,
+ write_mhpmevent },
+ [CSR_MHPMEVENT10] = { "mhpmevent10", any, read_mhpmevent,
+ write_mhpmevent },
+ [CSR_MHPMEVENT11] = { "mhpmevent11", any, read_mhpmevent,
+ write_mhpmevent },
+ [CSR_MHPMEVENT12] = { "mhpmevent12", any, read_mhpmevent,
+ write_mhpmevent },
+ [CSR_MHPMEVENT13] = { "mhpmevent13", any, read_mhpmevent,
+ write_mhpmevent },
+ [CSR_MHPMEVENT14] = { "mhpmevent14", any, read_mhpmevent,
+ write_mhpmevent },
+ [CSR_MHPMEVENT15] = { "mhpmevent15", any, read_mhpmevent,
+ write_mhpmevent },
+ [CSR_MHPMEVENT16] = { "mhpmevent16", any, read_mhpmevent,
+ write_mhpmevent },
+ [CSR_MHPMEVENT17] = { "mhpmevent17", any, read_mhpmevent,
+ write_mhpmevent },
+ [CSR_MHPMEVENT18] = { "mhpmevent18", any, read_mhpmevent,
+ write_mhpmevent },
+ [CSR_MHPMEVENT19] = { "mhpmevent19", any, read_mhpmevent,
+ write_mhpmevent },
+ [CSR_MHPMEVENT20] = { "mhpmevent20", any, read_mhpmevent,
+ write_mhpmevent },
+ [CSR_MHPMEVENT21] = { "mhpmevent21", any, read_mhpmevent,
+ write_mhpmevent },
+ [CSR_MHPMEVENT22] = { "mhpmevent22", any, read_mhpmevent,
+ write_mhpmevent },
+ [CSR_MHPMEVENT23] = { "mhpmevent23", any, read_mhpmevent,
+ write_mhpmevent },
+ [CSR_MHPMEVENT24] = { "mhpmevent24", any, read_mhpmevent,
+ write_mhpmevent },
+ [CSR_MHPMEVENT25] = { "mhpmevent25", any, read_mhpmevent,
+ write_mhpmevent },
+ [CSR_MHPMEVENT26] = { "mhpmevent26", any, read_mhpmevent,
+ write_mhpmevent },
+ [CSR_MHPMEVENT27] = { "mhpmevent27", any, read_mhpmevent,
+ write_mhpmevent },
+ [CSR_MHPMEVENT28] = { "mhpmevent28", any, read_mhpmevent,
+ write_mhpmevent },
+ [CSR_MHPMEVENT29] = { "mhpmevent29", any, read_mhpmevent,
+ write_mhpmevent },
+ [CSR_MHPMEVENT30] = { "mhpmevent30", any, read_mhpmevent,
+ write_mhpmevent },
+ [CSR_MHPMEVENT31] = { "mhpmevent31", any, read_mhpmevent,
+ write_mhpmevent },
+
+ [CSR_HPMCOUNTER3H] = { "hpmcounter3h", ctr32, read_hpmcounterh },
+ [CSR_HPMCOUNTER4H] = { "hpmcounter4h", ctr32, read_hpmcounterh },
+ [CSR_HPMCOUNTER5H] = { "hpmcounter5h", ctr32, read_hpmcounterh },
+ [CSR_HPMCOUNTER6H] = { "hpmcounter6h", ctr32, read_hpmcounterh },
+ [CSR_HPMCOUNTER7H] = { "hpmcounter7h", ctr32, read_hpmcounterh },
+ [CSR_HPMCOUNTER8H] = { "hpmcounter8h", ctr32, read_hpmcounterh },
+ [CSR_HPMCOUNTER9H] = { "hpmcounter9h", ctr32, read_hpmcounterh },
+ [CSR_HPMCOUNTER10H] = { "hpmcounter10h", ctr32, read_hpmcounterh },
+ [CSR_HPMCOUNTER11H] = { "hpmcounter11h", ctr32, read_hpmcounterh },
+ [CSR_HPMCOUNTER12H] = { "hpmcounter12h", ctr32, read_hpmcounterh },
+ [CSR_HPMCOUNTER13H] = { "hpmcounter13h", ctr32, read_hpmcounterh },
+ [CSR_HPMCOUNTER14H] = { "hpmcounter14h", ctr32, read_hpmcounterh },
+ [CSR_HPMCOUNTER15H] = { "hpmcounter15h", ctr32, read_hpmcounterh },
+ [CSR_HPMCOUNTER16H] = { "hpmcounter16h", ctr32, read_hpmcounterh },
+ [CSR_HPMCOUNTER17H] = { "hpmcounter17h", ctr32, read_hpmcounterh },
+ [CSR_HPMCOUNTER18H] = { "hpmcounter18h", ctr32, read_hpmcounterh },
+ [CSR_HPMCOUNTER19H] = { "hpmcounter19h", ctr32, read_hpmcounterh },
+ [CSR_HPMCOUNTER20H] = { "hpmcounter20h", ctr32, read_hpmcounterh },
+ [CSR_HPMCOUNTER21H] = { "hpmcounter21h", ctr32, read_hpmcounterh },
+ [CSR_HPMCOUNTER22H] = { "hpmcounter22h", ctr32, read_hpmcounterh },
+ [CSR_HPMCOUNTER23H] = { "hpmcounter23h", ctr32, read_hpmcounterh },
+ [CSR_HPMCOUNTER24H] = { "hpmcounter24h", ctr32, read_hpmcounterh },
+ [CSR_HPMCOUNTER25H] = { "hpmcounter25h", ctr32, read_hpmcounterh },
+ [CSR_HPMCOUNTER26H] = { "hpmcounter26h", ctr32, read_hpmcounterh },
+ [CSR_HPMCOUNTER27H] = { "hpmcounter27h", ctr32, read_hpmcounterh },
+ [CSR_HPMCOUNTER28H] = { "hpmcounter28h", ctr32, read_hpmcounterh },
+ [CSR_HPMCOUNTER29H] = { "hpmcounter29h", ctr32, read_hpmcounterh },
+ [CSR_HPMCOUNTER30H] = { "hpmcounter30h", ctr32, read_hpmcounterh },
+ [CSR_HPMCOUNTER31H] = { "hpmcounter31h", ctr32, read_hpmcounterh },
+
+ [CSR_MHPMCOUNTER3H] = { "mhpmcounter3h", mctr32, read_hpmcounterh,
+ write_mhpmcounterh },
+ [CSR_MHPMCOUNTER4H] = { "mhpmcounter4h", mctr32, read_hpmcounterh,
+ write_mhpmcounterh },
+ [CSR_MHPMCOUNTER5H] = { "mhpmcounter5h", mctr32, read_hpmcounterh,
+ write_mhpmcounterh },
+ [CSR_MHPMCOUNTER6H] = { "mhpmcounter6h", mctr32, read_hpmcounterh,
+ write_mhpmcounterh },
+ [CSR_MHPMCOUNTER7H] = { "mhpmcounter7h", mctr32, read_hpmcounterh,
+ write_mhpmcounterh },
+ [CSR_MHPMCOUNTER8H] = { "mhpmcounter8h", mctr32, read_hpmcounterh,
+ write_mhpmcounterh },
+ [CSR_MHPMCOUNTER9H] = { "mhpmcounter9h", mctr32, read_hpmcounterh,
+ write_mhpmcounterh },
+ [CSR_MHPMCOUNTER10H] = { "mhpmcounter10h", mctr32, read_hpmcounterh,
+ write_mhpmcounterh },
+ [CSR_MHPMCOUNTER11H] = { "mhpmcounter11h", mctr32, read_hpmcounterh,
+ write_mhpmcounterh },
+ [CSR_MHPMCOUNTER12H] = { "mhpmcounter12h", mctr32, read_hpmcounterh,
+ write_mhpmcounterh },
+ [CSR_MHPMCOUNTER13H] = { "mhpmcounter13h", mctr32, read_hpmcounterh,
+ write_mhpmcounterh },
+ [CSR_MHPMCOUNTER14H] = { "mhpmcounter14h", mctr32, read_hpmcounterh,
+ write_mhpmcounterh },
+ [CSR_MHPMCOUNTER15H] = { "mhpmcounter15h", mctr32, read_hpmcounterh,
+ write_mhpmcounterh },
+ [CSR_MHPMCOUNTER16H] = { "mhpmcounter16h", mctr32, read_hpmcounterh,
+ write_mhpmcounterh },
+ [CSR_MHPMCOUNTER17H] = { "mhpmcounter17h", mctr32, read_hpmcounterh,
+ write_mhpmcounterh },
+ [CSR_MHPMCOUNTER18H] = { "mhpmcounter18h", mctr32, read_hpmcounterh,
+ write_mhpmcounterh },
+ [CSR_MHPMCOUNTER19H] = { "mhpmcounter19h", mctr32, read_hpmcounterh,
+ write_mhpmcounterh },
+ [CSR_MHPMCOUNTER20H] = { "mhpmcounter20h", mctr32, read_hpmcounterh,
+ write_mhpmcounterh },
+ [CSR_MHPMCOUNTER21H] = { "mhpmcounter21h", mctr32, read_hpmcounterh,
+ write_mhpmcounterh },
+ [CSR_MHPMCOUNTER22H] = { "mhpmcounter22h", mctr32, read_hpmcounterh,
+ write_mhpmcounterh },
+ [CSR_MHPMCOUNTER23H] = { "mhpmcounter23h", mctr32, read_hpmcounterh,
+ write_mhpmcounterh },
+ [CSR_MHPMCOUNTER24H] = { "mhpmcounter24h", mctr32, read_hpmcounterh,
+ write_mhpmcounterh },
+ [CSR_MHPMCOUNTER25H] = { "mhpmcounter25h", mctr32, read_hpmcounterh,
+ write_mhpmcounterh },
+ [CSR_MHPMCOUNTER26H] = { "mhpmcounter26h", mctr32, read_hpmcounterh,
+ write_mhpmcounterh },
+ [CSR_MHPMCOUNTER27H] = { "mhpmcounter27h", mctr32, read_hpmcounterh,
+ write_mhpmcounterh },
+ [CSR_MHPMCOUNTER28H] = { "mhpmcounter28h", mctr32, read_hpmcounterh,
+ write_mhpmcounterh },
+ [CSR_MHPMCOUNTER29H] = { "mhpmcounter29h", mctr32, read_hpmcounterh,
+ write_mhpmcounterh },
+ [CSR_MHPMCOUNTER30H] = { "mhpmcounter30h", mctr32, read_hpmcounterh,
+ write_mhpmcounterh },
+ [CSR_MHPMCOUNTER31H] = { "mhpmcounter31h", mctr32, read_hpmcounterh,
+ write_mhpmcounterh },
#endif /* !CONFIG_USER_ONLY */
};
diff --git a/target/riscv/insn_trans/trans_privileged.c.inc b/target/riscv/insn_trans/trans_privileged.c.inc
index 53613682e8..46f96ad74d 100644
--- a/target/riscv/insn_trans/trans_privileged.c.inc
+++ b/target/riscv/insn_trans/trans_privileged.c.inc
@@ -75,6 +75,7 @@ static bool trans_sret(DisasContext *ctx, arg_sret *a)
{
#ifndef CONFIG_USER_ONLY
if (has_ext(ctx, RVS)) {
+ decode_save_opc(ctx);
gen_helper_sret(cpu_pc, cpu_env);
tcg_gen_exit_tb(NULL, 0); /* no chaining */
ctx->base.is_jmp = DISAS_NORETURN;
@@ -90,6 +91,7 @@ static bool trans_sret(DisasContext *ctx, arg_sret *a)
static bool trans_mret(DisasContext *ctx, arg_mret *a)
{
#ifndef CONFIG_USER_ONLY
+ decode_save_opc(ctx);
gen_helper_mret(cpu_pc, cpu_env);
tcg_gen_exit_tb(NULL, 0); /* no chaining */
ctx->base.is_jmp = DISAS_NORETURN;
@@ -102,6 +104,7 @@ static bool trans_mret(DisasContext *ctx, arg_mret *a)
static bool trans_wfi(DisasContext *ctx, arg_wfi *a)
{
#ifndef CONFIG_USER_ONLY
+ decode_save_opc(ctx);
gen_set_pc_imm(ctx, ctx->pc_succ_insn);
gen_helper_wfi(cpu_env);
return true;
@@ -113,6 +116,7 @@ static bool trans_wfi(DisasContext *ctx, arg_wfi *a)
static bool trans_sfence_vma(DisasContext *ctx, arg_sfence_vma *a)
{
#ifndef CONFIG_USER_ONLY
+ decode_save_opc(ctx);
gen_helper_tlb_flush(cpu_env);
return true;
#endif
diff --git a/target/riscv/insn_trans/trans_rvh.c.inc b/target/riscv/insn_trans/trans_rvh.c.inc
index cebcb3f8f6..4f8aecddc7 100644
--- a/target/riscv/insn_trans/trans_rvh.c.inc
+++ b/target/riscv/insn_trans/trans_rvh.c.inc
@@ -169,6 +169,7 @@ static bool trans_hfence_gvma(DisasContext *ctx, arg_sfence_vma *a)
{
REQUIRE_EXT(ctx, RVH);
#ifndef CONFIG_USER_ONLY
+ decode_save_opc(ctx);
gen_helper_hyp_gvma_tlb_flush(cpu_env);
return true;
#endif
@@ -179,6 +180,7 @@ static bool trans_hfence_vvma(DisasContext *ctx, arg_sfence_vma *a)
{
REQUIRE_EXT(ctx, RVH);
#ifndef CONFIG_USER_ONLY
+ decode_save_opc(ctx);
gen_helper_hyp_tlb_flush(cpu_env);
return true;
#endif
diff --git a/target/riscv/insn_trans/trans_rvi.c.inc b/target/riscv/insn_trans/trans_rvi.c.inc
index f1342f30f8..ca8e3d1ea1 100644
--- a/target/riscv/insn_trans/trans_rvi.c.inc
+++ b/target/riscv/insn_trans/trans_rvi.c.inc
@@ -32,17 +32,13 @@ static bool trans_c64_illegal(DisasContext *ctx, arg_empty *a)
static bool trans_lui(DisasContext *ctx, arg_lui *a)
{
- if (a->rd != 0) {
- gen_set_gpri(ctx, a->rd, a->imm);
- }
+ gen_set_gpri(ctx, a->rd, a->imm);
return true;
}
static bool trans_auipc(DisasContext *ctx, arg_auipc *a)
{
- if (a->rd != 0) {
- gen_set_gpri(ctx, a->rd, a->imm + ctx->base.pc_next);
- }
+ gen_set_gpri(ctx, a->rd, a->imm + ctx->base.pc_next);
return true;
}
@@ -822,6 +818,8 @@ static bool trans_fence_i(DisasContext *ctx, arg_fence_i *a)
static bool do_csr_post(DisasContext *ctx)
{
+ /* The helper may raise ILLEGAL_INSN -- record binv for unwind. */
+ decode_save_opc(ctx);
/* We may have changed important cpu state -- exit to main loop. */
gen_set_pc_imm(ctx, ctx->pc_succ_insn);
tcg_gen_exit_tb(NULL, 0);
diff --git a/target/riscv/machine.c b/target/riscv/machine.c
index 2a437b29a1..dc182ca811 100644
--- a/target/riscv/machine.c
+++ b/target/riscv/machine.c
@@ -279,7 +279,28 @@ static const VMStateDescription vmstate_envcfg = {
VMSTATE_UINT64(env.menvcfg, RISCVCPU),
VMSTATE_UINTTL(env.senvcfg, RISCVCPU),
VMSTATE_UINT64(env.henvcfg, RISCVCPU),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
+static bool pmu_needed(void *opaque)
+{
+ RISCVCPU *cpu = opaque;
+ return cpu->cfg.pmu_num;
+}
+
+static const VMStateDescription vmstate_pmu_ctr_state = {
+ .name = "cpu/pmu",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .needed = pmu_needed,
+ .fields = (VMStateField[]) {
+ VMSTATE_UINTTL(mhpmcounter_val, PMUCTRState),
+ VMSTATE_UINTTL(mhpmcounterh_val, PMUCTRState),
+ VMSTATE_UINTTL(mhpmcounter_prev, PMUCTRState),
+ VMSTATE_UINTTL(mhpmcounterh_prev, PMUCTRState),
+ VMSTATE_BOOL(started, PMUCTRState),
VMSTATE_END_OF_LIST()
}
};
@@ -330,6 +351,10 @@ const VMStateDescription vmstate_riscv_cpu = {
VMSTATE_UINTTL(env.siselect, RISCVCPU),
VMSTATE_UINTTL(env.scounteren, RISCVCPU),
VMSTATE_UINTTL(env.mcounteren, RISCVCPU),
+ VMSTATE_UINTTL(env.mcountinhibit, RISCVCPU),
+ VMSTATE_STRUCT_ARRAY(env.pmu_ctrs, RISCVCPU, RV_MAX_MHPMCOUNTERS, 0,
+ vmstate_pmu_ctr_state, PMUCTRState),
+ VMSTATE_UINTTL_ARRAY(env.mhpmevent_val, RISCVCPU, RV_MAX_MHPMEVENTS),
VMSTATE_UINTTL(env.sscratch, RISCVCPU),
VMSTATE_UINTTL(env.mscratch, RISCVCPU),
VMSTATE_UINT64(env.mfromhost, RISCVCPU),
diff --git a/target/riscv/meson.build b/target/riscv/meson.build
index 096249f3a3..2c1975e72c 100644
--- a/target/riscv/meson.build
+++ b/target/riscv/meson.build
@@ -30,7 +30,8 @@ riscv_softmmu_ss.add(files(
'pmp.c',
'debug.c',
'monitor.c',
- 'machine.c'
+ 'machine.c',
+ 'pmu.c'
))
target_arch += {'riscv': riscv_ss}
diff --git a/target/riscv/pmp.c b/target/riscv/pmp.c
index 151da3fa08..ea2b67d947 100644
--- a/target/riscv/pmp.c
+++ b/target/riscv/pmp.c
@@ -167,6 +167,9 @@ void pmp_update_rule_addr(CPURISCVState *env, uint32_t pmp_index)
case PMP_AMATCH_TOR:
sa = prev_addr << 2; /* shift up from [xx:0] to [xx+2:2] */
ea = (this_addr << 2) - 1u;
+ if (sa > ea) {
+ sa = ea = 0u;
+ }
break;
case PMP_AMATCH_NA4:
diff --git a/target/riscv/pmu.c b/target/riscv/pmu.c
new file mode 100644
index 0000000000..000fe8da45
--- /dev/null
+++ b/target/riscv/pmu.c
@@ -0,0 +1,32 @@
+/*
+ * RISC-V PMU file.
+ *
+ * Copyright (c) 2021 Western Digital Corporation or its affiliates.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2 or later, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "qemu/osdep.h"
+#include "cpu.h"
+#include "pmu.h"
+
+bool riscv_pmu_ctr_monitor_instructions(CPURISCVState *env,
+ uint32_t target_ctr)
+{
+ return (target_ctr == 0) ? true : false;
+}
+
+bool riscv_pmu_ctr_monitor_cycles(CPURISCVState *env, uint32_t target_ctr)
+{
+ return (target_ctr == 2) ? true : false;
+}
diff --git a/target/riscv/pmu.h b/target/riscv/pmu.h
new file mode 100644
index 0000000000..58a5bc3a40
--- /dev/null
+++ b/target/riscv/pmu.h
@@ -0,0 +1,28 @@
+/*
+ * RISC-V PMU header file.
+ *
+ * Copyright (c) 2021 Western Digital Corporation or its affiliates.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2 or later, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "qemu/osdep.h"
+#include "qemu/log.h"
+#include "cpu.h"
+#include "qemu/main-loop.h"
+#include "exec/exec-all.h"
+
+bool riscv_pmu_ctr_monitor_instructions(CPURISCVState *env,
+ uint32_t target_ctr);
+bool riscv_pmu_ctr_monitor_cycles(CPURISCVState *env,
+ uint32_t target_ctr);
diff --git a/target/riscv/translate.c b/target/riscv/translate.c
index b151c20674..63b04e8a94 100644
--- a/target/riscv/translate.c
+++ b/target/riscv/translate.c
@@ -206,6 +206,13 @@ static void gen_check_nanbox_s(TCGv_i64 out, TCGv_i64 in)
tcg_gen_movcond_i64(TCG_COND_GEU, out, in, t_max, in, t_nan);
}
+static void decode_save_opc(DisasContext *ctx)
+{
+ assert(ctx->insn_start != NULL);
+ tcg_set_insn_start_param(ctx->insn_start, 1, ctx->opcode);
+ ctx->insn_start = NULL;
+}
+
static void gen_set_pc_imm(DisasContext *ctx, target_ulong dest)
{
if (get_xl(ctx) == MXL_RV32) {
@@ -230,22 +237,17 @@ static void generate_exception(DisasContext *ctx, int excp)
ctx->base.is_jmp = DISAS_NORETURN;
}
-static void generate_exception_mtval(DisasContext *ctx, int excp)
-{
- gen_set_pc_imm(ctx, ctx->base.pc_next);
- tcg_gen_st_tl(cpu_pc, cpu_env, offsetof(CPURISCVState, badaddr));
- gen_helper_raise_exception(cpu_env, tcg_constant_i32(excp));
- ctx->base.is_jmp = DISAS_NORETURN;
-}
-
static void gen_exception_illegal(DisasContext *ctx)
{
+ tcg_gen_st_i32(tcg_constant_i32(ctx->opcode), cpu_env,
+ offsetof(CPURISCVState, bins));
generate_exception(ctx, RISCV_EXCP_ILLEGAL_INST);
}
static void gen_exception_inst_addr_mis(DisasContext *ctx)
{
- generate_exception_mtval(ctx, RISCV_EXCP_INST_ADDR_MIS);
+ tcg_gen_st_tl(cpu_pc, cpu_env, offsetof(CPURISCVState, badaddr));
+ generate_exception(ctx, RISCV_EXCP_INST_ADDR_MIS);
}
static void gen_goto_tb(DisasContext *ctx, int n, target_ulong dest)
@@ -640,6 +642,8 @@ static void gen_set_rm(DisasContext *ctx, int rm)
return;
}
+ /* The helper may raise ILLEGAL_INSN -- record binv for unwind. */
+ decode_save_opc(ctx);
gen_helper_set_rounding_mode(cpu_env, tcg_constant_i32(rm));
}
@@ -1018,13 +1022,6 @@ static uint32_t opcode_at(DisasContextBase *dcbase, target_ulong pc)
/* Include decoders for factored-out extensions */
#include "decode-XVentanaCondOps.c.inc"
-static inline void decode_save_opc(DisasContext *ctx, target_ulong opc)
-{
- assert(ctx->insn_start != NULL);
- tcg_set_insn_start_param(ctx->insn_start, 1, opc);
- ctx->insn_start = NULL;
-}
-
static void decode_opc(CPURISCVState *env, DisasContext *ctx, uint16_t opcode)
{
/*
@@ -1041,7 +1038,6 @@ static void decode_opc(CPURISCVState *env, DisasContext *ctx, uint16_t opcode)
/* Check for compressed insn */
if (extract16(opcode, 0, 2) != 3) {
- decode_save_opc(ctx, opcode);
if (!has_ext(ctx, RVC)) {
gen_exception_illegal(ctx);
} else {
@@ -1056,7 +1052,6 @@ static void decode_opc(CPURISCVState *env, DisasContext *ctx, uint16_t opcode)
opcode32 = deposit32(opcode32, 16, 16,
translator_lduw(env, &ctx->base,
ctx->base.pc_next + 2));
- decode_save_opc(ctx, opcode32);
ctx->opcode = opcode32;
ctx->pc_succ_insn = ctx->base.pc_next + 4;
diff --git a/tests/tcg/riscv64/Makefile.softmmu-target b/tests/tcg/riscv64/Makefile.softmmu-target
new file mode 100644
index 0000000000..e22cdb34c5
--- /dev/null
+++ b/tests/tcg/riscv64/Makefile.softmmu-target
@@ -0,0 +1,21 @@
+#
+# RISC-V system tests
+#
+
+TEST_SRC = $(SRC_PATH)/tests/tcg/riscv64
+VPATH += $(TEST_SRC)
+
+LINK_SCRIPT = $(TEST_SRC)/semihost.ld
+LDFLAGS = -T $(LINK_SCRIPT)
+CFLAGS += -g -Og
+
+%.o: %.S
+ $(CC) $(CFLAGS) $< -c -o $@
+%: %.o $(LINK_SCRIPT)
+ $(LD) $(LDFLAGS) $< -o $@
+
+QEMU_OPTS += -M virt -display none -semihosting -device loader,file=
+
+EXTRA_RUNS += run-issue1060
+run-issue1060: issue1060
+ $(call run-test, $<, $(QEMU) $(QEMU_OPTS)$<)
diff --git a/tests/tcg/riscv64/issue1060.S b/tests/tcg/riscv64/issue1060.S
new file mode 100644
index 0000000000..17b7fe1be2
--- /dev/null
+++ b/tests/tcg/riscv64/issue1060.S
@@ -0,0 +1,53 @@
+ .option norvc
+
+ .text
+ .global _start
+_start:
+ lla t0, trap
+ csrw mtvec, t0
+
+ # These are all illegal instructions
+ csrw time, x0
+ .insn i CUSTOM_0, 0, x0, x0, 0x321
+ csrw time, x0
+ .insn i CUSTOM_0, 0, x0, x0, 0x123
+ csrw cycle, x0
+
+ # Success!
+ li a0, 0
+ j _exit
+
+trap:
+ # When an instruction traps, compare it to the insn in memory.
+ csrr t0, mepc
+ csrr t1, mtval
+ lwu t2, 0(t0)
+ bne t1, t2, fail
+
+ # Skip the insn and continue.
+ addi t0, t0, 4
+ csrw mepc, t0
+ mret
+
+fail:
+ li a0, 1
+
+# Exit code in a0
+_exit:
+ lla a1, semiargs
+ li t0, 0x20026 # ADP_Stopped_ApplicationExit
+ sd t0, 0(a1)
+ sd a0, 8(a1)
+ li a0, 0x20 # TARGET_SYS_EXIT_EXTENDED
+
+ # Semihosting call sequence
+ .balign 16
+ slli zero, zero, 0x1f
+ ebreak
+ srai zero, zero, 0x7
+ j .
+
+ .data
+ .balign 16
+semiargs:
+ .space 16
diff --git a/tests/tcg/riscv64/semihost.ld b/tests/tcg/riscv64/semihost.ld
new file mode 100644
index 0000000000..a59cc56b28
--- /dev/null
+++ b/tests/tcg/riscv64/semihost.ld
@@ -0,0 +1,21 @@
+ENTRY(_start)
+
+SECTIONS
+{
+ /* virt machine, RAM starts at 2gb */
+ . = 0x80000000;
+ .text : {
+ *(.text)
+ }
+ .rodata : {
+ *(.rodata)
+ }
+ /* align r/w section to next 2mb */
+ . = ALIGN(1 << 21);
+ .data : {
+ *(.data)
+ }
+ .bss : {
+ *(.bss)
+ }
+}