Skip to content

Commit 800545a

Browse files
committed
uefi: Add wrapper for pages allocated by PCI protocol
1 parent 0704ae4 commit 800545a

File tree

2 files changed

+98
-1
lines changed

2 files changed

+98
-1
lines changed

uefi/src/proto/pci/mod.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ use core::cmp::Ordering;
66

77
use uefi_raw::protocol::pci::root_bridge::PciRootBridgeIoProtocolWidth;
88

9+
pub mod page;
910
pub mod root_bridge;
1011

1112
/// IO Address for PCI/register IO operations
@@ -106,7 +107,7 @@ enum PciIoMode {
106107
}
107108

108109
fn encode_io_mode_and_unit<U: PciIoUnit>(mode: PciIoMode) -> PciRootBridgeIoProtocolWidth {
109-
match (mode, core::mem::size_of::<U>()) {
110+
match (mode, size_of::<U>()) {
110111
(PciIoMode::Normal, 1) => PciRootBridgeIoProtocolWidth::UINT8,
111112
(PciIoMode::Normal, 2) => PciRootBridgeIoProtocolWidth::UINT16,
112113
(PciIoMode::Normal, 4) => PciRootBridgeIoProtocolWidth::UINT32,

uefi/src/proto/pci/page.rs

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
// SPDX-License-Identifier: MIT OR Apache-2.0
2+
3+
//! Defines wrapper for pages allocated by PCI Root Bridge protocol.
4+
use core::fmt::Debug;
5+
use core::mem::{ManuallyDrop, MaybeUninit};
6+
use core::num::NonZeroUsize;
7+
use core::ops::{Deref, DerefMut};
8+
use core::ptr::NonNull;
9+
use log::trace;
10+
use uefi_raw::Status;
11+
use uefi_raw::protocol::pci::root_bridge::PciRootBridgeIoProtocol;
12+
13+
/// Smart pointer for wrapping owned pages allocated by PCI Root Bridge protocol.
14+
///
15+
/// # Lifetime
16+
/// `'p` is the lifetime for Protocol.
17+
#[derive(Debug)]
18+
pub struct PciPage<'p, T> {
19+
base: NonNull<T>,
20+
pages: NonZeroUsize,
21+
proto: &'p PciRootBridgeIoProtocol,
22+
}
23+
24+
impl<'p, T> PciPage<'p, MaybeUninit<T>> {
25+
/// Creates wrapper for pages allocated by PCI Root Bridge protocol.
26+
#[must_use]
27+
pub const fn new(
28+
base: NonNull<MaybeUninit<T>>,
29+
pages: NonZeroUsize,
30+
proto: &'p PciRootBridgeIoProtocol,
31+
) -> Self {
32+
Self { base, pages, proto }
33+
}
34+
35+
/// Assumes the contents of this buffer have been initialized.
36+
///
37+
/// # Safety
38+
/// Callers of this function must guarantee that the value stored is valid.
39+
#[must_use]
40+
pub const unsafe fn assume_init(self) -> PciPage<'p, T> {
41+
let initialized = PciPage {
42+
base: self.base.cast(),
43+
pages: self.pages,
44+
proto: self.proto,
45+
};
46+
let _ = ManuallyDrop::new(self);
47+
initialized
48+
}
49+
}
50+
51+
impl<T> AsRef<T> for PciPage<'_, T> {
52+
fn as_ref(&self) -> &T {
53+
unsafe { self.base.as_ref() }
54+
}
55+
}
56+
57+
impl<T> AsMut<T> for PciPage<'_, T> {
58+
fn as_mut(&mut self) -> &mut T {
59+
unsafe { self.base.as_mut() }
60+
}
61+
}
62+
63+
impl<T> Deref for PciPage<'_, T> {
64+
type Target = T;
65+
66+
fn deref(&self) -> &Self::Target {
67+
self.as_ref()
68+
}
69+
}
70+
71+
impl<T> DerefMut for PciPage<'_, T> {
72+
fn deref_mut(&mut self) -> &mut Self::Target {
73+
self.as_mut()
74+
}
75+
}
76+
77+
impl<T> Drop for PciPage<'_, T> {
78+
fn drop(&mut self) {
79+
let status = unsafe {
80+
(self.proto.free_buffer)(self.proto, self.pages.get(), self.base.as_ptr().cast())
81+
};
82+
match status {
83+
Status::SUCCESS => {
84+
trace!(
85+
"Freed {} pages at 0x{:X}",
86+
self.pages.get(),
87+
self.base.as_ptr().addr()
88+
);
89+
}
90+
Status::INVALID_PARAMETER => {
91+
panic!("PciBuffer was not created through valid protocol usage!")
92+
}
93+
_ => unreachable!(),
94+
}
95+
}
96+
}

0 commit comments

Comments
 (0)