Added documentation for the dma, logger, and sgl modules

This commit is contained in:
Timothy Finnegan
2024-08-31 16:16:35 -07:00
parent d7852b4836
commit e9e7e2934e
3 changed files with 111 additions and 0 deletions
+89
View File
@@ -8,6 +8,10 @@ use syscall::PAGE_SIZE;
use crate::MemoryType;
/// Defines the platform-specific memory type for DMA operations
///
/// - On x86 systems, DMA uses Write-back memory ([MemoryType::Writeback])
/// - On aarch64 systems, DMA uses uncacheable memory ([MemoryType::Uncacheable])
const DMA_MEMTY: MemoryType = {
if cfg!(any(target_arch = "x86", target_arch = "x86_64")) {
// x86 ensures cache coherence with DMA memory
@@ -20,6 +24,19 @@ const DMA_MEMTY: MemoryType = {
}
};
/// Returns a file descriptor for zeroized physically-contiguous DMA memory.
///
/// # Returns
///
/// A [Result] containing:
/// - '[Ok]' - A [Fd] (file descriptor) to zeroized, physically continuous DMA usable memory
/// - '[Err]' - The error returned by the provider of the /scheme/memory/zeroed scheme.
///
/// # Errors
///
/// This function can return an error in the following case:
///
/// - The request for the physical memory fails.
pub(crate) fn phys_contiguous_fd() -> Result<Fd> {
Fd::open(
&format!("/scheme/memory/zeroed@{DMA_MEMTY}?phys_contiguous"),
@@ -28,6 +45,26 @@ pub(crate) fn phys_contiguous_fd() -> Result<Fd> {
)
}
/// Allocates a chunk of physical memory for DMA, and then maps it to virtual memory.
///
/// # Arguments
/// 'length: [usize]' - The length of the memory region. Must be a multiple of [PAGE_SIZE]
///
/// # Returns
///
/// This function returns a [Result] containing the following:
/// - A '[Ok]([usize], *[mut] ())' containing a Tuple of the physical address of the region, and a raw pointer to that region in virtual memory.
/// - An '[Err]' - containing the error for the operation.
///
/// # Errors
///
/// This function asserts if:
/// - length is not a multiple of [PAGE_SIZE]
///
/// This function returns an error if:
/// - A file descriptor to physically contiguous memory of type [DMA_MEMTY] could not be acquired
/// - A virtual mapping for the physically contiguous memory could not be created
/// - The virtual address returned by the memory manager was invalid.
fn alloc_and_map(length: usize) -> Result<(usize, *mut ())> {
assert_eq!(length % PAGE_SIZE, 0);
unsafe {
@@ -52,13 +89,29 @@ fn alloc_and_map(length: usize) -> Result<(usize, *mut ())> {
}
}
/// A safe accessor for DMA memory.
pub struct Dma<T: ?Sized> {
/// The physical address of the memory
phys: usize,
/// The page-aligned length of the memory. Will be a multiple of [PAGE_SIZE]
aligned_len: usize,
/// The pointer to the Dma memory in the virtual address space.
virt: *mut T,
}
impl<T> Dma<T> {
/// [Dma] constructor that allocates and initializes a region of DMA memory with the page-aligned
/// size and initial value of some T
///
/// # Arguments
/// 'value: T' - The initial value to write to the allocated region
///
/// # Returns
///
/// This function returns a [Result] containing the following:
///
/// - A '[Ok] (`[Dma]<T>`)' containing the initialized region
/// - An '[Err]' containing an error.
pub fn new(value: T) -> Result<Self> {
unsafe {
let mut zeroed = Self::zeroed()?;
@@ -66,6 +119,15 @@ impl<T> Dma<T> {
Ok(zeroed.assume_init())
}
}
/// [Dma] constructor that allocates and zeroizes a memory region of the page-aligned size of T
///
/// # Returns
///
/// This function returns a [Result] containing the following:
///
/// - A '[Ok] (`[Dma]<[MaybeUninit]<T>>`)' containing the allocated and zeroized memory
/// - An '[Err]' containing an error.
pub fn zeroed() -> Result<Dma<MaybeUninit<T>>> {
let aligned_len = size_of::<T>().next_multiple_of(PAGE_SIZE);
let (phys, virt) = alloc_and_map(aligned_len)?;
@@ -78,6 +140,16 @@ impl<T> Dma<T> {
}
impl<T> Dma<MaybeUninit<T>> {
/// Assumes that possibly uninitialized DMA memory has been initialized, and returns a new
/// instance of an object of type `[Dma]<T>`.
///
/// # Returns
/// - `[Dma]<T>` - The original structure without the [MaybeUninit] wrapper around its contents.
///
/// # Notes
/// - This is unsafe because it assumes that the memory stored within the `[Dma]<T>` is a valid
/// instance of T. If it isn't (for example -- if it was initialized with [Dma::zeroed]),
/// then the underlying memory may not contain the expected T structure.
pub unsafe fn assume_init(self) -> Dma<T> {
let Dma {
phys,
@@ -94,12 +166,23 @@ impl<T> Dma<MaybeUninit<T>> {
}
}
impl<T: ?Sized> Dma<T> {
/// Returns the physical address of the physical memory that this [Dma] structure references.
///
/// # Returns
/// [usize] - The physical address of the memory.
pub fn physical(&self) -> usize {
self.phys
}
}
impl<T> Dma<[T]> {
/// Returns a [Dma] object containing a zeroized slice of T with a given count.
///
/// # Arguments
///
/// - 'count: [usize]' - The number of elements of type T in the allocated slice.
///
///
pub fn zeroed_slice(count: usize) -> Result<Dma<[MaybeUninit<T>]>> {
let aligned_len = count
.checked_mul(size_of::<T>())
@@ -113,6 +196,11 @@ impl<T> Dma<[T]> {
virt: ptr::slice_from_raw_parts_mut(virt.cast(), count),
})
}
/// Casts the slice from type T to type U.
///
/// # Returns
/// '`[DMA]<U>`' - A cast handle to the Dma memory.
pub unsafe fn cast_slice<U>(self) -> Dma<[U]> {
let Dma {
phys,
@@ -129,6 +217,7 @@ impl<T> Dma<[T]> {
}
}
impl<T> Dma<[MaybeUninit<T>]> {
/// See [`Dma<MaybeUninit<T>>::assume_init`]
pub unsafe fn assume_init(self) -> Dma<[T]> {
let &Dma {
phys,
+1
View File
@@ -1,5 +1,6 @@
use redox_log::{OutputBuilder, RedoxLogger};
/// Configures logging for a single driver.
#[cfg_attr(not(target_os = "redox"), allow(unused_variables, unused_mut))]
pub fn setup_logging(
category: &str,
+21
View File
@@ -8,21 +8,38 @@ use syscall::{MAP_FIXED, PAGE_SIZE};
use crate::dma::phys_contiguous_fd;
/// A Scatter-Gather List data structure
///
/// See: https://en.wikipedia.org/wiki/Gather/scatter_(vector_addressing)
#[derive(Debug)]
pub struct Sgl {
/// A raw pointer to the SGL in virtual memory
virt: *mut u8,
/// The length of the allocated memory. This value is NOT guaranteed to be a multiple of [PAGE_SIZE]
unaligned_length: NonZeroUsize,
/// The vector of chunks tracked by this [Sgl] object. This is the sparsely-populated vector in the SGL algorithm.
chunks: Vec<Chunk>,
}
/// A structure representing a chunk of memory in the sparsely-populated vector of the SGL
#[derive(Debug)]
pub struct Chunk {
/// The offset of the chunk in the sparsely-populated vector.
pub offset: usize,
/// The physical address of the chunk
pub phys: usize,
/// A raw pointer to the chunk in virtual memory
pub virt: *mut u8,
/// The length of the chunk in bytes.
pub length: usize,
}
impl Sgl {
/// Constructor for the scatter/gather list.
///
/// # Arguments
///
/// 'unaligned_length: [usize]' - The length of the SGL, not aligned to the nearest page.
pub fn new(unaligned_length: usize) -> Result<Self> {
let unaligned_length = NonZeroUsize::new(unaligned_length).ok_or(Error::new(EINVAL))?;
@@ -77,12 +94,16 @@ impl Sgl {
Ok(this)
}
}
/// Returns an immutable reference to the vector of chunks
pub fn chunks(&self) -> &[Chunk] {
&self.chunks
}
/// Returns a raw pointer to the vector of chunks in virtual memory
pub fn as_ptr(&self) -> *mut u8 {
self.virt
}
/// Returns the length of the scatter-gather list.
pub fn len(&self) -> usize {
self.unaligned_length.get()
}