diff --git a/src/dragonball/dbs_acpi/src/fadt.rs b/src/dragonball/dbs_acpi/src/fadt.rs new file mode 100644 index 0000000000..0956793720 --- /dev/null +++ b/src/dragonball/dbs_acpi/src/fadt.rs @@ -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 +} diff --git a/src/dragonball/dbs_acpi/src/lib.rs b/src/dragonball/dbs_acpi/src/lib.rs index a3094e3096..584722dcbe 100644 --- a/src/dragonball/dbs_acpi/src/lib.rs +++ b/src/dragonball/dbs_acpi/src/lib.rs @@ -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) } diff --git a/src/dragonball/dbs_acpi/src/madt.rs b/src/dragonball/dbs_acpi/src/madt.rs new file mode 100644 index 0000000000..1567ae4ec2 --- /dev/null +++ b/src/dragonball/dbs_acpi/src/madt.rs @@ -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 +} diff --git a/src/dragonball/dbs_acpi/src/sdt.rs b/src/dragonball/dbs_acpi/src/sdt.rs index 62d463458e..2b763dca87 100644 --- a/src/dragonball/dbs_acpi/src/sdt.rs +++ b/src/dragonball/dbs_acpi/src/sdt.rs @@ -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, } @@ -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; diff --git a/src/dragonball/src/vm/x86_64.rs b/src/dragonball/src/vm/x86_64.rs index cd075c047f..ae5dff798d 100644 --- a/src/dragonball/src/vm/x86_64.rs +++ b/src/dragonball/src/vm/x86_64.rs @@ -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 = Vec::new(); + let acpi_tables: Vec = 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( §ions, @@ -383,7 +386,7 @@ impl Vm { vm_memory: &GuestMemoryImpl, address_space: AddressSpace, hob_address: &mut u64, - acpi_tables: &Vec, + acpi_tables: &Vec, ) -> 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, + acpi_tables: &Vec, ) -> std::result::Result<(), StartMicroVmError> { let mut hob = TdHob::start(hob_address);