Skip to content

Commit ba16acf

Browse files
committed
uefi: Add wrapper for the mapped region of memory
1 parent 800545a commit ba16acf

File tree

2 files changed

+114
-0
lines changed

2 files changed

+114
-0
lines changed

uefi/src/proto/pci/mod.rs

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

99
pub mod page;
10+
pub mod region;
1011
pub mod root_bridge;
1112

1213
/// IO Address for PCI/register IO operations

uefi/src/proto/pci/region.rs

Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
// SPDX-License-Identifier: MIT OR Apache-2.0
2+
3+
//! Defines wrapper for a region mapped by PCI Root Bridge I/O protocol.
4+
use core::ffi::c_void;
5+
use core::fmt::Debug;
6+
use core::marker::PhantomData;
7+
use log::trace;
8+
use uefi_raw::Status;
9+
use uefi_raw::protocol::pci::root_bridge::PciRootBridgeIoProtocol;
10+
11+
/// Represents a region of memory mapped by PCI Root Bridge I/O protocol.
12+
/// The region will be unmapped automatically when it is dropped.
13+
///
14+
/// # Lifetime
15+
/// `'p` is the lifetime for Protocol.
16+
/// `'r` is the lifetime for Mapped Region.
17+
/// Protocol must outlive the mapped region
18+
/// as unmap function can only be accessed through the protocol.
19+
#[derive(Debug)]
20+
pub struct PciMappedRegion<'p, 'r>
21+
where
22+
'p: 'r,
23+
{
24+
region: PciRegion,
25+
_lifetime_holder: PhantomData<&'r ()>,
26+
key: *const c_void,
27+
proto: &'p PciRootBridgeIoProtocol,
28+
}
29+
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+
43+
impl<'p, 'r> PciMappedRegion<'p, 'r>
44+
where
45+
'p: 'r,
46+
{
47+
#[allow(dead_code)] // TODO Implement Map function
48+
pub(crate) fn new<T: ?Sized>(
49+
device_address: u64,
50+
length: usize,
51+
key: *const c_void,
52+
_to_map: &'r T,
53+
proto: &'p PciRootBridgeIoProtocol,
54+
) -> Self {
55+
let end = device_address + length as u64;
56+
trace!("Mapped new region [0x{device_address:X}..0x{end:X}]");
57+
Self {
58+
region: PciRegion {
59+
device_address,
60+
length,
61+
},
62+
_lifetime_holder: PhantomData,
63+
key,
64+
proto,
65+
}
66+
}
67+
68+
/// Returns mapped address and length of a region.
69+
///
70+
/// # Warning
71+
/// **Returned address cannot be used to reference memory from CPU!**
72+
/// **Do not cast it back to pointer or reference**
73+
#[must_use]
74+
pub const fn region(&self) -> PciRegion {
75+
self.region
76+
}
77+
}
78+
79+
impl Drop for PciMappedRegion<'_, '_> {
80+
fn drop(&mut self) {
81+
let status = unsafe { (self.proto.unmap)(self.proto, self.key) };
82+
match status {
83+
Status::SUCCESS => {
84+
let end = self.region.device_address + self.region.length as u64;
85+
trace!(
86+
"Region [0x{:X}..0x{:X}] was unmapped",
87+
self.region.device_address, end
88+
);
89+
}
90+
Status::INVALID_PARAMETER => {
91+
panic!("This region was not mapped using PciRootBridgeIo::map");
92+
}
93+
Status::DEVICE_ERROR => {
94+
panic!("The data was not committed to the target system memory.");
95+
}
96+
_ => unreachable!(),
97+
}
98+
}
99+
}
100+
101+
impl PciRegion {
102+
/// Creates a new region of memory with different length.
103+
/// The new region must have shorter length to ensure
104+
/// it won't contain invalid memory address.
105+
#[must_use]
106+
pub fn with_length(self, new_length: usize) -> Self {
107+
assert!(new_length <= self.length);
108+
Self {
109+
device_address: self.device_address,
110+
length: new_length,
111+
}
112+
}
113+
}

0 commit comments

Comments
 (0)