Skip to content

Add from_rsdt method for AcpiTables. #222

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

Merged
merged 1 commit into from
Oct 6, 2024
Merged
Changes from all 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
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);
}
}
}
Loading