Skip to content

Implement rest of Pci Root Bridge Io protocol #1705

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 10 commits into
base: main
Choose a base branch
from
7 changes: 7 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ bitflags = "2.0.0"
log = { version = "0.4.5", default-features = false }
ptr_meta = { version = "0.3.0", default-features = false, features = ["derive"] }
uguid = "2.2.1"
static_assertions = "1.1.0"

[patch.crates-io]
uefi = { path = "uefi" }
Expand Down
1 change: 1 addition & 0 deletions uefi-raw/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ rust-version = "1.85.1"
[dependencies]
bitflags.workspace = true
uguid.workspace = true
static_assertions.workspace = true
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not a fan of adding a new dependency at this point. For consistency with the code base, please add a unit test instead. Something like

#[test]
fn test_abi() {
    assert_eq(size_of<...>, 0x123);
}

etc


[package.metadata.docs.rs]
rustdoc-args = ["--cfg", "docsrs"]
1 change: 1 addition & 0 deletions uefi-raw/src/protocol/pci/mod.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
// SPDX-License-Identifier: MIT OR Apache-2.0

pub mod resource;
pub mod root_bridge;
108 changes: 108 additions & 0 deletions uefi-raw/src/protocol/pci/resource.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
use bitflags::bitflags;
use static_assertions::assert_eq_size;

/// Descriptor for current PCI root bridge's configuration space.
/// Specification:
/// https://uefi.org/htmlspecs/ACPI_Spec_6_4_html/06_Device_Configuration/Device_Configuration.html#qword-address-space-descriptor
#[repr(C, packed)]
#[derive(Debug)]
pub struct QWordAddressSpaceDescriptor {
pub tag: u8,
pub descriptor_length: u16,
pub resource_type: ResourceType,
pub flags: GeneralFlags,
pub type_flags: u8,
pub address_granularity: u64,
pub range_min: u64,
pub range_max: u64, // inclusive
pub translation_offset: u64,
pub address_length: u64,
}
assert_eq_size!(QWordAddressSpaceDescriptor, [u8; 0x2E]);

newtype_enum! {
/// Indicates which type of resource this descriptor describes.
pub enum ResourceType: u8 => {
/// This resource describes range of memory.
MEMORY = 0,

/// This resource describes range of I/O ports.
IO = 1,

/// This resource describes range of Bus numbers.
BUS = 2,
}
}

bitflags! {
#[repr(transparent)]
#[derive(Debug, Copy, Clone)]
pub struct GeneralFlags: u8 {
/// Indicates maximum address is fixed.
const MAX_ADDRESS_FIXED = 0b1000;

/// Indicates minimum address is fixed.
const MIN_ADDRESS_FIXED = 0b0100;

/// Indicates if this bridge would subtract or positively decode address.
/// 1 This bridge subtractively decodes this address (top level bridges only)
/// 0 This bridge positively decodes this address
const DECODE_TYPE = 0b0010;
}
}

impl QWordAddressSpaceDescriptor {
/// Verifies if given descriptor is valid according to specification.
/// This also checks if all reserved bit fields which are supposed to be 0 are actually 0.
pub fn verify(&self) {
let tag = self.tag;
if tag != 0x8A {
panic!(
"Tag value for QWordAddressSpaceDescriptor should be 0x8A, not {}",
tag
);
}

let length = self.descriptor_length;
if self.descriptor_length != 0x2B {
panic!(
"Length value for QWordAddressSpaceDescriptor should be 0x2B, not {}",
length
);
}

if self.flags.bits() & 0b11110000 != 0 {
panic!("Reserved bits for GeneralFlags are 1")
}

let type_flags = self.type_flags;
match self.resource_type {
ResourceType::MEMORY => {
if type_flags & 0b11000000 != 0 {
panic!("Reserved bits for Memory Type Flags are 1");
}
}
ResourceType::IO => {
if type_flags & 0b11001100 != 0 {
panic!("Reserved bits for IO Type Flags are 1");
}
}
ResourceType::BUS => {
if type_flags != 0 {
panic!("Bus type flags should be 0, not {}", type_flags);
}
}
ResourceType(3..=191) => panic!("Invalid resource type: {}", self.resource_type.0),
ResourceType(192..) => {} // Hardware defined range
}

let min = self.range_min;
let max = self.range_max;
if max < min {
panic!(
"Address range is invalid. Max(0x{:X}) is smaller than Min(0x{:X}).",
max, min
);
}
}
}
36 changes: 36 additions & 0 deletions uefi-raw/src/protocol/pci/root_bridge.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

use crate::table::boot::{AllocateType, MemoryType};
use crate::{Handle, PhysicalAddress, Status};
use bitflags::bitflags;
use core::ffi::c_void;
use uguid::{Guid, guid};

Expand Down Expand Up @@ -37,6 +38,29 @@ newtype_enum! {
}
}

bitflags! {
/// Describes PCI I/O Protocol Attribute bitflags specified in UEFI specification.
///. https://uefi.org/specs/UEFI/2.10_A/14_Protocols_PCI_Bus_Support.html
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
#[repr(transparent)]
pub struct PciRootBridgeIoProtocolAttribute: u64 {
const ISA_MOTHERBOARD_IO = 0x0001;
const ISA_IO = 0x0002;
const VGA_PALETTE_IO = 0x0004;
const VGA_MEMORY = 0x0008;
const VGA_IO = 0x0010;
const IDE_PRIMARY_IO = 0x0020;
const IDE_SECONDARY_IO = 0x0040;
const MEMORY_WRITE_COMBINE = 0x0080;
const MEMORY_CACHED = 0x0800;
const MEMORY_DISABLE = 0x1000;
const DUAL_ADDRESS_CYCLE = 0x8000;
const ISA_IO_16 = 0x10000;
const VGA_PALETTE_IO_16 = 0x20000;
const VGA_IO_16 = 0x40000;
}
}

#[derive(Debug)]
#[repr(C)]
pub struct PciRootBridgeIoAccess {
Expand Down Expand Up @@ -130,3 +154,15 @@ pub struct PciRootBridgeIoProtocol {
impl PciRootBridgeIoProtocol {
pub const GUID: Guid = guid!("2f707ebb-4a1a-11d4-9a38-0090273fc14d");
}

impl PciRootBridgeIoProtocolWidth {
pub fn size(self) -> usize {
match self {
Self::UINT8 | Self::FIFO_UINT8 | Self::FILL_UINT8 => 1,
Self::UINT16 | Self::FIFO_UINT16 | Self::FILL_UINT16 => 2,
Self::UINT32 | Self::FIFO_UINT32 | Self::FILL_UINT32 => 4,
Self::UINT64 | Self::FIFO_UINT64 | Self::FILL_UINT64 => 8,
_ => unreachable!(),
}
}
}
6 changes: 5 additions & 1 deletion uefi-test-runner/src/proto/pci/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,9 @@
pub mod root_bridge;

pub fn test() {
root_bridge::test();
root_bridge::test_io();
root_bridge::test_buffer();
root_bridge::test_mapping();
root_bridge::test_copy();
root_bridge::test_config();
}
Loading