1/*
2 * Copyright 2019, Data61, CSIRO (ABN 41 687 119 230)
3 *
4 * SPDX-License-Identifier: BSD-2-Clause
5 */
6
7#include <autoconf.h>
8#include <stdio.h>
9#include <stdlib.h>
10
11#include <sel4/sel4.h>
12#include <sel4/messages.h>
13#include <utils/util.h>
14
15#include <sel4vm/guest_vm_util.h>
16#include <sel4vm/guest_memory.h>
17
18#include "vm.h"
19#include "syscalls.h"
20
21static void sys_pa_to_ipa(vm_t *vm, seL4_UserContext *regs)
22{
23    uint32_t pa;
24#ifdef CONFIG_ARCH_AARCH64
25#else
26    pa = regs->r0;
27#endif
28
29    ZF_LOGD("PA translation syscall from [%s]: 0x%08x->?\n", vm->vm_name, pa);
30#ifdef CONFIG_ARCH_AARCH64
31#else
32    regs->r0 = pa;
33#endif
34}
35
36#if 0
37/* sys_ipa_to_pa currently not supported
38 * TODO: Re-enable or re-evaluate support for syscall
39 */
40static void sys_ipa_to_pa(vm_t *vm, seL4_UserContext *regs)
41{
42    seL4_ARM_Page_GetAddress_t ret;
43    long ipa;
44    int err;
45    seL4_CPtr cap;
46#ifdef CONFIG_ARCH_AARCH64
47#else
48    ipa = regs->r0;
49#endif
50    cap = vspace_get_cap(vm_get_vspace(vm), (void *)ipa);
51    if (cap == seL4_CapNull) {
52        err = vm_alloc_guest_ram_at(vm, ipa, 0x1000);
53        if (err) {
54            printf("Could not map address for IPA translation\n");
55            return;
56        }
57        cap = vspace_get_cap(vm_get_vspace(vm), (void *)ipa);
58        assert(cap != seL4_CapNull);
59    }
60
61    ret = seL4_ARM_Page_GetAddress(cap);
62    assert(!ret.error);
63    ZF_LOGD("IPA translation syscall from [%s]: 0x%08x->0x%08x\n",
64            vm->vm_name, ipa, ret.paddr);
65#ifdef CONFIG_ARCH_AARCH64
66#else
67    regs->r0 = ret.paddr;
68#endif
69}
70#endif
71
72static void sys_nop(vm_t *vm, seL4_UserContext *regs)
73{
74    ZF_LOGD("NOP syscall from [%s]\n", vm->vm_name);
75}
76
77static int handle_syscall(vm_vcpu_t *vcpu)
78{
79    seL4_Word syscall, ip;
80    seL4_UserContext regs;
81    seL4_CPtr tcb;
82    vm_t *vm;
83    int err;
84
85    vm = vcpu->vm;
86    syscall = seL4_GetMR(seL4_UnknownSyscall_Syscall);
87    ip = seL4_GetMR(seL4_UnknownSyscall_FaultIP);
88
89    tcb = vm_get_vcpu_tcb(vcpu);
90    err = seL4_TCB_ReadRegisters(tcb, false, 0, sizeof(regs) / sizeof(regs.pc), &regs);
91    assert(!err);
92    regs.pc += 4;
93
94    ZF_LOGI("Syscall %d from [%s]\n", syscall, vm->vm_name);
95    switch (syscall) {
96    case SYS_PA_TO_IPA:
97        sys_pa_to_ipa(vm, &regs);
98        break;
99#if 0
100    case SYS_IPA_TO_PA:
101        /* sys_ipa_to_pa currently not supported
102         * TODO: Re-enable or re-evaluate support for syscall
103         */
104        sys_ipa_to_pa(vcpu->vm, &regs);
105        break;
106#endif
107    case SYS_NOP:
108        sys_nop(vm, &regs);
109        break;
110    default:
111        ZF_LOGE("%sBad syscall from [%s]: scno %zd at PC: %p%s\n",
112                ANSI_COLOR(RED, BOLD), vm->vm_name, syscall, (void *) ip, ANSI_COLOR(RESET));
113        return -1;
114    }
115    err = seL4_TCB_WriteRegisters(tcb, false, 0, sizeof(regs) / sizeof(regs.pc), &regs);
116    assert(!err);
117    return VM_EXIT_HANDLED;
118}
119
120int vm_syscall_handler(vm_vcpu_t *vcpu)
121{
122    int err;
123    err = handle_syscall(vcpu);
124    if (!err) {
125        seL4_MessageInfo_t reply;
126        reply = seL4_MessageInfo_new(0, 0, 0, 0);
127        seL4_Reply(reply);
128    }
129    return err;
130}
131