@@ -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 } ;
2222use log:: debug;
23- use pci:: DeviceRelocation ;
23+ #[ cfg( target_arch = "aarch64" ) ]
24+ use log:: error;
25+ use pci:: { DeviceRelocation , PciBarRegionType } ;
2426use serde:: { Deserialize , Serialize } ;
27+ use vm_allocator:: RangeInclusive ;
2528use vm_device:: interrupt:: { InterruptSourceGroup , MsiIrqSourceConfig } ;
2629use vmm_sys_util:: errno;
2730use vmm_sys_util:: eventfd:: EventFd ;
2831
2932pub use crate :: arch:: { ArchVm as Vm , ArchVmError , VmState } ;
33+ use crate :: devices:: virtio:: transport:: pci:: device:: VirtioPciDevice ;
3034use crate :: logger:: info;
3135use crate :: persist:: CreateSnapshotError ;
3236use crate :: snapshot:: Persist ;
@@ -619,13 +623,90 @@ impl Vm {
619623impl 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