Remove lots of unsafe code in acpi/

This commit is contained in:
Ruihan Li 2025-02-26 20:46:13 +08:00 committed by Tate, Hongliang Tian
parent 3322710900
commit 2cefa7e5fa
3 changed files with 138 additions and 138 deletions

View File

@ -3,7 +3,7 @@
#![expect(dead_code)]
use alloc::vec::Vec;
use core::{fmt::Debug, mem::size_of, slice::Iter};
use core::{fmt::Debug, slice::Iter};
use acpi::{
sdt::{SdtHeader, Signature},
@ -11,17 +11,22 @@ use acpi::{
};
use super::remapping::{Andd, Atsr, Drhd, Rhsa, Rmrr, Satc, Sidp};
use crate::mm::paddr_to_vaddr;
/// DMA Remapping structure. When IOMMU is enabled, the structure should be present in the ACPI table,
/// and the user can use the DRHD table in this structure to obtain the register base addresses used to configure functions such as IOMMU.
/// DMA Remapping structure.
///
/// When IOMMU is enabled, the structure should be present in the ACPI table, and the user can use
/// the DRHD table in this structure to obtain the register base addresses used to configure
/// functions such IOMMU.
#[derive(Debug)]
pub struct Dmar {
header: DmarHeader,
/// Actual size is indicated by `length` in header
remapping_structures: Vec<Remapping>, // Followed by `n` entries with format `Remapping Structures`
// The actual size is indicated by `length` in `header`.
// Entries with the format of Remapping Structures are followed.
remapping_structures: Vec<Remapping>,
}
/// Remapping Structures.
///
/// A DMAR structure contains serval remapping structures. Among these structures,
/// one DRHD must exist, the others must not exist at all.
#[derive(Debug)]
@ -57,6 +62,8 @@ struct DmarHeader {
reserved: [u8; 10],
}
// SAFETY: The `DmarHeader` is the header for the DMAR structure. All its fields are described in
// the Intel manual.
unsafe impl AcpiTable for DmarHeader {
const SIGNATURE: Signature = Signature::DMAR;
fn header(&self) -> &acpi::sdt::SdtHeader {
@ -67,34 +74,34 @@ unsafe impl AcpiTable for DmarHeader {
impl Dmar {
/// Creates a instance from ACPI table.
pub fn new() -> Option<Self> {
if !super::ACPI_TABLES.is_completed() {
return None;
}
let acpi_table_lock = super::ACPI_TABLES.get().unwrap().lock();
// SAFETY: The DmarHeader is the header for the DMAR structure, it fits all the field described in Intel manual.
let acpi_table_lock = super::ACPI_TABLES.get()?.lock();
let dmar_mapping = acpi_table_lock.find_table::<DmarHeader>().ok()?;
let physical_address = dmar_mapping.physical_start();
let len = dmar_mapping.mapped_length();
// SAFETY: The target address is the start of the remapping structures,
// and the length is valid since the value is read from the length field in SDTHeader minus the size of DMAR header.
let dmar_slice = unsafe {
core::slice::from_raw_parts_mut(
paddr_to_vaddr(physical_address + size_of::<DmarHeader>()) as *mut u8,
len - size_of::<DmarHeader>(),
let header = *dmar_mapping;
// SAFETY: `find_table` returns a region of memory that belongs to the ACPI table. This
// memory region is valid to read, properly initialized, lives for `'static`, and will
// never be mutated.
let slice = unsafe {
core::slice::from_raw_parts(
dmar_mapping
.virtual_start()
.as_ptr()
.cast::<u8>()
.cast_const(),
dmar_mapping.mapped_length(),
)
};
let mut index = core::mem::size_of::<DmarHeader>();
let mut remapping_structures = Vec::new();
let mut index = 0;
let mut remain_length = len - size_of::<DmarHeader>();
// SAFETY: Indexes and offsets are strictly followed by the manual.
unsafe {
while remain_length > 0 {
// Common header: type: u16, length: u16
let length = *dmar_slice[index + 2..index + 4].as_ptr() as usize;
let typ = *dmar_slice[index..index + 2].as_ptr() as usize;
let bytes = &&dmar_slice[index..index + length];
while index != (header.header.length as usize) {
// CommonHeader { type: u16, length: u16 }
let typ = u16::from_ne_bytes(slice[index..index + 2].try_into().unwrap());
let length =
u16::from_ne_bytes(slice[index + 2..index + 4].try_into().unwrap()) as usize;
let bytes = &slice[index..index + length];
let remapping = match typ {
0 => Remapping::Drhd(Drhd::from_bytes(bytes)),
1 => Remapping::Rmrr(Rmrr::from_bytes(bytes)),
@ -104,16 +111,15 @@ impl Dmar {
5 => Remapping::Satc(Satc::from_bytes(bytes)),
6 => Remapping::Sidp(Sidp::from_bytes(bytes)),
_ => {
panic!("Unidentified remapping structure type");
panic!(
"the type of the remapping structure is invalid or not supported: {}",
typ
);
}
};
// let temp = DeviceScope::from_bytes(
// &bytes[index as usize..index as usize + length],
// );
remapping_structures.push(remapping);
index += length;
remain_length -= length;
}
}
Some(Dmar {

View File

@ -1,7 +1,5 @@
// SPDX-License-Identifier: MPL-2.0
#![expect(unused_variables)]
pub mod dmar;
pub mod remapping;
@ -29,16 +27,19 @@ impl AcpiHandler for AcpiMemoryHandler {
physical_address: usize,
size: usize,
) -> acpi::PhysicalMapping<Self, T> {
acpi::PhysicalMapping::new(
physical_address,
NonNull::new(paddr_to_vaddr(physical_address) as *mut T).unwrap(),
size,
size,
self.clone(),
)
let virtual_address = NonNull::new(paddr_to_vaddr(physical_address) as *mut T).unwrap();
// SAFETY: The caller should guarantee that `physical_address..physical_address + size` is
// part of the ACPI table. Then the memory region is mapped to `virtual_address` and is
// valid for read and immutable dereferencing.
// FIXME: The caller guarantee only holds if we trust the hardware to provide a valid ACPI
// table. Otherwise, if the table is corrupted, it may reference arbitrary memory regions.
unsafe {
acpi::PhysicalMapping::new(physical_address, virtual_address, size, size, self.clone())
}
}
fn unmap_physical_region<T>(region: &acpi::PhysicalMapping<Self, T>) {}
fn unmap_physical_region<T>(_region: &acpi::PhysicalMapping<Self, T>) {}
}
pub fn init() {

View File

@ -1,20 +1,23 @@
// SPDX-License-Identifier: MPL-2.0
#![expect(dead_code)]
#![expect(unused_variables)]
//! Remapping structures of DMAR table.
//! This file defines these structures and provides a "Debug" implementation to see the value inside these structures.
//!
//! This file defines these structures and provides a `Debug` implementation to see the value
//! inside these structures.
//!
//! Most of the introduction are copied from Intel vt-directed-io-specification.
use alloc::{string::String, vec::Vec};
use core::{fmt::Debug, mem::size_of};
use alloc::{borrow::ToOwned, string::String, vec::Vec};
use core::fmt::Debug;
use ostd_pod::Pod;
/// DMA-remapping hardware unit definition (DRHD).
///
/// A DRHD structure uniquely represents a remapping hardware unit present in the platform.
/// There must be at least one instance of this structure for each
/// PCI segment in the platform.
/// There must be at least one instance of this structure for each PCI segment in the platform.
#[derive(Debug, Clone)]
pub struct Drhd {
header: DrhdHeader,
@ -28,7 +31,7 @@ impl Drhd {
}
#[repr(C)]
#[derive(Debug, Clone, Copy)]
#[derive(Debug, Clone, Copy, Pod)]
pub struct DrhdHeader {
typ: u16,
length: u16,
@ -50,7 +53,7 @@ pub struct Rmrr {
}
#[repr(C)]
#[derive(Debug, Clone, Copy)]
#[derive(Debug, Clone, Copy, Pod)]
pub struct RmrrHeader {
typ: u16,
length: u16,
@ -71,7 +74,7 @@ pub struct Atsr {
}
#[repr(C)]
#[derive(Debug, Clone, Copy)]
#[derive(Debug, Clone, Copy, Pod)]
pub struct AtsrHeader {
typ: u16,
length: u16,
@ -82,11 +85,12 @@ pub struct AtsrHeader {
/// Remapping Hardware Status Affinity (RHSA).
///
/// It is applicable for platforms supporting non-uniform memory (NUMA), where Remapping hardware units spans across nodes.
/// This optional structure provides the association between each Remapping hardware unit (identified by its
/// espective Base Address) and the proximity domain to which that hardware unit belongs.
/// It is applicable for platforms supporting non-uniform memory (NUMA),
/// where Remapping hardware units spans across nodes.
/// This optional structure provides the association between each Remapping hardware unit (identified
/// by its espective Base Address) and the proximity domain to which that hardware unit belongs.
#[repr(C)]
#[derive(Debug, Clone, Copy)]
#[derive(Debug, Clone, Copy, Pod)]
pub struct Rhsa {
typ: u16,
length: u16,
@ -106,7 +110,7 @@ pub struct Andd {
}
#[repr(C)]
#[derive(Debug, Clone, Copy)]
#[derive(Debug, Clone, Copy, Pod)]
pub struct AnddHeader {
typ: u16,
length: u16,
@ -125,7 +129,7 @@ pub struct Satc {
}
#[repr(C)]
#[derive(Debug, Clone, Copy)]
#[derive(Debug, Clone, Copy, Pod)]
pub struct SatcHeader {
typ: u16,
length: u16,
@ -139,7 +143,6 @@ pub struct SatcHeader {
/// The (SIDP) reporting structure identifies devices that have special
/// properties and that may put restrictions on how system software must configure remapping
/// structures that govern such devices in a platform where remapping hardware is enabled.
///
#[derive(Debug, Clone)]
pub struct Sidp {
header: SidpHeader,
@ -147,7 +150,7 @@ pub struct Sidp {
}
#[repr(C)]
#[derive(Debug, Clone, Copy)]
#[derive(Debug, Clone, Copy, Pod)]
pub struct SidpHeader {
typ: u16,
length: u16,
@ -164,7 +167,7 @@ pub struct DeviceScope {
}
#[repr(C)]
#[derive(Debug, Clone, Copy)]
#[derive(Debug, Clone, Copy, Pod)]
pub struct DeviceScopeHeader {
typ: u8,
length: u8,
@ -175,35 +178,32 @@ pub struct DeviceScopeHeader {
}
macro_rules! impl_from_bytes {
($(($struct:tt,$header_struct:tt,$dst_name:ident)),*) => {
($(($struct:tt, $header_struct:tt),)*) => {
$(impl $struct {
/// Creates instance from bytes
#[doc = concat!("Parses a [`", stringify!($struct), "`] from bytes.")]
///
/// # Safety
/// # Panics
///
/// User must ensure the bytes is valid.
///
pub unsafe fn from_bytes(bytes: &[u8]) -> Self {
let length = u16_from_slice(&bytes[2..4]) as usize;
debug_assert_eq!(length, bytes.len());
#[doc = concat!(
"This method may panic if the bytes do not represent a valid [`",
stringify!($struct),
"`].",
)]
pub fn from_bytes(bytes: &[u8]) -> Self {
let header = $header_struct::from_bytes(bytes);
debug_assert_eq!(header.length as usize, bytes.len());
let mut index = core::mem::size_of::<$header_struct>();
let mut remain_length = length - core::mem::size_of::<$header_struct>();
let mut $dst_name = Vec::new();
while remain_length > 0 {
let length = *bytes[index + 1..index + 2].as_ptr() as usize;
let temp = DeviceScope::from_bytes(
&bytes[index..index + length],
);
$dst_name.push(temp);
index += length;
remain_length -= length;
let mut device_scopes = Vec::new();
while index != (header.length as usize) {
let val = DeviceScope::from_bytes_prefix(&bytes[index..]);
index += val.header.length as usize;
device_scopes.push(val);
}
let header = *(bytes.as_ptr() as *const $header_struct);
Self{
header,
$dst_name
device_scopes,
}
}
})*
@ -211,33 +211,31 @@ macro_rules! impl_from_bytes {
}
impl_from_bytes!(
(Drhd, DrhdHeader, device_scopes),
(Rmrr, RmrrHeader, device_scopes),
(Atsr, AtsrHeader, device_scopes),
(Satc, SatcHeader, device_scopes),
(Sidp, SidpHeader, device_scopes)
(Drhd, DrhdHeader),
(Rmrr, RmrrHeader),
(Atsr, AtsrHeader),
(Satc, SatcHeader),
(Sidp, SidpHeader),
);
impl DeviceScope {
/// Creates instance from bytes
/// Parses a [`DeviceScope`] from a prefix of the bytes.
///
/// # Safety
/// # Panics
///
/// User must ensure the bytes is valid.
///
unsafe fn from_bytes(bytes: &[u8]) -> Self {
let length = bytes[1] as u32;
debug_assert_eq!(length, bytes.len() as u32);
let header = *(bytes.as_ptr() as *const DeviceScopeHeader);
/// This method may panic if the byte prefix does not represent a valid [`DeviceScope`].
fn from_bytes_prefix(bytes: &[u8]) -> Self {
let header = DeviceScopeHeader::from_bytes(bytes);
debug_assert!((header.length as usize) <= bytes.len());
let mut index = core::mem::size_of::<DeviceScopeHeader>();
debug_assert!((header.length as usize) >= index);
let mut index = size_of::<DeviceScopeHeader>();
let mut remain_length = length - index as u32;
let mut path = Vec::new();
while remain_length > 0 {
let temp: (u8, u8) = *(bytes[index..index + 2].as_ptr() as *const (u8, u8));
path.push(temp);
while index != (header.length as usize) {
let val = (bytes[index], bytes[index + 1]);
path.push(val);
index += 2;
remain_length -= 2;
}
Self { header, path }
@ -245,42 +243,37 @@ impl DeviceScope {
}
impl Rhsa {
/// Creates instance from bytes
/// Parses an [`Rhsa`] from the bytes.
///
/// # Safety
/// # Panics
///
/// User must ensure the bytes is valid.
///
pub unsafe fn from_bytes(bytes: &[u8]) -> Self {
let length = u16_from_slice(&bytes[2..4]) as u32;
debug_assert_eq!(length, bytes.len() as u32);
*(bytes.as_ptr() as *const Self)
/// This method may panic if the bytes do not represent a valid [`Rhsa`].
pub fn from_bytes(bytes: &[u8]) -> Self {
let val = <Self as Pod>::from_bytes(bytes);
debug_assert_eq!(val.length as usize, bytes.len());
val
}
}
impl Andd {
/// Creates instance from bytes
/// Parses an [`Andd`] from the bytes.
///
/// # Safety
/// # Panics
///
/// User must ensure the bytes is valid.
///
pub unsafe fn from_bytes(bytes: &[u8]) -> Self {
let length = u16_from_slice(&bytes[2..4]) as usize;
debug_assert_eq!(length, bytes.len());
/// This method may panic if the bytes do not represent a valid [`Andd`].
pub fn from_bytes(bytes: &[u8]) -> Self {
let header = AnddHeader::from_bytes(bytes);
debug_assert_eq!(header.length as usize, bytes.len());
let index = core::mem::size_of::<AnddHeader>();
let remain_length = length - core::mem::size_of::<AnddHeader>();
let string = String::from_utf8(bytes[index..index + length].to_vec()).unwrap();
let header_len = core::mem::size_of::<AnddHeader>();
let acpi_object_name = core::str::from_utf8(&bytes[header_len..])
.unwrap()
.to_owned();
let header = *(bytes.as_ptr() as *const AnddHeader);
Self {
header,
acpi_object_name: string,
acpi_object_name,
}
}
}
fn u16_from_slice(input: &[u8]) -> u16 {
u16::from_ne_bytes(input[0..size_of::<u16>()].try_into().unwrap())
}