1#define _USE_XOPEN /* for strdup() */
2#include <stdio.h>
3#include <string.h>
4
5#include <barrelfish/barrelfish.h>
6#include <barrelfish/cpu_arch.h> // for CURRENT_CPU_TYPE
7#include <barrelfish/spawn_client.h>
8
9#include <spawndomain/spawndomain.h>
10#include <vfs/vfs.h>
11
12#include "kaluga.h"
13#include "debug.h"
14
15#define MAX_DRIVER_MODULES 128
16
17static struct module_info modules[MAX_DRIVER_MODULES];
18
19inline bool is_auto_driver(struct module_info* mi) {
20    int i;
21    bool auto_driver = false;
22
23    for (i = 1; i < mi->argc; i++) {
24        if (strcmp(mi->argv[i], "auto") == 0) {
25            auto_driver = true;
26            break;
27        }
28    }
29
30    return auto_driver;
31}
32
33inline bool is_started(struct module_info* mi)
34{
35    return (mi->num_started);
36}
37
38inline bool can_start(struct module_info* mi)
39{
40    return (mi->allow_multi || (mi->num_started == 0));
41}
42
43void set_start_function(char* binary, module_start_fn start_fn)
44{
45    struct module_info* mi = find_module(binary);
46    if (mi != NULL) {
47        mi->start_function = start_fn;
48    }
49}
50
51void set_started(struct module_info* mi)
52{
53    mi->num_started += 1;
54    assert(mi->allow_multi || (mi->num_started == 1));
55}
56
57void set_multi_instance(struct module_info* mi, uint8_t is_multi)
58{
59    mi->allow_multi = (is_multi != 0);
60}
61
62void set_core_id_offset(struct module_info* mi, coreid_t offset)
63{
64    mi->coreoffset = offset;
65}
66
67struct capref *get_did_ptr(struct module_info *mi)
68{
69    return (mi->did + mi->num_started);
70}
71
72coreid_t get_core_id_offset(struct module_info* mi)
73{
74    return mi->coreoffset * mi->num_started;
75}
76
77struct module_info* find_module(char *binary)
78{
79    assert(binary != NULL);
80    bool found = false;
81    struct module_info* si = NULL;
82
83    for (size_t i=0; i< MAX_DRIVER_MODULES; i++) {
84        si = &modules[i];
85        if (si->binary != NULL && strcmp(si->binary, binary) == 0) {
86            found = true;
87            break;
88        }
89    }
90
91    return (found) ? si : NULL;
92}
93
94/**
95 * @brief finds corectrl driver module for a given CPU type.
96 *
97 * @param cpu_type  the CPU type
98 *
99 * @return pointer to the corectrl module, or NULL if not existing
100 */
101struct module_info* find_corectrl_for_cpu_type(enum cpu_type cpu_type)
102{
103    switch(cpu_type) {
104    case CPU_K1OM:
105    case CPU_X86_64:
106    case CPU_X86_32:
107    case CPU_ARM7:
108    case CPU_ARM8:
109        return find_module("corectrl");
110        break;
111    default:
112        return NULL;
113        break;
114    }
115}
116
117static void parse_module(char* line, struct module_info* si)
118{
119    si->complete_line = strdup(line);
120
121    char* path_end = strchr(line, ' ');
122    if (path_end == NULL) {
123        path_end = line + strlen(line);
124    }
125    size_t path_size = path_end-line;
126    si->path = malloc(path_size+1);
127    strncpy(si->path, line, path_size);
128    si->path[path_size] = '\0';
129
130    char* binary_start = strrchr(si->path, '/');
131    si->binary = strdup(binary_start+1); // exclude /
132    memset(si->did, 0, sizeof(si->did));
133    si->start_function = default_start_function;
134    si->num_started = 0;
135    char* cmdstart = line + path_size - strlen(si->binary);
136    si->args = strdup(line + path_size);
137
138    // cmdargs will be tagged with \0
139    si->cmdargs = strdup(cmdstart);
140    si->argc = spawn_tokenize_cmdargs(si->cmdargs, si->argv,
141                                      ARRAY_LENGTH(si->argv));
142}
143
144/**
145 * \brief Parses bootmodules and stores info in
146 * boot_modules.
147 */
148static errval_t parse_modules(char* bootmodules)
149{
150    assert(bootmodules != NULL);
151
152    size_t entry = 0;
153    char* bm = strdup(bootmodules);
154
155    static const char* delim = "\n";
156    char* line = strtok(bm, delim);
157
158    while (line != NULL && entry < MAX_DRIVER_MODULES) {
159        struct module_info* si = &modules[entry++];
160        parse_module(line, si);
161        KALUGA_DEBUG("found boot module:\n%s\n%s\n%s (%d)\n", si->binary, si->path, si->cmdargs, si->argc);
162
163        line = strtok(NULL, delim);
164    }
165    free(bm);
166
167    if (line == NULL) {
168        return SYS_ERR_OK;
169    }
170    else {
171        return KALUGA_ERR_PARSE_MODULES;
172    }
173}
174
175/**
176 * \brief Open bootmodules file and read it in
177 */
178static char* get_bootmodules(void)
179{
180    errval_t err;
181
182    // open bootmodules file and read it in
183    vfs_handle_t vh;
184    err = vfs_open("/bootmodules", &vh);
185    if (err_is_fail(err)) {
186        USER_PANIC_ERR(err, "unable to open /bootmodules");
187    }
188
189    struct vfs_fileinfo info;
190    err = vfs_stat(vh, &info);
191    if (err_is_fail(err)) {
192        USER_PANIC_ERR(err, "unable to stat /bootmodules");
193    }
194
195    char *bootmodules = malloc(info.size + 1);
196    if (bootmodules == NULL) {
197        USER_PANIC_ERR(LIB_ERR_MALLOC_FAIL,
198                       "failed to allocate memory for bootmodules");
199    }
200    size_t bootmodules_len;
201    err = vfs_read(vh, bootmodules, info.size, &bootmodules_len);
202    if (err_is_fail(err)) {
203        USER_PANIC_ERR(err, "unable to read /bootmodules");
204    } else if (bootmodules_len == 0) {
205        USER_PANIC_ERR(err, "/bootmodules is empty");
206    } else if (bootmodules_len != info.size) {
207        USER_PANIC_ERR(err, "unexpected short read of /bootmodules");
208    }
209
210    err = vfs_close(vh);
211    if (err_is_fail(err)) {
212        DEBUG_ERR(err, "could not close bottmodules file");
213    }
214
215    // terminate as a string
216    bootmodules[bootmodules_len] = '\0';
217    return bootmodules;
218}
219
220/**
221 * \brief Set an initial default environment for our boot-time children
222 */
223void init_environ(void)
224{
225    int r;
226
227    /* PATH=/build-arch/sbin */
228    char pathstr[64];
229    snprintf(pathstr, sizeof(pathstr), "/" BF_BINARY_PREFIX "%s/sbin",
230             cpu_type_to_archstr(CURRENT_CPU_TYPE));
231    pathstr[sizeof(pathstr) - 1] = '\0';
232    r = setenv("PATH", pathstr, 0);
233    if (r != 0) {
234        USER_PANIC("failed to set PATH");
235    }
236
237    /* HOME=/ */
238    r = setenv("HOME", "/", 0);
239    if (r != 0) {
240        USER_PANIC("failed to set HOME");
241    }
242}
243
244errval_t init_boot_modules(void)
245{
246    char* bootmodules = get_bootmodules();
247    errval_t err = parse_modules(bootmodules);
248    free(bootmodules);
249
250    return err;
251}
252
253errval_t init_driver_argument(struct driver_argument *arg){
254    int_startup_argument_init(&arg->int_arg);
255    errval_t err = cnode_create_l2(&arg->arg_caps, &arg->argnode_ref);
256    if(err_is_fail(err)){
257        DEBUG_ERR(err, "Could not cnode_create_l2");
258        return err;
259    }
260    return SYS_ERR_OK;
261}
262
263