Fifth RISC-V PR for QEMU 7.1

* Fix register zero guarding for auipc and lui
 * Ensure bins (mtval) is set correctly
 * Minimize the calls to decode_save_opc
 * Guard against PMP ranges with a negative size
 * Implement mcountinhibit CSR
 * Add support for hpmcounters/hpmevents
 * Improve PMU implenentation
 * Support mcycle/minstret write operation
 * Fixup MSECCFG minimum priv check
 * Ibex (OpenTitan) fixup priv version
 * Fix bug resulting in always using latest priv spec
 * Reduce FDT address alignment constraints
 * Set minumum priv spec version for mcountinhibit
 * AIA update to v0.3 of the spec
 -----BEGIN PGP SIGNATURE-----
 
 iQEzBAABCAAdFiEE9sSsRtSTSGjTuM6PIeENKd+XcFQFAmLA3r8ACgkQIeENKd+X
 cFQdFQf6A63mocJxSc0vqMTBNULwgcUKbRbnkazbFS4vtbo/YXioCGaHA8c8trKj
 HbZfJv64phOThj7Y8ifLozENjnHX7dHbspPOcWIK9yalvKLA4EB4+OI7LisoL1vg
 H4E+9nXSzskaCmJgwSM6WlS0Vf89VxL0CoBb3XqJocSaajstg1XpqrR9anTZlUhl
 N712cLze+bOxBHTdjtC5Kxuxj+zmNvcMmuhldIJRdPCW8P5v2yccNVc6+hrE3WUX
 9jHGMthS4qC5oVhok14/tPoyL0QTZpU2DXrJPFGUigOvUHoMBfQ3Qhulx3/rGLZv
 4SdTD9ASrNWJfa+eyHAPNw//5NxTYA==
 =N7VN
 -----END PGP SIGNATURE-----

Merge tag 'pull-riscv-to-apply-20220703-1' of github.com:alistair23/qemu into staging

Fifth RISC-V PR for QEMU 7.1

* Fix register zero guarding for auipc and lui
* Ensure bins (mtval) is set correctly
* Minimize the calls to decode_save_opc
* Guard against PMP ranges with a negative size
* Implement mcountinhibit CSR
* Add support for hpmcounters/hpmevents
* Improve PMU implenentation
* Support mcycle/minstret write operation
* Fixup MSECCFG minimum priv check
* Ibex (OpenTitan) fixup priv version
* Fix bug resulting in always using latest priv spec
* Reduce FDT address alignment constraints
* Set minumum priv spec version for mcountinhibit
* AIA update to v0.3 of the spec

# -----BEGIN PGP SIGNATURE-----
#
# iQEzBAABCAAdFiEE9sSsRtSTSGjTuM6PIeENKd+XcFQFAmLA3r8ACgkQIeENKd+X
# cFQdFQf6A63mocJxSc0vqMTBNULwgcUKbRbnkazbFS4vtbo/YXioCGaHA8c8trKj
# HbZfJv64phOThj7Y8ifLozENjnHX7dHbspPOcWIK9yalvKLA4EB4+OI7LisoL1vg
# H4E+9nXSzskaCmJgwSM6WlS0Vf89VxL0CoBb3XqJocSaajstg1XpqrR9anTZlUhl
# N712cLze+bOxBHTdjtC5Kxuxj+zmNvcMmuhldIJRdPCW8P5v2yccNVc6+hrE3WUX
# 9jHGMthS4qC5oVhok14/tPoyL0QTZpU2DXrJPFGUigOvUHoMBfQ3Qhulx3/rGLZv
# 4SdTD9ASrNWJfa+eyHAPNw//5NxTYA==
# =N7VN
# -----END PGP SIGNATURE-----
# gpg: Signature made Sun 03 Jul 2022 05:41:43 AM +0530
# gpg:                using RSA key F6C4AC46D4934868D3B8CE8F21E10D29DF977054
# gpg: Good signature from "Alistair Francis <alistair@alistair23.me>" [undefined]
# gpg: WARNING: This key is not certified with a trusted signature!
# gpg:          There is no indication that the signature belongs to the owner.
# Primary key fingerprint: F6C4 AC46 D493 4868 D3B8  CE8F 21E1 0D29 DF97 7054

* tag 'pull-riscv-to-apply-20220703-1' of github.com:alistair23/qemu:
  target/riscv: Update default priority table for local interrupts
  target/riscv: Remove CSRs that set/clear an IMSIC interrupt file bits
  target/riscv: Set minumum priv spec version for mcountinhibit
  hw/riscv: boot: Reduce FDT address alignment constraints
  target/riscv: Don't force update priv spec version to latest
  target/riscv: Ibex: Support priv version 1.11
  target/riscv: Fixup MSECCFG minimum priv check
  target/riscv: Support mcycle/minstret write operation
  target/riscv: Add support for hpmcounters/hpmevents
  target/riscv: Implement mcountinhibit CSR
  target/riscv: pmu: Make number of counters configurable
  target/riscv: pmu: Rename the counters extension to pmu
  target/riscv: Implement PMU CSR predicate function for S-mode
  target/riscv: Fix PMU CSR predicate function
  target/riscv/pmp: guard against PMP ranges with a negative size
  target/riscv: Minimize the calls to decode_save_opc
  target/riscv: Remove generate_exception_mtval
  target/riscv: Set env->bins in gen_exception_illegal
  target/riscv: Remove condition guarding register zero for auipc and lui

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
This commit is contained in:
Richard Henderson 2022-07-03 06:29:02 +05:30
commit e8e86b484e
18 changed files with 837 additions and 450 deletions

View File

@ -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 */

View File

@ -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),

View File

@ -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;

View File

@ -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)

View File

@ -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,
/* 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,
[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,
/* 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,
[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,
[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,
[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,
[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,
[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,
[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,
[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)

View File

@ -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)
{
#if !defined(CONFIG_USER_ONLY)
if (icount_enabled()) {
*val = icount_get();
} else {
*val = cpu_get_host_ticks();
}
#else
*val = cpu_get_host_ticks();
#endif
return RISCV_EXCP_NONE;
}
int64_t val;
target_ulong result;
static RISCVException read_instreth(CPURISCVState *env, int csrno,
target_ulong *val)
{
#if !defined(CONFIG_USER_ONLY)
if (icount_enabled()) {
*val = icount_get() >> 32;
val = icount_get();
} else {
*val = cpu_get_host_ticks() >> 32;
val = cpu_get_host_ticks();
}
#else
*val = cpu_get_host_ticks() >> 32;
val = cpu_get_host_ticks();
#endif
return RISCV_EXCP_NONE;
if (shift) {
result = val >> 32;
} else {
result = val;
}
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_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", 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_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_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_MCOUNTINHIBIT] = { "mcountinhibit", any, read_mcountinhibit,
write_mcountinhibit, .min_priv_ver = PRIV_VERSION_1_11_0 },
[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_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_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_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 */
};

View File

@ -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

View File

@ -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

View File

@ -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);

View File

@ -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),

View File

@ -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}

View File

@ -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:

32
target/riscv/pmu.c Normal file
View File

@ -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;
}

28
target/riscv/pmu.h Normal file
View File

@ -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);

View File

@ -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;

View File

@ -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)$<)

View File

@ -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

View File

@ -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)
}
}