Merge pull request #13063 from RainaYL/rainax/acpi_pr

dragonball: Add basic ACPI implementation for TDX boot
This commit is contained in:
Alex Lyn
2026-05-21 17:04:59 +08:00
committed by GitHub
5 changed files with 318 additions and 6 deletions

View File

@@ -0,0 +1,121 @@
// Copyright (c) 2026 Ant Group
//
// SPDX-License-Identifier: Apache-2.0
//
use crate::sdt::{GenericAddress, Sdt};
use vm_memory::ByteValued;
#[repr(C, packed)]
#[derive(Default, Copy, Clone)]
#[allow(non_snake_case)]
pub struct FadtBody {
pub FirmwareCtrl: u32,
pub Dsdt: u32,
pub Reserved: u8,
pub PreferredPowerManagementProfile: u8,
pub SCI_Interrupt: u16,
pub SMI_CommandPort: u32,
pub AcpiEnable: u8,
pub AcpiDisable: u8,
pub S4BIOS_REQ: u8,
pub PSTATE_Control: u8,
pub PM1aEventBlock: u32,
pub PM1bEventBlock: u32,
pub PM1aControlBlock: u32,
pub PM1bControlBlock: u32,
pub PM2ControlBlock: u32,
pub PMTimerBlock: u32,
pub GPE0Block: u32,
pub GPE1Block: u32,
pub PM1EventLength: u8,
pub PM1ControlLength: u8,
pub PM2ControlLength: u8,
pub PMTimerLength: u8,
pub GPE0Length: u8,
pub GPE1Length: u8,
pub GPE1Base: u8,
pub CStateControl: u8,
pub WorstC2Latency: u16,
pub WorstC3Latency: u16,
pub FlushSize: u16,
pub FlushStride: u16,
pub DutyOffset: u8,
pub DutyWidth: u8,
pub DayAlarm: u8,
pub MonthAlarm: u8,
pub Century: u8,
pub BootArchitectureFlags: u16,
pub Reserved2: u8,
pub Flags: u32,
pub ResetReg: GenericAddress,
pub ResetValue: u8,
pub ArmBootArch: u16,
pub FadtMinorVersion: u8,
pub X_FirmwareControl: u64,
pub X_Dsdt: u64,
pub X_PM1aEventBlock: GenericAddress,
pub X_PM1bEventBlock: GenericAddress,
pub X_PM1aControlBlock: GenericAddress,
pub X_PM1bControlBlock: GenericAddress,
pub X_PM2ControlBlock: GenericAddress,
pub X_PMTimerBlock: GenericAddress,
pub X_GPE0Block: GenericAddress,
pub X_GPE1Block: GenericAddress,
pub SleepControlReg: GenericAddress,
pub SleepStatusReg: GenericAddress,
pub HypervisorVendorIdentity: u64,
}
unsafe impl ByteValued for FadtBody {}
impl FadtBody {
pub fn new() -> Self {
FadtBody {
SCI_Interrupt: 9,
PM1aEventBlock: 0xb000,
PM1aControlBlock: 0xb004,
PMTimerBlock: 0xb008,
GPE0Block: 0xb020,
PM1EventLength: 4,
PM1ControlLength: 2,
PMTimerLength: 4,
GPE0Length: 2,
BootArchitectureFlags: 1,
Flags: (1 << 0) | (1 << 8) | (1 << 9) | (1 << 10),
X_PM1aEventBlock: GenericAddress {
address_space_id: 1,
register_bit_width: 32,
register_bit_offset: 0,
access_size: 3,
address: 0xb000,
},
X_PM1aControlBlock: GenericAddress {
address_space_id: 1,
register_bit_width: 16,
register_bit_offset: 0,
access_size: 2,
address: 0xb004,
},
X_PMTimerBlock: GenericAddress {
address_space_id: 1,
register_bit_width: 32,
register_bit_offset: 0,
access_size: 3,
address: 0xb008,
},
..Default::default()
}
}
}
pub fn create_fadt_table() -> Sdt {
let mut fadt = Sdt::new(*b"FACP", 36, 6);
fadt.append_slice(FadtBody::new().as_slice());
fadt
}

View File

@@ -2,9 +2,22 @@
// Copyright (c) 2023 Alibaba Cloud
//
// SPDX-License-Identifier: Apache-2.0
// Please refer to the official ACPI 6.0 documentation:
// https://uefi.org/sites/default/files/resources/ACPI_6.0.pdf
// for specification of ACPI tables.
#![allow(missing_docs)]
pub mod fadt;
pub mod madt;
pub mod rsdp;
pub mod sdt;
pub use fadt::create_fadt_table;
pub use madt::create_madt_table;
pub use sdt::create_dsdt_table;
fn generate_checksum(data: &[u8]) -> u8 {
(255 - data.iter().fold(0u8, |acc, x| acc.wrapping_add(*x))).wrapping_add(1)
}

View File

@@ -0,0 +1,164 @@
// Copyright (c) 2026 Ant Group
//
// SPDX-License-Identifier: Apache-2.0
//
use crate::sdt::Sdt;
use vm_memory::ByteValued;
const IOAPIC_START: u32 = 0xfec0_0000;
const APIC_START: u32 = 0xfee0_0000;
const MADT_CPU_ENABLE_FLAG: usize = 0;
#[repr(u8)]
#[derive(Default, Copy, Clone)]
pub enum MadtEntryType {
#[default]
LocalApic,
Ioapic,
InterruptSourceOverride,
LocalX2Apic = 9,
}
#[repr(C, packed)]
#[derive(Default, Copy, Clone)]
pub struct MadtBody {
pub apic_address: u32,
pub flags: u32,
}
impl MadtBody {
pub fn new(apic_address: u32, flags: u32) -> Self {
Self {
apic_address,
flags,
}
}
}
#[repr(C, packed)]
#[derive(Default, Copy, Clone)]
pub struct MadtEntryLocalApic {
pub r#type: MadtEntryType,
pub length: u8,
pub processor_id: u8,
pub apic_id: u8,
pub flags: u32,
}
impl MadtEntryLocalApic {
pub fn new(processor_id: u8, flags: u32) -> Self {
Self {
r#type: MadtEntryType::LocalApic,
length: 8,
processor_id,
apic_id: processor_id,
flags,
}
}
}
#[repr(C, packed)]
#[derive(Default, Copy, Clone)]
pub struct MadtEntryIoapic {
pub r#type: MadtEntryType,
pub length: u8,
pub ioapic_id: u8,
pub reserved: u8,
pub ioapic_address: u32,
pub gsi_base: u32,
}
impl MadtEntryIoapic {
pub fn new(ioapic_id: u8, ioapic_address: u32, gsi_base: u32) -> Self {
Self {
r#type: MadtEntryType::Ioapic,
length: 12,
ioapic_id,
reserved: 0,
ioapic_address,
gsi_base,
}
}
}
#[repr(C, packed)]
#[derive(Default, Copy, Clone)]
pub struct MadtEntryIntrSrcOverride {
pub r#type: MadtEntryType,
pub length: u8,
pub bus_source: u8,
pub irq_source: u8,
pub gsi: u32,
pub flags: u16,
}
impl MadtEntryIntrSrcOverride {
pub fn new(bus_source: u8, irq_source: u8, gsi: u32, flags: u16) -> Self {
Self {
r#type: MadtEntryType::InterruptSourceOverride,
length: 10,
bus_source,
irq_source,
gsi,
flags,
}
}
}
#[repr(C, packed)]
#[derive(Default, Copy, Clone)]
pub struct MadtEntryLocalX2Apic {
r#type: MadtEntryType,
length: u8,
reserved: u16,
x2apic_id: u32,
flags: u32,
processor_id: u32,
}
impl MadtEntryLocalX2Apic {
pub fn new(processor_id: u32, flags: u32) -> Self {
Self {
r#type: MadtEntryType::LocalX2Apic,
length: 16,
reserved: 0,
// TODO: Calculate x2apic id from processor id
x2apic_id: processor_id,
flags,
processor_id,
}
}
}
unsafe impl ByteValued for MadtBody {}
unsafe impl ByteValued for MadtEntryLocalApic {}
unsafe impl ByteValued for MadtEntryIoapic {}
unsafe impl ByteValued for MadtEntryIntrSrcOverride {}
unsafe impl ByteValued for MadtEntryLocalX2Apic {}
pub fn create_madt_table(max_vcpus: u8, boot_vcpus: u8) -> Sdt {
let mut madt = Sdt::new(*b"APIC", 36, 5);
madt.append_slice(MadtBody::new(APIC_START, 0).as_slice());
for cpu_id in 0..max_vcpus {
madt.append_slice(
MadtEntryLocalApic::new(
cpu_id,
if cpu_id < boot_vcpus {
1 << MADT_CPU_ENABLE_FLAG
} else {
0
},
)
.as_slice(),
);
}
madt.append_slice(MadtEntryIoapic::new(0, IOAPIC_START, 0).as_slice());
madt.append_slice(MadtEntryIntrSrcOverride::new(0, 2, 2, 0).as_slice());
madt
}

View File

@@ -2,7 +2,11 @@
// Copyright (c) 2023 Alibaba Cloud
//
// SPDX-License-Identifier: Apache-2.0
#[repr(Rust, packed)]
use vm_memory::ByteValued;
#[repr(C, packed)]
#[derive(Copy, Clone, Default)]
pub struct GenericAddress {
pub address_space_id: u8,
pub register_bit_width: u8,
@@ -33,6 +37,8 @@ impl GenericAddress {
}
}
unsafe impl ByteValued for GenericAddress {}
pub struct Sdt {
data: Vec<u8>,
}
@@ -116,6 +122,11 @@ impl Sdt {
self.data.len()
}
}
pub fn create_dsdt_table() -> Sdt {
Sdt::new(*b"DSDT", 36, 2)
}
#[cfg(test)]
mod tests {
use super::Sdt;

View File

@@ -10,7 +10,7 @@ use std::collections::HashMap;
use std::convert::TryInto;
use std::ops::Deref;
use dbs_acpi::sdt::Sdt;
use dbs_acpi::*;
use dbs_address_space::{AddressSpace, AddressSpaceRegionType};
use dbs_boot::{
add_e820_entry, bootparam, layout, mptable, tdshim::*, BootParamsWrapper, FirmwareType,
@@ -215,8 +215,11 @@ impl Vm {
.cloned()
.ok_or(StartMicroVmError::GuestMemoryNotInitialized)?;
let mut hob_address = 0;
// TODO: Fill the empty list with ACPI table content
let acpi_tables: Vec<Sdt> = Vec::new();
let acpi_tables: Vec<sdt::Sdt> = vec![
create_madt_table(self.vm_config.max_vcpu_count, self.vm_config.vcpu_count),
create_fadt_table(),
create_dsdt_table(),
];
self.load_kernel_with_tdshim(
&sections,
@@ -383,7 +386,7 @@ impl Vm {
vm_memory: &GuestMemoryImpl,
address_space: AddressSpace,
hob_address: &mut u64,
acpi_tables: &Vec<Sdt>,
acpi_tables: &Vec<sdt::Sdt>,
) -> std::result::Result<(), StartMicroVmError> {
let mut required_sections = vec!["Bfv", "TdHob", "PayloadParam"];
@@ -461,7 +464,7 @@ impl Vm {
vm_memory: &GuestMemoryImpl,
address_space: AddressSpace,
payload_info: PayloadInfo,
acpi_tables: &Vec<Sdt>,
acpi_tables: &Vec<sdt::Sdt>,
) -> std::result::Result<(), StartMicroVmError> {
let mut hob = TdHob::start(hob_address);