GCC Code Coverage Report


Directory: Svc/WasmSequencer/
File: WasmSequencerInterpreter.cpp
Date: 2026-09-23 21:15:03
Exec Total Coverage
Lines: 428 438 97.7%
Functions: 44 44 100.0%
Branches: 230 250 92.0%

Line Branch Exec Source
1 // ======================================================================
2 // \title WasmSequencerInterpreter.cpp
3 // \author tumbar
4 // \brief cpp file for WasmSequencer engine state machine
5 // ======================================================================
6
7 #include "Fw/Com/ComPacket.hpp"
8 #include "Fw/Types/Assert.hpp"
9 #include "Fw/Types/LinearBufferTemplate.hpp"
10 #include "Fw/Types/Serializable.hpp"
11 #include "Fw/Types/SuccessEnumAc.hpp"
12 #include "Svc/Seq/BlockStateEnumAc.hpp"
13 #include "Svc/WasmSequencer/WasmSequencer.hpp"
14 #include "Svc/WasmSequencer/WasmSequencer_HostFunctionEnumAc.hpp"
15 #include "Svc/WasmSequencer/WasmSequencer_TrapReasonEnumAc.hpp"
16 #include "config/FwAssertArgTypeAliasAc.h"
17 #include "spacewasm.h"
18
19 namespace Svc {
20
21 // ----------------------------------------------------------------------
22 // Implementations for internal state machine actions
23 // ----------------------------------------------------------------------
24
25 23 void WasmSequencer ::Svc_WasmSequencer_InterpreterStateMachine_action_cmdReplyOK(
26 SmId smId,
27 Svc_WasmSequencer_InterpreterStateMachine::Signal signal,
28 const Svc::WasmSequencer_CommandRequest& value) {
29
2/2
✓ Branch 6 taken 23 times.
✓ Branch 17 taken 23 times.
23 this->cmdResponse_out(value.get_opcode(), value.get_cmdSeq(), Fw::CmdResponse::OK);
30 23 }
31
32 235 void WasmSequencer ::Svc_WasmSequencer_InterpreterStateMachine_action_signalEntered(
33 SmId smId,
34 Svc_WasmSequencer_InterpreterStateMachine::Signal signal) {
35 235 this->interpreter_sendSignal_entered();
36 235 }
37
38 233 void WasmSequencer ::Svc_WasmSequencer_InterpreterStateMachine_action_spin(
39 SmId smId,
40 Svc_WasmSequencer_InterpreterStateMachine::Signal signal) {
41 233 FW_ASSERT(this->m_wasm);
42
43
1/1
✓ Branch 2 taken 233 times.
233 Fw::ParamValid prmValid;
44
1/1
✓ Branch 5 taken 233 times.
233 const auto fuelParam = this->paramGet_INSTRUCTION_FUEL(prmValid);
45 // Min of 1 so we don't spin the component queue forever
46
1/2
✓ Branch 0 taken 233 times.
✗ Branch 1 not taken.
233 const auto fuel = (fuelParam == 0) ? 1 : fuelParam;
47
48 233 spacewasm_trap_t trap = SPACEWASM_TRAP_NONE;
49
1/1
✓ Branch 5 taken 233 times.
233 const spacewasm_run_status_t runStatus = spacewasm_run(this->m_wasm, fuel, &trap);
50
51
4/5
✓ Branch 0 taken 69 times.
✓ Branch 1 taken 41 times.
✓ Branch 2 taken 67 times.
✓ Branch 3 taken 56 times.
✗ Branch 4 not taken.
233 switch (runStatus) {
52 69 case SPACEWASM_RUN_FINISHED: {
53 69 spacewasm_value_t result;
54
1/1
✓ Branch 5 taken 69 times.
69 auto status = spacewasm_get_result(this->m_wasm, spacewasm_valtype_t::SPACEWASM_I32, &result);
55
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 69 times.
69 if (status == SPACEWASM_ERR_NOT_FOUND) {
56 // Return status code was "void" (success)
57 ✗ this->interpreter_sendSignal_interpreterFinished(0);
58 } else {
59 69 FW_ASSERT(status == SPACEWASM_OK);
60 69 FW_ASSERT(result.tag == spacewasm_valtype_t::SPACEWASM_I32);
61
1/1
✓ Branch 5 taken 69 times.
69 this->interpreter_sendSignal_interpreterFinished(result.u.i32_);
62 }
63
64 69 break;
65 }
66 41 case SPACEWASM_RUN_TRAP:
67 // Filter out HOST traps due to exit/panic. These host functions just use trap as a mechanism
68 // to kill the interpreter.
69
8/8
✓ Branch 0 taken 27 times.
✓ Branch 1 taken 14 times.
✓ Branch 8 taken 23 times.
✓ Branch 9 taken 4 times.
✓ Branch 10 taken 2 times.
✓ Branch 11 taken 21 times.
✓ Branch 12 taken 6 times.
✓ Branch 13 taken 35 times.
64 if (trap == SPACEWASM_TRAP_HOST && (this->m_exit.reason == WasmSequencer_ExitReason::HOST_EXIT ||
70 23 this->m_exit.reason == WasmSequencer_ExitReason::HOST_PANIC)) {
71
2/2
✓ Branch 6 taken 6 times.
✓ Branch 10 taken 6 times.
6 this->interpreter_sendSignal_interpreterTrap(WasmSequencer_TrapReason::NONE);
72 } else {
73
3/3
✓ Branch 6 taken 35 times.
✓ Branch 9 taken 35 times.
✓ Branch 13 taken 35 times.
35 this->interpreter_sendSignal_interpreterTrap(WasmSequencer::mapTrapReason(trap));
74 }
75 41 break;
76 67 case SPACEWASM_RUN_PAUSE:
77
1/1
✓ Branch 5 taken 67 times.
67 this->interpreter_sendSignal_interpreterHostFunctionNeedsPause();
78 67 break;
79 56 case SPACEWASM_RUN_OUT_OF_FUEL:
80
1/1
✓ Branch 5 taken 56 times.
56 this->interpreter_sendSignal_interpreterOutOfFuel();
81 56 break;
82 ✗ default:
83 ✗ FW_ASSERT(false, runStatus);
84 ✗ break;
85 }
86 466 }
87
88 376 void WasmSequencer ::Svc_WasmSequencer_InterpreterStateMachine_action_reset(
89 SmId smId,
90 Svc_WasmSequencer_InterpreterStateMachine::Signal signal) {
91
2/2
✓ Branch 4 taken 152 times.
✓ Branch 5 taken 224 times.
376 if (this->m_wasm != nullptr) {
92 152 auto status = spacewasm_reset(this->m_wasm);
93 152 FW_ASSERT(status == SPACEWASM_OK);
94 } else {
95 224 FW_ASSERT(signal == Svc_WasmSequencer_InterpreterStateMachine::Signal::__FPRIME_INITIAL_TRANSITION);
96 }
97 376 }
98
99 153 void WasmSequencer ::Svc_WasmSequencer_InterpreterStateMachine_action_clearExitStatus(
100 SmId smId,
101 Svc_WasmSequencer_InterpreterStateMachine::Signal signal) {
102 153 this->m_exit.reason = WasmSequencer_ExitReason::UNKNOWN;
103 153 this->m_exit.lastHostFunction = WasmSequencer_HostFunction::NONE;
104 153 this->m_exit.code = 0;
105 153 this->m_exit.lastTrapReason = WasmSequencer_TrapReason::NONE;
106 153 }
107
108 69 void WasmSequencer ::Svc_WasmSequencer_InterpreterStateMachine_action_setExitReason_INTERPRETER_FINISHED(
109 SmId smId,
110 Svc_WasmSequencer_InterpreterStateMachine::Signal signal) {
111 69 this->m_exit.reason = WasmSequencer_ExitReason::INTERPRETER_FINISHED;
112 69 }
113
114 41 void WasmSequencer ::Svc_WasmSequencer_InterpreterStateMachine_action_setExitReason_INTERPRETER_TRAP(
115 SmId smId,
116 Svc_WasmSequencer_InterpreterStateMachine::Signal signal) {
117
2/2
✓ Branch 6 taken 35 times.
✓ Branch 7 taken 6 times.
41 if (this->m_exit.reason == WasmSequencer_ExitReason::UNKNOWN) {
118 35 this->m_exit.reason = WasmSequencer_ExitReason::INTERPRETER_TRAP;
119 }
120 41 }
121
122 2 void WasmSequencer ::Svc_WasmSequencer_InterpreterStateMachine_action_setExitReason_REPLY_TIMEOUT(
123 SmId smId,
124 Svc_WasmSequencer_InterpreterStateMachine::Signal signal) {
125 2 this->m_exit.reason = WasmSequencer_ExitReason::REPLY_TIMEOUT;
126 2 }
127
128 18 void WasmSequencer ::Svc_WasmSequencer_InterpreterStateMachine_action_setExitReason_HOST_FAILURE(
129 SmId smId,
130 Svc_WasmSequencer_InterpreterStateMachine::Signal signal) {
131 18 this->m_exit.reason = WasmSequencer_ExitReason::HOST_FAILURE;
132 18 }
133
134 5 void WasmSequencer ::Svc_WasmSequencer_InterpreterStateMachine_action_setExitReason_UNEXPECTED_REPLY(
135 SmId smId,
136 Svc_WasmSequencer_InterpreterStateMachine::Signal signal) {
137 5 this->m_exit.reason = WasmSequencer_ExitReason::UNEXPECTED_REPLY;
138 5 }
139
140 2 void WasmSequencer ::Svc_WasmSequencer_InterpreterStateMachine_action_setExitReason_TIMER_INCOMPARABLE(
141 SmId smId,
142 Svc_WasmSequencer_InterpreterStateMachine::Signal signal) {
143 2 this->m_exit.reason = WasmSequencer_ExitReason::TIMER_INCOMPARABLE;
144 2 }
145
146 15 void WasmSequencer ::Svc_WasmSequencer_InterpreterStateMachine_action_setExitReason_CANCEL(
147 SmId smId,
148 Svc_WasmSequencer_InterpreterStateMachine::Signal signal) {
149 15 this->m_exit.reason = WasmSequencer_ExitReason::CANCEL;
150 15 }
151
152 69 void WasmSequencer ::Svc_WasmSequencer_InterpreterStateMachine_action_setExitCode(
153 SmId smId,
154 Svc_WasmSequencer_InterpreterStateMachine::Signal signal,
155 I32 value) {
156 69 this->m_exit.code = value;
157 69 }
158
159 41 void WasmSequencer ::Svc_WasmSequencer_InterpreterStateMachine_action_setTrapReason(
160 SmId smId,
161 Svc_WasmSequencer_InterpreterStateMachine::Signal signal,
162 const Svc::WasmSequencer_TrapReason& value) {
163 41 this->m_exit.lastTrapReason = value;
164 41 }
165
166 67 void WasmSequencer ::Svc_WasmSequencer_InterpreterStateMachine_action_setLastHostFunction(
167 SmId smId,
168 Svc_WasmSequencer_InterpreterStateMachine::Signal signal) {
169 67 this->m_exit.lastHostFunction = this->m_pendingHostFunction.kind;
170 67 }
171
172 152 void WasmSequencer ::Svc_WasmSequencer_InterpreterStateMachine_action_finish(
173 SmId smId,
174 Svc_WasmSequencer_InterpreterStateMachine::Signal signal) {
175 152 this->controller_sendSignal_engineFinished(this->m_executingContext);
176 152 }
177
178 7 void WasmSequencer ::Svc_WasmSequencer_InterpreterStateMachine_action_reportPaused(
179 SmId smId,
180 Svc_WasmSequencer_InterpreterStateMachine::Signal signal) {
181 7 this->log_ACTIVITY_HI_SequencePaused();
182 7 }
183
184 159 void WasmSequencer ::Svc_WasmSequencer_InterpreterStateMachine_action_clearPause(
185 SmId smId,
186 Svc_WasmSequencer_InterpreterStateMachine::Signal signal) {
187 159 this->m_pendingPause = false;
188 159 }
189
190 67 void WasmSequencer ::Svc_WasmSequencer_InterpreterStateMachine_action_dispatchPendingHostFunction(
191 SmId smId,
192 Svc_WasmSequencer_InterpreterStateMachine::Signal signal) {
193
10/12
✗ Branch 6 not taken.
✓ Branch 7 taken 18 times.
✓ Branch 8 taken 6 times.
✓ Branch 9 taken 5 times.
✓ Branch 10 taken 11 times.
✓ Branch 11 taken 4 times.
✓ Branch 12 taken 1 times.
✓ Branch 13 taken 7 times.
✓ Branch 14 taken 2 times.
✓ Branch 15 taken 3 times.
✓ Branch 16 taken 10 times.
✗ Branch 17 not taken.
67 switch (this->m_pendingHostFunction.kind) {
194 ✗ case WasmSequencer_HostFunction::NONE:
195 // Invalid host function
196 ✗ FW_ASSERT(false);
197 ✗ break;
198 18 case WasmSequencer_HostFunction::COMMAND:
199 18 this->dispatchCommand();
200 18 break;
201 6 case WasmSequencer_HostFunction::TELEMETRY:
202 6 this->dispatchTelemetry();
203 6 break;
204 5 case WasmSequencer_HostFunction::PARAMETER:
205 5 this->dispatchParameter();
206 5 break;
207 11 case WasmSequencer_HostFunction::EVENT:
208 11 this->dispatchEvent();
209 11 break;
210 4 case WasmSequencer_HostFunction::RSLEEP:
211 4 this->dispatchRelativeSleep();
212 4 break;
213 1 case WasmSequencer_HostFunction::ASLEEP:
214 1 this->dispatchAbsoluteSleep();
215 1 break;
216 7 case WasmSequencer_HostFunction::ARGS:
217 7 this->dispatchArgs();
218 7 break;
219 2 case WasmSequencer_HostFunction::TIME:
220 2 this->dispatchTime();
221 2 break;
222 3 case WasmSequencer_HostFunction::SERIAL_OUT:
223 3 this->dispatchSerialOut();
224 3 break;
225 10 case WasmSequencer_HostFunction::SERIAL_RECV:
226 10 this->dispatchSerialRecv();
227 10 break;
228 }
229 67 }
230
231 32 Fw::Success WasmSequencer ::readGuestMemory(WasmSequencer_HostFunction::T kind, U32 addr, U8* dst, FwSizeType len) {
232 32 const spacewasm_status_t status = spacewasm_mem_read(this->m_pendingHostFunction.caller, addr, dst, len);
233
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 28 times.
32 if (status != SPACEWASM_OK) {
234
3/3
✓ Branch 6 taken 4 times.
✓ Branch 11 taken 4 times.
✓ Branch 15 taken 4 times.
4 this->log_WARNING_HI_HostFunctionInvalidPointer(kind, static_cast<WasmSequencer_Status::T>(status));
235 4 return Fw::Success::FAILURE;
236 } else {
237 28 return Fw::Success::SUCCESS;
238 }
239 }
240
241 35 Fw::Success WasmSequencer ::writeGuestMemory(WasmSequencer_HostFunction::T kind,
242 U32 addr,
243 const U8* src,
244 FwSizeType len) {
245 35 const spacewasm_status_t status = spacewasm_mem_write(this->m_pendingHostFunction.caller, addr, src, len);
246
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 27 times.
35 if (status != SPACEWASM_OK) {
247
3/3
✓ Branch 6 taken 8 times.
✓ Branch 11 taken 8 times.
✓ Branch 15 taken 8 times.
8 this->log_WARNING_HI_HostFunctionInvalidPointer(kind, static_cast<WasmSequencer_Status::T>(status));
248 8 return Fw::Success::FAILURE;
249 } else {
250 27 return Fw::Success::SUCCESS;
251 }
252 }
253
254 // ----------------------------------------------------------------------
255 // Per-host-function dispatch helpers (arms of dispatchPendingHostFunction)
256 // ----------------------------------------------------------------------
257
258 18 void WasmSequencer ::dispatchCommand() {
259
1/1
✓ Branch 2 taken 18 times.
18 Fw::ComBuffer cmd;
260
261 // Write the CMD descriptor to the ComBuffer
262
1/1
✓ Branch 2 taken 18 times.
18 auto serStatus = cmd.serializeFrom(static_cast<FwPacketDescriptorType>(Fw::ComPacketType::FW_PACKET_COMMAND));
263 18 FW_ASSERT(serStatus == Fw::FW_SERIALIZE_OK, serStatus);
264
265 // Copy the com buffer from the guest memory into our memory
266
3/3
✓ Branch 6 taken 18 times.
✓ Branch 11 taken 2 times.
✓ Branch 12 taken 16 times.
36 if (this->readGuestMemory(Svc::WasmSequencer_HostFunction::COMMAND, this->m_pendingHostFunction.u.command.ptr,
267 18 cmd.getBuffAddr() + sizeof(FwPacketDescriptorType),
268 36 this->m_pendingHostFunction.u.command.len) != Fw::Success::SUCCESS) {
269
1/1
✓ Branch 5 taken 2 times.
2 this->interpreter_sendSignal_hostResponseFailure();
270 2 return;
271 }
272
273 // Memory read succeeded, update the ComBuffer to hold the encoded command
274
1/1
✓ Branch 6 taken 16 times.
16 serStatus = cmd.moveSerToOffset(this->m_pendingHostFunction.u.command.len + sizeof(FwPacketDescriptorType));
275 16 FW_ASSERT(serStatus == Fw::FW_SERIALIZE_OK, serStatus);
276
277 // Dispatch command to CmdDisp. The command context (cmdUid)
278 // encodes the current sequence + command instance so we can
279 // reject late/stale responses in cmdResponseIn_handler.
280 16 this->m_tlm.commandsDispatched++;
281
282 // Start the host-function timeout clock: we are about to block in
283 // AWAITING_RESPONSE until the command response comes back in.
284
2/2
✓ Branch 3 taken 16 times.
✓ Branch 12 taken 16 times.
16 this->m_hostFunctionStart = this->getTime();
285 16 this->m_hasHostFunctionStart = true;
286
287
2/2
✓ Branch 8 taken 16 times.
✓ Branch 11 taken 16 times.
16 this->cmdOut_out(0, cmd, this->makeCmdUid());
288 18 }
289
290 6 void WasmSequencer ::dispatchTelemetry() {
291
1/1
✓ Branch 2 taken 6 times.
6 Fw::Time time;
292
1/1
✓ Branch 2 taken 6 times.
6 Fw::TlmBuffer tlmBuffer;
293
294
1/1
✓ Branch 7 taken 6 times.
6 auto valid = this->getTlmChan_out(0, this->m_pendingHostFunction.u.telemetry.chanId, time, tlmBuffer);
295
296 // Write the response into guest memory
297 6 FW_ASSERT(this->m_pendingHostFunction.u.telemetry.timeLen == Fw::Time::SERIALIZED_SIZE,
298 static_cast<FwAssertArgType>(this->m_pendingHostFunction.u.telemetry.timeLen), Fw::Time::SERIALIZED_SIZE);
299
1/1
✓ Branch 2 taken 6 times.
6 Fw::LinearBufferTemplate<Fw::Time::SERIALIZED_SIZE> timeBuf;
300
301
1/1
✓ Branch 2 taken 6 times.
6 auto serStatus = time.serializeTo(timeBuf);
302 6 FW_ASSERT(serStatus == Fw::FW_SERIALIZE_OK, serStatus);
303
304 // Write the time
305
3/3
✓ Branch 3 taken 6 times.
✓ Branch 8 taken 1 times.
✓ Branch 9 taken 5 times.
12 if (this->writeGuestMemory(Svc::WasmSequencer_HostFunction::TELEMETRY,
306 6 this->m_pendingHostFunction.u.telemetry.timePtr, timeBuf.getBuffAddr(),
307 12 this->m_pendingHostFunction.u.telemetry.timeLen) != Fw::Success::SUCCESS) {
308
1/1
✓ Branch 5 taken 1 times.
1 this->interpreter_sendSignal_hostResponseFailure();
309 1 return;
310 }
311
312
3/3
✓ Branch 2 taken 5 times.
✓ Branch 8 taken 1 times.
✓ Branch 9 taken 4 times.
5 if (tlmBuffer.getSize() > this->m_pendingHostFunction.u.telemetry.valueLen) {
313
2/2
✓ Branch 8 taken 1 times.
✓ Branch 12 taken 1 times.
2 this->log_WARNING_HI_BufferTooSmall(WasmSequencer_HostFunction::TELEMETRY,
314 1 this->m_pendingHostFunction.u.telemetry.valueLen,
315
1/1
✓ Branch 2 taken 1 times.
1 static_cast<U32>(tlmBuffer.getSize()));
316
1/1
✓ Branch 5 taken 1 times.
1 this->interpreter_sendSignal_hostResponseFailure();
317 1 return;
318 }
319
320 // Write the value
321
4/4
✓ Branch 1 taken 4 times.
✓ Branch 6 taken 4 times.
✓ Branch 11 taken 1 times.
✓ Branch 12 taken 3 times.
12 if (this->writeGuestMemory(Svc::WasmSequencer_HostFunction::TELEMETRY,
322 4 this->m_pendingHostFunction.u.telemetry.valuePtr, tlmBuffer.getBuffAddr(),
323 8 tlmBuffer.getSize()) != Fw::Success::SUCCESS) {
324
1/1
✓ Branch 5 taken 1 times.
1 this->interpreter_sendSignal_hostResponseFailure();
325 1 return;
326 }
327
328
2/3
✗ Branch 6 not taken.
✓ Branch 7 taken 3 times.
✓ Branch 9 taken 3 times.
3 this->interpreter_sendSignal_hostResumeI32(static_cast<I32>(valid.e));
329 15 }
330
331 5 void WasmSequencer ::dispatchParameter() {
332
1/1
✓ Branch 2 taken 5 times.
5 Fw::ParamBuffer prmBuf;
333
1/1
✓ Branch 7 taken 5 times.
5 auto prmStatus = this->getParam_out(0, this->m_pendingHostFunction.u.parameter.prmId, prmBuf);
334
335
3/3
✓ Branch 2 taken 5 times.
✓ Branch 8 taken 1 times.
✓ Branch 9 taken 4 times.
5 if (prmBuf.getSize() > this->m_pendingHostFunction.u.parameter.len) {
336
2/2
✓ Branch 8 taken 1 times.
✓ Branch 12 taken 1 times.
2 this->log_WARNING_HI_BufferTooSmall(WasmSequencer_HostFunction::PARAMETER,
337 1 this->m_pendingHostFunction.u.parameter.len,
338
1/1
✓ Branch 2 taken 1 times.
1 static_cast<U32>(prmBuf.getSize()));
339
1/1
✓ Branch 5 taken 1 times.
1 this->interpreter_sendSignal_hostResponseFailure();
340 1 return;
341 }
342
343 // Write the parameter to linear memory
344
4/4
✓ Branch 1 taken 4 times.
✓ Branch 8 taken 4 times.
✓ Branch 13 taken 1 times.
✓ Branch 14 taken 3 times.
12 if (this->writeGuestMemory(Svc::WasmSequencer_HostFunction::PARAMETER, this->m_pendingHostFunction.u.parameter.ptr,
345 12 prmBuf.getBuffAddr(), prmBuf.getSize()) != Fw::Success::SUCCESS) {
346
1/1
✓ Branch 5 taken 1 times.
1 this->interpreter_sendSignal_hostResponseFailure();
347 1 return;
348 }
349
350
2/3
✗ Branch 6 not taken.
✓ Branch 7 taken 3 times.
✓ Branch 9 taken 3 times.
3 this->interpreter_sendSignal_hostResumeI32(static_cast<I32>(prmStatus.e));
351 7 }
352
353 11 void WasmSequencer ::dispatchEvent() {
354 11 U8 stringStorage[FW_LOG_STRING_MAX_SIZE + 1];
355 11 FW_ASSERT(this->m_pendingHostFunction.u.event.msgLen <= FW_LOG_STRING_MAX_SIZE,
356 static_cast<FwAssertArgType>(this->m_pendingHostFunction.u.event.msgLen), FW_LOG_STRING_MAX_SIZE);
357
1/1
✓ Branch 2 taken 11 times.
11 const Fw::ExternalString msg(reinterpret_cast<char*>(stringStorage), FW_LOG_STRING_MAX_SIZE + 1);
358
359
3/3
✓ Branch 4 taken 11 times.
✓ Branch 9 taken 1 times.
✓ Branch 10 taken 10 times.
22 if (this->readGuestMemory(Svc::WasmSequencer_HostFunction::EVENT, this->m_pendingHostFunction.u.event.msgPtr,
360 22 stringStorage, this->m_pendingHostFunction.u.event.msgLen) != Fw::Success::SUCCESS) {
361
1/1
✓ Branch 5 taken 1 times.
1 this->interpreter_sendSignal_hostResponseFailure();
362 1 return;
363 }
364 10 stringStorage[this->m_pendingHostFunction.u.event.msgLen] = 0;
365
366 // Emit the event at the guest-requested severity. FATAL and
367 // COMMAND are forbidden for guest programs (FATAL would let
368 // untrusted code trigger the FatalHandler; COMMAND is reserved
369 // for the command dispatcher). A forbidden or out-of-range
370 // severity is reported via HostFunctionInvalidSeverity, carrying
371 // the raw id and the guest message, and the guest continues.
372 10 const I32 rawSeverity = static_cast<I32>(this->m_pendingHostFunction.u.event.rawSeverity);
373
6/6
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 1 times.
✓ Branch 4 taken 1 times.
✓ Branch 5 taken 3 times.
10 switch (static_cast<Fw::LogSeverity::T>(rawSeverity)) {
374 1 case Fw::LogSeverity::WARNING_HI:
375
1/1
✓ Branch 5 taken 1 times.
1 this->log_WARNING_HI_LogWarningHi(msg);
376 1 break;
377 1 case Fw::LogSeverity::WARNING_LO:
378
1/1
✓ Branch 5 taken 1 times.
1 this->log_WARNING_LO_LogWarningLo(msg);
379 1 break;
380 3 case Fw::LogSeverity::ACTIVITY_HI:
381
1/1
✓ Branch 5 taken 3 times.
3 this->log_ACTIVITY_HI_LogActivityHi(msg);
382 3 break;
383 1 case Fw::LogSeverity::ACTIVITY_LO:
384
1/1
✓ Branch 5 taken 1 times.
1 this->log_ACTIVITY_LO_LogActivityLo(msg);
385 1 break;
386 1 case Fw::LogSeverity::DIAGNOSTIC:
387
1/1
✓ Branch 5 taken 1 times.
1 this->log_DIAGNOSTIC_LogDiagnostic(msg);
388 1 break;
389 3 case Fw::LogSeverity::FATAL: // fallthrough to catch restricted severities
390 case Fw::LogSeverity::COMMAND:
391 default:
392
1/1
✓ Branch 5 taken 3 times.
3 this->log_WARNING_HI_HostFunctionInvalidSeverity(rawSeverity, msg);
393 3 break;
394 }
395
396
1/1
✓ Branch 5 taken 10 times.
10 this->interpreter_sendSignal_hostResume();
397 11 }
398
399 4 void WasmSequencer ::dispatchRelativeSleep() {
400 4 const U32 seconds = static_cast<U32>(this->m_pendingHostFunction.u.rsleep.us / 1000000);
401 4 const U32 useconds = static_cast<U32>(this->m_pendingHostFunction.u.rsleep.us % 1000000);
402
403
1/1
✓ Branch 3 taken 4 times.
4 const Fw::Time now = this->getTime();
404 const U64 deadlineSeconds =
405
2/2
✓ Branch 2 taken 4 times.
✓ Branch 6 taken 4 times.
4 static_cast<U64>(now.getSeconds()) + seconds + (static_cast<U64>(now.getUSeconds()) + useconds) / 1000000u;
406
407
1/1
✓ Branch 2 taken 4 times.
4 Fw::Time timer = now;
408
2/2
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 3 times.
4 if (deadlineSeconds > static_cast<U64>(std::numeric_limits<U32>::max())) {
409
1/1
✓ Branch 3 taken 1 times.
1 timer.set(std::numeric_limits<U32>::max(), 999999u);
410 } else {
411
1/1
✓ Branch 2 taken 3 times.
3 timer.add(seconds, useconds);
412 }
413
414
1/1
✓ Branch 6 taken 4 times.
4 this->m_pendingTimer = timer;
415 4 this->m_hasPendingTimer = true;
416 8 }
417
418 1 void WasmSequencer ::dispatchAbsoluteSleep() {
419 1 U32 seconds = static_cast<U32>(this->m_pendingHostFunction.u.asleep.us / 1000000);
420 1 U32 useconds = static_cast<U32>(this->m_pendingHostFunction.u.asleep.us % 1000000);
421
422 // Absolute is relative to epoch, we still need to get the time for base/context
423
1/1
✓ Branch 3 taken 1 times.
1 Fw::Time timer = this->getTime();
424
1/1
✓ Branch 2 taken 1 times.
1 timer.set(seconds, useconds);
425
426
1/1
✓ Branch 6 taken 1 times.
1 this->m_pendingTimer = timer;
427 1 this->m_hasPendingTimer = true;
428 2 }
429
430 7 void WasmSequencer ::dispatchArgs() {
431 7 const FwSizeType argCapacity = static_cast<FwSizeType>(sizeof(this->m_args.get_buffer()));
432
2/2
✓ Branch 6 taken 1 times.
✓ Branch 7 taken 6 times.
7 if (this->m_args.get_size() > argCapacity) {
433
2/2
✓ Branch 12 taken 1 times.
✓ Branch 16 taken 1 times.
1 this->log_WARNING_HI_BufferTooLarge(WasmSequencer_HostFunction::ARGS, static_cast<U32>(this->m_args.get_size()),
434 static_cast<U32>(argCapacity));
435 1 this->interpreter_sendSignal_hostResponseFailure();
436 1 return;
437 }
438
439
2/2
✓ Branch 10 taken 1 times.
✓ Branch 11 taken 5 times.
6 if (this->m_args.get_size() > this->m_pendingHostFunction.u.args.len) {
440 // Too many param bytes and we are going to leak data into the guest memory
441
2/2
✓ Branch 10 taken 1 times.
✓ Branch 14 taken 1 times.
2 this->log_WARNING_HI_BufferTooSmall(WasmSequencer_HostFunction::ARGS, this->m_pendingHostFunction.u.args.len,
442 1 static_cast<U32>(this->m_args.get_size()));
443 1 this->interpreter_sendSignal_hostResponseFailure();
444 1 return;
445 }
446
447 // Write the arguments to linear memory
448
3/3
✓ Branch 6 taken 5 times.
✓ Branch 11 taken 1 times.
✓ Branch 12 taken 4 times.
15 if (this->writeGuestMemory(Svc::WasmSequencer_HostFunction::ARGS, this->m_pendingHostFunction.u.args.ptr,
449 15 this->m_args.get_buffer(), this->m_args.get_size()) != Fw::Success::SUCCESS) {
450 1 this->interpreter_sendSignal_hostResponseFailure();
451 1 return;
452 }
453
454 4 this->interpreter_sendSignal_hostResumeI32(static_cast<I32>(this->m_args.get_size()));
455 }
456
457 2 void WasmSequencer ::dispatchTime() {
458
1/1
✓ Branch 3 taken 2 times.
2 auto time = this->getTime();
459
460 2 FW_ASSERT(this->m_pendingHostFunction.u.time.len == Fw::Time::SERIALIZED_SIZE,
461 static_cast<FwAssertArgType>(this->m_pendingHostFunction.u.time.len), Fw::Time::SERIALIZED_SIZE);
462
1/1
✓ Branch 2 taken 2 times.
2 Fw::LinearBufferTemplate<Fw::Time::SERIALIZED_SIZE> timeBuf;
463
464
1/1
✓ Branch 2 taken 2 times.
2 auto serStatus = time.serializeTo(timeBuf);
465 2 FW_ASSERT(serStatus == Fw::FW_SERIALIZE_OK, serStatus);
466
467 // Write the time
468
3/3
✓ Branch 5 taken 2 times.
✓ Branch 10 taken 1 times.
✓ Branch 11 taken 1 times.
4 if (this->writeGuestMemory(Svc::WasmSequencer_HostFunction::TIME, this->m_pendingHostFunction.u.time.ptr,
469 4 timeBuf.getBuffAddr(), this->m_pendingHostFunction.u.time.len) != Fw::Success::SUCCESS) {
470
1/1
✓ Branch 5 taken 1 times.
1 this->interpreter_sendSignal_hostResponseFailure();
471 1 return;
472 }
473
474
1/1
✓ Branch 5 taken 1 times.
1 this->interpreter_sendSignal_hostResume();
475 3 }
476
477 3 void WasmSequencer ::dispatchSerialOut() {
478 3 const FwIndexType portNum = static_cast<FwIndexType>(this->m_pendingHostFunction.u.serialOut.index);
479
480 // Copy the payload out of guest memory into our own buffer
481
3/3
✓ Branch 6 taken 3 times.
✓ Branch 11 taken 1 times.
✓ Branch 12 taken 2 times.
6 if (this->readGuestMemory(Svc::WasmSequencer_HostFunction::SERIAL_OUT, this->m_pendingHostFunction.u.serialOut.ptr,
482 3 this->m_serialOutBuffer.getBuffAddr(),
483 6 this->m_pendingHostFunction.u.serialOut.len) != Fw::Success::SUCCESS) {
484 1 this->interpreter_sendSignal_hostResponseFailure();
485 1 return;
486 }
487
488 2 auto serStatus = this->m_serialOutBuffer.setBuffLen(this->m_pendingHostFunction.u.serialOut.len);
489 2 FW_ASSERT(serStatus == Fw::FW_SERIALIZE_OK, serStatus);
490
491 // Invoke the serial output port.
492 2 serStatus = this->serialOut_out(portNum, this->m_serialOutBuffer);
493
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
2 if (serStatus != Fw::FW_SERIALIZE_OK) {
494
2/2
✓ Branch 6 taken 1 times.
✓ Branch 10 taken 1 times.
1 this->log_WARNING_HI_SerialPortSendFailed(Svc::WasmSequencer_HostFunction::SERIAL_OUT,
495 static_cast<I32>(serStatus));
496 1 this->interpreter_sendSignal_hostResponseFailure();
497 1 return;
498 }
499
500 // Send worked, wake up the interpreter
501 1 this->interpreter_sendSignal_hostResume();
502 }
503
504 10 void WasmSequencer ::dispatchSerialRecv() {
505 10 const FwIndexType portNum = static_cast<FwIndexType>(this->m_pendingHostFunction.u.serialRecv.index);
506 10 FW_ASSERT(portNum < NUM_SERIALIN_INPUT_PORTS, portNum);
507
1/1
✓ Branch 5 taken 10 times.
10 Os::ScopeLock scopeLock(this->m_serialInMutex);
508 10 auto& queue = this->m_serialInQueue[portNum];
509
510 // Check if there is an available message on the queue
511
3/3
✓ Branch 2 taken 10 times.
✓ Branch 4 taken 7 times.
✓ Branch 5 taken 3 times.
10 if (queue.get_allocated_size() > 0) {
512 // There is data available signal to the state machine to pull this data and wake up without blocking
513
1/1
✓ Branch 5 taken 7 times.
7 this->interpreter_sendSignal_serialInMessage(portNum);
514 } else {
515 // Check if we should block or not
516
3/5
✗ Branch 3 not taken.
✓ Branch 4 taken 3 times.
✓ Branch 5 taken 2 times.
✓ Branch 6 taken 1 times.
✗ Branch 7 not taken.
3 switch (this->m_pendingHostFunction.u.serialRecv.blockingType) {
517 2 case Svc::BlockState::BLOCK:
518 // Do not immediately resume the interpreter, this will let the state machine asynchronously
519 // wait for a signal that we got a message (or timeout).
520
2/2
✓ Branch 3 taken 2 times.
✓ Branch 12 taken 2 times.
2 this->m_hostFunctionStart = this->getTime();
521 2 this->m_hasHostFunctionStart = true;
522 2 break;
523 1 case Svc::BlockState::NO_BLOCK:
524 // We are non-blocking and the queue is empty, report this back to the interpreter and wake back
525 // up
526 1 constexpr I32 FPRIME_SERIAL_RECV_QUEUE_STATUS_EMPTY = 1;
527
1/1
✓ Branch 5 taken 1 times.
1 this->interpreter_sendSignal_hostResumeI32(FPRIME_SERIAL_RECV_QUEUE_STATUS_EMPTY);
528 1 break;
529 }
530 }
531 20 }
532
533 218 void WasmSequencer ::Svc_WasmSequencer_InterpreterStateMachine_action_clearPendingHostFunction(
534 SmId smId,
535 Svc_WasmSequencer_InterpreterStateMachine::Signal signal) {
536 218 this->m_pendingHostFunction.kind = WasmSequencer_HostFunction::NONE;
537 218 this->m_pendingHostFunction.caller = nullptr;
538 218 this->m_hasPendingTimer = false;
539 218 this->m_hasHostFunctionStart = false;
540 218 }
541
542 153 void WasmSequencer ::Svc_WasmSequencer_InterpreterStateMachine_action_setContext(
543 SmId smId,
544 Svc_WasmSequencer_InterpreterStateMachine::Signal signal,
545 const Svc::WasmSequencer_RequestContext& value) {
546 153 FW_ASSERT(!this->m_hasExecutingContext);
547 153 this->m_hasExecutingContext = true;
548 153 this->m_executingContext = value;
549
550 // A fresh execution window is starting. Bump the sequence counter so any command
551 // dispatched from this program carries a distinct cmdUid
552 153 this->m_sequencesStarted++;
553 153 }
554
555 376 void WasmSequencer ::Svc_WasmSequencer_InterpreterStateMachine_action_clearContext(
556 SmId smId,
557 Svc_WasmSequencer_InterpreterStateMachine::Signal signal) {
558 376 this->m_hasExecutingContext = false;
559 376 }
560
561 14 void WasmSequencer ::Svc_WasmSequencer_InterpreterStateMachine_action_resume(
562 SmId smId,
563 Svc_WasmSequencer_InterpreterStateMachine::Signal signal) {
564 14 FW_ASSERT(this->m_wasm != nullptr);
565 14 auto status = spacewasm_resume(this->m_wasm);
566 14 FW_ASSERT(status == SPACEWASM_OK, status);
567 14 }
568
569 21 void WasmSequencer ::Svc_WasmSequencer_InterpreterStateMachine_action_resumeI32(
570 SmId smId,
571 Svc_WasmSequencer_InterpreterStateMachine::Signal signal,
572 I32 value) {
573 21 FW_ASSERT(this->m_wasm != nullptr);
574 21 spacewasm_value_t return_val;
575 21 return_val.tag = SPACEWASM_I32;
576 21 return_val.u.i32_ = value;
577
578
1/1
✓ Branch 5 taken 21 times.
21 auto status = spacewasm_resume_value(this->m_wasm, return_val);
579 21 FW_ASSERT(status == SPACEWASM_OK, status);
580 21 }
581
582 5 void WasmSequencer ::Svc_WasmSequencer_InterpreterStateMachine_action_checkSleepTimers(
583 SmId smId,
584 Svc_WasmSequencer_InterpreterStateMachine::Signal signal) {
585 // Check if we have overrun the timer
586 5 FW_ASSERT(this->m_hasPendingTimer);
587
588
1/1
✓ Branch 3 taken 5 times.
5 const Fw::Time now = this->getTime();
589
4/5
✓ Branch 5 taken 5 times.
✓ Branch 14 taken 2 times.
✓ Branch 15 taken 2 times.
✓ Branch 16 taken 1 times.
✗ Branch 17 not taken.
5 switch (Fw::Time::compare(now, this->m_pendingTimer)) {
590 2 case Fw::TimeComparison::LT:
591 // No timer overrun
592 2 break;
593 2 case Fw::TimeComparison::EQ:
594 case Fw::TimeComparison::GT: {
595 // Timeout!
596
1/1
✓ Branch 5 taken 2 times.
2 this->interpreter_sendSignal_hostResume();
597 2 break;
598 }
599 1 case Fw::TimeComparison::INCOMPARABLE:
600 // Time base / context changed since we set the timer
601
1/1
✓ Branch 5 taken 1 times.
1 this->interpreter_sendSignal_hostResponseTimeIncomparable();
602 1 break;
603 }
604 10 }
605
606 6 void WasmSequencer ::Svc_WasmSequencer_InterpreterStateMachine_action_checkTimeout(
607 SmId smId,
608 Svc_WasmSequencer_InterpreterStateMachine::Signal signal) {
609 // Only blocking host functions that await an external event are subject to the
610 // host-function timeout (COMMAND -> cmdResponseIn, blocking SERIAL_RECV -> serialIn).
611 // Sleeps have their own wake timer (checkSleepTimers), separate from this timeout.
612
2/4
✗ Branch 3 not taken.
✓ Branch 4 taken 6 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 6 times.
6 if (!this->m_hasHostFunctionStart) {
613 ✗ return;
614 }
615
616
1/1
✓ Branch 2 taken 6 times.
6 Fw::ParamValid prmValid;
617
1/1
✓ Branch 5 taken 6 times.
6 const F32 timeoutSecs = this->paramGet_HOST_FUNCTION_TIMEOUT_SECS(prmValid);
618
619 // A non-positive or out-of-range timeout disables the check entirely.
620
5/6
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 5 times.
✓ Branch 5 taken 1 times.
✓ Branch 6 taken 5 times.
6 if (timeoutSecs <= 0.0f || timeoutSecs >= static_cast<F32>(std::numeric_limits<U32>::max())) {
621 1 return;
622 }
623
624 // Deadline = function start + timeout. Round microseconds up so the timeout
625 // is never reported early.
626 5 U32 seconds = static_cast<U32>(timeoutSecs);
627 5 U32 useconds = static_cast<U32>((timeoutSecs - static_cast<F32>(seconds)) * 1000000.0f + 0.5f);
628
629 // Rounding up can push the microsecond field to 1000000; carry it into
630 // seconds so Fw::Time::add() always receives a normalized (< 1e6) value.
631
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
5 if (useconds >= 1000000u) {
632 ✗ seconds += useconds / 1000000u;
633 ✗ useconds %= 1000000u;
634 }
635
636
1/1
✓ Branch 5 taken 5 times.
5 Fw::Time deadline = this->m_hostFunctionStart;
637
1/1
✓ Branch 2 taken 5 times.
5 deadline.add(seconds, useconds);
638
639
1/1
✓ Branch 3 taken 5 times.
5 const Fw::Time now = this->getTime();
640
4/5
✓ Branch 2 taken 5 times.
✓ Branch 11 taken 2 times.
✓ Branch 12 taken 2 times.
✓ Branch 13 taken 1 times.
✗ Branch 14 not taken.
5 switch (Fw::Time::compare(now, deadline)) {
641 2 case Fw::TimeComparison::LT:
642 // Deadline not yet reached.
643 2 break;
644 2 case Fw::TimeComparison::EQ:
645 case Fw::TimeComparison::GT:
646 // Host function timed out waiting for its reply.
647
1/1
✓ Branch 5 taken 2 times.
2 this->interpreter_sendSignal_hostResponseTimeout();
648 2 break;
649 1 case Fw::TimeComparison::INCOMPARABLE:
650 // Time base / context changed since the host function started.
651
1/1
✓ Branch 5 taken 1 times.
1 this->interpreter_sendSignal_hostResponseTimeIncomparable();
652 1 break;
653 }
654 6 }
655
656 8 void WasmSequencer ::Svc_WasmSequencer_InterpreterStateMachine_action_dequeueSerialAndResume(
657 SmId smId,
658 Svc_WasmSequencer_InterpreterStateMachine::Signal signal,
659 const FwIndexType& value) {
660 8 const FwIndexType portNum = static_cast<FwIndexType>(this->m_pendingHostFunction.u.serialRecv.index);
661 8 FW_ASSERT(portNum < NUM_SERIALIN_INPUT_PORTS, portNum);
662
1/1
✓ Branch 5 taken 8 times.
8 Os::ScopeLock scopeLock(this->m_serialInMutex);
663 8 auto& queue = this->m_serialInQueue[portNum];
664
665 8 this->m_dequeueSucceeded = false;
666
667 // Message is available, pull out the size
668 8 U32 msgSize;
669
1/1
✓ Branch 2 taken 8 times.
8 auto status = queue.peek(msgSize);
670 8 FW_ASSERT(status == Fw::FW_SERIALIZE_OK, status);
671
672
2/2
✓ Branch 4 taken 1 times.
✓ Branch 5 taken 7 times.
8 if (msgSize > this->m_pendingHostFunction.u.serialRecv.dataSize) {
673
2/2
✓ Branch 8 taken 1 times.
✓ Branch 12 taken 1 times.
2 this->log_WARNING_HI_BufferTooSmall(Svc::WasmSequencer_HostFunction::SERIAL_RECV,
674 1 this->m_pendingHostFunction.u.serialRecv.dataSize, msgSize);
675 // The frame doesn't fit in the guest's buffer and never will; drop it from the queue
676 // so it doesn't poison every subsequent serial_recv call on this port.
677
1/1
✓ Branch 2 taken 1 times.
1 status = queue.rotate(static_cast<U32>(sizeof(U32)) + msgSize);
678 1 FW_ASSERT(status == Fw::FW_SERIALIZE_OK, status);
679 1 return;
680 }
681
682 // The queue holds [U32 size][payload]; skip the size prefix when copying the payload.
683 7 const U32 queuePayloadStart = sizeof(U32);
684 7 const U32 dataSize = static_cast<U32>(sizeof(U32)) + msgSize;
685
686 // Write the message size in little endian to the guest memory
687
1/1
✓ Branch 2 taken 7 times.
7 Fw::LinearBufferTemplate<sizeof(U32)> msgSizeSer;
688
1/1
✓ Branch 2 taken 7 times.
7 status = msgSizeSer.serializeFrom(msgSize, Fw::Endianness::LITTLE);
689 7 FW_ASSERT(status == Fw::FW_SERIALIZE_OK, status);
690
691
3/3
✓ Branch 3 taken 7 times.
✓ Branch 8 taken 1 times.
✓ Branch 9 taken 6 times.
14 if (this->writeGuestMemory(Svc::WasmSequencer_HostFunction::SERIAL_RECV,
692 7 this->m_pendingHostFunction.u.serialRecv.actualSizePtr, msgSizeSer.getBuffAddr(),
693 14 sizeof(U32)) != Fw::Success::SUCCESS) {
694 1 return;
695 }
696
697 // Pull the message off the queue, we may need to do it in multiple chunks
698 6 constexpr U32 CHUNK_SIZE = 32;
699 6 U8 scratch[CHUNK_SIZE];
700
701 // Pull all the full chunks off the queue
702 6 U32 queueOffset = queuePayloadStart;
703
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 5 times.
8 for (; (queueOffset + CHUNK_SIZE) <= dataSize; queueOffset += CHUNK_SIZE) {
704
1/1
✓ Branch 2 taken 3 times.
3 status = queue.peek(scratch, CHUNK_SIZE, queueOffset);
705 3 FW_ASSERT(status == Fw::FW_SERIALIZE_OK, status);
706
707 // Copy the data into the guest memory
708
2/2
✓ Branch 3 taken 1 times.
✓ Branch 4 taken 2 times.
3 if (this->writeGuestMemory(Svc::WasmSequencer_HostFunction::SERIAL_RECV,
709
1/1
✓ Branch 5 taken 3 times.
3 this->m_pendingHostFunction.u.serialRecv.dataPtr + (queueOffset - queuePayloadStart),
710 6 scratch, CHUNK_SIZE) != Fw::Success::SUCCESS) {
711 1 return;
712 }
713 }
714
715 // Pull out the final partial chunk
716
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 1 times.
5 if (queueOffset < dataSize) {
717 4 const U32 remaining = dataSize - queueOffset;
718 4 FW_ASSERT(remaining < CHUNK_SIZE, static_cast<FwAssertArgType>(dataSize),
719 static_cast<FwAssertArgType>(queueOffset), CHUNK_SIZE);
720
721
1/1
✓ Branch 2 taken 4 times.
4 status = queue.peek(scratch, remaining, queueOffset);
722 4 FW_ASSERT(status == Fw::FW_SERIALIZE_OK, status);
723
724 // Copy the data into the guest memory
725
2/2
✓ Branch 3 taken 1 times.
✓ Branch 4 taken 3 times.
4 if (this->writeGuestMemory(Svc::WasmSequencer_HostFunction::SERIAL_RECV,
726
1/1
✓ Branch 5 taken 4 times.
4 this->m_pendingHostFunction.u.serialRecv.dataPtr + (queueOffset - queuePayloadStart),
727 8 scratch, remaining) != Fw::Success::SUCCESS) {
728 1 return;
729 }
730 }
731
732 // Dequeue the message now that we fully copied it into guest memory
733
1/1
✓ Branch 2 taken 4 times.
4 status = queue.rotate(dataSize);
734 4 FW_ASSERT(status == Fw::FW_SERIALIZE_OK);
735
736 4 this->m_dequeueSucceeded = true;
737
738 // Yay, we successfully dequeued a message from the queue, wake up the interpreter to tell it about our success
739 4 constexpr I32 FPRIME_SERIAL_RECV_QUEUE_STATUS_OK = 0;
740 4 spacewasm_value_t return_val;
741 4 return_val.tag = SPACEWASM_I32;
742 4 return_val.u.i32_ = FPRIME_SERIAL_RECV_QUEUE_STATUS_OK;
743
744
1/1
✓ Branch 5 taken 4 times.
4 auto resumeStatus = spacewasm_resume_value(this->m_wasm, return_val);
745 4 FW_ASSERT(resumeStatus == SPACEWASM_OK, resumeStatus);
746 11 }
747
748 // ----------------------------------------------------------------------
749 // Implementations for internal state machine guards
750 // ----------------------------------------------------------------------
751
752 306 bool WasmSequencer ::Svc_WasmSequencer_InterpreterStateMachine_guard_pendingPause(
753 SmId smId,
754 Svc_WasmSequencer_InterpreterStateMachine::Signal signal) const {
755
1/2
✗ Branch 3 not taken.
✓ Branch 4 taken 306 times.
306 return this->m_pendingPause;
756 }
757
758 3 bool WasmSequencer ::Svc_WasmSequencer_InterpreterStateMachine_guard_pendingHostFunction(
759 SmId smId,
760 Svc_WasmSequencer_InterpreterStateMachine::Signal signal) const {
761 3 return this->m_pendingHostFunction.isPending();
762 }
763
764 67 bool WasmSequencer ::Svc_WasmSequencer_InterpreterStateMachine_guard_pendingHostFunctionIsSleep(
765 SmId smId,
766 Svc_WasmSequencer_InterpreterStateMachine::Signal signal) const {
767
4/4
✓ Branch 11 taken 66 times.
✓ Branch 12 taken 1 times.
✓ Branch 13 taken 4 times.
✓ Branch 14 taken 62 times.
133 return this->m_pendingHostFunction.kind == WasmSequencer_HostFunction::ASLEEP ||
768 133 this->m_pendingHostFunction.kind == WasmSequencer_HostFunction::RSLEEP;
769 }
770
771 8 bool WasmSequencer ::Svc_WasmSequencer_InterpreterStateMachine_guard_blockingSerialIn(
772 SmId smId,
773 Svc_WasmSequencer_InterpreterStateMachine::Signal signal,
774 const FwIndexType& value) const {
775
1/2
✓ Branch 11 taken 8 times.
✗ Branch 12 not taken.
16 return (this->m_pendingHostFunction.kind == Svc::WasmSequencer_HostFunction::SERIAL_RECV &&
776
1/2
✓ Branch 5 taken 8 times.
✗ Branch 6 not taken.
16 this->m_pendingHostFunction.u.serialRecv.index == static_cast<U32>(value));
777 }
778
779 8 bool WasmSequencer ::Svc_WasmSequencer_InterpreterStateMachine_guard_dequeueSucceeded(
780 SmId smId,
781 Svc_WasmSequencer_InterpreterStateMachine::Signal signal) const {
782
1/2
✗ Branch 3 not taken.
✓ Branch 4 taken 8 times.
8 return this->m_dequeueSucceeded;
783 }
784
785 } // namespace Svc
786