From 0fbc3a5fc8f70f7975c6a7b88d8a446d50871218 Mon Sep 17 00:00:00 2001 From: boreddevnl Date: Fri, 8 May 2026 21:04:58 +0200 Subject: [PATCH] wm: implement root filesystem pivoting and persistence provisioning --- src/wm/explorer.c | 8 +++ src/wm/wallpaper.c | 59 +++++++++++++--- src/wm/wallpaper.h | 9 +-- src/wm/wm.c | 171 +++++++++++++++++++++++++++++++++++++++++++-- src/wm/wm.h | 1 + 5 files changed, 229 insertions(+), 19 deletions(-) diff --git a/src/wm/explorer.c b/src/wm/explorer.c index 95ceaa2..23114e5 100644 --- a/src/wm/explorer.c +++ b/src/wm/explorer.c @@ -11,6 +11,7 @@ #include "memory_manager.h" #include "process.h" #include "app_metadata.h" +extern void serial_write(const char *str); #define EXPLORER_ITEM_HEIGHT 80 #define EXPLORER_ITEM_WIDTH 120 #define EXPLORER_COLS 4 @@ -806,9 +807,15 @@ void explorer_open_directory(const char *path) { } void explorer_open_target(const char *path) { + serial_write("[EXPLORER] Opening target: "); + serial_write(path); + serial_write("\n"); + if (vfs_is_directory(path)) { + serial_write("[EXPLORER] Target is directory\n"); explorer_open_directory(path); } else { + serial_write("[EXPLORER] Target is file, checking extensions...\n"); if (explorer_str_ends_with(path, ".elf")) { process_create_elf(path, NULL, false, -1); } else if (explorer_str_ends_with(path, ".pdf")) { @@ -820,6 +827,7 @@ void explorer_open_target(const char *path) { } else if (explorer_is_image_file(path)) { process_create_elf("/bin/viewer.elf", path, false, -1); } else { + serial_write("[EXPLORER] Unknown file type, falling back to txtedit\n"); process_create_elf("/bin/txtedit.elf", path, false, -1); } } diff --git a/src/wm/wallpaper.c b/src/wm/wallpaper.c index 08b0f1a..fd752bd 100644 --- a/src/wm/wallpaper.c +++ b/src/wm/wallpaper.c @@ -6,6 +6,7 @@ #include "memory_manager.h" #include "wm.h" #include "io.h" +#include "core/kutils.h" #include // Static buffer for the current wallpaper (max 1920x1080) @@ -15,10 +16,11 @@ static uint32_t* wp_pixels = NULL; static int wp_width = 0; static int wp_height = 0; -// Deferred wallpaper action (set from interrupt context, processed in main loop) static volatile const char *pending_wallpaper_path = NULL; static char pending_path_buf[256]; +#define WALLPAPER_CONF_PATH "/Library/BWM/Wallpaper/wallpaper" + // Simple nearest-neighbor scale from decoded RGBA to ARGB pixel buffer static void scale_rgba_to_argb(const unsigned char *rgba, int src_w, int src_h, uint32_t *dst, int dst_w, int dst_h) { @@ -101,7 +103,45 @@ void wallpaper_request_set_from_file(const char *path) { pending_wallpaper_path = pending_path_buf; } -// Process deferred wallpaper actions (called from main loop, NOT interrupt context) +void wallpaper_save_setting(const char *path) { + if (!path) return; + fat32_mkdir("/Library/BWM"); + fat32_mkdir("/Library/BWM/Wallpaper"); + FAT32_FileHandle *fh = fat32_open(WALLPAPER_CONF_PATH, "w"); + if (!fh || !fh->valid) { + serial_str("[WALLPAPER] Failed to save setting\n"); + return; + } + fat32_write(fh, path, (uint32_t)k_strlen(path)); + fat32_close(fh); + serial_str("[WALLPAPER] Setting saved: "); + serial_str(path); + serial_str("\n"); +} + +void wallpaper_load_setting(void) { + if (!fat32_exists(WALLPAPER_CONF_PATH)) { + serial_str("[WALLPAPER] No saved setting found\n"); + return; + } + FAT32_FileHandle *fh = fat32_open(WALLPAPER_CONF_PATH, "r"); + if (!fh || !fh->valid) return; + + char path_buf[256]; + int bytes_read = fat32_read(fh, path_buf, 255); + fat32_close(fh); + + if (bytes_read > 0) { + path_buf[bytes_read] = '\0'; + serial_str("[WALLPAPER] Loaded setting: "); + serial_str(path_buf); + serial_str("\n"); + if (fat32_exists(path_buf)) { + wallpaper_request_set_from_file(path_buf); + } + } +} + void wallpaper_process_pending(void) { if (pending_wallpaper_path) { const char *path = (const char *)pending_wallpaper_path; @@ -131,6 +171,7 @@ void wallpaper_process_pending(void) { if (total_read > 0) { decode_and_set_wallpaper(buf, (unsigned int)total_read); + wallpaper_save_setting(path); wm_refresh(); } kfree(buf); @@ -149,11 +190,13 @@ int wallpaper_get_width(void) { return wp_width; } int wallpaper_get_height(void) { return wp_height; } void wallpaper_init(void) { - // We expect Limine modules to have been copied to /Library/images/Wallpapers/ by main.c - // Set a default wallpaper if one exists - if (fat32_exists("/Library/images/Wallpapers/bored.jpg")) { - wallpaper_request_set_from_file("/Library/images/Wallpapers/bored.jpg"); - } else if (fat32_exists("/Library/images/Wallpapers/moon.jpg")) { - wallpaper_request_set_from_file("/Library/images/Wallpapers/moon.jpg"); + wallpaper_load_setting(); + + if (pending_wallpaper_path == NULL) { + if (fat32_exists("/Library/images/Wallpapers/bored.jpg")) { + wallpaper_request_set_from_file("/Library/images/Wallpapers/bored.jpg"); + } else if (fat32_exists("/Library/images/Wallpapers/moon.jpg")) { + wallpaper_request_set_from_file("/Library/images/Wallpapers/moon.jpg"); + } } } diff --git a/src/wm/wallpaper.h b/src/wm/wallpaper.h index a98827f..9fefab6 100644 --- a/src/wm/wallpaper.h +++ b/src/wm/wallpaper.h @@ -8,16 +8,11 @@ #include #include -// Initialize wallpaper subsystem void wallpaper_init(void); - -// Request wallpaper change by file path (safe from interrupt context) void wallpaper_request_set_from_file(const char *path); - -// Process pending wallpaper actions (call from main loop only!) +void wallpaper_save_setting(const char *path); +void wallpaper_load_setting(void); void wallpaper_process_pending(void); - -// Get decoded wallpaper pixel buffer uint32_t* wallpaper_get_pixels(void); int wallpaper_get_width(void); int wallpaper_get_height(void); diff --git a/src/wm/wm.c b/src/wm/wm.c index 990c241..c16bc34 100644 --- a/src/wm/wm.c +++ b/src/wm/wm.c @@ -12,6 +12,8 @@ #include #include "wallpaper.h" #include "fat32.h" +#include "tar.h" +#include "vfs.h" #include "file_index.h" #include "../dev/ps2.h" #define STBI_NO_STDIO @@ -21,6 +23,7 @@ #include "app_metadata.h" #include "../sys/work_queue.h" #include "../sys/smp.h" +#include "../sys/bootfs_state.h" #include "../core/kconsole.h" #include "../input/keycodes.h" #include "../input/keymap.h" @@ -59,6 +62,155 @@ static bool str_eq(const char *s1, const char *s2) { return (*s1 == *s2); } +#define ROOT_MARKER_SUFFIX "/Library/.boredos_root" +#define ROOT_MARKER_PATH "/Library/.boredos_root" + +static void rootfs_append(char *buf, int max, const char *suffix) { + if (!buf || max <= 0 || !suffix) return; + int i = 0; + while (buf[i] && i < max - 1) i++; + int j = 0; + while (suffix[j] && i < max - 1) { + buf[i++] = suffix[j++]; + } + buf[i] = 0; +} + +static void rootfs_build_dev_mount(const char *devname, char *out, int max) { + if (!out || max <= 0) return; + const char *prefix = "/dev/"; + int i = 0; + while (prefix[i] && i < max - 1) { + out[i] = prefix[i]; + i++; + } + int j = 0; + while (devname && devname[j] && i < max - 1) { + out[i++] = devname[j++]; + } + out[i] = 0; +} + +static void rootfs_build_marker_path(const char *devname, char *out, int max) { + rootfs_build_dev_mount(devname, out, max); + rootfs_append(out, max, ROOT_MARKER_SUFFIX); +} + +static void* rootfs_get_mount_private(const char *mount_path) { + int mc = vfs_get_mount_count(); + for (int i = 0; i < mc; i++) { + vfs_mount_t *m = vfs_get_mount(i); + if (m && m->active && k_strcmp(m->path, mount_path) == 0) { + return m->fs_private; + } + } + return NULL; +} + +static bool rootfs_has_marker(Disk *disk) { + if (!disk) return false; + char marker_path[96]; + rootfs_build_marker_path(disk->devname, marker_path, (int)sizeof(marker_path)); + return vfs_exists(marker_path); +} + +static Disk* rootfs_select_disk(void) { + if (g_bootfs_state.boot_flags & BOOT_FLAG_LIVE) return NULL; + + if (g_bootfs_state.root_device[0]) { + Disk *d = disk_get_by_name(g_bootfs_state.root_device); + if (d && d->is_partition && d->is_fat32 && !d->is_esp) return d; + } + + Disk *fallback = NULL; + int candidate_count = 0; + int count = disk_get_count(); + for (int i = 0; i < count; i++) { + Disk *d = disk_get_by_index(i); + if (!d || !d->is_partition || !d->is_fat32 || d->is_esp) continue; + if (!fallback) fallback = d; + candidate_count++; + if (rootfs_has_marker(d)) return d; + } + + if (candidate_count == 1 && (g_bootfs_state.boot_flags & BOOT_FLAG_DISK)) { + return fallback; + } + + if (g_bootfs_state.boot_flags & BOOT_FLAG_FORCED) { + return fallback; + } + + return NULL; +} + +static bool rootfs_is_provisioned(void) { + return vfs_exists(ROOT_MARKER_PATH); +} + +static void rootfs_write_marker(void) { + FAT32_FileHandle *fh = fat32_open(ROOT_MARKER_PATH, "w"); + if (!fh || !fh->valid) return; + const char *msg = "boredos root\n"; + fat32_write(fh, msg, (uint32_t)k_strlen(msg)); + fat32_close(fh); +} + +static void rootfs_provision_from_initrd(void) { + if (rootfs_is_provisioned()) return; + if (!g_bootfs_state.initrd_ptr || g_bootfs_state.initrd_size == 0) { + serial_write("[ROOT] No initrd available for provisioning\n"); + return; + } + serial_write("[ROOT] Provisioning rootfs from initrd\n"); + tar_parse(g_bootfs_state.initrd_ptr, g_bootfs_state.initrd_size); + rootfs_write_marker(); +} + +static bool rootfs_try_pivot(void) { + Disk *root_disk = rootfs_select_disk(); + if (!root_disk) { + serial_write("[ROOT] No suitable root partition found, keeping RAMFS\n"); + return false; + } + + char dev_mount[32]; + rootfs_build_dev_mount(root_disk->devname, dev_mount, (int)sizeof(dev_mount)); + void *fs_private = rootfs_get_mount_private(dev_mount); + if (!fs_private) { + fs_private = fat32_mount_volume(root_disk); + if (!fs_private) { + serial_write("[ROOT] Failed to mount root volume\n"); + return false; + } + } + + vfs_umount("/"); + if (!vfs_mount("/", root_disk->devname, "fat32", fat32_get_realfs_ops(), fs_private)) { + serial_write("[ROOT] Failed to pivot root, restoring RAMFS\n"); + vfs_mount("/", "ramfs", "ramfs", fat32_get_ramfs_ops(), NULL); + return false; + } + + if (!g_bootfs_state.root_device[0]) { + int i = 0; + while (root_disk->devname[i] && i < (int)sizeof(g_bootfs_state.root_device) - 1) { + g_bootfs_state.root_device[i] = root_disk->devname[i]; + i++; + } + g_bootfs_state.root_device[i] = '\0'; + } + + g_bootfs_state.boot_flags |= (BOOT_FLAG_DISK | BOOT_FLAG_ROOT_PIVOTED); + fat32_set_root_volume(fs_private); + rootfs_provision_from_initrd(); + + serial_write("[ROOT] Pivoted root to /dev/"); + serial_write(root_disk->devname); + serial_write("\n"); + return true; +} + // --- State --- static int mx = 400, my = 300; @@ -1065,7 +1217,7 @@ static int dock_insertion_index_from_x(int x, int y, int sw, int sh) { static void dock_save_config(void) { fat32_mkdir("/root"); - fat32_mkdir("/Library/Dock/dock.cfg"); + fat32_mkdir("/Library/Dock"); FAT32_FileHandle *fh = fat32_open(DOCK_CONFIG_PATH, "w"); if (!fh) return; @@ -3863,6 +4015,11 @@ void wm_init(void) { disk_manager_scan(); log_ok("Disk scanning complete"); + extern void bootfs_mount_boot_partition(void); + bootfs_mount_boot_partition(); + + rootfs_try_pivot(); + explorer_init(); log_ok("Explorer ready"); @@ -3903,6 +4060,15 @@ void wm_init(void) { graphics_flip_buffer(); } +void wm_run_loop(void) { + while (1) { + wm_process_input(); + wm_process_deferred_thumbs(); + wallpaper_process_pending(); + asm("hlt"); + } +} + uint32_t wm_get_ticks(void) { return timer_ticks; } @@ -3958,9 +4124,6 @@ void wm_notify_fs_change(void) { file_index_invalidate_cache(); lumos_index_built = false; - // Kick off a background index rebuild so Lumos reflects changes immediately. - // The flag prevents flooding the work queue when many files change at once - // (e.g. during a bulk folder move that triggers one notification per file). if (!index_rebuild_queued) { index_rebuild_queued = true; work_queue_submit(index_rebuild_wrapper, NULL); diff --git a/src/wm/wm.h b/src/wm/wm.h index f33cc77..e1b4d98 100644 --- a/src/wm/wm.h +++ b/src/wm/wm.h @@ -90,6 +90,7 @@ typedef struct { } lumos_state_t; void wm_init(void); +void wm_run_loop(void); void wm_handle_mouse(int dx, int dy, uint8_t buttons, int dz); void wm_handle_key_event(uint16_t keycode, uint32_t codepoint, uint32_t mods, bool pressed); void wm_handle_click(int x, int y);