diff --git a/apps/app.c b/apps/app.c index 10c5c975..44449860 100644 --- a/apps/app.c +++ b/apps/app.c @@ -1,6 +1,8 @@ +#include #include #include #include +#include void bye() { @@ -12,13 +14,14 @@ int main() atexit(bye); printf("Welcome to %s from userspace!\n", "Luna"); - char* address = (char*)malloc(1); - printf("address: %p\n", address); - printf("memory at address: %c\n", *address); - *address = 'e'; - printf("memory at address: %c\n", *address); + int fd = open("/etc/motd", 0); + if (fd < 0) + { + perror("open"); + return 1; + } - free(address); + close(fd); time_t now = time(NULL); printf("date: %s", ctime(&now)); diff --git a/initrd/etc/motd b/initrd/etc/motd new file mode 100644 index 00000000..f222d343 --- /dev/null +++ b/initrd/etc/motd @@ -0,0 +1 @@ +G'day mate! diff --git a/kernel/CMakeLists.txt b/kernel/CMakeLists.txt index 7cc661f6..719384d4 100644 --- a/kernel/CMakeLists.txt +++ b/kernel/CMakeLists.txt @@ -26,6 +26,7 @@ set(SOURCES src/sys/clock_gettime.cpp src/sys/allocate_memory.cpp src/sys/usleep.cpp + src/sys/open.cpp src/fs/VFS.cpp src/fs/tmpfs/FileSystem.cpp src/InitRD.cpp diff --git a/kernel/src/sys/open.cpp b/kernel/src/sys/open.cpp new file mode 100644 index 00000000..5468ef6c --- /dev/null +++ b/kernel/src/sys/open.cpp @@ -0,0 +1,45 @@ +#include "Log.h" +#include "fs/VFS.h" +#include "memory/MemoryManager.h" +#include "sys/Syscall.h" +#include "thread/Scheduler.h" + +Result sys_open(Registers*, SyscallArgs args) +{ + u64 path_address = args[0]; + if (!MemoryManager::validate_userspace_string(path_address)) return err(EFAULT); + + const char* path = (const char*)path_address; + int flags = (int)args[1]; + + Thread* current = Scheduler::current(); + + kinfoln("open: trying to open file %s, flags %d", path, flags); + + auto inode = TRY(VFS::resolve_path(path)); + + int fd = TRY(current->allocate_fd(0)); + + current->fd_table->fds[fd] = FileDescriptor { inode, 0, flags }; + + kinfoln("open: allocated file descriptor %d for inode %zu", fd, inode->inode_number()); + + return (u64)fd; +} + +Result sys_close(Registers*, SyscallArgs args) +{ + int fd = (int)args[0]; + if (fd < 0 || fd >= FD_MAX) return err(EBADF); + + Thread* current = Scheduler::current(); + + if (!current->fd_table->fds[fd].has_value()) return err(EBADF); + + kinfoln("close: closing file descriptor %d (was referencing inode %zu)", fd, + current->fd_table->fds[fd]->inode->inode_number()); + + current->fd_table->fds[fd] = {}; + + return 0; +} diff --git a/kernel/src/thread/Scheduler.cpp b/kernel/src/thread/Scheduler.cpp index 0f1eb7cb..a733c579 100644 --- a/kernel/src/thread/Scheduler.cpp +++ b/kernel/src/thread/Scheduler.cpp @@ -151,6 +151,8 @@ namespace Scheduler guard.deactivate(); directory_guard.deactivate(); + thread->fd_table = FileDescriptorTable {}; + kinfoln("Created userspace thread: id %lu with ip %#.16lx and sp %#.16lx (ksp %#lx)", thread->id, thread->ip(), thread->sp(), thread->kernel_stack.top()); diff --git a/kernel/src/thread/Thread.cpp b/kernel/src/thread/Thread.cpp index ae20d89e..04fc2252 100644 --- a/kernel/src/thread/Thread.cpp +++ b/kernel/src/thread/Thread.cpp @@ -19,3 +19,16 @@ Result new_thread() return thread; } + +Result Thread::allocate_fd(int min) +{ + if (min < 0 || min >= FD_MAX) return err(EINVAL); + for (int i = min; i < FD_MAX; i++) + { + // FIXME: Possible race condition if multiple threads share a FileDescriptorTable? Let's not worry about it for + // now, we're still a long way away from reaching that point. + if (!fd_table->fds[i].has_value()) { return i; } + } + + return err(EMFILE); +} diff --git a/kernel/src/thread/Thread.h b/kernel/src/thread/Thread.h index 1df015d5..ca1b5aa5 100644 --- a/kernel/src/thread/Thread.h +++ b/kernel/src/thread/Thread.h @@ -1,6 +1,7 @@ #pragma once #include "arch/MMU.h" +#include "fs/VFS.h" #include "memory/UserVM.h" #include #include @@ -21,6 +22,20 @@ enum class ThreadState Dying }; +struct FileDescriptor +{ + SharedPtr inode; + usize offset { 0 }; + int flags { 0 }; +}; + +static constexpr int FD_MAX = 64; + +struct FileDescriptorTable +{ + Option fds[FD_MAX] = {}; +}; + struct Thread : public LinkedListNode { Registers regs; @@ -38,6 +53,9 @@ struct Thread : public LinkedListNode Stack kernel_stack; OwnedPtr vm_allocator; + Option fd_table; + + Result allocate_fd(int min); FPData fp_data; diff --git a/libc/CMakeLists.txt b/libc/CMakeLists.txt index 567f5a08..2a1b5048 100644 --- a/libc/CMakeLists.txt +++ b/libc/CMakeLists.txt @@ -7,6 +7,7 @@ set(SOURCES src/unistd.cpp src/errno.cpp src/string.cpp + src/fcntl.cpp src/assert.cpp src/atexit.cpp src/ctype.cpp diff --git a/libc/include/fcntl.h b/libc/include/fcntl.h new file mode 100644 index 00000000..401f936b --- /dev/null +++ b/libc/include/fcntl.h @@ -0,0 +1,18 @@ +/* fcntl.h: File control. */ + +#ifndef _FCNTL_H +#define _FCNTL_H + +#ifdef __cplusplus +extern "C" +{ +#endif + + /* Open a file path and return a file descriptor to it. */ + int open(const char* path, int flags); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libc/include/unistd.h b/libc/include/unistd.h index de7d321b..f7782ff1 100644 --- a/libc/include/unistd.h +++ b/libc/include/unistd.h @@ -30,6 +30,9 @@ extern "C" /* Sleeps for X seconds. */ unsigned long sleep(unsigned long seconds); + /* Closes a file descriptor. */ + int close(int fd); + #ifdef __cplusplus } #endif diff --git a/libc/src/fcntl.cpp b/libc/src/fcntl.cpp new file mode 100644 index 00000000..a2bbba8d --- /dev/null +++ b/libc/src/fcntl.cpp @@ -0,0 +1,13 @@ +#include +#include +#include +#include + +extern "C" +{ + int open(const char* path, int flags) + { + long rc = syscall(SYS_open, path, flags); + __errno_return(rc, int); + } +} diff --git a/libc/src/unistd.cpp b/libc/src/unistd.cpp index d83afe5b..4e459bd1 100644 --- a/libc/src/unistd.cpp +++ b/libc/src/unistd.cpp @@ -37,4 +37,10 @@ extern "C" syscall(SYS_usleep, seconds * 1000000); return 0; } + + int close(int fd) + { + long rc = syscall(SYS_close, fd); + __errno_return(rc, int); + } } diff --git a/libluna/include/luna/Syscall.h b/libluna/include/luna/Syscall.h index 65b1adf4..2e4afc2a 100644 --- a/libluna/include/luna/Syscall.h +++ b/libluna/include/luna/Syscall.h @@ -1,7 +1,7 @@ #pragma once #define enumerate_syscalls(_e) \ - _e(exit) _e(console_write) _e(clock_gettime) _e(allocate_memory) _e(deallocate_memory) _e(usleep) + _e(exit) _e(console_write) _e(clock_gettime) _e(allocate_memory) _e(deallocate_memory) _e(usleep) _e(open) _e(close) enum Syscalls {