mirror of
https://github.com/saymrwulf/xous-core.git
synced 2026-11-08 04:56:43 +00:00
kernel integrations for cramium
This commit is contained in:
parent
ed7bdf2589
commit
3c13516d57
6 changed files with 345 additions and 4 deletions
|
|
@ -15,6 +15,7 @@ xous-kernel = { package = "xous", version = "0.9.47", features = [
|
|||
"forget-memory-messages",
|
||||
] }
|
||||
utralib = { version = "0.1.20", optional = true, default_features = false }
|
||||
rand_chacha = { version = "0.3.1", optional = true, default_features = false }
|
||||
|
||||
[target.'cfg(any(windows,unix))'.dev-dependencies]
|
||||
xous-kernel = { package = "xous", version = "0.9.47", features = [
|
||||
|
|
@ -36,6 +37,8 @@ xous-kernel = { package = "xous", version = "0.9.47", features = [
|
|||
critical-section = "1.1.1"
|
||||
|
||||
[features]
|
||||
cramium-soc = ["utralib/cramium-soc"]
|
||||
cramium-fpga = ["utralib/cramium-fpga"]
|
||||
atsama5d27 = ["utralib/atsama5d27"]
|
||||
precursor = ["utralib/precursor"]
|
||||
hosted = ["utralib/hosted"]
|
||||
|
|
@ -47,6 +50,11 @@ print-panics = []
|
|||
report-memory = ["stats_alloc"]
|
||||
wrap-print = []
|
||||
v2p = ["xous-kernel/v2p"]
|
||||
|
||||
# patches for simulation targets ONLY. Applying these flags will result in totally broken security.
|
||||
hwsim = []
|
||||
fake-rng = ["rand_chacha"] # works around lack of a real TRNG in the full-chip sim for now. This should go away for production.
|
||||
|
||||
# default = ["print-panics", "debug-print", "wrap-print"]
|
||||
default = ["print-panics"]
|
||||
|
||||
|
|
|
|||
|
|
@ -12,15 +12,22 @@ pub mod panic;
|
|||
|
||||
pub use process::Thread;
|
||||
|
||||
#[cfg(feature="precursor")]
|
||||
use utralib::generated::*;
|
||||
#[cfg(feature="precursor")]
|
||||
use xous_kernel::{MemoryFlags, MemoryType, PID};
|
||||
#[cfg(feature="precursor")]
|
||||
use crate::mem::MemoryManager;
|
||||
#[cfg(any(feature="cramium-soc", feature="cramium-fpga"))]
|
||||
use xous_kernel::PID;
|
||||
|
||||
#[cfg(feature="precursor")]
|
||||
pub const WFI_KERNEL: Wfi = Wfi {
|
||||
// the manually chosen virtual address has to be in the top 4MiB as it is the only page shared among all processes
|
||||
base: 0xffcd_0000 as *mut usize, // see https://github.com/betrusted-io/xous-core/blob/master/docs/memory.md
|
||||
};
|
||||
|
||||
#[cfg(feature="precursor")]
|
||||
pub struct Wfi {
|
||||
pub base: *mut usize,
|
||||
}
|
||||
|
|
@ -30,6 +37,7 @@ pub fn current_pid() -> PID {
|
|||
}
|
||||
|
||||
pub fn init() {
|
||||
#[cfg(feature="precursor")]
|
||||
MemoryManager::with_mut(|memory_manager| {
|
||||
memory_manager
|
||||
.map_range(
|
||||
|
|
@ -42,7 +50,9 @@ pub fn init() {
|
|||
)
|
||||
.expect("unable to map WFI")
|
||||
});
|
||||
#[cfg(feature="precursor")]
|
||||
let mut wfi_kernel_csr = CSR::new(WFI_KERNEL.base as *mut u32);
|
||||
#[cfg(feature="precursor")]
|
||||
wfi_kernel_csr.wfo(utra::wfi::IGNORE_LOCKED_IGNORE_LOCKED, 1);
|
||||
|
||||
unsafe {
|
||||
|
|
@ -54,14 +64,17 @@ pub fn init() {
|
|||
/// Put the core to sleep until an interrupt hits. Returns `true`
|
||||
/// to indicate the kernel should not exit.
|
||||
pub fn idle() -> bool {
|
||||
#[cfg(feature="precursor")]
|
||||
let mut wfi_kernel_csr = CSR::new(WFI_KERNEL.base as *mut u32);
|
||||
|
||||
// Issue `wfi`. This will return as soon as an external interrupt
|
||||
// is available.
|
||||
if false {
|
||||
// "traditional" path for stopping a clock - effectively a NOP, doesn't do anything
|
||||
unsafe { riscv::asm::wfi() };
|
||||
} else {
|
||||
#[cfg(any(feature="cramium-fpga", feature="cramium-soc"))]
|
||||
// "traditional" path for stopping a clock
|
||||
unsafe { riscv::asm::wfi() };
|
||||
|
||||
#[cfg(feature="precursor")]
|
||||
{
|
||||
// this invokes Precusor-SoC specific path to gate clocks:
|
||||
// 1. ignore_locked prevents the chip from going into reset if the PLL goes unlocked
|
||||
wfi_kernel_csr.wfo(utra::wfi::IGNORE_LOCKED_IGNORE_LOCKED, 1);
|
||||
|
|
|
|||
13
kernel/src/platform/cramium/mod.rs
Normal file
13
kernel/src/platform/cramium/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();
|
||||
}
|
||||
129
kernel/src/platform/cramium/rand.rs
Normal file
129
kernel/src/platform/cramium/rand.rs
Normal file
|
|
@ -0,0 +1,129 @@
|
|||
// SPDX-FileCopyrightText: 2020 Sean Cross <sean@xobs.io>
|
||||
// SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. <hello@foundationdevices.com>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
#[cfg(not(feature="fake-rng"))]
|
||||
use crate::mem::MemoryManager;
|
||||
#[cfg(not(feature="fake-rng"))]
|
||||
use utralib::generated::*;
|
||||
#[cfg(not(feature="fake-rng"))]
|
||||
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
|
||||
#[cfg(not(feature="fake-rng"))]
|
||||
pub const TRNG_KERNEL_ADDR: usize = 0xffce_0000;
|
||||
#[cfg(not(feature="fake-rng"))]
|
||||
pub static mut TRNG_KERNEL: Option<TrngKernel> = None;
|
||||
#[cfg(feature="fake-rng")]
|
||||
use core::sync::atomic::{AtomicU32, Ordering};
|
||||
#[cfg(feature="fake-rng")]
|
||||
static LOCAL_RNG_STATE: AtomicU32 = AtomicU32::new(2);
|
||||
|
||||
#[cfg(not(feature="fake-rng"))]
|
||||
pub struct TrngKernel {
|
||||
pub trng_kernel_csr: CSR<u32>,
|
||||
}
|
||||
|
||||
#[cfg(not(feature="fake-rng"))]
|
||||
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.
|
||||
#[cfg(not(feature="fake-rng"))]
|
||||
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`.
|
||||
#[cfg(not(feature="fake-rng"))]
|
||||
pub fn get_u32() -> u32 {
|
||||
unsafe {
|
||||
TRNG_KERNEL
|
||||
.as_mut()
|
||||
.expect("TRNG_KERNEL driver not initialized")
|
||||
.get_u32()
|
||||
}
|
||||
}
|
||||
|
||||
/// Initialize TRNG driver.
|
||||
///
|
||||
/// Needed so that the kernel can allocate names.
|
||||
#[cfg(feature="fake-rng")]
|
||||
pub fn init() {
|
||||
}
|
||||
|
||||
#[cfg(feature="fake-rng")]
|
||||
pub fn get_u32() -> u32 {
|
||||
use rand_chacha::ChaCha8Rng;
|
||||
use rand_chacha::rand_core::RngCore;
|
||||
use rand_chacha::rand_core::SeedableRng;
|
||||
|
||||
let mut rng = ChaCha8Rng::seed_from_u64(LOCAL_RNG_STATE.load(Ordering::SeqCst) as u64);
|
||||
let r = rng.next_u32();
|
||||
LOCAL_RNG_STATE.store(rng.next_u64() as u32, Ordering::SeqCst);
|
||||
r
|
||||
}
|
||||
169
kernel/src/platform/cramium/uart.rs
Normal file
169
kernel/src/platform/cramium/uart.rs
Normal file
|
|
@ -0,0 +1,169 @@
|
|||
// SPDX-FileCopyrightText: 2020 Sean Cross <sean@xobs.io>
|
||||
// SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. <hello@foundationdevices.com>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
#[cfg(feature="cramium-fpga")]
|
||||
use crate::{
|
||||
io::{SerialWrite, SerialRead},
|
||||
mem::MemoryManager,
|
||||
debug::shell::process_characters,
|
||||
PID,
|
||||
};
|
||||
#[cfg(feature="cramium-fpga")]
|
||||
use utralib::generated::*;
|
||||
#[cfg(feature="cramium-fpga")]
|
||||
use xous_kernel::{MemoryFlags, MemoryType};
|
||||
|
||||
#[cfg(feature="cramium-soc")]
|
||||
use crate::{
|
||||
io::{SerialWrite, SerialRead},
|
||||
debug::shell::process_characters,
|
||||
};
|
||||
|
||||
/// UART virtual address.
|
||||
///
|
||||
/// See https://github.com/betrusted-io/xous-core/blob/master/docs/memory.md
|
||||
pub const UART_ADDR: usize = 0xffcf_0000;
|
||||
pub const IRQ0_ADDR: usize = UART_ADDR + 0x1000;
|
||||
|
||||
/// UART instance.
|
||||
///
|
||||
/// Initialized by [`init`].
|
||||
pub static mut UART: Option<Uart> = None;
|
||||
|
||||
/// UART peripheral driver.
|
||||
#[cfg(feature="cramium-fpga")]
|
||||
pub struct Uart {
|
||||
uart_csr: CSR<u32>,
|
||||
irq_csr: CSR<u32>,
|
||||
callback: fn(&mut Self),
|
||||
}
|
||||
|
||||
#[cfg(feature="cramium-fpga")]
|
||||
impl Uart {
|
||||
pub fn new(addr: usize, irq_addr: usize, callback: fn(&mut Self)) -> Uart {
|
||||
Uart {
|
||||
uart_csr: CSR::new(addr as *mut u32),
|
||||
irq_csr: CSR::new(irq_addr as *mut u32),
|
||||
callback,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn init(&mut self) {
|
||||
self.uart_csr.rmwf(utra::uart::EV_ENABLE_RX, 1);
|
||||
self.irq_csr.rmwf(utra::irqarray0::EV_ENABLE_SOURCE0, 1);
|
||||
}
|
||||
|
||||
pub fn irq(_irq_number: usize, arg: *mut usize) {
|
||||
let uart = unsafe { &mut *(arg as *mut Uart) };
|
||||
(uart.callback)(uart);
|
||||
// uart.acknowledge_irq();
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature="cramium-fpga")]
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature="cramium-fpga")]
|
||||
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);
|
||||
self.irq_csr.wfo(utra::irqarray0::EV_PENDING_SOURCE0, 1);
|
||||
ret
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Initialize UART driver and debug shell.
|
||||
#[cfg(feature="cramium-fpga")]
|
||||
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")
|
||||
});
|
||||
// Map the IRQ0 handler
|
||||
MemoryManager::with_mut(|memory_manager| {
|
||||
memory_manager
|
||||
.map_range(
|
||||
utra::irqarray0::HW_IRQARRAY0_BASE as *mut u8,
|
||||
(IRQ0_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, IRQ0_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");
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature="cramium-soc")]
|
||||
pub fn init() { // there is no kernel UART yet...just a placeholder function
|
||||
let uart = Uart::new(UART_ADDR, IRQ0_ADDR, process_characters);
|
||||
unsafe{
|
||||
UART = Some(uart);
|
||||
crate::debug::shell::init(UART.as_mut().unwrap());
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature="cramium-soc")]
|
||||
pub struct Uart {
|
||||
}
|
||||
|
||||
#[cfg(feature="cramium-soc")]
|
||||
impl Uart {
|
||||
pub fn new(_addr: usize, _irq_addr: usize, _callback: fn(&mut Self)) -> Uart {
|
||||
Uart {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature="cramium-soc")]
|
||||
impl SerialWrite for Uart {
|
||||
fn putc(&mut self, _c: u8) {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature="cramium-soc")]
|
||||
impl SerialRead for Uart {
|
||||
fn getc(&mut self) -> Option<u8> {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
|
@ -7,6 +7,12 @@ pub mod precursor;
|
|||
#[cfg(any(feature = "atsama5d27"))]
|
||||
pub mod atsama5d2;
|
||||
|
||||
#[cfg(any(any(feature="cramium-soc", feature="cramium-fpga")))]
|
||||
pub mod cramium;
|
||||
|
||||
#[cfg(any(any(feature="cramium-soc", feature="cramium-fpga")))]
|
||||
pub use cramium::rand;
|
||||
#[cfg(not(any(feature="cramium-soc", feature="cramium-fpga")))]
|
||||
pub mod rand;
|
||||
|
||||
/// Platform specific initialization.
|
||||
|
|
@ -17,4 +23,7 @@ pub fn init() {
|
|||
|
||||
#[cfg(any(feature = "atsama5d27"))]
|
||||
self::atsama5d2::init();
|
||||
|
||||
#[cfg(any(feature="cramium-fpga", feature="cramium-soc"))]
|
||||
self::cramium::init();
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue