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
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.
29 UINT8 MovAxRealSegment
; UINT16 RealSegment
;
36 UINT32 MovEaxCr0Value
;
39 UINT8 FarJmp32Flat
[2]; UINT32 FlatJmpOffset
; UINT16 FlatJmpSelector
;
45 UINT32 MovEaxCr4Value
;
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];
55 #if defined (MDE_CPU_X64)
63 UINT8 MoveCr4ToEax
[3];
65 UINT8 MoveEaxToCr4
[3];
67 UINT8 MoveLongModeEnableMsrToEcx
[5];
69 UINT8 SetLongModeEnableBit
[4];
72 UINT8 MoveCr0ToEax
[3];
73 UINT8 SetCr0PagingBit
[4];
74 UINT8 MoveEaxToCr0
[3];
77 UINT8 FarJmp32LongMode
; UINT32 LongJmpOffset
; UINT16 LongJmpSelector
;
78 #endif // defined (MDE_CPU_X64)
80 #if defined (MDE_CPU_X64)
81 UINT8 MovEaxOrRaxCpuDxeEntry
[2]; UINTN CpuDxeEntryValue
;
83 UINT8 MovEaxOrRaxCpuDxeEntry
; UINTN CpuDxeEntryValue
;
85 UINT8 JmpToCpuDxeEntry
[2];
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.
96 * nasm -o ApStartup ApStartup.asm
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)
103 %define DEFAULT_CR0 0x00000023
104 %define DEFAULT_CR4 0x640
108 jmp short TransitionFromReal16To32BitFlat
119 TransitionFromReal16To32BitFlat:
135 jmp 0x5a5a:dword jumpTo32BitAndLandHere
137 jumpTo32BitAndLandHere:
150 ; Jump to CpuDxe for IA32
154 jz Transition32FlatTo64Flat
160 Transition32FlatTo64Flat:
165 bts eax, 5 ; enable PAE
175 mov cr0, eax ; enable paging
178 ; Jump to CpuDxe for X64
180 jmp 0x5a5a:jumpTo64BitAndLandHere
182 jumpTo64BitAndLandHere:
183 mov rax, 0xcdcdcdcdcdcdcdcd
186 STARTUP_CODE mStartupCodeTemplate
= {
187 { 0xeb, 0x06 }, // Jump to cli
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
),
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
209 #if defined (MDE_CPU_X64)
210 0xB8, 0x00000000, // mov eax, cr3 value
211 { 0x0F, 0x22, 0xd8 }, // mov cr3, eax
213 { 0x0F, 0x20, 0xE0 }, // mov eax, cr4
214 { 0x0F, 0xBA, 0xE8, 0x05 }, // bts eax, 5
215 { 0x0F, 0x22, 0xE0 }, // mov cr4, eax
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
222 { 0x0F, 0x20, 0xC0 }, // mov eax, cr0
223 { 0x0F, 0xBA, 0xE8, 0x1F }, // bts eax, 31
224 { 0x0F, 0x22, 0xC0 }, // mov cr0, eax
226 0xEA, // FarJmp32LongMode
227 OFFSET_OF(STARTUP_CODE
, MovEaxOrRaxCpuDxeEntry
),
229 #endif // defined (MDE_CPU_X64)
231 //0xeb, 0xfe, // jmp $
232 #if defined (MDE_CPU_X64)
233 { 0x48, 0xb8 }, 0x0, // mov rax, X64 CpuDxe MP Entry Point
235 0xB8, 0x0, // mov eax, IA32 CpuDxe MP Entry Point
237 { 0xff, 0xe0 }, // jmp to eax/rax (CpuDxe MP Entry Point)
243 Starts the Application Processors and directs them to jump to the
246 The processor jumps to this code in flat mode, but the processor's
247 stack is not initialized.
249 @param ApEntryPoint Pointer to the Entry Point routine
251 @retval EFI_SUCCESS The APs were started
252 @retval EFI_OUT_OF_RESOURCES Cannot allocate memory to start APs
257 IN STACKLESS_AP_ENTRY_POINT ApEntryPoint
261 volatile STARTUP_CODE
*StartupCode
;
262 IA32_DESCRIPTOR Gdtr
;
263 EFI_PHYSICAL_ADDRESS StartAddress
;
265 StartAddress
= BASE_1MB
;
266 Status
= gBS
->AllocatePages (
269 EFI_SIZE_TO_PAGES (sizeof (*StartupCode
)),
272 if (EFI_ERROR (Status
)) {
276 StartupCode
= (STARTUP_CODE
*)(VOID
*)(UINTN
) StartAddress
;
277 CopyMem ((VOID
*) StartupCode
, &mStartupCodeTemplate
, sizeof (*StartupCode
));
278 StartupCode
->RealSegment
= (UINT16
) (((UINTN
) StartAddress
) >> 4);
281 StartupCode
->GdtLimit
= Gdtr
.Limit
;
282 StartupCode
->GdtBase
= (UINT32
) Gdtr
.Base
;
284 StartupCode
->CpuDxeEntryValue
= (UINTN
) ApEntryPoint
;
286 StartupCode
->FlatJmpOffset
+= (UINT32
) StartAddress
;
288 #if defined (MDE_CPU_X64)
289 StartupCode
->Cr3Value
= (UINT32
) AsmReadCr3 ();
290 StartupCode
->LongJmpOffset
+= (UINT32
) StartAddress
;
293 SendInitSipiSipiAllExcludingSelf ((UINT32
)(UINTN
)(VOID
*) StartupCode
);
296 // Wait 100 milliseconds for APs to arrive at the ApEntryPoint routine
298 MicroSecondDelay (100 * 1000);
300 gBS
->FreePages (StartAddress
, EFI_SIZE_TO_PAGES (sizeof (*StartupCode
)));