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

View File

@ -1,7 +1,5 @@
// SPDX-License-Identifier: MPL-2.0 // SPDX-License-Identifier: MPL-2.0
#![expect(unused_variables)]
pub mod dmar; pub mod dmar;
pub mod remapping; pub mod remapping;
@ -29,16 +27,19 @@ impl AcpiHandler for AcpiMemoryHandler {
physical_address: usize, physical_address: usize,
size: usize, size: usize,
) -> acpi::PhysicalMapping<Self, T> { ) -> acpi::PhysicalMapping<Self, T> {
acpi::PhysicalMapping::new( let virtual_address = NonNull::new(paddr_to_vaddr(physical_address) as *mut T).unwrap();
physical_address,
NonNull::new(paddr_to_vaddr(physical_address) as *mut T).unwrap(), // SAFETY: The caller should guarantee that `physical_address..physical_address + size` is
size, // part of the ACPI table. Then the memory region is mapped to `virtual_address` and is
size, // valid for read and immutable dereferencing.
self.clone(), // 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() { pub fn init() {

View File

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