Skip to content

Commit 7db9afb

Browse files
cpercivaaljimenezb
andcommitted
pvh/arch: Introduce EntryPoint struct
In order to properly configure the initial vCPU register state and boot parameters in guest memory, we must specify which boot protocol to use with the kernel entry point address. Create an EntryPoint struct that contains the required information. This structure will later be used in the vCPU configuration methods to set the appropriate initial conditions for the guest. Signed-off-by: Colin Percival <cperciva@freebsd.org> Co-authored-by: Alejandro Jimenez <alejandro.j.jimenez@oracle.com>
1 parent 78851bc commit 7db9afb

File tree

2 files changed

+55
-5
lines changed

2 files changed

+55
-5
lines changed

src/arch/src/lib.rs

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,3 +68,32 @@ impl fmt::Display for DeviceType {
6868
write!(f, "{:?}", self)
6969
}
7070
}
71+
72+
/// Suported boot protocols for
73+
#[derive(Debug, Copy, Clone)]
74+
pub enum BootProtocol {
75+
/// Linux 64-bit boot protocol
76+
LinuxBoot,
77+
/// PVH boot protocol (x86/HVM direct boot ABI)
78+
PvhBoot,
79+
}
80+
81+
impl fmt::Display for BootProtocol {
82+
fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
83+
match self {
84+
BootProtocol::LinuxBoot => write!(f, "Linux 64-bit boot protocol"),
85+
BootProtocol::PvhBoot => write!(f, "PVH boot protocol"),
86+
}
87+
}
88+
}
89+
90+
#[derive(Debug, Copy, Clone)]
91+
/// Specifies the entry point address where the guest must start
92+
/// executing code, as well as which boot protocol is to be used
93+
/// to configure the guest initial state.
94+
pub struct EntryPoint {
95+
/// Address in guest memory where the guest must start execution
96+
pub entry_addr: vm_memory::GuestAddress,
97+
/// Specifies which boot protocol to use
98+
pub protocol: BootProtocol,
99+
}

src/vmm/src/builder.rs

Lines changed: 26 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ use std::io::{self, Read, Seek, SeekFrom};
99
use std::os::unix::io::{AsRawFd, RawFd};
1010
use std::sync::{Arc, Mutex};
1111

12-
use arch::InitrdConfig;
12+
use arch::{BootProtocol, EntryPoint, InitrdConfig};
1313
#[cfg(target_arch = "x86_64")]
1414
use cpuid::common::is_same_model;
1515
#[cfg(target_arch = "aarch64")]
@@ -23,6 +23,8 @@ use libc::EFD_NONBLOCK;
2323
use linux_loader::cmdline::Cmdline as LoaderKernelCmdline;
2424
#[cfg(target_arch = "x86_64")]
2525
use linux_loader::loader::elf::Elf as Loader;
26+
#[cfg(target_arch = "x86_64")]
27+
use linux_loader::loader::elf::PvhBootCapability;
2628
#[cfg(target_arch = "aarch64")]
2729
use linux_loader::loader::pe::PE as Loader;
2830
use linux_loader::loader::KernelLoader;
@@ -335,7 +337,7 @@ pub fn build_microvm_for_boot(
335337
let guest_memory =
336338
create_guest_memory(vm_resources.vm_config().mem_size_mib, track_dirty_pages)?;
337339
let vcpu_config = vm_resources.vcpu_config();
338-
let entry_addr = load_kernel(boot_config, &guest_memory)?;
340+
let entry_point = load_kernel(boot_config, &guest_memory)?;
339341
let initrd = load_initrd_from_config(boot_config, &guest_memory)?;
340342
// Clone the command-line so that a failed boot doesn't pollute the original.
341343
#[allow(unused_mut)]
@@ -384,7 +386,7 @@ pub fn build_microvm_for_boot(
384386
&vmm,
385387
vcpus.as_mut(),
386388
vcpu_config,
387-
entry_addr,
389+
entry_point.entry_addr,
388390
&initrd,
389391
boot_cmdline,
390392
)?;
@@ -613,7 +615,7 @@ pub fn create_guest_memory(
613615
fn load_kernel(
614616
boot_config: &BootConfig,
615617
guest_memory: &GuestMemoryMmap,
616-
) -> std::result::Result<GuestAddress, StartMicrovmError> {
618+
) -> std::result::Result<EntryPoint, StartMicrovmError> {
617619
let mut kernel_file = boot_config
618620
.kernel_file
619621
.try_clone()
@@ -637,7 +639,26 @@ fn load_kernel(
637639
)
638640
.map_err(StartMicrovmError::KernelLoader)?;
639641

640-
Ok(entry_addr.kernel_load)
642+
#[cfg(target_arch = "x86_64")]
643+
let mut entry_point_addr: GuestAddress = entry_addr.kernel_load;
644+
#[cfg(target_arch = "x86_64")]
645+
let mut boot_prot: BootProtocol = BootProtocol::LinuxBoot;
646+
#[cfg(target_arch = "x86_64")]
647+
if let PvhBootCapability::PvhEntryPresent(pvh_entry_addr) = entry_addr.pvh_boot_cap {
648+
// Use the PVH kernel entry point to boot the guest
649+
entry_point_addr = pvh_entry_addr;
650+
boot_prot = BootProtocol::PvhBoot;
651+
}
652+
653+
#[cfg(not(target_arch = "x86_64"))]
654+
let entry_point_addr: GuestAddress = entry_addr.kernel_load;
655+
#[cfg(not(target_arch = "x86_64"))]
656+
let boot_prot: BootProtocol = BootProtocol::LinuxBoot;
657+
658+
Ok(EntryPoint {
659+
entry_addr: entry_point_addr,
660+
protocol: boot_prot,
661+
})
641662
}
642663

643664
fn load_initrd_from_config(

0 commit comments

Comments
 (0)