mirror of
https://github.com/BoredDevNL/BoredOS.git
synced 2026-05-15 10:48:38 +00:00
CHECKP: multi-thread applications
This commit is contained in:
parent
9fb307e603
commit
e95c82b162
14 changed files with 250 additions and 134 deletions
7
fix_syscalls.sh
Executable file
7
fix_syscalls.sh
Executable file
|
|
@ -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"
|
||||||
|
|
@ -7,11 +7,13 @@ global isr1_wrapper
|
||||||
global isr8_wrapper
|
global isr8_wrapper
|
||||||
global isr12_wrapper
|
global isr12_wrapper
|
||||||
global isr14_wrapper
|
global isr14_wrapper
|
||||||
|
global isr128_wrapper
|
||||||
global isr_sched_ipi_wrapper
|
global isr_sched_ipi_wrapper
|
||||||
extern timer_handler
|
extern timer_handler
|
||||||
extern keyboard_handler
|
extern keyboard_handler
|
||||||
extern mouse_handler
|
extern mouse_handler
|
||||||
extern sched_ipi_handler
|
extern sched_ipi_handler
|
||||||
|
extern syscall_handler_c
|
||||||
extern exception_handler_c
|
extern exception_handler_c
|
||||||
|
|
||||||
; Helper to send EOI (End of Interrupt) to PIC
|
; Helper to send EOI (End of Interrupt) to PIC
|
||||||
|
|
@ -90,6 +92,9 @@ isr12_wrapper:
|
||||||
isr_sched_ipi_wrapper:
|
isr_sched_ipi_wrapper:
|
||||||
ISR_NOERRCODE sched_ipi_handler, 65
|
ISR_NOERRCODE sched_ipi_handler, 65
|
||||||
|
|
||||||
|
isr128_wrapper:
|
||||||
|
ISR_NOERRCODE syscall_handler_c, 128
|
||||||
|
|
||||||
; Common exception macro for exceptions WITHOUT error code
|
; Common exception macro for exceptions WITHOUT error code
|
||||||
%macro EXCEPTION_NOERRCODE 1
|
%macro EXCEPTION_NOERRCODE 1
|
||||||
global exc%1_wrapper
|
global exc%1_wrapper
|
||||||
|
|
|
||||||
|
|
@ -59,7 +59,17 @@ uint64_t exception_handler_c(registers_t *regs) {
|
||||||
serial_write(buf);
|
serial_write(buf);
|
||||||
|
|
||||||
if ((regs->cs & 0x3) != 0) {
|
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");
|
if (cmd_get_cursor_col() != 0) cmd_write("\n");
|
||||||
cmd_write("*** USER EXCEPTION ***\nVector: "); cmd_write_hex(vector);
|
cmd_write("*** USER EXCEPTION ***\nVector: "); cmd_write_hex(vector);
|
||||||
cmd_write("\nRIP: "); cmd_write_hex(regs->rip);
|
cmd_write("\nRIP: "); cmd_write_hex(regs->rip);
|
||||||
|
|
@ -234,6 +244,9 @@ void idt_register_interrupts(void) {
|
||||||
extern void isr_sched_ipi_wrapper(void);
|
extern void isr_sched_ipi_wrapper(void);
|
||||||
idt_set_gate(0x41, isr_sched_ipi_wrapper, cs, 0x8E);
|
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) {
|
void idt_load(void) {
|
||||||
|
|
|
||||||
|
|
@ -16,14 +16,18 @@ static volatile uint32_t *lapic_base = 0;
|
||||||
#define LAPIC_ICR_LOW (0x300 / 4)
|
#define LAPIC_ICR_LOW (0x300 / 4)
|
||||||
#define LAPIC_ICR_HIGH (0x310 / 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) {
|
void lapic_init(void) {
|
||||||
extern uint64_t hhdm_offset;
|
extern uint64_t hhdm_offset;
|
||||||
lapic_base = (volatile uint32_t *)(hhdm_offset + 0xFEE00000ULL);
|
lapic_base = (volatile uint32_t *)(hhdm_offset + 0xFEE00000ULL);
|
||||||
|
|
||||||
// Enable the LAPIC by setting the Spurious Interrupt Vector Register
|
lapic_enable();
|
||||||
// Bit 8 = APIC Software Enable, vector = 0xFF (spurious)
|
|
||||||
lapic_base[LAPIC_SVR] = 0x1FF;
|
|
||||||
|
|
||||||
serial_write("[LAPIC] Initialized at HHDM + 0xFEE00000\n");
|
serial_write("[LAPIC] Initialized at HHDM + 0xFEE00000\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,9 @@
|
||||||
// Initialize LAPIC access (maps registers via HHDM)
|
// Initialize LAPIC access (maps registers via HHDM)
|
||||||
void lapic_init(void);
|
void lapic_init(void);
|
||||||
|
|
||||||
|
// Enable LAPIC (set SVR bit 8)
|
||||||
|
void lapic_enable(void);
|
||||||
|
|
||||||
// Send End-of-Interrupt to the local APIC
|
// Send End-of-Interrupt to the local APIC
|
||||||
void lapic_eoi(void);
|
void lapic_eoi(void);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -57,8 +57,13 @@ void process_init(void) {
|
||||||
current_process[0] = kernel_proc;
|
current_process[0] = kernel_proc;
|
||||||
}
|
}
|
||||||
|
|
||||||
void process_create(void* entry_point, bool is_user) {
|
process_t* process_create(void (*entry_point)(void), bool is_user) {
|
||||||
if (process_count >= MAX_PROCESSES) return;
|
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++];
|
process_t *new_proc = &processes[process_count++];
|
||||||
new_proc->pid = next_pid++;
|
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();
|
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
|
// 2. Allocate aligned stack
|
||||||
void* user_stack = kmalloc_aligned(4096, 4096);
|
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
|
new_proc->cpu_affinity = 0; // Non-ELF processes stay on BSP
|
||||||
|
|
||||||
// Add to linked list (Critical Section)
|
// Add to linked list
|
||||||
uint64_t rflags = spinlock_acquire_irqsave(&runqueue_lock);
|
|
||||||
new_proc->next = current_process[0]->next;
|
new_proc->next = current_process[0]->next;
|
||||||
current_process[0]->next = new_proc;
|
current_process[0]->next = new_proc;
|
||||||
|
|
||||||
spinlock_release_irqrestore(&runqueue_lock, rflags);
|
spinlock_release_irqrestore(&runqueue_lock, rflags);
|
||||||
|
return new_proc;
|
||||||
}
|
}
|
||||||
|
|
||||||
process_t* process_create_elf(const char* filepath, const char* args_str) {
|
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;
|
process_t *new_proc = NULL;
|
||||||
|
|
||||||
// Find an available slot
|
// 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->pid = next_pid++;
|
||||||
new_proc->is_user = true;
|
new_proc->is_user = true;
|
||||||
|
spinlock_release_irqrestore(&runqueue_lock, rflags);
|
||||||
|
|
||||||
// 1. Setup Page Table
|
// 1. Setup Page Table
|
||||||
new_proc->pml4_phys = paging_create_user_pml4_phys();
|
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)
|
// 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;
|
new_proc->next = current_process[0]->next;
|
||||||
current_process[0]->next = new_proc;
|
current_process[0]->next = new_proc;
|
||||||
spinlock_release_irqrestore(&runqueue_lock, rflags);
|
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;
|
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) {
|
process_t* process_get_current(void) {
|
||||||
uint32_t cpu = smp_this_cpu_id();
|
uint32_t cpu = smp_this_cpu_id();
|
||||||
return current_process[cpu];
|
return current_process[cpu];
|
||||||
|
|
@ -373,8 +397,8 @@ uint64_t process_schedule(uint64_t current_rsp) {
|
||||||
process_t *next_proc = cur->next;
|
process_t *next_proc = cur->next;
|
||||||
|
|
||||||
while (next_proc != start) {
|
while (next_proc != start) {
|
||||||
// Only consider processes assigned to our CPU
|
// Only consider processes assigned to our CPU and not terminated
|
||||||
if (next_proc->cpu_affinity == my_cpu) {
|
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) {
|
if (next_proc->pid == 0 || next_proc->sleep_until == 0 || next_proc->sleep_until <= now) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
@ -382,9 +406,20 @@ uint64_t process_schedule(uint64_t current_rsp) {
|
||||||
next_proc = next_proc->next;
|
next_proc = next_proc->next;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If we didn't find a ready process for our CPU, stay on current
|
// 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) {
|
if (next_proc->cpu_affinity != my_cpu || next_proc->pid == 0xFFFFFFFF) {
|
||||||
return current_rsp;
|
// 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;
|
current_process[my_cpu] = next_proc;
|
||||||
|
|
@ -465,12 +500,25 @@ void process_terminate(process_t *to_delete) {
|
||||||
uint32_t cpu_count = smp_cpu_count();
|
uint32_t cpu_count = smp_cpu_count();
|
||||||
for (uint32_t c = 0; c < cpu_count && c < MAX_CPUS_SCHED; c++) {
|
for (uint32_t c = 0; c < cpu_count && c < MAX_CPUS_SCHED; c++) {
|
||||||
if (current_process[c] == to_delete) {
|
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
|
// Mark slot as free
|
||||||
to_delete->pid = 0xFFFFFFFF;
|
to_delete->pid = 0xFFFFFFFF;
|
||||||
|
to_delete->cpu_affinity = 0xFFFFFFFF;
|
||||||
|
|
||||||
if (to_delete->user_stack_alloc) kfree(to_delete->user_stack_alloc);
|
if (to_delete->user_stack_alloc) kfree(to_delete->user_stack_alloc);
|
||||||
if (to_delete->kernel_stack_alloc) {
|
if (to_delete->kernel_stack_alloc) {
|
||||||
|
|
@ -518,10 +566,26 @@ uint64_t process_terminate_current(void) {
|
||||||
}
|
}
|
||||||
|
|
||||||
prev->next = to_delete->next;
|
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
|
// Mark slot as free
|
||||||
to_delete->pid = 0xFFFFFFFF;
|
to_delete->pid = 0xFFFFFFFF;
|
||||||
|
to_delete->cpu_affinity = 0xFFFFFFFF;
|
||||||
|
|
||||||
// 4. Load context for the NEXT process
|
// 4. Load context for the NEXT process
|
||||||
if (current_process[my_cpu]->is_user && current_process[my_cpu]->kernel_stack) {
|
if (current_process[my_cpu]->is_user && current_process[my_cpu]->kernel_stack) {
|
||||||
|
|
|
||||||
|
|
@ -63,9 +63,11 @@ typedef struct {
|
||||||
} ProcessInfo;
|
} ProcessInfo;
|
||||||
|
|
||||||
void process_init(void);
|
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_create_elf(const char* filepath, const char* args_str);
|
||||||
process_t* process_get_current(void);
|
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_schedule(uint64_t current_rsp);
|
||||||
uint64_t process_terminate_current(void);
|
uint64_t process_terminate_current(void);
|
||||||
void process_terminate(process_t *proc);
|
void process_terminate(process_t *proc);
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,7 @@
|
||||||
#include "idt.h"
|
#include "idt.h"
|
||||||
#include "platform.h"
|
#include "platform.h"
|
||||||
#include "paging.h"
|
#include "paging.h"
|
||||||
|
#include "process.h"
|
||||||
|
|
||||||
extern void serial_write(const char *str);
|
extern void serial_write(const char *str);
|
||||||
extern void serial_write_num(uint32_t n);
|
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("mov %0, %%cr4" : : "r"(cr4));
|
||||||
asm volatile("fninit");
|
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;
|
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
|
// 4. Load per-CPU TSS
|
||||||
gdt_load_ap_tss(my_id);
|
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();
|
uint64_t kernel_cr3 = paging_get_pml4_phys();
|
||||||
asm volatile("mov %0, %%cr3" : : "r"(kernel_cr3));
|
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;
|
cpu_states[my_id].online = true;
|
||||||
|
|
||||||
serial_write("[SMP] AP ");
|
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_num(cpu_states[my_id].lapic_id);
|
||||||
serial_write(")\n");
|
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).
|
// APs will be woken by scheduling IPIs from BSP (vector 0x41).
|
||||||
// The IPI handler does context switching for this CPU's processes.
|
// The IPI handler does context switching for this CPU's processes.
|
||||||
asm volatile("sti");
|
asm volatile("sti");
|
||||||
|
|
|
||||||
|
|
@ -33,25 +33,10 @@ static inline void wrmsr(uint32_t msr, uint64_t value) {
|
||||||
asm volatile("wrmsr" : : "c"(msr), "a"(low), "d"(high));
|
asm volatile("wrmsr" : : "c"(msr), "a"(low), "d"(high));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Implemented in assembly
|
extern void isr128_wrapper(void);
|
||||||
extern void syscall_entry(void);
|
|
||||||
|
|
||||||
extern uint64_t kernel_syscall_stack;
|
|
||||||
|
|
||||||
void syscall_init(void) {
|
void syscall_init(void) {
|
||||||
void* stack = kmalloc(16384);
|
// SMP-Safe System Calls using int 0x80 (configured in idt.c)
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void user_window_close(Window *win) {
|
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);
|
extern void graphics_set_render_target(uint32_t *buffer, int w, int h);
|
||||||
|
|
||||||
uint64_t rflags;
|
uint64_t rflags;
|
||||||
asm volatile("pushfq; pop %0; cli" : "=r"(rflags));
|
rflags = wm_lock_acquire();
|
||||||
|
|
||||||
if (win->pixels) {
|
if (win->pixels) {
|
||||||
// Strict user-to-window relative clamping
|
// 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);
|
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) {
|
} else if (cmd == GUI_CMD_DRAW_ROUNDED_RECT_FILLED) {
|
||||||
Window *win = (Window *)arg2;
|
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);
|
extern void graphics_set_render_target(uint32_t *buffer, int w, int h);
|
||||||
|
|
||||||
uint64_t rflags;
|
uint64_t rflags;
|
||||||
asm volatile("pushfq; pop %0; cli" : "=r"(rflags));
|
rflags = wm_lock_acquire();
|
||||||
|
|
||||||
if (win->pixels) {
|
if (win->pixels) {
|
||||||
int rx = (int)params[0]; int ry = (int)params[1];
|
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) {
|
} else if (cmd == GUI_CMD_DRAW_STRING) {
|
||||||
Window *win = (Window *)arg2;
|
Window *win = (Window *)arg2;
|
||||||
|
|
@ -359,7 +344,7 @@ static uint64_t syscall_handler_inner(registers_t *regs) {
|
||||||
kernel_str[i] = 0;
|
kernel_str[i] = 0;
|
||||||
|
|
||||||
uint64_t rflags;
|
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();
|
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
|
} else if (cmd == 10) { // GUI_CMD_DRAW_STRING_BITMAP
|
||||||
Window *win = (Window *)arg2;
|
Window *win = (Window *)arg2;
|
||||||
|
|
@ -418,7 +403,7 @@ static uint64_t syscall_handler_inner(registers_t *regs) {
|
||||||
kernel_str[i] = 0;
|
kernel_str[i] = 0;
|
||||||
|
|
||||||
uint64_t rflags;
|
uint64_t rflags;
|
||||||
asm volatile("pushfq; pop %0; cli" : "=r"(rflags));
|
rflags = wm_lock_acquire();
|
||||||
|
|
||||||
if (win->pixels) {
|
if (win->pixels) {
|
||||||
if (ux >= -100 && ux < win->w && uy >= -100 && uy < (win->h - 20)) {
|
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);
|
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
|
} else if (cmd == 11) { // GUI_CMD_DRAW_STRING_SCALED
|
||||||
Window *win = (Window *)arg2;
|
Window *win = (Window *)arg2;
|
||||||
|
|
@ -457,7 +442,7 @@ static uint64_t syscall_handler_inner(registers_t *regs) {
|
||||||
kernel_str[i] = 0;
|
kernel_str[i] = 0;
|
||||||
|
|
||||||
uint64_t rflags;
|
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();
|
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
|
} else if (cmd == 18) { // GUI_CMD_DRAW_STRING_SCALED_SLOPED
|
||||||
Window *win = (Window *)arg2;
|
Window *win = (Window *)arg2;
|
||||||
|
|
@ -530,7 +515,7 @@ static uint64_t syscall_handler_inner(registers_t *regs) {
|
||||||
kernel_str[i] = 0;
|
kernel_str[i] = 0;
|
||||||
|
|
||||||
uint64_t rflags;
|
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();
|
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) {
|
} else if (cmd == GUI_CMD_DRAW_IMAGE) {
|
||||||
Window *win = (Window *)arg2;
|
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];
|
for (int i = 0; i < 4; i++) params[i] = u_params[i];
|
||||||
|
|
||||||
uint64_t rflags;
|
uint64_t rflags;
|
||||||
asm volatile("pushfq; pop %0; cli" : "=r"(rflags));
|
rflags = wm_lock_acquire();
|
||||||
|
|
||||||
if (win->pixels) {
|
if (win->pixels) {
|
||||||
int rx = (int)params[0]; int ry = (int)params[1];
|
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) {
|
} else if (cmd == GUI_CMD_MARK_DIRTY) {
|
||||||
|
uint64_t rflags = wm_lock_acquire();
|
||||||
Window *win = (Window *)arg2;
|
Window *win = (Window *)arg2;
|
||||||
uint64_t *u_params = (uint64_t *)arg3;
|
uint64_t *u_params = (uint64_t *)arg3;
|
||||||
if (win && u_params) {
|
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_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) {
|
} else if (cmd == GUI_CMD_GET_EVENT) {
|
||||||
Window *win = (Window *)arg2;
|
Window *win = (Window *)arg2;
|
||||||
gui_event_t *ev_out = (gui_event_t *)arg3;
|
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 total_used = stats.used_memory;
|
||||||
size_t user_used = 0;
|
size_t user_used = 0;
|
||||||
for (int i = 0; i < 16; i++) {
|
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;
|
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;
|
else processes[0].used_memory = 0;
|
||||||
|
|
||||||
int count = 0;
|
int count = 0;
|
||||||
for (int i = 0; i < 16; i++) { // MAX_PROCESSES is 16
|
for (int i = 0; i < 16; i++) {
|
||||||
if (processes[i].pid != 0xFFFFFFFF) {
|
if (processes[i].pid != 0xFFFFFFFF && (processes[i].is_user || processes[i].pid == 0)) {
|
||||||
out[count].pid = processes[i].pid;
|
out[count].pid = processes[i].pid;
|
||||||
extern void mem_memcpy(void *dest, const void *src, size_t len);
|
extern void mem_memcpy(void *dest, const void *src, size_t len);
|
||||||
mem_memcpy(out[count].name, processes[i].name, 64);
|
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;
|
out[count].used_memory = processes[i].used_memory;
|
||||||
|
|
||||||
count++;
|
count++;
|
||||||
|
|
|
||||||
|
|
@ -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);
|
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 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++) {
|
for (int i = 0; i < proc_count; i++) {
|
||||||
if (proc_list[i].pid == 0) {
|
if (proc_list[i].pid != 0) {
|
||||||
kernel_ticks_now = proc_list[i].ticks;
|
user_ticks_now += proc_list[i].ticks;
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (uptime_prev > 0) {
|
if (uptime_prev > 0) {
|
||||||
uint64_t total_delta = uptime_now - uptime_prev;
|
uint64_t total_delta = uptime_now - uptime_prev;
|
||||||
if (total_delta > 0) {
|
if (total_delta > 0) {
|
||||||
uint64_t kernel_delta = kernel_ticks_now - kernel_ticks_prev;
|
uint64_t used_delta = user_ticks_now - kernel_ticks_prev; // Reusing the global state variable for prev user_ticks
|
||||||
if (kernel_delta > total_delta) kernel_delta = total_delta;
|
|
||||||
|
|
||||||
uint64_t used_delta = total_delta - kernel_delta;
|
// On a 4 CPU system, theoretically used_delta can be 4x total_delta
|
||||||
int usage = (int)((used_delta * 100) / total_delta);
|
int usage = (int)((used_delta * 100) / (total_delta * 4));
|
||||||
|
if (usage > 100) usage = 100;
|
||||||
cpu_history[history_idx] = usage;
|
cpu_history[history_idx] = usage;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
uptime_prev = uptime_now;
|
uptime_prev = uptime_now;
|
||||||
kernel_ticks_prev = kernel_ticks_now;
|
kernel_ticks_prev = user_ticks_now;
|
||||||
|
|
||||||
MemStats stats;
|
MemStats stats;
|
||||||
sys_system(SYSTEM_CMD_MEMINFO, (uint64_t)&stats, 0, 0, 0);
|
sys_system(SYSTEM_CMD_MEMINFO, (uint64_t)&stats, 0, 0, 0);
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@
|
||||||
|
|
||||||
uint64_t syscall0(uint64_t sys_num) {
|
uint64_t syscall0(uint64_t sys_num) {
|
||||||
uint64_t ret;
|
uint64_t ret;
|
||||||
asm volatile("syscall"
|
asm volatile("int $0x80"
|
||||||
: "=a"(ret)
|
: "=a"(ret)
|
||||||
: "a"(sys_num)
|
: "a"(sys_num)
|
||||||
: "rcx", "r11", "memory");
|
: "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 syscall1(uint64_t sys_num, uint64_t arg1) {
|
||||||
uint64_t ret;
|
uint64_t ret;
|
||||||
asm volatile("syscall"
|
asm volatile("int $0x80"
|
||||||
: "=a"(ret)
|
: "=a"(ret)
|
||||||
: "a"(sys_num), "D"(arg1)
|
: "a"(sys_num), "D"(arg1)
|
||||||
: "rcx", "r11", "memory");
|
: "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 syscall2(uint64_t sys_num, uint64_t arg1, uint64_t arg2) {
|
||||||
uint64_t ret;
|
uint64_t ret;
|
||||||
asm volatile("syscall"
|
asm volatile("int $0x80"
|
||||||
: "=a"(ret)
|
: "=a"(ret)
|
||||||
: "a"(sys_num), "D"(arg1), "S"(arg2)
|
: "a"(sys_num), "D"(arg1), "S"(arg2)
|
||||||
: "rcx", "r11", "memory");
|
: "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 syscall3(uint64_t sys_num, uint64_t arg1, uint64_t arg2, uint64_t arg3) {
|
||||||
uint64_t ret;
|
uint64_t ret;
|
||||||
asm volatile("syscall"
|
asm volatile("int $0x80"
|
||||||
: "=a"(ret)
|
: "=a"(ret)
|
||||||
: "a"(sys_num), "D"(arg1), "S"(arg2), "d"(arg3)
|
: "a"(sys_num), "D"(arg1), "S"(arg2), "d"(arg3)
|
||||||
: "rcx", "r11", "memory", "r10", "r8", "r9");
|
: "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 syscall4(uint64_t sys_num, uint64_t arg1, uint64_t arg2, uint64_t arg3, uint64_t arg4) {
|
||||||
uint64_t ret;
|
uint64_t ret;
|
||||||
register uint64_t r10 asm("r10") = arg4;
|
register uint64_t r10 asm("r10") = arg4;
|
||||||
asm volatile("syscall"
|
asm volatile("int $0x80"
|
||||||
: "=a"(ret)
|
: "=a"(ret)
|
||||||
: "a"(sys_num), "D"(arg1), "S"(arg2), "d"(arg3), "r"(r10)
|
: "a"(sys_num), "D"(arg1), "S"(arg2), "d"(arg3), "r"(r10)
|
||||||
: "rcx", "r11", "memory", "r8", "r9");
|
: "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;
|
uint64_t ret;
|
||||||
register uint64_t r10 asm("r10") = arg4;
|
register uint64_t r10 asm("r10") = arg4;
|
||||||
register uint64_t r8 asm("r8") = arg5;
|
register uint64_t r8 asm("r8") = arg5;
|
||||||
asm volatile("syscall"
|
asm volatile("int $0x80"
|
||||||
: "=a"(ret)
|
: "=a"(ret)
|
||||||
: "a"(sys_num), "D"(arg1), "S"(arg2), "d"(arg3), "r"(r10), "r"(r8)
|
: "a"(sys_num), "D"(arg1), "S"(arg2), "d"(arg3), "r"(r10), "r"(r8)
|
||||||
: "rcx", "r11", "memory", "r9");
|
: "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 r10 asm("r10") = arg4;
|
||||||
register uint64_t r8 asm("r8") = arg5;
|
register uint64_t r8 asm("r8") = arg5;
|
||||||
register uint64_t r9 asm("r9") = arg6;
|
register uint64_t r9 asm("r9") = arg6;
|
||||||
asm volatile("syscall"
|
asm volatile("int $0x80"
|
||||||
: "=a"(ret)
|
: "=a"(ret)
|
||||||
: "a"(sys_num), "D"(arg1), "S"(arg2), "d"(arg3), "r"(r10), "r"(r8), "r"(r9)
|
: "a"(sys_num), "D"(arg1), "S"(arg2), "d"(arg3), "r"(r10), "r"(r8), "r"(r9)
|
||||||
: "rcx", "r11", "memory");
|
: "rcx", "r11", "memory");
|
||||||
|
|
|
||||||
|
|
@ -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) {
|
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) {
|
if (x < 0) {
|
||||||
w += x;
|
w += x;
|
||||||
x = 0;
|
x = 0;
|
||||||
|
|
@ -149,12 +145,10 @@ void graphics_mark_dirty(int x, int y, int w, int h) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (w <= 0 || h <= 0) {
|
if (w <= 0 || h <= 0) {
|
||||||
asm volatile("push %0; popfq" : : "r"(rflags));
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
merge_dirty_rect(x, y, w, h);
|
merge_dirty_rect(x, y, w, h);
|
||||||
asm volatile("push %0; popfq" : : "r"(rflags));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void graphics_mark_screen_dirty(void) {
|
void graphics_mark_screen_dirty(void) {
|
||||||
|
|
@ -170,10 +164,11 @@ DirtyRect graphics_get_dirty_rect(void) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void graphics_clear_dirty(void) {
|
void graphics_clear_dirty(void) {
|
||||||
uint64_t rflags;
|
extern uint64_t wm_lock_acquire(void);
|
||||||
asm volatile("pushfq; pop %0; cli" : "=r"(rflags));
|
extern void wm_lock_release(uint64_t);
|
||||||
|
uint64_t rflags = wm_lock_acquire();
|
||||||
g_dirty.active = false;
|
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) {
|
void graphics_set_render_target(uint32_t *buffer, int w, int h) {
|
||||||
|
|
|
||||||
116
src/wm/wm.c
116
src/wm/wm.c
|
|
@ -28,6 +28,17 @@
|
||||||
// hours wasted: 57
|
// hours wasted: 57
|
||||||
// send help
|
// 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);
|
extern void serial_write(const char *str);
|
||||||
|
|
||||||
static bool str_eq(const char *s1, const char *s2) {
|
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);
|
return (*s1 == *s2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// --- State ---
|
// --- State ---
|
||||||
static int mx = 400, my = 300;
|
static int mx = 400, my = 300;
|
||||||
static int prev_mx = 400, prev_my = 300;
|
static int prev_mx = 400, prev_my = 300;
|
||||||
|
|
@ -1267,7 +1279,7 @@ void wm_paint(void) {
|
||||||
int sh = get_screen_height();
|
int sh = get_screen_height();
|
||||||
|
|
||||||
uint64_t rflags;
|
uint64_t rflags;
|
||||||
asm volatile("pushfq; pop %0; cli" : "=r"(rflags));
|
rflags = wm_lock_acquire();
|
||||||
|
|
||||||
DirtyRect dirty = graphics_get_dirty_rect();
|
DirtyRect dirty = graphics_get_dirty_rect();
|
||||||
|
|
||||||
|
|
@ -1339,14 +1351,16 @@ void wm_paint(void) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// 3. Windows - sort by z-index and draw
|
// 3. Windows - sort by z-index and draw
|
||||||
|
int local_window_count = window_count;
|
||||||
Window *sorted_windows[32];
|
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];
|
sorted_windows[i] = all_windows[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = 0; i < window_count - 1; i++) {
|
for (int i = 0; i < local_window_count - 1; i++) {
|
||||||
for (int j = 0; j < window_count - i - 1; j++) {
|
for (int j = 0; j < local_window_count - i - 1; j++) {
|
||||||
if (sorted_windows[j]->z_index > sorted_windows[j + 1]->z_index) {
|
if (sorted_windows[j] && sorted_windows[j + 1] &&
|
||||||
|
sorted_windows[j]->z_index > sorted_windows[j + 1]->z_index) {
|
||||||
Window *temp = sorted_windows[j];
|
Window *temp = sorted_windows[j];
|
||||||
sorted_windows[j] = sorted_windows[j + 1];
|
sorted_windows[j] = sorted_windows[j + 1];
|
||||||
sorted_windows[j + 1] = temp;
|
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];
|
Window *win = sorted_windows[i];
|
||||||
if (!win->visible) continue;
|
if (!win || !win->visible) continue;
|
||||||
|
|
||||||
if (dirty.active && !win->focused) {
|
if (dirty.active && !win->focused) {
|
||||||
if (win->x + win->w <= dirty.x || win->x >= dirty.x + dirty.w ||
|
if (win->x + win->w <= dirty.x || win->x >= dirty.x + dirty.w ||
|
||||||
|
|
@ -1516,7 +1530,7 @@ void wm_paint(void) {
|
||||||
graphics_flip_buffer();
|
graphics_flip_buffer();
|
||||||
|
|
||||||
// Restore IRQs
|
// Restore IRQs
|
||||||
asm volatile("push %0; popfq" : : "r"(rflags));
|
wm_lock_release(rflags);
|
||||||
}
|
}
|
||||||
|
|
||||||
// --- Input Handling ---
|
// --- 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;
|
return px >= x && px < x + w && py >= y && py < y + h;
|
||||||
}
|
}
|
||||||
|
|
||||||
void wm_bring_to_front(Window *win) {
|
void wm_bring_to_front_locked(Window *win) {
|
||||||
uint64_t rflags;
|
|
||||||
asm volatile("pushfq; pop %0; cli" : "=r"(rflags));
|
|
||||||
// Clear focus from all windows
|
|
||||||
for (int i = 0; i < window_count; i++) {
|
for (int i = 0; i < window_count; i++) {
|
||||||
all_windows[i]->focused = false;
|
all_windows[i]->focused = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Find current max z-index
|
|
||||||
int max_z = 0;
|
int max_z = 0;
|
||||||
for (int i = 0; i < window_count; i++) {
|
for (int i = 0; i < window_count; i++) {
|
||||||
if (all_windows[i]->z_index > max_z) max_z = all_windows[i]->z_index;
|
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->focused = true;
|
||||||
win->z_index = max_z + 1;
|
win->z_index = max_z + 1;
|
||||||
force_redraw = true;
|
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) {
|
void wm_add_window(Window *win) {
|
||||||
uint64_t rflags;
|
uint64_t rflags;
|
||||||
asm volatile("pushfq; pop %0; cli" : "=r"(rflags));
|
rflags = wm_lock_acquire();
|
||||||
if (window_count < 32) {
|
if (window_count < 32) {
|
||||||
all_windows[window_count++] = win;
|
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) {
|
Window* wm_find_window_by_title(const char *title) {
|
||||||
if (!title) return NULL;
|
if (!title) return NULL;
|
||||||
uint64_t rflags;
|
uint64_t rflags;
|
||||||
asm volatile("pushfq; pop %0; cli" : "=r"(rflags));
|
rflags = wm_lock_acquire();
|
||||||
for (int i = 0; i < window_count; i++) {
|
for (int i = 0; i < window_count; i++) {
|
||||||
if (all_windows[i] && all_windows[i]->title && str_eq(all_windows[i]->title, title)) {
|
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];
|
return all_windows[i];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
asm volatile("push %0; popfq" : : "r"(rflags));
|
wm_lock_release(rflags);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1579,7 +1595,7 @@ void wm_remove_window(Window *win) {
|
||||||
serial_write("'\n");
|
serial_write("'\n");
|
||||||
|
|
||||||
uint64_t rflags;
|
uint64_t rflags;
|
||||||
asm volatile("pushfq; pop %0; cli" : "=r"(rflags));
|
rflags = wm_lock_acquire();
|
||||||
|
|
||||||
int index = -1;
|
int index = -1;
|
||||||
for (int i = 0; i < window_count; i++) {
|
for (int i = 0; i < window_count; i++) {
|
||||||
|
|
@ -1603,7 +1619,7 @@ void wm_remove_window(Window *win) {
|
||||||
// Mark for redraw while protected
|
// Mark for redraw while protected
|
||||||
force_redraw = true;
|
force_redraw = true;
|
||||||
} else {
|
} else {
|
||||||
asm volatile("push %0; popfq" : : "r"(rflags));
|
wm_lock_release(rflags);
|
||||||
serial_write("WM: Window not found in all_windows list!\n");
|
serial_write("WM: Window not found in all_windows list!\n");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -1615,7 +1631,7 @@ void wm_remove_window(Window *win) {
|
||||||
}
|
}
|
||||||
kfree(win);
|
kfree(win);
|
||||||
|
|
||||||
asm volatile("push %0; popfq" : : "r"(rflags));
|
wm_lock_release(rflags);
|
||||||
}
|
}
|
||||||
|
|
||||||
void wm_handle_click(int x, int y) {
|
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);
|
process_create_elf("/bin/about.elf", NULL);
|
||||||
} else if (item == 1) { // Settings
|
} else if (item == 1) { // Settings
|
||||||
Window *existing = wm_find_window_by_title("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 process_create_elf("/bin/settings.elf", NULL);
|
||||||
} else if (item == 2) { // Shutdown
|
} else if (item == 2) { // Shutdown
|
||||||
k_shutdown();
|
k_shutdown();
|
||||||
|
|
@ -1813,7 +1829,7 @@ void wm_handle_click(int x, int y) {
|
||||||
|
|
||||||
// If a window was clicked
|
// If a window was clicked
|
||||||
if (topmost != NULL) {
|
if (topmost != NULL) {
|
||||||
wm_bring_to_front(topmost);
|
wm_bring_to_front_locked(topmost);
|
||||||
|
|
||||||
// Check traffic light close button (now at top-left)
|
// Check traffic light close button (now at top-left)
|
||||||
if (rect_contains(topmost->x + 8, topmost->y + 2, 12, 12, x, y)) {
|
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")) {
|
} else if (str_starts_with(start_menu_pending_app, "Notepad")) {
|
||||||
Window *existing = wm_find_window_by_title("Notepad");
|
Window *existing = wm_find_window_by_title("Notepad");
|
||||||
if (existing) {
|
if (existing) {
|
||||||
wm_bring_to_front(existing);
|
wm_bring_to_front_locked(existing);
|
||||||
} else {
|
} else {
|
||||||
process_create_elf("/bin/notepad.elf", NULL);
|
process_create_elf("/bin/notepad.elf", NULL);
|
||||||
}
|
}
|
||||||
} else if (str_starts_with(start_menu_pending_app, "Editor")) {
|
} else if (str_starts_with(start_menu_pending_app, "Editor")) {
|
||||||
Window *existing = wm_find_window_by_title("Txtedit");
|
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 process_create_elf("/bin/txtedit.elf", NULL);
|
||||||
} else if (str_starts_with(start_menu_pending_app, "Word Processor")) {
|
} else if (str_starts_with(start_menu_pending_app, "Word Processor")) {
|
||||||
Window *existing = wm_find_window_by_title("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 process_create_elf("/bin/boredword.elf", NULL);
|
||||||
} else if (str_starts_with(start_menu_pending_app, "Terminal")) {
|
} 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")) {
|
} else if (str_starts_with(start_menu_pending_app, "Calculator")) {
|
||||||
Window *existing = wm_find_window_by_title("Calculator");
|
Window *existing = wm_find_window_by_title("Calculator");
|
||||||
if (existing) {
|
if (existing) {
|
||||||
wm_bring_to_front(existing);
|
wm_bring_to_front_locked(existing);
|
||||||
} else {
|
} else {
|
||||||
process_create_elf("/bin/calculator.elf", NULL);
|
process_create_elf("/bin/calculator.elf", NULL);
|
||||||
}
|
}
|
||||||
} else if (str_starts_with(start_menu_pending_app, "Minesweeper")) {
|
} else if (str_starts_with(start_menu_pending_app, "Minesweeper")) {
|
||||||
Window *existing = wm_find_window_by_title("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 process_create_elf("/bin/minesweeper.elf", NULL);
|
||||||
} else if (str_starts_with(start_menu_pending_app, "Settings")) {
|
} else if (str_starts_with(start_menu_pending_app, "Settings")) {
|
||||||
Window *existing = wm_find_window_by_title("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 process_create_elf("/bin/settings.elf", NULL);
|
||||||
} else if (str_starts_with(start_menu_pending_app, "Paint")) {
|
} else if (str_starts_with(start_menu_pending_app, "Paint")) {
|
||||||
Window *existing = wm_find_window_by_title("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 process_create_elf("/bin/paint.elf", NULL);
|
||||||
} else if (str_starts_with(start_menu_pending_app, "Clock")) {
|
} else if (str_starts_with(start_menu_pending_app, "Clock")) {
|
||||||
Window *existing = wm_find_window_by_title("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 process_create_elf("/bin/clock.elf", NULL);
|
||||||
} else if (str_starts_with(start_menu_pending_app, "Browser")) {
|
} else if (str_starts_with(start_menu_pending_app, "Browser")) {
|
||||||
Window *existing = wm_find_window_by_title("Web 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 process_create_elf("/bin/browser.elf", NULL);
|
||||||
} else if (str_starts_with(start_menu_pending_app, "About")) {
|
} else if (str_starts_with(start_menu_pending_app, "About")) {
|
||||||
process_create_elf("/bin/about.elf", NULL);
|
process_create_elf("/bin/about.elf", NULL);
|
||||||
} else if (str_starts_with(start_menu_pending_app, "Task Manager")) {
|
} else if (str_starts_with(start_menu_pending_app, "Task Manager")) {
|
||||||
Window *existing = wm_find_window_by_title("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 process_create_elf("/bin/taskman.elf", NULL);
|
||||||
} else if (str_starts_with(start_menu_pending_app, "Shutdown")) {
|
} else if (str_starts_with(start_menu_pending_app, "Shutdown")) {
|
||||||
k_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")) {
|
} else if (str_ends_with(icon->name, "Settings.shortcut")) {
|
||||||
process_create_elf("/bin/settings.elf", NULL); handled = true;
|
process_create_elf("/bin/settings.elf", NULL); handled = true;
|
||||||
} else if (str_ends_with(icon->name, "Terminal.shortcut")) {
|
} 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")) {
|
} else if (str_ends_with(icon->name, "About.shortcut")) {
|
||||||
process_create_elf("/bin/about.elf", NULL); handled = true;
|
process_create_elf("/bin/about.elf", NULL); handled = true;
|
||||||
} else if (str_ends_with(icon->name, "Files.shortcut")) {
|
} else if (str_ends_with(icon->name, "Files.shortcut")) {
|
||||||
|
|
@ -2660,13 +2676,24 @@ void wm_process_input(void) {
|
||||||
}
|
}
|
||||||
|
|
||||||
uint64_t rflags;
|
uint64_t rflags;
|
||||||
asm volatile("pushfq; pop %0; cli" : "=r"(rflags));
|
rflags = wm_lock_acquire();
|
||||||
while (key_head != key_tail) {
|
while (key_head != key_tail) {
|
||||||
key_event_t ev = key_queue[key_tail];
|
key_event_t ev = key_queue[key_tail];
|
||||||
key_tail = (key_tail + 1) % INPUT_QUEUE_SIZE;
|
key_tail = (key_tail + 1) % INPUT_QUEUE_SIZE;
|
||||||
wm_dispatch_key(ev.c, ev.pressed);
|
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) {
|
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();
|
int sw = get_screen_width();
|
||||||
wm_mark_dirty(sw - 280, 40, 275, 60);
|
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) {
|
void wm_notify_fs_change(void) {
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,9 @@
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
uint64_t wm_lock_acquire(void);
|
||||||
|
void wm_lock_release(uint64_t flags);
|
||||||
|
|
||||||
// --- Constants ---
|
// --- Constants ---
|
||||||
#define COLOR_TEAL 0xFF008080
|
#define COLOR_TEAL 0xFF008080
|
||||||
#define COLOR_GRAY 0xFFC0C0C0
|
#define COLOR_GRAY 0xFFC0C0C0
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue