@@ -18,15 +18,19 @@ use kvm_bindings::{
18
18
KVM_IRQ_ROUTING_IRQCHIP , KVM_IRQ_ROUTING_MSI , KVM_MEM_LOG_DIRTY_PAGES , KVM_MSI_VALID_DEVID ,
19
19
KvmIrqRouting , kvm_irq_routing_entry, kvm_userspace_memory_region,
20
20
} ;
21
- use kvm_ioctls:: VmFd ;
21
+ use kvm_ioctls:: { IoEventAddress , NoDatamatch , VmFd } ;
22
22
use log:: debug;
23
- use pci:: DeviceRelocation ;
23
+ #[ cfg( target_arch = "aarch64" ) ]
24
+ use log:: error;
25
+ use pci:: { DeviceRelocation , PciBarRegionType } ;
24
26
use serde:: { Deserialize , Serialize } ;
27
+ use vm_allocator:: RangeInclusive ;
25
28
use vm_device:: interrupt:: { InterruptSourceGroup , MsiIrqSourceConfig } ;
26
29
use vmm_sys_util:: errno;
27
30
use vmm_sys_util:: eventfd:: EventFd ;
28
31
29
32
pub use crate :: arch:: { ArchVm as Vm , ArchVmError , VmState } ;
33
+ use crate :: devices:: virtio:: transport:: pci:: device:: VirtioPciDevice ;
30
34
use crate :: logger:: info;
31
35
use crate :: persist:: CreateSnapshotError ;
32
36
use crate :: snapshot:: Persist ;
@@ -619,13 +623,90 @@ impl Vm {
619
623
impl DeviceRelocation for Vm {
620
624
fn move_bar (
621
625
& 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 ,
627
631
) -> 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)
629
710
}
630
711
}
631
712
0 commit comments