Respect local X2Apic MADT entry

This commit is contained in:
Zhang Junyang 2025-03-29 19:21:25 +08:00 committed by Ruihan Li
parent 07792a1b1c
commit 09a8ab8800
2 changed files with 52 additions and 16 deletions

View File

@ -27,6 +27,8 @@
//! This sequence does not need to be strictly followed, and there may be
//! different considerations in different systems.
use acpi::madt::MadtEntry;
use crate::{
arch::x86::kernel::{
acpi::get_acpi_tables,
@ -45,19 +47,54 @@ use crate::{
/// This function needs to be called after the OS initializes the ACPI table.
pub(crate) fn get_num_processors() -> Option<u32> {
let acpi_tables = get_acpi_tables()?;
let mut local_apic_counts = 0;
acpi_tables
.find_table::<acpi::madt::Madt>()
.unwrap()
let madt_table = acpi_tables.find_table::<acpi::madt::Madt>().ok()?;
// In the UEFI spec [1], for compatibility, the firmware will provide
// "Processor X2APIC structure" for local APIC ID values >= 255 and
// "Processor APIC structure" for local APIC ID values < 255, even if it is
// in the x2APIC mode.
// [1]: https://uefi.org/htmlspecs/ACPI_Spec_6_4_html/05_ACPI_Software_Programming_Model/ACPI_Software_Programming_Model.html#processor-local-x2apic-structure
let local_apic_counts = madt_table
.get()
.entries()
.for_each(|entry| {
if let acpi::madt::MadtEntry::LocalApic(_) = entry {
local_apic_counts += 1;
.filter(|e| match e {
MadtEntry::LocalX2Apic(entry) => {
let processor_uid = entry.processor_uid;
let x2apic_id = entry.x2apic_id;
log::trace!(
"Found a local x2APIC entry in MADT: processor UID = {}, x2APIC ID = {}",
processor_uid,
x2apic_id,
);
true
}
});
MadtEntry::LocalApic(entry) => {
let processor_id = entry.processor_id;
let apic_id = entry.apic_id as u32;
log::trace!(
"Found a local APIC entry in MADT: processor ID = {}, APIC ID = {}",
processor_id,
apic_id,
);
// Check if APIC entries also show up as x2APIC entries.
if madt_table
.get()
.entries()
.any(|e| matches!(e, MadtEntry::LocalX2Apic(e) if e.x2apic_id == apic_id))
{
log::warn!(
"Firmware bug: in MADT, APIC ID {} is also listed as a x2APIC ID",
apic_id
);
return false;
}
true
}
_ => false,
})
.count();
Some(local_apic_counts)
Some(local_apic_counts as u32)
}
/// Brings up all application processors.

View File

@ -8,8 +8,8 @@ use core::sync::atomic::{AtomicBool, Ordering};
use spin::Once;
use crate::{
arch::boot::smp::{bringup_all_aps, get_num_processors},
cpu,
arch::boot::smp::bringup_all_aps,
cpu::{self, num_cpus},
mm::{
frame::{meta::KernelMeta, Segment},
paddr_to_vaddr, FrameAllocOptions, PAGE_SIZE,
@ -49,12 +49,11 @@ static AP_LATE_ENTRY: Once<fn()> = Once::new();
/// However, the function need to be called before any `cpu_local!` variables are
/// accessed, including the APIC instance.
pub fn boot_all_aps() {
// TODO: support boot protocols without ACPI tables, e.g., Multiboot
let Some(num_cpus) = get_num_processors() else {
log::warn!("No processor information found. The kernel operates with a single processor.");
let num_cpus = num_cpus() as u32;
if num_cpus == 1 {
return;
};
log::info!("Found {} processors.", num_cpus);
}
log::info!("Booting {} processors.", num_cpus - 1);
// We currently assumes that bootstrap processor (BSP) have always the
// processor ID 0. And the processor ID starts from 0 to `num_cpus - 1`.