Skip to content

Commit 136af52

Browse files
committed
Add methods for adding SSDT
1 parent ad1b570 commit 136af52

File tree

5 files changed

+72
-6
lines changed

5 files changed

+72
-6
lines changed

acpi/src/handler.rs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,20 @@ where
7676
pub fn handler(&self) -> &H {
7777
&self.handler
7878
}
79+
80+
pub fn write<V>(&mut self, offset: usize, value: V) {
81+
unsafe {
82+
let ptr = (self.virtual_start.as_ptr() as *mut u8).add(offset) as *mut V;
83+
ptr.write(value);
84+
}
85+
}
86+
87+
pub fn read<V>(&self, offset: usize) -> V {
88+
unsafe {
89+
let ptr = (self.virtual_start.as_ptr() as *mut u8).add(offset) as *mut V;
90+
ptr.read()
91+
}
92+
}
7993
}
8094

8195
unsafe impl<H: AcpiHandler + Send, T: Send> Send for PhysicalMapping<H, T> {}

acpi/src/iort.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ impl fmt::Display for Iort {
4343
impl Iort {
4444
pub fn nodes(&self) -> IortNodeIter {
4545
let node_offset = self.node_array_offset as usize;
46-
let pointer = unsafe { (self as *const Iort as *const u8).add(node_offset)};
46+
let pointer = unsafe { (self as *const Iort as *const u8).add(node_offset) };
4747
let remaining_length = self.header.length as u32 - node_offset as u32;
4848

4949
IortNodeIter { pointer, remaining_length, _phantom: PhantomData }

acpi/src/lib.rs

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -367,6 +367,43 @@ where
367367
SsdtIterator { tables_phys_ptrs: self.tables_phys_ptrs(), handler: self.handler.clone() }
368368
}
369369

370+
/// Add a new SSDT to the list of tables.
371+
/// Sould edit the XSDT or RSDT to include the new table.
372+
/// Safety: The address must be valid for reading as an SSDT. And must match the revision of the tables.
373+
/// The address must be 8-byte aligned and the 8-byte after xsdt must be not used.
374+
pub unsafe fn add_ssdt(&mut self, address: usize) -> AcpiResult<()> {
375+
#[repr(transparent)]
376+
struct Xsdt {
377+
header: SdtHeader,
378+
}
379+
380+
unsafe impl AcpiTable for Xsdt {
381+
const SIGNATURE: Signature = Signature::XSDT;
382+
383+
fn header(&self) -> &SdtHeader {
384+
&self.header
385+
}
386+
}
387+
388+
let mut xsdt =
389+
unsafe { read_table::<H, Xsdt>(self.handler.clone(), self.mapping.physical_start()).unwrap() };
390+
391+
xsdt.write::<u64>(xsdt.header.length as usize, address as u64);
392+
393+
xsdt.write::<u32>(4, xsdt.header.length + 8); // length of the table
394+
xsdt.write::<u8>(9, 0); // checksum
395+
let mut sum = 0u8;
396+
for i in 0..xsdt.header.length as usize {
397+
sum = sum.wrapping_add(xsdt.read::<u8>(i));
398+
}
399+
xsdt.write::<u8>(9, (!sum).wrapping_add(1)); // checksum
400+
401+
let address = xsdt.physical_start();
402+
let handler = xsdt.handler().clone();
403+
self.mapping = read_root_table!(XSDT, address, handler);
404+
Ok(())
405+
}
406+
370407
/// Convenience method for contructing a [`PlatformInfo`](crate::platform::PlatformInfo). This is one of the
371408
/// first things you should usually do with an `AcpiTables`, and allows to collect helpful information about
372409
/// the platform from the ACPI tables.

acpi/src/rsdp.rs

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,8 @@
1-
use uefi::table::{cfg::ACPI2_GUID, Boot, SystemTable};
1+
use uefi::table::{
2+
cfg::{ACPI2_GUID, ACPI_GUID},
3+
Boot,
4+
SystemTable,
5+
};
26

37
use crate::{AcpiError, AcpiHandler, AcpiResult, PhysicalMapping};
48
use core::{ffi::c_void, mem, ops::Range, slice, str};
@@ -112,9 +116,11 @@ impl Rsdp {
112116
where
113117
H: AcpiHandler,
114118
{
119+
// SAFETY: `system_table` is a valid pointer to a `SystemTable<Boot>`.
115120
let system_table = unsafe { SystemTable::<Boot>::from_ptr(system_table as *mut c_void).unwrap() };
116-
117121
let config_table = system_table.config_table();
122+
123+
// Search the configuration table for the RSDP, using GUIDs to identify the correct entry
118124
let rsdp = config_table.iter().find_map(|entry| {
119125
if entry.guid == ACPI2_GUID {
120126
let rsdp_mapping =
@@ -127,10 +133,22 @@ impl Rsdp {
127133
None
128134
}
129135
}
136+
} else if entry.guid == ACPI_GUID {
137+
let rsdp_mapping =
138+
unsafe { handler.map_physical_region::<Rsdp>(entry.address as usize, mem::size_of::<Rsdp>()) };
139+
match rsdp_mapping.validate() {
140+
Ok(()) => Some(rsdp_mapping),
141+
Err(AcpiError::RsdpIncorrectSignature) => None,
142+
Err(err) => {
143+
log::warn!("Invalid RSDP found at {:#x}: {:?}", system_table.as_ptr() as usize, err);
144+
None
145+
}
146+
}
130147
} else {
131148
None
132149
}
133150
});
151+
// Return the first valid RSDP found, or an error if none were found
134152
rsdp.ok_or(AcpiError::NoValidRsdp)
135153
}
136154

rust-toolchain

Lines changed: 0 additions & 3 deletions
This file was deleted.

0 commit comments

Comments
 (0)