diff --git a/src/runtime-rs/crates/hypervisor/ch-config/src/convert.rs b/src/runtime-rs/crates/hypervisor/ch-config/src/convert.rs index f1dc8574c0..f0f5e88e81 100644 --- a/src/runtime-rs/crates/hypervisor/ch-config/src/convert.rs +++ b/src/runtime-rs/crates/hypervisor/ch-config/src/convert.rs @@ -7,7 +7,7 @@ use crate::NamedHypervisorConfig; use crate::VmConfig; use crate::{ ConsoleConfig, ConsoleOutputMode, CpuFeatures, CpuTopology, CpusConfig, MacAddr, MemoryConfig, - PayloadConfig, RngConfig, VsockConfig, + PayloadConfig, PmemConfig, RngConfig, VsockConfig, }; use anyhow::{anyhow, Context, Result}; use kata_types::config::default::DEFAULT_CH_ENTROPY_SOURCE; @@ -20,6 +20,8 @@ use std::path::PathBuf; // 1 MiB const MIB: u64 = 1024 * 1024; +const PMEM_ALIGN_BYTES: u64 = 2 * MIB; + const DEFAULT_CH_MAX_PHYS_BITS: u8 = 46; impl TryFrom for VmConfig { @@ -31,14 +33,42 @@ impl TryFrom for VmConfig { let vsock_socket_path = n.vsock_socket_path; let sandbox_path = n.sandbox_path; let fs = n.shared_fs_devices; - let pmem = n.pmem_devices; let cpus = CpusConfig::try_from(cfg.cpu_info)?; let rng = RngConfig::try_from(cfg.machine_info)?; - // Note that PmemConfig replaces the PayloadConfig.initrd. - let payload = PayloadConfig::try_from((cfg.boot_info, kernel_params))?; + // Note how CH handles the different image types: + // + // - An image is specified in PmemConfig. + // - An initrd/initramfs is specified in PayloadConfig. + let boot_info = cfg.boot_info; + + let use_initrd = !boot_info.initrd.is_empty(); + let use_image = !boot_info.image.is_empty(); + + if use_initrd && use_image { + return Err(anyhow!("cannot specify image and initrd")); + } + + if !use_initrd && !use_image { + return Err(anyhow!("missing boot file (no image or initrd)")); + } + + let initrd = if use_initrd { + Some(PathBuf::from(boot_info.initrd.clone())) + } else { + None + }; + + let pmem = if use_initrd { + None + } else { + let pmem = PmemConfig::try_from(&boot_info)?; + Some(vec![pmem]) + }; + + let payload = PayloadConfig::try_from((boot_info, kernel_params, initrd))?; let serial = get_serial_cfg()?; let console = get_console_cfg()?; @@ -90,13 +120,18 @@ impl TryFrom for MemoryConfig { .ok_or("failed to calculate max hotplug size for CH") .map_err(|e| anyhow!(e))?; + let aligned_hotplug_size_bytes = + checked_next_multiple_of(hotplug_size_bytes, PMEM_ALIGN_BYTES) + .ok_or("cannot handle pmem alignment for CH") + .map_err(|e| anyhow!(e))?; + let cfg = MemoryConfig { size: mem_bytes, // Required shared: true, - hotplug_size: Some(hotplug_size_bytes), + hotplug_size: Some(aligned_hotplug_size_bytes), ..Default::default() }; @@ -105,6 +140,20 @@ impl TryFrom for MemoryConfig { } } +// Return the next multiple of 'multiple' starting from the specified value +// (aka align value to multiple). +// +// This is a temporary solution until checked_next_multiple_of() integer +// method is available in the rust language. +// +// See: https://github.com/rust-lang/rust/issues/88581 +fn checked_next_multiple_of(value: u64, multiple: u64) -> Option { + match value.checked_rem(multiple) { + None => Some(value), + Some(r) => value.checked_add(multiple - r), + } +} + impl TryFrom for CpusConfig { type Error = anyhow::Error; @@ -153,20 +202,23 @@ impl TryFrom for CpuFeatures { } // The 2nd tuple element is the space separated kernel parameters list. +// The 3rd tuple element is an optional initramfs image to use. // This cannot be created only from BootInfo since that contains the // user-specified kernel parameters only. -impl TryFrom<(BootInfo, String)> for PayloadConfig { +impl TryFrom<(BootInfo, String, Option)> for PayloadConfig { type Error = anyhow::Error; - fn try_from(args: (BootInfo, String)) -> Result { + fn try_from(args: (BootInfo, String, Option)) -> Result { let b = args.0; let cmdline = args.1; + let initramfs = args.2; let kernel = PathBuf::from(b.kernel); let payload = PayloadConfig { kernel: Some(kernel), cmdline: Some(cmdline), + initramfs, ..Default::default() }; @@ -195,6 +247,27 @@ impl TryFrom for RngConfig { } } +impl TryFrom<&BootInfo> for PmemConfig { + type Error = anyhow::Error; + + fn try_from(b: &BootInfo) -> Result { + let file = if b.image.is_empty() { + return Err(anyhow!("CH PmemConfig only used for images")); + } else { + b.image.clone() + }; + + let cfg = PmemConfig { + file: PathBuf::from(file), + discard_writes: true, + + ..Default::default() + }; + + Ok(cfg) + } +} + fn get_serial_cfg() -> Result { let cfg = ConsoleConfig { file: None, diff --git a/src/runtime-rs/crates/hypervisor/ch-config/src/lib.rs b/src/runtime-rs/crates/hypervisor/ch-config/src/lib.rs index 157ab89706..2969e68471 100644 --- a/src/runtime-rs/crates/hypervisor/ch-config/src/lib.rs +++ b/src/runtime-rs/crates/hypervisor/ch-config/src/lib.rs @@ -492,5 +492,4 @@ pub struct NamedHypervisorConfig { pub cfg: HypervisorConfig, pub shared_fs_devices: Option>, - pub pmem_devices: Option>, } diff --git a/src/runtime-rs/crates/hypervisor/src/ch/inner_device.rs b/src/runtime-rs/crates/hypervisor/src/ch/inner_device.rs index 03cf95daf8..f4475f66e4 100644 --- a/src/runtime-rs/crates/hypervisor/src/ch/inner_device.rs +++ b/src/runtime-rs/crates/hypervisor/src/ch/inner_device.rs @@ -10,7 +10,7 @@ use crate::HybridVsockConfig; use crate::VmmState; use anyhow::{anyhow, Context, Result}; use ch_config::ch_api::cloud_hypervisor_vm_fs_add; -use ch_config::{FsConfig, PmemConfig}; +use ch_config::FsConfig; use safe_path::scoped_join; use std::convert::TryFrom; use std::path::PathBuf; @@ -148,41 +148,6 @@ impl CloudHypervisorInner { Ok(None) } } - - pub(crate) async fn get_boot_file(&mut self) -> Result { - if let Some(ref config) = self.config { - let boot_info = &config.boot_info; - - let file = if !boot_info.initrd.is_empty() { - boot_info.initrd.clone() - } else if !boot_info.image.is_empty() { - boot_info.image.clone() - } else { - return Err(anyhow!("missing boot file (no image or initrd)")); - }; - - Ok(PathBuf::from(file)) - } else { - Err(anyhow!("no hypervisor config")) - } - } - - pub(crate) async fn get_pmem_devices(&mut self) -> Result>> { - let file = self.get_boot_file().await?; - - let pmem_cfg = PmemConfig { - file, - size: None, - iommu: false, - discard_writes: true, - id: None, - pci_segment: 0, - }; - - let pmem_devices = vec![pmem_cfg]; - - Ok(Some(pmem_devices)) - } } #[derive(Debug)] diff --git a/src/runtime-rs/crates/hypervisor/src/ch/inner_hypervisor.rs b/src/runtime-rs/crates/hypervisor/src/ch/inner_hypervisor.rs index 2ecc328bad..8eea6f4666 100644 --- a/src/runtime-rs/crates/hypervisor/src/ch/inner_hypervisor.rs +++ b/src/runtime-rs/crates/hypervisor/src/ch/inner_hypervisor.rs @@ -96,8 +96,6 @@ impl CloudHypervisorInner { async fn boot_vm(&mut self) -> Result<()> { let shared_fs_devices = self.get_shared_fs_devices().await?; - let pmem_devices = self.get_pmem_devices().await?; - let socket = self .api_socket .as_ref() @@ -129,7 +127,6 @@ impl CloudHypervisorInner { vsock_socket_path, cfg: hypervisor_config.clone(), shared_fs_devices, - pmem_devices, }; let cfg = VmConfig::try_from(named_cfg)?;