diff --git a/rustfmt.toml b/rustfmt.toml index 70b9735a1..acaa3c6c3 100644 --- a/rustfmt.toml +++ b/rustfmt.toml @@ -2,7 +2,7 @@ ignore = [ "services/graphics-server", "services/com", "services/keyboard", - "services/trng", + #"services/trng", "services/gam", "services/status", "services/benchmark", diff --git a/services/trng/src/api.rs b/services/trng/src/api.rs index 3481615c5..d153ae31a 100644 --- a/services/trng/src/api.rs +++ b/services/trng/src/api.rs @@ -1,5 +1,4 @@ -pub(crate) const SERVER_NAME_TRNG: &str = "_TRNG manager_"; - +pub(crate) const SERVER_NAME_TRNG: &str = "_TRNG manager_"; #[derive(Debug, Copy, Clone, rkyv::Archive, rkyv::Serialize, rkyv::Deserialize, Default)] pub struct ExcursionTest { @@ -79,6 +78,6 @@ pub(crate) enum EventCallback { #[derive(Debug, rkyv::Archive, rkyv::Serialize, rkyv::Deserialize, Copy, Clone)] pub(crate) struct ScalarHook { pub sid: (u32, u32, u32, u32), - pub id: u32, // ID of the scalar message to send through (e.g. the discriminant of the Enum on the caller's side API) - pub cid: xous::CID, // caller-side connection ID for the scalar message to route to. Created by the caller before hooking. + pub id: u32, // ID of the scalar message to send through (e.g. the discriminant of the Enum on the caller's side API) + pub cid: xous::CID, // caller-side connection ID for the scalar message to route to. Created by the caller before hooking. } diff --git a/services/trng/src/lib.rs b/services/trng/src/lib.rs index e74726f81..a4cd51df7 100644 --- a/services/trng/src/lib.rs +++ b/services/trng/src/lib.rs @@ -1,8 +1,8 @@ #![cfg_attr(target_os = "none", no_std)] pub mod api; -use xous::{CID, send_message}; use num_traits::*; +use xous::{send_message, CID}; use xous_ipc::Buffer; #[derive(Debug)] @@ -12,7 +12,9 @@ pub struct Trng { } impl Trng { pub fn new(xns: &xous_names::XousNames) -> Result { - let conn = xns.request_connection_blocking(api::SERVER_NAME_TRNG).expect("Can't connect to TRNG server"); + let conn = xns + .request_connection_blocking(api::SERVER_NAME_TRNG) + .expect("Can't connect to TRNG server"); REFCOUNT.store(REFCOUNT.load(Ordering::Relaxed) + 1, Ordering::Relaxed); Ok(Trng { conn, @@ -20,10 +22,17 @@ impl Trng { }) } pub fn get_u32(&self) -> Result { - let response = send_message(self.conn, - xous::Message::new_blocking_scalar(api::Opcode::GetTrng.to_usize().unwrap(), - 1 /* count */, 0, 0, 0, ) - ).expect("TRNG|LIB: can't get_u32"); + let response = send_message( + self.conn, + xous::Message::new_blocking_scalar( + api::Opcode::GetTrng.to_usize().unwrap(), + 1, /* count */ + 0, + 0, + 0, + ), + ) + .expect("TRNG|LIB: can't get_u32"); if let xous::Result::Scalar2(trng, _) = response { Ok(trng as u32) } else { @@ -31,27 +40,38 @@ impl Trng { } } pub fn get_u64(&self) -> Result { - let response = send_message(self.conn, - xous::Message::new_blocking_scalar(api::Opcode::GetTrng.to_usize().unwrap(), - 2 /* count */, 0, 0, 0, ) - ).expect("TRNG|LIB: can't get_u32"); - if let xous::Result::Scalar2(lo, hi) = response { - Ok( lo as u64 | ((hi as u64) << 32) ) + let response = send_message( + self.conn, + xous::Message::new_blocking_scalar( + api::Opcode::GetTrng.to_usize().unwrap(), + 2, /* count */ + 0, + 0, + 0, + ), + ) + .expect("TRNG|LIB: can't get_u32"); + if let xous::Result::Scalar2(lo, hi) = response { + Ok(lo as u64 | ((hi as u64) << 32)) } else { panic!("unexpected return value: {:#?}", response); } } pub fn fill_buf(&self, data: &mut [u32]) -> Result<(), xous::Error> { - let mut tb = api::TrngBuf { data: [0; 1024], len: 0 }; + let mut tb = api::TrngBuf { + data: [0; 1024], + len: 0, + }; if data.len() > tb.data.len() { return Err(xous::Error::OutOfMemory); } tb.len = data.len() as u16; let mut buf = Buffer::into_buf(tb).or(Err(xous::Error::InternalError))?; - buf.lend_mut(self.conn, api::Opcode::FillTrng.to_u32().unwrap()).or(Err(xous::Error::InternalError))?; + buf.lend_mut(self.conn, api::Opcode::FillTrng.to_u32().unwrap()) + .or(Err(xous::Error::InternalError))?; let rtb: api::TrngBuf = buf.to_original().unwrap(); if rtb.len as usize != data.len() { - return Err(xous::Error::InternalError) + return Err(xous::Error::InternalError); } for (&src, dst) in rtb.data.iter().zip(data.iter_mut()) { *dst = src; @@ -63,14 +83,22 @@ impl Trng { let sid = xous::create_server().unwrap(); self.error_sid = Some(sid); let sid_tuple = sid.to_u32(); - xous::create_thread_4(error_cb_server, sid_tuple.0 as usize, sid_tuple.1 as usize, sid_tuple.2 as usize, sid_tuple.3 as usize).unwrap(); + xous::create_thread_4( + error_cb_server, + sid_tuple.0 as usize, + sid_tuple.1 as usize, + sid_tuple.2 as usize, + sid_tuple.3 as usize, + ) + .unwrap(); let hookdata = api::ScalarHook { sid: sid_tuple, id, cid, }; let buf = Buffer::into_buf(hookdata).or(Err(xous::Error::InternalError))?; - buf.lend(self.conn, api::Opcode::ErrorSubscribe.to_u32().unwrap()).map(|_|()) + buf.lend(self.conn, api::Opcode::ErrorSubscribe.to_u32().unwrap()) + .map(|_| ()) } else { Err(xous::Error::MemoryInUse) // can't hook it twice } @@ -78,13 +106,15 @@ impl Trng { pub fn get_health_tests(&self) -> Result { let ht = api::HealthTests::default(); let mut buf = Buffer::into_buf(ht).or(Err(xous::Error::InternalError))?; - buf.lend_mut(self.conn, api::Opcode::HealthStats.to_u32().unwrap()).or(Err(xous::Error::InternalError))?; + buf.lend_mut(self.conn, api::Opcode::HealthStats.to_u32().unwrap()) + .or(Err(xous::Error::InternalError))?; Ok(buf.to_original().unwrap()) } pub fn get_error_stats(&self) -> Result { let errs = api::TrngErrors::default(); let mut buf = Buffer::into_buf(errs).or(Err(xous::Error::InternalError))?; - buf.lend_mut(self.conn, api::Opcode::ErrorStats.to_u32().unwrap()).or(Err(xous::Error::InternalError))?; + buf.lend_mut(self.conn, api::Opcode::ErrorStats.to_u32().unwrap()) + .or(Err(xous::Error::InternalError))?; Ok(buf.to_original().unwrap()) } } @@ -95,7 +125,9 @@ impl Drop for Trng { fn drop(&mut self) { // de-allocate myself. It's unsafe because we are responsible to make sure nobody else is using the connection. if REFCOUNT.load(Ordering::Relaxed) == 0 { - unsafe{xous::disconnect(self.conn).unwrap();} + unsafe { + xous::disconnect(self.conn).unwrap(); + } } } } @@ -107,9 +139,7 @@ fn error_cb_server(sid0: usize, sid1: usize, sid2: usize, sid3: usize) { match FromPrimitive::from_usize(msg.body.id()) { Some(api::EventCallback::Event) => xous::msg_scalar_unpack!(msg, cid, id, _, _, { // directly pass the scalar message onto the CID with the ID memorized in the original hook - send_message(cid as u32, - xous::Message::new_scalar(id, 0, 0, 0, 0) - ).unwrap(); + send_message(cid as u32, xous::Message::new_scalar(id, 0, 0, 0, 0)).unwrap(); }), Some(api::EventCallback::Drop) => { break; // this exits the loop and kills the thread @@ -129,56 +159,58 @@ impl RngCore for Trng { fn next_u64(&mut self) -> u64 { self.get_u64().expect("couldn't get random u64 from server") } - fn fill_bytes(&mut self, dest: &mut[u8]) { + fn fill_bytes(&mut self, dest: &mut [u8]) { // smaller than 64 bytes (512 bits), just use 8x next_u64 calls to fill. if dest.len() < 64 { return impls::fill_bytes_via_next(self, dest); } // one page is the max size we can do with the fill_buf() API - let chunks_page = - dest.chunks_exact_mut(4096); + let chunks_page = dest.chunks_exact_mut(4096); for chunks in chunks_page.into_iter() { - let mut data: [u32; 4096/4] = [0; 4096/4]; - self.fill_buf(&mut data).expect("couldn't fill page-sized TRNG buffer"); - for(&src, dst) in data.iter().zip(chunks.chunks_exact_mut(4)) { + let mut data: [u32; 4096 / 4] = [0; 4096 / 4]; + self.fill_buf(&mut data) + .expect("couldn't fill page-sized TRNG buffer"); + for (&src, dst) in data.iter().zip(chunks.chunks_exact_mut(4)) { for (&src_byte, dst_byte) in src.to_le_bytes().iter().zip(dst.iter_mut()) { *dst_byte = src_byte; } } } // a mid-sized chunk to span the gap between page and our smallest granularity - let chunks_512 = - dest.chunks_exact_mut(4096) + let chunks_512 = dest + .chunks_exact_mut(4096) .into_remainder() .chunks_exact_mut(512); for chunks in chunks_512.into_iter() { - let mut data: [u32; 512/4] = [0; 512/4]; - self.fill_buf(&mut data).expect("couldn't fill mid-sized TRNG buffer"); - for(&src, dst) in data.iter().zip(chunks.chunks_exact_mut(4)) { + let mut data: [u32; 512 / 4] = [0; 512 / 4]; + self.fill_buf(&mut data) + .expect("couldn't fill mid-sized TRNG buffer"); + for (&src, dst) in data.iter().zip(chunks.chunks_exact_mut(4)) { for (&src_byte, dst_byte) in src.to_le_bytes().iter().zip(dst.iter_mut()) { *dst_byte = src_byte; } } } // our smallest-sized "standard" chunk - let chunks_smallest = - dest.chunks_exact_mut(4096) + let chunks_smallest = dest + .chunks_exact_mut(4096) .into_remainder() .chunks_exact_mut(512) .into_remainder() .chunks_exact_mut(64); for chunks in chunks_smallest.into_iter() { - let mut data: [u32; 64/4] = [0; 64/4]; - self.fill_buf(&mut data).expect("couldn't fill small-sized TRNG buffer"); - for(&src, dst) in data.iter().zip(chunks.chunks_exact_mut(4)) { + let mut data: [u32; 64 / 4] = [0; 64 / 4]; + self.fill_buf(&mut data) + .expect("couldn't fill small-sized TRNG buffer"); + for (&src, dst) in data.iter().zip(chunks.chunks_exact_mut(4)) { for (&src_byte, dst_byte) in src.to_le_bytes().iter().zip(dst.iter_mut()) { *dst_byte = src_byte; } } } // any leftover bytes - let leftovers = - dest.chunks_exact_mut(4096) + let leftovers = dest + .chunks_exact_mut(4096) .into_remainder() .chunks_exact_mut(512) .into_remainder() @@ -186,7 +218,7 @@ impl RngCore for Trng { .into_remainder(); impls::fill_bytes_via_next(self, leftovers); } - fn try_fill_bytes(&mut self, dest: &mut[u8]) -> Result<(), rand_core::Error> { + fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), rand_core::Error> { Ok(self.fill_bytes(dest)) } } diff --git a/services/trng/src/main.rs b/services/trng/src/main.rs index 3000d648a..48217ec7b 100644 --- a/services/trng/src/main.rs +++ b/services/trng/src/main.rs @@ -19,14 +19,14 @@ struct ScalarCallback { #[cfg(any(target_os = "none", target_os = "xous"))] mod implementation { - use utralib::generated::*; - use crate::api::{ExcursionTest, MiniRunsTest, NistTests, HealthTests, TrngErrors, TrngBuf}; - use susres::{RegManager, RegOrField, SuspendResume}; + use crate::api::{ExcursionTest, HealthTests, MiniRunsTest, NistTests, TrngBuf, TrngErrors}; use num_traits::*; + use susres::{RegManager, RegOrField, SuspendResume}; + use utralib::generated::*; pub struct Trng { csr: utralib::CSR, - susres_manager: RegManager::<{utra::trng_server::TRNG_SERVER_NUMREGS}>, // probably can be reduced to save space? + susres_manager: RegManager<{ utra::trng_server::TRNG_SERVER_NUMREGS }>, // probably can be reduced to save space? conn: xous::CID, errors: TrngErrors, err_stat: HealthTests, @@ -44,14 +44,16 @@ mod implementation { min: trng.csr.rf(utra::trng_server::AV_EXCURSION0_LAST_ERR_MIN) as u16, max: trng.csr.rf(utra::trng_server::AV_EXCURSION0_LAST_ERR_MAX) as u16, }); - trng.csr.rmwf(utra::trng_server::AV_EXCURSION0_CTRL_RESET, 1); + trng.csr + .rmwf(utra::trng_server::AV_EXCURSION0_CTRL_RESET, 1); } if (pending & trng.csr.ms(utra::trng_server::EV_PENDING_EXCURSION1, 1)) != 0 { trng.errors.excursion_errs[1] = Some(ExcursionTest { min: trng.csr.rf(utra::trng_server::AV_EXCURSION1_LAST_ERR_MIN) as u16, max: trng.csr.rf(utra::trng_server::AV_EXCURSION1_LAST_ERR_MAX) as u16, }); - trng.csr.rmwf(utra::trng_server::AV_EXCURSION1_CTRL_RESET, 1); + trng.csr + .rmwf(utra::trng_server::AV_EXCURSION1_CTRL_RESET, 1); } if (pending & trng.csr.ms(utra::trng_server::EV_PENDING_HEALTH, 1)) != 0 { let av_repcount = trng.csr.rf(utra::trng_server::NIST_ERRORS_AV_REPCOUNT); @@ -73,15 +75,27 @@ mod implementation { } // record error summaries and errors from non-health sources trng.errors.nist_errs = trng.csr.r(utra::trng_server::NIST_ERRORS); - trng.errors.server_underruns = trng.csr.rf(utra::trng_server::UNDERRUNS_SERVER_UNDERRUN) as u16; - trng.errors.kernel_underruns = trng.csr.rf(utra::trng_server::UNDERRUNS_KERNEL_UNDERRUN) as u16; + trng.errors.server_underruns = + trng.csr.rf(utra::trng_server::UNDERRUNS_SERVER_UNDERRUN) as u16; + trng.errors.kernel_underruns = + trng.csr.rf(utra::trng_server::UNDERRUNS_KERNEL_UNDERRUN) as u16; // reset any error flags. try to do this a bit away from the pending clear, so it has time to take effect trng.csr.rmwf(utra::trng_server::CONTROL_CLR_ERR, 1); // notify the main loop of the error condition - xous::try_send_message(trng.conn, - xous::Message::new_scalar(crate::api::Opcode::ErrorNotification.to_usize().unwrap(), 0, 0, 0, 0)).map(|_|()).unwrap(); + xous::try_send_message( + trng.conn, + xous::Message::new_scalar( + crate::api::Opcode::ErrorNotification.to_usize().unwrap(), + 0, + 0, + 0, + 0, + ), + ) + .map(|_| ()) + .unwrap(); // clear the pending interrupt(s) trng.csr.wo(utra::trng_server::EV_PENDING, pending); @@ -99,7 +113,9 @@ mod implementation { let mut trng = Trng { csr: CSR::new(csr.as_mut_ptr() as *mut u32), - conn: xns.request_connection_blocking(crate::api::SERVER_NAME_TRNG).unwrap(), + conn: xns + .request_connection_blocking(crate::api::SERVER_NAME_TRNG) + .unwrap(), susres_manager: RegManager::new(csr.as_mut_ptr() as *mut u32), errors: TrngErrors { excursion_errs: [None; 2], @@ -117,69 +133,92 @@ mod implementation { ///// configure power settings and which generator to use if !(cfg!(feature = "avalanchetest") || cfg!(feature = "ringosctest")) { - trng.csr.wo(utra::trng_server::CONTROL, + trng.csr.wo( + utra::trng_server::CONTROL, trng.csr.ms(utra::trng_server::CONTROL_ENABLE, 1) - | trng.csr.ms(utra::trng_server::CONTROL_POWERSAVE, 1) - // | self.server_csr.ms(utra::trng_server::CONTROL_AV_DIS, 1) // disable the AV generator to characterize the RO - // | self.server_csr.ms(utra::trng_server::CONTROL_RO_DIS, 1) // disable the RO to characterize only the AV + | trng.csr.ms(utra::trng_server::CONTROL_POWERSAVE, 1), ); - log::trace!("TRNG configured for normal operation (av+ro): 0x{:08x}", trng.csr.r(utra::trng_server::CONTROL)); - } else if cfg!(feature = "avalanchetest") && ! cfg!(feature = "ringosctest") { + log::trace!( + "TRNG configured for normal operation (av+ro): 0x{:08x}", + trng.csr.r(utra::trng_server::CONTROL) + ); + } else if cfg!(feature = "avalanchetest") && !cfg!(feature = "ringosctest") { // avalanche test only - trng.csr.wo(utra::trng_server::CONTROL, + trng.csr.wo( + utra::trng_server::CONTROL, trng.csr.ms(utra::trng_server::CONTROL_ENABLE, 1) | trng.csr.ms(utra::trng_server::CONTROL_POWERSAVE, 1) // question: do we want power save on or off for testing?? let's leave it on for now, it will make the test run slower but maybe more accurate to our usual use case - | trng.csr.ms(utra::trng_server::CONTROL_RO_DIS, 1) // disable the RO to characterize only the AV + | trng.csr.ms(utra::trng_server::CONTROL_RO_DIS, 1), // disable the RO to characterize only the AV ); - log::info!("TRNG configured for avalanche testing: 0x{:08x}", trng.csr.r(utra::trng_server::CONTROL)); - } else if ! cfg!(feature = "avalanchetest") && cfg!(feature = "ringosctest") { + log::info!( + "TRNG configured for avalanche testing: 0x{:08x}", + trng.csr.r(utra::trng_server::CONTROL) + ); + } else if !cfg!(feature = "avalanchetest") && cfg!(feature = "ringosctest") { // ring osc test only - trng.csr.wo(utra::trng_server::CONTROL, + trng.csr.wo( + utra::trng_server::CONTROL, trng.csr.ms(utra::trng_server::CONTROL_ENABLE, 1) - | trng.csr.ms(utra::trng_server::CONTROL_POWERSAVE, 1) - | trng.csr.ms(utra::trng_server::CONTROL_AV_DIS, 1) // disable the AV generator to characterize the RO + | trng.csr.ms(utra::trng_server::CONTROL_POWERSAVE, 1) + | trng.csr.ms(utra::trng_server::CONTROL_AV_DIS, 1), // disable the AV generator to characterize the RO + ); + log::info!( + "TRNG configured for ring oscillator testing: 0x{:08x}", + trng.csr.r(utra::trng_server::CONTROL) ); - log::info!("TRNG configured for ring oscillator testing: 0x{:08x}", trng.csr.r(utra::trng_server::CONTROL)); } else { // both on - trng.csr.wo(utra::trng_server::CONTROL, + trng.csr.wo( + utra::trng_server::CONTROL, trng.csr.ms(utra::trng_server::CONTROL_ENABLE, 1) - | trng.csr.ms(utra::trng_server::CONTROL_POWERSAVE, 1) + | trng.csr.ms(utra::trng_server::CONTROL_POWERSAVE, 1), + ); + log::info!( + "TRNG configured for both avalanche and ring oscillator testing: 0x{:08x}", + trng.csr.r(utra::trng_server::CONTROL) ); - log::info!("TRNG configured for both avalanche and ring oscillator testing: 0x{:08x}", trng.csr.r(utra::trng_server::CONTROL)); } - trng.susres_manager.push(RegOrField::Reg(utra::trng_server::CONTROL), None); + trng.susres_manager + .push(RegOrField::Reg(utra::trng_server::CONTROL), None); /*** TRNG tuning parameters: these were configured and tested in a long run against Dieharder - There is a rate of TRNG generation vs. quality trade-off. The tuning below is toward quality of - TRNG versus rate of TRNG, such that we could use these without any whitening. - ***/ + There is a rate of TRNG generation vs. quality trade-off. The tuning below is toward quality of + TRNG versus rate of TRNG, such that we could use these without any whitening. + ***/ ///// configure avalanche // delay in microseconds for avalanche poweron after powersave - trng.csr.wo(utra::trng_server::AV_CONFIG, + trng.csr.wo( + utra::trng_server::AV_CONFIG, trng.csr.ms(utra::trng_server::AV_CONFIG_POWERDELAY, 50_000) - | trng.csr.ms(utra::trng_server::AV_CONFIG_SAMPLES, 32) + | trng.csr.ms(utra::trng_server::AV_CONFIG_SAMPLES, 32), ); - trng.susres_manager.push(RegOrField::Reg(utra::trng_server::AV_CONFIG), None); + trng.susres_manager + .push(RegOrField::Reg(utra::trng_server::AV_CONFIG), None); ///// configure ring oscillator - trng.csr.wo(utra::trng_server::RO_CONFIG, + trng.csr.wo( + utra::trng_server::RO_CONFIG, trng.csr.ms(utra::trng_server::RO_CONFIG_DELAY, 4) - | trng.csr.ms(utra::trng_server::RO_CONFIG_DWELL, 100) - | trng.csr.ms(utra::trng_server::RO_CONFIG_GANG, 1) - | trng.csr.ms(utra::trng_server::RO_CONFIG_FUZZ, 1) - | trng.csr.ms(utra::trng_server::RO_CONFIG_OVERSAMPLING, 3) + | trng.csr.ms(utra::trng_server::RO_CONFIG_DWELL, 100) + | trng.csr.ms(utra::trng_server::RO_CONFIG_GANG, 1) + | trng.csr.ms(utra::trng_server::RO_CONFIG_FUZZ, 1) + | trng.csr.ms(utra::trng_server::RO_CONFIG_OVERSAMPLING, 3), ); - trng.susres_manager.push(RegOrField::Reg(utra::trng_server::RO_CONFIG), None); + trng.susres_manager + .push(RegOrField::Reg(utra::trng_server::RO_CONFIG), None); // slightly reduce the frequency of these to reduce power - trng.csr.wo(utra::trng_server::CHACHA, + trng.csr.wo( + utra::trng_server::CHACHA, trng.csr.ms(utra::trng_server::CHACHA_RESEED_INTERVAL, 2) - | trng.csr.ms(utra::trng_server::CHACHA_SELFMIX_INTERVAL, 1000) - | trng.csr.ms(utra::trng_server::CHACHA_SELFMIX_ENA, 1) + | trng + .csr + .ms(utra::trng_server::CHACHA_SELFMIX_INTERVAL, 1000) + | trng.csr.ms(utra::trng_server::CHACHA_SELFMIX_ENA, 1), ); - trng.susres_manager.push(RegOrField::Reg(utra::trng_server::CHACHA), None); + trng.susres_manager + .push(RegOrField::Reg(utra::trng_server::CHACHA), None); // handle error interrupts xous::claim_interrupt( @@ -188,20 +227,24 @@ mod implementation { (&mut trng) as *mut Trng as *mut usize, ) .expect("couldn't claim audio irq"); - trng.csr.wo(utra::trng_server::EV_PENDING, + trng.csr.wo( + utra::trng_server::EV_PENDING, trng.csr.ms(utra::trng_server::EV_PENDING_ERROR, 1) - | trng.csr.ms(utra::trng_server::EV_PENDING_HEALTH, 1) - | trng.csr.ms(utra::trng_server::EV_PENDING_EXCURSION0, 1) - | trng.csr.ms(utra::trng_server::EV_PENDING_EXCURSION1, 1) + | trng.csr.ms(utra::trng_server::EV_PENDING_HEALTH, 1) + | trng.csr.ms(utra::trng_server::EV_PENDING_EXCURSION0, 1) + | trng.csr.ms(utra::trng_server::EV_PENDING_EXCURSION1, 1), ); - trng.csr.wo(utra::trng_server::EV_ENABLE, + trng.csr.wo( + utra::trng_server::EV_ENABLE, trng.csr.ms(utra::trng_server::EV_ENABLE_ERROR, 1) - | trng.csr.ms(utra::trng_server::EV_ENABLE_HEALTH, 1) - | trng.csr.ms(utra::trng_server::EV_ENABLE_EXCURSION0, 1) - | trng.csr.ms(utra::trng_server::EV_ENABLE_EXCURSION1, 1) + | trng.csr.ms(utra::trng_server::EV_ENABLE_HEALTH, 1) + | trng.csr.ms(utra::trng_server::EV_ENABLE_EXCURSION0, 1) + | trng.csr.ms(utra::trng_server::EV_ENABLE_EXCURSION1, 1), ); - trng.susres_manager.push_fixed_value(RegOrField::Reg(utra::trng_server::EV_PENDING), 0xFFFF_FFFF); - trng.susres_manager.push(RegOrField::Reg(utra::trng_server::EV_ENABLE), None); + trng.susres_manager + .push_fixed_value(RegOrField::Reg(utra::trng_server::EV_PENDING), 0xFFFF_FFFF); + trng.susres_manager + .push(RegOrField::Reg(utra::trng_server::EV_ENABLE), None); log::debug!("hardware initialized"); @@ -213,7 +256,8 @@ mod implementation { log::trace!("chacha not valid"); } } - log::trace!("chacha rands: 0x{:08x} 0x{:08x} 0x{:08x} 0x{:08x}", + log::trace!( + "chacha rands: 0x{:08x} 0x{:08x} 0x{:08x} 0x{:08x}", trng.csr.rf(utra::trng_server::URANDOM_URANDOM), trng.csr.rf(utra::trng_server::URANDOM_URANDOM), trng.csr.rf(utra::trng_server::URANDOM_URANDOM), @@ -223,7 +267,11 @@ mod implementation { trng } // for the test procedure - #[cfg(any(feature = "avalanchetest", feature="ringosctest", feature="urandomtest"))] + #[cfg(any( + feature = "avalanchetest", + feature = "ringosctest", + feature = "urandomtest" + ))] pub fn get_trng_csr(&self) -> *mut u32 { self.csr.base } @@ -235,6 +283,7 @@ mod implementation { self.err_stat } + #[rustfmt::skip] pub fn get_tests(&self) -> HealthTests { // the fresh bit gets reset on the first read of the register. Ensure these reads happen first before the structure is initialized. let av_nist_fresh0 = if self.csr.rf(utra::trng_server::NIST_AV_STAT0_FRESH) == 0 {false} else {true}; @@ -334,19 +383,27 @@ mod implementation { adaptive_b: self.csr.rf(utra::trng_server::NIST_RO_STAT1_ADAP_B) as u16, repcount_b: self.csr.rf(utra::trng_server::NIST_RO_STAT1_REP_B) as u16, }, - ] + ], } } pub fn get_data_eager(&mut self) -> u32 { let mut timeout = 0; - if false { // raw random + if false { + // raw random while self.csr.rf(utra::trng_server::STATUS_AVAIL) == 0 { if timeout > 100 { - log::debug!("TRNG ran out of data, blocked on READY: 0x{:x}", self.csr.r(utra::trng_server::READY)); - log::debug!("ROstats: 0x{:x} 0x{:x} 0x{:x} 0x{:x}", - self.csr.r(utra::trng_server::NIST_RO_STAT0), self.csr.r(utra::trng_server::NIST_RO_STAT1), - self.csr.r(utra::trng_server::NIST_RO_STAT2), self.csr.r(utra::trng_server::NIST_RO_STAT3)); + log::debug!( + "TRNG ran out of data, blocked on READY: 0x{:x}", + self.csr.r(utra::trng_server::READY) + ); + log::debug!( + "ROstats: 0x{:x} 0x{:x} 0x{:x} 0x{:x}", + self.csr.r(utra::trng_server::NIST_RO_STAT0), + self.csr.r(utra::trng_server::NIST_RO_STAT1), + self.csr.r(utra::trng_server::NIST_RO_STAT2), + self.csr.r(utra::trng_server::NIST_RO_STAT3) + ); self.csr.rmwf(utra::trng_server::CONTROL_CLR_ERR, 1); timeout = 0; } @@ -354,7 +411,8 @@ mod implementation { timeout += 1; } self.csr.rf(utra::trng_server::DATA_DATA) - } else { // urandom + } else { + // urandom // in practice, urandom generates data fast enough that we could skip this check // you would need a fully unrolled read loop to exceed the generation rate // but, better safe than sorry! @@ -371,7 +429,10 @@ mod implementation { } pub fn get_buf(&mut self, len: u16) -> TrngBuf { - let mut tb = TrngBuf {data: [0; 1024], len}; + let mut tb = TrngBuf { + data: [0; 1024], + len, + }; for i in 0..len as usize { tb.data[i] = self.get_data_eager(); } @@ -406,7 +467,7 @@ mod implementation { // a stub to try to avoid breaking hosted mode for as long as possible. #[cfg(not(any(target_os = "none", target_os = "xous")))] mod implementation { - use crate::api::{TrngBuf, HealthTests, TrngErrors}; + use crate::api::{HealthTests, TrngBuf, TrngErrors}; pub struct Trng { seed: u32, @@ -429,14 +490,17 @@ mod implementation { } #[allow(dead_code)] - pub fn wait_full(&self) { } + pub fn wait_full(&self) {} pub fn get_buf(&mut self, len: u16) -> TrngBuf { if self.msgcount < 3 { log::info!("hosted mode TRNG is *not* random, it is a deterministic LFSR"); } self.msgcount += 1; - let mut tb = TrngBuf {data: [0; 1024], len}; + let mut tb = TrngBuf { + data: [0; 1024], + len, + }; for i in 0..len as usize { self.seed = self.move_lfsr(self.seed); tb.data[i] = self.seed; @@ -457,10 +521,8 @@ mod implementation { ret } - pub fn suspend(&self) { - } - pub fn resume(&self) { - } + pub fn suspend(&self) {} + pub fn resume(&self) {} pub fn get_tests(&self) -> HealthTests { HealthTests::default() } @@ -483,14 +545,26 @@ mod implementation { } } -#[cfg(any(feature = "avalanchetest", feature="ringosctest", feature="urandomtest"))] -pub const TRNG_BUFF_LEN: usize = 512*1024; -#[cfg(any(feature = "avalanchetest", feature="ringosctest", feature="urandomtest"))] +#[cfg(any( + feature = "avalanchetest", + feature = "ringosctest", + feature = "urandomtest" +))] +pub const TRNG_BUFF_LEN: usize = 512 * 1024; +#[cfg(any( + feature = "avalanchetest", + feature = "ringosctest", + feature = "urandomtest" +))] pub enum WhichMessible { One, Two, } -#[cfg(any(feature = "avalanchetest", feature="ringosctest", feature="urandomtest"))] +#[cfg(any( + feature = "avalanchetest", + feature = "ringosctest", + feature = "urandomtest" +))] struct Tester { server_csr: utralib::CSR, messible_csr: utralib::CSR, @@ -499,7 +573,11 @@ struct Tester { buffer_b: xous::MemoryRange, ticktimer: ticktimer_server::Ticktimer, } -#[cfg(any(feature = "avalanchetest", feature="ringosctest", feature="urandomtest"))] +#[cfg(any( + feature = "avalanchetest", + feature = "ringosctest", + feature = "urandomtest" +))] impl Tester { pub fn new(server_csr: *mut u32) -> Tester { use utralib::generated::*; @@ -569,14 +647,14 @@ impl Tester { self.ticktimer.sleep_ms(10).unwrap(); } self.messible_csr.rf(utra::messible::OUT_OUT) as u8 - }, + } WhichMessible::Two => { while self.messible2_csr.rf(utra::messible2::STATUS_HAVE) == 0 { //xous::yield_slice(); self.ticktimer.sleep_ms(10).unwrap(); } self.messible2_csr.rf(utra::messible2::OUT_OUT) as u8 - }, + } } } @@ -595,7 +673,11 @@ impl Tester { } self.server_csr.rf(utra::trng_server::DATA_DATA) } else { - while self.server_csr.rf(utra::trng_server::URANDOM_VALID_URANDOM_VALID) == 0 {} + while self + .server_csr + .rf(utra::trng_server::URANDOM_VALID_URANDOM_VALID) + == 0 + {} self.server_csr.rf(utra::trng_server::URANDOM_URANDOM) } } @@ -607,7 +689,11 @@ impl Tester { } } } -#[cfg(any(feature = "avalanchetest", feature="ringosctest", feature="urandomtest"))] +#[cfg(any( + feature = "avalanchetest", + feature = "ringosctest", + feature = "urandomtest" +))] fn tester_thread(csr: usize) { let mut trng = Tester::new(csr as *mut u32); @@ -669,7 +755,9 @@ fn xmain() -> ! { let xns = xous_names::XousNames::new().unwrap(); // unlimited connections allowed, anyone including less-trusted processes can get a random number - let trng_sid = xns.register_name(api::SERVER_NAME_TRNG, None).expect("can't register server"); + let trng_sid = xns + .register_name(api::SERVER_NAME_TRNG, None) + .expect("can't register server"); log::trace!("registered with NS -- {:?}", trng_sid); let mut trng = Trng::new(&xns); @@ -683,8 +771,13 @@ fn xmain() -> ! { #[cfg(feature = "urandomtest")] log::info!("TRNG built with urandom test enabled"); - #[cfg(any(feature = "avalanchetest", feature="ringosctest", feature="urandomtest"))] - xous::create_thread_1(tester_thread, trng.get_trng_csr() as usize).expect("couldn't create test thread"); + #[cfg(any( + feature = "avalanchetest", + feature = "ringosctest", + feature = "urandomtest" + ))] + xous::create_thread_1(tester_thread, trng.get_trng_csr() as usize) + .expect("couldn't create test thread"); // pump the TRNG hardware to clear the first number out, sometimes it is 0 due to clock-sync issues on the fifo trng.get_trng(2); @@ -692,7 +785,8 @@ fn xmain() -> ! { // register a suspend/resume listener let sr_cid = xous::connect(trng_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"); + let mut susres = susres::Susres::new(&xns, api::Opcode::SuspendResume as u32, sr_cid) + .expect("couldn't create suspend/resume object"); let mut error_cb_conns: [Option; 32] = [None; 32]; loop { @@ -705,35 +799,45 @@ fn xmain() -> ! { }), Some(api::Opcode::SuspendResume) => xous::msg_scalar_unpack!(msg, token, _, _, _, { trng.suspend(); - susres.suspend_until_resume(token).expect("couldn't execute suspend/resume"); + susres + .suspend_until_resume(token) + .expect("couldn't execute suspend/resume"); trng.resume(); }), Some(api::Opcode::ErrorSubscribe) => { - let buffer = unsafe { Buffer::from_memory_message(msg.body.memory_message().unwrap()) }; + let buffer = + unsafe { Buffer::from_memory_message(msg.body.memory_message().unwrap()) }; let hookdata = buffer.to_original::().unwrap(); do_hook(hookdata, &mut error_cb_conns); - }, + } Some(api::Opcode::ErrorNotification) => { - log::error!("Got a notification interrupt from the TRNG. Syndrome: {:?}", trng.get_errors()); + log::error!( + "Got a notification interrupt from the TRNG. Syndrome: {:?}", + trng.get_errors() + ); log::error!("Stats: {:?}", trng.get_err_stats()); send_event(&error_cb_conns); - }, + } Some(api::Opcode::HealthStats) => { - let mut buffer = unsafe { Buffer::from_memory_message_mut(msg.body.memory_message_mut().unwrap()) }; + let mut buffer = unsafe { + Buffer::from_memory_message_mut(msg.body.memory_message_mut().unwrap()) + }; buffer.replace(trng.get_tests()).unwrap(); - }, + } Some(api::Opcode::ErrorStats) => { - let mut buffer = unsafe { Buffer::from_memory_message_mut(msg.body.memory_message_mut().unwrap()) }; + let mut buffer = unsafe { + Buffer::from_memory_message_mut(msg.body.memory_message_mut().unwrap()) + }; buffer.replace(trng.get_errors()).unwrap(); - }, + } Some(api::Opcode::FillTrng) => { - let mut buffer = unsafe { Buffer::from_memory_message_mut(msg.body.memory_message_mut().unwrap()) }; + let mut buffer = unsafe { + Buffer::from_memory_message_mut(msg.body.memory_message_mut().unwrap()) + }; let len = buffer.as_flat::().unwrap().len; buffer.replace(trng.get_buf(len)).unwrap(); - }, - Some(api::Opcode::Quit) => { - break - }, + } + Some(api::Opcode::Quit) => break, None => { log::error!("couldn't convert opcode, ignoring"); } @@ -748,7 +852,6 @@ fn xmain() -> ! { xous::terminate_process(0) } - fn do_hook(hookdata: ScalarHook, cb_conns: &mut [Option; 32]) { let (s0, s1, s2, s3) = hookdata.sid; let sid = xous::SID::from_u32(s0, s1, s2, s3); @@ -773,10 +876,20 @@ fn do_hook(hookdata: ScalarHook, cb_conns: &mut [Option; 32]) { fn unhook(cb_conns: &mut [Option; 32]) { for entry in cb_conns.iter_mut() { if let Some(scb) = entry { - xous::send_message(scb.server_to_cb_cid, - xous::Message::new_blocking_scalar(api::EventCallback::Drop.to_usize().unwrap(), 0, 0, 0, 0) - ).unwrap(); - unsafe{xous::disconnect(scb.server_to_cb_cid).unwrap();} + xous::send_message( + scb.server_to_cb_cid, + xous::Message::new_blocking_scalar( + api::EventCallback::Drop.to_usize().unwrap(), + 0, + 0, + 0, + 0, + ), + ) + .unwrap(); + unsafe { + xous::disconnect(scb.server_to_cb_cid).unwrap(); + } } *entry = None; } @@ -785,10 +898,17 @@ fn send_event(cb_conns: &[Option; 32]) { for entry in cb_conns.iter() { if let Some(scb) = entry { // note that the "which" argument is only used for GPIO events, to indicate which pin had the event - xous::send_message(scb.server_to_cb_cid, - xous::Message::new_scalar(api::EventCallback::Event.to_usize().unwrap(), - scb.cb_to_client_cid as usize, scb.cb_to_client_id as usize, 0, 0) - ).unwrap(); + xous::send_message( + scb.server_to_cb_cid, + xous::Message::new_scalar( + api::EventCallback::Event.to_usize().unwrap(), + scb.cb_to_client_cid as usize, + scb.cb_to_client_id as usize, + 0, + 0, + ), + ) + .unwrap(); }; } }