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