1/** 2 * \file 3 * \brief functionality to spawn domains 4 */ 5 6/* 7 * Copyright (c) 2007-2012, ETH Zurich. 8 * Copyright (c) 2015, Hewlett Packard Enterprise Development LP. 9 * All rights reserved. 10 * 11 * This file is distributed under the terms in the attached LICENSE file. 12 * If you do not find this file, copies can be found by writing to: 13 * ETH Zurich D-INFK, Universitaetstrasse 6, CH-8092 Zurich. Attn: Systems Group. 14 */ 15 16#include <string.h> 17#include <stdio.h> 18#include <inttypes.h> 19#include <barrelfish/barrelfish.h> 20#include <spawndomain/spawndomain.h> 21#include <barrelfish/dispatcher_arch.h> 22#include <barrelfish/spawn_client.h> 23#include <barrelfish_kpi/domain_params.h> 24#include <trace/trace.h> 25#include "spawn.h" 26#include "arch.h" 27#include <elf/elf.h> 28 29extern char **environ; 30 31/** 32 * \brief Setup an initial cspace 33 * 34 * Create an initial cspace layout 35 */ 36static errval_t spawn_setup_cspace(struct spawninfo *si) 37{ 38 errval_t err; 39 struct capref t1; 40 41 /* Create root CNode */ 42 err = cnode_create_l1(&si->rootcn_cap, &si->rootcn); 43 if (err_is_fail(err)) { 44 return err_push(err, SPAWN_ERR_CREATE_ROOTCN); 45 } 46 47 /* Create taskcn */ 48 err = cnode_create_foreign_l2(si->rootcn_cap, ROOTCN_SLOT_TASKCN, &si->taskcn); 49 if (err_is_fail(err)) { 50 return err_push(err, SPAWN_ERR_CREATE_TASKCN); 51 } 52 53 /* Create slot_alloc_cnode */ 54 err = cnode_create_foreign_l2(si->rootcn_cap, ROOTCN_SLOT_SLOT_ALLOC0, NULL); 55 if (err_is_fail(err)) { 56 return err_push(err, SPAWN_ERR_CREATE_SLOTALLOC_CNODE); 57 } 58 err = cnode_create_foreign_l2(si->rootcn_cap, ROOTCN_SLOT_SLOT_ALLOC1, NULL); 59 if (err_is_fail(err)) { 60 return err_push(err, SPAWN_ERR_CREATE_SLOTALLOC_CNODE); 61 } 62 err = cnode_create_foreign_l2(si->rootcn_cap, ROOTCN_SLOT_SLOT_ALLOC2, NULL); 63 if (err_is_fail(err)) { 64 return err_push(err, SPAWN_ERR_CREATE_SLOTALLOC_CNODE); 65 } 66 err = cnode_create_foreign_l2(si->rootcn_cap, ROOTCN_SLOT_ROOT_MAPPING, NULL); 67 if (err_is_fail(err)) { 68 return err_push(err, SPAWN_ERR_CREATE_SLOTALLOC_CNODE); 69 } 70 71 // Create DCB: make si->dcb invokable 72 err = slot_alloc(&si->dcb); 73 if (err_is_fail(err)) { 74 return err_push(err, LIB_ERR_SLOT_ALLOC); 75 } 76 err = dispatcher_create(si->dcb); 77 if (err_is_fail(err)) { 78 return err_push(err, SPAWN_ERR_CREATE_DISPATCHER); 79 } 80 81 // Copy DCB to new taskcn 82 t1.cnode = si->taskcn; 83 t1.slot = TASKCN_SLOT_DISPATCHER; 84 err = cap_copy(t1, si->dcb); 85 if (err_is_fail(err)) { 86 return err_push(err, LIB_ERR_CAP_COPY); 87 } 88 89 // Give domain endpoint to itself (in taskcn) 90 struct capref selfep = { 91 .cnode = si->taskcn, 92 .slot = TASKCN_SLOT_SELFEP, 93 }; 94 // XXX: could redo retyping of EPs now, and actually give offset and stuff 95 err = cap_retype(selfep, si->dcb, 0, ObjType_EndPointLMP, 0, 1); 96 if (err_is_fail(err)) { 97 return err_push(err, SPAWN_ERR_CREATE_SELFEP); 98 } 99 100 // Map root CNode (in taskcn) 101 t1.cnode = si->taskcn; 102 t1.slot = TASKCN_SLOT_ROOTCN; 103 err = cap_copy(t1, si->rootcn_cap); 104 if (err_is_fail(err)) { 105 return err_push(err, SPAWN_ERR_MINT_ROOTCN); 106 } 107 108#ifdef TRACING_EXISTS 109 // Set up tracing for the child 110 err = trace_setup_child(si->taskcn, si->handle); 111 if (err_is_fail(err)) { 112 printf("Warning: error setting up tracing for child domain\n"); 113 // SYS_DEBUG(err, ...); 114 } 115#endif 116 117 // XXX: copy over argspg? 118 memset(&si->argspg, 0, sizeof(si->argspg)); 119 120 /* Fill up basecn */ 121 struct cnoderef basecn; 122 123 // Create basecn in our rootcn so we can copy stuff in there 124 err = cnode_create_foreign_l2(si->rootcn_cap, ROOTCN_SLOT_BASE_PAGE_CN, &basecn); 125 if (err_is_fail(err)) { 126 return err_push(err, LIB_ERR_CNODE_CREATE); 127 } 128 129 // get big RAM cap for L2_CNODE_SLOTS BASE_PAGE_SIZEd caps 130 struct capref ram; 131 err = ram_alloc(&ram, L2_CNODE_BITS + BASE_PAGE_BITS); 132 if (err_is_fail(err)) { 133 return err_push(err, LIB_ERR_RAM_ALLOC); 134 } 135 136 // retype big RAM cap into small caps in new basecn 137 struct capref base = { 138 .cnode = basecn, 139 .slot = 0, 140 }; 141 err = cap_retype(base, ram, 0, ObjType_RAM, BASE_PAGE_SIZE, L2_CNODE_SLOTS); 142 if (err_is_fail(err)) { 143 return err_push(err, LIB_ERR_CAP_RETYPE); 144 } 145 146 // delete big RAM cap 147 err = cap_destroy(ram); 148 if (err_is_fail(err)) { 149 return err_push(err, LIB_ERR_CAP_DESTROY); 150 } 151 152 /* Fill up early_cn cnode */ 153 struct cnoderef earlycn; 154 155 // Create basecn in our rootcn so we can copy stuff in there 156 err = cnode_create_foreign_l2(si->rootcn_cap, ROOTCN_SLOT_EARLY_CN_CN, &earlycn); 157 if (err_is_fail(err)) { 158 return err_push(err, LIB_ERR_CNODE_CREATE); 159 } 160 161 // get big RAM cap for L2_CNODE_SLOTS L2_CNODE_SIZEd caps 162 err = ram_alloc(&ram, EARLY_CNODE_ALLOCATED_BITS + (L2_CNODE_BITS + OBJBITS_CTE)); 163 if (err_is_fail(err)) { 164 return err_push(err, LIB_ERR_RAM_ALLOC); 165 } 166 167 // retype big RAM cap into small caps in new basecn 168 base = (struct capref){ 169 .cnode = earlycn, 170 .slot = 0, 171 }; 172 err = cap_retype(base, ram, 0, ObjType_RAM, OBJSIZE_L2CNODE, EARLY_CNODE_ALLOCATED_SLOTS); 173 if (err_is_fail(err)) { 174 return err_push(err, LIB_ERR_CAP_RETYPE); 175 } 176 177 // delete big RAM cap 178 err = cap_destroy(ram); 179 if (err_is_fail(err)) { 180 return err_push(err, LIB_ERR_CAP_DESTROY); 181 } 182 183 return SYS_ERR_OK; 184} 185 186static errval_t spawn_setup_vspace(struct spawninfo *si) 187{ 188 errval_t err; 189 190 /* Create pagecn */ 191 err = cnode_create_foreign_l2(si->rootcn_cap, ROOTCN_SLOT_PAGECN, &si->pagecn); 192 if (err_is_fail(err)) { 193 return err_push(err, SPAWN_ERR_CREATE_PAGECN); 194 } 195 196 /* Init pagecn's slot allocator */ 197 si->pagecn_cap.cnode = si->rootcn; 198 si->pagecn_cap.slot = ROOTCN_SLOT_PAGECN; 199 200 // XXX: satisfy a peculiarity of the single_slot_alloc_init_raw API 201 size_t bufsize = SINGLE_SLOT_ALLOC_BUFLEN(L2_CNODE_SLOTS); 202 void *buf = malloc(bufsize); 203 assert(buf != NULL); 204 205 err = single_slot_alloc_init_raw(&si->pagecn_slot_alloc, si->pagecn_cap, 206 si->pagecn, L2_CNODE_SLOTS, 207 buf, bufsize); 208 if (err_is_fail(err)) { 209 return err_push(err, LIB_ERR_SINGLE_SLOT_ALLOC_INIT_RAW); 210 } 211 212 // Create root of pagetable 213 err = si->pagecn_slot_alloc.a.alloc(&si->pagecn_slot_alloc.a, &si->vtree); 214 if (err_is_fail(err)) { 215 return err_push(err, LIB_ERR_SLOT_ALLOC); 216 } 217 218 // top-level table should always live in slot 0 of pagecn 219 assert(si->vtree.slot == 0); 220 221 switch(si->cpu_type) { 222 case CPU_X86_64: 223 case CPU_K1OM: 224 err = vnode_create(si->vtree, ObjType_VNode_x86_64_pml4); 225 break; 226 227 case CPU_X86_32: 228#ifdef CONFIG_PAE 229 err = vnode_create(si->vtree, ObjType_VNode_x86_32_pdpt); 230#else 231 err = vnode_create(si->vtree, ObjType_VNode_x86_32_pdir); 232#endif 233 break; 234 235 case CPU_ARM7: 236 err = vnode_create(si->vtree, ObjType_VNode_ARM_l1); 237 break; 238 239 case CPU_ARM8: 240 err = vnode_create(si->vtree, ObjType_VNode_AARCH64_l0); 241 break; 242 243 default: 244 assert(!"Other architecture"); 245 return err_push(err, SPAWN_ERR_UNKNOWN_TARGET_ARCH); 246 } 247 248 if (err_is_fail(err)) { 249 return err_push(err, SPAWN_ERR_CREATE_VNODE); 250 } 251 252 err = spawn_vspace_init(si, si->vtree, si->cpu_type); 253 if (err_is_fail(err)) { 254 return err_push(err, SPAWN_ERR_VSPACE_INIT); 255 } 256 257 return SYS_ERR_OK; 258} 259 260#if 0 261/** 262 * \brief Lookup and map an image 263 */ 264static errval_t spawn_map(const char *name, struct bootinfo *bi, 265 lvaddr_t *binary, size_t *binary_size) 266{ 267 errval_t err; 268 269 /* Get the module from the multiboot */ 270 struct mem_region *module = multiboot_find_module(bi, name); 271 if (module == NULL) { 272 return SPAWN_ERR_FIND_MODULE; 273 } 274 275 /* Map the image */ 276 err = spawn_map_module(module, binary_size, binary, NULL); 277 if (err_is_fail(err)) { 278 return err_push(err, SPAWN_ERR_MAP_MODULE); 279 } 280 281 return SYS_ERR_OK; 282} 283#endif // 0 284 285 286/** 287 * \brief Determine cpu type of the image 288 */ 289static errval_t spawn_determine_cputype(struct spawninfo *si, lvaddr_t binary) 290{ 291 struct Elf64_Ehdr *head = (struct Elf64_Ehdr *)binary; 292 293 switch(head->e_machine) { 294 case EM_K1OM: 295 si->cpu_type = CPU_K1OM; 296 break; 297 case EM_X86_64: 298 si->cpu_type = CPU_X86_64; 299 break; 300 301 case EM_386: 302 si->cpu_type = CPU_X86_32; 303 break; 304 305 case EM_ARM: 306 si->cpu_type = CPU_ARM7; 307 break; 308 309 case EM_AARCH64: 310 si->cpu_type = CPU_ARM8; 311 break; 312 313 default: 314 assert(!"Unsupported architecture type"); 315 return SPAWN_ERR_UNKNOWN_TARGET_ARCH; 316 } 317 318 return SYS_ERR_OK; 319} 320 321/** 322 * \brief Setup the dispatcher frame 323 */ 324bool setup_dispatcher_debug = false; 325static errval_t spawn_setup_dispatcher(struct spawninfo *si, 326 coreid_t core_id, 327 const char *name, 328 genvaddr_t entry, 329 void* arch_info) 330{ 331 errval_t err; 332 333 /* Create dispatcher frame (in taskcn) */ 334 si->dispframe.cnode = si->taskcn; 335 si->dispframe.slot = TASKCN_SLOT_DISPFRAME; 336 err = frame_create(si->dispframe, DISPATCHER_FRAME_SIZE, NULL); 337 if (err_is_fail(err)) { 338 return err_push(err, SPAWN_ERR_CREATE_DISPATCHER_FRAME); 339 } 340 341 /* Map in dispatcher frame */ 342 dispatcher_handle_t handle; 343 err = vspace_map_one_frame((void**)&handle, DISPATCHER_FRAME_SIZE, 344 si->dispframe, NULL, NULL); 345 if (err_is_fail(err)) { 346 return err_push(err, SPAWN_ERR_MAP_DISPATCHER_TO_SELF); 347 } 348 genvaddr_t spawn_dispatcher_base; 349 err = spawn_vspace_map_one_frame(si, &spawn_dispatcher_base, si->dispframe, 350 DISPATCHER_FRAME_SIZE); 351 if (err_is_fail(err)) { 352 return err_push(err, SPAWN_ERR_MAP_DISPATCHER_TO_NEW); 353 } 354 if (setup_dispatcher_debug) { 355 debug_printf("dispatcher frame mapped at 0x%"PRIxGENVADDR" in domain AS\n", 356 spawn_dispatcher_base); 357 } 358 359 /* Set initial state */ 360 // XXX: Confusion address translation about l/gen/addr in entry 361 struct dispatcher_shared_generic *disp = 362 get_dispatcher_shared_generic(handle); 363 struct dispatcher_generic *disp_gen = get_dispatcher_generic(handle); 364 arch_registers_state_t *enabled_area = 365 dispatcher_get_enabled_save_area(handle); 366 arch_registers_state_t *disabled_area = 367 dispatcher_get_disabled_save_area(handle); 368 369 /* Place core_id */ 370 disp_gen->core_id = core_id; 371 372 /* place eh information */ 373 disp_gen->eh_frame = si->eh_frame; 374 disp_gen->eh_frame_size = si->eh_frame_size; 375 disp_gen->eh_frame_hdr = si->eh_frame_hdr; 376 disp_gen->eh_frame_hdr_size = si->eh_frame_hdr_size; 377 378 /* Setup dispatcher and make it runnable */ 379 disp->udisp = spawn_dispatcher_base; 380 disp->disabled = 1; 381#ifdef __k1om__ 382 disp->xeon_phi_id = disp_xeon_phi_id(); 383#endif 384 385 // Copy the name for debugging 386 const char *copy_name = strrchr(name, '/'); 387 if (copy_name == NULL) { 388 copy_name = name; 389 } else { 390 copy_name++; 391 } 392 strncpy(disp->name, copy_name, DISP_NAME_LEN); 393 394 spawn_arch_set_registers(arch_info, handle, enabled_area, disabled_area); 395 registers_set_entry(disabled_area, entry); 396 397 si->handle = handle; 398 return SYS_ERR_OK; 399 400} 401 402errval_t spawn_map_bootinfo(struct spawninfo *si, genvaddr_t *retvaddr) 403{ 404 errval_t err; 405 406 struct capref src = { 407 .cnode = cnode_task, 408 .slot = TASKCN_SLOT_BOOTINFO 409 }; 410 struct capref dest = { 411 .cnode = si->taskcn, 412 .slot = TASKCN_SLOT_BOOTINFO 413 }; 414 err = cap_copy(dest, src); 415 if (err_is_fail(err)) { 416 return err_push(err, LIB_ERR_CAP_COPY); 417 } 418 419 err = spawn_vspace_map_one_frame(si, retvaddr, dest, BOOTINFO_SIZE); 420 if (err_is_fail(err)) { 421 return err_push(err, SPAWN_ERR_MAP_BOOTINFO); 422 } 423 424 return SYS_ERR_OK; 425} 426 427/** 428 * \brief Retrive the commandline args of #name 429 * 430 * The arguments are malloced into a new space so need to be freed after use 431 */ 432errval_t spawn_get_cmdline_args(struct mem_region *module, 433 char **retargs) 434{ 435 assert(module != NULL && retargs != NULL); 436 437 /* Get the cmdline args */ 438 const char *args = getopt_module(module); 439 440 /* Allocate space */ 441 *retargs = malloc(sizeof(char) * strlen(args)); 442 if (!retargs) { 443 return LIB_ERR_MALLOC_FAIL; 444 } 445 446 /* Copy args */ 447 strcpy(*retargs, args); 448 return SYS_ERR_OK; 449} 450 451/** 452 * \brief Returns tokenized cmdline args 453 * 454 * \param s Argument string, which is modified in place 455 * \param argv Array to be filled-in with arguments 456 * \param argv_len Length of array available in argv, including terminator 457 * 458 * The arguments are placed in #argv, which is NULL-terminated 459 * 460 * \returns Number of arguments, not including terminator 461 * 462 * \bug Very limited handling of quoting etc. 463 */ 464int spawn_tokenize_cmdargs(char *s, char *argv[], size_t argv_len) 465{ 466 bool inquote = false; 467 int argc = 0; 468 assert(argv_len > 1); 469 assert(s != NULL); 470 471 // consume leading whitespace, and mark first argument 472 while (*s == ' ' || *s == '\t') s++; 473 if (*s != '\0') { 474 argv[argc++] = s; 475 } 476 477 while (argc + 1 < argv_len && *s != '\0') { 478 if (*s == '"') { 479 inquote = !inquote; 480 // consume quote mark, by moving remainder of string over it 481 memmove(s, s + 1, strlen(s)); 482 } else if ((*s == ' ' || *s == '\t') && !inquote) { // First whitespace, arg finished 483 *s++ = '\0'; 484 while (*s == ' ' || *s == '\t') s++; // Consume trailing whitespace 485 if (*s != '\0') { // New arg started 486 argv[argc++] = s; 487 } 488 } else { 489 s++; 490 } 491 } 492 493 argv[argc] = NULL; 494 return argc; 495} 496 497/** 498 * \brief Setup arguments and environment 499 * 500 * \param argv Command-line arguments, NULL-terminated 501 * \param envp Environment, NULL-terminated 502 */ 503static errval_t spawn_setup_env(struct spawninfo *si, 504 char *const argv[], char *const envp[]) 505{ 506 errval_t err; 507 508 // Create frame (actually multiple pages) for arguments 509 si->argspg.cnode = si->taskcn; 510 si->argspg.slot = TASKCN_SLOT_ARGSPAGE; 511 err = frame_create(si->argspg, ARGS_SIZE, NULL); 512 if (err_is_fail(err)) { 513 return err_push(err, SPAWN_ERR_CREATE_ARGSPG); 514 } 515 516 /* Map in args frame */ 517 genvaddr_t spawn_args_base; 518 err = spawn_vspace_map_one_frame(si, &spawn_args_base, si->argspg, ARGS_SIZE); 519 if (err_is_fail(err)) { 520 return err_push(err, SPAWN_ERR_MAP_ARGSPG_TO_NEW); 521 } 522 523 void *argspg; 524 err = vspace_map_one_frame(&argspg, ARGS_SIZE, si->argspg, NULL, NULL); 525 if (err_is_fail(err)) { 526 return err_push(err, SPAWN_ERR_MAP_ARGSPG_TO_SELF); 527 } 528 529 /* Layout of arguments page: 530 * struct spawn_domain_params; // contains pointers to other fields 531 * char buf[]; // NUL-terminated strings for arguments and environment 532 * vspace layout data follows the string data 533 */ 534 struct spawn_domain_params *params = argspg; 535 char *buf = (char *)(params + 1); 536 size_t buflen = ARGS_SIZE - (buf - (char *)argspg); 537 538 /* Copy command-line arguments */ 539 int i; 540 size_t len; 541 for (i = 0; argv[i] != NULL; i++) { 542 len = strlen(argv[i]) + 1; 543 if (len > buflen) { 544 return SPAWN_ERR_ARGSPG_OVERFLOW; 545 } 546 strcpy(buf, argv[i]); 547 params->argv[i] = buf - (char *)argspg + (char *)(lvaddr_t)spawn_args_base; 548 buf += len; 549 buflen -= len; 550 } 551 assert(i <= MAX_CMDLINE_ARGS); 552 int argc = i; 553 params->argv[i] = NULL; 554 555 /* Copy environment strings */ 556 for (i = 0; envp[i] != NULL; i++) { 557 len = strlen(envp[i]) + 1; 558 if (len > buflen) { 559 return SPAWN_ERR_ARGSPG_OVERFLOW; 560 } 561 strcpy(buf, envp[i]); 562 params->envp[i] = buf - (char *)argspg + (char *)(lvaddr_t)spawn_args_base; 563 buf += len; 564 buflen -= len; 565 } 566 567 assert(i <= MAX_ENVIRON_VARS); 568 params->envp[i] = NULL; 569 570 /* Serialise vspace data */ 571 // XXX: align buf to next word 572 char *vspace_buf = (char *)ROUND_UP((lvaddr_t)buf, sizeof(uintptr_t)); 573 buflen -= vspace_buf - buf; 574 575 // FIXME: currently just the pmap is serialised 576 err = si->vspace->pmap->f.serialise(si->vspace->pmap, vspace_buf, buflen); 577 if (err_is_fail(err)) { 578 return err_push(err, SPAWN_ERR_SERIALISE_VSPACE); 579 } 580 581 /* Setup environment pointer and vspace pointer */ 582 params->argc = argc; 583 params->vspace_buf = (char *)vspace_buf - (char *)argspg 584 + (char *)(lvaddr_t)spawn_args_base; 585 params->vspace_buf_len = buflen; 586 587 // Setup TLS data 588 params->tls_init_base = (void *)vspace_genvaddr_to_lvaddr(si->tls_init_base); 589 params->tls_init_len = si->tls_init_len; 590 params->tls_total_len = si->tls_total_len; 591 592 arch_registers_state_t *enabled_area = 593 dispatcher_get_enabled_save_area(si->handle); 594 registers_set_param(enabled_area, (uintptr_t)spawn_args_base); 595 596 return SYS_ERR_OK; 597} 598 599/** 600 * Copies caps from inheritcnode into destination cnode, 601 * ignores caps that to not exist. 602 * 603 * \param inheritcn Source cnode 604 * \param inherit_slot Source cnode slot 605 * \param destcn Target cnode 606 * \param destcn_slot Target cnode slot 607 * 608 * \retval SYS_ERR_OK Copy to target was successful or source cap 609 * did not exist. 610 * \retval SPAWN_ERR_COPY_INHERITCN_CAP Error in cap_copy 611 */ 612static errval_t spawn_setup_inherited_cap(struct cnoderef inheritcn, 613 capaddr_t inherit_slot, 614 struct cnoderef destcn, 615 capaddr_t destcn_slot) 616{ 617 errval_t err; 618 619 struct capref src; 620 src.cnode = inheritcn; 621 src.slot = inherit_slot; 622 623 // Create frame (actually multiple pages) for fds 624 struct capref dest; 625 dest.cnode = destcn; 626 dest.slot = destcn_slot; 627 628 err = cap_copy(dest, src); 629 if (err_no(err) == SYS_ERR_SOURCE_CAP_LOOKUP) { 630 // there was no fdcap to inherit, continue 631 return SYS_ERR_OK; 632 } else if (err_is_fail(err)) { 633 return err_push(err, SPAWN_ERR_COPY_INHERITCN_CAP); 634 } 635 636 return SYS_ERR_OK; 637} 638 639/** 640 * Copies caps in inherited cnode into targets cspace. 641 * 642 * \param si Target spawninfo 643 * \param inheritcn_cap Cnode of caps to inherit 644 * \retval SYS_ERR_OK Caps have been copied. 645 */ 646static errval_t spawn_setup_inherited_caps(struct spawninfo *si, 647 struct capref inheritcn_cap) 648{ 649 errval_t err; 650 struct cnoderef inheritcn; 651 652 if (capref_is_null(inheritcn_cap)) { 653 return SYS_ERR_OK; 654 } 655 656 // Put inheritcn cap into root cnode so we can grab caps out of it 657 struct capref inheritcn_cncap; 658 err = slot_alloc_root(&inheritcn_cncap); 659 if (err_is_fail(err)) { 660 return err_push(err, LIB_ERR_SLOT_ALLOC); 661 } 662 663 err = cap_copy(inheritcn_cncap, inheritcn_cap); 664 if (err_is_fail(err)) { 665 return err_push(err, SPAWN_ERR_MINT_INHERITCN); 666 } 667 668 err = cnode_build_cnoderef(&inheritcn, inheritcn_cncap); 669 if (err_is_fail(err)) { 670 return err; 671 } 672 673 /* Copy the file descriptor frame cap over */ 674 err = spawn_setup_inherited_cap(inheritcn, INHERITCN_SLOT_FDSPAGE, 675 si->taskcn, TASKCN_SLOT_FDSPAGE); 676 if (err_is_fail(err)) { 677 return err_push(err, SPAWN_ERR_SETUP_FDCAP); 678 } 679 680 /* Copy the session capability over */ 681 err = spawn_setup_inherited_cap(inheritcn, INHERITCN_SLOT_SESSIONID, 682 si->taskcn, TASKCN_SLOT_SESSIONID); 683 if (err_is_fail(err)) { 684 return err_push(err, SPAWN_ERR_SETUP_SIDCAP); 685 } 686 687 /* Copy the kernel capability over, scary */ 688 err = spawn_setup_inherited_cap(inheritcn, INHERITCN_SLOT_KERNELCAP, 689 si->taskcn, TASKCN_SLOT_KERNELCAP); 690 if (err_is_fail(err)) { 691 return err_push(err, SPAWN_ERR_SETUP_KERNEL_CAP); 692 } 693 694 /* Cleanup our copy of inheritcn */ 695 err = cap_delete(inheritcn_cncap); 696 if (err_is_fail(err)) { 697 return err_push(err, LIB_ERR_CAP_DELETE); 698 } 699 err = slot_free(inheritcn_cncap); 700 if (err_is_fail(err)) { 701 return err_push(err, LIB_ERR_SLOT_FREE); 702 } 703 704 return SYS_ERR_OK; 705} 706 707static errval_t spawn_setup_argcn(struct spawninfo *si, 708 struct capref argumentcn_cap) 709{ 710 errval_t err; 711 712 if (capref_is_null(argumentcn_cap)) { 713 return SYS_ERR_OK; 714 } 715 716 struct capref dest = { 717 .cnode = si->rootcn, 718 .slot = ROOTCN_SLOT_ARGCN 719 }; 720 721 err = cap_copy(dest, argumentcn_cap); 722 if (err_is_fail(err)) { 723 return err_push(err, SPAWN_ERR_COPY_ARGCN); 724 } 725 726 return SYS_ERR_OK; 727} 728 729 730/** 731 * \brief Load an image 732 * 733 * \param si Struct used by the library 734 * \param binary The image to load 735 * \param type The type of arch to load for 736 * \param name Name of the image required only to place it in disp 737 * struct 738 * \param coreid Coreid to load for, required only to place it in disp 739 * struct 740 * \param argv Command-line arguments, NULL-terminated 741 * \param envp Environment, NULL-terminated 742 * \param inheritcn_cap Cap to a CNode containing capabilities to be inherited 743 * \param argcn_cap Cap to a CNode containing capabilities passed as 744 * arguments 745 */ 746errval_t spawn_load_image(struct spawninfo *si, lvaddr_t binary, 747 size_t binary_size, enum cpu_type type, 748 const char *name, coreid_t coreid, 749 char *const argv[], char *const envp[], 750 struct capref inheritcn_cap, struct capref argcn_cap) 751{ 752 errval_t err; 753 754 si->cpu_type = type; 755 756 /* Initialize cspace */ 757 err = spawn_setup_cspace(si); 758 if (err_is_fail(err)) { 759 return err_push(err, SPAWN_ERR_SETUP_CSPACE); 760 } 761 762 /* Initialize vspace */ 763 err = spawn_setup_vspace(si); 764 if (err_is_fail(err)) { 765 return err_push(err, SPAWN_ERR_VSPACE_INIT); 766 } 767 768 si->name = name; 769 genvaddr_t entry; 770 void* arch_info; 771 /* Load the image */ 772 err = spawn_arch_load(si, binary, binary_size, &entry, &arch_info); 773 if (err_is_fail(err)) { 774 return err_push(err, SPAWN_ERR_LOAD); 775 } 776 777 /* Setup dispatcher frame */ 778 err = spawn_setup_dispatcher(si, coreid, name, entry, arch_info); 779 if (err_is_fail(err)) { 780 return err_push(err, SPAWN_ERR_SETUP_DISPATCHER); 781 } 782 783 /* Setup inherited caps */ 784 err = spawn_setup_inherited_caps(si, inheritcn_cap); 785 if (err_is_fail(err)) { 786 return err_push(err, SPAWN_ERR_SETUP_INHERITED_CAPS); 787 } 788 789 /* Setup argument caps */ 790 err = spawn_setup_argcn(si, argcn_cap); 791 if (err_is_fail(err)) { 792 return err_push(err, SPAWN_ERR_SETUP_ARGCN); 793 } 794 795 // Add vspace-pspace mapping to environment 796 char *envstrp = NULL; 797#ifdef __x86__ // SK: si->vregions only valid on x86 798 char envstr[2048]; 799 envstrp = envstr; 800 snprintf(envstr, 2048, "ARRAKIS_PMAP="); 801 for(int i = 0; i < si->vregions; i++) { 802 struct memobj_anon *m = (struct memobj_anon *)si->vregion[i]->memobj; 803 assert(m->m.type == ANONYMOUS); 804 for(struct memobj_frame_list *f = m->frame_list; f != NULL; f = f->next) { 805 if (f->pa == 0) { 806 struct frame_identity id; 807 err = frame_identify(f->frame, &id); 808 assert(err_is_ok(err)); 809 f->pa = id.base; 810 } 811 812 char str[128]; 813 snprintf(str, 128, "%" PRIxGENVADDR ":%" PRIxGENPADDR ":%zx ", 814 si->base[i] + f->offset, f->pa + f->foffset, f->size); 815 strcat(envstr, str); 816 } 817 } 818#endif /* __x86__ */ 819 820 char **myenv = (char **)envp; 821 for(int i = 0; i < MAX_ENVIRON_VARS; i++) { 822 if(i + 1 == MAX_ENVIRON_VARS) { 823 printf("spawnd: Couldn't set environemnt. Out of variables!\n"); 824 abort(); 825 } 826 827 if(myenv[i] == NULL) { 828 myenv[i] = envstrp; 829 myenv[i+1] = NULL; 830 break; 831 } 832 } 833 834 /* Setup cmdline args */ 835 err = spawn_setup_env(si, argv, envp); 836 if (err_is_fail(err)) { 837 return err_push(err, SPAWN_ERR_SETUP_ENV); 838 } 839 840 return SYS_ERR_OK; 841} 842 843/** 844 * \brief Spawn a domain with the given args 845 */ 846errval_t spawn_load_with_args(struct spawninfo *si, struct mem_region *module, 847 const char *name, coreid_t coreid, 848 char *const argv[], char *const envp[]) 849{ 850 errval_t err; 851 852 /* Lookup and map the elf image */ 853 lvaddr_t binary; 854 size_t binary_size; 855 err = spawn_map_module(module, &binary_size, &binary, NULL); 856 //err = spawn_map(name, bi, &binary, &binary_size); 857 if (err_is_fail(err)) { 858 return err_push(err, SPAWN_ERR_ELF_MAP); 859 } 860 861 /* Determine cpu type */ 862 err = spawn_determine_cputype(si, binary); 863 if (err_is_fail(err)) { 864 return err_push(err, SPAWN_ERR_DETERMINE_CPUTYPE); 865 } 866 867 /* Initialize cspace */ 868 err = spawn_setup_cspace(si); 869 if (err_is_fail(err)) { 870 return err_push(err, SPAWN_ERR_SETUP_CSPACE); 871 } 872 873 /* Initialize vspace */ 874 err = spawn_setup_vspace(si); 875 if (err_is_fail(err)) { 876 return err_push(err, SPAWN_ERR_VSPACE_INIT); 877 } 878 879 /* Load the image */ 880 genvaddr_t entry; 881 void* arch_info; 882 si->name = name; 883 err = spawn_arch_load(si, binary, binary_size, &entry, &arch_info); 884 if (err_is_fail(err)) { 885 return err_push(err, SPAWN_ERR_LOAD); 886 } 887 888 /* Setup dispatcher frame */ 889 err = spawn_setup_dispatcher(si, coreid, name, entry, arch_info); 890 if (err_is_fail(err)) { 891 return err_push(err, SPAWN_ERR_SETUP_DISPATCHER); 892 } 893 894 /* Setup cmdline args */ 895 err = spawn_setup_env(si, argv, envp); 896 if (err_is_fail(err)) { 897 return err_push(err, SPAWN_ERR_SETUP_ENV); 898 } 899 900 return SYS_ERR_OK; 901} 902 903/** 904 * \brief Spawn a domain and give it the bootinfo struct. 905 * Just monitor and memserv should be spawned using this. 906 */ 907errval_t spawn_load_with_bootinfo(struct spawninfo *si, struct bootinfo *bi, 908 const char *name, coreid_t coreid) 909{ 910 errval_t err; 911 912 /* Get the module from the multiboot */ 913 struct mem_region *module = multiboot_find_module(bi, name); 914 if (module == NULL) { 915 return SPAWN_ERR_FIND_MODULE; 916 } 917 918 /* Lookup and map the elf image */ 919 lvaddr_t binary; 920 size_t binary_size; 921 err = spawn_map_module(module, &binary_size, &binary, NULL); 922 if (err_is_fail(err)) { 923 return err_push(err, SPAWN_ERR_ELF_MAP); 924 } 925 926 927 /* Determine cpu type */ 928 err = spawn_determine_cputype(si, binary); 929 if (err_is_fail(err)) { 930 return err_push(err, SPAWN_ERR_DETERMINE_CPUTYPE); 931 } 932 933 /* Initialize cspace */ 934 err = spawn_setup_cspace(si); 935 if (err_is_fail(err)) { 936 return err_push(err, SPAWN_ERR_SETUP_CSPACE); 937 } 938 939 /* Initialize vspace */ 940 err = spawn_setup_vspace(si); 941 if (err_is_fail(err)) { 942 return err_push(err, SPAWN_ERR_VSPACE_INIT); 943 } 944 945 /* Load the image */ 946 genvaddr_t entry; 947 void* arch_info; 948 si->name = name; 949 err = spawn_arch_load(si, binary, binary_size, &entry, &arch_info); 950 if (err_is_fail(err)) { 951 return err_push(err, SPAWN_ERR_LOAD); 952 } 953 954 /* Setup dispatcher frame */ 955 err = spawn_setup_dispatcher(si, coreid, name, entry, arch_info); 956 if (err_is_fail(err)) { 957 return err_push(err, SPAWN_ERR_SETUP_DISPATCHER); 958 } 959 960 /* Map bootinfo */ 961 // XXX: Confusion address translation about l/gen/addr in entry 962 genvaddr_t vaddr; 963 err = spawn_map_bootinfo(si, &vaddr); 964 if (err_is_fail(err)) { 965 return err_push(err, SPAWN_ERR_MAP_BOOTINFO); 966 } 967 968 /* Construct cmdline args, 0 is name, 1 is bootinfo address, 969 remaining are from the multiboot */ 970 // Name 971 char args[1024]; 972 strcpy(args, name); 973 strcat(args, " "); 974 975 // bootinfo addr 976 char vaddr_char[32]; 977 978 // NB format here should be PRIuGENVADDR, but our ARM compiler has 979 // an out-by-4 bytes issue when rendering 64-bit numbers using 980 // __builtin_va_start/__builtin_va_arg. 981 // [ gcc version 4.4.1 (Sourcery G++ Lite 2009q3-67) ] 982 snprintf(vaddr_char, sizeof(vaddr_char), "%" PRIuPTR, (uintptr_t)vaddr); 983 984 strcat(args, vaddr_char); 985 strcat(args, " "); 986 987 // Multiboot args 988 char *multiboot_args; 989 err = spawn_get_cmdline_args(module, &multiboot_args); 990 if (err_is_fail(err)) { 991 return err_push(err, SPAWN_ERR_GET_CMDLINE_ARGS); 992 } 993 // Lop off the name 994 char *multiboot_args_lop = strchr(multiboot_args, ' '); 995 if (multiboot_args_lop) { 996 multiboot_args_lop++; 997 strcat(args, multiboot_args_lop); 998 } 999 1000 // Tokenize 1001 char *argv[MAX_CMDLINE_ARGS + 1]; 1002 spawn_tokenize_cmdargs(args, argv, ARRAY_LENGTH(argv)); 1003 1004 // Setup 1005 err = spawn_setup_env(si, argv, environ); 1006 if (err_is_fail(err)) { 1007 return err_push(err, SPAWN_ERR_SETUP_ENV); 1008 } 1009 free(multiboot_args); 1010 1011 // unmap bootinfo module pages 1012 err = spawn_unmap_module(binary); 1013 if (err_is_fail(err)) { 1014 return err_push(err, SPAWN_ERR_UNMAP_MODULE); 1015 } 1016 1017 return SYS_ERR_OK; 1018} 1019 1020errval_t spawn_run(struct spawninfo *si) 1021{ 1022 return invoke_dispatcher(si->dcb, cap_dispatcher, si->rootcn_cap, 1023 si->vtree, si->dispframe, true); 1024} 1025 1026errval_t spawn_free(struct spawninfo *si) 1027{ 1028 cap_destroy(si->rootcn_cap); 1029 cap_destroy(si->dispframe); 1030 cap_destroy(si->dcb); 1031 cap_destroy(si->argspg); 1032 1033 return SYS_ERR_OK; 1034} 1035 1036/** 1037 * \brief Span a domain with the given vroot and disp_frame 1038 * 1039 * Operation similar to spawning a domain but the vroot and disp_frame 1040 * are already provided 1041 */ 1042errval_t spawn_span_domain(struct spawninfo *si, struct capref vroot, 1043 struct capref disp_frame) 1044{ 1045 errval_t err; 1046 struct capref t1; 1047 struct cnoderef cnode; 1048 1049 /* Spawn cspace */ 1050 err = spawn_setup_cspace(si); 1051 if (err_is_fail(err)) { 1052 return err; 1053 } 1054 1055 /* Create pagecn: default L2 CNode size */ 1056 t1.cnode = si->rootcn; 1057 t1.slot = ROOTCN_SLOT_PAGECN; 1058 err = cnode_create_raw(t1, NULL, ObjType_L2CNode, L2_CNODE_SLOTS, NULL); 1059 if (err_is_fail(err)) { 1060 return err_push(err, SPAWN_ERR_CREATE_PAGECN); 1061 } 1062 // XXX: fix build_cnoderef() 1063 cnode.croot = get_cap_addr(si->rootcn_cap); 1064 cnode.cnode = ROOTCN_SLOT_ADDR(ROOTCN_SLOT_PAGECN); 1065 cnode.level = CNODE_TYPE_OTHER; 1066 1067 // Copy root of pagetable 1068 si->vtree.cnode = cnode; 1069 si->vtree.slot = 0; 1070 err = cap_copy(si->vtree, vroot); 1071 if (err_is_fail(err)) { 1072 return err_push(err, SPAWN_ERR_COPY_VNODE); 1073 } 1074 1075 /* Copy dispatcher frame (in taskcn) */ 1076 si->dispframe.cnode = si->taskcn; 1077 si->dispframe.slot = TASKCN_SLOT_DISPFRAME; 1078 err = cap_copy(si->dispframe, disp_frame); 1079 if (err_is_fail(err)) { 1080 return err_push(err, SPAWN_ERR_COPY_VNODE); 1081 } 1082 1083 return SYS_ERR_OK; 1084} 1085