11
11
// including PTWs (Page Table Walks) and TLBs (Translation Look-aside Buffers)
12
12
// Supported VM modes: Sv32, Sv39, Sv48, Sv57
13
13
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
+
14
19
// STYLE NOTES:
15
20
// PRIVATE items are used only within this VM code.
16
21
// PUBLIC items are invoked from other parts of sail-riscv.
@@ -72,6 +77,7 @@ val pt_walk : forall 'v, is_sv_mode('v) . (
72
77
ext_ptw // ext_ptw
73
78
) -> PTW_Result('v)
74
79
80
+ // Steps 2-8 of the VATP.
75
81
function pt_walk(
76
82
sv_width,
77
83
vpn,
@@ -100,49 +106,52 @@ function pt_walk(
100
106
assert(sv_width == 32 | xlen == 64);
101
107
let pte_addr = Physaddr(zero_extend(pte_addr));
102
108
103
- // Read this-level PTE from mem
109
+ // Read this-level PTE from mem (Step 2 of VATP)
104
110
match read_pte(pte_addr, 2 ^ log_pte_size_bytes) {
105
111
Err(_) => PTW_Failure(PTW_Access(), ext_ptw),
106
112
Ok(pte) => {
107
113
let pte_flags = Mk_PTE_Flags(pte[7 .. 0]);
108
114
let pte_ext = ext_bits_of_PTE(pte);
109
115
110
116
if pte_is_invalid(pte_flags, pte_ext) then
117
+ // Step 3 of VATP.
111
118
PTW_Failure(PTW_Invalid_PTE(), ext_ptw)
112
119
else {
120
+ // Step 4 of VATP.
113
121
let ppn = PPN_of_PTE(pte); // 22 or 44.
114
122
let global = global | (pte_flags[G] == 0b1);
115
123
if pte_is_non_leaf(pte_flags) then {
116
124
// Non-Leaf PTE
117
125
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)
119
127
pt_walk(sv_width, vpn, ac, priv, mxr, do_sum, ppn, level - 1, global, ext_ptw)
120
128
else
121
129
// level 0 PTE, but contains a pointer instead of a leaf
122
130
PTW_Failure(PTW_Invalid_PTE(), ext_ptw)
123
131
} 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) {
128
142
PTE_Check_Failure(ext_ptw, ext_ptw_fail) =>
129
143
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
134
148
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]
143
150
} 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
+ }
146
155
}
147
156
}
148
157
}
@@ -225,12 +234,11 @@ function translate_TLB_hit forall 'v, is_sv_mode('v) . (
225
234
) -> TR_Result(ppn_bits('v), PTW_Error) = {
226
235
227
236
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.
229
238
let ext_pte = ext_bits_of_PTE(pte);
230
239
let pte_flags = Mk_PTE_Flags(pte[7 .. 0]);
231
240
let pte_check = check_PTE_permission(ac, priv, mxr, do_sum, pte_flags,
232
- ext_pte,
233
- ext_ptw);
241
+ ext_pte, ext_ptw);
234
242
235
243
match pte_check {
236
244
PTE_Check_Failure(ext_ptw, ext_ptw_fail) =>
@@ -239,6 +247,7 @@ function translate_TLB_hit forall 'v, is_sv_mode('v) . (
239
247
match update_PTE_Bits(pte, ac) {
240
248
None() => TR_Address(tlb_get_ppn(sv_width, ent, vpn), ext_ptw),
241
249
Some(pte') =>
250
+ // Step 9 of VATP. See riscv_platform.sail.
242
251
if not(plat_enable_dirty_update()) then
243
252
// pte needs dirty/accessed update but that is not enabled
244
253
TR_Failure(PTW_PTE_Update(), ext_ptw)
@@ -248,7 +257,7 @@ function translate_TLB_hit forall 'v, is_sv_mode('v) . (
248
257
match write_pte(ent.pteAddr, pte_width, pte') {
249
258
Ok(_) => (),
250
259
Err(e) => internal_error(__FILE__, __LINE__,
251
- "invalid physical address in TLB")
260
+ "invalid physical address in TLB")
252
261
};
253
262
TR_Address(tlb_get_ppn(sv_width, ent, vpn), ext_ptw)
254
263
}
@@ -270,13 +279,14 @@ function translate_TLB_miss forall 'v, is_sv_mode('v) . (
270
279
) -> TR_Result(ppn_bits('v), PTW_Error) = {
271
280
let initial_level = if 'v == 32 then 1 else (if 'v == 39 then 2 else (if 'v == 48 then 3 else 4));
272
281
282
+ // Step 2 of VATP occurs in pt_walk().
273
283
let 'pte_width = if sv_width == 32 then 4 else 8;
274
284
let ptw_result = pt_walk(sv_width, vpn, ac, priv, mxr, do_sum,
275
285
base_ppn, initial_level, false, ext_ptw);
276
286
match ptw_result {
277
287
PTW_Failure(f, ext_ptw) => TR_Failure(f, ext_ptw),
278
288
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);
280
290
// Without TLBs, this 'match' expression can be replaced simply
281
291
// by: 'TR_Address(ppn, ext_ptw)' (see TLB NOTE above)
282
292
match update_PTE_Bits(pte, ac) {
@@ -285,7 +295,7 @@ function translate_TLB_miss forall 'v, is_sv_mode('v) . (
285
295
TR_Address(ppn, ext_ptw)
286
296
},
287
297
Some(pte) =>
288
- // See riscv_platform.sail
298
+ // Step 9 of VATP. See riscv_platform.sail.
289
299
if not(plat_enable_dirty_update()) then
290
300
// pte needs dirty/accessed update but that is not enabled
291
301
TR_Failure(PTW_PTE_Update(), ext_ptw)
@@ -377,8 +387,11 @@ function translateAddr(
377
387
} else {
378
388
let mxr = mstatus[MXR] == 0b1;
379
389
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.
381
393
let base_ppn = satp_to_ppn(satp_sxlen);
394
+
382
395
let res = translate(sv_width,
383
396
zero_extend(asid),
384
397
base_ppn,
@@ -388,6 +401,7 @@ function translateAddr(
388
401
// Fixup result PA or exception
389
402
match res {
390
403
TR_Address(ppn, ext_ptw) => {
404
+ // Step 10 of VATP.
391
405
// Append the page offset. This is now a 34 or 56 bit address.
392
406
let paddr = ppn @ virtaddr_bits(vAddr)[pagesize_bits - 1 .. 0];
393
407
0 commit comments