1/**
2 * \file
3 * \brief Support code for Flounder-generated stubs
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 <stdlib.h>
16#include <stdio.h>
17#include <string.h>
18#include <barrelfish/barrelfish.h>
19#include <barrelfish/monitor_client.h>
20#include <barrelfish/waitset_chan.h>
21#include <flounder/flounder_support.h>
22#include <flounder/flounder_support_caps.h>
23#include <if/monitor_defs.h>
24
25/// Special continuation for blocking
26void blocking_cont(void *v)
27{
28    debug_printf("%s: should never be called!\n", __func__);
29    assert(0);
30}
31
32/*
33 * NB: many of these functions are trivial, but exist so that we don't need to
34 * expose private libbarrelfish headers or generated flounder headers to every
35 * generated stub
36 */
37
38static void dummy_event_handler(void *arg)
39{
40}
41
42struct event_closure dummy_event_closure = {
43    .handler = dummy_event_handler,
44    .arg = NULL,
45};
46
47void flounder_support_trigger_chan(struct waitset_chanstate *wc)
48{
49    if (waitset_chan_is_registered(wc)) {
50        errval_t err = waitset_chan_trigger(wc);
51        assert(err_is_ok(err)); // shouldn't fail if registered
52    }
53}
54
55void flounder_support_deregister_chan(struct waitset_chanstate *wc)
56{
57    if (waitset_chan_is_registered(wc)) {
58        errval_t err = waitset_chan_deregister(wc);
59        assert(err_is_ok(err)); // shouldn't fail if registered
60    }
61}
62
63errval_t flounder_support_register(struct waitset *ws,
64                                   struct waitset_chanstate *wc,
65                                   struct event_closure ec,
66                                   bool trigger_now)
67{
68    if (trigger_now) {
69        return waitset_chan_trigger_closure(ws, wc, ec);
70    } else {
71        if (ec.handler == blocking_cont) {
72            assert(!wc->wait_for);          // this event should be received
73            wc->wait_for = thread_self();   // only by our thread
74        }
75        return waitset_chan_register(ws, wc, ec);
76    }
77}
78
79void flounder_support_waitset_chanstate_init(struct waitset_chanstate *wc)
80{
81    waitset_chanstate_init(wc, CHANTYPE_FLOUNDER);
82}
83
84void flounder_support_waitset_chanstate_init_persistent(struct waitset_chanstate *wc)
85{
86    waitset_chanstate_init(wc, CHANTYPE_FLOUNDER);
87    wc->persistent = true;
88}
89
90void flounder_support_waitset_chanstate_destroy(struct waitset_chanstate *wc)
91{
92    waitset_chanstate_destroy(wc);
93}
94
95struct waitset * flounder_support_get_current_monitor_waitset(struct monitor_binding *mb)
96{
97    return mb->waitset;
98}
99
100errval_t flounder_support_change_monitor_waitset(struct monitor_binding *mb,
101                                                 struct waitset *ws)
102{
103    return mb->change_waitset(mb, ws);
104}
105
106void flounder_support_monitor_mutex_enqueue(struct monitor_binding *mb,
107                                            struct event_queue_node *qn,
108                                            struct event_closure cl)
109{
110    event_mutex_enqueue_lock(&mb->mutex, qn, cl);
111}
112
113void flounder_support_monitor_mutex_unlock(struct monitor_binding *mb)
114{
115    event_mutex_unlock(&mb->mutex);
116}
117
118void flounder_support_migrate_notify(struct waitset_chanstate *chan,
119                                     struct waitset *new_ws)
120{
121    waitset_chan_migrate(chan, new_ws);
122}
123
124static void cap_send_cont(void *arg)
125{
126    struct flounder_cap_state *s = arg;
127    s->cap_send_continuation(s->binding);
128}
129
130errval_t flounder_stub_send_cap(struct flounder_cap_state *s,
131                                struct monitor_binding *mb,
132                                uintptr_t monitor_id,
133                                struct capref cap, bool give_away,
134                                void (*cont)(void *st))
135{
136    errval_t err;
137
138    s->cap_send_continuation = cont;
139
140    if (give_away) {
141        err = mb->tx_vtbl.cap_move_request(mb, MKCONT(cap_send_cont, s),
142                                           monitor_id, cap, s->tx_capnum);
143    }
144    else {
145        err = mb->tx_vtbl.cap_send_request(mb, MKCONT(cap_send_cont, s),
146                                           monitor_id, cap, s->tx_capnum);
147    }
148    if (err_is_ok(err)) {
149        thread_set_local_trigger(&mb->tx_cont_chanstate);
150        s->tx_capnum++;
151        return err;
152    } else if (err_no(err) == FLOUNDER_ERR_TX_BUSY) {
153        assert(0); // this should never happen
154        thread_set_local_trigger(&mb->tx_cont_chanstate); // not sure if this is
155        // ok since I don't know how to test this case
156        return mb->register_send(mb, mb->waitset, MKCONT(cap_send_cont, s));
157    } else {
158        return err_push(err, LIB_ERR_MONITOR_CAP_SEND);
159    }
160}
161
162#if defined(CONFIG_INTERCONNECT_DRIVER_UMP)
163static void flounder_stub_cap_state_init(struct flounder_cap_state *s, void *binding)
164{
165    s->tx_cap_ack = false;
166    s->rx_cap_ack = false;
167    s->monitor_mutex_held = false;
168    s->tx_capnum = 0;
169    s->rx_capnum = 0;
170    s->binding = binding;
171}
172#endif // UMP
173
174static uintptr_t getword(const uint8_t *buf, size_t *pos, size_t len)
175{
176    uintptr_t word = 0;
177
178    for (int i = 0; *pos < len && i < sizeof(uintptr_t); i++) {
179        // read and shift in next byte
180        word <<= NBBY;
181        word |= buf[(*pos)++];
182    }
183
184    return word;
185}
186
187static void putword(uintptr_t word, uint8_t *buf, size_t *pos, size_t len)
188{
189    const size_t shift_bits = (sizeof(uintptr_t) - 1) * NBBY;
190
191    // throw away leading zeros if this is the end of the message
192    if (len - *pos < sizeof(uintptr_t)) {
193        word <<= NBBY * (sizeof(uintptr_t) - (len - *pos));
194    }
195
196    for (int i = 0; *pos < len && i < sizeof(uintptr_t); i++) {
197        buf[(*pos)++] = word >> shift_bits;
198        word <<= NBBY;
199    }
200}
201
202#ifdef CONFIG_INTERCONNECT_DRIVER_LMP
203
204#include <flounder/flounder_support_lmp.h>
205
206errval_t flounder_stub_lmp_send_buf(struct lmp_chan *chan,
207                                    lmp_send_flags_t flags, const void *bufp,
208                                    size_t len, size_t *pos)
209{
210    errval_t err;
211    const uint8_t *buf = bufp;
212
213    do {
214        // compute number of words for this message
215        size_t msg_words = DIVIDE_ROUND_UP(len - *pos, sizeof(uintptr_t));
216        if (*pos == 0) { // space for header
217            msg_words += 1;
218        }
219        if (msg_words > LMP_MSG_LENGTH)
220            msg_words = LMP_MSG_LENGTH;
221
222        // store initial position for retry
223        size_t restartpos = *pos;
224
225        // is this the start of the string?
226        uintptr_t w1;
227        if (*pos == 0) {
228            // if so, send the length in the first word
229            w1 = len;
230        } else {
231            // otherwise use it for payload
232            w1 = getword(buf, pos, len);
233        }
234
235        // get the rest of the message, painfully
236#if LMP_MSG_LENGTH > 1
237        uintptr_t w2 = getword(buf, pos, len);
238#endif
239#if LMP_MSG_LENGTH > 2
240        uintptr_t w3 = getword(buf, pos, len);
241#endif
242#if LMP_MSG_LENGTH > 3
243        uintptr_t w4 = getword(buf, pos, len);
244#endif
245#if LMP_MSG_LENGTH > 4
246        uintptr_t w5 = getword(buf, pos, len);
247#endif
248#if LMP_MSG_LENGTH > 5
249        uintptr_t w6 = getword(buf, pos, len);
250#endif
251#if LMP_MSG_LENGTH > 6
252        uintptr_t w7 = getword(buf, pos, len);
253#endif
254#if LMP_MSG_LENGTH > 7
255        uintptr_t w8 = getword(buf, pos, len);
256#endif
257#if LMP_MSG_LENGTH > 8
258        uintptr_t w9 = getword(buf, pos, len);
259#endif
260#if LMP_MSG_LENGTH > 9
261        uintptr_t w10 = getword(buf, pos, len);
262#endif
263#if LMP_MSG_LENGTH > 10
264#error Need to unroll message send loop further
265#endif
266
267        // only set the sync flag if this is the last fragment
268        lmp_send_flags_t f = flags;
269        if (*pos < len) {
270            f &= ~LMP_FLAG_SYNC;
271        }
272
273        // try to send
274        err = lmp_chan_send(chan, f, NULL_CAP, msg_words, w1
275#if LMP_MSG_LENGTH > 1
276                            , w2
277#endif
278#if LMP_MSG_LENGTH > 2
279                            , w3
280#endif
281#if LMP_MSG_LENGTH > 3
282                            , w4
283#endif
284#if LMP_MSG_LENGTH > 4
285                            , w5
286#endif
287#if LMP_MSG_LENGTH > 5
288                            , w6
289#endif
290#if LMP_MSG_LENGTH > 6
291                            , w7
292#endif
293#if LMP_MSG_LENGTH > 7
294                            , w8
295#endif
296#if LMP_MSG_LENGTH > 8
297                            , w9
298#endif
299#if LMP_MSG_LENGTH > 9
300                            , w10
301#endif
302                            );
303
304        if (err_is_fail(err)) {
305            *pos = restartpos;
306        }
307    } while (err_is_ok(err) && *pos < len);
308
309    // do we need to send more? if not, zero out our state for the next send
310    if (*pos >= len) {
311        *pos = 0;
312    }
313
314    return err;
315}
316
317errval_t flounder_stub_lmp_recv_buf(struct lmp_recv_msg *msg, void *buf,
318                                    size_t *len, size_t *pos, size_t maxsize)
319{
320    int msgpos;
321
322    assert(buf);
323
324    // is this the first fragment?
325    // if so, unmarshall the length and allocate a buffer
326    if (*pos == 0) {
327        if (msg->buf.msglen == 0) {
328            return FLOUNDER_ERR_RX_INVALID_LENGTH;
329        }
330
331        *len = msg->words[0];
332        assert(*len <= maxsize);
333        msgpos = 1;
334    } else {
335        msgpos = 0;
336    }
337
338    // copy remainder of fragment to buffer
339    for (; msgpos < msg->buf.msglen && *pos < *len; msgpos++) {
340        putword(msg->words[msgpos], buf, pos, *len);
341    }
342
343    // are we done?
344    if (*pos < *len) {
345        return FLOUNDER_ERR_BUF_RECV_MORE;
346    } else {
347        // reset state for next buffer
348        *pos = 0;
349        return SYS_ERR_OK;
350    }
351}
352
353errval_t flounder_stub_lmp_send_string(struct lmp_chan *chan,
354                                       lmp_send_flags_t flags,
355                                       const char *str,
356                                       size_t *pos, size_t *len)
357{
358    // compute length, if this is the first call
359    if (*pos == 0) {
360        if (str == NULL) {
361            *len = 0;
362        } else {
363            // send the '\0', making it easy to reuse the buffer code
364            *len = strlen(str) + 1;
365        }
366    }
367
368    return flounder_stub_lmp_send_buf(chan, flags, str, *len, pos);
369}
370
371errval_t flounder_stub_lmp_recv_string(struct lmp_recv_msg *msg, char *str,
372                                       size_t *pos, size_t *len, size_t maxsize)
373{
374    errval_t err;
375
376    err = flounder_stub_lmp_recv_buf(msg, (void *)str, len, pos, maxsize);
377    if (*len == 0) {
378        str[0] = '\0';
379    }
380    return err;
381}
382#endif // CONFIG_INTERCONNECT_DRIVER_LMP
383
384
385#ifdef CONFIG_INTERCONNECT_DRIVER_UMP
386
387#include <flounder/flounder_support_ump.h>
388
389void flounder_stub_ump_state_init(struct flounder_ump_state *s, void *binding)
390{
391    s->token = 0;
392    flounder_stub_cap_state_init(&s->capst, binding);
393}
394
395errval_t flounder_stub_ump_send_buf(struct flounder_ump_state *s,
396                                       int msgnum, const void *bufp,
397                                       size_t len, size_t *pos)
398{
399    volatile struct ump_message *msg;
400    const uint8_t *buf = bufp;
401    struct ump_control ctrl;
402    int msgpos;
403
404    do {
405        msg = ump_chan_get_next(&s->chan, &ctrl);
406        if (!msg)
407            return FLOUNDER_ERR_BUF_SEND_MORE;
408        flounder_stub_ump_control_fill(s, &ctrl, msgnum);
409
410        // is this the start of the buffer?
411        if (*pos == 0) {
412            // if so, send the length in the first word
413            msg->data[0] = len;
414            // XXX: skip as many words as the largest word size
415            msgpos = (sizeof(uint64_t) / sizeof(uintptr_t));
416        } else {
417            // otherwise use it for payload
418            msgpos = 0;
419        }
420
421        for (; msgpos < UMP_PAYLOAD_WORDS && *pos < len; msgpos++) {
422            msg->data[msgpos] = getword(buf, pos, len);
423        }
424
425        flounder_stub_ump_barrier();
426        msg->header.control = ctrl;
427    } while (*pos < len);
428
429    // we're done. zero out our state for the next buffer
430    assert(*pos >= len);
431    *pos = 0;
432
433    return SYS_ERR_OK;
434}
435
436errval_t flounder_stub_ump_recv_buf(volatile struct ump_message *msg,
437                                    void *buf, size_t *len, size_t *pos,
438                                    size_t maxsize)
439{
440    int msgpos;
441
442    assert(buf);
443
444    // is this the first fragment?
445    // if so, unmarshall the length and allocate a buffer
446    if (*pos == 0) {
447        *len = msg->data[0];
448        assert(*len <= maxsize);
449        // XXX: skip as many words as the largest word size
450        msgpos = (sizeof(uint64_t) / sizeof(uintptr_t));
451    } else {
452        msgpos = 0;
453    }
454
455    // copy remainder of fragment to buffer
456    for (; msgpos < UMP_PAYLOAD_WORDS && *pos < *len; msgpos++) {
457        putword(msg->data[msgpos], buf, pos, *len);
458    }
459
460    // are we done?
461    if (*pos < *len) {
462        return FLOUNDER_ERR_BUF_RECV_MORE;
463    } else {
464        // reset state for next buffer
465        *pos = 0;
466        return SYS_ERR_OK;
467    }
468}
469
470errval_t flounder_stub_ump_send_string(struct flounder_ump_state *s,
471                                       int msgnum, const char *str,
472                                       size_t *pos, size_t *len)
473{
474    // compute length, if this is the first call
475    if (*pos == 0) {
476        if (str == NULL) {
477            *len = 0;
478        } else {
479            // send the '\0', making it easy to reuse the buffer code
480            *len = strlen(str) + 1;
481        }
482    }
483
484    return flounder_stub_ump_send_buf(s, msgnum, str, *len, pos);
485}
486
487errval_t flounder_stub_ump_recv_string(volatile struct ump_message *msg,
488                                       char *str, size_t *pos, size_t *len,
489                                       size_t maxsize)
490{
491    errval_t err;
492
493    err = flounder_stub_ump_recv_buf(msg, (void *)str, len, pos, maxsize);
494    if (*len == 0) {
495        str[0] = '\0';
496    }
497    return err;
498}
499
500#endif // CONFIG_INTERCONNECT_DRIVER_UMP
501