arch: x86_64: bring back bzImage support

Allow cloud-hypervisor to direct boot the bzImage kernel format using
the regular 32 bit entry point. This can share the memory and vcpu
setup with the regular PVH boot code, but requires the setup of the
'zero page'.

Signed-off-by: Stefan Nuernberger <stefan.nuernberger@cyberus-technology.de>
This commit is contained in:
Stefan Nuernberger
2024-02-09 17:35:29 +01:00
committed by Rob Bradford
parent da3693f164
commit 09cf8c3118
5 changed files with 289 additions and 29 deletions
+41 -2
View File
@@ -2715,9 +2715,12 @@ impl CpuElf64Writable for CpuManager {
#[cfg(all(feature = "kvm", target_arch = "x86_64"))]
#[cfg(test)]
mod tests {
use arch::layout::BOOT_STACK_POINTER;
use arch::layout::ZERO_PAGE_START;
use arch::x86_64::interrupts::*;
use arch::x86_64::regs::*;
use hypervisor::arch::x86::{FpuState, LapicState, StandardRegisters};
use linux_loader::loader::bootparam::setup_header;
#[test]
fn test_setlint() {
@@ -2796,7 +2799,7 @@ mod tests {
}
#[test]
fn test_setup_regs() {
fn test_setup_regs_for_pvh() {
let hv = hypervisor::new().unwrap();
let vm = hv.create_vm().expect("new VM fd creation failed");
let vcpu = vm.create_vcpu(0, None).unwrap();
@@ -2808,7 +2811,43 @@ mod tests {
..Default::default()
};
setup_regs(&vcpu, expected_regs.rip).unwrap();
setup_regs(
&vcpu,
arch::EntryPoint {
entry_addr: vm_memory::GuestAddress(expected_regs.rip),
setup_header: None,
},
)
.unwrap();
let actual_regs: StandardRegisters = vcpu.get_regs().unwrap();
assert_eq!(actual_regs, expected_regs);
}
#[test]
fn test_setup_regs_for_bzimage() {
let hv = hypervisor::new().unwrap();
let vm = hv.create_vm().expect("new VM fd creation failed");
let vcpu = vm.create_vcpu(0, None).unwrap();
let expected_regs: StandardRegisters = StandardRegisters {
rflags: 0x0000000000000002u64,
rip: 1,
rsp: BOOT_STACK_POINTER.0,
rsi: ZERO_PAGE_START.0,
..Default::default()
};
setup_regs(
&vcpu,
arch::EntryPoint {
entry_addr: vm_memory::GuestAddress(expected_regs.rip),
setup_header: Some(setup_header {
..Default::default()
}),
},
)
.unwrap();
let actual_regs: StandardRegisters = vcpu.get_regs().unwrap();
assert_eq!(actual_regs, expected_regs);
+41 -9
View File
@@ -62,6 +62,8 @@ use linux_loader::cmdline::Cmdline;
#[cfg(all(target_arch = "x86_64", feature = "guest_debug"))]
use linux_loader::elf;
#[cfg(target_arch = "x86_64")]
use linux_loader::loader::bzimage::BzImage;
#[cfg(target_arch = "x86_64")]
use linux_loader::loader::elf::PvhBootCapability::PvhEntryPresent;
#[cfg(target_arch = "aarch64")]
use linux_loader::loader::pe::Error::InvalidImageMagicNumber;
@@ -1012,12 +1014,12 @@ impl Vm {
cfg_if::cfg_if! {
if #[cfg(feature = "sev_snp")] {
let entry_point = if cpu_manager.lock().unwrap().sev_snp_enabled() {
EntryPoint { entry_addr: vm_memory::GuestAddress(res.vmsa_gpa) }
EntryPoint { entry_addr: vm_memory::GuestAddress(res.vmsa_gpa), setup_header: None }
} else {
EntryPoint {entry_addr: vm_memory::GuestAddress(res.vmsa.rip) }
EntryPoint {entry_addr: vm_memory::GuestAddress(res.vmsa.rip), setup_header: None }
};
} else {
let entry_point = EntryPoint { entry_addr: vm_memory::GuestAddress(res.vmsa.rip) };
let entry_point = EntryPoint { entry_addr: vm_memory::GuestAddress(res.vmsa.rip), setup_header: None };
}
};
Ok(entry_point)
@@ -1035,12 +1037,23 @@ impl Vm {
let guest_memory = memory_manager.lock().as_ref().unwrap().guest_memory();
guest_memory.memory()
};
// Try ELF binary with PVH boot.
let entry_addr = linux_loader::loader::elf::Elf::load(
mem.deref(),
None,
&mut kernel,
Some(arch::layout::HIGH_RAM_START),
)
// Try loading kernel as bzImage.
.or_else(|_| {
BzImage::load(
mem.deref(),
None,
&mut kernel,
Some(arch::layout::HIGH_RAM_START),
)
})
.map_err(Error::KernelLoad)?;
if let Some(cmdline) = cmdline {
@@ -1050,8 +1063,21 @@ impl Vm {
if let PvhEntryPresent(entry_addr) = entry_addr.pvh_boot_cap {
// Use the PVH kernel entry point to boot the guest
info!("Kernel loaded: entry_addr = 0x{:x}", entry_addr.0);
Ok(EntryPoint { entry_addr })
info!("PVH kernel loaded: entry_addr = 0x{:x}", entry_addr.0);
Ok(EntryPoint {
entry_addr,
setup_header: None,
})
} else if entry_addr.setup_header.is_some() {
// Use the bzImage 32bit entry point to boot the guest
info!(
"bzImage kernel loaded: entry_addr = 0x{:x}",
entry_addr.kernel_load.0
);
Ok(EntryPoint {
entry_addr: entry_addr.kernel_load,
setup_header: entry_addr.setup_header,
})
} else {
Err(Error::KernelMissingPvhHeader)
}
@@ -1144,7 +1170,7 @@ impl Vm {
}
#[cfg(target_arch = "x86_64")]
fn configure_system(&mut self, rsdp_addr: GuestAddress) -> Result<()> {
fn configure_system(&mut self, rsdp_addr: GuestAddress, entry_addr: EntryPoint) -> Result<()> {
trace_scoped!("configure_system");
info!("Configuring system");
let mem = self.memory_manager.lock().unwrap().boot_guest_memory();
@@ -1197,8 +1223,10 @@ impl Vm {
arch::configure_system(
&mem,
arch::layout::CMDLINE_START,
arch::layout::CMDLINE_MAX_SIZE,
&initramfs_config,
boot_vcpus,
entry_addr.setup_header,
rsdp_addr,
sgx_epc_region,
serial_number.as_deref(),
@@ -1211,7 +1239,11 @@ impl Vm {
}
#[cfg(target_arch = "aarch64")]
fn configure_system(&mut self, _rsdp_addr: GuestAddress) -> Result<()> {
fn configure_system(
&mut self,
_rsdp_addr: GuestAddress,
_entry_addr: EntryPoint,
) -> Result<()> {
let cmdline = Self::generate_cmdline(
self.config.lock().unwrap().payload.as_ref().unwrap(),
&self.device_manager,
@@ -2082,10 +2114,10 @@ impl Vm {
// Configure shared state based on loaded kernel
entry_point
.map(|_| {
.map(|entry_point| {
// Safe to unwrap rsdp_addr as we know it can't be None when
// the entry_point is Some.
self.configure_system(rsdp_addr.unwrap())
self.configure_system(rsdp_addr.unwrap(), entry_point)
})
.transpose()?;