Skip to content

Commit 6ac19d7

Browse files
committed
Implement the multiprocessor wakeup mechanism.
1 parent da9b3b1 commit 6ac19d7

File tree

1 file changed

+85
-1
lines changed

1 file changed

+85
-1
lines changed

acpi/src/madt.rs

Lines changed: 85 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
use crate::{
22
sdt::{ExtendedField, SdtHeader, Signature},
3+
AcpiError,
34
AcpiTable,
45
};
56
use bit_field::BitField;
6-
use core::{marker::PhantomData, mem};
7+
use core::{marker::PhantomData, mem, time::Duration};
78

89
#[cfg(feature = "allocator_api")]
910
use crate::{
@@ -21,6 +22,7 @@ pub enum MadtError {
2122
InvalidLocalNmiLine,
2223
MpsIntiInvalidPolarity,
2324
MpsIntiInvalidTriggerMode,
25+
WakeupApsTimeout,
2426
}
2527

2628
/// Represents the MADT - this contains the MADT header fields. You can then iterate over a `Madt`
@@ -48,7 +50,55 @@ unsafe impl AcpiTable for Madt {
4850
}
4951
}
5052

53+
pub type PhysToVirtFn = fn(u64) -> u64;
54+
5155
impl Madt {
56+
pub fn wakeup_aps(
57+
&self,
58+
apic_id: u32,
59+
wakeup_vector: u64,
60+
phys_to_virt: PhysToVirtFn,
61+
) -> Result<(), AcpiError> {
62+
let mailbox_addr = self.get_mpwk_mailbox_addr()?;
63+
unsafe {
64+
let mailbox = &mut *((phys_to_virt(mailbox_addr)) as *mut MultiprocessorWakeupMailbox);
65+
66+
mailbox.command = MpProtectedModeWakeupCommand::Noop as u16;
67+
68+
// Fill the mailbox
69+
mailbox.apic_id = apic_id;
70+
mailbox.wakeup_vector = wakeup_vector;
71+
mailbox.command = MpProtectedModeWakeupCommand::Wakeup as u16;
72+
73+
// Wait to join
74+
let timeout_loops = timeout_to_loops(Duration::from_secs(1));
75+
let mut loops = 0;
76+
let mut command = MpProtectedModeWakeupCommand::Wakeup;
77+
while command != MpProtectedModeWakeupCommand::Noop {
78+
if loops >= timeout_loops {
79+
return Err(AcpiError::InvalidMadt(MadtError::WakeupApsTimeout));
80+
}
81+
// Wait for the command to be processed
82+
command = mailbox.command.into();
83+
core::hint::spin_loop();
84+
loops += 1;
85+
}
86+
Ok(())
87+
}
88+
}
89+
90+
pub fn get_mpwk_mailbox_addr(&self) -> Result<u64, AcpiError> {
91+
for entry in self.entries() {
92+
match entry {
93+
MadtEntry::MultiprocessorWakeup(entry) => {
94+
return Ok(entry.mailbox_address);
95+
}
96+
_ => {}
97+
}
98+
}
99+
Err(AcpiError::InvalidMadt(MadtError::UnexpectedEntry))
100+
}
101+
52102
#[cfg(feature = "allocator_api")]
53103
pub fn parse_interrupt_model_in<'a, A>(
54104
&self,
@@ -630,6 +680,36 @@ pub struct MultiprocessorWakeupEntry {
630680
pub mailbox_address: u64,
631681
}
632682

683+
#[derive(Debug, PartialEq, Eq)]
684+
enum MpProtectedModeWakeupCommand {
685+
Noop = 0,
686+
Wakeup = 1,
687+
Sleep = 2,
688+
AcceptPages = 3,
689+
}
690+
691+
impl From<u16> for MpProtectedModeWakeupCommand {
692+
fn from(value: u16) -> Self {
693+
match value {
694+
0 => MpProtectedModeWakeupCommand::Noop,
695+
1 => MpProtectedModeWakeupCommand::Wakeup,
696+
2 => MpProtectedModeWakeupCommand::Sleep,
697+
3 => MpProtectedModeWakeupCommand::AcceptPages,
698+
_ => panic!("Invalid value for MpProtectedModeWakeupCommand"),
699+
}
700+
}
701+
}
702+
703+
#[repr(C, packed)]
704+
pub struct MultiprocessorWakeupMailbox {
705+
command: u16,
706+
_reserved: u16,
707+
apic_id: u32,
708+
wakeup_vector: u64,
709+
reserved_for_os: [u64; 254],
710+
reserved_for_firmware: [u64; 256],
711+
}
712+
633713
#[cfg(feature = "allocator_api")]
634714
fn parse_mps_inti_flags(flags: u16) -> crate::AcpiResult<(Polarity, TriggerMode)> {
635715
let polarity = match flags.get_bits(0..2) {
@@ -648,3 +728,7 @@ fn parse_mps_inti_flags(flags: u16) -> crate::AcpiResult<(Polarity, TriggerMode)
648728

649729
Ok((polarity, trigger_mode))
650730
}
731+
732+
fn timeout_to_loops(timeout: Duration) -> u64 {
733+
timeout.as_micros() as u64
734+
}

0 commit comments

Comments
 (0)