Skip to content

Commit da9b3b1

Browse files
authored
Add from_rsdt method for AcpiTables. (#222)
1 parent 26e92e9 commit da9b3b1

File tree

1 file changed

+63
-45
lines changed

1 file changed

+63
-45
lines changed

acpi/src/lib.rs

+63-45
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,43 @@ pub enum AcpiError {
145145
AllocError,
146146
}
147147

148+
macro_rules! read_root_table {
149+
($signature_name:ident, $address:ident, $acpi_handler:ident) => {{
150+
#[repr(transparent)]
151+
struct RootTable {
152+
header: SdtHeader,
153+
}
154+
155+
unsafe impl AcpiTable for RootTable {
156+
const SIGNATURE: Signature = Signature::$signature_name;
157+
158+
fn header(&self) -> &SdtHeader {
159+
&self.header
160+
}
161+
}
162+
163+
// Map and validate root table
164+
// SAFETY: Addresses from a validated RSDP are also guaranteed to be valid.
165+
let table_mapping = unsafe { read_table::<_, RootTable>($acpi_handler.clone(), $address) }?;
166+
167+
// Convert `table_mapping` to header mapping for storage
168+
// Avoid requesting table unmap twice (from both original and converted `table_mapping`s)
169+
let table_mapping = mem::ManuallyDrop::new(table_mapping);
170+
// SAFETY: `SdtHeader` is equivalent to `Sdt` memory-wise
171+
let table_mapping = unsafe {
172+
PhysicalMapping::new(
173+
table_mapping.physical_start(),
174+
table_mapping.virtual_start().cast::<SdtHeader>(),
175+
table_mapping.region_length(),
176+
table_mapping.mapped_length(),
177+
$acpi_handler.clone(),
178+
)
179+
};
180+
181+
table_mapping
182+
}};
183+
}
184+
148185
/// Type capable of enumerating the existing ACPI tables on the system.
149186
///
150187
///
@@ -189,61 +226,44 @@ where
189226
///
190227
/// ### Safety: Caller must ensure that the provided mapping is a fully validated RSDP.
191228
pub unsafe fn from_validated_rsdp(handler: H, rsdp_mapping: PhysicalMapping<H, Rsdp>) -> AcpiResult<Self> {
192-
macro_rules! read_root_table {
193-
($signature_name:ident, $address_getter:ident) => {{
194-
#[repr(transparent)]
195-
struct RootTable {
196-
header: SdtHeader,
197-
}
198-
199-
unsafe impl AcpiTable for RootTable {
200-
const SIGNATURE: Signature = Signature::$signature_name;
201-
202-
fn header(&self) -> &SdtHeader {
203-
&self.header
204-
}
205-
}
229+
let revision = rsdp_mapping.revision();
230+
let root_table_mapping = if revision == 0 {
231+
/*
232+
* We're running on ACPI Version 1.0. We should use the 32-bit RSDT address.
233+
*/
234+
let table_phys_start = rsdp_mapping.rsdt_address() as usize;
235+
drop(rsdp_mapping);
236+
read_root_table!(RSDT, table_phys_start, handler)
237+
} else {
238+
/*
239+
* We're running on ACPI Version 2.0+. We should use the 64-bit XSDT address, truncated
240+
* to 32 bits on x86.
241+
*/
242+
let table_phys_start = rsdp_mapping.xsdt_address() as usize;
243+
drop(rsdp_mapping);
244+
read_root_table!(XSDT, table_phys_start, handler)
245+
};
206246

207-
// Unmap RSDP as soon as possible
208-
let table_phys_start = rsdp_mapping.$address_getter() as usize;
209-
drop(rsdp_mapping);
210-
211-
// Map and validate root table
212-
// SAFETY: Addresses from a validated RSDP are also guaranteed to be valid.
213-
let table_mapping = unsafe { read_table::<_, RootTable>(handler.clone(), table_phys_start) }?;
214-
215-
// Convert `table_mapping` to header mapping for storage
216-
// Avoid requesting table unmap twice (from both original and converted `table_mapping`s)
217-
let table_mapping = mem::ManuallyDrop::new(table_mapping);
218-
// SAFETY: `SdtHeader` is equivalent to `Sdt` memory-wise
219-
let table_mapping = unsafe {
220-
PhysicalMapping::new(
221-
table_mapping.physical_start(),
222-
table_mapping.virtual_start().cast::<SdtHeader>(),
223-
table_mapping.region_length(),
224-
table_mapping.mapped_length(),
225-
handler.clone(),
226-
)
227-
};
228-
229-
table_mapping
230-
}};
231-
}
247+
Ok(Self { mapping: root_table_mapping, revision, handler })
248+
}
232249

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

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

246-
read_root_table!(XSDT, xsdt_address)
266+
read_root_table!(XSDT, address, handler)
247267
};
248268

249269
Ok(Self { mapping: root_table_mapping, revision, handler })
@@ -480,9 +500,7 @@ where
480500
log::warn!("Found invalid SDT at physical address {:p}: {:?}", table_phys_ptr, r);
481501
continue;
482502
}
483-
let result = header_mapping.clone();
484-
drop(header_mapping);
485-
return Some(result);
503+
return Some(*header_mapping);
486504
}
487505
}
488506
}

0 commit comments

Comments
 (0)