Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
80 changes: 72 additions & 8 deletions openvmm/openvmm_entry/src/ttrpc/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ use openvmm_defs::config::ArchTopologyConfig;
use openvmm_defs::config::Config;
use openvmm_defs::config::DeviceVtl;
use openvmm_defs::config::HypervisorConfig;
use openvmm_defs::config::IsolationType;
use openvmm_defs::config::LoadMode;
use openvmm_defs::config::MemoryConfig;
use openvmm_defs::config::NumaDistance;
Expand All @@ -75,6 +76,7 @@ use openvmm_defs::config::VirtioBus;
use openvmm_defs::config::VmbusConfig;
use openvmm_defs::config::VpAssignment;
use openvmm_defs::config::VpciDeviceConfig;
use openvmm_defs::config::Vtl2BaseAddressType;
use openvmm_defs::rpc::VmRpc;
use openvmm_defs::worker::VM_WORKER;
use openvmm_defs::worker::VmWorkerParameters;
Expand All @@ -88,6 +90,7 @@ use pal_async::task::Task;
use scsidisk_resources::SimpleScsiDiskHandle;
use std::fs::File;
use std::future::Future;
use std::path::PathBuf;
use std::sync::Arc;
use std::time::Duration;
use storvsp_resources::ScsiControllerHandle;
Expand Down Expand Up @@ -774,18 +777,32 @@ impl VmService {
#[cfg(guest_arch = "x86_64")]
let arch = vm_manifest_builder::MachineArch::X86_64;

// SMBIOS identity is applied regardless of boot type; build it once and
// move it into whichever LoadMode is selected below.
// Build SMBIOS identity for direct Linux or UEFI boot.
let smbios_requested = req_config.smbios_config.is_some();
let smbios = Box::new(smbios_config_from_proto(req_config.smbios_config.take())?);

let isolation_type = req_config
.isolation_config
.take()
.unwrap_or_default()
.isolation_type;
let isolation = match vmservice::isolation_config::Type::from_i32(isolation_type) {
Some(vmservice::isolation_config::Type::None) => None,
Some(vmservice::isolation_config::Type::Snp) => Some(IsolationType::Snp),
None => bail!("unsupported isolation type {isolation_type}"),
};

// The boot configuration also determines the base chipset, since the
// firmware and the device model have to agree on the platform.
let (load_mode, base_chipset_type, uefi_config) = match req_config
let (load_mode, base_chipset_type, uefi_config, igvm_path) = match req_config
.boot_config
.take()
.context("missing boot configuration")?
{
vmservice::vm_config::BootConfig::DirectBoot(boot) => {
if isolation.is_some() {
bail!("VM-service SNP isolation currently supports only IGVM boot");
}
let kernel = File::open(boot.kernel_path).context("failed to open kernel")?;
let initrd = if boot.initrd_path.is_empty() {
None
Expand All @@ -804,9 +821,47 @@ impl VmService {
},
vm_manifest_builder::BaseChipsetType::HyperVGen2LinuxDirect,
None,
None,
)
}
vmservice::vm_config::BootConfig::Igvm(boot) => {
if smbios_requested {
bail!("VM-service IGVM boot does not support SMBIOS overrides");
}
if isolation != Some(IsolationType::Snp) {
bail!("VM-service IGVM boot currently supports only SNP isolation");
}
let base_chipset_type =
match vmservice::igvm_boot::Personality::from_i32(boot.personality) {
Some(vmservice::igvm_boot::Personality::LinuxDirect) => {
vm_manifest_builder::BaseChipsetType::EnlightenedLinuxDirect
}
Some(vmservice::igvm_boot::Personality::Uefi) => {
bail!(
"VM-service IGVM boot with UEFI personality is not yet supported"
);
}
None => bail!("unsupported IGVM personality {}", boot.personality),
};
let igvm_path = PathBuf::from(&boot.igvm_path);
let file = File::open(&igvm_path)
.with_context(|| format!("failed to open IGVM {}", igvm_path.display()))?;
(
LoadMode::Igvm {
file,
cmdline: String::new(),
vtl2_base_address: Vtl2BaseAddressType::File,
com_serial: None,
Comment thread
nbojanic marked this conversation as resolved.
},
base_chipset_type,
None,
Some(igvm_path),
)
}
vmservice::vm_config::BootConfig::Uefi(uefi) => {
if isolation.is_some() {
bail!("VM-service SNP isolation currently supports only IGVM boot");
}
let firmware = File::open(&uefi.firmware_path).with_context(|| {
format!("failed to open uefi firmware {}", uefi.firmware_path)
})?;
Expand Down Expand Up @@ -851,7 +906,7 @@ impl VmService {
// VM with no graphics adapter.
uefi_console_mode: com1_configured.then_some(UefiConsoleMode::Com1),
smbios,
enable_vmbus: true,
enable_vmbus: !req_config.disable_vmbus,
// Everything below is fixed for now. The proto has no
// way to express these yet; fields will be added as
// callers need them.
Expand All @@ -872,12 +927,16 @@ impl VmService {
},
vm_manifest_builder::BaseChipsetType::HypervGen2Uefi,
Some((base_template, uefi.secure_boot_enabled)),
None,
)
}
};

let mut chipset_builder =
VmManifestBuilder::new(base_chipset_type, arch).with_serial(ports);
if req_config.disable_vmbus {
chipset_builder = chipset_builder.without_vmbus();
}
if let Some((base_template, secure_boot_enabled)) = uefi_config {
// The UEFI helper device backs the firmware's variable store and
// runtime services, so it is required for a UEFI boot. The store is
Expand Down Expand Up @@ -970,6 +1029,7 @@ impl VmService {
},
hypervisor: HypervisorConfig {
with_hv: true,
with_isolation: isolation,
..Default::default()
},
#[cfg(windows)]
Expand All @@ -979,7 +1039,7 @@ impl VmService {
vga_firmware: None,
vtl2_gfx: false,
virtio_devices: vec![],
vmbus: Some(VmbusConfig::default()),
vmbus: (!req_config.disable_vmbus).then(VmbusConfig::default),
vtl2_vmbus: None,
vmbus_devices: vec![],
#[cfg(windows)]
Expand Down Expand Up @@ -1103,11 +1163,15 @@ impl VmService {
}

if let Some(hvsocket_config) = req_config.hvsocket_config {
let vmbus = config
.vmbus
.as_mut()
.context("HVSocket requires VMBus to be enabled")?;
let listener = UnixListener::bind(&hvsocket_config.path).with_context(|| {
format!("failed to bind hvsocket path: {}", hvsocket_config.path)
})?;
config.vmbus.as_mut().unwrap().vsock_listener = Some(listener);
config.vmbus.as_mut().unwrap().vsock_path = Some(hvsocket_config.path);
vmbus.vsock_listener = Some(listener);
vmbus.vsock_path = Some(hvsocket_config.path);
}

let (send, recv) = mesh::channel();
Expand Down Expand Up @@ -1152,7 +1216,7 @@ impl VmService {
ged_rpc: None,
vm_rpc: send.clone(),
paravisor_diag: None,
igvm_path: None,
igvm_path,
memory_backing_file: None,
memory,
processors,
Expand Down
37 changes: 36 additions & 1 deletion openvmm/openvmm_ttrpc_vmservice/src/vmservice.proto
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,34 @@ message DirectBoot {
string kernel_cmdline = 3;
}

// Boot from an IGVM file.
message IgvmBoot {
enum Personality {
// Linux direct boot with Hyper-V enlightenments.
LINUX_DIRECT = 0;
// Reserved for UEFI IGVM boot.
UEFI = 1;
}

// Path to the IGVM file on the host.
string igvm_path = 1;
// Guest boot environment.
Personality personality = 2;
}

// Confidential-computing isolation configuration.
message IsolationConfig {
enum Type {
// No confidential-computing isolation.
NONE = 0;
// AMD SEV-SNP isolation.
SNP = 1;
}

// Isolation mode.
Type isolation_type = 1;
}

message UEFI {
// Variables used to initialize an empty UEFI variable store. These are
// ignored when the store already contains any variables.
Expand Down Expand Up @@ -566,6 +594,7 @@ message VMConfig {
oneof BootConfig {
DirectBoot direct_boot = 5;
UEFI uefi = 6;
IgvmBoot igvm = 15;
}
WindowsOptions windows_options = 7;
// Field 8 was previously map<string, string> extra_data.
Expand All @@ -584,10 +613,16 @@ message VMConfig {

// SMBIOS (DMI) identity overrides. Applied to whichever boot type is
// selected; note that PCAT boot honors only the system UUID and serial
// number.
// number. IGVM boot does not support these overrides.
SMBIOSConfig smbios_config = 13;

optional string crash_dump_path = 14;

// Run without VMBus.
bool disable_vmbus = 16;

// Confidential-computing isolation mode.
IsolationConfig isolation_config = 17;
}

// WindowsOptions contains virtual machine configurations that are only present on a Windows host.
Expand Down
Loading