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