From e95c82b1626b067ad51db45f00cb35ad65bb36fb Mon Sep 17 00:00:00 2001 From: boreddevnl Date: Wed, 18 Mar 2026 17:04:10 +0100 Subject: [PATCH] CHECKP: multi-thread applications --- fix_syscalls.sh | 7 +++ src/arch/interrupts.asm | 5 ++ src/sys/idt.c | 15 ++++- src/sys/lapic.c | 12 ++-- src/sys/lapic.h | 3 + src/sys/process.c | 92 +++++++++++++++++++++++----- src/sys/process.h | 4 +- src/sys/smp.c | 20 +++++-- src/sys/syscall.c | 63 +++++++++----------- src/userland/gui/taskman.c | 17 +++--- src/userland/libc/syscall.c | 14 ++--- src/wm/graphics.c | 13 ++-- src/wm/wm.c | 116 ++++++++++++++++++++---------------- src/wm/wm.h | 3 + 14 files changed, 250 insertions(+), 134 deletions(-) create mode 100755 fix_syscalls.sh diff --git a/fix_syscalls.sh b/fix_syscalls.sh new file mode 100755 index 0000000..e1d7072 --- /dev/null +++ b/fix_syscalls.sh @@ -0,0 +1,7 @@ +#!/bin/bash +sed -i '' -e 's/asm volatile("pushfq; pop %0; cli" : "=r"(rflags));/rflags = wm_lock_acquire();/g' src/sys/syscall.c +sed -i '' -e 's/asm volatile("push %0; popfq" : : "r"(rflags));/wm_lock_release(rflags);/g' src/sys/syscall.c +sed -i '' -e 's/asm volatile("pushfq; pop %0; cli" : "=r"(rflags));/rflags = wm_lock_acquire();/g' src/wm/wm.c +sed -i '' -e 's/asm volatile("push %0; popfq" : : "r"(rflags));/wm_lock_release(rflags);/g' src/wm/wm.c +sed -i '' -e 's/uint64_t rflags;/uint64_t rflags;/g' src/sys/syscall.c +echo "Done" diff --git a/src/arch/interrupts.asm b/src/arch/interrupts.asm index 82c4bc7..4329a36 100644 --- a/src/arch/interrupts.asm +++ b/src/arch/interrupts.asm @@ -7,11 +7,13 @@ global isr1_wrapper global isr8_wrapper global isr12_wrapper global isr14_wrapper +global isr128_wrapper global isr_sched_ipi_wrapper extern timer_handler extern keyboard_handler extern mouse_handler extern sched_ipi_handler +extern syscall_handler_c extern exception_handler_c ; Helper to send EOI (End of Interrupt) to PIC @@ -90,6 +92,9 @@ isr12_wrapper: isr_sched_ipi_wrapper: ISR_NOERRCODE sched_ipi_handler, 65 +isr128_wrapper: + ISR_NOERRCODE syscall_handler_c, 128 + ; Common exception macro for exceptions WITHOUT error code %macro EXCEPTION_NOERRCODE 1 global exc%1_wrapper diff --git a/src/sys/idt.c b/src/sys/idt.c index 8d562c4..e533cfd 100644 --- a/src/sys/idt.c +++ b/src/sys/idt.c @@ -59,7 +59,17 @@ uint64_t exception_handler_c(registers_t *regs) { serial_write(buf); if ((regs->cs & 0x3) != 0) { - serial_write("\nUSER MODE EXCEPTION - Terminating process.\n"); + serial_write("\n*** USER MODE EXCEPTION ***\nVector: 0x"); + k_itoa_hex(vector, buf); + serial_write(buf); + serial_write("\nRIP: 0x"); + k_itoa_hex(regs->rip, buf); + serial_write(buf); + serial_write("\nError Code: 0x"); + k_itoa_hex(regs->err_code, buf); + serial_write(buf); + serial_write("\nTerminating process.\n"); + if (cmd_get_cursor_col() != 0) cmd_write("\n"); cmd_write("*** USER EXCEPTION ***\nVector: "); cmd_write_hex(vector); cmd_write("\nRIP: "); cmd_write_hex(regs->rip); @@ -234,6 +244,9 @@ void idt_register_interrupts(void) { extern void isr_sched_ipi_wrapper(void); idt_set_gate(0x41, isr_sched_ipi_wrapper, cs, 0x8E); + // Syscall Handler (vector 128) - DPL 3 for user access + extern void isr128_wrapper(void); + idt_set_gate(128, isr128_wrapper, cs, 0xEE); } void idt_load(void) { diff --git a/src/sys/lapic.c b/src/sys/lapic.c index 5448b05..f070ad2 100644 --- a/src/sys/lapic.c +++ b/src/sys/lapic.c @@ -16,14 +16,18 @@ static volatile uint32_t *lapic_base = 0; #define LAPIC_ICR_LOW (0x300 / 4) #define LAPIC_ICR_HIGH (0x310 / 4) +void lapic_enable(void) { + if (!lapic_base) return; + // Enable the LAPIC by setting the Spurious Interrupt Vector Register + // Bit 8 = APIC Software Enable, vector = 0xFF (spurious) + lapic_base[LAPIC_SVR] = 0x1FF; +} + void lapic_init(void) { extern uint64_t hhdm_offset; lapic_base = (volatile uint32_t *)(hhdm_offset + 0xFEE00000ULL); - // Enable the LAPIC by setting the Spurious Interrupt Vector Register - // Bit 8 = APIC Software Enable, vector = 0xFF (spurious) - lapic_base[LAPIC_SVR] = 0x1FF; - + lapic_enable(); serial_write("[LAPIC] Initialized at HHDM + 0xFEE00000\n"); } diff --git a/src/sys/lapic.h b/src/sys/lapic.h index 57832fb..06e1cc9 100644 --- a/src/sys/lapic.h +++ b/src/sys/lapic.h @@ -12,6 +12,9 @@ // Initialize LAPIC access (maps registers via HHDM) void lapic_init(void); +// Enable LAPIC (set SVR bit 8) +void lapic_enable(void); + // Send End-of-Interrupt to the local APIC void lapic_eoi(void); diff --git a/src/sys/process.c b/src/sys/process.c index 5ddc494..b3c47e9 100644 --- a/src/sys/process.c +++ b/src/sys/process.c @@ -57,8 +57,13 @@ void process_init(void) { current_process[0] = kernel_proc; } -void process_create(void* entry_point, bool is_user) { - if (process_count >= MAX_PROCESSES) return; +process_t* process_create(void (*entry_point)(void), bool is_user) { + uint64_t rflags = spinlock_acquire_irqsave(&runqueue_lock); + + if (process_count >= MAX_PROCESSES) { + spinlock_release_irqrestore(&runqueue_lock, rflags); + return NULL; + } process_t *new_proc = &processes[process_count++]; new_proc->pid = next_pid++; @@ -71,7 +76,10 @@ void process_create(void* entry_point, bool is_user) { new_proc->pml4_phys = paging_get_pml4_phys(); } - if (!new_proc->pml4_phys) return; + if (!new_proc->pml4_phys) { + spinlock_release_irqrestore(&runqueue_lock, rflags); + return NULL; + } // 2. Allocate aligned stack void* user_stack = kmalloc_aligned(4096, 4096); @@ -140,14 +148,16 @@ void process_create(void* entry_point, bool is_user) { new_proc->cpu_affinity = 0; // Non-ELF processes stay on BSP - // Add to linked list (Critical Section) - uint64_t rflags = spinlock_acquire_irqsave(&runqueue_lock); + // Add to linked list new_proc->next = current_process[0]->next; current_process[0]->next = new_proc; + spinlock_release_irqrestore(&runqueue_lock, rflags); + return new_proc; } process_t* process_create_elf(const char* filepath, const char* args_str) { + uint64_t rflags = spinlock_acquire_irqsave(&runqueue_lock); process_t *new_proc = NULL; // Find an available slot @@ -159,10 +169,14 @@ process_t* process_create_elf(const char* filepath, const char* args_str) { } } - if (!new_proc) return NULL; + if (!new_proc) { + spinlock_release_irqrestore(&runqueue_lock, rflags); + return NULL; + } new_proc->pid = next_pid++; new_proc->is_user = true; + spinlock_release_irqrestore(&runqueue_lock, rflags); // 1. Setup Page Table new_proc->pml4_phys = paging_create_user_pml4_phys(); @@ -334,7 +348,7 @@ process_t* process_create_elf(const char* filepath, const char* args_str) { } // Add to linked list (Critical Section) - uint64_t rflags = spinlock_acquire_irqsave(&runqueue_lock); + rflags = spinlock_acquire_irqsave(&runqueue_lock); new_proc->next = current_process[0]->next; current_process[0]->next = new_proc; spinlock_release_irqrestore(&runqueue_lock, rflags); @@ -345,6 +359,16 @@ process_t* process_create_elf(const char* filepath, const char* args_str) { return new_proc; } +process_t* process_get_current_for_cpu(uint32_t cpu_id) { + if (cpu_id >= MAX_CPUS_SCHED) return NULL; + return current_process[cpu_id]; +} + +void process_set_current_for_cpu(uint32_t cpu_id, process_t* p) { + if (cpu_id >= MAX_CPUS_SCHED) return; + current_process[cpu_id] = p; +} + process_t* process_get_current(void) { uint32_t cpu = smp_this_cpu_id(); return current_process[cpu]; @@ -373,8 +397,8 @@ uint64_t process_schedule(uint64_t current_rsp) { process_t *next_proc = cur->next; while (next_proc != start) { - // Only consider processes assigned to our CPU - if (next_proc->cpu_affinity == my_cpu) { + // Only consider processes assigned to our CPU and not terminated + if (next_proc->cpu_affinity == my_cpu && next_proc->pid != 0xFFFFFFFF) { if (next_proc->pid == 0 || next_proc->sleep_until == 0 || next_proc->sleep_until <= now) { break; } @@ -382,9 +406,20 @@ uint64_t process_schedule(uint64_t current_rsp) { next_proc = next_proc->next; } - // If we didn't find a ready process for our CPU, stay on current - if (next_proc->cpu_affinity != my_cpu) { - return current_rsp; + // If we didn't find a ready process for our CPU, stay on current (unless we are terminated) + if (next_proc->cpu_affinity != my_cpu || next_proc->pid == 0xFFFFFFFF) { + // Fallback to idle if current is terminated + if (cur && cur->pid == 0xFFFFFFFF) { + // Find the idle process for this CPU + for (int i = 0; i < MAX_PROCESSES; i++) { + if (processes[i].pid == 0 || (processes[i].cpu_affinity == my_cpu && processes[i].is_user == false)) { + next_proc = &processes[i]; + break; + } + } + } else { + return current_rsp; + } } current_process[my_cpu] = next_proc; @@ -465,12 +500,25 @@ void process_terminate(process_t *to_delete) { uint32_t cpu_count = smp_cpu_count(); for (uint32_t c = 0; c < cpu_count && c < MAX_CPUS_SCHED; c++) { if (current_process[c] == to_delete) { - current_process[c] = to_delete->next; + process_t *np = to_delete->next; + while (np != to_delete) { + if (np->cpu_affinity == c && np->pid != 0xFFFFFFFF) break; + np = np->next; + } + if (np == to_delete || np->cpu_affinity != c) { + for (int i = 0; i < MAX_PROCESSES; i++) { + if (processes[i].pid == 0 || (processes[i].cpu_affinity == c && processes[i].is_user == false)) { + np = &processes[i]; break; + } + } + } + current_process[c] = np; } } // Mark slot as free to_delete->pid = 0xFFFFFFFF; + to_delete->cpu_affinity = 0xFFFFFFFF; if (to_delete->user_stack_alloc) kfree(to_delete->user_stack_alloc); if (to_delete->kernel_stack_alloc) { @@ -518,10 +566,26 @@ uint64_t process_terminate_current(void) { } prev->next = to_delete->next; - current_process[my_cpu] = to_delete->next; + + process_t *next_proc = to_delete->next; + while (next_proc != to_delete) { + if (next_proc->cpu_affinity == my_cpu && next_proc->pid != 0xFFFFFFFF) break; + next_proc = next_proc->next; + } + + if (next_proc == to_delete || next_proc->cpu_affinity != my_cpu) { + for (int i = 0; i < MAX_PROCESSES; i++) { + if (processes[i].pid == 0 || (processes[i].cpu_affinity == my_cpu && processes[i].is_user == false)) { + next_proc = &processes[i]; break; + } + } + } + + current_process[my_cpu] = next_proc; // Mark slot as free to_delete->pid = 0xFFFFFFFF; + to_delete->cpu_affinity = 0xFFFFFFFF; // 4. Load context for the NEXT process if (current_process[my_cpu]->is_user && current_process[my_cpu]->kernel_stack) { diff --git a/src/sys/process.h b/src/sys/process.h index 4831a9c..44a7320 100644 --- a/src/sys/process.h +++ b/src/sys/process.h @@ -63,9 +63,11 @@ typedef struct { } ProcessInfo; void process_init(void); -void process_create(void* entry_point, bool is_user); +process_t* process_create(void (*entry_point)(void), bool is_user); process_t* process_create_elf(const char* filepath, const char* args_str); process_t* process_get_current(void); +void process_set_current_for_cpu(uint32_t cpu_id, process_t* p); +process_t* process_get_current_for_cpu(uint32_t cpu_id); uint64_t process_schedule(uint64_t current_rsp); uint64_t process_terminate_current(void); void process_terminate(process_t *proc); diff --git a/src/sys/smp.c b/src/sys/smp.c index 6b12719..4f4ede1 100644 --- a/src/sys/smp.c +++ b/src/sys/smp.c @@ -8,6 +8,7 @@ #include "idt.h" #include "platform.h" #include "paging.h" +#include "process.h" extern void serial_write(const char *str); extern void serial_write_num(uint32_t n); @@ -65,9 +66,10 @@ static void ap_entry(struct limine_smp_info *info) { asm volatile("mov %0, %%cr4" : : "r"(cr4)); asm volatile("fninit"); - // 3. Load the shared GDT (same one the BSP uses — all CPUs share kernel mappings) + // 3. Load the shared GDT and properly reload all segments (including CS=0x08) extern struct gdt_ptr gdtr; - asm volatile("lgdt %0" : : "m"(gdtr)); + extern void gdt_flush(uint64_t); + gdt_flush((uint64_t)&gdtr); // 4. Load per-CPU TSS gdt_load_ap_tss(my_id); @@ -80,7 +82,11 @@ static void ap_entry(struct limine_smp_info *info) { uint64_t kernel_cr3 = paging_get_pml4_phys(); asm volatile("mov %0, %%cr3" : : "r"(kernel_cr3)); - // 7. Mark ourselves as online + // 7. Enable LAPIC on this core so it can receive IPIs + extern void lapic_enable(void); + lapic_enable(); + + // 8. Mark ourselves as online cpu_states[my_id].online = true; serial_write("[SMP] AP "); @@ -89,7 +95,13 @@ static void ap_entry(struct limine_smp_info *info) { serial_write_num(cpu_states[my_id].lapic_id); serial_write(")\n"); - // 8. Enable interrupts and enter idle halt loop. + // 9. Initialize the current_process pointer for this CPU + // Create a dedicated idle task for this AP (PID 0 is reserved for the BSP) + process_t *ap_idle = process_create(NULL, false); // Idle process + ap_idle->cpu_affinity = my_id; + process_set_current_for_cpu(my_id, ap_idle); + + // 10. Enable interrupts and enter idle halt loop. // APs will be woken by scheduling IPIs from BSP (vector 0x41). // The IPI handler does context switching for this CPU's processes. asm volatile("sti"); diff --git a/src/sys/syscall.c b/src/sys/syscall.c index e5cca93..edd8331 100644 --- a/src/sys/syscall.c +++ b/src/sys/syscall.c @@ -33,25 +33,10 @@ static inline void wrmsr(uint32_t msr, uint64_t value) { asm volatile("wrmsr" : : "c"(msr), "a"(low), "d"(high)); } -// Implemented in assembly -extern void syscall_entry(void); - -extern uint64_t kernel_syscall_stack; +extern void isr128_wrapper(void); void syscall_init(void) { - void* stack = kmalloc(16384); - kernel_syscall_stack = (uint64_t)stack + 16384; - uint64_t efer = rdmsr(MSR_EFER); - efer |= 1; // SCE bit is bit 0 - wrmsr(MSR_EFER, efer); - - - uint64_t star = ((uint64_t)0x08 << 32) | ((uint64_t)0x13 << 48); - wrmsr(MSR_STAR, star); - - wrmsr(MSR_LSTAR, (uint64_t)syscall_entry); - - wrmsr(MSR_FMASK, 0x200); + // SMP-Safe System Calls using int 0x80 (configured in idt.c) } static void user_window_close(Window *win) { @@ -284,7 +269,7 @@ static uint64_t syscall_handler_inner(registers_t *regs) { extern void graphics_set_render_target(uint32_t *buffer, int w, int h); uint64_t rflags; - asm volatile("pushfq; pop %0; cli" : "=r"(rflags)); + rflags = wm_lock_acquire(); if (win->pixels) { // Strict user-to-window relative clamping @@ -304,7 +289,7 @@ static uint64_t syscall_handler_inner(registers_t *regs) { draw_rect(win->x + params[0], win->y + params[1], params[2], params[3], color); } - asm volatile("push %0; popfq" : : "r"(rflags)); + wm_lock_release(rflags); } } else if (cmd == GUI_CMD_DRAW_ROUNDED_RECT_FILLED) { Window *win = (Window *)arg2; @@ -318,7 +303,7 @@ static uint64_t syscall_handler_inner(registers_t *regs) { extern void graphics_set_render_target(uint32_t *buffer, int w, int h); uint64_t rflags; - asm volatile("pushfq; pop %0; cli" : "=r"(rflags)); + rflags = wm_lock_acquire(); if (win->pixels) { int rx = (int)params[0]; int ry = (int)params[1]; @@ -336,7 +321,7 @@ static uint64_t syscall_handler_inner(registers_t *regs) { } } - asm volatile("push %0; popfq" : : "r"(rflags)); + wm_lock_release(rflags); } } else if (cmd == GUI_CMD_DRAW_STRING) { Window *win = (Window *)arg2; @@ -359,7 +344,7 @@ static uint64_t syscall_handler_inner(registers_t *regs) { kernel_str[i] = 0; uint64_t rflags; - asm volatile("pushfq; pop %0; cli" : "=r"(rflags)); + rflags = wm_lock_acquire(); ttf_font_t *font = win->font ? (ttf_font_t*)win->font : graphics_get_current_ttf(); @@ -395,7 +380,7 @@ static uint64_t syscall_handler_inner(registers_t *regs) { } } - asm volatile("push %0; popfq" : : "r"(rflags)); + wm_lock_release(rflags); } } else if (cmd == 10) { // GUI_CMD_DRAW_STRING_BITMAP Window *win = (Window *)arg2; @@ -418,7 +403,7 @@ static uint64_t syscall_handler_inner(registers_t *regs) { kernel_str[i] = 0; uint64_t rflags; - asm volatile("pushfq; pop %0; cli" : "=r"(rflags)); + rflags = wm_lock_acquire(); if (win->pixels) { if (ux >= -100 && ux < win->w && uy >= -100 && uy < (win->h - 20)) { @@ -430,7 +415,7 @@ static uint64_t syscall_handler_inner(registers_t *regs) { draw_string_bitmap(win->x + ux, win->y + uy, kernel_str, color); } - asm volatile("push %0; popfq" : : "r"(rflags)); + wm_lock_release(rflags); } } else if (cmd == 11) { // GUI_CMD_DRAW_STRING_SCALED Window *win = (Window *)arg2; @@ -457,7 +442,7 @@ static uint64_t syscall_handler_inner(registers_t *regs) { kernel_str[i] = 0; uint64_t rflags; - asm volatile("pushfq; pop %0; cli" : "=r"(rflags)); + rflags = wm_lock_acquire(); ttf_font_t *font = win->font ? (ttf_font_t*)win->font : graphics_get_current_ttf(); @@ -493,7 +478,7 @@ static uint64_t syscall_handler_inner(registers_t *regs) { } } - asm volatile("push %0; popfq" : : "r"(rflags)); + wm_lock_release(rflags); } } else if (cmd == 18) { // GUI_CMD_DRAW_STRING_SCALED_SLOPED Window *win = (Window *)arg2; @@ -530,7 +515,7 @@ static uint64_t syscall_handler_inner(registers_t *regs) { kernel_str[i] = 0; uint64_t rflags; - asm volatile("pushfq; pop %0; cli" : "=r"(rflags)); + rflags = wm_lock_acquire(); ttf_font_t *font = win->font ? (ttf_font_t*)win->font : graphics_get_current_ttf(); @@ -568,7 +553,7 @@ static uint64_t syscall_handler_inner(registers_t *regs) { } } - asm volatile("push %0; popfq" : : "r"(rflags)); + wm_lock_release(rflags); } } else if (cmd == GUI_CMD_DRAW_IMAGE) { Window *win = (Window *)arg2; @@ -579,7 +564,7 @@ static uint64_t syscall_handler_inner(registers_t *regs) { for (int i = 0; i < 4; i++) params[i] = u_params[i]; uint64_t rflags; - asm volatile("pushfq; pop %0; cli" : "=r"(rflags)); + rflags = wm_lock_acquire(); if (win->pixels) { int rx = (int)params[0]; int ry = (int)params[1]; @@ -614,9 +599,10 @@ static uint64_t syscall_handler_inner(registers_t *regs) { } } - asm volatile("push %0; popfq" : : "r"(rflags)); + wm_lock_release(rflags); } } else if (cmd == GUI_CMD_MARK_DIRTY) { + uint64_t rflags = wm_lock_acquire(); Window *win = (Window *)arg2; uint64_t *u_params = (uint64_t *)arg3; if (win && u_params) { @@ -630,6 +616,7 @@ static uint64_t syscall_handler_inner(registers_t *regs) { } wm_mark_dirty(win->x + (int)params[0], win->y + (int)params[1], (int)params[2], (int)params[3]); } + wm_lock_release(rflags); } else if (cmd == GUI_CMD_GET_EVENT) { Window *win = (Window *)arg2; gui_event_t *ev_out = (gui_event_t *)arg3; @@ -1184,7 +1171,7 @@ static uint64_t syscall_handler_inner(registers_t *regs) { size_t total_used = stats.used_memory; size_t user_used = 0; for (int i = 0; i < 16; i++) { - if (processes[i].pid != 0xFFFFFFFF && processes[i].pid != 0) { + if (processes[i].pid != 0xFFFFFFFF && processes[i].pid != 0 && processes[i].is_user) { user_used += processes[i].used_memory; } } @@ -1192,13 +1179,19 @@ static uint64_t syscall_handler_inner(registers_t *regs) { else processes[0].used_memory = 0; int count = 0; - for (int i = 0; i < 16; i++) { // MAX_PROCESSES is 16 - if (processes[i].pid != 0xFFFFFFFF) { + for (int i = 0; i < 16; i++) { + if (processes[i].pid != 0xFFFFFFFF && (processes[i].is_user || processes[i].pid == 0)) { out[count].pid = processes[i].pid; extern void mem_memcpy(void *dest, const void *src, size_t len); mem_memcpy(out[count].name, processes[i].name, 64); - out[count].ticks = processes[i].ticks; + if (processes[i].pid == 0) { + out[count].name[0] = 'k'; out[count].name[1] = 'e'; out[count].name[2] = 'r'; + out[count].name[3] = 'n'; out[count].name[4] = 'e'; out[count].name[5] = 'l'; + out[count].name[6] = '\0'; + } + + out[count].ticks = processes[i].ticks; out[count].used_memory = processes[i].used_memory; count++; diff --git a/src/userland/gui/taskman.c b/src/userland/gui/taskman.c index 2593c4b..c9a7b75 100644 --- a/src/userland/gui/taskman.c +++ b/src/userland/gui/taskman.c @@ -49,29 +49,28 @@ static void update_proc_list(void) { proc_count = sys_system(SYSTEM_CMD_PROCESS_LIST, (uint64_t)proc_list, 32, 0, 0); uint64_t uptime_now = sys_system(SYSTEM_CMD_UPTIME, 0, 0, 0, 0); - uint64_t kernel_ticks_now = 0; + uint64_t user_ticks_now = 0; for (int i = 0; i < proc_count; i++) { - if (proc_list[i].pid == 0) { - kernel_ticks_now = proc_list[i].ticks; - break; + if (proc_list[i].pid != 0) { + user_ticks_now += proc_list[i].ticks; } } if (uptime_prev > 0) { uint64_t total_delta = uptime_now - uptime_prev; if (total_delta > 0) { - uint64_t kernel_delta = kernel_ticks_now - kernel_ticks_prev; - if (kernel_delta > total_delta) kernel_delta = total_delta; + uint64_t used_delta = user_ticks_now - kernel_ticks_prev; // Reusing the global state variable for prev user_ticks - uint64_t used_delta = total_delta - kernel_delta; - int usage = (int)((used_delta * 100) / total_delta); + // On a 4 CPU system, theoretically used_delta can be 4x total_delta + int usage = (int)((used_delta * 100) / (total_delta * 4)); + if (usage > 100) usage = 100; cpu_history[history_idx] = usage; } } uptime_prev = uptime_now; - kernel_ticks_prev = kernel_ticks_now; + kernel_ticks_prev = user_ticks_now; MemStats stats; sys_system(SYSTEM_CMD_MEMINFO, (uint64_t)&stats, 0, 0, 0); diff --git a/src/userland/libc/syscall.c b/src/userland/libc/syscall.c index 3eb8935..2be5e55 100644 --- a/src/userland/libc/syscall.c +++ b/src/userland/libc/syscall.c @@ -4,7 +4,7 @@ uint64_t syscall0(uint64_t sys_num) { uint64_t ret; - asm volatile("syscall" + asm volatile("int $0x80" : "=a"(ret) : "a"(sys_num) : "rcx", "r11", "memory"); @@ -13,7 +13,7 @@ uint64_t syscall0(uint64_t sys_num) { uint64_t syscall1(uint64_t sys_num, uint64_t arg1) { uint64_t ret; - asm volatile("syscall" + asm volatile("int $0x80" : "=a"(ret) : "a"(sys_num), "D"(arg1) : "rcx", "r11", "memory"); @@ -22,7 +22,7 @@ uint64_t syscall1(uint64_t sys_num, uint64_t arg1) { uint64_t syscall2(uint64_t sys_num, uint64_t arg1, uint64_t arg2) { uint64_t ret; - asm volatile("syscall" + asm volatile("int $0x80" : "=a"(ret) : "a"(sys_num), "D"(arg1), "S"(arg2) : "rcx", "r11", "memory"); @@ -31,7 +31,7 @@ uint64_t syscall2(uint64_t sys_num, uint64_t arg1, uint64_t arg2) { uint64_t syscall3(uint64_t sys_num, uint64_t arg1, uint64_t arg2, uint64_t arg3) { uint64_t ret; - asm volatile("syscall" + asm volatile("int $0x80" : "=a"(ret) : "a"(sys_num), "D"(arg1), "S"(arg2), "d"(arg3) : "rcx", "r11", "memory", "r10", "r8", "r9"); @@ -41,7 +41,7 @@ uint64_t syscall3(uint64_t sys_num, uint64_t arg1, uint64_t arg2, uint64_t arg3) uint64_t syscall4(uint64_t sys_num, uint64_t arg1, uint64_t arg2, uint64_t arg3, uint64_t arg4) { uint64_t ret; register uint64_t r10 asm("r10") = arg4; - asm volatile("syscall" + asm volatile("int $0x80" : "=a"(ret) : "a"(sys_num), "D"(arg1), "S"(arg2), "d"(arg3), "r"(r10) : "rcx", "r11", "memory", "r8", "r9"); @@ -52,7 +52,7 @@ uint64_t syscall5(uint64_t sys_num, uint64_t arg1, uint64_t arg2, uint64_t arg3, uint64_t ret; register uint64_t r10 asm("r10") = arg4; register uint64_t r8 asm("r8") = arg5; - asm volatile("syscall" + asm volatile("int $0x80" : "=a"(ret) : "a"(sys_num), "D"(arg1), "S"(arg2), "d"(arg3), "r"(r10), "r"(r8) : "rcx", "r11", "memory", "r9"); @@ -64,7 +64,7 @@ uint64_t syscall6(uint64_t sys_num, uint64_t arg1, uint64_t arg2, uint64_t arg3, register uint64_t r10 asm("r10") = arg4; register uint64_t r8 asm("r8") = arg5; register uint64_t r9 asm("r9") = arg6; - asm volatile("syscall" + asm volatile("int $0x80" : "=a"(ret) : "a"(sys_num), "D"(arg1), "S"(arg2), "d"(arg3), "r"(r10), "r"(r8), "r"(r9) : "rcx", "r11", "memory"); diff --git a/src/wm/graphics.c b/src/wm/graphics.c index c3c9842..2d1d32f 100644 --- a/src/wm/graphics.c +++ b/src/wm/graphics.c @@ -129,10 +129,6 @@ static void merge_dirty_rect(int x, int y, int w, int h) { } void graphics_mark_dirty(int x, int y, int w, int h) { - uint64_t rflags; - asm volatile("pushfq; pop %0; cli" : "=r"(rflags)); - - // Clamp to screen bounds if (x < 0) { w += x; x = 0; @@ -149,12 +145,10 @@ void graphics_mark_dirty(int x, int y, int w, int h) { } if (w <= 0 || h <= 0) { - asm volatile("push %0; popfq" : : "r"(rflags)); return; } merge_dirty_rect(x, y, w, h); - asm volatile("push %0; popfq" : : "r"(rflags)); } void graphics_mark_screen_dirty(void) { @@ -170,10 +164,11 @@ DirtyRect graphics_get_dirty_rect(void) { } void graphics_clear_dirty(void) { - uint64_t rflags; - asm volatile("pushfq; pop %0; cli" : "=r"(rflags)); + extern uint64_t wm_lock_acquire(void); + extern void wm_lock_release(uint64_t); + uint64_t rflags = wm_lock_acquire(); g_dirty.active = false; - asm volatile("push %0; popfq" : : "r"(rflags)); + wm_lock_release(rflags); } void graphics_set_render_target(uint32_t *buffer, int w, int h) { diff --git a/src/wm/wm.c b/src/wm/wm.c index 94e941a..8f9531b 100644 --- a/src/wm/wm.c +++ b/src/wm/wm.c @@ -28,6 +28,17 @@ // hours wasted: 57 // send help +#include "../sys/spinlock.h" +static spinlock_t wm_lock = SPINLOCK_INIT; + +uint64_t wm_lock_acquire(void) { + return spinlock_acquire_irqsave(&wm_lock); +} + +void wm_lock_release(uint64_t flags) { + spinlock_release_irqrestore(&wm_lock, flags); +} + extern void serial_write(const char *str); static bool str_eq(const char *s1, const char *s2) { @@ -39,6 +50,7 @@ static bool str_eq(const char *s1, const char *s2) { return (*s1 == *s2); } + // --- State --- static int mx = 400, my = 300; static int prev_mx = 400, prev_my = 300; @@ -1267,7 +1279,7 @@ void wm_paint(void) { int sh = get_screen_height(); uint64_t rflags; - asm volatile("pushfq; pop %0; cli" : "=r"(rflags)); + rflags = wm_lock_acquire(); DirtyRect dirty = graphics_get_dirty_rect(); @@ -1339,14 +1351,16 @@ void wm_paint(void) { } // 3. Windows - sort by z-index and draw + int local_window_count = window_count; Window *sorted_windows[32]; - for (int i = 0; i < window_count; i++) { + for (int i = 0; i < local_window_count; i++) { sorted_windows[i] = all_windows[i]; } - for (int i = 0; i < window_count - 1; i++) { - for (int j = 0; j < window_count - i - 1; j++) { - if (sorted_windows[j]->z_index > sorted_windows[j + 1]->z_index) { + for (int i = 0; i < local_window_count - 1; i++) { + for (int j = 0; j < local_window_count - i - 1; j++) { + if (sorted_windows[j] && sorted_windows[j + 1] && + sorted_windows[j]->z_index > sorted_windows[j + 1]->z_index) { Window *temp = sorted_windows[j]; sorted_windows[j] = sorted_windows[j + 1]; sorted_windows[j + 1] = temp; @@ -1354,9 +1368,9 @@ void wm_paint(void) { } } - for (int i = 0; i < window_count; i++) { + for (int i = 0; i < local_window_count; i++) { Window *win = sorted_windows[i]; - if (!win->visible) continue; + if (!win || !win->visible) continue; if (dirty.active && !win->focused) { if (win->x + win->w <= dirty.x || win->x >= dirty.x + dirty.w || @@ -1516,7 +1530,7 @@ void wm_paint(void) { graphics_flip_buffer(); // Restore IRQs - asm volatile("push %0; popfq" : : "r"(rflags)); + wm_lock_release(rflags); } // --- Input Handling --- @@ -1525,15 +1539,11 @@ bool rect_contains(int x, int y, int w, int h, int px, int py) { return px >= x && px < x + w && py >= y && py < y + h; } -void wm_bring_to_front(Window *win) { - uint64_t rflags; - asm volatile("pushfq; pop %0; cli" : "=r"(rflags)); - // Clear focus from all windows +void wm_bring_to_front_locked(Window *win) { for (int i = 0; i < window_count; i++) { all_windows[i]->focused = false; } - // Find current max z-index int max_z = 0; for (int i = 0; i < window_count; i++) { if (all_windows[i]->z_index > max_z) max_z = all_windows[i]->z_index; @@ -1543,30 +1553,36 @@ void wm_bring_to_front(Window *win) { win->focused = true; win->z_index = max_z + 1; force_redraw = true; - asm volatile("push %0; popfq" : : "r"(rflags)); +} + +void wm_bring_to_front(Window *win) { + uint64_t rflags; + rflags = wm_lock_acquire(); + wm_bring_to_front_locked(win); + wm_lock_release(rflags); } void wm_add_window(Window *win) { uint64_t rflags; - asm volatile("pushfq; pop %0; cli" : "=r"(rflags)); + rflags = wm_lock_acquire(); if (window_count < 32) { all_windows[window_count++] = win; - wm_bring_to_front(win); // Ensure newly added windows are on top + wm_bring_to_front_locked(win); // Ensure newly added windows are on top } - asm volatile("push %0; popfq" : : "r"(rflags)); + wm_lock_release(rflags); } Window* wm_find_window_by_title(const char *title) { if (!title) return NULL; uint64_t rflags; - asm volatile("pushfq; pop %0; cli" : "=r"(rflags)); + rflags = wm_lock_acquire(); for (int i = 0; i < window_count; i++) { if (all_windows[i] && all_windows[i]->title && str_eq(all_windows[i]->title, title)) { - asm volatile("push %0; popfq" : : "r"(rflags)); + wm_lock_release(rflags); return all_windows[i]; } } - asm volatile("push %0; popfq" : : "r"(rflags)); + wm_lock_release(rflags); return NULL; } @@ -1579,7 +1595,7 @@ void wm_remove_window(Window *win) { serial_write("'\n"); uint64_t rflags; - asm volatile("pushfq; pop %0; cli" : "=r"(rflags)); + rflags = wm_lock_acquire(); int index = -1; for (int i = 0; i < window_count; i++) { @@ -1603,7 +1619,7 @@ void wm_remove_window(Window *win) { // Mark for redraw while protected force_redraw = true; } else { - asm volatile("push %0; popfq" : : "r"(rflags)); + wm_lock_release(rflags); serial_write("WM: Window not found in all_windows list!\n"); return; } @@ -1615,7 +1631,7 @@ void wm_remove_window(Window *win) { } kfree(win); - asm volatile("push %0; popfq" : : "r"(rflags)); + wm_lock_release(rflags); } void wm_handle_click(int x, int y) { @@ -1784,7 +1800,7 @@ void wm_handle_click(int x, int y) { process_create_elf("/bin/about.elf", NULL); } else if (item == 1) { // Settings Window *existing = wm_find_window_by_title("Settings"); - if (existing) wm_bring_to_front(existing); + if (existing) wm_bring_to_front_locked(existing); else process_create_elf("/bin/settings.elf", NULL); } else if (item == 2) { // Shutdown k_shutdown(); @@ -1813,7 +1829,7 @@ void wm_handle_click(int x, int y) { // If a window was clicked if (topmost != NULL) { - wm_bring_to_front(topmost); + wm_bring_to_front_locked(topmost); // Check traffic light close button (now at top-left) if (rect_contains(topmost->x + 8, topmost->y + 2, 12, 12, x, y)) { @@ -2122,52 +2138,52 @@ void wm_handle_right_click(int x, int y) { } else if (str_starts_with(start_menu_pending_app, "Notepad")) { Window *existing = wm_find_window_by_title("Notepad"); if (existing) { - wm_bring_to_front(existing); + wm_bring_to_front_locked(existing); } else { process_create_elf("/bin/notepad.elf", NULL); } } else if (str_starts_with(start_menu_pending_app, "Editor")) { Window *existing = wm_find_window_by_title("Txtedit"); - if (existing) wm_bring_to_front(existing); + if (existing) wm_bring_to_front_locked(existing); else process_create_elf("/bin/txtedit.elf", NULL); } else if (str_starts_with(start_menu_pending_app, "Word Processor")) { Window *existing = wm_find_window_by_title("Word Processor"); - if (existing) wm_bring_to_front(existing); + if (existing) wm_bring_to_front_locked(existing); else process_create_elf("/bin/boredword.elf", NULL); } else if (str_starts_with(start_menu_pending_app, "Terminal")) { - cmd_reset(); wm_bring_to_front(&win_cmd); + cmd_reset(); wm_bring_to_front_locked(&win_cmd); } else if (str_starts_with(start_menu_pending_app, "Calculator")) { Window *existing = wm_find_window_by_title("Calculator"); if (existing) { - wm_bring_to_front(existing); + wm_bring_to_front_locked(existing); } else { process_create_elf("/bin/calculator.elf", NULL); } } else if (str_starts_with(start_menu_pending_app, "Minesweeper")) { Window *existing = wm_find_window_by_title("Minesweeper"); - if (existing) wm_bring_to_front(existing); + if (existing) wm_bring_to_front_locked(existing); else process_create_elf("/bin/minesweeper.elf", NULL); } else if (str_starts_with(start_menu_pending_app, "Settings")) { Window *existing = wm_find_window_by_title("Settings"); - if (existing) wm_bring_to_front(existing); + if (existing) wm_bring_to_front_locked(existing); else process_create_elf("/bin/settings.elf", NULL); } else if (str_starts_with(start_menu_pending_app, "Paint")) { Window *existing = wm_find_window_by_title("Paint"); - if (existing) wm_bring_to_front(existing); + if (existing) wm_bring_to_front_locked(existing); else process_create_elf("/bin/paint.elf", NULL); } else if (str_starts_with(start_menu_pending_app, "Clock")) { Window *existing = wm_find_window_by_title("Clock"); - if (existing) wm_bring_to_front(existing); + if (existing) wm_bring_to_front_locked(existing); else process_create_elf("/bin/clock.elf", NULL); } else if (str_starts_with(start_menu_pending_app, "Browser")) { Window *existing = wm_find_window_by_title("Web Browser"); - if (existing) wm_bring_to_front(existing); + if (existing) wm_bring_to_front_locked(existing); else process_create_elf("/bin/browser.elf", NULL); } else if (str_starts_with(start_menu_pending_app, "About")) { process_create_elf("/bin/about.elf", NULL); } else if (str_starts_with(start_menu_pending_app, "Task Manager")) { Window *existing = wm_find_window_by_title("Task Manager"); - if (existing) wm_bring_to_front(existing); + if (existing) wm_bring_to_front_locked(existing); else process_create_elf("/bin/taskman.elf", NULL); } else if (str_starts_with(start_menu_pending_app, "Shutdown")) { k_shutdown(); @@ -2196,7 +2212,7 @@ void wm_handle_right_click(int x, int y) { } else if (str_ends_with(icon->name, "Settings.shortcut")) { process_create_elf("/bin/settings.elf", NULL); handled = true; } else if (str_ends_with(icon->name, "Terminal.shortcut")) { - wm_bring_to_front(&win_cmd); handled = true; + wm_bring_to_front_locked(&win_cmd); handled = true; } else if (str_ends_with(icon->name, "About.shortcut")) { process_create_elf("/bin/about.elf", NULL); handled = true; } else if (str_ends_with(icon->name, "Files.shortcut")) { @@ -2660,13 +2676,24 @@ void wm_process_input(void) { } uint64_t rflags; - asm volatile("pushfq; pop %0; cli" : "=r"(rflags)); + rflags = wm_lock_acquire(); while (key_head != key_tail) { key_event_t ev = key_queue[key_tail]; key_tail = (key_tail + 1) % INPUT_QUEUE_SIZE; wm_dispatch_key(ev.c, ev.pressed); } - asm volatile("push %0; popfq" : : "r"(rflags)); + wm_lock_release(rflags); + + if (force_redraw) { + graphics_mark_screen_dirty(); + force_redraw = false; + } + + DirtyRect dirty = graphics_get_dirty_rect(); + if (dirty.active) { + wm_paint(); + graphics_clear_dirty(); + } } void wm_mark_dirty(int x, int y, int w, int h) { @@ -2766,17 +2793,6 @@ void wm_timer_tick(void) { int sw = get_screen_width(); wm_mark_dirty(sw - 280, 40, 275, 60); } - - if (force_redraw) { - graphics_mark_screen_dirty(); - force_redraw = false; - } - - DirtyRect dirty = graphics_get_dirty_rect(); - if (dirty.active) { - wm_paint(); - graphics_clear_dirty(); - } } void wm_notify_fs_change(void) { diff --git a/src/wm/wm.h b/src/wm/wm.h index 320302d..e5b30e8 100644 --- a/src/wm/wm.h +++ b/src/wm/wm.h @@ -7,6 +7,9 @@ #include #include +uint64_t wm_lock_acquire(void); +void wm_lock_release(uint64_t flags); + // --- Constants --- #define COLOR_TEAL 0xFF008080 #define COLOR_GRAY 0xFFC0C0C0