libdragon
|
Exception Handler. More...
Data Structures | |
struct | syscall_handler_entry_t |
Syscall exception handler entry. More... | |
Macros | |
#define | MAX_SYSCALL_HANDLERS 4 |
Maximum number of syscall handlers that can be registered. | |
Functions | |
exception_handler_t | register_exception_handler (exception_handler_t cb) |
Register an exception handler to handle exceptions. | |
void | __exception_dump_header (FILE *out, exception_t *ex) |
Dump a brief recap of the exception. | |
void | __exception_dump_gpr (exception_t *ex, void(*cb)(void *arg, const char *regname, char *value), void *arg) |
Helper to dump the GPRs of an exception. | |
void | __exception_dump_fpr (exception_t *ex, void(*cb)(void *arg, const char *regname, char *hexvalue, char *singlevalue, char *doublevalue), void *arg) |
Helper to dump the FPRs of an exception. | |
void | exception_default_handler (exception_t *ex) |
Default exception handler. | |
void | __onCriticalException (reg_block_t *regs) |
Respond to a critical exception. | |
void | register_syscall_handler (syscall_handler_t handler, uint32_t first_code, uint32_t last_code) |
Register a handler that will be called when a syscall exception. | |
void | __onSyscallException (reg_block_t *regs) |
Respond to a syscall exception. | |
Variables | |
volatile reg_block_t | __baseRegAddr |
Base register offset as defined by the interrupt controller. | |
Exception Handler.
struct syscall_handler_entry_t |
Syscall exception handler entry.
Data Fields | ||
---|---|---|
syscall_handler_t | handler | Exception handler. |
uint32_t | first_code | Syscall code range start. |
uint32_t | last_code | Syscall code range end. |
exception_handler_t register_exception_handler | ( | exception_handler_t | cb | ) |
Register an exception handler to handle exceptions.
The registered handle is responsible for clearing any bits that may cause a re-trigger of the same exception and updating the EPC. An important example is the cause bits (12-17) of FCR31 from cop1. To prevent re-triggering the exception they should be cleared by the handler.
To manipulate the registers, update the values in the exception_t struct. They will be restored to appropriate locations when returning from the handler. Setting them directly will not work as expected as they will get overwritten with the values pointed by the struct.
There is only one exception to this, cr (cause register) which is also modified by the int handler before the saved values are restored thus it is only possible to update it through C0_WRITE_CR macro if it is needed. This shouldn't be necessary though as they are already handled by the library.
k0 ($26), k1 ($27) are not saved/restored and will not be available in the handler. Theoretically we can exclude s0-s7 ($16-$23), and gp ($28) to gain some performance as they are already saved by GCC when necessary. The same is true for sp ($29) and ra ($31) but current interrupt handler manipulates them via allocating a new stack and doing a jal. Similarly floating point registers f21-f31 are callee-saved. In the future we may consider removing them from the save state for interrupts (but not for exceptions)
[in] | cb | Callback function to call when exceptions happen |
void __exception_dump_header | ( | FILE * | out, |
exception_t * | ex | ||
) |
Dump a brief recap of the exception.
[in] | out | File to write to |
[in] | ex | Exception to dump |
void __exception_dump_gpr | ( | exception_t * | ex, |
void(*)(void *arg, const char *regname, char *value) | cb, | ||
void * | arg | ||
) |
Helper to dump the GPRs of an exception.
ex | Exception |
cb | Callback that will be called for each register |
arg | Argument to pass to the callback |
void __exception_dump_fpr | ( | exception_t * | ex, |
void(*)(void *arg, const char *regname, char *hexvalue, char *singlevalue, char *doublevalue) | cb, | ||
void * | arg | ||
) |
Helper to dump the FPRs of an exception.
ex | Exception |
cb | Callback that will be called for each register |
arg | Argument to pass to the callback |
void exception_default_handler | ( | exception_t * | ex | ) |
Default exception handler.
This handler is installed by default for all exceptions. It initializes the console and dump the exception state to the screen, including the value of all GPR/FPR registers. It then calls abort() to abort execution.
void register_syscall_handler | ( | syscall_handler_t | handler, |
uint32_t | first_code, | ||
uint32_t | last_code | ||
) |
Register a handler that will be called when a syscall exception.
This function allows to register a handler to be invoked in response to a syscall exception, generated by the SYSCALL opcode. The opcode allows to specify a 20-bit code which, in a more traditional operating system architecture, corresponds to the "service" to be called.
When the registered handler returns, the execution will resume from the instruction following the syscall one.
To allow for different usages of the code field, this function accepts a range of codes to associated with the handler. This allows a single handler to be invoked for multiple different codes, to specialize services.
handler | Handler to invoke when a syscall exception is triggered |
first_code | First syscall code to associate with this handler (begin of range) |
last_code | Last syscall code to associate with this handler (end of range) |
void __onSyscallException | ( | reg_block_t * | regs | ) |
Respond to a syscall exception.
Calls the handlers registered by register_syscall_handler.