Skip to content

Commit e6c8ede

Browse files
nwf-msrjrtc27
andcommitted
Introduce load-capability generation traps
Co-authored-by: Jessica Clarke <[email protected]>
1 parent 4349937 commit e6c8ede

File tree

4 files changed

+109
-22
lines changed

4 files changed

+109
-22
lines changed

src/cheri_insts.sail

+41-14
Original file line numberDiff line numberDiff line change
@@ -1376,11 +1376,25 @@ function handle_load_cap_via_cap(cd, auth_idx, auth_val, vaddrBits) = {
13761376
let c = mem_read_cap(addr, aq, rl, false);
13771377
match c {
13781378
MemValue(v) => {
1379-
let cr = if ptw_info.ptw_lc == PTW_LC_CLEAR
1380-
then {v with tag = false} /* strip the tag */
1381-
else {v with tag = v.tag & auth_val.permit_load_cap};
1382-
C(cd) = cr;
1383-
RETIRE_SUCCESS
1379+
match ptw_info.ptw_lc {
1380+
PTW_LC_OK => {
1381+
C(cd) = { v with tag = v.tag & auth_val.permit_load_cap };
1382+
RETIRE_SUCCESS
1383+
},
1384+
PTW_LC_CLEAR => {
1385+
C(cd) = { v with tag = false };
1386+
RETIRE_SUCCESS
1387+
},
1388+
PTW_LC_TRAP => {
1389+
if v.tag then {
1390+
handle_mem_exception(vaddrBits, E_Extension(EXC_LOAD_CAP_PAGE_FAULT));
1391+
RETIRE_FAIL
1392+
} else {
1393+
C(cd) = v;
1394+
RETIRE_SUCCESS
1395+
}
1396+
}
1397+
}
13841398
},
13851399
MemException(e) => {handle_mem_exception(vaddrBits, e); RETIRE_FAIL }
13861400
}
@@ -1607,15 +1621,28 @@ if not(auth_val.tag) then {
16071621
let c = mem_read_cap(addr, aq, rl, false);
16081622
match c {
16091623
MemValue(v) => {
1610-
let cr = if ptw_info.ptw_lc == PTW_LC_CLEAR
1611-
then {v with tag = false} /* strip the tag */
1612-
else {
1613-
/* the Sail model currently reserves virtual addresses */
1614-
load_reservation(addr);
1615-
{v with tag = v.tag & auth_val.permit_load_cap}
1616-
};
1617-
C(cd) = cr;
1618-
RETIRE_SUCCESS
1624+
match ptw_info.ptw_lc {
1625+
PTW_LC_OK => {
1626+
load_reservation(addr);
1627+
C(cd) = { v with tag = v.tag & auth_val.permit_load_cap };
1628+
RETIRE_SUCCESS
1629+
},
1630+
PTW_LC_CLEAR => {
1631+
load_reservation(addr);
1632+
C(cd) = { v with tag = false };
1633+
RETIRE_SUCCESS
1634+
},
1635+
PTW_LC_TRAP => {
1636+
if v.tag then {
1637+
handle_mem_exception(vaddrBits, E_Extension(EXC_LOAD_CAP_PAGE_FAULT));
1638+
RETIRE_FAIL
1639+
} else {
1640+
load_reservation(addr);
1641+
C(cd) = v;
1642+
RETIRE_SUCCESS
1643+
}
1644+
}
1645+
}
16191646
},
16201647
MemException(e) => {handle_mem_exception(vaddrBits, e); RETIRE_FAIL }
16211648
}

src/cheri_pte.sail

+44-6
Original file line numberDiff line numberDiff line change
@@ -31,22 +31,39 @@ bitfield PTE_Bits : pteAttribs = {
3131
* state cached and then observe a CW=1 CD=1 PTE, no PTE write is necessary.
3232
* On the other hand, if CW=0 is observed, the store operation must trap.
3333
*
34+
* The intended semantics for capability loads are as follows.
35+
*
36+
* CR CR_Mod CR_Gen Action
37+
*
38+
* 0 0 0 Capability loads strip tags
39+
* 0 1 0 Capability loads trap (on set tag)
40+
* 0 X 1 [Reserved]
41+
*
42+
* 1 0 0 Capability loads succeed: no traps or tag clearing
43+
* 1 0 1 [Reserved]
44+
* 1 1 G Capability loads trap if G mismatches sccsr.[su]gclg,
45+
* where the compared bit is keyed off of this PTE's U.
46+
*
3447
* SV32: There are no extension bits available, so we hard-code the result to
35-
* CW=1 CR=1 CD=1.
48+
* CW=1 CR=1 CD=1 CR_Mod=0 CR_Gen=0
3649
*/
3750
type extPte = bits(10)
3851

3952
bitfield Ext_PTE_Bits : extPte = {
4053
CapWrite : 9, /* Permit capability stores */
4154
CapRead : 8, /* Permit capability loads */
4255
CapDirty : 7, /* Capability Dirty flag */
56+
CapRead_Mod : 6, /* Modify capability load prohibition; see above table */
57+
CapRead_Gen : 5, /* When load-cap gens. are in use, the "local" gen. bit */
4358
}
4459

4560
/*
4661
* CapWrite = 1,
4762
* CapRead = 1,
4863
* CapDirty = 1,
49-
* bits 0 .. 6 = 0
64+
* CapRead_Mod = 0,
65+
* CapRead_Gen = 0,
66+
* bits 0 .. 4 = 0
5067
*/
5168
let default_sv32_ext_pte : extPte = 0b1110000000
5269

@@ -57,7 +74,10 @@ function isPTEPtr(p : pteAttribs, ext : extPte) -> bool = {
5774

5875
function isInvalidPTE(p : pteAttribs, ext : extPte) -> bool = {
5976
let a = Mk_PTE_Bits(p);
60-
a.V() == 0b0 | (a.W() == 0b1 & a.R() == 0b0)
77+
let e = Mk_Ext_PTE_Bits(ext);
78+
a.V() == 0b0 | (a.W() == 0b1 & a.R() == 0b0) |
79+
(e.CapRead() == 0b0 & e.CapRead_Gen() == 0b1) |
80+
(e.CapRead() == 0b1 & e.CapRead_Gen() == 0b1 & e.CapRead_Mod() == 0b0)
6181
}
6282

6383
union PTE_Check = {
@@ -73,6 +93,25 @@ function checkPTEPermission_SC(e, ext_ptw) = {
7393
else PTE_Check_Failure(ext_ptw, EPTWF_CAP_ERR)
7494
}
7595

96+
/*
97+
* Assuming we're allowed to load from this page, modulate our cap response
98+
*/
99+
val checkPTEPermission_LC : (PTE_Bits, Ext_PTE_Bits, ext_ptw) -> PTE_Check effect { escape, rreg }
100+
function checkPTEPermission_LC(p, e, ext_ptw) =
101+
match (e.CapRead(), e.CapRead_Mod(), e.CapRead_Gen()) {
102+
(0b0, 0b0, 0b0) => PTE_Check_Success(ext_ptw_lc_join(ext_ptw, PTW_LC_CLEAR)), /* Clear tag for "unmodified" no-LC case */
103+
(0b0, 0b1, 0b0) => PTE_Check_Success(ext_ptw_lc_join(ext_ptw, PTW_LC_TRAP)), /* Trap on tag load for "modified" no-LC case */
104+
(0b0, _ , 0b1) => internal_error("Bad PTE not caught by isInvalidPTE"),
105+
(0b1, 0b0, 0b0) => PTE_Check_Success(ext_ptw_lc_join(ext_ptw, PTW_LC_OK)), /* Unmodified LC case: go ahead */
106+
(0b1, 0b0, 0b1) => internal_error("Bad PTE not caught by isInvalidPTE"),
107+
(0b1, 0b1, lclg) => {
108+
/* Compare local CLG against the pte.U-selected, not mode-selected, global CLG bit */
109+
let gclg : bits(1) = if p.U() == 0b1 then sccsr.ugclg() else sccsr.sgclg();
110+
let ptwl = if lclg == gclg then PTW_LC_OK else PTW_LC_TRAP;
111+
PTE_Check_Success(ext_ptw_lc_join(ext_ptw, ptwl))
112+
}
113+
}
114+
76115
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 = {
77116
/*
78117
* Although in many cases MXR doesn't make sense for capabilities, we honour
@@ -123,7 +162,6 @@ function checkPTEPermission(ac : AccessType(ext_access_type), priv : Privilege,
123162
};
124163

125164
/* Load side */
126-
let ptw_lc = if e.CapRead() == 0b1 then PTW_LC_OK else PTW_LC_CLEAR;
127165
let res : PTE_Check = match res {
128166
PTE_Check_Failure(_, _) => res,
129167
PTE_Check_Success(ext_ptw) => match ac {
@@ -132,8 +170,8 @@ function checkPTEPermission(ac : AccessType(ext_access_type), priv : Privilege,
132170
Write(_) => res,
133171
ReadWrite(Data, _) => res,
134172

135-
Read(Cap) => PTE_Check_Success(ext_ptw_lc_join(ext_ptw, ptw_lc)),
136-
ReadWrite(Cap, _) => PTE_Check_Success(ext_ptw_lc_join(ext_ptw, ptw_lc))
173+
Read(Cap) => checkPTEPermission_LC(p, e, ext_ptw),
174+
ReadWrite(Cap, _) => checkPTEPermission_LC(p, e, ext_ptw)
137175
}
138176
};
139177

src/cheri_riscv_types.sail

+10-2
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,10 @@ enum ext_ptw_lc = {
1010
PTW_LC_OK,
1111

1212
/* PTE settings require clearing tags */
13-
PTW_LC_CLEAR
13+
PTW_LC_CLEAR,
14+
15+
/* PTE settings require us to trap */
16+
PTW_LC_TRAP
1417
}
1518

1619
struct ext_ptw = {
@@ -21,7 +24,12 @@ function ext_ptw_lc_join(e : ext_ptw, l : ext_ptw_lc) -> ext_ptw =
2124
{ e with ptw_lc =
2225
match l {
2326
PTW_LC_OK => e.ptw_lc,
24-
PTW_LC_CLEAR => l
27+
PTW_LC_CLEAR => match e.ptw_lc {
28+
PTW_LC_OK => PTW_LC_CLEAR,
29+
PTW_LC_CLEAR => PTW_LC_CLEAR,
30+
PTW_LC_TRAP => PTW_LC_TRAP
31+
},
32+
PTW_LC_TRAP => PTW_LC_TRAP
2533
}
2634
}
2735

src/cheri_sys_regs.sail

+14
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
/* Capability control csr */
44

55
bitfield ccsr : xlenbits = {
6+
ugclg : 3, /* Global Cap Load Gen bit for User pages */
7+
sgclg : 2, /* Global Cap Load Gen bit for System (not User) pages */
68
d : 1, /* dirty */
79
e : 0 /* enable */
810
}
@@ -16,6 +18,18 @@ function legalize_ccsr(csrp : Privilege, c : ccsr, v : xlenbits) -> ccsr = {
1618
// write only the defined bits, leaving the other bits untouched
1719
let v = Mk_ccsr(v);
1820

21+
let c : ccsr = match csrp {
22+
User => {
23+
// No bits defined for uccsr
24+
c
25+
},
26+
_ => {
27+
let c = update_ugclg(c, v.ugclg());
28+
let c = update_sgclg(c, v.sgclg());
29+
c
30+
}
31+
};
32+
1933
/* For now these bits are not really supported so hardwired to true */
2034
let c = update_d(c, 0b1);
2135
let c = update_e(c, 0b1);

0 commit comments

Comments
 (0)