1/* 2 * Copyright (c) 2012 ETH Zurich. 3 * All rights reserved. 4 * 5 * This file is distributed under the terms in the attached LICENSE file. 6 * If you do not find this file, copies can be found by writing to: 7 * ETH Zurich D-INFK, Universitaetstrasse 6, CH-8092 Zurich. Attn: Systems Group. 8 */ 9 10#include <barrelfish/barrelfish.h> 11#include <barrelfish/caddr.h> 12#include <if/intermon_defs.h> 13#include <monitor.h> 14#include <monitor_invocations.h> 15#include <dom_invocations.h> 16#include "capops.h" 17#include "capsend.h" 18#include "caplock.h" 19#include "internal.h" 20 21/* 22 * Retype states 23 */ 24 25struct retype_check_st { 26 enum objtype type; 27 size_t objsize; 28 size_t count; 29 size_t offset; 30 struct domcapref src; 31 struct result_closure cont; 32}; 33 34struct retype_output_st { 35 struct domcapref destcn; 36 cslot_t start_slot; 37 struct result_closure cont; 38}; 39 40struct requested_retype_st { 41 struct intermon_msg_queue_elem queue_elem; 42 struct retype_check_st check; 43 struct capref src; 44 coreid_t from; 45 errval_t status; 46 genvaddr_t request_st; 47}; 48 49struct local_retype_st { 50 struct retype_check_st check; 51 struct retype_output_st output; 52}; 53 54struct retype_request_st { 55 struct intermon_msg_queue_elem queue_elem; 56 intermon_caprep_t caprep; 57 struct retype_check_st check; 58 struct retype_output_st output; 59}; 60 61static uint64_t retype_seqnum = 0; 62 63/* 64 * Prototypes for static functions so ordering does not matter 65 */ 66 67static void check_retype__enq(struct retype_check_st *check_st); 68static void retype_check__rx(errval_t status, struct retype_check_st* check, 69 struct retype_output_st *output, void *to_free); 70 71/** 72 * \brief Intermon is ready to send retype result 73 */ 74static void 75retype_result__send(struct intermon_binding *b, struct intermon_msg_queue_elem *e) 76{ 77 TRACE(CAPOPS, RETYPE_RESULT_SEND, 0); 78 DEBUG_CAPOPS("%s\n", __FUNCTION__); 79 errval_t err; 80 struct requested_retype_st *req_st = (struct requested_retype_st*)e; 81 err = intermon_capops_retype_response__tx(b, NOP_CONT, req_st->status, 82 req_st->request_st); 83 84 if (err_no(err) == FLOUNDER_ERR_TX_BUSY) { 85 DEBUG_CAPOPS("%s: got FLOUNDER_ERR_TX_BUSY; requeueing msg.\n", __FUNCTION__); 86 struct intermon_state *inter_st = (struct intermon_state *)b->st; 87 // requeue send request at front and return 88 err = intermon_enqueue_send_at_front(b, &inter_st->queue, b->waitset, 89 (struct msg_queue_elem *)e); 90 GOTO_IF_ERR(err, handle_err); 91 return; 92 } 93 94handle_err: 95 PANIC_IF_ERR(err, "sending retype result message"); 96 free(req_st); 97} 98 99/** 100 * \brief Enqueue retype result 101 */ 102static void 103retype_result__enq(struct requested_retype_st *req_st) 104{ 105 TRACE(CAPOPS, RETYPE_RESULT_ENQ, 0); 106 DEBUG_CAPOPS("%s\n", __FUNCTION__); 107 req_st->queue_elem.cont = retype_result__send; 108 errval_t err = capsend_target(req_st->from, (struct msg_queue_elem*)req_st); 109 if (err_is_fail(err)) { 110 DEBUG_ERR(err, "failed to enqueue retype result"); 111 free(req_st); 112 } 113} 114 115/** 116 * \brief Retype temporary cap has been deleted 117 */ 118static void 119retype_tmpcap_delete__cont(errval_t status, void *st) 120{ 121 TRACE(CAPOPS, RETYPE_DEL_TMPCAP_DONE, 0); 122 DEBUG_CAPOPS("%s\n", __FUNCTION__); 123 errval_t err; 124 struct requested_retype_st *req_st = (struct requested_retype_st*)st; 125 126 if (err_is_fail(status) && err_no(status) != SYS_ERR_CAP_NOT_FOUND) { 127 DEBUG_ERR(status, "deleting tmp retype cap, cap will leak"); 128 } 129 130 err = slot_free(req_st->src); 131 DEBUG_IF_ERR(err, "freeing tmp retype slot, slot will leak"); 132 req_st->src = NULL_CAP; 133 memset(&req_st->check.src, 0, sizeof(struct domcapref)); 134 135 retype_result__enq(req_st); 136} 137 138/** 139 * \brief The check for a retype request has completed 140 */ 141static void 142retype_request_check__rx(errval_t status, void *st) 143{ 144 DEBUG_CAPOPS("%s\n", __FUNCTION__); 145 struct requested_retype_st *req_st = (struct requested_retype_st*)st; 146 147 if (err_is_ok(status)) { 148 status = monitor_remote_relations(req_st->src, RRELS_DESC_BIT, 149 RRELS_DESC_BIT, NULL); 150 } 151 152 req_st->status = status; 153 154 if (!capref_is_null(req_st->src)) { 155 DEBUG_CAPOPS("capops_retype: cleaning up our copy of src\n"); 156 TRACE(CAPOPS, RETYPE_DEL_TMPCAP, 0); 157 capops_delete(req_st->check.src, retype_tmpcap_delete__cont, req_st); 158 } 159 else { 160 retype_result__enq(req_st); 161 } 162} 163 164void 165retype_request__rx(struct intermon_binding *b, intermon_caprep_t srcrep, uint64_t offset, 166 uint32_t desttype, uint64_t destsize, uint64_t count, genvaddr_t st) 167{ 168 TRACE(CAPOPS, RETYPE_REQUEST_RX, 0); 169 DEBUG_CAPOPS("%s\n", __FUNCTION__); 170 errval_t err; 171 172 // allocate and setup state 173 struct requested_retype_st *req_st; 174 err = calloce(1, sizeof(*req_st), &req_st); 175 PANIC_IF_ERR(err, "allocating retype request state"); 176 177 req_st->queue_elem.cont = retype_result__send; 178 req_st->check.type = desttype; 179 req_st->check.objsize = destsize; 180 req_st->check.count = count; 181 req_st->check.offset = offset; 182 req_st->check.cont = MKRESCONT(retype_request_check__rx, req_st); 183 req_st->from = ((struct intermon_state*)b->st)->core_id; 184 req_st->request_st = st; 185 186 // get slot and cap 187 err = slot_alloc(&req_st->src); 188 GOTO_IF_ERR(err, cont_err); 189 req_st->check.src = get_cap_domref(req_st->src); 190 191 struct capability cap; 192 caprep_to_capability(&srcrep, &cap); 193 err = monitor_copy_if_exists(&cap, req_st->src); 194 GOTO_IF_ERR(err, cont_err); 195 196 // validate cap state 197 distcap_state_t state; 198 err = dom_cnode_get_state(req_st->check.src, &state); 199 GOTO_IF_ERR(err, cont_err); 200 201 if (distcap_state_is_foreign(state)) { 202 err = MON_ERR_CAP_FOREIGN; 203 goto cont_err; 204 } 205 if (distcap_state_is_busy(state)) { 206 err = MON_ERR_REMOTE_CAP_RETRY; 207 goto cont_err; 208 } 209 210 // check retypeability on self (owner) 211 err = monitor_is_retypeable(&cap, req_st->check.offset, 212 req_st->check.objsize, req_st->check.count); 213 // If this returns an error, including SYS_ERR_REVOKE_FIRST, we do not 214 // have to check retypeability on the other cores. 215 if (err_is_fail(err)) { 216 goto cont_err; 217 } 218 219 // initiate check on other cores 220 check_retype__enq(&req_st->check); 221 222 return; 223 224cont_err: 225 retype_request_check__rx(err, req_st); 226} 227 228static void 229retype_result__rx(errval_t status, struct retype_request_st *req_st) 230{ 231 TRACE(CAPOPS, RETYPE_RESULT_RX, 0); 232 DEBUG_CAPOPS("%s\n", __FUNCTION__); 233 retype_check__rx(status, &req_st->check, &req_st->output, req_st); 234} 235 236/** 237 * \brief Handle the response to a retype request 238 */ 239void 240retype_response__rx(struct intermon_binding *b, errval_t status, genvaddr_t st) 241{ 242 TRACE(CAPOPS, RETYPE_RESPONSE_RX, 0); 243 DEBUG_CAPOPS("%s\n", __FUNCTION__); 244 struct retype_request_st *req_st = (struct retype_request_st*)(lvaddr_t)st; 245 retype_result__rx(status, req_st); 246} 247 248/** 249 * \brief Intermon is ready to send request_retype 250 */ 251static void 252retype_request__send(struct intermon_binding *b, struct intermon_msg_queue_elem *e) 253{ 254 TRACE(CAPOPS, RETYPE_REQUEST_SEND, 0); 255 DEBUG_CAPOPS("%s\n", __FUNCTION__); 256 struct retype_request_st *req_st = (struct retype_request_st*)e; 257 errval_t err; 258 259 err = intermon_capops_request_retype__tx(b, NOP_CONT, req_st->caprep, 260 req_st->check.offset, 261 req_st->check.type, 262 req_st->check.objsize, 263 req_st->check.count, 264 (lvaddr_t)req_st); 265 266 267 if (err_no(err) == FLOUNDER_ERR_TX_BUSY) { 268 DEBUG_CAPOPS("%s: got FLOUNDER_ERR_TX_BUSY; requeueing msg.\n", __FUNCTION__); 269 struct intermon_state *inter_st = (struct intermon_state *)b->st; 270 // requeue send request at front and return 271 err = intermon_enqueue_send_at_front(b, &inter_st->queue, b->waitset, 272 (struct msg_queue_elem *)e); 273 GOTO_IF_ERR(err, handle_err); 274 return; 275 } 276 277handle_err: 278 if (err_is_fail(err)) { 279 retype_result__rx(err, req_st); 280 } 281} 282 283/** 284 * \brief Enqueue a retype request 285 */ 286static void 287retype_request__enq(struct retype_request_st *req_st) 288{ 289 TRACE(CAPOPS, RETYPE_REQUEST_ENQ, 0); 290 DEBUG_CAPOPS("%s\n", __FUNCTION__); 291 errval_t err; 292 struct capability cap; 293 err = monitor_domains_cap_identify(req_st->check.src.croot, 294 req_st->check.src.cptr, 295 req_st->check.src.level, &cap); 296 GOTO_IF_ERR(err, err_cont); 297 298 req_st->queue_elem.cont = retype_request__send; 299 capability_to_caprep(&cap, &req_st->caprep); 300 301 err = capsend_owner(req_st->check.src, (struct msg_queue_elem*)req_st); 302 GOTO_IF_ERR(err, err_cont); 303 304 return; 305 306err_cont: 307 retype_result__rx(err, req_st); 308} 309 310/** 311 * \brief The descendants search has completed 312 */ 313static void 314check_retypeable__rx(errval_t status, void *st) 315{ 316 TRACE(CAPOPS, RETYPE_CHECK_RETYPEABLE_RX, 0); 317 DEBUG_CAPOPS("%s: status=%s\n", __FUNCTION__, err_getcode(status)); 318 struct retype_check_st *check_st = (struct retype_check_st*)st; 319 320 // need to translate error codes: 321 // - not found -> ok 322 // - otherwise -> unchanged 323 if (err_no(status) == SYS_ERR_CAP_NOT_FOUND) { 324 status = err_push(status, SYS_ERR_OK); 325 } 326 327 // unlock cap and procede with check result continuation 328 caplock_unlock(check_st->src); 329 CALLRESCONT(check_st->cont, status); 330} 331 332/** 333 * \brief Enqueue a retype check 334 */ 335static void 336check_retype__enq(struct retype_check_st *check_st) 337{ 338 TRACE(CAPOPS, RETYPE_CHECK_ENQ, 0); 339 DEBUG_CAPOPS("%s\n", __FUNCTION__); 340 errval_t err; 341 342 if (check_st->type == ObjType_EndPointLMP) { 343 DEBUG_CAPOPS("%s: type = EndPoint\n", __FUNCTION__); 344 // XXX: because of the current "multi-retype" hack for endpoints, a 345 // dispatcher->endpoint retype can happen irrespective of the existence 346 // of descendents on any core. 347 err = monitor_domcap_remote_relations(check_st->src.croot, 348 check_st->src.cptr, 349 check_st->src.level, 350 RRELS_DESC_BIT, 351 RRELS_DESC_BIT, NULL); 352 goto cont_err; 353 } 354 355 DEBUG_CAPOPS("%s: locking cap\n", __FUNCTION__); 356 err = monitor_lock_cap(check_st->src.croot, check_st->src.cptr, 357 check_st->src.level); 358 GOTO_IF_ERR(err, cont_err); 359 360 DEBUG_CAPOPS("%s: checking retypeability of cap\n", __FUNCTION__); 361 err = capsend_check_retypeable(check_st->src, check_st->offset, 362 check_st->objsize, check_st->count, 363 check_retypeable__rx, check_st); 364 GOTO_IF_ERR(err, unlock_cap); 365 366 return; 367 368unlock_cap: 369 caplock_unlock(check_st->src); 370 371cont_err: 372 TRACE(CAPOPS, RETYPE_CALL_RESULT, retype_seqnum); 373 CALLRESCONT(check_st->cont, err); 374} 375 376/** 377 * \brief Handle a completed retype check 378 */ 379static void 380retype_check__rx(errval_t status, struct retype_check_st* check, 381 struct retype_output_st *output, void *to_free) 382{ 383 TRACE(CAPOPS, RETYPE_CHECK_RX, retype_seqnum); 384 DEBUG_CAPOPS("%s\n", __FUNCTION__); 385 errval_t err; 386 struct domcapref *src = &check->src; 387 struct domcapref *destcn = &output->destcn; 388 if (err_is_ok(status)) { 389 // the retype may procede 390 TRACE(CAPOPS, MONITOR_RETYPE_CREATE_CAPS, retype_seqnum); 391 status = monitor_create_caps(src->croot, destcn->croot, check->type, 392 check->objsize, check->count, src->cptr, 393 src->level, check->offset, destcn->cptr, 394 destcn->level, output->start_slot); 395 TRACE(CAPOPS, MONITOR_RETYPE_CREATE_CAPS_DONE, retype_seqnum); 396 } 397 struct result_closure cont = output->cont; 398 assert(cont.handler); 399 free(to_free); 400 // Delete copies of domain's src/dest root cnodes 401 if (!capcmp(destcn->croot, src->croot)) { 402 err = cap_destroy(destcn->croot); 403 PANIC_IF_ERR(err, "deleting monitor's copy dest rootcn"); 404 } 405 err = cap_destroy(src->croot); 406 PANIC_IF_ERR(err, "deleting monitor's copy of src rootcn"); 407 TRACE(CAPOPS, RETYPE_CALL_RESULT, retype_seqnum); 408 CALLRESCONT(cont, status); 409} 410 411/** 412 * \brief Handle result of a owner-initiated retype check. 413 */ 414static void 415local_retype_check__rx(errval_t status, void *st) 416{ 417 TRACE(CAPOPS, RETYPE_LOCAL_CHECK_RX, 0); 418 DEBUG_CAPOPS("%s\n", __FUNCTION__); 419 struct local_retype_st *rtp_st = (struct local_retype_st*)st; 420 retype_check__rx(status, &rtp_st->check, &rtp_st->output, rtp_st); 421} 422 423/* 424 * Entry 425 */ 426 427void 428capops_retype(enum objtype type, size_t objsize, size_t count, struct capref dest_root, 429 capaddr_t dest_cn, uint8_t dest_level, cslot_t dest_slot, 430 struct capref src_root, capaddr_t src, uint8_t src_level, 431 gensize_t offset, retype_result_handler_t result_handler, void *st) 432{ 433 TRACE(CAPOPS, RETYPE_START, ++retype_seqnum); 434 DEBUG_CAPOPS("%s\n", __FUNCTION__); 435 errval_t err; 436 distcap_state_t src_state; 437 struct retype_request_st *rtp_req_st; 438 struct local_retype_st *rtp_loc_st; 439 440 err = invoke_cnode_get_state(src_root, src, src_level, &src_state); 441 GOTO_IF_ERR(err, err_cont); 442 443 if (distcap_state_is_busy(src_state)) { 444 err = MON_ERR_REMOTE_CAP_RETRY; 445 goto err_cont; 446 } 447 448 err = invoke_cnode_retype(cap_root, get_cap_addr(src_root), src, 449 offset, type, objsize, count, get_cap_addr(dest_root), 450 dest_cn, dest_level, dest_slot); 451 if (err_no(err) != SYS_ERR_RETRY_THROUGH_MONITOR) { 452 goto err_cont; 453 } 454 455 // if retype invocation failed with "retry through mon", we assume that 456 // distcap_needs_locality(cap) would return true. 457 458 if (distcap_state_is_foreign(src_state)) { 459 DEBUG_CAPOPS("source is foreign; forward request to owner\n"); 460 // setup retype request 461 err = calloce(1, sizeof(*rtp_req_st), &rtp_req_st); 462 GOTO_IF_ERR(err, err_cont); 463 464 // fill in parameters 465 rtp_req_st->check.type = type; 466 rtp_req_st->check.objsize = objsize; 467 rtp_req_st->check.count = count; 468 rtp_req_st->check.offset = offset; 469 rtp_req_st->check.src = (struct domcapref){ 470 .croot = src_root, 471 .cptr = src, 472 .level = src_level, 473 }; 474 rtp_req_st->output.destcn = (struct domcapref){ 475 .croot = dest_root, 476 .cptr = dest_cn, 477 .level = dest_level, 478 }; 479 rtp_req_st->output.start_slot = dest_slot; 480 rtp_req_st->output.cont = MKRESCONT(result_handler, st); 481 482 // enqueue retype request 483 retype_request__enq(rtp_req_st); 484 } 485 else { 486 DEBUG_CAPOPS("source is local; run retype check\n"); 487 // on owner, setup retype check 488 err = calloce(1, sizeof(*rtp_loc_st), &rtp_loc_st); 489 GOTO_IF_ERR(err, err_cont); 490 491 // fill in parameters 492 rtp_loc_st->check.type = type; 493 rtp_loc_st->check.objsize = objsize; 494 rtp_loc_st->check.count = count; 495 rtp_loc_st->check.offset = offset; 496 rtp_loc_st->check.src = (struct domcapref){ 497 .croot = src_root, 498 .cptr = src, 499 .level = src_level, 500 }; 501 rtp_loc_st->output.destcn = (struct domcapref){ 502 .croot = dest_root, 503 .cptr = dest_cn, 504 .level = dest_level, 505 }; 506 rtp_loc_st->output.start_slot = dest_slot; 507 rtp_loc_st->output.cont = MKRESCONT(result_handler, st); 508 509 // setup handler for retype check result 510 rtp_loc_st->check.cont = MKRESCONT(local_retype_check__rx, rtp_loc_st); 511 512 // Can skip testing retypeability on our core here, as that will be 513 // done by the final retype invocation anyway 514 515 // initiate check 516 check_retype__enq(&rtp_loc_st->check); 517 } 518 519 return; 520 521err_cont: 522 TRACE(CAPOPS, RETYPE_CALL_RESULT, retype_seqnum); 523 result_handler(err, st); 524} 525 526