Change pass to NonNull + docs on it

This commit is contained in:
Mark Poliakov 2023-11-16 16:44:50 +02:00
parent 7785a8310f
commit 407ce3bae4

View File

@ -1,33 +1,51 @@
//! Interfaces for passing stuff between the kernel and the userspace
// TODO
#![allow(missing_docs)]
use core::ptr::NonNull;
use crate::error::Error;
// TODO use NonNull instead
pub trait Placer {
fn place_ref<T: Place>(&mut self, r: &T) -> Result<*const T::Output, Error>;
fn place_slice<T: Place>(&mut self, r: &[T]) -> Result<*const [T::Output], Error>;
/// Interface for a "writer", producing objects "owned" by the userspace.
///
/// # Safety
///
/// The trait is marked unsafe as it is the implementor's concern that the produced pointers can
/// actually hold the requested values and are properly aligned for that.
pub unsafe trait Placer {
/// Converts a kernel-space reference into a pointer that can be safely dereferenced in
/// userspace
fn place_ref<T: Place>(&mut self, r: &T) -> Result<NonNull<T::Output>, Error>;
/// Converts a kernel-space slice reference into a slice pointer, elements of which are placed
/// in safely-accessible memory by userspace
fn place_slice<T: Place>(&mut self, r: &[T]) -> Result<NonNull<[T::Output]>, Error>;
}
pub trait Place {
/// Interface for "transferring ownership" of an object to userspace.
///
/// # Safety
///
/// The trait is marked unsafe because it may produce arbitrary pointer, so it's the implementor's
/// concern that they are actually correct.
pub unsafe trait Place {
/// Conversion result type, must be safely accessible from userspace
type Output: 'static;
/// Creates a userspace-reachable variant of the internal value
fn place<P: Placer>(&self, placer: &mut P) -> Result<Self::Output, Error>;
/// Converts the internal value using [Place::place] and returns a safe userspace reference
fn place_ref<P: Placer>(&self, placer: &mut P) -> Result<&'static Self::Output, Error>
where
Self: Sized,
{
let ptr = placer.place_ref(self)?;
unsafe { Ok(&*ptr) }
unsafe { Ok(ptr.as_ref()) }
}
}
macro_rules! impl_primitive {
($($ty:ty),+) => {
$(
impl $crate::pass::Place for $ty {
unsafe impl $crate::pass::Place for $ty {
type Output = $ty;
fn place<P: $crate::pass::Placer>(&self, _placer: &mut P) -> Result<$ty, Error> {
@ -40,25 +58,27 @@ macro_rules! impl_primitive {
impl_primitive!(u8, u16, u32, u64, i8, i16, i32, i64, bool, char);
impl<'s> Place for &'s str {
unsafe impl<'s> Place for &'s str {
type Output = &'static str;
fn place<P: Placer>(&self, placer: &mut P) -> Result<Self::Output, Error> {
let data = placer.place_slice(self.as_bytes())?;
// Safety: safe, object passed in was already a proper &str
Ok(unsafe { core::str::from_utf8_unchecked(data.as_ref().unwrap()) })
Ok(unsafe { core::str::from_utf8_unchecked(data.as_ref()) })
}
}
impl<T: Place> Place for [T] {
unsafe impl<T: Place> Place for [T] {
type Output = &'static [T::Output];
fn place<P: Placer>(&self, placer: &mut P) -> Result<Self::Output, Error> {
let data = placer.place_slice(self)?;
Ok(unsafe { data.as_ref().unwrap() })
Ok(unsafe { data.as_ref() })
}
}
/// Automatically implements the [Place] interface for a struct, properly handling any nested
/// references
#[macro_export]
macro_rules! impl_place_lifetime {
(
@ -78,7 +98,7 @@ macro_rules! impl_place_lifetime {
),*
}
impl<$struct_lifetime> $crate::pass::Place for $struct_name<$struct_lifetime> {
unsafe impl<$struct_lifetime> $crate::pass::Place for $struct_name<$struct_lifetime> {
type Output = $struct_name<'static>;
fn place<P: $crate::pass::Placer>(&self, placer: &mut P)