From b334e5bc31e5e2da9f56be531142e83d27d9007f Mon Sep 17 00:00:00 2001 From: Jean-Pierre De Jesus DIAZ Date: Wed, 2 Nov 2022 13:30:20 +0100 Subject: [PATCH 1/6] kernel: Split debug shell and uart driver. 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 --- kernel/src/debug/macros.rs | 53 +++++ kernel/src/debug/mod.rs | 315 +------------------------- kernel/src/debug/shell.rs | 230 +++++++++++++++++++ kernel/src/io.rs | 14 ++ kernel/src/main.rs | 43 +--- kernel/src/platform/mod.rs | 12 + kernel/src/platform/precursor/mod.rs | 11 + kernel/src/platform/precursor/uart.rs | 103 +++++++++ 8 files changed, 431 insertions(+), 350 deletions(-) create mode 100644 kernel/src/debug/macros.rs create mode 100644 kernel/src/debug/shell.rs create mode 100644 kernel/src/io.rs create mode 100644 kernel/src/platform/mod.rs create mode 100644 kernel/src/platform/precursor/mod.rs create mode 100644 kernel/src/platform/precursor/uart.rs diff --git a/kernel/src/debug/macros.rs b/kernel/src/debug/macros.rs new file mode 100644 index 000000000..f05f19877 --- /dev/null +++ b/kernel/src/debug/macros.rs @@ -0,0 +1,53 @@ +// SPDX-FileCopyrightText: 2020 Sean Cross +// SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +// 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)+) => {{}}; +} diff --git a/kernel/src/debug/mod.rs b/kernel/src/debug/mod.rs index 5204d6fef..04452ee3e 100644 --- a/kernel/src/debug/mod.rs +++ b/kernel/src/debug/mod.rs @@ -1,318 +1,7 @@ // SPDX-FileCopyrightText: 2020 Sean Cross // 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; - +mod macros; #[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 {} -#[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 { - 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; diff --git a/kernel/src/debug/shell.rs b/kernel/src/debug/shell.rs new file mode 100644 index 000000000..86408ad97 --- /dev/null +++ b/kernel/src/debug/shell.rs @@ -0,0 +1,230 @@ +// SPDX-FileCopyrightText: 2020 Sean Cross +// SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +// SPDX-License-Identifier: Apache-2.0 + +use core::fmt; +use crate::{ + args::KernelArguments, + io::{SerialWrite, SerialRead}, +}; + +/// Instance of the shell output. +pub static mut OUTPUT: Option = None; + +/// Shell output. +pub struct Output { + serial: &'static mut dyn SerialWrite, + #[cfg(feature = "wrap-print")] + character_count: usize, +} + +impl Output { + fn new(serial: &'static mut dyn SerialWrite) -> Output { + Output { + serial, + #[cfg(feature = "wrap-print")] + character_count: 0, + } + } +} + +impl fmt::Write for Output { + fn write_str(&mut self, s: &str) -> fmt::Result { + for c in s.bytes() { + #[cfg(feature = "wrap-print")] + if c == b'\n' { + self.character_count = 0; + } else if self.character_count > 80 { + self.character_count = 0; + self.uart.putc(b'\n'); + self.uart.putc(b'\r'); + self.uart.putc(b' '); + self.uart.putc(b' '); + self.uart.putc(b' '); + self.uart.putc(b' '); + } else { + self.character_count += 1; + } + + self.serial.putc(c); + } + Ok(()) + } +} + +/// Initialize the kernel shell. +/// +/// This should be called in platform initialization code. +pub fn init(serial: &'static mut dyn SerialWrite) { + unsafe { + OUTPUT = Some(Output::new(serial)) + } + + // Print the processed kernel arguments + let args = KernelArguments::get(); + println!("Kernel arguments:"); + for arg in args.iter() { + println!(" {}", arg); + } +} + +/// Process possible characters received through a serial interface. +/// +/// This should be called when a serial interface has new data, for example, +/// on an interrupt. +pub fn process_characters(serial: &mut R) { + while let Some(b) = serial.getc() { + handle_character(b); + } +} + +fn handle_character(b: u8) { + use crate::services::ArchProcess; + + 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"); + } + _ => {} + } +} diff --git a/kernel/src/io.rs b/kernel/src/io.rs new file mode 100644 index 000000000..9caa56b9e --- /dev/null +++ b/kernel/src/io.rs @@ -0,0 +1,14 @@ +// SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +// SPDX-License-Identifier: Apache-2.0 + +/// A trait for serial like drivers which are byte-oriented sinks. +pub trait SerialWrite { + /// Write a single byte. + fn putc(&mut self, b: u8); +} + +/// A trait for serial like drivers which allows reading from a source. +pub trait SerialRead { + /// Read a single byte. + fn getc(&mut self) -> Option; +} diff --git a/kernel/src/main.rs b/kernel/src/main.rs index 60db7711d..0cb7c3ef0 100644 --- a/kernel/src/main.rs +++ b/kernel/src/main.rs @@ -18,9 +18,11 @@ mod arch; #[macro_use] mod args; +mod io; mod irq; mod macros; mod mem; +mod platform; mod server; mod services; mod syscall; @@ -59,45 +61,12 @@ pub unsafe extern "C" fn init(arg_offset: *const u32, init_offset: *const u32, r system_services.init_from_memory(init_offset, &args) }); - // Now that the memory manager is set up, perform any arch-specific initializations. + // Now that the memory manager is set up, perform any architecture and + // platform specific initializations. arch::init(); + platform::init(); - // Either map memory using a syscall, or if we're debugging the syscall - // handler then directly map it. - #[cfg(any(feature = "debug-print", feature = "print-panics"))] - { - use utralib::generated::*; - xous_kernel::claim_interrupt( - utra::uart::UART_IRQ, - debug::irq, - core::ptr::null_mut::(), - ) - .expect("Couldn't claim debug interrupt"); - // Map the serial port so println!() works as expected. - mem::MemoryManager::with_mut(|memory_manager| { - memory_manager - .map_range( - utra::uart::HW_UART_BASE as *mut u8, - ((debug::SUPERVISOR_UART_ADDR as u32) & !4095) as *mut u8, - 4096, - PID::new(1).unwrap(), - MemoryFlags::R | MemoryFlags::W, - MemoryType::Default, - ) - .expect("unable to map serial port") - }); - debug::Uart {}.init(); - println!("KMAIN (clean boot): Supervisor mode started..."); - println!("Claiming IRQ {} via syscall...", utra::uart::UART_IRQ); - print!("}} "); - - // Print the processed kernel arguments - let args = args::KernelArguments::get(); - println!("Kernel arguments:"); - for arg in args.iter() { - println!(" {}", arg); - } - } + println!("KMAIN (clean boot): Supervisor mode started..."); // rand::init() already clears the initial pipe, but pump the TRNG a little more out of no other reason than sheer paranoia arch::rand::get_u32(); diff --git a/kernel/src/platform/mod.rs b/kernel/src/platform/mod.rs new file mode 100644 index 000000000..66e742e3d --- /dev/null +++ b/kernel/src/platform/mod.rs @@ -0,0 +1,12 @@ +// SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +// SPDX-License-Identifier: Apache-2.0 + +#[cfg(any(feature="precursor", feature="renode"))] +pub mod precursor; + +/// Platform specific initialization. +#[cfg(not(any(unix, windows)))] +pub fn init() { + #[cfg(any(feature="precursor", feature="renode"))] + self::precursor::init(); +} \ No newline at end of file diff --git a/kernel/src/platform/precursor/mod.rs b/kernel/src/platform/precursor/mod.rs new file mode 100644 index 000000000..f02ec11ff --- /dev/null +++ b/kernel/src/platform/precursor/mod.rs @@ -0,0 +1,11 @@ +// SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +// SPDX-License-Identifier: Apache-2.0 + +#[cfg(any(feature = "debug-print", feature = "print-panics"))] +pub mod uart; + +/// Precursor specific initialization. +pub fn init() { + #[cfg(any(feature = "debug-print", feature = "print-panics"))] + self::uart::init(); +} \ No newline at end of file diff --git a/kernel/src/platform/precursor/uart.rs b/kernel/src/platform/precursor/uart.rs new file mode 100644 index 000000000..0001bbddb --- /dev/null +++ b/kernel/src/platform/precursor/uart.rs @@ -0,0 +1,103 @@ +// SPDX-FileCopyrightText: 2020 Sean Cross +// SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +// SPDX-License-Identifier: Apache-2.0 + +use crate::{ + io::{SerialWrite, SerialRead}, + mem::MemoryManager, + debug::shell::process_characters, + PID, +}; +use utralib::generated::*; +use xous_kernel::{MemoryFlags, MemoryType}; + +/// UART virtual address. +/// +/// See https://github.com/betrusted-io/xous-core/blob/master/docs/memory.md +pub const UART_ADDR: usize = 0xffcf_0000; + +/// UART instance. +/// +/// Initialized by [`init`]. +pub static mut UART: Option = None; + +/// UART peripheral driver. +pub struct Uart { + uart_csr: CSR, + callback: fn(&mut Self), +} + +impl Uart { + pub fn new(addr: usize, callback: fn(&mut Self)) -> Uart { + Uart { + uart_csr: CSR::new(addr as *mut u32), + callback, + } + } + + pub fn init(&mut self) { + self.uart_csr.rmwf(utra::uart::EV_ENABLE_RX, 1); + } + + pub fn irq(_irq_number: usize, arg: *mut usize) { + let uart = unsafe { &mut *(arg as *mut Uart) }; + (uart.callback)(uart); + // uart.acknowledge_irq(); + } +} + +impl SerialWrite for Uart { + fn putc(&mut self, c: u8) { + // Wait until TXFULL is `0` + while self.uart_csr.r(utra::uart::TXFULL) != 0 {} + self.uart_csr.wfo(utra::uart::RXTX_RXTX, c as u32); + } +} + +impl SerialRead for Uart { + fn getc(&mut self) -> Option { + // If EV_PENDING_RX is 1, return the pending character. + // Otherwise, return None. + match self.uart_csr.rf(utra::uart::EV_PENDING_RX) { + 0 => None, + _ => { + let ret = Some(self.uart_csr.r(utra::uart::RXTX) as u8); + self.uart_csr.wfo(utra::uart::EV_PENDING_RX, 1); + ret + } + } + } +} + +/// Initialize UART driver and debug shell. +pub fn init() { + // Map the UART peripheral. + MemoryManager::with_mut(|memory_manager| { + memory_manager + .map_range( + utra::uart::HW_UART_BASE as *mut u8, + (UART_ADDR & !4095) as *mut u8, + 4096, + PID::new(1).unwrap(), + MemoryFlags::R | MemoryFlags::W, + MemoryType::Default, + ) + .expect("unable to map serial port") + }); + + unsafe { + let mut uart = Uart::new(UART_ADDR, process_characters); + uart.init(); + + UART = Some(uart); + crate::debug::shell::init(UART.as_mut().unwrap()); + + // Claim UART interrupt. + println!("Claiming IRQ {} via syscall...", utra::uart::UART_IRQ); + xous_kernel::claim_interrupt( + utra::uart::UART_IRQ, + Uart::irq, + (UART.as_mut().unwrap() as *mut Uart) as *mut usize, + ).expect("Couldn't claim debug interrupt"); + } +} From d8807e6ceadafc1b175845cd0283f71f39c7318b Mon Sep 17 00:00:00 2001 From: Jean-Pierre De Jesus DIAZ Date: Wed, 2 Nov 2022 14:29:53 +0100 Subject: [PATCH 2/6] kernel: Move rand driver to platform module. Signed-off-by: Jean-Pierre De Jesus DIAZ --- kernel/src/arch/riscv/mod.rs | 2 - kernel/src/arch/riscv/rand.rs | 69 ------------------- kernel/src/main.rs | 4 +- kernel/src/platform/mod.rs | 2 + kernel/src/platform/precursor/mod.rs | 2 + kernel/src/platform/precursor/rand.rs | 98 +++++++++++++++++++++++++++ kernel/src/platform/precursor/uart.rs | 6 +- kernel/src/platform/rand.rs | 11 +++ kernel/src/services.rs | 9 +-- 9 files changed, 123 insertions(+), 80 deletions(-) delete mode 100644 kernel/src/arch/riscv/rand.rs create mode 100644 kernel/src/platform/precursor/rand.rs create mode 100644 kernel/src/platform/rand.rs diff --git a/kernel/src/arch/riscv/mod.rs b/kernel/src/arch/riscv/mod.rs index ac1d1fb99..eb2d5f784 100644 --- a/kernel/src/arch/riscv/mod.rs +++ b/kernel/src/arch/riscv/mod.rs @@ -7,7 +7,6 @@ pub mod exception; pub mod irq; pub mod mem; pub mod process; -pub mod rand; pub mod syscall; pub use process::Thread; @@ -49,7 +48,6 @@ pub fn init() { sie::set_ssoft(); sie::set_sext(); } - rand::init(); } /// Put the core to sleep until an interrupt hits. Returns `true` diff --git a/kernel/src/arch/riscv/rand.rs b/kernel/src/arch/riscv/rand.rs deleted file mode 100644 index c742af7f9..000000000 --- a/kernel/src/arch/riscv/rand.rs +++ /dev/null @@ -1,69 +0,0 @@ -// SPDX-FileCopyrightText: 2020 Sean Cross -// SPDX-License-Identifier: Apache-2.0 - -use crate::mem::MemoryManager; -use utralib::generated::*; -use xous_kernel::{MemoryFlags, MemoryType, PID}; - -pub const TRNG_KERNEL: Trng = Trng { - // the HW device mapping is done in xous-rs/src/lib.rs/init() - // the manually chosen virtual address has to be in the top 4MiB as it is the only page shared among all processes - base: 0xffce_0000 as *mut usize, // see https://github.com/betrusted-io/xous-core/blob/master/docs/memory.md -}; - -pub struct Trng { - pub base: *mut usize, -} - -pub fn init() { - // Map the TRNG so that we can allocate names - // hardware guarantees that: - // - TRNG will automatically power on - // - Both TRNGs are enabled, with conservative defaults - // - Kernel FIFO will fill with TRNGs such that at least the next 512 calls to get_u32() will succeed without delay - // - The kernel will start a TRNG server - // - All further security decisions and policies are 100% delegated to this new server. - MemoryManager::with_mut(|memory_manager| { - memory_manager - .map_range( - utra::trng_kernel::HW_TRNG_KERNEL_BASE as *mut u8, - ((TRNG_KERNEL.base as u32) & !4095) as *mut u8, - 4096, - PID::new(1).unwrap(), - MemoryFlags::R | MemoryFlags::W, - MemoryType::Default, - ) - .expect("unable to map TRNG") - }); - - let trng_kernel_csr = CSR::new(TRNG_KERNEL.base as *mut u32); - if false { // raw random path - left in for debugging urandom, can strip out later - while trng_kernel_csr.rf(utra::trng_kernel::STATUS_AVAIL) == 0 {} - // discard the first entry, as it is always 0x0000_0000 - // this is because the read register is a pipeline stage behind the FIFO - // once the pipeline has been filled, there is no need to prime it again. - trng_kernel_csr.rf(utra::trng_kernel::DATA_DATA); - } else { // urandom path (recommended) - // simulations show this isn't strictly necessary, but I prefer to have it - // just in case a subtle bug in the reset logic leaves something deterministic - // in the connecting logic: the simulation coverage stops at the edge of the TRNG block. - for _ in 0..4 { - // wait until the urandom port is initialized - while trng_kernel_csr.rf(utra::trng_kernel::URANDOM_VALID_URANDOM_VALID) == 0 {} - // pull a dummy piece of data - trng_kernel_csr.rf(utra::trng_kernel::URANDOM_URANDOM); - } - } - -} - -pub fn get_u32() -> u32 { - let trng_kernel_csr = CSR::new(TRNG_KERNEL.base as *mut u32); - if false { // raw random path - while trng_kernel_csr.rf(utra::trng_kernel::STATUS_AVAIL) == 0 {} - trng_kernel_csr.rf(utra::trng_kernel::DATA_DATA) - } else { // urandom path (recommended) - while trng_kernel_csr.rf(utra::trng_kernel::URANDOM_VALID_URANDOM_VALID) == 0 {} - trng_kernel_csr.rf(utra::trng_kernel::URANDOM_URANDOM) - } -} diff --git a/kernel/src/main.rs b/kernel/src/main.rs index 0cb7c3ef0..cefd0191d 100644 --- a/kernel/src/main.rs +++ b/kernel/src/main.rs @@ -69,8 +69,8 @@ pub unsafe extern "C" fn init(arg_offset: *const u32, init_offset: *const u32, r println!("KMAIN (clean boot): Supervisor mode started..."); // rand::init() already clears the initial pipe, but pump the TRNG a little more out of no other reason than sheer paranoia - arch::rand::get_u32(); - arch::rand::get_u32(); + platform::rand::get_u32(); + platform::rand::get_u32(); } /// Loop through the SystemServices list to determine the next PID to be run. diff --git a/kernel/src/platform/mod.rs b/kernel/src/platform/mod.rs index 66e742e3d..850735f37 100644 --- a/kernel/src/platform/mod.rs +++ b/kernel/src/platform/mod.rs @@ -4,6 +4,8 @@ #[cfg(any(feature="precursor", feature="renode"))] pub mod precursor; +pub mod rand; + /// Platform specific initialization. #[cfg(not(any(unix, windows)))] pub fn init() { diff --git a/kernel/src/platform/precursor/mod.rs b/kernel/src/platform/precursor/mod.rs index f02ec11ff..40ffd80a0 100644 --- a/kernel/src/platform/precursor/mod.rs +++ b/kernel/src/platform/precursor/mod.rs @@ -3,9 +3,11 @@ #[cfg(any(feature = "debug-print", feature = "print-panics"))] pub mod uart; +pub mod rand; /// Precursor specific initialization. pub fn init() { + self::rand::init(); #[cfg(any(feature = "debug-print", feature = "print-panics"))] self::uart::init(); } \ No newline at end of file diff --git a/kernel/src/platform/precursor/rand.rs b/kernel/src/platform/precursor/rand.rs new file mode 100644 index 000000000..227dd370f --- /dev/null +++ b/kernel/src/platform/precursor/rand.rs @@ -0,0 +1,98 @@ +// SPDX-FileCopyrightText: 2020 Sean Cross +// SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +// SPDX-License-Identifier: Apache-2.0 + +use crate::mem::MemoryManager; +use utralib::generated::*; +use xous_kernel::{MemoryFlags, MemoryType, PID}; + +/// The manually chosen virtual address has to be in the top 4MiB as it is the +/// only page shared among all processes. +/// +/// See https://github.com/betrusted-io/xous-core/blob/master/docs/memory.md +pub const TRNG_KERNEL_ADDR: usize = 0xffce_0000; +pub static mut TRNG_KERNEL: Option = None; + +pub struct TrngKernel { + pub trng_kernel_csr: CSR, +} + +impl TrngKernel { + pub fn new(addr: usize) -> TrngKernel { + TrngKernel { + trng_kernel_csr: CSR::new(addr as *mut u32), + } + } + + pub fn init(&mut self) { + if false { // raw random path - left in for debugging urandom, can strip out later + while self.trng_kernel_csr.rf(utra::trng_kernel::STATUS_AVAIL) == 0 {} + // discard the first entry, as it is always 0x0000_0000 + // this is because the read register is a pipeline stage behind the FIFO + // once the pipeline has been filled, there is no need to prime it again. + self.trng_kernel_csr.rf(utra::trng_kernel::DATA_DATA); + } else { // urandom path (recommended) + // simulations show this isn't strictly necessary, but I prefer to have it + // just in case a subtle bug in the reset logic leaves something deterministic + // in the connecting logic: the simulation coverage stops at the edge of the TRNG block. + for _ in 0..4 { + // wait until the urandom port is initialized + while self.trng_kernel_csr.rf(utra::trng_kernel::URANDOM_VALID_URANDOM_VALID) == 0 {} + // pull a dummy piece of data + self.trng_kernel_csr.rf(utra::trng_kernel::URANDOM_URANDOM); + } + } + } + + pub fn get_u32(&mut self) -> u32 { + if false { // raw random path + while self.trng_kernel_csr.rf(utra::trng_kernel::STATUS_AVAIL) == 0 {} + self.trng_kernel_csr.rf(utra::trng_kernel::DATA_DATA) + } else { // urandom path (recommended) + while self.trng_kernel_csr.rf(utra::trng_kernel::URANDOM_VALID_URANDOM_VALID) == 0 {} + self.trng_kernel_csr.rf(utra::trng_kernel::URANDOM_URANDOM) + } + } +} + +/// Initialize TRNG driver. +/// +/// Needed so that the kernel can allocate names. +pub fn init() { + // Map the TRNG so that we can allocate names + // hardware guarantees that: + // - TRNG will automatically power on + // - Both TRNGs are enabled, with conservative defaults + // - Kernel FIFO will fill with TRNGs such that at least the next 512 calls to get_u32() will succeed without delay + // - The kernel will start a TRNG server + // - All further security decisions and policies are 100% delegated to this new server. + MemoryManager::with_mut(|memory_manager| { + memory_manager + .map_range( + utra::trng_kernel::HW_TRNG_KERNEL_BASE as *mut u8, + (TRNG_KERNEL_ADDR & !4095) as *mut u8, + 4096, + PID::new(1).unwrap(), + MemoryFlags::R | MemoryFlags::W, + MemoryType::Default, + ) + .expect("unable to map TRNG_KERNEL") + }); + + let mut trng_kernel = TrngKernel::new(TRNG_KERNEL_ADDR); + trng_kernel.init(); + + unsafe { + TRNG_KERNEL = Some(trng_kernel); + } +} + +/// Retrieve random `u32`. +pub fn get_u32() -> u32 { + unsafe { + TRNG_KERNEL + .as_mut() + .expect("TRNG_KERNEL driver not initialized") + .get_u32() + } +} diff --git a/kernel/src/platform/precursor/uart.rs b/kernel/src/platform/precursor/uart.rs index 0001bbddb..0aa42c855 100644 --- a/kernel/src/platform/precursor/uart.rs +++ b/kernel/src/platform/precursor/uart.rs @@ -85,10 +85,10 @@ pub fn init() { .expect("unable to map serial port") }); - unsafe { - let mut uart = Uart::new(UART_ADDR, process_characters); - uart.init(); + let mut uart = Uart::new(UART_ADDR, process_characters); + uart.init(); + unsafe { UART = Some(uart); crate::debug::shell::init(UART.as_mut().unwrap()); diff --git a/kernel/src/platform/rand.rs b/kernel/src/platform/rand.rs new file mode 100644 index 000000000..22c5027c1 --- /dev/null +++ b/kernel/src/platform/rand.rs @@ -0,0 +1,11 @@ +// SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. +// SPDX-License-Identifier: Apache-2.0 + +pub fn get_u32() -> u32 { + // hosted rand code is coupled with arch code. + #[cfg(any(windows, unix))] + let rand = crate::arch::rand::get_u32(); + #[cfg(any(feature="precursor", feature="renode"))] + let rand = crate::platform::precursor::rand::get_u32(); + rand +} \ No newline at end of file diff --git a/kernel/src/services.rs b/kernel/src/services.rs index cbfd0d5c3..1f4b7a24b 100644 --- a/kernel/src/services.rs +++ b/kernel/src/services.rs @@ -5,6 +5,7 @@ use crate::arch; use crate::arch::mem::MemoryMapping; pub use crate::arch::process::Process as ArchProcess; pub use crate::arch::process::Thread; +use crate::platform; use xous_kernel::arch::ProcessStartup; use xous_kernel::MemoryRange; @@ -1742,10 +1743,10 @@ impl SystemServices { /// any processes. pub fn create_server_id(&mut self) -> Result { let sid = SID::from_u32( - arch::rand::get_u32(), - arch::rand::get_u32(), - arch::rand::get_u32(), - arch::rand::get_u32(), + platform::rand::get_u32(), + platform::rand::get_u32(), + platform::rand::get_u32(), + platform::rand::get_u32(), ); Ok(sid) } From ba46c6b04a0643fa8f6d198d1489da0582b4e511 Mon Sep 17 00:00:00 2001 From: bunnie Date: Thu, 3 Nov 2022 01:41:24 +0800 Subject: [PATCH 3/6] bump kernel version --- kernel/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kernel/Cargo.toml b/kernel/Cargo.toml index 2c12d81c9..2007d41f5 100644 --- a/kernel/Cargo.toml +++ b/kernel/Cargo.toml @@ -4,7 +4,7 @@ description = "Core kernel for Xous, including task switching and memory managem license = "MIT OR Apache-2.0" edition = "2018" name = "xous-kernel" -version = "0.9.13" +version = "0.9.14" resolver = "2" # Dependency versions enforced by Cargo.lock. From bbb7e279cd5dab3c6ef7429f1de9168ef582a6f8 Mon Sep 17 00:00:00 2001 From: bunnie Date: Thu, 3 Nov 2022 01:42:59 +0800 Subject: [PATCH 4/6] bump kernel version (this time with feeling) --- kernel/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kernel/Cargo.toml b/kernel/Cargo.toml index 2007d41f5..50254b6aa 100644 --- a/kernel/Cargo.toml +++ b/kernel/Cargo.toml @@ -4,7 +4,7 @@ description = "Core kernel for Xous, including task switching and memory managem license = "MIT OR Apache-2.0" edition = "2018" name = "xous-kernel" -version = "0.9.14" +version = "0.9.15" resolver = "2" # Dependency versions enforced by Cargo.lock. From 80094aef1e764f392da615b36ac8bd9b90b72464 Mon Sep 17 00:00:00 2001 From: bunnie Date: Thu, 3 Nov 2022 01:49:28 +0800 Subject: [PATCH 5/6] I see what's happening. The PR originator versions are very out of date. hopefully this fixes the issue. --- kernel/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kernel/Cargo.toml b/kernel/Cargo.toml index 50254b6aa..138f99bcf 100644 --- a/kernel/Cargo.toml +++ b/kernel/Cargo.toml @@ -4,7 +4,7 @@ description = "Core kernel for Xous, including task switching and memory managem license = "MIT OR Apache-2.0" edition = "2018" name = "xous-kernel" -version = "0.9.15" +version = "0.9.18" resolver = "2" # Dependency versions enforced by Cargo.lock. From 2cf4622f680b61f39fc8dda22fe5daa24a18f0f4 Mon Sep 17 00:00:00 2001 From: bunnie Date: Thu, 3 Nov 2022 01:50:36 +0800 Subject: [PATCH 6/6] commit lockfile and verification pins --- Cargo.lock | 2 +- xtask/src/main.rs | 2 +- xtask/src/verifier.rs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 461ac5bca..259ca6a0c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4809,7 +4809,7 @@ dependencies = [ [[package]] name = "xous-kernel" -version = "0.9.13" +version = "0.9.18" dependencies = [ "bitflags", "crossbeam-channel", diff --git a/xtask/src/main.rs b/xtask/src/main.rs index a8709becc..f991de75d 100644 --- a/xtask/src/main.rs +++ b/xtask/src/main.rs @@ -122,7 +122,7 @@ fn main() -> Result<(), Box> { "xous-susres@0.1.15", // ticktimer registers with susres to coordinate time continuity across sleeps "xous-ticktimer@0.1.14", // "well known" service: thread scheduling ].to_vec(); - let xous_kernel_remote = "xous-kernel@0.9.13"; + let xous_kernel_remote = "xous-kernel@0.9.18"; // ---- extract position independent args ---- let lkey = get_flag("--lkey")?; diff --git a/xtask/src/verifier.rs b/xtask/src/verifier.rs index f775cbb99..666e686aa 100644 --- a/xtask/src/verifier.rs +++ b/xtask/src/verifier.rs @@ -11,7 +11,7 @@ pub fn check_project_consistency() -> Result<(), DynError> { let check_pkgs = [ // this set updates with kernel API changes "xous@0.9.20", - "xous-kernel@0.9.13", + "xous-kernel@0.9.18", "xous-ipc@0.9.20", "xous-api-log@0.1.14", "xous-api-names@0.9.15",