Skip to content

Commit 0806ed5

Browse files
committed
More closely align address translation with the specification.
The specification has a numbered list of steps in the algorithm. The Sail version had implemented access permission checks (Steps 6,8) before the superpage alignment check (Step 5). This commit fixes the ordering. There is currently no functional difference between the two orders: all the steps involved raise page-faults corresponding to the access type; the only difference would be the error printed in the execution log. However, when shadow stack is implemented, it inserts a Step 7 that could raise an access-fault exception that would make the difference in step order visible. While here, mark in comments the steps of the algorithm for easier correlation with the prose spec.
1 parent adcca8e commit 0806ed5

File tree

2 files changed

+43
-27
lines changed

2 files changed

+43
-27
lines changed

model/riscv_vmem.sail

+41-27
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,11 @@
1111
// including PTWs (Page Table Walks) and TLBs (Translation Look-aside Buffers)
1212
// Supported VM modes: Sv32, Sv39, Sv48, Sv57
1313

14+
// The code below implements the steps in the "Virtual Address
15+
// Translation Process" (abbreviated here to VATP) section of the
16+
// Privileged Architecture specification. Code locations
17+
// corresponding to these steps are marked in the comments.
18+
1419
// STYLE NOTES:
1520
// PRIVATE items are used only within this VM code.
1621
// PUBLIC items are invoked from other parts of sail-riscv.
@@ -72,6 +77,7 @@ val pt_walk : forall 'v, is_sv_mode('v) . (
7277
ext_ptw // ext_ptw
7378
) -> PTW_Result('v)
7479

80+
// Steps 2-8 of the VATP.
7581
function pt_walk(
7682
sv_width,
7783
vpn,
@@ -100,49 +106,52 @@ function pt_walk(
100106
assert(sv_width == 32 | xlen == 64);
101107
let pte_addr = Physaddr(zero_extend(pte_addr));
102108

103-
// Read this-level PTE from mem
109+
// Read this-level PTE from mem (Step 2 of VATP)
104110
match read_pte(pte_addr, 2 ^ log_pte_size_bytes) {
105111
Err(_) => PTW_Failure(PTW_Access(), ext_ptw),
106112
Ok(pte) => {
107113
let pte_flags = Mk_PTE_Flags(pte[7 .. 0]);
108114
let pte_ext = ext_bits_of_PTE(pte);
109115

110116
if pte_is_invalid(pte_flags, pte_ext) then
117+
// Step 3 of VATP.
111118
PTW_Failure(PTW_Invalid_PTE(), ext_ptw)
112119
else {
120+
// Step 4 of VATP.
113121
let ppn = PPN_of_PTE(pte); // 22 or 44.
114122
let global = global | (pte_flags[G] == 0b1);
115123
if pte_is_non_leaf(pte_flags) then {
116124
// Non-Leaf PTE
117125
if level > 0 then
118-
// follow the pointer to walk next level
126+
// follow the pointer to walk next level (i.e., go to Step 2)
119127
pt_walk(sv_width, vpn, ac, priv, mxr, do_sum, ppn, level - 1, global, ext_ptw)
120128
else
121129
// level 0 PTE, but contains a pointer instead of a leaf
122130
PTW_Failure(PTW_Invalid_PTE(), ext_ptw)
123131
} else {
124-
// Leaf PTE
125-
let pte_check = check_PTE_permission(ac, priv, mxr, do_sum, pte_flags,
126-
pte_ext, ext_ptw);
127-
match pte_check {
132+
// Leaf PTE (Step 5 of VATP).
133+
let ppn_size_bits = if 'v == 32 then 10 else 9;
134+
if level > 0 then {
135+
// Check for misaligned superpage.
136+
let low_bits = ppn_size_bits * level;
137+
if ppn[low_bits - 1 .. 0] != zeros()
138+
then return PTW_Failure(PTW_Misaligned(), ext_ptw);
139+
};
140+
// Steps 6, 7 (TODO: shadow stack protection), 8 of VATP.
141+
match check_PTE_permission(ac, priv, mxr, do_sum, pte_flags, pte_ext, ext_ptw) {
128142
PTE_Check_Failure(ext_ptw, ext_ptw_fail) =>
129143
PTW_Failure(ext_get_ptw_error(ext_ptw_fail), ext_ptw),
130-
PTE_Check_Success(ext_ptw) =>
131-
if level > 0 then {
132-
// Superpage. Check it is correctly aligned.
133-
let ppn_size_bits = if 'v == 32 then 10 else 9;
144+
PTE_Check_Success(ext_ptw) => {
145+
let ppn = if level > 0 then {
146+
// Compose final PA in superpage:
147+
// Superpage PPN @ lower VPNs @ page-offset
134148
let low_bits = ppn_size_bits * level;
135-
if ppn[low_bits - 1 .. 0] != zeros() then
136-
PTW_Failure(PTW_Misaligned(), ext_ptw)
137-
else {
138-
// Compose final PA in superpage:
139-
// Superpage PPN @ lower VPNs @ page-offset
140-
let ppn = ppn[length(ppn) - 1 .. low_bits] @ vpn[low_bits - 1 .. 0];
141-
PTW_Success(struct { ppn=ppn, pte=pte, pteAddr=pte_addr, level=level, global=global}, ext_ptw)
142-
}
149+
ppn[length(ppn) - 1 .. low_bits] @ vpn[low_bits - 1 .. 0]
143150
} else {
144-
PTW_Success(struct { ppn=ppn, pte=pte, pteAddr=pte_addr, level=level, global=global}, ext_ptw)
145-
}
151+
ppn
152+
};
153+
PTW_Success(struct {ppn=ppn, pte=pte, pteAddr=pte_addr, level=level, global=global}, ext_ptw)
154+
}
146155
}
147156
}
148157
}
@@ -225,12 +234,11 @@ function translate_TLB_hit forall 'v, is_sv_mode('v) . (
225234
) -> TR_Result(ppn_bits('v), PTW_Error) = {
226235

227236
let pte_width = if sv_width == 32 then 4 else 8;
228-
let pte = tlb_get_pte(pte_width, ent);
237+
let pte = tlb_get_pte(pte_width, ent); // Step 2 of VATP.
229238
let ext_pte = ext_bits_of_PTE(pte);
230239
let pte_flags = Mk_PTE_Flags(pte[7 .. 0]);
231240
let pte_check = check_PTE_permission(ac, priv, mxr, do_sum, pte_flags,
232-
ext_pte,
233-
ext_ptw);
241+
ext_pte, ext_ptw);
234242

235243
match pte_check {
236244
PTE_Check_Failure(ext_ptw, ext_ptw_fail) =>
@@ -239,6 +247,7 @@ function translate_TLB_hit forall 'v, is_sv_mode('v) . (
239247
match update_PTE_Bits(pte, ac) {
240248
None() => TR_Address(tlb_get_ppn(sv_width, ent, vpn), ext_ptw),
241249
Some(pte') =>
250+
// Step 9 of VATP. See riscv_platform.sail.
242251
if not(plat_enable_dirty_update()) then
243252
// pte needs dirty/accessed update but that is not enabled
244253
TR_Failure(PTW_PTE_Update(), ext_ptw)
@@ -248,7 +257,7 @@ function translate_TLB_hit forall 'v, is_sv_mode('v) . (
248257
match write_pte(ent.pteAddr, pte_width, pte') {
249258
Ok(_) => (),
250259
Err(e) => internal_error(__FILE__, __LINE__,
251-
"invalid physical address in TLB")
260+
"invalid physical address in TLB")
252261
};
253262
TR_Address(tlb_get_ppn(sv_width, ent, vpn), ext_ptw)
254263
}
@@ -270,13 +279,14 @@ function translate_TLB_miss forall 'v, is_sv_mode('v) . (
270279
) -> TR_Result(ppn_bits('v), PTW_Error) = {
271280
let initial_level = if 'v == 32 then 1 else (if 'v == 39 then 2 else (if 'v == 48 then 3 else 4));
272281

282+
// Step 2 of VATP occurs in pt_walk().
273283
let 'pte_width = if sv_width == 32 then 4 else 8;
274284
let ptw_result = pt_walk(sv_width, vpn, ac, priv, mxr, do_sum,
275285
base_ppn, initial_level, false, ext_ptw);
276286
match ptw_result {
277287
PTW_Failure(f, ext_ptw) => TR_Failure(f, ext_ptw),
278288
PTW_Success(struct {ppn, pte, pteAddr, level, global}, ext_ptw) => {
279-
let ext_pte = ext_bits_of_PTE(pte);
289+
let ext_pte = ext_bits_of_PTE(pte);
280290
// Without TLBs, this 'match' expression can be replaced simply
281291
// by: 'TR_Address(ppn, ext_ptw)' (see TLB NOTE above)
282292
match update_PTE_Bits(pte, ac) {
@@ -285,7 +295,7 @@ function translate_TLB_miss forall 'v, is_sv_mode('v) . (
285295
TR_Address(ppn, ext_ptw)
286296
},
287297
Some(pte) =>
288-
// See riscv_platform.sail
298+
// Step 9 of VATP. See riscv_platform.sail.
289299
if not(plat_enable_dirty_update()) then
290300
// pte needs dirty/accessed update but that is not enabled
291301
TR_Failure(PTW_PTE_Update(), ext_ptw)
@@ -377,8 +387,11 @@ function translateAddr(
377387
} else {
378388
let mxr = mstatus[MXR] == 0b1;
379389
let do_sum = mstatus[SUM] == 0b1;
380-
let asid = satp_to_asid(satp_sxlen);
390+
let asid = satp_to_asid(satp_sxlen);
391+
392+
// Step 1 of VATP.
381393
let base_ppn = satp_to_ppn(satp_sxlen);
394+
382395
let res = translate(sv_width,
383396
zero_extend(asid),
384397
base_ppn,
@@ -388,6 +401,7 @@ function translateAddr(
388401
// Fixup result PA or exception
389402
match res {
390403
TR_Address(ppn, ext_ptw) => {
404+
// Step 10 of VATP.
391405
// Append the page offset. This is now a 34 or 56 bit address.
392406
let paddr = ppn @ virtaddr_bits(vAddr)[pagesize_bits - 1 .. 0];
393407

model/riscv_vmem_pte.sail

+2
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,8 @@ function check_PTE_permission(ac : AccessType(ext_access_type),
110110
let pte_X = pte_flags[X];
111111
let success : bool =
112112
match (ac, priv) {
113+
// Steps 6 and 8 of VATP, roughly (see riscv_vmem.sail).
114+
// (TODO: Step 7 awaits shadow stack implementation (Zicfiss).)
113115
(Read(_), User) => (pte_U == 0b1)
114116
& ((pte_R == 0b1)
115117
| ((pte_X == 0b1 & mxr))),

0 commit comments

Comments
 (0)