Skip to main content

acpi_lite/
apic.rs

1// Copyright 2026 The Fuchsia Authors
2//
3// Use of this source code is governed by a MIT-style
4// license that can be found in the LICENSE file or at
5// https://opensource.org/licenses/MIT
6
7use crate::binary_reader::{BinaryReader, DowncastFrom};
8use crate::structures::{
9    ACPI_MADT_FLAG_ENABLED, ACPI_MADT_TYPE_INT_SOURCE_OVERRIDE, ACPI_MADT_TYPE_IO_APIC,
10    ACPI_MADT_TYPE_LOCAL_APIC, AcpiMadtIntSourceOverrideEntry, AcpiMadtIoApicEntry,
11    AcpiMadtLocalApicEntry, AcpiMadtTable, AcpiSubTableHeader, VariableSized,
12};
13use crate::{AcpiParserInterface, get_table_by_type};
14use zx_status::Status;
15
16impl_downcast_from!(AcpiSubTableHeader =>
17    AcpiMadtLocalApicEntry,
18    AcpiMadtIoApicEntry,
19    AcpiMadtIntSourceOverrideEntry,
20);
21
22fn for_each_madt_entry_of_type<'a, T, F>(
23    parser: &'a dyn AcpiParserInterface,
24    r#type: u8,
25    mut visitor: F,
26) -> Result<(), Status>
27where
28    T: VariableSized + DowncastFrom<AcpiSubTableHeader> + 'a,
29    F: FnMut(&T) -> Result<(), Status>,
30{
31    let table = get_table_by_type::<AcpiMadtTable>(parser).ok_or(Status::NOT_FOUND)?;
32    let mut reader = BinaryReader::from_payload_of_struct(table);
33    while !reader.is_empty() {
34        let header = reader.read::<AcpiSubTableHeader>().ok_or(Status::INTERNAL)?;
35        if header.r#type != r#type {
36            continue;
37        }
38        // SAFETY: We verified that `header.r#type` matches the expected type for `T`
39        // by checking it against `r#type` passed to this function.
40        let entry = unsafe { T::downcast_from(header) }.ok_or(Status::INTERNAL)?;
41        visitor(entry)?;
42    }
43    Ok(())
44}
45
46// Enumerate all enabled Processor Local APICs in the system, calling
47// |callback| once for each.
48//
49// Each entry corresponds to an entry in the ACPI MADT table of type "Local
50// Apic". See ACPI v6.3 Section 5.2.12.2 for details.
51//
52// |callback| is invoked once for each entry. The function returns any error
53// returned by the callback, or if an error was found attempting to parse the
54// tables.
55pub fn enumerate_processor_local_apics<F>(
56    parser: &dyn AcpiParserInterface,
57    mut callback: F,
58) -> Result<(), Status>
59where
60    F: FnMut(&AcpiMadtLocalApicEntry) -> Result<(), Status>,
61{
62    for_each_madt_entry_of_type::<AcpiMadtLocalApicEntry, _>(
63        parser,
64        ACPI_MADT_TYPE_LOCAL_APIC,
65        |record| {
66            let flags = record.flags;
67            if (flags & ACPI_MADT_FLAG_ENABLED) == 0 {
68                return Ok(());
69            }
70            callback(record)
71        },
72    )
73}
74
75// Enumerate all IO APICs in the system, calling |callback| once for each.
76//
77// |callback| is called onced per IO APIC entry in the ACPI MADT table. The
78// function returns any error returned by the callback, or if an error was
79// found attempting to parse the tables.
80pub fn enumerate_io_apics<F>(parser: &dyn AcpiParserInterface, callback: F) -> Result<(), Status>
81where
82    F: FnMut(&AcpiMadtIoApicEntry) -> Result<(), Status>,
83{
84    for_each_madt_entry_of_type::<AcpiMadtIoApicEntry, F>(parser, ACPI_MADT_TYPE_IO_APIC, callback)
85}
86
87// Enumerate all ISA interrupt source override entries in the system MADT
88// table.
89//
90// By default, it is assumed that the first _n_ APIC interrupts correspond to
91// the first _n_ legacy ISA interrupts. Entries in this table record any
92// exceptions to this assumption.
93//
94// |callback| is called once per override entry in the ACPI MADT table. The
95// function returns any error returned by the callback, or if an error was
96// found attempting to parse the tables.
97pub fn enumerate_io_apic_isa_overrides<F>(
98    parser: &dyn AcpiParserInterface,
99    callback: F,
100) -> Result<(), Status>
101where
102    F: FnMut(&AcpiMadtIntSourceOverrideEntry) -> Result<(), Status>,
103{
104    for_each_madt_entry_of_type::<AcpiMadtIntSourceOverrideEntry, F>(
105        parser,
106        ACPI_MADT_TYPE_INT_SOURCE_OVERRIDE,
107        callback,
108    )
109}