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