Skip to content

Commit f25bc20

Browse files
committed
uefi: Implement PciRootBridgeIo::allocate_buffer
1 parent 9602a88 commit f25bc20

File tree

5 files changed

+132
-2
lines changed

5 files changed

+132
-2
lines changed

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

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
use crate::table::boot::{AllocateType, MemoryType};
44
use crate::{Handle, PhysicalAddress, Status};
5+
use bitflags::bitflags;
56
use core::ffi::c_void;
67
use uguid::{Guid, guid};
78

@@ -37,6 +38,28 @@ newtype_enum! {
3738
}
3839
}
3940

41+
bitflags! {
42+
/// Describes PCI I/O Protocol Attribute bitflags specified in UEFI specification.
43+
///. https://uefi.org/specs/UEFI/2.10_A/14_Protocols_PCI_Bus_Support.html
44+
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
45+
pub struct PciRootBridgeIoProtocolAttribute: u64 {
46+
const PCI_ATTRIBUTE_ISA_MOTHERBOARD_IO = 0x0001;
47+
const PCI_ATTRIBUTE_ISA_IO = 0x0002;
48+
const PCI_ATTRIBUTE_VGA_PALETTE_IO = 0x0004;
49+
const PCI_ATTRIBUTE_VGA_MEMORY = 0x0008;
50+
const PCI_ATTRIBUTE_VGA_IO = 0x0010;
51+
const PCI_ATTRIBUTE_IDE_PRIMARY_IO = 0x0020;
52+
const PCI_ATTRIBUTE_IDE_SECONDARY_IO = 0x0040;
53+
const PCI_ATTRIBUTE_MEMORY_WRITE_COMBINE = 0x0080;
54+
const PCI_ATTRIBUTE_MEMORY_CACHED = 0x0800;
55+
const PCI_ATTRIBUTE_MEMORY_DISABLE = 0x1000;
56+
const PCI_ATTRIBUTE_DUAL_ADDRESS_CYCLE = 0x8000;
57+
const PCI_ATTRIBUTE_ISA_IO_16 = 0x10000;
58+
const PCI_ATTRIBUTE_VGA_PALETTE_IO_16 = 0x20000;
59+
const PCI_ATTRIBUTE_VGA_IO_16 = 0x40000;
60+
}
61+
}
62+
4063
#[derive(Debug)]
4164
#[repr(C)]
4265
pub struct PciRootBridgeIoAccess {

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,5 +3,6 @@
33
pub mod root_bridge;
44

55
pub fn test() {
6-
root_bridge::test();
6+
root_bridge::test_io();
7+
root_bridge::test_buffer();
78
}

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

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,16 @@ use uefi::boot::{OpenProtocolAttributes, OpenProtocolParams, ScopedProtocol, ima
66
use uefi::proto::ProtocolPointer;
77
use uefi::proto::pci::PciIoAddress;
88
use uefi::proto::pci::root_bridge::PciRootBridgeIo;
9+
use uefi_raw::protocol::pci::root_bridge::PciRootBridgeIoProtocolAttribute;
10+
use uefi_raw::table::boot::MemoryType;
911

1012
const RED_HAT_PCI_VENDOR_ID: u16 = 0x1AF4;
1113
const MASS_STORAGE_CTRL_CLASS_CODE: u8 = 0x1;
1214
const SATA_CTRL_SUBCLASS_CODE: u8 = 0x6;
1315

1416
const REG_SIZE: u8 = mem::size_of::<u32>() as u8;
1517

16-
pub fn test() {
18+
pub fn test_io() {
1719
let pci_handles = uefi::boot::find_handles::<PciRootBridgeIo>().unwrap();
1820

1921
let mut red_hat_dev_cnt = 0;
@@ -74,6 +76,27 @@ pub fn test() {
7476
assert!(sata_ctrl_cnt > 0);
7577
}
7678

79+
pub fn test_buffer() {
80+
let pci_handles = uefi::boot::find_handles::<PciRootBridgeIo>().unwrap();
81+
82+
for pci_handle in pci_handles {
83+
let pci_proto = get_open_protocol::<PciRootBridgeIo>(pci_handle);
84+
85+
let mut buffer = pci_proto
86+
.allocate_buffer::<[u8; 4096]>(
87+
MemoryType::BOOT_SERVICES_DATA,
88+
None,
89+
PciRootBridgeIoProtocolAttribute::PCI_ATTRIBUTE_MEMORY_WRITE_COMBINE,
90+
)
91+
.unwrap();
92+
let buffer = unsafe {
93+
buffer.assume_init_mut().fill(0);
94+
buffer.assume_init()
95+
};
96+
assert_eq!(buffer.as_ptr().addr() % 4096, 0);
97+
}
98+
}
99+
77100
fn get_open_protocol<P: ProtocolPointer + ?Sized>(handle: Handle) -> ScopedProtocol<P> {
78101
let open_opts = OpenProtocolParams {
79102
handle,

uefi/src/proto/pci/buffer.rs

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

uefi/src/proto/pci/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
55
use uefi_raw::protocol::pci::root_bridge::PciRootBridgeIoProtocolWidth;
66

7+
pub mod buffer;
78
pub mod root_bridge;
89

910
/// IO Address for PCI/register IO operations

0 commit comments

Comments
 (0)