fadt.rs 5.0 KB

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