Skip to content

Commit daa4b25

Browse files
committed
Add a fast-cap-dirty PTE behavior
At present, the extra SC_Mod bit is ignored. I have not yet done the plumbing to add the requisite CASes to the PTW machinery. Gate cap-store traps on storing a tagged value; if we're going to clear the tag, act like we're storing data.
1 parent 0b4bb1b commit daa4b25

File tree

2 files changed

+35
-9
lines changed

2 files changed

+35
-9
lines changed

src/cheri_insts.sail

+2-2
Original file line numberDiff line numberDiff line change
@@ -1167,7 +1167,7 @@ function handle_store_cap_via_cap(rs, cs, cap_val, vaddrBits) = {
11671167
} else if not(is_aligned_addr(vaddrBits, cap_size)) then {
11681168
handle_mem_exception(vaddrBits, E_SAMO_Addr_Align());
11691169
RETIRE_FAIL
1170-
} else match translateAddr(vaddrBits, Write(Cap)) {
1170+
} else match translateAddr(vaddrBits, Write(if rs_val.tag then Cap else Data)) {
11711171
TR_Failure(E_Extension(EXC_CHERI_VMEM_STORE_CAP), _) => {
11721172
handle_cheri_cap_exception(CapEx_TLBNoStoreCap, cs);
11731173
RETIRE_FAIL
@@ -1315,7 +1315,7 @@ function handle_store_cond_cap_via_cap(cs2, cs, cap_val, vaddrBits) = {
13151315
cancel_reservation();
13161316
RETIRE_SUCCESS
13171317
} else {
1318-
match translateAddr(vaddrBits, Write(Cap)) {
1318+
match translateAddr(vaddrBits, Write(if cs2_val.tag then Cap else Data)) {
13191319
TR_Failure(E_Extension(EXC_CHERI_VMEM_STORE_CAP), _) => {
13201320
handle_cheri_cap_exception(CapEx_TLBNoStoreCap, cs);
13211321
RETIRE_FAIL

src/cheri_pte.sail

+33-7
Original file line numberDiff line numberDiff line change
@@ -42,14 +42,40 @@ bitfield PTE_Bits : pteAttribs = {
4242
* gate their capability-load traps on the PTE bits (and sccsr.gclg[su]); that
4343
* is, we permit relaxing only the dependence on the tag bit itself.
4444
*
45+
* While for StoreCap* the behaviors are as follows. Again, SCI is an inhibit.
46+
*
47+
* SCI SC_Mod Action
48+
*
49+
* 0 0 Permit tagged capability store
50+
* 0 1 [Reserved]
51+
*
52+
* 1 0 Trap on tagged capability store
53+
* 1 1 CAS the PTE to SC=0, SC_Mod=0 (i.e., reset both bits)
54+
*
55+
* It is permitted for implementations to ignore SC_Mod and behave as if it
56+
* were always 0, at the expense of traps on cap-dirtying stores. Note that
57+
* SCI and SC_Mod are not quite like W and D: SCI is both the (negated)
58+
* permission and dirty bit; SC_Mod just encapsulates a particular trap
59+
* handler behavior. This is again done for simplicity of gradual roll-out:
60+
* permitting SC_Mod to be treated as always zero means fewer things to
61+
* initially implement.
62+
*
63+
* The SCI=1 SC_Mod=1 behavior is described as a CAS of the PTE to close race
64+
* conditions, much as with W and D. Should the TLB have this state cached
65+
* and then observe a SCI=0 SC_Mod=0 PTE, no PTE write is necessary. On the
66+
* other hand, if SCI=1 SC_Mod=0 is observed, the store operation must trap
67+
* rather than transition the PTE to SCI=0 SC_Mod=0.
68+
*
69+
* At present, SC_Mod is ignored by the code below.
4570
*/
4671
type extPte = bits(10)
4772

4873
bitfield Ext_PTE_Bits : extPte = {
4974
LoadCapInh : 9, /* Inhibit capability loads */
50-
StoreCap : 8, /* Permit capability stores */
75+
StoreCapInh : 8, /* Inhibit capability stores */
5176
LoadCap_Mod : 7, /* Modify capability load inhibit; see above table */
5277
LoadCap_LCLG : 6, /* When cap. load gens. are in use, the "local" CLG */
78+
StoreCap_Mod : 5, /* Modify capability store inhibit; see above table */
5379
}
5480

5581
function isPTEPtr(p : pteAttribs, ext : extPte) -> bool = {
@@ -118,7 +144,7 @@ function checkPTEPermission(ac : AccessType(ext_access_type), priv : Privilege,
118144
(Write(Cap), User) => { if p.U() == 0b1 & p.W() == 0b1
119145
then {
120146
let e = Mk_Ext_PTE_Bits(ext);
121-
if e.StoreCap() == 0b1
147+
if e.StoreCapInh() == 0b0
122148
then (true, PTE_CAP_OK)
123149
else {
124150
/* Do not allow the address translation to proceed */
@@ -132,9 +158,9 @@ function checkPTEPermission(ac : AccessType(ext_access_type), priv : Privilege,
132158
then {
133159
let e = Mk_Ext_PTE_Bits(ext);
134160
let lcm = checkPTEPermission_LC(p, e);
135-
if e.StoreCap() == 0b1 & lcm == PTE_CAP_OK
161+
if e.StoreCapInh() == 0b0 & lcm == PTE_CAP_OK
136162
then (true, PTE_CAP_OK)
137-
else if e.StoreCap() == 0b0
163+
else if e.StoreCapInh() == 0b1
138164
/* return a failure since we should cause an exception */
139165
then (false, PTE_STORE_CAP_ERR)
140166
/* return a success since the translation should proceed */
@@ -154,7 +180,7 @@ function checkPTEPermission(ac : AccessType(ext_access_type), priv : Privilege,
154180
(Write(Cap), Supervisor) => { let e = Mk_Ext_PTE_Bits(ext);
155181
if (p.U() == 0b0 | do_sum) & p.W() == 0b1
156182
then {
157-
if e.StoreCap() == 0b1
183+
if e.StoreCapInh() == 0b0
158184
then (true, PTE_CAP_OK)
159185
else (false, PTE_STORE_CAP_ERR)
160186
}
@@ -165,9 +191,9 @@ function checkPTEPermission(ac : AccessType(ext_access_type), priv : Privilege,
165191
if (p.U() == 0b0 | do_sum) & p.R() == 0b1 & p.W() == 0b1
166192
then {
167193
let lcm = checkPTEPermission_LC(p, e);
168-
if e.StoreCap() == 0b1 & lcm == PTE_CAP_OK
194+
if e.StoreCapInh() == 0b0 & lcm == PTE_CAP_OK
169195
then (true, PTE_CAP_OK)
170-
else if e.StoreCap() == 0b0
196+
else if e.StoreCapInh() == 0b1
171197
/* return a failure since we should cause an exception */
172198
then (false, PTE_STORE_CAP_ERR)
173199
/* return a success since the translation should proceed */

0 commit comments

Comments
 (0)