1/**
2 * \brief Implements the handler function for a driver domain
3 * to act upon requests from a device manager (i.e., Kaluga).
4 *
5 * The stubs will create, destroy driver instances using functions
6 * mainly found in `modules.c` of this library.
7 */
8
9/*
10 * Copyright (c) 2016, ETH Zurich.
11 * All rights reserved.
12 *
13 * This file is distributed under the terms in the attached LICENSE file.
14 * If you do not find this file, copies can be found by writing to:
15 * ETH Zurich D-INFK, Universitaetstrasse 6, CH-8092 Zurich. Attn: Systems Group.
16 */
17#include <stdlib.h>
18#include <stdio.h>
19#include <string.h>
20#include <assert.h>
21
22#include <barrelfish/barrelfish.h>
23#include <barrelfish/nameservice_client.h>
24
25#include <driverkit/driverkit.h>
26
27#include <if/ddomain_defs.h>
28#include "debug.h"
29
30/**
31 * State for connection.
32 */
33static struct bind_state {
34    struct ddomain_binding* binding;
35    bool is_done;
36    errval_t err;
37} rpc_bind;
38
39/**
40 * Act upon request to create a driver instance.
41 *
42 * \param binding Controller binding
43 * \param cls     What class to instantiate?
44 * \param cls_len Ignored.
45 * \param name    What name the driver instance should have.
46 * \param nlen    Ignored.
47 * \param cap     Capabilities for the driver instance.
48 * \param flags   Flags for the driver instance.
49 */
50static void create_handler(struct ddomain_binding* binding, const char* cls, size_t cls_len,
51                           const char* name, size_t nlen,
52                           const char* a1, size_t a1len, const char* a2, size_t a2len,
53                           const char* a3, size_t a3len, const char* a4, size_t a4len,
54                           struct capref cap1, struct capref cap2, struct capref cap3,
55                           struct capref cap4, struct capref cap5,  struct capref cap6,
56                           uint64_t flags) {
57    errval_t err;
58    DRIVERKIT_DEBUG("Driver domain got create message from kaluga for cls=%s,"
59            "name=%s\n", cls, name);
60
61    iref_t dev = 0;
62
63    struct bfdriver_instance* inst = calloc(1, sizeof(struct bfdriver_instance));
64    if (inst == NULL) {
65        err = LIB_ERR_MALLOC_FAIL;
66        goto send_reply;
67    }
68
69    inst->capc = 0;
70    if (!capref_is_null(cap1)) {
71        inst->caps[inst->capc++] = cap1;
72    }
73    if (!capref_is_null(cap2)) {
74        inst->caps[inst->capc++] = cap2;
75    }
76    if (!capref_is_null(cap3)) {
77        inst->caps[inst->capc++] = cap3;
78    }
79    if (!capref_is_null(cap4)) {
80        inst->caps[inst->capc++] = cap4;
81    }
82    if (!capref_is_null(cap5)) {
83        inst->caps[inst->capc++] = cap5;
84    }
85    if (!capref_is_null(cap6)) {
86        inst->caps[inst->capc++] = cap6;
87    }
88
89    inst->argcn_cap = NULL_CAP;
90    inst->argcn = NULL_CNODE;
91
92    /* Copy the arguments to our own memory */
93    inst->argc = 0;
94    if (a1len) {
95        strncpy(inst->_argv[0], a1, a1len < sizeof(inst->_argv[0]) ? a1len: sizeof(inst->_argv[0]));
96        inst->argv[inst->argc++] = inst->_argv[0];
97    } else {
98        inst->argv[0] = NULL;
99    }
100    if (a2len) {
101        strncpy(inst->_argv[1], a2, a2len < sizeof(inst->_argv[1]) ? a2len: sizeof(inst->_argv[1]));
102        inst->argv[inst->argc++] = inst->_argv[1];
103    } else {
104        inst->argv[1] = NULL;
105    }
106    if (a3len){
107        strncpy(inst->_argv[2], a3, a3len < sizeof(inst->_argv[2]) ? a3len: sizeof(inst->_argv[2]));
108        inst->argv[inst->argc++] = inst->_argv[2];
109    } else {
110        inst->argv[2] = NULL;
111    }
112    if (a4len) {
113        strncpy(inst->_argv[3], a4, a4len < sizeof(inst->_argv[3]) ? a4len: sizeof(inst->_argv[3]));
114        inst->argv[inst->argc++] = inst->_argv[3];
115    } else {
116        inst->argv[3] = NULL;
117    }
118
119    strncpy(inst->name, name, 256);
120
121    err = slot_alloc(&inst->ctrl);
122    if (err_is_fail(err)){
123        DEBUG_ERR(err, "Instantiating driver failed, report this back to Kaluga."
124                "name=%s, cls=%s\n", name, cls);
125        free(inst);
126        goto send_reply;
127    }
128
129    DRIVERKIT_DEBUG("Instantiate driver\n");
130    err = driverkit_create_driver(cls, inst, flags, &dev, &inst->ctrl);
131    if (err_is_fail(err)) {
132        DEBUG_ERR(err, "Instantiating driver failed, report this back to Kaluga."
133                "name=%s, cls=%s\n", name, cls);
134        cap_destroy(inst->ctrl);
135        free(inst);
136    }
137
138    send_reply:
139
140    DRIVERKIT_DEBUG("sending create response to kaluga\n");
141    err = ddomain_create_response__tx(binding, NOP_CONT, dev, inst->ctrl, err);
142    if (err_is_fail(err)) {
143        DEBUG_ERR(err, "Sending reply failed.\n");
144        /* TODO: handle error */
145    }
146}
147
148static void create_with_argcn_handler(struct ddomain_binding* binding,
149                                      const char* cls, size_t cls_len,
150                                      const char* name, size_t nlen,
151                                      const char* a1, size_t a1len,
152                                      const char* a2, size_t a2len,
153                                      const char* a3, size_t a3len,
154                                      const char* a4, size_t a4len,
155                                      struct capref argcn,
156                                      uint64_t flags)
157{
158    errval_t err;
159    DRIVERKIT_DEBUG("Driver domain got create message from kaluga for cls=%s,"
160                            "name=%s\n", cls, name);
161
162    iref_t dev = 0;
163
164    struct bfdriver_instance* inst = calloc(1, sizeof(struct bfdriver_instance));
165    if (inst == NULL) {
166        err = LIB_ERR_MALLOC_FAIL;
167        goto send_reply;
168    }
169
170    err = slot_alloc_root(&inst->argcn_cap);
171    if (err_is_fail(err)) {
172        free(inst);
173        goto send_reply;
174    }
175
176    err = cap_copy(inst->argcn_cap, argcn);
177    if (err_is_fail(err)) {
178        DEBUG_ERR(err, "cannot copy argcn cap to root node\n");
179        slot_free(inst->argcn_cap);
180        free(inst);
181        goto send_reply;
182    }
183    inst->capc = 0;
184    inst->argcn = build_cnoderef(inst->argcn_cap, CNODE_TYPE_OTHER);
185
186    /* Copy the arguments to our own memory */
187    inst->argc = 0;
188    if (a1len) {
189        strncpy(inst->_argv[0], a1, a1len < sizeof(inst->_argv[0]) ? a1len: sizeof(inst->_argv[0]));
190        inst->argv[inst->argc++] = inst->_argv[0];
191    } else {
192        inst->argv[0] = NULL;
193    }
194    if (a2len) {
195        strncpy(inst->_argv[1], a2, a2len < sizeof(inst->_argv[1]) ? a2len: sizeof(inst->_argv[1]));
196        inst->argv[inst->argc++] = inst->_argv[1];
197    } else {
198        inst->argv[1] = NULL;
199    }
200    if (a3len){
201        strncpy(inst->_argv[2], a3, a3len < sizeof(inst->_argv[2]) ? a3len: sizeof(inst->_argv[2]));
202        inst->argv[inst->argc++] = inst->_argv[2];
203    } else {
204        inst->argv[2] = NULL;
205    }
206    if (a4len) {
207        strncpy(inst->_argv[3], a4, a4len < sizeof(inst->_argv[3]) ? a4len: sizeof(inst->_argv[3]));
208        inst->argv[inst->argc++] = inst->_argv[3];
209    } else {
210        inst->argv[3] = NULL;
211    }
212
213    err = slot_alloc(&inst->ctrl);
214    if (err_is_fail(err)){
215        DEBUG_ERR(err, "Instantiating driver failed, report this back to Kaluga."
216                "name=%s, cls=%s\n", name, cls);
217        cap_destroy(inst->argcn_cap);
218        free(inst);
219        goto send_reply;
220    }
221
222    strncpy(inst->name, name, 256);
223
224    DRIVERKIT_DEBUG("Instantiate driver\n");
225    err = driverkit_create_driver(cls, inst, flags, &dev, &inst->ctrl);
226    if (err_is_fail(err)) {
227        DEBUG_ERR(err, "Instantiating driver failed, report this back to Kaluga."
228                "name=%s, cls=%s\n", name, cls);
229        cap_destroy(inst->argcn_cap);
230        slot_free(inst->ctrl);
231        free(inst);
232    }
233
234    send_reply:
235
236    DRIVERKIT_DEBUG("sending create response to kaluga\n");
237    err = ddomain_create_with_argcn_response__tx(binding, NOP_CONT, dev, inst->ctrl,
238                                                 err);
239    if (err_is_fail(err)) {
240        USER_PANIC_ERR(err, "Sending reply failed.\n");
241        cap_destroy(inst->argcn_cap);
242        slot_free(inst->ctrl);
243        free(inst);
244    }
245}
246
247/**
248 * Destroy an existing driver instance.
249 *
250 * \param binding Controller binding.
251 * \param name    Name of the driver instance.
252 * \param len     Ignored
253 */
254static void destroy_handler(struct ddomain_binding* binding, const char* name, size_t len) {
255    DRIVERKIT_DEBUG("Driver domain got destroy message for instance %s\n", name);
256    errval_t err = driverkit_destroy(name);
257    if (err_is_fail(err)) {
258        DEBUG_ERR(err, "Destroying driver failed, report this back to Kaluga.");
259    }
260
261    err = binding->tx_vtbl.destroy_response(binding, NOP_CONT, err);
262    if (err_is_fail(err)) {
263        USER_PANIC_ERR(err, "Sending reply failed.");
264    }
265}
266
267/**
268 * Stubs table for functions to call on driver instance.
269 */
270static const struct ddomain_rx_vtbl rpc_rx_vtbl = {
271    .create_call = create_handler,
272    .create_with_argcn_call = create_with_argcn_handler,
273    .destroy_call = destroy_handler,
274};
275
276/**
277 * Called if connection to the manager has completed.
278 *
279 * \param st  NULL
280 * \param err Connection initiated successfully?
281 * \param b   Created binding, this is stored in rpc_bind.
282 */
283static void rpc_bind_cb(void *st, errval_t err, struct ddomain_binding *b)
284{
285    b->st = NULL;
286    if (err_is_fail(err)) {
287        DEBUG_ERR(err, "oct_event bind failed");
288        goto out;
289    }
290
291    DRIVERKIT_DEBUG("Driver domain has connected to ddomain controller service.\n");
292    rpc_bind.binding = b;
293    rpc_bind.binding->rx_vtbl = rpc_rx_vtbl;
294out:
295    assert(!rpc_bind.is_done);
296    rpc_bind.is_done = true;
297    rpc_bind.err = err;
298}
299
300/**
301 * Connects to the driver domain manager.
302 *
303 * \param  connect_to iref where to connect.
304 * \retval SYS_ERR_OK Connected to the driver manager.
305 */
306errval_t ddomain_communication_init(iref_t connect_to, uint64_t ident)
307{
308    rpc_bind.err = SYS_ERR_OK;
309    rpc_bind.is_done = false;
310
311    errval_t err = ddomain_bind(connect_to, rpc_bind_cb, NULL, get_default_waitset(), IDC_BIND_FLAGS_DEFAULT);
312    if (err_is_fail(err)) {
313        return err;
314    }
315    DRIVERKIT_DEBUG("%s:%s:%d: Trying to connect to kaluga...\n", __FILE__, __FUNCTION__, __LINE__);
316    // XXX: broken
317    while (!rpc_bind.is_done) {
318        messages_wait_and_handle_next();
319    }
320
321    DRIVERKIT_DEBUG("%s:%s:%d: Send identify %"PRIu64"\n", __FILE__, __FUNCTION__, __LINE__, ident);
322    errval_t send_err = rpc_bind.binding->tx_vtbl.identify(rpc_bind.binding, NOP_CONT, ident);
323    assert(err_is_ok(send_err));
324
325    return rpc_bind.err;
326}
327