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