You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
bsb1/arch/core_interrupt.h

144 lines
4.8 KiB
C++

/*! \file
* \brief \ref Core::Interrupt "Interrupt control" and \ref
* Core::Interrupt::Vector "interrupt vector list"
*/
#pragma once
#include "../types.h"
namespace Core {
/*! \brief Exception and Interrupt control
*
* \see [ISDMv3, Chapter 6 Interrupt and Exception
* Handling](intel_manual_vol3.pdf#page=185)
*/
namespace Interrupt {
/*! \brief Bit in `FLAGS` register corresponding to the current interrupt state
*/
constexpr uintptr_t FLAG_ENABLE = 1 << 9;
/*! \brief List of used interrupt vectors.
*
* The exception vectors from `0` to `31` are reserved for traps, faults and
* aborts. Their behavior is different for each exception, some push an *error
* code*, some are not recoverable.
*
* The vectors from `32` to `255` are user defined interrupts.
*
* \see [ISDMv3, 6.15 Exception and Interrupt
* Reference](intel_manual_vol3.pdf#page=203)
* \todo
*/
enum Vector {
// Predefined Exceptions
DIVISON_BY_ZERO =
0, ///< Divide-by-zero Error (at a `DIV`/`IDIV` instruction)
DEBUG = 1, ///< Debug exception
NON_MASKABLE_INTERRUPT = 2, ///< Non Maskable Interrupt
BREAKPOINT = 3, ///< Breakpoint exception (used for debugging)
OVERFLOW = 4, ///< Overflow exception (at `INTO` instruction)
BOUND_RANGE_EXCEEDED = 5, ///< Bound Range Exceeded (at `BOUND` instruction)
INVALID_OPCODE = 6, ///< Opcode at Instruction Pointer is invalid (you
///< probably shouldn't be here)
DEVICE_NOT_AVAILABLE =
7, ///< FPU/MMX/SSE instruction but corresponding extension not activated
DOUBLE_FAULT = 8, ///< Exception occurred while trying to call
///< exception/interrupt handler
// Coprocessor Segment Overrun (Legacy)
INVALID_TSS =
10, ///< Invalid Task State Segment selector (see error code for index)
SEGMENT_NOT_PRESENT =
11, ///< Segment not available (see error code for selector index)
STACK_SEGMENT_FAULT = 12, ///< Stack segment not available or invalid (see
///< error code for selector index)
GENERAL_PROTECTION_FAULT =
13, ///< Operation not allowed (see error code for selector index)
PAGE_FAULT = 14, ///< Operation on Page (r/w/x) not allowed for current
///< privilege (error code + `cr2`)
// reserved
FLOATING_POINT_EXCEPTION = 16, ///< x87 FPU error (at `WAIT`/`FWAIT`),
///< accidentally \ref Core::CR0_NE set?
ALIGNMENT_CHECK = 17, ///< Unaligned memory access in userspace (Exception
///< activated by \ref Core::CR0_AM)
MACHINE_CHECK = 18, ///< Model specific exception
SIMD_FP_EXCEPTION =
19, ///< SSE/MMX error (if \ref Core::CR4_OSXMMEXCPT activated)
SECURITY_EXCEPTION = 31,
// Interrupts
KEYBOARD=32,
PANIC=33
};
constexpr size_t VECTORS = 256;
/*! \brief Check if interrupts are enabled on this CPU
*
* This is done by pushing the `FLAGS` register onto stack,
* reading it into a register and checking the corresponding bit.
*
* \return `true` if enabled, `false` if disabled
*/
inline bool isEnabled() {
uintptr_t out;
asm volatile(
"pushf\n\t"
"pop %0\n\t"
: "=r"(out)
:
: "memory");
return (out & FLAG_ENABLE) != 0;
}
/*! \brief Allow interrupts
*
* Enables interrupt handling by executing the instruction `sti`.
* Since this instruction is delayed by one cycle, an subsequent `nop` is
* executed (to ensure deterministic behavior, independent from the compiler
* generated code)
*
* A pending interrupt (i.e., those arriving while interrupts were disabled)
* will be delivered after re-enabling interrupts.
*
* \see [ISDMv2, Chapter 4. STI - Set Interrupt
* Flag](intel_manual_vol2.pdf#page=1297)
*/
inline void enable() { asm volatile("sti\n\t nop\n\t" : : : "memory"); }
/*! \brief Forbid interrupts
*
* Prevents interrupt handling by executing the instruction `cli`.
* Will return the previous interrupt state.
* \return `true` if interrupts were enabled at the time of executing this
* function, `false` if they were already disabled.
*
* \see [ISDMv2, Chapter 3. CLI - Ckear Interrupt
* Flag](intel_manual_vol2.pdf#page=245)
*/
inline bool disable() {
bool enabled = isEnabled();
asm volatile("cli\n\t" : : : "memory");
return enabled;
}
/*! \brief Restore interrupt
*
* Restore the interrupt state to the state prior to calling \ref disable() by
* using its return value.
*
* \note This function will never disable interrupts, even if val is false!
* This function is designed to allow nested disabling and restoring of
* the interrupt state.
*
* \param val if set to `true`, interrupts will be enabled; nothing will happen
* on false.
*/
inline void restore(bool val) {
if (val) {
enable();
}
}
} // namespace Interrupt
} // namespace Core