1/** \file 2 * \brief IDC system test code 3 */ 4 5/* 6 * Copyright (c) 2018, ETH Zurich. 7 * All rights reserved. 8 * 9 * This file is distributed under the terms in the attached LICENSE file. 10 * If you do not find this file, copies can be found by writing to: 11 * ETH Zurich D-INFK, Universitaetsstrasse 6, CH-8092 Zurich. 12 * Attn: Systems Group. 13 */ 14 15#include <string.h> 16#include <stdio.h> 17#include <barrelfish/barrelfish.h> 18#include <barrelfish/spawn_client.h> 19 20#include <if/flounderbootstrap_defs.h> 21 22 23 24static struct flounderbootstrap_binding *binding_ump; 25static struct flounderbootstrap_binding *binding_lmp; 26static struct flounderbootstrap_binding *binding; 27 28static struct capref dom_lmp; 29static struct capref dom_ump; 30 31static struct capref ep_lmp; 32static struct capref ep_ump; 33 34 35struct state { 36 const char *name; 37 uint32_t counter; 38 uint32_t acks; 39}; 40 41/* */ 42 43static uint8_t phase = 0; 44 45 46static void tx_init(struct flounderbootstrap_binding *b, struct capref cap) 47{ 48 errval_t err; 49 50 struct state *state = b->st; 51 52 debug_printf("%s Sending tx_init\n", state->name); 53 54 55 if (state->counter == 2) { 56 debug_printf("stopping with cap transfers. already sent two\n"); 57 err = flounderbootstrap_ack__tx(b, NOP_CONT); 58 assert(err_is_ok(err)); 59 return; 60 } 61 62 state->counter++; 63 64 err = flounderbootstrap_init__tx(b, NOP_CONT, cap); 65 assert(err_is_ok(err)); 66} 67 68static void tx_ack(struct flounderbootstrap_binding *b) 69{ 70 errval_t err; 71 72 struct state *state = b->st; 73 74 debug_printf("%s Sending tx_ack\n", state->name); 75 76 err = flounderbootstrap_ack__tx(b, NOP_CONT); 77 assert(err_is_ok(err)); 78} 79 80static void tx_test(struct flounderbootstrap_binding *b, 81 uint32_t arg) 82{ 83 errval_t err; 84 85 struct state *state = b->st; 86 87 debug_printf("%s Sending tx_test\n", state->name); 88 89 err = flounderbootstrap_test__tx(b, NOP_CONT, arg); 90 assert(err_is_ok(err)); 91} 92 93/* ------------------------ COMMON MESSAGE HANDLERS ------------------------ */ 94 95static void rx_init(struct flounderbootstrap_binding *b, 96 struct capref cap) 97{ 98 struct state *state = b->st; 99 100 101 if (capref_is_null(cap)) { 102 debug_printf("rx_init %s NULL_CAP\n", state->name); 103 tx_test(b, 0xdeadbeef); 104 105 } else { 106 errval_t err; 107 108 struct frame_identity id; 109 err = frame_identify(cap, &id); 110 assert(err_is_ok(err)); 111 debug_printf("rx_init %s Frame: %lx\n", state->name, id.base); 112 tx_test(b, 0xb001b001); 113 } 114} 115 116static void rx_ack(struct flounderbootstrap_binding *b) 117{ 118 struct state *state = b->st; 119 120 debug_printf("rx_ack %s\n", state->name); 121 122 state->acks++; 123 124 if (state->acks == 2) { 125 phase++; 126 } else { 127 tx_test(b, 0xcafebabe); 128 } 129 130} 131 132static void rx_test(struct flounderbootstrap_binding *b, 133 uint32_t arg) 134{ 135 struct state *state = b->st; 136 137 debug_printf("rx_ack %s, %u\n", state->name, arg); 138 139 if (arg == 0xcafebabe) { 140 tx_init(b, NULL_CAP); 141 } else if (arg == 0xdeadbeef) { 142 errval_t err; 143 struct capref cap; 144 err = frame_alloc(&cap, BASE_PAGE_SIZE, NULL); 145 assert(err_is_ok(err)); 146 tx_init(b, cap); 147 } else { 148 tx_test(b, 0xcafebabe); 149 } 150} 151 152static struct flounderbootstrap_rx_vtbl rx_vtbl = { 153 .init = rx_init, 154 .ack = rx_ack, 155 .test = rx_test, 156}; 157 158/* ------------------------------ CLIENT ------------------------------ */ 159 160 161static void bind_cont(void *st, errval_t err, struct flounderbootstrap_binding *b) 162{ 163 if (err_is_fail(err)) { 164 USER_PANIC_ERR(err, "bind failed"); 165 } 166 167 debug_printf("client bound!\n"); 168 169 // copy my message receive handler vtable to the binding 170 b->rx_vtbl = rx_vtbl; 171 172 binding = b; 173 174 tx_ack(b); 175} 176 177 178static void dddebug_cap(char *c, struct capref cap) 179{ 180 181 char buf[512]; 182 debug_print_cap_at_capref(buf, 512, cap); 183 184 debug_printf("%s CAP: %s\n", c, buf); 185} 186 187 188static void start_client(void) 189{ 190 errval_t err; 191 192 debug_printf("Starting Client...\n"); 193 194 struct capref ep = { 195 .cnode = build_cnoderef(cap_argcn, CNODE_TYPE_OTHER), 196 .slot = 0 197 }; 198 199 dddebug_cap("Client", ep); 200 201 struct state *state = calloc(1, sizeof(*state)); 202 assert(state); 203 204 state->name = "Client"; 205 206 debug_printf("Bind to endpoint...\n"); 207 208 err = flounderbootstrap_bind_to_endpoint(ep, bind_cont, state, 209 get_default_waitset(), IDC_BIND_FLAGS_DEFAULT); 210 if (err_is_fail(err)) { 211 USER_PANIC_ERR(err, "Failed to bind..."); 212 } 213} 214 215/* ------------------------------ SERVER ------------------------------ */ 216 217 218 219 220static errval_t spawn_client(char *name, coreid_t core, void *st) 221{ 222 errval_t err; 223 224 struct capref *dom_cap; 225 226 struct capref argcn; 227 struct cnoderef argcnref; 228 err = cnode_create_l2(&argcn, &argcnref); 229 if (err_is_fail(err)) { 230 DEBUG_ERR(err, "failed to create the argcn"); 231 return err; 232 } 233 234 struct state *state = calloc(1, sizeof(*state)); 235 assert(state); 236 237 state->name = st; 238 239 if (core == disp_get_core_id()) { 240 debug_printf("Creating LMP Endpoint...\n"); 241 242 ep_lmp.cnode = argcnref; 243 ep_lmp.slot = 0; 244 245 dom_cap = &dom_lmp; 246 247 248 err = flounderbootstrap_create_endpoint(IDC_ENDPOINT_LMP, &rx_vtbl, state, 249 get_default_waitset(), 250 IDC_ENDPOINT_FLAGS_DUMMY, 251 &binding_lmp, ep_lmp); 252 253 dddebug_cap("server", ep_lmp); 254 } else { 255 256 debug_printf("Creating UMP Endpoint...\n"); 257 258 ep_ump.cnode = argcnref; 259 ep_ump.slot = 0; 260 261 dom_cap = &dom_ump; 262 263 264 err = flounderbootstrap_create_endpoint(IDC_ENDPOINT_UMP, &rx_vtbl, state, 265 get_default_waitset(), 266 IDC_ENDPOINT_FLAGS_DUMMY, 267 &binding_ump, ep_ump); 268 269 dddebug_cap("server", ep_ump); 270 271 }; 272 273 if (err_is_fail(err)) { 274 DEBUG_ERR(err, "failed to create the endpoint"); 275 return err; 276 } 277 278 char *argv[2]; 279 argv[0] = "client"; 280 argv[1] = NULL; 281 282 return spawn_program_with_caps(core, name, argv, NULL, NULL_CAP, argcn, 283 SPAWN_FLAGS_DEFAULT, dom_cap); 284} 285 286 287static void start_server(char *path) 288{ 289 errval_t err; 290 291 if (phase == 0) { 292 debug_printf("=================================\n"); 293 debug_printf("LMP Test\n"); 294 debug_printf("=================================\n"); 295 err = spawn_client(path, disp_get_core_id(), "server LMP"); 296 if (err_is_fail(err)) { 297 USER_PANIC_ERR(err, "failed to start clients\n"); 298 } 299 } else if (phase == 2) { 300 debug_printf("=================================\n"); 301 debug_printf("UMP Test\n"); 302 debug_printf("=================================\n"); 303 coreid_t target = 1; 304 if (disp_get_core_id() == 1) { 305 target = 0; 306 } 307 err = spawn_client(path, target, "server UMP"); 308 if (err_is_fail(err)) { 309 USER_PANIC_ERR(err, "failed to start clients\n"); 310 } 311 } 312 phase++; 313} 314 315/* ------------------------------ MAIN ------------------------------ */ 316 317int main(int argc, char *argv[]) 318{ 319 errval_t err; 320 321 debug_printf("%s: %u %s\n", argv[0], argc, ""); 322 323 uint8_t is_server = 0; 324 if (argc == 1 && strcmp(argv[0], "client") == 0) { 325 start_client(); 326 } else { 327 is_server = 1; 328 } 329 330 debug_printf("%s Going into message handler loop\n", is_server ? "SErver" : "Client"); 331 332 struct waitset *ws = get_default_waitset(); 333 while (1) { 334 if (is_server && phase == 0) { 335 start_server("tests/ep_basic"); 336 } else if (is_server && phase == 2) { 337 start_server("tests/ep_basic"); 338 } 339 err = event_dispatch(ws); 340 if (err_is_fail(err)) { 341 DEBUG_ERR(err, "in event_dispatch"); 342 break; 343 } 344 } 345 346 347 348 return EXIT_FAILURE; 349} 350