Closes T154: pmap, kernel: Add support for write-combining on ia32/64
[barrelfish] / kernel / arch / x86_32 / init.c
1 /**
2  * \file
3  * \brief x86-32 architecture initialization.
4  */
5
6 /*
7  * Copyright (c) 2007, 2008, 2009, 2010, 2011, 2012, 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, Haldeneggsteig 4, CH-8092 Zurich. Attn: Systems Group.
13  */
14
15 #include <kernel.h>
16 #include <string.h>
17 #include <stdio.h>
18 #include <paging_kernel_arch.h>
19 #include <elf/elf.h>
20 #include <init.h>
21 #include <irq.h>
22 #include <x86.h>
23 #include <serial.h>
24 #include <kernel_multiboot.h>
25 #include <syscall.h>
26 #include <getopt/getopt.h>
27 #include <exec.h>
28 #include <kputchar.h>
29 #include <arch/x86/conio.h>
30 #include <arch/x86/pic.h>
31 #include <arch/x86/apic.h>
32 #include <arch/x86/perfmon_intel.h>
33 #include <arch/x86/perfmon_amd.h>
34 #include <arch/x86/rtc.h>
35 #include <arch/x86/ipi_notify.h>
36 #include <target/x86/barrelfish_kpi/coredata_target.h>
37 #include <arch/x86/timing.h>
38 #include <arch/x86/startup_x86.h>
39 #include <arch/x86/start_aps.h>
40 #include <coreboot.h>
41 #include <kcb.h>
42
43 #include <dev/xapic_dev.h> // XXX
44
45 /**
46  * Used to store the address of global struct passed during boot across kernel
47  * relocations.
48  */
49 // XXX: This won't work if this kernel is not relocated from a pristine image!
50 static uint32_t addr_global;
51
52 /**
53  * EFLAGS mask for fast system calls. Put values to mask out here.
54  * We mask out everything (including interrupts).
55  */
56 #define SYSCALL_FMASK   (~(EFLAGS_ALWAYS1) & 0xffffffff)
57
58 /**
59  * Segment selector bases for both kernel- and user-space for fast
60  * system calls
61  */
62 #define SYSCALL_STAR \
63     ((((uint64_t)GSEL(KSTACK_SEL, SEL_UPL)) << 48) | \
64      ((uint64_t)GSEL(KCODE_SEL, SEL_KPL) << 32))
65
66 /**
67  * \brief Kernel stack.
68  *
69  * This is the one and only kernel stack for a kernel instance.
70  */
71 uintptr_t x86_32_kernel_stack[X86_32_KERNEL_STACK_SIZE/sizeof(uintptr_t)];
72
73 /**
74  * \brief Global Task State Segment (TSS).
75  *
76  * This is the global, static and only Task State Segment (TSS). It is used
77  * for interrupt and exception handling (stack setup) while in user-space.
78  */
79 static struct task_state_segment tss __attribute__ ((aligned (4)));
80
81 /**
82  * \brief Global Descriptor Table (GDT) for processor this kernel is running on.
83  *
84  * This descriptor table is completely static, as segments are basically
85  * turned off in 64-bit mode. They map flat-mode code and stack segments for
86  * both kernel- and user-space and the only Task State Segment (TSS).
87  */
88 static union segment_descriptor gdt[] __attribute__ ((aligned (4))) = {
89     {   // Null segment
90         .raw = 0
91     },
92     {   // Kernel code segment
93         .d = {
94             .lo_limit = 0xffff,
95             .lo_base = 0,
96             .type = 0xa,
97             .system_desc = 1,
98             .privilege_level = SEL_KPL,
99             .present = 1,
100             .hi_limit = 0xf,
101             .available = 0,
102             .long_mode = 0,
103             .operation_size = 1,
104             .granularity = 1,
105             .hi_base = 0
106         }
107     },
108     {   // Kernel stack segment
109         .d = {
110             .lo_limit = 0xffff,
111             .lo_base = 0,
112             .type = 2,
113             .system_desc = 1,
114             .privilege_level = SEL_KPL,
115             .present = 1,
116             .hi_limit = 0xf,
117             .available = 0,
118             .long_mode = 0,
119             .operation_size = 1,
120             .granularity = 1,
121             .hi_base = 0
122         }
123     },
124     {   // User stack segment
125         .d = {
126             .lo_limit = 0xffff,
127             .lo_base = 0,
128             .type = 2,
129             .system_desc = 1,
130             .privilege_level = SEL_UPL,
131             .present = 1,
132             .hi_limit = 0xf,
133             .available = 0,
134             .long_mode = 0,
135             .operation_size = 1,
136             .granularity = 1,
137             .hi_base = 0
138         }
139     },
140     {   // User code segment
141         .d = {
142             .lo_limit = 0xffff,
143             .lo_base = 0,
144             .type = 0xa,
145             .system_desc = 1,
146             .privilege_level = SEL_UPL,
147             .present = 1,
148             .hi_limit = 0xf,
149             .available = 0,
150             .long_mode = 0,
151             .operation_size = 1,
152             .granularity = 1,
153             .hi_base = 0
154         }
155     },
156     {   // Global Task State Segment (TSS)
157         .tss = {
158             .lo_limit = sizeof(tss) & 0xffff,
159             .type = SDT_SYSTSS,
160             .privilege_level = SEL_KPL,
161             .present = 1,
162             .hi_limit = (sizeof(tss) >> 16) & 0xf,
163             .available = 0,
164             .granularity = 0,
165         }
166     },
167     {
168         // Dispatcher "segment"
169         .d = {
170             .lo_limit = 0xffff,
171             .lo_base = 0,
172             .type = 2,
173             .system_desc = 1,
174             .privilege_level = SEL_UPL,
175             .present = 1,
176             .hi_limit = 0xf,
177             .available = 0,
178             .long_mode = 0,
179             .operation_size = 1,
180             .granularity = 1,
181             .hi_base = 0
182         }
183     }
184 };
185
186 volatile union segment_descriptor *curdisp = &gdt[6];
187
188 #ifdef CONFIG_PAE
189 /**
190  * Bootup PDPTE.
191  */
192 static union x86_32_pdpte_entry boot_pdpte[X86_32_PDPTE_SIZE]
193 __attribute__ ((aligned(X86_32_BASE_PAGE_SIZE)));
194
195 /**
196  * Bootup low-map PDIR and hi-map PDIR.
197  */
198 static union x86_32_ptable_entry boot_pdir[X86_32_PTABLE_SIZE]
199 __attribute__ ((aligned(X86_32_BASE_PAGE_SIZE))),
200     boot_pdir_hi[X86_32_PTABLE_SIZE] __attribute__ ((aligned(X86_32_BASE_PAGE_SIZE)));
201 #else
202 #       ifdef CONFIG_PSE
203 /**
204  * Bootup PDIR.
205  */
206 static union x86_32_ptable_entry boot_pdir[X86_32_PTABLE_SIZE]
207 __attribute__ ((aligned(X86_32_BASE_PAGE_SIZE)));
208 #       else
209 /**
210  * Bootup PDIR.
211  */
212 static union x86_32_pdir_entry boot_pdir[X86_32_PTABLE_SIZE]
213 __attribute__ ((aligned(X86_32_BASE_PAGE_SIZE)));
214
215 /**
216  * Bootup low-map PTABLE and hi-map PTABLE.
217  */
218 static union x86_32_ptable_entry
219 boot_ptable[MEM_PTABLE_SIZE][X86_32_PTABLE_SIZE]
220 __attribute__ ((aligned(X86_32_BASE_PAGE_SIZE)));
221 #       endif
222 #endif
223
224 /**
225  * This flag is set to true once the IDT is initialized and exceptions can be
226  * caught.
227  */
228 bool idt_initialized = false;
229
230 /**
231  * \brief Setup bootup page table.
232  *
233  * This function sets up the page table needed to boot the kernel proper.
234  * The table identity maps the first 2 MBytes (page size is 2 MBytes) of
235  * physical memory in order to have access to the first MByte containing
236  * bootloader-passed data structures. It also identity maps the local copy
237  * of the kernel in low memory and aliases it in kernel address space.
238  */
239 static void paging_init(void)
240 {
241     lvaddr_t vbase = X86_32_MEMORY_OFFSET, base = 0;
242
243     // Align vbase to kernel page size
244     if(vbase & X86_32_MEM_PAGE_MASK) {
245         vbase -= vbase & X86_32_MEM_PAGE_MASK;
246     }
247
248 #ifdef CONFIG_PAE
249     for(size_t i = 0; i < X86_32_PTABLE_SIZE; i++,
250             base += X86_32_MEM_PAGE_SIZE, vbase += X86_32_MEM_PAGE_SIZE) {
251         // Identity-map the kernel's physical region, so we don't lose ground
252         paging_x86_32_map_pdpte(&boot_pdpte[X86_32_PDPTE_BASE(base)],
253                                 (lpaddr_t)boot_pdir);
254         paging_x86_32_map_large(&boot_pdir[X86_32_PDIR_BASE(base)], base,
255                                 X86_32_PTABLE_PRESENT
256                                 | X86_32_PTABLE_READ_WRITE
257                                 | X86_32_PTABLE_USER_SUPERVISOR);
258
259         // Alias the same region at MEMORY_OFFSET
260         paging_x86_32_map_pdpte(&boot_pdpte[X86_32_PDPTE_BASE(vbase)],
261                                 (lpaddr_t)boot_pdir_hi);
262         paging_x86_32_map_large(&boot_pdir_hi[X86_32_PDIR_BASE(vbase)], base,
263                                 X86_32_PTABLE_PRESENT
264                                 | X86_32_PTABLE_READ_WRITE
265                                 | X86_32_PTABLE_USER_SUPERVISOR);
266     }
267
268     // Activate new page tables
269     paging_x86_32_context_switch((lpaddr_t)boot_pdpte);
270 #else
271     for(size_t i = 0; i < X86_32_PADDR_SPACE_LIMIT; i += X86_32_MEM_PAGE_SIZE,
272             base += X86_32_MEM_PAGE_SIZE, vbase += X86_32_MEM_PAGE_SIZE) {
273 #       ifdef CONFIG_PSE
274         // Identity-map the kernel's physical region, so we don't lose ground
275         paging_x86_32_map_large(&boot_pdir[X86_32_PDIR_BASE(base)], base,
276                                 X86_32_PTABLE_PRESENT
277                                 | X86_32_PTABLE_READ_WRITE
278                                 | X86_32_PTABLE_USER_SUPERVISOR);
279
280         // Alias the same region at MEMORY_OFFSET
281         paging_x86_32_map_large(&boot_pdir[X86_32_PDIR_BASE(vbase)], base,
282                                 X86_32_PTABLE_PRESENT
283                                 | X86_32_PTABLE_READ_WRITE
284                                 | X86_32_PTABLE_USER_SUPERVISOR);
285 #       else
286         // Identity-map the kernel's physical region, so we don't lose ground
287         paging_x86_32_map_table(&boot_pdir[X86_32_PDIR_BASE(base)],
288                                 (lpaddr_t)boot_ptable[X86_32_PDIR_BASE(base)]);
289         paging_x86_32_map(&boot_ptable[X86_32_PDIR_BASE(base)][X86_32_PTABLE_BASE(base)],
290                           base,
291                           X86_32_PTABLE_PRESENT
292                           | X86_32_PTABLE_READ_WRITE
293                           | X86_32_PTABLE_USER_SUPERVISOR);
294
295         // Alias the same region at MEMORY_OFFSET
296         paging_x86_32_map_table(&boot_pdir[X86_32_PDIR_BASE(vbase)],
297                                 (lpaddr_t)boot_ptable[X86_32_PDIR_BASE(base)]);
298 #       endif
299     }
300
301     // Activate new page tables
302     paging_x86_32_context_switch((lpaddr_t)boot_pdir);
303 #endif
304 }
305
306 /**
307  * \brief Setup default GDT.
308  *
309  * Loads the GDT register with the default GDT and reloads CS and SS
310  * to point to the new entries. Resets all other segment registers to null.
311  * Finally, completes setup of GDT to include TSS base address mapping and
312  * loads TSS into task register.
313  */
314 static void gdt_reset(void)
315 {
316     lvaddr_t                     ptss = (lvaddr_t)&tss;
317     struct region_descriptor    region = {
318         .rd_limit = sizeof(gdt),
319         .rd_base = (uint32_t)&gdt
320     };
321
322     // Load default GDT
323     __asm volatile("lgdt %[region]" :: [region] "m" (region));
324
325     // Reload segments
326     __asm volatile("mov %[ds], %%ds        \n\t"
327                    "mov %[ds], %%es        \n\t"
328                    "mov %[ss], %%ss        \n\t"
329                    "mov %[null], %%gs      \n\t"
330                    "mov %[null], %%fs      \n\t"
331                    "pushl %[cs]            \n\t"          // new CS
332                    "lea 1f, %%eax          \n\t"          // jumps to after lret
333                    "pushl %%eax            \n\t"          // new IP
334                    "lretl                  \n\t"          // fake return
335                    "1:                     \n\t"          // we'll continue here
336                    : /* No Output */
337                    :
338                    [null] "r" (0),
339                    [ss] "r" (GSEL(KSTACK_SEL, SEL_KPL)),
340                    [cs] "i" (GSEL(KCODE_SEL, SEL_KPL)),
341                    [ds] "r" (GSEL(USTACK_SEL, SEL_UPL))
342                    : "eax"
343                    );
344
345     // Complete setup of TSS descriptor (by inserting base address of TSS)
346     gdt[TSS_SEL].tss.lo_base = ptss & 0xffffff;
347     gdt[TSS_SEL].tss.hi_base = (ptss >> 24) & 0xff;
348
349     // Complete setup of TSS
350     tss.esp0 = (lvaddr_t)&x86_32_kernel_stack[X86_32_KERNEL_STACK_SIZE / sizeof(uintptr_t)];
351     tss.ss0 = GSEL(KSTACK_SEL, SEL_KPL);
352
353     // Load task state register
354     __asm volatile("ltr %%ax" :: "a" (GSEL(TSS_SEL, SEL_KPL)));
355 }
356
357 /**
358  * \brief Relocates the active stack.
359  *
360  * This function relocates the stack, by adding 'offset' to the stack
361  * pointer.
362  *
363  * \param offset        Offset to add to the stack pointer.
364  */
365 static inline void __attribute__ ((always_inline))
366 relocate_stack(lvaddr_t offset)
367 {
368     __asm volatile("add %[stack], %%esp\n\t"
369                    : /* No output */
370                    : [stack] "g" (offset)
371                    : "esp"
372                    );
373 }
374
375 /**
376  * \brief Enable SYSCALL/SYSRET fast system calls.
377  *
378  * This function enables the SYSCALL/SYSRET pair of fast system calls in
379  * long mode. Also sets the IA32_STAR and IA32_FMASK MSRs to point to the
380  * user-space base selector and RFLAGS mask for SYSCALL/SYSRET fast system
381  * calls.
382  */
383 static inline void enable_fast_syscalls(void)
384 {
385     // Set IA32_STAR MSR to point to user-space base selector
386     wrmsr(MSR_IA32_STAR, SYSCALL_STAR);
387
388     // Set IA32_LSTAR MSR to point to kernel-space system call multiplexer
389     wrmsr(MSR_IA32_LSTAR, (lvaddr_t)syscall_entry);
390
391     // Set IA32_FMASK MSR for our OSes EFLAGS mask
392     wrmsr(MSR_IA32_FMASK, SYSCALL_FMASK);
393
394     // Enable fast system calls
395     addmsr(MSR_IA32_EFER, IA32_EFER_SCE);
396 }
397
398 #define CR0_CD  (1 << 30)
399 #define CR0_NW  (1 << 29)
400 #define CR0_PG  (1 << 31)
401 #define CR4_MPE (1 << 11)
402 #define CR4_PCE (1 << 8)
403 #define CR4_PGE (1 << 7)
404 #define CR4_PAE (1 << 5)
405 #define CR4_PSE (1 << 4)
406
407 static inline void enable_user_rdpmc(void)
408 {
409     uint32_t cr4;
410
411     __asm volatile("mov %%cr4, %[cr4]" : [cr4] "=r" (cr4));
412     cr4 |= CR4_PCE;
413     __asm volatile("mov %[cr4], %%cr4" :: [cr4] "r" (cr4));
414 }
415
416 static inline void enable_tlb_flush_filter(void)
417 {
418     uint32_t eax, ebx, ecx, edx;
419
420     // Must read "AuthenticAMD"
421     cpuid(0, &eax, &ebx, &ecx, &edx);
422     if(ebx != 0x68747541 || ecx != 0x444d4163 || edx != 0x69746e65) {
423         return;
424     }
425
426     // Is at least family 0fh?
427     cpuid(1, &eax, &ebx, &ecx, &edx);
428     if(((eax >> 8) & 0xf) != 0xf) {
429         return;
430     }
431
432     debug(SUBSYS_STARTUP, "Enabling TLB flush filter\n");
433     uint64_t hwcr = rdmsr(MSR_AMD_HWCR);
434     hwcr &= ~AMD_HWCR_FFDIS;
435     wrmsr(MSR_AMD_HWCR, hwcr);
436 }
437
438 static inline void enable_pge(void)
439 {
440     uint32_t cr4;
441
442     __asm volatile("mov %%cr4, %[cr4]" : [cr4] "=r" (cr4));
443     cr4 |= CR4_PGE;
444     __asm volatile("mov %[cr4], %%cr4" :: [cr4] "r" (cr4));
445 }
446
447 static inline void enable_pae(void)
448 {
449     uint32_t cr4;
450
451     __asm volatile("mov %%cr4, %[cr4]" : [cr4] "=r" (cr4));
452     cr4 |= CR4_PAE;
453     __asm volatile("mov %[cr4], %%cr4" :: [cr4] "r" (cr4));
454 }
455
456 static inline void enable_pse(void)
457 {
458     uint32_t cr4;
459
460     __asm volatile("mov %%cr4, %[cr4]" : [cr4] "=r" (cr4));
461     cr4 |= CR4_PSE;
462     __asm volatile("mov %[cr4], %%cr4" :: [cr4] "r" (cr4));
463 }
464
465 static inline void enable_pg(void)
466 {
467     uint32_t cr0;
468
469     __asm volatile("mov %%cr0, %[cr0]" : [cr0] "=r" (cr0));
470     cr0 |= CR0_PG;
471     __asm volatile("mov %[cr0], %%cr0" :: [cr0] "r" (cr0));
472 }
473
474 static inline void enable_monitor_mwait(void)
475 {
476     uint32_t eax, ebx, ecx, edx;
477
478     cpuid(1, &eax, &ebx, &ecx, &edx);
479
480     if (ecx & (1 << 3)) {
481         cpuid(5, &eax, &ebx, &ecx, &edx);
482         debug(SUBSYS_STARTUP, "MONITOR/MWAIT supported: "
483               "min size %"PRIu32" bytes, max %"PRIu32" bytes. %s %s\n",
484               eax, ebx, (ecx & 2) ? "IBE" : "", (ecx & 1) ? "EMX" : "");
485     }
486 }
487
488 /**
489  * \brief Continue kernel initialization in kernel address space.
490  *
491  * This function resets paging to map out low memory and map in physical
492  * address space, relocating all remaining data structures. It resets the
493  * Global Descriptor Table for flat mode and to exclude legacy segments from
494  * boot initialization code. It sets up the IDT for exception and interrupt
495  * handling, initializes the local APIC and enables interrupts. After that it
496  * calls kernel_startup(), which should not return (if it does, this function
497  * halts the kernel).
498  */
499 static void  __attribute__ ((noreturn, noinline)) text_init(void)
500 {
501     // Relocate global to "memory"
502     global = (struct global*)local_phys_to_mem((lpaddr_t)addr_global);
503
504     // Relocate glbl_core_data to "memory"
505     glbl_core_data = (struct x86_core_data *)
506         local_phys_to_mem((lpaddr_t)glbl_core_data);
507
508     // Map-out low memory
509     paging_x86_32_reset();
510
511     /*
512      * Use new physical address space for video memory -- no calls to functions
513      * that end up calling a conio.c function may be called between
514      * paging_reset() and conio_relocate_vidmem()!
515      */
516     conio_relocate_vidmem(local_phys_to_mem(VIDEO_MEM));
517
518     /*
519      * Also reset the global descriptor table (GDT), so we get
520      * segmentation again and can catch interrupts/exceptions (the IDT
521      * needs the GDT).
522      */
523     gdt_reset();
524
525     // Arch-independent early startup
526     kernel_startup_early();
527
528     // XXX: re-init the serial driver, in case the port changed after parsing args
529     serial_console_init(false);
530
531     // Setup IDT
532     setup_default_idt();
533     idt_initialized = true;
534
535     // Initialize local APIC
536     apic_init();
537
538     // do not remove/change this printf: needed by regression harness
539     printf("Barrelfish CPU driver starting on x86_32 core %u\n", apic_id);
540
541     if(apic_is_bsp()) {
542         // Initialize classic (8259A) PIC
543         pic_init();
544     }
545
546     // Initialize real-time clock
547     rtc_init();
548
549     // Initialize local APIC timer
550     if (kernel_ticks_enabled) {
551         timing_calibrate();
552         apic_timer_init(false, true);
553         timing_apic_timer_set_ms(kernel_timeslice);
554     } else {
555         printk(LOG_WARN, "APIC timer disabled: NO timeslicing\n");
556         apic_mask_timer();
557     }
558
559     // Initialize IPI notification mechanism
560     ipi_notify_init();
561
562     // Enable SYSCALL/SYSRET fast system calls
563     /* enable_fast_syscalls(); */
564
565 #ifdef CONFIG_NXE
566     // Enable "no execute" page-level protection bit
567     addmsr(MSR_IA32_EFER, IA32_EFER_NXE);
568 #endif
569
570     // Enable FPU and MMX
571     enable_fpu();
572
573     // Enable user-mode RDPMC opcode
574     enable_user_rdpmc();
575
576     // AMD64: Check if TLB flush filter is enabled
577     enable_tlb_flush_filter();
578
579     // Enable global pages
580     enable_pge();
581
582     // Check/Enable MONITOR/MWAIT opcodes
583     enable_monitor_mwait();
584
585     // Setup Page Attribute Table MSR
586     configure_page_attribute_table();
587
588     // Call main kernel startup function -- this should never return
589     kernel_startup();
590
591     halt();
592     // Returning here will crash! -- low pages not mapped anymore!
593 }
594
595 /**
596  * \brief Architecture-specific initialization function.
597  *
598  * This function is called by the bootup code in boot.S to initialize
599  * architecture-specific stuff. It is expected to call the kernel main
600  * loop. This function never returns.
601  *
602  * The kernel expects one of two magic values in 'magic' that determine how it
603  * has been booted. If 'magic' is #MULTIBOOT_INFO_MAGIC the kernel has been
604  * booted by a (Multiboot-compliant) bootloader and this is the first image on
605  * the boot CPU. It will relocate itself to a default position. If 'magic' is
606  * #KERNEL_BOOT_MAGIC it has been booted by another image of itself and is
607  * running on an (so-called) application CPU. It expects 'dest' to be a physical
608  * address pointing to the base of a memory area to relocate itself to.
609  *
610  * For x86-64, after performing some sanity checks to the kernel image, this
611  * function first copies the whole kernel to a CPU-local version and then calls
612  * local_init(), at the offset of the local copy, to initialize that local
613  * copy. local_init() should never return.
614  *
615  * For bsp kernels, the void pointer is of type multiboot_info, for application
616  * CPUs, it is of type global. Global carries a pointer to multiboot_info.
617  * Global also contains pointers to memory that is shared between kernels.
618  *
619  * \param magic         Boot magic value
620  * \param pointer       Pointer to Multiboot Info or to Global structure
621  */
622 void arch_init(uint32_t magic, void *pointer)
623 {
624     // Sanitize the screen
625     conio_cls();
626     // Initialize serial, only initialize HW if we are
627     // the first kernel
628     serial_console_init((magic == MULTIBOOT_INFO_MAGIC));
629
630     /* determine page-aligned physical address past end of multiboot */
631     lvaddr_t dest = (lvaddr_t)&_start_kernel;
632     if (dest & (BASE_PAGE_SIZE - 1)) {
633         dest &= ~(BASE_PAGE_SIZE - 1);
634         dest += BASE_PAGE_SIZE;
635     }
636
637     // XXX: print kernel address for debugging with gdb
638     printf("Kernel starting at address 0x%"PRIxLVADDR"\n", local_phys_to_mem(dest));
639
640     void __attribute__ ((noreturn)) (*reloc_text_init)(void) =
641         (void *)local_phys_to_mem((lpaddr_t)text_init);
642     struct Elf32_Shdr *rela, *symtab;
643     struct x86_coredata_elf *elf;
644
645     /*
646      * If this is the boot image, make Multiboot information structure globally
647      * known. Otherwise the passed value should equal the original structure.
648      * If magic value does not match what we expect, we cannot proceed safely.
649      */
650     switch(magic) {
651     case MULTIBOOT_INFO_MAGIC:
652         {
653             struct multiboot_info *mb = (struct multiboot_info *)pointer;
654
655             elf = (struct x86_coredata_elf *)&mb->syms.elf;
656             // We need the ELF section header table for relocation
657             if (!(mb->flags & MULTIBOOT_INFO_FLAG_HAS_ELF_SYMS)) {
658                 panic("Multiboot information structure does not include ELF section"
659                       "header information -- Relocation impossible!");
660             }
661             assert(mb->flags & MULTIBOOT_INFO_FLAG_HAS_MMAP);
662
663             // Determine where free RAM starts
664             memset(glbl_core_data, 0, sizeof(struct x86_core_data));
665             glbl_core_data->start_free_ram =
666                 ROUND_UP(max(multiboot_end_addr(mb), (uintptr_t)&_end_kernel),
667                          BASE_PAGE_SIZE);
668
669             glbl_core_data->mods_addr = mb->mods_addr;
670             glbl_core_data->mods_count = mb->mods_count;
671             glbl_core_data->cmdline = mb->cmdline;
672             glbl_core_data->mmap_length = mb->mmap_length;
673             glbl_core_data->mmap_addr = mb->mmap_addr;
674         }
675         break;
676
677     case KERNEL_BOOT_MAGIC:
678         global = (struct global*)pointer;
679         // Store the address of global to retrive it across relocation
680         addr_global = (uint32_t)global;
681         memset(&global->locks, 0, sizeof(global->locks));
682         struct x86_core_data *core_data =
683             (struct x86_core_data*)(dest - BASE_PAGE_SIZE);
684         glbl_core_data = core_data;
685         glbl_core_data->cmdline = (lpaddr_t)&core_data->kernel_cmdline;
686         my_core_id = core_data->dst_core_id;
687         kcb_current = (struct kcb*) (lpaddr_t)glbl_core_data->kcb;
688         elf = &core_data->elf;
689         break;
690
691     default:
692         panic("Magic value does not match! (0x%x != 0x%"PRIu32" != 0x%x)",
693               KERNEL_BOOT_MAGIC, magic, MULTIBOOT_INFO_MAGIC);
694         break;
695     }
696
697     if(magic != KERNEL_BOOT_MAGIC) {
698         // Construct the global structure and store its address to retrive it
699         // across relocation
700         memset(&global->locks, 0, sizeof(global->locks));
701         addr_global            = (uint32_t)global;
702     }
703
704     // We're only able to process Elf32_Rela entries
705     if (elf->size != sizeof(struct Elf32_Shdr)) {
706         panic("ELF section header entry size mismatch!");
707     }
708
709     // Find relocation section
710     rela = elf32_find_section_header_type((struct Elf32_Shdr *)
711                                           (lpaddr_t)elf->addr,
712                                           elf->num, SHT_REL);
713
714     if (rela == NULL) {
715         panic("Kernel image does not include relocation section!");
716     }
717
718     // Find symbol table section
719     symtab = elf32_find_section_header_type((struct Elf32_Shdr *)
720                                             (lpaddr_t)elf->addr,
721                                             elf->num, SHT_DYNSYM);
722
723     if (symtab == NULL) {
724         panic("Kernel image does not include symbol table!");
725     }
726
727     // Kernel has to fit in mappable area
728     assert((lvaddr_t)&_end_kernel < X86_32_PADDR_SPACE_LIMIT);
729
730     // Map alias at MEMORY_OFFSET
731     paging_init();
732
733 #ifdef CONFIG_PAE
734     // Put CPU in PAE mode
735     enable_pae();
736 #elif defined(CONFIG_PSE)
737     // Enable page-size extensions
738     enable_pse();
739 #endif
740
741     // Enable paging
742     enable_pg();
743
744     // Relocate kernel image for top of memory
745     elf32_relocate(X86_32_MEMORY_OFFSET + (lvaddr_t)&_start_kernel,
746                    (lvaddr_t)&_start_kernel,
747                    (struct Elf32_Rel *)(rela->sh_addr - X86_32_START_KERNEL_PHYS + &_start_kernel),
748                    rela->sh_size,
749                    (struct Elf32_Sym *)(symtab->sh_addr - X86_32_START_KERNEL_PHYS + &_start_kernel),
750                    symtab->sh_size,
751                    X86_32_START_KERNEL_PHYS, &_start_kernel);
752
753     /*** Aliased kernel available now -- low memory still mapped ***/
754
755     // Relocate stack to aliased location
756     relocate_stack(X86_32_MEMORY_OFFSET);
757
758     // Call aliased text_init() function and continue initialization
759     reloc_text_init();
760 }