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