From 7726fd2f003616b601139db6a881285efab5f285 Mon Sep 17 00:00:00 2001 From: kamkow1 Date: Sun, 15 Feb 2026 21:34:07 +0100 Subject: [PATCH] Implement VFS syscalls --- ce/Makefile | 4 ++ ce/ce.c | 7 +-- include/m/path.h | 6 ++ include/m/syscall_defs.h | 4 ++ init.cmd | 1 + init/init.c | 16 ++++- kernel/amd64/smp.c | 2 +- kernel/fs/path.c | 2 +- kernel/fs/ramdiskfs.c | 6 +- kernel/fs/vfs.c | 78 +++++++++++++++++++++++- kernel/fs/vfs.h | 12 +++- kernel/libk/minmax.h | 7 +++ kernel/proc/proc.c | 33 +++++++---- kernel/proc/proc.h | 2 +- kernel/proc/procgroup.c | 5 ++ kernel/syscall/syscall.c | 125 ++++++++++++++++++++++++++++++++++++++- libmsl/m/system.c | 12 ++++ libmsl/m/system.h | 13 ++++ make/dist.mk | 3 +- 19 files changed, 307 insertions(+), 31 deletions(-) create mode 100644 include/m/path.h create mode 100644 init.cmd create mode 100644 kernel/libk/minmax.h diff --git a/ce/Makefile b/ce/Makefile index d16094b..a3bbf4e 100644 --- a/ce/Makefile +++ b/ce/Makefile @@ -1 +1,5 @@ +include ../make/ufuncs.mk + +$(eval $(call add_lib,libstring)) + include ../make/user.mk diff --git a/ce/ce.c b/ce/ce.c index 6d81e82..b60ff26 100644 --- a/ce/ce.c +++ b/ce/ce.c @@ -1,7 +1,4 @@ #include +#include -void app_main (void) { - for (;;) { - /* test ('x'); */ - } -} +void app_main (void) {} diff --git a/include/m/path.h b/include/m/path.h new file mode 100644 index 0000000..8ade9dd --- /dev/null +++ b/include/m/path.h @@ -0,0 +1,6 @@ +#ifndef _M_PATH_H +#define _M_PATH_H + +#define MAX_PATH 1024 + +#endif // _M_PATH_H diff --git a/include/m/syscall_defs.h b/include/m/syscall_defs.h index 4f3a685..d08a6e8 100644 --- a/include/m/syscall_defs.h +++ b/include/m/syscall_defs.h @@ -14,5 +14,9 @@ #define SYS_ARGUMENT_PTR 11 #define SYS_DEVICE_DO 12 #define SYS_EXEC 13 +#define SYS_OPEN 14 +#define SYS_CLOSE 15 +#define SYS_READ 16 +#define SYS_DESCRIBE 17 #endif // _M_SYSCALL_DEFS_H diff --git a/init.cmd b/init.cmd new file mode 100644 index 0000000..cd08755 --- /dev/null +++ b/init.cmd @@ -0,0 +1 @@ +Hello world! diff --git a/init/init.c b/init/init.c index b86e519..d4114bf 100644 --- a/init/init.c +++ b/init/init.c @@ -38,9 +38,19 @@ void app_main (void) { /* process_exec ("ramdisk:/ce"); */ - process_spawn (&app_proc, (void*)'b'); - process_spawn (&app_proc, (void*)'c'); - process_spawn (&app_proc, (void*)'d'); + /* process_spawn (&app_proc, (void*)'b'); */ + /* process_spawn (&app_proc, (void*)'c'); */ + /* process_spawn (&app_proc, (void*)'d'); */ + + const char* path = "ramdisk:/init.cmd"; + char buffer[1024]; + memset (buffer, 0, sizeof (buffer)); + + open (path); + read (path, 0, (uint8_t*)buffer, sizeof (buffer)); + close (path); + + terminal_print (buffer, strlen (buffer)); for (;;) { int ch = kb_read_key (); diff --git a/kernel/amd64/smp.c b/kernel/amd64/smp.c index 7ada72a..29f7f41 100644 --- a/kernel/amd64/smp.c +++ b/kernel/amd64/smp.c @@ -87,7 +87,7 @@ static void amd64_smp_bootstrap (struct limine_mp_info* mp_info) { atomic_fetch_sub (&cpu_counter, 1); - struct proc* spin_proc = proc_from_file ("ramdisk", "/spin"); + struct proc* spin_proc = proc_from_file (NULL, "ramdisk", "/spin"); struct cpu* spin_cpu = thiscpu; proc_register (spin_proc, &spin_cpu); diff --git a/kernel/fs/path.c b/kernel/fs/path.c index 0e9eb91..e0edce8 100644 --- a/kernel/fs/path.c +++ b/kernel/fs/path.c @@ -4,7 +4,7 @@ bool path_validate_char (char ch) { return ((ch >= '0' && ch <= '9') || (ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') || - (ch == '_') || (ch == '-') || (ch == '/')); + (ch == '_') || (ch == '-') || (ch == '/') || (ch == '.')); } bool path_validate (const char* path) { diff --git a/kernel/fs/ramdiskfs.c b/kernel/fs/ramdiskfs.c index 12e7bc6..3ef47b1 100644 --- a/kernel/fs/ramdiskfs.c +++ b/kernel/fs/ramdiskfs.c @@ -1,6 +1,7 @@ #include #include #include +#include #include #include #include @@ -129,10 +130,7 @@ int ramdiskfs_read (struct vfs_mountpoint* mountpoint, const char* path, uint8_t if (file == NULL) return -ST_NOT_FOUND; - if (off + size > file->size) - return -ST_OOB_ERROR; - - memcpy (buffer, (void*)((uintptr_t)file->content + off), size); + memcpy (buffer, (void*)((uintptr_t)file->content + off), min (size, file->size)); return ST_OK; } diff --git a/kernel/fs/vfs.c b/kernel/fs/vfs.c index 138f040..426f71a 100644 --- a/kernel/fs/vfs.c +++ b/kernel/fs/vfs.c @@ -7,6 +7,7 @@ #include #include #include +#include #include #include @@ -75,7 +76,9 @@ struct vfs_mountpoint* vfs_create_mountpoint (const char* key, int fs_type) { return mountpoint; } -int vfs_describe (const char* mountpoint, const char* path, struct fs_desc_buffer* desc) { +int vfs_open (struct procgroup* procgroup, const char* mountpoint, const char* path) { + (void)path; + struct vfs_mountpoint* vmp = vfs_find_mountpoint (mountpoint); if (vmp == NULL) @@ -83,6 +86,51 @@ int vfs_describe (const char* mountpoint, const char* path, struct fs_desc_buffe spin_lock (&vmp->lock); + vmp->ownerpg = procgroup; + vmp->locked = true; + + spin_unlock (&vmp->lock); + + return ST_OK; +} + +int vfs_close (struct procgroup* procgroup, const char* mountpoint, const char* path) { + (void)path; + + struct vfs_mountpoint* vmp = vfs_find_mountpoint (mountpoint); + + if (vmp == NULL) + return -ST_NOT_FOUND; + + spin_lock (&vmp->lock); + + if (procgroup != NULL && vmp->ownerpg != procgroup) { + spin_unlock (&vmp->lock); + return -ST_PERMISSION_ERROR; + } + + vmp->locked = false; + vmp->ownerpg = NULL; + + spin_unlock (&vmp->lock); + + return ST_OK; +} + +int vfs_describe (struct procgroup* procgroup, const char* mountpoint, const char* path, + struct fs_desc_buffer* desc) { + struct vfs_mountpoint* vmp = vfs_find_mountpoint (mountpoint); + + if (vmp == NULL) + return -ST_NOT_FOUND; + + spin_lock (&vmp->lock); + + if ((procgroup != NULL && vmp->ownerpg != procgroup) && vmp->locked) { + spin_unlock (&vmp->lock); + return -ST_PERMISSION_ERROR; + } + int ret = vmp->driver_ops.describe (vmp, path, desc); spin_unlock (&vmp->lock); @@ -90,7 +138,8 @@ int vfs_describe (const char* mountpoint, const char* path, struct fs_desc_buffe return ret; } -int vfs_read (const char* mountpoint, const char* path, uint8_t* buffer, size_t off, size_t size) { +int vfs_read (struct procgroup* procgroup, const char* mountpoint, const char* path, + uint8_t* buffer, size_t off, size_t size) { struct vfs_mountpoint* vmp = vfs_find_mountpoint (mountpoint); if (vmp == NULL) @@ -98,6 +147,11 @@ int vfs_read (const char* mountpoint, const char* path, uint8_t* buffer, size_t spin_lock (&vmp->lock); + if ((procgroup != NULL && vmp->ownerpg != procgroup) && vmp->locked) { + spin_unlock (&vmp->lock); + return -ST_PERMISSION_ERROR; + } + int ret = vmp->driver_ops.read (vmp, path, buffer, off, size); spin_unlock (&vmp->lock); @@ -105,6 +159,26 @@ int vfs_read (const char* mountpoint, const char* path, uint8_t* buffer, size_t return ret; } +void vfs_procgroup_cleanup (struct procgroup* procgroup) { + spin_lock (&mount_table.lock); + + for (size_t i = 0; i < lengthof (mount_table.mountpoint_buckets); i++) { + struct hash_node_link* link = mount_table.mountpoint_buckets[i]; + struct vfs_mountpoint* vmp = hash_entry (link, struct vfs_mountpoint, mount_table_link); + + spin_lock (&vmp->lock); + + if (vmp->ownerpg == procgroup) { + vmp->locked = false; + vmp->ownerpg = NULL; + } + + spin_unlock (&vmp->lock); + } + + spin_unlock (&mount_table.lock); +} + void vfs_init (void) { memset (&mount_table, 0, sizeof (mount_table)); diff --git a/kernel/fs/vfs.h b/kernel/fs/vfs.h index 13f4812..b37aeea 100644 --- a/kernel/fs/vfs.h +++ b/kernel/fs/vfs.h @@ -5,6 +5,7 @@ #include #include #include +#include #include #define VFS_RAMDISKFS 0 @@ -14,6 +15,8 @@ struct vfs_mountpoint { struct hash_node_link mount_table_link; int fs_type; spin_lock_t lock; + bool locked; + struct procgroup* ownerpg; struct { bool (*mount) (struct vfs_mountpoint* mountpoint); int (*describe) (struct vfs_mountpoint* mountpoint, const char* path, @@ -29,8 +32,13 @@ struct vfs_mount_table { }; struct vfs_mountpoint* vfs_create_mountpoint (const char* key, int fs_type); -int vfs_describe (const char* mountpoint, const char* path, struct fs_desc_buffer* desc); -int vfs_read (const char* mountpoint, const char* path, uint8_t* buffer, size_t off, size_t size); +int vfs_describe (struct procgroup* procgroup, const char* mountpoint, const char* path, + struct fs_desc_buffer* desc); +int vfs_read (struct procgroup* procgroup, const char* mountpoint, const char* path, + uint8_t* buffer, size_t off, size_t size); +int vfs_close (struct procgroup* procgroup, const char* mountpoint, const char* path); +int vfs_open (struct procgroup* procgroup, const char* mountpoint, const char* path); +void vfs_procgroup_cleanup (struct procgroup* procgroup); void vfs_init (void); #endif // _KERNEL_FS_VFS_H diff --git a/kernel/libk/minmax.h b/kernel/libk/minmax.h new file mode 100644 index 0000000..aad8857 --- /dev/null +++ b/kernel/libk/minmax.h @@ -0,0 +1,7 @@ +#ifndef _KERNEL_LIBK_MINMAX_H +#define _KERNEL_LIBK_MINMAX_H + +#define max(a, b) ((a) > (b) ? (a) : (b)) +#define min(a, b) ((a) < (b) ? (a) : (b)) + +#endif // _KERNEL_LIBK_MINMAX_H diff --git a/kernel/proc/proc.c b/kernel/proc/proc.c index 42096c6..f98e508 100644 --- a/kernel/proc/proc.c +++ b/kernel/proc/proc.c @@ -103,25 +103,38 @@ struct elf_aux proc_load_segments (struct proc* proc, uint8_t* elf) { return aux; } -struct proc* proc_from_file (const char* mountpoint, const char* path) { +struct proc* proc_from_file (struct procgroup* procgroup, const char* mountpoint, + const char* path) { struct fs_desc_buffer desc; - if (vfs_describe (mountpoint, path, &desc) != ST_OK) + if (vfs_open (procgroup, mountpoint, path) != ST_OK) return NULL; - if (desc.type != FS_FILE) + if (vfs_describe (procgroup, mountpoint, path, &desc) != ST_OK) { + vfs_close (procgroup, mountpoint, path); return NULL; + } + + if (desc.type != FS_FILE) { + vfs_close (procgroup, mountpoint, path); + return NULL; + } uint8_t* temp_buffer = malloc (desc.size); - if (temp_buffer == NULL) - return NULL; - - if (vfs_read (mountpoint, path, temp_buffer, 0, desc.size) != ST_OK) { - free (temp_buffer); + if (temp_buffer == NULL) { + vfs_close (procgroup, mountpoint, path); return NULL; } + if (vfs_read (procgroup, mountpoint, path, temp_buffer, 0, desc.size) != ST_OK) { + free (temp_buffer); + vfs_close (procgroup, mountpoint, path); + return NULL; + } + + vfs_close (procgroup, mountpoint, path); + bool ok = proc_check_elf (temp_buffer); DEBUG ("Spawning %s:%s, elf header %s\n", mountpoint, path, ok ? "ok" : "bad"); @@ -300,11 +313,11 @@ void proc_init (void) { irq_attach (&proc_irq_sched, NULL, CPU_REQUEST_SCHED); #endif - struct proc* spin_proc = proc_from_file ("ramdisk", "/spin"); + struct proc* spin_proc = proc_from_file (NULL, "ramdisk", "/spin"); struct cpu* spin_cpu = thiscpu; proc_register (spin_proc, &spin_cpu); - struct proc* init = proc_from_file ("ramdisk", "/init"); + struct proc* init = proc_from_file (NULL, "ramdisk", "/init"); init->procgroup->capabilities |= (PROC_CAP_TERMINAL | PROC_CAP_KB); struct cpu* init_cpu = thiscpu; proc_register (init, &init_cpu); diff --git a/kernel/proc/proc.h b/kernel/proc/proc.h index 525f655..d7a2d78 100644 --- a/kernel/proc/proc.h +++ b/kernel/proc/proc.h @@ -51,7 +51,7 @@ bool proc_kill (struct proc* proc, struct cpu** reschedule_cpu); struct elf_aux proc_load_segments (struct proc* proc, uint8_t* elf); bool proc_register (struct proc* proc, struct cpu** reschedule_cpu); struct proc* proc_find_pid (int pid); -struct proc* proc_from_file (const char* mountpoint, const char* path); +struct proc* proc_from_file (struct procgroup* procgroup, const char* mountpoint, const char* path); void proc_init (void); #endif // _KERNEL_PROC_PROC_H diff --git a/kernel/proc/procgroup.c b/kernel/proc/procgroup.c index b14445d..2ea2bd3 100644 --- a/kernel/proc/procgroup.c +++ b/kernel/proc/procgroup.c @@ -1,3 +1,4 @@ +#include #include #include #include @@ -195,6 +196,10 @@ void procgroup_detach (struct procgroup* procgroup, struct proc* proc) { proc_delete_resource (resource, &reschedule_cpu); } + /* unlock VFS owned mountpoints */ + vfs_procgroup_cleanup (procgroup); + + /* delete mappings */ struct list_node_link *mapping_link, *mapping_link_tmp; list_foreach (procgroup->mappings, mapping_link, mapping_link_tmp) { struct proc_mapping* mapping = diff --git a/kernel/syscall/syscall.c b/kernel/syscall/syscall.c index d3e02f4..ae901ba 100644 --- a/kernel/syscall/syscall.c +++ b/kernel/syscall/syscall.c @@ -248,7 +248,7 @@ DEFINE_SYSCALL (sys_exec) { if (!path_parse (path, mountpoint, &subpath)) return SYSRESULT (-ST_BAD_PATH); - struct proc* new = proc_from_file (mountpoint, subpath); + struct proc* new = proc_from_file (proc->procgroup, mountpoint, subpath); if (new == NULL) return SYSRESULT (-ST_EXEC_ERROR); @@ -261,6 +261,125 @@ DEFINE_SYSCALL (sys_exec) { return SYSRESULT (pid); } +/* int open (char* path) */ +DEFINE_SYSCALL (sys_open) { + uintptr_t uvaddr_path = a1; + + struct limine_hhdm_response* hhdm = limine_hhdm_request.response; + + uintptr_t out_paddr; + + spin_lock (&proc->procgroup->lock); + out_paddr = mm_v2p (&proc->procgroup->pd, uvaddr_path); + spin_unlock (&proc->procgroup->lock); + + if (out_paddr == 0) + return SYSRESULT (-ST_BAD_ADDRESS_SPACE); + + const char* path = (const char*)((uintptr_t)hhdm->offset + out_paddr); + + char mountpoint[fieldsizeof (struct vfs_mountpoint, key)]; + const char* subpath = NULL; + + if (!path_parse (path, mountpoint, &subpath)) + return SYSRESULT (-ST_BAD_PATH); + + return SYSRESULT (vfs_open (proc->procgroup, mountpoint, subpath)); +} + +/* int close (char* path) */ +DEFINE_SYSCALL (sys_close) { + uintptr_t uvaddr_path = a1; + + struct limine_hhdm_response* hhdm = limine_hhdm_request.response; + + uintptr_t out_paddr; + + spin_lock (&proc->procgroup->lock); + out_paddr = mm_v2p (&proc->procgroup->pd, uvaddr_path); + spin_unlock (&proc->procgroup->lock); + + if (out_paddr == 0) + return SYSRESULT (-ST_BAD_ADDRESS_SPACE); + + const char* path = (const char*)((uintptr_t)hhdm->offset + out_paddr); + + char mountpoint[fieldsizeof (struct vfs_mountpoint, key)]; + const char* subpath = NULL; + + if (!path_parse (path, mountpoint, &subpath)) + return SYSRESULT (-ST_BAD_PATH); + + return SYSRESULT (vfs_close (proc->procgroup, mountpoint, subpath)); +} + +/* int read (char* path, size_t off, uint8_t* buffer, size_t size) */ +DEFINE_SYSCALL (sys_read) { + uintptr_t uvaddr_path = a1; + size_t off = (size_t)a2; + uintptr_t uvaddr_buffer = a3; + size_t size = (size_t)a4; + + uint8_t* buffer = sys_get_user_buffer (proc, uvaddr_buffer, size); + + if (buffer == NULL) + return SYSRESULT (-ST_BAD_ADDRESS_SPACE); + + struct limine_hhdm_response* hhdm = limine_hhdm_request.response; + + uintptr_t out_paddr; + + spin_lock (&proc->procgroup->lock); + out_paddr = mm_v2p (&proc->procgroup->pd, uvaddr_path); + spin_unlock (&proc->procgroup->lock); + + if (out_paddr == 0) + return SYSRESULT (-ST_BAD_ADDRESS_SPACE); + + const char* path = (const char*)((uintptr_t)hhdm->offset + out_paddr); + + char mountpoint[fieldsizeof (struct vfs_mountpoint, key)]; + const char* subpath = NULL; + + if (!path_parse (path, mountpoint, &subpath)) + return SYSRESULT (-ST_BAD_PATH); + + return SYSRESULT (vfs_read (proc->procgroup, mountpoint, subpath, buffer, off, size)); +} + +/* int describe (char* path, struct fs_desc_buffer* desc) */ +DEFINE_SYSCALL (sys_describe) { + uintptr_t uvaddr_path = a1; + uintptr_t uvaddr_desc = a2; + + struct fs_desc_buffer* desc = + sys_get_user_buffer (proc, uvaddr_desc, sizeof (struct fs_desc_buffer)); + + if (desc == NULL) + return SYSRESULT (-ST_BAD_ADDRESS_SPACE); + + struct limine_hhdm_response* hhdm = limine_hhdm_request.response; + + uintptr_t out_paddr; + + spin_lock (&proc->procgroup->lock); + out_paddr = mm_v2p (&proc->procgroup->pd, uvaddr_path); + spin_unlock (&proc->procgroup->lock); + + if (out_paddr == 0) + return SYSRESULT (-ST_BAD_ADDRESS_SPACE); + + const char* path = (const char*)((uintptr_t)hhdm->offset + out_paddr); + + char mountpoint[fieldsizeof (struct vfs_mountpoint, key)]; + const char* subpath = NULL; + + if (!path_parse (path, mountpoint, &subpath)) + return SYSRESULT (-ST_BAD_PATH); + + return SYSRESULT (vfs_describe (proc->procgroup, mountpoint, subpath, desc)); +} + static syscall_handler_func_t handler_table[] = { [SYS_QUIT] = &sys_quit, [SYS_TEST] = &sys_test, @@ -275,6 +394,10 @@ static syscall_handler_func_t handler_table[] = { [SYS_MUTEX_UNLOCK] = &sys_mutex_unlock, [SYS_DEVICE_DO] = &sys_device_do, [SYS_EXEC] = &sys_exec, + [SYS_OPEN] = &sys_open, + [SYS_CLOSE] = &sys_close, + [SYS_READ] = &sys_read, + [SYS_DESCRIBE] = &sys_describe, }; syscall_handler_func_t syscall_find_handler (int syscall_num) { diff --git a/libmsl/m/system.c b/libmsl/m/system.c index 3c94306..1618c77 100644 --- a/libmsl/m/system.c +++ b/libmsl/m/system.c @@ -40,3 +40,15 @@ int device_do (int device_id, int cmd, void* a1, void* a2, void* a3, void* a4) { } int exec (const char* path) { return (int)do_syscall (SYS_EXEC, path); } + +int open (const char* path) { return (int)do_syscall (SYS_OPEN, path); } + +int close (const char* path) { return (int)do_syscall (SYS_CLOSE, path); } + +int read (const char* path, size_t off, uint8_t* buffer, size_t size) { + return (int)do_syscall (SYS_READ, path, off, buffer, size); +} + +int describe (const char* path, struct fs_desc_buffer* desc) { + return (int)do_syscall (SYS_DESCRIBE, path, desc); +} diff --git a/libmsl/m/system.h b/libmsl/m/system.h index 5c4cd8f..4eb2fb9 100644 --- a/libmsl/m/system.h +++ b/libmsl/m/system.h @@ -1,6 +1,7 @@ #ifndef _LIBMSL_M_SYSTEM_H #define _LIBMSL_M_SYSTEM_H +#include #include #include @@ -52,4 +53,16 @@ int device_do (int device_id, int cmd, void* a1, void* a2, void* a3, void* a4); /* Run external ELF program */ int exec (const char* path); +/* Open a file */ +int open (const char* path); + +/* Close a file */ +int close (const char* path); + +/* Read a file */ +int read (const char* path, size_t off, uint8_t* buffer, size_t size); + +/* describe a file */ +int describe (const char* path, struct fs_desc_buffer* desc); + #endif // _LIBMSL_M_SYSTEM_H diff --git a/make/dist.mk b/make/dist.mk index 743c048..09c384d 100644 --- a/make/dist.mk +++ b/make/dist.mk @@ -1,8 +1,9 @@ exe := $(foreach d,$(apps),$(wildcard $(d)/$(d))) +extra := init.cmd all_dist: mop3dist.tar mop3dist.tar: - tar -cf $@ --transform='s|.*/||' $(exe) + tar -cf $@ --transform='s|.*/||' $(exe) $(extra) .PHONY: all_dist