1/**
2 * \file
3 * \brief Boot module for the Xeon Phi
4 *
5 * Loads the co processor OS onto the card and boots it
6 */
7
8/*
9 * Copyright (c) 2014 ETH Zurich.
10 * All rights reserved.
11 *
12 * This file is distributed under the terms in the attached LICENSE file.
13 * If you do not find this file, copies can be found by writing to:
14 * ETH Zurich D-INFK, Universitaetsstrasse 6, CH-8092 Zurich. Attn: Systems Group.
15 */
16
17#include <stdio.h>
18#include <string.h>
19#include <barrelfish/barrelfish.h>
20#include <barrelfish/nameservice_client.h>
21#include <barrelfish/spawn_client.h>
22
23#include <flounder/flounder_txqueue.h>
24
25#include <if/interphi_defs.h>
26#include <if/mem_defs.h>
27
28#include <xeon_phi/xeon_phi.h>
29#include <xeon_phi/xeon_phi_domain.h>
30
31#include "xeon_phi_internal.h"
32#include "interphi.h"
33#include "smpt.h"
34#include "domain.h"
35#include "service.h"
36#include "xphi_service.h"
37#include "sysmem_caps.h"
38
39/**
40 * represents the information for the messaging channel between the host and
41 * the card.
42 */
43struct msg_info
44{
45    struct capref frame;
46    struct interphi_frameinfo fi;
47    struct interphi_binding *binding;
48    struct tx_queue queue;
49    errval_t rpc_err;
50    uint64_t rpc_data;
51    uint64_t rpc_data2;
52    uint8_t is_client;
53    uint8_t wait_reply;
54};
55
56/*
57 *
58 */
59struct interphi_msg_st
60{
61    struct txq_msg_st common;
62    /* union of arguments */
63    union
64    {
65        struct
66        {
67            uint8_t core;
68            char *cmdline;
69            size_t cmdlen;
70            uint8_t flags;
71            uint64_t cap_base;
72            uint8_t cap_size_bits;
73        } spawn_call;
74        struct
75        {
76            uint64_t domainid;
77        } spawn_reply;
78        struct
79        {
80            uint64_t domainid;
81        } kill;
82        struct
83        {
84            uint64_t base;
85            uint64_t offset;
86            uint8_t bits;
87            uint8_t xid;
88            uint8_t is_client;
89        } bootstrap;
90        struct
91        {
92            lpaddr_t msgbase;
93            uint8_t msgbits;
94            char *iface;
95            xphi_dom_id_t source;
96            uint64_t usrdata;
97            xphi_dom_id_t target;
98            xphi_chan_type_t type;
99        } open;
100        struct
101        {
102            const char *name;
103            xphi_dom_id_t domid;
104            uintptr_t state;
105        } domain;
106        struct {
107            uint64_t base;
108            uint64_t bytes;
109            errval_t err;
110        } alloc;
111    } args;
112};
113
114
115/*
116 * XXX: hack. just keep track of the frames for now and return them later
117 * for the paper usecase!
118 */
119struct mem_reg
120{
121    struct mem_reg *next;
122    struct capref cap;
123    struct frame_identity id;
124};
125
126static struct mem_reg *allocated_mem;
127
128/*
129 * ---------------------------------------------------------------------------
130 * RPC management
131 * ---------------------------------------------------------------------------
132 */
133
134/**
135 * \brief starts a new RPC to the inter Xeon Phi connection
136 *
137 * \param mi    Xeon Phi message info
138 *
139 * \returns 1 if the RPC transaction could be started
140 *          0 if there was already a transaction in process
141 */
142static inline uint8_t rpc_start(struct msg_info *mi)
143{
144    if (!mi->wait_reply) {
145        mi->wait_reply = 0x1;
146        return 1;
147    }
148    return 0;
149}
150
151/**
152 * \brief waits until the started transaction is finished
153 *
154 * \param mi    Xeon Phi message info
155 */
156static inline void rpc_wait_done(struct msg_info *mi)
157{
158
159    while (mi->wait_reply) {
160#ifndef __k1om__
161
162        struct xnode *node = mi->binding->st;
163
164        errval_t err;
165        uint32_t data = 0x0;
166        uint32_t serial_recv = 0xF;
167        while (serial_recv--) {
168            data |= xeon_phi_serial_handle_recv(node->local);
169        }
170
171        err = event_dispatch_non_block(get_default_waitset());
172        switch (err_no(err)) {
173            case SYS_ERR_OK:
174            break;
175            case LIB_ERR_NO_EVENT:
176            if (!data) {
177                thread_yield();
178            }
179            break;
180            default:
181            USER_PANIC_ERR(err, "in event dispatch\n");
182            break;
183        }
184
185#else
186        messages_wait_and_handle_next();
187#endif
188    }
189}
190
191/**
192 * \brief signals the completion of the RPC
193 *
194 * \param mi    Xeon Phi message info
195 */
196static inline void rpc_done(struct msg_info *mi)
197{
198    mi->wait_reply = 0x0;
199}
200
201static struct txq_msg_st *rpc_preamble(struct msg_info *mi)
202{
203    assert(mi);
204
205    if (mi->binding == NULL) {
206        assert(!"NYI");
207    }
208
209    if (!rpc_start(mi)) {
210        XINTER_DEBUG("waiting until previous rpc is finished\n");
211        rpc_wait_done(mi);
212        rpc_start(mi);
213    }
214
215    mi->rpc_err = SYS_ERR_OK;
216    mi->rpc_data = 0x0;
217
218    struct txq_msg_st *msg_st = txq_msg_st_alloc(&mi->queue);
219    if (msg_st == NULL) {
220        rpc_done(mi);
221    }
222
223    msg_st->cleanup = NULL;
224
225    return msg_st;
226}
227
228/*
229 * ----------------------------------------------------------------------------
230 * Helper functions
231 * ----------------------------------------------------------------------------
232 */
233static errval_t spawn_cmdline_extract_argv(char *cmdline,
234                                           size_t cmdlen,
235                                           char *argv[],
236                                           uint8_t argcmax)
237{
238       int i = 0;
239       size_t pos = 0;
240       while (pos < cmdlen && i < argcmax) {
241           argv[i++] = &cmdline[pos];
242           char *end = memchr(&cmdline[pos], '\0', cmdlen - pos);
243           if (end == NULL) {
244               return SPAWN_ERR_GET_CMDLINE_ARGS;
245
246           }
247           pos = end - cmdline + 1;
248       }
249       assert(i <= argcmax);
250       argv[i] = NULL;
251
252    return SYS_ERR_OK;
253}
254
255/*
256 * ----------------------------------------------------------------------------
257 * Message Send Handlers
258 * ----------------------------------------------------------------------------
259 */
260
261#ifdef __k1om__
262
263static errval_t domain_wait_call_tx(struct txq_msg_st *msg_st)
264{
265    struct interphi_msg_st *st = (struct interphi_msg_st *) msg_st;
266
267    size_t length = strlen(st->args.domain.name) + 1;
268
269    return interphi_domain_wait_call__tx(msg_st->queue->binding, TXQCONT(msg_st),
270                                         st->args.domain.name, length,
271                                         st->args.domain.state);
272}
273
274#else
275
276static errval_t domain_wait_response_tx(struct txq_msg_st *msg_st)
277{
278    struct interphi_msg_st *st = (struct interphi_msg_st *) msg_st;
279
280    return interphi_domain_wait_response__tx(msg_st->queue->binding,
281                    TXQCONT(msg_st),
282                    st->args.domain.domid,
283                    st->args.domain.state,
284                    msg_st->err);
285}
286#endif
287
288#ifdef __k1om__
289
290static errval_t domain_lookup_call_tx(struct txq_msg_st *msg_st)
291{
292    struct interphi_msg_st *st = (struct interphi_msg_st *) msg_st;
293
294    size_t length = strlen(st->args.domain.name) + 1;
295
296    return interphi_domain_lookup_call__tx(msg_st->queue->binding,
297                                           TXQCONT(msg_st), st->args.domain.name,
298                                           length);
299}
300
301#else
302
303static errval_t domain_lookup_response_tx(struct txq_msg_st *msg_st)
304{
305    struct interphi_msg_st *st = (struct interphi_msg_st *) msg_st;
306
307    return interphi_domain_lookup_response__tx(msg_st->queue->binding,
308                    TXQCONT(msg_st),
309                    st->args.domain.domid, msg_st->err);
310}
311
312#endif
313
314#ifdef __k1om__
315
316static errval_t domain_register_call_tx(struct txq_msg_st *msg_st)
317{
318    struct interphi_msg_st *st = (struct interphi_msg_st *) msg_st;
319
320    size_t length = strlen(st->args.domain.name) + 1;
321
322    return interphi_domain_register_call__tx(msg_st->queue->binding,
323                                             TXQCONT(msg_st),
324                                             st->args.domain.name, length,
325                                             st->args.domain.domid);
326}
327
328#else
329
330static errval_t domain_register_response_tx(struct txq_msg_st *msg_st)
331{
332    return interphi_domain_register_response__tx(msg_st->queue->binding,
333                    TXQCONT(msg_st), SYS_ERR_OK);
334}
335
336#endif
337
338static errval_t spawn_response_tx(struct txq_msg_st *msg_st)
339{
340    struct interphi_msg_st *st = (struct interphi_msg_st *) msg_st;
341
342    return interphi_spawn_response__tx(msg_st->queue->binding, TXQCONT(msg_st),
343                                       st->args.spawn_reply.domainid, msg_st->err);
344}
345
346static errval_t spawn_call_tx(struct txq_msg_st *msg_st)
347{
348    struct interphi_msg_st *st = (struct interphi_msg_st *) msg_st;
349
350    return interphi_spawn_call__tx(msg_st->queue->binding, TXQCONT(msg_st),
351                                   st->args.spawn_call.core,
352                                   st->args.spawn_call.cmdline,
353                                   st->args.spawn_call.cmdlen,
354                                   st->args.spawn_call.flags);
355}
356
357static errval_t spawn_with_cap_response_tx(struct txq_msg_st *msg_st)
358{
359    struct interphi_msg_st *st = (struct interphi_msg_st *) msg_st;
360
361    return interphi_spawn_with_cap_response__tx(msg_st->queue->binding,
362                                                TXQCONT(msg_st),
363                                                st->args.spawn_reply.domainid,
364                                                msg_st->err);
365}
366
367static errval_t spawn_with_cap_call_tx(struct txq_msg_st *msg_st)
368{
369    struct interphi_msg_st *st = (struct interphi_msg_st *) msg_st;
370
371    return interphi_spawn_with_cap_call__tx(msg_st->queue->binding,
372                                            TXQCONT(msg_st),
373                                            st->args.spawn_call.core,
374                                            st->args.spawn_call.cmdline,
375                                            st->args.spawn_call.cmdlen,
376                                            st->args.spawn_call.flags,
377                                            st->args.spawn_call.cap_base,
378                                            st->args.spawn_call.cap_size_bits);
379}
380
381static errval_t kill_response_tx(struct txq_msg_st *msg_st)
382{
383    return interphi_kill_response__tx(msg_st->queue->binding, TXQCONT(msg_st),
384                                      msg_st->err);
385}
386
387static errval_t kill_call_tx(struct txq_msg_st *msg_st)
388{
389    struct interphi_msg_st *st = (struct interphi_msg_st *) msg_st;
390
391    return interphi_kill_call__tx(msg_st->queue->binding, TXQCONT(msg_st),
392                                  st->args.kill.domainid);
393}
394
395static errval_t bootstrap_response_tx(struct txq_msg_st *msg_st)
396{
397    return interphi_bootstrap_response__tx(msg_st->queue->binding,
398                                           TXQCONT(msg_st), msg_st->err);
399}
400
401static errval_t bootstrap_call_tx(struct txq_msg_st *msg_st)
402{
403    struct interphi_msg_st *st = (struct interphi_msg_st *) msg_st;
404
405    return interphi_bootstrap_call__tx(msg_st->queue->binding, TXQCONT(msg_st),
406                                       st->args.bootstrap.base,
407                                       st->args.bootstrap.offset,
408                                       st->args.bootstrap.bits,
409                                       st->args.bootstrap.xid,
410                                       st->args.bootstrap.is_client);
411}
412
413static errval_t chan_open_call_tx(struct txq_msg_st *msg_st)
414{
415    struct interphi_msg_st *st = (struct interphi_msg_st *) msg_st;
416
417    return interphi_chan_open_call__tx(msg_st->queue->binding, TXQCONT(msg_st),
418                                       st->args.open.source, st->args.open.target,
419                                       st->args.open.usrdata,
420                                       st->args.open.msgbase,
421                                       st->args.open.msgbits, st->args.open.type);
422}
423
424static errval_t chan_open_response_tx(struct txq_msg_st *msg_st)
425{
426    return interphi_chan_open_response__tx(msg_st->queue->binding,
427                                           TXQCONT(msg_st), msg_st->err);
428}
429
430static errval_t alloc_mem_call_tx(struct txq_msg_st *msg_st)
431{
432    struct interphi_msg_st *st = (struct interphi_msg_st *) msg_st;
433    return interphi_alloc_mem_call__tx(msg_st->queue->binding, TXQCONT(msg_st),
434                                       st->args.alloc.base, st->args.alloc.bytes);
435}
436
437static errval_t alloc_mem_response_tx(struct txq_msg_st *msg_st)
438{
439    struct interphi_msg_st *st = (struct interphi_msg_st *) msg_st;
440    return interphi_alloc_mem_response__tx(msg_st->queue->binding, TXQCONT(msg_st),
441                                           st->args.alloc.base, st->args.alloc.bytes,
442                                           st->args.alloc.err);
443}
444
445
446/*
447 * ----------------------------------------------------------------------------
448 * Message Callbacks
449 * ----------------------------------------------------------------------------
450 */
451
452static void domain_wait_call_rx(struct interphi_binding *_binding,
453                                const char *name,
454                                size_t length,
455                                uintptr_t state)
456{
457#ifdef __k1om__
458    USER_PANIC("domain_wait_call_rx: not supported on the Xeon Phi\n");
459#else
460    XINTER_DEBUG("domain_wait_call_rx: {%s}\n", name);
461
462    struct xnode *local_node = _binding->st;
463
464    struct xeon_phi *phi = local_node->local;
465    assert(phi);
466
467    struct txq_msg_st *msg_st = txq_msg_st_alloc(&local_node->msg->queue);
468    if (msg_st == NULL) {
469        USER_PANIC("ran out of reply state resources\n");
470    }
471
472    msg_st->send = domain_wait_response_tx;
473    msg_st->cleanup = NULL;
474
475    struct interphi_msg_st *st = (struct interphi_msg_st *) msg_st;
476
477    st->args.domain.state = state;
478
479    msg_st->err = domain_wait(name, local_node, (void *)state, &st->args.domain.domid);
480    switch(err_no(msg_st->err)) {
481        case SYS_ERR_OK:
482            /* there was a record, reply */
483            txq_send(msg_st);
484            break;
485        case OCT_ERR_NO_RECORD:
486            /* trigger installed */
487            txq_msg_st_free(msg_st);
488            break;
489        default:
490            /* error condition */
491            txq_send(msg_st);
492        break;
493    }
494#endif
495}
496
497static void domain_wait_response_rx(struct interphi_binding *_binding,
498                                    xphi_dom_id_t domain,
499                                    uintptr_t state,
500                                    errval_t msgerr)
501{
502#ifdef __k1om__
503    XINTER_DEBUG("domain_wait_response_rx: domid:%lx, st:%p,  %s\n", domain,
504                 (void * )state, err_getstring(msgerr));
505
506    struct xphi_svc_st *st = (struct xphi_svc_st *) state;
507
508    xeon_phi_service_domain_wait_response(st, msgerr, domain);
509#else
510    USER_PANIC("domain_wait_call_rx: not supported on the host\n");
511#endif
512}
513
514static void domain_lookup_call_rx(struct interphi_binding *_binding,
515                                  const char *name,
516                                  size_t length)
517{
518#ifdef __k1om__
519    USER_PANIC("domain_lookup_call_rx: not supported on the Xeon Phi\n");
520#else
521    XINTER_DEBUG("domain_lookup_call_rx: {%s}\n", name);
522
523    struct xnode *local_node = _binding->st;
524
525    struct xeon_phi *phi = local_node->local;
526    assert(phi);
527
528    struct txq_msg_st *msg_st = txq_msg_st_alloc(&local_node->msg->queue);
529    if (msg_st == NULL) {
530        USER_PANIC("ran out of reply state resources\n");
531    }
532
533    msg_st->send = domain_lookup_response_tx;
534    msg_st->cleanup = NULL;
535
536    struct interphi_msg_st *st = (struct interphi_msg_st *)msg_st;
537
538    msg_st->err = domain_lookup(name, &st->args.domain.domid);
539
540    txq_send(msg_st);
541#endif
542}
543
544static void domain_lookup_response_rx(struct interphi_binding *_binding,
545                                      xphi_dom_id_t domain,
546                                      errval_t msgerr)
547{
548#ifdef __k1om__
549    XINTER_DEBUG("domain_lookup_response_rx: %lx, %s\n", domain,
550                 err_getstring(msgerr));
551
552    struct xnode *local_node = _binding->st;
553
554    local_node->msg->rpc_err = msgerr;
555    rpc_done(local_node->msg);
556#else
557    USER_PANIC("domain_lookup_response_rx: not supported on the host\n");
558#endif
559}
560
561static void domain_register_call_rx(struct interphi_binding *_binding,
562                                    const char *name,
563                                    size_t length,
564                                    xphi_dom_id_t domid)
565{
566#ifdef __k1om__
567    /* register calls on the K1OM are not valid */
568    USER_PANIC("domain_register_call_rx: not supported on the Xeon Phi\n");
569#else
570    XINTER_DEBUG("domain_register_call_rx: {%s} @ domid:%lx\n", name, domid);
571
572    struct xnode *local_node = _binding->st;
573
574    struct xeon_phi *phi = local_node->local;
575    assert(phi);
576
577    struct txq_msg_st *msg_st = txq_msg_st_alloc(&local_node->msg->queue);
578    if (msg_st == NULL) {
579        USER_PANIC("ran out of reply state resources\n");
580    }
581
582    msg_st->err = SYS_ERR_OK;
583    msg_st->send = domain_register_response_tx;
584    msg_st->cleanup = NULL;
585
586    msg_st->err = domain_register(name, domid);
587
588    txq_send(msg_st);
589#endif
590}
591
592static void domain_register_response_rx(struct interphi_binding *_binding,
593                                        errval_t msgerr)
594{
595#ifdef __k1om__
596    XINTER_DEBUG("domain_register_response_rx:%s\n", err_getstring(msgerr));
597
598    struct xnode *local_node = _binding->st;
599
600    local_node->msg->rpc_err = msgerr;
601    rpc_done(local_node->msg);
602#else
603    USER_PANIC("domain_register_response_rx: not supported on the host\n");
604#endif
605}
606
607static void spawn_call_rx(struct interphi_binding *_binding,
608                          uint8_t core,
609                          const char *cmdline,
610                          size_t length,
611                          uint8_t flags)
612{
613    XINTER_DEBUG("spawn_call_rx: {%s} of length %lu, @ core:%u\n", cmdline,
614                 length, core);
615
616    struct xnode *local_node = _binding->st;
617
618    struct xeon_phi *phi = local_node->local;
619    assert(phi);
620
621    struct txq_msg_st *msg_st = txq_msg_st_alloc(&local_node->msg->queue);
622    if (msg_st == NULL) {
623        USER_PANIC("ran out of reply state resources\n");
624    }
625
626    msg_st->send = spawn_response_tx;
627    msg_st->cleanup = NULL;
628
629    char *argv[MAX_CMDLINE_ARGS+1];
630    msg_st->err = spawn_cmdline_extract_argv((CONST_CAST)cmdline, length, argv, MAX_CMDLINE_ARGS);
631    if (err_is_fail(msg_st->err)) {
632        txq_send(msg_st);
633        return;
634    }
635    argv[MAX_CMDLINE_ARGS] = NULL;
636
637    struct interphi_msg_st *st = (struct interphi_msg_st *) msg_st;
638    struct capref* domain = (struct capref*) malloc(sizeof(struct capref));
639
640    /*
641     * TODO: check if we have that core present...
642     */
643
644    msg_st->err = spawn_program(core, cmdline, argv, NULL, flags, domain);
645    if (err_is_ok(msg_st->err)) {
646        phi->current_key++;
647#ifdef __k1om__
648        uint8_t is_host = 0x0;
649#else
650        uint8_t is_host = 0x1;
651#endif
652        st->args.spawn_reply.domainid = xeon_phi_domain_build_id(phi->id, core,
653                                                                 is_host, phi->current_key);
654        collections_hash_insert(phi->did_to_cap, st->args.spawn_reply.domainid,  domain);
655    }
656    txq_send(msg_st);
657}
658
659static void spawn_response_rx(struct interphi_binding *_binding,
660                              uint64_t domainid,
661                              interphi_errval_t msgerr)
662{
663    XINTER_DEBUG("spawn_response_rx: %lu, %s\n", domainid, err_getstring(msgerr));
664
665    struct xnode *local_node = _binding->st;
666
667    local_node->msg->rpc_err = msgerr;
668    local_node->msg->rpc_data = domainid;
669    rpc_done(local_node->msg);
670}
671
672static void spawn_with_cap_call_rx(struct interphi_binding *_binding,
673                                   uint8_t core,
674                                   const char *cmdline,
675                                   size_t length,
676                                   uint8_t flags,
677                                   uint64_t cap_base,
678                                   uint8_t cap_size_bits)
679{
680    XINTER_DEBUG("spawn_with_cap_call_rx: {%s} of length %lu @ core:%u\n", cmdline,
681                 length, core);
682
683    struct xnode *local_node = _binding->st;
684
685    struct xeon_phi *phi = local_node->local;
686    assert(phi);
687
688    struct txq_msg_st *msg_st = txq_msg_st_alloc(&local_node->msg->queue);
689    if (msg_st == NULL) {
690        USER_PANIC("ran out of reply state resources\n");
691    }
692
693    msg_st->send = spawn_with_cap_response_tx;
694    msg_st->cleanup = NULL;
695
696    char *argv[MAX_CMDLINE_ARGS+1];
697    msg_st->err = spawn_cmdline_extract_argv((CONST_CAST)cmdline, length, argv, MAX_CMDLINE_ARGS);
698    if (err_is_fail(msg_st->err)) {
699        txq_send(msg_st);
700        return;
701    }
702    argv[MAX_CMDLINE_ARGS] = NULL;
703
704    struct interphi_msg_st *st = (struct interphi_msg_st *) msg_st;
705
706    struct capref cap;
707    msg_st->err = sysmem_cap_request(cap_base, cap_size_bits, &cap);
708    if (err_is_fail(msg_st->err)) {
709        txq_send(msg_st);
710        return;
711    }
712
713    XINTER_DEBUG("Creating ARGCN for the domain to be spawned\n");
714
715    struct capref argcn;
716    struct cnoderef argcnref;
717    msg_st->err = cnode_create_l2(&argcn, &argcnref);
718    if (err_is_fail(msg_st->err)) {
719        sysmem_cap_return(cap);
720        txq_send(msg_st);
721        return;
722    }
723    struct capref dst = {
724            .cnode = argcnref,
725            .slot = 0
726    };
727    cap_copy(dst, cap);
728
729    struct capref* domain = (struct capref*) malloc(sizeof(struct capref));
730    msg_st->err = spawn_program_with_caps(core, cmdline, argv, NULL, NULL_CAP,
731                                          argcn, flags, domain);
732    if (err_is_ok(msg_st->err)) {
733        phi->current_key++;
734#ifdef __k1om__
735        st->args.spawn_reply.domainid = xeon_phi_domain_build_id(
736                        disp_xeon_phi_id(), core, 0, phi->current_key);
737#else
738        st->args.spawn_reply.domainid = xeon_phi_domain_build_id(
739                        XEON_PHI_DOMAIN_HOST, core, 1, phi->current_key);
740#endif
741        collections_hash_insert(phi->did_to_cap, st->args.spawn_reply.domainid,  domain);
742    }
743
744    cap_destroy(argcn);
745
746    txq_send(msg_st);
747}
748
749static void spawn_with_cap_response_rx(struct interphi_binding *_binding,
750                                       uint64_t domainid,
751                                       interphi_errval_t msgerr)
752{
753    XINTER_DEBUG("spawn_with_cap_response_rx: %lu, %s\n", domainid,
754                 err_getstring(msgerr));
755
756    struct xnode *local_node = _binding->st;
757
758    local_node->msg->rpc_err = msgerr;
759    local_node->msg->rpc_data = domainid;
760    rpc_done(local_node->msg);
761}
762
763static void kill_call_rx(struct interphi_binding *_binding,
764                         uint64_t domainid)
765{
766    XINTER_DEBUG("kill_call_rx: %lu,\n", domainid);
767
768    struct xnode *local_node = _binding->st;
769
770    struct xeon_phi *phi = local_node->local;
771    assert(phi);
772
773    struct txq_msg_st *msg_st = txq_msg_st_alloc(&local_node->msg->queue);
774    if (msg_st == NULL) {
775        USER_PANIC("ran out of reply state resources\n");
776    }
777
778    msg_st->err = SYS_ERR_OK;
779    msg_st->send = kill_response_tx;
780    msg_st->cleanup = NULL;
781
782    struct capref* domain = (struct capref*) collections_hash_find(phi->did_to_cap, domainid);
783    assert(domain);
784
785    msg_st->err = spawn_kill(*domain);
786
787    txq_send(msg_st);
788}
789
790static void kill_response_rx(struct interphi_binding *_binding,
791                             interphi_errval_t msgerr)
792{
793    XINTER_DEBUG("kill_response_rx: %s\n", err_getstring(msgerr));
794
795    struct xnode *local_node = _binding->st;
796
797    local_node->msg->rpc_err = msgerr;
798
799    rpc_done(local_node->msg);
800}
801
802static void bootstrap_call_rx(struct interphi_binding *_binding,
803                              uint64_t base,
804                              uint64_t offset,
805                              uint8_t bits,
806                              uint8_t xid,
807                              uint8_t is_client)
808{
809    XINTER_DEBUG("bootstrap_call_rx: {%016lx, %02x} of:%016lx, xid:%u, c:%u\n",
810                 base, bits, offset, xid, is_client);
811
812    struct xnode *local_node = _binding->st;
813
814    struct xeon_phi *phi = local_node->local;
815    assert(phi);
816
817    struct txq_msg_st *msg_st = txq_msg_st_alloc(&local_node->msg->queue);
818    if (msg_st == NULL) {
819        USER_PANIC("ran out of reply state resources\n");
820    }
821
822    msg_st->err = SYS_ERR_OK;
823    msg_st->send = bootstrap_response_tx;
824    msg_st->cleanup = NULL;
825
826    struct xnode *node = &phi->topology[xid];
827    if (node->msg) {
828        XINTER_DEBUG("already established a connection to xid:%u\n", xid);
829        txq_send(msg_st);
830    }
831
832    struct capref msg_frame;
833    msg_st->err = sysmem_cap_request(base, bits, &msg_frame);
834    if (err_is_fail(msg_st->err)) {
835        txq_send(msg_st);
836        return;
837    }
838
839    smpt_set_coprocessor_offset(phi, xid, offset);
840
841    msg_st->err = interphi_init_xphi(xid, phi, msg_frame, is_client);
842
843    txq_send(msg_st);
844}
845
846static void bootstrap_response_rx(struct interphi_binding *_binding,
847                                  interphi_errval_t msgerr)
848{
849    XINTER_DEBUG("bootstrap_response_rx: %s\n", err_getstring(msgerr));
850
851    struct xnode *local_node = _binding->st;
852
853    local_node->msg->rpc_err = msgerr;
854
855    rpc_done(local_node->msg);
856}
857
858static void chan_open_call_rx(struct interphi_binding *_binding,
859                              uint64_t source_did,
860                              uint64_t target_did,
861                              uint64_t usrdata,
862                              uint64_t msgbase,
863                              uint8_t msgbits,
864                              uint8_t type)
865{
866    XINTER_DEBUG("chan_open_call_rx: %lx -> %lx\n", source_did, target_did);
867
868    struct xnode *local_node = _binding->st;
869
870    struct xeon_phi *phi = local_node->local;
871    assert(phi);
872
873    struct txq_msg_st *msg_st = txq_msg_st_alloc(&local_node->msg->queue);
874    if (msg_st == NULL) {
875        USER_PANIC("ran out of reply state resources\n");
876    }
877
878    msg_st->send = chan_open_response_tx;
879    msg_st->cleanup = NULL;
880
881    struct capref msgcap;
882
883    lpaddr_t offset = smpt_get_coprocessor_address(phi, local_node->id);
884
885    msgbase += offset;
886
887    XINTER_DEBUG("chan_open_call_rx: msgbase=%lx\n", msgbase);
888    if (msgbase < XEON_PHI_SYSMEM_BASE) {
889        struct mem_reg *mreg = allocated_mem;
890        while(mreg) {
891            XINTER_DEBUG("%lx %lx | %lx %lx\n", mreg->id.base, msgbase, mreg->id.bytes, (1UL << msgbits));
892            if (mreg->id.base == msgbase && mreg->id.bytes == (1UL << msgbits)) {
893                debug_printf("XXX FOUND THE REGION %lx\n", msgbase);
894                msgcap = mreg->cap;
895                break;
896            }
897            mreg = mreg->next;
898        }
899    } else {
900        msg_st->err = sysmem_cap_request(msgbase, msgbits, &msgcap);
901        if (err_is_fail(msg_st->err)) {
902            txq_send(msg_st);
903            return;
904        }
905    }
906
907    msg_st->err = xeon_phi_service_open_channel(msgcap, type, target_did,
908                                                source_did, usrdata);
909    if (err_is_fail(msg_st->err)) {
910        DEBUG_ERR( msg_st->err, "Failed to open the channel!\n");
911       // sysmem_cap_return(msgcap);
912    }
913
914    txq_send(msg_st);
915}
916
917static void chan_open_response_rx(struct interphi_binding *_binding,
918                                  errval_t msgerr)
919{
920    XINTER_DEBUG("chan_open_did_response_rx: %s\n", err_getstring(msgerr));
921
922    struct xnode *local_node = _binding->st;
923
924    local_node->msg->rpc_err = msgerr;
925
926    rpc_done(local_node->msg);
927}
928
929
930static void alloc_mem_call_rx(struct interphi_binding *_binding,
931                              uint64_t base, uint64_t bytes)
932{
933    XINTER_DEBUG("alloc_mem_call_rx: %lu\n", bytes);
934    errval_t msgerr;
935
936    struct xnode *local_node = _binding->st;
937
938    struct txq_msg_st *msg_st = txq_msg_st_alloc(&local_node->msg->queue);
939    if (msg_st == NULL) {
940        USER_PANIC("ran out of reply state resources\n");
941    }
942
943    struct mem_reg *mreg = calloc(1, sizeof(*mreg));
944    assert(mreg);
945
946    struct capref ramcap;
947    slot_alloc(&ramcap);
948
949    struct mem_binding * b = get_mem_client();
950    msg_st->err = b->rpc_tx_vtbl.allocate(b, log2ceil(bytes), base, base + bytes,
951                                  &msgerr, &ramcap);
952    if (err_is_fail(msg_st->err)) {
953        goto send_out;
954    }
955
956    msg_st->err = msgerr;
957    if (err_is_fail(msg_st->err)) {
958        goto send_out;
959    }
960
961    slot_alloc(&mreg->cap);
962
963    msg_st->err = cap_retype(mreg->cap, ramcap, 0, ObjType_Frame, bytes, 1);
964
965    errval_t err = frame_identify(mreg->cap, &mreg->id);
966    assert(err_is_ok(err));
967
968    struct interphi_msg_st *st = (struct interphi_msg_st*)msg_st;
969
970    mreg->next = allocated_mem;
971    allocated_mem = mreg;
972
973    msg_st->send = alloc_mem_response_tx;
974    msg_st->cleanup = NULL;
975    st->args.alloc.bytes = mreg->id.bytes;
976
977    #ifdef __k1om__
978    st->args.alloc.base =  mreg->id.base;
979    #else
980    USER_PANIC("TODO: convert address!");
981    #endif
982
983    send_out:
984    txq_send(msg_st);
985}
986
987static void alloc_mem_response_rx(struct interphi_binding *_binding,
988                                  uint64_t base, uint64_t bytes, errval_t msgerr)
989{
990    XINTER_DEBUG("alloc_mem_response_rx: %s\n", err_getstring(msgerr));
991
992    struct xnode *local_node = _binding->st;
993
994    local_node->msg->rpc_err = msgerr;
995    local_node->msg->rpc_data = base;
996    local_node->msg->rpc_data2 = bytes;
997
998    rpc_done(local_node->msg);
999}
1000
1001
1002struct interphi_rx_vtbl rx_vtbl = {
1003    .domain_lookup_call = domain_lookup_call_rx,
1004    .domain_lookup_response = domain_lookup_response_rx,
1005    .domain_wait_call = domain_wait_call_rx,
1006    .domain_wait_response = domain_wait_response_rx,
1007    .domain_register_call = domain_register_call_rx,
1008    .domain_register_response = domain_register_response_rx,
1009    .chan_open_call = chan_open_call_rx,
1010    .chan_open_response = chan_open_response_rx,
1011    .spawn_call = spawn_call_rx,
1012    .spawn_response = spawn_response_rx,
1013    .spawn_with_cap_call = spawn_with_cap_call_rx,
1014    .spawn_with_cap_response = spawn_with_cap_response_rx,
1015    .kill_call = kill_call_rx,
1016    .kill_response = kill_response_rx,
1017    .bootstrap_call = bootstrap_call_rx,
1018    .bootstrap_response = bootstrap_response_rx,
1019    .alloc_mem_call = alloc_mem_call_rx,
1020    .alloc_mem_response = alloc_mem_response_rx
1021};
1022
1023/*
1024 * ----------------------------------------------------------------------------
1025 * Flounder Connect / Accept Callbacks
1026 * ----------------------------------------------------------------------------
1027 */
1028
1029static void interphi_bind_cb(void *st,
1030                             errval_t err,
1031                             struct interphi_binding *_binding)
1032{
1033    XINTER_DEBUG("interphi_bind_cb: driver bound %p  %s\n", _binding,
1034                 err_getstring(err));
1035
1036    assert(_binding);
1037
1038    struct xnode *node = st;
1039
1040    _binding->rx_vtbl = rx_vtbl;
1041    _binding->st = st;
1042
1043    node->msg->binding = _binding;
1044
1045    txq_init(&node->msg->queue, _binding, _binding->waitset,
1046             (txq_register_fn_t) _binding->register_send,
1047             sizeof(struct interphi_msg_st));
1048
1049    node->state = XNODE_STATE_READY;
1050}
1051
1052static void interphi_connect_cb(void *st,
1053                                errval_t err,
1054                                struct interphi_binding *_binding)
1055{
1056    XINTER_DEBUG("interphi_connect_cb: client driver connected %p\n", _binding);
1057
1058    struct xnode *node = st;
1059
1060    _binding->rx_vtbl = rx_vtbl;
1061    _binding->st = st;
1062
1063    node->msg->binding = _binding;
1064
1065    txq_init(&node->msg->queue, _binding, _binding->waitset,
1066             (txq_register_fn_t) _binding->register_send,
1067             sizeof(struct interphi_msg_st));
1068
1069    node->state = XNODE_STATE_READY;
1070}
1071
1072/**
1073 * \brief waits for the client driver to connect
1074 *
1075 * \param phi Xeon Phi
1076 *
1077 * \return SYS_ERR_OK when then client driver successfully connected
1078 */
1079errval_t interphi_wait_for_client(struct xeon_phi *phi)
1080{
1081#ifndef __k1om__
1082    errval_t err;
1083
1084    XINTER_DEBUG("interphi_wait_for_client\n");
1085
1086    struct xnode *node = &phi->topology[phi->id];
1087
1088    while (node->state == XNODE_STATE_WAIT_CONNECTION) {
1089        uint32_t data = 0x0;
1090        uint32_t serial_recv = 0xF;
1091        while (serial_recv--) {
1092            data |= xeon_phi_serial_handle_recv(phi);
1093        }
1094
1095        err = event_dispatch_non_block(get_default_waitset());
1096        switch (err_no(err)) {
1097            case SYS_ERR_OK:
1098            break;
1099            case LIB_ERR_NO_EVENT:
1100            if (!data) {
1101                thread_yield();
1102            }
1103            break;
1104            default:
1105            return err;
1106            break;
1107        }
1108    }
1109#endif
1110    return SYS_ERR_OK;
1111
1112}
1113
1114/*
1115 * ----------------------------------------------------------------------------
1116 * Initialization
1117 * ----------------------------------------------------------------------------
1118 */
1119
1120/**
1121 * \brief initializes the messaging boostrap infrastructure between the
1122 *        two Xeon Phi cards
1123 *
1124 * \param phi the xeon phi to initialize the basic messaging bootstrap
1125 *
1126 * \return SYS_ERR_OK on success
1127 *         errval on failure
1128 */
1129errval_t interphi_init_xphi(uint8_t xphi,
1130                            struct xeon_phi *phi,
1131                            struct capref frame,
1132                            uint8_t is_client)
1133{
1134    errval_t err;
1135
1136    XINTER_DEBUG("initializing intra Xeon Phi [%u <-> %u] client=%u\n", phi->id,
1137                 xphi, is_client);
1138
1139    assert(xphi < XEON_PHI_NUM_MAX);
1140    assert(xphi != phi->id);
1141
1142    assert(phi->topology[xphi].msg == NULL);
1143
1144    struct msg_info *mi = calloc(1, sizeof(struct msg_info));
1145    if (mi == NULL) {
1146        return LIB_ERR_MALLOC_FAIL;
1147    }
1148
1149    size_t frame_size;
1150
1151    if (capref_is_null(frame)) {
1152        err = frame_alloc(&mi->frame, XEON_PHI_INTERPHI_FRAME_SIZE, &frame_size);
1153        if (err_is_fail(err)) {
1154            return err;
1155        }
1156    } else {
1157        mi->frame = frame;
1158    }
1159
1160    struct frame_identity id;
1161    err = frame_identify(mi->frame, &id);
1162    if (err_is_fail(err)) {
1163        cap_destroy(mi->frame);
1164        free(mi);
1165        return err;
1166    }
1167
1168    mi->is_client = is_client;
1169
1170    frame_size = id.bytes;
1171
1172#ifdef __k1om__
1173    /*
1174     * XXX: the host does not need to do this
1175     */
1176    void *addr;
1177    err = vspace_map_one_frame(&addr, frame_size, mi->frame, NULL, NULL);
1178    if (err_is_fail(err)) {
1179        cap_destroy(mi->frame);
1180        free(mi);
1181        return err;
1182    }
1183
1184    XINTER_DEBUG("Messaging frame mapped: [%016lx -> %016lx, size = %lx ]\n",
1185                 id.base, (uintptr_t )addr, frame_size);
1186
1187    mi->fi.outbufsize = (frame_size >> 1);
1188    mi->fi.inbufsize = (frame_size >> 1);
1189
1190    struct waitset *ws = get_default_waitset();
1191
1192    struct xnode *node = &phi->topology[xphi];
1193
1194    node->msg = mi;
1195    node->local = phi;
1196    node->state = XNODE_STATE_WAIT_CONNECTION;
1197
1198    if (mi->is_client) {
1199        mi->fi.inbuf = ((uint8_t*) addr) + mi->fi.inbufsize;
1200        mi->fi.outbuf = addr;
1201        mi->fi.sendbase = id.base;
1202
1203        XINTER_DEBUG("client mode: connecting to server. %s\n", __FUNCTION__);
1204        err = interphi_connect(&mi->fi, interphi_bind_cb, node,
1205                               ws, IDC_EXPORT_FLAGS_DEFAULT);
1206    } else {
1207        mi->fi.inbuf = addr;
1208        mi->fi.outbuf = ((uint8_t*) addr) + mi->fi.outbufsize;
1209        mi->fi.sendbase = id.base + mi->fi.outbufsize;
1210
1211        XINTER_DEBUG("server mode: accepting connections. %s\n", __FUNCTION__);
1212
1213        err = interphi_accept(&mi->fi, node, interphi_connect_cb,
1214                              ws, IDC_EXPORT_FLAGS_DEFAULT);
1215    }
1216    if (err_is_fail(err)) {
1217        vspace_unmap(addr);
1218        cap_destroy(mi->frame);
1219        free(mi);
1220        return err;
1221    }
1222
1223    if (mi->is_client) {
1224        XINTER_DEBUG("Waiting for connect callback...\n");
1225        while(node->state == XNODE_STATE_WAIT_CONNECTION) {
1226            messages_wait_and_handle_next();
1227        }
1228        XINTER_DEBUG("connected to pier.\n");
1229    }
1230
1231    phi->connected++;
1232
1233#else
1234    struct xnode *node = &phi->topology[xphi];
1235    lpaddr_t offset = ((node->apt_base >> 32) - ((node->apt_base >> 34)<<2))<<32;
1236    assert((1UL << log2ceil(id.bytes)) == id.bytes);
1237    err = interphi_bootstrap(phi, id.base, log2ceil(id.bytes), offset, xphi, mi->is_client);
1238    if (err_is_fail(err)) {
1239        free(mi);
1240        return err;
1241    }
1242
1243    XINTER_DEBUG("Local bootstrap succeeded. Sending to other node.\n");
1244
1245    err = service_bootstrap(phi, xphi, mi->frame);
1246    if (err_is_fail(err)) {
1247        XINTER_DEBUG("Could not initialize messaging\n");
1248        return err;
1249    }
1250#endif
1251
1252    return SYS_ERR_OK;
1253}
1254
1255#include <driverkit/hwmodel.h>
1256#include <driverkit/iommu.h>
1257#include <skb/skb.h>
1258
1259
1260/**
1261 * \brief initializes the communication between the host and the card Xeon Phi
1262 *        drivers using a bootstraped flounder channel
1263 *
1264 * \param phi   Xeon Phi to initialize
1265 *
1266 * \return SYS_ERR_OK on success
1267 *         errval on failure
1268 */
1269errval_t interphi_init(struct xeon_phi *phi,
1270                       struct capref frame)
1271{
1272    errval_t err;
1273
1274    assert(phi->msg == NULL);
1275
1276    struct msg_info *mi = calloc(1, sizeof(struct msg_info));
1277    if (mi == NULL) {
1278        return LIB_ERR_MALLOC_FAIL;
1279    }
1280
1281    size_t frame_size;
1282
1283    if (capref_is_null(frame)) {
1284#if defined(__k1om__) || !defined(XEON_PHI_USE_HW_MODEL)
1285        err = frame_alloc(&mi->frame, XEON_PHI_INTERPHI_FRAME_SIZE, &frame_size);
1286#else
1287        int32_t knc_socket_id;
1288        err = xeon_phi_hw_model_lookup_nodeids(phi->nodeid, &knc_socket_id, NULL, NULL, NULL, NULL, NULL);
1289        if(err_is_fail(err)){
1290            return err;
1291        }
1292        int32_t nodes[3];
1293        nodes[0] = knc_socket_id;
1294        nodes[1] = driverkit_hwmodel_get_my_node_id();
1295        nodes[2] = 0;
1296        int32_t dest_nodeid = driverkit_hwmodel_lookup_dram_node_id();
1297
1298        err =  driverkit_hwmodel_frame_alloc(&mi->frame, XEON_PHI_INTERPHI_FRAME_SIZE,
1299                                      dest_nodeid, nodes);
1300
1301        frame_size =XEON_PHI_INTERPHI_FRAME_SIZE;
1302#endif
1303        //err = frame_alloc(&mi->frame, XEON_PHI_INTERPHI_FRAME_SIZE, &frame_size);
1304        if (err_is_fail(err)) {
1305            return err;
1306        }
1307    } else {
1308        mi->frame = frame;
1309    }
1310
1311    struct frame_identity id;
1312    err = frame_identify(mi->frame, &id);
1313    if (err_is_fail(err)) {
1314        cap_destroy(mi->frame);
1315        free(mi);
1316        return err;
1317    }
1318
1319    frame_size = id.bytes;
1320
1321    void *addr;
1322    err = vspace_map_one_frame(&addr, frame_size, mi->frame, NULL, NULL);
1323    if (err_is_fail(err)) {
1324        cap_destroy(mi->frame);
1325        free(mi);
1326        return err;
1327    }
1328
1329    XINTER_DEBUG("Messaging frame mapped: [%016lx->%016lx, size = %lx]\n",
1330                 id.base, (uintptr_t )addr, frame_size);
1331
1332    mi->is_client = phi->is_client;
1333
1334    mi->fi.outbufsize = (frame_size >> 1);
1335    mi->fi.inbufsize = (frame_size >> 1);
1336
1337    struct waitset *ws = get_default_waitset();
1338
1339    phi->msg = mi;
1340
1341    phi->topology[phi->id].msg = mi;
1342    phi->topology[phi->id].local = phi;
1343    phi->topology[phi->id].state = XNODE_STATE_WAIT_CONNECTION;
1344
1345    if (phi->is_client) {
1346        mi->fi.inbuf = ((uint8_t*) addr) + mi->fi.inbufsize;
1347        mi->fi.outbuf = addr;
1348        mi->fi.sendbase = id.base;
1349
1350        XINTER_DEBUG("client mode: connecting to server. %s\n", __FUNCTION__);
1351
1352        err = interphi_connect(&mi->fi, interphi_bind_cb, &phi->topology[phi->id],
1353                               ws, IDC_EXPORT_FLAGS_DEFAULT);
1354    } else {
1355        mi->fi.inbuf = addr;
1356        mi->fi.outbuf = ((uint8_t*) addr) + mi->fi.outbufsize;
1357        mi->fi.sendbase = id.base + mi->fi.outbufsize;
1358
1359        XINTER_DEBUG("server mode: accepting connections. %s\n", __FUNCTION__);
1360
1361        err = interphi_accept(&mi->fi, &phi->topology[phi->id],
1362                              interphi_connect_cb, ws, IDC_EXPORT_FLAGS_DEFAULT);
1363    }
1364    if (err_is_fail(err)) {
1365        vspace_unmap(addr);
1366        cap_destroy(mi->frame);
1367        free(mi);
1368        return err;
1369    }
1370
1371    phi->connected = 1;
1372
1373    if (!phi->is_client) {
1374
1375        genpaddr_t xphi_local_addr;
1376#ifdef XEON_PHI_USE_HW_MODEL
1377        err = xeon_phi_hw_model_query_and_config(phi, mi->frame, &xphi_local_addr, NULL);
1378        if (err_is_fail(err)) {
1379            vspace_unmap(addr);
1380            cap_destroy(mi->frame);
1381            free(mi);
1382        }
1383#else
1384        xphi_local_addr = id.base;
1385#endif
1386        struct xeon_phi_boot_params *bp;
1387        bp = (struct xeon_phi_boot_params *) (phi->apt.vbase + phi->os_offset);
1388        bp->msg_base = xphi_local_addr;
1389        assert((1UL << log2ceil(id.bytes)) == id.bytes);
1390        bp->msg_size_bits = log2ceil(id.bytes);
1391    }
1392
1393    collections_hash_create(&phi->did_to_cap, NULL);
1394    phi->current_key = 0;
1395
1396    return SYS_ERR_OK;
1397}
1398
1399/*
1400 * ----------------------------------------------------------------------------
1401 * Message Sending
1402 * ----------------------------------------------------------------------------
1403 */
1404
1405/**
1406 * \brief sends a bootstrap request to the Xeon Phi client driver
1407 *
1408 * \param phi        Xeon Phi
1409 * \param frame_base base address of the messaging frame
1410 * \param frame_bits size of the messaging frame in bits
1411 * \param offset     offset into the SMPT
1412 * \param xid        ID of the other Xeon Phi
1413 * \param is_client  flag indicating if this is the client of the connection
1414 *
1415 * \returns SYS_ERR_OK on success
1416 *          errval on faiure
1417 */
1418errval_t interphi_bootstrap(struct xeon_phi *phi,
1419                            lpaddr_t frame_base,
1420                            uint8_t frame_bits,
1421                            lpaddr_t offset,
1422                            uint8_t xid,
1423                            uint8_t is_client)
1424{
1425#ifdef __k1om__
1426    USER_PANIC("This function should not be called on the Xeon Phi\n");
1427#endif
1428
1429    XINTER_DEBUG("sending bootstrap to card. [%u] client:%u\n", xid, is_client);
1430
1431    struct msg_info *mi = phi->msg;
1432
1433    struct txq_msg_st *msg_st = rpc_preamble(mi);
1434    if (msg_st == NULL) {
1435        return LIB_ERR_MALLOC_FAIL;
1436    }
1437
1438    msg_st->send = bootstrap_call_tx;
1439
1440    struct interphi_msg_st *svc_st = (struct interphi_msg_st *) msg_st;
1441
1442    svc_st->args.bootstrap.xid = xid;
1443    svc_st->args.bootstrap.offset = offset;
1444    svc_st->args.bootstrap.is_client = is_client;
1445    svc_st->args.bootstrap.base = frame_base;
1446    svc_st->args.bootstrap.bits = frame_bits;
1447
1448    txq_send(msg_st);
1449
1450    rpc_wait_done(phi->msg);
1451
1452    return phi->msg->rpc_err;
1453}
1454
1455/**
1456 * \brief sends a spawn request to the Xeon Phi driver
1457 *
1458 * \param node      Xeon Phi Node
1459 * \param core      which core to spawn the domain on
1460 * \param cmdline   Commandline of the domain to spawn (marshalled)
1461 * \param cmdlen    length of the command line
1462 * \param domain    Domain identifier returned
1463 *
1464 * \returns SYS_ERR_OK on success
1465 *          errval on faiure
1466 */
1467errval_t interphi_spawn(struct xnode *node,
1468                        uint8_t core,
1469                        char *cmdline,
1470                        size_t cmdlen,
1471                        uint8_t flags,
1472                        uint64_t *domain)
1473{
1474    XINTER_DEBUG("spawning %s on core %u\n", cmdline, core);
1475    struct msg_info *mi = node->msg;
1476
1477    struct txq_msg_st *msg_st = rpc_preamble(mi);
1478    if (msg_st == NULL) {
1479        return LIB_ERR_MALLOC_FAIL;
1480    }
1481
1482    msg_st->send = spawn_call_tx;
1483
1484    struct interphi_msg_st *svc_st = (struct interphi_msg_st *) msg_st;
1485
1486    svc_st->args.spawn_call.cmdline = cmdline;
1487    svc_st->args.spawn_call.cmdlen = cmdlen;
1488    svc_st->args.spawn_call.core = core;
1489    svc_st->args.spawn_call.flags = flags;
1490
1491    txq_send(msg_st);
1492
1493    rpc_wait_done(node->msg);
1494
1495    if (err_is_ok(node->msg->rpc_err)) {
1496        if (domain) {
1497            *domain = node->msg->rpc_data;
1498        }
1499    }
1500
1501    return node->msg->rpc_err;
1502}
1503
1504/**
1505 * \brief sends a spawn request to the Xeon Phi driver
1506 *
1507 * \param node      Xeon Phi Node
1508 * \param core      which core to spawn the domain on
1509 * \param cmdline   Commandline of the domain to spawn (marshalled args)
1510 * \param cmdlen    length of the cmd line
1511 * \param cap       Cap to hand over to the domain at boot
1512 * \param domain    Domain identifier returned
1513 *
1514 * \returns SYS_ERR_OK on success
1515 *          errval on faiure
1516 */
1517errval_t interphi_spawn_with_cap(struct xnode *node,
1518                                 uint8_t core,
1519                                 char *cmdline,
1520                                 size_t cmdlen,
1521                                 uint8_t flags,
1522                                 struct capref cap,
1523                                 uint64_t *domain)
1524{
1525    errval_t err;
1526    struct msg_info *mi = node->msg;
1527
1528    XINTER_DEBUG("spawning %s with cap on core %u\n", cmdline, core);
1529
1530    struct frame_identity id;
1531    err = frame_identify(cap, &id);
1532    if (err_is_fail(err)) {
1533        return err;
1534    }
1535
1536    struct txq_msg_st *msg_st = rpc_preamble(mi);
1537    if (msg_st == NULL) {
1538        return LIB_ERR_MALLOC_FAIL;
1539    }
1540
1541    msg_st->send = spawn_with_cap_call_tx;
1542
1543    struct interphi_msg_st *svc_st = (struct interphi_msg_st *) msg_st;
1544
1545    svc_st->args.spawn_call.cmdline = cmdline;
1546    svc_st->args.spawn_call.cmdlen = cmdlen;
1547    svc_st->args.spawn_call.core = core;
1548    svc_st->args.spawn_call.flags = flags;
1549    assert((1UL << log2ceil(id.bytes)) == id.bytes);
1550    svc_st->args.spawn_call.cap_size_bits = log2ceil(id.bytes);
1551
1552#ifdef __k1om__
1553    svc_st->args.spawn_call.cap_base = id.base;
1554#else
1555    err = xeon_phi_hw_model_query_and_config(node->local, cap,
1556                                             &svc_st->args.spawn_call.cap_base, NULL);
1557    if (err_is_fail(err)) {
1558        rpc_done(node->msg);
1559        txq_msg_st_free(msg_st);
1560        return err;
1561    }
1562#endif
1563
1564    txq_send(msg_st);
1565
1566    rpc_wait_done(node->msg);
1567
1568    if (err_is_ok(node->msg->rpc_err)) {
1569        if (domain) {
1570            *domain = node->msg->rpc_data;
1571        }
1572    }
1573
1574    return node->msg->rpc_err;
1575}
1576
1577/**
1578 * \brief sends a kill request for a domain
1579 *
1580 * \param node      Target Xeon Phi node
1581 * \param domain    Domain identifier
1582 *
1583 * \returns SYS_ERR_OK on success
1584 *          errval on failure
1585 */
1586errval_t interphi_kill(struct xnode *node,
1587                       xphi_dom_id_t domain)
1588{
1589    XINTER_DEBUG("sending kill signal for domain:%lu\n", domain);
1590
1591    struct msg_info *mi = node->msg;
1592
1593    struct txq_msg_st *msg_st = rpc_preamble(mi);
1594    if (msg_st == NULL) {
1595        return LIB_ERR_MALLOC_FAIL;
1596    }
1597
1598    msg_st->send = kill_call_tx;
1599
1600    struct interphi_msg_st *svc_st = (struct interphi_msg_st *) msg_st;
1601
1602    svc_st->args.kill.domainid = domain;
1603
1604    txq_send(msg_st);
1605
1606    rpc_wait_done(mi);
1607
1608    return mi->rpc_err;
1609}
1610
1611/**
1612 * \brief sends a channel open messages to another Xeon Phi driver
1613 *
1614 * \param node      Xeon Phi Node to send the message to
1615 * \param target    target domain id
1616 * \param source    source domain id
1617 * \param usedata   usr specified data
1618 * \param msgframe  capability of the messaging frame
1619 * \param type      Channel type
1620 *
1621 * \returns SYS_ERR_OK on success
1622 */
1623errval_t interphi_chan_open(struct xnode *node,
1624                            xphi_dom_id_t target,
1625                            xphi_dom_id_t source,
1626                            uint64_t usrdata,
1627                            struct capref msgframe,
1628                            xphi_chan_type_t type)
1629{
1630    errval_t err;
1631
1632    XINTER_DEBUG("sending channel open to domain {%lx}\n", target);
1633
1634    struct msg_info *mi = node->msg;
1635
1636    struct frame_identity id;
1637    err = frame_identify(msgframe, &id);
1638    if (err_is_fail(err)) {
1639        return err;
1640    }
1641
1642    struct txq_msg_st *msg_st = rpc_preamble(mi);
1643    if (msg_st == NULL) {
1644        return LIB_ERR_MALLOC_FAIL;
1645    }
1646
1647    struct interphi_msg_st *svc_st = (struct interphi_msg_st *) msg_st;
1648
1649    #ifndef __k1om__
1650    int32_t nodeid;
1651    err = xeon_phi_hw_model_lookup_nodeids(node->local->nodeid, &nodeid,
1652                                           NULL, NULL, NULL, NULL, NULL);
1653    if (err_is_fail(err)) {
1654        rpc_done(node->msg);
1655        txq_msg_st_free(msg_st);
1656        return err;
1657    }
1658
1659    int32_t inodeid_mem = driverkit_hwmodel_lookup_pcibus_node_id();
1660
1661    err = driverkit_hwmodel_get_map_conf_addr(inodeid_mem, id.base, id.bytes, nodeid, NULL, 0,
1662                                         &svc_st->args.open.msgbase);
1663    if (err_is_fail(err)) {
1664        rpc_done(node->msg);
1665        txq_msg_st_free(msg_st);
1666        return err;
1667    }
1668    #else
1669    svc_st->args.open.msgbase = id.base;
1670    #endif
1671
1672    assert((1UL << log2ceil(id.bytes)) == id.bytes);
1673    svc_st->args.open.msgbits = log2ceil(id.bytes);
1674    svc_st->args.open.source = source;
1675    svc_st->args.open.usrdata = usrdata;
1676    svc_st->args.open.type = type;
1677
1678    if (target) {
1679        msg_st->send = chan_open_call_tx;
1680        svc_st->args.open.target = target;
1681    } else {
1682        rpc_done(node->msg);
1683        txq_msg_st_free(msg_st);
1684        return -1;
1685    }
1686
1687    txq_send(msg_st);
1688
1689    rpc_wait_done(mi);
1690
1691    return mi->rpc_err;
1692}
1693
1694/**
1695 * \brief registers a ready domain with the Xeon Phi Domain Service
1696 *
1697 * \param node  Xeon Phi Node to send the message to
1698 * \param name  Name to register
1699 * \param domid Xeon Phi Domain ID
1700 *
1701 * \returns SYS_ERR_OK on success
1702 *          errval on error
1703 */
1704errval_t interphi_domain_register(struct xnode *node,
1705                                  const char *name,
1706                                  xphi_dom_id_t domid)
1707{
1708#ifdef __k1om__
1709    XINTER_DEBUG("domain register {%s} with domainid:%lx @ xnode:%u\n", name,
1710                 domid, node->id);
1711
1712    assert(node->msg);
1713
1714    struct msg_info *mi = node->msg;
1715
1716    struct txq_msg_st *msg_st = rpc_preamble(mi);
1717    if (msg_st == NULL) {
1718        return LIB_ERR_MALLOC_FAIL;
1719    }
1720    msg_st->send = domain_register_call_tx;
1721
1722    struct interphi_msg_st *svc_st = (struct interphi_msg_st *) msg_st;
1723
1724    svc_st->args.domain.domid = domid;
1725    svc_st->args.domain.name = name;
1726
1727    txq_send(msg_st);
1728
1729    rpc_wait_done(mi);
1730
1731    return mi->rpc_err;
1732#else
1733    USER_PANIC("interphi_domain_lookup: not supporte on host.\n");
1734
1735    return SYS_ERR_OK;
1736#endif
1737}
1738
1739/**
1740 * \brief checks if a domain is running and returns its domain id if it is.
1741 *
1742 * \param node  Xeon Phi Node to send the message to
1743 * \param name  Name of the Domain
1744 * \param domid returned Xeon Phi Domain ID
1745 *
1746 * \returns SYS_ERR_OK on success
1747 *          errval on error
1748 */
1749errval_t interphi_domain_lookup(struct xnode *node,
1750                                char *name,
1751                                xphi_dom_id_t *retdomid)
1752{
1753#ifdef __k1om__
1754    XINTER_DEBUG("domain lookup {%s} @ xnode:%u\n", name, node->id);
1755
1756    struct msg_info *mi = node->msg;
1757
1758    struct txq_msg_st *msg_st = rpc_preamble(mi);
1759    if (msg_st == NULL) {
1760        return LIB_ERR_MALLOC_FAIL;
1761    }
1762
1763    msg_st->send = domain_lookup_call_tx;
1764
1765    struct interphi_msg_st *svc_st = (struct interphi_msg_st *) msg_st;
1766
1767    svc_st->args.domain.name = name;
1768
1769    txq_send(msg_st);
1770
1771    rpc_wait_done(mi);
1772
1773    return mi->rpc_err;
1774#else
1775    USER_PANIC("interphi_domain_lookup: not supporte on host.\n");
1776
1777    return SYS_ERR_OK;
1778#endif
1779}
1780
1781/**
1782 * \brief checks if a domain is running and installs a trigger to reply
1783 *
1784 * \param node  Xeon Phi Node to send the message to
1785 * \param name  Name of the Domain
1786 * \param state user state
1787 *
1788 * \returns SYS_ERR_OK on success
1789 *          errval on error
1790 */
1791errval_t interphi_domain_wait(struct xnode *node,
1792                              char *name,
1793                              void *state)
1794{
1795#ifdef __k1om__
1796    XINTER_DEBUG("domain wait {%s} @ xnode:%u\n", name, node->id);
1797
1798    assert(node->msg);
1799
1800    struct msg_info *mi = node->msg;
1801    if (mi->binding == NULL) {
1802        assert(!"NYI");
1803    }
1804
1805    struct txq_msg_st *msg_st = txq_msg_st_alloc(&mi->queue);
1806    if (msg_st == NULL) {
1807        rpc_done(node->msg);
1808        return LIB_ERR_MALLOC_FAIL;
1809    }
1810
1811    msg_st->send = domain_wait_call_tx;
1812    msg_st->cleanup = NULL;
1813
1814    struct interphi_msg_st *svc_st = (struct interphi_msg_st *) msg_st;
1815
1816    svc_st->args.domain.name = name;
1817    svc_st->args.domain.state = (uintptr_t) state;
1818
1819    txq_send(msg_st);
1820#else
1821    USER_PANIC("interphi_domain_wait: not supporte on host\n");
1822#endif
1823    return SYS_ERR_OK;
1824}
1825
1826/**
1827 * \brief sends a reply when the Octopus trigger fired
1828 *
1829 * \param node  Xeon Phi Node
1830 * \param domid Xeon Phi Domain ID
1831 * \param err   Outcome of the reply
1832 * \param state State pointer supplied by the card.
1833 *
1834 * \returns SYS_ERR_OK on success
1835 */
1836errval_t interphi_domain_wait_reply(struct xnode *node,
1837                                    errval_t err,
1838                                    void *state,
1839                                    xphi_dom_id_t domid)
1840{
1841#ifndef __k1om__
1842    XINTER_DEBUG("domain interphi_domain_wait_reply domid:%lx @ xnode:%u, st:%p\n",
1843                    domid, node->id, state);
1844
1845    struct msg_info *mi = node->msg;
1846    if (mi->binding == NULL) {
1847        assert(!"NYI");
1848    }
1849
1850    struct txq_msg_st *msg_st = txq_msg_st_alloc(&mi->queue);
1851    if (msg_st == NULL) {
1852        rpc_done(node->msg);
1853        return LIB_ERR_MALLOC_FAIL;
1854    }
1855
1856    msg_st->send = domain_wait_response_tx;
1857    msg_st->cleanup = NULL;
1858    msg_st->err = err;
1859
1860    struct interphi_msg_st *svc_st = (struct interphi_msg_st *) msg_st;
1861
1862    svc_st->args.domain.domid = domid;
1863    svc_st->args.domain.state = (uintptr_t)state;
1864
1865    txq_send(msg_st);
1866
1867#else
1868    USER_PANIC("interphi_domain_wait_reply: Not supported on Xeon Phi\n");
1869#endif
1870    return SYS_ERR_OK;
1871}
1872
1873
1874
1875errval_t interphi_alloc_mem(struct xnode *node,
1876                            uint64_t bytes,
1877                            struct capref *mem)
1878{
1879    errval_t err;
1880    struct msg_info *mi = node->msg;
1881
1882    XINTER_DEBUG("allocate memory %lu bytes\n", bytes);
1883
1884    int32_t nodeid, gddr_node;
1885    err = xeon_phi_hw_model_lookup_nodeids(node->local->nodeid, &nodeid,
1886                                           NULL, NULL, NULL, NULL, &gddr_node);
1887    if (err_is_fail(err)) {
1888        return err;
1889    }
1890
1891    int32_t nodes_reachable[] = {
1892            nodeid, driverkit_hwmodel_get_my_node_id(), 0
1893    };
1894
1895//    PHI NodeIds: KNC_SOCKET=7, SMPT=8, IOMMU=9, DMA=11, K1OM_CORE=10
1896
1897
1898    genpaddr_t addr;
1899    err = driverkit_hwmodel_allocate(bytes, gddr_node, nodes_reachable,
1900                                     21, &addr);
1901    if (err_is_fail(err)) {
1902        skb_execute("listing");
1903        DEBUG_ERR(err, "failed model query");
1904        return err;
1905    }
1906
1907    struct txq_msg_st *msg_st = rpc_preamble(mi);
1908    if (msg_st == NULL) {
1909        return LIB_ERR_MALLOC_FAIL;
1910    }
1911
1912
1913    struct interphi_msg_st *svc_st = (struct interphi_msg_st *) msg_st;
1914    msg_st->send = alloc_mem_call_tx;
1915    svc_st->args.alloc.bytes = bytes;
1916    svc_st->args.alloc.base = addr;
1917
1918    txq_send(msg_st);
1919
1920    rpc_wait_done(node->msg);
1921
1922
1923    if (err_is_ok(node->msg->rpc_err)) {
1924        if (mem) {
1925            XINTER_DEBUG("Obtain cap for 0x%lx of byte %lu\n", addr, bytes);
1926
1927            genpaddr_t hostbase;
1928            nodeid = driverkit_hwmodel_lookup_pcibus_node_id();
1929            err = driverkit_hwmodel_get_map_conf_addr(gddr_node, addr, bytes,
1930                                                      nodeid, NULL, 0,
1931                                                      &hostbase);
1932            if (err_is_fail(err)) {
1933                DEBUG_ERR(err, "failed model query");
1934                return err;
1935            }
1936            err = sysmem_cap_request(hostbase, log2ceil(bytes), mem);
1937            if (err_is_fail(err)) {
1938                DEBUG_ERR(err, "failed to get frame");
1939            }
1940            return err;
1941        }
1942    }
1943
1944    return node->msg->rpc_err;
1945}
1946