@@ -236,43 +236,52 @@ where
236
236
self . revision
237
237
}
238
238
239
- /// Searches through the ACPI table headers and attempts to locate the table with a matching `T::SIGNATURE`.
240
- pub fn find_table < T : AcpiTable > ( & self ) -> AcpiResult < PhysicalMapping < H , T > > {
241
- use core:: mem:: size_of;
239
+ /// Constructs a [`TablesPhysPtrsIter`] over this table.
240
+ fn tables_phys_ptrs ( & self ) -> TablesPhysPtrsIter < ' _ > {
241
+ // SAFETY: The virtual address of the array of pointers follows the virtual address of the table in memory.
242
+ let ptrs_virt_start = unsafe { self . mapping . virtual_start ( ) . as_ptr ( ) . add ( 1 ) . cast :: < u8 > ( ) } ;
243
+ let ptrs_bytes_len = self . mapping . region_length ( ) - mem:: size_of :: < SdtHeader > ( ) ;
244
+ // SAFETY: `ptrs_virt_start` points to an array of `ptrs_bytes_len` bytes that lives as long as `self`.
245
+ let ptrs_bytes = unsafe { core:: slice:: from_raw_parts ( ptrs_virt_start, ptrs_bytes_len) } ;
246
+ let ptr_size = if self . revision == 0 {
247
+ 4 // RSDT entry size
248
+ } else {
249
+ 8 // XSDT entry size
250
+ } ;
242
251
243
- if self . revision == 0 {
244
- let num_tables = ( ( self . mapping . length as usize ) - size_of :: < SdtHeader > ( ) ) / size_of :: < u32 > ( ) ;
245
- // Safety: Table pointer is known-good for these offsets and types.
246
- let tables_base = unsafe { self . mapping . virtual_start ( ) . as_ptr ( ) . add ( 1 ) . cast :: < u32 > ( ) } ;
252
+ ptrs_bytes. chunks ( ptr_size) . map ( |ptr_bytes_src| {
253
+ // Construct a native pointer using as many bytes as required from `ptr_bytes_src` (note that ACPI is
254
+ // little-endian)
247
255
248
- for offset in 0 ..num_tables {
249
- // Safety: Table pointer is known-good for these offsets and types.
250
- let sdt_header_address = unsafe { tables_base . add ( offset ) . read_unaligned ( ) } as usize ;
256
+ let mut ptr_bytes_dst = [ 0 ; mem :: size_of :: < usize > ( ) ] ;
257
+ let common_ptr_size = usize :: min ( mem :: size_of :: < usize > ( ) , ptr_bytes_src . len ( ) ) ;
258
+ ptr_bytes_dst [ ..common_ptr_size ] . copy_from_slice ( & ptr_bytes_src [ ..common_ptr_size ] ) ;
251
259
252
- // Safety: `RSDT` guarantees its contained addresses to be valid.
253
- let table_result = unsafe { read_table ( self . handler . clone ( ) , sdt_header_address) } ;
254
- if table_result. is_ok ( ) {
255
- return table_result;
256
- }
257
- }
258
- } else {
259
- let num_tables = ( ( self . mapping . length as usize ) - size_of :: < SdtHeader > ( ) ) / size_of :: < u64 > ( ) ;
260
- // Safety: Table pointer is known-good for these offsets and types.
261
- let tables_base = unsafe { self . mapping . virtual_start ( ) . as_ptr ( ) . add ( 1 ) . cast :: < u64 > ( ) } ;
262
-
263
- for offset in 0 ..num_tables {
264
- // Safety: Table pointer is known-good for these offsets and types.
265
- let sdt_header_address = unsafe { tables_base. add ( offset) . read_unaligned ( ) } as usize ;
266
-
267
- // Safety: `XSDT` guarantees its contained addresses to be valid.
268
- let table_result = unsafe { read_table ( self . handler . clone ( ) , sdt_header_address) } ;
269
- if table_result. is_ok ( ) {
270
- return table_result;
271
- }
272
- }
273
- }
260
+ usize:: from_le_bytes ( ptr_bytes_dst) as * const SdtHeader
261
+ } )
262
+ }
274
263
275
- Err ( AcpiError :: TableMissing ( T :: SIGNATURE ) )
264
+ /// Searches through the ACPI table headers and attempts to locate the table with a matching `T::SIGNATURE`.
265
+ pub fn find_table < T : AcpiTable > ( & self ) -> AcpiResult < PhysicalMapping < H , T > > {
266
+ self . tables_phys_ptrs ( )
267
+ . find_map ( |table_phys_ptr| {
268
+ // SAFETY: Table guarantees its contained addresses to be valid.
269
+ match unsafe { read_table ( self . handler . clone ( ) , table_phys_ptr as usize ) } {
270
+ Ok ( table_mapping) => Some ( table_mapping) ,
271
+ Err ( AcpiError :: SdtInvalidSignature ( _) ) => None ,
272
+ Err ( e) => {
273
+ log:: warn!(
274
+ "Found invalid {} table at physical address {:p}: {:?}" ,
275
+ T :: SIGNATURE ,
276
+ table_phys_ptr,
277
+ e
278
+ ) ;
279
+
280
+ None
281
+ }
282
+ }
283
+ } )
284
+ . ok_or ( AcpiError :: TableMissing ( T :: SIGNATURE ) )
276
285
}
277
286
278
287
/// Finds and returns the DSDT AML table, if it exists.
@@ -298,17 +307,7 @@ where
298
307
299
308
/// Iterates through all of the SSDT tables.
300
309
pub fn ssdts ( & self ) -> SsdtIterator < H > {
301
- let header_ptrs_base_ptr =
302
- unsafe { self . mapping . virtual_start ( ) . as_ptr ( ) . add ( 1 ) . cast :: < * const SdtHeader > ( ) } ;
303
- let header_ptr_count = ( ( self . mapping . length as usize ) - mem:: size_of :: < SdtHeader > ( ) )
304
- / core:: mem:: size_of :: < * const * const SdtHeader > ( ) ;
305
-
306
- SsdtIterator {
307
- current_sdt_ptr : header_ptrs_base_ptr,
308
- remaining : header_ptr_count,
309
- handler : self . handler . clone ( ) ,
310
- marker : core:: marker:: PhantomData ,
311
- }
310
+ SsdtIterator { tables_phys_ptrs : self . tables_phys_ptrs ( ) , handler : self . handler . clone ( ) }
312
311
}
313
312
314
313
/// Convenience method for contructing a [`PlatformInfo`](crate::platform::PlatformInfo). This is one of the
@@ -333,6 +332,9 @@ pub struct Sdt {
333
332
pub validated : bool ,
334
333
}
335
334
335
+ /// An iterator over the physical table addresses in an RSDT or XSDT.
336
+ type TablesPhysPtrsIter < ' t > = core:: iter:: Map < core:: slice:: Chunks < ' t , u8 > , fn ( & [ u8 ] ) -> * const SdtHeader > ;
337
+
336
338
#[ derive( Debug ) ]
337
339
pub struct AmlTable {
338
340
/// Physical address of the start of the AML stream (excluding the table header).
@@ -391,55 +393,50 @@ unsafe fn read_table<H: AcpiHandler, T: AcpiTable>(
391
393
}
392
394
393
395
/// Iterator that steps through all of the tables, and returns only the SSDTs as `AmlTable`s.
394
- pub struct SsdtIterator < ' a , H >
396
+ pub struct SsdtIterator < ' t , H >
395
397
where
396
398
H : AcpiHandler ,
397
399
{
398
- current_sdt_ptr : * const * const SdtHeader ,
399
- remaining : usize ,
400
+ tables_phys_ptrs : TablesPhysPtrsIter < ' t > ,
400
401
handler : H ,
401
- marker : core:: marker:: PhantomData < & ' a ( ) > ,
402
402
}
403
403
404
- impl < ' a , H > Iterator for SsdtIterator < ' a , H >
404
+ impl < ' t , H > Iterator for SsdtIterator < ' t , H >
405
405
where
406
406
H : AcpiHandler ,
407
407
{
408
408
type Item = AmlTable ;
409
409
410
410
fn next ( & mut self ) -> Option < Self :: Item > {
411
- struct Ssdt ;
412
- // Safety: Implementation properly represents a valid SSDT.
411
+ #[ repr( transparent) ]
412
+ struct Ssdt {
413
+ header : SdtHeader ,
414
+ }
415
+
416
+ // SAFETY: Implementation properly represents a valid SSDT.
413
417
unsafe impl AcpiTable for Ssdt {
414
418
const SIGNATURE : Signature = Signature :: SSDT ;
415
419
416
- fn header ( & self ) -> & sdt:: SdtHeader {
417
- // Safety: DSDT will always be valid for an SdtHeader at its `self` pointer.
418
- unsafe { & * ( self as * const Self as * const sdt:: SdtHeader ) }
420
+ fn header ( & self ) -> & SdtHeader {
421
+ & self . header
419
422
}
420
423
}
421
424
422
- if self . remaining == 0 {
423
- None
424
- } else {
425
- loop {
426
- // Attempt to peek at the SDT header to correctly enumerate the entire table.
427
- // Safety: `address` needs to be valid for the size of `SdtHeader`, or the ACPI tables are malformed (not a software issue).
428
- let sdt_header = unsafe {
429
- self . handler . map_physical_region :: < SdtHeader > (
430
- self . current_sdt_ptr . read ( ) as usize ,
431
- core:: mem:: size_of :: < SdtHeader > ( ) ,
432
- )
433
- } ;
425
+ // Borrow single field for closure to avoid immutable reference to `self` that inhibits `find_map`
426
+ let handler = & self . handler ;
434
427
435
- self . remaining -= 1 ;
428
+ // Consume iterator until next valid SSDT and return the latter
429
+ self . tables_phys_ptrs . find_map ( |table_phys_ptr| {
430
+ // SAFETY: Table guarantees its contained addresses to be valid.
431
+ match unsafe { read_table :: < _ , Ssdt > ( handler. clone ( ) , table_phys_ptr as usize ) } {
432
+ Ok ( ssdt_mapping) => Some ( AmlTable :: new ( ssdt_mapping. physical_start ( ) , ssdt_mapping. header . length ) ) ,
433
+ Err ( AcpiError :: SdtInvalidSignature ( _) ) => None ,
434
+ Err ( e) => {
435
+ log:: warn!( "Found invalid SSDT at physical address {:p}: {:?}" , table_phys_ptr, e) ;
436
436
437
- if sdt_header. validate ( Ssdt :: SIGNATURE ) . is_err ( ) {
438
- continue ;
439
- } else {
440
- return Some ( AmlTable { address : sdt_header. physical_start ( ) , length : sdt_header. length } ) ;
437
+ None
441
438
}
442
439
}
443
- }
440
+ } )
444
441
}
445
442
}
0 commit comments