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