Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions hw/riscv/virt.c
Original file line number Diff line number Diff line change
Expand Up @@ -273,6 +273,7 @@ static void create_fdt_socket_cpus(RISCVVirtState *s, int socket,
qemu_fdt_setprop_cell(ms->fdt, cpu_name, "reg",
s->soc[socket].hartid_base + cpu);
qemu_fdt_setprop_string(ms->fdt, cpu_name, "device_type", "cpu");
qemu_fdt_setprop_cell(ms->fdt, cpu_name, "clock-frequency", 1000000000);
riscv_socket_fdt_write_id(ms, cpu_name, socket);
qemu_fdt_setprop_cell(ms->fdt, cpu_name, "phandle", cpu_phandle);

Expand Down
2 changes: 2 additions & 0 deletions target/riscv/cpu.c
Original file line number Diff line number Diff line change
Expand Up @@ -205,6 +205,7 @@ const RISCVIsaExtData isa_edata_arr[] = {
ISA_EXT_DATA_ENTRY(ssccfg, PRIV_VERSION_1_12_0, ext_ssccfg),
ISA_EXT_DATA_ENTRY(sscofpmf, PRIV_VERSION_1_12_0, ext_sscofpmf),
ISA_EXT_DATA_ENTRY(ssqosid, PRIV_VERSION_1_12_0, ext_ssqosid),
ISA_EXT_DATA_ENTRY(sscpuutil, PRIV_VERSION_1_12_0, ext_sscpuutil),
ISA_EXT_DATA_ENTRY(sscounterenw, PRIV_VERSION_1_12_0, has_priv_1_12),
ISA_EXT_DATA_ENTRY(sscsrind, PRIV_VERSION_1_12_0, ext_sscsrind),
ISA_EXT_DATA_ENTRY(ssdbltrp, PRIV_VERSION_1_12_0, ext_ssdbltrp),
Expand Down Expand Up @@ -2981,6 +2982,7 @@ const char *riscv_get_misa_ext_description(uint32_t bit)
const RISCVCPUMultiExtConfig riscv_cpu_extensions[] = {
/* Defaults for standard extensions */
MULTI_EXT_CFG_BOOL("sscofpmf", ext_sscofpmf, false),
MULTI_EXT_CFG_BOOL("sscpuutil", ext_sscpuutil, false),
MULTI_EXT_CFG_BOOL("ssqosid", ext_ssqosid, false),
MULTI_EXT_CFG_BOOL("smcntrpmf", ext_smcntrpmf, false),
MULTI_EXT_CFG_BOOL("smcsrind", ext_smcsrind, false),
Expand Down
5 changes: 5 additions & 0 deletions target/riscv/cpu.h
Original file line number Diff line number Diff line change
Expand Up @@ -409,6 +409,11 @@ struct CPUArchState {
uint32_t scounteren;
uint32_t mcounteren;

/* Sscucnt: CPU utilization counter enable */
uint32_t mcpuutilen;
uint32_t scpuutilen;
uint32_t hcpuutilen;

uint32_t scountinhibit;
uint32_t mcountinhibit;

Expand Down
20 changes: 20 additions & 0 deletions target/riscv/cpu_bits.h
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,12 @@
#define CSR_CYCLE 0xc00
#define CSR_TIME 0xc01
#define CSR_INSTRET 0xc02

/* Sscucnt: S/U-mode shadow counters */
#define CSR_CORECYC 0xc30
#define CSR_ACTTIME 0xc31
#define CSR_CORECYCH 0xcb0
#define CSR_ACTTIMEH 0xcb1
#define CSR_HPMCOUNTER3 0xc03
#define CSR_HPMCOUNTER4 0xc04
#define CSR_HPMCOUNTER5 0xc05
Expand Down Expand Up @@ -204,6 +210,7 @@
#define CSR_SIE 0x104
#define CSR_STVEC 0x105
#define CSR_SCOUNTEREN 0x106
#define CSR_SCPUUTILEN 0x120

/* Supervisor Configuration CSRs */
#define CSR_SENVCFG 0x10A
Expand Down Expand Up @@ -269,6 +276,7 @@
#define CSR_HIDELEG 0x603
#define CSR_HIE 0x604
#define CSR_HCOUNTEREN 0x606
#define CSR_HCPUUTILEN 0x620
#define CSR_HGEIE 0x607
#define CSR_HTVAL 0x643
#define CSR_HVIP 0x645
Expand Down Expand Up @@ -443,6 +451,13 @@

/* Machine counter configuration registers */
#define CSR_MCYCLECFG 0x321

/* Sscucnt: CPU Utilization Counter CSRs (addresses TBD, placeholder) */
#define CSR_MCPUUTILEN 0x320
#define CSR_MCORECYC 0xb30
#define CSR_MACTTIME 0xb31
#define CSR_MCORECYCH 0xbb0
#define CSR_MACTTIMEH 0xbb1
#define CSR_MINSTRETCFG 0x322

#define CSR_MHPMEVENT3 0x323
Expand Down Expand Up @@ -1405,3 +1420,8 @@ typedef enum RISCVException {
#define SCONTEXT32 0xFFFF
#define SCONTEXT64 0xFFFFFFFF
#endif

/* Sscucnt enable bits */
#define CPUUTILEN_CORECYC (1U << 0)
#define CPUUTILEN_ACTTIME (1U << 1)
#define CPUUTILEN_ALL (CPUUTILEN_CORECYC | CPUUTILEN_ACTTIME)
1 change: 1 addition & 0 deletions target/riscv/cpu_cfg.h
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,7 @@ struct RISCVCPUConfig {
bool ext_smctr;
bool ext_ssctr;
bool ext_sscofpmf;
bool ext_sscpuutil;
bool ext_smepmp;
bool ext_ssnpm;
bool ext_smnpm;
Expand Down
198 changes: 198 additions & 0 deletions target/riscv/csr.c
Original file line number Diff line number Diff line change
Expand Up @@ -276,6 +276,73 @@ static RISCVException sscofpmf_32(CPURISCVState *env, int csrno)
return sscofpmf(env, csrno);
}

/* Sscucnt extension predicates */
static RISCVException sscpuutil_any(CPURISCVState *env, int csrno)
{
if (!riscv_cpu_cfg(env)->ext_sscpuutil) {
return RISCV_EXCP_ILLEGAL_INST;
}
return RISCV_EXCP_NONE;
}

static RISCVException sscpuutil_any32(CPURISCVState *env, int csrno)
{
if (riscv_cpu_mxl(env) != MXL_RV32) {
return RISCV_EXCP_ILLEGAL_INST;
}
return sscpuutil_any(env, csrno);
}

static RISCVException sscpuutil_ctr(CPURISCVState *env, int csrno)
{
if (!riscv_cpu_cfg(env)->ext_sscpuutil) {
return RISCV_EXCP_ILLEGAL_INST;
}

/* Determine which counter bit to check */
uint32_t ctr_bit;
if (csrno == CSR_CORECYC || csrno == CSR_CORECYCH) {
ctr_bit = CPUUTILEN_CORECYC;
} else {
ctr_bit = CPUUTILEN_ACTTIME;
}

if (env->debugger) {
return RISCV_EXCP_NONE;
}

/* M-mode access control */
if (env->priv < PRV_M && !(env->mcpuutilen & ctr_bit)) {
return RISCV_EXCP_ILLEGAL_INST;
}

/* S-mode -> U-mode access control */
if (riscv_has_ext(env, RVS) && env->priv == PRV_U &&
!(env->scpuutilen & ctr_bit)) {
return RISCV_EXCP_ILLEGAL_INST;
}

/* Virtual mode access control */
if (env->virt_enabled) {
if (!(env->hcpuutilen & ctr_bit)) {
return RISCV_EXCP_VIRT_INSTRUCTION_FAULT;
}
if (env->priv == PRV_U && !(env->scpuutilen & ctr_bit)) {
return RISCV_EXCP_VIRT_INSTRUCTION_FAULT;
}
}

return RISCV_EXCP_NONE;
}

static RISCVException sscpuutil_ctr32(CPURISCVState *env, int csrno)
{
if (riscv_cpu_mxl(env) != MXL_RV32) {
return RISCV_EXCP_ILLEGAL_INST;
}
return sscpuutil_ctr(env, csrno);
}

static RISCVException smcntrpmf(CPURISCVState *env, int csrno)
{
if (!riscv_cpu_cfg(env)->ext_smcntrpmf) {
Expand Down Expand Up @@ -6062,6 +6129,120 @@ static int write_mexstatus(CPURISCVState *env, int csrno, target_ulong val)
env->mexstatus = val;
return RISCV_EXCP_NONE;
}
/*
* Control and Status Register function table
* riscv_csr_operations::predicate() must be provided for an implemented CSR
*/
/* Sscucnt read/write handlers */
static RISCVException read_mcorecyc(CPURISCVState *env, int csrno,
target_ulong *val)
{
/*
* In QEMU, mcorecyc counts host ticks when the vCPU is running.
* WFI halts the vCPU, so ticks naturally pause during idle.
*/
*val = (target_ulong)cpu_get_host_ticks();
return RISCV_EXCP_NONE;
}

static RISCVException read_mcorecych(CPURISCVState *env, int csrno,
target_ulong *val)
{
*val = (target_ulong)(cpu_get_host_ticks() >> 32);
return RISCV_EXCP_NONE;
}

static RISCVException read_macttime(CPURISCVState *env, int csrno,
target_ulong *val)
{
/*
* macttime increments at a fixed reference frequency.
* Use the same time source as the architectural time CSR.
*/
if (env->rdtime_fn) {
*val = (target_ulong)env->rdtime_fn(env->rdtime_fn_arg);
} else {
*val = (target_ulong)cpu_get_host_ticks();
}
return RISCV_EXCP_NONE;
}

static RISCVException read_macttimeh(CPURISCVState *env, int csrno,
target_ulong *val)
{
if (env->rdtime_fn) {
*val = (target_ulong)(env->rdtime_fn(env->rdtime_fn_arg) >> 32);
} else {
*val = (target_ulong)(cpu_get_host_ticks() >> 32);
}
return RISCV_EXCP_NONE;
}

static RISCVException read_mcpuutilen(CPURISCVState *env, int csrno,
target_ulong *val)
{
*val = env->mcpuutilen;
return RISCV_EXCP_NONE;
}

static RISCVException write_mcpuutilen(CPURISCVState *env, int csrno,
target_ulong val)
{
env->mcpuutilen = val & CPUUTILEN_ALL;
return RISCV_EXCP_NONE;
}

static RISCVException read_hcpuutilen(CPURISCVState *env, int csrno,
target_ulong *val)
{
*val = env->hcpuutilen;
return RISCV_EXCP_NONE;
}

static RISCVException write_hcpuutilen(CPURISCVState *env, int csrno,
target_ulong val)
{
env->hcpuutilen = val & CPUUTILEN_ALL;
return RISCV_EXCP_NONE;
}

static RISCVException read_scpuutilen(CPURISCVState *env, int csrno,
target_ulong *val)
{
*val = env->scpuutilen;
return RISCV_EXCP_NONE;
}

static RISCVException write_scpuutilen(CPURISCVState *env, int csrno,
target_ulong val)
{
env->scpuutilen = val & CPUUTILEN_ALL;
return RISCV_EXCP_NONE;
}

static RISCVException read_corecyc(CPURISCVState *env, int csrno,
target_ulong *val)
{
return read_mcorecyc(env, csrno, val);
}

static RISCVException read_corecych(CPURISCVState *env, int csrno,
target_ulong *val)
{
return read_mcorecych(env, csrno, val);
}

static RISCVException read_acttime(CPURISCVState *env, int csrno,
target_ulong *val)
{
return read_macttime(env, csrno, val);
}

static RISCVException read_acttimeh(CPURISCVState *env, int csrno,
target_ulong *val)
{
return read_macttimeh(env, csrno, val);
}

static int read_mdtcmcr(CPURISCVState *env, int csrno, target_ulong *val)
{
Expand Down Expand Up @@ -7260,6 +7441,23 @@ riscv_csr_operations csr_ops[CSR_TABLE_SIZE] = {
write_mcountinhibit,
.min_priv_ver = PRIV_VERSION_1_11_0 },


/* Sscucnt: CPU Utilization Counters */
[CSR_MCORECYC] = { "mcorecyc", sscpuutil_any, read_mcorecyc },
[CSR_MACTTIME] = { "macttime", sscpuutil_any, read_macttime },
[CSR_MCORECYCH] = { "mcorecych", sscpuutil_any32, read_mcorecych },
[CSR_MACTTIMEH] = { "macttimeh", sscpuutil_any32, read_macttimeh },
[CSR_MCPUUTILEN] = { "mcpuutilen", sscpuutil_any, read_mcpuutilen,
write_mcpuutilen },
[CSR_HCPUUTILEN] = { "hcpuutilen", sscpuutil_any, read_hcpuutilen,
write_hcpuutilen },
[CSR_SCPUUTILEN] = { "scpuutilen", sscpuutil_any, read_scpuutilen,
write_scpuutilen },
[CSR_CORECYC] = { "corecyc", sscpuutil_ctr, read_corecyc },
[CSR_ACTTIME] = { "acttime", sscpuutil_ctr, read_acttime },
[CSR_CORECYCH] = { "corecych", sscpuutil_ctr32, read_corecych },
[CSR_ACTTIMEH] = { "acttimeh", sscpuutil_ctr32, read_acttimeh },

[CSR_MCYCLECFG] = { "mcyclecfg", smcntrpmf, read_mcyclecfg,
write_mcyclecfg,
.min_priv_ver = PRIV_VERSION_1_12_0 },
Expand Down