ostd/specs/mm/embedding/
segment.rs1use vstd::prelude::*;
33use vstd_extra::ownership::*;
34
35use core::ops::Range;
36
37use crate::mm::frame::has_safe_slot;
38use crate::mm::vm_space::UserPtConfig;
39use crate::mm::Paddr;
40use crate::specs::arch::mm::{MAX_PADDR, PAGE_SIZE};
41use crate::specs::mm::frame::mapping::frame_to_index;
42use crate::specs::mm::frame::meta_owners::{PageUsage, REF_COUNT_UNUSED};
43use crate::specs::mm::frame::meta_region_owners::MetaRegionOwners;
44use crate::specs::mm::page_table::cursor::owners::CursorOwner;
45
46use super::{axiom_segment_entry_new, SegmentEntry};
47
48verus! {
49
50pub axiom fn segment_from_unused_embedded(
70 tracked regions: &mut MetaRegionOwners,
71 range: Range<Paddr>,
72) -> (res: Option<()>)
73 requires
74 old(regions).inv(),
75 range.start % PAGE_SIZE == 0,
76 range.end % PAGE_SIZE == 0,
77 range.start < range.end,
78 range.end <= MAX_PADDR,
79 forall|paddr: Paddr|
82 #![trigger frame_to_index(paddr)]
83 (range.start <= paddr < range.end && paddr % PAGE_SIZE == 0)
84 ==> old(regions).slot_owners[frame_to_index(paddr)]
85 .inner_perms.ref_count.value() == REF_COUNT_UNUSED,
86 forall|paddr: Paddr|
87 #![trigger frame_to_index(paddr)]
88 (range.start <= paddr < range.end && paddr % PAGE_SIZE == 0)
89 ==> old(regions).slots.contains_key(frame_to_index(paddr)),
90 ensures
91 final(regions).inv(),
92 final(regions).slots =~= old(regions).slots,
94 res is Some ==> forall|paddr: Paddr|
97 #![trigger frame_to_index(paddr)]
98 (range.start <= paddr < range.end && paddr % PAGE_SIZE == 0)
99 ==> {
100 let idx = frame_to_index(paddr);
101 let so = final(regions).slot_owners[idx];
102 &&& so.usage == PageUsage::Frame
103 &&& so.inner_perms.ref_count.value() == 1
104 &&& so.paths_in_pt.is_empty()
105 &&& so.inner_perms.in_list.value() == 0
106 &&& so.inner_perms.storage.is_init()
107 },
108 res is Some ==> forall|i: usize|
110 #![trigger final(regions).slot_owners[i]]
111 i < crate::specs::mm::frame::mapping::max_meta_slots()
112 && !(range.start <= crate::specs::mm::frame::mapping::index_to_frame(i)
113 < range.end)
114 ==> final(regions).slot_owners[i] == old(regions).slot_owners[i],
115 res is None ==> *final(regions) == *old(regions),
117 forall|c: CursorOwner<'_, UserPtConfig>| #![auto]
120 c.metaregion_sound(*old(regions)) ==> c.metaregion_sound(*final(regions)),
121;
122
123pub axiom fn segment_drop_embedded(
139 tracked regions: &mut MetaRegionOwners,
140 range: Range<Paddr>,
141)
142 requires
143 old(regions).inv(),
144 range.start % PAGE_SIZE == 0,
145 range.end % PAGE_SIZE == 0,
146 range.start < range.end,
147 range.end <= MAX_PADDR,
148 forall|paddr: Paddr|
152 #![trigger frame_to_index(paddr)]
153 (range.start <= paddr < range.end && paddr % PAGE_SIZE == 0)
154 ==> {
155 let so = old(regions).slot_owners[frame_to_index(paddr)];
156 &&& so.inner_perms.ref_count.value() >= 1
157 &&& so.inner_perms.ref_count.value()
158 <= crate::specs::mm::frame::meta_owners::REF_COUNT_MAX
159 &&& so.usage == PageUsage::Frame
160 &&& so.inner_perms.ref_count.value() == 1
164 ==> so.paths_in_pt.is_empty()
165 },
166 ensures
167 final(regions).inv(),
168 final(regions).slots =~= old(regions).slots,
169 forall|paddr: Paddr|
172 #![trigger frame_to_index(paddr)]
173 (range.start <= paddr < range.end && paddr % PAGE_SIZE == 0)
174 ==> {
175 let idx = frame_to_index(paddr);
176 let so_old = old(regions).slot_owners[idx];
177 let so_new = final(regions).slot_owners[idx];
178 &&& so_new.usage == so_old.usage
179 &&& so_new.paths_in_pt == so_old.paths_in_pt
180 &&& so_new.self_addr == so_old.self_addr
181 &&& so_new.inner_perms.in_list == so_old.inner_perms.in_list
182 &&& so_old.inner_perms.ref_count.value() == 1
183 ==> so_new.inner_perms.ref_count.value() == REF_COUNT_UNUSED
184 &&& so_old.inner_perms.ref_count.value() > 1
185 ==> so_new.inner_perms.ref_count.value()
186 == (so_old.inner_perms.ref_count.value() - 1) as u64
187 },
188 forall|i: usize|
190 #![trigger final(regions).slot_owners[i]]
191 i < crate::specs::mm::frame::mapping::max_meta_slots()
192 && !(range.start <= crate::specs::mm::frame::mapping::index_to_frame(i)
193 < range.end)
194 ==> final(regions).slot_owners[i] == old(regions).slot_owners[i],
195 forall|c: CursorOwner<'_, UserPtConfig>| #![auto]
196 c.metaregion_sound(*old(regions)) ==> c.metaregion_sound(*final(regions)),
197;
198
199pub axiom fn segment_next_embedded(
215 tracked regions: &mut MetaRegionOwners,
216 paddr: Paddr,
217)
218 requires
219 old(regions).inv(),
220 paddr % PAGE_SIZE == 0,
221 paddr < MAX_PADDR,
222 old(regions).slots.contains_key(frame_to_index(paddr)),
223 old(regions).slot_owners[frame_to_index(paddr)]
224 .inner_perms.ref_count.value() >= 1,
225 old(regions).slot_owners[frame_to_index(paddr)]
226 .inner_perms.ref_count.value()
227 <= crate::specs::mm::frame::meta_owners::REF_COUNT_MAX,
228 old(regions).slot_owners[frame_to_index(paddr)].usage
229 == PageUsage::Frame,
230 ensures
231 final(regions).inv(),
232 final(regions).slots =~= old(regions).slots,
233 {
235 let idx = frame_to_index(paddr);
236 let so_old = old(regions).slot_owners[idx];
237 let so_new = final(regions).slot_owners[idx];
238 &&& so_new.inner_perms.ref_count == so_old.inner_perms.ref_count
239 &&& so_new.usage == so_old.usage
240 &&& so_new.self_addr == so_old.self_addr
241 &&& so_new.paths_in_pt == so_old.paths_in_pt
242 &&& so_new.inner_perms.in_list == so_old.inner_perms.in_list
243 &&& so_new.inner_perms.storage == so_old.inner_perms.storage
244 &&& so_new.inner_perms.vtable_ptr == so_old.inner_perms.vtable_ptr
245 },
246 forall|i: usize| #![trigger final(regions).slot_owners[i]]
248 i != frame_to_index(paddr)
249 ==> final(regions).slot_owners[i] == old(regions).slot_owners[i],
250 forall|c: CursorOwner<'_, UserPtConfig>| #![auto]
251 c.metaregion_sound(*old(regions)) ==> c.metaregion_sound(*final(regions)),
252;
253
254pub(super) proof fn from_unused_step(
262 tracked regions: &mut MetaRegionOwners,
263 range: Range<Paddr>,
264) -> (tracked res: Option<SegmentEntry>)
265 requires
266 old(regions).inv(),
267 range.start % PAGE_SIZE == 0,
268 range.end % PAGE_SIZE == 0,
269 range.start < range.end,
270 range.end <= MAX_PADDR,
271 forall|paddr: Paddr|
272 #![trigger frame_to_index(paddr)]
273 (range.start <= paddr < range.end && paddr % PAGE_SIZE == 0)
274 ==> old(regions).slot_owners[frame_to_index(paddr)]
275 .inner_perms.ref_count.value() == REF_COUNT_UNUSED,
276 forall|paddr: Paddr|
277 #![trigger frame_to_index(paddr)]
278 (range.start <= paddr < range.end && paddr % PAGE_SIZE == 0)
279 ==> old(regions).slots.contains_key(frame_to_index(paddr)),
280 ensures
281 final(regions).inv(),
282 final(regions).slots =~= old(regions).slots,
283 res matches Some(e) ==> e.range == range,
284 res is Some ==> forall|paddr: Paddr|
285 #![trigger frame_to_index(paddr)]
286 (range.start <= paddr < range.end && paddr % PAGE_SIZE == 0)
287 ==> {
288 let idx = frame_to_index(paddr);
289 let so = final(regions).slot_owners[idx];
290 &&& so.usage == PageUsage::Frame
291 &&& so.inner_perms.ref_count.value() == 1
292 &&& so.paths_in_pt.is_empty()
293 },
294 res is Some ==> forall|i: usize|
295 #![trigger final(regions).slot_owners[i]]
296 i < crate::specs::mm::frame::mapping::max_meta_slots()
297 && !(range.start <= crate::specs::mm::frame::mapping::index_to_frame(i)
298 < range.end)
299 ==> final(regions).slot_owners[i] == old(regions).slot_owners[i],
300 res is None ==> *final(regions) == *old(regions),
301 forall|c: CursorOwner<'_, UserPtConfig>| #![auto]
302 c.metaregion_sound(*old(regions)) ==> c.metaregion_sound(*final(regions)),
303{
304 let ghost outcome = segment_from_unused_embedded(regions, range);
305 match outcome {
306 Option::Some(()) => Option::Some(axiom_segment_entry_new(range)),
307 Option::None => Option::None,
308 }
309}
310
311pub(super) proof fn drop_step(
315 tracked regions: &mut MetaRegionOwners,
316 tracked entry: SegmentEntry,
317)
318 requires
319 old(regions).inv(),
320 entry.range.start % PAGE_SIZE == 0,
321 entry.range.end % PAGE_SIZE == 0,
322 entry.range.start < entry.range.end,
323 entry.range.end <= MAX_PADDR,
324 forall|paddr: Paddr|
325 #![trigger frame_to_index(paddr)]
326 (entry.range.start <= paddr < entry.range.end
327 && paddr % PAGE_SIZE == 0) ==> {
328 let so = old(regions).slot_owners[frame_to_index(paddr)];
329 &&& so.inner_perms.ref_count.value() >= 1
330 &&& so.inner_perms.ref_count.value()
331 <= crate::specs::mm::frame::meta_owners::REF_COUNT_MAX
332 &&& so.usage == PageUsage::Frame
333 &&& so.inner_perms.ref_count.value() == 1
334 ==> so.paths_in_pt.is_empty()
335 },
336 ensures
337 final(regions).inv(),
338 final(regions).slots =~= old(regions).slots,
339 forall|paddr: Paddr|
340 #![trigger frame_to_index(paddr)]
341 (entry.range.start <= paddr < entry.range.end
342 && paddr % PAGE_SIZE == 0) ==> {
343 let idx = frame_to_index(paddr);
344 let so_old = old(regions).slot_owners[idx];
345 let so_new = final(regions).slot_owners[idx];
346 &&& so_new.usage == so_old.usage
347 &&& so_new.paths_in_pt == so_old.paths_in_pt
348 &&& so_new.self_addr == so_old.self_addr
349 &&& so_new.inner_perms.in_list == so_old.inner_perms.in_list
350 &&& so_old.inner_perms.ref_count.value() == 1
351 ==> so_new.inner_perms.ref_count.value() == REF_COUNT_UNUSED
352 &&& so_old.inner_perms.ref_count.value() > 1
353 ==> so_new.inner_perms.ref_count.value()
354 == (so_old.inner_perms.ref_count.value() - 1) as u64
355 },
356 forall|i: usize|
357 #![trigger final(regions).slot_owners[i]]
358 i < crate::specs::mm::frame::mapping::max_meta_slots()
359 && !(entry.range.start <= crate::specs::mm::frame::mapping::index_to_frame(i)
360 < entry.range.end)
361 ==> final(regions).slot_owners[i] == old(regions).slot_owners[i],
362 forall|c: CursorOwner<'_, UserPtConfig>| #![auto]
363 c.metaregion_sound(*old(regions)) ==> c.metaregion_sound(*final(regions)),
364{
365 segment_drop_embedded(regions, entry.range);
366}
367
368}