Skip to content

Commit

Permalink
kernel: debug: add missing documentation
Browse files Browse the repository at this point in the history
Also reformat comments.
  • Loading branch information
bradjc committed Oct 10, 2024
1 parent 971d06a commit 293b690
Showing 1 changed file with 63 additions and 41 deletions.
104 changes: 63 additions & 41 deletions kernel/src/debug.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@
//! If you are writing and the buffer fills up, you can make the size of
//! `output_buffer` larger.
//!
//! Before debug interfaces can be used, the board file must assign them hardware:
//! Before debug interfaces can be used, the board file must assign them
//! hardware:
//!
//! ```ignore
//! kernel::debug::assign_gpios(
Expand All @@ -17,11 +18,12 @@
//! None,
//! );
//!
//! components::debug_writer::DebugWriterComponent::new(uart_mux).finalize(components::debug_writer_component_static!());
//! components::debug_writer::DebugWriterComponent::new(uart_mux)
//! .finalize(components::debug_writer_component_static!());
//! ```
//!
//! The debug queue is optional, if not set in the board it is just ignored.
//! You can add one in the board file as follows:
//! The debug queue is optional, if not set in the board it is just ignored. You
//! can add one in the board file as follows:
//!
//! ```ignore
//! components::debug_queue::DebugQueueComponent::new()
Expand Down Expand Up @@ -70,14 +72,18 @@ use crate::utilities::cells::NumericCellExt;
use crate::utilities::cells::{MapCell, TakeCell};
use crate::ErrorCode;

/// This trait is similar to std::io::Write in that it takes bytes instead of a string (contrary to
/// core::fmt::Write), but io::Write isn't available in no_std (due to std::io::Error not being
/// available).
/// Implementation of `std::io::Write` for `no_std`.
///
/// Also, in our use cases, writes are infaillible, so the write function cannot return an Error,
/// however it might not be able to write everything, so it returns the number of bytes written.
/// This takes bytes instead of a string (contrary to [`core::fmt::Write`]), but
/// we cannot use `std::io::Write' as it isn't available in `no_std` (due to
/// `std::io::Error` not being available).
///
/// See also the tracking issue: <https://github.com/rust-lang/rfcs/issues/2262>
/// Also, in our use cases, writes are infallible, so the write function cannot
/// return an `Err`, however it might not be able to write everything, so it
/// returns the number of bytes written.
///
/// See also the tracking issue:
/// <https://github.com/rust-lang/rfcs/issues/2262>.
pub trait IoWrite {
fn write(&mut self, buf: &[u8]) -> usize;

Expand All @@ -99,13 +105,13 @@ pub trait IoWrite {

/// Tock panic routine, without the infinite LED-blinking loop.
///
/// This is useful for boards which do not feature LEDs to blink or
/// want to implement their own behaviour. This method returns after
/// performing the panic dump.
/// This is useful for boards which do not feature LEDs to blink or want to
/// implement their own behavior. This method returns after performing the panic
/// dump.
///
/// After this method returns, the system is no longer in a
/// well-defined state. Care must be taken on how one interacts with
/// the system once this function returns.
/// After this method returns, the system is no longer in a well-defined state.
/// Care must be taken on how one interacts with the system once this function
/// returns.
///
/// **NOTE:** The supplied `writer` must be synchronous.
pub unsafe fn panic_print<W: Write + IoWrite, C: Chip, PP: ProcessPrinter>(
Expand All @@ -122,11 +128,10 @@ pub unsafe fn panic_print<W: Write + IoWrite, C: Chip, PP: ProcessPrinter>(
panic_banner(writer, panic_info);
panic_cpu_state(chip, writer);

// Some systems may enforce memory protection regions for the
// kernel, making application memory inaccessible. However,
// printing process information will attempt to access memory. If
// we are provided a chip reference, attempt to disable userspace
// memory protection first:
// Some systems may enforce memory protection regions for the kernel, making
// application memory inaccessible. However, printing process information
// will attempt to access memory. If we are provided a chip reference,
// attempt to disable userspace memory protection first:
chip.map(|c| {
use crate::platform::mpu::MPU;
c.mpu().disable_app_mpu()
Expand All @@ -149,8 +154,8 @@ pub unsafe fn panic<L: hil::led::Led, W: Write + IoWrite, C: Chip, PP: ProcessPr
chip: &'static Option<&'static C>,
process_printer: &'static Option<&'static PP>,
) -> ! {
// Call `panic_print` first which will print out the panic
// information and return
// Call `panic_print` first which will print out the panic information and
// return
panic_print(writer, panic_info, nop, processes, chip, process_printer);

// The system is no longer in a well-defined state, we cannot
Expand Down Expand Up @@ -260,12 +265,14 @@ pub fn panic_blink_forever<L: hil::led::Led>(leds: &mut [&L]) -> ! {
///////////////////////////////////////////////////////////////////
// debug_gpio! support

/// Object to hold the assigned debugging GPIOs.
pub static mut DEBUG_GPIOS: (
Option<&'static dyn hil::gpio::Pin>,
Option<&'static dyn hil::gpio::Pin>,
Option<&'static dyn hil::gpio::Pin>,
) = (None, None, None);

/// Map up to three GPIO pins to use for debugging.
pub unsafe fn assign_gpios(
gpio0: Option<&'static dyn hil::gpio::Pin>,
gpio1: Option<&'static dyn hil::gpio::Pin>,
Expand All @@ -276,7 +283,7 @@ pub unsafe fn assign_gpios(
DEBUG_GPIOS.2 = gpio2;
}

/// In-kernel gpio debugging, accepts any GPIO HIL method
/// In-kernel gpio debugging that accepts any GPIO HIL method.
#[macro_export]
macro_rules! debug_gpio {
($i:tt, $method:ident $(,)?) => {{
Expand All @@ -290,8 +297,8 @@ macro_rules! debug_gpio {
///////////////////////////////////////////////////////////////////
// debug_enqueue! support

/// Wrapper type that we need a mutable reference to for the core::fmt::Write
/// interface.
/// Wrapper type that we need a mutable reference to for the
/// [`core::fmt::Write`] interface.
pub struct DebugQueueWrapper {
dw: MapCell<&'static DebugQueue>,
}
Expand All @@ -304,6 +311,7 @@ impl DebugQueueWrapper {
}
}

/// Queue to hold debug strings.
pub struct DebugQueue {
ring_buffer: TakeCell<'static, RingBuffer<'static, u8>>,
}
Expand All @@ -316,6 +324,7 @@ impl DebugQueue {
}
}

/// Global reference used by debug macros.
static mut DEBUG_QUEUE: Option<&'static mut DebugQueueWrapper> = None;

/// Function used by board main.rs to set a reference to the debug queue.
Expand All @@ -338,13 +347,15 @@ impl Write for DebugQueueWrapper {
}
}

/// Add a format string to the debug queue.
pub fn debug_enqueue_fmt(args: Arguments) {
unsafe { DEBUG_QUEUE.as_deref_mut() }.map(|buffer| {
let _ = write(buffer, args);
let _ = buffer.write_str("\r\n");
});
}

/// Flush the debug queue by writing to the underlying writer implementation.
pub fn debug_flush_queue_() {
let writer = unsafe { get_debug_writer() };

Expand All @@ -358,8 +369,11 @@ pub fn debug_flush_queue_() {
}
}

/// This macro prints a new line to an internal ring buffer, the contents of
/// which are only flushed with `debug_flush_queue!` and in the panic handler.
/// Add a new line to an internal ring buffer.
///
/// The internal queue is only flushed with
/// [`debug_flush_queue!()`](crate::debug_flush_queue) or within the panic
/// handler.
#[macro_export]
macro_rules! debug_enqueue {
() => ({
Expand All @@ -373,8 +387,7 @@ macro_rules! debug_enqueue {
});
}

/// This macro flushes the contents of the debug queue into the regular
/// debug output.
/// Flushes the contents of the debug queue into the regular debug output.
#[macro_export]
macro_rules! debug_flush_queue {
() => {{
Expand All @@ -385,14 +398,13 @@ macro_rules! debug_flush_queue {
///////////////////////////////////////////////////////////////////
// debug! and debug_verbose! support

/// Wrapper type that we need a mutable reference to for the core::fmt::Write
/// interface.
/// Wrapper type that we need a mutable reference to for the
/// [`core::fmt::Write`] interface.
pub struct DebugWriterWrapper {
dw: MapCell<&'static DebugWriter>,
}

/// Main type that we need an immutable reference to so we can share it with
/// the UART provider and this debug module.
/// Main type that we share with the UART provider and this debug module.
pub struct DebugWriter {
// What provides the actual writing mechanism.
uart: &'static dyn hil::uart::Transmit<'static>,
Expand All @@ -404,8 +416,9 @@ pub struct DebugWriter {
count: Cell<usize>,
}

/// Static variable that holds the kernel's reference to the debug tool. This is
/// needed so the debug!() macros have a reference to the object to use.
/// Static variable that holds the kernel's reference to the debug tool.
///
/// This is needed so the debug!() macros have a reference to the object to use.
static mut DEBUG_WRITER: Option<&'static mut DebugWriterWrapper> = None;

unsafe fn try_get_debug_writer() -> Option<&'static mut DebugWriterWrapper> {
Expand Down Expand Up @@ -577,13 +590,15 @@ impl Write for DebugWriterWrapper {
}
}

/// Write a debug message without a trailing newline.
pub fn debug_print(args: Arguments) {
let writer = unsafe { get_debug_writer() };

let _ = write(writer, args);
writer.publish_bytes();
}

/// Write a debug message with a trailing newline.
pub fn debug_println(args: Arguments) {
let writer = unsafe { get_debug_writer() };

Expand All @@ -592,6 +607,7 @@ pub fn debug_println(args: Arguments) {
writer.publish_bytes();
}

/// Write a [`ReadableProcessSlice`] to the debug output.
pub fn debug_slice(slice: &ReadableProcessSlice) -> usize {
let writer = unsafe { get_debug_writer() };
let mut total = 0;
Expand All @@ -608,6 +624,7 @@ pub fn debug_slice(slice: &ReadableProcessSlice) -> usize {
total
}

/// Return how many bytes are remaining in the internal debug buffer.
pub fn debug_available_len() -> usize {
let writer = unsafe { get_debug_writer() };
writer.available_len()
Expand All @@ -619,6 +636,8 @@ fn write_header(writer: &mut DebugWriterWrapper, (file, line): &(&'static str, u
writer.write_fmt(format_args!("TOCK_DEBUG({}): {}:{}: ", count, file, line))
}

/// Write a debug message with file and line information without a trailing
/// newline.
pub fn debug_verbose_print(args: Arguments, file_line: &(&'static str, u32)) {
let writer = unsafe { get_debug_writer() };

Expand All @@ -627,6 +646,8 @@ pub fn debug_verbose_print(args: Arguments, file_line: &(&'static str, u32)) {
writer.publish_bytes();
}

/// Write a debug message with file and line information with a trailing
/// newline.
pub fn debug_verbose_println(args: Arguments, file_line: &(&'static str, u32)) {
let writer = unsafe { get_debug_writer() };

Expand Down Expand Up @@ -682,18 +703,18 @@ macro_rules! debug_verbose {
});
}

#[macro_export]
/// Prints out the expression and its location, then returns it.
///
/// ```rust,ignore
/// let foo: u8 = debug_expr!(0xff);
/// // Prints [main.rs:2] 0xff = 255
/// ```
/// Taken straight from Rust std::dbg.
/// Taken straight from Rust `std::dbg`.
#[macro_export]
macro_rules! debug_expr {
// NOTE: We cannot use `concat!` to make a static string as a format argument
// of `eprintln!` because `file!` could contain a `{` or
// `$val` expression could be a block (`{ .. }`), in which case the `eprintln!`
// NOTE: We cannot use `concat!` to make a static string as a format
// argument of `eprintln!` because `file!` could contain a `{` or `$val`
// expression could be a block (`{ .. }`), in which case the `eprintln!`
// will be malformed.
() => {
$crate::debug!("[{}:{}]", file!(), line!())
Expand All @@ -718,6 +739,7 @@ pub trait Debug {
fn write(&self, buf: &'static mut [u8], len: usize) -> usize;
}

/// Flush any stored messages to the output writer.
pub unsafe fn flush<W: Write + IoWrite>(writer: &mut W) {
if let Some(debug_writer) = try_get_debug_writer() {
if let Some(ring_buffer) = debug_writer.extract() {
Expand Down

0 comments on commit 293b690

Please sign in to comment.