1/*
2 * Copyright 2016, Data61
3 * Commonwealth Scientific and Industrial Research Organisation (CSIRO)
4 * ABN 41 687 119 230.
5 *
6 * This software may be distributed and modified according to the terms of
7 * the BSD 2-Clause license. Note that NO WARRANTY is provided.
8 * See "LICENSE_BSD2.txt" for details.
9 *
10 * @TAG(D61_BSD)
11 */
12
13#include <stdio.h>
14#include <assert.h>
15#include "dispatcher.h"
16#include "../system/process/process.h"
17#include <refos/refos.h>
18
19 /*! @file
20     @brief Common Process server dispatcher helper functions. */
21
22#define PROCSERV_SYSCALL_PARAM_SIZE_MAX (REFOS_PAGE_SIZE * 8)
23static char _paramBuffer[PROCSERV_SYSCALL_PARAM_SIZE_MAX];
24
25seL4_MessageInfo_t _dispatcherEmptyReply;
26
27int
28check_dispatch_interface(struct procserv_msg *m, void **userptr, int labelMin, int labelMax)
29{
30    assert(userptr);
31    if (seL4_MessageInfo_get_label(m->message) != seL4_Fault_NullFault ||
32            !dispatcher_badge_PID(m->badge)) {
33        /* Not a Syscall, pass onto next dispatcher. */
34        return DISPATCH_PASS;
35    }
36
37    struct proc_pcb *pcb = pid_get_pcb_from_badge(&procServ.PIDList, m->badge);
38    if (!pcb) {
39        ROS_WARNING("Unknown client.");
40        return DISPATCH_ERROR;
41    }
42
43    seL4_Word syscallFunc = seL4_GetMR(0);
44    if (syscallFunc <= labelMin || syscallFunc >= labelMax) {
45        /* Not our type of syscall to handle. */
46        return DISPATCH_PASS;
47    }
48
49    pcb->rpcClient.userptr = (void*) m;
50    pcb->rpcClient.minfo = m->message;
51    (*userptr) = (void*) pcb;
52
53    return DISPATCH_SUCCESS;
54}
55
56bool
57check_dispatch_caps(struct procserv_msg *m, seL4_Word unwrappedMask, int numExtraCaps)
58{
59    assert(m);
60    if (seL4_MessageInfo_get_capsUnwrapped(m->message) != unwrappedMask ||
61            seL4_MessageInfo_get_extraCaps(m->message) != numExtraCaps) {
62        return false;
63    }
64    return true;
65}
66
67seL4_CPtr
68dispatcher_copyout_cptr(seL4_CPtr c)
69{
70    cspacepath_t cslot;
71    int error = vka_cspace_alloc_path(&procServ.vka, &cslot);
72    if (error || cslot.capPtr == 0) {
73        return (seL4_CPtr) 0;
74    }
75    cspacepath_t src;
76    vka_cspace_make_path(&procServ.vka, c, &src);
77    error = vka_cnode_copy(&cslot, &src, seL4_AllRights);
78    if (error) {
79        assert(!"dispatcher_copyout_cptr could not copy cap. Most likely a procserv bug.");
80        vka_cspace_free(&procServ.vka, cslot.capPtr);
81        return (seL4_CPtr) 0;
82    }
83    return cslot.capPtr;
84}
85
86void
87dispatcher_release_copyout_cptr(seL4_CPtr c)
88{
89    if (!c) {
90        /* No capability here, nothing to do. */
91        return;
92    }
93    cspacepath_t cslot;
94    vka_cspace_make_path(&procServ.vka, c, &cslot);
95    vka_cnode_revoke(&cslot);
96    vka_cnode_delete(&cslot);
97    vka_cspace_free(&procServ.vka, cslot.capPtr);
98}
99
100char*
101dispatcher_read_param(struct proc_pcb *pcb, uint32_t readLen)
102{
103    assert(pcb && pcb->magic == REFOS_PCB_MAGIC);
104
105    /* Check that client actually has a paramBuffer set. */
106    if (!pcb->paramBuffer && readLen) {
107        dvprintf("WARNING: no param buffer exists.")
108        return NULL;
109    }
110
111    /* Check readLen is not too big. */
112    if (readLen > PROCSERV_SYSCALL_PARAM_SIZE_MAX) {
113        ROS_ERROR("Parameter buffer too large to be read.")
114        return NULL;
115    }
116
117    /* Reset the static temp buffer. */
118    char *tempBuffer = _paramBuffer;
119    memset(tempBuffer, 0, PROCSERV_SYSCALL_PARAM_SIZE_MAX);
120
121    /* Read bytes out of the paramBuffer dataspace. */
122    if (readLen > 0) {
123        int error = ram_dspace_read(tempBuffer, readLen, pcb->paramBuffer, 0);
124        if (error != ESUCCESS) {
125            ROS_ERROR("Parameter buffer failed to read from parameter buffer.");
126            assert(!"Failed to read from parameter buffer. This shouldn't happen; Procserv OOM.");
127            return NULL;
128        }
129    }
130
131    return tempBuffer;
132}
133
134