blob: 6a9ae007328e104403fba580d79aa693a283e3f8 (
plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
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);
|