diff --git a/.tokeignore b/.tokeignore index ac8ae9d..65db11d 100644 --- a/.tokeignore +++ b/.tokeignore @@ -3,7 +3,6 @@ build .venv kernel/data *.md -tools/ bootloader/ bootloader/src/uefi initramfs/ \ No newline at end of file diff --git a/ROADMAP.md b/ROADMAP.md index b19638e..e9f855c 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -23,13 +23,13 @@ ### v0.5.3 (Immediate Priority) *Focus: Lifecycle & Memory* -- [ ] **Syscall: Memory Management** - - Implement `sys_sbrk` or `sys_mem`. +- [x] **Syscall: Memory Management** + - Implement `sys_mem`. - Allow userspace to dynamically allocate pages (User Heap). -- [ ] **Syscall: Process Lifecycle** +- [x] **Syscall: Process Lifecycle** - `sys_spawn(path)`: Load `.hot` files via VFS, create new process structures. - `sys_exit(code)`: Proper termination, ZOMBIE state, resource cleanup in scheduler. -- [ ] **Userspace Lib (mini-libc)** +- [x] **Userspace Lib (mini-libc)** - Wrappers: `malloc`, `free`, `exec`, `exit`. - `crt0.asm` for proper `main()` entry. @@ -51,7 +51,7 @@ - [ ] **Bootloader Independence** - Remove `posix-uefi` library. - Write custom UEFI entry point (pure PE). - - Kernel itself becomes a valid `.hot` executable (or loaded by custom bootloader). + - Kernel itself becomes a valid `.hot` executable. - [ ] **HOT! Format Hardening** - Fix segment alignment (Page Alignment) in `elf2hot` and kernel loader. - Add metadata headers (stack size, permissions). diff --git a/kernel/inc/arch/x86_64/syscall.h b/kernel/inc/arch/x86_64/syscall.h index 92fd997..5ec0394 100644 --- a/kernel/inc/arch/x86_64/syscall.h +++ b/kernel/inc/arch/x86_64/syscall.h @@ -3,10 +3,11 @@ #pragma once -#define MSR_EFER 0xC0000080 -#define MSR_STAR 0xC0000081 -#define MSR_LSTAR 0xC0000082 -#define MSR_FMASK 0xC0000084 +#define MSR_EFER 0xC0000080 +#define MSR_STAR 0xC0000081 +#define MSR_LSTAR 0xC0000082 +#define MSR_FMASK 0xC0000084 +#define MSR_GS_BASE 0xC0000101 #define MSR_KERNEL_GS_BASE 0xC0000102 #define EFER_SCE 0x01 // System Call Enable @@ -17,6 +18,7 @@ typedef enum { SYS_MEM, SYS_WRITE, SYS_READ, + SYS_WAIT, } syscalls; void syscall_init(); \ No newline at end of file diff --git a/kernel/inc/core/scheduler.h b/kernel/inc/core/scheduler.h index ff7d8d0..ede8e03 100644 --- a/kernel/inc/core/scheduler.h +++ b/kernel/inc/core/scheduler.h @@ -7,6 +7,9 @@ typedef enum process_state { DEAD, RUNNING, + READY, + BLOCKED, + SLEEPING, } process_state; typedef struct process { @@ -27,9 +30,13 @@ typedef struct task { process_state task_state; // reusing process_state cuz wn u64 kernel_stack_top; process* proc; + i32 waiting_on_pid; } task; void sched_init(); task* sched_spawn(void(*entry)(), process* owner, bool is_user, u64 fixed_user_stack); u64 sched_next(u64 curr_rsp); -void yield(u64 ticks); \ No newline at end of file +void yield(u64 ticks); +void sched_block(u32 pid); +void sched_wakeup(u32 pid); +void sched_exit(); // suicide \ No newline at end of file diff --git a/kernel/inc/drivers/timer.h b/kernel/inc/drivers/timer.h index 632a473..c51eea2 100644 --- a/kernel/inc/drivers/timer.h +++ b/kernel/inc/drivers/timer.h @@ -7,4 +7,4 @@ void timer_init(u32 freq); u64 timer_handler(Registers *regs); void sleep(u64 ms); -u64 get_uptime(); +u64 get_uptime(); \ No newline at end of file diff --git a/kernel/inc/syscalls/proc.h b/kernel/inc/syscalls/proc.h index e9b51c4..e248044 100644 --- a/kernel/inc/syscalls/proc.h +++ b/kernel/inc/syscalls/proc.h @@ -6,4 +6,5 @@ #include u64 sys_exit(i32 code); -u64 sys_spawn(const char* path); \ No newline at end of file +u64 sys_spawn(const char* path); +u64 sys_wait(u64 pid); \ No newline at end of file diff --git a/kernel/src/arch/x86_64/interrupts.asm b/kernel/src/arch/x86_64/interrupts.asm index 96f5dc7..0558762 100644 --- a/kernel/src/arch/x86_64/interrupts.asm +++ b/kernel/src/arch/x86_64/interrupts.asm @@ -63,16 +63,37 @@ isr%1: global %2 %2: push 0 ; dummy err code - push %1 + push %1 ; int_no + + ; [rsp] = int_no (8) + ; [rsp + 8] = err_code (8) + ; [rsp + 16] = RIP (8) + ; [rsp + 24] = CS (8) + + test qword [rsp + 24], 3 + jz .skip_swap + swapgs +.skip_swap: + PUSHALL mov rdi, rsp cld call irq_handler_c - mov rsp, rax + mov rsp, rax + + ; PUSHALL - 15 * 8 = 120 bytes + ; + int_no (8) + err_code (8) = 136 bytes + ; [rsp + 136] = RIP + ; [rsp + 144] = CS + test qword [rsp + 144], 3 + jz .skip_swap_back + swapgs +.skip_swap_back: + POPALL add rsp, 16 iretq @@ -112,13 +133,18 @@ ISR_ERRCODE 30 ; Security Exception ISR_NOERRCODE 31 ; Reserved isr_common_stub: + test qword [rsp + 24], 3 + jz .skip_swap + swapgs +.skip_swap: PUSHALL - mov rdi, rsp call isr_handler_c - + test qword [rsp + 144], 3 + jz .skip_swap_back + swapgs +.skip_swap_back: POPALL - add rsp, 16 iretq diff --git a/kernel/src/arch/x86_64/interrupts.c b/kernel/src/arch/x86_64/interrupts.c index e1e4fc2..1be1d37 100644 --- a/kernel/src/arch/x86_64/interrupts.c +++ b/kernel/src/arch/x86_64/interrupts.c @@ -21,7 +21,7 @@ u64 irq_handler_c(Registers *regs) { switch (regs->int_no) { case 32: curr_rsp = timer_handler(regs); break; case 33: kb_handler(); break; - default: outb(SLAVE_COMMAND, 0x20); break; + default: break; } outb(MASTER_COMMAND, 0x20); diff --git a/kernel/src/arch/x86_64/syscall.asm b/kernel/src/arch/x86_64/syscall.asm index 78e33d2..b9f001b 100644 --- a/kernel/src/arch/x86_64/syscall.asm +++ b/kernel/src/arch/x86_64/syscall.asm @@ -58,9 +58,9 @@ syscall_entry: pop rbp pop rcx ; rip pop r11 ; rflags - add rsp, 8 ; skip rsp + + pop rsp - mov rsp, [gs:0] swapgs o64 sysret diff --git a/kernel/src/arch/x86_64/syscall.c b/kernel/src/arch/x86_64/syscall.c index b6b6f41..20a44bf 100644 --- a/kernel/src/arch/x86_64/syscall.c +++ b/kernel/src/arch/x86_64/syscall.c @@ -47,18 +47,20 @@ void syscall_init() { g_cpu.kernel_rsp = (u64)stack_phys + HHDM_OFFSET + 4096; } + wrmsr(MSR_GS_BASE, (u64)&g_cpu); wrmsr(MSR_KERNEL_GS_BASE, (u64)&g_cpu); } u64 syscall_dispatch(u64 id, u64 arg1, u64 arg2, u64 arg3, u64 arg4, u64 arg5) { - __asm__ volatile("cli"); switch (id) { case SYS_EXIT: return sys_exit(arg1); case SYS_SPAWN: return sys_spawn((const char*)arg1); case SYS_MEM: return sys_mem(arg1); case SYS_WRITE: return sys_write(arg1, arg2, arg3); - case SYS_READ: return sys_read(arg1, arg2, arg3); - default: kprintf("[Dewar] Unknown syscall %d\n", id); return -1; + case SYS_READ: return sys_read(arg1, arg2, arg3); + case SYS_WAIT: return sys_wait(arg1); + default: + kprintf("[Dewar] Unknown syscall %d\n", id); + return -1; } - __asm__ volatile("sti"); } \ No newline at end of file diff --git a/kernel/src/core/scheduler.c b/kernel/src/core/scheduler.c index b6ae56f..0154a4f 100644 --- a/kernel/src/core/scheduler.c +++ b/kernel/src/core/scheduler.c @@ -37,6 +37,7 @@ void sched_init() { kt->sleep_ticks = 0; kt->next = kt; kt->task_state = RUNNING; + kt->waiting_on_pid = -1; curr_task = kt; sched_spawn(idle_task, &kernel_process, false, 0); @@ -72,11 +73,12 @@ task* sched_spawn(void(*entry)(), process* owner, bool is_user, u64 fixed_user_s t->rsp = (u64)rsp; t->proc = owner; - t->id = next_pid++; + t->id = owner->pid; t->sleep_ticks = 0; t->next = curr_task->next; t->kernel_stack_top = (u64)stack_base + stack_size; t->task_state = RUNNING; + t->waiting_on_pid = -1; curr_task->next = t; return t; } @@ -94,24 +96,52 @@ u64 sched_next(u64 curr_rsp) { if (curr_task->sleep_ticks > 0) curr_task->sleep_ticks--; - task* next = curr_task->next; - while (next->task_state == DEAD) { + task* next = curr_task; + while (1) { // TODO: add gc here; next = next->next; - if (next == curr_task) panic("no alive tasks"); + if (next->task_state == SLEEPING && next->sleep_ticks == 0) next->task_state = RUNNING; + if (next->task_state == RUNNING) break; + if (next == curr_task) { + if (curr_task->task_state == RUNNING) break; + panic("no running tasks"); + } } - while (next != curr_task && next->sleep_ticks > 0) next = next->next; // what the fuck i just wrote - if (next->proc->pml4_phys != curr_task->proc->pml4_phys) load_cr3(next->proc->pml4_phys); - curr_task = next; tss.rsp0 = curr_task->kernel_stack_top; g_cpu.kernel_rsp = curr_task->kernel_stack_top; return curr_task->rsp; } +void sched_block(u32 pid) { + curr_task->task_state = BLOCKED; + curr_task->waiting_on_pid = pid; + __asm__ volatile("int $32"); +} + +void sched_wakeup(u32 pid) { + task* it = curr_task; + do { + if (it->task_state == BLOCKED && it->waiting_on_pid == (i32)pid) { + it->task_state = RUNNING; + it->waiting_on_pid = -1; + } + it = it->next; + } while (it != curr_task); +} + +void sched_exit() { + u32 my_pid = curr_task->id; + curr_task->task_state = DEAD; + + sched_wakeup(my_pid); + __asm__ volatile("int $32"); +} + void yield(u64 ticks) { curr_task->sleep_ticks = ticks; + curr_task->task_state = SLEEPING; __asm__ volatile("hlt"); } \ No newline at end of file diff --git a/kernel/src/drivers/keyboard.c b/kernel/src/drivers/keyboard.c index 47ce015..d2da2d3 100644 --- a/kernel/src/drivers/keyboard.c +++ b/kernel/src/drivers/keyboard.c @@ -111,5 +111,4 @@ void kb_handler() { default: break; } } - outb(MASTER_COMMAND, 0x20); } diff --git a/kernel/src/drivers/timer.c b/kernel/src/drivers/timer.c index 2bd8291..3f62358 100644 --- a/kernel/src/drivers/timer.c +++ b/kernel/src/drivers/timer.c @@ -26,10 +26,10 @@ void timer_init(u32 freq) { u64 timer_handler(Registers *regs) { ticks++; - outb(MASTER_COMMAND, 0x20); return sched_next((u64)regs); } + void sleep(u64 ms) { u64 start = ticks; while (ticks < start + ms) __asm__ volatile ("hlt"); diff --git a/kernel/src/syscalls/proc.c b/kernel/src/syscalls/proc.c index 013f2d4..04da742 100644 --- a/kernel/src/syscalls/proc.c +++ b/kernel/src/syscalls/proc.c @@ -10,9 +10,7 @@ extern task* curr_task; u64 sys_exit(i32 code) { kprintf("\n[Dewar] process %s exited with code %d", curr_task->proc->name, code); - curr_task->task_state = DEAD; - sched_next(curr_task->rsp); - while (1) { __asm__ ("hlt"); } + sched_exit(); } @@ -20,3 +18,6 @@ u64 sys_spawn(const char* path) { return process_spawn(path, path); } +u64 sys_wait(u64 pid) { + sched_block(pid); +} diff --git a/userspace/init/src/main.c b/userspace/init/src/main.c index 56cb533..19bafbd 100644 --- a/userspace/init/src/main.c +++ b/userspace/init/src/main.c @@ -6,7 +6,9 @@ #include int main() { - printf("Launching debug\n"); - spawn("debug"); - while (1) {} + wait(spawn("debug")); + printf("\nStill here?\n"); + while (1) { + printf("1"); + } } \ No newline at end of file diff --git a/userspace/libterm/inc/process.h b/userspace/libterm/inc/process.h index 59778f4..d12e7b9 100644 --- a/userspace/libterm/inc/process.h +++ b/userspace/libterm/inc/process.h @@ -4,4 +4,5 @@ #pragma once #include -u64 spawn(const char* path); \ No newline at end of file +u64 spawn(const char* path); +u64 wait(u64 pid); \ No newline at end of file diff --git a/userspace/libterm/src/process.c b/userspace/libterm/src/process.c index 95a5107..6ec7a66 100644 --- a/userspace/libterm/src/process.c +++ b/userspace/libterm/src/process.c @@ -4,7 +4,12 @@ #include extern u64 sys_spawn(const char* path); +extern u64 sys_wait(u64 pid); u64 spawn(const char* path) { return sys_spawn(path); +} + +u64 wait(u64 pid) { + return sys_wait(pid); } \ No newline at end of file diff --git a/userspace/libterm/src/syscalls.asm b/userspace/libterm/src/syscalls.asm index 122a6b9..8890f09 100644 --- a/userspace/libterm/src/syscalls.asm +++ b/userspace/libterm/src/syscalls.asm @@ -10,6 +10,7 @@ global sys_spawn global sys_mem global sys_write global sys_read +global sys_wait sys_exit: mov rax, 0 @@ -35,3 +36,8 @@ sys_read: mov rax, 4 syscall ret + +sys_wait: + mov rax, 5 + syscall + ret \ No newline at end of file