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/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]), 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) }