mirror of
https://github.com/BoredDevNL/BoredOS.git
synced 2026-05-15 10:48:38 +00:00
FEAT: bootfs
This commit is contained in:
parent
e4603792b6
commit
5bd9e537c5
5 changed files with 655 additions and 0 deletions
1
Makefile
1
Makefile
|
|
@ -166,6 +166,7 @@ $(BUILD_DIR)/initrd.tar: $(KERNEL_ELF)
|
||||||
done
|
done
|
||||||
@if [ -f README.md ]; then cp README.md $(BUILD_DIR)/initrd/; fi
|
@if [ -f README.md ]; then cp README.md $(BUILD_DIR)/initrd/; fi
|
||||||
@if [ -f LICENSE ]; then cp LICENSE $(BUILD_DIR)/initrd/; fi
|
@if [ -f LICENSE ]; then cp LICENSE $(BUILD_DIR)/initrd/; fi
|
||||||
|
@if [ -f limine.conf ]; then cp limine.conf $(BUILD_DIR)/initrd/; fi
|
||||||
|
|
||||||
cd $(BUILD_DIR)/initrd && COPYFILE_DISABLE=1 tar --exclude="._*" -cf ../initrd.tar *
|
cd $(BUILD_DIR)/initrd && COPYFILE_DISABLE=1 tar --exclude="._*" -cf ../initrd.tar *
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -19,6 +19,7 @@
|
||||||
#include "tar.h"
|
#include "tar.h"
|
||||||
#include "vfs.h"
|
#include "vfs.h"
|
||||||
#include "core/kconsole.h"
|
#include "core/kconsole.h"
|
||||||
|
#include "core/kutils.h"
|
||||||
#include "memory_manager.h"
|
#include "memory_manager.h"
|
||||||
#include "platform.h"
|
#include "platform.h"
|
||||||
#include "wallpaper.h"
|
#include "wallpaper.h"
|
||||||
|
|
@ -27,8 +28,10 @@
|
||||||
#include "lapic.h"
|
#include "lapic.h"
|
||||||
#include "fs/sysfs.h"
|
#include "fs/sysfs.h"
|
||||||
#include "fs/procfs.h"
|
#include "fs/procfs.h"
|
||||||
|
#include "fs/bootfs.h"
|
||||||
#include "sys/kernel_subsystem.h"
|
#include "sys/kernel_subsystem.h"
|
||||||
#include "sys/module_manager.h"
|
#include "sys/module_manager.h"
|
||||||
|
#include "sys/bootfs_state.h"
|
||||||
|
|
||||||
extern void sysfs_init_subsystems(void);
|
extern void sysfs_init_subsystems(void);
|
||||||
|
|
||||||
|
|
@ -61,12 +64,25 @@ static volatile struct limine_smp_request smp_request = {
|
||||||
.flags = 0
|
.flags = 0
|
||||||
};
|
};
|
||||||
|
|
||||||
|
__attribute__((used, section(".requests")))
|
||||||
|
static volatile struct limine_bootloader_info_request bootloader_info_request = {
|
||||||
|
.id = LIMINE_BOOTLOADER_INFO_REQUEST,
|
||||||
|
.revision = 0
|
||||||
|
};
|
||||||
|
|
||||||
|
static volatile struct limine_kernel_file_request kernel_file_request = {
|
||||||
|
.id = LIMINE_KERNEL_FILE_REQUEST,
|
||||||
|
.revision = 0
|
||||||
|
};
|
||||||
|
|
||||||
__attribute__((used, section(".requests_start")))
|
__attribute__((used, section(".requests_start")))
|
||||||
static volatile struct limine_request *const requests_start_marker[] = {
|
static volatile struct limine_request *const requests_start_marker[] = {
|
||||||
(struct limine_request *)&framebuffer_request,
|
(struct limine_request *)&framebuffer_request,
|
||||||
(struct limine_request *)&memmap_request,
|
(struct limine_request *)&memmap_request,
|
||||||
(struct limine_request *)&module_request,
|
(struct limine_request *)&module_request,
|
||||||
(struct limine_request *)&smp_request,
|
(struct limine_request *)&smp_request,
|
||||||
|
(struct limine_request *)&bootloader_info_request,
|
||||||
|
(struct limine_request *)&kernel_file_request,
|
||||||
NULL
|
NULL
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -259,6 +275,63 @@ void kmain(void) {
|
||||||
vfs_mount("/sys", "sysfs", "sysfs", sysfs_get_ops(), NULL);
|
vfs_mount("/sys", "sysfs", "sysfs", sysfs_get_ops(), NULL);
|
||||||
vfs_mount("/proc", "procfs", "procfs", procfs_get_ops(), NULL);
|
vfs_mount("/proc", "procfs", "procfs", procfs_get_ops(), NULL);
|
||||||
|
|
||||||
|
// Initialize bootfs with default values
|
||||||
|
bootfs_init();
|
||||||
|
|
||||||
|
// Populate bootfs with real Limine bootloader information BEFORE mounting
|
||||||
|
if (bootloader_info_request.response != NULL) {
|
||||||
|
if (bootloader_info_request.response->name) {
|
||||||
|
k_strcpy(g_bootfs_state.bootloader_name, bootloader_info_request.response->name);
|
||||||
|
}
|
||||||
|
if (bootloader_info_request.response->version) {
|
||||||
|
k_strcpy(g_bootfs_state.bootloader_version, bootloader_info_request.response->version);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get kernel size from kernel file request
|
||||||
|
if (kernel_file_request.response != NULL && kernel_file_request.response->kernel_file != NULL) {
|
||||||
|
g_bootfs_state.kernel_size = kernel_file_request.response->kernel_file->size;
|
||||||
|
serial_write("[INIT] Kernel size from bootloader: ");
|
||||||
|
serial_write_hex(g_bootfs_state.kernel_size);
|
||||||
|
serial_write(" bytes\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set boot time to current ticks
|
||||||
|
extern uint32_t wm_get_ticks(void);
|
||||||
|
g_bootfs_state.boot_time_ms = wm_get_ticks();
|
||||||
|
|
||||||
|
// BEFORE mounting bootfs, capture initrd from Limine modules
|
||||||
|
if (module_request.response != NULL) {
|
||||||
|
g_bootfs_state.num_modules = module_request.response->module_count;
|
||||||
|
|
||||||
|
serial_write("[INIT] Scanning modules for bootfs state...\n");
|
||||||
|
// Scan modules to find initrd
|
||||||
|
for (uint64_t i = 0; i < module_request.response->module_count; i++) {
|
||||||
|
struct limine_file *mod = module_request.response->modules[i];
|
||||||
|
const char *path = mod->path;
|
||||||
|
|
||||||
|
if (fs_starts_with(path, "boot():")) path += 7;
|
||||||
|
else if (fs_starts_with(path, "boot:///")) path += 8;
|
||||||
|
|
||||||
|
int path_len = 0;
|
||||||
|
while (path[path_len]) path_len++;
|
||||||
|
|
||||||
|
serial_write("[INIT] Module: ");
|
||||||
|
serial_write(path);
|
||||||
|
serial_write(" (");
|
||||||
|
serial_write_hex(mod->size);
|
||||||
|
serial_write(" bytes)\n");
|
||||||
|
|
||||||
|
if (path_len >= 5 && path[path_len-4] == '.' && path[path_len-3] == 't' &&
|
||||||
|
path[path_len-2] == 'a' && path[path_len-1] == 'r') {
|
||||||
|
g_bootfs_state.initrd_size = mod->size;
|
||||||
|
serial_write("[INIT] -> Initrd detected\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
vfs_mount("/boot", "bootfs", "bootfs", bootfs_get_ops(), NULL);
|
||||||
|
|
||||||
if (module_request.response == NULL) {
|
if (module_request.response == NULL) {
|
||||||
log_fail("Limine module response NULL");
|
log_fail("Limine module response NULL");
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -330,6 +403,9 @@ void kmain(void) {
|
||||||
|
|
||||||
asm volatile("sti");
|
asm volatile("sti");
|
||||||
|
|
||||||
|
extern void bootfs_refresh_from_disk(void);
|
||||||
|
bootfs_refresh_from_disk();
|
||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
wm_process_input();
|
wm_process_input();
|
||||||
wm_process_deferred_thumbs();
|
wm_process_deferred_thumbs();
|
||||||
|
|
|
||||||
541
src/fs/bootfs.c
Normal file
541
src/fs/bootfs.c
Normal file
|
|
@ -0,0 +1,541 @@
|
||||||
|
// Copyright (c) 2023-2026 Chris (boreddevnl)
|
||||||
|
// This software is released under the GNU General Public License v3.0. See LICENSE file for details.
|
||||||
|
// This header needs to maintain in any file it is present in, as per the GPL license terms.
|
||||||
|
|
||||||
|
#include "bootfs.h"
|
||||||
|
#include "../sys/bootfs_state.h"
|
||||||
|
#include "vfs.h"
|
||||||
|
#include "core/kutils.h"
|
||||||
|
#include "core/platform.h"
|
||||||
|
#include "core/kconsole.h"
|
||||||
|
#include "memory_manager.h"
|
||||||
|
|
||||||
|
extern void serial_write(const char *str);
|
||||||
|
extern void serial_write_hex(uint64_t value);
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
char path[512];
|
||||||
|
int offset;
|
||||||
|
bool is_root;
|
||||||
|
bool is_metadata_dir;
|
||||||
|
} bootfs_handle_t;
|
||||||
|
|
||||||
|
static void* bootfs_open(void *fs_private, const char *path, const char *mode);
|
||||||
|
static void bootfs_close(void *fs_private, void *handle);
|
||||||
|
static int bootfs_read(void *fs_private, void *handle, void *buf, int size);
|
||||||
|
static int bootfs_write(void *fs_private, void *handle, const void *buf, int size);
|
||||||
|
static int bootfs_seek(void *fs_private, void *handle, int offset, int whence);
|
||||||
|
static int bootfs_readdir(void *fs_private, const char *rel_path, vfs_dirent_t *entries, int max);
|
||||||
|
static bool bootfs_mkdir(void *fs_private, const char *rel_path);
|
||||||
|
static bool bootfs_rmdir(void *fs_private, const char *rel_path);
|
||||||
|
static bool bootfs_unlink(void *fs_private, const char *rel_path);
|
||||||
|
static bool bootfs_rename(void *fs_private, const char *old_path, const char *new_path);
|
||||||
|
static bool bootfs_exists(void *fs_private, const char *rel_path);
|
||||||
|
static bool bootfs_is_dir(void *fs_private, const char *rel_path);
|
||||||
|
static int bootfs_get_info(void *fs_private, const char *rel_path, vfs_dirent_t *info);
|
||||||
|
static uint32_t bootfs_get_position(void *file_handle);
|
||||||
|
static uint32_t bootfs_get_size(void *file_handle);
|
||||||
|
|
||||||
|
static vfs_fs_ops_t bootfs_ops = {
|
||||||
|
.open = bootfs_open,
|
||||||
|
.close = bootfs_close,
|
||||||
|
.read = bootfs_read,
|
||||||
|
.write = bootfs_write,
|
||||||
|
.seek = bootfs_seek,
|
||||||
|
.readdir = bootfs_readdir,
|
||||||
|
.mkdir = bootfs_mkdir,
|
||||||
|
.rmdir = bootfs_rmdir,
|
||||||
|
.unlink = bootfs_unlink,
|
||||||
|
.rename = bootfs_rename,
|
||||||
|
.exists = bootfs_exists,
|
||||||
|
.is_dir = bootfs_is_dir,
|
||||||
|
.get_info = bootfs_get_info,
|
||||||
|
.get_position = bootfs_get_position,
|
||||||
|
.get_size = bootfs_get_size,
|
||||||
|
};
|
||||||
|
|
||||||
|
bootfs_state_t g_bootfs_state = {0};
|
||||||
|
|
||||||
|
static bool is_metadata_path(const char *path) {
|
||||||
|
if (!path) return false;
|
||||||
|
return k_strncmp(path, "metadata", 8) == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool is_metadata_file(const char *path) {
|
||||||
|
if (k_strcmp(path, "metadata/boot_time") == 0) return true;
|
||||||
|
if (k_strcmp(path, "metadata/boot_flags") == 0) return true;
|
||||||
|
if (k_strcmp(path, "metadata/version") == 0) return true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void* bootfs_open(void *fs_private, const char *path, const char *mode) {
|
||||||
|
if (!path) path = "";
|
||||||
|
if (path[0] == '/') path++;
|
||||||
|
|
||||||
|
bootfs_handle_t *h = (bootfs_handle_t*)kmalloc(sizeof(bootfs_handle_t));
|
||||||
|
if (!h) return NULL;
|
||||||
|
|
||||||
|
k_memset(h, 0, sizeof(bootfs_handle_t));
|
||||||
|
k_strcpy(h->path, path);
|
||||||
|
h->offset = 0;
|
||||||
|
|
||||||
|
if (path[0] == '\0') {
|
||||||
|
h->is_root = true;
|
||||||
|
} else if (is_metadata_path(path) && path[8] == '\0') {
|
||||||
|
h->is_metadata_dir = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return h;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void bootfs_close(void *fs_private, void *handle) {
|
||||||
|
if (handle) kfree(handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int generate_metadata_content(const char *file, char *buffer, int max_size) {
|
||||||
|
if (!buffer || max_size <= 0) return 0;
|
||||||
|
|
||||||
|
buffer[0] = '\0';
|
||||||
|
int len = 0;
|
||||||
|
|
||||||
|
if (k_strcmp(file, "metadata/boot_time") == 0) {
|
||||||
|
extern uint32_t wm_get_ticks(void);
|
||||||
|
uint32_t ticks = wm_get_ticks();
|
||||||
|
|
||||||
|
k_strcpy(buffer, "Boot time: ");
|
||||||
|
char time_buf[32];
|
||||||
|
k_itoa(g_bootfs_state.boot_time_ms, time_buf);
|
||||||
|
k_strcpy(buffer + k_strlen(buffer), time_buf);
|
||||||
|
k_strcpy(buffer + k_strlen(buffer), " ms\nTicks: ");
|
||||||
|
k_itoa(ticks, time_buf);
|
||||||
|
k_strcpy(buffer + k_strlen(buffer), time_buf);
|
||||||
|
k_strcpy(buffer + k_strlen(buffer), "\n");
|
||||||
|
len = k_strlen(buffer);
|
||||||
|
} else if (k_strcmp(file, "metadata/version") == 0) {
|
||||||
|
k_strcpy(buffer, "Bootloader: ");
|
||||||
|
k_strcpy(buffer + k_strlen(buffer), g_bootfs_state.bootloader_name);
|
||||||
|
k_strcpy(buffer + k_strlen(buffer), "\nVersion: ");
|
||||||
|
k_strcpy(buffer + k_strlen(buffer), g_bootfs_state.bootloader_version);
|
||||||
|
k_strcpy(buffer + k_strlen(buffer), "\n");
|
||||||
|
len = k_strlen(buffer);
|
||||||
|
} else if (k_strcmp(file, "metadata/boot_flags") == 0) {
|
||||||
|
k_strcpy(buffer, "Boot flags: 0x");
|
||||||
|
char flags_buf[8];
|
||||||
|
uint8_t flags = g_bootfs_state.boot_flags;
|
||||||
|
int hex_digit = (flags >> 4) & 0xF;
|
||||||
|
flags_buf[0] = hex_digit < 10 ? '0' + hex_digit : 'a' + (hex_digit - 10);
|
||||||
|
hex_digit = flags & 0xF;
|
||||||
|
flags_buf[1] = hex_digit < 10 ? '0' + hex_digit : 'a' + (hex_digit - 10);
|
||||||
|
flags_buf[2] = '\n';
|
||||||
|
flags_buf[3] = '\0';
|
||||||
|
k_strcpy(buffer + k_strlen(buffer), flags_buf);
|
||||||
|
len = k_strlen(buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int bootfs_read(void *fs_private, void *handle, void *buf, int size) {
|
||||||
|
bootfs_handle_t *h = (bootfs_handle_t*)handle;
|
||||||
|
if (!h || !buf || size <= 0) return -1;
|
||||||
|
|
||||||
|
char *content_buffer = (char*)kmalloc(4096);
|
||||||
|
if (!content_buffer) return -1;
|
||||||
|
|
||||||
|
int content_len = 0;
|
||||||
|
|
||||||
|
if (k_strcmp(h->path, "limine.conf") == 0) {
|
||||||
|
k_memcpy(content_buffer, g_bootfs_state.limine_conf,
|
||||||
|
g_bootfs_state.limine_conf_len);
|
||||||
|
content_len = g_bootfs_state.limine_conf_len;
|
||||||
|
} else if (k_strcmp(h->path, "kernel") == 0) {
|
||||||
|
k_strcpy(content_buffer, "Kernel reference\nSize: ");
|
||||||
|
char size_buf[32];
|
||||||
|
k_itoa(g_bootfs_state.kernel_size, size_buf);
|
||||||
|
k_strcpy(content_buffer + k_strlen(content_buffer), size_buf);
|
||||||
|
k_strcpy(content_buffer + k_strlen(content_buffer), " bytes\n");
|
||||||
|
content_len = k_strlen(content_buffer);
|
||||||
|
} else if (k_strcmp(h->path, "initrd") == 0) {
|
||||||
|
k_strcpy(content_buffer, "Initial ramdisk reference\nSize: ");
|
||||||
|
char size_buf[32];
|
||||||
|
k_itoa(g_bootfs_state.initrd_size, size_buf);
|
||||||
|
k_strcpy(content_buffer + k_strlen(content_buffer), size_buf);
|
||||||
|
k_strcpy(content_buffer + k_strlen(content_buffer), " bytes\n");
|
||||||
|
content_len = k_strlen(content_buffer);
|
||||||
|
} else if (is_metadata_file(h->path)) {
|
||||||
|
content_len = generate_metadata_content(h->path, content_buffer, 4096);
|
||||||
|
} else {
|
||||||
|
kfree(content_buffer);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle offset and reading
|
||||||
|
if (h->offset >= content_len) {
|
||||||
|
kfree(content_buffer);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int available = content_len - h->offset;
|
||||||
|
int read_size = (available < size) ? available : size;
|
||||||
|
|
||||||
|
k_memcpy(buf, content_buffer + h->offset, read_size);
|
||||||
|
h->offset += read_size;
|
||||||
|
|
||||||
|
kfree(content_buffer);
|
||||||
|
return read_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int bootfs_write(void *fs_private, void *handle, const void *buf, int size) {
|
||||||
|
bootfs_handle_t *h = (bootfs_handle_t*)handle;
|
||||||
|
if (!h || !buf || size <= 0) return -1;
|
||||||
|
|
||||||
|
if (k_strcmp(h->path, "limine.conf") != 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int max_write = 2048 - h->offset;
|
||||||
|
if (max_write <= 0) return -1;
|
||||||
|
|
||||||
|
int write_size = (size < max_write) ? size : max_write;
|
||||||
|
k_memcpy(g_bootfs_state.limine_conf + h->offset, buf, write_size);
|
||||||
|
h->offset += write_size;
|
||||||
|
|
||||||
|
if (h->offset > g_bootfs_state.limine_conf_len) {
|
||||||
|
g_bootfs_state.limine_conf_len = h->offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
extern vfs_file_t* vfs_open(const char *path, const char *mode);
|
||||||
|
extern int vfs_write(vfs_file_t *file, const void *buf, int size);
|
||||||
|
extern void vfs_close(vfs_file_t *file);
|
||||||
|
|
||||||
|
vfs_file_t *fat_conf = vfs_open("/limine.conf", "w");
|
||||||
|
if (fat_conf) {
|
||||||
|
vfs_write(fat_conf, g_bootfs_state.limine_conf, g_bootfs_state.limine_conf_len);
|
||||||
|
vfs_close(fat_conf);
|
||||||
|
}
|
||||||
|
|
||||||
|
return write_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int bootfs_seek(void *fs_private, void *handle, int offset, int whence) {
|
||||||
|
bootfs_handle_t *h = (bootfs_handle_t*)handle;
|
||||||
|
if (!h) return -1;
|
||||||
|
|
||||||
|
switch (whence) {
|
||||||
|
case 0: // SEEK_SET
|
||||||
|
h->offset = offset;
|
||||||
|
break;
|
||||||
|
case 1: // SEEK_CUR
|
||||||
|
h->offset += offset;
|
||||||
|
break;
|
||||||
|
case 2: // SEEK_END
|
||||||
|
return -1;
|
||||||
|
default:
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return h->offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int bootfs_readdir(void *fs_private, const char *rel_path, vfs_dirent_t *entries, int max) {
|
||||||
|
if (!entries || max <= 0) return 0;
|
||||||
|
|
||||||
|
if (!rel_path) rel_path = "";
|
||||||
|
if (rel_path[0] == '/') rel_path++;
|
||||||
|
|
||||||
|
int count = 0;
|
||||||
|
|
||||||
|
if (rel_path[0] == '\0') {
|
||||||
|
if (count < max) {
|
||||||
|
k_strcpy(entries[count].name, "limine.conf");
|
||||||
|
entries[count].size = g_bootfs_state.limine_conf_len;
|
||||||
|
entries[count].is_directory = 0;
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (count < max) {
|
||||||
|
k_strcpy(entries[count].name, "kernel");
|
||||||
|
entries[count].size = g_bootfs_state.kernel_size;
|
||||||
|
entries[count].is_directory = 0;
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (count < max) {
|
||||||
|
k_strcpy(entries[count].name, "initrd");
|
||||||
|
entries[count].size = g_bootfs_state.initrd_size;
|
||||||
|
entries[count].is_directory = 0;
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (count < max) {
|
||||||
|
k_strcpy(entries[count].name, "metadata");
|
||||||
|
entries[count].size = 0;
|
||||||
|
entries[count].is_directory = 1;
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (k_strcmp(rel_path, "metadata") == 0) {
|
||||||
|
const char *meta_files[] = {
|
||||||
|
"boot_time",
|
||||||
|
"boot_flags",
|
||||||
|
"version"
|
||||||
|
};
|
||||||
|
|
||||||
|
for (int i = 0; i < 3 && count < max; i++) {
|
||||||
|
k_strcpy(entries[count].name, meta_files[i]);
|
||||||
|
entries[count].size = 0;
|
||||||
|
entries[count].is_directory = 0;
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool bootfs_mkdir(void *fs_private, const char *rel_path) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool bootfs_rmdir(void *fs_private, const char *rel_path) {
|
||||||
|
if (!rel_path) rel_path = "";
|
||||||
|
if (rel_path[0] == '/') rel_path++;
|
||||||
|
|
||||||
|
if (k_strcmp(rel_path, "metadata") == 0) {
|
||||||
|
return false; /* metadata directory is protected */
|
||||||
|
}
|
||||||
|
|
||||||
|
return false; /* no other directories to remove */
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool bootfs_unlink(void *fs_private, const char *rel_path) {
|
||||||
|
if (!rel_path) return false;
|
||||||
|
if (rel_path[0] == '/') rel_path++;
|
||||||
|
|
||||||
|
/* Only limine.conf can be deleted */
|
||||||
|
if (k_strcmp(rel_path, "limine.conf") != 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Clear the bootfs state */
|
||||||
|
g_bootfs_state.limine_conf[0] = '\0';
|
||||||
|
g_bootfs_state.limine_conf_len = 0;
|
||||||
|
|
||||||
|
/* Delete from partition */
|
||||||
|
extern bool vfs_delete(const char *path);
|
||||||
|
|
||||||
|
bool result = vfs_delete("/limine.conf");
|
||||||
|
|
||||||
|
if (result) {
|
||||||
|
serial_write("[BOOTFS] Deleted limine.conf from partition\n");
|
||||||
|
} else {
|
||||||
|
serial_write("[BOOTFS] Warning: Could not delete limine.conf from partition\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool bootfs_rename(void *fs_private, const char *old_path, const char *new_path) {
|
||||||
|
if (!old_path || !new_path) return false;
|
||||||
|
|
||||||
|
const char *old_rel = old_path;
|
||||||
|
const char *new_rel = new_path;
|
||||||
|
|
||||||
|
if (old_rel[0] == '/') old_rel++;
|
||||||
|
if (new_rel[0] == '/') new_rel++;
|
||||||
|
|
||||||
|
/* Only limine.conf can be renamed */
|
||||||
|
if (k_strcmp(old_rel, "limine.conf") != 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* kernel and initrd are protected */
|
||||||
|
if (k_strcmp(new_rel, "kernel") == 0 || k_strcmp(new_rel, "initrd") == 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* metadata directory is protected */
|
||||||
|
if (k_strncmp(new_rel, "metadata", 8) == 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
extern bool vfs_rename(const char *old_path, const char *new_path);
|
||||||
|
|
||||||
|
char new_partition_path[256];
|
||||||
|
k_strcpy(new_partition_path, "/");
|
||||||
|
|
||||||
|
/* Manually append new_rel to new_partition_path */
|
||||||
|
int path_len = 0;
|
||||||
|
while (new_partition_path[path_len]) path_len++;
|
||||||
|
|
||||||
|
int rel_len = 0;
|
||||||
|
while (new_rel[rel_len]) rel_len++;
|
||||||
|
|
||||||
|
if (path_len + rel_len >= 256) {
|
||||||
|
serial_write("[BOOTFS] Error: new path too long\n");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
k_memcpy(new_partition_path + path_len, new_rel, rel_len + 1);
|
||||||
|
|
||||||
|
/* Rename on partition filesystem */
|
||||||
|
bool result = vfs_rename("/limine.conf", new_partition_path);
|
||||||
|
|
||||||
|
if (result) {
|
||||||
|
serial_write("[BOOTFS] Renamed limine.conf to ");
|
||||||
|
serial_write(new_rel);
|
||||||
|
serial_write("\n");
|
||||||
|
} else {
|
||||||
|
serial_write("[BOOTFS] Warning: Could not rename limine.conf to ");
|
||||||
|
serial_write(new_rel);
|
||||||
|
serial_write("\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool bootfs_exists(void *fs_private, const char *rel_path) {
|
||||||
|
if (!rel_path) rel_path = "";
|
||||||
|
if (rel_path[0] == '/') rel_path++;
|
||||||
|
|
||||||
|
if (rel_path[0] == '\0') return true;
|
||||||
|
|
||||||
|
if (k_strcmp(rel_path, "limine.conf") == 0) return true;
|
||||||
|
if (k_strcmp(rel_path, "kernel") == 0) return true;
|
||||||
|
if (k_strcmp(rel_path, "initrd") == 0) return true;
|
||||||
|
|
||||||
|
if (k_strcmp(rel_path, "metadata") == 0) return true;
|
||||||
|
if (is_metadata_file(rel_path)) return true;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool bootfs_is_dir(void *fs_private, const char *rel_path) {
|
||||||
|
if (!rel_path) rel_path = "";
|
||||||
|
if (rel_path[0] == '/') rel_path++;
|
||||||
|
|
||||||
|
if (rel_path[0] == '\0') return true;
|
||||||
|
if (k_strcmp(rel_path, "metadata") == 0) return true;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int bootfs_get_info(void *fs_private, const char *rel_path, vfs_dirent_t *info) {
|
||||||
|
if (!info) return -1;
|
||||||
|
if (!rel_path) rel_path = "";
|
||||||
|
if (rel_path[0] == '/') rel_path++;
|
||||||
|
|
||||||
|
k_memset(info, 0, sizeof(vfs_dirent_t));
|
||||||
|
|
||||||
|
if (rel_path[0] == '\0') {
|
||||||
|
k_strcpy(info->name, "/");
|
||||||
|
info->is_directory = 1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (k_strcmp(rel_path, "limine.conf") == 0) {
|
||||||
|
k_strcpy(info->name, "limine.conf");
|
||||||
|
info->size = g_bootfs_state.limine_conf_len;
|
||||||
|
info->is_directory = 0;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (k_strcmp(rel_path, "kernel") == 0) {
|
||||||
|
k_strcpy(info->name, "kernel");
|
||||||
|
info->size = g_bootfs_state.kernel_size;
|
||||||
|
info->is_directory = 0;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (k_strcmp(rel_path, "initrd") == 0) {
|
||||||
|
k_strcpy(info->name, "initrd");
|
||||||
|
info->size = g_bootfs_state.initrd_size;
|
||||||
|
info->is_directory = 0;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (k_strcmp(rel_path, "metadata") == 0) {
|
||||||
|
k_strcpy(info->name, "metadata");
|
||||||
|
info->is_directory = 1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (is_metadata_file(rel_path)) {
|
||||||
|
char temp_buf[4096];
|
||||||
|
int len = generate_metadata_content(rel_path, temp_buf, 4096);
|
||||||
|
k_strcpy(info->name, rel_path + 9);
|
||||||
|
info->size = len;
|
||||||
|
info->is_directory = 0;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint32_t bootfs_get_position(void *file_handle) {
|
||||||
|
bootfs_handle_t *h = (bootfs_handle_t*)file_handle;
|
||||||
|
if (!h) return 0;
|
||||||
|
return h->offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint32_t bootfs_get_size(void *file_handle) {
|
||||||
|
bootfs_handle_t *h = (bootfs_handle_t*)file_handle;
|
||||||
|
if (!h) return 0;
|
||||||
|
|
||||||
|
if (k_strcmp(h->path, "limine.conf") == 0) {
|
||||||
|
return g_bootfs_state.limine_conf_len;
|
||||||
|
} else if (k_strcmp(h->path, "kernel") == 0) {
|
||||||
|
return g_bootfs_state.kernel_size;
|
||||||
|
} else if (k_strcmp(h->path, "initrd") == 0) {
|
||||||
|
return g_bootfs_state.initrd_size;
|
||||||
|
} else if (is_metadata_file(h->path)) {
|
||||||
|
char temp_buf[4096];
|
||||||
|
return generate_metadata_content(h->path, temp_buf, 4096);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
vfs_fs_ops_t* bootfs_get_ops(void) {
|
||||||
|
return &bootfs_ops;
|
||||||
|
}
|
||||||
|
|
||||||
|
void bootfs_state_init(void) {
|
||||||
|
k_memset(&g_bootfs_state, 0, sizeof(bootfs_state_t));
|
||||||
|
|
||||||
|
k_strcpy(g_bootfs_state.bootloader_name, "Limine");
|
||||||
|
k_strcpy(g_bootfs_state.bootloader_version, "6.0.0");
|
||||||
|
|
||||||
|
|
||||||
|
g_bootfs_state.limine_conf[0] = '\0';
|
||||||
|
g_bootfs_state.limine_conf_len = 0;
|
||||||
|
|
||||||
|
g_bootfs_state.kernel_size = 0;
|
||||||
|
g_bootfs_state.initrd_size = 0;
|
||||||
|
g_bootfs_state.boot_time_ms = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void bootfs_init(void) {
|
||||||
|
bootfs_state_init();
|
||||||
|
}
|
||||||
|
|
||||||
|
void bootfs_refresh_from_disk(void) {
|
||||||
|
extern vfs_file_t* vfs_open(const char *path, const char *mode);
|
||||||
|
extern int vfs_read(vfs_file_t *file, void *buf, int size);
|
||||||
|
extern void vfs_close(vfs_file_t *file);
|
||||||
|
|
||||||
|
vfs_file_t *boot_conf = vfs_open("/limine.conf", "r");
|
||||||
|
if (boot_conf) {
|
||||||
|
int bytes_read = vfs_read(boot_conf, g_bootfs_state.limine_conf, 2047);
|
||||||
|
if (bytes_read > 0) {
|
||||||
|
g_bootfs_state.limine_conf[bytes_read] = '\0';
|
||||||
|
g_bootfs_state.limine_conf_len = bytes_read;
|
||||||
|
serial_write("[BOOTFS] Loaded limine.conf from partition: ");
|
||||||
|
extern void serial_write_hex(uint64_t value);
|
||||||
|
serial_write_hex(bytes_read);
|
||||||
|
serial_write(" bytes\n");
|
||||||
|
}
|
||||||
|
vfs_close(boot_conf);
|
||||||
|
} else {
|
||||||
|
serial_write("[BOOTFS] Warning: /limine.conf not found on partition\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
13
src/fs/bootfs.h
Normal file
13
src/fs/bootfs.h
Normal file
|
|
@ -0,0 +1,13 @@
|
||||||
|
// Copyright (c) 2023-2026 Chris (boreddevnl)
|
||||||
|
// This software is released under the GNU General Public License v3.0. See LICENSE file for details.
|
||||||
|
// This header needs to maintain in any file it is present in, as per the GPL license terms.
|
||||||
|
#ifndef BOOTFS_H
|
||||||
|
#define BOOTFS_H
|
||||||
|
|
||||||
|
#include "vfs.h"
|
||||||
|
|
||||||
|
void bootfs_init(void);
|
||||||
|
void bootfs_refresh_from_disk(void);
|
||||||
|
vfs_fs_ops_t* bootfs_get_ops(void);
|
||||||
|
|
||||||
|
#endif
|
||||||
24
src/sys/bootfs_state.h
Normal file
24
src/sys/bootfs_state.h
Normal file
|
|
@ -0,0 +1,24 @@
|
||||||
|
// Copyright (c) 2023-2026 Chris (boreddevnl)
|
||||||
|
// This software is released under the GNU General Public License v3.0. See LICENSE file for details.
|
||||||
|
#ifndef BOOTFS_STATE_H
|
||||||
|
#define BOOTFS_STATE_H
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
char bootloader_name[64];
|
||||||
|
char bootloader_version[64];
|
||||||
|
uint64_t boot_time_ms;
|
||||||
|
uint8_t boot_flags;
|
||||||
|
char limine_conf[2048];
|
||||||
|
int limine_conf_len;
|
||||||
|
uint32_t num_modules;
|
||||||
|
uint32_t kernel_size;
|
||||||
|
uint32_t initrd_size;
|
||||||
|
|
||||||
|
} bootfs_state_t;
|
||||||
|
extern bootfs_state_t g_bootfs_state;
|
||||||
|
void bootfs_state_init(void);
|
||||||
|
|
||||||
|
#endif
|
||||||
Loading…
Reference in a new issue