Skip to main content

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