vmm: tdx: Don't load the kernel the usual way

In case of TDX, if a kernel and/or a command line are provided by the
user, they can't be treated the same way as for the non-TDX case. That
is why this patch ensures the function load_kernel() is only invoked for
the non-TDX case.

For the TDX case, whenever TDVF contains a Payload and/or PayloadParam
sections, the file provided through --kernel and the parameters provided
through --cmdline are copied at the locations specified by each TDVF
section.

Signed-off-by: Sebastien Boeuf <sebastien.boeuf@intel.com>
This commit is contained in:
Sebastien Boeuf 2021-12-15 14:16:42 +01:00
parent 2198baa547
commit 3c421593c3

View File

@ -64,6 +64,8 @@ use std::fmt;
use std::fs::{File, OpenOptions};
use std::io::{self, Read, Write};
use std::io::{Seek, SeekFrom};
#[cfg(feature = "tdx")]
use std::mem;
use std::num::Wrapping;
use std::ops::Deref;
use std::os::unix::net::UnixStream;
@ -75,9 +77,9 @@ use vm_device::Bus;
use vm_device::BusDevice;
#[cfg(target_arch = "x86_64")]
use vm_memory::Address;
use vm_memory::{Bytes, GuestAddress, GuestAddressSpace, GuestMemoryAtomic};
#[cfg(feature = "tdx")]
use vm_memory::{GuestMemory, GuestMemoryRegion};
use vm_memory::{ByteValued, GuestMemory, GuestMemoryRegion};
use vm_memory::{Bytes, GuestAddress, GuestAddressSpace, GuestMemoryAtomic};
use vm_migration::protocol::{Request, Response, Status};
use vm_migration::{
protocol::MemoryRangeTable, Migratable, MigratableError, Pausable, Snapshot,
@ -255,10 +257,14 @@ pub enum Error {
// Failed to copy to memory
FirmwareLoad(vm_memory::GuestMemoryError),
/// Error doing I/O on TDX firmware file
/// Error performing I/O on TDX firmware file
#[cfg(feature = "tdx")]
LoadTdvf(std::io::Error),
/// Error performing I/O on the payload file
#[cfg(feature = "tdx")]
LoadPayload(std::io::Error),
/// Error parsing TDVF
#[cfg(feature = "tdx")]
ParseTdvf(arch::x86_64::tdx::TdvfError),
@ -282,6 +288,10 @@ pub enum Error {
/// Error finalizing TDX setup
#[cfg(feature = "tdx")]
FinalizeTdx(hypervisor::HypervisorVmError),
/// Invalid payload type
#[cfg(feature = "tdx")]
InvalidPayloadType,
}
pub type Result<T> = result::Result<T, Error>;
@ -1773,6 +1783,54 @@ impl Vm {
TdvfSectionType::TdHob => {
hob_offset = Some(section.address);
}
TdvfSectionType::Payload => {
info!("Copying payload to guest memory");
if let Some(payload_file) = self.kernel.as_mut() {
let payload_size = payload_file
.seek(SeekFrom::End(0))
.map_err(Error::LoadPayload)?;
payload_file
.seek(SeekFrom::Start(0x1f1))
.map_err(Error::LoadPayload)?;
let mut payload_header = linux_loader::bootparam::setup_header::default();
payload_header
.as_bytes()
.read_from(
0,
payload_file,
mem::size_of::<linux_loader::bootparam::setup_header>(),
)
.unwrap();
if payload_header.header != 0x5372_6448 {
return Err(Error::InvalidPayloadType);
}
if (payload_header.version < 0x0200)
|| ((payload_header.loadflags & 0x1) == 0x0)
{
return Err(Error::InvalidPayloadType);
}
payload_file
.seek(SeekFrom::Start(0))
.map_err(Error::LoadPayload)?;
mem.read_from(
GuestAddress(section.address),
payload_file,
payload_size as usize,
)
.unwrap();
}
}
TdvfSectionType::PayloadParam => {
info!("Copying payload parameters to guest memory");
let cmdline = self.get_cmdline()?;
mem.write_slice(cmdline.as_str().as_bytes(), GuestAddress(section.address))
.unwrap();
}
_ => {}
}
}
@ -1965,6 +2023,18 @@ impl Vm {
Some(rsdp_addr)
}
fn entry_point(&mut self) -> Result<Option<EntryPoint>> {
Ok(if self.kernel.as_ref().is_some() {
#[cfg(feature = "tdx")]
if self.config.lock().unwrap().tdx.is_some() {
return Ok(None);
}
Some(self.load_kernel()?)
} else {
None
})
}
pub fn boot(&mut self) -> Result<()> {
info!("Booting VM");
event!("vm", "booting");
@ -1977,11 +2047,7 @@ impl Vm {
current_state.valid_transition(new_state)?;
// Load kernel if configured
let entry_point = if self.kernel.as_ref().is_some() {
Some(self.load_kernel()?)
} else {
None
};
let entry_point = self.entry_point()?;
// The initial TDX configuration must be done before the vCPUs are
// created