vmm: introduce platform option to limit maximum IOMMU address width

Signed-off-by: Nikolay Edigaryev <edigaryev@gmail.com>
This commit is contained in:
Nikolay Edigaryev 2025-01-08 12:14:19 +04:00 committed by Rob Bradford
parent fa686fdfc7
commit 74ca38f7a9
4 changed files with 42 additions and 1 deletions

View File

@ -204,7 +204,7 @@ fn create_app(default_vcpus: String, default_memory: String, default_rng: String
.arg(
Arg::new("platform")
.long("platform")
.help("num_pci_segments=<num_pci_segments>,iommu_segments=<list_of_segments>,serial_number=<dmi_device_serial_number>,uuid=<dmi_device_uuid>,oem_strings=<list_of_strings>")
.help("num_pci_segments=<num_pci_segments>,iommu_segments=<list_of_segments>,iommu_address_width=<bits>,serial_number=<dmi_device_serial_number>,uuid=<dmi_device_uuid>,oem_strings=<list_of_strings>")
.num_args(1)
.group("vm-config"),
)

View File

@ -718,6 +718,9 @@ components:
items:
type: integer
format: int16
iommu_address_width:
type: integer
format: uint8
serial_number:
type: string
uuid:

View File

@ -21,6 +21,7 @@ use crate::landlock::LandlockAccess;
use crate::vm_config::*;
const MAX_NUM_PCI_SEGMENTS: u16 = 96;
const MAX_IOMMU_ADDRESS_WIDTH_BITS: u8 = 64;
/// Errors associated with VM configuration parameters.
#[derive(Debug, Error)]
@ -183,6 +184,8 @@ pub enum ValidationError {
InvalidPciSegment(u16),
/// Invalid PCI segment aperture weight
InvalidPciSegmentApertureWeight(u32),
/// Invalid IOMMU address width in bits
InvalidIommuAddressWidthBits(u8),
/// Balloon too big
BalloonLargerThanRam(u64, u64),
/// On a IOMMU segment but not behind IOMMU
@ -309,6 +312,9 @@ impl fmt::Display for ValidationError {
InvalidPciSegmentApertureWeight(aperture_weight) => {
write!(f, "Invalid PCI segment aperture weight: {aperture_weight}")
}
InvalidIommuAddressWidthBits(iommu_address_width_bits) => {
write!(f, "IOMMU address width in bits ({iommu_address_width_bits}) should be less than or equal to {MAX_IOMMU_ADDRESS_WIDTH_BITS}")
}
BalloonLargerThanRam(balloon_size, ram_size) => {
write!(
f,
@ -817,6 +823,7 @@ impl PlatformConfig {
parser
.add("num_pci_segments")
.add("iommu_segments")
.add("iommu_address_width")
.add("serial_number")
.add("uuid")
.add("oem_strings");
@ -834,6 +841,10 @@ impl PlatformConfig {
.convert::<IntegerList>("iommu_segments")
.map_err(Error::ParsePlatform)?
.map(|v| v.0.iter().map(|e| *e as u16).collect());
let iommu_address_width_bits: u8 = parser
.convert("iommu_address_width")
.map_err(Error::ParsePlatform)?
.unwrap_or(MAX_IOMMU_ADDRESS_WIDTH_BITS);
let serial_number = parser
.convert("serial_number")
.map_err(Error::ParsePlatform)?;
@ -857,6 +868,7 @@ impl PlatformConfig {
Ok(PlatformConfig {
num_pci_segments,
iommu_segments,
iommu_address_width_bits,
serial_number,
uuid,
oem_strings,
@ -882,6 +894,12 @@ impl PlatformConfig {
}
}
if self.iommu_address_width_bits > MAX_IOMMU_ADDRESS_WIDTH_BITS {
return Err(ValidationError::InvalidIommuAddressWidthBits(
self.iommu_address_width_bits,
));
}
Ok(())
}
}
@ -3998,6 +4016,7 @@ mod tests {
PlatformConfig {
num_pci_segments: MAX_NUM_PCI_SEGMENTS,
iommu_segments: None,
iommu_address_width_bits: MAX_IOMMU_ADDRESS_WIDTH_BITS,
serial_number: None,
uuid: None,
oem_strings: None,
@ -4296,6 +4315,18 @@ mod tests {
Err(ValidationError::InvalidPciSegment(MAX_NUM_PCI_SEGMENTS + 1))
);
let mut invalid_config = valid_config.clone();
invalid_config.platform = Some(PlatformConfig {
iommu_address_width_bits: MAX_IOMMU_ADDRESS_WIDTH_BITS + 1,
..platform_fixture()
});
assert_eq!(
invalid_config.validate(),
Err(ValidationError::InvalidIommuAddressWidthBits(
MAX_IOMMU_ADDRESS_WIDTH_BITS + 1
))
);
let mut still_valid_config = valid_config.clone();
still_valid_config.platform = Some(PlatformConfig {
iommu_segments: Some(vec![1, 2, 3]),

View File

@ -88,12 +88,19 @@ pub fn default_platformconfig_num_pci_segments() -> u16 {
DEFAULT_NUM_PCI_SEGMENTS
}
pub const DEFAULT_IOMMU_ADDRESS_WIDTH_BITS: u8 = 64;
pub fn default_platformconfig_iommu_address_width_bits() -> u8 {
DEFAULT_IOMMU_ADDRESS_WIDTH_BITS
}
#[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)]
pub struct PlatformConfig {
#[serde(default = "default_platformconfig_num_pci_segments")]
pub num_pci_segments: u16,
#[serde(default)]
pub iommu_segments: Option<Vec<u16>>,
#[serde(default = "default_platformconfig_iommu_address_width_bits")]
pub iommu_address_width_bits: u8,
#[serde(default)]
pub serial_number: Option<String>,
#[serde(default)]