Skip to content

Commit c913739

Browse files
committed
PTEs are invalid if reserved bits are non-zero
This has only been the case since version 1.12 of the spec, so I added support for setting the spec version. It isn't exposed on the command line yet since hopefully we'll be using the new config system soon.
1 parent 601f3d8 commit c913739

File tree

4 files changed

+57
-24
lines changed

4 files changed

+57
-24
lines changed

model/riscv_extensions.sail

+7
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,13 @@ scattered enum extension
1111
// Note, these are sorted according to the canonical ordering vaguely described
1212
// in the `Subset Naming Convention` section of the unprivileged spec.
1313

14+
// Machine and Supervisor Architectures v1.11
15+
enum clause extension = Ext_Sx1p11
16+
// Machine and Supervisor Architectures v1.12
17+
enum clause extension = Ext_Sx1p12
18+
// Machine and Supervisor Architectures v1.13
19+
enum clause extension = Ext_Sx1p13
20+
1421
// Integer Multiplication and Division; not Machine!
1522
enum clause extension = Ext_M
1623
// Single-Precision Floating-Point

model/riscv_types.sail

+10
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,16 @@
1616
val extensionEnabled : extension -> bool
1717
scattered function extensionEnabled
1818

19+
// Priv/unpriv spec version.
20+
// TODO: Replace the `true`s with configuration flags.
21+
22+
// Machine and Supervisor Architectures v1.11
23+
function clause extensionEnabled(Ext_Sx1p11) = true
24+
// Machine and Supervisor Architectures v1.12
25+
function clause extensionEnabled(Ext_Sx1p12) = extensionEnabled(Ext_Sx1p11) | true
26+
// Machine and Supervisor Architectures v1.13
27+
function clause extensionEnabled(Ext_Sx1p13) = extensionEnabled(Ext_Sx1p12) | true
28+
1929
/* this value is only defined for the runtime platform for ELF loading
2030
* checks, and not used in the model.
2131
*/

model/riscv_vmem.sail

+6-4
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,9 @@ function pt_walk(sv_params,
115115
let pte : bits(64) = zero_extend(pte);
116116

117117
let pte_flags = Mk_PTE_Flags(pte[7 .. 0]);
118-
if pte_is_invalid(pte_flags) then
118+
let ext_pte = ext_bits_of_PTE(sv_params, pte);
119+
120+
if pte_is_invalid(pte_flags, ext_pte) then
119121
PTW_Failure(PTW_Invalid_PTE(), ext_ptw)
120122
else {
121123
let ppns : bits(64) = PPNs_of_PTE(sv_params, pte);
@@ -135,7 +137,7 @@ function pt_walk(sv_params,
135137
}
136138
else {
137139
// Leaf PTE
138-
let ext_pte = msbs_of_PTE(sv_params, pte);
140+
let ext_pte = ext_bits_of_PTE(sv_params, pte);
139141
let pte_check = check_PTE_permission(ac, priv, mxr, do_sum, pte_flags,
140142
ext_pte, ext_ptw);
141143
match pte_check {
@@ -296,7 +298,7 @@ function translate_TLB_hit(sv_params : SV_Params,
296298
ent : TLB_Entry)
297299
-> TR_Result(bits(64), PTW_Error) = {
298300
let pte = ent.pte;
299-
let ext_pte = msbs_of_PTE(sv_params, pte);
301+
let ext_pte = ext_bits_of_PTE(sv_params, pte);
300302
let pte_flags = Mk_PTE_Flags(pte[7 .. 0]);
301303
let pte_check = check_PTE_permission(ac, priv, mxr, do_sum, pte_flags,
302304
ext_pte,
@@ -345,7 +347,7 @@ function translate_TLB_miss(sv_params : SV_Params,
345347
match ptw_result {
346348
PTW_Failure(f, ext_ptw) => TR_Failure(f, ext_ptw),
347349
PTW_Success(pAddr, pte, pteAddr, level, global, ext_ptw) => {
348-
let ext_pte = msbs_of_PTE(sv_params, pte);
350+
let ext_pte = ext_bits_of_PTE(sv_params, pte);
349351
// Without TLBs, this 'match' expression can be replaced simply
350352
// by: 'TR_Address(pAddr, ext_ptw)' (see TLB_NOTE above)
351353
match update_PTE_Bits(sv_params, pte, ac) {

model/riscv_vmem_pte.sail

+34-20
Original file line numberDiff line numberDiff line change
@@ -19,21 +19,6 @@
1919

2020
type pte_flags_bits = bits(8)
2121

22-
// For PTW extensions (non-standard)
23-
type extPte = bits(64)
24-
25-
// PRIVATE: extract msbs of PTE above the PPN
26-
function msbs_of_PTE(sv_params : SV_Params, pte : bits(64)) -> bits(64) = {
27-
let mask : bits(64) = zero_extend(ones(sv_params.pte_msbs_size_bits));
28-
(pte >> sv_params.pte_msbs_lsb_index) & mask
29-
}
30-
31-
// PRIVATE: extract PPNs of PTE
32-
function PPNs_of_PTE(sv_params : SV_Params, pte : bits(64)) -> bits(64) = {
33-
let mask : bits(64) = zero_extend(ones(sv_params.pte_PPNs_size_bits));
34-
(pte >> sv_params.pte_PPNs_lsb_index) & mask
35-
}
36-
3722
// PRIVATE: 8 LSBs of PTEs in Sv32, Sv39, Sv48 and Sv57
3823
bitfield PTE_Flags : pte_flags_bits = {
3924
D : 7, // dirty
@@ -46,21 +31,50 @@ bitfield PTE_Flags : pte_flags_bits = {
4631
V : 0 // Valid
4732
}
4833

34+
/* Reserved PTE bits could be used by extensions on RV64. There are
35+
* no such available bits on RV32, so these bits will be zeros on RV32.
36+
*/
37+
type pte_ext_bits = bits(10)
38+
39+
bitfield PTE_Ext : pte_ext_bits = {
40+
N : 9, /* NAPOT page table entry */
41+
PBMT : 8 .. 7, /* Page based memory types */
42+
reserved : 6 .. 0,
43+
}
44+
45+
// PRIVATE: extract msbs of PTE above the PPN
46+
function ext_bits_of_PTE(sv_params : SV_Params, pte : bits(64)) -> PTE_Ext = {
47+
Mk_PTE_Ext(if sv_params.log_pte_size_bytes == 3 then pte[63 .. 54] else zeros())
48+
}
49+
50+
// PRIVATE: extract PPNs of PTE
51+
function PPNs_of_PTE(sv_params : SV_Params, pte : bits(64)) -> bits(64) = {
52+
let mask : bits(64) = zero_extend(ones(sv_params.pte_PPNs_size_bits));
53+
(pte >> sv_params.pte_PPNs_lsb_index) & mask
54+
}
55+
4956
// PRIVATE: check if a PTE is a pointer to next level (non-leaf)
5057
function pte_is_ptr(pte_flags : PTE_Flags) -> bool = (pte_flags[X] == 0b0)
5158
& (pte_flags[W] == 0b0)
5259
& (pte_flags[R] == 0b0)
5360

5461
// PRIVATE: check if a PTE is valid
55-
function pte_is_invalid(pte_flags : PTE_Flags) -> bool = (pte_flags[V] == 0b0)
56-
| ((pte_flags[W] == 0b1)
57-
& (pte_flags[R] == 0b0))
62+
function pte_is_invalid(pte_flags : PTE_Flags, pte_ext : PTE_Ext) -> bool =
63+
pte_flags[V] == 0b0
64+
| (pte_flags[W] == 0b1 & pte_flags[R] == 0b0)
65+
// Since version 1.12 of the spec, reserved bits must be zero.
66+
| extensionEnabled(Ext_Sx1p12) & (
67+
// If this is a non-leaf page, A/D/U bits are reserved
68+
pte_is_ptr(pte_flags) & (pte_flags[A] @ pte_flags[D] @ pte_flags[U] != zeros())
69+
// `pte_ext` contains bits for Svnapot and Svpbmt but these are not implemented yet.
70+
| pte_ext.bits != zeros()
71+
)
5872

5973
// ----------------
6074
// Check access permissions in PTE
6175

6276
// For (non-standard) extensions: this function gets the extension-available bits
63-
// of the PTE in extPte, and the accumulated information of the page-table-walk
77+
// of the PTE in PTE_Ext, and the accumulated information of the page-table-walk
6478
// in ext_ptw. It should return the updated ext_ptw in both success and failure cases.
6579

6680
union PTE_Check = {
@@ -74,7 +88,7 @@ function check_PTE_permission(ac : AccessType(ext_access_type),
7488
mxr : bool,
7589
do_sum : bool,
7690
pte_flags : PTE_Flags,
77-
ext : extPte,
91+
ext : PTE_Ext,
7892
ext_ptw : ext_ptw) -> PTE_Check = {
7993
let pte_U = pte_flags[U];
8094
let pte_R = pte_flags[R];

0 commit comments

Comments
 (0)