Adding some initializations
[barrelfish] / lib / barrelfish / flounder_support.c
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
26 void 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
38 static void dummy_event_handler(void *arg)
39 {
40 }
41
42 struct event_closure dummy_event_closure = {
43     .handler = dummy_event_handler,
44     .arg = NULL,
45 };
46
47 void 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
55 void 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
63 errval_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
79 void flounder_support_waitset_chanstate_init(struct waitset_chanstate *wc)
80 {
81     waitset_chanstate_init(wc, CHANTYPE_FLOUNDER);
82 }
83
84 void flounder_support_waitset_chanstate_init_persistent(struct waitset_chanstate *wc)
85 {
86     waitset_chanstate_init(wc, CHANTYPE_FLOUNDER);
87     wc->persistent = true;
88 }
89
90 void flounder_support_waitset_chanstate_destroy(struct waitset_chanstate *wc)
91 {
92     waitset_chanstate_destroy(wc);
93 }
94
95 struct waitset * flounder_support_get_current_monitor_waitset(struct monitor_binding *mb)
96 {
97     return mb->waitset;
98 }
99
100 errval_t flounder_support_change_monitor_waitset(struct monitor_binding *mb,
101                                                  struct waitset *ws)
102 {
103     return mb->change_waitset(mb, ws);
104 }
105
106 void 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
113 void flounder_support_monitor_mutex_unlock(struct monitor_binding *mb)
114 {
115     event_mutex_unlock(&mb->mutex);
116 }
117
118 void flounder_support_migrate_notify(struct waitset_chanstate *chan,
119                                      struct waitset *new_ws)
120 {
121     waitset_chan_migrate(chan, new_ws);
122 }
123
124 static void cap_send_cont(void *arg)
125 {
126     struct flounder_cap_state *s = arg;
127     s->cap_send_continuation(s->binding);
128 }
129
130 errval_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         s->tx_capnum++;
150         return err;
151     } else if (err_no(err) == FLOUNDER_ERR_TX_BUSY) {
152         // register to retry
153         return mb->register_send(mb, mb->waitset, MKCONT(cap_send_cont, s));
154     } else {
155         return err_push(err, LIB_ERR_MONITOR_CAP_SEND);
156     }
157 }
158
159 #if defined(CONFIG_INTERCONNECT_DRIVER_UMP)
160 static void flounder_stub_cap_state_init(struct flounder_cap_state *s, void *binding)
161 {
162     s->tx_cap_ack = false;
163     s->rx_cap_ack = false;
164     s->monitor_mutex_held = false;
165     s->tx_capnum = 0;
166     s->rx_capnum = 0;
167     s->binding = binding;
168 }
169 #endif // UMP
170
171 static uintptr_t getword(const uint8_t *buf, size_t *pos, size_t len)
172 {
173     uintptr_t word = 0;
174
175     for (int i = 0; *pos < len && i < sizeof(uintptr_t); i++) {
176         // read and shift in next byte
177         word <<= NBBY;
178         word |= buf[(*pos)++];
179     }
180
181     return word;
182 }
183
184 static void putword(uintptr_t word, uint8_t *buf, size_t *pos, size_t len)
185 {
186     const size_t shift_bits = (sizeof(uintptr_t) - 1) * NBBY;
187
188     // throw away leading zeros if this is the end of the message
189     if (len - *pos < sizeof(uintptr_t)) {
190         word <<= NBBY * (sizeof(uintptr_t) - (len - *pos));
191     }
192
193     for (int i = 0; *pos < len && i < sizeof(uintptr_t); i++) {
194         buf[(*pos)++] = word >> shift_bits;
195         word <<= NBBY;
196     }
197 }
198
199 #ifdef CONFIG_INTERCONNECT_DRIVER_LMP
200
201 #include <flounder/flounder_support_lmp.h>
202
203 errval_t flounder_stub_lmp_send_buf(struct lmp_chan *chan,
204                                     lmp_send_flags_t flags, const void *bufp,
205                                     size_t len, size_t *pos)
206 {
207     errval_t err;
208     const uint8_t *buf = bufp;
209
210     do {
211         // compute number of words for this message
212         size_t msg_words = DIVIDE_ROUND_UP(len - *pos, sizeof(uintptr_t));
213         if (*pos == 0) { // space for header
214             msg_words += 1;
215         }
216         if (msg_words > LMP_MSG_LENGTH)
217             msg_words = LMP_MSG_LENGTH;
218
219         // store initial position for retry
220         size_t restartpos = *pos;
221
222         // is this the start of the string?
223         uintptr_t w1;
224         if (*pos == 0) {
225             // if so, send the length in the first word
226             w1 = len;
227         } else {
228             // otherwise use it for payload
229             w1 = getword(buf, pos, len);
230         }
231
232         // get the rest of the message, painfully
233 #if LMP_MSG_LENGTH > 1
234         uintptr_t w2 = getword(buf, pos, len);
235 #endif
236 #if LMP_MSG_LENGTH > 2
237         uintptr_t w3 = getword(buf, pos, len);
238 #endif
239 #if LMP_MSG_LENGTH > 3
240         uintptr_t w4 = getword(buf, pos, len);
241 #endif
242 #if LMP_MSG_LENGTH > 4
243         uintptr_t w5 = getword(buf, pos, len);
244 #endif
245 #if LMP_MSG_LENGTH > 5
246         uintptr_t w6 = getword(buf, pos, len);
247 #endif
248 #if LMP_MSG_LENGTH > 6
249         uintptr_t w7 = getword(buf, pos, len);
250 #endif
251 #if LMP_MSG_LENGTH > 7
252         uintptr_t w8 = getword(buf, pos, len);
253 #endif
254 #if LMP_MSG_LENGTH > 8
255         uintptr_t w9 = getword(buf, pos, len);
256 #endif
257 #if LMP_MSG_LENGTH > 9
258         uintptr_t w10 = getword(buf, pos, len);
259 #endif
260 #if LMP_MSG_LENGTH > 10
261 #error Need to unroll message send loop further
262 #endif
263
264         // only set the sync flag if this is the last fragment
265         lmp_send_flags_t f = flags;
266         if (*pos < len) {
267             f &= ~LMP_FLAG_SYNC;
268         }
269
270         // try to send
271         err = lmp_chan_send(chan, f, NULL_CAP, msg_words, w1
272 #if LMP_MSG_LENGTH > 1
273                             , w2
274 #endif
275 #if LMP_MSG_LENGTH > 2
276                             , w3
277 #endif
278 #if LMP_MSG_LENGTH > 3
279                             , w4
280 #endif
281 #if LMP_MSG_LENGTH > 4
282                             , w5
283 #endif
284 #if LMP_MSG_LENGTH > 5
285                             , w6
286 #endif
287 #if LMP_MSG_LENGTH > 6
288                             , w7
289 #endif
290 #if LMP_MSG_LENGTH > 7
291                             , w8
292 #endif
293 #if LMP_MSG_LENGTH > 8
294                             , w9
295 #endif
296 #if LMP_MSG_LENGTH > 9
297                             , w10
298 #endif
299                             );
300
301         if (err_is_fail(err)) {
302             *pos = restartpos;
303         }
304     } while (err_is_ok(err) && *pos < len);
305
306     // do we need to send more? if not, zero out our state for the next send
307     if (*pos >= len) {
308         *pos = 0;
309     }
310
311     return err;
312 }
313
314 errval_t flounder_stub_lmp_recv_buf(struct lmp_recv_msg *msg, void *buf,
315                                     size_t *len, size_t *pos, size_t maxsize)
316 {
317     int msgpos;
318
319     assert(buf);
320
321     // is this the first fragment?
322     // if so, unmarshall the length and allocate a buffer
323     if (*pos == 0) {
324         if (msg->buf.msglen == 0) {
325             return FLOUNDER_ERR_RX_INVALID_LENGTH;
326         }
327
328         *len = msg->words[0];
329         assert(*len < maxsize);
330         msgpos = 1;
331     } else {
332         msgpos = 0;
333     }
334
335     // copy remainder of fragment to buffer
336     for (; msgpos < msg->buf.msglen && *pos < *len; msgpos++) {
337         putword(msg->words[msgpos], buf, pos, *len);
338     }
339
340     // are we done?
341     if (*pos < *len) {
342         return FLOUNDER_ERR_BUF_RECV_MORE;
343     } else {
344         // reset state for next buffer
345         *pos = 0;
346         return SYS_ERR_OK;
347     }
348 }
349
350 errval_t flounder_stub_lmp_send_string(struct lmp_chan *chan,
351                                        lmp_send_flags_t flags,
352                                        const char *str,
353                                        size_t *pos, size_t *len)
354 {
355     // compute length, if this is the first call
356     if (*pos == 0) {
357         if (str == NULL) {
358             *len = 0;
359         } else {
360             // send the '\0', making it easy to reuse the buffer code
361             *len = strlen(str) + 1;
362         }
363     }
364
365     return flounder_stub_lmp_send_buf(chan, flags, str, *len, pos);
366 }
367
368 errval_t flounder_stub_lmp_recv_string(struct lmp_recv_msg *msg, char *str,
369                                        size_t *pos, size_t *len, size_t maxsize)
370 {
371     errval_t err;
372
373     err = flounder_stub_lmp_recv_buf(msg, (void *)str, len, pos, maxsize);
374     if (*len == 0) {
375         str[0] = '\0';
376     }
377     return err;
378 }
379 #endif // CONFIG_INTERCONNECT_DRIVER_LMP
380
381
382 #ifdef CONFIG_INTERCONNECT_DRIVER_UMP
383
384 #include <flounder/flounder_support_ump.h>
385
386 void flounder_stub_ump_state_init(struct flounder_ump_state *s, void *binding)
387 {
388     s->next_id = 1;
389     s->seq_id = 0;
390     s->ack_id = 0;
391     s->last_ack = 0;
392     s->token = 0;
393     flounder_stub_cap_state_init(&s->capst, binding);
394 }
395
396 errval_t flounder_stub_ump_send_buf(struct flounder_ump_state *s,
397                                        int msgnum, const void *bufp,
398                                        size_t len, size_t *pos)
399 {
400     volatile struct ump_message *msg;
401     const uint8_t *buf = bufp;
402     struct ump_control ctrl;
403     int msgpos;
404
405     do {
406         if (!flounder_stub_ump_can_send(s)) {
407             return FLOUNDER_ERR_BUF_SEND_MORE;
408         }
409
410         msg = ump_chan_get_next(&s->chan, &ctrl);
411         flounder_stub_ump_control_fill(s, &ctrl, msgnum);
412
413         // is this the start of the buffer?
414         if (*pos == 0) {
415             // if so, send the length in the first word
416             msg->data[0] = len;
417             // XXX: skip as many words as the largest word size
418             msgpos = (sizeof(uint64_t) / sizeof(uintptr_t));
419         } else {
420             // otherwise use it for payload
421             msgpos = 0;
422         }
423
424         for (; msgpos < UMP_PAYLOAD_WORDS && *pos < len; msgpos++) {
425             msg->data[msgpos] = getword(buf, pos, len);
426         }
427
428         flounder_stub_ump_barrier();
429         msg->header.control = ctrl;
430     } while (*pos < len);
431
432     // we're done. zero out our state for the next buffer
433     assert(*pos >= len);
434     *pos = 0;
435
436     return SYS_ERR_OK;
437 }
438
439 errval_t flounder_stub_ump_recv_buf(volatile struct ump_message *msg,
440                                     void *buf, size_t *len, size_t *pos,
441                                     size_t maxsize)
442 {
443     int msgpos;
444
445     assert(buf);
446
447     // is this the first fragment?
448     // if so, unmarshall the length and allocate a buffer
449     if (*pos == 0) {
450         *len = msg->data[0];
451         assert(*len <= maxsize);
452         // XXX: skip as many words as the largest word size
453         msgpos = (sizeof(uint64_t) / sizeof(uintptr_t));
454     } else {
455         msgpos = 0;
456     }
457
458     // copy remainder of fragment to buffer
459     for (; msgpos < UMP_PAYLOAD_WORDS && *pos < *len; msgpos++) {
460         putword(msg->data[msgpos], buf, pos, *len);
461     }
462
463     // are we done?
464     if (*pos < *len) {
465         return FLOUNDER_ERR_BUF_RECV_MORE;
466     } else {
467         // reset state for next buffer
468         *pos = 0;
469         return SYS_ERR_OK;
470     }
471 }
472
473 errval_t flounder_stub_ump_send_string(struct flounder_ump_state *s,
474                                        int msgnum, const char *str,
475                                        size_t *pos, size_t *len)
476 {
477     // compute length, if this is the first call
478     if (*pos == 0) {
479         if (str == NULL) {
480             *len = 0;
481         } else {
482             // send the '\0', making it easy to reuse the buffer code
483             *len = strlen(str) + 1;
484         }
485     }
486
487     return flounder_stub_ump_send_buf(s, msgnum, str, *len, pos);
488 }
489
490 errval_t flounder_stub_ump_recv_string(volatile struct ump_message *msg,
491                                        char *str, size_t *pos, size_t *len,
492                                        size_t maxsize)
493 {
494     errval_t err;
495
496     err = flounder_stub_ump_recv_buf(msg, (void *)str, len, pos, maxsize);
497     if (*len == 0) {
498         str[0] = '\0';
499     }
500     return err;
501 }
502
503 #endif // CONFIG_INTERCONNECT_DRIVER_UMP