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