aboutsummaryrefslogtreecommitdiff
path: root/kernel/include/main/interrupt.h
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/include/main/interrupt.h')
-rw-r--r--kernel/include/main/interrupt.h117
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);