255bbff618bfdb3abd92a6a0a12fb7ddd0272739
[akaros.git] / kern / syscall.c
1 /* See COPYRIGHT for copyright information. */
2 #include <inc/x86.h>
3 #include <inc/error.h>
4 #include <inc/string.h>
5 #include <inc/assert.h>
6
7 #include <kern/env.h>
8 #include <kern/pmap.h>
9 #include <kern/trap.h>
10 #include <kern/syscall.h>
11 #include <kern/console.h>
12
13 // Print a string to the system console.
14 // The string is exactly 'len' characters long.
15 // Destroys the environment on memory errors.
16 static void
17 sys_cputs(const char *DANGEROUS s, size_t len)
18 {
19         // Check that the user has permission to read memory [s, s+len).
20         // Destroy the environment if not.
21     char *COUNT(len) _s = user_mem_assert(curenv, s, len, PTE_U);
22
23         // Print the string supplied by the user.
24         cprintf("%.*s", len, _s);
25 }
26
27 // Read a character from the system console.
28 // Returns the character.
29 static int
30 sys_cgetc(void)
31 {
32         int c;
33
34         // The cons_getc() primitive doesn't wait for a character,
35         // but the sys_cgetc() system call does.
36         while ((c = cons_getc()) == 0)
37                 /* do nothing */;
38
39         return c;
40 }
41
42 // Returns the current environment's envid.
43 static envid_t
44 sys_getenvid(void)
45 {
46         return curenv->env_id;
47 }
48
49 // Destroy a given environment (possibly the currently running environment).
50 //
51 // Returns 0 on success, < 0 on error.  Errors are:
52 //      -E_BAD_ENV if environment envid doesn't currently exist,
53 //              or the caller doesn't have permission to change envid.
54 static int
55 sys_env_destroy(envid_t envid)
56 {
57         int r;
58         env_t *e;
59
60         if ((r = envid2env(envid, &e, 1)) < 0)
61                 return r;
62         if (e == curenv)
63                 cprintf("[%08x] exiting gracefully\n", curenv->env_id);
64         else
65                 cprintf("[%08x] destroying %08x\n", curenv->env_id, e->env_id);
66         env_destroy(e);
67         return 0;
68 }
69
70
71
72 // Dispatches to the correct kernel function, passing the arguments.
73 uint32_t
74 syscall(uint32_t syscallno, uint32_t a1, uint32_t a2, uint32_t a3, uint32_t a4, uint32_t a5)
75 {
76         // Call the function corresponding to the 'syscallno' parameter.
77         // Return any appropriate return value.
78
79         //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);
80
81         if (syscallno >= NSYSCALLS)
82                 return -E_INVAL;
83         
84         switch (syscallno) {
85                 case SYS_cputs:
86                         sys_cputs((char *DANGEROUS)a1, (size_t)a2);
87                         return 0;
88                 case SYS_cgetc:
89                         return sys_cgetc();
90                 case SYS_getenvid:
91                         return sys_getenvid();
92                 case SYS_env_destroy:
93                         return sys_env_destroy((envid_t)a1);
94                 default:
95                         // or just return -E_INVAL
96                         panic("invalid syscall number!");
97         }
98         return 0xdeadbeef;
99 }
100
101 uint32_t syscall_async(syscall_req_t *call)
102 {
103         return syscall(call->num, call->args[0], call->args[1],
104                        call->args[2], call->args[3], call->args[4]);
105 }