Skip to content

Commit

Permalink
kernel: utilites: update documentation
Browse files Browse the repository at this point in the history
Add documentation for missing types, add rustdoc links, wrap lines,
format header comments.
  • Loading branch information
bradjc committed Oct 10, 2024
1 parent b249c8f commit 971d06a
Show file tree
Hide file tree
Showing 10 changed files with 177 additions and 120 deletions.
51 changes: 34 additions & 17 deletions kernel/src/utilities/copy_slice.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,38 @@
// SPDX-License-Identifier: Apache-2.0 OR MIT
// Copyright Tock Contributors 2022.

//! Helper functions for copying buffers.
//!
//! This utility provides an implementation of the standard Rust
//! [`slice::copy_from_slice()`] method that cannot panic. This method is
//! provided through the [`CopyOrErr`] trait.
//!
//! This functionality is currently provided for the following types:
//! - `u8`
//! - `u16`
//! - `u32`
//! - `u64`
//! - `usize`

use crate::ErrorCode;
use core::ptr;

/// Interface for copying buffers that cannot panic.
pub trait CopyOrErr {
/// Copies a nonoverlapping slice from src to self. Returns Err(ErrorCode) if source and self
/// are not the same length. This is a non-panicing version of slice::copy_from_slice.
/// Copy a non-overlapping slice from `src` to `self`.
///
/// This is a non-panicing version of [`slice::copy_from_slice`].
///
/// Returns `Err(ErrorCode)` if `src` and `self` are not the same length.
fn copy_from_slice_or_err(&mut self, src: &Self) -> Result<(), ErrorCode>;
}

impl CopyOrErr for [u8] {
fn copy_from_slice_or_err(&mut self, src: &Self) -> Result<(), ErrorCode> {
if self.len() == src.len() {
// SAFETY: `self` is valid for `self.len()` elements by definition, and `src` was
// checked to have the same length. The slices cannot overlap because
// mutable references are exclusive.
// SAFETY: `self` is valid for `self.len()` elements by definition,
// and `src` was checked to have the same length. The slices cannot
// overlap because mutable references are exclusive.
unsafe {
ptr::copy_nonoverlapping(src.as_ptr(), self.as_mut_ptr(), self.len());
}
Expand All @@ -30,9 +47,9 @@ impl CopyOrErr for [u8] {
impl CopyOrErr for [u16] {
fn copy_from_slice_or_err(&mut self, src: &Self) -> Result<(), ErrorCode> {
if self.len() == src.len() {
// SAFETY: `self` is valid for `self.len()` elements by definition, and `src` was
// checked to have the same length. The slices cannot overlap because
// mutable references are exclusive.
// SAFETY: `self` is valid for `self.len()` elements by definition,
// and `src` was checked to have the same length. The slices cannot
// overlap because mutable references are exclusive.
unsafe {
ptr::copy_nonoverlapping(src.as_ptr(), self.as_mut_ptr(), self.len());
}
Expand All @@ -46,9 +63,9 @@ impl CopyOrErr for [u16] {
impl CopyOrErr for [u32] {
fn copy_from_slice_or_err(&mut self, src: &Self) -> Result<(), ErrorCode> {
if self.len() == src.len() {
// SAFETY: `self` is valid for `self.len()` elements by definition, and `src` was
// checked to have the same length. The slices cannot overlap because
// mutable references are exclusive.
// SAFETY: `self` is valid for `self.len()` elements by definition,
// and `src` was checked to have the same length. The slices cannot
// overlap because mutable references are exclusive.
unsafe {
ptr::copy_nonoverlapping(src.as_ptr(), self.as_mut_ptr(), self.len());
}
Expand All @@ -62,9 +79,9 @@ impl CopyOrErr for [u32] {
impl CopyOrErr for [u64] {
fn copy_from_slice_or_err(&mut self, src: &Self) -> Result<(), ErrorCode> {
if self.len() == src.len() {
// SAFETY: `self` is valid for `self.len()` elements by definition, and `src` was
// checked to have the same length. The slices cannot overlap because
// mutable references are exclusive.
// SAFETY: `self` is valid for `self.len()` elements by definition,
// and `src` was checked to have the same length. The slices cannot
// overlap because mutable references are exclusive.
unsafe {
ptr::copy_nonoverlapping(src.as_ptr(), self.as_mut_ptr(), self.len());
}
Expand All @@ -78,9 +95,9 @@ impl CopyOrErr for [u64] {
impl CopyOrErr for [usize] {
fn copy_from_slice_or_err(&mut self, src: &Self) -> Result<(), ErrorCode> {
if self.len() == src.len() {
// SAFETY: `self` is valid for `self.len()` elements by definition, and `src` was
// checked to have the same length. The slices cannot overlap because
// mutable references are exclusive.
// SAFETY: `self` is valid for `self.len()` elements by definition,
// and `src` was checked to have the same length. The slices cannot
// overlap because mutable references are exclusive.
unsafe {
ptr::copy_nonoverlapping(src.as_ptr(), self.as_mut_ptr(), self.len());
}
Expand Down
7 changes: 6 additions & 1 deletion kernel/src/utilities/helpers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,12 @@
// SPDX-License-Identifier: Apache-2.0 OR MIT
// Copyright Tock Contributors 2022.

//! Helper macros.
//! Helper functions and macros.
//!
//! These are various utility functions and macros that are useful throughout
//! the Tock kernel and are provided here for convenience.
//!
//! The macros are exported through the top level of the `kernel` crate.

/// Create an object with the given capability.
///
Expand Down
7 changes: 3 additions & 4 deletions kernel/src/utilities/leasable_buffer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -143,9 +143,8 @@
//! will be called prior to passing the buffer down to lower layers, and
//! `reset()` will be called once the `SubSlice` is returned via a callback.
//!
//! ```rust
//! ```rust
//! # use kernel::utilities::leasable_buffer::SubSlice;
//!
//! let mut internal = ['a', 'b', 'c', 'd'];
//! let original_base_addr = internal.as_ptr();
//!
Expand All @@ -164,8 +163,8 @@
//! assert_eq!((buffer[0], buffer[1]), ('a', 'b'));
//!
//! ```
//!
//! Author: Amit Levy

// Author: Amit Levy

use core::ops::{Bound, Range, RangeBounds};
use core::ops::{Index, IndexMut};
Expand Down
46 changes: 24 additions & 22 deletions kernel/src/utilities/math.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,10 @@ pub fn closest_power_of_two(mut num: u32) -> u32 {
num
}

/// Represents an integral power-of-two as an exponent.
#[derive(Copy, Clone, Debug, PartialEq, PartialOrd, Eq, Ord)]
pub struct PowerOfTwo(u32);

/// Represents an integral power-of-two as an exponent
impl PowerOfTwo {
/// Returns the base-2 exponent as a numeric type
pub fn exp<R>(self) -> R
Expand All @@ -31,31 +31,32 @@ impl PowerOfTwo {
From::from(self.0)
}

/// Converts a number two the nearest `PowerOfTwo` less-than-or-equal to it.
/// Converts a number two the nearest [`PowerOfTwo`] less-than-or-equal to it.
pub fn floor<F: Into<u32>>(f: F) -> PowerOfTwo {
PowerOfTwo(log_base_two(f.into()))
}

/// Converts a number two the nearest `PowerOfTwo` greater-than-or-equal to
/// Converts a number two the nearest [`PowerOfTwo`] greater-than-or-equal to
/// it.
pub fn ceiling<F: Into<u32>>(f: F) -> PowerOfTwo {
PowerOfTwo(log_base_two(closest_power_of_two(f.into())))
}

/// Creates a new `PowerOfTwo` representing the number zero.
/// Creates a new [`PowerOfTwo`] representing the number zero.
pub fn zero() -> PowerOfTwo {
PowerOfTwo(0)
}

/// Converts a `PowerOfTwo` to a number.
/// Converts a [`PowerOfTwo`] to a number.
pub fn as_num<F: From<u32>>(self) -> F {
(1 << self.0).into()
}
}

/// Get log base 2 of a number.
///
/// Note: this is the floor of the result. Also, an input of 0 results in an
/// output of 0
/// output of 0.
pub fn log_base_two(num: u32) -> u32 {
if num == 0 {
0
Expand All @@ -77,6 +78,7 @@ pub fn log_base_two_u64(num: u64) -> u32 {
const EXPONENT_MASK: u32 = 0b01111111_10000000_00000000_00000000;
const EXPONENT_BIAS: u32 = 127;

/// Return the absolute value of the floating point number.
pub fn abs(n: f32) -> f32 {
f32::from_bits(n.to_bits() & 0x7FFF_FFFF)
}
Expand All @@ -90,28 +92,29 @@ fn extract_exponent_value(x: f32) -> i32 {
}

fn ln_1to2_series_approximation(x: f32) -> f32 {
// idea from https://stackoverflow.com/a/44232045/
// modified to not be restricted to int range and only values of x above 1.0.
// and got rid of most of the slow conversions,
// should work for all positive values of x.
// Idea from https://stackoverflow.com/a/44232045/. Modified to not be
// restricted to int range and only values of x above 1.0 and got rid of
// most of the slow conversions, should work for all positive values of x.

//x may essentially be 1.0 but, as clippy notes, these kinds of
//floating point comparisons can fail when the bit pattern is not the sames
// x may essentially be 1.0 but, as clippy notes, these kinds of floating
// point comparisons can fail when the bit pattern is not the same.
if abs(x - 1.0_f32) < f32::EPSILON {
return 0.0_f32;
}
let x_less_than_1: bool = x < 1.0;
// Note: we could use the fast inverse approximation here found in super::inv::inv_approx, but
// the precision of such an approximation is assumed not good enough.
// Note: we could use the fast inverse approximation here found in
// super::inv::inv_approx, but the precision of such an approximation is
// assumed not good enough.
let x_working: f32 = if x_less_than_1 { 1.0 / x } else { x };
//according to the SO post ln(x) = ln((2^n)*y)= ln(2^n) + ln(y) = ln(2) * n + ln(y)
//get exponent value
// According to the SO post:
// ln(x) = ln((2^n)*y)= ln(2^n) + ln(y) = ln(2) * n + ln(y)
// Get exponent value.
let base2_exponent: u32 = extract_exponent_value(x_working) as u32;
let divisor: f32 = f32::from_bits(x_working.to_bits() & EXPONENT_MASK);
//supposedly normalizing between 1.0 and 2.0
// Supposedly normalizing between 1.0 and 2.0.
let x_working: f32 = x_working / divisor;
//approximate polynomial generated from maple in the post using Remez Algorithm:
//https://en.wikipedia.org/wiki/Remez_algorithm
// Approximate polynomial generated from maple in the post using Remez
// Algorithm: https://en.wikipedia.org/wiki/Remez_algorithm.
let ln_1to2_polynomial: f32 = -1.741_793_9_f32
+ (2.821_202_6_f32
+ (-1.469_956_8_f32 + (0.447_179_55_f32 - 0.056_570_85_f32 * x_working) * x_working)
Expand All @@ -126,12 +129,11 @@ fn ln_1to2_series_approximation(x: f32) -> f32 {
}
}

/// Compute the base 10 logarithm of `f`.
pub fn log10(x: f32) -> f32 {
//using change of base log10(x) = ln(x)/ln(10)
// Using change of base log10(x) = ln(x)/ln(10)
let ln10_recip = f32::consts::LOG10_E;
let fract_base_ln = ln10_recip;
let value_ln = ln_1to2_series_approximation(x);
value_ln * fract_base_ln
}

//-----------------------------------------------------------
12 changes: 10 additions & 2 deletions kernel/src/utilities/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,13 @@ mod static_ref;

pub use self::static_ref::StaticRef;

/// Re-export the tock-register-interface library.
/// The Tock Register Interface.
///
/// This is a re-export of the `tock-register-interface` crate provided for
/// convenience.
///
/// The Tock Register Interface provides a mechanism for accessing hardware
/// registers and MMIO interfaces.
pub mod registers {
pub use tock_registers::fields::{Field, FieldValue};
pub use tock_registers::interfaces;
Expand All @@ -28,7 +34,9 @@ pub mod registers {
pub use tock_registers::{LocalRegisterCopy, RegisterLongName};
}

/// Create a "fake" module inside of `common` for all of the Tock `Cell` types.
/// The Tock `Cell` types.
///
/// This is a re-export of the `tock-cells` crate provided for convenience.
///
/// To use `TakeCell`, for example, users should use:
///
Expand Down
52 changes: 24 additions & 28 deletions kernel/src/utilities/mut_imut_buffer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,36 +2,30 @@
// SPDX-License-Identifier: Apache-2.0 OR MIT
// Copyright Tock Contributors 2022.

//! An enum that can contain a reference to either a mutable or
//! an immutable buffer.
//!
//! This type is intended for internal use in implementations of HILs
//! or abstractions which need to handle both mutable and immutable
//! buffers.
//!
//! One motivating use case is keys for public key
//! cryptography. Public keys are often distributed as constant values
//! in the flash of a kernel image (e.g., to verify signatures), which
//! requires they be immutable. Copying them to RAM is expensive
//! because these keys can be very large (e.g., 512 bytes for a
//! 4096-bit RSA key). At the same time, some clients may use
//! dynamically generated or received keys, which are stored in
//! mutable RAM. Requiring that keys be immutable would
//! discard mut on this memory. An
//! implementation can use this type to store either mutable and
//! immutable buffers. The OTBN (OpenTitan Big Number accelerator) is
//! one example use of MutImutBuffer.
//!
//! Because this type requires dynamic runtime checks that types
//! match, it should not be used in any HILs or standard, external
//! APIs. It is intended only for internal use in implementations.
//!
//! Author: Alistair Francis
//! An enum that can contain a reference to either a mutable or an immutable
//! buffer.
//!
//! This type is intended for internal use in implementations of HILs or
//! abstractions which need to handle both mutable and immutable buffers.
//!
//! One motivating use case is keys for public key cryptography. Public keys are
//! often distributed as constant values in the flash of a kernel image (e.g.,
//! to verify signatures), which requires they be immutable. Copying them to
//! RAM is expensive because these keys can be very large (e.g., 512 bytes for a
//! 4096-bit RSA key). At the same time, some clients may use dynamically
//! generated or received keys, which are stored in mutable RAM. Requiring that
//! keys be immutable would discard `mut` on this memory. An implementation can
//! use this type to store either mutable and immutable buffers. The OTBN
//! (OpenTitan Big Number accelerator) is one example use of [`MutImutBuffer`].
//!
//! Because this type requires dynamic runtime checks that types match, it
//! should not be used in any HILs or standard, external APIs. It is intended
//! only for internal use within implementations.
//!
//! Usage
//! -----
//!
//! ```rust
//! ```rust
//! use kernel::utilities::mut_imut_buffer::MutImutBuffer;
//!
//! let mut mutable = ['a', 'b', 'c', 'd'];
Expand All @@ -41,14 +35,16 @@
//! let shared_buf2 = MutImutBuffer::Immutable(&immutable);
//! ```

/// An enum which can hold either a mutable or an immutable buffer
// Author: Alistair Francis

/// An enum which can hold either a mutable or an immutable buffer.
pub enum MutImutBuffer<'a, T> {
Mutable(&'a mut [T]),
Immutable(&'a [T]),
}

impl<'a, T> MutImutBuffer<'a, T> {
/// Returns the length of the underlying buffer
/// Returns the length of the underlying buffer.
pub fn len(&self) -> usize {
match self {
MutImutBuffer::Mutable(buf) => buf.len(),
Expand Down
Loading

0 comments on commit 971d06a

Please sign in to comment.