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