1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116
//! Support for the DMAR Device Scope Structure.
use super::*;
/// DMAR Device Scope Structure.
///
/// This structure is described in Section 8.3.1 of the VT Directed I/O Spec.
#[derive(Clone, Copy, Debug, FromBytes)]
#[repr(packed)]
pub(crate) struct DeviceScope {
typ: u8,
length: u8,
_reserved: u16,
enumeration_id: u8,
start_bus_number: u8,
// Following this is a variable-sized `Path` field,
// so we cannot include it here in the static struct definition.
// It would look something like:
// path: [u16],
}
const _: () = assert!(core::mem::size_of::<DeviceScope>() == 6);
const _: () = assert!(core::mem::align_of::<DeviceScope>() == 1);
/// DMAR Device Scope Structure.
///
/// This structure is described in Section 8.3.1 of the VT Directed I/O Spec.
#[derive(Debug)]
pub struct DmarDeviceScope<'t> {
/// The fixed-size part of the [`DeviceScope`] structure.
table: &'t DeviceScope,
/// The underlying MappedPages that cover this structure.
mapped_pages: &'t MappedPages,
/// The offset into the above `mapped_pages` at which
/// the dynamic part (the Path) of the [`DeviceScope`] structure begins.
path_starting_offset: usize,
/// The total size in bytes of all dynamic Path entries.
/// The number of Path entries is `path_total_size / 2`.
#[allow(dead_code)]
path_total_size: usize,
}
impl<'t> DmarDeviceScope<'t> {
pub(crate) fn from_entry(
mp: &'t MappedPages,
mp_offset: usize,
) -> Result<DmarDeviceScope<'t>, &'static str> {
let dev_scope: &DeviceScope = mp.as_type(mp_offset)?;
Ok(DmarDeviceScope {
table: dev_scope,
mapped_pages: mp,
path_starting_offset: mp_offset + size_of::<DeviceScope>(),
path_total_size: dev_scope.length as usize - size_of::<DeviceScope>(),
})
}
/// Returns the type of this device scope structure.
///
/// TODO: use an enum to represent possible device types.
///
/// * `1`: PCI Endpoint Device - The device identified by the ‘Path’ field is
/// a PCI endpoint device. This type must not be used in Device Scope of
/// DRHD structures with INCLUDE_PCI_ALL flag Set.
/// * `2`: PCI Sub-hierarchy - The device identified by the ‘Path’ field is a
/// PCI-PCI bridge. In this case, the specified bridge device and all its
/// downstream devices are included in the scope. This type must not be
/// in Device Scope of DRHD structures with INCLUDE_PCI_ALL flag Set.
/// * `3`: IOAPIC - The device identified by the ‘Path’ field is an I/O APIC
/// (or I/O SAPIC) device, enumerated through the ACPI MADT I/O APIC
/// (or I/O SAPIC) structure.
/// * `4`: MSI_CAPABLE_HPET1 - The device identified by the ‘Path’ field
/// is an HPET Timer Block capable of generating MSI (Message Signaled
/// interrupts). HPET hardware is reported through ACPI HPET structure.
/// * `5`: ACPI_NAMESPACE_DEVICE - The device identified by the ‘Path’
/// field is an ACPI name-space enumerated
pub fn device_type(&self) -> u8 {
self.table.typ
}
pub(crate) fn length(&self) -> u8 { self.table.length }
/// Returns the Enumeration ID, which differs in meaning based on the type
/// of this [`DmarDeviceScope`] structure.
pub fn enumeration_id(&self) -> u8 {
self.table.enumeration_id
}
/// Returns the PCI bus number under which the device identified
/// by this [`DmarDeviceScope`] exists.
pub fn start_bus_number(&self) -> u8 {
self.table.start_bus_number
}
/// Calculates and returns the hierarchical path (along the PCI bus)
/// to the device specified by this [`DmarDeviceScope`] structure.
///
/// # Warning -- incomplete!
/// TODO: finish this function, it is not yet complete. It only returns the first path.
pub fn path(&self) -> Result<&'t DeviceScopePath, &'static str> {
log::warn!("The DmarDeviceScope::path() function is incomplete! Its value may be incorrect.");
let /* mut */ offset = self.path_starting_offset;
let starting_path: &DeviceScopePath = self.mapped_pages.as_type(offset)?;
// TODO: complete the path iteration algorithm described in Section 8.3.1
Ok(starting_path)
}
}
#[derive(Debug, Clone, Copy, FromBytes)]
#[repr(packed)]
pub struct DeviceScopePath {
pub device: u8,
pub function: u8,
}
const _: () = assert!(core::mem::size_of::<DeviceScopePath>() == 2);
const _: () = assert!(core::mem::align_of::<DeviceScopePath>() == 1);