bd1965b39352a732e426821cd8d45aa94121bee7
[barrelfish] / usr / monitor / arch / x86 / inter.c
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
19 struct bind_monitor_reply_state {
20     struct intermon_msg_queue_elem elem;
21     struct intermon_binding *orig_binding;
22     errval_t err;
23 };
24
25 static void send_bind_monitor_reply(struct intermon_binding *b, errval_t err);
26
27 static 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
35 static 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  */
62 static 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 */
116 reply:
117     send_bind_monitor_reply(b, err);
118     return;
119
120 error:
121     // FIXME: cleanup!
122     goto reply;
123 }
124
125 /**
126  * \brief The monitor that proxied the request for one monitor to
127  * setup a connection with another monitor gets the reply
128  */
129 static void bind_monitor_reply(struct intermon_binding *closure,
130                                errval_t err)
131 {
132     if (err_is_fail(err)) {
133         DEBUG_ERR(err, "Got error in bind monitor reply");
134     }
135     seen_connections++;
136 }
137
138 /* ---------------------- BIND_MONITOR_PROXY CODE START --------------------- */
139 struct bind_monitor_proxy_state {
140     struct intermon_msg_queue_elem elem;
141     struct intermon_binding *orig_binding;
142     coreid_t dst_core_id;
143     intermon_caprep_t caprep;
144 };
145
146 static void bind_monitor_proxy(struct intermon_binding *b,
147                                coreid_t dst_core_id,
148                                intermon_caprep_t caprep);
149
150 static void bind_monitor_proxy_cont(struct intermon_binding *b,
151                                     struct intermon_msg_queue_elem *e)
152 {
153     struct bind_monitor_proxy_state *st = (struct bind_monitor_proxy_state*)e;
154     bind_monitor_proxy(st->orig_binding, st->dst_core_id, st->caprep);
155     free(st);
156 }
157
158 /**
159  * \brief A monitor asks this monitor to proxy
160  * its request to bind to another monitor
161  */
162 static void bind_monitor_proxy(struct intermon_binding *b,
163                                coreid_t dst_core_id,
164                                intermon_caprep_t caprep)
165 {
166     errval_t err;
167
168     /* Get source monitor's core id */
169     coreid_t src_core_id = ((struct intermon_state *)b->st)->core_id;
170
171     /* Get destination monitor */
172     struct intermon_binding *dst_binding = NULL;
173     err = intermon_binding_get(dst_core_id, &dst_binding);
174     if (err_is_fail(err)) {
175         DEBUG_ERR(err, "intermon_binding_get failed");
176     }
177
178     // Proxy the request
179     err = dst_binding->tx_vtbl.
180         bind_monitor_request(dst_binding, NOP_CONT, src_core_id,
181                              caprep);
182     if (err_is_fail(err)) {
183         if (err_no(err) == FLOUNDER_ERR_TX_BUSY) {
184             struct intermon_state *is = dst_binding->st;
185             struct bind_monitor_proxy_state *st =
186                 malloc(sizeof(struct bind_monitor_proxy_state));
187             assert(st);
188
189             st->orig_binding = b;
190             st->elem.cont = bind_monitor_proxy_cont;
191             st->dst_core_id = dst_core_id;
192             st->caprep = caprep;
193
194             err = intermon_enqueue_send(dst_binding, &is->queue,
195                                         get_default_waitset(), &st->elem.queue);
196             assert(err_is_ok(err));
197
198         } else {
199             DEBUG_ERR(err, "forwarding bind request failed");
200         }
201     }
202 }
203
204 /* ---------------------- BIND_MONITOR_PROXY CODE END ----------------------- */
205
206 /**
207  * \brief Notification of a newly booted monitor.
208  *  Setup our connection and request the sender to proxy
209  *  the bind request to the monitor
210  */
211 static void new_monitor_notify(struct intermon_binding *st,
212                                coreid_t core_id)
213 {
214     errval_t err;
215
216     /* Setup the connection */
217     struct capref frame;
218     err = frame_alloc(&frame, MON_URPC_SIZE, NULL);
219     if (err_is_fail(err)) {
220         DEBUG_ERR(err, "frame_alloc failed");
221         return; // FIXME: cleanup
222     }
223
224     void *buf;
225     err = vspace_map_one_frame(&buf, MON_URPC_SIZE, frame, NULL, NULL);
226     if (err_is_fail(err)) {
227         DEBUG_ERR(err, "vspace_map_one_frame failed");
228         assert(buf); // XXX
229     }
230
231     // init our end of the binding and channel
232     struct intermon_ump_binding *ump_binding = malloc(sizeof(struct intermon_ump_binding));
233     assert(ump_binding != NULL);
234     err = intermon_ump_init(ump_binding, get_default_waitset(),
235                             buf, MON_URPC_CHANNEL_LEN,
236                             (char *)buf + MON_URPC_CHANNEL_LEN,
237                             MON_URPC_CHANNEL_LEN);
238     assert(err_is_ok(err));
239     /* if (err_is_fail(err)) { */
240     /*     cap_destroy(frame); */
241     /*     return err_push(err, LIB_ERR_UMP_CHAN_BIND); */
242     /* } */
243
244     // Identify UMP frame for tracing
245     struct frame_identity umpid = { .base = 0, .bits = 0 };
246     err = invoke_frame_identify(frame, &umpid);
247     assert(err_is_ok(err));
248     ump_binding->ump_state.chan.recvid = (uintptr_t)umpid.base;
249     ump_binding->ump_state.chan.sendid =
250         (uintptr_t)(umpid.base + MON_URPC_CHANNEL_LEN);
251
252     err = intermon_init(&ump_binding->b, core_id);
253     assert(err_is_ok(err));
254
255     /* Identify the frame cap */
256     struct capability frame_cap;
257     err = monitor_cap_identify(frame, &frame_cap);
258     if (err_is_fail(err)) {
259         DEBUG_ERR(err, "monitor_cap_identify failed");
260         return; // FIXME: cleanup
261     }
262
263     intermon_caprep_t caprep;
264     capability_to_caprep(&frame_cap, &caprep);
265
266     /* reply to the sending monitor to proxy request */
267     err = st->tx_vtbl.bind_monitor_proxy(st, NOP_CONT, core_id, caprep);
268     if (err_is_fail(err)) {
269         DEBUG_ERR(err, "bind proxy request failed");
270     }
271 }
272
273 errval_t arch_intermon_init(struct intermon_binding *b)
274 {
275     b->rx_vtbl.bind_monitor_request = bind_monitor_request;
276     b->rx_vtbl.bind_monitor_reply = bind_monitor_reply;
277     b->rx_vtbl.bind_monitor_proxy = bind_monitor_proxy;
278     b->rx_vtbl.new_monitor_notify = new_monitor_notify;
279
280     return SYS_ERR_OK;
281 }