From 4f6780ba5e55168de96d9554b80089ed413d25be Mon Sep 17 00:00:00 2001 From: LJP-TW Date: Tue, 19 Apr 2022 00:51:13 -0700 Subject: [PATCH 01/25] 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/25] 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/25] 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/25] 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/25] 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/25] 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/25] 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/25] 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/25] 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/25] 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/25] 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/25] 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/25] 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/25] 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/25] 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/25] 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); From 7d6e592b86413dcc70ea2ab40ce24102f0e3a8c5 Mon Sep 17 00:00:00 2001 From: LJP-TW Date: Mon, 16 May 2022 00:43:17 -0700 Subject: [PATCH 17/25] Fix bug in uart_send_num --- src/bootloader/mini_uart.c | 6 +++--- src/kernel/mini_uart.c | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/bootloader/mini_uart.c b/src/bootloader/mini_uart.c index 84ca235f1..217f65d37 100644 --- a/src/bootloader/mini_uart.c +++ b/src/bootloader/mini_uart.c @@ -85,7 +85,7 @@ static void uart_send_num(int64 num, int base, int type) char tmp[66]; int i; - if (type | SIGN) { + if (type & SIGN) { if (num < 0) { uart_send('-'); } @@ -97,8 +97,8 @@ static void uart_send_num(int64 num, int base, int type) tmp[i++] = '0'; } else { while (num != 0) { - uint8 r = (uint32)num % base; - num = (uint32)num / base; + uint8 r = ((uint64)num) % base; + num = ((uint64)num) / base; tmp[i++] = digits[r]; } } diff --git a/src/kernel/mini_uart.c b/src/kernel/mini_uart.c index 9e220a84c..848793aca 100644 --- a/src/kernel/mini_uart.c +++ b/src/kernel/mini_uart.c @@ -158,7 +158,7 @@ static void uart_send_num(sendfp _send_fp, int64 num, int base, int type) char tmp[66]; int i; - if (type | SIGN) { + if (type & SIGN) { if (num < 0) { (_send_fp)('-'); } @@ -170,8 +170,8 @@ static void uart_send_num(sendfp _send_fp, int64 num, int base, int type) tmp[i++] = '0'; } else { while (num != 0) { - uint8 r = (uint32)num % base; - num = (uint32)num / base; + uint8 r = (uint64)num % base; + num = (uint64)num / base; tmp[i++] = digits[r]; } } From 9b645e59dac5551a0e2d6dfb379524e76f76ff5c Mon Sep 17 00:00:00 2001 From: LJP-TW Date: Mon, 16 May 2022 01:52:54 -0700 Subject: [PATCH 18/25] Map kernel space, MMU is enable with identity paging The user program cannot be run currently. --- Makefile | 1 + include/{lib => bootloader}/BCM2837.h | 0 include/{lib => bootloader}/rpi3.h | 0 include/kernel/BCM2837.h | 54 ++++++++++++++ include/kernel/mini_uart.h | 2 + include/kernel/mmu.h | 13 ++++ include/kernel/panic.h | 6 ++ include/kernel/rpi3.h | 13 ++++ include/lib/utils.h | 2 + src/{lib => bootloader}/BCM2837.c | 0 src/{lib => bootloader}/rpi3.c | 0 src/kernel/BCM2837.c | 18 +++++ src/kernel/cpio.c | 4 +- src/kernel/head.S | 11 +++ src/kernel/irq.c | 2 +- src/kernel/linker.ld | 9 ++- src/kernel/main.c | 4 +- src/kernel/mini_uart.c | 72 +++++++++--------- src/kernel/mm/mm.c | 6 +- src/kernel/mmu.c | 63 ++++++++++++++++ src/kernel/panic.c | 20 +++++ src/kernel/rpi3.c | 101 ++++++++++++++++++++++++++ src/kernel/syscall.c | 4 +- src/kernel/timer.c | 6 +- 24 files changed, 361 insertions(+), 50 deletions(-) rename include/{lib => bootloader}/BCM2837.h (100%) rename include/{lib => bootloader}/rpi3.h (100%) create mode 100644 include/kernel/BCM2837.h create mode 100644 include/kernel/mmu.h create mode 100644 include/kernel/panic.h create mode 100644 include/kernel/rpi3.h rename src/{lib => bootloader}/BCM2837.c (100%) rename src/{lib => bootloader}/rpi3.c (100%) create mode 100644 src/kernel/BCM2837.c create mode 100644 src/kernel/mmu.c create mode 100644 src/kernel/panic.c create mode 100644 src/kernel/rpi3.c diff --git a/Makefile b/Makefile index 0f5e40644..965c0e84c 100644 --- a/Makefile +++ b/Makefile @@ -90,6 +90,7 @@ $(INITRAMFS_CPIO): $(INITRAMFS_FILES) qemu: all $(INITRAMFS_CPIO) $(RPI3_DTB) qemu-system-aarch64 -M raspi3 -kernel $(BOOTLOADER_IMG) \ + -display none \ -initrd $(INITRAMFS_CPIO) \ -dtb $(RPI3_DTB) \ -chardev pty,id=pty0,logfile=pty.log,signal=off \ diff --git a/include/lib/BCM2837.h b/include/bootloader/BCM2837.h similarity index 100% rename from include/lib/BCM2837.h rename to include/bootloader/BCM2837.h diff --git a/include/lib/rpi3.h b/include/bootloader/rpi3.h similarity index 100% rename from include/lib/rpi3.h rename to include/bootloader/rpi3.h diff --git a/include/kernel/BCM2837.h b/include/kernel/BCM2837.h new file mode 100644 index 000000000..a38cc74e7 --- /dev/null +++ b/include/kernel/BCM2837.h @@ -0,0 +1,54 @@ +#ifndef _BCM2837_H +#define _BCM2837_H +// Ref: https://www.raspberrypi.org/app/uploads/2012/02/BCM2835-ARM-Peripherals.pdf + +#define PERIPHERALS_BASE 0x3f000000 +#define BUS_BASE 0x7e000000 + +#define BUS_TO_PERIPHERALS(addr) (addr - BUS_BASE + PERIPHERALS_BASE) + +// Auxiliaries: UART1 & SPI1, SPI2 +#define AUX_IRQ BUS_TO_PERIPHERALS(0x7E215000) +#define AUX_ENABLES BUS_TO_PERIPHERALS(0x7E215004) +#define AUX_MU_IO_REG BUS_TO_PERIPHERALS(0x7E215040) +#define AUX_MU_IER_REG BUS_TO_PERIPHERALS(0x7E215044) +#define AUX_MU_IIR_REG BUS_TO_PERIPHERALS(0x7E215048) +#define AUX_MU_LCR_REG BUS_TO_PERIPHERALS(0x7E21504c) +#define AUX_MU_MCR_REG BUS_TO_PERIPHERALS(0x7E215050) +#define AUX_MU_LSR_REG BUS_TO_PERIPHERALS(0x7E215054) +#define AUX_MU_MSR_REG BUS_TO_PERIPHERALS(0x7E215058) +#define AUX_MU_SCRATCH BUS_TO_PERIPHERALS(0x7E21505c) +#define AUX_MU_CNTL_REG BUS_TO_PERIPHERALS(0x7E215060) +#define AUX_MU_STAT_REG BUS_TO_PERIPHERALS(0x7E215064) +#define AUX_MU_BAUD_REG BUS_TO_PERIPHERALS(0x7E215068) +#define AUX_SPI0_CNTL0_REG BUS_TO_PERIPHERALS(0x7E215080) +#define AUX_SPI0_CNTL1_REG BUS_TO_PERIPHERALS(0x7E215084) +#define AUX_SPI0_STAT_REG BUS_TO_PERIPHERALS(0x7E215088) +#define AUX_SPI0_IO_REG BUS_TO_PERIPHERALS(0x7E215090) +#define AUX_SPI0_PEEK_REG BUS_TO_PERIPHERALS(0x7E215094) +#define AUX_SPI1_CNTL0_REG BUS_TO_PERIPHERALS(0x7E2150c0) +#define AUX_SPI1_CNTL1_REG BUS_TO_PERIPHERALS(0x7E2150c4) +#define AUX_SPI1_STAT_REG BUS_TO_PERIPHERALS(0x7E2150c8) +#define AUX_SPI1_IO_REG BUS_TO_PERIPHERALS(0x7E2150d0) +#define AUX_SPI1_PEEK_REG BUS_TO_PERIPHERALS(0x7E2150d4) + +// GPIO +#define GPFSEL0 BUS_TO_PERIPHERALS(0x7E200000) +#define GPFSEL1 BUS_TO_PERIPHERALS(0x7E200004) +#define GPFSEL2 BUS_TO_PERIPHERALS(0x7E200008) +#define GPFSEL3 BUS_TO_PERIPHERALS(0x7E20000c) +#define GPFSEL4 BUS_TO_PERIPHERALS(0x7E200010) +#define GPFSEL5 BUS_TO_PERIPHERALS(0x7E200014) + +#define GPPUD BUS_TO_PERIPHERALS(0x7E200094) +#define GPPUDCLK0 BUS_TO_PERIPHERALS(0x7E200098) +#define GPPUDCLK1 BUS_TO_PERIPHERALS(0x7E20009c) + +// Interrupt +#define IRQ_ENABLE_1_REG BUS_TO_PERIPHERALS(0x7E00B210) + +void BCM2837_reset(int tick); +void BCM2837_cancel_reset(); + + +#endif /* _BCM2837_H */ \ No newline at end of file diff --git a/include/kernel/mini_uart.h b/include/kernel/mini_uart.h index ef83dedf6..5de196e03 100644 --- a/include/kernel/mini_uart.h +++ b/include/kernel/mini_uart.h @@ -1,6 +1,7 @@ #ifndef _MINI_UART_H #define _MINI_UART_H +#include #include uint32 uart_recvline(char *buff, int maxlen); @@ -13,6 +14,7 @@ void uart_sendn(const char *str, int n); void uart_printf(const char *fmt, ...); void uart_sync_printf(const char *fmt, ...); +void uart_sync_vprintf(const char *fmt, va_list args); int uart_irq_check(void); diff --git a/include/kernel/mmu.h b/include/kernel/mmu.h new file mode 100644 index 000000000..01af8764b --- /dev/null +++ b/include/kernel/mmu.h @@ -0,0 +1,13 @@ +#ifndef _MMU_H +#define _MMU_H + +#include + +typedef uint64 pd_t; + +/* + * Set identity paging, enable MMU + */ +void mmu_init(void); + +#endif /* _MMU_H */ \ No newline at end of file diff --git a/include/kernel/panic.h b/include/kernel/panic.h new file mode 100644 index 000000000..1c1978411 --- /dev/null +++ b/include/kernel/panic.h @@ -0,0 +1,6 @@ +#ifndef _PANIC_H +#define _PANIC_H + +void panic(const char *fmt, ...); + +#endif /* _PANIC_H */ \ No newline at end of file diff --git a/include/kernel/rpi3.h b/include/kernel/rpi3.h new file mode 100644 index 000000000..90d9ab894 --- /dev/null +++ b/include/kernel/rpi3.h @@ -0,0 +1,13 @@ +#ifndef _RPI3_H +#define _RPI3_H + +struct arm_memory_info { + unsigned int baseaddr; + 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 *); + +#endif \ No newline at end of file diff --git a/include/lib/utils.h b/include/lib/utils.h index 3c86f40a3..6ebee0dd9 100644 --- a/include/lib/utils.h +++ b/include/lib/utils.h @@ -60,4 +60,6 @@ static inline void restore_interrupt(uint32 daif) #define TO_CHAR_PTR(a) ((char *)(uint64)(a)) +#define PA2VA(x) ((uint64)x + 0xffff000000000000) + #endif /* _UTILS_H */ \ No newline at end of file diff --git a/src/lib/BCM2837.c b/src/bootloader/BCM2837.c similarity index 100% rename from src/lib/BCM2837.c rename to src/bootloader/BCM2837.c diff --git a/src/lib/rpi3.c b/src/bootloader/rpi3.c similarity index 100% rename from src/lib/rpi3.c rename to src/bootloader/rpi3.c diff --git a/src/kernel/BCM2837.c b/src/kernel/BCM2837.c new file mode 100644 index 000000000..64d2ebdc3 --- /dev/null +++ b/src/kernel/BCM2837.c @@ -0,0 +1,18 @@ +#include + +#define PM_PASSWORD 0x5a000000 +#define PM_RSTC 0x3F10001c +#define PM_WDOG 0x3F100024 + +void BCM2837_reset(int tick) { // reboot after watchdog timer expire + put32(PA2VA(PM_RSTC), PM_PASSWORD | 0x20); // full reset + put32(PA2VA(PM_WDOG), PM_PASSWORD | tick); // number of watchdog tick + + // Never return + while (1) {} +} + +void BCM2837_cancel_reset() { + put32(PA2VA(PM_RSTC), PM_PASSWORD | 0); // full reset + put32(PA2VA(PM_WDOG), PM_PASSWORD | 0); // number of watchdog tick +} diff --git a/src/kernel/cpio.c b/src/kernel/cpio.c index d9a3db95d..7e94eeb1f 100644 --- a/src/kernel/cpio.c +++ b/src/kernel/cpio.c @@ -189,11 +189,11 @@ static int initramfs_fdt_parser(int level, char *cur, char *dt_strings) case FDT_PROP: prop = (struct fdt_property *)nodehdr; if (!strcmp("linux,initrd-start", dt_strings + fdtp_nameoff(prop))) { - initramfs_base = TO_CHAR_PTR(fdt32_ld((fdt32_t *)&prop->data)); + initramfs_base = TO_CHAR_PTR(PA2VA(fdt32_ld((fdt32_t *)&prop->data))); uart_printf("[*] initrd addr base: %x\r\n", initramfs_base); ok += 1; } else if (!strcmp("linux,initrd-end", dt_strings + fdtp_nameoff(prop))) { - initramfs_end = TO_CHAR_PTR(fdt32_ld((fdt32_t *)&prop->data)); + initramfs_end = TO_CHAR_PTR(PA2VA(fdt32_ld((fdt32_t *)&prop->data))); uart_printf("[*] initrd addr end : %x\r\n", initramfs_end); ok += 1; } diff --git a/src/kernel/head.S b/src/kernel/head.S index 85e704204..41a700fbe 100644 --- a/src/kernel/head.S +++ b/src/kernel/head.S @@ -9,6 +9,17 @@ _start: bl from_el2_to_el1 // the next instruction runs in EL1 + // Set booting stack + ldr x0, =_PA_stack_top + mov sp, x0 + + bl mmu_init + + // Use virtual address after mmu_init + ldr x0, =_va_trampoline + br x0 +_va_trampoline: + bl set_exception_vector_table bl enable_core0_timer diff --git a/src/kernel/irq.c b/src/kernel/irq.c index 24a04a41c..d72a4f463 100644 --- a/src/kernel/irq.c +++ b/src/kernel/irq.c @@ -251,5 +251,5 @@ void exception_default_handler(uint32 n) void irq1_enable(int bit) { - put32(IRQ_ENABLE_1_REG, 1 << bit); + put32(PA2VA(IRQ_ENABLE_1_REG), 1 << bit); } \ No newline at end of file diff --git a/src/kernel/linker.ld b/src/kernel/linker.ld index 86395ee04..4cf71d3d6 100644 --- a/src/kernel/linker.ld +++ b/src/kernel/linker.ld @@ -1,10 +1,11 @@ -_stack_top = 0x00400000; -_early_mem_base = 0x07000000; -_early_mem_end = 0x07ffffff; +_stack_top = 0xffff000000400000; +_PA_stack_top = 0x0000000000400000; +_early_mem_base = 0xffff000007000000; +_early_mem_end = 0xffff000007ffffff; SECTIONS { - . = 0x80000; + . = 0xffff000000080000; .text.boot : { *(.text.boot) diff --git a/src/kernel/main.c b/src/kernel/main.c index f309adcc3..2ad660f76 100644 --- a/src/kernel/main.c +++ b/src/kernel/main.c @@ -306,11 +306,11 @@ void start_kernel(char *fdt) uart_printf("[*] Kernel start!\r\n"); // TODO: Remove shell? - // kthread_create(shell); + kthread_create(shell); // TODO: Add argv & envp // First user program - sched_new_user_prog("syscall.img"); + // sched_new_user_prog("syscall.img"); // Enable interrupt from Auxiliary peripherals irq1_enable(29); diff --git a/src/kernel/mini_uart.c b/src/kernel/mini_uart.c index 848793aca..383e044f5 100644 --- a/src/kernel/mini_uart.c +++ b/src/kernel/mini_uart.c @@ -1,5 +1,4 @@ // Ref: https://github.com/s-matyukevich/raspberry-pi-os/blob/master/src/lesson01/src/mini_uart.c -#include #include #include #include @@ -36,9 +35,9 @@ static char uart_asyn_recv(void) char tmp; // Enable R interrupt - ier = get32(AUX_MU_IER_REG); + ier = get32(PA2VA(AUX_MU_IER_REG)); ier = ier | 0x01; - put32(AUX_MU_IER_REG, ier); + put32(PA2VA(AUX_MU_IER_REG), ier); while (r_head == r_tail) {} @@ -59,23 +58,23 @@ static void uart_asyn_send(char c) w_tail = (w_tail + 1) % BUFSIZE; // Enable W interrupt - ier = get32(AUX_MU_IER_REG); + ier = get32(PA2VA(AUX_MU_IER_REG)); ier = ier | 0x02; - put32(AUX_MU_IER_REG, ier); + put32(PA2VA(AUX_MU_IER_REG), ier); } static char uart_sync_recv(void) { - while (!(get32(AUX_MU_LSR_REG) & 0x01)) {}; + while (!(get32(PA2VA(AUX_MU_LSR_REG)) & 0x01)) {}; - return (get32(AUX_MU_IO_REG) & 0xFF); + return (get32(PA2VA(AUX_MU_IO_REG)) & 0xFF); } static void uart_sync_send(char c) { - while (!(get32(AUX_MU_LSR_REG) & 0x20)) {}; + while (!(get32(PA2VA(AUX_MU_LSR_REG)) & 0x20)) {}; - put32(AUX_MU_IO_REG, c); + put32(PA2VA(AUX_MU_IO_REG), c); } char uart_recv(void) @@ -253,31 +252,36 @@ void uart_sync_printf(const char *fmt, ...) va_end(args); } +void uart_sync_vprintf(const char *fmt, va_list args) +{ + _uart_printf(uart_sync_send, fmt, args); +} + void uart_init(void) { unsigned int selector; - selector = get32(GPFSEL1); + selector = get32(PA2VA(GPFSEL1)); selector &= ~(7 << 12); // Clean gpio14 selector |= 2 << 12; // Set alt5 for gpio14 selector &= ~(7 << 15); // Clean gpio15 selector |= 2 << 15; // Set alt5 for gpio15 - put32(GPFSEL1, selector); + put32(PA2VA(GPFSEL1), selector); - put32(GPPUD, 0); + put32(PA2VA(GPPUD), 0); delay(150); - put32(GPPUDCLK0, (1 << 14) | (1 << 15)); + put32(PA2VA(GPPUDCLK0), (1 << 14) | (1 << 15)); delay(150); - put32(GPPUDCLK0, 0); + put32(PA2VA(GPPUDCLK0), 0); - put32(AUX_ENABLES, 1); // Enable mini uart (this also enables access to its registers) - put32(AUX_MU_CNTL_REG, 0); // Disable auto flow control and disable receiver and transmitter (for now) - put32(AUX_MU_IER_REG, 0); // Disable receive and transmit interrupts - put32(AUX_MU_LCR_REG, 3); // Enable 8 bit mode - put32(AUX_MU_MCR_REG, 0); // Set RTS line to be always high - put32(AUX_MU_BAUD_REG, 270); // Set baud rate to 115200 - put32(AUX_MU_IIR_REG, 6); // Clear the Rx/Tx FIFO - put32(AUX_MU_CNTL_REG, 3); // Finally, enable transmitter and receiver + put32(PA2VA(AUX_ENABLES), 1); // Enable mini uart (this also enables access to its registers) + put32(PA2VA(AUX_MU_CNTL_REG), 0); // Disable auto flow control and disable receiver and transmitter (for now) + put32(PA2VA(AUX_MU_IER_REG), 0); // Disable receive and transmit interrupts + put32(PA2VA(AUX_MU_LCR_REG), 3); // Enable 8 bit mode + put32(PA2VA(AUX_MU_MCR_REG), 0); // Set RTS line to be always high + put32(PA2VA(AUX_MU_BAUD_REG), 270); // Set baud rate to 115200 + put32(PA2VA(AUX_MU_IIR_REG), 6); // Clear the Rx/Tx FIFO + put32(PA2VA(AUX_MU_CNTL_REG), 3); // Finally, enable transmitter and receiver // UART start from synchronous mode uart_sync_mode = 0; @@ -287,7 +291,7 @@ void uart_init(void) int uart_irq_check(void) { - uint32 iir = get32(AUX_MU_IIR_REG); + uint32 iir = get32(PA2VA(AUX_MU_IIR_REG)); if (iir & 0x01) { // No interrupt @@ -295,9 +299,9 @@ int uart_irq_check(void) } // Disable RW interrupt - put32(AUX_MU_IER_REG, 0); + put32(PA2VA(AUX_MU_IER_REG), 0); if (irq_run_task(uart_irq_handler, NULL, uart_irq_fini, 1)) { - put32(AUX_MU_IER_REG, 0x03); + put32(PA2VA(AUX_MU_IER_REG), 0x03); } return 1; @@ -305,18 +309,18 @@ int uart_irq_check(void) static void uart_irq_handler(void *_) { - uint32 iir = get32(AUX_MU_IIR_REG); + uint32 iir = get32(PA2VA(AUX_MU_IIR_REG)); if (iir & 0x02) { // Transmit holding register empty if (w_head != w_tail) { - put32(AUX_MU_IO_REG, w_ringbuf[w_head]); + put32(PA2VA(AUX_MU_IO_REG), w_ringbuf[w_head]); w_head = (w_head + 1) % BUFSIZE; } } else if (iir & 0x04) { // Receiver holds valid byte if (r_head != (r_tail + 1) % BUFSIZE) { - r_ringbuf[r_tail] = get32(AUX_MU_IO_REG) & 0xFF; + r_ringbuf[r_tail] = get32(PA2VA(AUX_MU_IO_REG)) & 0xFF; r_tail = (r_tail + 1) % BUFSIZE; } } @@ -324,7 +328,7 @@ static void uart_irq_handler(void *_) static void uart_irq_fini(void) { - uint32 ier = get32(AUX_MU_IER_REG); + uint32 ier = get32(PA2VA(AUX_MU_IER_REG)); ier = ier & ~(0x03); // Set RW interrupt @@ -336,13 +340,13 @@ static void uart_irq_fini(void) ier = ier | 0x02; } - put32(AUX_MU_IER_REG, ier); + put32(PA2VA(AUX_MU_IER_REG), ier); } int uart_switch_mode(void) { uart_sync_mode = !uart_sync_mode; - uint32 ier = get32(AUX_MU_IER_REG); + uint32 ier = get32(PA2VA(AUX_MU_IER_REG)); ier = ier & ~(0x03); if (uart_sync_mode == 0) { @@ -351,18 +355,18 @@ int uart_switch_mode(void) uart_send_fp = uart_sync_send; // Disable RW interrupt - put32(AUX_MU_IER_REG, ier); + put32(PA2VA(AUX_MU_IER_REG), ier); } else { // Asynchronous mode uart_recv_fp = uart_asyn_recv; uart_send_fp = uart_asyn_send; // Clear the Rx/Tx FIFO - put32(AUX_MU_IIR_REG, 6); + put32(PA2VA(AUX_MU_IIR_REG), 6); // Enable R interrupt ier = ier | 0x01; - put32(AUX_MU_IER_REG, ier); + put32(PA2VA(AUX_MU_IER_REG), ier); } return uart_sync_mode; diff --git a/src/kernel/mm/mm.c b/src/kernel/mm/mm.c index a8388bea3..51be322b1 100644 --- a/src/kernel/mm/mm.c +++ b/src/kernel/mm/mm.c @@ -64,11 +64,11 @@ void mm_init(void) { parse_dtb(fdt_base, memory_fdt_parser); - page_allocator_early_init((void *)0, (void *)memory_end); + page_allocator_early_init((void *)PA2VA(0), (void *)PA2VA(memory_end)); sc_early_init(); - // Spin tables for multicore boot - mem_reserve((void *)0, (void *)0x1000); + // Spin tables for multicore boot & Booting page tables + mem_reserve((void *)PA2VA(0), (void *)PA2VA(0x4000)); // Kernel image in the physical memory mem_reserve(_start, &_stack_top); diff --git a/src/kernel/mmu.c b/src/kernel/mmu.c new file mode 100644 index 000000000..c492d0dcc --- /dev/null +++ b/src/kernel/mmu.c @@ -0,0 +1,63 @@ +#include +#include + +#define TCR_CONFIG_REGION_48bit (((64 - 48) << 0) | ((64 - 48) << 16)) +#define TCR_CONFIG_4KB ((0b00 << 14) | (0b10 << 30)) +#define TCR_CONFIG_DEFAULT (TCR_CONFIG_REGION_48bit | TCR_CONFIG_4KB) + +#define MAIR_DEVICE_nGnRnE 0b00000000 +#define MAIR_NORMAL_NOCACHE 0b01000100 +#define MAIR_IDX_DEVICE_nGnRnE 0 +#define MAIR_IDX_NORMAL_NOCACHE 1 + +#define PD_TABLE 0b11 +#define PD_BLOCK 0b01 +#define PD_ACCESS (1 << 10) +#define PD_NSTABLE ((uint64)1 << 63) +#define PD_UXNTABLE ((uint64)1 << 60) +#define PD_MAIR_DEVICE_IDX (MAIR_IDX_DEVICE_nGnRnE << 2) +#define PD_MAIR_NORMAL_IDX (MAIR_IDX_NORMAL_NOCACHE << 2) +// Block Entry +#define PD_BE PD_ACCESS | PD_BLOCK + +#define BOOT_PGD ((pd_t *)0x1000) +#define BOOT_PUD ((pd_t *)0x2000) +#define BOOT_PMD ((pd_t *)0x3000) + +void mmu_init(void) +{ + uint32 sctlr_el1; + + // Set Translation Control Register + write_sysreg(TCR_EL1, TCR_CONFIG_DEFAULT); + + // Set Memory Attribute Indirection Register + write_sysreg(MAIR_EL1, + (MAIR_DEVICE_nGnRnE << (MAIR_IDX_DEVICE_nGnRnE * 8)) | + (MAIR_NORMAL_NOCACHE << (MAIR_IDX_NORMAL_NOCACHE * 8))); + + // Set Identity Paging + // 0x00000000 ~ 0x3f000000: Normal + // 0x3f000000 ~ 0x40000000: Device + // 0x40000000 ~ 0x80000000: Device + /* TODO: Support run user program in EL0 */ + BOOT_PGD[0] = (uint64)BOOT_PUD | PD_NSTABLE | PD_UXNTABLE | PD_TABLE; + + BOOT_PUD[0] = (uint64)BOOT_PMD | PD_TABLE; + BOOT_PUD[1] = 0x40000000 | PD_MAIR_DEVICE_IDX | PD_BE; + + for (int i = 0; i < 504; ++i) { + BOOT_PMD[i] = (i * (1 << 21)) | PD_MAIR_NORMAL_IDX | PD_BE; + } + + for (int i = 504; i < 512; ++i) { + BOOT_PMD[i] = (i * (1 << 21)) | PD_MAIR_DEVICE_IDX | PD_BE; + } + + write_sysreg(TTBR0_EL1, BOOT_PGD); + write_sysreg(TTBR1_EL1, BOOT_PGD); + + // Enable MMU + sctlr_el1 = read_sysreg(SCTLR_EL1); + write_sysreg(SCTLR_EL1, sctlr_el1 | 1); +} \ No newline at end of file diff --git a/src/kernel/panic.c b/src/kernel/panic.c new file mode 100644 index 000000000..c0452f6f0 --- /dev/null +++ b/src/kernel/panic.c @@ -0,0 +1,20 @@ +#include +#include + +void panic(const char *fmt, ...) +{ + va_list args; + va_start(args, fmt); + + uart_sync_printf("\n"); + + uart_sync_vprintf(fmt, args); + va_end(args); + + uart_sync_printf("\n"); + + // TODO: Show more information + + // Never return + while (1) {} +} \ No newline at end of file diff --git a/src/kernel/rpi3.c b/src/kernel/rpi3.c new file mode 100644 index 000000000..ed577ecec --- /dev/null +++ b/src/kernel/rpi3.c @@ -0,0 +1,101 @@ +// Ref: +// https://github.com/bztsrc/raspi3-tutorial/blob/master/04_mailboxes/mbox.h +// https://github.com/raspberrypi/firmware/wiki/Mailboxes +// https://github.com/raspberrypi/firmware/wiki/Accessing-mailboxes +#include +#include +#include + +/* Mailbox registers */ +#define MAILBOX_BASE PA2VA(PERIPHERALS_BASE + 0xb880) +#define MAILBOX_READ MAILBOX_BASE +#define MAILBOX_STATUS MAILBOX_BASE + 0x18 +#define MAILBOX_WRITE MAILBOX_BASE + 0x20 + +/* Tags */ +#define GET_BOARD_REVISION 0x00010002 +#define GET_ARM_MEMORY 0x00010005 + +/* Channels */ +#define MAILBOX_CH_POWER 0 +#define MAILBOX_CH_FB 1 +#define MAILBOX_CH_VUART 2 +#define MAILBOX_CH_VCHIQ 3 +#define MAILBOX_CH_LEDS 4 +#define MAILBOX_CH_BTNS 5 +#define MAILBOX_CH_TOUCH 6 +#define MAILBOX_CH_COUNT 7 +#define MAILBOX_CH_PROP 8 + +/* Others */ +#define MAILBOX_EMPTY 0x40000000 +#define MAILBOX_FULL 0x80000000 + +#define REQUEST_CODE 0x00000000 +#define REQUEST_SUCCEED 0x80000000 +#define REQUEST_FAILED 0x80000001 +#define TAG_REQUEST_CODE 0x00000000 +#define END_TAG 0x00000000 + +// Aligned buffer +static unsigned int __attribute__((aligned(0x10))) mailbox[16]; + +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)mb) & ~0xf) | channel; + + // Check if Mailbox 0 status register’s full flag is set. + while ((get32(MAILBOX_STATUS) & MAILBOX_FULL)) {}; + + // If not, then you can write to Mailbox 1 Read/Write register. + put32(MAILBOX_WRITE, r); + + while (1) { + // Check if Mailbox 0 status register’s empty flag is set. + while ((get32(MAILBOX_STATUS) & MAILBOX_EMPTY)) {}; + + // If not, then you can read from Mailbox 0 Read/Write register. + // Check if the value is the same as you wrote in step 1. + if (r == get32(MAILBOX_READ)) + return; + } +} + +// 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; + + mailbox_call(MAILBOX_CH_PROP, mailbox); // Message passing procedure call + + return mailbox[5]; +} + +void get_arm_memory(struct arm_memory_info *info) +{ + mailbox[0] = 8 * 4; // Buffer size in bytes + mailbox[1] = REQUEST_CODE; + // Tags begin + mailbox[2] = GET_ARM_MEMORY; // Tag identifier + mailbox[3] = 8; // Value buffer size in bytes + mailbox[4] = TAG_REQUEST_CODE; // Request/response codes + mailbox[5] = 0; // Optional value buffer + mailbox[6] = 0; // Optional value buffer + // Tags end + mailbox[7] = END_TAG; + + mailbox_call(MAILBOX_CH_PROP, mailbox); // Message passing procedure call + + info->baseaddr = mailbox[5]; + info->size = mailbox[6]; +} diff --git a/src/kernel/syscall.c b/src/kernel/syscall.c index 05cefe65c..1b9c49451 100644 --- a/src/kernel/syscall.c +++ b/src/kernel/syscall.c @@ -12,6 +12,7 @@ #include #include #include +#include #define KSTACK_VARIABLE(x) \ (void *)((uint64)x - \ @@ -70,7 +71,8 @@ void syscall_handler(trapframe regs, uint32 syn) // SVC instruction execution if (esr->ec != 0x15) { - return; + panic("[X] Panic: esr->ec: %x", esr->ec); + // Never return } syscall_num = regs.x8; diff --git a/src/kernel/timer.c b/src/kernel/timer.c index 0ccd4a6d6..79f603226 100644 --- a/src/kernel/timer.c +++ b/src/kernel/timer.c @@ -51,13 +51,13 @@ uint64 timer_boot_cnt; static void timer_enable() { // Enable core0 cntp timer - put32(CORE0_TIMER_IRQ_CTRL, 2); + put32(PA2VA(CORE0_TIMER_IRQ_CTRL), 2); } static void timer_disable() { // Disable core0 cntp timer - put32(CORE0_TIMER_IRQ_CTRL, 0); + put32(PA2VA(CORE0_TIMER_IRQ_CTRL), 0); } static timer_proc *tp_alloc() @@ -215,7 +215,7 @@ void timer_init() int timer_irq_check() { - uint32 core0_irq_src = get32(CORE0_IRQ_SOURCE); + uint32 core0_irq_src = get32(PA2VA(CORE0_IRQ_SOURCE)); if (!(core0_irq_src & 0x02)) { return 0; From 451a9a6e2f4b84f06392b21483a11b4f29230d38 Mon Sep 17 00:00:00 2001 From: LJP-TW Date: Tue, 17 May 2022 02:06:31 -0700 Subject: [PATCH 19/25] Adjust newline --- src/kernel/panic.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/kernel/panic.c b/src/kernel/panic.c index c0452f6f0..6f21244ec 100644 --- a/src/kernel/panic.c +++ b/src/kernel/panic.c @@ -6,12 +6,12 @@ void panic(const char *fmt, ...) va_list args; va_start(args, fmt); - uart_sync_printf("\n"); + uart_sync_printf("\r\n"); uart_sync_vprintf(fmt, args); va_end(args); - uart_sync_printf("\n"); + uart_sync_printf("\r\n"); // TODO: Show more information From 11685610cd15ad148d94ba234dd5c20d653bcb20 Mon Sep 17 00:00:00 2001 From: LJP-TW Date: Tue, 17 May 2022 09:36:19 -0700 Subject: [PATCH 20/25] Implement mapping of user address space Now the "fork" function in vm.img works and the video plays fine. TODO: - User program vm.img will use address 0x3cxxxxxx, need to figure out why and how to handle it properly - Map sigreturn to user address space and allow user to execute - Implement pt_free --- Makefile | 1 - include/kernel/mmu.h | 15 ++++++ include/kernel/task.h | 6 ++- include/lib/utils.h | 16 ++++++- src/kernel/exec.c | 15 ++++-- src/kernel/main.c | 4 +- src/kernel/mmu.c | 109 ++++++++++++++++++++++++++++++++++++++---- src/kernel/sched.S | 9 ++++ src/kernel/signal.c | 1 + src/kernel/syscall.c | 105 ++++++++++++++++++++++++++++++++-------- src/kernel/task.c | 5 ++ 11 files changed, 246 insertions(+), 40 deletions(-) diff --git a/Makefile b/Makefile index 965c0e84c..0f5e40644 100644 --- a/Makefile +++ b/Makefile @@ -90,7 +90,6 @@ $(INITRAMFS_CPIO): $(INITRAMFS_FILES) qemu: all $(INITRAMFS_CPIO) $(RPI3_DTB) qemu-system-aarch64 -M raspi3 -kernel $(BOOTLOADER_IMG) \ - -display none \ -initrd $(INITRAMFS_CPIO) \ -dtb $(RPI3_DTB) \ -chardev pty,id=pty0,logfile=pty.log,signal=off \ diff --git a/include/kernel/mmu.h b/include/kernel/mmu.h index 01af8764b..e1498d9f4 100644 --- a/include/kernel/mmu.h +++ b/include/kernel/mmu.h @@ -3,6 +3,12 @@ #include +#define PAGE_TABLE_SIZE 0x1000 + +#define PT_R 0x0001 +#define PT_W 0x0002 +#define PT_X 0x0004 + typedef uint64 pd_t; /* @@ -10,4 +16,13 @@ typedef uint64 pd_t; */ void mmu_init(void); +pd_t *pt_create(void); +void pt_free(pd_t *pt); + +/* + * Create a @size mapping of @va -> @pa. + * @pt is PGD. + */ +void pt_map(pd_t *pt, void *va, uint64 size, void *pa, uint64 flag); + #endif /* _MMU_H */ \ No newline at end of file diff --git a/include/kernel/task.h b/include/kernel/task.h index 1720f1455..02dbaf78f 100644 --- a/include/kernel/task.h +++ b/include/kernel/task.h @@ -3,8 +3,9 @@ #include #include +#include -#define STACK_SIZE (2 * PAGE_SIZE) +#define STACK_SIZE (4 * PAGE_SIZE) /* Task status */ #define TASK_NEW 0 @@ -32,8 +33,9 @@ struct pt_regs { }; typedef struct _task_struct { - /* This must be the first element */ struct pt_regs regs; + pd_t *page_table; + /* The order of the above elements cannot be changed */ void *kernel_stack; void *user_stack; /* TODO: Update to address_space */ diff --git a/include/lib/utils.h b/include/lib/utils.h index 6ebee0dd9..b144e56a1 100644 --- a/include/lib/utils.h +++ b/include/lib/utils.h @@ -36,6 +36,19 @@ void memncpy(char *dst, char *src, unsigned long n); asm volatile("msr DAIFSet, 0xf"); \ } while (0) +#define set_page_table(task) do { \ + asm volatile( \ + "mov x9, %0\n" \ + "and x9, x9, #0x0000ffffffffffff\n" \ + "dsb ish\n" \ + "msr ttbr0_el1, x9\n" \ + "tlbi vmalle1is\n" \ + "dsb ish\n" \ + "isb\n" \ + :: "r" (task->page_table) \ + ); \ +} while (0) + static inline uint32 save_and_disable_interrupt(void) { uint32 daif; @@ -60,6 +73,7 @@ static inline void restore_interrupt(uint32 daif) #define TO_CHAR_PTR(a) ((char *)(uint64)(a)) -#define PA2VA(x) ((uint64)x + 0xffff000000000000) +#define PA2VA(x) (((uint64)(x)) | 0xffff000000000000) +#define VA2PA(x) (((uint64)(x)) & 0x0000ffffffffffff) #endif /* _UTILS_H */ \ No newline at end of file diff --git a/src/kernel/exec.c b/src/kernel/exec.c index fb8b11b6a..24b645c8c 100644 --- a/src/kernel/exec.c +++ b/src/kernel/exec.c @@ -12,11 +12,7 @@ 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); + enter_el0_run_user_prog((void *)0, (char *)0xffffffffeff0); // User program should call exit() to terminate } @@ -60,6 +56,15 @@ void sched_new_user_prog(char *filename) task->regs.sp = (char *)task->kernel_stack + STACK_SIZE - 0x10; pt_regs_init(&task->regs); + pt_map(task->page_table, (void *)0, datalen, + (void *)VA2PA(task->data), PT_R | PT_W | PT_X); + pt_map(task->page_table, (void *)0xffffffffb000, STACK_SIZE, + (void *)VA2PA(task->user_stack), PT_R | PT_W); + + // TODO: Why is this needed for the vm.img to run? + pt_map(task->page_table, (void *)0x3c000000, 0x04000000, + (void *)0x3c000000, PT_R | PT_W); + sched_add_task(task); EXEC_USER_PROG_END: diff --git a/src/kernel/main.c b/src/kernel/main.c index 2ad660f76..65479c859 100644 --- a/src/kernel/main.c +++ b/src/kernel/main.c @@ -306,11 +306,11 @@ void start_kernel(char *fdt) uart_printf("[*] Kernel start!\r\n"); // TODO: Remove shell? - kthread_create(shell); + // kthread_create(shell); // TODO: Add argv & envp // First user program - // sched_new_user_prog("syscall.img"); + sched_new_user_prog("vm.img"); // Enable interrupt from Auxiliary peripherals irq1_enable(29); diff --git a/src/kernel/mmu.c b/src/kernel/mmu.c index c492d0dcc..64d7e7c7b 100644 --- a/src/kernel/mmu.c +++ b/src/kernel/mmu.c @@ -1,24 +1,28 @@ #include #include +#include #define TCR_CONFIG_REGION_48bit (((64 - 48) << 0) | ((64 - 48) << 16)) -#define TCR_CONFIG_4KB ((0b00 << 14) | (0b10 << 30)) -#define TCR_CONFIG_DEFAULT (TCR_CONFIG_REGION_48bit | TCR_CONFIG_4KB) +#define TCR_CONFIG_4KB ((0b00 << 14) | (0b10 << 30)) +#define TCR_CONFIG_DEFAULT (TCR_CONFIG_REGION_48bit | TCR_CONFIG_4KB) -#define MAIR_DEVICE_nGnRnE 0b00000000 +#define MAIR_DEVICE_nGnRnE 0b00000000 #define MAIR_NORMAL_NOCACHE 0b01000100 -#define MAIR_IDX_DEVICE_nGnRnE 0 +#define MAIR_IDX_DEVICE_nGnRnE 0 #define MAIR_IDX_NORMAL_NOCACHE 1 -#define PD_TABLE 0b11 -#define PD_BLOCK 0b01 -#define PD_ACCESS (1 << 10) -#define PD_NSTABLE ((uint64)1 << 63) -#define PD_UXNTABLE ((uint64)1 << 60) +#define PD_TABLE 0b11 +#define PD_BLOCK 0b01 +#define PD_ACCESS (1 << 10) +#define PD_PXN ((uint64)1 << 53) +#define PD_NSTABLE ((uint64)1 << 63) +#define PD_UXNTABLE ((uint64)1 << 60) #define PD_MAIR_DEVICE_IDX (MAIR_IDX_DEVICE_nGnRnE << 2) #define PD_MAIR_NORMAL_IDX (MAIR_IDX_NORMAL_NOCACHE << 2) // Block Entry #define PD_BE PD_ACCESS | PD_BLOCK +// Level 3 Block Entry +#define PD_L3BE PD_ACCESS | PD_TABLE #define BOOT_PGD ((pd_t *)0x1000) #define BOOT_PUD ((pd_t *)0x2000) @@ -60,4 +64,91 @@ void mmu_init(void) // Enable MMU sctlr_el1 = read_sysreg(SCTLR_EL1); write_sysreg(SCTLR_EL1, sctlr_el1 | 1); +} + +pd_t *pt_create(void) +{ + pd_t *pt = kmalloc(PAGE_TABLE_SIZE); + + for (int i = 0; i < PAGE_TABLE_SIZE / sizeof(pt[0]); ++i) { + pt[i] = 0; + } + + return pt; +} + +void pt_free(pd_t *pt) +{ + // TODO +} + +static void _pt_map(pd_t *pt, void *va, void *pa, uint64 flag) +{ + pd_t pd; + int idx; + + // 47 ~ 39, 38 ~ 30, 29 ~ 21, 20 ~ 12 + for (int layer = 3; layer > 0; --layer) { + idx = ((uint64)va >> (12 + 9 * layer)) & 0b111111111; + pd = pt[idx]; + + if (!(pd & 1)) { + // Invalid entry + pd_t *tmp = pt_create(); + pt[idx] = VA2PA(tmp) | PD_TABLE; + pt = tmp; + continue; + } + + // Must be a table entry + pt = (pd_t *)PA2VA(pd & ~((uint64)0xfff)); + } + + idx = ((uint64)va >> 12) & 0b111111111; + pd = pt[idx]; + + if (!(pd & 1)) { + // Invalid entry + // Access permissions + uint64 ap; + uint64 uxn; + + if (flag & PT_R) { + if (flag & PT_W) { + ap = 0b01; + } else { + ap = 0b11; + } + } else { + ap = 0b00; + } + + if (flag & PT_X) { + uxn = 0; + } else { + uxn = 1; + } + + pt[idx] = (uint64)pa | (uxn << 54) | PD_PXN | + PD_MAIR_NORMAL_IDX | (ap << 6) | PD_L3BE; + } + + // TODO: Already mapping, do nothing? +} + +void pt_map(pd_t *pt, void *va, uint64 size, void *pa, uint64 flag) +{ + if ((uint64)va & (PAGE_SIZE - 1)) { + return; + } + + if ((uint64)pa & (PAGE_SIZE - 1)) { + return; + } + + size = ALIGN(size, PAGE_SIZE); + + for (uint64 i = 0; i < size; i += PAGE_SIZE) { + _pt_map(pt, (void *)((uint64)va + i), (void *)((uint64)pa + i), flag); + } } \ No newline at end of file diff --git a/src/kernel/sched.S b/src/kernel/sched.S index 0fd3da883..c099ab1ca 100644 --- a/src/kernel/sched.S +++ b/src/kernel/sched.S @@ -21,4 +21,13 @@ switch_to: // set_current msr tpidr_el1, x1 + // Switch page table 0 + ldr x9, [x1, 8 * 13] + and x9, x9, #0x0000ffffffffffff + dsb ish // ensure write has completed + msr ttbr0_el1, x9 // switch translation based address. + tlbi vmalle1is // invalidate all TLB entries + dsb ish // ensure completion of TLB invalidatation + isb // clear pipeline + ret diff --git a/src/kernel/signal.c b/src/kernel/signal.c index 35205bc17..e84da66da 100644 --- a/src/kernel/signal.c +++ b/src/kernel/signal.c @@ -148,6 +148,7 @@ void handle_signal(trapframe *frame) // Set user pc to handler frame->elr_el1 = sigaction->sighand; + // TODO: Map sigreturn to user address space and allow user to execute // Set user lr to sigreturn frame->x30 = (uint64)sigreturn; } diff --git a/src/kernel/syscall.c b/src/kernel/syscall.c index 1b9c49451..6815d2c34 100644 --- a/src/kernel/syscall.c +++ b/src/kernel/syscall.c @@ -19,16 +19,6 @@ (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 *_); @@ -62,6 +52,45 @@ typedef struct { ec:6; // Exception class } esr_el1; +static void show_trapframe(trapframe *regs) +{ + uart_sync_printf("\r\n[*] Trapframe:\r\n"); + uart_sync_printf("\tx0: %llx\r\n", regs->x0); + uart_sync_printf("\tx1: %llx\r\n", regs->x1); + uart_sync_printf("\tx2: %llx\r\n", regs->x2); + uart_sync_printf("\tx3: %llx\r\n", regs->x3); + uart_sync_printf("\tx4: %llx\r\n", regs->x4); + uart_sync_printf("\tx5: %llx\r\n", regs->x5); + uart_sync_printf("\tx6: %llx\r\n", regs->x6); + uart_sync_printf("\tx7: %llx\r\n", regs->x7); + uart_sync_printf("\tx8: %llx\r\n", regs->x8); + uart_sync_printf("\tx9: %llx\r\n", regs->x9); + uart_sync_printf("\tx10: %llx\r\n", regs->x10); + uart_sync_printf("\tx11: %llx\r\n", regs->x11); + uart_sync_printf("\tx12: %llx\r\n", regs->x12); + uart_sync_printf("\tx13: %llx\r\n", regs->x13); + uart_sync_printf("\tx14: %llx\r\n", regs->x14); + uart_sync_printf("\tx15: %llx\r\n", regs->x15); + uart_sync_printf("\tx16: %llx\r\n", regs->x16); + uart_sync_printf("\tx17: %llx\r\n", regs->x17); + uart_sync_printf("\tx18: %llx\r\n", regs->x18); + uart_sync_printf("\tx19: %llx\r\n", regs->x19); + uart_sync_printf("\tx20: %llx\r\n", regs->x20); + uart_sync_printf("\tx21: %llx\r\n", regs->x21); + uart_sync_printf("\tx22: %llx\r\n", regs->x22); + uart_sync_printf("\tx23: %llx\r\n", regs->x23); + uart_sync_printf("\tx24: %llx\r\n", regs->x24); + uart_sync_printf("\tx25: %llx\r\n", regs->x25); + uart_sync_printf("\tx26: %llx\r\n", regs->x26); + uart_sync_printf("\tx27: %llx\r\n", regs->x27); + uart_sync_printf("\tx28: %llx\r\n", regs->x28); + uart_sync_printf("\tx29: %llx\r\n", regs->x29); + uart_sync_printf("\tx30: %llx\r\n", regs->x30); + uart_sync_printf("\tsp_el0 : %llx\r\n", regs->sp_el0); + uart_sync_printf("\telr_el1 : %llx\r\n", regs->elr_el1); + uart_sync_printf("\tspsr_el1: %llx\r\n", regs->spsr_el1); +} + void syscall_handler(trapframe regs, uint32 syn) { esr_el1 *esr; @@ -71,6 +100,7 @@ void syscall_handler(trapframe regs, uint32 syn) // SVC instruction execution if (esr->ec != 0x15) { + show_trapframe(®s); panic("[X] Panic: esr->ec: %x", esr->ec); // Never return } @@ -110,7 +140,6 @@ void syscall_exec(trapframe *_, const char* name, char *const argv[]) { void *data; char *kernel_sp; - char *user_sp; uint32 datalen; datalen = cpio_load_prog(initramfs_base, name, (char **)&data); @@ -128,13 +157,26 @@ void syscall_exec(trapframe *_, const char* name, char *const argv[]) current->datalen = datalen; 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); + // Reset page table + pt_free(current->page_table); + current->page_table = pt_create(); + pt_map(current->page_table, (void *)0, datalen, + (void *)VA2PA(data), PT_R | PT_W | PT_X); + pt_map(current->page_table, (void *)0xffffffffb000, STACK_SIZE, + (void *)VA2PA(current->user_stack), PT_R | PT_W); + + // TODO: Why is this needed for the vm.img to run? + pt_map(current->page_table, (void *)0x3c000000, 0x04000000, + (void *)0x3c000000, PT_R | PT_W); + + set_page_table(current); + + exec_user_prog((void *)0, (char *)0xffffffffeff0, kernel_sp); } static inline void copy_regs(struct pt_regs *regs) @@ -167,16 +209,26 @@ void syscall_fork(trapframe *frame) memncpy(child->user_stack, current->user_stack, STACK_SIZE); memncpy(child->data, current->data, current->datalen); + // Set page table + pt_map(child->page_table, (void *)0, child->datalen, + (void *)VA2PA(child->data), PT_R | PT_W | PT_X); + pt_map(child->page_table, (void *)0xffffffffb000, STACK_SIZE, + (void *)VA2PA(child->user_stack), PT_R | PT_W); + + // TODO: Why is this needed for the vm.img to run? + pt_map(child->page_table, (void *)0x3c000000, 0x04000000, + (void *)0x3c000000, PT_R | PT_W); + // Copy signal handler sighand_copy(child->sighand, child->data); - // Save regs + // Save registers SAVE_REGS(current); - // Copy register + // Copy registers copy_regs(&child->regs); - // Copy stack realted registers + // Copy stack related registers child->regs.fp = KSTACK_VARIABLE(current->regs.fp); child->regs.sp = KSTACK_VARIABLE(current->regs.sp); @@ -187,9 +239,6 @@ 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); sched_add_task(child); @@ -210,7 +259,23 @@ void syscall_exit(trapframe *_) void syscall_mbox_call(trapframe *_, unsigned char ch, unsigned int *mbox) { - mailbox_call(ch, mbox); + int mbox_size; + char *kmbox; + + mbox_size = (int)mbox[0]; + + if (mbox_size <= 0) + return; + + kmbox = kmalloc(mbox_size); + + memncpy(kmbox, (char *)mbox, mbox_size); + + mailbox_call(ch, (unsigned int *)kmbox); + + memncpy((char *)mbox, kmbox, mbox_size); + + kfree(kmbox); } void syscall_kill_pid(trapframe *_, int pid) diff --git a/src/kernel/task.c b/src/kernel/task.c index 49b1aaae7..fdf7205c3 100644 --- a/src/kernel/task.c +++ b/src/kernel/task.c @@ -28,14 +28,17 @@ task_struct *task_create(void) task_struct *task; struct signal_head_t *signal; struct sighand_t *sighand; + pd_t *page_table; task = kmalloc(sizeof(task_struct)); signal = signal_head_create(); sighand = sighand_create(); + page_table = pt_create(); task->kernel_stack = NULL; task->user_stack = NULL; task->data = NULL; + task->page_table = page_table; INIT_LIST_HEAD(&task->list); list_add_tail(&task->task_list, &task_queue); task->status = TASK_NEW; @@ -65,6 +68,8 @@ void task_free(task_struct *task) signal_head_free(task->signal); sighand_free(task->sighand); + pt_free(task->page_table); + // TODO: release tid kfree(task); From ae62b96772c2a76c0b3d4eba9073486ae3ce0efd Mon Sep 17 00:00:00 2001 From: LJP-TW Date: Wed, 18 May 2022 07:53:35 -0700 Subject: [PATCH 21/25] Remove some comment --- include/kernel/task.h | 1 - src/kernel/mmu.c | 1 - 2 files changed, 2 deletions(-) diff --git a/include/kernel/task.h b/include/kernel/task.h index 02dbaf78f..40d6a9689 100644 --- a/include/kernel/task.h +++ b/include/kernel/task.h @@ -38,7 +38,6 @@ typedef struct _task_struct { /* The order of the above elements cannot be changed */ void *kernel_stack; void *user_stack; - /* TODO: Update to address_space */ void *data; uint32 datalen; /* @list is used by run_queue / wait_queue */ diff --git a/src/kernel/mmu.c b/src/kernel/mmu.c index 64d7e7c7b..b6a81685f 100644 --- a/src/kernel/mmu.c +++ b/src/kernel/mmu.c @@ -44,7 +44,6 @@ void mmu_init(void) // 0x00000000 ~ 0x3f000000: Normal // 0x3f000000 ~ 0x40000000: Device // 0x40000000 ~ 0x80000000: Device - /* TODO: Support run user program in EL0 */ BOOT_PGD[0] = (uint64)BOOT_PUD | PD_NSTABLE | PD_UXNTABLE | PD_TABLE; BOOT_PUD[0] = (uint64)BOOT_PMD | PD_TABLE; From 6c93febccece80c1b0957221fcdc279df38794d9 Mon Sep 17 00:00:00 2001 From: LJP-TW Date: Wed, 18 May 2022 08:06:26 -0700 Subject: [PATCH 22/25] Map 0x3c000000 ~ 0x3f000000 identity paging for mailbox The mailbox communication uses PA, and it may return some PA address at 0x3c000000 ~ 0x3f000000. The user program vm.img will use it. Currently implementation just does an identity paging for the user page table. --- src/kernel/exec.c | 4 ++-- src/kernel/syscall.c | 11 +++++++---- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/src/kernel/exec.c b/src/kernel/exec.c index 24b645c8c..0968848c9 100644 --- a/src/kernel/exec.c +++ b/src/kernel/exec.c @@ -61,8 +61,8 @@ void sched_new_user_prog(char *filename) pt_map(task->page_table, (void *)0xffffffffb000, STACK_SIZE, (void *)VA2PA(task->user_stack), PT_R | PT_W); - // TODO: Why is this needed for the vm.img to run? - pt_map(task->page_table, (void *)0x3c000000, 0x04000000, + // TODO: map the return addres of mailbox_call + pt_map(task->page_table, (void *)0x3c000000, 0x03000000, (void *)0x3c000000, PT_R | PT_W); sched_add_task(task); diff --git a/src/kernel/syscall.c b/src/kernel/syscall.c index 6815d2c34..66fceb2fe 100644 --- a/src/kernel/syscall.c +++ b/src/kernel/syscall.c @@ -170,8 +170,8 @@ void syscall_exec(trapframe *_, const char* name, char *const argv[]) pt_map(current->page_table, (void *)0xffffffffb000, STACK_SIZE, (void *)VA2PA(current->user_stack), PT_R | PT_W); - // TODO: Why is this needed for the vm.img to run? - pt_map(current->page_table, (void *)0x3c000000, 0x04000000, + // TODO: map the return addres of mailbox_call + pt_map(current->page_table, (void *)0x3c000000, 0x03000000, (void *)0x3c000000, PT_R | PT_W); set_page_table(current); @@ -215,8 +215,8 @@ void syscall_fork(trapframe *frame) pt_map(child->page_table, (void *)0xffffffffb000, STACK_SIZE, (void *)VA2PA(child->user_stack), PT_R | PT_W); - // TODO: Why is this needed for the vm.img to run? - pt_map(child->page_table, (void *)0x3c000000, 0x04000000, + // TODO: map the return addres of mailbox_call + pt_map(child->page_table, (void *)0x3c000000, 0x03000000, (void *)0x3c000000, PT_R | PT_W); // Copy signal handler @@ -257,6 +257,9 @@ void syscall_exit(trapframe *_) // Never reach } +/* + * TODO: map the return addres of mailbox_call + */ void syscall_mbox_call(trapframe *_, unsigned char ch, unsigned int *mbox) { int mbox_size; From 3a19963090e3baded808703f3ec2aabdbe87eadf Mon Sep 17 00:00:00 2001 From: LJP-TW Date: Wed, 18 May 2022 09:54:36 -0700 Subject: [PATCH 23/25] Fix signal related problem caused by enabling MMU --- include/kernel/task.h | 9 +++++++++ include/kernel/text_user_shared.h | 25 ++++++++++++++++++++++++ src/kernel/exec.c | 9 +++------ src/kernel/linker.ld | 10 ++++++++++ src/kernel/signal.c | 32 +++++++------------------------ src/kernel/syscall.c | 18 ++++++----------- src/kernel/task.c | 15 +++++++++++++++ 7 files changed, 75 insertions(+), 43 deletions(-) create mode 100644 include/kernel/text_user_shared.h diff --git a/include/kernel/task.h b/include/kernel/task.h index 40d6a9689..4a17b87da 100644 --- a/include/kernel/task.h +++ b/include/kernel/task.h @@ -73,4 +73,13 @@ void task_free(task_struct *task); task_struct *task_get_by_tid(uint32 tid); +/* + * Create initial mapping for user program + * + * 0x00003c000000 ~ 0x00003f000000: rw-: Mailbox address + * 0x7f0000000000 ~ : r-x: Kernel functions exposed to users + * 0xffffffffb000 ~ : rw-: Stack + */ +void task_init_map(task_struct *task); + #endif /* _TASK_H */ \ No newline at end of file diff --git a/include/kernel/text_user_shared.h b/include/kernel/text_user_shared.h new file mode 100644 index 000000000..3be42d0ed --- /dev/null +++ b/include/kernel/text_user_shared.h @@ -0,0 +1,25 @@ +#ifndef _TEXT_USER_SHARED_H +#define _TEXT_USER_SHARED_H + +/* + * See the comment of task_init_map in task.h: + * + * 0x7f0000000000 ~ : r-x: Kernel functions exposed to users + * + * The kernel functions with the SECTION_TUS attribute will be mapped into + * this user address space. + */ + +#define SECTION_TUS __attribute__ ((section (".text.user.shared"))) + +#define TUS2VA(x) ((((uint64)x) - TEXT_USER_SHARED_BASE) + 0x7f0000000000) + +/* From linker.ld */ +extern char _stext_user_shared; +extern char _etext_user_shared; + +#define TEXT_USER_SHARED_BASE (uint64)(&_stext_user_shared) +#define TEXT_USER_SHARED_END (uint64)(&_etext_user_shared) +#define TEXT_USER_SHARED_LEN (TEXT_USER_SHARED_END - TEXT_USER_SHARED_BASE) + +#endif /* _TEXT_USER_SHARED_H */ \ No newline at end of file diff --git a/src/kernel/exec.c b/src/kernel/exec.c index 0968848c9..919e16cd4 100644 --- a/src/kernel/exec.c +++ b/src/kernel/exec.c @@ -56,14 +56,11 @@ void sched_new_user_prog(char *filename) task->regs.sp = (char *)task->kernel_stack + STACK_SIZE - 0x10; pt_regs_init(&task->regs); + task_init_map(task); + + // 0x000000000000 ~ : rwx: Code pt_map(task->page_table, (void *)0, datalen, (void *)VA2PA(task->data), PT_R | PT_W | PT_X); - pt_map(task->page_table, (void *)0xffffffffb000, STACK_SIZE, - (void *)VA2PA(task->user_stack), PT_R | PT_W); - - // TODO: map the return addres of mailbox_call - pt_map(task->page_table, (void *)0x3c000000, 0x03000000, - (void *)0x3c000000, PT_R | PT_W); sched_add_task(task); diff --git a/src/kernel/linker.ld b/src/kernel/linker.ld index 4cf71d3d6..e2dc7a44c 100644 --- a/src/kernel/linker.ld +++ b/src/kernel/linker.ld @@ -15,6 +15,16 @@ SECTIONS *(.text) } + . = ALIGN(0x1000); + + _stext_user_shared = .; + .text.user.shared : { + *(.text.user.shared) + } + + . = ALIGN(0x1000); + _etext_user_shared = .; + .rodata : { *(.rodata) } diff --git a/src/kernel/signal.c b/src/kernel/signal.c index e84da66da..6a45d7fb9 100644 --- a/src/kernel/signal.c +++ b/src/kernel/signal.c @@ -4,6 +4,7 @@ #include #include #include +#include // TODO: implement SIGSTOP & SIGCONT kernel handler @@ -31,10 +32,7 @@ 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) SECTION_TUS; void sigreturn(void) { // sigreturn: syscall 11 @@ -148,9 +146,8 @@ void handle_signal(trapframe *frame) // Set user pc to handler frame->elr_el1 = sigaction->sighand; - // TODO: Map sigreturn to user address space and allow user to execute // Set user lr to sigreturn - frame->x30 = (uint64)sigreturn; + frame->x30 = TUS2VA(sigreturn); } signal_del(signal); @@ -187,21 +184,13 @@ void sighand_reset(struct sighand_t *sighand) sighand->sigactions[SIGKILL].sighand = sig_termiante; } -static inline void kernel_sighand_copy(struct sigaction_t *from, - struct sigaction_t *to) +static inline void _sighand_copy(struct sigaction_t *to, + struct sigaction_t *from) { - to->kernel_hand = 1; + to->kernel_hand = from->kernel_hand; 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) { @@ -210,14 +199,7 @@ void sighand_copy(struct sighand_t *sighand, void *addrbase) 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)); - } + _sighand_copy(&sighand->sigactions[i], &currhand->sigactions[i]); } } diff --git a/src/kernel/syscall.c b/src/kernel/syscall.c index 66fceb2fe..76ae84cf5 100644 --- a/src/kernel/syscall.c +++ b/src/kernel/syscall.c @@ -165,14 +165,11 @@ void syscall_exec(trapframe *_, const char* name, char *const argv[]) // Reset page table pt_free(current->page_table); current->page_table = pt_create(); + task_init_map(current); + + // 0x000000000000 ~ : rwx: Code pt_map(current->page_table, (void *)0, datalen, (void *)VA2PA(data), PT_R | PT_W | PT_X); - pt_map(current->page_table, (void *)0xffffffffb000, STACK_SIZE, - (void *)VA2PA(current->user_stack), PT_R | PT_W); - - // TODO: map the return addres of mailbox_call - pt_map(current->page_table, (void *)0x3c000000, 0x03000000, - (void *)0x3c000000, PT_R | PT_W); set_page_table(current); @@ -210,14 +207,11 @@ void syscall_fork(trapframe *frame) memncpy(child->data, current->data, current->datalen); // Set page table + task_init_map(child); + + // 0x000000000000 ~ : rwx: Code pt_map(child->page_table, (void *)0, child->datalen, (void *)VA2PA(child->data), PT_R | PT_W | PT_X); - pt_map(child->page_table, (void *)0xffffffffb000, STACK_SIZE, - (void *)VA2PA(child->user_stack), PT_R | PT_W); - - // TODO: map the return addres of mailbox_call - pt_map(child->page_table, (void *)0x3c000000, 0x03000000, - (void *)0x3c000000, PT_R | PT_W); // Copy signal handler sighand_copy(child->sighand, child->data); diff --git a/src/kernel/task.c b/src/kernel/task.c index fdf7205c3..b3cb223b1 100644 --- a/src/kernel/task.c +++ b/src/kernel/task.c @@ -1,6 +1,8 @@ #include #include #include +#include +#include // TODO: Use rbtree to manage tasks static struct list_head task_queue; @@ -86,4 +88,17 @@ task_struct *task_get_by_tid(uint32 tid) } return NULL; +} + +void task_init_map(task_struct *task) +{ + // TODO: map the return addres of mailbox_call + pt_map(task->page_table, (void *)0x3c000000, 0x03000000, + (void *)0x3c000000, PT_R | PT_W); + + pt_map(task->page_table, (void *)0x7f0000000000, TEXT_USER_SHARED_LEN, + (void *)VA2PA(TEXT_USER_SHARED_BASE), PT_R | PT_X); + + pt_map(task->page_table, (void *)0xffffffffb000, STACK_SIZE, + (void *)VA2PA(task->user_stack), PT_R | PT_W); } \ No newline at end of file From adea55689459d554d8766b52fb0ee2f5c6d04fbc Mon Sep 17 00:00:00 2001 From: LJP-TW Date: Thu, 19 May 2022 04:33:32 -0700 Subject: [PATCH 24/25] Implement demand paging --- Makefile | 8 +- README.md | 6 +- include/kernel/arm.h | 28 +++ include/kernel/entry.h | 9 + include/kernel/mm/page_alloc.h | 2 +- include/kernel/mm/sc_alloc.h | 2 +- include/kernel/mmu.h | 37 ++++ include/kernel/signal.h | 2 +- include/kernel/syscall.h | 5 +- include/kernel/task.h | 6 +- include/kernel/trapframe.h | 40 ++++ include/lib/utils.h | 10 +- src/kernel/entry.c | 25 +++ src/kernel/exec.c | 7 +- src/kernel/head.S | 2 +- src/kernel/mm/early_alloc.c | 2 +- src/kernel/mm/mm.c | 2 +- src/kernel/mm/page_alloc.c | 18 +- src/kernel/mm/sc_alloc.c | 8 +- src/kernel/mmu.c | 329 +++++++++++++++++++++++++++++++++ src/kernel/panic.c | 2 +- src/kernel/signal.c | 4 +- src/kernel/syscall.c | 103 +++-------- src/kernel/task.c | 33 ++-- 24 files changed, 554 insertions(+), 136 deletions(-) create mode 100644 include/kernel/arm.h create mode 100644 include/kernel/entry.h create mode 100644 src/kernel/entry.c diff --git a/Makefile b/Makefile index 0f5e40644..b4da3490a 100644 --- a/Makefile +++ b/Makefile @@ -43,8 +43,12 @@ LIB_ASM_FILES += $(shell find "$(SRC_DIR)/$(LIB_DIR)" -name "*.S") LIB_OBJ_FILES = $(patsubst $(SRC_DIR)/$(LIB_DIR)/%.c,$(BUILD_DIR)/$(LIB_DIR)/%_c.o,$(LIB_C_FILES)) LIB_OBJ_FILES += $(patsubst $(SRC_DIR)/$(LIB_DIR)/%.S,$(BUILD_DIR)/$(LIB_DIR)/%_s.o,$(LIB_ASM_FILES)) -ifdef DEBUG - CFLAGS += -g -DDEBUG +ifdef MM_DEBUG + CFLAGS += -g -DMM_DEBUG +endif + +ifdef DEMANDING_PAGE_DEBUG + CFLAGS += -g -DDEMANDING_PAGE_DEBUG endif all: $(KERNEL_IMG) $(BOOTLOADER_IMG) diff --git a/README.md b/README.md index 73dfe5019..024fb61d6 100644 --- a/README.md +++ b/README.md @@ -20,7 +20,11 @@ make * Build kernel8.img with some debug information: ``` -make DEBUG=1 +# Options: +# MM_DEBUG +# DEMANDING_PAGE_DEBUG +make MM_DEBUG=1 +make DEMANDING_PAGE_DEBUG=1 ``` * Build myos.img (which you can dd to SD card): diff --git a/include/kernel/arm.h b/include/kernel/arm.h new file mode 100644 index 000000000..c0e282c21 --- /dev/null +++ b/include/kernel/arm.h @@ -0,0 +1,28 @@ +#ifndef _ARM_H +#define _ARM_H + +/* ==== PAR_EL1 related ==== */ +#define PAR_FAILED(par) (par & 1) +#define PAR_PA(par) (par & 0x0000fffffffff000) + +/* ==== ESR_EL1 related ==== */ +#define EC_SVC_64 0x15 +#define EC_IA_LE 0x20 +#define EC_DA_LE 0x24 + +#define ISS_FSC(esr) (esr->iss & 0x3f) + +#define FSC_TF_L0 0b000100 +#define FSC_TF_L1 0b000101 +#define FSC_TF_L2 0b000110 +#define FSC_TF_L3 0b000111 + +#define ISS_WnR(esr) (esr->iss & 0x40) + +typedef struct { + unsigned int iss:25, // Instruction specific syndrome + il:1, // Instruction length bit + ec:6; // Exception class +} esr_el1_t; + +#endif /* _ARM_H */ \ No newline at end of file diff --git a/include/kernel/entry.h b/include/kernel/entry.h new file mode 100644 index 000000000..0f7d560f9 --- /dev/null +++ b/include/kernel/entry.h @@ -0,0 +1,9 @@ +#ifndef _ENTRY_H +#define _ENTRY_H + +#include +#include + +void el0_sync_handler(trapframe *regs, uint32 syn); + +#endif /* _ENTRY_H */ \ No newline at end of file diff --git a/include/kernel/mm/page_alloc.h b/include/kernel/mm/page_alloc.h index 7f6c09ad6..c4b6ee05c 100644 --- a/include/kernel/mm/page_alloc.h +++ b/include/kernel/mm/page_alloc.h @@ -52,7 +52,7 @@ void *alloc_page(void); void free_page(void *page); -#ifdef DEBUG +#ifdef MM_DEBUG void page_allocator_test(void); #endif diff --git a/include/kernel/mm/sc_alloc.h b/include/kernel/mm/sc_alloc.h index 0fd8c426c..991a98ca7 100644 --- a/include/kernel/mm/sc_alloc.h +++ b/include/kernel/mm/sc_alloc.h @@ -14,7 +14,7 @@ void *sc_alloc(int size); */ int sc_free(void *sc); -#ifdef DEBUG +#ifdef MM_DEBUG void sc_test(void); #endif diff --git a/include/kernel/mmu.h b/include/kernel/mmu.h index e1498d9f4..87b813df3 100644 --- a/include/kernel/mmu.h +++ b/include/kernel/mmu.h @@ -2,6 +2,8 @@ #define _MMU_H #include +#include +#include #define PAGE_TABLE_SIZE 0x1000 @@ -9,8 +11,34 @@ #define PT_W 0x0002 #define PT_X 0x0004 +#define VMA_R PT_R +#define VMA_W PT_W +#define VMA_X PT_X +// PA +#define VMA_PA 0x0008 +// Kernel VA +#define VMA_KVA 0x0010 +// Anonymous +#define VMA_ANON 0x0020 + typedef uint64 pd_t; +/* TODO: The vm_area_t linked list is not sorted, making it an ordered list. */ +typedef struct _vm_area_t { + /* @list links to next vm_area_t */ + struct list_head list; + uint64 va_begin; + uint64 va_end; + uint64 flag; + /* @kva: Mapped kernel virtual address */ + uint64 kva; +} vm_area_t; + +typedef struct { + /* @vma links all vm_area_t */ + struct list_head vma; +} vm_area_meta_t; + /* * Set identity paging, enable MMU */ @@ -25,4 +53,13 @@ void pt_free(pd_t *pt); */ void pt_map(pd_t *pt, void *va, uint64 size, void *pa, uint64 flag); +vm_area_meta_t *vma_meta_create(void); +void vma_meta_free(vm_area_meta_t *vma_meta, pd_t *page_table); +void vma_meta_copy(vm_area_meta_t *to, vm_area_meta_t *from, pd_t *page_table); + +void vma_map(vm_area_meta_t *vma_meta, void *va, uint64 size, + uint64 flag, void *addr); + +void mem_abort(esr_el1_t *esr); + #endif /* _MMU_H */ \ No newline at end of file diff --git a/include/kernel/signal.h b/include/kernel/signal.h index 4f6bdc108..69cf991f1 100644 --- a/include/kernel/signal.h +++ b/include/kernel/signal.h @@ -79,7 +79,7 @@ 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); +void sighand_copy(struct sighand_t *sighand); /* syscalls */ void syscall_signal(trapframe *_, uint32 signal, void (*handler)(int)); diff --git a/include/kernel/syscall.h b/include/kernel/syscall.h index f1a7593ac..34fba9bbf 100644 --- a/include/kernel/syscall.h +++ b/include/kernel/syscall.h @@ -1,11 +1,8 @@ #ifndef _SYSCALL_H #define _SYSCALL_H -#include #include -// @syn: syndrome information for an synchronous exception -// One should pass esr_el1 register value to @syn -void syscall_handler(trapframe regs, uint32 syn); +void syscall_handler(trapframe *regs); #endif /* _SYSCALL_H */ \ No newline at end of file diff --git a/include/kernel/task.h b/include/kernel/task.h index 4a17b87da..767fdbc1d 100644 --- a/include/kernel/task.h +++ b/include/kernel/task.h @@ -36,10 +36,8 @@ typedef struct _task_struct { struct pt_regs regs; pd_t *page_table; /* The order of the above elements cannot be changed */ + vm_area_meta_t *address_space; void *kernel_stack; - void *user_stack; - void *data; - uint32 datalen; /* @list is used by run_queue / wait_queue */ struct list_head list; /* @task_list links all tasks */ @@ -82,4 +80,6 @@ task_struct *task_get_by_tid(uint32 tid); */ void task_init_map(task_struct *task); +void task_reset_mm(task_struct *task); + #endif /* _TASK_H */ \ No newline at end of file diff --git a/include/kernel/trapframe.h b/include/kernel/trapframe.h index 4a9cb37b5..530467f54 100644 --- a/include/kernel/trapframe.h +++ b/include/kernel/trapframe.h @@ -2,6 +2,7 @@ #define _TRAPFRAME_H #include +#include typedef struct { uint64 x0; @@ -40,4 +41,43 @@ typedef struct { void *spsr_el1; } trapframe; +static inline void show_trapframe(trapframe *regs) +{ + uart_sync_printf("\r\n[*] Trapframe:\r\n"); + uart_sync_printf("\tx0: %llx\r\n", regs->x0); + uart_sync_printf("\tx1: %llx\r\n", regs->x1); + uart_sync_printf("\tx2: %llx\r\n", regs->x2); + uart_sync_printf("\tx3: %llx\r\n", regs->x3); + uart_sync_printf("\tx4: %llx\r\n", regs->x4); + uart_sync_printf("\tx5: %llx\r\n", regs->x5); + uart_sync_printf("\tx6: %llx\r\n", regs->x6); + uart_sync_printf("\tx7: %llx\r\n", regs->x7); + uart_sync_printf("\tx8: %llx\r\n", regs->x8); + uart_sync_printf("\tx9: %llx\r\n", regs->x9); + uart_sync_printf("\tx10: %llx\r\n", regs->x10); + uart_sync_printf("\tx11: %llx\r\n", regs->x11); + uart_sync_printf("\tx12: %llx\r\n", regs->x12); + uart_sync_printf("\tx13: %llx\r\n", regs->x13); + uart_sync_printf("\tx14: %llx\r\n", regs->x14); + uart_sync_printf("\tx15: %llx\r\n", regs->x15); + uart_sync_printf("\tx16: %llx\r\n", regs->x16); + uart_sync_printf("\tx17: %llx\r\n", regs->x17); + uart_sync_printf("\tx18: %llx\r\n", regs->x18); + uart_sync_printf("\tx19: %llx\r\n", regs->x19); + uart_sync_printf("\tx20: %llx\r\n", regs->x20); + uart_sync_printf("\tx21: %llx\r\n", regs->x21); + uart_sync_printf("\tx22: %llx\r\n", regs->x22); + uart_sync_printf("\tx23: %llx\r\n", regs->x23); + uart_sync_printf("\tx24: %llx\r\n", regs->x24); + uart_sync_printf("\tx25: %llx\r\n", regs->x25); + uart_sync_printf("\tx26: %llx\r\n", regs->x26); + uart_sync_printf("\tx27: %llx\r\n", regs->x27); + uart_sync_printf("\tx28: %llx\r\n", regs->x28); + uart_sync_printf("\tx29: %llx\r\n", regs->x29); + uart_sync_printf("\tx30: %llx\r\n", regs->x30); + uart_sync_printf("\tsp_el0 : %llx\r\n", regs->sp_el0); + uart_sync_printf("\telr_el1 : %llx\r\n", regs->elr_el1); + uart_sync_printf("\tspsr_el1: %llx\r\n", regs->spsr_el1); +} + #endif /* _TRAPFRAME_H */ \ No newline at end of file diff --git a/include/lib/utils.h b/include/lib/utils.h index b144e56a1..f8546c975 100644 --- a/include/lib/utils.h +++ b/include/lib/utils.h @@ -36,7 +36,7 @@ void memncpy(char *dst, char *src, unsigned long n); asm volatile("msr DAIFSet, 0xf"); \ } while (0) -#define set_page_table(task) do { \ +#define set_page_table(page_table) do { \ asm volatile( \ "mov x9, %0\n" \ "and x9, x9, #0x0000ffffffffffff\n" \ @@ -45,10 +45,16 @@ void memncpy(char *dst, char *src, unsigned long n); "tlbi vmalle1is\n" \ "dsb ish\n" \ "isb\n" \ - :: "r" (task->page_table) \ + :: "r" (page_table) \ ); \ } while (0) +#define get_page_table() ({ \ + uint64 __val; \ + __val = PA2VA(read_sysreg(TTBR0_EL1)); \ + __val; \ +}) + static inline uint32 save_and_disable_interrupt(void) { uint32 daif; diff --git a/src/kernel/entry.c b/src/kernel/entry.c new file mode 100644 index 000000000..7e62b4681 --- /dev/null +++ b/src/kernel/entry.c @@ -0,0 +1,25 @@ +#include +#include +#include +#include +#include + +void el0_sync_handler(trapframe *regs, uint32 syn) +{ + esr_el1_t *esr; + + esr = (esr_el1_t *)&syn; + + switch (esr->ec) { + case EC_SVC_64: + syscall_handler(regs); + break; + case EC_IA_LE: + case EC_DA_LE: + mem_abort(esr); + break; + default: + show_trapframe(regs); + panic("esr->ec: %x", esr->ec); + } +} \ No newline at end of file diff --git a/src/kernel/exec.c b/src/kernel/exec.c index 919e16cd4..7722efdff 100644 --- a/src/kernel/exec.c +++ b/src/kernel/exec.c @@ -49,9 +49,6 @@ void sched_new_user_prog(char *filename) task = task_create(); 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); @@ -59,8 +56,8 @@ void sched_new_user_prog(char *filename) task_init_map(task); // 0x000000000000 ~ : rwx: Code - pt_map(task->page_table, (void *)0, datalen, - (void *)VA2PA(task->data), PT_R | PT_W | PT_X); + vma_map(task->address_space, (void *)0, datalen, + VMA_R | VMA_W | VMA_X | VMA_KVA, data); sched_add_task(task); diff --git a/src/kernel/head.S b/src/kernel/head.S index 41a700fbe..1deaeaa08 100644 --- a/src/kernel/head.S +++ b/src/kernel/head.S @@ -193,7 +193,7 @@ l64_syn_eh: mov x0, sp mrs x1, esr_el1 - bl syscall_handler + bl el0_sync_handler mov x0, sp bl exit_to_user_mode diff --git a/src/kernel/mm/early_alloc.c b/src/kernel/mm/early_alloc.c index 4bf02c8ac..8494a9d1d 100644 --- a/src/kernel/mm/early_alloc.c +++ b/src/kernel/mm/early_alloc.c @@ -18,7 +18,7 @@ void *early_malloc(size_t size) tmp = cur; cur += size; -#ifdef DEBUG +#ifdef MM_DEBUG uart_printf("[*] Early allocate: %llx ~ %llx\r\n", tmp, cur - 1); #endif diff --git a/src/kernel/mm/mm.c b/src/kernel/mm/mm.c index 51be322b1..62002b75c 100644 --- a/src/kernel/mm/mm.c +++ b/src/kernel/mm/mm.c @@ -88,7 +88,7 @@ void mm_init(void) page_allocator_init(); sc_init(); -#ifdef DEBUG +#ifdef MM_DEBUG page_allocator_test(); sc_test(); #endif diff --git a/src/kernel/mm/page_alloc.c b/src/kernel/mm/page_alloc.c index e3d5493d9..710c1444a 100644 --- a/src/kernel/mm/page_alloc.c +++ b/src/kernel/mm/page_alloc.c @@ -71,7 +71,7 @@ void page_allocator_early_init(void *start, void *end) frame_ents[i].allocated = 0; } -#ifdef DEBUG +#ifdef MM_DEBUG uart_sync_printf("[*] init buddy (%llx ~ %llx)\r\n", buddy_base, buddy_end); #endif } @@ -86,7 +86,7 @@ void mem_reserve(void *start, void *end) frame_ents[idx].allocated = 1; -#ifdef DEBUG +#ifdef MM_DEBUG uart_sync_printf("[*] preserve page idx %d (%llx)\r\n", idx, start); #endif } @@ -136,7 +136,7 @@ void page_allocator_init(void) hdr = idx2addr(idx); list_add_tail(&hdr->list, &freelists[exp]); -#ifdef DEBUG +#ifdef MM_DEBUG uart_sync_printf("[*] page init, idx %d belong to exp %d\r\n", idx, exp); #endif @@ -149,7 +149,7 @@ void *alloc_pages(int num) frame_hdr *hdr; int idx, topexp, exp; -#ifdef DEBUG +#ifdef MM_DEBUG uart_sync_printf("[*] alloc_pages %d pages\r\n", num); #endif @@ -193,7 +193,7 @@ void *alloc_pages(int num) buddy_hdr = idx2addr(buddy_idx); list_add(&buddy_hdr->list, &freelists[topexp]); -#ifdef DEBUG +#ifdef MM_DEBUG uart_sync_printf("[*] Expand to idx (%d, %d) to exp (%d)\r\n", idx, buddy_idx, topexp); #endif @@ -202,7 +202,7 @@ void *alloc_pages(int num) frame_ents[idx].exp = exp; frame_ents[idx].allocated = 1; -#ifdef DEBUG +#ifdef MM_DEBUG uart_sync_printf("[*] Allocate idx %d exp %d\r\n", idx, exp); #endif @@ -231,7 +231,7 @@ static inline void _free_page(frame_hdr *page) while (exp + 1 < FREELIST_CNT && !frame_ents[buddy_idx].allocated && frame_ents[buddy_idx].exp == exp) { -#ifdef DEBUG +#ifdef MM_DEBUG uart_sync_printf("[*] merge idx (%d, %d) to exp (%d)\r\n", idx, buddy_idx, exp + 1); #endif @@ -262,14 +262,14 @@ void free_page(void *page) return; } -#ifdef DEBUG +#ifdef MM_DEBUG uart_sync_printf("[*] free_page idx %d\r\n", addr2idx(page)); #endif _free_page((frame_hdr *)page); } -#ifdef DEBUG +#ifdef MM_DEBUG void page_allocator_test(void) { char *ptr1 = alloc_pages(2); diff --git a/src/kernel/mm/sc_alloc.c b/src/kernel/mm/sc_alloc.c index 1c9c0f3de..d50526ed2 100644 --- a/src/kernel/mm/sc_alloc.c +++ b/src/kernel/mm/sc_alloc.c @@ -99,7 +99,7 @@ void *sc_alloc(int size) list_add_tail(&hdr->list, &sc_freelists[size_idx]); } -#ifdef DEBUG +#ifdef MM_DEBUG uart_sync_printf("[sc] Create chunks (page: %d; size: %d)\r\n", frame_idx, sc_sizes[size_idx]); #endif @@ -108,7 +108,7 @@ void *sc_alloc(int size) hdr = list_first_entry(&sc_freelists[size_idx], sc_hdr, list); list_del(&hdr->list); -#ifdef DEBUG +#ifdef MM_DEBUG uart_sync_printf("[sc] Allocate chunks %llx (request: %d; chunksize: %d)\r\n", hdr, size, @@ -135,7 +135,7 @@ int sc_free(void *sc) hdr = (sc_hdr *)sc; list_add(&hdr->list, &sc_freelists[size_idx]); -#ifdef DEBUG +#ifdef MM_DEBUG uart_sync_printf("[sc] Free chunks %llx(size: %d)\r\n", sc, sc_sizes[size_idx]); @@ -144,7 +144,7 @@ int sc_free(void *sc) return 0; } -#ifdef DEBUG +#ifdef MM_DEBUG void sc_test(void) { char *ptr1 = sc_alloc(0x18); // A; Allocate a page and create 0x20 chunks diff --git a/src/kernel/mmu.c b/src/kernel/mmu.c index b6a81685f..366ebd1da 100644 --- a/src/kernel/mmu.c +++ b/src/kernel/mmu.c @@ -1,5 +1,12 @@ #include +#include #include +#include +#include +#include +#include +#include +#include #include #define TCR_CONFIG_REGION_48bit (((64 - 48) << 0) | ((64 - 48) << 16)) @@ -28,6 +35,154 @@ #define BOOT_PUD ((pd_t *)0x2000) #define BOOT_PMD ((pd_t *)0x3000) +static void segmentation_fault(void) +{ + uart_sync_printf("[Segmentation fault]: Kill Process\r\n"); + exit_user_prog(); + + // Never reach +} + +static vm_area_t *vma_create(void *va, uint64 size, uint64 flag, void *addr) +{ + vm_area_t *vma; + + vma = kmalloc(sizeof(vm_area_t)); + size = ALIGN(size, PAGE_SIZE); + + vma->va_begin = (uint64)va; + vma->va_end = (uint64)va + size; + vma->flag = flag; + + if (vma->flag & VMA_ANON) { + vma->kva = 0; + } else if (vma->flag & VMA_PA) { + vma->kva = PA2VA(addr); + } else if (vma->flag & VMA_KVA) { + vma->kva = (uint64)addr; + } else { + // Unexpected + panic("vma_create flag error"); + } + + return vma; +} + +static void clone_uva_region(uint64 uva_begin, uint64 uva_end, + pd_t *pt, uint64 flag) +{ + for (uint64 addr = uva_begin; addr < uva_end; addr += PAGE_SIZE) { + void *new_kva; + uint64 par; + + // try to get the PA of UVA + asm volatile ( + "at s1e0r, %0" + :: "r" (addr) + ); + + par = read_sysreg(PAR_EL1); + + if (PAR_FAILED(par)) { + // VA to PA conversion aborted + continue; + } + + // convert PA to KVA + par = PA2VA(PAR_PA(par)); + + // Allocate a page and copy content to this page + new_kva = kmalloc(PAGE_SIZE); + memncpy(new_kva, (void *)par, PAGE_SIZE); + + // map @new_kva into @pt + pt_map(pt, (void *)addr, PAGE_SIZE, (void *)VA2PA(new_kva), flag); + } +} + +static vm_area_t *vma_clone(vm_area_t *vma, pd_t *page_table) +{ + vm_area_t *new_vma; + + new_vma = kmalloc(sizeof(vm_area_t)); + + new_vma->va_begin = vma->va_begin; + new_vma->va_end = vma->va_end; + new_vma->flag = vma->flag; + + if (vma->flag & VMA_ANON) { + clone_uva_region(vma->va_begin, vma->va_end, page_table, vma->flag); + new_vma->kva = 0; + } else if (vma->flag & VMA_PA) { + new_vma->kva = vma->kva; + } else if (vma->flag & VMA_KVA) { + void *new_kva; + + new_kva = kmalloc(vma->va_end - vma->va_begin); + memncpy(new_kva, (void *)vma->kva, vma->va_end - vma->va_begin); + + new_vma->kva = (uint64)new_kva; + } else { + // Unexpected + panic("vma_clone flag error"); + } + + return new_vma; +} + +static void free_uva_region(uint64 uva_begin, uint64 uva_end) +{ + for (uint64 addr = uva_begin; addr < uva_end; addr += PAGE_SIZE) { + uint64 par; + + // try to get the PA of UVA + asm volatile ( + "at s1e0r, %0" + :: "r" (addr) + ); + + par = read_sysreg(PAR_EL1); + + if (PAR_FAILED(par)) { + // VA to PA conversion aborted + continue; + } + + // convert PA to KVA + par = PA2VA(PAR_PA(par)); + + // free KVA + kfree((void *)par); + } +} + +static void vma_free(vm_area_t *vma) +{ + if (vma->kva && vma->flag & VMA_KVA) { + kfree((void *)vma->kva); + } else if (vma->flag & VMA_ANON) { + free_uva_region(vma->va_begin, vma->va_end); + } else if (!(vma->flag & VMA_PA)){ + // Unexpected + panic("vma_free flag error"); + } + + kfree(vma); +} + +static vm_area_t *vma_find(vm_area_meta_t *vma_meta, uint64 addr) +{ + vm_area_t *vma; + + list_for_each_entry(vma, &vma_meta->vma, list) { + if (vma->va_begin <= addr && addr < vma->va_end) { + return vma; + } + } + + return NULL; +} + void mmu_init(void) { uint32 sctlr_el1; @@ -150,4 +305,178 @@ void pt_map(pd_t *pt, void *va, uint64 size, void *pa, uint64 flag) for (uint64 i = 0; i < size; i += PAGE_SIZE) { _pt_map(pt, (void *)((uint64)va + i), (void *)((uint64)pa + i), flag); } +} + +vm_area_meta_t *vma_meta_create(void) +{ + vm_area_meta_t *vma_meta; + + vma_meta = kmalloc(sizeof(vm_area_meta_t)); + INIT_LIST_HEAD(&vma_meta->vma); + + return vma_meta; +} + +void vma_meta_free(vm_area_meta_t *vma_meta, pd_t *page_table) +{ + uint64 old_page_table; + vm_area_t *vma, *safe; + + old_page_table = get_page_table(); + set_page_table(page_table); + + preempt_disable(); + + list_for_each_entry_safe(vma, safe, &vma_meta->vma, list) { + vma_free(vma); + } + + preempt_enable(); + + kfree(vma_meta); + + set_page_table(old_page_table); +} + +void vma_meta_copy(vm_area_meta_t *to, vm_area_meta_t *from, pd_t *page_table) +{ + uint64 old_page_table; + vm_area_t *vma, *new_vma; + + old_page_table = get_page_table(); + set_page_table(page_table); + + preempt_disable(); + + list_for_each_entry(vma, &from->vma, list) { + new_vma = vma_clone(vma, (pd_t *)old_page_table); + + list_add_tail(&new_vma->list, &to->vma); + } + + preempt_enable(); + + set_page_table(old_page_table); +} + +void vma_map(vm_area_meta_t *vma_meta, void *va, uint64 size, + uint64 flag, void *addr) +{ + vm_area_t *vma; + int cnt = 0; + + if (flag & VMA_PA) cnt++; + if (flag & VMA_KVA) cnt++; + if (flag & VMA_ANON) cnt++; + + if (cnt != 1) { + return; + } + + if ((uint64)va & (PAGE_SIZE - 1)) { + return; + } + + vma = vma_find(vma_meta, (uint64)va); + if (vma) { + return; + } + + vma = vma_find(vma_meta, (uint64)va + size - 1); + if (vma) { + return; + } + + vma = vma_create(va, size, flag, addr); + + list_add_tail(&vma->list, &vma_meta->vma); +} + +static void do_page_fault(esr_el1_t *esr) +{ + uint64 far; + uint64 va; + uint64 fault_perm; + vm_area_t *vma; + + far = read_sysreg(FAR_EL1); + + vma = vma_find(current->address_space, far); + + if (!vma) { + segmentation_fault(); + // Never reach + } + + // Check permission + if (esr->ec == EC_IA_LE) { + // Execute abort + fault_perm = VMA_X; + } else if (ISS_WnR(esr)) { + // Write abort + fault_perm = VMA_W; + } else { + // Read abort + fault_perm = VMA_R; + } + + if (!(vma->flag & fault_perm)) { + goto PAGE_FAULT_INVALID; + } + + va = far & ~(PAGE_SIZE - 1); + + if (vma->kva) { + uint64 offset; + + offset = va - vma->va_begin; + + pt_map(current->page_table, (void *)va, PAGE_SIZE, + (void *)VA2PA(vma->kva + offset), vma->flag); + } else if (vma->flag & VMA_ANON) { + void *kva = kmalloc(PAGE_SIZE); + + memzero(kva, PAGE_SIZE); + + pt_map(current->page_table, (void *)va, PAGE_SIZE, + (void *)VA2PA(kva), vma->flag); + } else { + // Unexpected result + goto PAGE_FAULT_INVALID; + } + + return; + +PAGE_FAULT_INVALID: + segmentation_fault(); + + // Never reach +} + +void mem_abort(esr_el1_t *esr) +{ + int fsc; +#ifdef DEMANDING_PAGE_DEBUG + uint64 addr; + + addr = read_sysreg(FAR_EL1); +#endif + + fsc = ISS_FSC(esr); + + switch (fsc) { + case FSC_TF_L0: + case FSC_TF_L1: + case FSC_TF_L2: + case FSC_TF_L3: +#ifdef DEMANDING_PAGE_DEBUG + uart_sync_printf("[Translation fault]: 0x%llx\r\n", addr); +#endif + do_page_fault(esr); + break; + default: + segmentation_fault(); + + // Never reach + } } \ No newline at end of file diff --git a/src/kernel/panic.c b/src/kernel/panic.c index 6f21244ec..0c814cfb0 100644 --- a/src/kernel/panic.c +++ b/src/kernel/panic.c @@ -6,7 +6,7 @@ void panic(const char *fmt, ...) va_list args; va_start(args, fmt); - uart_sync_printf("\r\n"); + uart_sync_printf("\r\n[Kernel Panic] \r\n"); uart_sync_vprintf(fmt, args); va_end(args); diff --git a/src/kernel/signal.c b/src/kernel/signal.c index 6a45d7fb9..2ef7f5abf 100644 --- a/src/kernel/signal.c +++ b/src/kernel/signal.c @@ -8,8 +8,6 @@ // 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 @@ -192,7 +190,7 @@ static inline void _sighand_copy(struct sigaction_t *to, } /* Copy current signal handler to @sighand */ -void sighand_copy(struct sighand_t *sighand, void *addrbase) +void sighand_copy(struct sighand_t *sighand) { struct sighand_t *currhand; diff --git a/src/kernel/syscall.c b/src/kernel/syscall.c index 76ae84cf5..4b4e3586d 100644 --- a/src/kernel/syscall.c +++ b/src/kernel/syscall.c @@ -12,7 +12,6 @@ #include #include #include -#include #define KSTACK_VARIABLE(x) \ (void *)((uint64)x - \ @@ -46,66 +45,11 @@ syscall_funcp syscall_table[] = { (syscall_funcp) syscall_sigreturn, }; -typedef struct { - unsigned int iss:25, // Instruction specific syndrome - il:1, // Instruction length bit - ec:6; // Exception class -} esr_el1; - -static void show_trapframe(trapframe *regs) +void syscall_handler(trapframe *regs) { - uart_sync_printf("\r\n[*] Trapframe:\r\n"); - uart_sync_printf("\tx0: %llx\r\n", regs->x0); - uart_sync_printf("\tx1: %llx\r\n", regs->x1); - uart_sync_printf("\tx2: %llx\r\n", regs->x2); - uart_sync_printf("\tx3: %llx\r\n", regs->x3); - uart_sync_printf("\tx4: %llx\r\n", regs->x4); - uart_sync_printf("\tx5: %llx\r\n", regs->x5); - uart_sync_printf("\tx6: %llx\r\n", regs->x6); - uart_sync_printf("\tx7: %llx\r\n", regs->x7); - uart_sync_printf("\tx8: %llx\r\n", regs->x8); - uart_sync_printf("\tx9: %llx\r\n", regs->x9); - uart_sync_printf("\tx10: %llx\r\n", regs->x10); - uart_sync_printf("\tx11: %llx\r\n", regs->x11); - uart_sync_printf("\tx12: %llx\r\n", regs->x12); - uart_sync_printf("\tx13: %llx\r\n", regs->x13); - uart_sync_printf("\tx14: %llx\r\n", regs->x14); - uart_sync_printf("\tx15: %llx\r\n", regs->x15); - uart_sync_printf("\tx16: %llx\r\n", regs->x16); - uart_sync_printf("\tx17: %llx\r\n", regs->x17); - uart_sync_printf("\tx18: %llx\r\n", regs->x18); - uart_sync_printf("\tx19: %llx\r\n", regs->x19); - uart_sync_printf("\tx20: %llx\r\n", regs->x20); - uart_sync_printf("\tx21: %llx\r\n", regs->x21); - uart_sync_printf("\tx22: %llx\r\n", regs->x22); - uart_sync_printf("\tx23: %llx\r\n", regs->x23); - uart_sync_printf("\tx24: %llx\r\n", regs->x24); - uart_sync_printf("\tx25: %llx\r\n", regs->x25); - uart_sync_printf("\tx26: %llx\r\n", regs->x26); - uart_sync_printf("\tx27: %llx\r\n", regs->x27); - uart_sync_printf("\tx28: %llx\r\n", regs->x28); - uart_sync_printf("\tx29: %llx\r\n", regs->x29); - uart_sync_printf("\tx30: %llx\r\n", regs->x30); - uart_sync_printf("\tsp_el0 : %llx\r\n", regs->sp_el0); - uart_sync_printf("\telr_el1 : %llx\r\n", regs->elr_el1); - uart_sync_printf("\tspsr_el1: %llx\r\n", regs->spsr_el1); -} - -void syscall_handler(trapframe regs, uint32 syn) -{ - esr_el1 *esr; uint64 syscall_num; - - esr = (esr_el1 *)&syn; - - // SVC instruction execution - if (esr->ec != 0x15) { - show_trapframe(®s); - panic("[X] Panic: esr->ec: %x", esr->ec); - // Never return - } - syscall_num = regs.x8; + syscall_num = regs->x8; if (syscall_num > ARRAY_SIZE(syscall_table)) { // Invalid syscall @@ -114,8 +58,13 @@ void syscall_handler(trapframe regs, uint32 syn) enable_interrupt(); - (syscall_table[syscall_num])(®s, - regs.x0, regs.x1, regs.x2, regs.x3, regs.x4, regs.x5); + (syscall_table[syscall_num])(regs, + regs->x0, + regs->x1, + regs->x2, + regs->x3, + regs->x4, + regs->x5); disable_interrupt(); } @@ -152,26 +101,22 @@ void syscall_exec(trapframe *_, const char* name, char *const argv[]) // TODO: Clear user stack - kfree(current->data); - current->data = data; - current->datalen = datalen; - kernel_sp = (char *)current->kernel_stack + STACK_SIZE - 0x10; // Reset signal signal_head_reset(current->signal); sighand_reset(current->sighand); - // Reset page table - pt_free(current->page_table); - current->page_table = pt_create(); + // Reset address_space & page table + task_reset_mm(current); + task_init_map(current); // 0x000000000000 ~ : rwx: Code - pt_map(current->page_table, (void *)0, datalen, - (void *)VA2PA(data), PT_R | PT_W | PT_X); + vma_map(current->address_space, (void *)0, datalen, + VMA_R | VMA_W | VMA_X | VMA_KVA, data); - set_page_table(current); + set_page_table(current->page_table); exec_user_prog((void *)0, (char *)0xffffffffeff0, kernel_sp); } @@ -198,23 +143,17 @@ void syscall_fork(trapframe *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); - // Set page table - task_init_map(child); + // TODO: Implement copy on write - // 0x000000000000 ~ : rwx: Code - pt_map(child->page_table, (void *)0, child->datalen, - (void *)VA2PA(child->data), PT_R | PT_W | PT_X); + // Copy address_space + vma_meta_copy(child->address_space, + current->address_space, + current->page_table); // Copy signal handler - sighand_copy(child->sighand, child->data); + sighand_copy(child->sighand); // Save registers SAVE_REGS(current); diff --git a/src/kernel/task.c b/src/kernel/task.c index b3cb223b1..514c7c1b4 100644 --- a/src/kernel/task.c +++ b/src/kernel/task.c @@ -31,15 +31,16 @@ task_struct *task_create(void) struct signal_head_t *signal; struct sighand_t *sighand; pd_t *page_table; + vm_area_meta_t *as; task = kmalloc(sizeof(task_struct)); signal = signal_head_create(); sighand = sighand_create(); page_table = pt_create(); + as = vma_meta_create(); + task->address_space = as; task->kernel_stack = NULL; - task->user_stack = NULL; - task->data = NULL; task->page_table = page_table; INIT_LIST_HEAD(&task->list); list_add_tail(&task->task_list, &task_queue); @@ -59,17 +60,12 @@ 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); - list_del(&task->task_list); signal_head_free(task->signal); sighand_free(task->sighand); + vma_meta_free(task->address_space, task->page_table); pt_free(task->page_table); // TODO: release tid @@ -93,12 +89,21 @@ task_struct *task_get_by_tid(uint32 tid) void task_init_map(task_struct *task) { // TODO: map the return addres of mailbox_call - pt_map(task->page_table, (void *)0x3c000000, 0x03000000, - (void *)0x3c000000, PT_R | PT_W); + vma_map(task->address_space, (void *)0x3c000000, 0x03000000, + VMA_R | VMA_W | VMA_PA, (void *)0x3c000000); - pt_map(task->page_table, (void *)0x7f0000000000, TEXT_USER_SHARED_LEN, - (void *)VA2PA(TEXT_USER_SHARED_BASE), PT_R | PT_X); + vma_map(task->address_space, (void *)0x7f0000000000, TEXT_USER_SHARED_LEN, + VMA_R | VMA_X | VMA_PA, (void *)VA2PA(TEXT_USER_SHARED_BASE)); + + vma_map(task->address_space, (void *)0xffffffffb000, STACK_SIZE, + VMA_R | VMA_W | VMA_ANON, NULL); +} - pt_map(task->page_table, (void *)0xffffffffb000, STACK_SIZE, - (void *)VA2PA(task->user_stack), PT_R | PT_W); +void task_reset_mm(task_struct *task) +{ + vma_meta_free(task->address_space, task->page_table); + pt_free(task->page_table); + + task->page_table = pt_create(); + task->address_space = vma_meta_create(); } \ No newline at end of file From d9edd988b7f470cbeb021c1f0d62e8aa6fa34a20 Mon Sep 17 00:00:00 2001 From: LJP-TW Date: Thu, 19 May 2022 05:37:36 -0700 Subject: [PATCH 25/25] Implement mmap --- include/kernel/mmu.h | 16 +++++++++++ src/kernel/mmu.c | 64 ++++++++++++++++++++++++++++++++++++++++++++ src/kernel/syscall.c | 4 ++- 3 files changed, 83 insertions(+), 1 deletion(-) diff --git a/include/kernel/mmu.h b/include/kernel/mmu.h index 87b813df3..90ef6bd08 100644 --- a/include/kernel/mmu.h +++ b/include/kernel/mmu.h @@ -4,6 +4,7 @@ #include #include #include +#include #define PAGE_TABLE_SIZE 0x1000 @@ -62,4 +63,19 @@ void vma_map(vm_area_meta_t *vma_meta, void *va, uint64 size, void mem_abort(esr_el1_t *esr); +/* syscalls */ +#define PROT_NONE 0 +#define PROT_READ 1 +#define PROT_WRITE 2 +#define PROT_EXEC 4 + +#define MAP_ANONYMOUS 0x0020 +#define MAP_POPULATE 0x8000 + +/* + * TODO: @fd, @file_offset are ignored currently. + */ +void syscall_mmap(trapframe *frame, void *addr, size_t len, int prot, + int flags, int fd, int file_offset); + #endif /* _MMU_H */ \ No newline at end of file diff --git a/src/kernel/mmu.c b/src/kernel/mmu.c index 366ebd1da..38727340e 100644 --- a/src/kernel/mmu.c +++ b/src/kernel/mmu.c @@ -479,4 +479,68 @@ void mem_abort(esr_el1_t *esr) // Never reach } +} + +void syscall_mmap(trapframe *frame, void *addr, size_t len, int prot, + int flags, int fd, int file_offset) +{ + vm_area_t *vma; + int mapflag; + + // do some initial work + len = ALIGN(len, PAGE_SIZE); + + if (addr == NULL) { + addr = (void *)0x550000000000; + } + + while (1) { + if ((uint64)addr > 0x0000ffffffffffff) { + frame->x0 = 0; + return; + } + + vma = vma_find(current->address_space, (uint64)addr); + if (vma) { + addr = (void *)((uint64)addr + 0x10000000); + continue; + } + + vma = vma_find(current->address_space, (uint64)addr + len - 1); + if (vma) { + addr = (void *)((uint64)addr + 0x10000000); + continue; + } + + break; + } + + mapflag = 0; + + if (prot & PROT_READ) mapflag |= VMA_R; + if (prot & PROT_WRITE) mapflag |= VMA_W; + if (prot & PROT_EXEC) mapflag |= VMA_X; + + if (flags & MAP_POPULATE) { + void *kva; + + mapflag |= VMA_KVA; + + kva = kmalloc(len); + memzero(kva, len); + + vma_map(current->address_space, addr, len, mapflag, kva); + + pt_map(current->page_table, addr, len, (void *)VA2PA(kva), mapflag); + } else if (flags & MAP_ANONYMOUS) { + mapflag |= VMA_ANON; + + vma_map(current->address_space, addr, len, mapflag, NULL); + } else { + // Unexpected. + frame->x0 = 0; + return; + } + + frame->x0 = (uint64)addr; } \ No newline at end of file diff --git a/src/kernel/syscall.c b/src/kernel/syscall.c index 4b4e3586d..b2905ab9a 100644 --- a/src/kernel/syscall.c +++ b/src/kernel/syscall.c @@ -12,6 +12,7 @@ #include #include #include +#include #define KSTACK_VARIABLE(x) \ (void *)((uint64)x - \ @@ -41,8 +42,9 @@ syscall_funcp syscall_table[] = { (syscall_funcp) syscall_kill_pid, (syscall_funcp) syscall_signal, // 8 (syscall_funcp) syscall_kill, - (syscall_funcp) syscall_show_info, + (syscall_funcp) syscall_mmap, (syscall_funcp) syscall_sigreturn, + (syscall_funcp) syscall_show_info, // 12 }; void syscall_handler(trapframe *regs)