Skip to content

Commit a57d084

Browse files
committed
kernel/mm: Implement resize support for struct VMalloc
Support the resizing of VMalloc mappings. Signed-off-by: Joerg Roedel <joerg.roedel@amd.com>
1 parent 9ee1b9a commit a57d084

2 files changed

Lines changed: 90 additions & 4 deletions

File tree

kernel/src/mm/vm/mapping/rawalloc.rs

Lines changed: 82 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ use crate::error::SvsmError;
1111
use crate::mm::alloc::PageRef;
1212
use crate::types::{PAGE_SHIFT, PAGE_SIZE};
1313
use crate::utils::align_up;
14+
use core::cmp::Ordering;
1415

1516
extern crate alloc;
1617
use 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

2933
impl 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

kernel/src/mm/vm/mapping/vmalloc.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,14 @@ impl VirtualMapping for VMalloc {
7474
self.alloc.mapping_size()
7575
}
7676

77+
fn resize(&mut self, size: usize) -> Result<usize, SvsmError> {
78+
self.alloc.resize(size)
79+
}
80+
81+
fn flush(&mut self) {
82+
self.alloc.flush();
83+
}
84+
7785
fn map(&self, offset: usize) -> Option<PhysAddr> {
7886
self.alloc.map(offset)
7987
}

0 commit comments

Comments
 (0)