1/*
2 * Copyright (c) 2010, 2011, 2012, ETH Zurich.
3 * All rights reserved.
4 *
5 * This file is distributed under the terms in the attached LICENSE file.
6 * If you do not find this file, copies can be found by writing to:
7 * ETH Zurich D-INFK, CAB F.78, Universitaetstrasse 6, CH-8092 Zurich,
8 * Attn: Systems Group.
9 */
10
11#include <barrelfish/barrelfish.h>
12#include <barrelfish/nameservice_client.h>
13#include <flounder/flounder_txqueue.h>
14
15#include <xomp/xomp.h>
16#include <xomp_gateway.h>
17#include <xomp_debug.h>
18#include <bomp_internal.h>
19
20#include <if/xomp_gateway_defs.h>
21
22
23
24/**
25 * \brief represents a registered memory which can be obtained by the other
26 *        domains
27 */
28struct mem_reg
29{
30    struct mem_reg *next;           ///< next chunk of registered memory
31    lpaddr_t addr;                  ///< physical address of registered memory
32    struct capref frame;            ///< capability of the frame
33};
34
35/**
36 * \brief Message states for the TX queue
37 */
38struct xh_msg_st
39{
40    struct txq_msg_st common;       ///< common msg state
41    /* union of arguments */
42    struct capref frame;            ///< the replied frame
43};
44
45/// our token
46volatile uint64_t xgw_token = 0x0;
47
48/*
49 * ----------------------------------------------------------------------------
50 * XOMP helper memory management
51 * ----------------------------------------------------------------------------
52 *
53 * We are using a normal linked list here and put the new memory memory regions
54 * in front. When a new memory region is added, its likely that it will be
55 * requested soon. Once requested by all workers of the node, the likelyhood that
56 * it is requested later should be small
57 *
58 * Note: we are using virtual addresses here since when sharing a frame,
59 *       it should be mapped at the very same address for pointers to it
60 *       being valid in all worker domains
61 */
62
63/// list of registered memory
64static struct mem_reg *mem_regs;
65
66/**
67 * \brief allocates a new registered memory region and fills it
68 *
69 * \param addr  virtual mapped address of the region
70 * \param frame frame backing this memory
71 *
72 * \return pointer to the memory struct
73 *         NULL if we could not allocate memory
74 */
75static inline struct mem_reg *xgw_mem_alloc(lpaddr_t addr,
76                                            struct capref frame)
77{
78    struct mem_reg *mem = calloc(1, sizeof(*mem));
79    if (mem == NULL) {
80        return NULL;
81    }
82
83    mem->addr = addr;
84    mem->frame = frame;
85
86    return mem;
87}
88
89/**
90 * \brief looks up a memory region in the list of registered memory regions
91 *
92 * \param addr  the address to look for
93 *
94 * \return pointer ot the memory struct
95 *         NULL if there is no such memory region
96 */
97static struct mem_reg *xgw_do_lookup_mem(lpaddr_t addr)
98{
99    struct mem_reg *mem = mem_regs;
100    while (mem) {
101        if (mem->addr == addr) {
102            break;
103        }
104        mem = mem->next;
105    }
106    return mem;
107}
108
109/**
110 * \brief inserts a new memory region into the list
111 *
112 * \param addr  the virtual address of the region
113 * \param frame frame capability backing the address
114 *
115 * \return pointer to the newly allocated memory region
116 *         NULL if there was a failure
117 */
118static struct mem_reg *xgw_do_insert_mem(lpaddr_t addr,
119                                         struct capref frame)
120{
121    struct mem_reg *new_mem = xgw_mem_alloc(addr, frame);
122    if (new_mem == NULL) {
123        return NULL;
124    }
125
126    if (mem_regs) {
127        new_mem->next = mem_regs;
128        mem_regs = new_mem;
129    } else {
130        mem_regs = new_mem;
131    }
132
133    return new_mem;
134}
135
136/**
137 * \brief registers a new memory region that it can be requested lateron
138 *
139 * \param addr  the virtual address of the region
140 * \param frame frame capability backing the address
141 *
142 * \return SYS_ERR_OK on success
143 *         LIB_ERR_MALLOC_FAIL on failure
144 */
145errval_t xomp_gateway_mem_insert(struct capref frame,
146                                 lpaddr_t addr)
147{
148    XWG_DEBUG("inserting memory: [0x%016lx]", addr);
149    if (xgw_do_insert_mem(addr, frame)) {
150        return SYS_ERR_OK;
151    }
152
153    return LIB_ERR_MALLOC_FAIL;
154}
155
156/*
157 * ----------------------------------------------------------------------------
158 * XOMP helper send handlers
159 * ----------------------------------------------------------------------------
160 */
161
162static errval_t get_memory_response_tx(struct txq_msg_st *msg_st)
163{
164    struct xh_msg_st *st = (struct xh_msg_st *) msg_st;
165
166    return xomp_gateway_get_memory_response__tx(msg_st->queue->binding,
167                                                TXQCONT(msg_st), msg_st->err,
168                                                st->frame);
169}
170
171/*
172 * ----------------------------------------------------------------------------
173 * XOMP helper receive handlers
174 * ----------------------------------------------------------------------------
175 */
176
177static void get_memory_call_rx(struct xomp_gateway_binding *b,
178                               lpaddr_t addr,
179                               uint64_t token)
180{
181    XWG_DEBUG("get_memory_call_rx: [0x%016lx]", addr);
182
183    struct tx_queue *txq = b->st;
184    struct txq_msg_st *msg_st = txq_msg_st_alloc(txq);
185    assert(msg_st != NULL);
186
187    msg_st->cleanup = NULL;
188    msg_st->send = get_memory_response_tx;
189
190    if (token != xgw_token) {
191        XWG_DEBUG("get_memory_call_rx token do not match: %lx %lx\n", token,
192                  xgw_token);
193        msg_st->err = XOMP_ERR_INVALID_TOKEN;
194        txq_send(msg_st);
195        return;
196    }
197
198    struct xh_msg_st *st = (struct xh_msg_st *) msg_st;
199
200    struct mem_reg *mem = xgw_do_lookup_mem(addr);
201    if (mem == NULL) {
202        XWG_DEBUG("get_memory_call_rx: memory lookup failed\n");
203        msg_st->err = XOMP_ERR_INVALID_MEMORY;
204    } else {
205        msg_st->err = SYS_ERR_OK;
206        st->frame = mem->frame;
207    }
208
209    txq_send(msg_st);
210}
211
212static struct xomp_gateway_rx_vtbl rx_vtbl = {
213    .get_memory_call = get_memory_call_rx,
214};
215
216/*
217 * ----------------------------------------------------------------------------
218 * XOMP helper connect / export callbacks
219 * ----------------------------------------------------------------------------
220 */
221
222static errval_t xgw_svc_connect_cb(void *st,
223                                   struct xomp_gateway_binding *xb)
224{
225    XWG_DEBUG("new connection from client\n");
226
227    struct tx_queue *queue = calloc(1, sizeof(*queue));
228    if (queue == NULL) {
229        return LIB_ERR_MALLOC_FAIL;
230    }
231
232    txq_init(queue, xb, xb->waitset, (txq_register_fn_t) xb->register_send,
233             sizeof(struct xh_msg_st));
234
235    xb->rx_vtbl = rx_vtbl;
236    xb->st = queue;
237
238    return SYS_ERR_OK;
239}
240
241static void xh_svc_export_cb(void *st,
242                             errval_t err,
243                             iref_t iref)
244{
245    XWG_DEBUG("gateway service exported %s\n", err_getstring(err));
246
247    if (err_is_fail(err)) {
248        USER_PANIC_ERR(err, "export failed");
249    }
250
251    char svc_name[40];
252    snprintf(svc_name, 40, "%s.%s", disp_name(), "xgw");
253
254    err = nameservice_register(svc_name, iref);
255    if (err_is_fail(err)) {
256        USER_PANIC_ERR(err, "nameservice registration failed");
257    }
258
259    xgw_token = xomp_gateway_make_token();
260
261    XWG_DEBUG("gateway iref:%"PRIxIREF" @ {%s} with token: %lx\n", iref, svc_name,
262              xgw_token);
263}
264
265/*
266 * ----------------------------------------------------------------------------
267 * XOMP gateway service initialization
268 * ----------------------------------------------------------------------------
269 */
270
271/**
272 * \brief initializes the xomp gatway service
273 *
274 * \return SYS_ERR_OK on success
275 *         errval on failure
276 */
277errval_t xomp_gateway_init(void)
278{
279    errval_t err;
280
281    XWG_DEBUG("xomp gateway initialization\n");
282
283    err = xomp_gateway_export(NULL, xh_svc_export_cb, xgw_svc_connect_cb,
284                              get_default_waitset(), IDC_EXPORT_FLAGS_DEFAULT);
285    if (err_is_fail(err)) {
286        return err;
287    }
288
289    while (!xgw_token) {
290        messages_wait_and_handle_next();
291    }
292
293    return SYS_ERR_OK;
294}
295