diff --git a/kernel/aster-nix/src/device/tty/driver.rs b/kernel/aster-nix/src/device/tty/driver.rs index c8b083cec..9575df187 100644 --- a/kernel/aster-nix/src/device/tty/driver.rs +++ b/kernel/aster-nix/src/device/tty/driver.rs @@ -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); } } diff --git a/ostd/src/mm/frame/mod.rs b/ostd/src/mm/frame/mod.rs index 700dcdcb4..62a035288 100644 --- a/ostd/src/mm/frame/mod.rs +++ b/ostd/src/mm/frame/mod.rs @@ -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()) } } } diff --git a/ostd/src/mm/frame/segment.rs b/ostd/src/mm/frame/segment.rs index c49e60360..aeab21d26 100644 --- a/ostd/src/mm/frame/segment.rs +++ b/ostd/src/mm/frame/segment.rs @@ -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()) } } } diff --git a/ostd/src/mm/io.rs b/ostd/src/mm/io.rs index cb0cb88c5..3f56dba97 100644 --- a/ostd/src/mm/io.rs +++ b/ostd/src/mm/io.rs @@ -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, "(**self)"); impl_vmio_pointer!(Arc, "(**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; + +/// 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 +/// +/// - 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); } -impl<'a> VmReader<'a> { - /// Constructs a VmReader from a pointer and a length. +/// 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 { + 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 { + 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 /// - /// 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 { + /// 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(&mut self) -> Result { + if self.remain() < core::mem::size_of::() { + 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(&mut self) -> Result { + if self.remain() < core::mem::size_of::() { + 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. @@ -208,7 +434,7 @@ impl<'a> VmReader<'a> { /// Limits the length of remaining data. /// - /// This method ensures the postcondition of `self.remain() <= max_remain`. + /// This method ensures the post condition of `self.remain() <= max_remain`. pub const fn limit(mut self, max_remain: usize) -> Self { if max_remain < self.remain() { // SAFETY: the new end is less than the old end. @@ -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(&mut self) -> T { - assert!(self.remain() >= core::mem::size_of::()); - - 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. + pub fn write(&mut self, reader: &mut VmReader<'_, KernelSpace>) -> usize { + reader.read(self) + } + + /// Writes a value of `Pod` type. /// - /// 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; + /// If the length of the `Pod` type exceeds `self.avail()`, + /// this method will return `Err`. + pub fn write_val(&mut self, new_val: &T) -> Result<()> { + if self.avail() < core::mem::size_of::() { + return Err(Error::InvalidArgs); } - // 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); - } - 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> 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()) } +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(&mut self, new_val: &T) -> Result<()> { + if self.avail() < core::mem::size_of::() { + 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`, 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()) } } } diff --git a/ostd/src/mm/mod.rs b/ostd/src/mm/mod.rs index 906898253..ab7f995a0 100644 --- a/ostd/src/mm/mod.rs +++ b/ostd/src/mm/mod.rs @@ -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}, };