• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 use crate::{
2     sdt::{ExtendedField, SdtHeader, Signature},
3     AcpiError,
4     AcpiTable,
5 };
6 use bit_field::BitField;
7 use core::{
8     marker::{PhantomData, PhantomPinned},
9     mem,
10     pin::Pin,
11 };
12 
13 #[cfg(feature = "allocator_api")]
14 use crate::{
15     platform::{
16         interrupt::{InterruptModel, Polarity, TriggerMode},
17         ProcessorInfo,
18     },
19     AcpiResult,
20 };
21 
22 #[derive(Debug)]
23 pub enum MadtError {
24     UnexpectedEntry,
25     InterruptOverrideEntryHasInvalidBus,
26     InvalidLocalNmiLine,
27     MpsIntiInvalidPolarity,
28     MpsIntiInvalidTriggerMode,
29     WakeupApsTimeout,
30 }
31 
32 /// Represents the MADT - this contains the MADT header fields. You can then iterate over a `Madt`
33 /// to read each entry from it.
34 ///
35 /// In modern versions of ACPI, the MADT can detail one of four interrupt models:
36 /// - The ancient dual-i8259 legacy PIC model
37 /// - The Advanced Programmable Interrupt Controller (APIC) model
38 /// - The Streamlined Advanced Programmable Interrupt Controller (SAPIC) model (for Itanium systems)
39 /// - The Generic Interrupt Controller (GIC) model (for ARM systems)
40 ///
41 /// The MADT is a variable-sized structure consisting of a static header and then a variable number of entries.
42 /// This type only contains the static portion, and then uses pointer arithmetic to parse the following entries.
43 /// To make this sound, this type is `!Unpin` - this prevents you from getting anything other than a `Pin<&Madt>`
44 /// out of a `PhysicalMapping`, thereby preventing a `Madt` from being moved before [`Madt::entries`] is called.
45 #[repr(C, packed)]
46 #[derive(Debug)]
47 pub struct Madt {
48     pub header: SdtHeader,
49     pub local_apic_address: u32,
50     pub flags: u32,
51     _pinned: PhantomPinned,
52 }
53 
54 /// ### Safety: Implementation properly represents a valid MADT.
55 unsafe impl AcpiTable for Madt {
56     const SIGNATURE: Signature = Signature::MADT;
57 
header(&self) -> &SdtHeader58     fn header(&self) -> &SdtHeader {
59         &self.header
60     }
61 }
62 
63 impl Madt {
get_mpwk_mailbox_addr(self: Pin<&Self>) -> Result<u64, AcpiError>64     pub fn get_mpwk_mailbox_addr(self: Pin<&Self>) -> Result<u64, AcpiError> {
65         for entry in self.entries() {
66             if let MadtEntry::MultiprocessorWakeup(entry) = entry {
67                 return Ok(entry.mailbox_address);
68             }
69         }
70         Err(AcpiError::InvalidMadt(MadtError::UnexpectedEntry))
71     }
72 
73     #[cfg(feature = "allocator_api")]
parse_interrupt_model_in<'a, A>( self: Pin<&Self>, allocator: A, ) -> AcpiResult<(InterruptModel<'a, A>, Option<ProcessorInfo<'a, A>>)> where A: core::alloc::Allocator + Clone,74     pub fn parse_interrupt_model_in<'a, A>(
75         self: Pin<&Self>,
76         allocator: A,
77     ) -> AcpiResult<(InterruptModel<'a, A>, Option<ProcessorInfo<'a, A>>)>
78     where
79         A: core::alloc::Allocator + Clone,
80     {
81         /*
82          * We first do a pass through the MADT to determine which interrupt model is being used.
83          */
84         for entry in self.entries() {
85             match entry {
86                 MadtEntry::LocalApic(_) |
87                 MadtEntry::LocalX2Apic(_) |
88                 MadtEntry::IoApic(_) |
89                 MadtEntry::InterruptSourceOverride(_) |
90                 MadtEntry::NmiSource(_) |   // TODO: is this one used by more than one model?
91                 MadtEntry::LocalApicNmi(_) |
92                 MadtEntry::X2ApicNmi(_) |
93                 MadtEntry::LocalApicAddressOverride(_) => {
94                     return self.parse_apic_model_in(allocator);
95                 }
96 
97                 MadtEntry::IoSapic(_) |
98                 MadtEntry::LocalSapic(_) |
99                 MadtEntry::PlatformInterruptSource(_) => {
100                     unimplemented!();
101                 }
102 
103                 MadtEntry::Gicc(_) |
104                 MadtEntry::Gicd(_) |
105                 MadtEntry::GicMsiFrame(_) |
106                 MadtEntry::GicRedistributor(_) |
107                 MadtEntry::GicInterruptTranslationService(_) => {
108                     unimplemented!();
109                 }
110 
111                 MadtEntry::MultiprocessorWakeup(_) => ()
112             }
113         }
114 
115         Ok((InterruptModel::Unknown, None))
116     }
117 
118     #[cfg(feature = "allocator_api")]
parse_apic_model_in<'a, A>( self: Pin<&Self>, allocator: A, ) -> AcpiResult<(InterruptModel<'a, A>, Option<ProcessorInfo<'a, A>>)> where A: core::alloc::Allocator + Clone,119     fn parse_apic_model_in<'a, A>(
120         self: Pin<&Self>,
121         allocator: A,
122     ) -> AcpiResult<(InterruptModel<'a, A>, Option<ProcessorInfo<'a, A>>)>
123     where
124         A: core::alloc::Allocator + Clone,
125     {
126         use crate::platform::{
127             interrupt::{
128                 Apic,
129                 InterruptSourceOverride,
130                 IoApic,
131                 LocalInterruptLine,
132                 NmiLine,
133                 NmiProcessor,
134                 NmiSource,
135             },
136             Processor,
137             ProcessorState,
138         };
139 
140         let mut local_apic_address = self.local_apic_address as u64;
141         let mut io_apic_count = 0;
142         let mut iso_count = 0;
143         let mut nmi_source_count = 0;
144         let mut local_nmi_line_count = 0;
145         let mut processor_count = 0usize;
146 
147         // Do a pass over the entries so we know how much space we should reserve in the vectors
148         for entry in self.entries() {
149             match entry {
150                 MadtEntry::IoApic(_) => io_apic_count += 1,
151                 MadtEntry::InterruptSourceOverride(_) => iso_count += 1,
152                 MadtEntry::NmiSource(_) => nmi_source_count += 1,
153                 MadtEntry::LocalApicNmi(_) => local_nmi_line_count += 1,
154                 MadtEntry::X2ApicNmi(_) => local_nmi_line_count += 1,
155                 MadtEntry::LocalApic(_) => processor_count += 1,
156                 MadtEntry::LocalX2Apic(_) => processor_count += 1,
157                 _ => (),
158             }
159         }
160 
161         let mut io_apics = crate::ManagedSlice::new_in(io_apic_count, allocator.clone())?;
162         let mut interrupt_source_overrides = crate::ManagedSlice::new_in(iso_count, allocator.clone())?;
163         let mut nmi_sources = crate::ManagedSlice::new_in(nmi_source_count, allocator.clone())?;
164         let mut local_apic_nmi_lines = crate::ManagedSlice::new_in(local_nmi_line_count, allocator.clone())?;
165         let mut application_processors =
166             crate::ManagedSlice::new_in(processor_count.saturating_sub(1), allocator)?; // Subtract one for the BSP
167         let mut boot_processor = None;
168 
169         io_apic_count = 0;
170         iso_count = 0;
171         nmi_source_count = 0;
172         local_nmi_line_count = 0;
173         processor_count = 0;
174 
175         for entry in self.entries() {
176             match entry {
177                 MadtEntry::LocalApic(entry) => {
178                     /*
179                      * The first processor is the BSP. Subsequent ones are APs. If we haven't found
180                      * the BSP yet, this must be it.
181                      */
182                     let is_ap = boot_processor.is_some();
183                     let is_disabled = !{ entry.flags }.get_bit(0);
184 
185                     let state = match (is_ap, is_disabled) {
186                         (_, true) => ProcessorState::Disabled,
187                         (true, false) => ProcessorState::WaitingForSipi,
188                         (false, false) => ProcessorState::Running,
189                     };
190 
191                     let processor = Processor {
192                         processor_uid: entry.processor_id as u32,
193                         local_apic_id: entry.apic_id as u32,
194                         state,
195                         is_ap,
196                     };
197 
198                     if is_ap {
199                         application_processors[processor_count] = processor;
200                         processor_count += 1;
201                     } else {
202                         boot_processor = Some(processor);
203                     }
204                 }
205 
206                 MadtEntry::LocalX2Apic(entry) => {
207                     let is_ap = boot_processor.is_some();
208                     let is_disabled = !{ entry.flags }.get_bit(0);
209 
210                     let state = match (is_ap, is_disabled) {
211                         (_, true) => ProcessorState::Disabled,
212                         (true, false) => ProcessorState::WaitingForSipi,
213                         (false, false) => ProcessorState::Running,
214                     };
215 
216                     let processor = Processor {
217                         processor_uid: entry.processor_uid,
218                         local_apic_id: entry.x2apic_id,
219                         state,
220                         is_ap,
221                     };
222 
223                     if is_ap {
224                         application_processors[processor_count] = processor;
225                         processor_count += 1;
226                     } else {
227                         boot_processor = Some(processor);
228                     }
229                 }
230 
231                 MadtEntry::IoApic(entry) => {
232                     io_apics[io_apic_count] = IoApic {
233                         id: entry.io_apic_id,
234                         address: entry.io_apic_address,
235                         global_system_interrupt_base: entry.global_system_interrupt_base,
236                     };
237                     io_apic_count += 1;
238                 }
239 
240                 MadtEntry::InterruptSourceOverride(entry) => {
241                     if entry.bus != 0 {
242                         return Err(AcpiError::InvalidMadt(MadtError::InterruptOverrideEntryHasInvalidBus));
243                     }
244 
245                     let (polarity, trigger_mode) = parse_mps_inti_flags(entry.flags)?;
246 
247                     interrupt_source_overrides[iso_count] = InterruptSourceOverride {
248                         isa_source: entry.irq,
249                         global_system_interrupt: entry.global_system_interrupt,
250                         polarity,
251                         trigger_mode,
252                     };
253                     iso_count += 1;
254                 }
255 
256                 MadtEntry::NmiSource(entry) => {
257                     let (polarity, trigger_mode) = parse_mps_inti_flags(entry.flags)?;
258 
259                     nmi_sources[nmi_source_count] = NmiSource {
260                         global_system_interrupt: entry.global_system_interrupt,
261                         polarity,
262                         trigger_mode,
263                     };
264                     nmi_source_count += 1;
265                 }
266 
267                 MadtEntry::LocalApicNmi(entry) => {
268                     local_apic_nmi_lines[local_nmi_line_count] = NmiLine {
269                         processor: if entry.processor_id == 0xff {
270                             NmiProcessor::All
271                         } else {
272                             NmiProcessor::ProcessorUid(entry.processor_id as u32)
273                         },
274                         line: match entry.nmi_line {
275                             0 => LocalInterruptLine::Lint0,
276                             1 => LocalInterruptLine::Lint1,
277                             _ => return Err(AcpiError::InvalidMadt(MadtError::InvalidLocalNmiLine)),
278                         },
279                     };
280                     local_nmi_line_count += 1;
281                 }
282 
283                 MadtEntry::X2ApicNmi(entry) => {
284                     local_apic_nmi_lines[local_nmi_line_count] = NmiLine {
285                         processor: if entry.processor_uid == 0xffffffff {
286                             NmiProcessor::All
287                         } else {
288                             NmiProcessor::ProcessorUid(entry.processor_uid)
289                         },
290                         line: match entry.nmi_line {
291                             0 => LocalInterruptLine::Lint0,
292                             1 => LocalInterruptLine::Lint1,
293                             _ => return Err(AcpiError::InvalidMadt(MadtError::InvalidLocalNmiLine)),
294                         },
295                     };
296                     local_nmi_line_count += 1;
297                 }
298 
299                 MadtEntry::LocalApicAddressOverride(entry) => {
300                     local_apic_address = entry.local_apic_address;
301                 }
302 
303                 MadtEntry::MultiprocessorWakeup(_) => {}
304 
305                 _ => {
306                     return Err(AcpiError::InvalidMadt(MadtError::UnexpectedEntry));
307                 }
308             }
309         }
310 
311         Ok((
312             InterruptModel::Apic(Apic::new(
313                 local_apic_address,
314                 io_apics,
315                 local_apic_nmi_lines,
316                 interrupt_source_overrides,
317                 nmi_sources,
318                 self.supports_8259(),
319             )),
320             Some(ProcessorInfo::new(boot_processor.unwrap(), application_processors)),
321         ))
322     }
323 
entries(self: Pin<&Self>) -> MadtEntryIter<'_>324     pub fn entries(self: Pin<&Self>) -> MadtEntryIter<'_> {
325         let ptr = unsafe { Pin::into_inner_unchecked(self) as *const Madt as *const u8 };
326         MadtEntryIter {
327             pointer: unsafe { ptr.add(mem::size_of::<Madt>()) },
328             remaining_length: self.header.length - mem::size_of::<Madt>() as u32,
329             _phantom: PhantomData,
330         }
331     }
332 
supports_8259(&self) -> bool333     pub fn supports_8259(&self) -> bool {
334         { self.flags }.get_bit(0)
335     }
336 }
337 
338 #[derive(Debug)]
339 pub struct MadtEntryIter<'a> {
340     pointer: *const u8,
341     /*
342      * The iterator can only have at most `u32::MAX` remaining bytes, because the length of the
343      * whole SDT can only be at most `u32::MAX`.
344      */
345     remaining_length: u32,
346     _phantom: PhantomData<&'a ()>,
347 }
348 
349 #[derive(Debug)]
350 pub enum MadtEntry<'a> {
351     LocalApic(&'a LocalApicEntry),
352     IoApic(&'a IoApicEntry),
353     InterruptSourceOverride(&'a InterruptSourceOverrideEntry),
354     NmiSource(&'a NmiSourceEntry),
355     LocalApicNmi(&'a LocalApicNmiEntry),
356     LocalApicAddressOverride(&'a LocalApicAddressOverrideEntry),
357     IoSapic(&'a IoSapicEntry),
358     LocalSapic(&'a LocalSapicEntry),
359     PlatformInterruptSource(&'a PlatformInterruptSourceEntry),
360     LocalX2Apic(&'a LocalX2ApicEntry),
361     X2ApicNmi(&'a X2ApicNmiEntry),
362     Gicc(&'a GiccEntry),
363     Gicd(&'a GicdEntry),
364     GicMsiFrame(&'a GicMsiFrameEntry),
365     GicRedistributor(&'a GicRedistributorEntry),
366     GicInterruptTranslationService(&'a GicInterruptTranslationServiceEntry),
367     MultiprocessorWakeup(&'a MultiprocessorWakeupEntry),
368 }
369 
370 impl<'a> Iterator for MadtEntryIter<'a> {
371     type Item = MadtEntry<'a>;
372 
next(&mut self) -> Option<Self::Item>373     fn next(&mut self) -> Option<Self::Item> {
374         while self.remaining_length > 0 {
375             let entry_pointer = self.pointer;
376             let header = unsafe { *(self.pointer as *const EntryHeader) };
377 
378             self.pointer = unsafe { self.pointer.offset(header.length as isize) };
379             self.remaining_length -= header.length as u32;
380 
381             macro_rules! construct_entry {
382                 ($entry_type:expr,
383                  $entry_pointer:expr,
384                  $(($value:expr => $variant:path as $type:ty)),*
385                 ) => {
386                     match $entry_type {
387                         $(
388                             $value => {
389                                 return Some($variant(unsafe {
390                                     &*($entry_pointer as *const $type)
391                                 }))
392                             }
393                          )*
394 
395                         /*
396                          * These entry types are reserved by the ACPI standard. We should skip them
397                          * if they appear in a real MADT.
398                          */
399                         0x11..=0x7f => {}
400 
401                         /*
402                          * These entry types are reserved for OEM use. Atm, we just skip them too.
403                          * TODO: work out if we should ever do anything else here
404                          */
405                         0x80..=0xff => {}
406                     }
407                 }
408             }
409 
410             #[rustfmt::skip]
411             construct_entry!(
412                 header.entry_type,
413                 entry_pointer,
414                 (0x0 => MadtEntry::LocalApic as LocalApicEntry),
415                 (0x1 => MadtEntry::IoApic as IoApicEntry),
416                 (0x2 => MadtEntry::InterruptSourceOverride as InterruptSourceOverrideEntry),
417                 (0x3 => MadtEntry::NmiSource as NmiSourceEntry),
418                 (0x4 => MadtEntry::LocalApicNmi as LocalApicNmiEntry),
419                 (0x5 => MadtEntry::LocalApicAddressOverride as LocalApicAddressOverrideEntry),
420                 (0x6 => MadtEntry::IoSapic as IoSapicEntry),
421                 (0x7 => MadtEntry::LocalSapic as LocalSapicEntry),
422                 (0x8 => MadtEntry::PlatformInterruptSource as PlatformInterruptSourceEntry),
423                 (0x9 => MadtEntry::LocalX2Apic as LocalX2ApicEntry),
424                 (0xa => MadtEntry::X2ApicNmi as X2ApicNmiEntry),
425                 (0xb => MadtEntry::Gicc as GiccEntry),
426                 (0xc => MadtEntry::Gicd as GicdEntry),
427                 (0xd => MadtEntry::GicMsiFrame as GicMsiFrameEntry),
428                 (0xe => MadtEntry::GicRedistributor as GicRedistributorEntry),
429                 (0xf => MadtEntry::GicInterruptTranslationService as GicInterruptTranslationServiceEntry),
430                 (0x10 => MadtEntry::MultiprocessorWakeup as MultiprocessorWakeupEntry)
431             );
432         }
433 
434         None
435     }
436 }
437 
438 #[derive(Clone, Copy, Debug)]
439 #[repr(C, packed)]
440 pub struct EntryHeader {
441     pub entry_type: u8,
442     pub length: u8,
443 }
444 
445 #[derive(Clone, Copy, Debug)]
446 #[repr(C, packed)]
447 pub struct LocalApicEntry {
448     pub header: EntryHeader,
449     pub processor_id: u8,
450     pub apic_id: u8,
451     pub flags: u32,
452 }
453 
454 #[derive(Clone, Copy, Debug)]
455 #[repr(C, packed)]
456 pub struct IoApicEntry {
457     pub header: EntryHeader,
458     pub io_apic_id: u8,
459     _reserved: u8,
460     pub io_apic_address: u32,
461     pub global_system_interrupt_base: u32,
462 }
463 
464 #[derive(Clone, Copy, Debug)]
465 #[repr(C, packed)]
466 pub struct InterruptSourceOverrideEntry {
467     pub header: EntryHeader,
468     pub bus: u8, // 0 - ISA bus
469     pub irq: u8, // This is bus-relative
470     pub global_system_interrupt: u32,
471     pub flags: u16,
472 }
473 
474 #[derive(Clone, Copy, Debug)]
475 #[repr(C, packed)]
476 pub struct NmiSourceEntry {
477     pub header: EntryHeader,
478     pub flags: u16,
479     pub global_system_interrupt: u32,
480 }
481 
482 #[derive(Clone, Copy, Debug)]
483 #[repr(C, packed)]
484 pub struct LocalApicNmiEntry {
485     pub header: EntryHeader,
486     pub processor_id: u8,
487     pub flags: u16,
488     pub nmi_line: u8, // Describes which LINTn is the NMI connected to
489 }
490 
491 #[derive(Clone, Copy, Debug)]
492 #[repr(C, packed)]
493 pub struct LocalApicAddressOverrideEntry {
494     pub header: EntryHeader,
495     _reserved: u16,
496     pub local_apic_address: u64,
497 }
498 
499 /// If this entry is present, the system has an I/O SAPIC, which must be used instead of the I/O
500 /// APIC.
501 #[derive(Clone, Copy, Debug)]
502 #[repr(C, packed)]
503 pub struct IoSapicEntry {
504     pub header: EntryHeader,
505     pub io_apic_id: u8,
506     _reserved: u8,
507     pub global_system_interrupt_base: u32,
508     pub io_sapic_address: u64,
509 }
510 
511 #[derive(Clone, Copy, Debug)]
512 #[repr(C, packed)]
513 pub struct LocalSapicEntry {
514     pub header: EntryHeader,
515     pub processor_id: u8,
516     pub local_sapic_id: u8,
517     pub local_sapic_eid: u8,
518     _reserved: [u8; 3],
519     pub flags: u32,
520     pub processor_uid: u32,
521 
522     /// This string can be used to associate this local SAPIC to a processor defined in the
523     /// namespace when the `_UID` object is a string. It is a null-terminated ASCII string, and so
524     /// this field will be `'\0'` if the string is not present, otherwise it extends from the
525     /// address of this field.
526     processor_uid_string: u8,
527 }
528 
529 #[derive(Clone, Copy, Debug)]
530 #[repr(C, packed)]
531 pub struct PlatformInterruptSourceEntry {
532     pub header: EntryHeader,
533     pub flags: u16,
534     pub interrupt_type: u8,
535     pub processor_id: u8,
536     pub processor_eid: u8,
537     pub io_sapic_vector: u8,
538     pub global_system_interrupt: u32,
539     pub platform_interrupt_source_flags: u32,
540 }
541 
542 #[derive(Clone, Copy, Debug)]
543 #[repr(C, packed)]
544 pub struct LocalX2ApicEntry {
545     pub header: EntryHeader,
546     _reserved: u16,
547     pub x2apic_id: u32,
548     pub flags: u32,
549     pub processor_uid: u32,
550 }
551 
552 #[derive(Clone, Copy, Debug)]
553 #[repr(C, packed)]
554 pub struct X2ApicNmiEntry {
555     pub header: EntryHeader,
556     pub flags: u16,
557     pub processor_uid: u32,
558     pub nmi_line: u8,
559     _reserved: [u8; 3],
560 }
561 
562 /// This field will appear for ARM processors that support ACPI and use the Generic Interrupt
563 /// Controller. In the GICC interrupt model, each logical process has a Processor Device object in
564 /// the namespace, and uses this structure to convey its GIC information.
565 #[derive(Clone, Copy, Debug)]
566 #[repr(C, packed)]
567 pub struct GiccEntry {
568     pub header: EntryHeader,
569     _reserved1: u16,
570     pub cpu_interface_number: u32,
571     pub processor_uid: u32,
572     pub flags: u32,
573     pub parking_protocol_version: u32,
574     pub performance_interrupt_gsiv: u32,
575     pub parked_address: u64,
576     pub gic_registers_address: u64,
577     pub gic_virtual_registers_address: u64,
578     pub gic_hypervisor_registers_address: u64,
579     pub vgic_maintenance_interrupt: u32,
580     pub gicr_base_address: u64,
581     pub mpidr: u64,
582     pub processor_power_efficiency_class: u8,
583     _reserved2: u8,
584     /// SPE overflow Interrupt.
585     ///
586     /// ACPI 6.3 defined this field. It is zero in prior versions or
587     /// if this processor does not support SPE.
588     pub spe_overflow_interrupt: u16,
589     pub trbe_interrupt: ExtendedField<u16, 6>,
590 }
591 
592 #[derive(Clone, Copy, Debug)]
593 #[repr(C, packed)]
594 pub struct GicdEntry {
595     pub header: EntryHeader,
596     _reserved1: u16,
597     pub gic_id: u32,
598     pub physical_base_address: u64,
599     pub system_vector_base: u32,
600 
601     /// The GIC version
602     ///     0x00: Fall back to hardware discovery
603     ///     0x01: GICv1
604     ///     0x02: GICv2
605     ///     0x03: GICv3
606     ///     0x04: GICv4
607     ///     0x05-0xff: Reserved for future use
608     pub gic_version: u8,
609     _reserved2: [u8; 3],
610 }
611 
612 #[derive(Clone, Copy, Debug)]
613 #[repr(C, packed)]
614 pub struct GicMsiFrameEntry {
615     pub header: EntryHeader,
616     _reserved: u16,
617     pub frame_id: u32,
618     pub physical_base_address: u64,
619     pub flags: u32,
620     pub spi_count: u16,
621     pub spi_base: u16,
622 }
623 
624 #[derive(Clone, Copy, Debug)]
625 #[repr(C, packed)]
626 pub struct GicRedistributorEntry {
627     pub header: EntryHeader,
628     _reserved: u16,
629     pub discovery_range_base_address: u64,
630     pub discovery_range_length: u32,
631 }
632 
633 #[derive(Clone, Copy, Debug)]
634 #[repr(C, packed)]
635 pub struct GicInterruptTranslationServiceEntry {
636     pub header: EntryHeader,
637     _reserved1: u16,
638     pub id: u32,
639     pub physical_base_address: u64,
640     _reserved2: u32,
641 }
642 
643 #[derive(Clone, Copy, Debug)]
644 #[repr(C, packed)]
645 pub struct MultiprocessorWakeupEntry {
646     pub header: EntryHeader,
647     pub mailbox_version: u16,
648     _reserved: u32,
649     pub mailbox_address: u64,
650 }
651 
652 #[derive(Debug, PartialEq, Eq)]
653 pub enum MpProtectedModeWakeupCommand {
654     Noop = 0,
655     Wakeup = 1,
656     Sleep = 2,
657     AcceptPages = 3,
658 }
659 
660 impl From<u16> for MpProtectedModeWakeupCommand {
from(value: u16) -> Self661     fn from(value: u16) -> Self {
662         match value {
663             0 => MpProtectedModeWakeupCommand::Noop,
664             1 => MpProtectedModeWakeupCommand::Wakeup,
665             2 => MpProtectedModeWakeupCommand::Sleep,
666             3 => MpProtectedModeWakeupCommand::AcceptPages,
667             _ => panic!("Invalid value for MpProtectedModeWakeupCommand"),
668         }
669     }
670 }
671 
672 #[repr(C)]
673 pub struct MultiprocessorWakeupMailbox {
674     pub command: u16,
675     _reserved: u16,
676     pub apic_id: u32,
677     pub wakeup_vector: u64,
678     pub reserved_for_os: [u64; 254],
679     reserved_for_firmware: [u64; 256],
680 }
681 
682 #[cfg(feature = "allocator_api")]
parse_mps_inti_flags(flags: u16) -> crate::AcpiResult<(Polarity, TriggerMode)>683 fn parse_mps_inti_flags(flags: u16) -> crate::AcpiResult<(Polarity, TriggerMode)> {
684     let polarity = match flags.get_bits(0..2) {
685         0b00 => Polarity::SameAsBus,
686         0b01 => Polarity::ActiveHigh,
687         0b11 => Polarity::ActiveLow,
688         _ => return Err(crate::AcpiError::InvalidMadt(MadtError::MpsIntiInvalidPolarity)),
689     };
690 
691     let trigger_mode = match flags.get_bits(2..4) {
692         0b00 => TriggerMode::SameAsBus,
693         0b01 => TriggerMode::Edge,
694         0b11 => TriggerMode::Level,
695         _ => return Err(crate::AcpiError::InvalidMadt(MadtError::MpsIntiInvalidTriggerMode)),
696     };
697 
698     Ok((polarity, trigger_mode))
699 }
700