vmbase: Enter clients with dynamic PTs live
The layout and linker sections of clients are controlled by a linker
script provided by vmbase so the library should know how to replicate
the client-specific static PTs to generate the dynamic PTs. Therefore,
teach vmbase to use the information it gets from the linker to replicate
the client static PTs, with client-agnostic code, and switch to the
dynamic PTs before entering its clients.
Bug: 377276983
Test: m {pvmfw,rialto,vmbase_example_{bios,kernel}}_bin
Test: atest rialto_test vmbase_example.integration_test
Change-Id: I90fa0e62e6e4cb8474f3294633cee775b1191c71
diff --git a/guest/pvmfw/src/entry.rs b/guest/pvmfw/src/entry.rs
index 1da0513..2f0b391 100644
--- a/guest/pvmfw/src/entry.rs
+++ b/guest/pvmfw/src/entry.rs
@@ -28,9 +28,8 @@
arch::aarch64::min_dcache_line_size,
configure_heap, console_writeln, layout, limit_stack_size, main,
memory::{
- deactivate_dynamic_page_tables, map_image_footer, switch_to_dynamic_page_tables,
- unshare_all_memory, unshare_all_mmio_except_uart, unshare_uart, MemoryTrackerError,
- SIZE_128KB, SIZE_4KB,
+ deactivate_dynamic_page_tables, map_image_footer, unshare_all_memory,
+ unshare_all_mmio_except_uart, unshare_uart, MemoryTrackerError, SIZE_128KB, SIZE_4KB,
},
power::reboot,
};
@@ -109,13 +108,6 @@
log::set_max_level(LevelFilter::Info);
- let page_table = memory::init_page_table().map_err(|e| {
- error!("Failed to set up the dynamic page tables: {e}");
- RebootReason::InternalError
- })?;
- // Up to this point, we were using the built-in static (from .rodata) page tables.
- switch_to_dynamic_page_tables(page_table);
-
let appended_data = get_appended_data_slice().map_err(|e| {
error!("Failed to map the appended data: {e}");
RebootReason::InternalError
diff --git a/guest/pvmfw/src/memory.rs b/guest/pvmfw/src/memory.rs
index a0d2b14..35bfd3a 100644
--- a/guest/pvmfw/src/memory.rs
+++ b/guest/pvmfw/src/memory.rs
@@ -16,36 +16,17 @@
use crate::entry::RebootReason;
use crate::fdt;
-use aarch64_paging::MapError;
use core::num::NonZeroUsize;
-use core::result;
use core::slice;
use log::debug;
use log::error;
use log::info;
use log::warn;
use vmbase::{
- layout::{self, crosvm},
- memory::{init_shared_pool, map_data, map_rodata, resize_available_memory, PageTable},
+ layout::crosvm,
+ memory::{init_shared_pool, map_data, map_rodata, resize_available_memory},
};
-pub fn init_page_table() -> result::Result<PageTable, MapError> {
- let mut page_table = PageTable::default();
-
- // Stack and scratch ranges are explicitly zeroed and flushed before jumping to payload,
- // so dirty state management can be omitted.
- page_table.map_data(&layout::data_bss_range().into())?;
- page_table.map_data(&layout::eh_stack_range().into())?;
- page_table.map_data(&layout::stack_range().into())?;
- page_table.map_code(&layout::text_range().into())?;
- page_table.map_rodata(&layout::rodata_range().into())?;
- if let Err(e) = page_table.map_device(&layout::console_uart_page().into()) {
- error!("Failed to remap the UART as a dynamic page table entry: {e}");
- return Err(e);
- }
- Ok(page_table)
-}
-
pub(crate) struct MemorySlices<'a> {
pub fdt: &'a mut libfdt::Fdt,
pub kernel: &'a [u8],
diff --git a/guest/rialto/src/main.rs b/guest/rialto/src/main.rs
index 8f5a670..04d18be 100644
--- a/guest/rialto/src/main.rs
+++ b/guest/rialto/src/main.rs
@@ -46,11 +46,11 @@
fdt::pci::PciInfo,
fdt::SwiotlbInfo,
generate_image_header,
- layout::{self, crosvm},
+ layout::crosvm,
main,
memory::{
init_shared_pool, map_rodata, map_rodata_outside_main_memory, resize_available_memory,
- switch_to_dynamic_page_tables, PageTable, SIZE_128KB,
+ SIZE_128KB,
},
power::reboot,
virtio::{
@@ -71,28 +71,12 @@
}
}
-fn new_page_table() -> Result<PageTable> {
- let mut page_table = PageTable::default();
-
- page_table.map_data(&layout::data_bss_range().into())?;
- page_table.map_data(&layout::eh_stack_range().into())?;
- page_table.map_data(&layout::stack_range().into())?;
- page_table.map_code(&layout::text_range().into())?;
- page_table.map_rodata(&layout::rodata_range().into())?;
- page_table.map_device(&layout::console_uart_page().into())?;
-
- Ok(page_table)
-}
-
/// # Safety
///
/// Behavior is undefined if any of the following conditions are violated:
/// * The `fdt_addr` must be a valid pointer and points to a valid `Fdt`.
unsafe fn try_main(fdt_addr: usize) -> Result<()> {
info!("Welcome to Rialto!");
- let page_table = new_page_table()?;
-
- switch_to_dynamic_page_tables(page_table);
let fdt_size = NonZeroUsize::new(crosvm::FDT_MAX_SIZE).unwrap();
map_rodata(fdt_addr, fdt_size)?;
diff --git a/guest/vmbase_example/src/main.rs b/guest/vmbase_example/src/main.rs
index 138c90e..4c5e880 100644
--- a/guest/vmbase_example/src/main.rs
+++ b/guest/vmbase_example/src/main.rs
@@ -25,7 +25,6 @@
use crate::layout::print_addresses;
use crate::pci::check_pci;
-use aarch64_paging::MapError;
use alloc::{vec, vec::Vec};
use core::ptr::addr_of_mut;
use cstr::cstr;
@@ -35,15 +34,9 @@
bionic, configure_heap,
fdt::pci::PciInfo,
generate_image_header,
- layout::{
- console_uart_page, crosvm::FDT_MAX_SIZE, data_bss_range, eh_stack_range, rodata_range,
- stack_range, text_range,
- },
+ layout::crosvm::FDT_MAX_SIZE,
linker, logger, main,
- memory::{
- deactivate_dynamic_page_tables, map_data, switch_to_dynamic_page_tables, PageTable,
- SIZE_64KB,
- },
+ memory::{deactivate_dynamic_page_tables, map_data, SIZE_64KB},
};
static INITIALISED_DATA: [u32; 4] = [1, 2, 3, 4];
@@ -54,17 +47,6 @@
main!(main);
configure_heap!(SIZE_64KB);
-fn init_page_table(page_table: &mut PageTable) -> Result<(), MapError> {
- page_table.map_device(&console_uart_page().into())?;
- page_table.map_code(&text_range().into())?;
- page_table.map_rodata(&rodata_range().into())?;
- page_table.map_data(&data_bss_range().into())?;
- page_table.map_data(&eh_stack_range().into())?;
- page_table.map_data(&stack_range().into())?;
-
- Ok(())
-}
-
/// Entry point for VM bootloader.
pub fn main(arg0: u64, arg1: u64, arg2: u64, arg3: u64) {
log::set_max_level(LevelFilter::Debug);
@@ -75,12 +57,6 @@
check_data();
check_stack_guard();
- let mut page_table = PageTable::default();
- init_page_table(&mut page_table).unwrap();
- info!("Activating IdMap...");
- switch_to_dynamic_page_tables(page_table);
- info!("Activated.");
-
info!("Checking FDT...");
let fdt_addr = usize::try_from(arg0).unwrap();
// SAFETY: The DTB range is valid, writable memory, and we don't construct any aliases to it.
diff --git a/libs/libvmbase/src/entry.rs b/libs/libvmbase/src/entry.rs
index 2433722..b681aea 100644
--- a/libs/libvmbase/src/entry.rs
+++ b/libs/libvmbase/src/entry.rs
@@ -18,7 +18,7 @@
bionic, console, heap,
layout::{UART_ADDRESSES, UART_PAGE_ADDR},
logger,
- memory::{PAGE_SIZE, SIZE_16KB, SIZE_4KB},
+ memory::{switch_to_dynamic_page_tables, PAGE_SIZE, SIZE_16KB, SIZE_4KB},
power::{reboot, shutdown},
rand,
};
@@ -82,6 +82,8 @@
bionic::__get_tls().stack_guard = u64::from_ne_bytes(stack_guard);
+ switch_to_dynamic_page_tables();
+
// Note: If rust_entry ever returned (which it shouldn't by being -> !), the compiler-injected
// stack guard comparison would detect a mismatch and call __stack_chk_fail.
diff --git a/libs/libvmbase/src/memory.rs b/libs/libvmbase/src/memory.rs
index e903858..fd4706f 100644
--- a/libs/libvmbase/src/memory.rs
+++ b/libs/libvmbase/src/memory.rs
@@ -27,8 +27,8 @@
pub use shared::MemoryRange;
pub use tracker::{
deactivate_dynamic_page_tables, init_shared_pool, map_data, map_device, map_image_footer,
- map_rodata, map_rodata_outside_main_memory, resize_available_memory,
- switch_to_dynamic_page_tables, unshare_all_memory, unshare_all_mmio_except_uart, unshare_uart,
+ map_rodata, map_rodata_outside_main_memory, resize_available_memory, unshare_all_memory,
+ unshare_all_mmio_except_uart, unshare_uart,
};
pub use util::{
flush, flushed_zeroize, page_4kb_of, PAGE_SIZE, SIZE_128KB, SIZE_16KB, SIZE_2MB, SIZE_4KB,
@@ -37,5 +37,5 @@
pub(crate) use shared::{alloc_shared, dealloc_shared};
pub(crate) use stack::max_stack_size;
-pub(crate) use tracker::MEMORY;
+pub(crate) use tracker::{switch_to_dynamic_page_tables, MEMORY};
pub(crate) use util::{phys_to_virt, virt_to_phys};
diff --git a/libs/libvmbase/src/memory/tracker.rs b/libs/libvmbase/src/memory/tracker.rs
index e75dc11..3416dc6 100644
--- a/libs/libvmbase/src/memory/tracker.rs
+++ b/libs/libvmbase/src/memory/tracker.rs
@@ -52,14 +52,13 @@
/// Switch the MMU to the provided PageTable.
///
/// Panics if called more than once.
-pub fn switch_to_dynamic_page_tables(pt: PageTable) {
+pub(crate) fn switch_to_dynamic_page_tables() {
let mut locked_tracker = try_lock_memory_tracker().unwrap();
if locked_tracker.is_some() {
panic!("switch_to_dynamic_page_tables() called more than once.");
}
locked_tracker.replace(MemoryTracker::new(
- pt,
layout::crosvm::MEM_START..layout::MAX_VIRT_ADDR,
layout::crosvm::MMIO_RANGE,
));
@@ -207,12 +206,13 @@
const MMIO_CAPACITY: usize = 5;
/// Creates a new instance from an active page table, covering the maximum RAM size.
- fn new(mut page_table: PageTable, total: MemoryRange, mmio_range: MemoryRange) -> Self {
+ fn new(total: MemoryRange, mmio_range: MemoryRange) -> Self {
assert!(
!total.overlaps(&mmio_range),
"MMIO space should not overlap with the main memory region."
);
+ let mut page_table = Self::initialize_dynamic_page_tables();
// Activate dirty state management first, otherwise we may get permission faults immediately
// after activating the new page table. This has no effect before the new page table is
// activated because none of the entries in the initial idmap have the DBM flag.
@@ -503,6 +503,28 @@
.modify_range(&(addr..addr + 1).into(), &mark_dirty_block)
.map_err(|_| MemoryTrackerError::SetPteDirtyFailed)
}
+
+ // TODO(ptosi): Move this and `PageTable` references to crate::arch::aarch64
+ /// Produces a `PageTable` that can safely replace the static PTs.
+ fn initialize_dynamic_page_tables() -> PageTable {
+ let text = layout::text_range();
+ let rodata = layout::rodata_range();
+ let data_bss = layout::data_bss_range();
+ let eh_stack = layout::eh_stack_range();
+ let stack = layout::stack_range();
+ let console_uart_page = layout::console_uart_page();
+
+ let mut page_table = PageTable::default();
+
+ page_table.map_device(&console_uart_page.into()).unwrap();
+ page_table.map_code(&text.into()).unwrap();
+ page_table.map_rodata(&rodata.into()).unwrap();
+ page_table.map_data(&data_bss.into()).unwrap();
+ page_table.map_data(&eh_stack.into()).unwrap();
+ page_table.map_data(&stack.into()).unwrap();
+
+ page_table
+ }
}
impl Drop for MemoryTracker {