From 99a7eccbe48e6f9cff9711ba98b5ddde6bdd9ee4 Mon Sep 17 00:00:00 2001 From: Matheus Date: Sun, 25 Jun 2023 21:00:14 -0300 Subject: [PATCH] kernel: DPC support --- kernel-src/arch/x86-64/main.c | 2 + kernel-src/include/kernel/dpc.h | 22 ++++++++ kernel-src/include/kernel/interrupt.h | 1 + kernel-src/include/x86-64/arch/cpu.h | 2 + kernel-src/sys/dpc.c | 74 +++++++++++++++++++++++++++ 5 files changed, 101 insertions(+) create mode 100644 kernel-src/include/kernel/dpc.h create mode 100644 kernel-src/sys/dpc.c diff --git a/kernel-src/arch/x86-64/main.c b/kernel-src/arch/x86-64/main.c index 61faf688..9d02984a 100644 --- a/kernel-src/arch/x86-64/main.c +++ b/kernel-src/arch/x86-64/main.c @@ -22,6 +22,7 @@ #include #include #include +#include static cpu_t bsp_cpu; @@ -31,6 +32,7 @@ void kernel_entry() { arch_gdt_reload(); arch_idt_setup(); arch_idt_reload(); + dpc_init(); pmm_init(); term_init(); logging_sethook(term_putchar); diff --git a/kernel-src/include/kernel/dpc.h b/kernel-src/include/kernel/dpc.h new file mode 100644 index 00000000..a7e6a879 --- /dev/null +++ b/kernel-src/include/kernel/dpc.h @@ -0,0 +1,22 @@ +#ifndef _DPC_H +#define _DPC_H + +#include +#include + +typedef void * dpcarg_t; +typedef void (*dpcfn_t)(context_t *, dpcarg_t); + +typedef struct _dpc_t { + struct _dpc_t *next; + struct _dpc_t *prev; + bool enqueued; + dpcfn_t fn; + dpcarg_t arg; +} dpc_t; + +void dpc_enqueue(dpc_t *dpc, dpcfn_t, dpcarg_t); +void dpc_dequeue(dpc_t *dpc); +void dpc_init(); + +#endif diff --git a/kernel-src/include/kernel/interrupt.h b/kernel-src/include/kernel/interrupt.h index 12f90221..6cb837e7 100644 --- a/kernel-src/include/kernel/interrupt.h +++ b/kernel-src/include/kernel/interrupt.h @@ -15,6 +15,7 @@ #define IPL_MAX 0 #define IPL_TIMER 1 #define IPL_KEYBOARD 2 +#define IPL_DPC 900 #define IPL_NORMAL 1000 struct _isr_t; diff --git a/kernel-src/include/x86-64/arch/cpu.h b/kernel-src/include/x86-64/arch/cpu.h index 27b24a70..a0ff6755 100644 --- a/kernel-src/include/x86-64/arch/cpu.h +++ b/kernel-src/include/x86-64/arch/cpu.h @@ -10,6 +10,7 @@ #include #include #include +#include typedef struct cpu_t { thread_t *thread; @@ -26,6 +27,7 @@ typedef struct cpu_t { timerentry_t schedtimerentry; void *schedulerstack; isr_t *isrqueue; + dpc_t *dpcqueue; } cpu_t; #define CPU_HALT() asm volatile("hlt") diff --git a/kernel-src/sys/dpc.c b/kernel-src/sys/dpc.c new file mode 100644 index 00000000..77ef5f38 --- /dev/null +++ b/kernel-src/sys/dpc.c @@ -0,0 +1,74 @@ +#include +#include +#include +#include + +static isr_t *dpcisr; + +static void remove(dpc_t *dpc) { + if (dpc->prev) + dpc->prev->next = dpc->next; + else + _cpu()->dpcqueue = dpc->next; + + if (dpc->next) + dpc->next->prev = dpc->prev; +} + +static void insert(dpc_t *dpc) { + dpc->prev = NULL; + dpc->next = _cpu()->dpcqueue; + + if (dpc->next) + dpc->next->prev = dpc; + + _cpu()->dpcqueue = dpc; +} + +static void isrfn(isr_t *self, context_t *context) { + while (_cpu()->dpcqueue) { + dpc_t *dpc = _cpu()->dpcqueue; + remove(dpc); + + __assert(dpc->enqueued); + dpc->enqueued = false; + + interrupt_set(true); + dpc->fn(context, dpc->arg); + interrupt_set(false); + } +} + +void dpc_enqueue(dpc_t *dpc, dpcfn_t fn, dpcarg_t arg) { + bool entrystate = interrupt_set(false); + + if (dpc->enqueued) + goto cleanup; + + dpc->fn = fn; + dpc->arg = arg; + dpc->enqueued = true; + insert(dpc); + interrupt_raise(dpcisr); + + cleanup: + interrupt_set(entrystate); +} + +void dpc_dequeue(dpc_t *dpc) { + bool entrystate = interrupt_set(false); + + if (dpc->enqueued == false) + goto cleanup; + + dpc->enqueued = false; + remove(dpc); + + cleanup: + interrupt_set(entrystate); +} + +void dpc_init() { + dpcisr = interrupt_allocate(isrfn, NULL, IPL_DPC); + __assert(dpcisr); +}