From d91330ba7337393ea3d533b0c66af7b3e1115e64 Mon Sep 17 00:00:00 2001 From: kamkow1 Date: Fri, 15 Aug 2025 01:41:11 +0200 Subject: [PATCH] Simple VFS layer --- .gitignore | 1 + Makefile | 10 +++- kernel/Makefile | 2 + kernel/assert.h | 15 ++++++ kernel/errors.h | 9 ++++ kernel/fs/kvfs/kvfs.c | 92 +++++++++++++++++++++++++++++++++++ kernel/fs/kvfs/kvfs.h | 28 +++++++++++ kernel/hal/hal.h | 3 ++ kernel/hal/util.c | 31 ++++++++++++ kernel/hshtb.h | 50 +++++++++++++++++++ kernel/kmain.c | 2 + kernel/std/string.c | 4 ++ kernel/util/util.h | 2 + kernel/vfs/vfs.c | 108 ++++++++++++++++++++++++++++++++++++++++++ kernel/vfs/vfs.h | 46 ++++++++++++++++++ limine.conf | 2 + 16 files changed, 403 insertions(+), 2 deletions(-) create mode 100644 kernel/assert.h create mode 100644 kernel/errors.h create mode 100644 kernel/fs/kvfs/kvfs.c create mode 100644 kernel/fs/kvfs/kvfs.h create mode 100644 kernel/hshtb.h create mode 100644 kernel/vfs/vfs.c create mode 100644 kernel/vfs/vfs.h diff --git a/.gitignore b/.gitignore index f3b1f83..244b48a 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ /limine /iso_root *.iso +*.img diff --git a/Makefile b/Makefile index 8c3acf4..fa34022 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,4 @@ -.PHONY: all clean prepare cleanall iso +.PHONY: all clean prepare cleanall iso base all: make -C kernel all @@ -20,7 +20,13 @@ cleanall: clean: make -C kernel clean - rm -f mop2.iso + rm -f mop2.iso base.img + +base: + dd if=/dev/zero of=base.img bs=1M count=32 + mformat -F -i base.img :: + mcopy -i base.img Makefile :: + mdir -i base.img :: iso: rm -rf iso_root diff --git a/kernel/Makefile b/kernel/Makefile index 9cf1656..87a1696 100644 --- a/kernel/Makefile +++ b/kernel/Makefile @@ -31,6 +31,8 @@ SRCFILES := $(wildcard *.c) \ $(wildcard term/*.c) \ $(wildcard vmm/*.c) \ $(wildcard dlmalloc/*.c) \ + $(wildcard vfs/*.c) \ + $(wildcard fs/kvfs/*.c) \ $(wildcard hal/*.c) \ $(wildcard hal/$(ARCH)/*.c) \ $(wildcard hal/$(ARCH)/*.S) \ diff --git a/kernel/assert.h b/kernel/assert.h new file mode 100644 index 0000000..39fa9db --- /dev/null +++ b/kernel/assert.h @@ -0,0 +1,15 @@ +#ifndef ASSERT_H_ +#define ASSERT_H_ + +#include "kprintf.h" +#include "hal/hal.h" + +#define ASSERT(mod, cond, fmt, ...) \ + do { \ + if (!(cond)) { \ + ERR(mod, fmt, ##__VA_ARGS__); \ + hal_hang(); \ + } \ + } while(0) + +#endif // ASSERT_H_ diff --git a/kernel/errors.h b/kernel/errors.h new file mode 100644 index 0000000..6b7e7f7 --- /dev/null +++ b/kernel/errors.h @@ -0,0 +1,9 @@ +#ifndef ERRORS_H_ +#define ERRORS_H_ + +#define E_OK 0 +#define E_NOMEMORY -1 +#define E_UNKNOWN_FSTYPE -2 +#define E_NOENTRY -3 + +#endif // ERRORS_H_ diff --git a/kernel/fs/kvfs/kvfs.c b/kernel/fs/kvfs/kvfs.c new file mode 100644 index 0000000..79f0328 --- /dev/null +++ b/kernel/fs/kvfs/kvfs.c @@ -0,0 +1,92 @@ +#include +#include +#include +#include "spinlock/spinlock.h" +#include "errors.h" +#include "hal/hal.h" +#include "hshtb.h" +#include "kprintf.h" +#include "vfs/vfs.h" +#include "dlmalloc/malloc.h" +#include "util/util.h" + +int32_t kvfs_read(struct VfsMountPoint *vmp, const char *key, uint8_t *const buffer, size_t n) { + KvfsNode *node = NULL; + + spinlock_acquire(&vmp->spinlock); + HSHTB_GET(&vmp->fs.kvfs, nodes, (char *)key, key_, node); + spinlock_release(&vmp->spinlock); + + if (node == NULL) { + return E_NOENTRY; + } + + spinlock_acquire(&node->spinlock); + hal_memcpy(buffer, node->buffer, MIN(n, KVFS_BUFFER_SIZE)); + spinlock_release(&node->spinlock); + return E_OK; +} + +int32_t kvfs_write(struct VfsMountPoint *vmp, const char *key, const uint8_t *const buffer, size_t n) { + KvfsNode *node = NULL; + + spinlock_acquire(&vmp->spinlock); + HSHTB_GET(&vmp->fs.kvfs, nodes, (char *)key, key_, node); + if (node == NULL) { + HSHTB_ALLOC(&vmp->fs.kvfs, nodes, (char *)key, key_, node); + if (node == NULL) { + spinlock_release(&vmp->spinlock); + return E_NOMEMORY; + } + } + spinlock_release(&vmp->spinlock); + + spinlock_acquire(&node->spinlock); + node->buffer = dlmalloc(KVFS_BUFFER_SIZE); + if (node->buffer == NULL) { + spinlock_release(&node->spinlock); + return E_NOMEMORY; + } + + hal_memcpy(node->buffer, buffer, MIN(n, KVFS_BUFFER_SIZE)); + spinlock_release(&node->spinlock); + return E_OK; +} + +int32_t kvfs_remove(struct VfsMountPoint *vmp, const char *key) { + KvfsNode *node = NULL; + + spinlock_acquire(&vmp->spinlock); + HSHTB_GET(&vmp->fs.kvfs, nodes, (char *)key, key_, node); + spinlock_release(&vmp->spinlock); + + if (node == NULL) { + return E_NOENTRY; + } + + spinlock_acquire(&node->spinlock); + hal_memset(node, 0, sizeof(*node)); + spinlock_release(&node->spinlock); + return E_OK; +} + +bool kvfs_check(void) { + int32_t ret; + + char *hello = "WAWAWAWA!!!"; + ret = vfs_write("+tmpvars", "hello", hello, hal_strlen(hello)+1); + if (ret != E_OK) return false; + + char buf[20]; + ret = vfs_read("+tmpvars", "hello", buf, sizeof(buf)); + if (ret != E_OK) return false; + + vfs_remove("+tmpvars", "hello"); + if (ret != E_OK) return false; + + ret = vfs_read("+tmpvars", "hello", buf, sizeof(buf)); + if (ret != E_NOENTRY) return false; + + return true; +} + diff --git a/kernel/fs/kvfs/kvfs.h b/kernel/fs/kvfs/kvfs.h new file mode 100644 index 0000000..f82ac4f --- /dev/null +++ b/kernel/fs/kvfs/kvfs.h @@ -0,0 +1,28 @@ +#ifndef FS_KVFS_KVFS_H_ +#define FS_KVFS_KVFS_H_ + +#include + +struct VfsMountPoint; + +#define KVFS_NODE_KEY_MAX 128 +#define KVFS_NODES_MAX 256 +#define KVFS_BUFFER_SIZE (1024 * 2) + +typedef struct { + bool taken; + uint8_t key_[KVFS_NODE_KEY_MAX]; + uint8_t *buffer; + SpinLock spinlock; +} KvfsNode; + +typedef struct { + KvfsNode nodes[KVFS_NODES_MAX]; +} Kvfs; + +int32_t kvfs_read(struct VfsMountPoint *vmp, const char *key, uint8_t *const buffer, size_t n); +int32_t kvfs_write(struct VfsMountPoint *vmp, const char *key, const uint8_t *const buffer, size_t n); +int32_t kvfs_remove(struct VfsMountPoint *vmp, const char *key); +bool kvfs_check(void); + +#endif // FS_KVFS_KVFS_H_ diff --git a/kernel/hal/hal.h b/kernel/hal/hal.h index e6e8e84..e2d3577 100644 --- a/kernel/hal/hal.h +++ b/kernel/hal/hal.h @@ -11,6 +11,9 @@ void hal_intr_disable(void); void hal_intr_enable(void); void *hal_memset(void *p, int c, size_t n); void *hal_memcpy(void *dst, const void *src, size_t n); +size_t hal_strlen(char *s); +int hal_memcmp(const void *s1, const void *s2, int len); + #if defined(__x86_64__) # define HAL_PAGE_SIZE 0x1000 diff --git a/kernel/hal/util.c b/kernel/hal/util.c index e38adb5..c05fb74 100644 --- a/kernel/hal/util.c +++ b/kernel/hal/util.c @@ -14,3 +14,34 @@ void *hal_memcpy(void *dst, const void *src, size_t n) { for (size_t i = 0; i < n; i++) a[i] = b[i]; return dst; } + +size_t hal_strlen(char *s) { + char *s2; + for (s2 = s; *s2; ++s2); + return (s2 - s); +} + +// https://aticleworld.com/memcmp-in-c/ +int hal_memcmp(const void *s1, const void *s2, int len) +{ + unsigned char *p = s1; + unsigned char *q = s2; + int charCompareStatus = 0; + //If both pointer pointing same memory block + if (s1 == s2) + { + return charCompareStatus; + } + while (len > 0) + { + if (*p != *q) + { //compare the mismatching character + charCompareStatus = (*p >*q)?1:-1; + break; + } + len--; + p++; + q++; + } + return charCompareStatus; +} diff --git a/kernel/hshtb.h b/kernel/hshtb.h new file mode 100644 index 0000000..630ae65 --- /dev/null +++ b/kernel/hshtb.h @@ -0,0 +1,50 @@ +#ifndef HSHTB_H_ +#define HSHTB_H_ + +#include +#include +#include + +#define HSHTB_FNV32_BASE 0x811c9dc5 + +static inline uint32_t hshtb_fnv32(char *s, size_t len) { + uint32_t h = HSHTB_FNV32_BASE; + for (size_t i = 0; i < len; i++) { + h ^= s[i]; + h += (h << 1) + (h << 4) + (h << 7) + (h << 8) + (h << 24); + } + return h >> 8; +} + +#define HSHTB_ALLOC(tb, name, k, keyname, out) \ + do { \ + size_t len = sizeof((tb)->name) / sizeof((tb)->name[0]); \ + size_t idx = hshtb_fnv32(k, hal_strlen(k)) % len; \ + size_t i = idx; \ + do { \ + if (!(tb)->name[i].taken) { \ + (out) = &((tb)->name[i]); \ + hal_memset((out), 0, sizeof(*(out))); \ + (out)->taken = true; \ + hal_memcpy((out)->keyname, k, hal_strlen(k)); \ + break; \ + } \ + i = (i + 1) % len; \ + } while(i != idx); \ + } while(0) + +#define HSHTB_GET(tb, name, k, keyname, out) \ + do { \ + size_t len = sizeof((tb)->name) / sizeof((tb)->name[0]); \ + size_t idx = hshtb_fnv32(k, hal_strlen(k)) % len; \ + size_t i = idx; \ + do { \ + if (hal_memcmp((tb)->name[i].keyname, k, hal_strlen(k)) == 0) { \ + (out) = &((tb)->name[i]); \ + break; \ + } \ + i = (i + 1) % len; \ + } while(i != idx); \ + } while(0) + +#endif // HSHTB_H_ diff --git a/kernel/kmain.c b/kernel/kmain.c index 0ef809c..ac1e7fd 100644 --- a/kernel/kmain.c +++ b/kernel/kmain.c @@ -7,6 +7,7 @@ #include "term/term.h" #include "paging/paging.h" #include "dlmalloc/malloc.h" +#include "vfs/vfs.h" static volatile LIMINE_BASE_REVISION(2); @@ -21,6 +22,7 @@ void kmain(void) { pmm_init(); paging_init(); dlmalloc_check(); + vfs_init(); kprintf(BANNER_TEXT "\n"); diff --git a/kernel/std/string.c b/kernel/std/string.c index d7ff8fc..7ad5618 100644 --- a/kernel/std/string.c +++ b/kernel/std/string.c @@ -8,3 +8,7 @@ void *memset(void *p, int c, size_t n) { void *memcpy(void *dst, const void *src, size_t n) { return hal_memcpy(dst,src,n); } + +size_t strlen(char *s) { + return hal_strlen(s); +} diff --git a/kernel/util/util.h b/kernel/util/util.h index 76b72a8..906cdbd 100644 --- a/kernel/util/util.h +++ b/kernel/util/util.h @@ -3,5 +3,7 @@ #define _DIV_ROUNDUP(num, div) ((num + div - 1) / div) #define MAX(a, b) (((a) > (b)) ? (a) : (b)) +#define MIN(a, b) (((a) < (b)) ? (a) : (b)) +#define LEN(X) (sizeof(X)/sizeof(X[0])) #endif // UTIL_UTIL_H_ diff --git a/kernel/vfs/vfs.c b/kernel/vfs/vfs.c new file mode 100644 index 0000000..95c90a1 --- /dev/null +++ b/kernel/vfs/vfs.c @@ -0,0 +1,108 @@ +#include +#include +#include "vfs.h" +#include "kprintf.h" +#include "spinlock/spinlock.h" +#include "hal/hal.h" +#include "util/util.h" +#include "hshtb.h" +#include "assert.h" +#include "errors.h" +#include "fs/kvfs/kvfs.h" + +VfsTable VFS_TABLE; + +static const char *vfs_strings[] = { + [VFS_FATFS] = "FAT", + [VFS_KVFS] = "Kvfs", +}; + +void vfs_init_kvfs(VfsMountPoint *mp) { + mp->read = &kvfs_read; + mp->write = &kvfs_write; + mp->remove = &kvfs_remove; + mp->check = &kvfs_check; +} + +int32_t vfs_mount(char *mountpoint, int32_t fstype) { + VfsMountPoint *mp = NULL; + + spinlock_acquire(&VFS_TABLE.spinlock); + HSHTB_ALLOC(&VFS_TABLE, mountpoints, mountpoint, label, mp); + spinlock_release(&VFS_TABLE.spinlock); + + if (mp == NULL) { + return E_NOMEMORY; + } + + hal_memcpy(mp->label, mountpoint, hal_strlen(mountpoint)); + mp->fstype = fstype; + switch (fstype) { + case VFS_KVFS: + vfs_init_kvfs(mp); + break; + default: + return E_UNKNOWN_FSTYPE; + } + + return E_OK; +} + +int32_t vfs_read(char *mountpoint, const char *path, uint8_t *const buffer, size_t n) { + VfsMountPoint *mp = NULL; + + spinlock_acquire(&VFS_TABLE.spinlock); + HSHTB_GET(&VFS_TABLE, mountpoints, mountpoint, label, mp); + spinlock_release(&VFS_TABLE.spinlock); + + if (mp == NULL) { + return E_NOENTRY; + } + + return mp->read(mp, path, buffer, n); +} + +int32_t vfs_write(char *mountpoint, const char *path, const uint8_t *const buffer, size_t n) { + VfsMountPoint *mp = NULL; + + spinlock_acquire(&VFS_TABLE.spinlock); + HSHTB_GET(&VFS_TABLE, mountpoints, mountpoint, label, mp); + spinlock_release(&VFS_TABLE.spinlock); + + if (mp == NULL) { + return E_NOENTRY; + } + + return mp->write(mp, path, buffer, n); +} + +int32_t vfs_remove(char *mountpoint, const char *path) { + VfsMountPoint *mp = NULL; + + spinlock_acquire(&VFS_TABLE.spinlock); + HSHTB_GET(&VFS_TABLE, mountpoints, mountpoint, label, mp); + spinlock_release(&VFS_TABLE.spinlock); + + if (mp == NULL) { + return E_NOENTRY; + } + + return mp->remove(mp, path); +} + +void vfs_init(void) { + hal_memset(&VFS_TABLE, 0, sizeof(VFS_TABLE)); + spinlock_init(&VFS_TABLE.spinlock); + + ASSERT("vfs", vfs_mount("+tmpvars", VFS_KVFS) == E_OK, "could not create +tmpvars mount point\n"); + + LOG("vfs", "init done\n"); + + for (size_t i = 0; i < LEN(VFS_TABLE.mountpoints); i++) { + if (!VFS_TABLE.mountpoints[i].taken) continue; + VfsMountPoint *vmp = &VFS_TABLE.mountpoints[i]; + LOG("vfs", "mount point %s: %s\n", vmp->label, vfs_strings[vmp->fstype]); + LOG("vfs", "check = %s\n", vmp->check() ? "OK" : "FAIL"); + } +} + diff --git a/kernel/vfs/vfs.h b/kernel/vfs/vfs.h new file mode 100644 index 0000000..45e08ca --- /dev/null +++ b/kernel/vfs/vfs.h @@ -0,0 +1,46 @@ +#ifndef VFS_VFS_H_ +#define VFS_VFS_H_ + +#include +#include +#include +#include "spinlock/spinlock.h" +#include "fs/kvfs/kvfs.h" + +#define VFS_MOUNTPOINT_LABEL_MAX 128 +#define VFS_MOUNTPOINTS_MAX 30 + +enum { + VFS_FATFS, + VFS_KVFS, +}; + +typedef struct VfsMountPoint { + bool taken; + uint8_t label[VFS_MOUNTPOINT_LABEL_MAX]; + int32_t fstype; + + int32_t (*read)(struct VfsMountPoint *vmp, const char *path, uint8_t *const buffer, size_t n); + int32_t (*write)(struct VfsMountPoint *vmp, const char *path, const uint8_t *const buffer, size_t n); + int32_t (*remove)(struct VfsMountPoint *vmp, const char *path); + bool (*check)(void); + + union { + Kvfs kvfs; + } fs; + SpinLock spinlock; +} VfsMountPoint; + +typedef struct { + SpinLock spinlock; + VfsMountPoint mountpoints[VFS_MOUNTPOINTS_MAX]; +} VfsTable; + +extern VfsTable VFS_TABLE; + +void vfs_init(void); +int32_t vfs_read(char *mountpoint, const char *path, uint8_t *const buffer, size_t n); +int32_t vfs_write(char *mountpoint, const char *path, const uint8_t *const buffer, size_t n); +int32_t vfs_remove(char *mountpoint, const char *path); + +#endif // VFS_VFS_H_ diff --git a/limine.conf b/limine.conf index f6df4c3..8be4098 100644 --- a/limine.conf +++ b/limine.conf @@ -1,5 +1,7 @@ timeout: 5 +verbose: yes /mop2 protocol: limine path: boot():/boot/mop2 + module_path: boot():/base.img