Skip to content

Commit fc09396

Browse files
committed
Move contents of rsdp into acpi
Now `acpi` can be used from an allocator-less environment, the original motivation of the `rsdp` crate has been removed. We can therefore move towards deprecating it, and maintaining one less crate!
1 parent d5c4d8d commit fc09396

File tree

4 files changed

+355
-12
lines changed

4 files changed

+355
-12
lines changed

acpi/Cargo.toml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@ edition = "2021"
1212
[dependencies]
1313
bit_field = "0.10.2"
1414
log = "0.4.20"
15-
rsdp = { version = "2", path = "../rsdp" }
1615

1716
[features]
1817
default = ["allocator_api", "alloc"]

acpi/src/handler.rs

Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
use core::{ops::Deref, ptr::NonNull};
2+
3+
/// Describes a physical mapping created by `AcpiHandler::map_physical_region` and unmapped by
4+
/// `AcpiHandler::unmap_physical_region`. The region mapped must be at least `size_of::<T>()`
5+
/// bytes, but may be bigger.
6+
///
7+
/// See `PhysicalMapping::new` for the meaning of each field.
8+
#[derive(Debug)]
9+
pub struct PhysicalMapping<H, T>
10+
where
11+
H: AcpiHandler,
12+
{
13+
physical_start: usize,
14+
virtual_start: NonNull<T>,
15+
region_length: usize, // Can be equal or larger than size_of::<T>()
16+
mapped_length: usize, // Differs from `region_length` if padding is added for alignment
17+
handler: H,
18+
}
19+
20+
impl<H, T> PhysicalMapping<H, T>
21+
where
22+
H: AcpiHandler,
23+
{
24+
/// Construct a new `PhysicalMapping`.
25+
///
26+
/// - `physical_start` should be the physical address of the structure to be mapped.
27+
/// - `virtual_start` should be the corresponding virtual address of that structure. It may differ from the
28+
/// start of the region mapped due to requirements of the paging system. It must be a valid, non-null
29+
/// pointer.
30+
/// - `region_length` should be the number of bytes requested to be mapped. It must be equal to or larger than
31+
/// `size_of::<T>()`.
32+
/// - `mapped_length` should be the number of bytes mapped to fulfill the request. It may be equal to or larger
33+
/// than `region_length`, due to requirements of the paging system or other reasoning.
34+
/// - `handler` should be the same `AcpiHandler` that created the mapping. When the `PhysicalMapping` is
35+
/// dropped, it will be used to unmap the structure.
36+
pub unsafe fn new(
37+
physical_start: usize,
38+
virtual_start: NonNull<T>,
39+
region_length: usize,
40+
mapped_length: usize,
41+
handler: H,
42+
) -> Self {
43+
Self { physical_start, virtual_start, region_length, mapped_length, handler }
44+
}
45+
46+
pub fn physical_start(&self) -> usize {
47+
self.physical_start
48+
}
49+
50+
pub fn virtual_start(&self) -> NonNull<T> {
51+
self.virtual_start
52+
}
53+
54+
pub fn region_length(&self) -> usize {
55+
self.region_length
56+
}
57+
58+
pub fn mapped_length(&self) -> usize {
59+
self.mapped_length
60+
}
61+
62+
pub fn handler(&self) -> &H {
63+
&self.handler
64+
}
65+
}
66+
67+
unsafe impl<H: AcpiHandler + Send, T: Send> Send for PhysicalMapping<H, T> {}
68+
69+
impl<H, T> Deref for PhysicalMapping<H, T>
70+
where
71+
H: AcpiHandler,
72+
{
73+
type Target = T;
74+
75+
fn deref(&self) -> &T {
76+
unsafe { self.virtual_start.as_ref() }
77+
}
78+
}
79+
80+
impl<H, T> Drop for PhysicalMapping<H, T>
81+
where
82+
H: AcpiHandler,
83+
{
84+
fn drop(&mut self) {
85+
H::unmap_physical_region(self)
86+
}
87+
}
88+
89+
/// An implementation of this trait must be provided to allow `acpi` to access platform-specific
90+
/// functionality, such as mapping regions of physical memory. You are free to implement these
91+
/// however you please, as long as they conform to the documentation of each function. The handler is stored in
92+
/// every `PhysicalMapping` so it's able to unmap itself when dropped, so this type needs to be something you can
93+
/// clone/move about freely (e.g. a reference, wrapper over `Rc`, marker struct, etc.).
94+
pub trait AcpiHandler: Clone {
95+
/// Given a physical address and a size, map a region of physical memory that contains `T` (note: the passed
96+
/// size may be larger than `size_of::<T>()`). The address is not neccessarily page-aligned, so the
97+
/// implementation may need to map more than `size` bytes. The virtual address the region is mapped to does not
98+
/// matter, as long as it is accessible to `acpi`.
99+
///
100+
/// See the documentation on `PhysicalMapping::new` for an explanation of each field on the `PhysicalMapping`
101+
/// return type.
102+
///
103+
/// ## Safety
104+
///
105+
/// - `physical_address` must point to a valid `T` in physical memory.
106+
/// - `size` must be at least `size_of::<T>()`.
107+
unsafe fn map_physical_region<T>(&self, physical_address: usize, size: usize) -> PhysicalMapping<Self, T>;
108+
109+
/// Unmap the given physical mapping. This is called when a `PhysicalMapping` is dropped, you should **not** manually call this.
110+
///
111+
/// Note: A reference to the handler used to construct `region` can be acquired by calling [`PhysicalMapping::handler`].
112+
fn unmap_physical_region<T>(region: &PhysicalMapping<Self, T>);
113+
}
114+
115+
#[cfg(test)]
116+
mod tests {
117+
use super::*;
118+
119+
#[test]
120+
#[allow(dead_code)]
121+
fn test_send_sync() {
122+
// verify that PhysicalMapping implements Send and Sync
123+
fn test_send_sync<T: Send>() {}
124+
fn caller<H: AcpiHandler + Send, T: Send>() {
125+
test_send_sync::<PhysicalMapping<H, T>>();
126+
}
127+
}
128+
}

acpi/src/lib.rs

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -69,9 +69,11 @@ extern crate alloc;
6969
pub mod address;
7070
pub mod bgrt;
7171
pub mod fadt;
72+
pub mod handler;
7273
pub mod hpet;
7374
pub mod madt;
7475
pub mod mcfg;
76+
pub mod rsdp;
7577
pub mod sdt;
7678

7779
#[cfg(feature = "allocator_api")]
@@ -88,12 +90,9 @@ pub use crate::platform::{interrupt::InterruptModel, PlatformInfo};
8890
pub use crate::mcfg::PciConfigRegions;
8991

9092
pub use fadt::PowerProfile;
93+
pub use handler::{AcpiHandler, PhysicalMapping};
9194
pub use hpet::HpetInfo;
9295
pub use madt::MadtError;
93-
pub use rsdp::{
94-
handler::{AcpiHandler, PhysicalMapping},
95-
RsdpError,
96-
};
9796

9897
use crate::sdt::{SdtHeader, Signature};
9998
use core::mem;
@@ -126,7 +125,10 @@ pub unsafe trait AcpiTable {
126125
/// Error type used by functions that return an `AcpiResult<T>`.
127126
#[derive(Debug)]
128127
pub enum AcpiError {
129-
Rsdp(RsdpError),
128+
NoValidRsdp,
129+
RsdpIncorrectSignature,
130+
RsdpInvalidOemId,
131+
RsdpInvalidChecksum,
130132

131133
SdtInvalidSignature(Signature),
132134
SdtInvalidOemId(Signature),
@@ -147,8 +149,8 @@ pub enum AcpiError {
147149
///
148150
/// ### Implementation Note
149151
///
150-
/// When using the `allocator_api` feature, [`PlatformInfo::new()`] provides a much cleaner
151-
/// API for enumerating ACPI structures once an `AcpiTables` has been constructed.
152+
/// When using the `allocator_api`±`alloc` features, [`PlatformInfo::new()`] or [`PlatformInfo::new_in()`] provide
153+
/// a much cleaner API for enumerating ACPI structures once an `AcpiTables` has been constructed.
152154
#[derive(Debug)]
153155
pub struct AcpiTables<H: AcpiHandler> {
154156
mapping: PhysicalMapping<H, SdtHeader>,
@@ -165,17 +167,17 @@ where
165167
/// ### Safety: Caller must ensure the provided address is valid to read as an RSDP.
166168
pub unsafe fn from_rsdp(handler: H, address: usize) -> AcpiResult<Self> {
167169
let rsdp_mapping = unsafe { handler.map_physical_region::<Rsdp>(address, mem::size_of::<Rsdp>()) };
168-
rsdp_mapping.validate().map_err(AcpiError::Rsdp)?;
170+
rsdp_mapping.validate()?;
169171

170-
// Safety: `RSDP` has been validated.
172+
// Safety: RSDP has been validated.
171173
unsafe { Self::from_validated_rsdp(handler, rsdp_mapping) }
172174
}
173175

174176
/// Search for the RSDP on a BIOS platform. This accesses BIOS-specific memory locations and will probably not
175177
/// work on UEFI platforms. See [Rsdp::search_for_rsdp_bios](rsdp_search::Rsdp::search_for_rsdp_bios) for
176178
/// details.
177179
pub unsafe fn search_for_rsdp_bios(handler: H) -> AcpiResult<Self> {
178-
let rsdp_mapping = unsafe { Rsdp::search_for_on_bios(handler.clone()) }.map_err(AcpiError::Rsdp)?;
180+
let rsdp_mapping = unsafe { Rsdp::search_for_on_bios(handler.clone())? };
179181
// Safety: RSDP has been validated from `Rsdp::search_for_on_bios`
180182
unsafe { Self::from_validated_rsdp(handler, rsdp_mapping) }
181183
}
@@ -206,7 +208,7 @@ where
206208
drop(rsdp_mapping);
207209

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

212214
// Convert `table_mapping` to header mapping for storage

0 commit comments

Comments
 (0)