acpi.rs0.00%
1
// Copyright 2024 Google LLC2
//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 at6
//7
// https://www.apache.org/licenses/LICENSE-2.08
//9
// Unless required by applicable law or agreed to in writing, software10
// 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 and13
// limitations under the License.14
15
pub mod bindings;16
pub mod reg;17
18
use std::mem::{offset_of, size_of};19
20
use zerocopy::{FromBytes, IntoBytes, transmute};21
22
#[cfg(target_arch = "x86_64")]23
use crate::arch::layout::{24
APIC_START, IOAPIC_START, PORT_ACPI_RESET, PORT_ACPI_SLEEP_CONTROL, PORT_ACPI_SLEEP_STATUS,25
};26
use crate::arch::layout::{PCIE_CONFIG_START, PORT_ACPI_TIMER};27
use crate::firmware::acpi::bindings::AcpiFadtFlag;28
use crate::utils::wrapping_sum;29
30
use 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
};37
use self::reg::FADT_RESET_VAL;38
39
const OEM_ID: [u8; 6] = *b"ALIOTH";40
41
fn 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-structure54
pub 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-xsdt66
pub 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-format81
pub 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_ACPI119
| AcpiFadtFlag::RESET_REG_SUP120
| 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-madt129
#[cfg(target_arch = "x86_64")]130
pub 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
180
pub 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
mcfg199
}200
201
pub 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
208
impl 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.rsdp244
}245
246
pub fn tables(&self) -> &[u8] {247
&self.tables248
}249
250
pub fn pointers(&self) -> &[usize] {251
&self.table_pointers252
}253
254
pub fn checksums(&self) -> &[(usize, usize)] {255
&self.table_checksums256
}257
258
pub fn take(self) -> (AcpiTableRsdp, Vec<u8>) {259
(self.rsdp, self.tables)260
}261
}262