11// SPDX-License-Identifier: MPL-2.0
2+ use vstd:: prelude:: * ;
3+
24use alloc:: collections:: btree_map:: BTreeMap ;
35use core:: ops:: Range ;
46
57use crate :: sync:: { PreemptDisabled , SpinLock , SpinLockGuard } ;
68
9+ #[ verus_verify]
710pub struct RangeAllocator {
811 fullrange : Range < usize > ,
9- freelist : SpinLock < Option < BTreeMap < usize , FreeRange > > > ,
12+ // TODO: PreemptDisabled added, SpinLock should be improved.
13+ freelist : SpinLock < Option < BTreeMap < usize , FreeRange > > , PreemptDisabled > ,
1014}
1115
1216/// An error returned when allocating from a [`RangeAllocator`].
17+ #[ verus_verify]
1318#[ derive( Debug ) ]
1419pub struct RangeAllocError ;
1520
21+ verus ! {
22+
23+ impl View for RangeAllocator {
24+ type V = Range <int>;
25+
26+ /// Specification view of the allocator's managed full range.
27+ closed spec fn view( & self ) -> Range <int> {
28+ Range { start: self . fullrange. start as int, end: self . fullrange. end as int }
29+ }
30+ }
31+
32+ } // verus!
33+ #[ verus_verify]
1634impl RangeAllocator {
35+ #[ verus_spec( ret =>
36+ ensures
37+ ret@. start == fullrange. start,
38+ ret@. end == fullrange. end,
39+ ) ]
1740 pub const fn new ( fullrange : Range < usize > ) -> Self {
1841 Self {
1942 fullrange,
2043 freelist : SpinLock :: new ( None ) ,
2144 }
2245 }
2346
47+ #[ verus_spec( ret =>
48+ ensures
49+ ret. start == self @. start,
50+ ret. end == self @. end,
51+ ) ]
2452 pub const fn fullrange ( & self ) -> & Range < usize > {
2553 & self . fullrange
2654 }
2755
2856 /// Allocates a specific kernel virtual area.
57+ #[ verifier:: external_body]
58+ #[ verus_spec( res =>
59+ requires allocate_range. start < allocate_range. end,
60+ ensures
61+ res is Ok ==> ( self @. start <= allocate_range. start
62+ && allocate_range. end <= self @. end) ,
63+ ) ]
2964 pub fn alloc_specific ( & self , allocate_range : & Range < usize > ) -> Result < ( ) , RangeAllocError > {
3065 debug_assert ! ( allocate_range. start < allocate_range. end) ;
3166
@@ -69,6 +104,13 @@ impl RangeAllocator {
69104 /// Allocates a range specific by the `size`.
70105 ///
71106 /// This is currently implemented with a simple FIRST-FIT algorithm.
107+ #[ verifier:: external_body]
108+ #[ verus_spec( res =>
109+ ensures
110+ res is Ok ==> ( res->Ok_0 . end - res->Ok_0 . start == size) ,
111+ res is Ok ==> ( self @. start <= res->Ok_0 . start
112+ && res->Ok_0 . end <= self @. end) ,
113+ ) ]
72114 pub fn alloc ( & self , size : usize ) -> Result < Range < usize > , RangeAllocError > {
73115 let mut lock_guard = self . get_freelist_guard ( ) ;
74116 let freelist = lock_guard. as_mut ( ) . unwrap ( ) ;
@@ -101,6 +143,7 @@ impl RangeAllocator {
101143 }
102144
103145 /// Frees a `range`.
146+ #[ verifier:: external_body]
104147 pub fn free ( & self , range : Range < usize > ) {
105148 let mut lock_guard = self . freelist . lock ( ) ;
106149 let freelist = lock_guard. as_mut ( ) . unwrap_or_else ( || {
@@ -137,6 +180,7 @@ impl RangeAllocator {
137180 }
138181 }
139182
183+ #[ verifier:: external_body]
140184 fn get_freelist_guard (
141185 & self ,
142186 ) -> SpinLockGuard < Option < BTreeMap < usize , FreeRange > > , PreemptDisabled > {
@@ -150,11 +194,18 @@ impl RangeAllocator {
150194 }
151195}
152196
197+ #[ verus_verify]
153198struct FreeRange {
154199 block : Range < usize > ,
155200}
156201
202+ #[ verus_verify]
157203impl FreeRange {
204+ #[ verus_spec( ret =>
205+ ensures
206+ ret. block. start == range. start,
207+ ret. block. end == range. end,
208+ ) ]
158209 const fn new ( range : Range < usize > ) -> Self {
159210 Self { block : range }
160211 }
0 commit comments