Skip to content

Commit 7868c27

Browse files
committed
uefi: Switch to GhostCell
This allows PciRootBridgeIo to be used as `protocol.copy_mem` instead of `PciRootBridgeIo::copy_mem(protocol, ...)`
1 parent d2c59fb commit 7868c27

File tree

9 files changed

+288
-197
lines changed

9 files changed

+288
-197
lines changed

Cargo.lock

Lines changed: 8 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ bitflags = "2.0.0"
2424
log = { version = "0.4.5", default-features = false }
2525
ptr_meta = { version = "0.3.0", default-features = false, features = ["derive"] }
2626
uguid = "2.2.1"
27+
ghost-cell = "0.2.6"
2728

2829
[patch.crates-io]
2930
uefi = { path = "uefi" }

uefi-raw/src/protocol/pci/root_bridge.rs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -153,3 +153,23 @@ pub struct PciRootBridgeIoProtocol {
153153
impl PciRootBridgeIoProtocol {
154154
pub const GUID: Guid = guid!("2f707ebb-4a1a-11d4-9a38-0090273fc14d");
155155
}
156+
157+
impl PciRootBridgeIoProtocolWidth {
158+
pub fn size(self) -> usize {
159+
match self {
160+
Self::UINT8 |
161+
Self::FIFO_UINT8 |
162+
Self::FILL_UINT8 => 1,
163+
Self::UINT16 |
164+
Self::FIFO_UINT16 |
165+
Self::FILL_UINT16 => 2,
166+
Self::UINT32 |
167+
Self::FIFO_UINT32 |
168+
Self::FILL_UINT32 => 4,
169+
Self::UINT64 |
170+
Self::FIFO_UINT64 |
171+
Self::FILL_UINT64 => 8,
172+
_ => unreachable!(),
173+
}
174+
}
175+
}

uefi-test-runner/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ edition = "2024"
99
uefi-raw = { path = "../uefi-raw" }
1010
uefi = { path = "../uefi", features = ["alloc", "global_allocator", "panic_handler", "logger", "qemu", "log-debugcon"] }
1111
smoltcp = { version = "0.12.0", default-features = false, features = ["medium-ethernet", "proto-ipv4", "socket-udp"] }
12+
ghost-cell.workspace = true
1213

1314
log.workspace = true
1415

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

Lines changed: 125 additions & 117 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22

33
use core::cell::RefCell;
44
use core::mem;
5+
use core::ops::DerefMut;
6+
use ghost_cell::GhostToken;
57
use uefi::boot::{image_handle, OpenProtocolAttributes, OpenProtocolParams, ScopedProtocol};
68
use uefi::proto::pci::root_bridge::PciRootBridgeIo;
79
use uefi::proto::pci::PciIoAddress;
@@ -27,45 +29,46 @@ pub fn test_io() {
2729
let mut sata_ctrl_cnt = 0;
2830

2931
for pci_handle in pci_handles {
30-
let mut pci_proto = get_open_protocol::<PciRootBridgeIo>(pci_handle);
31-
32-
for bus in 0..=255 {
33-
for dev in 0..32 {
34-
for fun in 0..8 {
35-
let addr = PciIoAddress::new(bus, dev, fun);
36-
let Ok(reg0) = pci_proto.pci().read_one::<u32>(addr.with_register(0)) else {
37-
continue;
38-
};
39-
if reg0 == 0xFFFFFFFF {
40-
continue; // not a valid device
41-
}
42-
let reg1 = pci_proto
43-
.pci()
44-
.read_one::<u32>(addr.with_register(2 * REG_SIZE))
45-
.unwrap();
46-
47-
let vendor_id = (reg0 & 0xFFFF) as u16;
48-
let device_id = (reg0 >> 16) as u16;
49-
if vendor_id == RED_HAT_PCI_VENDOR_ID {
50-
red_hat_dev_cnt += 1;
51-
}
32+
GhostToken::new(|mut token| {
33+
let pci_proto = get_open_protocol::<PciRootBridgeIo>(pci_handle);
34+
for bus in 0..=255 {
35+
for dev in 0..32 {
36+
for fun in 0..8 {
37+
let addr = PciIoAddress::new(bus, dev, fun);
38+
let Ok(reg0) = pci_proto.pci(&mut token).read_one::<u32>(addr.with_register(0)) else {
39+
continue;
40+
};
41+
if reg0 == 0xFFFFFFFF {
42+
continue; // not a valid device
43+
}
44+
let reg1 = pci_proto
45+
.pci(&mut token)
46+
.read_one::<u32>(addr.with_register(2 * REG_SIZE))
47+
.unwrap();
48+
49+
let vendor_id = (reg0 & 0xFFFF) as u16;
50+
let device_id = (reg0 >> 16) as u16;
51+
if vendor_id == RED_HAT_PCI_VENDOR_ID {
52+
red_hat_dev_cnt += 1;
53+
}
5254

53-
let class_code = (reg1 >> 24) as u8;
54-
let subclass_code = ((reg1 >> 16) & 0xFF) as u8;
55-
if class_code == MASS_STORAGE_CTRL_CLASS_CODE {
56-
mass_storage_ctrl_cnt += 1;
55+
let class_code = (reg1 >> 24) as u8;
56+
let subclass_code = ((reg1 >> 16) & 0xFF) as u8;
57+
if class_code == MASS_STORAGE_CTRL_CLASS_CODE {
58+
mass_storage_ctrl_cnt += 1;
5759

58-
if subclass_code == SATA_CTRL_SUBCLASS_CODE {
59-
sata_ctrl_cnt += 1;
60+
if subclass_code == SATA_CTRL_SUBCLASS_CODE {
61+
sata_ctrl_cnt += 1;
62+
}
6063
}
61-
}
6264

63-
log::info!(
65+
log::info!(
6466
"PCI Device: [{bus}, {dev}, {fun}]: vendor={vendor_id:04X}, device={device_id:04X}, class={class_code:02X}, subclass={subclass_code:02X}"
6567
);
68+
}
6669
}
6770
}
68-
}
71+
});
6972
}
7073

7174
assert!(red_hat_dev_cnt > 0);
@@ -77,106 +80,111 @@ pub fn test_buffer() {
7780
let pci_handles = uefi::boot::find_handles::<PciRootBridgeIo>().unwrap();
7881

7982
for pci_handle in pci_handles {
80-
let pci_proto = get_open_protocol::<PciRootBridgeIo>(pci_handle);
81-
let pci_proto: RefCell<_> = pci_proto.into();
82-
83-
let mut buffer = PciRootBridgeIo::allocate_buffer::<[u8; 4096]>(
84-
&pci_proto,
85-
MemoryType::BOOT_SERVICES_DATA,
86-
None,
87-
PciRootBridgeIoProtocolAttribute::PCI_ATTRIBUTE_MEMORY_WRITE_COMBINE,
88-
)
89-
.unwrap();
90-
let buffer = unsafe {
91-
buffer.assume_init_mut().fill(0);
92-
buffer.assume_init()
93-
};
94-
assert_eq!(buffer.as_ptr().addr() % 4096, 0);
83+
GhostToken::new(|token| {
84+
let pci_proto = get_open_protocol::<PciRootBridgeIo>(pci_handle);
85+
let token: RefCell<_> = token.into();
86+
let mut buffer = pci_proto.allocate_buffer::<[u8; 4096]>(
87+
&token,
88+
MemoryType::BOOT_SERVICES_DATA,
89+
None,
90+
PciRootBridgeIoProtocolAttribute::PCI_ATTRIBUTE_MEMORY_WRITE_COMBINE,
91+
).unwrap();
92+
93+
let buffer = unsafe {
94+
buffer.assume_init_mut().fill(0);
95+
buffer.assume_init()
96+
};
97+
98+
assert_eq!(buffer.as_ptr().addr() % 4096, 0);
99+
});
95100
}
96101
}
97102

98103
pub fn test_mapping() {
99104
let pci_handles = uefi::boot::find_handles::<PciRootBridgeIo>().unwrap();
100105

101106
for pci_handle in pci_handles {
102-
let pci_proto = get_open_protocol::<PciRootBridgeIo>(pci_handle);
103-
let pci_proto: RefCell<_> = pci_proto.into();
104-
105-
let mut buffer = PciRootBridgeIo::allocate_buffer::<[u8; 4096]>(
106-
&pci_proto,
107-
MemoryType::BOOT_SERVICES_DATA,
108-
None,
109-
PciRootBridgeIoProtocolAttribute::PCI_ATTRIBUTE_MEMORY_WRITE_COMBINE,
110-
)
111-
.unwrap();
112-
let buffer = unsafe {
113-
buffer.assume_init_mut().fill(0);
114-
buffer.assume_init()
115-
};
116-
117-
let mapped = PciRootBridgeIo::map(
118-
&pci_proto,
119-
PciRootBridgeIoProtocolOperation::BUS_MASTER_COMMON_BUFFER64,
120-
buffer.as_ref(),
121-
);
122-
if mapped.region().device_address == buffer.as_ptr().addr() as u64 {
123-
info!("This PCI device uses identity mapping");
124-
} else {
125-
info!("This PCI device uses different mapping from CPU");
126-
}
107+
GhostToken::new(|token| {
108+
let pci_proto = get_open_protocol::<PciRootBridgeIo>(pci_handle);
109+
let token: RefCell<_> = token.into();
110+
111+
let mut buffer = pci_proto.allocate_buffer::<[u8; 4096]>(
112+
&token,
113+
MemoryType::BOOT_SERVICES_DATA,
114+
None,
115+
PciRootBridgeIoProtocolAttribute::PCI_ATTRIBUTE_MEMORY_WRITE_COMBINE,
116+
).unwrap();
117+
let buffer = unsafe {
118+
buffer.assume_init_mut().fill(0);
119+
buffer.assume_init()
120+
};
121+
122+
let mapped = pci_proto.map(
123+
&token,
124+
PciRootBridgeIoProtocolOperation::BUS_MASTER_COMMON_BUFFER64,
125+
buffer.as_ref(),
126+
);
127+
if mapped.region().device_address == buffer.as_ptr().addr() as u64 {
128+
info!("This PCI device uses identity mapping");
129+
} else {
130+
info!("This PCI device uses different mapping from CPU");
131+
}
132+
});
127133
}
128134
}
129135

130136
pub fn test_copy() {
131137
let pci_handles = uefi::boot::find_handles::<PciRootBridgeIo>().unwrap();
132138

133139
for pci_handle in pci_handles {
134-
let pci_proto = get_open_protocol::<PciRootBridgeIo>(pci_handle);
135-
let pci_proto: RefCell<_> = pci_proto.into();
136-
137-
let mut src = PciRootBridgeIo::allocate_buffer::<[u32; 4096 / 4]>(
138-
&pci_proto,
139-
MemoryType::BOOT_SERVICES_DATA,
140-
None,
141-
PciRootBridgeIoProtocolAttribute::PCI_ATTRIBUTE_MEMORY_WRITE_COMBINE,
142-
)
143-
.unwrap();
144-
assert_eq!(size_of_val(src.as_ref()), size_of::<[u8; PAGE_SIZE]>());
145-
let src = unsafe {
146-
src.assume_init_mut().fill(0xDEADBEEF);
147-
src.assume_init()
148-
};
149-
let src_mapped = PciRootBridgeIo::map(
150-
&pci_proto,
151-
PciRootBridgeIoProtocolOperation::BUS_MASTER_READ,
152-
src.as_ref(),
153-
);
154-
155-
let dst = PciRootBridgeIo::allocate_buffer::<[u32; 4096 / 4]>(
156-
&pci_proto,
157-
MemoryType::BOOT_SERVICES_DATA,
158-
None,
159-
PciRootBridgeIoProtocolAttribute::PCI_ATTRIBUTE_MEMORY_WRITE_COMBINE,
160-
)
161-
.unwrap();
162-
assert_eq!(size_of_val(dst.as_ref()), size_of::<[u8; PAGE_SIZE]>());
163-
let dst_mapped = PciRootBridgeIo::map(
164-
&pci_proto,
165-
PciRootBridgeIoProtocolOperation::BUS_MASTER_WRITE,
166-
dst.as_ref(),
167-
);
168-
169-
PciRootBridgeIo::copy(
170-
&pci_proto,
171-
PciRootBridgeIoProtocolWidth::UINT32,
172-
dst_mapped.region(),
173-
src_mapped.region(),
174-
)
175-
.unwrap();
176-
drop(dst_mapped);
177-
let dst = unsafe { dst.assume_init() };
178-
179-
assert!(dst.iter().all(|&b| b == 0xDEADBEEF));
140+
GhostToken::new(|token| {
141+
let pci_proto = get_open_protocol::<PciRootBridgeIo>(pci_handle);
142+
let token: RefCell<_> = token.into();
143+
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+
);
160+
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() };
185+
186+
assert!(dst.iter().all(|&b| b == 0xDEADBEEF));
187+
});
180188
}
181189
}
182190

uefi/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ ucs2 = "0.3.3"
4545
uefi-macros = "0.18.1"
4646
uefi-raw = "0.11.0"
4747
qemu-exit = { version = "3.0.2", optional = true }
48+
ghost-cell.workspace = true
4849

4950
[package.metadata.docs.rs]
5051
all-features = true

0 commit comments

Comments
 (0)