1/**
2 * \file
3 * \brief Contains handler functions for server-side octopus interface RPC call.
4 */
5
6/*
7 * Copyright (c) 2009, 2010, 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, Universitaetstr. 6, CH-8092 Zurich. Attn: Systems Group.
13 */
14
15#include <stdio.h>
16#include <string.h>
17#include <inttypes.h>
18#include <errno.h>
19
20#include <barrelfish/barrelfish.h>
21#include <barrelfish/nameservice_client.h>
22#include <skb/skb.h> // read list
23#include <int_route/int_route_server.h>
24#include <int_route/int_route_debug.h>
25
26#include <if/int_route_service_defs.h>
27#include <if/int_route_controller_defs.h>
28
29struct controller_driver {
30   char * label; // Label used in the SKB
31   char * class; // Label used in the SKB
32   struct int_route_controller_binding * binding; //
33   struct controller_driver * next; // Linked list next
34};
35
36/* This server exports two interfaces:
37 * * RPC interface - This is RPC the interface that
38 * * Controller interface - Interrupt controllers use a
39 */
40
41struct controller_driver * controller_head;
42static int exported = 0;
43
44static struct controller_driver * add_controller(struct controller_driver * d){
45    INT_DEBUG("%s: enter\n", __FUNCTION__);
46    struct controller_driver * cur;
47    if(controller_head == NULL){
48        controller_head = malloc(sizeof(struct controller_driver));
49        cur = controller_head;
50    } else if(d != NULL && d->next != NULL){
51        return add_controller(d->next);
52    } else {
53        assert(d != NULL);
54        d->next = malloc(sizeof(struct controller_driver));
55        cur = d->next;
56    }
57
58    // Initialize cur
59    cur->next = NULL;
60    cur->binding = NULL;
61    cur->label = NULL;
62    cur->class = NULL;
63    return cur;
64}
65
66/*
67 * Finds a controller for the given label/class combination.
68 * First, if a label is passed, it tries to match the label exactly, if no controller is found, it
69 * goes on to match on the class.
70 */
71static struct controller_driver * find_controller(char * label, char * class){
72    if(label != NULL && strlen(label) > 0) {
73        for(struct controller_driver * cur = controller_head; cur != NULL; cur = cur->next){
74            if(strcmp(label, cur->label) == 0){
75                return cur;
76            }
77        }
78    }
79    if(class != NULL && strlen(class) > 0) {
80        for(struct controller_driver * cur = controller_head; cur != NULL; cur = cur->next){
81            if(strcmp(class, cur->class) == 0){
82                return cur;
83            }
84        }
85    }
86    return NULL;
87}
88
89struct controller_add_mapping_data {
90    char * lbl;
91    char * class;
92    int_route_controller_int_message_t in_msg;
93    int_route_controller_int_message_t out_msg;
94    struct int_route_controller_binding *binding;
95};
96
97/*
98 * Parse string at pos, write parsed message into out. If pos_after is
99 * not null, the pointer after the parsing will be written there.
100 * Returns success value
101 *
102 * Example: 23,nullMsg        -> {23,0,0}
103 *          23,52             -> {23,52,0}
104 *          23,mem_write(1,2) -> {23,1,2}
105 */
106static int parse_int_message(char *pos, int_route_controller_int_message_t *out,
107        char **pos_after){
108    if(*pos == ',') return 1;
109
110    out->port = atoll(pos);
111    char * n_pos = strchr(pos, ',');
112    if(n_pos == NULL){
113        return 1;
114    }
115    n_pos++;
116    // n_pos points to after first comma
117
118    if(strncmp(n_pos, "mem_write", strlen("mem_write")) == 0){
119        char * int_1 = strchr(n_pos, '(');
120        if(int_1 == NULL){
121            return 1;
122        }
123        int_1++;
124        out->addr = atoll(int_1);
125
126        char * int_2 = strchr(int_1, ',');
127        if(int_2 == NULL){
128            return 1;
129        }
130        int_2++;
131        out->msg = atoll(int_2);
132
133        char * after = strchr(int_2, ')');
134        if(after == NULL){
135            return 1;
136        }
137        if(pos_after != NULL) *pos_after = after + 1;
138    } else if(strncmp(n_pos, "nullMsg", strlen("nullMsg"))==0) {
139        if(pos_after != NULL) *pos_after = n_pos + strlen("nullMsg");
140        out->msg = 0;
141        out->addr = 0;
142    } else {
143        out->msg = strtoll(n_pos, pos_after, 0);
144        out->addr = 0;
145        if(errno == EINVAL) {
146            return 1;
147        }
148    }
149    return 0;
150}
151
152//static int test_read(char *in, int_route_controller_int_message_t expected){
153//    int_route_controller_int_message_t actual;
154//    char * after = NULL;
155//    int err = parse_int_message(in, &actual, &after);
156//    if(err){
157//        printf("Returned error code %d\n", err);
158//    }
159//    if(memcmp(&actual, &expected, sizeof(actual)) != 0){
160//        printf("Parsing %s failed!\n", in);
161//    }
162//    if(*after != '\n'){
163//        printf("After pointer set wrong\n");
164//    }
165//    return 0;
166//}
167//}
168//
169//static void test_read_all(void){
170//    test_read("23,nullMsg\n", (int_route_controller_int_message_t){23,0,0});
171//    test_read("23,42\n", (int_route_controller_int_message_t){23,42,0});
172//    test_read("22,mem_write(33,44)\n", (int_route_controller_int_message_t){22,33,44});
173//};
174
175
176#define INVALID_PORT -1
177static errval_t read_route_output_and_tell_controllers(void){
178    //test_read_all();
179    char * out = malloc(strlen(skb_get_output())+1);
180    strcpy(out, skb_get_output());
181
182    INT_DEBUG("skb output: %s\n", out);
183    errval_t err;
184
185    // Parse output and instruct controller
186    char class[256];
187    char lbl[256];
188
189    for(char * pos = out; pos-1 != NULL && *pos != 0; pos = strchr(pos,'\n')+1 ) {
190        // Sample output line: msix_0,msix,0,nullMsg,0,mem_write(4276092928,34)
191
192        int matches = 0;
193        // lbl and class must not contain spaces:
194        matches = sscanf(pos, "%[^,\n],%[^,\n]", lbl, class);
195
196        if(matches != 2) {
197            debug_printf("WARNING: Invalid SKB response. (%d)\n", __LINE__);
198            continue;
199        }
200
201        char * pos_1 = strchr(pos,',');
202        if(pos_1 == NULL){
203            debug_printf("WARNING: Invalid SKB response. (%d)\n", __LINE__);
204        }
205        pos = strchr(pos_1 + 1,',');
206        if(pos == NULL){
207            debug_printf("WARNING: Invalid SKB response. (%d)\n", __LINE__);
208        }
209        pos += 1;
210
211        int_route_controller_int_message_t in_msg;
212        err = parse_int_message(pos, &in_msg, &pos);
213        if(err_is_fail(err)){
214            debug_printf("WARNING: Invalid SKB response. (%d)\n", __LINE__);
215            continue;
216        }
217        pos += 1;
218
219        int_route_controller_int_message_t out_msg;
220        err = parse_int_message(pos, &out_msg, &pos);
221        if(err_is_fail(err)){
222            debug_printf("WARNING: Invalid SKB response. (%d)\n", __LINE__);
223            continue;
224        }
225
226        INT_DEBUG("Scanned args: '%s' '%s': (%"PRIu64",%"PRIu64",%"PRIu64") -> "
227                "(%"PRIu64",%"PRIu64",%"PRIu64")\n", lbl, class,
228                in_msg.port, in_msg.msg, in_msg.addr,
229                out_msg.port, out_msg.msg, out_msg.addr);
230
231        struct controller_driver * dest = find_controller(lbl, class);
232        if(dest == NULL){
233            INT_DEBUG("No ctrl driver found (lbl=%s,class=%s). Ignoring.\n",lbl,
234                    class);
235        } else {
236            err = int_route_controller_add_mapping__tx(dest->binding,
237                    BLOCKING_CONT, lbl, class, in_msg,
238                    out_msg);
239            assert(err_is_ok(err));
240        }
241    }
242
243    free(out);
244    return SYS_ERR_OK;
245}
246
247#define INVALID_VECTOR ((uint64_t)-1)
248
249static void driver_route_call(struct int_route_service_binding *b,
250        struct capref intsource, int irq_idx,
251        struct capref intdest){
252    INT_DEBUG("%s: enter\n", __FUNCTION__);
253    errval_t err;
254
255    uint64_t int_src_num = INVALID_VECTOR;
256    err = invoke_irqsrc_get_vec_start(intsource, &int_src_num);
257    uint64_t int_src_num_high = INVALID_VECTOR;
258    err = invoke_irqsrc_get_vec_end(intsource, &int_src_num_high);
259
260    if(int_src_num + irq_idx > int_src_num_high || irq_idx < 0){
261        err = SYS_ERR_IRQ_INVALID;
262        DEBUG_ERR(err, "irq_idx out of range");
263        b->tx_vtbl.route_response(b, NOP_CONT, err);
264        return;
265    }
266
267    assert(err_is_ok(err));
268
269    uint64_t dest_vec = INVALID_VECTOR;
270    err = invoke_irqdest_get_vector(intdest, &dest_vec);
271    assert(err_is_ok(err));
272
273    //TODO fix this
274    uint64_t dest_cpu = INVALID_VECTOR;
275    err = invoke_irqdest_get_cpu(intdest, &dest_cpu);
276    assert(err_is_ok(err));
277
278    printf("Int route service: Routing request, (int=%"PRIu64") to "
279            "(cpu=%"PRIu64",vec=%"PRIu64")\n",
280            int_src_num, dest_cpu, dest_vec);
281
282    const char * template = "find_and_add_irq_route(%"PRIu64",%"PRIu64",%"PRIu64").";
283    int q_size = strlen(template) + 3 * 16;
284    char * query = malloc(q_size);
285    snprintf(query, q_size, template, int_src_num, dest_cpu, dest_vec);
286    err = skb_execute(query);
287    if(err_is_fail(err)){
288        DEBUG_SKB_ERR(err, "%s failed", query);
289        b->tx_vtbl.route_response(b, NOP_CONT, err);
290        return;
291    }
292
293    err = read_route_output_and_tell_controllers();
294    if(err_is_fail(err)){
295        DEBUG_ERR(err, "Error read_route_and_tell_controllers.\n");
296    }
297    b->tx_vtbl.route_response(b, NOP_CONT, err);
298}
299
300static void ctrl_register_controller(struct int_route_controller_binding *_binding,
301        const char *label, const char *class) {
302    struct controller_driver * c = add_controller(controller_head);
303    c->label = malloc(strlen(label)+1);
304    assert(c->label != NULL);
305    strcpy(c->label, label);
306
307    c->class = malloc(strlen(class)+1);
308    assert(c->class != NULL);
309    strcpy(c->class, class);
310    INT_DEBUG("ctrl_register_controller, label=%s, class=%s\n",c->label, c->class);
311
312    c->binding = _binding;
313}
314
315
316static struct int_route_service_rx_vtbl driver_rx_vtbl = {
317        .route_call = driver_route_call
318
319};
320
321static struct int_route_controller_rx_vtbl ctrl_rx_vtbl = {
322        .register_controller = ctrl_register_controller
323};
324
325static errval_t driver_connect_cb(void *st, struct int_route_service_binding *b) {
326    INT_DEBUG("%s: enter\n", __FUNCTION__);
327    b->st = NULL;
328    b->rx_vtbl = driver_rx_vtbl;
329    return SYS_ERR_OK;
330
331}
332
333static errval_t ctrl_connect_cb(void *st, struct int_route_controller_binding *b) {
334    INT_DEBUG("%s: enter\n", __FUNCTION__);
335    b->st = NULL;
336    b->rx_vtbl = ctrl_rx_vtbl;
337    return SYS_ERR_OK;
338
339}
340
341static void driver_export_cb(void *st, errval_t err, iref_t iref){
342    INT_DEBUG("%s: enter\n", __FUNCTION__);
343    assert(err_is_ok(err));
344
345    err = nameservice_register("int_route_service", iref);
346    if (err_is_fail(err)) {
347        USER_PANIC_ERR(err, "nameservice_register 1 failed");
348    };
349    exported++;
350}
351
352static void ctrl_export_cb(void *st, errval_t err, iref_t iref){
353    INT_DEBUG("%s: enter\n", __FUNCTION__);
354    assert(err_is_ok(err));
355
356    err = nameservice_register("int_ctrl_service", iref);
357    if (err_is_fail(err)) {
358        USER_PANIC_ERR(err, "nameservice_register 2 failed");
359    };
360    exported++;
361}
362
363
364// The main function of this service
365errval_t int_route_service_init(void)
366{
367    errval_t err;
368    INT_DEBUG("int_route_service_init\n");
369    // We need skb connection
370    skb_client_connect();
371
372    // Export route service for PCI device drivers
373    err = int_route_service_export(NULL, driver_export_cb, driver_connect_cb, get_default_waitset(),
374        IDC_EXPORT_FLAGS_DEFAULT);
375
376    if(err_is_fail(err)){
377        USER_PANIC_ERR(err, "int_route_service_export failed");
378    }
379
380    err = int_route_controller_export(NULL, ctrl_export_cb, ctrl_connect_cb, get_default_waitset(),
381         IDC_EXPORT_FLAGS_DEFAULT);
382    if(err_is_fail(err)){
383        USER_PANIC_ERR(err, "int_route_controller_export failed");
384    }
385
386
387    // XXX: Due to cyclic dependency, we must make sure the service has been exported before
388    // returning.
389
390    while(exported != 2){
391        event_dispatch(get_default_waitset());
392    }
393    return SYS_ERR_OK;
394}
395