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#ifndef _RPC_INTERFACE_DATA_CLIENT_HELPER_H_
14#define _RPC_INTERFACE_DATA_CLIENT_HELPER_H_
15
16#include <stdint.h>
17#include <stdlib.h>
18#include <refos/refos.h>
19#include <refos/error.h>
20#include <refos-rpc/rpc.h>
21#include <refos-rpc/data_client.h>
22#include <refos-rpc/proc_client_helper.h>
23#include <refos-util/walloc.h>
24#include <refos/sync.h>
25#include <refos-util/cspace.h>
26
27/*! @file
28    @brief Helper functions for the data interface.
29
30    This file contains a simple layer of helper functions that make using the dataspace interface
31    much easier, but are too complex to have been generated by the stub generator.
32*/
33
34/*! @brief Set the data_open() to paddr mode, for dataservers which support opening a dataspace at a
35           specific physical address. Mainly used for device MMIO.
36*/
37#define DSPACE_FLAG_DEVICE_PADDR 0x10000000
38#define DSPACE_FLAG_UNCACHED     0x20000000
39
40/*! @brief Structure containing state for a mapped dataspace. */
41typedef struct data_mapping {
42    seL4_CPtr session; /* No ownership. */
43    seL4_CPtr dataspace;  /* Has ownership. */
44    seL4_CPtr window;  /* Has ownership. */
45
46    char* vaddr;
47
48    int size;
49    int sizeNPages;
50    int dspaceSize;
51
52    refos_err_t err;
53} data_mapping_t;
54
55/*! @brief Helper function to open a dataspace, allocate a window to map into, then map it there.
56    @param session The client connection session to the dataspace server.  (No ownership)
57    @param name The name of the dataspace server.
58    @param flags The read / write / create flags.
59    @param mode The mode to create new file with, in the case that a new one is created.
60    @param size The size of mapping window.
61    @param dspaceSize The size of dataspace to open. Note that some data servers may ignore this.
62    @return A data_mapping_t structure containing the result mapping. Look in the err member of the
63            structure to check for any errors that have occured. (Gives ownership)
64*/
65static inline data_mapping_t
66data_open_map(seL4_CPtr session, char* name, int flags, int mode, int size, int dspaceSize)
67{
68    int errnoRetVal = EINVALID;
69    data_mapping_t d;
70    memset(&d, 0, sizeof(data_mapping_t));
71    d.session = session;
72
73    /* Allocate window. */
74    d.size = size;
75    d.sizeNPages = (size / REFOS_PAGE_SIZE) + ((size % REFOS_PAGE_SIZE) ? 1 : 0);
76    seL4_Word vaddr = 0;
77    if (flags & DSPACE_FLAG_UNCACHED) {
78        vaddr = walloc_ext(d.sizeNPages, &d.window, PROC_WINDOW_PERMISSION_READWRITE,
79                           PROC_WINDOW_FLAGS_UNCACHED);
80    } else {
81        vaddr = walloc(d.sizeNPages, &d.window);
82    }
83    if (!vaddr || !d.window) {
84        errnoRetVal = ENOMEM;
85        goto exit0;
86    }
87    d.vaddr = (char*) vaddr;
88
89    /* Open the dataspace. */
90    if (dspaceSize < 0) {
91        /* Default dataspace size to same size as the window. */
92        dspaceSize = size;
93    }
94    d.dspaceSize = dspaceSize;
95    d.dataspace = data_open(session, name, flags, mode, dspaceSize, &errnoRetVal);
96    if (errnoRetVal != ESUCCESS || d.dataspace == 0) {
97        REFOS_SET_ERRNO(errnoRetVal);
98        goto exit1;
99    }
100
101    /* Map the dataspace. */
102    errnoRetVal = data_datamap(session, d.dataspace, d.window, 0);
103    if (errnoRetVal != ESUCCESS) {
104        REFOS_SET_ERRNO(errnoRetVal);
105        goto exit2;
106    }
107
108    REFOS_SET_ERRNO(ESUCCESS);
109    d.err = ESUCCESS;
110    return d;
111
112    /* Exit stack. */
113exit2:
114    data_close(session, d.dataspace);
115    seL4_CNode_Delete(REFOS_CSPACE, d.dataspace, REFOS_CDEPTH);
116    csfree(d.dataspace);
117
118exit1:
119    walloc_free(vaddr, d.sizeNPages);
120
121exit0:
122    REFOS_SET_ERRNO(errnoRetVal);
123    memset(&d, 0, sizeof(data_mapping_t));
124    d.err = errnoRetVal;
125    return d;
126}
127
128/*! @brief Release a data mapping previous initialised by @ref data_open_map.
129    @param d The previously mapped dataspace. (Takes ownership)
130    @return ESUCCESS on success, refos_err_t error otherwise.
131*/
132static inline refos_err_t
133data_mapping_release(data_mapping_t d)
134{
135    if (d.err != ESUCCESS) {
136        return ESUCCESS;
137    }
138
139    if (d.window) {
140        refos_err_t error = data_dataunmap(d.session, d.window);
141        if (error != ESUCCESS) {
142            return error;
143        }
144        assert(d.vaddr);
145        walloc_free((uint32_t) d.vaddr, d.sizeNPages);
146    }
147
148    refos_err_t error = data_close(d.session, d.dataspace);
149    if (error != ESUCCESS) {
150        return error;
151    }
152    csfree_delete(d.dataspace);
153
154    memset(&d, 0, sizeof(data_mapping_t));
155    return ESUCCESS;
156}
157
158/*! @brief Helper function for data_provide_data_from_parambuffer().
159
160    Helper function for data_provide_data_from_parambuffer(), that basically copies the given
161    content into the given parameter buffer before calling data_provide_data_from_parambuffer().
162
163    @param session The client connection session to the dataspace server.  (No ownership)
164    @param dspace_fd The cap to the remote dataspace to provide the content for.
165    @param offset The offset into the remote dataspace to provide content for.
166    @param content The content buffer. (No ownership)
167    @param contentSize The size of the content. (May have maximum content size.)
168    @param paramBuffer The parameter buffer that has been set up.
169    @return ESUCCESS if success, refos_error error code otherwise.
170*/
171static inline refos_err_t
172data_provide_data(seL4_CPtr session, seL4_CPtr dspace_fd, uint32_t offset, char *content,
173                  uint32_t contentSize, data_mapping_t* paramBuffer)
174{
175    if (!content) {
176        return EINVALIDPARAM;
177    }
178    if (!paramBuffer || paramBuffer->err != ESUCCESS) {
179        return ENOPARAMBUFFER;
180    }
181    if (contentSize >= paramBuffer->size) {
182        return ENOMEM;
183    }
184    memcpy(paramBuffer->vaddr, content, contentSize);
185    return data_provide_data_from_parambuffer(session, dspace_fd, offset, contentSize);
186}
187
188#endif /* _RPC_INTERFACE_DATA_CLIENT_HELPER_H_ */
189