Skip to main content

starry_vm/
lib.rs

1//! Virtual memory utilities.
2#![no_std]
3#![feature(maybe_uninit_as_bytes)]
4#![warn(missing_docs)]
5
6use core::{mem::MaybeUninit, slice};
7
8use axerrno::AxError;
9use extern_trait::extern_trait;
10
11/// Errors that can occur during virtual memory operations.
12#[derive(Debug, PartialEq, Clone, Copy)]
13pub enum VmError {
14    /// The address is invalid, e.g., not aligned to the required boundary,
15    /// out of bounds (including null).
16    BadAddress,
17    /// The operation is not allowed, e.g., trying to write to read-only memory.
18    AccessDenied,
19    /// The C-style string or array is too long.
20    ///
21    /// This error is returned by [`vm_load_until_nul`] when the null terminator
22    /// is not found within a predefined search limit.
23    #[cfg(feature = "alloc")]
24    TooLong,
25}
26
27impl From<VmError> for AxError {
28    fn from(err: VmError) -> Self {
29        match err {
30            VmError::BadAddress | VmError::AccessDenied => AxError::BadAddress,
31            #[cfg(feature = "alloc")]
32            VmError::TooLong => AxError::NameTooLong,
33        }
34    }
35}
36
37/// A result type for virtual memory operations.
38pub type VmResult<T = ()> = Result<T, VmError>;
39
40/// The interface for accessing virtual memory.
41///
42/// # Safety
43///
44/// - The implementation must ensure that the memory accesses are safe and do
45///   not violate any memory safety rules.
46#[extern_trait(VmImpl)]
47pub unsafe trait VmIo {
48    /// Creates an instance of [`VmIo`].
49    ///
50    /// This is used for implementations which might need to store some state or
51    /// data to perform the operations. Implementators may leave this empty
52    /// if no state is needed.
53    fn new() -> Self;
54
55    /// Reads data from the virtual memory starting at `start` into `buf`.
56    fn read(&mut self, start: usize, buf: &mut [MaybeUninit<u8>]) -> VmResult;
57
58    /// Writes data to the virtual memory starting at `start` from `buf`.
59    fn write(&mut self, start: usize, buf: &[u8]) -> VmResult;
60}
61
62/// Reads a slice from the virtual memory.
63pub fn vm_read_slice<T>(ptr: *const T, buf: &mut [MaybeUninit<T>]) -> VmResult {
64    if !ptr.is_aligned() {
65        return Err(VmError::BadAddress);
66    }
67    VmImpl::new().read(ptr.addr(), buf.as_bytes_mut())
68}
69
70/// Writes data to the virtual memory.
71pub fn vm_write_slice<T>(ptr: *mut T, buf: &[T]) -> VmResult {
72    if !ptr.is_aligned() {
73        return Err(VmError::BadAddress);
74    }
75    // SAFETY: we don't care about validity, since these bytes are only used for
76    // writing to the virtual memory.
77    let bytes = unsafe { slice::from_raw_parts(buf.as_ptr().cast::<u8>(), size_of_val(buf)) };
78    VmImpl::new().write(ptr.addr(), bytes)
79}
80
81mod thin;
82pub use thin::{VmMutPtr, VmPtr};
83
84#[cfg(feature = "alloc")]
85mod alloc;
86#[cfg(feature = "alloc")]
87pub use alloc::{vm_load, vm_load_any, vm_load_until_nul};