Skip to content

Commit c241ed1

Browse files
committed
vm: implement DeviceRelocation for Vm
Implement PCI device relocation logic for Vm type. Up until now, we were only implementing it in a dummy way. Signed-off-by: Babis Chalios <[email protected]>
1 parent 9fe7faf commit c241ed1

File tree

1 file changed

+89
-8
lines changed

1 file changed

+89
-8
lines changed

src/vmm/src/vstate/vm.rs

Lines changed: 89 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -18,15 +18,19 @@ use kvm_bindings::{
1818
KVM_IRQ_ROUTING_IRQCHIP, KVM_IRQ_ROUTING_MSI, KVM_MEM_LOG_DIRTY_PAGES, KVM_MSI_VALID_DEVID,
1919
KvmIrqRouting, kvm_irq_routing_entry, kvm_userspace_memory_region,
2020
};
21-
use kvm_ioctls::VmFd;
21+
use kvm_ioctls::{IoEventAddress, NoDatamatch, VmFd};
2222
use log::debug;
23-
use pci::DeviceRelocation;
23+
#[cfg(target_arch = "aarch64")]
24+
use log::error;
25+
use pci::{DeviceRelocation, PciBarRegionType};
2426
use serde::{Deserialize, Serialize};
27+
use vm_allocator::RangeInclusive;
2528
use vm_device::interrupt::{InterruptSourceGroup, MsiIrqSourceConfig};
2629
use vmm_sys_util::errno;
2730
use vmm_sys_util::eventfd::EventFd;
2831

2932
pub use crate::arch::{ArchVm as Vm, ArchVmError, VmState};
33+
use crate::devices::virtio::transport::pci::device::VirtioPciDevice;
3034
use crate::logger::info;
3135
use crate::persist::CreateSnapshotError;
3236
use crate::snapshot::Persist;
@@ -619,13 +623,90 @@ impl Vm {
619623
impl DeviceRelocation for Vm {
620624
fn move_bar(
621625
&self,
622-
_old_base: u64,
623-
_new_base: u64,
624-
_len: u64,
625-
_pci_dev: &mut dyn pci::PciDevice,
626-
_region_type: pci::PciBarRegionType,
626+
old_base: u64,
627+
new_base: u64,
628+
len: u64,
629+
pci_dev: &mut dyn pci::PciDevice,
630+
region_type: pci::PciBarRegionType,
627631
) -> Result<(), std::io::Error> {
628-
todo!()
632+
debug!("pci: moving BAR from {old_base:#x}:{len:#x} to {new_base:#x}:{len:#x}");
633+
match region_type {
634+
PciBarRegionType::IoRegion => {
635+
#[cfg(target_arch = "x86_64")]
636+
// We do not allocate IO addresses, we just hard-code them, no need to handle
637+
// (re)allocations. Just update PIO bus
638+
self.pio_bus
639+
.update_range(old_base, len, new_base, len)
640+
.map_err(std::io::Error::other)?;
641+
642+
#[cfg(target_arch = "aarch64")]
643+
error!("pci: IO relocation is not supported on Aarch64");
644+
}
645+
PciBarRegionType::Memory32BitRegion | PciBarRegionType::Memory64BitRegion => {
646+
let old_range =
647+
RangeInclusive::new(old_base, old_base + len - 1).map_err(|_| {
648+
std::io::Error::other("pci: invalid old range for device relocation")
649+
})?;
650+
let allocator = if region_type == PciBarRegionType::Memory32BitRegion {
651+
&self.common.resource_allocator.mmio32_memory
652+
} else {
653+
&self.common.resource_allocator.mmio64_memory
654+
};
655+
656+
allocator
657+
.lock()
658+
.expect("Poisoned lock")
659+
.free(&old_range)
660+
.map_err(|_| {
661+
std::io::Error::other("pci: failed deallocating old MMIO range")
662+
})?;
663+
664+
allocator
665+
.lock()
666+
.unwrap()
667+
.allocate(len, len, vm_allocator::AllocPolicy::ExactMatch(new_base))
668+
.map_err(|_| std::io::Error::other("pci: failed allocating new MMIO range"))?;
669+
670+
// Update MMIO bus
671+
self.common
672+
.mmio_bus
673+
.update_range(old_base, len, new_base, len)
674+
.map_err(std::io::Error::other)?;
675+
}
676+
}
677+
678+
let any_dev = pci_dev.as_any_mut();
679+
if let Some(virtio_pci_dev) = any_dev.downcast_ref::<VirtioPciDevice>() {
680+
let bar_addr = virtio_pci_dev.config_bar_addr();
681+
if bar_addr == new_base {
682+
for (i, queue_evt) in virtio_pci_dev
683+
.virtio_device()
684+
.lock()
685+
.expect("Poisoned lock")
686+
.queue_events()
687+
.iter()
688+
.enumerate()
689+
{
690+
const NOTIFICATION_BAR_OFFSET: u64 = 0x6000;
691+
const NOTIFY_OFF_MULTIPLIER: u64 = 4;
692+
let notify_base = old_base + NOTIFICATION_BAR_OFFSET;
693+
let io_addr =
694+
IoEventAddress::Mmio(notify_base + i as u64 * NOTIFY_OFF_MULTIPLIER);
695+
self.common
696+
.fd
697+
.unregister_ioevent(queue_evt, &io_addr, NoDatamatch)?;
698+
699+
let notify_base = new_base + NOTIFICATION_BAR_OFFSET;
700+
let io_addr =
701+
IoEventAddress::Mmio(notify_base + i as u64 * NOTIFY_OFF_MULTIPLIER);
702+
self.common
703+
.fd
704+
.register_ioevent(queue_evt, &io_addr, NoDatamatch)?;
705+
}
706+
}
707+
}
708+
709+
pci_dev.move_bar(old_base, new_base)
629710
}
630711
}
631712

0 commit comments

Comments
 (0)