From e4603792b634cc1722a89f26ab83410d72dfa63f Mon Sep 17 00:00:00 2001 From: boreddevnl Date: Mon, 13 Apr 2026 12:17:39 +0200 Subject: [PATCH] FEAT: Verbose boot --- src/core/kconsole.c | 95 ++++++++++++++++++++++++++++++ src/core/kconsole.h | 13 ++++ src/core/main.c | 124 ++++++++++++++++++++++++++------------- src/dev/disk_manager.c | 23 +++++--- src/fs/vfs.c | 2 +- src/mem/memory_manager.c | 2 +- src/net/lwip/core/tcp.c | 1 - src/net/network.c | 4 +- src/sys/process.c | 4 +- src/sys/smp.c | 7 ++- src/sys/syscall.c | 29 +++++---- src/userland/net/net.c | 4 +- src/wm/graphics.c | 47 +++++++++++++-- src/wm/graphics.h | 1 + src/wm/wallpaper.c | 2 +- src/wm/wm.c | 25 ++++++-- 16 files changed, 296 insertions(+), 87 deletions(-) create mode 100644 src/core/kconsole.c create mode 100644 src/core/kconsole.h diff --git a/src/core/kconsole.c b/src/core/kconsole.c new file mode 100644 index 0000000..8bed8bb --- /dev/null +++ b/src/core/kconsole.c @@ -0,0 +1,95 @@ +#include "kconsole.h" +#include "graphics.h" +#include "sys/spinlock.h" +#include + +static spinlock_t console_lock = SPINLOCK_INIT; +static int cursor_x = 0; +static int cursor_y = 0; +static bool kconsole_active = false; +static uint32_t text_color = 0xFFFFFFFF; // White + +#define CHAR_WIDTH 8 +#define CHAR_HEIGHT 10 + +void kconsole_init(void) { + cursor_x = 10; + cursor_y = 10; + kconsole_active = true; + + // Initial clear screen during boot + graphics_clear_back_buffer(0x00000000); + graphics_mark_screen_dirty(); + graphics_flip_buffer(); +} + +void kconsole_set_active(bool active) { + kconsole_active = active; +} + +void kconsole_set_color(uint32_t color) { + uint64_t flags = spinlock_acquire_irqsave(&console_lock); + text_color = color; + spinlock_release_irqrestore(&console_lock, flags); +} + +static void kconsole_scroll(void) { + if (cursor_y + CHAR_HEIGHT >= get_screen_height() - 10) { + graphics_scroll_back_buffer(CHAR_HEIGHT); + cursor_y -= CHAR_HEIGHT; + graphics_mark_screen_dirty(); + graphics_flip_buffer(); + } +} + +static void kconsole_putc_nolock(char c) { + if (!kconsole_active) return; + + if (c == '\n') { + cursor_x = 10; + cursor_y += CHAR_HEIGHT; + kconsole_scroll(); + graphics_flip_buffer(); + return; + } + + if (c == '\r') { + cursor_x = 10; + return; + } + + if (c == '\t') { + cursor_x += CHAR_WIDTH * 4; + return; + } + + // Draw character + draw_char_bitmap(cursor_x, cursor_y, c, text_color); + graphics_mark_screen_dirty(); + + cursor_x += CHAR_WIDTH; + if (cursor_x + CHAR_WIDTH >= get_screen_width() - 10) { + cursor_x = 10; + cursor_y += CHAR_HEIGHT; + kconsole_scroll(); + } +} + +void kconsole_putc(char c) { + uint64_t flags = spinlock_acquire_irqsave(&console_lock); + kconsole_putc_nolock(c); + spinlock_release_irqrestore(&console_lock, flags); +} + +void kconsole_write(const char *s) { + if (!s) return; + + uint64_t flags = spinlock_acquire_irqsave(&console_lock); + while (*s) { + kconsole_putc_nolock(*s++); + } + + // Flip buffer after a write batch during boot + graphics_flip_buffer(); + spinlock_release_irqrestore(&console_lock, flags); +} diff --git a/src/core/kconsole.h b/src/core/kconsole.h new file mode 100644 index 0000000..c09bcf8 --- /dev/null +++ b/src/core/kconsole.h @@ -0,0 +1,13 @@ +#ifndef KCONSOLE_H +#define KCONSOLE_H + +#include +#include + +void kconsole_init(void); +void kconsole_set_color(uint32_t color); +void kconsole_putc(char c); +void kconsole_write(const char *s); +void kconsole_set_active(bool active); + +#endif // KCONSOLE_H diff --git a/src/core/main.c b/src/core/main.c index be1bb3c..777dc40 100644 --- a/src/core/main.c +++ b/src/core/main.c @@ -18,6 +18,7 @@ #include "fat32.h" #include "tar.h" #include "vfs.h" +#include "core/kconsole.h" #include "memory_manager.h" #include "platform.h" #include "wallpaper.h" @@ -91,26 +92,70 @@ static void init_serial() { outb(0x3F8 + 4, 0x0B); } +static spinlock_t serial_lock = SPINLOCK_INIT; + void serial_write(const char *str) { - while (*str) { + uint64_t flags = spinlock_acquire_irqsave(&serial_lock); + const char *p = str; + while (*p) { + char c = *p++; while ((inb(0x3F8 + 5) & 0x20) == 0); - outb(0x3F8, *str++); + outb(0x3F8, c); } + kconsole_write(str); + spinlock_release_irqrestore(&serial_lock, flags); +} + +static void serial_write_num_locked(uint32_t n) { + if (n >= 10) serial_write_num_locked(n / 10); + char c = '0' + (n % 10); + while ((inb(0x3F8 + 5) & 0x20) == 0); + outb(0x3F8, c); + kconsole_putc(c); } void serial_write_num(uint32_t n) { - if (n >= 10) serial_write_num(n / 10); + uint64_t flags = spinlock_acquire_irqsave(&serial_lock); + serial_write_num_locked(n); + spinlock_release_irqrestore(&serial_lock, flags); +} + +static void serial_write_hex_locked(uint64_t n) { + char *hex = "0123456789ABCDEF"; + if (n >= 16) serial_write_hex_locked(n / 16); + char c = hex[n % 16]; while ((inb(0x3F8 + 5) & 0x20) == 0); - outb(0x3F8, '0' + (n % 10)); + outb(0x3F8, c); + kconsole_putc(c); } void serial_write_hex(uint64_t n) { - char *hex = "0123456789ABCDEF"; - if (n >= 16) serial_write_hex(n / 16); - while ((inb(0x3F8 + 5) & 0x20) == 0); - outb(0x3F8, hex[n % 16]); + uint64_t flags = spinlock_acquire_irqsave(&serial_lock); + serial_write_hex_locked(n); + spinlock_release_irqrestore(&serial_lock, flags); } +void log_ok(const char *msg) { + serial_write("[ "); + kconsole_set_color(0xFF00FF00); + serial_write("OK"); + kconsole_set_color(0xFFFFFFFF); + serial_write(" ] "); + serial_write(msg); + serial_write("\n"); +} + +void log_fail(const char *msg) { + serial_write("[ "); + kconsole_set_color(0xFFFF0000); + serial_write("FAIL"); + kconsole_set_color(0xFFFFFFFF); + serial_write(" ] "); + serial_write(msg); + serial_write("\n"); +} + + // Kernel Entry Point static void fat32_mkdir_recursive(const char *path) { @@ -141,64 +186,65 @@ static void fat32_mkdir_recursive(const char *path) { void kmain(void) { init_serial(); vfs_init(); - serial_write("\n[DEBUG] Entering kmain...\n"); + serial_write("\n"); platform_init(); - serial_write("[DEBUG] platform_init OK\n"); + log_ok("Platform initialized"); extern uint64_t hhdm_offset; extern uint64_t kernel_phys_base; extern uint64_t kernel_virt_base; - serial_write("[DEBUG] HHDM Offset: 0x"); + serial_write("[INIT] HHDM Offset: 0x"); serial_write_hex(hhdm_offset); serial_write("\n"); - serial_write("[DEBUG] Kernel Phys: 0x"); + serial_write("[INIT] Kernel Phys: 0x"); serial_write_hex(kernel_phys_base); serial_write("\n"); - serial_write("[DEBUG] Kernel Virt: 0x"); + serial_write("[INIT] Kernel Virt: 0x"); serial_write_hex(kernel_virt_base); serial_write("\n"); - if (memmap_request.response != NULL) { - // The memory manager will now scan the memory map and manage all usable regions. - memory_manager_init_from_memmap(memmap_request.response); - serial_write("[DEBUG] memory_manager_init OK\n"); - smp_init_bsp(); - serial_write("[DEBUG] smp_init_bsp OK\n"); - } else { - serial_write("[DEBUG] ERROR: No usable memory for heap! Check Limine memmap.\n"); - hcf(); - } - if (framebuffer_request.response == NULL || framebuffer_request.response->framebuffer_count < 1) { - serial_write("[DEBUG] No framebuffer! Halting.\n"); + serial_write("[INIT] No framebuffer! Halting.\n"); hcf(); } struct limine_framebuffer *fb = framebuffer_request.response->framebuffers[0]; graphics_init(fb); - serial_write("[DEBUG] graphics_init OK\n"); + kconsole_init(); + log_ok("Graphics and Console ready"); + + if (memmap_request.response != NULL) { + // The memory manager will now scan the memory map and manage all usable regions. + memory_manager_init_from_memmap(memmap_request.response); + log_ok("Memory manager ready"); + smp_init_bsp(); + log_ok("SMP BSP initialized"); + } else { + log_fail("No usable memory for heap! Check Limine memmap."); + hcf(); + } gdt_init(); - serial_write("[DEBUG] gdt_init OK\n"); + log_ok("GDT initialized"); paging_init(); - serial_write("[DEBUG] paging_init OK\n"); + log_ok("Paging ready"); syscall_init(); - serial_write("[DEBUG] syscall_init OK\n"); + log_ok("Syscalls ready"); idt_init(); idt_register_interrupts(); idt_load(); - serial_write("[DEBUG] idt_init OK\n"); + log_ok("IDT ready"); process_init(); fat32_init(); - serial_write("[DEBUG] fat32_init OK\n"); + log_ok("FAT32 ready"); fat32_mkdir("/bin"); fat32_mkdir("/Library"); fat32_mkdir("/Library/images"); @@ -214,11 +260,9 @@ void kmain(void) { vfs_mount("/proc", "procfs", "procfs", procfs_get_ops(), NULL); if (module_request.response == NULL) { - serial_write("[DEBUG] ERROR: Limine Module Response is NULL!\n"); + log_fail("Limine module response NULL"); } else { - serial_write("[DEBUG] Limine Module Response found. Count: "); - serial_write_num(module_request.response->module_count); - serial_write("\n"); + log_ok("Limine modules loaded"); for (uint64_t i = 0; i < module_request.response->module_count; i++) { struct limine_file *mod = module_request.response->modules[i]; @@ -230,7 +274,7 @@ void kmain(void) { while(clean_path[len]) len++; if (len >= 4 && clean_path[len-4] == '.' && clean_path[len-3] == 't' && clean_path[len-2] == 'a' && clean_path[len-1] == 'r') { - serial_write("[DEBUG] Parsing TAR initrd: "); + serial_write("[INIT] Parsing TAR initrd: "); serial_write(clean_path); serial_write("\n"); tar_parse(mod->address, mod->size); @@ -260,7 +304,7 @@ void kmain(void) { // Initialize fonts now that FAT32 and modules are loaded uint64_t current_rsp; asm volatile("mov %%rsp, %0" : "=r"(current_rsp)); - serial_write("[DEBUG] Stack Alignment: 0x"); + serial_write("[INIT] Stack Alignment: 0x"); serial_write_hex(current_rsp); serial_write("\n"); @@ -276,11 +320,9 @@ void kmain(void) { // Initialize SMP if (smp_request.response != NULL) { uint32_t online = smp_init(smp_request.response); - serial_write("[DEBUG] SMP init complete, CPUs online: "); - serial_write_num(online); - serial_write("\n"); + log_ok("SMP initialized"); } else { - serial_write("[DEBUG] No SMP response from bootloader\n"); + serial_write("[INIT] No SMP response from bootloader\n"); smp_init(NULL); } diff --git a/src/dev/disk_manager.c b/src/dev/disk_manager.c index a42f804..83645c8 100644 --- a/src/dev/disk_manager.c +++ b/src/dev/disk_manager.c @@ -21,6 +21,8 @@ static int next_sd_index = 0; // For sda, sdb, sdc... extern void serial_write(const char *str); extern void serial_write_num(uint64_t num); +extern void log_ok(const char *msg); +extern void log_fail(const char *msg); // === String Helpers === @@ -306,14 +308,16 @@ void disk_register_partition(Disk *parent, uint32_t lba_offset, uint32_t sector_ dm_strcpy(mount_path + 5, part->devname); if (vfs_mount(mount_path, part->devname, "fat32", fat32_get_realfs_ops(), vol)) { - serial_write("[VFS] Mounted "); - serial_write(mount_path); - serial_write(" to VFS\n"); + char ok_msg[64]; + dm_strcpy(ok_msg, "Mounted "); + dm_strcpy(ok_msg + 8, mount_path); + log_ok(ok_msg); wm_notify_fs_change(); } else { - serial_write("[VFS] Failed to mount "); - serial_write(mount_path); - serial_write("\n"); + char fail_msg[64]; + dm_strcpy(fail_msg, "Failed to mount "); + dm_strcpy(fail_msg + 16, mount_path); + log_fail(fail_msg); } } } @@ -499,7 +503,7 @@ void disk_manager_init(void) { next_sd_index = 0; next_drive_letter_idx = 0; - serial_write("[DISK] Disk manager initialized (VFS mode)\n"); + log_ok("Disk manager ready"); // NOTE: Ramdisk (A:) is no longer registered here. // RAMFS is managed directly by fat32.c and mounted at "/" via VFS. } @@ -509,12 +513,13 @@ void disk_manager_scan(void) { ahci_init(); if (ahci_get_port_count() == 0) { - serial_write("[DISK] No AHCI ports found, falling back to legacy IDE PIO...\n"); + serial_write("[DISK] No AHCI ports found, falling back to legacy IDE...\n"); try_add_ata_drive(ATA_PRIMARY_IO, false, "IDE Primary Master"); try_add_ata_drive(ATA_PRIMARY_IO, true, "IDE Primary Slave"); try_add_ata_drive(ATA_SECONDARY_IO, false, "IDE Secondary Master"); try_add_ata_drive(ATA_SECONDARY_IO, true, "IDE Secondary Slave"); + log_ok("IDE probing complete"); } else { - serial_write("[DISK] AHCI initialized successfully, skipping legacy IDE.\n"); + log_ok("AHCI ports initialized, skipping IDE"); } } \ No newline at end of file diff --git a/src/fs/vfs.c b/src/fs/vfs.c index a96f60c..b053b4a 100644 --- a/src/fs/vfs.c +++ b/src/fs/vfs.c @@ -189,7 +189,7 @@ void vfs_init(void) { } mount_count = 0; - serial_write("[VFS] Virtual File System initialized\n"); + serial_write("[VFS] Ready\n"); } // =============== diff --git a/src/mem/memory_manager.c b/src/mem/memory_manager.c index da1577b..8e63adc 100644 --- a/src/mem/memory_manager.c +++ b/src/mem/memory_manager.c @@ -479,7 +479,7 @@ void memory_validate(void) { } if (errors == 0) { - cmd_write("Memory validation: OK\n"); + cmd_write("Memory validation: [OK]\n"); } else { cmd_write("Memory validation failed with "); cmd_write_int(errors); diff --git a/src/net/lwip/core/tcp.c b/src/net/lwip/core/tcp.c index 371db2b..aae2ca0 100644 --- a/src/net/lwip/core/tcp.c +++ b/src/net/lwip/core/tcp.c @@ -1133,7 +1133,6 @@ tcp_connect(struct tcp_pcb *pcb, const ip_addr_t *ipaddr, u16_t port, (cpcb->remote_port == port) && ip_addr_cmp(&cpcb->local_ip, &pcb->local_ip) && ip_addr_cmp(&cpcb->remote_ip, ipaddr)) { - /* linux returns EISCONN here, but ERR_USE should be OK for us */ return ERR_USE; } } diff --git a/src/net/network.c b/src/net/network.c index 4ae2702..42a1630 100644 --- a/src/net/network.c +++ b/src/net/network.c @@ -88,7 +88,7 @@ int network_init(void) { ipv4_address_t ip; network_get_ipv4_address(&ip); extern void serial_write(const char *str); - serial_write("[NETWORK] IP Assigned: "); + serial_write("[NET] IP Assigned: "); char buf[32]; k_itoa(ip.bytes[0], buf); serial_write(buf); serial_write("."); k_itoa(ip.bytes[1], buf); serial_write(buf); serial_write("."); @@ -96,7 +96,7 @@ int network_init(void) { k_itoa(ip.bytes[3], buf); serial_write(buf); serial_write("\n"); } else { extern void serial_write(const char *str); - serial_write("[NETWORK] DHCP Failed during init\n"); + serial_write("[NET] DHCP Failed during init\n"); } // Set default DNS server (1.1.1.1) diff --git a/src/sys/process.c b/src/sys/process.c index dae4f42..e7268f5 100644 --- a/src/sys/process.c +++ b/src/sys/process.c @@ -212,7 +212,7 @@ process_t* process_create_elf(const char* filepath, const char* args_str) { size_t elf_load_size = 0; uint64_t entry_point = elf_load(filepath, new_proc->pml4_phys, &elf_load_size); if (entry_point == 0) { - serial_write("[PROCESS] Failed to load ELF: "); + serial_write("[PROC] Failed to load ELF: "); serial_write(filepath); serial_write("\n"); // We technically leak the page table here, but let's ignore cleanup for now @@ -371,7 +371,7 @@ process_t* process_create_elf(const char* filepath, const char* args_str) { current_process[0]->next = new_proc; spinlock_release_irqrestore(&runqueue_lock, rflags); - serial_write("[PROCESS] Spawned ELF Executable: "); + serial_write("[PROC] Exec: "); serial_write(filepath); serial_write("\n"); return new_proc; diff --git a/src/sys/smp.c b/src/sys/smp.c index 621dece..c2942b2 100644 --- a/src/sys/smp.c +++ b/src/sys/smp.c @@ -37,10 +37,13 @@ static uint32_t read_lapic_id(void) { } uint32_t smp_this_cpu_id(void) { - if (total_cpus <= 1) return 0; + if (total_cpus <= 1 || !cpu_states) return 0; // Use GS-based self-pointer to get the structure first - cpu_state_t *state; + cpu_state_t *state = NULL; + // Safely check GS:0. If GS is not set or base is 0, this should be handled carefully. + // In BoredOS, if GS is not set, this might still fault depending on address space. + // However, the cpu_states check above covers the most likely early-boot failure. asm volatile("movq %%gs:0, %0" : "=r"(state) : : "memory"); if (state) return state->cpu_id; diff --git a/src/sys/syscall.c b/src/sys/syscall.c index 8c5528f..204a908 100644 --- a/src/sys/syscall.c +++ b/src/sys/syscall.c @@ -203,12 +203,14 @@ static uint64_t syscall_handler_inner(registers_t *regs) { if (cmd == GUI_CMD_WINDOW_CREATE) { extern void serial_write(const char *str); - serial_write("Kernel: GUI_CMD_WINDOW_CREATE\n"); - const char *title = (const char *)arg2; + + serial_write("[WM] CreateWindow: "); + serial_write(title ? title : "Unknown"); + serial_write("\n"); uint64_t *u_params = (uint64_t *)arg3; if (!u_params) { - serial_write("Kernel: Error - params is NULL\n"); + serial_write("[WM] Error - params is NULL\n"); return 0; } @@ -216,14 +218,14 @@ static uint64_t syscall_handler_inner(registers_t *regs) { uint64_t params[4]; for (int i = 0; i < 4; i++) params[i] = u_params[i]; - serial_write("Kernel: Window params copied.\n"); + // params verified Window *win = kmalloc(sizeof(Window)); if (!win) { - serial_write("Kernel: Error - kmalloc failed for Window\n"); + serial_write("[WM] Error - kmalloc failed for Window\n"); return 0; } - serial_write("Kernel: Window allocated.\n"); + // win allocated extern void mem_memset(void *dest, int val, size_t len); mem_memset(win, 0, sizeof(Window)); @@ -240,11 +242,8 @@ static uint64_t syscall_handler_inner(registers_t *regs) { kernel_title[i] = title[i]; } kernel_title[title_len] = '\0'; - serial_write("Kernel: Title copied: "); - serial_write(kernel_title); - serial_write("\n"); } else { - serial_write("Kernel: Warning - kernel_title kmalloc failed\n"); + serial_write("[WM] Warning: kernel_title kmalloc failed\n"); } // Basic initialization @@ -254,7 +253,7 @@ static uint64_t syscall_handler_inner(registers_t *regs) { win->w = (int)params[2]; win->h = (int)params[3]; - serial_write("Kernel: Init win dims.\n"); + // dims ready // Sanity checks for dimensions if (win->w <= 0 || win->w > 4096) win->w = 400; @@ -268,7 +267,7 @@ static uint64_t syscall_handler_inner(registers_t *regs) { win->font = NULL; win->lock = SPINLOCK_INIT; - serial_write("Kernel: Dims initialized.\n"); + // ready size_t pixel_size = 0; // Safe allocation @@ -283,7 +282,7 @@ static uint64_t syscall_handler_inner(registers_t *regs) { win->comp_pixels = kmalloc(pixel_size); } - serial_write("Kernel: Buffers allocated.\n"); + // buffs ok if (win->pixels) { extern void mem_memset(void *dest, int val, size_t len); @@ -294,7 +293,7 @@ static uint64_t syscall_handler_inner(registers_t *regs) { mem_memset(win->comp_pixels, 0, pixel_size); } - serial_write("Kernel: Buffers cleared.\n"); + serial_write("[WM] Buffers ready\n"); // Set callbacks win->paint = user_window_paint; @@ -800,7 +799,7 @@ static uint64_t syscall_handler_inner(registers_t *regs) { Window *win = (Window *)arg2; if (win) { extern void serial_write(const char *str); - serial_write("Kernel: Setting window resizable to "); + serial_write("[WM] Resizable: "); serial_write(arg3 ? "true\n" : "false\n"); win->resizable = (arg3 != 0); } diff --git a/src/userland/net/net.c b/src/userland/net/net.c index 696df1c..bab675d 100644 --- a/src/userland/net/net.c +++ b/src/userland/net/net.c @@ -239,8 +239,8 @@ int main(int argc, char** argv) { } if (strcmp(argv[1], "init") == 0) { - if (sys_network_init() == 0) printf("Network OK\n"); - else printf("Network Fail\n"); + if (sys_network_init() == 0) printf("Network [OK]\n"); + else printf("Network [FAIL]\n"); return 0; } diff --git a/src/wm/graphics.c b/src/wm/graphics.c index 6986a28..b3b48ba 100644 --- a/src/wm/graphics.c +++ b/src/wm/graphics.c @@ -7,6 +7,7 @@ #include "io.h" #include "font_manager.h" #include "../mem/memory_manager.h" +#include "sys/spinlock.h" static struct limine_framebuffer *g_fb = NULL; static uint32_t g_bg_color = 0xFF696969; @@ -25,6 +26,7 @@ static int g_bg_image_h = 0; static bool g_use_image = false; static DirtyRect g_dirty = {0, 0, 0, 0, false}; +static spinlock_t graphics_lock = SPINLOCK_INIT; #define MAX_FB_WIDTH 2048 @@ -163,15 +165,19 @@ void graphics_mark_dirty(int x, int y, int w, int h) { return; } + uint64_t flags = spinlock_acquire_irqsave(&graphics_lock); merge_dirty_rect(x, y, w, h); + spinlock_release_irqrestore(&graphics_lock, flags); } void graphics_mark_screen_dirty(void) { + uint64_t flags = spinlock_acquire_irqsave(&graphics_lock); g_dirty.x = 0; g_dirty.y = 0; g_dirty.w = get_screen_width(); g_dirty.h = get_screen_height(); g_dirty.active = true; + spinlock_release_irqrestore(&graphics_lock, flags); } DirtyRect graphics_get_dirty_rect(void) { @@ -179,11 +185,9 @@ DirtyRect graphics_get_dirty_rect(void) { } void graphics_clear_dirty(void) { - extern uint64_t wm_lock_acquire(void); - extern void wm_lock_release(uint64_t); - uint64_t rflags = wm_lock_acquire(); + uint64_t flags = spinlock_acquire_irqsave(&graphics_lock); g_dirty.active = false; - wm_lock_release(rflags); + spinlock_release_irqrestore(&graphics_lock, flags); } void graphics_clear_dirty_no_lock(void) { @@ -796,12 +800,22 @@ void graphics_clear_back_buffer(uint32_t color) { } void graphics_flip_buffer(void) { - if (!g_fb || !g_dirty.active) return; + if (!g_fb) return; + + uint64_t flags = spinlock_acquire_irqsave(&graphics_lock); + if (!g_dirty.active) { + spinlock_release_irqrestore(&graphics_lock, flags); + return; + } int x = g_dirty.x; int y = g_dirty.y; int w = g_dirty.w; int h = g_dirty.h; + + // Clear dirty state + g_dirty.active = false; + spinlock_release_irqrestore(&graphics_lock, flags); if (x < 0) { w += x; x = 0; } if (y < 0) { h += y; y = 0; } @@ -1021,3 +1035,26 @@ void graphics_blit_buffer(uint32_t *src, int dst_x, int dst_y, int w, int h) { } } } +void graphics_scroll_back_buffer(int lines) { + if (!g_fb || lines <= 0 || lines >= (int)g_fb->height) return; + + extern uint64_t wm_lock_acquire(void); + extern void wm_lock_release(uint64_t); + uint64_t rflags = wm_lock_acquire(); + + int sw = (int)g_fb->width; + int sh = (int)g_fb->height; + + for (int y = 0; y < sh - lines; y++) { + uint32_t *dst = &g_back_buffer[y * sw]; + uint32_t *src = &g_back_buffer[(y + lines) * sw]; + for (int x = 0; x < sw; x++) dst[x] = src[x]; + } + + for (int y = sh - lines; y < sh; y++) { + uint32_t *dst = &g_back_buffer[y * sw]; + for (int x = 0; x < sw; x++) dst[x] = 0; + } + + wm_lock_release(rflags); +} diff --git a/src/wm/graphics.h b/src/wm/graphics.h index e072ef7..06b4110 100644 --- a/src/wm/graphics.h +++ b/src/wm/graphics.h @@ -56,6 +56,7 @@ void graphics_clear_dirty_no_lock(void); // Double buffering void graphics_flip_buffer(void); void graphics_clear_back_buffer(uint32_t color); +void graphics_scroll_back_buffer(int lines); // Clipping void graphics_set_clipping(int x, int y, int w, int h); diff --git a/src/wm/wallpaper.c b/src/wm/wallpaper.c index 1eb2981..08b0f1a 100644 --- a/src/wm/wallpaper.c +++ b/src/wm/wallpaper.c @@ -107,7 +107,7 @@ void wallpaper_process_pending(void) { const char *path = (const char *)pending_wallpaper_path; pending_wallpaper_path = NULL; - serial_str("[WP] Processing wallpaper: "); + serial_str("[WM] Processing wallpaper: "); serial_str(path); serial_str("\n"); diff --git a/src/wm/wm.c b/src/wm/wm.c index defb1e5..8eaec67 100644 --- a/src/wm/wm.c +++ b/src/wm/wm.c @@ -21,6 +21,7 @@ #include "disk.h" #include "../sys/work_queue.h" #include "../sys/smp.h" +#include "../core/kconsole.h" // Hello developer, @@ -44,6 +45,8 @@ void wm_lock_release(uint64_t flags) { } extern void serial_write(const char *str); +extern void log_ok(const char *msg); +extern void log_fail(const char *msg); static bool str_eq(const char *s1, const char *s2) { if (!s1 || !s2) return false; @@ -1919,7 +1922,7 @@ void wm_remove_window(Window *win) { force_redraw = true; } else { wm_lock_release(rflags); - serial_write("WM: Window not found in all_windows list!\n"); + log_fail("Window not found in all_windows list!"); return; } @@ -3096,25 +3099,33 @@ void wm_process_deferred_thumbs(void) { void wm_init(void) { disk_manager_init(); + log_ok("Disk Manager ready"); + disk_manager_scan(); + log_ok("Disk scanning complete"); cmd_init(); + log_ok("Command CLI ready"); + explorer_init(); + log_ok("Explorer ready"); + wallpaper_init(); + log_ok("Wallpaper engine ready"); file_index_init(); + log_ok("File Indexer ready"); - // Try to load the file index from persistent cache - // If it doesn't exist, queue an async build if (!file_index_load()) { - // No cache exists - queue async build to background + log_ok("No Index cache, background build started"); work_queue_submit(build_file_index_async, NULL); } else { - // Cache loaded - mark as ready + log_ok("Index cache loaded"); lumos_index_built = true; } refresh_desktop_icons(); + log_ok("Desktop icons refreshed"); // Initialize z-indices win_cmd.z_index = 0; @@ -3131,6 +3142,10 @@ void wm_init(void) { win_cmd.visible = false; force_redraw = true; + + serial_write("[WM] Initialization complete, transitioning to GUI\n"); + kconsole_set_active(false); + graphics_flip_buffer(); } uint32_t wm_get_ticks(void) {