blob: c34afc9033673ad7c1bb1c39b574bbbb9d75e7ef [file] [log] [blame]
Pierre-Clément Tosia0934c12022-11-25 20:54:11 +00001// Copyright 2022, The Android Open Source Project
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15//! Low-level allocation and tracking of main memory.
16
Andrew Walbran848decf2022-12-15 14:39:38 +000017#![deny(unsafe_op_in_unsafe_fn)]
18
Alice Wang4be4dd02023-06-07 07:50:40 +000019use crate::helpers::PVMFW_PAGE_SIZE;
Pierre-Clément Tosiad1fc752023-05-31 16:56:56 +000020use aarch64_paging::MapError;
Andrew Walbran848decf2022-12-15 14:39:38 +000021use alloc::alloc::handle_alloc_error;
Srivatsa Vaddagiri37713ec2023-04-20 04:04:08 -070022use alloc::boxed::Box;
Alice Wangf47b2342023-06-02 11:51:57 +000023use buddy_system_allocator::LockedFrameAllocator;
Andrew Walbran848decf2022-12-15 14:39:38 +000024use core::alloc::Layout;
Jakob Vukalovic44b1ce32023-04-17 19:10:10 +010025use core::iter::once;
Pierre-Clément Tosia0934c12022-11-25 20:54:11 +000026use core::num::NonZeroUsize;
27use core::ops::Range;
Andrew Walbran848decf2022-12-15 14:39:38 +000028use core::ptr::NonNull;
Pierre-Clément Tosia0934c12022-11-25 20:54:11 +000029use core::result;
Alice Wang90e6f162023-04-17 13:49:45 +000030use hyp::get_hypervisor;
Pierre-Clément Tosi90238c52023-04-27 17:59:10 +000031use log::trace;
Jakob Vukalovic4c1edbe2023-04-17 19:10:57 +010032use log::{debug, error};
Srivatsa Vaddagiri37713ec2023-04-20 04:04:08 -070033use once_cell::race::OnceBox;
Jakob Vukalovic85a00d72023-04-20 09:51:10 +010034use spin::mutex::SpinMutex;
Pierre-Clément Tosi328dfb62022-11-25 18:20:42 +000035use tinyvec::ArrayVec;
Pierre-Clément Tosi3d4c5c32023-05-31 16:57:06 +000036use vmbase::{
Alice Wangb73a81b2023-06-07 13:05:09 +000037 dsb, layout,
Alice Wangeacb7382023-06-05 12:53:54 +000038 memory::{
Alice Wangb73a81b2023-06-07 13:05:09 +000039 flush_dirty_range, mark_dirty_block, mmio_guard_unmap_page, page_4kb_of, set_dbm_enabled,
Alice Wang110476e2023-06-07 13:12:21 +000040 verify_lazy_mapped_block, MemorySharer, MemoryTrackerError, PageTable, SIZE_2MB, SIZE_4KB,
Alice Wangeacb7382023-06-05 12:53:54 +000041 },
Alice Wang4be4dd02023-06-07 07:50:40 +000042 util::{align_up, RangeExt as _},
Pierre-Clément Tosi3d4c5c32023-05-31 16:57:06 +000043};
Pierre-Clément Tosia0934c12022-11-25 20:54:11 +000044
Jiyong Park0ee65392023-03-27 20:52:45 +090045/// First address that can't be translated by a level 1 TTBR0_EL1.
46pub const MAX_ADDR: usize = 1 << 40;
47
Alice Wangb73a81b2023-06-07 13:05:09 +000048type MemoryRange = Range<usize>;
Pierre-Clément Tosia0934c12022-11-25 20:54:11 +000049
Jakob Vukalovic85a00d72023-04-20 09:51:10 +010050pub static MEMORY: SpinMutex<Option<MemoryTracker>> = SpinMutex::new(None);
51unsafe impl Send for MemoryTracker {}
52
Jakob Vukalovic44b1ce32023-04-17 19:10:10 +010053#[derive(Clone, Copy, Debug, Default, PartialEq)]
Pierre-Clément Tosia0934c12022-11-25 20:54:11 +000054enum MemoryType {
Pierre-Clément Tosi328dfb62022-11-25 18:20:42 +000055 #[default]
Pierre-Clément Tosia0934c12022-11-25 20:54:11 +000056 ReadOnly,
57 ReadWrite,
58}
59
Pierre-Clément Tosi328dfb62022-11-25 18:20:42 +000060#[derive(Clone, Debug, Default)]
Pierre-Clément Tosia0934c12022-11-25 20:54:11 +000061struct MemoryRegion {
62 range: MemoryRange,
63 mem_type: MemoryType,
64}
65
Pierre-Clément Tosia0934c12022-11-25 20:54:11 +000066/// Tracks non-overlapping slices of main memory.
67pub struct MemoryTracker {
Pierre-Clément Tosia0934c12022-11-25 20:54:11 +000068 total: MemoryRange,
Pierre-Clément Tosiad1fc752023-05-31 16:56:56 +000069 page_table: PageTable,
Andrew Walbran19690632022-12-07 16:41:30 +000070 regions: ArrayVec<[MemoryRegion; MemoryTracker::CAPACITY]>,
71 mmio_regions: ArrayVec<[MemoryRange; MemoryTracker::MMIO_CAPACITY]>,
Alice Wang4c70d142023-06-06 11:52:33 +000072 mmio_range: MemoryRange,
Alice Wang446146a2023-06-07 08:18:46 +000073 payload_range: MemoryRange,
Pierre-Clément Tosia0934c12022-11-25 20:54:11 +000074}
75
Pierre-Clément Tosia0934c12022-11-25 20:54:11 +000076type Result<T> = result::Result<T, MemoryTrackerError>;
77
Andrew Walbran87933f32023-05-09 15:29:06 +000078static SHARED_POOL: OnceBox<LockedFrameAllocator<32>> = OnceBox::new();
Pierre-Clément Tosif19c0e62023-05-02 13:56:58 +000079static SHARED_MEMORY: SpinMutex<Option<MemorySharer>> = SpinMutex::new(None);
80
Pierre-Clément Tosia0934c12022-11-25 20:54:11 +000081impl MemoryTracker {
82 const CAPACITY: usize = 5;
Andrew Walbran19690632022-12-07 16:41:30 +000083 const MMIO_CAPACITY: usize = 5;
Pierre-Clément Tosia0934c12022-11-25 20:54:11 +000084
85 /// Create a new instance from an active page table, covering the maximum RAM size.
Alice Wang446146a2023-06-07 08:18:46 +000086 pub fn new(
87 mut page_table: PageTable,
88 total: MemoryRange,
89 mmio_range: MemoryRange,
90 payload_range: MemoryRange,
91 ) -> Self {
Alice Wang4c70d142023-06-06 11:52:33 +000092 assert!(
93 !total.overlaps(&mmio_range),
94 "MMIO space should not overlap with the main memory region."
95 );
96
Jakob Vukalovic4c1edbe2023-04-17 19:10:57 +010097 // Activate dirty state management first, otherwise we may get permission faults immediately
98 // after activating the new page table. This has no effect before the new page table is
99 // activated because none of the entries in the initial idmap have the DBM flag.
Alice Wang4dd20932023-05-26 13:47:16 +0000100 set_dbm_enabled(true);
Jakob Vukalovic4c1edbe2023-04-17 19:10:57 +0100101
102 debug!("Activating dynamic page table...");
103 // SAFETY - page_table duplicates the static mappings for everything that the Rust code is
104 // aware of so activating it shouldn't have any visible effect.
Pierre-Clément Tosiad1fc752023-05-31 16:56:56 +0000105 unsafe { page_table.activate() }
Jakob Vukalovic4c1edbe2023-04-17 19:10:57 +0100106 debug!("... Success!");
107
Andrew Walbran19690632022-12-07 16:41:30 +0000108 Self {
Alice Wang4c70d142023-06-06 11:52:33 +0000109 total,
Andrew Walbran19690632022-12-07 16:41:30 +0000110 page_table,
111 regions: ArrayVec::new(),
112 mmio_regions: ArrayVec::new(),
Alice Wang4c70d142023-06-06 11:52:33 +0000113 mmio_range,
Alice Wang446146a2023-06-07 08:18:46 +0000114 payload_range,
Andrew Walbran19690632022-12-07 16:41:30 +0000115 }
Pierre-Clément Tosia0934c12022-11-25 20:54:11 +0000116 }
117
118 /// Resize the total RAM size.
119 ///
120 /// This function fails if it contains regions that are not included within the new size.
121 pub fn shrink(&mut self, range: &MemoryRange) -> Result<()> {
122 if range.start != self.total.start {
123 return Err(MemoryTrackerError::DifferentBaseAddress);
124 }
125 if self.total.end < range.end {
126 return Err(MemoryTrackerError::SizeTooLarge);
127 }
Alice Wang81e8f142023-06-06 12:47:14 +0000128 if !self.regions.iter().all(|r| r.range.is_within(range)) {
Pierre-Clément Tosia0934c12022-11-25 20:54:11 +0000129 return Err(MemoryTrackerError::SizeTooSmall);
130 }
131
132 self.total = range.clone();
133 Ok(())
134 }
135
136 /// Allocate the address range for a const slice; returns None if failed.
137 pub fn alloc_range(&mut self, range: &MemoryRange) -> Result<MemoryRange> {
Andrew Walbranda65ab12022-12-07 15:10:13 +0000138 let region = MemoryRegion { range: range.clone(), mem_type: MemoryType::ReadOnly };
139 self.check(&region)?;
Pierre-Clément Tosia0934c12022-11-25 20:54:11 +0000140 self.page_table.map_rodata(range).map_err(|e| {
141 error!("Error during range allocation: {e}");
142 MemoryTrackerError::FailedToMap
143 })?;
Andrew Walbranda65ab12022-12-07 15:10:13 +0000144 self.add(region)
Pierre-Clément Tosia0934c12022-11-25 20:54:11 +0000145 }
146
147 /// Allocate the address range for a mutable slice; returns None if failed.
148 pub fn alloc_range_mut(&mut self, range: &MemoryRange) -> Result<MemoryRange> {
Andrew Walbranda65ab12022-12-07 15:10:13 +0000149 let region = MemoryRegion { range: range.clone(), mem_type: MemoryType::ReadWrite };
150 self.check(&region)?;
Pierre-Clément Tosiad1fc752023-05-31 16:56:56 +0000151 self.page_table.map_data_dbm(range).map_err(|e| {
Pierre-Clément Tosia0934c12022-11-25 20:54:11 +0000152 error!("Error during mutable range allocation: {e}");
153 MemoryTrackerError::FailedToMap
154 })?;
Andrew Walbranda65ab12022-12-07 15:10:13 +0000155 self.add(region)
Pierre-Clément Tosia0934c12022-11-25 20:54:11 +0000156 }
157
158 /// Allocate the address range for a const slice; returns None if failed.
159 pub fn alloc(&mut self, base: usize, size: NonZeroUsize) -> Result<MemoryRange> {
160 self.alloc_range(&(base..(base + size.get())))
161 }
162
163 /// Allocate the address range for a mutable slice; returns None if failed.
164 pub fn alloc_mut(&mut self, base: usize, size: NonZeroUsize) -> Result<MemoryRange> {
165 self.alloc_range_mut(&(base..(base + size.get())))
166 }
167
Andrew Walbran19690632022-12-07 16:41:30 +0000168 /// Checks that the given range of addresses is within the MMIO region, and then maps it
169 /// appropriately.
170 pub fn map_mmio_range(&mut self, range: MemoryRange) -> Result<()> {
Alice Wang4c70d142023-06-06 11:52:33 +0000171 if !range.is_within(&self.mmio_range) {
Andrew Walbran19690632022-12-07 16:41:30 +0000172 return Err(MemoryTrackerError::OutOfRange);
173 }
Alice Wang81e8f142023-06-06 12:47:14 +0000174 if self.mmio_regions.iter().any(|r| range.overlaps(r)) {
Andrew Walbran19690632022-12-07 16:41:30 +0000175 return Err(MemoryTrackerError::Overlaps);
176 }
177 if self.mmio_regions.len() == self.mmio_regions.capacity() {
178 return Err(MemoryTrackerError::Full);
179 }
180
Jakob Vukalovicb99905d2023-04-20 15:46:02 +0100181 self.page_table.map_device_lazy(&range).map_err(|e| {
Andrew Walbran19690632022-12-07 16:41:30 +0000182 error!("Error during MMIO device mapping: {e}");
183 MemoryTrackerError::FailedToMap
184 })?;
185
Andrew Walbran19690632022-12-07 16:41:30 +0000186 if self.mmio_regions.try_push(range).is_some() {
187 return Err(MemoryTrackerError::Full);
188 }
189
190 Ok(())
191 }
192
Andrew Walbranda65ab12022-12-07 15:10:13 +0000193 /// Checks that the given region is within the range of the `MemoryTracker` and doesn't overlap
194 /// with any other previously allocated regions, and that the regions ArrayVec has capacity to
195 /// add it.
196 fn check(&self, region: &MemoryRegion) -> Result<()> {
Alice Wang81e8f142023-06-06 12:47:14 +0000197 if !region.range.is_within(&self.total) {
Pierre-Clément Tosia0934c12022-11-25 20:54:11 +0000198 return Err(MemoryTrackerError::OutOfRange);
199 }
Alice Wang81e8f142023-06-06 12:47:14 +0000200 if self.regions.iter().any(|r| region.range.overlaps(&r.range)) {
Pierre-Clément Tosia0934c12022-11-25 20:54:11 +0000201 return Err(MemoryTrackerError::Overlaps);
202 }
Andrew Walbranda65ab12022-12-07 15:10:13 +0000203 if self.regions.len() == self.regions.capacity() {
204 return Err(MemoryTrackerError::Full);
205 }
206 Ok(())
207 }
208
209 fn add(&mut self, region: MemoryRegion) -> Result<MemoryRange> {
Pierre-Clément Tosi328dfb62022-11-25 18:20:42 +0000210 if self.regions.try_push(region).is_some() {
Pierre-Clément Tosia0934c12022-11-25 20:54:11 +0000211 return Err(MemoryTrackerError::Full);
212 }
213
Alice Wang81e8f142023-06-06 12:47:14 +0000214 Ok(self.regions.last().unwrap().range.clone())
Pierre-Clément Tosia0934c12022-11-25 20:54:11 +0000215 }
Andrew Walbran19690632022-12-07 16:41:30 +0000216
217 /// Unmaps all tracked MMIO regions from the MMIO guard.
218 ///
219 /// Note that they are not unmapped from the page table.
Jakob Vukalovicb99905d2023-04-20 15:46:02 +0100220 pub fn mmio_unmap_all(&mut self) -> Result<()> {
221 for range in &self.mmio_regions {
222 self.page_table
223 .modify_range(range, &mmio_guard_unmap_page)
224 .map_err(|_| MemoryTrackerError::FailedToUnmap)?;
Andrew Walbran19690632022-12-07 16:41:30 +0000225 }
Andrew Walbran19690632022-12-07 16:41:30 +0000226 Ok(())
227 }
Srivatsa Vaddagiri37713ec2023-04-20 04:04:08 -0700228
Pierre-Clément Tosif19c0e62023-05-02 13:56:58 +0000229 /// Initialize the shared heap to dynamically share memory from the global allocator.
230 pub fn init_dynamic_shared_pool(&mut self) -> Result<()> {
Alice Wangf47b2342023-06-02 11:51:57 +0000231 const INIT_CAP: usize = 10;
232
Pierre-Clément Tosif19c0e62023-05-02 13:56:58 +0000233 let granule = get_hypervisor().memory_protection_granule()?;
Alice Wangf47b2342023-06-02 11:51:57 +0000234 let previous = SHARED_MEMORY.lock().replace(MemorySharer::new(granule, INIT_CAP));
Pierre-Clément Tosif19c0e62023-05-02 13:56:58 +0000235 if previous.is_some() {
236 return Err(MemoryTrackerError::SharedMemorySetFailure);
237 }
238
239 SHARED_POOL
Andrew Walbran87933f32023-05-09 15:29:06 +0000240 .set(Box::new(LockedFrameAllocator::new()))
Pierre-Clément Tosif19c0e62023-05-02 13:56:58 +0000241 .map_err(|_| MemoryTrackerError::SharedPoolSetFailure)?;
242
243 Ok(())
244 }
245
246 /// Initialize the shared heap from a static region of memory.
Srivatsa Vaddagiri37713ec2023-04-20 04:04:08 -0700247 ///
248 /// Some hypervisors such as Gunyah do not support a MemShare API for guest
249 /// to share its memory with host. Instead they allow host to designate part
250 /// of guest memory as "shared" ahead of guest starting its execution. The
251 /// shared memory region is indicated in swiotlb node. On such platforms use
252 /// a separate heap to allocate buffers that can be shared with host.
Pierre-Clément Tosif19c0e62023-05-02 13:56:58 +0000253 pub fn init_static_shared_pool(&mut self, range: Range<usize>) -> Result<()> {
Srivatsa Vaddagiri37713ec2023-04-20 04:04:08 -0700254 let size = NonZeroUsize::new(range.len()).unwrap();
255 let range = self.alloc_mut(range.start, size)?;
Andrew Walbran87933f32023-05-09 15:29:06 +0000256 let shared_pool = LockedFrameAllocator::<32>::new();
Srivatsa Vaddagiri37713ec2023-04-20 04:04:08 -0700257
Andrew Walbran87933f32023-05-09 15:29:06 +0000258 shared_pool.lock().insert(range);
Srivatsa Vaddagiri37713ec2023-04-20 04:04:08 -0700259
260 SHARED_POOL
261 .set(Box::new(shared_pool))
262 .map_err(|_| MemoryTrackerError::SharedPoolSetFailure)?;
263
264 Ok(())
265 }
Pierre-Clément Tosif19c0e62023-05-02 13:56:58 +0000266
267 /// Unshares any memory that may have been shared.
268 pub fn unshare_all_memory(&mut self) {
269 drop(SHARED_MEMORY.lock().take());
270 }
Jakob Vukalovicb99905d2023-04-20 15:46:02 +0100271
272 /// Handles translation fault for blocks flagged for lazy MMIO mapping by enabling the page
273 /// table entry and MMIO guard mapping the block. Breaks apart a block entry if required.
274 pub fn handle_mmio_fault(&mut self, addr: usize) -> Result<()> {
275 let page_range = page_4kb_of(addr)..page_4kb_of(addr) + PVMFW_PAGE_SIZE;
276 self.page_table
277 .modify_range(&page_range, &verify_lazy_mapped_block)
278 .map_err(|_| MemoryTrackerError::InvalidPte)?;
279 get_hypervisor().mmio_guard_map(page_range.start)?;
280 // Maps a single device page, breaking up block mappings if necessary.
281 self.page_table.map_device(&page_range).map_err(|_| MemoryTrackerError::FailedToMap)
282 }
Jakob Vukalovic44b1ce32023-04-17 19:10:10 +0100283
284 /// Flush all memory regions marked as writable-dirty.
285 fn flush_dirty_pages(&mut self) -> Result<()> {
286 // Collect memory ranges for which dirty state is tracked.
287 let writable_regions =
288 self.regions.iter().filter(|r| r.mem_type == MemoryType::ReadWrite).map(|r| &r.range);
Jakob Vukalovic44b1ce32023-04-17 19:10:10 +0100289 // Execute a barrier instruction to ensure all hardware updates to the page table have been
290 // observed before reading PTE flags to determine dirty state.
291 dsb!("ish");
292 // Now flush writable-dirty pages in those regions.
Alice Wang446146a2023-06-07 08:18:46 +0000293 for range in writable_regions.chain(once(&self.payload_range)) {
Jakob Vukalovic44b1ce32023-04-17 19:10:10 +0100294 self.page_table
295 .modify_range(range, &flush_dirty_range)
296 .map_err(|_| MemoryTrackerError::FlushRegionFailed)?;
297 }
298 Ok(())
299 }
300
301 /// Handles permission fault for read-only blocks by setting writable-dirty state.
302 /// In general, this should be called from the exception handler when hardware dirty
303 /// state management is disabled or unavailable.
304 pub fn handle_permission_fault(&mut self, addr: usize) -> Result<()> {
305 self.page_table
306 .modify_range(&(addr..addr + 1), &mark_dirty_block)
307 .map_err(|_| MemoryTrackerError::SetPteDirtyFailed)
308 }
Pierre-Clément Tosia0934c12022-11-25 20:54:11 +0000309}
310
311impl Drop for MemoryTracker {
312 fn drop(&mut self) {
Alice Wang4dd20932023-05-26 13:47:16 +0000313 set_dbm_enabled(false);
Jakob Vukalovic44b1ce32023-04-17 19:10:10 +0100314 self.flush_dirty_pages().unwrap();
Jakob Vukalovic4c1edbe2023-04-17 19:10:57 +0100315 self.unshare_all_memory();
Pierre-Clément Tosia0934c12022-11-25 20:54:11 +0000316 }
317}
Andrew Walbran19690632022-12-07 16:41:30 +0000318
Andrew Walbran2b0c7fb2023-05-09 12:16:20 +0000319/// Allocates a memory range of at least the given size and alignment that is shared with the host.
320/// Returns a pointer to the buffer.
Pierre-Clément Tosi2d5bc582023-05-03 11:23:11 +0000321pub fn alloc_shared(layout: Layout) -> hyp::Result<NonNull<u8>> {
322 assert_ne!(layout.size(), 0);
Pierre-Clément Tosif19c0e62023-05-02 13:56:58 +0000323 let Some(buffer) = try_shared_alloc(layout) else {
Andrew Walbran848decf2022-12-15 14:39:38 +0000324 handle_alloc_error(layout);
325 };
326
Pierre-Clément Tosif19c0e62023-05-02 13:56:58 +0000327 trace!("Allocated shared buffer at {buffer:?} with {layout:?}");
Andrew Walbran848decf2022-12-15 14:39:38 +0000328 Ok(buffer)
329}
330
Pierre-Clément Tosif19c0e62023-05-02 13:56:58 +0000331fn try_shared_alloc(layout: Layout) -> Option<NonNull<u8>> {
332 let mut shared_pool = SHARED_POOL.get().unwrap().lock();
333
Andrew Walbran87933f32023-05-09 15:29:06 +0000334 if let Some(buffer) = shared_pool.alloc_aligned(layout) {
335 Some(NonNull::new(buffer as _).unwrap())
Pierre-Clément Tosif19c0e62023-05-02 13:56:58 +0000336 } else if let Some(shared_memory) = SHARED_MEMORY.lock().as_mut() {
337 shared_memory.refill(&mut shared_pool, layout);
Andrew Walbran87933f32023-05-09 15:29:06 +0000338 shared_pool.alloc_aligned(layout).map(|buffer| NonNull::new(buffer as _).unwrap())
Pierre-Clément Tosif19c0e62023-05-02 13:56:58 +0000339 } else {
340 None
341 }
342}
343
Andrew Walbran848decf2022-12-15 14:39:38 +0000344/// Unshares and deallocates a memory range which was previously allocated by `alloc_shared`.
345///
Andrew Walbran2b0c7fb2023-05-09 12:16:20 +0000346/// The layout passed in must be the same layout passed to the original `alloc_shared` call.
Andrew Walbran848decf2022-12-15 14:39:38 +0000347///
348/// # Safety
349///
Andrew Walbran2b0c7fb2023-05-09 12:16:20 +0000350/// The memory must have been allocated by `alloc_shared` with the same layout, and not yet
Andrew Walbran848decf2022-12-15 14:39:38 +0000351/// deallocated.
Pierre-Clément Tosi2d5bc582023-05-03 11:23:11 +0000352pub unsafe fn dealloc_shared(vaddr: NonNull<u8>, layout: Layout) -> hyp::Result<()> {
Andrew Walbran87933f32023-05-09 15:29:06 +0000353 SHARED_POOL.get().unwrap().lock().dealloc_aligned(vaddr.as_ptr() as usize, layout);
Srivatsa Vaddagiri37713ec2023-04-20 04:04:08 -0700354
Pierre-Clément Tosif19c0e62023-05-02 13:56:58 +0000355 trace!("Deallocated shared buffer at {vaddr:?} with {layout:?}");
Andrew Walbran848decf2022-12-15 14:39:38 +0000356 Ok(())
357}
358
Pierre-Clément Tosiad1fc752023-05-31 16:56:56 +0000359/// Returns memory range reserved for the appended payload.
Alice Wang446146a2023-06-07 08:18:46 +0000360pub fn appended_payload_range() -> MemoryRange {
Alice Wangeacb7382023-06-05 12:53:54 +0000361 let start = align_up(layout::binary_end(), SIZE_4KB).unwrap();
Pierre-Clément Tosiad1fc752023-05-31 16:56:56 +0000362 // pvmfw is contained in a 2MiB region so the payload can't be larger than the 2MiB alignment.
Alice Wangeacb7382023-06-05 12:53:54 +0000363 let end = align_up(start, SIZE_2MB).unwrap();
Pierre-Clément Tosiad1fc752023-05-31 16:56:56 +0000364 start..end
365}
366
367/// Region allocated for the stack.
Alice Wang446146a2023-06-07 08:18:46 +0000368pub fn stack_range() -> MemoryRange {
Pierre-Clément Tosiad1fc752023-05-31 16:56:56 +0000369 const STACK_PAGES: usize = 8;
370
371 layout::stack_range(STACK_PAGES * PVMFW_PAGE_SIZE)
372}
373
374pub fn init_page_table() -> result::Result<PageTable, MapError> {
Alice Wangee5b1802023-06-07 07:41:54 +0000375 let mut page_table = PageTable::default();
Pierre-Clément Tosiad1fc752023-05-31 16:56:56 +0000376
377 // Stack and scratch ranges are explicitly zeroed and flushed before jumping to payload,
378 // so dirty state management can be omitted.
379 page_table.map_data(&layout::scratch_range())?;
380 page_table.map_data(&stack_range())?;
381 page_table.map_code(&layout::text_range())?;
382 page_table.map_rodata(&layout::rodata_range())?;
383 page_table.map_data_dbm(&appended_payload_range())?;
Alice Wang807fa592023-06-02 09:54:43 +0000384 if let Err(e) = page_table.map_device(&layout::console_uart_range()) {
385 error!("Failed to remap the UART as a dynamic page table entry: {e}");
386 return Err(e);
387 }
Pierre-Clément Tosiad1fc752023-05-31 16:56:56 +0000388 Ok(page_table)
389}