Skip to content

Commit dab0752

Browse files
Merge pull request #1674 from seijikun/mr-safe-pciroot
uefi: Add (partial) safe protocol implementation for PCI_ROOT_BRIDGE_IO_PROTOCOL
2 parents d7cec59 + 080e87b commit dab0752

File tree

7 files changed

+433
-0
lines changed

7 files changed

+433
-0
lines changed

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ pub fn test() {
2020
loaded_image::test();
2121
media::test();
2222
network::test();
23+
pci::test();
2324
pi::test();
2425
rng::test();
2526
shell_params::test();
@@ -84,6 +85,7 @@ mod media;
8485
mod misc;
8586
mod network;
8687
mod nvme;
88+
mod pci;
8789
mod pi;
8890
mod rng;
8991
mod scsi;

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

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
// SPDX-License-Identifier: MIT OR Apache-2.0
2+
3+
pub mod root_bridge;
4+
5+
pub fn test() {
6+
root_bridge::test();
7+
}
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
// SPDX-License-Identifier: MIT OR Apache-2.0
2+
3+
use core::mem;
4+
use uefi::Handle;
5+
use uefi::boot::{OpenProtocolAttributes, OpenProtocolParams, ScopedProtocol, image_handle};
6+
use uefi::proto::ProtocolPointer;
7+
use uefi::proto::pci::PciIoAddress;
8+
use uefi::proto::pci::root_bridge::PciRootBridgeIo;
9+
10+
const RED_HAT_PCI_VENDOR_ID: u16 = 0x1AF4;
11+
const MASS_STORAGE_CTRL_CLASS_CODE: u8 = 0x1;
12+
const SATA_CTRL_SUBCLASS_CODE: u8 = 0x6;
13+
14+
const REG_SIZE: u8 = mem::size_of::<u32>() as u8;
15+
16+
pub fn test() {
17+
let pci_handles = uefi::boot::find_handles::<PciRootBridgeIo>().unwrap();
18+
19+
let mut red_hat_dev_cnt = 0;
20+
let mut mass_storage_ctrl_cnt = 0;
21+
let mut sata_ctrl_cnt = 0;
22+
23+
for pci_handle in pci_handles {
24+
let mut pci_proto = get_open_protocol::<PciRootBridgeIo>(pci_handle);
25+
26+
for bus in 0..=255 {
27+
for dev in 0..32 {
28+
for fun in 0..8 {
29+
let addr = PciIoAddress::new(bus, dev, fun);
30+
let Ok(reg0) = pci_proto.pci().read_one::<u32>(addr.with_register(0)) else {
31+
continue;
32+
};
33+
if reg0 == 0xFFFFFFFF {
34+
continue; // not a valid device
35+
}
36+
let reg1 = pci_proto
37+
.pci()
38+
.read_one::<u32>(addr.with_register(2 * REG_SIZE))
39+
.unwrap();
40+
41+
let vendor_id = (reg0 & 0xFFFF) as u16;
42+
let device_id = (reg0 >> 16) as u16;
43+
if vendor_id == RED_HAT_PCI_VENDOR_ID {
44+
red_hat_dev_cnt += 1;
45+
}
46+
47+
let class_code = (reg1 >> 24) as u8;
48+
let subclass_code = ((reg1 >> 16) & 0xFF) as u8;
49+
if class_code == MASS_STORAGE_CTRL_CLASS_CODE {
50+
mass_storage_ctrl_cnt += 1;
51+
52+
if subclass_code == SATA_CTRL_SUBCLASS_CODE {
53+
sata_ctrl_cnt += 1;
54+
}
55+
}
56+
57+
log::info!(
58+
"PCI Device: [{}, {}, {}]: vendor={:04X}, device={:04X}, class={:02X}, subclass={:02X}",
59+
bus,
60+
dev,
61+
fun,
62+
vendor_id,
63+
device_id,
64+
class_code,
65+
subclass_code
66+
);
67+
}
68+
}
69+
}
70+
}
71+
72+
assert!(red_hat_dev_cnt > 0);
73+
assert!(mass_storage_ctrl_cnt > 0);
74+
assert!(sata_ctrl_cnt > 0);
75+
}
76+
77+
fn get_open_protocol<P: ProtocolPointer + ?Sized>(handle: Handle) -> ScopedProtocol<P> {
78+
let open_opts = OpenProtocolParams {
79+
handle,
80+
agent: image_handle(),
81+
controller: None,
82+
};
83+
let open_attrs = OpenProtocolAttributes::GetProtocol;
84+
unsafe { uefi::boot::open_protocol(open_opts, open_attrs).unwrap() }
85+
}

uefi/CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
## Added
44
- Added `ConfigTableEntry::MEMORY_ATTRIBUTES_GUID` and `ConfigTableEntry::IMAGE_SECURITY_DATABASE_GUID`.
55
- Added `proto::usb::io::UsbIo`.
6+
- Added `proto::pci::PciRootBridgeIo`.
67

78
## Changed
89
- **Breaking:** `boot::stall` now take `core::time::Duration` instead of `usize`.

uefi/src/proto/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ pub mod misc;
2222
pub mod network;
2323
#[cfg(feature = "alloc")]
2424
pub mod nvme;
25+
pub mod pci;
2526
pub mod pi;
2627
pub mod rng;
2728
#[cfg(feature = "alloc")]

uefi/src/proto/pci/mod.rs

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
// SPDX-License-Identifier: MIT OR Apache-2.0
2+
3+
//! PCI Bus specific protocols.
4+
5+
use uefi_raw::protocol::pci::root_bridge::PciRootBridgeIoProtocolWidth;
6+
7+
pub mod root_bridge;
8+
9+
/// IO Address for PCI/register IO operations
10+
#[repr(C, packed)]
11+
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
12+
pub struct PciIoAddress {
13+
/// Register number within the PCI device.
14+
pub reg: u8,
15+
/// Function number within the PCI device.
16+
pub fun: u8,
17+
/// Device number within the PCI bus.
18+
pub dev: u8,
19+
/// Bus number in the PCI hierarchy.
20+
pub bus: u8,
21+
/// Extended register number within the PCI device.
22+
pub ext_reg: u32,
23+
}
24+
25+
impl PciIoAddress {
26+
/// Create address pointing to the device identified by `bus`, `dev` and `fun` ids.
27+
#[must_use]
28+
pub const fn new(bus: u8, dev: u8, fun: u8) -> Self {
29+
Self {
30+
bus,
31+
dev,
32+
fun,
33+
reg: 0,
34+
ext_reg: 0,
35+
}
36+
}
37+
38+
/// Configure the **byte**-offset of the register to access.
39+
#[must_use]
40+
pub const fn with_register(&self, reg: u8) -> Self {
41+
let mut addr = *self;
42+
addr.reg = reg;
43+
addr.ext_reg = 0;
44+
addr
45+
}
46+
47+
/// Configure the **byte**-offset of the extended register to access.
48+
#[must_use]
49+
pub const fn with_extended_register(&self, ext_reg: u32) -> Self {
50+
let mut addr = *self;
51+
addr.reg = 0;
52+
addr.ext_reg = ext_reg;
53+
addr
54+
}
55+
}
56+
57+
impl From<PciIoAddress> for u64 {
58+
fn from(value: PciIoAddress) -> Self {
59+
unsafe { core::mem::transmute(value) }
60+
}
61+
}
62+
63+
/// Trait implemented by all data types that can natively be read from a PCI device.
64+
/// Note: Not all of them have to actually be supported by the hardware at hand.
65+
pub trait PciIoUnit: Sized + Default {}
66+
impl PciIoUnit for u8 {}
67+
impl PciIoUnit for u16 {}
68+
impl PciIoUnit for u32 {}
69+
impl PciIoUnit for u64 {}
70+
71+
#[allow(dead_code)]
72+
enum PciIoMode {
73+
Normal,
74+
Fifo,
75+
Fill,
76+
}
77+
78+
fn encode_io_mode_and_unit<U: PciIoUnit>(mode: PciIoMode) -> PciRootBridgeIoProtocolWidth {
79+
match (mode, core::mem::size_of::<U>()) {
80+
(PciIoMode::Normal, 1) => PciRootBridgeIoProtocolWidth::UINT8,
81+
(PciIoMode::Normal, 2) => PciRootBridgeIoProtocolWidth::UINT16,
82+
(PciIoMode::Normal, 4) => PciRootBridgeIoProtocolWidth::UINT32,
83+
(PciIoMode::Normal, 8) => PciRootBridgeIoProtocolWidth::UINT64,
84+
85+
(PciIoMode::Fifo, 1) => PciRootBridgeIoProtocolWidth::FIFO_UINT8,
86+
(PciIoMode::Fifo, 2) => PciRootBridgeIoProtocolWidth::FIFO_UINT16,
87+
(PciIoMode::Fifo, 4) => PciRootBridgeIoProtocolWidth::FIFO_UINT32,
88+
(PciIoMode::Fifo, 8) => PciRootBridgeIoProtocolWidth::FIFO_UINT64,
89+
90+
(PciIoMode::Fill, 1) => PciRootBridgeIoProtocolWidth::FILL_UINT8,
91+
(PciIoMode::Fill, 2) => PciRootBridgeIoProtocolWidth::FILL_UINT16,
92+
(PciIoMode::Fill, 4) => PciRootBridgeIoProtocolWidth::FILL_UINT32,
93+
(PciIoMode::Fill, 8) => PciRootBridgeIoProtocolWidth::FILL_UINT64,
94+
95+
_ => unreachable!("Illegal PCI IO-Mode / Unit combination"),
96+
}
97+
}

0 commit comments

Comments
 (0)