// SPDX-FileCopyrightText: 2020 Sean Cross // SPDX-License-Identifier: Apache-2.0 use core::fmt::{Error, Write}; #[cfg(target_os = "none")] use utralib::generated::*; pub static mut DEBUG_OUTPUT: Option<&'static mut dyn Write> = None; #[macro_use] #[cfg(all( not(test), target_os = "none", 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), target_os = "none", any(feature = "debug-print", feature = "print-panics") ))] pub use crate::debug::debug_print_hardware::SUPERVISOR_UART_ADDR; #[cfg(all(target_os = "none"))] #[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(target_os = "none")] #[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(target_os = "none")] pub struct Uart {} #[cfg(target_os = "none")] pub static mut UART: Uart = Uart {}; #[cfg(all(target_os = "none", feature = "wrap-print"))] static mut CHAR_COUNT: usize = 0; #[cfg(target_os = "none")] 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 { if unsafe { DEBUG_OUTPUT.is_none() } { return None; } let 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::RXEMPTY_RXEMPTY) { 1 => None, _ => Some(uart_csr.r(utra::uart::RXTX) as u8), } } pub fn acknowledge_irq(&self) { if unsafe { DEBUG_OUTPUT.is_none() } { return; } let mut uart_csr = CSR::new(crate::debug::SUPERVISOR_UART_ADDR as *mut u32); uart_csr.wfo(utra::uart::EV_PENDING_RX, 1); } } #[cfg(all(feature = "gdbserver", target_os = "none"))] mod gdb_server; #[cfg(all(feature = "gdbserver", target_os = "none"))] impl gdbstub::Connection for Uart { type Error = (); fn write(&mut self, byte: u8) -> Result<(), Self::Error> { if unsafe { DEBUG_OUTPUT.is_none() } { return Err(()); } let mut uart_csr = CSR::new(crate::debug::SUPERVISOR_UART_ADDR as *mut u32); // Wait until TXFULL is not `0` while uart_csr.r(utra::uart::TXFULL) != 0 {} uart_csr.wo(utra::uart::RXTX, byte as u32); Ok(()) } fn peek(&mut self) -> Result, Self::Error> { Ok(None) } fn flush(&mut self) -> Result<(), Self::Error> { Ok(()) } } #[cfg(all( not(test), target_os = "none", 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(); } fn process_irq_character(b: u8) { #[cfg(all(feature = "gdbserver", target_os = "none"))] if gdb_server::handle(b) { return; } match b { 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() { println!( "{:?} {}:", process, system_services.process_name(process.pid).unwrap_or("") ); process.activate().unwrap(); } } 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); } #[cfg(all(feature = "gdbserver", target_os = "none"))] b'g' => { println!("Starting GDB server -- attach your debugger now"); gdb_server::setup(); } b'h' => { println!("Xous Kernel Debug"); println!("key | command"); println!("--- + -----------------------"); #[cfg(all(feature = "gdbserver", target_os = "none"))] println!(" g | enter the gdb server"); 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"); } _ => {} } } #[cfg(target_os = "none")] 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)+) => {{}}; }