mirror of
https://github.com/asterinas/asterinas.git
synced 2025-06-23 17:33:23 +00:00
Refactor VmReader/Writer to support both kernel space and user space
This commit is contained in:
committed by
Tate, Hongliang Tian
parent
994427c71a
commit
09b6153d29
@ -82,7 +82,7 @@ impl Default for TtyDriver {
|
||||
fn console_input_callback(mut reader: VmReader) {
|
||||
let tty_driver = get_tty_driver();
|
||||
while reader.remain() > 0 {
|
||||
let ch = reader.read_val();
|
||||
let ch = reader.read_val().unwrap();
|
||||
tty_driver.push_char(ch);
|
||||
}
|
||||
}
|
||||
|
@ -114,14 +114,20 @@ impl HasPaddr for Frame {
|
||||
impl<'a> Frame {
|
||||
/// Returns a reader to read data from it.
|
||||
pub fn reader(&'a self) -> VmReader<'a> {
|
||||
// SAFETY: the memory of the page is contiguous and is valid during `'a`.
|
||||
unsafe { VmReader::from_raw_parts(self.as_ptr(), self.size()) }
|
||||
// SAFETY: the memory of the page is untyped, contiguous and is valid during `'a`.
|
||||
// Currently, only slice can generate `VmWriter` with typed memory, and this `Frame` cannot
|
||||
// generate or be generated from an alias slice, so the reader will not overlap with `VmWriter`
|
||||
// with typed memory.
|
||||
unsafe { VmReader::from_kernel_space(self.as_ptr(), self.size()) }
|
||||
}
|
||||
|
||||
/// Returns a writer to write data into it.
|
||||
pub fn writer(&'a self) -> VmWriter<'a> {
|
||||
// SAFETY: the memory of the page is contiguous and is valid during `'a`.
|
||||
unsafe { VmWriter::from_raw_parts_mut(self.as_mut_ptr(), self.size()) }
|
||||
// SAFETY: the memory of the page is untyped, contiguous and is valid during `'a`.
|
||||
// Currently, only slice can generate `VmReader` with typed memory, and this `Frame` cannot
|
||||
// generate or be generated from an alias slice, so the writer will not overlap with `VmReader`
|
||||
// with typed memory.
|
||||
unsafe { VmWriter::from_kernel_space(self.as_mut_ptr(), self.size()) }
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -101,14 +101,20 @@ impl Segment {
|
||||
impl<'a> Segment {
|
||||
/// Returns a reader to read data from it.
|
||||
pub fn reader(&'a self) -> VmReader<'a> {
|
||||
// SAFETY: the memory of the page frames is contiguous and is valid during `'a`.
|
||||
unsafe { VmReader::from_raw_parts(self.as_ptr(), self.nbytes()) }
|
||||
// SAFETY: the memory of the page frames is untyped, contiguous and is valid during `'a`.
|
||||
// Currently, only slice can generate `VmWriter` with typed memory, and this `Segment` cannot
|
||||
// generate or be generated from an alias slice, so the reader will not overlap with `VmWriter`
|
||||
// with typed memory.
|
||||
unsafe { VmReader::from_kernel_space(self.as_ptr(), self.nbytes()) }
|
||||
}
|
||||
|
||||
/// Returns a writer to write data into it.
|
||||
pub fn writer(&'a self) -> VmWriter<'a> {
|
||||
// SAFETY: the memory of the page frames is contiguous and is valid during `'a`.
|
||||
unsafe { VmWriter::from_raw_parts_mut(self.as_mut_ptr(), self.nbytes()) }
|
||||
// SAFETY: the memory of the page frames is untyped, contiguous and is valid during `'a`.
|
||||
// Currently, only slice can generate `VmReader` with typed memory, and this `Segment` cannot
|
||||
// generate or be generated from an alias slice, so the writer will not overlap with `VmReader`
|
||||
// with typed memory.
|
||||
unsafe { VmWriter::from_kernel_space(self.as_mut_ptr(), self.nbytes()) }
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -8,7 +8,15 @@ use align_ext::AlignExt;
|
||||
use inherit_methods_macro::inherit_methods;
|
||||
use pod::Pod;
|
||||
|
||||
use crate::prelude::*;
|
||||
use crate::{
|
||||
arch::mm::__memcpy_fallible,
|
||||
mm::{
|
||||
kspace::{KERNEL_BASE_VADDR, KERNEL_END_VADDR},
|
||||
MAX_USERSPACE_VADDR,
|
||||
},
|
||||
prelude::*,
|
||||
Error,
|
||||
};
|
||||
|
||||
/// A trait that enables reading/writing data from/to a VM object,
|
||||
/// e.g., [`VmSpace`], [`FrameVec`], and [`Frame`].
|
||||
@ -168,21 +176,160 @@ impl_vmio_pointer!(&mut T, "(**self)");
|
||||
impl_vmio_pointer!(Box<T>, "(**self)");
|
||||
impl_vmio_pointer!(Arc<T>, "(**self)");
|
||||
|
||||
/// VmReader is a reader for reading data from a contiguous range of memory.
|
||||
pub struct VmReader<'a> {
|
||||
cursor: *const u8,
|
||||
end: *const u8,
|
||||
phantom: PhantomData<&'a [u8]>,
|
||||
}
|
||||
/// A marker structure used for [`VmReader`] and [`VmWriter`],
|
||||
/// representing their operated memory scope is in user space.
|
||||
pub struct UserSpace;
|
||||
|
||||
impl<'a> VmReader<'a> {
|
||||
/// Constructs a VmReader from a pointer and a length.
|
||||
/// A marker structure used for [`VmReader`] and [`VmWriter`],
|
||||
/// representing their operated memory scope is in kernel space.
|
||||
pub struct KernelSpace;
|
||||
|
||||
/// Copies `len` bytes from `src` to `dst`.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// User must ensure the memory from `ptr` to `ptr.add(len)` is contiguous.
|
||||
/// User must ensure the memory is valid during the entire period of `'a`.
|
||||
pub const unsafe fn from_raw_parts(ptr: *const u8, len: usize) -> Self {
|
||||
/// - Mappings of virtual memory range [`src`..`src` + len] and [`dst`..`dst` + len]
|
||||
/// must be [valid].
|
||||
/// - If one of the memory represents typed memory, these two virtual
|
||||
/// memory ranges and their corresponding physical pages should _not_ overlap.
|
||||
///
|
||||
/// Operation on typed memory may be safe only if it is plain-old-data. Otherwise
|
||||
/// the safety requirements of [`core::ptr::copy`] should also be considered.
|
||||
///
|
||||
/// [valid]: core::ptr#safety
|
||||
unsafe fn memcpy(src: *const u8, dst: *mut u8, len: usize) {
|
||||
core::ptr::copy(src, dst, len);
|
||||
}
|
||||
|
||||
/// Copies `len` bytes from `src` to `dst`.
|
||||
/// This function will early stop copying if encountering an unresolvable page fault.
|
||||
///
|
||||
/// Returns the number of successfully copied bytes.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// - Users should ensure one of [`src`..`src` + len] and [`dst`..`dst` + len]
|
||||
/// is in user space, and the other virtual memory range is in kernel space
|
||||
/// and is ensured to be [valid].
|
||||
/// - Users should ensure this function only be invoked when a suitable page
|
||||
/// table is activated.
|
||||
/// - The underlying physical memory range of [`src`..`src` + len] and [`dst`..`dst` + len]
|
||||
/// should _not_ overlap if the kernel space memory represent typed memory.
|
||||
///
|
||||
/// [valid]: core::ptr#safety
|
||||
unsafe fn memcpy_fallible(src: *const u8, dst: *mut u8, len: usize) -> usize {
|
||||
let failed_bytes = __memcpy_fallible(dst, src, len);
|
||||
len - failed_bytes
|
||||
}
|
||||
|
||||
/// `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.
|
||||
/// When the operating range is in kernel space, the memory within that range
|
||||
/// is guaranteed to be valid.
|
||||
/// 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`.
|
||||
///
|
||||
/// 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
|
||||
/// writer are not overlapped.
|
||||
///
|
||||
/// NOTE: The overlap mentioned above is at both the virtual address level
|
||||
/// and physical address level. There is not guarantee for the operation results
|
||||
/// of `VmReader` and `VmWriter` in overlapping untyped addresses, and it is
|
||||
/// the user's responsibility to handle this situation.
|
||||
pub struct VmReader<'a, Space = KernelSpace> {
|
||||
cursor: *const u8,
|
||||
end: *const u8,
|
||||
phantom: PhantomData<(&'a [u8], Space)>,
|
||||
}
|
||||
|
||||
macro_rules! impl_read_fallible {
|
||||
($read_space:ty, $write_space:ty) => {
|
||||
impl<'a> VmReader<'a, $read_space> {
|
||||
/// 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.
|
||||
pub fn read_fallible(
|
||||
&mut self,
|
||||
writer: &mut VmWriter<'_, $write_space>,
|
||||
) -> core::result::Result<usize, (Error, usize)> {
|
||||
let copy_len = self.remain().min(writer.avail());
|
||||
if copy_len == 0 {
|
||||
return Ok(0);
|
||||
}
|
||||
|
||||
// SAFETY: This method is only implemented when one of the operated
|
||||
// `VmReader` or `VmWriter` is in user space.
|
||||
// The the corresponding page table of the user space memory is
|
||||
// guaranteed to be activated due to its construction requirement.
|
||||
// The kernel space memory range will be valid since `copy_len` is the minimum
|
||||
// of the reader's remaining data and the writer's available space, and will
|
||||
// not overlap with user space memory range in physical address level if it
|
||||
// represents typed memory.
|
||||
let copied_len = unsafe {
|
||||
let copied_len = memcpy_fallible(self.cursor, writer.cursor, copy_len);
|
||||
self.cursor = self.cursor.add(copied_len);
|
||||
writer.cursor = writer.cursor.add(copied_len);
|
||||
copied_len
|
||||
};
|
||||
if copied_len < copy_len {
|
||||
Err((Error::PageFault, copied_len))
|
||||
} else {
|
||||
Ok(copied_len)
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! impl_write_fallible {
|
||||
($read_space:ty, $write_space:ty) => {
|
||||
impl<'a> VmWriter<'a, $write_space> {
|
||||
/// 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.
|
||||
pub fn write_fallible(
|
||||
&mut self,
|
||||
reader: &mut VmReader<'_, $read_space>,
|
||||
) -> core::result::Result<usize, (Error, usize)> {
|
||||
reader.read_fallible(self)
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// TODO: implement an additional function `memcpy_nonoverlapping_fallible`
|
||||
// to implement read/write instruction from user space to user space.
|
||||
impl_read_fallible!(UserSpace, KernelSpace);
|
||||
impl_read_fallible!(KernelSpace, UserSpace);
|
||||
impl_write_fallible!(UserSpace, KernelSpace);
|
||||
impl_write_fallible!(KernelSpace, UserSpace);
|
||||
|
||||
impl<'a> VmReader<'a, KernelSpace> {
|
||||
/// Constructs a `VmReader` from a pointer and a length, which represents
|
||||
/// a memory range in kernel space.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// Users must ensure the memory from `ptr` to `ptr.add(len)` is contiguous.
|
||||
/// Users must ensure the memory is valid during the entire period of `'a`.
|
||||
/// Users must ensure the memory should _not_ overlap with other `VmWriter`s
|
||||
/// with typed memory, and if the memory range in this `VmReader` is typed,
|
||||
/// it should _not_ overlap with other `VmWriter`s.
|
||||
/// The user space memory is treated as untyped.
|
||||
pub unsafe fn from_kernel_space(ptr: *const u8, len: usize) -> Self {
|
||||
debug_assert!(KERNEL_BASE_VADDR <= ptr as usize);
|
||||
debug_assert!(ptr.add(len) as usize <= KERNEL_END_VADDR);
|
||||
|
||||
Self {
|
||||
cursor: ptr,
|
||||
end: ptr.add(len),
|
||||
@ -190,6 +337,85 @@ impl<'a> VmReader<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Reads all data into the writer until one of the two conditions is met:
|
||||
/// 1. The reader has no remaining data.
|
||||
/// 2. The writer has no available space.
|
||||
///
|
||||
/// Returns the number of bytes read.
|
||||
pub fn read(&mut self, writer: &mut VmWriter<'_, KernelSpace>) -> usize {
|
||||
let copy_len = self.remain().min(writer.avail());
|
||||
if copy_len == 0 {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// SAFETY: the reading memory range and writing memory range will be valid
|
||||
// since `copy_len` is the minimum of the reader's remaining data and the
|
||||
// writer's available space, and will not overlap if one of them represents
|
||||
// typed memory.
|
||||
unsafe {
|
||||
memcpy(self.cursor, writer.cursor, copy_len);
|
||||
self.cursor = self.cursor.add(copy_len);
|
||||
writer.cursor = writer.cursor.add(copy_len);
|
||||
}
|
||||
|
||||
copy_len
|
||||
}
|
||||
|
||||
/// Reads a value of `Pod` type.
|
||||
///
|
||||
/// If the length of the `Pod` type exceeds `self.remain()`,
|
||||
/// this method will return `Err`.
|
||||
pub fn read_val<T: Pod>(&mut self) -> Result<T> {
|
||||
if self.remain() < core::mem::size_of::<T>() {
|
||||
return Err(Error::InvalidArgs);
|
||||
}
|
||||
|
||||
let mut val = T::new_uninit();
|
||||
let mut writer = VmWriter::from(val.as_bytes_mut());
|
||||
|
||||
self.read(&mut writer);
|
||||
Ok(val)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> VmReader<'a, UserSpace> {
|
||||
/// Constructs a `VmReader` from a pointer and a length, which represents
|
||||
/// a memory range in user space.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// Users must ensure the memory from `ptr` to `ptr.add(len)` is contiguous.
|
||||
/// Users must ensure that the page table for the process in which this constructor is called
|
||||
/// are active during the entire period of `'a`.
|
||||
pub unsafe fn from_user_space(ptr: *const u8, len: usize) -> Self {
|
||||
debug_assert!((ptr as usize).checked_add(len).unwrap_or(usize::MAX) <= MAX_USERSPACE_VADDR);
|
||||
|
||||
Self {
|
||||
cursor: ptr,
|
||||
end: ptr.add(len),
|
||||
phantom: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
/// Reads a value of `Pod` type.
|
||||
///
|
||||
/// If the length of the `Pod` type exceeds `self.remain()`,
|
||||
/// or the value can not be read completely,
|
||||
/// this method will return `Err`.
|
||||
pub fn read_val<T: Pod>(&mut self) -> Result<T> {
|
||||
if self.remain() < core::mem::size_of::<T>() {
|
||||
return Err(Error::InvalidArgs);
|
||||
}
|
||||
|
||||
let mut val = T::new_uninit();
|
||||
let mut writer = VmWriter::from(val.as_bytes_mut());
|
||||
self.read_fallible(&mut writer)
|
||||
.map(|_| val)
|
||||
.map_err(|err| err.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, Space> VmReader<'a, Space> {
|
||||
/// Returns the number of bytes for the remaining data.
|
||||
pub const fn remain(&self) -> usize {
|
||||
// SAFETY: the end is equal to or greater than the cursor.
|
||||
@ -230,69 +456,56 @@ impl<'a> VmReader<'a> {
|
||||
unsafe { self.cursor = self.cursor.add(nbytes) };
|
||||
self
|
||||
}
|
||||
|
||||
/// Reads all data into the writer until one of the two conditions is met:
|
||||
/// 1. The reader has no remaining data.
|
||||
/// 2. The writer has no available space.
|
||||
///
|
||||
/// Returns the number of bytes read.
|
||||
///
|
||||
/// It pulls the number of bytes data from the reader and
|
||||
/// fills in the writer with the number of bytes.
|
||||
pub fn read(&mut self, writer: &mut VmWriter<'_>) -> usize {
|
||||
let copy_len = self.remain().min(writer.avail());
|
||||
if copy_len == 0 {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// SAFETY: the memory range is valid since `copy_len` is the minimum
|
||||
// of the reader's remaining data and the writer's available space.
|
||||
unsafe {
|
||||
core::ptr::copy(self.cursor, writer.cursor, copy_len);
|
||||
self.cursor = self.cursor.add(copy_len);
|
||||
writer.cursor = writer.cursor.add(copy_len);
|
||||
}
|
||||
copy_len
|
||||
}
|
||||
|
||||
/// Read a value of `Pod` type.
|
||||
///
|
||||
/// # Panic
|
||||
///
|
||||
/// If the length of the `Pod` type exceeds `self.remain()`, then this method will panic.
|
||||
pub fn read_val<T: Pod>(&mut self) -> T {
|
||||
assert!(self.remain() >= core::mem::size_of::<T>());
|
||||
|
||||
let mut val = T::new_uninit();
|
||||
let mut writer = VmWriter::from(val.as_bytes_mut());
|
||||
let read_len = self.read(&mut writer);
|
||||
|
||||
val
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> From<&'a [u8]> for VmReader<'a> {
|
||||
fn from(slice: &'a [u8]) -> Self {
|
||||
// SAFETY: the range of memory is contiguous and is valid during `'a`.
|
||||
unsafe { Self::from_raw_parts(slice.as_ptr(), slice.len()) }
|
||||
// SAFETY: the range of memory is contiguous and is valid during `'a`,
|
||||
// and will not overlap with other `VmWriter` since the slice already has
|
||||
// an immutable reference. The slice will not be mapped to the user space hence
|
||||
// it will also not overlap with `VmWriter` generated from user space.
|
||||
unsafe { Self::from_kernel_space(slice.as_ptr(), slice.len()) }
|
||||
}
|
||||
}
|
||||
|
||||
/// VmWriter is a writer for writing data to a contiguous range of memory.
|
||||
pub struct VmWriter<'a> {
|
||||
/// `VmWriter` is a writer for writing data to a contiguous range of memory.
|
||||
///
|
||||
/// 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
|
||||
/// is guaranteed to be valid.
|
||||
/// 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`.
|
||||
///
|
||||
/// 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
|
||||
/// reader are not overlapped.
|
||||
///
|
||||
/// NOTE: The overlap mentioned above is at both the virtual address level
|
||||
/// and physical address level. There is not guarantee for the operation results
|
||||
/// of `VmReader` and `VmWriter` in overlapping untyped addresses, and it is
|
||||
/// the user's responsibility to handle this situation.
|
||||
pub struct VmWriter<'a, Space = KernelSpace> {
|
||||
cursor: *mut u8,
|
||||
end: *mut u8,
|
||||
phantom: PhantomData<&'a mut [u8]>,
|
||||
phantom: PhantomData<(&'a mut [u8], Space)>,
|
||||
}
|
||||
|
||||
impl<'a> VmWriter<'a> {
|
||||
/// Constructs a VmWriter from a pointer and a length.
|
||||
impl<'a> VmWriter<'a, KernelSpace> {
|
||||
/// Constructs a `VmWriter` from a pointer and a length, which represents
|
||||
/// a memory range in kernel space.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// User must ensure the memory from `ptr` to `ptr.add(len)` is contiguous.
|
||||
/// User must ensure the memory is valid during the entire period of `'a`.
|
||||
pub const unsafe fn from_raw_parts_mut(ptr: *mut u8, len: usize) -> Self {
|
||||
/// Users must ensure the memory from `ptr` to `ptr.add(len)` is contiguous.
|
||||
/// Users must ensure the memory is valid during the entire period of `'a`.
|
||||
/// Users must ensure the memory should _not_ overlap with other `VmWriter`s
|
||||
/// and `VmReader`s with typed memory, and if the memory range in this `VmWriter`
|
||||
/// is typed, it should _not_ overlap with other `VmReader`s and `VmWriter`s.
|
||||
/// The user space memory is treated as untyped.
|
||||
pub unsafe fn from_kernel_space(ptr: *mut u8, len: usize) -> Self {
|
||||
debug_assert!(KERNEL_BASE_VADDR <= ptr as usize);
|
||||
debug_assert!(ptr.add(len) as usize <= KERNEL_END_VADDR);
|
||||
|
||||
Self {
|
||||
cursor: ptr,
|
||||
end: ptr.add(len),
|
||||
@ -300,69 +513,27 @@ impl<'a> VmWriter<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the number of bytes for the available space.
|
||||
pub const fn avail(&self) -> usize {
|
||||
// SAFETY: the end is equal to or greater than the cursor.
|
||||
unsafe { self.end.sub_ptr(self.cursor) }
|
||||
}
|
||||
|
||||
/// Returns the cursor pointer, which refers to the address of the next byte to write.
|
||||
pub const fn cursor(&self) -> *mut u8 {
|
||||
self.cursor
|
||||
}
|
||||
|
||||
/// Returns if it has avaliable space to write.
|
||||
pub const fn has_avail(&self) -> bool {
|
||||
self.avail() > 0
|
||||
}
|
||||
|
||||
/// Limits the length of available space.
|
||||
///
|
||||
/// This method ensures the postcondition of `self.avail() <= max_avail`.
|
||||
pub const fn limit(mut self, max_avail: usize) -> Self {
|
||||
if max_avail < self.avail() {
|
||||
// SAFETY: the new end is less than the old end.
|
||||
unsafe { self.end = self.cursor.add(max_avail) };
|
||||
}
|
||||
self
|
||||
}
|
||||
|
||||
/// Skips the first `nbytes` bytes of data.
|
||||
/// The length of available space is decreased accordingly.
|
||||
///
|
||||
/// # Panic
|
||||
///
|
||||
/// If `nbytes` is greater than `self.avail()`, then the method panics.
|
||||
pub fn skip(mut self, nbytes: usize) -> Self {
|
||||
assert!(nbytes <= self.avail());
|
||||
|
||||
// SAFETY: the new cursor is less than or equal to the end.
|
||||
unsafe { self.cursor = self.cursor.add(nbytes) };
|
||||
self
|
||||
}
|
||||
|
||||
/// Writes data from the reader until one of the two conditions is met:
|
||||
/// 1. The writer has no available space.
|
||||
/// 2. The reader has no remaining data.
|
||||
/// Writes all data from the reader until one of the two conditions is met:
|
||||
/// 1. The reader has no remaining data.
|
||||
/// 2. The writer has no available space.
|
||||
///
|
||||
/// Returns the number of bytes written.
|
||||
///
|
||||
/// It pulls the number of bytes data from the reader and
|
||||
/// fills in the writer with the number of bytes.
|
||||
pub fn write(&mut self, reader: &mut VmReader<'_>) -> usize {
|
||||
let copy_len = self.avail().min(reader.remain());
|
||||
if copy_len == 0 {
|
||||
return 0;
|
||||
pub fn write(&mut self, reader: &mut VmReader<'_, KernelSpace>) -> usize {
|
||||
reader.read(self)
|
||||
}
|
||||
|
||||
// SAFETY: the memory range is valid since `copy_len` is the minimum
|
||||
// of the reader's remaining data and the writer's available space.
|
||||
unsafe {
|
||||
core::ptr::copy(reader.cursor, self.cursor, copy_len);
|
||||
self.cursor = self.cursor.add(copy_len);
|
||||
reader.cursor = reader.cursor.add(copy_len);
|
||||
/// Writes a value of `Pod` type.
|
||||
///
|
||||
/// If the length of the `Pod` type exceeds `self.avail()`,
|
||||
/// this method will return `Err`.
|
||||
pub fn write_val<T: Pod>(&mut self, new_val: &T) -> Result<()> {
|
||||
if self.avail() < core::mem::size_of::<T>() {
|
||||
return Err(Error::InvalidArgs);
|
||||
}
|
||||
copy_len
|
||||
|
||||
let mut reader = VmReader::from(new_val.as_bytes());
|
||||
self.write(&mut reader);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Fills the available space by repeating `value`.
|
||||
@ -396,9 +567,91 @@ impl<'a> VmWriter<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> VmWriter<'a, UserSpace> {
|
||||
/// Constructs a `VmWriter` from a pointer and a length, which represents
|
||||
/// a memory range in user space.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// Users must ensure the memory from `ptr` to `ptr.add(len)` is contiguous.
|
||||
/// Users must ensure that the page table for the process in which this constructor is called
|
||||
/// are active during the entire period of `'a`.
|
||||
pub unsafe fn from_user_space(ptr: *mut u8, len: usize) -> Self {
|
||||
debug_assert!((ptr as usize).checked_add(len).unwrap_or(usize::MAX) <= MAX_USERSPACE_VADDR);
|
||||
|
||||
Self {
|
||||
cursor: ptr,
|
||||
end: ptr.add(len),
|
||||
phantom: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
/// Writes a value of `Pod` type.
|
||||
///
|
||||
/// If the length of the `Pod` type exceeds `self.avail()`,
|
||||
/// or the value can not be write completely,
|
||||
/// this method will return `Err`.
|
||||
pub fn write_val<T: Pod>(&mut self, new_val: &T) -> Result<()> {
|
||||
if self.avail() < core::mem::size_of::<T>() {
|
||||
return Err(Error::InvalidArgs);
|
||||
}
|
||||
|
||||
let mut reader = VmReader::from(new_val.as_bytes());
|
||||
self.write_fallible(&mut reader).map_err(|err| err.0)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, Space> VmWriter<'a, Space> {
|
||||
/// Returns the number of bytes for the available space.
|
||||
pub const fn avail(&self) -> usize {
|
||||
// SAFETY: the end is equal to or greater than the cursor.
|
||||
unsafe { self.end.sub_ptr(self.cursor) }
|
||||
}
|
||||
|
||||
/// Returns the cursor pointer, which refers to the address of the next byte to write.
|
||||
pub const fn cursor(&self) -> *mut u8 {
|
||||
self.cursor
|
||||
}
|
||||
|
||||
/// Returns if it has available space to write.
|
||||
pub const fn has_avail(&self) -> bool {
|
||||
self.avail() > 0
|
||||
}
|
||||
|
||||
/// Limits the length of available space.
|
||||
///
|
||||
/// This method ensures the post condition of `self.avail() <= max_avail`.
|
||||
pub const fn limit(mut self, max_avail: usize) -> Self {
|
||||
if max_avail < self.avail() {
|
||||
// SAFETY: the new end is less than the old end.
|
||||
unsafe { self.end = self.cursor.add(max_avail) };
|
||||
}
|
||||
self
|
||||
}
|
||||
|
||||
/// Skips the first `nbytes` bytes of data.
|
||||
/// The length of available space is decreased accordingly.
|
||||
///
|
||||
/// # Panic
|
||||
///
|
||||
/// If `nbytes` is greater than `self.avail()`, then the method panics.
|
||||
pub fn skip(mut self, nbytes: usize) -> Self {
|
||||
assert!(nbytes <= self.avail());
|
||||
|
||||
// SAFETY: the new cursor is less than or equal to the end.
|
||||
unsafe { self.cursor = self.cursor.add(nbytes) };
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> From<&'a mut [u8]> for VmWriter<'a> {
|
||||
fn from(slice: &'a mut [u8]) -> Self {
|
||||
// SAFETY: the range of memory is contiguous and is valid during `'a`.
|
||||
unsafe { Self::from_raw_parts_mut(slice.as_mut_ptr(), slice.len()) }
|
||||
// SAFETY: the range of memory is contiguous and is valid during `'a`, and
|
||||
// will not overlap with other `VmWriter`s and `VmReader`s since the slice
|
||||
// already has an mutable reference. The slice will not be mapped to the user
|
||||
// space hence it will also not overlap with `VmWriter`s and `VmReader`s
|
||||
// generated from user space.
|
||||
unsafe { Self::from_kernel_space(slice.as_mut_ptr(), slice.len()) }
|
||||
}
|
||||
}
|
||||
|
@ -27,7 +27,7 @@ use spin::Once;
|
||||
pub use self::{
|
||||
dma::{Daddr, DmaCoherent, DmaDirection, DmaStream, DmaStreamSlice, HasDaddr},
|
||||
frame::{options::FrameAllocOptions, Frame, FrameVec, FrameVecIter, Segment},
|
||||
io::{VmIo, VmReader, VmWriter},
|
||||
io::{KernelSpace, UserSpace, VmIo, VmReader, VmWriter},
|
||||
page_prop::{CachePolicy, PageFlags, PageProperty},
|
||||
space::{VmMapOptions, VmSpace},
|
||||
};
|
||||
|
Reference in New Issue
Block a user