From: Jordan Justen <jordan.l.jus...@intel.com> This routine starts the APs and directs them to run the specified code.
The specified code is entered without a stack being available. Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Jordan Justen <jordan.l.jus...@intel.com> --- UefiCpuPkg/CpuDxe/ApStartup.asm | 111 +++++++++++++++++++++ UefiCpuPkg/CpuDxe/ApStartup.c | 209 ++++++++++++++++++++++++++++++++++++++++ UefiCpuPkg/CpuDxe/CpuDxe.h | 1 + UefiCpuPkg/CpuDxe/CpuDxe.inf | 3 + UefiCpuPkg/CpuDxe/CpuMp.h | 24 +++++ 5 files changed, 348 insertions(+) create mode 100644 UefiCpuPkg/CpuDxe/ApStartup.asm create mode 100644 UefiCpuPkg/CpuDxe/ApStartup.c diff --git a/UefiCpuPkg/CpuDxe/ApStartup.asm b/UefiCpuPkg/CpuDxe/ApStartup.asm new file mode 100644 index 0000000..049a45f --- /dev/null +++ b/UefiCpuPkg/CpuDxe/ApStartup.asm @@ -0,0 +1,111 @@ +;------------------------------------------------------------------------------ +; @file +; Transition from 16 bit real mode into 64 bit long mode +; +; Copyright (c) 2008 - 2012, Intel Corporation. All rights reserved.<BR> +; This program and the accompanying materials +; are licensed and made available under the terms and conditions of the BSD License +; which accompanies this distribution. The full text of the license may be found at +; http://opensource.org/licenses/bsd-license.php +; +; THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +; WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +; +;------------------------------------------------------------------------------ + +; +; NOTE: This file is *NOT USED* in the build. It was used to help create +; ApStartup.c. +; +; To assemble: +; * nasm -o ApStartup ApStartup.asm +; Then disassemble: +; * ndisasm -b 16 ApStartup +; * ndisasm -b 16 -e 6 ApStartup +; * ndisasm -b 32 -e 32 ApStartup (This -e offset may need adjustment) +; * ndisasm -b 64 -e 0x83 ApStartup (This -e offset may need adjustment) +; + +%define DEFAULT_CR0 0x00000023 +%define DEFAULT_CR4 0x640 + +BITS 16 + + jmp short TransitionFromReal16To32BitFlat + +ALIGN 2 + +Gdtr: + dw 0x5a5a + dd 0x5a5a5a5a + +; +; Modified: EAX, EBX +; +TransitionFromReal16To32BitFlat: + + cli + mov ax, 0x5a5a + mov ds, ax + + mov bx, Gdtr +o32 lgdt [ds:bx] + + mov eax, cr4 + btc eax, 5 + mov cr4, eax + + mov eax, DEFAULT_CR0 + mov cr0, eax + + jmp 0x5a5a:dword jumpTo32BitAndLandHere +BITS 32 +jumpTo32BitAndLandHere: + + mov eax, DEFAULT_CR4 + mov cr4, eax + + mov ax, 0x5a5a + mov ds, ax + mov es, ax + mov fs, ax + mov gs, ax + mov ss, ax + +; +; Jump to CpuDxe for IA32 +; + mov eax, 0x5a5a5a5a + or eax, eax + jz Transition32FlatTo64Flat + jmp eax + +; +; Transition to X64 +; +Transition32FlatTo64Flat: + mov eax, 0x5a5a5a5a + mov cr3, eax + + mov eax, cr4 + bts eax, 5 ; enable PAE + mov cr4, eax + + mov ecx, 0xc0000080 + rdmsr + bts eax, 8 ; set LME + wrmsr + + mov eax, cr0 + bts eax, 31 ; set PG + mov cr0, eax ; enable paging + +; +; Jump to CpuDxe for X64 +; + jmp 0x5a5a:jumpTo64BitAndLandHere +BITS 64 +jumpTo64BitAndLandHere: + mov rax, 0xcdcdcdcdcdcdcdcd + jmp rax + diff --git a/UefiCpuPkg/CpuDxe/ApStartup.c b/UefiCpuPkg/CpuDxe/ApStartup.c new file mode 100644 index 0000000..7b6f5dd --- /dev/null +++ b/UefiCpuPkg/CpuDxe/ApStartup.c @@ -0,0 +1,209 @@ +/** @file + CPU DXE AP Startup + + Copyright (c) 2008 - 2012, Intel Corporation. All rights reserved.<BR> + This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include "CpuDxe.h" +#include "CpuGdt.h" +#include "CpuMp.h" + +#pragma pack(1) + +typedef struct { + UINT8 JmpToCli[2]; + + UINT16 GdtLimit; + UINT32 GdtBase; + + UINT8 Cli; + + UINT8 MovAxRealSegment; UINT16 RealSegment; + UINT8 MovDsAx[2]; + + UINT8 MovBxGdtr[3]; + UINT8 LoadGdt[5]; + + UINT8 MovEaxCr0[2]; + UINT32 MovEaxCr0Value; + UINT8 MovCr0Eax[3]; + + UINT8 FarJmp32Flat[2]; UINT32 FlatJmpOffset; UINT16 FlatJmpSelector; + + // + // Now in IA32 + // + UINT8 MovEaxCr4; + UINT32 MovEaxCr4Value; + UINT8 MovCr4Eax[3]; + + UINT8 MoveDataSelectorIntoAx[2]; UINT16 FlatDataSelector; + UINT8 MoveFlatDataSelectorFromAxToDs[2]; + UINT8 MoveFlatDataSelectorFromAxToEs[2]; + UINT8 MoveFlatDataSelectorFromAxToFs[2]; + UINT8 MoveFlatDataSelectorFromAxToGs[2]; + UINT8 MoveFlatDataSelectorFromAxToSs[2]; + +#if defined (MDE_CPU_X64) + // + // Transition to X64 + // + UINT8 MovEaxCr3; + UINT32 Cr3Value; + UINT8 MovCr3Eax[3]; + + UINT8 MoveCr4ToEax[3]; + UINT8 SetCr4Bit5[4]; + UINT8 MoveEaxToCr4[3]; + + UINT8 MoveLongModeEnableMsrToEcx[5]; + UINT8 ReadLmeMsr[2]; + UINT8 SetLongModeEnableBit[4]; + UINT8 WriteLmeMsr[2]; + + UINT8 MoveCr0ToEax[3]; + UINT8 SetCr0PagingBit[4]; + UINT8 MoveEaxToCr0[3]; + //UINT8 DeadLoop[2]; + + UINT8 FarJmp32LongMode; UINT32 LongJmpOffset; UINT16 LongJmpSelector; +#endif // defined (MDE_CPU_X64) + +#if defined (MDE_CPU_X64) + UINT8 MovEaxOrRaxCpuDxeEntry[2]; UINTN CpuDxeEntryValue; +#else + UINT8 MovEaxOrRaxCpuDxeEntry; UINTN CpuDxeEntryValue; +#endif + UINT8 JmpToCpuDxeEntry[2]; + +} STARTUP_CODE; + +#pragma pack() + +STARTUP_CODE mStartupCodeTemplate = { + { 0xeb, 0x06 }, // Jump to cli + 0, // GDT Limit + 0, // GDT Base + 0xfa, // cli (Clear Interrupts) + 0xb8, 0x0000, // mov ax, RealSegment + { 0x8e, 0xd8 }, // mov ds, ax + { 0xBB, 0x02, 0x00 }, // mov bx, Gdtr + { 0x3e, 0x66, 0x0f, 0x01, 0x17 }, // lgdt [ds:bx] + { 0x66, 0xB8 }, 0x00000023, // mov eax, cr0 value + { 0x0F, 0x22, 0xC0 }, // mov cr0, eax + { 0x66, 0xEA }, // far jmp to 32-bit flat + OFFSET_OF(STARTUP_CODE, MovEaxCr4), + LINEAR_CODE_SEL, + 0xB8, 0x00000640, // mov eax, cr4 value + { 0x0F, 0x22, 0xe0 }, // mov cr4, eax + { 0x66, 0xb8 }, CPU_DATA_SEL, // mov ax, FlatDataSelector + { 0x8e, 0xd8 }, // mov ds, ax + { 0x8e, 0xc0 }, // mov es, ax + { 0x8e, 0xe0 }, // mov fs, ax + { 0x8e, 0xe8 }, // mov gs, ax + { 0x8e, 0xd0 }, // mov ss, ax + +#if defined (MDE_CPU_X64) + 0xB8, 0x00000000, // mov eax, cr3 value + { 0x0F, 0x22, 0xd8 }, // mov cr3, eax + + { 0x0F, 0x20, 0xE0 }, // mov eax, cr4 + { 0x0F, 0xBA, 0xE8, 0x05 }, // bts eax, 5 + { 0x0F, 0x22, 0xE0 }, // mov cr4, eax + + { 0xB9, 0x80, 0x00, 0x00, 0xC0 }, // mov ecx, 0xc0000080 + { 0x0F, 0x32 }, // rdmsr + { 0x0F, 0xBA, 0xE8, 0x08 }, // bts eax, 8 + { 0x0F, 0x30 }, // wrmsr + + { 0x0F, 0x20, 0xC0 }, // mov eax, cr0 + { 0x0F, 0xBA, 0xE8, 0x1F }, // bts eax, 31 + { 0x0F, 0x22, 0xC0 }, // mov cr0, eax + + 0xEA, // FarJmp32LongMode + OFFSET_OF(STARTUP_CODE, MovEaxOrRaxCpuDxeEntry), + LINEAR_CODE64_SEL, +#endif // defined (MDE_CPU_X64) + + //0xeb, 0xfe, // jmp $ +#if defined (MDE_CPU_X64) + { 0x48, 0xb8 }, 0x0, // mov rax, X64 CpuDxe MP Entry Point +#else + 0xB8, 0x0, // mov eax, IA32 CpuDxe MP Entry Point +#endif + { 0xff, 0xe0 }, // jmp to eax/rax (CpuDxe MP Entry Point) + +}; + + +/** + Starts the Application Processors and directs them to jump to the + specified routine. + + The processor jumps to this code in flat mode, but the processor's + stack is not initialized. + + @param ApEntryPoint Pointer to the Entry Point routine + + @retval EFI_SUCCESS The APs were started + @retval EFI_OUT_OF_RESOURCES Cannot allocate memory to start APs + +**/ +EFI_STATUS +StartApsStackless ( + IN STACKLESS_AP_ENTRY_POINT ApEntryPoint + ) +{ + EFI_STATUS Status; + volatile STARTUP_CODE *StartupCode; + IA32_DESCRIPTOR Gdtr; + EFI_PHYSICAL_ADDRESS StartAddress; + + StartAddress = BASE_1MB; + Status = gBS->AllocatePages ( + AllocateMaxAddress, + EfiACPIMemoryNVS, + EFI_SIZE_TO_PAGES (sizeof (*StartupCode)), + &StartAddress + ); + if (EFI_ERROR (Status)) { + return Status; + } + + StartupCode = (STARTUP_CODE*)(VOID*)(UINTN) StartAddress; + CopyMem ((VOID*) StartupCode, &mStartupCodeTemplate, sizeof (*StartupCode)); + StartupCode->RealSegment = (UINT16) (((UINTN) StartAddress) >> 4); + + AsmReadGdtr (&Gdtr); + StartupCode->GdtLimit = Gdtr.Limit; + StartupCode->GdtBase = (UINT32) Gdtr.Base; + + StartupCode->CpuDxeEntryValue = (UINTN) ApEntryPoint; + + StartupCode->FlatJmpOffset += (UINT32) StartAddress; + +#if defined (MDE_CPU_X64) + StartupCode->Cr3Value = (UINT32) AsmReadCr3 (); + StartupCode->LongJmpOffset += (UINT32) StartAddress; +#endif + + SendInitSipiSipiAllExcludingSelf ((UINT32)(UINTN)(VOID*) StartupCode); + + // + // Wait 100 milliseconds for APs to arrive at the ApEntryPoint routine + // + MicroSecondDelay (100 * 1000); + + gBS->FreePages (StartAddress, EFI_SIZE_TO_PAGES (sizeof (*StartupCode))); + + return EFI_SUCCESS; +} + diff --git a/UefiCpuPkg/CpuDxe/CpuDxe.h b/UefiCpuPkg/CpuDxe/CpuDxe.h index 2001cfc..2aef626 100644 --- a/UefiCpuPkg/CpuDxe/CpuDxe.h +++ b/UefiCpuPkg/CpuDxe/CpuDxe.h @@ -32,6 +32,7 @@ #include <Library/UefiCpuLib.h> #include <Library/UefiLib.h> #include <Library/CpuExceptionHandlerLib.h> +#include <Library/TimerLib.h> #include <Guid/IdleLoopEvent.h> #include <Guid/VectorHandoffTable.h> diff --git a/UefiCpuPkg/CpuDxe/CpuDxe.inf b/UefiCpuPkg/CpuDxe/CpuDxe.inf index 9952eb7..c2f12b7 100644 --- a/UefiCpuPkg/CpuDxe/CpuDxe.inf +++ b/UefiCpuPkg/CpuDxe/CpuDxe.inf @@ -41,11 +41,14 @@ UefiCpuLib UefiLib CpuExceptionHandlerLib + TimerLib [Sources] + ApStartup.c CpuDxe.c CpuDxe.h CpuGdt.c + CpuGdt.h CpuMp.c CpuMp.h diff --git a/UefiCpuPkg/CpuDxe/CpuMp.h b/UefiCpuPkg/CpuDxe/CpuMp.h index cdca152..6f5e615 100644 --- a/UefiCpuPkg/CpuDxe/CpuMp.h +++ b/UefiCpuPkg/CpuDxe/CpuMp.h @@ -23,6 +23,30 @@ VOID InitializeMpSupport ( VOID ); +typedef +VOID +(EFIAPI *STACKLESS_AP_ENTRY_POINT)( + VOID + ); + +/** + Starts the Application Processors and directs them to jump to the + specified routine. + + The processor jumps to this code in flat mode, but the processor's + stack is not initialized. + + @param ApEntryPoint Pointer to the Entry Point routine + + @retval EFI_SUCCESS The APs were started + @retval EFI_OUT_OF_RESOURCES Cannot allocate memory to start APs + +**/ +EFI_STATUS +StartApsStackless ( + IN STACKLESS_AP_ENTRY_POINT ApEntryPoint + ); + /** The AP entry point that the Startup-IPI target code will jump to. -- 1.9.3 ------------------------------------------------------------------------------ _______________________________________________ edk2-devel mailing list edk2-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/edk2-devel