@@ -26,6 +26,7 @@ use vm_allocator::{AddressAllocator, AllocPolicy, RangeInclusive};
2626use vm_memory:: { Address , ByteValued , GuestAddress , Le32 } ;
2727use vmm_sys_util:: errno;
2828use vmm_sys_util:: eventfd:: EventFd ;
29+ use zerocopy:: IntoBytes ;
2930
3031use crate :: Vm ;
3132use crate :: devices:: virtio:: device:: { VirtioDevice , VirtioDeviceType } ;
@@ -36,7 +37,9 @@ use crate::devices::virtio::transport::pci::common_config::{
3637} ;
3738use crate :: devices:: virtio:: transport:: { VirtioInterrupt , VirtioInterruptType } ;
3839use crate :: logger:: { debug, error} ;
39- use crate :: pci:: configuration:: { PciCapability , PciConfiguration , PciConfigurationState } ;
40+ use crate :: pci:: configuration:: {
41+ BAR0_REG , Bars , NUM_BAR_REGS , PciCapability , PciConfiguration , PciConfigurationState ,
42+ } ;
4043use crate :: pci:: msix:: { MsixCap , MsixConfig , MsixConfigState } ;
4144use crate :: pci:: { BarReprogrammingParams , DeviceRelocationError , PciDevice } ;
4245use crate :: snapshot:: Persist ;
@@ -242,7 +245,7 @@ pub struct VirtioPciDeviceState {
242245 pub pci_configuration_state : PciConfigurationState ,
243246 pub pci_dev_state : VirtioPciCommonConfigState ,
244247 pub msix_state : MsixConfigState ,
245- pub bar_address : u64 ,
248+ pub bars : Bars ,
246249}
247250
248251#[ derive( Debug , thiserror:: Error , displaydoc:: Display ) ]
@@ -286,8 +289,8 @@ pub struct VirtioPciDevice {
286289 // a device.
287290 cap_pci_cfg_info : VirtioPciCfgCapInfo ,
288291
289- // Allocated address for the BAR
290- pub bar_address : u64 ,
292+ // BARs region for the device
293+ pub bars : Bars ,
291294}
292295
293296impl Debug for VirtioPciDevice {
@@ -350,16 +353,14 @@ impl VirtioPciDevice {
350353 )
351354 . unwrap ( )
352355 . start ( ) ;
353-
354- self . configuration . add_pci_bar (
355- VIRTIO_BAR_INDEX as usize ,
356+ // Virtio BAR is 64bit BAR without prefetchable bit since it is an MMIO region.
357+ self . bars . set_bar_64 (
358+ VIRTIO_BAR_INDEX ,
356359 virtio_pci_bar_addr,
357360 CAPABILITY_BAR_SIZE ,
361+ false ,
358362 ) ;
359-
360- // Once the BARs are allocated, the capabilities can be added to the PCI configuration.
361363 self . add_pci_capabilities ( ) ;
362- self . bar_address = virtio_pci_bar_addr;
363364 }
364365
365366 /// Constructs a new PCI transport for the given virtio device.
@@ -408,7 +409,7 @@ impl VirtioPciDevice {
408409 virtio_interrupt : Some ( interrupt) ,
409410 memory,
410411 cap_pci_cfg_info : VirtioPciCfgCapInfo :: default ( ) ,
411- bar_address : 0 ,
412+ bars : Bars :: default ( ) ,
412413 } ;
413414
414415 Ok ( virtio_pci_device)
@@ -453,7 +454,7 @@ impl VirtioPciDevice {
453454 virtio_interrupt : Some ( interrupt) ,
454455 memory : vm. guest_memory ( ) . clone ( ) ,
455456 cap_pci_cfg_info,
456- bar_address : state. bar_address ,
457+ bars : state. bars ,
457458 } ;
458459
459460 if state. device_activated {
@@ -483,7 +484,7 @@ impl VirtioPciDevice {
483484 }
484485
485486 pub fn config_bar_addr ( & self ) -> u64 {
486- self . configuration . get_bar_addr ( VIRTIO_BAR_INDEX as usize )
487+ self . bars . get_bar_addr_64 ( VIRTIO_BAR_INDEX )
487488 }
488489
489490 fn add_pci_capabilities ( & mut self ) {
@@ -638,7 +639,7 @@ impl VirtioPciDevice {
638639 . lock ( )
639640 . expect ( "Poisoned lock" )
640641 . state ( ) ,
641- bar_address : self . bar_address ,
642+ bars : self . bars ,
642643 }
643644 }
644645}
@@ -742,42 +743,63 @@ impl PciDevice for VirtioPciDevice {
742743 offset : u64 ,
743744 data : & [ u8 ] ,
744745 ) -> Option < Arc < Barrier > > {
745- // Handle the special case where the capability VIRTIO_PCI_CAP_PCI_CFG
746- // is accessed. This capability has a special meaning as it allows the
747- // guest to access other capabilities without mapping the PCI BAR.
748- let base = reg_idx * 4 ;
749- if base + u64_to_usize ( offset) >= self . cap_pci_cfg_info . offset
750- && base + u64_to_usize ( offset) + data. len ( )
751- <= self . cap_pci_cfg_info . offset + self . cap_pci_cfg_info . cap . bytes ( ) . len ( )
752- {
753- let offset = base + u64_to_usize ( offset) - self . cap_pci_cfg_info . offset ;
754- self . write_cap_pci_cfg ( offset, data)
755- } else {
756- self . configuration
757- . write_config_register ( reg_idx, offset, data) ;
746+ if BAR0_REG as usize <= reg_idx && reg_idx < ( BAR0_REG + NUM_BAR_REGS ) as usize {
747+ // reg_idx is in [BAR0_REG, BAR0_REG+NUM_BAR_REGS), so the difference is 0..5.
748+ #[ allow( clippy:: cast_possible_truncation) ]
749+ let bar_idx = ( reg_idx - BAR0_REG as usize ) as u8 ;
750+ // offset is within a 4-byte PCI config register (0..3).
751+ #[ allow( clippy:: cast_possible_truncation) ]
752+ let offset = offset as u8 ;
753+ self . bars . write ( bar_idx, offset, data) ;
758754 None
755+ } else {
756+ // Handle the special case where the capability VIRTIO_PCI_CAP_PCI_CFG
757+ // is accessed. This capability has a special meaning as it allows the
758+ // guest to access other capabilities without mapping the PCI BAR.
759+ let base = reg_idx * 4 ;
760+ if base + u64_to_usize ( offset) >= self . cap_pci_cfg_info . offset
761+ && base + u64_to_usize ( offset) + data. len ( )
762+ <= self . cap_pci_cfg_info . offset + self . cap_pci_cfg_info . cap . bytes ( ) . len ( )
763+ {
764+ let offset = base + u64_to_usize ( offset) - self . cap_pci_cfg_info . offset ;
765+ self . write_cap_pci_cfg ( offset, data)
766+ } else {
767+ self . configuration
768+ . write_config_register ( reg_idx, offset, data) ;
769+ None
770+ }
759771 }
760772 }
761773
762774 fn read_config_register ( & mut self , reg_idx : usize ) -> u32 {
763- // Handle the special case where the capability VIRTIO_PCI_CAP_PCI_CFG
764- // is accessed. This capability has a special meaning as it allows the
765- // guest to access other capabilities without mapping the PCI BAR.
766- let base = reg_idx * 4 ;
767- if base >= self . cap_pci_cfg_info . offset
768- && base + 4 <= self . cap_pci_cfg_info . offset + self . cap_pci_cfg_info . cap . bytes ( ) . len ( )
769- {
770- let offset = base - self . cap_pci_cfg_info . offset ;
771- let mut data = [ 0u8 ; 4 ] ;
772- let len = u32:: from ( self . cap_pci_cfg_info . cap . cap . length ) as usize ;
773- if len <= 4 {
774- self . read_cap_pci_cfg ( offset, & mut data[ ..len] ) ;
775- u32:: from_le_bytes ( data)
775+ if BAR0_REG as usize <= reg_idx && reg_idx < ( BAR0_REG + NUM_BAR_REGS ) as usize {
776+ // reg_idx is in [BAR0_REG, BAR0_REG+NUM_BAR_REGS), so the difference is 0..5.
777+ #[ allow( clippy:: cast_possible_truncation) ]
778+ let bar_idx = ( reg_idx - BAR0_REG as usize ) as u8 ;
779+ let mut value: u32 = 0 ;
780+ self . bars . read ( bar_idx, 0 , value. as_mut_bytes ( ) ) ;
781+ value
782+ } else {
783+ // Handle the special case where the capability VIRTIO_PCI_CAP_PCI_CFG
784+ // is accessed. This capability has a special meaning as it allows the
785+ // guest to access other capabilities without mapping the PCI BAR.
786+ let base = reg_idx * 4 ;
787+ if base >= self . cap_pci_cfg_info . offset
788+ && base + 4
789+ <= self . cap_pci_cfg_info . offset + self . cap_pci_cfg_info . cap . bytes ( ) . len ( )
790+ {
791+ let offset = base - self . cap_pci_cfg_info . offset ;
792+ let mut data = [ 0u8 ; 4 ] ;
793+ let len = u32:: from ( self . cap_pci_cfg_info . cap . cap . length ) as usize ;
794+ if len <= 4 {
795+ self . read_cap_pci_cfg ( offset, & mut data[ ..len] ) ;
796+ u32:: from_le_bytes ( data)
797+ } else {
798+ 0
799+ }
776800 } else {
777- 0
801+ self . configuration . read_reg ( reg_idx )
778802 }
779- } else {
780- self . configuration . read_reg ( reg_idx)
781803 }
782804 }
783805
@@ -786,7 +808,7 @@ impl PciDevice for VirtioPciDevice {
786808 reg_idx : usize ,
787809 data : & [ u8 ] ,
788810 ) -> Option < BarReprogrammingParams > {
789- self . configuration . detect_bar_reprogramming ( reg_idx , data )
811+ None
790812 }
791813
792814 fn read_bar ( & mut self , _base : u64 , offset : u64 , data : & mut [ u8 ] ) {
0 commit comments