Update to linuxemu syscall structure
[akaros.git] / user / vmm / linuxemu.c
1 /* Copyright (c) 2016 Google Inc.
2  * See LICENSE for details.
3  *
4  * Linux emulation for virtual machines. */
5
6 #include <sys/stat.h>
7 #include <sys/types.h>
8 #include <stdio.h>
9 #include <stdlib.h>
10 #include <unistd.h>
11 #include <fcntl.h>
12 #include <vmm/vmm.h>
13 #include <errno.h>
14 #include <sys/syscall.h>
15 #include <vmm/linux_syscalls.h>
16 #include <sys/time.h>
17 #include <vmm/linuxemu.h>
18 #include <dlfcn.h>
19
20 bool dune_sys_read(struct vm_trapframe *tf)
21 {
22         int retval = read(tf->tf_rdi, (void *)tf->tf_rsi, (size_t)tf->tf_rdx);
23
24         if (retval == -1)
25                 tf->tf_rax = -errno;
26         else
27                 tf->tf_rax = retval;
28
29         return true;
30 }
31
32 bool dune_sys_write(struct vm_trapframe *tf)
33 {
34         int retval = write(tf->tf_rdi, (void *)tf->tf_rsi, (size_t)tf->tf_rdx);
35
36         if (retval == -1)
37                 tf->tf_rax = -errno;
38         else
39                 tf->tf_rax = retval;
40
41         return true;
42 }
43
44 bool dune_sys_gettid(struct vm_trapframe *tf)
45 {
46         tf->tf_rax = tf->tf_guest_pcoreid;
47         return true;
48 }
49
50 bool dune_sys_gettimeofday(struct vm_trapframe *tf)
51 {
52         int retval = gettimeofday((struct timeval*)tf->tf_rdi,
53                                   (struct timezone*)tf->tf_rsi);
54         if (retval == -1)
55                 tf->tf_rax = -errno;
56         else
57                 tf->tf_rax = retval;
58
59         return true;
60 }
61
62 void init_syscall_table(void)
63 {
64         int i;
65
66         for (i = 0; i < dune_max_syscall ; ++i) {
67                 dune_syscall_table[i].call = NULL;
68                 dune_syscall_table[i].name = "nosyscall";
69         }
70         // For now setup the syscalls here,
71         // there is probably a better way to do this.
72         dune_syscall_table[DUNE_SYS_WRITE].call = dune_sys_write;
73         dune_syscall_table[DUNE_SYS_WRITE].name = syscalls[DUNE_SYS_WRITE];
74         dune_syscall_table[DUNE_SYS_GETTID].call = dune_sys_gettid;
75         dune_syscall_table[DUNE_SYS_GETTID].name = syscalls[DUNE_SYS_GETTID];
76         dune_syscall_table[DUNE_SYS_GETTIMEOFDAY].call = dune_sys_gettimeofday;
77         dune_syscall_table[DUNE_SYS_GETTIMEOFDAY].name =
78                 syscalls[DUNE_SYS_GETTIMEOFDAY];
79         dune_syscall_table[DUNE_SYS_READ].call = dune_sys_read;
80         dune_syscall_table[DUNE_SYS_READ].name = syscalls[DUNE_SYS_READ];
81         if (dlopen("liblinuxemu_extend.so", RTLD_NOW) == NULL)
82                 fprintf(stderr, "Not using any syscall extensions\n Reason: %s\n",
83                         dlerror());
84
85 }
86
87
88 /* TODO: have an array which classifies syscall args
89  * and "special" system calls (ones with weird return
90  * values etc.). For some cases, we don't even do a system
91  * call, and in many cases we have to rearrange arguments
92  * since Linux and Akaros don't share signatures, so this
93  * gets tricky. */
94 bool
95 linuxemu(struct guest_thread *gth, struct vm_trapframe *tf)
96 {
97         bool ret = false;
98
99         fprintf(stderr, "vmcall(%s(%d), %p, %p, %p, %p, %p, %p);\n",
100                 tf->tf_rax < 311 ? syscalls[tf->tf_rax] : "",
101                 tf->tf_rax, tf->tf_rdi, tf->tf_rsi, tf->tf_rdx,
102                 tf->tf_rcx, tf->tf_r8, tf->tf_r9);
103
104         tf->tf_rip += 3;
105
106         if (tf->tf_rax >= dune_max_syscall) {
107                 fprintf(stderr, "System call %d is out of range\n", tf->tf_rax);
108                 return false;
109         }
110
111
112         if (dune_syscall_table[tf->tf_rax].call == NULL) {
113                 fprintf(stderr, "System call %d is not implemented\n", tf->tf_rax);
114                 return false;
115         }
116
117         return (dune_syscall_table[tf->tf_rax].call)(tf);
118 }