VFS mount/umount + sys_open/close/read/fake write

This commit is contained in:
2026-04-10 14:31:38 +02:00
parent 17589d72cf
commit aff113d02b
10 changed files with 592 additions and 12 deletions
+2
View File
@@ -28,6 +28,7 @@
#define PROCESS_NAME_MAX 64 #define PROCESS_NAME_MAX 64
#define PROCESS_STACK_SIZE 0x10000 // 64kb #define PROCESS_STACK_SIZE 0x10000 // 64kb
#define PROCESS_STACK_TOP 0x80000000 #define PROCESS_STACK_TOP 0x80000000
#define PROCESS_FD_MAX 32
/* sched */ /* sched */
// 1 tick = 1 ms => quantum = 10ms // 1 tick = 1 ms => quantum = 10ms
@@ -47,6 +48,7 @@
/* fs */ /* fs */
#define CALYXFS_FILES_MAX 10 #define CALYXFS_FILES_MAX 10
#define TAR_OPEN_FILES_MAX 64
/* paging */ /* paging */
#define PAGING_MAX_PHYS 0x200000000 #define PAGING_MAX_PHYS 0x200000000
+6
View File
@@ -9,6 +9,7 @@
#include <stdint.h> #include <stdint.h>
#include <limine.h> #include <limine.h>
#include <stddef.h>
struct tar_header struct tar_header
{ {
@@ -33,4 +34,9 @@ int tar_init_fs(struct limine_file* file);
struct tar_header* tar_file_lookup(const char* filename); struct tar_header* tar_file_lookup(const char* filename);
void tar_file_read(struct tar_header* header, uint8_t* buf); void tar_file_read(struct tar_header* header, uint8_t* buf);
int tar_open(const char* path, int flags);
int tar_close(int fd);
int64_t tar_read(int fd, char* buf, size_t count);
int64_t tar_write(int fd, char* buf, size_t count);
#endif #endif
+50
View File
@@ -0,0 +1,50 @@
/*
* @author xamidev <xamidev@riseup.net>
* @brief Virtual filesystem layer
* @license GPL-3.0-only
*/
/*
PepperOS will not work like the Unix-based mountpoint approach,
but rather like what Windows does. Filesystems will be separated
into "drives", and each drive will have a number assigned.
*/
#ifndef VFS_H
#define VFS_H
#include <limine.h>
#include <stddef.h>
#include <stdint.h>
typedef enum
{
DRIVE_TAR
} DriveType;
struct drive
{
unsigned int id;
DriveType type;
struct fs_operations* operations;
struct drive* next;
};
struct fs_operations
{
int (*open)(const char* path, int flags);
int (*close)(int fd);
int64_t (*read)(int fd, char* buf, size_t count);
int64_t (*write)(int fd, char* buf, size_t count);
};
int vfs_mount(struct limine_file* file, DriveType type);
int vfs_umount(unsigned int drive_id);
int vfs_open(const char* path, int flags);
int vfs_close(int fd);
int64_t vfs_read(int fd, char* buf, size_t count);
int64_t vfs_write(int fd, const char* buf, size_t count);
#endif
+7 -1
View File
@@ -10,7 +10,13 @@
#include "limine.h" #include "limine.h"
enum ErrorCodes { enum ErrorCodes {
ENOMEM, ENOMEM,
EIO EIO,
EINVAL,
ENOENT,
EFAULT,
EBADF,
EBUSY,
ENOSYS
}; };
#define CLEAR_INTERRUPTS __asm__ volatile("cli") #define CLEAR_INTERRUPTS __asm__ volatile("cli")
+13
View File
@@ -11,6 +11,7 @@
#include <config.h> #include <config.h>
#include <stdint.h> #include <stdint.h>
#include <limine.h> #include <limine.h>
#include <stdbool.h>
typedef enum { typedef enum {
READY, READY,
@@ -18,6 +19,12 @@ typedef enum {
DEAD DEAD
} status_t; } status_t;
struct process_fd {
bool used;
unsigned int drive_id;
int fs_fd;
};
struct process { struct process {
size_t pid; size_t pid;
char name[PROCESS_NAME_MAX]; char name[PROCESS_NAME_MAX];
@@ -26,6 +33,7 @@ struct process {
struct cpu_status* context; struct cpu_status* context;
void* root_page_table; // Process PML4 (should contain kernel PML4 in higher half [256-511] void* root_page_table; // Process PML4 (should contain kernel PML4 in higher half [256-511]
void* kernel_stack; // Used for interrupts (syscall: int 0x80), defines the TSS RSP0 void* kernel_stack; // Used for interrupts (syscall: int 0x80), defines the TSS RSP0
struct process_fd fds[PROCESS_FD_MAX];
struct process* next; struct process* next;
}; };
@@ -40,4 +48,9 @@ void process_display_list(struct process* processes_list);
void process_create_user(struct limine_file* file, char* name); void process_create_user(struct limine_file* file, char* name);
void process_fd_init(struct process* proc);
int process_fd_alloc(struct process* proc, unsigned int drive_id, int fs_fd);
int process_fd_get_fsfd(struct process* proc, int fd, unsigned int* drive_id, int* fs_fd);
int process_fd_release(struct process* proc, int fd);
#endif #endif
+31 -4
View File
@@ -10,26 +10,45 @@
#include <stddef.h> #include <stddef.h>
#include <io/term/term.h> #include <io/term/term.h>
#include <sched/process.h> #include <sched/process.h>
#include <fs/vfs.h>
extern struct process* current_process; extern struct process* current_process;
void sys_write(unsigned int fd, const char* buf, size_t count) int64_t sys_read(unsigned int fd, char* buf, size_t count)
{
return vfs_read((int)fd, buf, count);
}
int64_t sys_write(unsigned int fd, const char* buf, size_t count)
{ {
switch (fd) { switch (fd) {
case 1: //stdout case 1: //stdout
for (size_t i=0; i<count; i++) { for (size_t i=0; i<count; i++) {
internal_putc(buf[i], NULL); internal_putc(buf[i], NULL);
} }
break; return (int64_t)count;
case 2: //stderr case 2: //stderr
for (size_t i=0; i<count; i++) { for (size_t i=0; i<count; i++) {
internal_putc(buf[i], NULL); internal_putc(buf[i], NULL);
} }
break; return (int64_t)count;
default:
return vfs_write((int)fd, buf, count);
} }
} }
int64_t sys_open(const char* path, int flags)
{
return vfs_open(path, flags);
}
int64_t sys_close(unsigned int fd)
{
return vfs_close((int)fd);
}
void sys_exit(int error_code) void sys_exit(int error_code)
{ {
current_process->status = DEAD; current_process->status = DEAD;
@@ -61,12 +80,20 @@ struct cpu_status* syscall_handler(struct cpu_status* regs)
switch (regs->rax) switch (regs->rax)
{ {
case 0: //sys_read case 0: //sys_read
regs->rax = (uint64_t)sys_read((unsigned int)regs->rdi, (char*)regs->rsi, (size_t)regs->rdx);
break; break;
case 1: //sys_write case 1: //sys_write
sys_write(regs->rdi, (char*)regs->rsi, regs->rdx); regs->rax = (uint64_t)sys_write((unsigned int)regs->rdi, (const char*)regs->rsi, (size_t)regs->rdx);
break;
case 2: //sys_open
regs->rax = (uint64_t)sys_open((const char*)regs->rdi, (int)regs->rsi);
break;
case 3: //sys_close
regs->rax = (uint64_t)sys_close((unsigned int)regs->rdi);
break; break;
case 60: //sys_exit case 60: //sys_exit
sys_exit(regs->rdi); sys_exit(regs->rdi);
regs->rax = 0;
break; break;
default: default:
regs->rax = 0xbad515ca11; regs->rax = 0xbad515ca11;
+113
View File
@@ -25,6 +25,14 @@
struct tar_header* headers[CALYXFS_FILES_MAX] = {0}; struct tar_header* headers[CALYXFS_FILES_MAX] = {0};
struct tar_open_file {
bool used;
struct tar_header* header;
size_t offset;
};
struct tar_open_file open_files[TAR_OPEN_FILES_MAX] = {0};
struct tar_file archive; struct tar_file archive;
#define TAR_BLOCK_SIZE 512 #define TAR_BLOCK_SIZE 512
@@ -101,6 +109,7 @@ int tar_init_fs(struct limine_file* file)
DEBUG("calyxfs found at 0x%p (size=%u)", file->address, file->size); DEBUG("calyxfs found at 0x%p (size=%u)", file->address, file->size);
archive.address = file->address; archive.address = file->address;
archive.size = file->size; archive.size = file->size;
memset(open_files, 0, sizeof(open_files));
tar_parse((uint64_t)archive.address); tar_parse((uint64_t)archive.address);
return 0; return 0;
} }
@@ -179,4 +188,108 @@ void tar_file_read(struct tar_header* header, uint8_t* buf)
void* file_ptr = (void*)((uint8_t*)header + TAR_BLOCK_SIZE); void* file_ptr = (void*)((uint8_t*)header + TAR_BLOCK_SIZE);
memcpy(buf, (void*)file_ptr, sz); memcpy(buf, (void*)file_ptr, sz);
}
int tar_open(const char* path, int flags)
{
if (!path) {
return -EINVAL;
}
if (flags != 0) {
return -ENOSYS;
}
const char* lookup_path = path;
while (*lookup_path == '/') {
lookup_path++;
}
if (*lookup_path == '\0') {
return -EINVAL;
}
struct tar_header* header = tar_file_lookup(lookup_path);
if (!header) {
char prefixed[102] = {0};
prefixed[0] = '.';
prefixed[1] = '/';
size_t i = 0;
while (lookup_path[i] != '\0' && i < sizeof(prefixed) - 3) {
prefixed[2 + i] = lookup_path[i];
i++;
}
prefixed[2 + i] = '\0';
header = tar_file_lookup(prefixed);
}
if (!header) {
return -ENOENT;
}
for (int fd = 0; fd < TAR_OPEN_FILES_MAX; fd++) {
if (!open_files[fd].used) {
open_files[fd].used = true;
open_files[fd].header = header;
open_files[fd].offset = 0;
return fd;
}
}
return -ENOMEM;
}
int tar_close(int fd)
{
if (fd < 0 || fd >= TAR_OPEN_FILES_MAX) {
return -EBADF;
}
if (!open_files[fd].used) {
return -EBADF;
}
open_files[fd].used = false;
open_files[fd].header = NULL;
open_files[fd].offset = 0;
return 0;
}
int64_t tar_read(int fd, char* buf, size_t count)
{
if (!buf || fd < 0 || fd >= TAR_OPEN_FILES_MAX) {
return -EINVAL;
}
if (!open_files[fd].used || !open_files[fd].header) {
return -EBADF;
}
uint32_t file_size = tar_getsize(open_files[fd].header->size);
if (open_files[fd].offset >= file_size) {
return 0;
}
size_t remaining = (size_t)file_size - open_files[fd].offset;
size_t read_count = (count < remaining) ? count : remaining;
uint8_t* file_ptr = (uint8_t*)open_files[fd].header + TAR_BLOCK_SIZE + open_files[fd].offset;
memcpy(buf, file_ptr, read_count);
open_files[fd].offset += read_count;
return (int64_t)read_count;
}
/*
* tar_write - Write to file in TAR archive
*
* Not implemented.
*/
int64_t tar_write(int fd, char* buf, size_t count)
{
(void)fd;
(void)buf;
(void)count;
return -ENOSYS;
} }
+308 -1
View File
@@ -13,4 +13,311 @@ filesystem-dependent functions.
That way we have a nice abstraction layer and can just do calls no matter That way we have a nice abstraction layer and can just do calls no matter
the underlying fs. the underlying fs.
*/ */
#include <fs/tar.h>
#include <fs/vfs.h>
#include <mem/kheap.h>
#include <kernel.h>
#include <sched/process.h>
#include <string/string.h>
extern struct process* current_process;
struct drive* root_drive;
// Bump-allocated (much like PIDs)
unsigned int next_drive_id = 0;
static struct drive* vfs_find_drive(unsigned int drive_id)
{
struct drive* curr = root_drive;
while (curr != NULL) {
if (curr->id == drive_id) {
return curr;
}
curr = curr->next;
}
return NULL;
}
static int vfs_resolve_path(const char* path, struct drive** drive, const char** inner_path)
{
if (!path || !drive || !inner_path) {
return -EINVAL;
}
if (path[0] >= '0' && path[0] <= '9') {
unsigned int drive_id = 0;
size_t idx = 0;
while (path[idx] >= '0' && path[idx] <= '9') {
drive_id = (drive_id * 10) + (unsigned int)(path[idx] - '0');
idx++;
}
if (path[idx] != ':' || path[idx + 1] != '/') {
return -EINVAL;
}
*drive = vfs_find_drive(drive_id);
if (*drive == NULL) {
return -ENOENT;
}
*inner_path = &path[idx + 1];
return 0;
}
if (root_drive == NULL) {
return -ENOENT;
}
*drive = root_drive;
*inner_path = path;
return 0;
}
/*
* vfs_add_drive - Add a drive to the drive list
* @new: the new drive
*
* This function adds the @new drive at the end
* of the drive linked list.
*
* Return:
* %0 - on success
*/
int vfs_add_drive(struct drive* new)
{
if (root_drive == NULL) {
root_drive = new;
return 0;
}
struct drive* curr = root_drive;
while (curr->next != NULL) {
curr = curr->next;
}
curr->next = new;
new->next = NULL;
return 0;
}
/*
* vfs_mount - Mount a drive
* @file: Limine-loaded module file
* @type: Filesystem type
*
* This function creates a new drive object and then adds
* it to the drive linked list. It also initializes the
* filesystem driver corresponding to the drive type.
*
* Return:
* %0 - on success
* %-ENOMEM - not enough memory
*/
int vfs_mount(struct limine_file* file, DriveType type)
{
struct fs_operations* ops = NULL;
struct drive* new = kmalloc(sizeof(struct drive));
if (new == NULL) {
return -ENOMEM;
}
new->id = next_drive_id++;
new->type = type;
new->operations = NULL;
new->next = NULL;
switch (type) {
case DRIVE_TAR:
if (tar_init_fs(file) < 0) {
kfree(new);
return -EIO;
}
ops = kmalloc(sizeof(struct fs_operations));
if (ops == NULL) {
kfree(new);
return -ENOMEM;
}
ops->open = tar_open;
ops->close = tar_close;
ops->read = tar_read;
ops->write = tar_write;
new->operations = ops;
break;
default:
kfree(new);
return -EINVAL;
}
return vfs_add_drive(new);
}
/*
* vfs_remove_drive - Remove a drive from the drive list
* @old: Drive to remove
*
* Return:
* %0 - on success
*/
int vfs_remove_drive(struct drive* old)
{
if (!old || !root_drive) {
return -ENOENT;
}
if (root_drive == old) {
root_drive = old->next;
old->next = NULL;
if (old->operations) {
kfree(old->operations);
}
kfree(old);
return 0;
}
struct drive* tmp = root_drive;
while (tmp->next != NULL && tmp->next != old) {
tmp = tmp->next;
}
if (tmp->next == NULL) {
return -ENOENT;
}
// Next is the one to remove
tmp->next = old->next;
old->next = NULL;
if (old->operations) {
kfree(old->operations);
}
kfree(old);
return 0;
}
/*
* vfs_umount - Unmount a drive
* @drive_id: drive ID to unmount
*
* Return:
* %0 - on success
* %-ENOENT - drive not found
*/
int vfs_umount(unsigned int drive_id)
{
struct drive* tmp = root_drive;
while (tmp != NULL) {
if (tmp->id == drive_id) {
goto found;
}
tmp = tmp->next;
}
return -ENOENT;
found:
return vfs_remove_drive(tmp);
}
int vfs_open(const char* path, int flags)
{
struct drive* drive = NULL;
const char* inner_path = NULL;
if (!current_process) {
return -EINVAL;
}
int rc = vfs_resolve_path(path, &drive, &inner_path);
if (rc < 0) {
return rc;
}
if (!drive->operations || !drive->operations->open) {
return -ENOSYS;
}
int fs_fd = drive->operations->open(inner_path, flags);
if (fs_fd < 0) {
return fs_fd;
}
int proc_fd = process_fd_alloc(current_process, drive->id, fs_fd);
if (proc_fd < 0) {
drive->operations->close(fs_fd);
return proc_fd;
}
return proc_fd;
}
int vfs_close(int fd)
{
if (!current_process) {
return -EINVAL;
}
unsigned int drive_id = 0;
int fs_fd = -1;
int rc = process_fd_get_fsfd(current_process, fd, &drive_id, &fs_fd);
if (rc < 0) {
return rc;
}
struct drive* drive = vfs_find_drive(drive_id);
if (!drive || !drive->operations || !drive->operations->close) {
return -ENOENT;
}
rc = drive->operations->close(fs_fd);
if (rc < 0) {
return rc;
}
return process_fd_release(current_process, fd);
}
int64_t vfs_read(int fd, char* buf, size_t count)
{
if (!current_process || !buf) {
return -EINVAL;
}
unsigned int drive_id = 0;
int fs_fd = -1;
int rc = process_fd_get_fsfd(current_process, fd, &drive_id, &fs_fd);
if (rc < 0) {
return rc;
}
struct drive* drive = vfs_find_drive(drive_id);
if (!drive || !drive->operations || !drive->operations->read) {
return -ENOENT;
}
return (int64_t)drive->operations->read(fs_fd, buf, count);
}
int64_t vfs_write(int fd, const char* buf, size_t count)
{
if (!current_process || !buf) {
return -EINVAL;
}
unsigned int drive_id = 0;
int fs_fd = -1;
int rc = process_fd_get_fsfd(current_process, fd, &drive_id, &fs_fd);
if (rc < 0) {
return rc;
}
struct drive* drive = vfs_find_drive(drive_id);
if (!drive || !drive->operations || !drive->operations->write) {
return -ENOENT;
}
return (int64_t)drive->operations->write(fs_fd, (char*)buf, count);
}
+1 -6
View File
@@ -4,6 +4,7 @@
* @license GPL-3.0-only * @license GPL-3.0-only
*/ */
#include "fs/vfs.h"
#include <stdbool.h> #include <stdbool.h>
#include <stddef.h> #include <stddef.h>
#include <limine.h> #include <limine.h>
@@ -125,14 +126,8 @@ void kmain()
} }
file = boot_ctx.module->modules[0]; file = boot_ctx.module->modules[0];
tar_init_fs(file);
/* DANGER ZONE (tests)*/ /* DANGER ZONE (tests)*/
struct tar_header* header = tar_file_lookup("./welcome.txt");
uint8_t buf[1000] = {0};
tar_file_read(header, buf);
DEBUG("-BEGIN BUFFER-%s-END BUFFER-", buf);
/* END DANGER ZONE */ /* END DANGER ZONE */
scheduler_init(); scheduler_init();
+61
View File
@@ -26,6 +26,64 @@ extern uint64_t *kernel_pml4;
size_t next_free_pid = 0; size_t next_free_pid = 0;
void process_fd_init(struct process* proc)
{
if (!proc) {
return;
}
memset(proc->fds, 0, sizeof(proc->fds));
}
int process_fd_alloc(struct process* proc, unsigned int drive_id, int fs_fd)
{
if (!proc || fs_fd < 0) {
return -EINVAL;
}
for (int fd = 3; fd < PROCESS_FD_MAX; fd++) {
if (!proc->fds[fd].used) {
proc->fds[fd].used = true;
proc->fds[fd].drive_id = drive_id;
proc->fds[fd].fs_fd = fs_fd;
return fd;
}
}
return -ENOMEM;
}
int process_fd_get_fsfd(struct process* proc, int fd, unsigned int* drive_id, int* fs_fd)
{
if (!proc || !drive_id || !fs_fd || fd < 0 || fd >= PROCESS_FD_MAX) {
return -EINVAL;
}
if (!proc->fds[fd].used) {
return -EBADF;
}
*drive_id = proc->fds[fd].drive_id;
*fs_fd = proc->fds[fd].fs_fd;
return 0;
}
int process_fd_release(struct process* proc, int fd)
{
if (!proc || fd < 0 || fd >= PROCESS_FD_MAX) {
return -EINVAL;
}
if (!proc->fds[fd].used) {
return -EBADF;
}
proc->fds[fd].used = false;
proc->fds[fd].drive_id = 0;
proc->fds[fd].fs_fd = -1;
return 0;
}
/* /*
* process_init - Initializes process list * process_init - Initializes process list
*/ */
@@ -100,6 +158,8 @@ struct process* process_create(char* name, void(*function)(void*), void* arg)
proc->kernel_stack = kalloc_stack(); proc->kernel_stack = kalloc_stack();
process_fd_init(proc);
proc->next = 0; proc->next = 0;
process_add(&processes_list, proc); process_add(&processes_list, proc);
@@ -255,6 +315,7 @@ void process_create_user(struct limine_file* file, char* name)
proc->context->iret_ss = USER_DATA_SEGMENT | 3; proc->context->iret_ss = USER_DATA_SEGMENT | 3;
proc->context->iret_cs = USER_CODE_SEGMENT | 3; proc->context->iret_cs = USER_CODE_SEGMENT | 3;
proc->context->iret_flags = 0x202; // Interrupt Flag set proc->context->iret_flags = 0x202; // Interrupt Flag set
process_fd_init(proc);
void* exec_addr = file->address; void* exec_addr = file->address;
uint64_t exec_size = file->size; uint64_t exec_size = file->size;