1/**
2 * \file
3 * \brief Code responsible for booting application cores
4 */
5
6/*
7 * Copyright (c) 2007, 2008, 2009, 2010, 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, Haldeneggsteig 4, CH-8092 Zurich. Attn: Systems Group.
13 */
14
15#include <stdlib.h>
16#include <stdio.h>
17#include <string.h>
18#include <assert.h>
19
20#include <barrelfish/barrelfish.h>
21#include <barrelfish/spawn_client.h>
22
23#include <if/octopus_defs.h>
24#include <if/octopus_thc.h>
25
26#include <octopus/octopus.h>
27#include <octopus/trigger.h>
28
29#include <skb/skb.h>
30#include <thc/thc.h>
31
32#include "kaluga.h"
33
34
35/** Turn a line of comma seperated values into a a number of arguments
36 * and a pointer array of values (a la argc/argv).
37 * string pointed to by in _will be modified_
38 * argv will be null terminated
39 */
40
41static void csv_to_argv(char * in, int * argc, char *** argv) {
42    // Determine argc
43    *argc = 0;
44    for(char * pos = in; *pos; pos++) *argc += *pos == ',' ? 1 : 0;
45
46    char ** argv_out = (char **)malloc(sizeof(char *) * (*argc) + 1);
47    *argv = argv_out;
48    assert(argv_out != NULL);
49
50    //Replace , with \0 and generate argv
51    int argv_idx = 0;
52    argv_out[argv_idx] = in;
53    argv_idx++;
54    for(char * pos = in; *pos; pos++) {
55        if(*pos == ',') {
56            argv_out[argv_idx] = pos+1;
57            argv_idx++;
58            *pos = '\0';
59        }
60    }
61    argv_out[argv_idx] = NULL;
62}
63
64static void int_controller_change_event(octopus_mode_t mode,
65                                        const char* device_record, void* st)
66{
67    KALUGA_DEBUG("int_controller_change_event!\n");
68
69    errval_t err;
70    char ** argv = NULL;
71
72    if (mode & OCT_ON_SET) {
73        char * label;
74        char * class;
75        KALUGA_DEBUG("Device record: %s\n", device_record);
76        err = oct_read(device_record, "_ { label: %s, class: %s }",
77                &label, &class);
78        if (err_is_fail(err)) {
79            USER_PANIC_ERR(err, "Got malformed int controller device record?");
80            goto out;
81        }
82
83        KALUGA_DEBUG("Int Controller appeared, Label: %s\n", label);
84        // Ask the SKB which binary and where to start it...
85        static char* query = "find_int_controller_driver(%s).";
86        err = skb_execute_query(query, label);
87        if (err_no(err) == SKB_ERR_EXECUTION) {
88            KALUGA_DEBUG("No int controller driver found for: label=%s,class=%s\n",
89                    label, class);
90            goto out;
91        }
92        else if (err_is_fail(err)) {
93            DEBUG_ERR(err, "Failed to query SKB.\n");
94            goto out;
95        }
96
97        char * out = skb_get_output();
98        int argc;
99        csv_to_argv(out, &argc, &argv);
100
101        // TODO: specify core somehow. If core != my_core_id
102        // We must make sure that spawnd is up (see start_pci.c)
103        coreid_t core = get_my_core_id();
104        KALUGA_DEBUG("Starting int controller binary: %s\n", argv[0]);
105
106        err = spawn_program(core, argv[0], argv+1,
107                        environ, 0, NULL);
108        if (err_is_fail(err)) {
109            DEBUG_ERR(err, "Spawning %s failed.", argv[0]);
110        }
111    }
112
113out:
114    free(argv);
115}
116
117errval_t watch_for_int_controller(void) {
118    KALUGA_DEBUG("watch_for_int_controller\n");
119    static char* int_controller_device  = "r'hw\\.int\\.controller\\.[0-9]+' { "
120                               " label: _, class: _ }";
121    octopus_trigger_id_t tid;
122    return oct_trigger_existing_and_watch(int_controller_device, int_controller_change_event, NULL, &tid);
123}
124