1/**
2 * \file
3 * \brief UMP channel support
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
18/******* stack-ripped monitor_bind_ump_client_request *******/
19
20static void monitor_bind_ump_client_request_error(struct monitor_binding *b,
21                                                  struct capref frame,
22                                                  uintptr_t conn_id,
23                                                  uintptr_t domain_id,
24                                                  errval_t err)
25{
26    errval_t err2;
27
28    err2 = cap_destroy(frame);
29    if (err_is_fail(err2)) {
30        USER_PANIC_ERR(err, "cap_destroy failed");
31    }
32
33    if (conn_id != 0) {
34        err2 = remote_conn_free(conn_id);
35        if (err_is_fail(err2)) {
36            USER_PANIC_ERR(err2, "remote_conn_free failed");
37        }
38    }
39
40    err2 = b->tx_vtbl.bind_ump_reply_client(b, NOP_CONT, 0, domain_id, err,
41                                            NULL_CAP);
42    if (err_is_fail(err2)) {
43        USER_PANIC_ERR(err2, "error reply failed");
44    }
45}
46
47static void bind_ump_request_handler(struct intermon_binding *b,
48                                     struct intermon_msg_queue_elem *e);
49
50struct bind_ump_request_state {
51    struct intermon_msg_queue_elem elem;
52    struct intermon_bind_ump_request__tx_args args;
53    struct frame_identity frameid;
54    struct capability capability;
55    struct monitor_binding *mb;
56    struct capref frame;
57    uintptr_t domain_id;
58};
59
60static void bind_ump_request_cont(struct intermon_binding *intermon_binding,
61                                  iref_t iref, uintptr_t conn_id,
62                                  uint32_t channel_length_in,
63                                  uint32_t channel_length_out,
64                                  struct frame_identity frameid,
65                                  struct capability capability,
66                                  struct monitor_binding *mb,
67                                  struct capref frame,
68                                  uintptr_t domain_id)
69{
70    errval_t err;
71
72    intermon_caprep_t caprep;
73    capability_to_caprep(&capability, &caprep);
74
75    assert((1UL << log2ceil(frameid.bytes)) == frameid.bytes);
76    /* Send the request to the monitor on the server's core */
77    err = intermon_binding->tx_vtbl.
78        bind_ump_request(intermon_binding, NOP_CONT, iref, conn_id, channel_length_in,
79                         channel_length_out, frameid.base, log2ceil(frameid.bytes),
80                         caprep);
81    if (err_is_fail(err)) {
82        if(err_no(err) == FLOUNDER_ERR_TX_BUSY) {
83            struct bind_ump_request_state *me =
84                malloc(sizeof(struct bind_ump_request_state));
85            struct intermon_state *ist = intermon_binding->st;
86            me->args.iref = iref;
87            me->args.mon_id = conn_id;
88            me->args.channel_length_in = channel_length_in;
89            me->args.channel_length_out = channel_length_out;
90            me->frameid = frameid;
91            me->capability = capability;
92            me->mb = mb;
93            me->frame = frame;
94            me->domain_id = domain_id;
95            me->elem.cont = bind_ump_request_handler;
96
97            err = intermon_enqueue_send(intermon_binding, &ist->queue,
98                                        get_default_waitset(), &me->elem.queue);
99            assert(err_is_ok(err));
100            return;
101        }
102
103        USER_PANIC_ERR(err, "failed forwarding UMP bind request");
104        monitor_bind_ump_client_request_error(mb, frame, conn_id, domain_id, err);
105    }
106}
107
108static void bind_ump_request_handler(struct intermon_binding *b,
109                                     struct intermon_msg_queue_elem *e)
110{
111    struct bind_ump_request_state *st = (struct bind_ump_request_state *)e;
112    bind_ump_request_cont(b, st->args.iref, st->args.mon_id,
113                          st->args.channel_length_in,
114                          st->args.channel_length_out, st->frameid,
115                          st->capability, st->mb, st->frame, st->domain_id);
116    free(e);
117}
118
119static void monitor_bind_ump_client_request(struct monitor_binding *mb,
120                                            iref_t iref, uintptr_t domain_id,
121                                            struct capref frame,
122                                            size_t channel_length_in,
123                                            size_t channel_length_out,
124                                            struct capref notify)
125{
126    uint8_t core_id;
127    uintptr_t conn_id = 0;
128    errval_t err;
129    struct remote_conn_state *conn = NULL;
130
131    // Get the core id
132    err = iref_get_core_id(iref, &core_id);
133    if (err_is_fail(err)) {
134        debug_err(__FILE__, __func__, __LINE__, err, "iref_get_core_id failed");
135        monitor_bind_ump_client_request_error(mb, frame, conn_id, domain_id, err);
136        return;
137    }
138
139    if (core_id == my_core_id) {
140        USER_PANIC("Same-core UMP binding NYI");
141    }
142
143    /* Identify frame */
144    struct frame_identity frameid;
145    err = invoke_frame_identify(frame, &frameid);
146    if (err_is_fail(err)) {
147        debug_err(__FILE__, __func__, __LINE__, err, "frame_identify failed");
148        monitor_bind_ump_client_request_error(mb, frame, conn_id, domain_id, err);
149        return;
150    }
151
152    // Identify notify cap
153    struct capability capability;
154    err = monitor_cap_identify(notify, &capability);
155    if (err_is_fail(err)) {
156        USER_PANIC_ERR(err, "monitor_cap_identify failed, ignored");
157        return;
158    }
159    assert(capability.type == ObjType_Notify_IPI
160           || capability.type == ObjType_Null);
161    /* assert(capability.u.notify.coreid == my_core_id); */
162
163    /* Forward request to the corresponding monitor */
164    // Create local state
165    err = remote_conn_alloc(&conn, &conn_id, REMOTE_CONN_UMP);
166    if (err_is_fail(err)) {
167        debug_err(__FILE__, __func__, __LINE__, err, "remote_conn_alloc failed");
168        monitor_bind_ump_client_request_error(mb, frame, conn_id, domain_id, err);
169        return;
170    }
171
172    err = monitor_remote_relations(frame, RRELS_COPY_BIT, RRELS_COPY_BIT, NULL);
173    if (err_is_fail(err)) {
174        DEBUG_ERR(err, "setting remote copy bit failed");
175        monitor_bind_ump_client_request_error(mb, frame, conn_id, domain_id, err);
176        return;
177    }
178
179    // Track data
180    conn->domain_id = domain_id;
181    conn->domain_binding = mb;
182    conn->x.ump.frame = frame;
183    conn->core_id = core_id;
184
185    // Get connection to the monitor to forward request to
186    struct intermon_binding *intermon_binding;
187    err = intermon_binding_get(core_id, &intermon_binding);
188    if (err_is_fail(err)) {
189        debug_err(__FILE__, __func__, __LINE__, err, "intermon_binding_get failed");
190        monitor_bind_ump_client_request_error(mb, frame, conn_id, domain_id, err);
191        return;
192    }
193
194    bind_ump_request_cont(intermon_binding, iref, conn_id, channel_length_in,
195                          channel_length_out, frameid, capability, mb, frame,
196                          domain_id);
197}
198
199/******* stack-ripped monitor_bind_ump_reply *******/
200
201static void bind_ump_reply_handler(struct intermon_binding *b,
202                                   struct intermon_msg_queue_elem *e);
203
204struct bind_ump_reply_state {
205    struct intermon_msg_queue_elem elem;
206    struct intermon_bind_ump_reply__tx_args args;
207    struct capability capability;
208};
209
210static void bind_ump_reply_cont(struct intermon_binding *mon_binding,
211                                uintptr_t your_mon_id, uintptr_t my_mon_id,
212                                uintptr_t msgerr, struct capability capability)
213{
214    errval_t err;
215
216    intermon_caprep_t caprep;
217    capability_to_caprep(&capability, &caprep);
218
219    err = mon_binding->tx_vtbl.
220        bind_ump_reply(mon_binding, NOP_CONT, your_mon_id, my_mon_id, msgerr,
221                       caprep);
222    if (err_is_fail(err)) {
223        if(err_no(err) == FLOUNDER_ERR_TX_BUSY) {
224            struct bind_ump_reply_state *me =
225                malloc(sizeof(struct bind_ump_reply_state));
226            struct intermon_state *ist = mon_binding->st;
227            me->args.con_id = your_mon_id;
228            me->args.mon_id = my_mon_id;
229            me->args.err = msgerr;
230            me->capability = capability;
231            me->elem.cont = bind_ump_reply_handler;
232
233            err = intermon_enqueue_send(mon_binding, &ist->queue,
234                                        get_default_waitset(), &me->elem.queue);
235            assert(err_is_ok(err));
236            return;
237        }
238
239        USER_PANIC_ERR(err, "failed forwarding UMP bind reply");
240        // cleanup
241        if (err_is_ok(msgerr)) {
242            err = remote_conn_free(my_mon_id);
243            assert(err_is_ok(err));
244        }
245    }
246}
247
248static void bind_ump_reply_handler(struct intermon_binding *b,
249                                   struct intermon_msg_queue_elem *e)
250{
251    struct bind_ump_reply_state *st = (struct bind_ump_reply_state *)e;
252    bind_ump_reply_cont(b, st->args.con_id, st->args.mon_id, st->args.err,
253                        st->capability);
254    free(e);
255}
256
257static void monitor_bind_ump_reply(struct monitor_binding *dom_binding,
258                                   uintptr_t my_mon_id, uintptr_t domain_id,
259                                   errval_t msgerr, struct capref notify)
260{
261    errval_t err;
262
263    struct remote_conn_state *conn = remote_conn_lookup(my_mon_id);
264    if (conn == NULL) {
265        USER_PANIC("invalid mon_id in UMP bind reply");
266        return;
267    }
268
269    uintptr_t your_mon_id = conn->mon_id;
270    struct intermon_binding *mon_binding = conn->mon_binding;
271
272    if (err_is_ok(msgerr)) {
273        /* Connection accepted */
274        conn->domain_id = domain_id;
275        conn->domain_binding = dom_binding;
276    } else {
277//error:
278        /* Free the cap */
279        err = cap_destroy(conn->x.ump.frame);
280        assert(err_is_ok(err));
281
282        err = remote_conn_free(my_mon_id);
283        assert(err_is_ok(err));
284    }
285
286    // Identify notify cap
287    struct capability capability;
288    err = monitor_cap_identify(notify, &capability);
289    if (err_is_fail(err)) {
290        USER_PANIC_ERR(err, "monitor_cap_identify failed, ignored");
291        return;
292    }
293    assert(capability.type == ObjType_Notify_IPI
294           || capability.type == ObjType_Null);
295    /* assert(capability.u.notify.coreid == my_core_id); */
296
297    bind_ump_reply_cont(mon_binding, your_mon_id, my_mon_id, msgerr, capability);
298}
299
300/******* stack-ripped intermon_bind_ump_request *******/
301
302static void bind_ump_service_request_handler(struct monitor_binding *b,
303                                             struct monitor_msg_queue_elem *e);
304
305struct bind_ump_service_request_state {
306    struct monitor_msg_queue_elem elem;
307    struct monitor_bind_ump_service_request__tx_args args;
308    struct intermon_binding *binding;
309    uintptr_t your_mon_id;
310};
311
312static void bind_ump_service_request_cont(struct monitor_binding *domain_binding,
313                                          uintptr_t service_id,
314                                          con_id_t my_mon_id,
315                                          struct capref frame,
316                                          uint32_t channel_length_in,
317                                          uint32_t channel_length_out,
318                                          struct capref notify_cap,
319                                          struct intermon_binding *binding,
320                                          con_id_t your_mon_id)
321{
322    errval_t err, err2;
323
324    /* Proxy the request */
325    err = domain_binding->tx_vtbl.
326        bind_ump_service_request(domain_binding, NOP_CONT, service_id,
327                                 my_mon_id, frame,
328                                 channel_length_in, channel_length_out,
329                                 notify_cap);
330    if (err_is_fail(err)) {
331        if(err_no(err) == FLOUNDER_ERR_TX_BUSY) {
332            struct bind_ump_service_request_state *me =
333                malloc(sizeof(struct bind_ump_service_request_state));
334            struct monitor_state *ist = domain_binding->st;
335            me->args.service_id = service_id;
336            me->args.mon_id = my_mon_id;
337            me->args.frame = frame;
338            me->args.channel_length_in = channel_length_in;
339            me->args.channel_length_out = channel_length_out;
340            me->args.notify = notify_cap;
341            me->binding = binding;
342            me->your_mon_id = your_mon_id;
343            me->elem.cont = bind_ump_service_request_handler;
344
345            err = monitor_enqueue_send(domain_binding, &ist->queue,
346                                       get_default_waitset(), &me->elem.queue);
347            assert(err_is_ok(err));
348            return;
349        }
350
351        err2 = cap_destroy(frame);
352        if (err_is_fail(err2)) {
353            USER_PANIC_ERR(err2, "Cap destroy failed");
354        }
355        err2 = remote_conn_free(my_mon_id);
356        if (err_is_fail(err2)) {
357            USER_PANIC_ERR(err2, "remote_conn_free failed");
358        }
359        intermon_caprep_t nullcap = {0,0,0,0};
360        err2 = binding->tx_vtbl.bind_ump_reply(binding, NOP_CONT, your_mon_id, 0, err,
361                                               nullcap);
362        if (err_is_fail(err2)) {
363            USER_PANIC_ERR(err2, "Sending bind_ump_reply1 failed");
364        }
365    }
366}
367
368static void bind_ump_service_request_handler(struct monitor_binding *b,
369                                             struct monitor_msg_queue_elem *e)
370{
371    struct bind_ump_service_request_state *st = (struct bind_ump_service_request_state *)e;
372    bind_ump_service_request_cont(b, st->args.service_id, st->args.mon_id,
373                                  st->args.frame, st->args.channel_length_in,
374                                  st->args.channel_length_out, st->args.notify,
375                                  st->binding, st->your_mon_id);
376    free(e);
377}
378
379static void intermon_bind_ump_request(struct intermon_binding *ib,
380                                      iref_t iref, con_id_t your_mon_id,
381                                      uint32_t channel_length_in,
382                                      uint32_t channel_length_out,
383                                      genpaddr_t framebase, uint8_t framebits,
384                                      intermon_caprep_t caprep)
385{
386    errval_t err;
387
388    /* Get client's core_id */
389    struct intermon_state *ist = ib->st;
390    assert(ist != NULL);
391    coreid_t core_id = ist->core_id;
392
393    /* Construct the frame capability */
394    struct capability frame_cap = {
395        .type = ObjType_Frame,
396        .rights = CAPRIGHTS_READ_WRITE, // XXX
397        .u.frame = {
398            .base = framebase,
399            .bytes = 1UL << framebits
400        }
401    };
402
403    // Construct the notify cap
404    struct capref notify_cap = NULL_CAP;
405    struct capability capability;
406    caprep_to_capability(&caprep, &capability);
407    if(capability.type != ObjType_Null) {
408        err = slot_alloc(&notify_cap);
409        if (err_is_fail(err)) {
410            USER_PANIC_ERR(err, "Failed to allocate slot from channel_alloc");
411        }
412        err = monitor_cap_create(notify_cap, &capability, core_id);
413        if (err_is_fail(err)) {
414            USER_PANIC_ERR(err, "monitor_cap_create failed");
415        }
416    }
417
418    // XXX: Put frame cap on a separate allocator as it is not deleted anymore
419    struct capref frame;
420    err = slot_alloc(&frame);
421    if (err_is_fail(err)) {
422        USER_PANIC_ERR(err, "Failed to allocate slot from channel_alloc");
423    }
424    err = monitor_cap_create(frame, &frame_cap, core_id);
425    if (err_is_fail(err)) {
426        USER_PANIC_ERR(err, "monitor_cap_create failed");
427    }
428
429    /* Get the server's connection */
430    struct monitor_binding *domain_binding = NULL;
431    err = iref_get_binding(iref, &domain_binding);
432    assert(err_is_ok(err));
433
434    /* Get the service id */
435    uintptr_t service_id = 0;
436    err = iref_get_service_id(iref, &service_id);
437    assert(err_is_ok(err));
438
439    /* Create a new connection state */
440    uintptr_t my_mon_id;
441    struct remote_conn_state *con;
442    err = remote_conn_alloc(&con, &my_mon_id, REMOTE_CONN_UMP);
443    assert(err_is_ok(err));
444
445    // Set the monitor portion of it
446    con->mon_id = your_mon_id;
447    con->mon_binding = ib;
448    con->x.ump.frame = frame;
449    con->core_id = core_id;
450
451    bind_ump_service_request_cont(domain_binding, service_id, my_mon_id,
452                                  frame, channel_length_in, channel_length_out,
453                                  notify_cap, ib, your_mon_id);
454}
455
456/******* stack-ripped intermon_bind_ump_reply *******/
457
458static void bind_ump_reply_client_handler(struct monitor_binding *b,
459                                          struct monitor_msg_queue_elem *e);
460
461struct bind_ump_reply_client_state {
462    struct monitor_msg_queue_elem elem;
463    struct monitor_bind_ump_reply_client__tx_args args;
464};
465
466static void bind_ump_reply_client_cont(struct monitor_binding *domain_binding,
467                                       uintptr_t my_mon_id,
468                                       uintptr_t domain_id,
469                                       errval_t msgerr,
470                                       struct capref notify_cap)
471{
472    errval_t err;
473
474    err = domain_binding->tx_vtbl.
475        bind_ump_reply_client(domain_binding, NOP_CONT, my_mon_id, domain_id,
476                              msgerr, notify_cap);
477    if (err_is_fail(err)) {
478        if(err_no(err) == FLOUNDER_ERR_TX_BUSY) {
479            struct bind_ump_reply_client_state *me =
480                malloc(sizeof(struct bind_ump_reply_client_state));
481            struct monitor_state *ist = domain_binding->st;
482            me->args.mon_id = my_mon_id;
483            me->args.conn_id = domain_id;
484            me->args.err = msgerr;
485            me->args.notify = notify_cap;
486            me->elem.cont = bind_ump_reply_client_handler;
487
488            err = monitor_enqueue_send(domain_binding, &ist->queue,
489                                       get_default_waitset(), &me->elem.queue);
490            assert(err_is_ok(err));
491            return;
492        }
493
494        USER_PANIC_ERR(err, "UMP bind reply failed");
495        // cleanup
496        err = remote_conn_free(my_mon_id);
497        if (err_is_fail(err)) {
498            USER_PANIC_ERR(err, "remote_conn_free failed");
499        }
500    }
501}
502
503static void bind_ump_reply_client_handler(struct monitor_binding *b,
504                                             struct monitor_msg_queue_elem *e)
505{
506    struct bind_ump_reply_client_state *st = (struct bind_ump_reply_client_state *)e;
507    bind_ump_reply_client_cont(b, st->args.mon_id, st->args.conn_id,
508                               st->args.err, st->args.notify);
509    free(e);
510}
511
512static void intermon_bind_ump_reply(struct intermon_binding *ib,
513                                    uint64_t my_mon_id, uint64_t your_mon_id,
514                                    errval_t msgerr,
515                                    intermon_caprep_t caprep)
516{
517    errval_t err;
518    struct remote_conn_state *con = remote_conn_lookup(my_mon_id);
519    if (con == NULL) {
520        USER_PANIC_ERR(0, "unknown mon_id in UMP bind reply");
521        return;
522    }
523
524    uintptr_t domain_id = con->domain_id;
525    struct monitor_binding *domain_binding = con->domain_binding;
526    struct capref notify_cap = NULL_CAP;
527
528    if (err_is_ok(msgerr)) { /* bind succeeded */
529        con->mon_id = your_mon_id;
530        con->mon_binding = ib;
531
532#if 0
533        /* map in UMP channel state */
534        void *buf;
535        err = vspace_map_one_frame_attr(&buf,
536              2 * (UMP_CHANNEL_SIZE + con->localchan.size * sizeof(uintptr_t)),
537                                        con->frame, VREGION_FLAGS_READ,
538                                        NULL, NULL);
539        if (err_is_fail(err)) {
540            USER_PANIC_ERR(err, "vspace_map_one_frame failed");
541            // XXX: should not be an assert, but we don't have any way to do
542            // connection teardown here!
543            assert(buf != NULL);
544        }
545        con->sharedchan = buf;
546        con->localchan.buf = buf + 2 * UMP_CHANNEL_SIZE;
547
548        // XXX: Put frame cap on a separate allocator as it is not deleted anymore
549        struct capref frame_copy;
550        err = slot_alloc(&frame_copy);
551        if (err_is_fail(err)) {
552            USER_PANIC_ERR(err, "Failed to allocator slot from channel_alloc");
553        }
554        err = cap_copy(frame_copy, con->frame);
555        if (err_is_fail(err)) {
556            USER_PANIC_ERR(err, "Failed create copy of frame cap");
557        }
558        err = cap_destroy(con->frame);
559        if (err_is_fail(err)) {
560            USER_PANIC_ERR(err, "cap_destroy_default failed");
561        }
562        con->frame = frame_copy;
563#endif
564
565        struct capability capability;
566        caprep_to_capability(&caprep, &capability);
567
568        if(capability.type != ObjType_Null) {
569            // Get core id of sender
570            coreid_t core_id = ((struct intermon_state *)ib->st)->core_id;
571
572            // Construct the notify cap
573            err = slot_alloc(&notify_cap);
574            if (err_is_fail(err)) {
575                USER_PANIC_ERR(err, "Failed to allocate slot from channel_alloc");
576            }
577
578            err = monitor_cap_create(notify_cap, &capability, core_id);
579            if (err_is_fail(err)) {
580                USER_PANIC_ERR(err, "monitor_cap_create failed");
581            }
582        }
583    } else { /* bind refused */
584        err = cap_destroy(con->x.ump.frame);
585        if (err_is_fail(err)) {
586            USER_PANIC_ERR(err, "cap_destroy_default failed");
587        }
588        err = remote_conn_free(my_mon_id);
589        assert(err_is_ok(err));
590    }
591
592    bind_ump_reply_client_cont(domain_binding, my_mon_id, domain_id, msgerr,
593                               notify_cap);
594}
595
596errval_t ump_intermon_init(struct intermon_binding *ib)
597{
598    ib->rx_vtbl.bind_ump_request = intermon_bind_ump_request;
599    ib->rx_vtbl.bind_ump_reply = intermon_bind_ump_reply;
600    return SYS_ERR_OK;
601}
602
603errval_t ump_monitor_init(struct monitor_binding *mb)
604{
605    mb->rx_vtbl.bind_ump_client_request = monitor_bind_ump_client_request;
606    mb->rx_vtbl.bind_ump_reply_monitor = monitor_bind_ump_reply;
607    return SYS_ERR_OK;
608}
609