Make DMA code use whole pages in syscalls.
This commit is contained in:
@@ -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<Self> {
|
||||
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<PartialAllocStrategy>, mut min: usize) -> Result<Self> {
|
||||
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<Self> {
|
||||
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<T> Dma<T> {
|
||||
}
|
||||
|
||||
pub fn new(value: T) -> Result<Self> {
|
||||
let phys = PhysBox::new(mem::size_of::<T>())?;
|
||||
let phys = PhysBox::new(round_up(mem::size_of::<T>()))?;
|
||||
Self::from_physbox(phys, value)
|
||||
}
|
||||
pub fn zeroed() -> Result<Dma<MaybeUninit<T>>> {
|
||||
let phys = PhysBox::new(mem::size_of::<T>())?;
|
||||
let phys = PhysBox::new(round_up(mem::size_of::<T>()))?;
|
||||
Self::from_physbox_zeroed(phys)
|
||||
}
|
||||
}
|
||||
@@ -163,7 +172,7 @@ impl<T> 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<Self> {
|
||||
let phys = PhysBox::new(mem::size_of::<T>() * count)?;
|
||||
let phys = PhysBox::new(round_up(mem::size_of::<T>() * count))?;
|
||||
Ok(Self::from_physbox_zeroed_unsized(phys, count)?.assume_init())
|
||||
}
|
||||
}
|
||||
@@ -195,6 +204,6 @@ impl<T: ?Sized> DerefMut for Dma<T> {
|
||||
impl<T: ?Sized> Drop for Dma<T> {
|
||||
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) };
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user