From 995b01dfd2b6999a462266b14a834066656ae68b Mon Sep 17 00:00:00 2001 From: Ry Date: Sat, 21 May 2022 16:55:56 -0700 Subject: [PATCH] fox32os: Implement multitasking and add a jump table for applications --- fox32os.def | 15 +++++ kernel/fxf/fxf.asm | 6 +- kernel/main.asm | 47 +++++++++++-- kernel/task.asm | 164 +++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 223 insertions(+), 9 deletions(-) create mode 100644 fox32os.def create mode 100644 kernel/task.asm diff --git a/fox32os.def b/fox32os.def new file mode 100644 index 0000000..1da9a31 --- /dev/null +++ b/fox32os.def @@ -0,0 +1,15 @@ +; fox32os routine definitions + +; system jump table +get_os_version: jmp [0x00000810] + +; FXF jump table +parse_fxf_binary: jmp [0x00000820] + +; task jump table +new_task: jmp [0x00000830] +yield_task: jmp [0x00000834] +end_current_task: jmp [0x00000838] + +; memory jump table +allocate_memory: jmp [0x00000840] diff --git a/kernel/fxf/fxf.asm b/kernel/fxf/fxf.asm index 0526321..8e105e8 100644 --- a/kernel/fxf/fxf.asm +++ b/kernel/fxf/fxf.asm @@ -4,13 +4,13 @@ ; inputs: ; r0: pointer to memory buffer containing an FXF binary ; outputs: -; none -execute_fxf_binary: +; r0: relocation address +parse_fxf_binary: ; TODO: check the magic bytes and header version call fxf_reloc - jmp r0 + ret #include "fxf/reloc.asm" diff --git a/kernel/main.asm b/kernel/main.asm index 8d9f514..6784670 100644 --- a/kernel/main.asm +++ b/kernel/main.asm @@ -9,6 +9,27 @@ const FOX32OS_VERSION_PATCH: 0 const BACKGROUND_COLOR: 0xFF674764 const TEXT_COLOR: 0xFFFFFFFF + jmp entry + +jump_table: + ; system jump table + org.pad 0x00000810 + data.32 get_os_version + + ; FXF jump table + org.pad 0x00000820 + data.32 parse_fxf_binary + + ; task jump table + org.pad 0x00000830 + data.32 new_task + data.32 yield_task + data.32 end_current_task + + ; memory jump table + org.pad 0x00000840 + data.32 allocate_memory + ; initialization code entry: ; clear the background @@ -48,16 +69,23 @@ draw_startup_text: cmp r0, 0 ifz jmp startup_error - ; read the startup file into memory starting at the bottom of the kernel + ; read the startup file into memory starting at 0x03000000 mov r0, startup_file_struct - mov r1, kernel_bottom + mov r1, 0x03000000 call ryfs_read_whole_file - ; relocate and execute it!!! - mov r0, kernel_bottom - call execute_fxf_binary + ; relocate and execute it as a new task + mov r0, 0x03000000 + call parse_fxf_binary + mov r1, r0 + mov r0, 0 + mov r2, rsp + call new_task - rjmp 0 + ; when the startup file yields for the first time, we'll end up back here + ; jump back to it without adding this "task" (not really a task) into the queue + ; this does not return + call end_current_task startup_error: mov r0, BACKGROUND_COLOR @@ -74,8 +102,15 @@ startup_error: call draw_format_str_to_background rjmp 0 +get_os_version: + mov r0, FOX32OS_VERSION_MAJOR + mov r1, FOX32OS_VERSION_MINOR + mov r2, FOX32OS_VERSION_PATCH + ret + #include "allocator.asm" #include "fxf/fxf.asm" + #include "task.asm" startup_str: data.str "fox32 - OS version %u.%u.%u" data.8 0 startup_error_str: data.str "fox32 - OS version %u.%u.%u - startup.cfg is invalid!" data.8 0 diff --git a/kernel/task.asm b/kernel/task.asm new file mode 100644 index 0000000..564ccb9 --- /dev/null +++ b/kernel/task.asm @@ -0,0 +1,164 @@ +; task switching routines + +; add a new task to the queue and jump to it immediately +; inputs: +; r0: task ID +; r1: task instruction pointer +; r2: task stack pointer +; outputs: +; none +new_task: + bse [task_id_bitmap], r0 ; mark this task ID as used + + mov r4, r2 + mov r3, r1 + mov r2, r0 + + mov r0, [task_queue_ptr] + call task_store + mov [task_queue_ptr], r0 + + ; fall-through + +; switch to the next task in the queue +; inputs: +; none +; outputs: +; none +yield_task: + ; add the current task back into the queue + mov r0, current_task ; get the current task struct + call task_load + pop r3 ; pop the return address off of the stack + mov r4, rsp + mov r0, [task_queue_ptr] + call task_store + mov [task_queue_ptr], r0 + + jmp yield_task_0 + +; switch to the next task without adding the current task back into the queue +; inputs: +; none +; outputs: +; none +end_current_task: + cmp [task_queue_ptr], task_queue_bottom + ifz jmp task_empty + + mov r0, current_task ; get the current task struct + call task_load + bcl [task_id_bitmap], r2 ; mark this task ID as unused + pop r0 ; pop the return address off of the stack +yield_task_0: + mov r0, task_queue_bottom + call task_load + mov r0, current_task + call task_store + + mov r1, task_queue_bottom +yield_task_1: + add r1, TASK_SIZE + + cmp [task_queue_ptr], r1 + ifz jmp yield_task_2 + + mov r0, r1 + call task_load + + mov r0, r1 + sub r0, TASK_SIZE + call task_store + + jmp yield_task_1 +yield_task_2: + mov r0, current_task + call task_load + sub [task_queue_ptr], TASK_SIZE + + mov rsp, r4 + jmp r3 + +; get the next unused task ID, starting at 1 +; inputs: +; none +; outputs: +; r0: task ID, or zero if all IDs are used +get_unused_task_id: + mov r0, 1 +get_unused_task_id_loop: + bts [task_id_bitmap], r0 + ifz ret + inc r0 + cmp r0, 32 + iflt jmp get_unused_task_id_loop + ; if we reach this point, then add task IDs are used + mov r0, 0 + ret + +task_load: + mov r2, [r0] ; task ID + add r0, 4 + mov r3, [r0] ; instruction pointer + add r0, 4 + mov r4, [r0] ; stack pointer + add r0, 4 + ret + +task_store: + mov [r0], r2 ; task ID + add r0, 4 + mov [r0], r3 ; instruction pointer + add r0, 4 + mov [r0], r4 ; stack pointer + add r0, 4 + ret + +task_empty: + mov r0, task_panic_str + mov r1, task_queue_bottom ; show the address of the task queue in the panic brk output + mov r2, [task_queue_ptr] ; show the the task queue pointer in the panic brk output + call panic + +task_panic_str: data.str "Task queue empty! Hanging here" data.8 10 data.8 0 + +const TASK_SIZE: 12 +task_id_bitmap: data.32 0 +current_task: + data.32 0 ; task ID + data.32 0 ; instruction pointer + data.32 0 ; stack pointer +task_queue_ptr: data.32 task_queue_bottom +task_queue_bottom: + data.32 0 data.32 0 data.32 0 + data.32 0 data.32 0 data.32 0 + data.32 0 data.32 0 data.32 0 + data.32 0 data.32 0 data.32 0 + data.32 0 data.32 0 data.32 0 + data.32 0 data.32 0 data.32 0 + data.32 0 data.32 0 data.32 0 + data.32 0 data.32 0 data.32 0 + data.32 0 data.32 0 data.32 0 + data.32 0 data.32 0 data.32 0 + data.32 0 data.32 0 data.32 0 + data.32 0 data.32 0 data.32 0 + data.32 0 data.32 0 data.32 0 + data.32 0 data.32 0 data.32 0 + data.32 0 data.32 0 data.32 0 + data.32 0 data.32 0 data.32 0 + data.32 0 data.32 0 data.32 0 + data.32 0 data.32 0 data.32 0 + data.32 0 data.32 0 data.32 0 + data.32 0 data.32 0 data.32 0 + data.32 0 data.32 0 data.32 0 + data.32 0 data.32 0 data.32 0 + data.32 0 data.32 0 data.32 0 + data.32 0 data.32 0 data.32 0 + data.32 0 data.32 0 data.32 0 + data.32 0 data.32 0 data.32 0 + data.32 0 data.32 0 data.32 0 + data.32 0 data.32 0 data.32 0 + data.32 0 data.32 0 data.32 0 + data.32 0 data.32 0 data.32 0 + data.32 0 data.32 0 data.32 0 + data.32 0 data.32 0 data.32 0