v0.5.3: syscalls, minilibc.
- fix(gs): was a nightmare. now its solved. Both MSR_GS_BASE and MSR_KERNEL_GS_BASE are now initialized to , preventing null GS_BASE when interrupt occurs during the first kernel task run - chore(syscall.asm): stability improvements. User RSP is now saved via kernel stack instead of global g_cpu, preventing stack theft when task switch occurs during a syscall - feat(interrupts): all irq and isr handlers now conditionally perform swapgs based on the CS selector (checkin if comfing from ring 3) - upgrade(scheduler): big update: 1) added TASK_BLOCKED state from process sync; 2) syncronized PID and Task ID to fix wakeup logic; 3) implemented sched_block and sched_exit() for proper wait/exit syscalls
This commit is contained in:
@@ -3,7 +3,6 @@ build
|
||||
.venv
|
||||
kernel/data
|
||||
*.md
|
||||
tools/
|
||||
bootloader/
|
||||
bootloader/src/uefi
|
||||
initramfs/
|
||||
+5
-5
@@ -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).
|
||||
|
||||
@@ -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();
|
||||
@@ -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);
|
||||
void yield(u64 ticks);
|
||||
void sched_block(u32 pid);
|
||||
void sched_wakeup(u32 pid);
|
||||
void sched_exit(); // suicide
|
||||
@@ -7,4 +7,4 @@
|
||||
void timer_init(u32 freq);
|
||||
u64 timer_handler(Registers *regs);
|
||||
void sleep(u64 ms);
|
||||
u64 get_uptime();
|
||||
u64 get_uptime();
|
||||
@@ -6,4 +6,5 @@
|
||||
#include <types.h>
|
||||
|
||||
u64 sys_exit(i32 code);
|
||||
u64 sys_spawn(const char* path);
|
||||
u64 sys_spawn(const char* path);
|
||||
u64 sys_wait(u64 pid);
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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");
|
||||
}
|
||||
@@ -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");
|
||||
}
|
||||
@@ -111,5 +111,4 @@ void kb_handler() {
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
outb(MASTER_COMMAND, 0x20);
|
||||
}
|
||||
|
||||
@@ -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");
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -6,7 +6,9 @@
|
||||
#include <malloc.h>
|
||||
|
||||
int main() {
|
||||
printf("Launching debug\n");
|
||||
spawn("debug");
|
||||
while (1) {}
|
||||
wait(spawn("debug"));
|
||||
printf("\nStill here?\n");
|
||||
while (1) {
|
||||
printf("1");
|
||||
}
|
||||
}
|
||||
@@ -4,4 +4,5 @@
|
||||
#pragma once
|
||||
#include <types.h>
|
||||
|
||||
u64 spawn(const char* path);
|
||||
u64 spawn(const char* path);
|
||||
u64 wait(u64 pid);
|
||||
@@ -4,7 +4,12 @@
|
||||
#include <process.h>
|
||||
|
||||
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);
|
||||
}
|
||||
@@ -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
|
||||
Reference in New Issue
Block a user