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