1/** 2 * \file 3 * \brief 4 */ 5 6/* 7 * Copyright (c) 2007, 2008, 2009, 2010, 2011, 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, Haldeneggsteig 4, CH-8092 Zurich. Attn: Systems Group. 13 */ 14 15#define _USE_XOPEN /* for strdup() in string.h */ 16 17#include <monitor.h> 18#include <barrelfish/cpu_arch.h> 19 20extern char **environ; 21 22/** 23 * \brief Some domains require special caps for functionality 24 * and we do not have a better way to to this yet 25 */ 26static errval_t set_special_caps(struct spawninfo *si, const char *pname) 27{ 28 struct capref src, dest; 29 errval_t err; 30 31 // lop off leading path for name comparison 32 const char *name = strrchr(pname, '/'); 33 if (name == NULL) { 34 name = pname; 35 } else { 36 name++; 37 } 38 39 /* Pass IRQ cap to bfscope (XXX: kludge) */ 40 if (!strcmp(name, "bfscope")) { 41 dest.cnode = si->taskcn; 42 dest.slot = TASKCN_SLOT_IRQ; 43 src.cnode = cnode_task; 44 src.slot = TASKCN_SLOT_IRQ; 45 err = cap_copy(dest, src); 46 if (err_is_fail(err)) { 47 return err_push(err, SPAWN_ERR_COPY_IRQ_CAP); 48 } 49 } 50 51 if (!strcmp(name, "kaluga")) { 52 src = cap_kernel; 53 dest.cnode = si->taskcn, 54 dest.slot = TASKCN_SLOT_KERNELCAP; 55 err = cap_copy(dest, src); 56 if (err_is_fail(err)) { 57 DEBUG_ERR(err, "Can not give kernel cap to kaluga"); 58 return err_push(err, SPAWN_ERR_COPY_KERNEL_CAP); 59 } 60 } 61 62 if (!strcmp(name, "proc_mgmt")) { 63 // Pass ProcessManager cap. 64 dest.cnode = si->taskcn; 65 dest.slot = TASKCN_SLOT_PROC_MNG; 66 src = cap_procmng; 67 err = cap_copy(dest, src); 68 if (err_is_fail(err)) { 69 DEBUG_ERR(err, "Can not give ProcessManager cap"); 70 return err_push(err, SPAWN_ERR_COPY_PROC_MNG_CAP); 71 } 72 } 73 74#ifdef __k1om__ 75 if (!strcmp(name, "xeon_phi")) { 76 dest.cnode = si->taskcn; 77 dest.slot = TASKCN_SLOT_IO; 78 src.cnode = cnode_task; 79 src.slot = TASKCN_SLOT_IO; 80 err = cap_copy(dest, src); 81 if (err_is_fail(err)) { 82 return err_push(err, SPAWN_ERR_COPY_IRQ_CAP); 83 } 84 85 dest.cnode = si->taskcn; 86 dest.slot = TASKCN_SLOT_SYSMEM; 87 src.cnode = cnode_task; 88 src.slot = TASKCN_SLOT_SYSMEM; 89 err = cap_copy(dest, src); 90 if (err_is_fail(err)) { 91 return err_push(err, SPAWN_ERR_COPY_IRQ_CAP); 92 } 93 dest.cnode = si->taskcn; 94 dest.slot = TASKCN_SLOT_COREBOOT; 95 src.cnode = cnode_task; 96 src.slot = TASKCN_SLOT_COREBOOT; 97 err = cap_copy(dest, src); 98 if (err_is_fail(err)) { 99 return err_push(err, SPAWN_ERR_COPY_IRQ_CAP); 100 } 101 } 102#endif 103 104 return SYS_ERR_OK; 105} 106 107/** 108 * \brief Spawn the domain identified by #name 109 */ 110errval_t spawn_domain(char *name) 111{ 112 errval_t err; 113 114 /* Get the module from the multiboot */ 115 struct mem_region *module = multiboot_find_module(bi, name); 116 if (module == NULL) { 117 return SPAWN_ERR_FIND_MODULE; 118 } 119 120 /* Get and tokenize cmdline args */ 121 char *args; 122 err = spawn_get_cmdline_args(module, &args); 123 if (err_is_fail(err)) { 124 return err_push(err, SPAWN_ERR_GET_CMDLINE_ARGS); 125 } 126 char *argv[MAX_CMDLINE_ARGS + 1]; 127 spawn_tokenize_cmdargs(args, argv, ARRAY_LENGTH(argv)); 128 129 err = spawn_module_with_args(name, module, argv, environ); 130 free(args); 131 return err; 132} 133/** 134 * \brief Spawn the domain identified by #name with the provided args 135 */ 136errval_t spawn_domain_with_args(const char *name, 137 char *const argv[], char *const envp[]) 138{ 139 struct mem_region *module = multiboot_find_module(bi, name); 140 if (module == NULL) { 141 return SPAWN_ERR_FIND_MODULE; 142 } 143 144 return spawn_module_with_args(name, module, argv, envp); 145} 146 147/** 148 * \brief Spawn the domain identified by #module with the provided args 149 */ 150errval_t spawn_module_with_args(const char *name, struct mem_region *module, 151 char *const argv[], char *const envp[]) 152{ 153 errval_t err; 154 struct spawninfo si; 155 156 printf("Spawning %s on core %d\n", name, my_core_id); 157 158 err = spawn_load_with_args(&si, module, name, my_core_id, argv, envp); 159 if (err_is_fail(err)) { 160 return err_push(err, SPAWN_ERR_LOAD); 161 } 162 163 // Set special caps 164 err = set_special_caps(&si, name); 165 if (err_is_fail(err)) { 166 return err_push(err, SPAWN_ERR_SET_CAPS); 167 } 168 169 // Set connection 170 err = monitor_client_setup(&si); 171 if (err_is_fail(err)) { 172 return err_push(err, SPAWN_ERR_MONITOR_CLIENT); 173 } 174 175 // Make runnable 176 err = spawn_run(&si); 177 if (err_is_fail(err)) { 178 return err_push(err, SPAWN_ERR_RUN); 179 } 180 181 // Cleanup 182 err = spawn_free(&si); 183 if (err_is_fail(err)) { 184 return err_push(err, SPAWN_ERR_FREE); 185 } 186 187 return SYS_ERR_OK; 188} 189 190/** 191 * \brief Spawn the domain in the given image with the provided args 192 */ 193static errval_t spawn_image_with_args(const char *name, void *image, 194 size_t imagelen, 195 char *const argv[], char *const envp[]) 196{ 197 errval_t err; 198 struct spawninfo si; 199 200 printf("Spawning %s on core %d\n", name, my_core_id); 201 202 err = spawn_load_image(&si, (lvaddr_t)image, imagelen, CURRENT_CPU_TYPE, 203 name, my_core_id, argv, envp, NULL_CAP, NULL_CAP); 204 if (err_is_fail(err)) { 205 return err_push(err, SPAWN_ERR_LOAD); 206 } 207 208 // Set special caps 209 err = set_special_caps(&si, name); 210 if (err_is_fail(err)) { 211 return err_push(err, SPAWN_ERR_SET_CAPS); 212 } 213 214 // Set connection 215 err = monitor_client_setup(&si); 216 if (err_is_fail(err)) { 217 return err_push(err, SPAWN_ERR_MONITOR_CLIENT); 218 } 219 220 // Make runnable 221 err = spawn_run(&si); 222 if (err_is_fail(err)) { 223 return err_push(err, SPAWN_ERR_RUN); 224 } 225 226 // Cleanup 227 err = spawn_free(&si); 228 if (err_is_fail(err)) { 229 return err_push(err, SPAWN_ERR_FREE); 230 } 231 232 return SYS_ERR_OK; 233} 234 235/** 236 * \brief Spawn all 'boot' domains in modules (menu.lst) 237 */ 238errval_t spawn_all_domains(void) 239{ 240 errval_t err; 241 242 char name[128]; 243 244 for(size_t i = 0; i < bi->regions_length; i++) { 245 // Lookup modules in bootinfo 246 struct mem_region *region = &bi->regions[i]; 247 if (region->mr_type != RegionType_Module) { /* Not of module type */ 248 continue; 249 } 250 251 const char *mm_name = multiboot_module_name(region); 252 // Copy name because walking the multiboot changes the name field 253 strncpy(name, mm_name, sizeof(name)); 254 255 // Lop off the path from the name 256 const char *short_name = strrchr(name, '/'); 257 if (!short_name) { 258 short_name = name; 259 } else { 260 short_name++; 261 } 262 263 /* Do not spawn special domains */ 264 if(!strcmp(short_name, "init") 265 || !strcmp(short_name, "skb") 266 || !strcmp(short_name, "ramfsd") 267 || !strcmp(short_name, "cpu") 268 || !strcmp(short_name, "monitor") 269 || !strcmp(short_name, "mem_serv") 270 || !strcmp(short_name, "xeon_phi") 271 || !strcmp(short_name, "proc_mgmt") 272 ) 273 { 274 continue; 275 } 276 277 /* Get and tokenize cmdline args */ 278 char *args; 279 err = spawn_get_cmdline_args(region, &args); 280 if (err_is_fail(err)) { 281 return err_push(err, SPAWN_ERR_GET_CMDLINE_ARGS); 282 } 283 284 // Pass the local arch-specific core ID to the PCI and spawnd domains 285 if(strcmp(short_name, "pci") == 0 286 || strcmp(short_name, "spawnd") == 0 287 || strcmp(short_name, "kaluga") == 0 288 || strcmp(short_name, "acpi") == 0 289 || strcmp(short_name, "ioapic") == 0) { 290 // Get hardware core ID 291 uintptr_t my_arch_id = 0; 292 err = invoke_monitor_get_arch_id(&my_arch_id); 293 assert(err_is_ok(err)); 294 295 char *myargs = malloc(strlen(args) + 50); 296 snprintf(myargs, strlen(args) + 50, "%s apicid=%" PRIuPTR, 297 args, my_arch_id); 298 free(args); 299 args = myargs; 300 } 301 302 char *argv[MAX_CMDLINE_ARGS + 1]; 303 int argc = spawn_tokenize_cmdargs(args, argv, ARRAY_LENGTH(argv)); 304 305 /* Only spawn boot time modules */ 306 if (argc > 1 && strcmp(argv[1], "boot") == 0) { 307 err = spawn_module_with_args(name, region, argv, environ); 308 if (err_is_fail(err)) { 309 return err_push(err, MON_ERR_SPAWN_DOMAIN); 310 } 311 } 312 free(args); 313 } 314 315 return SYS_ERR_OK; 316} 317 318static struct { 319 genpaddr_t base; 320 size_t bytes; 321} spawnd_image; 322 323static void spawnd_image_reply_handler(struct intermon_binding *b, 324 genpaddr_t base, uint32_t bytes) 325{ 326 assert(spawnd_image.base == 0); 327 assert(base > 0 && bytes > 0); 328 spawnd_image.base = base; 329 spawnd_image.bytes = bytes; 330} 331 332/** 333 * \brief Span a domain to this core. 334 */ 335errval_t spawn_spawnd(struct intermon_binding *b) 336{ 337 assert(!bsp_monitor); 338 339 // find out where the image is 340 b->rx_vtbl.spawnd_image_reply = spawnd_image_reply_handler; 341 errval_t err = b->tx_vtbl.spawnd_image_request(b, NOP_CONT); 342 if (err_is_fail(err)) { 343 return err_push(err, MON_ERR_SEND_REMOTE_MSG); 344 } 345 346 while(spawnd_image.base == 0) { 347 messages_wait_and_handle_next(); 348 } 349 350 // construct cap to it 351 struct capability cap_raw = { 352 .type = ObjType_Frame, 353 .rights = CAPRIGHTS_ALLRIGHTS, 354 .u.frame = { 355 .base = spawnd_image.base, 356 .bytes = ROUND_UP(spawnd_image.bytes, BASE_PAGE_SIZE), 357 } 358 }; 359 struct capref frame; 360 err = slot_alloc(&frame); 361 if (err_is_fail(err)) { 362 USER_PANIC_ERR(err, "allocating slot failed for spawnd image"); 363 } 364 365 err = monitor_cap_create(frame, &cap_raw, my_core_id); 366 if (err_is_fail(err)) { 367 USER_PANIC_ERR(err, "monitor_cap_create failed"); 368 } 369 370 // map the image in 371 // XXX: leak memobj/region 372 void *image; 373 err = vspace_map_one_frame(&image, spawnd_image.bytes, frame, NULL, NULL); 374 if (err_is_fail(err)) { 375 return err_push(err, LIB_ERR_VSPACE_MAP); 376 } 377 378 // spawn! 379 char *argv[] = { "spawnd", NULL }; 380 return spawn_image_with_args(argv[0], image, spawnd_image.bytes, argv, 381 environ); 382} 383 384/** 385 * \brief Span a domain to this core. 386 */ 387errval_t span_domain(struct capref vroot, struct capref dispframe) 388{ 389 struct spawninfo si; 390 errval_t err; 391 392 memset(&si, 0, sizeof(si)); 393 394 printf("Spanning domain to core %d\n", my_core_id); 395 396 // Span domain 397 err = spawn_span_domain(&si, vroot, dispframe); 398 if (err_is_fail(err)) { 399 return err_push(err, SPAWN_ERR_SPAN); 400 } 401 402 // Set connection 403 err = monitor_client_setup(&si); 404 if (err_is_fail(err)) { 405 return err_push(err, SPAWN_ERR_MONITOR_CLIENT); 406 } 407 408 // Make runnable 409 err = spawn_run(&si); 410 if (err_is_fail(err)) { 411 return err_push(err, SPAWN_ERR_RUN); 412 } 413 414 // Cleanup 415 err = spawn_free(&si); 416 if (err_is_fail(err)) { 417 return err_push(err, SPAWN_ERR_FREE); 418 } 419 420 return SYS_ERR_OK; 421} 422