Merge pull request #266 from Foundation-Devices/driver-refactor

kernel: Drivers refactor.
This commit is contained in:
bunnie 2022-11-03 01:53:38 +08:00 committed by GitHub
commit f59bbc2d2b
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
17 changed files with 555 additions and 431 deletions

2
Cargo.lock generated
View file

@ -4819,7 +4819,7 @@ dependencies = [
[[package]]
name = "xous-kernel"
version = "0.9.17"
version = "0.9.18"
dependencies = [
"bitflags",
"crossbeam-channel",

View file

@ -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.

View file

@ -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`

View file

@ -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)
}
}

View 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)+) => {{}};
}

View file

@ -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
View 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
View 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>;
}

View file

@ -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.

View 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();
}

View 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();
}

View 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()
}
}

View 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");
}
}

View 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
}

View file

@ -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)
}

View file

@ -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")?;

View file

@ -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",