1use crate::{
2 address::{AccessSize, AddressSpace, GenericAddress, RawGenericAddress},
3 sdt::{ExtendedField, SdtHeader, Signature},
4 AcpiError,
5 AcpiTable,
6};
7use bit_field::BitField;
8
9#[derive(Debug, Clone, Copy, PartialEq, Eq)]
10pub enum PowerProfile {
11 Unspecified,
12 Desktop,
13 Mobile,
14 Workstation,
15 EnterpriseServer,
16 SohoServer,
17 AppliancePc,
18 PerformanceServer,
19 Tablet,
20 Reserved(u8),
21}
22
23#[repr(C, packed)]
31#[derive(Debug, Clone, Copy)]
32pub struct Fadt {
33 header: SdtHeader,
34
35 firmware_ctrl: u32,
36 dsdt_address: u32,
37
38 _reserved: u8,
40
41 preferred_pm_profile: u8,
42 pub sci_interrupt: u16,
47 pub smi_cmd_port: u32,
63 pub acpi_enable: u8,
64 pub acpi_disable: u8,
65 pub s4bios_req: u8,
66 pub pstate_control: u8,
67 pm1a_event_block: u32,
68 pm1b_event_block: u32,
69 pm1a_control_block: u32,
70 pm1b_control_block: u32,
71 pm2_control_block: u32,
72 pm_timer_block: u32,
73 gpe0_block: u32,
74 gpe1_block: u32,
75 pm1_event_length: u8,
76 pm1_control_length: u8,
77 pm2_control_length: u8,
78 pm_timer_length: u8,
79 gpe0_block_length: u8,
80 gpe1_block_length: u8,
81 pub gpe1_base: u8,
82 pub c_state_control: u8,
83 pub worst_c2_latency: u16,
86 pub worst_c3_latency: u16,
89 pub flush_size: u16,
90 pub flush_stride: u16,
91 pub duty_offset: u8,
92 pub duty_width: u8,
93 pub day_alarm: u8,
94 pub month_alarm: u8,
95 pub century: u8,
96 pub iapc_boot_arch: IaPcBootArchFlags,
97 _reserved2: u8, pub flags: FixedFeatureFlags,
99 reset_reg: RawGenericAddress,
100 pub reset_value: u8,
101 pub arm_boot_arch: ArmBootArchFlags,
102 fadt_minor_version: u8,
103 x_firmware_ctrl: ExtendedField<u64, 2>,
104 x_dsdt_address: ExtendedField<u64, 2>,
105 x_pm1a_event_block: ExtendedField<RawGenericAddress, 2>,
106 x_pm1b_event_block: ExtendedField<RawGenericAddress, 2>,
107 x_pm1a_control_block: ExtendedField<RawGenericAddress, 2>,
108 x_pm1b_control_block: ExtendedField<RawGenericAddress, 2>,
109 x_pm2_control_block: ExtendedField<RawGenericAddress, 2>,
110 x_pm_timer_block: ExtendedField<RawGenericAddress, 2>,
111 x_gpe0_block: ExtendedField<RawGenericAddress, 2>,
112 x_gpe1_block: ExtendedField<RawGenericAddress, 2>,
113 sleep_control_reg: ExtendedField<RawGenericAddress, 2>,
114 sleep_status_reg: ExtendedField<RawGenericAddress, 2>,
115 hypervisor_vendor_id: ExtendedField<u64, 2>,
116}
117
118unsafe impl AcpiTable for Fadt {
120 const SIGNATURE: Signature = Signature::FADT;
121
122 fn header(&self) -> &SdtHeader {
123 &self.header
124 }
125}
126
127impl Fadt {
128 pub fn validate(&self) -> Result<(), AcpiError> {
129 self.header.validate(crate::sdt::Signature::FADT)
130 }
131
132 pub fn facs_address(&self) -> Result<usize, AcpiError> {
133 unsafe {
134 { self.x_firmware_ctrl }
135 .access(self.header.revision)
136 .filter(|&p| p != 0)
137 .or(Some(self.firmware_ctrl as u64))
138 .filter(|&p| p != 0)
139 .map(|p| p as usize)
140 .ok_or(AcpiError::InvalidFacsAddress)
141 }
142 }
143
144 pub fn dsdt_address(&self) -> Result<usize, AcpiError> {
145 unsafe {
146 { self.x_dsdt_address }
147 .access(self.header.revision)
148 .filter(|&p| p != 0)
149 .or(Some(self.dsdt_address as u64))
150 .filter(|&p| p != 0)
151 .map(|p| p as usize)
152 .ok_or(AcpiError::InvalidDsdtAddress)
153 }
154 }
155
156 pub fn power_profile(&self) -> PowerProfile {
157 match self.preferred_pm_profile {
158 0 => PowerProfile::Unspecified,
159 1 => PowerProfile::Desktop,
160 2 => PowerProfile::Mobile,
161 3 => PowerProfile::Workstation,
162 4 => PowerProfile::EnterpriseServer,
163 5 => PowerProfile::SohoServer,
164 6 => PowerProfile::AppliancePc,
165 7 => PowerProfile::PerformanceServer,
166 8 => PowerProfile::Tablet,
167 other => PowerProfile::Reserved(other),
168 }
169 }
170
171 pub fn pm1a_event_block(&self) -> Result<GenericAddress, AcpiError> {
172 if let Some(raw) = unsafe { self.x_pm1a_event_block.access(self.header().revision) } {
173 if raw.address != 0x0 {
174 return GenericAddress::from_raw(raw);
175 }
176 }
177
178 Ok(GenericAddress {
179 address_space: AddressSpace::SystemIo,
180 bit_width: self.pm1_event_length * 8,
181 bit_offset: 0,
182 access_size: AccessSize::Undefined,
183 address: self.pm1a_event_block.into(),
184 })
185 }
186
187 pub fn pm1b_event_block(&self) -> Result<Option<GenericAddress>, AcpiError> {
188 if let Some(raw) = unsafe { self.x_pm1b_event_block.access(self.header().revision) } {
189 if raw.address != 0x0 {
190 return Ok(Some(GenericAddress::from_raw(raw)?));
191 }
192 }
193
194 if self.pm1b_event_block != 0 {
195 Ok(Some(GenericAddress {
196 address_space: AddressSpace::SystemIo,
197 bit_width: self.pm1_event_length * 8,
198 bit_offset: 0,
199 access_size: AccessSize::Undefined,
200 address: self.pm1b_event_block.into(),
201 }))
202 } else {
203 Ok(None)
204 }
205 }
206
207 pub fn pm1a_control_block(&self) -> Result<GenericAddress, AcpiError> {
208 if let Some(raw) = unsafe { self.x_pm1a_control_block.access(self.header().revision) } {
209 if raw.address != 0x0 {
210 return GenericAddress::from_raw(raw);
211 }
212 }
213
214 Ok(GenericAddress {
215 address_space: AddressSpace::SystemIo,
216 bit_width: self.pm1_control_length * 8,
217 bit_offset: 0,
218 access_size: AccessSize::Undefined,
219 address: self.pm1a_control_block.into(),
220 })
221 }
222
223 pub fn pm1b_control_block(&self) -> Result<Option<GenericAddress>, AcpiError> {
224 if let Some(raw) = unsafe { self.x_pm1b_control_block.access(self.header().revision) } {
225 if raw.address != 0x0 {
226 return Ok(Some(GenericAddress::from_raw(raw)?));
227 }
228 }
229
230 if self.pm1b_control_block != 0 {
231 Ok(Some(GenericAddress {
232 address_space: AddressSpace::SystemIo,
233 bit_width: self.pm1_control_length * 8,
234 bit_offset: 0,
235 access_size: AccessSize::Undefined,
236 address: self.pm1b_control_block.into(),
237 }))
238 } else {
239 Ok(None)
240 }
241 }
242
243 pub fn pm2_control_block(&self) -> Result<Option<GenericAddress>, AcpiError> {
244 if let Some(raw) = unsafe { self.x_pm2_control_block.access(self.header().revision) } {
245 if raw.address != 0x0 {
246 return Ok(Some(GenericAddress::from_raw(raw)?));
247 }
248 }
249
250 if self.pm2_control_block != 0 {
251 Ok(Some(GenericAddress {
252 address_space: AddressSpace::SystemIo,
253 bit_width: self.pm2_control_length * 8,
254 bit_offset: 0,
255 access_size: AccessSize::Undefined,
256 address: self.pm2_control_block.into(),
257 }))
258 } else {
259 Ok(None)
260 }
261 }
262
263 pub fn pm_timer_block(&self) -> Result<Option<GenericAddress>, AcpiError> {
266 if self.pm_timer_length != 4 {
268 return Ok(None);
269 }
270
271 if let Some(raw) = unsafe { self.x_pm_timer_block.access(self.header().revision) } {
272 if raw.address != 0x0 {
273 return Ok(Some(GenericAddress::from_raw(raw)?));
274 }
275 }
276
277 if self.pm_timer_block != 0 {
278 Ok(Some(GenericAddress {
279 address_space: AddressSpace::SystemIo,
280 bit_width: 32,
281 bit_offset: 0,
282 access_size: AccessSize::Undefined,
283 address: self.pm_timer_block.into(),
284 }))
285 } else {
286 Ok(None)
287 }
288 }
289
290 pub fn gpe0_block(&self) -> Result<Option<GenericAddress>, AcpiError> {
291 if let Some(raw) = unsafe { self.x_gpe0_block.access(self.header().revision) } {
292 if raw.address != 0x0 {
293 return Ok(Some(GenericAddress::from_raw(raw)?));
294 }
295 }
296
297 if self.gpe0_block != 0 {
298 Ok(Some(GenericAddress {
299 address_space: AddressSpace::SystemIo,
300 bit_width: self.gpe0_block_length * 8,
301 bit_offset: 0,
302 access_size: AccessSize::Undefined,
303 address: self.gpe0_block.into(),
304 }))
305 } else {
306 Ok(None)
307 }
308 }
309
310 pub fn gpe1_block(&self) -> Result<Option<GenericAddress>, AcpiError> {
311 if let Some(raw) = unsafe { self.x_gpe1_block.access(self.header().revision) } {
312 if raw.address != 0x0 {
313 return Ok(Some(GenericAddress::from_raw(raw)?));
314 }
315 }
316
317 if self.gpe1_block != 0 {
318 Ok(Some(GenericAddress {
319 address_space: AddressSpace::SystemIo,
320 bit_width: self.gpe1_block_length * 8,
321 bit_offset: 0,
322 access_size: AccessSize::Undefined,
323 address: self.gpe1_block.into(),
324 }))
325 } else {
326 Ok(None)
327 }
328 }
329
330 pub fn reset_register(&self) -> Result<GenericAddress, AcpiError> {
331 GenericAddress::from_raw(self.reset_reg)
332 }
333
334 pub fn sleep_control_register(&self) -> Result<Option<GenericAddress>, AcpiError> {
335 if let Some(raw) = unsafe { self.sleep_control_reg.access(self.header().revision) } {
336 Ok(Some(GenericAddress::from_raw(raw)?))
337 } else {
338 Ok(None)
339 }
340 }
341
342 pub fn sleep_status_register(&self) -> Result<Option<GenericAddress>, AcpiError> {
343 if let Some(raw) = unsafe { self.sleep_status_reg.access(self.header().revision) } {
344 Ok(Some(GenericAddress::from_raw(raw)?))
345 } else {
346 Ok(None)
347 }
348 }
349}
350
351#[derive(Clone, Copy, Debug)]
352pub struct FixedFeatureFlags(u32);
353
354impl FixedFeatureFlags {
355 pub fn supports_equivalent_to_wbinvd(&self) -> bool {
359 self.0.get_bit(0)
360 }
361
362 pub fn wbinvd_flushes_all_caches(&self) -> bool {
364 self.0.get_bit(1)
365 }
366
367 pub fn all_procs_support_c1_power_state(&self) -> bool {
369 self.0.get_bit(2)
370 }
371
372 pub fn c2_configured_for_mp_system(&self) -> bool {
374 self.0.get_bit(3)
375 }
376
377 pub fn power_button_is_control_method(&self) -> bool {
380 self.0.get_bit(4)
381 }
382
383 pub fn sleep_button_is_control_method(&self) -> bool {
386 self.0.get_bit(5)
387 }
388
389 pub fn no_rtc_wake_in_fixed_register_space(&self) -> bool {
391 self.0.get_bit(6)
392 }
393
394 pub fn rtc_wakes_system_from_s4(&self) -> bool {
396 self.0.get_bit(7)
397 }
398
399 pub fn pm_timer_is_32_bit(&self) -> bool {
402 self.0.get_bit(8)
403 }
404
405 pub fn supports_docking(&self) -> bool {
407 self.0.get_bit(9)
408 }
409
410 pub fn supports_system_reset_via_fadt(&self) -> bool {
412 self.0.get_bit(10)
413 }
414
415 pub fn case_is_sealed(&self) -> bool {
417 self.0.get_bit(11)
418 }
419
420 pub fn system_is_headless(&self) -> bool {
422 self.0.get_bit(12)
423 }
424
425 pub fn use_instr_after_write_to_slp_typx(&self) -> bool {
427 self.0.get_bit(13)
428 }
429
430 pub fn supports_pciexp_wake_in_pm1(&self) -> bool {
432 self.0.get_bit(14)
433 }
434
435 pub fn use_pm_or_hpet_for_monotonically_decreasing_timers(&self) -> bool {
437 self.0.get_bit(15)
438 }
439
440 pub fn rtc_sts_is_valid_after_wakeup_from_s4(&self) -> bool {
442 self.0.get_bit(16)
443 }
444
445 pub fn ospm_may_leave_gpe_wake_events_armed_before_s5(&self) -> bool {
447 self.0.get_bit(17)
448 }
449
450 pub fn lapics_must_use_cluster_model_for_logical_mode(&self) -> bool {
452 self.0.get_bit(18)
453 }
454
455 pub fn local_xapics_must_use_physical_destination_mode(&self) -> bool {
457 self.0.get_bit(19)
458 }
459
460 pub fn system_is_hw_reduced_acpi(&self) -> bool {
462 self.0.get_bit(20)
463 }
464
465 pub fn no_benefit_to_s3(&self) -> bool {
467 self.0.get_bit(21)
468 }
469}
470
471#[derive(Clone, Copy, Debug)]
472pub struct IaPcBootArchFlags(u16);
473
474impl IaPcBootArchFlags {
475 pub fn legacy_devices_are_accessible(&self) -> bool {
477 self.0.get_bit(0)
478 }
479
480 pub fn motherboard_implements_8042(&self) -> bool {
482 self.0.get_bit(1)
483 }
484
485 pub fn dont_probe_vga(&self) -> bool {
488 self.0.get_bit(2)
489 }
490
491 pub fn dont_enable_msi(&self) -> bool {
493 self.0.get_bit(3)
494 }
495
496 pub fn dont_enable_pcie_aspm(&self) -> bool {
498 self.0.get_bit(4)
499 }
500
501 pub fn use_time_and_alarm_namespace_for_rtc(&self) -> bool {
504 self.0.get_bit(5)
505 }
506}
507
508#[derive(Clone, Copy, Debug)]
509pub struct ArmBootArchFlags(u16);
510
511impl ArmBootArchFlags {
512 pub fn implements_psci(&self) -> bool {
514 self.0.get_bit(0)
515 }
516
517 pub fn use_hvc_as_psci_conduit(&self) -> bool {
519 self.0.get_bit(1)
520 }
521}