diff --git a/acpi/src/madt.rs b/acpi/src/madt.rs index f89ba17..2c9f48a 100644 --- a/acpi/src/madt.rs +++ b/acpi/src/madt.rs @@ -3,7 +3,11 @@ use crate::{ AcpiTable, }; use bit_field::BitField; -use core::{marker::PhantomData, mem}; +use core::{ + marker::{PhantomData, PhantomPinned}, + mem, + pin::Pin, +}; #[cfg(feature = "allocator_api")] use crate::{ @@ -27,16 +31,22 @@ pub enum MadtError { /// to read each entry from it. /// /// In modern versions of ACPI, the MADT can detail one of four interrupt models: -/// * The ancient dual-i8259 legacy PIC model -/// * The Advanced Programmable Interrupt Controller (APIC) model -/// * The Streamlined Advanced Programmable Interrupt Controller (SAPIC) model (for Itanium systems) -/// * The Generic Interrupt Controller (GIC) model (for ARM systems) +/// - The ancient dual-i8259 legacy PIC model +/// - The Advanced Programmable Interrupt Controller (APIC) model +/// - The Streamlined Advanced Programmable Interrupt Controller (SAPIC) model (for Itanium systems) +/// - The Generic Interrupt Controller (GIC) model (for ARM systems) +/// +/// The MADT is a variable-sized structure consisting of a static header and then a variable number of entries. +/// This type only contains the static portion, and then uses pointer arithmetic to parse the following entries. +/// To make this sound, this type is `!Unpin` - this prevents you from getting anything other than a `Pin<&Madt>` +/// out of a `PhysicalMapping`, and so prevents a `Madt` from being moved before [`Madt::entries`] is called. #[repr(C, packed)] -#[derive(Debug, Clone, Copy)] +#[derive(Debug)] pub struct Madt { pub header: SdtHeader, pub local_apic_address: u32, pub flags: u32, + _pinned: PhantomPinned, } /// ### Safety: Implementation properly represents a valid MADT. @@ -51,7 +61,7 @@ unsafe impl AcpiTable for Madt { impl Madt { #[cfg(feature = "allocator_api")] pub fn parse_interrupt_model_in<'a, A>( - &self, + self: Pin<&Self>, allocator: A, ) -> AcpiResult<(InterruptModel<'a, A>, Option>)> where @@ -96,7 +106,7 @@ impl Madt { #[cfg(feature = "allocator_api")] fn parse_apic_model_in<'a, A>( - &self, + self: Pin<&Self>, allocator: A, ) -> AcpiResult<(InterruptModel<'a, A>, Option>)> where @@ -301,9 +311,10 @@ impl Madt { )) } - pub fn entries(&self) -> MadtEntryIter { + pub fn entries(self: Pin<&Self>) -> MadtEntryIter<'_> { + let ptr = unsafe { Pin::into_inner_unchecked(self) as *const Madt as *const u8 }; MadtEntryIter { - pointer: unsafe { (self as *const Madt as *const u8).add(mem::size_of::()) }, + pointer: unsafe { ptr.add(mem::size_of::()) }, remaining_length: self.header.length - mem::size_of::() as u32, _phantom: PhantomData, }