blob: 00079dc8c671a332eb481824a89e36f6b7e226eb [file] [log] [blame]
// 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