|  | // Copyright Microsoft and CHERIoT Contributors. | 
|  | // SPDX-License-Identifier: MIT | 
|  |  | 
|  | #pragma once | 
|  | #include <cdefs.h> | 
|  | #include <compartment-macros.h> | 
|  | #include <stddef.h> | 
|  | #include <stdint.h> | 
|  |  | 
|  | #ifdef __cplusplus | 
|  | #	include <cheri.hh> | 
|  | #endif | 
|  |  | 
|  | /** | 
|  | * State for error handlers to use. | 
|  | * | 
|  | * Note: This structure should have the same layout as the register-save area | 
|  | * (that is, the initial sequence of a TrustedStack, up through ca5, inclusive). | 
|  | */ | 
|  | struct ErrorState | 
|  | { | 
|  | /** | 
|  | * The faulting program counter.  Error handlers may modify this but the | 
|  | * result *must* point into the compartment's program counter capability. | 
|  | * If it does not then the trusted stack will be unwound forcibly to the | 
|  | * caller's compartment. | 
|  | * | 
|  | * Note: This is passed as an *untagged* capability.  This allows error | 
|  | * handlers to inspect the bounds and permissions, but does not convey the | 
|  | * rights. | 
|  | */ | 
|  | void *pcc; | 
|  |  | 
|  | /** | 
|  | * The register state where the fault occurred.  These may be modified by | 
|  | * an error handler. | 
|  | */ | 
|  | void *registers[15]; | 
|  | #ifdef __cplusplus | 
|  | /** | 
|  | * Templated method to get a reference to value of given | 
|  | * CHERI::RegisterNumber. | 
|  | * | 
|  | * Static asserts that the register is one of the general purpose ones | 
|  | * excluding CZR. This doesn't support getting PCC because in that case | 
|  | * you can Use ErrorState.pcc directly. | 
|  | */ | 
|  | template<CHERI::RegisterNumber ARegisterNumber> | 
|  | [[nodiscard]] void *&get_register_value() | 
|  | { | 
|  | static_assert(ARegisterNumber > CHERI::RegisterNumber::CZR && | 
|  | ARegisterNumber <= CHERI::RegisterNumber::CA5, | 
|  | "get_register_value: invalid RegisterNumber"); | 
|  | return this->registers[static_cast<size_t>(ARegisterNumber) - 1]; | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Returns a pointer to the value of the given CHERI::RegisterNumber from | 
|  | * this ErrorState. | 
|  | * | 
|  | * Will either select the appropriate index into ErrorState.registers | 
|  | * accounting for the missing CZR, ErrorState.PCC, or if registerNumber is | 
|  | * invalid or not contained in ErrorState then nullptr is returned. | 
|  | */ | 
|  | [[nodiscard]] void ** | 
|  | get_register_value(CHERI::RegisterNumber registerNumber) | 
|  | { | 
|  | if (registerNumber > CHERI::RegisterNumber::CZR && | 
|  | registerNumber <= CHERI::RegisterNumber::CA5) | 
|  | { | 
|  | return &this->registers[static_cast<size_t>(registerNumber) - 1]; | 
|  | } | 
|  | if (registerNumber == CHERI::RegisterNumber::PCC) | 
|  | { | 
|  | return &this->pcc; | 
|  | } | 
|  | return nullptr; | 
|  | } | 
|  | #endif | 
|  | }; | 
|  |  | 
|  | /** | 
|  | * Valid return values from an error handler. | 
|  | */ | 
|  | enum ErrorRecoveryBehaviour | 
|  | { | 
|  | /// Install the modified context. | 
|  | InstallContext, | 
|  | /// Unwind the trusted stack to the caller. | 
|  | ForceUnwind | 
|  | }; | 
|  |  | 
|  | __BEGIN_DECLS | 
|  | /** | 
|  | * The error handler for the current compartment.  A compartment may choose to | 
|  | * implement this.  If not implemented then compartment faults will unwind the | 
|  | * trusted stack. | 
|  | */ | 
|  | __attribute__(( | 
|  | section(".compartment_error_handler"))) enum ErrorRecoveryBehaviour | 
|  | compartment_error_handler(struct ErrorState *frame, | 
|  | size_t             mcause, | 
|  | size_t             mtval); | 
|  | __END_DECLS |