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