Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Cramium sim #612

Merged
merged 11 commits into from
Jan 1, 2025
4 changes: 2 additions & 2 deletions kernel/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,8 @@ unexpected_cfgs = { level = "warn", check-cfg = ['cfg(ci)', 'cfg(baremetal)'] }

[features]
cramium-soc = ["utralib/cramium-soc", "cramium-hal", "rand_chacha", "raw-trng"]
verilator-only = ["cramium-hal/verilator-only"]
cramium-fpga = ["utralib/cramium-fpga"]
verilator-only = []
cramium-fpga = ["utralib/cramium-fpga", "rand_chacha"]
board-baosec = ["cramium-hal/board-baosec"]
board-baosor = ["cramium-hal/board-baosor"]
board-dabao = ["cramium-hal/board-dabao"]
Expand Down
3 changes: 3 additions & 0 deletions kernel/src/debug/shell.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@
// SPDX-FileCopyrightText: 2023 Foundation Devices, Inc. <hello@foundationdevices.com>
// SPDX-License-Identifier: Apache-2.0

// allow all functions to go unused in case debug is disabled with a feature flag
#![allow(dead_code)]

use core::fmt;

use crate::{
Expand Down
6 changes: 6 additions & 0 deletions kernel/src/platform/cramium/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,13 @@
// SPDX-FileCopyrightText: 2024 bunnie <bunnie@kosagi.com>
// SPDX-License-Identifier: Apache-2.0

#[cfg(feature = "cramium-soc")]
pub mod rand;
#[cfg(feature = "cramium-fpga")]
pub mod rand_fake;
#[cfg(feature = "cramium-fpga")]
pub use rand_fake as rand;

#[cfg(any(feature = "debug-print", feature = "print-panics"))]
pub mod uart;

Expand Down
63 changes: 63 additions & 0 deletions kernel/src/platform/cramium/rand_fake.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
// SPDX-FileCopyrightText: 2020 Sean Cross <sean@xobs.io>
// SPDX-FileCopyrightText: 2022 Foundation Devices, Inc. <hello@foundationdevices.com>
// SPDX-FileCopyrightText: 2024 bunnie <bunnie@kosagi.com>
// SPDX-License-Identifier: Apache-2.0

use core::convert::TryInto;
use core::sync::atomic::{AtomicU32, Ordering};

use rand_chacha::ChaCha8Rng;
use rand_chacha::rand_core::RngCore;
use rand_chacha::rand_core::SeedableRng;

// This is the sum total of state used for simulations
static LOCAL_RNG_STATE: [AtomicU32; 8] = [
AtomicU32::new(0),
AtomicU32::new(0),
AtomicU32::new(0),
AtomicU32::new(0),
AtomicU32::new(0),
AtomicU32::new(0),
AtomicU32::new(0),
AtomicU32::new(1),
];

pub fn init() {}

/// This a fully deterministic PRNG that relies on Chacha8 for state evolution.
pub fn get_u32() -> u32 {
// Local storage for the seed.
let mut seed = [0u8; 32];

// Pull our true seed data from the static AtomicU32 variables. We have to do this because
// we're the kernel: any machine persistent state is by definition, global mutable state.
//
// Mix in more data from the TRNG while recovering the state from the kernel holding area.
for (s, state) in seed.chunks_mut(4).zip(LOCAL_RNG_STATE.iter()) {
let incoming = get_raw_u32() ^ state.load(Ordering::SeqCst);
for (s_byte, &incoming_byte) in s.iter_mut().zip(incoming.to_le_bytes().iter()) {
*s_byte ^= incoming_byte;
}
}
let mut cstrng = ChaCha8Rng::from_seed(seed);
// Mix up the internal state with output from the CSPRNG. We do this because the TRNG bits
// could be biased, and by running the CSPRNG forward based on the new seed, we have a chance to
// diffuse any true entropy over all bits in the seed pool.
for s in seed.chunks_mut(8) {
for (s_byte, chacha_byte) in s.iter_mut().zip(cstrng.next_u64().to_le_bytes()) {
*s_byte ^= chacha_byte;
}
}
// Now extract one value from the CSPRNG: this is the number we reveal to the outside world.
// It should not, in theory, be possible to deduce the seed from this value.
let ret_val = cstrng.next_u32();

// Save the mixed state into the kernel holding area
for (s, state) in seed.chunks(4).zip(LOCAL_RNG_STATE.iter()) {
state.store(u32::from_le_bytes(s.try_into().unwrap()), Ordering::SeqCst);
}
ret_val
}

/// There is no TRNG in simulation, just return a constant and rely on the chacha8 whitener
pub fn get_raw_u32() -> u32 { 0 }
108 changes: 16 additions & 92 deletions kernel/src/platform/cramium/uart.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,13 @@
// FIXME(static_mut_refs): Do not allow `static_mut_refs` lint
#![allow(static_mut_refs)]

#[cfg(feature = "cramium-soc")]
use utralib::generated::*;
#[cfg(feature = "cramium-soc")]
use xous_kernel::{MemoryFlags, MemoryType};

#[cfg(feature = "cramium-fpga")]
use crate::{
PID,
debug::shell::process_characters,
io::{SerialRead, SerialWrite},
mem::MemoryManager,
};
use crate::io::{SerialRead, SerialWrite};
#[cfg(feature = "cramium-soc")]
use crate::{
PID,
Expand All @@ -27,117 +24,44 @@ use crate::{
/// UART virtual address.
///
/// See https://github.com/betrusted-io/xous-core/blob/master/docs/memory.md
#[cfg(feature = "cramium-soc")]
pub const UART_ADDR: usize = 0xffcf_0000;
#[cfg(feature = "cramium-soc")]
pub const IRQ0_ADDR: usize = UART_ADDR + 0x1000;

/// UART instance.
///
/// Initialized by [`init`].
#[cfg(feature = "cramium-soc")]
pub static mut UART: Option<Uart> = None;

/// UART peripheral driver.
/// All dummy stubs for cramium-fpga because we want the console to have the DUART
#[cfg(feature = "cramium-fpga")]
pub struct Uart {
uart_csr: CSR<u32>,
irq_csr: CSR<u32>,
callback: fn(&mut Self),
}
pub fn init() {}

#[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 struct Uart {}

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);
}
#[cfg(feature = "cramium-fpga")]
#[allow(dead_code)]
impl Uart {
pub fn new(_addr: usize, _irq_addr: usize, _callback: fn(&mut Self)) -> Uart { Uart {} }

pub fn irq(_irq_number: usize, arg: *mut usize) {
let uart = unsafe { &mut *(arg as *mut Uart) };
(uart.callback)(uart);
// uart.acknowledge_irq();
}
pub fn init(&mut self) {}
}

#[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);
}
fn putc(&mut self, _c: u8) {}
}

#[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((&mut *(&raw mut 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,
((&mut *(&raw mut UART)).as_mut().unwrap() as *mut Uart) as *mut usize,
)
.expect("Couldn't claim debug interrupt");
}
fn getc(&mut self) -> Option<u8> { None }
}

#[cfg(feature = "cramium-soc")]
pub fn init() {
// there is no kernel UART yet...just a placeholder function
// Map the UART peripheral.
MemoryManager::with_mut(|memory_manager| {
memory_manager
Expand Down
2 changes: 1 addition & 1 deletion loader/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ board-baosec = [
]
board-baosor = ["cramium-hal/board-baosor"]
board-dabao = ["cramium-hal/board-dabao"]
cramium-fpga = ["utralib/cramium-fpga", "debug-print", "cramium-hal"]
cramium-fpga = ["utralib/cramium-fpga", "debug-print"]
atsama5d27 = ["utralib/atsama5d27", "armv7", "dep:atsama5d27"]

# precursor flags
Expand Down
5 changes: 3 additions & 2 deletions loader/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,8 @@ fn boot_sequence(args: KernelArguments, _signature: u32, fs_prehash: [u8; 64], _
println!("No suspend marker found, doing a cold boot!");
#[cfg(feature = "simulation-only")]
println!("Configured for simulation. Skipping RAM clear!");
#[cfg(not(feature = "cramium-soc"))] // cramium-soc target clears RAM with assembly routine on boot
#[cfg(not(any(feature = "cramium-soc", feature = "cramium-fpga")))]
// cramium target clears RAM with assembly routine on boot
clear_ram(&mut cfg);
phase_1(&mut cfg);
phase_2(&mut cfg, &fs_prehash);
Expand Down Expand Up @@ -287,7 +288,7 @@ fn boot_sequence(args: KernelArguments, _signature: u32, fs_prehash: [u8; 64], _

#[cfg(not(feature = "atsama5d27"))]
{
#[cfg(not(feature = "cramium-soc"))]
#[cfg(not(any(feature = "cramium-soc", feature = "cramium-fpga")))]
{
// uart mux only exists on the FPGA variant
use utralib::generated::*;
Expand Down
2 changes: 2 additions & 0 deletions loader/src/platform/cramium/cramium.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
use cramium_hal::axp2101::Axp2101;
#[cfg(not(feature = "verilator-only"))]
use cramium_hal::iox::{Iox, IoxDir, IoxEnable, IoxFunction, IoxPort};
#[cfg(feature = "cramium-soc")]
use cramium_hal::udma;
#[cfg(any(feature = "board-baosec", feature = "board-baosor"))]
use cramium_hal::udma::PeriphId;
Expand Down Expand Up @@ -1556,6 +1557,7 @@ fn fsfreq_to_hz(fs_freq: u32) -> u32 { (fs_freq * (48_000_000 / 32)) / 1_000_000
fn fsfreq_to_hz_32(fs_freq: u32) -> u32 { (fs_freq * (32_000_000 / 32)) / 1_000_000 }

#[allow(dead_code)]
#[cfg(feature = "cramium-soc")]
/// Used mainly for debug breaks. Not used in every configuration.
pub fn getc() -> char {
let uart_buf_addr = loader::UART_IFRAM_ADDR;
Expand Down
9 changes: 4 additions & 5 deletions services/cram-mbox1/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,8 @@ num-derive = { version = "0.4.2", default-features = false }
num-traits = { version = "0.2.14", default-features = false }

[features]
"cramium" = []
"cramium-soc" = []
"cramium-fpga" = []
"cramium" = ["utralib/cramium-fpga"]
"hwsim" = []
"ext" = [] # must match setting in cram-mbox2
default = ["cramium", "ext"]
# ext specifies to use the APB client, instead of the loopback local
"ext" = [] # must match setting in cram-mbox2
default = ["cramium"]
Loading
Loading