Skip to content

Commit adb7d03

Browse files
committed
Plumb feature flags into PTW for data dependence control
1 parent 7e78691 commit adb7d03

File tree

4 files changed

+123
-44
lines changed

4 files changed

+123
-44
lines changed

src/cheri_insts.sail

+4-3
Original file line numberDiff line numberDiff line change
@@ -902,6 +902,9 @@ val handle_load_cap_via_cap : (regidx, capreg_idx, Capability, xlenbits) -> Reti
902902
function handle_load_cap_via_cap(rd, cs, cap_val, vaddrBits) = {
903903
let aq : bool = false;
904904
let rl : bool = false;
905+
906+
let vialc : bool = cap_val.permit_load_cap;
907+
905908
if not(cap_val.tag) then {
906909
handle_cheri_cap_exception(CapEx_TagViolation, cs);
907910
RETIRE_FAIL
@@ -917,11 +920,9 @@ function handle_load_cap_via_cap(rd, cs, cap_val, vaddrBits) = {
917920
} else if not(is_aligned_addr(vaddrBits, cap_size)) then {
918921
handle_mem_exception(vaddrBits, E_Load_Addr_Align());
919922
RETIRE_FAIL
920-
} else match translateAddr(vaddrBits, Read(Cap)) {
921-
TR_Failure(E_Extension(_), _) => { internal_error("unexpected cheri exception for cap load") },
923+
} else match translateAddr(vaddrBits, Read(if vialc then Cap else Data)) {
922924
TR_Failure(e, _) => { handle_mem_exception(vaddrBits, e); RETIRE_FAIL },
923925
TR_Address(addr, ptw_info) => {
924-
let vialc : bool = cap_val.permit_load_cap;
925926
let lcav : ext_ptw_lcm = ptw_info.ptw_lc_mod;
926927

927928
let c = mem_read_cap(addr, aq, rl, false);

src/cheri_pte.sail

+104-19
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ function isInvalidPTE(p : pteAttribs, ext : extPte) -> bool = {
8787

8888
union PTE_Check = {
8989
PTE_Check_Success : ext_ptw,
90-
PTE_Check_Failure : ext_ptw
90+
PTE_Check_Failure : (ext_ptw, ext_ptw_fail)
9191
}
9292

9393
val checkPTEPermission_SC_caveat : Ext_PTE_Bits -> ext_ptw_scm
@@ -117,6 +117,51 @@ function checkPTEPermission_LC_caveat(p, e) =
117117
else PTW_LCM_TRAP
118118
}
119119

120+
val checkPTEPermission_LC_caveat_datadep : (ext_ptw_lcm, ext_ptw) -> PTE_Check effect { rreg }
121+
function checkPTEPermission_LC_caveat_datadep(lcav, ext_ptw) = {
122+
let ext_ptw' = ext_ptw_join_lcm(ext_ptw, lcav);
123+
match (lcav) {
124+
PTW_LCM_OK => PTE_Check_Success(ext_ptw),
125+
PTW_LCM_CLR => PTE_Check_Success(ext_ptw'),
126+
PTW_LCM_TRAP => {
127+
if scisa.pte_cap_lc_datadep() == 0b1 then {
128+
/*
129+
* Continue translating, but add caveat
130+
*/
131+
PTE_Check_Success(ext_ptw')
132+
} else {
133+
/*
134+
* Stop translating and raise a trap now
135+
*/
136+
PTE_Check_Failure(ext_ptw', EPTWF_CAP_ERR)
137+
}
138+
}
139+
}
140+
}
141+
142+
val checkPTEPermission_SC_caveat : Ext_PTE_Bits -> ext_ptw_scm
143+
function checkPTEPermission_SC_caveat(e) =
144+
match (e.StoreCap(), e.StoreCap_Mod()) {
145+
(0b1, _) => PTW_SCM_OK, /* Permitted */
146+
(0b0, 0b0) => PTW_SCM_TRAP, /* Forbidden, unmodified */
147+
(0b0, 0b1) => PTW_SCM_OK /* Forbidden, modified; see update_PTE_bits */
148+
}
149+
150+
val checkPTEPermission_SC_caveat_datadep : (ext_ptw_scm, ext_ptw) -> PTE_Check effect { rreg }
151+
function checkPTEPermission_SC_caveat_datadep(scav, ext_ptw) = {
152+
match (scav) {
153+
PTW_SCM_OK => PTE_Check_Success(ext_ptw),
154+
PTW_SCM_TRAP => {
155+
let ext_ptw' = ext_ptw_join_scm(ext_ptw, scav);
156+
if scisa.pte_cap_sc_datadep() == 0b1 then {
157+
PTE_Check_Success(ext_ptw')
158+
} else {
159+
PTE_Check_Failure(ext_ptw', EPTWF_CAP_ERR)
160+
}
161+
}
162+
}
163+
}
164+
120165
function checkPTEPermission(ac : AccessType(ext_access_type), priv : Privilege, mxr : bool, do_sum : bool, p : PTE_Bits, ext : extPte, ext_ptw : ext_ptw) -> PTE_Check = {
121166
/*
122167
* Although in many cases MXR doesn't make sense for capabilities, we honour
@@ -130,7 +175,7 @@ function checkPTEPermission(ac : AccessType(ext_access_type), priv : Privilege,
130175
*
131176
* 3. It's simpler to implement yet still safe (LC is unaffected by MXR).
132177
*/
133-
let base_succ : bool =
178+
let succ : bool =
134179
match (ac, priv) {
135180
(Read(_), User) => p.U() == 0b1 & (p.R() == 0b1 | (p.X() == 0b1 & mxr)),
136181
(Write(_), User) => p.U() == 0b1 & p.W() == 0b1,
@@ -145,27 +190,67 @@ function checkPTEPermission(ac : AccessType(ext_access_type), priv : Privilege,
145190
(_, Machine) => internal_error("m-mode mem perm check")
146191
};
147192

193+
let res : PTE_Check =
194+
if succ
195+
then PTE_Check_Success(ext_ptw)
196+
else PTE_Check_Failure(ext_ptw, EPTWF_NO_PERM);
197+
148198
let e = Mk_Ext_PTE_Bits(ext);
199+
200+
/* And now it's time for a little (manual, expanded) Either-monadic logic. */
201+
202+
/*
203+
* Check for invalid modifiers
204+
*/
205+
let res : PTE_Check =
206+
match res {
207+
PTE_Check_Failure(_, _) => res,
208+
PTE_Check_Success(_) =>
209+
if scisa.pte_cap_lsmod() == 0b0 &
210+
~(e.StoreCap_Mod() == 0b0 &
211+
e.LoadCap_Mod() == 0b0 &
212+
e.LoadCap_Gen() == 0b0)
213+
then PTE_Check_Failure(ext_ptw, EPTWF_INVALID)
214+
else res
215+
};
216+
217+
/*
218+
* Check for store-side caveats, which may force a fault if data-independent
219+
*/
149220
let scav = checkPTEPermission_SC_caveat(e);
221+
let res : PTE_Check =
222+
match res {
223+
PTE_Check_Failure(_, _) => res,
224+
PTE_Check_Success(ext_ptw) => match ac {
225+
Execute() => res,
226+
Read(_) => res,
227+
Write(Data) => res,
228+
ReadWrite(_, Data) => res,
229+
230+
ReadWrite(_, Cap ) => checkPTEPermission_SC_caveat_datadep(scav, ext_ptw),
231+
Write(Cap) => checkPTEPermission_SC_caveat_datadep(scav, ext_ptw)
232+
}
233+
};
234+
235+
/*
236+
* Now do load-side caveats, which may also force a fault if data-dependent
237+
*/
150238
let lcav = checkPTEPermission_LC_caveat(p, e);
151-
let (succ, ext_ptw') : (bool, ext_ptw) =
152-
match (base_succ, ac) {
153-
/* Base translation exceptions take priority over CHERI exceptions */
154-
(false, _) => (false, init_ext_ptw),
155-
156-
(true, Read(Cap)) => (true, ext_ptw_join_lcm(ext_ptw, lcav)),
157-
(true, Write(Cap)) => (true, ext_ptw_join_scm(ext_ptw, scav)),
158-
(true, ReadWrite(Data,Cap)) => (true, ext_ptw_join_scm(ext_ptw, scav)),
159-
(true, ReadWrite(Cap,Data)) => (true, ext_ptw_join_lcm(ext_ptw, lcav)),
160-
(true, ReadWrite(Cap,Cap)) => (true, ext_ptw_join_scm(ext_ptw_join_lcm(ext_ptw, lcav), scav)),
161-
162-
(true, Read(Data)) => (true, ext_ptw),
163-
(true, Write(Data)) => (true, ext_ptw),
164-
(true, ReadWrite(Data,Data)) => (true, ext_ptw),
165-
(true, Execute()) => (true, ext_ptw)
166-
};
239+
let res : PTE_Check =
240+
match res {
241+
PTE_Check_Failure(_, _) => res,
242+
PTE_Check_Success(ext_ptw) => match ac {
243+
Execute() => res,
244+
Write(_) => res,
245+
Read(Data) => res,
246+
ReadWrite(Data, _) => res,
247+
248+
Read(Cap) => checkPTEPermission_LC_caveat_datadep(lcav, ext_ptw),
249+
ReadWrite(Cap, _) => checkPTEPermission_LC_caveat_datadep(lcav, ext_ptw)
250+
}
251+
};
167252

168-
if succ then PTE_Check_Success(ext_ptw') else PTE_Check_Failure(ext_ptw')
253+
res
169254
}
170255

171256
function update_PTE_Bits(p : PTE_Bits, a : AccessType(ext_access_type), ext : extPte) -> option((PTE_Bits, extPte)) = {

src/cheri_ptw.sail

+8-22
Original file line numberDiff line numberDiff line change
@@ -25,29 +25,15 @@ function ptw_error_to_str(e) =
2525
overload to_str = {ptw_error_to_str}
2626

2727
/*
28-
* I apologize for the confusion you have experienced if you have skipped over
29-
* this comment and read the body of this function first. Hopefully these two
30-
* points resolve most of it:
31-
*
32-
* 1) While it may look like we're signaling that we must *always* raise
33-
* faults, translationException below can see whether the instruction
34-
* triggering the PTW is claiming to store an asserted tag, and will ignore our
35-
* result if that isn't so.
36-
*
37-
* 2) We analyse only the store-side component of ext_ptw here. The PTW logic
38-
* cannot see into the data path, and so load-side responses, including traps,
39-
* must be handled by the instruction that initiated the translation.
28+
* checkPTEPermission has returned a failure; here, ext_ptw is no longer
29+
* caveats for data dependence, but rather certainly identifies the cause of a
30+
* trap.
4031
*/
41-
function ext_get_ptw_error(ext_ptw : ext_ptw) -> PTW_Error =
42-
match (ext_ptw.ptw_sc_mod) {
43-
44-
/*
45-
* This is confusing: PTW_No_Permission() is never used as such, but just
46-
* dodges the pattern matches in translationException, below.
47-
*/
48-
PTW_SCM_OK => PTW_No_Permission(),
49-
50-
PTW_SCM_TRAP => PTW_Ext_Error(AT_CAP_ERR)
32+
function ext_get_ptw_error(eptwf : ext_ptw_fail) -> PTW_Error =
33+
match (eptwf) {
34+
EPTWF_NO_PERM => PTW_No_Permission(),
35+
EPTWF_INVALID => PTW_Invalid_PTE(),
36+
EPTWF_CAP_ERR => PTW_Ext_Error(AT_CAP_ERR)
5137
}
5238

5339
/* conversion of these translation/PTW failures into architectural exceptions */

src/cheri_riscv_types.sail

+7
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,13 @@ let init_ext_ptw : ext_ptw = struct {
6363
ptw_sc_mod = PTW_SCM_OK
6464
}
6565

66+
/* Address translation failures */
67+
enum ext_ptw_fail = {
68+
EPTWF_NO_PERM,
69+
EPTWF_INVALID,
70+
EPTWF_CAP_ERR
71+
}
72+
6673
/* Address translation errors */
6774
enum ext_ptw_error = {AT_CAP_ERR}
6875

0 commit comments

Comments
 (0)