Async call tweaks
[akaros.git] / lib / syscall.c
1 // System call stubs.
2
3 #include <inc/syscall.h>
4 #include <inc/lib.h>
5 #include <inc/x86.h>
6
7 static inline uint32_t
8 syscall(int num, uint32_t a1, uint32_t a2, uint32_t a3, uint32_t a4, uint32_t a5)
9 {
10         uint32_t ret;
11
12         // Generic system call: pass system call number in AX,
13         // up to five parameters in DX, CX, BX, DI, SI.
14         // Interrupt kernel with T_SYSCALL.
15         //
16         // The "volatile" tells the assembler not to optimize
17         // this instruction away just because we don't use the
18         // return value.
19         //
20         // The last clause tells the assembler that this can
21         // potentially change the condition codes and arbitrary
22         // memory locations.
23
24         asm volatile("int %1\n"
25                 : "=a" (ret)
26                 : "i" (T_SYSCALL),
27                   "a" (num),
28                   "d" (a1),
29                   "c" (a2),
30                   "b" (a3),
31                   "D" (a4),
32                   "S" (a5)
33                 : "cc", "memory");
34
35         return ret;
36 }
37
38 static inline error_t async_syscall(syscall_req_t* req, syscall_desc_t* desc)
39 {
40         // Note that this assumes one global frontring (TODO)
41         // spin til there is room for our request.  ring size is currently 64.
42         if (RING_FULL(&sysfrontring))
43                 return E_BUSY;
44         // req_prod_pvt comes in as the previously produced item.  need to
45         // increment to the next available spot, which is the one we'll work on.
46         // at some point, we need to listen for the responses.
47         desc->idx = ++(sysfrontring.req_prod_pvt);
48         desc->sysfr = &sysfrontring;
49         syscall_req_t* r = RING_GET_REQUEST(&sysfrontring, desc->idx);
50         memcpy(r, req, sizeof(syscall_req_t));
51         // push our updates to sysfrontring.req_prod_pvt
52         RING_PUSH_REQUESTS(&sysfrontring);
53         //cprintf("DEBUG: sring->req_prod: %d, sring->rsp_prod: %d\n", \
54                 sysfrontring.sring->req_prod, sysfrontring.sring->rsp_prod);
55         return 0;
56 }
57
58 // consider a timeout too
59 error_t waiton_syscall(syscall_desc_t* desc, syscall_rsp_t* rsp)
60 {
61         // this forces us to call wait in the order in which they are called
62         if (desc->idx != desc->sysfr->rsp_cons + 1)
63                 return E_DEADLOCK;
64         while (!(RING_HAS_UNCONSUMED_RESPONSES(desc->sysfr)))
65                 cpu_relax();
66         memcpy(rsp, RING_GET_RESPONSE(desc->sysfr, desc->idx), sizeof(*rsp));
67         desc->sysfr->rsp_cons++;
68     // run a cleanup function for this desc, if available
69     if (desc->cleanup)
70         desc->cleanup(desc->data);
71         return 0;
72 }
73
74 void sys_cputs_async(const char *s, size_t len, syscall_desc_t* desc,
75                      void (*cleanup_handler)(void*), void* cleanup_data)
76 {
77         // could just hardcode 4 0's, will eventually wrap this marshaller anyway
78         syscall_req_t syscall = {SYS_cputs, 0, {(uint32_t)s, len, [2 ... (NUM_SYS_ARGS-1)] 0} };
79         desc->cleanup = cleanup_handler;
80         desc->data = cleanup_data;
81         async_syscall(&syscall, desc);
82 }
83
84 void sys_null()
85 {
86         syscall(SYS_null,0,0,0,0,0);
87 }
88
89 void
90 sys_cputs(const char *s, size_t len)
91 {
92         syscall(SYS_cputs, (uint32_t) s, len, 0, 0, 0);
93 }
94
95 int
96 sys_cgetc(void)
97 {
98         return syscall(SYS_cgetc, 0, 0, 0, 0, 0);
99 }
100
101 int
102 sys_env_destroy(envid_t envid)
103 {
104         return syscall(SYS_env_destroy, envid, 0, 0, 0, 0);
105 }
106
107 envid_t
108 sys_getenvid(void)
109 {
110          return syscall(SYS_getenvid, 0, 0, 0, 0, 0);
111 }
112
113