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

Reply via email to