From 0a81fd3a93ad9eaebae17b207c0048bf5fda1aa2 Mon Sep 17 00:00:00 2001 From: Andrew Waterman Date: Tue, 20 Jan 2015 16:40:30 -0800 Subject: Support linkat, unlinkat, mkdirat syscalls Also, old-style syscalls e.g. open are now implemented with e.g. openat. --- pk/file.c | 33 ++++---------- pk/frontend.c | 4 +- pk/frontend.h | 2 +- pk/init.c | 2 +- pk/syscall.c | 139 ++++++++++++++++++++++++++++++++++------------------------ pk/syscall.h | 5 +++ 6 files changed, 100 insertions(+), 85 deletions(-) diff --git a/pk/file.c b/pk/file.c index 4b85372..bc495c2 100644 --- a/pk/file.c +++ b/pk/file.c @@ -27,7 +27,7 @@ void file_decref(file_t* f) mb(); atomic_set(&f->refcnt, 0); - frontend_syscall(SYS_close, kfd, 0, 0, 0, 0); + frontend_syscall(SYS_close, kfd, 0, 0, 0, 0, 0, 0); } } @@ -86,22 +86,7 @@ file_t* file_get(int fd) file_t* file_open(const char* fn, int flags, int mode) { - file_t* f = file_get_free(); - if (f == NULL) - return ERR_PTR(-ENOMEM); - - size_t fn_size = strlen(fn)+1; - long ret = frontend_syscall(SYS_open, (long)fn, fn_size, flags, mode, 0); - if (ret >= 0) - { - f->kfd = ret; - return f; - } - else - { - file_decref(f); - return ERR_PTR(ret); - } + return file_openat(AT_FDCWD, fn, flags, mode); } file_t* file_openat(int dirfd, const char* fn, int flags, int mode) @@ -111,7 +96,7 @@ file_t* file_openat(int dirfd, const char* fn, int flags, int mode) return ERR_PTR(-ENOMEM); size_t fn_size = strlen(fn)+1; - long ret = frontend_syscall(SYS_openat, dirfd, (long)fn, fn_size, flags, mode); + long ret = frontend_syscall(SYS_openat, dirfd, (long)fn, fn_size, flags, mode, 0, 0); if (ret >= 0) { f->kfd = ret; @@ -140,34 +125,34 @@ int fd_close(int fd) ssize_t file_read(file_t* f, void* buf, size_t size) { populate_mapping(buf, size, PROT_WRITE); - return frontend_syscall(SYS_read, f->kfd, (uintptr_t)buf, size, 0, 0); + return frontend_syscall(SYS_read, f->kfd, (uintptr_t)buf, size, 0, 0, 0, 0); } ssize_t file_pread(file_t* f, void* buf, size_t size, off_t offset) { populate_mapping(buf, size, PROT_WRITE); - return frontend_syscall(SYS_pread, f->kfd, (uintptr_t)buf, size, offset, 0); + return frontend_syscall(SYS_pread, f->kfd, (uintptr_t)buf, size, offset, 0, 0, 0); } ssize_t file_write(file_t* f, const void* buf, size_t size) { populate_mapping(buf, size, PROT_READ); - return frontend_syscall(SYS_write, f->kfd, (uintptr_t)buf, size, 0, 0); + return frontend_syscall(SYS_write, f->kfd, (uintptr_t)buf, size, 0, 0, 0, 0); } ssize_t file_pwrite(file_t* f, const void* buf, size_t size, off_t offset) { populate_mapping(buf, size, PROT_READ); - return frontend_syscall(SYS_pwrite, f->kfd, (uintptr_t)buf, size, offset, 0); + return frontend_syscall(SYS_pwrite, f->kfd, (uintptr_t)buf, size, offset, 0, 0, 0); } int file_stat(file_t* f, struct stat* s) { populate_mapping(s, sizeof(*s), PROT_WRITE); - return frontend_syscall(SYS_fstat, f->kfd, (uintptr_t)s, 0, 0, 0); + return frontend_syscall(SYS_fstat, f->kfd, (uintptr_t)s, 0, 0, 0, 0, 0); } ssize_t file_lseek(file_t* f, size_t ptr, int dir) { - return frontend_syscall(SYS_lseek, f->kfd, ptr, dir, 0, 0); + return frontend_syscall(SYS_lseek, f->kfd, ptr, dir, 0, 0, 0, 0); } diff --git a/pk/frontend.c b/pk/frontend.c index 7bf4710..3771bca 100644 --- a/pk/frontend.c +++ b/pk/frontend.c @@ -5,7 +5,7 @@ #include "frontend.h" #include -long frontend_syscall(long n, long a0, long a1, long a2, long a3, long a4) +long frontend_syscall(long n, long a0, long a1, long a2, long a3, long a4, long a5, long a6) { static volatile uint64_t magic_mem[8]; @@ -18,6 +18,8 @@ long frontend_syscall(long n, long a0, long a1, long a2, long a3, long a4) magic_mem[3] = a2; magic_mem[4] = a3; magic_mem[5] = a4; + magic_mem[6] = a5; + magic_mem[7] = a6; mb(); diff --git a/pk/frontend.h b/pk/frontend.h index edbf22a..dde0d0c 100644 --- a/pk/frontend.h +++ b/pk/frontend.h @@ -3,6 +3,6 @@ #ifndef _RISCV_FRONTEND_H #define _RISCV_FRONTEND_H -long frontend_syscall(long n, long a0, long a1, long a2, long a3, long a4); +long frontend_syscall(long n, long a0, long a1, long a2, long a3, long a4, long a5, long a6); #endif diff --git a/pk/init.c b/pk/init.c index db74e70..4bbd095 100644 --- a/pk/init.c +++ b/pk/init.c @@ -59,7 +59,7 @@ struct mainvars { static struct mainvars* handle_args(struct mainvars* args) { - long r = frontend_syscall(SYS_getmainvars, (uintptr_t)args, sizeof(*args), 0, 0, 0); + long r = frontend_syscall(SYS_getmainvars, (uintptr_t)args, sizeof(*args), 0, 0, 0, 0, 0); kassert(r == 0); // argv[0] is the proxy kernel itself. skip it and any flags. diff --git a/pk/syscall.c b/pk/syscall.c index 177d50f..20de310 100644 --- a/pk/syscall.c +++ b/pk/syscall.c @@ -7,7 +7,6 @@ #include "vm.h" #include #include -//#include typedef long (*syscall_t)(long, long, long, long, long, long, long); @@ -51,7 +50,7 @@ void sys_exit(int code) } } - frontend_syscall(SYS_exit, code, 0, 0, 0, 0); + frontend_syscall(SYS_exit, code, 0, 0, 0, 0, 0, 0); clear_csr(status, SR_EI); while (1); } @@ -98,40 +97,40 @@ ssize_t sys_write(int fd, const char* buf, size_t n) return r; } -int sys_open(const char* name, int flags, int mode) +static int at_kfd(int dirfd) { - file_t* file = file_open(name, flags, mode); - if (IS_ERR_VALUE(file)) - return PTR_ERR(file); - - int fd = file_dup(file); - if (fd < 0) - return -ENOMEM; - - return fd; + if (dirfd == AT_FDCWD) + return AT_FDCWD; + file_t* dir = file_get(dirfd); + if (dir == NULL) + return -1; + return dir->kfd; } int sys_openat(int dirfd, const char* name, int flags, int mode) { - if(name[0] == '/'){ - return sys_open(name, flags, mode); - } - file_t* dir = file_get(dirfd); - if(dir) - { - file_t* file = file_openat(dir->kfd, name, flags, mode); + int kfd = at_kfd(dirfd); + if (kfd != -1) { + file_t* file = file_openat(kfd, name, flags, mode); if (IS_ERR_VALUE(file)) return PTR_ERR(file); int fd = file_dup(file); - if (fd < 0) + if (fd < 0) { + file_decref(file); return -ENOMEM; + } return fd; - } + } return -EBADF; } +int sys_open(const char* name, int flags, int mode) +{ + return sys_openat(AT_FDCWD, name, flags, mode); +} + int sys_close(int fd) { int ret = fd_close(fd); @@ -161,7 +160,7 @@ int sys_fcntl(int fd, int cmd, int arg) if (f) { - r = frontend_syscall(SYS_fcntl, f->kfd, cmd, arg, 0, 0); + r = frontend_syscall(SYS_fcntl, f->kfd, cmd, arg, 0, 0, 0, 0); file_decref(f); } @@ -196,76 +195,97 @@ ssize_t sys_lseek(int fd, size_t ptr, int dir) return r; } -long sys_stat(const char* name, void* st) -{ - size_t name_size = strlen(name)+1; - populate_mapping(st, sizeof(struct stat), PROT_WRITE); - return frontend_syscall(SYS_stat, (uintptr_t)name, name_size, (uintptr_t)st, 0, 0); -} - long sys_lstat(const char* name, void* st) { size_t name_size = strlen(name)+1; populate_mapping(st, sizeof(struct stat), PROT_WRITE); - return frontend_syscall(SYS_lstat, (uintptr_t)name, name_size, (uintptr_t)st, 0, 0); + return frontend_syscall(SYS_lstat, (uintptr_t)name, name_size, (uintptr_t)st, 0, 0, 0, 0); } + long sys_fstatat(int dirfd, const char* name, void* st, int flags) { - if(name[0] == '/'){ - return sys_stat(name, st); - } - file_t* dir = file_get(dirfd); - if(dir) - { + int kfd = at_kfd(dirfd); + if (kfd != -1) { size_t name_size = strlen(name)+1; populate_mapping(st, sizeof(struct stat), PROT_WRITE); - return frontend_syscall(SYS_fstatat, dir->kfd, (uintptr_t)name, name_size, (uintptr_t)st, flags); + return frontend_syscall(SYS_fstatat, kfd, (uintptr_t)name, name_size, (uintptr_t)st, flags, 0, 0); } return -EBADF; } -int sys_access(const char *name, int mode){ - size_t name_size = strlen(name)+1; - return frontend_syscall(SYS_access, (uintptr_t)name, name_size, mode, 0, 0); +long sys_stat(const char* name, void* st) +{ + return sys_fstatat(AT_FDCWD, name, st, 0); } -int sys_faccessat(int dirfd, const char *name, int mode, int flags){ - if(name[0] == '/'){ - return sys_access(name, mode); - } - file_t* dir = file_get(dirfd); - if(dir) - { +long sys_faccessat(int dirfd, const char *name, int mode) +{ + int kfd = at_kfd(dirfd); + if (kfd != -1) { size_t name_size = strlen(name)+1; - return frontend_syscall(SYS_access, dir->kfd, (uintptr_t)name, name_size, mode, flags); + return frontend_syscall(SYS_faccessat, kfd, (uintptr_t)name, name_size, mode, 0, 0, 0); + } + return -EBADF; +} + +long sys_access(const char *name, int mode) +{ + return sys_faccessat(AT_FDCWD, name, mode); +} + +long sys_linkat(int old_dirfd, const char* old_name, int new_dirfd, const char* new_name, int flags) +{ + int old_kfd = at_kfd(old_dirfd); + int new_kfd = at_kfd(new_dirfd); + if (old_kfd != -1 && new_kfd != -1) { + size_t old_size = strlen(old_name)+1; + size_t new_size = strlen(new_name)+1; + return frontend_syscall(SYS_linkat, old_kfd, (uintptr_t)old_name, old_size, + new_kfd, (uintptr_t)new_name, new_size, + flags); } return -EBADF; } long sys_link(const char* old_name, const char* new_name) { - size_t old_size = strlen(old_name)+1; - size_t new_size = strlen(new_name)+1; - return frontend_syscall(SYS_link, (uintptr_t)old_name, old_size, - (uintptr_t)new_name, new_size, 0); + return sys_linkat(AT_FDCWD, old_name, AT_FDCWD, new_name, 0); } -long sys_unlink(const char* name, size_t len) +long sys_unlinkat(int dirfd, const char* name, int flags) { - size_t name_size = strlen(name)+1; - return frontend_syscall(SYS_unlink, (uintptr_t)name, name_size, 0, 0, 0); + int kfd = at_kfd(dirfd); + if (kfd != -1) { + size_t name_size = strlen(name)+1; + return frontend_syscall(SYS_unlinkat, kfd, (uintptr_t)name, name_size, flags, 0, 0, 0); + } + return -EBADF; +} + +long sys_unlink(const char* name) +{ + return sys_unlinkat(AT_FDCWD, name, 0); +} + +long sys_mkdirat(int dirfd, const char* name, int mode) +{ + int kfd = at_kfd(dirfd); + if (kfd != -1) { + size_t name_size = strlen(name)+1; + return frontend_syscall(SYS_mkdirat, kfd, (uintptr_t)name, name_size, mode, 0, 0, 0); + } + return -EBADF; } long sys_mkdir(const char* name, int mode) { - size_t name_size = strlen(name)+1; - return frontend_syscall(SYS_mkdir, (uintptr_t)name, name_size, mode, 0, 0); + return sys_mkdirat(AT_FDCWD, name, mode); } long sys_getcwd(const char* buf, size_t size) { populate_mapping(buf, size, PROT_WRITE); - return frontend_syscall(SYS_getcwd, (uintptr_t)buf, size, 0, 0, 0); + return frontend_syscall(SYS_getcwd, (uintptr_t)buf, size, 0, 0, 0, 0, 0); } size_t sys_brk(size_t pos) @@ -413,6 +433,9 @@ long do_syscall(long a0, long a1, long a2, long a3, long a4, long a5, long n) [SYS_link] = sys_link, [SYS_unlink] = sys_unlink, [SYS_mkdir] = sys_mkdir, + [SYS_linkat] = sys_linkat, + [SYS_unlinkat] = sys_unlinkat, + [SYS_mkdirat] = sys_mkdirat, [SYS_getcwd] = sys_getcwd, [SYS_brk] = sys_brk, [SYS_uname] = sys_uname, diff --git a/pk/syscall.h b/pk/syscall.h index a9fc3c8..e071785 100644 --- a/pk/syscall.h +++ b/pk/syscall.h @@ -17,6 +17,9 @@ #define SYS_link 1025 #define SYS_unlink 1026 #define SYS_mkdir 1030 +#define SYS_linkat 37 +#define SYS_unlinkat 35 +#define SYS_mkdirat 34 #define SYS_chdir 49 #define SYS_getcwd 17 #define SYS_stat 1038 @@ -52,6 +55,8 @@ #define ERR_PTR(x) ((void*)(long)(x)) #define PTR_ERR(x) ((long)(x)) +#define AT_FDCWD -100 + void sys_exit(int code) __attribute__((noreturn)); long do_syscall(long a0, long a1, long a2, long a3, long a4, long a5, long n); -- cgit v1.1