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(
Arg::new("platform") Arg::new("platform")
.long("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) .num_args(1)
.group("vm-config"), .group("vm-config"),
) )

View File

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

View File

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