1/*
2 * Copyright (c) 2009,2011,2015, ETH Zurich.
3 * Copyright (c) 2015, Hewlett Packard Enterprise Development LP.
4 * All rights reserved.
5 *
6 * This file is distributed under the terms in the attached LICENSE file.
7 * If you do not find this file, copies can be found by writing to:
8 * ETH Zurich D-INFK, Universitaetstr. 6, CH-8092 Zurich. Attn: Systems Group.
9 */
10
11#include <kernel.h>
12
13#include <barrelfish_kpi/lmp.h>
14#include <barrelfish_kpi/syscalls.h>
15#include <barrelfish_kpi/sys_debug.h>
16#include <barrelfish_kpi/platform.h>
17#include <mdb/mdb_tree.h>
18
19#include <arm_hal.h>
20#include <irq.h>
21
22#include <paging_kernel_arch.h>
23#include <dispatch.h>
24#include <exec.h>
25#include <stdio.h>
26#include <sys_debug.h>
27#include <syscall.h>
28#include <arch/arm/syscall_arm.h>
29#include <start_aps.h>
30#include <useraccess.h>
31#include <platform.h>
32#include <systime.h>
33#include <timers.h>
34#include <psci.h>
35#include <arch/armv8/gic_v3.h>
36
37// helper macros  for invocation handler definitions
38#define INVOCATION_HANDLER(func) \
39static struct sysret \
40func( \
41    struct capability *kernel_cap, \
42    arch_registers_state_t* context, \
43    int argc \
44    )
45
46#define INVOCATION_PRELUDE(n) \
47    assert(n == argc); \
48    struct registers_aarch64_syscall_args* sa = &context->syscall_args
49
50#define NYI(str) printf("armv8: %s\n", str)
51
52__attribute__((noreturn)) void sys_syscall_kernel(void);
53__attribute__((noreturn))
54void sys_syscall(uint64_t a0, uint64_t a1, uint64_t a2, uint64_t a3,
55                 uint64_t a4, uint64_t a5, uint64_t a6,
56                 arch_registers_state_t *context);
57
58__attribute__((noreturn))
59void sys_syscall_kernel(void)
60{
61    panic("Why is the kernel making a system call?");
62}
63
64static struct sysret
65handle_dispatcher_setup(
66    struct capability* to,
67    arch_registers_state_t* context,
68    int argc
69    )
70{
71    assert(8 == argc);
72
73    struct registers_aarch64_syscall_args* sa = &context->syscall_args;
74
75    capaddr_t root  = sa->arg2;
76    uint8_t   level = sa->arg3;
77    capaddr_t vptr  = sa->arg4;
78    capaddr_t dptr  = sa->arg5;
79    bool      run   = sa->arg6;
80    capaddr_t odptr = sa->arg7;
81
82    return sys_dispatcher_setup(to, root, level, vptr, dptr, run, odptr);
83}
84
85static struct sysret
86handle_dispatcher_properties(
87    struct capability* to,
88    arch_registers_state_t* context,
89    int argc
90    )
91{
92    assert(8 == argc);
93
94    struct registers_aarch64_syscall_args* sa = &context->syscall_args;
95
96    enum task_type type = (enum task_type)(sa->arg3 >> 16);
97    uint16_t weight = sa->arg3 & 0xffff;
98
99    return sys_dispatcher_properties(to, type, sa->arg4,
100                                     sa->arg5, sa->arg6, sa->arg7, weight);
101}
102
103static struct sysret
104handle_dispatcher_perfmon(
105    struct capability* to,
106    arch_registers_state_t* context,
107    int argc
108    )
109{
110    /* XXX - implement this? */
111    return SYSRET(SYS_ERR_PERFMON_NOT_AVAILABLE);
112}
113
114static struct sysret
115handle_frame_identify(
116    struct capability* to,
117    arch_registers_state_t* context,
118    int argc
119    )
120{
121    assert(3 == argc);
122
123    struct registers_aarch64_syscall_args* sa = &context->syscall_args;
124
125    assert(to->type == ObjType_Frame || to->type == ObjType_DevFrame || to->type == ObjType_RAM);
126    assert((get_address(to) & BASE_PAGE_MASK) == 0);
127
128    struct frame_identity *fi = (struct frame_identity *)sa->arg2;
129
130    if (!access_ok(ACCESS_WRITE, (lvaddr_t)fi, sizeof(struct frame_identity))) {
131        return SYSRET(SYS_ERR_INVALID_USER_BUFFER);
132    }
133
134    fi->base = get_address(to);
135    fi->bytes = get_size(to);
136
137    return SYSRET(SYS_ERR_OK);
138}
139
140static struct sysret copy_or_mint(struct capability *root,
141                                  struct registers_aarch64_syscall_args* args,
142                                  bool mint)
143{
144    /* Retrieve arguments */
145    capaddr_t dest_cspace_cptr = args->arg2;
146    capaddr_t destcn_cptr      = args->arg3;
147    uint64_t  dest_slot        = args->arg4;
148    capaddr_t source_croot_ptr = args->arg5;
149    capaddr_t source_cptr      = args->arg6;
150    uint8_t destcn_level       = args->arg7;
151    uint8_t source_level       = args->x8;
152    uint64_t param1, param2;
153    // params only sent if mint operation
154    if (mint) {
155        param1 = args->x9;
156        param2 = args->x10;
157    } else {
158        param1 = param2 = 0;
159    }
160
161    struct sysret sr = sys_copy_or_mint(root, dest_cspace_cptr, destcn_cptr, dest_slot,
162                                        source_croot_ptr, source_cptr,
163                                        destcn_level, source_level,
164                                        param1, param2, mint);
165    return sr;
166}
167
168static struct sysret
169handle_mint(
170    struct capability* root,
171    arch_registers_state_t* context,
172    int argc
173    )
174{
175    assert(11 == argc);
176
177    return copy_or_mint(root, &context->syscall_args, true);
178}
179
180static struct sysret
181handle_copy(
182    struct capability* root,
183    arch_registers_state_t* context,
184    int argc
185    )
186{
187    assert(9 == argc);
188
189    return copy_or_mint(root, &context->syscall_args, false);
190}
191
192static struct sysret
193handle_retype_common(
194    struct capability* root,
195    bool from_monitor,
196    arch_registers_state_t* context,
197    int argc
198    )
199{
200    assert(11 == argc);
201
202    struct registers_aarch64_syscall_args* sa = &context->syscall_args;
203
204    // Source capability cptr
205    capaddr_t source_croot     = sa->arg2;
206    capaddr_t source_cptr      = sa->arg3;
207    gensize_t offset           = sa->arg4;
208    uint32_t word              = sa->arg5;
209    // Type to retype to
210    enum objtype type          = word & 0xFFFF;
211    assert(type < ObjType_Num);
212    // Object size for variable-sized types
213    gensize_t objsize          = sa->arg6;
214    // number of new objects
215    size_t count               = sa->arg7;
216    // Destination cspace cptr
217    capaddr_t dest_cspace_cptr = sa->x8;
218    // Destination cnode cptr
219    capaddr_t dest_cnode_cptr  = sa->x9;
220    // Destination slot number
221    capaddr_t dest_slot        = sa->x10;
222    // Level of destination cnode in destination cspace
223    uint8_t dest_cnode_level   = (word >> 16) & 0xF;
224
225    return sys_retype(root, source_croot, source_cptr, offset, type,
226                      objsize, count, dest_cspace_cptr, dest_cnode_cptr,
227                      dest_cnode_level, dest_slot, from_monitor);
228}
229
230static struct sysret
231handle_retype(
232    struct capability* root,
233    arch_registers_state_t* context,
234    int argc
235    )
236{
237    return handle_retype_common(root, false, context, argc);
238}
239
240static struct sysret
241handle_delete(
242    struct capability* root,
243    arch_registers_state_t* context,
244    int argc
245    )
246{
247    assert(4 == argc);
248
249    struct registers_aarch64_syscall_args* sa = &context->syscall_args;
250
251    capaddr_t cptr = (capaddr_t)sa->arg2;
252    int     bits = (int)sa->arg3;
253
254    return sys_delete(root, cptr, bits);
255}
256
257static struct sysret
258handle_create(
259    struct capability* root,
260    arch_registers_state_t* context,
261    int argc
262    )
263{
264    assert(7 == argc);
265
266    struct registers_aarch64_syscall_args* sa = &context->syscall_args;
267
268    enum objtype type      = sa->arg2;
269    size_t       objsize   = sa->arg3;
270    capaddr_t    dest_cptr = sa->arg4;
271    uint8_t      dest_level= sa->arg5;
272    cslot_t      dest_slot = sa->arg6;
273    printk(LOG_NOTE, "type = %d, bytes = %zu\n", type, objsize);
274
275    return sys_create(root, type, objsize, dest_cptr, dest_level, dest_slot);
276}
277
278static struct sysret
279handle_revoke(
280    struct capability* root,
281    arch_registers_state_t* context,
282    int argc
283    )
284{
285    assert(4 == argc);
286
287    struct registers_aarch64_syscall_args* sa = &context->syscall_args;
288
289    capaddr_t cptr = (capaddr_t)sa->arg2;
290    int     bits = (int)sa->arg3;
291
292    return sys_revoke(root, cptr, bits);
293}
294
295static struct sysret
296handle_get_state(
297    struct capability* root,
298    arch_registers_state_t* context,
299    int argc
300    )
301{
302    assert(4 == argc);
303
304    struct registers_aarch64_syscall_args* sa = &context->syscall_args;
305
306    capaddr_t cptr = (capaddr_t)sa->arg2;
307    int       bits = (int)sa->arg3;
308
309    return sys_get_state(root, cptr, bits);
310}
311
312static struct sysret
313handle_get_size(
314    struct capability* root,
315    arch_registers_state_t* context,
316    int argc
317    )
318{
319    assert(2 == argc);
320    return sys_get_size_l1cnode(root);
321}
322
323static struct sysret
324handle_resize(
325    struct capability* root,
326    arch_registers_state_t* context,
327    int argc
328    )
329{
330    INVOCATION_PRELUDE(5);
331
332    capaddr_t newroot_ptr = sa->arg2;
333    capaddr_t retcn_ptr   = sa->arg3;
334    cslot_t   retslot     = sa->arg4;
335
336    return sys_resize_l1cnode(root, newroot_ptr, retcn_ptr, retslot);
337}
338
339static struct sysret
340handle_map(
341    struct capability *ptable,
342    arch_registers_state_t *context,
343    int argc
344    )
345{
346    assert(10 == argc);
347
348    struct registers_aarch64_syscall_args* sa = &context->syscall_args;
349
350    /* Retrieve arguments */
351    capaddr_t source_root_cptr = (capaddr_t)sa->arg2;
352    capaddr_t source_cptr      = (capaddr_t)sa->arg3;
353    uintptr_t flags            = (uintptr_t)sa->arg4;
354    uintptr_t offset           = (uintptr_t)sa->arg5;
355    uintptr_t pte_count        = (uintptr_t)sa->arg6;
356    capaddr_t mcn_root         = (capaddr_t)sa->arg7;
357    capaddr_t mcn_addr         = (capaddr_t)sa->x8;
358    uint32_t  word             = sa->x9;
359    uint8_t   source_level     = word & 0xF;
360    uint8_t   mcn_level        = (word >> 4) & 0xF;
361    cslot_t   mapping_slot     = (word >> 8) & 0xFF;
362    cslot_t   slot             = (word >> 16) & 0xFFFF;
363
364    return sys_map(ptable, slot, source_root_cptr, source_cptr, source_level,
365                   flags, offset, pte_count, mcn_root, mcn_addr, mcn_level,
366                   mapping_slot);
367}
368
369static struct sysret
370handle_unmap(
371    struct capability* ptable,
372    arch_registers_state_t* context,
373    int argc
374    )
375{
376    assert(4 == argc);
377
378    struct registers_aarch64_syscall_args* sa = &context->syscall_args;
379
380    /* Retrieve arguments */
381    capaddr_t  mapping_cptr  = (capaddr_t)sa->arg2;
382    int mapping_bits         = (int)sa->arg3 & 0xff;
383
384    errval_t err;
385    struct cte *mapping = NULL;
386    err = caps_lookup_slot(&dcb_current->cspace.cap, mapping_cptr, mapping_bits,
387                           &mapping, CAPRIGHTS_READ_WRITE);
388    if (err_is_fail(err)) {
389        printk(LOG_NOTE, "%s: caps_lookup_slot: %ld\n", __FUNCTION__, err);
390        return SYSRET(err_push(err, SYS_ERR_CAP_NOT_FOUND));
391    }
392
393    err = page_mappings_unmap(ptable, mapping);
394    if (err_is_fail(err)) {
395        printk(LOG_NOTE, "%s: page_mappings_unmap: %ld\n", __FUNCTION__, err);
396    }
397    return SYSRET(err);
398}
399
400static struct sysret
401handle_mapping_destroy(
402        struct capability *to,
403        arch_registers_state_t *context,
404        int argc)
405{
406    panic("NYI!");
407    return SYSRET(SYS_ERR_OK);
408}
409
410static struct sysret
411handle_mapping_modify(
412        struct capability *to,
413        arch_registers_state_t *context,
414        int argc
415        )
416{
417    assert(5 == argc);
418    struct registers_aarch64_syscall_args* sa = &context->syscall_args;
419
420    // Modify flags of (part of) mapped region of frame
421    assert(type_is_mapping(to->type));
422
423    // unpack arguments
424    size_t offset = sa->arg2; // in pages; of first page to modify from first
425                             // page in mapped region
426    size_t pages  = sa->arg3; // #pages to modify
427    size_t flags  = sa->arg4; // new flags
428
429    errval_t err = paging_modify_flags(to, offset, pages, flags);
430
431    return (struct sysret) {
432        .error = err,
433        .value = 0,
434    };
435}
436
437/// Different handler for cap operations performed by the monitor
438INVOCATION_HANDLER(monitor_handle_retype)
439{
440    assert(argc == 11);
441    return handle_retype_common(&dcb_current->cspace.cap, true, context, argc);
442}
443
444INVOCATION_HANDLER(monitor_handle_has_descendants)
445{
446    INVOCATION_PRELUDE(3);
447    // check access to user pointer
448    if (!access_ok(ACCESS_READ, sa->arg2, sizeof(struct capability))) {
449        return SYSRET(SYS_ERR_INVALID_USER_BUFFER);
450    }
451
452    struct capability *src = (struct capability *)sa->arg2;
453
454    struct cte *next = mdb_find_greater(src, false);
455
456    return (struct sysret) {
457        .error = SYS_ERR_OK,
458        .value = (next && is_ancestor(&next->cap, src)),
459    };
460}
461
462INVOCATION_HANDLER(monitor_handle_delete_last)
463{
464    INVOCATION_PRELUDE(9);
465    capaddr_t root_caddr   = sa->arg2;
466    uint8_t   root_level   = sa->arg3;
467    capaddr_t target_caddr = sa->arg4;
468    uint8_t   target_level = sa->arg5;
469    capaddr_t retcn_caddr  = sa->arg6;
470    uint8_t retcn_level    = sa->arg7;
471    cslot_t retcn_slot     = sa->x8;
472
473    return sys_monitor_delete_last(root_caddr, root_level, target_caddr,
474                                   target_level, retcn_caddr, retcn_level, retcn_slot);
475}
476
477INVOCATION_HANDLER(monitor_handle_delete_foreigns)
478{
479    INVOCATION_PRELUDE(4);
480    capaddr_t caddr = sa->arg2;
481    uint8_t bits = sa->arg3;
482    return sys_monitor_delete_foreigns(caddr, bits);
483}
484
485INVOCATION_HANDLER(monitor_handle_revoke_mark_tgt)
486{
487    INVOCATION_PRELUDE(6);
488    capaddr_t root_caddr   = sa->arg2;
489    uint8_t root_vbits     = sa->arg3;
490    capaddr_t target_caddr = sa->arg4;
491    uint8_t target_vbits   = sa->arg5;
492
493    return sys_monitor_revoke_mark_tgt(root_caddr, root_vbits,
494                                       target_caddr, target_vbits);
495}
496
497INVOCATION_HANDLER(monitor_handle_revoke_mark_rels)
498{
499    INVOCATION_PRELUDE(3);
500    // user pointer to src cap, check access
501    if (!access_ok(ACCESS_READ, sa->arg2, sizeof(struct capability))) {
502        return SYSRET(SYS_ERR_INVALID_USER_BUFFER);
503    }
504    struct capability *base = (struct capability*)sa->arg2;
505
506    return sys_monitor_revoke_mark_rels(base);
507}
508
509INVOCATION_HANDLER(monitor_handle_delete_step)
510{
511    INVOCATION_PRELUDE(5);
512    capaddr_t ret_cn_addr = sa->arg2;
513    capaddr_t ret_cn_bits = sa->arg3;
514    capaddr_t ret_slot    = sa->arg4;
515
516    return sys_monitor_delete_step(ret_cn_addr, ret_cn_bits, ret_slot);
517}
518
519INVOCATION_HANDLER(monitor_handle_clear_step)
520{
521    INVOCATION_PRELUDE(5);
522    capaddr_t ret_cn_addr = sa->arg2;
523    capaddr_t ret_cn_bits = sa->arg3;
524    capaddr_t ret_slot    = sa->arg4;
525
526    return sys_monitor_clear_step(ret_cn_addr, ret_cn_bits, ret_slot);
527}
528
529
530static struct sysret
531monitor_get_core_id(
532    struct capability* to,
533    arch_registers_state_t* context,
534    int argc
535    )
536{
537    assert(2 == argc);
538
539    return (struct sysret) { .error = SYS_ERR_OK, .value = my_core_id };
540}
541
542static struct sysret
543monitor_get_arch_id(
544    struct capability* to,
545    arch_registers_state_t* context,
546    int argc
547    )
548{
549    assert(2 == argc);
550
551    // TODO: ARM doesn't support multicore yet...
552    return (struct sysret) { .error = SYS_ERR_OK, .value = my_core_id };
553}
554
555INVOCATION_HANDLER(monitor_handle_domain_id)
556{
557    INVOCATION_PRELUDE(4);
558    capaddr_t cptr       = sa->arg2;
559    domainid_t domain_id = sa->arg3;
560
561    return sys_monitor_domain_id(cptr, domain_id);
562}
563
564INVOCATION_HANDLER(monitor_get_cap_owner)
565{
566    INVOCATION_PRELUDE(6);
567    capaddr_t root_addr = sa->arg2;
568    uint8_t root_bits   = sa->arg3;
569    capaddr_t cptr      = sa->arg4;
570    uint8_t bits        = sa->arg5;
571
572    return sys_get_cap_owner(root_addr, root_bits, cptr, bits);
573}
574
575INVOCATION_HANDLER(monitor_set_cap_owner)
576{
577    INVOCATION_PRELUDE(7);
578    capaddr_t root_addr = sa->arg2;
579    uint8_t root_bits   = sa->arg3;
580    capaddr_t cptr      = sa->arg4;
581    uint8_t bits        = sa->arg5;
582    coreid_t owner      = sa->arg6;
583
584    return sys_set_cap_owner(root_addr, root_bits, cptr, bits, owner);
585}
586
587INVOCATION_HANDLER(monitor_lock_cap)
588{
589    INVOCATION_PRELUDE(6);
590    capaddr_t root_addr = sa->arg2;
591    uint8_t root_bits   = sa->arg3;
592    capaddr_t cptr      = sa->arg4;
593    uint8_t bits        = sa->arg5;
594
595    return sys_lock_cap(root_addr, root_bits, cptr, bits);
596}
597
598INVOCATION_HANDLER(monitor_unlock_cap)
599{
600    INVOCATION_PRELUDE(6);
601    capaddr_t root_addr = sa->arg2;
602    uint8_t root_bits   = sa->arg3;
603    capaddr_t cptr      = sa->arg4;
604    uint8_t bits        = sa->arg5;
605
606    return sys_unlock_cap(root_addr, root_bits, cptr, bits);
607}
608
609static struct sysret
610monitor_handle_register(
611    struct capability* to,
612    arch_registers_state_t* context,
613    int argc
614    )
615{
616    assert(3 == argc);
617
618    struct registers_aarch64_syscall_args* sa = &context->syscall_args;
619
620    capaddr_t ep_caddr = (capaddr_t)sa->arg2;
621
622    return sys_monitor_register(ep_caddr);
623}
624
625INVOCATION_HANDLER(monitor_cap_has_relations)
626{
627    INVOCATION_PRELUDE(5);
628    capaddr_t caddr = sa->arg2;
629    uint8_t vbits = sa->arg3;
630    uint8_t mask = sa->arg4;
631
632    return sys_cap_has_relations(caddr, vbits, mask);
633}
634
635INVOCATION_HANDLER(monitor_remote_relations)
636{
637    INVOCATION_PRELUDE(7);
638    capaddr_t root_addr = sa->arg2;
639    int root_bits       = sa->arg3;
640    capaddr_t cptr      = sa->arg4;
641    int bits            = sa->arg5;
642    uint8_t relations   = sa->arg6 & 0xFF;
643    uint8_t mask        = (sa->arg6 >> 8) & 0xFF;
644
645    return sys_monitor_remote_relations(root_addr, root_bits, cptr, bits,
646                                        relations, mask);
647}
648
649INVOCATION_HANDLER(monitor_copy_existing)
650{
651    INVOCATION_PRELUDE(7);
652    capaddr_t croot_cptr = sa->arg2;
653    capaddr_t cnode_cptr = sa->arg3;
654    int cnode_level      = sa->arg4;
655    size_t slot          = sa->arg5;
656
657    // user pointer to src cap, check access
658    if (!access_ok(ACCESS_READ, sa->arg6, sizeof(struct capability))) {
659        return SYSRET(SYS_ERR_INVALID_USER_BUFFER);
660    }
661    /* Get the raw metadata of the capability to create from user pointer */
662    struct capability *src = (struct capability *)sa->arg6;
663
664    return sys_monitor_copy_existing(src, croot_cptr, cnode_cptr, cnode_level, slot);
665}
666
667INVOCATION_HANDLER(monitor_nullify_cap)
668{
669    INVOCATION_PRELUDE(4);
670    capaddr_t cptr = sa->arg2;
671    int bits       = sa->arg3;
672
673    return sys_monitor_nullify_cap(cptr, bits);
674}
675
676static struct sysret
677monitor_create_cap(
678    struct capability *kernel_cap,
679    arch_registers_state_t* context,
680    int argc
681    )
682{
683    assert(7 == argc);
684
685    struct registers_aarch64_syscall_args* sa = &context->syscall_args;
686
687    /* Create the cap in the destination */
688    capaddr_t cnode_cptr = sa->arg2;
689    int cnode_vbits      = sa->arg3;
690    size_t slot          = sa->arg4;
691    coreid_t owner       = sa->arg5;
692    struct capability *src =
693        (struct capability*)sa->arg6;
694
695    /* Cannot create null caps */
696    if (src->type == ObjType_Null ) {
697        return SYSRET(SYS_ERR_ILLEGAL_DEST_TYPE);
698    }
699
700    /* For certain types, only foreign copies can be created here */
701    if ((src->type == ObjType_EndPoint || src->type == ObjType_Dispatcher
702         || src->type == ObjType_Kernel || src->type == ObjType_IRQTable)
703        && owner == my_core_id)
704    {
705        return SYSRET(SYS_ERR_ILLEGAL_DEST_TYPE);
706    }
707
708    return SYSRET(caps_create_from_existing(&dcb_current->cspace.cap,
709                                            cnode_cptr, cnode_vbits,
710                                            slot, owner, src));
711}
712
713INVOCATION_HANDLER(monitor_get_platform)
714{
715    INVOCATION_PRELUDE(3);
716    // check args
717    if (!access_ok(ACCESS_WRITE, sa->arg2, sizeof(struct platform_info))) {
718        return SYSRET(SYS_ERR_INVALID_USER_BUFFER);
719    }
720
721    platform_get_info((struct platform_info*)sa->arg2);
722
723    return SYSRET(SYS_ERR_OK);
724}
725
726/**
727 * \brief Spawn a new core and create a kernel cap for it.
728 */
729static struct sysret
730monitor_spawn_core(
731    struct capability *kernel_cap,
732    arch_registers_state_t* context,
733    int argc)
734{
735    struct registers_aarch64_syscall_args* sa = &context->syscall_args;
736
737    hwid_t core_id         = sa->arg2;
738    enum cpu_type cpu_type = sa->arg3;
739    genvaddr_t entry       = sa->arg4;
740    genpaddr_t context_id  = sa->arg5;
741    uint64_t psci_use_hvc  = sa->arg6;
742
743    psci_set_use_hvc(psci_use_hvc);
744    return sys_monitor_spawn_core(core_id, cpu_type, entry, context_id);
745}
746
747static struct sysret
748monitor_identify_cap(
749    struct capability *kernel_cap,
750    arch_registers_state_t* context,
751    int argc)
752{
753    struct registers_aarch64_syscall_args* sa = &context->syscall_args;
754
755    capaddr_t cptr = sa->arg2;
756    int bits = sa->arg3;
757    struct capability *retbuf = (void *)sa->arg4;
758
759    return sys_monitor_identify_cap(&dcb_current->cspace.cap, cptr, bits, retbuf);
760}
761
762INVOCATION_HANDLER(monitor_identify_domains_cap)
763{
764    /* XXX - why is this not used consistently? */
765    INVOCATION_PRELUDE(7);
766    errval_t err;
767
768    capaddr_t root_caddr = sa->arg2;
769    capaddr_t root_vbits = sa->arg3;
770    capaddr_t cptr       = sa->arg4;
771    int bits             = sa->arg5;
772    struct capability *retbuf = (void *)sa->arg6;
773
774    struct capability *root;
775    err = caps_lookup_cap(&dcb_current->cspace.cap, root_caddr, root_vbits,
776                          &root, CAPRIGHTS_READ);
777    if (err_is_fail(err)) {
778        return SYSRET(err_push(err, SYS_ERR_ROOT_CAP_LOOKUP));
779    }
780
781    return sys_monitor_identify_cap(root, cptr, bits, retbuf);
782}
783
784static struct sysret handle_irq_table_set( struct capability* to,
785        arch_registers_state_t* context, int argc)
786{
787    struct registers_aarch64_syscall_args* sa = &context->syscall_args;
788
789    return SYSRET(irq_table_set(sa->arg2, sa->arg3));
790}
791
792
793static struct sysret handle_irq_table_delete( struct capability* to,
794        arch_registers_state_t* context,
795        int argc
796        )
797{
798    struct registers_aarch64_syscall_args* sa = &context->syscall_args;
799
800    return SYSRET(irq_table_delete(sa->arg2));
801}
802
803
804static struct sysret dispatcher_dump_ptables(
805    struct capability* to, arch_registers_state_t* context, int argc)
806{
807    assert(to->type == ObjType_Dispatcher);
808    assert(2 == argc);
809
810    printf("kernel_dump_ptables\n");
811
812   // struct dcb *dispatcher = to->u.dispatcher.dcb;
813
814   // paging_dump_tables(dispatcher);
815
816    return SYSRET(SYS_ERR_OK);
817}
818
819static struct sysret dispatcher_dump_capabilities(struct capability *cap,
820        arch_registers_state_t* context, int argc)
821{
822    assert(cap->type == ObjType_Dispatcher);
823    assert(2 == argc);
824    struct dcb *dispatcher = cap->u.dispatcher.dcb;
825    errval_t err = debug_print_cababilities(dispatcher);
826    return SYSRET(err);
827}
828
829static struct sysret handle_idcap_identify(struct capability *to,
830                                           arch_registers_state_t *context,
831                                           int argc)
832{
833    assert(to->type == ObjType_ID);
834    assert(3 == argc);
835
836    struct registers_aarch64_syscall_args* sa = &context->syscall_args;
837    idcap_id_t *idp = (idcap_id_t *) sa->arg2;
838
839    // Check validity of user space pointer
840    if (!access_ok(ACCESS_WRITE, (lvaddr_t) idp, sizeof(*idp)))  {
841        return SYSRET(SYS_ERR_INVALID_USER_BUFFER);
842    }
843
844    return sys_idcap_identify(to, idp);
845}
846
847
848static struct sysret handle_kcb_identify(struct capability *to,
849                                  arch_registers_state_t *context,
850                                  int argc)
851{
852    assert(3 == argc);
853
854    struct registers_aarch64_syscall_args* sa = &context->syscall_args;
855
856    return sys_handle_kcb_identify(to, (struct frame_identity *)sa->arg2);
857}
858
859typedef struct sysret (*invocation_t)(struct capability*,
860                                      arch_registers_state_t*, int);
861
862static invocation_t invocations[ObjType_Num][CAP_MAX_CMD] = {
863    [ObjType_Dispatcher] = {
864        [DispatcherCmd_Setup]       = handle_dispatcher_setup,
865        [DispatcherCmd_Properties]  = handle_dispatcher_properties,
866        [DispatcherCmd_PerfMon]     = handle_dispatcher_perfmon,
867        [DispatcherCmd_DumpPTables]  = dispatcher_dump_ptables,
868        [DispatcherCmd_DumpCapabilities] = dispatcher_dump_capabilities
869    },
870    [ObjType_KernelControlBlock] = {
871        [FrameCmd_Identify] = handle_kcb_identify
872    },
873    [ObjType_RAM] = {
874        [RAMCmd_Identify] = handle_frame_identify,
875    },
876    [ObjType_Frame] = {
877        [FrameCmd_Identify] = handle_frame_identify,
878    },
879    [ObjType_DevFrame] = {
880        [FrameCmd_Identify] = handle_frame_identify,
881    },
882    [ObjType_L1CNode] = {
883        [CNodeCmd_Copy]   = handle_copy,
884        [CNodeCmd_Mint]   = handle_mint,
885        [CNodeCmd_Retype] = handle_retype,
886        [CNodeCmd_Create] = handle_create,
887        [CNodeCmd_Delete] = handle_delete,
888        [CNodeCmd_Revoke] = handle_revoke,
889        [CNodeCmd_GetState] = handle_get_state,
890        [CNodeCmd_GetSize] = handle_get_size,
891        [CNodeCmd_Resize] = handle_resize,
892    },
893    [ObjType_L2CNode] = {
894        [CNodeCmd_Copy]   = handle_copy,
895        [CNodeCmd_Mint]   = handle_mint,
896        [CNodeCmd_Retype] = handle_retype,
897        [CNodeCmd_Create] = handle_create,
898        [CNodeCmd_Delete] = handle_delete,
899        [CNodeCmd_Revoke] = handle_revoke,
900        [CNodeCmd_GetState] = handle_get_state,
901        [CNodeCmd_Resize] = handle_resize,
902    },
903    [ObjType_VNode_AARCH64_l0] = {
904        [VNodeCmd_Map]   = handle_map,
905        [VNodeCmd_Unmap] = handle_unmap,
906    },
907    [ObjType_VNode_AARCH64_l1] = {
908        [VNodeCmd_Map]   = handle_map,
909        [VNodeCmd_Unmap] = handle_unmap,
910    },
911    [ObjType_VNode_AARCH64_l2] = {
912        [VNodeCmd_Map]   = handle_map,
913        [VNodeCmd_Unmap] = handle_unmap,
914    },
915    [ObjType_VNode_AARCH64_l3] = {
916        [VNodeCmd_Map]   = handle_map,
917        [VNodeCmd_Unmap] = handle_unmap,
918    },
919    [ObjType_Frame_Mapping] = {
920        [MappingCmd_Destroy] = handle_mapping_destroy,
921        [MappingCmd_Modify] = handle_mapping_modify,
922    },
923    [ObjType_DevFrame_Mapping] = {
924        [MappingCmd_Destroy] = handle_mapping_destroy,
925        [MappingCmd_Modify] = handle_mapping_modify,
926    },
927    [ObjType_VNode_AARCH64_l0_Mapping] = {
928        [MappingCmd_Destroy] = handle_mapping_destroy,
929        [MappingCmd_Modify] = handle_mapping_modify,
930    },
931    [ObjType_VNode_AARCH64_l1_Mapping] = {
932        [MappingCmd_Destroy] = handle_mapping_destroy,
933        [MappingCmd_Modify] = handle_mapping_modify,
934    },
935    [ObjType_VNode_AARCH64_l2_Mapping] = {
936        [MappingCmd_Destroy] = handle_mapping_destroy,
937        [MappingCmd_Modify] = handle_mapping_modify,
938    },
939    [ObjType_VNode_AARCH64_l3_Mapping] = {
940        [MappingCmd_Destroy] = handle_mapping_destroy,
941        [MappingCmd_Modify] = handle_mapping_modify,
942    },
943    [ObjType_IRQTable] = {
944            [IRQTableCmd_Set] = handle_irq_table_set,
945            [IRQTableCmd_Delete] = handle_irq_table_delete,
946        },
947    [ObjType_Kernel] = {
948        [KernelCmd_Cap_has_relations] = monitor_cap_has_relations,
949        [KernelCmd_Clear_step]        = monitor_handle_clear_step,
950        [KernelCmd_Copy_existing]     = monitor_copy_existing,
951        [KernelCmd_Create_cap]        = monitor_create_cap,
952        [KernelCmd_Delete_foreigns]   = monitor_handle_delete_foreigns,
953        [KernelCmd_Delete_last]       = monitor_handle_delete_last,
954        [KernelCmd_Delete_step]       = monitor_handle_delete_step,
955        [KernelCmd_Domain_Id]         = monitor_handle_domain_id,
956        [KernelCmd_Get_arch_id]       = monitor_get_arch_id,
957        [KernelCmd_Get_cap_owner]     = monitor_get_cap_owner,
958        [KernelCmd_Get_core_id]       = monitor_get_core_id,
959        [KernelCmd_Has_descendants]   = monitor_handle_has_descendants,
960        [KernelCmd_Identify_cap]      = monitor_identify_cap,
961        [KernelCmd_Identify_domains_cap] = monitor_identify_domains_cap,
962        [KernelCmd_Lock_cap]          = monitor_lock_cap,
963        [KernelCmd_Nullify_cap]       = monitor_nullify_cap,
964        [KernelCmd_Register]          = monitor_handle_register,
965        [KernelCmd_Remote_relations]  = monitor_remote_relations,
966        [KernelCmd_Retype]            = monitor_handle_retype,
967        [KernelCmd_Revoke_mark_relations] = monitor_handle_revoke_mark_rels,
968        [KernelCmd_Revoke_mark_target] = monitor_handle_revoke_mark_tgt,
969        [KernelCmd_Set_cap_owner]     = monitor_set_cap_owner,
970        /* XXX - why is this commented out? */
971        //[KernelCmd_Setup_trace]       = handle_trace_setup,
972        [KernelCmd_Spawn_core]        = monitor_spawn_core,
973        [KernelCmd_Unlock_cap]        = monitor_unlock_cap,
974        [KernelCmd_Get_platform]        = monitor_get_platform,
975    },
976    [ObjType_IPI] = {
977        [IPICmd_Send_Start]  = monitor_spawn_core,
978    },
979    [ObjType_ID] = {
980        [IDCmd_Identify] = handle_idcap_identify
981    }
982};
983
984static struct sysret
985handle_invoke(uint64_t a0, uint64_t a1, uint64_t a2, uint64_t a3,
986              uint64_t a4, uint64_t a5, uint64_t a6,
987              arch_registers_state_t *context)
988{
989    struct registers_aarch64_syscall_args* sa = &context->syscall_args;
990
991    /* XXX - can we generate them from the same source? */
992    //
993    // Must match lib/barrelfish/include/arch/aarch64/arch/invocations.h
994    //
995    uint8_t   flags       = FIELD(24,4,a0);
996    uint8_t   invoke_bits = FIELD(16,8,a0);
997    capaddr_t invoke_cptr = a1;
998
999// printf("%s: %zd %zd\n", __func__, systime_now(), armv8_CNTP_TVAL_EL0_rd(NULL));
1000    debug(SUBSYS_SYSCALL, "sys_invoke(0x%"PRIxCADDR"(%d))\n",
1001                invoke_cptr, invoke_bits);
1002
1003    struct sysret r = { .error = SYS_ERR_OK, .value = 0 };
1004
1005    struct capability* to;
1006    r.error = caps_lookup_cap(&dcb_current->cspace.cap,
1007                              invoke_cptr, invoke_bits,
1008                              &to, CAPRIGHTS_READ);
1009    if (err_is_ok(r.error))
1010    {
1011        assert(to != NULL);
1012        assert(to->type < ObjType_Num);
1013
1014        if (ObjType_EndPoint == to->type)
1015        {
1016            struct dcb *listener = to->u.endpoint.listener;
1017            assert(listener != NULL);
1018
1019            if (listener->disp) {
1020                uint8_t length_words = FIELD(28,8,a0);
1021                uint8_t send_bits    = FIELD(8,8,a0);
1022                capaddr_t send_cptr = a2;
1023                /* limit length of message from buggy/malicious sender */
1024                length_words = min(length_words, LMP_MSG_LENGTH);
1025
1026                // does the sender want to yield their timeslice on success?
1027                bool sync = flags & LMP_FLAG_SYNC;
1028                // does the sender want to yield to the target
1029                // if undeliverable?
1030                bool yield = flags & LMP_FLAG_YIELD;
1031                // is the cap (if present) to be deleted on send?
1032                bool give_away = flags & LMP_FLAG_GIVEAWAY;
1033
1034                // Message registers in context are
1035                // discontinguous for now so copy message words
1036                // to temporary container. This is fixable, but
1037                // not in this pass.
1038                uintptr_t msg_words[LMP_MSG_LENGTH];
1039                msg_words[0] = a3;
1040                msg_words[1] = a4;
1041                msg_words[2] = a5;
1042                msg_words[3] = a6;
1043                STATIC_ASSERT(LMP_MSG_LENGTH == 4, "Oops");
1044
1045                // try to deliver message
1046                r.error = lmp_deliver(to, dcb_current, msg_words,
1047                                      length_words, send_cptr, send_bits, give_away);
1048
1049                /* Switch to reciever upon successful delivery
1050                 * with sync flag, or (some cases of)
1051                 * unsuccessful delivery with yield flag */
1052                enum err_code err_code = err_no(r.error);
1053                if ((sync && err_is_ok(r.error)) ||
1054                    (yield && (err_code == SYS_ERR_LMP_BUF_OVERFLOW
1055                               || err_code == SYS_ERR_LMP_CAPTRANSFER_DST_CNODE_LOOKUP
1056                               || err_code == SYS_ERR_LMP_CAPTRANSFER_DST_CNODE_INVALID
1057                               || err_code == SYS_ERR_LMP_CAPTRANSFER_DST_SLOT_OCCUPIED))
1058                   ) {
1059                    if (err_is_fail(r.error)) {
1060                        struct dispatcher_shared_generic *current_disp =
1061                            get_dispatcher_shared_generic(dcb_current->disp);
1062                        struct dispatcher_shared_generic *listener_disp =
1063                            get_dispatcher_shared_generic(listener->disp);
1064                        debug(SUBSYS_DISPATCH, "LMP failed; %.*s yields to %.*s: %u\n",
1065                              DISP_NAME_LEN, current_disp->name,
1066                              DISP_NAME_LEN, listener_disp->name, err_code);
1067                    }
1068
1069                    // special-case context switch: ensure correct state in
1070                    // current DCB
1071                    dispatcher_handle_t handle = dcb_current->disp;
1072                    struct dispatcher_shared_aarch64 *disp =
1073                        get_dispatcher_shared_aarch64(handle);
1074                    dcb_current->disabled =
1075                        dispatcher_is_disabled_ip(handle, context->named.pc);
1076                    if (dcb_current->disabled) {
1077                        assert(context == &disp->disabled_save_area);
1078                        context->named.x0 = r.error;
1079                    }
1080                    else {
1081                        assert(context == &disp->enabled_save_area);
1082                        context->named.x0 = r.error;
1083                    }
1084                    dispatch(listener);
1085                }
1086            }
1087            else {
1088                r.error = SYS_ERR_LMP_NO_TARGET;
1089            }
1090        }
1091        else
1092        {
1093            uint8_t cmd = FIELD(8,8,a0);
1094            int argc    = FIELD(4,4,a0);
1095            if (cmd < CAP_MAX_CMD)
1096            {
1097                invocation_t invocation = invocations[to->type][cmd];
1098                if (invocation)
1099                {
1100                    /* XXX - Until we improve the syscall path, we're stacking
1101                     * all of the argument registers here.  Yuck. */
1102                    sa->arg0 = a0;
1103                    sa->arg1 = a1;
1104                    sa->arg2 = a2;
1105                    sa->arg3 = a3;
1106                    sa->arg4 = a4;
1107                    sa->arg5 = a5;
1108                    sa->arg6 = a6;
1109
1110                    r = invocation(to, context, argc);
1111                    if (!dcb_current)
1112                    {
1113                        // dcb_current was removed, dispatch someone else
1114                        assert(err_is_ok(r.error));
1115                        dispatch(schedule());
1116                    }
1117                    return r;
1118                }
1119            }
1120            printk(LOG_ERR, "Bad invocation type %d cmd %d\n", to->type, cmd);
1121            r.error = SYS_ERR_ILLEGAL_INVOCATION;
1122        }
1123    }
1124
1125    return r;
1126}
1127
1128static struct sysret handle_debug_syscall(int msg)
1129{
1130    struct sysret retval = { .error = SYS_ERR_OK };
1131    switch (msg) {
1132        case DEBUG_FLUSH_CACHE:
1133            /* XXX - implement me */
1134            break;
1135
1136        case DEBUG_CONTEXT_COUNTER_RESET:
1137            dispatch_csc_reset();
1138            break;
1139
1140        case DEBUG_CONTEXT_COUNTER_READ:
1141            retval.value = dispatch_get_csc();
1142            break;
1143
1144        case DEBUG_TIMESLICE_COUNTER_READ:
1145            retval.value = systime_now();
1146            break;
1147
1148        case DEBUG_HARDWARE_TIMER_READ:
1149            retval.value = timer_get_timestamp();
1150            break;
1151
1152        case DEBUG_HARDWARE_TIMER_HERTZ_READ:
1153            retval.value = timer_get_frequency();
1154            break;
1155
1156        case DEBUG_GET_TSC_PER_MS:
1157            // XXX: Implement if possible at all.
1158            retval.value = 1;
1159            break;
1160
1161        default:
1162            printk(LOG_ERR, "invalid sys_debug msg type %d\n", msg);
1163            retval.error = err_push(retval.error, SYS_ERR_ILLEGAL_SYSCALL);
1164    }
1165    return retval;
1166}
1167
1168
1169/* XXX - function documentation is inconsistent. */
1170/**
1171 * System call dispatch routine.
1172 *
1173 * @return struct sysret for all calls except yield / invoke.
1174 *
1175 * The first 8 syscall arguments are passed in registers, preserved by the
1176 * assembly stub.
1177 *
1178 */
1179void sys_syscall(uint64_t a0, uint64_t a1, uint64_t a2, uint64_t a3,
1180                 uint64_t a4, uint64_t a5, uint64_t a6,
1181                 arch_registers_state_t *context)
1182{
1183    // XXX
1184    // Set dcb_current->disabled correctly.  This should really be
1185    // done in exceptions.S
1186    // XXX
1187
1188    assert(dcb_current != NULL);
1189    dispatcher_handle_t handle = dcb_current->disp;
1190    struct dispatcher_shared_generic *disp =
1191        get_dispatcher_shared_generic(handle);
1192    assert((struct dispatcher_shared_generic *)(dcb_current->disp) == disp);
1193    if (dispatcher_is_disabled_ip((dispatcher_handle_t)disp, context->named.pc)) {
1194        assert(context == dispatcher_get_disabled_save_area((dispatcher_handle_t)disp));
1195        dcb_current->disabled = true;
1196    } else {
1197        assert(context == dispatcher_get_enabled_save_area((dispatcher_handle_t)disp));
1198        dcb_current->disabled = false;
1199    }
1200    // TODO: ARMv7 gets this from assembly code.
1201    // assert(disabled == dcb_current->disabled);
1202
1203    STATIC_ASSERT_OFFSETOF(struct sysret, error, 0);
1204
1205    int syscall = FIELD(0,4,a0);
1206    int argc    = FIELD(4,4,a0);
1207
1208
1209    debug(SUBSYS_SYSCALL, "syscall: syscall=%d, argc=%d\n", syscall, argc);
1210//    debug(SUBSYS_SYSCALL, "syscall: disabled=%d\n", disabled);
1211    debug(SUBSYS_SYSCALL, "syscall: context=0x%"PRIxLVADDR", disp=0x%"PRIxLVADDR"\n",
1212            context, disp );
1213
1214    struct sysret r = { .error = SYS_ERR_INVARGS_SYSCALL, .value = 0 };
1215
1216    switch (syscall)
1217    {
1218        case SYSCALL_INVOKE:
1219            r = handle_invoke(a0, a1, a2, a3, a4, a5, a6, context);
1220            break;
1221
1222        case SYSCALL_YIELD:
1223            if (argc == 2) {
1224                r = sys_yield((capaddr_t)a1);
1225            }
1226            break;
1227
1228        case SYSCALL_NOP:
1229            r.error = SYS_ERR_OK;
1230            break;
1231
1232        case SYSCALL_PRINT:
1233            if (argc == 3) {
1234                /* XXX - The user can pass arbitrary bad pointers and lengths
1235                 * here! */
1236                r.error = sys_print((const char*)a1, (size_t)a2);
1237            }
1238            break;
1239
1240        case SYSCALL_DEBUG:
1241            if (a1 == DEBUG_CREATE_IRQ_SRC_CAP) {
1242                r.error = irq_debug_create_src_cap(a2, a3, a4, a5, a6);
1243            } else if (argc == 2) {
1244                r = handle_debug_syscall(a1);
1245            }
1246
1247            break;
1248
1249        default:
1250            printf("Illegal syscall %u\n", syscall);
1251            r.error = SYS_ERR_ILLEGAL_SYSCALL;
1252            break;
1253    }
1254
1255    if (r.error) {
1256        debug(SUBSYS_SYSCALL, "syscall failed %016"PRIx64
1257                              " => %016"PRIxERRV"\n", a0, r.error);
1258    }
1259
1260    /* XXX - shouldn't stack & unstack these. */
1261    context->named.x0 = r.error;
1262    context->named.x1 = r.value;
1263
1264    debug(SUBSYS_SYSCALL, "syscall: Resuming; dcb->disabled=%d, disp->disabled=%d\n",
1265          dcb_current->disabled, disp->disabled);
1266
1267    resume(context);
1268}
1269