From 4f6780ba5e55168de96d9554b80089ed413d25be Mon Sep 17 00:00:00 2001 From: LJP-TW Date: Tue, 19 Apr 2022 00:51:13 -0700 Subject: [PATCH 01/16] Fix user stack --- src/kernel/main.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/kernel/main.c b/src/kernel/main.c index 175903749..8d8350991 100644 --- a/src/kernel/main.c +++ b/src/kernel/main.c @@ -172,6 +172,7 @@ static void cmd_exec(char *filename) return; } + // Modify user stack to the bottom of page user_sp = kmalloc(PAGE_SIZE); if (user_sp == NULL) { @@ -179,6 +180,8 @@ static void cmd_exec(char *filename) return; } + user_sp += PAGE_SIZE - 0x8; + exec_user_prog(mem, user_sp); // TODO: Free user_sp and mem From c55a00c77334fa0dec2a6cba2650118d7758a571 Mon Sep 17 00:00:00 2001 From: LJP-TW Date: Tue, 19 Apr 2022 00:51:46 -0700 Subject: [PATCH 02/16] Update README.md --- README.md | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/README.md b/README.md index e3a8ef038..73dfe5019 100644 --- a/README.md +++ b/README.md @@ -35,6 +35,18 @@ make image make qemu ``` +* You should either attach gdb to qemu, or just remove the arugments `-s -S` passed to qemu in the Makefile + +* Qemu will emulate the bootloader and you can then attach to the bootloader shell with: +``` +sudo screen /dev/pts/ +``` + +* In the bootloader shell, you can use the command `load` to ask the bootloader to load the kernel image. After entering the `load` command, you can send the kernel image to the bootloader with the following command: +``` +sudo ./tools/loadkernel.py /dev/pts/ build/kernel8.img +``` + ## How to burn it into pi3 ``` From 8b09383184949d88f4d119d54d29df95b3e3733b Mon Sep 17 00:00:00 2001 From: LJP-TW Date: Wed, 20 Apr 2022 20:36:40 -0700 Subject: [PATCH 03/16] Add save_and_disable_interrupt and restore_interrupt --- include/lib/utils.h | 15 +++++++++++++++ src/kernel/mm/mm.c | 14 ++++++-------- src/kernel/timer.c | 26 ++++++++++++-------------- 3 files changed, 33 insertions(+), 22 deletions(-) diff --git a/include/lib/utils.h b/include/lib/utils.h index 6c9547582..3c86f40a3 100644 --- a/include/lib/utils.h +++ b/include/lib/utils.h @@ -36,6 +36,21 @@ void memncpy(char *dst, char *src, unsigned long n); asm volatile("msr DAIFSet, 0xf"); \ } while (0) +static inline uint32 save_and_disable_interrupt(void) +{ + uint32 daif; + + daif = read_sysreg(DAIF); + disable_interrupt(); + + return daif; +} + +static inline void restore_interrupt(uint32 daif) +{ + write_sysreg(DAIF, daif); +} + #define get_elem_idx(elem, array) \ (((char *)elem - (char *)array) / sizeof(array[0])) diff --git a/src/kernel/mm/mm.c b/src/kernel/mm/mm.c index 9fef7bbe3..a8388bea3 100644 --- a/src/kernel/mm/mm.c +++ b/src/kernel/mm/mm.c @@ -96,11 +96,10 @@ void mm_init(void) void *kmalloc(int size) { - uint64 daif; + uint32 daif; void *ret; - daif = read_sysreg(DAIF); - disable_interrupt(); + daif = save_and_disable_interrupt(); if (size <= PAGE_SIZE) { // Use the Small Chunk allocator @@ -112,17 +111,16 @@ void *kmalloc(int size) ret = alloc_pages(page_cnt); } - write_sysreg(DAIF, daif); + restore_interrupt(daif); return ret; } void kfree(void *ptr) { - uint64 daif; + uint32 daif; - daif = read_sysreg(DAIF); - disable_interrupt(); + daif = save_and_disable_interrupt(); if (!sc_free(ptr)) { /* @@ -136,5 +134,5 @@ void kfree(void *ptr) _KFREE_END: - write_sysreg(DAIF, daif); + restore_interrupt(daif); } \ No newline at end of file diff --git a/src/kernel/timer.c b/src/kernel/timer.c index 609f6cb47..9accb145b 100644 --- a/src/kernel/timer.c +++ b/src/kernel/timer.c @@ -59,23 +59,22 @@ static void timer_disable() static timer_proc *tp_alloc() { - uint64 daif; + uint32 daif; uint32 idx; - daif = read_sysreg(DAIF); - disable_interrupt(); + daif = save_and_disable_interrupt(); idx = ffs(t_status); if (idx == 0) { - write_sysreg(DAIF, daif); + restore_interrupt(daif); return NULL; } t_status &= ~(1 << (idx - 1)); - write_sysreg(DAIF, daif); + restore_interrupt(daif); return &t_procs[idx - 1]; } @@ -118,12 +117,11 @@ static void timer_update_remain_time() */ static int tp_insert(timer_proc *tp) { - uint64 daif; + uint32 daif; timer_proc *iter; int first; - daif = read_sysreg(DAIF); - disable_interrupt(); + daif = save_and_disable_interrupt(); // Update remain_time timer_update_remain_time(); @@ -141,7 +139,7 @@ static int tp_insert(timer_proc *tp) t_meta.size += 1; - write_sysreg(DAIF, daif); + restore_interrupt(daif); return first; } @@ -151,14 +149,14 @@ static int tp_insert(timer_proc *tp) */ static void timer_set() { - uint64 daif; + uint32 daif; timer_proc *tp; - daif = read_sysreg(DAIF); - disable_interrupt(); + daif = save_and_disable_interrupt(); if (!t_meta.size) { - write_sysreg(DAIF, daif); + restore_interrupt(daif); + return; } @@ -168,7 +166,7 @@ static void timer_set() t_interval = tp->remain_time; write_sysreg(cntp_tval_el0, t_interval); - write_sysreg(DAIF, daif); + restore_interrupt(daif); } static void timer_set_boot_cnt() From 277f3ffa37e620e7e71af1392d2b24438256b791 Mon Sep 17 00:00:00 2001 From: LJP-TW Date: Fri, 22 Apr 2022 08:54:17 -0700 Subject: [PATCH 04/16] Implement kernel thread --- include/kernel/current.h | 20 ++++++++++ include/kernel/irq.h | 5 ++- include/kernel/kthread.h | 8 ++++ include/kernel/mini_uart.h | 3 +- include/kernel/sched.h | 42 +++++++++++++++++++++ include/kernel/timer.h | 8 ++-- src/kernel/head.S | 69 +++++++++++++++++++++++++++++++--- src/kernel/irq.c | 34 +++++++++++++++-- src/kernel/kthread.c | 64 +++++++++++++++++++++++++++++++ src/kernel/main.c | 34 ++++++++++++++++- src/kernel/mini_uart.c | 21 ++++++++--- src/kernel/sched.S | 24 ++++++++++++ src/kernel/sched.c | 67 +++++++++++++++++++++++++++++++++ src/kernel/timer.c | 77 +++++++++++++++++++++++++++++--------- 14 files changed, 435 insertions(+), 41 deletions(-) create mode 100644 include/kernel/current.h create mode 100644 include/kernel/kthread.h create mode 100644 include/kernel/sched.h create mode 100644 src/kernel/kthread.c create mode 100644 src/kernel/sched.S create mode 100644 src/kernel/sched.c diff --git a/include/kernel/current.h b/include/kernel/current.h new file mode 100644 index 000000000..c98baf989 --- /dev/null +++ b/include/kernel/current.h @@ -0,0 +1,20 @@ +#ifndef _CURRENT_H +#define _CURRENT_H + +#include + +struct _task_struct; + +static inline struct _task_struct *get_current(void) +{ + return (struct _task_struct *)read_sysreg(tpidr_el1); +} + +static inline void set_current(struct _task_struct *task) +{ + write_sysreg(tpidr_el1, task); +} + +#define current get_current() + +#endif /* _CURRENT_H */ \ No newline at end of file diff --git a/include/kernel/irq.h b/include/kernel/irq.h index 08e2065b4..3fd4b75e9 100644 --- a/include/kernel/irq.h +++ b/include/kernel/irq.h @@ -8,7 +8,10 @@ void irq_init(); /* * On success, 0 is returned */ -int irq_add_tasks(void (*task)(void *), void *args, uint32 prio); +int irq_run_task(void (*task)(void *), + void *args, + void (*fini)(void), + uint32 prio); void irq_handler(); void exception_default_handler(uint32 n); diff --git a/include/kernel/kthread.h b/include/kernel/kthread.h new file mode 100644 index 000000000..c55ef43d0 --- /dev/null +++ b/include/kernel/kthread.h @@ -0,0 +1,8 @@ +#ifndef _KTHREAD_H +#define _KTHREAD_H + +void kthread_set_init(void); + +void kthread_create(void (*start)(void)); + +#endif /* _KTHREAD_H */ \ No newline at end of file diff --git a/include/kernel/mini_uart.h b/include/kernel/mini_uart.h index 8e643b8be..19da47700 100644 --- a/include/kernel/mini_uart.h +++ b/include/kernel/mini_uart.h @@ -13,8 +13,7 @@ void uart_printf(char *fmt, ...); void uart_sync_printf(char *fmt, ...); -void uart_irq_check(void); -void uart_irq_handler(void); +int uart_irq_check(void); /* Switch asynchronous/synchronous mode for uart RW */ int uart_switch_mode(void); diff --git a/include/kernel/sched.h b/include/kernel/sched.h new file mode 100644 index 000000000..8c019b3a3 --- /dev/null +++ b/include/kernel/sched.h @@ -0,0 +1,42 @@ +#ifndef _SCHED_H +#define _SCHED_H + +#include +#include + +struct pt_regs { + void *x19; + void *x20; + void *x21; + void *x22; + void *x23; + void *x24; + void *x25; + void *x26; + void *x27; + void *x28; + void *fp; + void *lr; + void *sp; +}; + +typedef struct _task_struct { + /* This must be the first element */ + struct pt_regs regs; + void *kernel_stack; + struct list_head list; + uint32 need_resched:1; + uint32 tid; +} task_struct; + +void switch_to(task_struct *from, task_struct *to); + +void scheduler_init(void); + +void schedule(void); + +void schedule_tick(void); + +void sched_add_task(task_struct *task); + +#endif /* _SCHED_H */ \ No newline at end of file diff --git a/include/kernel/timer.h b/include/kernel/timer.h index 64d13ae89..8253f6ad0 100644 --- a/include/kernel/timer.h +++ b/include/kernel/timer.h @@ -4,11 +4,13 @@ #include void timer_init(); -void timer_irq_check(); -void timer_irq_handler(); +int timer_irq_check(); void timer_switch_info(); /* Call @proc(@args) after @after seconds. */ -void timer_add_proc(void (*proc)(void *), void *args, uint32 after); +void timer_add_proc_after(void (*proc)(void *), void *args, uint32 after); + +/* Call @proc(@args) after 1/@freq second. */ +void timer_add_proc_freq(void (*proc)(void *), void *args, uint32 freq); #endif /* _TIMER_H */ \ No newline at end of file diff --git a/src/kernel/head.S b/src/kernel/head.S index 92fb6fc90..620d73be9 100644 --- a/src/kernel/head.S +++ b/src/kernel/head.S @@ -105,6 +105,68 @@ set_exception_vector_table: add sp, sp, 2 * 8 .endm +.macro kernel_entry el + sub sp, sp, 17 * 16 + 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] + + .if \el == 0 + mrs x0, sp_el\el + stp x30, x0, [sp, 16 * 15] + .else + str x30, [sp, 16 * 15] + .endif + + mrs x0, elr_el\el + mrs x1, spsr_el\el + stp x0, x1, [sp, 16 * 16] +.endm + +.macro kernel_exit el + ldp x0, x1, [sp, 16 * 16] + msr elr_el\el, x0 + msr spsr_el\el, x1 + + .if \el ==0 + ldp x30, x0, [sp, 16 * 15] + msr sp_el\el, x0 + .else + ldr x30, [sp, 16 * 15] + .endif + + ldp x28, x29, [sp ,16 * 14] + ldp x26, x27, [sp ,16 * 13] + ldp x24, x25, [sp ,16 * 12] + ldp x22, x23, [sp ,16 * 11] + ldp x20, x21, [sp ,16 * 10] + ldp x18, x19, [sp ,16 * 9] + ldp x16, x17, [sp ,16 * 8] + ldp x14, x15, [sp ,16 * 7] + ldp x12, x13, [sp ,16 * 6] + ldp x10, x11, [sp ,16 * 5] + ldp x8, x9, [sp ,16 * 4] + ldp x6, x7, [sp ,16 * 3] + ldp x4, x5, [sp ,16 * 2] + ldp x2, x3, [sp ,16 * 1] + ldp x0, x1, [sp ,16 * 0] + add sp, sp, 17 * 16 + + eret +.endm + exception_handler: // Do nothing save_all @@ -154,14 +216,11 @@ curr_syn_eh: eret curr_irq_eh: - save_all - save_exception_reg + kernel_entry 1 bl irq_handler - load_exception_reg - load_all - eret + kernel_exit 1 curr_fiq_eh: save_all diff --git a/src/kernel/irq.c b/src/kernel/irq.c index 82c349bac..68b19e473 100644 --- a/src/kernel/irq.c +++ b/src/kernel/irq.c @@ -5,6 +5,8 @@ #include #include #include +#include +#include #define IRQ_TASK_NUM 32 @@ -42,6 +44,8 @@ struct list_head irq_tasks_meta; */ uint32 irq_tasks_status; +uint32 irq_nested_layer; + /* * Interrupts must be disabled before calling this function. */ @@ -175,7 +179,10 @@ void irq_init() /* * Interrupts must be disabled before calling this function. */ -int irq_add_tasks(void (*task)(void *), void *args, uint32 prio) +int irq_run_task(void (*task)(void *), + void *args, + void (*fini)(void), + uint32 prio) { irq_task *it; int preempt; @@ -203,6 +210,8 @@ int irq_add_tasks(void (*task)(void *), void *args, uint32 prio) disable_interrupt(); + (fini)(); + it_remove(it); } @@ -213,9 +222,26 @@ int irq_add_tasks(void (*task)(void *), void *args, uint32 prio) void irq_handler() { - // These check functions may add irq_task. - timer_irq_check(); - uart_irq_check(); + irq_nested_layer++; + + // These check functions may add irq_task and run it. + if (!timer_irq_check()) {} + else if (!uart_irq_check()) {} + + irq_nested_layer--; + + // IRQ handling completed + + // Reschedule + if (irq_nested_layer || !current->need_resched) { + return; + } + + enable_interrupt(); + + schedule(); + + disable_interrupt(); } void exception_default_handler(uint32 n) diff --git a/src/kernel/kthread.c b/src/kernel/kthread.c new file mode 100644 index 000000000..d6e05e046 --- /dev/null +++ b/src/kernel/kthread.c @@ -0,0 +1,64 @@ +#include +#include +#include +#include + +#define STACK_SIZE (2 * PAGE_SIZE) + +// TODO: recycle usable tid +uint32 max_tid; + +static uint32 alloc_tid(void) +{ + uint32 tid; + + tid = max_tid; + max_tid += 1; + + return tid; +} + +void kthread_set_init(void) +{ + task_struct *task; + + task = kmalloc(sizeof(task_struct)); + + task->need_resched = 0; + task->tid = alloc_tid(); + + sched_add_task(task); + + set_current(task); +} + +static inline void pt_regs_init(struct pt_regs *regs, void *lr) +{ + regs->x19 = 0; + regs->x20 = 0; + regs->x21 = 0; + regs->x22 = 0; + regs->x23 = 0; + regs->x24 = 0; + regs->x25 = 0; + regs->x26 = 0; + regs->x27 = 0; + regs->x28 = 0; + regs->fp = 0; + regs->lr = lr; +} + +void kthread_create(void (*start)(void)) +{ + task_struct *task; + + task = kmalloc(sizeof(task_struct)); + + task->kernel_stack = kmalloc(STACK_SIZE); + task->need_resched = 0; + task->tid = alloc_tid(); + task->regs.sp = (char *)task->kernel_stack + STACK_SIZE - 0x10; + pt_regs_init(&task->regs, start); + + sched_add_task(task); +} \ No newline at end of file diff --git a/src/kernel/main.c b/src/kernel/main.c index 8d8350991..81728bb71 100644 --- a/src/kernel/main.c +++ b/src/kernel/main.c @@ -9,6 +9,9 @@ #include #include #include +#include +#include +#include #define BUFSIZE 0x100 @@ -132,7 +135,7 @@ static void cmd_setTimeout(char *msg, char *ssec) memncpy(m, msg, len); uart_printf("[*] time: %d\r\n", atoi(ssec)); - timer_add_proc((void (*)(void *))timeout_print, m, atoi(ssec)); + timer_add_proc_after((void (*)(void *))timeout_print, m, atoi(ssec)); } static void cmd_sw_timer(void) @@ -279,6 +282,22 @@ static void shell(void) } } +static void foo(void) +{ + for (int i = 0; i < 10; ++i) { + uart_sync_printf("Thread id: %d %d\r\n", current->tid, i); + delay(1000000); + schedule(); + } +} + +static void idle(void) +{ + while (1) { + schedule(); + } +} + void start_kernel(char *fdt) { fdt_base = fdt; @@ -295,10 +314,21 @@ void start_kernel(char *fdt) timer_init(); + scheduler_init(); + + kthread_set_init(); + kthread_create(shell); + + for (int i = 0; i < 3; ++i) { + kthread_create(foo); + } + + uart_sync_printf("[*] Go!\r\n"); + // Enable interrupt from Auxiliary peripherals irq1_enable(29); enable_interrupt(); - shell(); + idle(); } \ No newline at end of file diff --git a/src/kernel/mini_uart.c b/src/kernel/mini_uart.c index 2d00a1e13..04f724943 100644 --- a/src/kernel/mini_uart.c +++ b/src/kernel/mini_uart.c @@ -9,6 +9,9 @@ #define BUFSIZE 0x100 +static void uart_irq_handler(void *); +static void uart_irq_fini(void); + // UART asynchronous/synchronous mode // 0: Synchronous mode // 1: Asynchronous mode @@ -275,27 +278,27 @@ void uart_init(void) uart_send_fp = uart_sync_send; } -void uart_irq_check(void) +int uart_irq_check(void) { uint32 iir = get32(AUX_MU_IIR_REG); if (iir & 0x01) { // No interrupt - return; + return 0; } // Disable RW interrupt put32(AUX_MU_IER_REG, 0); - if (irq_add_tasks((void (*)(void *))uart_irq_handler, NULL, 1)) { + if (irq_run_task(uart_irq_handler, NULL, uart_irq_fini, 1)) { put32(AUX_MU_IER_REG, 0x03); } + + return 1; } -void uart_irq_handler(void) +static void uart_irq_handler(void *_) { uint32 iir = get32(AUX_MU_IIR_REG); - uint32 ier = get32(AUX_MU_IER_REG); - ier = ier & ~(0x03); if (iir & 0x02) { // Transmit holding register empty @@ -310,6 +313,12 @@ void uart_irq_handler(void) r_tail = (r_tail + 1) % BUFSIZE; } } +} + +static void uart_irq_fini(void) +{ + uint32 ier = get32(AUX_MU_IER_REG); + ier = ier & ~(0x03); // Set RW interrupt if (r_head != (r_tail + 1) % BUFSIZE) { diff --git a/src/kernel/sched.S b/src/kernel/sched.S new file mode 100644 index 000000000..0fd3da883 --- /dev/null +++ b/src/kernel/sched.S @@ -0,0 +1,24 @@ +.globl switch_to +switch_to: + stp x19, x20, [x0, 16 * 0] + stp x21, x22, [x0, 16 * 1] + stp x23, x24, [x0, 16 * 2] + stp x25, x26, [x0, 16 * 3] + stp x27, x28, [x0, 16 * 4] + stp fp, lr, [x0, 16 * 5] + mov x9, sp + str x9, [x0, 16 * 6] + + ldp x19, x20, [x1, 16 * 0] + ldp x21, x22, [x1, 16 * 1] + ldp x23, x24, [x1, 16 * 2] + ldp x25, x26, [x1, 16 * 3] + ldp x27, x28, [x1, 16 * 4] + ldp fp, lr, [x1, 16 * 5] + ldr x9, [x1, 16 * 6] + mov sp, x9 + + // set_current + msr tpidr_el1, x1 + + ret diff --git a/src/kernel/sched.c b/src/kernel/sched.c new file mode 100644 index 000000000..224adaf9e --- /dev/null +++ b/src/kernel/sched.c @@ -0,0 +1,67 @@ +#include +#include +#include +#include +#include + +#define SCHEDULER_TIMER_HZ 1000 +#define SCHEDULER_WATERMARK 15 + +static struct list_head run_queue; + +static uint32 schedule_ticks; + +static void timer_schdule_tick(void *_) +{ + schedule_tick(); + + timer_add_proc_freq(timer_schdule_tick, NULL, SCHEDULER_TIMER_HZ); +} + +void scheduler_init(void) +{ + INIT_LIST_HEAD(&run_queue); + + timer_add_proc_freq(timer_schdule_tick, NULL, SCHEDULER_TIMER_HZ); +} + +void schedule(void) +{ + uint64 daif; + task_struct *task; + + daif = save_and_disable_interrupt(); + + task = list_first_entry(&run_queue, task_struct, list); + + list_del(&task->list); + list_add_tail(&task->list, &run_queue); + + current->need_resched = 0; + + restore_interrupt(daif); + + switch_to(current, task); +} + +void schedule_tick(void) +{ + schedule_ticks += 1; + + if (schedule_ticks >= SCHEDULER_WATERMARK) { + schedule_ticks = 0; + + current->need_resched = 1; + } +} + +void sched_add_task(task_struct *task) +{ + uint32 daif; + + daif = save_and_disable_interrupt(); + + list_add_tail(&task->list, &run_queue); + + restore_interrupt(daif); +} \ No newline at end of file diff --git a/src/kernel/timer.c b/src/kernel/timer.c index 9accb145b..9cae43bc3 100644 --- a/src/kernel/timer.c +++ b/src/kernel/timer.c @@ -10,6 +10,9 @@ #define TIMER_PROC_NUM 32 +static void timer_irq_handler(void *); +static void timer_irq_fini(void); + typedef struct { // cb(args) void (*cb)(void *); @@ -96,7 +99,7 @@ static void tp_release(timer_proc *tp) static void timer_update_remain_time() { timer_proc *iter; - uint32 cntp_tval_el0; + int32 cntp_tval_el0; uint32 diff; if (!t_meta.size) { @@ -108,7 +111,11 @@ static void timer_update_remain_time() t_interval = cntp_tval_el0; list_for_each_entry(iter, &t_meta.head, list) { - iter->remain_time -= diff; + if (diff > iter->remain_time) { + iter->remain_time = 0; + } else { + iter->remain_time -= diff; + } } } @@ -183,7 +190,7 @@ static void timer_show_boot_time(void *_) (cntpct_el0 - timer_boot_cnt) / cntfrq_el0); } - timer_add_proc(timer_show_boot_time, NULL, 2); + timer_add_proc_after(timer_show_boot_time, NULL, 2); } void timer_init() @@ -196,22 +203,26 @@ void timer_init() t_interval = 0; t_status = 0xffffffff; - timer_add_proc(timer_show_boot_time, NULL, 2); + timer_add_proc_after(timer_show_boot_time, NULL, 2); } -void timer_irq_check() +int timer_irq_check() { uint32 core0_irq_src = get32(CORE0_IRQ_SOURCE); - if (core0_irq_src & 0x02) { - timer_disable(); - if (irq_add_tasks(timer_irq_handler, NULL, 0)) { - timer_enable(); - } + if (!(core0_irq_src & 0x02)) { + return 0; + } + + timer_disable(); + if (irq_run_task(timer_irq_handler, NULL, timer_irq_fini, 0)) { + timer_enable(); } + + return 1; } -void timer_irq_handler() +static void timer_irq_handler(void *_) { timer_proc *tp; @@ -231,7 +242,10 @@ void timer_irq_handler() // Execute the callback function (tp->cb)(tp->args); tp_release(tp); +} +static void timer_irq_fini(void) +{ timer_enable(); } @@ -240,11 +254,22 @@ void timer_switch_info() timer_show_enable = !timer_show_enable; } -void timer_add_proc(void (*proc)(void *), void *args, uint32 after) +static void timer_add_proc(timer_proc *tp) +{ + int need_update; + + need_update = tp_insert(tp); + + if (need_update) { + timer_set(); + timer_enable(); + } +} + +void timer_add_proc_after(void (*proc)(void *), void *args, uint32 after) { timer_proc *tp; uint32 cntfrq_el0; - int need_update; tp = tp_alloc(); @@ -257,10 +282,26 @@ void timer_add_proc(void (*proc)(void *), void *args, uint32 after) tp->cb = proc; tp->args = args; tp->remain_time = after * cntfrq_el0; - need_update = tp_insert(tp); - - if (need_update) { - timer_set(); - timer_enable(); + + timer_add_proc(tp); +} + +void timer_add_proc_freq(void (*proc)(void *), void *args, uint32 freq) +{ + timer_proc *tp; + uint32 cntfrq_el0; + + tp = tp_alloc(); + + if (!tp) { + return; } + + cntfrq_el0 = read_sysreg(cntfrq_el0); + + tp->cb = proc; + tp->args = args; + tp->remain_time = cntfrq_el0 / freq; + + timer_add_proc(tp); } \ No newline at end of file From 9df4883541ffaa43c8284565e306db3c2c0ccb30 Mon Sep 17 00:00:00 2001 From: LJP-TW Date: Mon, 25 Apr 2022 00:41:15 -0700 Subject: [PATCH 05/16] Implement the mechanism for kernel thread termination --- include/kernel/kthread.h | 4 +- include/kernel/preempt.h | 7 ++++ include/kernel/sched.h | 3 ++ include/kernel/waitqueue.h | 19 ++++++++++ src/kernel/irq.c | 2 +- src/kernel/kthread.c | 77 +++++++++++++++++++++++++++++++++++--- src/kernel/main.c | 47 +++++++++++------------ src/kernel/preempt.c | 25 +++++++++++++ src/kernel/sched.c | 17 +++++++-- src/kernel/waitqueue.c | 50 +++++++++++++++++++++++++ 10 files changed, 217 insertions(+), 34 deletions(-) create mode 100644 include/kernel/preempt.h create mode 100644 include/kernel/waitqueue.h create mode 100644 src/kernel/preempt.c create mode 100644 src/kernel/waitqueue.c diff --git a/include/kernel/kthread.h b/include/kernel/kthread.h index c55ef43d0..433b63c16 100644 --- a/include/kernel/kthread.h +++ b/include/kernel/kthread.h @@ -1,8 +1,10 @@ #ifndef _KTHREAD_H #define _KTHREAD_H -void kthread_set_init(void); +void kthread_init(void); void kthread_create(void (*start)(void)); +void kthread_kill_zombies(void); + #endif /* _KTHREAD_H */ \ No newline at end of file diff --git a/include/kernel/preempt.h b/include/kernel/preempt.h new file mode 100644 index 000000000..51f3d1920 --- /dev/null +++ b/include/kernel/preempt.h @@ -0,0 +1,7 @@ +#ifndef _PREEMPT_H +#define _PREEMPT_H + +void preempt_disable(void); +void preempt_enable(void); + +#endif /* _PREEMPT_H */ \ No newline at end of file diff --git a/include/kernel/sched.h b/include/kernel/sched.h index 8c019b3a3..115024129 100644 --- a/include/kernel/sched.h +++ b/include/kernel/sched.h @@ -27,6 +27,7 @@ typedef struct _task_struct { struct list_head list; uint32 need_resched:1; uint32 tid; + uint32 preempt; } task_struct; void switch_to(task_struct *from, task_struct *to); @@ -39,4 +40,6 @@ void schedule_tick(void); void sched_add_task(task_struct *task); +void sched_del_task(task_struct *task); + #endif /* _SCHED_H */ \ No newline at end of file diff --git a/include/kernel/waitqueue.h b/include/kernel/waitqueue.h new file mode 100644 index 000000000..967a5823e --- /dev/null +++ b/include/kernel/waitqueue.h @@ -0,0 +1,19 @@ +#ifndef _WAITQUEUE_H +#define _WAITQUEUE_H + +#include + +typedef struct { + struct list_head list; +} wait_queue_head; + +wait_queue_head *wq_create(void); + +int wq_empty(wait_queue_head *head); + +void wq_add_task(task_struct *task, wait_queue_head *head); +void wq_del_task(task_struct *task); + +task_struct *wq_get_first_task(wait_queue_head *head); + +#endif /* _WAITQUEUE_H */ \ No newline at end of file diff --git a/src/kernel/irq.c b/src/kernel/irq.c index 68b19e473..24a04a41c 100644 --- a/src/kernel/irq.c +++ b/src/kernel/irq.c @@ -233,7 +233,7 @@ void irq_handler() // IRQ handling completed // Reschedule - if (irq_nested_layer || !current->need_resched) { + if (irq_nested_layer || !current->need_resched || current->preempt) { return; } diff --git a/src/kernel/kthread.c b/src/kernel/kthread.c index d6e05e046..bd1499f16 100644 --- a/src/kernel/kthread.c +++ b/src/kernel/kthread.c @@ -2,9 +2,17 @@ #include #include #include +#include +#include #define STACK_SIZE (2 * PAGE_SIZE) +static uint32 alloc_tid(void); +static void kthread_start(void); +static void kthread_fini(void); + +static wait_queue_head *wait_queue; + // TODO: recycle usable tid uint32 max_tid; @@ -18,23 +26,58 @@ static uint32 alloc_tid(void) return tid; } -void kthread_set_init(void) +static void kthread_start(void) +{ + void (*main)(void); + + asm volatile("mov %0, x19\n" + "mov x19, xzr" + : "=r" (main)); + + main(); + + kthread_fini(); +} + +/* + * Add to wait_queue to wait some process to recycle this kthread + */ +static void kthread_fini(void) +{ + preempt_disable(); + + sched_del_task(current); + + wq_add_task(current, wait_queue); + + preempt_enable(); + + schedule(); +} + +void kthread_init(void) { task_struct *task; + // Initialze current task task = kmalloc(sizeof(task_struct)); task->need_resched = 0; task->tid = alloc_tid(); + task->preempt = 0; + + // Must set current first + set_current(task); sched_add_task(task); - set_current(task); + // Create wait_queue + wait_queue = wq_create(); } -static inline void pt_regs_init(struct pt_regs *regs, void *lr) +static inline void pt_regs_init(struct pt_regs *regs, void *main) { - regs->x19 = 0; + regs->x19 = main; regs->x20 = 0; regs->x21 = 0; regs->x22 = 0; @@ -45,7 +88,7 @@ static inline void pt_regs_init(struct pt_regs *regs, void *lr) regs->x27 = 0; regs->x28 = 0; regs->fp = 0; - regs->lr = lr; + regs->lr = kthread_start; } void kthread_create(void (*start)(void)) @@ -57,8 +100,32 @@ void kthread_create(void (*start)(void)) task->kernel_stack = kmalloc(STACK_SIZE); task->need_resched = 0; task->tid = alloc_tid(); + task->preempt = 0; task->regs.sp = (char *)task->kernel_stack + STACK_SIZE - 0x10; pt_regs_init(&task->regs, start); sched_add_task(task); +} + +void kthread_kill_zombies(void) +{ + while (1) { + task_struct *task; + + if (wq_empty(wait_queue)) { + return; + } + + preempt_disable(); + + task = wq_get_first_task(wait_queue); + + wq_del_task(task); + + preempt_enable(); + + kfree(task->kernel_stack); + // TODO: release tid + kfree(task); + } } \ No newline at end of file diff --git a/src/kernel/main.c b/src/kernel/main.c index 81728bb71..82d3dd2af 100644 --- a/src/kernel/main.c +++ b/src/kernel/main.c @@ -29,6 +29,15 @@ static void timeout_print(char *str) kfree(str); } +static void foo(void) +{ + for (int i = 0; i < 10; ++i) { + uart_sync_printf("Thread id: %d %d\r\n", current->tid, i); + delay(1000000); + schedule(); + } +} + static void cmd_alloc(char *ssize) { int size, idx; @@ -92,6 +101,7 @@ static void cmd_help(void) "print @msg after @sec seconds" "\r\n" "sw_timer\t: " "turn on/off timer debug info" "\r\n" "sw_uart_mode\t: " "use sync/async UART" "\r\n" + "thread_test\t: " "test kthread" "\r\n" ); } @@ -195,6 +205,13 @@ static void cmd_parsedtb(void) fdt_traversal(fdt_base); } +static void cmd_thread_test(void) +{ + for (int i = 0; i < 3; ++i) { + kthread_create(foo); + } +} + static int shell_read_cmd(void) { return uart_recvline(shell_buf, BUFSIZE); @@ -267,6 +284,8 @@ static void shell(void) cmd_ls(); } else if (!strcmp("parsedtb", shell_buf)) { cmd_parsedtb(); + } else if (!strcmp("thread_test", shell_buf)) { + cmd_thread_test(); } else if (!strncmp("cat", shell_buf, 3)) { if (cmd_len >= 5) { cmd_cat(&shell_buf[4]); @@ -282,18 +301,10 @@ static void shell(void) } } -static void foo(void) -{ - for (int i = 0; i < 10; ++i) { - uart_sync_printf("Thread id: %d %d\r\n", current->tid, i); - delay(1000000); - schedule(); - } -} - static void idle(void) { while (1) { + kthread_kill_zombies(); schedule(); } } @@ -303,27 +314,17 @@ void start_kernel(char *fdt) fdt_base = fdt; irq_init(); - uart_init(); - uart_printf("[*] fdt base: %x\r\n", fdt_base); - uart_printf("[*] Kernel\r\n"); - initramfs_init(); - mm_init(); - timer_init(); - scheduler_init(); + kthread_init(); - kthread_set_init(); - kthread_create(shell); - - for (int i = 0; i < 3; ++i) { - kthread_create(foo); - } + uart_printf("[*] fdt base: %x\r\n", fdt_base); + uart_printf("[*] Kernel start!\r\n"); - uart_sync_printf("[*] Go!\r\n"); + kthread_create(shell); // Enable interrupt from Auxiliary peripherals irq1_enable(29); diff --git a/src/kernel/preempt.c b/src/kernel/preempt.c new file mode 100644 index 000000000..8660bda83 --- /dev/null +++ b/src/kernel/preempt.c @@ -0,0 +1,25 @@ +#include +#include +#include + +void preempt_disable(void) +{ + uint32 daif; + + daif = save_and_disable_interrupt(); + + current->preempt += 1; + + restore_interrupt(daif); +} + +void preempt_enable(void) +{ + uint32 daif; + + daif = save_and_disable_interrupt(); + + current->preempt -= 1; + + restore_interrupt(daif); +} \ No newline at end of file diff --git a/src/kernel/sched.c b/src/kernel/sched.c index 224adaf9e..7c3971276 100644 --- a/src/kernel/sched.c +++ b/src/kernel/sched.c @@ -3,6 +3,7 @@ #include #include #include +#include #define SCHEDULER_TIMER_HZ 1000 #define SCHEDULER_WATERMARK 15 @@ -41,6 +42,7 @@ void schedule(void) restore_interrupt(daif); + // Set registers. Set current to task switch_to(current, task); } @@ -57,11 +59,18 @@ void schedule_tick(void) void sched_add_task(task_struct *task) { - uint32 daif; - - daif = save_and_disable_interrupt(); + preempt_disable(); list_add_tail(&task->list, &run_queue); - restore_interrupt(daif); + preempt_enable(); +} + +void sched_del_task(task_struct *task) +{ + preempt_disable(); + + list_del(&task->list); + + preempt_enable(); } \ No newline at end of file diff --git a/src/kernel/waitqueue.c b/src/kernel/waitqueue.c new file mode 100644 index 000000000..9e2a69484 --- /dev/null +++ b/src/kernel/waitqueue.c @@ -0,0 +1,50 @@ +#include +#include +#include + +wait_queue_head *wq_create(void) +{ + wait_queue_head *head; + + head = kmalloc(sizeof(wait_queue_head)); + + INIT_LIST_HEAD(&head->list); + + return head; +} + +int wq_empty(wait_queue_head *head) +{ + return list_empty(&head->list); +} + +void wq_add_task(task_struct *task, wait_queue_head *head) +{ + preempt_disable(); + + list_add_tail(&task->list, &head->list); + + preempt_enable(); +} + +void wq_del_task(task_struct *task) +{ + preempt_disable(); + + list_del(&task->list); + + preempt_enable(); +} + +task_struct *wq_get_first_task(wait_queue_head *head) +{ + task_struct *task; + + preempt_disable(); + + task = list_first_entry(&head->list, task_struct, list); + + preempt_enable(); + + return task; +} \ No newline at end of file From be23b643bc96a81a668834bff8a7d58e8e0ce506 Mon Sep 17 00:00:00 2001 From: LJP-TW Date: Mon, 25 Apr 2022 04:07:32 -0700 Subject: [PATCH 06/16] Implement user process, syscall exit Separate user stack and kernel stack. Save / restore sp_el0 when switch el0 / el1. --- include/kernel/exec.h | 7 +- include/kernel/kthread.h | 1 + include/kernel/sched.h | 29 +-------- include/kernel/syscall.h | 3 +- include/kernel/task.h | 39 ++++++++++++ include/kernel/trapframe.h | 43 +++++++++++++ include/kernel/waitqueue.h | 2 +- initramfs/userprog1 | Bin 28 -> 36 bytes initramfs/userprog1.s | 11 +++- src/kernel/exec.S | 6 +- src/kernel/exec.c | 71 +++++++++++++++++++++ src/kernel/head.S | 33 +++------- src/kernel/kthread.c | 34 ++-------- src/kernel/main.c | 24 +------ src/kernel/preempt.c | 2 +- src/kernel/syscall.c | 127 +++++++++++++++++++++++++++++++------ src/kernel/task.c | 47 ++++++++++++++ 17 files changed, 345 insertions(+), 134 deletions(-) create mode 100644 include/kernel/task.h create mode 100644 include/kernel/trapframe.h create mode 100644 src/kernel/exec.c create mode 100644 src/kernel/task.c diff --git a/include/kernel/exec.h b/include/kernel/exec.h index e95cbf78a..b3883a5a5 100644 --- a/include/kernel/exec.h +++ b/include/kernel/exec.h @@ -1,8 +1,9 @@ #ifndef _EXEC_H #define _EXEC_H -// Change current EL to EL0 and execute the user program at @mem -// Set user stack to @user_sp -void exec_user_prog(char *mem, char *user_sp); +// TODO: Add argv & envp +void exec_user_prog(char *filename); + +void exit_user_prog(void); #endif /* _EXEC_H */ \ No newline at end of file diff --git a/include/kernel/kthread.h b/include/kernel/kthread.h index 433b63c16..f9651c92a 100644 --- a/include/kernel/kthread.h +++ b/include/kernel/kthread.h @@ -4,6 +4,7 @@ void kthread_init(void); void kthread_create(void (*start)(void)); +void kthread_fini(void); void kthread_kill_zombies(void); diff --git a/include/kernel/sched.h b/include/kernel/sched.h index 115024129..2cce0fb5d 100644 --- a/include/kernel/sched.h +++ b/include/kernel/sched.h @@ -1,34 +1,7 @@ #ifndef _SCHED_H #define _SCHED_H -#include -#include - -struct pt_regs { - void *x19; - void *x20; - void *x21; - void *x22; - void *x23; - void *x24; - void *x25; - void *x26; - void *x27; - void *x28; - void *fp; - void *lr; - void *sp; -}; - -typedef struct _task_struct { - /* This must be the first element */ - struct pt_regs regs; - void *kernel_stack; - struct list_head list; - uint32 need_resched:1; - uint32 tid; - uint32 preempt; -} task_struct; +#include void switch_to(task_struct *from, task_struct *to); diff --git a/include/kernel/syscall.h b/include/kernel/syscall.h index 0a0649411..f1a7593ac 100644 --- a/include/kernel/syscall.h +++ b/include/kernel/syscall.h @@ -2,9 +2,10 @@ #define _SYSCALL_H #include +#include // @syn: syndrome information for an synchronous exception // One should pass esr_el1 register value to @syn -void syscall_handler(uint32 syn); +void syscall_handler(trapframe regs, uint32 syn); #endif /* _SYSCALL_H */ \ No newline at end of file diff --git a/include/kernel/task.h b/include/kernel/task.h new file mode 100644 index 000000000..1db3d16a2 --- /dev/null +++ b/include/kernel/task.h @@ -0,0 +1,39 @@ +#ifndef _TASK_H +#define _TASK_H + +#include +#include + +struct pt_regs { + void *x19; + void *x20; + void *x21; + void *x22; + void *x23; + void *x24; + void *x25; + void *x26; + void *x27; + void *x28; + void *fp; + void *lr; + void *sp; +}; + +typedef struct _task_struct { + /* This must be the first element */ + struct pt_regs regs; + void *kernel_stack; + void *user_stack; + /* TODO: Update to address_space */ + void *data; + struct list_head list; + uint32 need_resched:1; + uint32 tid; + uint32 preempt; +} task_struct; + +task_struct *task_create(void); +void task_free(task_struct *task); + +#endif /* _TASK_H */ \ No newline at end of file diff --git a/include/kernel/trapframe.h b/include/kernel/trapframe.h new file mode 100644 index 000000000..806508196 --- /dev/null +++ b/include/kernel/trapframe.h @@ -0,0 +1,43 @@ +#ifndef _TRAPFRAME_H +#define _TRAPFRAME_H + +#include + +typedef struct { + uint64 x0; + uint64 x1; + uint64 x2; + uint64 x3; + uint64 x4; + uint64 x5; + uint64 x6; + uint64 x7; + uint64 x8; + uint64 x9; + uint64 x10; + uint64 x11; + uint64 x12; + uint64 x13; + uint64 x14; + uint64 x15; + uint64 x16; + uint64 x17; + uint64 x18; + uint64 x19; + uint64 x20; + uint64 x21; + uint64 x22; + uint64 x23; + uint64 x24; + uint64 x25; + uint64 x26; + uint64 x27; + uint64 x28; + uint64 x29; + uint64 x30; + uint64 sp_el0; + uint64 elr_el1; + uint64 spsr_el1; +} trapframe; + +#endif /* _TRAPFRAME_H */ \ No newline at end of file diff --git a/include/kernel/waitqueue.h b/include/kernel/waitqueue.h index 967a5823e..8c31735b3 100644 --- a/include/kernel/waitqueue.h +++ b/include/kernel/waitqueue.h @@ -1,7 +1,7 @@ #ifndef _WAITQUEUE_H #define _WAITQUEUE_H -#include +#include typedef struct { struct list_head list; diff --git a/initramfs/userprog1 b/initramfs/userprog1 index 409eb763b60c8bfdcb840d49b098974c0d1b07a9..237765563c33740a73f2b6917a89ccccc207970c 100755 GIT binary patch literal 36 pcmZQzXt>0{!Z6W;vEdRU1H%=05r&W5|Nn=q0E&b7|Nj3M2LRVl4m$t< literal 28 jcmZQzXt>0{!Z4AMf#Hh02*bzK|Nn<50@?rn{}%@Ud3_4! diff --git a/initramfs/userprog1.s b/initramfs/userprog1.s index bd5024d54..1e0ab6b7e 100644 --- a/initramfs/userprog1.s +++ b/initramfs/userprog1.s @@ -4,11 +4,16 @@ _start: mov x0, 0 1: add x0, x0, 1 - // syscall_test + + // syscall_show_info + mov x8, 10 svc 0 + cmp x0, 5 blt 1b 1: // syscall_exit - svc 1 - b 1b \ No newline at end of file + mov x8, 5 + svc 0 + + b 1b diff --git a/src/kernel/exec.S b/src/kernel/exec.S index f2e03a550..3ed7b153b 100644 --- a/src/kernel/exec.S +++ b/src/kernel/exec.S @@ -1,7 +1,7 @@ -// See include/kernel/exec.h for function declaration +// See include/kernel/exec.c for function declaration -.globl exec_user_prog -exec_user_prog: +.globl enter_el0_run_user_prog +enter_el0_run_user_prog: // Set exception return address msr elr_el1, x0 diff --git a/src/kernel/exec.c b/src/kernel/exec.c new file mode 100644 index 000000000..f2d2e7804 --- /dev/null +++ b/src/kernel/exec.c @@ -0,0 +1,71 @@ +#include +#include +#include +#include +#include +#include +#include + +#define STACK_SIZE (2 * PAGE_SIZE) + +// Change current EL to EL0 and execute the user program at @entry +// Set user stack to @user_sp +void enter_el0_run_user_prog(void *entry, char *user_sp); + +static void user_prog_start(void) +{ + char *user_sp; + + user_sp = (char *)current->user_stack + STACK_SIZE - 0x10; + + enter_el0_run_user_prog(current->data, user_sp); + + // User program should call exit() to terminate +} + +static inline void pt_regs_init(struct pt_regs *regs) +{ + regs->x19 = 0; + regs->x20 = 0; + regs->x21 = 0; + regs->x22 = 0; + regs->x23 = 0; + regs->x24 = 0; + regs->x25 = 0; + regs->x26 = 0; + regs->x27 = 0; + regs->x28 = 0; + regs->fp = 0; + regs->lr = user_prog_start; +} + +// TODO: Add argv & envp +void exec_user_prog(char *filename) +{ + task_struct *task; + + task = task_create(); + + task->kernel_stack = kmalloc(STACK_SIZE); + task->user_stack = kmalloc(STACK_SIZE); + task->data = cpio_load_prog(initramfs_base, filename); + + if (task->data == NULL) { + goto EXEC_USER_PROG_END; + } + + task->regs.sp = (char *)task->kernel_stack + STACK_SIZE - 0x10; + pt_regs_init(&task->regs); + + sched_add_task(task); + + return; + +EXEC_USER_PROG_END: + task_free(task); +} + +void exit_user_prog(void) +{ + kthread_fini(); +} \ No newline at end of file diff --git a/src/kernel/head.S b/src/kernel/head.S index 620d73be9..ff04f09f3 100644 --- a/src/kernel/head.S +++ b/src/kernel/head.S @@ -130,15 +130,15 @@ set_exception_vector_table: str x30, [sp, 16 * 15] .endif - mrs x0, elr_el\el - mrs x1, spsr_el\el + mrs x0, elr_el1 + mrs x1, spsr_el1 stp x0, x1, [sp, 16 * 16] .endm .macro kernel_exit el ldp x0, x1, [sp, 16 * 16] - msr elr_el\el, x0 - msr spsr_el\el, x1 + msr elr_el1, x0 + msr spsr_el1, x1 .if \el ==0 ldp x30, x0, [sp, 16 * 15] @@ -178,33 +178,20 @@ exception_handler: eret l64_syn_eh: - save_all - save_exception_reg - - // Get exception class ({EC[31:26]}) - mrs x0, esr_el1 - asr x1, x0, 26 - - // SVC instruction execution - cmp x1, 0x15 - bne l64_syn_eh_end + kernel_entry 0 + mov x0, sp + mrs x1, esr_el1 bl syscall_handler -l64_syn_eh_end: - load_exception_reg - load_all - eret + kernel_exit 0 l64_irq_eh: - save_all - save_exception_reg + kernel_entry 0 bl irq_handler - load_exception_reg - load_all - eret + kernel_exit 0 curr_syn_eh: save_all diff --git a/src/kernel/kthread.c b/src/kernel/kthread.c index bd1499f16..005ee0ca8 100644 --- a/src/kernel/kthread.c +++ b/src/kernel/kthread.c @@ -7,25 +7,8 @@ #define STACK_SIZE (2 * PAGE_SIZE) -static uint32 alloc_tid(void); -static void kthread_start(void); -static void kthread_fini(void); - static wait_queue_head *wait_queue; -// TODO: recycle usable tid -uint32 max_tid; - -static uint32 alloc_tid(void) -{ - uint32 tid; - - tid = max_tid; - max_tid += 1; - - return tid; -} - static void kthread_start(void) { void (*main)(void); @@ -42,7 +25,7 @@ static void kthread_start(void) /* * Add to wait_queue to wait some process to recycle this kthread */ -static void kthread_fini(void) +void kthread_fini(void) { preempt_disable(); @@ -60,11 +43,7 @@ void kthread_init(void) task_struct *task; // Initialze current task - task = kmalloc(sizeof(task_struct)); - - task->need_resched = 0; - task->tid = alloc_tid(); - task->preempt = 0; + task = task_create(); // Must set current first set_current(task); @@ -95,12 +74,9 @@ void kthread_create(void (*start)(void)) { task_struct *task; - task = kmalloc(sizeof(task_struct)); + task = task_create(); task->kernel_stack = kmalloc(STACK_SIZE); - task->need_resched = 0; - task->tid = alloc_tid(); - task->preempt = 0; task->regs.sp = (char *)task->kernel_stack + STACK_SIZE - 0x10; pt_regs_init(&task->regs, start); @@ -124,8 +100,6 @@ void kthread_kill_zombies(void) preempt_enable(); - kfree(task->kernel_stack); - // TODO: release tid - kfree(task); + task_free(task); } } \ No newline at end of file diff --git a/src/kernel/main.c b/src/kernel/main.c index 82d3dd2af..78a859d06 100644 --- a/src/kernel/main.c +++ b/src/kernel/main.c @@ -176,28 +176,8 @@ static void cmd_cat(char *filename) static void cmd_exec(char *filename) { - char *mem; - char *user_sp; - - mem = cpio_load_prog(initramfs_base, filename); - - if (mem == NULL) { - return; - } - - // Modify user stack to the bottom of page - user_sp = kmalloc(PAGE_SIZE); - - if (user_sp == NULL) { - kfree(mem); - return; - } - - user_sp += PAGE_SIZE - 0x8; - - exec_user_prog(mem, user_sp); - - // TODO: Free user_sp and mem + // TODO: Add argv & envp + exec_user_prog(filename); } static void cmd_parsedtb(void) diff --git a/src/kernel/preempt.c b/src/kernel/preempt.c index 8660bda83..5132698f5 100644 --- a/src/kernel/preempt.c +++ b/src/kernel/preempt.c @@ -1,5 +1,5 @@ #include -#include +#include #include void preempt_disable(void) diff --git a/src/kernel/syscall.c b/src/kernel/syscall.c index 0d83a052c..154580a8d 100644 --- a/src/kernel/syscall.c +++ b/src/kernel/syscall.c @@ -1,15 +1,34 @@ #include #include #include +#include -typedef void *(*funcp)(); +typedef void *(*syscall_funcp)(); -void *syscall_test(); -void *syscall_exit(); +void *syscall_getpid(void); +void *syscall_uartread(char buf[], size_t size); +void *syscall_uartwrite(const char buf[], size_t size); +void *syscall_exec(const char* name, char *const argv[]); +void *syscall_fork(void); +void *syscall_exit(void); +void *syscall_mbox_call(unsigned char ch, unsigned int *mbox); +void *syscall_kill_pid(int pid); +void *syscall_signal(int signal, void (*handler)(void)); +void *syscall_kill(int pid, int signal); +void *syscall_show_info(void); -funcp syscall_table[] = { - syscall_test, // 0 - syscall_exit, // 1 +syscall_funcp syscall_table[] = { + (syscall_funcp) syscall_getpid, // 0 + (syscall_funcp) syscall_uartread, + (syscall_funcp) syscall_uartwrite, + (syscall_funcp) syscall_exec, + (syscall_funcp) syscall_fork, // 4 + (syscall_funcp) syscall_exit, + (syscall_funcp) syscall_mbox_call, + (syscall_funcp) syscall_kill_pid, + (syscall_funcp) syscall_signal, // 8 + (syscall_funcp) syscall_kill, + (syscall_funcp) syscall_show_info, }; typedef struct { @@ -18,25 +37,100 @@ typedef struct { ec:6; // Exception class } esr_el1; -void syscall_handler(uint32 syn) +void syscall_handler(trapframe regs, uint32 syn) { - esr_el1 *esr = (esr_el1 *)&syn; + esr_el1 *esr; + uint64 syscall_num; + + esr = (esr_el1 *)&syn; - int syscall_num = esr->iss & 0xffff; + // SVC instruction execution + if (esr->ec != 0x15) { + return; + } + + syscall_num = regs.x8; if (syscall_num >= ARRAY_SIZE(syscall_table)) { // Invalid syscall return; } - // TODO: bring the arguments to syscall enable_interrupt(); - (syscall_table[syscall_num])(); + (syscall_table[syscall_num])( + regs.x0, + regs.x1, + regs.x2, + regs.x3, + regs.x4, + regs.x5 + ); disable_interrupt(); } +void *syscall_getpid(void) +{ + // TODO + return NULL; +} + +void *syscall_uartread(char buf[], size_t size) +{ + // TODO + return NULL; +} + +void *syscall_uartwrite(const char buf[], size_t size) +{ + // TODO + return NULL; +} + +void *syscall_exec(const char* name, char *const argv[]) +{ + // TODO + return NULL; +} + +void *syscall_fork(void) +{ + // TODO + return NULL; +} + +void *syscall_exit(void) +{ + exit_user_prog(); + + return NULL; +} + +void *syscall_mbox_call(unsigned char ch, unsigned int *mbox) +{ + // TODO + return NULL; +} + +void *syscall_kill_pid(int pid) +{ + // TODO + return NULL; +} + +void *syscall_signal(int signal, void (*handler)(void)) +{ + // TODO + return NULL; +} + +void *syscall_kill(int pid, int signal) +{ + // TODO + return NULL; +} + // Print the content of spsr_el1, elr_el1 and esr_el1 -void *syscall_test() +void *syscall_show_info(void) { uint64 spsr_el1; uint64 elr_el1; @@ -46,13 +140,8 @@ void *syscall_test() elr_el1 = read_sysreg(elr_el1); esr_el1 = read_sysreg(esr_el1); - uart_printf("[TEST] spsr_el1: %llx; elr_el1: %llx; esr_el1: %llx\r\n", + uart_printf("[TEST] spsr_el1: %llx; elr_el1: %llx; esr_el1: %llx\r\n", spsr_el1, elr_el1, esr_el1); return NULL; -} - -void *syscall_exit() -{ - return NULL; -} +} \ No newline at end of file diff --git a/src/kernel/task.c b/src/kernel/task.c new file mode 100644 index 000000000..76e93513e --- /dev/null +++ b/src/kernel/task.c @@ -0,0 +1,47 @@ +#include +#include + +// TODO: recycle usable tid +uint32 max_tid; + +static uint32 alloc_tid(void) +{ + uint32 tid; + + tid = max_tid; + max_tid += 1; + + return tid; +} + +task_struct *task_create(void) +{ + task_struct *task; + + task = kmalloc(sizeof(task_struct)); + + task->kernel_stack = NULL; + task->user_stack = NULL; + task->data = NULL; + task->need_resched = 0; + task->tid = alloc_tid(); + task->preempt = 0; + + return task; +} + +void task_free(task_struct *task) +{ + if (task->kernel_stack) + kfree(task->kernel_stack); + + if (task->user_stack) + kfree(task->user_stack); + + if (task->data) + kfree(task->data); + + // TODO: release tid + + kfree(task); +} \ No newline at end of file From 73b803941e85f011eed99fb14bf1970251100b26 Mon Sep 17 00:00:00 2001 From: LJP-TW Date: Mon, 25 Apr 2022 11:28:14 -0700 Subject: [PATCH 07/16] Implement syscall getpid, uart_write --- include/kernel/mini_uart.h | 6 +-- initramfs/Makefile | 19 ++++++++- initramfs/linker.ld | 4 ++ initramfs/userprog2 | Bin 0 -> 748 bytes initramfs/userprog2.c | 84 +++++++++++++++++++++++++++++++++++++ src/kernel/exec.c | 17 ++++---- src/kernel/mini_uart.c | 8 ++-- src/kernel/syscall.c | 84 ++++++++++++++++--------------------- 8 files changed, 157 insertions(+), 65 deletions(-) create mode 100755 initramfs/userprog2 create mode 100644 initramfs/userprog2.c diff --git a/include/kernel/mini_uart.h b/include/kernel/mini_uart.h index 19da47700..03552d8fd 100644 --- a/include/kernel/mini_uart.h +++ b/include/kernel/mini_uart.h @@ -8,10 +8,10 @@ void uart_init(void); char uart_recv(void); uint32 uart_recv_uint(void); void uart_send(char c); -void uart_sendn(char *str, int n); -void uart_printf(char *fmt, ...); +void uart_sendn(const char *str, int n); +void uart_printf(const char *fmt, ...); -void uart_sync_printf(char *fmt, ...); +void uart_sync_printf(const char *fmt, ...); int uart_irq_check(void); diff --git a/initramfs/Makefile b/initramfs/Makefile index 3a1f56b3b..43e87bd49 100644 --- a/initramfs/Makefile +++ b/initramfs/Makefile @@ -2,6 +2,10 @@ CROSS_COMPILE ?= aarch64-linux-gnu- CC := $(CROSS_COMPILE)gcc LD := $(CROSS_COMPILE)ld +CFLAGS := -Wall -nostdlib -nostartfiles -ffreestanding -mgeneral-regs-only + +all: userprog1 userprog2 + userprog1: userprog1.elf $(CROSS_COMPILE)objcopy -O binary $^ $@ @@ -11,6 +15,19 @@ userprog1.elf: linker.ld userprog1.o userprog1.o: userprog1.s $(CC) $(CFLAGS) -c $< -o $@ +userprog2: userprog2.elf + $(CROSS_COMPILE)objcopy -O binary $^ $@ + +userprog2.elf: linker.ld userprog2.o + $(LD) $(LDFLAGS) -T $< -o $@ userprog2.o + +userprog2.o: userprog2.c + $(CC) $(CFLAGS) -c $< -o $@ + .PHONY: clean clean: - rm -f *.o *.elf \ No newline at end of file + rm -f *.o *.elf + +.PHONY: clean-all +clean-all: clean + rm -f userprog1 userprog2 \ No newline at end of file diff --git a/initramfs/linker.ld b/initramfs/linker.ld index b525f56a6..ab050c29d 100644 --- a/initramfs/linker.ld +++ b/initramfs/linker.ld @@ -1,5 +1,9 @@ SECTIONS { + .start : { + *(.start) + } + .text : { *(.text) } diff --git a/initramfs/userprog2 b/initramfs/userprog2 new file mode 100755 index 0000000000000000000000000000000000000000..de5abe4932641ae66ca00c7d742a1732bd522a29 GIT binary patch literal 748 zcmaJ;L2DC17=61NO(D`YCQu=zyUD?dXCZ+cGHs6$soUP$qu@owLva@x@an;!;Gral zcrfB0SP)I6-g>cGZ^~@aihp6S+wskA(Bi>`x4ZM+y!XA`NrJb7#6eeY+XKCA4RjOH z2Jlq25P3j3Ziz_lKk|qBZ|-@aw}X?-&vs~+ywEKz18wQpS8;z~4X_K?a@T6)mgaF$ zHbrFTP#iI@Iz+KX4xxAwKSZ~7%WFvH#?0Mit`$~ys?4o27tH0{wwZ7CxWL``mtNO( zMAN1Zb7ftaZf)dn^Ka&6L)JS{yfVq>9_mF&U(9#Yrv=9fclY#`soTK zD?-I{LXAp7jc0^9DhPF)7s>*@$VDi*C=_$LCNBxzrRQ-Tor7~kj&KN@un5jR7;F8E zGb8DWC<#8KJ(A%4e|^vCJEYI`oWms8op`cYl6_wLVF*^(TKmPG&Gr?=t z+;~|JeB`zktjYx!^ITsdUM5-#ek7KrMQ^H~w{Lv^#xq2jXb^j+TCeg+ebuL6d}e(@ q-st4LUas$4&upoFhjdwM&9gB2Y|rjn?KApg(pRX9Oi%rjvG@%fcn`w> literal 0 HcmV?d00001 diff --git a/initramfs/userprog2.c b/initramfs/userprog2.c new file mode 100644 index 000000000..4a73fec1b --- /dev/null +++ b/initramfs/userprog2.c @@ -0,0 +1,84 @@ +#include + +typedef unsigned long long int uint64; + +#define SYS_GETPID 0 +#define SYS_UART_WRITE 2 +#define SYS_EXIT 5 + +int start(void) __attribute__((section(".start"))); + +uint64 syscall(uint64 syscall_num, + void *x0, + void *x1, + void *x2, + void *x3, + void *x4, + void *x5) +{ + uint64 result; + + asm volatile ( + "ldr x8, %0\n" + "ldr x0, %1\n" + "ldr x1, %2\n" + "ldr x2, %3\n" + "ldr x3, %4\n" + "ldr x4, %5\n" + "ldr x5, %6\n" + "svc 0\n" + :: "m" (syscall_num), "m" (x0), "m" (x1), + "m" (x2), "m" (x3), "m" (x4), "m" (x5) + ); + + asm volatile ( + "str x0, %0\n" + : "=m" (result) + ); + + return result; +} + +int getpid() +{ + int pid = syscall(SYS_GETPID, 0, 0, 0, 0, 0, 0); + return pid; +} + +void exit(void) +{ + syscall(SYS_EXIT, 0, 0, 0, 0, 0, 0); +} + +void uart_write(const char buf[], size_t size) +{ + syscall(SYS_UART_WRITE, (void *)buf, (void *)size, 0, 0, 0, 0); +} + +int start(void) +{ + char buf1[0x10] = { 0 }; + char buf2[0x10] = { 0 }; + int pid, idx; + + idx = 0; + pid = getpid(); + + while (pid) { + buf1[idx++] = '0' + pid % 10; + pid /= 10; + } + + for (int i = 0; i < idx; ++i) { + buf2[i] = buf1[idx - i - 1]; + } + + buf2[idx] = '\r'; + buf2[idx+1] = '\n'; + + uart_write(buf2, idx+2); + + exit(); + + return 0; +} \ No newline at end of file diff --git a/src/kernel/exec.c b/src/kernel/exec.c index f2d2e7804..01ad7e97d 100644 --- a/src/kernel/exec.c +++ b/src/kernel/exec.c @@ -42,27 +42,28 @@ static inline void pt_regs_init(struct pt_regs *regs) // TODO: Add argv & envp void exec_user_prog(char *filename) { + void *data; task_struct *task; + data = cpio_load_prog(initramfs_base, filename); + + if (data == NULL) { + goto EXEC_USER_PROG_END; + } + task = task_create(); task->kernel_stack = kmalloc(STACK_SIZE); task->user_stack = kmalloc(STACK_SIZE); - task->data = cpio_load_prog(initramfs_base, filename); - - if (task->data == NULL) { - goto EXEC_USER_PROG_END; - } + task->data = data; task->regs.sp = (char *)task->kernel_stack + STACK_SIZE - 0x10; pt_regs_init(&task->regs); sched_add_task(task); - return; - EXEC_USER_PROG_END: - task_free(task); + return; } void exit_user_prog(void) diff --git a/src/kernel/mini_uart.c b/src/kernel/mini_uart.c index 04f724943..b8fa17973 100644 --- a/src/kernel/mini_uart.c +++ b/src/kernel/mini_uart.c @@ -126,7 +126,7 @@ uint32 uart_recvline(char *buff, int maxlen) return cnt; } -void uart_sendn(char *str, int n) +void uart_sendn(const char *str, int n) { while (n--) { (uart_send_fp)(*str++); @@ -175,7 +175,7 @@ static void uart_send_num(sendfp _send_fp, int64 num, int base, int type) } // Ref: https://elixir.bootlin.com/linux/v3.5/source/arch/x86/boot/printf.c#L115 -static void _uart_printf(sendfp _send_fp, char *fmt, va_list args) +static void _uart_printf(sendfp _send_fp, const char *fmt, va_list args) { const char *s; char c; @@ -226,7 +226,7 @@ static void _uart_printf(sendfp _send_fp, char *fmt, va_list args) } } -void uart_printf(char *fmt, ...) +void uart_printf(const char *fmt, ...) { va_list args; va_start(args, fmt); @@ -236,7 +236,7 @@ void uart_printf(char *fmt, ...) va_end(args); } -void uart_sync_printf(char *fmt, ...) +void uart_sync_printf(const char *fmt, ...) { va_list args; va_start(args, fmt); diff --git a/src/kernel/syscall.c b/src/kernel/syscall.c index 154580a8d..422307d99 100644 --- a/src/kernel/syscall.c +++ b/src/kernel/syscall.c @@ -2,25 +2,28 @@ #include #include #include +#include +#include +#include -typedef void *(*syscall_funcp)(); +typedef void (*syscall_funcp)(); -void *syscall_getpid(void); -void *syscall_uartread(char buf[], size_t size); -void *syscall_uartwrite(const char buf[], size_t size); -void *syscall_exec(const char* name, char *const argv[]); -void *syscall_fork(void); -void *syscall_exit(void); -void *syscall_mbox_call(unsigned char ch, unsigned int *mbox); -void *syscall_kill_pid(int pid); -void *syscall_signal(int signal, void (*handler)(void)); -void *syscall_kill(int pid, int signal); -void *syscall_show_info(void); +void syscall_getpid(trapframe *_); +void syscall_uart_read(trapframe *_, char buf[], size_t size); +void syscall_uart_write(trapframe *_, const char buf[], size_t size); +void syscall_exec(trapframe *_, const char* name, char *const argv[]); +void syscall_fork(trapframe *_); +void syscall_exit(trapframe *_); +void syscall_mbox_call(trapframe *_, unsigned char ch, unsigned int *mbox); +void syscall_kill_pid(trapframe *_, int pid); +void syscall_signal(trapframe *_, int signal, void (*handler)(void)); +void syscall_kill(trapframe *_, int pid, int signal); +void syscall_show_info(trapframe *_); syscall_funcp syscall_table[] = { (syscall_funcp) syscall_getpid, // 0 - (syscall_funcp) syscall_uartread, - (syscall_funcp) syscall_uartwrite, + (syscall_funcp) syscall_uart_read, + (syscall_funcp) syscall_uart_write, (syscall_funcp) syscall_exec, (syscall_funcp) syscall_fork, // 4 (syscall_funcp) syscall_exit, @@ -51,86 +54,71 @@ void syscall_handler(trapframe regs, uint32 syn) syscall_num = regs.x8; - if (syscall_num >= ARRAY_SIZE(syscall_table)) { + if (syscall_num > ARRAY_SIZE(syscall_table)) { // Invalid syscall return; } enable_interrupt(); - (syscall_table[syscall_num])( - regs.x0, - regs.x1, - regs.x2, - regs.x3, - regs.x4, - regs.x5 - ); + + (syscall_table[syscall_num])(®s, + regs.x0, regs.x1, regs.x2, regs.x3, regs.x4, regs.x5); + disable_interrupt(); } -void *syscall_getpid(void) +void syscall_getpid(trapframe *frame) { - // TODO - return NULL; + frame->x0 = current->tid; } -void *syscall_uartread(char buf[], size_t size) +void syscall_uart_read(trapframe *_, char buf[], size_t size) { // TODO - return NULL; } -void *syscall_uartwrite(const char buf[], size_t size) +void syscall_uart_write(trapframe *_, const char buf[], size_t size) { - // TODO - return NULL; + uart_sendn(buf, size); } -void *syscall_exec(const char* name, char *const argv[]) +void syscall_exec(trapframe *_, const char* name, char *const argv[]) { // TODO - return NULL; } -void *syscall_fork(void) +void syscall_fork(trapframe *_) { // TODO - return NULL; } -void *syscall_exit(void) +void syscall_exit(trapframe *_) { exit_user_prog(); - - return NULL; } -void *syscall_mbox_call(unsigned char ch, unsigned int *mbox) +void syscall_mbox_call(trapframe *_, unsigned char ch, unsigned int *mbox) { // TODO - return NULL; } -void *syscall_kill_pid(int pid) +void syscall_kill_pid(trapframe *_, int pid) { // TODO - return NULL; } -void *syscall_signal(int signal, void (*handler)(void)) +void syscall_signal(trapframe *_, int signal, void (*handler)(void)) { // TODO - return NULL; } -void *syscall_kill(int pid, int signal) +void syscall_kill(trapframe *_, int pid, int signal) { // TODO - return NULL; } // Print the content of spsr_el1, elr_el1 and esr_el1 -void *syscall_show_info(void) +void syscall_show_info(trapframe *_) { uint64 spsr_el1; uint64 elr_el1; @@ -142,6 +130,4 @@ void *syscall_show_info(void) uart_printf("[TEST] spsr_el1: %llx; elr_el1: %llx; esr_el1: %llx\r\n", spsr_el1, elr_el1, esr_el1); - - return NULL; } \ No newline at end of file From 3b848b1fef0f6a05f30bb9c783d6a7d94775b38a Mon Sep 17 00:00:00 2001 From: LJP-TW Date: Mon, 25 Apr 2022 11:40:05 -0700 Subject: [PATCH 08/16] Implement syscall uart_read --- include/kernel/mini_uart.h | 1 + initramfs/userprog2 | Bin 748 -> 924 bytes initramfs/userprog2.c | 12 ++++++++++++ src/kernel/mini_uart.c | 7 +++++++ src/kernel/syscall.c | 2 +- 5 files changed, 21 insertions(+), 1 deletion(-) diff --git a/include/kernel/mini_uart.h b/include/kernel/mini_uart.h index 03552d8fd..ef83dedf6 100644 --- a/include/kernel/mini_uart.h +++ b/include/kernel/mini_uart.h @@ -6,6 +6,7 @@ uint32 uart_recvline(char *buff, int maxlen); void uart_init(void); char uart_recv(void); +void uart_recvn(char *buff, int n); uint32 uart_recv_uint(void); void uart_send(char c); void uart_sendn(const char *str, int n); diff --git a/initramfs/userprog2 b/initramfs/userprog2 index de5abe4932641ae66ca00c7d742a1732bd522a29..16822cbce29f345e0793efcceaf3236105c28a1d 100755 GIT binary patch delta 247 zcmaFEI){CN2xIO>QE^7gAO?mh51JV!GBP$?vInvk0%-;Yh6xN0xF&id$$0?Tjto#a z1@4J1lXV$?^D6*Fj{g5YU0#9t>fh=^lfN^XYHUUDR~%rDzXmjoAv&};wJ260sWi>d zN&(2{Kwp8x;= delta 106 zcmbQk{)Tme2xI(4QE^5_lgX)!zb7wXVws%6Bry35lY-)szyJR`FfuSOIPy8n<(S9L z diff --git a/initramfs/userprog2.c b/initramfs/userprog2.c index 4a73fec1b..a3b357b68 100644 --- a/initramfs/userprog2.c +++ b/initramfs/userprog2.c @@ -3,6 +3,7 @@ typedef unsigned long long int uint64; #define SYS_GETPID 0 +#define SYS_UART_RECV 1 #define SYS_UART_WRITE 2 #define SYS_EXIT 5 @@ -50,6 +51,11 @@ void exit(void) syscall(SYS_EXIT, 0, 0, 0, 0, 0, 0); } +void uart_recv(const char buf[], size_t size) +{ + syscall(SYS_UART_RECV, (void *)buf, (void *)size, 0, 0, 0, 0); +} + void uart_write(const char buf[], size_t size) { syscall(SYS_UART_WRITE, (void *)buf, (void *)size, 0, 0, 0, 0); @@ -78,6 +84,12 @@ int start(void) uart_write(buf2, idx+2); + uart_recv(buf1, 8); + + uart_write("[User] buf1: ", 13); + uart_write(buf1, 8); + uart_write("\r\n", 2); + exit(); return 0; diff --git a/src/kernel/mini_uart.c b/src/kernel/mini_uart.c index b8fa17973..9e220a84c 100644 --- a/src/kernel/mini_uart.c +++ b/src/kernel/mini_uart.c @@ -88,6 +88,13 @@ void uart_send(char c) (uart_send_fp)(c); } +void uart_recvn(char *buff, int n) +{ + while (n--) { + *buff++ = (uart_recv_fp)(); + } +} + uint32 uart_recv_uint(void) { char buf[4]; diff --git a/src/kernel/syscall.c b/src/kernel/syscall.c index 422307d99..834fbbc09 100644 --- a/src/kernel/syscall.c +++ b/src/kernel/syscall.c @@ -74,7 +74,7 @@ void syscall_getpid(trapframe *frame) void syscall_uart_read(trapframe *_, char buf[], size_t size) { - // TODO + uart_recvn(buf, size); } void syscall_uart_write(trapframe *_, const char buf[], size_t size) From 20c80b8c42e49cd1b95e8fcea79d7af925a10a57 Mon Sep 17 00:00:00 2001 From: LJP-TW Date: Mon, 25 Apr 2022 12:18:53 -0700 Subject: [PATCH 09/16] Implement syscall mbox_call --- include/lib/rpi3.h | 1 + initramfs/userprog2 | Bin 924 -> 2768 bytes initramfs/userprog2.c | 162 ++++++++++++++++++++++++++++++++++++++++-- src/kernel/syscall.c | 3 +- src/lib/rpi3.c | 8 +-- 5 files changed, 165 insertions(+), 9 deletions(-) diff --git a/include/lib/rpi3.h b/include/lib/rpi3.h index 1822b096d..90d9ab894 100644 --- a/include/lib/rpi3.h +++ b/include/lib/rpi3.h @@ -6,6 +6,7 @@ struct arm_memory_info { unsigned int size; }; +void mailbox_call(unsigned char channel, unsigned int *mb); unsigned int get_board_revision(void); void get_arm_memory(struct arm_memory_info *); diff --git a/initramfs/userprog2 b/initramfs/userprog2 index 16822cbce29f345e0793efcceaf3236105c28a1d..0a20233258ef71e286bd1afa73a2fa3a6b378adb 100755 GIT binary patch literal 2768 zcmdT`U2GIp6h3!$`vd){TXba)R2b9_$CU_^o%Lcqm%t0Z-O|6*QHlD@f9!KpvNMLHvwm zroiQ#%>W%EqEX7P(#IH$pTZKG;Byl=rJPplZ$ow;^ocU@V*2#aLSWC2b{G3zsAQSV zWKB1cHPb-W)G8?%y-N3DxW!$=4#jPt9++svOh&5!1HQWM^ zF8PY-FPz`8oHA2oSV61+mV(8w;CpJuw%>(ML#W&+rcXI>6w_bc(Jl|W^RQF3!1-c& z(z9`W3B+q6UV*sg`<+HzOvJ3g{>-d>$>-hMbJ%};JNqGuiXqa&(D`kF&gV{EGDdqn z8B5SRVm*F$CnkD}h(~{ijacvX33TS;viDNx7n!@8|5slA#w@qlNXB#nY{3itKb|K_ zLIt86S1hD7rikW;j8r&dbV?4s;%V5>2oi}$s2Z}O#16ZJrIMoFWGin)&lVn z?v#*m<1F+4^_Kj<_VWMK$^W|i?a{l}1MJwhk`KKq>#B}ZUmkTReUF2?P{M{Ndh{wc0%xB z^2~Cviwt`Y<`dqonE=z1K|aBQG?5I(u(JvIrpfn9*1rn%cW2x;x6XLXSZBr$@#umX zk9ehh0rPj8m*@O`^SCwNyzhez`p}t0KVF1ztv}d4f4~#cf0t8Y#^}c= z160cp9a@}P6swR_nr3LF0Oa#>fkYV?CM$5tFp2z~Y{x0bl=E+L9H$u5l7ExSfV@5b pCQk!W7yeD2#U(ZQ0w;^ahkyV7JAgDf@+r(^naAvR?=ByR3jp2uEPMa} diff --git a/initramfs/userprog2.c b/initramfs/userprog2.c index a3b357b68..2157b1375 100644 --- a/initramfs/userprog2.c +++ b/initramfs/userprog2.c @@ -1,11 +1,23 @@ #include +#include + +#define SIGN 1 typedef unsigned long long int uint64; +typedef unsigned int uint32; +typedef unsigned short uint16; +typedef unsigned char uint8; + +typedef long long int int64; +typedef int int32; +typedef short int16; +typedef char int8; #define SYS_GETPID 0 #define SYS_UART_RECV 1 #define SYS_UART_WRITE 2 #define SYS_EXIT 5 +#define SYS_MBOX_CALL 6 int start(void) __attribute__((section(".start"))); @@ -61,11 +73,151 @@ void uart_write(const char buf[], size_t size) syscall(SYS_UART_WRITE, (void *)buf, (void *)size, 0, 0, 0, 0); } +static void uart_send_char(char c) +{ + uart_write(&c, 1); +} + +static void uart_send_string(const char *str) +{ + for (int i = 0; str[i] != '\0'; i++) { + uart_send_char(str[i]); + } +} + +static void uart_send_num(int64 num, int base, int type) +{ + static const char digits[16] = "0123456789ABCDEF"; + char tmp[66]; + int i; + + if (type | SIGN) { + if (num < 0) { + uart_send_char('-'); + } + } + + i = 0; + + if (num == 0) { + tmp[i++] = '0'; + } else { + while (num != 0) { + uint8 r = (uint32)num % base; + num = (uint32)num / base; + tmp[i++] = digits[r]; + } + } + + while (--i >= 0) { + uart_send_char(tmp[i]); + } +} + +static void _uart_printf(const char *fmt, va_list args) +{ + const char *s; + char c; + uint64 num; + char width; + + for (; *fmt; ++fmt) { + if (*fmt != '%') { + uart_send_char(*fmt); + continue; + } + + ++fmt; + + // Get width + width = 0; + if (fmt[0] == 'l' && fmt[1] == 'l') { + width = 1; + fmt += 2; + } + + switch (*fmt) { + case 'c': + c = va_arg(args, uint32) & 0xff; + uart_send_char(c); + continue; + case 'd': + if (width) { + num = va_arg(args, int64); + } else { + num = va_arg(args, int32); + } + uart_send_num(num, 10, SIGN); + continue; + case 's': + s = va_arg(args, char *); + uart_send_string(s); + continue; + case 'x': + if (width) { + num = va_arg(args, uint64); + } else { + num = va_arg(args, uint32); + } + uart_send_num(num, 16, 0); + continue; + } + } +} + +void uart_printf(const char *fmt, ...) +{ + va_list args; + va_start(args, fmt); + + _uart_printf(fmt, args); + + va_end(args); +} + +void mbox_call(unsigned char ch, unsigned int *mbox) +{ + syscall(SYS_MBOX_CALL, (void *)(uint64)ch, mbox, 0, 0, 0, 0); +} + +/* Channels */ +#define MAILBOX_CH_PROP 8 + +/* Tags */ +#define TAG_REQUEST_CODE 0x00000000 +#define END_TAG 0x00000000 + +/* Tag identifier */ +#define GET_BOARD_REVISION 0x00010002 + +/* Others */ +#define REQUEST_CODE 0x00000000 + +static unsigned int __attribute__((aligned(0x10))) mailbox[16]; + +// It should be 0xa020d3 for rpi3 b+ +unsigned int get_board_revision(void) +{ + mailbox[0] = 7 * 4; // Buffer size in bytes + mailbox[1] = REQUEST_CODE; + // Tags begin + mailbox[2] = GET_BOARD_REVISION; // Tag identifier + mailbox[3] = 4; // Value buffer size in bytes + mailbox[4] = TAG_REQUEST_CODE; // Request/response codes + mailbox[5] = 0; // Optional value buffer + // Tags end + mailbox[6] = END_TAG; + + mbox_call(MAILBOX_CH_PROP, mailbox); // Message passing procedure call + + return mailbox[5]; +} + int start(void) { char buf1[0x10] = { 0 }; char buf2[0x10] = { 0 }; - int pid, idx; + int pid, idx, revision; idx = 0; pid = getpid(); @@ -86,9 +238,11 @@ int start(void) uart_recv(buf1, 8); - uart_write("[User] buf1: ", 13); - uart_write(buf1, 8); - uart_write("\r\n", 2); + uart_printf("[User] buf1: %s\r\n", buf1); + + revision = get_board_revision(); + + uart_printf("revision: %x\r\n", revision); exit(); diff --git a/src/kernel/syscall.c b/src/kernel/syscall.c index 834fbbc09..074b7ed50 100644 --- a/src/kernel/syscall.c +++ b/src/kernel/syscall.c @@ -5,6 +5,7 @@ #include #include #include +#include typedef void (*syscall_funcp)(); @@ -99,7 +100,7 @@ void syscall_exit(trapframe *_) void syscall_mbox_call(trapframe *_, unsigned char ch, unsigned int *mbox) { - // TODO + mailbox_call(ch, mbox); } void syscall_kill_pid(trapframe *_, int pid) diff --git a/src/lib/rpi3.c b/src/lib/rpi3.c index 6778e9e1e..471e2a308 100644 --- a/src/lib/rpi3.c +++ b/src/lib/rpi3.c @@ -40,11 +40,11 @@ // Aligned buffer static unsigned int __attribute__((aligned(0x10))) mailbox[16]; -static void mailbox_call(void) +void mailbox_call(unsigned char channel, unsigned int *mb) { // Write the data (shifted into the upper 28 bits) combined with // the channel (in the lower four bits) to the write register. - unsigned int r = (((unsigned long)mailbox) & ~0xf) | MAILBOX_CH_PROP; + unsigned int r = (((unsigned long)mb) & ~0xf) | channel; // Check if Mailbox 0 status register’s full flag is set. while ((get32(MAILBOX_STATUS) & MAILBOX_FULL)) {}; @@ -76,7 +76,7 @@ unsigned int get_board_revision(void) // Tags end mailbox[6] = END_TAG; - mailbox_call(); // Message passing procedure call + mailbox_call(MAILBOX_CH_PROP, mailbox); // Message passing procedure call return mailbox[5]; } @@ -94,7 +94,7 @@ void get_arm_memory(struct arm_memory_info *info) // Tags end mailbox[7] = END_TAG; - mailbox_call(); // Message passing procedure call + mailbox_call(MAILBOX_CH_PROP, mailbox); // Message passing procedure call info->baseaddr = mailbox[5]; info->size = mailbox[6]; From d307f369fd2dcc6d7fa5c7037d1249b5cb846d06 Mon Sep 17 00:00:00 2001 From: LJP-TW Date: Tue, 26 Apr 2022 00:46:20 -0700 Subject: [PATCH 10/16] Implement syscall kill_pid --- include/kernel/kthread.h | 4 ++++ include/kernel/task.h | 15 ++++++++++++++- initramfs/userprog2 | Bin 2768 -> 2872 bytes initramfs/userprog2.c | 8 ++++++++ src/kernel/exec.c | 2 ++ src/kernel/kthread.c | 9 +++++++++ src/kernel/main.c | 1 + src/kernel/sched.c | 2 ++ src/kernel/syscall.c | 27 ++++++++++++++++++++++++++- src/kernel/task.c | 26 ++++++++++++++++++++++++++ 10 files changed, 92 insertions(+), 2 deletions(-) diff --git a/include/kernel/kthread.h b/include/kernel/kthread.h index f9651c92a..129ba07c2 100644 --- a/include/kernel/kthread.h +++ b/include/kernel/kthread.h @@ -1,11 +1,15 @@ #ifndef _KTHREAD_H #define _KTHREAD_H +#include + void kthread_init(void); void kthread_create(void (*start)(void)); void kthread_fini(void); +void kthread_add_wait_queue(task_struct *task); + void kthread_kill_zombies(void); #endif /* _KTHREAD_H */ \ No newline at end of file diff --git a/include/kernel/task.h b/include/kernel/task.h index 1db3d16a2..4e7db05d4 100644 --- a/include/kernel/task.h +++ b/include/kernel/task.h @@ -4,6 +4,11 @@ #include #include +/* Task status */ +#define TASK_NEW 0 +#define TASK_RUNNING 1 +#define TASK_DEAD 2 + struct pt_regs { void *x19; void *x20; @@ -27,13 +32,21 @@ typedef struct _task_struct { void *user_stack; /* TODO: Update to address_space */ void *data; + /* @list is used by run_queue / wait_queue */ struct list_head list; - uint32 need_resched:1; + /* @task_list links all tasks */ + struct list_head task_list; + uint16 status; + uint16 need_resched:1; uint32 tid; uint32 preempt; } task_struct; +void task_init(void); + task_struct *task_create(void); void task_free(task_struct *task); +task_struct *task_get_by_tid(uint32 tid); + #endif /* _TASK_H */ \ No newline at end of file diff --git a/initramfs/userprog2 b/initramfs/userprog2 index 0a20233258ef71e286bd1afa73a2fa3a6b378adb..1fda25c5e1ed3a275b3b5da1de6cd9089893d5b8 100755 GIT binary patch delta 415 zcmYjLO-lk%6utM&Kr=&#&?q9(vk!N*62hQhT()Q*fTyxNtr$=bV1zIvVp!HyvMtx~i~_s$j?YIC?gJi0^hegH;sqV9OsE2Mx5grHE%^Ck8zet=b&9gW2{w4!|5^S;R$R{;8=i>G66;IUa6DO$Ukm7u3x%4 zH+tI66Nw<-jjj3emr{bJKsMwwjn)*)zrBWt+H@JZmv5OjqiD;0ljD*+HaT;K^300M zzNxc906$C}h5V$CBN?$c>kZ|KHH&SzZ7neGM;;Jy<$oL#9`;(>Vqp-4lu`Gn{2=tVtM4- z|Nj+0XD~SOIn3pl$IcXU?=ByZD+0t8KrHj)|Nj6W4U`WE0!qjLnIL}1status = TASK_DEAD; + sched_del_task(current); wq_add_task(current, wait_queue); @@ -36,6 +43,8 @@ void kthread_fini(void) preempt_enable(); schedule(); + + // Never reach } void kthread_init(void) diff --git a/src/kernel/main.c b/src/kernel/main.c index 78a859d06..6074686ba 100644 --- a/src/kernel/main.c +++ b/src/kernel/main.c @@ -298,6 +298,7 @@ void start_kernel(char *fdt) initramfs_init(); mm_init(); timer_init(); + task_init(); scheduler_init(); kthread_init(); diff --git a/src/kernel/sched.c b/src/kernel/sched.c index 7c3971276..a0524c9c0 100644 --- a/src/kernel/sched.c +++ b/src/kernel/sched.c @@ -61,6 +61,8 @@ void sched_add_task(task_struct *task) { preempt_disable(); + task->status = TASK_RUNNING; + list_add_tail(&task->list, &run_queue); preempt_enable(); diff --git a/src/kernel/syscall.c b/src/kernel/syscall.c index 074b7ed50..111bc4ccd 100644 --- a/src/kernel/syscall.c +++ b/src/kernel/syscall.c @@ -6,6 +6,8 @@ #include #include #include +#include +#include typedef void (*syscall_funcp)(); @@ -96,6 +98,8 @@ void syscall_fork(trapframe *_) void syscall_exit(trapframe *_) { exit_user_prog(); + + // Never reach } void syscall_mbox_call(trapframe *_, unsigned char ch, unsigned int *mbox) @@ -105,7 +109,28 @@ void syscall_mbox_call(trapframe *_, unsigned char ch, unsigned int *mbox) void syscall_kill_pid(trapframe *_, int pid) { - // TODO + task_struct *task; + + if (current->tid == pid) { + exit_user_prog(); + + // Never reach + return; + } + + preempt_disable(); + + task = task_get_by_tid(pid); + + if (!task || task->status != TASK_RUNNING) { + goto SYSCALL_KILL_PID_END; + } + + list_del(&task->list); + kthread_add_wait_queue(task); + +SYSCALL_KILL_PID_END: + preempt_enable(); } void syscall_signal(trapframe *_, int signal, void (*handler)(void)) diff --git a/src/kernel/task.c b/src/kernel/task.c index 76e93513e..abe95cb15 100644 --- a/src/kernel/task.c +++ b/src/kernel/task.c @@ -1,6 +1,9 @@ #include #include +// TODO: Use rbtree to manage tasks +static struct list_head task_queue; + // TODO: recycle usable tid uint32 max_tid; @@ -14,6 +17,11 @@ static uint32 alloc_tid(void) return tid; } +void task_init(void) +{ + INIT_LIST_HEAD(&task_queue); +} + task_struct *task_create(void) { task_struct *task; @@ -23,6 +31,9 @@ task_struct *task_create(void) task->kernel_stack = NULL; task->user_stack = NULL; task->data = NULL; + INIT_LIST_HEAD(&task->list); + list_add_tail(&task->task_list, &task_queue); + task->status = TASK_NEW; task->need_resched = 0; task->tid = alloc_tid(); task->preempt = 0; @@ -41,7 +52,22 @@ void task_free(task_struct *task) if (task->data) kfree(task->data); + list_del(&task->task_list); + // TODO: release tid kfree(task); +} + +task_struct *task_get_by_tid(uint32 tid) +{ + task_struct *task; + + list_for_each_entry(task, &task_queue, task_list) { + if (task->tid == tid) { + return task; + } + } + + return NULL; } \ No newline at end of file From 4b8c7a80f5b57d1505bb4964190d1e51b58a7c64 Mon Sep 17 00:00:00 2001 From: LJP-TW Date: Tue, 26 Apr 2022 01:27:23 -0700 Subject: [PATCH 11/16] Implement syscall exec --- include/kernel/cpio.h | 2 +- include/kernel/exec.h | 4 +++- include/kernel/task.h | 2 ++ include/lib/string.h | 8 ++++---- initramfs/userprog2 | Bin 2872 -> 2992 bytes initramfs/userprog2.c | 18 ++++++++++++------ src/kernel/cpio.c | 2 +- src/kernel/exec.S | 25 ++++++++++++++++++++++++- src/kernel/exec.c | 4 +--- src/kernel/kthread.c | 2 -- src/kernel/main.c | 2 +- src/kernel/syscall.c | 25 ++++++++++++++++++++++++- src/lib/string.c | 8 ++++---- 13 files changed, 77 insertions(+), 25 deletions(-) diff --git a/include/kernel/cpio.h b/include/kernel/cpio.h index cc4af40b3..8622ae61e 100644 --- a/include/kernel/cpio.h +++ b/include/kernel/cpio.h @@ -16,7 +16,7 @@ void cpio_cat(char *cpio, char *filename); * * Return NULL if failed. */ -char *cpio_load_prog(char *cpio, char *filename); +char *cpio_load_prog(char *cpio, const char *filename); void initramfs_init(void); diff --git a/include/kernel/exec.h b/include/kernel/exec.h index b3883a5a5..c3f48b435 100644 --- a/include/kernel/exec.h +++ b/include/kernel/exec.h @@ -2,8 +2,10 @@ #define _EXEC_H // TODO: Add argv & envp -void exec_user_prog(char *filename); +void sched_new_user_prog(char *filename); void exit_user_prog(void); +void exec_user_prog(void *entry, char *user_sp, char *kernel_sp); + #endif /* _EXEC_H */ \ No newline at end of file diff --git a/include/kernel/task.h b/include/kernel/task.h index 4e7db05d4..65a079edd 100644 --- a/include/kernel/task.h +++ b/include/kernel/task.h @@ -4,6 +4,8 @@ #include #include +#define STACK_SIZE (2 * PAGE_SIZE) + /* Task status */ #define TASK_NEW 0 #define TASK_RUNNING 1 diff --git a/include/lib/string.h b/include/lib/string.h index 4307927d8..a333c2562 100644 --- a/include/lib/string.h +++ b/include/lib/string.h @@ -1,10 +1,10 @@ #ifndef _STRING_H #define _STRING_H -int strcmp(char *str1, char *str2); -int strncmp(char *str1, char *str2, int n); -int strlen(char *str); +int strcmp(const char *str1, const char *str2); +int strncmp(const char *str1, const char *str2, int n); +int strlen(const char *str); -int atoi(char *str); +int atoi(const char *str); #endif /* _STRING_H */ \ No newline at end of file diff --git a/initramfs/userprog2 b/initramfs/userprog2 index 1fda25c5e1ed3a275b3b5da1de6cd9089893d5b8..7b41e7067731ceb9b7505c02e943a575b8412b90 100755 GIT binary patch delta 542 zcmYk3!D|yi6vp41&Dz~W(j0;-CYlz~ST9SY3SzC@+@x5jK|BaTJxEW|67^I{xAat~ zkmUvRlIl?ep`|^Ti?sIAqXe(kUHu0<83Jj?FNu&IKIZqmZ)V;b=JSPZr<%6M6xH-3 zHI{ZRJ3Mobs1~kM!0b0~{^!V`k3>|Za4gths{Mw-32H6wAVOUKKLNxb}{+t#k0y%WpUv;QX+X|ySMXywcf-~R7!ev zYime7J^qn|O+&Y!YD?=mtjOoe2(rMgKWfPr`-%!%a%x{PtKA)PV&`~7rs5g%8*E;l zfc}8yWd)Q%7f85|zsC>M=gzBkT`O@^QAm`3?;BmJB9 zZVbf_%5&UNhGJ`fg)nG3r2I)sw%ho^^_8Dmo$49YCAvz8>kbChUOwdD3oY!+lb&?& zwHC%D)x$G2%$|^HI70N(Noi5bV@p%@Fz6=fj%tJaH+4U5`E2i8iyxpZO5{U*npK4yF!%2d9BM=Aj-HH X*23L;gln!44Y0t})^t2^OPD diff --git a/initramfs/userprog2.c b/initramfs/userprog2.c index 8292768db..8399abec3 100644 --- a/initramfs/userprog2.c +++ b/initramfs/userprog2.c @@ -16,6 +16,7 @@ typedef char int8; #define SYS_GETPID 0 #define SYS_UART_RECV 1 #define SYS_UART_WRITE 2 +#define SYS_EXEC 3 #define SYS_EXIT 5 #define SYS_MBOX_CALL 6 #define SYS_KILL_PID 7 @@ -59,11 +60,6 @@ int getpid() return pid; } -void exit(void) -{ - syscall(SYS_EXIT, 0, 0, 0, 0, 0, 0); -} - void uart_recv(const char buf[], size_t size) { syscall(SYS_UART_RECV, (void *)buf, (void *)size, 0, 0, 0, 0); @@ -176,6 +172,16 @@ void uart_printf(const char *fmt, ...) va_end(args); } +void exec(const char *name, char *const argv[]) +{ + syscall(SYS_EXEC, (void *)name, (void *)argv, 0, 0, 0, 0); +} + +void exit(void) +{ + syscall(SYS_EXIT, 0, 0, 0, 0, 0, 0); +} + void mbox_call(unsigned char ch, unsigned int *mbox) { syscall(SYS_MBOX_CALL, (void *)(uint64)ch, mbox, 0, 0, 0, 0); @@ -252,7 +258,7 @@ int start(void) uart_printf("revision: %x\r\n", revision); - exit(); + exec("userprog1", NULL); return 0; } \ No newline at end of file diff --git a/src/kernel/cpio.c b/src/kernel/cpio.c index 83af0992c..749cb6256 100644 --- a/src/kernel/cpio.c +++ b/src/kernel/cpio.c @@ -132,7 +132,7 @@ void cpio_cat(char *cpio, char *filename) } } -char *cpio_load_prog(char *cpio, char *filename) +char *cpio_load_prog(char *cpio, const char *filename) { char *cur = cpio; diff --git a/src/kernel/exec.S b/src/kernel/exec.S index 3ed7b153b..64fb98abe 100644 --- a/src/kernel/exec.S +++ b/src/kernel/exec.S @@ -1,4 +1,4 @@ -// See include/kernel/exec.c for function declaration +// See include/kernel/exec.h and src/kernel/exec.c for function declaration .globl enter_el0_run_user_prog enter_el0_run_user_prog: @@ -12,6 +12,29 @@ enter_el0_run_user_prog: // EL0 ({M[3:0]} = 0) mov x0, 0 msr spsr_el1, x0 + + // TODO: Clear all general registers + + // return to EL0 + eret + +.globl exec_user_prog +exec_user_prog: + // Set exception return address + msr elr_el1, x0 + + // Set user stack + msr sp_el0, x1 + + // Enable interrupt ({D, A, I, F} = 0 (unmasked)) + // EL0 ({M[3:0]} = 0) + mov x0, 0 + msr spsr_el1, x0 + + // Set kernel stack + mov sp, x2 + + // TODO: Clear all general registers // return to EL0 eret \ No newline at end of file diff --git a/src/kernel/exec.c b/src/kernel/exec.c index 3c6bdceb5..8ffe830bf 100644 --- a/src/kernel/exec.c +++ b/src/kernel/exec.c @@ -6,8 +6,6 @@ #include #include -#define STACK_SIZE (2 * PAGE_SIZE) - // Change current EL to EL0 and execute the user program at @entry // Set user stack to @user_sp void enter_el0_run_user_prog(void *entry, char *user_sp); @@ -40,7 +38,7 @@ static inline void pt_regs_init(struct pt_regs *regs) } // TODO: Add argv & envp -void exec_user_prog(char *filename) +void sched_new_user_prog(char *filename) { void *data; task_struct *task; diff --git a/src/kernel/kthread.c b/src/kernel/kthread.c index 1d508db9f..ebb31b2e9 100644 --- a/src/kernel/kthread.c +++ b/src/kernel/kthread.c @@ -5,8 +5,6 @@ #include #include -#define STACK_SIZE (2 * PAGE_SIZE) - static wait_queue_head *wait_queue; static void kthread_start(void) diff --git a/src/kernel/main.c b/src/kernel/main.c index 6074686ba..8b674a4c8 100644 --- a/src/kernel/main.c +++ b/src/kernel/main.c @@ -177,7 +177,7 @@ static void cmd_cat(char *filename) static void cmd_exec(char *filename) { // TODO: Add argv & envp - exec_user_prog(filename); + sched_new_user_prog(filename); } static void cmd_parsedtb(void) diff --git a/src/kernel/syscall.c b/src/kernel/syscall.c index 111bc4ccd..3978597a3 100644 --- a/src/kernel/syscall.c +++ b/src/kernel/syscall.c @@ -8,6 +8,8 @@ #include #include #include +#include +#include typedef void (*syscall_funcp)(); @@ -85,9 +87,30 @@ void syscall_uart_write(trapframe *_, const char buf[], size_t size) uart_sendn(buf, size); } +// TODO: Passing argv void syscall_exec(trapframe *_, const char* name, char *const argv[]) { - // TODO + void *data; + char *kernel_sp; + char *user_sp; + + data = cpio_load_prog(initramfs_base, name); + + if (data == NULL) { + return; + } + + // Use origin kernel stack + + // TODO: Clear user stack + + kfree(current->data); + current->data = data; + + kernel_sp = (char *)current->kernel_stack + STACK_SIZE - 0x10; + user_sp = (char *)current->user_stack + STACK_SIZE - 0x10; + + exec_user_prog(current->data, user_sp, kernel_sp); } void syscall_fork(trapframe *_) diff --git a/src/lib/string.c b/src/lib/string.c index 7c4bf0274..69170a319 100644 --- a/src/lib/string.c +++ b/src/lib/string.c @@ -1,6 +1,6 @@ #include -int strcmp(char *str1, char *str2) +int strcmp(const char *str1, const char *str2) { char c1, c2; @@ -9,7 +9,7 @@ int strcmp(char *str1, char *str2) return c1 - c2; } -int strncmp(char *str1, char *str2, int n) +int strncmp(const char *str1, const char *str2, int n) { char c1, c2; @@ -21,7 +21,7 @@ int strncmp(char *str1, char *str2, int n) return n ? c1 - c2 : 0; } -int strlen(char *str) +int strlen(const char *str) { int ret = 0; @@ -32,7 +32,7 @@ int strlen(char *str) return ret; } -int atoi(char *str) +int atoi(const char *str) { int i = 0, tmp = 0; From a38f9e02569db36fdbe6085caff7a89ffa0e0fd8 Mon Sep 17 00:00:00 2001 From: LJP-TW Date: Tue, 26 Apr 2022 03:19:08 -0700 Subject: [PATCH 12/16] Implement syscall fork --- include/kernel/cpio.h | 8 ++-- include/kernel/task.h | 14 +++++++ include/kernel/trapframe.h | 6 +-- initramfs/userprog2 | Bin 2992 -> 3152 bytes initramfs/userprog2.c | 62 +++++++++++++++++----------- src/kernel/cpio.c | 12 +++--- src/kernel/exec.c | 6 ++- src/kernel/syscall.c | 81 +++++++++++++++++++++++++++++++++++-- 8 files changed, 146 insertions(+), 43 deletions(-) diff --git a/include/kernel/cpio.h b/include/kernel/cpio.h index 8622ae61e..48f70943e 100644 --- a/include/kernel/cpio.h +++ b/include/kernel/cpio.h @@ -11,12 +11,12 @@ void cpio_cat(char *cpio, char *filename); /* * Allocate a memory chunk and load the @filename program onto it. Then return - * the address of the chunk. This memory chunk needs to be passed to kfree() - * manually. + * the address of the chunk by @output_data. @output_data needs to be passed + * to kfree() manually. * - * Return NULL if failed. + * Return output_data length, return 0 if no such file. */ -char *cpio_load_prog(char *cpio, const char *filename); +uint32 cpio_load_prog(char *cpio, const char *filename, char **output_data); void initramfs_init(void); diff --git a/include/kernel/task.h b/include/kernel/task.h index 65a079edd..22041b54c 100644 --- a/include/kernel/task.h +++ b/include/kernel/task.h @@ -34,6 +34,7 @@ typedef struct _task_struct { void *user_stack; /* TODO: Update to address_space */ void *data; + uint32 datalen; /* @list is used by run_queue / wait_queue */ struct list_head list; /* @task_list links all tasks */ @@ -44,6 +45,19 @@ typedef struct _task_struct { uint32 preempt; } task_struct; +#define SAVE_REGS(task) \ + asm volatile ( \ + "stp x19, x20, [%x0, 16 * 0]\n" \ + "stp x21, x22, [%x0, 16 * 1]\n" \ + "stp x23, x24, [%x0, 16 * 2]\n" \ + "stp x25, x26, [%x0, 16 * 3]\n" \ + "stp x27, x28, [%x0, 16 * 4]\n" \ + "stp fp, lr, [%x0, 16 * 5]\n" \ + "mov x9, sp\n" \ + "str x9, [%x0, 16 * 6]\n" \ + : : "r" (&task->regs) \ + ); + void task_init(void); task_struct *task_create(void); diff --git a/include/kernel/trapframe.h b/include/kernel/trapframe.h index 806508196..4a9cb37b5 100644 --- a/include/kernel/trapframe.h +++ b/include/kernel/trapframe.h @@ -35,9 +35,9 @@ typedef struct { uint64 x28; uint64 x29; uint64 x30; - uint64 sp_el0; - uint64 elr_el1; - uint64 spsr_el1; + void *sp_el0; + void *elr_el1; + void *spsr_el1; } trapframe; #endif /* _TRAPFRAME_H */ \ No newline at end of file diff --git a/initramfs/userprog2 b/initramfs/userprog2 index 7b41e7067731ceb9b7505c02e943a575b8412b90..6f524be75c1132650afeed068840f041bb7513ef 100755 GIT binary patch delta 1008 zcmZ`%-Ahw(7=C}}%yHaIcQMRXxYKY`@nW+mVg_!AK@updh`w+(M-8X0eV8z4Gl;tA z!oyFJ0!6whrHjC*gg#9D14PWbVnR1U7hTkrZS(a0&d%n!>A;WkywCf-&-0v*R|nS{ zQpMzl`63UJER*>jfT@fVmbRUqB>81)C^k#?aIOaDN`}qSU98{X0Twj5N*|C*^rX;83q;_H$Ek_I>~YRMCeF0A#WA=FU91_i)Frl ztC;+xygS9((=JW$X&(V7y*sR}x_#`$I7eYFN`!rG0y$E%Ut3KYY}Vig1*awniULXd zR%Lm*Yzk)25{6X+eN+PN;0N8QgWXJ>XSeb(GR@L3?r9$YHQ?&SSTK5BjD!Z=qJ8jy zfpP3o`Jqra+>gzcW38!DQ*E3bi6r7~q|~}M5od&GkEt3e?+cEFVxiFy?2IcNmG8P0 z3ZrFkJQxrY7$FiJz1hwNDn%(rS-)?fBN`k*g8*C9=2Zo|$3tsFqTh7X|i}BuC(+oFDdepHaNJa3h zXXzEAh4vYA+|Lq>AT;IZn4ys~=jda+_2uXryt)3+ErX4V{Xwg$fkYF!2qNerGgAZaU6jbNd|DcO@J$=ueF%KNh=ll77&*%F&KQ#oBIJI1*X*gFml~ZaFoS$OY%VA7wUxy5C|g&S)JN5V1{pLxfnxX8->?U zm}El>AruawFrY9t?iB_^jS6tj{>uk=6s#Iy2!&Zx7v_4w0~acy!!Z^$Ec>k60I_ai zKEQCFjaV2;0Nhsg`2dUO%7xE}kwiB!krc(Q7z*?p=6w(#=$s*cPTUNhfDmJ=>j2v_ zya0eau!#AHz}#<~tP`7dqNd>WR&xe90>+jb8?ELOKN5gf?qoiiKQEDYG)f{0Q}M{E zZaJBCIz+n27JW<-WPNp;v=gb&y6Tnhc$C3?KCf!>wkUe#JweXXuigYXLy!C7xwcB~ zc|ji9aWe1SM|Rs5+RSO$ND_duEsRx91$U#H5Ijv0Uxk}Sj#O7-we}DW9>NVSzMLm0 z3V3%PIG_LD6oTSJYpx;W;L64HXzHpqGI^upv=&Jp@e2}1YV^TadTjhIl2d}5#IlLh z_{|Q?(Q1EtxMi2~S+oz`HTt4&$tzv|@g08z1aZc2=J)6|e|`AV9_J#&GHubbB=?o8 zpb07b*}(SbH>HuT_&pL7UAT!*E7Bc*v(!?gySNM&X}!`c>3`@cB`g^wI*1V~(TBK{ oO7xA=ScUHiwT{?d^%`NjgUQCGF9`b_&huphwTsdc896ZU59o_0X#fBK diff --git a/initramfs/userprog2.c b/initramfs/userprog2.c index 8399abec3..80529d420 100644 --- a/initramfs/userprog2.c +++ b/initramfs/userprog2.c @@ -17,6 +17,7 @@ typedef char int8; #define SYS_UART_RECV 1 #define SYS_UART_WRITE 2 #define SYS_EXEC 3 +#define SYS_FORK 4 #define SYS_EXIT 5 #define SYS_MBOX_CALL 6 #define SYS_KILL_PID 7 @@ -56,8 +57,7 @@ uint64 syscall(uint64 syscall_num, int getpid() { - int pid = syscall(SYS_GETPID, 0, 0, 0, 0, 0, 0); - return pid; + return (int)syscall(SYS_GETPID, 0, 0, 0, 0, 0, 0); } void uart_recv(const char buf[], size_t size) @@ -177,6 +177,11 @@ void exec(const char *name, char *const argv[]) syscall(SYS_EXEC, (void *)name, (void *)argv, 0, 0, 0, 0); } +int fork(void) +{ + return (int)syscall(SYS_FORK, 0, 0, 0, 0, 0, 0); +} + void exit(void) { syscall(SYS_EXIT, 0, 0, 0, 0, 0, 0); @@ -225,40 +230,49 @@ unsigned int get_board_revision(void) return mailbox[5]; } +void show_stack(void) +{ + uint64 sp; + + asm volatile ( + "mov x9, sp\n" + "str x9, %0\n" + : "=m" (sp) + ); + + uart_printf("[User] Stack: %llx\r\n", sp); +} + int start(void) { char buf1[0x10] = { 0 }; - char buf2[0x10] = { 0 }; - int pid, idx, revision; + int pid, revision; - kill_pid(2); - - idx = 0; pid = getpid(); + uart_printf("[User] pid: %d\r\n", pid); - while (pid) { - buf1[idx++] = '0' + pid % 10; - pid /= 10; - } - - for (int i = 0; i < idx; ++i) { - buf2[i] = buf1[idx - i - 1]; - } - - buf2[idx] = '\r'; - buf2[idx+1] = '\n'; - - uart_write(buf2, idx+2); + uart_printf("[User] kill_pid(2)\r\n"); + kill_pid(2); + uart_printf("[User] Input:\r\n"); uart_recv(buf1, 8); - - uart_printf("[User] buf1: %s\r\n", buf1); + uart_printf("[User] Output: %s\r\n", buf1); revision = get_board_revision(); + uart_printf("[User] Revision: %x\r\n", revision); - uart_printf("revision: %x\r\n", revision); + pid = fork(); - exec("userprog1", NULL); + if (pid == 0) { + uart_printf("[User] Child: exec userprog1\r\n"); + show_stack(); + exec("userprog1", NULL); + } else { + uart_printf("[User] Parent: child pid: %d\r\n", pid); + show_stack(); + } + uart_printf("[User] Exit\r\n"); + exit(); return 0; } \ No newline at end of file diff --git a/src/kernel/cpio.c b/src/kernel/cpio.c index 749cb6256..d9a3db95d 100644 --- a/src/kernel/cpio.c +++ b/src/kernel/cpio.c @@ -132,7 +132,7 @@ void cpio_cat(char *cpio, char *filename) } } -char *cpio_load_prog(char *cpio, const char *filename) +uint32 cpio_load_prog(char *cpio, const char *filename, char **output_data) { char *cur = cpio; @@ -144,7 +144,7 @@ char *cpio_load_prog(char *cpio, const char *filename) if (*(uint32 *)&pheader->c_magic[0] != 0x37303730 && *(uint16 *)&pheader->c_magic[4] != 0x3130) { uart_printf("[*] Only support new ASCII format of cpio.\r\n"); - return NULL; + return 0; } uint32 namesize = _cpio_read_8hex(pheader->c_namesize); @@ -164,15 +164,15 @@ char *cpio_load_prog(char *cpio, const char *filename) if (!strcmp(filename, curfilename)) { // Found it! - char *mem = (char *)kmalloc(filesize); - memncpy(mem, curcontent, filesize); - return mem; + *output_data = (char *)kmalloc(filesize); + memncpy(*output_data, curcontent, filesize); + return filesize; } // TRAILER!!! if (namesize == 0xb && !strcmp(curfilename, "TRAILER!!!")) { uart_printf("[*] File not found.\r\n"); - return NULL; + return 0; } } } diff --git a/src/kernel/exec.c b/src/kernel/exec.c index 8ffe830bf..fb8b11b6a 100644 --- a/src/kernel/exec.c +++ b/src/kernel/exec.c @@ -41,11 +41,12 @@ static inline void pt_regs_init(struct pt_regs *regs) void sched_new_user_prog(char *filename) { void *data; + uint32 datalen; task_struct *task; - data = cpio_load_prog(initramfs_base, filename); + datalen = cpio_load_prog(initramfs_base, filename, (char **)&data); - if (data == NULL) { + if (datalen == 0) { goto EXEC_USER_PROG_END; } @@ -54,6 +55,7 @@ void sched_new_user_prog(char *filename) task->kernel_stack = kmalloc(STACK_SIZE); task->user_stack = kmalloc(STACK_SIZE); task->data = data; + task->datalen = datalen; task->regs.sp = (char *)task->kernel_stack + STACK_SIZE - 0x10; pt_regs_init(&task->regs); diff --git a/src/kernel/syscall.c b/src/kernel/syscall.c index 3978597a3..b84277f9a 100644 --- a/src/kernel/syscall.c +++ b/src/kernel/syscall.c @@ -9,8 +9,24 @@ #include #include #include +#include #include +#define KSTACK_VARIABLE(x) \ + (void *)((uint64)x - \ + (uint64)current->kernel_stack + \ + (uint64)child->kernel_stack) + +#define USTACK_VARIABLE(x) \ + (void *)((uint64)x - \ + (uint64)current->user_stack + \ + (uint64)child->user_stack) + +#define DATA_VARIABLE(x) \ + (void *)((uint64)x - \ + (uint64)current->data + \ + (uint64)child->data) + typedef void (*syscall_funcp)(); void syscall_getpid(trapframe *_); @@ -93,10 +109,11 @@ void syscall_exec(trapframe *_, const char* name, char *const argv[]) void *data; char *kernel_sp; char *user_sp; + uint32 datalen; - data = cpio_load_prog(initramfs_base, name); + datalen = cpio_load_prog(initramfs_base, name, (char **)&data); - if (data == NULL) { + if (datalen == 0) { return; } @@ -106,6 +123,7 @@ void syscall_exec(trapframe *_, const char* name, char *const argv[]) kfree(current->data); current->data = data; + current->datalen = datalen; kernel_sp = (char *)current->kernel_stack + STACK_SIZE - 0x10; user_sp = (char *)current->user_stack + STACK_SIZE - 0x10; @@ -113,9 +131,64 @@ void syscall_exec(trapframe *_, const char* name, char *const argv[]) exec_user_prog(current->data, user_sp, kernel_sp); } -void syscall_fork(trapframe *_) +static inline void copy_regs(struct pt_regs *regs) { - // TODO + regs->x19 = current->regs.x19; + regs->x20 = current->regs.x20; + regs->x21 = current->regs.x21; + regs->x22 = current->regs.x22; + regs->x23 = current->regs.x23; + regs->x24 = current->regs.x24; + regs->x25 = current->regs.x25; + regs->x26 = current->regs.x26; + regs->x27 = current->regs.x27; + regs->x28 = current->regs.x28; +} + +void syscall_fork(trapframe *frame) +{ + task_struct *child; + trapframe *child_frame; + + child = task_create(); + + child->kernel_stack = kmalloc(STACK_SIZE); + child->user_stack = kmalloc(STACK_SIZE); + child->data = kmalloc(current->datalen); + child->datalen = current->datalen; + + memncpy(child->kernel_stack, current->kernel_stack, STACK_SIZE); + memncpy(child->user_stack, current->user_stack, STACK_SIZE); + memncpy(child->data, current->data, current->datalen); + + // Save regs + SAVE_REGS(current); + + // Copy register + copy_regs(&child->regs); + + // Copy stack realted registers + child->regs.fp = KSTACK_VARIABLE(current->regs.fp); + child->regs.sp = KSTACK_VARIABLE(current->regs.sp); + + // https://gcc.gnu.org/onlinedocs/gcc/Labels-as-Values.html + child->regs.lr = &&SYSCALL_FORK_END; + + // Adjust child trapframe + child_frame = KSTACK_VARIABLE(frame); + + child_frame->x0 = 0; + child_frame->sp_el0 = USTACK_VARIABLE(frame->sp_el0); + child_frame->elr_el1 = DATA_VARIABLE(frame->elr_el1); + + sched_add_task(child); + + // Set return value + frame->x0 = child->tid; + +SYSCALL_FORK_END: + + asm volatile("nop"); } void syscall_exit(trapframe *_) From c6b2fc46a8ded38e884d20ae2d64bd7a1d8198c1 Mon Sep 17 00:00:00 2001 From: LJP-TW Date: Tue, 26 Apr 2022 06:45:24 -0700 Subject: [PATCH 13/16] Video player (syscall.img) can work --- Makefile | 2 +- src/kernel/main.c | 7 ++++++- src/kernel/timer.c | 7 +++++++ 3 files changed, 14 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index 6d6311090..0f5e40644 100644 --- a/Makefile +++ b/Makefile @@ -89,7 +89,7 @@ $(INITRAMFS_CPIO): $(INITRAMFS_FILES) cd initramfs; find . | cpio -o -H newc > ../$(INITRAMFS_CPIO) qemu: all $(INITRAMFS_CPIO) $(RPI3_DTB) - qemu-system-aarch64 -M raspi3 -kernel $(BOOTLOADER_IMG) -display none \ + qemu-system-aarch64 -M raspi3 -kernel $(BOOTLOADER_IMG) \ -initrd $(INITRAMFS_CPIO) \ -dtb $(RPI3_DTB) \ -chardev pty,id=pty0,logfile=pty.log,signal=off \ diff --git a/src/kernel/main.c b/src/kernel/main.c index 8b674a4c8..f309adcc3 100644 --- a/src/kernel/main.c +++ b/src/kernel/main.c @@ -305,7 +305,12 @@ void start_kernel(char *fdt) uart_printf("[*] fdt base: %x\r\n", fdt_base); uart_printf("[*] Kernel start!\r\n"); - kthread_create(shell); + // TODO: Remove shell? + // kthread_create(shell); + + // TODO: Add argv & envp + // First user program + sched_new_user_prog("syscall.img"); // Enable interrupt from Auxiliary peripherals irq1_enable(29); diff --git a/src/kernel/timer.c b/src/kernel/timer.c index 9cae43bc3..0ccd4a6d6 100644 --- a/src/kernel/timer.c +++ b/src/kernel/timer.c @@ -195,6 +195,8 @@ static void timer_show_boot_time(void *_) void timer_init() { + uint64 cntkctl_el1; + timer_set_boot_cnt(); INIT_LIST_HEAD(&t_meta.head); @@ -203,6 +205,11 @@ void timer_init() t_interval = 0; t_status = 0xffffffff; + // Allow EL0 to access timer + cntkctl_el1 = read_sysreg(CNTKCTL_EL1); + cntkctl_el1 |= 1; + write_sysreg(CNTKCTL_EL1, cntkctl_el1); + timer_add_proc_after(timer_show_boot_time, NULL, 2); } From 5b6721d4677b3b433c4afe24c8e7006dbf85b028 Mon Sep 17 00:00:00 2001 From: LJP-TW Date: Tue, 26 Apr 2022 06:54:09 -0700 Subject: [PATCH 14/16] Adjust the frequency of rescheduling --- src/kernel/sched.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/kernel/sched.c b/src/kernel/sched.c index a0524c9c0..bf3817374 100644 --- a/src/kernel/sched.c +++ b/src/kernel/sched.c @@ -5,8 +5,8 @@ #include #include -#define SCHEDULER_TIMER_HZ 1000 -#define SCHEDULER_WATERMARK 15 +#define SCHEDULER_TIMER_HZ 32 +#define SCHEDULER_WATERMARK 1 static struct list_head run_queue; From 862ab470134aaf7c25d848fd1eac94472a35725a Mon Sep 17 00:00:00 2001 From: LJP-TW Date: Fri, 29 Apr 2022 09:20:31 -0700 Subject: [PATCH 15/16] Implement POSIX signal --- include/kernel/mode_switch.h | 8 ++ include/kernel/signal.h | 89 ++++++++++++ include/kernel/task.h | 7 + src/kernel/head.S | 6 + src/kernel/mode_switch.c | 12 ++ src/kernel/signal.c | 272 +++++++++++++++++++++++++++++++++++ src/kernel/syscall.c | 21 ++- src/kernel/task.c | 11 ++ 8 files changed, 414 insertions(+), 12 deletions(-) create mode 100644 include/kernel/mode_switch.h create mode 100644 include/kernel/signal.h create mode 100644 src/kernel/mode_switch.c create mode 100644 src/kernel/signal.c diff --git a/include/kernel/mode_switch.h b/include/kernel/mode_switch.h new file mode 100644 index 000000000..54edbf70c --- /dev/null +++ b/include/kernel/mode_switch.h @@ -0,0 +1,8 @@ +#ifndef _MODE_SWITCH_H +#define _MODE_SWITCH_H + +#include + +void exit_to_user_mode(trapframe regs); + +#endif /* _MODE_SWITCH_H */ \ No newline at end of file diff --git a/include/kernel/signal.h b/include/kernel/signal.h new file mode 100644 index 000000000..4f6bdc108 --- /dev/null +++ b/include/kernel/signal.h @@ -0,0 +1,89 @@ +#ifndef _SIGNAL_H +#define _SIGNAL_H + +#include +#include +#include + +// https://man7.org/linux/man-pages/man7/signal.7.html +// 0 means no signal +#define SIGHUP 1 +#define SIGINT 2 +#define SIGQUIT 3 +#define SIGILL 4 +#define SIGTRAP 5 +#define SIGABRT 6 +#define SIGIOT 6 +#define SIGBUS 7 +#define SIGFPE 8 +#define SIGKILL 9 +#define SIGUSR1 10 +#define SIGSEGV 11 +#define SIGUSR2 12 +#define SIGPIPE 13 +#define SIGALRM 14 +#define SIGTERM 15 +#define SIGSTKFLT 16 +#define SIGCHLD 17 +#define SIGCONT 18 +#define SIGSTOP 19 +#define SIGTSTP 20 +#define SIGTTIN 21 +#define SIGTTOU 22 +#define SIGURG 23 +#define SIGXCPU 24 +#define SIGXFSZ 25 +#define SIGVTALRM 26 +#define SIGPROF 27 +#define SIGWINCH 28 +#define SIGIO 29 +#define SIGPOLL 29 +#define SIGPWR 30 +#define SIGSYS 31 +#define SIGUNUSED 31 + +#define NSIG 32 + +struct signal_head_t { + /* Link signal_t */ + struct list_head list; +}; + +struct signal_t { + struct list_head list; + uint32 signum; +}; + +typedef void (*sighandler_t)(int); + +struct sigaction_t { + sighandler_t sighand; + + /* flags */ + uint32 kernel_hand; +}; + +struct sighand_t { + // 0-th sigaction_t is not used + struct sigaction_t sigactions[NSIG]; +}; + +struct signal_head_t *signal_head_create(void); +void signal_head_free(struct signal_head_t *head); +void signal_head_reset(struct signal_head_t *head); + +void handle_signal(trapframe *_); + +struct sighand_t *sighand_create(void); +void sighand_free(struct sighand_t *sighand); +void sighand_reset(struct sighand_t *sighand); + +/* Copy current signal handler to @sighand */ +void sighand_copy(struct sighand_t *sighand, void *addrbase); + +/* syscalls */ +void syscall_signal(trapframe *_, uint32 signal, void (*handler)(int)); +void syscall_kill(trapframe *_, int pid, int signal); +void syscall_sigreturn(trapframe *_); + +#endif /* _SIGNAL_H */ \ No newline at end of file diff --git a/include/kernel/task.h b/include/kernel/task.h index 22041b54c..1720f1455 100644 --- a/include/kernel/task.h +++ b/include/kernel/task.h @@ -11,6 +11,10 @@ #define TASK_RUNNING 1 #define TASK_DEAD 2 +/* Define in include/kernel/signal.h */ +struct signal_head_t; +struct sighand_t; + struct pt_regs { void *x19; void *x20; @@ -43,6 +47,9 @@ typedef struct _task_struct { uint16 need_resched:1; uint32 tid; uint32 preempt; + /* Signal */ + struct signal_head_t *signal; + struct sighand_t *sighand; } task_struct; #define SAVE_REGS(task) \ diff --git a/src/kernel/head.S b/src/kernel/head.S index ff04f09f3..85e704204 100644 --- a/src/kernel/head.S +++ b/src/kernel/head.S @@ -184,6 +184,9 @@ l64_syn_eh: mrs x1, esr_el1 bl syscall_handler + mov x0, sp + bl exit_to_user_mode + kernel_exit 0 l64_irq_eh: @@ -191,6 +194,9 @@ l64_irq_eh: bl irq_handler + mov x0, sp + bl exit_to_user_mode + kernel_exit 0 curr_syn_eh: diff --git a/src/kernel/mode_switch.c b/src/kernel/mode_switch.c new file mode 100644 index 000000000..eb516daa4 --- /dev/null +++ b/src/kernel/mode_switch.c @@ -0,0 +1,12 @@ +#include +#include +#include + +void exit_to_user_mode(trapframe regs) +{ + enable_interrupt(); + + handle_signal(®s); + + disable_interrupt(); +} \ No newline at end of file diff --git a/src/kernel/signal.c b/src/kernel/signal.c new file mode 100644 index 000000000..35205bc17 --- /dev/null +++ b/src/kernel/signal.c @@ -0,0 +1,272 @@ +#include +#include +#include +#include +#include +#include + +// TODO: implement SIGSTOP & SIGCONT kernel handler + +#define DATA_OFFSET(x) ((uint64)current->data - (uint64)x) + +/* Kernel defined sighandler_t */ +#define SIG_DFL (sighandler_t)0 +#define SIG_IGN (sighandler_t)1 + +// SIG_DFL +static void sig_termiante(int); + +// SIG_IGN +static void sig_ignore(int); + +static void sig_termiante(int _) +{ + exit_user_prog(); + + // Never reach +} + +static void sig_ignore(int _) +{ + return; +} + +/* + * TODO: This function runs in user mode, make user can execute this function + * when MMU is enable. + */ +void sigreturn(void) +{ + // sigreturn: syscall 11 + asm volatile( + "mov x8, 11\n" + "svc 0\n" + ); +} + +/* + * Try to get the pending signal of current task. + */ +static struct signal_t *signal_try_get(void) +{ + if (list_empty(¤t->signal->list)) { + return NULL; + } + + return list_first_entry(¤t->signal->list, struct signal_t, list); +} + +static void signal_add(uint32 signum, struct signal_head_t *head) +{ + struct signal_t *signal; + + signal = kmalloc(sizeof(struct signal_t)); + + signal->signum = signum; + + list_add(&signal->list, &head->list); +} + +static void signal_del(struct signal_t *signal) +{ + list_del(&signal->list); + kfree(signal); +} + +static void save_context(void *user_sp, trapframe *frame) +{ + memncpy(user_sp, (char *)frame, sizeof(trapframe)); +} + +struct signal_head_t *signal_head_create(void) +{ + struct signal_head_t *head; + + head = kmalloc(sizeof(struct signal_head_t)); + + INIT_LIST_HEAD(&head->list); + + return head; +} + +void signal_head_free(struct signal_head_t *head) +{ + struct signal_t *signal, *safe; + + list_for_each_entry_safe(signal, safe, &head->list, list) { + signal_del(signal); + } + + kfree(head); +} + +void signal_head_reset(struct signal_head_t *head) +{ + struct signal_t *signal, *safe; + + list_for_each_entry_safe(signal, safe, &head->list, list) { + signal_del(signal); + } +} + +void handle_signal(trapframe *frame) +{ + struct signal_t *signal; + struct sigaction_t *sigaction; + + preempt_disable(); + + signal = signal_try_get(); + + preempt_enable(); + + if (signal == NULL) { + return; + } + + sigaction = ¤t->sighand->sigactions[signal->signum]; + + if (sigaction->kernel_hand) { + sigaction->sighand(signal->signum); + } else { + char *user_sp; + uint32 reserve_size; + + // Reserve space on user stack + reserve_size = sizeof(trapframe); + user_sp = frame->sp_el0 - ALIGN(reserve_size, 0x10); + + // Save cpu context onto user stack + save_context(user_sp, frame); + + // Set user sp + frame->sp_el0 = user_sp; + + // Set parameter of handler + frame->x0 = signal->signum; + + // Set user pc to handler + frame->elr_el1 = sigaction->sighand; + + // Set user lr to sigreturn + frame->x30 = (uint64)sigreturn; + } + + signal_del(signal); +} + +struct sighand_t *sighand_create(void) +{ + struct sighand_t *sighand; + + sighand = kmalloc(sizeof(struct sighand_t)); + + for (int i = 1; i < NSIG; ++i) { + sighand->sigactions[i].kernel_hand = 1; + sighand->sigactions[i].sighand = sig_ignore; + } + + sighand->sigactions[SIGKILL].sighand = sig_termiante; + + return sighand; +} + +void sighand_free(struct sighand_t *sighand) +{ + kfree(sighand); +} + +void sighand_reset(struct sighand_t *sighand) +{ + for (int i = 1; i < NSIG; ++i) { + sighand->sigactions[i].kernel_hand = 1; + sighand->sigactions[i].sighand = sig_ignore; + } + + sighand->sigactions[SIGKILL].sighand = sig_termiante; +} + +static inline void kernel_sighand_copy(struct sigaction_t *from, + struct sigaction_t *to) +{ + to->kernel_hand = 1; + to->sighand = from->sighand; +} + +static inline void user_sighand_copy(struct sigaction_t *from, + struct sigaction_t *to, + uint64 offset) +{ + to->kernel_hand = 0; + to->sighand = (sighandler_t)((char *)from->sighand - offset); +} + +/* Copy current signal handler to @sighand */ +void sighand_copy(struct sighand_t *sighand, void *addrbase) +{ + struct sighand_t *currhand; + + currhand = current->sighand; + + for (int i = 1; i < NSIG; ++i) { + if (currhand->sigactions[i].kernel_hand) { + kernel_sighand_copy(&currhand->sigactions[i], + &sighand->sigactions[i]); + } else { + user_sighand_copy(&currhand->sigactions[i], + &sighand->sigactions[i], + DATA_OFFSET(addrbase)); + } + } +} + +void syscall_signal(trapframe *_, uint32 signal, void (*handler)(int)) +{ + struct sigaction_t *sigaction; + + // Check if signal is valid + if (signal >= NSIG) { + return; + } + + sigaction = ¤t->sighand->sigactions[signal]; + + if (handler == SIG_DFL) { + sigaction->kernel_hand = 1; + sigaction->sighand = sig_termiante; + } else if (handler == SIG_IGN) { + sigaction->kernel_hand = 1; + sigaction->sighand = sig_ignore; + } else { + sigaction->kernel_hand = 0; + sigaction->sighand = handler; + } +} + +void syscall_kill(trapframe *_, int pid, int signal) +{ + task_struct *task; + + preempt_disable(); + + task = task_get_by_tid(pid); + + if (!task || task->status != TASK_RUNNING) { + goto SYSCALL_KILL_END; + } + + signal_add((uint32)signal, task->signal); + +SYSCALL_KILL_END: + preempt_enable(); +} + +// restore context +void syscall_sigreturn(trapframe *frame) +{ + trapframe *user_sp; + + user_sp = frame->sp_el0; + + memncpy((char *)frame, (char *)user_sp, sizeof(trapframe)); +} \ No newline at end of file diff --git a/src/kernel/syscall.c b/src/kernel/syscall.c index b84277f9a..de5db90ec 100644 --- a/src/kernel/syscall.c +++ b/src/kernel/syscall.c @@ -10,6 +10,7 @@ #include #include #include +#include #include #define KSTACK_VARIABLE(x) \ @@ -37,8 +38,6 @@ void syscall_fork(trapframe *_); void syscall_exit(trapframe *_); void syscall_mbox_call(trapframe *_, unsigned char ch, unsigned int *mbox); void syscall_kill_pid(trapframe *_, int pid); -void syscall_signal(trapframe *_, int signal, void (*handler)(void)); -void syscall_kill(trapframe *_, int pid, int signal); void syscall_show_info(trapframe *_); syscall_funcp syscall_table[] = { @@ -53,6 +52,7 @@ syscall_funcp syscall_table[] = { (syscall_funcp) syscall_signal, // 8 (syscall_funcp) syscall_kill, (syscall_funcp) syscall_show_info, + (syscall_funcp) syscall_sigreturn, }; typedef struct { @@ -128,6 +128,10 @@ void syscall_exec(trapframe *_, const char* name, char *const argv[]) kernel_sp = (char *)current->kernel_stack + STACK_SIZE - 0x10; user_sp = (char *)current->user_stack + STACK_SIZE - 0x10; + // Reset signal + signal_head_reset(current->signal); + sighand_reset(current->sighand); + exec_user_prog(current->data, user_sp, kernel_sp); } @@ -161,6 +165,9 @@ void syscall_fork(trapframe *frame) memncpy(child->user_stack, current->user_stack, STACK_SIZE); memncpy(child->data, current->data, current->datalen); + // Copy signal handler + sighand_copy(child->sighand, child->data); + // Save regs SAVE_REGS(current); @@ -229,16 +236,6 @@ void syscall_kill_pid(trapframe *_, int pid) preempt_enable(); } -void syscall_signal(trapframe *_, int signal, void (*handler)(void)) -{ - // TODO -} - -void syscall_kill(trapframe *_, int pid, int signal) -{ - // TODO -} - // Print the content of spsr_el1, elr_el1 and esr_el1 void syscall_show_info(trapframe *_) { diff --git a/src/kernel/task.c b/src/kernel/task.c index abe95cb15..49b1aaae7 100644 --- a/src/kernel/task.c +++ b/src/kernel/task.c @@ -1,4 +1,5 @@ #include +#include #include // TODO: Use rbtree to manage tasks @@ -25,8 +26,12 @@ void task_init(void) task_struct *task_create(void) { task_struct *task; + struct signal_head_t *signal; + struct sighand_t *sighand; task = kmalloc(sizeof(task_struct)); + signal = signal_head_create(); + sighand = sighand_create(); task->kernel_stack = NULL; task->user_stack = NULL; @@ -38,6 +43,9 @@ task_struct *task_create(void) task->tid = alloc_tid(); task->preempt = 0; + task->signal = signal; + task->sighand = sighand; + return task; } @@ -54,6 +62,9 @@ void task_free(task_struct *task) list_del(&task->task_list); + signal_head_free(task->signal); + sighand_free(task->sighand); + // TODO: release tid kfree(task); From cb56a871c2ec7d1bd652ef7fcc053c29a69443aa Mon Sep 17 00:00:00 2001 From: LJP-TW Date: Fri, 29 Apr 2022 09:22:30 -0700 Subject: [PATCH 16/16] Fix: adjust x30 (lr) in fork --- src/kernel/syscall.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/kernel/syscall.c b/src/kernel/syscall.c index de5db90ec..05cefe65c 100644 --- a/src/kernel/syscall.c +++ b/src/kernel/syscall.c @@ -185,6 +185,7 @@ void syscall_fork(trapframe *frame) child_frame = KSTACK_VARIABLE(frame); child_frame->x0 = 0; + child_frame->x30 = (uint64)DATA_VARIABLE(frame->x30); child_frame->sp_el0 = USTACK_VARIABLE(frame->sp_el0); child_frame->elr_el1 = DATA_VARIABLE(frame->elr_el1);