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