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