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