acpi_tables/
fadt.rs

1// Copyright 2024 Amazon.com, Inc. or its affiliates. All Rights Reserved.
2// Copyright 2023 Rivos, Inc.
3//
4// SPDX-License-Identifier: Apache-2.0
5
6use vm_memory::{Bytes, GuestAddress, GuestMemory};
7use zerocopy::little_endian::{U16, U32, U64};
8use zerocopy::{Immutable, IntoBytes};
9
10use crate::{GenericAddressStructure, Result, Sdt, SdtHeader, checksum};
11
12#[cfg(target_arch = "x86_64")]
13pub const IAPC_BOOT_ARG_FLAGS_VGA_NOT_PRESENT: u16 = 2;
14#[cfg(target_arch = "x86_64")]
15pub const IAPC_BOOT_ARG_FLAGS_MSI_NOT_PRESENT: u16 = 3;
16#[cfg(target_arch = "x86_64")]
17pub const IAPC_BOOT_ARG_FLAGS_PCI_ASPM: u16 = 4;
18
19// ACPI Flags. Reading from the specification here:
20// https://uefi.org/specs/ACPI/6.5/05_ACPI_Software_Programming_Model.html#fixed-acpi-description-table-fixed-feature-flags
21
22/// Flag for the Power Button functionality.
23/// If the system does not have a power button, this value would be “1” and no power button device
24/// would be present
25pub const FADT_F_PWR_BUTTON: u8 = 4;
26/// Flag for the Sleep Button Functionality.
27/// If the system does not have a sleep button, this value would be “1” and no power button device
28/// would be present
29pub const FADT_F_SLP_BUTTON: u8 = 5;
30/// Flag for Hardware Reduced API. If enabled, software-only alternatives are used for supported
31/// fixed features.
32pub const FADT_F_HW_REDUCED_ACPI: u8 = 20;
33
34// clippy doesn't understand that we actually "use" the fields of this struct when we serialize
35// them as bytes in guest memory, so here we just ignore dead code to avoid having to name
36// everything with an underscore prefix
37#[allow(dead_code)]
38/// Fixed ACPI Description Table (FADT)
39///
40/// This table includes fixed hardware ACPI information such as addresses of register blocks and
41/// the pointer to the DSDT table.
42/// More information about this table can be found in the ACPI specification:
43/// https://uefi.org/specs/ACPI/6.5/05_ACPI_Software_Programming_Model.html#fixed-acpi-description-table-fadt
44#[repr(C, packed)]
45#[derive(Debug, Copy, Clone, Default, IntoBytes, Immutable)]
46pub struct Fadt {
47    header: SdtHeader,
48    firmware_control: U32,
49    dsdt: U32,
50    reserved_1: u8,
51    preferred_pm_profile: u8,
52    // In HW-reduced mode, fields starting from SCI_INT until CENTURY are ignored
53    sci_int: U16,
54    smi_cmd: U32,
55    acpi_enable: u8,
56    acpi_disable: u8,
57    s4bios_req: u8,
58    pstate_cnt: u8,
59    pm1a_evt_blk: U32,
60    pm1b_evt_blk: U32,
61    pm1a_cnt_blk: U32,
62    pm1b_cnt_blk: U32,
63    pm2_cnt_blk: U32,
64    pm_tmr_blk: U32,
65    gpe0_blk: U32,
66    gpe1_blk: U32,
67    pm1_evt_len: u8,
68    pm1_cnt_len: u8,
69    pm2_cnt_len: u8,
70    pm_tmr_len: u8,
71    gpe0_blk_len: u8,
72    gpe1_blk_len: u8,
73    gpe1_base: u8,
74    cst_cnt: u8,
75    p_lvl2_lat: U16,
76    p_lvl3_lat: U16,
77    flush_size: U16,
78    flush_stride: U16,
79    duty_offset: u8,
80    duty_width: u8,
81    day_alrm: u8,
82    mon_alrm: u8,
83    century: u8,
84    iapc_boot_arch: U16,
85    reserved_2: u8,
86    flags: U32,
87    reset_reg: GenericAddressStructure,
88    reset_value: u8,
89    arm_boot_arch: U16,
90    fadt_minor_version: u8,
91    x_firmware_ctrl: U64,
92    x_dsdt: U64,
93    // In HW-reduced mode, fields starting from X_PM1a_EVT_BLK through X_GPE1_BLK
94    // are ignored
95    x_pm1a_evt_blk: GenericAddressStructure,
96    x_pm1b_evt_blk: GenericAddressStructure,
97    x_pm1a_cnt_blk: GenericAddressStructure,
98    x_pm1b_cnt_blk: GenericAddressStructure,
99    x_pm2_cnt_blk: GenericAddressStructure,
100    x_pm_tmr_blk: GenericAddressStructure,
101    x_gpe0_blk: GenericAddressStructure,
102    x_gpe1_blk: GenericAddressStructure,
103    sleep_control_reg: GenericAddressStructure,
104    sleep_status_reg: GenericAddressStructure,
105    hypervisor_vendor_id: [u8; 8],
106}
107
108impl Fadt {
109    pub fn new(oem_id: [u8; 6], oem_table_id: [u8; 8], oem_revision: u32) -> Self {
110        let header = SdtHeader::new(
111            *b"FACP",
112            // It's fine to unwrap here, we know that the size of the Fadt structure fits in 32
113            // bits.
114            std::mem::size_of::<Self>().try_into().unwrap(),
115            6, // revision 6
116            oem_id,
117            oem_table_id,
118            oem_revision,
119        );
120
121        Fadt {
122            header,
123            fadt_minor_version: 5,
124            ..Default::default()
125        }
126    }
127
128    /// Set the address of the DSDT table
129    ///
130    /// This sets the 64bit variant, X_DSDT field of the FADT table
131    pub fn set_x_dsdt(&mut self, addr: u64) {
132        self.x_dsdt = U64::new(addr);
133    }
134
135    /// Set the FADT flags
136    pub fn set_flags(&mut self, flags: u32) {
137        self.flags = U32::new(flags);
138    }
139
140    /// Set the IA-PC specific flags
141    pub fn setup_iapc_flags(&mut self, flags: u16) {
142        self.iapc_boot_arch = U16::new(flags);
143    }
144
145    /// Set the hypervisor vendor ID
146    pub fn set_hypervisor_vendor_id(&mut self, hypervisor_vendor_id: [u8; 8]) {
147        self.hypervisor_vendor_id = hypervisor_vendor_id;
148    }
149}
150
151impl Sdt for Fadt {
152    fn len(&self) -> usize {
153        self.header.length.get().try_into().unwrap()
154    }
155
156    fn write_to_guest<M: GuestMemory>(&mut self, mem: &M, address: GuestAddress) -> Result<()> {
157        self.header.checksum = checksum(&[self.as_bytes()]);
158        mem.write_slice(self.as_bytes(), address)?;
159        Ok(())
160    }
161}