1use crate::cpu;
2
3use super::ApicGenericAddress;
4
5#[allow(dead_code)]
6pub mod flags {
7 pub const PM_STS_TMR: u16 = 1 << 0;
9 pub const PM_STS_BM: u16 = 1 << 4;
10 pub const PM_STS_GBL: u16 = 1 << 5;
11 pub const PM_STS_PWRBTN: u16 = 1 << 8;
12 pub const PM_STS_SLPBTN: u16 = 1 << 9;
13 pub const PM_STS_RTC: u16 = 1 << 10;
14 pub const PM_STS_PCIEXP_WAKE: u16 = 1 << 14;
15 pub const PM_STS_WAK: u16 = 1 << 15;
16
17 pub const PM_EN_TMR: u16 = 1 << 0;
19 pub const PM_EN_GBL: u16 = 1 << 5;
20 pub const PM_EN_PWRBTN: u16 = 1 << 8;
21 pub const PM_EN_SLPBTN: u16 = 1 << 9;
22 pub const PM_EN_RTC: u16 = 1 << 10;
23 pub const PM_DIS_PCIEXP_WAKE: u16 = 1 << 14;
24
25 pub const PM_CTRL_SCI_EN: u16 = 1 << 0;
27 pub const PM_CTRL_BM_RLD: u16 = 1 << 1;
28 pub const PM_CTRL_GBL_RLS: u16 = 1 << 2;
29 pub const PM_CTRL_SLP_EN: u16 = 1 << 13;
30 pub const PM_CTRL_SLP_TYP_MASK: u16 = 0b111 << PM_CTRL_SLP_TYP_SHIFT;
31 pub const PM_CTRL_SLP_TYP_SHIFT: u8 = 10;
32}
33
34#[repr(C, packed)]
35#[derive(Debug, Clone)]
36pub struct Facp {
37 firmware_control: u32,
38 pub dsdt: u32,
39 reserved: u8,
40 preferred_pm_profile: u8,
41 sci_interrupt: u16,
42 smi_command_port: u32,
43 acpi_enable: u8,
44 acpi_disable: u8,
45 s4bios_req: u8,
46 pstate_control: u8,
47 pm1a_event_block: u32,
48 pm1b_event_block: u32,
49 pm1a_control_block: u32,
50 pm1b_control_block: u32,
51 pm2_control_block: u32,
52 pm_timer_block: u32,
53 gpe0_block: u32,
54 gpe1_block: u32,
55 pm1_event_length: u8,
56 pm1_control_length: u8,
57 pm2_control_length: u8,
58 pm_timer_length: u8,
59 gpe0_block_length: u8,
60 gpe1_block_length: u8,
61 gpe1_base: u8,
62 cstate_control: u8,
63 p_level2_latency: u16,
64 p_level3_latency: u16,
65 flush_size: u16,
66 flush_stride: u16,
67 duty_offset: u8,
68 duty_width: u8,
69 day_alarm: u8,
70 month_alarm: u8,
71 pub century: u8,
72 iapc_boot_arch: u16,
73 reserved2: u8,
74 flags: u32,
75 reset_reg: ApicGenericAddress,
76 reset_value: u8,
77 arm_boot_arch: u16,
78 fadt_minor_version: u8,
79 x_firmware_control: u64,
80 x_dsdt: u64,
81 x_pm1a_event_block: ApicGenericAddress,
82 x_pm1b_event_block: ApicGenericAddress,
83 x_pm1a_control_block: ApicGenericAddress,
84 x_pm1b_control_block: ApicGenericAddress,
85 x_pm2_control_block: ApicGenericAddress,
86 x_pm_timer_block: ApicGenericAddress,
87 x_gpe0_block: ApicGenericAddress,
88 x_gpe1_block: ApicGenericAddress,
89 sleep_control_reg: ApicGenericAddress,
90 sleep_status_reg: ApicGenericAddress,
91 hypervisor_vendor_id: u64,
92}
93
94#[allow(dead_code)]
95impl Facp {
96 pub fn sci_interrupt(&self) -> u8 {
97 assert!(self.sci_interrupt < 256);
98 assert!(self.sci_interrupt > 0);
99
100 self.sci_interrupt as u8
101 }
102
103 fn smi_command_port(&self) -> u16 {
104 assert!(self.smi_command_port > 0 && self.smi_command_port < 0xFFFF);
105 self.smi_command_port as u16
106 }
107
108 #[inline]
109 pub fn is_acpi_enabled(&self) -> bool {
110 (self.read_pm1_control() & 1) != 0
111 }
112
113 pub fn enable_acpi(&self) {
114 if self.is_acpi_enabled() {
115 return;
116 }
117 unsafe {
118 cpu::io_out(self.smi_command_port(), self.acpi_enable);
119 }
120 }
121
122 fn access_io_write(&self, register: u32, alt_register: Option<u32>, length: u8, value: u32) {
123 assert!(register > 0 && register < 0xFFFF);
124
125 match length {
126 2 => unsafe {
127 cpu::io_out::<u16>(
128 register as u16,
129 value.try_into().expect("Should be in u16 range"),
130 );
131 if let Some(alt_register) = alt_register {
132 assert!(alt_register > 0 && alt_register < 0xFFFF);
133 cpu::io_out::<u16>(
134 alt_register as u16,
135 value.try_into().expect("Should be in u16 range"),
136 );
137 }
138 },
139 4 => unsafe {
140 cpu::io_out::<u32>(register as u16, value);
141 if let Some(alt_register) = alt_register {
142 assert!(alt_register > 0 && alt_register < 0xFFFF);
143 cpu::io_out::<u32>(alt_register as u16, value);
144 }
145 },
146 _ => {
147 todo!("Can't handle `register length` of {}", length)
148 }
149 }
150 }
151
152 fn access_io_read(&self, register: u32, length: u8) -> u32 {
153 assert!(register > 0 && register < 0xFFFF);
154
155 match length {
156 2 => unsafe { cpu::io_in::<u16>(register as u16) as u32 },
157 4 => unsafe { cpu::io_in::<u32>(register as u16) },
158 _ => {
159 todo!("Can't handle `register length` of {}", length)
160 }
161 }
162 }
163
164 pub fn write_pm1_status(&self, value: u16) {
165 if !self.x_pm1a_event_block.is_zero() {
166 todo!("implement GenericAddress access");
167 }
168
169 let pm1_evt_part_len = self.pm1_event_length / 2;
170 let alt_reg = if self.pm1b_event_block == 0 {
171 None
172 } else {
173 Some(self.pm1b_event_block)
174 };
175
176 self.access_io_write(
177 self.pm1a_event_block,
178 alt_reg,
179 pm1_evt_part_len,
180 value as u32,
181 )
182 }
183
184 pub fn read_pm1_status(&self) -> u16 {
185 if !self.x_pm1a_event_block.is_zero() {
186 todo!("implement GenericAddress access");
187 }
188
189 let pm1_evt_part_len = self.pm1_event_length / 2;
190 self.access_io_read(self.pm1a_event_block, pm1_evt_part_len)
191 .try_into()
192 .expect("Should be in u16 range")
193 }
194
195 pub fn write_pm1_enable(&self, value: u16) {
196 if !self.x_pm1a_event_block.is_zero() {
197 todo!("implement GenericAddress access");
198 }
199
200 let pm1_evt_part_len = self.pm1_event_length / 2;
201 let alt_reg = if self.pm1b_event_block == 0 {
202 None
203 } else {
204 Some(self.pm1b_event_block + pm1_evt_part_len as u32)
205 };
206
207 self.access_io_write(
208 self.pm1a_event_block + pm1_evt_part_len as u32,
209 alt_reg,
210 pm1_evt_part_len,
211 value as u32,
212 )
213 }
214
215 pub fn read_pm1_enable(&self) -> u16 {
216 if !self.x_pm1a_event_block.is_zero() {
217 todo!("implement GenericAddress access");
218 }
219
220 let pm1_evt_part_len = self.pm1_event_length / 2;
221 self.access_io_read(
222 self.pm1a_event_block + pm1_evt_part_len as u32,
223 pm1_evt_part_len,
224 )
225 .try_into()
226 .expect("Should be in u16 range")
227 }
228
229 pub fn write_pm1_control(&self, value: u16) {
230 if !self.x_pm1a_control_block.is_zero() {
231 todo!("implement GenericAddress access");
232 }
233
234 let alt_reg = if self.pm1b_control_block == 0 {
235 None
236 } else {
237 Some(self.pm1b_control_block)
238 };
239 self.access_io_write(
240 self.pm1a_control_block,
241 alt_reg,
242 self.pm1_control_length,
243 value as u32,
244 )
245 }
246
247 pub fn read_pm1_control(&self) -> u16 {
248 if !self.x_pm1a_control_block.is_zero() {
249 todo!("implement GenericAddress access");
250 }
251
252 self.access_io_read(self.pm1a_control_block, self.pm1_control_length)
253 .try_into()
254 .expect("Should be in u16 range")
255 }
256
257 pub fn read_pm1_control_a(&self) -> u16 {
258 self.access_io_read(self.pm1a_control_block, self.pm1_control_length)
259 .try_into()
260 .expect("Should be in u16 range")
261 }
262
263 pub fn read_pm1_control_b(&self) -> Option<u16> {
264 if self.pm1b_control_block == 0 {
265 return None;
266 }
267
268 Some(
269 self.access_io_read(self.pm1b_control_block, self.pm1_control_length)
270 .try_into()
271 .expect("Should be in u16 range"),
272 )
273 }
274
275 pub fn write_pm1_control_a(&self, value: u16) {
276 self.access_io_write(
277 self.pm1a_control_block,
278 None,
279 self.pm1_control_length,
280 value as u32,
281 )
282 }
283
284 pub fn write_pm1_control_b(&self, value: u16) {
285 self.access_io_write(
286 self.pm1b_control_block,
287 None,
288 self.pm1_control_length,
289 value as u32,
290 )
291 }
292
293 pub fn read_pm_timer(&self) -> Option<u32> {
294 if !self.x_pm_timer_block.is_zero() {
295 todo!("implement GenericAddress access");
296 }
297
298 if self.pm_timer_block == 0 {
299 return None;
300 }
301 assert_eq!(self.pm_timer_length, 4);
302
303 Some(self.access_io_read(self.pm_timer_block, self.pm_timer_length))
304 }
305
306 pub fn write_pm2_control(&self, value: u16) -> Option<()> {
307 if !self.x_pm2_control_block.is_zero() {
308 todo!("implement GenericAddress access");
309 }
310
311 if self.pm2_control_block == 0 {
312 return None;
313 }
314
315 self.access_io_write(
316 self.pm2_control_block,
317 Some(self.pm2_control_block),
318 self.pm2_control_length,
319 value as u32,
320 );
321
322 Some(())
323 }
324
325 pub fn read_pm2_control(&self) -> Option<u16> {
326 if !self.x_pm2_control_block.is_zero() {
327 todo!("implement GenericAddress access");
328 }
329
330 if self.pm2_control_block == 0 {
331 return None;
332 }
333
334 Some(self.access_io_read(self.pm2_control_block, self.pm2_control_length) as u16)
335 }
336
337 fn gpe_reg_write(register: u32, length: u8, mut value: u32) {
338 assert!(register > 0 && register < 0xFFFF);
339 assert!(length <= 4);
340
341 for i in 0..length as u16 {
343 unsafe {
344 cpu::io_out::<u8>(register as u16 + i, (value & 0xff) as u8);
345 }
346
347 value >>= 8;
348 }
349 }
350
351 fn gpe_reg_read(register: u32, length: u8) -> u32 {
352 assert!(register > 0 && register < 0xFFFF);
353 assert!(length <= 4);
354
355 let mut result = 0;
356
357 for i in 0..length as u16 {
358 let s = unsafe { cpu::io_in::<u8>(register as u16 + i) as u32 };
359 result |= s << (i * 8);
360 }
361
362 result
363 }
364
365 pub fn write_gpe_0_event_status(&self, value: u32) -> Option<()> {
366 if !self.x_gpe0_block.is_zero() {
367 todo!("implement GenericAddress access");
368 }
369
370 if self.gpe0_block == 0 {
371 return None;
372 }
373
374 Self::gpe_reg_write(self.gpe0_block, self.gpe0_block_length / 2, value);
375
376 Some(())
377 }
378
379 pub fn read_gpe_0_event_status(&self) -> Option<u32> {
380 if !self.x_gpe0_block.is_zero() {
381 todo!("implement GenericAddress access");
382 }
383
384 if self.gpe0_block == 0 {
385 return None;
386 }
387
388 Some(Self::gpe_reg_read(
389 self.gpe0_block,
390 self.gpe0_block_length / 2,
391 ))
392 }
393
394 pub fn write_gpe_0_event_enable(&self, value: u16) -> Option<()> {
395 if !self.x_gpe0_block.is_zero() {
396 todo!("implement GenericAddress access");
397 }
398
399 if self.gpe0_block == 0 {
400 return None;
401 }
402
403 Self::gpe_reg_write(
404 self.gpe0_block + (self.gpe0_block_length / 2) as u32,
405 self.gpe0_block_length / 2,
406 value as u32,
407 );
408
409 Some(())
410 }
411
412 pub fn read_gpe_0_event_enable(&self) -> Option<u32> {
413 if !self.x_gpe0_block.is_zero() {
414 todo!("implement GenericAddress access");
415 }
416
417 if self.gpe0_block == 0 {
418 return None;
419 }
420
421 Some(Self::gpe_reg_read(
422 self.gpe0_block + (self.gpe0_block_length / 2) as u32,
423 self.gpe0_block_length / 2,
424 ))
425 }
426}