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