Skip to content

Commit

Permalink
kernel: Split debug shell and uart driver.
Browse files Browse the repository at this point in the history
I've added a `platform` module to store all platform specific code, (not
architecture specific) as some platforms will require custom drivers, e.g.
for debug output and for the random number generation code.  The platform
code is in charge of mapping any peripherals needed to work, also to
initialize any other parts of the kernel that require drivers, for example
the debug shell.

Signed-off-by: Jean-Pierre De Jesus DIAZ <me@jeandudey.tech>
  • Loading branch information
jeandudey committed Nov 2, 2022
1 parent 4f9e6f1 commit b334e5b
Show file tree
Hide file tree
Showing 8 changed files with 431 additions and 350 deletions.
53 changes: 53 additions & 0 deletions kernel/src/debug/macros.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
// SPDX-FileCopyrightText: 2020 Sean Cross <sean@xobs.io>
// SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. <hello@foundationdevices.com>
// SPDX-License-Identifier: Apache-2.0

/// Prints to the debug output directly.
#[cfg(baremetal)]
#[macro_export]
macro_rules! print {
($($args:tt)+) => {{
#[allow(unused_unsafe)]
unsafe {
use core::fmt::Write;
if let Some(stream) = crate::debug::shell::OUTPUT.as_mut() {
write!(stream, $($args)+).unwrap();
}
}
}};
}

/// Prints to the debug output directly, with a newline.
#[cfg(baremetal)]
#[macro_export]
macro_rules! println {
() => ({
print!("\r\n")
});
($fmt:expr) => ({
print!(concat!($fmt, "\r\n"))
});
($fmt:expr, $($args:tt)+) => ({
print!(concat!($fmt, "\r\n"), $($args)+)
});
}

#[cfg(feature = "debug-print")]
#[macro_export]
macro_rules! klog {
() => ({
print!(" [{}:{}]", file!(), line!())
});
($fmt:expr) => ({
print!(concat!(" [{}:{} ", $fmt, "]"), file!(), line!())
});
($fmt:expr, $($args:tt)+) => ({
print!(concat!(" [{}:{} ", $fmt, "]"), file!(), line!(), $($args)+)
});
}

#[cfg(not(feature = "debug-print"))]
#[macro_export]
macro_rules! klog {
($($args:tt)+) => {{}};
}
315 changes: 2 additions & 313 deletions kernel/src/debug/mod.rs
Original file line number Diff line number Diff line change
@@ -1,318 +1,7 @@
// SPDX-FileCopyrightText: 2020 Sean Cross <sean@xobs.io>
// SPDX-License-Identifier: Apache-2.0

#[cfg(baremetal)]
use core::fmt::{Error, Write};
#[cfg(baremetal)]
use utralib::generated::*;

#[cfg(baremetal)]
pub static mut DEBUG_OUTPUT: Option<&'static mut dyn Write> = None;

pub use crate::arch::process::Process as ArchProcess;

#[macro_use]
#[cfg(all(
not(test),
baremetal,
any(feature = "debug-print", feature = "print-panics")
))]
pub mod debug_print_hardware {
// the HW device mapping is done in main.rs/init(); the virtual address has to be in the top 4MiB as it is the only page shared among all processes
pub const SUPERVISOR_UART_ADDR: *mut usize = 0xffcf_0000 as *mut usize; // see https://github.com/betrusted-io/xous-core/blob/master/docs/memory.md
}
#[cfg(all(
not(test),
baremetal,
any(feature = "debug-print", feature = "print-panics")
))]
pub use crate::debug::debug_print_hardware::SUPERVISOR_UART_ADDR;

#[cfg(baremetal)]
#[macro_export]
macro_rules! print {
($($args:tt)+) => {{
#[allow(unused_unsafe)]
unsafe {
if let Some(mut stream) = crate::debug::DEBUG_OUTPUT.as_mut() {
write!(&mut stream, $($args)+).unwrap();
}
}
}};
}

#[cfg(baremetal)]
#[macro_export]
macro_rules! println
{
() => ({
print!("\r\n")
});
($fmt:expr) => ({
print!(concat!($fmt, "\r\n"))
});
($fmt:expr, $($args:tt)+) => ({
print!(concat!($fmt, "\r\n"), $($args)+)
});
}

#[cfg(baremetal)]
pub struct Uart {}
mod macros;
#[cfg(baremetal)]
pub static mut UART: Uart = Uart {};

#[cfg(all(baremetal, feature = "wrap-print"))]
static mut CHAR_COUNT: usize = 0;

#[cfg(baremetal)]
impl Uart {
#[allow(dead_code)]
pub fn init(self) {
unsafe { DEBUG_OUTPUT = Some(&mut UART) };
let mut uart_csr = CSR::new(crate::debug::SUPERVISOR_UART_ADDR as *mut u32);
uart_csr.rmwf(utra::uart::EV_ENABLE_RX, 1);
}

pub fn putc(&self, c: u8) {
if unsafe { DEBUG_OUTPUT.is_none() } {
return;
}

let mut uart_csr = CSR::new(crate::debug::SUPERVISOR_UART_ADDR as *mut u32);
// Wait until TXFULL is `0`
while uart_csr.r(utra::uart::TXFULL) != 0 {}
#[cfg(feature = "wrap-print")]
unsafe {
if c == b'\n' {
CHAR_COUNT = 0;
} else if CHAR_COUNT > 80 {
CHAR_COUNT = 0;
self.putc(b'\n');
self.putc(b'\r');
self.putc(b' ');
self.putc(b' ');
self.putc(b' ');
self.putc(b' ');
} else {
CHAR_COUNT += 1;
}
}
uart_csr.wfo(utra::uart::RXTX_RXTX, c as u32);
}

#[allow(dead_code)]
pub fn getc(&self) -> Option<u8> {
if unsafe { DEBUG_OUTPUT.is_none() } {
return None;
}
let mut uart_csr = CSR::new(crate::debug::SUPERVISOR_UART_ADDR as *mut u32);
// If EV_PENDING_RX is 1, return the pending character.
// Otherwise, return None.
match uart_csr.rf(utra::uart::EV_PENDING_RX) {
0 => None,
_ => {
let ret = Some(uart_csr.r(utra::uart::RXTX) as u8);
uart_csr.wfo(utra::uart::EV_PENDING_RX, 1);
ret
}
}
}
}

#[cfg(all(
baremetal,
not(test),
any(feature = "debug-print", feature = "print-panics")
))]
pub fn irq(_irq_number: usize, _arg: *mut usize) {
let uart = Uart {};
while let Some(b) = uart.getc() {
process_irq_character(b);
}
// uart.acknowledge_irq();
}

#[cfg(all(
baremetal,
not(test),
any(feature = "debug-print", feature = "print-panics")
))]
fn process_irq_character(b: u8) {
match b {
b'i' => {
println!("Interrupt handlers:");
println!(" IRQ | Process | Handler | Argument");
crate::services::SystemServices::with(|system_services| {
crate::irq::for_each_irq(|irq, pid, address, arg| {
println!(
" {}: {} @ {:x?} {:x?}",
irq,
system_services.process_name(*pid).unwrap_or(""),
address,
arg
);
});
});
}
b'm' => {
println!("Printing memory page tables");
crate::services::SystemServices::with(|system_services| {
let current_pid = system_services.current_pid();
for process in &system_services.processes {
if !process.free() {
println!(
"PID {} {}:",
process.pid,
system_services.process_name(process.pid).unwrap_or("")
);
process.activate().unwrap();
crate::arch::mem::MemoryMapping::current().print_map();
println!();
}
}
system_services
.get_process(current_pid)
.unwrap()
.activate()
.unwrap();
});
}
b'p' => {
println!("Printing processes");
crate::services::SystemServices::with(|system_services| {
let current_pid = system_services.current_pid();
for process in &system_services.processes {
if !process.free() {
process.activate().unwrap();
let mut connection_count = 0;
ArchProcess::with_inner(|process_inner| {
for conn in &process_inner.connection_map {
if conn.is_some() {
connection_count += 1;
}
}
});
println!(
"{:?} conns:{}/32 {}",
process,
connection_count,
system_services.process_name(process.pid).unwrap_or("")
);
}
}
system_services
.get_process(current_pid)
.unwrap()
.activate()
.unwrap();
});
}
b'P' => {
println!("Printing processes and threads");
crate::services::SystemServices::with(|system_services| {
let current_pid = system_services.current_pid();
for process in &system_services.processes {
if !process.free() {
println!(
"{:?} {}:",
process,
system_services.process_name(process.pid).unwrap_or("")
);
process.activate().unwrap();
crate::arch::process::Process::with_current_mut(|arch_process| {
arch_process.print_all_threads()
});
println!();
}
}
system_services
.get_process(current_pid)
.unwrap()
.activate()
.unwrap();
});
}
b'r' => {
println!("RAM usage:");
let mut total_bytes = 0;
crate::services::SystemServices::with(|system_services| {
crate::mem::MemoryManager::with(|mm| {
for process in &system_services.processes {
if !process.free() {
let bytes_used = mm.ram_used_by(process.pid);
total_bytes += bytes_used;
println!(
" PID {:>3}: {:>4} k {}",
process.pid,
bytes_used / 1024,
system_services.process_name(process.pid).unwrap_or("")
);
}
}
});
});
println!("{} k total", total_bytes / 1024);
}
b's' => {
println!("Servers in use:");
crate::services::SystemServices::with(|system_services| {
println!(" idx | pid | process | sid");
println!(" --- + --- + -------------------- | ------------------");
for (idx, server) in system_services.servers.iter().enumerate() {
if let Some(s) = server {
println!(
" {:3} | {:3} | {:20} | {:x?}",
idx,
s.pid,
system_services.process_name(s.pid).unwrap_or(""),
s.sid
);
}
}
});
}
b'h' => {
println!("Xous Kernel Debug");
println!("key | command");
println!("--- + -----------------------");
println!(" i | print irq handlers");
println!(" m | print MMU page tables of all processes");
println!(" p | print all processes");
println!(" P | print all processes and threads");
println!(" r | report RAM usage of all processes");
println!(" s | print all allocated servers");
}
_ => {}
}
}

#[cfg(baremetal)]
impl Write for Uart {
fn write_str(&mut self, s: &str) -> Result<(), Error> {
for c in s.bytes() {
self.putc(c);
}
Ok(())
}
}

#[cfg(feature = "debug-print")]
#[macro_export]
macro_rules! klog
{
() => ({
print!(" [{}:{}]", file!(), line!())
});
($fmt:expr) => ({
print!(concat!(" [{}:{} ", $fmt, "]"), file!(), line!())
});
($fmt:expr, $($args:tt)+) => ({
print!(concat!(" [{}:{} ", $fmt, "]"), file!(), line!(), $($args)+)
});
}

#[cfg(not(feature = "debug-print"))]
#[macro_export]
macro_rules! klog {
($($args:tt)+) => {{}};
}
pub mod shell;
Loading

0 comments on commit b334e5b

Please sign in to comment.