diff --git a/kernel/comps/block/src/bio.rs b/kernel/comps/block/src/bio.rs index be12fb923..1af73425e 100644 --- a/kernel/comps/block/src/bio.rs +++ b/kernel/comps/block/src/bio.rs @@ -5,8 +5,9 @@ use bitvec::array::BitArray; use int_to_c_enum::TryFromInt; use ostd::{ mm::{ - DmaDirection, DmaStream, DmaStreamSlice, FrameAllocOptions, Infallible, USegment, VmIo, - VmReader, VmWriter, + io_util::{HasVmReaderWriter, VmReaderWriterResult}, + DmaDirection, DmaStream, DmaStreamSlice, FrameAllocOptions, Infallible, USegment, VmReader, + VmWriter, }, sync::{SpinLock, WaitQueue}, Error, @@ -391,7 +392,7 @@ pub enum BioDirection { ToDevice, } -impl<'a> BioSegment { +impl BioSegment { /// Allocates a new `BioSegment` with the wanted blocks count and /// the bio direction. pub fn alloc(nblocks: usize, direction: BioDirection) -> Self { @@ -484,28 +485,20 @@ impl<'a> BioSegment { pub fn inner_segment(&self) -> &USegment { self.inner.dma_slice.stream().segment() } +} - /// Returns a reader to read data from it. - pub fn reader(&'a self) -> Result, Error> { +impl HasVmReaderWriter for BioSegment { + type Types = VmReaderWriterResult; + + fn reader(&self) -> Result, Error> { self.inner.dma_slice.reader() } - /// Returns a writer to write data into it. - pub fn writer(&'a self) -> Result, Error> { + fn writer(&self) -> Result, Error> { self.inner.dma_slice.writer() } } -impl VmIo for BioSegment { - fn read(&self, offset: usize, writer: &mut VmWriter) -> Result<(), Error> { - self.inner.dma_slice.read(offset, writer) - } - - fn write(&self, offset: usize, reader: &mut VmReader) -> Result<(), Error> { - self.inner.dma_slice.write(offset, reader) - } -} - // The timing for free the segment to the pool. impl Drop for BioSegmentInner { fn drop(&mut self) { diff --git a/kernel/comps/mlsdisk/src/lib.rs b/kernel/comps/mlsdisk/src/lib.rs index e8592d39c..7c52b70bf 100644 --- a/kernel/comps/mlsdisk/src/lib.rs +++ b/kernel/comps/mlsdisk/src/lib.rs @@ -25,7 +25,10 @@ use aster_block::{ BlockDevice, SECTOR_SIZE, }; use component::{init_component, ComponentInitError}; -use ostd::{mm::VmIo, prelude::*}; +use ostd::{ + mm::{io_util::HasVmReaderWriter, VmIo}, + prelude::*, +}; pub use self::{ error::{Errno, Error}, diff --git a/kernel/comps/network/src/buffer.rs b/kernel/comps/network/src/buffer.rs index c8d75d4c2..1985cc2a0 100644 --- a/kernel/comps/network/src/buffer.rs +++ b/kernel/comps/network/src/buffer.rs @@ -5,8 +5,8 @@ use alloc::{collections::linked_list::LinkedList, sync::Arc}; use aster_softirq::BottomHalfDisabled; use ostd::{ mm::{ - Daddr, DmaDirection, DmaStream, FrameAllocOptions, HasDaddr, Infallible, VmReader, - VmWriter, PAGE_SIZE, + io_util::HasVmReaderWriter, Daddr, DmaDirection, DmaStream, FrameAllocOptions, HasDaddr, + Infallible, VmReader, VmWriter, PAGE_SIZE, }, sync::SpinLock, Pod, diff --git a/kernel/comps/network/src/dma_pool.rs b/kernel/comps/network/src/dma_pool.rs index 448a57427..88ccdad6a 100644 --- a/kernel/comps/network/src/dma_pool.rs +++ b/kernel/comps/network/src/dma_pool.rs @@ -12,8 +12,8 @@ use aster_softirq::BottomHalfDisabled; use bitvec::{array::BitArray, prelude::Lsb0}; use ostd::{ mm::{ - Daddr, DmaDirection, DmaStream, FrameAllocOptions, HasDaddr, Infallible, VmReader, - VmWriter, PAGE_SIZE, + io_util::HasVmReaderWriter, Daddr, DmaDirection, DmaStream, FrameAllocOptions, HasDaddr, + Infallible, VmReader, VmWriter, PAGE_SIZE, }, sync::{RwLock, SpinLock}, }; diff --git a/kernel/comps/virtio/src/device/console/device.rs b/kernel/comps/virtio/src/device/console/device.rs index 7a5434ef0..e6575b860 100644 --- a/kernel/comps/virtio/src/device/console/device.rs +++ b/kernel/comps/virtio/src/device/console/device.rs @@ -7,7 +7,10 @@ use aster_console::{AnyConsoleDevice, ConsoleCallback}; use log::debug; use ostd::{ arch::trap::TrapFrame, - mm::{DmaDirection, DmaStream, DmaStreamSlice, FrameAllocOptions, VmReader}, + mm::{ + io_util::HasVmReaderWriter, DmaDirection, DmaStream, DmaStreamSlice, FrameAllocOptions, + VmReader, + }, sync::{Rcu, SpinLock}, }; diff --git a/kernel/libs/aster-util/src/segment_slice.rs b/kernel/libs/aster-util/src/segment_slice.rs index d63bb06b6..42e2a9045 100644 --- a/kernel/libs/aster-util/src/segment_slice.rs +++ b/kernel/libs/aster-util/src/segment_slice.rs @@ -7,12 +7,9 @@ use alloc::sync::Arc; use core::ops::Range; -use ostd::{ - mm::{ - FallibleVmRead, FallibleVmWrite, Infallible, Paddr, UFrame, USegment, UntypedMem, VmIo, - VmReader, VmWriter, PAGE_SIZE, - }, - Error, Result, +use ostd::mm::{ + io_util::{HasVmReaderWriter, VmReaderWriterIdentity}, + Infallible, Paddr, UFrame, USegment, VmReader, VmWriter, PAGE_SIZE, }; /// A reference to a slice of a [`USegment`]. @@ -69,8 +66,15 @@ impl SegmentSlice { self.nframes() * PAGE_SIZE } - /// Gets a reader for the slice. - pub fn reader(&self) -> VmReader<'_, Infallible> { + fn start_frame_index(&self) -> usize { + self.inner.start_paddr() / PAGE_SIZE + self.range.start + } +} + +impl HasVmReaderWriter for SegmentSlice { + type Types = VmReaderWriterIdentity; + + fn reader(&self) -> VmReader<'_, Infallible> { let mut reader = self.inner.reader(); reader .skip(self.start_paddr() - self.inner.start_paddr()) @@ -78,52 +82,13 @@ impl SegmentSlice { reader } - /// Gets a writer for the slice. - pub fn writer(&self) -> VmWriter<'_, Infallible> { + fn writer(&self) -> VmWriter<'_, Infallible> { let mut writer = self.inner.writer(); writer .skip(self.start_paddr() - self.inner.start_paddr()) .limit(self.nbytes()); writer } - - fn start_frame_index(&self) -> usize { - self.inner.start_paddr() / PAGE_SIZE + self.range.start - } -} - -impl VmIo for SegmentSlice { - fn read(&self, offset: usize, writer: &mut VmWriter) -> Result<()> { - let read_len = writer.avail(); - // Do bound check with potential integer overflow in mind - let max_offset = offset.checked_add(read_len).ok_or(Error::Overflow)?; - if max_offset > self.nbytes() { - return Err(Error::InvalidArgs); - } - let len = self - .reader() - .skip(offset) - .read_fallible(writer) - .map_err(|(e, _)| e)?; - debug_assert!(len == read_len); - Ok(()) - } - - fn write(&self, offset: usize, reader: &mut VmReader) -> Result<()> { - let write_len = reader.remain(); - // Do bound check with potential integer overflow in mind - let max_offset = offset.checked_add(reader.remain()).ok_or(Error::Overflow)?; - if max_offset > self.nbytes() { - return Err(Error::InvalidArgs); - } - let len = self - .writer() - .skip(offset) - .write_fallible(reader) - .map_err(|(e, _)| e)?; - debug_assert!(len == write_len); - Ok(()) - } } impl From for SegmentSlice { diff --git a/kernel/src/fs/exfat/inode.rs b/kernel/src/fs/exfat/inode.rs index 97dcb80c2..bafdc9459 100644 --- a/kernel/src/fs/exfat/inode.rs +++ b/kernel/src/fs/exfat/inode.rs @@ -13,7 +13,7 @@ use aster_block::{ BLOCK_SIZE, }; use aster_rights::Full; -use ostd::mm::{Segment, VmIo}; +use ostd::mm::{io_util::HasVmReaderWriter, Segment, VmIo}; use super::{ constants::*, diff --git a/kernel/src/fs/exfat/mod.rs b/kernel/src/fs/exfat/mod.rs index 6d97629b2..16376f56e 100644 --- a/kernel/src/fs/exfat/mod.rs +++ b/kernel/src/fs/exfat/mod.rs @@ -31,7 +31,7 @@ mod test { BlockDevice, BlockDeviceMeta, }; use ostd::{ - mm::{FrameAllocOptions, Segment, VmIo, PAGE_SIZE}, + mm::{io_util::HasVmReaderWriter, FrameAllocOptions, Segment, VmIo, PAGE_SIZE}, prelude::*, }; use rand::{rngs::SmallRng, RngCore, SeedableRng}; diff --git a/kernel/src/fs/ext2/block_group.rs b/kernel/src/fs/ext2/block_group.rs index c30692488..051583d28 100644 --- a/kernel/src/fs/ext2/block_group.rs +++ b/kernel/src/fs/ext2/block_group.rs @@ -1,7 +1,7 @@ // SPDX-License-Identifier: MPL-2.0 use id_alloc::IdAlloc; -use ostd::{const_assert, mm::UntypedMem}; +use ostd::{const_assert, mm::io_util::HasVmReaderWriter}; use super::{ block_ptr::Ext2Bid, diff --git a/kernel/src/fs/ext2/inode.rs b/kernel/src/fs/ext2/inode.rs index ce635124d..03a7af370 100644 --- a/kernel/src/fs/ext2/inode.rs +++ b/kernel/src/fs/ext2/inode.rs @@ -7,7 +7,7 @@ use alloc::{borrow::ToOwned, rc::Rc}; use core::sync::atomic::{AtomicUsize, Ordering}; use inherit_methods_macro::inherit_methods; -use ostd::{const_assert, mm::UntypedMem}; +use ostd::{const_assert, mm::io_util::HasVmReaderWriter}; use super::{ block_ptr::{BidPath, BlockPtrs, Ext2Bid, BID_SIZE, MAX_BLOCK_PTRS}, diff --git a/kernel/src/fs/ext2/xattr.rs b/kernel/src/fs/ext2/xattr.rs index 97ab00054..2be71681d 100644 --- a/kernel/src/fs/ext2/xattr.rs +++ b/kernel/src/fs/ext2/xattr.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MPL-2.0 -use ostd::mm::UntypedMem; +use ostd::mm::io_util::HasVmReaderWriter; use super::{block_ptr::Ext2Bid, prelude::*, Ext2, Inode}; use crate::fs::utils::{XattrName, XattrNamespace, XattrSetFlags, XATTR_NAME_MAX_LEN}; diff --git a/kernel/src/fs/overlayfs/fs.rs b/kernel/src/fs/overlayfs/fs.rs index 954b8a2d2..385a3d4cb 100644 --- a/kernel/src/fs/overlayfs/fs.rs +++ b/kernel/src/fs/overlayfs/fs.rs @@ -13,7 +13,7 @@ use aster_block::BLOCK_SIZE; use aster_rights::Full; use hashbrown::HashSet; use inherit_methods_macro::inherit_methods; -use ostd::mm::{FrameAllocOptions, UntypedMem}; +use ostd::mm::{io_util::HasVmReaderWriter, FrameAllocOptions}; use crate::{ fs::{ diff --git a/kernel/src/fs/ramfs/fs.rs b/kernel/src/fs/ramfs/fs.rs index a29405354..f1ee970da 100644 --- a/kernel/src/fs/ramfs/fs.rs +++ b/kernel/src/fs/ramfs/fs.rs @@ -11,7 +11,7 @@ use aster_rights::Full; use aster_util::slot_vec::SlotVec; use hashbrown::HashMap; use ostd::{ - mm::{UntypedMem, VmIo}, + mm::{io_util::HasVmReaderWriter, VmIo}, sync::{PreemptDisabled, RwLockWriteGuard}, }; diff --git a/kernel/src/process/process_vm/init_stack/mod.rs b/kernel/src/process/process_vm/init_stack/mod.rs index 531c0d131..fd2199ecb 100644 --- a/kernel/src/process/process_vm/init_stack/mod.rs +++ b/kernel/src/process/process_vm/init_stack/mod.rs @@ -21,7 +21,7 @@ use core::{ use align_ext::AlignExt; use aster_rights::Full; use ostd::{ - mm::{UntypedMem, VmIo, MAX_USERSPACE_VADDR}, + mm::{io_util::HasVmReaderWriter, VmIo, MAX_USERSPACE_VADDR}, task::disable_preempt, }; diff --git a/kernel/src/util/ring_buffer.rs b/kernel/src/util/ring_buffer.rs index 9052d3b93..29aea09c1 100644 --- a/kernel/src/util/ring_buffer.rs +++ b/kernel/src/util/ring_buffer.rs @@ -8,7 +8,7 @@ use core::{ }; use inherit_methods_macro::inherit_methods; -use ostd::mm::{FrameAllocOptions, Segment, UntypedMem, VmIo}; +use ostd::mm::{io_util::HasVmReaderWriter, FrameAllocOptions, Segment, VmIo}; use super::{MultiRead, MultiWrite}; use crate::prelude::*; diff --git a/kernel/src/vm/util.rs b/kernel/src/vm/util.rs index ceba2f48f..b8cf1b88a 100644 --- a/kernel/src/vm/util.rs +++ b/kernel/src/vm/util.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MPL-2.0 -use ostd::mm::{Frame, FrameAllocOptions, UFrame, UntypedMem}; +use ostd::mm::{io_util::HasVmReaderWriter, Frame, FrameAllocOptions, UFrame}; use crate::prelude::*; diff --git a/kernel/src/vm/vmo/mod.rs b/kernel/src/vm/vmo/mod.rs index 77e084bc2..3d7611da4 100644 --- a/kernel/src/vm/vmo/mod.rs +++ b/kernel/src/vm/vmo/mod.rs @@ -13,7 +13,7 @@ use core::{ use align_ext::AlignExt; use aster_rights::Rights; use ostd::{ - mm::{FrameAllocOptions, UFrame, UntypedMem, VmReader, VmWriter}, + mm::{io_util::HasVmReaderWriter, FrameAllocOptions, UFrame, VmReader, VmWriter}, task::disable_preempt, }; use xarray::{Cursor, LockedXArray, XArray}; diff --git a/ostd/src/arch/x86/iommu/interrupt_remapping/table.rs b/ostd/src/arch/x86/iommu/interrupt_remapping/table.rs index ad1a171bc..b56105484 100644 --- a/ostd/src/arch/x86/iommu/interrupt_remapping/table.rs +++ b/ostd/src/arch/x86/iommu/interrupt_remapping/table.rs @@ -8,7 +8,7 @@ use int_to_c_enum::TryFromInt; use super::IrtEntryHandle; use crate::{ - mm::{FrameAllocOptions, Segment, UntypedMem, PAGE_SIZE}, + mm::{io_util::HasVmReaderWriter, FrameAllocOptions, Segment, PAGE_SIZE}, sync::{LocalIrqDisabled, SpinLock}, }; diff --git a/ostd/src/io/io_mem/mod.rs b/ostd/src/io/io_mem/mod.rs index e1680be6f..517c36c9d 100644 --- a/ostd/src/io/io_mem/mod.rs +++ b/ostd/src/io/io_mem/mod.rs @@ -12,10 +12,10 @@ pub(super) use self::allocator::init; pub(crate) use self::allocator::IoMemAllocatorBuilder; use crate::{ mm::{ + io_util::{HasVmReaderWriter, VmReaderWriterIdentity}, kspace::kvirt_area::KVirtArea, page_prop::{CachePolicy, PageFlags, PageProperty, PrivilegedPageFlags}, - FallibleVmRead, FallibleVmWrite, HasPaddr, Infallible, Paddr, PodOnce, VmIo, VmIoOnce, - VmReader, VmWriter, PAGE_SIZE, + HasPaddr, Infallible, Paddr, VmReader, VmWriter, PAGE_SIZE, }, prelude::*, Error, @@ -31,12 +31,6 @@ pub struct IoMem { pa: Paddr, } -impl HasPaddr for IoMem { - fn paddr(&self) -> Paddr { - self.pa - } -} - impl IoMem { /// Acquires an `IoMem` instance for the given range. pub fn acquire(range: Range) -> Result { @@ -143,7 +137,9 @@ impl IoMem { // is in OSTD, so we can rely on the implementation details of `VmReader` and `VmWriter`, which we // know are also suitable for accessing I/O memory. -impl IoMem { +impl HasVmReaderWriter for IoMem { + type Types = VmReaderWriterIdentity; + fn reader(&self) -> VmReader<'_, Infallible> { // SAFETY: The constructor of the `IoMem` structure has already ensured the // safety of reading from the mapped physical address, and the mapping is valid. @@ -167,53 +163,9 @@ impl IoMem { } } -impl VmIo for IoMem { - fn read(&self, offset: usize, writer: &mut VmWriter) -> Result<()> { - let offset = offset + self.offset; - if self - .limit - .checked_sub(offset) - .is_none_or(|remain| remain < writer.avail()) - { - return Err(Error::InvalidArgs); - } - - self.reader() - .skip(offset) - .read_fallible(writer) - .map_err(|(e, _)| e)?; - debug_assert!(!writer.has_avail()); - - Ok(()) - } - - fn write(&self, offset: usize, reader: &mut VmReader) -> Result<()> { - let offset = offset + self.offset; - if self - .limit - .checked_sub(offset) - .is_none_or(|remain| remain < reader.remain()) - { - return Err(Error::InvalidArgs); - } - - self.writer() - .skip(offset) - .write_fallible(reader) - .map_err(|(e, _)| e)?; - debug_assert!(!reader.has_remain()); - - Ok(()) - } -} - -impl VmIoOnce for IoMem { - fn read_once(&self, offset: usize) -> Result { - self.reader().skip(offset).read_once() - } - - fn write_once(&self, offset: usize, new_val: &T) -> Result<()> { - self.writer().skip(offset).write_once(new_val) +impl HasPaddr for IoMem { + fn paddr(&self) -> Paddr { + self.pa } } diff --git a/ostd/src/mm/dma/dma_coherent.rs b/ostd/src/mm/dma/dma_coherent.rs index b7e45fa3f..3e0f129b3 100644 --- a/ostd/src/mm/dma/dma_coherent.rs +++ b/ostd/src/mm/dma/dma_coherent.rs @@ -10,13 +10,11 @@ use crate::{ arch::iommu, mm::{ dma::{dma_type, Daddr, DmaType}, - io::VmIoOnce, + io_util::{HasVmReaderWriter, VmReaderWriterIdentity}, kspace::{paddr_to_vaddr, KERNEL_PAGE_TABLE}, page_prop::CachePolicy, - HasPaddr, Infallible, Paddr, PodOnce, USegment, UntypedMem, VmIo, VmReader, VmWriter, - PAGE_SIZE, + HasPaddr, Infallible, Paddr, USegment, VmReader, VmWriter, PAGE_SIZE, }, - prelude::*, }; cfg_if! { @@ -176,34 +174,14 @@ impl Drop for DmaCoherentInner { } } -impl VmIo for DmaCoherent { - fn read(&self, offset: usize, writer: &mut VmWriter) -> Result<()> { - self.inner.segment.read(offset, writer) - } +impl HasVmReaderWriter for DmaCoherent { + type Types = VmReaderWriterIdentity; - fn write(&self, offset: usize, reader: &mut VmReader) -> Result<()> { - self.inner.segment.write(offset, reader) - } -} - -impl VmIoOnce for DmaCoherent { - fn read_once(&self, offset: usize) -> Result { - self.inner.segment.reader().skip(offset).read_once() - } - - fn write_once(&self, offset: usize, new_val: &T) -> Result<()> { - self.inner.segment.writer().skip(offset).write_once(new_val) - } -} - -impl<'a> DmaCoherent { - /// Returns a reader to read data from it. - pub fn reader(&'a self) -> VmReader<'a, Infallible> { + fn reader(&self) -> VmReader<'_, Infallible> { self.inner.segment.reader() } - /// Returns a writer to write data into it. - pub fn writer(&'a self) -> VmWriter<'a, Infallible> { + fn writer(&self) -> VmWriter<'_, Infallible> { self.inner.segment.writer() } } diff --git a/ostd/src/mm/dma/dma_stream.rs b/ostd/src/mm/dma/dma_stream.rs index 73917bbd4..626e391c6 100644 --- a/ostd/src/mm/dma/dma_stream.rs +++ b/ostd/src/mm/dma/dma_stream.rs @@ -9,7 +9,8 @@ use crate::{ error::Error, mm::{ dma::{dma_type, Daddr, DmaType}, - HasPaddr, Infallible, Paddr, USegment, UntypedMem, VmIo, VmReader, VmWriter, PAGE_SIZE, + io_util::{HasVmReaderWriter, VmReaderWriterResult}, + HasPaddr, Infallible, Paddr, USegment, VmReader, VmWriter, PAGE_SIZE, }, }; @@ -135,8 +136,8 @@ impl DmaStream { /// (e.g., using [`write_bytes`]). /// Before the CPU side notifies the device side to read, it must call the `sync` method first. /// - /// [`read_bytes`]: Self::read_bytes - /// [`write_bytes`]: Self::write_bytes + /// [`read_bytes`]: crate::mm::VmIo::read_bytes + /// [`write_bytes`]: crate::mm::VmIo::write_bytes pub fn sync(&self, _byte_range: Range) -> Result<(), Error> { cfg_if::cfg_if! { if #[cfg(target_arch = "x86_64")]{ @@ -203,35 +204,17 @@ impl Drop for DmaStreamInner { } } -impl VmIo for DmaStream { - /// Reads data into the buffer. - fn read(&self, offset: usize, writer: &mut VmWriter) -> Result<(), Error> { - if self.inner.direction == DmaDirection::ToDevice { - return Err(Error::AccessDenied); - } - self.inner.segment.read(offset, writer) - } +impl HasVmReaderWriter for DmaStream { + type Types = VmReaderWriterResult; - /// Writes data from the buffer. - fn write(&self, offset: usize, reader: &mut VmReader) -> Result<(), Error> { - if self.inner.direction == DmaDirection::FromDevice { - return Err(Error::AccessDenied); - } - self.inner.segment.write(offset, reader) - } -} - -impl<'a> DmaStream { - /// Returns a reader to read data from it. - pub fn reader(&'a self) -> Result, Error> { + fn reader(&self) -> Result, Error> { if self.inner.direction == DmaDirection::ToDevice { return Err(Error::AccessDenied); } Ok(self.inner.segment.reader()) } - /// Returns a writer to write data into it. - pub fn writer(&'a self) -> Result, Error> { + fn writer(&self) -> Result, Error> { if self.inner.direction == DmaDirection::FromDevice { return Err(Error::AccessDenied); } @@ -300,38 +283,24 @@ impl> DmaStreamSlice { .as_ref() .sync(self.offset..self.offset + self.len) } +} - /// Returns a reader to read data from it. - pub fn reader(&self) -> Result, Error> { +impl> HasVmReaderWriter for DmaStreamSlice { + type Types = VmReaderWriterResult; + + fn reader(&self) -> Result, Error> { let mut stream_reader = self.stream.as_ref().reader()?; stream_reader.skip(self.offset).limit(self.len); Ok(stream_reader) } - /// Returns a writer to write data into it. - pub fn writer(&self) -> Result, Error> { + fn writer(&self) -> Result, Error> { let mut stream_writer = self.stream.as_ref().writer()?; stream_writer.skip(self.offset).limit(self.len); Ok(stream_writer) } } -impl + Send + Sync> VmIo for DmaStreamSlice { - fn read(&self, offset: usize, writer: &mut VmWriter) -> Result<(), Error> { - if writer.avail() + offset > self.len { - return Err(Error::InvalidArgs); - } - self.stream.as_ref().read(self.offset + offset, writer) - } - - fn write(&self, offset: usize, reader: &mut VmReader) -> Result<(), Error> { - if reader.remain() + offset > self.len { - return Err(Error::InvalidArgs); - } - self.stream.as_ref().write(self.offset + offset, reader) - } -} - impl> HasDaddr for DmaStreamSlice { fn daddr(&self) -> Daddr { self.stream.as_ref().daddr() + self.offset diff --git a/ostd/src/mm/dma/test.rs b/ostd/src/mm/dma/test.rs index 0ef1243a6..154285995 100644 --- a/ostd/src/mm/dma/test.rs +++ b/ostd/src/mm/dma/test.rs @@ -6,6 +6,7 @@ use crate::{ mm::{ dma::*, io::{VmIo, VmIoOnce}, + io_util::HasVmReaderWriter, kspace::KERNEL_PAGE_TABLE, paddr_to_vaddr, CachePolicy, FrameAllocOptions, HasPaddr, VmReader, VmWriter, PAGE_SIZE, }, diff --git a/ostd/src/mm/frame/test.rs b/ostd/src/mm/frame/test.rs index 95544ee01..d25ba1b35 100644 --- a/ostd/src/mm/frame/test.rs +++ b/ostd/src/mm/frame/test.rs @@ -1,7 +1,9 @@ // SPDX-License-Identifier: MPL-2.0 use super::{allocator::FrameAllocOptions, *}; -use crate::{impl_frame_meta_for, impl_untyped_frame_meta_for, prelude::*}; +use crate::{ + impl_frame_meta_for, impl_untyped_frame_meta_for, mm::io_util::HasVmReaderWriter, prelude::*, +}; /// Typed mock metadata struct for testing #[derive(Debug, Default)] diff --git a/ostd/src/mm/frame/untyped.rs b/ostd/src/mm/frame/untyped.rs index 89c999b67..a3f1dbc14 100644 --- a/ostd/src/mm/frame/untyped.rs +++ b/ostd/src/mm/frame/untyped.rs @@ -6,14 +6,14 @@ //! relaxed rules but we cannot create references to them. This module provides //! the declaration of untyped frames and segments, and the implementation of //! extra functionalities (such as [`VmIo`]) for them. +//! +//! [`VmIo`]: crate::mm::VmIo use super::{meta::AnyFrameMeta, Frame, Segment}; -use crate::{ - mm::{ - io::{FallibleVmRead, FallibleVmWrite, VmIo, VmReader, VmWriter}, - paddr_to_vaddr, Infallible, - }, - Error, Result, +use crate::mm::{ + io::{VmReader, VmWriter}, + io_util::{HasVmReaderWriter, VmReaderWriterIdentity}, + paddr_to_vaddr, Infallible, }; /// The metadata of untyped frame. @@ -66,66 +66,29 @@ macro_rules! impl_untyped_frame_meta_for { // A special case of untyped metadata is the unit type. impl_untyped_frame_meta_for!(()); -/// A physical memory range that is untyped. -/// -/// Untyped frames or segments can be safely read and written by the kernel or -/// the user. -pub trait UntypedMem { - /// Borrows a reader that can read the untyped memory. - fn reader(&self) -> VmReader<'_, Infallible>; - /// Borrows a writer that can write the untyped memory. - fn writer(&self) -> VmWriter<'_, Infallible>; -} - macro_rules! impl_untyped_for { ($t:ident) => { - impl UntypedMem for $t { + impl HasVmReaderWriter for $t { + type Types = VmReaderWriterIdentity; + fn reader(&self) -> VmReader<'_, Infallible> { let ptr = paddr_to_vaddr(self.start_paddr()) as *const u8; - // SAFETY: Only untyped frames are allowed to be read. + // SAFETY: + // - The memory range points to untyped memory. + // - The frame/segment is alive during the lifetime `'_`. + // - Using `VmReader` and `VmWriter` is the only way to access the frame/segment. unsafe { VmReader::from_kernel_space(ptr, self.size()) } } fn writer(&self) -> VmWriter<'_, Infallible> { let ptr = paddr_to_vaddr(self.start_paddr()) as *mut u8; - // SAFETY: Only untyped frames are allowed to be written. + // SAFETY: + // - The memory range points to untyped memory. + // - The frame/segment is alive during the lifetime `'_`. + // - Using `VmReader` and `VmWriter` is the only way to access the frame/segment. unsafe { VmWriter::from_kernel_space(ptr, self.size()) } } } - - impl VmIo for $t { - fn read(&self, offset: usize, writer: &mut VmWriter) -> Result<()> { - let read_len = writer.avail().min(self.size().saturating_sub(offset)); - // Do bound check with potential integer overflow in mind - let max_offset = offset.checked_add(read_len).ok_or(Error::Overflow)?; - if max_offset > self.size() { - return Err(Error::InvalidArgs); - } - let len = self - .reader() - .skip(offset) - .read_fallible(writer) - .map_err(|(e, _)| e)?; - debug_assert!(len == read_len); - Ok(()) - } - - fn write(&self, offset: usize, reader: &mut VmReader) -> Result<()> { - let write_len = reader.remain().min(self.size().saturating_sub(offset)); - // Do bound check with potential integer overflow in mind - let max_offset = offset.checked_add(write_len).ok_or(Error::Overflow)?; - if max_offset > self.size() { - return Err(Error::InvalidArgs); - } - let len = self - .writer() - .skip(offset) - .write_fallible(reader) - .map_err(|(e, _)| e)?; - debug_assert!(len == write_len); - Ok(()) - } - } }; } diff --git a/ostd/src/mm/io.rs b/ostd/src/mm/io.rs index e35e0869f..33ef1afb9 100644 --- a/ostd/src/mm/io.rs +++ b/ostd/src/mm/io.rs @@ -43,7 +43,6 @@ use core::{marker::PhantomData, mem::MaybeUninit}; use align_ext::AlignExt; -use inherit_methods_macro::inherit_methods; use crate::{ arch::mm::{__memcpy_fallible, __memset_fallible}, @@ -256,42 +255,6 @@ pub trait VmIoOnce { fn write_once(&self, offset: usize, new_val: &T) -> Result<()>; } -macro_rules! impl_vm_io_pointer { - ($typ:ty,$from:tt) => { - #[inherit_methods(from = $from)] - impl VmIo for $typ { - fn read(&self, offset: usize, writer: &mut VmWriter) -> Result<()>; - fn read_bytes(&self, offset: usize, buf: &mut [u8]) -> Result<()>; - fn read_val(&self, offset: usize) -> Result; - fn read_slice(&self, offset: usize, slice: &mut [F]) -> Result<()>; - fn write(&self, offset: usize, reader: &mut VmReader) -> Result<()>; - fn write_bytes(&self, offset: usize, buf: &[u8]) -> Result<()>; - fn write_val(&self, offset: usize, new_val: &F) -> Result<()>; - fn write_slice(&self, offset: usize, slice: &[F]) -> Result<()>; - } - }; -} - -impl_vm_io_pointer!(&T, "(**self)"); -impl_vm_io_pointer!(&mut T, "(**self)"); -impl_vm_io_pointer!(Box, "(**self)"); -impl_vm_io_pointer!(Arc, "(**self)"); - -macro_rules! impl_vm_io_once_pointer { - ($typ:ty,$from:tt) => { - #[inherit_methods(from = $from)] - impl VmIoOnce for $typ { - fn read_once(&self, offset: usize) -> Result; - fn write_once(&self, offset: usize, new_val: &F) -> Result<()>; - } - }; -} - -impl_vm_io_once_pointer!(&T, "(**self)"); -impl_vm_io_once_pointer!(&mut T, "(**self)"); -impl_vm_io_once_pointer!(Box, "(**self)"); -impl_vm_io_once_pointer!(Arc, "(**self)"); - /// A marker type used for [`VmReader`] and [`VmWriter`], /// representing whether reads or writes on the underlying memory region are fallible. pub enum Fallible {} diff --git a/ostd/src/mm/io_util.rs b/ostd/src/mm/io_util.rs new file mode 100644 index 000000000..7caf63224 --- /dev/null +++ b/ostd/src/mm/io_util.rs @@ -0,0 +1,196 @@ +// SPDX-License-Identifier: MPL-2.0 + +//! Utilities for types in [`super::io`]. + +use inherit_methods_macro::inherit_methods; +use ostd_pod::Pod; + +use super::{Infallible, PodOnce, VmIo, VmIoOnce, VmReader, VmWriter}; +use crate::{ + mm::{FallibleVmRead, FallibleVmWrite}, + prelude::*, + Error, +}; + +/// A helper trait that denotes types that can provide [`VmReader`]s and [`VmWriter`]s. +/// +/// Having the reader and writer means that the type is capable of performing a range of VM +/// operations. Thus, several traits will be automatically and efficiently implemented, such as +/// [`VmIo`] and [`VmIoOnce`]. +pub trait HasVmReaderWriter { + /// A marker type that denotes the return types of [`Self::reader`] and [`Self::writer`]. + /// + /// This can be either [`VmReaderWriterIdentity`] or [`VmReaderWriterResult`]. + // + // TODO: This exists because `DmaStream` and related types track the DMA direction at runtime. + // The goal is to achieve this at compile time, which would eliminate the need for + // `VmReaderWriterTypes`. See the discussion at + // . + type Types: VmReaderWriterTypes; + + /// Returns a reader to read data from it. + fn reader(&self) -> ::Reader<'_>; + /// Returns a writer to write data to it. + fn writer(&self) -> ::Writer<'_>; +} + +/// A marker trait that denotes the return types for [`HasVmReaderWriter`]. +pub trait VmReaderWriterTypes { + /// The return type of [`HasVmReaderWriter::reader`]. + type Reader<'a>; + /// The return type of [`HasVmReaderWriter::writer`]. + type Writer<'a>; + + /// Converts [`Self::Reader`] to [`Result>`]. + fn to_reader_result(reader: Self::Reader<'_>) -> Result>; + /// Converts [`Self::Writer`] to [`Result>`]. + fn to_writer_result(writer: Self::Writer<'_>) -> Result>; +} + +/// A marker type that denotes reader and writer identities as [`HasVmReaderWriter`] return types. +pub enum VmReaderWriterIdentity {} +impl VmReaderWriterTypes for VmReaderWriterIdentity { + type Reader<'a> = VmReader<'a, Infallible>; + type Writer<'a> = VmWriter<'a, Infallible>; + fn to_reader_result(reader: Self::Reader<'_>) -> Result> { + Ok(reader) + } + fn to_writer_result(writer: Self::Writer<'_>) -> Result> { + Ok(writer) + } +} + +/// A marker type that denotes reader and writer results as [`HasVmReaderWriter`] return types. +pub enum VmReaderWriterResult {} +impl VmReaderWriterTypes for VmReaderWriterResult { + type Reader<'a> = Result>; + type Writer<'a> = Result>; + fn to_reader_result(reader: Self::Reader<'_>) -> Result> { + reader + } + fn to_writer_result(writer: Self::Writer<'_>) -> Result> { + writer + } +} + +impl VmIo for S { + fn read(&self, offset: usize, writer: &mut VmWriter) -> Result<()> { + let mut reader = ::Types::to_reader_result(self.reader())?; + + let limit = offset.checked_add(writer.avail()).ok_or(Error::Overflow)?; + if limit > reader.remain() { + return Err(Error::InvalidArgs); + } + + reader.skip(offset); + let _len = reader + .to_fallible() + .read_fallible(writer) + .map_err(|(err, _)| err)?; + debug_assert!(!writer.has_avail()); + Ok(()) + } + + fn read_bytes(&self, offset: usize, buf: &mut [u8]) -> Result<()> { + let mut reader = ::Types::to_reader_result(self.reader())?; + + let limit = offset.checked_add(buf.len()).ok_or(Error::Overflow)?; + if limit > reader.remain() { + return Err(Error::InvalidArgs); + } + + let len = reader.skip(offset).read(&mut VmWriter::from(&mut *buf)); + debug_assert_eq!(len, buf.len()); + Ok(()) + } + + // No need to implement `read_slice`. Its default implementation is efficient enough by relying + // on `read_bytes`. + + fn read_val(&self, offset: usize) -> Result { + let mut reader = ::Types::to_reader_result(self.reader())?; + + if offset > reader.remain() { + return Err(Error::InvalidArgs); + } + + reader.skip(offset).read_val() + } + + fn write(&self, offset: usize, reader: &mut VmReader) -> Result<()> { + let mut writer = ::Types::to_writer_result(self.writer())?; + + let limit = offset.checked_add(reader.remain()).ok_or(Error::Overflow)?; + if limit > writer.avail() { + return Err(Error::InvalidArgs); + } + + writer.skip(offset); + let _len = writer + .to_fallible() + .write_fallible(reader) + .map_err(|(err, _)| err)?; + debug_assert!(!reader.has_remain()); + Ok(()) + } + + fn write_bytes(&self, offset: usize, buf: &[u8]) -> Result<()> { + let mut writer = ::Types::to_writer_result(self.writer())?; + + let limit = offset.checked_add(buf.len()).ok_or(Error::Overflow)?; + if limit > writer.avail() { + return Err(Error::InvalidArgs); + } + + let len = writer.skip(offset).write(&mut VmReader::from(buf)); + debug_assert_eq!(len, buf.len()); + Ok(()) + } + + // No need to implement `write_slice`. Its default implementation is efficient enough by + // relying on `write_bytes`. + + fn write_val(&self, offset: usize, new_val: &T) -> Result<()> { + let mut writer = ::Types::to_writer_result(self.writer())?; + + if offset > writer.avail() { + return Err(Error::InvalidArgs); + } + + writer.skip(offset).write_val(new_val) + } +} + +impl VmIoOnce for S { + fn read_once(&self, offset: usize) -> Result { + let mut reader = ::Types::to_reader_result(self.reader())?; + reader.skip(offset).read_once() + } + + fn write_once(&self, offset: usize, new_val: &T) -> Result<()> { + let mut writer = ::Types::to_writer_result(self.writer())?; + writer.skip(offset).write_once(new_val) + } +} + +// The pointer implementations below (i.e., `impl_vm_io_pointer`/`impl_vm_io_once_pointer`) should +// apply to the `VmIo`/`VmIoOnce` traits themselves, instead of these helper traits. +// +// However, there are some unexpected compiler errors that complain that downstream crates can +// implement `HasVmReaderWriter` to cause conflict implementations. + +macro_rules! impl_vm_io_pointer { + ($typ:ty,$from:tt) => { + #[inherit_methods(from = $from)] + impl HasVmReaderWriter for $typ { + type Types = T::Types; + fn reader(&self) -> ::Reader<'_>; + fn writer(&self) -> ::Writer<'_>; + } + }; +} + +impl_vm_io_pointer!(&T, "(**self)"); +impl_vm_io_pointer!(&mut T, "(**self)"); +impl_vm_io_pointer!(Box, "(**self)"); +impl_vm_io_pointer!(Arc, "(**self)"); diff --git a/ostd/src/mm/mod.rs b/ostd/src/mm/mod.rs index 922838566..118732ae6 100644 --- a/ostd/src/mm/mod.rs +++ b/ostd/src/mm/mod.rs @@ -12,6 +12,7 @@ pub(crate) mod dma; pub mod frame; pub mod heap; pub mod io; +pub mod io_util; pub(crate) mod kspace; pub(crate) mod page_prop; pub(crate) mod page_table; @@ -29,7 +30,7 @@ pub use self::{ allocator::FrameAllocOptions, segment::{Segment, USegment}, unique::UniqueFrame, - untyped::{AnyUFrameMeta, UFrame, UntypedMem}, + untyped::{AnyUFrameMeta, UFrame}, Frame, }, io::{ diff --git a/ostd/src/prelude.rs b/ostd/src/prelude.rs index 443296493..b11fe5ad1 100644 --- a/ostd/src/prelude.rs +++ b/ostd/src/prelude.rs @@ -14,6 +14,6 @@ pub use ostd_macros::ktest; pub use crate::{ early_print as print, early_println as println, - mm::{Paddr, UntypedMem, Vaddr}, + mm::{Paddr, Vaddr}, panic::abort, };