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