1/** 2 * \file 3 * \brief UMP channel support 4 */ 5 6/* 7 * Copyright (c) 2009, 2010, ETH Zurich. 8 * All rights reserved. 9 * 10 * This file is distributed under the terms in the attached LICENSE file. 11 * If you do not find this file, copies can be found by writing to: 12 * ETH Zurich D-INFK, Haldeneggsteig 4, CH-8092 Zurich. Attn: Systems Group. 13 */ 14 15#include <inttypes.h> 16#include "monitor.h" 17 18/******* stack-ripped monitor_bind_ump_client_request *******/ 19 20static void monitor_bind_ump_client_request_error(struct monitor_binding *b, 21 struct capref frame, 22 uintptr_t conn_id, 23 uintptr_t domain_id, 24 errval_t err) 25{ 26 errval_t err2; 27 28 err2 = cap_destroy(frame); 29 if (err_is_fail(err2)) { 30 USER_PANIC_ERR(err, "cap_destroy failed"); 31 } 32 33 if (conn_id != 0) { 34 err2 = remote_conn_free(conn_id); 35 if (err_is_fail(err2)) { 36 USER_PANIC_ERR(err2, "remote_conn_free failed"); 37 } 38 } 39 40 err2 = b->tx_vtbl.bind_ump_reply_client(b, NOP_CONT, 0, domain_id, err, 41 NULL_CAP); 42 if (err_is_fail(err2)) { 43 USER_PANIC_ERR(err2, "error reply failed"); 44 } 45} 46 47static void bind_ump_request_handler(struct intermon_binding *b, 48 struct intermon_msg_queue_elem *e); 49 50struct bind_ump_request_state { 51 struct intermon_msg_queue_elem elem; 52 struct intermon_bind_ump_request__tx_args args; 53 struct frame_identity frameid; 54 struct capability capability; 55 struct monitor_binding *mb; 56 struct capref frame; 57 uintptr_t domain_id; 58}; 59 60static void bind_ump_request_cont(struct intermon_binding *intermon_binding, 61 iref_t iref, uintptr_t conn_id, 62 uint32_t channel_length_in, 63 uint32_t channel_length_out, 64 struct frame_identity frameid, 65 struct capability capability, 66 struct monitor_binding *mb, 67 struct capref frame, 68 uintptr_t domain_id) 69{ 70 errval_t err; 71 72 intermon_caprep_t caprep; 73 capability_to_caprep(&capability, &caprep); 74 75 assert((1UL << log2ceil(frameid.bytes)) == frameid.bytes); 76 /* Send the request to the monitor on the server's core */ 77 err = intermon_binding->tx_vtbl. 78 bind_ump_request(intermon_binding, NOP_CONT, iref, conn_id, channel_length_in, 79 channel_length_out, frameid.base, log2ceil(frameid.bytes), 80 caprep); 81 if (err_is_fail(err)) { 82 if(err_no(err) == FLOUNDER_ERR_TX_BUSY) { 83 struct bind_ump_request_state *me = 84 malloc(sizeof(struct bind_ump_request_state)); 85 struct intermon_state *ist = intermon_binding->st; 86 me->args.iref = iref; 87 me->args.mon_id = conn_id; 88 me->args.channel_length_in = channel_length_in; 89 me->args.channel_length_out = channel_length_out; 90 me->frameid = frameid; 91 me->capability = capability; 92 me->mb = mb; 93 me->frame = frame; 94 me->domain_id = domain_id; 95 me->elem.cont = bind_ump_request_handler; 96 97 err = intermon_enqueue_send(intermon_binding, &ist->queue, 98 get_default_waitset(), &me->elem.queue); 99 assert(err_is_ok(err)); 100 return; 101 } 102 103 USER_PANIC_ERR(err, "failed forwarding UMP bind request"); 104 monitor_bind_ump_client_request_error(mb, frame, conn_id, domain_id, err); 105 } 106} 107 108static void bind_ump_request_handler(struct intermon_binding *b, 109 struct intermon_msg_queue_elem *e) 110{ 111 struct bind_ump_request_state *st = (struct bind_ump_request_state *)e; 112 bind_ump_request_cont(b, st->args.iref, st->args.mon_id, 113 st->args.channel_length_in, 114 st->args.channel_length_out, st->frameid, 115 st->capability, st->mb, st->frame, st->domain_id); 116 free(e); 117} 118 119static void monitor_bind_ump_client_request(struct monitor_binding *mb, 120 iref_t iref, uintptr_t domain_id, 121 struct capref frame, 122 size_t channel_length_in, 123 size_t channel_length_out, 124 struct capref notify) 125{ 126 uint8_t core_id; 127 uintptr_t conn_id = 0; 128 errval_t err; 129 struct remote_conn_state *conn = NULL; 130 131 // Get the core id 132 err = iref_get_core_id(iref, &core_id); 133 if (err_is_fail(err)) { 134 debug_err(__FILE__, __func__, __LINE__, err, "iref_get_core_id failed"); 135 monitor_bind_ump_client_request_error(mb, frame, conn_id, domain_id, err); 136 return; 137 } 138 139 if (core_id == my_core_id) { 140 USER_PANIC("Same-core UMP binding NYI"); 141 } 142 143 /* Identify frame */ 144 struct frame_identity frameid; 145 err = invoke_frame_identify(frame, &frameid); 146 if (err_is_fail(err)) { 147 debug_err(__FILE__, __func__, __LINE__, err, "frame_identify failed"); 148 monitor_bind_ump_client_request_error(mb, frame, conn_id, domain_id, err); 149 return; 150 } 151 152 // Identify notify cap 153 struct capability capability; 154 err = monitor_cap_identify(notify, &capability); 155 if (err_is_fail(err)) { 156 USER_PANIC_ERR(err, "monitor_cap_identify failed, ignored"); 157 return; 158 } 159 assert(capability.type == ObjType_Notify_IPI 160 || capability.type == ObjType_Null); 161 /* assert(capability.u.notify.coreid == my_core_id); */ 162 163 /* Forward request to the corresponding monitor */ 164 // Create local state 165 err = remote_conn_alloc(&conn, &conn_id, REMOTE_CONN_UMP); 166 if (err_is_fail(err)) { 167 debug_err(__FILE__, __func__, __LINE__, err, "remote_conn_alloc failed"); 168 monitor_bind_ump_client_request_error(mb, frame, conn_id, domain_id, err); 169 return; 170 } 171 172 err = monitor_remote_relations(frame, RRELS_COPY_BIT, RRELS_COPY_BIT, NULL); 173 if (err_is_fail(err)) { 174 DEBUG_ERR(err, "setting remote copy bit failed"); 175 monitor_bind_ump_client_request_error(mb, frame, conn_id, domain_id, err); 176 return; 177 } 178 179 // Track data 180 conn->domain_id = domain_id; 181 conn->domain_binding = mb; 182 conn->x.ump.frame = frame; 183 conn->core_id = core_id; 184 185 // Get connection to the monitor to forward request to 186 struct intermon_binding *intermon_binding; 187 err = intermon_binding_get(core_id, &intermon_binding); 188 if (err_is_fail(err)) { 189 debug_err(__FILE__, __func__, __LINE__, err, "intermon_binding_get failed"); 190 monitor_bind_ump_client_request_error(mb, frame, conn_id, domain_id, err); 191 return; 192 } 193 194 bind_ump_request_cont(intermon_binding, iref, conn_id, channel_length_in, 195 channel_length_out, frameid, capability, mb, frame, 196 domain_id); 197} 198 199/******* stack-ripped monitor_bind_ump_reply *******/ 200 201static void bind_ump_reply_handler(struct intermon_binding *b, 202 struct intermon_msg_queue_elem *e); 203 204struct bind_ump_reply_state { 205 struct intermon_msg_queue_elem elem; 206 struct intermon_bind_ump_reply__tx_args args; 207 struct capability capability; 208}; 209 210static void bind_ump_reply_cont(struct intermon_binding *mon_binding, 211 uintptr_t your_mon_id, uintptr_t my_mon_id, 212 uintptr_t msgerr, struct capability capability) 213{ 214 errval_t err; 215 216 intermon_caprep_t caprep; 217 capability_to_caprep(&capability, &caprep); 218 219 err = mon_binding->tx_vtbl. 220 bind_ump_reply(mon_binding, NOP_CONT, your_mon_id, my_mon_id, msgerr, 221 caprep); 222 if (err_is_fail(err)) { 223 if(err_no(err) == FLOUNDER_ERR_TX_BUSY) { 224 struct bind_ump_reply_state *me = 225 malloc(sizeof(struct bind_ump_reply_state)); 226 struct intermon_state *ist = mon_binding->st; 227 me->args.con_id = your_mon_id; 228 me->args.mon_id = my_mon_id; 229 me->args.err = msgerr; 230 me->capability = capability; 231 me->elem.cont = bind_ump_reply_handler; 232 233 err = intermon_enqueue_send(mon_binding, &ist->queue, 234 get_default_waitset(), &me->elem.queue); 235 assert(err_is_ok(err)); 236 return; 237 } 238 239 USER_PANIC_ERR(err, "failed forwarding UMP bind reply"); 240 // cleanup 241 if (err_is_ok(msgerr)) { 242 err = remote_conn_free(my_mon_id); 243 assert(err_is_ok(err)); 244 } 245 } 246} 247 248static void bind_ump_reply_handler(struct intermon_binding *b, 249 struct intermon_msg_queue_elem *e) 250{ 251 struct bind_ump_reply_state *st = (struct bind_ump_reply_state *)e; 252 bind_ump_reply_cont(b, st->args.con_id, st->args.mon_id, st->args.err, 253 st->capability); 254 free(e); 255} 256 257static void monitor_bind_ump_reply(struct monitor_binding *dom_binding, 258 uintptr_t my_mon_id, uintptr_t domain_id, 259 errval_t msgerr, struct capref notify) 260{ 261 errval_t err; 262 263 struct remote_conn_state *conn = remote_conn_lookup(my_mon_id); 264 if (conn == NULL) { 265 USER_PANIC("invalid mon_id in UMP bind reply"); 266 return; 267 } 268 269 uintptr_t your_mon_id = conn->mon_id; 270 struct intermon_binding *mon_binding = conn->mon_binding; 271 272 if (err_is_ok(msgerr)) { 273 /* Connection accepted */ 274 conn->domain_id = domain_id; 275 conn->domain_binding = dom_binding; 276 } else { 277//error: 278 /* Free the cap */ 279 err = cap_destroy(conn->x.ump.frame); 280 assert(err_is_ok(err)); 281 282 err = remote_conn_free(my_mon_id); 283 assert(err_is_ok(err)); 284 } 285 286 // Identify notify cap 287 struct capability capability; 288 err = monitor_cap_identify(notify, &capability); 289 if (err_is_fail(err)) { 290 USER_PANIC_ERR(err, "monitor_cap_identify failed, ignored"); 291 return; 292 } 293 assert(capability.type == ObjType_Notify_IPI 294 || capability.type == ObjType_Null); 295 /* assert(capability.u.notify.coreid == my_core_id); */ 296 297 bind_ump_reply_cont(mon_binding, your_mon_id, my_mon_id, msgerr, capability); 298} 299 300/******* stack-ripped intermon_bind_ump_request *******/ 301 302static void bind_ump_service_request_handler(struct monitor_binding *b, 303 struct monitor_msg_queue_elem *e); 304 305struct bind_ump_service_request_state { 306 struct monitor_msg_queue_elem elem; 307 struct monitor_bind_ump_service_request__tx_args args; 308 struct intermon_binding *binding; 309 uintptr_t your_mon_id; 310}; 311 312static void bind_ump_service_request_cont(struct monitor_binding *domain_binding, 313 uintptr_t service_id, 314 con_id_t my_mon_id, 315 struct capref frame, 316 uint32_t channel_length_in, 317 uint32_t channel_length_out, 318 struct capref notify_cap, 319 struct intermon_binding *binding, 320 con_id_t your_mon_id) 321{ 322 errval_t err, err2; 323 324 /* Proxy the request */ 325 err = domain_binding->tx_vtbl. 326 bind_ump_service_request(domain_binding, NOP_CONT, service_id, 327 my_mon_id, frame, 328 channel_length_in, channel_length_out, 329 notify_cap); 330 if (err_is_fail(err)) { 331 if(err_no(err) == FLOUNDER_ERR_TX_BUSY) { 332 struct bind_ump_service_request_state *me = 333 malloc(sizeof(struct bind_ump_service_request_state)); 334 struct monitor_state *ist = domain_binding->st; 335 me->args.service_id = service_id; 336 me->args.mon_id = my_mon_id; 337 me->args.frame = frame; 338 me->args.channel_length_in = channel_length_in; 339 me->args.channel_length_out = channel_length_out; 340 me->args.notify = notify_cap; 341 me->binding = binding; 342 me->your_mon_id = your_mon_id; 343 me->elem.cont = bind_ump_service_request_handler; 344 345 err = monitor_enqueue_send(domain_binding, &ist->queue, 346 get_default_waitset(), &me->elem.queue); 347 assert(err_is_ok(err)); 348 return; 349 } 350 351 err2 = cap_destroy(frame); 352 if (err_is_fail(err2)) { 353 USER_PANIC_ERR(err2, "Cap destroy failed"); 354 } 355 err2 = remote_conn_free(my_mon_id); 356 if (err_is_fail(err2)) { 357 USER_PANIC_ERR(err2, "remote_conn_free failed"); 358 } 359 intermon_caprep_t nullcap = {0,0,0,0}; 360 err2 = binding->tx_vtbl.bind_ump_reply(binding, NOP_CONT, your_mon_id, 0, err, 361 nullcap); 362 if (err_is_fail(err2)) { 363 USER_PANIC_ERR(err2, "Sending bind_ump_reply1 failed"); 364 } 365 } 366} 367 368static void bind_ump_service_request_handler(struct monitor_binding *b, 369 struct monitor_msg_queue_elem *e) 370{ 371 struct bind_ump_service_request_state *st = (struct bind_ump_service_request_state *)e; 372 bind_ump_service_request_cont(b, st->args.service_id, st->args.mon_id, 373 st->args.frame, st->args.channel_length_in, 374 st->args.channel_length_out, st->args.notify, 375 st->binding, st->your_mon_id); 376 free(e); 377} 378 379static void intermon_bind_ump_request(struct intermon_binding *ib, 380 iref_t iref, con_id_t your_mon_id, 381 uint32_t channel_length_in, 382 uint32_t channel_length_out, 383 genpaddr_t framebase, uint8_t framebits, 384 intermon_caprep_t caprep) 385{ 386 errval_t err; 387 388 /* Get client's core_id */ 389 struct intermon_state *ist = ib->st; 390 assert(ist != NULL); 391 coreid_t core_id = ist->core_id; 392 393 /* Construct the frame capability */ 394 struct capability frame_cap = { 395 .type = ObjType_Frame, 396 .rights = CAPRIGHTS_READ_WRITE, // XXX 397 .u.frame = { 398 .base = framebase, 399 .bytes = 1UL << framebits 400 } 401 }; 402 403 // Construct the notify cap 404 struct capref notify_cap = NULL_CAP; 405 struct capability capability; 406 caprep_to_capability(&caprep, &capability); 407 if(capability.type != ObjType_Null) { 408 err = slot_alloc(¬ify_cap); 409 if (err_is_fail(err)) { 410 USER_PANIC_ERR(err, "Failed to allocate slot from channel_alloc"); 411 } 412 err = monitor_cap_create(notify_cap, &capability, core_id); 413 if (err_is_fail(err)) { 414 USER_PANIC_ERR(err, "monitor_cap_create failed"); 415 } 416 } 417 418 // XXX: Put frame cap on a separate allocator as it is not deleted anymore 419 struct capref frame; 420 err = slot_alloc(&frame); 421 if (err_is_fail(err)) { 422 USER_PANIC_ERR(err, "Failed to allocate slot from channel_alloc"); 423 } 424 err = monitor_cap_create(frame, &frame_cap, core_id); 425 if (err_is_fail(err)) { 426 USER_PANIC_ERR(err, "monitor_cap_create failed"); 427 } 428 429 /* Get the server's connection */ 430 struct monitor_binding *domain_binding = NULL; 431 err = iref_get_binding(iref, &domain_binding); 432 assert(err_is_ok(err)); 433 434 /* Get the service id */ 435 uintptr_t service_id = 0; 436 err = iref_get_service_id(iref, &service_id); 437 assert(err_is_ok(err)); 438 439 /* Create a new connection state */ 440 uintptr_t my_mon_id; 441 struct remote_conn_state *con; 442 err = remote_conn_alloc(&con, &my_mon_id, REMOTE_CONN_UMP); 443 assert(err_is_ok(err)); 444 445 // Set the monitor portion of it 446 con->mon_id = your_mon_id; 447 con->mon_binding = ib; 448 con->x.ump.frame = frame; 449 con->core_id = core_id; 450 451 bind_ump_service_request_cont(domain_binding, service_id, my_mon_id, 452 frame, channel_length_in, channel_length_out, 453 notify_cap, ib, your_mon_id); 454} 455 456/******* stack-ripped intermon_bind_ump_reply *******/ 457 458static void bind_ump_reply_client_handler(struct monitor_binding *b, 459 struct monitor_msg_queue_elem *e); 460 461struct bind_ump_reply_client_state { 462 struct monitor_msg_queue_elem elem; 463 struct monitor_bind_ump_reply_client__tx_args args; 464}; 465 466static void bind_ump_reply_client_cont(struct monitor_binding *domain_binding, 467 uintptr_t my_mon_id, 468 uintptr_t domain_id, 469 errval_t msgerr, 470 struct capref notify_cap) 471{ 472 errval_t err; 473 474 err = domain_binding->tx_vtbl. 475 bind_ump_reply_client(domain_binding, NOP_CONT, my_mon_id, domain_id, 476 msgerr, notify_cap); 477 if (err_is_fail(err)) { 478 if(err_no(err) == FLOUNDER_ERR_TX_BUSY) { 479 struct bind_ump_reply_client_state *me = 480 malloc(sizeof(struct bind_ump_reply_client_state)); 481 struct monitor_state *ist = domain_binding->st; 482 me->args.mon_id = my_mon_id; 483 me->args.conn_id = domain_id; 484 me->args.err = msgerr; 485 me->args.notify = notify_cap; 486 me->elem.cont = bind_ump_reply_client_handler; 487 488 err = monitor_enqueue_send(domain_binding, &ist->queue, 489 get_default_waitset(), &me->elem.queue); 490 assert(err_is_ok(err)); 491 return; 492 } 493 494 USER_PANIC_ERR(err, "UMP bind reply failed"); 495 // cleanup 496 err = remote_conn_free(my_mon_id); 497 if (err_is_fail(err)) { 498 USER_PANIC_ERR(err, "remote_conn_free failed"); 499 } 500 } 501} 502 503static void bind_ump_reply_client_handler(struct monitor_binding *b, 504 struct monitor_msg_queue_elem *e) 505{ 506 struct bind_ump_reply_client_state *st = (struct bind_ump_reply_client_state *)e; 507 bind_ump_reply_client_cont(b, st->args.mon_id, st->args.conn_id, 508 st->args.err, st->args.notify); 509 free(e); 510} 511 512static void intermon_bind_ump_reply(struct intermon_binding *ib, 513 uint64_t my_mon_id, uint64_t your_mon_id, 514 errval_t msgerr, 515 intermon_caprep_t caprep) 516{ 517 errval_t err; 518 struct remote_conn_state *con = remote_conn_lookup(my_mon_id); 519 if (con == NULL) { 520 USER_PANIC_ERR(0, "unknown mon_id in UMP bind reply"); 521 return; 522 } 523 524 uintptr_t domain_id = con->domain_id; 525 struct monitor_binding *domain_binding = con->domain_binding; 526 struct capref notify_cap = NULL_CAP; 527 528 if (err_is_ok(msgerr)) { /* bind succeeded */ 529 con->mon_id = your_mon_id; 530 con->mon_binding = ib; 531 532#if 0 533 /* map in UMP channel state */ 534 void *buf; 535 err = vspace_map_one_frame_attr(&buf, 536 2 * (UMP_CHANNEL_SIZE + con->localchan.size * sizeof(uintptr_t)), 537 con->frame, VREGION_FLAGS_READ, 538 NULL, NULL); 539 if (err_is_fail(err)) { 540 USER_PANIC_ERR(err, "vspace_map_one_frame failed"); 541 // XXX: should not be an assert, but we don't have any way to do 542 // connection teardown here! 543 assert(buf != NULL); 544 } 545 con->sharedchan = buf; 546 con->localchan.buf = buf + 2 * UMP_CHANNEL_SIZE; 547 548 // XXX: Put frame cap on a separate allocator as it is not deleted anymore 549 struct capref frame_copy; 550 err = slot_alloc(&frame_copy); 551 if (err_is_fail(err)) { 552 USER_PANIC_ERR(err, "Failed to allocator slot from channel_alloc"); 553 } 554 err = cap_copy(frame_copy, con->frame); 555 if (err_is_fail(err)) { 556 USER_PANIC_ERR(err, "Failed create copy of frame cap"); 557 } 558 err = cap_destroy(con->frame); 559 if (err_is_fail(err)) { 560 USER_PANIC_ERR(err, "cap_destroy_default failed"); 561 } 562 con->frame = frame_copy; 563#endif 564 565 struct capability capability; 566 caprep_to_capability(&caprep, &capability); 567 568 if(capability.type != ObjType_Null) { 569 // Get core id of sender 570 coreid_t core_id = ((struct intermon_state *)ib->st)->core_id; 571 572 // Construct the notify cap 573 err = slot_alloc(¬ify_cap); 574 if (err_is_fail(err)) { 575 USER_PANIC_ERR(err, "Failed to allocate slot from channel_alloc"); 576 } 577 578 err = monitor_cap_create(notify_cap, &capability, core_id); 579 if (err_is_fail(err)) { 580 USER_PANIC_ERR(err, "monitor_cap_create failed"); 581 } 582 } 583 } else { /* bind refused */ 584 err = cap_destroy(con->x.ump.frame); 585 if (err_is_fail(err)) { 586 USER_PANIC_ERR(err, "cap_destroy_default failed"); 587 } 588 err = remote_conn_free(my_mon_id); 589 assert(err_is_ok(err)); 590 } 591 592 bind_ump_reply_client_cont(domain_binding, my_mon_id, domain_id, msgerr, 593 notify_cap); 594} 595 596errval_t ump_intermon_init(struct intermon_binding *ib) 597{ 598 ib->rx_vtbl.bind_ump_request = intermon_bind_ump_request; 599 ib->rx_vtbl.bind_ump_reply = intermon_bind_ump_reply; 600 return SYS_ERR_OK; 601} 602 603errval_t ump_monitor_init(struct monitor_binding *mb) 604{ 605 mb->rx_vtbl.bind_ump_client_request = monitor_bind_ump_client_request; 606 mb->rx_vtbl.bind_ump_reply_monitor = monitor_bind_ump_reply; 607 return SYS_ERR_OK; 608} 609