Skip to content

Commit

Permalink
TDX: Declare MultiprocessorWakeup structure.
Browse files Browse the repository at this point in the history
Also add more documentation for the other existing structures.

BUG: 357604639
Change-Id: Idde493c511c59ac1ef92e46e2b77a9e65c455795
  • Loading branch information
ernoc committed Oct 15, 2024
1 parent a8a3436 commit 3150abf
Show file tree
Hide file tree
Showing 2 changed files with 109 additions and 17 deletions.
98 changes: 89 additions & 9 deletions stage0/src/acpi_tables.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@
// limitations under the License.
//

/// Defines ACPI structures based on ACPI specification.
/// You can find this specification here:
/// https://uefi.org/htmlspecs/ACPI_Spec_6_4_html/05_ACPI_Software_Programming_Model/ACPI_Software_Programming_Model.html
use core::{marker::PhantomData, mem::size_of, ops::Deref, slice};

use bitflags::bitflags;
Expand Down Expand Up @@ -369,6 +372,10 @@ bitflags! {
/// Multiple APIC Description Table (MADT).
///
/// See Section 5.2.12 in the ACPI specification for more details.
/// Note that the MADT has the same fields as the RSDT plus a few more,
/// the first few fields are the same. These common fields are represented
/// by DescriptionHeader; here we reuse that and add the remaining fields.
/// Table 5.19 of ACPI Spec lists the fields.
#[derive(Debug)]
#[repr(C, packed)]
pub struct Madt {
Expand All @@ -380,13 +387,18 @@ pub struct Madt {
/// Multiple APIC flags.
flags: MadtFlags,
// This is followed by a dynamic number of variable-length interrupt controller structures,
// which unfortunately can't be expressed in safe Rust.
// which unfortunately can't be expressed in safe Rust. See ControllerHeader below.
}

/// Header for values in MADT field "Interrupt Controller Structure".
/// This is the last field in the MADT and can appear N times, each time
/// containing a different structure (e.g. ProcessorLocalApic) and length
/// according to its type. However, all of these structures look the same in
/// their first 2 fields - we factor them here for reuse and call it a header.
#[derive(Clone, Copy, Debug)]
#[repr(C, packed)]
pub struct ControllerHeader {
pub structure_type: u8,
pub structure_type: ControllerStructureType,
len: u8,
}

Expand All @@ -408,6 +420,20 @@ impl ControllerHeader {
}
}

/// Structure type for an entry in the field "Interrupt Controller Structure"
/// in the MADT. Valid types documented in Table 5.21 of ACPI Specification.
/// Only adding here the types that we currently use.
#[derive(Debug, Clone, Copy, PartialEq)]
#[repr(u8)]
pub enum ControllerStructureType {
ProcessorLocalApic = 0,
ProcessorLocalX2Apic = 9,
MultiprocessorWakeup = 0x10,
}

/// Processor Local Apic Structure.
/// One of the possible structures in MADT's Interrupt Controller Structure
/// field. Documented in section 5.2.12.2 of APIC Specification.
#[derive(Debug)]
#[repr(C, packed)]
pub struct ProcessorLocalApic {
Expand All @@ -424,10 +450,8 @@ pub struct ProcessorLocalApic {
}

impl ProcessorLocalApic {
pub const STRUCTURE_TYPE: u8 = 0;

pub fn new(header: &ControllerHeader) -> Result<&Self, &'static str> {
if header.structure_type != Self::STRUCTURE_TYPE {
if header.structure_type != ControllerStructureType::ProcessorLocalApic {
return Err("structure is not Processor Local APIC Structure");
}
header.validate()?;
Expand All @@ -437,6 +461,9 @@ impl ProcessorLocalApic {
}
}

/// Processor Local x2APIC structure.
/// One of the possible structures in MADT's Interrupt Controller Structure
/// field. Documented in section 5.2.12.12 of APIC Specification.
#[derive(Debug)]
#[repr(C, packed)]
pub struct ProcessorLocalX2Apic {
Expand All @@ -459,10 +486,8 @@ pub struct ProcessorLocalX2Apic {
}

impl ProcessorLocalX2Apic {
pub const STRUCTURE_TYPE: u8 = 9;

pub fn new(header: &ControllerHeader) -> Result<&Self, &'static str> {
if header.structure_type != Self::STRUCTURE_TYPE {
if header.structure_type != ControllerStructureType::ProcessorLocalX2Apic {
return Err("structure is not Processor Local X2APIC Structure");
}
header.validate()?;
Expand All @@ -472,6 +497,50 @@ impl ProcessorLocalX2Apic {
}
}

/// Multiprocessor Wakeup structure.
/// One of the possible structures in MADT's Interrupt Controller Structure
/// field. Documented in section 5.2.12.19 of APIC Specification.
#[derive(Debug)]
#[repr(C, packed)]
pub struct MultiprocessorWakeup {
/// Interrupt structure common header.
/// Type must be 0x10, length must be 16.
header: ControllerHeader,

/// MailBox version: must be set to 0.
mailbox_version: u16,

/// 4 bytes reserved.
_reserved: [u8; 4],

/// Physical address of the mailbox. It must be in ACPINvs. It must also be
/// 4K bytes aligned. Memory declared in stage0_bin/layout.ld. Mailbox
/// structure defined in table 5.44 of ACPI Spec.
pub mailbox_address: u8,
}

impl MultiprocessorWakeup {
const MULTIPROCESSOR_WAKEUP_STRUCTURE_LENGTH: u8 = 16;

/// Gets a reference to a MultiprocessorWakeup given a reference to its
/// first field (header). This assumes that the memory that immediately
/// follows header is actually a MultiprocessorWakeup.
pub fn from_header_cast(header: &ControllerHeader) -> Result<&Self, &'static str> {
if header.structure_type != ControllerStructureType::MultiprocessorWakeup {
return Err("structure is not MultiprocessorWakeup");
}
if header.len != Self::MULTIPROCESSOR_WAKEUP_STRUCTURE_LENGTH {
return Err("MultiprocessorWakeup structure length must be 16");
}
header.validate()?;

let header_raw_pointer = header as *const _ as *const Self;
// Deref to get a &Self. Safety: we're verified correct structure type.
// There's no guarantee the actual structure comforms to that type.
Ok(unsafe { &*(header_raw_pointer) })
}
}

impl Madt {
pub const SIGNATURE: &'static [u8; 4] = b"APIC";

Expand All @@ -492,13 +561,24 @@ impl Madt {
Ok(())
}

pub fn iter(&self) -> MadtIterator<'_> {
/// Create an iterator over entries of field Interrupt Controller Structure
/// that returns references to the entries' headers.
pub fn controller_struct_headers(&self) -> MadtIterator<'_> {
// The Madt struct does not itself contain the interrupt controller
// entries (see struct Madt above) but these entries are expected to
// exist right after the Madt struct. Therefore, we set the offset to
// point to one byte after, which is size_of Madt.
MadtIterator { madt: self, offset: size_of::<Madt>() }
}
}

pub struct MadtIterator<'a> {
madt: &'a Madt,

/// Offset with respect to where Madt starts where the first interrupt
/// controller entry starts. The first interrupt controller entry
/// should be right after the Madt struct ends, and its address should be
/// address of Madt (madt, above) + length of madt (offset)
offset: usize,
}

Expand Down
28 changes: 20 additions & 8 deletions stage0/src/smp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,10 @@ use core::{
use x86_64::{structures::paging::Size4KiB, PhysAddr};

use crate::{
acpi_tables::{LocalApicFlags, Madt, ProcessorLocalApic, ProcessorLocalX2Apic, Rsdp},
acpi_tables::{
ControllerStructureType, LocalApicFlags, Madt, MultiprocessorWakeup, ProcessorLocalApic,
ProcessorLocalX2Apic, Rsdp,
},
apic::Lapic,
pic::disable_pic8259,
Platform,
Expand Down Expand Up @@ -104,21 +107,30 @@ pub fn bootstrap_aps<P: Platform>(rsdp: &Rsdp) -> Result<(), &'static str> {
// APIC and X2APIC structures are largely the same; X2APIC entries are used if
// the APIC ID is too large to fit into the one-byte field of the APIC
// structure (e.g. if you have more than 256 CPUs).
for item in madt.iter() {
let (remote_lapic_id, flags) = match item.structure_type {
ProcessorLocalApic::STRUCTURE_TYPE => {
let remote_lapic = ProcessorLocalApic::new(item)?;
for controller_header in madt.controller_struct_headers() {
let (remote_lapic_id, flags) = match controller_header.structure_type {
ControllerStructureType::ProcessorLocalApic => {
let remote_lapic = ProcessorLocalApic::new(controller_header)?;
log::debug!("Local APIC: {:?}", remote_lapic);
(remote_lapic.apic_id as u32, remote_lapic.flags)
}
ProcessorLocalX2Apic::STRUCTURE_TYPE => {
let remote_lapic = ProcessorLocalX2Apic::new(item)?;
ControllerStructureType::ProcessorLocalX2Apic => {
let remote_lapic = ProcessorLocalX2Apic::new(controller_header)?;
log::debug!("Local X2APIC: {:?}", remote_lapic);
(remote_lapic.x2apic_id, remote_lapic.flags)
}
ControllerStructureType::MultiprocessorWakeup => {
let multiprocessor_wakeup =
MultiprocessorWakeup::from_header_cast(controller_header)?;
log::debug!(
"Found a MultiprocessorWakeup :D MailBox address: {:?}",
multiprocessor_wakeup.mailbox_address
);
continue;
}
// We don't care about other interrupt controller structure types.
_ => {
log::debug!("uninteresting structure: {}", item.structure_type);
log::debug!("uninteresting structure: {:?}", controller_header.structure_type);
continue;
}
};
Expand Down

0 comments on commit 3150abf

Please sign in to comment.