GCC Code Coverage Report


Directory: ./
File: Svc/WasmSequencer/WasmSequencer.hpp
Date: 2026-10-14 22:11:56
Exec Total Coverage
Lines: 4 7 57.1%
Functions: 4 7 57.1%
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 2 ~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]
205 //! ```
206 //!
207 //! If $block == Svc.BlockState.BLOCK this command will wait for completion.
208 void RUN_cmdHandler(FwOpcodeType opCode, //!< The opcode
209 U32 cmdSeq, //!< The command sequence number
210 const Fw::CmdStringArg& fileName, //!< The name of the sequence file
211 const Svc::BlockState& block //!< Block until sequence has finished running
212 ) override;
213
214 //! Handler implementation for command LOAD
215 //!
216 //! Loads and validates a WebAssembly module into the store under the given name.
217 //! Naming the module lets its exports be referenced by other modules and lets
218 //! INVOKE, GLOBAL_GET and GLOBAL_SET address it. Use an empty name for a single,
219 //! standalone module. The name must not conflict with a previously loaded module.
220 void LOAD_cmdHandler(FwOpcodeType opCode, //!< The opcode
221 U32 cmdSeq, //!< The command sequence number
222 const Fw::CmdStringArg& fileName, //!< The name of the sequence file
223 const Fw::CmdStringArg& name //!< WebAssembly module name (empty for a single unnamed module)
224 ) override;
225
226 //! Handler implementation for command INVOKE
227 //!
228 //! Invoke a main function from a loaded module
229 void INVOKE_cmdHandler(FwOpcodeType opCode, //!< The opcode
230 U32 cmdSeq, //!< The command sequence number
231 const Fw::CmdStringArg& module, //!< Name of the module to invoke a function from
232 const Svc::BlockState& block //!< Block until sequence has finished running
233 ) override;
234
235 //! Handler implementation for command WAIT
236 //!
237 //! Wait for the interpreter to finish and return it's result as a CmdResponse
238 void WAIT_cmdHandler(FwOpcodeType opCode, //!< The opcode
239 U32 cmdSeq //!< The command sequence number
240 ) override;
241
242 //! Handler implementation for command CANCEL
243 //!
244 //! Cancels a running or validated sequence. After running CANCEL, the sequencer should return to IDLE
245 //! This completely clears the store.
246 void CANCEL_cmdHandler(FwOpcodeType opCode, //!< The opcode
247 U32 cmdSeq //!< The command sequence number
248 ) override;
249
250 //! Handler implementation for command PAUSE
251 //!
252 //! Pauses the execution of the sequencer, just before it is about to start spinning.
253 //! This simply pends a pause flag that will be taken before the sequence engine starts
254 //! up again.
255 //!
256 //! This command completes immediately
257 void PAUSE_cmdHandler(FwOpcodeType opCode, //!< The opcode
258 U32 cmdSeq //!< The command sequence number
259 ) override;
260
261 //! Handler implementation for command CONTINUE
262 //!
263 //! Resume the sequence from a paused state
264 void CONTINUE_cmdHandler(FwOpcodeType opCode, //!< The opcode
265 U32 cmdSeq //!< The command sequence number
266 ) override;
267
268 //! Handler implementation for command GLOBAL_SET_I32
269 //!
270 //! Set a global variable to a given i32 value.
271 //! Command fails if the module is not found, global is not exported, mutable, or of i32 type
272 void GLOBAL_SET_I32_cmdHandler(FwOpcodeType opCode, //!< The opcode
273 U32 cmdSeq, //!< The command sequence number
274 const Fw::CmdStringArg& moduleName, //!< Name of the module to set global for
275 const Fw::CmdStringArg& name, //!< Name of the global
276 I32 value //!< Value to set global to
277 ) override;
278
279 //! Handler implementation for command GLOBAL_SET_I64
280 //!
281 //! Set a global variable to a given i64 value.
282 //! Command fails if the module is not found, global is not exported, mutable, or of i64 type
283 void GLOBAL_SET_I64_cmdHandler(FwOpcodeType opCode, //!< The opcode
284 U32 cmdSeq, //!< The command sequence number
285 const Fw::CmdStringArg& moduleName, //!< Name of the module to set global for
286 const Fw::CmdStringArg& name, //!< Name of the global
287 I64 value //!< Value to set global to
288 ) override;
289
290 //! Handler implementation for command GLOBAL_SET_F32
291 //!
292 //! Set a global variable to a given f32 value.
293 //! Command fails if the module is not found, global is not exported, mutable, or of f32 type
294 void GLOBAL_SET_F32_cmdHandler(FwOpcodeType opCode, //!< The opcode
295 U32 cmdSeq, //!< The command sequence number
296 const Fw::CmdStringArg& moduleName, //!< Name of the module to set global for
297 const Fw::CmdStringArg& name, //!< Name of the global
298 F32 value //!< Value to set global to
299 ) override;
300
301 //! Handler implementation for command GLOBAL_SET_F64
302 //!
303 //! Set a global variable to a given f64 value.
304 //! Command fails if the module is not found, global is not exported, mutable, or of f64 type
305 void GLOBAL_SET_F64_cmdHandler(FwOpcodeType opCode, //!< The opcode
306 U32 cmdSeq, //!< The command sequence number
307 const Fw::CmdStringArg& moduleName, //!< Name of the module to set global for
308 const Fw::CmdStringArg& name, //!< Name of the global
309 F64 value //!< Value to set global to
310 ) override;
311
312 //! Handler implementation for command GLOBAL_GET
313 //!
314 //! Get the current value of a global variable and emit an event
315 //! Command fails if the module is not found or the global is not exported
316 void GLOBAL_GET_cmdHandler(FwOpcodeType opCode, //!< The opcode
317 U32 cmdSeq, //!< The command sequence number
318 const Fw::CmdStringArg& moduleName, //!< Name of the module to get global for
319 const Fw::CmdStringArg& name //!< Name of the global
320 ) override;
321
322 private:
323 // ----------------------------------------------------------------------
324 // Implementations for internal state machine actions
325 // ----------------------------------------------------------------------
326
327 //! Implementation for action processInvoke of state machine Svc_WasmSequencer_ControllerStateMachine
328 //!
329 //! Action to save the invoke arguments and emit an 'invoked' signal
330 void Svc_WasmSequencer_ControllerStateMachine_action_processInvoke(
331 SmId smId, //!< The state machine id
332 Svc_WasmSequencer_ControllerStateMachine::Signal signal, //!< The signal
333 const Svc::WasmSequencer_InvokeRequest& value //!< The value
334 ) override;
335
336 //! Implementation for action setCancelRequested of state machine Svc_WasmSequencer_ControllerStateMachine
337 //!
338 //! Latch a cancel that arrives while a sequence is loading/resolving
339 void Svc_WasmSequencer_ControllerStateMachine_action_setCancelRequested(
340 SmId smId, //!< The state machine id
341 Svc_WasmSequencer_ControllerStateMachine::Signal signal //!< The signal
342 ) override;
343
344 //! Implementation for action clearCancelRequested of state machine Svc_WasmSequencer_ControllerStateMachine
345 //!
346 //! Acknowledge/clear any pending cancel
347 void Svc_WasmSequencer_ControllerStateMachine_action_clearCancelRequested(
348 SmId smId, //!< The state machine id
349 Svc_WasmSequencer_ControllerStateMachine::Signal signal //!< The signal
350 ) override;
351
352 //! Implementation for action cancelPendingRequest of state machine Svc_WasmSequencer_ControllerStateMachine
353 //!
354 //! Abort a load/invoke that was cancelled before the engine ran
355 //! Reports a done on seqDoneOut for a port-sourced RUN
356 void Svc_WasmSequencer_ControllerStateMachine_action_cancelPendingRequest(
357 SmId smId, //!< The state machine id
358 Svc_WasmSequencer_ControllerStateMachine::Signal signal, //!< The signal
359 const Svc::WasmSequencer_RequestContext& value //!< The value
360 ) override;
361
362 //! Implementation for action respond_noblock_OK of state machine Svc_WasmSequencer_ControllerStateMachine
363 //!
364 //! Responds to $block == NO_BLOCK requests with OK
365 void Svc_WasmSequencer_ControllerStateMachine_action_respond_noblock_OK(
366 SmId smId, //!< The state machine id
367 Svc_WasmSequencer_ControllerStateMachine::Signal signal, //!< The signal
368 const Svc::WasmSequencer_RequestContext& value //!< The value
369 ) override;
370
371 //! Implementation for action respond_ERROR of state machine Svc_WasmSequencer_ControllerStateMachine
372 //!
373 //! Responds to request with EXECUTION_ERROR
374 //! Reports a done on seqDoneOut for a port-sourced RUN
375 void Svc_WasmSequencer_ControllerStateMachine_action_respond_ERROR(
376 SmId smId, //!< The state machine id
377 Svc_WasmSequencer_ControllerStateMachine::Signal signal, //!< The signal
378 const Svc::WasmSequencer_RequestContext& value //!< The value
379 ) override;
380
381 //! Implementation for action incrementSequenceFailure of state machine Svc_WasmSequencer_ControllerStateMachine
382 //!
383 //! Increment the SequencesFailed telemetry counter
384 void Svc_WasmSequencer_ControllerStateMachine_action_incrementSequenceFailure(
385 SmId smId, //!< The state machine id
386 Svc_WasmSequencer_ControllerStateMachine::Signal signal //!< The signal
387 ) override;
388
389 //! Implementation for action respondInvoke_BUSY of state machine Svc_WasmSequencer_ControllerStateMachine
390 //!
391 //! Responds to request with BUSY
392 //! Emit an event to say why we are rejecting this request in the current state
393 void Svc_WasmSequencer_ControllerStateMachine_action_respondInvoke_BUSY(
394 SmId smId, //!< The state machine id
395 Svc_WasmSequencer_ControllerStateMachine::Signal signal, //!< The signal
396 const Svc::WasmSequencer_InvokeRequest& value //!< The value
397 ) override;
398
399 //! Implementation for action respondInvoke_ERROR of state machine Svc_WasmSequencer_ControllerStateMachine
400 //!
401 //! Responds to request with EXECUTION_ERROR
402 //! Emit an event to say why we are rejecting this request in the current state
403 void Svc_WasmSequencer_ControllerStateMachine_action_respondInvoke_ERROR(
404 SmId smId, //!< The state machine id
405 Svc_WasmSequencer_ControllerStateMachine::Signal signal, //!< The signal
406 const Svc::WasmSequencer_InvokeRequest& value //!< The value
407 ) override;
408
409 //! Implementation for action respondLoad_BUSY of state machine Svc_WasmSequencer_ControllerStateMachine
410 //!
411 //! Responds to request with BUSY
412 //! Emit an event to say why we are rejecting this request in the current state
413 //! Reports a done on seqDoneOut for a port-sourced RUN
414 void Svc_WasmSequencer_ControllerStateMachine_action_respondLoad_BUSY(
415 SmId smId, //!< The state machine id
416 Svc_WasmSequencer_ControllerStateMachine::Signal signal, //!< The signal
417 const Svc::WasmSequencer_LoadRequest& value //!< The value
418 ) override;
419
420 //! Implementation for action respond_block_OK of state machine Svc_WasmSequencer_ControllerStateMachine
421 //!
422 //! Responds to $block == BLOCK requests with OK
423 //! Responds to any pending WAIT requests with OK
424 void Svc_WasmSequencer_ControllerStateMachine_action_respond_block_OK(
425 SmId smId, //!< The state machine id
426 Svc_WasmSequencer_ControllerStateMachine::Signal signal, //!< The signal
427 const Svc::WasmSequencer_RequestContext& value //!< The value
428 ) override;
429
430 //! Implementation for action respond_block_ERROR of state machine Svc_WasmSequencer_ControllerStateMachine
431 //!
432 //! Responds to $block == BLOCK requests with ERROR.
433 //! Responds to any pending WAIT requests with ERROR
434 void Svc_WasmSequencer_ControllerStateMachine_action_respond_block_ERROR(
435 SmId smId, //!< The state machine id
436 Svc_WasmSequencer_ControllerStateMachine::Signal signal, //!< The signal
437 const Svc::WasmSequencer_RequestContext& value //!< The value
438 ) override;
439
440 //! Implementation for action load of state machine Svc_WasmSequencer_ControllerStateMachine
441 //!
442 //! Load a module into the store.
443 //! Emits `loadSucceded` or `loadFailed` depending on result
444 void Svc_WasmSequencer_ControllerStateMachine_action_load(
445 SmId smId, //!< The state machine id
446 Svc_WasmSequencer_ControllerStateMachine::Signal signal, //!< The signal
447 const Svc::WasmSequencer_LoadRequest& value //!< The value
448 ) override;
449
450 //! Implementation for action invokeStart of state machine Svc_WasmSequencer_ControllerStateMachine
451 //!
452 //! Invoke the start function on a loaded module
453 void Svc_WasmSequencer_ControllerStateMachine_action_invokeStart(
454 SmId smId, //!< The state machine id
455 Svc_WasmSequencer_ControllerStateMachine::Signal signal, //!< The signal
456 const Svc::WasmSequencer_RequestContext& value //!< The value
457 ) override;
458
459 //! Implementation for action invokeMain of state machine Svc_WasmSequencer_ControllerStateMachine
460 //!
461 //! Invoke the main function for module in context
462 void Svc_WasmSequencer_ControllerStateMachine_action_invokeMain(
463 SmId smId, //!< The state machine id
464 Svc_WasmSequencer_ControllerStateMachine::Signal signal, //!< The signal
465 const Svc::WasmSequencer_RequestContext& value //!< The value
466 ) override;
467
468 //! Implementation for action reportModuleInvalidMain of state machine Svc_WasmSequencer_ControllerStateMachine
469 //!
470 //! Emit an event noting that a given module has no [valid] main function
471 void Svc_WasmSequencer_ControllerStateMachine_action_reportModuleInvalidMain(
472 SmId smId, //!< The state machine id
473 Svc_WasmSequencer_ControllerStateMachine::Signal signal, //!< The signal
474 const Svc::WasmSequencer_RequestContext& value //!< The value
475 ) override;
476
477 //! Implementation for action reportModuleMainInvokeFailed of state machine Svc_WasmSequencer_ControllerStateMachine
478 //!
479 //! Emit an event noting why the invocation of a module main failed
480 void Svc_WasmSequencer_ControllerStateMachine_action_reportModuleMainInvokeFailed(
481 SmId smId, //!< The state machine id
482 Svc_WasmSequencer_ControllerStateMachine::Signal signal, //!< The signal
483 const Svc::WasmSequencer_RequestContext& value //!< The value
484 ) override;
485
486 //! Implementation for action reportModuleStartInvokeFailed of state machine
487 //! Svc_WasmSequencer_ControllerStateMachine
488 //!
489 //! Emit an event noting why the invocation of a module start failed
490 void Svc_WasmSequencer_ControllerStateMachine_action_reportModuleStartInvokeFailed(
491 SmId smId, //!< The state machine id
492 Svc_WasmSequencer_ControllerStateMachine::Signal signal, //!< The signal
493 const Svc::WasmSequencer_RequestContext& value //!< The value
494 ) override;
495
496 //! Implementation for action reportModuleStarted of state machine Svc_WasmSequencer_ControllerStateMachine
497 //!
498 //! Reports that a module started running it's main function
499 void Svc_WasmSequencer_ControllerStateMachine_action_reportModuleStarted(
500 SmId smId, //!< The state machine id
501 Svc_WasmSequencer_ControllerStateMachine::Signal signal, //!< The signal
502 const Svc::WasmSequencer_RequestContext& value //!< The value
503 ) override;
504
505 //! Implementation for action reportModuleSucceeded of state machine Svc_WasmSequencer_ControllerStateMachine
506 //!
507 //! Emit an event noting a module succeeded during execution. Increment telemetry counters.
508 void Svc_WasmSequencer_ControllerStateMachine_action_reportModuleSucceeded(
509 SmId smId, //!< The state machine id
510 Svc_WasmSequencer_ControllerStateMachine::Signal signal, //!< The signal
511 const Svc::WasmSequencer_RequestContext& value //!< The value
512 ) override;
513
514 //! Implementation for action reportModuleStartFailed of state machine Svc_WasmSequencer_ControllerStateMachine
515 //!
516 //! Emit an event noting a module failed during execution of start. Increment telemetry counters.
517 void Svc_WasmSequencer_ControllerStateMachine_action_reportModuleStartFailed(
518 SmId smId, //!< The state machine id
519 Svc_WasmSequencer_ControllerStateMachine::Signal signal, //!< The signal
520 const Svc::WasmSequencer_RequestContext& value //!< The value
521 ) override;
522
523 //! Implementation for action reportModuleMainFailed of state machine Svc_WasmSequencer_ControllerStateMachine
524 //!
525 //! Emit an event noting a module failed during execution. Increment telemetry counters.
526 void Svc_WasmSequencer_ControllerStateMachine_action_reportModuleMainFailed(
527 SmId smId, //!< The state machine id
528 Svc_WasmSequencer_ControllerStateMachine::Signal signal, //!< The signal
529 const Svc::WasmSequencer_RequestContext& value //!< The value
530 ) override;
531
532 //! Implementation for action resetStore of state machine Svc_WasmSequencer_ControllerStateMachine
533 //!
534 //! Create a new store with N_MODULES (parameter) modules
535 void Svc_WasmSequencer_ControllerStateMachine_action_resetStore(
536 SmId smId, //!< The state machine id
537 Svc_WasmSequencer_ControllerStateMachine::Signal signal //!< The signal
538 ) override;
539
540 //! Implementation for action runEngine of state machine Svc_WasmSequencer_ControllerStateMachine
541 //!
542 //! Send a signal to the engine state machine to begin running
543 //! The engine will asynchronously reply with the `engineFinished` signal
544 void Svc_WasmSequencer_ControllerStateMachine_action_runEngine(
545 SmId smId, //!< The state machine id
546 Svc_WasmSequencer_ControllerStateMachine::Signal signal, //!< The signal
547 const Svc::WasmSequencer_RequestContext& value //!< The value
548 ) override;
549
550 //! Implementation for action cmdReplyOK of state machine Svc_WasmSequencer_InterpreterStateMachine
551 //!
552 //! Respond to a pending command with OK
553 void Svc_WasmSequencer_InterpreterStateMachine_action_cmdReplyOK(
554 SmId smId, //!< The state machine id
555 Svc_WasmSequencer_InterpreterStateMachine::Signal signal, //!< The signal
556 const Svc::WasmSequencer_CommandRequest& value //!< The value
557 ) override;
558
559 //! Implementation for action signalEntered of state machine Svc_WasmSequencer_InterpreterStateMachine
560 //!
561 //! generic signal raised
562 void Svc_WasmSequencer_InterpreterStateMachine_action_signalEntered(
563 SmId smId, //!< The state machine id
564 Svc_WasmSequencer_InterpreterStateMachine::Signal signal //!< The signal
565 ) override;
566
567 //! Implementation for action spin of state machine Svc_WasmSequencer_InterpreterStateMachine
568 //!
569 //! spins the interpreter loop, executing up to a bounded number of instructions
570 void Svc_WasmSequencer_InterpreterStateMachine_action_spin(
571 SmId smId, //!< The state machine id
572 Svc_WasmSequencer_InterpreterStateMachine::Signal signal //!< The signal
573 ) override;
574
575 //! Implementation for action reset of state machine Svc_WasmSequencer_InterpreterStateMachine
576 //!
577 //! resets the engine's state (clears operand stack, pc, fp, sp)
578 void Svc_WasmSequencer_InterpreterStateMachine_action_reset(
579 SmId smId, //!< The state machine id
580 Svc_WasmSequencer_InterpreterStateMachine::Signal signal //!< The signal
581 ) override;
582
583 //! Implementation for action clearExitStatus of state machine Svc_WasmSequencer_InterpreterStateMachine
584 void Svc_WasmSequencer_InterpreterStateMachine_action_clearExitStatus(
585 SmId smId, //!< The state machine id
586 Svc_WasmSequencer_InterpreterStateMachine::Signal signal //!< The signal
587 ) override;
588
589 //! Implementation for action setExitReason_INTERPRETER_FINISHED of state machine
590 //! Svc_WasmSequencer_InterpreterStateMachine
591 void Svc_WasmSequencer_InterpreterStateMachine_action_setExitReason_INTERPRETER_FINISHED(
592 SmId smId, //!< The state machine id
593 Svc_WasmSequencer_InterpreterStateMachine::Signal signal //!< The signal
594 ) override;
595
596 //! Implementation for action setExitReason_INTERPRETER_TRAP of state machine
597 //! Svc_WasmSequencer_InterpreterStateMachine
598 void Svc_WasmSequencer_InterpreterStateMachine_action_setExitReason_INTERPRETER_TRAP(
599 SmId smId, //!< The state machine id
600 Svc_WasmSequencer_InterpreterStateMachine::Signal signal //!< The signal
601 ) override;
602
603 //! Implementation for action setExitReason_REPLY_TIMEOUT of state machine Svc_WasmSequencer_InterpreterStateMachine
604 void Svc_WasmSequencer_InterpreterStateMachine_action_setExitReason_REPLY_TIMEOUT(
605 SmId smId, //!< The state machine id
606 Svc_WasmSequencer_InterpreterStateMachine::Signal signal //!< The signal
607 ) override;
608
609 //! Implementation for action setExitReason_HOST_FAILURE of state machine Svc_WasmSequencer_InterpreterStateMachine
610 void Svc_WasmSequencer_InterpreterStateMachine_action_setExitReason_HOST_FAILURE(
611 SmId smId, //!< The state machine id
612 Svc_WasmSequencer_InterpreterStateMachine::Signal signal //!< The signal
613 ) override;
614
615 //! Implementation for action setExitReason_TIMER_INCOMPARABLE of state machine
616 //! Svc_WasmSequencer_InterpreterStateMachine
617 void Svc_WasmSequencer_InterpreterStateMachine_action_setExitReason_TIMER_INCOMPARABLE(
618 SmId smId, //!< The state machine id
619 Svc_WasmSequencer_InterpreterStateMachine::Signal signal //!< The signal
620 ) override;
621
622 //! Implementation for action setExitReason_UNEXPECTED_REPLY of state machine
623 //! Svc_WasmSequencer_InterpreterStateMachine
624 void Svc_WasmSequencer_InterpreterStateMachine_action_setExitReason_UNEXPECTED_REPLY(
625 SmId smId, //!< The state machine id
626 Svc_WasmSequencer_InterpreterStateMachine::Signal signal //!< The signal
627 ) override;
628
629 //! Implementation for action setExitReason_CANCEL of state machine Svc_WasmSequencer_InterpreterStateMachine
630 void Svc_WasmSequencer_InterpreterStateMachine_action_setExitReason_CANCEL(
631 SmId smId, //!< The state machine id
632 Svc_WasmSequencer_InterpreterStateMachine::Signal signal //!< The signal
633 ) override;
634
635 //! Implementation for action setExitCode of state machine Svc_WasmSequencer_InterpreterStateMachine
636 void Svc_WasmSequencer_InterpreterStateMachine_action_setExitCode(
637 SmId smId, //!< The state machine id
638 Svc_WasmSequencer_InterpreterStateMachine::Signal signal, //!< The signal
639 I32 value //!< The value
640 ) override;
641
642 //! Implementation for action setTrapReason of state machine Svc_WasmSequencer_InterpreterStateMachine
643 void Svc_WasmSequencer_InterpreterStateMachine_action_setTrapReason(
644 SmId smId, //!< The state machine id
645 Svc_WasmSequencer_InterpreterStateMachine::Signal signal, //!< The signal
646 const Svc::WasmSequencer_TrapReason& value //!< The value
647 ) override;
648
649 //! Implementation for action setLastHostFunction of state machine Svc_WasmSequencer_InterpreterStateMachine
650 void Svc_WasmSequencer_InterpreterStateMachine_action_setLastHostFunction(
651 SmId smId, //!< The state machine id
652 Svc_WasmSequencer_InterpreterStateMachine::Signal signal //!< The signal
653 ) override;
654
655 //! Implementation for action finish of state machine Svc_WasmSequencer_InterpreterStateMachine
656 //!
657 //! Send a signal back to the controller state machine that we have finished executing
658 //! The response codes are stored in m_exit (reason, code, lastTrapReason)
659 void Svc_WasmSequencer_InterpreterStateMachine_action_finish(
660 SmId smId, //!< The state machine id
661 Svc_WasmSequencer_InterpreterStateMachine::Signal signal //!< The signal
662 ) override;
663
664 //! Implementation for action reportPaused of state machine Svc_WasmSequencer_InterpreterStateMachine
665 //!
666 //! reports that execution was paused at a breakpoint
667 void Svc_WasmSequencer_InterpreterStateMachine_action_reportPaused(
668 SmId smId, //!< The state machine id
669 Svc_WasmSequencer_InterpreterStateMachine::Signal signal //!< The signal
670 ) override;
671
672 //! Implementation for action clearPause of state machine Svc_WasmSequencer_InterpreterStateMachine
673 //!
674 //! sets the pause flag to false
675 void Svc_WasmSequencer_InterpreterStateMachine_action_clearPause(
676 SmId smId, //!< The state machine id
677 Svc_WasmSequencer_InterpreterStateMachine::Signal signal //!< The signal
678 ) override;
679
680 //! Implementation for action dispatchPendingHostFunction of state machine Svc_WasmSequencer_InterpreterStateMachine
681 //!
682 //! dispatch a host function port call
683 void Svc_WasmSequencer_InterpreterStateMachine_action_dispatchPendingHostFunction(
684 SmId smId, //!< The state machine id
685 Svc_WasmSequencer_InterpreterStateMachine::Signal signal //!< The signal
686 ) override;
687
688 //! Implementation for action clearPendingHostFunction of state machine Svc_WasmSequencer_InterpreterStateMachine
689 //!
690 //! clears the pending host function port call
691 void Svc_WasmSequencer_InterpreterStateMachine_action_clearPendingHostFunction(
692 SmId smId, //!< The state machine id
693 Svc_WasmSequencer_InterpreterStateMachine::Signal signal //!< The signal
694 ) override;
695
696 //! Implementation for action setContext of state machine Svc_WasmSequencer_InterpreterStateMachine
697 //!
698 //! Set the current executing context
699 void Svc_WasmSequencer_InterpreterStateMachine_action_setContext(
700 SmId smId, //!< The state machine id
701 Svc_WasmSequencer_InterpreterStateMachine::Signal signal, //!< The signal
702 const Svc::WasmSequencer_RequestContext& value //!< The value
703 ) override;
704
705 //! Implementation for action clearContext of state machine Svc_WasmSequencer_InterpreterStateMachine
706 //!
707 //! Clear the current executing context
708 void Svc_WasmSequencer_InterpreterStateMachine_action_clearContext(
709 SmId smId, //!< The state machine id
710 Svc_WasmSequencer_InterpreterStateMachine::Signal signal //!< The signal
711 ) override;
712
713 //! Implementation for action resume of state machine Svc_WasmSequencer_InterpreterStateMachine
714 //!
715 //! spacewasm_engine_resume
716 void Svc_WasmSequencer_InterpreterStateMachine_action_resume(
717 SmId smId, //!< The state machine id
718 Svc_WasmSequencer_InterpreterStateMachine::Signal signal //!< The signal
719 ) override;
720
721 //! Implementation for action resumeI32 of state machine Svc_WasmSequencer_InterpreterStateMachine
722 //!
723 //! spacewasm_engine_resume_some(I32(value))
724 void Svc_WasmSequencer_InterpreterStateMachine_action_resumeI32(
725 SmId smId, //!< The state machine id
726 Svc_WasmSequencer_InterpreterStateMachine::Signal signal, //!< The signal
727 I32 value //!< The value
728 ) override;
729
730 //! Implementation for action checkSleepTimers of state machine Svc_WasmSequencer_InterpreterStateMachine
731 //!
732 //! A periodic check on the pending timer to see if we can wake up
733 void Svc_WasmSequencer_InterpreterStateMachine_action_checkSleepTimers(
734 SmId smId, //!< The state machine id
735 Svc_WasmSequencer_InterpreterStateMachine::Signal signal //!< The signal
736 ) override;
737
738 //! Implementation for action checkTimeout of state machine Svc_WasmSequencer_InterpreterStateMachine
739 //!
740 //! A periodic check on any host function to guard against timeouts
741 void Svc_WasmSequencer_InterpreterStateMachine_action_checkTimeout(
742 SmId smId, //!< The state machine id
743 Svc_WasmSequencer_InterpreterStateMachine::Signal signal //!< The signal
744 ) override;
745
746 //! Implementation for action dequeueSerialAndResume of state machine Svc_WasmSequencer_InterpreterStateMachine
747 //!
748 //! Dequeue a serial message into the host guest memory and resume the interpreter
749 void Svc_WasmSequencer_InterpreterStateMachine_action_dequeueSerialAndResume(
750 SmId smId, //!< The state machine id
751 Svc_WasmSequencer_InterpreterStateMachine::Signal signal, //!< The signal
752 const FwIndexType& value //!< The value
753 ) override;
754
755 private:
756 // ----------------------------------------------------------------------
757 // Implementations for internal state machine guards
758 // ----------------------------------------------------------------------
759
760 //! Implementation for guard cancelRequested of state machine Svc_WasmSequencer_ControllerStateMachine
761 //!
762 //! True if a cancel was latched since the controller last came to rest.
763 bool Svc_WasmSequencer_ControllerStateMachine_guard_cancelRequested(
764 SmId smId, //!< The state machine id
765 Svc_WasmSequencer_ControllerStateMachine::Signal signal //!< The signal
766 ) const override;
767
768 //! Implementation for guard moduleHasStart of state machine Svc_WasmSequencer_ControllerStateMachine
769 //!
770 //! return true if this module has a start function
771 bool Svc_WasmSequencer_ControllerStateMachine_guard_moduleHasStart(
772 SmId smId, //!< The state machine id
773 Svc_WasmSequencer_ControllerStateMachine::Signal signal, //!< The signal
774 const Svc::WasmSequencer_RequestContext& value //!< The value
775 ) const override;
776
777 //! Implementation for guard moduleHasValidMain of state machine Svc_WasmSequencer_ControllerStateMachine
778 //!
779 //! return true if this module has a valid main function ([] -> i32)
780 bool Svc_WasmSequencer_ControllerStateMachine_guard_moduleHasValidMain(
781 SmId smId, //!< The state machine id
782 Svc_WasmSequencer_ControllerStateMachine::Signal signal, //!< The signal
783 const Svc::WasmSequencer_RequestContext& value //!< The value
784 ) const override;
785
786 //! Implementation for guard invokeSucceeded of state machine Svc_WasmSequencer_ControllerStateMachine
787 //!
788 //! return true if invokeStatus == SPACEWASM_OK. This flag is set as a result of invokeStart/invokeMain
789 bool Svc_WasmSequencer_ControllerStateMachine_guard_invokeSucceeded(
790 SmId smId, //!< The state machine id
791 Svc_WasmSequencer_ControllerStateMachine::Signal signal, //!< The signal
792 const Svc::WasmSequencer_RequestContext& value //!< The value
793 ) const override;
794
795 //! Implementation for guard interpreterSucceeded of state machine Svc_WasmSequencer_ControllerStateMachine
796 //!
797 //! Check if the last engine execution finished executing successfully
798 bool Svc_WasmSequencer_ControllerStateMachine_guard_interpreterSucceeded(
799 SmId smId, //!< The state machine id
800 Svc_WasmSequencer_ControllerStateMachine::Signal signal //!< The signal
801 ) const override;
802
803 //! Implementation for guard pendingPause of state machine Svc_WasmSequencer_InterpreterStateMachine
804 //!
805 //! return true if execution should pause before spinning the interpreter again
806 bool Svc_WasmSequencer_InterpreterStateMachine_guard_pendingPause(
807 SmId smId, //!< The state machine id
808 Svc_WasmSequencer_InterpreterStateMachine::Signal signal //!< The signal
809 ) const override;
810
811 //! Implementation for guard pendingHostFunction of state machine Svc_WasmSequencer_InterpreterStateMachine
812 //!
813 //! a host function is waiting to be processed
814 bool Svc_WasmSequencer_InterpreterStateMachine_guard_pendingHostFunction(
815 SmId smId, //!< The state machine id
816 Svc_WasmSequencer_InterpreterStateMachine::Signal signal //!< The signal
817 ) const override;
818
819 //! Implementation for guard pendingHostFunctionIsSleep of state machine Svc_WasmSequencer_InterpreterStateMachine
820 //!
821 //! the pending host function is a sleep (therefore we need to check the sleep timers)
822 bool Svc_WasmSequencer_InterpreterStateMachine_guard_pendingHostFunctionIsSleep(
823 SmId smId, //!< The state machine id
824 Svc_WasmSequencer_InterpreterStateMachine::Signal signal //!< The signal
825 ) const override;
826
827 //! Implementation for guard blockingSerialIn of state machine Svc_WasmSequencer_InterpreterStateMachine
828 //!
829 //! Check if we are currently blocking on a serial_recv() for a given serial port index
830 bool Svc_WasmSequencer_InterpreterStateMachine_guard_blockingSerialIn(
831 SmId smId, //!< The state machine id
832 Svc_WasmSequencer_InterpreterStateMachine::Signal signal, //!< The signal
833 const FwIndexType& value //!< The value
834 ) const override;
835
836 //! Implementation for guard dequeueSucceeded of state machine Svc_WasmSequencer_InterpreterStateMachine
837 //!
838 //! Return true `dequeueSerialAndResume` processed a message successfully
839 bool Svc_WasmSequencer_InterpreterStateMachine_guard_dequeueSucceeded(
840 SmId smId, //!< The state machine id
841 Svc_WasmSequencer_InterpreterStateMachine::Signal signal //!< The signal
842 ) const override;
843
844 private:
845 /// The global allocator callbacks
846 U8* globalAlloc(U32 size, U32 align);
847 void globalDealloc(const U8* ptr);
848
849 /// C-callback trampolines for the spacewasm global-allocator registry
850 static U8* globalAllocCallback(void* userdata, size_t size, size_t align);
851 static void globalDeallocCallback(void* userdata, U8* ptr, size_t size, size_t align);
852
853 /// The Wasm guest allocator callbacks for this component
854 U8* guestAlloc(FwSizeType size, U32 align);
855 U8* guestRealloc(U8* ptr, FwSizeType oldSize, FwSizeType newSize, U32 align);
856 void guestDealloc(const U8* ptr, FwSizeType size);
857
858 // Guest allocator callbacks passed to C API
859 static U8* guestAllocCallback(void* userdata, size_t size, size_t align);
860 static U8* guestReallocCallback(void* userdata, U8* ptr, size_t old_size, size_t new_size, size_t align);
861 static void guestDeallocCallback(void* userdata, U8* ptr, size_t size, size_t align);
862
863 //! Create a fresh interpreter store with the given module capacity,
864 //! destroying any existing store first.
865 void createStore();
866
867 //! Destroy the current interpreter store, if any, releasing its memory.
868 void destroyStore();
869
870 //! Take control of the spacewasm global allocator on this WasmSequence
871 void takeAllocatorLock();
872
873 //! Release control of the spacewasm global allocator on this WasmSequence
874 void releaseAllocatorLock();
875
876 //! Map a spacewasm_trap_t onto the TrapReason event enum.
877 static Svc::WasmSequencer_TrapReason::T mapTrapReason(spacewasm_trap_t trap);
878
879 //! Record the SeqName telemetry for a load. Uses moduleName when non-empty;
880 //! otherwise derives it from the file's basename with any ".wasm" suffix
881 //! stripped (an empty-name RUN / LOAD).
882 void setSequenceName(const Fw::StringBase& filePath, const Fw::StringBase& moduleName);
883
884 //! Return a pointer to the basename of `path` (the segment after the last '/')
885 //! and write its length to `outLen`. `len` is the length of `path`. Pure string
886 //! manipulation, no filesystem access.
887 static const char* pathBaseName(const char* path, FwSizeType len, FwSizeType& outLen);
888
889 //! True if `path` contains a ".." path-traversal component (a segment, delimited
890 //! by '/', that is exactly ".."). Used to keep a ground-supplied sequence file
891 //! name from escaping the configured SEQ_BASE_DIR.
892 static bool pathHasParentTraversal(const Fw::StringBase& path);
893
894 //! Resolve a sequence `fileName` against the SEQ_BASE_DIR parameter, writing the
895 //! result to `filePath`. On failure (a ".." component that would escape the base
896 //! dir, or a joined path that overflows the buffer) it logs the specific event
897 //! and returns false; the caller is responsible for failing the load.
898 bool resolveSequencePath(const Fw::StringBase& fileName, Fw::String& filePath);
899
900 //! Read `len` bytes of guest linear memory at `addr` into `dst` (via
901 //! spacewasm_mem_read on the pending host function's caller).
902 Fw::Success readGuestMemory(WasmSequencer_HostFunction::T kind, U32 addr, U8* dst, FwSizeType len);
903
904 //! Write `len` bytes from `src` into guest linear memory at `addr` (via
905 //! spacewasm_mem_write)
906 Fw::Success writeGuestMemory(WasmSequencer_HostFunction::T kind, U32 addr, const U8* src, FwSizeType len);
907
908 Fw::MemAllocator* m_allocator = nullptr;
909
910 //! Memory-resource configuration captured by configure()
911 Config m_config;
912
913 //! Page pool backing the process-wide spacewasm global page allocator for this instance.
914 //! Each page is `Svc::WasmSequencerConfig::SPACEWASM_PAGE_SIZE` with m_config.heapPages pages.
915 //! Stores dynamic memory allocated to hold each loaded module in the store (and the store itself).
916 U8** m_heapPages;
917
918 //! Number of currently used
919 FwSizeType m_heapPagesUsed;
920
921 //! A deallocation has poisoned the heap allocator
922 //! No more allocations can happen until every page is dropped.
923 //! SpaceWasm will drop everything in one shot so this simply helps us guard this invariant with an assertion
924 bool m_heapPoisoned;
925
926 //! Pool backing the per-load guest linear-memory allocator; a simple
927 //! bump allocator. `memory.grow` is enabled, but a bump allocator can only
928 //! service growth at the tail of the pool; see `guestRealloc`.
929 U8* m_guestPool;
930
931 //! Current bump offset into `m_guestPool`.
932 FwSizeType m_guestPoolOffset;
933
934 //! Opaque handle to the spacewasm engine, or null (before the store is initialized).
935 spacewasm_t* m_wasm;
936
937 //! Opaque handle to the spacewasm guest memory allocator, or null (before store/allocator is initialized)
938 spacewasm_allocator_t* m_guest_allocator;
939
940 //! Pending command waiting for a response
941 struct WaitingCmd {
942 FwOpcodeType opCode;
943 U32 cmdSeq;
944
945 8 WaitingCmd() : opCode(0), cmdSeq(0) {}
946 ✗ WaitingCmd(FwOpcodeType opCode_, U32 cmdSeq_) : opCode(opCode_), cmdSeq(cmdSeq_) {}
947 };
948
949 //! WAIT commands waiting for sequence completion
950 Fw::FifoQueue<WaitingCmd, WasmSequencerConfig::MAX_CONCURRENT_WAIT_COMMANDS> m_waiting;
951
952 //! File path of the last module load
953 Fw::FileNameString m_lastLoadFileName;
954
955 WasmSequencer_RequestContext m_executingContext;
956 bool m_hasExecutingContext;
957
958 //! Pending timer from sleep host function
959 Fw::Time m_pendingTimer;
960 bool m_hasPendingTimer;
961
962 //! Wall-clock time at which the current blocking async host function
963 //! (COMMAND / blocking SERIAL_RECV) began awaiting its reply. Used to enforce
964 //! HOST_FUNCTION_TIMEOUT_SECS. Only meaningful while awaiting one of those.
965 Fw::Time m_hostFunctionStart;
966 bool m_hasHostFunctionStart;
967
968 bool m_dequeueSucceeded;
969
970 //! Flag indicating a function invocation failed
971 spacewasm_status_t m_invokeStatus;
972
973 //! Flag indicating interpreter is waiting to be paused
974 bool m_pendingPause;
975
976 //! Latches a CANCEL that arrives while a sequence is loading/resolving
977 bool m_cancelRequested;
978
979 //! Backing state for the periodically-written telemetry channels (see
980 //! writeTelemetry_handler). Grouped so the counters read as one unit.
981 struct Telemetry {
982 //! Sequences successfully completed
983 U64 sequencesSucceeded{0};
984
985 //! Sequences that failed to validate or execute
986 U64 sequencesFailed{0};
987
988 //! Sequences that were cancelled
989 U64 sequencesCancelled{0};
990
991 //! Commands dispatched total
992 U64 commandsDispatched{0};
993
994 //! Number of commands that failed
995 U64 commandsFailed{0};
996
997 //! Currently running sequence name
998 Fw::FileNameString sequenceName{""};
999 };
1000
1001 Telemetry m_tlm;
1002
1003 //! Sequences started counter (bumped whenever the interpreter
1004 //! begins spinning a freshly-invoked program). The low 16 bits form the
1005 //! high half of the command context (cmdUid) so we can detect a command
1006 //! response that arrives late, after its originating sequence has ended.
1007 U32 m_sequencesStarted;
1008
1009 //! Compose the command context (cmdUid) sent to the command dispatcher from
1010 //! the current sequence counter and the m_tlm.commandsDispatched counter. The
1011 //! low 16 bits of the latter form the low half of the cmdUid, letting us
1012 //! detect a response for a different instance of the same opcode.
1013 U32 makeCmdUid() const;
1014
1015 //! Why the last sequence ended. Set as the program runs and classified into
1016 //! the appropriate completion event (see reportSequenceFailure in the controller).
1017 struct ExitStatus {
1018 //! Reason the current program exited.
1019 //! By default this is INTERPRETER but can be overriden from host functions
1020 WasmSequencer_ExitReason reason{WasmSequencer_ExitReason::UNKNOWN};
1021
1022 //! Currently stored exit code for non-INTERPRETER exits
1023 I32 code{0};
1024
1025 //! Last run host function that could have caused the error
1026 WasmSequencer_HostFunction lastHostFunction{WasmSequencer_HostFunction::NONE};
1027
1028 //! Reason last sequence trapped
1029 WasmSequencer_TrapReason lastTrapReason{WasmSequencer_TrapReason::NONE};
1030 };
1031
1032 //! Status codes for exit reason. Set by the interpreter state machine.
1033 ExitStatus m_exit;
1034
1035 //! Buffer to hold the serial output port invocation invoked by the guest
1036 Fw::ExternalSerializeBuffer m_serialOutBuffer;
1037
1038 //! Queues (or queue) that handle inputs on the serial input port. Each is backed by
1039 //! the corresponding row of m_serialInQueueData (see the setup() loop in the ctor).
1040 Types::CircularBuffer m_serialInQueue[NUM_SERIALIN_INPUT_PORTS];
1041
1042 //! A lock for guarding the serialInQueue
1043 Os::Mutex m_serialInMutex;
1044
1045 //! A host function call the guest requested that is pending dispatch by the
1046 //! engine state machine (see dispatchPendingHostFunction). `kind` selects
1047 //! which arm of the `u` union carries the call's arguments.
1048 struct PendingHostFunction {
1049 1 PendingHostFunction() = default;
1050 ✗ bool isPending() const { return kind != WasmSequencer_HostFunction::NONE; }
1051 ✗ void clear() { kind = WasmSequencer_HostFunction::NONE; }
1052
1053 WasmSequencer_HostFunction kind{WasmSequencer_HostFunction::NONE};
1054
1055 // Handle that holds the Wasm guest memory pointer
1056 spacewasm_caller_t* caller{nullptr};
1057
1058 //! Per-kind call arguments. Only the arm matching `kind` is live.
1059 union Args {
1060 // COMMAND: encoded command payload in guest memory
1061 struct {
1062 U32 ptr;
1063 U32 len;
1064 } command;
1065
1066 // TELEMETRY: channel id plus where to write the serialized time and value
1067 struct {
1068 FwChanIdType chanId;
1069 U32 timePtr;
1070 U32 timeLen;
1071 U32 valuePtr;
1072 U32 valueLen;
1073 } telemetry;
1074
1075 // PARAMETER: parameter id plus where to write the serialized value
1076 struct {
1077 FwPrmIdType prmId;
1078 U32 ptr;
1079 U32 len;
1080 } parameter;
1081
1082 // EVENT: raw guest-requested severity (may be out of range) plus the message
1083 struct {
1084 U32 rawSeverity;
1085 U32 msgPtr;
1086 U32 msgLen;
1087 } event;
1088
1089 // RSLEEP: relative sleep duration
1090 struct {
1091 U64 us;
1092 } rsleep;
1093
1094 // ASLEEP: absolute sleep time
1095 struct {
1096 U64 us;
1097 } asleep;
1098
1099 // TIME: where to write the serialized current time
1100 struct {
1101 U32 ptr;
1102 U32 len;
1103 } time;
1104
1105 // SERIAL_OUT: serial output port index plus payload in guest memory
1106 struct {
1107 U32 index;
1108 U32 ptr;
1109 U32 len;
1110 } serialOut;
1111
1112 // SERIAL_RECV: Read a message from the serialIn port queue given a port index
1113 struct {
1114 U32 index;
1115 U32 dataPtr;
1116 U32 dataSize;
1117 U32 actualSizePtr;
1118 Svc::BlockState::T blockingType;
1119 } serialRecv;
1120
1121 1 Args() : command{0, 0} {}
1122 } u;
1123 };
1124
1125 PendingHostFunction m_pendingHostFunction;
1126
1127 //! Helper function for checking the signature of a modules main function
1128 spacewasm_status_t validateModuleMain(WasmSequencer_ModuleIdx moduleIdx) const;
1129
1130 //! Report an engine-completion failure as the appropriate distinct event
1131 //! (SequenceExited / SequencePanic / SequenceTrapped / SequenceHostFailure,
1132 //! or SequenceCancelled) and bump the matching telemetry counter. `phase`
1133 //! records whether the failure occurred running the module's start function
1134 //! or its main entrypoint.
1135 void reportSequenceRuntimeFailure(WasmSequencer_ModuleIdx moduleIdx, WasmSequencer_SequencePhase phase);
1136
1137 //! Respond to a request with certain reply
1138 void respondToRequest(const Svc::WasmSequencer_RequestContext& value, const Fw::CmdResponse& response);
1139
1140 //! Send response to all waiting requests
1141 void respondToWaiting(const Fw::CmdResponse& response);
1142
1143 //! Report that a RUN finished on seqDoneOut (if connected) with the given
1144 //! response. Only emits for RUN-sourced requests, matching the RUN-gated
1145 //! seqStartOut in reportModuleStarted, so the seqStart/seqDone pair stays
1146 //! balanced. A no-op for INVOKE/LOAD, so both controller completion actions
1147 //! (respond_block_OK and respond_block_ERROR, which send the final command
1148 //! response) can call it unconditionally.
1149 void reportSeqDone(const Svc::WasmSequencer_RequestContext& value, const Fw::CmdResponse& response);
1150
1151 //! Report that a RUN ended before it ever started running on seqDoneOut (if
1152 //! connected) with the given response: rejected as BUSY, failed to load, failed to
1153 //! resolve an entrypoint, or cancelled while loading.
1154 void reportSeqAborted(const Svc::WasmSequencer_RequestContext& value, const Fw::CmdResponse& response);
1155
1156 //! Set a global to a value given the name of the module, global export name and value
1157 spacewasm_status_t setGlobal(const Fw::StringBase& moduleName, const Fw::StringBase& name, spacewasm_value_t value);
1158
1159 //! Get the value of a global variable given its module name and global name
1160 spacewasm_status_t getGlobal(const Fw::StringBase& moduleName,
1161 const Fw::StringBase& name,
1162 spacewasm_value_t& value);
1163
1164 //! Set up the fprime host interface
1165 void hostFprimeV1(spacewasm_host_t*);
1166
1167 /// FPrime Wasm Interface Host Functions
1168 spacewasm_hostcall_result_t wasmExit(struct spacewasm_caller_t* caller,
1169 const struct spacewasm_value_t* params,
1170 size_t n_params,
1171 struct spacewasm_value_t* out_result);
1172
1173 spacewasm_hostcall_result_t wasmPanic(struct spacewasm_caller_t* caller,
1174 const struct spacewasm_value_t* params,
1175 size_t n_params,
1176 struct spacewasm_value_t* out_result);
1177
1178 spacewasm_hostcall_result_t wasmArgs(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 wasmTime(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 wasmReadTelemetry(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 wasmReadParameter(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 wasmCommand(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 wasmEvent(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 wasmRsleep(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 wasmAsleep(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 wasmSerialOut(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 wasmSerialRecv(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 //! COMMAND: forward an encoded command from guest memory to the command dispatcher.
1229 void dispatchCommand();
1230
1231 //! TELEMETRY: read a telemetry channel and write its value + time into guest memory.
1232 void dispatchTelemetry();
1233
1234 //! PARAMETER: read a parameter and write it into guest memory.
1235 void dispatchParameter();
1236
1237 //! EVENT: emit a guest-requested event at the guest-requested severity.
1238 void dispatchEvent();
1239
1240 //! RSLEEP: arm a relative sleep timer.
1241 void dispatchRelativeSleep();
1242
1243 //! ASLEEP: arm an absolute sleep timer.
1244 void dispatchAbsoluteSleep();
1245
1246 //! TIME: write the current time into guest memory.
1247 void dispatchTime();
1248
1249 //! SERIAL_OUT: copy a payload out of guest memory and invoke the serial output port.
1250 void dispatchSerialOut();
1251
1252 //! SERIAL_RECV: check the serial input queue and either resume or block awaiting a message.
1253 void dispatchSerialRecv();
1254
1255 // A global static lock. This is needed to allow the global allocator in spacewasm
1256 // to not require to pass context to fine grained context to allocations.
1257 // Read more about this in the SDD.
1258 static Os::Mutex* getGlobalAllocatorLock();
1259 };
1260
1261 } // namespace Svc
1262
1263 #endif
1264