Fix: interrupt preemption

This commit is contained in:
2025-04-15 17:22:45 +08:00
parent 89ff8a018d
commit c4a44542ef
8 changed files with 93 additions and 51 deletions

View File

@@ -101,11 +101,11 @@ logger_cur = _Generic((msg), \
// #define DEBUG_DTB(val) DEBUG(val) // #define DEBUG_DTB(val) DEBUG(val)
#define DEBUG_DTB(val) CLEAN #define DEBUG_DTB(val) CLEAN
// #define DEBUG_EXCEP(val) DEBUG(val) #define DEBUG_EXCEP(val) DEBUG(val)
#define DEBUG_EXCEP(val) CLEAN // #define DEBUG_EXCEP(val) CLEAN
#define DEBUG_MEM(val) DEBUG(val) // #define DEBUG_MEM(val) DEBUG(val)
// #define DEBUG_MEM(val) CLEAN #define DEBUG_MEM(val) CLEAN
// #define DEBUG_INITRD(val) DEBUG(val) // #define DEBUG_INITRD(val) DEBUG(val)
#define DEBUG_INITRD(val) CLEAN #define DEBUG_INITRD(val) CLEAN

View File

@@ -11,6 +11,8 @@ typedef struct interrupt {
uint64_t priority; uint64_t priority;
interrupt_callback_func_t func; interrupt_callback_func_t func;
uint64_t param; uint64_t param;
int is_start;
} interrupt_t; } interrupt_t;
void add_interrupt_task(uint64_t priority, void add_interrupt_task(uint64_t priority,

View File

@@ -73,16 +73,27 @@ void add_interrupt_task(uint64_t priority,
.priority = priority, .priority = priority,
.func = func, .func = func,
.param = param .param = param,
.is_start = false,
}; };
global_interrupt_pool = _merge(global_interrupt_pool, newint); global_interrupt_pool = _merge(global_interrupt_pool, newint);
while (global_interrupt_pool) {
// LOG("check interrupt"); DEBUG_EXCEP(global_interrupt_pool->priority);
if (global_interrupt_pool->is_start)
return;
global_interrupt_pool->is_start = true;
global_interrupt_pool->func(global_interrupt_pool->param);
global_interrupt_pool = _pop(global_interrupt_pool);
}
} }
void init_interrupt(void) void init_interrupt(void)
{ {
W_SYSREG(cntp_ctl_el0, 1);
_enable_interrupt(); _enable_interrupt();
_enable_timer_irq(true);
} }
void irq_handler(void) void irq_handler(void)
@@ -99,6 +110,8 @@ void irq_handler(void)
void wfe(void) void wfe(void)
{ {
return; // do nothing for now
if (!global_interrupt_pool) { if (!global_interrupt_pool) {
// asm volatile("wfe"); // asm volatile("wfe");
asm volatile("nop"); asm volatile("nop");

View File

@@ -1,4 +1,3 @@
#include <uart.h>
#include <logger.h> #include <logger.h>
#include <errcode.h> #include <errcode.h>
#include <utils.h> #include <utils.h>

View File

@@ -118,16 +118,12 @@ uint64_t _allocate_page(size_t req, int idx, uint64_t l, uint64_t r)
switch (CUR->state) { switch (CUR->state) {
case PAGE_FREE: case PAGE_FREE:
if (req == sz) { if (req == sz) {
LOG("page allocated"); LOG("page allocated"); LOG(l); DEBUG_MEM(r);
LOG(l);
DEBUG_MEM(r);
CUR->state = PAGE_ALLOCATED; CUR->state = PAGE_ALLOCATED;
CUR->size = 0; CUR->size = 0;
return l; return l;
} }
LOG("page divided"); LOG("page divided"); LOG(l); DEBUG_MEM(r);
LOG(l);
DEBUG(r);
LCH->state = RCH->state = PAGE_FREE; LCH->state = RCH->state = PAGE_FREE;
LCH->size = m - l; LCH->size = m - l;
RCH->size = r - m; RCH->size = r - m;

View File

@@ -125,6 +125,7 @@ static inline
void _settimeout_cb_func(uint64_t args) void _settimeout_cb_func(uint64_t args)
{ {
vector_t *v = (void *)args; vector_t *v = (void *)args;
uart_puts("timeout: ");
for (int i = 2; i < (int)v->size; ++i) { for (int i = 2; i < (int)v->size; ++i) {
uart_puts(VEC_AT(char, v, i)); uart_puts(VEC_AT(char, v, i));
uart_puts(" "); uart_puts(" ");

View File

@@ -47,7 +47,7 @@ timer_t *_pop(timer_t *t)
} }
static inline static inline
void _set_timer_interrupt() void _check_enable_timer()
{ {
if (global_timer) { if (global_timer) {
uint64_t cntpct_el0; uint64_t cntpct_el0;
@@ -59,8 +59,9 @@ void _set_timer_interrupt()
else else
W_SYSREG(cntp_cval_el0, global_timer->data.firing_tick); W_SYSREG(cntp_cval_el0, global_timer->data.firing_tick);
_enable_timer_irq(true); W_SYSREG(cntp_ctl_el0, 1);
} } else
W_SYSREG(cntp_ctl_el0, 0);
} }
static inline static inline
@@ -87,8 +88,23 @@ void add_timer_task(task_t task)
global_timer = _merge(global_timer, newtimer); global_timer = _merge(global_timer, newtimer);
_traverse(global_timer); // _traverse(global_timer);
_set_timer_interrupt(); _check_enable_timer();
}
typedef struct {
interrupt_callback_func_t func;
uint64_t param;
} _timer_task_wrapper_param_t;
static inline
void _timer_task_wrapper(uint64_t param)
{
_timer_task_wrapper_param_t *data = (void *)param;
data->func(data->param);
kfree(data);
_enable_timer_irq(true);
} }
void timer_irq_handler(void) void timer_irq_handler(void)
@@ -100,9 +116,15 @@ void timer_irq_handler(void)
LOG("timer irq"); DEBUG_EXCEP(cntpct_el0); LOG("timer irq"); DEBUG_EXCEP(cntpct_el0);
if (global_timer) { if (global_timer) {
add_interrupt_task(20, global_timer->data.func, global_timer->data.param); _timer_task_wrapper_param_t *param =
global_timer = _pop(global_timer); kmalloc(sizeof(_timer_task_wrapper_param_t));
} *param = (_timer_task_wrapper_param_t){
.func = global_timer->data.func,
.param = global_timer->data.param,
};
add_interrupt_task(20, _timer_task_wrapper, (uint64_t)param);
_set_timer_interrupt(); global_timer = _pop(global_timer);
_check_enable_timer();
}
} }

View File

@@ -29,6 +29,8 @@ size_t (*uart_putb)(const uint8_t *bytes, size_t len) = uart_putb_sync;
size_t (*uart_getb)(uint8_t *bytes, size_t len) = uart_getb_sync; size_t (*uart_getb)(uint8_t *bytes, size_t len) = uart_getb_sync;
int is_uart_inited = false; int is_uart_inited = false;
int is_uart_in_interrupt_queue = false;
ringbuffer_t *uart_readbuf; ringbuffer_t *uart_readbuf;
ringbuffer_t *uart_writebuf; ringbuffer_t *uart_writebuf;
@@ -83,37 +85,47 @@ void uart_init(void)
is_uart_inited = true; is_uart_inited = true;
} }
void uart_transmit_interrupt_handler() static inline
void _enable_uart_interrupt()
{ {
_uart_enable_receive_interrupt(true);
if (uart_writebuf->size > 0) if (uart_writebuf->size > 0)
_uart_write_data(ringbuffer_bump(uart_writebuf)); _uart_enable_transmit_interrupt(true);
} }
typedef struct {
ringbuffer_t *buf;
uint8_t val;
} uart_interrupt_callback_payload_t;
static inline static inline
void uart_receive_interrupt_callback(uint64_t param) void _uart_transmit_interrupt_callback(uint64_t)
{ {
uart_interrupt_callback_payload_t *payload = (void *)param; _uart_write_data(ringbuffer_bump(uart_writebuf));
ringbuffer_push(payload->buf, payload->val);
kfree(payload); is_uart_in_interrupt_queue = false;
_enable_uart_interrupt();
} }
void uart_receive_interrupt_handler() static inline
void _uart_transmit_interrupt_handler()
{
if (uart_writebuf->size > 0) {
is_uart_in_interrupt_queue = true;
add_interrupt_task(11, _uart_transmit_interrupt_callback, 0x0);
}
}
static inline
void _uart_receive_interrupt_callback(uint64_t)
{
ringbuffer_push(uart_readbuf, _uart_read_data());
is_uart_in_interrupt_queue = false;
_enable_uart_interrupt();
}
static inline
void _uart_receive_interrupt_handler()
{ {
if (uart_readbuf->size < uart_readbuf->cap) { if (uart_readbuf->size < uart_readbuf->cap) {
uint8_t b = _uart_read_data(); is_uart_in_interrupt_queue = true;
add_interrupt_task(12, _uart_receive_interrupt_callback, 0x0);
uart_interrupt_callback_payload_t *param = kmalloc(
sizeof(uart_interrupt_callback_payload_t));
*param = (uart_interrupt_callback_payload_t){
.buf = uart_readbuf,
.val = b,
};
add_interrupt_task(10, uart_receive_interrupt_callback, (uint64_t)param);
} }
} }
@@ -121,14 +133,11 @@ void uart_irq_handler(void)
{ {
_uart_enable_receive_interrupt(false); _uart_enable_receive_interrupt(false);
_uart_enable_transmit_interrupt(false); _uart_enable_transmit_interrupt(false);
if (_uart_receive_interrupt())
uart_receive_interrupt_handler();
if (_uart_transmit_interrupt())
uart_transmit_interrupt_handler();
_uart_enable_receive_interrupt(true); if (_uart_receive_interrupt())
if (uart_writebuf->size > 0) _uart_receive_interrupt_handler();
_uart_enable_transmit_interrupt(true); if (_uart_transmit_interrupt())
_uart_transmit_interrupt_handler();
} }
size_t uart_putb_async(const uint8_t *bytes, size_t len) size_t uart_putb_async(const uint8_t *bytes, size_t len)
@@ -137,8 +146,8 @@ size_t uart_putb_async(const uint8_t *bytes, size_t len)
for (; sentlen < len; ++bytes, ++sentlen) for (; sentlen < len; ++bytes, ++sentlen)
ringbuffer_push(uart_writebuf, *bytes); ringbuffer_push(uart_writebuf, *bytes);
if (uart_writebuf->size > 0) if (!is_uart_in_interrupt_queue && uart_writebuf)
_uart_enable_transmit_interrupt(true); _enable_uart_interrupt();
return sentlen; return sentlen;
} }