diff --git a/kernel/driver/block/ahci/src/command.rs b/kernel/driver/block/ahci/src/command.rs index a6f524a4..aba491f9 100644 --- a/kernel/driver/block/ahci/src/command.rs +++ b/kernel/driver/block/ahci/src/command.rs @@ -1,10 +1,10 @@ use core::mem::{size_of, MaybeUninit}; use device_api::dma::DmaAllocator; -use libk::dma::{BusAddress, DmaBuffer}; +use libk::dma::{BusAddress, DmaBuffer, DmaSliceMut}; use tock_registers::register_structs; -use crate::{data::AtaString, error::AhciError, MAX_PRD_SIZE, SECTOR_SIZE}; +use crate::{data::AtaString, error::AhciError, MAX_PRD_SIZE}; #[derive(Clone, Copy, PartialEq, Eq, Debug)] #[repr(u8)] @@ -85,10 +85,7 @@ impl AtaIdentify { } impl AtaReadDmaEx { - pub fn new(lba: u64, sector_count: usize, buffer: &mut DmaBuffer<[MaybeUninit]>) -> Self { - assert_eq!(buffer.len() % SECTOR_SIZE, 0); - assert_ne!(buffer.len(), 0); - + pub fn new(lba: u64, sector_count: usize, buffer: DmaSliceMut>) -> Self { Self { lba, sector_count, diff --git a/kernel/driver/block/ahci/src/port.rs b/kernel/driver/block/ahci/src/port.rs index 8a918ff9..0166b9a9 100644 --- a/kernel/driver/block/ahci/src/port.rs +++ b/kernel/driver/block/ahci/src/port.rs @@ -10,9 +10,13 @@ use async_trait::async_trait; use bytemuck::Zeroable; use device_api::{device::Device, dma::DmaAllocator}; use futures_util::task::AtomicWaker; -use libk::{device::block::BlockDevice, dma::DmaBuffer, error::Error}; +use libk::{ + device::block::BlockDevice, + dma::{DmaBuffer, DmaSlice, DmaSliceMut}, + error::Error, +}; use libk_mm::{ - address::PhysicalAddress, device::DeviceMemoryIo, table::MapAttributes, PageProvider, PageSlice, + address::PhysicalAddress, device::DeviceMemoryIo, table::MapAttributes, PageProvider, }; use libk_util::{sync::IrqSafeSpinlock, waker::QueueWaker, OneTimeInit}; use tock_registers::interfaces::{Readable, Writeable}; @@ -305,31 +309,38 @@ impl AhciPort { #[async_trait] impl BlockDevice for AhciPort { - // TODO read directly into cache + fn allocate_buffer(&self, size: usize) -> Result]>, Error> { + DmaBuffer::new_uninit_slice(&*self.ahci.dma, size) + } + async fn read_aligned( &self, position: u64, - buffer: &mut PageSlice>, + buffer: DmaSliceMut<'_, MaybeUninit>, ) -> Result<(), Error> { - if position % SECTOR_SIZE as u64 != 0 { - return Err(Error::InvalidOperation); - } if buffer.len() % SECTOR_SIZE != 0 { + log::warn!("ahci: misaligned buffer size: {}", buffer.len()); + return Err(Error::InvalidOperation); + } + if position % SECTOR_SIZE as u64 != 0 { + log::warn!("ahci: misaligned read"); return Err(Error::InvalidOperation); } - let mut dma_buffer = DmaBuffer::new_uninit_slice(&*self.ahci.dma, buffer.len())?; let lba = position / SECTOR_SIZE as u64; + let lba_count = buffer.len() / SECTOR_SIZE; + if lba + lba_count as u64 >= self.block_count() { + log::warn!("ahci: read crosses medium end"); + return Err(Error::InvalidOperation); + } - let command = AtaReadDmaEx::new(lba, buffer.len() / SECTOR_SIZE, &mut dma_buffer); + let command = AtaReadDmaEx::new(lba, lba_count, buffer); self.submit(&command).await?.wait_for_completion().await?; - buffer.copy_from_slice(&dma_buffer[..]); - Ok(()) } - async fn write_aligned(&self, _position: u64, _buffer: &PageSlice) -> Result<(), Error> { + async fn write_aligned(&self, _position: u64, _buffer: DmaSlice<'_, u8>) -> Result<(), Error> { // TODO AtaWriteDmaEx Err(Error::NotImplemented) } diff --git a/kernel/driver/block/nvme/src/drive.rs b/kernel/driver/block/nvme/src/drive.rs index 4399af3f..c2279903 100644 --- a/kernel/driver/block/nvme/src/drive.rs +++ b/kernel/driver/block/nvme/src/drive.rs @@ -3,7 +3,11 @@ use core::mem::MaybeUninit; use alloc::{boxed::Box, sync::Arc}; use async_trait::async_trait; use device_api::device::Device; -use libk::{device::block::BlockDevice, dma::DmaBuffer, error::Error}; +use libk::{ + device::block::BlockDevice, + dma::{DmaBuffer, DmaSlice, DmaSliceMut}, + error::Error, +}; use libk_mm::{ address::{AsPhysicalAddress, PhysicalAddress}, table::MapAttributes, @@ -78,18 +82,27 @@ impl Device for NvmeNamespace { #[async_trait] impl BlockDevice for NvmeNamespace { + fn allocate_buffer(&self, size: usize) -> Result]>, Error> { + DmaBuffer::new_uninit_slice(&*self.controller.dma, size) + } + // TODO read directly to cache async fn read_aligned( &self, position: u64, - buffer: &mut PageSlice>, + buffer: DmaSliceMut<'_, MaybeUninit>, ) -> Result<(), Error> { - debug_assert_eq!(position % self.block_size() as u64, 0); + if position % self.block_size() as u64 != 0 { + return Err(Error::InvalidOperation); + } + if buffer.len() % self.block_size() != 0 { + return Err(Error::InvalidOperation); + } let lba = position / self.block_size() as u64; - debug_assert_eq!(buffer.len() % self.block_size(), 0); let lba_count = buffer.len() / self.block_size(); - - let mut dma_buffer = DmaBuffer::new_uninit_slice(&*self.controller.dma, buffer.len())?; + if lba + lba_count as u64 > self.block_count() { + return Err(Error::InvalidOperation); + } let result = self .controller @@ -97,28 +110,29 @@ impl BlockDevice for NvmeNamespace { self.nsid, lba, lba_count, - dma_buffer.bus_address(), + buffer.bus_address(), buffer.len(), IoDirection::Read, ) .await; - log::info!(target: "io", "read #{lba}, {lba_count} blocks -> {result:?} @ {dma_buffer:p}"); - - if result.is_ok() { - buffer.copy_from_slice(&dma_buffer[..]); - } + log::info!("read #{lba}, {lba_count} blocks -> {result:?} @ {buffer:p}"); result.map_err(NvmeError::into) } - async fn write_aligned(&self, position: u64, buffer: &PageSlice) -> Result<(), Error> { - debug_assert_eq!(position % self.block_size() as u64, 0); + async fn write_aligned(&self, position: u64, buffer: DmaSlice<'_, u8>) -> Result<(), Error> { + if position % self.block_size() as u64 != 0 { + return Err(Error::InvalidOperation); + } + if buffer.len() % self.block_size() != 0 { + return Err(Error::InvalidOperation); + } let lba = position / self.block_size() as u64; - debug_assert_eq!(buffer.len() % self.block_size(), 0); - // let buffer_address = unsafe { buffer.as_physical_address() }; - // debug_assert_eq!(buffer_address.into_u64() % self.block_size() as u64, 0); let lba_count = buffer.len() / self.block_size(); + if lba + lba_count as u64 > self.block_count() { + return Err(Error::InvalidOperation); + } // TODO ArchitectureImpl::flush_data_cache() #[cfg(target_arch = "x86_64")] @@ -126,20 +140,19 @@ impl BlockDevice for NvmeNamespace { core::arch::asm!("wbinvd"); } - let dma_buffer = DmaBuffer::from_slice(&*self.controller.dma, &buffer[..])?; let result = self .controller .perform_io( self.nsid, lba, lba_count, - dma_buffer.bus_address(), + buffer.bus_address(), buffer.len(), IoDirection::Write, ) .await; - log::info!(target: "io", "write -> #{lba}, {lba_count} blocks -> {result:?} @ {dma_buffer:p}"); + log::info!(target: "io", "write -> #{lba}, {lba_count} blocks -> {result:?} @ {buffer:p}"); result.map_err(NvmeError::into) } diff --git a/kernel/driver/block/scsi/src/lib.rs b/kernel/driver/block/scsi/src/lib.rs index 68bb97a8..d6477de6 100644 --- a/kernel/driver/block/scsi/src/lib.rs +++ b/kernel/driver/block/scsi/src/lib.rs @@ -12,11 +12,12 @@ use command::{ScsiReadCapacity, ScsiRequestSense, ScsiTestUnitReady}; use device_api::device::Device; use libk::{ device::{block::BlockDevice, manager::probe_partitions}, + dma::{DmaBuffer, DmaSlice, DmaSliceMut}, error::Error, fs::devfs, task::runtime, }; -use libk_mm::{address::PhysicalAddress, table::MapAttributes, PageProvider, PageSlice}; +use libk_mm::{address::PhysicalAddress, table::MapAttributes, PageProvider}; use libk_util::{ sync::{spin_rwlock::IrqSafeRwLock, IrqSafeSpinlock}, OneTimeInit, @@ -105,49 +106,58 @@ impl ScsiDevice { #[async_trait] impl BlockDevice for ScsiDevice { - // TODO avoid copies by reading directly into the cache? + fn allocate_buffer(&self, size: usize) -> Result]>, Error> { + self.transport.lock().allocate_buffer(size) + } + async fn read_aligned( &self, position: u64, - buffer: &mut PageSlice>, + buffer: DmaSliceMut<'_, MaybeUninit>, ) -> Result<(), Error> { - if buffer.len() % self.lba_size != 0 { - log::warn!("scsi: buffer is not multiple of LBA size"); + if position % self.lba_size as u64 != 0 { + log::warn!("scsi: misaligned read"); + return Err(Error::InvalidArgument); + } + if buffer.len() % self.lba_size != 0 { + log::warn!("scsi: misaligned buffer size"); return Err(Error::InvalidArgument); } - let lba_start = position / self.lba_size as u64; let lba_count = buffer.len() / self.lba_size; - let lba_end = lba_start + lba_count as u64; if lba_start.saturating_add(lba_count as u64) >= self.lba_count { log::warn!("scsi: read beyond medium end"); return Err(Error::InvalidArgument); } + let lba_end = lba_start + lba_count as u64; + let mut transport = self.transport.lock(); - let mut offset = 0; + // TODO DmaSliceMut subslicing + let (buffer, range) = buffer.into_parts(); + let mut offset = range.start; + for i in (0..lba_count).step_by(self.max_lba_per_request) { let lba = lba_start + i as u64; let end = (lba + self.max_lba_per_request as u64).min(lba_end); let count = (end - lba) as usize; let amount = count * self.lba_size; - let slice = - unsafe { MaybeUninit::slice_assume_init_mut(&mut buffer[offset..offset + amount]) }; - let len = transport.read(0, lba, count as _, slice).await?; + let dst_slice = buffer.slice_mut(offset..offset + amount); + let len = transport.read(0, lba, count as u16, dst_slice).await?; if len != amount { return Err(Error::InvalidArgument); } + offset += amount; } Ok(()) } - async fn write_aligned(&self, _position: u64, _buffer: &PageSlice) -> Result<(), Error> { - // TODO AtaWriteDmaEx + async fn write_aligned(&self, _position: u64, _buffer: DmaSlice<'_, u8>) -> Result<(), Error> { Err(Error::NotImplemented) } diff --git a/kernel/driver/block/scsi/src/transport.rs b/kernel/driver/block/scsi/src/transport.rs index 52655643..ee8bca04 100644 --- a/kernel/driver/block/scsi/src/transport.rs +++ b/kernel/driver/block/scsi/src/transport.rs @@ -1,17 +1,24 @@ +use core::{mem::MaybeUninit, ops::Deref}; + use alloc::boxed::Box; use async_trait::async_trait; -use libk::error::Error; +use libk::{ + dma::{DmaBuffer, DmaSliceMut}, + error::Error, +}; use crate::command::ScsiCommand; #[async_trait] pub trait ScsiTransport: Send + Sync { + fn allocate_buffer(&self, size: usize) -> Result]>, Error>; + /// Perform a no-data request async fn perform_request_raw( &mut self, lun: u8, request_data: &[u8], - response_buffer: &mut [u8], + response_buffer: DmaSliceMut<'_, MaybeUninit>, ) -> Result; fn max_bytes_per_request(&self) -> usize; @@ -33,7 +40,7 @@ impl ScsiTransportWrapper { lun: u8, lba: u64, lba_count: u16, - buffer: &mut [u8], + buffer: DmaSliceMut<'_, MaybeUninit>, ) -> Result { if lba >= u32::MAX as u64 { return Err(Error::InvalidArgument); @@ -68,18 +75,28 @@ impl ScsiTransportWrapper { [u8; R::RESPONSE_LEN]: Sized, [u8; R::REQUEST_LEN]: Sized, { - let mut response_buffer = [0; R::RESPONSE_LEN]; + let mut response_buffer = self.allocate_buffer(R::RESPONSE_LEN)?; let request_buffer = request.into_bytes(); let response_len = self .inner - .perform_request_raw(lun, &request_buffer, &mut response_buffer) + .perform_request_raw( + lun, + &request_buffer, + response_buffer.slice_mut(0..R::RESPONSE_LEN), + ) .await?; + let response_bytes = + unsafe { MaybeUninit::slice_assume_init_ref(&response_buffer[..response_len]) }; - R::parse_response(&response_buffer[..response_len]) - } - - pub fn max_bytes_per_request(&self) -> usize { - self.inner.max_bytes_per_request() + R::parse_response(response_bytes) + } +} + +impl Deref for ScsiTransportWrapper { + type Target = dyn ScsiTransport; + + fn deref(&self) -> &Self::Target { + self.inner.as_ref() } } diff --git a/kernel/driver/bus/usb/src/class_driver/mass_storage.rs b/kernel/driver/bus/usb/src/class_driver/mass_storage.rs index 3596d186..32538bca 100644 --- a/kernel/driver/bus/usb/src/class_driver/mass_storage.rs +++ b/kernel/driver/bus/usb/src/class_driver/mass_storage.rs @@ -3,7 +3,10 @@ use core::mem::MaybeUninit; use alloc::{boxed::Box, sync::Arc}; use async_trait::async_trait; use bytemuck::{Pod, Zeroable}; -use libk::{dma::DmaBuffer, error::Error}; +use libk::{ + dma::{DmaBuffer, DmaSliceMut}, + error::Error, +}; use ygg_driver_scsi::{transport::ScsiTransport, ScsiDevice}; use crate::{ @@ -50,7 +53,6 @@ struct Bbb { device: Arc, in_pipe: UsbBulkInPipeAccess, out_pipe: UsbBulkOutPipeAccess, - buffer: DmaBuffer<[MaybeUninit]>, last_tag: u32, } @@ -62,12 +64,10 @@ impl Bbb { in_pipe: UsbBulkInPipeAccess, out_pipe: UsbBulkOutPipeAccess, ) -> Result { - let buffer = in_pipe.allocate_dma_buffer(32768)?; Ok(Self { device, in_pipe, out_pipe, - buffer, last_tag: 0, }) } @@ -128,34 +128,37 @@ impl Bbb { Ok(()) } - async fn read_response_data(&mut self, buffer: &mut [u8]) -> Result { - if buffer.is_empty() { + async fn read_response_data( + &mut self, + buffer: DmaSliceMut<'_, MaybeUninit>, + ) -> Result { + if buffer.len() == 0 { return Ok(0); } let len = self .in_pipe - .read_dma(&mut self.buffer, buffer.len()) + .read_dma(buffer) .await .inspect_err(|error| log::error!("msc: DMA read error: {error:?}"))?; - let dma_slice = unsafe { MaybeUninit::slice_assume_init_ref(&self.buffer[..len]) }; - buffer[..len].copy_from_slice(dma_slice); - Ok(len) } } #[async_trait] impl ScsiTransport for Bbb { + fn allocate_buffer(&self, size: usize) -> Result]>, Error> { + Ok(self.in_pipe.allocate_dma_buffer(size)?) + } + // TODO DMA support for SCSI async fn perform_request_raw( &mut self, lun: u8, request_data: &[u8], - response_buffer: &mut [u8], + response_buffer: DmaSliceMut<'_, MaybeUninit>, ) -> Result { - if request_data.len() > 16 || response_buffer.len() > self.buffer.len() { - todo!() - // return Err(Error::InvalidArgument); + if request_data.len() > 16 || response_buffer.len() > self.max_bytes_per_request() { + return Err(Error::InvalidArgument); } let tag = self @@ -167,7 +170,7 @@ impl ScsiTransport for Bbb { } fn max_bytes_per_request(&self) -> usize { - self.buffer.len() + 32768 } } diff --git a/kernel/driver/bus/usb/src/pipe/normal.rs b/kernel/driver/bus/usb/src/pipe/normal.rs index b5496d7e..59649afd 100644 --- a/kernel/driver/bus/usb/src/pipe/normal.rs +++ b/kernel/driver/bus/usb/src/pipe/normal.rs @@ -2,7 +2,7 @@ use core::{mem::MaybeUninit, ops::Deref}; use alloc::boxed::Box; use async_trait::async_trait; -use libk::dma::DmaBuffer; +use libk::dma::{DmaBuffer, DmaSlice, DmaSliceMut}; use crate::error::{TransferError, UsbError}; @@ -10,15 +10,11 @@ use super::UsbGenericPipe; #[async_trait] pub trait UsbNormalPipeIn: UsbGenericPipe { - async fn read_dma( - &self, - buffer: &mut DmaBuffer<[MaybeUninit]>, - limit: usize, - ) -> Result; + async fn read_dma(&self, buffer: DmaSliceMut<'_, MaybeUninit>) -> Result; async fn read(&self, buffer: &mut [u8]) -> Result { let mut dma_buffer = self.allocate_dma_buffer(buffer.len())?; - let len = self.read_dma(&mut dma_buffer, buffer.len()).await?; + let len = self.read_dma(dma_buffer.slice_mut(0..buffer.len())).await?; let dma_slice = unsafe { MaybeUninit::slice_assume_init_ref(&dma_buffer[..len]) }; buffer[..len].copy_from_slice(dma_slice); Ok(len) @@ -35,14 +31,14 @@ pub trait UsbNormalPipeIn: UsbGenericPipe { #[async_trait] pub trait UsbNormalPipeOut: UsbGenericPipe { - async fn write_dma(&self, buffer: &DmaBuffer<[u8]>) -> Result; + async fn write_dma(&self, buffer: DmaSlice<'_, u8>) -> Result; async fn write(&self, buffer: &[u8]) -> Result { let mut dma_buffer = self.allocate_dma_buffer(buffer.len())?; MaybeUninit::copy_from_slice(&mut dma_buffer, buffer); let dma_buffer = unsafe { DmaBuffer::assume_init_slice(dma_buffer) }; - self.write_dma(&dma_buffer).await + self.write_dma(dma_buffer.slice(0..buffer.len())).await } } diff --git a/kernel/driver/usb/xhci/src/pipe.rs b/kernel/driver/usb/xhci/src/pipe.rs index b91ab053..45008a25 100644 --- a/kernel/driver/usb/xhci/src/pipe.rs +++ b/kernel/driver/usb/xhci/src/pipe.rs @@ -2,7 +2,7 @@ use core::mem::MaybeUninit; use alloc::{boxed::Box, sync::Arc}; use async_trait::async_trait; -use libk::dma::DmaBuffer; +use libk::dma::{DmaBuffer, DmaSlice, DmaSliceMut}; use ygg_driver_usb::{ error::{TransferError, UsbError}, pipe::{ @@ -164,17 +164,12 @@ impl UsbGenericPipe for NormalInPipe { #[async_trait] impl UsbNormalPipeIn for NormalInPipe { - async fn read_dma( - &self, - buffer: &mut DmaBuffer<[MaybeUninit]>, - limit: usize, - ) -> Result { - let len = limit.min(buffer.len()); + async fn read_dma(&self, buffer: DmaSliceMut<'_, MaybeUninit>) -> Result { let result = self .ring - .normal_transfer(self.xhci.as_ref(), buffer.bus_address(), len) + .normal_transfer(self.xhci.as_ref(), buffer.bus_address(), buffer.len()) .await; - allow_short_packet(len, result) + allow_short_packet(buffer.len(), result) } } @@ -186,7 +181,7 @@ impl UsbGenericPipe for NormalOutPipe { #[async_trait] impl UsbNormalPipeOut for NormalOutPipe { - async fn write_dma(&self, buffer: &DmaBuffer<[u8]>) -> Result { + async fn write_dma(&self, buffer: DmaSlice<'_, u8>) -> Result { self.ring .normal_transfer(self.xhci.as_ref(), buffer.bus_address(), buffer.len()) .await diff --git a/kernel/libk/src/device/block/cache.rs b/kernel/libk/src/device/block/cache.rs index 0191776d..4ff75464 100644 --- a/kernel/libk/src/device/block/cache.rs +++ b/kernel/libk/src/device/block/cache.rs @@ -1,48 +1,37 @@ #![allow(clippy::missing_transmute_annotations)] use core::{ - marker::PhantomData, + mem::MaybeUninit, ops::{Deref, DerefMut}, }; use alloc::sync::Arc; -use kernel_arch::mem::PhysicalMemoryAllocator; -use libk_mm::{address::PhysicalAddress, phys::GlobalPhysicalAllocator, PageBox}; use libk_util::{lru_hash_table::LruCache, sync::spin_rwlock::IrqSafeRwLock}; use yggdrasil_abi::error::Error; -use crate::task::sync::AsyncMutex; +use crate::{dma::DmaBuffer, task::sync::AsyncMutex}; use super::BlockDevice; -pub struct CachedSegment< - A: PhysicalMemoryAllocator
= GlobalPhysicalAllocator, -> { - data: PageBox<[u8], A>, +pub struct CachedSegment { + data: DmaBuffer<[u8]>, dirty: bool, } -pub struct UncachedCache< - A: PhysicalMemoryAllocator
= GlobalPhysicalAllocator, -> { +pub struct UncachedCache { device: Arc, block_size: usize, - _pd: PhantomData, } -pub enum DeviceMapper< - A: PhysicalMemoryAllocator
= GlobalPhysicalAllocator, -> { - Uncached(UncachedCache), - Cached(BlockCache), +pub enum DeviceMapper { + Uncached(UncachedCache), + Cached(BlockCache), } -pub struct BlockCache< - A: PhysicalMemoryAllocator
= GlobalPhysicalAllocator, -> { +pub struct BlockCache { device: Arc, block_size: usize, segment_size: usize, - cache: AsyncMutex>>>>, + cache: AsyncMutex>>>, } impl DeviceMapper { @@ -54,7 +43,7 @@ impl DeviceMapper { bucket_count: usize, filesystem: &str, ) -> Result { - DeviceMapper::cached_with_capacity_in( + BlockCache::with_capacity( device, block_size, segment_size, @@ -62,6 +51,7 @@ impl DeviceMapper { bucket_count, filesystem, ) + .map(DeviceMapper::Cached) } pub fn uncached( @@ -69,47 +59,14 @@ impl DeviceMapper { block_size: usize, filesystem: &str, ) -> Result { - DeviceMapper::uncached_in(device, block_size, filesystem) - } -} - -impl> DeviceMapper { - pub fn cached_with_capacity_in( - device: Arc, - block_size: usize, - segment_size: usize, - bucket_capacity: usize, - bucket_count: usize, - filesystem: &str, - ) -> Result, Error> { - BlockCache::::with_capacity_in( - device, - block_size, - segment_size, - bucket_capacity, - bucket_count, - filesystem, - ) - .map(DeviceMapper::::Cached) - } - - pub fn uncached_in( - device: Arc, - block_size: usize, - filesystem: &str, - ) -> Result, Error> { if block_size % device.block_size() != 0 { log::error!( "Couldn't create block mapper for {filesystem}: \ - cache block size is not a multiple of device block size" + cache block size is not a multiple of device block size" ); return Err(Error::InvalidArgument); } - let uncache = UncachedCache:: { - device, - block_size, - _pd: PhantomData, - }; + let uncache = UncachedCache { device, block_size }; Ok(Self::Uncached(uncache)) } @@ -154,7 +111,7 @@ impl> DeviceMapper { } } -impl> UncachedCache { +impl UncachedCache { pub fn device(&self) -> &Arc { &self.device } @@ -171,9 +128,11 @@ impl> UncachedCache { ); return Err(Error::InvalidArgument); } - let mut data = PageBox::<_, A>::new_uninit_slice_in(self.block_size)?; - self.device.read_aligned(pos, data.as_slice_mut()).await?; - let result = mapper(unsafe { data.assume_init_slice_ref() })?; + let mut buffer = self.device.allocate_buffer(self.block_size)?; + self.device + .read_aligned(pos, buffer.slice_mut(0..self.block_size)) + .await?; + let result = mapper(unsafe { MaybeUninit::slice_assume_init_ref(&buffer[..]) })?; Ok(result) } @@ -190,27 +149,31 @@ impl> UncachedCache { ); return Err(Error::InvalidArgument); } - let mut data = PageBox::<_, A>::new_uninit_slice_in(self.block_size)?; + let mut buffer = self.device.allocate_buffer(self.block_size)?; // No need to read a block only to then fully rewrite it if size != self.block_size { - self.device.read_aligned(pos, data.as_slice_mut()).await?; + self.device + .read_aligned(pos, buffer.slice_mut(0..self.block_size)) + .await?; } - let mut data = unsafe { data.assume_init_slice() }; - let result = mapper(&mut data[..])?; - self.device.write_aligned(pos, data.as_slice()).await?; + let mut buffer = unsafe { DmaBuffer::assume_init_slice(buffer) }; + let result = mapper(&mut buffer[..])?; + self.device + .write_aligned(pos, buffer.slice(0..self.block_size)) + .await?; Ok(result) } } -impl> BlockCache { - pub fn with_capacity_in( +impl BlockCache { + pub fn with_capacity( device: Arc, block_size: usize, segment_size: usize, bucket_capacity: usize, bucket_count: usize, filesystem: &str, - ) -> Result, Error> { + ) -> Result { if block_size % device.block_size() != 0 { log::error!( "Couldn't create block cache for {filesystem}: \ @@ -251,17 +214,13 @@ impl> BlockCache { &self.device } - async fn evict_block( - &self, - segment_position: u64, - block: Arc>>, - ) { + async fn evict_block(&self, segment_position: u64, block: Arc>) { let read = block.read(); if read.dirty { assert_eq!(segment_position % self.segment_size as u64, 0); if let Err(err) = self .device - .write_aligned(segment_position, read.data.as_slice()) + .write_aligned(segment_position, read.data.slice(0..self.segment_size)) .await { log::error!("Disk error: flushing block {}: {:?}", segment_position, err); @@ -272,12 +231,12 @@ impl> BlockCache { async fn fetch_block( &self, segment_position: u64, - ) -> Result>>, Error> { - let mut data = PageBox::new_uninit_slice_in(self.segment_size)?; + ) -> Result>, Error> { + let mut buffer = self.device.allocate_buffer(self.segment_size)?; self.device - .read_aligned(segment_position, data.as_slice_mut()) + .read_aligned(segment_position, buffer.slice_mut(0..self.segment_size)) .await?; - let data = unsafe { data.assume_init_slice() }; + let data = unsafe { DmaBuffer::assume_init_slice(buffer) }; Ok(Arc::new(IrqSafeRwLock::new(CachedSegment { data, dirty: false, @@ -287,7 +246,7 @@ impl> BlockCache { async fn entry( &self, segment_position: u64, - ) -> Result>>, Error> { + ) -> Result>, Error> { assert_eq!(segment_position % self.segment_size as u64, 0); let mut lock = self.cache.lock().await; let (value, evicted) = lock @@ -349,354 +308,23 @@ impl> BlockCache { } } -impl> CachedSegment { +impl CachedSegment { pub fn set_dirty(&mut self) { self.dirty = true; } } -impl> Deref for CachedSegment { - type Target = PageBox<[u8], A>; +impl Deref for CachedSegment { + type Target = DmaBuffer<[u8]>; fn deref(&self) -> &Self::Target { &self.data } } -impl> DerefMut for CachedSegment { +impl DerefMut for CachedSegment { fn deref_mut(&mut self) -> &mut Self::Target { self.dirty = true; &mut self.data } } - -// #[cfg(test)] -// mod tests { -// use core::{ -// ffi::c_void, -// mem::MaybeUninit, -// ptr::null_mut, -// sync::atomic::{AtomicBool, Ordering}, -// }; -// use std::{io, sync::Mutex}; -// -// use async_trait::async_trait; -// use kernel_arch::mem::PhysicalMemoryAllocator; -// use libk_mm::{address::PhysicalAddress, PageBox, PageSlice}; -// use yggdrasil_abi::error::Error; -// -// use crate::vfs::block::{BlockDevice, NgBlockDevice, NgBlockDeviceWrapper}; -// -// use super::BlockCache; -// -// struct DummyBlock { -// block_size: usize, -// block_count: usize, -// deny_writes: AtomicBool, -// data: Mutex>, -// } -// -// struct PA; -// -// impl DummyBlock { -// pub fn new(block_size: usize, block_count: usize) -> Self { -// let mut data = vec![0; block_size * block_count]; -// for i in 0..block_count { -// let block = &mut data[block_size * i..block_size * (i + 1)]; -// block.fill(i as u8); -// } -// Self { -// data: Mutex::new(data), -// deny_writes: AtomicBool::new(false), -// block_size, -// block_count, -// } -// } -// } -// -// #[async_trait::async_trait] -// impl NgBlockDevice for DummyBlock { -// type Error = Error; -// -// async fn read( -// &self, -// lba: u64, -// buffer: &mut PageSlice>, -// ) -> Result<(), Error> { -// let start = lba as usize * self.block_size; -// let end = start + buffer.len(); -// -// if end > self.block_count * self.block_size { -// return Err(Error::InvalidArgument); -// } -// -// let data = self.data.lock().unwrap(); -// let buffer = unsafe { MaybeUninit::slice_assume_init_mut(&mut buffer[..]) }; -// buffer.copy_from_slice(&data[start..end]); -// -// Ok(()) -// } -// -// async fn write(&self, lba: u64, buffer: &PageSlice) -> Result<(), Error> { -// if self.deny_writes.load(Ordering::Acquire) { -// panic!("write() with deny_writes = true"); -// } -// -// let start = lba as usize * self.block_size; -// let end = start + buffer.len(); -// -// if end > self.block_count * self.block_size { -// return Err(Error::InvalidArgument); -// } -// -// let mut data = self.data.lock().unwrap(); -// data[start..end].copy_from_slice(&buffer[..]); -// -// Ok(()) -// } -// -// fn block_size(&self) -> usize { -// self.block_size -// } -// -// fn block_count(&self) -> usize { -// self.block_count -// } -// } -// -// impl PhysicalMemoryAllocator for PA { -// type Address = PhysicalAddress; -// -// unsafe fn free_page(page: Self::Address) { -// let base = page.try_into_usize().unwrap(); -// let base = core::ptr::with_exposed_provenance_mut::(base); -// if unsafe { libc::munmap(base, 0x1000) } != 0 { -// let err = io::Error::last_os_error(); -// panic!("free_page: munmap returned {err}"); -// } -// } -// -// fn allocate_page() -> Result { -// Self::allocate_contiguous_pages(1) -// } -// -// fn allocate_contiguous_pages(count: usize) -> Result { -// let base = unsafe { -// libc::mmap( -// null_mut(), -// count * 0x1000, -// libc::PROT_READ | libc::PROT_WRITE, -// libc::MAP_ANON | libc::MAP_PRIVATE, -// -1, -// 0, -// ) -// }; -// if base != libc::MAP_FAILED { -// let base = base.addr(); -// Ok(PhysicalAddress::from_usize(base)) -// } else { -// Err(Error::OutOfMemory) -// } -// } -// } -// -// const BS: usize = 1024; -// -// // The test must not crash with denied writes -// #[tokio::test] -// async fn test_no_modification() { -// let device = Box::leak(Box::new(DummyBlock::new(BS, 1024))); -// let wrapper = NgBlockDeviceWrapper::new(device); -// let cache = BlockCache::::with_capacity_in(wrapper, BS, BS, 64, 8); -// -// device.deny_writes.store(true, Ordering::Release); -// cache -// .try_with(1 * BS as u64, |block| { -// assert!(block.iter().all(|x| *x == 1)); -// Ok(()) -// }) -// .await -// .unwrap(); -// cache -// .try_with(2 * BS as u64, |block| { -// assert!(block.iter().all(|x| *x == 2)); -// Ok(()) -// }) -// .await -// .unwrap(); -// -// cache.flush().await; -// } -// -// #[tokio::test] -// async fn test_partial_modification() { -// let device = Box::leak(Box::new(DummyBlock::new(BS, 1024))); -// let wrapper = NgBlockDeviceWrapper::new(device); -// // 8 * 8 -// let cache = BlockCache::::with_capacity_in(wrapper, BS, BS, 8, 8); -// -// const LBA: u64 = 1; -// cache -// .try_with_mut(LBA * BS as u64, 16, |block| { -// block[0..16].fill(0x12); -// Ok(()) -// }) -// .await -// .unwrap(); -// cache.flush().await; -// -// { -// let mut buffer = PageBox::<_, PA>::new_uninit_slice_in(BS).unwrap(); -// device.read(LBA, buffer.as_slice_mut()).await.unwrap(); -// let buffer = unsafe { buffer.assume_init_slice() }; -// buffer[0..16].iter().for_each(|&x| { -// assert_eq!(x, 0x12); -// }); -// buffer[16..].iter().for_each(|&x| { -// assert_eq!(x, LBA as u8); -// }); -// } -// -// cache -// .try_with_mut(LBA * BS as u64, 16, |block| { -// block[16..32].fill(0x23); -// Ok(()) -// }) -// .await -// .unwrap(); -// cache -// .try_with_mut(LBA * BS as u64, 16, |block| { -// block[48..64].fill(0x34); -// Ok(()) -// }) -// .await -// .unwrap(); -// cache -// .try_with_mut(LBA * BS as u64, 128, |block| { -// block[128..256].fill(0xF1); -// Ok(()) -// }) -// .await -// .unwrap(); -// cache.flush().await; -// -// { -// let mut buffer = PageBox::<_, PA>::new_uninit_slice_in(BS).unwrap(); -// device.read(LBA, buffer.as_slice_mut()).await.unwrap(); -// let buffer = unsafe { buffer.assume_init_slice() }; -// buffer[0..16].iter().for_each(|&x| { -// assert_eq!(x, 0x12); -// }); -// buffer[16..32].iter().for_each(|&x| { -// assert_eq!(x, 0x23); -// }); -// buffer[48..64].iter().for_each(|&x| { -// assert_eq!(x, 0x34); -// }); -// buffer[128..256].iter().for_each(|&x| { -// assert_eq!(x, 0xF1); -// }); -// buffer[32..48].iter().for_each(|&x| { -// assert_eq!(x, LBA as u8); -// }); -// buffer[64..128].iter().for_each(|&x| { -// assert_eq!(x, LBA as u8); -// }); -// buffer[256..].iter().for_each(|&x| { -// assert_eq!(x, LBA as u8); -// }); -// } -// } -// -// #[tokio::test] -// async fn test_implicit_eviction() { -// let device = Box::leak(Box::new(DummyBlock::new(BS, 1024))); -// let wrapper = NgBlockDeviceWrapper::new(device); -// // 8 * 8 -// let cache = BlockCache::::with_capacity_in(wrapper, BS, BS, 8, 8); -// -// fn mapper(x: u64) -> u8 { -// (x + 3) as u8 -// } -// -// // Go through all blocks, fill those with some values -// for i in 0..1024 { -// cache -// .try_with_mut(i * BS as u64, BS, |block| { -// block.fill(mapper(i)); -// Ok(()) -// }) -// .await -// .unwrap(); -// } -// cache.flush().await; -// -// for i in 0..1024 { -// let mut buffer = PageBox::<_, PA>::new_uninit_slice_in(BS).unwrap(); -// device.read(i, buffer.as_slice_mut()).await.unwrap(); -// let buffer = unsafe { buffer.assume_init_slice() }; -// assert!(buffer.iter().all(|x| *x == mapper(i))); -// } -// -// for i in 0..1023 { -// cache -// .try_with_mut(i * BS as u64, BS, |block| { -// block.fill(0x12); -// Ok(()) -// }) -// .await -// .unwrap(); -// cache -// .try_with_mut((i + 1) * BS as u64, BS, |block| { -// block.fill(0x23); -// Ok(()) -// }) -// .await -// .unwrap(); -// } -// -// for i in 0..1023 { -// cache -// .try_with_mut(i * BS as u64, BS, |block| { -// block.iter_mut().for_each(|x| *x += 1); -// Ok(()) -// }) -// .await -// .unwrap(); -// cache -// .try_with_mut((i + 1) * BS as u64, BS, |block| { -// block.iter_mut().for_each(|x| *x += 2); -// Ok(()) -// }) -// .await -// .unwrap(); -// } -// -// cache.flush().await; -// -// { -// let mut buffer = PageBox::<_, PA>::new_uninit_slice_in(BS).unwrap(); -// device.read(0, buffer.as_slice_mut()).await.unwrap(); -// let buffer = unsafe { buffer.assume_init_slice() }; -// buffer.iter().for_each(|&x| { -// assert_eq!(x, 0x13, "block 0 mismatch"); -// }); -// } -// for i in 1..1023 { -// let mut buffer = PageBox::<_, PA>::new_uninit_slice_in(BS).unwrap(); -// device.read(i, buffer.as_slice_mut()).await.unwrap(); -// let buffer = unsafe { buffer.assume_init_slice() }; -// buffer.iter().for_each(|&x| { -// assert_eq!(x, 0x15, "block {i} mismatch"); -// }); -// } -// { -// let mut buffer = PageBox::<_, PA>::new_uninit_slice_in(BS).unwrap(); -// device.read(1023, buffer.as_slice_mut()).await.unwrap(); -// let buffer = unsafe { buffer.assume_init_slice() }; -// buffer.iter().for_each(|&x| { -// assert_eq!(x, 0x25, "block 1023 mismatch"); -// }); -// } -// } -// } diff --git a/kernel/libk/src/device/block/mod.rs b/kernel/libk/src/device/block/mod.rs index 408e858c..9ed3fa38 100644 --- a/kernel/libk/src/device/block/mod.rs +++ b/kernel/libk/src/device/block/mod.rs @@ -3,10 +3,13 @@ use core::{any::Any, mem::MaybeUninit, ops::Deref}; use alloc::{boxed::Box, sync::Arc}; use async_trait::async_trait; use device_api::device::Device; -use libk_mm::{PageBox, PageProvider, PageSlice}; +use libk_mm::PageProvider; use yggdrasil_abi::error::Error; -use crate::vfs::{CommonImpl, NodeRef}; +use crate::{ + dma::{DmaBuffer, DmaSlice, DmaSliceMut}, + vfs::{CommonImpl, NodeRef}, +}; pub mod cache; pub mod partition; @@ -90,15 +93,17 @@ impl Iterator for Chunked { #[async_trait] pub trait BlockDevice: Device + PageProvider { + fn allocate_buffer(&self, size: usize) -> Result]>, Error>; + async fn read_aligned( &self, position: u64, - buffer: &mut PageSlice>, + buffer: DmaSliceMut<'_, MaybeUninit>, ) -> Result<(), Error> { let _ = (position, buffer); Err(Error::NotImplemented) } - async fn write_aligned(&self, position: u64, buffer: &PageSlice) -> Result<(), Error> { + async fn write_aligned(&self, position: u64, buffer: DmaSlice<'_, u8>) -> Result<(), Error> { let _ = (position, buffer); Err(Error::NotImplemented) } @@ -108,13 +113,13 @@ pub trait BlockDevice: Device + PageProvider { let Some((iter, max_lba_count)) = Chunked::begin(self, position, buffer.len()) else { return Ok(0); }; - let mut read_buffer = PageBox::new_uninit_slice(max_lba_count * bs)?; + let mut read_buffer = self.allocate_buffer(max_lba_count * bs)?; + // let mut read_buffer = PageBox::new_uninit_slice(max_lba_count * bs)?; let mut total = 0; for (lba, block_count, block_offset, offset, amount) in iter { - let read_buffer_slice = read_buffer.as_slice_mut().subslice_mut(..block_count * bs); - self.read_aligned(lba * bs as u64, read_buffer_slice) - .await?; + let slice = read_buffer.slice_mut(0..block_count * bs); + self.read_aligned(lba * bs as u64, slice).await?; let src = unsafe { MaybeUninit::slice_assume_init_ref( @@ -143,19 +148,19 @@ pub trait BlockDevice: Device + PageProvider { let amount = core::cmp::min(bs - block_offset, buf.len()); - let mut block = PageBox::new_uninit_slice(bs)?; + let mut dma_buffer = self.allocate_buffer(bs)?; if amount != bs { // Need to read the block first -- it's modified partially - self.read_aligned(lba * bs as u64, block.as_slice_mut()) + self.read_aligned(lba * bs as u64, dma_buffer.slice_mut(0..bs)) .await?; } - let mut block = unsafe { block.assume_init_slice() }; + let mut block = unsafe { DmaBuffer::assume_init_slice(dma_buffer) }; block[block_offset..block_offset + amount].copy_from_slice(&buf[..amount]); // Write the block back - self.write_aligned(lba * bs as u64, block.as_slice()) + self.write_aligned(lba * bs as u64, block.slice(0..bs)) .await?; buf = &buf[amount..]; diff --git a/kernel/libk/src/device/block/partition/gpt.rs b/kernel/libk/src/device/block/partition/gpt.rs index b723adbe..a5e37acd 100644 --- a/kernel/libk/src/device/block/partition/gpt.rs +++ b/kernel/libk/src/device/block/partition/gpt.rs @@ -1,7 +1,6 @@ use alloc::{sync::Arc, vec::Vec}; use bytemuck::{Pod, Zeroable}; use libk_mm::PageBox; -use static_assertions::const_assert_eq; use uuid::Uuid; use yggdrasil_abi::error::Error; @@ -9,7 +8,7 @@ use crate::device::block::BlockDevice; use super::Partition; -#[derive(Clone, Copy)] +#[derive(Clone, Copy, Pod, Zeroable)] #[repr(C)] struct GptHeader { signature: [u8; 8], @@ -26,7 +25,7 @@ struct GptHeader { partition_table_len: u32, partition_table_entry_size: u32, partition_table_crc32: u32, - _1: [u8; 420], + _1: u32, } #[derive(Clone, Copy, Zeroable, Pod)] @@ -39,18 +38,18 @@ struct GptEntry { attrs: u64, } -const_assert_eq!(size_of::(), 512); - -async unsafe fn read_struct_lba(dev: &dyn BlockDevice, lba: u64) -> Result, Error> { - assert_eq!(size_of::(), 512); - let mut data = PageBox::new_uninit()?; - dev.read_aligned(lba * 512, PageBox::as_bytes_mut(&mut data)) - .await?; - Ok(data.assume_init()) +async unsafe fn read_struct_lba<'b, T: Pod + 'b>( + dev: &dyn BlockDevice, + lba: u64, + buffer: &'b mut [u8], +) -> Result<&'b mut T, Error> { + dev.read_exact(lba * 512, buffer).await?; + Ok(bytemuck::from_bytes_mut(buffer)) } pub(crate) async fn probe_gpt(dev: &Arc) -> Result>, Error> { - let header = unsafe { read_struct_lba::(dev.as_ref(), 1) }.await?; + let mut header = [0; size_of::()]; + let header = unsafe { read_struct_lba::(dev.as_ref(), 1, &mut header) }.await?; if &header.signature != b"EFI PART" { // Not a GPT partition table diff --git a/kernel/libk/src/device/block/partition/mod.rs b/kernel/libk/src/device/block/partition/mod.rs index a5c38d85..61fa5518 100644 --- a/kernel/libk/src/device/block/partition/mod.rs +++ b/kernel/libk/src/device/block/partition/mod.rs @@ -3,9 +3,11 @@ use core::mem::MaybeUninit; use alloc::{boxed::Box, sync::Arc}; use async_trait::async_trait; use device_api::device::Device; -use libk_mm::{address::PhysicalAddress, table::MapAttributes, PageProvider, PageSlice}; +use libk_mm::{address::PhysicalAddress, table::MapAttributes, PageProvider}; use yggdrasil_abi::error::Error; +use crate::dma::{DmaBuffer, DmaSlice, DmaSliceMut}; + use super::BlockDevice; pub mod gpt; @@ -56,28 +58,24 @@ impl Device for Partition { #[async_trait] impl BlockDevice for Partition { + fn allocate_buffer(&self, size: usize) -> Result]>, Error> { + self.device.allocate_buffer(size) + } + async fn read_aligned( &self, position: u64, - buffer: &mut PageSlice>, + buffer: DmaSliceMut<'_, MaybeUninit>, ) -> Result<(), Error> { - // TODO check against partition range - debug_assert_eq!(position % self.device.block_size() as u64, 0); - debug_assert_eq!(buffer.len() % self.device.block_size(), 0); - - self.device - .read_aligned(self.lba_start * self.block_size() as u64 + position, buffer) - .await + // TODO check against partition bounds + let lba = self.lba_start * self.block_size() as u64 + position; + self.device.read_aligned(lba, buffer).await } - async fn write_aligned(&self, position: u64, buffer: &PageSlice) -> Result<(), Error> { - // TODO check against partition range - debug_assert_eq!(position % self.device.block_size() as u64, 0); - debug_assert_eq!(buffer.len() % self.device.block_size(), 0); - - self.device - .write_aligned(self.lba_start * self.block_size() as u64 + position, buffer) - .await + async fn write_aligned(&self, position: u64, buffer: DmaSlice<'_, u8>) -> Result<(), Error> { + // TODO check against partition bounds + let lba = self.lba_start * self.block_size() as u64 + position; + self.device.write_aligned(lba, buffer).await } fn block_size(&self) -> usize { diff --git a/kernel/libk/src/device/display/mod.rs b/kernel/libk/src/device/display/mod.rs index 1ee4616f..46a38a62 100644 --- a/kernel/libk/src/device/display/mod.rs +++ b/kernel/libk/src/device/display/mod.rs @@ -20,7 +20,7 @@ pub mod font; pub use color::Color; -use crate::task::thread::Thread; +use crate::{dma::DmaBuffer, task::thread::Thread}; use super::block::BlockDevice; @@ -151,6 +151,10 @@ impl DisplayWrapper { #[async_trait] impl BlockDevice for DisplayWrapper { + fn allocate_buffer(&self, _size: usize) -> Result]>, Error> { + Err(Error::NotImplemented) + } + async fn read(&self, _pos: u64, _buf: &mut [u8]) -> Result { Err(Error::InvalidOperation) } diff --git a/kernel/libk/src/dma.rs b/kernel/libk/src/dma.rs index 4614230d..e599e46e 100644 --- a/kernel/libk/src/dma.rs +++ b/kernel/libk/src/dma.rs @@ -2,7 +2,7 @@ use core::{ alloc::Layout, fmt, mem::{self, MaybeUninit}, - ops::{Deref, DerefMut, Sub}, + ops::{Deref, DerefMut, Range, Sub}, ptr::{self, NonNull}, }; @@ -44,6 +44,16 @@ pub struct DmaBuffer { page_count: usize, } +pub struct DmaSlice<'a, T> { + buffer: &'a DmaBuffer<[T]>, + range: Range, +} + +pub struct DmaSliceMut<'a, T> { + buffer: &'a mut DmaBuffer<[T]>, + range: Range, +} + #[derive(Clone, Copy, PartialEq, Eq, Debug, PartialOrd, Ord, Pod, Zeroable)] #[repr(transparent)] pub struct BusAddress(u64); @@ -179,6 +189,32 @@ impl DmaBuffer { } } +impl DmaBuffer<[T]> { + fn slice_range_check(&self, range: &Range) { + assert!( + range.end <= self.len() && range.start <= self.len(), + "DMA buffer slice range out of bounds" + ); + assert!(range.start <= range.end, "Invalid DMA slice range"); + } + + pub fn slice(&self, range: Range) -> DmaSlice { + self.slice_range_check(&range); + DmaSlice { + buffer: self, + range, + } + } + + pub fn slice_mut(&mut self, range: Range) -> DmaSliceMut { + self.slice_range_check(&range); + DmaSliceMut { + buffer: self, + range, + } + } +} + impl DmaBuffer { #[inline] pub fn page_count(&self) -> usize { @@ -262,3 +298,59 @@ impl fmt::LowerHex for BusAddress { fmt::LowerHex::fmt(&self.0, f) } } + +impl<'a, T> DmaSlice<'a, T> { + pub fn bus_address(&self) -> BusAddress { + self.buffer.bus_address().add(self.range.start) + } + + // TODO subslicing + pub fn into_parts(self) -> (&'a DmaBuffer<[T]>, Range) { + (self.buffer, self.range) + } +} + +impl Deref for DmaSlice<'_, T> { + type Target = [T]; + + fn deref(&self) -> &Self::Target { + &self.buffer[self.range.clone()] + } +} + +impl fmt::Pointer for DmaSlice<'_, T> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{:p}[{:?}]", *self.buffer, self.range) + } +} + +impl<'a, T> DmaSliceMut<'a, T> { + pub fn bus_address(&self) -> BusAddress { + self.buffer.bus_address().add(self.range.start) + } + + // TODO subslicing + pub fn into_parts(self) -> (&'a mut DmaBuffer<[T]>, Range) { + (self.buffer, self.range) + } +} + +impl Deref for DmaSliceMut<'_, T> { + type Target = [T]; + + fn deref(&self) -> &Self::Target { + &self.buffer[self.range.clone()] + } +} + +impl DerefMut for DmaSliceMut<'_, T> { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.buffer[self.range.clone()] + } +} + +impl fmt::Pointer for DmaSliceMut<'_, T> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{:p}[{:?}]", *self.buffer, self.range) + } +}