From e9e7e2934ee0a862960641e857d1d61a0d04b260 Mon Sep 17 00:00:00 2001 From: Timothy Finnegan Date: Sat, 31 Aug 2024 16:16:35 -0700 Subject: [PATCH] Added documentation for the dma, logger, and sgl modules --- common/src/dma.rs | 89 ++++++++++++++++++++++++++++++++++++++++++++ common/src/logger.rs | 1 + common/src/sgl.rs | 21 +++++++++++ 3 files changed, 111 insertions(+) diff --git a/common/src/dma.rs b/common/src/dma.rs index fbeb74bf96..98233411d2 100644 --- a/common/src/dma.rs +++ b/common/src/dma.rs @@ -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::open( &format!("/scheme/memory/zeroed@{DMA_MEMTY}?phys_contiguous"), @@ -28,6 +45,26 @@ pub(crate) fn phys_contiguous_fd() -> Result { ) } +/// 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 { + /// 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 Dma { + /// [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]`)' containing the initialized region + /// - An '[Err]' containing an error. pub fn new(value: T) -> Result { unsafe { let mut zeroed = Self::zeroed()?; @@ -66,6 +119,15 @@ impl Dma { 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]>`)' containing the allocated and zeroized memory + /// - An '[Err]' containing an error. pub fn zeroed() -> Result>> { let aligned_len = size_of::().next_multiple_of(PAGE_SIZE); let (phys, virt) = alloc_and_map(aligned_len)?; @@ -78,6 +140,16 @@ impl Dma { } impl Dma> { + /// Assumes that possibly uninitialized DMA memory has been initialized, and returns a new + /// instance of an object of type `[Dma]`. + /// + /// # Returns + /// - `[Dma]` - The original structure without the [MaybeUninit] wrapper around its contents. + /// + /// # Notes + /// - This is unsafe because it assumes that the memory stored within the `[Dma]` 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 { let Dma { phys, @@ -94,12 +166,23 @@ impl Dma> { } } impl Dma { + /// 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 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]>> { let aligned_len = count .checked_mul(size_of::()) @@ -113,6 +196,11 @@ impl Dma<[T]> { virt: ptr::slice_from_raw_parts_mut(virt.cast(), count), }) } + + /// Casts the slice from type T to type U. + /// + /// # Returns + /// '`[DMA]`' - A cast handle to the Dma memory. pub unsafe fn cast_slice(self) -> Dma<[U]> { let Dma { phys, @@ -129,6 +217,7 @@ impl Dma<[T]> { } } impl Dma<[MaybeUninit]> { + /// See [`Dma>::assume_init`] pub unsafe fn assume_init(self) -> Dma<[T]> { let &Dma { phys, diff --git a/common/src/logger.rs b/common/src/logger.rs index 4f39f253b9..6b62cf86fe 100644 --- a/common/src/logger.rs +++ b/common/src/logger.rs @@ -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, diff --git a/common/src/sgl.rs b/common/src/sgl.rs index cdd043415c..541250fbe9 100644 --- a/common/src/sgl.rs +++ b/common/src/sgl.rs @@ -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, } + +/// 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 { 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() }