Skip to content

Commit 0bcbd39

Browse files
nemecadjdupak
authored andcommitted
Machine: propagate xRET type, add privilege illegal instruction checks
Decode MRET/SRET/URET in the decode stage, carry the return type through the interstage registers, and pass it to ControlState::exception_return in the memory stage. Extend instruction metadata with privilege flags (IMF_PRIV_M/H/S) for privileged operations and use them for masking.
1 parent a72df9a commit 0bcbd39

File tree

8 files changed

+85
-18
lines changed

8 files changed

+85
-18
lines changed

src/machine/core.cpp

Lines changed: 36 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,21 @@ Xlen Core::get_xlen() const {
127127

128128
void Core::set_current_privilege(CSR::PrivilegeLevel privilege) {
129129
state.set_current_privilege(privilege);
130+
const unsigned PRIV_BITS = unsigned(IMF_PRIV_M) | unsigned(IMF_PRIV_H) | unsigned(IMF_PRIV_S);
131+
132+
InstructionFlags base_mask = InstructionFlags(unsigned(check_inst_flags_mask) & ~PRIV_BITS);
133+
InstructionFlags base_val = InstructionFlags(unsigned(check_inst_flags_val) & ~PRIV_BITS);
134+
135+
unsigned allowed_priv = 0;
136+
if (privilege >= CSR::PrivilegeLevel::SUPERVISOR) { allowed_priv |= unsigned(IMF_PRIV_S); }
137+
if (privilege >= CSR::PrivilegeLevel::HYPERVISOR) { allowed_priv |= unsigned(IMF_PRIV_H); }
138+
if (privilege >= CSR::PrivilegeLevel::MACHINE) { allowed_priv |= unsigned(IMF_PRIV_M); }
139+
unsigned disallowed_priv = (PRIV_BITS & ~allowed_priv);
140+
InstructionFlags new_mask = InstructionFlags(unsigned(base_mask) | disallowed_priv);
141+
InstructionFlags new_val = base_val;
142+
143+
check_inst_flags_mask = new_mask;
144+
check_inst_flags_val = new_val;
130145
}
131146

132147
CSR::PrivilegeLevel Core::get_current_privilege() const {
@@ -317,7 +332,18 @@ DecodeState Core::decode(const FetchInterstage &dt) {
317332
ExceptionCause excause = dt.excause;
318333

319334
dt.inst.flags_alu_op_mem_ctl(flags, alu_op, mem_ctl);
320-
335+
CSR::PrivilegeLevel inst_xret_priv = CSR::PrivilegeLevel::UNPRIVILEGED;
336+
if (flags & IMF_XRET) {
337+
if (flags & IMF_PRIV_M) {
338+
inst_xret_priv = CSR::PrivilegeLevel::MACHINE;
339+
} else if (flags & IMF_PRIV_H) {
340+
inst_xret_priv = CSR::PrivilegeLevel::HYPERVISOR;
341+
} else if (flags & IMF_PRIV_S) {
342+
inst_xret_priv = CSR::PrivilegeLevel::SUPERVISOR;
343+
} else {
344+
inst_xret_priv = CSR::PrivilegeLevel::UNPRIVILEGED;
345+
}
346+
}
321347
if ((flags ^ check_inst_flags_val) & check_inst_flags_mask) { excause = EXCAUSE_INSN_ILLEGAL; }
322348

323349
RegisterId num_rs = (flags & (IMF_ALU_REQ_RS | IMF_ALU_RS_ID)) ? dt.inst.rs() : 0;
@@ -332,8 +358,9 @@ DecodeState Core::decode(const FetchInterstage &dt) {
332358
const bool regwrite = flags & IMF_REGWRITE;
333359

334360
CSR::Address csr_address = (flags & IMF_CSR) ? dt.inst.csr_address() : CSR::Address(0);
335-
RegisterValue csr_read_val
336-
= ((control_state != nullptr && (flags & IMF_CSR))) ? control_state->read(csr_address) : 0;
361+
RegisterValue csr_read_val = ((control_state != nullptr && (flags & IMF_CSR)))
362+
? control_state->read(csr_address, get_current_privilege())
363+
: 0;
337364
bool csr_write = (flags & IMF_CSR) && (!(flags & IMF_CSR_TO_ALU) || (num_rs != 0));
338365

339366
if ((flags & IMF_EXCEPTION) && (excause == EXCAUSE_NONE)) {
@@ -393,6 +420,7 @@ DecodeState Core::decode(const FetchInterstage &dt) {
393420
.csr_to_alu = bool(flags & IMF_CSR_TO_ALU),
394421
.csr_write = csr_write,
395422
.xret = bool(flags & IMF_XRET),
423+
.xret_privlev = inst_xret_priv,
396424
.insert_stall_before = bool(flags & IMF_CSR) } };
397425
}
398426

@@ -463,6 +491,7 @@ ExecuteState Core::execute(const DecodeInterstage &dt) {
463491
.csr = dt.csr,
464492
.csr_write = dt.csr_write,
465493
.xret = dt.xret,
494+
.xret_privlev = dt.xret_privlev,
466495
} };
467496
}
468497

@@ -523,11 +552,12 @@ MemoryState Core::memory(const ExecuteInterstage &dt) {
523552
if (control_state != nullptr && dt.is_valid && dt.excause == EXCAUSE_NONE) {
524553
control_state->increment_internal(CSR::Id::MINSTRET, 1);
525554
if (dt.csr_write) {
526-
control_state->write(dt.csr_address, dt.alu_val);
555+
control_state->write(dt.csr_address, dt.alu_val, get_current_privilege());
527556
csr_written = true;
528557
}
529558
if (dt.xret) {
530-
CSR::PrivilegeLevel restored = control_state->exception_return(get_current_privilege());
559+
CSR::PrivilegeLevel restored
560+
= control_state->exception_return(get_current_privilege(), dt.xret_privlev);
531561
set_current_privilege(restored);
532562
if (this->xlen == Xlen::_32)
533563
computed_next_inst_addr
@@ -577,6 +607,7 @@ MemoryState Core::memory(const ExecuteInterstage &dt) {
577607
.regwrite = regwrite,
578608
.is_valid = dt.is_valid,
579609
.csr_written = csr_written,
610+
.xret_privlev = dt.xret_privlev,
580611
} };
581612
}
582613

src/machine/core.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -116,8 +116,8 @@ class Core : public QObject {
116116
Address mem_ref_addr);
117117

118118
const Xlen xlen;
119-
const InstructionFlags check_inst_flags_val;
120-
const InstructionFlags check_inst_flags_mask;
119+
InstructionFlags check_inst_flags_val;
120+
InstructionFlags check_inst_flags_mask;
121121
BORROWED Registers *const regs;
122122
BORROWED CSR::ControlState *const control_state;
123123
BORROWED BranchPredictor *const predictor;

src/machine/csr/controlstate.cpp

Lines changed: 30 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -55,16 +55,23 @@ namespace machine { namespace CSR {
5555
}
5656
}
5757

58-
RegisterValue ControlState::read(Address address) const {
59-
// Only machine level privilege is supported so no checking is needed.
58+
RegisterValue ControlState::read(Address address, PrivilegeLevel current_priv) const {
6059
size_t reg_id = get_register_internal_id(address);
60+
PrivilegeLevel required = address.get_privilege_level();
61+
if (current_priv < required) {
62+
throw SIMULATOR_EXCEPTION(
63+
UnsupportedInstruction,
64+
QString("CSR address %1 not accessible at current privilege level.")
65+
.arg(address.data),
66+
"");
67+
}
6168
RegisterValue value = register_data[reg_id];
6269
DEBUG("Read CSR[%u] == 0x%" PRIx64, address.data, value.as_u64());
6370
emit read_signal(reg_id, value);
6471
return value;
6572
}
6673

67-
void ControlState::write(Address address, RegisterValue value) {
74+
void ControlState::write(Address address, RegisterValue value, PrivilegeLevel current_priv) {
6875
DEBUG(
6976
"Write CSR[%u/%zu] <== 0x%zu", address.data, get_register_internal_id(address),
7077
value.as_u64());
@@ -74,6 +81,15 @@ namespace machine { namespace CSR {
7481
UnsupportedInstruction,
7582
QString("CSR address %1 is not writable.").arg(address.data), "");
7683
}
84+
85+
PrivilegeLevel required = address.get_privilege_level();
86+
if (current_priv < required) {
87+
throw SIMULATOR_EXCEPTION(
88+
UnsupportedInstruction,
89+
QString("CSR address %1 not writable at current privilege level.").arg(address.data),
90+
"");
91+
}
92+
7793
write_internal(get_register_internal_id(address), value);
7894
}
7995

@@ -190,11 +206,13 @@ namespace machine { namespace CSR {
190206
emit write_signal(reg_id, reg);
191207
}
192208

193-
PrivilegeLevel ControlState::exception_return(enum PrivilegeLevel act_privlev) {
209+
PrivilegeLevel ControlState::exception_return(
210+
enum PrivilegeLevel act_privlev,
211+
enum PrivilegeLevel xret_privlev) {
194212
size_t reg_id = Id::MSTATUS;
195213
RegisterValue &reg = register_data[reg_id];
196214
PrivilegeLevel restored_privlev = PrivilegeLevel::MACHINE;
197-
if (act_privlev == PrivilegeLevel::MACHINE) {
215+
if (xret_privlev == PrivilegeLevel::MACHINE) {
198216
// MRET semantics:
199217
// MIE <- MPIE
200218
// MPIE <- 1
@@ -212,7 +230,7 @@ namespace machine { namespace CSR {
212230
default: restored_privlev = PrivilegeLevel::UNPRIVILEGED; break;
213231
}
214232
write_field(Field::mstatus::MPP, (uint64_t)0); // clear MPP per spec
215-
} else if (act_privlev == PrivilegeLevel::SUPERVISOR) {
233+
} else if (xret_privlev == PrivilegeLevel::SUPERVISOR) {
216234
// SRET semantics:
217235
// SIE <- SPIE
218236
// SPIE <- 1
@@ -229,6 +247,12 @@ namespace machine { namespace CSR {
229247
restored_privlev = PrivilegeLevel::UNPRIVILEGED;
230248
}
231249

250+
// If the instruction was executed in M-mode and the restored privilege is less-privileged
251+
// than M, clear MPRV per the privileged spec.
252+
if (act_privlev == PrivilegeLevel::MACHINE && restored_privlev != PrivilegeLevel::MACHINE) {
253+
write_field(Field::mstatus::MPRV, (uint64_t)0);
254+
}
255+
232256
emit write_signal(reg_id, reg);
233257

234258
return restored_privlev;

src/machine/csr/controlstate.h

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@ namespace machine { namespace CSR {
9393
ControlState(const ControlState &);
9494

9595
/** Read CSR register with ISA specified address. */
96-
[[nodiscard]] RegisterValue read(Address address) const;
96+
[[nodiscard]] RegisterValue read(Address address, PrivilegeLevel current_priv) const;
9797

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

106106
/** Write value to CSR register by ISA specified address and receive the previous value. */
107-
void write(Address address, RegisterValue value);
107+
void write(Address address, RegisterValue value, PrivilegeLevel current_priv);
108108

109109
/** Used for writes occurring as a side-effect (instruction count update...) and
110110
* internally by the write method. */
@@ -144,7 +144,8 @@ namespace machine { namespace CSR {
144144
public slots:
145145
void set_interrupt_signal(uint irq_num, bool active);
146146
void exception_initiate(PrivilegeLevel act_privlev, PrivilegeLevel to_privlev);
147-
PrivilegeLevel exception_return(enum PrivilegeLevel act_privlev);
147+
PrivilegeLevel
148+
exception_return(enum PrivilegeLevel act_privlev, enum PrivilegeLevel xret_privlev);
148149

149150
private:
150151
static size_t get_register_internal_id(Address address);
@@ -201,6 +202,8 @@ namespace machine { namespace CSR {
201202
= { "SPIE", Id::MSTATUS, { 1, 5 }, "Previous SIE before the trap" };
202203
static constexpr RegisterFieldDesc MPIE
203204
= { "MPIE", Id::MSTATUS, { 1, 7 }, "Previous MIE before the trap" };
205+
static constexpr RegisterFieldDesc MPRV
206+
= { "MPRV", Id::MSTATUS, { 1, 17 }, "Modify privilege for loads/stores/fetches" };
204207
static constexpr RegisterFieldDesc SPP
205208
= { "SPP", Id::MSTATUS, { 1, 8 }, "System previous privilege mode" };
206209
static constexpr RegisterFieldDesc MPP

src/machine/instruction.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -464,7 +464,7 @@ static const struct InstructionMap SYSTEM_PRIV_map[] = {
464464
IM_UNKNOWN,
465465
IM_UNKNOWN,
466466
IM_UNKNOWN,
467-
{"sret", IT_I, NOALU, NOMEM, nullptr, {}, 0x10200073, 0xffffffff, { .flags = IMF_SUPPORTED | IMF_XRET }, nullptr},
467+
{"sret", IT_I, NOALU, NOMEM, nullptr, {}, 0x10200073, 0xffffffff, { .flags = IMF_SUPPORTED | IMF_XRET | IMF_PRIV_S }, nullptr},
468468
IM_UNKNOWN,
469469
IM_UNKNOWN,
470470
IM_UNKNOWN,
@@ -480,7 +480,7 @@ static const struct InstructionMap SYSTEM_PRIV_map[] = {
480480
IM_UNKNOWN,
481481
IM_UNKNOWN,
482482
IM_UNKNOWN,
483-
{"mret", IT_I, NOALU, NOMEM, nullptr, {}, 0x30200073, 0xffffffff, { .flags = IMF_SUPPORTED | IMF_XRET }, nullptr},
483+
{"mret", IT_I, NOALU, NOMEM, nullptr, {}, 0x30200073, 0xffffffff, { .flags = IMF_SUPPORTED | IMF_XRET | IMF_PRIV_M }, nullptr},
484484
IM_UNKNOWN,
485485
IM_UNKNOWN,
486486
IM_UNKNOWN,

src/machine/instruction.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,11 @@ enum InstructionFlags : unsigned {
6060
// TODO do we want to add those signals to the visualization?
6161

6262
IMF_RV64 = 1L << 24, /**< Mark instructions which are available in 64-bit mode only. */
63+
64+
/* Privilege requirement flags */
65+
IMF_PRIV_S = 1L << 25, /**< Requires at least Supervisor privilege */
66+
IMF_PRIV_H = 1L << 26, /**< Requires at least Hypervisor privilege */
67+
IMF_PRIV_M = 1L << 27, /**< Requires Machine privilege */
6368
};
6469

6570
/**

src/machine/memory/frontend_memory.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
#define FRONTEND_MEMORY_H
33

44
#include "common/endian.h"
5+
#include "csr/address.h"
56
#include "machinedefs.h"
67
#include "memory/address.h"
78
#include "memory/memory_utils.h"

src/machine/pipeline.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,7 @@ struct DecodeInterstage {
117117
bool csr_to_alu = false;
118118
bool csr_write = false;
119119
bool xret = false; // Return from exception, MRET and SRET
120+
CSR::PrivilegeLevel xret_privlev = CSR::PrivilegeLevel::UNPRIVILEGED;
120121
bool insert_stall_before = false;
121122

122123
public:
@@ -179,6 +180,7 @@ struct ExecuteInterstage {
179180
bool csr = false;
180181
bool csr_write = false;
181182
bool xret = false;
183+
CSR::PrivilegeLevel xret_privlev = CSR::PrivilegeLevel::UNPRIVILEGED;
182184

183185
public:
184186
/** Reset to value corresponding to NOP. */
@@ -245,6 +247,7 @@ struct MemoryInterstage {
245247
bool regwrite = false;
246248
bool is_valid = false;
247249
bool csr_written = false;
250+
CSR::PrivilegeLevel xret_privlev = CSR::PrivilegeLevel::UNPRIVILEGED;
248251

249252
public:
250253
/** Reset to value corresponding to NOP. */

0 commit comments

Comments
 (0)