aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authormylai-mtk <ming-yi.lai@mediatek.com>2024-03-23 04:56:11 +0800
committerGitHub <noreply@github.com>2024-03-22 13:56:11 -0700
commit9637e60b96b21a7f85a85bf033b87f64fb823b6c (patch)
treeddb0bcf4d4a4f5feac8f68f02a4723dd9f346ac4
parentf03685954e825a974e59f278b5c8647440291fc7 (diff)
downloadpk-9637e60b96b21a7f85a85bf033b87f64fb823b6c.zip
pk-9637e60b96b21a7f85a85bf033b87f64fb823b6c.tar.gz
pk-9637e60b96b21a7f85a85bf033b87f64fb823b6c.tar.bz2
Implement syscall readlinkat and readv (#318)
* Implement syscall readlinkat * Implement syscall readv by read syscalls Since pk lacks kernel-space dynamic memory management, we implement readv with normal read syscalls rather than forwarding it to spike
-rw-r--r--pk/syscall.c87
-rw-r--r--pk/syscall.h1
2 files changed, 88 insertions, 0 deletions
diff --git a/pk/syscall.c b/pk/syscall.c
index bda4393..3dd0bf7 100644
--- a/pk/syscall.c
+++ b/pk/syscall.c
@@ -13,6 +13,11 @@
typedef long (*syscall_t)(long, long, long, long, long, long, long);
+struct iovec {
+ void *iov_base;
+ size_t iov_len;
+};
+
#define CLOCK_FREQ 1000000000
#define MAX_BUF 512
@@ -566,6 +571,86 @@ int sys_chdir(const char *path)
return frontend_syscall(SYS_chdir, kva2pa(kbuf), 0, 0, 0, 0, 0, 0);
}
+int sys_readlinkat(int dirfd, const char *pathname, char *buf, size_t bufsiz)
+{
+ if (bufsiz > MAX_BUF)
+ return -ENOMEM;
+
+ const int kdirfd = at_kfd(dirfd);
+ if (kdirfd == -1)
+ return -EBADF;
+
+ char kpathname[MAX_BUF];
+ if (!strcpy_from_user(kpathname, pathname, MAX_BUF))
+ return -ENAMETOOLONG;
+ const size_t pathname_len = strlen(kpathname);
+
+ char kbuf[MAX_BUF];
+ const ssize_t ret = frontend_syscall(SYS_readlinkat, kdirfd, kva2pa(kpathname),
+ pathname_len + 1, kva2pa(kbuf), bufsiz, 0, 0);
+ if (ret < 0)
+ return ret;
+
+ if (ret > 0)
+ memcpy_to_user(buf, kbuf, ret);
+ return ret;
+}
+
+ssize_t sys_readv(int fd, const struct iovec *iov, int iovcnt)
+{
+ if (iovcnt < 0)
+ return -EINVAL;
+ if (iov == NULL)
+ return -EFAULT;
+
+ file_t * const f = file_get(fd);
+ if (!f)
+ return -EBADF;
+
+ ssize_t ret = 0;
+ for (int cur_iovcnt = 0; cur_iovcnt < iovcnt; ++cur_iovcnt) {
+ struct iovec kiov;
+ memcpy_from_user(&kiov, iov + cur_iovcnt, sizeof(struct iovec));
+
+ // iov_len is too large to be represented in ssize_t
+ if (kiov.iov_len & (1ULL << (sizeof(kiov.iov_len) * 8 - 1))) {
+ ret = -EINVAL;
+ goto out_decref_f;
+ }
+
+ char *buf = kiov.iov_base;
+ for (size_t already_read_size = 0; already_read_size < kiov.iov_len; ) {
+ char kread_buf[MAX_BUF];
+ const size_t to_read_size = MIN(kiov.iov_len - already_read_size, sizeof(kread_buf));
+ const ssize_t read_res = file_read(f, kread_buf, to_read_size);
+ if (read_res < 0) {
+ ret = read_res;
+ goto out_decref_f;
+ }
+
+ memcpy_to_user(buf, kread_buf, read_res);
+
+ already_read_size += read_res;
+ if (read_res < to_read_size) {
+ ret += already_read_size;
+ goto out_decref_f;
+ }
+
+ buf += read_res;
+ }
+
+ ret += kiov.iov_len;
+ if (ret < 0) { // ret overflowed
+ ret = -EINVAL;
+ goto out_decref_f;
+ }
+ }
+
+out_decref_f:
+ file_decref(f);
+ return ret;
+}
+
void sys_tgkill(int tgid, int tid, int sig)
{
// assume target is current thread
@@ -632,6 +717,8 @@ long do_syscall(long a0, long a1, long a2, long a3, long a4, long a5, unsigned l
[SYS_rt_sigprocmask] = sys_stub_success,
[SYS_clock_gettime] = sys_clock_gettime,
[SYS_chdir] = sys_chdir,
+ [SYS_readlinkat] = sys_readlinkat,
+ [SYS_readv] = sys_readv,
};
const static void* old_syscall_table[] = {
diff --git a/pk/syscall.h b/pk/syscall.h
index 31fb3be..6731edd 100644
--- a/pk/syscall.h
+++ b/pk/syscall.h
@@ -58,6 +58,7 @@
#define SYS_set_robust_list 99
#define SYS_madvise 233
#define SYS_statx 291
+#define SYS_readv 65
#define OLD_SYSCALL_THRESHOLD 1024
#define SYS_open 1024