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