Added non-preemptive pthreads support.
[akaros.git] / kern / src / syscall.c
1 /* See COPYRIGHT for copyright information. */
2
3 #ifdef __SHARC__
4 #pragma nosharc
5 #endif
6
7 #include <ros/common.h>
8 #include <arch/types.h>
9 #include <arch/arch.h>
10 #include <arch/mmu.h>
11 #include <arch/console.h>
12 #include <ros/timer.h>
13 #include <ros/error.h>
14
15 #include <string.h>
16 #include <assert.h>
17 #include <process.h>
18 #include <schedule.h>
19 #include <pmap.h>
20 #include <mm.h>
21 #include <trap.h>
22 #include <syscall.h>
23 #include <kmalloc.h>
24 #include <stdio.h>
25 #include <resource.h>
26 #include <kfs.h> // eventually replace this with vfs.h
27
28 #ifdef __sparc_v8__
29 #include <arch/frontend.h>
30 #endif 
31
32 #ifdef __NETWORK__
33 #include <arch/nic_common.h>
34 extern char *CT(PACKET_HEADER_SIZE + len) (*packet_wrap)(const char *CT(len) data, size_t len);
35 extern int (*send_frame)(const char *CT(len) data, size_t len);
36 #endif
37
38 //Do absolutely nothing.  Used for profiling.
39 static void sys_null(void)
40 {
41         return;
42 }
43
44 //Write a buffer over the serial port
45 static ssize_t sys_serial_write(env_t* e, const char *DANGEROUS buf, size_t len)
46 {
47         if (len == 0)
48                 return 0;
49         #ifdef SERIAL_IO
50                 char *COUNT(len) _buf = user_mem_assert(e, buf, len, PTE_USER_RO);
51                 for(int i =0; i<len; i++)
52                         serial_send_byte(buf[i]);
53                 return (ssize_t)len;
54         #else
55                 return -EINVAL;
56         #endif
57 }
58
59 //Read a buffer over the serial port
60 static ssize_t sys_serial_read(env_t* e, char *DANGEROUS _buf, size_t len)
61 {
62         if (len == 0)
63                 return 0;
64
65         #ifdef SERIAL_IO
66             char *COUNT(len) buf = user_mem_assert(e, _buf, len, PTE_USER_RO);
67                 size_t bytes_read = 0;
68                 int c;
69                 while((c = serial_read_byte()) != -1) {
70                         buf[bytes_read++] = (uint8_t)c;
71                         if(bytes_read == len) break;
72                 }
73                 return (ssize_t)bytes_read;
74         #else
75                 return -EINVAL;
76         #endif
77 }
78
79 //
80 /* START OF REMOTE SYSTEMCALL SUPPORT SYSCALLS. THESE WILL GO AWAY AS THINGS MATURE */
81 //
82
83 static ssize_t sys_run_binary(env_t* e, void *DANGEROUS binary_buf,
84                               void*DANGEROUS arg, size_t len) {
85         uint8_t* new_binary = kmalloc(len, 0);
86         if(new_binary == NULL)
87                 return -ENOMEM;
88         if(memcpy_from_user(e, new_binary, binary_buf, len))
89         {
90                 kfree(new_binary);
91                 proc_destroy(e);
92                 return 0;
93         }
94
95         env_t* env = env_create(new_binary, len);
96         kfree(new_binary);
97         proc_set_state(env, PROC_RUNNABLE_S);
98         schedule_proc(env);
99         proc_yield(e); // changed from sys_yield.  did not test this at all.
100         return 0;
101 }
102
103 #ifdef __NETWORK__
104 // This is not a syscall we want. Its hacky. Here just for syscall stuff until get a stack.
105 static ssize_t sys_eth_write(env_t* e, const char *DANGEROUS buf, size_t len)
106 {
107         extern int eth_up;
108
109         if (eth_up) {
110
111                 if (len == 0)
112                         return 0;
113
114                 char *COUNT(len) _buf = user_mem_assert(e, buf, len, PTE_U);
115                 int total_sent = 0;
116                 int just_sent = 0;
117                 int cur_packet_len = 0;
118                 while (total_sent != len) {
119                         cur_packet_len = ((len - total_sent) > MAX_PACKET_DATA) ? MAX_PACKET_DATA : (len - total_sent);
120                         char* wrap_buffer = packet_wrap(_buf + total_sent, cur_packet_len);
121                         just_sent = send_frame(wrap_buffer, cur_packet_len + PACKET_HEADER_SIZE);
122
123                         if (just_sent < 0)
124                                 return 0; // This should be an error code of its own
125
126                         if (wrap_buffer)
127                                 kfree(wrap_buffer);
128
129                         total_sent += cur_packet_len;
130                 }
131
132                 return (ssize_t)len;
133
134         }
135         else
136                 return -EINVAL;
137 }
138
139 // This is not a syscall we want. Its hacky. Here just for syscall stuff until get a stack.
140 static ssize_t sys_eth_read(env_t* e, char *DANGEROUS buf, size_t len)
141 {
142         extern int eth_up;
143
144         if (eth_up) {
145                 extern int packet_waiting;
146                 extern int packet_buffer_size;
147                 extern char*CT(packet_buffer_size) packet_buffer;
148                 extern char*CT(MAX_FRAME_SIZE) packet_buffer_orig;
149                 extern int packet_buffer_pos;
150
151                 if (len == 0)
152                         return 0;
153
154                 char *CT(len) _buf = user_mem_assert(e, buf,len, PTE_U);
155
156                 if (packet_waiting == 0)
157                         return 0;
158
159                 int read_len = ((packet_buffer_pos + len) > packet_buffer_size) ? packet_buffer_size - packet_buffer_pos : len;
160
161                 memcpy(_buf, packet_buffer + packet_buffer_pos, read_len);
162
163                 packet_buffer_pos = packet_buffer_pos + read_len;
164
165                 if (packet_buffer_pos == packet_buffer_size) {
166                         kfree(packet_buffer_orig);
167                         packet_waiting = 0;
168                 }
169
170                 return read_len;
171         }
172         else
173                 return -EINVAL;
174 }
175 #endif // Network
176
177 //
178 /* END OF REMOTE SYSTEMCALL SUPPORT SYSCALLS. */
179 //
180
181 static ssize_t sys_shared_page_alloc(env_t* p1,
182                                      void**DANGEROUS _addr, envid_t p2_id,
183                                      int p1_flags, int p2_flags
184                                     )
185 {
186         //if (!VALID_USER_PERMS(p1_flags)) return -EPERM;
187         //if (!VALID_USER_PERMS(p2_flags)) return -EPERM;
188
189         void * COUNT(1) * COUNT(1) addr = user_mem_assert(p1, _addr, sizeof(void *),
190                                                       PTE_USER_RW);
191         page_t* page;
192         env_t* p2 = &(envs[ENVX(p2_id)]);
193         error_t e = page_alloc(&page);
194
195         if(e < 0) return e;
196
197         void* p2_addr = page_insert_in_range(p2->env_pgdir, page,
198                                              (void*SNT)UTEXT, (void*SNT)UTOP, p2_flags);
199         if(p2_addr == NULL)
200                 return -EFAIL;
201
202         void* p1_addr = page_insert_in_range(p1->env_pgdir, page,
203                                             (void*SNT)UTEXT, (void*SNT)UTOP, p1_flags);
204         if(p1_addr == NULL) {
205                 page_remove(p2->env_pgdir, p2_addr);
206                 return -EFAIL;
207         }
208         *addr = p1_addr;
209         return ESUCCESS;
210 }
211
212 static void sys_shared_page_free(env_t* p1, void*DANGEROUS addr, envid_t p2)
213 {
214 }
215
216 // Invalidate the cache of this core.  Only useful if you want a cold cache for
217 // performance testing reasons.
218 static void sys_cache_invalidate(void)
219 {
220         #ifdef __i386__
221                 wbinvd();
222         #endif
223         return;
224 }
225
226 // Writes 'val' to 'num_writes' entries of the well-known array in the kernel
227 // address space.  It's just #defined to be some random 4MB chunk (which ought
228 // to be boot_alloced or something).  Meant to grab exclusive access to cache
229 // lines, to simulate doing something useful.
230 static void sys_cache_buster(env_t* e, uint32_t num_writes, uint32_t num_pages,
231                              uint32_t flags)
232 { TRUSTEDBLOCK /* zra: this is not really part of the kernel */
233         #define BUSTER_ADDR             0xd0000000  // around 512 MB deep
234         #define MAX_WRITES              1048576*8
235         #define MAX_PAGES               32
236         #define INSERT_ADDR     (UINFO + 2*PGSIZE) // should be free for these tests
237         uint32_t* buster = (uint32_t*)BUSTER_ADDR;
238         static uint32_t buster_lock = 0;
239         uint64_t ticks = -1;
240         page_t* a_page[MAX_PAGES];
241
242         /* Strided Accesses or Not (adjust to step by cachelines) */
243         uint32_t stride = 1;
244         if (flags & BUSTER_STRIDED) {
245                 stride = 16;
246                 num_writes *= 16;
247         }
248
249         /* Shared Accesses or Not (adjust to use per-core regions)
250          * Careful, since this gives 8MB to each core, starting around 512MB.
251          * Also, doesn't separate memory for core 0 if it's an async call.
252          */
253         if (!(flags & BUSTER_SHARED))
254                 buster = (uint32_t*)(BUSTER_ADDR + core_id() * 0x00800000);
255
256         /* Start the timer, if we're asked to print this info*/
257         if (flags & BUSTER_PRINT_TICKS)
258                 ticks = start_timing();
259
260         /* Allocate num_pages (up to MAX_PAGES), to simulate doing some more
261          * realistic work.  Note we don't write to these pages, even if we pick
262          * unshared.  Mostly due to the inconvenience of having to match up the
263          * number of pages with the number of writes.  And it's unnecessary.
264          */
265         if (num_pages) {
266                 spin_lock(&buster_lock);
267                 for (int i = 0; i < MIN(num_pages, MAX_PAGES); i++) {
268                         page_alloc(&a_page[i]);
269                         page_insert(e->env_pgdir, a_page[i], (void*)INSERT_ADDR + PGSIZE*i,
270                                     PTE_USER_RW);
271                 }
272                 spin_unlock(&buster_lock);
273         }
274
275         if (flags & BUSTER_LOCKED)
276                 spin_lock(&buster_lock);
277         for (int i = 0; i < MIN(num_writes, MAX_WRITES); i=i+stride)
278                 buster[i] = 0xdeadbeef;
279         if (flags & BUSTER_LOCKED)
280                 spin_unlock(&buster_lock);
281
282         if (num_pages) {
283                 spin_lock(&buster_lock);
284                 for (int i = 0; i < MIN(num_pages, MAX_PAGES); i++) {
285                         page_remove(e->env_pgdir, (void*)(INSERT_ADDR + PGSIZE * i));
286                         page_decref(a_page[i]);
287                 }
288                 spin_unlock(&buster_lock);
289         }
290
291         /* Print info */
292         if (flags & BUSTER_PRINT_TICKS) {
293                 ticks = stop_timing(ticks);
294                 printk("%llu,", ticks);
295         }
296         return;
297 }
298
299 // Print a string to the system console.
300 // The string is exactly 'len' characters long.
301 // Destroys the environment on memory errors.
302 static ssize_t sys_cputs(env_t* e, const char *DANGEROUS s, size_t len)
303 {
304         // Check that the user has permission to read memory [s, s+len).
305         // Destroy the environment if not.
306         pte_t* p = pgdir_walk(e->env_pgdir,s,0);
307         char *COUNT(len) _s = user_mem_assert(e, s, len, PTE_USER_RO);
308
309         // Print the string supplied by the user.
310         printk("%.*s", len, _s);
311         return (ssize_t)len;
312 }
313
314 // Read a character from the system console.
315 // Returns the character.
316 static uint16_t sys_cgetc(env_t* e)
317 {
318         uint16_t c;
319
320         // The cons_getc() primitive doesn't wait for a character,
321         // but the sys_cgetc() system call does.
322         while ((c = cons_getc()) == 0)
323                 cpu_relax();
324
325         return c;
326 }
327
328 // Returns the current environment's envid.
329 static envid_t sys_getenvid(env_t* e)
330 {
331         return e->env_id;
332 }
333
334 // Returns the id of the cpu this syscall is executed on.
335 static envid_t sys_getcpuid(void)
336 {
337         return core_id();
338 }
339
340 // TODO: Temporary hack until thread-local storage is implemented on i386
341 static size_t sys_getvcoreid(env_t* e)
342 {
343         if(e->state == PROC_RUNNING_S)
344                 return 0;
345
346         size_t i;
347         for(i = 0; i < e->num_vcores; i++)
348                 if(core_id() == e->vcoremap[i])
349                         return i;
350
351         panic("virtual core id not found in sys_getvcoreid()!");
352 }
353
354 // TODO FIX Me!!!! for processes
355 // Destroy a given environment (possibly the currently running environment).
356 //
357 // Returns 0 on success, < 0 on error.  Errors are:
358 //      -EBADENV if environment envid doesn't currently exist,
359 //              or the caller doesn't have permission to change envid.
360 static error_t sys_env_destroy(env_t* e, envid_t envid)
361 {
362         int r;
363         env_t *env_to_die;
364
365         if ((r = envid2env(envid, &env_to_die, 1)) < 0)
366                 return r;
367         if (env_to_die == e)
368                 printk("[%08x] exiting gracefully\n", e->env_id);
369         else
370                 panic("Destroying other processes is not supported yet.");
371                 //printk("[%08x] destroying %08x\n", e->env_id, env_to_die->env_id);
372         proc_destroy(env_to_die);
373         return ESUCCESS;
374 }
375
376 /*
377  * Creates a process found at the user string 'path'.  Currently uses KFS.
378  * Not runnable by default, so it needs it's status to be changed so that the
379  * next call to schedule() will try to run it.
380  * TODO: once we have a decent VFS, consider splitting this up
381  * and once there's an mmap, can have most of this in process.c
382  */
383 static int sys_proc_create(struct proc *p, const char *DANGEROUS path)
384 {
385         #define MAX_PATH_LEN 256 // totally arbitrary
386         int pid = 0;
387         char tpath[MAX_PATH_LEN];
388         /*
389          * There's a bunch of issues with reading in the path, which we'll
390          * need to sort properly in the VFS.  Main concerns are TOCTOU (copy-in),
391          * whether or not it's a big deal that the pointer could be into kernel
392          * space, and resolving both of these without knowing the length of the
393          * string. (TODO)
394          * Change this so that all syscalls with a pointer take a length.
395          *
396          * zra: I've added this user_mem_strlcpy, which I think eliminates the
397      * the TOCTOU issue. Adding a length arg to this call would allow a more
398          * efficient implementation, though, since only one call to user_mem_check
399          * would be required.
400          */
401         int ret = user_mem_strlcpy(p,tpath, path, MAX_PATH_LEN, PTE_USER_RO);
402         int kfs_inode = kfs_lookup_path(tpath);
403         if (kfs_inode < 0)
404                 return -EINVAL;
405         struct proc *new_p = kfs_proc_create(kfs_inode);
406         return new_p->env_id; // TODO replace this with a real proc_id
407 }
408
409 /* Makes process PID runnable.  Consider moving the functionality to env.c */
410 static error_t sys_proc_run(struct proc *p, unsigned pid)
411 {
412         struct proc *target = get_proc(pid);
413         error_t retval = 0;
414         spin_lock_irqsave(&p->proc_lock); // note we can get interrupted here. it's not bad.
415         // make sure we have access and it's in the right state to be activated
416         if (!proc_controls(p, target)) {
417                 retval = -EPERM;
418         } else if (target->state != PROC_CREATED) {
419                 retval = -EINVAL;
420         } else {
421                 proc_set_state(target, PROC_RUNNABLE_S);
422                 schedule_proc(target);
423         }
424         spin_unlock_irqsave(&p->proc_lock);
425         return retval;
426 }
427
428 static error_t sys_brk(struct proc *p, void* addr) {
429         size_t range;
430
431         if((addr < p->end_text_segment) || (addr >= (void*)USTACKBOT))
432                 return -EINVAL;
433         if(addr == p->end_data_segment)
434                 return ESUCCESS;
435
436         if (addr > p->end_data_segment) {
437                 range = addr - p->end_data_segment;
438                 env_segment_alloc(p, p->end_data_segment, range);
439         }
440         else if (addr < p->end_data_segment) {
441                 range = p->end_data_segment - addr;
442                 env_segment_free(p, addr, range);
443         }
444         p->end_data_segment = addr;
445         return ESUCCESS;
446 }
447
448 /* Executes the given syscall.
449  *
450  * Note tf is passed in, which points to the tf of the context on the kernel
451  * stack.  If any syscall needs to block, it needs to save this info, as well as
452  * any silly state.
453  *
454  * TODO: Build a dispatch table instead of switching on the syscallno
455  * Dispatches to the correct kernel function, passing the arguments.
456  */
457 intreg_t syscall(struct proc *p, trapframe_t *tf, uintreg_t syscallno,
458                  uintreg_t a1, uintreg_t a2, uintreg_t a3, uintreg_t a4,
459                                  uintreg_t a5)
460 {
461         // Call the function corresponding to the 'syscallno' parameter.
462         // Return any appropriate return value.
463
464         //cprintf("Incoming syscall on core: %d number: %d\n    a1: %x\n   "
465         //        " a2: %x\n    a3: %x\n    a4: %x\n    a5: %x\n", core_id(),
466         //        syscallno, a1, a2, a3, a4, a5);
467
468         // used if we need more args, like in mmap
469         int32_t _a4, _a5, _a6, *COUNT(3) args;
470
471         assert(p); // should always have an env for every syscall
472         //printk("Running syscall: %d\n", syscallno);
473         if (INVALID_SYSCALL(syscallno))
474                 return -EINVAL;
475
476         switch (syscallno) {
477                 case SYS_null:
478                         sys_null();
479                         return ESUCCESS;
480                 case SYS_cache_buster:
481                         sys_cache_buster(p, a1, a2, a3);
482                         return 0;
483                 case SYS_cache_invalidate:
484                         sys_cache_invalidate();
485                         return 0;
486                 case SYS_shared_page_alloc:
487                         return sys_shared_page_alloc(p, (void** DANGEROUS) a1,
488                                                  a2, (int) a3, (int) a4);
489                 case SYS_shared_page_free:
490                         sys_shared_page_free(p, (void* DANGEROUS) a1, a2);
491                     return ESUCCESS;
492                 case SYS_cputs:
493                         return sys_cputs(p, (char *DANGEROUS)a1, (size_t)a2);
494                 case SYS_cgetc:
495                         return sys_cgetc(p); // this will need to block
496                 case SYS_getcpuid:
497                         return sys_getcpuid();
498                 case SYS_getvcoreid:
499                         return sys_getvcoreid(p);
500                 case SYS_getpid:
501                         return sys_getenvid(p);
502                 case SYS_proc_destroy:
503                         return sys_env_destroy(p, (envid_t)a1);
504                 case SYS_yield:
505                         proc_yield(p);
506                         return ESUCCESS;
507                 case SYS_proc_create:
508                         return sys_proc_create(p, (char *DANGEROUS)a1);
509                 case SYS_proc_run:
510                         return sys_proc_run(p, (size_t)a1);
511                 case SYS_mmap:
512                         // we only have 4 parameters from sysenter currently, need to copy
513                         // in the others.  if we stick with this, we can make a func for it.
514                         args = user_mem_assert(p, (void*DANGEROUS)a4,
515                                                3*sizeof(_a4), PTE_USER_RW);
516                         _a4 = args[0];
517                         _a5 = args[1];
518                         _a6 = args[2];
519                         return (intreg_t) mmap(p, a1, a2, a3, _a4, _a5, _a6);
520                 case SYS_brk:
521                         return sys_brk(p, (void*)a1);
522                 case SYS_resource_req:
523                         /* preemptively set the return code to 0.  if it's not, it will get
524                          * overwriten on a proper return path.  if it ends up being a core
525                          * request from a RUNNING_S, it will never return out this way
526                          */
527                         proc_set_syscall_retval(tf, ESUCCESS);
528                         return resource_req(p, a1, a2, a3);
529
530         #ifdef __i386__
531                 case SYS_serial_write:
532                         return sys_serial_write(p, (char *DANGEROUS)a1, (size_t)a2);
533                 case SYS_serial_read:
534                         return sys_serial_read(p, (char *DANGEROUS)a1, (size_t)a2);
535         #endif
536                 case SYS_run_binary:
537                         return sys_run_binary(p, (char *DANGEROUS)a1,
538                                               (char* DANGEROUS)a2, (size_t)a3);
539         #ifdef __NETWORK__
540                 case SYS_eth_write:
541                         return sys_eth_write(p, (char *DANGEROUS)a1, (size_t)a2);
542                 case SYS_eth_read:
543                         return sys_eth_read(p, (char *DANGEROUS)a1, (size_t)a2);
544         #endif
545         #ifdef __sparc_v8__
546                 case SYS_frontend:
547                         return frontend_syscall_from_user(p,a1,a2,a3,a4);
548         #endif
549
550                 default:
551                         // or just return -EINVAL
552                         panic("Invalid syscall number %d for env %x!", syscallno, *p);
553         }
554         return 0xdeadbeef;
555 }
556
557 intreg_t syscall_async(env_t* e, syscall_req_t *call)
558 {
559         return syscall(e, NULL, call->num, call->args[0], call->args[1],
560                        call->args[2], call->args[3], call->args[4]);
561 }
562
563 intreg_t process_generic_syscalls(env_t* e, size_t max)
564 {
565         size_t count = 0;
566         syscall_back_ring_t* sysbr = &e->syscallbackring;
567
568         // make sure the env is still alive.
569         // incref will return ESUCCESS on success.
570         if (proc_incref(e))
571                 return -EFAIL;
572
573         // max is the most we'll process.  max = 0 means do as many as possible
574         while (RING_HAS_UNCONSUMED_REQUESTS(sysbr) && ((!max)||(count < max)) ) {
575                 if (!count) {
576                         // ASSUME: one queue per process
577                         // only switch cr3 for the very first request for this queue
578                         // need to switch to the right context, so we can handle the user pointer
579                         // that points to a data payload of the syscall
580                         lcr3(e->env_cr3);
581                 }
582                 count++;
583                 //printk("DEBUG PRE: sring->req_prod: %d, sring->rsp_prod: %d\n",
584                 //         sysbr->sring->req_prod, sysbr->sring->rsp_prod);
585                 // might want to think about 0-ing this out, if we aren't
586                 // going to explicitly fill in all fields
587                 syscall_rsp_t rsp;
588                 // this assumes we get our answer immediately for the syscall.
589                 syscall_req_t* req = RING_GET_REQUEST(sysbr, ++(sysbr->req_cons));
590                 rsp.retval = syscall_async(e, req);
591                 // write response into the slot it came from
592                 memcpy(req, &rsp, sizeof(syscall_rsp_t));
593                 // update our counter for what we've produced (assumes we went in order!)
594                 (sysbr->rsp_prod_pvt)++;
595                 RING_PUSH_RESPONSES(sysbr);
596                 //printk("DEBUG POST: sring->req_prod: %d, sring->rsp_prod: %d\n",
597                 //         sysbr->sring->req_prod, sysbr->sring->rsp_prod);
598         }
599         // load sane page tables (and don't rely on decref to do it for you).
600         lcr3(boot_cr3);
601         proc_decref(e);
602         return (intreg_t)count;
603 }