@@ -28,6 +28,11 @@ pub enum RsdpError {
2828 InvalidChecksum ,
2929}
3030
31+ /// The size in bytes of the ACPI 1.0 RSDP.
32+ const RSDP_V1_LENGTH : usize = 20 ;
33+ /// The total size in bytes of the RSDP fields introduced in ACPI 2.0.
34+ const RSDP_V2_EXT_LENGTH : usize = mem:: size_of :: < Rsdp > ( ) - RSDP_V1_LENGTH ;
35+
3136/// The first structure found in ACPI. It just tells us where the RSDT is.
3237///
3338/// On BIOS systems, it is either found in the first 1KB of the Extended Bios Data Area, or between
@@ -79,32 +84,45 @@ impl Rsdp {
7984 where
8085 H : AcpiHandler ,
8186 {
82- let rsdp_address = {
83- let mut rsdp_address = None ;
84- let areas = find_search_areas ( handler. clone ( ) ) ;
85-
86- ' areas: for area in areas. iter ( ) {
87- let mapping = unsafe { handler. map_physical_region :: < u8 > ( area. start , area. end - area. start ) } ;
88-
89- for address in area. clone ( ) . step_by ( 16 ) {
90- let ptr_in_mapping =
91- unsafe { mapping. virtual_start ( ) . as_ptr ( ) . add ( address - area. start ) } ;
92- let signature = unsafe { * ( ptr_in_mapping as * const [ u8 ; 8 ] ) } ;
93-
94- if signature == RSDP_SIGNATURE {
95- match unsafe { * ( ptr_in_mapping as * const Rsdp ) } . validate ( ) {
96- Ok ( ( ) ) => {
97- rsdp_address = Some ( address) ;
98- break ' areas;
99- }
100- Err ( err) => warn ! ( "Invalid RSDP found at {:#x}: {:?}" , address, err) ,
101- }
87+ let rsdp_address = find_search_areas ( handler. clone ( ) ) . iter ( ) . find_map ( |area| {
88+ // Map the search area for the RSDP followed by `RSDP_V2_EXT_LENGTH` bytes so an ACPI 1.0 RSDP at the
89+ // end of the area can be read as an `Rsdp` (which always has the size of an ACPI 2.0 RSDP)
90+ let mapping = unsafe {
91+ handler. map_physical_region :: < u8 > ( area. start , area. end - area. start + RSDP_V2_EXT_LENGTH )
92+ } ;
93+
94+ // SAFETY: The entirety of `mapping` maps the search area and an additional `RSDP_V2_EXT_LENGTH` bytes
95+ // that are assumed to be safe to read while `extended_area_bytes` lives. (Ideally, an assumption about
96+ // the memory following the search area would not be made.)
97+ let extended_area_bytes = unsafe {
98+ slice:: from_raw_parts (
99+ mapping. virtual_start ( ) . as_ptr ( ) ,
100+ mapping. region_length ( ) + RSDP_V2_EXT_LENGTH ,
101+ )
102+ } ;
103+
104+ // Search `Rsdp`-sized windows at 16-byte boundaries relative to the base of the area (which is also
105+ // aligned to 16 bytes due to the implementation of `find_search_areas`)
106+ extended_area_bytes. windows ( mem:: size_of :: < Rsdp > ( ) ) . step_by ( 16 ) . find_map ( |maybe_rsdp_bytes_slice| {
107+ let maybe_rsdp_virt_ptr = maybe_rsdp_bytes_slice. as_ptr ( ) . cast :: < Rsdp > ( ) ;
108+ let maybe_rsdp_phys_start = maybe_rsdp_virt_ptr as usize
109+ - mapping. virtual_start ( ) . as_ptr ( ) as usize
110+ + mapping. physical_start ( ) ;
111+ // SAFETY: `maybe_rsdp_virt_ptr` points to an aligned, readable `Rsdp`-sized value, and the `Rsdp`
112+ // struct's fields are always initialized.
113+ let maybe_rsdp = unsafe { & * maybe_rsdp_virt_ptr } ;
114+
115+ match maybe_rsdp. validate ( ) {
116+ Ok ( ( ) ) => Some ( maybe_rsdp_phys_start) ,
117+ Err ( RsdpError :: IncorrectSignature ) => None ,
118+ Err ( e) => {
119+ warn ! ( "Invalid RSDP found at {:#x}: {:?}" , maybe_rsdp_phys_start, e) ;
120+
121+ None
102122 }
103123 }
104- }
105-
106- rsdp_address
107- } ;
124+ } )
125+ } ) ;
108126
109127 match rsdp_address {
110128 Some ( address) => {
@@ -120,8 +138,6 @@ impl Rsdp {
120138 /// 2) The checksum is correct
121139 /// 3) For Version 2.0+, that the extension checksum is correct
122140 pub fn validate ( & self ) -> Result < ( ) , RsdpError > {
123- const RSDP_V1_LENGTH : usize = 20 ;
124-
125141 // Check the signature
126142 if self . signature != RSDP_SIGNATURE {
127143 return Err ( RsdpError :: IncorrectSignature ) ;
0 commit comments