mirror of
https://github.com/Mathewnd/Astral.git
synced 2026-11-01 23:18:21 +00:00
interrupts: execute pending interrupts
This commit is contained in:
@@ -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;
|
||||||
|
|||||||
@@ -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")
|
||||||
|
|||||||
@@ -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;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user