1pub mod interrupt;
2
3use crate::{
4 address::GenericAddress,
5 fadt::Fadt,
6 madt::{Madt, MadtError, MpProtectedModeWakeupCommand, MultiprocessorWakeupMailbox},
7 AcpiError,
8 AcpiHandler,
9 AcpiResult,
10 AcpiTables,
11 ManagedSlice,
12 PowerProfile,
13};
14use core::{alloc::Allocator, mem, ptr};
15use interrupt::InterruptModel;
16
17#[derive(Clone, Copy, Debug, PartialEq, Eq)]
18pub enum ProcessorState {
19 Disabled,
21
22 WaitingForSipi,
25
26 Running,
28}
29
30#[derive(Clone, Copy, Debug, PartialEq, Eq)]
31pub struct Processor {
32 pub processor_uid: u32,
35 pub local_apic_id: u32,
38
39 pub state: ProcessorState,
41
42 pub is_ap: bool,
46}
47
48#[derive(Debug, Clone)]
49pub struct ProcessorInfo<'a, A>
50where
51 A: Allocator,
52{
53 pub boot_processor: Processor,
54 pub application_processors: ManagedSlice<'a, Processor, A>,
56}
57
58impl<'a, A> ProcessorInfo<'a, A>
59where
60 A: Allocator,
61{
62 pub(crate) fn new(boot_processor: Processor, application_processors: ManagedSlice<'a, Processor, A>) -> Self {
63 Self { boot_processor, application_processors }
64 }
65}
66
67#[derive(Debug, Clone)]
69pub struct PmTimer {
70 pub base: GenericAddress,
72 pub supports_32bit: bool,
74}
75
76impl PmTimer {
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#[derive(Debug, Clone)]
89pub struct PlatformInfo<'a, A>
90where
91 A: Allocator,
92{
93 pub power_profile: PowerProfile,
94 pub interrupt_model: InterruptModel<'a, A>,
95 pub processor_info: Option<ProcessorInfo<'a, A>>,
98 pub pm_timer: Option<PmTimer>,
99 }
103
104#[cfg(feature = "alloc")]
105impl PlatformInfo<'_, alloc::alloc::Global> {
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
114impl<A> PlatformInfo<'_, A>
115where
116 A: Allocator + Clone,
117{
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.get().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
136pub fn wakeup_aps<H>(
146 tables: &AcpiTables<H>,
147 handler: H,
148 apic_id: u32,
149 wakeup_vector: u64,
150 timeout_loops: u64,
151) -> Result<(), AcpiError>
152where
153 H: AcpiHandler,
154{
155 let madt = tables.find_table::<Madt>()?;
156 let mailbox_addr = madt.get().get_mpwk_mailbox_addr()?;
157 let mut mpwk_mapping = unsafe {
158 handler.map_physical_region::<MultiprocessorWakeupMailbox>(
159 mailbox_addr as usize,
160 mem::size_of::<MultiprocessorWakeupMailbox>(),
161 )
162 };
163
164 unsafe {
166 ptr::write_volatile(&mut mpwk_mapping.command, MpProtectedModeWakeupCommand::Noop as u16);
167 }
168
169 mpwk_mapping.apic_id = apic_id;
171 mpwk_mapping.wakeup_vector = wakeup_vector;
172 unsafe {
173 ptr::write_volatile(&mut mpwk_mapping.command, MpProtectedModeWakeupCommand::Wakeup as u16);
174 }
175
176 let mut loops = 0;
178 let mut command = MpProtectedModeWakeupCommand::Wakeup;
179 while command != MpProtectedModeWakeupCommand::Noop {
180 if loops >= timeout_loops {
181 return Err(AcpiError::InvalidMadt(MadtError::WakeupApsTimeout));
182 }
183 unsafe {
186 command = ptr::read_volatile(&mpwk_mapping.command).into();
187 }
188 core::hint::spin_loop();
189 loops += 1;
190 }
191 drop(mpwk_mapping);
192
193 Ok(())
194}