2 * Copyright (c) 2012 ETH Zurich.
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.
10 #include <barrelfish/barrelfish.h>
11 #include <barrelfish/caddr.h>
12 #include <if/intermon_defs.h>
14 #include <monitor_invocations.h>
15 #include <dom_invocations.h>
26 struct retype_check_st {
30 struct result_closure cont;
33 struct retype_output_st {
34 struct domcapref destcn;
36 struct result_closure cont;
39 struct requested_retype_st {
40 struct intermon_msg_queue_elem queue_elem;
41 struct retype_check_st check;
45 genvaddr_t request_st;
48 struct local_retype_st {
49 struct retype_check_st check;
50 struct retype_output_st output;
53 struct retype_request_st {
54 struct intermon_msg_queue_elem queue_elem;
55 intermon_caprep_t caprep;
56 struct retype_check_st check;
57 struct retype_output_st output;
61 * Prototypes for static functions so ordering does not matter
64 static void check_retype__enq(struct retype_check_st *check_st);
65 static void retype_check__rx(errval_t status, struct retype_check_st* check,
66 struct retype_output_st *output, void *to_free);
69 * \brief Intermon is ready to send retype result
72 retype_result__send(struct intermon_binding *b, struct intermon_msg_queue_elem *e)
75 struct requested_retype_st *req_st = (struct requested_retype_st*)e;
76 err = intermon_capops_retype_response__tx(b, NOP_CONT, req_st->status,
79 if (err_no(err) == FLOUNDER_ERR_TX_BUSY) {
80 DEBUG_CAPOPS("%s: got FLOUNDER_ERR_TX_BUSY; requeueing msg.\n", __FUNCTION__);
81 struct intermon_state *inter_st = (struct intermon_state *)b->st;
82 // requeue send request at front and return
83 err = intermon_enqueue_send_at_front(b, &inter_st->queue, b->waitset,
84 (struct msg_queue_elem *)e);
85 GOTO_IF_ERR(err, handle_err);
90 PANIC_IF_ERR(err, "sending retype result message");
95 * \brief Enqueue retype result
98 retype_result__enq(struct requested_retype_st *req_st)
100 req_st->queue_elem.cont = retype_result__send;
101 errval_t err = capsend_target(req_st->from, (struct msg_queue_elem*)req_st);
102 if (err_is_fail(err)) {
103 DEBUG_ERR(err, "failed to enqueue retype result");
109 * \brief Retype temporary cap has been deleted
112 retype_tmpcap_delete__cont(errval_t status, void *st)
115 struct requested_retype_st *req_st = (struct requested_retype_st*)st;
117 if (err_is_fail(status) && err_no(status) != SYS_ERR_CAP_NOT_FOUND) {
118 DEBUG_ERR(status, "deleting tmp retype cap, cap will leak");
121 err = slot_free(req_st->src);
122 DEBUG_IF_ERR(err, "freeing tmp retype slot, slot will leak");
123 req_st->src = NULL_CAP;
124 memset(&req_st->check.src, 0, sizeof(struct domcapref));
126 retype_result__enq(req_st);
130 * \brief The check for a retype request has completed
133 retype_request_check__rx(errval_t status, void *st)
135 struct requested_retype_st *req_st = (struct requested_retype_st*)st;
137 if (err_is_ok(status)) {
138 status = monitor_remote_relations(req_st->src, RRELS_DESC_BIT,
139 RRELS_DESC_BIT, NULL);
142 req_st->status = status;
144 if (!capref_is_null(req_st->src)) {
145 capops_delete(req_st->check.src, retype_tmpcap_delete__cont, req_st);
148 retype_result__enq(req_st);
153 retype_request__rx(struct intermon_binding *b, intermon_caprep_t srcrep,
154 uint32_t desttype, uint32_t destbits, genvaddr_t st)
158 // allocate and setup state
159 struct requested_retype_st *req_st;
160 err = calloce(1, sizeof(*req_st), &req_st);
161 PANIC_IF_ERR(err, "allocating retype request state");
163 req_st->queue_elem.cont = retype_result__send;
164 req_st->check.type = desttype;
165 req_st->check.objbits = destbits;
166 req_st->check.cont = MKRESCONT(retype_request_check__rx, req_st);
167 req_st->from = ((struct intermon_state*)b->st)->core_id;
168 req_st->request_st = st;
171 err = slot_alloc(&req_st->src);
172 GOTO_IF_ERR(err, cont_err);
173 req_st->check.src = get_cap_domref(req_st->src);
175 struct capability cap;
176 caprep_to_capability(&srcrep, &cap);
177 err = monitor_copy_if_exists(&cap, req_st->src);
178 GOTO_IF_ERR(err, cont_err);
180 // validate cap state
181 distcap_state_t state;
182 err = dom_cnode_get_state(req_st->check.src, &state);
183 GOTO_IF_ERR(err, cont_err);
185 if (distcap_state_is_foreign(state)) {
186 err = MON_ERR_CAP_FOREIGN;
189 if (distcap_state_is_busy(state)) {
190 err = MON_ERR_REMOTE_CAP_RETRY;
195 check_retype__enq(&req_st->check);
200 retype_request_check__rx(err, req_st);
204 retype_result__rx(errval_t status, struct retype_request_st *req_st)
206 retype_check__rx(status, &req_st->check, &req_st->output, req_st);
210 * \brief Handle the response to a retype request
213 retype_response__rx(struct intermon_binding *b, errval_t status, genvaddr_t st)
215 struct retype_request_st *req_st = (struct retype_request_st*)(lvaddr_t)st;
216 retype_result__rx(status, req_st);
220 * \brief Intermon is ready to send request_retype
223 retype_request__send(struct intermon_binding *b, struct intermon_msg_queue_elem *e)
225 struct retype_request_st *req_st = (struct retype_request_st*)e;
228 err = intermon_capops_request_retype__tx(b, NOP_CONT, req_st->caprep,
230 req_st->check.objbits,
234 if (err_no(err) == FLOUNDER_ERR_TX_BUSY) {
235 DEBUG_CAPOPS("%s: got FLOUNDER_ERR_TX_BUSY; requeueing msg.\n", __FUNCTION__);
236 struct intermon_state *inter_st = (struct intermon_state *)b->st;
237 // requeue send request at front and return
238 err = intermon_enqueue_send_at_front(b, &inter_st->queue, b->waitset,
239 (struct msg_queue_elem *)e);
240 GOTO_IF_ERR(err, handle_err);
245 if (err_is_fail(err)) {
246 retype_result__rx(err, req_st);
251 * \brief Enqueue a retype request
254 retype_request__enq(struct retype_request_st *req_st)
257 struct capability cap;
258 err = monitor_domains_cap_identify(req_st->check.src.croot,
259 req_st->check.src.cptr,
260 req_st->check.src.bits, &cap);
261 GOTO_IF_ERR(err, err_cont);
263 req_st->queue_elem.cont = retype_request__send;
264 capability_to_caprep(&cap, &req_st->caprep);
266 err = capsend_owner(req_st->check.src, (struct msg_queue_elem*)req_st);
267 GOTO_IF_ERR(err, err_cont);
272 retype_result__rx(err, req_st);
276 * \brief The descendants search has completed
279 find_descendants__rx(errval_t status, void *st)
281 struct retype_check_st *check_st = (struct retype_check_st*)st;
283 // need to translate error codes:
284 // - descendants found -> revoke first
286 // - otherwise -> unchanged
287 if (err_is_ok(status)) {
288 status = SYS_ERR_REVOKE_FIRST;
290 else if (err_no(status) == SYS_ERR_CAP_NOT_FOUND) {
291 status = err_push(status, SYS_ERR_OK);
294 // unlock cap and procede with check result continuation
295 caplock_unlock(check_st->src);
296 CALLRESCONT(check_st->cont, status);
300 * \brief Enqueue a retype check
303 check_retype__enq(struct retype_check_st *check_st)
307 if (check_st->type == ObjType_EndPoint) {
308 // XXX: because of the current "multi-retype" hack for endpoints, a
309 // dispatcher->endpoint retype can happen irrespective of the existence
310 // of descendents on any core.
311 err = monitor_domcap_remote_relations(check_st->src.croot,
315 RRELS_DESC_BIT, NULL);
319 err = monitor_lock_cap(check_st->src.croot, check_st->src.cptr,
321 GOTO_IF_ERR(err, cont_err);
323 err = capsend_find_descendants(check_st->src, find_descendants__rx,
325 GOTO_IF_ERR(err, unlock_cap);
330 caplock_unlock(check_st->src);
333 CALLRESCONT(check_st->cont, err);
337 * \brief Handle a completed retype check
340 retype_check__rx(errval_t status, struct retype_check_st* check,
341 struct retype_output_st *output, void *to_free)
343 errval_t err = status;
344 if (err_is_ok(err)) {
345 // the retype may procede
346 struct domcapref *src = &check->src;
347 struct domcapref *destcn = &output->destcn;
348 assert(capcmp(src->croot, destcn->croot));
349 err = monitor_create_caps(src->croot, check->type, check->objbits,
350 src->cptr, src->bits, destcn->cptr,
351 destcn->bits, output->start_slot);
353 struct result_closure cont = output->cont;
354 assert(cont.handler);
356 CALLRESCONT(cont, err);
360 * \brief Handle result of a owner-initiated retype check.
363 local_retype_check__rx(errval_t status, void *st)
365 struct local_retype_st *rtp_st = (struct local_retype_st*)st;
366 retype_check__rx(status, &rtp_st->check, &rtp_st->output, rtp_st);
374 capops_retype(enum objtype type, size_t objbits, struct capref croot,
375 capaddr_t dest_cn, uint8_t dest_bits, cslot_t dest_slot,
376 capaddr_t src, uint8_t src_bits,
377 retype_result_handler_t result_handler, void *st)
380 distcap_state_t src_state;
381 struct retype_request_st *rtp_req_st;
382 struct local_retype_st *rtp_loc_st;
384 err = invoke_cnode_get_state(croot, src, src_bits, &src_state);
385 GOTO_IF_ERR(err, err_cont);
387 if (distcap_state_is_busy(src_state)) {
388 err = MON_ERR_REMOTE_CAP_RETRY;
392 err = invoke_cnode_retype(croot, src, type, objbits, dest_cn, dest_slot,
394 if (err_no(err) != SYS_ERR_RETRY_THROUGH_MONITOR) {
398 // if retype invocation failed with "retry through mon", we assume that
399 // distcap_needs_locality(cap) would return true.
401 if (distcap_state_is_foreign(src_state)) {
402 // setup retype request
403 err = calloce(1, sizeof(*rtp_req_st), &rtp_req_st);
404 GOTO_IF_ERR(err, err_cont);
406 // fill in parameters
407 rtp_req_st->check.type = type;
408 rtp_req_st->check.objbits = objbits;
409 rtp_req_st->check.src = (struct domcapref){
414 rtp_req_st->output.destcn = (struct domcapref){
419 rtp_req_st->output.start_slot = dest_slot;
420 rtp_req_st->output.cont = MKRESCONT(result_handler, st);
422 // enqueue retype request
423 retype_request__enq(rtp_req_st);
426 // on owner, setup retype check
427 err = calloce(1, sizeof(*rtp_loc_st), &rtp_loc_st);
428 GOTO_IF_ERR(err, err_cont);
430 // fill in parameters
431 rtp_loc_st->check.type = type;
432 rtp_loc_st->check.objbits = objbits;
433 rtp_loc_st->check.src = (struct domcapref){
438 rtp_loc_st->output.destcn = (struct domcapref){
443 rtp_loc_st->output.start_slot = dest_slot;
444 rtp_loc_st->output.cont = MKRESCONT(result_handler, st);
446 // setup handler for retype check result
447 rtp_loc_st->check.cont = MKRESCONT(local_retype_check__rx, rtp_loc_st);
450 check_retype__enq(&rtp_loc_st->check);
456 result_handler(err, st);