From ac9741e12222e72bad3414bc6f588e70a3d130cc Mon Sep 17 00:00:00 2001 From: Richard Qin Date: Tue, 14 Apr 2026 22:47:15 +0800 Subject: feat: implement FDT-based memory discovery and add comprehensive debug logging to exec syscalls --- src/kernel/syscall.cc | 377 ++++++++++++++++++++++++-------------------------- 1 file changed, 182 insertions(+), 195 deletions(-) (limited to 'src/kernel/syscall.cc') diff --git a/src/kernel/syscall.cc b/src/kernel/syscall.cc index b891ada..0979c24 100644 --- a/src/kernel/syscall.cc +++ b/src/kernel/syscall.cc @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-or-later /* - * Copyright (C) 2026 Richard QIn + * Copyright (C) 2026 Richard Qin */ #include "kernel/syscall.h" #include "common/types.h" @@ -17,12 +17,13 @@ #include "fs/fat32.h" #include "fs/file.h" #include "lib/string.h" +#include "lib/errno.h" extern "C++" int fork(); namespace Exec { int exec(char *path, char **argv); -} +} namespace ProcManager { @@ -30,7 +31,6 @@ namespace ProcManager int wait(uint64_t addr); } - static uint64_t argraw(int n) { Proc *p = myproc(); @@ -69,26 +69,18 @@ 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() { 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; }; @@ -107,16 +99,17 @@ static int fdalloc(struct file *f) return -1; } -static uint64 sys_open() +// sys_openat(int dfd, const char *filename, int flags, mode_t mode) +static uint64 sys_openat() { char path[128]; - int omode; + int dfd, omode, mode_unused; int fd; struct file *f; Inode *ip; - if (argstr(0, path, 128) < 0 || argint(1, &omode) < 0) - return -1; + if (argint(0, &dfd) < 0 || argstr(1, path, 128) < 0 || argint(2, &omode) < 0 || argint(3, &mode_unused) < 0) + return -EINVAL; if (omode & O_CREATE) { @@ -139,9 +132,7 @@ static uint64 sys_open() } if (ip == nullptr) - { - return -1; - } + return -ENOENT; VFS::ilock(ip); if ((omode & O_TRUNC) && ip->type == T_FILE) @@ -154,7 +145,7 @@ static uint64 sys_open() if (f == nullptr) { VFS::iput(ip); - return -1; + return -ENFILE; } fd = fdalloc(f); @@ -163,7 +154,7 @@ static uint64 sys_open() f->ref = 0; f->type = FD_NONE; VFS::iput(ip); - return -1; + return -EMFILE; } f->type = FD_INODE; @@ -175,30 +166,33 @@ static uint64 sys_open() return fd; } -static uint64 sys_mkdir() +// sys_mkdirat(int dfd, const char *pathname, mode_t mode) +static uint64 sys_mkdirat() { char path[128]; - if (argstr(0, path, 128) < 0) - return -1; + int dfd, mode; + + if (argint(0, &dfd) < 0 || argstr(1, path, 128) < 0 || argint(2, &mode) < 0) + return -EINVAL; Inode *ip = VFS::namei(path); if (ip != nullptr) { VFS::iput(ip); - return -1; // the dir is exist + return -EEXIST; } char name[128]; Inode *dp = VFS::nameiparent(path, name); if (dp == nullptr) - return -1; + return -ENOENT; VFS::ilock(dp); ip = dp->create(name, T_DIR, 0, 0); VFS::iunlockput(dp); if (ip == nullptr) - return -1; + return -EIO; VFS::iput(ip); return 0; @@ -208,24 +202,24 @@ static uint64 sys_chdir() { char path[128]; if (argstr(0, path, 128) < 0) - return -1; + return -EFAULT; Inode *ip = VFS::namei(path); if (ip == nullptr) - return -1; + return -ENOENT; VFS::ilock(ip); if (ip->type != T_DIR) { VFS::iunlockput(ip); - return -1; + return -ENOTDIR; } VFS::iunlock(ip); struct Proc *p = myproc(); - VFS::iput(p->cwd); // release old cwd - p->cwd = ip; // switch to new cwd - + if (p->cwd) + VFS::iput(p->cwd); + p->cwd = ip; return 0; } @@ -233,18 +227,18 @@ static uint64 sys_dup() { int oldfd; if (argint(0, &oldfd) < 0) - return -1; + return -EINVAL; struct Proc *p = myproc(); if (oldfd < 0 || oldfd >= NOFILE || p->ofile[oldfd] == nullptr) - return -1; + return -EBADF; struct file *f = FileTable::dup(p->ofile[oldfd]); int newfd = fdalloc(f); if (newfd < 0) { - FileTable::close(f); // fdalloc failed - return -1; + FileTable::close(f); + return -EMFILE; } return newfd; } @@ -255,75 +249,86 @@ static uint64 sys_fstat() uint64 stat_addr; if (argint(0, &fd) < 0 || argint(1, (int *)&stat_addr) < 0) - return -1; + return -EINVAL; struct Proc *p = myproc(); if (fd < 0 || fd >= NOFILE || p->ofile[fd] == nullptr) - return -1; + return -EBADF; - return FileTable::stat(p->ofile[fd], stat_addr); + if (FileTable::stat(p->ofile[fd], stat_addr) < 0) + return -EIO; + + return 0; } -static uint64 sys_mknod() +// sys_mknodat(int dfd, const char *filename, mode_t mode, dev_t dev) +static uint64 sys_mknodat() { char path[128]; - int major, minor; + int dfd, mode, dev; - if (argstr(0, path, 128) < 0 || argint(1, &major) < 0 || argint(2, &minor) < 0) - return -1; + if (argint(0, &dfd) < 0 || argstr(1, path, 128) < 0 || argint(2, &mode) < 0 || argint(3, &dev) < 0) + return -EINVAL; Inode *ip = VFS::namei(path); if (ip != nullptr) { VFS::iput(ip); - return -1; + return -EEXIST; } char name[128]; Inode *dp = VFS::nameiparent(path, name); if (dp == nullptr) - return -1; + return -ENOENT; + + // Decode dev_t (Assuming simplified minor/major for now) + int major = (dev >> 20) & 0xFFF; // Just a guess for Linux packing, or pass raw + int minor = dev & 0xFFFFF; + + // For Phase 1 compatibility with init.cc: + // init.cc passes raw major/minor. Shim will pack them. + // We just unpack naively or assume Shim passed us correct structure. VFS::ilock(dp); ip = dp->create(name, T_DEVICE, major, minor); VFS::iunlockput(dp); if (ip == nullptr) - return -1; + return -EIO; VFS::iput(ip); return 0; } - - static uint64 sys_close() { int fd; if (argint(0, &fd) < 0) - return -1; + return -EINVAL; struct Proc *p = myproc(); if (fd < 0 || fd >= NOFILE || p->ofile[fd] == 0) - return -1; + return -EBADF; FileTable::close(p->ofile[fd]); p->ofile[fd] = 0; return 0; } -static uint64 sys_pipe() +static uint64 sys_pipe2() { - uint64 fdarray; // int fd[2] + uint64 fdarray; + int flags; struct file *rf, *wf; int fd0, fd1; struct Proc *p = myproc(); - if (argint(0, (int *)&fdarray) < 0) - return -1; + if (argint(0, (int *)&fdarray) < 0 || argint(1, &flags) < 0) + return -EFAULT; - if(Pipe::create_pair(&rf, &wf) < 0) - return -1; + if (Pipe::create_pair(&rf, &wf) < 0) + return -ENFILE; if ((fd0 = fdalloc(rf)) < 0 || (fd1 = fdalloc(wf)) < 0) { @@ -331,7 +336,7 @@ static uint64 sys_pipe() p->ofile[fd0] = nullptr; FileTable::close(rf); FileTable::close(wf); - return -1; + return -EMFILE; } if (VM::copyout(p->pagetable, fdarray, (char *)&fd0, sizeof(int)) < 0 || @@ -341,56 +346,58 @@ static uint64 sys_pipe() p->ofile[fd1] = nullptr; FileTable::close(rf); FileTable::close(wf); - return -1; + return -EFAULT; } return 0; } -static uint64 sys_link() -{ - Drivers::uart_puts("Not supported now"); - return -1; -} - -static uint64 sys_unlink() +static uint64 sys_unlinkat() { char path[128], name[128]; - if (argstr(0, path, 128) < 0) - return -1; + int dfd, flag; + + if (argint(0, &dfd) < 0 || argstr(1, path, 128) < 0 || argint(2, &flag) < 0) + return -EINVAL; Inode *dp = VFS::nameiparent(path, name); if (!dp) - return -1; + return -ENOENT; VFS::ilock(dp); int ret = dp->unlink(name); VFS::iunlockput(dp); - return ret; + return (ret < 0) ? -EIO : 0; } -static uint64 sys_exec() +// sys_linkat(int olddirfd, const char *oldpath, int newdirfd, const char *newpath, int flags) +static uint64 sys_linkat() +{ + // FAT32 does not support hard links. + // Return Error to allow compilation/running to proceed (ln will fail gracefully). + return -EPERM; +} + +static uint64 sys_execve() { char path[128]; uint64 uargv_ptr; if (argstr(0, path, sizeof(path)) < 0) - { - return -1; - } + return -EFAULT; uargv_ptr = argraw(1); + // uenvp_ptr = argraw(2); // Ignored 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; - } + { + return -EFAULT; + } if (uarg_str_ptr == 0) { @@ -400,16 +407,15 @@ static uint64 sys_exec() kargv.args[i] = (char *)Slab::kmalloc(KernelArgv::MAX_ARG_LEN); if (kargv.args[i] == nullptr) - { - return -1; - } + { + return -ENOMEM; + } if (VM::copyinstr(myproc()->pagetable, kargv.args[i], uarg_str_ptr, KernelArgv::MAX_ARG_LEN) < 0) - { - return -1; - } + { + return -EFAULT; + } } - return Exec::exec(path, kargv.args); } @@ -417,20 +423,29 @@ static uint64 sys_exit() { int n; if (argint(0, &n) < 0) - return static_cast(-1); + return -EINVAL; ProcManager::exit(n); return 0; } -static uint64 sys_fork() +static uint64 sys_clone() { return static_cast(fork()); } -static uint64 sys_wait() +static uint64 sys_wait4() { - uint64 p = argraw(0); - return static_cast(ProcManager::wait(p)); + uint64 status_addr; + + // argraw(0) is pid (ignored) + status_addr = argraw(1); + // argraw(2) is options (ignored) + // argraw(3) is rusage (ignored) + + if (status_addr == static_cast(-1)) + return -EINVAL; + + return static_cast(ProcManager::wait(status_addr)); } static uint64 sys_getpid() @@ -452,20 +467,14 @@ static uint64 sys_write() uint64 p; int fd; - if (argint(0, &fd) < 0 || argint(2, &n) < 0 || argint(1, (int *)&p) < 0) - return -1; - - struct Proc *proc = myproc(); + if (argint(0, &fd) < 0 || argint(1, (int *)&p) < 0 || argint(2, &n) < 0) + return -EINVAL; p = argraw(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"); + struct Proc *proc = myproc(); - if (fd == 1 && proc->ofile[fd] == nullptr) // stdout + if (fd == 1 && proc->ofile[fd] == nullptr) { constexpr int MAX_WRITE_BUF = 128; char buf[MAX_WRITE_BUF]; @@ -478,10 +487,7 @@ static uint64 sys_write() len = MAX_WRITE_BUF; if (VM::copyin(proc->pagetable, buf, p + i, static_cast(len)) < 0) - { - Drivers::uart_puts("sys_write: copyin failed\n"); - return static_cast(-1); - } + return -EFAULT; for (int j = 0; j < len; j++) { @@ -491,8 +497,9 @@ static uint64 sys_write() } return static_cast(n); } + if (fd < 0 || fd >= NOFILE || (f = proc->ofile[fd]) == 0) - return static_cast(-1); + return -EBADF; return FileTable::write(f, p, n); } @@ -504,50 +511,39 @@ static uint64_t sys_read() 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; - + if (argint(0, &fd) < 0 || argint(1, (int *)&p) < 0 || argint(2, &n) < 0) + return -EINVAL; + p = argraw(1); - struct Proc* proc = myproc(); + 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 -EBADF; return FileTable::read(f, p, n); - - return -1; } -static uint64 sys_sbrk() +static uint64 sys_brk() { int n; if (argint(0, &n) < 0) - return -1; + return -EINVAL; uint64 addr = myproc()->sz; if (ProcManager::growproc(n) < 0) - return -1; + return -ENOMEM; return addr; } -static uint64 sys_uptime() -{ - return Timer::get_ticks(); -} - static uint64 sys_kill() { int pid; if (argint(0, &pid) < 0) - return -1; - + return -EINVAL; return ProcManager::kill(pid); } @@ -557,24 +553,20 @@ static uint64 sys_sleep() uint64 ticks0; if (argint(0, &n) < 0) - return -1; + return -EINVAL; Spinlock *lk = Timer::get_lock(); lk->acquire(); - ticks0 = Timer::get_ticks(); - while (Timer::get_ticks() - ticks0 < (uint64)n) { if (myproc()->killed) { lk->release(); - return -1; + return -EINTR; } - ProcManager::sleep(Timer::get_tick_chan(), lk); } - lk->release(); return 0; } @@ -591,20 +583,18 @@ static uint64 sys_lseek() { int fd, offset, whence; if (argint(0, &fd) < 0 || argint(1, &offset) < 0 || argint(2, &whence) < 0) - return -1; + return -EINVAL; struct Proc *p = myproc(); if (fd < 0 || fd >= NOFILE || p->ofile[fd] == 0) - return -1; + return -EBADF; return FileTable::lseek(p->ofile[fd], offset, whence); } -static uint64 sys_shutdown() +static uint64 sys_reboot() { SBI::sbi_shutdown(); - while (1) - ; return 0; } @@ -612,98 +602,95 @@ void syscall() { Proc *p = myproc(); int num = p->tf->a7; - uint64 ret = static_cast(-1); - - /* Just For Debug */ - // Drivers::uart_puts("Syscall: "); - // Drivers::print_hex(num); - // Drivers::uart_puts("\n"); + uint64 ret = static_cast(-ENOSYS); switch (num) { - case SYS_open: - ret = sys_open(); + case SYS_mknodat: + ret = sys_mknodat(); break; - case SYS_close: - ret = sys_close(); + case SYS_mkdirat: + ret = sys_mkdirat(); break; - case SYS_write: - ret = sys_write(); + case SYS_unlinkat: + ret = sys_unlinkat(); break; - case SYS_read: - ret = sys_read(); + case SYS_linkat: + ret = sys_linkat(); 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(-1)) - return; + case SYS_chdir: + ret = sys_chdir(); break; - case SYS_exit: - ret = sys_exit(); + case SYS_openat: + ret = sys_openat(); break; - case SYS_wait: - ret = sys_wait(); + case SYS_dup: + ret = sys_dup(); break; - case SYS_getpid: - ret = sys_getpid(); + case SYS_close: + ret = sys_close(); break; - case SYS_sbrk: - ret = sys_sbrk(); - break; - case SYS_disk_test: - ret = sys_disk_test(); + case SYS_pipe2: + ret = sys_pipe2(); break; case SYS_lseek: ret = sys_lseek(); break; - case SYS_dup: - ret = sys_dup(); + case SYS_read: + ret = sys_read(); + break; + case SYS_write: + ret = sys_write(); break; case SYS_fstat: ret = sys_fstat(); break; - case SYS_chdir: - ret = sys_chdir(); + case SYS_exit: + ret = sys_exit(); + break; + case SYS_exit_group: + ret = sys_exit(); + break; + case SYS_kill: + ret = sys_kill(); break; - case SYS_mkdir: - ret = sys_mkdir(); + case SYS_getpid: + ret = sys_getpid(); break; - case SYS_mknod: - ret = sys_mknod(); + case SYS_brk: + ret = sys_brk(); break; - case SYS_pipe: - ret = sys_pipe(); + case SYS_clone: + ret = sys_clone(); break; - case SYS_unlink: - ret = sys_unlink(); + case SYS_execve: + ret = sys_execve(); + if (ret == 0) + return; break; - case SYS_link: - Drivers::uart_puts("Unimplemented syscall\n"); - ret = sys_link(); + case SYS_wait4: + ret = sys_wait4(); break; - case SYS_uptime: - ret = sys_uptime(); + + // Custom / Debug + case SYS_reboot: + ret = sys_reboot(); break; - case SYS_sleep: - ret = sys_sleep(); + case SYS_putc: + ret = sys_putc(); break; - case SYS_kill: - ret = sys_kill(); + case SYS_disk_test: + ret = sys_disk_test(); break; - case SYS_shutdown: - ret = sys_shutdown(); + case SYS_nanosleep: + ret = sys_sleep(); break; + default: Drivers::uart_puts("Unknown Syscall ID: "); Drivers::print_hex(num); Drivers::uart_puts("\n"); - ret = static_cast(-1); + ret = -ENOSYS; break; } -- cgit v1.2.3