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