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