mirror of
https://github.com/saymrwulf/xous-core.git
synced 2026-11-08 04:56:43 +00:00
move trng into the standardized formatting set with some exceptions
This commit is contained in:
parent
6f5be1e4bb
commit
fd4e047d62
4 changed files with 306 additions and 155 deletions
|
|
@ -2,7 +2,7 @@ ignore = [
|
|||
"services/graphics-server",
|
||||
"services/com",
|
||||
"services/keyboard",
|
||||
"services/trng",
|
||||
#"services/trng",
|
||||
"services/gam",
|
||||
"services/status",
|
||||
"services/benchmark",
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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<Self, xous::Error> {
|
||||
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<u32, xous::Error> {
|
||||
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<u64, xous::Error> {
|
||||
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<api::HealthTests, xous::Error> {
|
||||
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<api::TrngErrors, xous::Error> {
|
||||
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))
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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<u32>,
|
||||
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<u32>,
|
||||
messible_csr: utralib::CSR<u32>,
|
||||
|
|
@ -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<ScalarCallback>; 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::<api::ScalarHook, _>().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::<TrngBuf, _>().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<ScalarCallback>; 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<ScalarCallback>; 32]) {
|
|||
fn unhook(cb_conns: &mut [Option<ScalarCallback>; 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<ScalarCallback>; 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();
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue