From 5ae11ac06299d4f1e0c7f8904414f22a183d8bdd Mon Sep 17 00:00:00 2001 From: Yi-Ting Shih Date: Tue, 1 Apr 2025 17:13:46 +0800 Subject: [PATCH] Feat: lab 3 --- .gitignore | 1 + Makefile | 2 +- include/ctype.h | 8 ++++ kernel/exception_table.S | 80 ++++++++++++++++++++++---------------- kernel/include/interrupt.h | 19 +++++++++ kernel/lib/interrupt.c | 72 ++++++++++++++++++++++++++++++++++ kernel/lib/shell.c | 17 ++++---- kernel/lib/timer.c | 13 ++++--- kernel/lib/uart.c | 26 ++++++++++++- kernel/main.c | 24 +++++------- 10 files changed, 197 insertions(+), 65 deletions(-) create mode 100644 include/ctype.h diff --git a/.gitignore b/.gitignore index 724759f..31ff8a2 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,4 @@ **.cpio .gdb_history userprog/userprog +rootfs/userprog diff --git a/Makefile b/Makefile index b685978..60f9d99 100644 --- a/Makefile +++ b/Makefile @@ -1,5 +1,5 @@ MAKE := make -MAKEFLAGS += -j 8 +MAKEFLAGS += -j8 ARCH := aarch64 GNU := $(ARCH)-linux-gnu diff --git a/include/ctype.h b/include/ctype.h new file mode 100644 index 0000000..9562e3c --- /dev/null +++ b/include/ctype.h @@ -0,0 +1,8 @@ +#pragma once + +#include + +int isdigit(int); +int isxdigit(int); +int isupper(int); +int isspace(int); diff --git a/kernel/exception_table.S b/kernel/exception_table.S index 76f153f..6638a6d 100644 --- a/kernel/exception_table.S +++ b/kernel/exception_table.S @@ -2,44 +2,56 @@ // save general registers to stack .macro save_all - sub sp, sp, 32 * 8 - stp x0, x1, [sp ,16 * 0] - stp x2, x3, [sp ,16 * 1] - stp x4, x5, [sp ,16 * 2] - stp x6, x7, [sp ,16 * 3] - stp x8, x9, [sp ,16 * 4] - stp x10, x11, [sp ,16 * 5] - stp x12, x13, [sp ,16 * 6] - stp x14, x15, [sp ,16 * 7] - stp x16, x17, [sp ,16 * 8] - stp x18, x19, [sp ,16 * 9] - stp x20, x21, [sp ,16 * 10] - stp x22, x23, [sp ,16 * 11] - stp x24, x25, [sp ,16 * 12] - stp x26, x27, [sp ,16 * 13] - stp x28, x29, [sp ,16 * 14] - str x30, [sp, 16 * 15] + sub sp, sp, 36 * 8 + stp x0, x1, [sp, 16 * 0] + stp x2, x3, [sp, 16 * 1] + stp x4, x5, [sp, 16 * 2] + stp x6, x7, [sp, 16 * 3] + stp x8, x9, [sp, 16 * 4] + stp x10, x11, [sp, 16 * 5] + stp x12, x13, [sp, 16 * 6] + stp x14, x15, [sp, 16 * 7] + stp x16, x17, [sp, 16 * 8] + stp x18, x19, [sp, 16 * 9] + stp x20, x21, [sp, 16 * 10] + stp x22, x23, [sp, 16 * 11] + stp x24, x25, [sp, 16 * 12] + stp x26, x27, [sp, 16 * 13] + stp x28, x29, [sp, 16 * 14] + stp x30, lr, [sp, 16 * 15] + + mrs x0, spsr_el1 + mrs x1, elr_el1 + mrs x2, esr_el1 + stp x0, x1, [sp, 16 * 16] + str x2, [sp, 16 * 17] .endm // load general registers from stack .macro load_all - ldp x0, x1, [sp ,16 * 0] - ldp x2, x3, [sp ,16 * 1] - ldp x4, x5, [sp ,16 * 2] - ldp x6, x7, [sp ,16 * 3] - ldp x8, x9, [sp ,16 * 4] - ldp x10, x11, [sp ,16 * 5] - ldp x12, x13, [sp ,16 * 6] - ldp x14, x15, [sp ,16 * 7] - ldp x16, x17, [sp ,16 * 8] - ldp x18, x19, [sp ,16 * 9] - ldp x20, x21, [sp ,16 * 10] - ldp x22, x23, [sp ,16 * 11] - ldp x24, x25, [sp ,16 * 12] - ldp x26, x27, [sp ,16 * 13] - ldp x28, x29, [sp ,16 * 14] - ldr x30, [sp, 16 * 15] - add sp, sp, 32 * 8 + ldp x0, x1, [sp, 16 * 0] + ldp x2, x3, [sp, 16 * 1] + ldp x4, x5, [sp, 16 * 2] + ldp x6, x7, [sp, 16 * 3] + ldp x8, x9, [sp, 16 * 4] + ldp x10, x11, [sp, 16 * 5] + ldp x12, x13, [sp, 16 * 6] + ldp x14, x15, [sp, 16 * 7] + ldp x16, x17, [sp, 16 * 8] + ldp x18, x19, [sp, 16 * 9] + ldp x20, x21, [sp, 16 * 10] + ldp x22, x23, [sp, 16 * 11] + ldp x24, x25, [sp, 16 * 12] + ldp x26, x27, [sp, 16 * 13] + ldp x28, x29, [sp, 16 * 14] + ldp x30, lr, [sp, 16 * 15] + + mrs x0, spsr_el1 + mrs x1, elr_el1 + mrs x2, esr_el1 + ldp x0, x1, [sp, 16 * 16] + ldr x2, [sp, 16 * 17] + add sp, sp, 36 * 8 .endm _null_handler: diff --git a/kernel/include/interrupt.h b/kernel/include/interrupt.h index 47de170..25b2349 100644 --- a/kernel/include/interrupt.h +++ b/kernel/include/interrupt.h @@ -2,5 +2,24 @@ #include +typedef void (*interrupt_callback_func_t)(uint64_t); + +typedef struct interrupt { + struct interrupt *_l, *_r; + uint32_t _d; + + uint64_t priority; + interrupt_callback_func_t func; + uint64_t param; +} interrupt_t; + +void add_interrupt_task(uint64_t priority, + interrupt_callback_func_t func, + uint64_t param); + void init_interrupt(void); void irq_handler(void); + +void wfe(void); + +extern interrupt_t *global_interrupt_pool; diff --git a/kernel/lib/interrupt.c b/kernel/lib/interrupt.c index b44b551..6d17a50 100644 --- a/kernel/lib/interrupt.c +++ b/kernel/lib/interrupt.c @@ -1,4 +1,5 @@ #include +#include #include #include #include @@ -8,6 +9,8 @@ #define CORE0_TIMER_IRQ_CTRL ((volatile uint32_t *)0x40000040) #define CORE0_IRQ_SOURCE ((volatile uint32_t *)0x40000060) +interrupt_t *global_interrupt_pool = (interrupt_t *)0x0; + static inline void _enable_interrupt(void) { W_SYSREG_IMM(DAIFClr, 0xf); } @@ -21,6 +24,61 @@ MMIO_W_HELPER(_enable_timer_irq, CORE0_TIMER_IRQ_CTRL, 0x1, 1); MMIO_R_HELPER(_irq_source_timer, CORE0_IRQ_SOURCE, 0x1, 1); MMIO_R_HELPER(_irq_source_uart, CORE0_IRQ_SOURCE, 0x1, 8); +static inline +uint32_t _d(interrupt_t *interrupt) +{ return interrupt ? interrupt->_d : 0; } + +static inline +void _swap(interrupt_t **a, interrupt_t **b) +{ + interrupt_t *tmp = *a; + *a = *b, *b = tmp; +} + +static inline +interrupt_t *_merge(interrupt_t *a, interrupt_t *b) +{ + if (!a || !b) + return a ?: b; + + if (a->priority < b->priority) + _swap(&a, &b); + a->_r = _merge(a->_r, b); + + if (_d(a->_l) < _d(a->_r)) + _swap(&a->_l, &a->_r); + + a->_d = _d(a->_r) + 1; + return a; +} + +static inline +interrupt_t *_pop(interrupt_t *interrupt) +{ + if (!interrupt || (!interrupt->_l && !interrupt->_r)) + return (interrupt_t *)0x0; + return _merge(interrupt->_l, interrupt->_r); +} + +void add_interrupt_task(uint64_t priority, + interrupt_callback_func_t func, + uint64_t param) +{ + // DEBUG_EXCEP("add interrupt"); + interrupt_t *newint = kmalloc(sizeof(interrupt_t)); + *newint = (interrupt_t){ + ._l = (interrupt_t *)0x0, + ._r = (interrupt_t *)0x0, + ._d = 0, + + .priority = priority, + .func = func, + .param = param + }; + + global_interrupt_pool = _merge(global_interrupt_pool, newint); +} + void init_interrupt(void) { uint64_t cntfrq_el0; @@ -43,3 +101,17 @@ void irq_handler(void) if (_irq_source_uart()) uart_irq_handler(); } + +void wfe(void) +{ + if (!global_interrupt_pool) { + asm volatile("wfe"); + return; + } + + interrupt_t *interrupt = global_interrupt_pool; + global_interrupt_pool = _merge(global_interrupt_pool->_l, + global_interrupt_pool->_r); + + interrupt->func(interrupt->param); +} diff --git a/kernel/lib/shell.c b/kernel/lib/shell.c index d3dfaf9..1e2f6fe 100644 --- a/kernel/lib/shell.c +++ b/kernel/lib/shell.c @@ -22,14 +22,15 @@ static inline void _help (void) { uart_puts( - "help : print this help menu" ENDL - "hello : print Hello World!" ENDL - "hwinfo : print hardware info" ENDL - "memalloc : alloate memory and print" ENDL - "ls : list directory contents" ENDL - "cat : concatenate files and print" ENDL - "exec : execute file in usermode" ENDL - "reboot : reboot the device" ENDL + "help : print this help menu" ENDL + "hello : print Hello World!" ENDL + "hwinfo : print hardware info" ENDL + "memalloc : alloate memory and print" ENDL + "ls : list directory contents" ENDL + "cat : concatenate files and print" ENDL + "exec : execute file in usermode" ENDL + "settimeout : pring message after a few seconds" ENDL + "reboot : reboot the device" ENDL ); } diff --git a/kernel/lib/timer.c b/kernel/lib/timer.c index ef418a3..bdbac99 100644 --- a/kernel/lib/timer.c +++ b/kernel/lib/timer.c @@ -1,4 +1,5 @@ #include +#include #include #include #include @@ -14,10 +15,10 @@ uint32_t _d(timer_t *t) { return t ? t->_d : 0; } static inline -void _swap(timer_t *a, timer_t *b) +void _swap(timer_t **a, timer_t **b) { - timer_t *tmp = a; - a = b, b = tmp; + timer_t *tmp = *a; + *a = *b, *b = tmp; } static inline @@ -27,11 +28,11 @@ timer_t *_merge(timer_t *a, timer_t *b) return a ?: b; if (a->data.firing_tick > b->data.firing_tick) - _swap(a, b); + _swap(&a, &b); a->_r = _merge(a->_r, b); if (_d(a->_l) < _d(a->_r)) - _swap(a->_l, a->_r); + _swap(&a->_l, &a->_r); a->_d = _d(a->_r) + 1; return a; @@ -87,7 +88,7 @@ void timer_irq_handler(void) DEBUG_EXCEP(cntpct_el0); if (global_timer) { - global_timer->data.func(global_timer->data.param); + add_interrupt_task(20, global_timer->data.func, global_timer->data.param); global_timer = _pop(global_timer); } diff --git a/kernel/lib/uart.c b/kernel/lib/uart.c index 9435a31..f2894a6 100644 --- a/kernel/lib/uart.c +++ b/kernel/lib/uart.c @@ -1,4 +1,6 @@ #include +#include +#include #include #include #include @@ -87,11 +89,31 @@ void uart_transmit_interrupt_handler() _uart_write_data(ringbuffer_bump(uart_writebuf)); } +typedef struct { + ringbuffer_t *buf; + uint8_t val; +} uart_interrupt_callback_payload_t; + +static inline +void uart_receive_interrupt_callback(uint64_t param) +{ + uart_interrupt_callback_payload_t *payload = (void *)param; + ringbuffer_push(payload->buf, payload->val); + kfree(payload); +} + void uart_receive_interrupt_handler() { if (uart_readbuf->size < uart_readbuf->cap) { uint8_t b = _uart_read_data(); - ringbuffer_push(uart_readbuf, b); + + 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); } } @@ -139,7 +161,7 @@ size_t uart_getb_async(uint8_t *bytes, size_t len) size_t recvlen = 0; for (; recvlen < len; ++bytes, ++recvlen) { while (!uart_readbuf->size) - asm volatile("wfe"); // wait for interrupt + wfe(); // wait for interrupt *bytes = ringbuffer_bump(uart_readbuf); } diff --git a/kernel/main.c b/kernel/main.c index d181853..da96882 100644 --- a/kernel/main.c +++ b/kernel/main.c @@ -42,20 +42,7 @@ void _print_time(uint64_t) uint64_t cntpct_el0, cntfrq_el0; R_SYSREG(cntpct_el0, cntpct_el0); R_SYSREG(cntfrq_el0, cntfrq_el0); - DEBUG_EXCEP(cntpct_el0 / cntpct_el0); -} - -void main(void *dtb) -{ - file_node_t *initrd_root = 0x0; - init(dtb, &initrd_root); - - LOG("system booting in"); - _print_time(0x0); - - uint64_t cntpct_el0, cntfrq_el0; - R_SYSREG(cntpct_el0, cntpct_el0); - R_SYSREG(cntfrq_el0, cntfrq_el0); + DEBUG_EXCEP(cntpct_el0 / cntfrq_el0); task_t task = { .firing_tick = cntpct_el0 + 2 * cntfrq_el0, @@ -67,6 +54,15 @@ void main(void *dtb) }; add_task(task); +} + +void main(void *dtb) +{ + file_node_t *initrd_root = 0x0; + init(dtb, &initrd_root); + + LOG("system booting in"); + _print_time(0x0); uint64_t el; R_SYSREG(el, CurrentEL);