|
| 1 | +use std::ops::Range; |
| 2 | + |
| 3 | +use vstd::prelude::*; |
| 4 | +use vstd::vstd::arithmetic::power2::*; |
| 5 | +use vstd::arithmetic::div_mod::*; |
| 6 | +use vstd::arithmetic::power2::*; |
| 7 | +use vstd::bits::*; |
| 8 | + |
| 9 | +use crate::helpers::bits::*; |
| 10 | +use crate::helpers::extern_const::*; |
| 11 | +use crate::spec::{common::*, utils::*}; |
| 12 | + |
| 13 | +pub use super::configs::*; |
| 14 | +pub use crate::mm::{Paddr, Vaddr, PagingLevel}; |
| 15 | + |
| 16 | +verus! { |
| 17 | + |
| 18 | +// pub const MAX_FRAME_NUM: u64 = 256; |
| 19 | +pub const INVALID_PADDR: Paddr = 0xffff_ffff_ffff_ffff; |
| 20 | + |
| 21 | +// extern_const!( |
| 22 | +// pub MAX_RC [MAX_RC_SPEC, CONST_MAX_RC]: u64 = 382); |
| 23 | +} // verus! |
| 24 | +verus! { |
| 25 | + |
| 26 | +// Maybe introduce a MAX_PADDR constant in the future. |
| 27 | +pub open spec fn valid_paddr(pa: Paddr) -> bool { |
| 28 | + true |
| 29 | +} |
| 30 | + |
| 31 | +pub uninterp spec fn paddr_to_vaddr_spec(pa: Paddr) -> Vaddr; |
| 32 | + |
| 33 | +#[inline(always)] |
| 34 | +#[verifier::when_used_as_spec(paddr_to_vaddr_spec)] |
| 35 | +#[verifier::external_body] |
| 36 | +pub fn paddr_to_vaddr(pa: Paddr) -> (va: Vaddr) |
| 37 | +// requires |
| 38 | +// valid_paddr(pa), |
| 39 | + |
| 40 | + ensures |
| 41 | + va == paddr_to_vaddr_spec(pa), |
| 42 | +{ |
| 43 | + unimplemented!() |
| 44 | +} |
| 45 | + |
| 46 | +} // verus! |
| 47 | +verus! { |
| 48 | + |
| 49 | +pub open spec fn valid_vaddr(va: Vaddr) -> bool { |
| 50 | + 0 <= va < (1u64 << 48) |
| 51 | +} |
| 52 | + |
| 53 | +pub open spec fn valid_va_range(va: Range<Vaddr>) -> bool { |
| 54 | + 0 <= va.start <= va.end <= (1u64 << 48) |
| 55 | +} |
| 56 | + |
| 57 | +#[verifier::allow_in_spec] |
| 58 | +pub fn vaddr_is_aligned(va: Vaddr) -> (res: bool) |
| 59 | + requires |
| 60 | + valid_vaddr(va), |
| 61 | + returns |
| 62 | + (va & (low_bits_mask(12) as usize)) == 0, |
| 63 | +{ |
| 64 | + (va & low_bits_mask_usize(12)) == 0 |
| 65 | +} |
| 66 | + |
| 67 | +pub open spec fn va_level_to_offset(va: Vaddr, level: PagingLevel) -> nat |
| 68 | + recommends |
| 69 | + valid_vaddr(va), |
| 70 | + 1 <= level <= 4, |
| 71 | +{ |
| 72 | + ((va >> (12 + (level - 1) * 9)) & low_bits_mask(9) as usize) as nat |
| 73 | +} |
| 74 | + |
| 75 | +pub fn pte_index(va: Vaddr, level: PagingLevel) -> (res: usize) |
| 76 | + requires |
| 77 | + valid_vaddr(va), |
| 78 | + 1 <= level <= 4, |
| 79 | + ensures |
| 80 | + valid_pte_offset(res as nat), |
| 81 | + returns |
| 82 | + va_level_to_offset(va, level) as usize, |
| 83 | +{ |
| 84 | + let offset = (va >> (12 + (level - 1) * 9)) & low_bits_mask_usize(9); |
| 85 | + |
| 86 | + proof { |
| 87 | + lemma2_to64(); |
| 88 | + let num = (va >> (12 + (level - 1) * 9)); |
| 89 | + assert((num & 511) < 512) by (bit_vector); |
| 90 | + } |
| 91 | + |
| 92 | + offset |
| 93 | +} |
| 94 | + |
| 95 | +pub open spec fn va_level_to_trace(va: Vaddr, level: PagingLevel) -> Seq<nat> |
| 96 | + recommends |
| 97 | + 1 <= level <= 4, |
| 98 | +{ |
| 99 | + Seq::new((4 - level) as nat, |i| va_level_to_offset(va, (4 - i) as PagingLevel)) |
| 100 | +} |
| 101 | + |
| 102 | +pub open spec fn va_level_to_nid(va: Vaddr, level: PagingLevel) -> NodeId { |
| 103 | + NodeHelper::trace_to_nid(va_level_to_trace(va, level)) |
| 104 | +} |
| 105 | + |
| 106 | +pub proof fn lemma_va_level_to_nid_inc(va: Vaddr, level: PagingLevel, nid: NodeId, idx: nat) |
| 107 | + requires |
| 108 | + valid_vaddr(va), |
| 109 | + 1 <= level < 4, |
| 110 | + NodeHelper::valid_nid(nid), |
| 111 | + nid == va_level_to_nid(va, (level + 1) as PagingLevel), |
| 112 | + valid_pte_offset(idx), |
| 113 | + idx == va_level_to_offset(va, (level + 1) as PagingLevel), |
| 114 | + ensures |
| 115 | + NodeHelper::get_child(nid, idx) == va_level_to_nid(va, level), |
| 116 | +{ |
| 117 | + broadcast use group_node_helper_lemmas; |
| 118 | + // Establish the relationship between traces at consecutive levels |
| 119 | + |
| 120 | + let trace_level_plus_1 = va_level_to_trace(va, (level + 1) as PagingLevel); |
| 121 | + let trace_level = va_level_to_trace(va, level); |
| 122 | + |
| 123 | + // Show that trace_level = trace_level_plus_1.push(idx) |
| 124 | + assert(trace_level == trace_level_plus_1.push(idx)); |
| 125 | + |
| 126 | + // Now use the fact that nid = trace_to_nid(trace_level_plus_1) |
| 127 | + // and get_child(nid, idx) = trace_to_nid(nid_to_trace(nid).push(idx)) |
| 128 | + assert(NodeHelper::nid_to_trace(nid) == trace_level_plus_1) by { |
| 129 | + // First establish that trace_level_plus_1 is a valid trace |
| 130 | + assert(NodeHelper::valid_trace(trace_level_plus_1)) by { |
| 131 | + lemma_va_level_to_trace_valid(va, (level + 1) as PagingLevel); |
| 132 | + }; |
| 133 | + NodeHelper::lemma_trace_to_nid_bijective(); |
| 134 | + }; |
| 135 | +} |
| 136 | + |
| 137 | +pub proof fn lemma_va_level_to_offset_range(va: Vaddr, level: PagingLevel) |
| 138 | + requires |
| 139 | + 1 <= level <= 4, |
| 140 | + ensures |
| 141 | + 0 <= va_level_to_offset(va, level) < 512, |
| 142 | +{ |
| 143 | + let offset = va_level_to_offset(va, level); |
| 144 | + assert(offset < 512) by { |
| 145 | + assert(low_bits_mask(9) == 511) by { |
| 146 | + lemma_low_bits_mask_values(); |
| 147 | + }; |
| 148 | + assert((va >> (12 + (level - 1) as usize * 9)) & 511 <= 511) by (bit_vector); |
| 149 | + } |
| 150 | +} |
| 151 | + |
| 152 | +pub proof fn lemma_va_level_to_trace_valid(va: Vaddr, level: PagingLevel) |
| 153 | + requires |
| 154 | + 1 <= level <= 4, |
| 155 | + ensures |
| 156 | + NodeHelper::valid_trace(va_level_to_trace(va, level)), |
| 157 | + decreases 4 - level, |
| 158 | +{ |
| 159 | + if level < 4 { |
| 160 | + lemma_va_level_to_trace_valid(va, (level + 1) as PagingLevel); |
| 161 | + lemma_va_level_to_offset_range(va, (level + 1) as PagingLevel); |
| 162 | + assert(va_level_to_trace(va, level) == va_level_to_trace( |
| 163 | + va, |
| 164 | + (level + 1) as PagingLevel, |
| 165 | + ).push(va_level_to_offset(va, (level + 1) as PagingLevel))); |
| 166 | + } |
| 167 | +} |
| 168 | + |
| 169 | +} // verus! |
0 commit comments