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