@@ -135,7 +135,123 @@ pub proof fn lemma_va_level_to_nid_inc(va: Vaddr, level: PagingLevel, nid: NodeI
135135 ensures
136136 NodeHelper :: get_child( nid, idx) == va_level_to_nid( va, level) ,
137137{
138- admit( ) ; // TODO
138+ // Establish the relationship between traces at consecutive levels
139+ let trace_level_plus_1 = va_level_to_trace( va, ( level + 1 ) as PagingLevel ) ;
140+ let trace_level = va_level_to_trace( va, level) ;
141+
142+ // Show that trace_level = trace_level_plus_1.push(idx)
143+ assert( trace_level == trace_level_plus_1. push( idx) ) by {
144+ // By definition: va_level_to_trace(va, level) = va_level_to_trace_rec(va >> 12, level)
145+ // And: va_level_to_trace_rec(va >> 12, level) = va_level_to_trace_rec(va >> 12, level + 1).push(((va >> 12 >> (level * 9)) & mask) as nat)
146+ // We need to show that ((va >> 12 >> (level * 9)) & mask) as nat == idx
147+ // Since idx = va_level_to_offset(va, level + 1) = ((va >> (12 + level * 9)) & mask) as nat
148+ // And (va >> 12 >> (level * 9)) = (va >> (12 + level * 9)) by bit shift properties
149+ // reveal(va_level_to_trace_rec);
150+ assert( va_level_to_trace_rec( va >> 12 , level) == va_level_to_trace_rec(
151+ va >> 12 ,
152+ ( level + 1 ) as PagingLevel ,
153+ ) . push( ( ( va >> 12 >> ( level * 9 ) ) & low_bits_mask( 9 ) as usize ) as nat) ) ;
154+
155+ // Show the bit extraction equivalence
156+ let offset = ( va >> 12 >> ( level * 9 ) ) & low_bits_mask( 9 ) as usize ;
157+ assert( offset as nat == idx) by {
158+ // va_level_to_offset(va, level + 1) = ((va >> (12 + ((level + 1) - 1) * 9)) & mask) as nat
159+ // = ((va >> (12 + level * 9)) & mask) as nat
160+ // We need to show: (va >> 12 >> (level * 9)) & mask == (va >> (12 + level * 9)) & mask
161+ // This follows from bit shift associativity: a >> b >> c == a >> (b + c)
162+ assert( low_bits_mask( 9 ) == 511 ) by {
163+ lemma_low_bits_mask_values( ) ;
164+ } ;
165+ assert( ( va >> 12 >> ( level * 9 ) ) == ( va >> ( 12 + level * 9 ) ) ) by ( bit_vector) ;
166+ assert( ( ( va >> 12 >> ( level * 9 ) ) & 511 as usize ) == ( ( va >> ( 12 + level * 9 ) )
167+ & 511 as usize ) ) by ( bit_vector) ;
168+ }
169+ } ;
170+
171+ // Now use the fact that nid = trace_to_nid(trace_level_plus_1)
172+ // and get_child(nid, idx) = trace_to_nid(nid_to_trace(nid).push(idx))
173+ assert( NodeHelper :: nid_to_trace( nid) == trace_level_plus_1) by {
174+ // First establish that trace_level_plus_1 is a valid trace
175+ assert( NodeHelper :: valid_trace( trace_level_plus_1) ) by {
176+ // trace_level_plus_1 = va_level_to_trace(va, level + 1)
177+ // Use the lemma that directly proves va_level_to_trace produces valid traces
178+ lemma_va_level_to_trace_valid( va, ( level + 1 ) as PagingLevel ) ;
179+ } ;
180+
181+ // Since nid = trace_to_nid(trace_level_plus_1) and trace_to_nid is bijective
182+ NodeHelper :: lemma_nid_to_trace_sound( nid) ;
183+ NodeHelper :: lemma_trace_to_nid_sound( trace_level_plus_1) ;
184+ // From the precondition: nid == va_level_to_nid(va, level + 1)
185+ // And va_level_to_nid(va, level + 1) == trace_to_nid(trace_level_plus_1)
186+ // So nid == trace_to_nid(trace_level_plus_1)
187+ // Since trace_to_nid is bijective, nid_to_trace(nid) == trace_level_plus_1
188+ assert( nid == NodeHelper :: trace_to_nid( trace_level_plus_1) ) ;
189+ assert( NodeHelper :: trace_to_nid( NodeHelper :: nid_to_trace( nid) ) == nid) ;
190+ assert( NodeHelper :: trace_to_nid( NodeHelper :: nid_to_trace( nid) ) == NodeHelper :: trace_to_nid(
191+ trace_level_plus_1,
192+ ) ) ;
193+ NodeHelper :: lemma_trace_to_nid_bijective( ) ;
194+ } ;
195+
196+ // Therefore get_child(nid, idx) = trace_to_nid(trace_level_plus_1.push(idx)) = trace_to_nid(trace_level)
197+ assert( NodeHelper :: get_child( nid, idx) == NodeHelper :: trace_to_nid(
198+ trace_level_plus_1. push( idx) ,
199+ ) ) ;
200+ assert( trace_level_plus_1. push( idx) == trace_level) ;
201+ assert( NodeHelper :: get_child( nid, idx) == NodeHelper :: trace_to_nid( trace_level) ) ;
202+ assert( NodeHelper :: trace_to_nid( trace_level) == va_level_to_nid( va, level) ) ;
203+ }
204+
205+ pub proof fn lemma_va_level_to_trace_rec_len( va: Vaddr , level: PagingLevel )
206+ requires
207+ 1 <= level <= 4 ,
208+ ensures
209+ va_level_to_trace_rec( va, level) . len( ) == 4 - level,
210+ decreases 4 - level,
211+ {
212+ if level < 4 {
213+ lemma_va_level_to_trace_rec_len( va, ( level + 1 ) as PagingLevel ) ;
214+ }
215+ }
216+
217+ pub proof fn lemma_va_level_to_trace_valid( va: Vaddr , level: PagingLevel )
218+ requires
219+ 1 <= level <= 4 ,
220+ ensures
221+ NodeHelper :: valid_trace( va_level_to_trace( va, level) ) ,
222+ {
223+ lemma_va_level_to_trace_rec_valid( va >> 12 , level) ;
224+ }
225+
226+ pub proof fn lemma_va_level_to_trace_rec_valid( va: Vaddr , level: PagingLevel )
227+ requires
228+ 1 <= level <= 4 ,
229+ ensures
230+ NodeHelper :: valid_trace( va_level_to_trace_rec( va, level) ) ,
231+ decreases 4 - level,
232+ {
233+ if level < 4 {
234+ lemma_va_level_to_trace_rec_valid( va, ( level + 1 ) as PagingLevel ) ;
235+ let offset = ( va >> ( level * 9 ) ) & low_bits_mask( 9 ) as usize ;
236+ assert( offset < 512 ) by {
237+ assert( low_bits_mask( 9 ) == 511 ) by {
238+ lemma_low_bits_mask_values( ) ;
239+ } ;
240+ assert( ( va >> ( level * 9 ) ) & 511 <= 511 ) by ( bit_vector) ;
241+ }
242+ // By inductive hypothesis, the recursive trace is valid
243+ assert( NodeHelper :: valid_trace( va_level_to_trace_rec( va, ( level + 1 ) as PagingLevel ) ) ) ;
244+ // Therefore its length is < 4
245+ assert( va_level_to_trace_rec( va, ( level + 1 ) as PagingLevel ) . len( ) < 4 ) ;
246+ // Since we add exactly one element, the new length is still < 4
247+ assert( va_level_to_trace_rec( va, level) . len( ) == va_level_to_trace_rec(
248+ va,
249+ ( level + 1 ) as PagingLevel ,
250+ ) . len( ) + 1 ) ;
251+ assert( va_level_to_trace_rec( va, ( level + 1 ) as PagingLevel ) . len( ) + 1 <= 3 ) by {
252+ lemma_va_level_to_trace_rec_len( va, ( level + 1 ) as PagingLevel ) ;
253+ } ;
254+ }
139255}
140256
141257} // verus!
0 commit comments