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