Skip to content

Commit da6f960

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. On x86-64 (the only architecture where multiple boot protocols are supported) we print the protocol used to load the kernel at the debug log level. 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. This commit also splits the load_kernel function into an x86-64 specific version and an aarch64 specific version. Signed-off-by: Colin Percival <cperciva@freebsd.org> Co-authored-by: Alejandro Jimenez <alejandro.j.jimenez@oracle.com>
1 parent 1a2c6ad commit da6f960

File tree

2 files changed

+71
-7
lines changed

2 files changed

+71
-7
lines changed

src/vmm/src/arch/mod.rs

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

src/vmm/src/builder.rs

Lines changed: 40 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,15 @@ use libc::EFD_NONBLOCK;
1414
use linux_loader::cmdline::Cmdline as LoaderKernelCmdline;
1515
#[cfg(target_arch = "x86_64")]
1616
use linux_loader::loader::elf::Elf as Loader;
17+
#[cfg(target_arch = "x86_64")]
18+
use linux_loader::loader::elf::PvhBootCapability;
1719
#[cfg(target_arch = "aarch64")]
1820
use linux_loader::loader::pe::PE as Loader;
1921
use linux_loader::loader::KernelLoader;
22+
#[cfg(target_arch = "aarch64")]
2023
use log::error;
24+
#[cfg(target_arch = "x86_64")]
25+
use log::{debug, error};
2126
use seccompiler::BpfThreadMap;
2227
use snapshot::Persist;
2328
use userfaultfd::Uffd;
@@ -28,7 +33,7 @@ use utils::vm_memory::{GuestAddress, GuestMemory, GuestMemoryMmap, ReadVolatile}
2833
use vm_superio::Rtc;
2934
use vm_superio::Serial;
3035

31-
use crate::arch::InitrdConfig;
36+
use crate::arch::{BootProtocol, EntryPoint, InitrdConfig};
3237
#[cfg(target_arch = "aarch64")]
3338
use crate::construct_kvm_mpidrs;
3439
use crate::cpu_config::templates::{
@@ -256,7 +261,7 @@ pub fn build_microvm_for_boot(
256261

257262
let track_dirty_pages = vm_resources.track_dirty_pages();
258263
let guest_memory = create_guest_memory(vm_resources.vm_config.mem_size_mib, track_dirty_pages)?;
259-
let entry_addr = load_kernel(boot_config, &guest_memory)?;
264+
let entry_point = load_kernel(boot_config, &guest_memory)?;
260265
let initrd = load_initrd_from_config(boot_config, &guest_memory)?;
261266
// Clone the command-line so that a failed boot doesn't pollute the original.
262267
#[allow(unused_mut)]
@@ -310,7 +315,7 @@ pub fn build_microvm_for_boot(
310315
&vmm,
311316
vcpus.as_mut(),
312317
&vm_resources.vm_config,
313-
entry_addr,
318+
entry_point.entry_addr,
314319
&initrd,
315320
boot_cmdline,
316321
)?;
@@ -544,16 +549,16 @@ pub fn create_guest_memory(
544549
.map_err(StartMicrovmError::GuestMemoryMmap)
545550
}
546551

552+
#[cfg(target_arch = "x86_64")]
547553
fn load_kernel(
548554
boot_config: &BootConfig,
549555
guest_memory: &GuestMemoryMmap,
550-
) -> Result<GuestAddress, StartMicrovmError> {
556+
) -> Result<EntryPoint, StartMicrovmError> {
551557
let mut kernel_file = boot_config
552558
.kernel_file
553559
.try_clone()
554560
.map_err(|err| StartMicrovmError::Internal(VmmError::KernelFile(err)))?;
555561

556-
#[cfg(target_arch = "x86_64")]
557562
let entry_addr = Loader::load::<std::fs::File, GuestMemoryMmap>(
558563
guest_memory,
559564
None,
@@ -562,7 +567,32 @@ fn load_kernel(
562567
)
563568
.map_err(StartMicrovmError::KernelLoader)?;
564569

565-
#[cfg(target_arch = "aarch64")]
570+
let mut entry_point_addr: GuestAddress = entry_addr.kernel_load;
571+
let mut boot_prot: BootProtocol = BootProtocol::LinuxBoot;
572+
if let PvhBootCapability::PvhEntryPresent(pvh_entry_addr) = entry_addr.pvh_boot_cap {
573+
// Use the PVH kernel entry point to boot the guest
574+
entry_point_addr = pvh_entry_addr;
575+
boot_prot = BootProtocol::PvhBoot;
576+
}
577+
578+
debug!("Kernel loaded using {boot_prot}");
579+
580+
Ok(EntryPoint {
581+
entry_addr: entry_point_addr,
582+
protocol: boot_prot,
583+
})
584+
}
585+
586+
#[cfg(target_arch = "aarch64")]
587+
fn load_kernel(
588+
boot_config: &BootConfig,
589+
guest_memory: &GuestMemoryMmap,
590+
) -> Result<EntryPoint, StartMicrovmError> {
591+
let mut kernel_file = boot_config
592+
.kernel_file
593+
.try_clone()
594+
.map_err(|err| StartMicrovmError::Internal(VmmError::KernelFile(err)))?;
595+
566596
let entry_addr = Loader::load::<std::fs::File, GuestMemoryMmap>(
567597
guest_memory,
568598
Some(GuestAddress(crate::arch::get_kernel_start())),
@@ -571,7 +601,10 @@ fn load_kernel(
571601
)
572602
.map_err(StartMicrovmError::KernelLoader)?;
573603

574-
Ok(entry_addr.kernel_load)
604+
Ok(EntryPoint {
605+
entry_addr: entry_addr.kernel_load,
606+
protocol: BootProtocol::LinuxBoot,
607+
})
575608
}
576609

577610
fn load_initrd_from_config(

0 commit comments

Comments
 (0)