diff options
Diffstat (limited to 'kernel/include/main/interrupt.h')
-rw-r--r-- | kernel/include/main/interrupt.h | 117 |
1 files changed, 117 insertions, 0 deletions
diff --git a/kernel/include/main/interrupt.h b/kernel/include/main/interrupt.h new file mode 100644 index 0000000..6a9ae00 --- /dev/null +++ b/kernel/include/main/interrupt.h @@ -0,0 +1,117 @@ +#pragma once + +#include "kernel.h" +#include "types.h" +#include "util/debug.h" + +// intr_disk_priamry/seconday so that they are different task priority classes +#define INTR_DIVIDE_BY_ZERO 0x00 +#define INTR_INVALID_OPCODE 0x06 +#define INTR_GPF 0x0d +#define INTR_PAGE_FAULT 0x0e + +#define INTR_APICTIMER 0xf0 +#define INTR_KEYBOARD 0xe0 + +#define INTR_DISK_PRIMARY 0xd0 +#define INTR_SPURIOUS 0xfe +#define INTR_APICERR 0xff +#define INTR_SHUTDOWN 0xfd + +/* NOTE: INTR_SYSCALL is not defined here, but is in syscall.h (it must be + * in a userland-accessible header) */ + +// Intel Volume 3-A, 10.8.3.1 (10-29) +#define IPL_LOW 0 +// we want to keep timer interrupts happening all the time to keep track of time +// :) +#define IPL_HIGH 0xe0 +#define IPL_HIGHEST 0xff + +typedef struct regs +{ + // all the regs + uint64_t r_r15; + uint64_t r_r14; + uint64_t r_r13; + uint64_t r_r12; + uint64_t r_rbp; + uint64_t r_rbx; + uint64_t r_r11; + uint64_t r_r10; + uint64_t r_r9; + uint64_t r_r8; + uint64_t r_rax; + uint64_t r_rcx; + uint64_t r_rdx; + uint64_t r_rsi; + uint64_t r_rdi; + + // interrupt number + uint64_t r_intr; + + // pushed by processor + uint64_t r_err; + uint64_t r_rip; + uint64_t r_cs; + uint64_t r_rflags; + uint64_t r_rsp; + uint64_t r_ss; +} packed regs_t; + +void intr_init(); + +/* The function pointer which should be implemented by functions + * which will handle interrupts. These handlers should be registered + * with the interrupt subsystem via the intr_register function. + * The regs structure contains the state of the registers saved when + * the interrupt occured. Return whether or not the handler has itself + * acknowledged the interrupt with a call to apic_eoi(). */ +typedef long (*intr_handler_t)(regs_t *regs); + +/* Registers an interrupt handler for the given interrupt handler. + * If another handler had been previously registered for this interrupt + * number it is returned, otherwise this function returns NULL. It + * is good practice to assert that this function returns NULL unless + * it is known that this will not be the case. */ +intr_handler_t intr_register(uint8_t intr, intr_handler_t handler); + +int32_t intr_map(uint16_t irq, uint8_t intr); + +static inline uint64_t intr_enabled() +{ + uint64_t flags; + __asm__ volatile("pushf; pop %0; and $0x200, %0;" + : "=r"(flags)::); + return flags; +} + +static inline void intr_enable() { __asm__ volatile("sti"); } + +static inline void intr_disable() { __asm__ volatile("cli"); } + +/* Atomically enables interrupts using the sti + * instruction and puts the processor into a halted + * state, this function returns once an interrupt + * occurs. */ +static inline void intr_wait() +{ + /* the sti instruction enables interrupts, however + * interrupts are not checked for until the next + * instruction is executed, this means that the following + * code will not be succeptible to a bug where an + * interrupt occurs between the sti and hlt commands + * and does not wake us up from the hlt. */ + __asm__ volatile("sti; hlt"); +} + +/* Sets the interrupt priority level for hardware interrupts. + * At initialization time devices should detect their individual + * IPLs and save them for use with this function. IPL_LOW allows + * all hardware interrupts. IPL_HIGH blocks all hardware interrupts */ +uint8_t intr_setipl(uint8_t ipl); + +/* Retreives the current interrupt priority level. */ +uint8_t intr_getipl(); + +void dump_registers(regs_t *regs); |