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 * A monitor newly booted monitor receives 60 * request to setup a connection with another monitor 61 * from a third monitor. 62 * 63 * \param core_id Originating core id 64 * \param caprep Endpoint capability 65 */ 66static void bind_monitor_request(struct intermon_binding *b, 67 coreid_t core_id, 68 intermon_caprep_t caprep) 69{ 70 //printf("%s:%s:%d\n", __FILE__, __FUNCTION__, __LINE__); 71 errval_t err; 72 trace_event(TRACE_SUBSYS_MONITOR, TRACE_EVENT_MONITOR_BIND_MONITOR_REQUEST, core_id); 73 74 /* Create the cap */ 75 struct capability cap_raw; 76 caprep_to_capability(&caprep, &cap_raw); 77 if (cap_raw.type != ObjType_Frame) { 78 err = MON_ERR_WRONG_CAP_TYPE; 79 goto error; 80 } 81 82 struct capref frame; 83 err = slot_alloc(&frame); 84 if (err_is_fail(err)) { 85 goto error; 86 } 87 88 err = monitor_cap_create(frame, &cap_raw, core_id); 89 if (err_is_fail(err)) { 90 goto error; 91 } 92 93 /* Setup the connection */ 94 void *buf; 95 err = vspace_map_one_frame(&buf, MON_URPC_SIZE, frame, NULL, NULL); 96 if (err_is_fail(err)) { 97 err = err_push(err, LIB_ERR_VSPACE_MAP); 98 goto error; 99 } 100 101 // setup our side of the binding 102 struct intermon_ump_binding *umpb; 103 umpb = malloc(sizeof(struct intermon_ump_binding)); 104 assert(umpb != NULL); 105 106 err = intermon_ump_init(umpb, get_default_waitset(), 107 (char *)buf + MON_URPC_CHANNEL_LEN, 108 MON_URPC_CHANNEL_LEN, 109 buf, MON_URPC_CHANNEL_LEN); 110 assert(err_is_ok(err)); 111 112 // Identify UMP frame for tracing 113 umpb->ump_state.chan.sendid = (uintptr_t)cap_raw.u.frame.base; 114 umpb->ump_state.chan.recvid = 115 (uintptr_t)(cap_raw.u.frame.base + MON_URPC_CHANNEL_LEN); 116 117 // connect it to our request handlers 118 err = intermon_init(&umpb->b, core_id); 119 assert(err_is_ok(err)); 120 121 /* Send reply */ 122reply: 123 send_bind_monitor_reply(b, err); 124 return; 125 126error: 127 // FIXME: cleanup! 128 goto reply; 129} 130 131/** 132 * The monitor that proxied the request for one monitor to 133 * setup a connection with another monitor gets the reply. 134 * 135 * In the current set-up this happens to be the BSP monitor. 136 * 137 * \param err Error status of bind request. 138 */ 139static void bind_monitor_reply(struct intermon_binding *closure, 140 errval_t err) 141{ 142 if (err_is_fail(err)) { 143 DEBUG_ERR(err, "Got error in bind monitor reply"); 144 } 145 trace_event(TRACE_SUBSYS_MONITOR, TRACE_EVENT_MONITOR_BIND_MONITOR_REPLY, 0); 146 seen_connections++; 147} 148 149/* ---------------------- BIND_MONITOR_PROXY CODE START --------------------- */ 150struct bind_monitor_proxy_state { 151 struct intermon_msg_queue_elem elem; 152 struct intermon_binding *orig_binding; 153 coreid_t dst_core_id; 154 intermon_caprep_t caprep; 155}; 156 157static void bind_monitor_proxy(struct intermon_binding *b, 158 coreid_t dst_core_id, 159 intermon_caprep_t caprep); 160 161static void bind_monitor_proxy_cont(struct intermon_binding *b, 162 struct intermon_msg_queue_elem *e) 163{ 164 struct bind_monitor_proxy_state *st = (struct bind_monitor_proxy_state*)e; 165 bind_monitor_proxy(st->orig_binding, st->dst_core_id, st->caprep); 166 free(st); 167} 168 169/** 170 * \brief A monitor asks this monitor to proxy 171 * its request to bind to another monitor 172 */ 173static void bind_monitor_proxy(struct intermon_binding *b, 174 coreid_t dst_core_id, 175 intermon_caprep_t caprep) 176{ 177 //printf("%s:%s:%d\n", __FILE__, __FUNCTION__, __LINE__); 178 errval_t err; 179 180 /* Get source monitor's core id */ 181 coreid_t src_core_id = ((struct intermon_state *)b->st)->core_id; 182 183 /* Get destination monitor */ 184 struct intermon_binding *dst_binding = NULL; 185 err = intermon_binding_get(dst_core_id, &dst_binding); 186 if (err_is_fail(err)) { 187 DEBUG_ERR(err, "intermon_binding_get failed"); 188 printf("%s:%s:%d: my_core_id=%"PRIuCOREID" dst_core_id=%"PRIuCOREID"\n", 189 __FILE__, __FUNCTION__, __LINE__, my_core_id, dst_core_id); 190 } 191 192 // Proxy the request 193 err = dst_binding->tx_vtbl. 194 bind_monitor_request(dst_binding, NOP_CONT, src_core_id, 195 caprep); 196 if (err_is_fail(err)) { 197 if (err_no(err) == FLOUNDER_ERR_TX_BUSY) { 198 struct intermon_state *is = dst_binding->st; 199 struct bind_monitor_proxy_state *st = 200 malloc(sizeof(struct bind_monitor_proxy_state)); 201 assert(st); 202 203 st->orig_binding = b; 204 st->elem.cont = bind_monitor_proxy_cont; 205 st->dst_core_id = dst_core_id; 206 st->caprep = caprep; 207 208 err = intermon_enqueue_send(dst_binding, &is->queue, 209 get_default_waitset(), &st->elem.queue); 210 assert(err_is_ok(err)); 211 212 } else { 213 DEBUG_ERR(err, "forwarding bind request failed"); 214 } 215 } 216} 217 218/* ---------------------- BIND_MONITOR_PROXY CODE END ----------------------- */ 219 220/** 221 * \brief Notification of a newly booted monitor. 222 * Setup our connection and request the sender to proxy 223 * the bind request to the monitor 224 */ 225static void new_monitor_notify(struct intermon_binding *st, 226 coreid_t core_id) 227{ 228 //printf("%s:%s:%d for core %"PRIuCOREID"\n", 229 // __FILE__, __FUNCTION__, __LINE__, core_id); 230 errval_t err; 231 232 /* Setup the connection */ 233 struct capref frame; 234 err = frame_alloc(&frame, MON_URPC_SIZE, NULL); 235 if (err_is_fail(err)) { 236 DEBUG_ERR(err, "frame_alloc failed"); 237 return; // FIXME: cleanup 238 } 239 240 void *buf; 241 err = vspace_map_one_frame(&buf, MON_URPC_SIZE, frame, NULL, NULL); 242 if (err_is_fail(err)) { 243 DEBUG_ERR(err, "vspace_map_one_frame failed"); 244 assert(buf); // XXX 245 } 246 247 // init our end of the binding and channel 248 struct intermon_ump_binding *ump_binding = malloc(sizeof(struct intermon_ump_binding)); 249 assert(ump_binding != NULL); 250 err = intermon_ump_init(ump_binding, get_default_waitset(), 251 buf, MON_URPC_CHANNEL_LEN, 252 (char *)buf + MON_URPC_CHANNEL_LEN, 253 MON_URPC_CHANNEL_LEN); 254 if (err_is_fail(err)) { 255 cap_destroy(frame); 256 USER_PANIC_ERR(err, "intermonitor channel initialization"); 257 // TODO(gz): Recover from this 258 } 259 260 // Identify UMP frame for tracing 261 struct frame_identity umpid = { .base = 0, .bytes = 0 }; 262 err = invoke_frame_identify(frame, &umpid); 263 assert(err_is_ok(err)); 264 ump_binding->ump_state.chan.recvid = (uintptr_t)umpid.base; 265 ump_binding->ump_state.chan.sendid = 266 (uintptr_t)(umpid.base + MON_URPC_CHANNEL_LEN); 267 268 err = intermon_init(&ump_binding->b, core_id); 269 assert(err_is_ok(err)); 270 271 /* Identify the frame cap */ 272 struct capability frame_cap; 273 err = monitor_cap_identify(frame, &frame_cap); 274 if (err_is_fail(err)) { 275 DEBUG_ERR(err, "monitor_cap_identify failed"); 276 return; // FIXME: cleanup 277 } 278 279 intermon_caprep_t caprep; 280 capability_to_caprep(&frame_cap, &caprep); 281 282 /* reply to the sending monitor to proxy request */ 283 err = st->tx_vtbl.bind_monitor_proxy(st, NOP_CONT, core_id, caprep); 284 if (err_is_fail(err)) { 285 DEBUG_ERR(err, "bind proxy request failed"); 286 } 287} 288 289errval_t arch_intermon_init(struct intermon_binding *b) 290{ 291 b->rx_vtbl.bind_monitor_request = bind_monitor_request; 292 b->rx_vtbl.bind_monitor_reply = bind_monitor_reply; 293 b->rx_vtbl.bind_monitor_proxy = bind_monitor_proxy; 294 b->rx_vtbl.new_monitor_notify = new_monitor_notify; 295 296 return SYS_ERR_OK; 297} 298