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