diff options
Diffstat (limited to 'src/kernel/syscall.cc')
| -rw-r--r-- | src/kernel/syscall.cc | 348 |
1 files changed, 312 insertions, 36 deletions
diff --git a/src/kernel/syscall.cc b/src/kernel/syscall.cc index 92b1a1b..6af7730 100644 --- a/src/kernel/syscall.cc +++ b/src/kernel/syscall.cc @@ -1,22 +1,34 @@ #include "kernel/syscall.h" #include "common/types.h" +#include "common/fcntl.h" #include "kernel/proc.h" #include "kernel/riscv.h" #include "drivers/uart.h" +#include "drivers/virtio.h" #include "kernel/timer.h" #include "kernel/mm.h" +#include "kernel/trap.h" +#include "kernel/slab.h" +#include "fs/fat32.h" +#include "fs/file.h" +#include "lib/string.h" -extern int fork(); +extern "C++" int fork(); +namespace Exec +{ + int exec(char *path, char **argv); +} namespace ProcManager { void exit(int status); - int wait(uint64 addr); + int wait(uint64_t addr); } -uint64 argraw(int n) + +static uint64_t argraw(int n) { - struct Proc *p = myproc(); + Proc *p = myproc(); switch (n) { case 0: @@ -31,76 +43,237 @@ uint64 argraw(int n) return p->tf->a4; case 5: return p->tf->a5; + default: + return static_cast<uint64_t>(-1); + } +} + +static int argint(int n, int *ip) +{ + *ip = static_cast<int>(argraw(n)); + return 0; +} + +static int argstr(int n, char *buf, int max) +{ + uint64 addr = argraw(n); + return VM::copyinstr(myproc()->pagetable, buf, addr, max); +} + +struct KernelArgv +{ + static const int MAX_ARGS = 32; + static const int MAX_ARG_LEN = 128; + + char *args[MAX_ARGS]; + + KernelArgv() + { + memset(args, 0, sizeof(args)); + } + + ~KernelArgv() + { + for (int i = 0; i < MAX_ARGS; i++) + { + if (args[i]) + { + Slab::kfree(args[i]); + args[i] = nullptr; + } + } + } + + KernelArgv(const KernelArgv &) = delete; + KernelArgv &operator=(const KernelArgv &) = delete; +}; + +static int fdalloc(struct file *f) +{ + struct Proc *p = myproc(); + for (int i = 0; i < NOFILE; i++) + { + if (p->ofile[i] == 0) + { + p->ofile[i] = f; + return i; + } } return -1; } -int argint(int n, int *ip) +static uint64 sys_open() +{ + char path[128]; + int omode; + int fd; + struct file *f; + Inode *ip; + + if (argstr(0, path, 128) < 0 || argint(1, &omode) < 0) + return -1; + + ip = VFS::namei(path); + if (ip == nullptr) + { + return -1; + } + + f = FileTable::alloc(); + if (f == nullptr) + { + VFS::iput(ip); + return -1; + } + + fd = fdalloc(f); + if (fd < 0) + { + f->ref = 0; + f->type = FD_NONE; + VFS::iput(ip); + return -1; + } + + f->type = FD_INODE; + f->ip = ip; + f->off = 0; + f->readable = !(omode & O_WRONLY); + f->writable = (omode & O_WRONLY) || (omode & O_RDWR); + + return fd; +} + +static uint64 sys_close() { - *ip = argraw(n); + int fd; + if (argint(0, &fd) < 0) + return -1; + + struct Proc *p = myproc(); + if (fd < 0 || fd >= NOFILE || p->ofile[fd] == 0) + return -1; + + FileTable::close(p->ofile[fd]); + p->ofile[fd] = 0; return 0; } -uint64 sys_exit() +static uint64 sys_exec() +{ + char path[128]; + uint64 uargv_ptr; + + if (argstr(0, path, sizeof(path)) < 0) + { + return -1; + } + + if (argint(1, (int *)&uargv_ptr) < 0) + { + return -1; + } + + KernelArgv kargv; + + for (int i = 0; i < KernelArgv::MAX_ARGS; ++i) + { + uint64 uarg_str_ptr; + + if (VM::copyin(myproc()->pagetable, (char *)&uarg_str_ptr, uargv_ptr + i * sizeof(uint64), sizeof(uint64)) < 0) + { + return -1; + } + + if (uarg_str_ptr == 0) + { + kargv.args[i] = nullptr; + break; + } + + kargv.args[i] = (char *)Slab::kmalloc(KernelArgv::MAX_ARG_LEN); + if (kargv.args[i] == nullptr) + { + return -1; + } + + if (VM::copyinstr(myproc()->pagetable, kargv.args[i], uarg_str_ptr, KernelArgv::MAX_ARG_LEN) < 0) + { + return -1; + } + } + + return Exec::exec(path, kargv.args); +} + +static uint64 sys_exit() { int n; if (argint(0, &n) < 0) - return -1; + return static_cast<uint64>(-1); ProcManager::exit(n); return 0; } -uint64 sys_fork() +static uint64 sys_fork() { - return fork(); + return static_cast<uint64>(fork()); } -uint64 sys_wait() +static uint64 sys_wait() { - uint64 p; - p = argraw(0); - return ProcManager::wait(p); + uint64 p = argraw(0); + return static_cast<uint64>(ProcManager::wait(p)); } -uint64 sys_getpid() +static uint64 sys_getpid() { - return myproc()->pid; + return static_cast<uint64>(myproc()->pid); } -uint64 sys_putc() +static uint64 sys_putc() { - char c = (char)argraw(0); + char c = static_cast<char>(argraw(0)); Drivers::uart_putc(c); return 0; } -uint64 sys_write() +static uint64 sys_write() { - int fd; - uint64 p; + struct file *f; int n; + uint64 p; + int fd; - if (argint(0, &fd) < 0 || argint(2, &n) < 0 || argraw(1) == 0) + if (argint(0, &fd) < 0 || argint(2, &n) < 0 || argint(1, (int *)&p) < 0) return -1; + + struct Proc *proc = myproc(); + p = argraw(1); - if (fd == 1) + // Drivers::uart_puts("DEBUG: sys_write fd="); + // Drivers::uart_put_int(fd); + // Drivers::uart_puts(" len="); + // Drivers::uart_put_int(n); + // Drivers::uart_puts("\n"); + + if (fd == 1 && proc->ofile[fd] == nullptr) // stdout { - struct Proc *proc = myproc(); - const int max = 128; - char buf[max]; + constexpr int MAX_WRITE_BUF = 128; + char buf[MAX_WRITE_BUF]; int i = 0; while (i < n) { int len = n - i; - if (len > max) - len = max; + if (len > MAX_WRITE_BUF) + len = MAX_WRITE_BUF; - if (VM::copyin(proc->pagetable, buf, p + i, len) < 0) + if (VM::copyin(proc->pagetable, buf, p + i, static_cast<uint64>(len)) < 0) { Drivers::uart_puts("sys_write: copyin failed\n"); - return -1; + return static_cast<uint64>(-1); } for (int j = 0; j < len; j++) @@ -109,25 +282,111 @@ uint64 sys_write() } i += len; } - return n; + return static_cast<uint64>(n); + } + if (fd < 0 || fd >= NOFILE || (f = proc->ofile[fd]) == 0) + return static_cast<uint64>(-1); + + return FileTable::write(f, p, n); +} + +static uint64_t sys_read() +{ + struct file *f; + int n; + uint64 p; + int fd; + + // get param: fd, buf, len + if (argint(0, &fd) < 0 || argint(2, &n) < 0 || argint(1, (int *)&p) < 0) + return -1; + + struct Proc* proc = myproc(); + if (fd == 0 && proc->ofile[fd] == nullptr) + { + return Drivers::console_read(p, n); } + + if (fd < 0 || fd >= NOFILE || (f = proc->ofile[fd]) == 0) + return -1; + + return FileTable::read(f, p, n); + return -1; } -void syscall() +static uint64 sys_sbrk() +{ + int n; + if (argint(0, &n) < 0) + return -1; + + uint64 addr = myproc()->sz; + if (ProcManager::growproc(n) < 0) + return -1; + + return addr; +} + +static uint64 sys_disk_test() { + // VirtIO::test_rw(); + // VirtIO::test_bio(); + fat32_test(); + return 0; +} + +static uint64 sys_lseek() +{ + int fd, offset, whence; + if (argint(0, &fd) < 0 || argint(1, &offset) < 0 || argint(2, &whence) < 0) + return -1; + struct Proc *p = myproc(); + if (fd < 0 || fd >= NOFILE || p->ofile[fd] == 0) + return -1; + + return FileTable::lseek(p->ofile[fd], offset, whence); +} + +void syscall() +{ + Proc *p = myproc(); int num = p->tf->a7; - uint64 ret = -1; + uint64 ret = static_cast<uint64>(-1); + + /* Just For Debug */ + // Drivers::uart_puts("Syscall: "); + // Drivers::print_hex(num); + // Drivers::uart_puts("\n"); switch (num) { + case SYS_open: + ret = sys_open(); + break; + case SYS_close: + ret = sys_close(); + break; + case SYS_write: + ret = sys_write(); + break; + case SYS_read: + ret = sys_read(); + break; case SYS_putc: ret = sys_putc(); break; case SYS_fork: ret = sys_fork(); break; + case SYS_exec: + ret = sys_exec(); + if (ret != static_cast<uint64>(-1)) + { + return; + } + break; case SYS_exit: ret = sys_exit(); break; @@ -137,14 +396,31 @@ void syscall() case SYS_getpid: ret = sys_getpid(); break; - case SYS_write: - ret = sys_write(); + case SYS_sbrk: + ret = sys_sbrk(); + break; + case SYS_disk_test: + ret = sys_disk_test(); + break; + case SYS_lseek: + ret = sys_lseek(); + break; + case SYS_pipe: + case SYS_dup: + case SYS_chdir: + case SYS_fstat: + case SYS_mkdir: + case SYS_mknod: + case SYS_unlink: + case SYS_link: + Drivers::uart_puts("Unimplemented syscall\n"); + ret = static_cast<uint64>(-1); break; default: Drivers::uart_puts("Unknown Syscall ID: "); Drivers::print_hex(num); Drivers::uart_puts("\n"); - ret = -1; + ret = static_cast<uint64>(-1); break; } |
