T119: implement syscall and monitor interface to debug_print_capabilities
[barrelfish] / lib / barrelfish / monitor_client.c
1 /**
2  * \file
3  * \brief Client for interacting with the monitor
4  */
5
6 /*
7  * Copyright (c) 2010, 2011, 2012, 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 <barrelfish/barrelfish.h>
16 #include <barrelfish/dispatcher_arch.h>
17 #include <if/monitor_defs.h>
18 #include <barrelfish/monitor_client.h>
19 #include <if/monitor_blocking_rpcclient_defs.h>
20 #include <string.h>
21 #include <inttypes.h>
22
23 static void error_handler(struct monitor_binding *b, errval_t err)
24 {
25 #if defined(__x86_64__) || defined(__i386__)
26     debug_printf("%p %p %p %p\n", __builtin_return_address(0), __builtin_return_address(1),__builtin_return_address(2),__builtin_return_address(3));
27 #endif
28     debug_err(__FILE__, __func__, __LINE__, err,
29               "asynchronous error in monitor binding");
30     abort();
31 }
32
33 /// Handler for incoming LMP messages from the monitor binding with an
34 /// indirected cap for a UMP/BMP/... channel
35 static void cap_receive_request_handler(struct monitor_binding *b,
36                                         uintptr_t conn_id, errval_t success,
37                                         struct capref cap, uint32_t capid)
38 {
39     /* XXX: this relies on the monitor_cap_handlers table being the first thing
40      * in every channel state struct */
41     struct monitor_cap_handlers *h = (void *)conn_id;
42     assert(h->cap_receive_handler != NULL);
43     h->cap_receive_handler(h->st, success, cap, capid);
44 }
45
46 /// vtable for handlers declared in this file
47 // other handlers are set directly on the binding by various init()
48 // functions after we bind to the monitor
49 static struct monitor_rx_vtbl monitor_rx_vtbl = {
50     .cap_receive_request = cap_receive_request_handler,
51 };
52
53 static void monitor_accept_recv_handler(void *arg)
54 {
55     struct monitor_lmp_binding *b = arg;
56     struct lmp_recv_msg msg = LMP_RECV_MSG_INIT;
57     struct capref cap;
58     errval_t err;
59
60     // try to retrieve a message from the channel
61     err = lmp_chan_recv(&b->chan, &msg, &cap);
62     if (err_is_fail(err)) {
63         if (err_no(err) == LIB_ERR_NO_LMP_MSG) {
64             // nothing there, re-register
65             struct event_closure recv_handler = {
66                 .handler = monitor_accept_recv_handler,
67                 .arg = b,
68             };
69             err = lmp_chan_register_recv(&b->chan, b->b.waitset, recv_handler);
70             b->b.error_handler(&b->b, err_push(err, LIB_ERR_CHAN_REGISTER_RECV));
71         } else {
72             // real error, report to user
73             b->b.error_handler(&b->b, err_push(err, LIB_ERR_LMP_CHAN_RECV));
74         }
75         return;
76     }
77
78     // if we're the monitor, we might be waiting for the other side's cap
79     assert(b->chan.connstate == LMP_MONITOR_ACCEPT);
80     assert(!capref_is_null(cap));
81     b->chan.remote_cap = cap;
82     b->chan.connstate = LMP_CONNECTED;
83
84     /* allocate a new receive slot */
85     err = lmp_chan_alloc_recv_slot(&b->chan);
86     if (err_is_fail(err)) {
87         // XXX: report the error, but continue
88         b->b.error_handler(&b->b, err_push(err, LIB_ERR_LMP_ALLOC_RECV_SLOT));
89     }
90
91     /* Run the RX handler; has a side-effect of registering for receive events */
92     monitor_lmp_rx_handler(b);
93 }
94
95 static errval_t init_lmp_binding(struct monitor_lmp_binding *mcb,
96                                  struct waitset *ws, size_t buflen_words)
97 {
98     errval_t err;
99
100     monitor_lmp_init(mcb, ws);
101
102     /* allocate a cap slot for the new endpoint cap */
103     err = slot_alloc(&mcb->chan.local_cap);
104     if (err_is_fail(err)) {
105         return err_push(err, LIB_ERR_SLOT_ALLOC);
106     }
107
108     /* allocate a local endpoint */
109     err = lmp_endpoint_create_in_slot(buflen_words, mcb->chan.local_cap,
110                                       &mcb->chan.endpoint);
111     if (err_is_fail(err)) {
112         /* TODO: free cap slot */
113         return err_push(err, LIB_ERR_ENDPOINT_CREATE);
114     }
115
116     /* allocate an initial receive slot */
117     err = lmp_chan_alloc_recv_slot(&mcb->chan);
118     if (err_is_fail(err)) {
119         return err;
120     }
121
122     /* setup error handler */
123     mcb->b.error_handler = error_handler;
124
125     /* setup initial receive handlers */
126     mcb->b.rx_vtbl = monitor_rx_vtbl;
127
128     return SYS_ERR_OK;
129 }
130
131 /**
132  * \brief Initiate a new LMP binding to the monitor
133  *
134  * Must only be called once at startup time on any dispatcher.
135  *
136  * \param mcb         Storage for binding state
137  * \param ws          Waitset for handling incoming messages
138  * \param cont        Continuation for when binding completes or fails
139  * \param st          State passed to continuation function
140  * \param buflen_words Size of incoming buffer, in number of words
141  */
142 errval_t monitor_client_lmp_bind(struct monitor_lmp_binding *mcb,
143                                  monitor_bind_continuation_fn *cont, void *st,
144                                  struct waitset *ws, size_t lmp_buflen_words)
145 {
146     errval_t err = init_lmp_binding(mcb, ws, lmp_buflen_words);
147     if (err_is_fail(err)) {
148         return err;
149     }
150
151     mcb->chan.remote_cap = cap_monitorep;
152
153     /* Send the local endpoint cap to the monitor */
154     mcb->chan.connstate = LMP_CONNECTED; /* pre-established */
155     err = lmp_chan_send0(&mcb->chan, 0, mcb->chan.local_cap);
156     if (err_is_fail(err)) {
157         /* XXX: I'm lazily assuming this can never fail with a transient error,
158          * since we only do it once at dispatcher startup. If not, we need to
159          * register and retry here */
160         assert(!lmp_err_is_transient(err));
161         return err;
162     }
163
164     /* Run the RX handler; has a side-effect of registering for receive events */
165     monitor_lmp_rx_handler(mcb);
166
167     /* Run the continuation */
168     cont(st, SYS_ERR_OK, &mcb->b);
169
170     return SYS_ERR_OK;
171 }
172
173 /**
174  * \brief Accept a new LMP binding in a client from the monitor
175  *
176  * Should only be used in the monitor.
177  *
178  * \param mcb         Storage for binding state
179  * \param ws          Waitset for handling incoming messages
180  * \param buflen_words Size of incoming buffer, in number of words
181  */
182 errval_t monitor_client_lmp_accept(struct monitor_lmp_binding *mcb,
183                                    struct waitset *ws, size_t lmp_buflen_words)
184 {
185     errval_t err = init_lmp_binding(mcb, ws, lmp_buflen_words);
186     if (err_is_fail(err)) {
187         return err;
188     }
189
190     mcb->chan.connstate = LMP_MONITOR_ACCEPT;
191     mcb->chan.remote_cap = NULL_CAP; // will be sent to us by the client
192
193     /* Register for receive notification on our special handler */
194     struct event_closure receive_handler = {
195         .handler = monitor_accept_recv_handler,
196         .arg = mcb,
197     };
198     err = lmp_chan_register_recv(&mcb->chan, ws, receive_handler);
199     if (err_is_fail(err)) {
200         return err; // TODO: cleanup?
201     }
202
203     return SYS_ERR_OK;
204 }
205
206 static void new_monitor_binding_reply_handler(struct monitor_binding *b,
207                                               errval_t err, struct capref ep,
208                                               uintptr_t st)
209 {
210     struct monitor_lmp_binding *lmpb = (void *)st;
211
212     if (err_is_fail(err)) {
213         goto out;
214     }
215
216     // success! store the cap
217     lmpb->chan.remote_cap = ep;
218
219     /* Send the local endpoint cap to the monitor */
220     lmpb->chan.connstate = LMP_CONNECTED; /* pre-established */
221     err = lmp_chan_send0(&lmpb->chan, 0, lmpb->chan.local_cap);
222     if (err_is_fail(err) && lmp_err_is_transient(err)) {
223         // XXX: TODO: stack-rip, register send event and retry!
224         USER_PANIC_ERR(err, "AB was lazy and didn't bother to retry a transient send error");
225     }
226
227 out:
228     /* Run the continuation */
229     assert(lmpb->b.bind_cont != NULL);
230     lmpb->b.bind_cont(lmpb->b.st, err, &lmpb->b);
231
232     if (err_is_fail(err)) {
233         // destroy the binding
234         monitor_lmp_destroy(lmpb);
235         free(lmpb);
236     }
237 }
238
239 static void new_monitor_binding_request_sender(void *arg)
240 {
241     struct monitor_lmp_binding *lmpb = arg; // new binding
242     struct monitor_binding *mb = get_monitor_binding();
243     errval_t err;
244
245     /* Send request to the monitor on our existing binding */
246     err = mb->tx_vtbl.new_monitor_binding_request(mb, NOP_CONT, (uintptr_t)lmpb);
247     if (err_is_ok(err)) {
248         event_mutex_unlock(&mb->mutex);
249     } else if (err_no(err) == FLOUNDER_ERR_TX_BUSY) {
250         err = mb->register_send(mb, mb->waitset,
251                                 MKCONT(new_monitor_binding_request_sender,lmpb));
252         assert(err_is_ok(err)); // shouldn't fail, as we have the mutex
253     } else { // permanent error
254         event_mutex_unlock(&mb->mutex);
255         lmpb->b.bind_cont(lmpb->b.st, err, &lmpb->b);
256         monitor_lmp_destroy(lmpb);
257         free(lmpb);
258     }
259 }
260
261 /**
262  * \brief Initiate a new (subsequent to boot) LMP binding to the monitor
263  *
264  * May be called after initialisation to create another binding to the monitor.
265  * Must not be called in the monitor.
266  *
267  * \param cont        Continuation for when binding completes or fails
268  * \param st          State passed to continuation function
269  * \param buflen_words Size of incoming buffer, in number of words
270  * \param ws          Waitset for handling incoming messages
271  */
272 errval_t monitor_client_new_binding(monitor_bind_continuation_fn *cont, void *st,
273                                     struct waitset *ws, size_t lmp_buflen_words)
274 {
275     errval_t err;
276
277     // allocate space for the binding state
278     struct monitor_lmp_binding *lmpb = malloc(sizeof(struct monitor_lmp_binding));
279     if (lmpb == NULL) {
280         return LIB_ERR_MALLOC_FAIL;
281     }
282
283     err = init_lmp_binding(lmpb, ws, lmp_buflen_words);
284     if (err_is_fail(err)) {
285         free(lmpb);
286         return err;
287     }
288
289     // copy the rx_vtbl from the main monitor binding
290     struct monitor_binding *mcb = get_monitor_binding();
291     lmpb->b.rx_vtbl = mcb->rx_vtbl;
292
293     // store continuation
294     lmpb->b.bind_cont = cont;
295     lmpb->b.st = st;
296
297     /* Run the RX handler; has a side-effect of registering for receive events */
298     monitor_lmp_rx_handler(lmpb);
299
300     /* Set reply handler (should only need to do this once!) */
301     mcb->rx_vtbl.new_monitor_binding_reply = new_monitor_binding_reply_handler;
302
303     /* Wait to use the monitor binding */
304     event_mutex_enqueue_lock(&mcb->mutex, &lmpb->b.event_qnode,
305                              MKCLOSURE(new_monitor_binding_request_sender,lmpb));
306
307     return SYS_ERR_OK;
308 }
309
310 errval_t monitor_cap_set_remote(struct capref cap, bool remote)
311 {
312     return ERR_NOTIMP;
313 #if 0
314     struct monitor_blocking_rpc_client *mc = get_monitor_blocking_rpc_client();
315     assert(mc != NULL);
316     errval_t err, reterr;
317
318     err = mc->vtbl.cap_set_remote(mc, cap, remote, &reterr);
319     if(err_is_fail(err)) {
320         return err;
321     } else {
322         return reterr;
323     }
324 #endif
325 }
326
327 struct bind_state {
328     bool done;
329     errval_t err;
330 };
331
332 static void monitor_rpc_bind_continuation(void *st_arg, errval_t err,
333                                           struct monitor_blocking_binding *b)
334 {
335     struct bind_state *st = st_arg;
336
337     if (err_is_ok(err)) {
338         struct monitor_blocking_rpc_client *r = 
339             malloc(sizeof(struct monitor_blocking_rpc_client));
340         assert(r != NULL);
341         err = monitor_blocking_rpc_client_init(r, b);
342         if (err_is_fail(err)) {
343             free(r);
344             USER_PANIC_ERR(err, "error in mem_rpc_client_init");
345         } else {
346             set_monitor_blocking_rpc_client(r);
347         }
348     }
349
350     st->err  = err;
351     st->done = true;
352 }
353
354 static void get_monitor_rpc_iref_reply(struct monitor_binding *mb, iref_t iref,
355                                        uintptr_t st_arg)
356 {
357     errval_t err;
358
359     struct bind_state *st = (void *)st_arg;
360     if (iref == 0) {
361         st->err = LIB_ERR_GET_MON_BLOCKING_IREF;
362         st->done = true;
363         return;
364     }
365
366     struct monitor_blocking_lmp_binding *mbb = malloc(sizeof(*mbb));
367     assert(mbb != NULL);
368
369     err = monitor_blocking_lmp_bind(mbb, iref, monitor_rpc_bind_continuation,
370                                     st, get_default_waitset(),
371                                     IDC_BIND_FLAG_RPC_CAP_TRANSFER,
372                                     LMP_RECV_LENGTH);
373     if (err_is_fail(err)) {
374         st->err  = err;
375         st->done = true;
376     }
377 }
378
379 /**
380  * \brief Sets up binding to monitor's blocking rpc channel
381  */
382 errval_t monitor_client_blocking_rpc_init(void)
383 {
384     errval_t err;
385
386     struct bind_state st = { .done = false };
387
388     /* fire off a request for the iref for monitor rpc channel */
389     struct monitor_binding *mb = get_monitor_binding();
390     mb->rx_vtbl.get_monitor_rpc_iref_reply = get_monitor_rpc_iref_reply;
391     err = mb->tx_vtbl.get_monitor_rpc_iref_request(mb, NOP_CONT, 
392                                                    (uintptr_t) &st);
393     if (err_is_fail(err)) {
394         return err_push(err, LIB_ERR_GET_MON_BLOCKING_IREF);
395     }
396
397     
398     /* block on the default waitset until we're bound */
399     struct waitset *ws = get_default_waitset();
400     while (!st.done) {
401         err = event_dispatch(ws);
402         if (err_is_fail(err)) {
403             return err_push(err, LIB_ERR_EVENT_DISPATCH);
404         }
405     }
406     
407     return st.err;
408 }
409
410 errval_t monitor_debug_print_cababilities(void)
411 {
412     errval_t err;
413
414     struct monitor_binding *mb = get_monitor_binding();
415     err = mb->tx_vtbl.debug_print_capabilities(mb, NOP_CONT);
416
417     return err;
418 }