diff --git a/Cargo.lock b/Cargo.lock index 0cc7c79b8..d6033a047 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1237,18 +1237,18 @@ dependencies = [ [[package]] name = "ptr_meta" -version = "0.1.1" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aad980f4bb4053abd4733b1680024a8c71ffde345f6e584c6af9eb6f0067a198" +checksum = "7424255320182a46c403331afed6f95e0259a7c578f9da54a27e262ef3b60118" dependencies = [ "ptr_meta_derive", ] [[package]] name = "ptr_meta_derive" -version = "0.1.1" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7bcd6232fa7d7fcd15703da5c07c9f10d203ee4fdf6ecf6d7ac5056db78089a3" +checksum = "53005b9863728f508d3f23ae37e03d60986a01b65f7ae8397dcebaa1d5e54e10" dependencies = [ "proc-macro2 1.0.24", "quote 1.0.8", diff --git a/Cargo.toml b/Cargo.toml index 550cc607d..060e78865 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -28,6 +28,7 @@ default-members = [ "services/engine-25519", "services/aes", "services/test-stub", + #"services/spinor", ] members = [ "xous-ipc", @@ -69,6 +70,7 @@ members = [ "services/engine-25519", "services/aes", "services/test-stub", + #"services/spinor", ] resolver = "2" diff --git a/precursors/soc.svd b/precursors/soc.svd index a1b1021df..bed594047 100755 --- a/precursors/soc.svd +++ b/precursors/soc.svd @@ -3,7 +3,7 @@ litex SOC - + 8 32 @@ -1222,10 +1222,10 @@ register to disable individual events.]]> GIT_GITREV 0x0014 - 0x977355ba + 0x27ddfe4b 32 @@ -1242,7 +1242,7 @@ the exact git version used to build this firmware.]]> is ``1``, then the repository this was built from has one additional commit beyond the tag indicated in `MAJOR`, `MINOR`, and `REVISION`.]]> 0x0018 - 0x26 + 0x28 32 @@ -3467,7 +3467,7 @@ inject too fast.]]> SEED1 0x0000 - 0x698bb704 + 0x6a034505 32 @@ -3482,7 +3482,7 @@ inject too fast.]]> SEED0 0x0004 - 0x5d2ea7df + 0x6ebb0afe 32 @@ -3535,10 +3535,40 @@ inject too fast.]]> + + LOCKADDR + + 0x0008 + 0x00 + 32 + + + lockaddr + 7 + [7:0] + 0 + + + + + LOCKSTAT + + 0x000c + 0x00 + 32 + + + lockstat + 0 + [0:0] + 0 + + + 0 - 0x8 + 0x10 registers diff --git a/precursors/soc_csr.bin b/precursors/soc_csr.bin index 1636496a5..a4a8c12d2 100755 Binary files a/precursors/soc_csr.bin and b/precursors/soc_csr.bin differ diff --git a/services/spinor/Cargo.toml b/services/spinor/Cargo.toml new file mode 100644 index 000000000..1163bf1c8 --- /dev/null +++ b/services/spinor/Cargo.toml @@ -0,0 +1,23 @@ +[package] +name = "spinor" +version = "0.1.0" +authors = ["bunnie "] +edition = "2018" +description = "SPINOR ROM operations server" + +[dependencies] +xous = { path = "../../xous-rs" } +log-server = { path = "../log-server" } +ticktimer-server = { path = "../ticktimer-server" } +xous-names = { path = "../xous-names" } +log = "0.4" +num-derive = {version = "0.3", default-features = false} +num-traits = {version = "0.2", default-features = false} +susres = {path = "../susres"} +rkyv = {version = "0.6.7", default-features = false, features = ["const_generics"]} + +[target.'cfg(not(any(windows,unix)))'.dependencies] +utralib = { path = "../../utralib"} + +[features] +default = [] diff --git a/services/spinor/src/api.rs b/services/spinor/src/api.rs new file mode 100644 index 000000000..c8845ed70 --- /dev/null +++ b/services/spinor/src/api.rs @@ -0,0 +1,32 @@ +pub(crate) const SERVER_NAME_SPINOR: &str = "_SPINOR Hardware Interface Server_"; + +#[allow(dead_code)] +#[derive(num_derive::FromPrimitive, num_derive::ToPrimitive, Debug)] +pub(crate) enum Opcode { + /// erase a region + EraseRegion, + + /// program a region + WriteRegion, + + /// Suspend/resume callback + SuspendResume, +} + +#[derive(Debug, rkyv::Archive, rkyv::Serialize, rkyv::Deserialize, Clone, Copy)] +pub struct EraseRegion { + /// start location for the erase + pub start: u32, + /// length of the region to erase + pub len: u32, +} + +#[derive(Debug, rkyv::Archive, rkyv::Serialize, rkyv::Deserialize, Clone, Copy)] +pub struct WriteRegion { // wait...can we do const generics with rkyv?? + /// start location for the write + pub start: u32, + /// if true, erase the region to write if not already erased; otherwise, if not erased, the routine will error out + pub autoerase: bool, + /// data to write + pub sector: [u8; N], +} diff --git a/services/spinor/src/lib.rs b/services/spinor/src/lib.rs new file mode 100644 index 000000000..9dbf92feb --- /dev/null +++ b/services/spinor/src/lib.rs @@ -0,0 +1,33 @@ +#![cfg_attr(target_os = "none", no_std)] + +pub mod api; +use xous::{CID, send_message}; +use num_traits::ToPrimitive; + +pub struct Spinor { + conn: CID, +} +impl Spinor { + pub fn new(xns: &xous_names::XousNames) -> Result { + REFCOUNT.store(REFCOUNT.load(Ordering::Relaxed) + 1, Ordering::Relaxed); + let conn = xns.request_connection_blocking(api::SERVER_NAME_SPINOR).expect("Can't connect to Spinor server"); + Ok(Spinor { + conn + }) + } +} + +use core::sync::atomic::{AtomicU32, Ordering}; +static REFCOUNT: AtomicU32 = AtomicU32::new(0); +impl Drop for Spinor { + fn drop(&mut self) { + // the connection to the server side must be reference counted, so that multiple instances of this object within + // a single process do not end up de-allocating the CID on other threads before they go out of scope. + // Note to future me: you want this. Don't get rid of it because you think, "nah, nobody will ever make more than one copy of this object". + if REFCOUNT.load(Ordering::Relaxed) == 0 { + unsafe{xous::disconnect(self.conn).unwrap();} + } + // if there was object-specific state (such as a one-time use server for async callbacks, specific to the object instance), + // de-allocate those items here. They don't need a reference count because they are object-specific + } +} \ No newline at end of file diff --git a/services/spinor/src/main.rs b/services/spinor/src/main.rs new file mode 100644 index 000000000..c2d20143f --- /dev/null +++ b/services/spinor/src/main.rs @@ -0,0 +1,127 @@ +#![cfg_attr(target_os = "none", no_std)] +#![cfg_attr(target_os = "none", no_main)] + +mod api; + +use num_traits::FromPrimitive; + +use log::info; + + +#[cfg(target_os = "none")] +mod implementation { + use utralib::generated::*; + // use crate::api::*; + use log::info; + use susres::{RegManager, RegOrField, SuspendResume}; + + pub struct Spinor { + csr: utralib::CSR, + fifo: xous::MemoryRange, + susres_manager: RegManager::<{utra::audio::AUDIO_NUMREGS}>, + } + + impl Spinor { + pub fn new() -> Spinor { + let csr = xous::syscall::map_memory( + xous::MemoryAddress::new(utra::audio::HW_AUDIO_BASE), + None, + 4096, + xous::MemoryFlags::R | xous::MemoryFlags::W, + ) + .expect("couldn't map Audio CSR range"); + let fifo = xous::syscall::map_memory( + xous::MemoryAddress::new(utralib::HW_AUDIO_MEM), + None, + utralib::HW_AUDIO_MEM_LEN, + xous::MemoryFlags::R | xous::MemoryFlags::W, + ) + .expect("couldn't map Audio CSR range"); + + let mut spinor = Spinor { + csr: CSR::new(csr.as_mut_ptr() as *mut u32), + susres_manager: RegManager::new(csr.as_mut_ptr() as *mut u32), + fifo, + }; + + spinor + } + + pub fn suspend(&mut self) { + self.susres_manager.suspend(); + } + pub fn resume(&mut self) { + self.susres_manager.resume(); + } + } +} + +// a stub to try to avoid breaking hosted mode for as long as possible. +#[cfg(not(target_os = "none"))] +mod implementation { + use log::info; + + pub struct Spinor { + } + + impl Spinor { + pub fn new() -> Spinor { + Spinor { + } + } + pub fn suspend(&self) { + } + pub fn resume(&self) { + } + } +} + + +#[xous::xous_main] +fn xmain() -> ! { + use crate::implementation::Spinor; + + log_server::init_wait().unwrap(); + log::set_max_level(log::LevelFilter::Info); + info!("my PID is {}", xous::process::id()); + + let xns = xous_names::XousNames::new().unwrap(); + /* + Very important to track who has access to the SPINOR server, and limit access. Access to this server is essential for persistent rootkits. + Here is the list of servers allowed to access, and why: + - shellchat (for testing ONLY, remove once done) + - PDDB (not yet written) + - keystore (not yet written) + */ + let spinor_sid = xns.register_name(api::SERVER_NAME_SPINOR, Some(1)).expect("can't register server"); + log::trace!("registered with NS -- {:?}", spinor_sid); + + let mut spinor = Spinor::new(); + + log::trace!("ready to accept requests"); + + // register a suspend/resume listener + let sr_cid = xous::connect(spinor_sid).expect("couldn't create suspend callback connection"); + let mut susres = susres::Susres::new(&xns, api::Opcode::SuspendResume as u32, sr_cid).expect("couldn't create suspend/resume object"); + + loop { + let msg = xous::receive_message(spinor_sid).unwrap(); + match FromPrimitive::from_usize(msg.body.id()) { + Some(api::Opcode::SuspendResume) => xous::msg_scalar_unpack!(msg, token, _, _, _, { + spinor.suspend(); + susres.suspend_until_resume(token).expect("couldn't execute suspend/resume"); + spinor.resume(); + }), + None => { + log::error!("couldn't convert opcode"); + break + } + } + } + // clean up our program + log::trace!("main loop exit, destroying servers"); + xns.unregister_server(spinor_sid).unwrap(); + xous::destroy_server(spinor_sid).unwrap(); + log::trace!("quitting"); + xous::terminate_process(0) +} diff --git a/xtask/src/main.rs b/xtask/src/main.rs index 930f15dcf..94dfe1b03 100644 --- a/xtask/src/main.rs +++ b/xtask/src/main.rs @@ -55,6 +55,7 @@ fn try_main() -> Result<(), DynError> { "codec", "engine-sha512", "engine-25519", + //"spinor", ]; let benchmark_pkgs = [ "benchmark",