Warning to pleco file added.
[barrelfish] / kernel / arch / x86_64 / syscall.c
1 /**
2  * \file
3  * \brief System calls implementation.
4  */
5
6 /*
7  * Copyright (c) 2007, 2008, 2009, 2010, 2012, ETH Zurich.
8  * All rights reserved.
9  *
10  * This file is distributed under the terms in the attached LICENSE file.
11  * If you do not find this file, copies can be found by writing to:
12  * ETH Zurich D-INFK, Haldeneggsteig 4, CH-8092 Zurich. Attn: Systems Group.
13  */
14
15 #include <kernel.h>
16 #include <kcb.h>
17 #include <syscall.h>
18 #include <barrelfish_kpi/syscalls.h>
19 #include <mdb/mdb.h>
20 #include <dispatch.h>
21 #include <paging_kernel_arch.h>
22 #include <paging_generic.h>
23 #include <exec.h>
24 #include <arch/x86/x86.h>
25 #include <arch/x86/apic.h>
26 #include <arch/x86/global.h>
27 #include <arch/x86/perfmon.h>
28 #include <vmkit.h>
29 #include <barrelfish_kpi/sys_debug.h>
30 #include <barrelfish_kpi/lmp.h>
31 #include <barrelfish_kpi/dispatcher_shared_target.h>
32 #include <arch/x86/debugregs.h>
33 #include <trace/trace.h>
34 #include <arch/x86/syscall.h>
35 #include <arch/x86/timing.h>
36 #include <fpu.h>
37 #include <arch/x86/ipi_notify.h>
38
39 #define MIN(a,b)        ((a) < (b) ? (a) : (b))
40
41 extern uint64_t user_stack_save;
42
43 /* FIXME: lots of missing argument checks in this function */
44 static struct sysret handle_dispatcher_setup(struct capability *to,
45                                              int cmd, uintptr_t *args)
46 {
47     capaddr_t cptr = args[0];
48     int depth    = args[1];
49     capaddr_t vptr = args[2];
50     capaddr_t dptr = args[3];
51     bool run = args[4];
52     capaddr_t odptr = args[5];
53
54     TRACE(KERNEL, SC_DISP_SETUP, 0);
55     struct sysret sr = sys_dispatcher_setup(to, cptr, depth, vptr, dptr, run, odptr);
56     TRACE(KERNEL, SC_DISP_SETUP, 1);
57     return sr;
58 }
59
60 static struct sysret handle_dispatcher_properties(struct capability *to,
61                                                   int cmd, uintptr_t *args)
62 {
63     enum task_type type = args[0];
64     unsigned long deadline = args[1];
65     unsigned long wcet = args[2];
66     unsigned long period = args[3];
67     unsigned long release = args[4];
68     unsigned short weight = args[5];
69
70     TRACE(KERNEL, SC_DISP_PROPS, 0);
71     struct sysret sr = sys_dispatcher_properties(to, type, deadline, wcet, period,
72                                                  release, weight);
73     TRACE(KERNEL, SC_DISP_PROPS, 1);
74     return sr;
75 }
76
77 static struct sysret handle_retype_common(struct capability *root,
78                                           uintptr_t *args,
79                                           bool from_monitor)
80 {
81     uint64_t source_cptr     = args[0];
82     uint64_t type            = args[1];
83     uint64_t objbits         = args[2];
84     uint64_t  dest_cnode_cptr = args[3];
85     uint64_t dest_slot       = args[4];
86     uint64_t dest_vbits      = args[5];
87
88     TRACE(KERNEL, SC_RETYPE, 0);
89     struct sysret sr = sys_retype(root, source_cptr, type, objbits, dest_cnode_cptr,
90                                   dest_slot, dest_vbits, from_monitor);
91     TRACE(KERNEL, SC_RETYPE, 1);
92     return sr;
93 }
94
95 static struct sysret handle_retype(struct capability *root,
96                                    int cmd, uintptr_t *args)
97 {
98     return handle_retype_common(root, args, false);
99 }
100
101 static struct sysret handle_create(struct capability *root,
102                                    int cmd, uintptr_t *args)
103 {
104     /* Retrieve arguments */
105     enum objtype type         = args[0];
106     uint8_t objbits           = args[1];
107     capaddr_t dest_cnode_cptr = args[2];
108     cslot_t dest_slot         = args[3];
109     uint8_t dest_vbits        = args[4];
110
111     TRACE(KERNEL, SC_CREATE, 0);
112     struct sysret sr = sys_create(root, type, objbits, dest_cnode_cptr, dest_slot,
113                                   dest_vbits);
114     TRACE(KERNEL, SC_CREATE, 1);
115     return sr;
116 }
117
118
119 /**
120  * Common code for copying and minting except the mint flag and param passing
121  */
122 static struct sysret copy_or_mint(struct capability *root,
123                                   uintptr_t *args, bool mint)
124 {
125     /* Retrive arguments */
126     capaddr_t  destcn_cptr   = args[0];
127     uint64_t dest_slot     = args[1];
128     capaddr_t  source_cptr   = args[2];
129     int      destcn_vbits  = args[3];
130     int      source_vbits  = args[4];
131     uint64_t param1, param2;
132     // params only sent if mint operation
133     if (mint) {
134         param1 = args[5];
135         param2 = args[6];
136     } else {
137         param1 = param2 = 0;
138     }
139
140     TRACE(KERNEL, SC_COPY_OR_MINT, 0);
141     struct sysret sr = sys_copy_or_mint(root, destcn_cptr, dest_slot, source_cptr,
142                                         destcn_vbits, source_vbits, param1, param2, mint);
143     TRACE(KERNEL, SC_COPY_OR_MINT, 1);
144     return sr;
145 }
146
147 static struct sysret handle_map(struct capability *ptable,
148                                 int cmd, uintptr_t *args)
149 {
150     /* Retrieve arguments */
151     uint64_t  slot          = args[0];
152     capaddr_t source_cptr   = args[1];
153     int       source_vbits  = args[2];
154     uint64_t  flags         = args[3];
155     uint64_t  offset        = args[4];
156     uint64_t  pte_count     = args[5];
157
158     TRACE(KERNEL, SC_MAP, 0);
159     struct sysret sr = sys_map(ptable, slot, source_cptr, source_vbits, flags, offset,
160                    pte_count);
161     TRACE(KERNEL, SC_MAP, 1);
162     return sr;
163 }
164
165 static struct sysret handle_mint(struct capability *root,
166                                  int cmd, uintptr_t *args)
167 {
168     return copy_or_mint(root, args, true);
169 }
170
171 static struct sysret handle_copy(struct capability *root,
172                                  int cmd, uintptr_t *args)
173 {
174     return copy_or_mint(root, args, false);
175 }
176
177 static struct sysret handle_delete_common(struct capability *root,
178                                    uintptr_t *args,
179                                    bool from_monitor)
180 {
181     capaddr_t cptr = args[0];
182     int bits     = args[1];
183
184     TRACE(KERNEL, SC_DELETE, 0);
185     struct sysret sr = sys_delete(root, cptr, bits, from_monitor);
186     TRACE(KERNEL, SC_DELETE, 1);
187
188     return sr;
189 }
190
191 static struct sysret handle_delete(struct capability *root,
192                                    int cmd, uintptr_t *args)
193 {
194     return handle_delete_common(root, args, false);
195 }
196
197
198 static struct sysret handle_revoke_common(struct capability *root,
199                                           uintptr_t *args,
200                                           bool from_monitor)
201 {
202     capaddr_t cptr = args[0];
203     int bits     = args[1];
204
205     TRACE(KERNEL, SC_REVOKE, 0);
206     struct sysret sr = sys_revoke(root, cptr, bits, from_monitor);
207     TRACE(KERNEL, SC_REVOKE, 1);
208
209     return sr;
210 }
211
212 static struct sysret handle_revoke(struct capability *root,
213                                    int cmd, uintptr_t *args)
214 {
215     return handle_revoke_common(root, args, false);
216 }
217
218
219 static struct sysret handle_unmap(struct capability *pgtable,
220                                   int cmd, uintptr_t *args)
221 {
222     capaddr_t cptr = args[0];
223     int bits       = args[1];
224     size_t entry   = args[2];
225     size_t pages   = args[3];
226
227     errval_t err;
228     struct cte *mapping;
229     err = caps_lookup_slot(&dcb_current->cspace.cap, cptr, bits,
230                                     &mapping, CAPRIGHTS_READ_WRITE);
231     if (err_is_fail(err)) {
232         return SYSRET(err_push(err, SYS_ERR_CAP_NOT_FOUND));
233     }
234
235     TRACE(KERNEL, SC_UNMAP, 0);
236     err = page_mappings_unmap(pgtable, mapping, entry, pages);
237     TRACE(KERNEL, SC_UNMAP, 1);
238     return SYSRET(err);
239 }
240
241 /// Different handler for cap operations performed by the monitor
242 static struct sysret monitor_handle_retype(struct capability *kernel_cap,
243                                            int cmd, uintptr_t *args)
244 {
245     errval_t err;
246
247     capaddr_t root_caddr = args[0];
248     capaddr_t root_vbits = args[1];
249
250     struct capability *root;
251     err = caps_lookup_cap(&dcb_current->cspace.cap, root_caddr, root_vbits,
252                           &root, CAPRIGHTS_READ);
253     if (err_is_fail(err)) {
254         return SYSRET(err_push(err, SYS_ERR_ROOT_CAP_LOOKUP));
255     }
256
257     /* XXX: this hides the first two arguments */
258     return handle_retype_common(root, &args[2], true);
259 }
260
261 /// Different handler for cap operations performed by the monitor
262 static struct sysret monitor_handle_delete(struct capability *kernel_cap,
263                                            int cmd, uintptr_t *args)
264 {
265     errval_t err;
266
267     capaddr_t root_caddr = args[0];
268     capaddr_t root_vbits = args[1];
269
270     struct capability *root;
271     err = caps_lookup_cap(&dcb_current->cspace.cap, root_caddr, root_vbits,
272                           &root, CAPRIGHTS_READ);
273     if (err_is_fail(err)) {
274         return SYSRET(err_push(err, SYS_ERR_ROOT_CAP_LOOKUP));
275     }
276
277     /* XXX: this hides the first two arguments */
278     return handle_delete_common(root, &args[2], true);
279 }
280
281 /// Different handler for cap operations performed by the monitor
282 static struct sysret monitor_handle_revoke(struct capability *kernel_cap,
283                                            int cmd, uintptr_t *args)
284 {
285     errval_t err;
286
287     capaddr_t root_caddr = args[0];
288     capaddr_t root_vbits = args[1];
289
290     struct capability *root;
291     err = caps_lookup_cap(&dcb_current->cspace.cap, root_caddr, root_vbits,
292                           &root, CAPRIGHTS_READ);
293     if (err_is_fail(err)) {
294         return SYSRET(err_push(err, SYS_ERR_ROOT_CAP_LOOKUP));
295     }
296
297     /* XXX: this hides the first two arguments */
298     return handle_revoke_common(root, &args[2], true);
299 }
300
301 static struct sysret monitor_handle_register(struct capability *kernel_cap,
302                                              int cmd, uintptr_t *args)
303 {
304     capaddr_t ep_caddr = args[0];
305
306     TRACE(KERNEL, SC_MONITOR_REGISTER, 0);
307     struct sysret sr = sys_monitor_register(ep_caddr);
308     TRACE(KERNEL, SC_MONITOR_REGISTER, 1);
309     return sr;
310 }
311
312 /**
313  * \brief Spawn a new core and create a kernel cap for it.
314  */
315 static struct sysret monitor_spawn_core(struct capability *kernel_cap,
316                                         int cmd, uintptr_t *args)
317 {
318     coreid_t core_id       = args[0];
319     enum cpu_type cpu_type = args[1];
320     genvaddr_t entry       = args[2];
321
322     TRACE(KERNEL, SC_SPAWN_CORE, 0);
323     struct sysret sr = sys_monitor_spawn_core(core_id, cpu_type, entry);
324     TRACE(KERNEL, SC_SPAWN_CORE, 1);
325     return sr;
326 }
327
328 static inline void __monitor(const void *eax, unsigned long ecx,
329                  unsigned long edx)
330 {
331     /* "monitor %eax, %ecx, %edx;" */
332     __asm__ __volatile__ (".byte 0x0f, 0x01, 0xc8;"
333                           :: "a" (eax), "c" (ecx), "d"(edx));
334 }
335
336 static inline void __mwait(unsigned long eax, unsigned long ecx)
337 {
338     /* "mwait %eax, %ecx;" */
339     __asm__ __volatile__ (".byte 0x0f, 0x01, 0xc9;"
340                           :: "a" (eax), "c" (ecx));
341 }
342
343 /**
344  * \brief Request to stop the current core
345  */
346 #include "startup.h"
347 #include <barrelfish_kpi/init.h>
348 #define CNODE(cte)     (cte)->cap.u.cnode.cnode
349 static struct sysret monitor_stop_core(struct capability *kernel_cap,
350                                        int cmd, uintptr_t *args)
351 {
352     printk(LOG_ERR, "monitor_stop_core id=%d\n", my_core_id);
353
354     /*extern struct spawn_state spawn_state;
355     struct cte *urpc_frame_cte = caps_locate_slot(CNODE(spawn_state.taskcn),
356                                                   TASKCN_SLOT_MON_URPC);
357     int  err = paging_x86_64_map_memory(urpc_frame_cte->cap.u.frame.base, 4096);
358     assert (err == 0);
359     lpaddr_t urpc_ptr = local_phys_to_mem(urpc_frame_cte->cap.u.frame.base);
360     printf("%s:%s:%d: waiting on urpc 0x%"PRIxGENPADDR" 0x%"PRIxLPADDR"\n",
361            __FILE__, __FUNCTION__, __LINE__, urpc_frame_cte->cap.u.frame.base, urpc_ptr);*/
362
363     printf("%s:%s:%d: before monitor...\n", __FILE__, __FUNCTION__, __LINE__);
364     //apic_mask_timer();
365     //apic_disable();
366
367     //dcb_current->disabled = false;
368
369     global->wait[0] = 0x1;
370     if (has_monitor_mwait()) {
371         printf("%s:%s:%d: before monitor/mwait\n", __FILE__, __FUNCTION__, __LINE__);
372         monitor_mwait((lvaddr_t)&(global->wait[0]), 0x1, 0, 0);
373     }
374     else {
375         printf("%s:%s:%d: before halt \n", __FILE__, __FUNCTION__, __LINE__);
376
377         halt();
378     }
379
380     printf("%s:%s:%d: woken up again...\n", __FILE__, __FUNCTION__, __LINE__);
381     /**
382      * This means we reenable on an IRQ an jump in irq handler
383      * in irq.c, after that we segfault in the kernel
384      */
385     //__asm__ __volatile__ ("sti");
386     //halt();
387
388     return (struct sysret){.error = SYS_ERR_OK, .value = my_core_id};
389 }
390
391 static struct sysret kernel_start_core(struct capability *kernel_cap,
392                                        int cmd, uintptr_t *args)
393 {
394     printf("%s:%s:%d %"PRIu64"\n", __FILE__, __FUNCTION__, __LINE__, global->wait[0]);
395     global->wait[0] = 0x0;
396     return (struct sysret){.error = SYS_ERR_OK, .value = 0x0};
397 }
398
399 static struct sysret kernel_add_kcb(struct capability *kern_cap,
400                                     int cmd, uintptr_t *args)
401 {
402     uint64_t kcb_addr = args[0];
403
404     struct kcb *new_kcb = (struct kcb *)kcb_addr;
405     if (kcb_current->next) {
406         assert(kcb_current->prev);
407         new_kcb->next = kcb_current->next;
408         new_kcb->prev = kcb_current;
409         new_kcb->next->prev = new_kcb;
410         new_kcb->prev->next = new_kcb;
411     } else {
412         kcb_current->next = kcb_current->prev = new_kcb;
413         new_kcb->next = new_kcb->prev = kcb_current;
414     }
415     // update kernel_now offset
416     new_kcb->kernel_off -= kernel_now;
417     // reset scheduler statistics
418     scheduler_reset_time();
419     // update current core id of all domains
420     kcb_update_core_id(new_kcb);
421     // upcall domains with registered interrupts to tell them to reregister
422     irq_table_notify_domains(new_kcb);
423
424     printk(LOG_NOTE, "kcb_current = %p\n", kcb_current);
425
426     return SYSRET(SYS_ERR_OK);
427 }
428
429 static struct sysret kernel_remove_kcb(struct capability *kern_cap,
430                                        int cmd, uintptr_t *args)
431 {
432     printk(LOG_NOTE, "in kernel_remove_kcb invocation!\n");
433     uint64_t kcb_addr = args[0];
434
435     struct kcb *to_remove = (struct kcb *)kcb_addr;
436
437     return SYSRET(kcb_remove(to_remove));
438 }
439
440 static struct sysret kernel_suspend_kcb_sched(struct capability *kern_cap,
441                                               int cmd, uintptr_t *args)
442 {
443     printk(LOG_NOTE, "in kernel_suspend_kcb_sched invocation!\n");
444     kcb_sched_suspended = (bool)args[0];
445     return SYSRET(SYS_ERR_OK);
446 }
447
448
449 static struct sysret monitor_get_core_id(struct capability *kernel_cap,
450                                          int cmd, uintptr_t *args)
451 {
452     return (struct sysret){.error = SYS_ERR_OK, .value = my_core_id};
453 }
454
455 static struct sysret monitor_get_arch_id(struct capability *kernel_cap,
456                                          int cmd, uintptr_t *args)
457 {
458     return (struct sysret){.error = SYS_ERR_OK, .value = apic_id};
459 }
460
461 static struct sysret monitor_identify_cap_common(struct capability *kernel_cap,
462                                                  struct capability *root,
463                                                  uintptr_t *args)
464 {
465     capaddr_t cptr = args[0];
466     uint8_t bits = args[1];
467     struct capability *retbuf = (void *)args[2];
468
469     return sys_monitor_identify_cap(root, cptr, bits, retbuf);
470 }
471
472 static struct sysret monitor_identify_cap(struct capability *kernel_cap,
473                                           int cmd, uintptr_t *args)
474 {
475     return monitor_identify_cap_common(kernel_cap, &dcb_current->cspace.cap, args);
476 }
477
478 static struct sysret monitor_identify_domains_cap(struct capability *kernel_cap,
479                                                   int cmd, uintptr_t *args)
480 {
481     errval_t err;
482
483     capaddr_t root_caddr = args[0];
484     capaddr_t root_vbits = args[1];
485
486     struct capability *root;
487     err = caps_lookup_cap(&dcb_current->cspace.cap, root_caddr, root_vbits,
488                           &root, CAPRIGHTS_READ);
489
490     if (err_is_fail(err)) {
491         return SYSRET(err_push(err, SYS_ERR_ROOT_CAP_LOOKUP));
492     }
493
494     /* XXX: this hides the first two arguments */
495     return monitor_identify_cap_common(kernel_cap, root, &args[2]);
496 }
497
498 static struct sysret monitor_remote_cap(struct capability *kernel_cap,
499                                         int cmd, uintptr_t *args)
500 {
501     struct capability *root = &dcb_current->cspace.cap;
502     capaddr_t cptr = args[0];
503     int bits = args[1];
504     bool remote = args[2];
505
506     struct cte *cte;
507     errval_t err = caps_lookup_slot(root, cptr, bits, &cte, CAPRIGHTS_WRITE);
508     if (err_is_fail(err)) {
509         return SYSRET(err_push(err, SYS_ERR_IDENTIFY_LOOKUP));
510     }
511
512     set_cap_remote(cte, remote);
513     bool has_desc = has_descendants(cte);
514
515     return (struct sysret){ .error = SYS_ERR_OK, .value = has_desc };
516 }
517
518
519 static struct sysret monitor_create_cap(struct capability *kernel_cap,
520                                         int cmd, uintptr_t *args)
521 {
522     /* XXX: Get the raw metadata of the capability to create */
523     struct capability *src = (struct capability *)args;
524     int pos = sizeof(struct capability) / sizeof(uint64_t);
525
526     /* Certain types cannot be created here */
527     if ((src->type == ObjType_Null) || (src->type == ObjType_EndPoint)
528         || (src->type == ObjType_Dispatcher) || (src->type == ObjType_Kernel)
529         || (src->type == ObjType_IRQTable)) {
530         return SYSRET(SYS_ERR_ILLEGAL_DEST_TYPE);
531     }
532
533     /* Create the cap in the destination */
534     capaddr_t cnode_cptr = args[pos];
535     int cnode_vbits    = args[pos + 1];
536     size_t slot        = args[pos + 2];
537
538     return SYSRET(caps_create_from_existing(&dcb_current->cspace.cap,
539                                             cnode_cptr, cnode_vbits,
540                                             slot, src));
541 }
542
543 static struct sysret monitor_nullify_cap(struct capability *kernel_cap,
544                                          int cmd, uintptr_t *args)
545 {
546     capaddr_t cptr = args[0];
547     uint8_t bits = args[1];
548
549     return sys_monitor_nullify_cap(cptr, bits);
550 }
551
552 static struct sysret monitor_iden_cnode_get_cap(struct capability *kern_cap,
553                                                 int cmd, uintptr_t *args)
554 {
555     errval_t err;
556
557     /* XXX: Get the raw metadata of the cnode */
558     int pos = sizeof(struct capability) / sizeof(uint64_t);
559     struct capability *cnode = (struct capability *)args;
560     assert(cnode->type == ObjType_CNode);
561
562     struct capability *cnode_copy;
563     err = mdb_get_copy(cnode, &cnode_copy);
564     if (err_is_fail(err)) {
565         return SYSRET(err);
566     }
567
568     capaddr_t slot = args[pos];
569     struct cte* cte = caps_locate_slot(cnode_copy->u.cnode.cnode, slot);
570
571     // XXX: Write cap data directly back to user-space
572     // FIXME: this should involve a pointer/range check for reliability,
573     // but because the monitor is inherently trusted it's not a security hole
574     struct capability *retbuf = (void *)args[pos + 1];
575     *retbuf = cte->cap;
576
577     return SYSRET(SYS_ERR_OK);
578 }
579
580 static struct sysret monitor_handle_sync_timer(struct capability *kern_cap,
581                                                int cmd, uintptr_t *args)
582 {
583     uint64_t synctime = args[0];
584     return sys_monitor_handle_sync_timer(synctime);
585 }
586
587
588 static struct sysret handle_frame_identify(struct capability *to,
589                                            int cmd, uintptr_t *args)
590 {
591     // Return with physical base address of frame
592     // XXX: pack size into bottom bits of base address
593     assert(to->type == ObjType_Frame || to->type == ObjType_DevFrame);
594     assert((to->u.frame.base & BASE_PAGE_MASK) == 0);
595     return (struct sysret) {
596         .error = SYS_ERR_OK,
597         .value = to->u.frame.base | to->u.frame.bits,
598     };
599 }
600
601 static struct sysret handle_frame_modify_flags(struct capability *to,
602                                                int cmd, uintptr_t *args)
603 {
604     // Modify flags of (part of) mapped region of frame
605     assert(to->type == ObjType_Frame || to->type == ObjType_DevFrame);
606
607     // unpack arguments
608     size_t offset = args[0]; // in pages; of first page to modify from first
609                              // page in mapped region
610     size_t pages  = args[1]; // #pages to modify
611     size_t flags  = args[2]; // new flags
612
613     page_mappings_modify_flags(to, offset, pages, flags);
614
615     return (struct sysret) {
616         .error = SYS_ERR_OK,
617         .value = 0,
618     };
619 }
620
621 static struct sysret handle_kcb_identify(struct capability *to,
622                                          int cmd, uintptr_t *args)
623 {
624     // Return with physical base address of frame
625     // XXX: pack size into bottom bits of base address
626     assert(to->type == ObjType_KernelControlBlock);
627     lvaddr_t vkcb = (lvaddr_t) to->u.kernelcontrolblock.kcb;
628     assert((vkcb & BASE_PAGE_MASK) == 0);
629     return (struct sysret) {
630         .error = SYS_ERR_OK,
631         .value = mem_to_local_phys(vkcb) | OBJBITS_KCB,
632     };
633 }
634
635
636
637 static struct sysret handle_io(struct capability *to, int cmd, uintptr_t *args)
638 {
639     uint64_t    port = args[0];
640     uint64_t    data = args[1]; // ignored for input
641
642     return sys_io(to, cmd, port, data);
643 }
644
645 static struct sysret
646 handle_dispatcher_setup_guest (struct capability *to, int cmd, uintptr_t *args)
647 {
648     errval_t err;
649     struct dcb *dcb = to->u.dispatcher.dcb;
650
651     capaddr_t epp = args[0];
652     capaddr_t vnodep = args[1];
653     capaddr_t vmcbp = args[2];
654     capaddr_t ctrlp = args[3];
655
656     // 0. Enable VM extensions
657     err = vmkit_enable_virtualization();
658     if(err != SYS_ERR_OK) {
659         return SYSRET(err);
660     }
661
662     // 1. Check arguments
663     // Monitor endpoint for exits of this geust
664     struct cte *ep_cte;
665
666     err = caps_lookup_slot(&dcb_current->cspace.cap, epp, CPTR_BITS,
667                            &ep_cte, CAPRIGHTS_READ_WRITE);
668     if (err_is_fail(err)) {
669         return SYSRET(err);
670     }
671     if (ep_cte->cap.type != ObjType_EndPoint) {
672         return SYSRET(SYS_ERR_VMKIT_ENDPOINT_INVALID);
673     }
674     err = caps_copy_to_cte(&dcb->guest_desc.monitor_ep, ep_cte, false, 0, 0);
675     if (err_is_fail(err)) {
676         return SYSRET(err_push(err, SYS_ERR_VMKIT_ENDPOINT));
677     }
678
679     // Domain vspace
680     struct capability *vnode_cap;
681     err = caps_lookup_cap(&dcb_current->cspace.cap, vnodep, CPTR_BITS,
682                           &vnode_cap, CAPRIGHTS_WRITE);
683     if (err_is_fail(err)) {
684         return SYSRET(err);
685     }
686     if (vnode_cap->type != ObjType_VNode_x86_64_pml4) {
687         return SYSRET(SYS_ERR_DISP_VSPACE_INVALID);
688     }
689
690     assert(vnode_cap->type == ObjType_VNode_x86_64_pml4);
691
692     // VMCB
693     struct cte *vmcb_cte;
694     err = caps_lookup_slot(&dcb_current->cspace.cap, vmcbp, CPTR_BITS,
695                            &vmcb_cte, CAPRIGHTS_READ_WRITE);
696     if (err_is_fail(err)) {
697         return SYSRET(err);
698     }
699     if (vmcb_cte->cap.type != ObjType_Frame ||
700         vmcb_cte->cap.u.frame.bits < BASE_PAGE_BITS) {
701         return SYSRET(SYS_ERR_VMKIT_VMCB_INVALID);
702     }
703     err = caps_copy_to_cte(&dcb->guest_desc.vmcb, vmcb_cte, false, 0, 0);
704     if (err_is_fail(err)) {
705         return SYSRET(err_push(err, SYS_ERR_VMKIT_VMCB));
706     }
707
708     // guest control
709     struct cte *ctrl_cte;
710     err = caps_lookup_slot(&dcb_current->cspace.cap, ctrlp, CPTR_BITS,
711                            &ctrl_cte, CAPRIGHTS_READ_WRITE);
712     if (err_is_fail(err)) {
713         return SYSRET(err);
714     }
715     if (ctrl_cte->cap.type != ObjType_Frame ||
716         ctrl_cte->cap.u.frame.bits < BASE_PAGE_BITS) {
717         return SYSRET(SYS_ERR_VMKIT_CTRL_INVALID);
718     }
719     err = caps_copy_to_cte(&dcb->guest_desc.ctrl, ctrl_cte, false, 0, 0);
720     if (err_is_fail(err)) {
721         return SYSRET(err_push(err, SYS_ERR_VMKIT_CTRL));
722     }
723
724     // 2. Set up the target DCB
725 /*     dcb->guest_desc.monitor_ep = ep_cap; */
726     dcb->vspace = vnode_cap->u.vnode_x86_64_pml4.base;
727     dcb->is_vm_guest = true;
728 /*     dcb->guest_desc.vmcb = vmcb_cap->u.frame.base; */
729 /*     dcb->guest_desc.ctrl = (void *)x86_64_phys_to_mem(ctrl_cap->u.frame.base); */
730
731     return SYSRET(SYS_ERR_OK);
732 }
733
734 static struct sysret monitor_handle_domain_id(struct capability *monitor_cap,
735                                               int cmd, uintptr_t *args)
736 {
737     capaddr_t cptr = args[0];
738     domainid_t domain_id = args[1];
739
740     return sys_monitor_domain_id(cptr, domain_id);
741 }
742
743 /**
744  * \brief Set up tracing in the kernel
745  */
746 static struct sysret handle_trace_setup(struct capability *cap,
747                                         int cmd, uintptr_t *args)
748 {
749     struct capability *frame;
750     errval_t err;
751
752     /* lookup passed cap */
753     capaddr_t cptr = args[0];
754     err = caps_lookup_cap(&dcb_current->cspace.cap, cptr, CPTR_BITS, &frame,
755                           CAPRIGHTS_READ_WRITE);
756     if (err_is_fail(err)) {
757         return SYSRET(err);
758     }
759
760     lpaddr_t lpaddr = gen_phys_to_local_phys(frame->u.frame.base);
761     kernel_trace_buf = local_phys_to_mem(lpaddr);
762     //printf("kernel.%u: handle_trace_setup at %lx\n", apic_id, kernel_trace_buf);
763
764     // Copy boot applications.
765     trace_copy_boot_applications();
766
767     return SYSRET(SYS_ERR_OK);
768 }
769
770 static struct sysret handle_irq_table_alloc(struct capability *to, int cmd,
771                                             uintptr_t *args)
772 {
773     struct sysret ret;
774     int outvec;
775     ret.error = irq_table_alloc(&outvec);
776     ret.value = outvec;
777     return ret;
778 }
779
780
781 static struct sysret handle_irq_table_set(struct capability *to, int cmd,
782                                           uintptr_t *args)
783 {
784     return SYSRET(irq_table_set(args[0], args[1]));
785 }
786
787 static struct sysret handle_irq_table_delete(struct capability *to, int cmd,
788                                              uintptr_t *args)
789 {
790     return SYSRET(irq_table_delete(args[0]));
791 }
792
793 static struct sysret handle_ipi_notify_send(struct capability *cap,
794                                             int cmd, uintptr_t *args)
795 {
796     assert(cap->type == ObjType_Notify_IPI);
797     return ipi_raise_notify(cap->u.notify_ipi.coreid, cap->u.notify_ipi.chanid);
798 }
799
800 static struct sysret kernel_ipi_register(struct capability *cap,
801                                          int cmd, uintptr_t *args)
802 {
803     assert(cap->type == ObjType_Kernel);
804     capaddr_t ep = args[0];
805     int chanid = args[1];
806     return SYSRET(ipi_register_notification(ep, chanid));
807 }
808
809 static struct sysret kernel_ipi_delete(struct capability *cap,
810                                        int cmd, uintptr_t *args)
811 {
812     assert(cap->type == ObjType_Kernel);
813     assert(!"NYI");
814     return SYSRET(SYS_ERR_OK);
815 }
816
817 static struct sysret dispatcher_dump_ptables(struct capability *cap,
818                                              int cmd, uintptr_t *args)
819 {
820     assert(cap->type == ObjType_Dispatcher);
821
822     printf("kernel_dump_ptables\n");
823
824     struct dcb *dispatcher = cap->u.dispatcher.dcb;
825
826     paging_dump_tables(dispatcher);
827
828     return SYSRET(SYS_ERR_OK);
829 }
830
831 /*
832  * \brief Activate performance monitoring
833  *
834  * Activates performance monitoring.
835  * \param xargs Expected parameters in args:
836  * - performance monitoring type
837  * - mask for given type
838  * - Counter id
839  * - Also count in privileged mode
840  * - Number of counts before overflow. This parameter may be used to
841  *   set tradeoff between accuracy and overhead. Set the counter to 0
842  *   to deactivate the usage of APIC.
843  * - Endpoint capability to be invoked when the counter overflows.
844  *   The buffer associated with the endpoint needs to be large enough
845  *   to hold several overflow notifications depending on the overflow
846  *   frequency.
847  */
848 static struct sysret performance_counter_activate(struct capability *cap,
849                                                   int cmd, uintptr_t *args)
850 {
851     uint8_t event = args[0];
852     uint8_t umask = args[1];
853     uint8_t counter_id = args[2];
854     bool kernel = args[3];
855     uint64_t counter_value = args[4];
856     capaddr_t ep_addr = args[5];
857
858     errval_t err;
859     struct capability *ep;
860     extern struct capability perfmon_callback_ep;
861
862     // Make sure that
863     assert(ep_addr!=0 || counter_value==0);
864
865     perfmon_init();
866     perfmon_measure_start(event, umask, counter_id, kernel, counter_value);
867
868     if(ep_addr!=0) {
869
870         err = caps_lookup_cap(&dcb_current->cspace.cap, ep_addr, CPTR_BITS, &ep,
871                                CAPRIGHTS_READ);
872         if(err_is_fail(err)) {
873             return SYSRET(err);
874         }
875
876         perfmon_callback_ep = *ep;
877     }
878
879     return SYSRET(SYS_ERR_OK);
880 }
881
882 /*
883  * \brief Write counter values.
884  */
885 static struct sysret performance_counter_write(struct capability *cap,
886                                                int cmd, uintptr_t *args)
887 {
888     uint8_t counter_id = args[0];
889     uint64_t counter_value = args[1];
890
891     perfmon_measure_write(counter_id, counter_value);
892     return SYSRET(SYS_ERR_OK);
893 }
894
895 /*
896  * \brief Deactivate performance counters again.
897  */
898 static struct sysret performance_counter_deactivate(struct capability *cap,
899                                                   int cmd, uintptr_t *args)
900 {
901     perfmon_measure_stop();
902     return SYSRET(SYS_ERR_OK);
903 }
904
905 /*
906  * \brief Return system-wide unique ID of this ID cap.
907  */
908 static struct sysret handle_idcap_identify(struct capability *cap, int cmd,
909                                            uintptr_t *args)
910 {
911     idcap_id_t id;
912     struct sysret sysret = sys_idcap_identify(cap, &id);
913     sysret.value = id;
914
915     return sysret;
916 }
917
918 static struct sysret kernel_send_init_ipi(struct capability *cap, int cmd,
919                                           uintptr_t *args)
920 {
921     coreid_t destination = args[0];
922     printk(LOG_DEBUG, "%s:%s:%d: destination=%"PRIuCOREID"\n",
923            __FILE__, __FUNCTION__, __LINE__, destination);
924
925     apic_send_init_assert(destination, xapic_none);
926     apic_send_init_deassert();
927
928     return SYSRET(SYS_ERR_OK);
929 }
930
931 static struct sysret kernel_send_start_ipi(struct capability *cap,
932                                            int cmd,
933                                            uintptr_t *args)
934 {
935     coreid_t destination = args[0];
936     genvaddr_t start_vector = X86_64_REAL_MODE_SEGMENT_TO_REAL_MODE_PAGE(X86_64_REAL_MODE_SEGMENT);
937     printk(LOG_DEBUG, "%s:%d: destination=%"PRIuCOREID" start_vector=%"PRIxGENVADDR"\n",
938            __FILE__, __LINE__, destination, start_vector);
939
940     apic_send_start_up(destination, xapic_none, start_vector);
941
942     return SYSRET(SYS_ERR_OK);
943 }
944
945 static struct sysret kernel_get_global_phys(struct capability *cap,
946                                            int cmd,
947                                            uintptr_t *args)
948 {
949
950     struct sysret sysret;
951     sysret.value = mem_to_local_phys((lvaddr_t)global);
952     sysret.error = SYS_ERR_OK;
953
954     return sysret;
955 }
956
957 typedef struct sysret (*invocation_handler_t)(struct capability *to,
958                                               int cmd, uintptr_t *args);
959
960 static invocation_handler_t invocations[ObjType_Num][CAP_MAX_CMD] = {
961     [ObjType_Dispatcher] = {
962         [DispatcherCmd_Setup] = handle_dispatcher_setup,
963         [DispatcherCmd_Properties] = handle_dispatcher_properties,
964         [DispatcherCmd_SetupGuest] = handle_dispatcher_setup_guest,
965         [DispatcherCmd_DumpPTables]  = dispatcher_dump_ptables,
966     },
967     [ObjType_KernelControlBlock] = {
968         [FrameCmd_Identify] = handle_kcb_identify,
969     },
970     [ObjType_Frame] = {
971         [FrameCmd_Identify] = handle_frame_identify,
972         [FrameCmd_ModifyFlags] = handle_frame_modify_flags,
973     },
974     [ObjType_DevFrame] = {
975         [FrameCmd_Identify] = handle_frame_identify,
976         [FrameCmd_ModifyFlags] = handle_frame_modify_flags,
977     },
978     [ObjType_CNode] = {
979         [CNodeCmd_Copy]   = handle_copy,
980         [CNodeCmd_Mint]   = handle_mint,
981         [CNodeCmd_Retype] = handle_retype,
982         [CNodeCmd_Create] = handle_create,
983         [CNodeCmd_Delete] = handle_delete,
984         [CNodeCmd_Revoke] = handle_revoke,
985     },
986     [ObjType_VNode_x86_64_pml4] = {
987         [VNodeCmd_Map]   = handle_map,
988         [VNodeCmd_Unmap] = handle_unmap,
989     },
990     [ObjType_VNode_x86_64_pdpt] = {
991         [VNodeCmd_Map]   = handle_map,
992         [VNodeCmd_Unmap] = handle_unmap,
993     },
994     [ObjType_VNode_x86_64_pdir] = {
995         [VNodeCmd_Map]   = handle_map,
996         [VNodeCmd_Unmap] = handle_unmap,
997     },
998     [ObjType_VNode_x86_64_ptable] = {
999         [VNodeCmd_Map]   = handle_map,
1000         [VNodeCmd_Unmap] = handle_unmap,
1001     },
1002     [ObjType_Kernel] = {
1003         [KernelCmd_Stop_core]    = monitor_stop_core,
1004         [KernelCmd_Spawn_core]   = monitor_spawn_core,
1005         [KernelCmd_Get_core_id]  = monitor_get_core_id,
1006         [KernelCmd_Get_arch_id]  = monitor_get_arch_id,
1007         [KernelCmd_Identify_cap] = monitor_identify_cap,
1008         [KernelCmd_Identify_domains_cap] = monitor_identify_domains_cap,
1009         [KernelCmd_Remote_cap]   = monitor_remote_cap,
1010         [KernelCmd_Iden_cnode_get_cap] = monitor_iden_cnode_get_cap,
1011         [KernelCmd_Create_cap]   = monitor_create_cap,
1012         [KernelCmd_Nullify_cap]  = monitor_nullify_cap,
1013         [KernelCmd_Setup_trace]  = handle_trace_setup,
1014         [KernelCmd_Register]     = monitor_handle_register,
1015         [KernelCmd_Domain_Id]    = monitor_handle_domain_id,
1016         [MonitorCmd_Retype]      = monitor_handle_retype,
1017         [MonitorCmd_Delete]      = monitor_handle_delete,
1018         [MonitorCmd_Revoke]      = monitor_handle_revoke,
1019         [KernelCmd_Sync_timer]   = monitor_handle_sync_timer,
1020         [KernelCmd_IPI_Register] = kernel_ipi_register,
1021         [KernelCmd_IPI_Delete]   = kernel_ipi_delete,
1022         [KernelCmd_Start_IPI_Send] = kernel_send_start_ipi,
1023         [KernelCmd_Init_IPI_Send] = kernel_send_init_ipi,
1024         [KernelCmd_GetGlobalPhys] = kernel_get_global_phys,
1025         [KernelCmd_StartCore] = kernel_start_core,
1026         [KernelCmd_Add_kcb]      = kernel_add_kcb,
1027         [KernelCmd_Remove_kcb]   = kernel_remove_kcb,
1028         [KernelCmd_Suspend_kcb_sched]   = kernel_suspend_kcb_sched,
1029     },
1030     [ObjType_IRQTable] = {
1031         [IRQTableCmd_Alloc] = handle_irq_table_alloc,
1032         [IRQTableCmd_Set] = handle_irq_table_set,
1033         [IRQTableCmd_Delete] = handle_irq_table_delete
1034     },
1035     [ObjType_IO] = {
1036         [IOCmd_Outb] = handle_io,
1037         [IOCmd_Outw] = handle_io,
1038         [IOCmd_Outd] = handle_io,
1039         [IOCmd_Inb] = handle_io,
1040         [IOCmd_Inw] = handle_io,
1041         [IOCmd_Ind] = handle_io
1042     },
1043     [ObjType_Notify_IPI] = {
1044         [NotifyCmd_Send] = handle_ipi_notify_send
1045     },
1046     [ObjType_PerfMon] = {
1047         [PerfmonCmd_Activate] = performance_counter_activate,
1048         [PerfmonCmd_Deactivate] = performance_counter_deactivate,
1049         [PerfmonCmd_Write] = performance_counter_write,
1050     },
1051     [ObjType_ID] = {
1052         [IDCmd_Identify] = handle_idcap_identify,
1053     }
1054 };
1055
1056 /* syscall C entry point; called only from entry.S so no prototype in header */
1057 struct sysret sys_syscall(uint64_t syscall, uint64_t arg0, uint64_t arg1,
1058                           uint64_t *args, uint64_t rflags, uint64_t rip);
1059 struct sysret sys_syscall(uint64_t syscall, uint64_t arg0, uint64_t arg1,
1060                           uint64_t *args, uint64_t rflags, uint64_t rip)
1061 {
1062     struct sysret retval = { .error = SYS_ERR_OK, .value = 0 };
1063
1064     switch(syscall) {
1065     case SYSCALL_INVOKE: /* Handle capability invocation */
1066     {
1067         // unpack "header" word
1068         capaddr_t invoke_cptr = arg0 >> 32;
1069         uint8_t send_bits = arg0 >> 24;
1070         uint8_t invoke_bits = arg0 >> 16;
1071         uint8_t length_words = arg0 >> 8;
1072         uint8_t flags = arg0;
1073
1074         debug(SUBSYS_SYSCALL, "sys_invoke(0x%x(%d), 0x%lx)\n",
1075               invoke_cptr, invoke_bits, arg1);
1076
1077         // Capability to invoke
1078         struct capability *to = NULL;
1079         retval.error = caps_lookup_cap(&dcb_current->cspace.cap, invoke_cptr,
1080                                        invoke_bits, &to, CAPRIGHTS_READ);
1081         if (err_is_fail(retval.error)) {
1082             break;
1083         }
1084
1085         assert(to != NULL);
1086         assert(to->type < ObjType_Num);
1087
1088         // Endpoint cap, do LMP
1089         if (to->type == ObjType_EndPoint) {
1090             struct dcb *listener = to->u.endpoint.listener;
1091             assert(listener != NULL);
1092
1093             if (listener->disp == 0) {
1094                 retval.error = SYS_ERR_LMP_NO_TARGET;
1095                 break;
1096             }
1097
1098             /* limit length of message from buggy/malicious sender */
1099             length_words = MIN(length_words, LMP_MSG_LENGTH);
1100
1101             // does the sender want to yield their timeslice on success?
1102             bool sync = flags & LMP_FLAG_SYNC;
1103             // does the sender want to yield to the target if undeliverable?
1104             bool yield = flags & LMP_FLAG_YIELD;
1105
1106             // try to deliver message
1107             retval.error = lmp_deliver(to, dcb_current, args, length_words,
1108                                        arg1, send_bits);
1109
1110             /* Switch to reciever upon successful delivery with sync flag,
1111              * or (some cases of) unsuccessful delivery with yield flag */
1112             enum err_code err_code = err_no(retval.error);
1113             if ((sync && err_is_ok(retval.error)) ||
1114                 (yield && (err_code == SYS_ERR_LMP_BUF_OVERFLOW
1115                            || err_code == SYS_ERR_LMP_CAPTRANSFER_DST_CNODE_LOOKUP
1116                            || err_code == SYS_ERR_LMP_CAPTRANSFER_DST_CNODE_INVALID
1117                            || err_code == SYS_ERR_LMP_CAPTRANSFER_DST_SLOT_OCCUPIED))
1118                     ) {
1119                 if (err_is_fail(retval.error)) {
1120                     struct dispatcher_shared_generic *current_disp =
1121                         get_dispatcher_shared_generic(dcb_current->disp);
1122                     struct dispatcher_shared_generic *listener_disp =
1123                         get_dispatcher_shared_generic(listener->disp);
1124                     debug(SUBSYS_DISPATCH, "LMP failed; %.*s yields to %.*s: %u\n",
1125                           DISP_NAME_LEN, current_disp->name,
1126                           DISP_NAME_LEN, listener_disp->name, err_code);
1127                 }
1128
1129                 // special-case context switch: ensure correct state in current DCB
1130                 dispatcher_handle_t handle = dcb_current->disp;
1131                 struct dispatcher_shared_x86_64 *disp =
1132                     get_dispatcher_shared_x86_64(handle);
1133                 dcb_current->disabled = dispatcher_is_disabled_ip(handle, rip);
1134                 struct registers_x86_64 *save_area;
1135                 if (dcb_current->disabled) {
1136                     save_area = &disp->disabled_save_area;
1137                 } else {
1138                     save_area = &disp->enabled_save_area;
1139                 }
1140
1141                 // save calling dispatcher's registers, so that when the dispatcher
1142                 // next runs, it has a valid state in the relevant save area.
1143                 // Save RIP, RFLAGS, RSP and set RAX (return value) for later resume
1144                 save_area->rax = retval.error; // XXX: x86 1st return register
1145                 save_area->rip = rip;
1146                 save_area->eflags = rflags;
1147                 save_area->rsp = user_stack_save;
1148
1149                 /* save and zero FS/GS selectors (they're unmodified by the syscall path) */
1150                 __asm ("mov     %%fs, %[fs]     \n\t"
1151                        "mov     %%gs, %[gs]     \n\t"
1152                        "mov     %[zero], %%fs   \n\t"
1153                        "mov     %[zero], %%gs   \n\t"
1154                        : /* No output */
1155                        :
1156                        [fs] "m" (save_area->fs),
1157                        [gs] "m" (save_area->gs),
1158                        [zero] "r" (0)
1159                        );
1160
1161                 dispatch(to->u.endpoint.listener);
1162                 panic("dispatch returned");
1163             }
1164         } else { // not endpoint cap, call kernel handler through dispatch table
1165             uint64_t cmd = args[0];
1166             if (cmd >= CAP_MAX_CMD) {
1167                 retval.error = SYS_ERR_ILLEGAL_INVOCATION;
1168                 break;
1169             }
1170
1171             // Call the invocation
1172             invocation_handler_t invocation = invocations[to->type][cmd];
1173             if(invocation == NULL) {
1174                 retval.error = SYS_ERR_ILLEGAL_INVOCATION;
1175             } else {
1176                 retval = invocation(to, cmd, &args[1]);
1177             }
1178         }
1179         break;
1180     }
1181
1182         // Yield the CPU to the next dispatcher
1183     case SYSCALL_YIELD:
1184         TRACE(KERNEL, SC_YIELD, 0);
1185         retval = sys_yield((capaddr_t)arg0);
1186         TRACE(KERNEL, SC_YIELD, 1);
1187         break;
1188
1189         // NOP system call for benchmarking purposes
1190     case SYSCALL_NOP:
1191         break;
1192
1193         // Debug print system call
1194     case SYSCALL_PRINT:
1195         TRACE(KERNEL, SC_PRINT, 0);
1196         retval.error = sys_print((char *)arg0, arg1);
1197         TRACE(KERNEL, SC_PRINT, 1);
1198         break;
1199
1200         // Reboot!
1201         // FIXME: this should be a kernel cap invocation or similarly restricted
1202     case SYSCALL_REBOOT:
1203         reboot();
1204         break;
1205
1206     case SYSCALL_X86_FPU_TRAP_ON:
1207         fpu_trap_on();
1208         break;
1209
1210     case SYSCALL_X86_RELOAD_LDT:
1211         maybe_reload_ldt(dcb_current, true);
1212         break;
1213
1214         // Temporarily suspend the CPU
1215     case SYSCALL_SUSPEND:
1216         TRACE(KERNEL, SC_SUSPEND, 0);
1217         retval = sys_suspend((bool)arg0);
1218         TRACE(KERNEL, SC_SUSPEND, 1);
1219         break;
1220
1221     case SYSCALL_DEBUG:
1222         switch(arg0) {
1223         case DEBUG_CONTEXT_COUNTER_RESET:
1224             dispatch_csc_reset();
1225             break;
1226
1227         case DEBUG_CONTEXT_COUNTER_READ:
1228             retval.value = dispatch_get_csc();
1229             break;
1230
1231         case DEBUG_TIMESLICE_COUNTER_READ:
1232             retval.value = kernel_now;
1233             break;
1234
1235         case DEBUG_FLUSH_CACHE:
1236             wbinvd();
1237             break;
1238
1239         case DEBUG_SEND_IPI:
1240             apic_send_std_ipi(arg1, args[0], args[1]);
1241             break;
1242
1243         case DEBUG_SET_BREAKPOINT:
1244             debugregs_set_breakpoint(arg1, args[0], args[1]);
1245             break;
1246
1247         case DEBUG_GET_TSC_PER_MS:
1248             retval.value = timing_get_tsc_per_ms();
1249             break;
1250
1251         case DEBUG_GET_APIC_TIMER:
1252             retval.value = apic_timer_get_count();
1253             break;
1254
1255         case DEBUG_GET_APIC_TICKS_PER_SEC:
1256             retval.value = timing_get_apic_ticks_per_sec();
1257             break;
1258
1259         default:
1260             printk(LOG_ERR, "invalid sys_debug msg type\n");
1261         }
1262         break;
1263
1264     default:
1265         printk(LOG_ERR, "sys_syscall: Illegal system call! "
1266                "(0x%lx, 0x%lx, 0x%lx)\n", syscall, arg0, arg1);
1267         retval.error = SYS_ERR_ILLEGAL_SYSCALL;
1268         break;
1269     }
1270
1271     // If dcb_current got removed, dispatch someone else
1272     if (dcb_current == NULL) {
1273         assert(err_is_ok(retval.error));
1274         dispatch(schedule());
1275     }
1276
1277     if (syscall == SYSCALL_INVOKE) {
1278         debug(SUBSYS_SYSCALL, "invoke returning 0x%lx 0x%lx\n",
1279               retval.error, retval.value);
1280     }
1281
1282     return retval;
1283 }