Browse Source

feat(file): add file descriptors

greatbridf 2 năm trước cách đây
mục cha
commit
79482631aa

+ 111 - 2
include/kernel/process.hpp

@@ -1,14 +1,18 @@
 #pragma once
 
-#include "types/map.hpp"
-#include "types/pair.hpp"
+#include <kernel/errno.h>
 #include <kernel/event/evtqueue.hpp>
 #include <kernel/interrupt.h>
 #include <kernel/mm.hpp>
 #include <kernel/task.h>
+#include <kernel/vfs.hpp>
+#include <types/allocator.hpp>
 #include <types/cplusplus.hpp>
 #include <types/hash_map.hpp>
 #include <types/list.hpp>
+#include <types/map.hpp>
+#include <types/pair.hpp>
+#include <types/status.h>
 #include <types/stdint.h>
 #include <types/types.h>
 
@@ -141,6 +145,110 @@ public:
 };
 
 class process {
+public:
+    class filearr {
+    public:
+        using container_type = types::list<fs::file>;
+        using array_type = types::hash_map<int, container_type::iterator_type, types::linux_hasher<size_t>>;
+
+    private:
+        inline static container_type* files = nullptr;
+        array_type arr;
+        int next_fd = 0;
+
+    public:
+        constexpr filearr(const filearr&) = delete;
+        constexpr filearr& operator=(const filearr&) = delete;
+        constexpr filearr& operator=(filearr&&) = delete;
+        constexpr filearr(filearr&& val)
+            : arr { types::move(val.arr) }
+            , next_fd { val.next_fd }
+        {
+            val.next_fd = 0;
+        }
+
+        explicit filearr()
+        {
+            if (!files)
+                files = types::pnew<types::kernel_allocator>(files);
+        }
+
+        constexpr void dup(const filearr& orig)
+        {
+            if (this->next_fd)
+                return;
+
+            this->next_fd = orig.next_fd;
+
+            for (int i = 0; i < this->next_fd; ++i) {
+                auto iter = orig.arr.find(i);
+                if (!iter)
+                    continue;
+
+                this->arr.emplace(iter->key, iter->value);
+                ++iter->value->ref;
+            }
+        }
+
+        constexpr fs::file* operator[](int i) const
+        {
+            auto iter = arr.find(i);
+            if (!iter)
+                return nullptr;
+            else
+                return &iter->value;
+        }
+
+        // TODO: file opening flags (permissions etc.)
+        int open(const char* filename, uint32_t)
+        {
+            auto* dentry = fs::vfs_open(filename);
+
+            if (!dentry) {
+                errno = ENOTFOUND;
+                return -1;
+            }
+
+            if (!(dentry->ind->flags.in.file || dentry->ind->flags.in.special_node)) {
+                errno = EISDIR;
+                return -1;
+            }
+
+            auto iter = files->emplace_back(fs::file {
+                fs::file::types::regular_file,
+                { .ind = dentry->ind },
+                0,
+                1 });
+
+            int fd = next_fd++;
+            arr.emplace(fd, iter);
+            return fd;
+        }
+
+        // close file descriptor
+        // where iter is guaranteed not nullptr
+        constexpr void close(array_type::iterator_type iter)
+        {
+            if (iter->value->ref == 1)
+                files->erase(iter->value);
+            else
+                --iter->value->ref;
+        }
+
+        constexpr void close(int fd)
+        {
+            auto iter = arr.find(fd);
+            if (iter)
+                close(iter);
+        }
+
+        constexpr ~filearr()
+        {
+            for (int i = 0; i < next_fd; ++i)
+                close(i);
+        }
+    };
+
 public:
     mutable kernel::mm_list mms;
     thdlist thds;
@@ -148,6 +256,7 @@ public:
     process_attr attr;
     pid_t pid;
     pid_t ppid;
+    filearr files;
 
 public:
     process(process&& val);

+ 11 - 0
include/kernel/vfs.hpp

@@ -162,6 +162,17 @@ public:
     virtual int inode_stat(dentry* dir, stat* stat);
 };
 
+struct file {
+    enum class types {
+        regular_file,
+    } type;
+    union {
+        inode* ind;
+    } impl;
+    size_t cursor;
+    size_t ref;
+};
+
 inline fs::vfs::dentry* fs_root;
 
 void register_special_block(uint16_t major,

+ 4 - 0
src/kernel/process.cpp

@@ -52,6 +52,7 @@ process::process(process&& val)
     , attr { val.attr }
     , pid(val.pid)
     , ppid(val.ppid)
+    , files(types::move(val.files))
 {
     if (current_process == &val)
         current_process = this;
@@ -71,6 +72,8 @@ process::process(const process& parent)
 
         mms.mirror_area(area);
     }
+
+    this->files.dup(parent.files);
 }
 
 process::process(pid_t _ppid, bool _system)
@@ -207,6 +210,7 @@ void NORETURN init_scheduler()
 
     // init process has no parent
     auto* init = &procs->emplace(0)->value;
+    init->files.open("/dev/console", 0);
 
     // we need interrupts enabled for cow mapping so now we disable it
     // in case timer interrupt mess things up

+ 13 - 2
src/kernel/syscall.cpp

@@ -7,6 +7,7 @@
 #include <kernel/process.hpp>
 #include <kernel/syscall.hpp>
 #include <kernel/tty.h>
+#include <kernel/vfs.hpp>
 #include <kernel_main.h>
 #include <types/allocator.hpp>
 #include <types/assert.h>
@@ -75,9 +76,19 @@ void _syscall_fork(interrupt_stack* data)
 
 void _syscall_write(interrupt_stack* data)
 {
-    tty_print(console, reinterpret_cast<const char*>(data->s_regs.edi));
+    int fd = data->s_regs.edi;
+    const char* buf = reinterpret_cast<const char*>(data->s_regs.esi);
+    size_t n = data->s_regs.edx;
 
-    SYSCALL_SET_RETURN_VAL(0, 0);
+    auto* file = current_process->files[fd];
+    if (file->type != fs::file::types::regular_file) {
+        SYSCALL_SET_RETURN_VAL(GB_FAILED, EINVAL);
+        return;
+    }
+
+    int n_wrote = fs::vfs_write(file->impl.ind, buf, file->cursor, n);
+    file->cursor += n_wrote;
+    SYSCALL_SET_RETURN_VAL(n_wrote, 0);
 }
 
 void _syscall_sleep(interrupt_stack* data)

+ 11 - 0
src/kernel/vfs.cpp

@@ -473,12 +473,23 @@ size_t b_null_write(fs::special_node*, const char*, size_t, size_t n)
 {
     return n;
 }
+static size_t console_write(fs::special_node*, const char* buf, size_t, size_t n)
+{
+    size_t orig_n = n;
+    while (n--)
+        console->ops->put_char(console, *(buf++));
+
+    return orig_n;
+}
 
 void init_vfs(void)
 {
     using namespace fs;
     // null
     register_special_block(0, 0, b_null_read, b_null_write, 0, 0);
+    // console (supports serial console only for now)
+    // TODO: add interface to bind console device to other devices
+    register_special_block(1, 0, nullptr, console_write, 0, 0);
 
     fs_es = types::pnew<types::kernel_ident_allocator>(fs_es);
 

+ 17 - 14
user-space-program/basic-lib.h

@@ -3,60 +3,63 @@ typedef __UINT16_TYPE__ uint16_t;
 typedef __UINT8_TYPE__ uint8_t;
 
 typedef uint32_t pid_t;
+typedef uint32_t size_t;
 
 #define GNU_ATTRIBUTE(attr) __attribute__((attr))
 #define NORETURN GNU_ATTRIBUTE(noreturn)
 
-static inline uint32_t syscall(uint32_t num, uint32_t arg1, uint32_t arg2)
+static inline uint32_t syscall(uint32_t num, uint32_t arg1, uint32_t arg2, uint32_t arg3)
 {
     asm volatile(
         "movl %1, %%edi\n"
         "movl %2, %%esi\n"
-        "movl %3, %%eax\n"
+        "movl %3, %%edx\n"
+        "movl %4, %%eax\n"
         "int $0x80\n"
         "movl %%eax, %0"
         : "=g"(num)
-        : "g"(arg1), "g"(arg2), "g"(num)
+        : "g"(arg1), "g"(arg2), "g"(arg3), "g"(num)
         : "eax", "edx", "edi", "esi");
     return num;
 }
 
-static inline void NORETURN syscall_noreturn(uint32_t num, uint32_t arg1, uint32_t arg2)
+static inline void NORETURN syscall_noreturn(uint32_t num, uint32_t arg1, uint32_t arg2, uint32_t arg3)
 {
     asm volatile(
         "movl %1, %%edi\n"
         "movl %2, %%esi\n"
-        "movl %3, %%eax\n"
+        "movl %3, %%edx\n"
+        "movl %4, %%eax\n"
         "int $0x80\n"
         "movl %%eax, %0"
         : "=g"(num)
-        : "g"(arg1), "g"(arg2), "g"(num)
+        : "g"(arg1), "g"(arg2), "g"(arg3), "g"(num)
         : "eax", "edx", "edi", "esi");
     // crash
-    syscall_noreturn(0x05, 0, 0);
+    syscall_noreturn(0x05, 0, 0, 0);
 }
 
 static inline int fork(void)
 {
-    return syscall(0x00, 0, 0);
+    return syscall(0x00, 0, 0, 0);
 }
-static inline uint32_t write(const char* buf)
+static inline uint32_t write(int fd, const char* buf, size_t count)
 {
-    return syscall(0x01, (uint32_t)buf, 0);
+    return syscall(0x01, fd, (uint32_t)buf, count);
 }
 static inline void sleep(void)
 {
-    syscall(0x02, 0, 0);
+    syscall(0x02, 0, 0, 0);
 }
 static inline void NORETURN exec(const char* bin, const char** argv)
 {
-    syscall_noreturn(0x04, (uint32_t)bin, (uint32_t)argv);
+    syscall_noreturn(0x04, (uint32_t)bin, (uint32_t)argv, 0);
 }
 static inline void NORETURN exit(int exit_code)
 {
-    syscall_noreturn(0x05, exit_code, 0);
+    syscall_noreturn(0x05, exit_code, 0, 0);
 }
 static inline uint32_t wait(int* return_value)
 {
-    return syscall(0x06, (uint32_t)return_value, 0);
+    return syscall(0x06, (uint32_t)return_value, 0, 0);
 }

+ 4 - 4
user-space-program/init.c

@@ -3,16 +3,16 @@
 int main(int argc, char** argv)
 {
     for (int i = 0; i < argc; ++i)
-        write(argv[i]);
+        write(0, argv[i], 0);
 
     const char* data = "Hello World from user space init\n";
-    write(data);
+    write(0, data, 33);
     int ret = fork();
     if (ret == 0) {
-        write("child\n");
+        write(0, "child\n", 6);
         exit(255);
     } else {
-        write("parent\n");
+        write(0, "parent\n", 7);
     }
 
     for (;;) {