GCC Code Coverage Report


Directory: ./
File: WasmSequencer.hpp
Date: 2026-09-23 22:13:25
Exec Total Coverage
Lines: 3 7 42.9%
Functions: 3 7 42.9%
Branches: 0 0 -%

Line Branch Exec Source
1 // ======================================================================
2 // \title WasmSequencer.hpp
3 // \author tumbar
4 // \brief hpp file for WasmSequencer component implementation class
5 // ======================================================================
6
7 #ifndef Svc_WasmSequencer_HPP
8 #define Svc_WasmSequencer_HPP
9
10 #include "Fw/Cmd/CmdResponseEnumAc.hpp"
11 #include "Fw/DataStructures/FifoQueue.hpp"
12 #include "Fw/Types/FileNameString.hpp"
13 #include "Fw/Types/MemAllocator.hpp"
14 #include "Fw/Types/Serializable.hpp"
15 #include "Fw/Types/StringBase.hpp"
16 #include "Fw/Types/SuccessEnumAc.hpp"
17 #include "Svc/Seq/SeqArgsSerializableAc.hpp"
18 #include "Svc/WasmSequencer/WasmSequencerComponentAc.hpp"
19 #include "Svc/WasmSequencer/WasmSequencer_HostFunctionEnumAc.hpp"
20 #include "Svc/WasmSequencer/WasmSequencer_ModuleIdxAliasAc.hpp"
21 #include "Svc/WasmSequencer/WasmSequencer_RequestContextSerializableAc.hpp"
22 #include "Svc/WasmSequencer/WasmSequencer_TrapReasonEnumAc.hpp"
23 #include "Svc/WasmSequencer/spacewasm_include/spacewasm.h"
24 #include "Utils/Types/CircularBuffer.hpp"
25 #include "config/FwChanIdTypeAliasAc.h"
26 #include "config/FwPrmIdTypeAliasAc.h"
27 #include "config/FwSizeTypeAliasAc.h"
28 #include "config/WasmSequencerConfig.hpp"
29
30 namespace Svc {
31
32 class WasmSequencer final : public WasmSequencerComponentBase {
33 friend class WasmSequencerTester;
34
35 public:
36 // ----------------------------------------------------------------------
37 // Component construction and destruction
38 // ----------------------------------------------------------------------
39
40 //! Construct WasmSequencer object
41 WasmSequencer(const char* const compName //!< The component name
42 );
43
44 //! Destroy WasmSequencer object
45 ✗ ~WasmSequencer() = default;
46
47 //! WasmSequencer owns a raw spacewasm_t* handle and a slot in the
48 //! process-wide global-allocator registry; copying would double-free both.
49 WasmSequencer(const WasmSequencer&) = delete;
50 WasmSequencer& operator=(const WasmSequencer&) = delete;
51
52 //! Configuration to select what happens when a serialIn fills
53 enum class SerialInQueueFullBehavior {
54 DROP_NEWEST, //!< Drop the latest message if it cannot fit in the remaining queue space
55 DROP_OLDEST, //!< Oldest message[s] will be de-queued and dropped to make space for the new message. Keep
56 //!< dropping messages until enough space is made
57 ASSERT, //!< Trigger an assertion if the queue fills and cannot process another message
58 };
59
60 //! SpaceWasm has a hard-coded memory alignment requirement
61 constexpr static FwSizeType SPACEWASM_MEMORY_ALIGNMENT = 8;
62
63 //! Heap pages must be able to hold IR pages (512 bytes) minimum
64 //! type IrWord = U16
65 //! type IrPage = [256] IrWord => sizeof(IrPage) == 512
66 constexpr static FwSizeType SPACEWASM_IR_PAGE_SIZE = 512;
67 static_assert(Svc::WasmSequencerConfig::SPACEWASM_PAGE_SIZE >= SPACEWASM_IR_PAGE_SIZE,
68 "SpaceWasm does not support dynamic memory pages smaller than a single IR page (512 bytes)");
69
70 //! Per-port serialIn queue configuration.
71 struct SerialInQueueConfig {
72 //! Queue size in bytes. A port left at size 0 gets no queue (all inbound frames on that index are dropped).
73 FwSizeType size = 0;
74 //! Overflow policy applied when a new frame does not fit.
75 SerialInQueueFullBehavior fullBehavior = SerialInQueueFullBehavior::DROP_NEWEST;
76 };
77
78 //! Memory resource configuration for WasmSequencer.
79 //! See the [sizing guide](docs/sdd.md#sizing-guide) for how to configure this.
80 struct Config {
81 //! Number of `WASM_SEQ_SPACEWASM_PAGE_SIZE` pages to allocate
82 //! for the backing heap memory pool.
83 //! This is used for store the loaded Wasm modules and their IR (executable code)
84 //! but NOT for the guest memory (linear memory).
85 FwSizeType heapPages = 8;
86
87 //! Guest linear memory pool shared across all loaded modules
88 //! Note that a `.wasm` module will specify its linear memory size up-front in multiples of page-sizes
89 //! By default Wasm pages are 64k. if custom-page-sizes is enabled, page sizes are 1 byte.
90 FwSizeType guestMemorySize = 8192;
91
92 //! Wasm operand stack. The operand stack holds function parameters, locals and temporary operands.
93 //! When Wasm code calls another function, its frame will be pushed to the stack.
94 //!
95 //! This size is in units of 32-bit words.
96 //! The Wasm stack will be allocated from the heap memory pool
97 FwSizeType stackSize = 1024;
98
99 //! Allocates an empty list of pointers into the heap (i.e. sizeof(void*) * maxCodePages capacity).
100 //! A fixed capacity for holding decoded Wasm executable instructions in units of _Code Pages_.
101 //! Each page is 512 bytes (256 16-bit words) where each word holds a single resolved instruction (intermediate
102 //! representation - IR).
103 //!
104 //! This should be sized large enough to hold all the code pages you will need.
105 //! Note that this does not allocate the code pages themselves, it just incurs a `maxCodePages * sizeof(void*)`
106 //! allocates to the heap. From there, each code page (512 bytes) will be lazily allocated to the heap as needed
107 //! by .wasm modules.
108 //!
109 //! The larger this number is the higher overhead needed in the Wasm heap.
110 FwSizeType maxCodePages = 256;
111
112 //! Maximum number of Wasm modules that may be loaded into the sequencer's store.
113 U8 maxGuestModules = 8;
114
115 //! Size (in bytes) of the serialOut buffer used to copy a `serial_send` payload out of guest memory
116 //! before invoking the connected serialOut port. A value of 0 leaves serialOut unconfigured (disabled
117 //! serial_send).
118 FwSizeType serialOutMax = 0;
119
120 //! Per-port serialIn queue sizing and overflow policy. Default-construct the Config then populate
121 //! per port index, e.g.
122 //! `Config cfg; cfg.serialIn[0] = {256, SerialInQueueFullBehavior::DROP_OLDEST};`
123 //! A port left at size 0 gets no queue (all inbound frames on that index are dropped).
124 SerialInQueueConfig serialIn[NUM_SERIALIN_INPUT_PORTS];
125 };
126
127 //! [REQUIRED] Configure and allocate the dynamic backing pools for heap memory, guest memory, Wasm stack,
128 //! serialIn queues, and the serialOut buffer.
129 void configure(const Config& cfg, Fw::MemAllocator& mallocator);
130
131 //! Tear down the allocations made by `configure()`
132 void deinit() override;
133
134 private:
135 // ----------------------------------------------------------------------
136 // Handler implementations for typed input ports
137 // ----------------------------------------------------------------------
138
139 //! Handler implementation for checkTimers
140 //!
141 //! Port to periodically drive sleep-wake and host-function-timeout checks
142 void checkTimers_handler(FwIndexType portNum, //!< The port number
143 U32 context //!< The call order
144 ) override;
145
146 //! Handler implementation for cmdResponseIn
147 //!
148 //! Command response input
149 void cmdResponseIn_handler(FwIndexType portNum, //!< The port number
150 FwOpcodeType opCode, //!< Command Op Code
151 U32 cmdSeq, //!< Command Sequence
152 const Fw::CmdResponse& response //!< The command response argument
153 ) override;
154
155 //! Handler implementation for seqCancelIn
156 //!
157 //! port for requesting to cancel the currently running sequence
158 void seqCancelIn_handler(FwIndexType portNum //!< The port number
159 ) override;
160
161 //! Handler implementation for seqRunIn
162 //!
163 //! port for requests to run sequences
164 void seqRunIn_handler(FwIndexType portNum, //!< The port number
165 const Fw::StringBase& filename, //!< The sequence file
166 const Svc::SeqArgs& args //!< Sequence arguments
167 ) override;
168
169 //! Handler implementation for writeTelemetry
170 //!
171 //! Port to periodically write telemetry channels (optional)
172 void writeTelemetry_handler(FwIndexType portNum, //!< The port number
173 U32 context //!< The call order
174 ) override;
175
176 private:
177 // ----------------------------------------------------------------------
178 // Handler implementations for serial input ports
179 // ----------------------------------------------------------------------
180
181 //! Handler implementation for serialIn
182 //!
183 //! Port for receiving serial messages from other components.
184 //! All port indices will be placed into their own internal binary queue to be
185 //! handled by the serial_recv host function.
186 void serialIn_handler(FwIndexType portNum, //!< The port number
187 Fw::LinearBufferBase& buffer //!< The serialization buffer
188 ) override;
189
190 private:
191 // ----------------------------------------------------------------------
192 // Handler implementations for commands
193 // ----------------------------------------------------------------------
194
195 //! Handler implementation for command RUN
196 //!
197 //! Run a Wasm module main function on it's own in the interpreter
198 //! This command first resets the store (discarding any modules previously staged
199 //! with LOAD), then is short-hand for:
200 //!
201 //! ```sh
202 //! CANCEL # doesn't actually cancel a sequence, just resets the store
203 //! LOAD [fileName] ""
204 //! INVOKE "" [block] [seqArgs]
205 //! ```
206 //!
207 //! If $block == Svc.BlockState.BLOCK this command will wait for completion.
208 void RUN_cmdHandler(
209 FwOpcodeType opCode, //!< The opcode
210 U32 cmdSeq, //!< The command sequence number
211 const Fw::CmdStringArg& fileName, //!< The name of the sequence file
212 const Svc::BlockState& block, //!< Block until sequence has finished running
213 const Svc::SeqArgs& seqArgs //!< Optional arguments to execute the sequence with
214 //!< Depending on the sequence being loaded these arguments may differ
215 ) override;
216
217 //! Handler implementation for command LOAD
218 //!
219 //! Loads and validates a WebAssembly module into the store under the given name.
220 //! Naming the module lets its exports be referenced by other modules and lets
221 //! INVOKE, GLOBAL_GET and GLOBAL_SET address it. Use an empty name for a single,
222 //! standalone module. The name must not conflict with a previously loaded module.
223 void LOAD_cmdHandler(FwOpcodeType opCode, //!< The opcode
224 U32 cmdSeq, //!< The command sequence number
225 const Fw::CmdStringArg& fileName, //!< The name of the sequence file
226 const Fw::CmdStringArg& name //!< WebAssembly module name (empty for a single unnamed module)
227 ) override;
228
229 //! Handler implementation for command INVOKE
230 //!
231 //! Invoke a main function from a loaded module
232 void INVOKE_cmdHandler(FwOpcodeType opCode, //!< The opcode
233 U32 cmdSeq, //!< The command sequence number
234 const Fw::CmdStringArg& module, //!< Name of the module to invoke a function from
235 const Svc::BlockState& block, //!< Block until sequence has finished running
236 const Svc::SeqArgs& seqArgs //!< Arguments to invoke the sequence entrypoint with
237 ) override;
238
239 //! Handler implementation for command WAIT
240 //!
241 //! Wait for the interpreter to finish and return it's result as a CmdResponse
242 void WAIT_cmdHandler(FwOpcodeType opCode, //!< The opcode
243 U32 cmdSeq //!< The command sequence number
244 ) override;
245
246 //! Handler implementation for command CANCEL
247 //!
248 //! Cancels a running or validated sequence. After running CANCEL, the sequencer should return to IDLE
249 //! This completely clears the store.
250 void CANCEL_cmdHandler(FwOpcodeType opCode, //!< The opcode
251 U32 cmdSeq //!< The command sequence number
252 ) override;
253
254 //! Handler implementation for command PAUSE
255 //!
256 //! Pauses the execution of the sequencer, just before it is about to start spinning.
257 //! This simply pends a pause flag that will be taken before the sequence engine starts
258 //! up again.
259 //!
260 //! This command completes immediately
261 void PAUSE_cmdHandler(FwOpcodeType opCode, //!< The opcode
262 U32 cmdSeq //!< The command sequence number
263 ) override;
264
265 //! Handler implementation for command CONTINUE
266 //!
267 //! Resume the sequence from a paused state
268 void CONTINUE_cmdHandler(FwOpcodeType opCode, //!< The opcode
269 U32 cmdSeq //!< The command sequence number
270 ) override;
271
272 //! Handler implementation for command GLOBAL_SET_I32
273 //!
274 //! Set a global variable to a given i32 value.
275 //! Command fails if the module is not found, global is not exported, mutable, or of i32 type
276 void GLOBAL_SET_I32_cmdHandler(FwOpcodeType opCode, //!< The opcode
277 U32 cmdSeq, //!< The command sequence number
278 const Fw::CmdStringArg& moduleName, //!< Name of the module to set global for
279 const Fw::CmdStringArg& name, //!< Name of the global
280 I32 value //!< Value to set global to
281 ) override;
282
283 //! Handler implementation for command GLOBAL_SET_I64
284 //!
285 //! Set a global variable to a given i64 value.
286 //! Command fails if the module is not found, global is not exported, mutable, or of i64 type
287 void GLOBAL_SET_I64_cmdHandler(FwOpcodeType opCode, //!< The opcode
288 U32 cmdSeq, //!< The command sequence number
289 const Fw::CmdStringArg& moduleName, //!< Name of the module to set global for
290 const Fw::CmdStringArg& name, //!< Name of the global
291 I64 value //!< Value to set global to
292 ) override;
293
294 //! Handler implementation for command GLOBAL_SET_F32
295 //!
296 //! Set a global variable to a given f32 value.
297 //! Command fails if the module is not found, global is not exported, mutable, or of f32 type
298 void GLOBAL_SET_F32_cmdHandler(FwOpcodeType opCode, //!< The opcode
299 U32 cmdSeq, //!< The command sequence number
300 const Fw::CmdStringArg& moduleName, //!< Name of the module to set global for
301 const Fw::CmdStringArg& name, //!< Name of the global
302 F32 value //!< Value to set global to
303 ) override;
304
305 //! Handler implementation for command GLOBAL_SET_F64
306 //!
307 //! Set a global variable to a given f64 value.
308 //! Command fails if the module is not found, global is not exported, mutable, or of f64 type
309 void GLOBAL_SET_F64_cmdHandler(FwOpcodeType opCode, //!< The opcode
310 U32 cmdSeq, //!< The command sequence number
311 const Fw::CmdStringArg& moduleName, //!< Name of the module to set global for
312 const Fw::CmdStringArg& name, //!< Name of the global
313 F64 value //!< Value to set global to
314 ) override;
315
316 //! Handler implementation for command GLOBAL_GET
317 //!
318 //! Get the current value of a global variable and emit an event
319 //! Command fails if the module is not found or the global is not exported
320 void GLOBAL_GET_cmdHandler(FwOpcodeType opCode, //!< The opcode
321 U32 cmdSeq, //!< The command sequence number
322 const Fw::CmdStringArg& moduleName, //!< Name of the module to get global for
323 const Fw::CmdStringArg& name //!< Name of the global
324 ) override;
325
326 private:
327 // ----------------------------------------------------------------------
328 // Implementations for internal state machine actions
329 // ----------------------------------------------------------------------
330
331 //! Implementation for action processInvoke of state machine Svc_WasmSequencer_ControllerStateMachine
332 //!
333 //! Action to save the invoke arguments and emit an 'invoked' signal
334 void Svc_WasmSequencer_ControllerStateMachine_action_processInvoke(
335 SmId smId, //!< The state machine id
336 Svc_WasmSequencer_ControllerStateMachine::Signal signal, //!< The signal
337 const Svc::WasmSequencer_InvokeRequest& value //!< The value
338 ) override;
339
340 //! Implementation for action setCancelRequested of state machine Svc_WasmSequencer_ControllerStateMachine
341 //!
342 //! Latch a cancel that arrives while a sequence is loading/resolving
343 void Svc_WasmSequencer_ControllerStateMachine_action_setCancelRequested(
344 SmId smId, //!< The state machine id
345 Svc_WasmSequencer_ControllerStateMachine::Signal signal //!< The signal
346 ) override;
347
348 //! Implementation for action clearCancelRequested of state machine Svc_WasmSequencer_ControllerStateMachine
349 //!
350 //! Acknowledge/clear any pending cancel
351 void Svc_WasmSequencer_ControllerStateMachine_action_clearCancelRequested(
352 SmId smId, //!< The state machine id
353 Svc_WasmSequencer_ControllerStateMachine::Signal signal //!< The signal
354 ) override;
355
356 //! Implementation for action cancelPendingRequest of state machine Svc_WasmSequencer_ControllerStateMachine
357 //!
358 //! Abort a load/invoke that was cancelled before the engine ran
359 void Svc_WasmSequencer_ControllerStateMachine_action_cancelPendingRequest(
360 SmId smId, //!< The state machine id
361 Svc_WasmSequencer_ControllerStateMachine::Signal signal, //!< The signal
362 const Svc::WasmSequencer_RequestContext& value //!< The value
363 ) override;
364
365 //! Implementation for action respond_noblock_OK of state machine Svc_WasmSequencer_ControllerStateMachine
366 //!
367 //! Responds to $block == NO_BLOCK requests with OK
368 void Svc_WasmSequencer_ControllerStateMachine_action_respond_noblock_OK(
369 SmId smId, //!< The state machine id
370 Svc_WasmSequencer_ControllerStateMachine::Signal signal, //!< The signal
371 const Svc::WasmSequencer_RequestContext& value //!< The value
372 ) override;
373
374 //! Implementation for action respond_ERROR of state machine Svc_WasmSequencer_ControllerStateMachine
375 //!
376 //! Responds to request with EXECUTION_ERROR
377 void Svc_WasmSequencer_ControllerStateMachine_action_respond_ERROR(
378 SmId smId, //!< The state machine id
379 Svc_WasmSequencer_ControllerStateMachine::Signal signal, //!< The signal
380 const Svc::WasmSequencer_RequestContext& value //!< The value
381 ) override;
382
383 //! Implementation for action incrementSequenceFailure of state machine Svc_WasmSequencer_ControllerStateMachine
384 //!
385 //! Increment the SequencesFailed telemetry counter
386 void Svc_WasmSequencer_ControllerStateMachine_action_incrementSequenceFailure(
387 SmId smId, //!< The state machine id
388 Svc_WasmSequencer_ControllerStateMachine::Signal signal //!< The signal
389 ) override;
390
391 //! Implementation for action respondInvoke_BUSY of state machine Svc_WasmSequencer_ControllerStateMachine
392 //!
393 //! Responds to request with BUSY
394 //! Emit an event to say why we are rejecting this request in the current state
395 void Svc_WasmSequencer_ControllerStateMachine_action_respondInvoke_BUSY(
396 SmId smId, //!< The state machine id
397 Svc_WasmSequencer_ControllerStateMachine::Signal signal, //!< The signal
398 const Svc::WasmSequencer_InvokeRequest& value //!< The value
399 ) override;
400
401 //! Implementation for action respondInvoke_ERROR of state machine Svc_WasmSequencer_ControllerStateMachine
402 //!
403 //! Responds to request with EXECUTION_ERROR
404 //! Emit an event to say why we are rejecting this request in the current state
405 void Svc_WasmSequencer_ControllerStateMachine_action_respondInvoke_ERROR(
406 SmId smId, //!< The state machine id
407 Svc_WasmSequencer_ControllerStateMachine::Signal signal, //!< The signal
408 const Svc::WasmSequencer_InvokeRequest& value //!< The value
409 ) override;
410
411 //! Implementation for action respondLoad_BUSY of state machine Svc_WasmSequencer_ControllerStateMachine
412 //!
413 //! Responds to request with BUSY
414 //! Emit an event to say why we are rejecting this request in the current state
415 void Svc_WasmSequencer_ControllerStateMachine_action_respondLoad_BUSY(
416 SmId smId, //!< The state machine id
417 Svc_WasmSequencer_ControllerStateMachine::Signal signal, //!< The signal
418 const Svc::WasmSequencer_LoadRequest& value //!< The value
419 ) override;
420
421 //! Implementation for action respond_block_OK of state machine Svc_WasmSequencer_ControllerStateMachine
422 //!
423 //! Responds to $block == BLOCK requests with OK
424 //! Responds to any pending WAIT requests with OK
425 void Svc_WasmSequencer_ControllerStateMachine_action_respond_block_OK(
426 SmId smId, //!< The state machine id
427 Svc_WasmSequencer_ControllerStateMachine::Signal signal, //!< The signal
428 const Svc::WasmSequencer_RequestContext& value //!< The value
429 ) override;
430
431 //! Implementation for action respond_block_ERROR of state machine Svc_WasmSequencer_ControllerStateMachine
432 //!
433 //! Responds to $block == BLOCK requests with ERROR.
434 //! Responds to any pending WAIT requests with ERROR
435 void Svc_WasmSequencer_ControllerStateMachine_action_respond_block_ERROR(
436 SmId smId, //!< The state machine id
437 Svc_WasmSequencer_ControllerStateMachine::Signal signal, //!< The signal
438 const Svc::WasmSequencer_RequestContext& value //!< The value
439 ) override;
440
441 //! Implementation for action load of state machine Svc_WasmSequencer_ControllerStateMachine
442 //!
443 //! Load a module into the store.
444 //! Emits `loadSucceded` or `loadFailed` depending on result
445 void Svc_WasmSequencer_ControllerStateMachine_action_load(
446 SmId smId, //!< The state machine id
447 Svc_WasmSequencer_ControllerStateMachine::Signal signal, //!< The signal
448 const Svc::WasmSequencer_LoadRequest& value //!< The value
449 ) override;
450
451 //! Implementation for action invokeStart of state machine Svc_WasmSequencer_ControllerStateMachine
452 //!
453 //! Invoke the start function on a loaded module
454 void Svc_WasmSequencer_ControllerStateMachine_action_invokeStart(
455 SmId smId, //!< The state machine id
456 Svc_WasmSequencer_ControllerStateMachine::Signal signal, //!< The signal
457 const Svc::WasmSequencer_RequestContext& value //!< The value
458 ) override;
459
460 //! Implementation for action invokeMain of state machine Svc_WasmSequencer_ControllerStateMachine
461 //!
462 //! Invoke the main function for module in context
463 void Svc_WasmSequencer_ControllerStateMachine_action_invokeMain(
464 SmId smId, //!< The state machine id
465 Svc_WasmSequencer_ControllerStateMachine::Signal signal, //!< The signal
466 const Svc::WasmSequencer_RequestContext& value //!< The value
467 ) override;
468
469 //! Implementation for action reportModuleInvalidMain of state machine Svc_WasmSequencer_ControllerStateMachine
470 //!
471 //! Emit an event noting that a given module has no [valid] main function
472 void Svc_WasmSequencer_ControllerStateMachine_action_reportModuleInvalidMain(
473 SmId smId, //!< The state machine id
474 Svc_WasmSequencer_ControllerStateMachine::Signal signal, //!< The signal
475 const Svc::WasmSequencer_RequestContext& value //!< The value
476 ) override;
477
478 //! Implementation for action reportModuleMainInvokeFailed of state machine Svc_WasmSequencer_ControllerStateMachine
479 //!
480 //! Emit an event noting why the invocation of a module main failed
481 void Svc_WasmSequencer_ControllerStateMachine_action_reportModuleMainInvokeFailed(
482 SmId smId, //!< The state machine id
483 Svc_WasmSequencer_ControllerStateMachine::Signal signal, //!< The signal
484 const Svc::WasmSequencer_RequestContext& value //!< The value
485 ) override;
486
487 //! Implementation for action reportModuleStartInvokeFailed of state machine
488 //! Svc_WasmSequencer_ControllerStateMachine
489 //!
490 //! Emit an event noting why the invocation of a module start failed
491 void Svc_WasmSequencer_ControllerStateMachine_action_reportModuleStartInvokeFailed(
492 SmId smId, //!< The state machine id
493 Svc_WasmSequencer_ControllerStateMachine::Signal signal, //!< The signal
494 const Svc::WasmSequencer_RequestContext& value //!< The value
495 ) override;
496
497 //! Implementation for action reportModuleStarted of state machine Svc_WasmSequencer_ControllerStateMachine
498 //!
499 //! Reports that a module started running it's main function
500 void Svc_WasmSequencer_ControllerStateMachine_action_reportModuleStarted(
501 SmId smId, //!< The state machine id
502 Svc_WasmSequencer_ControllerStateMachine::Signal signal, //!< The signal
503 const Svc::WasmSequencer_RequestContext& value //!< The value
504 ) override;
505
506 //! Implementation for action reportModuleSucceeded of state machine Svc_WasmSequencer_ControllerStateMachine
507 //!
508 //! Emit an event noting a module succeeded during execution. Increment telemetry counters.
509 void Svc_WasmSequencer_ControllerStateMachine_action_reportModuleSucceeded(
510 SmId smId, //!< The state machine id
511 Svc_WasmSequencer_ControllerStateMachine::Signal signal, //!< The signal
512 const Svc::WasmSequencer_RequestContext& value //!< The value
513 ) override;
514
515 //! Implementation for action reportModuleStartFailed of state machine Svc_WasmSequencer_ControllerStateMachine
516 //!
517 //! Emit an event noting a module failed during execution of start. Increment telemetry counters.
518 void Svc_WasmSequencer_ControllerStateMachine_action_reportModuleStartFailed(
519 SmId smId, //!< The state machine id
520 Svc_WasmSequencer_ControllerStateMachine::Signal signal, //!< The signal
521 const Svc::WasmSequencer_RequestContext& value //!< The value
522 ) override;
523
524 //! Implementation for action reportModuleMainFailed of state machine Svc_WasmSequencer_ControllerStateMachine
525 //!
526 //! Emit an event noting a module failed during execution. Increment telemetry counters.
527 void Svc_WasmSequencer_ControllerStateMachine_action_reportModuleMainFailed(
528 SmId smId, //!< The state machine id
529 Svc_WasmSequencer_ControllerStateMachine::Signal signal, //!< The signal
530 const Svc::WasmSequencer_RequestContext& value //!< The value
531 ) override;
532
533 //! Implementation for action resetStore of state machine Svc_WasmSequencer_ControllerStateMachine
534 //!
535 //! Create a new store with N_MODULES (parameter) modules
536 void Svc_WasmSequencer_ControllerStateMachine_action_resetStore(
537 SmId smId, //!< The state machine id
538 Svc_WasmSequencer_ControllerStateMachine::Signal signal //!< The signal
539 ) override;
540
541 //! Implementation for action runEngine of state machine Svc_WasmSequencer_ControllerStateMachine
542 //!
543 //! Send a signal to the engine state machine to begin running
544 //! The engine will asynchronously reply with the `engineFinished` signal
545 void Svc_WasmSequencer_ControllerStateMachine_action_runEngine(
546 SmId smId, //!< The state machine id
547 Svc_WasmSequencer_ControllerStateMachine::Signal signal, //!< The signal
548 const Svc::WasmSequencer_RequestContext& value //!< The value
549 ) override;
550
551 //! Implementation for action cmdReplyOK of state machine Svc_WasmSequencer_InterpreterStateMachine
552 //!
553 //! Respond to a pending command with OK
554 void Svc_WasmSequencer_InterpreterStateMachine_action_cmdReplyOK(
555 SmId smId, //!< The state machine id
556 Svc_WasmSequencer_InterpreterStateMachine::Signal signal, //!< The signal
557 const Svc::WasmSequencer_CommandRequest& value //!< The value
558 ) override;
559
560 //! Implementation for action signalEntered of state machine Svc_WasmSequencer_InterpreterStateMachine
561 //!
562 //! generic signal raised
563 void Svc_WasmSequencer_InterpreterStateMachine_action_signalEntered(
564 SmId smId, //!< The state machine id
565 Svc_WasmSequencer_InterpreterStateMachine::Signal signal //!< The signal
566 ) override;
567
568 //! Implementation for action spin of state machine Svc_WasmSequencer_InterpreterStateMachine
569 //!
570 //! spins the interpreter loop, executing up to a bounded number of instructions
571 void Svc_WasmSequencer_InterpreterStateMachine_action_spin(
572 SmId smId, //!< The state machine id
573 Svc_WasmSequencer_InterpreterStateMachine::Signal signal //!< The signal
574 ) override;
575
576 //! Implementation for action reset of state machine Svc_WasmSequencer_InterpreterStateMachine
577 //!
578 //! resets the engine's state (clears operand stack, pc, fp, sp)
579 void Svc_WasmSequencer_InterpreterStateMachine_action_reset(
580 SmId smId, //!< The state machine id
581 Svc_WasmSequencer_InterpreterStateMachine::Signal signal //!< The signal
582 ) override;
583
584 //! Implementation for action clearExitStatus of state machine Svc_WasmSequencer_InterpreterStateMachine
585 void Svc_WasmSequencer_InterpreterStateMachine_action_clearExitStatus(
586 SmId smId, //!< The state machine id
587 Svc_WasmSequencer_InterpreterStateMachine::Signal signal //!< The signal
588 ) override;
589
590 //! Implementation for action setExitReason_INTERPRETER_FINISHED of state machine
591 //! Svc_WasmSequencer_InterpreterStateMachine
592 void Svc_WasmSequencer_InterpreterStateMachine_action_setExitReason_INTERPRETER_FINISHED(
593 SmId smId, //!< The state machine id
594 Svc_WasmSequencer_InterpreterStateMachine::Signal signal //!< The signal
595 ) override;
596
597 //! Implementation for action setExitReason_INTERPRETER_TRAP of state machine
598 //! Svc_WasmSequencer_InterpreterStateMachine
599 void Svc_WasmSequencer_InterpreterStateMachine_action_setExitReason_INTERPRETER_TRAP(
600 SmId smId, //!< The state machine id
601 Svc_WasmSequencer_InterpreterStateMachine::Signal signal //!< The signal
602 ) override;
603
604 //! Implementation for action setExitReason_REPLY_TIMEOUT of state machine Svc_WasmSequencer_InterpreterStateMachine
605 void Svc_WasmSequencer_InterpreterStateMachine_action_setExitReason_REPLY_TIMEOUT(
606 SmId smId, //!< The state machine id
607 Svc_WasmSequencer_InterpreterStateMachine::Signal signal //!< The signal
608 ) override;
609
610 //! Implementation for action setExitReason_HOST_FAILURE of state machine Svc_WasmSequencer_InterpreterStateMachine
611 void Svc_WasmSequencer_InterpreterStateMachine_action_setExitReason_HOST_FAILURE(
612 SmId smId, //!< The state machine id
613 Svc_WasmSequencer_InterpreterStateMachine::Signal signal //!< The signal
614 ) override;
615
616 //! Implementation for action setExitReason_TIMER_INCOMPARABLE of state machine
617 //! Svc_WasmSequencer_InterpreterStateMachine
618 void Svc_WasmSequencer_InterpreterStateMachine_action_setExitReason_TIMER_INCOMPARABLE(
619 SmId smId, //!< The state machine id
620 Svc_WasmSequencer_InterpreterStateMachine::Signal signal //!< The signal
621 ) override;
622
623 //! Implementation for action setExitReason_UNEXPECTED_REPLY of state machine
624 //! Svc_WasmSequencer_InterpreterStateMachine
625 void Svc_WasmSequencer_InterpreterStateMachine_action_setExitReason_UNEXPECTED_REPLY(
626 SmId smId, //!< The state machine id
627 Svc_WasmSequencer_InterpreterStateMachine::Signal signal //!< The signal
628 ) override;
629
630 //! Implementation for action setExitReason_CANCEL of state machine Svc_WasmSequencer_InterpreterStateMachine
631 void Svc_WasmSequencer_InterpreterStateMachine_action_setExitReason_CANCEL(
632 SmId smId, //!< The state machine id
633 Svc_WasmSequencer_InterpreterStateMachine::Signal signal //!< The signal
634 ) override;
635
636 //! Implementation for action setExitCode of state machine Svc_WasmSequencer_InterpreterStateMachine
637 void Svc_WasmSequencer_InterpreterStateMachine_action_setExitCode(
638 SmId smId, //!< The state machine id
639 Svc_WasmSequencer_InterpreterStateMachine::Signal signal, //!< The signal
640 I32 value //!< The value
641 ) override;
642
643 //! Implementation for action setTrapReason of state machine Svc_WasmSequencer_InterpreterStateMachine
644 void Svc_WasmSequencer_InterpreterStateMachine_action_setTrapReason(
645 SmId smId, //!< The state machine id
646 Svc_WasmSequencer_InterpreterStateMachine::Signal signal, //!< The signal
647 const Svc::WasmSequencer_TrapReason& value //!< The value
648 ) override;
649
650 //! Implementation for action setLastHostFunction of state machine Svc_WasmSequencer_InterpreterStateMachine
651 void Svc_WasmSequencer_InterpreterStateMachine_action_setLastHostFunction(
652 SmId smId, //!< The state machine id
653 Svc_WasmSequencer_InterpreterStateMachine::Signal signal //!< The signal
654 ) override;
655
656 //! Implementation for action finish of state machine Svc_WasmSequencer_InterpreterStateMachine
657 //!
658 //! Send a signal back to the controller state machine that we have finished executing
659 //! The response codes are stored in m_exit (reason, code, lastTrapReason)
660 void Svc_WasmSequencer_InterpreterStateMachine_action_finish(
661 SmId smId, //!< The state machine id
662 Svc_WasmSequencer_InterpreterStateMachine::Signal signal //!< The signal
663 ) override;
664
665 //! Implementation for action reportPaused of state machine Svc_WasmSequencer_InterpreterStateMachine
666 //!
667 //! reports that execution was paused at a breakpoint
668 void Svc_WasmSequencer_InterpreterStateMachine_action_reportPaused(
669 SmId smId, //!< The state machine id
670 Svc_WasmSequencer_InterpreterStateMachine::Signal signal //!< The signal
671 ) override;
672
673 //! Implementation for action clearPause of state machine Svc_WasmSequencer_InterpreterStateMachine
674 //!
675 //! sets the pause flag to false
676 void Svc_WasmSequencer_InterpreterStateMachine_action_clearPause(
677 SmId smId, //!< The state machine id
678 Svc_WasmSequencer_InterpreterStateMachine::Signal signal //!< The signal
679 ) override;
680
681 //! Implementation for action dispatchPendingHostFunction of state machine Svc_WasmSequencer_InterpreterStateMachine
682 //!
683 //! dispatch a host function port call
684 void Svc_WasmSequencer_InterpreterStateMachine_action_dispatchPendingHostFunction(
685 SmId smId, //!< The state machine id
686 Svc_WasmSequencer_InterpreterStateMachine::Signal signal //!< The signal
687 ) override;
688
689 //! Implementation for action clearPendingHostFunction of state machine Svc_WasmSequencer_InterpreterStateMachine
690 //!
691 //! clears the pending host function port call
692 void Svc_WasmSequencer_InterpreterStateMachine_action_clearPendingHostFunction(
693 SmId smId, //!< The state machine id
694 Svc_WasmSequencer_InterpreterStateMachine::Signal signal //!< The signal
695 ) override;
696
697 //! Implementation for action setContext of state machine Svc_WasmSequencer_InterpreterStateMachine
698 //!
699 //! Set the current executing context
700 void Svc_WasmSequencer_InterpreterStateMachine_action_setContext(
701 SmId smId, //!< The state machine id
702 Svc_WasmSequencer_InterpreterStateMachine::Signal signal, //!< The signal
703 const Svc::WasmSequencer_RequestContext& value //!< The value
704 ) override;
705
706 //! Implementation for action clearContext of state machine Svc_WasmSequencer_InterpreterStateMachine
707 //!
708 //! Clear the current executing context
709 void Svc_WasmSequencer_InterpreterStateMachine_action_clearContext(
710 SmId smId, //!< The state machine id
711 Svc_WasmSequencer_InterpreterStateMachine::Signal signal //!< The signal
712 ) override;
713
714 //! Implementation for action resume of state machine Svc_WasmSequencer_InterpreterStateMachine
715 //!
716 //! spacewasm_engine_resume
717 void Svc_WasmSequencer_InterpreterStateMachine_action_resume(
718 SmId smId, //!< The state machine id
719 Svc_WasmSequencer_InterpreterStateMachine::Signal signal //!< The signal
720 ) override;
721
722 //! Implementation for action resumeI32 of state machine Svc_WasmSequencer_InterpreterStateMachine
723 //!
724 //! spacewasm_engine_resume_some(I32(value))
725 void Svc_WasmSequencer_InterpreterStateMachine_action_resumeI32(
726 SmId smId, //!< The state machine id
727 Svc_WasmSequencer_InterpreterStateMachine::Signal signal, //!< The signal
728 I32 value //!< The value
729 ) override;
730
731 //! Implementation for action checkSleepTimers of state machine Svc_WasmSequencer_InterpreterStateMachine
732 //!
733 //! A periodic check on the pending timer to see if we can wake up
734 void Svc_WasmSequencer_InterpreterStateMachine_action_checkSleepTimers(
735 SmId smId, //!< The state machine id
736 Svc_WasmSequencer_InterpreterStateMachine::Signal signal //!< The signal
737 ) override;
738
739 //! Implementation for action checkTimeout of state machine Svc_WasmSequencer_InterpreterStateMachine
740 //!
741 //! A periodic check on any host function to guard against timeouts
742 void Svc_WasmSequencer_InterpreterStateMachine_action_checkTimeout(
743 SmId smId, //!< The state machine id
744 Svc_WasmSequencer_InterpreterStateMachine::Signal signal //!< The signal
745 ) override;
746
747 //! Implementation for action dequeueSerialAndResume of state machine Svc_WasmSequencer_InterpreterStateMachine
748 //!
749 //! Dequeue a serial message into the host guest memory and resume the interpreter
750 void Svc_WasmSequencer_InterpreterStateMachine_action_dequeueSerialAndResume(
751 SmId smId, //!< The state machine id
752 Svc_WasmSequencer_InterpreterStateMachine::Signal signal, //!< The signal
753 const FwIndexType& value //!< The value
754 ) override;
755
756 private:
757 // ----------------------------------------------------------------------
758 // Implementations for internal state machine guards
759 // ----------------------------------------------------------------------
760
761 //! Implementation for guard cancelRequested of state machine Svc_WasmSequencer_ControllerStateMachine
762 //!
763 //! True if a cancel was latched since the controller last came to rest.
764 bool Svc_WasmSequencer_ControllerStateMachine_guard_cancelRequested(
765 SmId smId, //!< The state machine id
766 Svc_WasmSequencer_ControllerStateMachine::Signal signal //!< The signal
767 ) const override;
768
769 //! Implementation for guard moduleHasStart of state machine Svc_WasmSequencer_ControllerStateMachine
770 //!
771 //! return true if this module has a start function
772 bool Svc_WasmSequencer_ControllerStateMachine_guard_moduleHasStart(
773 SmId smId, //!< The state machine id
774 Svc_WasmSequencer_ControllerStateMachine::Signal signal, //!< The signal
775 const Svc::WasmSequencer_RequestContext& value //!< The value
776 ) const override;
777
778 //! Implementation for guard moduleHasValidMain of state machine Svc_WasmSequencer_ControllerStateMachine
779 //!
780 //! return true if this module has a valid main function ([] -> i32)
781 bool Svc_WasmSequencer_ControllerStateMachine_guard_moduleHasValidMain(
782 SmId smId, //!< The state machine id
783 Svc_WasmSequencer_ControllerStateMachine::Signal signal, //!< The signal
784 const Svc::WasmSequencer_RequestContext& value //!< The value
785 ) const override;
786
787 //! Implementation for guard invokeSucceeded of state machine Svc_WasmSequencer_ControllerStateMachine
788 //!
789 //! return true if invokeStatus == SPACEWASM_OK. This flag is set as a result of invokeStart/invokeMain
790 bool Svc_WasmSequencer_ControllerStateMachine_guard_invokeSucceeded(
791 SmId smId, //!< The state machine id
792 Svc_WasmSequencer_ControllerStateMachine::Signal signal, //!< The signal
793 const Svc::WasmSequencer_RequestContext& value //!< The value
794 ) const override;
795
796 //! Implementation for guard interpreterSucceeded of state machine Svc_WasmSequencer_ControllerStateMachine
797 //!
798 //! Check if the last engine execution finished executing successfully
799 bool Svc_WasmSequencer_ControllerStateMachine_guard_interpreterSucceeded(
800 SmId smId, //!< The state machine id
801 Svc_WasmSequencer_ControllerStateMachine::Signal signal //!< The signal
802 ) const override;
803
804 //! Implementation for guard pendingPause of state machine Svc_WasmSequencer_InterpreterStateMachine
805 //!
806 //! return true if execution should pause before spinning the interpreter again
807 bool Svc_WasmSequencer_InterpreterStateMachine_guard_pendingPause(
808 SmId smId, //!< The state machine id
809 Svc_WasmSequencer_InterpreterStateMachine::Signal signal //!< The signal
810 ) const override;
811
812 //! Implementation for guard pendingHostFunction of state machine Svc_WasmSequencer_InterpreterStateMachine
813 //!
814 //! a host function is waiting to be processed
815 bool Svc_WasmSequencer_InterpreterStateMachine_guard_pendingHostFunction(
816 SmId smId, //!< The state machine id
817 Svc_WasmSequencer_InterpreterStateMachine::Signal signal //!< The signal
818 ) const override;
819
820 //! Implementation for guard pendingHostFunctionIsSleep of state machine Svc_WasmSequencer_InterpreterStateMachine
821 //!
822 //! the pending host function is a sleep (therefore we need to check the sleep timers)
823 bool Svc_WasmSequencer_InterpreterStateMachine_guard_pendingHostFunctionIsSleep(
824 SmId smId, //!< The state machine id
825 Svc_WasmSequencer_InterpreterStateMachine::Signal signal //!< The signal
826 ) const override;
827
828 //! Implementation for guard blockingSerialIn of state machine Svc_WasmSequencer_InterpreterStateMachine
829 //!
830 //! Check if we are currently blocking on a serial_recv() for a given serial port index
831 bool Svc_WasmSequencer_InterpreterStateMachine_guard_blockingSerialIn(
832 SmId smId, //!< The state machine id
833 Svc_WasmSequencer_InterpreterStateMachine::Signal signal, //!< The signal
834 const FwIndexType& value //!< The value
835 ) const override;
836
837 //! Implementation for guard dequeueSucceeded of state machine Svc_WasmSequencer_InterpreterStateMachine
838 //!
839 //! Return true `dequeueSerialAndResume` processed a message successfully
840 bool Svc_WasmSequencer_InterpreterStateMachine_guard_dequeueSucceeded(
841 SmId smId, //!< The state machine id
842 Svc_WasmSequencer_InterpreterStateMachine::Signal signal //!< The signal
843 ) const override;
844
845 private:
846 /// The global allocator callbacks
847 U8* globalAlloc(U32 size, U32 align);
848 void globalDealloc(const U8* ptr);
849
850 /// C-callback trampolines for the spacewasm global-allocator registry
851 static U8* globalAllocCallback(void* userdata, size_t size, size_t align);
852 static void globalDeallocCallback(void* userdata, U8* ptr, size_t size, size_t align);
853
854 /// The Wasm guest allocator callbacks for this component
855 U8* guestAlloc(FwSizeType size, U32 align);
856 U8* guestRealloc(U8* ptr, FwSizeType oldSize, FwSizeType newSize, U32 align);
857 void guestDealloc(const U8* ptr, FwSizeType size);
858
859 // Guest allocator callbacks passed to C API
860 static U8* guestAllocCallback(void* userdata, size_t size, size_t align);
861 static U8* guestReallocCallback(void* userdata, U8* ptr, size_t old_size, size_t new_size, size_t align);
862 static void guestDeallocCallback(void* userdata, U8* ptr, size_t size, size_t align);
863
864 //! Create a fresh interpreter store with the given module capacity,
865 //! destroying any existing store first.
866 void createStore();
867
868 //! Destroy the current interpreter store, if any, releasing its memory.
869 void destroyStore();
870
871 //! Take control of the spacewasm global allocator on this WasmSequence
872 void takeAllocatorLock();
873
874 //! Release control of the spacewasm global allocator on this WasmSequence
875 void releaseAllocatorLock();
876
877 //! Map a spacewasm_trap_t onto the TrapReason event enum.
878 static Svc::WasmSequencer_TrapReason::T mapTrapReason(spacewasm_trap_t trap);
879
880 //! Record the SeqName telemetry for a load. Uses moduleName when non-empty;
881 //! otherwise derives it from the file's basename with any ".wasm" suffix
882 //! stripped (an empty-name RUN / LOAD).
883 void setSequenceName(const Fw::StringBase& filePath, const Fw::StringBase& moduleName);
884
885 //! Return a pointer to the basename of `path` (the segment after the last '/')
886 //! and write its length to `outLen`. `len` is the length of `path`. Pure string
887 //! manipulation, no filesystem access.
888 static const char* pathBaseName(const char* path, FwSizeType len, FwSizeType& outLen);
889
890 //! True if `path` contains a ".." path-traversal component (a segment, delimited
891 //! by '/', that is exactly ".."). Used to keep a ground-supplied sequence file
892 //! name from escaping the configured SEQ_BASE_DIR.
893 static bool pathHasParentTraversal(const Fw::StringBase& path);
894
895 //! Resolve a sequence `fileName` against the SEQ_BASE_DIR parameter, writing the
896 //! result to `filePath`. On failure (a ".." component that would escape the base
897 //! dir, or a joined path that overflows the buffer) it logs the specific event
898 //! and returns false; the caller is responsible for failing the load.
899 bool resolveSequencePath(const Fw::StringBase& fileName, Fw::String& filePath);
900
901 //! Read `len` bytes of guest linear memory at `addr` into `dst` (via
902 //! spacewasm_mem_read on the pending host function's caller).
903 Fw::Success readGuestMemory(WasmSequencer_HostFunction::T kind, U32 addr, U8* dst, FwSizeType len);
904
905 //! Write `len` bytes from `src` into guest linear memory at `addr` (via
906 //! spacewasm_mem_write)
907 Fw::Success writeGuestMemory(WasmSequencer_HostFunction::T kind, U32 addr, const U8* src, FwSizeType len);
908
909 Fw::MemAllocator* m_allocator = nullptr;
910
911 //! Memory-resource configuration captured by configure()
912 Config m_config;
913
914 //! Page pool backing the process-wide spacewasm global page allocator for this instance.
915 //! Each page is `Svc::WasmSequencerConfig::SPACEWASM_PAGE_SIZE` with m_config.heapPages pages.
916 //! Stores dynamic memory allocated to hold each loaded module in the store (and the store itself).
917 U8** m_heapPages;
918
919 //! Number of currently used
920 FwSizeType m_heapPagesUsed;
921
922 //! A deallocation has poisoned the heap allocator
923 //! No more allocations can happen until every page is dropped.
924 //! SpaceWasm will drop everything in one shot so this simply helps us guard this invariant with an assertion
925 bool m_heapPoisoned;
926
927 //! Pool backing the per-load guest linear-memory allocator; a simple
928 //! bump allocator. `memory.grow` is enabled, but a bump allocator can only
929 //! service growth at the tail of the pool; see `guestRealloc`.
930 U8* m_guestPool;
931
932 //! Current bump offset into `m_guestPool`.
933 FwSizeType m_guestPoolOffset;
934
935 //! Opaque handle to the spacewasm engine, or null (before the store is initialized).
936 spacewasm_t* m_wasm;
937
938 //! Opaque handle to the spacewasm guest memory allocator, or null (before store/allocator is initialized)
939 spacewasm_allocator_t* m_guest_allocator;
940
941 //! Pending command waiting for a response
942 struct WaitingCmd {
943 FwOpcodeType opCode;
944 U32 cmdSeq;
945
946 8 WaitingCmd() : opCode(0), cmdSeq(0) {}
947 ✗ WaitingCmd(FwOpcodeType opCode_, U32 cmdSeq_) : opCode(opCode_), cmdSeq(cmdSeq_) {}
948 };
949
950 //! WAIT commands waiting for sequence completion
951 Fw::FifoQueue<WaitingCmd, WasmSequencerConfig::MAX_CONCURRENT_WAIT_COMMANDS> m_waiting;
952
953 //! Currently stored sequence arguments
954 Svc::SeqArgs m_args;
955
956 //! File path of the last module load
957 Fw::FileNameString m_lastLoadFileName;
958
959 WasmSequencer_RequestContext m_executingContext;
960 bool m_hasExecutingContext;
961
962 //! Pending timer from sleep host function
963 Fw::Time m_pendingTimer;
964 bool m_hasPendingTimer;
965
966 //! Wall-clock time at which the current blocking async host function
967 //! (COMMAND / blocking SERIAL_RECV) began awaiting its reply. Used to enforce
968 //! HOST_FUNCTION_TIMEOUT_SECS. Only meaningful while awaiting one of those.
969 Fw::Time m_hostFunctionStart;
970 bool m_hasHostFunctionStart;
971
972 bool m_dequeueSucceeded;
973
974 //! Flag indicating a function invocation failed
975 spacewasm_status_t m_invokeStatus;
976
977 //! Flag indicating interpreter is waiting to be paused
978 bool m_pendingPause;
979
980 //! Latches a CANCEL that arrives while a sequence is loading/resolving
981 bool m_cancelRequested;
982
983 //! Backing state for the periodically-written telemetry channels (see
984 //! writeTelemetry_handler). Grouped so the counters read as one unit.
985 struct Telemetry {
986 //! Sequences successfully completed
987 U64 sequencesSucceeded{0};
988
989 //! Sequences that failed to validate or execute
990 U64 sequencesFailed{0};
991
992 //! Sequences that were cancelled
993 U64 sequencesCancelled{0};
994
995 //! Commands dispatched total
996 U64 commandsDispatched{0};
997
998 //! Number of commands that failed
999 U64 commandsFailed{0};
1000
1001 //! Currently running sequence name
1002 Fw::FileNameString sequenceName{""};
1003 };
1004
1005 Telemetry m_tlm;
1006
1007 //! Sequences started counter (bumped whenever the interpreter
1008 //! begins spinning a freshly-invoked program). The low 16 bits form the
1009 //! high half of the command context (cmdUid) so we can detect a command
1010 //! response that arrives late, after its originating sequence has ended.
1011 U32 m_sequencesStarted;
1012
1013 //! Compose the command context (cmdUid) sent to the command dispatcher from
1014 //! the current sequence counter and the m_tlm.commandsDispatched counter. The
1015 //! low 16 bits of the latter form the low half of the cmdUid, letting us
1016 //! detect a response for a different instance of the same opcode.
1017 U32 makeCmdUid() const;
1018
1019 //! Why the last sequence ended. Set as the program runs and classified into
1020 //! the appropriate completion event (see reportSequenceFailure in the controller).
1021 struct ExitStatus {
1022 //! Reason the current program exited.
1023 //! By default this is INTERPRETER but can be overriden from host functions
1024 WasmSequencer_ExitReason reason{WasmSequencer_ExitReason::UNKNOWN};
1025
1026 //! Currently stored exit code for non-INTERPRETER exits
1027 I32 code{0};
1028
1029 //! Last run host function that could have caused the error
1030 WasmSequencer_HostFunction lastHostFunction{WasmSequencer_HostFunction::NONE};
1031
1032 //! Reason last sequence trapped
1033 WasmSequencer_TrapReason lastTrapReason{WasmSequencer_TrapReason::NONE};
1034 };
1035
1036 //! Status codes for exit reason. Set by the interpreter state machine.
1037 ExitStatus m_exit;
1038
1039 //! Buffer to hold the serial output port invocation invoked by the guest
1040 Fw::ExternalSerializeBuffer m_serialOutBuffer;
1041
1042 //! Queues (or queue) that handle inputs on the serial input port. Each is backed by
1043 //! the corresponding row of m_serialInQueueData (see the setup() loop in the ctor).
1044 Types::CircularBuffer m_serialInQueue[NUM_SERIALIN_INPUT_PORTS];
1045
1046 //! A lock for guarding the serialInQueue
1047 Os::Mutex m_serialInMutex;
1048
1049 //! A host function call the guest requested that is pending dispatch by the
1050 //! engine state machine (see dispatchPendingHostFunction). `kind` selects
1051 //! which arm of the `u` union carries the call's arguments.
1052 struct PendingHostFunction {
1053 1 PendingHostFunction() = default;
1054 ✗ bool isPending() const { return kind != WasmSequencer_HostFunction::NONE; }
1055 ✗ void clear() { kind = WasmSequencer_HostFunction::NONE; }
1056
1057 WasmSequencer_HostFunction kind{WasmSequencer_HostFunction::NONE};
1058
1059 // Handle that holds the Wasm guest memory pointer
1060 spacewasm_caller_t* caller{nullptr};
1061
1062 //! Per-kind call arguments. Only the arm matching `kind` is live.
1063 union Args {
1064 // COMMAND: encoded command payload in guest memory
1065 struct {
1066 U32 ptr;
1067 U32 len;
1068 } command;
1069
1070 // TELEMETRY: channel id plus where to write the serialized time and value
1071 struct {
1072 FwChanIdType chanId;
1073 U32 timePtr;
1074 U32 timeLen;
1075 U32 valuePtr;
1076 U32 valueLen;
1077 } telemetry;
1078
1079 // PARAMETER: parameter id plus where to write the serialized value
1080 struct {
1081 FwPrmIdType prmId;
1082 U32 ptr;
1083 U32 len;
1084 } parameter;
1085
1086 // EVENT: raw guest-requested severity (may be out of range) plus the message
1087 struct {
1088 U32 rawSeverity;
1089 U32 msgPtr;
1090 U32 msgLen;
1091 } event;
1092
1093 // RSLEEP: relative sleep duration
1094 struct {
1095 U64 us;
1096 } rsleep;
1097
1098 // ASLEEP: absolute sleep time
1099 struct {
1100 U64 us;
1101 } asleep;
1102
1103 // ARGS: where to write the stored sequence arguments
1104 struct {
1105 U32 ptr;
1106 U32 len;
1107 } args;
1108
1109 // TIME: where to write the serialized current time
1110 struct {
1111 U32 ptr;
1112 U32 len;
1113 } time;
1114
1115 // SERIAL_OUT: serial output port index plus payload in guest memory
1116 struct {
1117 U32 index;
1118 U32 ptr;
1119 U32 len;
1120 } serialOut;
1121
1122 // SERIAL_RECV: Read a message from the serialIn port queue given a port index
1123 struct {
1124 U32 index;
1125 U32 dataPtr;
1126 U32 dataSize;
1127 U32 actualSizePtr;
1128 Svc::BlockState::T blockingType;
1129 } serialRecv;
1130
1131 1 Args() : command{0, 0} {}
1132 } u;
1133 };
1134
1135 PendingHostFunction m_pendingHostFunction;
1136
1137 //! Helper function for checking the signature of a modules main function
1138 spacewasm_status_t validateModuleMain(WasmSequencer_ModuleIdx moduleIdx) const;
1139
1140 //! Report an engine-completion failure as the appropriate distinct event
1141 //! (SequenceExited / SequencePanic / SequenceTrapped / SequenceHostFailure,
1142 //! or SequenceCancelled) and bump the matching telemetry counter. `phase`
1143 //! records whether the failure occurred running the module's start function
1144 //! or its main entrypoint.
1145 void reportSequenceRuntimeFailure(WasmSequencer_ModuleIdx moduleIdx, WasmSequencer_SequencePhase phase);
1146
1147 //! Respond to a request with certain reply
1148 void respondToRequest(const Svc::WasmSequencer_RequestContext& value, const Fw::CmdResponse& response);
1149
1150 //! Send response to all waiting requests
1151 void respondToWaiting(const Fw::CmdResponse& response);
1152
1153 //! Report that a RUN finished on seqDoneOut (if connected) with the given
1154 //! response. Only emits for RUN-sourced requests, matching the RUN-gated
1155 //! seqStartOut in reportModuleStarted, so the seqStart/seqDone pair stays
1156 //! balanced. A no-op for INVOKE/LOAD, so both controller completion actions
1157 //! (respond_block_OK and respond_block_ERROR, which send the final command
1158 //! response) can call it unconditionally.
1159 void reportSeqDone(const Svc::WasmSequencer_RequestContext& value, const Fw::CmdResponse& response);
1160
1161 //! Report that a RUN ended before it ever started running on seqDoneOut (if
1162 //! connected) with the given response: rejected as BUSY, failed to load, failed to
1163 //! resolve an entrypoint, or cancelled while loading.
1164 void reportSeqAborted(const Svc::WasmSequencer_RequestContext& value, const Fw::CmdResponse& response);
1165
1166 //! Set a global to a value given the name of the module, global export name and value
1167 spacewasm_status_t setGlobal(const Fw::StringBase& moduleName, const Fw::StringBase& name, spacewasm_value_t value);
1168
1169 //! Get the value of a global variable given its module name and global name
1170 spacewasm_status_t getGlobal(const Fw::StringBase& moduleName,
1171 const Fw::StringBase& name,
1172 spacewasm_value_t& value);
1173
1174 //! Set up the fprime host interface
1175 void hostFprimeV1(spacewasm_host_t*);
1176
1177 /// FPrime Wasm Interface Host Functions
1178 spacewasm_hostcall_result_t wasmExit(struct spacewasm_caller_t* caller,
1179 const struct spacewasm_value_t* params,
1180 size_t n_params,
1181 struct spacewasm_value_t* out_result);
1182
1183 spacewasm_hostcall_result_t wasmPanic(struct spacewasm_caller_t* caller,
1184 const struct spacewasm_value_t* params,
1185 size_t n_params,
1186 struct spacewasm_value_t* out_result);
1187
1188 spacewasm_hostcall_result_t wasmArgs(struct spacewasm_caller_t* caller,
1189 const struct spacewasm_value_t* params,
1190 size_t n_params,
1191 struct spacewasm_value_t* out_result);
1192
1193 spacewasm_hostcall_result_t wasmTime(struct spacewasm_caller_t* caller,
1194 const struct spacewasm_value_t* params,
1195 size_t n_params,
1196 struct spacewasm_value_t* out_result);
1197
1198 spacewasm_hostcall_result_t wasmReadTelemetry(struct spacewasm_caller_t* caller,
1199 const struct spacewasm_value_t* params,
1200 size_t n_params,
1201 struct spacewasm_value_t* out_result);
1202
1203 spacewasm_hostcall_result_t wasmReadParameter(struct spacewasm_caller_t* caller,
1204 const struct spacewasm_value_t* params,
1205 size_t n_params,
1206 struct spacewasm_value_t* out_result);
1207
1208 spacewasm_hostcall_result_t wasmCommand(struct spacewasm_caller_t* caller,
1209 const struct spacewasm_value_t* params,
1210 size_t n_params,
1211 struct spacewasm_value_t* out_result);
1212
1213 spacewasm_hostcall_result_t wasmEvent(struct spacewasm_caller_t* caller,
1214 const struct spacewasm_value_t* params,
1215 size_t n_params,
1216 struct spacewasm_value_t* out_result);
1217
1218 spacewasm_hostcall_result_t wasmRsleep(struct spacewasm_caller_t* caller,
1219 const struct spacewasm_value_t* params,
1220 size_t n_params,
1221 struct spacewasm_value_t* out_result);
1222
1223 spacewasm_hostcall_result_t wasmAsleep(struct spacewasm_caller_t* caller,
1224 const struct spacewasm_value_t* params,
1225 size_t n_params,
1226 struct spacewasm_value_t* out_result);
1227
1228 spacewasm_hostcall_result_t wasmSerialOut(struct spacewasm_caller_t* caller,
1229 const struct spacewasm_value_t* params,
1230 size_t n_params,
1231 struct spacewasm_value_t* out_result);
1232
1233 spacewasm_hostcall_result_t wasmSerialRecv(struct spacewasm_caller_t* caller,
1234 const struct spacewasm_value_t* params,
1235 size_t n_params,
1236 struct spacewasm_value_t* out_result);
1237
1238 //! COMMAND: forward an encoded command from guest memory to the command dispatcher.
1239 void dispatchCommand();
1240
1241 //! TELEMETRY: read a telemetry channel and write its value + time into guest memory.
1242 void dispatchTelemetry();
1243
1244 //! PARAMETER: read a parameter and write it into guest memory.
1245 void dispatchParameter();
1246
1247 //! EVENT: emit a guest-requested event at the guest-requested severity.
1248 void dispatchEvent();
1249
1250 //! RSLEEP: arm a relative sleep timer.
1251 void dispatchRelativeSleep();
1252
1253 //! ASLEEP: arm an absolute sleep timer.
1254 void dispatchAbsoluteSleep();
1255
1256 //! ARGS: write the stored sequence arguments into guest memory.
1257 void dispatchArgs();
1258
1259 //! TIME: write the current time into guest memory.
1260 void dispatchTime();
1261
1262 //! SERIAL_OUT: copy a payload out of guest memory and invoke the serial output port.
1263 void dispatchSerialOut();
1264
1265 //! SERIAL_RECV: check the serial input queue and either resume or block awaiting a message.
1266 void dispatchSerialRecv();
1267
1268 // A global static lock. This is needed to allow the global allocator in spacewasm
1269 // to not require to pass context to fine grained context to allocations.
1270 // Read more about this in the SDD.
1271 static Os::Mutex* getGlobalAllocatorLock();
1272 };
1273
1274 } // namespace Svc
1275
1276 #endif
1277