]> git.proxmox.com Git - mirror_edk2.git/blob - UefiCpuPkg/CpuDxe/ApStartup.c
UefiCpuPkg/CpuDxe: split out StartupCode from StartApsStackless()
[mirror_edk2.git] / UefiCpuPkg / CpuDxe / ApStartup.c
1 /** @file
2 CPU DXE AP Startup
3
4 Copyright (c) 2008 - 2012, Intel Corporation. All rights reserved.<BR>
5 This program and the accompanying materials
6 are licensed and made available under the terms and conditions of the BSD License
7 which accompanies this distribution. The full text of the license may be found at
8 http://opensource.org/licenses/bsd-license.php
9
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
12
13 **/
14
15 #include "CpuDxe.h"
16 #include "CpuGdt.h"
17 #include "CpuMp.h"
18
19 #pragma pack(1)
20
21 typedef struct {
22 UINT8 JmpToCli[2];
23
24 UINT16 GdtLimit;
25 UINT32 GdtBase;
26
27 UINT8 Cli;
28
29 UINT8 MovAxRealSegment; UINT16 RealSegment;
30 UINT8 MovDsAx[2];
31
32 UINT8 MovBxGdtr[3];
33 UINT8 LoadGdt[5];
34
35 UINT8 MovEaxCr0[2];
36 UINT32 MovEaxCr0Value;
37 UINT8 MovCr0Eax[3];
38
39 UINT8 FarJmp32Flat[2]; UINT32 FlatJmpOffset; UINT16 FlatJmpSelector;
40
41 //
42 // Now in IA32
43 //
44 UINT8 MovEaxCr4;
45 UINT32 MovEaxCr4Value;
46 UINT8 MovCr4Eax[3];
47
48 UINT8 MoveDataSelectorIntoAx[2]; UINT16 FlatDataSelector;
49 UINT8 MoveFlatDataSelectorFromAxToDs[2];
50 UINT8 MoveFlatDataSelectorFromAxToEs[2];
51 UINT8 MoveFlatDataSelectorFromAxToFs[2];
52 UINT8 MoveFlatDataSelectorFromAxToGs[2];
53 UINT8 MoveFlatDataSelectorFromAxToSs[2];
54
55 #if defined (MDE_CPU_X64)
56 //
57 // Transition to X64
58 //
59 UINT8 MovEaxCr3;
60 UINT32 Cr3Value;
61 UINT8 MovCr3Eax[3];
62
63 UINT8 MoveCr4ToEax[3];
64 UINT8 SetCr4Bit5[4];
65 UINT8 MoveEaxToCr4[3];
66
67 UINT8 MoveLongModeEnableMsrToEcx[5];
68 UINT8 ReadLmeMsr[2];
69 UINT8 SetLongModeEnableBit[4];
70 UINT8 WriteLmeMsr[2];
71
72 UINT8 MoveCr0ToEax[3];
73 UINT8 SetCr0PagingBit[4];
74 UINT8 MoveEaxToCr0[3];
75 //UINT8 DeadLoop[2];
76
77 UINT8 FarJmp32LongMode; UINT32 LongJmpOffset; UINT16 LongJmpSelector;
78 #endif // defined (MDE_CPU_X64)
79
80 #if defined (MDE_CPU_X64)
81 UINT8 MovEaxOrRaxCpuDxeEntry[2]; UINTN CpuDxeEntryValue;
82 #else
83 UINT8 MovEaxOrRaxCpuDxeEntry; UINTN CpuDxeEntryValue;
84 #endif
85 UINT8 JmpToCpuDxeEntry[2];
86
87 } STARTUP_CODE;
88
89 #pragma pack()
90
91 /**
92 This .asm code used for translating processor from 16 bit real mode into
93 64 bit long mode. which help to create the mStartupCodeTemplate value.
94
95 To assemble:
96 * nasm -o ApStartup ApStartup.asm
97 Then disassemble:
98 * ndisasm -b 16 ApStartup
99 * ndisasm -b 16 -e 6 ApStartup
100 * ndisasm -b 32 -e 32 ApStartup (This -e offset may need adjustment)
101 * ndisasm -b 64 -e 0x83 ApStartup (This -e offset may need adjustment)
102
103 %define DEFAULT_CR0 0x00000023
104 %define DEFAULT_CR4 0x640
105
106 BITS 16
107
108 jmp short TransitionFromReal16To32BitFlat
109
110 ALIGN 2
111
112 Gdtr:
113 dw 0x5a5a
114 dd 0x5a5a5a5a
115
116 ;
117 ; Modified: EAX, EBX
118 ;
119 TransitionFromReal16To32BitFlat:
120
121 cli
122 mov ax, 0x5a5a
123 mov ds, ax
124
125 mov bx, Gdtr
126 o32 lgdt [ds:bx]
127
128 mov eax, cr4
129 btc eax, 5
130 mov cr4, eax
131
132 mov eax, DEFAULT_CR0
133 mov cr0, eax
134
135 jmp 0x5a5a:dword jumpTo32BitAndLandHere
136 BITS 32
137 jumpTo32BitAndLandHere:
138
139 mov eax, DEFAULT_CR4
140 mov cr4, eax
141
142 mov ax, 0x5a5a
143 mov ds, ax
144 mov es, ax
145 mov fs, ax
146 mov gs, ax
147 mov ss, ax
148
149 ;
150 ; Jump to CpuDxe for IA32
151 ;
152 mov eax, 0x5a5a5a5a
153 or eax, eax
154 jz Transition32FlatTo64Flat
155 jmp eax
156
157 ;
158 ; Transition to X64
159 ;
160 Transition32FlatTo64Flat:
161 mov eax, 0x5a5a5a5a
162 mov cr3, eax
163
164 mov eax, cr4
165 bts eax, 5 ; enable PAE
166 mov cr4, eax
167
168 mov ecx, 0xc0000080
169 rdmsr
170 bts eax, 8 ; set LME
171 wrmsr
172
173 mov eax, cr0
174 bts eax, 31 ; set PG
175 mov cr0, eax ; enable paging
176
177 ;
178 ; Jump to CpuDxe for X64
179 ;
180 jmp 0x5a5a:jumpTo64BitAndLandHere
181 BITS 64
182 jumpTo64BitAndLandHere:
183 mov rax, 0xcdcdcdcdcdcdcdcd
184 jmp rax
185 **/
186 STARTUP_CODE mStartupCodeTemplate = {
187 { 0xeb, 0x06 }, // Jump to cli
188 0, // GDT Limit
189 0, // GDT Base
190 0xfa, // cli (Clear Interrupts)
191 0xb8, 0x0000, // mov ax, RealSegment
192 { 0x8e, 0xd8 }, // mov ds, ax
193 { 0xBB, 0x02, 0x00 }, // mov bx, Gdtr
194 { 0x3e, 0x66, 0x0f, 0x01, 0x17 }, // lgdt [ds:bx]
195 { 0x66, 0xB8 }, 0x00000023, // mov eax, cr0 value
196 { 0x0F, 0x22, 0xC0 }, // mov cr0, eax
197 { 0x66, 0xEA }, // far jmp to 32-bit flat
198 OFFSET_OF(STARTUP_CODE, MovEaxCr4),
199 LINEAR_CODE_SEL,
200 0xB8, 0x00000640, // mov eax, cr4 value
201 { 0x0F, 0x22, 0xe0 }, // mov cr4, eax
202 { 0x66, 0xb8 }, CPU_DATA_SEL, // mov ax, FlatDataSelector
203 { 0x8e, 0xd8 }, // mov ds, ax
204 { 0x8e, 0xc0 }, // mov es, ax
205 { 0x8e, 0xe0 }, // mov fs, ax
206 { 0x8e, 0xe8 }, // mov gs, ax
207 { 0x8e, 0xd0 }, // mov ss, ax
208
209 #if defined (MDE_CPU_X64)
210 0xB8, 0x00000000, // mov eax, cr3 value
211 { 0x0F, 0x22, 0xd8 }, // mov cr3, eax
212
213 { 0x0F, 0x20, 0xE0 }, // mov eax, cr4
214 { 0x0F, 0xBA, 0xE8, 0x05 }, // bts eax, 5
215 { 0x0F, 0x22, 0xE0 }, // mov cr4, eax
216
217 { 0xB9, 0x80, 0x00, 0x00, 0xC0 }, // mov ecx, 0xc0000080
218 { 0x0F, 0x32 }, // rdmsr
219 { 0x0F, 0xBA, 0xE8, 0x08 }, // bts eax, 8
220 { 0x0F, 0x30 }, // wrmsr
221
222 { 0x0F, 0x20, 0xC0 }, // mov eax, cr0
223 { 0x0F, 0xBA, 0xE8, 0x1F }, // bts eax, 31
224 { 0x0F, 0x22, 0xC0 }, // mov cr0, eax
225
226 0xEA, // FarJmp32LongMode
227 OFFSET_OF(STARTUP_CODE, MovEaxOrRaxCpuDxeEntry),
228 LINEAR_CODE64_SEL,
229 #endif // defined (MDE_CPU_X64)
230
231 //0xeb, 0xfe, // jmp $
232 #if defined (MDE_CPU_X64)
233 { 0x48, 0xb8 }, 0x0, // mov rax, X64 CpuDxe MP Entry Point
234 #else
235 0xB8, 0x0, // mov eax, IA32 CpuDxe MP Entry Point
236 #endif
237 { 0xff, 0xe0 }, // jmp to eax/rax (CpuDxe MP Entry Point)
238
239 };
240
241 volatile STARTUP_CODE *StartupCode = NULL;
242
243 /**
244 Prepares Startup Code for APs.
245 This function prepares Startup Code for APs.
246
247 @retval EFI_SUCCESS The APs were started
248 @retval EFI_OUT_OF_RESOURCES Cannot allocate memory to start APs
249
250 **/
251 EFI_STATUS
252 PrepareAPStartupCode (
253 VOID
254 )
255 {
256 EFI_STATUS Status;
257 IA32_DESCRIPTOR Gdtr;
258 EFI_PHYSICAL_ADDRESS StartAddress;
259
260 StartAddress = BASE_1MB;
261 Status = gBS->AllocatePages (
262 AllocateMaxAddress,
263 EfiACPIMemoryNVS,
264 EFI_SIZE_TO_PAGES (sizeof (*StartupCode)),
265 &StartAddress
266 );
267 if (EFI_ERROR (Status)) {
268 return Status;
269 }
270
271 StartupCode = (STARTUP_CODE*)(VOID*)(UINTN) StartAddress;
272 CopyMem ((VOID*) StartupCode, &mStartupCodeTemplate, sizeof (*StartupCode));
273 StartupCode->RealSegment = (UINT16) (((UINTN) StartAddress) >> 4);
274
275 AsmReadGdtr (&Gdtr);
276 StartupCode->GdtLimit = Gdtr.Limit;
277 StartupCode->GdtBase = (UINT32) Gdtr.Base;
278
279 StartupCode->CpuDxeEntryValue = (UINTN) AsmApEntryPoint;
280
281 StartupCode->FlatJmpOffset += (UINT32) StartAddress;
282
283 #if defined (MDE_CPU_X64)
284 StartupCode->Cr3Value = (UINT32) AsmReadCr3 ();
285 StartupCode->LongJmpOffset += (UINT32) StartAddress;
286 #endif
287
288 return EFI_SUCCESS;
289 }
290
291 /**
292 Free the code buffer of startup AP.
293
294 **/
295 VOID
296 FreeApStartupCode (
297 VOID
298 )
299 {
300 if (StartupCode != NULL) {
301 gBS->FreePages ((EFI_PHYSICAL_ADDRESS)(UINTN)(VOID*) StartupCode,
302 EFI_SIZE_TO_PAGES (sizeof (*StartupCode)));
303 }
304 }
305
306
307 /**
308 Starts the Application Processors and directs them to jump to the
309 specified routine.
310
311 The processor jumps to this code in flat mode, but the processor's
312 stack is not initialized.
313
314 @retval EFI_SUCCESS The APs were started
315
316 **/
317 EFI_STATUS
318 StartApsStackless (
319 VOID
320 )
321 {
322 SendInitSipiSipiAllExcludingSelf ((UINT32)(UINTN)(VOID*) StartupCode);
323 //
324 // Wait 100 milliseconds for APs to arrive at the ApEntryPoint routine
325 //
326 MicroSecondDelay (100 * 1000);
327
328 return EFI_SUCCESS;
329 }
330