1/** 2 * \file 3 * \brief Driverkit module implementation. 4 * 5 * Contians helper functions to iterate over driver modules in a domain 6 * and create driver instances from driver modules. 7 */ 8/* 9 * Copyright (c) 2016, ETH Zurich. 10 * All rights reserved. 11 * 12 * This file is distributed under the terms in the attached LICENSE file. 13 * If you do not find this file, copies can be found by writing to: 14 * ETH Zurich D-INFK, Universitaetstrasse 6, CH-8092 Zurich. Attn: Systems Group. 15 */ 16#include <stdlib.h> 17 18#include <barrelfish/barrelfish.h> 19#include <driverkit/driverkit.h> 20#include <collections/hash_table.h> 21 22 23#include "debug.h" 24 25#pragma GCC diagnostic ignored "-Wdiscarded-qualifiers" 26 27///< Points to start of the ELF section where the bfdriver structs are. 28extern struct bfdriver bfdrivers_start[]; 29///< Points to the end of the ELF section where the bfdriver structs are. 30extern struct bfdriver bfdrivers_end[]; 31 32static collections_listnode* instances = NULL; 33 34/** 35 * Initializes a pointer to point to the list of all bfdrivers. 36 * 37 * The driver structs are stored in a special ELF section (called .bfdrivers). 38 * The custom link script of the driver domain makes sure there is a bfdrivers_start 39 * and bfdrivers_end symbol at the beginning and end of that section. 40 * 41 * \param[out] start Initialized to point to the first bfdriver instance. 42 * \param[out] num How many drivers there are. 43 */ 44void driverkit_list(struct bfdriver** start, size_t* num) { 45 *start = (struct bfdriver*) bfdrivers_start; 46 *num = ((ptrdiff_t)bfdrivers_end - (ptrdiff_t)bfdrivers_start) / sizeof(struct bfdriver); 47} 48 49/** 50 * Finds a driver instance linked with the driver domain: 51 * \param name The name of the driver we're interested in. 52 * \return bfdriver instance with matching name or NULL in case not found. 53 */ 54struct bfdriver* driverkit_lookup_cls(const char* name) { 55 assert(name != NULL); 56 57 size_t drivers = 0; 58 struct bfdriver* cur = NULL; 59 driverkit_list(&cur, &drivers); 60 61 for (size_t i=0; i<drivers; i++) { 62 if (strcmp(name, cur->name) == 0) { 63 return cur; 64 } 65 cur += 1; 66 } 67 68 return NULL; // not found 69} 70 71/** 72 * Frees a bfdriver instance. Callers need to make sure 73 * that bfi->destroy was called beforehand to clean up 74 * state that is owned by the driver. 75 * 76 * \param arg bfdriver instance. 77 */ 78static void free_driver_instance(void* arg) { 79 assert (arg != NULL); 80 struct bfdriver_instance* bfi = (struct bfdriver_instance*) arg; 81 free(bfi); 82} 83 84/** 85 * Compare driver instance name with supplied argument. 86 * 87 * Helper function for collection_list_* data-structure. 88 * 89 * \param[in] elem bfdriver instance 90 * \param[in] name String 91 * \retval True iff name == bfi->name 92 * \retval False iff name != bfi->name 93 */ 94static int32_t match_name(void* elem, void* name) { 95 assert(elem != NULL); 96 assert(name != NULL); 97 98 struct bfdriver_instance* bfi = (struct bfdriver_instance*) elem; 99 assert (bfi->name != NULL); 100 assert (name != NULL); 101 if (strcmp((char*)name, bfi->name) == 0) { 102 return 1; 103 } 104 else { 105 return 0; 106 } 107} 108 109/** 110 * Destroys a driver instances identified by its name. 111 * \todo various tricky service clean-up issues are simply ignored here. 112 * 113 * \param name Name of the instance 114 * \retval SYS_ER_OK Driver successfully destroyed. 115 * \retval DRIVERKIT_ERR_DRIVER_DETACH detaching failed. 116 */ 117errval_t driverkit_destroy(const char* name) { 118 assert(name != NULL); 119 if (instances == NULL) { 120 collections_list_create(&instances, free_driver_instance); 121 } 122 123 void* namearg = (void*) name; // Get rid of the const because collections_* API is not specific enough... 124 struct bfdriver_instance* bfi = collections_list_find_if(instances, match_name, namearg); 125 errval_t err = bfi->driver->destroy(bfi); 126 if (err_is_ok(err)) { 127 struct bfdriver_instance* bfi2 = (struct bfdriver_instance*) collections_list_remove_if(instances, match_name, namearg); 128 free_driver_instance(bfi2); 129 } 130 else { 131 err = err_push(err, DRIVERKIT_ERR_DRIVER_DETACH); 132 } 133 134 return err; 135} 136 137/** 138 * Destroys a driver instances identified by its name. 139 * \todo various tricky service clean-up issues are simply ignored here. 140 * 141 * \param name Name of the instance 142 * \retval SYS_ER_OK Driver successfully destroyed. 143 * \retval DRIVERKIT_ERR_DRIVER_DETACH detaching failed. 144 */ 145/* 146errval_t driverkit_get_ep(const char* name) { 147 assert(name != NULL); 148 if (instances == NULL) { 149 collections_list_create(&instances, free_driver_instance); 150 } 151 152 void* namearg = (void*) name; // Get rid of the const because collections_* API is not specific enough... 153 struct bfdriver_instance* bfi = collections_list_find_if(instances, match_name, namearg); 154 errval_t err = bfi->driver->destroy(bfi); 155 if (err_is_ok(err)) { 156 struct bfdriver_instance* bfi2 = (struct bfdriver_instance*) collections_list_remove_if(instances, match_name, namearg); 157 free_driver_instance(bfi2); 158 } 159 else { 160 err = err_push(err, DRIVERKIT_ERR_DRIVER_DETACH); 161 } 162 163 return err; 164} 165*/ 166 167/** 168 * Create a driver instance within the driver domain. 169 * 170 * \param[in] cls The class of driver (found in bfdriver). 171 * \param[in] name The name of the driver instance. 172 * \param[in] caps Caps provided to the driver's init function. 173 * \param[in] flags Flags provided to the driver's init function. 174 * \param[out] device iref of the device interface (as created by the device). 175 * \param[out] control endpoint cap of the control interface (created as part of this function). 176 * \return Error status of driver creation. 177 */ 178errval_t driverkit_create_driver(const char* cls, struct bfdriver_instance *inst, 179 uint64_t flags, iref_t* device, struct capref* control) 180{ 181 assert(cls != NULL); 182 assert(device != NULL); 183 assert(inst != NULL); 184 185 errval_t err = SYS_ERR_OK; 186 187 struct bfdriver* drv = driverkit_lookup_cls(cls); 188 if (drv == NULL) { 189 return DRIVERKIT_ERR_NO_DRIVER_FOUND; 190 } 191 DRIVERKIT_DEBUG("Using driver %s for class %s\n", drv->name, cls); 192 193#if defined(ENABLE_DRIVERKIT_DEBUG) 194 { 195 char caps[1024]; 196 for(int i=0; i<16; i++){ 197 struct capref cc = { 198 .cnode = inst->argcn, 199 .slot = i 200 }; 201 debug_print_cap_at_capref(caps, sizeof(caps), cc); 202 debug_printf("[dkit] cap %d = %s\n", i, caps); 203 } 204 } 205#endif 206 207 inst->driver = drv; 208 209 err = drv->init(inst, flags, device); 210 if (err_is_fail(err)) { 211 //DRIVERKIT_DEBUG("Init returned error...\n"); 212 DEBUG_ERR(err, "Can't initialize the device"); 213 free_driver_instance(inst); 214 return err_push(err, DRIVERKIT_ERR_DRIVER_INIT); 215 } 216 217 // Since Kaluga always has to be on core 0, we can do this ... 218 err = dcontrol_service_init(inst, NULL, (disp_get_core_id() == 0), control); 219 if (err_is_fail(err)) { 220 DEBUG_ERR(err, "Can't set-up control interface for device."); 221 free_driver_instance(inst); 222 return err_push(err, DRIVERKIT_ERR_CONTROL_SERVICE_INIT); 223 } 224 225 DRIVERKIT_DEBUG("Driver class %s initialized.\n", drv->name); 226 if (instances == NULL) { 227 collections_list_create(&instances, free_driver_instance); 228 } 229 collections_list_insert(instances, inst); 230 231 return err; 232} 233 234 235errval_t driverkit_local_service_register(char* name, void* tbl) 236{ 237 238 return SYS_ERR_OK; 239} 240 241void* driverkit_local_service_lookup(char* name) 242{ 243 244 return NULL; 245} 246 247static errval_t get_cap(struct bfdriver_instance *bfi, cslot_t slot, struct capref *cap) 248{ 249 if (slot >= DRIVERKIT_ARGCN_SLOT_MAX) { 250 return DRIVERKIT_ERR_CAP_CAPACITY; 251 } 252 253 struct capref dest = { 254 .cnode = bfi->argcn, 255 .slot = slot 256 }; 257 258 *cap = dest; 259 260 return SYS_ERR_OK; 261} 262 263errval_t driverkit_get_interrupt_cap(struct bfdriver_instance *bfi, struct capref *cap) 264{ 265 return get_cap(bfi, DRIVERKIT_ARGCN_SLOT_INT, cap); 266} 267 268errval_t driverkit_get_iommu_cap(struct bfdriver_instance *bfi, struct capref *cap) 269{ 270 return get_cap(bfi, DRIVERKIT_ARGCN_SLOT_IOMMU, cap); 271} 272 273errval_t driverkit_get_pci_cap(struct bfdriver_instance *bfi, struct capref *cap) 274{ 275 return get_cap(bfi, DRIVERKIT_ARGCN_SLOT_PCI_EP, cap); 276} 277 278errval_t driverkit_get_bar_cap(struct bfdriver_instance *bfi, uint8_t idx, 279 struct capref *cap) 280{ 281 if (idx >= 6) { 282 return DRIVERKIT_ERR_CAP_CAPACITY; 283 } 284 return get_cap(bfi, DRIVERKIT_ARGCN_SLOT_BAR0 + idx, cap); 285} 286