Add BF_BINARY_PREFIX define to configure binary path by build system.
[barrelfish] / kernel / arch / x86 / startup_x86.c
1 /**
2  * \file
3  * \brief x86 kernel bootup code.
4  */
5
6 /*
7  * Copyright (c) 2007, 2008, 2009, 2010, 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
17 #include <dispatch.h>
18 #include <elf/elf.h>
19 #include <exec.h>
20 #include <init.h>
21 #include <getopt/getopt.h>
22 #include <kcb.h>
23 #include <kernel_multiboot.h>
24 #include <irq.h>
25 #include <kputchar.h>
26 #include <mdb/mdb_tree.h>
27 #ifdef CONFIG_MICROBENCHMARKS
28 #include <microbenchmarks.h>
29 #endif
30 #include <paging_kernel_arch.h>
31 #include <startup.h>
32 #include <string.h>
33 #include <wakeup.h>
34 #include <barrelfish_kpi/cpu.h>
35 #include <barrelfish_kpi/init.h>
36 #include <barrelfish_kpi/paging_arch.h>
37 #include <barrelfish_kpi/syscalls.h>
38 #include <arch/x86/apic.h>
39 #include <target/x86/barrelfish_kpi/coredata_target.h>
40 #include <arch/x86/startup_x86.h>
41 #ifdef __scc__
42 #       include <rck.h>
43 #endif
44
45 /// Optional core ID to use for the BSP core (command-line argument)
46 static int bsp_coreid;
47
48 /// Quick way to find the base address of a cnode capability
49 #define CNODE(cte)     (cte)->cap.u.cnode.cnode
50
51 /// Pointer to bootinfo structure for init
52 static struct bootinfo *bootinfo = (struct bootinfo *)BOOTINFO_BASE;
53
54 /**
55  * Each kernel has a local copy of global and locks. However, during booting and
56  * kernel relocation, these are set to point to global of the pristine kernel,
57  * so that all the kernels can share it.
58  */
59 static  struct global myglobal;
60 struct global *global = &myglobal;
61
62 // Physical memory allocator for spawn_app_init
63 static lpaddr_t app_alloc_phys_start, app_alloc_phys_end;
64 static lpaddr_t app_alloc_phys(size_t size)
65 {
66     uint32_t npages = (size + BASE_PAGE_SIZE - 1) / BASE_PAGE_SIZE;
67
68     lpaddr_t addr = app_alloc_phys_start;
69     app_alloc_phys_start += npages * BASE_PAGE_SIZE;
70
71     if (app_alloc_phys_start >= app_alloc_phys_end) {
72         panic("Out of memory, increase CORE_DATA_PAGES");
73     }
74
75     return addr;
76 }
77
78 /**
79  * The address from where bsp_alloc_phys will start allocating memory
80  */
81 static lpaddr_t bsp_init_alloc_addr = 0;
82
83 /**
84  * \brief Linear physical memory allocator.
85  *
86  * This function allocates a linear region of addresses of size 'size' from
87  * physical memory.
88  *
89  * \param size  Number of bytes to allocate.
90  *
91  * \return Base physical address of memory region.
92  */
93 static lpaddr_t bsp_alloc_phys(size_t size)
94 {
95     // round to base page size
96     uint32_t npages = (size + BASE_PAGE_SIZE - 1) / BASE_PAGE_SIZE;
97
98     assert(bsp_init_alloc_addr != 0);
99     lpaddr_t addr = bsp_init_alloc_addr;
100
101     bsp_init_alloc_addr += npages * BASE_PAGE_SIZE;
102     return addr;
103 }
104
105 /**
106  * \brief Map init user-space memory.
107  *
108  * This function maps pages of the init user-space module. It expects
109  * the virtual base address 'vbase' of a program segment of the init executable,
110  * its size 'size' and its ELF64 access control flags. It maps pages
111  * into physical memory that is allocated on the fly and puts
112  * corresponding frame caps into init's segcn.
113  *
114  * \param vbase Virtual base address of program segment.
115  * \param size  Size of program segment in bytes.
116  * \param flags ELF64 access control flags of program segment.
117  * \param ret   Used to return base region pointer
118  */
119 errval_t startup_alloc_init(void *state, genvaddr_t gvbase, size_t size,
120                             uint32_t flags, void **ret)
121 {
122
123     errval_t err;
124
125     struct spawn_state *spawn_state = state;
126
127     lvaddr_t vbase = (lvaddr_t)gvbase; /* XXX */
128     lvaddr_t offset = BASE_PAGE_OFFSET(vbase);
129
130     /* Page align the parameters */
131     paging_align(&vbase, NULL, &size, BASE_PAGE_SIZE);
132
133     lpaddr_t pbase = 0, paddr = 0;
134     for(lvaddr_t i = vbase; i < vbase + size; i += BASE_PAGE_SIZE) {
135         if (apic_is_bsp()) {
136             paddr = bsp_alloc_phys(BASE_PAGE_SIZE);
137         } else {
138             paddr = app_alloc_phys(BASE_PAGE_SIZE);
139         }
140
141         if(pbase == 0) {
142             pbase = paddr;
143         }
144
145         err = startup_map_init(i, paddr, BASE_PAGE_SIZE, flags);
146         assert(err_is_ok(err));
147     }
148
149     if (apic_is_bsp()) {
150         // Create frame caps for segcn
151         paddr += BASE_PAGE_SIZE;
152
153         debug(SUBSYS_STARTUP,
154               "Allocated physical memory [0x%"PRIxLPADDR", 0x%"PRIxLPADDR"]\n",
155               pbase, paddr - pbase);
156
157         err = create_caps_to_cnode(pbase, paddr - pbase,
158                                    RegionType_RootTask, spawn_state, bootinfo);
159         if (err_is_fail(err)) {
160             return err;
161         }
162     }
163
164     assert(ret != NULL);
165     *ret = (void *)(vbase + offset);
166
167     return SYS_ERR_OK;
168 }
169
170 /// Setup the module cnode, which contains frame caps to all multiboot modules
171 void create_module_caps(struct spawn_state *st)
172 {
173     errval_t err;
174
175     /* Create caps for multiboot modules */
176     struct multiboot_modinfo *module =
177         (struct multiboot_modinfo *)local_phys_to_mem(glbl_core_data->mods_addr);
178
179     // Allocate strings area
180     lpaddr_t mmstrings_phys = bsp_alloc_phys(BASE_PAGE_SIZE);
181     lvaddr_t mmstrings_base = local_phys_to_mem(mmstrings_phys);
182     lvaddr_t mmstrings = mmstrings_base;
183
184     // create cap for strings area in first slot of modulecn
185     assert(st->modulecn_slot == 0);
186     err = caps_create_new(ObjType_Frame, mmstrings_phys, BASE_PAGE_BITS,
187                           BASE_PAGE_BITS, my_core_id,
188                           caps_locate_slot(CNODE(st->modulecn),
189                                            st->modulecn_slot++));
190     assert(err_is_ok(err));
191
192     /* Walk over multiboot modules, creating frame caps */
193     for (int i = 0; i < glbl_core_data->mods_count; i++) {
194         struct multiboot_modinfo *m = &module[i];
195
196         // Set memory regions within bootinfo
197         struct mem_region *region =
198             &bootinfo->regions[bootinfo->regions_length++];
199
200         genpaddr_t remain = MULTIBOOT_MODULE_SIZE(*m);
201         genpaddr_t base_addr = local_phys_to_gen_phys(m->mod_start);
202
203         region->mr_type = RegionType_Module;
204         region->mr_base = base_addr;
205         region->mrmod_slot = st->modulecn_slot;  // first slot containing caps
206         region->mrmod_size = remain;  // size of image _in bytes_
207         region->mrmod_data = mmstrings - mmstrings_base; // offset of string in area
208
209         // round up to page size for caps
210         remain = ROUND_UP(remain, BASE_PAGE_SIZE);
211
212         // Create max-sized caps to multiboot module in module cnode
213         while (remain > 0) {
214             assert((base_addr & BASE_PAGE_MASK) == 0);
215             assert((remain & BASE_PAGE_MASK) == 0);
216
217             // determine size of next chunk
218             uint8_t block_size = bitaddralign(remain, base_addr);
219
220             assert(st->modulecn_slot < (1UL << st->modulecn->cap.u.cnode.bits));
221             // create as DevFrame cap to avoid zeroing memory contents
222             err = caps_create_new(ObjType_DevFrame, base_addr, block_size,
223                                   block_size, my_core_id,
224                                   caps_locate_slot(CNODE(st->modulecn),
225                                                    st->modulecn_slot++));
226             assert(err_is_ok(err));
227
228             // Advance by that chunk
229             base_addr += ((genpaddr_t)1 << block_size);
230             remain -= ((genpaddr_t)1 << block_size);
231         }
232
233         // Copy multiboot module string to mmstrings area
234         strcpy((char *)mmstrings, MBADDR_ASSTRING(m->string));
235         mmstrings += strlen(MBADDR_ASSTRING(m->string)) + 1;
236         assert(mmstrings < mmstrings_base + BASE_PAGE_SIZE);
237     }
238 }
239
240 void cleanup_bios_regions(char *mmap_addr, char **new_mmap_addr,
241                           uint32_t *new_mmap_length)
242 {
243     assert(new_mmap_addr);
244     assert(new_mmap_length);
245 #define PRINT_REGIONS(map, map_length) do {\
246         for(char * printcur = map; printcur < map + map_length;) {\
247             struct multiboot_mmap * printcurmmap = (struct multiboot_mmap * SAFE)TC(printcur);\
248             printf("\t0x%08"PRIx64" - 0x%08"PRIx64" Type: %"PRIu32" Length: 0x%"PRIx64"\n", printcurmmap->base_addr, printcurmmap->base_addr + printcurmmap->length, printcurmmap->type, printcurmmap->length);\
249             printcur += printcurmmap->size + 4;\
250         }\
251     } while (0)
252
253     printf("Raw MMAP from BIOS\n");
254     PRINT_REGIONS(mmap_addr, glbl_core_data->mmap_length);
255
256     // normalize memory regions
257     lpaddr_t clean_base = bsp_alloc_phys(glbl_core_data->mmap_length);
258     char *clean_mmap_addr = (char *)local_phys_to_mem(clean_base);
259     uint32_t clean_mmap_length = glbl_core_data->mmap_length;
260     memcpy(clean_mmap_addr, mmap_addr, glbl_core_data->mmap_length);
261
262     // first of all, sort regions by base address
263     // yes, it's a bubble sort, but the dataset is small and usually in the right order
264     bool swapped;
265     do {
266         swapped = false;
267
268         for(char * cur = clean_mmap_addr; cur < clean_mmap_addr + clean_mmap_length;) {
269             struct multiboot_mmap * curmmap = (struct multiboot_mmap * SAFE)TC(cur);
270             if (cur + curmmap->size + 4 >= clean_mmap_addr + clean_mmap_length)
271                 break; // do not try to move this check into the forloop as entries do not have to be the same length
272
273             struct multiboot_mmap * nextmmap = (struct multiboot_mmap * SAFE)TC(cur + curmmap->size + 4);
274
275             if (nextmmap->base_addr < curmmap->base_addr ||
276                 (nextmmap->base_addr == curmmap->base_addr && nextmmap->length > curmmap->length)) {
277                 // swap
278                 assert(curmmap->size == 20); // FIXME: The multiboot specification does not require this size
279                 assert(nextmmap->size == 20);
280
281                 struct multiboot_mmap tmp;
282                 tmp = *curmmap;
283                 *curmmap = *nextmmap;
284                 *nextmmap = tmp;
285
286                 swapped = true;
287             }
288
289             cur += curmmap->size + 4;
290         }
291     } while(swapped);
292
293     printf("Sorted MMAP\n");
294     PRINT_REGIONS(clean_mmap_addr, clean_mmap_length);
295
296     // now merge consecutive memory regions of the same or lower type
297     for(char * cur = clean_mmap_addr; cur < clean_mmap_addr + clean_mmap_length;) {
298         struct multiboot_mmap * curmmap = (struct multiboot_mmap * SAFE)TC(cur);
299         if (cur + curmmap->size + 4 >= clean_mmap_addr + clean_mmap_length)
300             break; // do not try to move this check into the forloop as entries do not have to be the same length
301
302         struct multiboot_mmap * nextmmap = (struct multiboot_mmap * SAFE)TC(cur + curmmap->size + 4);
303
304         /* On some machines (brie1) the IOAPIC region is only 1kB.
305          * Currently we're not able to map regions that are <4kB so we
306          * make sure that every region (if there is no problematic overlap)
307          * is at least BASE_PAGE_SIZEd (==4kB) here.
308          */
309         if ((curmmap->length < BASE_PAGE_SIZE) && (curmmap->base_addr + BASE_PAGE_SIZE <= nextmmap->base_addr)) {
310             curmmap->length = BASE_PAGE_SIZE;
311         }
312
313 #define DISCARD_NEXT_MMAP do {\
314     uint32_t discardsize = nextmmap->size + 4;\
315     memmove(cur + curmmap->size + 4, cur + curmmap->size + 4 + discardsize, clean_mmap_length - (cur - clean_mmap_addr) - curmmap->size - 4 - discardsize);\
316     clean_mmap_length -= discardsize;\
317     } while (0)
318
319 #define BUBBLE_NEXT_MMAP do {\
320     for (char * bubblecur = cur + curmmap->size + 4; bubblecur < clean_mmap_addr + clean_mmap_length;){\
321         struct multiboot_mmap * bubblecur_mmap = (struct multiboot_mmap * SAFE)TC(bubblecur);\
322         if (bubblecur + bubblecur_mmap->size + 4 >= clean_mmap_addr + clean_mmap_length)\
323             break;\
324         struct multiboot_mmap * bubblenext_mmap = (struct multiboot_mmap * SAFE)TC(bubblecur + bubblecur_mmap->size + 4);\
325         if (bubblenext_mmap->base_addr < bubblecur_mmap->base_addr || (bubblecur_mmap->base_addr == bubblenext_mmap->base_addr && bubblenext_mmap->length > bubblecur_mmap->length)) {\
326             struct multiboot_mmap bubbletmp; bubbletmp = *bubblecur_mmap; *bubblecur_mmap = *bubblenext_mmap; *bubblenext_mmap = bubbletmp;\
327         } else break;\
328     }} while(0)
329
330
331         bool reduced = false;
332         do {
333             reduced = false;
334
335             if (curmmap->base_addr == nextmmap->base_addr) {
336                 // regions start at the same location
337                 if (curmmap->length == nextmmap->length) {
338                     // trivial case. They are the same. Choose higher type and discard next
339                     curmmap->type = max(curmmap->type, nextmmap->type);
340
341                     DISCARD_NEXT_MMAP;
342
343                     reduced = true;
344                     continue;
345                 } else {
346                     // next region is smaller (we sorted that way)
347                     if (nextmmap->type <= curmmap->type) {
348                         // next regions type is the same or smaller. discard
349                         DISCARD_NEXT_MMAP;
350
351                         reduced = true;
352                         continue;
353                     } else {
354                         // next regions type is higher, so it gets priority
355                         // change type of current region and shrink next
356                         uint32_t tmptype = curmmap->type;
357                         uint64_t newlength = curmmap->length - nextmmap->length;
358                         curmmap->type = nextmmap->type;
359                         curmmap->length = nextmmap->length;
360                         nextmmap->type = tmptype;
361                         nextmmap->base_addr += nextmmap->length;
362                         nextmmap->length = newlength;
363
364                         // now we need to bubble next to the right place to restore order
365                         BUBBLE_NEXT_MMAP;
366
367                         reduced = true;
368                         continue;
369                     }
370                 }
371             }
372
373             // regions overlap
374             if (nextmmap->base_addr > curmmap->base_addr && nextmmap->base_addr < curmmap->base_addr + curmmap->length) {
375                 // same type
376                 if (curmmap->type == nextmmap->type) {
377                     // simple. just extend if necessary and discard next
378                     if (nextmmap->base_addr + nextmmap->length > curmmap->base_addr + curmmap->length)
379                         curmmap->length = (nextmmap->base_addr + nextmmap->length) - curmmap->base_addr;
380
381                     DISCARD_NEXT_MMAP;
382
383                     reduced = true;
384                     continue;
385                 } else {
386                     // type is not the same
387                     if (nextmmap->base_addr + nextmmap->length < curmmap->base_addr + curmmap->length) {
388                         // there is a chunk at the end. create a new region
389                         struct multiboot_mmap tmpmmap;
390                         tmpmmap.size = 20;
391                         tmpmmap.base_addr = nextmmap->base_addr + nextmmap->length;
392                         tmpmmap.length = (curmmap->base_addr + curmmap->length) - (nextmmap->base_addr + nextmmap->length);
393                         tmpmmap.type = curmmap->type;
394
395                         // move everything to make room
396                         assert(clean_mmap_length + tmpmmap.length + 4 < BOOTINFO_SIZE);
397                         memmove(cur + curmmap->size + 4 + tmpmmap.size + 4, cur + curmmap->size + 4, clean_mmap_length - ((cur - clean_mmap_addr) + curmmap->size + 4));
398                         clean_mmap_length += tmpmmap.size + 4;
399
400                         // insert new
401                         *nextmmap = tmpmmap;
402
403                         // restore order
404                         BUBBLE_NEXT_MMAP;
405
406                         reduced = true;
407                     }
408
409                     // after the previous step, the next region either ends
410                     // at the same location as the current or is longer
411                     uint64_t overlap = (curmmap->base_addr + curmmap->length) - nextmmap->base_addr;
412
413                     if (curmmap-> type > nextmmap->type) {
414                         // current has priority, shrink next and extend current
415                         nextmmap->length -= overlap;
416                         nextmmap->base_addr += overlap;
417                         curmmap->length += overlap;
418
419                         if (nextmmap->length == 0)
420                             DISCARD_NEXT_MMAP;
421
422                         reduced = true;
423                         continue;
424                     } else {
425                         // next has priority, shrink current and extend next
426                         nextmmap->length += overlap;
427                         nextmmap->base_addr -= overlap;
428                         curmmap->length -= overlap;
429
430                         reduced = true;
431                         continue;
432                     }
433                 }
434             }
435         } while (reduced);
436
437         cur += curmmap->size + 4;
438
439 #undef DISCARD_NEXT_MMAP
440 #undef BUBBLE_NEXT_MMAP
441     }
442
443     printf("Preprocessed MMAP\n");
444     PRINT_REGIONS(clean_mmap_addr, clean_mmap_length);
445
446     // we can only map pages. Therefore page align regions
447     for(char * cur = clean_mmap_addr; cur < clean_mmap_addr + clean_mmap_length;) {
448         struct multiboot_mmap * curmmap = (struct multiboot_mmap * SAFE)TC(cur);
449         if (cur + curmmap->size + 4 >= clean_mmap_addr + clean_mmap_length)
450             break; // do not try to move this check into the forloop as entries do not have to be the same length
451
452         struct multiboot_mmap * nextmmap = (struct multiboot_mmap * SAFE)TC(cur + curmmap->size + 4);
453
454         if (nextmmap->base_addr & BASE_PAGE_MASK) {
455             uint64_t offset = nextmmap->base_addr - ((nextmmap->base_addr >> BASE_PAGE_BITS) << BASE_PAGE_BITS);
456
457             // round in favour of higher type
458             if (curmmap->type > nextmmap->type) {
459                 curmmap->length += BASE_PAGE_SIZE - offset;
460                 nextmmap->base_addr += BASE_PAGE_SIZE - offset;
461                 nextmmap->length -= BASE_PAGE_SIZE - offset;
462             } else {
463                 curmmap->length -= offset;
464                 nextmmap->base_addr -= offset;
465                 nextmmap->length += offset;
466             }
467         }
468
469         cur += curmmap->size + 4;
470     }
471
472     printf("Pagealigned MMAP\n");
473     PRINT_REGIONS(clean_mmap_addr, clean_mmap_length);
474
475 #undef PRINT_REGIONS
476     *new_mmap_addr = clean_mmap_addr;
477     *new_mmap_length = clean_mmap_length;
478     return;
479 }
480
481 // XXX from serial.c
482 extern int serial_portbase;
483
484 static struct cmdarg cmdargs[] = {
485     {"loglevel", ArgType_Int, { .integer = &kernel_loglevel }},
486     {"logmask", ArgType_Int, { .integer = &kernel_log_subsystem_mask }},
487     {"ticks", ArgType_Bool, { .boolean = &kernel_ticks_enabled }},
488     {"timeslice", ArgType_Int, { .integer = &kernel_timeslice }},
489 #ifndef __scc__ // FIXME: why not?
490     {"serial", ArgType_Int, { .integer = &serial_portbase }},
491 #endif
492     {"bsp_coreid", ArgType_Int, { .integer = &bsp_coreid }},
493     {NULL, 0, {NULL}}
494 };
495
496 /**
497  * Name of multiboot module containing program for init domains.
498  */
499 #if defined(__k1om__)
500 #       define BSP_INIT_MODULE_PATH     BF_BINARY_PREFIX "k1om/sbin/init"
501 #elif defined(__x86_64__)
502 #       define BSP_INIT_MODULE_PATH     BF_BINARY_PREFIX "x86_64/sbin/init"
503 #elif defined(__scc__)
504 #       define BSP_INIT_MODULE_PATH     BF_BINARY_PREFIX "scc/sbin/init"
505 #elif defined(__i386__)
506 #       define BSP_INIT_MODULE_PATH     BF_BINARY_PREFIX "x86_32/sbin/init"
507 #else
508 #       error "Unknown x86"
509 #endif
510 #define BSP_INIT_PROG_NAME       "init"
511 #define APP_INIT_PROG_NAME       "monitor"
512
513 /**
514  * \brief Kernel's early startup code, called from arch-specific bootstrap.
515  */
516 void kernel_startup_early(void)
517 {
518     const char *cmdline;
519     assert(glbl_core_data != NULL);
520     cmdline = MBADDR_ASSTRING(glbl_core_data->cmdline);
521     parse_commandline(cmdline, cmdargs);
522 }
523
524 /**
525  * \brief Kernel's main startup code, called from arch-specific bootstrap.
526  *
527  * This function never returns.
528  */
529 extern bool verbose_dispatch;
530 void kernel_startup(void)
531 {
532 #ifdef CONFIG_MICROBENCHMARKS
533     printk(LOG_NOTE, "\nRunning microbenchmarks...\n");
534     microbenchmarks_run_all();
535 #endif
536
537     /* Initialize the core_data */
538     /* Used when bringing up other cores, must be at consistent global address
539      * seen by all cores */
540     struct x86_core_data *core_data
541         = (void *)((lvaddr_t)&_start_kernel - BASE_PAGE_SIZE);
542
543     struct dcb *init_dcb;
544     if (apic_is_bsp()) {
545         if (bsp_coreid != 0) {
546             my_core_id = bsp_coreid;
547         }
548
549         /* Initialize the location to allocate phys memory from */
550         bsp_init_alloc_addr = glbl_core_data->start_free_ram;
551
552         /* spawn init */
553         init_dcb = spawn_bsp_init(BSP_INIT_MODULE_PATH, bsp_alloc_phys);
554     } else {
555         // if we have a kernel control block, use it
556         if (kcb_current && kcb_current->is_valid) {
557             debug(SUBSYS_STARTUP, "have valid kcb, restoring state\n");
558             print_kcb();
559
560             // restore mdb
561             errval_t err = mdb_init(kcb_current);
562             if (err_is_fail(err)) {
563                 panic("couldn't restore mdb");
564             }
565             // figure out if we need to convert scheduler state
566 #ifdef CONFIG_SCHEDULER_RR
567             if (kcb_current->sched != SCHED_RR) {
568                 printf("converting scheduler state to RR\n");
569                 scheduler_convert();
570             }
571 #elif CONFIG_SCHEDULER_RBED
572             if (kcb_current->sched != SCHED_RBED) {
573                 printf("converting scheduler state to RBED\n");
574                 scheduler_convert();
575             }
576 #else
577 #error must define scheduler
578 #endif
579             // update core id of domains
580             kcb_update_core_id(kcb_current);
581             // set queue pointers
582             scheduler_restore_state();
583             // restore wakeup queue state
584             printk(LOG_DEBUG, "%s:%s:%d: kcb_current->wakeup_queue_head = %p\n",
585                    __FILE__, __FUNCTION__, __LINE__, kcb_current->wakeup_queue_head);
586             wakeup_set_queue_head(kcb_current->wakeup_queue_head);
587
588             printk(LOG_DEBUG, "%s:%s:%d: dcb_current = %p\n",
589                    __FILE__, __FUNCTION__, __LINE__, dcb_current);
590             struct dcb *next = schedule();
591             debug(SUBSYS_STARTUP, "next = %p\n", next);
592             if (next != NULL) {
593                 assert (next->disp);
594                 struct dispatcher_shared_generic *dst =
595                     get_dispatcher_shared_generic(next->disp);
596                 debug(SUBSYS_STARTUP, "scheduling '%s' from restored state\n",
597                       dst->name);
598             }
599             // interrupt state should be fine, as it's used directly from the
600             // kcb.
601             dispatch(next);
602             panic("should not get here!");
603         }
604         my_core_id = core_data->dst_core_id;
605
606         /* Initialize the allocator */
607         app_alloc_phys_start = core_data->memory_base_start;
608         app_alloc_phys_end   = ((lpaddr_t)1 << core_data->memory_bits) +
609                                     app_alloc_phys_start;
610
611         init_dcb = spawn_app_init(core_data, APP_INIT_PROG_NAME, app_alloc_phys);
612     }
613
614     // Should not return
615     //if (apic_is_bsp()) {
616     dispatch(init_dcb);
617     //}
618     panic("Error spawning init!");
619 }