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)
241 volatile STARTUP_CODE
*StartupCode
= NULL
;
244 Prepares Startup Code for APs.
245 This function prepares Startup Code for APs.
247 @retval EFI_SUCCESS The APs were started
248 @retval EFI_OUT_OF_RESOURCES Cannot allocate memory to start APs
252 PrepareAPStartupCode (
257 IA32_DESCRIPTOR Gdtr
;
258 EFI_PHYSICAL_ADDRESS StartAddress
;
260 StartAddress
= BASE_1MB
;
261 Status
= gBS
->AllocatePages (
264 EFI_SIZE_TO_PAGES (sizeof (*StartupCode
)),
267 if (EFI_ERROR (Status
)) {
271 StartupCode
= (STARTUP_CODE
*)(VOID
*)(UINTN
) StartAddress
;
272 CopyMem ((VOID
*) StartupCode
, &mStartupCodeTemplate
, sizeof (*StartupCode
));
273 StartupCode
->RealSegment
= (UINT16
) (((UINTN
) StartAddress
) >> 4);
276 StartupCode
->GdtLimit
= Gdtr
.Limit
;
277 StartupCode
->GdtBase
= (UINT32
) Gdtr
.Base
;
279 StartupCode
->CpuDxeEntryValue
= (UINTN
) AsmApEntryPoint
;
281 StartupCode
->FlatJmpOffset
+= (UINT32
) StartAddress
;
283 #if defined (MDE_CPU_X64)
284 StartupCode
->Cr3Value
= (UINT32
) AsmReadCr3 ();
285 StartupCode
->LongJmpOffset
+= (UINT32
) StartAddress
;
292 Free the code buffer of startup AP.
300 if (StartupCode
!= NULL
) {
301 gBS
->FreePages ((EFI_PHYSICAL_ADDRESS
)(UINTN
)(VOID
*) StartupCode
,
302 EFI_SIZE_TO_PAGES (sizeof (*StartupCode
)));
308 Starts the Application Processors and directs them to jump to the
311 The processor jumps to this code in flat mode, but the processor's
312 stack is not initialized.
314 @retval EFI_SUCCESS The APs were started
322 SendInitSipiSipiAllExcludingSelf ((UINT32
)(UINTN
)(VOID
*) StartupCode
);
324 // Wait 100 milliseconds for APs to arrive at the ApEntryPoint routine
326 MicroSecondDelay (100 * 1000);
332 Resets the Application Processor and directs it to jump to the
335 The processor jumps to this code in flat mode, but the processor's
336 stack is not initialized.
338 @param ProcessorId the AP of ProcessorId was reset
342 IN UINT32 ProcessorId
345 SendInitSipiSipi (ProcessorId
,
346 (UINT32
)(UINTN
)(VOID
*) StartupCode
);