Alioth Code Coverage

acpi.rs0.00%

1// Copyright 2024 Google LLC
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// https://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15pub mod bindings;
16pub mod reg;
17
18use std::mem::{offset_of, size_of};
19
20use zerocopy::{FromBytes, IntoBytes, transmute};
21
22#[cfg(target_arch = "x86_64")]
23use crate::arch::layout::{
24 APIC_START, IOAPIC_START, PORT_ACPI_RESET, PORT_ACPI_SLEEP_CONTROL, PORT_ACPI_SLEEP_STATUS,
25};
26use crate::arch::layout::{PCIE_CONFIG_START, PORT_ACPI_TIMER};
27use crate::firmware::acpi::bindings::AcpiFadtFlag;
28use crate::utils::wrapping_sum;
29
30use self::bindings::{
31 AcpiGenericAddress, AcpiMadtIoApic, AcpiMadtLocalX2apic, AcpiMcfgAllocation,
32 AcpiSubtableHeader, AcpiTableFadt, AcpiTableHeader, AcpiTableMadt, AcpiTableMcfg1,
33 AcpiTableRsdp, AcpiTableXsdt3, FADT_MAJOR_VERSION, FADT_MINOR_VERSION, MADT_IO_APIC,
34 MADT_LOCAL_X2APIC, MADT_REVISION, MCFG_REVISION, RSDP_REVISION, SIG_FADT, SIG_MADT, SIG_MCFG,
35 SIG_RSDP, SIG_XSDT, XSDT_REVISION,
36};
37use self::reg::FADT_RESET_VAL;
38
39const OEM_ID: [u8; 6] = *b"ALIOTH";
40
41fn default_header() -> AcpiTableHeader {
42 AcpiTableHeader {
43 checksum: 0,
44 oem_id: OEM_ID,
45 oem_table_id: *b"ALIOTHVM",
46 oem_revision: 1,
47 asl_compiler_id: *b"ALTH",
48 asl_compiler_revision: 1,
49 ..Default::default()
50 }
51}
52
53// https://uefi.org/htmlspecs/ACPI_Spec_6_4_html/05_ACPI_Software_Programming_Model/ACPI_Software_Programming_Model.html#root-system-description-pointer-rsdp-structure
54pub fn create_rsdp(xsdt_addr: u64) -> AcpiTableRsdp {
55 AcpiTableRsdp {
56 signature: SIG_RSDP,
57 oem_id: OEM_ID,
58 revision: RSDP_REVISION,
59 length: size_of::<AcpiTableRsdp>() as u32,
60 xsdt_physical_address: transmute!(xsdt_addr),
61 ..Default::default()
62 }
63}
64
65// https://uefi.org/htmlspecs/ACPI_Spec_6_4_html/05_ACPI_Software_Programming_Model/ACPI_Software_Programming_Model.html#extended-system-description-table-fields-xsdt
66pub fn create_xsdt(entries: [u64; 3]) -> AcpiTableXsdt3 {
67 let total_length = size_of::<AcpiTableHeader>() + size_of::<u64>() * 3;
68 let entries = entries.map(|e| transmute!(e));
69 AcpiTableXsdt3 {
70 header: AcpiTableHeader {
71 signature: SIG_XSDT,
72 length: total_length as u32,
73 revision: XSDT_REVISION,
74 ..default_header()
75 },
76 entries,
77 }
78}
79
80// https://uefi.org/htmlspecs/ACPI_Spec_6_4_html/05_ACPI_Software_Programming_Model/ACPI_Software_Programming_Model.html#fadt-format
81pub fn create_fadt(dsdt_addr: u64) -> AcpiTableFadt {
82 AcpiTableFadt {
83 header: AcpiTableHeader {
84 signature: SIG_FADT,
85 revision: FADT_MAJOR_VERSION,
86 length: size_of::<AcpiTableFadt>() as u32,
87 ..default_header()
88 },
89 reset_register: AcpiGenericAddress {
90 space_id: 1,
91 bit_width: 8,
92 bit_offset: 0,
93 access_width: 1,
94 address: transmute!(PORT_ACPI_RESET as u64),
95 },
96 reset_value: FADT_RESET_VAL,
97 xpm_timer_block: AcpiGenericAddress {
98 space_id: 1,
99 bit_width: 32,
100 bit_offset: 0,
101 access_width: 3,
102 address: transmute!(PORT_ACPI_TIMER as u64),
103 },
104 sleep_control: AcpiGenericAddress {
105 space_id: 1,
106 bit_width: 8,
107 bit_offset: 0,
108 access_width: 1,
109 address: transmute!(PORT_ACPI_SLEEP_CONTROL as u64),
110 },
111 sleep_status: AcpiGenericAddress {
112 space_id: 1,
113 bit_width: 8,
114 bit_offset: 0,
115 access_width: 1,
116 address: transmute!(PORT_ACPI_SLEEP_STATUS as u64),
117 },
118 flags: AcpiFadtFlag::HW_REDUCED_ACPI
119 | AcpiFadtFlag::RESET_REG_SUP
120 | AcpiFadtFlag::TMR_VAL_EXT,
121 minor_revision: FADT_MINOR_VERSION,
122 hypervisor_id: *b"ALIOTH ",
123 xdsdt: transmute!(dsdt_addr),
124 ..Default::default()
125 }
126}
127
128// https://uefi.org/specs/ACPI/6.5/05_ACPI_Software_Programming_Model.html#multiple-apic-description-table-madt
129#[cfg(target_arch = "x86_64")]
130pub fn create_madt(apic_ids: &[u32]) -> (AcpiTableMadt, AcpiMadtIoApic, Vec<AcpiMadtLocalX2apic>) {
131 let total_length = size_of::<AcpiTableMadt>()
132 + size_of::<AcpiMadtIoApic>()
133 + apic_ids.len() * size_of::<AcpiMadtLocalX2apic>();
134 let mut checksum = 0u8;
135
136 let mut madt = AcpiTableMadt {
137 header: AcpiTableHeader {
138 signature: SIG_MADT,
139 length: total_length as u32,
140 revision: MADT_REVISION,
141 ..default_header()
142 },
143 address: APIC_START as u32,
144 flags: 0,
145 };
146 checksum = checksum.wrapping_sub(wrapping_sum(madt.as_bytes()));
147
148 let io_apic = AcpiMadtIoApic {
149 header: AcpiSubtableHeader {
150 type_: MADT_IO_APIC,
151 length: size_of::<AcpiMadtIoApic>() as u8,
152 },
153 id: 0,
154 address: IOAPIC_START as u32,
155 global_irq_base: 0,
156 ..Default::default()
157 };
158 checksum = checksum.wrapping_sub(wrapping_sum(io_apic.as_bytes()));
159
160 let mut x2apics = vec![];
161 for (index, apic_id) in apic_ids.iter().enumerate() {
162 let x2apic = AcpiMadtLocalX2apic {
163 header: AcpiSubtableHeader {
164 type_: MADT_LOCAL_X2APIC,
165 length: size_of::<AcpiMadtLocalX2apic>() as u8,
166 },
167 local_apic_id: *apic_id,
168 uid: index as u32,
169 lapic_flags: 1,
170 ..Default::default()
171 };
172 checksum = checksum.wrapping_sub(wrapping_sum(x2apic.as_bytes()));
173 x2apics.push(x2apic);
174 }
175 madt.header.checksum = checksum;
176
177 (madt, io_apic, x2apics)
178}
179
180pub fn create_mcfg() -> AcpiTableMcfg1 {
181 let mut mcfg = AcpiTableMcfg1 {
182 header: AcpiTableHeader {
183 signature: SIG_MCFG,
184 length: size_of::<AcpiTableMcfg1>() as u32,
185 revision: MCFG_REVISION,
186 ..default_header()
187 },
188 reserved: [0; 8],
189 allocations: [AcpiMcfgAllocation {
190 address: transmute!(PCIE_CONFIG_START),
191 pci_segment: 0,
192 start_bus_number: 0,
193 end_bus_number: 0,
194 ..Default::default()
195 }],
196 };
197 mcfg.header.checksum = 0u8.wrapping_sub(wrapping_sum(mcfg.as_bytes()));
198 mcfg
199}
200
201pub struct AcpiTable {
202 pub(crate) rsdp: AcpiTableRsdp,
203 pub(crate) tables: Vec<u8>,
204 pub(crate) table_pointers: Vec<usize>,
205 pub(crate) table_checksums: Vec<(usize, usize)>,
206}
207
208impl AcpiTable {
209 pub fn relocate(&mut self, table_addr: u64) {
210 let old_addr: u64 = transmute!(self.rsdp.xsdt_physical_address);
211 self.rsdp.xsdt_physical_address = transmute!(table_addr);
212
213 for pointer in self.table_pointers.iter() {
214 let (old_val, _) = u64::read_from_prefix(&self.tables[*pointer..]).unwrap();
215 let new_val = old_val.wrapping_sub(old_addr).wrapping_add(table_addr);
216 IntoBytes::write_to_prefix(&new_val, &mut self.tables[*pointer..]).unwrap();
217 }
218 }
219
220 pub fn update_checksums(&mut self) {
221 let sum = wrapping_sum(&self.rsdp.as_bytes()[0..20]);
222 self.rsdp.checksum = self.rsdp.checksum.wrapping_sub(sum);
223 let ext_sum = wrapping_sum(self.rsdp.as_bytes());
224 self.rsdp.extended_checksum = self.rsdp.extended_checksum.wrapping_sub(ext_sum);
225
226 for (start, len) in self.table_checksums.iter() {
227 let sum = wrapping_sum(&self.tables[*start..(*start + *len)]);
228 let checksum = &mut self.tables[start + offset_of!(AcpiTableHeader, checksum)];
229 *checksum = checksum.wrapping_sub(sum);
230 }
231 }
232
233 pub fn clear_checksums(&mut self) {
234 for (start, _) in self.table_checksums.iter() {
235 let checksum = &mut self.tables[start + offset_of!(AcpiTableHeader, checksum)];
236 *checksum = 0;
237 }
238 self.rsdp.checksum = 0;
239 self.rsdp.extended_checksum = 0;
240 }
241
242 pub fn rsdp(&self) -> &AcpiTableRsdp {
243 &self.rsdp
244 }
245
246 pub fn tables(&self) -> &[u8] {
247 &self.tables
248 }
249
250 pub fn pointers(&self) -> &[usize] {
251 &self.table_pointers
252 }
253
254 pub fn checksums(&self) -> &[(usize, usize)] {
255 &self.table_checksums
256 }
257
258 pub fn take(self) -> (AcpiTableRsdp, Vec<u8>) {
259 (self.rsdp, self.tables)
260 }
261}
262