1use vm_memory::{GuestAddress, GuestMemory, GuestMemoryError};
8
9pub mod aml;
10pub mod dsdt;
11pub mod fadt;
12pub mod madt;
13pub mod mcfg;
14pub mod rsdp;
15pub mod xsdt;
16
17pub use aml::Aml;
18pub use dsdt::Dsdt;
19pub use fadt::Fadt;
20pub use madt::Madt;
21pub use mcfg::Mcfg;
22pub use rsdp::Rsdp;
23pub use xsdt::Xsdt;
24use zerocopy::little_endian::{U32, U64};
25use zerocopy::{Immutable, IntoBytes};
26
27const FC_ACPI_CREATOR_ID: [u8; 4] = *b"FCAT";
29const FC_ACPI_CREATOR_REVISION: u32 = 0x20240119;
32
33fn checksum(buf: &[&[u8]]) -> u8 {
34 (255 - buf
35 .iter()
36 .flat_map(|b| b.iter())
37 .fold(0u8, |acc, x| acc.wrapping_add(*x)))
38 .wrapping_add(1)
39}
40
41#[derive(Debug, thiserror::Error, displaydoc::Display)]
42pub enum AcpiError {
43 GuestMemory(#[from] GuestMemoryError),
45 InvalidGuestAddress,
47 InvalidRegisterSize,
49}
50
51pub type Result<T> = std::result::Result<T, AcpiError>;
52
53#[repr(C, packed)]
55#[derive(IntoBytes, Immutable, Clone, Copy, Debug, Default)]
56pub struct GenericAddressStructure {
57 pub address_space_id: u8,
58 pub register_bit_width: u8,
59 pub register_bit_offset: u8,
60 pub access_size: u8,
61 pub address: U64,
62}
63
64impl GenericAddressStructure {
65 pub fn new(
66 address_space_id: u8,
67 register_bit_width: u8,
68 register_bit_offset: u8,
69 access_size: u8,
70 address: u64,
71 ) -> Self {
72 Self {
73 address_space_id,
74 register_bit_width,
75 register_bit_offset,
76 access_size,
77 address: U64::new(address),
78 }
79 }
80}
81
82#[repr(C, packed)]
84#[derive(Clone, Debug, Copy, Default, IntoBytes, Immutable)]
85pub struct SdtHeader {
86 pub signature: [u8; 4],
87 pub length: U32,
88 pub revision: u8,
89 pub checksum: u8,
90 pub oem_id: [u8; 6],
91 pub oem_table_id: [u8; 8],
92 pub oem_revision: U32,
93 pub creator_id: [u8; 4],
94 pub creator_revision: U32,
95}
96
97impl SdtHeader {
98 pub(crate) fn new(
99 signature: [u8; 4],
100 length: u32,
101 table_revision: u8,
102 oem_id: [u8; 6],
103 oem_table_id: [u8; 8],
104 oem_revision: u32,
105 ) -> Self {
106 SdtHeader {
107 signature,
108 length: U32::new(length),
109 revision: table_revision,
110 checksum: 0,
111 oem_id,
112 oem_table_id,
113 oem_revision: U32::new(oem_revision),
114 creator_id: FC_ACPI_CREATOR_ID,
115 creator_revision: U32::new(FC_ACPI_CREATOR_REVISION),
116 }
117 }
118}
119
120pub trait Sdt {
122 fn len(&self) -> usize;
124
125 fn is_empty(&self) -> bool {
127 self.len() == 0
128 }
129
130 fn write_to_guest<M: GuestMemory>(&mut self, mem: &M, address: GuestAddress) -> Result<()>;
132}
133
134#[cfg(test)]
135mod tests {
136 use super::checksum;
137
138 #[test]
139 fn test_checksum() {
140 assert_eq!(checksum(&[&[]]), 0u8);
141 assert_eq!(checksum(&[]), 0u8);
142 assert_eq!(checksum(&[&[1, 2, 3]]), 250u8);
143 assert_eq!(checksum(&[&[1, 2, 3], &[]]), 250u8);
144 assert_eq!(checksum(&[&[1, 2], &[3]]), 250u8);
145 assert_eq!(checksum(&[&[1, 2], &[3], &[250]]), 0u8);
146 assert_eq!(checksum(&[&[255]]), 1u8);
147 assert_eq!(checksum(&[&[1, 2], &[3], &[250], &[255]]), 1u8);
148 }
149}