diff --git a/src/io/dma.rs b/src/io/dma.rs index b356c8a..e16ffba 100644 --- a/src/io/dma.rs +++ b/src/io/dma.rs @@ -13,12 +13,26 @@ pub struct PhysBox { size: usize } +#[cfg(target_arch = "x86_64")] +const PAGE_SIZE: usize = 4096; + +const fn round_up(x: usize) -> usize { + (x + PAGE_SIZE - 1) / PAGE_SIZE * PAGE_SIZE +} +fn assert_aligned(x: usize) { + assert_eq!(x % PAGE_SIZE, 0); +} + impl PhysBox { - /// Construct a PhysBox from an address and a size. + /// Construct a PhysBox from an address and a size. The address must be page-aligned, and the + /// size must similarly be a multiple of the page size. /// /// # Safety /// This function is unsafe because when dropping, Self has to a valid allocation. pub unsafe fn from_raw_parts(address: usize, size: usize) -> Self { + assert_aligned(address); + assert_aligned(size); + Self { address, size, @@ -42,12 +56,10 @@ impl PhysBox { pub fn new_with_flags(size: usize, flags: PhysallocFlags) -> Result { assert!(!flags.contains(PhysallocFlags::PARTIAL_ALLOC)); + assert_aligned(size); let address = unsafe { crate::physalloc2(size, flags.bits())? }; - Ok(Self { - address, - size, - }) + Ok(unsafe { Self::from_raw_parts(address, size) }) } /// "Partially" allocate physical memory, in the sense that the allocation may be smaller than @@ -57,21 +69,18 @@ impl PhysBox { /// that first allocation only returns half the size, the driver can do another allocation /// and then let the device use both buffers. pub fn new_partial_allocation(size: usize, flags: PhysallocFlags, strategy: Option, mut min: usize) -> Result { + assert_aligned(size); debug_assert!(!(flags.contains(PhysallocFlags::PARTIAL_ALLOC) && strategy.is_none())); - let address = unsafe { crate::physalloc3(size, flags.bits() | strategy.map(|s| s as usize).unwrap_or(0), &mut min)? }; - Ok(Self { - address, - size: min, - }) + let address = unsafe { crate::physalloc3(size, flags.bits() | strategy.map_or(0, |s| s as usize), &mut min)? }; + Ok(unsafe { Self::from_raw_parts(address, size) }) } pub fn new(size: usize) -> Result { + assert_aligned(size); + let address = unsafe { crate::physalloc(size)? }; - Ok(Self { - address, - size, - }) + Ok(unsafe { Self::from_raw_parts(address, size) }) } } @@ -111,11 +120,11 @@ impl Dma { } pub fn new(value: T) -> Result { - let phys = PhysBox::new(mem::size_of::())?; + let phys = PhysBox::new(round_up(mem::size_of::()))?; Self::from_physbox(phys, value) } pub fn zeroed() -> Result>> { - let phys = PhysBox::new(mem::size_of::())?; + let phys = PhysBox::new(round_up(mem::size_of::()))?; Self::from_physbox_zeroed(phys) } } @@ -163,7 +172,7 @@ impl Dma<[T]> { /// * `T` must be properly aligned. /// * `T` must be valid as zeroed (i.e. no NonNull pointers). pub unsafe fn zeroed_unsized(count: usize) -> Result { - let phys = PhysBox::new(mem::size_of::() * count)?; + let phys = PhysBox::new(round_up(mem::size_of::() * count))?; Ok(Self::from_physbox_zeroed_unsized(phys, count)?.assume_init()) } } @@ -195,6 +204,6 @@ impl DerefMut for Dma { impl Drop for Dma { fn drop(&mut self) { unsafe { ptr::drop_in_place(self.virt) } - let _ = unsafe { crate::physunmap(self.virt as *mut u8 as usize) }; + let _ = unsafe { crate::funmap(self.virt as *mut u8 as usize, self.phys.size) }; } }