@@ -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 {
@@ -734,67 +745,62 @@ impl PciDevice for VirtioPciDevice {
734745 offset : u8 ,
735746 data : & [ u8 ] ,
736747 ) -> Option < Arc < Barrier > > {
737- if BAR0_REG_IDX <= reg_idx && reg_idx < BAR0_REG_IDX + u16:: from ( NUM_BAR_REGS ) {
748+ let in_bars = BAR0_REG_IDX <= reg_idx && reg_idx < BAR0_REG_IDX + u16:: from ( NUM_BAR_REGS ) ;
749+ let in_msix_cap_header = reg_idx * 4 == self . msix_config_cap_offset ;
750+ let in_pci_cfg = self . cap_pci_cfg_info . in_range ( reg_idx, offset, data. len ( ) ) ;
751+ if in_bars {
738752 // reg_idx is in [BAR0_REG_IDX, BAR0_REG_IDX+NUM_BAR_REGS), so the difference is 0..5.
739753 #[ allow( clippy:: cast_possible_truncation) ]
740754 let bar_idx = ( reg_idx - BAR0_REG_IDX ) as u8 ;
741755 self . bars . write ( bar_idx, offset, data) ;
742756 None
757+ } else if in_msix_cap_header {
758+ // For the MsixCap structure, we need to capture writes to the second 2 bytes
759+ // of the capability header where Function Mask and MSI-X Enable bits are present.
760+ // Everything else can be served from `self.configuration`.
761+ self . msix_config
762+ . lock ( )
763+ . unwrap ( )
764+ . write_msg_ctl_register ( offset, data) ;
765+ self . configuration
766+ . write_config_register ( reg_idx, offset, data) ;
767+ None
768+ } else if in_pci_cfg {
769+ let offset = ( reg_idx * 4 + u16:: from ( offset) - self . cap_pci_cfg_info . offset ) as usize ;
770+ self . write_cap_pci_cfg ( offset, data)
743771 } else {
744- // Handle access to the header of the MsixCapability. The rest of the
745- // capability is handled by the PciConfiguration.
746- let base = reg_idx * 4 ;
747- if base == self . msix_config_cap_offset {
748- self . msix_config
749- . lock ( )
750- . unwrap ( )
751- . write_msg_ctl_register ( offset, data) ;
752- }
753- if base + u16:: from ( offset) >= self . cap_pci_cfg_info . offset
754- && ( base + u16:: from ( offset) ) as usize + data. len ( )
755- <= self . cap_pci_cfg_info . offset as usize
756- + self . cap_pci_cfg_info . cap . bytes ( ) . len ( )
757- {
758- let offset = ( base + u16:: from ( offset) - self . cap_pci_cfg_info . offset ) as usize ;
759- self . write_cap_pci_cfg ( offset, data)
760- } else {
761- self . configuration
762- . write_config_register ( reg_idx, offset, data) ;
763- None
764- }
772+ self . configuration
773+ . write_config_register ( reg_idx, offset, data) ;
774+ None
765775 }
766776 }
767777
768778 fn read_config_register ( & mut self , reg_idx : u16 ) -> u32 {
769- if BAR0_REG_IDX <= reg_idx && reg_idx < BAR0_REG_IDX + u16:: from ( NUM_BAR_REGS ) {
779+ let in_bars = BAR0_REG_IDX <= reg_idx && reg_idx < BAR0_REG_IDX + u16:: from ( NUM_BAR_REGS ) ;
780+ let in_pci_cfg = self . cap_pci_cfg_info . in_range ( reg_idx, 0 , 4 ) ;
781+
782+ if in_bars {
770783 // reg_idx is in [BAR0_REG_IDX, BAR0_REG_IDX+NUM_BAR_REGS), so the difference is 0..5.
771784 #[ allow( clippy:: cast_possible_truncation) ]
772785 let bar_idx = ( reg_idx - BAR0_REG_IDX ) as u8 ;
773786 let mut value: u32 = 0 ;
774787 self . bars . read ( bar_idx, 0 , value. as_mut_bytes ( ) ) ;
775788 value
776- } else {
789+ } else if in_pci_cfg {
777790 // Handle the special case where the capability VIRTIO_PCI_CAP_PCI_CFG
778791 // is accessed. This capability has a special meaning as it allows the
779792 // guest to access other capabilities without mapping the PCI BAR.
780- let base = reg_idx as usize * 4 ;
781- if base >= self . cap_pci_cfg_info . offset as usize
782- && base + 4
783- <= self . cap_pci_cfg_info . offset as usize
784- + self . cap_pci_cfg_info . cap . bytes ( ) . len ( )
785- {
786- let offset = base - self . cap_pci_cfg_info . offset as usize ;
787- let mut data = [ 0u8 ; 4 ] ;
788- let len = u32:: from ( self . cap_pci_cfg_info . cap . cap . length ) as usize ;
789- if len <= 4 {
790- self . read_cap_pci_cfg ( offset, & mut data[ ..len] ) ;
791- u32:: from_le_bytes ( data)
792- } else {
793- 0
794- }
793+ let offset = ( reg_idx * 4 - self . cap_pci_cfg_info . offset ) as usize ;
794+ let mut data = [ 0u8 ; 4 ] ;
795+ let len = u32:: from ( self . cap_pci_cfg_info . cap . cap . length ) as usize ;
796+ if len <= 4 {
797+ self . read_cap_pci_cfg ( offset, & mut data[ ..len] ) ;
798+ u32:: from_le_bytes ( data)
795799 } else {
796- self . configuration . read_reg ( reg_idx )
800+ 0
797801 }
802+ } else {
803+ self . configuration . read_reg ( reg_idx)
798804 }
799805 }
800806
0 commit comments