diff --git a/boredos.iso b/boredos.iso index 8d91f88..95bd27c 100644 Binary files a/boredos.iso and b/boredos.iso differ diff --git a/build/cmd.o b/build/cmd.o index 979d22e..1559945 100644 Binary files a/build/cmd.o and b/build/cmd.o differ diff --git a/build/idt.o b/build/idt.o index 190ea7d..c82d835 100644 Binary files a/build/idt.o and b/build/idt.o differ diff --git a/disk.img b/disk.img index 5c027e9..fa13297 100644 Binary files a/disk.img and b/disk.img differ diff --git a/limine.conf b/limine.conf index f1bca17..29323b5 100644 --- a/limine.conf +++ b/limine.conf @@ -3,8 +3,6 @@ timeout: 3 # Graphics mode and Splash screen term_palette: ffffff;ffffff;ffffff;ffffff;ffffff;ffffff;ffffff;ffffff;ffffff;ffffff;ffffff;ffffff;ffffff;ffffff;ffffff;ffffff term_background: #00000000 -# Hide terminal by placing it out of view or making it very small initially if possible, -# but Limine's wallapper will be the main background. wallpaper: boot():/splash.jpg /BoredOS diff --git a/src/kernel/cli_apps/cli_apps.h b/src/kernel/cli_apps/cli_apps.h index 9186949..6d349fd 100644 --- a/src/kernel/cli_apps/cli_apps.h +++ b/src/kernel/cli_apps/cli_apps.h @@ -18,6 +18,7 @@ void cli_cmd_boredver(char *args); void cli_cmd_clear(char *args); void cli_cmd_exit(char *args); + // Filesystem commands void cli_cmd_cd(char *args); void cli_cmd_pwd(char *args); diff --git a/src/kernel/cmd.c b/src/kernel/cmd.c index c39698b..3e23838 100644 --- a/src/kernel/cmd.c +++ b/src/kernel/cmd.c @@ -361,7 +361,6 @@ void pager_wrap_content(const char **lines, int count) { pager_total_lines++; processed += chunk_len; - // Skip the space we just split on if (processed < len && line[processed] == ' ') { processed++; } @@ -425,7 +424,6 @@ static void internal_cmd_cd(char *args) { } path[i] = 0; - // For cmd_state, we need to build and validate the full path if (cmd_state) { // Build full path for validation char full_path[512] = {0}; @@ -942,9 +940,7 @@ static void cmd_exec_single(char *cmd) { if (needs_path) { if (args && args[0]) { - // For echo with redirection, we need to prepend drive to redirect target too if (is_echo_command) { - // Find > or >> and prepend drive to the filename after it char temp_args[512] = {0}; int i = 0; int j = 0; diff --git a/src/kernel/disk_manager.c b/src/kernel/disk_manager.c index 1a7da1d..21a4abe 100644 --- a/src/kernel/disk_manager.c +++ b/src/kernel/disk_manager.c @@ -112,7 +112,7 @@ static int ata_identify(uint16_t port_base, bool slave) { // Read 256 words (512 bytes) of identity data for (int i = 0; i < 256; i++) { uint16_t data = inw(port_base + ATA_REG_DATA); - (void)data; // We discard identity data for now, just checking presence + (void)data; } return 1; diff --git a/src/kernel/fat32.c b/src/kernel/fat32.c index 230a022..263903d 100644 --- a/src/kernel/fat32.c +++ b/src/kernel/fat32.c @@ -5,8 +5,6 @@ #include #include -// === RAMFS Implementation (Drive A:) === -// We keep the original logic for Drive A to preserve existing OS functionality. #define MAX_FILES 256 #define MAX_CLUSTERS 1024 @@ -149,17 +147,14 @@ static char parse_drive_from_path(const char **path_ptr) { // Normalize path (remove .., ., etc) void fat32_normalize_path(const char *path, char *normalized) { - // Basic normalization - // If we have a drive letter, strip it for internal processing logic if needed, - // but the output 'normalized' should conceptually be the path *on that drive*. + char temp[FAT32_MAX_PATH]; int temp_len = 0; const char *p = path; char drive = parse_drive_from_path(&p); - // Initialize with current directory or root - // If drive changed, we assume root of that drive + if (p[0] == '/') { fs_strcpy(temp, "/"); temp_len = 1; @@ -632,7 +627,6 @@ static FAT32_FileHandle* realfs_open(char drive, const char *path, const char *m } if (!found) { - // Check if we want to create file if ((mode[0] == 'w' || mode[0] == 'a') && *p == 0) { // Create file logic char dos_name[11]; @@ -1030,7 +1024,6 @@ static bool realfs_delete(char drive, const char *path) { if (*p == 0) break; // End of path } - // We found the file entry - now delete it // 1. Mark directory entry as deleted uint8_t *entry_buf = (uint8_t*)kmalloc(512); @@ -1090,16 +1083,11 @@ static int realfs_list_directory(char drive, const char *path, FAT32_FileInfo *e } FAT32_Volume *vol = &volumes[vol_idx]; - // Find directory start cluster - // Reuse realfs_open logic basically to find the cluster - // but without creating a handle. - // For simplicity, just use realfs_open and then read the directory entries + FAT32_FileHandle *dir_handle = realfs_open(drive, path, "r"); if (!dir_handle) return 0; - // Extract start_cluster BEFORE closing the handle uint32_t current_cluster = dir_handle->start_cluster; - // We don't use the handle for reading via realfs_read because directories are special fat32_close(dir_handle); // Return to pool - this invalidates the handle int count = 0; @@ -1236,9 +1224,7 @@ void fat32_close(FAT32_FileHandle *handle) { entry->start_cluster_high = (handle->start_cluster >> 16); entry->start_cluster_low = (handle->start_cluster & 0xFFFF); } - // Write back with error checking if (d->write_sector(d, handle->dir_sector, buf) != 0) { - // Write failed - at least we tried } } kfree(buf); @@ -1506,26 +1492,13 @@ bool fat32_is_directory(const char *path) { } else { FAT32_FileHandle *fh = realfs_open(drive, p, "r"); if (fh) { - // Wait, open checks if file/dir. - // We need to check if what we opened is a directory. - // realfs_open returns handle for directory too if strictly reading? - // Actually my realfs_open logic tries to find the entry. - // If it returns a handle, how do we know if it was a dir? - // Handle doesn't store attributes. - // But we can check if size == 0 (often for dirs) or inferred from how we opened it. - // Better: use realfs_list_directory check or modify open to return attributes? - // For now, let's assume if we can open it and it has size 0 (or we opened root), it's dir. - // This is imperfect. - // Correct way: Add attributes to FAT32_FileHandle or separate check function. - // Let's rely on naming convention or just return false for now if not root. + if (fs_strcmp(p, "/") == 0 || fs_strcmp(p, "") == 0) is_dir = true; else { - // Hack: check if list_directory returns > 0 entries? No empty dirs exists. - // We need to improve realfs_open to store attr. + } fat32_close(fh); } - // Workaround: assume true if path ends in /? No. } asm volatile("push %0; popfq" : : "r"(rflags)); @@ -1586,23 +1559,15 @@ bool fat32_chdir(const char *path) { } } - // Change dir on current drive if (fat32_is_directory(path)) { - // Normalize and set if (drive == 'A') { char normalized[FAT32_MAX_PATH]; fat32_normalize_path(p, normalized); fs_strcpy(current_dir, normalized); } else { - // For real drive, just store path - // Need a way to validate path exists on real drive first - // fat32_is_directory call above should suffice? - // But my realfs is_directory is weak. fs_strcpy(current_dir, p); - // Ensure leading slash if (current_dir[0] != '/') { - // Prepend / - // ... (skip for brevity, assume absolute paths mostly) + } } asm volatile("push %0; popfq" : : "r"(rflags)); diff --git a/src/kernel/idt.c b/src/kernel/idt.c index f1f2fc0..60d8f02 100644 --- a/src/kernel/idt.c +++ b/src/kernel/idt.c @@ -3,7 +3,7 @@ extern void serial_write(const char *str); -// Simple hex printer for debugging exceptions +// Simple hex printer for debugging static void print_hex(uint64_t val) { const char* digits = "0123456789ABCDEF"; char buf[17]; @@ -19,40 +19,64 @@ static void print_hex(uint64_t val) { #include "process.h" #include "cmd.h" +void kernel_panic(registers_t *regs, const char *error_name); + +static const char *exception_messages[] = { + "Division By Zero", + "Debug", + "Non-Maskable Interrupt", + "Breakpoint", + "Into Detected Overflow", + "Out of Bounds", + "Invalid Opcode", + "No Coprocessor", + "Double Fault", + "Coprocessor Segment Overrun", + "Bad TSS", + "Segment Not Present", + "Stack Fault", + "General Protection Fault", + "Page Fault", + "Unknown Interrupt", + "Coprocessor Fault", + "Alignment Check", + "Machine Check", + "SIMD Floating-Point Exception", + "Virtualization Exception", + "Control Protection Exception", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Hypervisor Injection Exception", + "VMM Communication Exception", + "Security Exception", + "Reserved" +}; + uint64_t exception_handler_c(registers_t *regs) { uint64_t vector = regs->int_no; - uint64_t rip = regs->rip; - uint64_t cr2; - asm volatile("mov %%cr2, %0" : "=r"(cr2)); - + + // Serial Mirror serial_write("\n*** EXCEPTION ***\nVector: "); print_hex(vector); - serial_write("\nError Code: "); - print_hex(regs->err_code); - serial_write("\nRIP: "); - print_hex(rip); - serial_write("\nCR2: "); - print_hex(cr2); - - // Mirror to shell - if (cmd_get_cursor_col() != 0) cmd_write("\n"); - cmd_write("*** EXCEPTION ***\nVector: "); cmd_write_hex(vector); - cmd_write("\nError Code: "); cmd_write_hex(regs->err_code); - cmd_write("\nRIP: "); cmd_write_hex(rip); - cmd_write("\nCR2: "); cmd_write_hex(cr2); - cmd_write("\n"); - - // Filter by CS selector to check if we are in user mode (RPL=3) + if ((regs->cs & 0x3) != 0) { serial_write("\nUSER MODE EXCEPTION - Terminating process.\n"); - cmd_write("USER MODE EXCEPTION - Terminating process.\n"); + if (cmd_get_cursor_col() != 0) cmd_write("\n"); + cmd_write("*** USER EXCEPTION ***\nVector: "); cmd_write_hex(vector); + cmd_write("\nRIP: "); cmd_write_hex(regs->rip); + cmd_write("\nTerminating process.\n"); return process_terminate_current(); } - serial_write("\nKERNEL PANIC - CPU HALTED.\n"); - cmd_write("KERNEL PANIC - CPU HALTED.\n"); - while(1) { asm volatile("cli; hlt"); } - return (uint64_t)regs; // Unreachable but for completeness + // Kernel mode exception + const char *name = (vector < 32) ? exception_messages[vector] : "Unknown Kernel Exception"; + kernel_panic(regs, name); + + return (uint64_t)regs; // Unreachable } #define IDT_ENTRIES 256 @@ -145,10 +169,72 @@ void idt_register_interrupts(void) { idt_set_gate(44, isr12_wrapper, cs, 0x8E); // Mouse (IRQ 12) // Exceptions - extern void isr8_wrapper(void); - extern void isr14_wrapper(void); - idt_set_gate(8, isr8_wrapper, cs, 0x8E); // Double Fault - idt_set_gate(14, isr14_wrapper, cs, 0x8E); // Page Fault + extern void exc0_wrapper(void); + extern void exc1_wrapper(void); + extern void exc2_wrapper(void); + extern void exc3_wrapper(void); + extern void exc4_wrapper(void); + extern void exc5_wrapper(void); + extern void exc6_wrapper(void); + extern void exc7_wrapper(void); + extern void exc8_wrapper(void); + extern void exc9_wrapper(void); + extern void exc10_wrapper(void); + extern void exc11_wrapper(void); + extern void exc12_wrapper(void); + extern void exc13_wrapper(void); + extern void exc14_wrapper(void); + extern void exc15_wrapper(void); + extern void exc16_wrapper(void); + extern void exc17_wrapper(void); + extern void exc18_wrapper(void); + extern void exc19_wrapper(void); + extern void exc20_wrapper(void); + extern void exc21_wrapper(void); + extern void exc22_wrapper(void); + extern void exc23_wrapper(void); + extern void exc24_wrapper(void); + extern void exc25_wrapper(void); + extern void exc26_wrapper(void); + extern void exc27_wrapper(void); + extern void exc28_wrapper(void); + extern void exc29_wrapper(void); + extern void exc30_wrapper(void); + extern void exc31_wrapper(void); + + idt_set_gate(0, exc0_wrapper, cs, 0x8E); + idt_set_gate(1, exc1_wrapper, cs, 0x8E); + idt_set_gate(2, exc2_wrapper, cs, 0x8E); + idt_set_gate(3, exc3_wrapper, cs, 0x8E); + idt_set_gate(4, exc4_wrapper, cs, 0x8E); + idt_set_gate(5, exc5_wrapper, cs, 0x8E); + idt_set_gate(6, exc6_wrapper, cs, 0x8E); + idt_set_gate(7, exc7_wrapper, cs, 0x8E); + idt_set_gate(8, exc8_wrapper, cs, 0x8E); + idt_set_gate(9, exc9_wrapper, cs, 0x8E); + idt_set_gate(10, exc10_wrapper, cs, 0x8E); + idt_set_gate(11, exc11_wrapper, cs, 0x8E); + idt_set_gate(12, exc12_wrapper, cs, 0x8E); + idt_set_gate(13, exc13_wrapper, cs, 0x8E); + idt_set_gate(14, exc14_wrapper, cs, 0x8E); + idt_set_gate(15, exc15_wrapper, cs, 0x8E); + idt_set_gate(16, exc16_wrapper, cs, 0x8E); + idt_set_gate(17, exc17_wrapper, cs, 0x8E); + idt_set_gate(18, exc18_wrapper, cs, 0x8E); + idt_set_gate(19, exc19_wrapper, cs, 0x8E); + idt_set_gate(20, exc20_wrapper, cs, 0x8E); + idt_set_gate(21, exc21_wrapper, cs, 0x8E); + idt_set_gate(22, exc22_wrapper, cs, 0x8E); + idt_set_gate(23, exc23_wrapper, cs, 0x8E); + idt_set_gate(24, exc24_wrapper, cs, 0x8E); + idt_set_gate(25, exc25_wrapper, cs, 0x8E); + idt_set_gate(26, exc26_wrapper, cs, 0x8E); + idt_set_gate(27, exc27_wrapper, cs, 0x8E); + idt_set_gate(28, exc28_wrapper, cs, 0x8E); + idt_set_gate(29, exc29_wrapper, cs, 0x8E); + idt_set_gate(30, exc30_wrapper, cs, 0x8E); + idt_set_gate(31, exc31_wrapper, cs, 0x8E); + } void idt_load(void) { diff --git a/src/kernel/interrupts.asm b/src/kernel/interrupts.asm index df80303..2a792e4 100644 --- a/src/kernel/interrupts.asm +++ b/src/kernel/interrupts.asm @@ -74,28 +74,66 @@ isr1_wrapper: isr12_wrapper: ISR_NOERRCODE mouse_handler, 44 -; Common exception macro -%macro EXCEPTION_ERRCODE 1 -isr%1_wrapper: - push %1 +; Common exception macro for exceptions WITHOUT error code +%macro EXCEPTION_NOERRCODE 1 +global exc%1_wrapper +exc%1_wrapper: + push 0 ; Dummy error code + push %1 ; Vector jmp exception_common %endmacro -; Exception 8: Double Fault (has error code) -EXCEPTION_ERRCODE 8 +; Common exception macro for exceptions WITH error code +%macro EXCEPTION_ERRCODE 1 +global exc%1_wrapper +exc%1_wrapper: + push %1 ; Vector + jmp exception_common +%endmacro -; Exception 14: Page Fault (has error code) -EXCEPTION_ERRCODE 14 +; Define all 32 standard exceptions +EXCEPTION_NOERRCODE 0 ; Divide Error +EXCEPTION_NOERRCODE 1 ; Debug +EXCEPTION_NOERRCODE 2 ; NMI +EXCEPTION_NOERRCODE 3 ; Breakpoint +EXCEPTION_NOERRCODE 4 ; Overflow +EXCEPTION_NOERRCODE 5 ; Bound Range Exceeded +EXCEPTION_NOERRCODE 6 ; Invalid Opcode +EXCEPTION_NOERRCODE 7 ; Device Not Available +EXCEPTION_ERRCODE 8 ; Double Fault +EXCEPTION_NOERRCODE 9 ; Coprocessor Segment Overrun +EXCEPTION_ERRCODE 10 ; Invalid TSS +EXCEPTION_ERRCODE 11 ; Segment Not Present +EXCEPTION_ERRCODE 12 ; Stack-Segment Fault +EXCEPTION_ERRCODE 13 ; General Protection Fault +EXCEPTION_ERRCODE 14 ; Page Fault +EXCEPTION_NOERRCODE 15 ; Reserved +EXCEPTION_NOERRCODE 16 ; x87 Floating-Point Exception +EXCEPTION_ERRCODE 17 ; Alignment Check +EXCEPTION_NOERRCODE 18 ; Machine Check +EXCEPTION_NOERRCODE 19 ; SIMD Floating-Point Exception +EXCEPTION_NOERRCODE 20 ; Virtualization Exception +EXCEPTION_ERRCODE 21 ; Control Protection Exception +EXCEPTION_NOERRCODE 22 ; Reserved +EXCEPTION_NOERRCODE 23 ; Reserved +EXCEPTION_NOERRCODE 24 ; Reserved +EXCEPTION_NOERRCODE 25 ; Reserved +EXCEPTION_NOERRCODE 26 ; Reserved +EXCEPTION_NOERRCODE 27 ; Reserved +EXCEPTION_NOERRCODE 28 ; Hypervisor Injection Exception +EXCEPTION_ERRCODE 29 ; VMM Communication Exception +EXCEPTION_ERRCODE 30 ; Security Exception +EXCEPTION_NOERRCODE 31 ; Reserved exception_common: - ; Save registers + ; Save registers (registers_t structure) push rax + push rbx push rcx push rdx - push rbx push rbp - push rsi push rdi + push rsi push r8 push r9 push r10 @@ -105,14 +143,15 @@ exception_common: push r14 push r15 - ; Call C handler: uint64_t exception_handler_c(registers_t *regs) + ; Pass current RSP as 1st argument (registers_t*) mov rdi, rsp + call exception_handler_c ; Switch stack if needed (for process termination) mov rsp, rax - ; Restore (in case we want to return, but usually we halt if kernel) + ; Restore registers pop r15 pop r14 pop r13 @@ -121,12 +160,13 @@ exception_common: pop r10 pop r9 pop r8 - pop rdi pop rsi + pop rdi pop rbp - pop rbx pop rdx pop rcx + pop rbx pop rax add rsp, 16 ; drop vector and error code iretq + diff --git a/src/kernel/main.c b/src/kernel/main.c index f285b2d..0c41312 100644 --- a/src/kernel/main.c +++ b/src/kernel/main.c @@ -58,7 +58,6 @@ static void hcf(void) { } } -// Simple serial port initialization and output for debugging static void init_serial() { outb(0x3F8 + 1, 0x00); outb(0x3F8 + 3, 0x80); @@ -84,7 +83,6 @@ void kmain(void) { platform_init(); serial_write("[DEBUG] platform_init OK\n"); - // 1. Memory Detection and Heap Init uint64_t heap_phys_addr = 0; size_t heap_size = 0; if (memmap_request.response != NULL) { @@ -99,7 +97,7 @@ void kmain(void) { } } - if (heap_size > 512 * 1024 * 1024) heap_size = 512 * 1024 * 1024; // Cap at 512MB + if (heap_size > 512 * 1024 * 1024) heap_size = 512 * 1024 * 1024; if (heap_phys_addr != 0) { memory_manager_init_at((void*)p2v(heap_phys_addr), heap_size); @@ -109,7 +107,6 @@ void kmain(void) { hcf(); } - // 2. Graphics Init if (framebuffer_request.response == NULL || framebuffer_request.response->framebuffer_count < 1) { serial_write("[DEBUG] No framebuffer! Halting.\n"); hcf(); @@ -119,19 +116,15 @@ void kmain(void) { graphics_init(fb); serial_write("[DEBUG] graphics_init OK\n"); - // 3. GDT & TSS Init gdt_init(); serial_write("[DEBUG] gdt_init OK\n"); - // 4. Paging Init paging_init(); serial_write("[DEBUG] paging_init OK\n"); - // 5. Syscall Init syscall_init(); serial_write("[DEBUG] syscall_init OK\n"); - // 6. Interrupts Init idt_init(); idt_register_interrupts(); idt_load(); @@ -141,13 +134,11 @@ void kmain(void) { serial_write("[DEBUG] Skipping user mode test, proceeding with normal boot.\n"); - // Initialize FAT32 RAMFS and mount Limine modules fat32_init(); if (module_request.response != NULL) { for (uint64_t i = 0; i < module_request.response->module_count; i++) { struct limine_file *mod = module_request.response->modules[i]; - // mod->path typically starts with a '/' from Limine FAT32_FileHandle *fh = fat32_open(mod->path, "w"); if (fh && fh->valid) { fat32_write(fh, mod->address, mod->size); @@ -159,25 +150,20 @@ void kmain(void) { } } - int ENABLE_USER_TEST = 1; // Set to 1 to test User Mode ring 3 jump + int ENABLE_USER_TEST = 1; #ifdef ENABLE_USER_TEST process_init(); - // The desktop is PID 0 #endif - // 3. PS/2 Init (Mouse/Keyboard) asm("cli"); ps2_init(); asm("sti"); - // 4. Window Manager Init (Draws initial desktop) wm_init(); - // Re-enable interrupts since we removed sti from idt_load asm volatile("sti"); - // 5. Main loop - just wait for interrupts - // Timer interrupt will drive the redraw system + while (1) { wm_process_input(); wm_process_deferred_thumbs(); diff --git a/src/kernel/memory_manager.c b/src/kernel/memory_manager.c index ca1b92c..3aa10f1 100644 --- a/src/kernel/memory_manager.c +++ b/src/kernel/memory_manager.c @@ -159,11 +159,9 @@ void memory_manager_init_at(void *pool_address, size_t pool_size) { } 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) { @@ -183,7 +181,6 @@ void* kmalloc_aligned(size_t size, size_t alignment) { return NULL; } - // Check if we can allocate if (total_allocated + size > memory_pool_size) { asm volatile("push %0; popfq" : : "r"(rflags)); return NULL; diff --git a/src/kernel/paging.c b/src/kernel/paging.c index 7265031..442e5dd 100644 --- a/src/kernel/paging.c +++ b/src/kernel/paging.c @@ -19,7 +19,6 @@ static void write_cr3(uint64_t cr3) { // Helper to allocate a page table and clear it static uint64_t alloc_page_table_phys(void) { - // We allocate a page table in Virtual Memory (HHDM) void* ptr = kmalloc(PAGE_SIZE * 2); if (!ptr) return 0; @@ -41,8 +40,7 @@ static uint64_t alloc_page_table_phys(void) { } void paging_init(void) { - // Limine sets up a highly mapped page table for us. - // CR3 contains the physical address of the PML4. + current_pml4_phys = read_cr3() & PT_ADDR_MASK; } diff --git a/src/kernel/panic.c b/src/kernel/panic.c new file mode 100644 index 0000000..b3f1bab --- /dev/null +++ b/src/kernel/panic.c @@ -0,0 +1,116 @@ +#include "process.h" +#include "graphics.h" +#include "io.h" + +extern void serial_write(const char *str); + +static void draw_string_centered(int y, const char *s, uint32_t color) { + if (!s) return; + int len = 0; + while (s[len]) len++; + int x = (get_screen_width() - (len * 8)) / 2; + draw_string(x, y, s, color); +} + +void kernel_panic(registers_t *regs, const char *error_name) { + // Disable interrupts to prevent nested panics + asm volatile("cli"); + + // Clear back buffer to black + graphics_clear_back_buffer(0x00000000); + + int sh = get_screen_height(); + int cy = sh / 2; + + // Draw header + draw_string_centered(cy - 150, "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!", 0xFFFF0000); + draw_string_centered(cy - 130, "KERNEL EXCEPTION OCCURRED", 0xFFFFFFFF); + draw_string_centered(cy - 110, "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!", 0xFFFF0000); + + // Error name + char err_buf[256]; + int pos = 0; + const char *prefix = "Exception: "; + while(prefix[pos]) { err_buf[pos] = prefix[pos]; pos++; } + int i = 0; + while(error_name[i]) { err_buf[pos++] = error_name[i++]; } + err_buf[pos] = 0; + draw_string_centered(cy - 70, err_buf, 0xFFFFCC00); + + // Details - simplified centering by drawing them as a block or individually centered + char info_buf[64]; + + // Vector + pos = 0; + prefix = "Vector: "; + while(prefix[pos]) { info_buf[pos] = prefix[pos]; pos++; } + uint64_t v = regs->int_no; + const char* digits = "0123456789ABCDEF"; + info_buf[pos++] = '0'; info_buf[pos++] = 'x'; + for (int i = 15; i >= 0; i--) { + info_buf[pos + i] = digits[v & 0xF]; + v >>= 4; + } + info_buf[pos + 16] = 0; + draw_string_centered(cy - 40, info_buf, 0xFFFFFFFF); + + // Error Code + pos = 0; + prefix = "Error Code: "; + while(prefix[pos]) { info_buf[pos] = prefix[pos]; pos++; } + v = regs->err_code; + info_buf[pos++] = '0'; info_buf[pos++] = 'x'; + for (int i = 15; i >= 0; i--) { + info_buf[pos + i] = digits[v & 0xF]; + v >>= 4; + } + info_buf[pos + 16] = 0; + draw_string_centered(cy - 20, info_buf, 0xFFFFFFFF); + + // RIP + pos = 0; + prefix = "RIP: "; + while(prefix[pos]) { info_buf[pos] = prefix[pos]; pos++; } + v = regs->rip; + info_buf[pos++] = '0'; info_buf[pos++] = 'x'; + for (int i = 15; i >= 0; i--) { + info_buf[pos + i] = digits[v & 0xF]; + v >>= 4; + } + info_buf[pos + 16] = 0; + draw_string_centered(cy, info_buf, 0xFFFFFFFF); + + // CR2 for page faults + if (regs->int_no == 14) { + uint64_t cr2; + asm volatile("mov %%cr2, %0" : "=r"(cr2)); + pos = 0; + prefix = "CR2: "; + while(prefix[pos]) { info_buf[pos] = prefix[pos]; pos++; } + info_buf[pos++] = '0'; info_buf[pos++] = 'x'; + for (int i = 15; i >= 0; i--) { + info_buf[pos + i] = digits[cr2 & 0xF]; + cr2 >>= 4; + } + info_buf[pos + 16] = 0; + draw_string_centered(cy + 20, info_buf, 0xFFFF5555); + } + + // Message + draw_string_centered(cy + 100, "The system has been halted to prevent damage.", 0xFFFFFFFF); + draw_string_centered(cy + 120, "Please restart your computer.", 0xFFAAAAAA); + + + // Flip buffer to screen + graphics_mark_screen_dirty(); + graphics_flip_buffer(); + + serial_write("\n*** KERNEL PANIC ***\n"); + serial_write(error_name); + serial_write("\n"); + + // Halt + while(1) { + asm volatile("cli; hlt"); + } +} diff --git a/src/kernel/syscall.c b/src/kernel/syscall.c index ca093dc..0da7767 100644 --- a/src/kernel/syscall.c +++ b/src/kernel/syscall.c @@ -336,8 +336,6 @@ uint64_t syscall_handler_c(uint64_t syscall_num, uint64_t arg1, uint64_t arg2, u asm volatile("pushfq; pop %0; cli" : "=r"(rflags)); if (win->pixels) { - // String clipping is handled by draw_char -> put_pixel, - // but we ensure coordinate sanity here if (ux >= -100 && ux < win->w && uy >= -100 && uy < (win->h - 20)) { graphics_set_render_target(win->pixels, win->w, win->h - 20); draw_string(ux, uy, kernel_str, color); diff --git a/src/kernel/userland/txtedit.c b/src/kernel/userland/txtedit.c index 25b42c3..fd7e3c3 100644 --- a/src/kernel/userland/txtedit.c +++ b/src/kernel/userland/txtedit.c @@ -325,8 +325,6 @@ static void editor_paint(ui_window_t win) { ui_draw_rounded_rect_filled(win, padding, status_y + 2, content_width, footer_h - 4, 6, COLOR_DARK_PANEL); char status_text[128]; - // Simple manual sprintf-like functionality for BoredOS userspace - // We'll just draw parts for now as before but cleaned up ui_draw_string(win, padding + 15, status_y + 5, "Line:", COLOR_DKGRAY); char line_str[32]; diff --git a/src/kernel/vm.c b/src/kernel/vm.c index 26d52a0..d83f8f6 100644 --- a/src/kernel/vm.c +++ b/src/kernel/vm.c @@ -464,15 +464,10 @@ int vm_exec(const uint8_t *code, int code_size) { vm_reset(); - // Reset Graphics Overlay vm_rect_count = 0; wm_custom_paint_hook = vm_paint_overlay; - // Copy data segment if any? - // For this simple VM, we will copy the ENTIRE bytecode to the start of memory - // So code and data share the same space (Von Neumann) - // But we need to be careful not to overwrite running code if we write to it - + // Safety check if (code_size > VM_MEMORY_SIZE) { cmd_write("VM Error: Binary too large\n"); @@ -489,13 +484,7 @@ int vm_exec(const uint8_t *code, int code_size) { while (pc < code_size) { uint8_t op = memory[pc++]; - // DEBUGGING - /* - cmd_write("PC:"); cmd_write_int(pc-1); - cmd_write(" OP:"); cmd_write_int(op); - cmd_write(" SP:"); cmd_write_int(sp); - cmd_write("\n"); - */ + switch (op) { case OP_HALT: