1/*
2 * Copyright 2014, General Dynamics C4 Systems
3 *
4 * This software may be distributed and modified according to the terms of
5 * the GNU General Public License version 2. Note that NO WARRANTY is provided.
6 * See "LICENSE_GPLv2.txt" for details.
7 *
8 * @TAG(GD_GPL)
9 */
10
11/* Configuration for MultiBoot, see MultiBoot Specification:
12   www.gnu.org/software/grub/manual/multiboot
13   We use a flags field of 3, indicating that we want modules loaded on page
14   boundaries and access to the memory map information. We do not set bit 16,
15   indicating that the structure of the image should be taken from its ELF
16   headers. */
17
18#include <config.h>
19#include <machine/assembler.h>
20
21.section .phys.text
22
23BEGIN_FUNC(enable_paging)
24    # Set PSE (bit 4) to enable 4M pages
25    movl %cr4,  %eax
26    orl  $0x10, %eax
27    movl %eax,  %cr4
28
29    # Load the boot PD (or PDPT) address into CR3
30    leal _boot_pd, %eax
31    movl %eax,     %cr3
32
33    # Enable caches by clearing bits 29 and 30 of CR0
34    # Enable paging by setting bit 31 of CR0
35    movl %cr0,        %eax
36    andl $0x9fffffff, %eax
37    orl  $0x80000000, %eax
38    movl %eax,        %cr0
39
40    # Now that paging is enabled we can enable global pages
41    # Must be done in this sequence as per the intel manual
42    # Set PGE (bit 7) to enable global pages
43    movl %cr4,  %eax
44    orl  $0x80, %eax
45    movl %eax,  %cr4
46    ret
47END_FUNC(enable_paging)
48
49/* ===== booting up first CPU ===== */
50
51BEGIN_FUNC(_start)
52    /* Assume we are MultiBooted, e.g. by GRUB.
53       See MultiBoot Specification: www.gnu.org/software/grub/manual/multiboot
54    */
55
56    movl %eax, %edi /* multiboot_magic    */
57    movl %ebx, %esi /* multiboot_info_ptr */
58
59    /* Load kernel boot stack pointer */
60    leal boot_stack_top, %esp
61
62    /* Reset EFLAGS register (also disables interrupts etc.) */
63    pushl $0
64    popf
65
66    /* Push parameters to preserve for calling boot_sys later */
67    pushl %esi /* 2nd parameter: multiboot_info_ptr */
68    pushl %edi /* 1st parameter: multiboot_magic    */
69
70    /* Initialise boot PD and enable paging */
71    call init_boot_pd
72    call enable_paging
73
74    popl %edi
75    popl %esi
76
77    /* Stop using shared boot stack and get a real stack and move to the top of the stack */
78    leal kernel_stack_alloc + (1 << CONFIG_KERNEL_STACK_BITS) - 4, %esp
79
80    pushl %esi /* 2nd parameter: multiboot_info_ptr */
81    pushl %edi /* 1st parameter: multiboot_magic    */
82
83    /* Call boot_sys() (takes 2 parameters) and set restore_user_context() as  */
84    /* return EIP. This will start the roottask as soon as boot_sys() returns. */
85    pushl $restore_user_context
86    jmp   boot_sys
87END_FUNC(_start)
88
89/* ===== booting up another CPU ===== */
90#ifdef ENABLE_SMP_SUPPORT
91BEGIN_FUNC(boot_cpu_start)
92
93.code16
94    /* Set DS equal to CS and load GDTR register with GDT pointer */
95    movw %cs, %ax
96    movw %ax, %ds
97    lgdt _boot_gdt_ptr - boot_cpu_start
98
99    /* Enable Protected Mode */
100    movl %cr0, %eax
101    orl  $1,   %eax
102    movl %eax, %cr0
103
104    /* Reload CS with a far jump */
105    ljmpl $0x08, $1f
106
107.code32
108    /* Load DS/ES/SS with kernel data segment selector */
1091:  movw $0x10, %ax
110    movw %ax,   %ds
111    movw %ax,   %es
112    movw %ax,   %ss
113
114    /* Use temporary kernel boot stack pointer */
115    leal boot_stack_top, %esp
116
117    /* Reset EFLAGS register (also disables interrupts etc.) */
118    pushl $0
119    popf
120
121    /* Enable paging */
122    call enable_paging
123
124    /* Get index of this cpu, BSP always gets index of zero */
125    movl smp_aps_index, %ecx
126
127    /* Stop using shared boot stack and get a real stack and move to the top of the stack */
128    leal kernel_stack_alloc, %esp
129    inc %ecx
130    shll $CONFIG_KERNEL_STACK_BITS, %ecx
131    addl %ecx, %esp
132    subl $4, %esp
133
134    /* Call boot_node() and set restore_user_context() as return EIP. */
135    pushl $restore_user_context
136    jmp   boot_node
137END_FUNC(boot_cpu_start)
138
139_boot_gdt_ptr:
140    .word   (3 * 8) - 1 /* Limit: 3 segments * 8 bytes - 1 byte */
141    .long   _boot_gdt   /* Address of boot GDT */
142
143    .align 16
144_boot_gdt:
145    .quad 0x0000000000000000 /* Null segment */
146    .quad 0x00cf9b000000ffff /* 4GB kernel code segment */
147    .quad 0x00cf93000000ffff /* 4GB kernel data segment */
148
149.global boot_cpu_end
150boot_cpu_end:
151
152#endif /* ENABLE_SMP_SUPPORT */
153