@@ -11,6 +11,7 @@ use crate::error::SvsmError;
1111use crate :: mm:: alloc:: PageRef ;
1212use crate :: types:: { PAGE_SHIFT , PAGE_SIZE } ;
1313use crate :: utils:: align_up;
14+ use core:: cmp:: Ordering ;
1415
1516extern crate alloc;
1617use alloc:: vec:: Vec ;
@@ -24,6 +25,9 @@ pub struct RawAllocMapping {
2425
2526 /// Number of pages required in `pages`
2627 count : usize ,
28+
29+ /// Pages to flush
30+ unmapped_pages : Vec < Option < PageRef > > ,
2731}
2832
2933impl RawAllocMapping {
@@ -39,7 +43,12 @@ impl RawAllocMapping {
3943 pub fn new ( size : usize ) -> Self {
4044 let count = align_up ( size, PAGE_SIZE ) >> PAGE_SHIFT ;
4145 let pages: Vec < Option < PageRef > > = iter:: repeat_n ( None , count) . collect ( ) ;
42- RawAllocMapping { pages, count }
46+ let unmapped_pages: Vec < Option < PageRef > > = Vec :: new ( ) ;
47+ RawAllocMapping {
48+ pages,
49+ count,
50+ unmapped_pages,
51+ }
4352 }
4453
4554 /// Allocates a single backing page of type PageFile if the page has not already
@@ -61,18 +70,32 @@ impl RawAllocMapping {
6170 Ok ( ( ) )
6271 }
6372
64- /// Allocates a full set of backing pages of type PageFile
73+ /// Allocates backing pages for the mapping starting at a give offset
74+ ///
75+ /// # Arguments:
76+ ///
77+ /// * `offset` - Byte offset into the mapping to start allocating from
6578 ///
6679 /// # Returns
6780 ///
6881 /// `Ok(())` when all pages could be allocated, `Err(SvsmError::Mem)` otherwise
69- pub fn alloc_pages ( & mut self ) -> Result < ( ) , SvsmError > {
70- for index in 0 ..self . count {
82+ fn alloc_pages_offset ( & mut self , offset : usize ) -> Result < ( ) , SvsmError > {
83+ let start = offset / PAGE_SIZE ;
84+ for index in start..self . count {
7185 self . alloc_page ( index * PAGE_SIZE ) ?;
7286 }
7387 Ok ( ( ) )
7488 }
7589
90+ /// Allocates a full set of backing pages of type PageFile
91+ ///
92+ /// # Returns
93+ ///
94+ /// `Ok(())` when all pages could be allocated, `Err(SvsmError::Mem)` otherwise
95+ pub fn alloc_pages ( & mut self ) -> Result < ( ) , SvsmError > {
96+ self . alloc_pages_offset ( 0 )
97+ }
98+
7699 /// Returns a reference to a page at a given index. The page must already
77100 /// been allocated.
78101 ///
@@ -101,6 +124,61 @@ impl RawAllocMapping {
101124 self . count * PAGE_SIZE
102125 }
103126
127+ /// Change the size of the mapping. Note that the backing pages are not yet
128+ /// freed when the mapping is shrinked. To free the pages a separate call to
129+ /// the `flush()` method is required.
130+ ///
131+ /// # Arguments
132+ ///
133+ /// * `size` - The new size of the mapping. This will be rounded up to the
134+ /// next PAGE_SIZE boundary.
135+ ///
136+ /// # Returns
137+ ///
138+ /// Returns `OK(new_aligned_size)` on success, `Err(SvsmError)` on failure.
139+ pub fn resize ( & mut self , size : usize ) -> Result < usize , SvsmError > {
140+ let size = align_up ( size, PAGE_SIZE ) ;
141+ let old_size = self . mapping_size ( ) ;
142+
143+ match size. cmp ( & old_size) {
144+ Ordering :: Equal => Ok ( size) ,
145+ Ordering :: Greater => {
146+ // Increase pages vector
147+ let diff_count = ( size - old_size) / PAGE_SIZE ;
148+ let new_total_count = size / PAGE_SIZE ;
149+ // Reserve memory in pages vector
150+ self . pages
151+ . try_reserve_exact ( diff_count)
152+ . map_err ( |_| SvsmError :: Mem ) ?;
153+ // Increase pages vector
154+ self . pages . resize_with ( new_total_count, || None ) ;
155+ self . count += diff_count;
156+ // Try to allocate the pages
157+ if let Err ( e) = self . alloc_pages_offset ( old_size) {
158+ // Shrink pages vector
159+ self . count -= diff_count;
160+ // Free any stale backing pages
161+ self . pages . truncate ( self . count ) ;
162+ Err ( e)
163+ } else {
164+ Ok ( size)
165+ }
166+ }
167+ Ordering :: Less => {
168+ self . count = size / PAGE_SIZE ;
169+ let mut old_pages = self . pages . split_off ( self . count ) ;
170+ self . unmapped_pages . append ( & mut old_pages) ;
171+ Ok ( size)
172+ }
173+ }
174+ }
175+
176+ /// Free unmapped pages. This needs to be called after the unmapped pages
177+ /// have been flushed out of all TLBs.
178+ pub fn flush ( & mut self ) {
179+ self . unmapped_pages . clear ( ) ;
180+ }
181+
104182 /// Request physical address to map for a given offset
105183 ///
106184 /// # Arguments
0 commit comments