mirror of
https://github.com/cloud-hypervisor/cloud-hypervisor.git
synced 2024-12-22 13:45:20 +00:00
vmm: Add support for booting raw binary (e.g. firmware) on x86-64
If the provided binary isn't an ELF binary assume that it is a firmware to be loaded in directly. In this case we shouldn't program any of the registers as KVM starts in that state. Signed-off-by: Rob Bradford <robert.bradford@intel.com>
This commit is contained in:
parent
bc827ee3be
commit
82d06c0efa
@ -57,7 +57,7 @@ const KVM_FEATURE_STEAL_TIME_BIT: u8 = 5;
|
|||||||
/// is to be used to configure the guest initial state.
|
/// is to be used to configure the guest initial state.
|
||||||
pub struct EntryPoint {
|
pub struct EntryPoint {
|
||||||
/// Address in guest memory where the guest must start execution
|
/// Address in guest memory where the guest must start execution
|
||||||
pub entry_addr: GuestAddress,
|
pub entry_addr: Option<GuestAddress>,
|
||||||
}
|
}
|
||||||
|
|
||||||
const E820_RAM: u32 = 1;
|
const E820_RAM: u32 = 1;
|
||||||
@ -741,11 +741,12 @@ pub fn configure_vcpu(
|
|||||||
|
|
||||||
regs::setup_msrs(fd).map_err(Error::MsrsConfiguration)?;
|
regs::setup_msrs(fd).map_err(Error::MsrsConfiguration)?;
|
||||||
if let Some(kernel_entry_point) = kernel_entry_point {
|
if let Some(kernel_entry_point) = kernel_entry_point {
|
||||||
// Safe to unwrap because this method is called after the VM is configured
|
if let Some(entry_addr) = kernel_entry_point.entry_addr {
|
||||||
regs::setup_regs(fd, kernel_entry_point.entry_addr.raw_value())
|
// Safe to unwrap because this method is called after the VM is configured
|
||||||
.map_err(Error::RegsConfiguration)?;
|
regs::setup_regs(fd, entry_addr.raw_value()).map_err(Error::RegsConfiguration)?;
|
||||||
regs::setup_fpu(fd).map_err(Error::FpuConfiguration)?;
|
regs::setup_fpu(fd).map_err(Error::FpuConfiguration)?;
|
||||||
regs::setup_sregs(&vm_memory.memory(), fd).map_err(Error::SregsConfiguration)?;
|
regs::setup_sregs(&vm_memory.memory(), fd).map_err(Error::SregsConfiguration)?;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
interrupts::set_lint(fd).map_err(|e| Error::LocalIntConfiguration(e.into()))?;
|
interrupts::set_lint(fd).map_err(|e| Error::LocalIntConfiguration(e.into()))?;
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -70,9 +70,7 @@ use std::{result, str, thread};
|
|||||||
use vm_device::Bus;
|
use vm_device::Bus;
|
||||||
#[cfg(target_arch = "x86_64")]
|
#[cfg(target_arch = "x86_64")]
|
||||||
use vm_device::BusDevice;
|
use vm_device::BusDevice;
|
||||||
#[cfg(any(target_arch = "aarch64", feature = "tdx"))]
|
use vm_memory::{Address, Bytes, GuestAddress, GuestAddressSpace, GuestMemoryAtomic};
|
||||||
use vm_memory::Address;
|
|
||||||
use vm_memory::{Bytes, GuestAddress, GuestAddressSpace, GuestMemoryAtomic};
|
|
||||||
#[cfg(feature = "tdx")]
|
#[cfg(feature = "tdx")]
|
||||||
use vm_memory::{GuestMemory, GuestMemoryRegion};
|
use vm_memory::{GuestMemory, GuestMemoryRegion};
|
||||||
use vm_migration::{
|
use vm_migration::{
|
||||||
@ -238,6 +236,18 @@ pub enum Error {
|
|||||||
/// Kernel lacks PVH header
|
/// Kernel lacks PVH header
|
||||||
KernelMissingPvhHeader,
|
KernelMissingPvhHeader,
|
||||||
|
|
||||||
|
/// Failed to allocate firmware RAM
|
||||||
|
AllocateFirmwareMemory(MemoryManagerError),
|
||||||
|
|
||||||
|
/// Error manipulating firmware file
|
||||||
|
FirmwareFile(std::io::Error),
|
||||||
|
|
||||||
|
/// Firmware too big
|
||||||
|
FirmwareTooLarge,
|
||||||
|
|
||||||
|
// Failed to copy to memory
|
||||||
|
FirmwareLoad(vm_memory::GuestMemoryError),
|
||||||
|
|
||||||
/// Error doing I/O on TDX firmware file
|
/// Error doing I/O on TDX firmware file
|
||||||
#[cfg(feature = "tdx")]
|
#[cfg(feature = "tdx")]
|
||||||
LoadTdvf(std::io::Error),
|
LoadTdvf(std::io::Error),
|
||||||
@ -961,6 +971,7 @@ impl Vm {
|
|||||||
|
|
||||||
#[cfg(target_arch = "x86_64")]
|
#[cfg(target_arch = "x86_64")]
|
||||||
fn load_kernel(&mut self) -> Result<EntryPoint> {
|
fn load_kernel(&mut self) -> Result<EntryPoint> {
|
||||||
|
use linux_loader::loader::{elf::Error::InvalidElfMagicNumber, Error::Elf};
|
||||||
info!("Loading kernel");
|
info!("Loading kernel");
|
||||||
let cmdline = self.get_cmdline()?;
|
let cmdline = self.get_cmdline()?;
|
||||||
let guest_memory = self.memory_manager.lock().as_ref().unwrap().guest_memory();
|
let guest_memory = self.memory_manager.lock().as_ref().unwrap().guest_memory();
|
||||||
@ -973,9 +984,41 @@ impl Vm {
|
|||||||
Some(arch::layout::HIGH_RAM_START),
|
Some(arch::layout::HIGH_RAM_START),
|
||||||
) {
|
) {
|
||||||
Ok(entry_addr) => entry_addr,
|
Ok(entry_addr) => entry_addr,
|
||||||
Err(e) => {
|
Err(e) => match e {
|
||||||
return Err(Error::KernelLoad(e));
|
Elf(InvalidElfMagicNumber) => {
|
||||||
}
|
// Not an ELF header - assume raw binary data / firmware
|
||||||
|
let size = kernel.seek(SeekFrom::End(0)).map_err(Error::FirmwareFile)?;
|
||||||
|
|
||||||
|
// The OVMF firmware is as big as you might expect and it's 4MiB so limit to that
|
||||||
|
if size > 4 << 20 {
|
||||||
|
return Err(Error::FirmwareTooLarge);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Loaded at the end of the 4GiB
|
||||||
|
let load_address = GuestAddress(4 << 30)
|
||||||
|
.checked_sub(size)
|
||||||
|
.ok_or(Error::FirmwareTooLarge)?;
|
||||||
|
|
||||||
|
self.memory_manager
|
||||||
|
.lock()
|
||||||
|
.unwrap()
|
||||||
|
.add_ram_region(load_address, size as usize)
|
||||||
|
.map_err(Error::AllocateFirmwareMemory)?;
|
||||||
|
|
||||||
|
kernel
|
||||||
|
.seek(SeekFrom::Start(0))
|
||||||
|
.map_err(Error::FirmwareFile)?;
|
||||||
|
guest_memory
|
||||||
|
.memory()
|
||||||
|
.read_exact_from(load_address, &mut kernel, size as usize)
|
||||||
|
.map_err(Error::FirmwareLoad)?;
|
||||||
|
|
||||||
|
return Ok(EntryPoint { entry_addr: None });
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
return Err(Error::KernelLoad(e));
|
||||||
|
}
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
linux_loader::loader::load_cmdline(mem.deref(), arch::layout::CMDLINE_START, &cmdline)
|
linux_loader::loader::load_cmdline(mem.deref(), arch::layout::CMDLINE_START, &cmdline)
|
||||||
@ -984,7 +1027,9 @@ impl Vm {
|
|||||||
if let PvhEntryPresent(entry_addr) = entry_addr.pvh_boot_cap {
|
if let PvhEntryPresent(entry_addr) = entry_addr.pvh_boot_cap {
|
||||||
// Use the PVH kernel entry point to boot the guest
|
// Use the PVH kernel entry point to boot the guest
|
||||||
info!("Kernel loaded: entry_addr = 0x{:x}", entry_addr.0);
|
info!("Kernel loaded: entry_addr = 0x{:x}", entry_addr.0);
|
||||||
Ok(EntryPoint { entry_addr })
|
Ok(EntryPoint {
|
||||||
|
entry_addr: Some(entry_addr),
|
||||||
|
})
|
||||||
} else {
|
} else {
|
||||||
Err(Error::KernelMissingPvhHeader)
|
Err(Error::KernelMissingPvhHeader)
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user