1/**
2 * \file
3 * \brief x86_32 kernel bootup code.
4 */
5
6/*
7 * Copyright (c) 2007-2013 ETH Zurich.
8 * Copyright (c) 2014, HP Labs.
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 <kernel.h>
17#include <string.h>
18#include <paging_kernel_arch.h>
19#include <elf/elf.h>
20#include <kernel_multiboot.h>
21#include <irq.h>
22#include <init.h>
23#include <barrelfish_kpi/cpu.h>
24#include <exec.h>
25#include <getopt/getopt.h>
26#include <dispatch.h>
27#include <barrelfish_kpi/init.h>
28#include <arch/x86/apic.h>
29#include <kputchar.h>
30#include <startup.h>
31#include <barrelfish_kpi/paging_arch.h>
32#include <barrelfish_kpi/syscalls.h>
33#include <target/x86/barrelfish_kpi/coredata_target.h>
34#include <arch/x86/startup_x86.h>
35
36/// Quick way to find the base address of a cnode capability
37#define CNODE(cte)     (cte)->cap.u.cnode.cnode
38
39/**
40 * init's needed boot pages.
41 */
42#define INIT_PDIR_SIZE          X86_32_PDIR_ENTRIES(X86_32_INIT_SPACE_LIMIT)
43#define INIT_PTABLE_SIZE        X86_32_PTABLE_ENTRIES(X86_32_INIT_SPACE_LIMIT)
44#define INIT_PAGE_BITMAP        X86_32_PTABLE_PRESENT
45
46/// Pointer to bootinfo structure for init
47static struct bootinfo *bootinfo = (struct bootinfo *)BOOTINFO_BASE;
48
49static struct spawn_state spawn_state;
50
51#ifdef CONFIG_PAE
52/**
53 * Page directory pointer table for init user address space.
54 */
55static union x86_32_pdpte_entry *init_pdpte; //[INIT_PDPT_SIZE][PTABLE_SIZE]
56#endif
57
58/**
59 * Page directory for init user address space.
60 */
61static union x86_32_pdir_entry *init_pdir; //[INIT_PDPT_SIZE][INIT_PDIR_SIZE][PTABLE_SIZE]
62
63/**
64 * Page tables for init user address space.
65 */
66static union x86_32_ptable_entry *init_ptable; //[INIT_PDPT_SIZE][INIT_PDIR_SIZE][INIT_PTABLE_SIZE][PTABLE_SIZE]
67
68/**
69 * \brief Convert elf flags to page flags
70 *
71 * \param flags ELF64 program segment flags.
72 *
73 * \return page flags.
74 *
75 * Not all combinations may be supported by an architecture
76 */
77static paging_x86_32_flags_t paging_elf_to_page_flags(uint32_t flags)
78{
79    paging_x86_32_flags_t pageflags = 0;
80
81    pageflags |= flags & PF_R ? PTABLE_USER_SUPERVISOR : 0;
82    pageflags |= flags & PF_W ? PTABLE_READ_WRITE : 0;
83    pageflags |= flags & PF_X ? 0 : PTABLE_EXECUTE_DISABLE;
84
85    return pageflags;
86}
87
88/**
89 * \brief Map init user-space memory.
90 *
91 * This function maps pages of the init user-space module. It expects
92 * the virtual base address 'vbase' of a program segment of the init executable,
93 * its size 'size' and its ELF64 access control flags. It maps pages
94 * to the sequential area of physical memory, given by 'base'. If you
95 * want to allocate physical memory frames as you go, you better use
96 * startup_alloc_init().
97 *
98 * \param vbase Virtual base address of program segment.
99 * \param base  Physical base address of program segment.
100 * \param size  Size of program segment in bytes.
101 * \param flags ELF64 access control flags of program segment.
102 */
103errval_t startup_map_init(lvaddr_t vbase, lpaddr_t base, size_t size,
104                          uint32_t flags)
105{
106    lvaddr_t vaddr;
107
108    paging_align(&vbase, &base, &size, BASE_PAGE_SIZE);
109    assert(vbase + size < X86_32_INIT_SPACE_LIMIT);
110
111    // Map pages
112    for(vaddr = vbase; vaddr < vbase + size;
113        vaddr += BASE_PAGE_SIZE, base += BASE_PAGE_SIZE) {
114#ifdef CONFIG_PAE
115        union x86_32_ptable_entry *ptable_base = &init_ptable[
116                    + X86_32_PDPTE_BASE(vaddr) * X86_32_PTABLE_SIZE * X86_32_PTABLE_SIZE
117                    + X86_32_PDIR_BASE(vaddr) * X86_32_PTABLE_SIZE
118                    + X86_32_PTABLE_BASE(vaddr)];
119
120        debug(SUBSYS_PAGING, "Mapping 4K page: vaddr = 0x%"PRIxLVADDR
121              ", base = 0x%"PRIxLPADDR", PDPTE_BASE = %lu, PDIR_BASE = %lu, "
122              "PTABLE_BASE = %lu -- ", vaddr, base, X86_32_PDPTE_BASE(vaddr),
123              X86_32_PDIR_BASE(vaddr), X86_32_PTABLE_BASE(vaddr));
124#else
125        union x86_32_ptable_entry *ptable_base = &init_ptable[
126                    X86_32_PDIR_BASE(vaddr) * X86_32_PTABLE_SIZE
127                    + X86_32_PTABLE_BASE(vaddr)];
128
129        debug(SUBSYS_PAGING, "Mapping 4K page: vaddr = 0x%"PRIxLVADDR
130                             ", base = 0x%"PRIxLPADDR", "
131              "PDIR_BASE = %"PRIuLPADDR", "
132              "PTABLE_BASE = %"PRIuLPADDR" -- ", vaddr, base,
133              X86_32_PDIR_BASE(vaddr), X86_32_PTABLE_BASE(vaddr));
134#endif
135
136        if(!X86_32_IS_PRESENT(ptable_base)) {
137            debug(SUBSYS_PAGING, "mapped!\n");
138            paging_x86_32_map(ptable_base, base,
139                       INIT_PAGE_BITMAP | paging_elf_to_page_flags(flags));
140        } else {
141            debug(SUBSYS_PAGING, "already existing!\n");
142        }
143    }
144
145    return SYS_ERR_OK;
146}
147
148/// Create physical address range or RAM caps to unused physical memory
149static void create_phys_caps(lpaddr_t init_alloc_addr)
150{
151    errval_t err;
152
153    // map first meg of RAM, which contains lots of crazy BIOS tables
154    err = create_caps_to_cnode(0, X86_32_START_KERNEL_PHYS,
155                               RegionType_PlatformData, &spawn_state, bootinfo);
156    assert(err_is_ok(err));
157
158    /* Walk multiboot MMAP structure, and create appropriate caps for memory */
159    char *mmap_addr = MBADDR_ASSTRING(glbl_core_data->mmap_addr);
160    genpaddr_t last_end_addr = 0;
161
162    char *clean_mmap_addr;
163    uint32_t clean_mmap_length;
164    cleanup_bios_regions(mmap_addr, &clean_mmap_addr, &clean_mmap_length);
165
166
167    for(char *m = mmap_addr; m < mmap_addr + glbl_core_data->mmap_length;) {
168        struct multiboot_mmap *mmap = (struct multiboot_mmap * SAFE)TC(m);
169
170        debug(SUBSYS_STARTUP, "MMAP %llx--%llx Type %"PRIu32"\n",
171              mmap->base_addr, mmap->base_addr + mmap->length,
172              mmap->type);
173
174#if 0
175        // XXX: Remove intersecting regions
176        bool skip = false;
177        for(int i = 0; i < bootinfo->regions_length; i++) {
178            struct mem_region *r = &bootinfo->regions[i];
179
180            // Remove intersecting regions (earlier additions take precedence)
181            if((r->base + (1 << r->bits) >= mmap->base_addr
182                && r->base + (1 << r->bits) <= mmap->base_addr + mmap->length)
183               || (r->base >= mmap->base_addr
184                   && r->base <= mmap->base_addr + mmap->length)) {
185                skip = true;
186                break;
187            }
188        }
189
190        if(skip) {
191            continue;
192        }
193#endif
194
195        if (last_end_addr >= init_alloc_addr
196            && mmap->base_addr > last_end_addr) {
197            /* we have a gap between regions. add this as a physaddr range */
198            debug(SUBSYS_STARTUP, "physical address range %llx--%llx\n",
199                  last_end_addr, mmap->base_addr);
200
201            err = create_caps_to_cnode(last_end_addr,
202                                       mmap->base_addr - last_end_addr,
203                                       RegionType_PhyAddr, &spawn_state, bootinfo);
204            assert(err_is_ok(err));
205        }
206
207        if (mmap->type == MULTIBOOT_MEM_TYPE_RAM) {
208            genpaddr_t base_addr = mmap->base_addr;
209            genpaddr_t end_addr  = base_addr + mmap->length;
210
211            // only map RAM which is greater than init_alloc_addr
212            if (end_addr > local_phys_to_gen_phys(init_alloc_addr)) {
213                if (base_addr < local_phys_to_gen_phys(init_alloc_addr)) {
214                    base_addr = local_phys_to_gen_phys(init_alloc_addr);
215                }
216
217#ifndef CONFIG_PAE
218                if(base_addr >= X86_32_PADDR_SPACE_SIZE) {
219                    printk(LOG_NOTE, "skipping RAM [%llx--%llx] out of "
220                           "mappable space\n", base_addr, end_addr);
221                    last_end_addr = mmap->base_addr + mmap->length;
222                    m += mmap->size + 4;
223                    continue;
224                }
225                if(end_addr > X86_32_PADDR_SPACE_SIZE) {
226                    printk(LOG_NOTE, "shortening RAM [%llx--%llx] to mappable "
227                           "space [0--%llx]\n", base_addr, end_addr,
228                           X86_32_PADDR_SPACE_LIMIT);
229                    end_addr = X86_32_PADDR_SPACE_SIZE;
230                }
231#endif
232
233                // XXX: Do not create ram caps for memory the kernel cannot
234                // address to prevent kernel objects from being created there
235                if(base_addr >= PADDR_SPACE_LIMIT) {
236                    last_end_addr = mmap->base_addr + mmap->length;
237                    m += mmap->size + 4;
238                    continue;
239                }
240                if (end_addr > PADDR_SPACE_LIMIT) {
241                    end_addr = PADDR_SPACE_LIMIT;
242                }
243
244                debug(SUBSYS_STARTUP, "RAM %llx--%llx\n", base_addr, end_addr);
245
246                assert(end_addr >= base_addr);
247                err = create_caps_to_cnode(base_addr, end_addr - base_addr,
248                                           RegionType_Empty, &spawn_state, bootinfo);
249                assert(err_is_ok(err));
250            }
251        } else if (mmap->base_addr > local_phys_to_gen_phys(init_alloc_addr)) {
252            /* XXX: The multiboot spec just says that mapping types other than
253             * RAM are "reserved", but GRUB always maps the ACPI tables as type
254             * 3, and things like the IOAPIC tend to show up as type 2 or 4,
255             * so we map all these regions as platform data
256             */
257            debug(SUBSYS_STARTUP, "platform %llx--%llx\n", mmap->base_addr,
258                  mmap->base_addr + mmap->length);
259            assert(mmap->base_addr > local_phys_to_gen_phys(init_alloc_addr));
260            err = create_caps_to_cnode(mmap->base_addr, mmap->length,
261                                       RegionType_PlatformData, &spawn_state, bootinfo);
262            assert(err_is_ok(err));
263        }
264
265        last_end_addr = mmap->base_addr + mmap->length;
266        m += mmap->size + 4;
267    }
268
269    // Assert that we have some physical address space
270    assert(last_end_addr != 0);
271
272    if (last_end_addr < X86_32_PADDR_SPACE_SIZE) {
273        /*
274         * FIXME: adding the full range results in too many caps to add
275         * to the cnode (and we can't handle such big caps in user-space
276         * yet anyway) so instead we limit it to something much smaller
277         */
278        genpaddr_t size = X86_32_PADDR_SPACE_SIZE - last_end_addr;
279        const genpaddr_t phys_region_limit = 1ULL << 32; // PCI implementation limit
280        if (last_end_addr > phys_region_limit) {
281            size = 0; // end of RAM is already too high!
282        } else if (last_end_addr + size > phys_region_limit) {
283            size = phys_region_limit - last_end_addr;
284        }
285        debug(SUBSYS_STARTUP, "end physical address range %llx--%llx\n",
286              last_end_addr, last_end_addr + size);
287        err = create_caps_to_cnode(last_end_addr, size,
288                                   RegionType_PhyAddr, &spawn_state, bootinfo);
289        assert(err_is_ok(err));
290    }
291}
292
293#define NEEDED_KERNEL_SPACE \
294    ((SIZE_KERNEL_IMAGE & 0x1000 ) == SIZE_KERNEL_IMAGE ? \
295    SIZE_KERNEL_IMAGE : \
296    (SIZE_KERNEL_IMAGE & 0xfffffffffffff000) + 0x1000)
297
298#define OBJSPERPAGE_CTE         (1 << (BASE_PAGE_BITS - OBJBITS_CTE))
299
300
301static void init_page_tables(struct spawn_state *st, alloc_phys_func alloc_phys)
302{
303    /* Allocate memory for init's page tables */
304#ifdef CONFIG_PAE
305    init_pdpte = (void *)local_phys_to_mem(alloc_phys(X86_32_PDPTE_SIZE
306                                           * sizeof(union x86_32_pdpte_entry)));
307#endif
308    init_pdir = (void *)local_phys_to_mem(
309                alloc_phys(X86_32_PTABLE_SIZE * INIT_PDIR_SIZE
310                           * sizeof(union x86_32_pdir_entry)));
311    init_ptable = (void *)local_phys_to_mem(
312                alloc_phys(X86_32_PTABLE_SIZE * INIT_PDIR_SIZE
313                           * INIT_PTABLE_SIZE * sizeof(union x86_32_ptable_entry)));
314
315    /* Page table setup */
316    /* Initialize init page tables */
317    for(size_t j = 0; j < INIT_PDIR_SIZE; j++) {
318        paging_x86_32_clear_pdir(&init_pdir[j]);
319        for(size_t k = 0; k < INIT_PTABLE_SIZE; k++) {
320            paging_x86_32_clear_ptable(&init_ptable[j * X86_32_PTABLE_SIZE + k]);
321        }
322    }
323    /* Map pagetables into pageCN */
324    int     pagecn_pagemap = 0;
325#ifdef CONFIG_PAE
326    // Map PDPTE into first slot in pagecn
327    caps_create_new(ObjType_VNode_x86_32_pdpt,
328                    mem_to_local_phys((lvaddr_t)init_pdpte),
329                    BASE_PAGE_BITS, 0, my_core_id,
330                    caps_locate_slot(CNODE(st->pagecn), pagecn_pagemap++));
331#endif
332    // Map PDIR into successive slots in pagecn
333    for(size_t i = 0; i < INIT_PDIR_SIZE; i++) {
334        caps_create_new(ObjType_VNode_x86_32_pdir,
335                        mem_to_local_phys((lvaddr_t)init_pdir) + i * BASE_PAGE_SIZE,
336                        BASE_PAGE_BITS, 0, my_core_id,
337                        caps_locate_slot(CNODE(st->pagecn), pagecn_pagemap++));
338    }
339    // Map page tables into successive slots in pagecn
340    for(size_t i = 0; i < INIT_PTABLE_SIZE; i++) {
341        caps_create_new(ObjType_VNode_x86_32_ptable,
342                        mem_to_local_phys((lvaddr_t)init_ptable) + i * BASE_PAGE_SIZE,
343                        BASE_PAGE_BITS, 0, my_core_id,
344                        caps_locate_slot(CNODE(st->pagecn), pagecn_pagemap++));
345    }
346    // Connect all page tables to page directories.
347    // init's memory manager expects page tables within the pagecn to
348    // already be connected to the corresponding directories. To avoid
349    // unneccessary special cases, we connect them here.
350    for(lvaddr_t vaddr = 0; vaddr < X86_32_INIT_SPACE_LIMIT;
351        vaddr += BASE_PAGE_SIZE) {
352#ifdef CONFIG_PAE
353        union x86_32_pdpte_entry *pdpte_base =
354            &init_pdpte[X86_32_PDPTE_BASE(vaddr)];
355        union x86_32_pdir_entry *pdir_base =
356            &init_pdir[X86_32_PDPTE_BASE(vaddr) * X86_32_PTABLE_SIZE +
357                       X86_32_PDIR_BASE(vaddr)];
358        union x86_32_ptable_entry *ptable_base =
359            &init_ptable[X86_32_PDPTE_BASE(vaddr) * X86_32_PTABLE_SIZE *
360                         X86_32_PTABLE_SIZE + X86_32_PDIR_BASE(vaddr) *
361                         X86_32_PTABLE_SIZE + X86_32_PTABLE_BASE(vaddr)];
362
363        paging_x86_32_map_pdpte(pdpte_base, mem_to_local_phys((lvaddr_t)pdir_base));
364#else
365        union x86_32_pdir_entry *pdir_base =
366            &init_pdir[X86_32_PDIR_BASE(vaddr)];
367        union x86_32_ptable_entry *ptable_base =
368            &init_ptable[X86_32_PDIR_BASE(vaddr) * X86_32_PTABLE_SIZE +
369                         X86_32_PTABLE_BASE(vaddr)];
370#endif
371        paging_x86_32_map_table(pdir_base,
372                                mem_to_local_phys((lvaddr_t)ptable_base));
373    }
374
375    /* Switch to init's VSpace */
376#ifdef CONFIG_PAE
377    paging_x86_32_context_switch(mem_to_local_phys((lvaddr_t)init_pdpte));
378#else
379    paging_x86_32_context_switch(mem_to_local_phys((lvaddr_t)init_pdir));
380#endif
381
382    /***** VSpace available *****/
383
384    /* Map cmdline args R/W into VSpace at ARGS_BASE */
385#ifdef CONFIG_PAE
386    paging_x86_32_map_pdpte(&init_pdpte[X86_32_PDPTE_BASE(ARGS_BASE)],
387                            mem_to_local_phys((lvaddr_t)init_pdir));
388#endif
389    paging_x86_32_map_table(&init_pdir[X86_32_PDIR_BASE(ARGS_BASE)],
390                            mem_to_local_phys((lvaddr_t)init_ptable));
391    for (int i = 0; i < ARGS_SIZE / BASE_PAGE_SIZE; i++) {
392        paging_x86_32_map(&init_ptable[X86_32_PTABLE_BASE(ARGS_BASE) + i],
393                   st->args_page + i * BASE_PAGE_SIZE,
394                   INIT_PAGE_BITMAP | paging_elf_to_page_flags(PF_R | PF_W));
395    }
396}
397
398static struct dcb *spawn_init_common(struct spawn_state *st, const char *name,
399                                     int argc, const char *argv[],
400                                     lpaddr_t bootinfo_phys,
401                                     alloc_phys_func alloc_phys,
402                                     alloc_phys_aligned_func alloc_phys_aligned)
403{
404    errval_t err;
405
406    /* Perform arch-independent spawn */
407    lvaddr_t paramaddr;
408    struct dcb *init_dcb = spawn_module(st, name, argc, argv, bootinfo_phys,
409                                        ARGS_BASE, alloc_phys, alloc_phys_aligned,
410                                        &paramaddr);
411
412
413
414    /* Init page tables */
415    init_page_tables(st, alloc_phys);
416
417    /* Map dispatcher R/W into VSpace starting at vaddr 0x204000
418     * (Starting after Bootinfo pages)*/
419#ifdef CONFIG_PAE
420    paging_x86_32_map_pdpte(&init_pdpte[X86_32_PDPTE_BASE(DISPATCHER_BASE)],
421                            mem_to_local_phys((lvaddr_t)init_pdir));
422#endif
423    paging_x86_32_map_table(&init_pdir[X86_32_PDIR_BASE(DISPATCHER_BASE)],
424                            mem_to_local_phys((lvaddr_t)init_ptable));
425    for (int i = 0; i < DISPATCHER_FRAME_SIZE / BASE_PAGE_SIZE; i++) {
426        paging_x86_32_map(&init_ptable[X86_32_PTABLE_BASE(DISPATCHER_BASE) + i],
427                   mem_to_local_phys(init_dcb->disp) + i * BASE_PAGE_SIZE,
428                   INIT_PAGE_BITMAP | paging_elf_to_page_flags(PF_R | PF_W));
429    }
430
431    struct dispatcher_shared_generic *init_disp =
432        get_dispatcher_shared_generic(init_dcb->disp);
433    struct dispatcher_shared_x86_32 *init_disp_x86_32 =
434        get_dispatcher_shared_x86_32(init_dcb->disp);
435
436    registers_set_param(&init_disp_x86_32->enabled_save_area, paramaddr);
437
438    // Map IO cap in task cnode
439    struct cte *iocap = caps_locate_slot(CNODE(st->taskcn), TASKCN_SLOT_IO);
440    err = caps_create_new(ObjType_IO, 0, 0, 0, my_core_id, iocap);
441    assert(err_is_ok(err));
442
443    /* Set fields in DCB */
444    // Set Vspace
445#ifdef CONFIG_PAE
446    init_dcb->vspace = mem_to_local_phys((lvaddr_t)init_pdpte);
447#else
448    init_dcb->vspace = mem_to_local_phys((lvaddr_t)init_pdir);
449#endif
450
451    /* Initialize dispatcher */
452    init_disp->disabled = true;
453    strncpy(init_disp->name, argv[0], DISP_NAME_LEN);
454
455    /* tell init the vspace addr of its dispatcher */
456    init_disp->udisp = DISPATCHER_BASE;
457
458    init_disp_x86_32->disabled_save_area.edi = DISPATCHER_BASE;
459    init_disp_x86_32->disabled_save_area.fs = 0;
460    init_disp_x86_32->disabled_save_area.gs = 0;
461    init_disp_x86_32->disabled_save_area.cs = USER_CS;
462    init_disp_x86_32->disabled_save_area.ss = USER_SS;
463    init_disp_x86_32->disabled_save_area.eflags = USER_EFLAGS;
464
465    return init_dcb;
466}
467
468struct dcb *spawn_bsp_init(const char *name, alloc_phys_func alloc_phys,
469                           alloc_phys_aligned_func alloc_phys_aligned)
470{
471    errval_t err;
472
473    /* Only the first core can run this code */
474    assert(apic_is_bsp());
475
476    /* Allocate bootinfo */
477    lpaddr_t bootinfo_phys = alloc_phys(BOOTINFO_SIZE);
478    memset((void *)local_phys_to_mem(bootinfo_phys), 0, BOOTINFO_SIZE);
479
480    /* Construct cmdline args */
481    char bootinfochar[16];
482    snprintf(bootinfochar, sizeof(bootinfochar), "%"PRIuLPADDR, BOOTINFO_BASE);
483
484    const char *argv[6] = { "init", bootinfochar };
485    int argc = 2;
486
487    struct dcb *init_dcb = spawn_init_common(&spawn_state, name, argc, argv,
488                                             bootinfo_phys, alloc_phys,
489                                             alloc_phys_aligned);
490
491    /* Map bootinfo R/W into VSpace at vaddr 0x200000 (BOOTINFO_BASE) */
492#ifdef CONFIG_PAE
493    paging_x86_32_map_pdpte(&init_pdpte[0], mem_to_local_phys((lvaddr_t)init_pdir));
494    paging_x86_32_map_table(&init_pdir[1], mem_to_local_phys((lvaddr_t)init_ptable));
495    for (int i = 0; i < BOOTINFO_SIZE / BASE_PAGE_SIZE; i++) {
496        paging_x86_32_map(&init_ptable[i], bootinfo_phys + i * BASE_PAGE_SIZE,
497                   INIT_PAGE_BITMAP | paging_elf_to_page_flags(PF_R|PF_W));
498    }
499#else
500    paging_x86_32_map_table(&init_pdir[0], mem_to_local_phys((lvaddr_t)init_ptable));
501    for (int i = 0; i < BOOTINFO_SIZE / BASE_PAGE_SIZE; i++) {
502        paging_x86_32_map(&init_ptable[i + 512], bootinfo_phys + i * BASE_PAGE_SIZE,
503                   INIT_PAGE_BITMAP | paging_elf_to_page_flags(PF_R|PF_W));
504    }
505#endif
506
507    /* Load init ELF32 binary */
508    struct multiboot_modinfo *module = multiboot_find_module(name);
509    if (module == NULL) {
510        panic("Could not find init module!");
511    }
512    genvaddr_t init_ep;
513    err = elf_load(EM_386, startup_alloc_init, &spawn_state,
514                   local_phys_to_mem(module->mod_start),
515                   MULTIBOOT_MODULE_SIZE(*module), &init_ep);
516    if (err_is_fail(err)) {
517        //err_print_calltrace(err);
518        panic("ELF load of init module failed!");
519    }
520
521    struct dispatcher_shared_x86_32 *init_disp_x86_32 =
522        get_dispatcher_shared_x86_32(init_dcb->disp);
523    init_disp_x86_32->disabled_save_area.eip = init_ep;
524
525    /* Create caps for init to use */
526    create_module_caps(&spawn_state);
527    lpaddr_t init_alloc_end = alloc_phys(0); // XXX
528    create_phys_caps(init_alloc_end);
529
530    /* Fill bootinfo struct */
531    bootinfo->mem_spawn_core = NEEDED_KERNEL_SPACE; // Size of kernel
532
533    /* for (int i = 0; i < bootinfo->regions_length; i++) { */
534    /*     printf("%d region %d: 0x%09" PRIxPTR " - 0x%09lx (%lu MB, %u bits)\n", */
535    /*            bootinfo->regions[i].mr_type, i, bootinfo->regions[i].mr_base, */
536    /*            bootinfo->regions[i].mr_base + (1UL<<bootinfo->regions[i].mr_bits), */
537    /*            bootinfo->regions[i].mr_bits >= 20 */
538    /*            ? 1UL << (bootinfo->regions[i].mr_bits - 20) : 0, */
539    /*            bootinfo->regions[i].mr_bits); */
540    /* } */
541
542    return init_dcb;
543}
544
545struct dcb *spawn_app_init(struct x86_core_data *core_data,
546                           const char *name, alloc_phys_func alloc_phys,
547                           alloc_phys_aligned_func alloc_phys_aligned)
548{
549    errval_t err;
550
551    /* Construct cmdline args */
552    // Core id of the core that booted this core
553    char coreidchar[10];
554    snprintf(coreidchar, sizeof(coreidchar), "%d", core_data->src_core_id);
555
556    // IPI channel id of core that booted this core
557    char chanidchar[30];
558    snprintf(chanidchar, sizeof(chanidchar), "chanid=%"PRIu32, core_data->chan_id);
559
560    // Arch id of the core that booted this core
561    char archidchar[30];
562    snprintf(archidchar, sizeof(archidchar), "archid=%d",
563             core_data->src_arch_id);
564
565    const char *argv[5] = { name, coreidchar, chanidchar, archidchar };
566    int argc = 4;
567
568    struct dcb *init_dcb = spawn_init_common(&spawn_state, name, argc, argv,
569                                             0, alloc_phys, alloc_phys_aligned);
570
571    // Urpc frame cap
572    struct cte *urpc_frame_cte = caps_locate_slot(CNODE(spawn_state.taskcn),
573                                                  TASKCN_SLOT_MON_URPC);
574    // XXX: Create as devframe so the memory is not zeroed out
575    err = caps_create_new(ObjType_DevFrame, core_data->urpc_frame_base,
576                          core_data->urpc_frame_bits,
577                          core_data->urpc_frame_bits, core_data->src_core_id,
578                          urpc_frame_cte);
579    assert(err_is_ok(err));
580    urpc_frame_cte->cap.type = ObjType_Frame;
581    lpaddr_t urpc_ptr = gen_phys_to_local_phys(urpc_frame_cte->cap.u.frame.base);
582
583    /* Map urpc frame at MON_URPC_BASE */
584#ifdef CONFIG_PAE
585    paging_x86_32_map_pdpte(&init_pdpte[X86_32_PDPTE_BASE(MON_URPC_BASE)],
586                            mem_to_local_phys((lvaddr_t)init_pdir));
587#endif
588    paging_x86_32_map_table(&init_pdir[X86_32_PDIR_BASE(MON_URPC_BASE)],
589                            mem_to_local_phys((lvaddr_t)init_ptable));
590    for (int i = 0; i < MON_URPC_SIZE / BASE_PAGE_SIZE; i++) {
591        paging_x86_32_map(&init_ptable[X86_32_PTABLE_BASE(MON_URPC_BASE) + i],
592                   urpc_ptr + i * BASE_PAGE_SIZE,
593                   INIT_PAGE_BITMAP | paging_elf_to_page_flags(PF_R | PF_W));
594    }
595
596    // elf load the domain
597    genvaddr_t entry_point;
598    err = elf_load(EM_386, startup_alloc_init, &spawn_state,
599                   local_phys_to_mem(core_data->monitor_binary),
600                   core_data->monitor_binary_size, &entry_point);
601    if (err_is_fail(err)) {
602        //err_print_calltrace(err);
603        panic("ELF load of init module failed!");
604    }
605
606    struct dispatcher_shared_x86_32 *init_disp_x86_32 =
607        get_dispatcher_shared_x86_32(init_dcb->disp);
608    init_disp_x86_32->disabled_save_area.eip = entry_point;
609
610    return init_dcb;
611}
612