@@ -170,40 +170,64 @@ where
170
170
///
171
171
/// ### Safety: Caller must ensure that the provided mapping is a fully validated RSDP.
172
172
pub unsafe fn from_validated_rsdp ( handler : H , rsdp_mapping : PhysicalMapping < H , Rsdp > ) -> AcpiResult < Self > {
173
- let revision = rsdp_mapping. revision ( ) ;
173
+ macro_rules! read_root_table {
174
+ ( $signature_name: ident, $address_getter: ident) => { {
175
+ #[ repr( transparent) ]
176
+ struct RootTable {
177
+ header: SdtHeader ,
178
+ }
179
+
180
+ unsafe impl AcpiTable for RootTable {
181
+ const SIGNATURE : Signature = Signature :: $signature_name;
182
+
183
+ fn header( & self ) -> & SdtHeader {
184
+ & self . header
185
+ }
186
+ }
187
+
188
+ // Unmap RSDP as soon as possible
189
+ let table_phys_start = rsdp_mapping. $address_getter( ) as usize ;
190
+ drop( rsdp_mapping) ;
191
+
192
+ // Map and validate root table
193
+ // SAFETY: Addresses from a validated `RSDP` are also guaranteed to be valid.
194
+ let table_mapping = unsafe { read_table:: <_, RootTable >( handler. clone( ) , table_phys_start) } ?;
195
+
196
+ // Convert `table_mapping` to header mapping for storage
197
+ // Avoid requesting table unmap twice (from both original and converted `table_mapping`s)
198
+ let table_mapping = mem:: ManuallyDrop :: new( table_mapping) ;
199
+ // SAFETY: `SdtHeader` is equivalent to `Sdt` memory-wise
200
+ let table_mapping = unsafe {
201
+ PhysicalMapping :: new(
202
+ table_mapping. physical_start( ) ,
203
+ table_mapping. virtual_start( ) . cast:: <SdtHeader >( ) ,
204
+ table_mapping. region_length( ) ,
205
+ table_mapping. mapped_length( ) ,
206
+ handler. clone( ) ,
207
+ )
208
+ } ;
209
+
210
+ table_mapping
211
+ } } ;
212
+ }
174
213
175
- if revision == 0 {
214
+ let revision = rsdp_mapping. revision ( ) ;
215
+ let root_table_mapping = if revision == 0 {
176
216
/*
177
217
* We're running on ACPI Version 1.0. We should use the 32-bit RSDT address.
178
218
*/
179
219
180
- // Safety: Addresses from a validated `RSDP` are also guaranteed to be valid.
181
- let rsdt_mapping: PhysicalMapping < H , SdtHeader > = unsafe {
182
- handler. map_physical_region :: < SdtHeader > (
183
- rsdp_mapping. rsdt_address ( ) as usize ,
184
- core:: mem:: size_of :: < SdtHeader > ( ) ,
185
- )
186
- } ;
187
- rsdt_mapping. validate ( Signature :: RSDT ) ?;
188
-
189
- Ok ( Self { mapping : rsdt_mapping, revision, handler } )
220
+ read_root_table ! ( RSDT , rsdt_address)
190
221
} else {
191
222
/*
192
223
* We're running on ACPI Version 2.0+. We should use the 64-bit XSDT address, truncated
193
224
* to 32 bits on x86.
194
225
*/
195
226
196
- // Safety: Addresses from a validated `RSDP` are also guaranteed to be valid.
197
- let xsdt_mapping: PhysicalMapping < H , SdtHeader > = unsafe {
198
- handler. map_physical_region :: < SdtHeader > (
199
- rsdp_mapping. xsdt_address ( ) as usize ,
200
- core:: mem:: size_of :: < SdtHeader > ( ) ,
201
- )
202
- } ;
203
- xsdt_mapping. validate ( Signature :: XSDT ) ?;
227
+ read_root_table ! ( XSDT , xsdt_address)
228
+ } ;
204
229
205
- Ok ( Self { mapping : xsdt_mapping, revision, handler } )
206
- }
230
+ Ok ( Self { mapping : root_table_mapping, revision, handler } )
207
231
}
208
232
209
233
/// The ACPI revision of the tables enumerated by this structure.
@@ -333,35 +357,37 @@ unsafe fn read_table<H: AcpiHandler, T: AcpiTable>(
333
357
address : usize ,
334
358
) -> AcpiResult < PhysicalMapping < H , T > > {
335
359
// Attempt to peek at the SDT header to correctly enumerate the entire table.
336
- // Safety: `address` needs to be valid for the size of `SdtHeader`, or the ACPI tables are malformed (not a software issue).
337
- let mapping = unsafe { handler. map_physical_region :: < SdtHeader > ( address, core:: mem:: size_of :: < SdtHeader > ( ) ) } ;
338
- mapping. validate ( T :: SIGNATURE ) ?;
360
+ // SAFETY: `address` needs to be valid for the size of `SdtHeader`, or the ACPI tables are malformed (not a software issue).
361
+ let header_mapping = unsafe { handler. map_physical_region :: < SdtHeader > ( address, mem:: size_of :: < SdtHeader > ( ) ) } ;
339
362
340
- // If possible (if the existing mapping covers enough memory), resuse the existing physical mapping.
363
+ // If possible (if the existing mapping covers enough memory), reuse the existing physical mapping.
341
364
// This allows allocators/memory managers that map in chunks larger than `size_of::<SdtHeader>()` to be used more efficiently.
342
- if mapping . mapped_length ( ) >= ( mapping . length as usize ) {
343
- // Safety: Pointer is known non-null.
344
- let virtual_start =
345
- unsafe { core :: ptr :: NonNull :: new_unchecked ( mapping . virtual_start ( ) . as_ptr ( ) as * mut _ ) } ;
365
+ let table_length = header_mapping . length as usize ;
366
+ let table_mapping = if header_mapping . mapped_length ( ) >= table_length {
367
+ // Avoid requesting table unmap twice (from both `header_mapping` and `table_mapping`)
368
+ let header_mapping = mem :: ManuallyDrop :: new ( header_mapping ) ;
346
369
347
- // Safety: Mapping is known-good and validated .
348
- Ok ( unsafe {
370
+ // SAFETY: `header_mapping` maps entire table .
371
+ unsafe {
349
372
PhysicalMapping :: new (
350
- mapping . physical_start ( ) ,
351
- virtual_start,
352
- mapping . region_length ( ) ,
353
- mapping . mapped_length ( ) ,
354
- handler. clone ( ) ,
373
+ header_mapping . physical_start ( ) ,
374
+ header_mapping . virtual_start ( ) . cast :: < T > ( ) ,
375
+ table_length ,
376
+ header_mapping . mapped_length ( ) ,
377
+ handler,
355
378
)
356
- } )
379
+ }
357
380
} else {
358
- let sdt_length = mapping. length ;
359
381
// Drop the old mapping here, to ensure it's unmapped in software before requesting an overlapping mapping.
360
- drop ( mapping ) ;
382
+ drop ( header_mapping ) ;
361
383
362
- // Safety: Address and length are already known-good.
363
- Ok ( unsafe { handler. map_physical_region ( address, sdt_length as usize ) } )
364
- }
384
+ // SAFETY: Address and length are already known-good.
385
+ unsafe { handler. map_physical_region ( address, table_length) }
386
+ } ;
387
+
388
+ table_mapping. validate ( ) ?;
389
+
390
+ Ok ( table_mapping)
365
391
}
366
392
367
393
/// Iterator that steps through all of the tables, and returns only the SSDTs as `AmlTable`s.
0 commit comments