Skip to content

Commit b8ee693

Browse files
nemecadjdupak
authored andcommitted
Machine: propagate xRET type and clear MPRV
Decode MRET/SRET/URET in the decode stage, carry the return type through interstage registers, and pass it to ControlState::exception_return in the memory stage. Mark returns illegal if they request a higher privilege (e.g., MRET in S-mode). When returning from M to a less-privileged mode, clear MPRV per the privileged spec.
1 parent 35f1145 commit b8ee693

File tree

4 files changed

+53
-5
lines changed

4 files changed

+53
-5
lines changed

src/machine/core.cpp

Lines changed: 39 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,33 @@ static InstructionFlags unsupported_inst_flags_to_check(Xlen xlen, ConfigIsaWord
1919
return InstructionFlags(flags_to_check);
2020
}
2121

22+
static CSR::PrivilegeLevel decode_xret_type_from_inst(const Instruction &inst) {
23+
// bits [6:0] = opcode (SYSTEM opcode == 0x73)
24+
// bits [31:20] = funct12 (distinguishes MRET/SRET/URET)
25+
const uint32_t w = inst.data();
26+
const uint32_t OPCODE_MASK = 0x7Fu; // bits 6:0
27+
const uint32_t FUNCT12_SHIFT = 20u; // funct12 starts at bit 20
28+
const uint32_t FUNCT12_MASK = 0xFFFu; // 12 bits
29+
30+
const uint32_t opcode = w & OPCODE_MASK;
31+
if (opcode != 0x73u) { // not a SYSTEM-family instruction
32+
return CSR::PrivilegeLevel::UNPRIVILEGED;
33+
}
34+
35+
const uint32_t funct12 = (w >> FUNCT12_SHIFT) & FUNCT12_MASK;
36+
37+
constexpr uint32_t MRET_FUNCT12 = 0x302u;
38+
constexpr uint32_t SRET_FUNCT12 = 0x102u;
39+
constexpr uint32_t URET_FUNCT12 = 0x002u;
40+
41+
switch (funct12) {
42+
case MRET_FUNCT12: return CSR::PrivilegeLevel::MACHINE; // MRET
43+
case SRET_FUNCT12: return CSR::PrivilegeLevel::SUPERVISOR; // SRET
44+
case URET_FUNCT12: return CSR::PrivilegeLevel::UNPRIVILEGED; // URET
45+
default: return CSR::PrivilegeLevel::UNPRIVILEGED;
46+
}
47+
}
48+
2249
Core::Core(
2350
Registers *regs,
2451
BranchPredictor *predictor,
@@ -316,6 +343,14 @@ DecodeState Core::decode(const FetchInterstage &dt) {
316343
ExceptionCause excause = dt.excause;
317344

318345
dt.inst.flags_alu_op_mem_ctl(flags, alu_op, mem_ctl);
346+
CSR::PrivilegeLevel inst_xret_priv = CSR::PrivilegeLevel::UNPRIVILEGED;
347+
if (flags & IMF_XRET) {
348+
inst_xret_priv = decode_xret_type_from_inst(dt.inst);
349+
// Mark illegal if current privilege is lower than encoded xRET type (e.g. MRET executed in S-mode)
350+
if (state.current_privilege() < inst_xret_priv) {
351+
excause = EXCAUSE_INSN_ILLEGAL;
352+
}
353+
}
319354

320355
if ((flags ^ check_inst_flags_val) & check_inst_flags_mask) { excause = EXCAUSE_INSN_ILLEGAL; }
321356

@@ -392,6 +427,7 @@ DecodeState Core::decode(const FetchInterstage &dt) {
392427
.csr_to_alu = bool(flags & IMF_CSR_TO_ALU),
393428
.csr_write = csr_write,
394429
.xret = bool(flags & IMF_XRET),
430+
.xret_privlev = inst_xret_priv,
395431
.insert_stall_before = bool(flags & IMF_CSR) } };
396432
}
397433

@@ -462,6 +498,7 @@ ExecuteState Core::execute(const DecodeInterstage &dt) {
462498
.csr = dt.csr,
463499
.csr_write = dt.csr_write,
464500
.xret = dt.xret,
501+
.xret_privlev = dt.xret_privlev,
465502
} };
466503
}
467504

@@ -527,7 +564,7 @@ MemoryState Core::memory(const ExecuteInterstage &dt) {
527564
}
528565
if (dt.xret) {
529566
CSR::PrivilegeLevel restored
530-
= control_state->exception_return(state.current_privilege());
567+
= control_state->exception_return(state.current_privilege(), dt.xret_privlev);
531568
state.set_current_privilege(restored);
532569
if (auto prog_tlb = dynamic_cast<TLB *>(mem_program)) {
533570
prog_tlb->on_privilege_changed(restored);
@@ -583,6 +620,7 @@ MemoryState Core::memory(const ExecuteInterstage &dt) {
583620
.regwrite = regwrite,
584621
.is_valid = dt.is_valid,
585622
.csr_written = csr_written,
623+
.xret_privlev = dt.xret_privlev,
586624
} };
587625
}
588626

src/machine/csr/controlstate.cpp

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -190,11 +190,11 @@ namespace machine { namespace CSR {
190190
emit write_signal(reg_id, reg);
191191
}
192192

193-
PrivilegeLevel ControlState::exception_return(enum PrivilegeLevel act_privlev) {
193+
PrivilegeLevel ControlState::exception_return(enum PrivilegeLevel act_privlev, enum PrivilegeLevel xret_privlev) {
194194
size_t reg_id = Id::MSTATUS;
195195
RegisterValue &reg = register_data[reg_id];
196196
PrivilegeLevel restored_privlev = PrivilegeLevel::MACHINE;
197-
if (act_privlev == PrivilegeLevel::MACHINE) {
197+
if (xret_privlev == PrivilegeLevel::MACHINE) {
198198
// MRET semantics:
199199
// MIE <- MPIE
200200
// MPIE <- 1
@@ -212,7 +212,7 @@ namespace machine { namespace CSR {
212212
default: restored_privlev = PrivilegeLevel::UNPRIVILEGED; break;
213213
}
214214
write_field(Field::mstatus::MPP, (uint64_t)0); // clear MPP per spec
215-
} else if (act_privlev == PrivilegeLevel::SUPERVISOR) {
215+
} else if (xret_privlev == PrivilegeLevel::SUPERVISOR) {
216216
// SRET semantics:
217217
// SIE <- SPIE
218218
// SPIE <- 1
@@ -229,6 +229,12 @@ namespace machine { namespace CSR {
229229
restored_privlev = PrivilegeLevel::UNPRIVILEGED;
230230
}
231231

232+
// If the instruction was executed in M-mode and the restored privilege is less-privileged
233+
// than M, clear MPRV per the privileged spec.
234+
if (act_privlev == PrivilegeLevel::MACHINE && restored_privlev != PrivilegeLevel::MACHINE) {
235+
write_field(Field::mstatus::MPRV, (uint64_t)0);
236+
}
237+
232238
emit write_signal(reg_id, reg);
233239

234240
return restored_privlev;

src/machine/csr/controlstate.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -150,7 +150,7 @@ namespace machine { namespace CSR {
150150
public slots:
151151
void set_interrupt_signal(uint irq_num, bool active);
152152
void exception_initiate(PrivilegeLevel act_privlev, PrivilegeLevel to_privlev);
153-
PrivilegeLevel exception_return(enum PrivilegeLevel act_privlev);
153+
PrivilegeLevel exception_return(enum PrivilegeLevel act_privlev, enum PrivilegeLevel xret_privlev);
154154

155155
private:
156156
static size_t get_register_internal_id(Address address);
@@ -211,6 +211,7 @@ namespace machine { namespace CSR {
211211
static constexpr RegisterFieldDesc MIE = { "MIE", Id::MSTATUS, {1, 3}, "Machine global interrupt-enable"};
212212
static constexpr RegisterFieldDesc SPIE = { "SPIE", Id::MSTATUS, {1, 5}, "Previous SIE before the trap"};
213213
static constexpr RegisterFieldDesc MPIE = { "MPIE", Id::MSTATUS, {1, 7}, "Previous MIE before the trap"};
214+
static constexpr RegisterFieldDesc MPRV = { "MPRV", Id::MSTATUS, {1, 17}, "Modify privilege for loads/stores/fetches" };
214215
static constexpr RegisterFieldDesc SPP = { "SPP", Id::MSTATUS, {1, 8}, "System previous privilege mode"};
215216
static constexpr RegisterFieldDesc MPP = { "MPP", Id::MSTATUS, {2, 11}, "Machine previous privilege mode"};
216217
static constexpr RegisterFieldDesc UXL = { "UXL", Id::MSTATUS, {2, 32}, "User mode XLEN (RV64 only)"};

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)