interrupts: execute pending interrupts

This commit is contained in:
Matheus
2023-06-25 16:00:08 -03:00
parent f03c34075e
commit 80671b6e11
3 changed files with 101 additions and 4 deletions
+2
View File
@@ -19,6 +19,8 @@
struct _isr_t; struct _isr_t;
typedef struct _isr_t { typedef struct _isr_t {
struct _isr_t *next;
struct _isr_t *prev;
void (*func)(struct _isr_t *self, context_t *ctx); void (*func)(struct _isr_t *self, context_t *ctx);
void (*eoi)(struct _isr_t *self); void (*eoi)(struct _isr_t *self);
long id; long id;
+1
View File
@@ -25,6 +25,7 @@ typedef struct cpu_t {
thread_t *idlethread; thread_t *idlethread;
timerentry_t schedtimerentry; timerentry_t schedtimerentry;
void *schedulerstack; void *schedulerstack;
isr_t *isrqueue;
} cpu_t; } cpu_t;
#define CPU_HALT() asm volatile("hlt") #define CPU_HALT() asm volatile("hlt")
+98 -4
View File
@@ -4,6 +4,92 @@
#include <arch/context.h> #include <arch/context.h>
#include <panic.h> #include <panic.h>
void arch_interrupt_disable();
void arch_interrupt_enable();
#define DOPENDING_SAVE() arch_context_saveandcall(dopending, NULL)
static void removefromqueue(isr_t *isr) {
if (isr->prev)
isr->prev->next = isr->next;
else
_cpu()->isrqueue = isr->next;
if (isr->next)
isr->next->prev = isr->prev;
}
static void insertinqueue(isr_t *isr) {
if (isr->pending)
return;
isr->next = _cpu()->isrqueue;
if (isr->next)
isr->next->prev = isr;
_cpu()->isrqueue = isr;
}
static void dopending(context_t *ctx) {
bool entrystatus = _cpu()->intstatus;
if (entrystatus) {
_cpu()->intstatus = false;
arch_interrupt_disable();
}
isr_t *list = NULL;
isr_t *iterator = _cpu()->isrqueue;
// build a list of pending ISRs and remove them from the main queue
while (iterator) {
isr_t *next = iterator->next;
if (_cpu()->ipl > iterator->priority) {
removefromqueue(iterator);
if (list)
list->prev = iterator;
iterator->next = list;
iterator->prev = NULL;
list = iterator;
__assert(iterator->pending);
}
iterator = next;
}
if (list == NULL)
goto cleanup;
// run pending ISRs
while (list) {
isr_t *isr = list;
list = list->next;
if (list)
list->prev = NULL;
isr->pending = false;
long oldipl = interrupt_raiseipl(isr->priority);
isr->func(isr, ctx);
interrupt_set(false);
interrupt_loweripl(oldipl);
// if any new interrupts are pending, they will be taken care of here
// XXX this is kinda hacky could be very very bad if there are a lot of interrupts
dopending(ctx);
}
cleanup:
if (entrystatus) {
_cpu()->intstatus = true;
arch_interrupt_enable();
}
}
void interrupt_isr(int vec, context_t *ctx) { void interrupt_isr(int vec, context_t *ctx) {
isr_t *isr = &_cpu()->isr[vec]; isr_t *isr = &_cpu()->isr[vec];
_cpu()->intstatus = false; _cpu()->intstatus = false;
@@ -18,7 +104,9 @@ void interrupt_isr(int vec, context_t *ctx) {
interrupt_set(false); interrupt_set(false);
interrupt_loweripl(oldipl); interrupt_loweripl(oldipl);
dopending(ctx);
} else { } else {
insertinqueue(isr);
isr->pending = true; isr->pending = true;
} }
@@ -58,7 +146,8 @@ long interrupt_loweripl(long ipl) {
_cpu()->ipl = ipl; _cpu()->ipl = ipl;
interrupt_set(oldintstatus); interrupt_set(oldintstatus);
// TODO do pending interrupts if (oldintstatus)
DOPENDING_SAVE();
return oldipl; return oldipl;
} }
@@ -66,21 +155,26 @@ long interrupt_loweripl(long ipl) {
long interrupt_raiseipl(long ipl) { long interrupt_raiseipl(long ipl) {
bool oldintstatus = interrupt_set(false); bool oldintstatus = interrupt_set(false);
long oldipl = _cpu()->ipl; long oldipl = _cpu()->ipl;
if (oldipl > ipl) if (oldipl > ipl)
_cpu()->ipl = ipl; _cpu()->ipl = ipl;
interrupt_set(oldintstatus); interrupt_set(oldintstatus);
return oldipl; return oldipl;
} }
void arch_interrupt_disable();
void arch_interrupt_enable();
bool interrupt_set(bool status) { bool interrupt_set(bool status) {
if (status) if (status)
arch_interrupt_enable(); arch_interrupt_enable();
else else
arch_interrupt_disable(); arch_interrupt_disable();
bool old = _cpu()->intstatus; bool old = _cpu()->intstatus;
_cpu()->intstatus = status; _cpu()->intstatus = status;
if (status)
DOPENDING_SAVE();
return old; return old;
} }