Skip to content

Commit 3238c4f

Browse files
committed
Machine: add CSR privilege checks in ControlState::read/write
Add a caller-privilege parameter to ControlState::read/write and implement csr_min_privilege_from_addr() that extracts the CSR access field (csr[11:8]) to determine minimum privilege.
1 parent f0d244b commit 3238c4f

File tree

3 files changed

+28
-6
lines changed

3 files changed

+28
-6
lines changed

src/machine/core.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -367,7 +367,7 @@ DecodeState Core::decode(const FetchInterstage &dt) {
367367

368368
CSR::Address csr_address = (flags & IMF_CSR) ? dt.inst.csr_address() : CSR::Address(0);
369369
RegisterValue csr_read_val
370-
= ((control_state != nullptr && (flags & IMF_CSR))) ? control_state->read(csr_address) : 0;
370+
= ((control_state != nullptr && (flags & IMF_CSR))) ? control_state->read(csr_address, state.current_privilege()) : 0;
371371
bool csr_write = (flags & IMF_CSR) && (!(flags & IMF_CSR_TO_ALU) || (num_rs != 0));
372372

373373
if ((flags & IMF_EXCEPTION) && (excause == EXCAUSE_NONE)) {
@@ -559,7 +559,7 @@ MemoryState Core::memory(const ExecuteInterstage &dt) {
559559
if (control_state != nullptr && dt.is_valid && dt.excause == EXCAUSE_NONE) {
560560
control_state->increment_internal(CSR::Id::MINSTRET, 1);
561561
if (dt.csr_write) {
562-
control_state->write(dt.csr_address, dt.alu_val);
562+
control_state->write(dt.csr_address, dt.alu_val, state.current_privilege());
563563
csr_written = true;
564564
}
565565
if (dt.xret) {

src/machine/csr/controlstate.cpp

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,18 @@ LOG_CATEGORY("machine.csr.control_state");
1111

1212
namespace machine { namespace CSR {
1313

14+
static CSR::PrivilegeLevel csr_min_privilege_from_addr(const Address &addr) {
15+
uint32_t csr = addr.data & 0xfffu; // csr[11:0]
16+
uint32_t min_bits = (csr >> 8) & 0x3; // csr[9:8] per spec
17+
switch (min_bits) {
18+
case 0u: return PrivilegeLevel::UNPRIVILEGED;
19+
case 1u: return PrivilegeLevel::SUPERVISOR;
20+
case 2u: return PrivilegeLevel::HYPERVISOR;
21+
case 3u: return PrivilegeLevel::MACHINE;
22+
default: return PrivilegeLevel::MACHINE;
23+
}
24+
}
25+
1426
ControlState::ControlState(Xlen xlen, ConfigIsaWord isa_word) : xlen(xlen) {
1527
reset();
1628
uint64_t misa = read_internal(CSR::Id::MISA).as_u64();
@@ -55,19 +67,29 @@ namespace machine { namespace CSR {
5567
}
5668
}
5769

58-
RegisterValue ControlState::read(Address address) const {
70+
RegisterValue ControlState::read(Address address, PrivilegeLevel current_privilege) const {
5971
// Only machine level privilege is supported so no checking is needed.
6072
size_t reg_id = get_register_internal_id(address);
73+
if (PrivilegeLevel min_priv = csr_min_privilege_from_addr(address); current_privilege < min_priv) {
74+
throw SIMULATOR_EXCEPTION(
75+
UnsupportedInstruction,
76+
QString("CSR %1 inaccessible at current privilege level").arg(address.data), "");
77+
}
6178
RegisterValue value = register_data[reg_id];
6279
DEBUG("Read CSR[%u] == 0x%" PRIx64, address.data, value.as_u64());
6380
emit read_signal(reg_id, value);
6481
return value;
6582
}
6683

67-
void ControlState::write(Address address, RegisterValue value) {
84+
void ControlState::write(Address address, RegisterValue value, PrivilegeLevel current_privilege) {
6885
DEBUG(
6986
"Write CSR[%u/%zu] <== 0x%zu", address.data, get_register_internal_id(address),
7087
value.as_u64());
88+
if (PrivilegeLevel min_priv = csr_min_privilege_from_addr(address); current_privilege < min_priv) {
89+
throw SIMULATOR_EXCEPTION(
90+
UnsupportedInstruction,
91+
QString("CSR %1 inaccessible at current privilege level").arg(address.data), "");
92+
}
7193
// Attempts to write a read-only register also raise illegal instruction exceptions.
7294
if (!address.is_writable()) {
7395
throw SIMULATOR_EXCEPTION(

src/machine/csr/controlstate.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,7 @@ namespace machine { namespace CSR {
9999
ControlState(const ControlState &);
100100

101101
/** Read CSR register with ISA specified address. */
102-
[[nodiscard]] RegisterValue read(Address address) const;
102+
[[nodiscard]] RegisterValue read(Address address, PrivilegeLevel current_privilege) const;
103103

104104
/**
105105
* Read CSR register with an internal id.
@@ -110,7 +110,7 @@ namespace machine { namespace CSR {
110110
[[nodiscard]] RegisterValue read_internal(size_t internal_id) const;
111111

112112
/** Write value to CSR register by ISA specified address and receive the previous value. */
113-
void write(Address address, RegisterValue value);
113+
void write(Address address, RegisterValue value, PrivilegeLevel current_privilege);
114114

115115
/** Used for writes occurring as a side-effect (instruction count update...) and
116116
* internally by the write method. */

0 commit comments

Comments
 (0)