Atmosphere/thermosphere/src/exceptions.c

100 lines
2.5 KiB
C
Raw Normal View History

/**
* Thermosphère: exception handler
* Handles all exceptions, including a return to EL2.
*
* Copyright (c) 2018 Kate J. Temkin <k@ktemkin.com>
*/
#include <stdint.h>
#include <stddef.h>
#include "exceptions.h"
#include "lib/printk.h"
/**
* Simple debug function that prints all of our saved registers.
*/
static void print_registers(struct guest_state *regs)
{
// print x0-29
for(int i = 0; i < 30; i += 2) {
printk("x%d:\t0x%p\t", i, regs->x[i]);
printk("x%d:\t0x%p\n", i + 1, regs->x[i + 1]);
}
// print x30; don't bother with x31 (SP), as it's used by the stack that's
// storing this stuff; we really care about the saved SP anyways
printk("x30:\t0x%p\n", regs->x[30]);
// Special registers.
printk("pc:\t0x%p\tcpsr:\t0x%p\n", regs->pc, regs->cpsr);
printk("sp_el1:\t0x%p\tsp_el0:\t0x%p\n", regs->sp_el1, regs->sp_el0);
printk("elr_el1:0x%p\tspsr_el1:0x%p\n", regs->elr_el1, regs->spsr_el1);
// Note that we don't print ESR_EL2, as this isn't really part of the saved state.
}
/**
* Placeholder function that triggers whenever a vector happens we're not
* expecting. Currently prints out some debug information.
*/
void unhandled_vector(struct guest_state *regs)
{
printk("\nAn unexpected vector happened!\n");
print_registers(regs);
printk("\n\n");
}
/**
* Handles an HVC call.
*/
static void handle_hvc(struct guest_state *regs, int call_number)
{
switch(call_number) {
default:
printk("Got a HVC call from 64-bit code.\n");
printk("Calling instruction was: hvc %d\n\n", call_number);
printk("Calling context (you can use these regs as hypercall args!):\n");
print_registers(regs);
printk("\n\n");
break;
}
}
/**
* Placeholder function that triggers whenever a user event triggers a
* synchronous interrupt. Currently, we really only care about 'hvc',
* so that's all we're going to handle here.
*/
void handle_hypercall(struct guest_state *regs)
{
// This is demonstration code.
// In the future, you'd stick your hypercall table here.
switch (regs->esr_el2.ec) {
case HSR_EC_HVC64: {
// Read the hypercall number.
int hvc_nr = regs->esr_el2.iss & 0xFFFF;
// ... and handle the hypercall.
handle_hvc(regs, hvc_nr);
break;
}
default:
printk("Unexpected hypercall! ESR=%p\n", regs->esr_el2.bits);
print_registers(regs);
printk("\n\n");
break;
}
}