11// SPDX-License-Identifier: MIT OR Apache-2.0
22
3+ use alloc:: collections:: btree_set:: BTreeSet ;
4+ use alloc:: string:: ToString ;
35use uefi:: Handle ;
46use uefi:: boot:: { OpenProtocolAttributes , OpenProtocolParams , ScopedProtocol , image_handle} ;
57use uefi:: proto:: ProtocolPointer ;
8+ use uefi:: proto:: device_path:: DevicePath ;
9+ use uefi:: proto:: device_path:: text:: { AllowShortcuts , DisplayOnly } ;
610use uefi:: proto:: pci:: root_bridge:: PciRootBridgeIo ;
11+ use uefi:: proto:: scsi:: pass_thru:: ExtScsiPassThru ;
712
813const RED_HAT_PCI_VENDOR_ID : u16 = 0x1AF4 ;
914const MASS_STORAGE_CTRL_CLASS_CODE : u8 = 0x1 ;
@@ -14,55 +19,73 @@ const REG_SIZE: u8 = size_of::<u32>() as u8;
1419pub fn test ( ) {
1520 let pci_handles = uefi:: boot:: find_handles :: < PciRootBridgeIo > ( ) . unwrap ( ) ;
1621
22+ let mut sata_ctrl_cnt = 0 ;
1723 let mut red_hat_dev_cnt = 0 ;
1824 let mut mass_storage_ctrl_cnt = 0 ;
19- let mut sata_ctrl_cnt = 0 ;
25+ let mut mass_storage_dev_paths = BTreeSet :: new ( ) ;
2026
2127 for pci_handle in pci_handles {
2228 let mut pci_proto = get_open_protocol :: < PciRootBridgeIo > ( pci_handle) ;
29+ let root_device_path = get_open_protocol :: < DevicePath > ( pci_handle) ;
2330
2431 let pci_tree = pci_proto. enumerate ( ) . unwrap ( ) ;
2532 for addr in pci_tree. iter ( ) . cloned ( ) {
26- let Ok ( reg0) = pci_proto. pci ( ) . read_one :: < u32 > ( addr. with_register ( 0 ) ) else {
27- continue ;
28- } ;
29- if reg0 == 0xFFFFFFFF {
30- continue ; // not a valid device
31- }
33+ let reg0 = pci_proto
34+ . pci ( )
35+ . read_one :: < u32 > ( addr. with_register ( 0 ) )
36+ . unwrap ( ) ;
3237 let reg1 = pci_proto
3338 . pci ( )
3439 . read_one :: < u32 > ( addr. with_register ( 2 * REG_SIZE ) )
3540 . unwrap ( ) ;
3641
3742 let vendor_id = ( reg0 & 0xFFFF ) as u16 ;
3843 let device_id = ( reg0 >> 16 ) as u16 ;
44+ let class_code = ( reg1 >> 24 ) as u8 ;
45+ let subclass_code = ( ( reg1 >> 16 ) & 0xFF ) as u8 ;
46+ let device_path = pci_tree. device_path ( & root_device_path, addr) . unwrap ( ) ;
47+ let device_path_str = device_path
48+ . to_string ( DisplayOnly ( false ) , AllowShortcuts ( false ) )
49+ . unwrap ( )
50+ . to_string ( ) ;
51+
3952 if vendor_id == RED_HAT_PCI_VENDOR_ID {
4053 red_hat_dev_cnt += 1 ;
4154 }
42-
43- let class_code = ( reg1 >> 24 ) as u8 ;
44- let subclass_code = ( ( reg1 >> 16 ) & 0xFF ) as u8 ;
4555 if class_code == MASS_STORAGE_CTRL_CLASS_CODE {
4656 mass_storage_ctrl_cnt += 1 ;
47-
4857 if subclass_code == SATA_CTRL_SUBCLASS_CODE {
4958 sata_ctrl_cnt += 1 ;
5059 }
60+ mass_storage_dev_paths. insert ( device_path_str. clone ( ) ) ;
5161 }
5262
5363 let ( bus, dev, fun) = ( addr. bus , addr. dev , addr. fun ) ;
5464 log:: info!(
55- "PCI Device: [{bus:02x}, {dev:02x}, {fun:02x}]: vendor={vendor_id:04X}, device={device_id:04X}, class={class_code:02X}, subclass={subclass_code:02X}"
65+ "PCI Device: [{bus:02x}, {dev:02x}, {fun:02x}]: vendor={vendor_id:04X}, device={device_id:04X}, class={class_code:02X}, subclass={subclass_code:02X} - {}" ,
66+ device_path_str
5667 ) ;
5768 for child_bus in pci_tree. iter_subsequent_busses_for ( addr) {
58- log:: info!( " | - Bus: {child_bus:02x}" ) ;
69+ log:: info!( " \\ - Bus: {child_bus:02x}" ) ;
5970 }
6071 }
6172 }
6273
74+ assert ! ( sata_ctrl_cnt > 0 ) ;
6375 assert ! ( red_hat_dev_cnt > 0 ) ;
6476 assert ! ( mass_storage_ctrl_cnt > 0 ) ;
65- assert ! ( sata_ctrl_cnt > 0 ) ;
77+ assert_eq ! ( mass_storage_ctrl_cnt, mass_storage_dev_paths. len( ) ) ;
78+
79+ // Check that all `ExtScsiPassThru` instances' device paths have been found
80+ let scsi_handles = uefi:: boot:: find_handles :: < ExtScsiPassThru > ( ) . unwrap ( ) ;
81+ for scsi_handle in scsi_handles {
82+ let device_path = get_open_protocol :: < DevicePath > ( scsi_handle) ;
83+ let device_path = device_path
84+ . to_string ( DisplayOnly ( false ) , AllowShortcuts ( false ) )
85+ . unwrap ( )
86+ . to_string ( ) ;
87+ assert ! ( mass_storage_dev_paths. contains( & device_path) ) ;
88+ }
6689}
6790
6891fn get_open_protocol < P : ProtocolPointer + ?Sized > ( handle : Handle ) -> ScopedProtocol < P > {
0 commit comments