1 pub mod interrupt;
2 
3 use crate::{
4     address::GenericAddress,
5     fadt::Fadt,
6     madt::Madt,
7     AcpiError,
8     AcpiHandler,
9     AcpiResult,
10     AcpiTables,
11     ManagedSlice,
12     PowerProfile,
13 };
14 use core::alloc::Allocator;
15 use interrupt::InterruptModel;
16 
17 #[derive(Clone, Copy, Debug, PartialEq, Eq)]
18 pub enum ProcessorState {
19     /// A processor in this state is unusable, and you must not attempt to bring it up.
20     Disabled,
21 
22     /// A processor waiting for a SIPI (Startup Inter-processor Interrupt) is currently not active,
23     /// but may be brought up.
24     WaitingForSipi,
25 
26     /// A Running processor is currently brought up and running code.
27     Running,
28 }
29 
30 #[derive(Clone, Copy, Debug, PartialEq, Eq)]
31 pub struct Processor {
32     /// Corresponds to the `_UID` object of the processor's `Device`, or the `ProcessorId` field of the `Processor`
33     /// object, in AML.
34     pub processor_uid: u32,
35     /// The ID of the local APIC of the processor. Will be less than `256` if the APIC is being used, but can be
36     /// greater than this if the X2APIC is being used.
37     pub local_apic_id: u32,
38 
39     /// The state of this processor. Check that the processor is not `Disabled` before attempting to bring it up!
40     pub state: ProcessorState,
41 
42     /// Whether this processor is the Bootstrap Processor (BSP), or an Application Processor (AP).
43     /// When the bootloader is entered, the BSP is the only processor running code. To run code on
44     /// more than one processor, you need to "bring up" the APs.
45     pub is_ap: bool,
46 }
47 
48 #[derive(Debug)]
49 pub struct ProcessorInfo<'a, A>
50 where
51     A: Allocator,
52 {
53     pub boot_processor: Processor,
54     /// Application processors should be brought up in the order they're defined in this list.
55     pub application_processors: ManagedSlice<'a, Processor, A>,
56 }
57 
58 impl<'a, A> ProcessorInfo<'a, A>
59 where
60     A: Allocator,
61 {
new(boot_processor: Processor, application_processors: ManagedSlice<'a, Processor, A>) -> Self62     pub(crate) fn new(boot_processor: Processor, application_processors: ManagedSlice<'a, Processor, A>) -> Self {
63         Self { boot_processor, application_processors }
64     }
65 }
66 
67 /// Information about the ACPI Power Management Timer (ACPI PM Timer).
68 #[derive(Debug)]
69 pub struct PmTimer {
70     /// A generic address to the register block of ACPI PM Timer.
71     pub base: GenericAddress,
72     /// This field is `true` if the hardware supports 32-bit timer, and `false` if the hardware supports 24-bit timer.
73     pub supports_32bit: bool,
74 }
75 
76 impl PmTimer {
new(fadt: &Fadt) -> Result<Option<PmTimer>, AcpiError>77     pub fn new(fadt: &Fadt) -> Result<Option<PmTimer>, AcpiError> {
78         match fadt.pm_timer_block()? {
79             Some(base) => Ok(Some(PmTimer { base, supports_32bit: { fadt.flags }.pm_timer_is_32_bit() })),
80             None => Ok(None),
81         }
82     }
83 }
84 
85 /// `PlatformInfo` allows the collection of some basic information about the platform from some of the fixed-size
86 /// tables in a nice way. It requires access to the `FADT` and `MADT`. It is the easiest way to get information
87 /// about the processors and interrupt controllers on a platform.
88 #[derive(Debug)]
89 pub struct PlatformInfo<'a, A>
90 where
91     A: Allocator,
92 {
93     pub power_profile: PowerProfile,
94     pub interrupt_model: InterruptModel<'a, A>,
95     /// On `x86_64` platforms that support the APIC, the processor topology must also be inferred from the
96     /// interrupt model. That information is stored here, if present.
97     pub processor_info: Option<ProcessorInfo<'a, A>>,
98     pub pm_timer: Option<PmTimer>,
99     /*
100      * TODO: we could provide a nice view of the hardware register blocks in the FADT here.
101      */
102 }
103 
104 #[cfg(feature = "alloc")]
105 impl<'a> PlatformInfo<'a, alloc::alloc::Global> {
new<H>(tables: &AcpiTables<H>) -> AcpiResult<Self> where H: AcpiHandler,106     pub fn new<H>(tables: &AcpiTables<H>) -> AcpiResult<Self>
107     where
108         H: AcpiHandler,
109     {
110         Self::new_in(tables, alloc::alloc::Global)
111     }
112 }
113 
114 impl<'a, A> PlatformInfo<'a, A>
115 where
116     A: Allocator + Clone,
117 {
new_in<H>(tables: &AcpiTables<H>, allocator: A) -> AcpiResult<Self> where H: AcpiHandler,118     pub fn new_in<H>(tables: &AcpiTables<H>, allocator: A) -> AcpiResult<Self>
119     where
120         H: AcpiHandler,
121     {
122         let fadt = tables.find_table::<Fadt>()?;
123         let power_profile = fadt.power_profile();
124 
125         let madt = tables.find_table::<Madt>();
126         let (interrupt_model, processor_info) = match madt {
127             Ok(madt) => madt.parse_interrupt_model_in(allocator)?,
128             Err(_) => (InterruptModel::Unknown, None),
129         };
130         let pm_timer = PmTimer::new(&fadt)?;
131 
132         Ok(PlatformInfo { power_profile, interrupt_model, processor_info, pm_timer })
133     }
134 }
135