Skip to content

Commit 462d7bf

Browse files
committed
Add Smpmpind Smcfiss Smucfiss
1 parent efdaa08 commit 462d7bf

File tree

11 files changed

+213
-55
lines changed

11 files changed

+213
-55
lines changed

disasm/isa_parser.cc

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -247,14 +247,20 @@ isa_parser_t::isa_parser_t(const char* str, const char *priv)
247247
} else if (ext_str == "zkr") {
248248
extension_table[EXT_ZKR] = true;
249249
} else if (ext_str == "zkt") {
250+
} else if (ext_str == "smcfiss") {
251+
extension_table[EXT_SMCFISS] = true;
250252
} else if (ext_str == "smepmp") {
251253
extension_table[EXT_SMEPMP] = true;
252254
} else if (ext_str == "smstateen") {
253255
extension_table[EXT_SMSTATEEN] = true;
256+
} else if (ext_str == "smpmpind") {
257+
extension_table[EXT_SMPMPIND] = true;
254258
} else if (ext_str == "smpmpmt") {
255259
extension_table[EXT_SMPMPMT] = true;
256260
} else if (ext_str == "smrnmi") {
257261
extension_table[EXT_SMRNMI] = true;
262+
} else if (ext_str == "smucfiss") {
263+
extension_table[EXT_SMUCFISS] = true;
258264
} else if (ext_str == "sscofpmf") {
259265
extension_table[EXT_SSCOFPMF] = true;
260266
} else if (ext_str == "svadu") {
@@ -562,6 +568,15 @@ isa_parser_t::isa_parser_t(const char* str, const char *priv)
562568
!extension_table[EXT_ZCMOP]) {
563569
bad_isa_string(str, "'Zicfiss' extension requires 'Zcmop' extension when `Zca` is supported");
564570
}
571+
if (extension_table[EXT_SMCFISS] && !extension_table[EXT_ZICFISS]) {
572+
bad_isa_string(str, "'Smcfiss' extension requires 'Zicfiss'");
573+
}
574+
if (extension_table[EXT_SMCFISS] && !extension_table[EXT_SMPMPIND]) {
575+
bad_isa_string(str, "'Smcfiss' extension requires 'Smpmpind'");
576+
}
577+
if (extension_table[EXT_SMUCFISS] && !extension_table[EXT_SMCFISS]) {
578+
bad_isa_string(str, "'Smucfiss' extension requires 'Smcfiss'");
579+
}
565580
#ifdef WORDS_BIGENDIAN
566581
// Access to the vector registers as element groups is unimplemented on big-endian setups.
567582
if (extension_table[EXT_ZVKG] || extension_table[EXT_ZVKNHA] || extension_table[EXT_ZVKNHB] ||
@@ -607,6 +622,10 @@ isa_parser_t::isa_parser_t(const char* str, const char *priv)
607622
extension_table['U'] = user;
608623
extension_table['S'] = supervisor;
609624

625+
if (extension_table[EXT_SMUCFISS] && (extension_table['S'] || !extension_table['U'])) {
626+
bad_isa_string(str, "'Smucfiss' extension is only supported for M+U systems");
627+
}
628+
610629
if (extension_table['H'] && !supervisor)
611630
bad_isa_string(str, "'H' extension requires S mode");
612631

riscv/csr_init.cc

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -441,13 +441,29 @@ void state_t::csr_init(processor_t* const proc, reg_t max_isa)
441441
csr_t_p miselect = std::make_shared<basic_csr_t>(proc, CSR_MISELECT, 0);
442442
add_csr(CSR_MISELECT, miselect);
443443

444-
sscsrind_reg_csr_t::sscsrind_reg_csr_t_p mireg;
444+
sscsrind_reg_csr_t::sscsrind_reg_csr_t_p mireg, mireg2;
445445
add_csr(CSR_MIREG, mireg = std::make_shared<sscsrind_reg_csr_t>(proc, CSR_MIREG, miselect));
446446
if (proc->extension_enabled_const(EXT_SMAIA))
447447
add_iprio_proxy(proc, mireg);
448-
const reg_t mireg_csrs[] = { CSR_MIREG2, CSR_MIREG3, CSR_MIREG4, CSR_MIREG5, CSR_MIREG6 };
448+
add_csr(CSR_MIREG2, mireg2 = std::make_shared<sscsrind_reg_csr_t>(proc, CSR_MIREG2, miselect));
449+
const reg_t mireg_csrs[] = { CSR_MIREG3, CSR_MIREG4, CSR_MIREG5, CSR_MIREG6 };
449450
for (auto csr : mireg_csrs)
450451
add_csr(csr, std::make_shared<sscsrind_reg_csr_t>(proc, csr, miselect));
452+
453+
if (proc->extension_enabled_const(EXT_SMPMPIND)) {
454+
// For indirect access to PMP registers, `miselect` selects the target PMP
455+
// entry; `mireg` accesses its `pmpaddr` register, and `mireg2` accesses its
456+
// `pmpcfg` register. Attempts to access `mireg3` through `mireg6` raise an
457+
// illegal instruction exception.
458+
// The mireg2 (mireg_csrs[0]) proxies to ind_pmpcfg_csr_t objects as there
459+
// is no direct proxy for these registers. In the ind_pmpcfg_csr_t object,
460+
// the address member holds the entry number (i).
461+
for (int i = 0; i < max_pmp; ++i) {
462+
mireg->add_ireg_proxy(MISELECT_PMPIND_START + i, pmpaddr[i]);
463+
auto ind_pmpcfg = std::make_shared<ind_pmpcfg_csr_t>(proc, i);
464+
mireg2->add_ireg_proxy(MISELECT_PMPIND_START + i, ind_pmpcfg);
465+
}
466+
}
451467
}
452468

453469
if (proc->extension_enabled_const(EXT_SSCSRIND)) {

riscv/csrs.cc

Lines changed: 107 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -182,17 +182,43 @@ bool pmpaddr_csr_t::subset_match(reg_t addr, reg_t len) const noexcept {
182182
return !(is_tor ? tor_homogeneous : napot_homogeneous);
183183
}
184184

185-
bool pmpaddr_csr_t::access_ok(access_type type, reg_t mode, bool hlvx) const noexcept {
185+
bool pmpaddr_csr_t::access_ok(access_type type, reg_t mode, bool hlvx, bool ss_access) const noexcept {
186+
const uint8_t xwr = cfg & (PMP_X | PMP_W | PMP_R);
186187
const bool cfgx = cfg & PMP_X;
187188
const bool cfgw = cfg & PMP_W;
188189
const bool cfgr = cfg & PMP_R;
189190
const bool cfgl = cfg & PMP_L;
190-
191-
const bool prvm = mode == PRV_M;
192-
193191
const bool typer = type == LOAD;
194192
const bool typex = type == FETCH;
195193
const bool typew = type == STORE;
194+
const bool prvm = mode == PRV_M;
195+
const bool prvu = mode == PRV_U;
196+
const bool msse = state->mseccfg->get_msse();
197+
const bool usse = ((state->menvcfg->read() & MENVCFG_SSE) != 0) &&
198+
proc->extension_enabled(EXT_SMUCFISS);
199+
const bool is_m_ss_rgn = E && (xwr == PMP_W) && msse;
200+
const bool is_u_ss_rgn = E && (xwr == (PMP_W | PMP_X)) && usse;
201+
/*
202+
* Shadow-stack access rules (Smcfiss / Smucfiss):
203+
* - Shadow-stack accesses with effective privilege mode M are permitted
204+
* only when accessing an M-mode shadow-stack region. Loads with effective
205+
* privilege mode M are permitted to read an M-mode shadow-stack region.
206+
* - When Smucfiss is implemented, shadow-stack accesses with effective
207+
* privilege mode U are permitted only when accessing a U-mode shadow-stack
208+
* region. Loads with effective privilege mode U are permitted to read a
209+
* U-mode shadow-stack region.
210+
* - All other accesses (stores, instruction fetches, or accesses from an
211+
* incorrect privilege mode) to M-mode or U-mode shadow-stack regions are
212+
* disallowed.
213+
* - When E = 1 and the PMP entry does not denote a valid shadow-stack
214+
* region, all accesses are disallowed.
215+
*/
216+
if (ss_access && prvm) return is_m_ss_rgn;
217+
if (ss_access && prvu && proc->extension_enabled(EXT_SMUCFISS)) return is_u_ss_rgn;
218+
if (is_m_ss_rgn) return prvm && typer && !hlvx;
219+
if (is_u_ss_rgn) return prvu && typer && !hlvx;
220+
if (E) return false;
221+
196222
const bool normal_rwx = (typer && cfgr && (!hlvx || cfgx)) || (typew && cfgw) || (typex && cfgx);
197223
const bool mseccfg_mml = state->mseccfg->get_mml();
198224

@@ -238,54 +264,90 @@ reg_t pmpcfg_csr_t::read() const noexcept {
238264
return cfg_res;
239265
}
240266

267+
void pmpcfg_csr_t::update_pmpcfg_entry(const size_t index, const uint8_t cfg_in, const bool E) {
268+
const bool locked = (state->pmpaddr[index]->cfg & PMP_L);
269+
const bool rlb = state->mseccfg->get_rlb();
270+
const bool mml = state->mseccfg->get_mml();
271+
uint8_t cfg = cfg_in;
272+
if (rlb || !locked) {
273+
// Drop R=0 W=1 when MML = 0
274+
// Remove the restriction when MML = 1 or, when E=1
275+
if (!mml && !E) {
276+
cfg &= ~PMP_W | ((cfg & PMP_R) ? PMP_W : 0);
277+
}
278+
// Disallow A=NA4 when granularity > 4
279+
if (proc->lg_pmp_granularity != PMP_SHIFT && (cfg & PMP_A) == PMP_NA4)
280+
cfg |= PMP_NAPOT;
281+
// MT value 0x3 is reserved
282+
if (get_field(cfg, PMP_MT) == 0x3)
283+
cfg = set_field(cfg, PMP_MT, 0);
284+
/*
285+
* Adding a rule with executable privileges that either is M-mode-only or a locked Shared-Region
286+
* is not possible and such pmpcfg writes are ignored, leaving pmpcfg unchanged.
287+
* This restriction can be temporarily lifted e.g. during the boot process, by setting mseccfg.RLB.
288+
*/
289+
const bool cfgx = cfg & PMP_X;
290+
const bool cfgw = cfg & PMP_W;
291+
const bool cfgr = cfg & PMP_R;
292+
if (rlb || !(mml && ((cfg & PMP_L) // M-mode-only or a locked Shared-Region
293+
&& !(cfgx && cfgw && cfgr) // RWX = 111 is allowed
294+
&& (cfgx || (cfgw && !cfgr)) // X=1 or RW=01 is not allowed
295+
&& !E // Only apply this restruction when E=0
296+
))) {
297+
state->pmpaddr[index]->cfg = cfg;
298+
state->pmpaddr[index]->E = E;
299+
}
300+
}
301+
return;
302+
}
303+
241304
bool pmpcfg_csr_t::unlogged_write(const reg_t val) noexcept {
242305
if (proc->n_pmp == 0)
243306
return false;
244307

245308
bool write_success = false;
246-
const bool rlb = state->mseccfg->get_rlb();
247-
const bool mml = state->mseccfg->get_mml();
248309
for (size_t i0 = (address - CSR_PMPCFG0) * 4, i = i0; i < i0 + proc->get_xlen() / 8; i++) {
249310
if (i < proc->n_pmp) {
250-
const bool locked = (state->pmpaddr[i]->cfg & PMP_L);
251-
if (rlb || !locked) {
252-
uint8_t all_cfg_fields = (PMP_R | PMP_W | PMP_X | PMP_A |
253-
(proc->extension_enabled(EXT_SMPMPMT) ? PMP_MT : 0) |
311+
uint8_t all_cfg_fields = (PMP_R | PMP_W | PMP_X | PMP_A |
312+
(proc->extension_enabled(EXT_SMPMPMT) ? PMP_MT : 0) |
254313
PMP_L);
255-
uint8_t cfg = (val >> (8 * (i - i0))) & all_cfg_fields;
256-
// Drop R=0 W=1 when MML = 0
257-
// Remove the restriction when MML = 1
258-
if (!mml) {
259-
cfg &= ~PMP_W | ((cfg & PMP_R) ? PMP_W : 0);
260-
}
261-
// Disallow A=NA4 when granularity > 4
262-
if (proc->lg_pmp_granularity != PMP_SHIFT && (cfg & PMP_A) == PMP_NA4)
263-
cfg |= PMP_NAPOT;
264-
// MT value 0x3 is reserved
265-
if (get_field(cfg, PMP_MT) == 0x3)
266-
cfg = set_field(cfg, PMP_MT, 0);
267-
/*
268-
* Adding a rule with executable privileges that either is M-mode-only or a locked Shared-Region
269-
* is not possible and such pmpcfg writes are ignored, leaving pmpcfg unchanged.
270-
* This restriction can be temporarily lifted e.g. during the boot process, by setting mseccfg.RLB.
271-
*/
272-
const bool cfgx = cfg & PMP_X;
273-
const bool cfgw = cfg & PMP_W;
274-
const bool cfgr = cfg & PMP_R;
275-
if (rlb || !(mml && ((cfg & PMP_L) // M-mode-only or a locked Shared-Region
276-
&& !(cfgx && cfgw && cfgr) // RWX = 111 is allowed
277-
&& (cfgx || (cfgw && !cfgr)) // X=1 or RW=01 is not allowed
278-
))) {
279-
state->pmpaddr[i]->cfg = cfg;
280-
}
281-
}
314+
uint8_t cfg = (val >> (8 * (i - i0))) & all_cfg_fields;
315+
update_pmpcfg_entry(i, cfg, 0);
282316
write_success = true;
283317
}
284318
}
285319
proc->get_mmu()->flush_tlb();
286320
return write_success;
287321
}
288322

323+
ind_pmpcfg_csr_t::ind_pmpcfg_csr_t(processor_t* const proc, const reg_t addr):
324+
pmpcfg_csr_t(proc, addr) {
325+
}
326+
327+
reg_t ind_pmpcfg_csr_t::read() const noexcept {
328+
// Bit MXLEN-1 of the pmpcfg register is the extended-attributes (E) field.
329+
// The address member of this object holds the PMP entry index.
330+
return state->pmpaddr[address]->cfg |
331+
((proc->get_const_xlen() == 32)
332+
? (state->pmpaddr[address]->E ? PMPCFG32_E : 0)
333+
: (state->pmpaddr[address]->E ? PMPCFG64_E : 0));
334+
}
335+
336+
bool ind_pmpcfg_csr_t::unlogged_write(const reg_t val) noexcept {
337+
const bool E = (proc->get_const_xlen() == 32)
338+
? ((val & PMPCFG32_E) ? 1 : 0)
339+
: ((val & PMPCFG64_E) ? 1 : 0);
340+
// The low 8 bits of the indirect pmpcfg register alias to the
341+
// PMP configurations accessible via the direct CSRs
342+
const uint8_t cfg = val & 0xFF;
343+
344+
// The address member of this object holds the PMP entry index.
345+
update_pmpcfg_entry(address, cfg, E);
346+
347+
proc->get_mmu()->flush_tlb();
348+
return true;
349+
}
350+
289351
// implement class mseccfg_csr_t
290352
mseccfg_csr_t::mseccfg_csr_t(processor_t* const proc, const reg_t addr):
291353
basic_csr_t(proc, addr, 0) {
@@ -319,6 +381,9 @@ bool mseccfg_csr_t::get_useed() const noexcept {
319381
bool mseccfg_csr_t::get_sseed() const noexcept {
320382
return (read() & MSECCFG_SSEED);
321383
}
384+
bool mseccfg_csr_t::get_msse() const noexcept {
385+
return (read() & MSECCFG_MSSE);
386+
}
322387

323388
bool mseccfg_csr_t::unlogged_write(const reg_t val) noexcept {
324389
reg_t new_val = read();
@@ -351,6 +416,11 @@ bool mseccfg_csr_t::unlogged_write(const reg_t val) noexcept {
351416
new_val |= (val & MSECCFG_MLPE);
352417
}
353418

419+
if (proc->extension_enabled(EXT_SMCFISS)) {
420+
new_val &= ~MSECCFG_MSSE;
421+
new_val |= (val & MSECCFG_MSSE);
422+
}
423+
354424
if (proc->extension_enabled(EXT_SMMPM)) {
355425
const reg_t pmm_reserved = 1; // Reserved value of mseccfg.PMM
356426
reg_t pmm = get_field(val, MSECCFG_PMM);

riscv/csrs.h

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,7 @@ class pmpaddr_csr_t: public csr_t {
102102
bool subset_match(reg_t addr, reg_t len) const noexcept;
103103

104104
// Is the specified access allowed given the pmpcfg privileges?
105-
bool access_ok(access_type type, reg_t mode, bool hlvx) const noexcept;
105+
bool access_ok(access_type type, reg_t mode, bool hlvx, bool ss_access) const noexcept;
106106

107107
// To check lock bit status from outside like mseccfg
108108
bool is_locked() const noexcept {
@@ -127,8 +127,10 @@ class pmpaddr_csr_t: public csr_t {
127127

128128
bool next_locked_and_tor() const noexcept;
129129
reg_t val;
130-
friend class pmpcfg_csr_t; // so he can access cfg
130+
friend class pmpcfg_csr_t; // so he can access cfg
131+
friend class ind_pmpcfg_csr_t; // so he can access cfg
131132
uint8_t cfg;
133+
bool E; // Extended attribute (E)
132134
const size_t pmpidx;
133135
};
134136

@@ -141,6 +143,7 @@ class pmpcfg_csr_t: public csr_t {
141143
virtual reg_t read() const noexcept override;
142144
protected:
143145
virtual bool unlogged_write(const reg_t val) noexcept override;
146+
virtual void update_pmpcfg_entry(const size_t index, const uint8_t cfg_in, const bool E);
144147
};
145148

146149
class mseccfg_csr_t: public basic_csr_t {
@@ -152,6 +155,7 @@ class mseccfg_csr_t: public basic_csr_t {
152155
bool get_rlb() const noexcept;
153156
bool get_useed() const noexcept;
154157
bool get_sseed() const noexcept;
158+
bool get_msse() const noexcept;
155159
protected:
156160
virtual bool unlogged_write(const reg_t val) noexcept override;
157161
};
@@ -877,6 +881,14 @@ class sscsrind_reg_csr_t : public csr_t {
877881
csr_t_p get_reg() const noexcept;
878882
};
879883

884+
class ind_pmpcfg_csr_t: public pmpcfg_csr_t {
885+
public:
886+
ind_pmpcfg_csr_t(processor_t* const proc, const reg_t addr);
887+
reg_t read() const noexcept override;
888+
protected:
889+
virtual bool unlogged_write(const reg_t val) noexcept override;
890+
};
891+
880892
// smcntrpmf_csr_t caches the previous state of the CSR in case a CSRW instruction
881893
// modifies the state that should not be immediately visible to bump()
882894
class smcntrpmf_csr_t : public masked_csr_t {

riscv/encoding.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -284,11 +284,15 @@
284284
#define MISELECT_IMSIC _RISCV_UL(0x70)
285285
#define MISELECT_IMSIC_TOP _RISCV_UL(0xff)
286286

287+
287288
#define SISELECT_IPRIO _RISCV_UL(0x30)
288289
#define SISELECT_IPRIO_TOP _RISCV_UL(0x3f)
289290
#define SISELECT_IMSIC _RISCV_UL(0x70)
290291
#define SISELECT_IMSIC_TOP _RISCV_UL(0xff)
291292

293+
#define MISELECT_PMPIND_START _RISCV_UL(0x300)
294+
#define MISELECT_PMPIND_TOP _RISCV_UL(0x33F)
295+
292296
#define VSISELECT_IMSIC _RISCV_UL(0x70)
293297
#define VSISELECT_IMSIC_TOP _RISCV_UL(0xff)
294298

@@ -330,6 +334,7 @@
330334
#define MSECCFG_USEED _RISCV_UL(0x00000100)
331335
#define MSECCFG_SSEED _RISCV_UL(0x00000200)
332336
#define MSECCFG_MLPE _RISCV_UL(0x00000400)
337+
#define MSECCFG_MSSE _RISCV_UL(0x00000800)
333338
#define MSECCFG_PMM _RISCV_ULL(0x0000000300000000)
334339

335340
/* jvt fields */
@@ -393,6 +398,8 @@
393398

394399
#define SPMP_U _RISCV_UL(0x100)
395400
#define SPMP_SHARED _RISCV_UL(0x200)
401+
#define PMPCFG64_E _RISCV_UL(0x8000000000000000)
402+
#define PMPCFG32_E _RISCV_UL(0x80000000)
396403

397404
#define MCTRCTL_U _RISCV_ULL(0x0000000000000001)
398405
#define MCTRCTL_S _RISCV_ULL(0x0000000000000002)

riscv/insns/ssamoswap_d.h

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,5 +3,11 @@ require_extension(EXT_ZAAMO);
33
require_rv64;
44

55
DECLARE_XENVCFG_VARS(SSE);
6-
require_envcfg(SSE);
6+
7+
if (p->extension_enabled('S')) {
8+
require_envcfg(SSE);
9+
} else {
10+
require_extension(EXT_SMUCFISS);
11+
require(mSSE);
12+
}
713
WRITE_RD(MMU.ssamoswap<uint64_t>(RS1, RS2));

riscv/insns/ssamoswap_w.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,10 @@ require_extension(EXT_ZAAMO);
33

44
DECLARE_XENVCFG_VARS(SSE);
55
require_envcfg(SSE);
6+
if (p->extension_enabled('S')) {
7+
require_envcfg(SSE);
8+
} else {
9+
require_extension(EXT_SMUCFISS);
10+
require(mSSE);
11+
}
612
WRITE_RD(sext32(MMU.ssamoswap<uint32_t>(RS1, RS2)));

riscv/isa_parser.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,10 +38,13 @@ typedef enum {
3838
EXT_ZVFHMIN,
3939
EXT_ZVFOFP4MIN,
4040
EXT_ZVFOFP8MIN,
41+
EXT_SMCFISS,
4142
EXT_SMEPMP,
4243
EXT_SMSTATEEN,
44+
EXT_SMPMPIND,
4345
EXT_SMPMPMT,
4446
EXT_SMRNMI,
47+
EXT_SMUCFISS,
4548
EXT_SSCOFPMF,
4649
EXT_SVADU,
4750
EXT_SVADE,

0 commit comments

Comments
 (0)