1/**
2 * \file
3 * \brief Bootstrap the bootloader.
4 */
5
6/*
7 * Copyright (c) 2007, 2008, 2009, 2010, 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 <multiboot.h>
16
17#define STACK_SIZE  4096
18
19#define MSR_IA32_EFER   0xc0000080      ///< Extended features enables
20#define PAGING_ENABLE 31
21#define LONG_MODE_CS 0x0008
22#define PAE     0x20
23#define LME     8
24
25/* The flags for the Multiboot header */
26#define MB_FLAGS (MULTIBOOT_HEADER_FLAG_MODS_PGALIGNED | MULTIBOOT_HEADER_FLAG_NEED_MEMINFO)
27
28.code32
29.text
30.globl  start, halt
31
32/* Multiboot header, 4-byte aligned */
33    .align  4
34    .long   MULTIBOOT_HEADER_MAGIC               /* magic */
35    .long   MB_FLAGS                             /* flags */
36    .long   -(MULTIBOOT_HEADER_MAGIC + MB_FLAGS) /* checksum */
37
38start:
39    /* Initialize the stack pointer */
40    movl    $(stack + STACK_SIZE), %esp
41
42    /* Reset EFLAGS */
43    pushl   $0
44    popf
45
46    /* Enter main -- this should never return */
47    push    %ebp
48    mov %esp, %ebp
49    push    %ebx        /* Pointer to multiboot info struct */
50    push    %eax        /* Multiboot magic value */
51    call    startup
52
53    // Load 64-bit GDT
54    mov $gdt_ptr, %esi
55    lgdt    (%esi)
56
57    // enable page address extension
58    mov %cr4,%eax
59    or $PAE,%eax
60    mov %eax,%cr4
61
62    // set PML4 pointer to cr3
63    mov $boot_pml4, %eax
64    mov %eax,%cr3
65
66    // enable long-mode by setting EFER.LME
67    mov $MSR_IA32_EFER,%ecx
68    rdmsr
69    bts $LME,%eax
70    wrmsr
71
72    // enable paging
73    mov %cr0,%eax
74    bts $PAGING_ENABLE,%eax
75    mov %eax,%cr0
76
77    // Setup multiboot registers
78    mov     eax, %eax
79    mov     multiboot_info, %ebx
80    mov kernel_entry, %ecx
81
82    // jmp to long-mode to the linear address corresponding the
83    // real mode segment REAL_MODE_SEGMENT
84    //  jmp LONG_MODE_CS:start_64
85    .byte 0xea
86    .long start_64
87    .word LONG_MODE_CS
88
89/* start the 64bit long-mode code here */
90.code64
91start_64:
92
93    // initialize bootup stack for the 64bit long mode
94    lea (start_64_stack)(%rip), %rsp
95    // Jump to kernel image entry
96    jmp *%rcx
97
98/* Halt -- this should never be reached */
99halt:
100    hlt
101    jmp halt
102
103/* Stack for 64bit mode */
104    .comm   stack, STACK_SIZE
105    .align 16
106    .fill STACK_SIZE,1,0
107start_64_stack:
108
109/* Global descriptor table */
110.align 16
111gdt:
112    .byte 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
113    .byte 0xff,0xff,0x00,0x00,0x00,0x9a,0xaf,0x00 // 64bit code segment, D _cleared_ => "16bit"
114    .byte 0xff,0xff,0x00,0x00,0x00,0x92,0xcf,0x00 // data
115    .byte 0xff,0xff,0x00,0x00,0x00,0x9a,0xcf,0x00 // 32bit code segment for protected-mode
116    .byte 0xff,0xff,0x00,0x80,0x0b,0x92,0xff,0x00 // screen
117    .byte 0xff,0xff,0x00,0x60,0x00,0x9a,0xcf,0x00 // segment at linear address 0x6000
118    .byte 0xff,0xff,0x00,0x00,0x00,0x92,0xaf,0x00 // stack segment in 64bit mode
119
120gdt_ptr:
121    .word gdt_ptr - gdt
122    .long gdt
123    .long 0
124