1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
use crate::{parse_validated_rsdp, rsdp::Rsdp, Acpi, AcpiError, AcpiHandler};
use core::{mem, ops::RangeInclusive};
use log::warn;
const EBDA_START_SEGMENT_PTR: usize = 0x40e;
const EBDA_EARLIEST_START: usize = 0x80000;
const EBDA_END: usize = 0x9ffff;
const RSDP_BIOS_AREA_START: usize = 0xe0000;
const RSDP_BIOS_AREA_END: usize = 0xfffff;
const RSDP_SIGNATURE: &'static [u8; 8] = b"RSD PTR ";
pub fn find_search_areas<H>(handler: &mut H) -> [RangeInclusive<usize>; 2]
where
H: AcpiHandler,
{
let ebda_start_mapping =
unsafe { handler.map_physical_region::<u16>(EBDA_START_SEGMENT_PTR, mem::size_of::<u16>()) };
let ebda_start = (*ebda_start_mapping as usize) << 4;
handler.unmap_physical_region(ebda_start_mapping);
[
RSDP_BIOS_AREA_START..=RSDP_BIOS_AREA_END,
if (EBDA_EARLIEST_START..EBDA_END).contains(&ebda_start) {
ebda_start..=ebda_start + 1024
} else {
EBDA_EARLIEST_START..=EBDA_END
},
]
}
pub unsafe fn search_for_rsdp_bios<H>(handler: &mut H) -> Result<Acpi, AcpiError>
where
H: AcpiHandler,
{
let areas = find_search_areas(handler);
let mut area_mapping = handler.map_physical_region::<[[u8; 8]; 0x1000 / 8]>(
areas[0].clone().next().unwrap() & !0xfff,
0x1000,
);
for address in areas.iter().flat_map(|i| i.clone()).step_by(16) {
let mut mapping_start = area_mapping.physical_start as usize;
if !(mapping_start..mapping_start + 0x1000).contains(&address) {
handler.unmap_physical_region(area_mapping);
area_mapping = handler.map_physical_region::<[[u8; 8]; 0x1000 / 8]>(
address & !0xfff,
0x1000,
);
mapping_start = area_mapping.physical_start as usize;
}
let index = (address - mapping_start) / 8;
let signature = (*area_mapping)[index];
if signature != *RSDP_SIGNATURE {
continue;
}
let rsdp_mapping = handler.map_physical_region::<Rsdp>(address, mem::size_of::<Rsdp>());
if let Err(e) = (*rsdp_mapping).validate() {
warn!("Invalid RSDP found at 0x{:x}: {:?}", address, e);
continue;
}
handler.unmap_physical_region(area_mapping);
return parse_validated_rsdp(handler, rsdp_mapping);
}
Err(AcpiError::NoValidRsdp)
}