fadt.rs 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157
  1. use crate::{
  2. platform::address::RawGenericAddress,
  3. sdt::{ExtendedField, SdtHeader},
  4. AcpiError,
  5. AcpiTable,
  6. AcpiTables,
  7. };
  8. use bit_field::BitField;
  9. use rsdp::handler::AcpiHandler;
  10. #[derive(Clone, Copy, PartialEq, Eq, Debug)]
  11. pub enum PowerProfile {
  12. Unspecified,
  13. Desktop,
  14. Mobile,
  15. Workstation,
  16. EnterpriseServer,
  17. SohoServer,
  18. AppliancePc,
  19. PerformanceServer,
  20. Tablet,
  21. Reserved(u8),
  22. }
  23. /// Represents the Fixed ACPI Description Table (FADT). This table contains various fixed hardware
  24. /// details, such as the addresses of the hardware register blocks. It also contains a pointer to
  25. /// the Differentiated Definition Block (DSDT).
  26. ///
  27. /// In cases where the FADT contains both a 32-bit and 64-bit field for the same address, we should
  28. /// always prefer the 64-bit one. Only if it's zero or the CPU will not allow us to access that
  29. /// address should the 32-bit one be used.
  30. #[repr(C, packed)]
  31. pub struct Fadt {
  32. header: SdtHeader,
  33. firmware_ctrl: u32,
  34. dsdt_address: u32,
  35. // used in acpi 1.0; compatibility only, should be zero
  36. _reserved: u8,
  37. preferred_pm_profile: u8,
  38. sci_interrupt: u16,
  39. smi_cmd_port: u32,
  40. acpi_enable: u8,
  41. acpi_disable: u8,
  42. s4bios_req: u8,
  43. pstate_control: u8,
  44. pm1a_event_block: u32,
  45. pm1b_event_block: u32,
  46. pm1a_control_block: u32,
  47. pm1b_control_block: u32,
  48. pm2_control_block: u32,
  49. pm_timer_block: u32,
  50. gpe0_block: u32,
  51. gpe1_block: u32,
  52. pm1_event_length: u8,
  53. pm1_control_length: u8,
  54. pm2_control_length: u8,
  55. pm_timer_length: u8,
  56. gpe0_block_length: u8,
  57. gpe1_block_length: u8,
  58. gpe1_base: u8,
  59. c_state_control: u8,
  60. worst_c2_latency: u16,
  61. worst_c3_latency: u16,
  62. flush_size: u16,
  63. flush_stride: u16,
  64. duty_offset: u8,
  65. duty_width: u8,
  66. day_alarm: u8,
  67. month_alarm: u8,
  68. century: u8,
  69. iapc_boot_arch: u16,
  70. _reserved2: u8, // must be 0
  71. flags: u32,
  72. reset_reg: RawGenericAddress,
  73. reset_value: u8,
  74. arm_boot_arch: u16,
  75. fadt_minor_version: u8,
  76. x_firmware_ctrl: ExtendedField<u64, 2>,
  77. x_dsdt_address: ExtendedField<u64, 2>,
  78. x_pm1a_event_block: ExtendedField<RawGenericAddress, 2>,
  79. x_pm1b_event_block: ExtendedField<RawGenericAddress, 2>,
  80. x_pm1a_control_block: ExtendedField<RawGenericAddress, 2>,
  81. x_pm1b_control_block: ExtendedField<RawGenericAddress, 2>,
  82. x_pm2_control_block: ExtendedField<RawGenericAddress, 2>,
  83. x_pm_timer_block: ExtendedField<RawGenericAddress, 2>,
  84. x_gpe0_block: ExtendedField<RawGenericAddress, 2>,
  85. x_gpe1_block: ExtendedField<RawGenericAddress, 2>,
  86. sleep_control_reg: ExtendedField<RawGenericAddress, 2>,
  87. sleep_status_reg: ExtendedField<RawGenericAddress, 2>,
  88. hypervisor_vendor_id: ExtendedField<u64, 2>,
  89. }
  90. impl AcpiTable for Fadt {
  91. fn header(&self) -> &SdtHeader {
  92. &self.header
  93. }
  94. }
  95. impl Fadt {
  96. pub fn validate(&self) -> Result<(), AcpiError> {
  97. self.header.validate(crate::sdt::Signature::FADT)
  98. }
  99. pub fn dsdt_address(&self) -> Result<usize, AcpiError> {
  100. unsafe {
  101. self.x_dsdt_address
  102. .access(self.header.revision)
  103. .filter(|&p| p != 0)
  104. .or(Some(self.dsdt_address as u64))
  105. .filter(|p| *p != 0)
  106. .map(|p| p as usize)
  107. .ok_or(AcpiError::InvalidDsdtAddress)
  108. }
  109. }
  110. pub fn power_profile(&self) -> PowerProfile {
  111. match self.preferred_pm_profile {
  112. 0 => PowerProfile::Unspecified,
  113. 1 => PowerProfile::Desktop,
  114. 2 => PowerProfile::Mobile,
  115. 3 => PowerProfile::Workstation,
  116. 4 => PowerProfile::EnterpriseServer,
  117. 5 => PowerProfile::SohoServer,
  118. 6 => PowerProfile::AppliancePc,
  119. 7 => PowerProfile::PerformanceServer,
  120. 8 => PowerProfile::Tablet,
  121. other => PowerProfile::Reserved(other),
  122. }
  123. }
  124. }
  125. /// Information about the ACPI Power Management Timer (ACPI PM Timer).
  126. pub struct PmTimer {
  127. /// An I/O space address to the register block of ACPI PM Timer.
  128. pub io_base: u32,
  129. /// This field is true if the hardware supports 32-bit timer, and false if the hardware
  130. /// supports 24-bit timer.
  131. pub supports_32bit: bool,
  132. }
  133. impl PmTimer {
  134. /// Creates a new instance of `PmTimer`.
  135. pub fn new<H>(tables: &AcpiTables<H>) -> Result<PmTimer, AcpiError>
  136. where
  137. H: AcpiHandler,
  138. {
  139. let fadt = unsafe {
  140. tables
  141. .get_sdt::<Fadt>(crate::sdt::Signature::FADT)?
  142. .ok_or(AcpiError::TableMissing(crate::sdt::Signature::FADT))?
  143. };
  144. Ok(PmTimer { io_base: fadt.pm_timer_block, supports_32bit: fadt.flags.get_bit(8) })
  145. }
  146. }