Stability improvements

This commit is contained in:
boreddevnl 2026-02-26 21:45:57 +01:00
parent 2801dbc21f
commit fcc290f3f9
32 changed files with 171 additions and 97 deletions

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
disk.img

Binary file not shown.

Binary file not shown.

View file

@ -287,6 +287,7 @@ void draw_char(int x, int y, char c, uint32_t color) {
}
void draw_string(int x, int y, const char *s, uint32_t color) {
if (!s) return;
int cur_x = x;
int cur_y = y;
while (*s) {
@ -370,22 +371,22 @@ void graphics_set_bg_image(uint32_t *pixels, int w, int h) {
void draw_boredos_logo(int x, int y, int scale) {
static const uint8_t brewos_bmp[] = {
0,0,1,1,1,0,0,0,0,0,0,1,1,1,0,0, // 0: Ears
0,1,1,1,1,0,0,0,0,0,0,1,1,1,1,0, // 1: Ears
1,1,1,1,1,0,0,0,0,0,0,1,1,1,1,1, // 2: Ears (Separated)
1,1,1,1,2,2,2,2,2,2,2,2,1,1,1,1, // 3: Forehead / Ears
1,1,1,2,2,2,2,2,2,2,2,2,2,1,1,1, // 4: Face
1,1,2,2,2,1,1,2,2,1,1,2,2,2,1,1, // 5: Eyes start
1,1,2,2,1,1,1,1,1,1,1,1,2,2,1,1, // 6: Eyes
1,1,2,2,1,1,1,1,1,1,1,1,2,2,1,1, // 7: Eyes
1,1,2,2,1,1,1,1,1,1,1,1,2,2,1,1, // 8: Eyes
1,1,2,2,2,1,1,2,2,1,1,2,2,2,1,1, // 9: Under eyes
1,1,2,2,2,2,2,1,1,2,2,2,2,2,1,1, // 10: Nose
1,1,2,2,2,2,2,2,2,2,2,2,2,2,1,1, // 11: Cheeks
1,1,1,2,2,2,2,2,2,2,2,2,2,1,1,1, // 12: Jaw
0,1,1,1,2,2,2,2,2,2,2,2,1,1,1,0, // 13: Chin
0,0,1,1,1,2,2,2,2,2,2,1,1,1,0,0, // 14: Chin outline
0,0,0,1,1,1,1,1,1,1,1,1,1,0,0,0 // 15: Bottom
0,0,1,1,1,0,0,0,0,0,0,1,1,1,0,0,
0,1,1,1,1,0,0,0,0,0,0,1,1,1,1,0,
1,1,1,1,1,0,0,0,0,0,0,1,1,1,1,1,
1,1,1,1,2,2,2,2,2,2,2,2,1,1,1,1,
1,1,1,2,2,2,2,2,2,2,2,2,2,1,1,1,
1,1,2,2,2,1,1,2,2,1,1,2,2,2,1,1,
1,1,2,2,1,1,1,1,1,1,1,1,2,2,1,1,
1,1,2,2,1,1,1,1,1,1,1,1,2,2,1,1,
1,1,2,2,1,1,1,1,1,1,1,1,2,2,1,1,
1,1,2,2,2,1,1,2,2,1,1,2,2,2,1,1,
1,1,2,2,2,2,2,1,1,2,2,2,2,2,1,1,
1,1,2,2,2,2,2,2,2,2,2,2,2,2,1,1,
1,1,1,2,2,2,2,2,2,2,2,2,2,1,1,1,
0,1,1,1,2,2,2,2,2,2,2,2,1,1,1,0,
0,0,1,1,1,2,2,2,2,2,2,1,1,1,0,0,
0,0,0,1,1,1,1,1,1,1,1,1,1,0,0,0
};
for (int r = 0; r < 16; r++) {
@ -435,6 +436,15 @@ void graphics_flip_buffer(void) {
}
void graphics_set_clipping(int x, int y, int w, int h) {
if (x < 0) { w += x; x = 0; }
if (y < 0) { h += y; y = 0; }
int sw = get_screen_width();
int sh = get_screen_height();
if (x + w > sw) w = sw - x;
if (y + h > sh) h = sh - y;
if (w < 0) w = 0;
if (h < 0) h = 0;
g_clip_x = x;
g_clip_y = y;
g_clip_w = w;
@ -459,9 +469,7 @@ void graphics_blit_buffer(uint32_t *src, int dst_x, int dst_y, int w, int h) {
if (vx < 0 || vx >= sw) continue;
uint32_t pcol = src[y * w + x];
// Alpha blending support:
// If the alpha byte is 0, we treat it as transparent ONLY if the color is also 0.
// This handles common 0xRRGGBB as opaque.
if ((pcol & 0xFF000000) != 0 || (pcol & 0xFFFFFF) != 0) {
g_back_buffer[vy * sw + vx] = pcol;
}

View file

@ -84,7 +84,32 @@ void kmain(void) {
platform_init();
serial_write("[DEBUG] platform_init OK\n");
// 1. Graphics Init
// 1. Memory Detection and Heap Init
uint64_t heap_phys_addr = 0;
size_t heap_size = 0;
if (memmap_request.response != NULL) {
for (uint64_t i = 0; i < memmap_request.response->entry_count; i++) {
struct limine_memmap_entry *entry = memmap_request.response->entries[i];
if (entry->type == LIMINE_MEMMAP_USABLE) {
if (entry->length > heap_size) {
heap_size = entry->length;
heap_phys_addr = entry->base;
}
}
}
}
if (heap_size > 512 * 1024 * 1024) heap_size = 512 * 1024 * 1024; // Cap at 512MB
if (heap_phys_addr != 0) {
memory_manager_init_at((void*)p2v(heap_phys_addr), heap_size);
serial_write("[DEBUG] memory_manager_init OK\n");
} else {
serial_write("[DEBUG] ERROR: No usable memory for heap!\n");
hcf();
}
// 2. Graphics Init
if (framebuffer_request.response == NULL || framebuffer_request.response->framebuffer_count < 1) {
serial_write("[DEBUG] No framebuffer! Halting.\n");
hcf();
@ -94,20 +119,19 @@ void kmain(void) {
graphics_init(fb);
serial_write("[DEBUG] graphics_init OK\n");
// 1.5 GDT & TSS Init
// 3. GDT & TSS Init
gdt_init();
serial_write("[DEBUG] gdt_init OK\n");
// 1.6 Paging Init
// 4. Paging Init
paging_init();
serial_write("[DEBUG] paging_init OK\n");
// 1.7 Syscall Init
// 5. Syscall Init
syscall_init();
serial_write("[DEBUG] syscall_init OK\n");
// Set up a user page and jump to user space
// 2. Interrupts Init
// 6. Interrupts Init
idt_init();
idt_register_interrupts();
idt_load();
@ -115,33 +139,8 @@ void kmain(void) {
process_init();
serial_write("[DEBUG] Skipping user mode test, proceeding with normal boot.\n");
// 2.5 Memory Manager Init - Calculate available RAM from Limine
size_t total_usable_memory = 0;
if (memmap_request.response != NULL) {
for (uint64_t i = 0; i < memmap_request.response->entry_count; i++) {
struct limine_memmap_entry *entry = memmap_request.response->entries[i];
// Count usable memory regions
if (entry->type == LIMINE_MEMMAP_USABLE) {
total_usable_memory += entry->length;
}
}
}
// Initialize memory manager with available memory (cap at 2GB for practical reasons)
size_t pool_size = total_usable_memory > (2 * 1024 * 1024 * 1024) ?
(2 * 1024 * 1024 * 1024) : total_usable_memory;
if (pool_size == 0) {
pool_size = 512 * 1024 * 1024; // Fallback to 512MB if detection fails
}
memory_manager_init_with_size(pool_size);
// Initialize FAT32 RAMFS and mount Limine modules
fat32_init();
if (module_request.response != NULL) {
@ -181,6 +180,7 @@ void kmain(void) {
// Timer interrupt will drive the redraw system
while (1) {
wm_process_input();
wm_process_deferred_thumbs();
wallpaper_process_pending();
asm("hlt");
}

View file

@ -3,10 +3,8 @@
#include <stdint.h>
// --- Internal State ---
#define KERNEL_HEAP_SIZE (32 * 1024 * 1024) // 32MB Static Heap
static uint8_t memory_pool_buffer[KERNEL_HEAP_SIZE];
static uint8_t *memory_pool = memory_pool_buffer;
static size_t memory_pool_size = KERNEL_HEAP_SIZE;
static uint8_t *memory_pool = NULL;
static size_t memory_pool_size = 0;
static MemBlock block_list[MAX_ALLOCATIONS];
static int block_count = 0;
static size_t total_allocated = 0;
@ -137,9 +135,11 @@ static size_t calculate_fragmentation(void) {
// --- Public API ---
void memory_manager_init_with_size(size_t pool_size) {
void memory_manager_init_at(void *pool_address, size_t pool_size) {
if (initialized) return;
memory_pool = (uint8_t *)pool_address;
memory_pool_size = pool_size;
// Clear metadata
mem_memset(block_list, 0, sizeof(block_list));
@ -158,6 +158,14 @@ void memory_manager_init_with_size(size_t pool_size) {
initialized = true;
}
void memory_manager_init_with_size(size_t pool_size) {
// This is now just a wrapper if init_at wasn't called.
// However, in BoredOS we now prefer explicit init_at.
if (initialized) return;
// Fallback: we still need a buffer if no address is provided?
// Let's assume for now that BoredOS always calls init_at.
}
void memory_manager_init(void) {
memory_manager_init_with_size(DEFAULT_POOL_SIZE);
}

View file

@ -6,8 +6,8 @@
#include <stdbool.h>
// Memory Manager Configuration
#define DEFAULT_POOL_SIZE (512 * 1024 * 1024) // 512MB default (can be overridden)
#define MAX_ALLOCATIONS 4096 // Increased for larger pools
#define DEFAULT_POOL_SIZE (128 * 1024 * 1024) // 128MB default
#define MAX_ALLOCATIONS 16384 // Increased for larger pools
#define MAX_FRAGMENTATION_SLOTS 2048
// Allocation block metadata
@ -35,6 +35,7 @@ typedef struct {
// Public API
void memory_manager_init(void);
void memory_manager_init_with_size(size_t pool_size);
void memory_manager_init_at(void *pool_address, size_t pool_size);
// Allocation/Deallocation
void* kmalloc(size_t size);

View file

@ -239,6 +239,8 @@ void process_create_elf(const char* filepath, const char* args_str) {
*(--stack_ptr) = 0; // R15
new_proc->kernel_stack = (uint64_t)kernel_stack + 16384;
new_proc->kernel_stack_alloc = kernel_stack;
new_proc->user_stack_alloc = stack;
new_proc->rsp = (uint64_t)stack_ptr;
// We only increment process_count after success
@ -333,6 +335,13 @@ uint64_t process_terminate_current(void) {
paging_switch_directory(current_process->pml4_phys);
// 5. Actually free the memory (after switching state to avoid issues)
if (to_delete->kernel_stack_alloc) kfree(to_delete->kernel_stack_alloc);
if (to_delete->user_stack_alloc) kfree(to_delete->user_stack_alloc);
// NOTE: In a real system we would also free all physical pages
// used by the user page table. For now we just free the stacks.
return current_process->rsp;
}

View file

@ -35,6 +35,9 @@ typedef struct process {
void *fds[MAX_PROCESS_FDS];
void *kernel_stack_alloc; // Original pointer from kmalloc for freeing
void *user_stack_alloc; // Original pointer from kmalloc for freeing
struct process *next;
} process_t;

View file

@ -27,20 +27,20 @@ static bool str_eq(const char *s1, const char *s2) {
}
// --- State ---
static int mx = 400, my = 300; // Mouse Pos
static int prev_mx = 400, prev_my = 300; // Previous mouse position
static int mx = 400, my = 300;
static int prev_mx = 400, prev_my = 300;
static bool start_menu_open = false;
static char *start_menu_pending_app = NULL; // For click vs drag detection
static int pending_desktop_icon_click = -1; // For desktop icon click vs drag
static char *start_menu_pending_app = NULL;
static int pending_desktop_icon_click = -1;
// Desktop Context Menu
static bool desktop_menu_visible = false;
static int desktop_menu_x = 0;
static int desktop_menu_y = 0;
static int desktop_menu_target_icon = -1; // -1 for background
static int desktop_menu_target_icon = -1;
// Desktop Dialog State
static int desktop_dialog_state = 0; // 0=None, 8=Rename
static int desktop_dialog_state = 0;
static char desktop_dialog_input[64];
static int desktop_dialog_cursor = 0;
static int desktop_dialog_target = -1;
@ -62,7 +62,7 @@ static int drag_offset_y = 0;
// File Dragging State
bool is_dragging_file = false;
static char drag_file_path[256];
static int drag_icon_type = 0; // 0=File, 1=Folder, 2=App
static int drag_icon_type = 0;
static int drag_start_x = 0;
static int drag_start_y = 0;
static int drag_icon_orig_x = 0;
@ -74,7 +74,7 @@ static Window *all_windows[32];
static int window_count = 0;
// Redraw system
static bool force_redraw = true; // Force full redraw on next tick
static bool force_redraw = true;
static uint32_t timer_ticks = 0;
static int desktop_refresh_timer = 0;
@ -88,7 +88,7 @@ static int last_cursor_y = 300;
typedef struct {
char name[64];
int x, y;
int type; // 0=File, 1=Folder, 2=App
int type;
} DesktopIcon;
static DesktopIcon desktop_icons[MAX_DESKTOP_ICONS];
@ -101,7 +101,7 @@ int desktop_max_rows_per_col = 13;
int desktop_max_cols = 23;
// Mouse Settings
int mouse_speed = 10; // Default 1.0x (range 1-50)
int mouse_speed = 10;
static int mouse_accum_x = 0;
static int mouse_accum_y = 0;
@ -141,9 +141,7 @@ static void refresh_desktop_icons(void) {
bool file_processed[MAX_DESKTOP_ICONS];
for(int i=0; i<MAX_DESKTOP_ICONS; i++) file_processed[i] = false;
// 1. Preserve existing icons in their current order
for (int i = 0; i < desktop_icon_count; i++) {
// Find if this icon still exists in the file list
int found_idx = -1;
for (int j = 0; j < file_count; j++) {
if (!file_processed[j] && str_eq(desktop_icons[i].name, files[j].name) != 0) {
@ -162,10 +160,9 @@ static void refresh_desktop_icons(void) {
}
}
// 2. Add new files (not currently on desktop) to the end
for (int i = 0; i < file_count; i++) {
if (!file_processed[i]) {
if (files[i].name[0] == '.') continue; // Skip . and ..
if (files[i].name[0] == '.') continue;
if (new_count >= MAX_DESKTOP_ICONS) break;
DesktopIcon *dest = &new_icons[new_count];
@ -186,14 +183,12 @@ static void refresh_desktop_icons(void) {
for(int i=0; i<new_count; i++) desktop_icons[i] = new_icons[i];
kfree(files);
// 3. Layout Icons
if (desktop_auto_align) {
int start_x = 20;
int start_y = 30;
int grid_x = 0;
int grid_y = 0;
// Find Recycle Bin index
int recycle_idx = -1;
for (int i = 0; i < desktop_icon_count; i++) {
if (str_starts_with(desktop_icons[i].name, "Recycle Bin")) {
@ -521,6 +516,42 @@ static struct {
} thumb_cache[THUMB_CACHE_SIZE];
static int thumb_cache_next = 0; // Round-robin eviction
// Deferred Thumbnail Request Queue
#define THUMB_QUEUE_SIZE 16
static char thumb_request_queue[THUMB_QUEUE_SIZE][256];
static int thumb_queue_head = 0;
static int thumb_queue_tail = 0;
static void thumb_request_push(const char *path) {
if (!path) return;
// Check if already in queue
int curr = thumb_queue_head;
while (curr != thumb_queue_tail) {
if (str_eq(thumb_request_queue[curr], path) != 0) return;
curr = (curr + 1) % THUMB_QUEUE_SIZE;
}
// Push if space
int next_tail = (thumb_queue_tail + 1) % THUMB_QUEUE_SIZE;
if (next_tail != thumb_queue_head) {
int i = 0;
while (path[i] && i < 255) {
thumb_request_queue[thumb_queue_tail][i] = path[i];
i++;
}
thumb_request_queue[thumb_queue_tail][i] = 0;
thumb_queue_tail = next_tail;
}
}
static bool thumb_cache_is_failed(const char *path) {
for (int i = 0; i < THUMB_CACHE_SIZE; i++) {
if (thumb_cache[i].failed && str_eq(thumb_cache[i].path, path) != 0) return true;
}
return false;
}
static uint32_t* thumb_cache_lookup(const char *path) {
for (int i = 0; i < THUMB_CACHE_SIZE; i++) {
if (thumb_cache[i].valid && str_eq(thumb_cache[i].path, path) != 0) {
@ -530,14 +561,7 @@ static uint32_t* thumb_cache_lookup(const char *path) {
return NULL;
}
static bool thumb_cache_is_failed(const char *path) {
for (int i = 0; i < THUMB_CACHE_SIZE; i++) {
if (thumb_cache[i].failed && str_eq(thumb_cache[i].path, path) != 0) {
return true;
}
}
return false;
}
static uint32_t* thumb_cache_decode(const char *path) {
// Open and read the JPG file
@ -566,11 +590,14 @@ static uint32_t* thumb_cache_decode(const char *path) {
// Decode JPEG
njInit();
if (njDecode(buf, total) != NJ_OK) {
serial_write("[WM] njDecode failed for deferred thumb\n");
njDone();
kfree(buf);
return NULL;
}
serial_write("[WM] njDecode OK for deferred thumb\n");
int img_w = njGetWidth();
int img_h = njGetHeight();
unsigned char *img = njGetImage();
@ -627,22 +654,8 @@ void draw_image_icon(int x, int y, const char *label) {
if (!thumb && !thumb_cache_is_failed(label)) {
thumb = thumb_cache_lookup(label);
if (!thumb) {
// Try to decode and cache
graphics_set_render_target(NULL, 0, 0); // Restore before file I/O
thumb = thumb_cache_decode(label);
if (!thumb) {
// Mark as failed so we don't retry every frame
int slot = thumb_cache_next;
int p = 0;
while (label[p] && p < 255) { thumb_cache[slot].path[p] = label[p]; p++; }
thumb_cache[slot].path[p] = 0;
thumb_cache[slot].valid = false;
thumb_cache[slot].failed = true;
thumb_cache_next = (thumb_cache_next + 1) % THUMB_CACHE_SIZE;
}
// Re-set render target for icon drawing
for (int i = 0; i < 48 * 48; i++) icon_buf[i] = 0xFFFF00FF;
graphics_set_render_target(icon_buf, 48, 48);
// Queue for background decoding
thumb_request_push(label);
}
}
@ -1097,6 +1110,9 @@ void wm_paint(void) {
int sw = get_screen_width();
int sh = get_screen_height();
uint64_t rflags;
asm volatile("pushfq; pop %0; cli" : "=r"(rflags));
DirtyRect dirty = graphics_get_dirty_rect();
if (dirty.active) {
graphics_set_clipping(dirty.x, dirty.y, dirty.w, dirty.h);
@ -1299,6 +1315,9 @@ void wm_paint(void) {
// Flip the buffer - display the rendered frame atomically
graphics_flip_buffer();
// Restore IRQs
asm volatile("push %0; popfq" : : "r"(rflags));
}
// --- Input Handling ---
@ -2299,11 +2318,14 @@ void wm_handle_key(char c) {
}
void wm_process_input(void) {
uint64_t rflags;
asm volatile("pushfq; pop %0; cli" : "=r"(rflags));
while (key_head != key_tail) {
char c = key_queue[key_tail];
key_tail = (key_tail + 1) % INPUT_QUEUE_SIZE;
wm_dispatch_key(c);
}
asm volatile("push %0; popfq" : : "r"(rflags));
}
void wm_mark_dirty(int x, int y, int w, int h) {
@ -2314,6 +2336,28 @@ void wm_refresh(void) {
force_redraw = true;
}
void wm_process_deferred_thumbs(void) {
if (thumb_queue_head == thumb_queue_tail) return;
char path[256];
int i = 0;
while (thumb_request_queue[thumb_queue_head][i]) {
path[i] = thumb_request_queue[thumb_queue_head][i];
i++;
}
path[i] = 0;
serial_write("[WM] Processing deferred thumb: ");
serial_write(path);
serial_write("\n");
// Pop from queue
thumb_queue_head = (thumb_queue_head + 1) % THUMB_QUEUE_SIZE;
// Process (this takes time but it's okay because we are in the main loop with IRQs enabled)
thumb_cache_decode(path);
}
void wm_init(void) {
disk_manager_init();
disk_manager_scan();

View file

@ -64,6 +64,7 @@ void wm_handle_key(char c);
void wm_handle_click(int x, int y);
void wm_handle_right_click(int x, int y);
void wm_process_input(void);
void wm_process_deferred_thumbs(void);
void wm_add_window(Window *win);
void wm_remove_window(Window *win);
void wm_bring_to_front(Window *win);