@@ -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+
241304bool 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
290352mseccfg_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 {
319381bool 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
323388bool 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);
0 commit comments