kernel/acpi/tables/
facp.rs

1use crate::cpu;
2
3use super::ApicGenericAddress;
4
5#[allow(dead_code)]
6pub mod flags {
7    // Power Management Status Register flags
8    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    // Power Management Enable Register flags
18    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    // Power Management Control Register flags
26    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        // GPE is accessible by bytes regardless of the length
342        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}