1
2/**
3 * Low level multiprocessor boot code
4 */
5
6#define KERNEL_BASE 0xFFFF800000000000
7#define LOWMEM(_x) (_x - KERNEL_BASE)
8#define MPLOWMEM(_x) (_x - KERNEL_BASE + 0x7000)
9
10.extern bootpgtbl1
11.extern stack
12.extern Machine_InitAP
13
14.text
15
16/**
17 * mpstart_begin --
18 *
19 *	Support processors start executing here in 16-bit compat mode.
20 */
21.code16
22.globl mpstart_begin
23mpstart_begin:
24    // Disable interrupts
25    cli
26
27    // Initialize the segment registers to 0, which is an offset in 16-bit mode
28    xorw    %ax, %ax
29    movw    %ax, %ds
30    movw    %ax, %es
31    movw    %ax, %fs
32    movw    %ax, %gs
33
34    // Load 32-bit GDT
35    lgdt    (mpstartgdtdesc32 - mpstart_begin + 0x7000)
36
37    movl    %cr0, %eax
38    orl	    0x00000011, %eax
39    movl    %eax, %cr0
40
41    // Long jump to reload the code segment switching us into 32-bit mode
42    ljmp    $0x08, $(mpstart_enter32 - mpstart_begin + 0x7000)
43
44    nop
45    nop
46
47    // Now we're in 32-bit mode
48.code32
49mpstart_enter32:
50    nop
51    nop
52
53    // Initialize segment registers
54    movw    $0x10, %ax
55    movw    %ax, %ds
56    movw    %ax, %es
57    movw    %ax, %fs
58    movw    %ax, %gs
59
60    // Setup stack
61    movw    %ax,%ss
62    movl    $0x7000, %esp
63
64    // Reset EFLAGS
65    pushl   $0x0
66    popf
67
68    // Set CR4
69    movl    %cr4, %eax
70    orl     $0x0000006A0, %eax
71    movl    %eax, %cr4
72
73    // Temporary Page Table
74    movl    $LOWMEM(bootpgtbl1), %eax
75    movl    %eax, %cr3
76
77    // Set EFER
78    movl    $0xC0000080, %ecx
79    rdmsr
80    orl     $0x0900, %eax
81    wrmsr
82
83    // Load 64-bit GDT
84    movl    $LOWMEM(mpstartgdtdesc), %eax
85    lgdt    (%eax)
86
87    // Set CR0
88    movl    %cr0, %eax
89    // QEMU seems to set cr0 with garbage
90    andl    $0x1FF5FFC0, %eax
91    orl     $0x8005002B, %eax
92    movl    %eax, %cr0
93
94    // Long jump again to swithc us into 64-bit mode
95    movl    $LOWMEM(mpstart_enter64ptr), %edi
96    ljmp    *(%edi)
97
98    nop
99    nop
100
101    // Now we're playing with power
102.code64
103mpstart_enter64:
104    nop
105    nop
106
107    // Jump into the high memory address where the kernel should execute
108    movq    $LOWMEM(mpstart_high64ptr), %rdi
109    jmp	    *(%rdi)
110
111    nop
112    nop
113
114mpstart_high64:
115    nop
116    nop
117
118    // Load Initial CPU State
119    movq    (0x6F00), %rax
120    movq    (0x6F08), %rbx
121    movq    %rax, %cr3
122    movq    %rbx, %rsp
123
124    call    Machine_InitAP
125
126    // If we get here something went wrong so we write HALT to the display
1271:
128    movw    $(0x5000 + 'H'), (0xB8098)
129    movw    $(0x5000 + 'A'), (0xB809A)
130    movw    $(0x5000 + 'L'), (0xB809C)
131    movw    $(0x5000 + 'T'), (0xB809E)
132    jmp	    1b
133
134.p2align 4
135mpstart_enter64ptr:
136.long	LOWMEM(mpstart_enter64)
137.word	0x08
138
139.p2align 4
140mpstart_high64ptr:
141.quad	mpstart_high64
142
143/**
144 * 32-bit GDT Table
145 */
146.p2align 12
147mpstartgdt32:
148.quad	0x0000000000000000 /* Null */
149.quad	0x00CF9A000000FFFF /* Temporary CS */
150.quad	0x00CF92000000FFFF /* Temporary DS */
151.quad	0x0000000000000000
152.quad	0x0000000000000000
153.quad	0x0000000000000000
154.quad	0x0000000000000000
155.quad	0x0000000000000000
156
157.p2align 4
158mpstartgdtdesc32:
159.word	0x003F
160.long	LOWMEM(mpstartgdt32)
161
162.p2align 12
163mpstartgdt:
164.quad	0x0000000000000000 /* Null */
165.quad	0x00AF9C000000FFFF /* Kernel CS */
166.quad	0x00CF92000000FFFF /* Kernel DS */
167.quad	0x0000000000000000
168.quad	0x0000000000000000
169.quad	0x0000000000000000
170.quad	0x0000000000000000
171.quad	0x0000000000000000
172
173.p2align 4
174.quad	0x0
175mpstartgdtdesc:
176.word	0x003F
177.quad	LOWMEM(mpstartgdt)
178
179.globl mpstart_end
180mpstart_end:
181
182// Boot stack
183//.globl	mpstack
184//.comm	mpstack, STACK_SIZE
185
186