1
1
use crate :: {
2
2
sdt:: { ExtendedField , SdtHeader , Signature } ,
3
+ AcpiError ,
3
4
AcpiTable ,
4
5
} ;
5
6
use bit_field:: BitField ;
6
- use core:: { marker:: PhantomData , mem} ;
7
+ use core:: { marker:: PhantomData , mem, time :: Duration } ;
7
8
8
9
#[ cfg( feature = "allocator_api" ) ]
9
10
use crate :: {
@@ -21,6 +22,7 @@ pub enum MadtError {
21
22
InvalidLocalNmiLine ,
22
23
MpsIntiInvalidPolarity ,
23
24
MpsIntiInvalidTriggerMode ,
25
+ WakeupApsTimeout ,
24
26
}
25
27
26
28
/// 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 {
48
50
}
49
51
}
50
52
53
+ pub type PhysToVirtFn = fn ( u64 ) -> u64 ;
54
+
51
55
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
+
52
102
#[ cfg( feature = "allocator_api" ) ]
53
103
pub fn parse_interrupt_model_in < ' a , A > (
54
104
& self ,
@@ -630,6 +680,36 @@ pub struct MultiprocessorWakeupEntry {
630
680
pub mailbox_address : u64 ,
631
681
}
632
682
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
+
633
713
#[ cfg( feature = "allocator_api" ) ]
634
714
fn parse_mps_inti_flags ( flags : u16 ) -> crate :: AcpiResult < ( Polarity , TriggerMode ) > {
635
715
let polarity = match flags. get_bits ( 0 ..2 ) {
@@ -648,3 +728,7 @@ fn parse_mps_inti_flags(flags: u16) -> crate::AcpiResult<(Polarity, TriggerMode)
648
728
649
729
Ok ( ( polarity, trigger_mode) )
650
730
}
731
+
732
+ fn timeout_to_loops ( timeout : Duration ) -> u64 {
733
+ timeout. as_micros ( ) as u64
734
+ }
0 commit comments