@@ -189,6 +189,17 @@ struct VirtioPciCfgCapInfo {
189189 cap : VirtioPciCfgCap ,
190190}
191191
192+ impl VirtioPciCfgCapInfo {
193+ fn in_range ( & self , reg_idx : u16 , offset : u8 , data_len : usize ) -> bool {
194+ let base = reg_idx * 4 ;
195+ let cap_start = self . offset ;
196+ let cap_end = self . offset as usize + self . cap . bytes ( ) . len ( ) ;
197+ let start = base + u16:: from ( offset) ;
198+ let end = ( base + u16:: from ( offset) ) as usize + data_len;
199+ cap_start <= start && end <= cap_end
200+ }
201+ }
202+
192203#[ derive( Debug , Copy , Clone ) ]
193204#[ repr( u8 ) ]
194205pub enum PciVirtioSubclass {
@@ -736,67 +747,62 @@ impl PciDevice for VirtioPciDevice {
736747 offset : u8 ,
737748 data : & [ u8 ] ,
738749 ) -> Option < Arc < Barrier > > {
739- if BAR0_REG_IDX <= reg_idx && reg_idx < BAR0_REG_IDX + u16:: from ( NUM_BAR_REGS ) {
750+ let in_bars = BAR0_REG_IDX <= reg_idx && reg_idx < BAR0_REG_IDX + u16:: from ( NUM_BAR_REGS ) ;
751+ let in_msix_cap_header = reg_idx * 4 == self . msix_config_cap_offset ;
752+ let in_pci_cfg = self . cap_pci_cfg_info . in_range ( reg_idx, offset, data. len ( ) ) ;
753+ if in_bars {
740754 // reg_idx is in [BAR0_REG_IDX, BAR0_REG_IDX+NUM_BAR_REGS), so the difference is 0..5.
741755 #[ allow( clippy:: cast_possible_truncation) ]
742756 let bar_idx = ( reg_idx - BAR0_REG_IDX ) as u8 ;
743757 self . bars . write ( bar_idx, offset, data) ;
744758 None
759+ } else if in_msix_cap_header {
760+ // For writes to MsixCap structure, we need to capture write to the second 2 bytes
761+ // of the capability header where the Function Mask and MSI-X Enable bits are present.
762+ // Everything else can be served from `self.configuration`.
763+ self . msix_config
764+ . lock ( )
765+ . unwrap ( )
766+ . write_msg_ctl_register ( offset, data) ;
767+ self . configuration
768+ . write_config_register ( reg_idx, offset, data) ;
769+ None
770+ } else if in_pci_cfg {
771+ let offset = ( reg_idx * 4 + u16:: from ( offset) - self . cap_pci_cfg_info . offset ) as usize ;
772+ self . write_cap_pci_cfg ( offset, data)
745773 } else {
746- // Handle access to the header of the MsixCapability. The rest of the
747- // capability is handled by the PciConfiguration.
748- let base = reg_idx * 4 ;
749- if base == self . msix_config_cap_offset {
750- self . msix_config
751- . lock ( )
752- . unwrap ( )
753- . write_msg_ctl_register ( offset, data) ;
754- }
755- if base + u16:: from ( offset) >= self . cap_pci_cfg_info . offset
756- && ( base + u16:: from ( offset) ) as usize + data. len ( )
757- <= self . cap_pci_cfg_info . offset as usize
758- + self . cap_pci_cfg_info . cap . bytes ( ) . len ( )
759- {
760- let offset = ( base + u16:: from ( offset) - self . cap_pci_cfg_info . offset ) as usize ;
761- self . write_cap_pci_cfg ( offset, data)
762- } else {
763- self . configuration
764- . write_config_register ( reg_idx, offset, data) ;
765- None
766- }
774+ self . configuration
775+ . write_config_register ( reg_idx, offset, data) ;
776+ None
767777 }
768778 }
769779
770780 fn read_config_register ( & mut self , reg_idx : u16 ) -> u32 {
771- if BAR0_REG_IDX <= reg_idx && reg_idx < BAR0_REG_IDX + u16:: from ( NUM_BAR_REGS ) {
781+ let in_bars = BAR0_REG_IDX <= reg_idx && reg_idx < BAR0_REG_IDX + u16:: from ( NUM_BAR_REGS ) ;
782+ let in_pci_cfg = self . cap_pci_cfg_info . in_range ( reg_idx, 0 , 4 ) ;
783+
784+ if in_bars {
772785 // reg_idx is in [BAR0_REG_IDX, BAR0_REG_IDX+NUM_BAR_REGS), so the difference is 0..5.
773786 #[ allow( clippy:: cast_possible_truncation) ]
774787 let bar_idx = ( reg_idx - BAR0_REG_IDX ) as u8 ;
775788 let mut value: u32 = 0 ;
776789 self . bars . read ( bar_idx, 0 , value. as_mut_bytes ( ) ) ;
777790 value
778- } else {
791+ } else if in_pci_cfg {
779792 // Handle the special case where the capability VIRTIO_PCI_CAP_PCI_CFG
780793 // is accessed. This capability has a special meaning as it allows the
781794 // guest to access other capabilities without mapping the PCI BAR.
782- let base = reg_idx as usize * 4 ;
783- if base >= self . cap_pci_cfg_info . offset as usize
784- && base + 4
785- <= self . cap_pci_cfg_info . offset as usize
786- + self . cap_pci_cfg_info . cap . bytes ( ) . len ( )
787- {
788- let offset = base - self . cap_pci_cfg_info . offset as usize ;
789- let mut data = [ 0u8 ; 4 ] ;
790- let len = u32:: from ( self . cap_pci_cfg_info . cap . cap . length ) as usize ;
791- if len <= 4 {
792- self . read_cap_pci_cfg ( offset, & mut data[ ..len] ) ;
793- u32:: from_le_bytes ( data)
794- } else {
795- 0
796- }
795+ let offset = ( reg_idx * 4 - self . cap_pci_cfg_info . offset ) as usize ;
796+ let mut data = [ 0u8 ; 4 ] ;
797+ let len = u32:: from ( self . cap_pci_cfg_info . cap . cap . length ) as usize ;
798+ if len <= 4 {
799+ self . read_cap_pci_cfg ( offset, & mut data[ ..len] ) ;
800+ u32:: from_le_bytes ( data)
797801 } else {
798- self . configuration . read_reg ( reg_idx )
802+ 0
799803 }
804+ } else {
805+ self . configuration . read_reg ( reg_idx)
800806 }
801807 }
802808
0 commit comments