Skip to content

Commit c4a1231

Browse files
committed
uefi: Implement PciRootBridgeIo::allocate_buffer
1 parent d5e07ab commit c4a1231

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;
@@ -67,6 +69,27 @@ pub fn test() {
6769
assert!(sata_ctrl_cnt > 0);
6870
}
6971

72+
pub fn test_buffer() {
73+
let pci_handles = uefi::boot::find_handles::<PciRootBridgeIo>().unwrap();
74+
75+
for pci_handle in pci_handles {
76+
let pci_proto = get_open_protocol::<PciRootBridgeIo>(pci_handle);
77+
78+
let mut buffer = pci_proto
79+
.allocate_buffer::<[u8; 4096]>(
80+
MemoryType::BOOT_SERVICES_DATA,
81+
None,
82+
PciRootBridgeIoProtocolAttribute::PCI_ATTRIBUTE_MEMORY_WRITE_COMBINE,
83+
)
84+
.unwrap();
85+
let buffer = unsafe {
86+
buffer.assume_init_mut().fill(0);
87+
buffer.assume_init()
88+
};
89+
assert_eq!(buffer.as_ptr().addr() % 4096, 0);
90+
}
91+
}
92+
7093
fn get_open_protocol<P: ProtocolPointer + ?Sized>(handle: Handle) -> ScopedProtocol<P> {
7194
let open_opts = OpenProtocolParams {
7295
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
@@ -6,6 +6,7 @@ use core::cmp::Ordering;
66

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

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

1112
/// IO Address for PCI/register IO operations

0 commit comments

Comments
 (0)