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, Universitaetstr. 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 * Check if the argument is non-null and of non zero length 41 */ 42static bool arg_valid(const char * a){ 43 return a != NULL && strlen(a) > 0; 44} 45 46/** 47 * Act upon request to create a driver instance. 48 * 49 * \param binding Controller binding 50 * \param cls What class to instantiate? 51 * \param cls_len Ignored. 52 * \param name What name the driver instance should have. 53 * \param nlen Ignored. 54 * \param cap Capabilities for the driver instance. 55 * \param flags Flags for the driver instance. 56 */ 57static void create_handler(struct ddomain_binding* binding, const char* cls, size_t cls_len, 58 const char* name, size_t nlen, 59 const char* a1, size_t a1len, const char* a2, size_t a2len, 60 const char* a3, size_t a3len, const char* a4, size_t a4len, 61 struct capref cap1, struct capref cap2, struct capref cap3, 62 struct capref cap4, struct capref cap5, struct capref cap6, 63 uint64_t flags) { 64 errval_t err; 65 DRIVERKIT_DEBUG("Driver domain got create message from kaluga for cls=%s," 66 "name=%s\n", cls, name); 67 68 iref_t dev = 0, ctrl = 0; 69 70 static size_t NR_CAPS = 6; 71 static size_t NR_ARGS = 4; 72 73 // This array is owned by the driver after create: 74 struct capref* cap_array = calloc(sizeof(struct capref), NR_CAPS); 75 cap_array[0] = cap1; 76 cap_array[1] = cap2; 77 cap_array[2] = cap3; 78 cap_array[3] = cap4; 79 cap_array[4] = cap5; 80 cap_array[5] = cap6; 81 82 struct capref cnodecap; 83 err = slot_alloc_root(&cnodecap); 84 assert(err_is_ok(err)); 85 err = cap_copy(cnodecap, cap_array[0]); 86 struct capref cap0_0 = { 87 .slot = 0, 88 .cnode = build_cnoderef(cnodecap, CNODE_TYPE_OTHER) 89 }; 90 char debug_msg[100]; 91 debug_print_cap_at_capref(debug_msg, sizeof(debug_msg), cap0_0); 92 DRIVERKIT_DEBUG("Received cap0_0=%s\n", debug_msg); 93 94 char** args_array = calloc(sizeof(char*), 4); 95 args_array[0] = arg_valid(a1) ? strdup(a1) : NULL; 96 args_array[1] = arg_valid(a2) ? strdup(a2) : NULL; 97 args_array[2] = arg_valid(a3) ? strdup(a3) : NULL; 98 args_array[3] = arg_valid(a4) ? strdup(a4) : NULL; 99 100 int args_len; 101 for(args_len=0; args_len<NR_ARGS; args_len++) { 102 if(args_array[args_len] == NULL) break; 103 } 104 105 DRIVERKIT_DEBUG("Instantiate driver\n"); 106 err = driverkit_create_driver(cls, name, cap_array, NR_CAPS, args_array, args_len, flags, &dev, &ctrl); 107 if (err_is_fail(err)) { 108 DEBUG_ERR(err, "Instantiating driver failed, report this back to Kaluga." 109 "name=%s, cls=%s\n", name, cls); 110 } 111 112 DRIVERKIT_DEBUG("sending create response to kaluga\n"); 113 err = ddomain_create_response__tx(binding, NOP_CONT, dev, ctrl, err); 114 if (err_is_fail(err)) { 115 USER_PANIC_ERR(err, "Sending reply failed.\n"); 116 } 117} 118 119/** 120 * Destroy an existing driver instance. 121 * 122 * \param binding Controller binding. 123 * \param name Name of the driver instance. 124 * \param len Ignored 125 */ 126static void destroy_handler(struct ddomain_binding* binding, const char* name, size_t len) { 127 DRIVERKIT_DEBUG("Driver domain got destroy message for instance %s\n", name); 128 errval_t err = driverkit_destroy(name); 129 if (err_is_fail(err)) { 130 DEBUG_ERR(err, "Destroying driver failed, report this back to Kaluga."); 131 } 132 133 err = binding->tx_vtbl.destroy_response(binding, NOP_CONT, err); 134 if (err_is_fail(err)) { 135 USER_PANIC_ERR(err, "Sending reply failed."); 136 } 137} 138 139/** 140 * Stubs table for functions to call on driver instance. 141 */ 142static const struct ddomain_rx_vtbl rpc_rx_vtbl = { 143 .create_call = create_handler, 144 .destroy_call = destroy_handler, 145}; 146 147/** 148 * Called if connection to the manager has completed. 149 * 150 * \param st NULL 151 * \param err Connection initiated successfully? 152 * \param b Created binding, this is stored in rpc_bind. 153 */ 154static void rpc_bind_cb(void *st, errval_t err, struct ddomain_binding *b) 155{ 156 b->st = NULL; 157 if (err_is_fail(err)) { 158 DEBUG_ERR(err, "oct_event bind failed"); 159 goto out; 160 } 161 162 DRIVERKIT_DEBUG("Driver domain has connected to ddomain controller service.\n"); 163 rpc_bind.binding = b; 164 rpc_bind.binding->rx_vtbl = rpc_rx_vtbl; 165 166out: 167 assert(!rpc_bind.is_done); 168 rpc_bind.is_done = true; 169 rpc_bind.err = err; 170} 171 172/** 173 * Connects to the driver domain manager. 174 * 175 * \param connect_to iref where to connect. 176 * \retval SYS_ERR_OK Connected to the driver manager. 177 */ 178errval_t ddomain_communication_init(iref_t connect_to, uint64_t ident) 179{ 180 rpc_bind.err = SYS_ERR_OK; 181 rpc_bind.is_done = false; 182 183 errval_t err = ddomain_bind(connect_to, rpc_bind_cb, NULL, get_default_waitset(), IDC_BIND_FLAGS_DEFAULT); 184 if (err_is_fail(err)) { 185 return err; 186 } 187 DRIVERKIT_DEBUG("%s:%s:%d: Trying to connect to kaluga...\n", __FILE__, __FUNCTION__, __LINE__); 188 // XXX: broken 189 while (!rpc_bind.is_done) { 190 messages_wait_and_handle_next(); 191 } 192 193 DRIVERKIT_DEBUG("%s:%s:%d: Send identify %"PRIu64"\n", __FILE__, __FUNCTION__, __LINE__, ident); 194 errval_t send_err = rpc_bind.binding->tx_vtbl.identify(rpc_bind.binding, NOP_CONT, ident); 195 assert(err_is_ok(send_err)); 196 197 return rpc_bind.err; 198} 199