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