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