11use crate :: {
22 sdt:: { ExtendedField , SdtHeader , Signature } ,
3+ AcpiError ,
34 AcpiTable ,
45} ;
56use bit_field:: BitField ;
6- use core:: { marker:: PhantomData , mem} ;
7+ use core:: { marker:: PhantomData , mem, time :: Duration } ;
78
89#[ cfg( feature = "allocator_api" ) ]
910use 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+
5155impl 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" ) ]
634714fn 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