3 * \brief Support code for Flounder-generated stubs
7 * Copyright (c) 2010, 2011, 2012, ETH Zurich.
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.
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>
25 /// Special continuation for blocking
26 void blocking_cont(void *v)
28 debug_printf("%s: should never be called!\n", __func__);
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
38 static void dummy_event_handler(void *arg)
42 struct event_closure dummy_event_closure = {
43 .handler = dummy_event_handler,
47 void flounder_support_trigger_chan(struct waitset_chanstate *wc)
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
55 void flounder_support_deregister_chan(struct waitset_chanstate *wc)
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
63 errval_t flounder_support_register(struct waitset *ws,
64 struct waitset_chanstate *wc,
65 struct event_closure ec,
69 return waitset_chan_trigger_closure(ws, wc, ec);
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
75 return waitset_chan_register(ws, wc, ec);
79 void flounder_support_waitset_chanstate_init(struct waitset_chanstate *wc)
81 waitset_chanstate_init(wc, CHANTYPE_FLOUNDER);
84 void flounder_support_waitset_chanstate_init_persistent(struct waitset_chanstate *wc)
86 waitset_chanstate_init(wc, CHANTYPE_FLOUNDER);
87 wc->persistent = true;
90 void flounder_support_waitset_chanstate_destroy(struct waitset_chanstate *wc)
92 waitset_chanstate_destroy(wc);
95 struct waitset * flounder_support_get_current_monitor_waitset(struct monitor_binding *mb)
100 errval_t flounder_support_change_monitor_waitset(struct monitor_binding *mb,
103 return mb->change_waitset(mb, ws);
106 void flounder_support_monitor_mutex_enqueue(struct monitor_binding *mb,
107 struct event_queue_node *qn,
108 struct event_closure cl)
110 event_mutex_enqueue_lock(&mb->mutex, qn, cl);
113 void flounder_support_monitor_mutex_unlock(struct monitor_binding *mb)
115 event_mutex_unlock(&mb->mutex);
118 void flounder_support_migrate_notify(struct waitset_chanstate *chan,
119 struct waitset *new_ws)
121 waitset_chan_migrate(chan, new_ws);
124 static void cap_send_cont(void *arg)
126 struct flounder_cap_state *s = arg;
127 s->cap_send_continuation(s->binding);
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))
138 s->cap_send_continuation = cont;
141 err = mb->tx_vtbl.cap_move_request(mb, MKCONT(cap_send_cont, s),
142 monitor_id, cap, s->tx_capnum);
145 err = mb->tx_vtbl.cap_send_request(mb, MKCONT(cap_send_cont, s),
146 monitor_id, cap, s->tx_capnum);
148 if (err_is_ok(err)) {
151 } else if (err_no(err) == FLOUNDER_ERR_TX_BUSY) {
153 return mb->register_send(mb, mb->waitset, MKCONT(cap_send_cont, s));
155 return err_push(err, LIB_ERR_MONITOR_CAP_SEND);
159 #if defined(CONFIG_INTERCONNECT_DRIVER_UMP)
160 static void flounder_stub_cap_state_init(struct flounder_cap_state *s, void *binding)
162 s->tx_cap_ack = false;
163 s->rx_cap_ack = false;
164 s->monitor_mutex_held = false;
167 s->binding = binding;
171 static uintptr_t getword(const uint8_t *buf, size_t *pos, size_t len)
175 for (int i = 0; *pos < len && i < sizeof(uintptr_t); i++) {
176 // read and shift in next byte
178 word |= buf[(*pos)++];
184 static void putword(uintptr_t word, uint8_t *buf, size_t *pos, size_t len)
186 const size_t shift_bits = (sizeof(uintptr_t) - 1) * NBBY;
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));
193 for (int i = 0; *pos < len && i < sizeof(uintptr_t); i++) {
194 buf[(*pos)++] = word >> shift_bits;
199 #ifdef CONFIG_INTERCONNECT_DRIVER_LMP
201 #include <flounder/flounder_support_lmp.h>
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)
208 const uint8_t *buf = bufp;
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
216 if (msg_words > LMP_MSG_LENGTH)
217 msg_words = LMP_MSG_LENGTH;
219 // store initial position for retry
220 size_t restartpos = *pos;
222 // is this the start of the string?
225 // if so, send the length in the first word
228 // otherwise use it for payload
229 w1 = getword(buf, pos, len);
232 // get the rest of the message, painfully
233 #if LMP_MSG_LENGTH > 1
234 uintptr_t w2 = getword(buf, pos, len);
236 #if LMP_MSG_LENGTH > 2
237 uintptr_t w3 = getword(buf, pos, len);
239 #if LMP_MSG_LENGTH > 3
240 uintptr_t w4 = getword(buf, pos, len);
242 #if LMP_MSG_LENGTH > 4
243 uintptr_t w5 = getword(buf, pos, len);
245 #if LMP_MSG_LENGTH > 5
246 uintptr_t w6 = getword(buf, pos, len);
248 #if LMP_MSG_LENGTH > 6
249 uintptr_t w7 = getword(buf, pos, len);
251 #if LMP_MSG_LENGTH > 7
252 uintptr_t w8 = getword(buf, pos, len);
254 #if LMP_MSG_LENGTH > 8
255 uintptr_t w9 = getword(buf, pos, len);
257 #if LMP_MSG_LENGTH > 9
258 uintptr_t w10 = getword(buf, pos, len);
260 #if LMP_MSG_LENGTH > 10
261 #error Need to unroll message send loop further
264 // only set the sync flag if this is the last fragment
265 lmp_send_flags_t f = flags;
271 err = lmp_chan_send(chan, f, NULL_CAP, msg_words, w1
272 #if LMP_MSG_LENGTH > 1
275 #if LMP_MSG_LENGTH > 2
278 #if LMP_MSG_LENGTH > 3
281 #if LMP_MSG_LENGTH > 4
284 #if LMP_MSG_LENGTH > 5
287 #if LMP_MSG_LENGTH > 6
290 #if LMP_MSG_LENGTH > 7
293 #if LMP_MSG_LENGTH > 8
296 #if LMP_MSG_LENGTH > 9
301 if (err_is_fail(err)) {
304 } while (err_is_ok(err) && *pos < len);
306 // do we need to send more? if not, zero out our state for the next send
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)
321 // is this the first fragment?
322 // if so, unmarshall the length and allocate a buffer
324 if (msg->buf.msglen == 0) {
325 return FLOUNDER_ERR_RX_INVALID_LENGTH;
328 *len = msg->words[0];
329 assert(*len < maxsize);
335 // copy remainder of fragment to buffer
336 for (; msgpos < msg->buf.msglen && *pos < *len; msgpos++) {
337 putword(msg->words[msgpos], buf, pos, *len);
342 return FLOUNDER_ERR_BUF_RECV_MORE;
344 // reset state for next buffer
350 errval_t flounder_stub_lmp_send_string(struct lmp_chan *chan,
351 lmp_send_flags_t flags,
353 size_t *pos, size_t *len)
355 // compute length, if this is the first call
360 // send the '\0', making it easy to reuse the buffer code
361 *len = strlen(str) + 1;
365 return flounder_stub_lmp_send_buf(chan, flags, str, *len, pos);
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)
373 err = flounder_stub_lmp_recv_buf(msg, (void *)str, len, pos, maxsize);
379 #endif // CONFIG_INTERCONNECT_DRIVER_LMP
382 #ifdef CONFIG_INTERCONNECT_DRIVER_UMP
384 #include <flounder/flounder_support_ump.h>
386 void flounder_stub_ump_state_init(struct flounder_ump_state *s, void *binding)
393 flounder_stub_cap_state_init(&s->capst, binding);
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)
400 volatile struct ump_message *msg;
401 const uint8_t *buf = bufp;
402 struct ump_control ctrl;
406 if (!flounder_stub_ump_can_send(s)) {
407 return FLOUNDER_ERR_BUF_SEND_MORE;
410 msg = ump_chan_get_next(&s->chan, &ctrl);
411 flounder_stub_ump_control_fill(s, &ctrl, msgnum);
413 // is this the start of the buffer?
415 // if so, send the length in the first word
417 // XXX: skip as many words as the largest word size
418 msgpos = (sizeof(uint64_t) / sizeof(uintptr_t));
420 // otherwise use it for payload
424 for (; msgpos < UMP_PAYLOAD_WORDS && *pos < len; msgpos++) {
425 msg->data[msgpos] = getword(buf, pos, len);
428 flounder_stub_ump_barrier();
429 msg->header.control = ctrl;
430 } while (*pos < len);
432 // we're done. zero out our state for the next buffer
439 errval_t flounder_stub_ump_recv_buf(volatile struct ump_message *msg,
440 void *buf, size_t *len, size_t *pos,
447 // is this the first fragment?
448 // if so, unmarshall the length and allocate a buffer
451 assert(*len <= maxsize);
452 // XXX: skip as many words as the largest word size
453 msgpos = (sizeof(uint64_t) / sizeof(uintptr_t));
458 // copy remainder of fragment to buffer
459 for (; msgpos < UMP_PAYLOAD_WORDS && *pos < *len; msgpos++) {
460 putword(msg->data[msgpos], buf, pos, *len);
465 return FLOUNDER_ERR_BUF_RECV_MORE;
467 // reset state for next buffer
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)
477 // compute length, if this is the first call
482 // send the '\0', making it easy to reuse the buffer code
483 *len = strlen(str) + 1;
487 return flounder_stub_ump_send_buf(s, msgnum, str, *len, pos);
490 errval_t flounder_stub_ump_recv_string(volatile struct ump_message *msg,
491 char *str, size_t *pos, size_t *len,
496 err = flounder_stub_ump_recv_buf(msg, (void *)str, len, pos, maxsize);
503 #endif // CONFIG_INTERCONNECT_DRIVER_UMP