Add BF_BINARY_PREFIX define to configure binary path by build system.
[barrelfish] / kernel / arch / arm_gem5 / startup_arch.c
1 /*
2  * Copyright (c) 2009, 2010 ETH Zurich.
3  * All rights reserved.
4  *
5  * This file is distributed under the terms in the attached LICENSE file.
6  * If you do not find this file, copies can be found by writing to:
7  * ETH Zurich D-INFK, Haldeneggsteig 4, CH-8092 Zurich. Attn: Systems Group.
8  */
9
10 #include <kernel.h>
11 #include <dispatch.h>
12 #include <string.h>
13 #include <stdio.h>
14
15 #include <barrelfish_kpi/init.h>
16 #include <barrelfish_kpi/syscalls.h>
17 #include <elf/elf.h>
18
19 #include <arm_hal.h>
20 #include <paging_kernel_arch.h>
21 #include <exceptions.h>
22 #include <cp15.h>
23 #include <cpiobin.h>
24 #include <init.h>
25 #include <barrelfish_kpi/paging_arm_v7.h>
26 #include <barrelfish_kpi/arm_core_data.h>
27 #include <kernel_multiboot.h>
28 #include <offsets.h>
29 #include <startup_arch.h>
30 #include <global.h>
31
32 #define CNODE(cte)              (cte)->cap.u.cnode.cnode
33 #define UNUSED(x)               (x) = (x)
34
35 #define STARTUP_PROGRESS()      debug(SUBSYS_STARTUP, "%s:%d\n",          \
36                                       __FUNCTION__, __LINE__);
37
38 #define BSP_INIT_MODULE_NAME    BF_BINARY_PREFIX "armv7/sbin/init"
39 #define APP_INIT_MODULE_NAME    BF_BINARY_PREFIX "armv7/sbin/monitor"
40
41
42
43 //static phys_mmap_t* g_phys_mmap;        // Physical memory map
44 static union arm_l1_entry * init_l1;              // L1 page table for init
45 static union arm_l2_entry * init_l2;              // L2 page tables for init
46
47 static struct spawn_state spawn_state;
48
49 /// Pointer to bootinfo structure for init
50 struct bootinfo* bootinfo = (struct bootinfo*)INIT_BOOTINFO_VBASE;
51
52 /**
53  * Each kernel has a local copy of global and locks. However, during booting and
54  * kernel relocation, these are set to point to global of the pristine kernel,
55  * so that all the kernels can share it.
56  */
57 //static  struct global myglobal;
58 struct global *global = (struct global *)GLOBAL_VBASE;
59
60 static inline uintptr_t round_up(uintptr_t value, size_t unit)
61 {
62     assert(0 == (unit & (unit - 1)));
63     size_t m = unit - 1;
64     return (value + m) & ~m;
65 }
66
67 static inline uintptr_t round_down(uintptr_t value, size_t unit)
68 {
69     assert(0 == (unit & (unit - 1)));
70     size_t m = unit - 1;
71     return value & ~m;
72 }
73
74 // Physical memory allocator for spawn_app_init
75 static lpaddr_t app_alloc_phys_start, app_alloc_phys_end;
76 static lpaddr_t app_alloc_phys(size_t size)
77 {
78     uint32_t npages = (size + BASE_PAGE_SIZE - 1) / BASE_PAGE_SIZE;
79
80
81     lpaddr_t addr = app_alloc_phys_start;
82     app_alloc_phys_start += npages * BASE_PAGE_SIZE;
83
84     if (app_alloc_phys_start >= app_alloc_phys_end) {
85         panic("Out of memory, increase CORE_DATA_PAGES");
86     }
87
88     return addr;
89 }
90
91 static lpaddr_t app_alloc_phys_aligned(size_t size, size_t align)
92 {
93         app_alloc_phys_start = round_up(app_alloc_phys_start, align);
94         return app_alloc_phys(size);
95 }
96
97 /**
98  * The address from where bsp_alloc_phys will start allocating memory
99  */
100 static lpaddr_t bsp_init_alloc_addr = 0;
101
102 /**
103  * \brief Linear physical memory allocator.
104  *
105  * This function allocates a linear region of addresses of size 'size' from
106  * physical memory.
107  *
108  * \param size  Number of bytes to allocate.
109  *
110  * \return Base physical address of memory region.
111  */
112 static lpaddr_t bsp_alloc_phys(size_t size)
113 {
114     // round to base page size
115     uint32_t npages = (size + BASE_PAGE_SIZE - 1) / BASE_PAGE_SIZE;
116
117     assert(bsp_init_alloc_addr != 0);
118
119     lpaddr_t addr = bsp_init_alloc_addr;
120
121     bsp_init_alloc_addr += npages * BASE_PAGE_SIZE;
122     return addr;
123 }
124
125 static lpaddr_t bsp_alloc_phys_aligned(size_t size, size_t align)
126 {
127         bsp_init_alloc_addr = round_up(bsp_init_alloc_addr, align);
128         return bsp_alloc_phys(size);
129 }
130
131 /**
132  * Map frames into init process address space. Init has a contiguous set of
133  * l2 entries so this is straightforward.
134  *
135  * @param l2_table      pointer to init's L2 table.
136  * @param l2_base       virtual address represented by first L2 table entry
137  * @param va_base       virtual address to map.
138  * @param pa_base       physical address to associate with virtual address.
139  * @param bytes        number of bytes to map.
140  * @param l2_flags      ARM L2 small page flags for mapped pages.
141  */
142 static void
143 spawn_init_map(union arm_l2_entry* l2_table,
144                lvaddr_t   l2_base,
145                lvaddr_t   va_base,
146                lpaddr_t   pa_base,
147                size_t     bytes,
148                uintptr_t  l2_flags)
149 {
150     assert(va_base >= l2_base);
151     assert(0 == (va_base & (BASE_PAGE_SIZE - 1)));
152     assert(0 == (pa_base & (BASE_PAGE_SIZE - 1)));
153     assert(0 == (bytes & (BASE_PAGE_SIZE - 1)));
154
155     int bi = (va_base - l2_base) / BASE_PAGE_SIZE;
156     int li = bi + bytes / BASE_PAGE_SIZE;
157
158     while (bi < li)
159     {
160         paging_set_l2_entry((uintptr_t *)&l2_table[bi], pa_base, l2_flags);
161         pa_base += BASE_PAGE_SIZE;
162         bi++;
163     }
164 }
165
166 static uint32_t elf_to_l2_flags(uint32_t eflags)
167 {
168     switch (eflags & (PF_W|PF_R))
169     {
170       case PF_W|PF_R:
171         return (ARM_L2_SMALL_USR_RW |
172                 ARM_L2_SMALL_CACHEABLE |
173                 ARM_L2_SMALL_BUFFERABLE);
174       case PF_R:
175         return (ARM_L2_SMALL_USR_RO |
176                 ARM_L2_SMALL_CACHEABLE |
177                 ARM_L2_SMALL_BUFFERABLE);
178       default:
179         panic("Unknown ELF flags combination.");
180     }
181 }
182
183 struct startup_l2_info
184 {
185     union arm_l2_entry* l2_table;
186     lvaddr_t   l2_base;
187 };
188
189 static errval_t
190 startup_alloc_init(
191     void*      state,
192     genvaddr_t gvbase,
193     size_t     bytes,
194     uint32_t   flags,
195     void**     ret
196     )
197 {
198     const struct startup_l2_info* s2i = (const struct startup_l2_info*)state;
199
200     lvaddr_t sv = round_down((lvaddr_t)gvbase, BASE_PAGE_SIZE);
201     size_t   off = (lvaddr_t)gvbase - sv;
202     lvaddr_t lv = round_up((lvaddr_t)gvbase + bytes, BASE_PAGE_SIZE);
203     lpaddr_t pa;
204
205     //STARTUP_PROGRESS();
206     if(hal_cpu_is_bsp())
207         pa = bsp_alloc_phys_aligned((lv - sv), BASE_PAGE_SIZE);
208     else
209         pa = app_alloc_phys_aligned((lv - sv), BASE_PAGE_SIZE);
210
211     if (lv > sv && (pa != 0))
212     {
213         spawn_init_map(s2i->l2_table, s2i->l2_base, sv,
214                        pa, lv - sv, elf_to_l2_flags(flags));
215         *ret = (void*)(local_phys_to_mem(pa) + off);
216     }
217     else
218     {
219         *ret = 0;
220     }
221     return SYS_ERR_OK;
222 }
223
224 static void
225 load_init_image(
226     struct startup_l2_info* l2i,
227     const char *name,
228     genvaddr_t* init_ep,
229     genvaddr_t* got_base
230     )
231 {
232     lvaddr_t elf_base;
233     size_t elf_bytes;
234     errval_t err;
235
236
237     *init_ep = *got_base = 0;
238
239     /* Load init ELF32 binary */
240     struct multiboot_modinfo *module = multiboot_find_module(name);
241     if (module == NULL) {
242         panic("Could not find init module!");
243     }
244
245     elf_base =  local_phys_to_mem(module->mod_start);
246     elf_bytes = MULTIBOOT_MODULE_SIZE(*module);
247
248     debug(SUBSYS_STARTUP, "load_init_image %p %08x\n", elf_base, elf_bytes);
249     //printf("load_init_image %p %08x\n", elf_base, elf_bytes);
250
251     err = elf_load(EM_ARM, startup_alloc_init, l2i,
252                 elf_base, elf_bytes, init_ep);
253     if (err_is_fail(err)) {
254         //err_print_calltrace(err);
255         panic("ELF load of " BSP_INIT_MODULE_NAME " failed!\n");
256     }
257
258     // TODO: Fix application linkage so that it's non-PIC.
259     struct Elf32_Shdr* got_shdr =
260         elf32_find_section_header_name((lvaddr_t)elf_base, elf_bytes, ".got");
261     if (got_shdr)
262     {
263         *got_base = got_shdr->sh_addr;
264     }
265 }
266
267 /// Setup the module cnode, which contains frame caps to all multiboot modules
268 void create_module_caps(struct spawn_state *st)
269 {
270     errval_t err;
271
272     /* Create caps for multiboot modules */
273     struct multiboot_modinfo *module =
274         (struct multiboot_modinfo *)local_phys_to_mem(glbl_core_data->mods_addr);
275
276     // Allocate strings area
277     lpaddr_t mmstrings_phys = bsp_alloc_phys(BASE_PAGE_SIZE);
278     lvaddr_t mmstrings_base = local_phys_to_mem(mmstrings_phys);
279     lvaddr_t mmstrings = mmstrings_base;
280
281     // create cap for strings area in first slot of modulecn
282     assert(st->modulecn_slot == 0);
283     err = caps_create_new(ObjType_Frame, mmstrings_phys, BASE_PAGE_BITS,
284                           BASE_PAGE_BITS, my_core_id,
285                           caps_locate_slot(CNODE(st->modulecn),
286                                            st->modulecn_slot++));
287     assert(err_is_ok(err));
288
289     /* Walk over multiboot modules, creating frame caps */
290     for (int i = 0; i < glbl_core_data->mods_count; i++) {
291         struct multiboot_modinfo *m = &module[i];
292
293         // Set memory regions within bootinfo
294         struct mem_region *region =
295             &bootinfo->regions[bootinfo->regions_length++];
296
297         genpaddr_t remain = MULTIBOOT_MODULE_SIZE(*m);
298         genpaddr_t base_addr = local_phys_to_gen_phys(m->mod_start);
299
300         region->mr_type = RegionType_Module;
301         region->mr_base = base_addr;
302         region->mrmod_slot = st->modulecn_slot;  // first slot containing caps
303         region->mrmod_size = remain;  // size of image _in bytes_
304         region->mrmod_data = mmstrings - mmstrings_base; // offset of string in area
305
306         // round up to page size for caps
307         remain = ROUND_UP(remain, BASE_PAGE_SIZE);
308
309         // Create max-sized caps to multiboot module in module cnode
310         while (remain > 0) {
311             assert((base_addr & BASE_PAGE_MASK) == 0);
312             assert((remain & BASE_PAGE_MASK) == 0);
313
314             // determine size of next chunk
315             uint8_t block_size = bitaddralign(remain, base_addr);
316
317             assert(st->modulecn_slot < (1UL << st->modulecn->cap.u.cnode.bits));
318             // create as DevFrame cap to avoid zeroing memory contents
319             err = caps_create_new(ObjType_DevFrame, base_addr, block_size,
320                                   block_size, my_core_id,
321                                   caps_locate_slot(CNODE(st->modulecn),
322                                                    st->modulecn_slot++));
323             assert(err_is_ok(err));
324
325             // Advance by that chunk
326             base_addr += ((genpaddr_t)1 << block_size);
327             remain -= ((genpaddr_t)1 << block_size);
328         }
329
330         // Copy multiboot module string to mmstrings area
331         strcpy((char *)mmstrings, MBADDR_ASSTRING(m->string));
332         mmstrings += strlen(MBADDR_ASSTRING(m->string)) + 1;
333         assert(mmstrings < mmstrings_base + BASE_PAGE_SIZE);
334     }
335 }
336
337 /// Create physical address range or RAM caps to unused physical memory
338 static void create_phys_caps(lpaddr_t init_alloc_addr)
339 {
340         errval_t err;
341
342         /* Walk multiboot MMAP structure, and create appropriate caps for memory */
343         char *mmap_addr = MBADDR_ASSTRING(glbl_core_data->mmap_addr);
344         genpaddr_t last_end_addr = 0;
345
346         for(char *m = mmap_addr; m < mmap_addr + glbl_core_data->mmap_length;)
347         {
348                 struct multiboot_mmap *mmap = (struct multiboot_mmap * SAFE)TC(m);
349
350                 debug(SUBSYS_STARTUP, "MMAP %llx--%llx Type %"PRIu32"\n",
351                                 mmap->base_addr, mmap->base_addr + mmap->length,
352                                 mmap->type);
353
354                 if (last_end_addr >= init_alloc_addr
355                                 && mmap->base_addr > last_end_addr)
356                 {
357                         /* we have a gap between regions. add this as a physaddr range */
358                         debug(SUBSYS_STARTUP, "physical address range %llx--%llx\n",
359                                         last_end_addr, mmap->base_addr);
360
361                         err = create_caps_to_cnode(last_end_addr,
362                                         mmap->base_addr - last_end_addr,
363                                         RegionType_PhyAddr, &spawn_state, bootinfo);
364                         assert(err_is_ok(err));
365                 }
366
367                 if (mmap->type == MULTIBOOT_MEM_TYPE_RAM)
368                 {
369                         genpaddr_t base_addr = mmap->base_addr;
370                         genpaddr_t end_addr  = base_addr + mmap->length;
371
372                         // only map RAM which is greater than init_alloc_addr
373                         if (end_addr > local_phys_to_gen_phys(init_alloc_addr))
374                         {
375                                 if (base_addr < local_phys_to_gen_phys(init_alloc_addr)) {
376                                         base_addr = local_phys_to_gen_phys(init_alloc_addr);
377                                 }
378                                 debug(SUBSYS_STARTUP, "RAM %llx--%llx\n", base_addr, end_addr);
379
380                                 assert(end_addr >= base_addr);
381                                 err = create_caps_to_cnode(base_addr, end_addr - base_addr,
382                                                 RegionType_Empty, &spawn_state, bootinfo);
383                                 assert(err_is_ok(err));
384                         }
385                 }
386                 else if (mmap->base_addr > local_phys_to_gen_phys(init_alloc_addr))
387                 {
388                         /* XXX: The multiboot spec just says that mapping types other than
389                          * RAM are "reserved", but GRUB always maps the ACPI tables as type
390                          * 3, and things like the IOAPIC tend to show up as type 2 or 4,
391                          * so we map all these regions as platform data
392                          */
393                         debug(SUBSYS_STARTUP, "platform %llx--%llx\n", mmap->base_addr,
394                                         mmap->base_addr + mmap->length);
395                         assert(mmap->base_addr > local_phys_to_gen_phys(init_alloc_addr));
396                         err = create_caps_to_cnode(mmap->base_addr, mmap->length,
397                                         RegionType_PlatformData, &spawn_state, bootinfo);
398                         assert(err_is_ok(err));
399                 }
400         last_end_addr = mmap->base_addr + mmap->length;
401         m += mmap->size + 4;
402         }
403
404     // Assert that we have some physical address space
405     assert(last_end_addr != 0);
406
407     if (last_end_addr < PADDR_SPACE_SIZE)
408     {
409         /*
410          * FIXME: adding the full range results in too many caps to add
411          * to the cnode (and we can't handle such big caps in user-space
412          * yet anyway) so instead we limit it to something much smaller
413          */
414         genpaddr_t size = PADDR_SPACE_SIZE - last_end_addr;
415         const genpaddr_t phys_region_limit = 1ULL << 32; // PCI implementation limit
416         if (last_end_addr > phys_region_limit) {
417                 size = 0; // end of RAM is already too high!
418         } else if (last_end_addr + size > phys_region_limit) {
419                 size = phys_region_limit - last_end_addr;
420         }
421         debug(SUBSYS_STARTUP, "end physical address range %llx--%llx\n",
422                         last_end_addr, last_end_addr + size);
423         err = create_caps_to_cnode(last_end_addr, size,
424                         RegionType_PhyAddr, &spawn_state, bootinfo);
425         assert(err_is_ok(err));
426     }
427 }
428
429 static void init_page_tables(void)
430 {
431         // Create page table for init
432         if(hal_cpu_is_bsp())
433         {
434                 init_l1 =  (union arm_l1_entry *)local_phys_to_mem(bsp_alloc_phys_aligned(INIT_L1_BYTES, ARM_L1_ALIGN));
435                 memset(init_l1, 0, INIT_L1_BYTES);
436
437                 init_l2 = (union arm_l2_entry *)local_phys_to_mem(bsp_alloc_phys_aligned(INIT_L2_BYTES, ARM_L2_ALIGN));
438                 memset(init_l2, 0, INIT_L2_BYTES);
439         }
440         else
441         {
442                 init_l1 =  (union arm_l1_entry *)local_phys_to_mem(app_alloc_phys_aligned(INIT_L1_BYTES, ARM_L1_ALIGN));
443                 memset(init_l1, 0, INIT_L1_BYTES);
444
445                 init_l2 = (union arm_l2_entry *)local_phys_to_mem(app_alloc_phys_aligned(INIT_L2_BYTES, ARM_L2_ALIGN));
446                 memset(init_l2, 0, INIT_L2_BYTES);
447         }
448
449
450         /* Map pagetables into page CN */
451         int pagecn_pagemap = 0;
452
453         /*
454          * ARM has:
455          *
456          * L1 has 4096 entries (16KB).
457          * L2 Coarse has 256 entries (256 * 4B = 1KB).
458          *
459          * CPU driver currently fakes having 1024 entries in L1 and
460          * L2 with 1024 entries by treating a page as 4 consecutive
461          * L2 tables and mapping this as a unit in L1.
462          */
463         caps_create_new(
464                         ObjType_VNode_ARM_l1,
465                         mem_to_local_phys((lvaddr_t)init_l1),
466                         vnode_objbits(ObjType_VNode_ARM_l1), 0,
467                         my_core_id,
468                         caps_locate_slot(CNODE(spawn_state.pagecn), pagecn_pagemap++)
469         );
470
471         //STARTUP_PROGRESS();
472
473         // Map L2 into successive slots in pagecn
474         size_t i;
475         for (i = 0; i < INIT_L2_BYTES / BASE_PAGE_SIZE; i++) {
476                 size_t objbits_vnode = vnode_objbits(ObjType_VNode_ARM_l2);
477                 assert(objbits_vnode == BASE_PAGE_BITS);
478                 caps_create_new(
479                                 ObjType_VNode_ARM_l2,
480                                 mem_to_local_phys((lvaddr_t)init_l2) + (i << objbits_vnode),
481                                 objbits_vnode, 0,
482                                 my_core_id,
483                                 caps_locate_slot(CNODE(spawn_state.pagecn), pagecn_pagemap++)
484                 );
485         }
486
487         /*
488          * Initialize init page tables - this just wires the L1
489          * entries through to the corresponding L2 entries.
490          */
491         STATIC_ASSERT(0 == (INIT_VBASE % ARM_L1_SECTION_BYTES), "");
492         for (lvaddr_t vaddr = INIT_VBASE; vaddr < INIT_SPACE_LIMIT; vaddr += ARM_L1_SECTION_BYTES)
493         {
494                 uintptr_t section = (vaddr - INIT_VBASE) / ARM_L1_SECTION_BYTES;
495                 uintptr_t l2_off = section * ARM_L2_TABLE_BYTES;
496                 lpaddr_t paddr = mem_to_local_phys((lvaddr_t)init_l2) + l2_off;
497                 paging_map_user_pages_l1((lvaddr_t)init_l1, vaddr, paddr);
498         }
499
500         paging_context_switch(mem_to_local_phys((lvaddr_t)init_l1));
501 }
502
503 static struct dcb *spawn_init_common(const char *name,
504                                      int argc, const char *argv[],
505                                      lpaddr_t bootinfo_phys,
506                                      alloc_phys_func alloc_phys)
507 {
508         lvaddr_t paramaddr;
509         struct dcb *init_dcb = spawn_module(&spawn_state, name,
510                                                                                 argc, argv,
511                                                                                 bootinfo_phys, INIT_ARGS_VBASE,
512                                                                                 alloc_phys, &paramaddr);
513
514         init_page_tables();
515
516     init_dcb->vspace = mem_to_local_phys((lvaddr_t)init_l1);
517
518         spawn_init_map(init_l2, INIT_VBASE, INIT_ARGS_VBASE,
519                            spawn_state.args_page, ARGS_SIZE, INIT_PERM_RW);
520
521
522     // Map dispatcher
523     spawn_init_map(init_l2, INIT_VBASE, INIT_DISPATCHER_VBASE,
524                    mem_to_local_phys(init_dcb->disp), DISPATCHER_SIZE,
525                    INIT_PERM_RW);
526
527
528     /*
529      * Create a capability that allows user-level applications to
530      * access device memory. This capability will be passed to Kaluga,
531      * split up into smaller pieces and distributed to among device
532      * drivers.
533      *
534      * For arm_gem5, this is currently a dummy capability. We do not
535      * have support for user-level device drivers in gem5 yet, so we
536      * do not allocate any memory as device memory. Some cap_copy
537      * operations in the bootup code fail if this capability is not
538      * present.
539      */
540     struct cte *iocap = caps_locate_slot(CNODE(spawn_state.taskcn), TASKCN_SLOT_IO);
541     errval_t  err = caps_create_new(ObjType_IO, 0, 0, 0, my_core_id, iocap);
542     assert(err_is_ok(err));
543
544     struct dispatcher_shared_generic *disp
545         = get_dispatcher_shared_generic(init_dcb->disp);
546     struct dispatcher_shared_arm *disp_arm
547         = get_dispatcher_shared_arm(init_dcb->disp);
548
549     /* Initialize dispatcher */
550     disp->disabled = true;
551     strncpy(disp->name, argv[0], DISP_NAME_LEN);
552
553     /* tell init the vspace addr of its dispatcher */
554     disp->udisp = INIT_DISPATCHER_VBASE;
555
556     disp_arm->enabled_save_area.named.r0   = paramaddr;
557     disp_arm->enabled_save_area.named.cpsr = ARM_MODE_USR | CPSR_F_MASK;
558     disp_arm->enabled_save_area.named.rtls = INIT_DISPATCHER_VBASE;
559     disp_arm->disabled_save_area.named.rtls = INIT_DISPATCHER_VBASE;
560
561
562     return init_dcb;
563 }
564
565 struct dcb *spawn_bsp_init(const char *name, alloc_phys_func alloc_phys)
566 {
567         /* Only the first core can run this code */
568         assert(hal_cpu_is_bsp());
569
570         /* Allocate bootinfo */
571         lpaddr_t bootinfo_phys = alloc_phys(BOOTINFO_SIZE);
572         memset((void *)local_phys_to_mem(bootinfo_phys), 0, BOOTINFO_SIZE);
573
574         /* Construct cmdline args */
575         char bootinfochar[16];
576         snprintf(bootinfochar, sizeof(bootinfochar), "%u", INIT_BOOTINFO_VBASE);
577         const char *argv[] = { "init", bootinfochar };
578         int argc = 2;
579
580         struct dcb *init_dcb = spawn_init_common(name, argc, argv,bootinfo_phys, alloc_phys);
581
582         // Map bootinfo
583         spawn_init_map(init_l2, INIT_VBASE, INIT_BOOTINFO_VBASE,
584                         bootinfo_phys, BOOTINFO_SIZE  , INIT_PERM_RW);
585
586         struct startup_l2_info l2_info = { init_l2, INIT_VBASE };
587
588         genvaddr_t init_ep, got_base;
589         load_init_image(&l2_info, BSP_INIT_MODULE_NAME, &init_ep, &got_base);
590
591     struct dispatcher_shared_arm *disp_arm
592         = get_dispatcher_shared_arm(init_dcb->disp);
593     disp_arm->enabled_save_area.named.r10  = got_base;
594     disp_arm->got_base = got_base;
595
596     disp_arm->disabled_save_area.named.pc   = init_ep;
597     disp_arm->disabled_save_area.named.cpsr = ARM_MODE_USR | CPSR_F_MASK;
598     disp_arm->disabled_save_area.named.r10  = got_base;
599
600     /* Create caps for init to use */
601     create_module_caps(&spawn_state);
602     lpaddr_t init_alloc_end = alloc_phys(0); // XXX
603     create_phys_caps(init_alloc_end);
604
605     /* Fill bootinfo struct */
606     bootinfo->mem_spawn_core = KERNEL_IMAGE_SIZE; // Size of kernel
607
608     /*
609     // Map dispatcher
610     spawn_init_map(init_l2, INIT_VBASE, INIT_DISPATCHER_VBASE,
611                    mem_to_local_phys(init_dcb->disp), DISPATCHER_SIZE,
612                    INIT_PERM_RW);
613     disp_arm->disabled_save_area.named.rtls = INIT_DISPATCHER_VBASE;
614         */
615     return init_dcb;
616 }
617
618 struct dcb *spawn_app_init(struct arm_core_data *core_data,
619                            const char *name, alloc_phys_func alloc_phys)
620 {
621         errval_t err;
622
623         /* Construct cmdline args */
624         // Core id of the core that booted this core
625         char coreidchar[10];
626         snprintf(coreidchar, sizeof(coreidchar), "%d", core_data->src_core_id);
627
628         // IPI channel id of core that booted this core
629         char chanidchar[30];
630         snprintf(chanidchar, sizeof(chanidchar), "chanid=%"PRIu32, core_data->chan_id);
631
632         // Arch id of the core that booted this core
633         char archidchar[30];
634         snprintf(archidchar, sizeof(archidchar), "archid=%d",
635                         core_data->src_arch_id);
636
637         const char *argv[5] = { name, coreidchar, chanidchar, archidchar };
638         int argc = 4;
639
640     struct dcb *init_dcb = spawn_init_common(name, argc, argv,0, alloc_phys);
641
642     // Urpc frame cap
643     struct cte *urpc_frame_cte = caps_locate_slot(CNODE(spawn_state.taskcn),
644                 TASKCN_SLOT_MON_URPC);
645     // XXX: Create as devframe so the memory is not zeroed out
646     err = caps_create_new(ObjType_DevFrame, core_data->urpc_frame_base,
647             core_data->urpc_frame_bits, core_data->urpc_frame_bits,
648             my_core_id, urpc_frame_cte);
649     assert(err_is_ok(err));
650     urpc_frame_cte->cap.type = ObjType_Frame;
651     lpaddr_t urpc_ptr = gen_phys_to_local_phys(urpc_frame_cte->cap.u.frame.base);
652
653     /* Map urpc frame at MON_URPC_BASE */
654     spawn_init_map(init_l2, INIT_VBASE, MON_URPC_VBASE, urpc_ptr, MON_URPC_SIZE,
655                            INIT_PERM_RW);
656
657     struct startup_l2_info l2_info = { init_l2, INIT_VBASE };
658
659     // elf load the domain
660     genvaddr_t entry_point, got_base=0;
661     err = elf_load(EM_ARM, startup_alloc_init, &l2_info,
662                 local_phys_to_mem(core_data->monitor_binary),
663                 core_data->monitor_binary_size, &entry_point);
664     if (err_is_fail(err)) {
665         //err_print_calltrace(err);
666         panic("ELF load of init module failed!");
667     }
668
669     // TODO: Fix application linkage so that it's non-PIC.
670     struct Elf32_Shdr* got_shdr =
671                 elf32_find_section_header_name(local_phys_to_mem(core_data->monitor_binary),
672                                                                            core_data->monitor_binary_size, ".got");
673     if (got_shdr)
674     {
675         got_base = got_shdr->sh_addr;
676     }
677
678     struct dispatcher_shared_arm *disp_arm =
679                 get_dispatcher_shared_arm(init_dcb->disp);
680     disp_arm->enabled_save_area.named.r10  = got_base;
681     disp_arm->got_base = got_base;
682
683     disp_arm->disabled_save_area.named.pc   = entry_point;
684     disp_arm->disabled_save_area.named.cpsr = ARM_MODE_USR | CPSR_F_MASK;
685     disp_arm->disabled_save_area.named.r10  = got_base;
686     //disp_arm->disabled_save_area.named.rtls = INIT_DISPATCHER_VBASE;
687
688     return init_dcb;
689 }
690
691 void arm_kernel_startup(void)
692 {
693     /* Initialize the core_data */
694     /* Used when bringing up other cores, must be at consistent global address
695      * seen by all cores */
696     struct arm_core_data *core_data
697     = (void *)((lvaddr_t)&kernel_first_byte - BASE_PAGE_SIZE);
698
699     struct dcb *init_dcb;
700
701     if(hal_cpu_is_bsp())
702     {
703         /* Initialize the location to allocate phys memory from */
704         printf("start_free_ram = 0x%lx\n", glbl_core_data->start_free_ram);
705         bsp_init_alloc_addr = glbl_core_data->start_free_ram;
706
707         init_dcb = spawn_bsp_init(BSP_INIT_MODULE_NAME, bsp_alloc_phys);
708
709         pit_start(0);
710
711     }
712     else
713     {
714
715         my_core_id = core_data->dst_core_id;
716
717         /* Initialize the allocator */
718         app_alloc_phys_start = core_data->memory_base_start;
719         app_alloc_phys_end   = ((lpaddr_t)1 << core_data->memory_bits) +
720                         app_alloc_phys_start;
721
722         init_dcb = spawn_app_init(core_data, APP_INIT_MODULE_NAME, app_alloc_phys);
723
724         uint32_t irq = gic_get_active_irq();
725         gic_ack_irq(irq);
726     }
727
728     // enable interrupt forwarding to cpu
729     gic_cpu_interface_enable();
730
731     // Should not return
732     dispatch(init_dcb);
733     panic("Error spawning init!");
734
735 }