Skip to content

Commit 0bfd3c0

Browse files
committed
Sending WIP - squash later
1 parent 81da7a4 commit 0bfd3c0

File tree

5 files changed

+152
-45
lines changed

5 files changed

+152
-45
lines changed

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

Lines changed: 44 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,14 @@
11
// SPDX-License-Identifier: MIT OR Apache-2.0
22

33
use core::mem;
4+
use qcell::{QCell, QCellOwner};
45
use uefi::Handle;
56
use uefi::boot::{OpenProtocolAttributes, OpenProtocolParams, ScopedProtocol, image_handle};
67
use uefi::proto::ProtocolPointer;
78
use uefi::proto::pci::PciIoAddress;
89
use uefi::proto::pci::root_bridge::PciRootBridgeIo;
9-
use uefi_raw::protocol::pci::root_bridge::{PciRootBridgeIoProtocolAttribute, PciRootBridgeIoProtocolOperation};
10-
use uefi_raw::table::boot::MemoryType;
10+
use uefi_raw::protocol::pci::root_bridge::{PciRootBridgeIoProtocolAttribute, PciRootBridgeIoProtocolOperation, PciRootBridgeIoProtocolWidth};
11+
use uefi_raw::table::boot::{MemoryType, PAGE_SIZE};
1112

1213
const RED_HAT_PCI_VENDOR_ID: u16 = 0x1AF4;
1314
const MASS_STORAGE_CTRL_CLASS_CODE: u8 = 0x1;
@@ -108,14 +109,54 @@ pub fn test_mapping() {
108109
buffer.assume_init()
109110
};
110111
let mapped = pci_proto.map(PciRootBridgeIoProtocolOperation::BUS_MASTER_COMMON_BUFFER64, buffer.as_ref());
111-
if mapped.region().0 == buffer.as_ptr().addr() as u64 {
112+
if mapped.region().device_address == buffer.as_ptr().addr() as u64 {
112113
info!("This PCI device uses identity mapping");
113114
} else {
114115
info!("This PCI device uses different mapping from CPU");
115116
}
116117
}
117118
}
118119

120+
pub fn test_copy() {
121+
let pci_handles = uefi::boot::find_handles::<PciRootBridgeIo>().unwrap();
122+
123+
for pci_handle in pci_handles {
124+
let mut owner = QCellOwner::new();
125+
let item = QCell::new(&owner, get_open_protocol::<PciRootBridgeIo>(pci_handle));
126+
let pci_proto = owner.rw(&item);
127+
128+
let mut src = pci_proto
129+
.allocate_buffer::<[u32; 4096 / 4]>(
130+
MemoryType::BOOT_SERVICES_DATA,
131+
None,
132+
PciRootBridgeIoProtocolAttribute::PCI_ATTRIBUTE_MEMORY_WRITE_COMBINE,
133+
)
134+
.unwrap();
135+
assert_eq!(size_of_val(src.as_ref()), size_of::<[u8; PAGE_SIZE]>());
136+
let src = unsafe {
137+
src.assume_init_mut().fill(0xDEADBEEF);
138+
src.assume_init()
139+
};
140+
let src_mapped = pci_proto.map(PciRootBridgeIoProtocolOperation::BUS_MASTER_READ, src.as_ref());
141+
142+
let dst = pci_proto
143+
.allocate_buffer::<[u32; 4096 / 4]>(
144+
MemoryType::BOOT_SERVICES_DATA,
145+
None,
146+
PciRootBridgeIoProtocolAttribute::PCI_ATTRIBUTE_MEMORY_WRITE_COMBINE,
147+
)
148+
.unwrap();
149+
assert_eq!(size_of_val(dst.as_ref()), size_of::<[u8; PAGE_SIZE]>());
150+
let dst_mapped = pci_proto.map(PciRootBridgeIoProtocolOperation::BUS_MASTER_WRITE, dst.as_ref());
151+
152+
pci_proto.copy(PciRootBridgeIoProtocolWidth::UINT32, dst_mapped.region(), src_mapped.region()).unwrap();
153+
drop(dst_mapped);
154+
let dst = unsafe { dst.assume_init() };
155+
156+
assert!(dst.iter().all(|&b| b == 0xDEADBEEF));
157+
}
158+
}
159+
119160
fn get_open_protocol<P: ProtocolPointer + ?Sized>(handle: Handle) -> ScopedProtocol<P> {
120161
let open_opts = OpenProtocolParams {
121162
handle,

uefi/src/proto/pci/buffer.rs

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
use core::mem::{ManuallyDrop, MaybeUninit};
66
use core::num::NonZeroUsize;
77
use core::ops::{Deref, DerefMut};
8+
use core::ptr;
89
use core::ptr::NonNull;
910
use log::debug;
1011
use uefi_raw::Status;
@@ -13,12 +14,27 @@ use uefi_raw::protocol::pci::root_bridge::PciRootBridgeIoProtocol;
1314
/// Smart pointer for wrapping owned buffer allocated by PCI Root Bridge protocol.
1415
#[derive(Debug)]
1516
pub struct PciBuffer<'p, T> {
16-
pub(crate) base: NonNull<T>,
17-
pub(crate) pages: NonZeroUsize,
18-
pub(crate) proto: &'p PciRootBridgeIoProtocol,
17+
base: NonNull<T>,
18+
pages: NonZeroUsize,
19+
proto_lifetime: &'p (),
20+
proto: *const PciRootBridgeIoProtocol,
1921
}
2022

2123
impl<'p, T> PciBuffer<'p, MaybeUninit<T>> {
24+
25+
/// Creates wrapper for buffer allocated by PCI Root Bridge protocol.
26+
/// Passed protocol is stored as a pointer along with its lifetime so that it doesn't
27+
/// block others from using its mutable functions.
28+
#[must_use]
29+
pub const fn new(base: NonNull<MaybeUninit<T>>, pages: NonZeroUsize, proto: &'p PciRootBridgeIoProtocol) -> Self {
30+
Self {
31+
base,
32+
pages,
33+
proto_lifetime: &(),
34+
proto: ptr::from_ref(proto),
35+
}
36+
}
37+
2238
/// Assumes the contents of this buffer have been initialized.
2339
///
2440
/// # Safety
@@ -29,6 +45,7 @@ impl<'p, T> PciBuffer<'p, MaybeUninit<T>> {
2945
PciBuffer {
3046
base: old.base.cast(),
3147
pages: old.pages,
48+
proto_lifetime: old.proto_lifetime,
3249
proto: old.proto,
3350
}
3451
}
@@ -63,7 +80,8 @@ impl<'p, T> DerefMut for PciBuffer<'p, T> {
6380
impl<'p, T> Drop for PciBuffer<'p, T> {
6481
fn drop(&mut self) {
6582
let status = unsafe {
66-
(self.proto.free_buffer)(self.proto, self.pages.get(), self.base.as_ptr().cast())
83+
let proto = self.proto.as_ref().unwrap();
84+
(proto.free_buffer)(proto, self.pages.get(), self.base.as_ptr().cast())
6785
};
6886
match status {
6987
Status::SUCCESS => {

uefi/src/proto/pci/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ use core::cmp::Ordering;
77
use uefi_raw::protocol::pci::root_bridge::PciRootBridgeIoProtocolWidth;
88

99
pub mod buffer;
10-
pub mod mapped_region;
10+
pub mod region;
1111
pub mod root_bridge;
1212

1313
/// IO Address for PCI/register IO operations

uefi/src/proto/pci/mapped_region.rs renamed to uefi/src/proto/pci/region.rs

Lines changed: 36 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -21,13 +21,25 @@ pub struct PciMappedRegion<'p, 'r>
2121
where
2222
'p: 'r,
2323
{
24-
device_address: u64,
25-
length: usize,
24+
region: PciRegion,
2625
_lifetime_holder: &'r (),
2726
key: *const c_void,
2827
proto: &'p PciRootBridgeIoProtocol,
2928
}
3029

30+
/// Represents a region of memory in PCI root bridge memory space.
31+
/// CPU cannot use address in this struct to deference memory.
32+
/// This is effectively the same as rust's slice type.
33+
/// This type only exists to prevent users from accidentally dereferencing it.
34+
#[derive(Debug, Copy, Clone)]
35+
pub struct PciRegion {
36+
/// Starting address of the memory region
37+
pub device_address: u64,
38+
39+
/// Byte length of the memory region.
40+
pub length: usize
41+
}
42+
3143
impl<'p, 'r> PciMappedRegion<'p, 'r> where 'p: 'r {
3244
pub(crate) fn new<T>(
3345
device_address: u64,
@@ -44,8 +56,10 @@ impl<'p, 'r> PciMappedRegion<'p, 'r> where 'p: 'r {
4456
let end = device_address + length as u64;
4557
debug!("Mapped new region [0x{:X}..0x{:X}]", device_address, end);
4658
Self {
47-
device_address,
48-
length,
59+
region: PciRegion {
60+
device_address,
61+
length,
62+
},
4963
_lifetime_holder,
5064
key,
5165
proto,
@@ -58,8 +72,8 @@ impl<'p, 'r> PciMappedRegion<'p, 'r> where 'p: 'r {
5872
/// **Returned address cannot be used to reference memory from CPU!**
5973
/// **Do not cast it back to pointer or reference**
6074
#[must_use]
61-
pub const fn region(&self) -> (u64, usize) {
62-
(self.device_address, self.length)
75+
pub const fn region(&self) -> PciRegion {
76+
self.region
6377
}
6478
}
6579

@@ -68,8 +82,8 @@ impl<'p, 'r> Drop for PciMappedRegion<'p, 'r> {
6882
let status = unsafe { (self.proto.unmap)(self.proto, self.key) };
6983
match status {
7084
Status::SUCCESS => {
71-
let end = self.device_address + self.length as u64;
72-
debug!("Region [0x{:X}..0x{:X}] was unmapped", self.device_address, end);
85+
let end = self.region.device_address + self.region.length as u64;
86+
debug!("Region [0x{:X}..0x{:X}] was unmapped", self.region.device_address, end);
7387
}
7488
Status::INVALID_PARAMETER => {
7589
panic!("This region was not mapped using PciRootBridgeIo::map");
@@ -81,3 +95,17 @@ impl<'p, 'r> Drop for PciMappedRegion<'p, 'r> {
8195
}
8296
}
8397
}
98+
99+
impl PciRegion {
100+
/// Creates a new region of memory with different length.
101+
/// The new region must have shorter length to ensure
102+
/// it won't contain invalid memory address.
103+
#[must_use]
104+
pub fn with_length(self, new_length: usize) -> Self {
105+
assert!(new_length <= self.length);
106+
Self {
107+
device_address: self.device_address,
108+
length: new_length,
109+
}
110+
}
111+
}

uefi/src/proto/pci/root_bridge.rs

Lines changed: 49 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
use super::{PciIoAddress, PciIoUnit, encode_io_mode_and_unit};
66
use crate::StatusExt;
77
use crate::proto::pci::buffer::PciBuffer;
8-
use crate::proto::pci::mapped_region::PciMappedRegion;
8+
use crate::proto::pci::region::{PciMappedRegion, PciRegion};
99
use core::ffi::c_void;
1010
use core::mem::MaybeUninit;
1111
use core::num::NonZeroUsize;
@@ -14,10 +14,7 @@ use core::ptr::NonNull;
1414
use log::debug;
1515
use uefi_macros::unsafe_protocol;
1616
use uefi_raw::Status;
17-
use uefi_raw::protocol::pci::root_bridge::{
18-
PciRootBridgeIoAccess, PciRootBridgeIoProtocol, PciRootBridgeIoProtocolAttribute,
19-
PciRootBridgeIoProtocolOperation,
20-
};
17+
use uefi_raw::protocol::pci::root_bridge::{PciRootBridgeIoAccess, PciRootBridgeIoProtocol, PciRootBridgeIoProtocolAttribute, PciRootBridgeIoProtocolOperation, PciRootBridgeIoProtocolWidth};
2118
use uefi_raw::table::boot::{AllocateType, MemoryType, PAGE_SIZE};
2219

2320
/// Protocol that provides access to the PCI Root Bridge I/O protocol.
@@ -48,7 +45,7 @@ impl PciRootBridgeIo {
4845
/// Flush all PCI posted write transactions from a PCI host bridge to system memory.
4946
///
5047
/// # Errors
51-
/// - [`crate::Status::DEVICE_ERROR`] The PCI posted write transactions were not flushed from the PCI host bridge
48+
/// - [`Status::DEVICE_ERROR`] The PCI posted write transactions were not flushed from the PCI host bridge
5249
/// due to a hardware error.
5350
pub fn flush(&mut self) -> crate::Result<()> {
5451
unsafe { (self.0.flush)(&mut self.0).to_result() }
@@ -57,12 +54,12 @@ impl PciRootBridgeIo {
5754
/// Allocates pages suitable for communicating with PCI devices.
5855
///
5956
/// # Errors
60-
/// - [`crate::Status::INVALID_PARAMETER`] MemoryType is invalid.
61-
/// - [`crate::Status::UNSUPPORTED`] Attributes is unsupported. The only legal attribute bits are:
57+
/// - [`Status::INVALID_PARAMETER`] MemoryType is invalid.
58+
/// - [`Status::UNSUPPORTED`] Attributes is unsupported. The only legal attribute bits are:
6259
/// - [`PciRootBridgeIoProtocolAttribute::PCI_ATTRIBUTE_MEMORY_WRITE_COMBINE`]
6360
/// - [`PciRootBridgeIoProtocolAttribute::PCI_ATTRIBUTE_MEMORY_CACHED`]
6461
/// - [`PciRootBridgeIoProtocolAttribute::PCI_ATTRIBUTE_DUAL_ADDRESS_CYCLE`]
65-
/// - [`crate::Status::OUT_OF_RESOURCES`] The memory pages could not be allocated.
62+
/// - [`Status::OUT_OF_RESOURCES`] The memory pages could not be allocated.
6663
pub fn allocate_buffer<T>(
6764
&self,
6865
memory_type: MemoryType,
@@ -101,11 +98,7 @@ impl PciRootBridgeIo {
10198
Status::SUCCESS => {
10299
let base = NonNull::new(address as *mut MaybeUninit<T>).unwrap();
103100
debug!("Allocated {} pages at 0x{:X}", pages.get(), address);
104-
Ok(PciBuffer {
105-
base,
106-
pages,
107-
proto: &self.0,
108-
})
101+
Ok(PciBuffer::new(base, pages, &self.0))
109102
}
110103
error
111104
@ (Status::INVALID_PARAMETER | Status::UNSUPPORTED | Status::OUT_OF_RESOURCES) => {
@@ -155,10 +148,37 @@ impl PciRootBridgeIo {
155148
}
156149
}
157150

151+
/// Copies a region in PCI root bridge memory space onto the other.
152+
/// Two regions must have same length. Functionally, this is the same as
153+
/// `<[T]>::copy_from_slice` which is effectively memcpy.
154+
/// And the same safety requirements as the above method apply.
155+
pub fn copy(
156+
&mut self,
157+
width: PciRootBridgeIoProtocolWidth,
158+
destination: PciRegion,
159+
source: PciRegion,
160+
) -> crate::Result<()> {
161+
assert_eq!(destination.length, source.length);
162+
163+
let status = unsafe {
164+
(self.0.copy_mem)(
165+
&mut self.0,
166+
width,
167+
destination.device_address,
168+
source.device_address,
169+
destination.length,
170+
)
171+
};
172+
173+
match status {
174+
Status::SUCCESS => Ok(()),
175+
error => Err(error.into()),
176+
}
177+
}
178+
158179
// TODO: poll I/O
159180
// TODO: mem I/O access
160181
// TODO: io I/O access
161-
// TODO: copy memory
162182
// TODO: get/set attributes
163183
// TODO: configuration / resource settings
164184
}
@@ -180,8 +200,8 @@ impl PciIoAccessPci<'_> {
180200
/// - The read value of type `U`.
181201
///
182202
/// # Errors
183-
/// - [`crate::Status::INVALID_PARAMETER`] The requested width is invalid for this PCI root bridge.
184-
/// - [`crate::Status::OUT_OF_RESOURCES`] The read request could not be completed due to a lack of resources.
203+
/// - [`Status::INVALID_PARAMETER`] The requested width is invalid for this PCI root bridge.
204+
/// - [`Status::OUT_OF_RESOURCES`] The read request could not be completed due to a lack of resources.
185205
pub fn read_one<U: PciIoUnit>(&self, addr: PciIoAddress) -> crate::Result<U> {
186206
let width_mode = encode_io_mode_and_unit::<U>(super::PciIoMode::Normal);
187207
let mut result = U::default();
@@ -204,8 +224,8 @@ impl PciIoAccessPci<'_> {
204224
/// - `data` - The value to write.
205225
///
206226
/// # Errors
207-
/// - [`crate::Status::INVALID_PARAMETER`] The requested width is invalid for this PCI root bridge.
208-
/// - [`crate::Status::OUT_OF_RESOURCES`] The write request could not be completed due to a lack of resources.
227+
/// - [`Status::INVALID_PARAMETER`] The requested width is invalid for this PCI root bridge.
228+
/// - [`Status::OUT_OF_RESOURCES`] The write request could not be completed due to a lack of resources.
209229
pub fn write_one<U: PciIoUnit>(&self, addr: PciIoAddress, data: U) -> crate::Result<()> {
210230
let width_mode = encode_io_mode_and_unit::<U>(super::PciIoMode::Normal);
211231
unsafe {
@@ -227,8 +247,8 @@ impl PciIoAccessPci<'_> {
227247
/// - `data` - A mutable slice to store the read values.
228248
///
229249
/// # Errors
230-
/// - [`crate::Status::INVALID_PARAMETER`] The requested width is invalid for this PCI root bridge.
231-
/// - [`crate::Status::OUT_OF_RESOURCES`] The read operation could not be completed due to a lack of resources.
250+
/// - [`Status::INVALID_PARAMETER`] The requested width is invalid for this PCI root bridge.
251+
/// - [`Status::OUT_OF_RESOURCES`] The read operation could not be completed due to a lack of resources.
232252
pub fn read<U: PciIoUnit>(&self, addr: PciIoAddress, data: &mut [U]) -> crate::Result<()> {
233253
let width_mode = encode_io_mode_and_unit::<U>(super::PciIoMode::Normal);
234254
unsafe {
@@ -250,8 +270,8 @@ impl PciIoAccessPci<'_> {
250270
/// - `data` - A slice containing the values to write.
251271
///
252272
/// # Errors
253-
/// - [`crate::Status::INVALID_PARAMETER`] The requested width is invalid for this PCI root bridge.
254-
/// - [`crate::Status::OUT_OF_RESOURCES`] The write operation could not be completed due to a lack of resources.
273+
/// - [`Status::INVALID_PARAMETER`] The requested width is invalid for this PCI root bridge.
274+
/// - [`Status::OUT_OF_RESOURCES`] The write operation could not be completed due to a lack of resources.
255275
pub fn write<U: PciIoUnit>(&self, addr: PciIoAddress, data: &[U]) -> crate::Result<()> {
256276
let width_mode = encode_io_mode_and_unit::<U>(super::PciIoMode::Normal);
257277
unsafe {
@@ -274,8 +294,8 @@ impl PciIoAccessPci<'_> {
274294
/// - `data` - The value to fill the address range with.
275295
///
276296
/// # Errors
277-
/// - [`crate::Status::INVALID_PARAMETER`] The requested width is invalid for this PCI root bridge.
278-
/// - [`crate::Status::OUT_OF_RESOURCES`] The operation could not be completed due to a lack of resources.
297+
/// - [`Status::INVALID_PARAMETER`] The requested width is invalid for this PCI root bridge.
298+
/// - [`Status::OUT_OF_RESOURCES`] The operation could not be completed due to a lack of resources.
279299
pub fn fill_write<U: PciIoUnit>(
280300
&self,
281301
addr: PciIoAddress,
@@ -306,8 +326,8 @@ impl PciIoAccessPci<'_> {
306326
/// The resulting `data` buffer will contain the elements returned by reading the same address multiple times sequentially.
307327
///
308328
/// # Errors
309-
/// - [`crate::Status::INVALID_PARAMETER`] The requested width is invalid for this PCI root bridge.
310-
/// - [`crate::Status::OUT_OF_RESOURCES`] The read operation could not be completed due to a lack of resources.
329+
/// - [`Status::INVALID_PARAMETER`] The requested width is invalid for this PCI root bridge.
330+
/// - [`Status::OUT_OF_RESOURCES`] The read operation could not be completed due to a lack of resources.
311331
pub fn fifo_read<U: PciIoUnit>(&self, addr: PciIoAddress, data: &mut [U]) -> crate::Result<()> {
312332
let width_mode = encode_io_mode_and_unit::<U>(super::PciIoMode::Fifo);
313333
unsafe {
@@ -333,8 +353,8 @@ impl PciIoAccessPci<'_> {
333353
/// (starting at `addr` and ending at `addr + size_of::<U>()`) sequentially.
334354
///
335355
/// # Errors
336-
/// - [`crate::Status::INVALID_PARAMETER`] The requested width is invalid for this PCI root bridge.
337-
/// - [`crate::Status::OUT_OF_RESOURCES`] The write operation could not be completed due to a lack of resources.
356+
/// - [`Status::INVALID_PARAMETER`] The requested width is invalid for this PCI root bridge.
357+
/// - [`Status::OUT_OF_RESOURCES`] The write operation could not be completed due to a lack of resources.
338358
pub fn fifo_write<U: PciIoUnit>(&self, addr: PciIoAddress, data: &[U]) -> crate::Result<()> {
339359
let width_mode = encode_io_mode_and_unit::<U>(super::PciIoMode::Fifo);
340360
unsafe {

0 commit comments

Comments
 (0)