From fb5e88a175ce38bfd7f4b8e03248c075d8a32757 Mon Sep 17 00:00:00 2001 From: kamkow1 Date: Fri, 5 Sep 2025 19:56:27 +0200 Subject: [PATCH] Simple file IO with the ioctl syscall --- kernel/Makefile | 1 + kernel/fs/portlfs/portlfs.c | 29 ++++++++ kernel/path/path.c | 41 +++++++++++ kernel/path/path.h | 6 ++ kernel/proc/proc.h | 1 + kernel/syscall/ioctl.c | 139 ++++++++++++++++++++++++++++++++++++ kernel/syscall/ioctl.h | 9 +++ kernel/syscall/syscall.c | 2 + kernel/vfs/vfs.h | 2 + share/errors.h | 1 + share/sysdefs/ioctl.h | 40 +++++++++++ ulib/libulib.a | Bin 6748 -> 6894 bytes ulib/system/system.c | 8 ++- ulib/system/system.h | 5 +- user/Makefile.inc | 2 +- user/init/main.c | 19 ++++- 16 files changed, 299 insertions(+), 6 deletions(-) create mode 100644 kernel/path/path.c create mode 100644 kernel/path/path.h create mode 100644 kernel/syscall/ioctl.c create mode 100644 kernel/syscall/ioctl.h create mode 100644 share/sysdefs/ioctl.h diff --git a/kernel/Makefile b/kernel/Makefile index 23c3529..f33dd8d 100644 --- a/kernel/Makefile +++ b/kernel/Makefile @@ -59,6 +59,7 @@ SRCFILES += $(call GRABSRC, \ flanterm/src \ flanterm/src/flanterm_backends \ syscall \ + path \ ) ifeq ($(ARCH),x86_64) diff --git a/kernel/fs/portlfs/portlfs.c b/kernel/fs/portlfs/portlfs.c index a789c51..f6f660b 100644 --- a/kernel/fs/portlfs/portlfs.c +++ b/kernel/fs/portlfs/portlfs.c @@ -27,6 +27,10 @@ void littlefs_vobj_cleanup(struct VfsObj *vobj) { } int32_t littlefs_vobj_read(struct VfsObj *vobj, uint8_t *const buffer, size_t n, size_t off) { + if (!(vobj->flags & VFS_FLAG_READ)) { + return E_INVALIDOPER; + } + spinlock_acquire(&vobj->spinlock); int ok = lfs_file_seek(&vobj->vmp->fs.littlefs.instance, (lfs_file_t *)vobj->extra, off, LFS_SEEK_SET); @@ -45,6 +49,29 @@ int32_t littlefs_vobj_read(struct VfsObj *vobj, uint8_t *const buffer, size_t n, return E_OK; } +int32_t littlefs_vobj_write(struct VfsObj *vobj, const uint8_t *const buffer, size_t n, size_t off) { + if (!(vobj->flags & VFS_FLAG_WRITE)) { + return E_INVALIDOPER; + } + + spinlock_acquire(&vobj->spinlock); + + int ok = lfs_file_seek(&vobj->vmp->fs.littlefs.instance, (lfs_file_t *)vobj->extra, off, LFS_SEEK_SET); + if (ok < 0) { + spinlock_release(&vobj->spinlock); + return E_BADIO; + } + + ok = lfs_file_write(&vobj->vmp->fs.littlefs.instance, (lfs_file_t *)vobj->extra, buffer, n); + if (ok < 0) { + spinlock_release(&vobj->spinlock); + return E_BADIO; + } + + spinlock_release(&vobj->spinlock); + return E_OK; +} + int32_t littlefs_vobj_stat(struct VfsObj *vobj, struct VfsStat *stat) { struct lfs_info statbuf; @@ -107,12 +134,14 @@ struct VfsObj *littlefs_open(struct VfsMountPoint *vmp, const char *path, uint32 return NULL; } + vobj->flags = flags; vobj->extra = file; vobj->extrasize = sizeof(*file); vobj->vmp = vmp; vobj->cleanup = &littlefs_vobj_cleanup; vobj->read = &littlefs_vobj_read; vobj->stat = &littlefs_vobj_stat; + vobj->write = &littlefs_vobj_write; hal_strcpy(vobj->path, path); spinlock_release(&vmp->spinlock); diff --git a/kernel/path/path.c b/kernel/path/path.c new file mode 100644 index 0000000..4bb2717 --- /dev/null +++ b/kernel/path/path.c @@ -0,0 +1,41 @@ +#include "path.h" + +void path_parse(const char *in, char *mp, char *path) { + if (in == 0 || *in == 0) { + mp[0] = 0; + path[0] = 0; + return; + } + + int i = 0, j = 0, colonfound = 0; + + while (in[i]) { + if (in[i] == ':') { + if (colonfound) { + mp[0] = 0; + path[0] = 0; + return; + } + colonfound = 1; + mp[i] = 0; + i++; + continue; + } + + if (!colonfound) { + mp[i] = in[i]; + } else { + path[j++] = in[i]; + } + + i++; + } + + if (!colonfound) { + mp[i] = 0; + path[0] = 0; + } else { + path[j] = 0; + } +} + diff --git a/kernel/path/path.h b/kernel/path/path.h new file mode 100644 index 0000000..9b2db24 --- /dev/null +++ b/kernel/path/path.h @@ -0,0 +1,6 @@ +#ifndef PATH_PATH_H_ +#define PATH_PATH_H_ + +void path_parse(const char *in, char *mp, char *path); + +#endif // PATH_PATH_H_ diff --git a/kernel/proc/proc.h b/kernel/proc/proc.h index 7215590..6e67f34 100644 --- a/kernel/proc/proc.h +++ b/kernel/proc/proc.h @@ -41,6 +41,7 @@ typedef struct Proc { bool kern; VfsObj *vobjs[PROC_VFSHANDLES_MAX]; + uint64_t vobjcnt; } Proc; typedef struct { diff --git a/kernel/syscall/ioctl.c b/kernel/syscall/ioctl.c new file mode 100644 index 0000000..4c1ce3c --- /dev/null +++ b/kernel/syscall/ioctl.c @@ -0,0 +1,139 @@ +#include +#include +#include "syscall.h" +#include "sysdefs/ioctl.h" +#include "errors.h" +#include "path/path.h" +#include "vfs/vfs.h" +#include "kprintf.h" +#include "proc/proc.h" +#include "spinlock/spinlock.h" + +#define IOCTL_MP_MAX 0xff +#define IOCTL_PATH_MAX VFS_PATH_MAX + +int32_t SYSCALL3(sys_ioctl, ioh1, cmd1, optsptr1) { + uint64_t ioh = ioh1; + uint64_t cmd = cmd1; + int32_t ret = E_BADIO; + + switch (cmd) { + case IOCTL_OPENF: { + IOCtlOF *ioctlof = (IOCtlOF *)(void *)optsptr1; + + if (ioctlof == NULL) { + ret = E_INVALIDARGUMENT; + goto done; + } + + char mp[IOCTL_MP_MAX]; + char path[IOCTL_PATH_MAX]; + + if (ioctlof->path == NULL) { + ret = E_INVALIDARGUMENT; + goto done; + } + + path_parse(ioctlof->path, mp, path); + + VfsObj *vobj = vfs_open(mp, path, ioctlof->flags); + if (vobj == NULL) { + ret = E_NOENTRY; + goto done; + } + + spinlock_acquire(&PROCS.spinlock); + + Proc *proc = PROCS.current; + if (proc->vobjcnt < PROC_VFSHANDLES_MAX) { + proc->vobjs[proc->vobjcnt++] = vobj; + ret = proc->vobjcnt - 1; + } else { + ret = E_NOMEMORY; + } + + spinlock_release(&PROCS.spinlock); + } break; + case IOCTL_CLOSEF: { + spinlock_acquire(&PROCS.spinlock); + Proc *proc = PROCS.current; + VfsObj *vobj = proc->vobjs[ioh]; + spinlock_release(&PROCS.spinlock); + + if (vobj == NULL) { + ret = E_INVALIDARGUMENT; + goto done; + } + + vfs_close(vobj); + ret = E_OK; + } break; + case IOCTL_WRITE: { + IOCtlWF *ioctlwf = (IOCtlWF *)(void *)optsptr1; + + if (ioctlwf == NULL) { + ret = E_INVALIDARGUMENT; + goto done; + } + + if (ioctlwf->buffer == NULL) { + ret = E_INVALIDARGUMENT; + goto done; + } + + if (ioh >= PROC_VFSHANDLES_MAX) { + ret = E_INVALIDARGUMENT; + goto done; + } + + spinlock_acquire(&PROCS.spinlock); + Proc *proc = PROCS.current; + VfsObj *vobj = proc->vobjs[ioh]; + spinlock_release(&PROCS.spinlock); + + if (vobj == NULL) { + ret = E_INVALIDARGUMENT; + goto done; + } + + ret = vobj->write(vobj, ioctlwf->buffer, ioctlwf->len, ioctlwf->off); + } break; + case IOCTL_READ: { + IOCtlRF *ioctlrf = (IOCtlRF *)(void *)optsptr1; + + if (ioctlrf == NULL) { + ret = E_INVALIDARGUMENT; + goto done; + } + + if (ioctlrf->buffer == NULL) { + ret = E_INVALIDARGUMENT; + goto done; + } + + if (ioh >= PROC_VFSHANDLES_MAX) { + ret = E_INVALIDARGUMENT; + goto done; + } + + spinlock_acquire(&PROCS.spinlock); + Proc *proc = PROCS.current; + VfsObj *vobj = proc->vobjs[ioh]; + spinlock_release(&PROCS.spinlock); + + if (vobj == NULL) { + ret = E_INVALIDARGUMENT; + goto done; + } + + ret = vobj->read(vobj, ioctlrf->buffer, ioctlrf->len, ioctlrf->off); + } break; + default: { + ret = E_INVALIDARGUMENT; + goto done; + } break; + } + +done: + return ret; +} diff --git a/kernel/syscall/ioctl.h b/kernel/syscall/ioctl.h new file mode 100644 index 0000000..057d188 --- /dev/null +++ b/kernel/syscall/ioctl.h @@ -0,0 +1,9 @@ +#ifndef SYSCALL_IOCTL_H_ +#define SYSCALL_IOCTL_H_ + +#include +#include "syscall.h" + +int32_t SYSCALL3(sys_ioctl, ioh1, cmd1, optsptr1); + +#endif // SYSCALL_IOCTL_H_ diff --git a/kernel/syscall/syscall.c b/kernel/syscall/syscall.c index 38a1055..7b6b6e5 100644 --- a/kernel/syscall/syscall.c +++ b/kernel/syscall/syscall.c @@ -4,6 +4,7 @@ #include "kprintf.h" #include "processctl.h" #include "sysdefs/syscall.h" +#include "ioctl.h" int32_t SYSCALL1(sys_debugprint, string) { char *p = (char *)string; @@ -14,4 +15,5 @@ int32_t SYSCALL1(sys_debugprint, string) { SyscallFn SYSCALL_TABLE[SYSCALLS_MAX] = { [SYS_DEBUGPRINT] = &sys_debugprint, [SYS_PROCESSCTL] = &sys_processctl, + [SYS_IOCTL] = &sys_ioctl, }; diff --git a/kernel/vfs/vfs.h b/kernel/vfs/vfs.h index 990e0b9..907d217 100644 --- a/kernel/vfs/vfs.h +++ b/kernel/vfs/vfs.h @@ -43,8 +43,10 @@ typedef struct VfsObj { size_t extrasize; struct VfsMountPoint *vmp; char path[VFS_PATH_MAX]; + int32_t flags; int32_t (*read)(struct VfsObj *vobj, uint8_t *const buffer, size_t n, size_t off); int32_t (*stat)(struct VfsObj *vobj, struct VfsStat *stat); + int32_t (*write)(struct VfsObj *vobj, const uint8_t *const buffer, size_t n, size_t off); void (*cleanup)(struct VfsObj *vobj); } VfsObj; diff --git a/share/errors.h b/share/errors.h index ded8db8..200503f 100644 --- a/share/errors.h +++ b/share/errors.h @@ -13,6 +13,7 @@ enum { E_BADSYSCALL = -8, E_DOSCHEDULING = -9, E_INVALIDARGUMENT = -10, + E_INVALIDOPER = -11, }; #endif // ERRORS_H_ diff --git a/share/sysdefs/ioctl.h b/share/sysdefs/ioctl.h new file mode 100644 index 0000000..afbc992 --- /dev/null +++ b/share/sysdefs/ioctl.h @@ -0,0 +1,40 @@ +#ifndef SHARE_SYSDEFS_IOCTL_H_ +#define SHARE_SYSDEFS_IOCTL_H_ + +#include +#include + +#define IOCTL_NOHANDLE (-1) + +enum { + IOCTL_OPENF = 0, + IOCTL_CLOSEF = 1, + IOCTL_READ = 2, + IOCTL_STAT = 3, + IOCTL_WRITE = 4, +}; + +enum { + IOCTL_F_READ = 1<<0, + IOCTL_F_WRITE = 1<<1, + IOCTL_F_MAKE = 1<<2, +}; + +typedef struct { + const char *path; + int32_t flags; +} IOCtlOF; + +typedef struct { + const uint8_t *const buffer; + size_t len; + size_t off; +} IOCtlWF; + +typedef struct { + uint8_t *const buffer; + size_t len; + size_t off; +} IOCtlRF; + +#endif // SHARE_SYSDEFS_IOCTL_H_ diff --git a/ulib/libulib.a b/ulib/libulib.a index 320c8f2a54032bcdf84554915adf94c14682e2b0..a24426dee4aa6cbbb80ba4f2b86d256a8717bc7d 100644 GIT binary patch delta 473 zcmca(^3HUEthc3!g{7H-f`I}EAd?CThK3NnfEJnqE+pnODM4P?VpXT3no5lEaXhKXHj7E7+>Za_r(8A6l?Mc$?+e|Fa+@ zHe2#cK;kl+T9{0>;W1z`V4f@`7$p?y(RtC;@T5oQCs)G*9-aU8Gfz$tRGGYt$8Yil zK?hbDpyOgDe-*4|6rEfsB(5k6gz9UlbCbBy1p<05S~-n4s8Y@?7TQjA@fU3Y&8}fCPcSW3r)$Ipea) zid@>06(mJ~tcRTHlP`!!09lD#>XQXTB^VD(UI=6bh)QsNfM{ZwtRyZ94-2u)LE>|m E0jP~=fB*mh diff --git a/ulib/system/system.c b/ulib/system/system.c index 0f0cfda..eded22d 100644 --- a/ulib/system/system.c +++ b/ulib/system/system.c @@ -3,11 +3,15 @@ #include #include -void sys_debugprint(const char *string) { +void debugprint(const char *string) { syscall(SYS_DEBUGPRINT, (uint64_t)string, 0, 0, 0, 0, 0); } -int32_t sys_processctl(uint64_t pid, uint64_t cmd, void *extra) { +int32_t processctl(uint64_t pid, uint64_t cmd, void *extra) { return syscall(SYS_PROCESSCTL, pid, cmd, (uint64_t)extra, 0, 0, 0); } +int32_t ioctl(uint64_t ioh, uint64_t cmd, void *extra) { + return syscall(SYS_IOCTL, ioh, cmd, (uint64_t)extra, 0, 0, 0); +} + diff --git a/ulib/system/system.h b/ulib/system/system.h index bd63bc6..9a45337 100644 --- a/ulib/system/system.h +++ b/ulib/system/system.h @@ -3,7 +3,8 @@ #include -void sys_debugprint(const char *string); -int32_t sys_processctl(uint64_t pid, uint64_t cmd, void *extra); +void debugprint(const char *string); +int32_t processctl(uint64_t pid, uint64_t cmd, void *extra); +int32_t ioctl(uint64_t ioh, uint64_t cmd, void *extra); #endif // ULIB_SYSTEM_SYSTEM_H_ diff --git a/user/Makefile.inc b/user/Makefile.inc index 35f41bd..274a750 100644 --- a/user/Makefile.inc +++ b/user/Makefile.inc @@ -1,5 +1,5 @@ CFLAGS := -ffreestanding -Wall -Wextra -g -fcommon -nostdinc \ - -isystem $(ROOT)/std/include -isystem $(ROOT)/ulib + -isystem $(ROOT)/std/include -isystem $(ROOT)/ulib -isystem $(ROOT)/share CURRENT_DIR := $(dir $(abspath $(lastword $(MAKEFILE_LIST)))) diff --git a/user/init/main.c b/user/init/main.c index 205d20b..e4c41a2 100644 --- a/user/init/main.c +++ b/user/init/main.c @@ -1,6 +1,23 @@ #include +#include +#include void main(void) { - sys_debugprint("Hello world from userspace in C"); + debugprint("Hello world from userspace in C"); + + IOCtlOF ioctlof = { .path = "base:/hello.txt", .flags = IOCTL_F_WRITE | IOCTL_F_READ | IOCTL_F_MAKE }; + int32_t ioh = ioctl(IOCTL_NOHANDLE, IOCTL_OPENF, &ioctlof); + + char *text = "Write to a file"; + IOCtlWF ioctlwf = { .buffer = text, .len = string_len(text), .off = 0 }; + ioctl(ioh, IOCTL_WRITE, &ioctlwf); + + char buf[0x100]; + IOCtlRF ioctlrf = { .buffer = buf, .len = string_len(text), .off = 0 }; + ioctl(ioh, IOCTL_READ, &ioctlrf); + + debugprint(buf); + + ioctl(ioh, IOCTL_CLOSEF, NULL); }