From 73f83e146b8ebf151043740c2b721902e3ee34aa 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 | 40 ++++++--------------------- 2 files changed, 9 insertions(+), 33 deletions(-) diff --git a/litebox_platform_lvbs/src/mshv/mod.rs b/litebox_platform_lvbs/src/mshv/mod.rs index 0da18875d..12f8a5207 100644 --- a/litebox_platform_lvbs/src/mshv/mod.rs +++ b/litebox_platform_lvbs/src/mshv/mod.rs @@ -111,8 +111,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 483de17bb..f66989fa3 100644 --- a/litebox_platform_lvbs/src/mshv/vsm.rs +++ b/litebox_platform_lvbs/src/mshv/vsm.rs @@ -16,12 +16,12 @@ 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_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, - HvCrInterceptControlFlags, HvPageProtFlags, HvRegisterVsmPartitionConfig, - HvRegisterVsmVpSecureVtlConfig, VsmFunction, X86Cr0Flags, X86Cr4Flags, + 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, HvCrInterceptControlFlags, + HvPageProtFlags, HvRegisterVsmPartitionConfig, HvRegisterVsmVpSecureVtlConfig, VsmFunction, + X86Cr0Flags, X86Cr4Flags, error::VsmError, heki::{ HekiKdataType, HekiKernelInfo, HekiKernelSymbol, HekiKexecType, HekiPage, HekiPatch, @@ -112,13 +112,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(|_| VsmError::InvalidPhysicalAddress)?; - let boot_signal_page_addr = PhysAddr::try_new(boot_signal_pfn << PAGE_SHIFT) - .map_err(|_| VsmError::InvalidPhysicalAddress)?; let Some(cpu_mask) = (unsafe { crate::platform_low().copy_from_vtl0_phys::(cpu_online_mask_page_addr) @@ -135,26 +132,14 @@ pub fn mshv_vsm_boot_aps(cpu_online_mask_pfn: u64, boot_signal_pfn: u64) -> Resu 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 { - return Err(VsmError::BootSignalPageCopyFailed); - }; - 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; - } 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 { @@ -164,14 +149,7 @@ pub fn mshv_vsm_boot_aps(cpu_online_mask_pfn: u64, boot_signal_pfn: u64) -> Resu // 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 { - Err(VsmError::BootSignalWriteFailed) - } + Ok(0) } /// VSM function for enforcing certain security features of VTL0 @@ -920,7 +898,7 @@ fn mshv_vsm_allocate_ringbuffer_memory(phys_addr: u64, size: usize) -> Result i64 { let result: 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 12a1ddb82ea12be38b78dca788eedb78936e2bc0 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 | 28 +-- litebox_runner_lvbs/src/main.rs | 9 +- 3 files changed, 24 insertions(+), 196 deletions(-) diff --git a/litebox_platform_lvbs/src/host/bootparam.rs b/litebox_platform_lvbs/src/host/bootparam.rs index 2cd42b3bf..c8aaefbe3 100644 --- a/litebox_platform_lvbs/src/host/bootparam.rs +++ b/litebox_platform_lvbs/src/host/bootparam.rs @@ -1,200 +1,49 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT license. -//! VTL1 kernel boot parameters (compatible with Linux kernel's boot_params structure and command line) - -use crate::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 litebox_common_linux::errno::Errno; use spin::Once; -#[cfg(debug_assertions)] -use crate::debug_serial_println; - -// 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() } { - crate::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); + 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 save_boot_info(possible_cpus: u32, mem_pa: u64, mem_size: u64) { + 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 9a87469cf..f64a2181c 100644 --- a/litebox_platform_lvbs/src/mshv/vtl1_mem_layout.rs +++ b/litebox_platform_lvbs/src/mshv/vtl1_mem_layout.rs @@ -3,8 +3,6 @@ //! VTL1 physical memory layout (LVBS-specific) -use thiserror::Error; - pub const PAGE_SIZE: usize = 4096; pub const PAGE_SHIFT: usize = 12; pub const PTES_PER_PAGE: usize = 512; @@ -13,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 @@ -24,12 +21,15 @@ pub const VTL1_PDPE_PAGE: usize = 3; pub const VTL1_PDE_PAGE: usize = 4; 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; + /// PDPT page for the Phase 1 high-canonical PML4 entry. Placed after the /// VTL0-reserved special pages (GDT, TSS, PT pages, stack, boot params, /// cmdline) so that all 8 VTL0 PTE pages remain available for the /// high-canonical mapping. This page is within the VTL0 identity-mapped /// 16 MiB region but is otherwise unused memory. -pub const VTL1_REMAP_PDPT_PAGE: usize = VTL1_CMDLINE_PAGE + 1; +pub const VTL1_REMAP_PDPT_PAGE: usize = VTL1_KERNEL_STACK_PAGE + 1; /// PDE page for the Phase 1 high-canonical mapping. PDE entries point to /// all 8 VTL0 PTE pages (pages 5–12) to establish 4KB-granularity mappings @@ -47,16 +47,6 @@ const _: () = assert!( "Phase 1 remap assumes all PTE pages fit in a single PDE page" ); -// 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: VTL1_BOOT_PARAMS_PAGE and VTL1_CMDLINE_PAGE will be removed in an -// upcoming PR: boot parameters will be passed as arguments to _start() instead. -// When that lands, VTL1_REMAP_PDPT_PAGE should follow VTL1_KERNEL_STACK_PAGE -// directly. -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; @@ -116,13 +106,3 @@ pub fn get_rela_start_address() -> u64 { pub fn get_rela_end_address() -> u64 { &raw const _rela_end as u64 } - -/// Errors for VTL memory operations. -#[derive(Debug, Error, PartialEq)] -#[non_exhaustive] -pub enum VtlMemoryError { - #[error("invalid boot parameters")] - InvalidBootParams, - #[error("invalid command line")] - InvalidCmdLine, -} diff --git a/litebox_runner_lvbs/src/main.rs b/litebox_runner_lvbs/src/main.rs index e2fd5b792..a744dbd09 100644 --- a/litebox_runner_lvbs/src/main.rs +++ b/litebox_runner_lvbs/src/main.rs @@ -10,7 +10,7 @@ use core::sync::atomic::{AtomicBool, Ordering}; use litebox_platform_lvbs::{ arch::{enable_extended_states, enable_fsgsbase, enable_smep_smap, instrs::hlt_loop}, host::{ - bootparam::parse_boot_info, + bootparam::save_boot_info, per_cpu_variables::{ PerCpuVariablesAsm, allocate_per_cpu_variables, init_per_cpu_variables, }, @@ -430,7 +430,8 @@ unsafe extern "C" fn common_start(is_bsp: bool) -> ! { /// context set up by `hvcall_enable_vp_vtl`. #[expect(clippy::missing_safety_doc)] #[unsafe(no_mangle)] -pub unsafe extern "C" fn _start() -> ! { +#[allow(clippy::cast_possible_truncation)] +pub unsafe extern "C" fn _start(possible_cpus: u64, mem_pa: u64, mem_size: u64) -> ! { unsafe { // Phase 1a: Fix GOT entries from link-time (base 0x0) to PA-based VAs. // The binary is linked at address 0x0 but loaded by VTL0 at an arbitrary @@ -438,7 +439,7 @@ pub unsafe extern "C" fn _start() -> ! { // that globals and function pointers resolve correctly under the // identity map (VA == PA) that VTL0 left us with. apply_relocations(); - + save_boot_info(possible_cpus as u32, mem_pa, mem_size); remap_to_high_canonical(); } } @@ -454,8 +455,6 @@ unsafe extern "C" fn kernel_main(is_bsp: bool) -> ! { serial_println!("=============================="); serial_println!(" Hello from LiteBox for LVBS! "); serial_println!("=============================="); - - parse_boot_info(); } let platform = litebox_runner_lvbs::init(is_bsp);