Skip to content

Commit

Permalink
Add from_rsdt method for AcpiTables. (#222)
Browse files Browse the repository at this point in the history
  • Loading branch information
Hsy-Intel authored Oct 6, 2024
1 parent 26e92e9 commit da9b3b1
Showing 1 changed file with 63 additions and 45 deletions.
108 changes: 63 additions & 45 deletions acpi/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,43 @@ pub enum AcpiError {
AllocError,
}

macro_rules! read_root_table {
($signature_name:ident, $address:ident, $acpi_handler:ident) => {{
#[repr(transparent)]
struct RootTable {
header: SdtHeader,
}

unsafe impl AcpiTable for RootTable {
const SIGNATURE: Signature = Signature::$signature_name;

fn header(&self) -> &SdtHeader {
&self.header
}
}

// Map and validate root table
// SAFETY: Addresses from a validated RSDP are also guaranteed to be valid.
let table_mapping = unsafe { read_table::<_, RootTable>($acpi_handler.clone(), $address) }?;

// Convert `table_mapping` to header mapping for storage
// Avoid requesting table unmap twice (from both original and converted `table_mapping`s)
let table_mapping = mem::ManuallyDrop::new(table_mapping);
// SAFETY: `SdtHeader` is equivalent to `Sdt` memory-wise
let table_mapping = unsafe {
PhysicalMapping::new(
table_mapping.physical_start(),
table_mapping.virtual_start().cast::<SdtHeader>(),
table_mapping.region_length(),
table_mapping.mapped_length(),
$acpi_handler.clone(),
)
};

table_mapping
}};
}

/// Type capable of enumerating the existing ACPI tables on the system.
///
///
Expand Down Expand Up @@ -189,61 +226,44 @@ where
///
/// ### Safety: Caller must ensure that the provided mapping is a fully validated RSDP.
pub unsafe fn from_validated_rsdp(handler: H, rsdp_mapping: PhysicalMapping<H, Rsdp>) -> AcpiResult<Self> {
macro_rules! read_root_table {
($signature_name:ident, $address_getter:ident) => {{
#[repr(transparent)]
struct RootTable {
header: SdtHeader,
}

unsafe impl AcpiTable for RootTable {
const SIGNATURE: Signature = Signature::$signature_name;

fn header(&self) -> &SdtHeader {
&self.header
}
}
let revision = rsdp_mapping.revision();
let root_table_mapping = if revision == 0 {
/*
* We're running on ACPI Version 1.0. We should use the 32-bit RSDT address.
*/
let table_phys_start = rsdp_mapping.rsdt_address() as usize;
drop(rsdp_mapping);
read_root_table!(RSDT, table_phys_start, handler)
} else {
/*
* We're running on ACPI Version 2.0+. We should use the 64-bit XSDT address, truncated
* to 32 bits on x86.
*/
let table_phys_start = rsdp_mapping.xsdt_address() as usize;
drop(rsdp_mapping);
read_root_table!(XSDT, table_phys_start, handler)
};

// Unmap RSDP as soon as possible
let table_phys_start = rsdp_mapping.$address_getter() as usize;
drop(rsdp_mapping);

// Map and validate root table
// SAFETY: Addresses from a validated RSDP are also guaranteed to be valid.
let table_mapping = unsafe { read_table::<_, RootTable>(handler.clone(), table_phys_start) }?;

// Convert `table_mapping` to header mapping for storage
// Avoid requesting table unmap twice (from both original and converted `table_mapping`s)
let table_mapping = mem::ManuallyDrop::new(table_mapping);
// SAFETY: `SdtHeader` is equivalent to `Sdt` memory-wise
let table_mapping = unsafe {
PhysicalMapping::new(
table_mapping.physical_start(),
table_mapping.virtual_start().cast::<SdtHeader>(),
table_mapping.region_length(),
table_mapping.mapped_length(),
handler.clone(),
)
};

table_mapping
}};
}
Ok(Self { mapping: root_table_mapping, revision, handler })
}

let revision = rsdp_mapping.revision();
/// Create an `AcpiTables` if you have the physical address of the RSDT/XSDT.
///
/// ### Safety: Caller must ensure the provided address is valid RSDT/XSDT address.
pub unsafe fn from_rsdt(handler: H, revision: u8, address: usize) -> AcpiResult<Self> {
let root_table_mapping = if revision == 0 {
/*
* We're running on ACPI Version 1.0. We should use the 32-bit RSDT address.
*/

read_root_table!(RSDT, rsdt_address)
read_root_table!(RSDT, address, handler)
} else {
/*
* We're running on ACPI Version 2.0+. We should use the 64-bit XSDT address, truncated
* to 32 bits on x86.
*/

read_root_table!(XSDT, xsdt_address)
read_root_table!(XSDT, address, handler)
};

Ok(Self { mapping: root_table_mapping, revision, handler })
Expand Down Expand Up @@ -480,9 +500,7 @@ where
log::warn!("Found invalid SDT at physical address {:p}: {:?}", table_phys_ptr, r);
continue;
}
let result = header_mapping.clone();
drop(header_mapping);
return Some(result);
return Some(*header_mapping);
}
}
}

0 comments on commit da9b3b1

Please sign in to comment.