1/** 2 * \file 3 * \brief Boot module for the Xeon Phi 4 * 5 * Loads the co processor OS onto the card and boots it 6 */ 7 8/* 9 * Copyright (c) 2014 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, Universitaetsstrasse 6, CH-8092 Zurich. Attn: Systems Group. 15 */ 16 17#include <stdio.h> 18#include <string.h> 19#include <barrelfish/barrelfish.h> 20#include <barrelfish/nameservice_client.h> 21#include <barrelfish/spawn_client.h> 22 23#include <flounder/flounder_txqueue.h> 24 25#include <if/interphi_defs.h> 26#include <if/mem_defs.h> 27 28#include <xeon_phi/xeon_phi.h> 29#include <xeon_phi/xeon_phi_domain.h> 30 31#include "xeon_phi_internal.h" 32#include "interphi.h" 33#include "smpt.h" 34#include "domain.h" 35#include "service.h" 36#include "xphi_service.h" 37#include "sysmem_caps.h" 38 39/** 40 * represents the information for the messaging channel between the host and 41 * the card. 42 */ 43struct msg_info 44{ 45 struct capref frame; 46 struct interphi_frameinfo fi; 47 struct interphi_binding *binding; 48 struct tx_queue queue; 49 errval_t rpc_err; 50 uint64_t rpc_data; 51 uint64_t rpc_data2; 52 uint8_t is_client; 53 uint8_t wait_reply; 54}; 55 56/* 57 * 58 */ 59struct interphi_msg_st 60{ 61 struct txq_msg_st common; 62 /* union of arguments */ 63 union 64 { 65 struct 66 { 67 uint8_t core; 68 char *cmdline; 69 size_t cmdlen; 70 uint8_t flags; 71 uint64_t cap_base; 72 uint8_t cap_size_bits; 73 } spawn_call; 74 struct 75 { 76 uint64_t domainid; 77 } spawn_reply; 78 struct 79 { 80 uint64_t domainid; 81 } kill; 82 struct 83 { 84 uint64_t base; 85 uint64_t offset; 86 uint8_t bits; 87 uint8_t xid; 88 uint8_t is_client; 89 } bootstrap; 90 struct 91 { 92 lpaddr_t msgbase; 93 uint8_t msgbits; 94 char *iface; 95 xphi_dom_id_t source; 96 uint64_t usrdata; 97 xphi_dom_id_t target; 98 xphi_chan_type_t type; 99 } open; 100 struct 101 { 102 const char *name; 103 xphi_dom_id_t domid; 104 uintptr_t state; 105 } domain; 106 struct { 107 uint64_t base; 108 uint64_t bytes; 109 errval_t err; 110 } alloc; 111 } args; 112}; 113 114 115/* 116 * XXX: hack. just keep track of the frames for now and return them later 117 * for the paper usecase! 118 */ 119struct mem_reg 120{ 121 struct mem_reg *next; 122 struct capref cap; 123 struct frame_identity id; 124}; 125 126static struct mem_reg *allocated_mem; 127 128/* 129 * --------------------------------------------------------------------------- 130 * RPC management 131 * --------------------------------------------------------------------------- 132 */ 133 134/** 135 * \brief starts a new RPC to the inter Xeon Phi connection 136 * 137 * \param mi Xeon Phi message info 138 * 139 * \returns 1 if the RPC transaction could be started 140 * 0 if there was already a transaction in process 141 */ 142static inline uint8_t rpc_start(struct msg_info *mi) 143{ 144 if (!mi->wait_reply) { 145 mi->wait_reply = 0x1; 146 return 1; 147 } 148 return 0; 149} 150 151/** 152 * \brief waits until the started transaction is finished 153 * 154 * \param mi Xeon Phi message info 155 */ 156static inline void rpc_wait_done(struct msg_info *mi) 157{ 158 159 while (mi->wait_reply) { 160#ifndef __k1om__ 161 162 struct xnode *node = mi->binding->st; 163 164 errval_t err; 165 uint32_t data = 0x0; 166 uint32_t serial_recv = 0xF; 167 while (serial_recv--) { 168 data |= xeon_phi_serial_handle_recv(node->local); 169 } 170 171 err = event_dispatch_non_block(get_default_waitset()); 172 switch (err_no(err)) { 173 case SYS_ERR_OK: 174 break; 175 case LIB_ERR_NO_EVENT: 176 if (!data) { 177 thread_yield(); 178 } 179 break; 180 default: 181 USER_PANIC_ERR(err, "in event dispatch\n"); 182 break; 183 } 184 185#else 186 messages_wait_and_handle_next(); 187#endif 188 } 189} 190 191/** 192 * \brief signals the completion of the RPC 193 * 194 * \param mi Xeon Phi message info 195 */ 196static inline void rpc_done(struct msg_info *mi) 197{ 198 mi->wait_reply = 0x0; 199} 200 201static struct txq_msg_st *rpc_preamble(struct msg_info *mi) 202{ 203 assert(mi); 204 205 if (mi->binding == NULL) { 206 assert(!"NYI"); 207 } 208 209 if (!rpc_start(mi)) { 210 XINTER_DEBUG("waiting until previous rpc is finished\n"); 211 rpc_wait_done(mi); 212 rpc_start(mi); 213 } 214 215 mi->rpc_err = SYS_ERR_OK; 216 mi->rpc_data = 0x0; 217 218 struct txq_msg_st *msg_st = txq_msg_st_alloc(&mi->queue); 219 if (msg_st == NULL) { 220 rpc_done(mi); 221 } 222 223 msg_st->cleanup = NULL; 224 225 return msg_st; 226} 227 228/* 229 * ---------------------------------------------------------------------------- 230 * Helper functions 231 * ---------------------------------------------------------------------------- 232 */ 233static errval_t spawn_cmdline_extract_argv(char *cmdline, 234 size_t cmdlen, 235 char *argv[], 236 uint8_t argcmax) 237{ 238 int i = 0; 239 size_t pos = 0; 240 while (pos < cmdlen && i < argcmax) { 241 argv[i++] = &cmdline[pos]; 242 char *end = memchr(&cmdline[pos], '\0', cmdlen - pos); 243 if (end == NULL) { 244 return SPAWN_ERR_GET_CMDLINE_ARGS; 245 246 } 247 pos = end - cmdline + 1; 248 } 249 assert(i <= argcmax); 250 argv[i] = NULL; 251 252 return SYS_ERR_OK; 253} 254 255/* 256 * ---------------------------------------------------------------------------- 257 * Message Send Handlers 258 * ---------------------------------------------------------------------------- 259 */ 260 261#ifdef __k1om__ 262 263static errval_t domain_wait_call_tx(struct txq_msg_st *msg_st) 264{ 265 struct interphi_msg_st *st = (struct interphi_msg_st *) msg_st; 266 267 size_t length = strlen(st->args.domain.name) + 1; 268 269 return interphi_domain_wait_call__tx(msg_st->queue->binding, TXQCONT(msg_st), 270 st->args.domain.name, length, 271 st->args.domain.state); 272} 273 274#else 275 276static errval_t domain_wait_response_tx(struct txq_msg_st *msg_st) 277{ 278 struct interphi_msg_st *st = (struct interphi_msg_st *) msg_st; 279 280 return interphi_domain_wait_response__tx(msg_st->queue->binding, 281 TXQCONT(msg_st), 282 st->args.domain.domid, 283 st->args.domain.state, 284 msg_st->err); 285} 286#endif 287 288#ifdef __k1om__ 289 290static errval_t domain_lookup_call_tx(struct txq_msg_st *msg_st) 291{ 292 struct interphi_msg_st *st = (struct interphi_msg_st *) msg_st; 293 294 size_t length = strlen(st->args.domain.name) + 1; 295 296 return interphi_domain_lookup_call__tx(msg_st->queue->binding, 297 TXQCONT(msg_st), st->args.domain.name, 298 length); 299} 300 301#else 302 303static errval_t domain_lookup_response_tx(struct txq_msg_st *msg_st) 304{ 305 struct interphi_msg_st *st = (struct interphi_msg_st *) msg_st; 306 307 return interphi_domain_lookup_response__tx(msg_st->queue->binding, 308 TXQCONT(msg_st), 309 st->args.domain.domid, msg_st->err); 310} 311 312#endif 313 314#ifdef __k1om__ 315 316static errval_t domain_register_call_tx(struct txq_msg_st *msg_st) 317{ 318 struct interphi_msg_st *st = (struct interphi_msg_st *) msg_st; 319 320 size_t length = strlen(st->args.domain.name) + 1; 321 322 return interphi_domain_register_call__tx(msg_st->queue->binding, 323 TXQCONT(msg_st), 324 st->args.domain.name, length, 325 st->args.domain.domid); 326} 327 328#else 329 330static errval_t domain_register_response_tx(struct txq_msg_st *msg_st) 331{ 332 return interphi_domain_register_response__tx(msg_st->queue->binding, 333 TXQCONT(msg_st), SYS_ERR_OK); 334} 335 336#endif 337 338static errval_t spawn_response_tx(struct txq_msg_st *msg_st) 339{ 340 struct interphi_msg_st *st = (struct interphi_msg_st *) msg_st; 341 342 return interphi_spawn_response__tx(msg_st->queue->binding, TXQCONT(msg_st), 343 st->args.spawn_reply.domainid, msg_st->err); 344} 345 346static errval_t spawn_call_tx(struct txq_msg_st *msg_st) 347{ 348 struct interphi_msg_st *st = (struct interphi_msg_st *) msg_st; 349 350 return interphi_spawn_call__tx(msg_st->queue->binding, TXQCONT(msg_st), 351 st->args.spawn_call.core, 352 st->args.spawn_call.cmdline, 353 st->args.spawn_call.cmdlen, 354 st->args.spawn_call.flags); 355} 356 357static errval_t spawn_with_cap_response_tx(struct txq_msg_st *msg_st) 358{ 359 struct interphi_msg_st *st = (struct interphi_msg_st *) msg_st; 360 361 return interphi_spawn_with_cap_response__tx(msg_st->queue->binding, 362 TXQCONT(msg_st), 363 st->args.spawn_reply.domainid, 364 msg_st->err); 365} 366 367static errval_t spawn_with_cap_call_tx(struct txq_msg_st *msg_st) 368{ 369 struct interphi_msg_st *st = (struct interphi_msg_st *) msg_st; 370 371 return interphi_spawn_with_cap_call__tx(msg_st->queue->binding, 372 TXQCONT(msg_st), 373 st->args.spawn_call.core, 374 st->args.spawn_call.cmdline, 375 st->args.spawn_call.cmdlen, 376 st->args.spawn_call.flags, 377 st->args.spawn_call.cap_base, 378 st->args.spawn_call.cap_size_bits); 379} 380 381static errval_t kill_response_tx(struct txq_msg_st *msg_st) 382{ 383 return interphi_kill_response__tx(msg_st->queue->binding, TXQCONT(msg_st), 384 msg_st->err); 385} 386 387static errval_t kill_call_tx(struct txq_msg_st *msg_st) 388{ 389 struct interphi_msg_st *st = (struct interphi_msg_st *) msg_st; 390 391 return interphi_kill_call__tx(msg_st->queue->binding, TXQCONT(msg_st), 392 st->args.kill.domainid); 393} 394 395static errval_t bootstrap_response_tx(struct txq_msg_st *msg_st) 396{ 397 return interphi_bootstrap_response__tx(msg_st->queue->binding, 398 TXQCONT(msg_st), msg_st->err); 399} 400 401static errval_t bootstrap_call_tx(struct txq_msg_st *msg_st) 402{ 403 struct interphi_msg_st *st = (struct interphi_msg_st *) msg_st; 404 405 return interphi_bootstrap_call__tx(msg_st->queue->binding, TXQCONT(msg_st), 406 st->args.bootstrap.base, 407 st->args.bootstrap.offset, 408 st->args.bootstrap.bits, 409 st->args.bootstrap.xid, 410 st->args.bootstrap.is_client); 411} 412 413static errval_t chan_open_call_tx(struct txq_msg_st *msg_st) 414{ 415 struct interphi_msg_st *st = (struct interphi_msg_st *) msg_st; 416 417 return interphi_chan_open_call__tx(msg_st->queue->binding, TXQCONT(msg_st), 418 st->args.open.source, st->args.open.target, 419 st->args.open.usrdata, 420 st->args.open.msgbase, 421 st->args.open.msgbits, st->args.open.type); 422} 423 424static errval_t chan_open_response_tx(struct txq_msg_st *msg_st) 425{ 426 return interphi_chan_open_response__tx(msg_st->queue->binding, 427 TXQCONT(msg_st), msg_st->err); 428} 429 430static errval_t alloc_mem_call_tx(struct txq_msg_st *msg_st) 431{ 432 struct interphi_msg_st *st = (struct interphi_msg_st *) msg_st; 433 return interphi_alloc_mem_call__tx(msg_st->queue->binding, TXQCONT(msg_st), 434 st->args.alloc.base, st->args.alloc.bytes); 435} 436 437static errval_t alloc_mem_response_tx(struct txq_msg_st *msg_st) 438{ 439 struct interphi_msg_st *st = (struct interphi_msg_st *) msg_st; 440 return interphi_alloc_mem_response__tx(msg_st->queue->binding, TXQCONT(msg_st), 441 st->args.alloc.base, st->args.alloc.bytes, 442 st->args.alloc.err); 443} 444 445 446/* 447 * ---------------------------------------------------------------------------- 448 * Message Callbacks 449 * ---------------------------------------------------------------------------- 450 */ 451 452static void domain_wait_call_rx(struct interphi_binding *_binding, 453 const char *name, 454 size_t length, 455 uintptr_t state) 456{ 457#ifdef __k1om__ 458 USER_PANIC("domain_wait_call_rx: not supported on the Xeon Phi\n"); 459#else 460 XINTER_DEBUG("domain_wait_call_rx: {%s}\n", name); 461 462 struct xnode *local_node = _binding->st; 463 464 struct xeon_phi *phi = local_node->local; 465 assert(phi); 466 467 struct txq_msg_st *msg_st = txq_msg_st_alloc(&local_node->msg->queue); 468 if (msg_st == NULL) { 469 USER_PANIC("ran out of reply state resources\n"); 470 } 471 472 msg_st->send = domain_wait_response_tx; 473 msg_st->cleanup = NULL; 474 475 struct interphi_msg_st *st = (struct interphi_msg_st *) msg_st; 476 477 st->args.domain.state = state; 478 479 msg_st->err = domain_wait(name, local_node, (void *)state, &st->args.domain.domid); 480 switch(err_no(msg_st->err)) { 481 case SYS_ERR_OK: 482 /* there was a record, reply */ 483 txq_send(msg_st); 484 break; 485 case OCT_ERR_NO_RECORD: 486 /* trigger installed */ 487 txq_msg_st_free(msg_st); 488 break; 489 default: 490 /* error condition */ 491 txq_send(msg_st); 492 break; 493 } 494#endif 495} 496 497static void domain_wait_response_rx(struct interphi_binding *_binding, 498 xphi_dom_id_t domain, 499 uintptr_t state, 500 errval_t msgerr) 501{ 502#ifdef __k1om__ 503 XINTER_DEBUG("domain_wait_response_rx: domid:%lx, st:%p, %s\n", domain, 504 (void * )state, err_getstring(msgerr)); 505 506 struct xphi_svc_st *st = (struct xphi_svc_st *) state; 507 508 xeon_phi_service_domain_wait_response(st, msgerr, domain); 509#else 510 USER_PANIC("domain_wait_call_rx: not supported on the host\n"); 511#endif 512} 513 514static void domain_lookup_call_rx(struct interphi_binding *_binding, 515 const char *name, 516 size_t length) 517{ 518#ifdef __k1om__ 519 USER_PANIC("domain_lookup_call_rx: not supported on the Xeon Phi\n"); 520#else 521 XINTER_DEBUG("domain_lookup_call_rx: {%s}\n", name); 522 523 struct xnode *local_node = _binding->st; 524 525 struct xeon_phi *phi = local_node->local; 526 assert(phi); 527 528 struct txq_msg_st *msg_st = txq_msg_st_alloc(&local_node->msg->queue); 529 if (msg_st == NULL) { 530 USER_PANIC("ran out of reply state resources\n"); 531 } 532 533 msg_st->send = domain_lookup_response_tx; 534 msg_st->cleanup = NULL; 535 536 struct interphi_msg_st *st = (struct interphi_msg_st *)msg_st; 537 538 msg_st->err = domain_lookup(name, &st->args.domain.domid); 539 540 txq_send(msg_st); 541#endif 542} 543 544static void domain_lookup_response_rx(struct interphi_binding *_binding, 545 xphi_dom_id_t domain, 546 errval_t msgerr) 547{ 548#ifdef __k1om__ 549 XINTER_DEBUG("domain_lookup_response_rx: %lx, %s\n", domain, 550 err_getstring(msgerr)); 551 552 struct xnode *local_node = _binding->st; 553 554 local_node->msg->rpc_err = msgerr; 555 rpc_done(local_node->msg); 556#else 557 USER_PANIC("domain_lookup_response_rx: not supported on the host\n"); 558#endif 559} 560 561static void domain_register_call_rx(struct interphi_binding *_binding, 562 const char *name, 563 size_t length, 564 xphi_dom_id_t domid) 565{ 566#ifdef __k1om__ 567 /* register calls on the K1OM are not valid */ 568 USER_PANIC("domain_register_call_rx: not supported on the Xeon Phi\n"); 569#else 570 XINTER_DEBUG("domain_register_call_rx: {%s} @ domid:%lx\n", name, domid); 571 572 struct xnode *local_node = _binding->st; 573 574 struct xeon_phi *phi = local_node->local; 575 assert(phi); 576 577 struct txq_msg_st *msg_st = txq_msg_st_alloc(&local_node->msg->queue); 578 if (msg_st == NULL) { 579 USER_PANIC("ran out of reply state resources\n"); 580 } 581 582 msg_st->err = SYS_ERR_OK; 583 msg_st->send = domain_register_response_tx; 584 msg_st->cleanup = NULL; 585 586 msg_st->err = domain_register(name, domid); 587 588 txq_send(msg_st); 589#endif 590} 591 592static void domain_register_response_rx(struct interphi_binding *_binding, 593 errval_t msgerr) 594{ 595#ifdef __k1om__ 596 XINTER_DEBUG("domain_register_response_rx:%s\n", err_getstring(msgerr)); 597 598 struct xnode *local_node = _binding->st; 599 600 local_node->msg->rpc_err = msgerr; 601 rpc_done(local_node->msg); 602#else 603 USER_PANIC("domain_register_response_rx: not supported on the host\n"); 604#endif 605} 606 607static void spawn_call_rx(struct interphi_binding *_binding, 608 uint8_t core, 609 const char *cmdline, 610 size_t length, 611 uint8_t flags) 612{ 613 XINTER_DEBUG("spawn_call_rx: {%s} of length %lu, @ core:%u\n", cmdline, 614 length, core); 615 616 struct xnode *local_node = _binding->st; 617 618 struct xeon_phi *phi = local_node->local; 619 assert(phi); 620 621 struct txq_msg_st *msg_st = txq_msg_st_alloc(&local_node->msg->queue); 622 if (msg_st == NULL) { 623 USER_PANIC("ran out of reply state resources\n"); 624 } 625 626 msg_st->send = spawn_response_tx; 627 msg_st->cleanup = NULL; 628 629 char *argv[MAX_CMDLINE_ARGS+1]; 630 msg_st->err = spawn_cmdline_extract_argv((CONST_CAST)cmdline, length, argv, MAX_CMDLINE_ARGS); 631 if (err_is_fail(msg_st->err)) { 632 txq_send(msg_st); 633 return; 634 } 635 argv[MAX_CMDLINE_ARGS] = NULL; 636 637 struct interphi_msg_st *st = (struct interphi_msg_st *) msg_st; 638 struct capref* domain = (struct capref*) malloc(sizeof(struct capref)); 639 640 /* 641 * TODO: check if we have that core present... 642 */ 643 644 msg_st->err = spawn_program(core, cmdline, argv, NULL, flags, domain); 645 if (err_is_ok(msg_st->err)) { 646 phi->current_key++; 647#ifdef __k1om__ 648 uint8_t is_host = 0x0; 649#else 650 uint8_t is_host = 0x1; 651#endif 652 st->args.spawn_reply.domainid = xeon_phi_domain_build_id(phi->id, core, 653 is_host, phi->current_key); 654 collections_hash_insert(phi->did_to_cap, st->args.spawn_reply.domainid, domain); 655 } 656 txq_send(msg_st); 657} 658 659static void spawn_response_rx(struct interphi_binding *_binding, 660 uint64_t domainid, 661 interphi_errval_t msgerr) 662{ 663 XINTER_DEBUG("spawn_response_rx: %lu, %s\n", domainid, err_getstring(msgerr)); 664 665 struct xnode *local_node = _binding->st; 666 667 local_node->msg->rpc_err = msgerr; 668 local_node->msg->rpc_data = domainid; 669 rpc_done(local_node->msg); 670} 671 672static void spawn_with_cap_call_rx(struct interphi_binding *_binding, 673 uint8_t core, 674 const char *cmdline, 675 size_t length, 676 uint8_t flags, 677 uint64_t cap_base, 678 uint8_t cap_size_bits) 679{ 680 XINTER_DEBUG("spawn_with_cap_call_rx: {%s} of length %lu @ core:%u\n", cmdline, 681 length, core); 682 683 struct xnode *local_node = _binding->st; 684 685 struct xeon_phi *phi = local_node->local; 686 assert(phi); 687 688 struct txq_msg_st *msg_st = txq_msg_st_alloc(&local_node->msg->queue); 689 if (msg_st == NULL) { 690 USER_PANIC("ran out of reply state resources\n"); 691 } 692 693 msg_st->send = spawn_with_cap_response_tx; 694 msg_st->cleanup = NULL; 695 696 char *argv[MAX_CMDLINE_ARGS+1]; 697 msg_st->err = spawn_cmdline_extract_argv((CONST_CAST)cmdline, length, argv, MAX_CMDLINE_ARGS); 698 if (err_is_fail(msg_st->err)) { 699 txq_send(msg_st); 700 return; 701 } 702 argv[MAX_CMDLINE_ARGS] = NULL; 703 704 struct interphi_msg_st *st = (struct interphi_msg_st *) msg_st; 705 706 struct capref cap; 707 msg_st->err = sysmem_cap_request(cap_base, cap_size_bits, &cap); 708 if (err_is_fail(msg_st->err)) { 709 txq_send(msg_st); 710 return; 711 } 712 713 XINTER_DEBUG("Creating ARGCN for the domain to be spawned\n"); 714 715 struct capref argcn; 716 struct cnoderef argcnref; 717 msg_st->err = cnode_create_l2(&argcn, &argcnref); 718 if (err_is_fail(msg_st->err)) { 719 sysmem_cap_return(cap); 720 txq_send(msg_st); 721 return; 722 } 723 struct capref dst = { 724 .cnode = argcnref, 725 .slot = 0 726 }; 727 cap_copy(dst, cap); 728 729 struct capref* domain = (struct capref*) malloc(sizeof(struct capref)); 730 msg_st->err = spawn_program_with_caps(core, cmdline, argv, NULL, NULL_CAP, 731 argcn, flags, domain); 732 if (err_is_ok(msg_st->err)) { 733 phi->current_key++; 734#ifdef __k1om__ 735 st->args.spawn_reply.domainid = xeon_phi_domain_build_id( 736 disp_xeon_phi_id(), core, 0, phi->current_key); 737#else 738 st->args.spawn_reply.domainid = xeon_phi_domain_build_id( 739 XEON_PHI_DOMAIN_HOST, core, 1, phi->current_key); 740#endif 741 collections_hash_insert(phi->did_to_cap, st->args.spawn_reply.domainid, domain); 742 } 743 744 cap_destroy(argcn); 745 746 txq_send(msg_st); 747} 748 749static void spawn_with_cap_response_rx(struct interphi_binding *_binding, 750 uint64_t domainid, 751 interphi_errval_t msgerr) 752{ 753 XINTER_DEBUG("spawn_with_cap_response_rx: %lu, %s\n", domainid, 754 err_getstring(msgerr)); 755 756 struct xnode *local_node = _binding->st; 757 758 local_node->msg->rpc_err = msgerr; 759 local_node->msg->rpc_data = domainid; 760 rpc_done(local_node->msg); 761} 762 763static void kill_call_rx(struct interphi_binding *_binding, 764 uint64_t domainid) 765{ 766 XINTER_DEBUG("kill_call_rx: %lu,\n", domainid); 767 768 struct xnode *local_node = _binding->st; 769 770 struct xeon_phi *phi = local_node->local; 771 assert(phi); 772 773 struct txq_msg_st *msg_st = txq_msg_st_alloc(&local_node->msg->queue); 774 if (msg_st == NULL) { 775 USER_PANIC("ran out of reply state resources\n"); 776 } 777 778 msg_st->err = SYS_ERR_OK; 779 msg_st->send = kill_response_tx; 780 msg_st->cleanup = NULL; 781 782 struct capref* domain = (struct capref*) collections_hash_find(phi->did_to_cap, domainid); 783 assert(domain); 784 785 msg_st->err = spawn_kill(*domain); 786 787 txq_send(msg_st); 788} 789 790static void kill_response_rx(struct interphi_binding *_binding, 791 interphi_errval_t msgerr) 792{ 793 XINTER_DEBUG("kill_response_rx: %s\n", err_getstring(msgerr)); 794 795 struct xnode *local_node = _binding->st; 796 797 local_node->msg->rpc_err = msgerr; 798 799 rpc_done(local_node->msg); 800} 801 802static void bootstrap_call_rx(struct interphi_binding *_binding, 803 uint64_t base, 804 uint64_t offset, 805 uint8_t bits, 806 uint8_t xid, 807 uint8_t is_client) 808{ 809 XINTER_DEBUG("bootstrap_call_rx: {%016lx, %02x} of:%016lx, xid:%u, c:%u\n", 810 base, bits, offset, xid, is_client); 811 812 struct xnode *local_node = _binding->st; 813 814 struct xeon_phi *phi = local_node->local; 815 assert(phi); 816 817 struct txq_msg_st *msg_st = txq_msg_st_alloc(&local_node->msg->queue); 818 if (msg_st == NULL) { 819 USER_PANIC("ran out of reply state resources\n"); 820 } 821 822 msg_st->err = SYS_ERR_OK; 823 msg_st->send = bootstrap_response_tx; 824 msg_st->cleanup = NULL; 825 826 struct xnode *node = &phi->topology[xid]; 827 if (node->msg) { 828 XINTER_DEBUG("already established a connection to xid:%u\n", xid); 829 txq_send(msg_st); 830 } 831 832 struct capref msg_frame; 833 msg_st->err = sysmem_cap_request(base, bits, &msg_frame); 834 if (err_is_fail(msg_st->err)) { 835 txq_send(msg_st); 836 return; 837 } 838 839 smpt_set_coprocessor_offset(phi, xid, offset); 840 841 msg_st->err = interphi_init_xphi(xid, phi, msg_frame, is_client); 842 843 txq_send(msg_st); 844} 845 846static void bootstrap_response_rx(struct interphi_binding *_binding, 847 interphi_errval_t msgerr) 848{ 849 XINTER_DEBUG("bootstrap_response_rx: %s\n", err_getstring(msgerr)); 850 851 struct xnode *local_node = _binding->st; 852 853 local_node->msg->rpc_err = msgerr; 854 855 rpc_done(local_node->msg); 856} 857 858static void chan_open_call_rx(struct interphi_binding *_binding, 859 uint64_t source_did, 860 uint64_t target_did, 861 uint64_t usrdata, 862 uint64_t msgbase, 863 uint8_t msgbits, 864 uint8_t type) 865{ 866 XINTER_DEBUG("chan_open_call_rx: %lx -> %lx\n", source_did, target_did); 867 868 struct xnode *local_node = _binding->st; 869 870 struct xeon_phi *phi = local_node->local; 871 assert(phi); 872 873 struct txq_msg_st *msg_st = txq_msg_st_alloc(&local_node->msg->queue); 874 if (msg_st == NULL) { 875 USER_PANIC("ran out of reply state resources\n"); 876 } 877 878 msg_st->send = chan_open_response_tx; 879 msg_st->cleanup = NULL; 880 881 struct capref msgcap; 882 883 lpaddr_t offset = smpt_get_coprocessor_address(phi, local_node->id); 884 885 msgbase += offset; 886 887 XINTER_DEBUG("chan_open_call_rx: msgbase=%lx\n", msgbase); 888 if (msgbase < XEON_PHI_SYSMEM_BASE) { 889 struct mem_reg *mreg = allocated_mem; 890 while(mreg) { 891 XINTER_DEBUG("%lx %lx | %lx %lx\n", mreg->id.base, msgbase, mreg->id.bytes, (1UL << msgbits)); 892 if (mreg->id.base == msgbase && mreg->id.bytes == (1UL << msgbits)) { 893 debug_printf("XXX FOUND THE REGION %lx\n", msgbase); 894 msgcap = mreg->cap; 895 break; 896 } 897 mreg = mreg->next; 898 } 899 } else { 900 msg_st->err = sysmem_cap_request(msgbase, msgbits, &msgcap); 901 if (err_is_fail(msg_st->err)) { 902 txq_send(msg_st); 903 return; 904 } 905 } 906 907 msg_st->err = xeon_phi_service_open_channel(msgcap, type, target_did, 908 source_did, usrdata); 909 if (err_is_fail(msg_st->err)) { 910 DEBUG_ERR( msg_st->err, "Failed to open the channel!\n"); 911 // sysmem_cap_return(msgcap); 912 } 913 914 txq_send(msg_st); 915} 916 917static void chan_open_response_rx(struct interphi_binding *_binding, 918 errval_t msgerr) 919{ 920 XINTER_DEBUG("chan_open_did_response_rx: %s\n", err_getstring(msgerr)); 921 922 struct xnode *local_node = _binding->st; 923 924 local_node->msg->rpc_err = msgerr; 925 926 rpc_done(local_node->msg); 927} 928 929 930static void alloc_mem_call_rx(struct interphi_binding *_binding, 931 uint64_t base, uint64_t bytes) 932{ 933 XINTER_DEBUG("alloc_mem_call_rx: %lu\n", bytes); 934 errval_t msgerr; 935 936 struct xnode *local_node = _binding->st; 937 938 struct txq_msg_st *msg_st = txq_msg_st_alloc(&local_node->msg->queue); 939 if (msg_st == NULL) { 940 USER_PANIC("ran out of reply state resources\n"); 941 } 942 943 struct mem_reg *mreg = calloc(1, sizeof(*mreg)); 944 assert(mreg); 945 946 struct capref ramcap; 947 slot_alloc(&ramcap); 948 949 struct mem_binding * b = get_mem_client(); 950 msg_st->err = b->rpc_tx_vtbl.allocate(b, log2ceil(bytes), base, base + bytes, 951 &msgerr, &ramcap); 952 if (err_is_fail(msg_st->err)) { 953 goto send_out; 954 } 955 956 msg_st->err = msgerr; 957 if (err_is_fail(msg_st->err)) { 958 goto send_out; 959 } 960 961 slot_alloc(&mreg->cap); 962 963 msg_st->err = cap_retype(mreg->cap, ramcap, 0, ObjType_Frame, bytes, 1); 964 965 errval_t err = frame_identify(mreg->cap, &mreg->id); 966 assert(err_is_ok(err)); 967 968 struct interphi_msg_st *st = (struct interphi_msg_st*)msg_st; 969 970 mreg->next = allocated_mem; 971 allocated_mem = mreg; 972 973 msg_st->send = alloc_mem_response_tx; 974 msg_st->cleanup = NULL; 975 st->args.alloc.bytes = mreg->id.bytes; 976 977 #ifdef __k1om__ 978 st->args.alloc.base = mreg->id.base; 979 #else 980 USER_PANIC("TODO: convert address!"); 981 #endif 982 983 send_out: 984 txq_send(msg_st); 985} 986 987static void alloc_mem_response_rx(struct interphi_binding *_binding, 988 uint64_t base, uint64_t bytes, errval_t msgerr) 989{ 990 XINTER_DEBUG("alloc_mem_response_rx: %s\n", err_getstring(msgerr)); 991 992 struct xnode *local_node = _binding->st; 993 994 local_node->msg->rpc_err = msgerr; 995 local_node->msg->rpc_data = base; 996 local_node->msg->rpc_data2 = bytes; 997 998 rpc_done(local_node->msg); 999} 1000 1001 1002struct interphi_rx_vtbl rx_vtbl = { 1003 .domain_lookup_call = domain_lookup_call_rx, 1004 .domain_lookup_response = domain_lookup_response_rx, 1005 .domain_wait_call = domain_wait_call_rx, 1006 .domain_wait_response = domain_wait_response_rx, 1007 .domain_register_call = domain_register_call_rx, 1008 .domain_register_response = domain_register_response_rx, 1009 .chan_open_call = chan_open_call_rx, 1010 .chan_open_response = chan_open_response_rx, 1011 .spawn_call = spawn_call_rx, 1012 .spawn_response = spawn_response_rx, 1013 .spawn_with_cap_call = spawn_with_cap_call_rx, 1014 .spawn_with_cap_response = spawn_with_cap_response_rx, 1015 .kill_call = kill_call_rx, 1016 .kill_response = kill_response_rx, 1017 .bootstrap_call = bootstrap_call_rx, 1018 .bootstrap_response = bootstrap_response_rx, 1019 .alloc_mem_call = alloc_mem_call_rx, 1020 .alloc_mem_response = alloc_mem_response_rx 1021}; 1022 1023/* 1024 * ---------------------------------------------------------------------------- 1025 * Flounder Connect / Accept Callbacks 1026 * ---------------------------------------------------------------------------- 1027 */ 1028 1029static void interphi_bind_cb(void *st, 1030 errval_t err, 1031 struct interphi_binding *_binding) 1032{ 1033 XINTER_DEBUG("interphi_bind_cb: driver bound %p %s\n", _binding, 1034 err_getstring(err)); 1035 1036 assert(_binding); 1037 1038 struct xnode *node = st; 1039 1040 _binding->rx_vtbl = rx_vtbl; 1041 _binding->st = st; 1042 1043 node->msg->binding = _binding; 1044 1045 txq_init(&node->msg->queue, _binding, _binding->waitset, 1046 (txq_register_fn_t) _binding->register_send, 1047 sizeof(struct interphi_msg_st)); 1048 1049 node->state = XNODE_STATE_READY; 1050} 1051 1052static void interphi_connect_cb(void *st, 1053 errval_t err, 1054 struct interphi_binding *_binding) 1055{ 1056 XINTER_DEBUG("interphi_connect_cb: client driver connected %p\n", _binding); 1057 1058 struct xnode *node = st; 1059 1060 _binding->rx_vtbl = rx_vtbl; 1061 _binding->st = st; 1062 1063 node->msg->binding = _binding; 1064 1065 txq_init(&node->msg->queue, _binding, _binding->waitset, 1066 (txq_register_fn_t) _binding->register_send, 1067 sizeof(struct interphi_msg_st)); 1068 1069 node->state = XNODE_STATE_READY; 1070} 1071 1072/** 1073 * \brief waits for the client driver to connect 1074 * 1075 * \param phi Xeon Phi 1076 * 1077 * \return SYS_ERR_OK when then client driver successfully connected 1078 */ 1079errval_t interphi_wait_for_client(struct xeon_phi *phi) 1080{ 1081#ifndef __k1om__ 1082 errval_t err; 1083 1084 XINTER_DEBUG("interphi_wait_for_client\n"); 1085 1086 struct xnode *node = &phi->topology[phi->id]; 1087 1088 while (node->state == XNODE_STATE_WAIT_CONNECTION) { 1089 uint32_t data = 0x0; 1090 uint32_t serial_recv = 0xF; 1091 while (serial_recv--) { 1092 data |= xeon_phi_serial_handle_recv(phi); 1093 } 1094 1095 err = event_dispatch_non_block(get_default_waitset()); 1096 switch (err_no(err)) { 1097 case SYS_ERR_OK: 1098 break; 1099 case LIB_ERR_NO_EVENT: 1100 if (!data) { 1101 thread_yield(); 1102 } 1103 break; 1104 default: 1105 return err; 1106 break; 1107 } 1108 } 1109#endif 1110 return SYS_ERR_OK; 1111 1112} 1113 1114/* 1115 * ---------------------------------------------------------------------------- 1116 * Initialization 1117 * ---------------------------------------------------------------------------- 1118 */ 1119 1120/** 1121 * \brief initializes the messaging boostrap infrastructure between the 1122 * two Xeon Phi cards 1123 * 1124 * \param phi the xeon phi to initialize the basic messaging bootstrap 1125 * 1126 * \return SYS_ERR_OK on success 1127 * errval on failure 1128 */ 1129errval_t interphi_init_xphi(uint8_t xphi, 1130 struct xeon_phi *phi, 1131 struct capref frame, 1132 uint8_t is_client) 1133{ 1134 errval_t err; 1135 1136 XINTER_DEBUG("initializing intra Xeon Phi [%u <-> %u] client=%u\n", phi->id, 1137 xphi, is_client); 1138 1139 assert(xphi < XEON_PHI_NUM_MAX); 1140 assert(xphi != phi->id); 1141 1142 assert(phi->topology[xphi].msg == NULL); 1143 1144 struct msg_info *mi = calloc(1, sizeof(struct msg_info)); 1145 if (mi == NULL) { 1146 return LIB_ERR_MALLOC_FAIL; 1147 } 1148 1149 size_t frame_size; 1150 1151 if (capref_is_null(frame)) { 1152 err = frame_alloc(&mi->frame, XEON_PHI_INTERPHI_FRAME_SIZE, &frame_size); 1153 if (err_is_fail(err)) { 1154 return err; 1155 } 1156 } else { 1157 mi->frame = frame; 1158 } 1159 1160 struct frame_identity id; 1161 err = frame_identify(mi->frame, &id); 1162 if (err_is_fail(err)) { 1163 cap_destroy(mi->frame); 1164 free(mi); 1165 return err; 1166 } 1167 1168 mi->is_client = is_client; 1169 1170 frame_size = id.bytes; 1171 1172#ifdef __k1om__ 1173 /* 1174 * XXX: the host does not need to do this 1175 */ 1176 void *addr; 1177 err = vspace_map_one_frame(&addr, frame_size, mi->frame, NULL, NULL); 1178 if (err_is_fail(err)) { 1179 cap_destroy(mi->frame); 1180 free(mi); 1181 return err; 1182 } 1183 1184 XINTER_DEBUG("Messaging frame mapped: [%016lx -> %016lx, size = %lx ]\n", 1185 id.base, (uintptr_t )addr, frame_size); 1186 1187 mi->fi.outbufsize = (frame_size >> 1); 1188 mi->fi.inbufsize = (frame_size >> 1); 1189 1190 struct waitset *ws = get_default_waitset(); 1191 1192 struct xnode *node = &phi->topology[xphi]; 1193 1194 node->msg = mi; 1195 node->local = phi; 1196 node->state = XNODE_STATE_WAIT_CONNECTION; 1197 1198 if (mi->is_client) { 1199 mi->fi.inbuf = ((uint8_t*) addr) + mi->fi.inbufsize; 1200 mi->fi.outbuf = addr; 1201 mi->fi.sendbase = id.base; 1202 1203 XINTER_DEBUG("client mode: connecting to server. %s\n", __FUNCTION__); 1204 err = interphi_connect(&mi->fi, interphi_bind_cb, node, 1205 ws, IDC_EXPORT_FLAGS_DEFAULT); 1206 } else { 1207 mi->fi.inbuf = addr; 1208 mi->fi.outbuf = ((uint8_t*) addr) + mi->fi.outbufsize; 1209 mi->fi.sendbase = id.base + mi->fi.outbufsize; 1210 1211 XINTER_DEBUG("server mode: accepting connections. %s\n", __FUNCTION__); 1212 1213 err = interphi_accept(&mi->fi, node, interphi_connect_cb, 1214 ws, IDC_EXPORT_FLAGS_DEFAULT); 1215 } 1216 if (err_is_fail(err)) { 1217 vspace_unmap(addr); 1218 cap_destroy(mi->frame); 1219 free(mi); 1220 return err; 1221 } 1222 1223 if (mi->is_client) { 1224 XINTER_DEBUG("Waiting for connect callback...\n"); 1225 while(node->state == XNODE_STATE_WAIT_CONNECTION) { 1226 messages_wait_and_handle_next(); 1227 } 1228 XINTER_DEBUG("connected to pier.\n"); 1229 } 1230 1231 phi->connected++; 1232 1233#else 1234 struct xnode *node = &phi->topology[xphi]; 1235 lpaddr_t offset = ((node->apt_base >> 32) - ((node->apt_base >> 34)<<2))<<32; 1236 assert((1UL << log2ceil(id.bytes)) == id.bytes); 1237 err = interphi_bootstrap(phi, id.base, log2ceil(id.bytes), offset, xphi, mi->is_client); 1238 if (err_is_fail(err)) { 1239 free(mi); 1240 return err; 1241 } 1242 1243 XINTER_DEBUG("Local bootstrap succeeded. Sending to other node.\n"); 1244 1245 err = service_bootstrap(phi, xphi, mi->frame); 1246 if (err_is_fail(err)) { 1247 XINTER_DEBUG("Could not initialize messaging\n"); 1248 return err; 1249 } 1250#endif 1251 1252 return SYS_ERR_OK; 1253} 1254 1255#include <driverkit/hwmodel.h> 1256#include <driverkit/iommu.h> 1257#include <skb/skb.h> 1258 1259 1260/** 1261 * \brief initializes the communication between the host and the card Xeon Phi 1262 * drivers using a bootstraped flounder channel 1263 * 1264 * \param phi Xeon Phi to initialize 1265 * 1266 * \return SYS_ERR_OK on success 1267 * errval on failure 1268 */ 1269errval_t interphi_init(struct xeon_phi *phi, 1270 struct capref frame) 1271{ 1272 errval_t err; 1273 1274 assert(phi->msg == NULL); 1275 1276 struct msg_info *mi = calloc(1, sizeof(struct msg_info)); 1277 if (mi == NULL) { 1278 return LIB_ERR_MALLOC_FAIL; 1279 } 1280 1281 size_t frame_size; 1282 1283 if (capref_is_null(frame)) { 1284#if defined(__k1om__) || !defined(XEON_PHI_USE_HW_MODEL) 1285 err = frame_alloc(&mi->frame, XEON_PHI_INTERPHI_FRAME_SIZE, &frame_size); 1286#else 1287 int32_t knc_socket_id; 1288 err = xeon_phi_hw_model_lookup_nodeids(phi->nodeid, &knc_socket_id, NULL, NULL, NULL, NULL, NULL); 1289 if(err_is_fail(err)){ 1290 return err; 1291 } 1292 int32_t nodes[3]; 1293 nodes[0] = knc_socket_id; 1294 nodes[1] = driverkit_hwmodel_get_my_node_id(); 1295 nodes[2] = 0; 1296 int32_t dest_nodeid = driverkit_hwmodel_lookup_dram_node_id(); 1297 1298 err = driverkit_hwmodel_frame_alloc(&mi->frame, XEON_PHI_INTERPHI_FRAME_SIZE, 1299 dest_nodeid, nodes); 1300 1301 frame_size =XEON_PHI_INTERPHI_FRAME_SIZE; 1302#endif 1303 //err = frame_alloc(&mi->frame, XEON_PHI_INTERPHI_FRAME_SIZE, &frame_size); 1304 if (err_is_fail(err)) { 1305 return err; 1306 } 1307 } else { 1308 mi->frame = frame; 1309 } 1310 1311 struct frame_identity id; 1312 err = frame_identify(mi->frame, &id); 1313 if (err_is_fail(err)) { 1314 cap_destroy(mi->frame); 1315 free(mi); 1316 return err; 1317 } 1318 1319 frame_size = id.bytes; 1320 1321 void *addr; 1322 err = vspace_map_one_frame(&addr, frame_size, mi->frame, NULL, NULL); 1323 if (err_is_fail(err)) { 1324 cap_destroy(mi->frame); 1325 free(mi); 1326 return err; 1327 } 1328 1329 XINTER_DEBUG("Messaging frame mapped: [%016lx->%016lx, size = %lx]\n", 1330 id.base, (uintptr_t )addr, frame_size); 1331 1332 mi->is_client = phi->is_client; 1333 1334 mi->fi.outbufsize = (frame_size >> 1); 1335 mi->fi.inbufsize = (frame_size >> 1); 1336 1337 struct waitset *ws = get_default_waitset(); 1338 1339 phi->msg = mi; 1340 1341 phi->topology[phi->id].msg = mi; 1342 phi->topology[phi->id].local = phi; 1343 phi->topology[phi->id].state = XNODE_STATE_WAIT_CONNECTION; 1344 1345 if (phi->is_client) { 1346 mi->fi.inbuf = ((uint8_t*) addr) + mi->fi.inbufsize; 1347 mi->fi.outbuf = addr; 1348 mi->fi.sendbase = id.base; 1349 1350 XINTER_DEBUG("client mode: connecting to server. %s\n", __FUNCTION__); 1351 1352 err = interphi_connect(&mi->fi, interphi_bind_cb, &phi->topology[phi->id], 1353 ws, IDC_EXPORT_FLAGS_DEFAULT); 1354 } else { 1355 mi->fi.inbuf = addr; 1356 mi->fi.outbuf = ((uint8_t*) addr) + mi->fi.outbufsize; 1357 mi->fi.sendbase = id.base + mi->fi.outbufsize; 1358 1359 XINTER_DEBUG("server mode: accepting connections. %s\n", __FUNCTION__); 1360 1361 err = interphi_accept(&mi->fi, &phi->topology[phi->id], 1362 interphi_connect_cb, ws, IDC_EXPORT_FLAGS_DEFAULT); 1363 } 1364 if (err_is_fail(err)) { 1365 vspace_unmap(addr); 1366 cap_destroy(mi->frame); 1367 free(mi); 1368 return err; 1369 } 1370 1371 phi->connected = 1; 1372 1373 if (!phi->is_client) { 1374 1375 genpaddr_t xphi_local_addr; 1376#ifdef XEON_PHI_USE_HW_MODEL 1377 err = xeon_phi_hw_model_query_and_config(phi, mi->frame, &xphi_local_addr, NULL); 1378 if (err_is_fail(err)) { 1379 vspace_unmap(addr); 1380 cap_destroy(mi->frame); 1381 free(mi); 1382 } 1383#else 1384 xphi_local_addr = id.base; 1385#endif 1386 struct xeon_phi_boot_params *bp; 1387 bp = (struct xeon_phi_boot_params *) (phi->apt.vbase + phi->os_offset); 1388 bp->msg_base = xphi_local_addr; 1389 assert((1UL << log2ceil(id.bytes)) == id.bytes); 1390 bp->msg_size_bits = log2ceil(id.bytes); 1391 } 1392 1393 collections_hash_create(&phi->did_to_cap, NULL); 1394 phi->current_key = 0; 1395 1396 return SYS_ERR_OK; 1397} 1398 1399/* 1400 * ---------------------------------------------------------------------------- 1401 * Message Sending 1402 * ---------------------------------------------------------------------------- 1403 */ 1404 1405/** 1406 * \brief sends a bootstrap request to the Xeon Phi client driver 1407 * 1408 * \param phi Xeon Phi 1409 * \param frame_base base address of the messaging frame 1410 * \param frame_bits size of the messaging frame in bits 1411 * \param offset offset into the SMPT 1412 * \param xid ID of the other Xeon Phi 1413 * \param is_client flag indicating if this is the client of the connection 1414 * 1415 * \returns SYS_ERR_OK on success 1416 * errval on faiure 1417 */ 1418errval_t interphi_bootstrap(struct xeon_phi *phi, 1419 lpaddr_t frame_base, 1420 uint8_t frame_bits, 1421 lpaddr_t offset, 1422 uint8_t xid, 1423 uint8_t is_client) 1424{ 1425#ifdef __k1om__ 1426 USER_PANIC("This function should not be called on the Xeon Phi\n"); 1427#endif 1428 1429 XINTER_DEBUG("sending bootstrap to card. [%u] client:%u\n", xid, is_client); 1430 1431 struct msg_info *mi = phi->msg; 1432 1433 struct txq_msg_st *msg_st = rpc_preamble(mi); 1434 if (msg_st == NULL) { 1435 return LIB_ERR_MALLOC_FAIL; 1436 } 1437 1438 msg_st->send = bootstrap_call_tx; 1439 1440 struct interphi_msg_st *svc_st = (struct interphi_msg_st *) msg_st; 1441 1442 svc_st->args.bootstrap.xid = xid; 1443 svc_st->args.bootstrap.offset = offset; 1444 svc_st->args.bootstrap.is_client = is_client; 1445 svc_st->args.bootstrap.base = frame_base; 1446 svc_st->args.bootstrap.bits = frame_bits; 1447 1448 txq_send(msg_st); 1449 1450 rpc_wait_done(phi->msg); 1451 1452 return phi->msg->rpc_err; 1453} 1454 1455/** 1456 * \brief sends a spawn request to the Xeon Phi driver 1457 * 1458 * \param node Xeon Phi Node 1459 * \param core which core to spawn the domain on 1460 * \param cmdline Commandline of the domain to spawn (marshalled) 1461 * \param cmdlen length of the command line 1462 * \param domain Domain identifier returned 1463 * 1464 * \returns SYS_ERR_OK on success 1465 * errval on faiure 1466 */ 1467errval_t interphi_spawn(struct xnode *node, 1468 uint8_t core, 1469 char *cmdline, 1470 size_t cmdlen, 1471 uint8_t flags, 1472 uint64_t *domain) 1473{ 1474 XINTER_DEBUG("spawning %s on core %u\n", cmdline, core); 1475 struct msg_info *mi = node->msg; 1476 1477 struct txq_msg_st *msg_st = rpc_preamble(mi); 1478 if (msg_st == NULL) { 1479 return LIB_ERR_MALLOC_FAIL; 1480 } 1481 1482 msg_st->send = spawn_call_tx; 1483 1484 struct interphi_msg_st *svc_st = (struct interphi_msg_st *) msg_st; 1485 1486 svc_st->args.spawn_call.cmdline = cmdline; 1487 svc_st->args.spawn_call.cmdlen = cmdlen; 1488 svc_st->args.spawn_call.core = core; 1489 svc_st->args.spawn_call.flags = flags; 1490 1491 txq_send(msg_st); 1492 1493 rpc_wait_done(node->msg); 1494 1495 if (err_is_ok(node->msg->rpc_err)) { 1496 if (domain) { 1497 *domain = node->msg->rpc_data; 1498 } 1499 } 1500 1501 return node->msg->rpc_err; 1502} 1503 1504/** 1505 * \brief sends a spawn request to the Xeon Phi driver 1506 * 1507 * \param node Xeon Phi Node 1508 * \param core which core to spawn the domain on 1509 * \param cmdline Commandline of the domain to spawn (marshalled args) 1510 * \param cmdlen length of the cmd line 1511 * \param cap Cap to hand over to the domain at boot 1512 * \param domain Domain identifier returned 1513 * 1514 * \returns SYS_ERR_OK on success 1515 * errval on faiure 1516 */ 1517errval_t interphi_spawn_with_cap(struct xnode *node, 1518 uint8_t core, 1519 char *cmdline, 1520 size_t cmdlen, 1521 uint8_t flags, 1522 struct capref cap, 1523 uint64_t *domain) 1524{ 1525 errval_t err; 1526 struct msg_info *mi = node->msg; 1527 1528 XINTER_DEBUG("spawning %s with cap on core %u\n", cmdline, core); 1529 1530 struct frame_identity id; 1531 err = frame_identify(cap, &id); 1532 if (err_is_fail(err)) { 1533 return err; 1534 } 1535 1536 struct txq_msg_st *msg_st = rpc_preamble(mi); 1537 if (msg_st == NULL) { 1538 return LIB_ERR_MALLOC_FAIL; 1539 } 1540 1541 msg_st->send = spawn_with_cap_call_tx; 1542 1543 struct interphi_msg_st *svc_st = (struct interphi_msg_st *) msg_st; 1544 1545 svc_st->args.spawn_call.cmdline = cmdline; 1546 svc_st->args.spawn_call.cmdlen = cmdlen; 1547 svc_st->args.spawn_call.core = core; 1548 svc_st->args.spawn_call.flags = flags; 1549 assert((1UL << log2ceil(id.bytes)) == id.bytes); 1550 svc_st->args.spawn_call.cap_size_bits = log2ceil(id.bytes); 1551 1552#ifdef __k1om__ 1553 svc_st->args.spawn_call.cap_base = id.base; 1554#else 1555 err = xeon_phi_hw_model_query_and_config(node->local, cap, 1556 &svc_st->args.spawn_call.cap_base, NULL); 1557 if (err_is_fail(err)) { 1558 rpc_done(node->msg); 1559 txq_msg_st_free(msg_st); 1560 return err; 1561 } 1562#endif 1563 1564 txq_send(msg_st); 1565 1566 rpc_wait_done(node->msg); 1567 1568 if (err_is_ok(node->msg->rpc_err)) { 1569 if (domain) { 1570 *domain = node->msg->rpc_data; 1571 } 1572 } 1573 1574 return node->msg->rpc_err; 1575} 1576 1577/** 1578 * \brief sends a kill request for a domain 1579 * 1580 * \param node Target Xeon Phi node 1581 * \param domain Domain identifier 1582 * 1583 * \returns SYS_ERR_OK on success 1584 * errval on failure 1585 */ 1586errval_t interphi_kill(struct xnode *node, 1587 xphi_dom_id_t domain) 1588{ 1589 XINTER_DEBUG("sending kill signal for domain:%lu\n", domain); 1590 1591 struct msg_info *mi = node->msg; 1592 1593 struct txq_msg_st *msg_st = rpc_preamble(mi); 1594 if (msg_st == NULL) { 1595 return LIB_ERR_MALLOC_FAIL; 1596 } 1597 1598 msg_st->send = kill_call_tx; 1599 1600 struct interphi_msg_st *svc_st = (struct interphi_msg_st *) msg_st; 1601 1602 svc_st->args.kill.domainid = domain; 1603 1604 txq_send(msg_st); 1605 1606 rpc_wait_done(mi); 1607 1608 return mi->rpc_err; 1609} 1610 1611/** 1612 * \brief sends a channel open messages to another Xeon Phi driver 1613 * 1614 * \param node Xeon Phi Node to send the message to 1615 * \param target target domain id 1616 * \param source source domain id 1617 * \param usedata usr specified data 1618 * \param msgframe capability of the messaging frame 1619 * \param type Channel type 1620 * 1621 * \returns SYS_ERR_OK on success 1622 */ 1623errval_t interphi_chan_open(struct xnode *node, 1624 xphi_dom_id_t target, 1625 xphi_dom_id_t source, 1626 uint64_t usrdata, 1627 struct capref msgframe, 1628 xphi_chan_type_t type) 1629{ 1630 errval_t err; 1631 1632 XINTER_DEBUG("sending channel open to domain {%lx}\n", target); 1633 1634 struct msg_info *mi = node->msg; 1635 1636 struct frame_identity id; 1637 err = frame_identify(msgframe, &id); 1638 if (err_is_fail(err)) { 1639 return err; 1640 } 1641 1642 struct txq_msg_st *msg_st = rpc_preamble(mi); 1643 if (msg_st == NULL) { 1644 return LIB_ERR_MALLOC_FAIL; 1645 } 1646 1647 struct interphi_msg_st *svc_st = (struct interphi_msg_st *) msg_st; 1648 1649 #ifndef __k1om__ 1650 int32_t nodeid; 1651 err = xeon_phi_hw_model_lookup_nodeids(node->local->nodeid, &nodeid, 1652 NULL, NULL, NULL, NULL, NULL); 1653 if (err_is_fail(err)) { 1654 rpc_done(node->msg); 1655 txq_msg_st_free(msg_st); 1656 return err; 1657 } 1658 1659 int32_t inodeid_mem = driverkit_hwmodel_lookup_pcibus_node_id(); 1660 1661 err = driverkit_hwmodel_get_map_conf_addr(inodeid_mem, id.base, id.bytes, nodeid, NULL, 0, 1662 &svc_st->args.open.msgbase); 1663 if (err_is_fail(err)) { 1664 rpc_done(node->msg); 1665 txq_msg_st_free(msg_st); 1666 return err; 1667 } 1668 #else 1669 svc_st->args.open.msgbase = id.base; 1670 #endif 1671 1672 assert((1UL << log2ceil(id.bytes)) == id.bytes); 1673 svc_st->args.open.msgbits = log2ceil(id.bytes); 1674 svc_st->args.open.source = source; 1675 svc_st->args.open.usrdata = usrdata; 1676 svc_st->args.open.type = type; 1677 1678 if (target) { 1679 msg_st->send = chan_open_call_tx; 1680 svc_st->args.open.target = target; 1681 } else { 1682 rpc_done(node->msg); 1683 txq_msg_st_free(msg_st); 1684 return -1; 1685 } 1686 1687 txq_send(msg_st); 1688 1689 rpc_wait_done(mi); 1690 1691 return mi->rpc_err; 1692} 1693 1694/** 1695 * \brief registers a ready domain with the Xeon Phi Domain Service 1696 * 1697 * \param node Xeon Phi Node to send the message to 1698 * \param name Name to register 1699 * \param domid Xeon Phi Domain ID 1700 * 1701 * \returns SYS_ERR_OK on success 1702 * errval on error 1703 */ 1704errval_t interphi_domain_register(struct xnode *node, 1705 const char *name, 1706 xphi_dom_id_t domid) 1707{ 1708#ifdef __k1om__ 1709 XINTER_DEBUG("domain register {%s} with domainid:%lx @ xnode:%u\n", name, 1710 domid, node->id); 1711 1712 assert(node->msg); 1713 1714 struct msg_info *mi = node->msg; 1715 1716 struct txq_msg_st *msg_st = rpc_preamble(mi); 1717 if (msg_st == NULL) { 1718 return LIB_ERR_MALLOC_FAIL; 1719 } 1720 msg_st->send = domain_register_call_tx; 1721 1722 struct interphi_msg_st *svc_st = (struct interphi_msg_st *) msg_st; 1723 1724 svc_st->args.domain.domid = domid; 1725 svc_st->args.domain.name = name; 1726 1727 txq_send(msg_st); 1728 1729 rpc_wait_done(mi); 1730 1731 return mi->rpc_err; 1732#else 1733 USER_PANIC("interphi_domain_lookup: not supporte on host.\n"); 1734 1735 return SYS_ERR_OK; 1736#endif 1737} 1738 1739/** 1740 * \brief checks if a domain is running and returns its domain id if it is. 1741 * 1742 * \param node Xeon Phi Node to send the message to 1743 * \param name Name of the Domain 1744 * \param domid returned Xeon Phi Domain ID 1745 * 1746 * \returns SYS_ERR_OK on success 1747 * errval on error 1748 */ 1749errval_t interphi_domain_lookup(struct xnode *node, 1750 char *name, 1751 xphi_dom_id_t *retdomid) 1752{ 1753#ifdef __k1om__ 1754 XINTER_DEBUG("domain lookup {%s} @ xnode:%u\n", name, node->id); 1755 1756 struct msg_info *mi = node->msg; 1757 1758 struct txq_msg_st *msg_st = rpc_preamble(mi); 1759 if (msg_st == NULL) { 1760 return LIB_ERR_MALLOC_FAIL; 1761 } 1762 1763 msg_st->send = domain_lookup_call_tx; 1764 1765 struct interphi_msg_st *svc_st = (struct interphi_msg_st *) msg_st; 1766 1767 svc_st->args.domain.name = name; 1768 1769 txq_send(msg_st); 1770 1771 rpc_wait_done(mi); 1772 1773 return mi->rpc_err; 1774#else 1775 USER_PANIC("interphi_domain_lookup: not supporte on host.\n"); 1776 1777 return SYS_ERR_OK; 1778#endif 1779} 1780 1781/** 1782 * \brief checks if a domain is running and installs a trigger to reply 1783 * 1784 * \param node Xeon Phi Node to send the message to 1785 * \param name Name of the Domain 1786 * \param state user state 1787 * 1788 * \returns SYS_ERR_OK on success 1789 * errval on error 1790 */ 1791errval_t interphi_domain_wait(struct xnode *node, 1792 char *name, 1793 void *state) 1794{ 1795#ifdef __k1om__ 1796 XINTER_DEBUG("domain wait {%s} @ xnode:%u\n", name, node->id); 1797 1798 assert(node->msg); 1799 1800 struct msg_info *mi = node->msg; 1801 if (mi->binding == NULL) { 1802 assert(!"NYI"); 1803 } 1804 1805 struct txq_msg_st *msg_st = txq_msg_st_alloc(&mi->queue); 1806 if (msg_st == NULL) { 1807 rpc_done(node->msg); 1808 return LIB_ERR_MALLOC_FAIL; 1809 } 1810 1811 msg_st->send = domain_wait_call_tx; 1812 msg_st->cleanup = NULL; 1813 1814 struct interphi_msg_st *svc_st = (struct interphi_msg_st *) msg_st; 1815 1816 svc_st->args.domain.name = name; 1817 svc_st->args.domain.state = (uintptr_t) state; 1818 1819 txq_send(msg_st); 1820#else 1821 USER_PANIC("interphi_domain_wait: not supporte on host\n"); 1822#endif 1823 return SYS_ERR_OK; 1824} 1825 1826/** 1827 * \brief sends a reply when the Octopus trigger fired 1828 * 1829 * \param node Xeon Phi Node 1830 * \param domid Xeon Phi Domain ID 1831 * \param err Outcome of the reply 1832 * \param state State pointer supplied by the card. 1833 * 1834 * \returns SYS_ERR_OK on success 1835 */ 1836errval_t interphi_domain_wait_reply(struct xnode *node, 1837 errval_t err, 1838 void *state, 1839 xphi_dom_id_t domid) 1840{ 1841#ifndef __k1om__ 1842 XINTER_DEBUG("domain interphi_domain_wait_reply domid:%lx @ xnode:%u, st:%p\n", 1843 domid, node->id, state); 1844 1845 struct msg_info *mi = node->msg; 1846 if (mi->binding == NULL) { 1847 assert(!"NYI"); 1848 } 1849 1850 struct txq_msg_st *msg_st = txq_msg_st_alloc(&mi->queue); 1851 if (msg_st == NULL) { 1852 rpc_done(node->msg); 1853 return LIB_ERR_MALLOC_FAIL; 1854 } 1855 1856 msg_st->send = domain_wait_response_tx; 1857 msg_st->cleanup = NULL; 1858 msg_st->err = err; 1859 1860 struct interphi_msg_st *svc_st = (struct interphi_msg_st *) msg_st; 1861 1862 svc_st->args.domain.domid = domid; 1863 svc_st->args.domain.state = (uintptr_t)state; 1864 1865 txq_send(msg_st); 1866 1867#else 1868 USER_PANIC("interphi_domain_wait_reply: Not supported on Xeon Phi\n"); 1869#endif 1870 return SYS_ERR_OK; 1871} 1872 1873 1874 1875errval_t interphi_alloc_mem(struct xnode *node, 1876 uint64_t bytes, 1877 struct capref *mem) 1878{ 1879 errval_t err; 1880 struct msg_info *mi = node->msg; 1881 1882 XINTER_DEBUG("allocate memory %lu bytes\n", bytes); 1883 1884 int32_t nodeid, gddr_node; 1885 err = xeon_phi_hw_model_lookup_nodeids(node->local->nodeid, &nodeid, 1886 NULL, NULL, NULL, NULL, &gddr_node); 1887 if (err_is_fail(err)) { 1888 return err; 1889 } 1890 1891 int32_t nodes_reachable[] = { 1892 nodeid, driverkit_hwmodel_get_my_node_id(), 0 1893 }; 1894 1895// PHI NodeIds: KNC_SOCKET=7, SMPT=8, IOMMU=9, DMA=11, K1OM_CORE=10 1896 1897 1898 genpaddr_t addr; 1899 err = driverkit_hwmodel_allocate(bytes, gddr_node, nodes_reachable, 1900 21, &addr); 1901 if (err_is_fail(err)) { 1902 skb_execute("listing"); 1903 DEBUG_ERR(err, "failed model query"); 1904 return err; 1905 } 1906 1907 struct txq_msg_st *msg_st = rpc_preamble(mi); 1908 if (msg_st == NULL) { 1909 return LIB_ERR_MALLOC_FAIL; 1910 } 1911 1912 1913 struct interphi_msg_st *svc_st = (struct interphi_msg_st *) msg_st; 1914 msg_st->send = alloc_mem_call_tx; 1915 svc_st->args.alloc.bytes = bytes; 1916 svc_st->args.alloc.base = addr; 1917 1918 txq_send(msg_st); 1919 1920 rpc_wait_done(node->msg); 1921 1922 1923 if (err_is_ok(node->msg->rpc_err)) { 1924 if (mem) { 1925 XINTER_DEBUG("Obtain cap for 0x%lx of byte %lu\n", addr, bytes); 1926 1927 genpaddr_t hostbase; 1928 nodeid = driverkit_hwmodel_lookup_pcibus_node_id(); 1929 err = driverkit_hwmodel_get_map_conf_addr(gddr_node, addr, bytes, 1930 nodeid, NULL, 0, 1931 &hostbase); 1932 if (err_is_fail(err)) { 1933 DEBUG_ERR(err, "failed model query"); 1934 return err; 1935 } 1936 err = sysmem_cap_request(hostbase, log2ceil(bytes), mem); 1937 if (err_is_fail(err)) { 1938 DEBUG_ERR(err, "failed to get frame"); 1939 } 1940 return err; 1941 } 1942 } 1943 1944 return node->msg->rpc_err; 1945} 1946