mirror of
https://github.com/saymrwulf/xous-core.git
synced 2026-11-04 04:27:34 +00:00
Merge pull request #266 from Foundation-Devices/driver-refactor
kernel: Drivers refactor.
This commit is contained in:
commit
f59bbc2d2b
17 changed files with 555 additions and 431 deletions
2
Cargo.lock
generated
2
Cargo.lock
generated
|
|
@ -4819,7 +4819,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "xous-kernel"
|
||||
version = "0.9.17"
|
||||
version = "0.9.18"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"crossbeam-channel",
|
||||
|
|
|
|||
|
|
@ -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.17"
|
||||
version = "0.9.18"
|
||||
resolver = "2"
|
||||
|
||||
# Dependency versions enforced by Cargo.lock.
|
||||
|
|
|
|||
|
|
@ -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`
|
||||
|
|
|
|||
|
|
@ -1,69 +0,0 @@
|
|||
// SPDX-FileCopyrightText: 2020 Sean Cross <sean@xobs.io>
|
||||
// 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)
|
||||
}
|
||||
}
|
||||
53
kernel/src/debug/macros.rs
Normal file
53
kernel/src/debug/macros.rs
Normal file
|
|
@ -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)+) => {{}};
|
||||
}
|
||||
|
|
@ -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;
|
||||
|
||||
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<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;
|
||||
|
|
|
|||
230
kernel/src/debug/shell.rs
Normal file
230
kernel/src/debug/shell.rs
Normal file
|
|
@ -0,0 +1,230 @@
|
|||
// SPDX-FileCopyrightText: 2020 Sean Cross <sean@xobs.io>
|
||||
// SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. <hello@foundationdevices.com>
|
||||
// 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<Output> = 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<R: SerialRead>(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");
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
14
kernel/src/io.rs
Normal file
14
kernel/src/io.rs
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
// SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. <hello@foundationdevices.com>
|
||||
// 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<u8>;
|
||||
}
|
||||
|
|
@ -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,49 +61,16 @@ 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::<usize>(),
|
||||
)
|
||||
.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();
|
||||
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.
|
||||
|
|
|
|||
14
kernel/src/platform/mod.rs
Normal file
14
kernel/src/platform/mod.rs
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
// SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. <hello@foundationdevices.com>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
#[cfg(any(feature="precursor", feature="renode"))]
|
||||
pub mod precursor;
|
||||
|
||||
pub mod rand;
|
||||
|
||||
/// Platform specific initialization.
|
||||
#[cfg(not(any(unix, windows)))]
|
||||
pub fn init() {
|
||||
#[cfg(any(feature="precursor", feature="renode"))]
|
||||
self::precursor::init();
|
||||
}
|
||||
13
kernel/src/platform/precursor/mod.rs
Normal file
13
kernel/src/platform/precursor/mod.rs
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
// SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. <hello@foundationdevices.com>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
#[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();
|
||||
}
|
||||
98
kernel/src/platform/precursor/rand.rs
Normal file
98
kernel/src/platform/precursor/rand.rs
Normal file
|
|
@ -0,0 +1,98 @@
|
|||
// SPDX-FileCopyrightText: 2020 Sean Cross <sean@xobs.io>
|
||||
// SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. <hello@foundationdevices.com>
|
||||
// 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<TrngKernel> = None;
|
||||
|
||||
pub struct TrngKernel {
|
||||
pub trng_kernel_csr: CSR<u32>,
|
||||
}
|
||||
|
||||
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()
|
||||
}
|
||||
}
|
||||
103
kernel/src/platform/precursor/uart.rs
Normal file
103
kernel/src/platform/precursor/uart.rs
Normal file
|
|
@ -0,0 +1,103 @@
|
|||
// SPDX-FileCopyrightText: 2020 Sean Cross <sean@xobs.io>
|
||||
// SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. <hello@foundationdevices.com>
|
||||
// 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<Uart> = None;
|
||||
|
||||
/// UART peripheral driver.
|
||||
pub struct Uart {
|
||||
uart_csr: CSR<u32>,
|
||||
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<u8> {
|
||||
// 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")
|
||||
});
|
||||
|
||||
let mut uart = Uart::new(UART_ADDR, process_characters);
|
||||
uart.init();
|
||||
|
||||
unsafe {
|
||||
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");
|
||||
}
|
||||
}
|
||||
11
kernel/src/platform/rand.rs
Normal file
11
kernel/src/platform/rand.rs
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
// SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. <hello@foundationdevices.com>
|
||||
// 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
|
||||
}
|
||||
|
|
@ -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;
|
||||
|
||||
|
|
@ -1743,10 +1744,10 @@ impl SystemServices {
|
|||
/// any processes.
|
||||
pub fn create_server_id(&mut self) -> Result<SID, xous_kernel::Error> {
|
||||
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)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -122,7 +122,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|||
"xous-susres@0.1.18", // ticktimer registers with susres to coordinate time continuity across sleeps
|
||||
"xous-ticktimer@0.1.17", // "well known" service: thread scheduling
|
||||
].to_vec();
|
||||
let xous_kernel_remote = "xous-kernel@0.9.17";
|
||||
let xous_kernel_remote = "xous-kernel@0.9.18";
|
||||
|
||||
// ---- extract position independent args ----
|
||||
let lkey = get_flag("--lkey")?;
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ pub fn check_project_consistency() -> Result<(), DynError> {
|
|||
let check_pkgs = [
|
||||
// this set updates with kernel API changes
|
||||
"xous@0.9.23",
|
||||
"xous-kernel@0.9.17",
|
||||
"xous-kernel@0.9.18",
|
||||
"xous-ipc@0.9.23",
|
||||
"xous-api-log@0.1.17",
|
||||
"xous-api-names@0.9.18",
|
||||
|
|
|
|||
Loading…
Reference in a new issue