diff --git a/src/arch/src/lib.rs b/src/arch/src/lib.rs index 8aec44865462..82c41303cb09 100644 --- a/src/arch/src/lib.rs +++ b/src/arch/src/lib.rs @@ -68,3 +68,32 @@ impl fmt::Display for DeviceType { write!(f, "{:?}", self) } } + +/// Suported boot protocols for +#[derive(Debug, Copy, Clone)] +pub enum BootProtocol { + /// Linux 64-bit boot protocol + LinuxBoot, + /// PVH boot protocol (x86/HVM direct boot ABI) + PvhBoot, +} + +impl fmt::Display for BootProtocol { + fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { + match self { + BootProtocol::LinuxBoot => write!(f, "Linux 64-bit boot protocol"), + BootProtocol::PvhBoot => write!(f, "PVH boot protocol"), + } + } +} + +#[derive(Debug, Copy, Clone)] +/// Specifies the entry point address where the guest must start +/// executing code, as well as which boot protocol is to be used +/// to configure the guest initial state. +pub struct EntryPoint { + /// Address in guest memory where the guest must start execution + pub entry_addr: vm_memory::GuestAddress, + /// Specifies which boot protocol to use + pub protocol: BootProtocol, +} diff --git a/src/vmm/src/builder.rs b/src/vmm/src/builder.rs index ea0e9862dcfb..f2812b6a50b1 100644 --- a/src/vmm/src/builder.rs +++ b/src/vmm/src/builder.rs @@ -9,7 +9,7 @@ use std::io::{self, Read, Seek, SeekFrom}; use std::os::unix::io::{AsRawFd, RawFd}; use std::sync::{Arc, Mutex}; -use arch::InitrdConfig; +use arch::{BootProtocol, EntryPoint, InitrdConfig}; #[cfg(target_arch = "x86_64")] use cpuid::common::is_same_model; #[cfg(target_arch = "aarch64")] @@ -23,6 +23,7 @@ use libc::EFD_NONBLOCK; use linux_loader::cmdline::Cmdline as LoaderKernelCmdline; #[cfg(target_arch = "x86_64")] use linux_loader::loader::elf::Elf as Loader; +use linux_loader::loader::elf::PvhBootCapability; #[cfg(target_arch = "aarch64")] use linux_loader::loader::pe::PE as Loader; use linux_loader::loader::KernelLoader; @@ -335,7 +336,7 @@ pub fn build_microvm_for_boot( let guest_memory = create_guest_memory(vm_resources.vm_config().mem_size_mib, track_dirty_pages)?; let vcpu_config = vm_resources.vcpu_config(); - let entry_addr = load_kernel(boot_config, &guest_memory)?; + let entry_point = load_kernel(boot_config, &guest_memory)?; let initrd = load_initrd_from_config(boot_config, &guest_memory)?; // Clone the command-line so that a failed boot doesn't pollute the original. #[allow(unused_mut)] @@ -384,7 +385,7 @@ pub fn build_microvm_for_boot( &vmm, vcpus.as_mut(), vcpu_config, - entry_addr, + entry_point.entry_addr, &initrd, boot_cmdline, )?; @@ -613,7 +614,7 @@ pub fn create_guest_memory( fn load_kernel( boot_config: &BootConfig, guest_memory: &GuestMemoryMmap, -) -> std::result::Result { +) -> std::result::Result { let mut kernel_file = boot_config .kernel_file .try_clone() @@ -637,7 +638,21 @@ fn load_kernel( ) .map_err(StartMicrovmError::KernelLoader)?; - Ok(entry_addr.kernel_load) + let mut entry_point_addr: GuestAddress = entry_addr.kernel_load; + let mut boot_prot: BootProtocol = BootProtocol::LinuxBoot; + + if cfg!(target_arch = "x86_64") { + if let PvhBootCapability::PvhEntryPresent(pvh_entry_addr) = entry_addr.pvh_boot_cap { + // Use the PVH kernel entry point to boot the guest + entry_point_addr = pvh_entry_addr; + boot_prot = BootProtocol::PvhBoot; + } + } + + Ok(EntryPoint { + entry_addr: entry_point_addr, + protocol: boot_prot, + }) } fn load_initrd_from_config(