Skip to content

Commit 40163cd

Browse files
committed
uefi: Fix copy_mem test and implement access for io and memory space
1 parent 1e47344 commit 40163cd

File tree

5 files changed

+175
-84
lines changed

5 files changed

+175
-84
lines changed

uefi-test-runner/src/proto/pci/root_bridge.rs

Lines changed: 68 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
// SPDX-License-Identifier: MIT OR Apache-2.0
22

33
use core::cell::RefCell;
4-
use core::mem;
54
use core::ops::DerefMut;
5+
use core::ptr;
66
use ghost_cell::GhostToken;
77
use uefi::boot::{image_handle, OpenProtocolAttributes, OpenProtocolParams, ScopedProtocol};
88
use uefi::proto::pci::root_bridge::PciRootBridgeIo;
@@ -11,15 +11,15 @@ use uefi::proto::ProtocolPointer;
1111
use uefi::Handle;
1212
use uefi_raw::protocol::pci::root_bridge::{
1313
PciRootBridgeIoProtocolAttribute, PciRootBridgeIoProtocolOperation,
14-
PciRootBridgeIoProtocolWidth,
1514
};
16-
use uefi_raw::table::boot::{MemoryType, PAGE_SIZE};
15+
use uefi_raw::table::boot::MemoryType;
1716

1817
const RED_HAT_PCI_VENDOR_ID: u16 = 0x1AF4;
1918
const MASS_STORAGE_CTRL_CLASS_CODE: u8 = 0x1;
2019
const SATA_CTRL_SUBCLASS_CODE: u8 = 0x6;
20+
const DEVICE_IVSHMEM: u16 = 0x1110;
2121

22-
const REG_SIZE: u8 = mem::size_of::<u32>() as u8;
22+
const REG_SIZE: u8 = size_of::<u32>() as u8;
2323

2424
pub fn test_io() {
2525
let pci_handles = uefi::boot::find_handles::<PciRootBridgeIo>().unwrap();
@@ -123,7 +123,7 @@ pub fn test_mapping() {
123123
&token,
124124
PciRootBridgeIoProtocolOperation::BUS_MASTER_COMMON_BUFFER64,
125125
buffer.as_ref(),
126-
);
126+
).unwrap();
127127
if mapped.region().device_address == buffer.as_ptr().addr() as u64 {
128128
info!("This PCI device uses identity mapping");
129129
} else {
@@ -138,52 +138,73 @@ pub fn test_copy() {
138138

139139
for pci_handle in pci_handles {
140140
GhostToken::new(|token| {
141-
let pci_proto = get_open_protocol::<PciRootBridgeIo>(pci_handle);
142141
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+
}
143155

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;
160158

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);
185168

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+
}
187208
});
188209
}
189210
}

uefi/src/proto/pci/mod.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,10 @@ impl PciIoUnit for u8 {}
9999
impl PciIoUnit for u16 {}
100100
impl PciIoUnit for u32 {}
101101
impl PciIoUnit for u64 {}
102+
impl PciIoUnit for i8 {}
103+
impl PciIoUnit for i16 {}
104+
impl PciIoUnit for i32 {}
105+
impl PciIoUnit for i64 {}
102106

103107
#[allow(dead_code)]
104108
enum PciIoMode {
@@ -108,7 +112,7 @@ enum PciIoMode {
108112
}
109113

110114
fn encode_io_mode_and_unit<U: PciIoUnit>(mode: PciIoMode) -> PciRootBridgeIoProtocolWidth {
111-
match (mode, core::mem::size_of::<U>()) {
115+
match (mode, size_of::<U>()) {
112116
(PciIoMode::Normal, 1) => PciRootBridgeIoProtocolWidth::UINT8,
113117
(PciIoMode::Normal, 2) => PciRootBridgeIoProtocolWidth::UINT16,
114118
(PciIoMode::Normal, 4) => PciRootBridgeIoProtocolWidth::UINT32,

uefi/src/proto/pci/region.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ pub struct PciRegion {
4545
}
4646

4747
impl<'p, 'r, 'id> PciMappedRegion<'p, 'r, 'id> where 'p: 'r {
48-
pub(crate) fn new<T>(
48+
pub(crate) fn new<T: ?Sized>(
4949
device_address: u64,
5050
length: usize,
5151
key: *const c_void,

0 commit comments

Comments
 (0)