mirror of
https://github.com/BoredDevNL/BoredOS.git
synced 2026-05-15 10:48:38 +00:00
wm: implement root filesystem pivoting and persistence provisioning
This commit is contained in:
parent
5ae8c56d40
commit
0fbc3a5fc8
5 changed files with 229 additions and 19 deletions
|
|
@ -11,6 +11,7 @@
|
||||||
#include "memory_manager.h"
|
#include "memory_manager.h"
|
||||||
#include "process.h"
|
#include "process.h"
|
||||||
#include "app_metadata.h"
|
#include "app_metadata.h"
|
||||||
|
extern void serial_write(const char *str);
|
||||||
#define EXPLORER_ITEM_HEIGHT 80
|
#define EXPLORER_ITEM_HEIGHT 80
|
||||||
#define EXPLORER_ITEM_WIDTH 120
|
#define EXPLORER_ITEM_WIDTH 120
|
||||||
#define EXPLORER_COLS 4
|
#define EXPLORER_COLS 4
|
||||||
|
|
@ -806,9 +807,15 @@ void explorer_open_directory(const char *path) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void explorer_open_target(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)) {
|
if (vfs_is_directory(path)) {
|
||||||
|
serial_write("[EXPLORER] Target is directory\n");
|
||||||
explorer_open_directory(path);
|
explorer_open_directory(path);
|
||||||
} else {
|
} else {
|
||||||
|
serial_write("[EXPLORER] Target is file, checking extensions...\n");
|
||||||
if (explorer_str_ends_with(path, ".elf")) {
|
if (explorer_str_ends_with(path, ".elf")) {
|
||||||
process_create_elf(path, NULL, false, -1);
|
process_create_elf(path, NULL, false, -1);
|
||||||
} else if (explorer_str_ends_with(path, ".pdf")) {
|
} 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)) {
|
} else if (explorer_is_image_file(path)) {
|
||||||
process_create_elf("/bin/viewer.elf", path, false, -1);
|
process_create_elf("/bin/viewer.elf", path, false, -1);
|
||||||
} else {
|
} else {
|
||||||
|
serial_write("[EXPLORER] Unknown file type, falling back to txtedit\n");
|
||||||
process_create_elf("/bin/txtedit.elf", path, false, -1);
|
process_create_elf("/bin/txtedit.elf", path, false, -1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,7 @@
|
||||||
#include "memory_manager.h"
|
#include "memory_manager.h"
|
||||||
#include "wm.h"
|
#include "wm.h"
|
||||||
#include "io.h"
|
#include "io.h"
|
||||||
|
#include "core/kutils.h"
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
|
|
||||||
// Static buffer for the current wallpaper (max 1920x1080)
|
// 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_width = 0;
|
||||||
static int wp_height = 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 volatile const char *pending_wallpaper_path = NULL;
|
||||||
static char pending_path_buf[256];
|
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
|
// 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,
|
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) {
|
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;
|
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) {
|
void wallpaper_process_pending(void) {
|
||||||
if (pending_wallpaper_path) {
|
if (pending_wallpaper_path) {
|
||||||
const char *path = (const char *)pending_wallpaper_path;
|
const char *path = (const char *)pending_wallpaper_path;
|
||||||
|
|
@ -131,6 +171,7 @@ void wallpaper_process_pending(void) {
|
||||||
|
|
||||||
if (total_read > 0) {
|
if (total_read > 0) {
|
||||||
decode_and_set_wallpaper(buf, (unsigned int)total_read);
|
decode_and_set_wallpaper(buf, (unsigned int)total_read);
|
||||||
|
wallpaper_save_setting(path);
|
||||||
wm_refresh();
|
wm_refresh();
|
||||||
}
|
}
|
||||||
kfree(buf);
|
kfree(buf);
|
||||||
|
|
@ -149,11 +190,13 @@ int wallpaper_get_width(void) { return wp_width; }
|
||||||
int wallpaper_get_height(void) { return wp_height; }
|
int wallpaper_get_height(void) { return wp_height; }
|
||||||
|
|
||||||
void wallpaper_init(void) {
|
void wallpaper_init(void) {
|
||||||
// We expect Limine modules to have been copied to /Library/images/Wallpapers/ by main.c
|
wallpaper_load_setting();
|
||||||
// Set a default wallpaper if one exists
|
|
||||||
|
if (pending_wallpaper_path == NULL) {
|
||||||
if (fat32_exists("/Library/images/Wallpapers/bored.jpg")) {
|
if (fat32_exists("/Library/images/Wallpapers/bored.jpg")) {
|
||||||
wallpaper_request_set_from_file("/Library/images/Wallpapers/bored.jpg");
|
wallpaper_request_set_from_file("/Library/images/Wallpapers/bored.jpg");
|
||||||
} else if (fat32_exists("/Library/images/Wallpapers/moon.jpg")) {
|
} else if (fat32_exists("/Library/images/Wallpapers/moon.jpg")) {
|
||||||
wallpaper_request_set_from_file("/Library/images/Wallpapers/moon.jpg");
|
wallpaper_request_set_from_file("/Library/images/Wallpapers/moon.jpg");
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -8,16 +8,11 @@
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
|
|
||||||
// Initialize wallpaper subsystem
|
|
||||||
void wallpaper_init(void);
|
void wallpaper_init(void);
|
||||||
|
|
||||||
// Request wallpaper change by file path (safe from interrupt context)
|
|
||||||
void wallpaper_request_set_from_file(const char *path);
|
void wallpaper_request_set_from_file(const char *path);
|
||||||
|
void wallpaper_save_setting(const char *path);
|
||||||
// Process pending wallpaper actions (call from main loop only!)
|
void wallpaper_load_setting(void);
|
||||||
void wallpaper_process_pending(void);
|
void wallpaper_process_pending(void);
|
||||||
|
|
||||||
// Get decoded wallpaper pixel buffer
|
|
||||||
uint32_t* wallpaper_get_pixels(void);
|
uint32_t* wallpaper_get_pixels(void);
|
||||||
int wallpaper_get_width(void);
|
int wallpaper_get_width(void);
|
||||||
int wallpaper_get_height(void);
|
int wallpaper_get_height(void);
|
||||||
|
|
|
||||||
171
src/wm/wm.c
171
src/wm/wm.c
|
|
@ -12,6 +12,8 @@
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include "wallpaper.h"
|
#include "wallpaper.h"
|
||||||
#include "fat32.h"
|
#include "fat32.h"
|
||||||
|
#include "tar.h"
|
||||||
|
#include "vfs.h"
|
||||||
#include "file_index.h"
|
#include "file_index.h"
|
||||||
#include "../dev/ps2.h"
|
#include "../dev/ps2.h"
|
||||||
#define STBI_NO_STDIO
|
#define STBI_NO_STDIO
|
||||||
|
|
@ -21,6 +23,7 @@
|
||||||
#include "app_metadata.h"
|
#include "app_metadata.h"
|
||||||
#include "../sys/work_queue.h"
|
#include "../sys/work_queue.h"
|
||||||
#include "../sys/smp.h"
|
#include "../sys/smp.h"
|
||||||
|
#include "../sys/bootfs_state.h"
|
||||||
#include "../core/kconsole.h"
|
#include "../core/kconsole.h"
|
||||||
#include "../input/keycodes.h"
|
#include "../input/keycodes.h"
|
||||||
#include "../input/keymap.h"
|
#include "../input/keymap.h"
|
||||||
|
|
@ -59,6 +62,155 @@ static bool str_eq(const char *s1, const char *s2) {
|
||||||
return (*s1 == *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 ---
|
// --- State ---
|
||||||
static int mx = 400, my = 300;
|
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) {
|
static void dock_save_config(void) {
|
||||||
fat32_mkdir("/root");
|
fat32_mkdir("/root");
|
||||||
fat32_mkdir("/Library/Dock/dock.cfg");
|
fat32_mkdir("/Library/Dock");
|
||||||
|
|
||||||
FAT32_FileHandle *fh = fat32_open(DOCK_CONFIG_PATH, "w");
|
FAT32_FileHandle *fh = fat32_open(DOCK_CONFIG_PATH, "w");
|
||||||
if (!fh) return;
|
if (!fh) return;
|
||||||
|
|
@ -3863,6 +4015,11 @@ void wm_init(void) {
|
||||||
disk_manager_scan();
|
disk_manager_scan();
|
||||||
log_ok("Disk scanning complete");
|
log_ok("Disk scanning complete");
|
||||||
|
|
||||||
|
extern void bootfs_mount_boot_partition(void);
|
||||||
|
bootfs_mount_boot_partition();
|
||||||
|
|
||||||
|
rootfs_try_pivot();
|
||||||
|
|
||||||
explorer_init();
|
explorer_init();
|
||||||
log_ok("Explorer ready");
|
log_ok("Explorer ready");
|
||||||
|
|
||||||
|
|
@ -3903,6 +4060,15 @@ void wm_init(void) {
|
||||||
graphics_flip_buffer();
|
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) {
|
uint32_t wm_get_ticks(void) {
|
||||||
return timer_ticks;
|
return timer_ticks;
|
||||||
}
|
}
|
||||||
|
|
@ -3958,9 +4124,6 @@ void wm_notify_fs_change(void) {
|
||||||
file_index_invalidate_cache();
|
file_index_invalidate_cache();
|
||||||
lumos_index_built = false;
|
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) {
|
if (!index_rebuild_queued) {
|
||||||
index_rebuild_queued = true;
|
index_rebuild_queued = true;
|
||||||
work_queue_submit(index_rebuild_wrapper, NULL);
|
work_queue_submit(index_rebuild_wrapper, NULL);
|
||||||
|
|
|
||||||
|
|
@ -90,6 +90,7 @@ typedef struct {
|
||||||
} lumos_state_t;
|
} lumos_state_t;
|
||||||
|
|
||||||
void wm_init(void);
|
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_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_key_event(uint16_t keycode, uint32_t codepoint, uint32_t mods, bool pressed);
|
||||||
void wm_handle_click(int x, int y);
|
void wm_handle_click(int x, int y);
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue