Skip to content
Merged
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
2 changes: 2 additions & 0 deletions openhcl/underhill_core/src/worker.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2861,6 +2861,7 @@ async fn new_underhill_vm(
.context("failed to create direct mmio accessor")?,
)
},
vtom,
);

// Allow NVMe devices.
Expand Down Expand Up @@ -2990,6 +2991,7 @@ async fn new_underhill_vm(
let device = Arc::new(device);
Ok((device.clone(), VpciInterruptMapper::new(device)))
},
vtom,
)
.await?;
}
Expand Down
3 changes: 3 additions & 0 deletions openvmm/hvlite_core/src/worker/dispatch.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1833,6 +1833,7 @@ impl InitializedVm {
&mut mmio,
vmbus.control().as_ref(),
interrupt_mapper,
None,
)
.await?;

Expand Down Expand Up @@ -1947,6 +1948,7 @@ impl InitializedVm {
hv_device.clone().interrupt_mapper(),
))
},
None,
)
.await?;
}
Expand Down Expand Up @@ -1988,6 +1990,7 @@ impl InitializedVm {
&mut services.register_mmio(),
vmbus,
crate::partition::VpciDevice::interrupt_mapper(hv_device),
None,
)
.await
})
Expand Down
23 changes: 23 additions & 0 deletions vm/devices/pci/vpci/src/bus.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ use crate::device::NotPciDevice;
use crate::device::VpciChannel;
use crate::device::VpciConfigSpace;
use crate::device::VpciConfigSpaceOffset;
use crate::device::VpciConfigSpaceVtom;
use chipset_device::ChipsetDevice;
use chipset_device::io::IoError;
use chipset_device::io::IoResult;
Expand Down Expand Up @@ -57,6 +58,9 @@ pub struct VpciBusDevice {
config_space_offset: VpciConfigSpaceOffset,
#[inspect(with = "|&x| u32::from(x)")]
current_slot: SlotNumber,
/// Track vtom as when isolated with vtom enabled, guests may access mmio
/// with or without vtom set.
vtom: Option<u64>,
}

/// An error creating a VPCI bus.
Expand All @@ -78,9 +82,15 @@ impl VpciBusDevice {
device: Arc<CloseableMutex<dyn ChipsetDevice>>,
register_mmio: &mut dyn RegisterMmioIntercept,
msi_controller: VpciInterruptMapper,
vtom: Option<u64>,
) -> Result<(Self, VpciChannel), NotPciDevice> {
let config_space = VpciConfigSpace::new(
register_mmio.new_io_region(&format!("vpci-{instance_id}-config"), 2 * HV_PAGE_SIZE),
vtom.map(|vtom| VpciConfigSpaceVtom {
vtom,
control_mmio: register_mmio
.new_io_region(&format!("vpci-{instance_id}-config-vtom"), 2 * HV_PAGE_SIZE),
}),
);
let config_space_offset = config_space.offset().clone();
let channel = VpciChannel::new(&device, instance_id, config_space, msi_controller)?;
Expand All @@ -89,6 +99,7 @@ impl VpciBusDevice {
device,
config_space_offset,
current_slot: SlotNumber::from(0),
vtom,
};

Ok((this, channel))
Expand All @@ -104,12 +115,14 @@ impl VpciBus {
register_mmio: &mut dyn RegisterMmioIntercept,
vmbus: &dyn vmbus_channel::bus::ParentBus,
msi_controller: VpciInterruptMapper,
vtom: Option<u64>,
) -> Result<Self, CreateBusError> {
let (bus, channel) = VpciBusDevice::new(
instance_id,
device.clone(),
register_mmio,
msi_controller.clone(),
vtom,
)
.map_err(CreateBusError::NotPci)?;
let channel = offer_simple_device(driver_source, vmbus, channel)
Expand Down Expand Up @@ -164,6 +177,11 @@ impl ChipsetDevice for VpciBusDevice {

impl MmioIntercept for VpciBusDevice {
fn mmio_read(&mut self, addr: u64, data: &mut [u8]) -> IoResult {
tracing::trace!(addr, "VPCI bus MMIO read");

// Remove vtom, as the guest may access it with or without set.
let addr = addr & !self.vtom.unwrap_or(0);

let reg = match self.register(addr, data.len()) {
Ok(reg) => reg,
Err(err) => return IoResult::Err(err),
Expand Down Expand Up @@ -192,6 +210,11 @@ impl MmioIntercept for VpciBusDevice {
}

fn mmio_write(&mut self, addr: u64, data: &[u8]) -> IoResult {
tracing::trace!(addr, "VPCI bus MMIO write");

// Remove vtom, as the guest may access it with or without set.
let addr = addr & !self.vtom.unwrap_or(0);

let reg = match self.register(addr, data.len()) {
Ok(reg) => reg,
Err(err) => return IoResult::Err(err),
Expand Down
34 changes: 30 additions & 4 deletions vm/devices/pci/vpci/src/device.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1048,14 +1048,27 @@ pub struct VpciChannel {
pub struct VpciConfigSpace {
offset: VpciConfigSpaceOffset,
control_mmio: Box<dyn ControlMmioIntercept>,
vtom: Option<VpciConfigSpaceVtom>,
}

/// The vtom info used by config space.
pub struct VpciConfigSpaceVtom {
/// The vtom bit.
pub vtom: u64,
/// The mmio control region to be registered with vtom.
pub control_mmio: Box<dyn ControlMmioIntercept>,
}

impl VpciConfigSpace {
/// Create New PCI Config space
pub fn new(control_mmio: Box<dyn ControlMmioIntercept>) -> Self {
/// Create New PCI Config space.
pub fn new(
control_mmio: Box<dyn ControlMmioIntercept>,
vtom: Option<VpciConfigSpaceVtom>,
) -> Self {
Self {
offset: VpciConfigSpaceOffset::new(),
control_mmio,
vtom,
}
}

Expand All @@ -1065,13 +1078,22 @@ impl VpciConfigSpace {
}

fn map(&mut self, addr: u64) {
tracing::debug!(addr, "mapping config space");
tracing::trace!(addr, "mapping config space");

// Remove the vtom bit if set
let vtom_bit = self.vtom.as_ref().map(|v| v.vtom).unwrap_or(0);
let addr = addr & !vtom_bit;

self.offset.0.store(addr, Ordering::Relaxed);
self.control_mmio.map(addr);

if let Some(vtom) = self.vtom.as_mut() {
vtom.control_mmio.map(addr | vtom_bit);
}
}

fn unmap(&mut self) {
tracing::debug!(
tracing::trace!(
addr = self.offset.0.load(Ordering::Relaxed),
"unmapping config space"
);
Expand All @@ -1081,6 +1103,9 @@ impl VpciConfigSpace {
//
// This is idempotent. See [`impl_device_range!`].
self.control_mmio.unmap();
if let Some(vtom) = self.vtom.as_mut() {
vtom.control_mmio.unmap();
}
self.offset
.0
.store(VpciConfigSpaceOffset::INVALID, Ordering::Relaxed);
Expand Down Expand Up @@ -1287,6 +1312,7 @@ mod tests {
}
let config_space = VpciConfigSpace::new(
ExternallyManagedMmioIntercepts.new_io_region("test", 2 * HV_PAGE_SIZE),
None,
);
let mut state = VpciChannel {
msi_mapper: VpciInterruptMapper::new(msi_mapper),
Expand Down
1 change: 1 addition & 0 deletions vm/devices/pci/vpci_client/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ async fn test_negotiate_version(driver: DefaultDriver) {
device,
&mut ExternallyManagedMmioIntercepts,
VpciInterruptMapper::new(msi_controller),
None,
)
.unwrap();

Expand Down
5 changes: 5 additions & 0 deletions vm/devices/pci/vpci_relay/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,8 @@ pub struct VpciRelay {
mmio_access: Box<dyn CreateMemoryAccess>,
#[inspect(iter_by_index)]
allowed_devices: Vec<AllowedDevice>,
#[inspect(hex)]
vtom: Option<u64>,
}

#[derive(Inspect)]
Expand Down Expand Up @@ -157,6 +159,7 @@ impl VpciRelay {
dma_client: Arc<dyn DmaClient>,
mmio_range: MemoryRange,
mmio_access: Box<dyn CreateMemoryAccess>,
vtom: Option<u64>,
) -> Self {
Self {
driver_source,
Expand All @@ -168,6 +171,7 @@ impl VpciRelay {
mmio_range,
mmio_access,
allowed_devices: Vec::new(),
vtom,
}
}

Expand Down Expand Up @@ -304,6 +308,7 @@ impl VpciRelay {
mmio,
self.vmbus.as_ref(),
interrupt_mapper,
self.vtom,
)
.await?;

Expand Down
2 changes: 2 additions & 0 deletions vmm_core/src/device_builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ pub async fn build_vpci_device(
Arc<dyn MsiInterruptTarget>,
VpciInterruptMapper,
)>,
vtom: Option<u64>,
) -> anyhow::Result<()> {
let device_name = format!("{}:vpci-{instance_id}", resource.id());

Expand Down Expand Up @@ -82,6 +83,7 @@ pub async fn build_vpci_device(
&mut services.register_mmio(),
vmbus,
interrupt_mapper,
vtom,
)
.await?;

Expand Down