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-util/serv_connect.h>
19#include <refos-util/cspace.h>
20
21/*! @file
22    @brief Server client connection module implementation. */
23
24static cvector_item_t
25client_oat_create(coat_t *oat, int id, uint32_t arg[COAT_ARGS])
26{
27    struct srv_client_table *ct = ((struct srv_client_table*) oat);
28    assert(ct && ct->magic == SRC_CLIENT_LIST_MAGIC);
29
30    /* Allocate and set up new client structure. */
31    struct srv_client *nclient = malloc(sizeof(struct srv_client));
32    if (!nclient) {
33        printf("ERROR: client_oat_create out of memory!\n");
34        return NULL;
35    }
36    memset(&nclient->rpcClient, 0, sizeof(nclient->rpcClient));
37    nclient->magic = ct->clientMagic;
38    nclient->cID = id;
39    nclient->liveness = arg[0];
40    nclient->deathID = -1;
41    nclient->paramBufferStart = 0;
42    nclient->paramBuffer = 0;
43
44    /* Mint a session cap. */
45    nclient->session = csalloc();
46    if (!nclient->session) {
47        printf("ERROR: could not not allocate cslot.\n");
48        goto exit1;
49    }
50    int error = seL4_CNode_Mint (
51            REFOS_CSPACE, nclient->session, REFOS_CDEPTH,
52            REFOS_CSPACE, ct->sessionSrcEP, REFOS_CDEPTH,
53            seL4_NoRead,
54            seL4_CapData_Badge_new(nclient->cID + ct->badgeBase)
55    );
56    if (error != seL4_NoError) {
57        printf("ERROR: failed to mint client session cap.\n");
58        goto exit2;
59    }
60
61    return (cvector_item_t) nclient;
62
63    /* Exit stack. */
64exit2:
65    csfree(nclient->session);
66exit1:
67    assert(nclient);
68    free(nclient);
69    return NULL;
70}
71
72static void
73client_oat_delete(coat_t *oat, cvector_item_t *obj)
74{
75    struct srv_client_table *ct = ((struct srv_client_table*) oat);
76    assert(ct && ct->magic == SRC_CLIENT_LIST_MAGIC);
77    (void) ct;
78
79    struct srv_client *client = (struct srv_client *) obj;
80    assert(client && client->magic == ct->clientMagic);
81
82    /* Clean up client info from cspace. */
83    if (client->liveness) {
84        //seL4_CNode_Revoke(REFOS_CSPACE, client->liveness, REFOS_CDEPTH); // FIXME REVOKE BUG
85        seL4_CNode_Delete(REFOS_CSPACE, client->liveness, REFOS_CDEPTH);
86        csfree(client->liveness);
87    }
88    if (client->session) {
89        //seL4_CNode_Revoke(REFOS_CSPACE, client->session, REFOS_CDEPTH); // FIXME REVOKE BUG
90        seL4_CNode_Delete(REFOS_CSPACE, client->session, REFOS_CDEPTH);
91        csfree(client->session);
92    }
93
94    if (client->paramBuffer) {
95        //seL4_CNode_Revoke(REFOS_CSPACE, client->paramBuffer, REFOS_CDEPTH); // FIXME REVOKE BUG
96        seL4_CNode_Delete(REFOS_CSPACE, client->paramBuffer, REFOS_CDEPTH);
97        csfree(client->paramBuffer);
98    }
99
100    /* Finally, free the entire structure. */
101    free(client);
102}
103
104void
105client_table_init(struct srv_client_table *ct, int maxClients, int badgeBase, uint32_t magic,
106                  seL4_CPtr sessionSrcEP)
107{
108    ct->magic = SRC_CLIENT_LIST_MAGIC;
109    ct->maxClients = maxClients;
110    ct->clientMagic = magic;
111    ct->badgeBase = badgeBase;
112    ct->sessionSrcEP = sessionSrcEP;
113
114    /* Configure the object allocation table creation / deletion callback func pointers. */
115    ct->allocTable.oat_expand = NULL;
116    ct->allocTable.oat_create = client_oat_create;
117    ct->allocTable.oat_delete = client_oat_delete;
118
119    /* Initialise our data structures. */
120    coat_init(&ct->allocTable, 1, ct->maxClients);
121    cvector_init(&ct->pendingFreeList);
122}
123
124void
125client_table_release(struct srv_client_table *ct)
126{
127    coat_release(&ct->allocTable);
128    cvector_free(&ct->pendingFreeList);
129}
130
131void
132client_table_postaction(struct srv_client_table *ct)
133{
134    /* Actually delete all the clients on the pending free list. */
135    int len = cvector_count(&ct->pendingFreeList);
136    for (int i = 0; i < len; i++) {
137        /* Actually delete this client. */
138        int id = (int) cvector_get(&ct->pendingFreeList, i);
139        if (!client_get(ct, id)) {
140            assert(!"Client in pending free list doesn't exist. Book keeping error.");
141            continue;
142        }
143        coat_free(&ct->allocTable, id);
144    }
145    /* Clear the pending free list. */
146    cvector_reset(&ct->pendingFreeList);
147}
148
149struct srv_client*
150client_alloc(struct srv_client_table *ct, seL4_CPtr liveness)
151{
152    struct srv_client* nclient = NULL;
153    uint32_t arg[COAT_ARGS];
154    arg[0] = liveness;
155
156    /* Allocate an ID, and the client structure associated with it. */
157    int ID = coat_alloc(&ct->allocTable, arg, (cvector_item_t *) &nclient);
158    if (!nclient) {
159        printf("ERROR: client_alloc couldn't allocate a client ID.\n");
160        return NULL;
161    }
162
163    assert(ID != COAT_INVALID_ID);
164    assert(nclient->magic == ct->clientMagic);
165    (void) ID;
166    return nclient;
167}
168
169struct srv_client*
170client_get(struct srv_client_table *ct, int id)
171{
172    if (id < 0 || id >= ct->maxClients) {
173        /* Invalid ID. */
174        return NULL;
175    }
176    struct srv_client* nclient = (struct srv_client*) coat_get(&ct->allocTable, id);
177    if (!nclient) {
178        /* No such client ID exists. */
179        return NULL;
180    }
181    assert(nclient->magic == ct->clientMagic);
182    return nclient;
183}
184
185struct srv_client*
186client_get_badge(struct srv_client_table *ct, int badge)
187{
188    if (badge < ct->badgeBase || badge >= ct->badgeBase + ct->maxClients) {
189        return NULL;
190    }
191    return client_get(ct, badge - ct->badgeBase );
192}
193
194void
195client_queue_delete(struct srv_client_table *ct, int id)
196{
197    /* Sanity check on the given ID. */
198    if (!client_get(ct, id)) {
199        return;
200    }
201    int len = cvector_count(&ct->pendingFreeList);
202    for (int i = 0; i < len; i++) {
203        int cid = (int) cvector_get(&ct->pendingFreeList, i);
204        if (id == cid) {
205            /* Client already queued for deletion. Ignore. */
206            return;
207        }
208    }
209    /* Queue this client ID up to be deleted. */
210    cvector_add(&ct->pendingFreeList, (cvector_item_t) id);
211}
212
213int
214client_queue_delete_deathID(struct srv_client_table *ct, int deathID)
215{
216    for (int i = 0; i < ct->maxClients; i++) {
217        struct srv_client *c = client_get(ct, i);
218        if (c && c->deathID == deathID) {
219            client_queue_delete(ct, c->cID);
220            return 0;
221        }
222    }
223    return -1;
224}
225