Skip to content

Implement rest of PCI Root Bridge I/O 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 14 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 10 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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

[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
Loading