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