You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

99 lines
3.2 KiB
Rust

// SPDX-License-Identifier: MIT OR Apache-2.0
//
// Copyright (c) 2018-2022 Andre Richter <andre.o.richter@gmail.com>
//! BSP console facilities.
use crate::{bsp::device_driver, console, cpu, driver};
use core::fmt;
//--------------------------------------------------------------------------------------------------
// Public Code
//--------------------------------------------------------------------------------------------------
/// In case of a panic, the panic handler uses this function to take a last shot at printing
/// something before the system is halted.
///
/// We try to init panic-versions of the GPIO and the UART. The panic versions are not protected
/// with synchronization primitives, which increases chances that we get to print something, even
/// when the kernel's default GPIO or UART instances happen to be locked at the time of the panic.
///
/// # Safety
///
/// - Use only for printing during a panic.
#[cfg(not(feature = "test_build"))]
pub unsafe fn panic_console_out() -> impl fmt::Write {
use driver::interface::DeviceDriver;
// If remapping of the driver's MMIO hasn't already happened, we won't be able to print. Just
// park the CPU core in this case.
let gpio_mmio_start_addr = match super::GPIO.virt_mmio_start_addr() {
None => cpu::wait_forever(),
Some(x) => x,
};
let uart_mmio_start_addr = match super::PL011_UART.virt_mmio_start_addr() {
None => cpu::wait_forever(),
Some(x) => x,
};
let mut panic_gpio = device_driver::PanicGPIO::new(gpio_mmio_start_addr);
let mut panic_uart = device_driver::PanicUart::new(uart_mmio_start_addr);
panic_gpio
.init(None)
.unwrap_or_else(|_| cpu::wait_forever());
panic_gpio.map_pl011_uart();
panic_uart
.init(None)
.unwrap_or_else(|_| cpu::wait_forever());
panic_uart
}
/// Reduced version for test builds.
///
/// # Safety
///
/// - Use only for printing during a panic.
#[cfg(feature = "test_build")]
pub unsafe fn panic_console_out() -> impl fmt::Write {
use driver::interface::DeviceDriver;
let uart_mmio_start_addr = match super::PL011_UART.virt_mmio_start_addr() {
None => cpu::wait_forever(),
Some(x) => x,
};
let mut panic_uart = device_driver::PanicUart::new(uart_mmio_start_addr);
panic_uart
.init(None)
.unwrap_or_else(|_| cpu::qemu_exit_failure());
panic_uart
}
/// Return a reference to the console.
pub fn console() -> &'static impl console::interface::All {
&super::PL011_UART
}
//--------------------------------------------------------------------------------------------------
// Testing
//--------------------------------------------------------------------------------------------------
/// Minimal code needed to bring up the console in QEMU (for testing only). This is often less steps
/// than on real hardware due to QEMU's abstractions.
#[cfg(feature = "test_build")]
pub fn qemu_bring_up_console() {
use driver::interface::DeviceDriver;
// Calling the UART's init ensures that the BSP's instance of the UART does remap the MMIO
// addresses.
unsafe {
super::PL011_UART
.init()
.unwrap_or_else(|_| cpu::qemu_exit_failure());
}
}