diff --git a/task/hiffy/Cargo.toml b/task/hiffy/Cargo.toml index ccd56f270..fc8a927bd 100644 --- a/task/hiffy/Cargo.toml +++ b/task/hiffy/Cargo.toml @@ -42,9 +42,10 @@ i2c = [] gpio = [] spi = [] send = [] +send-rw = [] sprot = ["drv-sprot-api"] -stm32h7 = ["drv-stm32xx-sys-api/family-stm32h7", "userlib/panic-messages", "send"] -lpc55 = ["drv-lpc55-gpio-api", "userlib/panic-messages", "send"] +stm32h7 = ["drv-stm32xx-sys-api/family-stm32h7", "userlib/panic-messages", "send", "send-rw"] +lpc55 = ["drv-lpc55-gpio-api", "userlib/panic-messages", "send", "send-rw"] stm32g0 = ["drv-stm32xx-sys-api/family-stm32g0"] qspi = ["drv-gimlet-hf-api"] hash = ["drv-hash-api"] diff --git a/task/hiffy/src/common.rs b/task/hiffy/src/common.rs index a5bb985f8..eff226a42 100644 --- a/task/hiffy/src/common.rs +++ b/task/hiffy/src/common.rs @@ -419,6 +419,159 @@ pub(crate) fn send_lease_write( Ok(nreply + nlease) } +/// +/// Function to send an arbitrary message to an arbitrary task with a single +/// read lease and a single write lease attached to the tail end of `rval` +/// (shared with reply bytes) +/// +/// arg2+n+3: Size of write lease +/// arg2+n+2: Size of read lease +/// arg2+n+1: Number of reply bytes +/// arg2+n: Number of bytes +/// arg2: Argument bytes +/// arg1: Operation +/// arg0: Task +/// +#[cfg(feature = "send-rw")] +#[allow(dead_code)] +pub(crate) fn send_lease_read_write( + stack: &[Option], + data: &[u8], + rval: &mut [u8], +) -> Result { + let mut payload = [0u8; 32]; + + if stack.len() < 6 { + return Err(Failure::Fault(Fault::MissingParameters)); + } + + let sp = stack.len(); + + // get number of bytes in writable lease + let nlease_write = match stack[sp - 1] { + Some(n) => n as usize, + None => { + return Err(Failure::Fault(Fault::EmptyParameter(6))); + } + }; + + // get number of bytes in the readable lease + let nlease_read = match stack[sp - 2] { + Some(n) => n as usize, + None => { + return Err(Failure::Fault(Fault::EmptyParameter(5))); + } + }; + + // ensure the size of the provided slice is sufficient to hold the + // size described by the stack + if nlease_read > data.len() { + return Err(Failure::Fault(Fault::BadParameter(5))); + } + + // get size of reply required by the op + let nreply = match stack[sp - 3] { + Some(n) => n as usize, + None => { + return Err(Failure::Fault(Fault::EmptyParameter(4))); + } + }; + + // ensure the reply and writable lease will fit in the provided writable + // slice + if nreply + nlease_write > rval.len() { + return Err(Failure::Fault(Fault::ReturnStackOverflow)); + } + + // get number of bytes in payload + let nbytes = match stack[sp - 4] { + Some(n) => n as usize, + None => { + return Err(Failure::Fault(Fault::EmptyParameter(3))); + } + }; + + // ensure stack is large enough to hold the op payload + hif data + if stack.len() < nbytes + 6 { + return Err(Failure::Fault(Fault::StackUnderflow)); + } + + let fp = sp - (nbytes + 6); + + // get id of the task we've been asked to call + let task = match stack[fp + 0] { + Some(task) => { + if task >= NUM_TASKS as u32 { + return Err(Failure::Fault(Fault::BadParameter(0))); + } + + let prototype = + TaskId::for_index_and_gen(task as usize, Generation::default()); + + sys_refresh_task_id(prototype) + } + None => { + return Err(Failure::Fault(Fault::EmptyParameter(0))); + } + }; + + // get id of the operation we've been asked to call + let op = match stack[fp + 1] { + Some(op) => { + if op > core::u16::MAX.into() { + return Err(Failure::Fault(Fault::BadParameter(1))); + } + + op as u16 + } + None => { + return Err(Failure::Fault(Fault::EmptyParameter(1))); + } + }; + + if nbytes > payload.len() { + return Err(Failure::Fault(Fault::StackUnderflow)); + } + + let base = fp + 2; + + // copy the payload from the stack + for i in base..base + nbytes { + payload[i - base] = match stack[i] { + Some(byte) => { + if byte > core::u8::MAX.into() { + return Err(Failure::Fault(Fault::BadParameter(2))); + } + + byte as u8 + } + None => { + return Err(Failure::Fault(Fault::EmptyParameter(2))); + } + }; + } + + // split rval into two writable leases: one for the data returned by the + // task / op we're calling, the other for the writable lease passed to same + let (rval, lease) = rval.split_at_mut(nreply); + let (code, _) = sys_send( + task, + op, + &payload[0..nbytes], + &mut rval[0..nreply], + &[ + userlib::Lease::read_only(&data[..nlease_read]), + userlib::Lease::write_only(&mut lease[..nlease_write]), + ], + ); + + if code != 0 { + return Err(Failure::FunctionError(code)); + } + + Ok(nreply + nlease_write) +} + #[cfg(feature = "spi")] fn spi_args(stack: &[Option]) -> Result<(TaskId, u8, usize), Failure> { if stack.len() < 3 { diff --git a/task/hiffy/src/lpc55.rs b/task/hiffy/src/lpc55.rs index e0bf2e574..eff356ad7 100644 --- a/task/hiffy/src/lpc55.rs +++ b/task/hiffy/src/lpc55.rs @@ -36,6 +36,7 @@ pub enum Functions { Sleep(u16, u32), Send((Task, u16, Buffer, usize), u32), SendLeaseRead((Task, u16, Buffer, usize, usize), u32), + SendLeaseReadWrite((Task, u16, Buffer, usize, usize, usize), u32), SendLeaseWrite((Task, u16, Buffer, usize, usize), u32), #[cfg(feature = "gpio")] GpioInput(drv_lpc55_gpio_api::Pin, u32), @@ -348,6 +349,7 @@ pub(crate) static HIFFY_FUNCS: &[Function] = &[ crate::common::sleep, crate::common::send, crate::common::send_lease_read, + crate::common::send_lease_read_write, crate::common::send_lease_write, #[cfg(feature = "gpio")] gpio_input, diff --git a/task/hiffy/src/stm32g0.rs b/task/hiffy/src/stm32g0.rs index dc2440cd2..2e52f6cdd 100644 --- a/task/hiffy/src/stm32g0.rs +++ b/task/hiffy/src/stm32g0.rs @@ -32,6 +32,8 @@ pub enum Functions { Send((Task, u16, Buffer, usize), u32), #[cfg(feature = "send")] SendLeaseRead((Task, u16, Buffer, usize, usize), u32), + #[cfg(feature = "send-rw")] + SendLeaseReadWrite((Task, u16, Buffer, usize, usize, usize), u32), #[cfg(feature = "send")] SendLeaseWrite((Task, u16, Buffer, usize, usize), u32), #[cfg(feature = "i2c")] @@ -430,6 +432,8 @@ pub(crate) static HIFFY_FUNCS: &[Function] = &[ crate::common::send, #[cfg(feature = "send")] crate::common::send_lease_read, + #[cfg(feature = "send-rw")] + crate::common::send_lease_read_write, #[cfg(feature = "send")] crate::common::send_lease_write, #[cfg(feature = "i2c")] diff --git a/task/hiffy/src/stm32h7.rs b/task/hiffy/src/stm32h7.rs index 02c5f9056..26636fb5a 100644 --- a/task/hiffy/src/stm32h7.rs +++ b/task/hiffy/src/stm32h7.rs @@ -56,6 +56,7 @@ pub enum Functions { Sleep(u16, u32), Send((Task, u16, Buffer, usize), u32), SendLeaseRead((Task, u16, Buffer, usize, usize), u32), + SendLeaseReadWrite((Task, u16, Buffer, usize, usize, usize), u32), SendLeaseWrite((Task, u16, Buffer, usize, usize), u32), #[cfg(feature = "i2c")] I2cRead( @@ -525,6 +526,7 @@ pub(crate) static HIFFY_FUNCS: &[Function] = &[ crate::common::sleep, crate::common::send, crate::common::send_lease_read, + crate::common::send_lease_read_write, crate::common::send_lease_write, #[cfg(feature = "i2c")] i2c_read,