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 <driverkit/iommu.h> 21#include <driverkit/hwmodel.h> 22#include <collections/hash_table.h> 23#include <skb/skb.h> 24#include <if/mem_defs.h> 25#include "debug.h" 26#include "../libc/include/namespace.h" 27 28 29__attribute__((unused)) 30static void format_nodelist(int32_t *nodes, char *out){ 31 *out = '\0'; 32 sprintf(out + strlen(out), "["); 33 int first = 1; 34 while(*nodes != 0){ 35 if(!first) sprintf(out + strlen(out), ","); 36 sprintf(out + strlen(out), "%" PRIi32, *nodes); 37 nodes++; 38 first = 0; 39 } 40 sprintf(out + strlen(out), "]"); 41} 42 43void driverkit_parse_namelist(char *in, struct hwmodel_name *names, int *conversions){ 44 assert(in); 45 *conversions = 0; 46 struct list_parser_status status; 47 skb_read_list_init_offset(&status, in, 0); 48 while(skb_read_list(&status, "name(%"SCNu64", %"SCNi32")", 49 &names->address, &names->nodeid)) { 50 debug_printf("parse_namelist: %lx\n", names->address); 51 names++; 52 *conversions += 1; 53 } 54} 55 56#define ALLOC_WRAP_Q "state_get(S)," \ 57 "alloc_wrap(S, %zu, %d, %"PRIi32",%s, NewS)," \ 58 "state_set(NewS)." 59 60errval_t 61driverkit_hwmodel_allocate(size_t bytes, int32_t dstnode, int32_t * nodes, 62 uint8_t alloc_bits, genpaddr_t *retaddr) { 63 errval_t err; 64 65 char nodes_str[128]; 66 format_nodelist(nodes, nodes_str); 67 HWMODEL_QUERY_DEBUG(ALLOC_WRAP_Q, bytes, alloc_bits, dstnode, nodes_str); 68 err = skb_execute_query(ALLOC_WRAP_Q, bytes, alloc_bits, dstnode, nodes_str); 69 if (err_is_fail(err)) { 70 DEBUG_SKB_ERR(err, "failed to query\n"); 71 return err; 72 } 73 74 struct hwmodel_name names[1]; 75 int num_conversions = 0; 76 driverkit_parse_namelist(skb_get_output(), names, &num_conversions); 77 assert(num_conversions == 1); 78 79 80 if (retaddr) { 81 *retaddr = names[0].address; 82 } 83 84 return SYS_ERR_OK; 85 86} 87 88errval_t driverkit_hwmodel_ram_alloc(struct capref *dst, 89 size_t bytes, int32_t dstnode, 90 int32_t *nodes) 91{ 92 93 if (bytes < (LARGE_PAGE_SIZE)) { 94 bytes = LARGE_PAGE_SIZE; 95 } 96 97 98 int bits = log2ceil(bytes); 99 bytes = 1 << bits; 100 assert(bits >= 21); 101 // The PT configuration in the SKB is currently using 2M pages. 102 103#ifdef DISABLE_MODEL 104 if (dstnode != driverkit_hwmodel_lookup_dram_node_id()) { 105 return LIB_ERR_RAM_ALLOC_MS_CONSTRAINTS; 106 } 107 return ram_alloc(dst, bits); 108#else 109 errval_t err; 110 errval_t msgerr; 111 genpaddr_t addr; 112 err = driverkit_hwmodel_allocate(bytes, dstnode, nodes, bits, &addr); 113 if(err_is_fail(err)) { 114 return err; 115 } 116 117 // Alloc cap slot 118 err = slot_alloc(dst); 119 if (err_is_fail(err)) { 120 return err_push(err, LIB_ERR_SLOT_ALLOC); 121 } 122 123 124 struct mem_binding * b = get_mem_client(); 125 debug_printf("Determined addr=0x%"PRIx64" as address for (nodeid=%d, size=%zu) request\n", 126 addr, dstnode, bytes); 127 128 err = b->rpc_tx_vtbl.allocate(b, bits, addr, addr + bytes, 129 &msgerr, dst); 130 if(err_is_fail(err)){ 131 DEBUG_ERR(err, "allocate RPC"); 132 return err; 133 } 134 if(err_is_fail(msgerr)){ 135 DEBUG_ERR(msgerr, "allocate"); 136 return msgerr; 137 } 138 return SYS_ERR_OK; 139 140#endif 141} 142 143errval_t driverkit_hwmodel_frame_alloc(struct capref *dst, 144 size_t bytes, int32_t dstnode, 145 int32_t *nodes) 146{ 147#ifdef DISABLE_MODEL 148 if (dstnode != driverkit_hwmodel_lookup_dram_node_id()) { 149 return LIB_ERR_RAM_ALLOC_MS_CONSTRAINTS; 150 } 151 return frame_alloc(dst, bytes, NULL); 152#else 153 errval_t err; 154 struct capref ram_cap; 155 156 if(bytes < LARGE_PAGE_SIZE) bytes = LARGE_PAGE_SIZE; 157 158 // Allocate RAM cap 159 err = driverkit_hwmodel_ram_alloc(&ram_cap, bytes, dstnode, nodes); 160 if(err_is_fail(err)){ 161 return err; 162 } 163 164 // Alloc cap slot 165 err = slot_alloc(dst); 166 if (err_is_fail(err)) { 167 return err_push(err, LIB_ERR_SLOT_ALLOC); 168 } 169 170 // Get bits 171 assert(bytes > 0); 172 uint8_t bits = log2ceil(bytes); 173 assert((1UL << bits) >= bytes); 174 175 // This is doing what "create_ram_descendant" in 176 // lib/barrelfish/capabilities.c is doing. 177 err = cap_retype(*dst, ram_cap, 0, ObjType_Frame, (1UL << bits), 1); 178 if (err_is_fail(err)) { 179 return err_push(err, LIB_ERR_CAP_RETYPE); 180 } 181 182 err = cap_destroy(ram_cap); 183 if (err_is_fail(err)) { 184 return err_push(err, LIB_ERR_CAP_DESTROY); 185 } 186 187 return SYS_ERR_OK; 188#endif 189} 190 191 192 193 194/** 195 * fills in dmem->vbase + maps frame 196 */ 197errval_t driverkit_hwmodel_vspace_map(int32_t nodeid, struct capref frame, 198 vregion_flags_t flags, struct dmem *dmem) 199{ 200 201#ifdef DISABLE_MODEL 202 return SYS_ERR_OK; 203#else 204 errval_t err; 205 struct frame_identity id; 206 err = frame_identify(frame, &id); 207 if (err_is_fail(err)) { 208 return err; 209 } 210 211 char conf_buf[512]; 212 213 dmem->mem = frame; 214 dmem->size = id.bytes; 215 dmem->devaddr = id.base; 216 217 // Alloc space in my vspace 218 assert(nodeid == driverkit_hwmodel_get_my_node_id()); 219 err = driverkit_hwmodel_get_map_conf(frame, nodeid, conf_buf, sizeof(conf_buf), 220 &dmem->vbase); 221 if(err_is_fail(err)) { 222 DEBUG_ERR(err, "vspace_map local"); 223 return err; 224 } 225 226 uint64_t inaddr, outaddr; 227 int32_t conf_nodeid; 228 struct list_parser_status status; 229 skb_read_list_init_offset(&status, conf_buf, 0); 230 while(skb_read_list(&status, "c(%"SCNi32", %"SCNu64", %"SCNu64")", 231 &conf_nodeid, &inaddr, &outaddr)) { 232 debug_printf("%s:%u %i, %i, inaddr=%lx, vbase=%lx\n", __FUNCTION__, __LINE__, 233 nodeid, conf_nodeid, inaddr, dmem->vbase); 234 235 err = driverkit_hwmodel_vspace_map_fixed(nodeid, dmem->vbase, frame, 236 flags, dmem); 237 if (err_is_fail(err)) { 238 DEBUG_ERR(err, "TODO CLEANUP!"); 239 return err; 240 } 241 } 242 243 return SYS_ERR_OK; 244#endif 245 246} 247 248errval_t driverkit_hwmodel_vspace_map_fixed(int32_t nodeid, 249 genvaddr_t addr, 250 struct capref frame, 251 vregion_flags_t flags, 252 struct dmem *dmem) 253{ 254 errval_t err; 255 256 if(nodeid != driverkit_hwmodel_get_my_node_id()){ 257 return LIB_ERR_NOT_IMPLEMENTED; 258 } 259 260 struct frame_identity id; 261 err = frame_identify(frame, &id); 262 if (err_is_fail(err)) { 263 return err; 264 } 265 266 dmem->vbase = addr; 267 268 return vspace_map_one_frame_fixed_attr(addr, id.bytes, frame, flags, NULL, NULL); 269} 270 271 272#define MAP_WRAP_Q "state_get(S)," \ 273 "map_wrap(S, %zu, 21, %"PRIi32", %"PRIu64", %s, NewS)," \ 274 "state_set(NewS)." 275 276errval_t driverkit_hwmodel_vspace_alloc(struct capref frame, 277 int32_t nodeid, genvaddr_t *addr) 278{ 279 errval_t err; 280 281 struct frame_identity id; 282 err = frame_identify(frame, &id); 283 if (err_is_fail(err)) { 284 return err; 285 } 286 287 int32_t src_nodeid[2]; 288 char src_nodeid_str[128]; 289 src_nodeid[0] = nodeid; 290 src_nodeid[1] = 0; 291 format_nodelist(src_nodeid, src_nodeid_str); 292 293 //int32_t mem_nodeid = id.pasid; 294 int32_t mem_nodeid = driverkit_hwmodel_lookup_dram_node_id(); 295 uint64_t mem_addr = id.base; 296 HWMODEL_QUERY_DEBUG(MAP_WRAP_Q, 297 id.bytes, mem_nodeid, mem_addr, src_nodeid_str); 298 err = skb_execute_query(MAP_WRAP_Q, 299 id.bytes, mem_nodeid, mem_addr, src_nodeid_str); 300 if(err_is_fail(err)){ 301 DEBUG_SKB_ERR(err, "map_wrap"); 302 return err; 303 } 304 305 struct hwmodel_name names[2]; 306 int num_conversions = 0; 307 driverkit_parse_namelist(skb_get_output(), names, &num_conversions); 308 assert(num_conversions == 2); 309 //ignore, names[0] it is the resolved name as stored in frame 310 *addr = names[1].address; 311 debug_printf("Determined addr=0x%"PRIx64" as vbase for (nodeid=%d, size=%zu) request\n", 312 *addr, nodeid, id.bytes); 313 return SYS_ERR_OK; 314} 315 316/* 317 * Returns this process nodeid. It lazily adds the process' model node 318 * and returns it's identifier. 319 */ 320int32_t driverkit_hwmodel_get_my_node_id(void) 321{ 322 errval_t err; 323 324 err = skb_client_connect(); 325 if (err_is_fail(err)) { 326 return -1; 327 } 328 /* 329 * XXX: this assumes the domain only runs on a single core! 330 */ 331 static int32_t nodeid = -1; 332 333 if(nodeid == -1){ 334 HWMODEL_QUERY_DEBUG( 335 "state_get(S), " 336 "add_process(S, E, NewS), writeln(E), " 337 "state_set(NewS)"); 338 err = skb_execute_query( 339 "state_get(S), " 340 "add_process(S, E, NewS), writeln(E), " 341 "state_set(NewS)"); 342 if (err_is_fail(err)) { 343 DEBUG_SKB_ERR(err, "add_process"); 344 return -1; 345 } 346 err = skb_read_output("%d", &nodeid); 347 assert(err_is_ok(err)); 348 DRIVERKIT_DEBUG("Instantiated new process model node, nodeid=%"PRIi32"\n", 349 nodeid); 350 } 351 return nodeid; 352} 353 354int32_t driverkit_hwmodel_lookup_dram_node_id(void) 355{ 356#ifdef DISABLE_MODEL 357 return 1; 358#else 359 return driverkit_hwmodel_lookup_node_id("[\"DRAM\"]"); 360#endif 361} 362 363int32_t driverkit_hwmodel_lookup_pcibus_node_id(void) 364{ 365 return driverkit_hwmodel_lookup_node_id("[\"PCIBUS\"]"); 366} 367 368 369int32_t driverkit_hwmodel_lookup_node_id(const char *path) 370{ 371 372 debug_printf("%s:%u with path='%s'\n", __FUNCTION__, __LINE__, path); 373 374 errval_t err; 375 HWMODEL_QUERY_DEBUG( 376 "node_enum(%s, E), writeln(E)", 377 path); 378 err = skb_execute_query( 379 "node_enum(%s, E), writeln(E)", 380 path); 381 if (err_is_fail(err)) { 382 DEBUG_SKB_ERR(err, "query node_enum"); 383 } 384 int32_t nodeid; 385 err = skb_read_output("%d", &nodeid); 386 assert(err_is_ok(err)); 387 return nodeid; 388} 389 390#define REVERSE_RESOLVE_Q "state_get(S)," \ 391 "reverse_resolve_wrap(S, %"PRIi32", %"PRIu64", %zu, %"PRIi32")." 392 393#define FORMAT "[\"KNC_SOCKET\", \"PCI0\", %d]" 394 395// Without reconfiguration, under what ret_addr can you reach dst 396// from nodeid? 397errval_t driverkit_hwmodel_reverse_resolve(struct capref dst, int32_t nodeid, 398 genpaddr_t *ret_addr) 399{ 400 401 errval_t err; 402 struct frame_identity id; 403 err = frame_identify(dst, &id); 404 if (err_is_fail(err)) { 405 return err; 406 } 407 assert(ret_addr); 408#ifdef DISABLE_MODEL 409 *ret_addr = id.base; 410 return SYS_ERR_OK; 411#else 412 int dst_enum = id.pasid; 413 dst_enum = driverkit_hwmodel_lookup_pcibus_node_id(); 414 415 assert(nodeid < 100); 416 char buf[sizeof(FORMAT)]; 417 snprintf(buf, sizeof(buf), FORMAT, nodeid); 418 419 nodeid = driverkit_hwmodel_lookup_node_id(buf); 420 421 HWMODEL_QUERY_DEBUG(REVERSE_RESOLVE_Q, dst_enum, id.base, id.bytes, nodeid); 422 err = skb_execute_query(REVERSE_RESOLVE_Q, dst_enum, id.base, id.bytes, nodeid); 423 424 DEBUG_SKB_ERR(err, "reverse_resolve"); 425 if(err_is_fail(err)){ 426 DEBUG_SKB_ERR(err, "reverse_resolve"); 427 return err; 428 } 429 430 struct hwmodel_name names[1]; 431 int num_conversions = 0; 432 driverkit_parse_namelist(skb_get_output(), names, &num_conversions); 433 assert(num_conversions == 1); 434 *ret_addr = names[0].address; 435 436 debug_printf("Determined (0x%"PRIx64", %d) is alias of (0x%"PRIx64", %d)\n", 437 names[0].address, nodeid, id.base, dst_enum); 438 439 return SYS_ERR_OK; 440#endif 441} 442 443 444#define MAP_WRAP_Q "state_get(S)," \ 445 "map_wrap(S, %zu, 21, %"PRIi32", %"PRIu64", %s, NewS)," \ 446 "state_set(NewS)." 447 448errval_t driverkit_hwmodel_get_map_conf_addr(int32_t mem_nodeid, genpaddr_t addr, 449 gensize_t size, int32_t nodeid, 450 char *ret_conf, size_t ret_conf_size, 451 lvaddr_t *ret_addr) 452{ 453 errval_t err; 454#ifdef DISABLE_MODEL 455 return SYS_ERR_OK; 456#endif 457 458 debug_printf("%s:%d: alias_conf request addr=0x%"PRIx64", size=%"PRIuGENSIZE"\n", 459 __FUNCTION__, __LINE__, addr, size); 460 461 462 463 int32_t src_nodeid[2]; 464 char src_nodeid_str[128]; 465 src_nodeid[0] = nodeid; 466 src_nodeid[1] = 0; 467 format_nodelist(src_nodeid, src_nodeid_str); 468 469 for(int tries=0; tries<3; tries++){ 470 HWMODEL_QUERY_DEBUG(MAP_WRAP_Q, size, mem_nodeid, addr, src_nodeid_str); 471 err = skb_execute_query(MAP_WRAP_Q, size, mem_nodeid, addr, src_nodeid_str); 472 if(err_is_ok(err)) break; 473 } 474 if (err_is_fail(err)) { 475 DEBUG_SKB_ERR(err, "alias_conf \n"); 476 return err; 477 } 478 479 // Determine and copy conf line (second output line) 480 char * confline = strstr(skb_get_output(), "\n"); 481 assert(confline); 482 if(ret_conf){ 483 strncpy(ret_conf, confline + 1, ret_conf_size); 484 } 485 486 debug_printf("retbuf=%p, %s\n", ret_conf, confline); 487 488 // Parse names 489 *confline = 0; 490 struct hwmodel_name names[2]; 491 int conversions; 492 driverkit_parse_namelist(skb_get_output(), names, &conversions); 493 debug_printf("Conversions = %d\n", conversions); 494 495 496 if(ret_addr) *ret_addr = names[1].address; 497 498 return SYS_ERR_OK; 499} 500 501/** 502 * Makes dst visible to nodeid, assuming the configuration returned 503 * in ret_conf will be installed. 504 */ 505errval_t driverkit_hwmodel_get_map_conf(struct capref dst, 506 int32_t nodeid, 507 char *ret_conf, size_t ret_conf_size, 508 lvaddr_t *ret_addr) 509{ 510#ifdef DISABLE_MODEL 511 return SYS_ERR_OK; 512#else 513 struct frame_identity id; 514 errval_t err; 515 err = frame_identify(dst, &id); 516 if (err_is_fail(err)) { 517 return err; 518 } 519 520 int32_t mem_nodeid = driverkit_hwmodel_lookup_pcibus_node_id(); 521 522 return driverkit_hwmodel_get_map_conf_addr(mem_nodeid, id.base, id.bytes, 523 nodeid, ret_conf, ret_conf_size, ret_addr); 524#endif 525} 526