Skip to content

Conversation

@mayank-microsoft
Copy link
Contributor

adding additional code to read the CPU count from ACPI table.

Copilot AI review requested due to automatic review settings November 6, 2025 14:48
@mayank-microsoft mayank-microsoft requested review from a team as code owners November 6, 2025 14:48
@github-actions github-actions bot added the unsafe Related to unsafe code label Nov 6, 2025
@github-actions
Copy link

github-actions bot commented Nov 6, 2025

⚠️ Unsafe Code Detected

This PR modifies files containing unsafe Rust code. Extra scrutiny is required during review.

For more on why we check whole files, instead of just diffs, check out the Rustonomicon

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

This PR implements ACPI table parsing in the UEFI environment to dynamically determine the number of logical processors from the MADT (Multiple APIC Description Table), replacing a hardcoded processor count.

  • Adds a new acpi_wrap module with functions to parse ACPI tables (RSDP, XSDT, MADT)
  • Updates get_vp_count() to use actual APIC count from MADT instead of returning a hardcoded value of 4
  • Adds acpi_spec dependency to support ACPI table parsing

Reviewed Changes

Copilot reviewed 5 out of 6 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
opentmk/src/uefi/acpi_wrap.rs New module implementing ACPI table parsing to extract processor count from MADT
opentmk/src/uefi/mod.rs Exposes the new acpi_wrap module and fixes entry attribute syntax
opentmk/src/platform/hyperv/arch/x86_64/ctx.rs Updates get_vp_count() to call ACPI parsing on UEFI, returns error on other platforms
opentmk/src/tmkdefs.rs Adds new AcpiError variant to the error enum
opentmk/Cargo.toml Adds acpi_spec dependency
Cargo.lock Updates lock file with acpi_spec dependency

fn get_vp_count(&self) -> TmkResult<u32> {
// TODO: use ACPI to get the actual count
Ok(4)
#[cfg(target_os = "uefi")]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When are we not uefi?

let system_table = uefi::table::system_table_raw();

if system_table.is_none() {
return Err(TmkError::AcpiError);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These errors should carry more detail so we can tell which of these conditions we've hit.

return Err(TmkError::AcpiError);
}

let mut system_table = system_table.unwrap();
Copy link
Contributor

@smalis-msft smalis-msft Nov 13, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

let Ok(system_table) = system_table else { return Err(TmkError::AcpiError) };

// SAFETY: UEFI guarantees that the configuration table pointer is valid for the number of entries
let config_slice = unsafe { core::slice::from_raw_parts(config_table_ptr, config_count) };

let find = |guid| {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

just inline this if it's only used once?

use crate::tmkdefs::TmkError;
use crate::tmkdefs::TmkResult;

fn get_rsdp_ptr() -> TmkResult<NonNull<Rsdp>> {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this function return a &'static Rsdp instead? Is that safe to do? It'd be more useful to its callers that way at least.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same applies to other functions in here.

Ok(NonNull::new(xsdt_address as *mut Header).ok_or(TmkError::AcpiError)?)
}

fn get_madt_ptr() -> TmkResult<NonNull<Header>> {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we have some sort of AcpiContext that gets carried around and saved so that we don't have to repeat this parsing if we call get_apic_count_from_madt multiple times?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Like we could provide platform contexts with an AcpiContext that finds all the tables ahead of time and holds on to an XsdtParser, MadtParser, RsdpParser, etc, and then we don't have to repeat any of the parsing ever.

})
.map(|u64| {
// SAFETY: the address is valid as it was found in the ACPI tables, UEFI guarantees their validity
unsafe { transmute::<*const c_void, &Header>(*u64 as *const c_void) }
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should avoid using transmute whenever possible, use the pointer methods for casting and as_ref instead.

use crate::tmkdefs::TmkResult;

fn get_rsdp_ptr() -> TmkResult<NonNull<Rsdp>> {
let system_table = uefi::table::system_table_raw();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would it be more worthwhile to move some of this code into acpi_spec as a SystemTableParser, RsdpParser, etc, even if they don't expose everything those tables have just yet?

@github-actions
Copy link

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

unsafe Related to unsafe code

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants