Refactor all io APIs of vfs based on VmReader/VmWriter

This commit is contained in:
Shaowei Song
2024-08-22 07:52:20 +00:00
committed by Tate, Hongliang Tian
parent 837c7bebb6
commit dce796cdde
50 changed files with 566 additions and 376 deletions

View File

@ -5,7 +5,10 @@
use core::{mem::size_of, ops::Range};
use crate::{
mm::{kspace::LINEAR_MAPPING_BASE_VADDR, paddr_to_vaddr, HasPaddr, Paddr, Vaddr, VmIo},
mm::{
kspace::LINEAR_MAPPING_BASE_VADDR, paddr_to_vaddr, HasPaddr, Paddr, Vaddr, VmIo, VmReader,
VmWriter,
},
Error, Pod, Result,
};
@ -17,25 +20,27 @@ pub struct IoMem {
}
impl VmIo for IoMem {
fn read_bytes(&self, offset: usize, buf: &mut [u8]) -> crate::Result<()> {
self.check_range(offset, buf.len())?;
fn read(&self, offset: usize, writer: &mut VmWriter) -> crate::Result<()> {
let read_len = writer.avail();
self.check_range(offset, read_len)?;
unsafe {
core::ptr::copy(
(self.virtual_address + offset) as *const u8,
buf.as_mut_ptr(),
buf.len(),
writer.cursor(),
read_len,
);
}
Ok(())
}
fn write_bytes(&self, offset: usize, buf: &[u8]) -> crate::Result<()> {
self.check_range(offset, buf.len())?;
fn write(&self, offset: usize, reader: &mut VmReader) -> crate::Result<()> {
let write_len = reader.remain();
self.check_range(offset, write_len)?;
unsafe {
core::ptr::copy(
buf.as_ptr(),
reader.cursor(),
(self.virtual_address + offset) as *mut u8,
buf.len(),
write_len,
);
}
Ok(())

View File

@ -167,12 +167,12 @@ impl Drop for DmaCoherentInner {
}
impl VmIo for DmaCoherent {
fn read_bytes(&self, offset: usize, buf: &mut [u8]) -> Result<()> {
self.inner.vm_segment.read_bytes(offset, buf)
fn read(&self, offset: usize, writer: &mut VmWriter) -> Result<()> {
self.inner.vm_segment.read(offset, writer)
}
fn write_bytes(&self, offset: usize, buf: &[u8]) -> Result<()> {
self.inner.vm_segment.write_bytes(offset, buf)
fn write(&self, offset: usize, reader: &mut VmReader) -> Result<()> {
self.inner.vm_segment.write(offset, reader)
}
}

View File

@ -202,19 +202,19 @@ impl Drop for DmaStreamInner {
impl VmIo for DmaStream {
/// Reads data into the buffer.
fn read_bytes(&self, offset: usize, buf: &mut [u8]) -> Result<(), Error> {
fn read(&self, offset: usize, writer: &mut VmWriter) -> Result<(), Error> {
if self.inner.direction == DmaDirection::ToDevice {
return Err(Error::AccessDenied);
}
self.inner.vm_segment.read_bytes(offset, buf)
self.inner.vm_segment.read(offset, writer)
}
/// Writes data from the buffer.
fn write_bytes(&self, offset: usize, buf: &[u8]) -> Result<(), Error> {
fn write(&self, offset: usize, reader: &mut VmReader) -> Result<(), Error> {
if self.inner.direction == DmaDirection::FromDevice {
return Err(Error::AccessDenied);
}
self.inner.vm_segment.write_bytes(offset, buf)
self.inner.vm_segment.write(offset, reader)
}
}
@ -282,18 +282,18 @@ impl<'a> DmaStreamSlice<'a> {
}
impl VmIo for DmaStreamSlice<'_> {
fn read_bytes(&self, offset: usize, buf: &mut [u8]) -> Result<(), Error> {
if buf.len() + offset > self.len {
fn read(&self, offset: usize, writer: &mut VmWriter) -> Result<(), Error> {
if writer.avail() + offset > self.len {
return Err(Error::InvalidArgs);
}
self.stream.read_bytes(self.offset + offset, buf)
self.stream.read(self.offset + offset, writer)
}
fn write_bytes(&self, offset: usize, buf: &[u8]) -> Result<(), Error> {
if buf.len() + offset > self.len {
fn write(&self, offset: usize, reader: &mut VmReader) -> Result<(), Error> {
if reader.remain() + offset > self.len {
return Err(Error::InvalidArgs);
}
self.stream.write_bytes(self.offset + offset, buf)
self.stream.write(self.offset + offset, reader)
}
}

View File

@ -24,7 +24,7 @@ use super::{
};
use crate::{
mm::{
io::{VmIo, VmReader, VmWriter},
io::{FallibleVmRead, FallibleVmWrite, VmIo, VmReader, VmWriter},
paddr_to_vaddr, HasPaddr, Paddr, PAGE_SIZE,
},
Error, Result,
@ -133,42 +133,55 @@ impl<'a> Frame {
}
impl VmIo for Frame {
fn read_bytes(&self, offset: usize, buf: &mut [u8]) -> Result<()> {
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(buf.len()).ok_or(Error::Overflow)?;
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(&mut buf.into());
debug_assert!(len == buf.len());
let len = self
.reader()
.skip(offset)
.read_fallible(writer)
.map_err(|(e, _)| e)?;
debug_assert!(len == read_len);
Ok(())
}
fn write_bytes(&self, offset: usize, buf: &[u8]) -> Result<()> {
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(buf.len()).ok_or(Error::Overflow)?;
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(&mut buf.into());
debug_assert!(len == buf.len());
let len = self
.writer()
.skip(offset)
.write_fallible(reader)
.map_err(|(e, _)| e)?;
debug_assert!(len == write_len);
Ok(())
}
}
impl VmIo for alloc::vec::Vec<Frame> {
fn read_bytes(&self, offset: usize, buf: &mut [u8]) -> Result<()> {
fn read(&self, offset: usize, writer: &mut VmWriter) -> Result<()> {
// Do bound check with potential integer overflow in mind
let max_offset = offset.checked_add(buf.len()).ok_or(Error::Overflow)?;
let max_offset = offset.checked_add(writer.avail()).ok_or(Error::Overflow)?;
if max_offset > self.len() * PAGE_SIZE {
return Err(Error::InvalidArgs);
}
let num_skip_pages = offset / PAGE_SIZE;
let mut start = offset % PAGE_SIZE;
let mut buf_writer: VmWriter<Infallible> = buf.into();
for frame in self.iter().skip(num_skip_pages) {
let read_len = frame.reader().skip(start).read(&mut buf_writer);
let read_len = frame
.reader()
.skip(start)
.read_fallible(writer)
.map_err(|(e, _)| e)?;
if read_len == 0 {
break;
}
@ -177,18 +190,21 @@ impl VmIo for alloc::vec::Vec<Frame> {
Ok(())
}
fn write_bytes(&self, offset: usize, buf: &[u8]) -> Result<()> {
fn write(&self, offset: usize, reader: &mut VmReader) -> Result<()> {
// Do bound check with potential integer overflow in mind
let max_offset = offset.checked_add(buf.len()).ok_or(Error::Overflow)?;
let max_offset = offset.checked_add(reader.remain()).ok_or(Error::Overflow)?;
if max_offset > self.len() * PAGE_SIZE {
return Err(Error::InvalidArgs);
}
let num_skip_pages = offset / PAGE_SIZE;
let mut start = offset % PAGE_SIZE;
let mut buf_reader: VmReader<Infallible> = buf.into();
for frame in self.iter().skip(num_skip_pages) {
let write_len = frame.writer().skip(start).write(&mut buf_reader);
let write_len = frame
.writer()
.skip(start)
.write_fallible(reader)
.map_err(|(e, _)| e)?;
if write_len == 0 {
break;
}

View File

@ -9,7 +9,8 @@ use super::Frame;
use crate::{
mm::{
page::{cont_pages::ContPages, meta::FrameMeta, Page},
HasPaddr, Infallible, Paddr, VmIo, VmReader, VmWriter, PAGE_SIZE,
FallibleVmRead, FallibleVmWrite, HasPaddr, Infallible, Paddr, VmIo, VmReader, VmWriter,
PAGE_SIZE,
},
Error, Result,
};
@ -114,25 +115,35 @@ impl<'a> Segment {
}
impl VmIo for Segment {
fn read_bytes(&self, offset: usize, buf: &mut [u8]) -> Result<()> {
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(buf.len()).ok_or(Error::Overflow)?;
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(&mut buf.into());
debug_assert!(len == buf.len());
let len = self
.reader()
.skip(offset)
.read_fallible(writer)
.map_err(|(e, _)| e)?;
debug_assert!(len == read_len);
Ok(())
}
fn write_bytes(&self, offset: usize, buf: &[u8]) -> Result<()> {
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(buf.len()).ok_or(Error::Overflow)?;
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(&mut buf.into());
debug_assert!(len == buf.len());
let len = self
.writer()
.skip(offset)
.write_fallible(reader)
.map_err(|(e, _)| e)?;
debug_assert!(len == write_len);
Ok(())
}
}

View File

@ -40,6 +40,7 @@
//! user space, making it impossible to avoid data races). However, they may produce erroneous
//! results, such as unexpected bytes being copied, but do not cause soundness problems.
use alloc::vec;
use core::marker::PhantomData;
use align_ext::AlignExt;
@ -69,14 +70,26 @@ use crate::{
/// [`Segment`]: crate::mm::Segment
/// [`Frame`]: crate::mm::Frame
pub trait VmIo: Send + Sync {
/// Reads requested data at a specified offset into a given `VmWriter`.
///
/// # No short reads
///
/// On success, the `writer` must be written with the requested data
/// completely. If, for any reason, the requested data is only partially
/// available, then the method shall return an error.
fn read(&self, offset: usize, writer: &mut VmWriter) -> Result<()>;
/// Reads a specified number of bytes at a specified offset into a given buffer.
///
/// # No short reads
///
/// On success, the output `buf` must be filled with the requested data
/// completely. If, for any reason, the requested data is only partially
/// available, then the method shall return an error.
fn read_bytes(&self, offset: usize, buf: &mut [u8]) -> Result<()>;
/// Similar to [`read`].
///
/// [`read`]: VmIo::read
fn read_bytes(&self, offset: usize, buf: &mut [u8]) -> Result<()> {
let mut writer = VmWriter::from(buf).to_fallible();
self.read(offset, &mut writer)
}
/// Reads a value of a specified type at a specified offset.
fn read_val<T: Pod>(&self, offset: usize) -> Result<T> {
@ -89,9 +102,9 @@ pub trait VmIo: Send + Sync {
///
/// # No short reads
///
/// Similar to [`read_bytes`].
/// Similar to [`read`].
///
/// [`read_bytes`]: VmIo::read_bytes
/// [`read`]: VmIo::read
fn read_slice<T: Pod>(&self, offset: usize, slice: &mut [T]) -> Result<()> {
let len_in_bytes = core::mem::size_of_val(slice);
let ptr = slice as *mut [T] as *mut u8;
@ -101,14 +114,26 @@ pub trait VmIo: Send + Sync {
self.read_bytes(offset, buf)
}
/// Writes all data from a given `VmReader` at a specified offset.
///
/// # No short writes
///
/// On success, the data from the `reader` must be read to the VM object entirely.
/// If, for any reason, the input data can only be written partially,
/// then the method shall return an error.
fn write(&self, offset: usize, reader: &mut VmReader) -> Result<()>;
/// Writes a specified number of bytes from a given buffer at a specified offset.
///
/// # No short writes
///
/// On success, the input `buf` must be written to the VM object entirely.
/// If, for any reason, the input data can only be written partially,
/// then the method shall return an error.
fn write_bytes(&self, offset: usize, buf: &[u8]) -> Result<()>;
/// Similar to [`write`].
///
/// [`write`]: VmIo::write
fn write_bytes(&self, offset: usize, buf: &[u8]) -> Result<()> {
let mut reader = VmReader::from(buf).to_fallible();
self.write(offset, &mut reader)
}
/// Writes a value of a specified type at a specified offset.
fn write_val<T: Pod>(&self, offset: usize, new_val: &T) -> Result<()> {
@ -120,9 +145,9 @@ pub trait VmIo: Send + Sync {
///
/// # No short write
///
/// Similar to [`write_bytes`].
/// Similar to [`write`].
///
/// [`write_bytes`]: VmIo::write_bytes
/// [`write`]: VmIo::write
fn write_slice<T: Pod>(&self, offset: usize, slice: &[T]) -> Result<()> {
let len_in_bytes = core::mem::size_of_val(slice);
let ptr = slice as *const [T] as *const u8;
@ -219,9 +244,11 @@ 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<()>;
@ -364,7 +391,7 @@ macro_rules! impl_read_fallible {
return Ok(0);
}
// SAFETY: The source and destionation are subsets of memory ranges specified by
// SAFETY: The source and destination are subsets of memory ranges specified by
// the reader and writer, so they are either valid for reading and writing or in
// user space.
let copied_len = unsafe {
@ -437,7 +464,7 @@ impl<'a> VmReader<'a, Infallible> {
return 0;
}
// SAFETY: The source and destionation are subsets of memory ranges specified by the reader
// SAFETY: The source and destination are subsets of memory ranges specified by the reader
// and writer, so they are valid for reading and writing.
unsafe {
memcpy(writer.cursor, self.cursor, copy_len);
@ -545,6 +572,25 @@ impl<'a> VmReader<'a, Fallible> {
})?;
Ok(val)
}
/// Collects all the remaining bytes into a `Vec<u8>`.
///
/// If the memory read failed, this method will return `Err`
/// and the current reader's cursor remains pointing to
/// the original starting position.
pub fn collect(&mut self) -> Result<Vec<u8>> {
let mut buf = vec![0u8; self.remain()];
self.read_fallible(&mut buf.as_mut_slice().into())
.map_err(|(err, copied_len)| {
// SAFETY: The `copied_len` is the number of bytes read so far.
// So the `cursor` can be moved back to the original position.
unsafe {
self.cursor = self.cursor.sub(copied_len);
}
err
})?;
Ok(buf)
}
}
impl<'a, Fallibility> VmReader<'a, Fallibility> {