GCC Code Coverage Report


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