madt.rs 21 KB

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