Thanks to visit codestin.com
Credit goes to github.com

Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
105 changes: 64 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,10 @@ 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 +591,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 +608,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 +625,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 +637,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 +647,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 +704,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 @@ -714,6 +736,7 @@ macro_rules! debug_expr {
};
}

/// 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
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-panicking 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
Loading
Loading