| // Copyright Microsoft and CHERIoT Contributors. |
| // SPDX-License-Identifier: MIT |
| |
| #pragma once |
| |
| #include "loaderinfo.h" |
| #include <cdefs.h> |
| #include <cheri.hh> |
| #include <debug.hh> |
| #include <stdlib.h> |
| #include <token.h> |
| #include <type_traits> |
| |
| namespace |
| { |
| constexpr bool DebugScheduler = |
| #ifdef DEBUG_SCHEDULER |
| DEBUG_SCHEDULER |
| #else |
| false |
| #endif |
| ; |
| |
| /// Is scheduler accounting enabled? |
| constexpr bool Accounting = |
| #ifdef SCHEDULER_ACCOUNTING |
| SCHEDULER_ACCOUNTING |
| #else |
| false |
| #endif |
| ; |
| |
| using Debug = ConditionalDebug<DebugScheduler, "Scheduler">; |
| |
| constexpr StackCheckMode StackMode = |
| #if CHERIOT_STACK_CHECKS_SCHEDULER |
| StackCheckMode::Asserting |
| #else |
| StackCheckMode::Disabled |
| // Uncomment if checks failed to find the correct values |
| // StackCheckMode::Logging |
| #endif |
| ; |
| |
| #define STACK_CHECK(expected) \ |
| StackUsageCheck<StackMode, expected, __PRETTY_FUNCTION__> stackCheck |
| |
| /** |
| * Base class for sealed objects that are exported from the scheduler. |
| * |
| * Subclasses must implement a static `sealing_type` method that returns |
| * the sealing key. |
| */ |
| template<bool IsDynamic> |
| struct Handle |
| { |
| /** |
| * Unseal `unsafePointer` as a pointer to an object of the specified |
| * type. Returns nullptr if `unsafePointer` is not a valid sealed |
| * pointer to an object of the correct type. |
| */ |
| template<typename T> |
| static T *unseal(void *unsafePointer) |
| { |
| return static_cast<Handle *>(unsafePointer)->unseal_as<T>(); |
| } |
| |
| /** |
| * Unseal this object as the specified type. Returns nullptr if this |
| * is not a valid sealed object of the correct type. |
| */ |
| template<typename T> |
| T *unseal_as() |
| { |
| static_assert(std::is_base_of_v<Handle, T>, |
| "Cannot down-cast something that is not a subclass " |
| "of Handle"); |
| void *result; |
| if constexpr (IsDynamic) |
| { |
| result = token_obj_unseal_dynamic(T::sealing_type(), |
| reinterpret_cast<SObj>(this)); |
| } |
| else |
| { |
| result = token_obj_unseal_static(T::sealing_type(), |
| reinterpret_cast<SObj>(this)); |
| } |
| return static_cast<T *>(result); |
| } |
| }; |
| |
| /** |
| * RAII class for preventing nested exceptions. |
| */ |
| struct ExceptionGuard |
| { |
| /// The number of exception's currently being handled. |
| static inline uint8_t exceptionLevel; |
| |
| /// RAII type, no copy constructor. |
| ExceptionGuard(const ExceptionGuard &) = delete; |
| /// RAII type, no move constructor. |
| ExceptionGuard(ExceptionGuard &&) = delete; |
| |
| /** |
| * Constructor. Increments the exception level and calls the handler |
| * if we are in a nested exception. |
| */ |
| __always_inline ExceptionGuard(auto &&errorHandler) |
| { |
| exceptionLevel++; |
| if (exceptionLevel > 1) |
| { |
| errorHandler(); |
| } |
| } |
| |
| /** |
| * Destructor, decrements the current exception level. |
| */ |
| __always_inline ~ExceptionGuard() |
| { |
| exceptionLevel--; |
| } |
| |
| /** |
| * Panic if we are in a trying to block in an interrupt handler. |
| * |
| * In debug builds, this will report an error message with the caller's |
| * source location. |
| */ |
| static void |
| assert_safe_to_block(SourceLocation loc = SourceLocation::current()) |
| { |
| Debug::Invariant<>(exceptionLevel == 0, |
| "Trying to block in an interrupt context.", |
| loc); |
| } |
| }; |
| |
| __BEGIN_DECLS |
| void exception_entry_asm(void); |
| __END_DECLS |
| |
| } // namespace |