1
1
// SPDX-License-Identifier: MIT OR Apache-2.0
2
2
3
3
use core:: cell:: RefCell ;
4
- use core:: mem;
5
4
use core:: ops:: DerefMut ;
5
+ use core:: ptr;
6
6
use ghost_cell:: GhostToken ;
7
7
use uefi:: boot:: { image_handle, OpenProtocolAttributes , OpenProtocolParams , ScopedProtocol } ;
8
8
use uefi:: proto:: pci:: root_bridge:: PciRootBridgeIo ;
@@ -11,15 +11,15 @@ use uefi::proto::ProtocolPointer;
11
11
use uefi:: Handle ;
12
12
use uefi_raw:: protocol:: pci:: root_bridge:: {
13
13
PciRootBridgeIoProtocolAttribute , PciRootBridgeIoProtocolOperation ,
14
- PciRootBridgeIoProtocolWidth ,
15
14
} ;
16
- use uefi_raw:: table:: boot:: { MemoryType , PAGE_SIZE } ;
15
+ use uefi_raw:: table:: boot:: MemoryType ;
17
16
18
17
const RED_HAT_PCI_VENDOR_ID : u16 = 0x1AF4 ;
19
18
const MASS_STORAGE_CTRL_CLASS_CODE : u8 = 0x1 ;
20
19
const SATA_CTRL_SUBCLASS_CODE : u8 = 0x6 ;
20
+ const DEVICE_IVSHMEM : u16 = 0x1110 ;
21
21
22
- const REG_SIZE : u8 = mem :: size_of :: < u32 > ( ) as u8 ;
22
+ const REG_SIZE : u8 = size_of :: < u32 > ( ) as u8 ;
23
23
24
24
pub fn test_io ( ) {
25
25
let pci_handles = uefi:: boot:: find_handles :: < PciRootBridgeIo > ( ) . unwrap ( ) ;
@@ -123,7 +123,7 @@ pub fn test_mapping() {
123
123
& token,
124
124
PciRootBridgeIoProtocolOperation :: BUS_MASTER_COMMON_BUFFER64 ,
125
125
buffer. as_ref ( ) ,
126
- ) ;
126
+ ) . unwrap ( ) ;
127
127
if mapped. region ( ) . device_address == buffer. as_ptr ( ) . addr ( ) as u64 {
128
128
info ! ( "This PCI device uses identity mapping" ) ;
129
129
} else {
@@ -138,52 +138,73 @@ pub fn test_copy() {
138
138
139
139
for pci_handle in pci_handles {
140
140
GhostToken :: new ( |token| {
141
- let pci_proto = get_open_protocol :: < PciRootBridgeIo > ( pci_handle) ;
142
141
let token: RefCell < _ > = token. into ( ) ;
142
+ let pci_proto = get_open_protocol :: < PciRootBridgeIo > ( pci_handle) ;
143
+ for bus in 0 ..=255 {
144
+ for dev in 0 ..32 {
145
+ for fun in 0 ..8 {
146
+ let addr = PciIoAddress :: new ( bus, dev, fun) ;
147
+ let mut token_mut = token. borrow_mut ( ) ;
148
+ let pci_access = pci_proto. pci ( token_mut. deref_mut ( ) ) ;
149
+ let Ok ( reg0) = pci_access. read_one :: < u32 > ( addr. with_register ( 0 ) ) else {
150
+ continue ;
151
+ } ;
152
+ if reg0 == 0xFFFFFFFF {
153
+ continue ; // not a valid device
154
+ }
143
155
144
- let mut src = pci_proto. allocate_buffer :: < [ u32 ; 4096 / 4 ] > (
145
- & token,
146
- MemoryType :: BOOT_SERVICES_DATA ,
147
- None ,
148
- PciRootBridgeIoProtocolAttribute :: PCI_ATTRIBUTE_MEMORY_WRITE_COMBINE ,
149
- ) . unwrap ( ) ;
150
- assert_eq ! ( size_of_val( src. as_ref( ) ) , size_of:: <[ u8 ; PAGE_SIZE ] >( ) ) ;
151
- let src = unsafe {
152
- src. assume_init_mut ( ) . fill ( 0xDEADBEEF ) ;
153
- src. assume_init ( )
154
- } ;
155
- let src_mapped = pci_proto. map (
156
- & token,
157
- PciRootBridgeIoProtocolOperation :: BUS_MASTER_READ ,
158
- src. as_ref ( ) ,
159
- ) ;
156
+ let vendor_id = ( reg0 & 0xFFFF ) as u16 ;
157
+ let device_id = ( reg0 >> 16 ) as u16 ;
160
158
161
- let dst = pci_proto. allocate_buffer :: < [ u32 ; 4096 / 4 ] > (
162
- & token,
163
- MemoryType :: BOOT_SERVICES_DATA ,
164
- None ,
165
- PciRootBridgeIoProtocolAttribute :: PCI_ATTRIBUTE_MEMORY_WRITE_COMBINE ,
166
- ) . unwrap ( ) ;
167
- assert_eq ! ( size_of_val( dst. as_ref( ) ) , size_of:: <[ u8 ; PAGE_SIZE ] >( ) ) ;
168
- let dst_mapped = pci_proto. map (
169
- & token,
170
- PciRootBridgeIoProtocolOperation :: BUS_MASTER_WRITE ,
171
- dst. as_ref ( ) ,
172
- ) ;
173
-
174
- let width = PciRootBridgeIoProtocolWidth :: UINT32 ;
175
- assert_eq ! ( width. size( ) , 4 ) ;
176
-
177
- pci_proto. copy (
178
- token. borrow_mut ( ) . deref_mut ( ) ,
179
- width,
180
- dst_mapped. region ( ) ,
181
- src_mapped. region ( ) ,
182
- ) . unwrap ( ) ;
183
- drop ( dst_mapped) ;
184
- let dst = unsafe { dst. assume_init ( ) } ;
159
+ if vendor_id != RED_HAT_PCI_VENDOR_ID {
160
+ continue ;
161
+ }
162
+ if device_id != DEVICE_IVSHMEM {
163
+ continue ;
164
+ }
165
+
166
+ let header_type: u8 = pci_access. read_one ( addr. with_register ( 0xE ) ) . unwrap ( ) ;
167
+ assert_eq ! ( header_type, 0 ) ;
185
168
186
- assert ! ( dst. iter( ) . all( |& b| b == 0xDEADBEEF ) ) ;
169
+ let command_value = pci_access. read_one :: < u16 > ( addr. with_register ( 4 ) ) . unwrap ( ) ;
170
+ pci_access. write_one :: < u16 > ( addr. with_register ( 4 ) , command_value & !0x11 ) . unwrap ( ) ;
171
+
172
+ let bar2 = pci_access. read_one :: < u64 > ( addr. with_register ( 0x18 ) ) . unwrap ( ) ; // reads both bar2 and bar3 since it's 64bit
173
+ assert_eq ! ( bar2 & 0b1 , 0 ) ;
174
+ assert_eq ! ( ( bar2 & 0b110 ) >> 1 , 2 ) ; // make sure it's actually 64bit
175
+
176
+ let bar2_value = bar2 & 0xFFFFFFFFFFFFFFF0 ;
177
+ let bar2_size = {
178
+ pci_access. write_one ( addr. with_register ( 0x18 ) , u32:: MAX ) . unwrap ( ) ;
179
+ let value: u32 = pci_access. read_one ( addr. with_register ( 0x18 ) ) . unwrap ( ) ;
180
+ let size = ( !value) . wrapping_add ( 1 ) ;
181
+ pci_access. write_one ( addr. with_register ( 0x18 ) , bar2 as u32 ) . unwrap ( ) ;
182
+ size
183
+ } ;
184
+ assert ! ( bar2_size >= 0x1000 * 2 ) ;
185
+
186
+ pci_access. write_one :: < u16 > ( addr. with_register ( 4 ) , command_value | 0b10 ) . unwrap ( ) ;
187
+ drop ( pci_access) ;
188
+ drop ( token_mut) ;
189
+
190
+ let ( src, dst) = unsafe {
191
+ let src = ptr:: slice_from_raw_parts_mut ( ( bar2_value as usize ) as * mut u32 , 0x1000 / size_of :: < u32 > ( ) ) . as_mut ( ) . unwrap ( ) ;
192
+ let dst = ptr:: slice_from_raw_parts ( ( bar2_value as usize + 0x1000 ) as * mut u32 , 0x1000 / size_of :: < u32 > ( ) ) . as_ref ( ) . unwrap ( ) ;
193
+ ( src, dst)
194
+ } ;
195
+ src. fill ( 0xDEADBEEF ) ;
196
+
197
+ pci_proto. copy :: < u32 > (
198
+ token. borrow_mut ( ) . deref_mut ( ) ,
199
+ dst,
200
+ src,
201
+ ) . unwrap ( ) ;
202
+
203
+ assert ! ( dst. iter( ) . all( |& b| b == 0xDEADBEEF ) ) ;
204
+ break ;
205
+ }
206
+ }
207
+ }
187
208
} ) ;
188
209
}
189
210
}
0 commit comments