From 1cb9641333886d826abadee51908ebbe81a16efb Mon Sep 17 00:00:00 2001 From: Thara Gopinath Date: Mon, 9 Feb 2026 11:39:34 -0500 Subject: [PATCH 1/2] Remove support for boot signal page. --- litebox_platform_lvbs/src/mshv/mod.rs | 2 -- litebox_platform_lvbs/src/mshv/vsm.rs | 36 ++++----------------------- 2 files changed, 5 insertions(+), 33 deletions(-) diff --git a/litebox_platform_lvbs/src/mshv/mod.rs b/litebox_platform_lvbs/src/mshv/mod.rs index ad51e91f1..6e0c83aff 100644 --- a/litebox_platform_lvbs/src/mshv/mod.rs +++ b/litebox_platform_lvbs/src/mshv/mod.rs @@ -103,8 +103,6 @@ pub const HV_REGISTER_CR_INTERCEPT_CR0_MASK: u32 = 0x000e_0001; pub const HV_REGISTER_CR_INTERCEPT_CR4_MASK: u32 = 0x000e_0002; pub const HV_REGISTER_PENDING_EVENT0: u32 = 0x0001_0004; -pub const HV_SECURE_VTL_BOOT_TOKEN: u8 = 0xdc; - /// VTL call parameters (`param[0]`: function ID, `param[1..4]`: parameters) pub const NUM_VTLCALL_PARAMS: usize = 4; diff --git a/litebox_platform_lvbs/src/mshv/vsm.rs b/litebox_platform_lvbs/src/mshv/vsm.rs index 838f3e4fe..70065b406 100644 --- a/litebox_platform_lvbs/src/mshv/vsm.rs +++ b/litebox_platform_lvbs/src/mshv/vsm.rs @@ -17,7 +17,7 @@ use crate::{ mshv::{ HV_REGISTER_CR_INTERCEPT_CONTROL, HV_REGISTER_CR_INTERCEPT_CR0_MASK, HV_REGISTER_CR_INTERCEPT_CR4_MASK, HV_REGISTER_VSM_PARTITION_CONFIG, - HV_REGISTER_VSM_VP_SECURE_CONFIG_VTL0, HV_SECURE_VTL_BOOT_TOKEN, HV_X64_REGISTER_APIC_BASE, + HV_REGISTER_VSM_VP_SECURE_CONFIG_VTL0, HV_X64_REGISTER_APIC_BASE, HV_X64_REGISTER_CR0, HV_X64_REGISTER_CR4, HV_X64_REGISTER_CSTAR, HV_X64_REGISTER_EFER, HV_X64_REGISTER_LSTAR, HV_X64_REGISTER_SFMASK, HV_X64_REGISTER_STAR, HV_X64_REGISTER_SYSENTER_CS, HV_X64_REGISTER_SYSENTER_EIP, HV_X64_REGISTER_SYSENTER_ESP, @@ -116,13 +116,10 @@ pub fn mshv_vsm_enable_aps(_cpu_present_mask_pfn: u64) -> Result { /// VSM function for enabling VTL and booting APs /// `cpu_online_mask_pfn` indicates the page containing the VTL0's CPU online mask. -/// `boot_signal_pfn` indicates the boot signal page to let VTL0 know that VTL1 is ready. -pub fn mshv_vsm_boot_aps(cpu_online_mask_pfn: u64, boot_signal_pfn: u64) -> Result { +pub fn mshv_vsm_boot_aps(cpu_online_mask_pfn: u64) -> Result { debug_serial_println!("VSM: Boot APs"); let cpu_online_mask_page_addr = PhysAddr::try_new(cpu_online_mask_pfn << PAGE_SHIFT).map_err(|_| Errno::EINVAL)?; - let boot_signal_page_addr = - PhysAddr::try_new(boot_signal_pfn << PAGE_SHIFT).map_err(|_| Errno::EINVAL)?; if let Some(cpu_mask) = unsafe { crate::platform_low().copy_from_vtl0_phys::(cpu_online_mask_page_addr) } @@ -131,48 +128,25 @@ pub fn mshv_vsm_boot_aps(cpu_online_mask_pfn: u64, boot_signal_pfn: u64) -> Resu cpu_mask.for_each_cpu(|cpu_id| { debug_serial_print!("{}, ", cpu_id); }); - debug_serial_println!(""); - - // boot_signal is an array of bytes whose length is the number of possible cores. Copy the entire page for now. - let Some(mut boot_signal_page_buf) = (unsafe { - crate::platform_low().copy_from_vtl0_phys::(boot_signal_page_addr) - }) else { - serial_println!("Failed to get boot signal page"); - return Err(Errno::EINVAL); - }; let mut error = None; // Initialize VTL for each online CPU and update its boot signal byte - cpu_mask.for_each_cpu(|cpu_id| { - if cpu_id > boot_signal_page_buf.0.len() - 1 { - error = Some(HypervCallError::InvalidInput); - return; - } + cpu_mask.for_each_cpu(|cpu_id| { let cpu_id_u32: u32 = cpu_id.truncate(); if let Err(e) = init_vtl_ap(cpu_id_u32) { error = Some(e); } - boot_signal_page_buf.0[cpu_id] = HV_SECURE_VTL_BOOT_TOKEN; }); if let Some(e) = error { serial_println!("Failed to initialize one or more APs: {:?}", e); return Err(Errno::EINVAL); } - // Store the cpu_online_mask for later use CPU_ONLINE_MASK.call_once(|| cpu_mask); - if unsafe { - crate::platform_low() - .copy_to_vtl0_phys::(boot_signal_page_addr, &boot_signal_page_buf) - } { - Ok(0) - } else { - serial_println!("Failed to copy boot signal page to VTL0"); - Err(Errno::EINVAL) - } + Ok(0) } else { serial_println!("Failed to get cpu_online_mask"); Err(Errno::EINVAL) @@ -974,7 +948,7 @@ fn mshv_vsm_allocate_ringbuffer_memory(phys_addr: u64, size: usize) -> Result i64 { let result = match func_id { VsmFunction::EnableAPsVtl => mshv_vsm_enable_aps(params[0]), - VsmFunction::BootAPs => mshv_vsm_boot_aps(params[0], params[1]), + VsmFunction::BootAPs => mshv_vsm_boot_aps(params[0]), VsmFunction::LockRegs => mshv_vsm_lock_regs(), VsmFunction::SignalEndOfBoot => Ok(mshv_vsm_end_of_boot()), VsmFunction::ProtectMemory => mshv_vsm_protect_memory(params[0], params[1]), From 5882b4d1e970f27142c840b6d3737d1c0e893418 Mon Sep 17 00:00:00 2001 From: Thara Gopinath Date: Mon, 9 Feb 2026 11:40:28 -0500 Subject: [PATCH 2/2] Remove support for bootparams and cmdline pages. The need for bootparams and cmdline came from having a Linux secure kernel in VTL1. With rust based Litebox as secure kernel, we no longer need these pages. Instead pass the require boot info as arguments when primary cpu enters VTL1 the first time to boot. --- litebox_platform_lvbs/src/host/bootparam.rs | 183 ++---------------- .../src/mshv/vtl1_mem_layout.rs | 14 +- litebox_runner_lvbs/src/main.rs | 11 +- 3 files changed, 26 insertions(+), 182 deletions(-) diff --git a/litebox_platform_lvbs/src/host/bootparam.rs b/litebox_platform_lvbs/src/host/bootparam.rs index db94e4bde..191153656 100644 --- a/litebox_platform_lvbs/src/host/bootparam.rs +++ b/litebox_platform_lvbs/src/host/bootparam.rs @@ -3,198 +3,51 @@ //! VTL1 kernel boot parameters (compatible with Linux kernel's boot_params structure and command line) -use crate::{ - debug_serial_println, - mshv::vtl1_mem_layout::{ - VTL1_BOOT_PARAMS_PAGE, VTL1_CMDLINE_PAGE, VtlMemoryError, get_address_of_special_page, - }, -}; -use core::ffi::{CStr, c_char}; -use num_enum::TryFromPrimitive; +use crate::debug_serial_println; +use litebox_common_linux::errno::Errno; use spin::Once; -// This module defines a simplified Linux boot params structure -// (based on arch/x86/include/uapi/asm/bootparam.h and -// arch/x86/include/uapi/asm/e820.h). We need this because VTL0 kernel -// passes memory information to VTL1 kernel via boot params. - -const E820_MAX_ENTRIES: usize = 128; - -const E820_RAM: u32 = 1; -const E820_RESERVED: u32 = 2; -const E820_ACPI: u32 = 3; -const E820_NVS: u32 = 4; -const E820_UNUSABLE: u32 = 5; -const E820_PMEM: u32 = 7; -const E820_PRAM: u32 = 12; -const E820_RESERVED_KERN: u32 = 128; - static POSSIBLE_CPUS: Once = Once::new(); static VTL1_MEMORY_INFO: Once<(u64, u64)> = Once::new(); -#[derive(Default, Clone, Copy)] -#[repr(C, packed)] -struct BootE820Entry { - pub addr: u64, - pub size: u64, - pub typ: u32, -} - -#[derive(Clone, Copy)] -#[repr(C, packed)] -struct BootParams { - _unused0: [u8; 720], // fields in this area are not used. - e820_table: [BootE820Entry; E820_MAX_ENTRIES], - _unused1: [u8; 816], // fields in this area are not used. -} - -impl BootParams { - pub fn new() -> Self { - Self { - _unused0: [0; 720], - e820_table: [BootE820Entry::default(); E820_MAX_ENTRIES], - _unused1: [0; 816], - } - } - - #[cfg(debug_assertions)] - pub fn dump(&self) { - for entry in self.e820_table { - let typ_val = entry.typ; - - if E820Type::try_from(typ_val).unwrap_or(E820Type::Unknown) == E820Type::Unknown { - break; - } else { - let addr_val = entry.addr; - let size_val = entry.size; - debug_serial_println!( - "addr: {:#x}, size: {:#x}, type: {:?}", - addr_val, - size_val, - typ_val - ); - } - } - } - - pub fn memory_info(&self) -> Result<(u64, u64), VtlMemoryError> { - for entry in self.e820_table { - let typ_val = entry.typ; - - match E820Type::try_from(typ_val).unwrap_or(E820Type::Unknown) { - E820Type::Ram => { - let addr_val = entry.addr; - let size_val = entry.size; - return Ok((addr_val, size_val)); - } - E820Type::Unknown => { - return Err(VtlMemoryError::InvalidBootParams); - } - _ => {} - } - } - - Err(VtlMemoryError::InvalidBootParams) - } -} - -impl Default for BootParams { - fn default() -> Self { - Self::new() - } -} - -#[cfg(debug_assertions)] -fn dump_boot_params() { - let boot_params = get_address_of_special_page(VTL1_BOOT_PARAMS_PAGE) as *const BootParams; - unsafe { - (*boot_params).dump(); - } -} - -#[cfg(debug_assertions)] -fn dump_cmdline() { - let cmdline = get_address_of_special_page(VTL1_CMDLINE_PAGE) as *const c_char; - if cmdline.is_null() { - return; - } - - if let Some(cmdline_str) = unsafe { CStr::from_ptr(cmdline).to_str().ok() } { - debug_serial_println!("{}", cmdline_str); - } -} - /// Funtion to get the guest physical start address and size of VTL1 memory -pub fn get_vtl1_memory_info() -> Result<(u64, u64), VtlMemoryError> { +pub fn get_vtl1_memory_info() -> Result<(u64, u64), Errno> { if let Some(pair) = VTL1_MEMORY_INFO.get().copied() { Ok(pair) } else { - Err(VtlMemoryError::InvalidBootParams) + Err(Errno::EINVAL) } } /// Funtion to get the number of possible cpus from the command line (Linux kernel's num_possible_cpus()) -pub fn get_num_possible_cpus() -> Result { +pub fn get_num_possible_cpus() -> Result { if let Some(cpus) = POSSIBLE_CPUS.get() { Ok(*cpus) } else { - Err(VtlMemoryError::InvalidCmdLine) + Err(Errno::EINVAL) } } -fn save_vtl1_memory_info() -> Result<(), VtlMemoryError> { - let boot_params = get_address_of_special_page(VTL1_BOOT_PARAMS_PAGE) as *const BootParams; - if let Some((start, size)) = unsafe { (*boot_params).memory_info().ok() } { +fn save_vtl1_memory_info(start: u64, size: u64) -> Result<(), Errno> { + if start > 0 && size > 0 { VTL1_MEMORY_INFO.call_once(|| (start, size)); return Ok(()); } - Err(VtlMemoryError::InvalidBootParams) + Err(Errno::EINVAL) } -fn save_possible_cpus() -> Result<(), VtlMemoryError> { - let cmdline = get_address_of_special_page(VTL1_CMDLINE_PAGE) as *const c_char; - if cmdline.is_null() { - return Err(VtlMemoryError::InvalidCmdLine); - } - - if let Some(cmdline_str) = unsafe { CStr::from_ptr(cmdline).to_str().ok() } { - for token in cmdline_str.split_whitespace() { - if token.starts_with("possible_cpus=") - && let Some((_, v)) = token.split_once('=') - { - let num = v.parse::().unwrap_or(0); - if num > 0 { - POSSIBLE_CPUS.call_once(|| num); - return Ok(()); - } - } - } +fn save_possible_cpus(possible_cpus: u32) -> Result<(), Errno> { + if possible_cpus > 0 { + POSSIBLE_CPUS.call_once(|| possible_cpus as u32); + return Ok(()); } - Err(VtlMemoryError::InvalidCmdLine) + Err(Errno::EINVAL) } /// # Panics /// /// Panics if possible cpus or vtl1 memory extraction fails -pub fn parse_boot_info() { - #[cfg(debug_assertions)] - dump_cmdline(); - #[cfg(debug_assertions)] - dump_boot_params(); - save_possible_cpus().unwrap(); // Panic if CPU extraction fails - save_vtl1_memory_info().unwrap(); // Panic if memory extraction fails -} - -/// E820 entry type -#[derive(Debug, PartialEq, TryFromPrimitive)] -#[repr(u32)] -enum E820Type { - Ram = E820_RAM, - Reserved = E820_RESERVED, - Acpi = E820_ACPI, - Nvs = E820_NVS, - Unusable = E820_UNUSABLE, - Pmem = E820_PMEM, - Pram = E820_PRAM, - ReservedKern = E820_RESERVED_KERN, - Unknown = 0xffff_ffff, +pub fn parse_boot_info(possible_cpus: u32, mem_pa: u64, mem_size: u64) { + debug_serial_println!("VTL1 Boot Info possible_cpus: {}, mem_pa: {:#x}, mem_size: {:#x}", possible_cpus, mem_pa, mem_size ); + save_possible_cpus(possible_cpus).unwrap(); // Panic if CPU extraction fails + save_vtl1_memory_info(mem_pa, mem_size).unwrap(); // Panic if memory extraction fails } diff --git a/litebox_platform_lvbs/src/mshv/vtl1_mem_layout.rs b/litebox_platform_lvbs/src/mshv/vtl1_mem_layout.rs index 42e0813a4..676d8a380 100644 --- a/litebox_platform_lvbs/src/mshv/vtl1_mem_layout.rs +++ b/litebox_platform_lvbs/src/mshv/vtl1_mem_layout.rs @@ -11,7 +11,6 @@ pub const VSM_PMD_SIZE: usize = PAGE_SIZE * PTES_PER_PAGE; pub const VSM_SK_INITIAL_MAP_SIZE: usize = 16 * 1024 * 1024; pub const VSM_SK_PTE_PAGES_COUNT: usize = VSM_SK_INITIAL_MAP_SIZE / VSM_PMD_SIZE; -pub const VTL1_TOTAL_MEMORY_SIZE: usize = 128 * 1024 * 1024; pub const VTL1_PRE_POPULATED_MEMORY_SIZE: usize = VSM_SK_INITIAL_MAP_SIZE; // physical page frames specified by VTL0 kernel @@ -25,10 +24,6 @@ pub const VTL1_PTE_0_PAGE: usize = 5; // use this stack only for per-core VTL startup pub const VTL1_KERNEL_STACK_PAGE: usize = VTL1_PTE_0_PAGE + VSM_SK_PTE_PAGES_COUNT; -// TODO: get addresses from VTL call params rather than use these static indexes -pub const VTL1_BOOT_PARAMS_PAGE: usize = VTL1_KERNEL_STACK_PAGE + 1; -pub const VTL1_CMDLINE_PAGE: usize = VTL1_BOOT_PARAMS_PAGE + 1; - // initial heap to add the entire VTL1 physical memory to the kernel page table // We need ~256 KiB to cover the entire VTL1 physical memory (128 MiB) pub const VTL1_INIT_HEAP_START_PAGE: usize = 256; @@ -52,11 +47,4 @@ pub fn get_heap_start_address() -> u64 { #[inline] pub fn get_address_of_special_page(page: usize) -> u64 { get_memory_base_address() + (page as u64) * PAGE_SIZE as u64 -} - -/// Error for VSM memory -#[derive(Debug, PartialEq)] -pub enum VtlMemoryError { - InvalidBootParams, - InvalidCmdLine, -} +} \ No newline at end of file diff --git a/litebox_runner_lvbs/src/main.rs b/litebox_runner_lvbs/src/main.rs index 4efc293fd..bd43b7b1f 100644 --- a/litebox_runner_lvbs/src/main.rs +++ b/litebox_runner_lvbs/src/main.rs @@ -118,11 +118,17 @@ unsafe fn apply_relocations() { #[expect(clippy::missing_safety_doc)] #[unsafe(no_mangle)] -pub unsafe extern "C" fn _start() -> ! { +pub unsafe extern "C" fn _start(possible_cpus: u64, mem_pa: u64, mem_size: u64) -> ! { + // possible_cpus and start memory address and vtl1 memory size are captured + // from rdi/rsi/rdx immediately as function parameters, before any code runs. + // They're stored on the stack and survive relocations (which only patch binary + // addresses, not stack). + let core_id = get_core_id(); if core_id == 0 { unsafe { apply_relocations(); + parse_boot_info(possible_cpus as u32, mem_pa, mem_size); } } @@ -148,10 +154,7 @@ unsafe extern "C" fn kernel_main() -> ! { serial_println!("=============================="); serial_println!(" Hello from LiteBox for LVBS! "); serial_println!("=============================="); - - parse_boot_info(); } - let platform = litebox_runner_lvbs::init(); litebox_runner_lvbs::run(platform) }