Skip to main content

alioth/device/fw_cfg/
acpi.rs

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
15use std::mem::{offset_of, size_of};
16
17use zerocopy::{Immutable, IntoBytes};
18
19use crate::device::fw_cfg::{FILE_NAME_SIZE, FwCfgContent, FwCfgItem, create_file_name};
20use crate::firmware::acpi::AcpiTable;
21use crate::firmware::acpi::bindings::{AcpiTableHeader, AcpiTableRsdp};
22
23pub const COMMAND_ALLOCATE: u32 = 0x1;
24pub const COMMAND_ADD_POINTER: u32 = 0x2;
25pub const COMMAND_ADD_CHECKSUM: u32 = 0x3;
26
27pub const ALLOC_ZONE_HIGH: u8 = 0x1;
28pub const ALLOC_ZONE_FSEG: u8 = 0x2;
29
30pub const FW_CFG_FILENAME_TABLE_LOADER: &str = "etc/table-loader";
31pub const FW_CFG_FILENAME_RSDP: &str = "acpi/rsdp";
32pub const FW_CFG_FILENAME_ACPI_TABLES: &str = "acpi/tables";
33
34#[repr(C, align(4))]
35#[derive(Debug, IntoBytes, Immutable)]
36pub struct Allocate {
37    command: u32,
38    file: [u8; FILE_NAME_SIZE],
39    align: u32,
40    zone: u8,
41    _pad: [u8; 63],
42}
43
44#[repr(C, align(4))]
45#[derive(Debug, IntoBytes, Immutable)]
46pub struct AddPointer {
47    command: u32,
48    dst: [u8; FILE_NAME_SIZE],
49    src: [u8; FILE_NAME_SIZE],
50    offset: u32,
51    size: u8,
52    _pad: [u8; 7],
53}
54
55#[repr(C, align(4))]
56#[derive(Debug, IntoBytes, Immutable)]
57pub struct AddChecksum {
58    command: u32,
59    file: [u8; FILE_NAME_SIZE],
60    offset: u32,
61    start: u32,
62    len: u32,
63    _pad: [u8; 56],
64}
65
66fn create_intra_pointer(name: &str, offset: usize, size: u8) -> AddPointer {
67    AddPointer {
68        command: COMMAND_ADD_POINTER,
69        dst: create_file_name(name),
70        src: create_file_name(name),
71        offset: offset as u32,
72        size,
73        _pad: [0; 7],
74    }
75}
76
77fn create_acpi_table_checksum(offset: usize, len: usize) -> AddChecksum {
78    AddChecksum {
79        command: COMMAND_ADD_CHECKSUM,
80        file: create_file_name(FW_CFG_FILENAME_ACPI_TABLES),
81        offset: (offset + offset_of!(AcpiTableHeader, checksum)) as u32,
82        start: offset as u32,
83        len: len as u32,
84        _pad: [0; 56],
85    }
86}
87
88pub fn create_acpi_loader(mut acpi_table: AcpiTable) -> [FwCfgItem; 3] {
89    acpi_table.relocate(0);
90    acpi_table.clear_checksums();
91    let mut table_loader_bytes: Vec<u8> = Vec::new();
92    let allocate_rsdp = Allocate {
93        command: COMMAND_ALLOCATE,
94        file: create_file_name(FW_CFG_FILENAME_RSDP),
95        align: 4,
96        zone: ALLOC_ZONE_FSEG,
97        _pad: [0; 63],
98    };
99    table_loader_bytes.extend(allocate_rsdp.as_bytes());
100
101    let allocate_tables = Allocate {
102        command: COMMAND_ALLOCATE,
103        file: create_file_name(FW_CFG_FILENAME_ACPI_TABLES),
104        align: 4,
105        zone: ALLOC_ZONE_HIGH,
106        _pad: [0; 63],
107    };
108    table_loader_bytes.extend(allocate_tables.as_bytes());
109
110    for pinter_offset in acpi_table.pointers().iter() {
111        let pinter = create_intra_pointer(FW_CFG_FILENAME_ACPI_TABLES, *pinter_offset, 8);
112        table_loader_bytes.extend(pinter.as_bytes());
113    }
114    for (offset, len) in acpi_table.checksums().iter() {
115        let checksum = create_acpi_table_checksum(*offset, *len);
116        table_loader_bytes.extend(checksum.as_bytes());
117    }
118    let pointer_rsdp_to_xsdt = AddPointer {
119        command: COMMAND_ADD_POINTER,
120        dst: create_file_name(FW_CFG_FILENAME_RSDP),
121        src: create_file_name(FW_CFG_FILENAME_ACPI_TABLES),
122        offset: offset_of!(AcpiTableRsdp, xsdt_physical_address) as u32,
123        size: 8,
124        _pad: [0; 7],
125    };
126    table_loader_bytes.extend(pointer_rsdp_to_xsdt.as_bytes());
127    let checksum_rsdp = AddChecksum {
128        command: COMMAND_ADD_CHECKSUM,
129        file: create_file_name(FW_CFG_FILENAME_RSDP),
130        offset: offset_of!(AcpiTableRsdp, checksum) as u32,
131        start: 0,
132        len: offset_of!(AcpiTableRsdp, length) as u32,
133        _pad: [0; 56],
134    };
135    let checksum_rsdp_ext = AddChecksum {
136        command: COMMAND_ADD_CHECKSUM,
137        file: create_file_name(FW_CFG_FILENAME_RSDP),
138        offset: offset_of!(AcpiTableRsdp, extended_checksum) as u32,
139        start: 0,
140        len: size_of::<AcpiTableRsdp>() as u32,
141        _pad: [0; 56],
142    };
143    table_loader_bytes.extend(checksum_rsdp.as_bytes());
144    table_loader_bytes.extend(checksum_rsdp_ext.as_bytes());
145
146    let table_loader = FwCfgItem {
147        name: FW_CFG_FILENAME_TABLE_LOADER.to_owned(),
148        content: FwCfgContent::Bytes(table_loader_bytes),
149    };
150    let (rsdp, tables) = acpi_table.take();
151    let acpi_rsdp = FwCfgItem {
152        name: FW_CFG_FILENAME_RSDP.to_owned(),
153        content: FwCfgContent::Bytes(rsdp.as_bytes().to_owned()),
154    };
155    let apci_tables = FwCfgItem {
156        name: FW_CFG_FILENAME_ACPI_TABLES.to_owned(),
157        content: FwCfgContent::Bytes(tables),
158    };
159    [table_loader, acpi_rsdp, apci_tables]
160}
161
162#[cfg(test)]
163#[path = "acpi_test.rs"]
164mod tests;