mirror of
https://github.com/BoredDevNL/BoredOS.git
synced 2026-05-15 10:48:38 +00:00
task manager and major memory stability fixes
This commit is contained in:
parent
1639b09cb5
commit
6a41be2437
31 changed files with 567 additions and 50 deletions
BIN
boredos.iso
BIN
boredos.iso
Binary file not shown.
BIN
build/cmd.o
BIN
build/cmd.o
Binary file not shown.
BIN
build/explorer.o
BIN
build/explorer.o
Binary file not shown.
BIN
build/idt.o
BIN
build/idt.o
Binary file not shown.
BIN
build/main.o
BIN
build/main.o
Binary file not shown.
BIN
build/platform.o
BIN
build/platform.o
Binary file not shown.
BIN
build/ps2.o
BIN
build/ps2.o
Binary file not shown.
|
|
@ -51,3 +51,21 @@ uint64_t v2p(uint64_t virt) {
|
||||||
}
|
}
|
||||||
return virt;
|
return virt;
|
||||||
}
|
}
|
||||||
|
void platform_get_cpu_model(char *model) {
|
||||||
|
uint32_t brand[12];
|
||||||
|
uint32_t eax, ebx, ecx, edx;
|
||||||
|
|
||||||
|
for (uint32_t i = 0; i < 3; i++) {
|
||||||
|
asm volatile("cpuid" : "=a"(eax), "=b"(ebx), "=c"(ecx), "=d"(edx) : "a"(0x80000002 + i));
|
||||||
|
brand[i * 4 + 0] = eax;
|
||||||
|
brand[i * 4 + 1] = ebx;
|
||||||
|
brand[i * 4 + 2] = ecx;
|
||||||
|
brand[i * 4 + 3] = edx;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *p = (char *)brand;
|
||||||
|
for (int i = 0; i < 48; i++) {
|
||||||
|
model[i] = p[i];
|
||||||
|
}
|
||||||
|
model[48] = '\0';
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -9,5 +9,6 @@
|
||||||
void platform_init(void);
|
void platform_init(void);
|
||||||
uint64_t p2v(uint64_t phys);
|
uint64_t p2v(uint64_t phys);
|
||||||
uint64_t v2p(uint64_t virt);
|
uint64_t v2p(uint64_t virt);
|
||||||
|
void platform_get_cpu_model(char *model);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -15,12 +15,16 @@ extern void cmd_write(const char *str);
|
||||||
extern void serial_write(const char *str);
|
extern void serial_write(const char *str);
|
||||||
|
|
||||||
#define MAX_PROCESSES 16
|
#define MAX_PROCESSES 16
|
||||||
static process_t processes[MAX_PROCESSES] __attribute__((aligned(16)));
|
process_t processes[MAX_PROCESSES] __attribute__((aligned(16)));
|
||||||
static int process_count = 0;
|
int process_count = 0;
|
||||||
static process_t* current_process = NULL;
|
static process_t* current_process = NULL;
|
||||||
static uint32_t next_pid = 0;
|
static uint32_t next_pid = 0;
|
||||||
|
|
||||||
void process_init(void) {
|
void process_init(void) {
|
||||||
|
for (int i = 0; i < MAX_PROCESSES; i++) {
|
||||||
|
processes[i].pid = 0xFFFFFFFF;
|
||||||
|
}
|
||||||
|
|
||||||
// Current kernel execution is PID 0
|
// Current kernel execution is PID 0
|
||||||
process_t *kernel_proc = &processes[process_count++];
|
process_t *kernel_proc = &processes[process_count++];
|
||||||
kernel_proc->pid = next_pid++;
|
kernel_proc->pid = next_pid++;
|
||||||
|
|
@ -36,6 +40,10 @@ void process_init(void) {
|
||||||
|
|
||||||
for (int i = 0; i < MAX_PROCESS_FDS; i++) kernel_proc->fds[i] = NULL;
|
for (int i = 0; i < MAX_PROCESS_FDS; i++) kernel_proc->fds[i] = NULL;
|
||||||
|
|
||||||
|
extern void mem_memcpy(void *dest, const void *src, size_t len);
|
||||||
|
mem_memcpy(kernel_proc->name, "kernel", 7);
|
||||||
|
kernel_proc->ticks = 0;
|
||||||
|
|
||||||
kernel_proc->next = kernel_proc; // Circular linked list
|
kernel_proc->next = kernel_proc; // Circular linked list
|
||||||
current_process = kernel_proc;
|
current_process = kernel_proc;
|
||||||
}
|
}
|
||||||
|
|
@ -121,9 +129,12 @@ void process_create(void* entry_point, bool is_user) {
|
||||||
asm volatile("fninit");
|
asm volatile("fninit");
|
||||||
new_proc->fpu_initialized = true;
|
new_proc->fpu_initialized = true;
|
||||||
|
|
||||||
// Add to linked list
|
// Add to linked list (Critical Section)
|
||||||
|
uint64_t rflags;
|
||||||
|
asm volatile("pushfq; pop %0; cli" : "=r"(rflags));
|
||||||
new_proc->next = current_process->next;
|
new_proc->next = current_process->next;
|
||||||
current_process->next = new_proc;
|
current_process->next = new_proc;
|
||||||
|
asm volatile("push %0; popfq" : : "r"(rflags));
|
||||||
}
|
}
|
||||||
|
|
||||||
process_t* process_create_elf(const char* filepath, const char* args_str) {
|
process_t* process_create_elf(const char* filepath, const char* args_str) {
|
||||||
|
|
@ -165,11 +176,23 @@ process_t* process_create_elf(const char* filepath, const char* args_str) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Set process name from filepath
|
||||||
|
int last_slash = -1;
|
||||||
|
for (int i = 0; filepath[i]; i++) if (filepath[i] == '/') last_slash = i;
|
||||||
|
const char *filename = (last_slash == -1) ? filepath : (filepath + last_slash + 1);
|
||||||
|
int ni = 0;
|
||||||
|
while (filename[ni] && ni < 63) {
|
||||||
|
new_proc->name[ni] = filename[ni];
|
||||||
|
ni++;
|
||||||
|
}
|
||||||
|
new_proc->name[ni] = 0;
|
||||||
|
new_proc->ticks = 0;
|
||||||
|
|
||||||
// 3. Allocate generic User stack and Kernel stack for interrupts
|
// 3. Allocate generic User stack and Kernel stack for interrupts
|
||||||
// Increase to 256KB to prevent stack smashing on heavy networking
|
// Increase to 256KB to prevent stack smashing on heavy networking
|
||||||
size_t user_stack_size = 262144;
|
size_t user_stack_size = 262144;
|
||||||
void* stack = kmalloc_aligned(user_stack_size, 4096);
|
void* stack = kmalloc_aligned(user_stack_size, 4096);
|
||||||
void* kernel_stack = kmalloc_aligned(32768, 32768);
|
void* kernel_stack = kmalloc_aligned(65536, 65536);
|
||||||
|
|
||||||
// Map User stack to 0x800000
|
// Map User stack to 0x800000
|
||||||
for (uint64_t i = 0; i < (user_stack_size / 4096); i++) {
|
for (uint64_t i = 0; i < (user_stack_size / 4096); i++) {
|
||||||
|
|
@ -248,7 +271,7 @@ process_t* process_create_elf(const char* filepath, const char* args_str) {
|
||||||
current_user_sp &= ~15ULL;
|
current_user_sp &= ~15ULL;
|
||||||
|
|
||||||
// 4. Build Stack Frame for context switch via IRETQ
|
// 4. Build Stack Frame for context switch via IRETQ
|
||||||
uint64_t* stack_ptr = (uint64_t*)((uint64_t)kernel_stack + 32768);
|
uint64_t* stack_ptr = (uint64_t*)((uint64_t)kernel_stack + 65536);
|
||||||
*(--stack_ptr) = 0x1B; // SS (User Mode Data)
|
*(--stack_ptr) = 0x1B; // SS (User Mode Data)
|
||||||
*(--stack_ptr) = current_user_sp; // RSP (Updated user stack pointer)
|
*(--stack_ptr) = current_user_sp; // RSP (Updated user stack pointer)
|
||||||
*(--stack_ptr) = 0x202; // RFLAGS (Interrupts Enabled)
|
*(--stack_ptr) = 0x202; // RFLAGS (Interrupts Enabled)
|
||||||
|
|
@ -279,7 +302,7 @@ process_t* process_create_elf(const char* filepath, const char* args_str) {
|
||||||
asm volatile("fninit");
|
asm volatile("fninit");
|
||||||
asm volatile("fxsave %0" : "=m"(*stack_ptr));
|
asm volatile("fxsave %0" : "=m"(*stack_ptr));
|
||||||
|
|
||||||
new_proc->kernel_stack = (uint64_t)kernel_stack + 32768;
|
new_proc->kernel_stack = (uint64_t)kernel_stack + 65536;
|
||||||
new_proc->kernel_stack_alloc = kernel_stack;
|
new_proc->kernel_stack_alloc = kernel_stack;
|
||||||
new_proc->user_stack_alloc = stack;
|
new_proc->user_stack_alloc = stack;
|
||||||
new_proc->rsp = (uint64_t)stack_ptr;
|
new_proc->rsp = (uint64_t)stack_ptr;
|
||||||
|
|
@ -288,11 +311,12 @@ process_t* process_create_elf(const char* filepath, const char* args_str) {
|
||||||
asm volatile("fninit");
|
asm volatile("fninit");
|
||||||
new_proc->fpu_initialized = true;
|
new_proc->fpu_initialized = true;
|
||||||
|
|
||||||
// Slot is already counted in process_count if new, or reused.
|
// Add to linked list (Critical Section)
|
||||||
|
uint64_t rflags;
|
||||||
// Add to linked list
|
asm volatile("pushfq; pop %0; cli" : "=r"(rflags));
|
||||||
new_proc->next = current_process->next;
|
new_proc->next = current_process->next;
|
||||||
current_process->next = new_proc;
|
current_process->next = new_proc;
|
||||||
|
asm volatile("push %0; popfq" : : "r"(rflags));
|
||||||
|
|
||||||
serial_write("[PROCESS] Spawned ELF Executable: ");
|
serial_write("[PROCESS] Spawned ELF Executable: ");
|
||||||
serial_write(filepath);
|
serial_write(filepath);
|
||||||
|
|
@ -308,13 +332,24 @@ uint64_t process_schedule(uint64_t current_rsp) {
|
||||||
if (!current_process || !current_process->next || current_process == current_process->next)
|
if (!current_process || !current_process->next || current_process == current_process->next)
|
||||||
return current_rsp;
|
return current_rsp;
|
||||||
|
|
||||||
// serial_write("SCHED\n");
|
// Save context
|
||||||
|
|
||||||
// Save/Restore context
|
|
||||||
current_process->rsp = current_rsp;
|
current_process->rsp = current_rsp;
|
||||||
|
|
||||||
// Switch process
|
// Switch to next ready process
|
||||||
current_process = current_process->next;
|
extern uint32_t wm_get_ticks(void);
|
||||||
|
uint32_t now = wm_get_ticks();
|
||||||
|
|
||||||
|
process_t *start = current_process;
|
||||||
|
process_t *next_proc = current_process->next;
|
||||||
|
|
||||||
|
while (next_proc != start) {
|
||||||
|
if (next_proc->pid == 0 || next_proc->sleep_until == 0 || next_proc->sleep_until <= now) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
next_proc = next_proc->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
current_process = next_proc;
|
||||||
|
|
||||||
// Update Kernel Stack for User Mode interrupts and System Calls
|
// Update Kernel Stack for User Mode interrupts and System Calls
|
||||||
if (current_process->is_user && current_process->kernel_stack) {
|
if (current_process->is_user && current_process->kernel_stack) {
|
||||||
|
|
@ -326,9 +361,18 @@ uint64_t process_schedule(uint64_t current_rsp) {
|
||||||
// Switch page table
|
// Switch page table
|
||||||
paging_switch_directory(current_process->pml4_phys);
|
paging_switch_directory(current_process->pml4_phys);
|
||||||
|
|
||||||
|
current_process->ticks++;
|
||||||
|
|
||||||
return current_process->rsp;
|
return current_process->rsp;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
process_t* process_get_by_pid(uint32_t pid) {
|
||||||
|
for (int i = 0; i < MAX_PROCESSES; i++) {
|
||||||
|
if (processes[i].pid == pid) return &processes[i];
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
static void process_cleanup_inner(process_t *proc) {
|
static void process_cleanup_inner(process_t *proc) {
|
||||||
if (!proc || proc->pid == 0xFFFFFFFF) return;
|
if (!proc || proc->pid == 0xFFFFFFFF) return;
|
||||||
|
|
||||||
|
|
@ -356,7 +400,7 @@ static void process_cleanup_inner(process_t *proc) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void process_terminate(process_t *to_delete) {
|
void process_terminate(process_t *to_delete) {
|
||||||
if (!to_delete || to_delete->pid == 0xFFFFFFFF) return;
|
if (!to_delete || to_delete->pid == 0xFFFFFFFF || to_delete->pid == 0) return;
|
||||||
|
|
||||||
uint64_t rflags;
|
uint64_t rflags;
|
||||||
asm volatile("pushfq; pop %0; cli" : "=r"(rflags));
|
asm volatile("pushfq; pop %0; cli" : "=r"(rflags));
|
||||||
|
|
@ -389,6 +433,7 @@ void process_terminate(process_t *to_delete) {
|
||||||
to_delete->pid = 0xFFFFFFFF;
|
to_delete->pid = 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) kfree(to_delete->kernel_stack_alloc);
|
||||||
to_delete->user_stack_alloc = NULL;
|
to_delete->user_stack_alloc = NULL;
|
||||||
to_delete->kernel_stack_alloc = NULL;
|
to_delete->kernel_stack_alloc = NULL;
|
||||||
|
|
||||||
|
|
@ -399,7 +444,7 @@ uint64_t process_terminate_current(void) {
|
||||||
uint64_t rflags;
|
uint64_t rflags;
|
||||||
asm volatile("pushfq; pop %0; cli" : "=r"(rflags));
|
asm volatile("pushfq; pop %0; cli" : "=r"(rflags));
|
||||||
|
|
||||||
if (!current_process) {
|
if (!current_process || current_process->pid == 0) {
|
||||||
asm volatile("push %0; popfq" : : "r"(rflags));
|
asm volatile("push %0; popfq" : : "r"(rflags));
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,7 @@
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
|
#include <stddef.h>
|
||||||
#include "gui_ipc.h"
|
#include "gui_ipc.h"
|
||||||
|
|
||||||
#define MAX_GUI_EVENTS 32
|
#define MAX_GUI_EVENTS 32
|
||||||
|
|
@ -13,9 +14,8 @@
|
||||||
|
|
||||||
struct FAT32_FileHandle;
|
struct FAT32_FileHandle;
|
||||||
|
|
||||||
// Registers saved on the stack by interrupts/exceptions
|
|
||||||
typedef struct registers_t {
|
typedef struct registers_t {
|
||||||
uint8_t fxsave_region[512]; // SSE/FPU state, MUST be at the bottom (lowest address)
|
uint8_t fxsave_region[512];
|
||||||
uint64_t r15, r14, r13, r12, r11, r10, r9, r8;
|
uint64_t r15, r14, r13, r12, r11, r10, r9, r8;
|
||||||
uint64_t rbp, rdi, rsi, rdx, rcx, rbx, rax;
|
uint64_t rbp, rdi, rsi, rdx, rcx, rbx, rax;
|
||||||
uint64_t int_no, err_code;
|
uint64_t int_no, err_code;
|
||||||
|
|
@ -24,31 +24,42 @@ typedef struct registers_t {
|
||||||
|
|
||||||
typedef struct process {
|
typedef struct process {
|
||||||
uint32_t pid;
|
uint32_t pid;
|
||||||
uint64_t rsp; // Current stack pointer representing context
|
uint64_t rsp;
|
||||||
uint64_t pml4_phys; // Physical address of the page table
|
uint64_t pml4_phys;
|
||||||
uint64_t kernel_stack; // Ring 0 stack pointer for user mode switches
|
uint64_t kernel_stack;
|
||||||
bool is_user;
|
bool is_user;
|
||||||
|
|
||||||
gui_event_t gui_events[MAX_GUI_EVENTS];
|
gui_event_t gui_events[MAX_GUI_EVENTS];
|
||||||
int gui_event_head;
|
int gui_event_head;
|
||||||
int gui_event_tail;
|
int gui_event_tail;
|
||||||
void *ui_window; // Pointer to the active Window
|
void *ui_window;
|
||||||
|
|
||||||
uint64_t heap_start;
|
uint64_t heap_start;
|
||||||
uint64_t heap_end;
|
uint64_t heap_end;
|
||||||
|
|
||||||
void *fds[MAX_PROCESS_FDS];
|
void *fds[MAX_PROCESS_FDS];
|
||||||
|
|
||||||
void *kernel_stack_alloc; // Original pointer from kmalloc for freeing
|
void *kernel_stack_alloc;
|
||||||
void *user_stack_alloc; // Original pointer from kmalloc for freeing
|
void *user_stack_alloc;
|
||||||
|
|
||||||
bool is_terminal_proc;
|
bool is_terminal_proc;
|
||||||
|
|
||||||
struct process *next;
|
struct process *next;
|
||||||
|
|
||||||
bool fpu_initialized;
|
bool fpu_initialized;
|
||||||
|
|
||||||
|
char name[64];
|
||||||
|
uint64_t ticks;
|
||||||
|
uint64_t sleep_until;
|
||||||
} __attribute__((aligned(16))) process_t;
|
} __attribute__((aligned(16))) process_t;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint32_t pid;
|
||||||
|
char name[64];
|
||||||
|
uint64_t ticks;
|
||||||
|
size_t used_memory;
|
||||||
|
} ProcessInfo;
|
||||||
|
|
||||||
void process_init(void);
|
void process_init(void);
|
||||||
void process_create(void* entry_point, bool is_user);
|
void process_create(void* entry_point, 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);
|
||||||
|
|
@ -56,6 +67,7 @@ process_t* process_get_current(void);
|
||||||
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);
|
||||||
|
process_t* process_get_by_pid(uint32_t pid);
|
||||||
|
|
||||||
void process_push_gui_event(process_t *proc, gui_event_t *ev);
|
void process_push_gui_event(process_t *proc, gui_event_t *ev);
|
||||||
process_t* process_get_by_ui_window(void* win);
|
process_t* process_get_by_ui_window(void* win);
|
||||||
|
|
|
||||||
|
|
@ -14,11 +14,11 @@ extern void serial_print_hex(uint64_t n);
|
||||||
volatile uint64_t kernel_ticks = 0;
|
volatile uint64_t kernel_ticks = 0;
|
||||||
|
|
||||||
uint64_t timer_handler(registers_t *regs) {
|
uint64_t timer_handler(registers_t *regs) {
|
||||||
outb(0x20, 0x20); // EOI as fast as possible
|
|
||||||
kernel_ticks++;
|
kernel_ticks++;
|
||||||
wm_timer_tick();
|
wm_timer_tick();
|
||||||
network_process_frames();
|
network_process_frames();
|
||||||
|
|
||||||
|
outb(0x20, 0x20); // EOI after processing to prevent nested timer interrupts
|
||||||
extern uint64_t process_schedule(uint64_t current_rsp);
|
extern uint64_t process_schedule(uint64_t current_rsp);
|
||||||
return process_schedule((uint64_t)regs);
|
return process_schedule((uint64_t)regs);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -811,6 +811,7 @@ static uint64_t syscall_handler_inner(registers_t *regs) {
|
||||||
return old_end;
|
return old_end;
|
||||||
} else if (syscall_num == 5) { // SYS_SYSTEM
|
} else if (syscall_num == 5) { // SYS_SYSTEM
|
||||||
int cmd = (int)arg1;
|
int cmd = (int)arg1;
|
||||||
|
process_t *proc = process_get_current();
|
||||||
if (cmd == 1) { // SYSTEM_CMD_SET_BG_COLOR
|
if (cmd == 1) { // SYSTEM_CMD_SET_BG_COLOR
|
||||||
uint32_t color = (uint32_t)arg2;
|
uint32_t color = (uint32_t)arg2;
|
||||||
extern void graphics_set_bg_color(uint32_t color);
|
extern void graphics_set_bg_color(uint32_t color);
|
||||||
|
|
@ -1068,6 +1069,51 @@ static uint64_t syscall_handler_inner(registers_t *regs) {
|
||||||
size_t max_len = (size_t)arg3;
|
size_t max_len = (size_t)arg3;
|
||||||
extern int network_tcp_recv_nb(void *buf, size_t max_len);
|
extern int network_tcp_recv_nb(void *buf, size_t max_len);
|
||||||
return (uint64_t)network_tcp_recv_nb(buf, max_len);
|
return (uint64_t)network_tcp_recv_nb(buf, max_len);
|
||||||
|
} else if (cmd == SYSTEM_CMD_PROCESS_LIST) {
|
||||||
|
ProcessInfo *out = (ProcessInfo *)arg2;
|
||||||
|
int max_procs = (int)arg3;
|
||||||
|
if (!out) return 0;
|
||||||
|
|
||||||
|
extern process_t processes[];
|
||||||
|
extern int process_count;
|
||||||
|
int count = 0;
|
||||||
|
for (int i = 0; i < 16; i++) { // MAX_PROCESSES is 16
|
||||||
|
if (processes[i].pid != 0xFFFFFFFF) {
|
||||||
|
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;
|
||||||
|
|
||||||
|
// Memory estimation: heap + stacks
|
||||||
|
size_t mem = 0;
|
||||||
|
if (processes[i].heap_end > processes[i].heap_start)
|
||||||
|
mem += (processes[i].heap_end - processes[i].heap_start);
|
||||||
|
|
||||||
|
if (processes[i].pid == 0) {
|
||||||
|
// For kernel, we can report a more realistic figure if we want,
|
||||||
|
// but 32KB is specifically its stack. Let's keep it but maybe
|
||||||
|
// add a note in documentation.
|
||||||
|
mem = 32768;
|
||||||
|
} else {
|
||||||
|
if (processes[i].is_user) mem += 262144; // User stack
|
||||||
|
mem += 32768; // Kernel stack
|
||||||
|
}
|
||||||
|
|
||||||
|
out[count].used_memory = mem;
|
||||||
|
|
||||||
|
count++;
|
||||||
|
if (count >= max_procs) break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return (uint64_t)count;
|
||||||
|
} else if (cmd == SYSTEM_CMD_GET_CPU_MODEL) {
|
||||||
|
char *user_buf = (char *)arg2;
|
||||||
|
if (!user_buf) return -1;
|
||||||
|
char model[64];
|
||||||
|
platform_get_cpu_model(model);
|
||||||
|
extern void mem_memcpy(void *dest, const void *src, size_t len);
|
||||||
|
mem_memcpy(user_buf, model, 49);
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
@ -1079,16 +1125,47 @@ uint64_t syscall_handler_c(registers_t *regs) {
|
||||||
uint64_t syscall_num = regs->rax;
|
uint64_t syscall_num = regs->rax;
|
||||||
|
|
||||||
// Check for context-switching syscalls
|
// Check for context-switching syscalls
|
||||||
if (syscall_num == 0 || syscall_num == 60 || syscall_num == 10) { // EXIT or KILL
|
if (syscall_num == 0 || syscall_num == 60) { // EXIT
|
||||||
return process_terminate_current();
|
return process_terminate_current();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (syscall_num == 10) { // KILL
|
||||||
|
uint32_t target_pid = (uint32_t)regs->rdi;
|
||||||
|
process_t *current = process_get_current();
|
||||||
|
if (target_pid == 0) {
|
||||||
|
// Protect kernel process
|
||||||
|
regs->rax = -1;
|
||||||
|
return (uint64_t)regs;
|
||||||
|
}
|
||||||
|
if (target_pid == 0xFFFFFFFF || target_pid == current->pid) {
|
||||||
|
return process_terminate_current();
|
||||||
|
} else {
|
||||||
|
process_t *target = process_get_by_pid(target_pid);
|
||||||
|
if (target) {
|
||||||
|
process_terminate(target);
|
||||||
|
}
|
||||||
|
regs->rax = 0;
|
||||||
|
return (uint64_t)regs;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (syscall_num == 5 && regs->rdi == 43) { // SYSTEM_CMD_YIELD
|
if (syscall_num == 5 && regs->rdi == 43) { // SYSTEM_CMD_YIELD
|
||||||
extern uint64_t process_schedule(uint64_t current_rsp);
|
extern uint64_t process_schedule(uint64_t current_rsp);
|
||||||
regs->rax = 0;
|
regs->rax = 0;
|
||||||
return process_schedule((uint64_t)regs);
|
return process_schedule((uint64_t)regs);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (syscall_num == 5 && regs->rdi == 46) { // SYSTEM_CMD_SLEEP
|
||||||
|
uint32_t ms = (uint32_t)regs->rsi;
|
||||||
|
process_t *proc = process_get_current();
|
||||||
|
extern uint32_t wm_get_ticks(void);
|
||||||
|
uint32_t ticks = ms / 16;
|
||||||
|
if (ticks == 0 && ms > 0) ticks = 1;
|
||||||
|
proc->sleep_until = wm_get_ticks() + ticks;
|
||||||
|
regs->rax = 0;
|
||||||
|
return process_schedule((uint64_t)regs);
|
||||||
|
}
|
||||||
|
|
||||||
// Normal syscalls
|
// Normal syscalls
|
||||||
regs->rax = syscall_handler_inner(regs);
|
regs->rax = syscall_handler_inner(regs);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -39,6 +39,13 @@ typedef struct registers_t registers_t;
|
||||||
#define FS_CMD_CHDIR 13
|
#define FS_CMD_CHDIR 13
|
||||||
#define FS_CMD_GET_INFO 14
|
#define FS_CMD_GET_INFO 14
|
||||||
|
|
||||||
|
#define SYSTEM_CMD_SET_RAW_MODE 41
|
||||||
|
#define SYSTEM_CMD_TCP_RECV_NB 42
|
||||||
|
#define SYSTEM_CMD_YIELD 43
|
||||||
|
#define SYSTEM_CMD_PROCESS_LIST 44
|
||||||
|
#define SYSTEM_CMD_GET_CPU_MODEL 45
|
||||||
|
#define SYSTEM_CMD_SLEEP 46
|
||||||
|
|
||||||
void syscall_init(void);
|
void syscall_init(void);
|
||||||
uint64_t syscall_handler_c(registers_t *regs);
|
uint64_t syscall_handler_c(registers_t *regs);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,9 @@ section .text
|
||||||
; R9 = arg5
|
; R9 = arg5
|
||||||
|
|
||||||
syscall_entry:
|
syscall_entry:
|
||||||
; 1. Switch to Kernel Stack
|
; 1. Switch to Kernel Stack safely
|
||||||
|
; Note: For true SMP safety, we need per-CPU storage (via swapgs).
|
||||||
|
; For now, we use a global scratch which is only safe because we mask interrupts on entry.
|
||||||
mov [rel user_rsp_scratch], rsp
|
mov [rel user_rsp_scratch], rsp
|
||||||
mov rsp, [rel kernel_syscall_stack]
|
mov rsp, [rel kernel_syscall_stack]
|
||||||
|
|
||||||
|
|
@ -52,9 +54,7 @@ syscall_entry:
|
||||||
|
|
||||||
; 4. Call C handler with registers_t*
|
; 4. Call C handler with registers_t*
|
||||||
mov rdi, rsp
|
mov rdi, rsp
|
||||||
sti
|
|
||||||
call syscall_handler_c
|
call syscall_handler_c
|
||||||
cli
|
|
||||||
|
|
||||||
; 5. Switch to the resulting RSP (might be different if task switched)
|
; 5. Switch to the resulting RSP (might be different if task switched)
|
||||||
mov rsp, rax
|
mov rsp, rax
|
||||||
|
|
@ -80,6 +80,11 @@ syscall_entry:
|
||||||
pop rbx
|
pop rbx
|
||||||
pop rax
|
pop rax
|
||||||
add rsp, 16 ; drop int_no/err_code
|
add rsp, 16 ; drop int_no/err_code
|
||||||
|
|
||||||
|
; Debug: check RIP before iretq
|
||||||
|
; We can't easily print from here without destroying registers,
|
||||||
|
; but we can at least check if it's canonical.
|
||||||
|
|
||||||
iretq
|
iretq
|
||||||
|
|
||||||
section .bss
|
section .bss
|
||||||
|
|
|
||||||
|
|
@ -2,8 +2,9 @@
|
||||||
// This software is released under the GNU General Public License v3.0. See LICENSE file for details.
|
// This software is released under the GNU General Public License v3.0. See LICENSE file for details.
|
||||||
// This header needs to maintain in any file it is present in, as per the GPL license terms.
|
// This header needs to maintain in any file it is present in, as per the GPL license terms.
|
||||||
#include "syscall.h"
|
#include "syscall.h"
|
||||||
#include "libui.h"
|
#include "libc/libui.h"
|
||||||
#include <stddef.h>
|
#include "libc/stdlib.h"
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
static uint32_t ansi_to_boredos_color(int code) {
|
static uint32_t ansi_to_boredos_color(int code) {
|
||||||
uint32_t default_color = 0xFFFFFFFF;
|
uint32_t default_color = 0xFFFFFFFF;
|
||||||
|
|
@ -121,7 +122,7 @@ int main(void) {
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Avoid high CPU usage
|
// Avoid high CPU usage
|
||||||
for(volatile int i=0; i<10000; i++);
|
sleep(10);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,7 @@
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stdlib.h>
|
#include "libc/stdlib.h"
|
||||||
|
|
||||||
static int win_w = 1280;
|
static int win_w = 1280;
|
||||||
static int win_h = 960;
|
static int win_h = 960;
|
||||||
|
|
@ -1734,9 +1734,9 @@ int main(int argc, char **argv) {
|
||||||
}
|
}
|
||||||
if (gif_updated) {
|
if (gif_updated) {
|
||||||
browser_paint(); ui_mark_dirty(win_browser, 0, 0, win_w, win_h);
|
browser_paint(); ui_mark_dirty(win_browser, 0, 0, win_w, win_h);
|
||||||
|
} else {
|
||||||
|
sleep(10);
|
||||||
}
|
}
|
||||||
|
|
||||||
for(volatile int x=0; x<10000; x++);
|
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
@ -4,6 +4,7 @@
|
||||||
#include "syscall.h"
|
#include "syscall.h"
|
||||||
#include "libui.h"
|
#include "libui.h"
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
|
#include "stdlib.h"
|
||||||
|
|
||||||
#define SCALE 1000000LL
|
#define SCALE 1000000LL
|
||||||
|
|
||||||
|
|
@ -254,8 +255,7 @@ int main(void) {
|
||||||
sys_exit(0);
|
sys_exit(0);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Avoid high CPU usage
|
sleep(10);
|
||||||
for(volatile int i=0; i<10000; i++);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -256,7 +256,7 @@ int main(void) {
|
||||||
} else {
|
} else {
|
||||||
long long now = sys_system(16, 0, 0, 0, 0);
|
long long now = sys_system(16, 0, 0, 0, 0);
|
||||||
if (now - last_rep >= 6) { clock_paint(); ui_mark_dirty(win_clock, 0, 0, WIN_W, WIN_H); last_rep = now; }
|
if (now - last_rep >= 6) { clock_paint(); ui_mark_dirty(win_clock, 0, 0, WIN_W, WIN_H); last_rep = now; }
|
||||||
for(volatile int i=0; i<5000; i++);
|
sleep(10);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
||||||
|
|
@ -292,8 +292,7 @@ char* getcwd(char *buf, int size) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void sleep(int ms) {
|
void sleep(int ms) {
|
||||||
|
sys_system(46, ms, 0, 0, 0);
|
||||||
(void)ms;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void exit(int status) {
|
void exit(int status) {
|
||||||
|
|
|
||||||
|
|
@ -68,6 +68,9 @@
|
||||||
#define SYSTEM_CMD_DNS_LOOKUP 37
|
#define SYSTEM_CMD_DNS_LOOKUP 37
|
||||||
#define SYSTEM_CMD_SET_DNS 38
|
#define SYSTEM_CMD_SET_DNS 38
|
||||||
#define SYSTEM_CMD_NET_UNLOCK 39
|
#define SYSTEM_CMD_NET_UNLOCK 39
|
||||||
|
#define SYSTEM_CMD_PROCESS_LIST 44
|
||||||
|
#define SYSTEM_CMD_GET_CPU_MODEL 45
|
||||||
|
#define SYSTEM_CMD_SLEEP 46
|
||||||
#define SYSTEM_CMD_SET_RAW_MODE 41
|
#define SYSTEM_CMD_SET_RAW_MODE 41
|
||||||
#define SYSTEM_CMD_TCP_RECV_NB 42
|
#define SYSTEM_CMD_TCP_RECV_NB 42
|
||||||
#define SYSTEM_CMD_YIELD 43
|
#define SYSTEM_CMD_YIELD 43
|
||||||
|
|
@ -113,6 +116,13 @@ typedef struct {
|
||||||
int sys_list(const char *path, FAT32_FileInfo *entries, int max_entries);
|
int sys_list(const char *path, FAT32_FileInfo *entries, int max_entries);
|
||||||
int sys_get_file_info(const char *path, FAT32_FileInfo *info);
|
int sys_get_file_info(const char *path, FAT32_FileInfo *info);
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint32_t pid;
|
||||||
|
char name[64];
|
||||||
|
uint64_t ticks;
|
||||||
|
size_t used_memory;
|
||||||
|
} ProcessInfo;
|
||||||
|
|
||||||
// Network API
|
// Network API
|
||||||
typedef struct { uint8_t bytes[6]; } net_mac_address_t;
|
typedef struct { uint8_t bytes[6]; } net_mac_address_t;
|
||||||
typedef struct { uint8_t bytes[4]; } net_ipv4_address_t;
|
typedef struct { uint8_t bytes[4]; } net_ipv4_address_t;
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@
|
||||||
// This header needs to maintain in any file it is present in, as per the GPL license terms.
|
// This header needs to maintain in any file it is present in, as per the GPL license terms.
|
||||||
#include "libc/syscall.h"
|
#include "libc/syscall.h"
|
||||||
#include "libc/libui.h"
|
#include "libc/libui.h"
|
||||||
|
#include "libc/stdlib.h"
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
@ -441,6 +442,8 @@ int main(int argc, char **argv) {
|
||||||
} else if (ev.type == GUI_EVENT_CLOSE) {
|
} else if (ev.type == GUI_EVENT_CLOSE) {
|
||||||
sys_exit(0);
|
sys_exit(0);
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
sleep(10);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,7 @@
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
#include "libc/stdlib.h"
|
||||||
|
|
||||||
#define COLOR_DARK_BG 0xFF121212
|
#define COLOR_DARK_BG 0xFF121212
|
||||||
#define COLOR_DARK_PANEL 0xFF202020
|
#define COLOR_DARK_PANEL 0xFF202020
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@
|
||||||
// This header needs to maintain in any file it is present in, as per the GPL license terms.
|
// This header needs to maintain in any file it is present in, as per the GPL license terms.
|
||||||
#include "libc/syscall.h"
|
#include "libc/syscall.h"
|
||||||
#include "libc/libui.h"
|
#include "libc/libui.h"
|
||||||
|
#include "libc/stdlib.h"
|
||||||
#include "libc/syscall_user.h"
|
#include "libc/syscall_user.h"
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
|
|
||||||
|
|
@ -257,8 +258,7 @@ int main(int argc, char **argv) {
|
||||||
sys_exit(0);
|
sys_exit(0);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
sleep(10);
|
||||||
for(volatile int i=0; i<10000; i++);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -247,6 +247,8 @@ int main(int argc, char **argv) {
|
||||||
} else if (ev.type == GUI_EVENT_CLOSE) {
|
} else if (ev.type == GUI_EVENT_CLOSE) {
|
||||||
sys_exit(0);
|
sys_exit(0);
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
sleep(10);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
||||||
|
|
@ -825,6 +825,8 @@ int main(int argc, char **argv) {
|
||||||
} else if (ev.type == GUI_EVENT_CLOSE) {
|
} else if (ev.type == GUI_EVENT_CLOSE) {
|
||||||
sys_exit(0);
|
sys_exit(0);
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
sleep(10);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
||||||
|
|
@ -138,8 +138,7 @@ int main(void) {
|
||||||
goto exit_app;
|
goto exit_app;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// No explicit sleep, rendering takes some time and provides natural visual delay.
|
sleep(2);
|
||||||
// If it's too fast, we'll add sleep(1) here later.
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -168,13 +167,14 @@ int main(void) {
|
||||||
goto exit_app;
|
goto exit_app;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
sleep(2);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
start = start + 1;
|
start = start + 1;
|
||||||
} else {
|
} else {
|
||||||
// Sort is done, just render and idle
|
// Sort is done, just render and idle
|
||||||
render_state(win);
|
render_state(win);
|
||||||
sleep(50);
|
sleep(200);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
306
src/kernel/userland/taskman.c
Normal file
306
src/kernel/userland/taskman.c
Normal file
|
|
@ -0,0 +1,306 @@
|
||||||
|
// Copyright (c) 2023-2026 Chris (boreddevnl)
|
||||||
|
// This software is released under the GNU General Public License v3.0. See LICENSE file for details.
|
||||||
|
#include "syscall.h"
|
||||||
|
#include "libui.h"
|
||||||
|
#include "stdlib.h"
|
||||||
|
|
||||||
|
#define COLOR_DARK_BG 0xFF121212
|
||||||
|
#define COLOR_DARK_PANEL 0xFF1E1E1E
|
||||||
|
#define COLOR_DARK_TEXT 0xFFE0E0E0
|
||||||
|
#define COLOR_DARK_BORDER 0xFF333333
|
||||||
|
#define COLOR_ACCENT 0xFF4FC3F7
|
||||||
|
#define COLOR_CPU 0xFF81C784
|
||||||
|
#define COLOR_MEM 0xFFFFB74D
|
||||||
|
#define COLOR_KILL 0xFFE57373
|
||||||
|
#define COLOR_DIM_TEXT 0xFF999999
|
||||||
|
|
||||||
|
#define MAX_VISIBLE_PROCS 10
|
||||||
|
#define GRAPH_POINTS 60
|
||||||
|
|
||||||
|
static ui_window_t win_taskman;
|
||||||
|
static ProcessInfo proc_list[32];
|
||||||
|
static int proc_count = 0;
|
||||||
|
static int selected_proc = -1;
|
||||||
|
|
||||||
|
// History as fixed-point (x100)
|
||||||
|
static int cpu_history[GRAPH_POINTS];
|
||||||
|
static int mem_history[GRAPH_POINTS];
|
||||||
|
static int history_idx = 0;
|
||||||
|
|
||||||
|
static uint64_t uptime_prev = 0;
|
||||||
|
static uint64_t kernel_ticks_prev = 0;
|
||||||
|
static uint64_t total_mem_system = 0;
|
||||||
|
static uint64_t used_mem_system = 0;
|
||||||
|
static char cpu_model_name[64] = "Unknown CPU";
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
size_t total_memory;
|
||||||
|
size_t used_memory;
|
||||||
|
size_t available_memory;
|
||||||
|
size_t allocated_blocks;
|
||||||
|
size_t free_blocks;
|
||||||
|
size_t largest_free_block;
|
||||||
|
size_t smallest_free_block;
|
||||||
|
size_t fragmentation_percent;
|
||||||
|
size_t peak_memory_used;
|
||||||
|
} MemStats;
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
for (int i = 0; i < proc_count; i++) {
|
||||||
|
if (proc_list[i].pid == 0) {
|
||||||
|
kernel_ticks_now = proc_list[i].ticks;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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 = total_delta - kernel_delta;
|
||||||
|
int usage = (int)((used_delta * 100) / total_delta);
|
||||||
|
cpu_history[history_idx] = usage;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uptime_prev = uptime_now;
|
||||||
|
kernel_ticks_prev = kernel_ticks_now;
|
||||||
|
|
||||||
|
MemStats stats;
|
||||||
|
sys_system(SYSTEM_CMD_MEMINFO, (uint64_t)&stats, 0, 0, 0);
|
||||||
|
total_mem_system = stats.total_memory;
|
||||||
|
used_mem_system = stats.used_memory;
|
||||||
|
mem_history[history_idx] = (int)(stats.used_memory / 1024);
|
||||||
|
|
||||||
|
history_idx = (history_idx + 1) % GRAPH_POINTS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void draw_graph(int x, int y, int w, int h, int *data, uint32_t color, int max_val) {
|
||||||
|
ui_draw_rect(win_taskman, x, y, w, h, COLOR_DARK_PANEL);
|
||||||
|
ui_draw_rect(win_taskman, x, y, w, 1, COLOR_DARK_BORDER);
|
||||||
|
ui_draw_rect(win_taskman, x, y + h - 1, w, 1, COLOR_DARK_BORDER);
|
||||||
|
|
||||||
|
if (max_val == 0) max_val = 1;
|
||||||
|
|
||||||
|
for (int i = 0; i < GRAPH_POINTS - 1; i++) {
|
||||||
|
int idx1 = (history_idx + i) % GRAPH_POINTS;
|
||||||
|
|
||||||
|
long long val = (long long)data[idx1];
|
||||||
|
int h_val = (int)((val * h) / max_val);
|
||||||
|
if (h_val > h) h_val = h;
|
||||||
|
if (h_val < 0) h_val = 0;
|
||||||
|
|
||||||
|
int x1 = x + (i * w) / GRAPH_POINTS;
|
||||||
|
int next_x = x + ((i + 1) * w) / GRAPH_POINTS;
|
||||||
|
int draw_w = next_x - x1;
|
||||||
|
if (draw_w <= 0) draw_w = 1;
|
||||||
|
|
||||||
|
ui_draw_rect(win_taskman, x1, y + h - h_val, draw_w, h_val ? h_val : 1, color);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void format_gib(uint64_t bytes, char *out) {
|
||||||
|
uint64_t gib_int = bytes / (1024 * 1024 * 1024);
|
||||||
|
uint64_t gib_frac = ((bytes % (1024 * 1024 * 1024)) * 100) / (1024 * 1024 * 1024);
|
||||||
|
|
||||||
|
char s_int[16], s_frac[16];
|
||||||
|
itoa((int)gib_int, s_int);
|
||||||
|
itoa((int)gib_frac, s_frac);
|
||||||
|
|
||||||
|
out[0] = 0;
|
||||||
|
strcat(out, s_int);
|
||||||
|
strcat(out, ".");
|
||||||
|
if (gib_frac < 10) strcat(out, "0");
|
||||||
|
strcat(out, s_frac);
|
||||||
|
strcat(out, " GiB");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void draw_taskman(void) {
|
||||||
|
int win_w = 400;
|
||||||
|
int win_h = 480;
|
||||||
|
|
||||||
|
ui_draw_rect(win_taskman, 0, 0, win_w, win_h, COLOR_DARK_BG);
|
||||||
|
|
||||||
|
// CPU Graph Area
|
||||||
|
ui_draw_string(win_taskman, 10, 10, "PROCESSOR", COLOR_CPU);
|
||||||
|
char cpu_label[16];
|
||||||
|
int current_cpu = cpu_history[(history_idx + GRAPH_POINTS - 1) % GRAPH_POINTS];
|
||||||
|
itoa(current_cpu, cpu_label);
|
||||||
|
strcat(cpu_label, "%");
|
||||||
|
ui_draw_string(win_taskman, 140, 10, cpu_label, COLOR_CPU);
|
||||||
|
draw_graph(10, 25, 185, 60, cpu_history, COLOR_CPU, 100);
|
||||||
|
|
||||||
|
// CPU Model (Safe truncation)
|
||||||
|
char model_disp[32];
|
||||||
|
int mlen = strlen(cpu_model_name);
|
||||||
|
if (mlen > 22) {
|
||||||
|
memcpy(model_disp, cpu_model_name, 19);
|
||||||
|
model_disp[19] = '.'; model_disp[20] = '.'; model_disp[21] = '.'; model_disp[22] = 0;
|
||||||
|
} else {
|
||||||
|
strcpy(model_disp, cpu_model_name);
|
||||||
|
}
|
||||||
|
ui_draw_string(win_taskman, 10, 92, model_disp, COLOR_DIM_TEXT);
|
||||||
|
|
||||||
|
// Memory Graph Area
|
||||||
|
ui_draw_string(win_taskman, 205, 10, "MEMORY", COLOR_MEM);
|
||||||
|
char mem_pct_label[16];
|
||||||
|
int current_mem_pct = 0;
|
||||||
|
if (total_mem_system > 0) current_mem_pct = (int)((used_mem_system * 100) / total_mem_system);
|
||||||
|
itoa(current_mem_pct, mem_pct_label);
|
||||||
|
strcat(mem_pct_label, "%");
|
||||||
|
ui_draw_string(win_taskman, 340, 10, mem_pct_label, COLOR_MEM);
|
||||||
|
|
||||||
|
int max_mem_kb = (int)(total_mem_system / 1024);
|
||||||
|
draw_graph(205, 25, 185, 60, mem_history, COLOR_MEM, max_mem_kb);
|
||||||
|
|
||||||
|
// Memory GiB usage
|
||||||
|
char s_used[24], s_total[24], mem_text[64];
|
||||||
|
format_gib(used_mem_system, s_used);
|
||||||
|
format_gib(total_mem_system, s_total);
|
||||||
|
mem_text[0] = 0;
|
||||||
|
strcat(mem_text, s_used);
|
||||||
|
strcat(mem_text, " / ");
|
||||||
|
strcat(mem_text, s_total);
|
||||||
|
|
||||||
|
ui_draw_string(win_taskman, 205, 92, mem_text, COLOR_DIM_TEXT);
|
||||||
|
|
||||||
|
// Process List Header
|
||||||
|
ui_draw_rect(win_taskman, 10, 120, 380, 24, COLOR_DARK_PANEL);
|
||||||
|
ui_draw_string(win_taskman, 15, 125, "PID", COLOR_DIM_TEXT);
|
||||||
|
ui_draw_string(win_taskman, 60, 125, "NAME", COLOR_DIM_TEXT);
|
||||||
|
ui_draw_string(win_taskman, 250, 125, "MEMORY", COLOR_DIM_TEXT);
|
||||||
|
|
||||||
|
// Process Rows
|
||||||
|
int row = 0;
|
||||||
|
for (int i = 0; i < proc_count && row < MAX_VISIBLE_PROCS; i++) {
|
||||||
|
if (proc_list[i].pid == 0xFFFFFFFF) continue;
|
||||||
|
|
||||||
|
int ry = 150 + row * 26;
|
||||||
|
uint32_t bg = (selected_proc == row) ? 0xFF334455 : COLOR_DARK_PANEL;
|
||||||
|
ui_draw_rounded_rect_filled(win_taskman, 10, ry, 380, 24, 4, bg);
|
||||||
|
|
||||||
|
char pid_str[16];
|
||||||
|
itoa(proc_list[i].pid, pid_str);
|
||||||
|
ui_draw_string(win_taskman, 20, ry + 6, pid_str, COLOR_DARK_TEXT);
|
||||||
|
|
||||||
|
char name_disp[28];
|
||||||
|
if (strlen(proc_list[i].name) > 22) {
|
||||||
|
memcpy(name_disp, proc_list[i].name, 19);
|
||||||
|
name_disp[19] = '.'; name_disp[20] = '.'; name_disp[21] = '.'; name_disp[22] = 0;
|
||||||
|
} else {
|
||||||
|
strcpy(name_disp, proc_list[i].name);
|
||||||
|
}
|
||||||
|
ui_draw_string(win_taskman, 65, ry + 6, name_disp, COLOR_DARK_TEXT);
|
||||||
|
|
||||||
|
char m_str[32];
|
||||||
|
itoa((int)(proc_list[i].used_memory / 1024), m_str);
|
||||||
|
strcat(m_str, " KB");
|
||||||
|
ui_draw_string(win_taskman, 255, ry + 6, m_str, COLOR_DARK_TEXT);
|
||||||
|
|
||||||
|
row++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Kill button (Positioned relative to window height)
|
||||||
|
int btn_x = 400 - 110;
|
||||||
|
int btn_y = 480 - 70;
|
||||||
|
int btn_w = 100;
|
||||||
|
int btn_h = 30;
|
||||||
|
|
||||||
|
// Disable kill for PID 0
|
||||||
|
bool can_kill = (selected_proc != -1);
|
||||||
|
if (can_kill) {
|
||||||
|
int v_cnt = 0;
|
||||||
|
for (int i = 0; i < proc_count; i++) {
|
||||||
|
if (proc_list[i].pid != 0xFFFFFFFF) {
|
||||||
|
if (v_cnt == selected_proc) {
|
||||||
|
if (proc_list[i].pid == 0) can_kill = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
v_cnt++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ui_draw_rounded_rect_filled(win_taskman, btn_x, btn_y, btn_w, btn_h, 6, can_kill ? COLOR_KILL : COLOR_DARK_BORDER);
|
||||||
|
|
||||||
|
const char *btn_text = "FORCE KILL";
|
||||||
|
int tx = btn_x + (btn_w - 80) / 2;
|
||||||
|
int ty = btn_y + (btn_h - 12) / 2;
|
||||||
|
ui_draw_string(win_taskman, tx, ty, btn_text, can_kill ? 0xFFFFFFFF : 0xFF666666);
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(void) {
|
||||||
|
win_taskman = ui_window_create("Task Manager", 100, 100, 400, 480);
|
||||||
|
|
||||||
|
// Fetch CPU model
|
||||||
|
sys_system(SYSTEM_CMD_GET_CPU_MODEL, (uint64_t)cpu_model_name, 0, 0, 0);
|
||||||
|
|
||||||
|
for(int i=0; i<GRAPH_POINTS; i++) { cpu_history[i] = 0; mem_history[i] = 0; }
|
||||||
|
|
||||||
|
gui_event_t ev;
|
||||||
|
|
||||||
|
while (1) {
|
||||||
|
// Drain events
|
||||||
|
while (ui_get_event(win_taskman, &ev)) {
|
||||||
|
if (ev.type == GUI_EVENT_CLOSE) {
|
||||||
|
sys_exit(0);
|
||||||
|
} else if (ev.type == GUI_EVENT_CLICK) {
|
||||||
|
int mx = ev.arg1;
|
||||||
|
int my = ev.arg2;
|
||||||
|
|
||||||
|
if (mx >= 10 && mx < 390 && my >= 150 && my < 150 + MAX_VISIBLE_PROCS * 26) {
|
||||||
|
int idx = (my - 150) / 26;
|
||||||
|
int valid_count = 0;
|
||||||
|
int target_i = -1;
|
||||||
|
for (int i = 0; i < proc_count; i++) {
|
||||||
|
if (proc_list[i].pid != 0xFFFFFFFF) {
|
||||||
|
if (valid_count == idx) { target_i = i; break; }
|
||||||
|
valid_count++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (target_i != -1) selected_proc = idx;
|
||||||
|
else selected_proc = -1;
|
||||||
|
|
||||||
|
draw_taskman();
|
||||||
|
ui_mark_dirty(win_taskman, 0, 0, 400, 480);
|
||||||
|
} else if (mx >= 290 && mx < 390 && my >= 410 && my < 440) {
|
||||||
|
if (selected_proc != -1) {
|
||||||
|
int valid_count = 0;
|
||||||
|
for (int i = 0; i < proc_count; i++) {
|
||||||
|
if (proc_list[i].pid != 0xFFFFFFFF) {
|
||||||
|
if (valid_count == selected_proc) {
|
||||||
|
if (proc_list[i].pid != 0) sys_kill(proc_list[i].pid);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
valid_count++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
selected_proc = -1;
|
||||||
|
update_proc_list();
|
||||||
|
draw_taskman();
|
||||||
|
ui_mark_dirty(win_taskman, 0, 0, 400, 480);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (ev.type == GUI_EVENT_PAINT) {
|
||||||
|
draw_taskman();
|
||||||
|
ui_mark_dirty(win_taskman, 0, 0, 400, 480);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
update_proc_list();
|
||||||
|
draw_taskman();
|
||||||
|
ui_mark_dirty(win_taskman, 0, 0, 400, 480);
|
||||||
|
|
||||||
|
// Proper blocking sleep (200ms)
|
||||||
|
sys_system(46, 200, 0, 0, 0); // SYSTEM_CMD_SLEEP
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
@ -3,6 +3,7 @@
|
||||||
// This header needs to maintain in any file it is present in, as per the GPL license terms.
|
// This header needs to maintain in any file it is present in, as per the GPL license terms.
|
||||||
#include "libc/syscall.h"
|
#include "libc/syscall.h"
|
||||||
#include "libc/libui.h"
|
#include "libc/libui.h"
|
||||||
|
#include "libc/stdlib.h"
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
|
|
||||||
#define COLOR_DARK_PANEL 0xFF202020
|
#define COLOR_DARK_PANEL 0xFF202020
|
||||||
|
|
@ -426,6 +427,8 @@ int main(int argc, char **argv) {
|
||||||
} else if (ev.type == GUI_EVENT_CLOSE) {
|
} else if (ev.type == GUI_EVENT_CLOSE) {
|
||||||
sys_exit(0);
|
sys_exit(0);
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
sleep(10);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
||||||
|
|
@ -307,7 +307,7 @@ int main(int argc, char **argv) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Small sleep to avoid eating 100% CPU
|
// Small sleep to avoid eating 100% CPU
|
||||||
for (volatile int i = 0; i < 10000; i++);
|
sleep(10);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
||||||
|
|
@ -409,6 +409,8 @@ static void draw_dock_terminal(int x, int y);
|
||||||
static void draw_dock_minesweeper(int x, int y);
|
static void draw_dock_minesweeper(int x, int y);
|
||||||
static void draw_dock_paint(int x, int y);
|
static void draw_dock_paint(int x, int y);
|
||||||
static void draw_dock_clock(int x, int y);
|
static void draw_dock_clock(int x, int y);
|
||||||
|
static void draw_dock_taskman(int x, int y);
|
||||||
|
static void draw_dock_editor(int x, int y);
|
||||||
static void draw_dock_editor(int x, int y);
|
static void draw_dock_editor(int x, int y);
|
||||||
static void draw_filled_circle(int cx, int cy, int r, uint32_t color);
|
static void draw_filled_circle(int cx, int cy, int r, uint32_t color);
|
||||||
|
|
||||||
|
|
@ -795,6 +797,22 @@ void draw_paint_icon(int x, int y, const char *label) {
|
||||||
draw_icon_label(x, y, label);
|
draw_icon_label(x, y, label);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void draw_dock_taskman(int x, int y) {
|
||||||
|
draw_rounded_rect_filled(x, y, 48, 48, 12, 0xFF37474F); // Dark blue-grey
|
||||||
|
draw_rounded_rect_filled(x+4, y+4, 40, 40, 8, 0xFF455A64);
|
||||||
|
|
||||||
|
// Draw "Activity" lines
|
||||||
|
draw_rect(x+8, y+24, 6, 12, 0xFF4FC3F7); // Light blue bar
|
||||||
|
draw_rect(x+16, y+16, 6, 20, 0xFF81C784); // Green bar
|
||||||
|
draw_rect(x+24, y+20, 6, 16, 0xFFFFB74D); // Orange bar
|
||||||
|
draw_rect(x+32, y+10, 6, 26, 0xFFE57373); // Red bar
|
||||||
|
}
|
||||||
|
|
||||||
|
void draw_taskman_icon(int x, int y, const char *label) {
|
||||||
|
draw_scaled_icon(x, y, draw_dock_taskman);
|
||||||
|
draw_icon_label(x, y, label);
|
||||||
|
}
|
||||||
|
|
||||||
static void draw_filled_circle(int cx, int cy, int r, uint32_t color);
|
static void draw_filled_circle(int cx, int cy, int r, uint32_t color);
|
||||||
|
|
||||||
// Draw traffic light (close button - red)
|
// Draw traffic light (close button - red)
|
||||||
|
|
@ -1299,7 +1317,7 @@ void wm_paint(void) {
|
||||||
int dock_y = sh - dock_h - 6;
|
int dock_y = sh - dock_h - 6;
|
||||||
int dock_item_size = 48;
|
int dock_item_size = 48;
|
||||||
int dock_spacing = 10;
|
int dock_spacing = 10;
|
||||||
int total_dock_width = 9 * (dock_item_size + dock_spacing);
|
int total_dock_width = 10 * (dock_item_size + dock_spacing);
|
||||||
int dock_bg_x = (sw - total_dock_width) / 2 - 12;
|
int dock_bg_x = (sw - total_dock_width) / 2 - 12;
|
||||||
int dock_bg_w = total_dock_width + 24;
|
int dock_bg_w = total_dock_width + 24;
|
||||||
draw_rounded_rect_filled(dock_bg_x, dock_y, dock_bg_w, dock_h, 18, COLOR_DOCK_BG);
|
draw_rounded_rect_filled(dock_bg_x, dock_y, dock_bg_w, dock_h, 18, COLOR_DOCK_BG);
|
||||||
|
|
@ -1323,6 +1341,8 @@ void wm_paint(void) {
|
||||||
dock_x += dock_item_size + dock_spacing;
|
dock_x += dock_item_size + dock_spacing;
|
||||||
draw_dock_browser(dock_x, dock_item_y);
|
draw_dock_browser(dock_x, dock_item_y);
|
||||||
dock_x += dock_item_size + dock_spacing;
|
dock_x += dock_item_size + dock_spacing;
|
||||||
|
draw_dock_taskman(dock_x, dock_item_y);
|
||||||
|
dock_x += dock_item_size + dock_spacing;
|
||||||
draw_dock_clock(dock_x, dock_item_y);
|
draw_dock_clock(dock_x, dock_item_y);
|
||||||
// Editor removed from dock
|
// Editor removed from dock
|
||||||
|
|
||||||
|
|
@ -1867,7 +1887,7 @@ void wm_handle_right_click(int x, int y) {
|
||||||
int dock_y = sh - dock_h - 6;
|
int dock_y = sh - dock_h - 6;
|
||||||
int dock_item_size = 48;
|
int dock_item_size = 48;
|
||||||
int dock_spacing = 10;
|
int dock_spacing = 10;
|
||||||
int total_dock_width = 9 * (dock_item_size + dock_spacing);
|
int total_dock_width = 10 * (dock_item_size + dock_spacing);
|
||||||
int dock_bg_x = (sw - total_dock_width) / 2 - 12;
|
int dock_bg_x = (sw - total_dock_width) / 2 - 12;
|
||||||
int dock_bg_w = total_dock_width + 24;
|
int dock_bg_w = total_dock_width + 24;
|
||||||
|
|
||||||
|
|
@ -1886,7 +1906,8 @@ void wm_handle_right_click(int x, int y) {
|
||||||
else if (item == 5) start_menu_pending_app = "Minesweeper";
|
else if (item == 5) start_menu_pending_app = "Minesweeper";
|
||||||
else if (item == 6) start_menu_pending_app = "Paint";
|
else if (item == 6) start_menu_pending_app = "Paint";
|
||||||
else if (item == 7) start_menu_pending_app = "Browser";
|
else if (item == 7) start_menu_pending_app = "Browser";
|
||||||
else if (item == 8) start_menu_pending_app = "Clock";
|
else if (item == 8) start_menu_pending_app = "Task Manager";
|
||||||
|
else if (item == 9) start_menu_pending_app = "Clock";
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
wm_handle_click(mx, my);
|
wm_handle_click(mx, my);
|
||||||
|
|
@ -2040,6 +2061,10 @@ void wm_handle_right_click(int x, int y) {
|
||||||
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")) {
|
||||||
|
Window *existing = wm_find_window_by_title("Task Manager");
|
||||||
|
if (existing) wm_bring_to_front(existing);
|
||||||
|
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();
|
||||||
} else if (str_starts_with(start_menu_pending_app, "Restart")) {
|
} else if (str_starts_with(start_menu_pending_app, "Restart")) {
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue