Async syscall handling
[akaros.git] / kern / syscall.c
1 /* See COPYRIGHT for copyright information. */
2 #ifdef __DEPUTY__
3 #pragma nodeputy
4 #endif
5
6 #include <inc/x86.h>
7 #include <inc/error.h>
8 #include <inc/string.h>
9 #include <inc/assert.h>
10
11 #include <kern/env.h>
12 #include <kern/pmap.h>
13 #include <kern/trap.h>
14 #include <kern/syscall.h>
15 #include <kern/console.h>
16
17 //Do absolutely nothing.  Used for profiling.  
18 static void sys_null() 
19 {
20         return;
21 }
22
23 // Print a string to the system console.
24 // The string is exactly 'len' characters long.
25 // Destroys the environment on memory errors.
26 static void
27 sys_cputs(const char *DANGEROUS s, size_t len)
28 {
29         // Check that the user has permission to read memory [s, s+len).
30         // Destroy the environment if not.
31     char *COUNT(len) _s = user_mem_assert(curenv, s, len, PTE_U);
32
33         // Print the string supplied by the user.
34         cprintf("%.*s", len, _s);
35 }
36
37 // Read a character from the system console.
38 // Returns the character.
39 static int
40 sys_cgetc(void)
41 {
42         int c;
43
44         // The cons_getc() primitive doesn't wait for a character,
45         // but the sys_cgetc() system call does.
46         while ((c = cons_getc()) == 0)
47                 /* do nothing */;
48
49         return c;
50 }
51
52 // Returns the current environment's envid.
53 static envid_t
54 sys_getenvid(void)
55 {
56         return curenv->env_id;
57 }
58
59 // Destroy a given environment (possibly the currently running environment).
60 //
61 // Returns 0 on success, < 0 on error.  Errors are:
62 //      -E_BAD_ENV if environment envid doesn't currently exist,
63 //              or the caller doesn't have permission to change envid.
64 static int
65 sys_env_destroy(envid_t envid)
66 {
67         int r;
68         env_t *e;
69
70         if ((r = envid2env(envid, &e, 1)) < 0)
71                 return r;
72         if (e == curenv)
73                 cprintf("[%08x] exiting gracefully\n", curenv->env_id);
74         else
75                 cprintf("[%08x] destroying %08x\n", curenv->env_id, e->env_id);
76         env_destroy(e);
77         return 0;
78 }
79
80
81
82 // Dispatches to the correct kernel function, passing the arguments.
83 uint32_t
84 syscall(uint32_t syscallno, uint32_t a1, uint32_t a2, uint32_t a3, uint32_t a4, uint32_t a5)
85 {
86         // Call the function corresponding to the 'syscallno' parameter.
87         // Return any appropriate return value.
88
89         //cprintf("Incoming syscall number: %d\n    a1: %x\n    a2: %x\n    a3: %x\n    a4: %x\n    a5: %x\n", syscallno, a1, a2, a3, a4, a5);
90
91         if (syscallno >= NSYSCALLS)
92                 return -E_INVAL;
93         
94         switch (syscallno) {
95                 case SYS_null:
96                         sys_null();
97                         return 0;
98                 case SYS_cputs:
99                         sys_cputs((char *DANGEROUS)a1, (size_t)a2);
100                         return 0;
101                 case SYS_cgetc:
102                         return sys_cgetc();
103                 case SYS_getenvid:
104                         return sys_getenvid();
105                 case SYS_env_destroy:
106                         return sys_env_destroy((envid_t)a1);
107                 default:
108                         // or just return -E_INVAL
109                         panic("invalid syscall number (%d)!", syscallno);
110         }
111         return 0xdeadbeef;
112 }
113
114 uint32_t syscall_async(syscall_req_t *call)
115 {
116         return syscall(call->num, call->args[0], call->args[1],
117                        call->args[2], call->args[3], call->args[4]);
118 }
119
120 uint32_t process_generic_syscalls(env_t* e, uint32_t max)
121 {
122         uint32_t count = 0;
123         syscall_back_ring_t* sysbr = &e->env_sysbackring;
124
125         // need to switch to the right context, so we can handle the user pointer
126         // that points to a data payload of the syscall
127         lcr3(e->env_cr3);
128         // max is the most we'll process.  max = 0 means do as many as possible
129         while (RING_HAS_UNCONSUMED_REQUESTS(sysbr) && ((!max)||(count < max)) ) {
130                 count++;
131                 //printk("DEBUG PRE: sring->req_prod: %d, sring->rsp_prod: %d\n",\
132                            sysbr->sring->req_prod, sysbr->sring->rsp_prod);
133                 // might want to think about 0-ing this out, if we aren't
134                 // going to explicitly fill in all fields
135                 syscall_resp_t rsp;
136                 // this assumes we get our answer immediately for the syscall.
137                 syscall_req_t* req = RING_GET_REQUEST(sysbr, ++(sysbr->req_cons));
138                 rsp.retval = syscall_async(req);
139                 // write response into the slot it came from
140                 memcpy(req, &rsp, sizeof(syscall_resp_t));
141                 // update our counter for what we've produced (assumes we went in order!)
142                 (sysbr->rsp_prod_pvt)++;
143                 RING_PUSH_RESPONSES(sysbr);
144                 //printk("DEBUG POST: sring->req_prod: %d, sring->rsp_prod: %d\n",\
145                            sysbr->sring->req_prod, sysbr->sring->rsp_prod);
146         }
147         return count;
148 }