Refactor VmReader&VmWriter as given fallibility marker

This commit is contained in:
Shaowei Song
2024-08-20 02:05:25 +00:00
committed by Tate, Hongliang Tian
parent 562e644375
commit 2102107be1
16 changed files with 172 additions and 104 deletions

View File

@ -5,7 +5,7 @@
use core::mem; use core::mem;
use ostd::{ use ostd::{
mm::{UserSpace, VmReader, VmSpace, VmWriter}, mm::{Fallible, Infallible, VmReader, VmSpace, VmWriter},
task::Task, task::Task,
}; };
@ -56,14 +56,14 @@ impl CurrentUserSpace {
/// Creates a reader to read data from the user space of the current task. /// Creates a reader to read data from the user space of the current task.
/// ///
/// Returns `Err` if the `vaddr` and `len` do not represent a user space memory range. /// Returns `Err` if the `vaddr` and `len` do not represent a user space memory range.
pub fn reader(&self, vaddr: Vaddr, len: usize) -> Result<VmReader<'_, UserSpace>> { pub fn reader(&self, vaddr: Vaddr, len: usize) -> Result<VmReader<'_, Fallible>> {
Ok(self.0.reader(vaddr, len)?) Ok(self.0.reader(vaddr, len)?)
} }
/// Creates a writer to write data into the user space. /// Creates a writer to write data into the user space.
/// ///
/// Returns `Err` if the `vaddr` and `len` do not represent a user space memory range. /// Returns `Err` if the `vaddr` and `len` do not represent a user space memory range.
pub fn writer(&self, vaddr: Vaddr, len: usize) -> Result<VmWriter<'_, UserSpace>> { pub fn writer(&self, vaddr: Vaddr, len: usize) -> Result<VmWriter<'_, Fallible>> {
Ok(self.0.writer(vaddr, len)?) Ok(self.0.writer(vaddr, len)?)
} }
@ -76,7 +76,7 @@ impl CurrentUserSpace {
/// If the destination `VmWriter` (`dest`) is empty, this function still /// If the destination `VmWriter` (`dest`) is empty, this function still
/// checks if the current task and user space are available. If they are, /// checks if the current task and user space are available. If they are,
/// it returns `Ok`. /// it returns `Ok`.
pub fn read_bytes(&self, src: Vaddr, dest: &mut VmWriter<'_>) -> Result<()> { pub fn read_bytes(&self, src: Vaddr, dest: &mut VmWriter<'_, Infallible>) -> Result<()> {
let copy_len = dest.avail(); let copy_len = dest.avail();
if copy_len > 0 { if copy_len > 0 {
@ -107,7 +107,7 @@ impl CurrentUserSpace {
/// If the source `VmReader` (`src`) is empty, this function still checks if /// If the source `VmReader` (`src`) is empty, this function still checks if
/// the current task and user space are available. If they are, it returns /// the current task and user space are available. If they are, it returns
/// `Ok`. /// `Ok`.
pub fn write_bytes(&self, dest: Vaddr, src: &mut VmReader<'_>) -> Result<()> { pub fn write_bytes(&self, dest: Vaddr, src: &mut VmReader<'_, Infallible>) -> Result<()> {
let copy_len = src.remain(); let copy_len = src.remain();
if copy_len > 0 { if copy_len > 0 {
@ -150,7 +150,7 @@ pub trait ReadCString {
fn read_cstring(&mut self) -> Result<CString>; fn read_cstring(&mut self) -> Result<CString>;
} }
impl<'a> ReadCString for VmReader<'a, UserSpace> { impl<'a> ReadCString for VmReader<'a, Fallible> {
/// This implementation is inspired by /// This implementation is inspired by
/// the `do_strncpy_from_user` function in Linux kernel. /// the `do_strncpy_from_user` function in Linux kernel.
/// The original Linux implementation can be found at: /// The original Linux implementation can be found at:

View File

@ -2,7 +2,7 @@
#![allow(dead_code)] #![allow(dead_code)]
use ostd::mm::VmReader; use ostd::mm::{Infallible, VmReader};
use spin::Once; use spin::Once;
use crate::{ use crate::{
@ -78,7 +78,7 @@ impl Default for TtyDriver {
} }
} }
fn console_input_callback(mut reader: VmReader) { fn console_input_callback(mut reader: VmReader<Infallible>) {
let tty_driver = get_tty_driver(); let tty_driver = get_tty_driver();
while reader.remain() > 0 { while reader.remain() > 0 {
let ch = reader.read_val().unwrap(); let ch = reader.read_val().unwrap();

View File

@ -17,7 +17,7 @@ pub(crate) use bitflags::bitflags;
pub(crate) use int_to_c_enum::TryFromInt; pub(crate) use int_to_c_enum::TryFromInt;
pub(crate) use log::{debug, error, info, log_enabled, trace, warn}; pub(crate) use log::{debug, error, info, log_enabled, trace, warn};
pub(crate) use ostd::{ pub(crate) use ostd::{
mm::{Vaddr, VmReader, VmWriter, PAGE_SIZE}, mm::{FallibleVmRead, FallibleVmWrite, Vaddr, VmReader, VmWriter, PAGE_SIZE},
sync::{Mutex, MutexGuard, RwLock, RwMutex, SpinLock, SpinLockGuard}, sync::{Mutex, MutexGuard, RwLock, RwMutex, SpinLock, SpinLockGuard},
Pod, Pod,
}; };

View File

@ -11,7 +11,7 @@ use align_ext::AlignExt;
use aster_rights::Rights; use aster_rights::Rights;
use ostd::{ use ostd::{
collections::xarray::{CursorMut, XArray}, collections::xarray::{CursorMut, XArray},
mm::{Frame, FrameAllocOptions, VmReader, VmWriter}, mm::{Frame, FrameAllocOptions, Infallible, VmReader, VmWriter},
}; };
use crate::prelude::*; use crate::prelude::*;
@ -304,7 +304,7 @@ impl Vmo_ {
let read_len = buf.len(); let read_len = buf.len();
let read_range = offset..(offset + read_len); let read_range = offset..(offset + read_len);
let mut read_offset = offset % PAGE_SIZE; let mut read_offset = offset % PAGE_SIZE;
let mut buf_writer: VmWriter = buf.into(); let mut buf_writer: VmWriter<Infallible> = buf.into();
let read = move |page: Frame| { let read = move |page: Frame| {
page.reader().skip(read_offset).read(&mut buf_writer); page.reader().skip(read_offset).read(&mut buf_writer);
@ -319,7 +319,7 @@ impl Vmo_ {
let write_len = buf.len(); let write_len = buf.len();
let write_range = offset..(offset + write_len); let write_range = offset..(offset + write_len);
let mut write_offset = offset % PAGE_SIZE; let mut write_offset = offset % PAGE_SIZE;
let mut buf_reader: VmReader = buf.into(); let mut buf_reader: VmReader<Infallible> = buf.into();
let mut write = move |page: Frame| { let mut write = move |page: Frame| {
page.writer().skip(write_offset).write(&mut buf_reader); page.writer().skip(write_offset).write(&mut buf_reader);

View File

@ -3,7 +3,7 @@
use align_ext::AlignExt; use align_ext::AlignExt;
use int_to_c_enum::TryFromInt; use int_to_c_enum::TryFromInt;
use ostd::{ use ostd::{
mm::{Frame, Segment, VmReader, VmWriter}, mm::{Frame, Infallible, Segment, VmReader, VmWriter},
sync::WaitQueue, sync::WaitQueue,
}; };
@ -423,7 +423,7 @@ impl<'a> BioSegment {
} }
/// Returns a reader to read data from it. /// Returns a reader to read data from it.
pub fn reader(&'a self) -> VmReader<'a> { pub fn reader(&'a self) -> VmReader<'a, Infallible> {
self.pages self.pages
.reader() .reader()
.skip(self.offset.value()) .skip(self.offset.value())
@ -431,7 +431,7 @@ impl<'a> BioSegment {
} }
/// Returns a writer to write data into it. /// Returns a writer to write data into it.
pub fn writer(&'a self) -> VmWriter<'a> { pub fn writer(&'a self) -> VmWriter<'a, Infallible> {
self.pages self.pages
.writer() .writer()
.skip(self.offset.value()) .skip(self.offset.value())

View File

@ -11,10 +11,13 @@ use alloc::{collections::BTreeMap, fmt::Debug, string::String, sync::Arc, vec::V
use core::any::Any; use core::any::Any;
use component::{init_component, ComponentInitError}; use component::{init_component, ComponentInitError};
use ostd::{mm::VmReader, sync::SpinLock}; use ostd::{
mm::{Infallible, VmReader},
sync::SpinLock,
};
use spin::Once; use spin::Once;
pub type ConsoleCallback = dyn Fn(VmReader) + Send + Sync; pub type ConsoleCallback = dyn Fn(VmReader<Infallible>) + Send + Sync;
pub trait AnyConsoleDevice: Send + Sync + Any + Debug { pub trait AnyConsoleDevice: Send + Sync + Any + Debug {
fn send(&self, buf: &[u8]); fn send(&self, buf: &[u8]);

View File

@ -5,7 +5,8 @@ use alloc::{collections::LinkedList, sync::Arc};
use align_ext::AlignExt; use align_ext::AlignExt;
use ostd::{ use ostd::{
mm::{ mm::{
Daddr, DmaDirection, DmaStream, FrameAllocOptions, HasDaddr, VmReader, VmWriter, PAGE_SIZE, Daddr, DmaDirection, DmaStream, FrameAllocOptions, HasDaddr, Infallible, VmReader,
VmWriter, PAGE_SIZE,
}, },
sync::SpinLock, sync::SpinLock,
Pod, Pod,
@ -52,7 +53,7 @@ impl TxBuffer {
tx_buffer tx_buffer
} }
pub fn writer(&self) -> VmWriter<'_> { pub fn writer(&self) -> VmWriter<'_, Infallible> {
self.dma_stream.writer().unwrap().limit(self.nbytes) self.dma_stream.writer().unwrap().limit(self.nbytes)
} }
@ -106,7 +107,7 @@ impl RxBuffer {
self.packet_len = packet_len; self.packet_len = packet_len;
} }
pub fn packet(&self) -> VmReader<'_> { pub fn packet(&self) -> VmReader<'_, Infallible> {
self.segment self.segment
.sync(self.header_len..self.header_len + self.packet_len) .sync(self.header_len..self.header_len + self.packet_len)
.unwrap(); .unwrap();
@ -117,7 +118,7 @@ impl RxBuffer {
.limit(self.packet_len) .limit(self.packet_len)
} }
pub fn buf(&self) -> VmReader<'_> { pub fn buf(&self) -> VmReader<'_, Infallible> {
self.segment self.segment
.sync(0..self.header_len + self.packet_len) .sync(0..self.header_len + self.packet_len)
.unwrap(); .unwrap();

View File

@ -11,7 +11,8 @@ use core::ops::Range;
use bitvec::{array::BitArray, prelude::Lsb0}; use bitvec::{array::BitArray, prelude::Lsb0};
use ostd::{ use ostd::{
mm::{ mm::{
Daddr, DmaDirection, DmaStream, FrameAllocOptions, HasDaddr, VmReader, VmWriter, PAGE_SIZE, Daddr, DmaDirection, DmaStream, FrameAllocOptions, HasDaddr, Infallible, VmReader,
VmWriter, PAGE_SIZE,
}, },
sync::{RwLock, SpinLock}, sync::{RwLock, SpinLock},
}; };
@ -233,12 +234,12 @@ impl DmaSegment {
self.size self.size
} }
pub fn reader(&self) -> Result<VmReader<'_>, ostd::Error> { pub fn reader(&self) -> Result<VmReader<'_, Infallible>, ostd::Error> {
let offset = self.start_addr - self.dma_stream.daddr(); let offset = self.start_addr - self.dma_stream.daddr();
Ok(self.dma_stream.reader()?.skip(offset).limit(self.size)) Ok(self.dma_stream.reader()?.skip(offset).limit(self.size))
} }
pub fn writer(&self) -> Result<VmWriter<'_>, ostd::Error> { pub fn writer(&self) -> Result<VmWriter<'_, Infallible>, ostd::Error> {
let offset = self.start_addr - self.dma_stream.daddr(); let offset = self.start_addr - self.dma_stream.daddr();
Ok(self.dma_stream.writer()?.skip(offset).limit(self.size)) Ok(self.dma_stream.writer()?.skip(offset).limit(self.size))
} }

View File

@ -13,8 +13,8 @@ use alloc::vec;
use ostd::arch::qemu::{exit_qemu, QemuExitCode}; use ostd::arch::qemu::{exit_qemu, QemuExitCode};
use ostd::cpu::UserContext; use ostd::cpu::UserContext;
use ostd::mm::{ use ostd::mm::{
CachePolicy, FrameAllocOptions, PageFlags, PageProperty, Vaddr, VmIo, VmSpace, VmWriter, CachePolicy, FallibleVmRead, FallibleVmWrite, FrameAllocOptions, PageFlags, PageProperty,
PAGE_SIZE, Vaddr, VmIo, VmSpace, VmWriter, PAGE_SIZE,
}; };
use ostd::prelude::*; use ostd::prelude::*;
use ostd::task::{Task, TaskOptions}; use ostd::task::{Task, TaskOptions};

View File

@ -13,7 +13,7 @@ use crate::{
io::VmIoOnce, io::VmIoOnce,
kspace::{paddr_to_vaddr, KERNEL_PAGE_TABLE}, kspace::{paddr_to_vaddr, KERNEL_PAGE_TABLE},
page_prop::CachePolicy, page_prop::CachePolicy,
HasPaddr, Paddr, PodOnce, Segment, VmIo, VmReader, VmWriter, PAGE_SIZE, HasPaddr, Infallible, Paddr, PodOnce, Segment, VmIo, VmReader, VmWriter, PAGE_SIZE,
}, },
prelude::*, prelude::*,
}; };
@ -192,12 +192,12 @@ impl VmIoOnce for DmaCoherent {
impl<'a> DmaCoherent { impl<'a> DmaCoherent {
/// Returns a reader to read data from it. /// Returns a reader to read data from it.
pub fn reader(&'a self) -> VmReader<'a> { pub fn reader(&'a self) -> VmReader<'a, Infallible> {
self.inner.vm_segment.reader() self.inner.vm_segment.reader()
} }
/// Returns a writer to write data into it. /// Returns a writer to write data into it.
pub fn writer(&'a self) -> VmWriter<'a> { pub fn writer(&'a self) -> VmWriter<'a, Infallible> {
self.inner.vm_segment.writer() self.inner.vm_segment.writer()
} }
} }

View File

@ -11,7 +11,7 @@ use crate::{
error::Error, error::Error,
mm::{ mm::{
dma::{dma_type, Daddr, DmaType}, dma::{dma_type, Daddr, DmaType},
HasPaddr, Paddr, Segment, VmIo, VmReader, VmWriter, PAGE_SIZE, HasPaddr, Infallible, Paddr, Segment, VmIo, VmReader, VmWriter, PAGE_SIZE,
}, },
}; };
@ -220,7 +220,7 @@ impl VmIo for DmaStream {
impl<'a> DmaStream { impl<'a> DmaStream {
/// Returns a reader to read data from it. /// Returns a reader to read data from it.
pub fn reader(&'a self) -> Result<VmReader<'a>, Error> { pub fn reader(&'a self) -> Result<VmReader<'a, Infallible>, Error> {
if self.inner.direction == DmaDirection::ToDevice { if self.inner.direction == DmaDirection::ToDevice {
return Err(Error::AccessDenied); return Err(Error::AccessDenied);
} }
@ -228,7 +228,7 @@ impl<'a> DmaStream {
} }
/// Returns a writer to write data into it. /// Returns a writer to write data into it.
pub fn writer(&'a self) -> Result<VmWriter<'a>, Error> { pub fn writer(&'a self) -> Result<VmWriter<'a, Infallible>, Error> {
if self.inner.direction == DmaDirection::FromDevice { if self.inner.direction == DmaDirection::FromDevice {
return Err(Error::AccessDenied); return Err(Error::AccessDenied);
} }

View File

@ -15,9 +15,12 @@ use core::mem::ManuallyDrop;
pub use segment::Segment; pub use segment::Segment;
use super::page::{ use super::{
page::{
meta::{FrameMeta, MetaSlot, PageMeta, PageUsage}, meta::{FrameMeta, MetaSlot, PageMeta, PageUsage},
DynPage, Page, DynPage, Page,
},
Infallible,
}; };
use crate::{ use crate::{
mm::{ mm::{
@ -111,7 +114,7 @@ impl HasPaddr for Frame {
impl<'a> Frame { impl<'a> Frame {
/// Returns a reader to read data from it. /// Returns a reader to read data from it.
pub fn reader(&'a self) -> VmReader<'a> { pub fn reader(&'a self) -> VmReader<'a, Infallible> {
// SAFETY: // SAFETY:
// - The memory range points to untyped memory. // - The memory range points to untyped memory.
// - The frame is alive during the lifetime `'a`. // - The frame is alive during the lifetime `'a`.
@ -120,7 +123,7 @@ impl<'a> Frame {
} }
/// Returns a writer to write data into it. /// Returns a writer to write data into it.
pub fn writer(&'a self) -> VmWriter<'a> { pub fn writer(&'a self) -> VmWriter<'a, Infallible> {
// SAFETY: // SAFETY:
// - The memory range points to untyped memory. // - The memory range points to untyped memory.
// - The frame is alive during the lifetime `'a`. // - The frame is alive during the lifetime `'a`.
@ -163,7 +166,7 @@ impl VmIo for alloc::vec::Vec<Frame> {
let num_skip_pages = offset / PAGE_SIZE; let num_skip_pages = offset / PAGE_SIZE;
let mut start = offset % PAGE_SIZE; let mut start = offset % PAGE_SIZE;
let mut buf_writer: VmWriter = buf.into(); let mut buf_writer: VmWriter<Infallible> = buf.into();
for frame in self.iter().skip(num_skip_pages) { 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(&mut buf_writer);
if read_len == 0 { if read_len == 0 {
@ -183,7 +186,7 @@ impl VmIo for alloc::vec::Vec<Frame> {
let num_skip_pages = offset / PAGE_SIZE; let num_skip_pages = offset / PAGE_SIZE;
let mut start = offset % PAGE_SIZE; let mut start = offset % PAGE_SIZE;
let mut buf_reader: VmReader = buf.into(); let mut buf_reader: VmReader<Infallible> = buf.into();
for frame in self.iter().skip(num_skip_pages) { 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(&mut buf_reader);
if write_len == 0 { if write_len == 0 {

View File

@ -9,7 +9,7 @@ use super::Frame;
use crate::{ use crate::{
mm::{ mm::{
page::{cont_pages::ContPages, meta::FrameMeta, Page}, page::{cont_pages::ContPages, meta::FrameMeta, Page},
HasPaddr, Paddr, VmIo, VmReader, VmWriter, PAGE_SIZE, HasPaddr, Infallible, Paddr, VmIo, VmReader, VmWriter, PAGE_SIZE,
}, },
Error, Result, Error, Result,
}; };
@ -95,7 +95,7 @@ impl Segment {
impl<'a> Segment { impl<'a> Segment {
/// Returns a reader to read data from it. /// Returns a reader to read data from it.
pub fn reader(&'a self) -> VmReader<'a> { pub fn reader(&'a self) -> VmReader<'a, Infallible> {
// SAFETY: // SAFETY:
// - The memory range points to untyped memory. // - The memory range points to untyped memory.
// - The segment is alive during the lifetime `'a`. // - The segment is alive during the lifetime `'a`.
@ -104,7 +104,7 @@ impl<'a> Segment {
} }
/// Returns a writer to write data into it. /// Returns a writer to write data into it.
pub fn writer(&'a self) -> VmWriter<'a> { pub fn writer(&'a self) -> VmWriter<'a, Infallible> {
// SAFETY: // SAFETY:
// - The memory range points to untyped memory. // - The memory range points to untyped memory.
// - The segment is alive during the lifetime `'a`. // - The segment is alive during the lifetime `'a`.

View File

@ -250,12 +250,11 @@ impl_vm_io_once_pointer!(Box<T>, "(**self)");
impl_vm_io_once_pointer!(Arc<T>, "(**self)"); impl_vm_io_once_pointer!(Arc<T>, "(**self)");
/// A marker structure used for [`VmReader`] and [`VmWriter`], /// A marker structure used for [`VmReader`] and [`VmWriter`],
/// representing their operated memory scope is in user space. /// representing whether reads or writes on the underlying memory region are fallible.
pub struct UserSpace; pub struct Fallible;
/// A marker structure used for [`VmReader`] and [`VmWriter`], /// A marker structure used for [`VmReader`] and [`VmWriter`],
/// representing their operated memory scope is in kernel space. /// representing whether reads or writes on the underlying memory region are infallible.
pub struct KernelSpace; pub struct Infallible;
/// Copies `len` bytes from `src` to `dst`. /// Copies `len` bytes from `src` to `dst`.
/// ///
@ -300,13 +299,44 @@ unsafe fn memcpy_fallible(dst: *mut u8, src: *const u8, len: usize) -> usize {
len - failed_bytes len - failed_bytes
} }
/// Fallible memory read from a `VmWriter`.
pub trait FallibleVmRead<F> {
/// Reads all data into the writer until one of the three conditions is met:
/// 1. The reader has no remaining data.
/// 2. The writer has no available space.
/// 3. The reader/writer encounters some error.
///
/// On success, the number of bytes read is returned;
/// On error, both the error and the number of bytes read so far are returned.
fn read_fallible(
&mut self,
writer: &mut VmWriter<'_, F>,
) -> core::result::Result<usize, (Error, usize)>;
}
/// Fallible memory write from a `VmReader`.
pub trait FallibleVmWrite<F> {
/// Writes all data from the reader until one of the three conditions is met:
/// 1. The reader has no remaining data.
/// 2. The writer has no available space.
/// 3. The reader/writer encounters some error.
///
/// On success, the number of bytes written is returned;
/// On error, both the error and the number of bytes written so far are returned.
fn write_fallible(
&mut self,
reader: &mut VmReader<'_, F>,
) -> core::result::Result<usize, (Error, usize)>;
}
/// `VmReader` is a reader for reading data from a contiguous range of memory. /// `VmReader` is a reader for reading data from a contiguous range of memory.
/// ///
/// The memory range read by `VmReader` can be in either kernel space or user space. /// The memory range read by `VmReader` can be in either kernel space or user space.
/// When the operating range is in kernel space, the memory within that range /// When the operating range is in kernel space, the memory within that range
/// is guaranteed to be valid. /// is guaranteed to be valid, and the corresponding memory reads are infallible.
/// When the operating range is in user space, it is ensured that the page table of /// When the operating range is in user space, it is ensured that the page table of
/// the process creating the `VmReader` is active for the duration of `'a`. /// the process creating the `VmReader` is active for the duration of `'a`,
/// and the corresponding memory reads are considered fallible.
/// ///
/// When perform reading with a `VmWriter`, if one of them represents typed memory, /// When perform reading with a `VmWriter`, if one of them represents typed memory,
/// it can ensure that the reading range in this reader and writing range in the /// it can ensure that the reading range in this reader and writing range in the
@ -316,25 +346,18 @@ unsafe fn memcpy_fallible(dst: *mut u8, src: *const u8, len: usize) -> usize {
/// and physical address level. There is not guarantee for the operation results /// and physical address level. There is not guarantee for the operation results
/// of `VmReader` and `VmWriter` in overlapping untyped addresses, and it is /// of `VmReader` and `VmWriter` in overlapping untyped addresses, and it is
/// the user's responsibility to handle this situation. /// the user's responsibility to handle this situation.
pub struct VmReader<'a, Space = KernelSpace> { pub struct VmReader<'a, Fallibility = Fallible> {
cursor: *const u8, cursor: *const u8,
end: *const u8, end: *const u8,
phantom: PhantomData<(&'a [u8], Space)>, phantom: PhantomData<(&'a [u8], Fallibility)>,
} }
macro_rules! impl_read_fallible { macro_rules! impl_read_fallible {
($read_space:ty, $write_space:ty) => { ($reader_fallibility:ty, $writer_fallibility:ty) => {
impl<'a> VmReader<'a, $read_space> { impl<'a> FallibleVmRead<$writer_fallibility> for VmReader<'a, $reader_fallibility> {
/// Reads all data into the writer until one of the three conditions is met: fn read_fallible(
/// 1. The reader has no remaining data.
/// 2. The writer has no available space.
/// 3. The reader/writer encounters some error.
///
/// On success, the number of bytes read is returned;
/// On error, both the error and the number of bytes read so far are returned.
pub fn read_fallible(
&mut self, &mut self,
writer: &mut VmWriter<'_, $write_space>, writer: &mut VmWriter<'_, $writer_fallibility>,
) -> core::result::Result<usize, (Error, usize)> { ) -> core::result::Result<usize, (Error, usize)> {
let copy_len = self.remain().min(writer.avail()); let copy_len = self.remain().min(writer.avail());
if copy_len == 0 { if copy_len == 0 {
@ -361,18 +384,11 @@ macro_rules! impl_read_fallible {
} }
macro_rules! impl_write_fallible { macro_rules! impl_write_fallible {
($read_space:ty, $write_space:ty) => { ($writer_fallibility:ty, $reader_fallibility:ty) => {
impl<'a> VmWriter<'a, $write_space> { impl<'a> FallibleVmWrite<$reader_fallibility> for VmWriter<'a, $writer_fallibility> {
/// Writes all data from the reader until one of the three conditions is met: fn write_fallible(
/// 1. The reader has no remaining data.
/// 2. The writer has no available space.
/// 3. The reader/writer encounters some error.
///
/// On success, the number of bytes written is returned;
/// On error, both the error and the number of bytes written so far are returned.
pub fn write_fallible(
&mut self, &mut self,
reader: &mut VmReader<'_, $read_space>, reader: &mut VmReader<'_, $reader_fallibility>,
) -> core::result::Result<usize, (Error, usize)> { ) -> core::result::Result<usize, (Error, usize)> {
reader.read_fallible(self) reader.read_fallible(self)
} }
@ -380,14 +396,14 @@ macro_rules! impl_write_fallible {
}; };
} }
// TODO: implement an additional function `memcpy_nonoverlapping_fallible` impl_read_fallible!(Fallible, Infallible);
// to implement read/write instruction from user space to user space. impl_read_fallible!(Fallible, Fallible);
impl_read_fallible!(UserSpace, KernelSpace); impl_read_fallible!(Infallible, Fallible);
impl_read_fallible!(KernelSpace, UserSpace); impl_write_fallible!(Fallible, Infallible);
impl_write_fallible!(UserSpace, KernelSpace); impl_write_fallible!(Fallible, Fallible);
impl_write_fallible!(KernelSpace, UserSpace); impl_write_fallible!(Infallible, Fallible);
impl<'a> VmReader<'a, KernelSpace> { impl<'a> VmReader<'a, Infallible> {
/// Constructs a `VmReader` from a pointer and a length, which represents /// Constructs a `VmReader` from a pointer and a length, which represents
/// a memory range in kernel space. /// a memory range in kernel space.
/// ///
@ -397,8 +413,9 @@ impl<'a> VmReader<'a, KernelSpace> {
/// ///
/// [valid]: crate::mm::io#safety /// [valid]: crate::mm::io#safety
pub unsafe fn from_kernel_space(ptr: *const u8, len: usize) -> Self { pub unsafe fn from_kernel_space(ptr: *const u8, len: usize) -> Self {
// If casting a zero sized slice to a pointer, the pointer may be null // Rust is allowed to give the reference to a zero-sized object a very small address,
// and does not reside in our kernel space range. // falling out of the kernel virtual address space range.
// So when `len` is zero, we should not and need not to check `ptr`.
debug_assert!(len == 0 || KERNEL_BASE_VADDR <= ptr as usize); debug_assert!(len == 0 || KERNEL_BASE_VADDR <= ptr as usize);
debug_assert!(len == 0 || ptr.add(len) as usize <= KERNEL_END_VADDR); debug_assert!(len == 0 || ptr.add(len) as usize <= KERNEL_END_VADDR);
@ -414,7 +431,7 @@ impl<'a> VmReader<'a, KernelSpace> {
/// 2. The writer has no available space. /// 2. The writer has no available space.
/// ///
/// Returns the number of bytes read. /// Returns the number of bytes read.
pub fn read(&mut self, writer: &mut VmWriter<'_, KernelSpace>) -> usize { pub fn read(&mut self, writer: &mut VmWriter<'_, Infallible>) -> usize {
let copy_len = self.remain().min(writer.avail()); let copy_len = self.remain().min(writer.avail());
if copy_len == 0 { if copy_len == 0 {
return 0; return 0;
@ -474,9 +491,17 @@ impl<'a> VmReader<'a, KernelSpace> {
Ok(val) Ok(val)
} }
/// Converts to a fallible reader.
pub fn to_fallible(self) -> VmReader<'a, Fallible> {
// SAFETY: It is safe to transmute to a fallible reader since
// 1. the fallibility is a zero-sized marker type,
// 2. an infallible reader covers the capabilities of a fallible reader.
unsafe { core::mem::transmute(self) }
}
} }
impl<'a> VmReader<'a, UserSpace> { impl<'a> VmReader<'a, Fallible> {
/// Constructs a `VmReader` from a pointer and a length, which represents /// Constructs a `VmReader` from a pointer and a length, which represents
/// a memory range in user space. /// a memory range in user space.
/// ///
@ -498,6 +523,10 @@ impl<'a> VmReader<'a, UserSpace> {
/// If the length of the `Pod` type exceeds `self.remain()`, /// If the length of the `Pod` type exceeds `self.remain()`,
/// or the value can not be read completely, /// or the value can not be read completely,
/// this method will return `Err`. /// this method will return `Err`.
///
/// 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 read_val<T: Pod>(&mut self) -> Result<T> { pub fn read_val<T: Pod>(&mut self) -> Result<T> {
if self.remain() < core::mem::size_of::<T>() { if self.remain() < core::mem::size_of::<T>() {
return Err(Error::InvalidArgs); return Err(Error::InvalidArgs);
@ -506,12 +535,19 @@ impl<'a> VmReader<'a, UserSpace> {
let mut val = T::new_uninit(); let mut val = T::new_uninit();
let mut writer = VmWriter::from(val.as_bytes_mut()); let mut writer = VmWriter::from(val.as_bytes_mut());
self.read_fallible(&mut writer) self.read_fallible(&mut writer)
.map(|_| val) .map_err(|(err, copied_len)| {
.map_err(|err| err.0) // 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(val)
} }
} }
impl<'a, Space> VmReader<'a, Space> { impl<'a, Fallibility> VmReader<'a, Fallibility> {
/// Returns the number of bytes for the remaining data. /// Returns the number of bytes for the remaining data.
pub const fn remain(&self) -> usize { pub const fn remain(&self) -> usize {
// SAFETY: the end is equal to or greater than the cursor. // SAFETY: the end is equal to or greater than the cursor.
@ -554,7 +590,7 @@ impl<'a, Space> VmReader<'a, Space> {
} }
} }
impl<'a> From<&'a [u8]> for VmReader<'a> { impl<'a> From<&'a [u8]> for VmReader<'a, Infallible> {
fn from(slice: &'a [u8]) -> Self { fn from(slice: &'a [u8]) -> Self {
// SAFETY: // SAFETY:
// - The memory range points to typed memory. // - The memory range points to typed memory.
@ -569,9 +605,10 @@ impl<'a> From<&'a [u8]> for VmReader<'a> {
/// ///
/// The memory range write by `VmWriter` can be in either kernel space or user space. /// The memory range write by `VmWriter` can be in either kernel space or user space.
/// When the operating range is in kernel space, the memory within that range /// When the operating range is in kernel space, the memory within that range
/// is guaranteed to be valid. /// is guaranteed to be valid, and the corresponding memory writes are infallible.
/// When the operating range is in user space, it is ensured that the page table of /// When the operating range is in user space, it is ensured that the page table of
/// the process creating the `VmWriter` is active for the duration of `'a`. /// the process creating the `VmWriter` is active for the duration of `'a`,
/// and the corresponding memory writes are considered fallible.
/// ///
/// When perform writing with a `VmReader`, if one of them represents typed memory, /// When perform writing with a `VmReader`, if one of them represents typed memory,
/// it can ensure that the writing range in this writer and reading range in the /// it can ensure that the writing range in this writer and reading range in the
@ -581,13 +618,13 @@ impl<'a> From<&'a [u8]> for VmReader<'a> {
/// and physical address level. There is not guarantee for the operation results /// and physical address level. There is not guarantee for the operation results
/// of `VmReader` and `VmWriter` in overlapping untyped addresses, and it is /// of `VmReader` and `VmWriter` in overlapping untyped addresses, and it is
/// the user's responsibility to handle this situation. /// the user's responsibility to handle this situation.
pub struct VmWriter<'a, Space = KernelSpace> { pub struct VmWriter<'a, Fallibility = Fallible> {
cursor: *mut u8, cursor: *mut u8,
end: *mut u8, end: *mut u8,
phantom: PhantomData<(&'a mut [u8], Space)>, phantom: PhantomData<(&'a mut [u8], Fallibility)>,
} }
impl<'a> VmWriter<'a, KernelSpace> { impl<'a> VmWriter<'a, Infallible> {
/// Constructs a `VmWriter` from a pointer and a length, which represents /// Constructs a `VmWriter` from a pointer and a length, which represents
/// a memory range in kernel space. /// a memory range in kernel space.
/// ///
@ -614,7 +651,7 @@ impl<'a> VmWriter<'a, KernelSpace> {
/// 2. The writer has no available space. /// 2. The writer has no available space.
/// ///
/// Returns the number of bytes written. /// Returns the number of bytes written.
pub fn write(&mut self, reader: &mut VmReader<'_, KernelSpace>) -> usize { pub fn write(&mut self, reader: &mut VmReader<'_, Infallible>) -> usize {
reader.read(self) reader.read(self)
} }
@ -686,9 +723,17 @@ impl<'a> VmWriter<'a, KernelSpace> {
self.cursor = self.end; self.cursor = self.end;
written_num written_num
} }
/// Converts to a fallible writer.
pub fn to_fallible(self) -> VmWriter<'a, Fallible> {
// SAFETY: It is safe to transmute to a fallible writer since
// 1. the fallibility is a zero-sized marker type,
// 2. an infallible reader covers the capabilities of a fallible reader.
unsafe { core::mem::transmute(self) }
}
} }
impl<'a> VmWriter<'a, UserSpace> { impl<'a> VmWriter<'a, Fallible> {
/// Constructs a `VmWriter` from a pointer and a length, which represents /// Constructs a `VmWriter` from a pointer and a length, which represents
/// a memory range in user space. /// a memory range in user space.
/// ///
@ -713,18 +758,30 @@ impl<'a> VmWriter<'a, UserSpace> {
/// If the length of the `Pod` type exceeds `self.avail()`, /// If the length of the `Pod` type exceeds `self.avail()`,
/// or the value can not be write completely, /// or the value can not be write completely,
/// this method will return `Err`. /// this method will return `Err`.
///
/// If the memory write failed, this method will return `Err`
/// and the current writer's cursor remains pointing to
/// the original starting position.
pub fn write_val<T: Pod>(&mut self, new_val: &T) -> Result<()> { pub fn write_val<T: Pod>(&mut self, new_val: &T) -> Result<()> {
if self.avail() < core::mem::size_of::<T>() { if self.avail() < core::mem::size_of::<T>() {
return Err(Error::InvalidArgs); return Err(Error::InvalidArgs);
} }
let mut reader = VmReader::from(new_val.as_bytes()); let mut reader = VmReader::from(new_val.as_bytes());
self.write_fallible(&mut reader).map_err(|err| err.0)?; self.write_fallible(&mut reader)
.map_err(|(err, copied_len)| {
// SAFETY: The `copied_len` is the number of bytes written so far.
// So the `cursor` can be moved back to the original position.
unsafe {
self.cursor = self.cursor.sub(copied_len);
}
err
})?;
Ok(()) Ok(())
} }
} }
impl<'a, Space> VmWriter<'a, Space> { impl<'a, Fallibility> VmWriter<'a, Fallibility> {
/// Returns the number of bytes for the available space. /// Returns the number of bytes for the available space.
pub const fn avail(&self) -> usize { pub const fn avail(&self) -> usize {
// SAFETY: the end is equal to or greater than the cursor. // SAFETY: the end is equal to or greater than the cursor.
@ -767,7 +824,7 @@ impl<'a, Space> VmWriter<'a, Space> {
} }
} }
impl<'a> From<&'a mut [u8]> for VmWriter<'a> { impl<'a> From<&'a mut [u8]> for VmWriter<'a, Infallible> {
fn from(slice: &'a mut [u8]) -> Self { fn from(slice: &'a mut [u8]) -> Self {
// SAFETY: // SAFETY:
// - The memory range points to typed memory. // - The memory range points to typed memory.

View File

@ -28,7 +28,10 @@ use spin::Once;
pub use self::{ pub use self::{
dma::{Daddr, DmaCoherent, DmaDirection, DmaStream, DmaStreamSlice, HasDaddr}, dma::{Daddr, DmaCoherent, DmaDirection, DmaStream, DmaStreamSlice, HasDaddr},
frame::{options::FrameAllocOptions, Frame, Segment}, frame::{options::FrameAllocOptions, Frame, Segment},
io::{KernelSpace, PodOnce, UserSpace, VmIo, VmIoOnce, VmReader, VmWriter}, io::{
Fallible, FallibleVmRead, FallibleVmWrite, Infallible, PodOnce, VmIo, VmIoOnce, VmReader,
VmWriter,
},
page_prop::{CachePolicy, PageFlags, PageProperty}, page_prop::{CachePolicy, PageFlags, PageProperty},
vm_space::VmSpace, vm_space::VmSpace,
}; };

View File

@ -14,7 +14,7 @@ use core::ops::Range;
use spin::Once; use spin::Once;
use super::{ use super::{
io::UserSpace, io::Fallible,
kspace::KERNEL_PAGE_TABLE, kspace::KERNEL_PAGE_TABLE,
page_table::{PageTable, UserMode}, page_table::{PageTable, UserMode},
PageFlags, PageProperty, VmReader, VmWriter, PageFlags, PageProperty, VmReader, VmWriter,
@ -192,7 +192,7 @@ impl VmSpace {
/// ///
/// Returns `Err` if this `VmSpace` is not belonged to the user space of the current task /// Returns `Err` if this `VmSpace` is not belonged to the user space of the current task
/// or the `vaddr` and `len` do not represent a user space memory range. /// or the `vaddr` and `len` do not represent a user space memory range.
pub fn reader(&self, vaddr: Vaddr, len: usize) -> Result<VmReader<'_, UserSpace>> { pub fn reader(&self, vaddr: Vaddr, len: usize) -> Result<VmReader<'_, Fallible>> {
if current_page_table_paddr() != unsafe { self.pt.root_paddr() } { if current_page_table_paddr() != unsafe { self.pt.root_paddr() } {
return Err(Error::AccessDenied); return Err(Error::AccessDenied);
} }
@ -206,14 +206,14 @@ impl VmSpace {
// the `VmReader`. // the `VmReader`.
// //
// SAFETY: The memory range is in user space, as checked above. // SAFETY: The memory range is in user space, as checked above.
Ok(unsafe { VmReader::<UserSpace>::from_user_space(vaddr as *const u8, len) }) Ok(unsafe { VmReader::<Fallible>::from_user_space(vaddr as *const u8, len) })
} }
/// Creates a writer to write data into the user space. /// Creates a writer to write data into the user space.
/// ///
/// Returns `Err` if this `VmSpace` is not belonged to the user space of the current task /// Returns `Err` if this `VmSpace` is not belonged to the user space of the current task
/// or the `vaddr` and `len` do not represent a user space memory range. /// or the `vaddr` and `len` do not represent a user space memory range.
pub fn writer(&self, vaddr: Vaddr, len: usize) -> Result<VmWriter<'_, UserSpace>> { pub fn writer(&self, vaddr: Vaddr, len: usize) -> Result<VmWriter<'_, Fallible>> {
if current_page_table_paddr() != unsafe { self.pt.root_paddr() } { if current_page_table_paddr() != unsafe { self.pt.root_paddr() } {
return Err(Error::AccessDenied); return Err(Error::AccessDenied);
} }
@ -227,7 +227,7 @@ impl VmSpace {
// the `VmWriter`. // the `VmWriter`.
// //
// SAFETY: The memory range is in user space, as checked above. // SAFETY: The memory range is in user space, as checked above.
Ok(unsafe { VmWriter::<UserSpace>::from_user_space(vaddr as *mut u8, len) }) Ok(unsafe { VmWriter::<Fallible>::from_user_space(vaddr as *mut u8, len) })
} }
} }