Skip to content

Commit b4d1e3b

Browse files
cpercivaaljimenezb
authored 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 <[email protected]> Co-authored-by: Alejandro Jimenez <[email protected]> Signed-off-by: Patrick Roy <[email protected]>
1 parent 1e1d8ae commit b4d1e3b

File tree

3 files changed

+77
-9
lines changed

3 files changed

+77
-9
lines changed

src/vmm/src/arch/mod.rs

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ use std::sync::LazyLock;
66

77
use log::warn;
88
use serde::{Deserialize, Serialize};
9+
use vm_memory::GuestAddress;
910

1011
/// Module for aarch64 related functionality.
1112
#[cfg(target_arch = "aarch64")]
@@ -77,3 +78,34 @@ impl fmt::Display for DeviceType {
7778
write!(f, "{:?}", self)
7879
}
7980
}
81+
82+
/// Suported boot protocols for
83+
#[derive(Debug, Copy, Clone, PartialEq)]
84+
pub enum BootProtocol {
85+
/// Linux 64-bit boot protocol
86+
LinuxBoot,
87+
#[cfg(target_arch = "x86_64")]
88+
/// PVH boot protocol (x86/HVM direct boot ABI)
89+
PvhBoot,
90+
}
91+
92+
impl fmt::Display for BootProtocol {
93+
fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
94+
match self {
95+
BootProtocol::LinuxBoot => write!(f, "Linux 64-bit boot protocol"),
96+
#[cfg(target_arch = "x86_64")]
97+
BootProtocol::PvhBoot => write!(f, "PVH boot protocol"),
98+
}
99+
}
100+
}
101+
102+
#[derive(Debug, Copy, Clone)]
103+
/// Specifies the entry point address where the guest must start
104+
/// executing code, as well as which boot protocol is to be used
105+
/// to configure the guest initial state.
106+
pub struct EntryPoint {
107+
/// Address in guest memory where the guest must start execution
108+
pub entry_addr: GuestAddress,
109+
/// Specifies which boot protocol to use
110+
pub protocol: BootProtocol,
111+
}

src/vmm/src/builder.rs

Lines changed: 44 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ use libc::EFD_NONBLOCK;
1616
use linux_loader::cmdline::Cmdline as LoaderKernelCmdline;
1717
#[cfg(target_arch = "x86_64")]
1818
use linux_loader::loader::elf::Elf as Loader;
19+
#[cfg(target_arch = "x86_64")]
20+
use linux_loader::loader::elf::PvhBootCapability;
1921
#[cfg(target_arch = "aarch64")]
2022
use linux_loader::loader::pe::PE as Loader;
2123
use linux_loader::loader::KernelLoader;
@@ -29,7 +31,7 @@ use vmm_sys_util::eventfd::EventFd;
2931

3032
#[cfg(target_arch = "x86_64")]
3133
use crate::acpi;
32-
use crate::arch::InitrdConfig;
34+
use crate::arch::{BootProtocol, EntryPoint, InitrdConfig};
3335
#[cfg(target_arch = "aarch64")]
3436
use crate::construct_kvm_mpidrs;
3537
use crate::cpu_config::templates::{
@@ -256,7 +258,7 @@ pub fn build_microvm_for_boot(
256258
.allocate_guest_memory()
257259
.map_err(StartMicrovmError::GuestMemory)?;
258260

259-
let entry_addr = load_kernel(boot_config, &guest_memory)?;
261+
let entry_point = load_kernel(boot_config, &guest_memory)?;
260262
let initrd = load_initrd_from_config(boot_config, &guest_memory)?;
261263
// Clone the command-line so that a failed boot doesn't pollute the original.
262264
#[allow(unused_mut)]
@@ -330,7 +332,7 @@ pub fn build_microvm_for_boot(
330332
vcpus.as_mut(),
331333
&vm_resources.machine_config,
332334
&cpu_template,
333-
entry_addr,
335+
entry_point.entry_addr,
334336
&initrd,
335337
boot_cmdline,
336338
)?;
@@ -339,8 +341,14 @@ pub fn build_microvm_for_boot(
339341

340342
#[cfg(feature = "gdb")]
341343
if let Some(gdb_socket_path) = &vm_resources.machine_config.gdb_socket_path {
342-
gdb::gdb_thread(vmm.clone(), vcpu_fds, gdb_rx, entry_addr, gdb_socket_path)
343-
.map_err(GdbServer)?;
344+
gdb::gdb_thread(
345+
vmm.clone(),
346+
vcpu_fds,
347+
gdb_rx,
348+
entry_point.entry_addr,
349+
gdb_socket_path,
350+
)
351+
.map_err(GdbServer)?;
344352
} else {
345353
debug!("No GDB socket provided not starting gdb server.");
346354
}
@@ -562,13 +570,12 @@ pub fn build_microvm_from_snapshot(
562570
fn load_kernel(
563571
boot_config: &BootConfig,
564572
guest_memory: &GuestMemoryMmap,
565-
) -> Result<GuestAddress, StartMicrovmError> {
573+
) -> Result<EntryPoint, StartMicrovmError> {
566574
let mut kernel_file = boot_config
567575
.kernel_file
568576
.try_clone()
569577
.map_err(|err| StartMicrovmError::Internal(VmmError::KernelFile(err)))?;
570578

571-
#[cfg(target_arch = "x86_64")]
572579
let entry_addr = Loader::load::<std::fs::File, GuestMemoryMmap>(
573580
guest_memory,
574581
None,
@@ -577,7 +584,32 @@ fn load_kernel(
577584
)
578585
.map_err(StartMicrovmError::KernelLoader)?;
579586

580-
#[cfg(target_arch = "aarch64")]
587+
let mut entry_point_addr: GuestAddress = entry_addr.kernel_load;
588+
let mut boot_prot: BootProtocol = BootProtocol::LinuxBoot;
589+
if let PvhBootCapability::PvhEntryPresent(pvh_entry_addr) = entry_addr.pvh_boot_cap {
590+
// Use the PVH kernel entry point to boot the guest
591+
entry_point_addr = pvh_entry_addr;
592+
boot_prot = BootProtocol::PvhBoot;
593+
}
594+
595+
debug!("Kernel loaded using {boot_prot}");
596+
597+
Ok(EntryPoint {
598+
entry_addr: entry_point_addr,
599+
protocol: boot_prot,
600+
})
601+
}
602+
603+
#[cfg(target_arch = "aarch64")]
604+
fn load_kernel(
605+
boot_config: &BootConfig,
606+
guest_memory: &GuestMemoryMmap,
607+
) -> Result<EntryPoint, StartMicrovmError> {
608+
let mut kernel_file = boot_config
609+
.kernel_file
610+
.try_clone()
611+
.map_err(|err| StartMicrovmError::Internal(VmmError::KernelFile(err)))?;
612+
581613
let entry_addr = Loader::load::<std::fs::File, GuestMemoryMmap>(
582614
guest_memory,
583615
Some(GuestAddress(crate::arch::get_kernel_start())),
@@ -586,7 +618,10 @@ fn load_kernel(
586618
)
587619
.map_err(StartMicrovmError::KernelLoader)?;
588620

589-
Ok(entry_addr.kernel_load)
621+
Ok(EntryPoint {
622+
entry_addr: entry_addr.kernel_load,
623+
protocol: BootProtocol::LinuxBoot,
624+
})
590625
}
591626

592627
fn load_initrd_from_config(

src/vmm/src/vstate/vcpu/aarch64.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -302,6 +302,7 @@ mod tests {
302302
use std::os::unix::io::AsRawFd;
303303

304304
use kvm_bindings::{KVM_ARM_VCPU_PSCI_0_2, KVM_REG_SIZE_U64};
305+
use vm_memory::GuestAddress;
305306

306307
use super::*;
307308
use crate::arch::aarch64::regs::Aarch64RegisterRef;

0 commit comments

Comments
 (0)