Async error handling
[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 error_t async_syscall(syscall_req_t* req, syscall_desc_t* desc)
39 {
40         // Note that this assumes one global frontring (TODO)
41         // abort if there is no room for our request.  ring size is currently 64.
42         // we could spin til it's free, but that could deadlock if this same thread
43         // is supposed to consume the requests it is waiting on later.
44         if (RING_FULL(&sysfrontring))
45                 return E_BUSY;
46         // req_prod_pvt comes in as the previously produced item.  need to
47         // increment to the next available spot, which is the one we'll work on.
48         // at some point, we need to listen for the responses.
49         desc->idx = ++(sysfrontring.req_prod_pvt);
50         desc->sysfr = &sysfrontring;
51         syscall_req_t* r = RING_GET_REQUEST(&sysfrontring, desc->idx);
52         memcpy(r, req, sizeof(syscall_req_t));
53         // push our updates to sysfrontring.req_prod_pvt
54         RING_PUSH_REQUESTS(&sysfrontring);
55         //cprintf("DEBUG: sring->req_prod: %d, sring->rsp_prod: %d\n", \
56                 sysfrontring.sring->req_prod, sysfrontring.sring->rsp_prod);
57         return 0;
58 }
59
60 // consider a timeout too
61 error_t waiton_syscall(syscall_desc_t* desc, syscall_rsp_t* rsp)
62 {
63         // Make sure we were given a desc with a non-NULL frontring.  This could
64         // happen if someone forgot to check the error code on the paired syscall.
65         if (!desc->sysfr)
66                 return E_FAIL;
67         // this forces us to call wait in the order in which the syscalls are made.
68         if (desc->idx != desc->sysfr->rsp_cons + 1)
69                 return E_DEADLOCK;
70         while (!(RING_HAS_UNCONSUMED_RESPONSES(desc->sysfr)))
71                 cpu_relax();
72         memcpy(rsp, RING_GET_RESPONSE(desc->sysfr, desc->idx), sizeof(*rsp));
73         desc->sysfr->rsp_cons++;
74     // run a cleanup function for this desc, if available
75     if (desc->cleanup)
76         desc->cleanup(desc->data);
77         return 0;
78 }
79
80 error_t sys_null_async(syscall_desc_t* desc)
81 {
82         syscall_req_t syscall = {SYS_null, 0, {[0 ... (NUM_SYS_ARGS-1)] 0}};
83         desc->cleanup = NULL;
84         desc->data = NULL;
85         return async_syscall(&syscall, desc);
86 }
87
88 error_t sys_cputs_async(const char *s, size_t len, syscall_desc_t* desc,
89                      void (*cleanup_handler)(void*), void* cleanup_data)
90 {
91         // could just hardcode 4 0's, will eventually wrap this marshaller anyway
92         syscall_req_t syscall = {SYS_cputs, 0, {(uint32_t)s, len, [2 ... (NUM_SYS_ARGS-1)] 0} };
93         desc->cleanup = cleanup_handler;
94         desc->data = cleanup_data;
95         return async_syscall(&syscall, desc);
96 }
97
98 void sys_null()
99 {
100         syscall(SYS_null,0,0,0,0,0);
101 }
102
103 void
104 sys_cputs(const char *s, size_t len)
105 {
106         syscall(SYS_cputs, (uint32_t) s, len, 0, 0, 0);
107 }
108
109 int
110 sys_cgetc(void)
111 {
112         return syscall(SYS_cgetc, 0, 0, 0, 0, 0);
113 }
114
115 int
116 sys_env_destroy(envid_t envid)
117 {
118         return syscall(SYS_env_destroy, envid, 0, 0, 0, 0);
119 }
120
121 envid_t
122 sys_getenvid(void)
123 {
124          return syscall(SYS_getenvid, 0, 0, 0, 0, 0);
125 }
126
127