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
22use crate::arch::layout::PCIE_CONFIG_START;
23#[cfg(target_arch = "x86_64")]
24use crate::arch::layout::{
25 APIC_START, IOAPIC_START, PORT_ACPI_RESET, PORT_ACPI_SLEEP_CONTROL, PORT_ACPI_SLEEP_STATUS,
26};
27use crate::utils::wrapping_sum;
28
29use self::bindings::{
30 AcpiGenericAddress, AcpiMadtIoApic, AcpiMadtLocalX2apic, AcpiMcfgAllocation,
31 AcpiSubtableHeader, AcpiTableFadt, AcpiTableHeader, AcpiTableMadt, AcpiTableMcfg1,
32 AcpiTableRsdp, AcpiTableXsdt3, FADT_MAJOR_VERSION, FADT_MINOR_VERSION, MADT_IO_APIC,
33 MADT_LOCAL_X2APIC, MADT_REVISION, MCFG_REVISION, RSDP_REVISION, SIG_FADT, SIG_MADT, SIG_MCFG,
34 SIG_RSDP, SIG_XSDT, XSDT_REVISION,
35};
36use self::reg::FADT_RESET_VAL;
37
38const OEM_ID: [u8; 6] = *b"ALIOTH";
39
40fn default_header() -> AcpiTableHeader {
41 AcpiTableHeader {
42 checksum: 0,
43 oem_id: OEM_ID,
44 oem_table_id: *b"ALIOTHVM",
45 oem_revision: 1,
46 asl_compiler_id: *b"ALTH",
47 asl_compiler_revision: 1,
48 ..Default::default()
49 }
50}
51
52// 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
53pub fn create_rsdp(xsdt_addr: u64) -> AcpiTableRsdp {
54 AcpiTableRsdp {
55 signature: SIG_RSDP,
56 oem_id: OEM_ID,
57 revision: RSDP_REVISION,
58 length: size_of::<AcpiTableRsdp>() as u32,
59 xsdt_physical_address: transmute!(xsdt_addr),
60 ..Default::default()
61 }
62}
63
64// 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
65pub fn create_xsdt(entries: [u64; 3]) -> AcpiTableXsdt3 {
66 let total_length = size_of::<AcpiTableHeader>() + size_of::<u64>() * 3;
67 let entries = entries.map(|e| transmute!(e));
68 AcpiTableXsdt3 {
69 header: AcpiTableHeader {
70 signature: SIG_XSDT,
71 length: total_length as u32,
72 revision: XSDT_REVISION,
73 ..default_header()
74 },
75 entries,
76 }
77}
78
79// https://uefi.org/htmlspecs/ACPI_Spec_6_4_html/05_ACPI_Software_Programming_Model/ACPI_Software_Programming_Model.html#fadt-format
80pub fn create_fadt(dsdt_addr: u64) -> AcpiTableFadt {
81 AcpiTableFadt {
82 header: AcpiTableHeader {
83 signature: SIG_FADT,
84 revision: FADT_MAJOR_VERSION,
85 length: size_of::<AcpiTableFadt>() as u32,
86 ..default_header()
87 },
88 reset_register: AcpiGenericAddress {
89 space_id: 1,
90 bit_width: 8,
91 bit_offset: 0,
92 access_width: 1,
93 address: transmute!(PORT_ACPI_RESET as u64),
94 },
95 reset_value: FADT_RESET_VAL,
96 sleep_control: AcpiGenericAddress {
97 space_id: 1,
98 bit_width: 8,
99 bit_offset: 0,
100 access_width: 1,
101 address: transmute!(PORT_ACPI_SLEEP_CONTROL as u64),
102 },
103 sleep_status: AcpiGenericAddress {
104 space_id: 1,
105 bit_width: 8,
106 bit_offset: 0,
107 access_width: 1,
108 address: transmute!(PORT_ACPI_SLEEP_STATUS as u64),
109 },
110 flags: (1 << 20) | (1 << 10),
111 minor_revision: FADT_MINOR_VERSION,
112 hypervisor_id: *b"ALIOTH ",
113 xdsdt: transmute!(dsdt_addr),
114 ..Default::default()
115 }
116}
117
118// https://uefi.org/specs/ACPI/6.5/05_ACPI_Software_Programming_Model.html#multiple-apic-description-table-madt
119#[cfg(target_arch = "x86_64")]
120pub fn create_madt(apic_ids: &[u32]) -> (AcpiTableMadt, AcpiMadtIoApic, Vec<AcpiMadtLocalX2apic>) {
121 let total_length = size_of::<AcpiTableMadt>()
122 + size_of::<AcpiMadtIoApic>()
123 + apic_ids.len() * size_of::<AcpiMadtLocalX2apic>();
124 let mut checksum = 0u8;
125
126 let mut madt = AcpiTableMadt {
127 header: AcpiTableHeader {
128 signature: SIG_MADT,
129 length: total_length as u32,
130 revision: MADT_REVISION,
131 ..default_header()
132 },
133 address: APIC_START as u32,
134 flags: 0,
135 };
136 checksum = checksum.wrapping_sub(wrapping_sum(madt.as_bytes()));
137
138 let io_apic = AcpiMadtIoApic {
139 header: AcpiSubtableHeader {
140 type_: MADT_IO_APIC,
141 length: size_of::<AcpiMadtIoApic>() as u8,
142 },
143 id: 0,
144 address: IOAPIC_START as u32,
145 global_irq_base: 0,
146 ..Default::default()
147 };
148 checksum = checksum.wrapping_sub(wrapping_sum(io_apic.as_bytes()));
149
150 let mut x2apics = vec![];
151 for (index, apic_id) in apic_ids.iter().enumerate() {
152 let x2apic = AcpiMadtLocalX2apic {
153 header: AcpiSubtableHeader {
154 type_: MADT_LOCAL_X2APIC,
155 length: size_of::<AcpiMadtLocalX2apic>() as u8,
156 },
157 local_apic_id: *apic_id,
158 uid: index as u32,
159 lapic_flags: 1,
160 ..Default::default()
161 };
162 checksum = checksum.wrapping_sub(wrapping_sum(x2apic.as_bytes()));
163 x2apics.push(x2apic);
164 }
165 madt.header.checksum = checksum;
166
167 (madt, io_apic, x2apics)
168}
169
170pub fn create_mcfg() -> AcpiTableMcfg1 {
171 let mut mcfg = AcpiTableMcfg1 {
172 header: AcpiTableHeader {
173 signature: SIG_MCFG,
174 length: size_of::<AcpiTableMcfg1>() as u32,
175 revision: MCFG_REVISION,
176 ..default_header()
177 },
178 reserved: [0; 8],
179 allocations: [AcpiMcfgAllocation {
180 address: transmute!(PCIE_CONFIG_START),
181 pci_segment: 0,
182 start_bus_number: 0,
183 end_bus_number: 0,
184 ..Default::default()
185 }],
186 };
187 mcfg.header.checksum = 0u8.wrapping_sub(wrapping_sum(mcfg.as_bytes()));
188 mcfg
189}
190
191pub struct AcpiTable {
192 pub(crate) rsdp: AcpiTableRsdp,
193 pub(crate) tables: Vec<u8>,
194 pub(crate) table_pointers: Vec<usize>,
195 pub(crate) table_checksums: Vec<(usize, usize)>,
196}
197
198impl AcpiTable {
199 pub fn relocate(&mut self, table_addr: u64) {
200 let old_addr: u64 = transmute!(self.rsdp.xsdt_physical_address);
201 self.rsdp.xsdt_physical_address = transmute!(table_addr);
202
203 let sum = wrapping_sum(&self.rsdp.as_bytes()[0..20]);
204 self.rsdp.checksum = self.rsdp.checksum.wrapping_sub(sum);
205 let ext_sum = wrapping_sum(self.rsdp.as_bytes());
206 self.rsdp.extended_checksum = self.rsdp.extended_checksum.wrapping_sub(ext_sum);
207
208 for pointer in self.table_pointers.iter() {
209 let (old_val, _) = u64::read_from_prefix(&self.tables[*pointer..]).unwrap();
210 let new_val = old_val.wrapping_sub(old_addr).wrapping_add(table_addr);
211 IntoBytes::write_to_prefix(&new_val, &mut self.tables[*pointer..]).unwrap();
212 }
213
214 for (start, len) in self.table_checksums.iter() {
215 let sum = wrapping_sum(&self.tables[*start..(*start + *len)]);
216 let checksum = &mut self.tables[start + offset_of!(AcpiTableHeader, checksum)];
217 *checksum = checksum.wrapping_sub(sum);
218 }
219 }
220
221 pub fn rsdp(&self) -> &AcpiTableRsdp {
222 &self.rsdp
223 }
224
225 pub fn tables(&self) -> &[u8] {
226 &self.tables
227 }
228
229 pub fn pointers(&self) -> &[usize] {
230 &self.table_pointers
231 }
232
233 pub fn checksums(&self) -> &[(usize, usize)] {
234 &self.table_checksums
235 }
236
237 pub fn take(self) -> (AcpiTableRsdp, Vec<u8>) {
238 (self.rsdp, self.tables)
239 }
240}
241