Massive reorganizing and making all the makefiles consistent.
[akaros.git] / user / parlib / src / syscall.c
1 // System call stubs.
2 #ifdef __DEPUTY__
3 #pragma nodeputy
4 #endif
5
6 #include <inc/syscall.h>
7 #include <inc/lib.h>
8 #include <inc/x86.h>
9
10 // TODO: modify to take only four parameters
11 static uint32_t
12 syscall_sysenter(int num, uint32_t a1, uint32_t a2, uint32_t a3, uint32_t a4, uint32_t a5)
13 {
14         uint32_t ret;
15     asm volatile(
16             //"pushl %%ecx\n\t"
17             //"pushl %%edx\n\t"
18             "pushl %%ebp\n\t"
19                         "pushl %%esi\n\t"
20             "movl %%esp, %%ebp\n\t"
21             "leal after_sysenter, %%esi\n\t"
22             "sysenter\n\t"
23             "after_sysenter:\n\t"
24                         "popl %%esi\n\t"
25             "popl %%ebp\n\t"
26             //"popl %%edx\n\t"
27             //"popl %%ecx"
28             :"=a" (ret)
29             : "a" (num),
30                 "d" (a1),
31                 "c" (a2),
32                 "b" (a3),
33                 "D" (a4)
34         : "cc", "memory", "%esp");
35         return ret;
36 }
37 static inline uint32_t
38 syscall_trap(int num, uint32_t a1, uint32_t a2, uint32_t a3, uint32_t a4, uint32_t a5)
39 {
40         uint32_t ret;
41
42         // Generic system call: pass system call number in AX,
43         // up to five parameters in DX, CX, BX, DI, SI.
44         // Interrupt kernel with T_SYSCALL.
45         //
46         // The "volatile" tells the assembler not to optimize
47         // this instruction away just because we don't use the
48         // return value.
49         //
50         // The last clause tells the assembler that this can
51         // potentially change the condition codes and arbitrary
52         // memory locations.
53
54         asm volatile("int %1\n"
55                 : "=a" (ret)
56                 : "i" (T_SYSCALL),
57                   "a" (num),
58                   "d" (a1),
59                   "c" (a2),
60                   "b" (a3),
61                   "D" (a4),
62                   "S" (a5)
63                 : "cc", "memory");
64
65         return ret;
66 }
67
68 static inline uint32_t
69 syscall(int num, uint32_t a1, uint32_t a2, uint32_t a3, uint32_t a4, uint32_t a5)
70 {
71         #ifndef SYSCALL_TRAP
72         return syscall_sysenter(num, a1, a2, a3, a4, a5);
73         #else
74         return syscall_trap(num, a1, a2, a3, a4, a5);
75         #endif
76 }
77
78 static error_t async_syscall(syscall_req_t* req, syscall_desc_t* desc)
79 {
80         // Note that this assumes one global frontring (TODO)
81         // abort if there is no room for our request.  ring size is currently 64.
82         // we could spin til it's free, but that could deadlock if this same thread
83         // is supposed to consume the requests it is waiting on later.
84         if (RING_FULL(&sysfrontring))
85                 return E_BUSY;
86         // req_prod_pvt comes in as the previously produced item.  need to
87         // increment to the next available spot, which is the one we'll work on.
88         // at some point, we need to listen for the responses.
89         desc->idx = ++(sysfrontring.req_prod_pvt);
90         desc->sysfr = &sysfrontring;
91         syscall_req_t* r = RING_GET_REQUEST(&sysfrontring, desc->idx);
92         memcpy(r, req, sizeof(syscall_req_t));
93         // push our updates to sysfrontring.req_prod_pvt
94         RING_PUSH_REQUESTS(&sysfrontring);
95         //cprintf("DEBUG: sring->req_prod: %d, sring->rsp_prod: %d\n", \
96                 sysfrontring.sring->req_prod, sysfrontring.sring->rsp_prod);
97         return 0;
98 }
99
100 // consider a timeout too
101 error_t waiton_syscall(syscall_desc_t* desc, syscall_rsp_t* rsp)
102 {
103         // Make sure we were given a desc with a non-NULL frontring.  This could
104         // happen if someone forgot to check the error code on the paired syscall.
105         if (!desc->sysfr)
106                 return E_FAIL;
107         // this forces us to call wait in the order in which the syscalls are made.
108         if (desc->idx != desc->sysfr->rsp_cons + 1)
109                 return E_DEADLOCK;
110         while (!(RING_HAS_UNCONSUMED_RESPONSES(desc->sysfr)))
111                 cpu_relax();
112         memcpy(rsp, RING_GET_RESPONSE(desc->sysfr, desc->idx), sizeof(*rsp));
113         desc->sysfr->rsp_cons++;
114     // run a cleanup function for this desc, if available
115     if (desc->cleanup)
116         desc->cleanup(desc->data);
117         return 0;
118 }
119
120 error_t sys_null_async(syscall_desc_t* desc)
121 {
122         syscall_req_t syscall = {SYS_null, 0, {[0 ... (NUM_SYS_ARGS-1)] 0}};
123         desc->cleanup = NULL;
124         desc->data = NULL;
125         return async_syscall(&syscall, desc);
126 }
127
128 void sys_cache_buster(uint32_t num_writes, uint32_t val)
129 {
130         syscall(SYS_cache_buster, num_writes, val, 0, 0, 0);
131 }
132
133 error_t sys_cache_buster_async(syscall_desc_t* desc, uint32_t num_writes,
134                                uint32_t val)
135 {
136         syscall_req_t syscall = {SYS_cache_buster, 0,
137                                  {num_writes, val, [2 ... (NUM_SYS_ARGS-1)] 0}};
138         // just to be safe, 0 these out.  they should have been 0'd right after
139         // the desc was POOL_GET'd
140         desc->cleanup = NULL;
141         desc->data = NULL;
142         return async_syscall(&syscall, desc);
143 }
144
145 error_t sys_cputs_async(const char *s, size_t len, syscall_desc_t* desc,
146                      void (*cleanup_handler)(void*), void* cleanup_data)
147 {
148         // could just hardcode 4 0's, will eventually wrap this marshaller anyway
149         syscall_req_t syscall = {SYS_cputs, 0, {(uint32_t)s, len, [2 ... (NUM_SYS_ARGS-1)] 0} };
150         desc->cleanup = cleanup_handler;
151         desc->data = cleanup_data;
152         return async_syscall(&syscall, desc);
153 }
154
155 void sys_null()
156 {
157         syscall(SYS_null,0,0,0,0,0);
158 }
159
160 void
161 sys_cputs(const char *s, size_t len)
162 {
163         syscall(SYS_cputs, (uint32_t) s,  len, 0, 0, 0);
164 }
165
166 int
167 sys_cgetc(void)
168 {
169         return syscall(SYS_cgetc, 0, 0, 0, 0, 0);
170 }
171
172 int
173 sys_env_destroy(envid_t envid)
174 {
175         return syscall(SYS_env_destroy, envid, 0, 0, 0, 0);
176 }
177
178 envid_t
179 sys_getenvid(void)
180 {
181          return syscall(SYS_getenvid, 0, 0, 0, 0, 0);
182 }
183
184