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 <stdlib.h>
15#include <assert.h>
16#include <sel4/sel4.h>
17#include <refos/refos.h>
18#include <refos/vmlayout.h>
19#include "badge.h"
20#include "state.h"
21#include "dataspace.h"
22
23 /*! @file
24     @brief File server CPIO dataspace object allocation and management.
25
26     This module contains the concrete implementations for file server CPIO dataspaces. The
27     dispatcher module simple does basic error checking before calling one of the helper functions
28     here.
29*/
30
31/* --------------------- CPIO Dataspace OAT Callback Functions ---------------------------------- */
32
33/*! @brief Dataspace object OAT creation function.
34
35    This is called by coat helper library to create a new structure. The first argument is the
36    client's DeathID, second argument is the fileData pointer, 3rd argument is the fileData size,
37    and 4th argument the permissions mask.
38
39    Allocates and fills in a new dataspace structure with the given arguments, and mints a new cap
40    representing this new dataspace.
41
42    @param oat The parent struct fs_dataspace_table structure of dspace object being created.
43    @param id The dataspace object ID that has been allocated for this object to go into.
44    @param arg The arguments (see above).
45    @return A new dataspace (struct fs_dataspace) if success, NULL otherwise. (Passes ownership, it
46            is the caller's responsibility to call dspace_oat_delete on the returned object.)
47*/
48static cvector_item_t
49dspace_oat_create(coat_t *oat, int id, uint32_t arg[COAT_ARGS])
50{
51    /* Allocate and fill in structure. */
52    struct fs_dataspace *ndspace = malloc(sizeof(struct fs_dataspace));
53    if (!ndspace) {
54        assert(!"oom");
55        ROS_ERROR("dspace_oat_create out of memory!");
56        return NULL;
57    }
58
59    ndspace->magic = FS_DATASPACE_MAGIC;
60    ndspace->dID = id;
61    ndspace->deathID = arg[0];
62    ndspace->dataspaceCap = csalloc();
63    ndspace->fileData = (char*) arg[1];
64    ndspace->fileDataSize = arg[2];
65    ndspace->permissions = arg[3];
66    ndspace->fileCreated = false;
67
68    /* Check that the dataspace cap cslot has been successfully allocated, and that
69       the given pointer is valid. */
70    if (!ndspace->dataspaceCap || !ndspace->fileData) {
71        free(ndspace);
72        return NULL;
73    }
74
75    /* Create the badged cap represending this dataspace. */
76    int error = seL4_CNode_Mint(
77            REFOS_CSPACE, ndspace->dataspaceCap, REFOS_CDEPTH,
78            REFOS_CSPACE, fileServCommon->anonEP, REFOS_CDEPTH,
79            seL4_AllRights, seL4_CapData_Badge_new(id + FS_DSPACE_BADGE_BASE)
80    );
81    assert(!error);
82    (void) error;
83
84    return (cvector_item_t) ndspace;
85}
86
87/*! @brief Dataspace object OAT deletion function.
88    @param oat The parent struct fs_dataspace_table structure of dspace object being deleted.
89    @param obj The dataspace object (struct fs_dataspace) to release resources for.
90               (Takes ownership since it frees the given structure.)
91*/
92static void
93dspace_oat_delete(coat_t *oat, cvector_item_t *obj)
94{
95    struct fs_dataspace *dspace = (struct fs_dataspace *) obj;
96    assert(dspace && dspace->magic == FS_DATASPACE_MAGIC);
97    dprintf("Deleting dataspace ID %d\n", dspace->dID);
98
99    assert(dspace->dataspaceCap);
100    seL4_CNode_Revoke(REFOS_CSPACE, dspace->dataspaceCap, REFOS_CDEPTH);
101    csfree_delete(dspace->dataspaceCap);
102
103    /* Finally, free the entire structure. */
104    free(dspace);
105}
106
107/* ----------------------- CPIO Dataspace Table Functions --------------------------------------- */
108
109void
110dspace_table_init(struct fs_dataspace_table *dt)
111{
112    /* Configure the object allocation table creation / deletion callback func pointers. */
113    dt->allocTable.oat_expand = NULL;
114    dt->allocTable.oat_create = dspace_oat_create;
115    dt->allocTable.oat_delete = dspace_oat_delete;
116
117    /* Initialise our data structures. */
118    coat_init(&dt->allocTable, 1, FILESERVER_MAX_DATASPACES);
119    chash_init(&dt->windowAssocTable, FILESERVER_WINDOW_ASSOC_HASHSIZE);
120    chash_init(&dt->dspaceAssocTable, FILESERVER_DSPACE_ASSOC_HASHSIZE);
121}
122
123void
124dspace_table_release(struct fs_dataspace_table *dt)
125{
126    for (int i = 0; i < PROCESS_MAX_WINDOWS; i++) {
127        dspace_window_unassociate(dt, i);
128    }
129    coat_release(&dt->allocTable);
130    chash_release(&dt->windowAssocTable);
131}
132
133/* --------------------- CPIO Dataspace Allocation Functions ------------------------------------ */
134
135struct fs_dataspace*
136dspace_alloc(struct fs_dataspace_table *dt, uint32_t deathID, char *fileData, size_t fileDataSize,
137             seL4_Word permissions)
138{
139    struct fs_dataspace* ndspace = NULL;
140
141    uint32_t arg[COAT_ARGS];
142    arg[0] = deathID;
143    arg[1] = (uint32_t) fileData;
144    arg[2] = (uint32_t) fileDataSize;
145    arg[3] = (uint32_t) permissions;
146
147    /* Allocate an ID, and the dspace structure associated with it. */
148    int ID = coat_alloc(&dt->allocTable, arg, (cvector_item_t *) &ndspace);
149    if (!ndspace) {
150        ROS_ERROR("dspace_alloc couldn't allocate a dataspace.");
151        return NULL;
152    }
153
154    assert(ID != COAT_INVALID_ID);
155    assert(ndspace->magic == FS_DATASPACE_MAGIC);
156    (void) ID;
157    return ndspace;
158}
159
160struct fs_dataspace*
161dspace_get(struct fs_dataspace_table *dt, int id)
162{
163    if (id < 0 || id >= FILESERVER_MAX_DATASPACES) {
164        /* Invalid ID. */
165        return NULL;
166    }
167    struct fs_dataspace* ndspace = (struct fs_dataspace*) coat_get(&dt->allocTable, id);
168    if (!ndspace) {
169        /* No such dataspace ID exists. */
170        return NULL;
171    }
172    assert(ndspace->magic == FS_DATASPACE_MAGIC);
173    return ndspace;
174}
175
176struct fs_dataspace*
177dspace_get_badge(struct fs_dataspace_table *dt, int badge)
178{
179    if (badge < FS_DSPACE_BADGE_BASE || badge >= FS_DSPACE_BADGE_BASE + FILESERVER_MAX_DATASPACES) {
180        /* Invalid badge. */
181        return NULL;
182    }
183    return dspace_get(dt, badge - FS_DSPACE_BADGE_BASE);
184}
185
186void
187dspace_delete(struct fs_dataspace_table *dt, int id)
188{
189    coat_free(&dt->allocTable, id);
190}
191
192/* ----------------------------- CPIO Dataspace Functions --------------------------------------- */
193
194/*! @brief Internal unassociation helper function. */
195static void
196dspace_externalID_unassociate(chash_t *ht, int objID)
197{
198    struct dataspace_association_info *di = (struct dataspace_association_info *)
199            chash_get(ht, objID);
200    if (!di) {
201        /* No association structure here to free. */
202        return;
203    }
204    chash_set(ht, objID, (chash_item_t) NULL);
205    if (di->objectCap) {
206        seL4_CNode_Revoke(REFOS_CSPACE, di->objectCap, REFOS_CDEPTH);
207        seL4_CNode_Delete(REFOS_CSPACE, di->objectCap, REFOS_CDEPTH);
208        csfree(di->objectCap);
209    }
210    free(di);
211}
212
213/*! @brief Internal association helper function. */
214static int
215dspace_externalID_associate(chash_t *ht, int objID, int dsID, int dsOffset,
216                            seL4_CPtr cap)
217{
218    dspace_externalID_unassociate(ht, objID);
219    struct dataspace_association_info *di = malloc(sizeof(struct dataspace_association_info));
220    if (!di) {
221        return ENOMEM;
222    }
223    di->dataspaceID = dsID;
224    di->dataspaceOffset = dsOffset;
225    di->objectCap = cap;
226    chash_set(ht, objID, (chash_item_t) di);
227    return ESUCCESS;
228}
229
230int
231dspace_window_associate(struct fs_dataspace_table *dt, int winID, int dsID, int dsOffset,
232                              seL4_CPtr windowCap)
233{
234    return dspace_externalID_associate(&dt->windowAssocTable, winID, dsID, dsOffset, windowCap);
235}
236
237struct dataspace_association_info *
238dspace_window_find(struct fs_dataspace_table *dt, int winID)
239{
240    return (struct dataspace_association_info *) chash_get(&dt->windowAssocTable, winID);
241}
242
243void
244dspace_window_unassociate(struct fs_dataspace_table *dt, int winID)
245{
246    dspace_externalID_unassociate(&dt->windowAssocTable, winID);
247}
248
249int
250dspace_external_associate(struct fs_dataspace_table *dt, int xdsID, int dsID, int dsOffset,
251                                seL4_CPtr xdspaceCap)
252{
253    return dspace_externalID_associate(&dt->dspaceAssocTable, xdsID, dsID, dsOffset, xdspaceCap);
254}
255
256void
257dspace_external_unassociate(struct fs_dataspace_table *dt, int xdsID)
258{
259    dspace_externalID_unassociate(&dt->dspaceAssocTable, xdsID);
260}
261
262struct dataspace_association_info *
263dspace_external_find(struct fs_dataspace_table *dt, int xdsID)
264{
265    return (struct dataspace_association_info *) chash_get(&dt->dspaceAssocTable, xdsID);
266}
267