diff --git a/Cargo.lock b/Cargo.lock index 51f6bee17..14c003258 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5840,6 +5840,7 @@ dependencies = [ "ringbuf", "serde", "static-cell", + "task-net-api", "test-api", "userlib", "zerocopy 0.8.27", diff --git a/app/cosmo/base.toml b/app/cosmo/base.toml index 5757837ae..cf69d2d0c 100644 --- a/app/cosmo/base.toml +++ b/app/cosmo/base.toml @@ -46,7 +46,7 @@ name = "task-net" stacksize = 8000 priority = 5 features = ["mgmt", "h753", "cosmo", "vlan", "vpd-mac"] -max-sizes = {flash = 131072, ram = 65536, sram1_mac = 16384} +max-sizes = {flash = 131072, ram = 131072, sram1_mac = 16384} default-ram = "dtcm" sections = {eth_bulk = "sram1_mac"} uses = ["eth", "tim16"] @@ -171,10 +171,11 @@ notifications = ["timer"] name = "task-hiffy" features = ["h753", "stm32h7", "i2c", "gpio", "spi", "qspi", "hash", "sprot", "turbo"] priority = 7 -max-sizes = {flash = 32768, ram = 32768 } +max-sizes = {flash = 32768, ram = 65536 } stacksize = 1200 start = true -task-slots = ["sys", "hf", "i2c_driver", "hash_driver", "update_server", "sprot"] +task-slots = ["sys", "hf", "i2c_driver", "hash_driver", "update_server", "sprot", "net"] +notifications = ["timer"] [tasks.cosmo_seq] name = "drv-cosmo-seq-server" diff --git a/app/cosmo/dev.toml b/app/cosmo/dev.toml index 70ab20e45..3c23b437b 100644 --- a/app/cosmo/dev.toml +++ b/app/cosmo/dev.toml @@ -29,9 +29,20 @@ port = 998 tx = { packets = 3, bytes = 1024 } rx = { packets = 3, bytes = 1024 } +[tasks.hiffy] +features = ["net", "vlan"] +notifications = ["socket"] + [config.net.sockets.fmc_test] kind = "udp" owner = {name = "fmc_demo", notification = "socket"} port = 11114 tx = { packets = 3, bytes = 4096 } rx = { packets = 3, bytes = 4096 } + +[config.net.sockets.hiffy] +kind = "udp" +owner = {name = "hiffy", notification = "socket"} +port = 11115 +tx = { packets = 3, bytes = 32 } +rx = { packets = 1, bytes = 4096 } diff --git a/app/demo-stm32f4-discovery/app-f3.toml b/app/demo-stm32f4-discovery/app-f3.toml index 61ea32183..efab4abe9 100644 --- a/app/demo-stm32f4-discovery/app-f3.toml +++ b/app/demo-stm32f4-discovery/app-f3.toml @@ -69,6 +69,7 @@ priority = 3 max-sizes = {flash = 16384, ram = 16384 } stacksize = 2048 start = true +notifications = ["timer"] [tasks.idle] name = "task-idle" diff --git a/app/demo-stm32f4-discovery/app.toml b/app/demo-stm32f4-discovery/app.toml index f6816a882..e804d0a78 100644 --- a/app/demo-stm32f4-discovery/app.toml +++ b/app/demo-stm32f4-discovery/app.toml @@ -69,6 +69,7 @@ priority = 3 max-sizes = {flash = 16384, ram = 16384 } stacksize = 2048 start = true +notifications = ["timer"] [tasks.idle] name = "task-idle" diff --git a/app/demo-stm32g0-nucleo/app-g031.toml b/app/demo-stm32g0-nucleo/app-g031.toml index bb537f7d3..b60c2000e 100644 --- a/app/demo-stm32g0-nucleo/app-g031.toml +++ b/app/demo-stm32g0-nucleo/app-g031.toml @@ -56,6 +56,7 @@ start = true task-slots = ["sys"] stacksize = 912 features = ["stm32g0", "gpio", "micro", "send"] +notifications = ["timer"] [tasks.idle] name = "task-idle" diff --git a/app/demo-stm32g0-nucleo/app-g070.toml b/app/demo-stm32g0-nucleo/app-g070.toml index 57eabd710..1be325868 100644 --- a/app/demo-stm32g0-nucleo/app-g070.toml +++ b/app/demo-stm32g0-nucleo/app-g070.toml @@ -76,6 +76,7 @@ features = ["no-ipc-counters"] priority = 3 max-sizes = {flash = 8192, ram = 8192 } start = true +notifications = ["timer"] [tasks.idle] name = "task-idle" diff --git a/app/demo-stm32g0-nucleo/app-g0b1.toml.noworky b/app/demo-stm32g0-nucleo/app-g0b1.toml.noworky index 5209dd9b6..99019cd4a 100644 --- a/app/demo-stm32g0-nucleo/app-g0b1.toml.noworky +++ b/app/demo-stm32g0-nucleo/app-g0b1.toml.noworky @@ -83,6 +83,7 @@ name = "task-hiffy" priority = 3 requires = {flash = 8192, ram = 8192 } start = true +notifications = ["timer"] [tasks.idle] name = "task-idle" diff --git a/app/demo-stm32h7-nucleo/app-h743.toml b/app/demo-stm32h7-nucleo/app-h743.toml index 3814cf55e..d7077f216 100644 --- a/app/demo-stm32h7-nucleo/app-h743.toml +++ b/app/demo-stm32h7-nucleo/app-h743.toml @@ -127,6 +127,7 @@ max-sizes = {flash = 32768, ram = 65536 } stacksize = 2048 start = true task-slots = ["sys", "i2c_driver"] +notifications = ["timer"] [tasks.idle] name = "task-idle" diff --git a/app/demo-stm32h7-nucleo/app-h753.toml b/app/demo-stm32h7-nucleo/app-h753.toml index d7df7ca63..3be7c6241 100644 --- a/app/demo-stm32h7-nucleo/app-h753.toml +++ b/app/demo-stm32h7-nucleo/app-h753.toml @@ -153,6 +153,7 @@ max-sizes = {flash = 32768, ram = 65536 } stacksize = 2048 start = true task-slots = ["sys", "i2c_driver", "hf", "hash_driver"] +notifications = ["timer"] [tasks.hf] name = "drv-mock-gimlet-hf-server" diff --git a/app/donglet/app-g031-i2c.toml b/app/donglet/app-g031-i2c.toml index ac2348d27..dc7e8b295 100644 --- a/app/donglet/app-g031-i2c.toml +++ b/app/donglet/app-g031-i2c.toml @@ -49,6 +49,7 @@ start = true task-slots = ["sys", "i2c_driver"] stacksize = 912 features = ["stm32g0", "g031", "i2c", "gpio", "send", "no-ipc-counters"] +notifications = ["timer"] [tasks.idle] name = "task-idle" diff --git a/app/donglet/app-g031.toml b/app/donglet/app-g031.toml index b6c0b06c4..a484effa0 100644 --- a/app/donglet/app-g031.toml +++ b/app/donglet/app-g031.toml @@ -68,6 +68,7 @@ start = true task-slots = ["sys"] stacksize = 912 features = ["stm32g0", "g031", "gpio", "micro", "send"] +notifications = ["timer"] [tasks.idle] name = "task-idle" diff --git a/app/gemini-bu/app.toml b/app/gemini-bu/app.toml index daec06ae3..25f197ece 100644 --- a/app/gemini-bu/app.toml +++ b/app/gemini-bu/app.toml @@ -124,6 +124,7 @@ max-sizes = {flash = 32768, ram = 16384 } stacksize = 2048 start = true task-slots = ["sys", "i2c_driver", "hf", "hash_driver", "sprot", "update_server"] +notifications = ["timer"] [tasks.sprot] name = "drv-stm32h7-sprot-server" diff --git a/app/gimlet/base.toml b/app/gimlet/base.toml index 8444756fb..41cc38e2e 100644 --- a/app/gimlet/base.toml +++ b/app/gimlet/base.toml @@ -159,6 +159,7 @@ max-sizes = {flash = 32768, ram = 32768 } stacksize = 1200 start = true task-slots = ["sys", "hf", "i2c_driver", "hash_driver", "update_server", "sprot"] +notifications = ["timer"] [tasks.gimlet_seq] name = "drv-gimlet-seq-server" diff --git a/app/gimletlet/app-mgmt.toml b/app/gimletlet/app-mgmt.toml index 57ba434eb..05dcf263e 100644 --- a/app/gimletlet/app-mgmt.toml +++ b/app/gimletlet/app-mgmt.toml @@ -46,6 +46,7 @@ max-sizes = {flash = 32768, ram = 65536 } stacksize = 2048 start = true task-slots = ["sys", "user_leds"] +notifications = ["timer"] [tasks.net] name = "task-net" diff --git a/app/gimletlet/base-gimletlet2.toml b/app/gimletlet/base-gimletlet2.toml index 3e1ffee07..f173272ff 100644 --- a/app/gimletlet/base-gimletlet2.toml +++ b/app/gimletlet/base-gimletlet2.toml @@ -85,6 +85,7 @@ priority = 7 max-sizes = {flash = 32768, ram = 65536} stacksize = 2048 start = true +notifications = ["timer"] [tasks.validate] name = "task-validate" diff --git a/app/grapefruit/base.toml b/app/grapefruit/base.toml index d3baa9ef0..42315ec22 100644 --- a/app/grapefruit/base.toml +++ b/app/grapefruit/base.toml @@ -118,8 +118,9 @@ priority = 7 max-sizes = {flash = 32768, ram = 65536} stacksize = 2048 start = true -features = ["h753", "stm32h7", "i2c", "gpio", "sprot", "qspi", "hash", "turbo"] -task-slots = ["i2c_driver", "sys", "user_leds", "sprot", "hf", "hash_driver"] +features = ["h753", "stm32h7", "i2c", "gpio", "sprot", "qspi", "hash", "turbo", "net", "vlan"] +task-slots = ["i2c_driver", "sys", "user_leds", "sprot", "hf", "hash_driver", "net"] +notifications = ["timer", "socket"] [tasks.validate] name = "task-validate" @@ -276,7 +277,7 @@ name = "task-net" stacksize = 8000 priority = 3 features = ["h753", "vlan", "grapefruit"] -max-sizes = {flash = 131072, ram = 65536, sram1_mac = 16384} +max-sizes = {flash = 131072, ram = 131072, sram1_mac = 16384} default-ram = "dtcm" sections = {eth_bulk = "sram1_mac"} uses = ["eth", "tim16"] @@ -391,6 +392,13 @@ port = 11114 tx = { packets = 3, bytes = 4096 } rx = { packets = 3, bytes = 4096 } +[config.net.sockets.hiffy] +kind = "udp" +owner = {name = "hiffy", notification = "socket"} +port = 11115 +tx = { packets = 3, bytes = 4096 } +rx = { packets = 3, bytes = 4096 } + ################################################################################ [config] diff --git a/app/lpc55xpresso/app.toml b/app/lpc55xpresso/app.toml index 989211016..ca437f53e 100644 --- a/app/lpc55xpresso/app.toml +++ b/app/lpc55xpresso/app.toml @@ -35,6 +35,7 @@ max-sizes = {flash = 32768, ram = 16384 } stacksize = 2048 start = true task-slots = ["gpio_driver", "update_server"] +notifications = ["timer"] [tasks.idle] name = "task-idle" diff --git a/app/medusa/base.toml b/app/medusa/base.toml index cd77a134d..ee522d588 100644 --- a/app/medusa/base.toml +++ b/app/medusa/base.toml @@ -51,6 +51,7 @@ stacksize = 2048 start = true task-slots = ["sys", "i2c_driver"] features = ["turbo"] +notifications = ["timer"] [tasks.i2c_driver] name = "drv-stm32xx-i2c-server" diff --git a/app/minibar/base.toml b/app/minibar/base.toml index eafdbb37e..31e287199 100644 --- a/app/minibar/base.toml +++ b/app/minibar/base.toml @@ -103,6 +103,7 @@ max-sizes = {flash = 32768, ram = 32768 } stacksize = 1200 start = true task-slots = ["sys", "i2c_driver", "sprot"] +notifications = ["timer"] [tasks.thermal] name = "task-thermal" diff --git a/app/oxcon2023g0/app.toml b/app/oxcon2023g0/app.toml index ea53b1b48..b42b214ec 100644 --- a/app/oxcon2023g0/app.toml +++ b/app/oxcon2023g0/app.toml @@ -47,6 +47,7 @@ start = true task-slots = ["sys", "i2c_driver"] stacksize = 912 features = ["stm32g0", "gpio", "i2c", "g030", "micro"] +notifications = ["timer"] [tasks.i2c_driver] name = "drv-stm32xx-i2c-server" diff --git a/app/oxide-rot-1/app-dev.toml b/app/oxide-rot-1/app-dev.toml index f1ed39547..49cea1c5e 100644 --- a/app/oxide-rot-1/app-dev.toml +++ b/app/oxide-rot-1/app-dev.toml @@ -40,6 +40,7 @@ max-sizes = {flash = 32768, ram = 16384 } stacksize = 2048 start = true task-slots = ["gpio_driver", "swd", "update_server"] +notifications = ["timer"] [tasks.idle] name = "task-idle" diff --git a/app/psc/base.toml b/app/psc/base.toml index 446113095..0538116e1 100644 --- a/app/psc/base.toml +++ b/app/psc/base.toml @@ -162,6 +162,7 @@ max-sizes = {flash = 32768} stacksize = 1200 start = true task-slots = ["sys", "i2c_driver", "sprot"] +notifications = ["timer"] [tasks.validate] name = "task-validate" diff --git a/app/rot-carrier/app.toml b/app/rot-carrier/app.toml index a920c28f9..f3233e263 100644 --- a/app/rot-carrier/app.toml +++ b/app/rot-carrier/app.toml @@ -132,6 +132,7 @@ max-sizes = {flash = 32768, ram = 16384 } stacksize = 2048 start = true task-slots = ["gpio_driver", "update_server"] +notifications = ["timer"] [tasks.attest] name = "task-attest" diff --git a/app/sidecar/base.toml b/app/sidecar/base.toml index 362ce2994..29661dedc 100644 --- a/app/sidecar/base.toml +++ b/app/sidecar/base.toml @@ -207,6 +207,7 @@ max-sizes = {flash = 32768, ram = 32768 } stacksize = 1200 start = true task-slots = ["sys", "i2c_driver", "sprot"] +notifications = ["timer"] [tasks.sensor] name = "task-sensor" diff --git a/task/hiffy/Cargo.toml b/task/hiffy/Cargo.toml index 7bf7056d1..6de62de3d 100644 --- a/task/hiffy/Cargo.toml +++ b/task/hiffy/Cargo.toml @@ -13,6 +13,7 @@ drv-spi-api = { path = "../../drv/spi-api" } drv-sprot-api = { path = "../../drv/sprot-api", optional = true } drv-stm32xx-i2c = { path = "../../drv/stm32xx-i2c", optional = true } drv-stm32xx-sys-api = { path = "../../drv/stm32xx-sys-api", optional = true } +task-net-api = { path = "../../task/net-api", optional = true } hubris-num-tasks = { path = "../../sys/num-tasks", features = ["task-enum"] } ringbuf = { path = "../../lib/ringbuf" } static-cell = { path = "../../lib/static-cell" } @@ -63,6 +64,8 @@ micro = ["no-ipc-counters"] turbo = [] panic-messages = ["userlib/panic-messages"] spctrl = ["drv-sp-ctrl-api"] +net = ["task-net-api"] +vlan = ["task-net-api?/vlan"] # This section is here to discourage RLS/rust-analyzer from doing test builds, # since test builds don't work for cross compilation. diff --git a/task/hiffy/build.rs b/task/hiffy/build.rs index 280089593..d90cea3b7 100644 --- a/task/hiffy/build.rs +++ b/task/hiffy/build.rs @@ -2,6 +2,8 @@ // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at https://mozilla.org/MPL/2.0/. -fn main() { +fn main() -> anyhow::Result<()> { build_util::expose_target_board(); + build_util::build_notifications()?; + Ok(()) } diff --git a/task/hiffy/src/main.rs b/task/hiffy/src/main.rs index adfeca4e8..175c7ee4d 100644 --- a/task/hiffy/src/main.rs +++ b/task/hiffy/src/main.rs @@ -192,83 +192,104 @@ fn main() -> ! { let mut stack = [None; 32]; const NLABELS: usize = 4; + #[cfg(feature = "net")] + let mut net_state = net::State::new(); + loop { + // Sleep until either the timer expires or we receive a notification + // from the `net` task indicating that it's ready for us. + let deadline = sys_get_timer().now.saturating_add(sleep_ms); HIFFY_READY.store(1, Ordering::Relaxed); - hl::sleep_for(sleep_ms); + sys_set_timer(Some(deadline), notifications::TIMER_MASK); + + #[cfg(feature = "net")] + let bits = notifications::SOCKET_MASK | notifications::TIMER_MASK; + #[cfg(not(feature = "net"))] + let bits = notifications::TIMER_MASK; + + let notif = sys_recv_notification(bits); HIFFY_READY.store(0, Ordering::Relaxed); - // Humility writes `1` to `HIFFY_KICK` - if HIFFY_KICK.load(Ordering::Acquire) == 0 { - sleeps += 1; + #[cfg(feature = "net")] + if notif.check_notification_mask(notifications::SOCKET_MASK) { + net_state.check_net(); + } + + if notif.has_timer_fired(notifications::TIMER_MASK) { + // Humility writes `1` to `HIFFY_KICK` + if HIFFY_KICK.load(Ordering::Acquire) == 0 { + sleeps += 1; + + // Exponentially backoff our sleep value, but no more than 250ms + if sleeps == 10 { + sleep_ms = core::cmp::min(sleep_ms * 10, 250); + sleeps = 0; + } - // Exponentially backoff our sleep value, but no more than 250ms - if sleeps == 10 { - sleep_ms = core::cmp::min(sleep_ms * 10, 250); - sleeps = 0; + continue; } - continue; - } + // + // Whenever we have been kicked, we adjust our timeout down to 1ms, + // from which we will exponentially backoff + // + HIFFY_KICK.store(0, Ordering::Release); + sleep_ms = 1; + sleeps = 0; - // - // Whenever we have been kicked, we adjust our timeout down to 1ms, - // from which we will exponentially backoff - // - HIFFY_KICK.store(0, Ordering::Release); - sleep_ms = 1; - sleeps = 0; - - let check = |offset: usize, op: &Op| -> Result<(), Failure> { - trace_execute(offset, *op); - Ok(()) - }; - - let rv = { - // Dummy object to bind references to a non-static lifetime - let lifetime = (); - - // SAFETY: We construct references from our pointers with a limited - // (non-static) lifetime, so they can't escape this block. We are - // in single-threaded code, so no one else can read or write to - // static memory. While the HIF program is running, the debugger is - // only reading from `HIFFY_REQUESTS` and `HIFFY_ERRORS`; it is not - // writing to any locations in memory. See the diagram above for - // Hubris / Humility coordination. - let (text, data, rstack) = unsafe { - ( - bind_lifetime_ref(&lifetime, &raw const HIFFY_TEXT), - bind_lifetime_ref(&lifetime, &raw const HIFFY_DATA), - bind_lifetime_mut(&lifetime, &raw mut HIFFY_RSTACK), + let check = |offset: usize, op: &Op| -> Result<(), Failure> { + trace_execute(offset, *op); + Ok(()) + }; + let rv = { + // Dummy object to bind references to a non-static lifetime + let lifetime = (); + + // SAFETY: We construct references from our pointers with a limited + // (non-static) lifetime, so they can't escape this block. We are + // in single-threaded code, so no one else can read or write to + // static memory. While the HIF program is running, the debugger is + // only reading from `HIFFY_REQUESTS` and `HIFFY_ERRORS`; it is not + // writing to any locations in memory. See the diagram above for + // Hubris / Humility coordination. + let (text, data, rstack) = unsafe { + ( + bind_lifetime_ref(&lifetime, &raw const HIFFY_TEXT), + bind_lifetime_ref(&lifetime, &raw const HIFFY_DATA), + bind_lifetime_mut(&lifetime, &raw mut HIFFY_RSTACK), + ) + }; + execute::<_, NLABELS>( + text, + HIFFY_FUNCS, + data, + &mut stack, + rstack, + &mut *HIFFY_SCRATCH.borrow_mut(), + check, ) }; - execute::<_, NLABELS>( - text, - HIFFY_FUNCS, - data, - &mut stack, - rstack, - &mut *HIFFY_SCRATCH.borrow_mut(), - check, - ) - }; - - match rv { - Ok(_) => { - let prev = HIFFY_REQUESTS.load(Ordering::Relaxed); - HIFFY_REQUESTS.store(prev.wrapping_add(1), Ordering::Release); - trace_success(); - } - Err(failure) => { - // SAFETY: We are in single-threaded code and the debugger will - // not be reading HIFFY_FAILURE until HIFFY_ERRORS is - // incremented below. See the diagram above for Hubris / - // Humility coordination. - unsafe { - HIFFY_FAILURE = Some(failure); + + match rv { + Ok(_) => { + let prev = HIFFY_REQUESTS.load(Ordering::Relaxed); + HIFFY_REQUESTS + .store(prev.wrapping_add(1), Ordering::Release); + trace_success(); + } + Err(failure) => { + // SAFETY: We are in single-threaded code and the debugger will + // not be reading HIFFY_FAILURE until HIFFY_ERRORS is + // incremented below. See the diagram above for Hubris / + // Humility coordination. + unsafe { + HIFFY_FAILURE = Some(failure); + let prev = HIFFY_ERRORS.load(Ordering::Relaxed); + HIFFY_ERRORS + .store(prev.wrapping_add(1), Ordering::Release); + trace_failure(failure); + } } - let prev = HIFFY_ERRORS.load(Ordering::Relaxed); - HIFFY_ERRORS.store(prev.wrapping_add(1), Ordering::Release); - trace_failure(failure); } } } @@ -303,3 +324,217 @@ unsafe fn bind_lifetime_mut<'a, const N: usize>( // safety conditions (listed in docstring) unsafe { array.as_mut().unwrap_lite() } } + +#[cfg(feature = "net")] +mod net { + use super::{ + HIFFY_DATA, HIFFY_KICK, HIFFY_TEXT, bind_lifetime_mut, notifications, + }; + use core::sync::atomic::Ordering; + use static_cell::ClaimOnceCell; + use task_net_api::{ + LargePayloadBehavior, RecvError, SendError, SocketName, UdpMetadata, + }; + use userlib::{FromPrimitive, UnwrapLite, sys_recv_notification}; + use zerocopy::{FromBytes, IntoBytes, LittleEndian, U16, U32, U64}; + + const SOCKET: SocketName = SocketName::hiffy; + const SOCKET_TX_SIZE: usize = task_net_api::SOCKET_TX_SIZE[SOCKET as usize]; + const SOCKET_RX_SIZE: usize = task_net_api::SOCKET_RX_SIZE[SOCKET as usize]; + + /// Header for an RPC request + /// + /// `humility` must cooperate with this layout and the `OP_*` values below; + /// they are mirrored in `doppel.rs`. + #[derive(Copy, Clone, Debug, FromBytes)] + #[repr(C)] + struct RpcHeader { + /// Expected image ID + image_id: U64, + /// Header version (always 1 right now) + version: U16, + /// Operation to perform + operation: U16, + /// Argument-dependent operation + arg: U32, + } + const CURRENT_VERSION: u16 = 1; + + #[derive(Copy, Clone, Debug, FromPrimitive)] + #[repr(u16)] + enum RpcOp { + WriteHiffyText = 1, + WriteHiffyData, + HiffyKick, + } + + #[derive(Copy, Clone, Debug)] + #[repr(u8)] + enum RpcReply { + Ok = 0u8, + /// The RPC packet was too short to include the complete header + TooShort, + /// The RPC packet's image ID does not match ours + BadImageId, + /// The RPC packet's header version does not match our version + BadVersion, + /// The RPC operation field is invalid + InvalidOperation, + /// The write exceeds our data buffers + OutOfRange, + } + + userlib::task_slot!(NET, net); + + pub(super) struct State { + net: task_net_api::Net, + tx_data_buf: &'static mut [u8], + rx_data_buf: &'static mut [u8], + image_id: u64, + } + impl State { + pub(super) fn new() -> Self { + let (tx_data_buf, rx_data_buf) = { + static BUFS: ClaimOnceCell<( + [u8; SOCKET_TX_SIZE], + [u8; SOCKET_RX_SIZE], + )> = ClaimOnceCell::new(( + [0; SOCKET_TX_SIZE], + [0; SOCKET_RX_SIZE], + )); + BUFS.claim() + }; + let net = task_net_api::Net::from(NET.get_task_id()); + let image_id = userlib::kipc::read_image_id(); + Self { + net, + tx_data_buf, + rx_data_buf, + image_id, + } + } + pub(super) fn check_net(&mut self) { + match self.net.recv_packet( + SOCKET, + LargePayloadBehavior::Discard, + self.rx_data_buf, + ) { + Ok(meta) => self.handle_packet(meta), + Err(RecvError::QueueEmpty | RecvError::ServerRestarted) => { + // Our incoming queue is empty or `net` restarted. Wait for + // more packets in dispatch, back in the main loop. + } + } + } + + fn handle_packet(&mut self, mut meta: UdpMetadata) { + // Steal `tx_data_buf` to work around lifetime shenanigans; + // `handle_packet_inner` does not write to it! + let tx_data_buf = core::mem::take(&mut self.tx_data_buf); + let (r, data) = self.handle_packet_inner(meta); + tx_data_buf[0] = r as u8; + tx_data_buf[1..][..data.len()].copy_from_slice(data); + meta.size = (1 + data.len()) as u32; + self.tx_data_buf = tx_data_buf; + loop { + match self.net.send_packet( + SOCKET, + meta, + &self.tx_data_buf[..(meta.size as usize)], + ) { + Ok(()) => break, + // If `net` just restarted, immediately retry our send. + Err(SendError::ServerRestarted) => continue, + // If our tx queue is full, wait for space. This is the + // same notification we get for incoming packets, so we + // might spuriously wake up due to an incoming packet + // (which we can't service anyway because we are still + // waiting to respond to a previous request); once we + // finally succeed in sending we'll peel any queued + // packets off our recv queue at the top of our main + // loop. + Err(SendError::QueueFull) => { + sys_recv_notification(notifications::SOCKET_MASK); + } + } + } + } + + fn handle_packet_inner(&self, meta: UdpMetadata) -> (RpcReply, &[u8]) { + const HEADER_SIZE: usize = core::mem::size_of::(); + if (meta.size as usize) < HEADER_SIZE { + return (RpcReply::TooShort, &[]); + } + + // We can always read the header, since it's raw data + let header = + RpcHeader::read_from_bytes(&self.rx_data_buf[..HEADER_SIZE]) + .unwrap_lite(); + let rest = &self.rx_data_buf[HEADER_SIZE..]; + if self.image_id != header.image_id.get() { + return (RpcReply::BadImageId, self.image_id.as_bytes()); + } + + if header.version.get() != 1 { + return (RpcReply::BadVersion, CURRENT_VERSION.as_bytes()); + } + + // Perform the actual operation + match RpcOp::from_u16(header.operation.get()) { + Some(RpcOp::WriteHiffyText) => { + // Dummy object to bind references to a non-static lifetime + let lifetime = (); + let offset = header.arg.get() as usize; + + // SAFETY: we are constructing a slice with a bounded + // lifetime, and are in single-threaded code. We don't + // expect a debugger to be editing our memory. If someone + // is simultaneously editing `HIFFY_TEXT` with a debugger + // *and* over the network, they deserve whatever happens. + let text = unsafe { + bind_lifetime_mut(&lifetime, &raw mut HIFFY_TEXT) + }; + if let Some(chunk) = offset + .checked_add(rest.len()) + .and_then(|e| text.get_mut(offset..e)) + { + chunk.copy_from_slice(rest); + (RpcReply::Ok, &[]) + } else { + (RpcReply::OutOfRange, &[]) + } + } + Some(RpcOp::WriteHiffyData) => { + // Dummy object to bind references to a non-static lifetime + let lifetime = (); + let offset = header.arg.get() as usize; + + // SAFETY: we are constructing a slice with a bounded + // lifetime, and are in single-threaded code. We don't + // expect a debugger to be editing our memory. If someone + // is simultaneously editing `HIFFY_DATA` with a debugger + // *and* over the network, they deserve whatever happens. + let data = unsafe { + bind_lifetime_mut(&lifetime, &raw mut HIFFY_DATA) + }; + if let Some(chunk) = offset + .checked_add(rest.len()) + .and_then(|e| data.get_mut(offset..e)) + { + chunk.copy_from_slice(rest); + (RpcReply::Ok, &[]) + } else { + (RpcReply::OutOfRange, &[]) + } + } + Some(RpcOp::HiffyKick) => { + HIFFY_KICK.fetch_add(1, Ordering::SeqCst); + (RpcReply::Ok, &[]) + } + None => (RpcReply::InvalidOperation, &[]), + } + } + } +} + +include!(concat!(env!("OUT_DIR"), "/notifications.rs")); diff --git a/test/tests-gemini-bu/app.toml b/test/tests-gemini-bu/app.toml index 2aaa6e8eb..ed784087b 100644 --- a/test/tests-gemini-bu/app.toml +++ b/test/tests-gemini-bu/app.toml @@ -54,6 +54,7 @@ max-sizes = {flash = 32768, ram = 16384 } stacksize = 2048 start = true task-slots = ["suite", "runner"] +notifications = ["timer"] [tasks.idle] name = "task-idle" diff --git a/test/tests-gimletlet/app.toml b/test/tests-gimletlet/app.toml index 419f8dc82..54b5cb793 100644 --- a/test/tests-gimletlet/app.toml +++ b/test/tests-gimletlet/app.toml @@ -54,6 +54,7 @@ max-sizes = {flash = 32768, ram = 32768 } stacksize = 2048 start = true task-slots = ["suite", "runner"] +notifications = ["timer"] [tasks.idle] name = "task-idle" diff --git a/test/tests-lpc55xpresso/app.toml b/test/tests-lpc55xpresso/app.toml index e839f4497..a2ba31c6d 100644 --- a/test/tests-lpc55xpresso/app.toml +++ b/test/tests-lpc55xpresso/app.toml @@ -56,6 +56,7 @@ max-sizes = {flash = 32768, ram = 16384 } stacksize = 2048 start = true task-slots = ["suite", "runner"] +notifications = ["timer"] [tasks.idle] name = "task-idle" diff --git a/test/tests-psc/app.toml b/test/tests-psc/app.toml index 47e9f71c7..f8752a6fb 100644 --- a/test/tests-psc/app.toml +++ b/test/tests-psc/app.toml @@ -75,6 +75,7 @@ features = ["testsuite"] stacksize = 2048 start = true task-slots = ["suite", "runner"] +notifications = ["timer"] [tasks.idle] name = "task-idle" diff --git a/test/tests-rot-carrier/app.toml b/test/tests-rot-carrier/app.toml index fd77d9ae7..dd07ab0c7 100644 --- a/test/tests-rot-carrier/app.toml +++ b/test/tests-rot-carrier/app.toml @@ -56,6 +56,7 @@ max-sizes = {flash = 32768, ram = 16384 } stacksize = 2048 start = true task-slots = ["suite", "runner"] +notifications = ["timer"] [tasks.idle] name = "task-idle" diff --git a/test/tests-stm32fx/app-f3.toml b/test/tests-stm32fx/app-f3.toml index f64538016..09cce41de 100644 --- a/test/tests-stm32fx/app-f3.toml +++ b/test/tests-stm32fx/app-f3.toml @@ -55,6 +55,7 @@ max-sizes = {flash = 32768, ram = 32768 } stacksize = 2048 start = true task-slots = ["suite", "runner"] +notifications = ["timer"] [tasks.idle] name = "task-idle" diff --git a/test/tests-stm32fx/app.toml b/test/tests-stm32fx/app.toml index bff063060..1027e1e43 100644 --- a/test/tests-stm32fx/app.toml +++ b/test/tests-stm32fx/app.toml @@ -55,6 +55,7 @@ max-sizes = {flash = 32768, ram = 32768 } stacksize = 2048 start = true task-slots = ["suite", "runner"] +notifications = ["timer"] [tasks.idle] name = "task-idle" diff --git a/test/tests-stm32g0/app-g070.toml b/test/tests-stm32g0/app-g070.toml index 88d9a8e00..9a9a7d128 100644 --- a/test/tests-stm32g0/app-g070.toml +++ b/test/tests-stm32g0/app-g070.toml @@ -59,6 +59,7 @@ max-sizes = {flash = 32768, ram = 32768 } stacksize = 2048 start = true task-slots = ["suite", "runner"] +notifications = ["timer"] [tasks.idle] name = "task-idle" diff --git a/test/tests-stm32h7/app-h743.toml b/test/tests-stm32h7/app-h743.toml index 979442e22..8f80bb963 100644 --- a/test/tests-stm32h7/app-h743.toml +++ b/test/tests-stm32h7/app-h743.toml @@ -56,6 +56,7 @@ max-sizes = {flash = 32768, ram = 32768 } stacksize = 2048 start = true task-slots = ["suite", "runner"] +notifications = ["timer"] [tasks.idle] name = "task-idle" diff --git a/test/tests-stm32h7/app-h753.toml b/test/tests-stm32h7/app-h753.toml index 1e6527635..30348ab58 100644 --- a/test/tests-stm32h7/app-h753.toml +++ b/test/tests-stm32h7/app-h753.toml @@ -56,6 +56,7 @@ max-sizes = {flash = 32768, ram = 32768 } stacksize = 2048 start = true task-slots = ["suite", "runner"] +notifications = ["timer"] [tasks.idle] name = "task-idle"