Provide efficient `VmIo` with VM readers/writers
This commit is contained in:
parent
894b942a79
commit
2700d88bef
|
|
@ -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<VmReader<'a, Infallible>, Error> {
|
||||
impl HasVmReaderWriter for BioSegment {
|
||||
type Types = VmReaderWriterResult;
|
||||
|
||||
fn reader(&self) -> Result<VmReader<'_, Infallible>, Error> {
|
||||
self.inner.dma_slice.reader()
|
||||
}
|
||||
|
||||
/// Returns a writer to write data into it.
|
||||
pub fn writer(&'a self) -> Result<VmWriter<'a, Infallible>, Error> {
|
||||
fn writer(&self) -> Result<VmWriter<'_, Infallible>, 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) {
|
||||
|
|
|
|||
|
|
@ -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},
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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},
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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},
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -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<USegment> for SegmentSlice {
|
||||
|
|
|
|||
|
|
@ -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::*,
|
||||
|
|
|
|||
|
|
@ -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};
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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},
|
||||
|
|
|
|||
|
|
@ -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};
|
||||
|
|
|
|||
|
|
@ -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::{
|
||||
|
|
|
|||
|
|
@ -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},
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -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::*;
|
||||
|
|
|
|||
|
|
@ -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::*;
|
||||
|
||||
|
|
|
|||
|
|
@ -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};
|
||||
|
|
|
|||
|
|
@ -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},
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -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<Paddr>) -> Result<IoMem> {
|
||||
|
|
@ -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<T: PodOnce>(&self, offset: usize) -> Result<T> {
|
||||
self.reader().skip(offset).read_once()
|
||||
}
|
||||
|
||||
fn write_once<T: PodOnce>(&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
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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<T: PodOnce>(&self, offset: usize) -> Result<T> {
|
||||
self.inner.segment.reader().skip(offset).read_once()
|
||||
}
|
||||
|
||||
fn write_once<T: PodOnce>(&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()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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<usize>) -> 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<VmReader<'a, Infallible>, Error> {
|
||||
fn reader(&self) -> Result<VmReader<'_, Infallible>, 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<VmWriter<'a, Infallible>, Error> {
|
||||
fn writer(&self) -> Result<VmWriter<'_, Infallible>, Error> {
|
||||
if self.inner.direction == DmaDirection::FromDevice {
|
||||
return Err(Error::AccessDenied);
|
||||
}
|
||||
|
|
@ -300,38 +283,24 @@ impl<Dma: AsRef<DmaStream>> DmaStreamSlice<Dma> {
|
|||
.as_ref()
|
||||
.sync(self.offset..self.offset + self.len)
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns a reader to read data from it.
|
||||
pub fn reader(&self) -> Result<VmReader<Infallible>, Error> {
|
||||
impl<Dma: AsRef<DmaStream>> HasVmReaderWriter for DmaStreamSlice<Dma> {
|
||||
type Types = VmReaderWriterResult;
|
||||
|
||||
fn reader(&self) -> Result<VmReader<'_, Infallible>, 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<VmWriter<Infallible>, Error> {
|
||||
fn writer(&self) -> Result<VmWriter<'_, Infallible>, Error> {
|
||||
let mut stream_writer = self.stream.as_ref().writer()?;
|
||||
stream_writer.skip(self.offset).limit(self.len);
|
||||
Ok(stream_writer)
|
||||
}
|
||||
}
|
||||
|
||||
impl<Dma: AsRef<DmaStream> + Send + Sync> VmIo for DmaStreamSlice<Dma> {
|
||||
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<Dma: AsRef<DmaStream>> HasDaddr for DmaStreamSlice<Dma> {
|
||||
fn daddr(&self) -> Daddr {
|
||||
self.stream.as_ref().daddr() + self.offset
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
},
|
||||
|
|
|
|||
|
|
@ -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)]
|
||||
|
|
|
|||
|
|
@ -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<UM: AnyUFrameMeta + ?Sized> UntypedMem for $t<UM> {
|
||||
impl<UM: AnyUFrameMeta + ?Sized> HasVmReaderWriter for $t<UM> {
|
||||
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<UM: AnyUFrameMeta + ?Sized> VmIo for $t<UM> {
|
||||
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(())
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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<T: PodOnce>(&self, offset: usize, new_val: &T) -> Result<()>;
|
||||
}
|
||||
|
||||
macro_rules! impl_vm_io_pointer {
|
||||
($typ:ty,$from:tt) => {
|
||||
#[inherit_methods(from = $from)]
|
||||
impl<T: VmIo> 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<F: Pod>(&self, offset: usize) -> Result<F>;
|
||||
fn read_slice<F: Pod>(&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<F: Pod>(&self, offset: usize, new_val: &F) -> Result<()>;
|
||||
fn write_slice<F: Pod>(&self, offset: usize, slice: &[F]) -> Result<()>;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
impl_vm_io_pointer!(&T, "(**self)");
|
||||
impl_vm_io_pointer!(&mut T, "(**self)");
|
||||
impl_vm_io_pointer!(Box<T>, "(**self)");
|
||||
impl_vm_io_pointer!(Arc<T>, "(**self)");
|
||||
|
||||
macro_rules! impl_vm_io_once_pointer {
|
||||
($typ:ty,$from:tt) => {
|
||||
#[inherit_methods(from = $from)]
|
||||
impl<T: VmIoOnce> VmIoOnce for $typ {
|
||||
fn read_once<F: PodOnce>(&self, offset: usize) -> Result<F>;
|
||||
fn write_once<F: PodOnce>(&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<T>, "(**self)");
|
||||
impl_vm_io_once_pointer!(Arc<T>, "(**self)");
|
||||
|
||||
/// A marker type used for [`VmReader`] and [`VmWriter`],
|
||||
/// representing whether reads or writes on the underlying memory region are fallible.
|
||||
pub enum Fallible {}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
// <https://github.com/asterinas/asterinas/pull/2289#discussion_r2261801694>.
|
||||
type Types: VmReaderWriterTypes;
|
||||
|
||||
/// Returns a reader to read data from it.
|
||||
fn reader(&self) -> <Self::Types as VmReaderWriterTypes>::Reader<'_>;
|
||||
/// Returns a writer to write data to it.
|
||||
fn writer(&self) -> <Self::Types as VmReaderWriterTypes>::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<VmReader<Infallible>>`].
|
||||
fn to_reader_result(reader: Self::Reader<'_>) -> Result<VmReader<'_, Infallible>>;
|
||||
/// Converts [`Self::Writer`] to [`Result<VmWriter<Infallible>>`].
|
||||
fn to_writer_result(writer: Self::Writer<'_>) -> Result<VmWriter<'_, Infallible>>;
|
||||
}
|
||||
|
||||
/// 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<VmReader<'_, Infallible>> {
|
||||
Ok(reader)
|
||||
}
|
||||
fn to_writer_result(writer: Self::Writer<'_>) -> Result<VmWriter<'_, Infallible>> {
|
||||
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<VmReader<'a, Infallible>>;
|
||||
type Writer<'a> = Result<VmWriter<'a, Infallible>>;
|
||||
fn to_reader_result(reader: Self::Reader<'_>) -> Result<VmReader<'_, Infallible>> {
|
||||
reader
|
||||
}
|
||||
fn to_writer_result(writer: Self::Writer<'_>) -> Result<VmWriter<'_, Infallible>> {
|
||||
writer
|
||||
}
|
||||
}
|
||||
|
||||
impl<S: HasVmReaderWriter + Send + Sync> VmIo for S {
|
||||
fn read(&self, offset: usize, writer: &mut VmWriter) -> Result<()> {
|
||||
let mut reader = <Self as HasVmReaderWriter>::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 = <Self as HasVmReaderWriter>::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<T: Pod>(&self, offset: usize) -> Result<T> {
|
||||
let mut reader = <Self as HasVmReaderWriter>::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 = <Self as HasVmReaderWriter>::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 = <Self as HasVmReaderWriter>::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<T: Pod>(&self, offset: usize, new_val: &T) -> Result<()> {
|
||||
let mut writer = <Self as HasVmReaderWriter>::Types::to_writer_result(self.writer())?;
|
||||
|
||||
if offset > writer.avail() {
|
||||
return Err(Error::InvalidArgs);
|
||||
}
|
||||
|
||||
writer.skip(offset).write_val(new_val)
|
||||
}
|
||||
}
|
||||
|
||||
impl<S: HasVmReaderWriter> VmIoOnce for S {
|
||||
fn read_once<T: PodOnce>(&self, offset: usize) -> Result<T> {
|
||||
let mut reader = <Self as HasVmReaderWriter>::Types::to_reader_result(self.reader())?;
|
||||
reader.skip(offset).read_once()
|
||||
}
|
||||
|
||||
fn write_once<T: PodOnce>(&self, offset: usize, new_val: &T) -> Result<()> {
|
||||
let mut writer = <Self as HasVmReaderWriter>::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<T: HasVmReaderWriter> HasVmReaderWriter for $typ {
|
||||
type Types = T::Types;
|
||||
fn reader(&self) -> <Self::Types as VmReaderWriterTypes>::Reader<'_>;
|
||||
fn writer(&self) -> <Self::Types as VmReaderWriterTypes>::Writer<'_>;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
impl_vm_io_pointer!(&T, "(**self)");
|
||||
impl_vm_io_pointer!(&mut T, "(**self)");
|
||||
impl_vm_io_pointer!(Box<T>, "(**self)");
|
||||
impl_vm_io_pointer!(Arc<T>, "(**self)");
|
||||
|
|
@ -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::{
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
};
|
||||
|
|
|
|||
Loading…
Reference in New Issue