Check for null location before setting errno and retval.
[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 <ros/notification.h>
9 #include <arch/types.h>
10 #include <arch/arch.h>
11 #include <arch/mmu.h>
12 #include <arch/console.h>
13 #include <ros/timer.h>
14 #include <error.h>
15
16 #include <elf.h>
17 #include <string.h>
18 #include <assert.h>
19 #include <process.h>
20 #include <schedule.h>
21 #include <pmap.h>
22 #include <umem.h>
23 #include <mm.h>
24 #include <trap.h>
25 #include <syscall.h>
26 #include <kmalloc.h>
27 #include <stdio.h>
28 #include <resource.h>
29 #include <frontend.h>
30 #include <colored_caches.h>
31 #include <hashtable.h>
32 #include <arch/bitmask.h>
33 #include <kfs.h> // eventually replace this with vfs.h
34 #include <smp.h>
35 #include <arsc_server.h>
36
37
38 #ifdef __CONFIG_NETWORKING__
39 #include <arch/nic_common.h>
40 extern int (*send_frame)(const char *CT(len) data, size_t len);
41 extern unsigned char device_mac[6];
42 #endif
43
44 /* Tracing Globals */
45 int systrace_flags = 0;
46 struct systrace_record *systrace_buffer = 0;
47 unsigned int systrace_bufidx = 0;
48 size_t systrace_bufsize = 0;
49 struct proc *systrace_procs[MAX_NUM_TRACED] = {0};
50 spinlock_t systrace_lock = SPINLOCK_INITIALIZER;
51
52 /* Not enforcing the packing of systrace_procs yet, but don't rely on that */
53 static bool proc_is_traced(struct proc *p)
54 {
55         for (int i = 0; i < MAX_NUM_TRACED; i++)
56                 if (systrace_procs[i] == p)
57                         return true;
58         return false;
59 }
60
61 /************** Utility Syscalls **************/
62
63 static int sys_null(void)
64 {
65         return 0;
66 }
67
68 // Writes 'val' to 'num_writes' entries of the well-known array in the kernel
69 // address space.  It's just #defined to be some random 4MB chunk (which ought
70 // to be boot_alloced or something).  Meant to grab exclusive access to cache
71 // lines, to simulate doing something useful.
72 static int sys_cache_buster(struct proc *p, uint32_t num_writes,
73                              uint32_t num_pages, uint32_t flags)
74 { TRUSTEDBLOCK /* zra: this is not really part of the kernel */
75         #define BUSTER_ADDR             0xd0000000  // around 512 MB deep
76         #define MAX_WRITES              1048576*8
77         #define MAX_PAGES               32
78         #define INSERT_ADDR     (UINFO + 2*PGSIZE) // should be free for these tests
79         uint32_t* buster = (uint32_t*)BUSTER_ADDR;
80         static spinlock_t buster_lock = SPINLOCK_INITIALIZER;
81         uint64_t ticks = -1;
82         page_t* a_page[MAX_PAGES];
83
84         /* Strided Accesses or Not (adjust to step by cachelines) */
85         uint32_t stride = 1;
86         if (flags & BUSTER_STRIDED) {
87                 stride = 16;
88                 num_writes *= 16;
89         }
90
91         /* Shared Accesses or Not (adjust to use per-core regions)
92          * Careful, since this gives 8MB to each core, starting around 512MB.
93          * Also, doesn't separate memory for core 0 if it's an async call.
94          */
95         if (!(flags & BUSTER_SHARED))
96                 buster = (uint32_t*)(BUSTER_ADDR + core_id() * 0x00800000);
97
98         /* Start the timer, if we're asked to print this info*/
99         if (flags & BUSTER_PRINT_TICKS)
100                 ticks = start_timing();
101
102         /* Allocate num_pages (up to MAX_PAGES), to simulate doing some more
103          * realistic work.  Note we don't write to these pages, even if we pick
104          * unshared.  Mostly due to the inconvenience of having to match up the
105          * number of pages with the number of writes.  And it's unnecessary.
106          */
107         if (num_pages) {
108                 spin_lock(&buster_lock);
109                 for (int i = 0; i < MIN(num_pages, MAX_PAGES); i++) {
110                         upage_alloc(p, &a_page[i],1);
111                         page_insert(p->env_pgdir, a_page[i], (void*)INSERT_ADDR + PGSIZE*i,
112                                     PTE_USER_RW);
113                 }
114                 spin_unlock(&buster_lock);
115         }
116
117         if (flags & BUSTER_LOCKED)
118                 spin_lock(&buster_lock);
119         for (int i = 0; i < MIN(num_writes, MAX_WRITES); i=i+stride)
120                 buster[i] = 0xdeadbeef;
121         if (flags & BUSTER_LOCKED)
122                 spin_unlock(&buster_lock);
123
124         if (num_pages) {
125                 spin_lock(&buster_lock);
126                 for (int i = 0; i < MIN(num_pages, MAX_PAGES); i++) {
127                         page_remove(p->env_pgdir, (void*)(INSERT_ADDR + PGSIZE * i));
128                         page_decref(a_page[i]);
129                 }
130                 spin_unlock(&buster_lock);
131         }
132
133         /* Print info */
134         if (flags & BUSTER_PRINT_TICKS) {
135                 ticks = stop_timing(ticks);
136                 printk("%llu,", ticks);
137         }
138         return 0;
139 }
140
141 static int sys_cache_invalidate(void)
142 {
143         #ifdef __i386__
144                 wbinvd();
145         #endif
146         return 0;
147 }
148
149 /* sys_reboot(): called directly from dispatch table. */
150
151 /* Print a string to the system console. */
152 static ssize_t sys_cputs(struct proc *p, const char *DANGEROUS string,
153                          size_t strlen)
154 {
155         char *t_string;
156         t_string = user_strdup_errno(p, string, strlen);
157         if (!t_string)
158                 return -1;
159         printk("%.*s", strlen, t_string);
160         user_memdup_free(p, t_string);
161         return (ssize_t)strlen;
162 }
163
164 // Read a character from the system console.
165 // Returns the character.
166 static uint16_t sys_cgetc(struct proc *p)
167 {
168         uint16_t c;
169
170         // The cons_getc() primitive doesn't wait for a character,
171         // but the sys_cgetc() system call does.
172         while ((c = cons_getc()) == 0)
173                 cpu_relax();
174
175         return c;
176 }
177
178 /* Returns the id of the cpu this syscall is executed on. */
179 static uint32_t sys_getcpuid(void)
180 {
181         return core_id();
182 }
183
184 // TODO: Temporary hack until thread-local storage is implemented on i386 and
185 // this is removed from the user interface
186 static size_t sys_getvcoreid(struct proc *p)
187 {
188         return proc_get_vcoreid(p, core_id());
189 }
190
191 /************** Process management syscalls **************/
192
193 /* Returns the calling process's pid */
194 static pid_t sys_getpid(struct proc *p)
195 {
196         return p->pid;
197 }
198
199 /* Creates a process from the file 'path'.  The process is not runnable by
200  * default, so it needs it's status to be changed so that the next call to
201  * schedule() will try to run it.  TODO: take args/envs from userspace. */
202 static int sys_proc_create(struct proc *p, char *path, size_t path_l,
203                            struct procinfo *pi)
204 {
205         int pid = 0;
206         char *t_path;
207         struct file *program;
208         struct proc *new_p;
209
210         /* Copy in the path.  Consider putting an upper bound on path_l. */
211         t_path = user_strdup_errno(p, path, path_l);
212         if (!t_path)
213                 return -1;
214         program = do_file_open(t_path, 0, 0);
215         user_memdup_free(p, t_path);
216         if (!program)
217                 return -1;                      /* presumably, errno is already set */
218         /* TODO: need to split the proc creation, since you must load after setting
219          * args/env, since auxp gets set up there. */
220         //new_p = proc_create(program, 0, 0);
221         if (proc_alloc(&new_p, current))
222                 goto mid_error;
223         /* Set the argument stuff needed by glibc */
224         if (memcpy_from_user_errno(p, new_p->procinfo->argp, pi->argp,
225                                    sizeof(pi->argp)))
226                 goto late_error;
227         if (memcpy_from_user_errno(p, new_p->procinfo->argbuf, pi->argbuf,
228                                    sizeof(pi->argbuf)))
229                 goto late_error;
230         if (load_elf(new_p, program))
231                 goto late_error;
232         kref_put(&program->f_kref);
233         pid = new_p->pid;
234         kref_put(&new_p->kref); /* give up the reference created in proc_create() */
235         return pid;
236 late_error:
237         proc_destroy(new_p);
238 mid_error:
239         kref_put(&program->f_kref);
240         return -1;
241 }
242
243 /* Makes process PID runnable.  Consider moving the functionality to process.c */
244 static error_t sys_proc_run(struct proc *p, unsigned pid)
245 {
246         struct proc *target = pid2proc(pid);
247         error_t retval = 0;
248
249         if (!target)
250                 return -EBADPROC;
251         // note we can get interrupted here. it's not bad.
252         spin_lock(&p->proc_lock);
253         // make sure we have access and it's in the right state to be activated
254         if (!proc_controls(p, target)) {
255                 kref_put(&target->kref);
256                 retval = -EPERM;
257         } else if (target->state != PROC_CREATED) {
258                 kref_put(&target->kref);
259                 retval = -EINVAL;
260         } else {
261                 __proc_set_state(target, PROC_RUNNABLE_S);
262                 schedule_proc(target);
263         }
264         spin_unlock(&p->proc_lock);
265         kref_put(&target->kref);
266         return retval;
267 }
268
269 /* Destroy proc pid.  If this is called by the dying process, it will never
270  * return.  o/w it will return 0 on success, or an error.  Errors include:
271  * - EBADPROC: if there is no such process with pid
272  * - EPERM: if caller does not control pid */
273 static error_t sys_proc_destroy(struct proc *p, pid_t pid, int exitcode)
274 {
275         error_t r;
276         struct proc *p_to_die = pid2proc(pid);
277
278         if (!p_to_die) {
279                 set_errno(ESRCH);
280                 return -1;
281         }
282         if (!proc_controls(p, p_to_die)) {
283                 kref_put(&p_to_die->kref);
284                 set_errno(EPERM);
285                 return -1;
286         }
287         if (p_to_die == p) {
288                 // syscall code and pid2proc both have edible references, only need 1.
289                 p->exitcode = exitcode;
290                 kref_put(&p_to_die->kref);
291                 printd("[PID %d] proc exiting gracefully (code %d)\n", p->pid,exitcode);
292         } else {
293                 printd("[%d] destroying proc %d\n", p->pid, p_to_die->pid);
294         }
295         proc_destroy(p_to_die);
296         kref_put(&p_to_die->kref);
297         return ESUCCESS;
298 }
299
300 static int sys_proc_yield(struct proc *p, bool being_nice)
301 {
302         proc_yield(p, being_nice);
303         return 0;
304 }
305
306 static ssize_t sys_fork(env_t* e)
307 {
308         // TODO: right now we only support fork for single-core processes
309         if(e->state != PROC_RUNNING_S)
310         {
311                 set_errno(EINVAL);
312                 return -1;
313         }
314
315         env_t* env;
316         assert(!proc_alloc(&env, current));
317         assert(env != NULL);
318
319         env->heap_top = e->heap_top;
320         env->ppid = e->pid;
321         env->env_tf = *current_tf;
322
323         env->cache_colors_map = cache_colors_map_alloc();
324         for(int i=0; i < llc_cache->num_colors; i++)
325                 if(GET_BITMASK_BIT(e->cache_colors_map,i))
326                         cache_color_alloc(llc_cache, env->cache_colors_map);
327
328         duplicate_vmrs(e, env);
329
330         int copy_page(env_t* e, pte_t* pte, void* va, void* arg)
331         {
332                 env_t* env = (env_t*)arg;
333
334                 if(PAGE_PRESENT(*pte))
335                 {
336                         page_t* pp;
337                         if(upage_alloc(env,&pp,0))
338                                 return -1;
339                         if(page_insert(env->env_pgdir,pp,va,*pte & PTE_PERM))
340                         {
341                                 page_decref(pp);
342                                 return -1;
343                         }
344
345                         pagecopy(page2kva(pp),ppn2kva(PTE2PPN(*pte)));
346                 } else {
347                         assert(PAGE_PAGED_OUT(*pte));
348                         /* TODO: (SWAP) will need to either make a copy or CoW/refcnt the
349                          * backend store.  For now, this PTE will be the same as the
350                          * original PTE */
351                         panic("Swapping not supported!");
352                         pte_t* newpte = pgdir_walk(env->env_pgdir,va,1);
353                         if(!newpte)
354                                 return -1;
355                         *newpte = *pte;
356                 }
357                 return 0;
358         }
359
360         // TODO: (PC) this won't work.  Needs revisiting.
361         // copy procdata and procinfo
362         memcpy(env->procdata,e->procdata,sizeof(struct procdata));
363         memcpy(env->procinfo,e->procinfo,sizeof(struct procinfo));
364         env->procinfo->pid = env->pid;
365         env->procinfo->ppid = env->ppid;
366
367         /* for now, just copy the contents of every present page in the entire
368          * address space. */
369         if (env_user_mem_walk(e, 0, UMAPTOP, &copy_page, env)) {
370                 proc_destroy(env);      /* this is prob what you want, not decref by 2 */
371                 set_errno(ENOMEM);
372                 return -1;
373         }
374         clone_files(&e->open_files, &env->open_files);
375         __proc_set_state(env, PROC_RUNNABLE_S);
376         schedule_proc(env);
377
378         // don't decref the new process.
379         // that will happen when the parent waits for it.
380         // TODO: if the parent doesn't wait, we need to change the child's parent
381         // when the parent dies, or at least decref it
382
383         printd("[PID %d] fork PID %d\n",e->pid,env->pid);
384
385         return env->pid;
386 }
387
388 /* Load the binary "path" into the current process, and start executing it.
389  * argv and envp are magically bundled in procinfo for now.  Keep in sync with
390  * glibc's sysdeps/ros/execve.c */
391 static int sys_exec(struct proc *p, char *path, size_t path_l,
392                     struct procinfo *pi)
393 {
394         int ret = -1;
395         char *t_path;
396         struct file *program;
397
398         /* We probably want it to never be allowed to exec if it ever was _M */
399         if(p->state != PROC_RUNNING_S)
400                 return -1;
401
402         /* Copy in the path.  Consider putting an upper bound on path_l. */
403         t_path = user_strdup_errno(p, path, path_l);
404         if (!t_path)
405                 return -1;
406         program = do_file_open(t_path, 0, 0);
407         user_memdup_free(p, t_path);
408         if (!program)
409                 return -1;                      /* presumably, errno is already set */
410         /* Set the argument stuff needed by glibc */
411         if (memcpy_from_user_errno(p, p->procinfo->argp, pi->argp,
412                                    sizeof(pi->argp)))
413                 goto mid_error;
414         if (memcpy_from_user_errno(p, p->procinfo->argbuf, pi->argbuf,
415                                    sizeof(pi->argbuf)))
416                 goto mid_error;
417         /* This is the point of no return for the process. */
418         /* TODO: issues with this: Need to also assert there are no outstanding
419          * users of the sysrings.  the ldt page will get freed shortly, so that's
420          * okay.  Potentially issues with the nm and vcpd if we were in _M before
421          * and someone is trying to notify. */
422         memset(p->procdata, 0, sizeof(procdata_t));
423         destroy_vmrs(p);
424         close_all_files(&p->open_files, TRUE);
425         env_user_mem_free(p, 0, UMAPTOP);
426         if (load_elf(p, program)) {
427                 kref_put(&program->f_kref);
428                 proc_destroy(p);
429                 smp_idle();             /* syscall can't return on failure now */
430         }
431         printd("[PID %d] exec %s\n", p->pid, file_name(program));
432         kref_put(&program->f_kref);
433         *current_tf = p->env_tf;
434         return 0;
435 mid_error:
436         kref_put(&program->f_kref);
437         return -1;
438 }
439
440 static ssize_t sys_trywait(env_t* e, pid_t pid, int* status)
441 {
442         struct proc* p = pid2proc(pid);
443
444         // TODO: this syscall is racy, so we only support for single-core procs
445         if(e->state != PROC_RUNNING_S)
446                 return -1;
447
448         // TODO: need to use errno properly.  sadly, ROS error codes conflict..
449
450         if(p)
451         {
452                 ssize_t ret;
453
454                 if(current->pid == p->ppid)
455                 {
456                         if(p->state == PROC_DYING)
457                         {
458                                 memcpy_to_user(e,status,&p->exitcode,sizeof(int));
459                                 printd("[PID %d] waited for PID %d (code %d)\n",
460                                        e->pid,p->pid,p->exitcode);
461                                 ret = 0;
462                         }
463                         else // not dead yet
464                         {
465                                 set_errno(ESUCCESS);
466                                 ret = -1;
467                         }
468                 }
469                 else // not a child of the calling process
470                 {
471                         set_errno(EPERM);
472                         ret = -1;
473                 }
474
475                 // if the wait succeeded, decref twice
476                 if (ret == 0)
477                         kref_put(&p->kref);
478                 kref_put(&p->kref);
479                 return ret;
480         }
481
482         set_errno(EPERM);
483         return -1;
484 }
485
486 /************** Memory Management Syscalls **************/
487
488 static void *sys_mmap(struct proc *p, uintreg_t a1, uintreg_t a2, uintreg_t a3,
489                       uintreg_t *a456)
490 {
491         uintreg_t _a456[3];
492         if (memcpy_from_user(p, _a456, a456, 3 * sizeof(uintreg_t)))
493                 sys_proc_destroy(p, p->pid, -1);
494         return mmap(p, a1, a2, a3, _a456[0], _a456[1], _a456[2]);
495 }
496
497 static intreg_t sys_mprotect(struct proc *p, void *addr, size_t len, int prot)
498 {
499         return mprotect(p, (uintptr_t)addr, len, prot);
500 }
501
502 static intreg_t sys_munmap(struct proc *p, void *addr, size_t len)
503 {
504         return munmap(p, (uintptr_t)addr, len);
505 }
506
507 static ssize_t sys_shared_page_alloc(env_t* p1,
508                                      void**DANGEROUS _addr, pid_t p2_id,
509                                      int p1_flags, int p2_flags
510                                     )
511 {
512         /* When we remove/change this, also get rid of page_insert_in_range() */
513         printk("[kernel] the current shared page alloc is deprecated.\n");
514         //if (!VALID_USER_PERMS(p1_flags)) return -EPERM;
515         //if (!VALID_USER_PERMS(p2_flags)) return -EPERM;
516
517         void * COUNT(1) * COUNT(1) addr = user_mem_assert(p1, _addr, sizeof(void *),
518                                                       PTE_USER_RW);
519         struct proc *p2 = pid2proc(p2_id);
520         if (!p2)
521                 return -EBADPROC;
522
523         page_t* page;
524         error_t e = upage_alloc(p1, &page,1);
525         if (e < 0) {
526                 kref_put(&p2->kref);
527                 return e;
528         }
529
530         void* p2_addr = page_insert_in_range(p2->env_pgdir, page,
531                         (void*SNT)UTEXT, (void*SNT)UTOP, p2_flags);
532         if (p2_addr == NULL) {
533                 page_free(page);
534                 kref_put(&p2->kref);
535                 return -EFAIL;
536         }
537
538         void* p1_addr = page_insert_in_range(p1->env_pgdir, page,
539                         (void*SNT)UTEXT, (void*SNT)UTOP, p1_flags);
540         if(p1_addr == NULL) {
541                 page_remove(p2->env_pgdir, p2_addr);
542                 page_free(page);
543                 kref_put(&p2->kref);
544                 return -EFAIL;
545         }
546         *addr = p1_addr;
547         kref_put(&p2->kref);
548         return ESUCCESS;
549 }
550
551 static int sys_shared_page_free(env_t* p1, void*DANGEROUS addr, pid_t p2)
552 {
553         return -1;
554 }
555
556
557 /* sys_resource_req(): called directly from dispatch table. */
558
559 /* Will notify the target on the given vcore, if the caller controls the target.
560  * Will honor the target's wanted/vcoreid.  u_ne can be NULL. */
561 static int sys_notify(struct proc *p, int target_pid, unsigned int notif,
562                       struct notif_event *u_ne)
563 {
564         struct notif_event local_ne;
565         struct proc *target = pid2proc(target_pid);
566
567         if (!target) {
568                 set_errno(EBADPROC);
569                 return -1;
570         }
571         if (!proc_controls(p, target)) {
572                 kref_put(&target->kref);
573                 set_errno(EPERM);
574                 return -1;
575         }
576         /* if the user provided a notif_event, copy it in and use that */
577         if (u_ne) {
578                 if (memcpy_from_user(p, &local_ne, u_ne, sizeof(struct notif_event))) {
579                         kref_put(&target->kref);
580                         set_errno(EINVAL);
581                         return -1;
582                 }
583                 proc_notify(target, local_ne.ne_type, &local_ne);
584         } else {
585                 proc_notify(target, notif, 0);
586         }
587         kref_put(&target->kref);
588         return 0;
589 }
590
591 /* Will notify the calling process on the given vcore, independently of WANTED
592  * or advertised vcoreid.  If you change the parameters, change pop_ros_tf() */
593 static int sys_self_notify(struct proc *p, uint32_t vcoreid, unsigned int notif,
594                            struct notif_event *u_ne)
595 {
596         struct notif_event local_ne;
597
598         printd("[kernel] received self notify for vcoreid %d, notif %d, ne %08p\n",
599                vcoreid, notif, u_ne);
600         /* if the user provided a notif_event, copy it in and use that */
601         if (u_ne) {
602                 if (memcpy_from_user(p, &local_ne, u_ne, sizeof(struct notif_event))) {
603                         set_errno(EINVAL);
604                         return -1;
605                 }
606                 do_notify(p, vcoreid, local_ne.ne_type, &local_ne);
607         } else {
608                 do_notify(p, vcoreid, notif, 0);
609         }
610         return 0;
611 }
612
613 /* This will set a local timer for usec, then shut down the core */
614 static int sys_halt_core(struct proc *p, unsigned int usec)
615 {
616         /* TODO: ought to check and see if a timer was already active, etc, esp so
617          * userspace can't turn off timers.  also note we will also call whatever
618          * timer_interrupt() will do, though all we care about is just
619          * self_ipi/interrupting. */
620         set_core_timer(usec);
621         cpu_halt();
622
623         return 0;
624 }
625
626 /************** Platform Specific Syscalls **************/
627
628 //Read a buffer over the serial port
629 static ssize_t sys_serial_read(env_t* e, char *DANGEROUS _buf, size_t len)
630 {
631         printk("[kernel] serial reading is deprecated.\n");
632         if (len == 0)
633                 return 0;
634
635         #ifdef __CONFIG_SERIAL_IO__
636             char *COUNT(len) buf = user_mem_assert(e, _buf, len, PTE_USER_RO);
637                 size_t bytes_read = 0;
638                 int c;
639                 while((c = serial_read_byte()) != -1) {
640                         buf[bytes_read++] = (uint8_t)c;
641                         if(bytes_read == len) break;
642                 }
643                 return (ssize_t)bytes_read;
644         #else
645                 return -EINVAL;
646         #endif
647 }
648
649 //Write a buffer over the serial port
650 static ssize_t sys_serial_write(env_t* e, const char *DANGEROUS buf, size_t len)
651 {
652         printk("[kernel] serial writing is deprecated.\n");
653         if (len == 0)
654                 return 0;
655         #ifdef __CONFIG_SERIAL_IO__
656                 char *COUNT(len) _buf = user_mem_assert(e, buf, len, PTE_USER_RO);
657                 for(int i =0; i<len; i++)
658                         serial_send_byte(buf[i]);
659                 return (ssize_t)len;
660         #else
661                 return -EINVAL;
662         #endif
663 }
664
665 #ifdef __CONFIG_NETWORKING__
666 // This is not a syscall we want. Its hacky. Here just for syscall stuff until get a stack.
667 static ssize_t sys_eth_read(env_t* e, char *DANGEROUS buf)
668 {
669         if (eth_up) {
670
671                 uint32_t len;
672                 char *ptr;
673
674                 spin_lock(&packet_buffers_lock);
675
676                 if (num_packet_buffers == 0) {
677                         spin_unlock(&packet_buffers_lock);
678                         return 0;
679                 }
680
681                 ptr = packet_buffers[packet_buffers_head];
682                 len = packet_buffers_sizes[packet_buffers_head];
683
684                 num_packet_buffers--;
685                 packet_buffers_head = (packet_buffers_head + 1) % MAX_PACKET_BUFFERS;
686
687                 spin_unlock(&packet_buffers_lock);
688
689                 char* _buf = user_mem_assert(e, buf, len, PTE_U);
690
691                 memcpy(_buf, ptr, len);
692
693                 kfree(ptr);
694
695                 return len;
696         }
697         else
698                 return -EINVAL;
699 }
700
701 // This is not a syscall we want. Its hacky. Here just for syscall stuff until get a stack.
702 static ssize_t sys_eth_write(env_t* e, const char *DANGEROUS buf, size_t len)
703 {
704         if (eth_up) {
705
706                 if (len == 0)
707                         return 0;
708
709                 // HACK TO BYPASS HACK
710                 int just_sent = send_frame(buf, len);
711
712                 if (just_sent < 0) {
713                         printk("Packet send fail\n");
714                         return 0;
715                 }
716
717                 return just_sent;
718
719                 // END OF RECURSIVE HACK
720 /*
721                 char *COUNT(len) _buf = user_mem_assert(e, buf, len, PTE_U);
722                 int total_sent = 0;
723                 int just_sent = 0;
724                 int cur_packet_len = 0;
725                 while (total_sent != len) {
726                         cur_packet_len = ((len - total_sent) > MTU) ? MTU : (len - total_sent);
727                         char dest_mac[6] = APPSERVER_MAC_ADDRESS;
728                         char* wrap_buffer = eth_wrap(_buf + total_sent, cur_packet_len, device_mac, dest_mac, APPSERVER_PORT);
729                         just_sent = send_frame(wrap_buffer, cur_packet_len + sizeof(struct ETH_Header));
730
731                         if (just_sent < 0)
732                                 return 0; // This should be an error code of its own
733
734                         if (wrap_buffer)
735                                 kfree(wrap_buffer);
736
737                         total_sent += cur_packet_len;
738                 }
739
740                 return (ssize_t)len;
741 */
742         }
743         else
744                 return -EINVAL;
745 }
746
747 static ssize_t sys_eth_get_mac_addr(env_t* e, char *DANGEROUS buf) 
748 {
749         if (eth_up) {
750                 for (int i = 0; i < 6; i++)
751                         buf[i] = device_mac[i];
752                 return 0;
753         }
754         else
755                 return -EINVAL;
756 }
757
758 static int sys_eth_recv_check(env_t* e) 
759 {
760         if (num_packet_buffers != 0) 
761                 return 1;
762         else
763                 return 0;
764 }
765
766 #endif // Network
767
768 static intreg_t sys_read(struct proc *p, int fd, void *buf, int len)
769 {
770         ssize_t ret;
771         struct file *file = get_file_from_fd(&p->open_files, fd);
772         if (!file) {
773                 set_errno(EBADF);
774                 return -1;
775         }
776         /* TODO: (UMEM) currently, read() handles user memcpy issues, but we
777          * probably should user_mem_check and pin the region here, so read doesn't
778          * worry about it */
779         ret = file->f_op->read(file, buf, len, &file->f_pos);
780         kref_put(&file->f_kref);
781         return ret;
782 }
783
784 static intreg_t sys_write(struct proc *p, int fd, const void *buf, int len)
785 {
786         /* Catch common usage of stdout and stderr.  No protections or anything. */
787         if (fd == 1) {
788                 printk("[stdout]: %s\n", buf);
789                 return len;
790         } else if (fd == 2) {
791                 printk("[stderr]: %s\n", buf);
792                 return len;
793         }
794         /* the real sys_write: */
795         ssize_t ret;
796         struct file *file = get_file_from_fd(&p->open_files, fd);
797         if (!file) {
798                 set_errno(EBADF);
799                 return -1;
800         }
801         /* TODO: (UMEM) */
802         ret = file->f_op->write(file, buf, len, &file->f_pos);
803         kref_put(&file->f_kref);
804         return ret;
805 }
806
807 /* Checks args/reads in the path, opens the file, and inserts it into the
808  * process's open file list. 
809  *
810  * TODO: take the path length */
811 static intreg_t sys_open(struct proc *p, const char *path, size_t path_l,
812                          int oflag, int mode)
813 {
814         int fd = 0;
815         struct file *file;
816
817         char *t_path = user_strdup_errno(p, path, path_l);
818         if (!t_path)
819                 return -1;
820         file = do_file_open(t_path, oflag, mode);
821         user_memdup_free(p, t_path);
822         if (!file)
823                 return -1;
824         fd = insert_file(&p->open_files, file); /* stores the ref to file */
825         kref_put(&file->f_kref);
826         if (fd < 0) {
827                 warn("File insertion failed");
828                 return -1;
829         }
830         printd("File %s Open, res=%d\n", path, fd);
831         return fd;
832 }
833
834 static intreg_t sys_close(struct proc *p, int fd)
835 {
836         struct file *file = put_file_from_fd(&p->open_files, fd);
837         if (!file) {
838                 set_errno(EBADF);
839                 return -1;
840         }
841         return 0;
842 }
843
844 /* kept around til we remove the last ufe */
845 #define ufe(which,a0,a1,a2,a3) \
846         frontend_syscall_errno(p,APPSERVER_SYSCALL_##which,\
847                            (int)(a0),(int)(a1),(int)(a2),(int)(a3))
848
849 static intreg_t sys_fstat(struct proc *p, int fd, struct kstat *u_stat)
850 {
851         struct kstat *kbuf;
852         struct file *file = get_file_from_fd(&p->open_files, fd);
853         if (!file) {
854                 set_errno(EBADF);
855                 return -1;
856         }
857         kbuf = kmalloc(sizeof(struct kstat), 0);
858         if (!kbuf) {
859                 kref_put(&file->f_kref);
860                 set_errno(ENOMEM);
861                 return -1;
862         }
863         stat_inode(file->f_dentry->d_inode, kbuf);
864         kref_put(&file->f_kref);
865         /* TODO: UMEM: pin the memory, copy directly, and skip the kernel buffer */
866         if (memcpy_to_user_errno(p, u_stat, kbuf, sizeof(struct kstat))) {
867                 kfree(kbuf);
868                 set_errno(EINVAL);
869                 return -1;
870         }
871         kfree(kbuf);
872         return 0;
873 }
874
875 /* sys_stat() and sys_lstat() do nearly the same thing, differing in how they
876  * treat a symlink for the final item, which (probably) will be controlled by
877  * the lookup flags */
878 static intreg_t stat_helper(struct proc *p, const char *path, size_t path_l,
879                             struct kstat *u_stat, int flags)
880 {
881         struct kstat *kbuf;
882         struct inode *path_i;
883         char *t_path = user_strdup_errno(p, path, path_l);
884         if (!t_path)
885                 return -1;
886         path_i = lookup_inode(t_path, flags);
887         user_memdup_free(p, t_path);
888         if (!path_i)
889                 return -1;
890         kbuf = kmalloc(sizeof(struct kstat), 0);
891         if (!kbuf) {
892                 set_errno(ENOMEM);
893                 kref_put(&path_i->i_kref);
894                 return -1;
895         }
896         stat_inode(path_i, kbuf);
897         kref_put(&path_i->i_kref);
898         /* TODO: UMEM: pin the memory, copy directly, and skip the kernel buffer */
899         if (memcpy_to_user_errno(p, u_stat, kbuf, sizeof(struct kstat))) {
900                 kfree(kbuf);
901                 set_errno(EINVAL);
902                 return -1;
903         }
904         kfree(kbuf);
905         return 0;
906 }
907
908 /* Follow a final symlink */
909 static intreg_t sys_stat(struct proc *p, const char *path, size_t path_l,
910                          struct kstat *u_stat)
911 {
912         return stat_helper(p, path, path_l, u_stat, LOOKUP_FOLLOW);
913 }
914
915 /* Don't follow a final symlink */
916 static intreg_t sys_lstat(struct proc *p, const char *path, size_t path_l,
917                           struct kstat *u_stat)
918 {
919         return stat_helper(p, path, path_l, u_stat, 0);
920 }
921
922 intreg_t sys_fcntl(struct proc *p, int fd, int cmd, int arg)
923 {
924         return ufe(fcntl,fd,cmd,arg,0);
925 }
926
927 static intreg_t sys_access(struct proc *p, const char *path, size_t path_l,
928                            int mode)
929 {
930         int retval;
931
932         char *t_path = user_strdup_errno(p, path, path_l);
933         if (!t_path)
934                 return -1;
935         retval = do_file_access(t_path, mode);
936         user_memdup_free(p, t_path);
937         printd("Access for path: %s retval: %d\n", path, retval);
938         if (retval < 0) {
939                 set_errno(-retval);
940                 return -1;
941         }
942         return retval;
943 }
944
945 intreg_t sys_umask(struct proc *p, int mask)
946 {
947         return ufe(umask,mask,0,0,0);
948 }
949
950 intreg_t sys_chmod(struct proc *p, const char *path, size_t path_l, int mode)
951 {
952         char* fn = user_strdup_errno(p,path,PGSIZE);
953         if(fn == NULL)
954                 return -1;
955         int ret = ufe(chmod,PADDR(fn),mode,0,0);
956         user_memdup_free(p,fn);
957         return ret;
958 }
959
960 static intreg_t sys_lseek(struct proc *p, int fd, off_t offset, int whence)
961 {
962         off_t ret;
963         struct file *file = get_file_from_fd(&p->open_files, fd);
964         if (!file) {
965                 set_errno(EBADF);
966                 return -1;
967         }
968         ret = file->f_op->llseek(file, offset, whence);
969         kref_put(&file->f_kref);
970         return ret;
971 }
972
973 intreg_t sys_link(struct proc *p, const char *_old, size_t old_l,
974                   const char *_new, size_t new_l)
975 {
976         char* oldpath = user_strdup_errno(p,_old,PGSIZE);
977         if(oldpath == NULL)
978                 return -1;
979
980         char* newpath = user_strdup_errno(p,_new,PGSIZE);
981         if(newpath == NULL)
982         {
983                 user_memdup_free(p,oldpath);
984                 return -1;
985         }
986
987         int ret = ufe(link,PADDR(oldpath),PADDR(newpath),0,0);
988         user_memdup_free(p,oldpath);
989         user_memdup_free(p,newpath);
990         return ret;
991 }
992
993 intreg_t sys_unlink(struct proc *p, const char *path, size_t path_l)
994 {
995         char* fn = user_strdup_errno(p,path,PGSIZE);
996         if(fn == NULL)
997                 return -1;
998         int ret = ufe(unlink,PADDR(fn),0,0,0);
999         user_memdup_free(p,fn);
1000         return ret;
1001 }
1002
1003 intreg_t sys_chdir(struct proc *p, const char *path, size_t path_l)
1004 {
1005         char* fn = user_strdup_errno(p,path,PGSIZE);
1006         if(fn == NULL)
1007                 return -1;
1008         int ret = ufe(chdir,PADDR(fn),0,0,0);
1009         user_memdup_free(p,fn);
1010         return ret;
1011 }
1012
1013 intreg_t sys_getcwd(struct proc *p, char *pwd, int size)
1014 {
1015         void* kbuf = kmalloc_errno(size);
1016         if(kbuf == NULL)
1017                 return -1;
1018         int ret = ufe(read,PADDR(kbuf),size,0,0);
1019         if(ret != -1 && memcpy_to_user_errno(p,pwd,kbuf,strnlen(kbuf,size)))
1020                 ret = -1;
1021         user_memdup_free(p,kbuf);
1022         return ret;
1023 }
1024
1025 intreg_t sys_gettimeofday(struct proc *p, int *buf)
1026 {
1027         static spinlock_t gtod_lock = SPINLOCK_INITIALIZER;
1028         static int t0 = 0;
1029
1030         spin_lock(&gtod_lock);
1031         if(t0 == 0)
1032
1033 #if (defined __CONFIG_APPSERVER__)
1034         t0 = ufe(time,0,0,0,0);
1035 #else
1036         // Nanwan's birthday, bitches!!
1037         t0 = 1242129600;
1038 #endif 
1039         spin_unlock(&gtod_lock);
1040
1041         long long dt = read_tsc();
1042         int kbuf[2] = {t0+dt/system_timing.tsc_freq,
1043             (dt%system_timing.tsc_freq)*1000000/system_timing.tsc_freq};
1044
1045         return memcpy_to_user_errno(p,buf,kbuf,sizeof(kbuf));
1046 }
1047
1048 #define SIZEOF_STRUCT_TERMIOS 60
1049 intreg_t sys_tcgetattr(struct proc *p, int fd, void *termios_p)
1050 {
1051         int* kbuf = kmalloc(SIZEOF_STRUCT_TERMIOS,0);
1052         int ret = ufe(tcgetattr,fd,PADDR(kbuf),0,0);
1053         if(ret != -1 && memcpy_to_user_errno(p,termios_p,kbuf,SIZEOF_STRUCT_TERMIOS))
1054                 ret = -1;
1055         kfree(kbuf);
1056         return ret;
1057 }
1058
1059 intreg_t sys_tcsetattr(struct proc *p, int fd, int optional_actions,
1060                        const void *termios_p)
1061 {
1062         void* kbuf = user_memdup_errno(p,termios_p,SIZEOF_STRUCT_TERMIOS);
1063         if(kbuf == NULL)
1064                 return -1;
1065         int ret = ufe(tcsetattr,fd,optional_actions,PADDR(kbuf),0);
1066         user_memdup_free(p,kbuf);
1067         return ret;
1068 }
1069
1070 /************** Syscall Invokation **************/
1071
1072 /* Executes the given syscall.
1073  *
1074  * Note tf is passed in, which points to the tf of the context on the kernel
1075  * stack.  If any syscall needs to block, it needs to save this info, as well as
1076  * any silly state.
1077  * 
1078  * This syscall function is used by both local syscall and arsc, and should
1079  * remain oblivious of the caller.
1080  *
1081  * TODO: Keep in mind that not every syscall has a user trapframe. 
1082  * e.g. ARSC
1083  */
1084 intreg_t syscall(struct proc *p, uintreg_t syscallno, uintreg_t a1,
1085                  uintreg_t a2, uintreg_t a3, uintreg_t a4, uintreg_t a5)
1086 {
1087         // Initialize the return value and error code returned to 0
1088         if(current_tf != NULL){
1089                 set_retval(ESUCCESS);
1090                 set_errno(ESUCCESS);
1091         }
1092
1093         typedef intreg_t (*syscall_t)(struct proc*,uintreg_t,uintreg_t,
1094                                       uintreg_t,uintreg_t,uintreg_t);
1095
1096         const static syscall_t syscall_table[] = {
1097                 [SYS_null] = (syscall_t)sys_null,
1098                 [SYS_cache_buster] = (syscall_t)sys_cache_buster,
1099                 [SYS_cache_invalidate] = (syscall_t)sys_cache_invalidate,
1100                 [SYS_reboot] = (syscall_t)reboot,
1101                 [SYS_cputs] = (syscall_t)sys_cputs,
1102                 [SYS_cgetc] = (syscall_t)sys_cgetc,
1103                 [SYS_getcpuid] = (syscall_t)sys_getcpuid,
1104                 [SYS_getvcoreid] = (syscall_t)sys_getvcoreid,
1105                 [SYS_getpid] = (syscall_t)sys_getpid,
1106                 [SYS_proc_create] = (syscall_t)sys_proc_create,
1107                 [SYS_proc_run] = (syscall_t)sys_proc_run,
1108                 [SYS_proc_destroy] = (syscall_t)sys_proc_destroy,
1109                 [SYS_yield] = (syscall_t)sys_proc_yield,
1110                 [SYS_fork] = (syscall_t)sys_fork,
1111                 [SYS_exec] = (syscall_t)sys_exec,
1112                 [SYS_trywait] = (syscall_t)sys_trywait,
1113                 [SYS_mmap] = (syscall_t)sys_mmap,
1114                 [SYS_munmap] = (syscall_t)sys_munmap,
1115                 [SYS_mprotect] = (syscall_t)sys_mprotect,
1116                 [SYS_shared_page_alloc] = (syscall_t)sys_shared_page_alloc,
1117                 [SYS_shared_page_free] = (syscall_t)sys_shared_page_free,
1118                 [SYS_resource_req] = (syscall_t)resource_req,
1119                 [SYS_notify] = (syscall_t)sys_notify,
1120                 [SYS_self_notify] = (syscall_t)sys_self_notify,
1121                 [SYS_halt_core] = (syscall_t)sys_halt_core,
1122         #ifdef __CONFIG_SERIAL_IO__
1123                 [SYS_serial_read] = (syscall_t)sys_serial_read,
1124                 [SYS_serial_write] = (syscall_t)sys_serial_write,
1125         #endif
1126         #ifdef __CONFIG_NETWORKING__
1127                 [SYS_eth_read] = (syscall_t)sys_eth_read,
1128                 [SYS_eth_write] = (syscall_t)sys_eth_write,
1129                 [SYS_eth_get_mac_addr] = (syscall_t)sys_eth_get_mac_addr,
1130                 [SYS_eth_recv_check] = (syscall_t)sys_eth_recv_check,
1131         #endif
1132         #ifdef __CONFIG_ARSC_SERVER__
1133                 [SYS_init_arsc] = (syscall_t)sys_init_arsc,
1134         #endif
1135                 // Syscalls serviced by the appserver for now.
1136                 [SYS_read] = (syscall_t)sys_read,
1137                 [SYS_write] = (syscall_t)sys_write,
1138                 [SYS_open] = (syscall_t)sys_open,
1139                 [SYS_close] = (syscall_t)sys_close,
1140                 [SYS_fstat] = (syscall_t)sys_fstat,
1141                 [SYS_stat] = (syscall_t)sys_stat,
1142                 [SYS_lstat] = (syscall_t)sys_lstat,
1143                 [SYS_fcntl] = (syscall_t)sys_fcntl,
1144                 [SYS_access] = (syscall_t)sys_access,
1145                 [SYS_umask] = (syscall_t)sys_umask,
1146                 [SYS_chmod] = (syscall_t)sys_chmod,
1147                 [SYS_lseek] = (syscall_t)sys_lseek,
1148                 [SYS_link] = (syscall_t)sys_link,
1149                 [SYS_unlink] = (syscall_t)sys_unlink,
1150                 [SYS_chdir] = (syscall_t)sys_chdir,
1151                 [SYS_getcwd] = (syscall_t)sys_getcwd,
1152                 [SYS_gettimeofday] = (syscall_t)sys_gettimeofday,
1153                 [SYS_tcgetattr] = (syscall_t)sys_tcgetattr,
1154                 [SYS_tcsetattr] = (syscall_t)sys_tcsetattr
1155         };
1156
1157         const int max_syscall = sizeof(syscall_table)/sizeof(syscall_table[0]);
1158
1159         uint32_t coreid, vcoreid;
1160         if (systrace_flags & SYSTRACE_ON) {
1161                 if ((systrace_flags & SYSTRACE_ALLPROC) || (proc_is_traced(p))) {
1162                         coreid = core_id();
1163                         vcoreid = proc_get_vcoreid(p, core_id());
1164                         if (systrace_flags & SYSTRACE_LOUD) {
1165                                 printk("[%16llu] Syscall %d for proc %d on core %d, vcore %d\n",
1166                                        read_tsc(), syscallno, p->pid, coreid, vcoreid);
1167                         } else {
1168                                 struct systrace_record *trace;
1169                                 unsigned int idx, new_idx;
1170                                 do {
1171                                         idx = systrace_bufidx;
1172                                         new_idx = (idx + 1) % systrace_bufsize;
1173                                 } while (!atomic_comp_swap(&systrace_bufidx, idx, new_idx));
1174                                 trace = &systrace_buffer[idx];
1175                                 trace->timestamp = read_tsc();
1176                                 trace->syscallno = syscallno;
1177                                 trace->pid = p->pid;
1178                                 trace->coreid = coreid;
1179                                 trace->vcoreid = vcoreid;
1180                         }
1181                 }
1182         }
1183         //printk("Incoming syscall on core: %d number: %d\n    a1: %x\n   "
1184         //       " a2: %x\n    a3: %x\n    a4: %x\n    a5: %x\n", core_id(),
1185         //       syscallno, a1, a2, a3, a4, a5);
1186
1187         if(syscallno > max_syscall || syscall_table[syscallno] == NULL)
1188                 panic("Invalid syscall number %d for proc %x!", syscallno, *p);
1189
1190         return syscall_table[syscallno](p,a1,a2,a3,a4,a5);
1191 }
1192
1193 /* Syscall tracing */
1194 static void __init_systrace(void)
1195 {
1196         systrace_buffer = kmalloc(MAX_SYSTRACES*sizeof(struct systrace_record), 0);
1197         if (!systrace_buffer)
1198                 panic("Unable to alloc a trace buffer\n");
1199         systrace_bufidx = 0;
1200         systrace_bufsize = MAX_SYSTRACES;
1201         /* Note we never free the buffer - it's around forever.  Feel free to change
1202          * this if you want to change the size or something dynamically. */
1203 }
1204
1205 /* If you call this while it is running, it will change the mode */
1206 void systrace_start(bool silent)
1207 {
1208         static bool init = FALSE;
1209         spin_lock_irqsave(&systrace_lock);
1210         if (!init) {
1211                 __init_systrace();
1212                 init = TRUE;
1213         }
1214         systrace_flags = silent ? SYSTRACE_ON : SYSTRACE_ON | SYSTRACE_LOUD; 
1215         spin_unlock_irqsave(&systrace_lock);
1216 }
1217
1218 int systrace_reg(bool all, struct proc *p)
1219 {
1220         int retval = 0;
1221         spin_lock_irqsave(&systrace_lock);
1222         if (all) {
1223                 printk("Tracing syscalls for all processes\n");
1224                 systrace_flags |= SYSTRACE_ALLPROC;
1225                 retval = 0;
1226         } else {
1227                 for (int i = 0; i < MAX_NUM_TRACED; i++) {
1228                         if (!systrace_procs[i]) {
1229                                 printk("Tracing syscalls for process %d\n", p->pid);
1230                                 systrace_procs[i] = p;
1231                                 retval = 0;
1232                                 break;
1233                         }
1234                 }
1235         }
1236         spin_unlock_irqsave(&systrace_lock);
1237         return retval;
1238 }
1239
1240 void systrace_stop(void)
1241 {
1242         spin_lock_irqsave(&systrace_lock);
1243         systrace_flags = 0;
1244         for (int i = 0; i < MAX_NUM_TRACED; i++)
1245                 systrace_procs[i] = 0;
1246         spin_unlock_irqsave(&systrace_lock);
1247 }
1248
1249 /* If you registered a process specifically, then you need to dereg it
1250  * specifically.  Or just fully stop, which will do it for all. */
1251 int systrace_dereg(bool all, struct proc *p)
1252 {
1253         spin_lock_irqsave(&systrace_lock);
1254         if (all) {
1255                 printk("No longer tracing syscalls for all processes.\n");
1256                 systrace_flags &= ~SYSTRACE_ALLPROC;
1257         } else {
1258                 for (int i = 0; i < MAX_NUM_TRACED; i++) {
1259                         if (systrace_procs[i] == p) {
1260                                 systrace_procs[i] = 0;
1261                                 printk("No longer tracing syscalls for process %d\n", p->pid);
1262                         }
1263                 }
1264         }
1265         spin_unlock_irqsave(&systrace_lock);
1266         return 0;
1267 }
1268
1269 /* Regardless of locking, someone could be writing into the buffer */
1270 void systrace_print(bool all, struct proc *p)
1271 {
1272         spin_lock_irqsave(&systrace_lock);
1273         /* if you want to be clever, you could make this start from the earliest
1274          * timestamp and loop around.  Careful of concurrent writes. */
1275         for (int i = 0; i < systrace_bufsize; i++)
1276                 if (systrace_buffer[i].timestamp)
1277                         printk("[%16llu] Syscall %d for proc %d on core %d, vcore %d\n",
1278                                systrace_buffer[i].timestamp,
1279                                systrace_buffer[i].syscallno,
1280                                systrace_buffer[i].pid,
1281                                systrace_buffer[i].coreid,
1282                                systrace_buffer[i].vcoreid);
1283         spin_unlock_irqsave(&systrace_lock);
1284 }
1285
1286 void systrace_clear_buffer(void)
1287 {
1288         spin_lock_irqsave(&systrace_lock);
1289         memset(systrace_buffer, 0, sizeof(struct systrace_record)*MAX_NUM_TRACED);
1290         spin_unlock_irqsave(&systrace_lock);
1291 }
1292
1293 void set_retval(uint32_t retval)
1294 {
1295         struct per_cpu_info* coreinfo = &per_cpu_info[core_id()];
1296         *(coreinfo->cur_ret.returnloc) = retval;
1297 }
1298 void set_errno(uint32_t errno)
1299 {
1300         struct per_cpu_info* coreinfo = &per_cpu_info[core_id()];
1301         if (coreinfo && coreinfo->cur_ret.errno_loc)
1302                 *(coreinfo->cur_ret.errno_loc) = errno;
1303 }