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