Skip to content

Commit 995e484

Browse files
nwfnwf
authored and
nwf
committed
Introduce capability load generation traps
1 parent 7a308ef commit 995e484

File tree

5 files changed

+110
-42
lines changed

5 files changed

+110
-42
lines changed

src/cheri_insts.sail

+19-14
Original file line numberDiff line numberDiff line change
@@ -882,6 +882,17 @@ function clause execute (CLoadCap(rd, cs, is_unsigned, width)) =
882882
handle_load_data_via_cap(rd, 0b0 @ cs, cap_val, vaddr, is_unsigned, width)
883883
}
884884

885+
val handle_load_cap_ptw_ext : (Capability, bool, ext_ptw) -> option(Capability)
886+
function handle_load_cap_ptw_ext (v, vialc, ptw_info) =
887+
if v.tag == false
888+
then Some(v)
889+
else match ptw_info {
890+
PTW_CAP_OK => Some({v with tag = v.tag & vialc}),
891+
PTW_LOAD_CAP_CLR => Some({v with tag = false}),
892+
PTW_LOAD_CAP_TRAP => None(),
893+
PTW_STORE_CAP_ERR => internal_error("PTW store fault on load path")
894+
}
895+
885896
val handle_load_cap_via_cap : (regidx, capreg_idx, Capability, xlenbits) -> Retired effect {escape, rmem, rmemt, rreg, wmv, wmvt, wreg}
886897
function handle_load_cap_via_cap(rd, cs, cap_val, vaddrBits) = {
887898
let aq : bool = false;
@@ -908,11 +919,10 @@ function handle_load_cap_via_cap(rd, cs, cap_val, vaddrBits) = {
908919
let c = mem_read_cap(addr, aq, rl, false);
909920
match c {
910921
MemValue(v) => {
911-
let cr = if ptw_info == PTW_LOAD_CAP_ERR
912-
then {v with tag = false} /* strip the tag */
913-
else {v with tag = v.tag & cap_val.permit_load_cap};
914-
writeCapReg(rd, cr);
915-
RETIRE_SUCCESS
922+
match handle_load_cap_ptw_ext(v, cap_val.permit_load_cap, ptw_info) {
923+
Some(v') => { writeCapReg(rd, v'); RETIRE_SUCCESS },
924+
None() => { handle_cheri_cap_exception(CapEx_CapLoadGen, cs); RETIRE_FAIL }
925+
}
916926
},
917927
MemException(e) => {handle_mem_exception(vaddrBits, e); RETIRE_FAIL }
918928
}
@@ -1006,15 +1016,10 @@ if not(cap_val.tag) then {
10061016
let c = mem_read_cap(addr, aq, rl, false);
10071017
match c {
10081018
MemValue(v) => {
1009-
let cr = if ptw_info == PTW_LOAD_CAP_ERR
1010-
then {v with tag = false} /* strip the tag */
1011-
else {
1012-
/* the Sail model currently reserves virtual addresses */
1013-
load_reservation(addr);
1014-
{v with tag = v.tag & cap_val.permit_load_cap}
1015-
};
1016-
writeCapReg(cd, cr);
1017-
RETIRE_SUCCESS
1019+
match handle_load_cap_ptw_ext(v, cap_val.permit_load_cap, ptw_info) {
1020+
Some(v') => { load_reservation(addr); writeCapReg(cd, v'); RETIRE_SUCCESS },
1021+
None() => { handle_cheri_cap_exception(CapEx_CapLoadGen, cs); RETIRE_FAIL }
1022+
}
10181023
},
10191024
MemException(e) => {handle_mem_exception(vaddrBits, e); RETIRE_FAIL }
10201025
}

src/cheri_pte.sail

+55-15
Original file line numberDiff line numberDiff line change
@@ -15,12 +15,34 @@ bitfield PTE_Bits : pteAttribs = {
1515

1616
/* Reserved PTE bits could be used by extensions on RV64. There are
1717
* no such available bits on RV32, so these bits will be zeros on RV32.
18+
*
19+
* XXX Because these bits are 0 on RV32, do we want to use inverted polarity,
20+
* so that 0 is the *enabled* form?
21+
*
22+
* XXX For initial implementation, only LoadCap and StoreCap are expected to
23+
* be implemented. The LC_Mod and LC_LCLG bits are for Revocation 3's benefit
24+
* and will be first brought up in emulation.
25+
*
26+
* The intended semantics for LoadCap* are:
27+
*
28+
* LC LC_Mod LC_LCLG Action
29+
* 0 0 0 Capability loads strip tags
30+
* 0 1 0 Capability loads trap (on set tag)
31+
* 0 X 1 [Reserved]
32+
*
33+
* 1 0 0 Capability loads succeed: no traps or tag clearing
34+
* 1 0 1 [Reserved]
35+
* 1 1 G Capability loads trap if G mismatches sccsr.gclg[su],
36+
* where the compared bit is keyed off of this PTE's U.
37+
*
1838
*/
1939
type extPte = bits(10)
2040

2141
bitfield Ext_PTE_Bits : extPte = {
22-
LoadCap : 9,
23-
StoreCap : 8,
42+
LoadCap : 9, /* Permit capability loads */
43+
StoreCap : 8, /* Permit capability stores */
44+
LoadCap_Mod : 7, /* Modify capability load behavior; see above table */
45+
LoadCap_LCLG : 6, /* When cap. load gens. are in use, the "local" CLG */
2446
}
2547

2648
function isPTEPtr(p : pteAttribs, ext : extPte) -> bool = {
@@ -41,6 +63,29 @@ union PTE_Check = {
4163
function to_pte_check(b : bool) -> (bool, pte_check) =
4264
(b, PTE_CAP_OK)
4365

66+
/*
67+
* Assuming we're allowed to load from this page, modulate our cap response
68+
*/
69+
val checkPTEPermission_LC : (PTE_Bits, Ext_PTE_Bits) -> pte_check effect {rreg}
70+
function checkPTEPermission_LC(p, e) =
71+
if e.LoadCap() == 0b0
72+
then match (e.LoadCap_LCLG(), e.LoadCap_Mod()) {
73+
(0b1, _) => not_implemented("Reserved PTE extension bits: !LC but LCLG"),
74+
(_, 0b0) => PTE_LOAD_CAP_CLR /* Clear tag for "unmodified" no-LC case */,
75+
(_, 0b1) => PTE_LOAD_CAP_TRAP /* Trap on tag load for "modified" no-LC case */
76+
}
77+
else if e.LoadCap_Mod() == 0b0
78+
then { if e.LoadCap_LCLG() == 0b0
79+
then PTE_CAP_OK /* Unmodified LC case: go ahead */
80+
else not_implemented("Reserved PTE extension bits: LC, !LC_Mod but LCLG")
81+
}
82+
else { /* With LoadCap_Mod on with LC, use LCLG */
83+
let gclg : bits(1) = if p.U() == 0b1 then sccsr.gclgu() else sccsr.gclgs();
84+
if e.LoadCap_LCLG() == gclg
85+
then PTE_CAP_OK
86+
else PTE_LOAD_CAP_TRAP
87+
}
88+
4489
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 = {
4590
let (succ, pte_chk) : (bool, pte_check) =
4691
match (ac, priv) {
@@ -58,12 +103,7 @@ function checkPTEPermission(ac : AccessType(ext_access_type), priv : Privilege,
58103
if p.U() == 0b1 & p.R() == 0b1
59104
then {
60105
let e = Mk_Ext_PTE_Bits(ext);
61-
if e.LoadCap() == 0b1
62-
then (true, PTE_CAP_OK)
63-
else {
64-
/* Allow the address translation to proceed, but mark for tag stripping */
65-
(true, PTE_LOAD_CAP_ERR)
66-
}
106+
(true, checkPTEPermission_LC(p, e))
67107
}
68108
else (false, PTE_CAP_OK)
69109
},
@@ -84,23 +124,22 @@ function checkPTEPermission(ac : AccessType(ext_access_type), priv : Privilege,
84124
(ReadWrite(Cap), User) => { if p.U() == 0b1 & p.R() == 0b1 & p.W() == 0b1
85125
then {
86126
let e = Mk_Ext_PTE_Bits(ext);
87-
if e.StoreCap() == 0b1 & e.LoadCap() == 0b1
127+
let lcm = checkPTEPermission_LC(p, e);
128+
if e.StoreCap() == 0b1 & lcm == PTE_CAP_OK
88129
then (true, PTE_CAP_OK)
89130
else if e.StoreCap() == 0b0
90131
/* return a failure since we should cause an exception */
91132
then (false, PTE_STORE_CAP_ERR)
92133
/* return a success since the translation should proceed */
93-
else (true, PTE_LOAD_CAP_ERR)
134+
else (true, lcm)
94135
}
95136
else (false, PTE_CAP_OK)
96137
},
97138

98139
(Read(Cap), Supervisor) => { if (p.U() == 0b0 | do_sum) & p.R() == 0b1
99140
then {
100141
let e = Mk_Ext_PTE_Bits(ext);
101-
if e.LoadCap() == 0b1
102-
then (true, PTE_CAP_OK)
103-
else (true, PTE_LOAD_CAP_ERR)
142+
(true, checkPTEPermission_LC(p, e))
104143
}
105144
else (false, PTE_CAP_OK)
106145
},
@@ -118,13 +157,14 @@ function checkPTEPermission(ac : AccessType(ext_access_type), priv : Privilege,
118157
(ReadWrite(Cap), Supervisor) => { let e = Mk_Ext_PTE_Bits(ext);
119158
if (p.U() == 0b0 | do_sum) & p.R() == 0b1 & p.W() == 0b1
120159
then {
121-
if e.StoreCap() == 0b1 & e.LoadCap() == 0b1
160+
let lcm = checkPTEPermission_LC(p, e);
161+
if e.StoreCap() == 0b1 & lcm == PTE_CAP_OK
122162
then (true, PTE_CAP_OK)
123163
else if e.StoreCap() == 0b0
124164
/* return a failure since we should cause an exception */
125165
then (false, PTE_STORE_CAP_ERR)
126166
/* return a success since the translation should proceed */
127-
else (true, PTE_LOAD_CAP_ERR)
167+
else (true, lcm)
128168
}
129169
else (false, PTE_CAP_OK)
130170
},

src/cheri_riscv_types.sail

+28-10
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,44 @@
11
/* Extension for CHERI PTE checks */
2-
enum pte_check = {PTE_CAP_OK, PTE_LOAD_CAP_ERR, PTE_STORE_CAP_ERR}
2+
enum pte_check = {
3+
PTE_CAP_OK,
4+
PTE_LOAD_CAP_TRAP,
5+
PTE_LOAD_CAP_CLR,
6+
PTE_STORE_CAP_ERR
7+
}
38

49
/* Extension for CHERI page-table-walks */
510

6-
enum ext_ptw = {PTW_CAP_OK, PTW_LOAD_CAP_ERR, PTW_STORE_CAP_ERR}
11+
enum ext_ptw = {
12+
PTW_CAP_OK,
13+
PTW_LOAD_CAP_TRAP,
14+
PTW_LOAD_CAP_CLR,
15+
PTW_STORE_CAP_ERR
16+
}
717

818
let init_ext_ptw : ext_ptw = PTW_CAP_OK /* initial value of the PTW accumulator */
919

1020
/* Default accumulation of PTE check extensions into PTW accumulator */
1121
function ext_accum_ptw_result(ptw : ext_ptw, pte : pte_check) -> ext_ptw =
1222
match (ptw, pte) {
13-
(PTW_CAP_OK, PTE_CAP_OK) => PTW_CAP_OK,
14-
(PTW_CAP_OK, PTE_LOAD_CAP_ERR) => PTW_LOAD_CAP_ERR,
15-
(PTW_CAP_OK, PTE_STORE_CAP_ERR) => PTW_STORE_CAP_ERR,
23+
(PTW_CAP_OK, PTE_CAP_OK) => PTW_CAP_OK,
24+
(PTW_CAP_OK, PTE_LOAD_CAP_TRAP) => PTW_LOAD_CAP_TRAP,
25+
(PTW_CAP_OK, PTE_LOAD_CAP_CLR) => PTW_LOAD_CAP_CLR,
26+
(PTW_CAP_OK, PTE_STORE_CAP_ERR) => PTW_STORE_CAP_ERR,
27+
28+
/*
29+
* CHECK ME: The below prioritizes store exceptions over load modifiers,
30+
* and prefers load traps from permission to load traps from CLG to load
31+
* clearing.
32+
*/
1633

17-
/* CHECK ME: The below prioritizes store exceptions over load tag stripping. */
34+
(PTW_LOAD_CAP_CLR, PTE_STORE_CAP_ERR) => PTW_STORE_CAP_ERR,
35+
(PTW_LOAD_CAP_CLR, PTE_STORE_CAP_TRAP) => PTW_LOAD_CAP_TRAP,
36+
(PTW_LOAD_CAP_CLR, _) => PTW_LOAD_CAP_CLR,
1837

19-
(PTW_LOAD_CAP_ERR, PTE_CAP_OK) => PTW_LOAD_CAP_ERR,
20-
(PTW_LOAD_CAP_ERR, PTE_LOAD_CAP_ERR) => PTW_LOAD_CAP_ERR,
21-
(PTW_LOAD_CAP_ERR, PTE_STORE_CAP_ERR) => PTW_STORE_CAP_ERR,
38+
(PTW_LOAD_CAP_TRAP, PTE_STORE_CAP_ERR) => PTW_STORE_CAP_ERR,
39+
(PTW_LOAD_CAP_TRAP, _) => PTW_LOAD_CAP_TRAP,
2240

23-
(PTW_STORE_CAP_ERR, _ ) => PTW_STORE_CAP_ERR
41+
(PTW_STORE_CAP_ERR, _ ) => PTW_STORE_CAP_ERR
2442
}
2543

2644
/* Address translation errors */

src/cheri_sys_regs.sail

+2
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55
bitfield ccsr : xlenbits = {
66
cap_idx : 15 .. 10,
77
cause : 9 .. 5, /* cap cause */
8+
gclgu : 3, /* Global Cap Load Gen bit for User pages */
9+
gclgs : 2, /* Global Cap Load Gen bit for System (not User) pages */
810
d : 1, /* dirty */
911
e : 0 /* enable */
1012
}

src/cheri_types.sail

+6-3
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,8 @@ enum CapEx = {
7979
CapEx_PermitCCallViolation,
8080
CapEx_AccessCCallIDCViolation,
8181
CapEx_PermitUnsealViolation,
82-
CapEx_PermitSetCIDViolation
82+
CapEx_PermitSetCIDViolation,
83+
CapEx_CapLoadGen
8384
}
8485

8586
function CapExCode(ex) : CapEx -> bits(5) =
@@ -108,7 +109,8 @@ function CapExCode(ex) : CapEx -> bits(5) =
108109
CapEx_PermitCCallViolation => 0b11001,
109110
CapEx_AccessCCallIDCViolation => 0b11010,
110111
CapEx_PermitUnsealViolation => 0b11011,
111-
CapEx_PermitSetCIDViolation => 0b11100
112+
CapEx_PermitSetCIDViolation => 0b11100,
113+
CapEx_CapLoadGen => 0b11101
112114
}
113115

114116
function string_of_capex (ex) : CapEx -> string =
@@ -137,7 +139,8 @@ function string_of_capex (ex) : CapEx -> string =
137139
CapEx_PermitCCallViolation => "PermitCCallViolation" ,
138140
CapEx_AccessCCallIDCViolation => "AccessCCallIDCViolation" ,
139141
CapEx_PermitUnsealViolation => "PermitUnsealViolation" ,
140-
CapEx_PermitSetCIDViolation => "PermitSetCIDViolation"
142+
CapEx_PermitSetCIDViolation => "PermitSetCIDViolation" ,
143+
CapEx_CapLoadGen => "CapLoadGen"
141144
}
142145

143146
type capreg_idx = bits(6)

0 commit comments

Comments
 (0)