1/** 2 * \file 3 * \brief Arch-specific inter-monitor communication 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#include <trace/trace.h> 18 19struct bind_monitor_reply_state { 20 struct intermon_msg_queue_elem elem; 21 struct intermon_binding *orig_binding; 22 errval_t err; 23}; 24 25static void send_bind_monitor_reply(struct intermon_binding *b, errval_t err); 26 27static void send_bind_monitor_reply_cont(struct intermon_binding *b, 28 struct intermon_msg_queue_elem *e) 29{ 30 struct bind_monitor_reply_state *st = (struct bind_monitor_reply_state *)e; 31 send_bind_monitor_reply(st->orig_binding, st->err); 32 free(st); 33} 34 35static void send_bind_monitor_reply(struct intermon_binding *b, errval_t err) 36{ 37 errval_t err2 = b->tx_vtbl.bind_monitor_reply(b, NOP_CONT, err); 38 if (err_is_fail(err2)) { 39 if (err_no(err2) == FLOUNDER_ERR_TX_BUSY) { 40 struct intermon_state *is = b->st; 41 struct bind_monitor_reply_state *st = malloc(sizeof(*st)); 42 assert(st != NULL); 43 44 st->orig_binding = b; 45 st->elem.cont = send_bind_monitor_reply_cont; 46 st->err = err; 47 48 err2 = intermon_enqueue_send(b, &is->queue, 49 get_default_waitset(), &st->elem.queue); 50 assert(err_is_ok(err2)); 51 52 } else { 53 DEBUG_ERR(err2, "reply failed"); 54 } 55 } 56} 57 58/** 59 * \brief A monitor receives request to setup a connection 60 * with another newly booted monitor from a third monitor 61 */ 62static void bind_monitor_request(struct intermon_binding *b, 63 coreid_t core_id, 64 intermon_caprep_t caprep) 65{ 66 errval_t err; 67 68 /* Create the cap */ 69 struct capability cap_raw; 70 caprep_to_capability(&caprep, &cap_raw); 71 if (cap_raw.type != ObjType_Frame) { 72 err = MON_ERR_WRONG_CAP_TYPE; 73 goto error; 74 } 75 76 struct capref frame; 77 err = slot_alloc(&frame); 78 if (err_is_fail(err)) { 79 goto error; 80 } 81 82 err = monitor_cap_create(frame, &cap_raw, core_id); 83 if (err_is_fail(err)) { 84 goto error; 85 } 86 87 /* Setup the connection */ 88 void *buf; 89 err = vspace_map_one_frame(&buf, MON_URPC_SIZE, frame, NULL, NULL); 90 if (err_is_fail(err)) { 91 err = err_push(err, LIB_ERR_VSPACE_MAP); 92 goto error; 93 } 94 95 // setup our side of the binding 96 struct intermon_ump_binding *umpb; 97 umpb = malloc(sizeof(struct intermon_ump_binding)); 98 assert(umpb != NULL); 99 100 err = intermon_ump_init(umpb, get_default_waitset(), 101 (char *)buf + MON_URPC_CHANNEL_LEN, 102 MON_URPC_CHANNEL_LEN, 103 buf, MON_URPC_CHANNEL_LEN); 104 assert(err_is_ok(err)); 105 106 // Identify UMP frame for tracing 107 umpb->ump_state.chan.sendid = (uintptr_t)cap_raw.u.frame.base; 108 umpb->ump_state.chan.recvid = 109 (uintptr_t)(cap_raw.u.frame.base + MON_URPC_CHANNEL_LEN); 110 111 // connect it to our request handlers 112 err = intermon_init(&umpb->b, core_id); 113 assert(err_is_ok(err)); 114 115 /* Send reply */ 116reply: 117 send_bind_monitor_reply(b, err); 118 return; 119 120error: 121 // FIXME: cleanup! 122 goto reply; 123} 124/** 125 * \brief The monitor that proxied the request for one monitor to 126 * setup a connection with another monitor gets the reply 127 */ 128static void bind_monitor_reply(struct intermon_binding *closure, 129 errval_t err) 130{ 131 if (err_is_fail(err)) { 132 DEBUG_ERR(err, "Got error in bind monitor reply"); 133 } 134 seen_connections++; 135} 136/** 137 * \brief A monitor asks this monitor to proxy 138 * its request to bind to another monitor 139 */ 140 141/* ---------------------- BIND_MONITOR_PROXY CODE START --------------------- */ 142struct bind_monitor_proxy_state { 143 struct intermon_msg_queue_elem elem; 144 struct intermon_binding *orig_binding; 145 coreid_t dst_core_id; 146 intermon_caprep_t caprep; 147}; 148 149static void bind_monitor_proxy(struct intermon_binding *b, 150 coreid_t dst_core_id, 151 intermon_caprep_t caprep); 152 153static void bind_monitor_proxy_cont(struct intermon_binding *b, 154 struct intermon_msg_queue_elem *e) 155{ 156 struct bind_monitor_proxy_state *st = (struct bind_monitor_proxy_state*)e; 157 bind_monitor_proxy(st->orig_binding, st->dst_core_id, st->caprep); 158 free(st); 159} 160/** 161 * \brief A monitor asks this monitor to proxy 162 * its request to bind to another monitor 163 */ 164static void bind_monitor_proxy(struct intermon_binding *b, 165 coreid_t dst_core_id, 166 intermon_caprep_t caprep) 167{ 168 errval_t err; 169 170 /* Get source monitor's core id */ 171 coreid_t src_core_id = ((struct intermon_state *)b->st)->core_id; 172 173 /* Get destination monitor */ 174 struct intermon_binding *dst_binding = NULL; 175 err = intermon_binding_get(dst_core_id, &dst_binding); 176 if (err_is_fail(err)) { 177 DEBUG_ERR(err, "intermon_binding_get failed"); 178 } 179 180 // Proxy the request 181 err = dst_binding->tx_vtbl. 182 bind_monitor_request(dst_binding, NOP_CONT, src_core_id, 183 caprep); 184 if (err_is_fail(err)) { 185 if (err_no(err) == FLOUNDER_ERR_TX_BUSY) { 186 struct intermon_state *is = dst_binding->st; 187 struct bind_monitor_proxy_state *st = 188 malloc(sizeof(struct bind_monitor_proxy_state)); 189 assert(st); 190 191 st->orig_binding = b; 192 st->elem.cont = bind_monitor_proxy_cont; 193 st->dst_core_id = dst_core_id; 194 st->caprep = caprep; 195 196 err = intermon_enqueue_send(dst_binding, &is->queue, 197 get_default_waitset(), &st->elem.queue); 198 assert(err_is_ok(err)); 199 200 } else { 201 DEBUG_ERR(err, "forwarding bind request failed"); 202 } 203 } 204} 205 206/* ---------------------- BIND_MONITOR_PROXY CODE END ----------------------- */ 207 208/** 209 * \brief Notification of a newly booted monitor. 210 * Setup our connection and request the sender to proxy 211 * the bind request to the monitor 212 */ 213static void new_monitor_notify(struct intermon_binding *st, 214 coreid_t core_id) 215{ 216 errval_t err; 217 218 /* Setup the connection */ 219 struct capref frame; 220 err = frame_alloc(&frame, MON_URPC_SIZE, NULL); 221 if (err_is_fail(err)) { 222 DEBUG_ERR(err, "frame_alloc failed"); 223 return; // FIXME: cleanup 224 } 225 226 void *buf; 227 err = vspace_map_one_frame(&buf, MON_URPC_SIZE, frame, NULL, NULL); 228 if (err_is_fail(err)) { 229 DEBUG_ERR(err, "vspace_map_one_frame failed"); 230 assert(buf); // XXX 231 } 232 233 // init our end of the binding and channel 234 struct intermon_ump_binding *ump_binding = malloc(sizeof(struct intermon_ump_binding)); 235 assert(ump_binding != NULL); 236 err = intermon_ump_init(ump_binding, get_default_waitset(), 237 buf, MON_URPC_CHANNEL_LEN, 238 (char *)buf + MON_URPC_CHANNEL_LEN, 239 MON_URPC_CHANNEL_LEN); 240 assert(err_is_ok(err)); 241 /* if (err_is_fail(err)) { */ 242 /* cap_destroy(frame); */ 243 /* return err_push(err, LIB_ERR_UMP_CHAN_BIND); */ 244 /* } */ 245 246 // Identify UMP frame for tracing 247 struct frame_identity umpid = { .base = 0, .bytes = 0 }; 248 err = invoke_frame_identify(frame, &umpid); 249 assert(err_is_ok(err)); 250 ump_binding->ump_state.chan.recvid = (uintptr_t)umpid.base; 251 ump_binding->ump_state.chan.sendid = 252 (uintptr_t)(umpid.base + MON_URPC_CHANNEL_LEN); 253 254 err = intermon_init(&ump_binding->b, core_id); 255 assert(err_is_ok(err)); 256 257 /* Identify the frame cap */ 258 struct capability frame_cap; 259 err = monitor_cap_identify(frame, &frame_cap); 260 if (err_is_fail(err)) { 261 DEBUG_ERR(err, "monitor_cap_identify failed"); 262 return; // FIXME: cleanup 263 } 264 265 intermon_caprep_t caprep; 266 capability_to_caprep(&frame_cap, &caprep); 267 268 /* reply to the sending monitor to proxy request */ 269 err = st->tx_vtbl.bind_monitor_proxy(st, NOP_CONT, core_id, caprep); 270 if (err_is_fail(err)) { 271 DEBUG_ERR(err, "bind proxy request failed"); 272 } 273} 274errval_t arch_intermon_init(struct intermon_binding *b) 275{ 276 b->rx_vtbl.bind_monitor_request = bind_monitor_request; 277 b->rx_vtbl.bind_monitor_reply = bind_monitor_reply; 278 b->rx_vtbl.bind_monitor_proxy = bind_monitor_proxy; 279 b->rx_vtbl.new_monitor_notify = new_monitor_notify; 280 281 return SYS_ERR_OK; 282} 283