-
-
Notifications
You must be signed in to change notification settings - Fork 188
Expand file tree
/
Copy pathbuffer.rs
More file actions
104 lines (94 loc) · 3.12 KB
/
buffer.rs
File metadata and controls
104 lines (94 loc) · 3.12 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
// SPDX-License-Identifier: MIT OR Apache-2.0
//! Defines wrapper for pages allocated by PCI Root Bridge protocol.
use crate::StatusExt;
use core::cell::UnsafeCell;
use core::fmt::Debug;
use core::mem::{ManuallyDrop, MaybeUninit};
use core::num::NonZeroUsize;
use core::ptr::NonNull;
use log::{error, trace};
use uefi_raw::Status;
use uefi_raw::protocol::pci::root_bridge::PciRootBridgeIoProtocol;
use uefi_raw::table::boot::PAGE_SIZE;
/// Smart pointer for wrapping owned pages allocated by PCI Root Bridge protocol.
/// Value stored in this buffer maybe modified by a PCI device.
///
/// # Lifetime
/// `'p` is the lifetime for Protocol.
///
/// # Invariant
/// * Value stored in this memory cannot have a larger alignment requirement
/// than page size, which is 4096.
/// * Value stored in this memory cannot be larger than the buffer's size, which is 4096 * `pages`
#[derive(Debug)]
pub struct PciBuffer<'p, T> {
pub(super) base: NonNull<UnsafeCell<T>>,
pub(super) pages: NonZeroUsize,
pub(super) proto: &'p PciRootBridgeIoProtocol,
}
impl<'p, T> PciBuffer<'p, MaybeUninit<T>> {
/// Assumes the contents of this buffer have been initialized.
///
/// # Safety
/// Callers of this function must guarantee that the value stored is valid.
#[must_use]
pub const unsafe fn assume_init(self) -> PciBuffer<'p, T> {
let initialized = PciBuffer {
base: self.base.cast(),
pages: self.pages,
proto: self.proto,
};
let _ = ManuallyDrop::new(self);
initialized
}
}
impl<'p, T> PciBuffer<'p, T> {
/// Returns the base pointer of this buffer
#[must_use]
pub const fn base_ptr(&self) -> *mut T {
self.base.as_ptr().cast()
}
/// Returns the number of pages this buffer uses
#[must_use]
pub const fn pages(&self) -> NonZeroUsize {
self.pages
}
/// Returns the size of this buffer in bytes
#[must_use]
pub const fn bytes_size(&self) -> NonZeroUsize {
self.pages
.checked_mul(NonZeroUsize::new(PAGE_SIZE).unwrap())
.expect("Memory size Overflow")
}
/// Frees underlying memory of this buffer.
/// It is recommended to use this over drop implementation.
pub fn free(self) -> crate::Result {
self.free_inner()
}
fn free_inner(&self) -> crate::Result {
unsafe { (self.proto.free_buffer)(self.proto, self.pages.get(), self.base.as_ptr().cast()) }
.to_result_with_val(|| {
trace!(
"Freed {} pages at 0x{:X}",
self.pages,
self.base.as_ptr().addr()
)
})
}
}
impl<T> Drop for PciBuffer<'_, T> {
fn drop(&mut self) {
let Err(status) = self.free_inner() else {
return;
};
match status.status() {
Status::SUCCESS => {}
Status::INVALID_PARAMETER => {
error!("PciBuffer was not created through valid protocol usage!")
}
etc => {
error!("Unexpected error occurred when freeing memory: {:?}", etc);
}
}
}
}