acpi_spec/
madt.rs

1// Copyright (c) Microsoft Corporation.
2// Licensed under the MIT License.
3
4use super::Table;
5use bitfield_struct::bitfield;
6use core::mem::size_of;
7use open_enum::open_enum;
8use size_of_val;
9use static_assertions::const_assert_eq;
10use thiserror::Error;
11use zerocopy::FromBytes;
12use zerocopy::FromZeros;
13use zerocopy::Immutable;
14use zerocopy::IntoBytes;
15use zerocopy::KnownLayout;
16use zerocopy::LE;
17use zerocopy::U16;
18use zerocopy::U32;
19use zerocopy::U64;
20use zerocopy::Unaligned;
21
22#[repr(C, packed)]
23#[derive(Copy, Clone, Debug, IntoBytes, Immutable, KnownLayout, FromBytes, Unaligned)]
24pub struct Madt {
25    pub apic_addr: u32,
26    pub flags: u32,
27}
28
29impl Table for Madt {
30    const SIGNATURE: [u8; 4] = *b"APIC";
31}
32
33pub const MADT_PCAT_COMPAT: u32 = 1 << 0;
34
35open_enum! {
36    #[derive(IntoBytes, Immutable, KnownLayout, FromBytes, Unaligned)]
37    pub enum MadtType: u8 {
38        APIC = 0x0,
39        IO_APIC = 0x1,
40        INTERRUPT_SOURCE_OVERRIDE = 0x2,
41        LOCAL_NMI_SOURCE = 0x4,
42        X2APIC = 0x9,
43        GICC = 0xb,
44        GICD = 0xc,
45        GIC_MSI_FRAME = 0xd,
46    }
47}
48
49#[repr(C, packed)]
50#[derive(Copy, Clone, Debug, IntoBytes, Immutable, KnownLayout, FromBytes)]
51pub struct MadtEntryHeader {
52    pub typ: MadtType,
53    pub length: u8,
54}
55
56#[repr(C, packed)]
57#[derive(Copy, Clone, Debug, PartialEq, Eq, IntoBytes, Immutable, KnownLayout, FromBytes)]
58pub struct MadtApic {
59    pub typ: MadtType,
60    pub length: u8,
61    pub acpi_processor_uid: u8,
62    pub apic_id: u8,
63    pub flags: u32,
64}
65
66const_assert_eq!(size_of::<MadtApic>(), 8);
67
68impl MadtApic {
69    pub fn new() -> Self {
70        Self {
71            typ: MadtType::APIC,
72            length: size_of::<Self>() as u8,
73            acpi_processor_uid: 0,
74            apic_id: 0,
75            flags: 0,
76        }
77    }
78}
79
80pub const MADT_APIC_ENABLED: u32 = 1 << 0;
81pub const MADT_APIC_ONLINE_CAPABLE: u32 = 1 << 1;
82
83#[repr(C, packed)]
84#[derive(Copy, Clone, Debug, PartialEq, Eq, IntoBytes, Immutable, KnownLayout, FromBytes)]
85pub struct MadtX2Apic {
86    pub typ: MadtType,
87    pub length: u8,
88    pub reserved: u16,
89    pub x2_apic_id: u32,
90    pub flags: u32,
91    pub acpi_processor_uid: u32,
92}
93
94const_assert_eq!(size_of::<MadtX2Apic>(), 16);
95
96impl MadtX2Apic {
97    pub fn new() -> Self {
98        Self {
99            typ: MadtType::X2APIC,
100            length: size_of::<Self>() as u8,
101            reserved: 0,
102            x2_apic_id: 0,
103            flags: 0,
104            acpi_processor_uid: 0,
105        }
106    }
107}
108
109#[repr(C, packed)]
110#[derive(Copy, Clone, Debug, IntoBytes, Immutable, KnownLayout, FromBytes)]
111pub struct MadtIoApic {
112    pub typ: MadtType,
113    pub length: u8,
114    pub io_apic_id: u8,
115    pub rsvd: u8,
116    pub io_apic_address: u32,
117    pub global_system_interrupt_base: u32,
118}
119
120const_assert_eq!(size_of::<MadtIoApic>(), 12);
121
122impl MadtIoApic {
123    pub fn new() -> Self {
124        Self {
125            typ: MadtType::IO_APIC,
126            length: size_of::<Self>() as u8,
127            io_apic_id: 0,
128            rsvd: 0,
129            io_apic_address: 0,
130            global_system_interrupt_base: 0,
131        }
132    }
133}
134
135#[repr(C, packed)]
136#[derive(Copy, Clone, Debug, IntoBytes, Immutable, KnownLayout, FromBytes)]
137pub struct MadtInterruptSourceOverride {
138    pub typ: MadtType,
139    pub length: u8,
140    pub bus: u8,
141    pub source: u8,
142    pub gsi: u32,
143    pub flags: u16,
144}
145
146const_assert_eq!(size_of::<MadtInterruptSourceOverride>(), 10);
147
148pub enum InterruptPolarity {
149    ActiveLow,
150    ActiveHigh,
151}
152
153pub enum InterruptTriggerMode {
154    Edge,
155    Level,
156}
157
158impl MadtInterruptSourceOverride {
159    pub fn new(
160        source: u8,
161        gsi: u32,
162        polarity: Option<InterruptPolarity>,
163        trigger_mode: Option<InterruptTriggerMode>,
164    ) -> Self {
165        Self {
166            typ: MadtType::INTERRUPT_SOURCE_OVERRIDE,
167            length: size_of::<Self>() as u8,
168            bus: 0,
169            source,
170            gsi,
171            flags: match polarity {
172                None => 0,
173                Some(InterruptPolarity::ActiveHigh) => 1,
174                Some(InterruptPolarity::ActiveLow) => 3,
175            } | (match trigger_mode {
176                None => 0,
177                Some(InterruptTriggerMode::Edge) => 1,
178                Some(InterruptTriggerMode::Level) => 3,
179            } << 2),
180        }
181    }
182}
183
184// EFI_ACPI_6_2_LOCAL_APIC_NMI_STRUCTURE
185#[repr(C, packed)]
186#[derive(Copy, Clone, Debug, IntoBytes, Immutable, KnownLayout, FromBytes)]
187pub struct MadtLocalNmiSource {
188    pub typ: MadtType,
189    pub length: u8,
190    pub acpi_processor_uid: u8,
191    pub flags: u16,
192    pub local_apic_lint: u8,
193}
194
195const_assert_eq!(size_of::<MadtLocalNmiSource>(), 6);
196
197impl MadtLocalNmiSource {
198    pub fn new() -> Self {
199        Self {
200            typ: MadtType::LOCAL_NMI_SOURCE,
201            length: size_of::<Self>() as u8,
202            acpi_processor_uid: 1, // 0xFF indicates all processors. UID 1 is the BSP
203            flags: 0,
204            local_apic_lint: 1,
205        }
206    }
207}
208
209#[repr(C)]
210#[derive(Copy, Clone, Debug, IntoBytes, Immutable, KnownLayout, FromBytes)]
211pub struct MadtGicd {
212    pub typ: MadtType,
213    pub length: u8,
214    pub reserved: u16,
215    pub gic_id: u32,
216    pub base_address: u64,
217    pub reserved2: u32,
218    pub gic_version: u8,
219    pub reserved3: [u8; 3],
220}
221
222const_assert_eq!(size_of::<MadtGicd>(), 24);
223
224impl MadtGicd {
225    pub fn new(gic_id: u32, base_address: u64, gic_version: u8) -> Self {
226        Self {
227            typ: MadtType::GICD,
228            length: size_of::<Self>() as u8,
229            reserved: 0,
230            gic_id,
231            base_address,
232            reserved2: 0,
233            gic_version,
234            reserved3: [0; 3],
235        }
236    }
237}
238
239/// ACPI 6.5 MADT GIC MSI Frame structure (Table 5-67).
240#[repr(C)]
241#[derive(Copy, Clone, Debug, IntoBytes, Immutable, KnownLayout, FromBytes)]
242pub struct MadtGicMsiFrame {
243    pub typ: MadtType,
244    pub length: u8,
245    pub reserved: u16,
246    pub gic_msi_frame_id: u32,
247    pub base_address: u64,
248    pub flags: u32,
249    pub spi_count: u16,
250    pub spi_base: u16,
251}
252
253const_assert_eq!(size_of::<MadtGicMsiFrame>(), 24);
254
255pub const GIC_MSI_FRAME_FLAGS_SPI_SELECT: u32 = 1 << 0;
256
257impl MadtGicMsiFrame {
258    pub fn new(gic_msi_frame_id: u32, base_address: u64, spi_base: u16, spi_count: u16) -> Self {
259        Self {
260            typ: MadtType::GIC_MSI_FRAME,
261            length: size_of::<Self>() as u8,
262            reserved: 0,
263            gic_msi_frame_id,
264            base_address,
265            flags: GIC_MSI_FRAME_FLAGS_SPI_SELECT,
266            spi_count,
267            spi_base,
268        }
269    }
270}
271
272// TODO: use LE types everywhere, as here, to avoid #[repr(packed)] and to be
273// specific about endianness (which the ACPI spec dictates is always LE).
274#[repr(C)]
275#[derive(Copy, Clone, Debug, IntoBytes, Immutable, KnownLayout, FromBytes, Unaligned)]
276pub struct MadtGicc {
277    pub typ: MadtType,
278    pub length: u8,
279    pub reserved: [u8; 2],
280    pub cpu_interface_number: U32<LE>,
281    pub acpi_processor_uid: U32<LE>,
282    pub flags: U32<LE>,
283    pub parking_protocol_version: U32<LE>,
284    pub performance_monitoring_gsiv: U32<LE>,
285    pub parked_address: U64<LE>,
286    pub base_address: U64<LE>,
287    pub gicv: U64<LE>,
288    pub gich: U64<LE>,
289    pub vgic_maintenance_interrupt: U32<LE>,
290    pub gicr_base_address: U64<LE>,
291    pub mpidr: U64<LE>,
292    pub processor_power_efficiency_class: u8,
293    pub reserved2: u8,
294    pub spe_overflow_interrupt: U16<LE>,
295}
296
297const_assert_eq!(size_of::<MadtGicc>(), 80);
298
299impl MadtGicc {
300    pub fn new(
301        acpi_processor_uid: u32,
302        mpidr: u64,
303        gicr: u64,
304        performance_monitoring_gsiv: u32,
305    ) -> Self {
306        Self {
307            typ: MadtType::GICC,
308            length: size_of::<Self>() as u8,
309            flags: u32::from(MadtGiccFlags::new().with_enabled(true)).into(),
310            acpi_processor_uid: acpi_processor_uid.into(),
311            mpidr: mpidr.into(),
312            gicr_base_address: gicr.into(),
313            performance_monitoring_gsiv: performance_monitoring_gsiv.into(),
314            ..Self::new_zeroed()
315        }
316    }
317}
318
319#[bitfield(u32)]
320pub struct MadtGiccFlags {
321    pub enabled: bool,
322    #[bits(31)]
323    _reserved: u32,
324}
325
326/// A MADT parser that can be iterated through for different [`MadtEntry`].
327pub struct MadtParser<'a>(&'a [u8]);
328
329impl<'a> MadtParser<'a> {
330    /// Partially an MADT table.
331    pub fn new(table: &'a [u8]) -> Result<Self, ParserError> {
332        let header = crate::Header::read_from_prefix(table)
333            .map_err(|_| ParserError)?
334            .0; // TODO: zerocopy: map_err (https://github.com/microsoft/openvmm/issues/759)
335        if (header.length.get() as usize) < size_of::<Madt>() {
336            return Err(ParserError);
337        }
338        let off = size_of_val(&header);
339        let table = table
340            .get(off..header.length.get() as usize)
341            .ok_or(ParserError)?;
342        Ok(Self(table))
343    }
344
345    /// Returns an iterator to parse the MADT entries.
346    pub fn entries(&self) -> MadtIter<'_> {
347        MadtIter {
348            entries: &self.0[size_of::<Madt>()..],
349        }
350    }
351
352    /// Parse apic_ids from the given MADT for enabled processors. Returned as a
353    /// `Vec<Option<u32>>` with element 0 being processor_acpi_uid 1.
354    #[cfg(feature = "alloc")]
355    pub fn parse_apic_ids(&self) -> Result<alloc::vec::Vec<Option<u32>>, ParseApicIdError> {
356        use alloc::vec::Vec;
357
358        let mut apic_ids: Vec<Option<u32>> = Vec::new();
359
360        for entry in self.entries() {
361            let (uid, apic_id) = match entry.map_err(ParseApicIdError::Parser)? {
362                MadtEntry::Apic(apic) => {
363                    if apic.flags & MADT_APIC_ENABLED == MADT_APIC_ENABLED {
364                        (apic.acpi_processor_uid as u32, apic.apic_id as u32)
365                    } else {
366                        continue;
367                    }
368                }
369                MadtEntry::X2Apic(x2apic) => {
370                    if x2apic.flags & MADT_APIC_ENABLED == MADT_APIC_ENABLED {
371                        (x2apic.acpi_processor_uid, x2apic.x2_apic_id)
372                    } else {
373                        continue;
374                    }
375                }
376            };
377
378            // ACPI uids start at 1.
379            let index = uid as usize - 1;
380
381            if apic_ids.get(index).is_none() {
382                apic_ids.resize(index + 1, None);
383            }
384
385            if apic_ids[index].replace(apic_id).is_some() {
386                return Err(ParseApicIdError::ProcessorNotUnique(uid));
387            }
388        }
389
390        Ok(apic_ids)
391    }
392}
393
394/// MADT parsing error.
395#[derive(Debug, Error)]
396#[error("madt parsing failed")]
397pub struct ParserError;
398
399/// parse_apic_ids error
400#[derive(Debug, thiserror::Error)]
401pub enum ParseApicIdError {
402    #[error("error parsing entry")]
403    Parser(#[source] ParserError),
404    #[error("processor_acpi_uid specified more than once in the MADT")]
405    ProcessorNotUnique(u32),
406}
407
408/// The MADT entry type.
409#[derive(Debug, Clone, Copy, PartialEq, Eq)]
410pub enum MadtEntry {
411    /// An APIC entry
412    Apic(MadtApic),
413    /// An X2 APIC entry
414    X2Apic(MadtX2Apic),
415}
416
417/// The MADT iterator. Ignores unknown entries.
418pub struct MadtIter<'a> {
419    entries: &'a [u8],
420}
421
422impl MadtIter<'_> {
423    fn parse(&mut self) -> Result<Option<MadtEntry>, ParserError> {
424        // TODO: zerocopy: map_err (https://github.com/microsoft/openvmm/issues/759)
425        while let Ok((header, _)) = MadtEntryHeader::read_from_prefix(self.entries) {
426            // TODO: zerocopy: ok (https://github.com/microsoft/openvmm/issues/759)
427            if self.entries.len() < header.length as usize {
428                return Err(ParserError);
429            }
430            let (buf, rest) = self.entries.split_at(header.length as usize);
431            self.entries = rest;
432            let entry = match header.typ {
433                MadtType::APIC => {
434                    MadtEntry::Apic(FromBytes::read_from_prefix(buf).map_err(|_| ParserError)?.0)
435                    // TODO: zerocopy: map_err (https://github.com/microsoft/openvmm/issues/759)
436                }
437                MadtType::X2APIC => {
438                    MadtEntry::X2Apic(FromBytes::read_from_prefix(buf).map_err(|_| ParserError)?.0)
439                    // TODO: zerocopy: map_err (https://github.com/microsoft/openvmm/issues/759)
440                }
441                _ => continue,
442            };
443            return Ok(Some(entry));
444        }
445        Ok(None)
446    }
447}
448
449impl Iterator for MadtIter<'_> {
450    type Item = Result<MadtEntry, ParserError>;
451
452    fn next(&mut self) -> Option<Self::Item> {
453        self.parse().transpose()
454    }
455}
456
457// TODO: could check-in binary files and do `include_bytes!()`
458#[cfg(test)]
459mod test {
460    use super::*;
461    #[cfg(feature = "alloc")]
462    use alloc::vec;
463    #[cfg(feature = "alloc")]
464    use alloc::vec::Vec;
465
466    // test sparse madt with not sequential processors enabled
467    #[test]
468    #[cfg(feature = "alloc")]
469    fn sparse_madt() {
470        const DATA: &[u8] = &[
471            65, 80, 73, 67, 194, 0, 0, 0, 5, 195, 72, 86, 76, 73, 84, 69, 72, 86, 76, 73, 84, 69,
472            84, 66, 0, 0, 0, 0, 77, 83, 72, 86, 0, 0, 0, 0, 0, 0, 224, 254, 0, 0, 0, 0, 1, 12, 16,
473            0, 0, 0, 192, 254, 0, 0, 0, 0, 2, 10, 0, 2, 2, 0, 0, 0, 13, 0, 0, 8, 1, 0, 1, 0, 0, 0,
474            0, 8, 4, 1, 1, 0, 0, 0, 0, 8, 6, 2, 1, 0, 0, 0, 0, 8, 8, 3, 1, 0, 0, 0, 0, 8, 10, 4, 1,
475            0, 0, 0, 0, 8, 12, 5, 1, 0, 0, 0, 0, 8, 14, 6, 1, 0, 0, 0, 0, 8, 16, 7, 1, 0, 0, 0, 0,
476            8, 18, 8, 1, 0, 0, 0, 0, 8, 20, 9, 1, 0, 0, 0, 0, 8, 22, 10, 1, 0, 0, 0, 0, 8, 24, 11,
477            1, 0, 0, 0, 0, 8, 26, 12, 1, 0, 0, 0, 0, 8, 28, 13, 1, 0, 0, 0, 0, 8, 30, 14, 1, 0, 0,
478            0, 0, 8, 32, 15, 1, 0, 0, 0,
479        ];
480
481        let madt = MadtParser::new(DATA).unwrap();
482        let entries = madt.parse_apic_ids().unwrap();
483
484        assert_eq!(
485            entries,
486            vec![
487                Some(0),
488                None,
489                None,
490                Some(1),
491                None,
492                Some(2),
493                None,
494                Some(3),
495                None,
496                Some(4),
497                None,
498                Some(5),
499                None,
500                Some(6),
501                None,
502                Some(7),
503                None,
504                Some(8),
505                None,
506                Some(9),
507                None,
508                Some(10),
509                None,
510                Some(11),
511                None,
512                Some(12),
513                None,
514                Some(13),
515                None,
516                Some(14),
517                None,
518                Some(15)
519            ]
520        );
521    }
522
523    #[test]
524    fn single_apic() {
525        // single APIC
526        const DATA: &[u8] = &[
527            0x41, 0x50, 0x49, 0x43, 0x50, 0x00, 0x00, 0x00, 0x04, 0x23, 0x56, 0x52, 0x54, 0x55,
528            0x41, 0x4c, 0x4d, 0x49, 0x43, 0x52, 0x4f, 0x53, 0x46, 0x54, 0x01, 0x00, 0x00, 0x00,
529            0x4d, 0x53, 0x46, 0x54, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0xfe, 0x00, 0x00,
530            0x00, 0x00, 0x01, 0x0c, 0x01, 0x00, 0x00, 0x00, 0xc0, 0xfe, 0x00, 0x00, 0x00, 0x00,
531            0x02, 0x0a, 0x00, 0x09, 0x09, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x04, 0x06, 0x01, 0x00,
532            0x00, 0x01, 0x00, 0x08, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00,
533        ];
534
535        let madt = MadtParser::new(DATA).unwrap();
536
537        let entries = madt.entries().collect::<Result<Vec<_>, _>>().unwrap();
538
539        assert_eq!(
540            entries[0],
541            MadtEntry::Apic(MadtApic {
542                typ: MadtType::APIC,
543                length: 8,
544                acpi_processor_uid: 1,
545                apic_id: 0,
546                flags: 1,
547            })
548        );
549    }
550
551    #[test]
552    #[cfg(feature = "alloc")]
553    fn madt_50_vps() {
554        const DATA: &[u8] = &[
555            0x41, 0x50, 0x49, 0x43, 0xd8, 0x01, 0x00, 0x00, 0x04, 0x06, 0x56, 0x52, 0x54, 0x55,
556            0x41, 0x4c, //  APIC......VRTUAL
557            0x4d, 0x49, 0x43, 0x52, 0x4f, 0x53, 0x46, 0x54, 0x01, 0x00, 0x00, 0x00, 0x4d, 0x53,
558            0x46, 0x54, //  MICROSFT....MSFT
559            0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x02, 0x0a,
560            0x00, 0x09, //  ................
561            0x09, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x04, 0x06, 0x01, 0x00, 0x00, 0x01, 0x01, 0x0c,
562            0x32, 0x00, //  ..............2.
563            0x00, 0x00, 0xc0, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x01, 0x00, 0x01, 0x00,
564            0x00, 0x00, //  ................
565            0x00, 0x08, 0x02, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x08, 0x03, 0x02, 0x01, 0x00,
566            0x00, 0x00, //  ................
567            0x00, 0x08, 0x04, 0x03, 0x01, 0x00, 0x00, 0x00, 0x00, 0x08, 0x05, 0x04, 0x01, 0x00,
568            0x00, 0x00, //  ................
569            0x00, 0x08, 0x06, 0x05, 0x01, 0x00, 0x00, 0x00, 0x00, 0x08, 0x07, 0x06, 0x01, 0x00,
570            0x00, 0x00, //  ................
571            0x00, 0x08, 0x08, 0x07, 0x01, 0x00, 0x00, 0x00, 0x00, 0x08, 0x09, 0x08, 0x01, 0x00,
572            0x00, 0x00, //  ................
573            0x00, 0x08, 0x0a, 0x09, 0x01, 0x00, 0x00, 0x00, 0x00, 0x08, 0x0b, 0x0a, 0x01, 0x00,
574            0x00, 0x00, //  ................
575            0x00, 0x08, 0x0c, 0x0b, 0x01, 0x00, 0x00, 0x00, 0x00, 0x08, 0x0d, 0x0c, 0x01, 0x00,
576            0x00, 0x00, //  ................
577            0x00, 0x08, 0x0e, 0x10, 0x01, 0x00, 0x00, 0x00, 0x00, 0x08, 0x0f, 0x11, 0x01, 0x00,
578            0x00, 0x00, //  ................
579            0x00, 0x08, 0x10, 0x12, 0x01, 0x00, 0x00, 0x00, 0x00, 0x08, 0x11, 0x13, 0x01, 0x00,
580            0x00, 0x00, //  ................
581            0x00, 0x08, 0x12, 0x14, 0x01, 0x00, 0x00, 0x00, 0x00, 0x08, 0x13, 0x15, 0x01, 0x00,
582            0x00, 0x00, //  ................
583            0x00, 0x08, 0x14, 0x16, 0x01, 0x00, 0x00, 0x00, 0x00, 0x08, 0x15, 0x17, 0x01, 0x00,
584            0x00, 0x00, //  ................
585            0x00, 0x08, 0x16, 0x18, 0x01, 0x00, 0x00, 0x00, 0x00, 0x08, 0x17, 0x19, 0x01, 0x00,
586            0x00, 0x00, //  ................
587            0x00, 0x08, 0x18, 0x1a, 0x01, 0x00, 0x00, 0x00, 0x00, 0x08, 0x19, 0x1b, 0x01, 0x00,
588            0x00, 0x00, //  ................
589            0x00, 0x08, 0x1a, 0x1c, 0x01, 0x00, 0x00, 0x00, 0x00, 0x08, 0x1b, 0x20, 0x01, 0x00,
590            0x00, 0x00, //  ........... ....
591            0x00, 0x08, 0x1c, 0x21, 0x01, 0x00, 0x00, 0x00, 0x00, 0x08, 0x1d, 0x22, 0x01, 0x00,
592            0x00, 0x00, //  ...!......."....
593            0x00, 0x08, 0x1e, 0x23, 0x01, 0x00, 0x00, 0x00, 0x00, 0x08, 0x1f, 0x24, 0x01, 0x00,
594            0x00, 0x00, //  ...#.......$....
595            0x00, 0x08, 0x20, 0x25, 0x01, 0x00, 0x00, 0x00, 0x00, 0x08, 0x21, 0x26, 0x01, 0x00,
596            0x00, 0x00, //  .. %......!&....
597            0x00, 0x08, 0x22, 0x27, 0x01, 0x00, 0x00, 0x00, 0x00, 0x08, 0x23, 0x28, 0x01, 0x00,
598            0x00, 0x00, //  .."'......#(....
599            0x00, 0x08, 0x24, 0x29, 0x01, 0x00, 0x00, 0x00, 0x00, 0x08, 0x25, 0x2a, 0x01, 0x00,
600            0x00, 0x00, //  ..$)......%*....
601            0x00, 0x08, 0x26, 0x2b, 0x01, 0x00, 0x00, 0x00, 0x00, 0x08, 0x27, 0x30, 0x01, 0x00,
602            0x00, 0x00, //  ..&+......'0....
603            0x00, 0x08, 0x28, 0x31, 0x01, 0x00, 0x00, 0x00, 0x00, 0x08, 0x29, 0x32, 0x01, 0x00,
604            0x00, 0x00, //  ..(1......)2....
605            0x00, 0x08, 0x2a, 0x33, 0x01, 0x00, 0x00, 0x00, 0x00, 0x08, 0x2b, 0x34, 0x01, 0x00,
606            0x00, 0x00, //  ..*3......+4....
607            0x00, 0x08, 0x2c, 0x35, 0x01, 0x00, 0x00, 0x00, 0x00, 0x08, 0x2d, 0x36, 0x01, 0x00,
608            0x00, 0x00, //  ..,5......-6....
609            0x00, 0x08, 0x2e, 0x37, 0x01, 0x00, 0x00, 0x00, 0x00, 0x08, 0x2f, 0x38, 0x01, 0x00,
610            0x00, 0x00, //  ...7....../8....
611            0x00, 0x08, 0x30, 0x39, 0x01, 0x00, 0x00, 0x00, 0x00, 0x08, 0x31, 0x3a, 0x01, 0x00,
612            0x00, 0x00, //  ..09......1:....
613            0x00, 0x08, 0x32, 0x3b, 0x01, 0x00, 0x00, 0x00, // ..2;....
614        ];
615
616        let madt = MadtParser::new(DATA).unwrap();
617
618        let entries = madt.entries().collect::<Result<Vec<_>, _>>().unwrap();
619
620        assert_eq!(entries.len(), 50);
621        assert!(matches!(
622            entries[0],
623            MadtEntry::Apic(MadtApic {
624                typ: MadtType::APIC,
625                length: 8,
626                acpi_processor_uid: 1,
627                apic_id: 0,
628                flags: 1
629            })
630        ));
631        assert!(matches!(
632            entries[49],
633            MadtEntry::Apic(MadtApic {
634                typ: MadtType::APIC,
635                length: 8,
636                acpi_processor_uid: 50,
637                apic_id: 59,
638                flags: 1
639            })
640        ));
641
642        let entries = madt.parse_apic_ids().unwrap();
643
644        assert_eq!(
645            entries,
646            (0..13)
647                .chain(16..29)
648                .chain(32..44)
649                .chain(48..60)
650                .map(Some)
651                .collect::<Vec<_>>()
652        );
653    }
654
655    #[test]
656    #[cfg(feature = "alloc")]
657    fn madt_256() {
658        const DATA: &[u8] = &[
659            0x41, 0x50, 0x49, 0x43, 0x50, 0x08, 0x00, 0x00, 0x04, 0x14, 0x56, 0x52, 0x54, 0x55,
660            0x41, 0x4c, //  APICP.....VRTUAL
661            0x4d, 0x49, 0x43, 0x52, 0x4f, 0x53, 0x46, 0x54, 0x01, 0x00, 0x00, 0x00, 0x4d, 0x53,
662            0x46, 0x54, //  MICROSFT....MSFT
663            0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x02, 0x0a,
664            0x00, 0x09, //  ................
665            0x09, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x04, 0x06, 0x01, 0x00, 0x00, 0x01, 0x01, 0x0c,
666            0x00, 0x00, //  ................
667            0x00, 0x00, 0xc0, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x01, 0x00, 0x01, 0x00,
668            0x00, 0x00, //  ................
669            0x00, 0x08, 0x02, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x08, 0x03, 0x02, 0x01, 0x00,
670            0x00, 0x00, //  ................
671            0x00, 0x08, 0x04, 0x03, 0x01, 0x00, 0x00, 0x00, 0x00, 0x08, 0x05, 0x04, 0x01, 0x00,
672            0x00, 0x00, //  ................
673            0x00, 0x08, 0x06, 0x05, 0x01, 0x00, 0x00, 0x00, 0x00, 0x08, 0x07, 0x06, 0x01, 0x00,
674            0x00, 0x00, //  ................
675            0x00, 0x08, 0x08, 0x07, 0x01, 0x00, 0x00, 0x00, 0x00, 0x08, 0x09, 0x08, 0x01, 0x00,
676            0x00, 0x00, //  ................
677            0x00, 0x08, 0x0a, 0x09, 0x01, 0x00, 0x00, 0x00, 0x00, 0x08, 0x0b, 0x0a, 0x01, 0x00,
678            0x00, 0x00, //  ................
679            0x00, 0x08, 0x0c, 0x0b, 0x01, 0x00, 0x00, 0x00, 0x00, 0x08, 0x0d, 0x0c, 0x01, 0x00,
680            0x00, 0x00, //  ................
681            0x00, 0x08, 0x0e, 0x0d, 0x01, 0x00, 0x00, 0x00, 0x00, 0x08, 0x0f, 0x0e, 0x01, 0x00,
682            0x00, 0x00, //  ................
683            0x00, 0x08, 0x10, 0x0f, 0x01, 0x00, 0x00, 0x00, 0x00, 0x08, 0x11, 0x10, 0x01, 0x00,
684            0x00, 0x00, //  ................
685            0x00, 0x08, 0x12, 0x11, 0x01, 0x00, 0x00, 0x00, 0x00, 0x08, 0x13, 0x12, 0x01, 0x00,
686            0x00, 0x00, //  ................
687            0x00, 0x08, 0x14, 0x13, 0x01, 0x00, 0x00, 0x00, 0x00, 0x08, 0x15, 0x14, 0x01, 0x00,
688            0x00, 0x00, //  ................
689            0x00, 0x08, 0x16, 0x15, 0x01, 0x00, 0x00, 0x00, 0x00, 0x08, 0x17, 0x16, 0x01, 0x00,
690            0x00, 0x00, //  ................
691            0x00, 0x08, 0x18, 0x17, 0x01, 0x00, 0x00, 0x00, 0x00, 0x08, 0x19, 0x18, 0x01, 0x00,
692            0x00, 0x00, //  ................
693            0x00, 0x08, 0x1a, 0x19, 0x01, 0x00, 0x00, 0x00, 0x00, 0x08, 0x1b, 0x1a, 0x01, 0x00,
694            0x00, 0x00, //  ................
695            0x00, 0x08, 0x1c, 0x1b, 0x01, 0x00, 0x00, 0x00, 0x00, 0x08, 0x1d, 0x1c, 0x01, 0x00,
696            0x00, 0x00, //  ................
697            0x00, 0x08, 0x1e, 0x1d, 0x01, 0x00, 0x00, 0x00, 0x00, 0x08, 0x1f, 0x1e, 0x01, 0x00,
698            0x00, 0x00, //  ................
699            0x00, 0x08, 0x20, 0x1f, 0x01, 0x00, 0x00, 0x00, 0x00, 0x08, 0x21, 0x20, 0x01, 0x00,
700            0x00, 0x00, //  .. .......! ....
701            0x00, 0x08, 0x22, 0x21, 0x01, 0x00, 0x00, 0x00, 0x00, 0x08, 0x23, 0x22, 0x01, 0x00,
702            0x00, 0x00, //  .."!......#"....
703            0x00, 0x08, 0x24, 0x23, 0x01, 0x00, 0x00, 0x00, 0x00, 0x08, 0x25, 0x24, 0x01, 0x00,
704            0x00, 0x00, //  ..$#......%$....
705            0x00, 0x08, 0x26, 0x25, 0x01, 0x00, 0x00, 0x00, 0x00, 0x08, 0x27, 0x26, 0x01, 0x00,
706            0x00, 0x00, //  ..&%......'&....
707            0x00, 0x08, 0x28, 0x27, 0x01, 0x00, 0x00, 0x00, 0x00, 0x08, 0x29, 0x28, 0x01, 0x00,
708            0x00, 0x00, //  ..('......)(....
709            0x00, 0x08, 0x2a, 0x29, 0x01, 0x00, 0x00, 0x00, 0x00, 0x08, 0x2b, 0x2a, 0x01, 0x00,
710            0x00, 0x00, //  ..*)......+*....
711            0x00, 0x08, 0x2c, 0x2b, 0x01, 0x00, 0x00, 0x00, 0x00, 0x08, 0x2d, 0x2c, 0x01, 0x00,
712            0x00, 0x00, //  ..,+......-,....
713            0x00, 0x08, 0x2e, 0x2d, 0x01, 0x00, 0x00, 0x00, 0x00, 0x08, 0x2f, 0x2e, 0x01, 0x00,
714            0x00, 0x00, //  ...-....../.....
715            0x00, 0x08, 0x30, 0x2f, 0x01, 0x00, 0x00, 0x00, 0x00, 0x08, 0x31, 0x30, 0x01, 0x00,
716            0x00, 0x00, //  ..0/......10....
717            0x00, 0x08, 0x32, 0x31, 0x01, 0x00, 0x00, 0x00, 0x00, 0x08, 0x33, 0x32, 0x01, 0x00,
718            0x00, 0x00, //  ..21......32....
719            0x00, 0x08, 0x34, 0x33, 0x01, 0x00, 0x00, 0x00, 0x00, 0x08, 0x35, 0x34, 0x01, 0x00,
720            0x00, 0x00, //  ..43......54....
721            0x00, 0x08, 0x36, 0x35, 0x01, 0x00, 0x00, 0x00, 0x00, 0x08, 0x37, 0x36, 0x01, 0x00,
722            0x00, 0x00, //  ..65......76....
723            0x00, 0x08, 0x38, 0x37, 0x01, 0x00, 0x00, 0x00, 0x00, 0x08, 0x39, 0x38, 0x01, 0x00,
724            0x00, 0x00, //  ..87......98....
725            0x00, 0x08, 0x3a, 0x39, 0x01, 0x00, 0x00, 0x00, 0x00, 0x08, 0x3b, 0x3a, 0x01, 0x00,
726            0x00, 0x00, //  ..:9......;:....
727            0x00, 0x08, 0x3c, 0x3b, 0x01, 0x00, 0x00, 0x00, 0x00, 0x08, 0x3d, 0x3c, 0x01, 0x00,
728            0x00, 0x00, //  ..<;......=<....
729            0x00, 0x08, 0x3e, 0x3d, 0x01, 0x00, 0x00, 0x00, 0x00, 0x08, 0x3f, 0x3e, 0x01, 0x00,
730            0x00, 0x00, //  ..>=......?>....
731            0x00, 0x08, 0x40, 0x3f, 0x01, 0x00, 0x00, 0x00, 0x00, 0x08, 0x41, 0x40, 0x01, 0x00,
732            0x00, 0x00, //  ..@?......A@....
733            0x00, 0x08, 0x42, 0x41, 0x01, 0x00, 0x00, 0x00, 0x00, 0x08, 0x43, 0x42, 0x01, 0x00,
734            0x00, 0x00, //  ..BA......CB....
735            0x00, 0x08, 0x44, 0x43, 0x01, 0x00, 0x00, 0x00, 0x00, 0x08, 0x45, 0x44, 0x01, 0x00,
736            0x00, 0x00, //  ..DC......ED....
737            0x00, 0x08, 0x46, 0x45, 0x01, 0x00, 0x00, 0x00, 0x00, 0x08, 0x47, 0x46, 0x01, 0x00,
738            0x00, 0x00, //  ..FE......GF....
739            0x00, 0x08, 0x48, 0x47, 0x01, 0x00, 0x00, 0x00, 0x00, 0x08, 0x49, 0x48, 0x01, 0x00,
740            0x00, 0x00, //  ..HG......IH....
741            0x00, 0x08, 0x4a, 0x49, 0x01, 0x00, 0x00, 0x00, 0x00, 0x08, 0x4b, 0x4a, 0x01, 0x00,
742            0x00, 0x00, //  ..JI......KJ....
743            0x00, 0x08, 0x4c, 0x4b, 0x01, 0x00, 0x00, 0x00, 0x00, 0x08, 0x4d, 0x4c, 0x01, 0x00,
744            0x00, 0x00, //  ..LK......ML....
745            0x00, 0x08, 0x4e, 0x4d, 0x01, 0x00, 0x00, 0x00, 0x00, 0x08, 0x4f, 0x4e, 0x01, 0x00,
746            0x00, 0x00, //  ..NM......ON....
747            0x00, 0x08, 0x50, 0x4f, 0x01, 0x00, 0x00, 0x00, 0x00, 0x08, 0x51, 0x50, 0x01, 0x00,
748            0x00, 0x00, //  ..PO......QP....
749            0x00, 0x08, 0x52, 0x51, 0x01, 0x00, 0x00, 0x00, 0x00, 0x08, 0x53, 0x52, 0x01, 0x00,
750            0x00, 0x00, //  ..RQ......SR....
751            0x00, 0x08, 0x54, 0x53, 0x01, 0x00, 0x00, 0x00, 0x00, 0x08, 0x55, 0x54, 0x01, 0x00,
752            0x00, 0x00, //  ..TS......UT....
753            0x00, 0x08, 0x56, 0x55, 0x01, 0x00, 0x00, 0x00, 0x00, 0x08, 0x57, 0x56, 0x01, 0x00,
754            0x00, 0x00, //  ..VU......WV....
755            0x00, 0x08, 0x58, 0x57, 0x01, 0x00, 0x00, 0x00, 0x00, 0x08, 0x59, 0x58, 0x01, 0x00,
756            0x00, 0x00, //  ..XW......YX....
757            0x00, 0x08, 0x5a, 0x59, 0x01, 0x00, 0x00, 0x00, 0x00, 0x08, 0x5b, 0x5a, 0x01, 0x00,
758            0x00, 0x00, //  ..ZY......[Z....
759            0x00, 0x08, 0x5c, 0x5b, 0x01, 0x00, 0x00, 0x00, 0x00, 0x08, 0x5d, 0x5c, 0x01, 0x00,
760            0x00, 0x00, //  ..\[......]\....
761            0x00, 0x08, 0x5e, 0x5d, 0x01, 0x00, 0x00, 0x00, 0x00, 0x08, 0x5f, 0x5e, 0x01, 0x00,
762            0x00, 0x00, //  ..^]......_^....
763            0x00, 0x08, 0x60, 0x5f, 0x01, 0x00, 0x00, 0x00, 0x00, 0x08, 0x61, 0x60, 0x01, 0x00,
764            0x00, 0x00, //  ..`_......a`....
765            0x00, 0x08, 0x62, 0x61, 0x01, 0x00, 0x00, 0x00, 0x00, 0x08, 0x63, 0x62, 0x01, 0x00,
766            0x00, 0x00, //  ..ba......cb....
767            0x00, 0x08, 0x64, 0x63, 0x01, 0x00, 0x00, 0x00, 0x00, 0x08, 0x65, 0x64, 0x01, 0x00,
768            0x00, 0x00, //  ..dc......ed....
769            0x00, 0x08, 0x66, 0x65, 0x01, 0x00, 0x00, 0x00, 0x00, 0x08, 0x67, 0x66, 0x01, 0x00,
770            0x00, 0x00, //  ..fe......gf....
771            0x00, 0x08, 0x68, 0x67, 0x01, 0x00, 0x00, 0x00, 0x00, 0x08, 0x69, 0x68, 0x01, 0x00,
772            0x00, 0x00, //  ..hg......ih....
773            0x00, 0x08, 0x6a, 0x69, 0x01, 0x00, 0x00, 0x00, 0x00, 0x08, 0x6b, 0x6a, 0x01, 0x00,
774            0x00, 0x00, //  ..ji......kj....
775            0x00, 0x08, 0x6c, 0x6b, 0x01, 0x00, 0x00, 0x00, 0x00, 0x08, 0x6d, 0x6c, 0x01, 0x00,
776            0x00, 0x00, //  ..lk......ml....
777            0x00, 0x08, 0x6e, 0x6d, 0x01, 0x00, 0x00, 0x00, 0x00, 0x08, 0x6f, 0x6e, 0x01, 0x00,
778            0x00, 0x00, //  ..nm......on....
779            0x00, 0x08, 0x70, 0x6f, 0x01, 0x00, 0x00, 0x00, 0x00, 0x08, 0x71, 0x70, 0x01, 0x00,
780            0x00, 0x00, //  ..po......qp....
781            0x00, 0x08, 0x72, 0x71, 0x01, 0x00, 0x00, 0x00, 0x00, 0x08, 0x73, 0x72, 0x01, 0x00,
782            0x00, 0x00, //  ..rq......sr....
783            0x00, 0x08, 0x74, 0x73, 0x01, 0x00, 0x00, 0x00, 0x00, 0x08, 0x75, 0x74, 0x01, 0x00,
784            0x00, 0x00, //  ..ts......ut....
785            0x00, 0x08, 0x76, 0x75, 0x01, 0x00, 0x00, 0x00, 0x00, 0x08, 0x77, 0x76, 0x01, 0x00,
786            0x00, 0x00, //  ..vu......wv....
787            0x00, 0x08, 0x78, 0x77, 0x01, 0x00, 0x00, 0x00, 0x00, 0x08, 0x79, 0x78, 0x01, 0x00,
788            0x00, 0x00, //  ..xw......yx....
789            0x00, 0x08, 0x7a, 0x79, 0x01, 0x00, 0x00, 0x00, 0x00, 0x08, 0x7b, 0x7a, 0x01, 0x00,
790            0x00, 0x00, //  ..zy......{z....
791            0x00, 0x08, 0x7c, 0x7b, 0x01, 0x00, 0x00, 0x00, 0x00, 0x08, 0x7d, 0x7c, 0x01, 0x00,
792            0x00, 0x00, //  ..|{......}|....
793            0x00, 0x08, 0x7e, 0x7d, 0x01, 0x00, 0x00, 0x00, 0x00, 0x08, 0x7f, 0x7e, 0x01, 0x00,
794            0x00, 0x00, //  ..~}.......~....
795            0x00, 0x08, 0x80, 0x7f, 0x01, 0x00, 0x00, 0x00, 0x00, 0x08, 0x81, 0x80, 0x01, 0x00,
796            0x00, 0x00, //  ................
797            0x00, 0x08, 0x82, 0x81, 0x01, 0x00, 0x00, 0x00, 0x00, 0x08, 0x83, 0x82, 0x01, 0x00,
798            0x00, 0x00, //  ................
799            0x00, 0x08, 0x84, 0x83, 0x01, 0x00, 0x00, 0x00, 0x00, 0x08, 0x85, 0x84, 0x01, 0x00,
800            0x00, 0x00, //  ................
801            0x00, 0x08, 0x86, 0x85, 0x01, 0x00, 0x00, 0x00, 0x00, 0x08, 0x87, 0x86, 0x01, 0x00,
802            0x00, 0x00, //  ................
803            0x00, 0x08, 0x88, 0x87, 0x01, 0x00, 0x00, 0x00, 0x00, 0x08, 0x89, 0x88, 0x01, 0x00,
804            0x00, 0x00, //  ................
805            0x00, 0x08, 0x8a, 0x89, 0x01, 0x00, 0x00, 0x00, 0x00, 0x08, 0x8b, 0x8a, 0x01, 0x00,
806            0x00, 0x00, //  ................
807            0x00, 0x08, 0x8c, 0x8b, 0x01, 0x00, 0x00, 0x00, 0x00, 0x08, 0x8d, 0x8c, 0x01, 0x00,
808            0x00, 0x00, //  ................
809            0x00, 0x08, 0x8e, 0x8d, 0x01, 0x00, 0x00, 0x00, 0x00, 0x08, 0x8f, 0x8e, 0x01, 0x00,
810            0x00, 0x00, //  ................
811            0x00, 0x08, 0x90, 0x8f, 0x01, 0x00, 0x00, 0x00, 0x00, 0x08, 0x91, 0x90, 0x01, 0x00,
812            0x00, 0x00, //  ................
813            0x00, 0x08, 0x92, 0x91, 0x01, 0x00, 0x00, 0x00, 0x00, 0x08, 0x93, 0x92, 0x01, 0x00,
814            0x00, 0x00, //  ................
815            0x00, 0x08, 0x94, 0x93, 0x01, 0x00, 0x00, 0x00, 0x00, 0x08, 0x95, 0x94, 0x01, 0x00,
816            0x00, 0x00, //  ................
817            0x00, 0x08, 0x96, 0x95, 0x01, 0x00, 0x00, 0x00, 0x00, 0x08, 0x97, 0x96, 0x01, 0x00,
818            0x00, 0x00, //  ................
819            0x00, 0x08, 0x98, 0x97, 0x01, 0x00, 0x00, 0x00, 0x00, 0x08, 0x99, 0x98, 0x01, 0x00,
820            0x00, 0x00, //  ................
821            0x00, 0x08, 0x9a, 0x99, 0x01, 0x00, 0x00, 0x00, 0x00, 0x08, 0x9b, 0x9a, 0x01, 0x00,
822            0x00, 0x00, //  ................
823            0x00, 0x08, 0x9c, 0x9b, 0x01, 0x00, 0x00, 0x00, 0x00, 0x08, 0x9d, 0x9c, 0x01, 0x00,
824            0x00, 0x00, //  ................
825            0x00, 0x08, 0x9e, 0x9d, 0x01, 0x00, 0x00, 0x00, 0x00, 0x08, 0x9f, 0x9e, 0x01, 0x00,
826            0x00, 0x00, //  ................
827            0x00, 0x08, 0xa0, 0x9f, 0x01, 0x00, 0x00, 0x00, 0x00, 0x08, 0xa1, 0xa0, 0x01, 0x00,
828            0x00, 0x00, //  ................
829            0x00, 0x08, 0xa2, 0xa1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x08, 0xa3, 0xa2, 0x01, 0x00,
830            0x00, 0x00, //  ................
831            0x00, 0x08, 0xa4, 0xa3, 0x01, 0x00, 0x00, 0x00, 0x00, 0x08, 0xa5, 0xa4, 0x01, 0x00,
832            0x00, 0x00, //  ................
833            0x00, 0x08, 0xa6, 0xa5, 0x01, 0x00, 0x00, 0x00, 0x00, 0x08, 0xa7, 0xa6, 0x01, 0x00,
834            0x00, 0x00, //  ................
835            0x00, 0x08, 0xa8, 0xa7, 0x01, 0x00, 0x00, 0x00, 0x00, 0x08, 0xa9, 0xa8, 0x01, 0x00,
836            0x00, 0x00, //  ................
837            0x00, 0x08, 0xaa, 0xa9, 0x01, 0x00, 0x00, 0x00, 0x00, 0x08, 0xab, 0xaa, 0x01, 0x00,
838            0x00, 0x00, //  ................
839            0x00, 0x08, 0xac, 0xab, 0x01, 0x00, 0x00, 0x00, 0x00, 0x08, 0xad, 0xac, 0x01, 0x00,
840            0x00, 0x00, //  ................
841            0x00, 0x08, 0xae, 0xad, 0x01, 0x00, 0x00, 0x00, 0x00, 0x08, 0xaf, 0xae, 0x01, 0x00,
842            0x00, 0x00, //  ................
843            0x00, 0x08, 0xb0, 0xaf, 0x01, 0x00, 0x00, 0x00, 0x00, 0x08, 0xb1, 0xb0, 0x01, 0x00,
844            0x00, 0x00, //  ................
845            0x00, 0x08, 0xb2, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x08, 0xb3, 0xb2, 0x01, 0x00,
846            0x00, 0x00, //  ................
847            0x00, 0x08, 0xb4, 0xb3, 0x01, 0x00, 0x00, 0x00, 0x00, 0x08, 0xb5, 0xb4, 0x01, 0x00,
848            0x00, 0x00, //  ................
849            0x00, 0x08, 0xb6, 0xb5, 0x01, 0x00, 0x00, 0x00, 0x00, 0x08, 0xb7, 0xb6, 0x01, 0x00,
850            0x00, 0x00, //  ................
851            0x00, 0x08, 0xb8, 0xb7, 0x01, 0x00, 0x00, 0x00, 0x00, 0x08, 0xb9, 0xb8, 0x01, 0x00,
852            0x00, 0x00, //  ................
853            0x00, 0x08, 0xba, 0xb9, 0x01, 0x00, 0x00, 0x00, 0x00, 0x08, 0xbb, 0xba, 0x01, 0x00,
854            0x00, 0x00, //  ................
855            0x00, 0x08, 0xbc, 0xbb, 0x01, 0x00, 0x00, 0x00, 0x00, 0x08, 0xbd, 0xbc, 0x01, 0x00,
856            0x00, 0x00, //  ................
857            0x00, 0x08, 0xbe, 0xbd, 0x01, 0x00, 0x00, 0x00, 0x00, 0x08, 0xbf, 0xbe, 0x01, 0x00,
858            0x00, 0x00, //  ................
859            0x00, 0x08, 0xc0, 0xbf, 0x01, 0x00, 0x00, 0x00, 0x00, 0x08, 0xc1, 0xc0, 0x01, 0x00,
860            0x00, 0x00, //  ................
861            0x00, 0x08, 0xc2, 0xc1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x08, 0xc3, 0xc2, 0x01, 0x00,
862            0x00, 0x00, //  ................
863            0x00, 0x08, 0xc4, 0xc3, 0x01, 0x00, 0x00, 0x00, 0x00, 0x08, 0xc5, 0xc4, 0x01, 0x00,
864            0x00, 0x00, //  ................
865            0x00, 0x08, 0xc6, 0xc5, 0x01, 0x00, 0x00, 0x00, 0x00, 0x08, 0xc7, 0xc6, 0x01, 0x00,
866            0x00, 0x00, //  ................
867            0x00, 0x08, 0xc8, 0xc7, 0x01, 0x00, 0x00, 0x00, 0x00, 0x08, 0xc9, 0xc8, 0x01, 0x00,
868            0x00, 0x00, //  ................
869            0x00, 0x08, 0xca, 0xc9, 0x01, 0x00, 0x00, 0x00, 0x00, 0x08, 0xcb, 0xca, 0x01, 0x00,
870            0x00, 0x00, //  ................
871            0x00, 0x08, 0xcc, 0xcb, 0x01, 0x00, 0x00, 0x00, 0x00, 0x08, 0xcd, 0xcc, 0x01, 0x00,
872            0x00, 0x00, //  ................
873            0x00, 0x08, 0xce, 0xcd, 0x01, 0x00, 0x00, 0x00, 0x00, 0x08, 0xcf, 0xce, 0x01, 0x00,
874            0x00, 0x00, //  ................
875            0x00, 0x08, 0xd0, 0xcf, 0x01, 0x00, 0x00, 0x00, 0x00, 0x08, 0xd1, 0xd0, 0x01, 0x00,
876            0x00, 0x00, //  ................
877            0x00, 0x08, 0xd2, 0xd1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x08, 0xd3, 0xd2, 0x01, 0x00,
878            0x00, 0x00, //  ................
879            0x00, 0x08, 0xd4, 0xd3, 0x01, 0x00, 0x00, 0x00, 0x00, 0x08, 0xd5, 0xd4, 0x01, 0x00,
880            0x00, 0x00, //  ................
881            0x00, 0x08, 0xd6, 0xd5, 0x01, 0x00, 0x00, 0x00, 0x00, 0x08, 0xd7, 0xd6, 0x01, 0x00,
882            0x00, 0x00, //  ................
883            0x00, 0x08, 0xd8, 0xd7, 0x01, 0x00, 0x00, 0x00, 0x00, 0x08, 0xd9, 0xd8, 0x01, 0x00,
884            0x00, 0x00, //  ................
885            0x00, 0x08, 0xda, 0xd9, 0x01, 0x00, 0x00, 0x00, 0x00, 0x08, 0xdb, 0xda, 0x01, 0x00,
886            0x00, 0x00, //  ................
887            0x00, 0x08, 0xdc, 0xdb, 0x01, 0x00, 0x00, 0x00, 0x00, 0x08, 0xdd, 0xdc, 0x01, 0x00,
888            0x00, 0x00, //  ................
889            0x00, 0x08, 0xde, 0xdd, 0x01, 0x00, 0x00, 0x00, 0x00, 0x08, 0xdf, 0xde, 0x01, 0x00,
890            0x00, 0x00, //  ................
891            0x00, 0x08, 0xe0, 0xdf, 0x01, 0x00, 0x00, 0x00, 0x00, 0x08, 0xe1, 0xe0, 0x01, 0x00,
892            0x00, 0x00, //  ................
893            0x00, 0x08, 0xe2, 0xe1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x08, 0xe3, 0xe2, 0x01, 0x00,
894            0x00, 0x00, //  ................
895            0x00, 0x08, 0xe4, 0xe3, 0x01, 0x00, 0x00, 0x00, 0x00, 0x08, 0xe5, 0xe4, 0x01, 0x00,
896            0x00, 0x00, //  ................
897            0x00, 0x08, 0xe6, 0xe5, 0x01, 0x00, 0x00, 0x00, 0x00, 0x08, 0xe7, 0xe6, 0x01, 0x00,
898            0x00, 0x00, //  ................
899            0x00, 0x08, 0xe8, 0xe7, 0x01, 0x00, 0x00, 0x00, 0x00, 0x08, 0xe9, 0xe8, 0x01, 0x00,
900            0x00, 0x00, //  ................
901            0x00, 0x08, 0xea, 0xe9, 0x01, 0x00, 0x00, 0x00, 0x00, 0x08, 0xeb, 0xea, 0x01, 0x00,
902            0x00, 0x00, //  ................
903            0x00, 0x08, 0xec, 0xeb, 0x01, 0x00, 0x00, 0x00, 0x00, 0x08, 0xed, 0xec, 0x01, 0x00,
904            0x00, 0x00, //  ................
905            0x00, 0x08, 0xee, 0xed, 0x01, 0x00, 0x00, 0x00, 0x00, 0x08, 0xef, 0xee, 0x01, 0x00,
906            0x00, 0x00, //  ................
907            0x00, 0x08, 0xf0, 0xef, 0x01, 0x00, 0x00, 0x00, 0x00, 0x08, 0xf1, 0xf0, 0x01, 0x00,
908            0x00, 0x00, //  ................
909            0x00, 0x08, 0xf2, 0xf1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x08, 0xf3, 0xf2, 0x01, 0x00,
910            0x00, 0x00, //  ................
911            0x00, 0x08, 0xf4, 0xf3, 0x01, 0x00, 0x00, 0x00, 0x00, 0x08, 0xf5, 0xf4, 0x01, 0x00,
912            0x00, 0x00, //  ................
913            0x00, 0x08, 0xf6, 0xf5, 0x01, 0x00, 0x00, 0x00, 0x00, 0x08, 0xf7, 0xf6, 0x01, 0x00,
914            0x00, 0x00, //  ................
915            0x00, 0x08, 0xf8, 0xf7, 0x01, 0x00, 0x00, 0x00, 0x00, 0x08, 0xf9, 0xf8, 0x01, 0x00,
916            0x00, 0x00, //  ................
917            0x00, 0x08, 0xfa, 0xf9, 0x01, 0x00, 0x00, 0x00, 0x00, 0x08, 0xfb, 0xfa, 0x01, 0x00,
918            0x00, 0x00, //  ................
919            0x00, 0x08, 0xfc, 0xfb, 0x01, 0x00, 0x00, 0x00, 0x00, 0x08, 0xfd, 0xfc, 0x01, 0x00,
920            0x00, 0x00, //  ................
921            0x00, 0x08, 0xfe, 0xfd, 0x01, 0x00, 0x00, 0x00, 0x00, 0x08, 0xff, 0xfe, 0x01, 0x00,
922            0x00, 0x00, //  ................
923            0x09, 0x10, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01,
924            0x00, 0x00, //  ................
925        ];
926
927        let madt = MadtParser::new(DATA).unwrap();
928
929        let entries = madt.entries().collect::<Result<Vec<_>, _>>().unwrap();
930
931        assert!(entries.len() == 256);
932        assert!(matches!(
933            entries[0],
934            MadtEntry::Apic(MadtApic {
935                typ: MadtType::APIC,
936                length: 8,
937                acpi_processor_uid: 1,
938                apic_id: 0,
939                flags: 1
940            })
941        ));
942        assert!(matches!(
943            entries[255],
944            MadtEntry::X2Apic(MadtX2Apic {
945                typ: MadtType::X2APIC,
946                length: 16,
947                reserved: 0,
948                x2_apic_id: 255,
949                flags: 1,
950                acpi_processor_uid: 256
951            })
952        ));
953
954        let entries = madt.parse_apic_ids().unwrap();
955
956        assert_eq!(entries, (0..256).map(Some).collect::<Vec<_>>());
957    }
958}