Tidy simulation_exit
Wrap the cross-call, which can fail, in a noreturn void wrapper that
can't. Tweak callers appropriately. Have the scheduler internally use
the platform layer everywhere.
diff --git a/sdk/core/scheduler/main.cc b/sdk/core/scheduler/main.cc
index d4d36a8..132103b 100644
--- a/sdk/core/scheduler/main.cc
+++ b/sdk/core/scheduler/main.cc
@@ -31,9 +31,10 @@
/**
* Exit simulation, reporting the error code given as the argument.
*/
-void simulation_exit(uint32_t code)
+int scheduler_simulation_exit(uint32_t code)
{
platform_simulation_exit(code);
+ return -EPROTO;
}
#endif
@@ -228,8 +229,10 @@
static_cast<uint32_t>(capcause),
badcap);
+#ifdef SIMULATION
// If we're in simulation, exit here
- simulation_exit(1);
+ platform_simulation_exit(1);
+#endif
for (;;)
{
@@ -300,9 +303,11 @@
// Make the current thread non-runnable.
if (Thread::exit())
{
+#ifdef SIMULATION
// If we have no threads left (not counting the idle
// thread), exit.
- simulation_exit(0);
+ platform_simulation_exit(0);
+#endif
}
// We cannot continue exiting this thread, make sure we will
// pick a new one.
diff --git a/sdk/include/fail-simulator-on-error.h b/sdk/include/fail-simulator-on-error.h
index cad8bd7..1c656aa 100644
--- a/sdk/include/fail-simulator-on-error.h
+++ b/sdk/include/fail-simulator-on-error.h
@@ -67,11 +67,14 @@
DebugErrorHandler::log("Unhandled error {} at {}", mcause, frame->pcc);
}
- simulation_exit(1);
+#ifdef SIMULATION
/*
- * simulation_exit may fail (say, we're not on a simulator or there isn't
+ * simulation exit may fail (say, we're not on a simulator or there isn't
* enough stack space to invoke the function. In that case, just fall back
* to forcibly unwinding.
*/
+ (void)scheduler_simulation_exit(1);
+#endif
+
return ErrorRecoveryBehaviour::ForceUnwind;
}
diff --git a/sdk/include/simulator.h b/sdk/include/simulator.h
index 9de4a77..2d4733b 100644
--- a/sdk/include/simulator.h
+++ b/sdk/include/simulator.h
@@ -3,14 +3,34 @@
#pragma once
#include <compartment.h>
+#include <errno.h>
#include <stdint.h>
#ifdef SIMULATION
/**
* Exit simulation, reporting the error code given as the argument.
*/
-[[cheri::interrupt_state(disabled)]] void __cheri_compartment("sched")
- simulation_exit(uint32_t code = 0);
-#else
-static inline void simulation_exit(uint32_t code){};
+[[cheri::interrupt_state(disabled)]] int __cheri_compartment("sched")
+ scheduler_simulation_exit(uint32_t code __if_cxx(= 0));
#endif
+
+/**
+ * Exit the simulation, if we can, or fall back to an infinite loop.
+ */
+static inline void __attribute__((noreturn))
+simulation_exit(uint32_t code __if_cxx(= 0))
+{
+#ifdef SIMULATION
+ /*
+ * This fails only if either we are out of (trusted) stack space for the
+ * cross-call or the platform is misconfigured. If either of those happen,
+ * fall back to infinite looping.
+ */
+ (void)scheduler_simulation_exit(code);
+#endif
+
+ while (true)
+ {
+ yield();
+ }
+};
diff --git a/tests/test-runner.cc b/tests/test-runner.cc
index c9f3acb..37d2958 100644
--- a/tests/test-runner.cc
+++ b/tests/test-runner.cc
@@ -66,10 +66,7 @@
if (mcause == 0x2)
{
debug_log("Test failure in test runner");
-#ifdef SIMULATION
simulation_exit(1);
-#endif
- return ErrorRecoveryBehaviour::ForceUnwind;
}
debug_log("mcause: {}, pcc: {}", mcause, frame->pcc);
auto [reg, cause] = CHERI::extract_cheri_mtval(mtval);
@@ -162,13 +159,5 @@
TEST(crashDetected == false, "One or more tests failed");
- // Exit the simulator if we are running in simulation.
-#ifdef SIMULATION
simulation_exit();
-#endif
- // Infinite loop if we're not in simulation.
- while (true)
- {
- yield();
- }
}