Removes some struct proc* refcnting
[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 <vfs.h>
34 #include <devfs.h>
35 #include <smp.h>
36 #include <arsc_server.h>
37
38
39 #ifdef __CONFIG_NETWORKING__
40 #include <arch/nic_common.h>
41 extern int (*send_frame)(const char *CT(len) data, size_t len);
42 extern unsigned char device_mac[6];
43 #endif
44
45 /* Tracing Globals */
46 int systrace_flags = 0;
47 struct systrace_record *systrace_buffer = 0;
48 unsigned int systrace_bufidx = 0;
49 size_t systrace_bufsize = 0;
50 struct proc *systrace_procs[MAX_NUM_TRACED] = {0};
51 spinlock_t systrace_lock = SPINLOCK_INITIALIZER;
52
53 /* Not enforcing the packing of systrace_procs yet, but don't rely on that */
54 static bool proc_is_traced(struct proc *p)
55 {
56         for (int i = 0; i < MAX_NUM_TRACED; i++)
57                 if (systrace_procs[i] == p)
58                         return true;
59         return false;
60 }
61
62 /* Helper that "finishes" the current async syscall.  This should be used when
63  * we are calling a function in a syscall that might not return and won't be
64  * able to use the normal syscall return path, such as proc_yield() and
65  * resource_req().  Call this from within syscall.c (I don't want it global).
66  *
67  * It is possible for another user thread to see the syscall being done early -
68  * they just need to be careful with the weird proc management calls (as in,
69  * don't trust an async fork).
70  *
71  * *sysc is in user memory, and should be pinned (TODO: UMEM).  There may be
72  * issues with unpinning this if we never return.
73  *
74  * Note, this is currently tied to how cores execute syscall batches: pcpui
75  * telling them what to do *next*, which should be advanced one past the call we
76  * are currently working on.  If this sucks too much in the future, we can have
77  * two separate struct syscall *s. */
78 static void signal_current_sc(int retval)
79 {
80         struct per_cpu_info *pcpui = &per_cpu_info[core_id()];
81         struct syscall *sysc = pcpui->syscalls - 1;     /* it was already advanced */
82         sysc->retval = retval;
83         sysc->flags |= SC_DONE;
84 }
85
86 /* Callable by any function while executing a syscall (or otherwise, actually).
87  * Prep this by setting the errno_loc in advance. */
88 void set_errno(int errno)
89 {
90         struct per_cpu_info *pcpui = &per_cpu_info[core_id()];
91         if (pcpui->errno_loc)
92                 *(pcpui->errno_loc) = errno;
93 }
94
95 /************** Utility Syscalls **************/
96
97 static int sys_null(void)
98 {
99         return 0;
100 }
101
102 // Writes 'val' to 'num_writes' entries of the well-known array in the kernel
103 // address space.  It's just #defined to be some random 4MB chunk (which ought
104 // to be boot_alloced or something).  Meant to grab exclusive access to cache
105 // lines, to simulate doing something useful.
106 static int sys_cache_buster(struct proc *p, uint32_t num_writes,
107                              uint32_t num_pages, uint32_t flags)
108 { TRUSTEDBLOCK /* zra: this is not really part of the kernel */
109         #define BUSTER_ADDR             0xd0000000  // around 512 MB deep
110         #define MAX_WRITES              1048576*8
111         #define MAX_PAGES               32
112         #define INSERT_ADDR     (UINFO + 2*PGSIZE) // should be free for these tests
113         uint32_t* buster = (uint32_t*)BUSTER_ADDR;
114         static spinlock_t buster_lock = SPINLOCK_INITIALIZER;
115         uint64_t ticks = -1;
116         page_t* a_page[MAX_PAGES];
117
118         /* Strided Accesses or Not (adjust to step by cachelines) */
119         uint32_t stride = 1;
120         if (flags & BUSTER_STRIDED) {
121                 stride = 16;
122                 num_writes *= 16;
123         }
124
125         /* Shared Accesses or Not (adjust to use per-core regions)
126          * Careful, since this gives 8MB to each core, starting around 512MB.
127          * Also, doesn't separate memory for core 0 if it's an async call.
128          */
129         if (!(flags & BUSTER_SHARED))
130                 buster = (uint32_t*)(BUSTER_ADDR + core_id() * 0x00800000);
131
132         /* Start the timer, if we're asked to print this info*/
133         if (flags & BUSTER_PRINT_TICKS)
134                 ticks = start_timing();
135
136         /* Allocate num_pages (up to MAX_PAGES), to simulate doing some more
137          * realistic work.  Note we don't write to these pages, even if we pick
138          * unshared.  Mostly due to the inconvenience of having to match up the
139          * number of pages with the number of writes.  And it's unnecessary.
140          */
141         if (num_pages) {
142                 spin_lock(&buster_lock);
143                 for (int i = 0; i < MIN(num_pages, MAX_PAGES); i++) {
144                         upage_alloc(p, &a_page[i],1);
145                         page_insert(p->env_pgdir, a_page[i], (void*)INSERT_ADDR + PGSIZE*i,
146                                     PTE_USER_RW);
147                         page_decref(a_page[i]);
148                 }
149                 spin_unlock(&buster_lock);
150         }
151
152         if (flags & BUSTER_LOCKED)
153                 spin_lock(&buster_lock);
154         for (int i = 0; i < MIN(num_writes, MAX_WRITES); i=i+stride)
155                 buster[i] = 0xdeadbeef;
156         if (flags & BUSTER_LOCKED)
157                 spin_unlock(&buster_lock);
158
159         if (num_pages) {
160                 spin_lock(&buster_lock);
161                 for (int i = 0; i < MIN(num_pages, MAX_PAGES); i++) {
162                         page_remove(p->env_pgdir, (void*)(INSERT_ADDR + PGSIZE * i));
163                         page_decref(a_page[i]);
164                 }
165                 spin_unlock(&buster_lock);
166         }
167
168         /* Print info */
169         if (flags & BUSTER_PRINT_TICKS) {
170                 ticks = stop_timing(ticks);
171                 printk("%llu,", ticks);
172         }
173         return 0;
174 }
175
176 static int sys_cache_invalidate(void)
177 {
178         #ifdef __i386__
179                 wbinvd();
180         #endif
181         return 0;
182 }
183
184 /* sys_reboot(): called directly from dispatch table. */
185
186 /* Print a string to the system console. */
187 static ssize_t sys_cputs(struct proc *p, const char *DANGEROUS string,
188                          size_t strlen)
189 {
190         char *t_string;
191         t_string = user_strdup_errno(p, string, strlen);
192         if (!t_string)
193                 return -1;
194         printk("%.*s", strlen, t_string);
195         user_memdup_free(p, t_string);
196         return (ssize_t)strlen;
197 }
198
199 // Read a character from the system console.
200 // Returns the character.
201 static uint16_t sys_cgetc(struct proc *p)
202 {
203         uint16_t c;
204
205         // The cons_getc() primitive doesn't wait for a character,
206         // but the sys_cgetc() system call does.
207         while ((c = cons_getc()) == 0)
208                 cpu_relax();
209
210         return c;
211 }
212
213 /* Returns the id of the cpu this syscall is executed on. */
214 static uint32_t sys_getcpuid(void)
215 {
216         return core_id();
217 }
218
219 // TODO: Temporary hack until thread-local storage is implemented on i386 and
220 // this is removed from the user interface
221 static size_t sys_getvcoreid(struct proc *p)
222 {
223         return proc_get_vcoreid(p, core_id());
224 }
225
226 /************** Process management syscalls **************/
227
228 /* Returns the calling process's pid */
229 static pid_t sys_getpid(struct proc *p)
230 {
231         return p->pid;
232 }
233
234 /* Creates a process from the file 'path'.  The process is not runnable by
235  * default, so it needs it's status to be changed so that the next call to
236  * schedule() will try to run it.  TODO: take args/envs from userspace. */
237 static int sys_proc_create(struct proc *p, char *path, size_t path_l,
238                            struct procinfo *pi)
239 {
240         int pid = 0;
241         char *t_path;
242         struct file *program;
243         struct proc *new_p;
244
245         /* Copy in the path.  Consider putting an upper bound on path_l. */
246         t_path = user_strdup_errno(p, path, path_l);
247         if (!t_path)
248                 return -1;
249         program = do_file_open(t_path, 0, 0);
250         user_memdup_free(p, t_path);
251         if (!program)
252                 return -1;                      /* presumably, errno is already set */
253         /* TODO: need to split the proc creation, since you must load after setting
254          * args/env, since auxp gets set up there. */
255         //new_p = proc_create(program, 0, 0);
256         if (proc_alloc(&new_p, current))
257                 goto mid_error;
258         /* Set the argument stuff needed by glibc */
259         if (memcpy_from_user_errno(p, new_p->procinfo->argp, pi->argp,
260                                    sizeof(pi->argp)))
261                 goto late_error;
262         if (memcpy_from_user_errno(p, new_p->procinfo->argbuf, pi->argbuf,
263                                    sizeof(pi->argbuf)))
264                 goto late_error;
265         if (load_elf(new_p, program))
266                 goto late_error;
267         kref_put(&program->f_kref);
268         /* Connect to stdin, stdout, stderr (part of proc_create()) */
269         assert(insert_file(&new_p->open_files, dev_stdin,  0) == 0);
270         assert(insert_file(&new_p->open_files, dev_stdout, 0) == 1);
271         assert(insert_file(&new_p->open_files, dev_stderr, 0) == 2);
272         __proc_ready(new_p);
273         pid = new_p->pid;
274         kref_put(&new_p->kref); /* give up the reference created in proc_create() */
275         return pid;
276 late_error:
277         proc_destroy(new_p);
278 mid_error:
279         kref_put(&program->f_kref);
280         return -1;
281 }
282
283 /* Makes process PID runnable.  Consider moving the functionality to process.c */
284 static error_t sys_proc_run(struct proc *p, unsigned pid)
285 {
286         struct proc *target = pid2proc(pid);
287         error_t retval = 0;
288
289         if (!target)
290                 return -EBADPROC;
291         // note we can get interrupted here. it's not bad.
292         spin_lock(&p->proc_lock);
293         // make sure we have access and it's in the right state to be activated
294         if (!proc_controls(p, target)) {
295                 kref_put(&target->kref);
296                 retval = -EPERM;
297         } else if (target->state != PROC_CREATED) {
298                 kref_put(&target->kref);
299                 retval = -EINVAL;
300         } else {
301                 __proc_set_state(target, PROC_RUNNABLE_S);
302                 schedule_proc(target);
303         }
304         spin_unlock(&p->proc_lock);
305         kref_put(&target->kref);
306         return retval;
307 }
308
309 /* Destroy proc pid.  If this is called by the dying process, it will never
310  * return.  o/w it will return 0 on success, or an error.  Errors include:
311  * - EBADPROC: if there is no such process with pid
312  * - EPERM: if caller does not control pid */
313 static error_t sys_proc_destroy(struct proc *p, pid_t pid, int exitcode)
314 {
315         error_t r;
316         struct proc *p_to_die = pid2proc(pid);
317
318         if (!p_to_die) {
319                 set_errno(ESRCH);
320                 return -1;
321         }
322         if (!proc_controls(p, p_to_die)) {
323                 kref_put(&p_to_die->kref);
324                 set_errno(EPERM);
325                 return -1;
326         }
327         if (p_to_die == p) {
328                 p->exitcode = exitcode;
329                 printd("[PID %d] proc exiting gracefully (code %d)\n", p->pid,exitcode);
330         } else {
331                 printd("[%d] destroying proc %d\n", p->pid, p_to_die->pid);
332         }
333         proc_destroy(p_to_die);
334         /* we only get here if we weren't the one to die */
335         kref_put(&p_to_die->kref);
336         return ESUCCESS;
337 }
338
339 static int sys_proc_yield(struct proc *p, bool being_nice)
340 {
341         /* proc_yield() often doesn't return - we need to set the syscall retval
342          * early.  If it doesn't return, it expects to eat our reference (for now).
343          */
344         signal_current_sc(0);
345         kref_get(&p->kref, 1);
346         proc_yield(p, being_nice);
347         kref_put(&p->kref);
348         return 0;
349 }
350
351 static ssize_t sys_fork(env_t* e)
352 {
353         // TODO: right now we only support fork for single-core processes
354         if (e->state != PROC_RUNNING_S) {
355                 set_errno(EINVAL);
356                 return -1;
357         }
358         /* Can't really fork if we don't have a current_tf to fork */
359         if (!current_tf) {
360                 set_errno(EINVAL);
361                 return -1;
362         }
363         env_t* env;
364         assert(!proc_alloc(&env, current));
365         assert(env != NULL);
366
367         env->heap_top = e->heap_top;
368         env->ppid = e->pid;
369         env->env_tf = *current_tf;
370
371         /* We need to speculatively say the syscall worked before copying the memory
372          * out, since the 'forked' process's call never actually goes through the
373          * syscall return path, and will never think it is done.  This violates a
374          * few things.  Just be careful with fork. */
375         signal_current_sc(0);
376
377         env->cache_colors_map = cache_colors_map_alloc();
378         for(int i=0; i < llc_cache->num_colors; i++)
379                 if(GET_BITMASK_BIT(e->cache_colors_map,i))
380                         cache_color_alloc(llc_cache, env->cache_colors_map);
381
382         duplicate_vmrs(e, env);
383
384         int copy_page(env_t* e, pte_t* pte, void* va, void* arg)
385         {
386                 env_t* env = (env_t*)arg;
387
388                 if(PAGE_PRESENT(*pte))
389                 {
390                         page_t* pp;
391                         if(upage_alloc(env,&pp,0))
392                                 return -1;
393                         if(page_insert(env->env_pgdir,pp,va,*pte & PTE_PERM))
394                         {
395                                 page_decref(pp);
396                                 return -1;
397                         }
398                         pagecopy(page2kva(pp),ppn2kva(PTE2PPN(*pte)));
399                         page_decref(pp);
400                 } else {
401                         assert(PAGE_PAGED_OUT(*pte));
402                         /* TODO: (SWAP) will need to either make a copy or CoW/refcnt the
403                          * backend store.  For now, this PTE will be the same as the
404                          * original PTE */
405                         panic("Swapping not supported!");
406                         pte_t* newpte = pgdir_walk(env->env_pgdir,va,1);
407                         if(!newpte)
408                                 return -1;
409                         *newpte = *pte;
410                 }
411                 return 0;
412         }
413
414         // TODO: (PC) this won't work.  Needs revisiting.
415         // copy procdata and procinfo
416         memcpy(env->procdata,e->procdata,sizeof(struct procdata));
417         memcpy(env->procinfo,e->procinfo,sizeof(struct procinfo));
418         env->procinfo->pid = env->pid;
419         env->procinfo->ppid = env->ppid;
420
421         /* for now, just copy the contents of every present page in the entire
422          * address space. */
423         if (env_user_mem_walk(e, 0, UMAPTOP, &copy_page, env)) {
424                 proc_destroy(env);      /* this is prob what you want, not decref by 2 */
425                 set_errno(ENOMEM);
426                 return -1;
427         }
428         clone_files(&e->open_files, &env->open_files);
429         __proc_ready(env);
430         __proc_set_state(env, PROC_RUNNABLE_S);
431         schedule_proc(env);
432
433         // don't decref the new process.
434         // that will happen when the parent waits for it.
435         // TODO: if the parent doesn't wait, we need to change the child's parent
436         // when the parent dies, or at least decref it
437
438         printd("[PID %d] fork PID %d\n",e->pid,env->pid);
439         return env->pid;
440 }
441
442 /* Load the binary "path" into the current process, and start executing it.
443  * argv and envp are magically bundled in procinfo for now.  Keep in sync with
444  * glibc's sysdeps/ros/execve.c.  Once past a certain point, this function won't
445  * return.  It assumes (and checks) that it is current.  Don't give it an extra
446  * refcnt'd *p (syscall won't do that). */
447 static int sys_exec(struct proc *p, char *path, size_t path_l,
448                     struct procinfo *pi)
449 {
450         int ret = -1;
451         char *t_path;
452         struct file *program;
453         struct trapframe *old_cur_tf = current_tf;
454         struct per_cpu_info *pcpui = &per_cpu_info[core_id()];
455
456         /* We probably want it to never be allowed to exec if it ever was _M */
457         if (p->state != PROC_RUNNING_S) {
458                 set_errno(EINVAL);
459                 return -1;
460         }
461         if (p != current) {
462                 set_errno(EINVAL);
463                 return -1;
464         }
465         /* Can't exec if we don't have a current_tf to restart (if we fail). */
466         if (!old_cur_tf) {
467                 set_errno(EINVAL);
468                 return -1;
469         }
470         /* Copy in the path.  Consider putting an upper bound on path_l. */
471         t_path = user_strdup_errno(p, path, path_l);
472         if (!t_path)
473                 return -1;
474         /* Clear the current_tf.  We won't be returning the 'normal' way.  Even if
475          * we want to return with an error, we need to go back differently in case
476          * we succeed.  This needs to be done before we could possibly block, but
477          * unfortunately happens before the point of no return. */
478         current_tf = 0;
479         /* This could block: */
480         program = do_file_open(t_path, 0, 0);
481         user_memdup_free(p, t_path);
482         if (!program)
483                 goto early_error;
484         /* Set the argument stuff needed by glibc */
485         if (memcpy_from_user_errno(p, p->procinfo->argp, pi->argp,
486                                    sizeof(pi->argp)))
487                 goto mid_error;
488         if (memcpy_from_user_errno(p, p->procinfo->argbuf, pi->argbuf,
489                                    sizeof(pi->argbuf)))
490                 goto mid_error;
491         /* This is the point of no return for the process. */
492         /* TODO: issues with this: Need to also assert there are no outstanding
493          * users of the sysrings.  the ldt page will get freed shortly, so that's
494          * okay.  Potentially issues with the nm and vcpd if we were in _M before
495          * and someone is trying to notify. */
496         memset(p->procdata, 0, sizeof(procdata_t));
497         destroy_vmrs(p);
498         close_all_files(&p->open_files, TRUE);
499         env_user_mem_free(p, 0, UMAPTOP);
500         if (load_elf(p, program)) {
501                 kref_put(&program->f_kref);
502                 proc_destroy(p);
503                 /* We don't want to do anything else - we just need to not accidentally
504                  * return to the user (hence the all_out) */
505                 goto all_out;
506         }
507         printd("[PID %d] exec %s\n", p->pid, file_name(program));
508         kref_put(&program->f_kref);
509         goto success;
510         /* These error and out paths are so we can handle the async interface, both
511          * for when we want to error/return to the proc, as well as when we succeed
512          * and want to start the newly exec'd _S */
513 mid_error:
514         /* These two error paths are for when we want to restart the process with an
515          * error value (errno is already set). */
516         kref_put(&program->f_kref);
517 early_error:
518         p->env_tf = *old_cur_tf;
519         signal_current_sc(-1);
520 success:
521         /* Here's how we'll restart the new (or old) process: */
522         spin_lock(&p->proc_lock);
523         __proc_set_state(p, PROC_RUNNABLE_S);
524         schedule_proc(p);
525         spin_unlock(&p->proc_lock);
526 all_out:
527         /* When we idle, we don't want to try executing other syscalls.  If exec
528          * succeeded (or the proc was destroyed) it'd just be wrong. */
529         pcpui->syscalls = 0;
530         pcpui->nr_calls = 0;
531         /* we can't return, since we'd write retvals to the old location of the
532          * sycall struct (which has been freed and is in the old userspace) (or has
533          * already been written to).*/
534         abandon_core();
535         smp_idle();
536         assert(0);
537 }
538
539 static ssize_t sys_trywait(env_t* e, pid_t pid, int* status)
540 {
541         struct proc* p = pid2proc(pid);
542
543         // TODO: this syscall is racy, so we only support for single-core procs
544         if(e->state != PROC_RUNNING_S)
545                 return -1;
546
547         // TODO: need to use errno properly.  sadly, ROS error codes conflict..
548
549         if(p)
550         {
551                 ssize_t ret;
552
553                 if(current->pid == p->ppid)
554                 {
555                         if(p->state == PROC_DYING)
556                         {
557                                 memcpy_to_user(e,status,&p->exitcode,sizeof(int));
558                                 printd("[PID %d] waited for PID %d (code %d)\n",
559                                        e->pid,p->pid,p->exitcode);
560                                 ret = 0;
561                         }
562                         else // not dead yet
563                         {
564                                 set_errno(ESUCCESS);
565                                 ret = -1;
566                         }
567                 }
568                 else // not a child of the calling process
569                 {
570                         set_errno(EPERM);
571                         ret = -1;
572                 }
573
574                 // if the wait succeeded, decref twice
575                 if (ret == 0)
576                         kref_put(&p->kref);
577                 kref_put(&p->kref);
578                 return ret;
579         }
580
581         set_errno(EPERM);
582         return -1;
583 }
584
585 /************** Memory Management Syscalls **************/
586
587 static void *sys_mmap(struct proc *p, uintreg_t a1, uintreg_t a2, uintreg_t a3,
588                       uintreg_t *a456)
589 {
590         uintreg_t _a456[3];
591         if (memcpy_from_user(p, _a456, a456, 3 * sizeof(uintreg_t)))
592                 sys_proc_destroy(p, p->pid, -1);
593         return mmap(p, a1, a2, a3, _a456[0], _a456[1], _a456[2]);
594 }
595
596 static intreg_t sys_mprotect(struct proc *p, void *addr, size_t len, int prot)
597 {
598         return mprotect(p, (uintptr_t)addr, len, prot);
599 }
600
601 static intreg_t sys_munmap(struct proc *p, void *addr, size_t len)
602 {
603         return munmap(p, (uintptr_t)addr, len);
604 }
605
606 static ssize_t sys_shared_page_alloc(env_t* p1,
607                                      void**DANGEROUS _addr, pid_t p2_id,
608                                      int p1_flags, int p2_flags
609                                     )
610 {
611         printk("[kernel] shared page alloc is deprecated/unimplemented.\n");
612         return -1;
613 }
614
615 static int sys_shared_page_free(env_t* p1, void*DANGEROUS addr, pid_t p2)
616 {
617         return -1;
618 }
619
620
621 static int sys_resource_req(struct proc *p, int type, unsigned int amt_wanted,
622                             unsigned int amt_wanted_min, int flags)
623 {
624         int retval;
625         signal_current_sc(0);
626         /* this might not return (if it's a _S -> _M transition) */
627         kref_get(&p->kref, 1);
628         retval = resource_req(p, type, amt_wanted, amt_wanted_min, flags);
629         kref_put(&p->kref);
630         return retval;
631 }
632
633 /* Will notify the target on the given vcore, if the caller controls the target.
634  * Will honor the target's wanted/vcoreid.  u_ne can be NULL. */
635 static int sys_notify(struct proc *p, int target_pid, unsigned int notif,
636                       struct notif_event *u_ne)
637 {
638         struct notif_event local_ne;
639         struct proc *target = pid2proc(target_pid);
640
641         if (!target) {
642                 set_errno(EBADPROC);
643                 return -1;
644         }
645         if (!proc_controls(p, target)) {
646                 kref_put(&target->kref);
647                 set_errno(EPERM);
648                 return -1;
649         }
650         /* if the user provided a notif_event, copy it in and use that */
651         if (u_ne) {
652                 if (memcpy_from_user(p, &local_ne, u_ne, sizeof(struct notif_event))) {
653                         kref_put(&target->kref);
654                         set_errno(EINVAL);
655                         return -1;
656                 }
657                 proc_notify(target, local_ne.ne_type, &local_ne);
658         } else {
659                 proc_notify(target, notif, 0);
660         }
661         kref_put(&target->kref);
662         return 0;
663 }
664
665 /* Will notify the calling process on the given vcore, independently of WANTED
666  * or advertised vcoreid.  If you change the parameters, change pop_ros_tf() */
667 static int sys_self_notify(struct proc *p, uint32_t vcoreid, unsigned int notif,
668                            struct notif_event *u_ne)
669 {
670         struct notif_event local_ne;
671
672         printd("[kernel] received self notify for vcoreid %d, notif %d, ne %08p\n",
673                vcoreid, notif, u_ne);
674         /* if the user provided a notif_event, copy it in and use that */
675         if (u_ne) {
676                 if (memcpy_from_user(p, &local_ne, u_ne, sizeof(struct notif_event))) {
677                         set_errno(EINVAL);
678                         return -1;
679                 }
680                 do_notify(p, vcoreid, local_ne.ne_type, &local_ne);
681         } else {
682                 do_notify(p, vcoreid, notif, 0);
683         }
684         return 0;
685 }
686
687 /* This will set a local timer for usec, then shut down the core */
688 static int sys_halt_core(struct proc *p, unsigned int usec)
689 {
690         /* TODO: ought to check and see if a timer was already active, etc, esp so
691          * userspace can't turn off timers.  also note we will also call whatever
692          * timer_interrupt() will do, though all we care about is just
693          * self_ipi/interrupting. */
694         set_core_timer(usec);
695         cpu_halt();
696         set_core_timer(0);              /* Disable the timer (we don't have a 0-shot yet) */
697
698         return 0;
699 }
700
701 /************** Platform Specific Syscalls **************/
702
703 //Read a buffer over the serial port
704 static ssize_t sys_serial_read(env_t* e, char *DANGEROUS _buf, size_t len)
705 {
706         printk("[kernel] serial reading is deprecated.\n");
707         if (len == 0)
708                 return 0;
709
710         #ifdef __CONFIG_SERIAL_IO__
711             char *COUNT(len) buf = user_mem_assert(e, _buf, len, PTE_USER_RO);
712                 size_t bytes_read = 0;
713                 int c;
714                 while((c = serial_read_byte()) != -1) {
715                         buf[bytes_read++] = (uint8_t)c;
716                         if(bytes_read == len) break;
717                 }
718                 return (ssize_t)bytes_read;
719         #else
720                 return -EINVAL;
721         #endif
722 }
723
724 //Write a buffer over the serial port
725 static ssize_t sys_serial_write(env_t* e, const char *DANGEROUS buf, size_t len)
726 {
727         printk("[kernel] serial writing is deprecated.\n");
728         if (len == 0)
729                 return 0;
730         #ifdef __CONFIG_SERIAL_IO__
731                 char *COUNT(len) _buf = user_mem_assert(e, buf, len, PTE_USER_RO);
732                 for(int i =0; i<len; i++)
733                         serial_send_byte(buf[i]);
734                 return (ssize_t)len;
735         #else
736                 return -EINVAL;
737         #endif
738 }
739
740 #ifdef __CONFIG_NETWORKING__
741 // This is not a syscall we want. Its hacky. Here just for syscall stuff until get a stack.
742 static ssize_t sys_eth_read(env_t* e, char *DANGEROUS buf)
743 {
744         if (eth_up) {
745
746                 uint32_t len;
747                 char *ptr;
748
749                 spin_lock(&packet_buffers_lock);
750
751                 if (num_packet_buffers == 0) {
752                         spin_unlock(&packet_buffers_lock);
753                         return 0;
754                 }
755
756                 ptr = packet_buffers[packet_buffers_head];
757                 len = packet_buffers_sizes[packet_buffers_head];
758
759                 num_packet_buffers--;
760                 packet_buffers_head = (packet_buffers_head + 1) % MAX_PACKET_BUFFERS;
761
762                 spin_unlock(&packet_buffers_lock);
763
764                 char* _buf = user_mem_assert(e, buf, len, PTE_U);
765
766                 memcpy(_buf, ptr, len);
767
768                 kfree(ptr);
769
770                 return len;
771         }
772         else
773                 return -EINVAL;
774 }
775
776 // This is not a syscall we want. Its hacky. Here just for syscall stuff until get a stack.
777 static ssize_t sys_eth_write(env_t* e, const char *DANGEROUS buf, size_t len)
778 {
779         if (eth_up) {
780
781                 if (len == 0)
782                         return 0;
783
784                 // HACK TO BYPASS HACK
785                 int just_sent = send_frame(buf, len);
786
787                 if (just_sent < 0) {
788                         printk("Packet send fail\n");
789                         return 0;
790                 }
791
792                 return just_sent;
793
794                 // END OF RECURSIVE HACK
795 /*
796                 char *COUNT(len) _buf = user_mem_assert(e, buf, len, PTE_U);
797                 int total_sent = 0;
798                 int just_sent = 0;
799                 int cur_packet_len = 0;
800                 while (total_sent != len) {
801                         cur_packet_len = ((len - total_sent) > MTU) ? MTU : (len - total_sent);
802                         char dest_mac[6] = APPSERVER_MAC_ADDRESS;
803                         char* wrap_buffer = eth_wrap(_buf + total_sent, cur_packet_len, device_mac, dest_mac, APPSERVER_PORT);
804                         just_sent = send_frame(wrap_buffer, cur_packet_len + sizeof(struct ETH_Header));
805
806                         if (just_sent < 0)
807                                 return 0; // This should be an error code of its own
808
809                         if (wrap_buffer)
810                                 kfree(wrap_buffer);
811
812                         total_sent += cur_packet_len;
813                 }
814
815                 return (ssize_t)len;
816 */
817         }
818         else
819                 return -EINVAL;
820 }
821
822 static ssize_t sys_eth_get_mac_addr(env_t* e, char *DANGEROUS buf) 
823 {
824         if (eth_up) {
825                 for (int i = 0; i < 6; i++)
826                         buf[i] = device_mac[i];
827                 return 0;
828         }
829         else
830                 return -EINVAL;
831 }
832
833 static int sys_eth_recv_check(env_t* e) 
834 {
835         if (num_packet_buffers != 0) 
836                 return 1;
837         else
838                 return 0;
839 }
840
841 #endif // Network
842
843 static intreg_t sys_read(struct proc *p, int fd, void *buf, int len)
844 {
845         ssize_t ret;
846         struct file *file = get_file_from_fd(&p->open_files, fd);
847         if (!file) {
848                 set_errno(EBADF);
849                 return -1;
850         }
851         if (!file->f_op->read) {
852                 kref_put(&file->f_kref);
853                 set_errno(EINVAL);
854                 return -1;
855         }
856         /* TODO: (UMEM) currently, read() handles user memcpy issues, but we
857          * probably should user_mem_check and pin the region here, so read doesn't
858          * worry about it */
859         ret = file->f_op->read(file, buf, len, &file->f_pos);
860         kref_put(&file->f_kref);
861         return ret;
862 }
863
864 static intreg_t sys_write(struct proc *p, int fd, const void *buf, int len)
865 {
866         ssize_t ret;
867         struct file *file = get_file_from_fd(&p->open_files, fd);
868         if (!file) {
869                 set_errno(EBADF);
870                 return -1;
871         }
872         if (!file->f_op->write) {
873                 kref_put(&file->f_kref);
874                 set_errno(EINVAL);
875                 return -1;
876         }
877         /* TODO: (UMEM) */
878         ret = file->f_op->write(file, buf, len, &file->f_pos);
879         kref_put(&file->f_kref);
880         return ret;
881 }
882
883 /* Checks args/reads in the path, opens the file, and inserts it into the
884  * process's open file list. 
885  *
886  * TODO: take the path length */
887 static intreg_t sys_open(struct proc *p, const char *path, size_t path_l,
888                          int oflag, int mode)
889 {
890         int fd = 0;
891         struct file *file;
892
893         printd("File %s Open attempt\n", path);
894         char *t_path = user_strdup_errno(p, path, path_l);
895         if (!t_path)
896                 return -1;
897         mode &= ~p->fs_env.umask;
898         file = do_file_open(t_path, oflag, mode);
899         user_memdup_free(p, t_path);
900         if (!file)
901                 return -1;
902         fd = insert_file(&p->open_files, file, 0);      /* stores the ref to file */
903         kref_put(&file->f_kref);
904         if (fd < 0) {
905                 warn("File insertion failed");
906                 return -1;
907         }
908         printd("File %s Open, res=%d\n", path, fd);
909         return fd;
910 }
911
912 static intreg_t sys_close(struct proc *p, int fd)
913 {
914         struct file *file = put_file_from_fd(&p->open_files, fd);
915         if (!file) {
916                 set_errno(EBADF);
917                 return -1;
918         }
919         return 0;
920 }
921
922 /* kept around til we remove the last ufe */
923 #define ufe(which,a0,a1,a2,a3) \
924         frontend_syscall_errno(p,APPSERVER_SYSCALL_##which,\
925                            (int)(a0),(int)(a1),(int)(a2),(int)(a3))
926
927 static intreg_t sys_fstat(struct proc *p, int fd, struct kstat *u_stat)
928 {
929         struct kstat *kbuf;
930         struct file *file = get_file_from_fd(&p->open_files, fd);
931         if (!file) {
932                 set_errno(EBADF);
933                 return -1;
934         }
935         kbuf = kmalloc(sizeof(struct kstat), 0);
936         if (!kbuf) {
937                 kref_put(&file->f_kref);
938                 set_errno(ENOMEM);
939                 return -1;
940         }
941         stat_inode(file->f_dentry->d_inode, kbuf);
942         kref_put(&file->f_kref);
943         /* TODO: UMEM: pin the memory, copy directly, and skip the kernel buffer */
944         if (memcpy_to_user_errno(p, u_stat, kbuf, sizeof(struct kstat))) {
945                 kfree(kbuf);
946                 set_errno(EINVAL);
947                 return -1;
948         }
949         kfree(kbuf);
950         return 0;
951 }
952
953 /* sys_stat() and sys_lstat() do nearly the same thing, differing in how they
954  * treat a symlink for the final item, which (probably) will be controlled by
955  * the lookup flags */
956 static intreg_t stat_helper(struct proc *p, const char *path, size_t path_l,
957                             struct kstat *u_stat, int flags)
958 {
959         struct kstat *kbuf;
960         struct dentry *path_d;
961         char *t_path = user_strdup_errno(p, path, path_l);
962         if (!t_path)
963                 return -1;
964         path_d = lookup_dentry(t_path, flags);
965         user_memdup_free(p, t_path);
966         if (!path_d)
967                 return -1;
968         kbuf = kmalloc(sizeof(struct kstat), 0);
969         if (!kbuf) {
970                 set_errno(ENOMEM);
971                 kref_put(&path_d->d_kref);
972                 return -1;
973         }
974         stat_inode(path_d->d_inode, kbuf);
975         kref_put(&path_d->d_kref);
976         /* TODO: UMEM: pin the memory, copy directly, and skip the kernel buffer */
977         if (memcpy_to_user_errno(p, u_stat, kbuf, sizeof(struct kstat))) {
978                 kfree(kbuf);
979                 set_errno(EINVAL);
980                 return -1;
981         }
982         kfree(kbuf);
983         return 0;
984 }
985
986 /* Follow a final symlink */
987 static intreg_t sys_stat(struct proc *p, const char *path, size_t path_l,
988                          struct kstat *u_stat)
989 {
990         return stat_helper(p, path, path_l, u_stat, LOOKUP_FOLLOW);
991 }
992
993 /* Don't follow a final symlink */
994 static intreg_t sys_lstat(struct proc *p, const char *path, size_t path_l,
995                           struct kstat *u_stat)
996 {
997         return stat_helper(p, path, path_l, u_stat, 0);
998 }
999
1000 intreg_t sys_fcntl(struct proc *p, int fd, int cmd, int arg)
1001 {
1002         int retval = 0;
1003         struct file *file = get_file_from_fd(&p->open_files, fd);
1004         if (!file) {
1005                 set_errno(EBADF);
1006                 return -1;
1007         }
1008         switch (cmd) {
1009                 case (F_DUPFD):
1010                         retval = insert_file(&p->open_files, file, arg);
1011                         if (retval < 0) {
1012                                 set_errno(-retval);
1013                                 retval = -1;
1014                         }
1015                         break;
1016                 case (F_GETFD):
1017                         retval = p->open_files.fd[fd].fd_flags;
1018                         break;
1019                 case (F_SETFD):
1020                         if (arg == FD_CLOEXEC)
1021                                 file->f_flags |= O_CLOEXEC;
1022                         break;
1023                 case (F_GETFL):
1024                         retval = file->f_flags;
1025                         break;
1026                 case (F_SETFL):
1027                         /* only allowed to set certain flags. */
1028                         arg &= O_FCNTL_FLAGS;
1029                         file->f_flags = (file->f_flags & ~O_FCNTL_FLAGS) | arg;
1030                         break;
1031                 default:
1032                         warn("Unsupported fcntl cmd %d\n", cmd);
1033         }
1034         kref_put(&file->f_kref);
1035         return retval;
1036 }
1037
1038 static intreg_t sys_access(struct proc *p, const char *path, size_t path_l,
1039                            int mode)
1040 {
1041         int retval;
1042         char *t_path = user_strdup_errno(p, path, path_l);
1043         if (!t_path)
1044                 return -1;
1045         retval = do_access(t_path, mode);
1046         user_memdup_free(p, t_path);
1047         printd("Access for path: %s retval: %d\n", path, retval);
1048         if (retval < 0) {
1049                 set_errno(-retval);
1050                 return -1;
1051         }
1052         return retval;
1053 }
1054
1055 intreg_t sys_umask(struct proc *p, int mask)
1056 {
1057         int old_mask = p->fs_env.umask;
1058         p->fs_env.umask = mask & S_PMASK;
1059         return old_mask;
1060 }
1061
1062 intreg_t sys_chmod(struct proc *p, const char *path, size_t path_l, int mode)
1063 {
1064         int retval;
1065         char *t_path = user_strdup_errno(p, path, path_l);
1066         if (!t_path)
1067                 return -1;
1068         retval = do_chmod(t_path, mode);
1069         user_memdup_free(p, t_path);
1070         if (retval < 0) {
1071                 set_errno(-retval);
1072                 return -1;
1073         }
1074         return retval;
1075 }
1076
1077 static intreg_t sys_lseek(struct proc *p, int fd, off_t offset, int whence)
1078 {
1079         off_t ret;
1080         struct file *file = get_file_from_fd(&p->open_files, fd);
1081         if (!file) {
1082                 set_errno(EBADF);
1083                 return -1;
1084         }
1085         ret = file->f_op->llseek(file, offset, whence);
1086         kref_put(&file->f_kref);
1087         return ret;
1088 }
1089
1090 intreg_t sys_link(struct proc *p, char *old_path, size_t old_l,
1091                   char *new_path, size_t new_l)
1092 {
1093         int ret;
1094         char *t_oldpath = user_strdup_errno(p, old_path, old_l);
1095         if (t_oldpath == NULL)
1096                 return -1;
1097         char *t_newpath = user_strdup_errno(p, new_path, new_l);
1098         if (t_newpath == NULL) {
1099                 user_memdup_free(p, t_oldpath);
1100                 return -1;
1101         }
1102         ret = do_link(t_oldpath, t_newpath);
1103         user_memdup_free(p, t_oldpath);
1104         user_memdup_free(p, t_newpath);
1105         return ret;
1106 }
1107
1108 intreg_t sys_unlink(struct proc *p, const char *path, size_t path_l)
1109 {
1110         int retval;
1111         char *t_path = user_strdup_errno(p, path, path_l);
1112         if (!t_path)
1113                 return -1;
1114         retval = do_unlink(t_path);
1115         user_memdup_free(p, t_path);
1116         return retval;
1117 }
1118
1119 intreg_t sys_symlink(struct proc *p, char *old_path, size_t old_l,
1120                      char *new_path, size_t new_l)
1121 {
1122         int ret;
1123         char *t_oldpath = user_strdup_errno(p, old_path, old_l);
1124         if (t_oldpath == NULL)
1125                 return -1;
1126         char *t_newpath = user_strdup_errno(p, new_path, new_l);
1127         if (t_newpath == NULL) {
1128                 user_memdup_free(p, t_oldpath);
1129                 return -1;
1130         }
1131         ret = do_symlink(new_path, old_path, S_IRWXU | S_IRWXG | S_IRWXO);
1132         user_memdup_free(p, t_oldpath);
1133         user_memdup_free(p, t_newpath);
1134         return ret;
1135 }
1136
1137 intreg_t sys_readlink(struct proc *p, char *path, size_t path_l,
1138                       char *u_buf, size_t buf_l)
1139 {
1140         char *symname;
1141         ssize_t copy_amt;
1142         struct dentry *path_d;
1143         char *t_path = user_strdup_errno(p, path, path_l);
1144         if (t_path == NULL)
1145                 return -1;
1146         path_d = lookup_dentry(t_path, 0);
1147         user_memdup_free(p, t_path);
1148         if (!path_d)
1149                 return -1;
1150         symname = path_d->d_inode->i_op->readlink(path_d);
1151         copy_amt = strnlen(symname, buf_l - 1) + 1;
1152         if (memcpy_to_user_errno(p, u_buf, symname, copy_amt)) {
1153                 kref_put(&path_d->d_kref);
1154                 set_errno(EINVAL);
1155                 return -1;
1156         }
1157         kref_put(&path_d->d_kref);
1158         printd("READLINK returning %s\n", u_buf);
1159         return copy_amt;
1160 }
1161
1162 intreg_t sys_chdir(struct proc *p, const char *path, size_t path_l)
1163 {
1164         int retval;
1165         char *t_path = user_strdup_errno(p, path, path_l);
1166         if (!t_path)
1167                 return -1;
1168         retval = do_chdir(&p->fs_env, t_path);
1169         user_memdup_free(p, t_path);
1170         if (retval) {
1171                 set_errno(-retval);
1172                 return -1;
1173         }
1174         return 0;
1175 }
1176
1177 /* Note cwd_l is not a strlen, it's an absolute size */
1178 intreg_t sys_getcwd(struct proc *p, char *u_cwd, size_t cwd_l)
1179 {
1180         int retval = 0;
1181         char *kfree_this;
1182         char *k_cwd = do_getcwd(&p->fs_env, &kfree_this, cwd_l);
1183         if (!k_cwd)
1184                 return -1;              /* errno set by do_getcwd */
1185         if (memcpy_to_user_errno(p, u_cwd, k_cwd, strnlen(k_cwd, cwd_l - 1) + 1))
1186                 retval = -1;
1187         kfree(kfree_this);
1188         return retval;
1189 }
1190
1191 intreg_t sys_mkdir(struct proc *p, const char *path, size_t path_l, int mode)
1192 {
1193         int retval;
1194         char *t_path = user_strdup_errno(p, path, path_l);
1195         if (!t_path)
1196                 return -1;
1197         mode &= ~p->fs_env.umask;
1198         retval = do_mkdir(t_path, mode);
1199         user_memdup_free(p, t_path);
1200         return retval;
1201 }
1202
1203 intreg_t sys_rmdir(struct proc *p, const char *path, size_t path_l)
1204 {
1205         int retval;
1206         char *t_path = user_strdup_errno(p, path, path_l);
1207         if (!t_path)
1208                 return -1;
1209         retval = do_rmdir(t_path);
1210         user_memdup_free(p, t_path);
1211         return retval;
1212 }
1213
1214 intreg_t sys_gettimeofday(struct proc *p, int *buf)
1215 {
1216         static spinlock_t gtod_lock = SPINLOCK_INITIALIZER;
1217         static int t0 = 0;
1218
1219         spin_lock(&gtod_lock);
1220         if(t0 == 0)
1221
1222 #if (defined __CONFIG_APPSERVER__)
1223         t0 = ufe(time,0,0,0,0);
1224 #else
1225         // Nanwan's birthday, bitches!!
1226         t0 = 1242129600;
1227 #endif 
1228         spin_unlock(&gtod_lock);
1229
1230         long long dt = read_tsc();
1231         int kbuf[2] = {t0+dt/system_timing.tsc_freq,
1232             (dt%system_timing.tsc_freq)*1000000/system_timing.tsc_freq};
1233
1234         return memcpy_to_user_errno(p,buf,kbuf,sizeof(kbuf));
1235 }
1236
1237 #define SIZEOF_STRUCT_TERMIOS 60
1238 intreg_t sys_tcgetattr(struct proc *p, int fd, void *termios_p)
1239 {
1240         int* kbuf = kmalloc(SIZEOF_STRUCT_TERMIOS,0);
1241         int ret = ufe(tcgetattr,fd,PADDR(kbuf),0,0);
1242         if(ret != -1 && memcpy_to_user_errno(p,termios_p,kbuf,SIZEOF_STRUCT_TERMIOS))
1243                 ret = -1;
1244         kfree(kbuf);
1245         return ret;
1246 }
1247
1248 intreg_t sys_tcsetattr(struct proc *p, int fd, int optional_actions,
1249                        const void *termios_p)
1250 {
1251         void* kbuf = user_memdup_errno(p,termios_p,SIZEOF_STRUCT_TERMIOS);
1252         if(kbuf == NULL)
1253                 return -1;
1254         int ret = ufe(tcsetattr,fd,optional_actions,PADDR(kbuf),0);
1255         user_memdup_free(p,kbuf);
1256         return ret;
1257 }
1258
1259 /* TODO: we don't have any notion of UIDs or GIDs yet, but don't let that stop a
1260  * process from thinking it can do these.  The other alternative is to have
1261  * glibc return 0 right away, though someone might want to do something with
1262  * these calls.  Someday. */
1263 intreg_t sys_setuid(struct proc *p, uid_t uid)
1264 {
1265         return 0;
1266 }
1267
1268 intreg_t sys_setgid(struct proc *p, gid_t gid)
1269 {
1270         return 0;
1271 }
1272
1273 /************** Syscall Invokation **************/
1274
1275 const static struct sys_table_entry syscall_table[] = {
1276         [SYS_null] = {(syscall_t)sys_null, "null"},
1277         [SYS_cache_buster] = {(syscall_t)sys_cache_buster, "buster"},
1278         [SYS_cache_invalidate] = {(syscall_t)sys_cache_invalidate, "wbinv"},
1279         [SYS_reboot] = {(syscall_t)reboot, "reboot!"},
1280         [SYS_cputs] = {(syscall_t)sys_cputs, "cputs"},
1281         [SYS_cgetc] = {(syscall_t)sys_cgetc, "cgetc"},
1282         [SYS_getcpuid] = {(syscall_t)sys_getcpuid, "getcpuid"},
1283         [SYS_getvcoreid] = {(syscall_t)sys_getvcoreid, "getvcoreid"},
1284         [SYS_getpid] = {(syscall_t)sys_getpid, "getpid"},
1285         [SYS_proc_create] = {(syscall_t)sys_proc_create, "proc_create"},
1286         [SYS_proc_run] = {(syscall_t)sys_proc_run, "proc_run"},
1287         [SYS_proc_destroy] = {(syscall_t)sys_proc_destroy, "proc_destroy"},
1288         [SYS_yield] = {(syscall_t)sys_proc_yield, "proc_yield"},
1289         [SYS_fork] = {(syscall_t)sys_fork, "fork"},
1290         [SYS_exec] = {(syscall_t)sys_exec, "exec"},
1291         [SYS_trywait] = {(syscall_t)sys_trywait, "trywait"},
1292         [SYS_mmap] = {(syscall_t)sys_mmap, "mmap"},
1293         [SYS_munmap] = {(syscall_t)sys_munmap, "munmap"},
1294         [SYS_mprotect] = {(syscall_t)sys_mprotect, "mprotect"},
1295         [SYS_shared_page_alloc] = {(syscall_t)sys_shared_page_alloc, "pa"},
1296         [SYS_shared_page_free] = {(syscall_t)sys_shared_page_free, "pf"},
1297         [SYS_resource_req] = {(syscall_t)sys_resource_req, "resource_req"},
1298         [SYS_notify] = {(syscall_t)sys_notify, "notify"},
1299         [SYS_self_notify] = {(syscall_t)sys_self_notify, "self_notify"},
1300         [SYS_halt_core] = {(syscall_t)sys_halt_core, "halt_core"},
1301 #ifdef __CONFIG_SERIAL_IO__
1302         [SYS_serial_read] = {(syscall_t)sys_serial_read, "ser_read"},
1303         [SYS_serial_write] = {(syscall_t)sys_serial_write, "ser_write"},
1304 #endif
1305 #ifdef __CONFIG_NETWORKING__
1306         [SYS_eth_read] = {(syscall_t)sys_eth_read, "eth_read"},
1307         [SYS_eth_write] = {(syscall_t)sys_eth_write, "eth_write"},
1308         [SYS_eth_get_mac_addr] = {(syscall_t)sys_eth_get_mac_addr, "get_mac"},
1309         [SYS_eth_recv_check] = {(syscall_t)sys_eth_recv_check, "recv_check"},
1310 #endif
1311 #ifdef __CONFIG_ARSC_SERVER__
1312         [SYS_init_arsc] = {(syscall_t)sys_init_arsc, "init_arsc"},
1313 #endif
1314         [SYS_read] = {(syscall_t)sys_read, "read"},
1315         [SYS_write] = {(syscall_t)sys_write, "write"},
1316         [SYS_open] = {(syscall_t)sys_open, "open"},
1317         [SYS_close] = {(syscall_t)sys_close, "close"},
1318         [SYS_fstat] = {(syscall_t)sys_fstat, "fstat"},
1319         [SYS_stat] = {(syscall_t)sys_stat, "stat"},
1320         [SYS_lstat] = {(syscall_t)sys_lstat, "lstat"},
1321         [SYS_fcntl] = {(syscall_t)sys_fcntl, "fcntl"},
1322         [SYS_access] = {(syscall_t)sys_access, "access"},
1323         [SYS_umask] = {(syscall_t)sys_umask, "umask"},
1324         [SYS_chmod] = {(syscall_t)sys_chmod, "chmod"},
1325         [SYS_lseek] = {(syscall_t)sys_lseek, "lseek"},
1326         [SYS_link] = {(syscall_t)sys_link, "link"},
1327         [SYS_unlink] = {(syscall_t)sys_unlink, "unlink"},
1328         [SYS_symlink] = {(syscall_t)sys_symlink, "symlink"},
1329         [SYS_readlink] = {(syscall_t)sys_readlink, "readlink"},
1330         [SYS_chdir] = {(syscall_t)sys_chdir, "chdir"},
1331         [SYS_getcwd] = {(syscall_t)sys_getcwd, "getcwd"},
1332         [SYS_mkdir] = {(syscall_t)sys_mkdir, "mkdri"},
1333         [SYS_rmdir] = {(syscall_t)sys_rmdir, "rmdir"},
1334         [SYS_gettimeofday] = {(syscall_t)sys_gettimeofday, "gettime"},
1335         [SYS_tcgetattr] = {(syscall_t)sys_tcgetattr, "tcgetattr"},
1336         [SYS_tcsetattr] = {(syscall_t)sys_tcsetattr, "tcsetattr"},
1337         [SYS_setuid] = {(syscall_t)sys_setuid, "setuid"},
1338         [SYS_setgid] = {(syscall_t)sys_setgid, "setgid"}
1339 };
1340
1341 /* Executes the given syscall.
1342  *
1343  * Note tf is passed in, which points to the tf of the context on the kernel
1344  * stack.  If any syscall needs to block, it needs to save this info, as well as
1345  * any silly state.
1346  * 
1347  * This syscall function is used by both local syscall and arsc, and should
1348  * remain oblivious of the caller. */
1349 intreg_t syscall(struct proc *p, uintreg_t syscallno, uintreg_t a1,
1350                  uintreg_t a2, uintreg_t a3, uintreg_t a4, uintreg_t a5)
1351 {
1352         const int max_syscall = sizeof(syscall_table)/sizeof(syscall_table[0]);
1353
1354         uint32_t coreid, vcoreid;
1355         if (systrace_flags & SYSTRACE_ON) {
1356                 if ((systrace_flags & SYSTRACE_ALLPROC) || (proc_is_traced(p))) {
1357                         coreid = core_id();
1358                         vcoreid = proc_get_vcoreid(p, coreid);
1359                         if (systrace_flags & SYSTRACE_LOUD) {
1360                                 printk("[%16llu] Syscall %3d (%12s):(%08p, %08p, %08p, %08p, "
1361                                        "%08p) proc: %d core: %d vcore: %d\n", read_tsc(),
1362                                        syscallno, syscall_table[syscallno].name, a1, a2, a3,
1363                                        a4, a5, p->pid, coreid, vcoreid);
1364                         } else {
1365                                 struct systrace_record *trace;
1366                                 unsigned int idx, new_idx;
1367                                 do {
1368                                         idx = systrace_bufidx;
1369                                         new_idx = (idx + 1) % systrace_bufsize;
1370                                 } while (!atomic_comp_swap(&systrace_bufidx, idx, new_idx));
1371                                 trace = &systrace_buffer[idx];
1372                                 trace->timestamp = read_tsc();
1373                                 trace->syscallno = syscallno;
1374                                 trace->arg1 = a1;
1375                                 trace->arg2 = a2;
1376                                 trace->arg3 = a3;
1377                                 trace->arg4 = a4;
1378                                 trace->arg5 = a5;
1379                                 trace->pid = p->pid;
1380                                 trace->coreid = coreid;
1381                                 trace->vcoreid = vcoreid;
1382                         }
1383                 }
1384         }
1385         //printk("Incoming syscall on core: %d number: %d\n    a1: %x\n   "
1386         //       " a2: %x\n    a3: %x\n    a4: %x\n    a5: %x\n", core_id(),
1387         //       syscallno, a1, a2, a3, a4, a5);
1388
1389         if (syscallno > max_syscall || syscall_table[syscallno].call == NULL)
1390                 panic("Invalid syscall number %d for proc %x!", syscallno, *p);
1391
1392         return syscall_table[syscallno].call(p, a1, a2, a3, a4, a5);
1393 }
1394
1395 /* A process can trap and call this function, which will set up the core to
1396  * handle all the syscalls.  a.k.a. "sys_debutante(needs, wants)" */
1397 void prep_syscalls(struct proc *p, struct syscall *sysc, unsigned int nr_calls)
1398 {
1399         int retval;
1400         struct per_cpu_info *pcpui = &per_cpu_info[core_id()];
1401         /* TODO: (UMEM) assert / pin the memory range sysc for nr_calls.  Not sure
1402          * how we'll know it is done to unpin it. (might need to handle it in
1403          * abandon_core() or smp_idle(). */
1404         user_mem_assert(p, sysc, nr_calls * sizeof(struct syscall), PTE_USER_RW);
1405         /* TEMP! */
1406         if (nr_calls != 1)
1407                 warn("Debutante calls: %d\n", nr_calls);
1408         /* Set up this core to process the local call */
1409         *pcpui->tf_retval_loc = 0;      /* current_tf's retval says how many are done */
1410         pcpui->syscalls = sysc;
1411         pcpui->nr_calls = nr_calls;
1412 }
1413
1414 /* This returns if there are no syscalls to do, o/w it always calls smp_idle()
1415  * afterwards. */
1416 void run_local_syscall(void)
1417 {
1418         struct per_cpu_info *pcpui = &per_cpu_info[core_id()];
1419         struct syscall *sysc;
1420
1421         if (!pcpui->nr_calls) {
1422                 /* TODO: UMEM - stop pinning their memory.  Note, we may need to do this
1423                  * in other places.  This also will be tricky with exec, which doesn't
1424                  * have the same memory map anymore */
1425                 return;
1426         }
1427         sysc = pcpui->syscalls++;               /* get the next */
1428         pcpui->nr_calls--;                              /* one less to do */
1429         (*pcpui->tf_retval_loc)++;              /* one more started */
1430         pcpui->errno_loc = &sysc->err;
1431         /* TODO: arg5 */
1432         sysc->retval = syscall(pcpui->cur_proc, sysc->num, sysc->arg0, sysc->arg1,
1433                                sysc->arg2, sysc->arg3, sysc->arg4);
1434         sysc->flags |= SC_DONE;
1435         /* regardless of whether the call blocked or not, we smp_idle().  If it was
1436          * the last call, it'll return to the process.  If there are more, it will
1437          * do them. */
1438         smp_idle();
1439         assert(0);
1440 }
1441
1442 /* Syscall tracing */
1443 static void __init_systrace(void)
1444 {
1445         systrace_buffer = kmalloc(MAX_SYSTRACES*sizeof(struct systrace_record), 0);
1446         if (!systrace_buffer)
1447                 panic("Unable to alloc a trace buffer\n");
1448         systrace_bufidx = 0;
1449         systrace_bufsize = MAX_SYSTRACES;
1450         /* Note we never free the buffer - it's around forever.  Feel free to change
1451          * this if you want to change the size or something dynamically. */
1452 }
1453
1454 /* If you call this while it is running, it will change the mode */
1455 void systrace_start(bool silent)
1456 {
1457         static bool init = FALSE;
1458         spin_lock_irqsave(&systrace_lock);
1459         if (!init) {
1460                 __init_systrace();
1461                 init = TRUE;
1462         }
1463         systrace_flags = silent ? SYSTRACE_ON : SYSTRACE_ON | SYSTRACE_LOUD; 
1464         spin_unlock_irqsave(&systrace_lock);
1465 }
1466
1467 int systrace_reg(bool all, struct proc *p)
1468 {
1469         int retval = 0;
1470         spin_lock_irqsave(&systrace_lock);
1471         if (all) {
1472                 printk("Tracing syscalls for all processes\n");
1473                 systrace_flags |= SYSTRACE_ALLPROC;
1474                 retval = 0;
1475         } else {
1476                 for (int i = 0; i < MAX_NUM_TRACED; i++) {
1477                         if (!systrace_procs[i]) {
1478                                 printk("Tracing syscalls for process %d\n", p->pid);
1479                                 systrace_procs[i] = p;
1480                                 retval = 0;
1481                                 break;
1482                         }
1483                 }
1484         }
1485         spin_unlock_irqsave(&systrace_lock);
1486         return retval;
1487 }
1488
1489 void systrace_stop(void)
1490 {
1491         spin_lock_irqsave(&systrace_lock);
1492         systrace_flags = 0;
1493         for (int i = 0; i < MAX_NUM_TRACED; i++)
1494                 systrace_procs[i] = 0;
1495         spin_unlock_irqsave(&systrace_lock);
1496 }
1497
1498 /* If you registered a process specifically, then you need to dereg it
1499  * specifically.  Or just fully stop, which will do it for all. */
1500 int systrace_dereg(bool all, struct proc *p)
1501 {
1502         spin_lock_irqsave(&systrace_lock);
1503         if (all) {
1504                 printk("No longer tracing syscalls for all processes.\n");
1505                 systrace_flags &= ~SYSTRACE_ALLPROC;
1506         } else {
1507                 for (int i = 0; i < MAX_NUM_TRACED; i++) {
1508                         if (systrace_procs[i] == p) {
1509                                 systrace_procs[i] = 0;
1510                                 printk("No longer tracing syscalls for process %d\n", p->pid);
1511                         }
1512                 }
1513         }
1514         spin_unlock_irqsave(&systrace_lock);
1515         return 0;
1516 }
1517
1518 /* Regardless of locking, someone could be writing into the buffer */
1519 void systrace_print(bool all, struct proc *p)
1520 {
1521         spin_lock_irqsave(&systrace_lock);
1522         /* if you want to be clever, you could make this start from the earliest
1523          * timestamp and loop around.  Careful of concurrent writes. */
1524         for (int i = 0; i < systrace_bufsize; i++)
1525                 if (systrace_buffer[i].timestamp)
1526                         printk("[%16llu] Syscall %3d (%12s):(%08p, %08p, %08p, %08p, "
1527                                "%08p) proc: %d core: %d vcore: %d\n",
1528                                systrace_buffer[i].timestamp,
1529                                systrace_buffer[i].syscallno,
1530                                syscall_table[systrace_buffer[i].syscallno].name,
1531                                systrace_buffer[i].arg1,
1532                                systrace_buffer[i].arg2,
1533                                systrace_buffer[i].arg3,
1534                                systrace_buffer[i].arg4,
1535                                systrace_buffer[i].arg5,
1536                                systrace_buffer[i].pid,
1537                                systrace_buffer[i].coreid,
1538                                systrace_buffer[i].vcoreid);
1539         spin_unlock_irqsave(&systrace_lock);
1540 }
1541
1542 void systrace_clear_buffer(void)
1543 {
1544         spin_lock_irqsave(&systrace_lock);
1545         memset(systrace_buffer, 0, sizeof(struct systrace_record) * MAX_SYSTRACES);
1546         spin_unlock_irqsave(&systrace_lock);
1547 }