2024-08-04 06:37:50 +00:00
|
|
|
// SPDX-License-Identifier: MPL-2.0
|
|
|
|
|
|
|
|
|
|
//! The context that can be accessed from the current task, thread or process.
|
|
|
|
|
|
2025-03-17 02:53:56 +00:00
|
|
|
use core::{cell::Ref, mem};
|
2024-08-04 06:37:50 +00:00
|
|
|
|
2025-03-17 02:53:56 +00:00
|
|
|
use aster_rights::Full;
|
2024-08-04 06:37:50 +00:00
|
|
|
use ostd::{
|
2025-07-31 14:39:36 +00:00
|
|
|
mm::{Fallible, Infallible, PodAtomic, VmReader, VmWriter, MAX_USERSPACE_VADDR},
|
2025-07-31 15:52:45 +00:00
|
|
|
task::Task,
|
2024-08-04 06:37:50 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
use crate::{
|
|
|
|
|
prelude::*,
|
2024-12-01 01:19:03 +00:00
|
|
|
process::{
|
|
|
|
|
posix_thread::{PosixThread, ThreadLocal},
|
|
|
|
|
Process,
|
|
|
|
|
},
|
2024-08-04 06:37:50 +00:00
|
|
|
thread::Thread,
|
2025-04-09 06:36:21 +00:00
|
|
|
util::{MultiRead, VmReaderArray},
|
2025-03-17 02:53:56 +00:00
|
|
|
vm::vmar::Vmar,
|
2024-08-04 06:37:50 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/// The context that can be accessed from the current POSIX thread.
|
2024-08-30 09:12:07 +00:00
|
|
|
#[derive(Clone)]
|
2024-08-04 06:37:50 +00:00
|
|
|
pub struct Context<'a> {
|
|
|
|
|
pub process: &'a Process,
|
2024-12-01 01:19:03 +00:00
|
|
|
pub thread_local: &'a ThreadLocal,
|
2024-08-04 06:37:50 +00:00
|
|
|
pub posix_thread: &'a PosixThread,
|
|
|
|
|
pub thread: &'a Thread,
|
|
|
|
|
pub task: &'a Task,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl Context<'_> {
|
|
|
|
|
/// Gets the userspace of the current task.
|
2024-11-13 15:39:10 +00:00
|
|
|
pub fn user_space(&self) -> CurrentUserSpace {
|
2025-03-17 02:53:56 +00:00
|
|
|
CurrentUserSpace(self.thread_local.root_vmar().borrow())
|
2024-08-04 06:37:50 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// The user's memory space of the current task.
|
|
|
|
|
///
|
|
|
|
|
/// It provides methods to read from or write to the user space efficiently.
|
2025-03-17 02:53:56 +00:00
|
|
|
pub struct CurrentUserSpace<'a>(Ref<'a, Option<Vmar<Full>>>);
|
2024-08-04 06:37:50 +00:00
|
|
|
|
2024-08-30 09:12:07 +00:00
|
|
|
/// Gets the [`CurrentUserSpace`] from the current task.
|
|
|
|
|
///
|
2024-11-13 15:39:10 +00:00
|
|
|
/// This is slower than [`Context::user_space`]. Don't use this getter
|
2024-08-30 09:12:07 +00:00
|
|
|
/// If you get the access to the [`Context`].
|
|
|
|
|
#[macro_export]
|
2024-11-14 11:46:20 +00:00
|
|
|
macro_rules! current_userspace {
|
2025-04-19 14:59:12 +00:00
|
|
|
() => {{
|
2025-07-31 15:52:45 +00:00
|
|
|
use $crate::{context::CurrentUserSpace, process::posix_thread::AsThreadLocal};
|
|
|
|
|
CurrentUserSpace::new(
|
|
|
|
|
ostd::task::Task::current()
|
|
|
|
|
.unwrap()
|
|
|
|
|
.as_thread_local()
|
|
|
|
|
.unwrap(),
|
|
|
|
|
)
|
2025-04-19 14:59:12 +00:00
|
|
|
}};
|
2024-08-30 09:12:07 +00:00
|
|
|
}
|
2024-08-04 06:37:50 +00:00
|
|
|
|
2024-08-30 09:12:07 +00:00
|
|
|
impl<'a> CurrentUserSpace<'a> {
|
2025-03-17 02:53:56 +00:00
|
|
|
/// Creates a new `CurrentUserSpace` from the current task.
|
2024-08-30 09:12:07 +00:00
|
|
|
///
|
2024-11-13 15:39:10 +00:00
|
|
|
/// If you have access to a [`Context`], it is preferable to call [`Context::user_space`].
|
2024-08-30 09:12:07 +00:00
|
|
|
///
|
2024-11-14 11:46:20 +00:00
|
|
|
/// Otherwise, you can use the `current_userspace` macro
|
2024-08-30 09:12:07 +00:00
|
|
|
/// to obtain an instance of `CurrentUserSpace` if it will only be used once.
|
2025-07-31 15:52:45 +00:00
|
|
|
pub fn new(thread_local: &'a ThreadLocal) -> Self {
|
2025-03-17 02:53:56 +00:00
|
|
|
let vmar_ref = thread_local.root_vmar().borrow();
|
|
|
|
|
Self(vmar_ref)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Returns the root `Vmar` of the current userspace.
|
2024-08-30 09:12:07 +00:00
|
|
|
///
|
|
|
|
|
/// # Panics
|
2024-08-04 06:37:50 +00:00
|
|
|
///
|
2025-03-17 02:53:56 +00:00
|
|
|
/// This method will panic if the current process has cleared its `Vmar`.
|
|
|
|
|
pub fn root_vmar(&self) -> &Vmar<Full> {
|
|
|
|
|
self.0.as_ref().unwrap()
|
2024-08-04 06:37:50 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// 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.
|
2024-08-20 02:05:25 +00:00
|
|
|
pub fn reader(&self, vaddr: Vaddr, len: usize) -> Result<VmReader<'_, Fallible>> {
|
2025-03-17 02:53:56 +00:00
|
|
|
Ok(self.root_vmar().vm_space().reader(vaddr, len)?)
|
2024-08-04 06:37:50 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// 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.
|
2024-08-20 02:05:25 +00:00
|
|
|
pub fn writer(&self, vaddr: Vaddr, len: usize) -> Result<VmWriter<'_, Fallible>> {
|
2025-03-17 02:53:56 +00:00
|
|
|
Ok(self.root_vmar().vm_space().writer(vaddr, len)?)
|
2024-08-04 06:37:50 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Reads bytes into the destination `VmWriter` from the user space of the
|
|
|
|
|
/// current process.
|
|
|
|
|
///
|
|
|
|
|
/// If the reading is completely successful, returns `Ok`. Otherwise, it
|
|
|
|
|
/// returns `Err`.
|
|
|
|
|
///
|
|
|
|
|
/// If the destination `VmWriter` (`dest`) is empty, this function still
|
|
|
|
|
/// checks if the current task and user space are available. If they are,
|
|
|
|
|
/// it returns `Ok`.
|
2024-08-20 02:05:25 +00:00
|
|
|
pub fn read_bytes(&self, src: Vaddr, dest: &mut VmWriter<'_, Infallible>) -> Result<()> {
|
2024-08-04 06:37:50 +00:00
|
|
|
let copy_len = dest.avail();
|
|
|
|
|
|
|
|
|
|
if copy_len > 0 {
|
|
|
|
|
check_vaddr(src)?;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
let mut user_reader = self.reader(src, copy_len)?;
|
|
|
|
|
user_reader.read_fallible(dest).map_err(|err| err.0)?;
|
|
|
|
|
Ok(())
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Reads a value typed `Pod` from the user space of the current process.
|
|
|
|
|
pub fn read_val<T: Pod>(&self, src: Vaddr) -> Result<T> {
|
|
|
|
|
if core::mem::size_of::<T>() > 0 {
|
|
|
|
|
check_vaddr(src)?;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
let mut user_reader = self.reader(src, core::mem::size_of::<T>())?;
|
|
|
|
|
Ok(user_reader.read_val()?)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Writes bytes from the source `VmReader` to the user space of the current
|
|
|
|
|
/// process.
|
|
|
|
|
///
|
|
|
|
|
/// If the writing is completely successful, returns `Ok`. Otherwise, it
|
|
|
|
|
/// returns `Err`.
|
|
|
|
|
///
|
|
|
|
|
/// 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
|
|
|
|
|
/// `Ok`.
|
2024-08-20 02:05:25 +00:00
|
|
|
pub fn write_bytes(&self, dest: Vaddr, src: &mut VmReader<'_, Infallible>) -> Result<()> {
|
2024-08-04 06:37:50 +00:00
|
|
|
let copy_len = src.remain();
|
|
|
|
|
|
|
|
|
|
if copy_len > 0 {
|
|
|
|
|
check_vaddr(dest)?;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
let mut user_writer = self.writer(dest, copy_len)?;
|
|
|
|
|
user_writer.write_fallible(src).map_err(|err| err.0)?;
|
|
|
|
|
Ok(())
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Writes `val` to the user space of the current process.
|
|
|
|
|
pub fn write_val<T: Pod>(&self, dest: Vaddr, val: &T) -> Result<()> {
|
|
|
|
|
if core::mem::size_of::<T>() > 0 {
|
|
|
|
|
check_vaddr(dest)?;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
let mut user_writer = self.writer(dest, core::mem::size_of::<T>())?;
|
|
|
|
|
Ok(user_writer.write_val(val)?)
|
|
|
|
|
}
|
|
|
|
|
|
2025-07-31 14:39:36 +00:00
|
|
|
/// Atomically loads a `PodAtomic` value with [`Ordering::Relaxed`] semantics.
|
|
|
|
|
///
|
|
|
|
|
/// # Panics
|
|
|
|
|
///
|
|
|
|
|
/// This method will panic if `vaddr` is not aligned on a `core::mem::align_of::<T>()`-byte
|
|
|
|
|
/// boundary.
|
|
|
|
|
///
|
|
|
|
|
/// [`Ordering::Relaxed`]: core::sync::atomic::Ordering::Relaxed
|
|
|
|
|
pub fn atomic_load<T: PodAtomic>(&self, vaddr: Vaddr) -> Result<T> {
|
|
|
|
|
check_vaddr(vaddr)?;
|
|
|
|
|
|
|
|
|
|
let user_reader = self.reader(vaddr, core::mem::size_of::<T>())?;
|
|
|
|
|
Ok(user_reader.atomic_load()?)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Atomically updates a `PodAtomic` value with [`Ordering::Relaxed`] semantics.
|
|
|
|
|
///
|
2025-08-18 23:34:01 +00:00
|
|
|
/// This method internally uses [`atomic_compare_exchange`]. If the value changes
|
2025-07-31 14:39:36 +00:00
|
|
|
/// concurrently, this method will retry so the operation may be performed multiple times.
|
|
|
|
|
///
|
|
|
|
|
/// # Panics
|
|
|
|
|
///
|
|
|
|
|
/// This method will panic if `vaddr` is not aligned on a `core::mem::align_of::<T>()`-byte
|
|
|
|
|
/// boundary.
|
|
|
|
|
///
|
|
|
|
|
/// [`Ordering::Relaxed`]: core::sync::atomic::Ordering::Relaxed
|
2025-08-18 23:34:01 +00:00
|
|
|
/// [`atomic_compare_exchange`]: VmWriter::atomic_compare_exchange
|
2025-07-31 14:39:36 +00:00
|
|
|
pub fn atomic_update<T>(&self, vaddr: Vaddr, op: impl Fn(T) -> T) -> Result<T>
|
|
|
|
|
where
|
|
|
|
|
T: PodAtomic + Eq,
|
|
|
|
|
{
|
|
|
|
|
check_vaddr(vaddr)?;
|
2025-08-18 23:34:01 +00:00
|
|
|
let writer = self.writer(vaddr, core::mem::size_of::<T>())?;
|
|
|
|
|
let reader = self.reader(vaddr, core::mem::size_of::<T>())?;
|
2025-07-31 14:39:36 +00:00
|
|
|
|
2025-08-18 23:34:01 +00:00
|
|
|
let mut old_val = reader.atomic_load()?;
|
2025-07-31 14:39:36 +00:00
|
|
|
loop {
|
2025-08-18 23:34:01 +00:00
|
|
|
match writer.atomic_compare_exchange(&reader, old_val, op(old_val))? {
|
|
|
|
|
(_, true) => return Ok(old_val),
|
|
|
|
|
(cur_val, false) => old_val = cur_val,
|
2025-07-31 14:39:36 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2024-08-04 06:37:50 +00:00
|
|
|
/// Reads a C string from the user space of the current process.
|
|
|
|
|
/// The length of the string should not exceed `max_len`,
|
|
|
|
|
/// including the final `\0` byte.
|
|
|
|
|
pub fn read_cstring(&self, vaddr: Vaddr, max_len: usize) -> Result<CString> {
|
|
|
|
|
if max_len > 0 {
|
|
|
|
|
check_vaddr(vaddr)?;
|
|
|
|
|
}
|
|
|
|
|
|
2025-07-09 07:31:44 +00:00
|
|
|
// If `vaddr` is within user address space, adjust `max_len`
|
|
|
|
|
// to ensure `vaddr + max_len` does not exceed `MAX_USERSPACE_VADDR`.
|
|
|
|
|
// If `vaddr` is outside user address space, `max_len` will be set to zero
|
|
|
|
|
// and further call to `self.reader` will return `EFAULT` in this case.
|
|
|
|
|
let max_len = MAX_USERSPACE_VADDR.saturating_sub(vaddr).min(max_len);
|
|
|
|
|
|
2024-08-04 06:37:50 +00:00
|
|
|
let mut user_reader = self.reader(vaddr, max_len)?;
|
|
|
|
|
user_reader.read_cstring()
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2024-10-13 13:39:47 +00:00
|
|
|
/// A trait providing the ability to read a C string from the user space.
|
2024-08-04 06:37:50 +00:00
|
|
|
pub trait ReadCString {
|
2025-04-11 07:32:56 +00:00
|
|
|
/// Reads a C string from `self`.
|
|
|
|
|
///
|
|
|
|
|
/// This method should read the bytes iteratively in `self` until
|
|
|
|
|
/// encountering the end of the reader or reading a `\0` (which is also
|
|
|
|
|
/// included in the final C String).
|
2024-08-04 06:37:50 +00:00
|
|
|
fn read_cstring(&mut self) -> Result<CString>;
|
2025-04-11 07:32:56 +00:00
|
|
|
|
|
|
|
|
/// Reads a C string from `self` with a maximum length of `max_len`.
|
|
|
|
|
///
|
|
|
|
|
/// This method functions similarly to [`ReadCString::read_cstring`],
|
|
|
|
|
/// but imposes an additional limit on the length of the C string.
|
|
|
|
|
fn read_cstring_with_max_len(&mut self, max_len: usize) -> Result<CString>;
|
2024-08-04 06:37:50 +00:00
|
|
|
}
|
|
|
|
|
|
2024-10-13 13:39:47 +00:00
|
|
|
impl ReadCString for VmReader<'_, Fallible> {
|
2024-08-04 06:37:50 +00:00
|
|
|
fn read_cstring(&mut self) -> Result<CString> {
|
2025-04-11 07:32:56 +00:00
|
|
|
self.read_cstring_with_max_len(self.remain())
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn read_cstring_with_max_len(&mut self, max_len: usize) -> Result<CString> {
|
|
|
|
|
// This implementation is inspired by
|
|
|
|
|
// the `do_strncpy_from_user` function in Linux kernel.
|
|
|
|
|
// The original Linux implementation can be found at:
|
|
|
|
|
// <https://elixir.bootlin.com/linux/v6.0.9/source/lib/strncpy_from_user.c#L28>
|
2024-08-04 06:37:50 +00:00
|
|
|
let mut buffer: Vec<u8> = Vec::with_capacity(max_len);
|
|
|
|
|
|
2025-04-09 06:36:21 +00:00
|
|
|
if read_until_nul_byte(self, &mut buffer, max_len)? {
|
|
|
|
|
return Ok(CString::from_vec_with_nul(buffer).unwrap());
|
2024-08-04 06:37:50 +00:00
|
|
|
}
|
|
|
|
|
|
2025-04-09 06:36:21 +00:00
|
|
|
return_errno_with_message!(
|
|
|
|
|
Errno::EFAULT,
|
|
|
|
|
"no nul terminator is present before reaching the buffer limit"
|
2024-08-04 06:37:50 +00:00
|
|
|
);
|
2025-04-09 06:36:21 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl ReadCString for VmReaderArray<'_> {
|
|
|
|
|
fn read_cstring(&mut self) -> Result<CString> {
|
2025-04-11 07:32:56 +00:00
|
|
|
self.read_cstring_with_max_len(self.sum_lens())
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn read_cstring_with_max_len(&mut self, max_len: usize) -> Result<CString> {
|
2025-04-09 06:36:21 +00:00
|
|
|
let mut buffer: Vec<u8> = Vec::with_capacity(max_len);
|
|
|
|
|
|
|
|
|
|
for reader in self.readers_mut() {
|
|
|
|
|
if read_until_nul_byte(reader, &mut buffer, max_len)? {
|
|
|
|
|
return Ok(CString::from_vec_with_nul(buffer).unwrap());
|
|
|
|
|
}
|
|
|
|
|
}
|
2024-08-04 06:37:50 +00:00
|
|
|
|
2025-04-09 06:36:21 +00:00
|
|
|
return_errno_with_message!(
|
|
|
|
|
Errno::EFAULT,
|
|
|
|
|
"no nul terminator is present before reaching the buffer limit"
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Reads bytes from `reader` into `buffer` until a nul byte is found.
|
|
|
|
|
///
|
|
|
|
|
/// This method returns the following values:
|
|
|
|
|
/// 1. `Ok(true)`: If a nul byte is found in the reader;
|
|
|
|
|
/// 2. `Ok(false)`: If no nul byte is found and the `reader` is exhausted;
|
|
|
|
|
/// 3. `Err(_)`: If an error occurs while reading from the `reader`.
|
|
|
|
|
fn read_until_nul_byte(
|
|
|
|
|
reader: &mut VmReader,
|
|
|
|
|
buffer: &mut Vec<u8>,
|
|
|
|
|
max_len: usize,
|
|
|
|
|
) -> Result<bool> {
|
|
|
|
|
macro_rules! read_one_byte_at_a_time_while {
|
|
|
|
|
($cond:expr) => {
|
|
|
|
|
while $cond {
|
|
|
|
|
let byte = reader.read_val::<u8>()?;
|
|
|
|
|
buffer.push(byte);
|
|
|
|
|
if byte == 0 {
|
|
|
|
|
return Ok(true);
|
2024-08-04 06:37:50 +00:00
|
|
|
}
|
|
|
|
|
}
|
2025-04-09 06:36:21 +00:00
|
|
|
};
|
|
|
|
|
}
|
2024-08-04 06:37:50 +00:00
|
|
|
|
2025-04-09 06:36:21 +00:00
|
|
|
// Handle the first few bytes to make `cur_addr` aligned with `size_of::<usize>`
|
|
|
|
|
read_one_byte_at_a_time_while!(
|
|
|
|
|
!is_addr_aligned(reader.cursor() as usize) && buffer.len() < max_len && reader.has_remain()
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
// Handle the rest of the bytes in bulk
|
|
|
|
|
let mut cloned_reader = reader.clone();
|
|
|
|
|
while (buffer.len() + mem::size_of::<usize>()) <= max_len {
|
|
|
|
|
let Ok(word) = cloned_reader.read_val::<usize>() else {
|
|
|
|
|
break;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
if has_zero(word) {
|
|
|
|
|
for byte in word.to_ne_bytes() {
|
|
|
|
|
reader.skip(1);
|
|
|
|
|
buffer.push(byte);
|
|
|
|
|
if byte == 0 {
|
|
|
|
|
return Ok(true);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
unreachable!("The branch should never be reached unless `has_zero` has bugs.")
|
2024-08-04 06:37:50 +00:00
|
|
|
}
|
|
|
|
|
|
2025-04-09 06:36:21 +00:00
|
|
|
reader.skip(size_of::<usize>());
|
|
|
|
|
buffer.extend_from_slice(&word.to_ne_bytes());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Handle the last few bytes that are not enough for a word
|
|
|
|
|
read_one_byte_at_a_time_while!(buffer.len() < max_len && reader.has_remain());
|
2024-08-04 06:37:50 +00:00
|
|
|
|
2025-04-09 06:36:21 +00:00
|
|
|
if buffer.len() >= max_len {
|
|
|
|
|
return_errno_with_message!(
|
|
|
|
|
Errno::EFAULT,
|
|
|
|
|
"no nul terminator is present before exceeding the maximum length"
|
|
|
|
|
);
|
|
|
|
|
} else {
|
|
|
|
|
Ok(false)
|
2024-08-04 06:37:50 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Determines whether the value contains a zero byte.
|
|
|
|
|
///
|
|
|
|
|
/// This magic algorithm is from the Linux `has_zero` function:
|
|
|
|
|
/// <https://elixir.bootlin.com/linux/v6.0.9/source/include/asm-generic/word-at-a-time.h#L93>
|
|
|
|
|
const fn has_zero(value: usize) -> bool {
|
|
|
|
|
const ONE_BITS: usize = usize::from_le_bytes([0x01; mem::size_of::<usize>()]);
|
|
|
|
|
const HIGH_BITS: usize = usize::from_le_bytes([0x80; mem::size_of::<usize>()]);
|
|
|
|
|
|
|
|
|
|
value.wrapping_sub(ONE_BITS) & !value & HIGH_BITS != 0
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Checks if the user space pointer is below the lowest userspace address.
|
|
|
|
|
///
|
|
|
|
|
/// If a pointer is below the lowest userspace address, it is likely to be a
|
|
|
|
|
/// NULL pointer. Reading from or writing to a NULL pointer should trigger a
|
|
|
|
|
/// segmentation fault.
|
|
|
|
|
///
|
|
|
|
|
/// If it is not checked here, a kernel page fault will happen and we would
|
|
|
|
|
/// deny the access in the page fault handler either. It may save a page fault
|
|
|
|
|
/// in some occasions. More importantly, double page faults may not be handled
|
|
|
|
|
/// quite well on some platforms.
|
|
|
|
|
fn check_vaddr(va: Vaddr) -> Result<()> {
|
|
|
|
|
if va < crate::vm::vmar::ROOT_VMAR_LOWEST_ADDR {
|
|
|
|
|
Err(Error::with_message(
|
|
|
|
|
Errno::EFAULT,
|
2025-07-31 14:39:36 +00:00
|
|
|
"the userspace address is too small",
|
2024-08-04 06:37:50 +00:00
|
|
|
))
|
|
|
|
|
} else {
|
|
|
|
|
Ok(())
|
|
|
|
|
}
|
|
|
|
|
}
|
2024-09-26 04:03:32 +00:00
|
|
|
|
|
|
|
|
/// Checks if the given address is aligned.
|
|
|
|
|
const fn is_addr_aligned(addr: usize) -> bool {
|
|
|
|
|
(addr & (mem::size_of::<usize>() - 1)) == 0
|
|
|
|
|
}
|
2025-03-31 03:01:22 +00:00
|
|
|
|
|
|
|
|
#[cfg(ktest)]
|
|
|
|
|
mod test {
|
|
|
|
|
use ostd::prelude::*;
|
|
|
|
|
|
|
|
|
|
use super::*;
|
|
|
|
|
|
2025-04-09 06:36:21 +00:00
|
|
|
fn init_buffer(cstrs: &[CString]) -> Vec<u8> {
|
|
|
|
|
let mut buffer = vec![255u8; 100];
|
|
|
|
|
|
|
|
|
|
let mut writer = VmWriter::from(buffer.as_mut_slice());
|
|
|
|
|
|
|
|
|
|
for cstr in cstrs {
|
|
|
|
|
writer.write(&mut VmReader::from(cstr.as_bytes_with_nul()));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
buffer
|
|
|
|
|
}
|
|
|
|
|
|
2025-03-31 03:01:22 +00:00
|
|
|
#[ktest]
|
|
|
|
|
fn read_multiple_cstring() {
|
2025-04-09 06:36:21 +00:00
|
|
|
let strs = {
|
|
|
|
|
let str1 = CString::new("hello").unwrap();
|
|
|
|
|
let str2 = CString::new("world!").unwrap();
|
|
|
|
|
vec![str1, str2]
|
|
|
|
|
};
|
2025-03-31 03:01:22 +00:00
|
|
|
|
2025-04-09 06:36:21 +00:00
|
|
|
let buffer = init_buffer(&strs);
|
2025-03-31 03:01:22 +00:00
|
|
|
|
|
|
|
|
let mut reader = VmReader::from(buffer.as_slice()).to_fallible();
|
|
|
|
|
let read_str1 = reader.read_cstring().unwrap();
|
2025-04-09 06:36:21 +00:00
|
|
|
assert_eq!(read_str1, strs[0]);
|
2025-03-31 03:01:22 +00:00
|
|
|
let read_str2 = reader.read_cstring().unwrap();
|
2025-04-09 06:36:21 +00:00
|
|
|
assert_eq!(read_str2, strs[1]);
|
|
|
|
|
|
|
|
|
|
assert!(reader
|
|
|
|
|
.read_cstring()
|
|
|
|
|
.is_err_and(|err| err.error() == Errno::EFAULT));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[ktest]
|
|
|
|
|
fn read_cstring_from_multiread() {
|
|
|
|
|
let strs = {
|
|
|
|
|
let str1 = CString::new("hello").unwrap();
|
|
|
|
|
let str2 = CString::new("world!").unwrap();
|
|
|
|
|
let str3 = CString::new("asterinas").unwrap();
|
|
|
|
|
vec![str1, str2, str3]
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
let buffer = init_buffer(&strs);
|
|
|
|
|
|
|
|
|
|
let mut readers = {
|
|
|
|
|
let reader1 = VmReader::from(&buffer[0..20]).to_fallible();
|
|
|
|
|
let reader2 = VmReader::from(&buffer[20..40]).to_fallible();
|
|
|
|
|
let reader3 = VmReader::from(&buffer[40..60]).to_fallible();
|
|
|
|
|
VmReaderArray::new(vec![reader1, reader2, reader3].into_boxed_slice())
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
let multiread = &mut readers as &mut dyn MultiRead;
|
|
|
|
|
let read_str1 = multiread.read_cstring().unwrap();
|
|
|
|
|
assert_eq!(read_str1, strs[0]);
|
|
|
|
|
let read_str2 = multiread.read_cstring().unwrap();
|
|
|
|
|
assert_eq!(read_str2, strs[1]);
|
|
|
|
|
let read_str3 = multiread.read_cstring().unwrap();
|
|
|
|
|
assert_eq!(read_str3, strs[2]);
|
|
|
|
|
|
|
|
|
|
assert!(multiread
|
|
|
|
|
.read_cstring()
|
|
|
|
|
.is_err_and(|err| err.error() == Errno::EFAULT));
|
2025-03-31 03:01:22 +00:00
|
|
|
}
|
|
|
|
|
}
|