From 067e938ed71aaf6c2e18c052c5588447512d713c Mon Sep 17 00:00:00 2001 From: Ebrahim Aleem Date: Sun, 26 Apr 2026 15:55:16 -0700 Subject: [PATCH 01/13] stubbed fs_create --- Makefile | 5 ++- drivers/ext2/ext2.c | 10 ++++- kernel/core/fs.c | 62 ++++++++++++++++++-------- kernel/core/syscall.S | 2 + kernel/core/syscall_dispatch.c | 6 +++ kernel/devfs/devfs.c | 7 +++ kernel/include/core/fs.h | 7 ++- kernel/include/core/syscall_dispatch.h | 1 + kernel/include/core/syscall_vectors.h | 8 +++- kernel/include/devfs/devfs.h | 1 + userland/Makefile | 16 +++---- 11 files changed, 92 insertions(+), 33 deletions(-) diff --git a/Makefile b/Makefile index 3a4a4f4..6a37fd0 100644 --- a/Makefile +++ b/Makefile @@ -103,9 +103,12 @@ index: cscope.files ctags --C-kinds=+pxzL -L $< cscope -b -q -i $< +.PHONY: clean-full +clean-full: clean + -rm -rdf userland/mlibc/ + .PHONY: clean clean: - $(MAKE) -C userland clean -rm -rd $(OBJ_DIR)/ tags cscope.* .PHONY: test-all diff --git a/drivers/ext2/ext2.c b/drivers/ext2/ext2.c index dd71869..aa29a77 100644 --- a/drivers/ext2/ext2.c +++ b/drivers/ext2/ext2.c @@ -638,6 +638,13 @@ static size_t ext2_write(struct file_handle_t* handle, void* buffer, size_t coun return 0; } +static enum file_status_t ext2_create(struct mount_cntx_t* cntx, char* path) { + (void)cntx; + (void)path; + + return FILE_NO_SUPPORT; +} + uint8_t ext2_attempt_init(struct disk_t* disk, uint64_t start_lba, uint64_t end_lba) { struct ext2_superblock_t* superblock = kmalloc(sizeof(struct ext2_superblock_t)); struct ext2_bg_desc_t* bgdt; @@ -693,7 +700,8 @@ uint8_t ext2_attempt_init(struct disk_t* disk, uint64_t start_lba, uint64_t end_ ext2_read, ext2_get_seek, ext2_seek, - ext2_write + ext2_write, + ext2_create ) != FILE_OK) { logging_log_error("Failed to mount rootfs"); panic(PANIC_STATE); diff --git a/kernel/core/fs.c b/kernel/core/fs.c index 975e0eb..0b5d7ae 100644 --- a/kernel/core/fs.c +++ b/kernel/core/fs.c @@ -31,8 +31,6 @@ #include -//TODO: implement per file blocking - static uint8_t fs_lock; struct vfs_mount_t { @@ -45,6 +43,7 @@ struct vfs_mount_t { fs_get_seek_t get_seek; fs_seek_t seek; fs_write_t write; + fs_create_t create; }; struct fs_handle_t { @@ -72,7 +71,8 @@ static struct vfs_mount_t dev_mount = { .read = devfs_read, .get_seek = devfs_get_seek, .seek = devfs_seek, - .write = devfs_write + .write = devfs_write, + .create = devfs_create }; static inline char* path_next(char* path, size_t* len) { @@ -113,7 +113,8 @@ enum file_status_t fs_mount( fs_read_t read, fs_get_seek_t get_seek, fs_seek_t seek, - fs_write_t write + fs_write_t write, + fs_create_t create ) { if (kstrcmp(mountpoint, "") && !vfs_root.mount) { @@ -132,6 +133,7 @@ enum file_status_t fs_mount( vfs_root.mount->get_seek = get_seek; vfs_root.mount->seek = seek; vfs_root.mount->write = write; + vfs_root.mount->create = create; return FILE_OK; } @@ -141,7 +143,7 @@ enum file_status_t fs_mount( return FILE_ERROR; } -struct fs_handle_t* fs_open(const char* path) { +static char* find_mount(const char* path, struct vfs_mount_t** mount_out, void** clean_path_out) { struct vfs_tree_node_t* node = &vfs_root, * walk = 0; size_t len = kstrlen(path); char* clean_path = kmalloc(len + 1); @@ -200,7 +202,7 @@ struct fs_handle_t* fs_open(const char* path) { } - //lock_acquire(&fs_lock); + lock_acquire(&fs_lock); do { if (node->mount) { @@ -220,14 +222,27 @@ struct fs_handle_t* fs_open(const char* path) { } while (walk && node == walk); - //lock_release(&fs_lock); + lock_release(&fs_lock); + + *mount_out = mount; + *clean_path_out = clean_path; + + return mount_path; +} + +struct fs_handle_t* fs_open(const char* path) { + struct vfs_mount_t* mount; + void* clean_path; + char* mount_path = find_mount(path, &mount, &clean_path); if (!mount) { kfree(clean_path); return 0; } + lock_acquire(&fs_lock); struct file_handle_t* handle = mount->open(mount->cntx, mount_path); + lock_release(&fs_lock); kfree(clean_path); @@ -238,28 +253,22 @@ struct fs_handle_t* fs_open(const char* path) { } void fs_close(struct fs_handle_t* handle) { - //lock_acquire(&fs_lock); handle->mount->close(handle->handle); - //lock_release(&fs_lock); kfree(handle); } enum file_status_t fs_stat(struct fs_handle_t* handle, struct file_info_t* info) { - //lock_acquire(&fs_lock); enum file_status_t ret = handle->mount->stat(handle->handle, info); - //lock_release(&fs_lock); return ret; } size_t fs_read(struct fs_handle_t* handle, void* buffer, size_t count) { size_t ret; - //lock_acquire(&fs_lock); ret = handle->mount->read(handle->handle, buffer, count); - //lock_release(&fs_lock); return ret; } @@ -267,9 +276,7 @@ size_t fs_read(struct fs_handle_t* handle, void* buffer, size_t count) { uint64_t fs_get_seek(struct fs_handle_t* handle) { uint64_t seek; - //lock_acquire(&fs_lock); seek = handle->mount->get_seek(handle->handle); - //lock_release(&fs_lock); return seek; } @@ -277,9 +284,7 @@ uint64_t fs_get_seek(struct fs_handle_t* handle) { enum file_status_t fs_seek(struct fs_handle_t* handle, uint64_t seek) { enum file_status_t sts; - //lock_acquire(&fs_lock); sts = handle->mount->seek(handle->handle, seek); - //lock_release(&fs_lock); return sts; } @@ -287,9 +292,28 @@ enum file_status_t fs_seek(struct fs_handle_t* handle, uint64_t seek) { size_t fs_write(struct fs_handle_t* handle, void* buffer, size_t count) { size_t ret; - //lock_acquire(&fs_lock); ret = handle->mount->write(handle->handle, buffer, count); - //lock_release(&fs_lock); return ret; } + +enum file_status_t fs_create(const char* path) { + enum file_status_t sts; + + struct vfs_mount_t* mount; + void* clean_path; + char* mount_path = find_mount(path, &mount, &clean_path); + + if (!mount) { + kfree(clean_path); + return FILE_DNE; + } + + lock_acquire(&fs_lock); + sts = mount->create(mount->cntx, mount_path); + lock_release(&fs_lock); + + kfree(clean_path); + + return sts; +} diff --git a/kernel/core/syscall.S b/kernel/core/syscall.S index d4738ff..93ebb9a 100644 --- a/kernel/core/syscall.S +++ b/kernel/core/syscall.S @@ -66,6 +66,7 @@ sysretq .extern syscall_dispatch_read .extern syscall_dispatch_write .extern syscall_dispatch_alloc +.extern syscall_dispatch_create .global syscall_handlers syscall_handlers: @@ -76,3 +77,4 @@ syscall_handlers: .quad syscall_dispatch_read .quad syscall_dispatch_write .quad syscall_dispatch_alloc +.quad syscall_dispatch_create diff --git a/kernel/core/syscall_dispatch.c b/kernel/core/syscall_dispatch.c index 1f6481c..9558924 100644 --- a/kernel/core/syscall_dispatch.c +++ b/kernel/core/syscall_dispatch.c @@ -150,3 +150,9 @@ DECLARE_SYSCALL(alloc) { return vaddr; } + +DECLARE_SYSCALL(create) { + ARGC_1; + + return fs_create((const char*)arg1) != FILE_OK; +} diff --git a/kernel/devfs/devfs.c b/kernel/devfs/devfs.c index e0c9103..67442df 100644 --- a/kernel/devfs/devfs.c +++ b/kernel/devfs/devfs.c @@ -142,3 +142,10 @@ size_t devfs_write(struct file_handle_t* handle, void* buffer, size_t count) { return count; } } + +enum file_status_t devfs_create(struct mount_cntx_t* cntx, char* path) { + (void)cntx; + (void)path; + + return FILE_NO_SUPPORT; +} diff --git a/kernel/include/core/fs.h b/kernel/include/core/fs.h index 8c2e754..9cc81a3 100644 --- a/kernel/include/core/fs.h +++ b/kernel/include/core/fs.h @@ -53,6 +53,8 @@ typedef uint64_t (*fs_get_seek_t)(struct file_handle_t*); typedef enum file_status_t (*fs_seek_t)(struct file_handle_t*, uint64_t); typedef size_t (*fs_write_t)(struct file_handle_t*, void*, size_t); +typedef enum file_status_t (*fs_create_t)(struct mount_cntx_t*, char*); + void fs_init(void); enum file_status_t fs_mount( @@ -64,7 +66,8 @@ enum file_status_t fs_mount( fs_read_t read, fs_get_seek_t get_seek, fs_seek_t seek, - fs_write_t write + fs_write_t write, + fs_create_t create ); extern struct fs_handle_t* fs_open(const char* path); @@ -76,4 +79,6 @@ extern uint64_t fs_get_seek(struct fs_handle_t* handle); extern enum file_status_t fs_seek(struct fs_handle_t* handle, uint64_t seek); extern size_t fs_write(struct fs_handle_t* handle, void* buffer, size_t count); +extern enum file_status_t fs_create(const char* path); + #endif /* KERNEL_CORE_FS_H */ diff --git a/kernel/include/core/syscall_dispatch.h b/kernel/include/core/syscall_dispatch.h index bd82d6f..443c77a 100644 --- a/kernel/include/core/syscall_dispatch.h +++ b/kernel/include/core/syscall_dispatch.h @@ -48,5 +48,6 @@ extern DECLARE_SYSCALL(close); extern DECLARE_SYSCALL(read); extern DECLARE_SYSCALL(write); extern DECLARE_SYSCALL(alloc); +extern DECLARE_SYSCALL(create); #endif /* KERNEL_CORE_SYSCALL_DISPATCH_H */ diff --git a/kernel/include/core/syscall_vectors.h b/kernel/include/core/syscall_vectors.h index 92d0a40..9912fa2 100644 --- a/kernel/include/core/syscall_vectors.h +++ b/kernel/include/core/syscall_vectors.h @@ -75,6 +75,12 @@ */ #define SYSCALL_ALLOC 5 -#define SYSCALL_MAX 6 +/* + * rdi: path (const char*) + * ret: (int) + */ +#define SYSCALL_CREATE 6 + +#define SYSCALL_MAX 7 diff --git a/kernel/include/devfs/devfs.h b/kernel/include/devfs/devfs.h index 4a2996d..4ae5019 100644 --- a/kernel/include/devfs/devfs.h +++ b/kernel/include/devfs/devfs.h @@ -31,5 +31,6 @@ extern size_t devfs_read(struct file_handle_t* handle, void* buffer, size_t coun extern uint64_t devfs_get_seek(struct file_handle_t* handle); extern enum file_status_t devfs_seek(struct file_handle_t* handle, uint64_t seek); extern size_t devfs_write(struct file_handle_t* handle, void* buffer, size_t count); +extern enum file_status_t devfs_create(struct mount_cntx_t* cntx, char* path); #endif /* KERNEL_DEVFS_DEVFS_H */ diff --git a/userland/Makefile b/userland/Makefile index e9fb829..78e38c2 100644 --- a/userland/Makefile +++ b/userland/Makefile @@ -35,17 +35,13 @@ all: build .PHONY: build build: libc $(OBJ_DIR)/../userland_files/bin/shell -.PHONY: clean -clean: - -rm -rdf $(OBJ_DIR)/mlibc-meson-setup mlibc/ +mlibc/: + git clone https://github.com/managarm/mlibc.git $@ + git -C $@ checkout v6.3.1 + git -C $@ apply ../mlibc-patch/mlibc-v6-3-1-port.patch + cp -r mlibc-patch/* $@ - -$(OBJ_DIR)/mlibc-meson-setup: | $(OBJ_DIR)/libc-build/ $(OBJ_DIR)/../userland_files/usr/ - -rm -rdf mlibc/ - git clone https://github.com/managarm/mlibc.git mlibc - git -C mlibc/ checkout v6.3.1 - git -C mlibc/ apply ../mlibc-patch/mlibc-v6-3-1-port.patch - cp -r mlibc-patch/* mlibc/ +$(OBJ_DIR)/mlibc-meson-setup: | mlibc/ $(OBJ_DIR)/libc-build/ $(OBJ_DIR)/../userland_files/usr/ meson setup \ --native-file mlibc/ci/linux-x86_64-clang.cross-file \ --cross-file mlibc/ci/modulos.cross-file \ From 6865a628d8308b6ae2d7ae179be7ae34ae292705 Mon Sep 17 00:00:00 2001 From: Ebrahim Aleem Date: Tue, 28 Apr 2026 12:12:22 -0700 Subject: [PATCH 02/13] reduced ahci busy wait periods --- drivers/ahci/ahci.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/drivers/ahci/ahci.c b/drivers/ahci/ahci.c index 12b7880..e53286c 100644 --- a/drivers/ahci/ahci.c +++ b/drivers/ahci/ahci.c @@ -255,13 +255,13 @@ static enum disk_error_t ahci_read_lba(void* cntx, void* buffer, uint64_t lba, u while (hba_read(ahci, PXTFD_OFF(port)) & TFD_STS_CON_MASK) { - time_busy_wait(10 * TIME_CONV_MS_TO_NS); + time_busy_wait(100); } hba_write(ahci, PXCI_OFF(port), 1u << slot); while (hba_read(ahci, PXCI_OFF(port)) & (1u << slot)) { - time_busy_wait(10 * TIME_CONV_MS_TO_NS); + time_busy_wait(100); if (hba_read(ahci, PXIS_OFF(port)) & IS_TFES) { logging_log_error("AHCI error while reading"); @@ -381,13 +381,13 @@ static enum disk_error_t ahci_write_lba(void* cntx, void* buffer, uint64_t lba, while (hba_read(ahci, PXTFD_OFF(port)) & TFD_STS_CON_MASK) { - time_busy_wait(10 * TIME_CONV_MS_TO_NS); + time_busy_wait(100); } hba_write(ahci, PXCI_OFF(port), 1u << slot); while (hba_read(ahci, PXCI_OFF(port)) & (1u << slot)) { - time_busy_wait(10 * TIME_CONV_MS_TO_NS); + time_busy_wait(100); if (hba_read(ahci, PXIS_OFF(port)) & IS_TFES) { logging_log_error("AHCI error while reading"); @@ -462,13 +462,13 @@ static enum disk_error_t ahci_flush_cache(void* cntx) { ahci->ports[port]->com_list[slot].ctba_u0 = 0; while (hba_read(ahci, PXTFD_OFF(port)) & TFD_STS_CON_MASK) { - time_busy_wait(10 * TIME_CONV_MS_TO_NS); + time_busy_wait(100); } hba_write(ahci, PXCI_OFF(port), 1u << slot); while (hba_read(ahci, PXCI_OFF(port)) & (1u << slot)) { - time_busy_wait(10 * TIME_CONV_MS_TO_NS); + time_busy_wait(100); if (hba_read(ahci, PXIS_OFF(port)) & IS_TFES) { logging_log_error("AHCI flush cache error"); @@ -542,13 +542,13 @@ static void port_identify(struct ahci_t* ahci, uint32_t port) { ahci->ports[port]->com_list[slot].ctba_u0 = 0; while (hba_read(ahci, PXTFD_OFF(port)) & TFD_STS_CON_MASK) { - time_busy_wait(10 * TIME_CONV_MS_TO_NS); + time_busy_wait(100); } hba_write(ahci, PXCI_OFF(port), 1u << slot); while (hba_read(ahci, PXCI_OFF(port)) & (1u << slot)) { - time_busy_wait(10 * TIME_CONV_MS_TO_NS); + time_busy_wait(100); } lock_release(&ahci->ports[port]->lock); From cffff272ec82543eb0bddbce14a9f1eb6f73db54 Mon Sep 17 00:00:00 2001 From: Ebrahim Aleem Date: Tue, 28 Apr 2026 12:31:04 -0700 Subject: [PATCH 03/13] optimized kmemcpy and kmemset --- kernel/lib/kmemcpy.c | 25 ++++++++++++++++++------- kernel/lib/kmemset.c | 20 +++++++++++++++++--- 2 files changed, 35 insertions(+), 10 deletions(-) diff --git a/kernel/lib/kmemcpy.c b/kernel/lib/kmemcpy.c index 8c65b43..79efcfd 100644 --- a/kernel/lib/kmemcpy.c +++ b/kernel/lib/kmemcpy.c @@ -23,13 +23,24 @@ void* memcpy(void* dest, const void* src, size_t c) __attribute__((weak)); void* memcpy(void* dest, const void* src, size_t c) { - const uint8_t* p1 = src; - uint8_t* p2 = dest; - - for (size_t i = 0; i < c; i++) { - *p2 = *p1; - p1++; - p2++; + const uint64_t* src64 = (const uint64_t*)src; + uint64_t* dest64 = (uint64_t*)dest; + + while (c >= sizeof(uint64_t)) { + *dest64 = *src64; + dest64++; + src64++; + c -= sizeof(uint64_t); + } + + const uint8_t* src8 = (const uint8_t*)src64; + uint8_t* dest8 = (uint8_t*)dest64; + + while (c >= sizeof(uint8_t)) { + *dest8 = *src8; + dest8++; + src8++; + c -= sizeof(uint8_t); } return dest; diff --git a/kernel/lib/kmemset.c b/kernel/lib/kmemset.c index c3c6cbb..2297b5f 100644 --- a/kernel/lib/kmemset.c +++ b/kernel/lib/kmemset.c @@ -20,13 +20,27 @@ #include +#define PAT(s) (((uint64_t)v8) << (8*s)) + void* memset(void* ptr, int32_t v, size_t c) __attribute__((weak)); void* memset(void* ptr, int32_t v, size_t c) { - uint8_t* p = ptr; + uint8_t v8 = (uint8_t)v; + uint64_t v64 = PAT(0) | PAT(1) | PAT(2) | PAT(3) | PAT(4) | PAT(5) | PAT(6) | PAT(7); + uint64_t* ptr64 = (uint64_t*)ptr; + + while (c >= sizeof(uint64_t)) { + *ptr64 = v64; + ptr64++; + c -= sizeof(uint64_t); + } + + uint8_t* ptr8 = (uint8_t*)ptr64; - for (size_t i = 0; i < c; i++) { - p[i] = (uint8_t)v; + while (c >= sizeof(uint8_t)) { + *ptr8 = v8; + ptr8++; + c -= sizeof(uint8_t); } return ptr; From d9609654504dd53be800d42a7389a4776e3edc95 Mon Sep 17 00:00:00 2001 From: Ebrahim Aleem Date: Tue, 28 Apr 2026 14:03:57 -0700 Subject: [PATCH 04/13] seperate process for starting userland shell --- drivers/ext2/ext2.c | 35 ++--------------------------------- kernel/core/kentry.c | 36 ++++++++++++++++++++++++++++++++++++ kernel/include/core/kentry.h | 2 ++ 3 files changed, 40 insertions(+), 33 deletions(-) diff --git a/drivers/ext2/ext2.c b/drivers/ext2/ext2.c index aa29a77..78c57ae 100644 --- a/drivers/ext2/ext2.c +++ b/drivers/ext2/ext2.c @@ -27,8 +27,8 @@ #include #include #include -#include #include +#include #include #include @@ -707,38 +707,7 @@ uint8_t ext2_attempt_init(struct disk_t* disk, uint64_t start_lba, uint64_t end_ panic(PANIC_STATE); } - struct file_info_t stat_buf; - enum file_status_t sts; - - struct fs_handle_t* root_handle = fs_open("/"); - if (!root_handle) { - logging_log_error("Failed to open root directory"); - } - else { - if ((sts = fs_stat(root_handle, &stat_buf)) != FILE_OK) { - logging_log_error("Failed to stat root directory %u", (uint32_t)sts); - } - else { - logging_log_debug("Root directory %u (%u)", stat_buf.size, stat_buf.type); - } - - fs_close(root_handle); - } - - - struct fs_handle_t* shell = fs_open("/bin/shell"); - if (!shell) { - logging_log_error("Failed to open shell file"); - } - else { - struct pcb_t* shell_pcb = elf_load(shell, process_assign_pid(), "/bin/shell ModulOS", "USER=root PWD=/"); - if (!shell_pcb) { - logging_log_error("Failed to load shell file"); - } - fs_close(shell); - - scheduler_schedule(shell_pcb); - } + scheduler_schedule(process_from_func(prepare_userland, 0)); } //TODO: mount other volumes diff --git a/kernel/core/kentry.c b/kernel/core/kentry.c index 2a567bf..5f74eaa 100644 --- a/kernel/core/kentry.c +++ b/kernel/core/kentry.c @@ -35,6 +35,9 @@ #include #include #include +#include +#include +#include #include @@ -73,6 +76,9 @@ extern uint64_t init_stack_paddr; extern uint64_t* init_stacks_paddr; extern uint64_t* init_stacks_vaddr; +static uint8_t prepare_userland_lock; +static uint8_t init_done; + static inline void write_syscall_msr(void) { msr_write(MSR_STAR, ((GDT_USER_CS - 0x10) << 48) | (GDT_KERNEL_CS << 32)); msr_write(MSR_LSTAR, (uint64_t)syscall_entry); @@ -96,6 +102,8 @@ void kentry(void) { scheduler_init(); mm_transaction_init(); + init_done = 0; + lock_init(&prepare_userland_lock); write_syscall_msr(); cpu_set_cr4(CR4_FSGSBASE); @@ -182,3 +190,31 @@ void kapentry(uint64_t arb_id) { process_kill_current(); } + +void prepare_userland(void* cntx) { + (void)cntx; + + lock_acquire(&prepare_userland_lock); + if (init_done) { + logging_log_error("Multiple calls to prepare userland"); + panic(PANIC_STATE); + } + + init_done = 1; + lock_release(&prepare_userland_lock); + + struct fs_handle_t* shell = fs_open("/bin/shell"); + if (!shell) { + logging_log_error("Failed to open shell file"); + } + + else { + struct pcb_t* shell_pcb = elf_load(shell, process_assign_pid(), "/bin/shell ModulOS", "USER=root PWD=/"); + if (!shell_pcb) { + logging_log_error("Failed to load shell file"); + } + fs_close(shell); + + scheduler_schedule(shell_pcb); + } +} diff --git a/kernel/include/core/kentry.h b/kernel/include/core/kentry.h index cd53561..f0d16d9 100644 --- a/kernel/include/core/kentry.h +++ b/kernel/include/core/kentry.h @@ -43,4 +43,6 @@ extern void kentry(void) __attribute__((noreturn)); extern void kapentry(uint64_t arb_id) __attribute__((noreturn)); +extern void prepare_userland(void* cntx); + #endif /* KERNEL_CORE_KENTRY_H */ From a454209705a129fa9b2db6220f7019c04654dd64 Mon Sep 17 00:00:00 2001 From: Ebrahim Aleem Date: Tue, 28 Apr 2026 17:36:46 -0700 Subject: [PATCH 05/13] per file locks at vfs layer --- kernel/core/fs.c | 118 ++++++++++++++++-- kernel/core/mm.c | 2 - kernel/include/lib/hash.h | 2 + .../include/lib/{mergesort.h => hash_table.h} | 24 +++- kernel/lib/hash.c | 26 +++- kernel/lib/hash_table.c | 113 +++++++++++++++++ kernel/lib/mergesort.c | 72 ----------- test/include/macros.h | 2 +- test/lib/test.c | 6 + 9 files changed, 274 insertions(+), 91 deletions(-) rename kernel/include/lib/{mergesort.h => hash_table.h} (54%) create mode 100644 kernel/lib/hash_table.c delete mode 100644 kernel/lib/mergesort.c diff --git a/kernel/core/fs.c b/kernel/core/fs.c index 0b5d7ae..bfa9ab9 100644 --- a/kernel/core/fs.c +++ b/kernel/core/fs.c @@ -28,9 +28,31 @@ #include #include #include +#include +#include #include +#define OPEN_TABLE_BUCKETS 100 + +/* + * Locking conventions: + * + * The vfs layer guarantees non concurrent access to the same file, up to absolute paths. + * The vfs layer does not guarnatee non concurrent access to directory creation, file creation, + * multiple references to the same file via hard links, or atomic operations for multiple step + * calls (e.g. directory listing). + * + * In other words, the vfs is only responsible for ensuring that no two access are made to the + * inode at the same time. It is the actual fs driver's responsibility to ensure consistent access + * to filesystem metadata such as inode tables and journals + * + * Internally, the vfs must guarantee locked access to the open_table via the fs_lock. The vfs must + * also guarantee locked access to the vfs tree. + * + * TODO: support multiple readers on the filetree while blocking writers + */ + static uint8_t fs_lock; struct vfs_mount_t { @@ -46,9 +68,17 @@ struct vfs_mount_t { fs_create_t create; }; +struct vfs_open_file_t { + uint8_t lock; + const char* path; + uint64_t refs; + uint64_t key; +}; + struct fs_handle_t { struct vfs_mount_t* mount; struct file_handle_t* handle; + struct vfs_open_file_t* shared; }; struct vfs_tree_node_t { @@ -63,6 +93,8 @@ struct vfs_tree_node_t { static struct vfs_tree_node_t vfs_root; static struct vfs_tree_node_t dev_root; +static struct hash_table_t* open_table; + static struct vfs_mount_t dev_mount = { .cntx = 0, .open = devfs_open, @@ -90,6 +122,49 @@ static inline char* path_next(char* path, size_t* len) { return path; } +static struct vfs_open_file_t* lookup_register(char* path) { + uint64_t key = fnv64_1a(path, kstrlen(path)); + struct vfs_open_file_t* file; + + while ((file = hash_table_get(open_table, key))) { + if (kstrcmp(path, file->path) == 0) { + break; + } + + key++; + } + + if (!file) { + file = kmalloc(sizeof(struct vfs_open_file_t)); + + file->path = kmalloc(kstrlen(path) + 1); + kstrcpy((char*)file->path, path); + + file->refs = 0; + file->key = key; + lock_init(&file->lock); + + hash_table_insert(open_table, key, file); + } + + file->refs++; + + return file; +} + +static void lookup_close(struct vfs_open_file_t* file) { + file->refs--; + + if (file->refs) { + return; + } + + kfree((char*)file->path); + hash_table_remove(open_table, file->key); + + kfree(file); +} + void fs_init(void) { lock_init(&fs_lock); @@ -102,6 +177,8 @@ void fs_init(void) { dev_root.sub = 0; dev_root.name = "dev"; dev_root.mount = &dev_mount; + + open_table = hash_table_alloc(OPEN_TABLE_BUCKETS); } enum file_status_t fs_mount( @@ -143,13 +220,13 @@ enum file_status_t fs_mount( return FILE_ERROR; } -static char* find_mount(const char* path, struct vfs_mount_t** mount_out, void** clean_path_out) { +static char* find_mount(const char* path, struct vfs_mount_t** mount_out, void** clean_path_out, char** path_write_out) { struct vfs_tree_node_t* node = &vfs_root, * walk = 0; - size_t len = kstrlen(path); - char* clean_path = kmalloc(len + 1); char* mount_path = (char*)""; struct vfs_mount_t* mount = 0; + size_t len = kstrlen(path); + char* clean_path = kmalloc(len + 1); uint64_t num_chars = 0; uint64_t skip = 0; @@ -201,6 +278,7 @@ static char* find_mount(const char* path, struct vfs_mount_t** mount_out, void** path_write++; // one to skip / } + *path_write_out = path_write; lock_acquire(&fs_lock); @@ -233,7 +311,8 @@ static char* find_mount(const char* path, struct vfs_mount_t** mount_out, void** struct fs_handle_t* fs_open(const char* path) { struct vfs_mount_t* mount; void* clean_path; - char* mount_path = find_mount(path, &mount, &clean_path); + char* path_write; + char* mount_path = find_mount(path, &mount, &clean_path, &path_write); if (!mount) { kfree(clean_path); @@ -244,31 +323,51 @@ struct fs_handle_t* fs_open(const char* path) { struct file_handle_t* handle = mount->open(mount->cntx, mount_path); lock_release(&fs_lock); + if (!handle) { + return 0; + } + + lock_acquire(&fs_lock); + struct vfs_open_file_t* open_file = lookup_register(path_write); + lock_release(&fs_lock); + kfree(clean_path); struct fs_handle_t* fs_handle = kmalloc(sizeof(struct fs_handle_t)); fs_handle->handle = handle; fs_handle->mount = mount; + fs_handle->shared = open_file; return fs_handle; } void fs_close(struct fs_handle_t* handle) { + lock_acquire(&handle->shared->lock); handle->mount->close(handle->handle); + lock_release(&handle->shared->lock); + + lock_acquire(&fs_lock); + lookup_close(handle->shared); + lock_release(&fs_lock); kfree(handle); } enum file_status_t fs_stat(struct fs_handle_t* handle, struct file_info_t* info) { + lock_acquire(&handle->shared->lock); enum file_status_t ret = handle->mount->stat(handle->handle, info); + lock_release(&handle->shared->lock); + return ret; } size_t fs_read(struct fs_handle_t* handle, void* buffer, size_t count) { size_t ret; + lock_acquire(&handle->shared->lock); ret = handle->mount->read(handle->handle, buffer, count); + lock_release(&handle->shared->lock); return ret; } @@ -276,7 +375,9 @@ size_t fs_read(struct fs_handle_t* handle, void* buffer, size_t count) { uint64_t fs_get_seek(struct fs_handle_t* handle) { uint64_t seek; + lock_acquire(&handle->shared->lock); seek = handle->mount->get_seek(handle->handle); + lock_release(&handle->shared->lock); return seek; } @@ -284,7 +385,9 @@ uint64_t fs_get_seek(struct fs_handle_t* handle) { enum file_status_t fs_seek(struct fs_handle_t* handle, uint64_t seek) { enum file_status_t sts; + lock_release(&handle->shared->lock); sts = handle->mount->seek(handle->handle, seek); + lock_release(&handle->shared->lock); return sts; } @@ -292,7 +395,9 @@ enum file_status_t fs_seek(struct fs_handle_t* handle, uint64_t seek) { size_t fs_write(struct fs_handle_t* handle, void* buffer, size_t count) { size_t ret; + lock_release(&handle->shared->lock); ret = handle->mount->write(handle->handle, buffer, count); + lock_release(&handle->shared->lock); return ret; } @@ -302,16 +407,15 @@ enum file_status_t fs_create(const char* path) { struct vfs_mount_t* mount; void* clean_path; - char* mount_path = find_mount(path, &mount, &clean_path); + char* path_write; + char* mount_path = find_mount(path, &mount, &clean_path, &path_write); if (!mount) { kfree(clean_path); return FILE_DNE; } - lock_acquire(&fs_lock); sts = mount->create(mount->cntx, mount_path); - lock_release(&fs_lock); kfree(clean_path); diff --git a/kernel/core/mm.c b/kernel/core/mm.c index 6f7a6ba..8ccdd63 100644 --- a/kernel/core/mm.c +++ b/kernel/core/mm.c @@ -30,8 +30,6 @@ #include #include -#include - #include #define PAGE_4K_MASK 0xFFFFFFFFFFFFF000 diff --git a/kernel/include/lib/hash.h b/kernel/include/lib/hash.h index 763a90d..6e28cbc 100644 --- a/kernel/include/lib/hash.h +++ b/kernel/include/lib/hash.h @@ -25,4 +25,6 @@ extern uint8_t hash_byte_sum(const void* ptr, size_t c); extern uint32_t crc32_ansi(const void* data, size_t length); +extern uint64_t fnv64_1a(const void* data, size_t length); + #endif /* KERNEL_LIB_HASH_H */ diff --git a/kernel/include/lib/mergesort.h b/kernel/include/lib/hash_table.h similarity index 54% rename from kernel/include/lib/mergesort.h rename to kernel/include/lib/hash_table.h index 0877ffd..f30ef36 100644 --- a/kernel/include/lib/mergesort.h +++ b/kernel/include/lib/hash_table.h @@ -1,5 +1,5 @@ -/* mergesort.h - mergesort interface */ -/* Copyright (C) 2025-2026 Ebrahim Aleem +/* hash_table.h - hash table interface */ +/* Copyright (C) 2026 Ebrahim Aleem * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -15,9 +15,21 @@ * along with this program. If not, see */ -#ifndef KERNEL_LIB_MERGESORT_H -#define KERNEL_LIB_MERGESORT_H +#ifndef KERNEL_LIB_HASH_TABLE_H +#define KERNEL_LIB_HASH_TABLE_H -extern void* mergesort_ll_inplace_ul(void* ll, void** (*next)(void*), unsigned long (*value)(void*)); +#include +#include + +struct hash_table_t; + +extern struct hash_table_t* hash_table_alloc(size_t buckets); + +extern void* hash_table_insert(struct hash_table_t* table, uint64_t key, void* value); + +extern void* hash_table_get(struct hash_table_t* table, uint64_t key); + +extern void* hash_table_remove(struct hash_table_t* table, uint64_t key); + +#endif /* KERNEL_LIB_HASH_TABLE_H */ -#endif /* KERNEL_LIB_MERGESORT_H */ diff --git a/kernel/lib/hash.c b/kernel/lib/hash.c index 501dcf0..0863e96 100644 --- a/kernel/lib/hash.c +++ b/kernel/lib/hash.c @@ -20,6 +20,13 @@ #include +#define CRC32_ANSI_C0 0xFFFFFFFF +#define CRC32_ANSI_C1 0xEDB88320; + + +#define FNV64_1A_C0 0xcbf29ce484222325 +#define FNV64_1A_C1 0x100000001b3 + uint8_t hash_byte_sum(const void* ptr, size_t c) { const uint8_t* _ptr = ptr; uint8_t sum = 0; @@ -31,7 +38,7 @@ uint8_t hash_byte_sum(const void* ptr, size_t c) { } uint32_t crc32_ansi(const void* data, size_t length) { - uint32_t crc = 0xFFFFFFFF; + uint32_t crc = CRC32_ANSI_C0; const uint8_t *p = (const uint8_t*)data; uint8_t i; @@ -40,7 +47,7 @@ uint32_t crc32_ansi(const void* data, size_t length) { for (i = 0; i < 8; i++) { if (crc & 1) { - crc = (crc >> 1) ^ 0xEDB88320; + crc = (crc >> 1) ^ CRC32_ANSI_C1; } else { crc >>= 1; @@ -48,5 +55,18 @@ uint32_t crc32_ansi(const void* data, size_t length) { } } - return crc ^ 0xFFFFFFFF; + return crc ^ CRC32_ANSI_C0; +} + +uint64_t fnv64_1a(const void* data, size_t length) { + const uint8_t* bytes = data; + uint64_t fnv64 = FNV64_1A_C0; + + for (size_t i = 0; i < length; i++) { + fnv64 ^= *bytes; + fnv64 *= FNV64_1A_C1; + bytes++; + } + + return fnv64; } diff --git a/kernel/lib/hash_table.c b/kernel/lib/hash_table.c new file mode 100644 index 0000000..0885bc5 --- /dev/null +++ b/kernel/lib/hash_table.c @@ -0,0 +1,113 @@ +/* hash_table.c - hash table implementation */ +/* Copyright (C) 2026 Ebrahim Aleem +* +* This program is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see +*/ + +#include +#include + +#include + +#include + +struct node_t { + uint64_t key; + void* value; + struct node_t* next; +}; + +struct hash_table_t { + size_t num_buckets; + struct node_t* buckets[]; +}; + +static inline uint64_t bucket_index(struct hash_table_t* table, uint64_t key) { + return key % table->num_buckets; +} + +static struct node_t** find_node(struct node_t** bucket, uint64_t key) { + for (; *bucket; bucket = &(*bucket)->next) { + if ((*bucket)->key == key) { + break; + } + } + + return bucket; +} + +struct hash_table_t* hash_table_alloc(size_t buckets) { + struct hash_table_t* table = kmalloc(sizeof(struct hash_table_t) + buckets * sizeof(struct node_t*)); + + if (!table) { + return 0; + } + + table->num_buckets = buckets; + + for (size_t i = 0; i < buckets; i++) { + table->buckets[i] = 0; + } + + return table; +} + +void* hash_table_insert(struct hash_table_t* table, uint64_t key, void* value) { + uint64_t index = bucket_index(table, key); + + struct node_t* node = *find_node(&table->buckets[index], key); + + if (!node) { + node = kmalloc(sizeof(struct node_t)); + node->next = table->buckets[index]; + node->key = key; + node->value = 0; + table->buckets[index] = node; + } + + void* old = node->value; + node->value = value; + + return old; +} + +void* hash_table_get(struct hash_table_t* table, uint64_t key) { + uint64_t index = bucket_index(table, key); + + struct node_t* node = *find_node(&table->buckets[index], key); + + if (!node) { + return 0; + } + + return node->value; +} + +void* hash_table_remove(struct hash_table_t* table, uint64_t key) { + uint64_t index = bucket_index(table, key); + + struct node_t** node = find_node(&table->buckets[index], key); + + if (!*node) { + return 0; + } + + void* old = (*node)->value; + struct node_t* to_free = *node; + *node = (*node)->next; + + kfree(to_free); + + return old; +} diff --git a/kernel/lib/mergesort.c b/kernel/lib/mergesort.c deleted file mode 100644 index b46aaf9..0000000 --- a/kernel/lib/mergesort.c +++ /dev/null @@ -1,72 +0,0 @@ -/* mergesort.h - mergesort implementation */ -/* Copyright (C) 2025-2026 Ebrahim Aleem -* -* This program is free software: you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published by -* the Free Software Foundation, either version 3 of the License, or -* (at your option) any later version. -* -* This program is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU General Public License for more details. -* -* You should have received a copy of the GNU General Public License -* along with this program. If not, see -*/ - -#include - -void* mergesort_ll_inplace_ul(void* ll, void** (*next)(void*), unsigned long (*value)(void*)) { - if (!ll || !*next(ll)) { - return ll; - } - - void *mid, *right, *left; - void *fast; - void *head, *tail; - - // find mid - mid = ll; - fast = *next(ll); - - while (fast && *next(fast)) { - mid = *next(mid); - fast = *next(*next(fast)); - } - - right = *next(mid); - *next(mid) = 0; - - left = mergesort_ll_inplace_ul(ll, next, value); - right = mergesort_ll_inplace_ul(right, next, value); - - // merge - if (!left) return right; - if (!right) return left; - - if (value(left) <= value(right)) { - head = left; - left = *next(left); - } else { - head = right; - right = *next(right); - } - - tail = head; - - while (left && right) { - if (value(left) <= value(right)) { - *next(tail) = left; - left = *next(left); - } else { - *next(tail) = right; - right = *next(right); - } - tail = *next(tail); - } - - *next(tail) = left ? left : right; - - return head; -} diff --git a/test/include/macros.h b/test/include/macros.h index 5d4c0b1..4b1709a 100644 --- a/test/include/macros.h +++ b/test/include/macros.h @@ -60,7 +60,7 @@ extern void _test_report(const char* report); static void _test_##id(void) #define TEST_PASS() exit(EXIT_SUCCESS) -#define TEST_FAIL(code) exit(EXIT_FAILURE) +#define TEST_FAIL() exit(EXIT_FAILURE) #define ASSERT_TRUE(condition, report) \ if (!(condition)) { \ diff --git a/test/lib/test.c b/test/lib/test.c index 983890a..f13973d 100644 --- a/test/lib/test.c +++ b/test/lib/test.c @@ -29,6 +29,7 @@ #include #include #include +#include #define MEM_TEST_SIZE 256 @@ -127,3 +128,8 @@ TEST("crc32_ansi") { ASSERT_TRUE(crc32_ansi("Hello, World!", 13) == 0xec4ac3d0, "fails expected checksum"); ASSERT_FALSE(crc32_ansi("Hello, World!", 12) == 0xec4ac3d0, "fails unexpected checksum"); } + +TEST("fnc64_1a") { + //TODO + TEST_FAIL(); +} From 05838f2c86db2ef45a17b62e29ed263c4d3f78e1 Mon Sep 17 00:00:00 2001 From: Ebrahim Aleem Date: Tue, 28 Apr 2026 18:08:01 -0700 Subject: [PATCH 06/13] non blocking vfs mount tree parse via semaphores --- kernel/core/fs.c | 21 ++++----- kernel/core/kentry.c | 2 +- kernel/core/semaphore.c | 75 +++++++++++++++++++++++++++++++++ kernel/include/core/lock.h | 6 +-- kernel/include/core/semaphore.h | 38 +++++++++++++++++ 5 files changed, 126 insertions(+), 16 deletions(-) create mode 100644 kernel/core/semaphore.c create mode 100644 kernel/include/core/semaphore.h diff --git a/kernel/core/fs.c b/kernel/core/fs.c index bfa9ab9..ca0166b 100644 --- a/kernel/core/fs.c +++ b/kernel/core/fs.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #include @@ -49,11 +50,9 @@ * * Internally, the vfs must guarantee locked access to the open_table via the fs_lock. The vfs must * also guarantee locked access to the vfs tree. - * - * TODO: support multiple readers on the filetree while blocking writers */ -static uint8_t fs_lock; +static struct semaphore_t* fs_sem; struct vfs_mount_t { struct mount_cntx_t* cntx; @@ -166,7 +165,7 @@ static void lookup_close(struct vfs_open_file_t* file) { } void fs_init(void) { - lock_init(&fs_lock); + fs_sem = semaphore_alloc(SEMAPHORE_CAP_UNLIM); vfs_root.co = 0; vfs_root.sub = &dev_root; @@ -280,7 +279,7 @@ static char* find_mount(const char* path, struct vfs_mount_t** mount_out, void** *path_write_out = path_write; - lock_acquire(&fs_lock); + semaphore_wait(fs_sem); do { if (node->mount) { @@ -300,7 +299,7 @@ static char* find_mount(const char* path, struct vfs_mount_t** mount_out, void** } while (walk && node == walk); - lock_release(&fs_lock); + semaphore_signal(fs_sem); *mount_out = mount; *clean_path_out = clean_path; @@ -319,17 +318,15 @@ struct fs_handle_t* fs_open(const char* path) { return 0; } - lock_acquire(&fs_lock); struct file_handle_t* handle = mount->open(mount->cntx, mount_path); - lock_release(&fs_lock); if (!handle) { return 0; } - lock_acquire(&fs_lock); + semaphore_wait(fs_sem); struct vfs_open_file_t* open_file = lookup_register(path_write); - lock_release(&fs_lock); + semaphore_signal(fs_sem); kfree(clean_path); @@ -346,9 +343,9 @@ void fs_close(struct fs_handle_t* handle) { handle->mount->close(handle->handle); lock_release(&handle->shared->lock); - lock_acquire(&fs_lock); + semaphore_wait_full(fs_sem); lookup_close(handle->shared); - lock_release(&fs_lock); + semaphore_signal_full(fs_sem); kfree(handle); } diff --git a/kernel/core/kentry.c b/kernel/core/kentry.c index 5f74eaa..a98aef4 100644 --- a/kernel/core/kentry.c +++ b/kernel/core/kentry.c @@ -101,7 +101,6 @@ void kentry(void) { paging_ensure_mapped(); scheduler_init(); - mm_transaction_init(); init_done = 0; lock_init(&prepare_userland_lock); @@ -136,6 +135,7 @@ void kentry(void) { logging_log_debug("Early PCIE init"); disk_init(); fs_init(); + mm_transaction_init(); tty_init(); pcie_init(); pcie_enumerate(); diff --git a/kernel/core/semaphore.c b/kernel/core/semaphore.c new file mode 100644 index 0000000..1b069fc --- /dev/null +++ b/kernel/core/semaphore.c @@ -0,0 +1,75 @@ +/* semaphore.c - semaphore implementation */ +/* Copyright (C) 2026 Ebrahim Aleem +* +* This program is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see +*/ + +#include +#include + +#include +#include +#include +#include + +struct semaphore_t { + size_t rem; + size_t cap; + uint8_t lock; +}; + +struct semaphore_t* semaphore_alloc(size_t cap) { + struct semaphore_t* sem = kmalloc(sizeof(struct semaphore_t)); + + sem->rem = sem->cap = cap; + lock_init(&sem->lock); + + return sem; +} + +void semaphore_free(struct semaphore_t* sem) { + kfree(sem); +} + +void semaphore_wait(struct semaphore_t* sem) { + lock_acquire(&sem->lock); + + while (!sem->rem) { + cpu_pause(); + } + + sem->rem--; + + lock_release(&sem->lock); +} + +void semaphore_signal(struct semaphore_t* sem) { + sem->rem++; +} + +void semaphore_wait_full(struct semaphore_t* sem) { + lock_acquire(&sem->lock); + + while (sem->rem != sem->cap) { + cpu_pause(); + } + + sem->rem = 0; + + lock_release(&sem->lock); +} + +void semaphore_signal_full(struct semaphore_t* sem) { + sem->rem = sem->cap; +} diff --git a/kernel/include/core/lock.h b/kernel/include/core/lock.h index 0ba48ef..cc2c79d 100644 --- a/kernel/include/core/lock.h +++ b/kernel/include/core/lock.h @@ -17,11 +17,11 @@ #include -#ifndef KERNEL_INCLUDE_CORE_LOCK_H -#define KERNEL_INCLUDE_CORE_LOCK_H +#ifndef KERNEL_CORE_LOCK_H +#define KERNEL_CORE_LOCK_H extern void lock_init(uint8_t* lock); extern void lock_acquire(uint8_t* lock); extern void lock_release(uint8_t* lock); -#endif /* KERNEL_INCLUDE_CORE_LOCK_H */ +#endif /* KERNEL_CORE_LOCK_H */ diff --git a/kernel/include/core/semaphore.h b/kernel/include/core/semaphore.h new file mode 100644 index 0000000..6c670c8 --- /dev/null +++ b/kernel/include/core/semaphore.h @@ -0,0 +1,38 @@ +/* semaphore.h - semaphore interface */ +/* Copyright (C) 2026 Ebrahim Aleem +* +* This program is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see +*/ + +#ifndef KERNEL_CORE_SEMAPHORE_H +#define KERNEL_CORE_SEMAPHORE_H + +#include +#include + +#define SEMAPHORE_CAP_UNLIM (uint64_t)(-1) + +struct semaphore_t; + +extern struct semaphore_t* semaphore_alloc(size_t cap); +extern void semaphore_free(struct semaphore_t* sem); + +extern void semaphore_wait(struct semaphore_t* sem); +extern void semaphore_signal(struct semaphore_t* sem); + +extern void semaphore_wait_full(struct semaphore_t* sem); +extern void semaphore_signal_full(struct semaphore_t* sem); + +#endif /* KERNEL_CORE_SEMAPHORE_H */ + From bb101440954866e0b2086fc797ee8beb7f5cc824 Mon Sep 17 00:00:00 2001 From: Ebrahim Aleem Date: Tue, 5 May 2026 12:23:49 -0700 Subject: [PATCH 07/13] more stubs for file related syscalls --- drivers/ext2/ext2.c | 87 ++++++++-- kernel/core/exception_dispatch.c | 1 - kernel/core/fs.c | 122 ++++++++++++--- kernel/core/syscall.S | 22 ++- kernel/core/syscall_dispatch.c | 148 +++++++++++++++++- kernel/devfs/devfs.c | 42 ++++- kernel/include/core/fs.h | 34 +++- kernel/include/core/syscall_dispatch.h | 9 ++ kernel/include/core/syscall_vectors.h | 63 +++++++- kernel/include/devfs/devfs.h | 14 +- test/lib/test.c | 4 +- .../mlibc-patch/sysdeps/modulos/sysdeps.cpp | 63 +++++--- 12 files changed, 525 insertions(+), 84 deletions(-) diff --git a/drivers/ext2/ext2.c b/drivers/ext2/ext2.c index 78c57ae..17294c8 100644 --- a/drivers/ext2/ext2.c +++ b/drivers/ext2/ext2.c @@ -56,8 +56,6 @@ #define EXT2_S_IFREG 0x8000 #define EXT2_S_IFDIR 0x4000 -#define DIRLS_SET 0x8000000000000000 - struct ext2_superblock_t { uint32_t s_inodes_count; uint32_t s_blocks_count; @@ -169,6 +167,8 @@ struct ext2_t { struct ext2_superblock_t* superblock; struct ext2_bg_desc_t* bgdt; struct disk_t* disk; + uint64_t block_size; + uint8_t lock; }; struct ext2_inode_handle_t { @@ -188,7 +188,7 @@ struct ext2_block_track_t { static uint8_t label_rootfs[16] = {'r', 'o', 'o', 't', 'f', 's', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; static void* read_block(uint64_t block, struct ext2_t* ext2) { - const uint64_t block_size = 1024u << ext2->superblock->s_log_block_size; + const uint64_t block_size = ext2->block_size; void* buffer = kmalloc(block_size); @@ -211,7 +211,7 @@ static uint8_t get_inode(const struct ext2_inode_handle_t* inode_handle, struct const struct ext2_superblock_t* superblock = inode_handle->ext2->superblock; const struct ext2_bg_desc_t* bgdt = inode_handle->ext2->bgdt; - const uint64_t block_size = 1024u << superblock->s_log_block_size; + const uint64_t block_size = inode_handle->ext2->block_size; const uint64_t block_group = (inode_handle->inode_index - 1) / superblock->s_inodes_per_group; const uint64_t lcl_inode_idx = (inode_handle->inode_index - 1) % superblock->s_inodes_per_group; const uint64_t lcl_inode_off = lcl_inode_idx * superblock->s_inode_size; @@ -251,7 +251,7 @@ static uint8_t get_block_index(struct ext2_block_track_t* bt, uint64_t* index) { block -= DIRECT_BLOCKS; - const uint64_t block_size = 1024u << ext2->superblock->s_log_block_size; + const uint64_t block_size = ext2->block_size; const uint64_t indir1 = block_size / sizeof(uint32_t); uint32_t* buffer; @@ -415,8 +415,7 @@ static struct file_handle_t* ext2_open(struct mount_cntx_t* cntx, char* path) { track.handle->seek = 0; track.handle->seek_block = 0; - const struct ext2_superblock_t* superblock = track.handle->ext2->superblock; - const uint64_t block_size = 1024u << superblock->s_log_block_size; + const uint64_t block_size = track.handle->ext2->block_size; const uint64_t size = (uint64_t)inode.i_size | ((uint64_t)inode.i_dir_acl << 32); void* buffer; @@ -529,8 +528,7 @@ static enum file_status_t ext2_stat(struct file_handle_t* handle, struct file_in static uint64_t ext2_get_seek(struct file_handle_t* handle) { struct ext2_inode_handle_t* inode_handle = (struct ext2_inode_handle_t*)handle; - const struct ext2_superblock_t* superblock = inode_handle->ext2->superblock; - const uint64_t block_size = 1024u << superblock->s_log_block_size; + const uint64_t block_size = inode_handle->ext2->block_size; return inode_handle->seek_block * block_size + inode_handle->seek; } @@ -546,8 +544,7 @@ static size_t ext2_read(struct file_handle_t* handle, void* buffer, size_t count } const uint64_t size = (uint64_t)inode.i_size | ((uint64_t)inode.i_dir_acl << 32); - const struct ext2_superblock_t* superblock = inode_handle->ext2->superblock; - const uint64_t block_size = 1024u << superblock->s_log_block_size; + const uint64_t block_size = inode_handle->ext2->block_size; size_t read = 0; uint64_t index; @@ -622,8 +619,7 @@ static size_t ext2_read(struct file_handle_t* handle, void* buffer, size_t count static enum file_status_t ext2_seek(struct file_handle_t* handle, uint64_t seek) { struct ext2_inode_handle_t* inode_handle = (struct ext2_inode_handle_t*)handle; - const struct ext2_superblock_t* superblock = inode_handle->ext2->superblock; - const uint64_t block_size = 1024u << superblock->s_log_block_size; + const uint64_t block_size = inode_handle->ext2->block_size; inode_handle->seek_block = seek / block_size; inode_handle->seek = seek % block_size; @@ -638,9 +634,57 @@ static size_t ext2_write(struct file_handle_t* handle, void* buffer, size_t coun return 0; } -static enum file_status_t ext2_create(struct mount_cntx_t* cntx, char* path) { - (void)cntx; - (void)path; +static enum file_status_t ext2_create(struct file_handle_t* handle, const char* name) { + (void)handle; + (void)name; + + enum file_status_t sts; + + struct file_info_t info; + if ((sts = ext2_stat(handle, &info)) != FILE_OK) { + return sts; + } + + if (info.type != FILE_TYPE_DIR) { + return FILE_NO_SUPPORT; + } + + return FILE_NO_SUPPORT; +} + +static enum file_status_t ext2_delete(struct file_handle_t* handle) { + (void)handle; + return FILE_NO_SUPPORT; +} + +static void ext2_delete_final(struct file_handle_t* handle) { + (void)handle; +} + +static enum file_status_t ext2_open_dir(struct file_handle_t* handle) { + (void)handle; + return FILE_NO_SUPPORT; +} + +static void ext2_close_dir(struct file_handle_t* handle) { + (void)handle; +} + +static enum file_status_t ext2_read_dir(struct file_handle_t* handle, struct dir_info_t* info) { + (void)handle; + (void)info; + return FILE_NO_SUPPORT; +} + +static enum file_status_t ext2_create_dir(struct file_handle_t* handle, const char* name) { + (void)handle; + (void)name; + + return FILE_NO_SUPPORT; +} + +static enum file_status_t ext2_delete_dir(struct file_handle_t* handle) { + (void)handle; return FILE_NO_SUPPORT; } @@ -685,6 +729,8 @@ uint8_t ext2_attempt_init(struct disk_t* disk, uint64_t start_lba, uint64_t end_ ext2->superblock = superblock; ext2->bgdt = bgdt; ext2->disk = disk; + ext2->block_size = 1024u << superblock->s_log_block_size; + lock_init(&ext2->lock); logging_log_debug("ext2 blocks: 0x%x x 0x%x (0x%lX)", 1024u << superblock->s_log_block_size, superblock->s_blocks_count, @@ -701,7 +747,14 @@ uint8_t ext2_attempt_init(struct disk_t* disk, uint64_t start_lba, uint64_t end_ ext2_get_seek, ext2_seek, ext2_write, - ext2_create + ext2_create, + ext2_delete, + ext2_delete_final, + ext2_open_dir, + ext2_close_dir, + ext2_read_dir, + ext2_create_dir, + ext2_delete_dir ) != FILE_OK) { logging_log_error("Failed to mount rootfs"); panic(PANIC_STATE); diff --git a/kernel/core/exception_dispatch.c b/kernel/core/exception_dispatch.c index c7bde50..2fb0bbe 100644 --- a/kernel/core/exception_dispatch.c +++ b/kernel/core/exception_dispatch.c @@ -101,7 +101,6 @@ static inline const char* get_exception_name(uint64_t vector) { } void exception_dispatch(struct exception_context_t* context) { - //TODO: remove reduntant rsp push logging_log_error("Unrecoverable exception 0x%lX %s (0x%lX) @ 0x%lX", context->vector, get_exception_name(context->vector), context->code, context->rip); diff --git a/kernel/core/fs.c b/kernel/core/fs.c index ca0166b..7208b45 100644 --- a/kernel/core/fs.c +++ b/kernel/core/fs.c @@ -65,13 +65,21 @@ struct vfs_mount_t { fs_seek_t seek; fs_write_t write; fs_create_t create; + fs_delete_t delete; + fs_delete_final_t delete_final; + fs_open_dir_t open_dir; + fs_close_dir_t close_dir; + fs_read_dir_t read_dir; + fs_create_dir_t create_dir; + fs_delete_dir_t delete_dir; }; struct vfs_open_file_t { - uint8_t lock; const char* path; uint64_t refs; uint64_t key; + uint8_t lock; + uint8_t pending_delete; }; struct fs_handle_t { @@ -103,7 +111,12 @@ static struct vfs_mount_t dev_mount = { .get_seek = devfs_get_seek, .seek = devfs_seek, .write = devfs_write, - .create = devfs_create + .create = devfs_create, + .delete = devfs_delete, + .delete_final = devfs_delete_final, + .open_dir = devfs_open_dir, + .close_dir = devfs_close_dir, + .read_dir = devfs_read_dir }; static inline char* path_next(char* path, size_t* len) { @@ -141,6 +154,7 @@ static struct vfs_open_file_t* lookup_register(char* path) { file->refs = 0; file->key = key; + file->pending_delete = 0; lock_init(&file->lock); hash_table_insert(open_table, key, file); @@ -151,17 +165,18 @@ static struct vfs_open_file_t* lookup_register(char* path) { return file; } -static void lookup_close(struct vfs_open_file_t* file) { +static uint8_t lookup_close(struct vfs_open_file_t* file) { file->refs--; if (file->refs) { - return; + return 0; } kfree((char*)file->path); hash_table_remove(open_table, file->key); kfree(file); + return 1; } void fs_init(void) { @@ -190,7 +205,14 @@ enum file_status_t fs_mount( fs_get_seek_t get_seek, fs_seek_t seek, fs_write_t write, - fs_create_t create + fs_create_t create, + fs_delete_t delete, + fs_delete_final_t delete_final, + fs_open_dir_t open_dir, + fs_close_dir_t close_dir, + fs_read_dir_t read_dir, + fs_create_dir_t create_dir, + fs_delete_dir_t delete_dir ) { if (kstrcmp(mountpoint, "") && !vfs_root.mount) { @@ -210,6 +232,13 @@ enum file_status_t fs_mount( vfs_root.mount->seek = seek; vfs_root.mount->write = write; vfs_root.mount->create = create; + vfs_root.mount->delete = delete; + vfs_root.mount->delete_final = delete_final; + vfs_root.mount->open_dir = open_dir; + vfs_root.mount->close_dir = close_dir; + vfs_root.mount->read_dir = read_dir; + vfs_root.mount->create_dir = create_dir; + vfs_root.mount->delete_dir = delete_dir; return FILE_OK; } @@ -338,15 +367,18 @@ struct fs_handle_t* fs_open(const char* path) { } void fs_close(struct fs_handle_t* handle) { + semaphore_wait_full(fs_sem); + if (lookup_close(handle->shared)) { + if (handle->shared->pending_delete) { + handle->mount->delete_final(handle->handle); + } + } + semaphore_signal_full(fs_sem); lock_acquire(&handle->shared->lock); handle->mount->close(handle->handle); lock_release(&handle->shared->lock); - semaphore_wait_full(fs_sem); - lookup_close(handle->shared); - semaphore_signal_full(fs_sem); - kfree(handle); } @@ -399,22 +431,74 @@ size_t fs_write(struct fs_handle_t* handle, void* buffer, size_t count) { return ret; } -enum file_status_t fs_create(const char* path) { +enum file_status_t fs_create(struct fs_handle_t* handle, const char* name) { enum file_status_t sts; - struct vfs_mount_t* mount; - void* clean_path; - char* path_write; - char* mount_path = find_mount(path, &mount, &clean_path, &path_write); + lock_acquire(&handle->shared->lock); + sts = handle->mount->create(handle->handle, name); + lock_release(&handle->shared->lock); - if (!mount) { - kfree(clean_path); - return FILE_DNE; + return sts; +} + +enum file_status_t fs_delete(struct fs_handle_t* handle) { + enum file_status_t sts; + + lock_acquire(&handle->shared->lock); + sts = handle->mount->delete(handle->handle); + handle->shared->pending_delete = 1; + lock_release(&handle->shared->lock); + + return sts; +} + +struct fs_handle_t* fs_open_dir(struct fs_handle_t* handle) { + enum file_status_t sts; + + lock_acquire(&handle->shared->lock); + sts = handle->mount->open_dir(handle->handle); + lock_release(&handle->shared->lock); + + if (sts != FILE_OK) { + return 0; } - sts = mount->create(mount->cntx, mount_path); + return handle; +} - kfree(clean_path); +void fs_close_dir(struct fs_handle_t* handle) { + lock_acquire(&handle->shared->lock); + handle->mount->close_dir(handle->handle); + lock_release(&handle->shared->lock); +} + +enum file_status_t fs_read_dir(struct fs_handle_t* handle, struct dir_info_t* info) { + enum file_status_t sts; + + lock_acquire(&handle->shared->lock); + sts = handle->mount->read_dir(handle->handle, info); + lock_release(&handle->shared->lock); + + return sts; +} + +enum file_status_t fs_create_dir(struct fs_handle_t* handle, const char* name) { + enum file_status_t sts; + + lock_acquire(&handle->shared->lock); + sts = handle->mount->create_dir(handle->handle, name); + lock_release(&handle->shared->lock); + + return sts; +} + +enum file_status_t fs_delete_dir(struct fs_handle_t* handle) { + enum file_status_t sts; + + lock_acquire(&handle->shared->lock); + sts = handle->mount->delete_dir(handle->handle); + handle->shared->pending_delete = 1; + lock_release(&handle->shared->lock); return sts; } diff --git a/kernel/core/syscall.S b/kernel/core/syscall.S index 93ebb9a..77d5588 100644 --- a/kernel/core/syscall.S +++ b/kernel/core/syscall.S @@ -60,14 +60,6 @@ sysretq .section .rodata -.extern syscall_dispatch_exit -.extern syscall_dispatch_open -.extern syscall_disaptch_close -.extern syscall_dispatch_read -.extern syscall_dispatch_write -.extern syscall_dispatch_alloc -.extern syscall_dispatch_create - .global syscall_handlers syscall_handlers: @@ -78,3 +70,17 @@ syscall_handlers: .quad syscall_dispatch_write .quad syscall_dispatch_alloc .quad syscall_dispatch_create +.quad syscall_dispatch_delete +.quad syscall_dispatch_open_dir +.quad syscall_dispatch_read_dir +.quad syscall_dispatch_close_dir +.quad syscall_dispatch_seek +.quad syscall_dispatch_tell +.quad syscall_dispatch_create_dir +.quad syscall_dispatch_delete_dir +.quad syscall_dispatch_epoch_time + +.set num_entries, . - syscall_handlers +.if num_entries != SYSCALL_MAX * 8 +.error "Inconsistent number of registered system cals in call table" +.endif diff --git a/kernel/core/syscall_dispatch.c b/kernel/core/syscall_dispatch.c index 9558924..521c4ae 100644 --- a/kernel/core/syscall_dispatch.c +++ b/kernel/core/syscall_dispatch.c @@ -27,6 +27,7 @@ #include #include #include +#include #include @@ -75,7 +76,7 @@ DECLARE_SYSCALL(exit) { } DECLARE_SYSCALL(open) { - ARGC_0; + ARGC_1; int fd; struct pcb_t* pcb = proc_data_get()->current_process; @@ -95,15 +96,16 @@ DECLARE_SYSCALL(open) { } DECLARE_SYSCALL(close) { - ARGC_0; + ARGC_1; struct pcb_t* pcb = proc_data_get()->current_process; + struct fs_handle_t* handle = pcb->fd_table[arg1]; - if (!pcb->fd_table[arg1]) { + if (!handle) { return SYSCALL_STS_FAIL; } - fs_close(pcb->fd_table[arg1]); + fs_close(handle); pcb->fd_table[arg1] = 0; return SYSCALL_STS_OK; @@ -113,14 +115,26 @@ DECLARE_SYSCALL(read) { ARGC_3; struct pcb_t* pcb = proc_data_get()->current_process; - return (uint64_t)fs_read(pcb->fd_table[arg1], (void*)arg2, (size_t)arg3); + struct fs_handle_t* handle = pcb->fd_table[arg1]; + + if (!handle) { + return SYSCALL_STS_FAIL; + } + + return fs_read(handle, (void*)arg2, (size_t)arg3); } DECLARE_SYSCALL(write) { ARGC_3; struct pcb_t* pcb = proc_data_get()->current_process; - return (uint64_t)fs_write(pcb->fd_table[arg1], (void*)arg2, (size_t)arg3); + struct fs_handle_t* handle = pcb->fd_table[arg1]; + + if (!handle) { + return SYSCALL_STS_FAIL; + } + + return fs_write(handle, (void*)arg2, (size_t)arg3); } DECLARE_SYSCALL(alloc) { @@ -152,7 +166,127 @@ DECLARE_SYSCALL(alloc) { } DECLARE_SYSCALL(create) { + ARGC_2; + + struct pcb_t* pcb = proc_data_get()->current_process; + struct fs_handle_t* handle = pcb->fd_table[arg1]; + + if (!handle) { + return SYSCALL_STS_FAIL; + } + + return fs_create(handle, (const char*)arg2) == FILE_OK; +} + +DECLARE_SYSCALL(delete) { + ARGC_1; + + struct pcb_t* pcb = proc_data_get()->current_process; + struct fs_handle_t* handle = pcb->fd_table[arg1]; + + if (!handle) { + return SYSCALL_STS_FAIL; + } + + return fs_delete(handle) == FILE_OK; +} + +DECLARE_SYSCALL(open_dir) { + ARGC_1; + + struct pcb_t* pcb = proc_data_get()->current_process; + struct fs_handle_t* handle = pcb->fd_table[arg1]; + + if (!handle) { + return SYSCALL_STS_FAIL; + } + + return (uint64_t)fs_open_dir(handle); +} + +DECLARE_SYSCALL(read_dir) { + ARGC_2; + + struct pcb_t* pcb = proc_data_get()->current_process; + struct fs_handle_t* handle = pcb->fd_table[arg1]; + + if (!handle) { + return SYSCALL_STS_FAIL; + } + + return fs_read_dir(handle, (struct dir_info_t*)arg2) == FILE_OK; +} + +DECLARE_SYSCALL(close_dir) { ARGC_1; - return fs_create((const char*)arg1) != FILE_OK; + struct pcb_t* pcb = proc_data_get()->current_process; + struct fs_handle_t* handle = pcb->fd_table[arg1]; + + if (!handle) { + return SYSCALL_STS_FAIL; + } + + fs_close_dir(handle); + + return SYSCALL_STS_OK; +} + +DECLARE_SYSCALL(seek) { + ARGC_2; + + struct pcb_t* pcb = proc_data_get()->current_process; + struct fs_handle_t* handle = pcb->fd_table[arg1]; + + if (!handle) { + return SYSCALL_STS_FAIL; + } + + fs_seek(handle, (uint64_t)arg2); + return fs_get_seek(handle); +} + +DECLARE_SYSCALL(tell) { + ARGC_1; + + struct pcb_t* pcb = proc_data_get()->current_process; + struct fs_handle_t* handle = pcb->fd_table[arg1]; + + if (!handle) { + return SYSCALL_STS_FAIL; + } + + return fs_get_seek(handle); +} + +DECLARE_SYSCALL(create_dir) { + ARGC_2; + + struct pcb_t* pcb = proc_data_get()->current_process; + struct fs_handle_t* handle = pcb->fd_table[arg1]; + + if (!handle) { + return SYSCALL_STS_FAIL; + } + + return fs_create_dir(handle, (const char*)arg2) == FILE_OK; +} + +DECLARE_SYSCALL(delete_dir) { + ARGC_1; + + struct pcb_t* pcb = proc_data_get()->current_process; + struct fs_handle_t* handle = pcb->fd_table[arg1]; + + if (!handle) { + return SYSCALL_STS_FAIL; + } + + return fs_delete_dir(handle) == FILE_OK; +} + +DECLARE_SYSCALL(epoch_time) { + ARGC_0; + + return time_since_init_ns(); } diff --git a/kernel/devfs/devfs.c b/kernel/devfs/devfs.c index 67442df..e970f72 100644 --- a/kernel/devfs/devfs.c +++ b/kernel/devfs/devfs.c @@ -143,9 +143,45 @@ size_t devfs_write(struct file_handle_t* handle, void* buffer, size_t count) { } } -enum file_status_t devfs_create(struct mount_cntx_t* cntx, char* path) { - (void)cntx; - (void)path; +enum file_status_t devfs_create(struct file_handle_t* handle, const char* name) { + (void)handle; + (void)name; + return FILE_NO_SUPPORT; +} + +enum file_status_t devfs_delete(struct file_handle_t* handle) { + (void)handle; + return FILE_NO_SUPPORT; +} + +void devfs_delete_final(struct file_handle_t* handle) { + (void)handle; +} + +enum file_status_t devfs_open_dir(struct file_handle_t* handle) { + (void)handle; + return FILE_NO_SUPPORT; +} + +void devfs_close_dir(struct file_handle_t* handle) { + (void)handle; +} + +enum file_status_t devfs_read_dir(struct file_handle_t* handle, struct dir_info_t* info) { + (void)handle; + (void)info; + return FILE_NO_SUPPORT; +} + +enum file_status_t devfs_create_dir(struct file_handle_t* handle, const char* name) { + (void)handle; + (void)name; + + return FILE_NO_SUPPORT; +} + +enum file_status_t devfs_delete_dir(struct file_handle_t* handle) { + (void)handle; return FILE_NO_SUPPORT; } diff --git a/kernel/include/core/fs.h b/kernel/include/core/fs.h index 9cc81a3..84484b4 100644 --- a/kernel/include/core/fs.h +++ b/kernel/include/core/fs.h @@ -44,6 +44,10 @@ struct file_info_t { uint64_t size; }; +struct dir_info_t { + const char* name; +}; + typedef struct file_handle_t* (*fs_open_t)(struct mount_cntx_t*, char*); typedef void (*fs_close_t)(struct file_handle_t*); @@ -52,8 +56,17 @@ typedef size_t (*fs_read_t)(struct file_handle_t*, void*, size_t); typedef uint64_t (*fs_get_seek_t)(struct file_handle_t*); typedef enum file_status_t (*fs_seek_t)(struct file_handle_t*, uint64_t); typedef size_t (*fs_write_t)(struct file_handle_t*, void*, size_t); +typedef enum file_status_t (*fs_create_t)(struct file_handle_t*, const char*); +typedef enum file_status_t (*fs_delete_t)(struct file_handle_t*); +typedef void (*fs_delete_final_t)(struct file_handle_t*); + +typedef enum file_status_t (*fs_open_dir_t)(struct file_handle_t*); +typedef void (*fs_close_dir_t)(struct file_handle_t*); -typedef enum file_status_t (*fs_create_t)(struct mount_cntx_t*, char*); +typedef enum file_status_t (*fs_read_dir_t)(struct file_handle_t*, struct dir_info_t*); + +typedef enum file_status_t (*fs_create_dir_t)(struct file_handle_t*, const char*); +typedef enum file_status_t (*fs_delete_dir_t)(struct file_handle_t*); void fs_init(void); @@ -67,7 +80,14 @@ enum file_status_t fs_mount( fs_get_seek_t get_seek, fs_seek_t seek, fs_write_t write, - fs_create_t create + fs_create_t create, + fs_delete_t delete, + fs_delete_final_t delete_final, + fs_open_dir_t open_dir, + fs_close_dir_t close_dir, + fs_read_dir_t read_dir, + fs_create_dir_t create_dir, + fs_delete_dir_t delete_dir ); extern struct fs_handle_t* fs_open(const char* path); @@ -78,7 +98,15 @@ extern size_t fs_read(struct fs_handle_t* handle, void* buffer, size_t count); extern uint64_t fs_get_seek(struct fs_handle_t* handle); extern enum file_status_t fs_seek(struct fs_handle_t* handle, uint64_t seek); extern size_t fs_write(struct fs_handle_t* handle, void* buffer, size_t count); +extern enum file_status_t fs_create(struct fs_handle_t* handle, const char* name); +extern enum file_status_t fs_delete(struct fs_handle_t* handle); + +extern struct fs_handle_t* fs_open_dir(struct fs_handle_t* handle); +extern void fs_close_dir(struct fs_handle_t* handle); + +extern enum file_status_t fs_read_dir(struct fs_handle_t* handle, struct dir_info_t* info); -extern enum file_status_t fs_create(const char* path); +extern enum file_status_t fs_create_dir(struct fs_handle_t* handle, const char* name); +extern enum file_status_t fs_delete_dir(struct fs_handle_t* handle); #endif /* KERNEL_CORE_FS_H */ diff --git a/kernel/include/core/syscall_dispatch.h b/kernel/include/core/syscall_dispatch.h index 443c77a..ac50bd0 100644 --- a/kernel/include/core/syscall_dispatch.h +++ b/kernel/include/core/syscall_dispatch.h @@ -49,5 +49,14 @@ extern DECLARE_SYSCALL(read); extern DECLARE_SYSCALL(write); extern DECLARE_SYSCALL(alloc); extern DECLARE_SYSCALL(create); +extern DECLARE_SYSCALL(delete); +extern DECLARE_SYSCALL(open_dir); +extern DECLARE_SYSCALL(read_dir); +extern DECLARE_SYSCALL(close_dir); +extern DECLARE_SYSCALL(seek); +extern DECLARE_SYSCALL(tell); +extern DECLARE_SYSCALL(create_dir); +extern DECLARE_SYSCALL(delete_dir); +extern DECLARE_SYSCALL(epoch_time); #endif /* KERNEL_CORE_SYSCALL_DISPATCH_H */ diff --git a/kernel/include/core/syscall_vectors.h b/kernel/include/core/syscall_vectors.h index 9912fa2..f7b0c3c 100644 --- a/kernel/include/core/syscall_vectors.h +++ b/kernel/include/core/syscall_vectors.h @@ -76,11 +76,68 @@ #define SYSCALL_ALLOC 5 /* - * rdi: path (const char*) - * ret: (int) + * rdi: handle (int) + * rsi: name (const char*) + * ret: success (int) */ #define SYSCALL_CREATE 6 -#define SYSCALL_MAX 7 +/* + * rdi: handle (int) + * ret: success (int) + */ +#define SYSCALL_DELETE 7 + +/* + * rdi: handle (int) + * ret handle (void*) + */ +#define SYSCALL_OPEN_DIR 8 + +/* + * rdi: handle (void*) + * rsi: info buffer (void*) + * ret: success (int) + */ +#define SYSCALL_READ_DIR 9 + +/* + * rdi: handle (void*) + * ret: (void) + */ +#define SYSCALL_CLOSE_DIR 10 + +/* + * rdi: handle (int) + * rsi: seek (long int) + * ret: new seek (long int) + */ +#define SYSCALL_SEEK 11 + +/* + * rdi: handle (int) + * ret: seek (long int) + */ +#define SYSCALL_TELL 12 + +/* + * rdi: handle (int) + * rsi: name (const char*) + * ret: success (int) + */ +#define SYSCALL_CREATE_DIR 13 + +/* + * rdi: handle (int) + * ret: success (int) + */ +#define SYSCALL_DELETE_DIR 14 + +/* + * ret: time since epoch in nanos (long int) + */ +#define SYSCALL_EPOCH_TIME 15 + +#define SYSCALL_MAX 16 diff --git a/kernel/include/devfs/devfs.h b/kernel/include/devfs/devfs.h index 4ae5019..f01c4fe 100644 --- a/kernel/include/devfs/devfs.h +++ b/kernel/include/devfs/devfs.h @@ -21,7 +21,7 @@ #include #include -#include +#include extern struct file_handle_t* devfs_open(struct mount_cntx_t* cntx, char* path); extern void devfs_close(struct file_handle_t* handle); @@ -31,6 +31,16 @@ extern size_t devfs_read(struct file_handle_t* handle, void* buffer, size_t coun extern uint64_t devfs_get_seek(struct file_handle_t* handle); extern enum file_status_t devfs_seek(struct file_handle_t* handle, uint64_t seek); extern size_t devfs_write(struct file_handle_t* handle, void* buffer, size_t count); -extern enum file_status_t devfs_create(struct mount_cntx_t* cntx, char* path); +extern enum file_status_t devfs_create(struct file_handle_t* handle, const char* name); +extern enum file_status_t devfs_delete(struct file_handle_t* handle); +extern void devfs_delete_final(struct file_handle_t* handle); + +extern enum file_status_t devfs_open_dir(struct file_handle_t* handle); +extern void devfs_close_dir(struct file_handle_t* handle); + +extern enum file_status_t devfs_read_dir(struct file_handle_t* handle, struct dir_info_t* info); + +extern enum file_status_t devfs_create_dir(struct file_handle_t* handle, const char* name); +extern enum file_status_t devfs_delete_dir(struct file_handle_t* handle); #endif /* KERNEL_DEVFS_DEVFS_H */ diff --git a/test/lib/test.c b/test/lib/test.c index f13973d..e081e25 100644 --- a/test/lib/test.c +++ b/test/lib/test.c @@ -130,6 +130,6 @@ TEST("crc32_ansi") { } TEST("fnc64_1a") { - //TODO - TEST_FAIL(); + ASSERT_TRUE(fnv64_1a("Hello, World!", 13) == 0x6ef05bd7cc857c54, "fails expected checksum"); + ASSERT_FALSE(fnv64_1a("Hello, World!", 12) == 0x6ef05bd7cc857c54, "fails expected checksum"); } diff --git a/userland/mlibc-patch/sysdeps/modulos/sysdeps.cpp b/userland/mlibc-patch/sysdeps/modulos/sysdeps.cpp index a6a16cf..15b7ad9 100644 --- a/userland/mlibc-patch/sysdeps/modulos/sysdeps.cpp +++ b/userland/mlibc-patch/sysdeps/modulos/sysdeps.cpp @@ -20,12 +20,21 @@ #include -#include +#include +#include + #include +#define stdout 0 +#define stdin 1 #define stderr 2 -#define TRAP asm volatile ("int3" : : : "memory") +#define SECONDS_PER_NANO 0x10000000000 + +[[noreturn]] static inline void _trap(void) { + asm volatile ("int3" : : : "memory"); + __builtin_unreachable(); +} namespace mlibc { @@ -97,12 +106,16 @@ int sys_read(int fd, void *buf, size_t count, ssize_t *bytes_read) { } int sys_seek(int fd, off_t offset, int whence, off_t *new_offset) { - (void)fd; - (void)offset; - (void)whence; - (void)new_offset; - - return 0; + switch (whence) { + case SEEK_CUR: + offset += syscall_1(fd, 0, 0, SYSCALL_TELL); + __attribute__((fallthrough)); + case SEEK_SET: + *new_offset = syscall_2(fd, (uint64_t)offset, 0, SYSCALL_SEEK); + return 0; + default: + _trap(); + } } int sys_close(int fd) { @@ -120,8 +133,7 @@ int sys_vm_map(void *hint, size_t size, int prot, int flags, int fd, off_t offse (void)offset; (void)window; - TRAP; - return 0; + _trap(); } int sys_vm_unmap(void *pointer, size_t size) { @@ -138,16 +150,16 @@ int sys_vm_unmap(void *pointer, size_t size) { } int sys_write(int fd, const void *buf, size_t count, ssize_t *bytes_written) { - *bytes_written = syscall_3((uint64_t)fd, (uint64_t)buf , (uint64_t)count, SYSCALL_WRITE); + *bytes_written = syscall_3((uint64_t)fd, (uint64_t)buf, (uint64_t)count, SYSCALL_WRITE); return 0; } int sys_isatty(int fd) { switch (fd) { - case 0: - case 1: - case 2: + case stdout: + case stdin: + case stderr: return 0; //mlibc expects 0 for tty default: return ENOTTY; @@ -155,11 +167,24 @@ int sys_isatty(int fd) { } int sys_clock_get(int clock, time_t *secs, long *nanos) { - (void)clock; - (void)secs; - (void)nanos; - TRAP; - return 0; + uint64_t epoch_nanos = syscall_0(0, 0, 0, SYSCALL_EPOCH_TIME); + + switch (clock) { + case CLOCK_REALTIME: + case CLOCK_MONOTONIC: + case CLOCK_MONOTONIC_RAW: + case CLOCK_REALTIME_COARSE: + case CLOCK_MONOTONIC_COARSE: + case CLOCK_BOOTTIME: + case CLOCK_REALTIME_ALARM: + case CLOCK_BOOTTIME_ALARM: + case CLOCK_TAI: + *secs = epoch_nanos / SECONDS_PER_NANO; + *nanos = epoch_nanos % SECONDS_PER_NANO; + return 0; + default: + return 1; + } } } //namespace mlibc From d26406b2cd0f8d3382683e89546cd0ec7d216f3c Mon Sep 17 00:00:00 2001 From: Ebrahim Aleem Date: Wed, 6 May 2026 10:55:48 -0700 Subject: [PATCH 08/13] implemented directory reading --- drivers/ext2/ext2.c | 458 ++++++++++-------- kernel/core/elf.c | 6 +- kernel/core/fs.c | 27 +- kernel/core/kentry.c | 2 +- kernel/core/process.c | 6 +- kernel/core/syscall.S | 1 + kernel/core/syscall_dispatch.c | 17 +- kernel/devfs/devfs.c | 19 +- kernel/include/core/fs.h | 23 +- kernel/include/core/syscall_dispatch.h | 1 + kernel/include/core/syscall_vectors.h | 11 +- kernel/include/devfs/devfs.h | 2 + userland/mlibc-patch/abis/modulos/fcntl.h | 8 +- userland/mlibc-patch/abis/modulos/mode_t.h | 2 + .../mlibc-patch/sysdeps/modulos/sysdeps.cpp | 14 +- 15 files changed, 364 insertions(+), 233 deletions(-) diff --git a/drivers/ext2/ext2.c b/drivers/ext2/ext2.c index 17294c8..b05953d 100644 --- a/drivers/ext2/ext2.c +++ b/drivers/ext2/ext2.c @@ -33,6 +33,7 @@ #include #include #include +#include #define SUPERBLOCK_LBA 2 #define SUPERBLOCK_SECTORS 2 @@ -42,13 +43,6 @@ #define INDIR_2 13 #define INDIR_3 14 -#define BLOCK_OK 0 -#define BLOCK_RETRY 1 -#define BLOCK_LAST 2 -#define BLOCK_ERROR 3 - -#define EXT2_FT_DIR 2 - #define EXT2_SUPER_MAGIC 0xEF53 #define EXT2_ROOT_INO 2 @@ -56,6 +50,11 @@ #define EXT2_S_IFREG 0x8000 #define EXT2_S_IFDIR 0x4000 +#define EXT2_FT_REG_FILE 1 +#define EXT2_FT_DIR 2 + +#define MODE_DIR 0x1 + struct ext2_superblock_t { uint32_t s_inodes_count; uint32_t s_blocks_count; @@ -176,13 +175,13 @@ struct ext2_inode_handle_t { uint64_t inode_index; uint64_t seek; uint64_t seek_block; + uint8_t ext2_mode; }; -struct ext2_block_track_t { - struct ext2_inode_handle_t* handle; - struct ext2_inode_t* inode; - uint64_t off; - uint64_t block; +enum ext2_block_state_t { + BLOCK_OK, + BLOCK_SPARSE, + BLOCK_ERROR }; static uint8_t label_rootfs[16] = {'r', 'o', 'o', 't', 'f', 's', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; @@ -207,6 +206,24 @@ static void* read_block(uint64_t block, struct ext2_t* ext2) { return buffer; } +static void* write_block(uint64_t block, struct ext2_t* ext2, void* buffer) { + const uint64_t block_size = ext2->block_size; + + const uint64_t lba = ext2->start_lba + block * block_size / SECTOR_SIZE; + + if (lba > ext2->end_lba) { + logging_log_error("Attempt to write beyond ext2 end lba (0x%x > 0x%x)", lba, ext2->end_lba); + } + + if (disk_write(ext2->disk, buffer, lba, (uint16_t)(block_size / SECTOR_SIZE)) != DISK_OK) { + logging_log_error("Failed to write"); + kfree(buffer); + return 0; + } + + return buffer; +} + static uint8_t get_inode(const struct ext2_inode_handle_t* inode_handle, struct ext2_inode_t* inode) { const struct ext2_superblock_t* superblock = inode_handle->ext2->superblock; const struct ext2_bg_desc_t* bgdt = inode_handle->ext2->bgdt; @@ -232,94 +249,115 @@ static uint8_t get_inode(const struct ext2_inode_handle_t* inode_handle, struct return 0; } -static uint8_t get_block_index(struct ext2_block_track_t* bt, uint64_t* index) { - uint64_t block = bt->block; - struct ext2_inode_t* inode = bt->inode; - struct ext2_t* ext2 = bt->handle->ext2; +__attribute__((unused)) //TODO: remove +static uint8_t set_inode(const struct ext2_inode_handle_t* inode_handle, struct ext2_inode_t* inode) { + const struct ext2_superblock_t* superblock = inode_handle->ext2->superblock; + const struct ext2_bg_desc_t* bgdt = inode_handle->ext2->bgdt; + + const uint64_t block_size = inode_handle->ext2->block_size; + const uint64_t block_group = (inode_handle->inode_index - 1) / superblock->s_inodes_per_group; + const uint64_t lcl_inode_idx = (inode_handle->inode_index - 1) % superblock->s_inodes_per_group; + const uint64_t lcl_inode_off = lcl_inode_idx * superblock->s_inode_size; + const uint64_t lcl_inode_blk = lcl_inode_off / block_size; + const uint64_t inode_off = lcl_inode_off % block_size; + + const uint64_t inode_table_block = bgdt[block_group].bg_inode_table + lcl_inode_blk; + void* buffer = read_block(inode_table_block, inode_handle->ext2); + if (!buffer) { + logging_log_error("Failed to read inode %lu", inode_handle->inode_index); + kfree(buffer); + return 1; + } - if (block < DIRECT_BLOCKS) { - *index = inode->i_block[block]; + *(struct ext2_inode_t*)((uint64_t)buffer + inode_off) = *inode; - if (!*index) { - bt->block += 1; - return BLOCK_RETRY; - } + if (!write_block(inode_table_block, inode_handle->ext2, buffer)) { + logging_log_error("Failed to write inode %lu", inode_handle->inode_index); + kfree(buffer); + return 1; + } + kfree(buffer); + return 0; +} + +static enum ext2_block_state_t get_block(struct ext2_t* ext2, + struct ext2_inode_t* inode, + uint64_t index, + uint64_t* block) { + if (index < DIRECT_BLOCKS) { + *block = inode->i_block[index]; + if (!*block) { + return BLOCK_SPARSE; + } return BLOCK_OK; } - block -= DIRECT_BLOCKS; + index -= DIRECT_BLOCKS; + uint32_t* buffer; const uint64_t block_size = ext2->block_size; const uint64_t indir1 = block_size / sizeof(uint32_t); - uint32_t* buffer; - - if (block < indir1) { - *index = inode->i_block[INDIR_1]; + if (index < indir1) { + *block = inode->i_block[INDIR_1]; - if (!*index) { - bt->block += indir1; - return BLOCK_RETRY; + if (!*block) { + return BLOCK_SPARSE; } - buffer = read_block(*index, ext2); + buffer = read_block(*block, ext2); if (!buffer) { return BLOCK_ERROR; } - *index = buffer[block]; + *block = buffer[index]; kfree(buffer); - if (!*index) { - bt->block += 1; - return BLOCK_RETRY; + if (!*block) { + return BLOCK_SPARSE; } return BLOCK_OK; } - block -= indir1; + index -= indir1; const uint64_t indir2 = indir1 * indir1; + if (index < indir2) { + *block = inode->i_block[INDIR_2]; - if (block < indir2) { - *index = inode->i_block[INDIR_2]; - - if (!*index) { - bt->block += indir2; - return BLOCK_RETRY; + if (!*block) { + return BLOCK_SPARSE; } - buffer = read_block(*index, ext2); + buffer = read_block(*block, ext2); if (!buffer) { return BLOCK_ERROR; } - *index = buffer[block / indir1]; + *block = buffer[index / indir1]; kfree(buffer); - if (!*index) { - bt->block += indir1; - return BLOCK_RETRY; + if (!*block) { + return BLOCK_SPARSE; } - buffer = read_block(*index, ext2); + buffer = read_block(*block, ext2); if (!buffer) { return BLOCK_ERROR; } - *index = buffer[block % indir1]; + *block = buffer[index % indir1]; kfree(buffer); - if (!*index) { - bt->block += 1; - return BLOCK_RETRY; + if (!*block) { + return BLOCK_SPARSE; } return BLOCK_OK; @@ -329,60 +367,56 @@ static uint8_t get_block_index(struct ext2_block_track_t* bt, uint64_t* index) { const uint64_t indir3 = indir2 * indir1; - if (block < indir3) { - *index = inode->i_block[INDIR_3]; + if (index < indir3) { + *block = inode->i_block[INDIR_3]; - if (!*index) { - bt->block += indir3; - return BLOCK_RETRY; + if (!*block) { + return BLOCK_SPARSE; } - buffer = read_block(*index, ext2); + buffer = read_block(*block, ext2); if (!buffer) { return BLOCK_ERROR; } - *index = buffer[block / indir2]; + *block = buffer[index / indir2]; kfree(buffer); - if (!*index) { - bt->block += indir2; - return BLOCK_RETRY; + if (!*block) { + return BLOCK_SPARSE; } - buffer = read_block(*index, ext2); + buffer = read_block(*block, ext2); if (!buffer) { return BLOCK_ERROR; } - *index = buffer[(block % indir2) / indir1]; + *block = buffer[(index % indir2) / indir1]; kfree(buffer); - if (!*index) { - bt->block += indir1; - return BLOCK_RETRY; + if (!*block) { + return BLOCK_SPARSE; } - buffer = read_block(*index, ext2); + buffer = read_block(*block, ext2); if (!buffer) { return BLOCK_ERROR; } - *index = buffer[block % indir1]; + *block = buffer[index % indir1]; kfree(buffer); - if (!*index) { - bt->block += 1; - return BLOCK_RETRY; + if (!*block) { + return BLOCK_SPARSE; } return BLOCK_OK; } - return BLOCK_LAST; + return BLOCK_ERROR; } static inline size_t path_entry_len(char* path) { @@ -395,149 +429,194 @@ static inline size_t path_entry_len(char* path) { return len; } +static uint64_t ext2_get_seek(struct file_handle_t* handle) { + struct ext2_inode_handle_t* inode_handle = (struct ext2_inode_handle_t*)handle; + const uint64_t block_size = inode_handle->ext2->block_size; + + return inode_handle->seek_block * block_size + inode_handle->seek; +} -static struct file_handle_t* ext2_open(struct mount_cntx_t* cntx, char* path) { +static enum file_status_t ext2_stat(struct file_handle_t* handle, struct file_info_t* info) { struct ext2_inode_t inode; - size_t path_len; - struct ext2_block_track_t track; - uint64_t block_index; - uint8_t cntrl = 0; + struct ext2_inode_handle_t* inode_handle = (struct ext2_inode_handle_t*)handle; + + if (!inode_handle || get_inode(inode_handle, &inode)) { + return FILE_ERROR; + } + + if (inode.i_mode & EXT2_S_IFREG) { + info->type = FILE_TYPE_REG; + } + else if (inode.i_mode & EXT2_S_IFDIR) { + info->type = FILE_TYPE_DIR; + } + else { + return FILE_NO_SUPPORT; + } + + info->size = (uint64_t)inode.i_size | ((uint64_t)inode.i_dir_acl << 32); + return FILE_OK; +} - track.handle = kmalloc(sizeof(struct ext2_inode_handle_t)); +static enum file_status_t ext2_open_dir(struct file_handle_t* handle) { + struct ext2_inode_handle_t* inode_handle = (struct ext2_inode_handle_t*)handle; - if (!track.handle) { - return 0; + struct file_info_t info; + ext2_stat(handle, &info); + + if (info.type != FILE_TYPE_DIR) { + return FILE_NOT_DIR; } - track.handle->ext2 = (struct ext2_t*)cntx; - track.handle->inode_index = EXT2_ROOT_INO; - track.handle->seek = 0; - track.handle->seek_block = 0; + inode_handle->seek = 0; + inode_handle->seek_block = 0; + inode_handle->ext2_mode |= MODE_DIR; + return FILE_OK; +} - const uint64_t block_size = track.handle->ext2->block_size; - const uint64_t size = (uint64_t)inode.i_size | ((uint64_t)inode.i_dir_acl << 32); - void* buffer; - while (*path && cntrl != 2) { - path_len = path_entry_len(path); +static void ext2_close_dir(struct file_handle_t* handle) { + struct ext2_inode_handle_t* inode_handle = (struct ext2_inode_handle_t*)handle; - if (get_inode(track.handle, &inode)) { - return 0; - } + inode_handle->seek = 0; + inode_handle->seek_block = 0; + inode_handle->ext2_mode &= ~MODE_DIR; +} - track.inode = &inode; - track.block = 0; - track.off = 0; +static enum file_status_t ext2_read_dir(struct file_handle_t* handle, struct dir_info_t* info) { + struct ext2_inode_handle_t* inode_handle = (struct ext2_inode_handle_t*)handle; + struct ext2_inode_t inode; - cntrl = 1; - while (cntrl == 1) { - if (track.block * block_size > size) { - cntrl = 2; - break; - } + if (!(inode_handle->ext2_mode & MODE_DIR)) { + return FILE_BAD_MODE; + } - if (track.off >= block_size) { - track.block++; - track.off = 0; - } + if (get_inode(inode_handle, &inode)) { + return FILE_ERROR; + } - switch (get_block_index(&track, &block_index)) { - case BLOCK_OK: - buffer = read_block(block_index, track.handle->ext2); - if (!buffer) { - kfree(track.handle); - return 0; - } + const uint64_t size = (uint64_t)inode.i_size | ((uint64_t)inode.i_dir_acl << 32); + uint64_t block; + + while (1) { + info->seek_pos = ext2_get_seek(handle); - struct ext2_ll_dir_entry_t* entry = (struct ext2_ll_dir_entry_t*)((uint64_t)buffer + track.off); + if (info->seek_pos >= size) { + return FILE_DNE; + } - if (entry->inode != 0) { - if (entry->name_len == path_len && !kmemcmp(entry->name, path, path_len)) { - path += path_len; + switch (get_block(inode_handle->ext2, &inode, inode_handle->seek_block, &block)) { + case BLOCK_OK: + void* buffer = read_block(block, inode_handle->ext2); - // handle non EOS - if (*path == '/') { - path++; - } + if (!buffer) { + return FILE_ERROR; + } - track.handle->inode_index = entry->inode; + struct ext2_ll_dir_entry_t* entry = (struct ext2_ll_dir_entry_t*)((uint64_t)buffer + inode_handle->seek); - if (*path && entry->file_type != EXT2_FT_DIR) { - cntrl = 2; // file not found - } - else { - cntrl = 0; - } + inode_handle->seek += entry->rec_len; + if (inode_handle->seek >= inode_handle->ext2->block_size) { + inode_handle->seek_block++; + inode_handle->seek = 0; + } - kfree(buffer); + if (entry->inode != 0) { + info->inode_num = entry->inode; + info->rec_len = entry->rec_len; + + switch (entry->file_type) { + case EXT2_FT_REG_FILE: + info->type = FILE_INFO_REG; + break; + case EXT2_FT_DIR: + info->type = FILE_INFO_DIR; + break; + default: + info->type = FILE_INFO_UNK; break; - } } - track.off += entry->rec_len; + kmemcpy(info->name, entry->name, entry->name_len); + info->name[entry->name_len] = 0; + kfree(buffer); - __attribute__((fallthrough)); - case BLOCK_RETRY: - continue; - case BLOCK_LAST: - cntrl = 2; // file not found - break; - case BLOCK_ERROR: - default: - kfree(track.handle); - return 0; - } + return FILE_OK; + } + + kfree(buffer); + continue; + case BLOCK_SPARSE: + inode_handle->seek_block++; + inode_handle->seek = 0; + continue; + case BLOCK_ERROR: + return FILE_ERROR; } } +} - if (*path || cntrl == 2) { - kfree(track.handle); // file not found - return 0; - } +static struct file_handle_t* ext2_open(struct mount_cntx_t* cntx, char* path) { + size_t path_len; + uint8_t cntrl = 0; - return (struct file_handle_t*)track.handle; -} + struct ext2_inode_handle_t* handle = kmalloc(sizeof(struct ext2_inode_handle_t)); + handle->ext2 = (struct ext2_t*)cntx; + handle->inode_index = EXT2_ROOT_INO; + handle->ext2_mode = 0; -static void ext2_close(struct file_handle_t* handle) { - kfree(handle); -} + struct dir_info_t info; -static enum file_status_t ext2_stat(struct file_handle_t* handle, struct file_info_t* info) { - struct ext2_inode_t inode; - struct ext2_inode_handle_t* inode_handle = (struct ext2_inode_handle_t*)handle; + while (*path) { + if (ext2_open_dir((struct file_handle_t*)handle) != FILE_OK) { + break; + } - if (!inode_handle || get_inode(inode_handle, &inode)) { - return FILE_ERROR; - } + path_len = path_entry_len(path); - if (inode.i_mode & EXT2_S_IFREG) { - info->type = FILE_TYPE_REG; - } - else if (inode.i_mode & EXT2_S_IFDIR) { - info->type = FILE_TYPE_DIR; - } - else { - return FILE_NO_SUPPORT; + cntrl = 1; + while (ext2_read_dir((struct file_handle_t*)handle, &info) == FILE_OK) { + if (path_len == kstrlen(info.name) && kmemcmp(path, info.name, path_len) == 0) { + cntrl = 0; + ext2_close_dir((struct file_handle_t*)handle); + handle->inode_index = info.inode_num; + break; + } + } + + if (cntrl) { + break; // file not found + } + + path += path_len; + + // handle non EOS + if (*path == '/') { + path++; + } } - info->size = (uint64_t)inode.i_size | ((uint64_t)inode.i_dir_acl << 32); + ext2_close_dir((struct file_handle_t*)handle); - return FILE_OK; -} + if (*path) { + // file not found + kfree(handle); + return 0; + } -static uint64_t ext2_get_seek(struct file_handle_t* handle) { - struct ext2_inode_handle_t* inode_handle = (struct ext2_inode_handle_t*)handle; - const uint64_t block_size = inode_handle->ext2->block_size; + return (struct file_handle_t*)handle; +} - return inode_handle->seek_block * block_size + inode_handle->seek; +static void ext2_close(struct file_handle_t* handle) { + kfree(handle); } static size_t ext2_read(struct file_handle_t* handle, void* buffer, size_t count) { struct ext2_inode_t inode; struct ext2_inode_handle_t* inode_handle = (struct ext2_inode_handle_t*)handle; - struct ext2_block_track_t track; uint8_t* block_buffer = 0; + uint64_t block; if (!inode_handle || get_inode(inode_handle, &inode)) { return 0; @@ -547,21 +626,13 @@ static size_t ext2_read(struct file_handle_t* handle, void* buffer, size_t count const uint64_t block_size = inode_handle->ext2->block_size; size_t read = 0; - uint64_t index; uint64_t write_seek = 0; size_t write_len; uint64_t full_seek = ext2_get_seek(handle); - if (full_seek > size) { - return 0; - } while (count) { - track.block = inode_handle->seek_block; - track.inode = &inode; - track.handle = inode_handle; - - if (track.block * block_size > size) { + if (full_seek > size) { break; } @@ -577,9 +648,9 @@ static size_t ext2_read(struct file_handle_t* handle, void* buffer, size_t count write_len = block_size - inode_handle->seek; } - switch (get_block_index(&track, &index)) { + switch (get_block(inode_handle->ext2, &inode, inode_handle->seek_block, &block)) { case BLOCK_OK: - block_buffer = read_block(index, inode_handle->ext2); + block_buffer = read_block(block, inode_handle->ext2); if (!block_buffer) { return read; @@ -595,10 +666,10 @@ static size_t ext2_read(struct file_handle_t* handle, void* buffer, size_t count kfree(block_buffer); break; - case BLOCK_RETRY: + case BLOCK_SPARSE: kmemset((uint8_t*)buffer + write_seek, 0, write_len); break; - default: + case BLOCK_ERROR: return read; } @@ -661,21 +732,6 @@ static void ext2_delete_final(struct file_handle_t* handle) { (void)handle; } -static enum file_status_t ext2_open_dir(struct file_handle_t* handle) { - (void)handle; - return FILE_NO_SUPPORT; -} - -static void ext2_close_dir(struct file_handle_t* handle) { - (void)handle; -} - -static enum file_status_t ext2_read_dir(struct file_handle_t* handle, struct dir_info_t* info) { - (void)handle; - (void)info; - return FILE_NO_SUPPORT; -} - static enum file_status_t ext2_create_dir(struct file_handle_t* handle, const char* name) { (void)handle; (void)name; diff --git a/kernel/core/elf.c b/kernel/core/elf.c index ba01228..a9e438d 100644 --- a/kernel/core/elf.c +++ b/kernel/core/elf.c @@ -539,9 +539,9 @@ struct pcb_t* elf_load(struct fs_handle_t* file, uint64_t pid, const char* invok kmemset(pcb->fd_table, 0, sizeof(struct fs_handle_t*) * MAX_FD); - pcb->fd_table[0] = fs_open("/dev/ttyS0"); - pcb->fd_table[1] = fs_open("/dev/ttyS0"); - pcb->fd_table[2] = fs_open("/dev/ttyS0"); + pcb->fd_table[0] = fs_open("/dev/ttyS0", FILE_MODE_READ); + pcb->fd_table[1] = fs_open("/dev/ttyS0", FILE_MODE_WRITE); + pcb->fd_table[2] = fs_open("/dev/ttyS0", FILE_MODE_WRITE); restore_cr3: diff --git a/kernel/core/fs.c b/kernel/core/fs.c index 7208b45..05bb687 100644 --- a/kernel/core/fs.c +++ b/kernel/core/fs.c @@ -72,6 +72,7 @@ struct vfs_mount_t { fs_read_dir_t read_dir; fs_create_dir_t create_dir; fs_delete_dir_t delete_dir; + fs_is_interactive_t is_interactive; }; struct vfs_open_file_t { @@ -86,6 +87,7 @@ struct fs_handle_t { struct vfs_mount_t* mount; struct file_handle_t* handle; struct vfs_open_file_t* shared; + uint8_t mode; }; struct vfs_tree_node_t { @@ -116,9 +118,15 @@ static struct vfs_mount_t dev_mount = { .delete_final = devfs_delete_final, .open_dir = devfs_open_dir, .close_dir = devfs_close_dir, - .read_dir = devfs_read_dir + .read_dir = devfs_read_dir, + .is_interactive = devfs_is_interactive }; +static uint8_t fs_not_interactive(struct file_handle_t* handle) { + (void)handle; + return 0; +} + static inline char* path_next(char* path, size_t* len) { *len = 0; @@ -240,6 +248,8 @@ enum file_status_t fs_mount( vfs_root.mount->create_dir = create_dir; vfs_root.mount->delete_dir = delete_dir; + vfs_root.mount->is_interactive = fs_not_interactive; + return FILE_OK; } @@ -336,7 +346,7 @@ static char* find_mount(const char* path, struct vfs_mount_t** mount_out, void** return mount_path; } -struct fs_handle_t* fs_open(const char* path) { +struct fs_handle_t* fs_open(const char* path, uint8_t mode) { struct vfs_mount_t* mount; void* clean_path; char* path_write; @@ -363,6 +373,7 @@ struct fs_handle_t* fs_open(const char* path) { fs_handle->handle = handle; fs_handle->mount = mount; fs_handle->shared = open_file; + fs_handle->mode = mode; return fs_handle; } @@ -394,6 +405,10 @@ enum file_status_t fs_stat(struct fs_handle_t* handle, struct file_info_t* info) size_t fs_read(struct fs_handle_t* handle, void* buffer, size_t count) { size_t ret; + if (!(handle->mode & FILE_MODE_READ)) { + return 0; + } + lock_acquire(&handle->shared->lock); ret = handle->mount->read(handle->handle, buffer, count); lock_release(&handle->shared->lock); @@ -424,6 +439,10 @@ enum file_status_t fs_seek(struct fs_handle_t* handle, uint64_t seek) { size_t fs_write(struct fs_handle_t* handle, void* buffer, size_t count) { size_t ret; + if (!(handle->mode & FILE_MODE_WRITE)) { + return 0; + } + lock_release(&handle->shared->lock); ret = handle->mount->write(handle->handle, buffer, count); lock_release(&handle->shared->lock); @@ -502,3 +521,7 @@ enum file_status_t fs_delete_dir(struct fs_handle_t* handle) { return sts; } + +uint8_t fs_is_interactive(struct fs_handle_t* handle) { + return handle->mount->is_interactive(handle->handle); +} diff --git a/kernel/core/kentry.c b/kernel/core/kentry.c index a98aef4..1185aa0 100644 --- a/kernel/core/kentry.c +++ b/kernel/core/kentry.c @@ -203,7 +203,7 @@ void prepare_userland(void* cntx) { init_done = 1; lock_release(&prepare_userland_lock); - struct fs_handle_t* shell = fs_open("/bin/shell"); + struct fs_handle_t* shell = fs_open("/bin/shell", FILE_MODE_READ); if (!shell) { logging_log_error("Failed to open shell file"); } diff --git a/kernel/core/process.c b/kernel/core/process.c index 0717354..991bccf 100644 --- a/kernel/core/process.c +++ b/kernel/core/process.c @@ -128,9 +128,9 @@ struct pcb_t* process_from_vaddr(uint64_t vaddr) { kmemset(pcb->fd_table, 0, sizeof(struct fs_handle_t*) * MAX_FD); - pcb->fd_table[0] = fs_open("/dev/ttyS0"); - pcb->fd_table[1] = fs_open("/dev/ttyS0"); - pcb->fd_table[2] = fs_open("/dev/ttyS0"); + pcb->fd_table[0] = fs_open("/dev/ttyS0", FILE_MODE_READ); + pcb->fd_table[1] = fs_open("/dev/ttyS0", FILE_MODE_WRITE); + pcb->fd_table[2] = fs_open("/dev/ttyS0", FILE_MODE_WRITE); return pcb; } diff --git a/kernel/core/syscall.S b/kernel/core/syscall.S index 77d5588..b620702 100644 --- a/kernel/core/syscall.S +++ b/kernel/core/syscall.S @@ -79,6 +79,7 @@ syscall_handlers: .quad syscall_dispatch_create_dir .quad syscall_dispatch_delete_dir .quad syscall_dispatch_epoch_time +.quad syscall_dispatch_is_a_tty .set num_entries, . - syscall_handlers .if num_entries != SYSCALL_MAX * 8 diff --git a/kernel/core/syscall_dispatch.c b/kernel/core/syscall_dispatch.c index 521c4ae..c16ddde 100644 --- a/kernel/core/syscall_dispatch.c +++ b/kernel/core/syscall_dispatch.c @@ -76,14 +76,14 @@ DECLARE_SYSCALL(exit) { } DECLARE_SYSCALL(open) { - ARGC_1; + ARGC_2; int fd; struct pcb_t* pcb = proc_data_get()->current_process; for (fd = 0; fd < MAX_FD; fd++) { if (!pcb->fd_table[fd]) { - pcb->fd_table[fd] = fs_open((const char*)arg1); + pcb->fd_table[fd] = fs_open((const char*)arg1, (uint8_t)arg2); if (!pcb->fd_table[fd]) { return SYSCALL_STS_FAIL; } @@ -290,3 +290,16 @@ DECLARE_SYSCALL(epoch_time) { return time_since_init_ns(); } + +DECLARE_SYSCALL(is_a_tty) { + ARGC_1; + + struct pcb_t* pcb = proc_data_get()->current_process; + struct fs_handle_t* handle = pcb->fd_table[arg1]; + + if (!handle) { + return SYSCALL_STS_FAIL; + } + + return fs_is_interactive(handle); +} diff --git a/kernel/devfs/devfs.c b/kernel/devfs/devfs.c index e970f72..29888fc 100644 --- a/kernel/devfs/devfs.c +++ b/kernel/devfs/devfs.c @@ -27,12 +27,12 @@ #include struct dev_handle_t { - enum { - DEV_TYPE_TTY - } type; union { struct tty_handle_t* tty; } dev_handle; + enum { + DEV_TYPE_TTY + } type; }; struct file_handle_t* devfs_open(struct mount_cntx_t* cntx, char* path) { @@ -185,3 +185,16 @@ enum file_status_t devfs_delete_dir(struct file_handle_t* handle) { return FILE_NO_SUPPORT; } + +uint8_t devfs_is_interactive(struct file_handle_t* handle) { + struct dev_handle_t* dev_handle = (struct dev_handle_t*)handle; + + if (!dev_handle) { + return FILE_ERROR; + } + + switch (dev_handle->type) { + case DEV_TYPE_TTY: + return 1; + } +} diff --git a/kernel/include/core/fs.h b/kernel/include/core/fs.h index 84484b4..681f53b 100644 --- a/kernel/include/core/fs.h +++ b/kernel/include/core/fs.h @@ -21,6 +21,13 @@ #include #include +#define FILE_MODE_READ 0x1 +#define FILE_MODE_WRITE 0x2 + +#define FILE_INFO_UNK 0 +#define FILE_INFO_REG 1 +#define FILE_INFO_DIR 2 + struct mount_cntx_t; struct file_handle_t; @@ -32,7 +39,9 @@ enum file_status_t { FILE_ERROR, FILE_DNE, FILE_BUSY, - FILE_NO_SUPPORT + FILE_NO_SUPPORT, + FILE_BAD_MODE, + FILE_NOT_DIR, }; struct file_info_t { @@ -45,7 +54,11 @@ struct file_info_t { }; struct dir_info_t { - const char* name; + uint64_t inode_num; + uint64_t seek_pos; + uint16_t rec_len; + uint8_t type; + char name[256]; }; typedef struct file_handle_t* (*fs_open_t)(struct mount_cntx_t*, char*); @@ -68,6 +81,8 @@ typedef enum file_status_t (*fs_read_dir_t)(struct file_handle_t*, struct dir_in typedef enum file_status_t (*fs_create_dir_t)(struct file_handle_t*, const char*); typedef enum file_status_t (*fs_delete_dir_t)(struct file_handle_t*); +typedef uint8_t (*fs_is_interactive_t)(struct file_handle_t*); + void fs_init(void); enum file_status_t fs_mount( @@ -90,7 +105,7 @@ enum file_status_t fs_mount( fs_delete_dir_t delete_dir ); -extern struct fs_handle_t* fs_open(const char* path); +extern struct fs_handle_t* fs_open(const char* path, uint8_t mode); extern void fs_close(struct fs_handle_t* handle); extern enum file_status_t fs_stat(struct fs_handle_t* handle, struct file_info_t* info); @@ -109,4 +124,6 @@ extern enum file_status_t fs_read_dir(struct fs_handle_t* handle, struct dir_inf extern enum file_status_t fs_create_dir(struct fs_handle_t* handle, const char* name); extern enum file_status_t fs_delete_dir(struct fs_handle_t* handle); +extern uint8_t fs_is_interactive(struct fs_handle_t* handle); + #endif /* KERNEL_CORE_FS_H */ diff --git a/kernel/include/core/syscall_dispatch.h b/kernel/include/core/syscall_dispatch.h index ac50bd0..09fc287 100644 --- a/kernel/include/core/syscall_dispatch.h +++ b/kernel/include/core/syscall_dispatch.h @@ -58,5 +58,6 @@ extern DECLARE_SYSCALL(tell); extern DECLARE_SYSCALL(create_dir); extern DECLARE_SYSCALL(delete_dir); extern DECLARE_SYSCALL(epoch_time); +extern DECLARE_SYSCALL(is_a_tty); #endif /* KERNEL_CORE_SYSCALL_DISPATCH_H */ diff --git a/kernel/include/core/syscall_vectors.h b/kernel/include/core/syscall_vectors.h index f7b0c3c..005daa6 100644 --- a/kernel/include/core/syscall_vectors.h +++ b/kernel/include/core/syscall_vectors.h @@ -43,6 +43,7 @@ /* * rdi: path (const char*) + * rsi: mode (uint8_t) * ret: handle (int) */ #define SYSCALL_OPEN 1 @@ -136,8 +137,14 @@ /* * ret: time since epoch in nanos (long int) */ -#define SYSCALL_EPOCH_TIME 15 +#define SYSCALL_EPOCH_TIME 15 -#define SYSCALL_MAX 16 +/* + * rdi: handle (int) + * ret: 1 on tty. 0 otherwise + */ +#define SYSCALL_IS_A_TTY 16 + +#define SYSCALL_MAX 17 diff --git a/kernel/include/devfs/devfs.h b/kernel/include/devfs/devfs.h index f01c4fe..68244bc 100644 --- a/kernel/include/devfs/devfs.h +++ b/kernel/include/devfs/devfs.h @@ -43,4 +43,6 @@ extern enum file_status_t devfs_read_dir(struct file_handle_t* handle, struct di extern enum file_status_t devfs_create_dir(struct file_handle_t* handle, const char* name); extern enum file_status_t devfs_delete_dir(struct file_handle_t* handle); +extern uint8_t devfs_is_interactive(struct file_handle_t* handle); + #endif /* KERNEL_DEVFS_DEVFS_H */ diff --git a/userland/mlibc-patch/abis/modulos/fcntl.h b/userland/mlibc-patch/abis/modulos/fcntl.h index 4e7eb2e..058957f 100644 --- a/userland/mlibc-patch/abis/modulos/fcntl.h +++ b/userland/mlibc-patch/abis/modulos/fcntl.h @@ -6,10 +6,10 @@ #define O_PATH 010000000 -#define O_ACCMODE (03 | O_PATH) -#define O_RDONLY 00 -#define O_WRONLY 01 -#define O_RDWR 02 +#define O_ACCMODE (0x03) +#define O_RDONLY 0x1 +#define O_WRONLY 0x2 +#define O_RDWR 0x3 #define O_CREAT 0100 #define O_EXCL 0200 diff --git a/userland/mlibc-patch/abis/modulos/mode_t.h b/userland/mlibc-patch/abis/modulos/mode_t.h index b00bb97..2e00d6f 100644 --- a/userland/mlibc-patch/abis/modulos/mode_t.h +++ b/userland/mlibc-patch/abis/modulos/mode_t.h @@ -1,6 +1,8 @@ #ifndef _ABIBITS_MODE_T_H #define _ABIBITS_MODE_T_H +#include + typedef unsigned int mode_t; #endif /* _ABIBITS_MODE_T_H */ diff --git a/userland/mlibc-patch/sysdeps/modulos/sysdeps.cpp b/userland/mlibc-patch/sysdeps/modulos/sysdeps.cpp index 15b7ad9..5bb59d0 100644 --- a/userland/mlibc-patch/sysdeps/modulos/sysdeps.cpp +++ b/userland/mlibc-patch/sysdeps/modulos/sysdeps.cpp @@ -87,10 +87,9 @@ int sys_anon_free(void *pointer, size_t size) { } int sys_open(const char *pathname, int flags, mode_t mode, int *fd) { - (void)flags; (void)mode; - int f = syscall_1((uint64_t)pathname, 0, 0, SYSCALL_OPEN); + int f = syscall_1((uint64_t)pathname, flags, 0, SYSCALL_OPEN); if (!f) { return 1; } @@ -156,14 +155,11 @@ int sys_write(int fd, const void *buf, size_t count, ssize_t *bytes_written) { } int sys_isatty(int fd) { - switch (fd) { - case stdout: - case stdin: - case stderr: - return 0; //mlibc expects 0 for tty - default: - return ENOTTY; + if (syscall_1(fd, 0, 0, SYSCALL_IS_A_TTY)) { + return 0; //mlibc expects 0 for tty } + + return ENOTTY; } int sys_clock_get(int clock, time_t *secs, long *nanos) { From 8e13f0f50c05407ee73fd883adc4ed4154bc148c Mon Sep 17 00:00:00 2001 From: Ebrahim Aleem Date: Wed, 6 May 2026 13:10:40 -0700 Subject: [PATCH 09/13] added scan-build static analysis --- boot/multiboot2/init.c | 12 +++++------ drivers/ahci/ahci.c | 10 +++++++-- drivers/disk/disk.c | 2 +- drivers/ext2/ext2.c | 8 ++++---- drivers/hpet/hpet_init.c | 6 +++--- drivers/include/pcie/pcie.h | 2 ++ drivers/pcie/pcie_init.c | 2 +- drivers/serial/interrupts.c | 3 --- drivers/serial/serial_print.c | 2 +- kernel/acpi/tables.c | 34 +++++++++++++++---------------- kernel/apic/apic_init.c | 4 ++-- kernel/apic/ipi.c | 2 +- kernel/core/alloc.c | 2 +- kernel/core/elf.c | 4 ++-- kernel/core/fs.c | 14 ++++++------- kernel/core/idt.c | 6 +++--- kernel/core/kentry.c | 2 +- kernel/core/logging.c | 4 ++-- kernel/core/mm.c | 12 +++++------ kernel/core/paging.c | 5 ++++- kernel/core/scheduler.c | 8 ++------ kernel/core/signal.c | 2 +- kernel/core/tss.c | 4 ++-- kernel/devfs/tty.c | 4 ++-- kernel/graphicsbase/framebuffer.c | 6 +++--- kernel/include/acpi/tables.h | 8 ++++---- kernel/include/apic/apic_init.h | 14 +++++++++++++ kernel/include/core/clock_src.h | 6 +++--- kernel/include/core/kentry.h | 2 +- kernel/include/core/proc_data.h | 2 +- kernel/include/core/tss.h | 2 +- kernel/lib/hash.c | 2 +- scripts/Makefile.kcflags | 8 ++++---- scripts/gen_compile_commands | 3 +++ scripts/scan_build | 5 +++++ test/helpers/main.c | 2 +- test/include/macros.h | 32 +++++++++++++++++------------ test/lib/test.c | 2 +- test/testsuite/test.c | 2 +- 39 files changed, 141 insertions(+), 109 deletions(-) create mode 100755 scripts/gen_compile_commands create mode 100755 scripts/scan_build diff --git a/boot/multiboot2/init.c b/boot/multiboot2/init.c index b53a244..9aae077 100644 --- a/boot/multiboot2/init.c +++ b/boot/multiboot2/init.c @@ -72,7 +72,7 @@ struct mb2_tag_t { struct { struct acpi_rsdp_t rsdp; - } __attribute__((packed)) rsdpv2; + } rsdpv2; #ifdef GRAPHICSBASE struct { @@ -91,8 +91,8 @@ struct mb2_tag_t { uint8_t framebuffer_green_mask_size; uint8_t framebuffer_blue_field_position; uint8_t framebuffer_blue_mask_size; - } __attribute__((packed)) rgb; - } __attribute__((packed)) color_info; + } rgb; + } color_info; } __attribute__((packed)) framebuffer; #endif /* GRAPHICSBASE */ } tag; @@ -101,11 +101,11 @@ struct mb2_tag_t { struct mb2_info_t { const uint32_t total_size; const uint32_t reserved; -} __attribute__((packed)) header; +} __attribute__((packed)); -extern volatile struct gdt_t gdt[GDT_NUM_ENTRIES]; +extern struct gdt_t gdt[GDT_NUM_ENTRIES]; -static volatile struct mb2_tag_t* memmap_tag; +static struct mb2_tag_t* memmap_tag; extern uint64_t init_stack_paddr; extern uint64_t init_stack_vaddr; diff --git a/drivers/ahci/ahci.c b/drivers/ahci/ahci.c index e53286c..bfaf088 100644 --- a/drivers/ahci/ahci.c +++ b/drivers/ahci/ahci.c @@ -494,7 +494,7 @@ static enum disk_error_t ahci_flush_cache(void* cntx) { static void port_identify(struct ahci_t* ahci, uint32_t port) { uint8_t slot; uint32_t paddr_identity; - volatile uint16_t* identity; + uint16_t* identity; uint8_t model[41]; paddr_identity = (uint32_t)mm_alloc_pmax(PAGE_SIZE_4K, 0, ~0u); @@ -515,12 +515,18 @@ static void port_identify(struct ahci_t* ahci, uint32_t port) { lock_acquire(&ahci->lock); slot = find_slot(ahci, port); + + if (slot == SLOT_NO_SLOT) { + logging_log_error("No available slots for identification"); + panic(PANIC_STATE); + } + ahci->used_com |= 1u << slot; lock_release(&ahci->lock); kmemset(&ahci->ports[port]->com_list[slot], 0, sizeof(struct ahci_command_header_t)); kmemset(ahci->com_tables_v[slot], 0, PAGE_SIZE_4K); - kmemset((void*)identity, 0, PAGE_SIZE_4K); + kmemset(identity, 0, PAGE_SIZE_4K); ahci->com_tables_v[slot]->prdt[0].dba = paddr_identity; ahci->com_tables_v[slot]->prdt[0].dbau = 0; diff --git a/drivers/disk/disk.c b/drivers/disk/disk.c index b438e65..1f241c2 100644 --- a/drivers/disk/disk.c +++ b/drivers/disk/disk.c @@ -36,7 +36,7 @@ struct disk_t { struct disk_t* next; }; -uint8_t disk_lock; +static uint8_t disk_lock; static struct disk_t* disk_list; static uint64_t disk_id; diff --git a/drivers/ext2/ext2.c b/drivers/ext2/ext2.c index b05953d..31a3b66 100644 --- a/drivers/ext2/ext2.c +++ b/drivers/ext2/ext2.c @@ -266,15 +266,13 @@ static uint8_t set_inode(const struct ext2_inode_handle_t* inode_handle, struct if (!buffer) { logging_log_error("Failed to read inode %lu", inode_handle->inode_index); - kfree(buffer); return 1; } *(struct ext2_inode_t*)((uint64_t)buffer + inode_off) = *inode; - if (!write_block(inode_table_block, inode_handle->ext2, buffer)) { + if (!(buffer = write_block(inode_table_block, inode_handle->ext2, buffer))) { logging_log_error("Failed to write inode %lu", inode_handle->inode_index); - kfree(buffer); return 1; } @@ -463,7 +461,9 @@ static enum file_status_t ext2_open_dir(struct file_handle_t* handle) { struct ext2_inode_handle_t* inode_handle = (struct ext2_inode_handle_t*)handle; struct file_info_t info; - ext2_stat(handle, &info); + if (ext2_stat(handle, &info) != FILE_OK) { + return FILE_ERROR; + } if (info.type != FILE_TYPE_DIR) { return FILE_NOT_DIR; diff --git a/drivers/hpet/hpet_init.c b/drivers/hpet/hpet_init.c index d28bf02..e813c6f 100644 --- a/drivers/hpet/hpet_init.c +++ b/drivers/hpet/hpet_init.c @@ -54,13 +54,13 @@ static volatile struct hpet_group_t { struct hpet_timer_t timers[32]; } __attribute__((packed))* hpet_reg_bases[8]; -static uint64_t hpet_get_counter(void* meta) { +static uint64_t hpet_get_counter(volatile void* meta) { volatile struct hpet_group_t* hpet = meta; const uint64_t ret = hpet->counter; return ret; } -static void hpet_set_counter(void* meta, uint64_t counter) { +static void hpet_set_counter(volatile void* meta, uint64_t counter) { volatile struct hpet_group_t* hpet = meta; hpet->gen_conf &= ~(uint64_t)HPET_GROUP_ENA; hpet->counter = counter; @@ -104,7 +104,7 @@ void hpet_init(void) { clock = kmalloc(sizeof(struct clock_src_t)); clock->counter = hpet_get_counter; clock->reset = hpet_set_counter; - clock->meta = (void*)hpet_reg_bases[i]; + clock->meta = hpet_reg_bases[i]; clock->period_fs = (hpet_reg_bases[i]->cap & HPET_PER) >> HPET_PER_SHF; clock_src_register(clock); diff --git a/drivers/include/pcie/pcie.h b/drivers/include/pcie/pcie.h index 6ee320f..cc0f0bd 100644 --- a/drivers/include/pcie/pcie.h +++ b/drivers/include/pcie/pcie.h @@ -38,6 +38,8 @@ #define PCI_BAR_BA_MAKS 0xFFFFE000 +extern uint64_t**** ecam; + extern uint32_t pcie_read(uint16_t segment, uint8_t bus, uint8_t dev, uint8_t fun, uint16_t off); extern void pcie_write(uint16_t segment, uint8_t bus, uint8_t dev, uint8_t fun, uint16_t off, uint32_t val); diff --git a/drivers/pcie/pcie_init.c b/drivers/pcie/pcie_init.c index 738c20b..8c9cb2c 100644 --- a/drivers/pcie/pcie_init.c +++ b/drivers/pcie/pcie_init.c @@ -46,7 +46,7 @@ #define PCI_BRIDGE_SEC_NUM(seg, bus, dev, func) (0xFF & (pcie_read(seg, bus, dev, func, 0x18) >> 8)) -#define DISABLE_INT(seg, bus, dev, func) pcie_write(seg, bus, dev, func, 0x4, pcie_read(seg, bus, dev, 0, 0x4) | 0x400); +#define DISABLE_INT(seg, bus, dev, func) pcie_write(seg, bus, dev, func, 0x4, pcie_read(seg, bus, dev, 0, 0x4) | 0x400) extern uint64_t**** ecam; diff --git a/drivers/serial/interrupts.c b/drivers/serial/interrupts.c index 03d5dcb..fae9540 100644 --- a/drivers/serial/interrupts.c +++ b/drivers/serial/interrupts.c @@ -42,9 +42,6 @@ #define DR_MASK 1 -struct signal_wait_t* com1_signal; -struct signal_wait_t* com2_signal; - void serial_init_interrupts(void) { uint8_t com1_v = idt_get_vector(); uint8_t com2_v = idt_get_vector(); diff --git a/drivers/serial/serial_print.c b/drivers/serial/serial_print.c index e96452a..23f390c 100644 --- a/drivers/serial/serial_print.c +++ b/drivers/serial/serial_print.c @@ -241,7 +241,7 @@ void serial_log(enum log_severity_t severity, const char* s, va_list args) { serial_printf(s, serial_com12, args); serial_print("\r\n", serial_com12); break; - default: + case SEVERITY_NON: serial_printf(s, serial_com12, args); break; } diff --git a/kernel/acpi/tables.c b/kernel/acpi/tables.c index 6689a8e..4c530f8 100644 --- a/kernel/acpi/tables.c +++ b/kernel/acpi/tables.c @@ -233,24 +233,24 @@ static uint8_t hpet_count; #define CHECK_AND_COPY(sig, tbl, store, fnd, post) \ do { \ - if (!kmemcmp((uint8_t*)gen->Signature, sig, 4)) { \ + if (!kmemcmp(gen->Signature, sig, 4)) { \ logging_log_info("Copying ACPI " tbl " @ 0x%lX", (uint64_t)gen); \ store = kmalloc(gen->Length); \ - kmemcpy((void*)store, (void*)gen, gen->Length); \ + kmemcpy(store, gen, gen->Length); \ found |= fnd; \ post; \ } \ } \ while (0) -static inline uint8_t verify_checksum(const volatile struct acpi_gen_header_t* table) { - const volatile struct acpi_gen_header_t* gen = (struct acpi_gen_header_t*)table; - return hash_byte_sum((void*)gen, gen->Length); +static inline uint8_t verify_checksum(const struct acpi_gen_header_t* table) { + const struct acpi_gen_header_t* gen = (const struct acpi_gen_header_t*)table; + return hash_byte_sum(gen, gen->Length); } -static volatile void* map_table(const volatile void* table) { +static void* map_table(const void* table) { uint64_t base = (uint64_t)table & PAGE_BASE_MASK, vaddr, len, off; - volatile struct acpi_gen_header_t* v_table; + struct acpi_gen_header_t* v_table; vaddr = mm_alloc_v(PAGE_SIZE_4K * 2); if (!vaddr) { @@ -261,7 +261,7 @@ static volatile void* map_table(const volatile void* table) { paging_map(vaddr, base, PAGE_PRESENT | PAGE_RW | PAT_MMIO_4K, PAGE_4K); paging_map(vaddr + PAGE_SIZE_4K, base + PAGE_SIZE_4K, PAGE_PRESENT | PAGE_RW | PAT_MMIO_4K, PAGE_4K); - v_table = (volatile struct acpi_gen_header_t*)(vaddr + (uint64_t)table - base); + v_table = (struct acpi_gen_header_t*)(vaddr + (uint64_t)table - base); if (!vaddr) { logging_log_error("Failed to allocate memory for ACPI table"); panic(PANIC_NO_MEM); @@ -293,8 +293,8 @@ static volatile void* map_table(const volatile void* table) { return (void*)(vaddr + (uint64_t)table - base); } -static void unmap_table(const volatile void* table) { - volatile struct acpi_gen_header_t* v_table = (volatile struct acpi_gen_header_t*)table; +static void unmap_table(const void* table) { + const struct acpi_gen_header_t* v_table = (const struct acpi_gen_header_t*)table; uint64_t base, len, off; base = (uint64_t)table & PAGE_BASE_MASK; @@ -312,7 +312,7 @@ void acpi_copy_tables(void) { hpet_count = 0; #endif /* HPET */ - const volatile struct acpi_gen_header_t* gen; + const struct acpi_gen_header_t* gen; uint8_t found; if (kmemcmp(boot_context.rsdp.Signature, "RSD PTR ", 8)) { @@ -329,7 +329,7 @@ void acpi_copy_tables(void) { case RSDPV1: fallback: found = 0; - volatile struct acpi_rsdt_t* rsdt = (volatile struct acpi_rsdt_t*)(uint64_t)boot_context.rsdp.RsdtAddress; + struct acpi_rsdt_t* rsdt = (struct acpi_rsdt_t*)(uint64_t)boot_context.rsdp.RsdtAddress; rsdt = map_table(rsdt); if (!rsdt) { logging_log_error("Bad RSDT checksum"); @@ -343,9 +343,9 @@ void acpi_copy_tables(void) { logging_log_info("Parsing ACPI RSDT entries @ 0x%lX", (uint64_t)&rsdt->Entry[0]); - for (const volatile uint32_t* entry = &rsdt->Entry[0]; + for (const uint32_t* entry = &rsdt->Entry[0]; (uint64_t)entry < (uint64_t)rsdt + rsdt->Length; entry++) { - gen = (const volatile struct acpi_gen_header_t*)(uint64_t)*entry; + gen = (const struct acpi_gen_header_t*)(uint64_t)*entry; gen = map_table(gen); if (!gen) { @@ -389,7 +389,7 @@ void acpi_copy_tables(void) { } found = 0; - volatile struct acpi_xsdt_t* xsdt = (volatile struct acpi_xsdt_t*)boot_context.rsdp.XsdtAddress; + struct acpi_xsdt_t* xsdt = (struct acpi_xsdt_t*)boot_context.rsdp.XsdtAddress; xsdt = map_table(xsdt); if (!xsdt) { @@ -404,9 +404,9 @@ void acpi_copy_tables(void) { logging_log_info("Parsing ACPI XSDT entries @ 0x%lX", (uint64_t)&xsdt->Entry[0]); - for (const volatile uint64_t* entry = &xsdt->Entry[0]; + for (const uint64_t* entry = &xsdt->Entry[0]; (uint64_t)entry < (uint64_t)xsdt + xsdt->Length; entry++) { - gen = (const volatile struct acpi_gen_header_t*)*entry; + gen = (const struct acpi_gen_header_t*)*entry; gen = map_table(gen); if (!gen) { diff --git a/kernel/apic/apic_init.c b/kernel/apic/apic_init.c index 85817b9..1f72f2a 100644 --- a/kernel/apic/apic_init.c +++ b/kernel/apic/apic_init.c @@ -99,8 +99,8 @@ extern uint8_t kernel_pml4; uint64_t* init_stacks_paddr; uint64_t* init_stacks_vaddr; -volatile struct gdt_t(** ap_gdts)[GDT_NUM_ENTRIES]; -volatile struct gdt_ptr_64_t** ap_gdt_ptr_64; +struct gdt_t(** ap_gdts)[GDT_NUM_ENTRIES]; +struct gdt_ptr_64_t** ap_gdt_ptr_64; uint8_t* ap_init_locks; void apic_init(void) { diff --git a/kernel/apic/ipi.c b/kernel/apic/ipi.c index 04b69b5..26cebe7 100644 --- a/kernel/apic/ipi.c +++ b/kernel/apic/ipi.c @@ -40,7 +40,7 @@ #define ICR_PID_SHFT 24 static uint8_t tlb_shootdown_vector; -uint8_t shootdown_enable = 0; +static uint8_t shootdown_enable = 0; struct shootdown_node_t { struct shootdown_node_t* next; diff --git a/kernel/core/alloc.c b/kernel/core/alloc.c index 78110bf..35e9d16 100644 --- a/kernel/core/alloc.c +++ b/kernel/core/alloc.c @@ -206,7 +206,7 @@ void* kmalloc(size_t size) { lock_acquire(&alloc_lock); i = i->next; lock_release(&alloc_lock); - }; + } // out of heap space, new arena arena_base = mm_alloc_p(ARENA_SIZE); diff --git a/kernel/core/elf.c b/kernel/core/elf.c index a9e438d..b0bcfa0 100644 --- a/kernel/core/elf.c +++ b/kernel/core/elf.c @@ -109,7 +109,7 @@ #define AT_EXECFN 31 #define AT_SYSINFO_EHDR 33 -enum { +enum at_index_t { AT_INDEX_PHDR, AT_INDEX_PHENT, AT_INDEX_PHNUM, @@ -123,7 +123,7 @@ enum { AT_INDEX_CLKTCK, AT_INDEX_NULL -} at_index_t; +}; typedef struct { int a_type; diff --git a/kernel/core/fs.c b/kernel/core/fs.c index 05bb687..4a25f4f 100644 --- a/kernel/core/fs.c +++ b/kernel/core/fs.c @@ -76,7 +76,7 @@ struct vfs_mount_t { }; struct vfs_open_file_t { - const char* path; + char* path; uint64_t refs; uint64_t key; uint8_t lock; @@ -158,7 +158,7 @@ static struct vfs_open_file_t* lookup_register(char* path) { file = kmalloc(sizeof(struct vfs_open_file_t)); file->path = kmalloc(kstrlen(path) + 1); - kstrcpy((char*)file->path, path); + kstrcpy(file->path, path); file->refs = 0; file->key = key; @@ -180,11 +180,13 @@ static uint8_t lookup_close(struct vfs_open_file_t* file) { return 0; } - kfree((char*)file->path); + kfree(file->path); hash_table_remove(open_table, file->key); + uint8_t pending_delete = file->pending_delete; + kfree(file); - return 1; + return pending_delete; } void fs_init(void) { @@ -380,9 +382,7 @@ struct fs_handle_t* fs_open(const char* path, uint8_t mode) { void fs_close(struct fs_handle_t* handle) { semaphore_wait_full(fs_sem); if (lookup_close(handle->shared)) { - if (handle->shared->pending_delete) { - handle->mount->delete_final(handle->handle); - } + handle->mount->delete_final(handle->handle); } semaphore_signal_full(fs_sem); diff --git a/kernel/core/idt.c b/kernel/core/idt.c index 8785133..f85ead8 100644 --- a/kernel/core/idt.c +++ b/kernel/core/idt.c @@ -40,12 +40,12 @@ struct idt_ptr_t { uint64_t base; } __attribute__((packed)); -static volatile struct idt_entry_t idt[IDT_MAX_ENTRY] __attribute__((aligned(64))); -static volatile struct idt_ptr_t idt_ptr; +static struct idt_entry_t idt[IDT_MAX_ENTRY] __attribute__((aligned(64))); +static struct idt_ptr_t idt_ptr; static uint8_t next_vector; void idt_init(void) { - kmemset((void*)&idt[0], 0, sizeof(idt)); + kmemset(&idt[0], 0, sizeof(idt)); idt_install(0x00, (uint64_t)isr_00, GDT_CODE_SEL, 0, IDT_GATE_TRP, 0); idt_install(0x01, (uint64_t)isr_01, GDT_CODE_SEL, 0, IDT_GATE_TRP, 0); diff --git a/kernel/core/kentry.c b/kernel/core/kentry.c index 1185aa0..31bd91a 100644 --- a/kernel/core/kentry.c +++ b/kernel/core/kentry.c @@ -67,7 +67,7 @@ struct boot_context_t boot_context; extern uint8_t ap_bootstrap_start; extern uint64_t* init_stacks; extern uint8_t ap_bootstrap_end; -extern volatile struct gdt_t(** ap_gdts)[GDT_NUM_ENTRIES]; +extern struct gdt_t(** ap_gdts)[GDT_NUM_ENTRIES]; extern uint8_t* ap_init_locks; extern uint64_t init_stack_vaddr; diff --git a/kernel/core/logging.c b/kernel/core/logging.c index 6ee875d..a109b6d 100644 --- a/kernel/core/logging.c +++ b/kernel/core/logging.c @@ -26,7 +26,7 @@ static void (*loggers[MAX_LOGGER_OUT])(enum log_severity_t, const char* format, static uint64_t last_logger; static void log(enum log_severity_t severity, const char* format, va_list args) { - for (uint64_t i = 0 ; i < last_logger; i++) { + for (uint64_t i = 0 ; i < last_logger && i < MAX_LOGGER_OUT; i++) { loggers[i](severity, format, args); } } @@ -36,7 +36,7 @@ void logging_init(void) { } void logging_register(void (*logger)(enum log_severity_t, const char* format, va_list args)) { - loggers[last_logger++] = logger; + loggers[(last_logger++) % MAX_LOGGER_OUT] = logger; } void _logging_log_debug(const char* format, ...) { diff --git a/kernel/core/mm.c b/kernel/core/mm.c index 8ccdd63..35d7cd8 100644 --- a/kernel/core/mm.c +++ b/kernel/core/mm.c @@ -50,7 +50,7 @@ struct mm_tree_node_t { struct disarm_list_t { struct disarm_list_t* next; uint8_t id; - volatile uint8_t state; + uint8_t state; }; static struct mm_tree_node_t* p_tree; @@ -67,9 +67,9 @@ static uint8_t n_lock; static struct mm_tree_node_t node_pool[MAX_INIT_NODES]; static struct mm_tree_node_t* free_nodes; -static struct free_transaction_list_t* volatile pending_free; +static struct free_transaction_list_t* pending_free; static struct free_transaction_list_t* transaction_list; -uint8_t pending_free_lock; +static uint8_t pending_free_lock; static struct disarm_list_t* disarm_list; static struct signal_wait_t* free_pending_wait; @@ -429,12 +429,12 @@ void mm_free_p(uint64_t base, size_t size) { } void mm_free_v(uint64_t base, size_t size) { - volatile struct free_transaction_list_t* pending = kmalloc(sizeof(struct free_transaction_list_t)); + struct free_transaction_list_t* pending = kmalloc(sizeof(struct free_transaction_list_t)); pending->base = base; pending->size = size; lock_acquire(&pending_free_lock); pending->next = pending_free; - pending_free = (struct free_transaction_list_t* volatile)pending; + pending_free = (struct free_transaction_list_t*)pending; lock_release(&pending_free_lock); if (free_pending_wait) { @@ -442,7 +442,7 @@ void mm_free_v(uint64_t base, size_t size) { } } -static void free_all_pending(void* _ign) { +__attribute((noreturn)) static void free_all_pending(void* _ign) { (void)_ign; struct free_transaction_list_t* next; diff --git a/kernel/core/paging.c b/kernel/core/paging.c index 3320f7c..4113246 100644 --- a/kernel/core/paging.c +++ b/kernel/core/paging.c @@ -103,9 +103,12 @@ static uint64_t* increase_granularity(uint64_t vaddr, uint64_t* access, enum pag case PAGE_1G: access = &(access)[GET_PD_INDEX(vaddr)]; break; - default: + case PAGE_2M: access = &(access)[GET_PT_INDEX(vaddr)]; break; + case PAGE_4K: + logging_log_error("Invalid call to increase granularity"); + panic(PANIC_STATE); } } diff --git a/kernel/core/scheduler.c b/kernel/core/scheduler.c index 3aa044e..28c5af0 100644 --- a/kernel/core/scheduler.c +++ b/kernel/core/scheduler.c @@ -30,8 +30,8 @@ #include static uint8_t lock_sched; -static volatile struct pcb_t* active_queue; -static volatile struct pcb_t* active_queue_tail; +static struct pcb_t* active_queue; +static struct pcb_t* active_queue_tail; static struct pcb_t* sleep_queue; @@ -71,7 +71,6 @@ void scheduler_run(void) { cpu_cli(); apic_write_reg(APIC_REG_EOI, APIC_EOI); process_resume(current_pcb); - break; case SCHED_KILL: process_discard(current_pcb); break; @@ -93,9 +92,6 @@ void scheduler_run(void) { case SCHED_CALLBACK: current_pcb->sleep_state.callback(current_pcb); break; - default: - logging_log_error("Invalid scheduler code %u", current_pcb->sched_cntr); - __attribute__((fallthrough)); case SCHED_READY: case SCHED_SIGNAL_READY: scheduler_schedule(current_pcb); diff --git a/kernel/core/signal.c b/kernel/core/signal.c index e8a91cc..790976a 100644 --- a/kernel/core/signal.c +++ b/kernel/core/signal.c @@ -49,7 +49,7 @@ struct signal_wait_t* signal_wait_alloc(void) { } void signal_wait(struct signal_wait_t* wait) { - volatile struct pcb_t* current = proc_data_get()->current_process; + struct pcb_t* current = proc_data_get()->current_process; current->meta[0] = wait; process_set_callback(signal_wait_callback); diff --git a/kernel/core/tss.c b/kernel/core/tss.c index fdc1408..a446420 100644 --- a/kernel/core/tss.c +++ b/kernel/core/tss.c @@ -34,8 +34,8 @@ #define IST_LO_MASK 0xFFFFFFFF #define IST_HI_SHFT 32 -void tss_init(volatile struct gdt_t(* gdt)[GDT_NUM_ENTRIES]) { - volatile struct tss_t* tss = kmalloc(sizeof(struct tss_t)); +void tss_init(struct gdt_t(* gdt)[GDT_NUM_ENTRIES]) { + struct tss_t* tss = kmalloc(sizeof(struct tss_t)); kmemset((void*)tss, 0, sizeof(struct tss_t)); diff --git a/kernel/devfs/tty.c b/kernel/devfs/tty.c index 8ba73b4..64b0763 100644 --- a/kernel/devfs/tty.c +++ b/kernel/devfs/tty.c @@ -50,8 +50,8 @@ typedef void (*tty_write_t)(uint8_t byte); struct tty_handle_t { tty_write_t writer; uint8_t* read_buffer; - volatile uint16_t write_index; - volatile uint16_t read_index; + uint16_t write_index; + uint16_t read_index; struct signal_wait_t* signal; enum { TTY_MODE_COOKED, diff --git a/kernel/graphicsbase/framebuffer.c b/kernel/graphicsbase/framebuffer.c index 4268a15..8a5e720 100644 --- a/kernel/graphicsbase/framebuffer.c +++ b/kernel/graphicsbase/framebuffer.c @@ -25,7 +25,7 @@ static uint32_t convert_color(struct framebuffer_t* framebuffer, uint8_t r, uint switch (framebuffer->mode) { case VIDEO_RGB_XRGB8888: return ((uint32_t)r << 16) + ((uint32_t)g << 8) + (uint32_t)b; - default: + case VIDEO_NONE: return 0; } } @@ -34,8 +34,8 @@ void framebuffer_fillrect( struct framebuffer_t* framebuffer, uint32_t startx, uint32_t starty, uint32_t width, uint32_t height, uint8_t r, uint8_t g, uint8_t b) { - uint8_t* row = - (uint8_t*)(framebuffer->addr + starty * framebuffer->pitch + startx * BYTES_PER_PIXEL); + volatile uint8_t* row = + (volatile uint8_t*)(framebuffer->addr + starty * framebuffer->pitch + startx * BYTES_PER_PIXEL); volatile uint32_t* loc; uint32_t color = convert_color(framebuffer, r, g, b); diff --git a/kernel/include/acpi/tables.h b/kernel/include/acpi/tables.h index a1e4449..835458f 100644 --- a/kernel/include/acpi/tables.h +++ b/kernel/include/acpi/tables.h @@ -53,12 +53,12 @@ struct acpi_madt_ics_gen_t { uint8_t Type; uint8_t Length; uint8_t _[]; -} __attribute__((packed)); +}; struct acpi_madt_ics_mps_t { uint8_t PolarityAndTriggerMode; uint8_t Reserved; -} __attribute__((packed)); +}; struct acpi_madt_ics_local_apic_t { uint8_t Type; @@ -66,7 +66,7 @@ struct acpi_madt_ics_local_apic_t { uint8_t ACPIProcessorUID; uint8_t APICID; uint8_t Flags; -} __attribute__((packed)); +}; struct acpi_madt_ics_io_apic_t { uint8_t Type; @@ -99,7 +99,7 @@ struct acpi_madt_ics_local_apic_nmi_t { uint8_t ACPIProcessorUID; struct acpi_madt_ics_mps_t Flags; uint8_t LocalAPICLINTNum; -} __attribute__((packed)); +}; struct acpi_mcfg_conf_t { uint64_t base; diff --git a/kernel/include/apic/apic_init.h b/kernel/include/apic/apic_init.h index 2146ba7..15661bc 100644 --- a/kernel/include/apic/apic_init.h +++ b/kernel/include/apic/apic_init.h @@ -20,6 +20,20 @@ #include +#include + +extern uint64_t apic_base; +extern uint8_t bsp_apic_id; + +extern struct gdt_ptr_64_t** ap_gdt_ptr_64; + +extern struct gdt_t(** ap_gdts)[GDT_NUM_ENTRIES]; + +extern uint64_t* init_stacks_paddr; +extern uint64_t* init_stacks_vaddr; + +extern uint8_t* ap_init_locks; + extern void apic_init(void); extern void apic_init_ap(void); diff --git a/kernel/include/core/clock_src.h b/kernel/include/core/clock_src.h index 6b95b47..afecf75 100644 --- a/kernel/include/core/clock_src.h +++ b/kernel/include/core/clock_src.h @@ -22,9 +22,9 @@ struct clock_src_t { uint64_t period_fs; - uint64_t (*counter)(void*); - void (*reset)(void*, uint64_t); - void* meta; + uint64_t (*counter)(volatile void*); + void (*reset)(volatile void*, uint64_t); + volatile void* meta; }; extern void clock_src_init(void); diff --git a/kernel/include/core/kentry.h b/kernel/include/core/kentry.h index f0d16d9..bc5c2ff 100644 --- a/kernel/include/core/kentry.h +++ b/kernel/include/core/kentry.h @@ -31,7 +31,7 @@ struct boot_context_t { struct acpi_rsdp_t rsdp; - volatile struct gdt_t(* gdt)[GDT_NUM_ENTRIES]; + struct gdt_t(* gdt)[GDT_NUM_ENTRIES]; #ifdef GRAPHICSBASE struct framebuffer_t framebuffer; #endif /* GRAPHICSBASE */ diff --git a/kernel/include/core/proc_data.h b/kernel/include/core/proc_data.h index 20890f0..53fe3d6 100644 --- a/kernel/include/core/proc_data.h +++ b/kernel/include/core/proc_data.h @@ -28,7 +28,7 @@ struct proc_data_t { uint64_t kernel_rsp; // order matters uint8_t arb_id; - volatile struct tss_t* tss; + struct tss_t* tss; struct pcb_t* current_process; uint64_t sts; }; diff --git a/kernel/include/core/tss.h b/kernel/include/core/tss.h index 9913cf9..cfd9bc5 100644 --- a/kernel/include/core/tss.h +++ b/kernel/include/core/tss.h @@ -54,6 +54,6 @@ struct tss_t { uint16_t iopb; } __attribute__((packed)); -extern void tss_init(volatile struct gdt_t(* gdt)[GDT_NUM_ENTRIES]); +extern void tss_init(struct gdt_t(* gdt)[GDT_NUM_ENTRIES]); #endif /* KERNEL_CORE_TSS_H */ diff --git a/kernel/lib/hash.c b/kernel/lib/hash.c index 0863e96..923b136 100644 --- a/kernel/lib/hash.c +++ b/kernel/lib/hash.c @@ -21,7 +21,7 @@ #include #define CRC32_ANSI_C0 0xFFFFFFFF -#define CRC32_ANSI_C1 0xEDB88320; +#define CRC32_ANSI_C1 0xEDB88320 #define FNV64_1A_C0 0xcbf29ce484222325 diff --git a/scripts/Makefile.kcflags b/scripts/Makefile.kcflags index 2e5cf8d..715c28c 100644 --- a/scripts/Makefile.kcflags +++ b/scripts/Makefile.kcflags @@ -14,12 +14,12 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see -CWARN := -Wall -Wextra -pedantic -Wshadow -Wpointer-arith -Wwrite-strings -Wmissing-prototypes \ - -Wmissing-declarations -Wredundant-decls -Wnested-externs -Winline -Wno-long-long -Wconversion \ - -Wstrict-prototypes +CWARN := -Weverything ifndef DEBUG - CWARN := $(CWARN) -Werror + CWARN := $(CWARN) -Werror -Wno-unsafe-buffer-usage -Wno-reserved-identifier -Wno-unused-macros \ + -Wno-declaration-after-statement -Wno-padded -Wno-bad-function-cast -Wno-pre-c11-compat \ + -Wno-switch-default -Wno-cast-align -Wno-pre-c23-compat endif LD_USR_FLAGS := -std=c23 -fno-pie -mno-mmx -mno-sse -mno-sse2 -mno-avx -mno-avx2 -mno-avx512f \ diff --git a/scripts/gen_compile_commands b/scripts/gen_compile_commands new file mode 100755 index 0000000..329d224 --- /dev/null +++ b/scripts/gen_compile_commands @@ -0,0 +1,3 @@ +#!/bin/bash + +bear -- make all diff --git a/scripts/scan_build b/scripts/scan_build new file mode 100755 index 0000000..910ca76 --- /dev/null +++ b/scripts/scan_build @@ -0,0 +1,5 @@ +#!/bin/bash + +scan-build --use-cc=clang --use-c++=clang++ \ + -analyze-headers -enable-checker core,deadcode,nullability,security,unix \ + make all diff --git a/test/helpers/main.c b/test/helpers/main.c index 84b699a..cf8eaeb 100644 --- a/test/helpers/main.c +++ b/test/helpers/main.c @@ -101,7 +101,7 @@ int main(void) { } else { test->test(); - exit(0); + exit(EXIT_SUCCESS); } } diff --git a/test/include/macros.h b/test/include/macros.h index 4b1709a..f7ce5d2 100644 --- a/test/include/macros.h +++ b/test/include/macros.h @@ -24,6 +24,8 @@ #include #include +#pragma clang diagnostic ignored "-Wmissing-noreturn" + enum _test_result_t { _TEST_PASS, _TEST_FAIL, @@ -40,7 +42,7 @@ extern const char* _test_name; extern void _test_report(const char* report); -#define TEST_NAME(name) const char* _test_name = name; +#define TEST_NAME(name) const char* _test_name = name #define TEST_EXP_PASS(nm) _TEST_EXPAND(__COUNTER__, nm, _TEST_PASS) #define TEST_EXP_FAIL(nm) _TEST_EXPAND(__COUNTER__, nm, _TEST_FAIL) @@ -63,16 +65,20 @@ extern void _test_report(const char* report); #define TEST_FAIL() exit(EXIT_FAILURE) #define ASSERT_TRUE(condition, report) \ - if (!(condition)) { \ - _test_report(report); \ - TEST_FAIL(); \ - } + do { \ + if (!(condition)) { \ + _test_report(report); \ + TEST_FAIL(); \ + } \ + } while (0) #define ASSERT_FALSE(condition, report) \ - if ((condition)) { \ - _test_report(report); \ - TEST_FAIL(); \ - } + do { \ + if ((condition)) { \ + _test_report(report); \ + TEST_FAIL(); \ + } \ + } while (0) #define ASSERT_EXCEPTION(callback, report, ...) \ do { \ @@ -86,9 +92,9 @@ extern void _test_report(const char* report); } \ else { \ callback(__VA_OPT__(__VA_ARGS__)); \ - exit(0); \ + exit(EXIT_SUCCESS); \ } \ - } while (0); + } while (0) #define ASSERT_NO_EXCEPTION(callback, report, ...) \ do { \ @@ -102,8 +108,8 @@ extern void _test_report(const char* report); } \ else { \ callback(__VA_ARGS__); \ - exit(0); \ + exit(EXIT_SUCCESS); \ } \ - } while (0); + } while (0) #endif /* TEST_HELPERS_MACROS_H */ diff --git a/test/lib/test.c b/test/lib/test.c index e081e25..6304e6b 100644 --- a/test/lib/test.c +++ b/test/lib/test.c @@ -33,7 +33,7 @@ #define MEM_TEST_SIZE 256 -TEST_NAME("libary test suite") +TEST_NAME("libary test suite"); TEST("kmemset") { char* actual = malloc(MEM_TEST_SIZE); diff --git a/test/testsuite/test.c b/test/testsuite/test.c index 49b23a8..9bd260d 100644 --- a/test/testsuite/test.c +++ b/test/testsuite/test.c @@ -29,7 +29,7 @@ static void nested_exception(void) { ASSERT_NO_EXCEPTION(will_throw, "nested exception caught"); } -TEST_NAME("testsuite validation") +TEST_NAME("testsuite validation"); TEST("Implicit pass") {} From dfe7942c717a2da05cbe0a4cf133cb003460f83a Mon Sep 17 00:00:00 2001 From: Ebrahim Aleem Date: Wed, 6 May 2026 20:34:21 -0700 Subject: [PATCH 10/13] implemented ext2 file writing --- drivers/ext2/ext2.c | 449 +++++++++++++++++++++++++++++++++++++-- scripts/Makefile.kcflags | 8 +- userland/shell/main.c | 25 +-- 3 files changed, 435 insertions(+), 47 deletions(-) diff --git a/drivers/ext2/ext2.c b/drivers/ext2/ext2.c index 31a3b66..b922676 100644 --- a/drivers/ext2/ext2.c +++ b/drivers/ext2/ext2.c @@ -157,6 +157,7 @@ struct ext2_ll_dir_entry_t { } __attribute__((packed)); _Static_assert(sizeof(struct ext2_superblock_t) == 1024, "Bad ext2 superblock size"); +_Static_assert(sizeof(struct ext2_superblock_t) == SUPERBLOCK_SECTORS * SECTOR_SIZE, "Bad ext2 superblock size"); _Static_assert(sizeof(struct ext2_bg_desc_t) == 32, "Bad ext2 bg descriptor size"); _Static_assert(sizeof(struct ext2_inode_t) == 128, "Bad exte2 inode size"); @@ -194,7 +195,8 @@ static void* read_block(uint64_t block, struct ext2_t* ext2) { const uint64_t lba = ext2->start_lba + block * block_size / SECTOR_SIZE; if (lba > ext2->end_lba) { - logging_log_error("Attempt to read beyond ext2 end lba (0x%x > 0x%x)", lba, ext2->end_lba); + logging_log_error("Attempt to read beyond ext2 end lba (0x%llx > 0x%llx)", lba, ext2->end_lba); + return 0; } if (disk_read(ext2->disk, buffer, lba, (uint16_t)(block_size / SECTOR_SIZE)) != DISK_OK) { @@ -213,6 +215,8 @@ static void* write_block(uint64_t block, struct ext2_t* ext2, void* buffer) { if (lba > ext2->end_lba) { logging_log_error("Attempt to write beyond ext2 end lba (0x%x > 0x%x)", lba, ext2->end_lba); + kfree(buffer); + return 0; } if (disk_write(ext2->disk, buffer, lba, (uint16_t)(block_size / SECTOR_SIZE)) != DISK_OK) { @@ -249,7 +253,6 @@ static uint8_t get_inode(const struct ext2_inode_handle_t* inode_handle, struct return 0; } -__attribute__((unused)) //TODO: remove static uint8_t set_inode(const struct ext2_inode_handle_t* inode_handle, struct ext2_inode_t* inode) { const struct ext2_superblock_t* superblock = inode_handle->ext2->superblock; const struct ext2_bg_desc_t* bgdt = inode_handle->ext2->bgdt; @@ -280,6 +283,332 @@ static uint8_t set_inode(const struct ext2_inode_handle_t* inode_handle, struct return 0; } +static void sync_meta(const struct ext2_t* ext2) { + // superblock + disk_write(ext2->disk, ext2->superblock, ext2->start_lba + SUPERBLOCK_LBA, SUPERBLOCK_SECTORS); + + // bgdt + const uint64_t bgdt_start_lba = ext2->start_lba + (1u << (1 + ext2->superblock->s_log_block_size)); + uint64_t bgdt_size = (1 + ext2->superblock->s_blocks_count / ext2->superblock->s_blocks_per_group) + * sizeof(struct ext2_bg_desc_t); + const uint64_t adj = bgdt_size % SECTOR_SIZE; + if (adj) { + bgdt_size += SECTOR_SIZE - adj; + } + + disk_write(ext2->disk, ext2->bgdt, bgdt_start_lba, (uint16_t)(bgdt_size / SECTOR_SIZE)); +} + +static uint32_t alloc_block(struct ext2_t* ext2, uint64_t group) { + const uint64_t start_group = group; + const uint64_t num_groups = ext2->superblock->s_inodes_count / ext2->superblock->s_inodes_per_group; + const uint64_t bitmap_bytes = ext2->superblock->s_blocks_per_group / 8; + + do { + if (ext2->bgdt[group].bg_free_blocks_count) { + void* bitmap = 0; + for (uint64_t off = 0; off < bitmap_bytes; off += sizeof(uint64_t)) { + if (off % ext2->block_size == 0) { + kfree(bitmap); + + bitmap = read_block(ext2->bgdt[group].bg_block_bitmap + (off / ext2->block_size), ext2); + + if (!bitmap) { + // try next block on failure + off += ext2->block_size - sizeof(uint64_t); + continue; + } + } + + uint64_t word = ~*(uint64_t*)((uint64_t)bitmap + off); + if (word) { + for (uint8_t bit = 0; bit < 64; bit++) { + if (word & (1uLL << bit)) { + *(uint64_t*)((uint64_t)bitmap + off) = ~word | (1uLL << bit); + ext2->bgdt[group].bg_free_blocks_count--; + ext2->superblock->s_free_blocks_count--; + + bitmap = write_block(ext2->bgdt[group].bg_block_bitmap + (off / ext2->block_size), ext2, bitmap); + + sync_meta(ext2); + + kfree(bitmap); + return (uint32_t)((group * ext2->superblock->s_blocks_per_group) + off * 8 + bit); + } + } + } + } + } + + if (++group == num_groups - 1) { // TODO: support allocating from last group + group = 0; + } + } while (start_group != group); + + return 0; // out of blocks +} + +static uint32_t alloc_and_zero_block(struct ext2_t* ext2, void* zeros, uint64_t group) { + uint32_t block = alloc_block(ext2, group); + + if (block) { + write_block(block, ext2, zeros); + } + + return block; +} + +static uint64_t assign_block(struct ext2_inode_handle_t* handle, uint64_t index, struct ext2_inode_t* inode) { + const uint64_t group = (handle->inode_index - 1) / handle->ext2->superblock->s_inodes_per_group; + const uint64_t blocks_usage = handle->ext2->block_size / 512; + + void* zeros = kmalloc(handle->ext2->block_size); + kmemset(zeros, 0, handle->ext2->block_size); + lock_acquire(&handle->ext2->lock); + + if (get_inode(handle, inode)) { + return 0; + } + + uint32_t block = 0; + + if (index < DIRECT_BLOCKS) { + block = inode->i_block[index]; + if (!block) { + block = alloc_and_zero_block(handle->ext2, zeros, group); + inode->i_block[index] = block; + + if (block) { + inode->i_blocks += blocks_usage; + } + } + + goto cleanup; + } + + index -= DIRECT_BLOCKS; + + uint32_t* buffer; + const uint64_t block_size = handle->ext2->block_size; + const uint64_t indir1 = block_size / sizeof(uint32_t); + uint64_t old_block; + + if (index < indir1) { + block = inode->i_block[INDIR_1]; + + if (!block) { + block = alloc_and_zero_block(handle->ext2, zeros, group); + + if (!block) { + goto cleanup; + } + + inode->i_blocks += blocks_usage; + + inode->i_block[INDIR_1] = block; + } + + + old_block = block; + buffer = read_block(block, handle->ext2); + + if (!buffer) { + block = 0; + goto cleanup; + } + + block = buffer[index]; + + if (!block) { + block = alloc_and_zero_block(handle->ext2, zeros, group); + buffer[index] = block; + buffer = write_block(old_block, handle->ext2, buffer); + + if (block) { + inode->i_blocks += blocks_usage; + } + } + + kfree(buffer); + + goto cleanup; + } + + index -= indir1; + + const uint64_t indir2 = indir1 * indir1; + + if (index < indir2) { + block = inode->i_block[INDIR_2]; + + if (!block) { + block = alloc_and_zero_block(handle->ext2, zeros, group); + + if (!block) { + goto cleanup; + } + + inode->i_blocks += blocks_usage; + + inode->i_block[INDIR_2] = block; + } + + old_block = block; + buffer = read_block(block, handle->ext2); + + if (!buffer) { + block = 0; + goto cleanup; + } + + block = buffer[index / indir1]; + + if (!block) { + block = alloc_and_zero_block(handle->ext2, zeros, group); + buffer[index / indir1] = block; + buffer = write_block(old_block, handle->ext2, buffer); + + if (block) { + inode->i_blocks += blocks_usage; + } + } + + kfree(buffer); + + if (!block) { + goto cleanup; + } + + old_block = block; + buffer = read_block(block, handle->ext2); + + if (!buffer) { + block = 0; + goto cleanup; + } + + block = buffer[index % indir1]; + + if (!block) { + block = alloc_and_zero_block(handle->ext2, zeros, group); + buffer[index % indir1] = block; + buffer = write_block(old_block, handle->ext2, buffer); + + if (block) { + inode->i_blocks += blocks_usage; + } + } + + kfree(buffer); + + goto cleanup; + } + + index -= indir2; + + const uint64_t indir3 = indir2 * indir1; + + if (index < indir3) { + block = inode->i_block[INDIR_3]; + + if (!block) { + block = alloc_and_zero_block(handle->ext2, zeros, group); + + if (!block) { + goto cleanup; + } + + inode->i_blocks += blocks_usage; + + inode->i_block[INDIR_3] = block; + } + + old_block = block; + buffer = read_block(block, handle->ext2); + + if (!buffer) { + block = 0; + goto cleanup; + } + + block = buffer[index / indir2]; + + if (!block) { + block = alloc_and_zero_block(handle->ext2, zeros, group); + buffer[index / indir2] = block; + buffer = write_block(old_block, handle->ext2, buffer); + + if (block) { + inode->i_blocks += blocks_usage; + } + } + + kfree(buffer); + + if (!block) { + goto cleanup; + } + + old_block = block; + buffer = read_block(block, handle->ext2); + + if (!buffer) { + block = 0; + goto cleanup; + } + + block = buffer[(index % indir2) / indir1]; + + if (!block) { + block = alloc_and_zero_block(handle->ext2, zeros, group); + buffer[(index % indir2) / indir1] = block; + buffer = write_block(old_block, handle->ext2, buffer); + + if (block) { + inode->i_blocks += blocks_usage; + } + } + + kfree(buffer); + + if (!block) { + goto cleanup; + } + + old_block = block; + buffer = read_block(block, handle->ext2); + + if (!buffer) { + block = 0; + goto cleanup; + } + + block = buffer[index % indir1]; + + if (!block) { + block = alloc_and_zero_block(handle->ext2, zeros, group); + buffer[index % indir1] = block; + buffer = write_block(old_block, handle->ext2, buffer); + + if (block) { + inode->i_blocks += blocks_usage; + } + } + + kfree(buffer); + + goto cleanup; + } + +cleanup: + set_inode(handle, inode); + + lock_release(&handle->ext2->lock); + kfree(zeros); + + return block; +} + static enum ext2_block_state_t get_block(struct ext2_t* ext2, struct ext2_inode_t* inode, uint64_t index, @@ -361,7 +690,7 @@ static enum ext2_block_state_t get_block(struct ext2_t* ext2, return BLOCK_OK; } - block -= indir2; + index -= indir2; const uint64_t indir3 = indir2 * indir1; @@ -627,7 +956,7 @@ static size_t ext2_read(struct file_handle_t* handle, void* buffer, size_t count size_t read = 0; uint64_t write_seek = 0; - size_t write_len; + size_t read_len; uint64_t full_seek = ext2_get_seek(handle); @@ -636,16 +965,16 @@ static size_t ext2_read(struct file_handle_t* handle, void* buffer, size_t count break; } - write_len = block_size; // default full block + read_len = block_size; // default full block if (count < block_size) { // read partial, only requested - write_len = count; + read_len = count; } - if (write_len + inode_handle->seek > block_size) { + if (read_len + inode_handle->seek > block_size) { // read partial, not past block - write_len = block_size - inode_handle->seek; + read_len = block_size - inode_handle->seek; } switch (get_block(inode_handle->ext2, &inode, inode_handle->seek_block, &block)) { @@ -656,28 +985,28 @@ static size_t ext2_read(struct file_handle_t* handle, void* buffer, size_t count return read; } - if (write_len + full_seek > size) { + if (read_len + full_seek > size) { // full block read, but only copy up to limit of the file - write_len = size - full_seek; + read_len = size - full_seek; count = 0; } - kmemcpy((uint8_t*)buffer + write_seek, block_buffer + inode_handle->seek, write_len); + kmemcpy((uint8_t*)buffer + write_seek, block_buffer + inode_handle->seek, read_len); kfree(block_buffer); break; case BLOCK_SPARSE: - kmemset((uint8_t*)buffer + write_seek, 0, write_len); + kmemset((uint8_t*)buffer + write_seek, 0, read_len); break; case BLOCK_ERROR: return read; } - write_seek += write_len; - full_seek += write_len; - inode_handle->seek += write_len; - count -= write_len; - read += write_len; + write_seek += read_len; + full_seek += read_len; + inode_handle->seek += read_len; + count -= read_len; + read += read_len; if (inode_handle->seek == block_size) { inode_handle->seek = 0; @@ -699,10 +1028,88 @@ static enum file_status_t ext2_seek(struct file_handle_t* handle, uint64_t seek) } static size_t ext2_write(struct file_handle_t* handle, void* buffer, size_t count) { - (void)handle; - (void)buffer; - (void)count; - return 0; + struct ext2_inode_t inode; + struct ext2_inode_handle_t* inode_handle = (struct ext2_inode_handle_t*)handle; + uint8_t* block_buffer = 0; + uint64_t block; + + if (!inode_handle || get_inode(inode_handle, &inode)) { + return 0; + } + + const uint64_t size = (uint64_t)inode.i_size | ((uint64_t)inode.i_dir_acl << 32); + const uint64_t block_size = inode_handle->ext2->block_size; + + size_t written = 0; + uint64_t read_seek = 0; + size_t write_len; + uint64_t full_seek = ext2_get_seek(handle); + + + while (count) { + write_len = block_size; // default full block + + if (count < block_size) { + // write partial, only requested + write_len = count; + } + + if (write_len + inode_handle->seek > block_size) { + // write partial, not past block + write_len = block_size - inode_handle->seek; + } + + switch (get_block(inode_handle->ext2, &inode, inode_handle->seek_block, &block)) { + case BLOCK_SPARSE: + block = assign_block(inode_handle, inode_handle->seek_block, &inode); + + if (!block) { + goto update_inode; + } + + __attribute__((fallthrough)); + case BLOCK_OK: + block_buffer = read_block(block, inode_handle->ext2); + + if (!block_buffer) { + goto update_inode; + } + + kmemcpy(block_buffer + inode_handle->seek, (uint8_t*)buffer + read_seek, write_len); + + block_buffer = write_block(block, inode_handle->ext2, block_buffer); + + if (!block_buffer) { + goto update_inode; + } + + kfree(block_buffer); + break; + case BLOCK_ERROR: + goto update_inode; + } + + read_seek += write_len; + full_seek += write_len; + inode_handle->seek += write_len; + count -= write_len; + written += write_len; + + if (inode_handle->seek == block_size) { + inode_handle->seek = 0; + inode_handle->seek_block++; + } + } + +update_inode: + if (full_seek > size) { + inode.i_size = (uint32_t)full_seek; + inode.i_dir_acl = (uint32_t)(full_seek >> 32); + + set_inode(inode_handle, &inode); + } + + return written; } static enum file_status_t ext2_create(struct file_handle_t* handle, const char* name) { diff --git a/scripts/Makefile.kcflags b/scripts/Makefile.kcflags index 715c28c..d080699 100644 --- a/scripts/Makefile.kcflags +++ b/scripts/Makefile.kcflags @@ -14,12 +14,12 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see -CWARN := -Weverything +CWARN := -Weverything -Werror -Wno-unsafe-buffer-usage -Wno-reserved-identifier -Wno-unused-macros \ + -Wno-declaration-after-statement -Wno-padded -Wno-bad-function-cast -Wno-pre-c11-compat \ + -Wno-switch-default -Wno-cast-align -Wno-pre-c23-compat -Wno-c++-compat ifndef DEBUG - CWARN := $(CWARN) -Werror -Wno-unsafe-buffer-usage -Wno-reserved-identifier -Wno-unused-macros \ - -Wno-declaration-after-statement -Wno-padded -Wno-bad-function-cast -Wno-pre-c11-compat \ - -Wno-switch-default -Wno-cast-align -Wno-pre-c23-compat + CWARN := $(CWARN) -Werror endif LD_USR_FLAGS := -std=c23 -fno-pie -mno-mmx -mno-sse -mno-sse2 -mno-avx -mno-avx2 -mno-avx512f \ diff --git a/userland/shell/main.c b/userland/shell/main.c index 113cfeb..87786c3 100644 --- a/userland/shell/main.c +++ b/userland/shell/main.c @@ -19,29 +19,10 @@ #include int main(int argc, char** argv) { - printf("%s\n", argv[0]); - if (argc > 1) { - printf("%s ", argv[1]); - } - printf("Shell\n"); - - FILE* f = fopen(argv[0], "r"); - - if (!f) { - perror("Failed top open file"); - } - - static char buffer[4]; + (void)argc; + (void)argv; - ssize_t read = fread(buffer, 1, sizeof(buffer), f); - if (read != 4) { - fprintf(stderr, "Failed to read file\n"); - return EXIT_FAILURE; - } - - printf("%3s\n", &buffer[1]); - - fclose(f); + printf("Shell\n"); return EXIT_SUCCESS; } From ff5a19e5d233e91ec60620c25166355b3f316c6f Mon Sep 17 00:00:00 2001 From: Ebrahim Aleem Date: Wed, 6 May 2026 22:22:25 -0700 Subject: [PATCH 11/13] implemented ext2 regular file creation --- drivers/ext2/ext2.c | 192 +++++++++++++++++++++++++++++++++++++++--- kernel/core/kentry.c | 4 + userland/shell/main.c | 4 + 3 files changed, 190 insertions(+), 10 deletions(-) diff --git a/drivers/ext2/ext2.c b/drivers/ext2/ext2.c index b922676..3a4312b 100644 --- a/drivers/ext2/ext2.c +++ b/drivers/ext2/ext2.c @@ -34,6 +34,7 @@ #include #include #include +#include #define SUPERBLOCK_LBA 2 #define SUPERBLOCK_SECTORS 2 @@ -320,11 +321,11 @@ static uint32_t alloc_block(struct ext2_t* ext2, uint64_t group) { } } - uint64_t word = ~*(uint64_t*)((uint64_t)bitmap + off); + uint64_t word = ~*(uint64_t*)((uint64_t)bitmap + (off % ext2->block_size)); if (word) { for (uint8_t bit = 0; bit < 64; bit++) { if (word & (1uLL << bit)) { - *(uint64_t*)((uint64_t)bitmap + off) = ~word | (1uLL << bit); + *(uint64_t*)((uint64_t)bitmap + (off % ext2->block_size)) = ~word | (1uLL << bit); ext2->bgdt[group].bg_free_blocks_count--; ext2->superblock->s_free_blocks_count--; @@ -348,6 +349,55 @@ static uint32_t alloc_block(struct ext2_t* ext2, uint64_t group) { return 0; // out of blocks } +static uint64_t alloc_inode(struct ext2_t* ext2, uint64_t group) { + const uint64_t start_group = group; + const uint64_t num_groups = ext2->superblock->s_inodes_count / ext2->superblock->s_inodes_per_group; + const uint64_t bitmap_bytes = ext2->superblock->s_inodes_per_group / 8; + + do { + if (ext2->bgdt[group].bg_free_inodes_count) { + void* bitmap = 0; + for (uint64_t off = 0; off < bitmap_bytes; off += sizeof(uint64_t)) { + if (off % ext2->block_size == 0) { + kfree(bitmap); + + bitmap = read_block(ext2->bgdt[group].bg_inode_bitmap + (off / ext2->block_size), ext2); + + if (!bitmap) { + // try next block on failure + off += ext2->block_size - sizeof(uint64_t); + continue; + } + } + + uint64_t word = ~*(uint64_t*)((uint64_t)bitmap + (off % ext2->block_size)); + if (word) { + for (uint8_t bit = 0; bit < 64; bit++) { + if (word & (1uLL << bit)) { + *(uint64_t*)((uint64_t)bitmap + (off % ext2->block_size)) = ~word | (1uLL << bit); + ext2->bgdt[group].bg_free_inodes_count--; + ext2->superblock->s_free_inodes_count--; + + bitmap = write_block(ext2->bgdt[group].bg_inode_bitmap + (off / ext2->block_size), ext2, bitmap); + + sync_meta(ext2); + + kfree(bitmap); + return (uint32_t)((group * ext2->superblock->s_inodes_per_group) + off * 8 + bit + 1); + } + } + } + } + } + + if (++group == num_groups - 1) { // TODO: support allocating from last group + group = 0; + } + } while (start_group != group); + + return 0; // out of inodes +} + static uint32_t alloc_and_zero_block(struct ext2_t* ext2, void* zeros, uint64_t group) { uint32_t block = alloc_block(ext2, group); @@ -358,13 +408,16 @@ static uint32_t alloc_and_zero_block(struct ext2_t* ext2, void* zeros, uint64_t return block; } -static uint64_t assign_block(struct ext2_inode_handle_t* handle, uint64_t index, struct ext2_inode_t* inode) { +static uint64_t assign_block(struct ext2_inode_handle_t* handle, uint64_t index, struct ext2_inode_t* inode, uint8_t lock) { const uint64_t group = (handle->inode_index - 1) / handle->ext2->superblock->s_inodes_per_group; const uint64_t blocks_usage = handle->ext2->block_size / 512; void* zeros = kmalloc(handle->ext2->block_size); kmemset(zeros, 0, handle->ext2->block_size); - lock_acquire(&handle->ext2->lock); + + if (!lock) { + lock_acquire(&handle->ext2->lock); + } if (get_inode(handle, inode)) { return 0; @@ -603,7 +656,9 @@ static uint64_t assign_block(struct ext2_inode_handle_t* handle, uint64_t index, cleanup: set_inode(handle, inode); - lock_release(&handle->ext2->lock); + if (!lock) { + lock_release(&handle->ext2->lock); + } kfree(zeros); return block; @@ -886,6 +941,13 @@ static enum file_status_t ext2_read_dir(struct file_handle_t* handle, struct dir } } +static struct ext2_inode_handle_t* ext2_duplicate(struct ext2_inode_handle_t* handle) { + struct ext2_inode_handle_t* dup = kmalloc(sizeof(struct ext2_inode_handle_t)); + + *dup = *handle; + return dup; +} + static struct file_handle_t* ext2_open(struct mount_cntx_t* cntx, char* path) { size_t path_len; uint8_t cntrl = 0; @@ -1061,7 +1123,7 @@ static size_t ext2_write(struct file_handle_t* handle, void* buffer, size_t coun switch (get_block(inode_handle->ext2, &inode, inode_handle->seek_block, &block)) { case BLOCK_SPARSE: - block = assign_block(inode_handle, inode_handle->seek_block, &inode); + block = assign_block(inode_handle, inode_handle->seek_block, &inode, 0); if (!block) { goto update_inode; @@ -1113,9 +1175,6 @@ static size_t ext2_write(struct file_handle_t* handle, void* buffer, size_t coun } static enum file_status_t ext2_create(struct file_handle_t* handle, const char* name) { - (void)handle; - (void)name; - enum file_status_t sts; struct file_info_t info; @@ -1127,7 +1186,120 @@ static enum file_status_t ext2_create(struct file_handle_t* handle, const char* return FILE_NO_SUPPORT; } - return FILE_NO_SUPPORT; + + struct dir_info_t dir_info; + struct ext2_inode_handle_t* inode_handle = ext2_duplicate((struct ext2_inode_handle_t*)handle); + + lock_acquire(&inode_handle->ext2->lock); + + ext2_open_dir((struct file_handle_t*)inode_handle); + + + while (ext2_read_dir((struct file_handle_t*)inode_handle, &dir_info) == FILE_OK) { + if (kstrcmp(dir_info.name, name) == 0) { + ext2_close_dir((struct file_handle_t*)inode_handle); + + lock_release(&inode_handle->ext2->lock); + + ext2_close((struct file_handle_t*)inode_handle); + + return FILE_BUSY; + } + } + + const uint64_t group = (inode_handle->inode_index - 1) / inode_handle->ext2->superblock->s_inodes_per_group; + uint64_t inode_index = alloc_inode(inode_handle->ext2, group); + struct ext2_inode_handle_t* parent_handle = ext2_duplicate((struct ext2_inode_handle_t*)handle); + + sts = FILE_OK; + if (inode_index == 0) { + sts = FILE_ERROR; + goto cleanup; + } + + struct ext2_inode_t parent_inode; + + if (get_inode(parent_handle, &parent_inode)) { + sts = FILE_ERROR; + goto cleanup; + } + + struct ext2_inode_t inode = { + .i_mode = EXT2_S_IFREG, + .i_uid = 0, + .i_size = 0, + .i_atime = 0, + .i_ctime = 0, + .i_mtime = 0, + .i_dtime = 0, + .i_gid = 0, + .i_links_count = 1, + .i_blocks = 0, + .i_flags = 0, + .i_osd1 = 0, + .i_block = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + }, + .i_generation = 0, + .i_file_acl = 0, + .i_dir_acl = 0, + .i_faddr = 0, + .i_osd2 = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + } + }; + + inode_handle->inode_index = inode_index; + + set_inode(inode_handle, &inode); + + uint64_t block; + ext2_open_dir((struct file_handle_t*)parent_handle); + //TODO: allocate on in already used block + while (1) { + switch (get_block(parent_handle->ext2, &parent_inode, parent_handle->seek_block, &block)) { + case BLOCK_SPARSE: + block = assign_block(parent_handle, parent_handle->seek_block, &parent_inode, 1); + + if (!block) { + sts = FILE_ERROR; + goto cleanup; + } + + struct ext2_ll_dir_entry_t* dir_entry = read_block(block, parent_handle->ext2); + *dir_entry = (struct ext2_ll_dir_entry_t){ + .inode = (uint32_t)inode_index, + .rec_len = (uint16_t)parent_handle->ext2->block_size, + .name_len = (uint8_t)kstrlen(name), + .file_type = EXT2_FT_REG_FILE + }; + + kmemcpy(&dir_entry->name, name, dir_entry->name_len); + + dir_entry = write_block(block, parent_handle->ext2, dir_entry); + kfree(dir_entry); + + parent_inode.i_size += parent_handle->ext2->block_size; + set_inode(parent_handle, &parent_inode); + goto cleanup; + case BLOCK_OK: + parent_handle->seek_block++; + continue; + case BLOCK_ERROR: + sts = FILE_ERROR; + goto cleanup; + } + } + +cleanup: + ext2_close_dir((struct file_handle_t*)inode_handle); + + lock_release(&inode_handle->ext2->lock); + + ext2_close((struct file_handle_t*)inode_handle); + ext2_close((struct file_handle_t*)parent_handle); + + return sts; } static enum file_status_t ext2_delete(struct file_handle_t* handle) { diff --git a/kernel/core/kentry.c b/kernel/core/kentry.c index 31bd91a..0764476 100644 --- a/kernel/core/kentry.c +++ b/kernel/core/kentry.c @@ -194,6 +194,10 @@ void kapentry(uint64_t arb_id) { void prepare_userland(void* cntx) { (void)cntx; + struct fs_handle_t* f = fs_open("/", FILE_MODE_READ | FILE_MODE_WRITE); + fs_create(f, "test.txt"); + fs_close(f); + lock_acquire(&prepare_userland_lock); if (init_done) { logging_log_error("Multiple calls to prepare userland"); diff --git a/userland/shell/main.c b/userland/shell/main.c index 87786c3..e8556d5 100644 --- a/userland/shell/main.c +++ b/userland/shell/main.c @@ -24,5 +24,9 @@ int main(int argc, char** argv) { printf("Shell\n"); + FILE* f = fopen("/test.txt", "w"); + fprintf(f, "Hello, World\n"); + fclose(f); + return EXIT_SUCCESS; } From ac7c35bee7f417591aa69e8adb76b7bf4daf3683 Mon Sep 17 00:00:00 2001 From: Ebrahim Aleem Date: Wed, 6 May 2026 22:49:22 -0700 Subject: [PATCH 12/13] more portable warning flags --- drivers/ext2/ext2.c | 20 ++++++++++++++------ kernel/core/fs.c | 6 +++--- kernel/devfs/devfs.c | 2 +- kernel/devfs/tty.c | 2 +- kernel/include/core/fs.h | 2 +- kernel/include/devfs/devfs.h | 2 +- kernel/include/devfs/tty.h | 2 +- scripts/Makefile.kcflags | 8 +++++--- test/lib/test.c | 4 ++-- 9 files changed, 29 insertions(+), 19 deletions(-) diff --git a/drivers/ext2/ext2.c b/drivers/ext2/ext2.c index 3a4312b..e7e67fc 100644 --- a/drivers/ext2/ext2.c +++ b/drivers/ext2/ext2.c @@ -209,26 +209,34 @@ static void* read_block(uint64_t block, struct ext2_t* ext2) { return buffer; } -static void* write_block(uint64_t block, struct ext2_t* ext2, void* buffer) { +static void* write_block_free(uint64_t block, struct ext2_t* ext2, void* buffer, uint8_t free) { const uint64_t block_size = ext2->block_size; const uint64_t lba = ext2->start_lba + block * block_size / SECTOR_SIZE; if (lba > ext2->end_lba) { logging_log_error("Attempt to write beyond ext2 end lba (0x%x > 0x%x)", lba, ext2->end_lba); - kfree(buffer); + if (free) { + kfree(buffer); + } return 0; } if (disk_write(ext2->disk, buffer, lba, (uint16_t)(block_size / SECTOR_SIZE)) != DISK_OK) { logging_log_error("Failed to write"); - kfree(buffer); + if (free) { + kfree(buffer); + } return 0; } return buffer; } +static inline void* write_block(uint64_t block, struct ext2_t* ext2, void* buffer) { + return write_block_free(block, ext2, buffer, 1); +} + static uint8_t get_inode(const struct ext2_inode_handle_t* inode_handle, struct ext2_inode_t* inode) { const struct ext2_superblock_t* superblock = inode_handle->ext2->superblock; const struct ext2_bg_desc_t* bgdt = inode_handle->ext2->bgdt; @@ -402,7 +410,7 @@ static uint32_t alloc_and_zero_block(struct ext2_t* ext2, void* zeros, uint64_t uint32_t block = alloc_block(ext2, group); if (block) { - write_block(block, ext2, zeros); + write_block_free(block, ext2, zeros, 0); } return block; @@ -801,7 +809,7 @@ static enum ext2_block_state_t get_block(struct ext2_t* ext2, return BLOCK_ERROR; } -static inline size_t path_entry_len(char* path) { +static inline size_t path_entry_len(const char* path) { size_t len = 0; for (; *path && *path != '/'; path++) { @@ -948,7 +956,7 @@ static struct ext2_inode_handle_t* ext2_duplicate(struct ext2_inode_handle_t* ha return dup; } -static struct file_handle_t* ext2_open(struct mount_cntx_t* cntx, char* path) { +static struct file_handle_t* ext2_open(struct mount_cntx_t* cntx, const char* path) { size_t path_len; uint8_t cntrl = 0; diff --git a/kernel/core/fs.c b/kernel/core/fs.c index 4a25f4f..1f4dd20 100644 --- a/kernel/core/fs.c +++ b/kernel/core/fs.c @@ -260,9 +260,9 @@ enum file_status_t fs_mount( return FILE_ERROR; } -static char* find_mount(const char* path, struct vfs_mount_t** mount_out, void** clean_path_out, char** path_write_out) { +static const char* find_mount(const char* path, struct vfs_mount_t** mount_out, void** clean_path_out, char** path_write_out) { struct vfs_tree_node_t* node = &vfs_root, * walk = 0; - char* mount_path = (char*)""; + const char* mount_path = ""; struct vfs_mount_t* mount = 0; size_t len = kstrlen(path); @@ -352,7 +352,7 @@ struct fs_handle_t* fs_open(const char* path, uint8_t mode) { struct vfs_mount_t* mount; void* clean_path; char* path_write; - char* mount_path = find_mount(path, &mount, &clean_path, &path_write); + const char* mount_path = find_mount(path, &mount, &clean_path, &path_write); if (!mount) { kfree(clean_path); diff --git a/kernel/devfs/devfs.c b/kernel/devfs/devfs.c index 29888fc..e445c97 100644 --- a/kernel/devfs/devfs.c +++ b/kernel/devfs/devfs.c @@ -35,7 +35,7 @@ struct dev_handle_t { } type; }; -struct file_handle_t* devfs_open(struct mount_cntx_t* cntx, char* path) { +struct file_handle_t* devfs_open(struct mount_cntx_t* cntx, const char* path) { (void)cntx; struct dev_handle_t* dev_handle; diff --git a/kernel/devfs/tty.c b/kernel/devfs/tty.c index 64b0763..a39c577 100644 --- a/kernel/devfs/tty.c +++ b/kernel/devfs/tty.c @@ -97,7 +97,7 @@ struct tty_handle_t* tty_com2(void) { } #endif /* SERIAL */ -struct tty_handle_t* tty_open(char* name) { +struct tty_handle_t* tty_open(const char* name) { #ifdef SERIAL if (!kstrcmp(name, "S0")) { // COM1 diff --git a/kernel/include/core/fs.h b/kernel/include/core/fs.h index 681f53b..baad35d 100644 --- a/kernel/include/core/fs.h +++ b/kernel/include/core/fs.h @@ -61,7 +61,7 @@ struct dir_info_t { char name[256]; }; -typedef struct file_handle_t* (*fs_open_t)(struct mount_cntx_t*, char*); +typedef struct file_handle_t* (*fs_open_t)(struct mount_cntx_t*, const char*); typedef void (*fs_close_t)(struct file_handle_t*); typedef enum file_status_t (*fs_stat_t)(struct file_handle_t*, struct file_info_t*); diff --git a/kernel/include/devfs/devfs.h b/kernel/include/devfs/devfs.h index 68244bc..c27ee9f 100644 --- a/kernel/include/devfs/devfs.h +++ b/kernel/include/devfs/devfs.h @@ -23,7 +23,7 @@ #include -extern struct file_handle_t* devfs_open(struct mount_cntx_t* cntx, char* path); +extern struct file_handle_t* devfs_open(struct mount_cntx_t* cntx, const char* path); extern void devfs_close(struct file_handle_t* handle); extern enum file_status_t devfs_stat(struct file_handle_t* handle, struct file_info_t* info); diff --git a/kernel/include/devfs/tty.h b/kernel/include/devfs/tty.h index 0b8a157..f275bbe 100644 --- a/kernel/include/devfs/tty.h +++ b/kernel/include/devfs/tty.h @@ -32,7 +32,7 @@ extern struct tty_handle_t* tty_com1(void); extern struct tty_handle_t* tty_com2(void); #endif /* SERIAL */ -extern struct tty_handle_t* tty_open(char* name); +extern struct tty_handle_t* tty_open(const char* name); extern void tty_close(struct tty_handle_t* tty); extern size_t tty_read(struct tty_handle_t* tty, void* buffer, size_t count); extern uint8_t tty_queue_read(struct tty_handle_t* tty, uint8_t byte); diff --git a/scripts/Makefile.kcflags b/scripts/Makefile.kcflags index d080699..408f551 100644 --- a/scripts/Makefile.kcflags +++ b/scripts/Makefile.kcflags @@ -14,9 +14,11 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see -CWARN := -Weverything -Werror -Wno-unsafe-buffer-usage -Wno-reserved-identifier -Wno-unused-macros \ - -Wno-declaration-after-statement -Wno-padded -Wno-bad-function-cast -Wno-pre-c11-compat \ - -Wno-switch-default -Wno-cast-align -Wno-pre-c23-compat -Wno-c++-compat +CWARN := -Wall -Wextra -pedantic -Wshadow -Wpointer-arith -Wwrite-strings -Wmissing-prototypes \ + -Wmissing-declarations -Wredundant-decls -Wnested-externs -Winline -Wno-long-long -Wconversion \ + -Wstrict-prototypes -Wundef -Wcast-qual -Wstrict-overflow=5 -Wswitch-enum -Winit-self -Wdouble-promotion \ + -Wformat=2 -Wnull-dereference -Wpacked -Wvolatile-register-var -Walloca -Wvla -Wframe-larger-than=1024 \ + -Wstrict-aliasing=2 -Wmissing-noreturn -Wmissing-format-attribute ifndef DEBUG CWARN := $(CWARN) -Werror diff --git a/test/lib/test.c b/test/lib/test.c index 6304e6b..3e2bd9e 100644 --- a/test/lib/test.c +++ b/test/lib/test.c @@ -120,8 +120,8 @@ TEST("kstrcmp") { TEST("hash_byte_sum") { ASSERT_TRUE(hash_byte_sum((uint8_t*)0xdeadbeef, 0) == 0, "fails invalid ptr"); - ASSERT_TRUE(hash_byte_sum((uint8_t*)"\0\1\2\3\0\0\1\2", 8) == 9, "fails basic sum"); - ASSERT_TRUE(hash_byte_sum((uint8_t*)"\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF", 8) == 248, "fails overflow"); + ASSERT_TRUE(hash_byte_sum((const uint8_t*)"\0\1\2\3\0\0\1\2", 8) == 9, "fails basic sum"); + ASSERT_TRUE(hash_byte_sum((const uint8_t*)"\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF", 8) == 248, "fails overflow"); } TEST("crc32_ansi") { From e3dd522f271e2d4636f38a608ca23c3dde2fb765 Mon Sep 17 00:00:00 2001 From: Ebrahim Aleem Date: Thu, 28 May 2026 19:10:09 -0700 Subject: [PATCH 13/13] switched to openat --- Makefile | 1 + drivers/ext2/ext2.c | 342 ++++++++++-------- kernel/core/elf.c | 16 +- kernel/core/fs.c | 140 ++++--- kernel/core/kentry.c | 9 +- kernel/core/process.c | 24 +- kernel/core/signal.c | 2 +- kernel/core/syscall.S | 13 +- kernel/core/syscall_dispatch.c | 186 ++++++---- kernel/devfs/devfs.c | 35 +- kernel/devfs/tty.c | 8 +- kernel/include/core/fs.h | 49 ++- kernel/include/core/process.h | 10 +- kernel/include/core/syscall_dispatch.h | 13 +- kernel/include/core/syscall_vectors.h | 71 +++- kernel/include/devfs/devfs.h | 11 +- kernel/include/devfs/tty.h | 2 +- kernel/include/lib/array_list.h | 43 +++ kernel/include/lib/hash_table.h | 14 +- kernel/include/lib/kstrcpy.h | 4 + kernel/lib/array_list.c | 154 ++++++++ kernel/lib/hash_table.c | 81 ++++- kernel/lib/kstrcpy.c | 15 + test/helpers/memport.c | 29 ++ test/include/memport.h | 26 ++ test/lib/test.c | 130 ++++++- userland/Makefile | 3 +- userland/mlibc-patch/abis/modulos/dev_t.h | 9 + userland/mlibc-patch/abis/modulos/ino_t.h | 11 + .../mlibc-patch/abis/modulos/seek-whence.h | 2 - userland/mlibc-patch/abis/modulos/stat.h | 6 + .../mlibc-patch/sysdeps/modulos/sysdeps.cpp | 309 ++++++++++++++-- userland/shell/main.c | 38 +- 33 files changed, 1393 insertions(+), 413 deletions(-) create mode 100644 kernel/include/lib/array_list.h create mode 100644 kernel/lib/array_list.c create mode 100644 test/helpers/memport.c create mode 100644 test/include/memport.h create mode 100644 userland/mlibc-patch/abis/modulos/dev_t.h create mode 100644 userland/mlibc-patch/abis/modulos/ino_t.h diff --git a/Makefile b/Makefile index 6a37fd0..9b7f98c 100644 --- a/Makefile +++ b/Makefile @@ -136,6 +136,7 @@ $(USERLAND_TARGETS): userland $(TEST_TARGETS): test +.PHONY: $(TEST_EXEC) $(TEST_EXEC): %: %.a $(OBJ_DIR)/boot.a $(OBJ_DIR)/kernel.a $(OBJ_DIR)/drivers.a $(CC) -g -O0 -std=c23 $(CWARN) -fuse-ld=lld -o $@ $^ diff --git a/drivers/ext2/ext2.c b/drivers/ext2/ext2.c index e7e67fc..24a790a 100644 --- a/drivers/ext2/ext2.c +++ b/drivers/ext2/ext2.c @@ -868,7 +868,7 @@ static enum file_status_t ext2_open_dir(struct file_handle_t* handle) { } -static void ext2_close_dir(struct file_handle_t* handle) { +static void ext2_reset_dir(struct file_handle_t* handle) { struct ext2_inode_handle_t* inode_handle = (struct ext2_inode_handle_t*)handle; inode_handle->seek = 0; @@ -881,7 +881,7 @@ static enum file_status_t ext2_read_dir(struct file_handle_t* handle, struct dir struct ext2_inode_t inode; if (!(inode_handle->ext2_mode & MODE_DIR)) { - return FILE_BAD_MODE; + return FILE_BAD_FLAGS; } if (get_inode(inode_handle, &inode)) { @@ -956,12 +956,16 @@ static struct ext2_inode_handle_t* ext2_duplicate(struct ext2_inode_handle_t* ha return dup; } -static struct file_handle_t* ext2_open(struct mount_cntx_t* cntx, const char* path) { +static void ext2_close(struct file_handle_t* handle) { + kfree(handle); +} + +static const char* reduce_path(struct ext2_t* ext2, const char* path, struct ext2_inode_handle_t** handle_ret) { size_t path_len; uint8_t cntrl = 0; struct ext2_inode_handle_t* handle = kmalloc(sizeof(struct ext2_inode_handle_t)); - handle->ext2 = (struct ext2_t*)cntx; + handle->ext2 = ext2; handle->inode_index = EXT2_ROOT_INO; handle->ext2_mode = 0; @@ -978,7 +982,7 @@ static struct file_handle_t* ext2_open(struct mount_cntx_t* cntx, const char* pa while (ext2_read_dir((struct file_handle_t*)handle, &info) == FILE_OK) { if (path_len == kstrlen(info.name) && kmemcmp(path, info.name, path_len) == 0) { cntrl = 0; - ext2_close_dir((struct file_handle_t*)handle); + ext2_reset_dir((struct file_handle_t*)handle); handle->inode_index = info.inode_num; break; } @@ -996,21 +1000,179 @@ static struct file_handle_t* ext2_open(struct mount_cntx_t* cntx, const char* pa } } - ext2_close_dir((struct file_handle_t*)handle); + ext2_reset_dir((struct file_handle_t*)handle); + *handle_ret = handle; + + return path; +} + +static enum file_status_t ext2_create(struct ext2_t* ext2, const char* path, uint32_t mode) { + (void)mode; + + enum file_status_t sts; + struct ext2_inode_handle_t* handle; + + path = reduce_path(ext2, path, &handle); + + if (!*path) { + return FILE_BUSY; + } + + const char* name = path; + + while (*path && *path != '/') { + path++; + } + + if (*path == '/') { + return FILE_DNE; + } + + struct file_info_t info; + if ((sts = ext2_stat((struct file_handle_t*)handle, &info)) != FILE_OK) { + return sts; + } + + if (info.type != FILE_TYPE_DIR) { + return FILE_NO_SUPPORT; + } + + struct dir_info_t dir_info; + struct ext2_inode_handle_t* inode_handle = ext2_duplicate((struct ext2_inode_handle_t*)handle); + + lock_acquire(&ext2->lock); + + ext2_open_dir((struct file_handle_t*)inode_handle); + + while (ext2_read_dir((struct file_handle_t*)inode_handle, &dir_info) == FILE_OK) { + if (kstrcmp(dir_info.name, name) == 0) { + ext2_reset_dir((struct file_handle_t*)inode_handle); + + lock_release(&inode_handle->ext2->lock); + + ext2_close((struct file_handle_t*)inode_handle); + + return FILE_BUSY; + } + } + + const uint64_t group = (inode_handle->inode_index - 1) / inode_handle->ext2->superblock->s_inodes_per_group; + uint64_t inode_index = alloc_inode(inode_handle->ext2, group); + struct ext2_inode_handle_t* parent_handle = ext2_duplicate((struct ext2_inode_handle_t*)handle); + + sts = FILE_OK; + if (inode_index == 0) { + sts = FILE_ERROR; + goto cleanup; + } + + struct ext2_inode_t parent_inode; + + if (get_inode(parent_handle, &parent_inode)) { + sts = FILE_ERROR; + goto cleanup; + } + + struct ext2_inode_t inode = { + .i_mode = EXT2_S_IFREG, + .i_uid = 0, + .i_size = 0, + .i_atime = 0, + .i_ctime = 0, + .i_mtime = 0, + .i_dtime = 0, + .i_gid = 0, + .i_links_count = 1, + .i_blocks = 0, + .i_flags = 0, + .i_osd1 = 0, + .i_block = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + }, + .i_generation = 0, + .i_file_acl = 0, + .i_dir_acl = 0, + .i_faddr = 0, + .i_osd2 = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + } + }; + + inode_handle->inode_index = inode_index; + + set_inode(inode_handle, &inode); + + uint64_t block; + ext2_open_dir((struct file_handle_t*)parent_handle); + //TODO: allocate on an already used block + while (1) { + switch (get_block(parent_handle->ext2, &parent_inode, parent_handle->seek_block, &block)) { + case BLOCK_SPARSE: + block = assign_block(parent_handle, parent_handle->seek_block, &parent_inode, 1); + + if (!block) { + sts = FILE_ERROR; + goto cleanup; + } + + struct ext2_ll_dir_entry_t* dir_entry = read_block(block, parent_handle->ext2); + *dir_entry = (struct ext2_ll_dir_entry_t){ + .inode = (uint32_t)inode_index, + .rec_len = (uint16_t)parent_handle->ext2->block_size, + .name_len = (uint8_t)kstrlen(name), + .file_type = EXT2_FT_REG_FILE + }; + + kmemcpy(&dir_entry->name, name, dir_entry->name_len); + + dir_entry = write_block(block, parent_handle->ext2, dir_entry); + kfree(dir_entry); + + parent_inode.i_size += parent_handle->ext2->block_size; + set_inode(parent_handle, &parent_inode); + goto cleanup; + case BLOCK_OK: + parent_handle->seek_block++; + continue; + case BLOCK_ERROR: + sts = FILE_ERROR; + goto cleanup; + } + } + +cleanup: + ext2_reset_dir((struct file_handle_t*)inode_handle); + + lock_release(&inode_handle->ext2->lock); + + ext2_close((struct file_handle_t*)inode_handle); + ext2_close((struct file_handle_t*)parent_handle); + + return sts; +} + +static struct file_handle_t* ext2_open(struct mount_cntx_t* cntx, const char* path, uint32_t flags, uint32_t mode) { + struct ext2_t* ext2 = (struct ext2_t*)cntx; + struct ext2_inode_handle_t* handle; + + path = reduce_path(ext2, path, &handle); if (*path) { // file not found kfree(handle); + + if (flags & FILE_FLAGS_CREATE) { + enum file_status_t create_sts = ext2_create(ext2, path, mode); + if (create_sts == FILE_OK) { + return ext2_open(cntx, path, flags & FILE_FLAGS_CREATE, mode); + } + } return 0; } return (struct file_handle_t*)handle; } -static void ext2_close(struct file_handle_t* handle) { - kfree(handle); -} - static size_t ext2_read(struct file_handle_t* handle, void* buffer, size_t count) { struct ext2_inode_t inode; struct ext2_inode_handle_t* inode_handle = (struct ext2_inode_handle_t*)handle; @@ -1031,7 +1193,7 @@ static size_t ext2_read(struct file_handle_t* handle, void* buffer, size_t count while (count) { - if (full_seek > size) { + if (full_seek >= size) { break; } @@ -1055,7 +1217,7 @@ static size_t ext2_read(struct file_handle_t* handle, void* buffer, size_t count return read; } - if (read_len + full_seek > size) { + if (read_len + full_seek >= size) { // full block read, but only copy up to limit of the file read_len = size - full_seek; count = 0; @@ -1097,7 +1259,7 @@ static enum file_status_t ext2_seek(struct file_handle_t* handle, uint64_t seek) return FILE_OK; } -static size_t ext2_write(struct file_handle_t* handle, void* buffer, size_t count) { +static size_t ext2_write(struct file_handle_t* handle, const void* buffer, size_t count) { struct ext2_inode_t inode; struct ext2_inode_handle_t* inode_handle = (struct ext2_inode_handle_t*)handle; uint8_t* block_buffer = 0; @@ -1145,7 +1307,7 @@ static size_t ext2_write(struct file_handle_t* handle, void* buffer, size_t coun goto update_inode; } - kmemcpy(block_buffer + inode_handle->seek, (uint8_t*)buffer + read_seek, write_len); + kmemcpy(block_buffer + inode_handle->seek, (const uint8_t*)buffer + read_seek, write_len); block_buffer = write_block(block, inode_handle->ext2, block_buffer); @@ -1182,151 +1344,37 @@ static size_t ext2_write(struct file_handle_t* handle, void* buffer, size_t coun return written; } -static enum file_status_t ext2_create(struct file_handle_t* handle, const char* name) { - enum file_status_t sts; - - struct file_info_t info; - if ((sts = ext2_stat(handle, &info)) != FILE_OK) { - return sts; - } - - if (info.type != FILE_TYPE_DIR) { - return FILE_NO_SUPPORT; - } - - - struct dir_info_t dir_info; - struct ext2_inode_handle_t* inode_handle = ext2_duplicate((struct ext2_inode_handle_t*)handle); - - lock_acquire(&inode_handle->ext2->lock); - - ext2_open_dir((struct file_handle_t*)inode_handle); - - - while (ext2_read_dir((struct file_handle_t*)inode_handle, &dir_info) == FILE_OK) { - if (kstrcmp(dir_info.name, name) == 0) { - ext2_close_dir((struct file_handle_t*)inode_handle); - - lock_release(&inode_handle->ext2->lock); - - ext2_close((struct file_handle_t*)inode_handle); - - return FILE_BUSY; - } - } - - const uint64_t group = (inode_handle->inode_index - 1) / inode_handle->ext2->superblock->s_inodes_per_group; - uint64_t inode_index = alloc_inode(inode_handle->ext2, group); - struct ext2_inode_handle_t* parent_handle = ext2_duplicate((struct ext2_inode_handle_t*)handle); - - sts = FILE_OK; - if (inode_index == 0) { - sts = FILE_ERROR; - goto cleanup; - } - - struct ext2_inode_t parent_inode; - - if (get_inode(parent_handle, &parent_inode)) { - sts = FILE_ERROR; - goto cleanup; - } - - struct ext2_inode_t inode = { - .i_mode = EXT2_S_IFREG, - .i_uid = 0, - .i_size = 0, - .i_atime = 0, - .i_ctime = 0, - .i_mtime = 0, - .i_dtime = 0, - .i_gid = 0, - .i_links_count = 1, - .i_blocks = 0, - .i_flags = 0, - .i_osd1 = 0, - .i_block = { - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 - }, - .i_generation = 0, - .i_file_acl = 0, - .i_dir_acl = 0, - .i_faddr = 0, - .i_osd2 = { - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 - } - }; - - inode_handle->inode_index = inode_index; - - set_inode(inode_handle, &inode); - - uint64_t block; - ext2_open_dir((struct file_handle_t*)parent_handle); - //TODO: allocate on in already used block - while (1) { - switch (get_block(parent_handle->ext2, &parent_inode, parent_handle->seek_block, &block)) { - case BLOCK_SPARSE: - block = assign_block(parent_handle, parent_handle->seek_block, &parent_inode, 1); - - if (!block) { - sts = FILE_ERROR; - goto cleanup; - } - - struct ext2_ll_dir_entry_t* dir_entry = read_block(block, parent_handle->ext2); - *dir_entry = (struct ext2_ll_dir_entry_t){ - .inode = (uint32_t)inode_index, - .rec_len = (uint16_t)parent_handle->ext2->block_size, - .name_len = (uint8_t)kstrlen(name), - .file_type = EXT2_FT_REG_FILE - }; - - kmemcpy(&dir_entry->name, name, dir_entry->name_len); - - dir_entry = write_block(block, parent_handle->ext2, dir_entry); - kfree(dir_entry); - - parent_inode.i_size += parent_handle->ext2->block_size; - set_inode(parent_handle, &parent_inode); - goto cleanup; - case BLOCK_OK: - parent_handle->seek_block++; - continue; - case BLOCK_ERROR: - sts = FILE_ERROR; - goto cleanup; - } - } - -cleanup: - ext2_close_dir((struct file_handle_t*)inode_handle); - - lock_release(&inode_handle->ext2->lock); +static void ext2_delete_final(struct file_handle_t* handle) { + (void)handle; +} - ext2_close((struct file_handle_t*)inode_handle); - ext2_close((struct file_handle_t*)parent_handle); +static enum file_status_t ext2_create_dir(struct file_handle_t* handle) { + (void)handle; - return sts; + return FILE_NO_SUPPORT; } -static enum file_status_t ext2_delete(struct file_handle_t* handle) { +static enum file_status_t ext2_delete_dir(struct file_handle_t* handle) { (void)handle; + return FILE_NO_SUPPORT; } -static void ext2_delete_final(struct file_handle_t* handle) { +static enum file_status_t ext2_truncate(struct file_handle_t* handle, size_t size) { (void)handle; + (void)size; + + return FILE_NO_SUPPORT; } -static enum file_status_t ext2_create_dir(struct file_handle_t* handle, const char* name) { +static enum file_status_t ext2_link(struct file_handle_t* handle, struct file_handle_t* replace) { (void)handle; - (void)name; + (void)replace; return FILE_NO_SUPPORT; } -static enum file_status_t ext2_delete_dir(struct file_handle_t* handle) { +static enum file_status_t ext2_unlink(struct file_handle_t* handle) { (void)handle; return FILE_NO_SUPPORT; @@ -1390,14 +1438,14 @@ uint8_t ext2_attempt_init(struct disk_t* disk, uint64_t start_lba, uint64_t end_ ext2_get_seek, ext2_seek, ext2_write, - ext2_create, - ext2_delete, ext2_delete_final, ext2_open_dir, - ext2_close_dir, ext2_read_dir, ext2_create_dir, - ext2_delete_dir + ext2_delete_dir, + ext2_truncate, + ext2_link, + ext2_unlink ) != FILE_OK) { logging_log_error("Failed to mount rootfs"); panic(PANIC_STATE); diff --git a/kernel/core/elf.c b/kernel/core/elf.c index b0bcfa0..2df7fbb 100644 --- a/kernel/core/elf.c +++ b/kernel/core/elf.c @@ -35,6 +35,7 @@ #include #include #include +#include #define EI_MAG0 0 #define EI_CLASS 4 @@ -109,6 +110,9 @@ #define AT_EXECFN 31 #define AT_SYSINFO_EHDR 33 +#define FD_INIT_SIZE 4 +#define FD_GROWTH 8 + enum at_index_t { AT_INDEX_PHDR, AT_INDEX_PHENT, @@ -537,11 +541,13 @@ struct pcb_t* elf_load(struct fs_handle_t* file, uint64_t pid, const char* invok } } - kmemset(pcb->fd_table, 0, sizeof(struct fs_handle_t*) * MAX_FD); - - pcb->fd_table[0] = fs_open("/dev/ttyS0", FILE_MODE_READ); - pcb->fd_table[1] = fs_open("/dev/ttyS0", FILE_MODE_WRITE); - pcb->fd_table[2] = fs_open("/dev/ttyS0", FILE_MODE_WRITE); + pcb->fd_table = array_list_alloc(FD_INIT_SIZE, FD_GROWTH, 0); + pcb->wd = fs_open("/", FILE_FLAGS_READ | FILE_FLAGS_WRITE); +#ifdef SERIAL + array_list_push(pcb->fd_table, fs_open("/dev/ttyS0", FILE_FLAGS_READ)); + array_list_push(pcb->fd_table, fs_open("/dev/ttyS0", FILE_FLAGS_WRITE)); + array_list_push(pcb->fd_table, fs_open("/dev/ttyS0", FILE_FLAGS_WRITE)); +#endif /* SERIAL */ restore_cr3: diff --git a/kernel/core/fs.c b/kernel/core/fs.c index 1f4dd20..071d5d0 100644 --- a/kernel/core/fs.c +++ b/kernel/core/fs.c @@ -64,15 +64,15 @@ struct vfs_mount_t { fs_get_seek_t get_seek; fs_seek_t seek; fs_write_t write; - fs_create_t create; - fs_delete_t delete; fs_delete_final_t delete_final; fs_open_dir_t open_dir; - fs_close_dir_t close_dir; fs_read_dir_t read_dir; fs_create_dir_t create_dir; fs_delete_dir_t delete_dir; fs_is_interactive_t is_interactive; + fs_truncate_t truncate; + fs_link_t link; + fs_unlink_t unlink; }; struct vfs_open_file_t { @@ -87,7 +87,7 @@ struct fs_handle_t { struct vfs_mount_t* mount; struct file_handle_t* handle; struct vfs_open_file_t* shared; - uint8_t mode; + uint32_t flags; }; struct vfs_tree_node_t { @@ -113,13 +113,13 @@ static struct vfs_mount_t dev_mount = { .get_seek = devfs_get_seek, .seek = devfs_seek, .write = devfs_write, - .create = devfs_create, - .delete = devfs_delete, .delete_final = devfs_delete_final, .open_dir = devfs_open_dir, - .close_dir = devfs_close_dir, .read_dir = devfs_read_dir, - .is_interactive = devfs_is_interactive + .is_interactive = devfs_is_interactive, + .truncate = devfs_truncate, + .link = devfs_link, + .unlink = devfs_unlink }; static uint8_t fs_not_interactive(struct file_handle_t* handle) { @@ -143,11 +143,12 @@ static inline char* path_next(char* path, size_t* len) { } static struct vfs_open_file_t* lookup_register(char* path) { - uint64_t key = fnv64_1a(path, kstrlen(path)); + size_t path_len = kstrlen(path); + uint64_t key = fnv64_1a(path, path_len); struct vfs_open_file_t* file; - while ((file = hash_table_get(open_table, key))) { - if (kstrcmp(path, file->path) == 0) { + while (hash_table_get(open_table, key, (void**)&file)) { + if (kstrcmp(path, file->path + 1) == 0) { break; } @@ -157,8 +158,9 @@ static struct vfs_open_file_t* lookup_register(char* path) { if (!file) { file = kmalloc(sizeof(struct vfs_open_file_t)); - file->path = kmalloc(kstrlen(path) + 1); - kstrcpy(file->path, path); + file->path = kmalloc(path_len + 2); + file->path[0] = '/'; + kstrcpy(file->path + 1, path); file->refs = 0; file->key = key; @@ -181,7 +183,8 @@ static uint8_t lookup_close(struct vfs_open_file_t* file) { } kfree(file->path); - hash_table_remove(open_table, file->key); + void* ign; + hash_table_remove(open_table, file->key, &ign); uint8_t pending_delete = file->pending_delete; @@ -215,14 +218,14 @@ enum file_status_t fs_mount( fs_get_seek_t get_seek, fs_seek_t seek, fs_write_t write, - fs_create_t create, - fs_delete_t delete, fs_delete_final_t delete_final, fs_open_dir_t open_dir, - fs_close_dir_t close_dir, fs_read_dir_t read_dir, fs_create_dir_t create_dir, - fs_delete_dir_t delete_dir + fs_delete_dir_t delete_dir, + fs_truncate_t truncate, + fs_link_t link, + fs_unlink_t unlink ) { if (kstrcmp(mountpoint, "") && !vfs_root.mount) { @@ -241,14 +244,14 @@ enum file_status_t fs_mount( vfs_root.mount->get_seek = get_seek; vfs_root.mount->seek = seek; vfs_root.mount->write = write; - vfs_root.mount->create = create; - vfs_root.mount->delete = delete; vfs_root.mount->delete_final = delete_final; vfs_root.mount->open_dir = open_dir; - vfs_root.mount->close_dir = close_dir; vfs_root.mount->read_dir = read_dir; vfs_root.mount->create_dir = create_dir; vfs_root.mount->delete_dir = delete_dir; + vfs_root.mount->truncate = truncate; + vfs_root.mount->link = link; + vfs_root.mount->unlink = unlink; vfs_root.mount->is_interactive = fs_not_interactive; @@ -348,7 +351,7 @@ static const char* find_mount(const char* path, struct vfs_mount_t** mount_out, return mount_path; } -struct fs_handle_t* fs_open(const char* path, uint8_t mode) { +struct fs_handle_t* fs_open_mode(const char* path, uint32_t flags, uint32_t mode) { struct vfs_mount_t* mount; void* clean_path; char* path_write; @@ -359,7 +362,7 @@ struct fs_handle_t* fs_open(const char* path, uint8_t mode) { return 0; } - struct file_handle_t* handle = mount->open(mount->cntx, mount_path); + struct file_handle_t* handle = mount->open(mount->cntx, mount_path, flags, mode); if (!handle) { return 0; @@ -375,10 +378,33 @@ struct fs_handle_t* fs_open(const char* path, uint8_t mode) { fs_handle->handle = handle; fs_handle->mount = mount; fs_handle->shared = open_file; - fs_handle->mode = mode; + fs_handle->flags = flags; return fs_handle; } +struct fs_handle_t* fs_open(const char* path, uint32_t flags) { + return fs_open_mode(path, flags, 0); +} + +struct fs_handle_t* fs_openat(const char* path, uint32_t flags, struct fs_handle_t* at, uint32_t mode) { + + if (*path == '/') { + // absolute, no at + return fs_open_mode(path, flags, mode); + } + else { + size_t prefix_len = kstrlen(at->shared->path); + size_t suffix_len = kstrlen(path); + char* full_path = kmalloc(prefix_len + suffix_len + 1); + kmemcpy(full_path, at->shared->path, prefix_len); + kmemcpy(full_path + prefix_len, path, suffix_len); + full_path[prefix_len + suffix_len] = 0; + struct fs_handle_t* ret = fs_open_mode(full_path, flags, mode); + kfree(full_path); + return ret; + } +} + void fs_close(struct fs_handle_t* handle) { semaphore_wait_full(fs_sem); if (lookup_close(handle->shared)) { @@ -405,7 +431,7 @@ enum file_status_t fs_stat(struct fs_handle_t* handle, struct file_info_t* info) size_t fs_read(struct fs_handle_t* handle, void* buffer, size_t count) { size_t ret; - if (!(handle->mode & FILE_MODE_READ)) { + if (!(handle->flags & FILE_FLAGS_READ)) { return 0; } @@ -429,97 +455,109 @@ uint64_t fs_get_seek(struct fs_handle_t* handle) { enum file_status_t fs_seek(struct fs_handle_t* handle, uint64_t seek) { enum file_status_t sts; - lock_release(&handle->shared->lock); + lock_acquire(&handle->shared->lock); sts = handle->mount->seek(handle->handle, seek); lock_release(&handle->shared->lock); return sts; } -size_t fs_write(struct fs_handle_t* handle, void* buffer, size_t count) { +size_t fs_write(struct fs_handle_t* handle, const void* buffer, size_t count) { size_t ret; - if (!(handle->mode & FILE_MODE_WRITE)) { + if (!(handle->flags & FILE_FLAGS_WRITE)) { return 0; } - lock_release(&handle->shared->lock); + lock_acquire(&handle->shared->lock); ret = handle->mount->write(handle->handle, buffer, count); lock_release(&handle->shared->lock); return ret; } -enum file_status_t fs_create(struct fs_handle_t* handle, const char* name) { +struct fs_handle_t* fs_open_dir(struct fs_handle_t* handle) { enum file_status_t sts; lock_acquire(&handle->shared->lock); - sts = handle->mount->create(handle->handle, name); + sts = handle->mount->open_dir(handle->handle); lock_release(&handle->shared->lock); - return sts; + if (sts != FILE_OK) { + return 0; + } + + return handle; } -enum file_status_t fs_delete(struct fs_handle_t* handle) { +enum file_status_t fs_create_dir(struct fs_handle_t* handle) { enum file_status_t sts; lock_acquire(&handle->shared->lock); - sts = handle->mount->delete(handle->handle); - handle->shared->pending_delete = 1; + sts = handle->mount->create_dir(handle->handle); lock_release(&handle->shared->lock); return sts; } -struct fs_handle_t* fs_open_dir(struct fs_handle_t* handle) { +enum file_status_t fs_delete_dir(struct fs_handle_t* handle) { enum file_status_t sts; lock_acquire(&handle->shared->lock); - sts = handle->mount->open_dir(handle->handle); + sts = handle->mount->delete_dir(handle->handle); lock_release(&handle->shared->lock); - if (sts != FILE_OK) { - return 0; - } - - return handle; + return sts; } -void fs_close_dir(struct fs_handle_t* handle) { +enum file_status_t fs_read_dir(struct fs_handle_t* handle, struct dir_info_t* info) { + enum file_status_t sts; + lock_acquire(&handle->shared->lock); - handle->mount->close_dir(handle->handle); + sts = handle->mount->read_dir(handle->handle, info); lock_release(&handle->shared->lock); + + return sts; } -enum file_status_t fs_read_dir(struct fs_handle_t* handle, struct dir_info_t* info) { +enum file_status_t fs_truncate(struct fs_handle_t* handle, size_t size) { enum file_status_t sts; lock_acquire(&handle->shared->lock); - sts = handle->mount->read_dir(handle->handle, info); + sts = handle->mount->truncate(handle->handle, size); lock_release(&handle->shared->lock); return sts; + } -enum file_status_t fs_create_dir(struct fs_handle_t* handle, const char* name) { +enum file_status_t fs_link(struct fs_handle_t* handle, struct fs_handle_t* replace) { enum file_status_t sts; + if (handle->mount != replace->mount) { + return FILE_BAD_FLAGS; // cannot create hardlink between filesystems + } + lock_acquire(&handle->shared->lock); - sts = handle->mount->create_dir(handle->handle, name); + sts = handle->mount->link(handle->handle, replace->handle); lock_release(&handle->shared->lock); return sts; } -enum file_status_t fs_delete_dir(struct fs_handle_t* handle) { +enum file_status_t fs_unlink(struct fs_handle_t* handle) { enum file_status_t sts; lock_acquire(&handle->shared->lock); - sts = handle->mount->delete_dir(handle->handle); - handle->shared->pending_delete = 1; + sts = handle->mount->unlink(handle->handle); lock_release(&handle->shared->lock); return sts; + +} + +void fs_path(struct fs_handle_t* handle, size_t max_len, char* buf) { + kstrncpy(buf, handle->shared->path, max_len); } uint8_t fs_is_interactive(struct fs_handle_t* handle) { diff --git a/kernel/core/kentry.c b/kernel/core/kentry.c index 0764476..92b6065 100644 --- a/kernel/core/kentry.c +++ b/kernel/core/kentry.c @@ -194,8 +194,11 @@ void kapentry(uint64_t arb_id) { void prepare_userland(void* cntx) { (void)cntx; - struct fs_handle_t* f = fs_open("/", FILE_MODE_READ | FILE_MODE_WRITE); - fs_create(f, "test.txt"); + struct fs_handle_t* f = fs_open("/test.txt", FILE_FLAGS_READ | FILE_FLAGS_WRITE | FILE_FLAGS_CREATE); + if (f == 0) { + logging_log_error("Failed to create /test.txt"); + } + fs_write(f, "Hi\n", 3); fs_close(f); lock_acquire(&prepare_userland_lock); @@ -207,7 +210,7 @@ void prepare_userland(void* cntx) { init_done = 1; lock_release(&prepare_userland_lock); - struct fs_handle_t* shell = fs_open("/bin/shell", FILE_MODE_READ); + struct fs_handle_t* shell = fs_open("/bin/shell", FILE_FLAGS_READ); if (!shell) { logging_log_error("Failed to open shell file"); } diff --git a/kernel/core/process.c b/kernel/core/process.c index 991bccf..bd40de1 100644 --- a/kernel/core/process.c +++ b/kernel/core/process.c @@ -32,6 +32,7 @@ #include #include +#include #include @@ -70,7 +71,8 @@ void process_init_ap(uint64_t init_rsp_vaddr, uint64_t init_rsp_paddr) { pcb->init_k_rsp_vaddr = init_rsp_vaddr; pcb->init_k_rsp_paddr = init_rsp_paddr; pcb->sched_cntr = SCHED_SKIP; - kmemset(pcb->fd_table, 0, sizeof(struct fs_handle_t*) * MAX_FD); + pcb->fd_table = array_list_alloc(1, 1, 0); + pcb->wd = 0; proc_data_get()->current_process = pcb; proc_data_get()->current_process->pid = process_assign_pid(); proc_data_get()->current_process->cr3 = 0; @@ -126,11 +128,8 @@ struct pcb_t* process_from_vaddr(uint64_t vaddr) { pcb->pid = process_assign_pid(); - kmemset(pcb->fd_table, 0, sizeof(struct fs_handle_t*) * MAX_FD); - - pcb->fd_table[0] = fs_open("/dev/ttyS0", FILE_MODE_READ); - pcb->fd_table[1] = fs_open("/dev/ttyS0", FILE_MODE_WRITE); - pcb->fd_table[2] = fs_open("/dev/ttyS0", FILE_MODE_WRITE); + pcb->fd_table = array_list_alloc(1, 1, 0); + pcb->wd = fs_open("/", FILE_FLAGS_READ | FILE_FLAGS_WRITE); return pcb; } @@ -157,6 +156,10 @@ void process_kill_current(void) { cpu_wait_loop(); } +static void close_fd(void* handle) { + fs_close(handle); +} + void process_discard(struct pcb_t* pcb) { _Static_assert(INIT_STACK_SIZE == 4 * PAGE_SIZE_4K, "stack size must be page size multiple of four"); paging_unmap(pcb->init_k_rsp_vaddr + 1 * PAGE_SIZE_4K, PAGE_4K); @@ -172,13 +175,12 @@ void process_discard(struct pcb_t* pcb) { paging_free_userspace((uint64_t*)pcb->cr3); } - for (uint64_t i = 0; i < MAX_FD; i++) { - if (pcb->fd_table[i]) { - fs_close(pcb->fd_table[i]); - } + array_list_clear(pcb->fd_table, close_fd); + if (pcb->wd) { + fs_close(pcb->wd); } - logging_log_debug("Killed %ld", pcb->pid); + logging_log_debug("Killed %lu (%ld)", pcb->pid, pcb->exit_code); kfree(pcb); } diff --git a/kernel/core/signal.c b/kernel/core/signal.c index 790976a..6266ee9 100644 --- a/kernel/core/signal.c +++ b/kernel/core/signal.c @@ -55,7 +55,7 @@ void signal_wait(struct signal_wait_t* wait) { process_set_callback(signal_wait_callback); while (current->sched_cntr != SCHED_SIGNAL_READY) { - cpu_wait_loop(); + cpu_hlt(); } current->sched_cntr = SCHED_READY; diff --git a/kernel/core/syscall.S b/kernel/core/syscall.S index b620702..3b80822 100644 --- a/kernel/core/syscall.S +++ b/kernel/core/syscall.S @@ -64,22 +64,27 @@ sysretq syscall_handlers: .quad syscall_dispatch_exit -.quad syscall_dispatch_open +.quad syscall_dispatch_openat .quad syscall_dispatch_close .quad syscall_dispatch_read .quad syscall_dispatch_write .quad syscall_dispatch_alloc -.quad syscall_dispatch_create -.quad syscall_dispatch_delete +.quad 0 +.quad 0 .quad syscall_dispatch_open_dir .quad syscall_dispatch_read_dir -.quad syscall_dispatch_close_dir +.quad syscall_dispatch_truncate .quad syscall_dispatch_seek .quad syscall_dispatch_tell .quad syscall_dispatch_create_dir .quad syscall_dispatch_delete_dir .quad syscall_dispatch_epoch_time .quad syscall_dispatch_is_a_tty +.quad syscall_dispatch_gcwd +.quad syscall_dispatch_ccwd +.quad syscall_dispatch_link +.quad syscall_dispatch_unlink +.quad syscall_dispatch_stat .set num_entries, . - syscall_handlers .if num_entries != SYSCALL_MAX * 8 diff --git a/kernel/core/syscall_dispatch.c b/kernel/core/syscall_dispatch.c index c16ddde..02472c6 100644 --- a/kernel/core/syscall_dispatch.c +++ b/kernel/core/syscall_dispatch.c @@ -30,6 +30,7 @@ #include #include +#include #define ARGC_0 \ (void)arg1; \ @@ -66,47 +67,54 @@ #define ARGC_6 +#define USERLAND_AT_FDCWD -100 + DECLARE_SYSCALL(exit) { ARGC_1; - //TODO: handle exit code - (void)arg1; + struct pcb_t* pcb = proc_data_get()->current_process; + pcb->exit_code = arg1; process_kill_current(); } -DECLARE_SYSCALL(open) { - ARGC_2; +DECLARE_SYSCALL(openat) { + ARGC_4; - int fd; struct pcb_t* pcb = proc_data_get()->current_process; + struct fs_handle_t* at; - for (fd = 0; fd < MAX_FD; fd++) { - if (!pcb->fd_table[fd]) { - pcb->fd_table[fd] = fs_open((const char*)arg1, (uint8_t)arg2); - if (!pcb->fd_table[fd]) { - return SYSCALL_STS_FAIL; - } + if ((int32_t)arg3 == USERLAND_AT_FDCWD) { + at = pcb->wd; + } + else { + at = array_list_get(pcb->fd_table, arg1); + } - return (uint64_t)fd; - } + if (!at) { + return SYSCALL_STS_FAIL; } - return SYSCALL_STS_FAIL; + struct fs_handle_t* handle = fs_openat((const char*)arg1, (uint32_t)arg2, at, (uint32_t)arg4); + if (!handle) { + return SYSCALL_STS_FAIL; + } + + return array_list_push(pcb->fd_table, handle); } DECLARE_SYSCALL(close) { ARGC_1; struct pcb_t* pcb = proc_data_get()->current_process; - struct fs_handle_t* handle = pcb->fd_table[arg1]; + struct fs_handle_t* handle = array_list_get(pcb->fd_table, arg1); if (!handle) { return SYSCALL_STS_FAIL; } fs_close(handle); - pcb->fd_table[arg1] = 0; + array_list_remove(pcb->fd_table, arg1); return SYSCALL_STS_OK; } @@ -115,7 +123,7 @@ DECLARE_SYSCALL(read) { ARGC_3; struct pcb_t* pcb = proc_data_get()->current_process; - struct fs_handle_t* handle = pcb->fd_table[arg1]; + struct fs_handle_t* handle = array_list_get(pcb->fd_table, arg1); if (!handle) { return SYSCALL_STS_FAIL; @@ -128,7 +136,7 @@ DECLARE_SYSCALL(write) { ARGC_3; struct pcb_t* pcb = proc_data_get()->current_process; - struct fs_handle_t* handle = pcb->fd_table[arg1]; + struct fs_handle_t* handle = array_list_get(pcb->fd_table, arg1); if (!handle) { return SYSCALL_STS_FAIL; @@ -148,7 +156,7 @@ DECLARE_SYSCALL(alloc) { uint64_t paddr = mm_alloc_p(arg1); if (!paddr) { - return 0; + return SYSCALL_STS_FAIL; } uint64_t vaddr = pcb->mem_top; @@ -165,141 +173,193 @@ DECLARE_SYSCALL(alloc) { return vaddr; } -DECLARE_SYSCALL(create) { +DECLARE_SYSCALL(open_dir) { + ARGC_1; + + struct pcb_t* pcb = proc_data_get()->current_process; + struct fs_handle_t* handle = array_list_get(pcb->fd_table, arg1); + + if (!handle) { + return SYSCALL_STS_FAIL; + } + + return (uint64_t)fs_open_dir(handle); +} + +DECLARE_SYSCALL(read_dir) { + ARGC_3; + + (void)arg1; + (void)arg2; + (void)arg3; + + //TODO + return SYSCALL_STS_FAIL; +} + +DECLARE_SYSCALL(truncate) { ARGC_2; - + struct pcb_t* pcb = proc_data_get()->current_process; - struct fs_handle_t* handle = pcb->fd_table[arg1]; + struct fs_handle_t* handle = array_list_get(pcb->fd_table, arg1); if (!handle) { return SYSCALL_STS_FAIL; } - return fs_create(handle, (const char*)arg2) == FILE_OK; + return (fs_truncate(handle, (size_t)arg2) == FILE_OK) ? SYSCALL_STS_OK : SYSCALL_STS_FAIL; } -DECLARE_SYSCALL(delete) { - ARGC_1; +DECLARE_SYSCALL(seek) { + ARGC_2; struct pcb_t* pcb = proc_data_get()->current_process; - struct fs_handle_t* handle = pcb->fd_table[arg1]; + struct fs_handle_t* handle = array_list_get(pcb->fd_table, arg1); if (!handle) { return SYSCALL_STS_FAIL; } - return fs_delete(handle) == FILE_OK; + fs_seek(handle, (uint64_t)arg2); + return fs_get_seek(handle); } -DECLARE_SYSCALL(open_dir) { +DECLARE_SYSCALL(tell) { ARGC_1; struct pcb_t* pcb = proc_data_get()->current_process; - struct fs_handle_t* handle = pcb->fd_table[arg1]; + struct fs_handle_t* handle = array_list_get(pcb->fd_table, arg1); if (!handle) { return SYSCALL_STS_FAIL; } - return (uint64_t)fs_open_dir(handle); + return fs_get_seek(handle); } -DECLARE_SYSCALL(read_dir) { - ARGC_2; +DECLARE_SYSCALL(create_dir) { + ARGC_1; struct pcb_t* pcb = proc_data_get()->current_process; - struct fs_handle_t* handle = pcb->fd_table[arg1]; + struct fs_handle_t* handle = array_list_get(pcb->fd_table, arg1); if (!handle) { return SYSCALL_STS_FAIL; } - return fs_read_dir(handle, (struct dir_info_t*)arg2) == FILE_OK; + return (fs_create_dir(handle) == FILE_OK) ? SYSCALL_STS_OK : SYSCALL_STS_FAIL; } -DECLARE_SYSCALL(close_dir) { +DECLARE_SYSCALL(delete_dir) { ARGC_1; struct pcb_t* pcb = proc_data_get()->current_process; - struct fs_handle_t* handle = pcb->fd_table[arg1]; + struct fs_handle_t* handle = array_list_get(pcb->fd_table, arg1); if (!handle) { return SYSCALL_STS_FAIL; } - fs_close_dir(handle); + return (fs_delete_dir(handle) == FILE_OK) ? SYSCALL_STS_OK : SYSCALL_STS_FAIL; +} - return SYSCALL_STS_OK; +DECLARE_SYSCALL(epoch_time) { + ARGC_0; + + return time_since_init_ns(); } -DECLARE_SYSCALL(seek) { - ARGC_2; +DECLARE_SYSCALL(is_a_tty) { + ARGC_1; struct pcb_t* pcb = proc_data_get()->current_process; - struct fs_handle_t* handle = pcb->fd_table[arg1]; + struct fs_handle_t* handle = array_list_get(pcb->fd_table, arg1); if (!handle) { return SYSCALL_STS_FAIL; } - fs_seek(handle, (uint64_t)arg2); - return fs_get_seek(handle); + return fs_is_interactive(handle); } -DECLARE_SYSCALL(tell) { +DECLARE_SYSCALL(gcwd) { + ARGC_2; + + struct pcb_t* pcb = proc_data_get()->current_process; + + fs_path(pcb->wd, (size_t)arg2, (char*)arg1); + + return SYSCALL_STS_FAIL; +} + +DECLARE_SYSCALL(ccwd) { ARGC_1; struct pcb_t* pcb = proc_data_get()->current_process; - struct fs_handle_t* handle = pcb->fd_table[arg1]; + struct fs_handle_t* handle = array_list_get(pcb->fd_table, arg1); if (!handle) { return SYSCALL_STS_FAIL; } - return fs_get_seek(handle); + pcb->wd = handle; + + return SYSCALL_STS_OK; } -DECLARE_SYSCALL(create_dir) { +DECLARE_SYSCALL(link) { ARGC_2; struct pcb_t* pcb = proc_data_get()->current_process; - struct fs_handle_t* handle = pcb->fd_table[arg1]; + struct fs_handle_t* handle1 = array_list_get(pcb->fd_table, arg1); - if (!handle) { + if (!handle1) { + return SYSCALL_STS_FAIL; + } + + struct fs_handle_t* handle2 = array_list_get(pcb->fd_table, arg2); + + if (!handle2) { return SYSCALL_STS_FAIL; } - return fs_create_dir(handle, (const char*)arg2) == FILE_OK; + return (fs_link(handle1, handle2) == FILE_OK) ? SYSCALL_STS_OK : SYSCALL_STS_FAIL; } -DECLARE_SYSCALL(delete_dir) { +DECLARE_SYSCALL(unlink) { ARGC_1; struct pcb_t* pcb = proc_data_get()->current_process; - struct fs_handle_t* handle = pcb->fd_table[arg1]; + struct fs_handle_t* handle = array_list_get(pcb->fd_table, arg1); if (!handle) { return SYSCALL_STS_FAIL; } - return fs_delete_dir(handle) == FILE_OK; -} - -DECLARE_SYSCALL(epoch_time) { - ARGC_0; - - return time_since_init_ns(); + return (fs_unlink(handle) == FILE_OK) ? SYSCALL_STS_OK : SYSCALL_STS_FAIL; } -DECLARE_SYSCALL(is_a_tty) { - ARGC_1; +DECLARE_SYSCALL(stat) { + ARGC_2; struct pcb_t* pcb = proc_data_get()->current_process; - struct fs_handle_t* handle = pcb->fd_table[arg1]; + struct fs_handle_t* handle = array_list_get(pcb->fd_table, arg1); if (!handle) { return SYSCALL_STS_FAIL; } - return fs_is_interactive(handle); + struct userland_stat_t { + size_t st_size; + }; + + struct file_info_t info; + if (fs_stat(handle, &info) != FILE_OK) { + return SYSCALL_STS_FAIL; + } + + struct userland_stat_t* u_stat = (struct userland_stat_t*)arg2; + u_stat->st_size = info.size; + + return SYSCALL_STS_OK; } diff --git a/kernel/devfs/devfs.c b/kernel/devfs/devfs.c index e445c97..9d1ad01 100644 --- a/kernel/devfs/devfs.c +++ b/kernel/devfs/devfs.c @@ -35,8 +35,10 @@ struct dev_handle_t { } type; }; -struct file_handle_t* devfs_open(struct mount_cntx_t* cntx, const char* path) { +struct file_handle_t* devfs_open(struct mount_cntx_t* cntx, const char* path, uint32_t flags, uint32_t mode) { (void)cntx; + (void)flags; + (void)mode; struct dev_handle_t* dev_handle; // tty devices @@ -129,7 +131,7 @@ enum file_status_t devfs_seek(struct file_handle_t* handle, uint64_t seek) { } } -size_t devfs_write(struct file_handle_t* handle, void* buffer, size_t count) { +size_t devfs_write(struct file_handle_t* handle, const void* buffer, size_t count) { struct dev_handle_t* dev_handle = (struct dev_handle_t*)handle; if (!dev_handle) { @@ -143,44 +145,49 @@ size_t devfs_write(struct file_handle_t* handle, void* buffer, size_t count) { } } -enum file_status_t devfs_create(struct file_handle_t* handle, const char* name) { +void devfs_delete_final(struct file_handle_t* handle) { (void)handle; - (void)name; - return FILE_NO_SUPPORT; } -enum file_status_t devfs_delete(struct file_handle_t* handle) { +enum file_status_t devfs_open_dir(struct file_handle_t* handle) { (void)handle; return FILE_NO_SUPPORT; } -void devfs_delete_final(struct file_handle_t* handle) { +enum file_status_t devfs_read_dir(struct file_handle_t* handle, struct dir_info_t* info) { (void)handle; + (void)info; + return FILE_NO_SUPPORT; } -enum file_status_t devfs_open_dir(struct file_handle_t* handle) { +enum file_status_t devfs_create_dir(struct file_handle_t* handle, const char* name) { (void)handle; + (void)name; + return FILE_NO_SUPPORT; } -void devfs_close_dir(struct file_handle_t* handle) { +enum file_status_t devfs_delete_dir(struct file_handle_t* handle) { (void)handle; + + return FILE_NO_SUPPORT; } -enum file_status_t devfs_read_dir(struct file_handle_t* handle, struct dir_info_t* info) { +enum file_status_t devfs_truncate(struct file_handle_t* handle, size_t size) { (void)handle; - (void)info; + (void)size; + return FILE_NO_SUPPORT; } -enum file_status_t devfs_create_dir(struct file_handle_t* handle, const char* name) { +enum file_status_t devfs_link(struct file_handle_t* handle, struct file_handle_t* replace) { (void)handle; - (void)name; + (void)replace; return FILE_NO_SUPPORT; } -enum file_status_t devfs_delete_dir(struct file_handle_t* handle) { +enum file_status_t devfs_unlink(struct file_handle_t* handle) { (void)handle; return FILE_NO_SUPPORT; diff --git a/kernel/devfs/tty.c b/kernel/devfs/tty.c index a39c577..687bf30 100644 --- a/kernel/devfs/tty.c +++ b/kernel/devfs/tty.c @@ -146,22 +146,22 @@ size_t tty_read(struct tty_handle_t* tty, void* buffer, size_t count) { return read; } -void tty_write(struct tty_handle_t* tty, void* buffer, size_t count) { +void tty_write(struct tty_handle_t* tty, const void* buffer, size_t count) { for (size_t i = 0; i < count; i++) { - uint8_t val = ((uint8_t*)buffer)[i]; + uint8_t val = ((const uint8_t*)buffer)[i]; switch (val) { case '\n': tty->writer('\r'); __attribute__((fallthrough)); default: - tty->writer(((uint8_t*)buffer)[i]); + tty->writer(((const uint8_t*)buffer)[i]); break; } } } uint8_t tty_queue_read(struct tty_handle_t* tty, uint8_t byte) { - if (FULL(tty->read_index, tty->write_index)) { + if (byte == 0 || FULL(tty->read_index, tty->write_index)) { return 0; } diff --git a/kernel/include/core/fs.h b/kernel/include/core/fs.h index baad35d..11456d6 100644 --- a/kernel/include/core/fs.h +++ b/kernel/include/core/fs.h @@ -21,8 +21,10 @@ #include #include -#define FILE_MODE_READ 0x1 -#define FILE_MODE_WRITE 0x2 +#define FILE_FLAGS_READ 0x1 +#define FILE_FLAGS_WRITE 0x2 + +#define FILE_FLAGS_CREATE 0100 #define FILE_INFO_UNK 0 #define FILE_INFO_REG 1 @@ -40,7 +42,7 @@ enum file_status_t { FILE_DNE, FILE_BUSY, FILE_NO_SUPPORT, - FILE_BAD_MODE, + FILE_BAD_FLAGS, FILE_NOT_DIR, }; @@ -61,26 +63,27 @@ struct dir_info_t { char name[256]; }; -typedef struct file_handle_t* (*fs_open_t)(struct mount_cntx_t*, const char*); +typedef struct file_handle_t* (*fs_open_t)(struct mount_cntx_t*, const char*, uint32_t, uint32_t); typedef void (*fs_close_t)(struct file_handle_t*); typedef enum file_status_t (*fs_stat_t)(struct file_handle_t*, struct file_info_t*); typedef size_t (*fs_read_t)(struct file_handle_t*, void*, size_t); typedef uint64_t (*fs_get_seek_t)(struct file_handle_t*); typedef enum file_status_t (*fs_seek_t)(struct file_handle_t*, uint64_t); -typedef size_t (*fs_write_t)(struct file_handle_t*, void*, size_t); -typedef enum file_status_t (*fs_create_t)(struct file_handle_t*, const char*); -typedef enum file_status_t (*fs_delete_t)(struct file_handle_t*); +typedef size_t (*fs_write_t)(struct file_handle_t*, const void*, size_t); typedef void (*fs_delete_final_t)(struct file_handle_t*); typedef enum file_status_t (*fs_open_dir_t)(struct file_handle_t*); -typedef void (*fs_close_dir_t)(struct file_handle_t*); typedef enum file_status_t (*fs_read_dir_t)(struct file_handle_t*, struct dir_info_t*); -typedef enum file_status_t (*fs_create_dir_t)(struct file_handle_t*, const char*); +typedef enum file_status_t (*fs_create_dir_t)(struct file_handle_t*); typedef enum file_status_t (*fs_delete_dir_t)(struct file_handle_t*); +typedef enum file_status_t (*fs_truncate_t)(struct file_handle_t*, size_t); +typedef enum file_status_t (*fs_link_t)(struct file_handle_t*, struct file_handle_t*); +typedef enum file_status_t (*fs_unlink_t)(struct file_handle_t*); + typedef uint8_t (*fs_is_interactive_t)(struct file_handle_t*); void fs_init(void); @@ -95,35 +98,41 @@ enum file_status_t fs_mount( fs_get_seek_t get_seek, fs_seek_t seek, fs_write_t write, - fs_create_t create, - fs_delete_t delete, fs_delete_final_t delete_final, fs_open_dir_t open_dir, - fs_close_dir_t close_dir, fs_read_dir_t read_dir, fs_create_dir_t create_dir, - fs_delete_dir_t delete_dir + fs_delete_dir_t delete_dir, + fs_truncate_t truncate, + fs_link_t link, + fs_unlink_t unlink ); -extern struct fs_handle_t* fs_open(const char* path, uint8_t mode); +extern struct fs_handle_t* fs_open_mode(const char* path, uint32_t flags, uint32_t mode); +extern struct fs_handle_t* fs_open(const char* path, uint32_t flags); extern void fs_close(struct fs_handle_t* handle); +extern struct fs_handle_t* fs_openat(const char* path, uint32_t flags, struct fs_handle_t* at, uint32_t mode); + extern enum file_status_t fs_stat(struct fs_handle_t* handle, struct file_info_t* info); extern size_t fs_read(struct fs_handle_t* handle, void* buffer, size_t count); extern uint64_t fs_get_seek(struct fs_handle_t* handle); extern enum file_status_t fs_seek(struct fs_handle_t* handle, uint64_t seek); -extern size_t fs_write(struct fs_handle_t* handle, void* buffer, size_t count); -extern enum file_status_t fs_create(struct fs_handle_t* handle, const char* name); -extern enum file_status_t fs_delete(struct fs_handle_t* handle); +extern size_t fs_write(struct fs_handle_t* handle, const void* buffer, size_t count); -extern struct fs_handle_t* fs_open_dir(struct fs_handle_t* handle); -extern void fs_close_dir(struct fs_handle_t* handle); +extern struct fs_handle_t* fs_open_dir(struct fs_handle_t* handle); // invalidates old handle extern enum file_status_t fs_read_dir(struct fs_handle_t* handle, struct dir_info_t* info); -extern enum file_status_t fs_create_dir(struct fs_handle_t* handle, const char* name); +extern enum file_status_t fs_create_dir(struct fs_handle_t* handle); extern enum file_status_t fs_delete_dir(struct fs_handle_t* handle); +extern enum file_status_t fs_truncate(struct fs_handle_t* handle, size_t size); +extern enum file_status_t fs_link(struct fs_handle_t* handle, struct fs_handle_t* replace); +extern enum file_status_t fs_unlink(struct fs_handle_t* handle); + extern uint8_t fs_is_interactive(struct fs_handle_t* handle); +extern void fs_path(struct fs_handle_t* handle, size_t max_len, char* buf); + #endif /* KERNEL_CORE_FS_H */ diff --git a/kernel/include/core/process.h b/kernel/include/core/process.h index 25e5d74..eab2c86 100644 --- a/kernel/include/core/process.h +++ b/kernel/include/core/process.h @@ -25,8 +25,9 @@ #include #include -#define MAX_FD 256 -#define MAX_META 1 +#include + +#define MAX_META 1 struct pcb_t; @@ -68,7 +69,10 @@ struct pcb_t { struct pcb_t* next; - struct fs_handle_t* fd_table[MAX_FD]; + uint64_t exit_code; + + struct fs_handle_t* wd; + struct array_list_t* fd_table; uint8_t fxdata[512] __attribute__((aligned(16))); diff --git a/kernel/include/core/syscall_dispatch.h b/kernel/include/core/syscall_dispatch.h index 09fc287..fef9737 100644 --- a/kernel/include/core/syscall_dispatch.h +++ b/kernel/include/core/syscall_dispatch.h @@ -43,21 +43,26 @@ typedef uint64_t (*syscall_dispatch_t)( extern syscall_dispatch_t syscall_handlers[SYSCALL_MAX]; extern DECLARE_SYSCALL(exit); -extern DECLARE_SYSCALL(open); +extern DECLARE_SYSCALL(openat); extern DECLARE_SYSCALL(close); extern DECLARE_SYSCALL(read); extern DECLARE_SYSCALL(write); extern DECLARE_SYSCALL(alloc); -extern DECLARE_SYSCALL(create); -extern DECLARE_SYSCALL(delete); +// reserved +// reserved extern DECLARE_SYSCALL(open_dir); extern DECLARE_SYSCALL(read_dir); -extern DECLARE_SYSCALL(close_dir); +extern DECLARE_SYSCALL(truncate); extern DECLARE_SYSCALL(seek); extern DECLARE_SYSCALL(tell); extern DECLARE_SYSCALL(create_dir); extern DECLARE_SYSCALL(delete_dir); extern DECLARE_SYSCALL(epoch_time); extern DECLARE_SYSCALL(is_a_tty); +extern DECLARE_SYSCALL(gcwd); +extern DECLARE_SYSCALL(ccwd); +extern DECLARE_SYSCALL(link); +extern DECLARE_SYSCALL(unlink); +extern DECLARE_SYSCALL(stat); #endif /* KERNEL_CORE_SYSCALL_DISPATCH_H */ diff --git a/kernel/include/core/syscall_vectors.h b/kernel/include/core/syscall_vectors.h index 005daa6..86dfd20 100644 --- a/kernel/include/core/syscall_vectors.h +++ b/kernel/include/core/syscall_vectors.h @@ -43,10 +43,12 @@ /* * rdi: path (const char*) - * rsi: mode (uint8_t) + * rsi: flags (uint8_t) + * rdx: at (int) + * r8 : mode (int) * ret: handle (int) */ -#define SYSCALL_OPEN 1 +#define SYSCALL_OPENAT 1 /* * rdi: handle (int) @@ -77,36 +79,35 @@ #define SYSCALL_ALLOC 5 /* - * rdi: handle (int) - * rsi: name (const char*) - * ret: success (int) + * reserved */ -#define SYSCALL_CREATE 6 +#define SYSCALL_RESV1 6 /* - * rdi: handle (int) - * ret: success (int) + * reserved */ -#define SYSCALL_DELETE 7 +#define SYSCALL_RESV2 7 /* * rdi: handle (int) - * ret handle (void*) + * ret handle (int) */ #define SYSCALL_OPEN_DIR 8 /* - * rdi: handle (void*) + * rdi: handle (int) * rsi: info buffer (void*) - * ret: success (int) + * rdx: max_size (size_t) + * ret: size (size_t) */ #define SYSCALL_READ_DIR 9 /* - * rdi: handle (void*) - * ret: (void) + * rdi: handle (int) + * rsi: size (size_t) + * ret: success (int) */ -#define SYSCALL_CLOSE_DIR 10 +#define SYSCALL_TRUNCATE 10 /* * rdi: handle (int) @@ -116,14 +117,13 @@ #define SYSCALL_SEEK 11 /* - * rdi: handle (int) + * rdi: handle * ret: seek (long int) */ #define SYSCALL_TELL 12 /* * rdi: handle (int) - * rsi: name (const char*) * ret: success (int) */ #define SYSCALL_CREATE_DIR 13 @@ -141,10 +141,43 @@ /* * rdi: handle (int) - * ret: 1 on tty. 0 otherwise + * ret: 1 on tty. 0 otherwise (int) */ #define SYSCALL_IS_A_TTY 16 -#define SYSCALL_MAX 17 +/* + * rdi: buffer (char*) + * rsi: max len (size_t) + * ret: success (int) + */ +#define SYSCALL_GCWD 17 + +/* + * rdi: handle (int) + * ret: success (int) + */ +#define SYSCALL_CCWD 18 + +/* + * rdi: handle + * rsi: replace handle + * ret: success (int) + */ +#define SYSCALL_LINK 19 + +/* + * rdi: handle (int) + * ret: success (int) + */ +#define SYSCALL_UNLINK 20 + +/* + * rdi: handle (int) + * rsi: statbuf (struct file_info_t*) + * ret: success (int) + */ +#define SYSCALL_STAT 21 + +#define SYSCALL_MAX 22 diff --git a/kernel/include/devfs/devfs.h b/kernel/include/devfs/devfs.h index c27ee9f..5143e7c 100644 --- a/kernel/include/devfs/devfs.h +++ b/kernel/include/devfs/devfs.h @@ -23,26 +23,27 @@ #include -extern struct file_handle_t* devfs_open(struct mount_cntx_t* cntx, const char* path); +extern struct file_handle_t* devfs_open(struct mount_cntx_t* cntx, const char* path, uint32_t flags, uint32_t mode); extern void devfs_close(struct file_handle_t* handle); extern enum file_status_t devfs_stat(struct file_handle_t* handle, struct file_info_t* info); extern size_t devfs_read(struct file_handle_t* handle, void* buffer, size_t count); extern uint64_t devfs_get_seek(struct file_handle_t* handle); extern enum file_status_t devfs_seek(struct file_handle_t* handle, uint64_t seek); -extern size_t devfs_write(struct file_handle_t* handle, void* buffer, size_t count); -extern enum file_status_t devfs_create(struct file_handle_t* handle, const char* name); -extern enum file_status_t devfs_delete(struct file_handle_t* handle); +extern size_t devfs_write(struct file_handle_t* handle, const void* buffer, size_t count); extern void devfs_delete_final(struct file_handle_t* handle); extern enum file_status_t devfs_open_dir(struct file_handle_t* handle); -extern void devfs_close_dir(struct file_handle_t* handle); extern enum file_status_t devfs_read_dir(struct file_handle_t* handle, struct dir_info_t* info); extern enum file_status_t devfs_create_dir(struct file_handle_t* handle, const char* name); extern enum file_status_t devfs_delete_dir(struct file_handle_t* handle); +extern enum file_status_t devfs_truncate(struct file_handle_t* handle, size_t size); +extern enum file_status_t devfs_link(struct file_handle_t* handle, struct file_handle_t* replace); +extern enum file_status_t devfs_unlink(struct file_handle_t* handle); + extern uint8_t devfs_is_interactive(struct file_handle_t* handle); #endif /* KERNEL_DEVFS_DEVFS_H */ diff --git a/kernel/include/devfs/tty.h b/kernel/include/devfs/tty.h index f275bbe..8dfc672 100644 --- a/kernel/include/devfs/tty.h +++ b/kernel/include/devfs/tty.h @@ -36,6 +36,6 @@ extern struct tty_handle_t* tty_open(const char* name); extern void tty_close(struct tty_handle_t* tty); extern size_t tty_read(struct tty_handle_t* tty, void* buffer, size_t count); extern uint8_t tty_queue_read(struct tty_handle_t* tty, uint8_t byte); -extern void tty_write(struct tty_handle_t* tty, void* buffer, size_t count); +extern void tty_write(struct tty_handle_t* tty, const void* buffer, size_t count); #endif /* KERNEL_DEVFS_TTY_H */ diff --git a/kernel/include/lib/array_list.h b/kernel/include/lib/array_list.h new file mode 100644 index 0000000..a0a6954 --- /dev/null +++ b/kernel/include/lib/array_list.h @@ -0,0 +1,43 @@ +/* array_list.h - array list interface */ +/* Copyright (C) 2026 Ebrahim Aleem +* +* This program is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see +*/ + +#ifndef KERNEL_LIB_ARRAY_LIST_H +#define KERNEL_LIB_ARRAY_LIST_H + +#include +#include + +struct array_list_t; + +extern struct array_list_t* array_list_alloc(size_t init_cap, size_t growth, void* null); + +extern uint64_t array_list_push(struct array_list_t* list, void* value); + +extern void* array_list_get(struct array_list_t* list, uint64_t index); + +extern void* array_list_remove(struct array_list_t* list, uint64_t index); + +extern void array_list_clear(struct array_list_t* list, void (*free_func)(void*)); + +extern void array_list_free(struct array_list_t* list, void (*free_func)(void*)); + +extern struct array_list_t* array_list_dup(struct array_list_t* list, void* (*dup_func)(void*)); + +extern uint64_t array_list_count(struct array_list_t* list); + +#endif /* KERNEL_LIB_ARRAY_LIST_H */ + diff --git a/kernel/include/lib/hash_table.h b/kernel/include/lib/hash_table.h index f30ef36..e30d61f 100644 --- a/kernel/include/lib/hash_table.h +++ b/kernel/include/lib/hash_table.h @@ -27,9 +27,19 @@ extern struct hash_table_t* hash_table_alloc(size_t buckets); extern void* hash_table_insert(struct hash_table_t* table, uint64_t key, void* value); -extern void* hash_table_get(struct hash_table_t* table, uint64_t key); +extern uint8_t hash_table_get(struct hash_table_t* table, uint64_t key, void** out); -extern void* hash_table_remove(struct hash_table_t* table, uint64_t key); +extern uint8_t hash_table_remove(struct hash_table_t* table, uint64_t key, void** out); + +extern void hash_table_clear(struct hash_table_t* table, void (*free_func)(void*)); + +extern void hash_table_free(struct hash_table_t* table, void (*free_func)(void*)); + +extern void hash_table_copy(struct hash_table_t* table, struct hash_table_t* copy, void* (*dup_func)(void*)); + +extern void hash_table_resize(struct hash_table_t* table, size_t buckets); + +extern size_t hash_table_count(struct hash_table_t* table); #endif /* KERNEL_LIB_HASH_TABLE_H */ diff --git a/kernel/include/lib/kstrcpy.h b/kernel/include/lib/kstrcpy.h index b591a4c..5a2a6b0 100644 --- a/kernel/include/lib/kstrcpy.h +++ b/kernel/include/lib/kstrcpy.h @@ -18,9 +18,13 @@ #ifndef KERNEL_LIB_KSTRCPY_H #define KERNEL_LIB_KSTRCPY_H +#include + extern char* kstrcpy(char* dest, const char* src); extern char* kstrcpy_no_null(char* dest, const char* src); +extern char* kstrncpy(char* dest, const char* src, size_t len); + #endif /* KERNEL_LIB_KSTRCPY_H */ diff --git a/kernel/lib/array_list.c b/kernel/lib/array_list.c new file mode 100644 index 0000000..7eb568b --- /dev/null +++ b/kernel/lib/array_list.c @@ -0,0 +1,154 @@ +/* array_list.c - array list implementation */ +/* Copyright (C) 2026 Ebrahim Aleem +* +* This program is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see +*/ + +#include +#include + +#include +#include + +#include + +struct array_list_t { + void** buffer; + void* null; + size_t cap; + size_t growth; + size_t count; + size_t hint; +}; + +static void* get_increase(struct array_list_t* list, size_t index) { + if (index < list->cap) { + return list->buffer[index]; + } + + void** buffer = kmalloc(sizeof(void*) * list->cap + list->growth); + kmemcpy(buffer, list->buffer, sizeof(void*) * list->cap); + + for (size_t i = list->cap; i < list->cap + list->growth; i++) { + buffer[i] = list->null; + } + + kfree(list->buffer); + list->buffer = buffer; + list->cap += list->growth; + + return list->null; +} + +struct array_list_t* array_list_alloc(size_t init_cap, size_t growth, void* null) { + struct array_list_t* list = kmalloc(sizeof(struct array_list_t)); + + list->cap = init_cap; + list->null = null; + list->growth = growth; + list->count = list->hint = 0; + + list->buffer = kmalloc(sizeof(void*) * init_cap); + + for (size_t i = 0; i < init_cap; i++) { + list->buffer[i] = null; + } + + return list; +} + +uint64_t array_list_push(struct array_list_t* list, void* value) { + while (get_increase(list, list->hint) != list->null) { + list->hint++; + } + + list->buffer[list->hint] = value; + list->count++; + return list->hint++; +} + +void* array_list_get(struct array_list_t* list, uint64_t index) { + if (index >= list->cap) { + return list->null; + } + + return list->buffer[index]; +} + +void* array_list_remove(struct array_list_t* list, uint64_t index) { + if (index >= list->cap) { + return list->null; + } + + void* ret = list->buffer[index]; + list->buffer[index] = list->null; + + list->count--; + + if (index < list->hint) { + list->hint = index; + } + + return ret; +} + +void array_list_clear(struct array_list_t* list, void (*free_func)(void*)) { + for (size_t i = 0; i < list->cap; i++) { + if (list->buffer[i] != list->null) { + if (free_func) { + free_func(list->buffer[i]); + } + list->buffer[i] = list->null; + } + } + + list->count = 0; + list->hint = 0; +} + +void array_list_free(struct array_list_t* list, void (*free_func)(void*)) { + array_list_clear(list, free_func); + + kfree(list->buffer); + kfree(list); +} + +struct array_list_t* array_list_dup(struct array_list_t* list, void* (*dup_func)(void*)) { + struct array_list_t* copy = kmalloc(sizeof(struct array_list_t)); + + copy->cap = list->cap; + copy->null = list->null; + copy->growth = list->growth; + copy->count = list->count; + copy->hint = list->hint; + + copy->buffer = kmalloc(sizeof(void*) * list->cap); + + for (size_t i = 0; i < list->cap; i++) { + if (list->buffer[i] == list->null) { + copy->buffer[i] = list->null; + } + else { + copy->buffer[i] = dup_func(list->buffer[i]); + } + } + + kmemcpy(copy->buffer, list->buffer, sizeof(void*) * list->cap); + + return copy; +} + +uint64_t array_list_count(struct array_list_t* list) { + return list->count; +} diff --git a/kernel/lib/hash_table.c b/kernel/lib/hash_table.c index 0885bc5..acf32f3 100644 --- a/kernel/lib/hash_table.c +++ b/kernel/lib/hash_table.c @@ -19,6 +19,7 @@ #include #include +#include #include @@ -30,9 +31,14 @@ struct node_t { struct hash_table_t { size_t num_buckets; - struct node_t* buckets[]; + size_t num_elems; + struct node_t** buckets; }; +static void* dup(void* value) { + return value; +} + static inline uint64_t bucket_index(struct hash_table_t* table, uint64_t key) { return key % table->num_buckets; } @@ -48,17 +54,17 @@ static struct node_t** find_node(struct node_t** bucket, uint64_t key) { } struct hash_table_t* hash_table_alloc(size_t buckets) { - struct hash_table_t* table = kmalloc(sizeof(struct hash_table_t) + buckets * sizeof(struct node_t*)); + struct hash_table_t* table = kmalloc(sizeof(struct hash_table_t)); if (!table) { return 0; } table->num_buckets = buckets; + table->num_elems = 0; + table->buckets = kmalloc(sizeof(struct node_t*) * buckets); - for (size_t i = 0; i < buckets; i++) { - table->buckets[i] = 0; - } + kmemset(table->buckets, 0, sizeof(struct node_t*) * buckets); return table; } @@ -72,8 +78,9 @@ void* hash_table_insert(struct hash_table_t* table, uint64_t key, void* value) { node = kmalloc(sizeof(struct node_t)); node->next = table->buckets[index]; node->key = key; - node->value = 0; + node->value = value; table->buckets[index] = node; + table->num_elems++; } void* old = node->value; @@ -82,7 +89,7 @@ void* hash_table_insert(struct hash_table_t* table, uint64_t key, void* value) { return old; } -void* hash_table_get(struct hash_table_t* table, uint64_t key) { +uint8_t hash_table_get(struct hash_table_t* table, uint64_t key, void** out) { uint64_t index = bucket_index(table, key); struct node_t* node = *find_node(&table->buckets[index], key); @@ -91,10 +98,11 @@ void* hash_table_get(struct hash_table_t* table, uint64_t key) { return 0; } - return node->value; + *out = node->value; + return 1; } -void* hash_table_remove(struct hash_table_t* table, uint64_t key) { +uint8_t hash_table_remove(struct hash_table_t* table, uint64_t key, void** out) { uint64_t index = bucket_index(table, key); struct node_t** node = find_node(&table->buckets[index], key); @@ -103,11 +111,62 @@ void* hash_table_remove(struct hash_table_t* table, uint64_t key) { return 0; } - void* old = (*node)->value; + *out = (*node)->value; struct node_t* to_free = *node; *node = (*node)->next; kfree(to_free); - return old; + table->num_elems--; + + return 1; +} + +void hash_table_clear(struct hash_table_t* table, void (*free_func)(void*)) { + for (size_t i = 0; i < table->num_buckets; i++) { + struct node_t* next; + for (struct node_t* node = table->buckets[i]; node; node = next) { + next = node->next; + if (free_func) { + free_func(node->value); + } + kfree(node); + } + + table->buckets[i] = 0; + } + + table->num_elems = 0; +} + +void hash_table_free(struct hash_table_t* table, void (*free_func)(void*)) { + hash_table_clear(table, free_func); + + kfree(table->buckets); + kfree(table); +} + +void hash_table_copy(struct hash_table_t* table, struct hash_table_t* copy, void* (*dup_func)(void*)) { + for (size_t i = 0; i < table->num_buckets; i++) { + for (struct node_t* node = table->buckets[i]; node; node = node->next) { + hash_table_insert(copy, node->key, dup_func(node->value)); + } + } +} + +void hash_table_resize(struct hash_table_t* table, size_t buckets) { + struct hash_table_t temp = *table; + + table->num_buckets = buckets; + table->num_elems = 0; + table->buckets = kmalloc(sizeof(struct node_t*) * buckets); + kmemset(table->buckets, 0, sizeof(struct node_t*) * buckets); + + hash_table_copy(&temp, table, dup); + + kfree(temp.buckets); +} + +size_t hash_table_count(struct hash_table_t* table) { + return table->num_elems; } diff --git a/kernel/lib/kstrcpy.c b/kernel/lib/kstrcpy.c index a24e571..843f4ae 100644 --- a/kernel/lib/kstrcpy.c +++ b/kernel/lib/kstrcpy.c @@ -37,3 +37,18 @@ char* kstrcpy_no_null(char* dest, const char* src) { return dest; } + +char* kstrncpy(char* dest, const char* src, size_t len) { + if (!len) { + return dest; + } + + while (*src && --len) { + *dest = *src; + src++; + dest++; + } + + *dest = 0; + return dest + 1; +} diff --git a/test/helpers/memport.c b/test/helpers/memport.c new file mode 100644 index 0000000..6befcb1 --- /dev/null +++ b/test/helpers/memport.c @@ -0,0 +1,29 @@ +/* memport.c - kernel allocator port to userland */ +/* Copyright (C) 2025-2026 Ebrahim Aleem +* +* This program is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see +*/ + +#include +#include + +#include + +void* kmalloc(size_t size) { + return malloc(size); +} + +void kfree(void* ptr) { + free(ptr); +} diff --git a/test/include/memport.h b/test/include/memport.h new file mode 100644 index 0000000..3bcafbb --- /dev/null +++ b/test/include/memport.h @@ -0,0 +1,26 @@ +/* memport.h - kernel allocator port to userland interface */ +/* Copyright (C) 2025-2026 Ebrahim Aleem +* +* This program is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see +*/ + +#ifndef TEST_HELPERS_MEMPORT_H +#define TEST_HELPERS_MEMPORT_H + +#include + +void* kmalloc(size_t size); +void kfree(void* ptr); + +#endif /* TEST_HELPERS_MEMPORT_H */ diff --git a/test/lib/test.c b/test/lib/test.c index 3e2bd9e..d10f004 100644 --- a/test/lib/test.c +++ b/test/lib/test.c @@ -15,7 +15,7 @@ * along with this program. If not, see */ -#include +#include #include #include #include @@ -30,6 +30,7 @@ #include #include #include +#include #define MEM_TEST_SIZE 256 @@ -133,3 +134,130 @@ TEST("fnc64_1a") { ASSERT_TRUE(fnv64_1a("Hello, World!", 13) == 0x6ef05bd7cc857c54, "fails expected checksum"); ASSERT_FALSE(fnv64_1a("Hello, World!", 12) == 0x6ef05bd7cc857c54, "fails expected checksum"); } + +static void* hash_table_dup_fun(void* value) { + return (void*)((uint64_t)value + 1); +} + +TEST("hash_table") { + struct hash_table_t* table1 = hash_table_alloc(10); + struct hash_table_t* table2 = hash_table_alloc(10); + void* tmp; + + ASSERT_TRUE(hash_table_insert(table1, 1, (void*)1) == (void*)1, "fails hash_table_insert"); + ASSERT_TRUE(hash_table_insert(table1, 2, (void*)2) == (void*)2, "fails hash_table_insert"); + ASSERT_TRUE(hash_table_insert(table1, 328642, (void*)3) == (void*)3, "fails hash_table_insert"); + ASSERT_TRUE(hash_table_insert(table1, ~834ULL, (void*)4) == (void*)4, "fails hash_table_insert"); + ASSERT_TRUE(hash_table_insert(table1, 1, (void*)5) == (void*)1, "fails hash_table_insert"); + ASSERT_TRUE(hash_table_insert(table1, 11, (void*)6) == (void*)6, "fails hash_table_insert"); + + ASSERT_TRUE(hash_table_get(table1, 1, &tmp), "fails hash_table_get"); + ASSERT_TRUE(tmp == (void*)5, "fails hash_table_get"); + + ASSERT_TRUE(hash_table_get(table1, 2, &tmp), "fails hash_table_get"); + ASSERT_TRUE(tmp == (void*)2, "fails hash_table_get"); + + ASSERT_TRUE(hash_table_get(table1, 328642, &tmp), "fails hash_table_get"); + ASSERT_TRUE(tmp == (void*)3, "fails hash_table_get"); + + ASSERT_TRUE(hash_table_get(table1, ~834ULL, &tmp), "fails hash_table_get"); + ASSERT_TRUE(tmp == (void*)4, "fails hash_table_get"); + + ASSERT_TRUE(hash_table_get(table1, 11, &tmp), "fails hash_table_get"); + ASSERT_TRUE(tmp == (void*)6, "fails hash_table_get"); + + ASSERT_FALSE(hash_table_get(table1, 3, &tmp), "fails hash_table_get"); + ASSERT_FALSE(hash_table_get(table1, 0, &tmp), "fails hash_table_get"); + ASSERT_FALSE(hash_table_get(table2, 0, &tmp), "fails hash_table_get"); + + ASSERT_TRUE(hash_table_remove(table1, 1, &tmp), "fails hash_table_remove"); + ASSERT_TRUE(tmp == (void*)5, "fails hash_table_remove"); + tmp = (void*)0; + ASSERT_FALSE(hash_table_remove(table1, 1, &tmp), "fails hash_table_remove"); + ASSERT_TRUE(tmp == (void*)0, "fails hash_table_remove"); + + ASSERT_TRUE(hash_table_get(table1, 11, &tmp), "fails hash_table_get after remove"); + ASSERT_FALSE(hash_table_remove(table2, 1, &tmp), "fails hash_table_remove"); + + hash_table_copy(table1, table2, hash_table_dup_fun); + hash_table_clear(table1, 0); + + ASSERT_TRUE(hash_table_count(table1) == 0, "fails hash_table_count"); + ASSERT_TRUE(hash_table_count(table2) == 4, "fails hash_table_count"); + + ASSERT_FALSE(hash_table_get(table1, 11, &tmp), "fails hash_table_get after clear"); + ASSERT_TRUE(hash_table_get(table2, 11, &tmp), "fails hash_table_get after copy"); + ASSERT_TRUE(tmp == (void*)7, "fails hash_table_get after copy"); + + hash_table_insert(table2, 1, (void*)8); + hash_table_insert(table2, 101, (void*)9); + hash_table_resize(table2, 100); + + ASSERT_TRUE(hash_table_get(table2, 1, &tmp), "fails hash_table_get after resize"); + ASSERT_TRUE(tmp == (void*)8, "fails hash_table_get after resize"); + + ASSERT_TRUE(hash_table_get(table2, 2, &tmp), "fails hash_table_get after resize"); + ASSERT_TRUE(tmp == (void*)3, "fails hash_table_get after resize"); + + ASSERT_TRUE(hash_table_get(table2, 328642, &tmp), "fails hash_table_get after resize"); + ASSERT_TRUE(tmp == (void*)4, "fails hash_table_get after resize"); + + ASSERT_TRUE(hash_table_get(table2, ~834ULL, &tmp), "fails hash_table_get after resize"); + ASSERT_TRUE(tmp == (void*)5, "fails hash_table_get after resize"); + + ASSERT_TRUE(hash_table_get(table2, 11, &tmp), "fails hash_table_get after resize"); + ASSERT_TRUE(tmp == (void*)7, "fails hash_table_get after resize"); + + ASSERT_TRUE(hash_table_get(table2, 101, &tmp), "fails hash_table_get after resize"); + ASSERT_TRUE(tmp == (void*)9, "fails hash_table_get after resize"); + + hash_table_free(table1, 0); + hash_table_free(table2, 0); +} + +static void* array_list_dup_fun(void* value) { + return (void*)((uint64_t)value + 1); +} + +TEST("array_list") { + struct array_list_t* list1 = array_list_alloc(1, 1, (void*)2); + struct array_list_t* list2; + + ASSERT_TRUE(array_list_count(list1) == 0, "fails array_list_count"); + + ASSERT_TRUE(array_list_get(list1, 0) == (void*)2, "fails array_list_get"); + ASSERT_TRUE(array_list_get(list1, 1) == (void*)2, "fails array_list_get"); + + ASSERT_TRUE(array_list_push(list1, (void*)101) == 0, "fails array_list_push"); + ASSERT_TRUE(array_list_push(list1, (void*)201) == 1, "fails array_list_push"); + ASSERT_TRUE(array_list_push(list1, (void*)301) == 2, "fails array_list_push"); + + ASSERT_TRUE(array_list_get(list1, 0) == (void*)101, "fails array_list_get"); + ASSERT_TRUE(array_list_get(list1, 1) == (void*)201, "fails array_list_get"); + ASSERT_TRUE(array_list_get(list1, 100) == (void*)2, "fails array_list_get"); + + ASSERT_TRUE(array_list_remove(list1, 1) == (void*)201, "fails array_list_remove"); + ASSERT_TRUE(array_list_remove(list1, 3) == (void*)2, "fails array_list_remove"); + ASSERT_TRUE(array_list_remove(list1, 100) == (void*)2, "fails array_list_remove"); + + ASSERT_TRUE(array_list_push(list1, (void*)401) == 1, "fails array_list_push"); + + list2 = array_list_dup(list1, array_list_dup_fun); + array_list_clear(list1, 0); + + ASSERT_TRUE(array_list_count(list1) == 0, "fails array_list_count after clear"); + ASSERT_TRUE(array_list_count(list2) == 3, "fails array_list_count after copy"); + + ASSERT_TRUE(array_list_push(list1, (void*)501) == 0, "fails array_list_push after clear"); + + ASSERT_TRUE(array_list_get(list1, 0) == (void*)501, "fails array_list_get after clear"); + ASSERT_TRUE(array_list_get(list1, 1) == (void*)2, "fails array_list_get after clear"); + ASSERT_TRUE(array_list_get(list1, 100) == (void*)2, "fails array_list_get after clear"); + + ASSERT_TRUE(array_list_get(list2, 0) == (void*)101, "fails array_list_get after copy"); + ASSERT_TRUE(array_list_get(list2, 1) == (void*)401, "fails array_list_get after copy"); + ASSERT_TRUE(array_list_get(list2, 100) == (void*)2, "fails array_list_get after copy"); + + array_list_free(list1, 0); + array_list_free(list2, 0); +} diff --git a/userland/Makefile b/userland/Makefile index 78e38c2..75329af 100644 --- a/userland/Makefile +++ b/userland/Makefile @@ -39,7 +39,7 @@ mlibc/: git clone https://github.com/managarm/mlibc.git $@ git -C $@ checkout v6.3.1 git -C $@ apply ../mlibc-patch/mlibc-v6-3-1-port.patch - cp -r mlibc-patch/* $@ + cp -r mlibc-patch/* mlibc/ $(OBJ_DIR)/mlibc-meson-setup: | mlibc/ $(OBJ_DIR)/libc-build/ $(OBJ_DIR)/../userland_files/usr/ meson setup \ @@ -54,6 +54,7 @@ $(OBJ_DIR)/mlibc-meson-setup: | mlibc/ $(OBJ_DIR)/libc-build/ $(OBJ_DIR)/../user .PHONY: libc libc: $(OBJ_DIR)/mlibc-meson-setup + cp -u -r mlibc-patch/* mlibc/ ninja -C $(OBJ_DIR)/libc-build/ meson install --only-changed -C $(OBJ_DIR)/libc-build/ diff --git a/userland/mlibc-patch/abis/modulos/dev_t.h b/userland/mlibc-patch/abis/modulos/dev_t.h new file mode 100644 index 0000000..e814cf9 --- /dev/null +++ b/userland/mlibc-patch/abis/modulos/dev_t.h @@ -0,0 +1,9 @@ +#ifndef _ABIBITS_DEV_T_H +#define _ABIBITS_DEV_T_H + +#include + +typedef uint32_t dev_t; + +#endif /* _ABIBITS_DEV_T_H */ + diff --git a/userland/mlibc-patch/abis/modulos/ino_t.h b/userland/mlibc-patch/abis/modulos/ino_t.h new file mode 100644 index 0000000..c7976dc --- /dev/null +++ b/userland/mlibc-patch/abis/modulos/ino_t.h @@ -0,0 +1,11 @@ +#ifndef _ABIBITS_INO_T_H +#define _ABIBITS_INO_T_H + +#include + +typedef uint32_t ino_t; +typedef ino_t ino64_t; + +#endif /* _ABIBITS_INO_T_H */ + + diff --git a/userland/mlibc-patch/abis/modulos/seek-whence.h b/userland/mlibc-patch/abis/modulos/seek-whence.h index b8864db..29360c7 100644 --- a/userland/mlibc-patch/abis/modulos/seek-whence.h +++ b/userland/mlibc-patch/abis/modulos/seek-whence.h @@ -4,8 +4,6 @@ #define SEEK_SET 0 #define SEEK_CUR 1 #define SEEK_END 2 -#define SEEK_DATA 3 -#define SEEK_HOLE 4 #endif /* _ABIBITS_SEEK_WHENCE_H */ diff --git a/userland/mlibc-patch/abis/modulos/stat.h b/userland/mlibc-patch/abis/modulos/stat.h index 9bc4686..bf26331 100644 --- a/userland/mlibc-patch/abis/modulos/stat.h +++ b/userland/mlibc-patch/abis/modulos/stat.h @@ -2,7 +2,11 @@ #define _ABIBITS_STAT_H #include +#include + #include +#include +#include #define S_IFMT 0x0F000 #define S_IFBLK 0x06000 @@ -37,5 +41,7 @@ struct stat { size_t st_size; }; +#define stat64 stat + #endif /* _ABIBITS_STAT_H */ diff --git a/userland/mlibc-patch/sysdeps/modulos/sysdeps.cpp b/userland/mlibc-patch/sysdeps/modulos/sysdeps.cpp index 5bb59d0..0f22575 100644 --- a/userland/mlibc-patch/sysdeps/modulos/sysdeps.cpp +++ b/userland/mlibc-patch/sysdeps/modulos/sysdeps.cpp @@ -19,7 +19,9 @@ #include #include +#include +#include #include #include @@ -31,14 +33,20 @@ #define SECONDS_PER_NANO 0x10000000000 -[[noreturn]] static inline void _trap(void) { - asm volatile ("int3" : : : "memory"); - __builtin_unreachable(); +extern "C" { +struct file_info_t { + enum { + FILE_TYPE_REG, + FILE_TYPE_DIR, + FILE_TYPE_CHAR + } type; + uint64_t size; +}; } namespace mlibc { -// internal +// misc void sys_libc_log(const char *message) { ssize_t _ign; @@ -51,11 +59,20 @@ void sys_libc_log(const char *message) { sys_exit(-1); } +// proccess + int sys_tcb_set(void *pointer) { asm volatile ("wrfsbaseq %0" : : "r"(pointer) : "memory"); return 0; } +[[noreturn]] void sys_exit(int status) { + syscall_1(status, 0, 0, SYSCALL_EXIT); + __builtin_unreachable(); +} + +// locking + int sys_futex_wait(int *pointer, int expected, const struct timespec *time) { (void)pointer; (void)expected; @@ -68,10 +85,12 @@ int sys_futex_wake(int *pointer) { return 0; } +// memory + int sys_anon_allocate(size_t size, void **pointer) { uint64_t addr = syscall_1(size, 0, 0, SYSCALL_ALLOC); if (!addr) { - return 1; + return ENOMEM; } memset((void*)addr, 0, size); @@ -86,66 +105,93 @@ int sys_anon_free(void *pointer, size_t size) { return 0; } -int sys_open(const char *pathname, int flags, mode_t mode, int *fd) { - (void)mode; +// mlibc assumes that anonymous memory returned by sys_vm_map() is zeroed by the kernel / whatever is behind the sysdeps +int sys_vm_map(void *hint, size_t size, int prot, int flags, int fd, off_t offset, void **window) { + (void)hint; + (void)size; + (void)prot; + (void)flags; + (void)fd; + (void)offset; + (void)window; - int f = syscall_1((uint64_t)pathname, flags, 0, SYSCALL_OPEN); - if (!f) { - return 1; - } + return ENOSYS; +} + +int sys_vm_unmap(void *pointer, size_t size) { + (void)pointer; + (void)size; + return 0; +} + +// files +int sys_openat(int dirfd, const char *path, int flags, mode_t mode, int *fd) { + uint64_t f = syscall_4((uint64_t)path, flags, dirfd, SYSCALL_OPENAT, mode); + + if (f == SYSCALL_STS_FAIL) { + return EACCES; + } + *fd = f; return 0; } -int sys_read(int fd, void *buf, size_t count, ssize_t *bytes_read) { - *bytes_read = (ssize_t)syscall_3((uint64_t)fd, (uint64_t)buf, (uint64_t)count, SYSCALL_READ); +int sys_open(const char *pathname, int flags, mode_t mode, int *fd) { + return sys_openat(AT_FDCWD, pathname, flags, mode, fd); +} +int sys_close(int fd) { + syscall_1(fd, 0, 0, SYSCALL_CLOSE); return 0; } int sys_seek(int fd, off_t offset, int whence, off_t *new_offset) { + off_t new_off; switch (whence) { + case SEEK_END: + struct stat statbuf; + if (sys_stat(fsfd_target::fd, fd, nullptr, 0, &statbuf)) { + return EACCES; + } + offset += statbuf.st_size; + goto set; case SEEK_CUR: offset += syscall_1(fd, 0, 0, SYSCALL_TELL); - __attribute__((fallthrough)); + goto set; case SEEK_SET: - *new_offset = syscall_2(fd, (uint64_t)offset, 0, SYSCALL_SEEK); +set: + new_off = syscall_2(fd, (uint64_t)offset, 0, SYSCALL_SEEK); + if ((uint64_t)*new_offset == SYSCALL_STS_FAIL) { + return EACCES; + } + + *new_offset = new_off; return 0; + default: - _trap(); + return ENOSYS; } } -int sys_close(int fd) { - syscall_1(fd, 0, 0, SYSCALL_CLOSE); - return 0; -} - -// mlibc assumes that anonymous memory returned by sys_vm_map() is zeroed by the kernel / whatever is behind the sysdeps -int sys_vm_map(void *hint, size_t size, int prot, int flags, int fd, off_t offset, void **window) { - (void)hint; - (void)size; - (void)prot; - (void)flags; +int sys_ftruncate(int fd, size_t size) { (void)fd; - (void)offset; - (void)window; + (void)size; - _trap(); + if (syscall_2(fd, size, 0, SYSCALL_TRUNCATE) == SYSCALL_STS_FAIL) { + return EACCES; + } + return 0; } -int sys_vm_unmap(void *pointer, size_t size) { - (void)pointer; - (void)size; - return 0; +int sys_fallocate(int fd, off_t offset, size_t size) { + return sys_ftruncate(fd, offset + size); } -// ansi +int sys_read(int fd, void *buf, size_t count, ssize_t *bytes_read) { + *bytes_read = (ssize_t)syscall_3((uint64_t)fd, (uint64_t)buf, (uint64_t)count, SYSCALL_READ); -[[noreturn]] void sys_exit(int status) { - syscall_1(status, 0, 0, SYSCALL_EXIT); - __builtin_unreachable(); + return 0; } int sys_write(int fd, const void *buf, size_t count, ssize_t *bytes_written) { @@ -154,6 +200,36 @@ int sys_write(int fd, const void *buf, size_t count, ssize_t *bytes_written) { return 0; } +int sys_open_dir(const char *path, int *handle) { + int fd; + int sts; + if ((sts = sys_open(path, O_RDWR, 0, &fd))) { + return sts; + } + + uint64_t dfd = syscall_1(fd, 0, 0, SYSCALL_OPEN_DIR); + + if (dfd == SYSCALL_STS_FAIL) { + sys_close(fd); + return ENOTDIR; + } + + *handle = (int)dfd; + + return 0; +} + +int sys_read_entries(int handle, void *buffer, size_t max_size, + size_t *bytes_read) { + (void)handle; + (void)buffer; + (void)max_size; + (void)bytes_read; + + //TODO + return ENOSYS; +} + int sys_isatty(int fd) { if (syscall_1(fd, 0, 0, SYSCALL_IS_A_TTY)) { return 0; //mlibc expects 0 for tty @@ -162,6 +238,160 @@ int sys_isatty(int fd) { return ENOTTY; } +int sys_faccessat(int dirfd, const char *pathname, int mode, int flags) { + (void)dirfd; + (void)pathname; + (void)mode; + (void)flags; + + return 0; +} + +int sys_access(const char *path, int mode) { + return sys_faccessat(AT_FDCWD, path, mode, 0); +} + +int sys_stat(fsfd_target fsfdt, int fd, const char *path, int flags, + struct stat *statbuf) { + + int f; + int sts; + + switch (fsfdt) { + case fsfd_target::fd: + f = fd; + break; + case fsfd_target::path: + if ((sts = sys_open(path, flags, 0, &f))) { + return sts; + } + case fsfd_target::fd_path: + if ((sts = sys_openat(fd, path, flags, 0, &f))) { + return sts; + } + default: + return ENOSYS; + + } + + struct file_info_t buf; + uint64_t res = syscall_2(f, (uint64_t)&buf, 0, SYSCALL_STAT); + + if (res == SYSCALL_STS_FAIL) { + return EACCES; + } + + statbuf->st_size = buf.size; + + return 0; +} + +int sys_linkat(int olddirfd, const char *old_path, int newdirfd, const char *new_path, int flags) { + int sts; + int old_f; + int new_f; + + if ((sts = sys_openat(olddirfd, old_path, flags, 0, &old_f))) { + return sts; + } + + if ((sts = sys_openat(newdirfd, new_path, flags, 0, &new_f))) { + return sts; + } + + uint64_t res = syscall_2(old_f, new_f, 0, SYSCALL_LINK); + + if (res == SYSCALL_STS_FAIL) { + return EACCES; + } + + return 0; +} + +int sys_link(const char *old_path, const char *new_path) { + return sys_linkat(AT_FDCWD, old_path, AT_FDCWD, new_path, 0); +} + +int sys_unlinkat(int fd, const char *path, int flags) { + int sts; + int f; + + if ((sts = sys_openat(fd, path, O_RDWR, 0, &f))) { + return sts; + } + + uint64_t res = syscall_1(f, 0, 0, SYSCALL_UNLINK); + + if (res == SYSCALL_STS_FAIL) { + return EACCES; + } + + return 0; +} + +int sys_rmdir(const char *path) { + return sys_unlinkat(AT_FDCWD, path, AT_REMOVEDIR); +} + +int sys_mkdirat(int dirfd, const char *path, mode_t mode) { + (void)dirfd; + (void)path; + (void)mode; + + return ENOSYS; + //TODO +} + +int sys_mkdir(const char *path, mode_t mode) { + return sys_mkdirat(AT_FDCWD, path, mode); +} + +int sys_renameat(int olddirfd, const char *old_path, int newdirfd, const char *new_path) { + int sts; + if ((sts = sys_linkat(olddirfd, old_path, newdirfd, new_path, 0))) { + return sts; + } + + return sys_unlinkat(olddirfd, old_path, 0); +} + +int sys_rename(const char *path, const char *new_path) { + return sys_renameat(AT_FDCWD, path, AT_FDCWD, new_path); +} + +// working directory + +int sys_getcwd(char *buffer, size_t size) { + if (syscall_2((uint64_t)buffer, size, 0, SYSCALL_GCWD) == SYSCALL_STS_FAIL) { + return EACCES; + } + + return 0; +} + +int sys_fchdir(int fd) { + if (syscall_1(fd, 0, 0, SYSCALL_CCWD) SYSCALL_STS_FAIL) { + return ENOTDIR; + } + + return 0; +} + +int sys_chdir(const char *path) { + int fd; + int sts; + if ((sts = sys_open(path, O_RDWR, 0, &fd))) { + return sts; + } + + sts = sys_fchdir(fd); + sys_close(fd); + + return sts; +} + +// time + int sys_clock_get(int clock, time_t *secs, long *nanos) { uint64_t epoch_nanos = syscall_0(0, 0, 0, SYSCALL_EPOCH_TIME); @@ -179,8 +409,9 @@ int sys_clock_get(int clock, time_t *secs, long *nanos) { *nanos = epoch_nanos % SECONDS_PER_NANO; return 0; default: - return 1; + return ENOSYS; } } + } //namespace mlibc diff --git a/userland/shell/main.c b/userland/shell/main.c index e8556d5..239954a 100644 --- a/userland/shell/main.c +++ b/userland/shell/main.c @@ -22,11 +22,45 @@ int main(int argc, char** argv) { (void)argc; (void)argv; + static char buffer[8]; + printf("Shell\n"); - FILE* f = fopen("/test.txt", "w"); - fprintf(f, "Hello, World\n"); + FILE* f = fopen("/test.txt", "r"); + if (f == 0) { + perror("Failed to open file"); + return EXIT_FAILURE; + } + + ssize_t bytes_read = fread(buffer, 1, 8, f); + if (bytes_read == -1) { + perror("Failed to read file"); + return EXIT_FAILURE; + } + fclose(f); + printf("Bytes read: %lu\nContent: %s", bytes_read, buffer); + + static char input_buf[64]; + printf("Enter file name:\n"); + scanf("%s", input_buf); + + f = fopen(input_buf, "a"); + + if (f == 0) { + perror("Failed to open file"); + return EXIT_FAILURE; + } + + if (fwrite(buffer, 1, bytes_read, f) != bytes_read) { + perror("Failed to write to file"); + return EXIT_FAILURE; + } + + fclose(f); + + printf("Done\n"); + return EXIT_SUCCESS; }