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 <if/intermon_defs.h> 12#include "monitor.h" 13#include "capops.h" 14#include "capsend.h" 15#include "caplock.h" 16#include "internal.h" 17#include "dom_invocations.h" 18#include "monitor_invocations.h" 19 20struct retrieve_rpc_st { 21 struct intermon_msg_queue_elem iqn; 22 struct domcapref cap; 23 struct capability rawcap; 24 move_result_handler_t result_handler; 25 void *st; 26 coreid_t prev_owner; 27}; 28 29struct retrieve_response_st { 30 struct intermon_msg_queue_elem iqn; 31 errval_t status; 32 uint8_t relations; 33 genvaddr_t st; 34 coreid_t from; 35}; 36 37static void retrieve_owner__enq(struct retrieve_rpc_st *st); 38static void retrieve_owner__send(struct intermon_binding *b, 39 struct intermon_msg_queue_elem *e); 40static void retrieve_result__enq(errval_t status, 41 struct retrieve_response_st *st); 42static void retrieve_result__send(struct intermon_binding *b, 43 struct intermon_msg_queue_elem *e); 44static void retrieve_ownership_update__fin(void *st); 45 46void 47capops_retrieve(struct domcapref cap, 48 move_result_handler_t result_handler, 49 void *st) 50{ 51 errval_t err; 52 53 DEBUG_CAPOPS("%s ## start transfer ownership \n", __FUNCTION__); 54 55 distcap_state_t state; 56 err = dom_cnode_get_state(cap, &state); 57 GOTO_IF_ERR(err, report_error); 58 if (distcap_state_is_busy(state)) { 59 err = MON_ERR_REMOTE_CAP_RETRY; 60 } 61 GOTO_IF_ERR(err, report_error); 62 63 err = monitor_lock_cap(cap.croot, cap.cptr, cap.level); 64 GOTO_IF_ERR(err, report_error); 65 66 struct retrieve_rpc_st *rst = NULL; 67 err = calloce(1, sizeof(*rst), &rst); 68 GOTO_IF_ERR(err, unlock_cap); 69 70 rst->cap = cap; 71 rst->result_handler = result_handler; 72 rst->st = st; 73 74 err = monitor_domains_cap_identify(cap.croot, cap.cptr, cap.level, &rst->rawcap); 75 GOTO_IF_ERR(err, free_st); 76 77 err = monitor_get_domcap_owner(cap, &rst->prev_owner); 78 GOTO_IF_ERR(err, free_st); 79 80 if (rst->prev_owner == my_core_id) { 81 err = SYS_ERR_OK; 82 goto free_st; 83 } 84 85 retrieve_owner__enq(rst); 86 87 return; 88 89free_st: 90 free(rst); 91 92unlock_cap: 93 caplock_unlock(cap); 94 95report_error: 96 result_handler(err, st); 97} 98 99static void 100retrieve_ownership__rx(errval_t status, struct retrieve_rpc_st *st) 101{ 102 DEBUG_CAPOPS("%s ## transfer ownership done. calling %p\n", __FUNCTION__, 103 st->result_handler); 104 105 caplock_unlock(st->cap); 106 st->result_handler(status, st->st); 107 free(st); 108} 109 110static void 111retrieve_owner__enq(struct retrieve_rpc_st *st) 112{ 113 errval_t err; 114 115 st->iqn.cont = retrieve_owner__send; 116 err = capsend_owner(st->cap, (struct msg_queue_elem*)st); 117 if (err_is_fail(err)) { 118 retrieve_ownership__rx(err, st); 119 } 120} 121 122static void 123retrieve_owner__send(struct intermon_binding *b, 124 struct intermon_msg_queue_elem *e) 125{ 126 errval_t err; 127 struct retrieve_rpc_st *st = (struct retrieve_rpc_st*)e; 128 intermon_caprep_t caprep; 129 130 err = monitor_set_domcap_owner(st->cap, my_core_id); 131 GOTO_IF_ERR(err, report_error); 132 133 capability_to_caprep(&st->rawcap, &caprep); 134 err = intermon_capops_retrieve_request__tx(b, NOP_CONT, caprep, (lvaddr_t)st); 135 136 if (err_no(err) == FLOUNDER_ERR_TX_BUSY) { 137 DEBUG_CAPOPS("%s: got FLOUNDER_ERR_TX_BUSY; requeueing msg.\n", __FUNCTION__); 138 struct intermon_state *inter_st = (struct intermon_state *)b->st; 139 // requeue send request at front and return 140 err = intermon_enqueue_send_at_front(b, &inter_st->queue, b->waitset, 141 (struct msg_queue_elem *)e); 142 } 143 144 GOTO_IF_ERR(err, report_error); 145 146 return; 147 148report_error: 149 DEBUG_CAPOPS("%s failed \n", __FUNCTION__); 150 retrieve_ownership__rx(err, st); 151} 152 153void 154retrieve_request__rx(struct intermon_binding *b, 155 intermon_caprep_t caprep, 156 genvaddr_t st) 157{ 158 errval_t err, err2; 159 struct intermon_state *inter_st = (struct intermon_state*)b->st; 160 161 DEBUG_CAPOPS("%s ## transfer ownership request\n", __FUNCTION__); 162 163 struct retrieve_response_st *rst; 164 err = calloce(1, sizeof(*rst), &rst); 165 PANIC_IF_ERR(err, "allocating retrieve respones state"); 166 rst->st = st; 167 rst->from = inter_st->core_id; 168 169 struct capability rawcap; 170 caprep_to_capability(&caprep, &rawcap); 171 172 struct capref cap; 173 err = slot_alloc(&cap); 174 GOTO_IF_ERR(err, respond_err); 175 176 err = monitor_copy_if_exists(&rawcap, cap); 177 GOTO_IF_ERR(err, free_slot); 178 179 distcap_state_t state; 180 err = dom_cnode_get_state(get_cap_domref(cap), &state); 181 GOTO_IF_ERR(err, delete_cap); 182 183 if (distcap_state_is_busy(state)) { 184 err = MON_ERR_REMOTE_CAP_RETRY; 185 goto delete_cap; 186 } 187 if (distcap_state_is_foreign(state)) { 188 err = MON_ERR_CAP_FOREIGN; 189 goto delete_cap; 190 } 191 192 uint8_t relations, remote_relations; 193 err = monitor_cap_has_relations(cap, 0xFF, &relations); 194 GOTO_IF_ERR(err, delete_cap); 195 196 err = monitor_remote_relations(cap, 0, 0, &remote_relations); 197 GOTO_IF_ERR(err, delete_cap); 198 199 rst->relations = relations | remote_relations | RRELS_COPY_BIT; 200 201 err = monitor_set_cap_owner(cap_root, get_cap_addr(cap), 202 get_cap_level(cap), 203 rst->from); 204 205delete_cap: 206 err2 = cap_delete(cap); 207 DEBUG_IF_ERR(err2, "while deleting temp cap for retrieve"); 208 209free_slot: 210 err2 = slot_free(cap); 211 DEBUG_IF_ERR(err2, "freeing temp cap slot for retrieve"); 212 213respond_err: 214 retrieve_result__enq(err, rst); 215} 216 217static void 218retrieve_result__enq(errval_t status, struct retrieve_response_st *st) 219{ 220 errval_t err; 221 st->status = status; 222 st->iqn.cont = retrieve_result__send; 223 224 err = capsend_target(st->from, (struct msg_queue_elem*)st); 225 PANIC_IF_ERR(err, "enqueing retrieve result"); 226} 227 228static void 229retrieve_result__send(struct intermon_binding *b, 230 struct intermon_msg_queue_elem *e) 231{ 232 errval_t err; 233 struct retrieve_response_st *st = (struct retrieve_response_st*)e; 234 235 err = intermon_capops_retrieve_result__tx(b, NOP_CONT, st->status, 236 st->relations, st->st); 237 238 if (err_no(err) == FLOUNDER_ERR_TX_BUSY) { 239 DEBUG_CAPOPS("%s: got FLOUNDER_ERR_TX_BUSY; requeueing msg.\n", __FUNCTION__); 240 struct intermon_state *inter_st = (struct intermon_state *)b->st; 241 // requeue send request at front and return 242 err = intermon_enqueue_send_at_front(b, &inter_st->queue, b->waitset, 243 (struct msg_queue_elem *)e); 244 GOTO_IF_ERR(err, handle_err); 245 return; 246 } 247 248handle_err: 249 PANIC_IF_ERR(err, "sending retrieve result"); 250 free(st); 251} 252 253void 254retrieve_result__rx(struct intermon_binding *b, errval_t status, 255 uint8_t relations, genvaddr_t st) 256{ 257 errval_t err; 258 struct retrieve_rpc_st *rst = (struct retrieve_rpc_st*)(lvaddr_t)st; 259 260 DEBUG_CAPOPS("%s ## ownership transferred: %s \n", __FUNCTION__, 261 err_getstring(status)); 262 263 if (err_is_fail(status)) { 264 err = status; 265 goto report_error; 266 } 267 268 err = monitor_domcap_remote_relations(rst->cap.croot, rst->cap.cptr, 269 rst->cap.level, relations, 0xFF, 270 NULL); 271 PANIC_IF_ERR(err, "setting rrels for retrieved cap"); 272 273 DEBUG_CAPOPS("%s broadcast updates to other monitors.\n", __FUNCTION__); 274 275 struct event_closure updated_cont 276 = MKCONT(retrieve_ownership_update__fin, rst); 277 err = capsend_update_owner(rst->cap, updated_cont); 278 PANIC_IF_ERR(err, "updating retrieve ownership"); 279 280 return; 281 282report_error: 283 retrieve_ownership__rx(err, rst); 284} 285 286static void 287retrieve_ownership_update__fin(void *st) 288{ 289 struct retrieve_rpc_st *rst = (struct retrieve_rpc_st*)st; 290 291 DEBUG_CAPOPS("%s updated in ownership broadcasted.\n", __FUNCTION__); 292 293 retrieve_ownership__rx(SYS_ERR_OK, rst); 294} 295