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
use crate::arch::layout::PCIE_CONFIG_START;23
#[cfg(target_arch = "x86_64")]24
use crate::arch::layout::{25
APIC_START, IOAPIC_START, PORT_ACPI_RESET, PORT_ACPI_SLEEP_CONTROL, PORT_ACPI_SLEEP_STATUS,26
};27
use crate::utils::wrapping_sum;28
29
use 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
};36
use self::reg::FADT_RESET_VAL;37
38
const OEM_ID: [u8; 6] = *b"ALIOTH";39
40
fn 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-structure53
pub 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-xsdt65
pub 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-format80
pub 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-madt119
#[cfg(target_arch = "x86_64")]120
pub 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
170
pub 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
mcfg189
}190
191
pub 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
198
impl 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.rsdp223
}224
225
pub fn tables(&self) -> &[u8] {226
&self.tables227
}228
229
pub fn pointers(&self) -> &[usize] {230
&self.table_pointers231
}232
233
pub fn checksums(&self) -> &[(usize, usize)] {234
&self.table_checksums235
}236
237
pub fn take(self) -> (AcpiTableRsdp, Vec<u8>) {238
(self.rsdp, self.tables)239
}240
}241