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