]> git.proxmox.com Git - mirror_edk2.git/commitdiff
Check in thunk driver to produce PI MP Services Protocol based on Framework MP Servic...
authorxli24 <xli24@6f19259b-4bc3-4df7-8a09-765794883524>
Tue, 15 Dec 2009 03:00:49 +0000 (03:00 +0000)
committerxli24 <xli24@6f19259b-4bc3-4df7-8a09-765794883524>
Tue, 15 Dec 2009 03:00:49 +0000 (03:00 +0000)
git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@9563 6f19259b-4bc3-4df7-8a09-765794883524

EdkCompatibilityPkg/Compatibility/MpServicesOnFrameworkMpServicesThunk/IA32/AsmInclude.inc [new file with mode: 0644]
EdkCompatibilityPkg/Compatibility/MpServicesOnFrameworkMpServicesThunk/IA32/MpFuncs.S [new file with mode: 0644]
EdkCompatibilityPkg/Compatibility/MpServicesOnFrameworkMpServicesThunk/IA32/MpFuncs.asm [new file with mode: 0644]
EdkCompatibilityPkg/Compatibility/MpServicesOnFrameworkMpServicesThunk/MpServicesOnFrameworkMpServicesThunk.c [new file with mode: 0644]
EdkCompatibilityPkg/Compatibility/MpServicesOnFrameworkMpServicesThunk/MpServicesOnFrameworkMpServicesThunk.h [new file with mode: 0644]
EdkCompatibilityPkg/Compatibility/MpServicesOnFrameworkMpServicesThunk/MpServicesOnFrameworkMpServicesThunk.inf [new file with mode: 0644]
EdkCompatibilityPkg/Compatibility/MpServicesOnFrameworkMpServicesThunk/X64/AsmInclude.inc [new file with mode: 0644]
EdkCompatibilityPkg/Compatibility/MpServicesOnFrameworkMpServicesThunk/X64/MpFuncs.S [new file with mode: 0644]
EdkCompatibilityPkg/Compatibility/MpServicesOnFrameworkMpServicesThunk/X64/MpFuncs.asm [new file with mode: 0644]
EdkCompatibilityPkg/EdkCompatibilityPkg.dsc

diff --git a/EdkCompatibilityPkg/Compatibility/MpServicesOnFrameworkMpServicesThunk/IA32/AsmInclude.inc b/EdkCompatibilityPkg/Compatibility/MpServicesOnFrameworkMpServicesThunk/IA32/AsmInclude.inc
new file mode 100644 (file)
index 0000000..2714817
--- /dev/null
@@ -0,0 +1,25 @@
+;------------------------------------------------------------------------------\r
+; Include file for IA32 MpFuncs.asm\r
+;\r
+; Copyright (c) 2009, Intel Corporation\r
+; All rights reserved. This program and the accompanying materials\r
+; are licensed and made available under the terms and conditions of the BSD License\r
+; which accompanies this distribution.  The full text of the license may be found at\r
+; http://opensource.org/licenses/bsd-license.php\r
+;\r
+; THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+; WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+;\r
+;------------------------------------------------------------------------------\r
+\r
+VacantFlag             Equ   00h\r
+NotVacantFlag          Equ   0ffh\r
+\r
+LockLocation        equ        RendezvousFunnelProcEnd - RendezvousFunnelProcStart\r
+StackStart          equ        LockLocation + 4h\r
+StackSize           equ        LockLocation + 8h\r
+RendezvousProc      equ        LockLocation + 0Ch\r
+GdtrProfile         equ        LockLocation + 10h\r
+BufferStart         equ        LockLocation + 18h\r
+\r
+;-------------------------------------------------------------------------------\r
diff --git a/EdkCompatibilityPkg/Compatibility/MpServicesOnFrameworkMpServicesThunk/IA32/MpFuncs.S b/EdkCompatibilityPkg/Compatibility/MpServicesOnFrameworkMpServicesThunk/IA32/MpFuncs.S
new file mode 100644 (file)
index 0000000..40f5759
--- /dev/null
@@ -0,0 +1,154 @@
+#------------------------------------------------------------------------------\r
+# IA32 assembly file for AP startup vector.\r
+#\r
+# Copyright (c) 2009, Intel Corporation\r
+# All rights reserved. This program and the accompanying materials\r
+# are licensed and made available under the terms and conditions of the BSD License\r
+# which accompanies this distribution.  The full text of the license may be found at\r
+# http://opensource.org/licenses/bsd-license.php\r
+#\r
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+#\r
+#------------------------------------------------------------------------------\r
+\r
+.equ                   VacantFlag,       0x0\r
+.equ                   NotVacantFlag,    0xff\r
+\r
+.equ                   LockLocation,     RendezvousFunnelProcEnd - RendezvousFunnelProcStart\r
+.equ                   StackStart,       LockLocation + 0x04\r
+.equ                   StackSize,        LockLocation + 0x08\r
+.equ                   RendezvousProc,   LockLocation + 0x0C\r
+.equ                   GdtrProfile,      LockLocation + 0x10\r
+.equ                   BufferStart,      LockLocation + 0x18\r
+\r
+#-------------------------------------------------------------------------------------\r
+#RendezvousFunnelProc  procedure follows. All APs execute their procedure. This\r
+#procedure serializes all the AP processors through an Init sequence. It must be\r
+#noted that APs arrive here very raw...ie: real mode, no stack.\r
+#ALSO THIS PROCEDURE IS EXECUTED BY APs ONLY ON 16 BIT MODE. HENCE THIS PROC\r
+#IS IN MACHINE CODE.\r
+#-------------------------------------------------------------------------------------\r
+#RendezvousFunnelProc (&WakeUpBuffer,MemAddress);\r
+\r
+ASM_GLOBAL ASM_PFX(RendezvousFunnelProc)\r
+ASM_PFX(RendezvousFunnelProc):\r
+RendezvousFunnelProcStart:\r
+\r
+\r
+# At this point CS = 0x(vv00) and ip= 0x0.\r
+\r
+        .byte 0x8c,0xc8               # mov        ax,  cs\r
+        .byte 0x8e,0xd8               # mov        ds,  ax\r
+        .byte 0x8e,0xc0               # mov        es,  ax\r
+        .byte 0x8e,0xd0               # mov        ss,  ax \r
+        .byte 0x33,0xc0               # xor        ax,  ax\r
+        .byte 0x8e,0xe0               # mov        fs,  ax\r
+        .byte 0x8e,0xe8               # mov        gs,  ax\r
+\r
+# Switch to flat mode.\r
+\r
+        .byte 0xBE\r
+        .word BufferStart\r
+        .byte 0x66,0x8B,0xC           # mov        ecx,dword ptr [si]          ; ECX is keeping the start address of wakeup buffer\r
+\r
+        .byte 0xFA                    # cli\r
+        .byte 0xBE\r
+        .word GdtrProfile\r
+        .byte 0x66                    # db         66h\r
+        .byte 0x2E,0xF,0x1,0x14       # lgdt       fword ptr cs:[si]\r
+\r
+        .byte 0x33,0xC0               # xor        ax,  ax\r
+        .byte 0x8E,0xD8               # mov        ds,  ax\r
+        .byte 0xF,0x20,0xC0           # mov        eax, cr0                    ; Get control register 0\r
+        .byte 0x66,0x83,0xC8,0x1      # or         eax, 000000001h             ; Set PE bit (bit #0)\r
+        .byte 0xF,0x22,0xC0           # mov        cr0, eax\r
+\r
+\r
+#step-4:\r
+\r
+FLAT32_JUMP:\r
+        .byte 0x66\r
+        .byte 0x67\r
+        .byte 0xEA              # far jump\r
+        .long 0x0\r
+        .word 0x10\r
+\r
+ProtectedModeStart:                   # protected mode entry point\r
+\r
+        movw        $0x8,%ax\r
+        .byte       0x66\r
+        movw        %ax,%ds\r
+        .byte       0x66\r
+        movw        %ax,%es\r
+        .byte       0x66\r
+        movw        %ax,%fs\r
+        .byte       0x66\r
+        movw        %ax,%gs\r
+        .byte       0x66\r
+        movw        %ax,%ss           # Flat mode setup.\r
+\r
+\r
+        movl        %esi,%edi\r
+        addl        $LockLocation, %edi\r
+        movb        $NotVacantFlag, %al\r
+TestLock:\r
+        xchgb       (%edi), %al\r
+        cmpb        $NotVacantFlag, %al\r
+        jz          TestLock\r
+\r
+ProgramStack:\r
+        movl        %esi,%edi\r
+        addl        $StackSize, %edi\r
+        movl        (%edi), %eax\r
+        movl        %esi,%edi\r
+        addl        $StackStart, %edi\r
+        addl        (%edi), %eax\r
+        movl        %eax,%esp\r
+        movl        %eax, (%edi)\r
+\r
+Releaselock:\r
+        movb        $VacantFlag, %al\r
+        movl        %esi,%edi\r
+        addl        $LockLocation, %edi\r
+        xchgb       (%edi), %al\r
+\r
+        #\r
+        # Call C Function\r
+        #\r
+        movl        %esi,%edi\r
+        addl        $RendezvousProc, %edi\r
+        movl        (%edi), %ebx\r
+\r
+        testl       %ebx,%ebx\r
+        jz          GoToSleep\r
+        call        *%ebx                         # Call C function\r
+\r
+#Step-6: Sleep\r
+\r
+GoToSleep:\r
+\r
+        cli\r
+        hlt\r
+        jmp         GoToSleep\r
+\r
+RendezvousFunnelProcEnd:\r
+#-------------------------------------------------------------------------------------\r
+#  AsmGetAddressMap (&AddressMap);\r
+#-------------------------------------------------------------------------------------\r
+ASM_GLOBAL ASM_PFX(AsmGetAddressMap)\r
+ASM_PFX(AsmGetAddressMap):\r
+\r
+        pushal\r
+        movl        %esp,%ebp\r
+\r
+        movl        0x24(%ebp), %ebx\r
+        movl        $RendezvousFunnelProcStart, (%ebx)\r
+        movl        $(ProtectedModeStart - RendezvousFunnelProcStart), 0x4(%ebx)\r
+        movl        $(FLAT32_JUMP - RendezvousFunnelProcStart), 0x8(%ebx)\r
+        movl        $0, 0x0c(%ebx)\r
+        movl        $0, 0x10(%ebx)\r
+        movl        $(RendezvousFunnelProcEnd - RendezvousFunnelProcStart), 0x14(%ebx)\r
+\r
+        popal\r
+        ret\r
diff --git a/EdkCompatibilityPkg/Compatibility/MpServicesOnFrameworkMpServicesThunk/IA32/MpFuncs.asm b/EdkCompatibilityPkg/Compatibility/MpServicesOnFrameworkMpServicesThunk/IA32/MpFuncs.asm
new file mode 100644 (file)
index 0000000..67ebc34
--- /dev/null
@@ -0,0 +1,148 @@
+;------------------------------------------------------------------------------\r
+; IA32 assembly file for AP startup vector.\r
+;\r
+; Copyright (c) 2009, Intel Corporation\r
+; All rights reserved. This program and the accompanying materials\r
+; are licensed and made available under the terms and conditions of the BSD License\r
+; which accompanies this distribution.  The full text of the license may be found at\r
+; http://opensource.org/licenses/bsd-license.php\r
+;\r
+; THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+; WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+;\r
+;------------------------------------------------------------------------------\r
+\r
+.686p\r
+.model  flat        \r
+.code        \r
+\r
+include AsmInclude.inc\r
+;-------------------------------------------------------------------------------------\r
+FJMP32  MACRO   Selector, Offset\r
+            DB      066h\r
+            DB      067h\r
+            DB      0EAh            ; far jump\r
+            DD      Offset          ; 32-bit offset\r
+            DW      Selector        ; 16-bit selector\r
+            ENDM\r
+\r
+;-------------------------------------------------------------------------------------\r
+;RendezvousFunnelProc  procedure follows. All APs execute their procedure. This\r
+;procedure serializes all the AP processors through an Init sequence. It must be\r
+;noted that APs arrive here very raw...ie: real mode, no stack.\r
+;ALSO THIS PROCEDURE IS EXECUTED BY APs ONLY ON 16 BIT MODE. HENCE THIS PROC\r
+;IS IN MACHINE CODE.\r
+;-------------------------------------------------------------------------------------\r
+;RendezvousFunnelProc (&WakeUpBuffer,MemAddress);\r
+\r
+RendezvousFunnelProc   PROC  near C  PUBLIC\r
+RendezvousFunnelProcStart::\r
+\r
+\r
+; At this point CS = 0x(vv00) and ip= 0x0.\r
+\r
+        db 8ch,  0c8h                 ; mov        ax,  cs\r
+        db 8eh,  0d8h                 ; mov        ds,  ax\r
+        db 8eh,  0c0h                 ; mov        es,  ax\r
+        db 8eh,  0d0h                 ; mov        ss,  ax \r
+        db 33h,  0c0h                 ; xor        ax,  ax\r
+        db 8eh,  0e0h                 ; mov        fs,  ax\r
+        db 8eh,  0e8h                 ; mov        gs,  ax\r
+\r
+; Switch to flat mode.\r
+\r
+        db 0BEh\r
+        dw BufferStart                ; mov        si, BufferStart\r
+        db 66h,  8Bh, 0Ch             ; mov        ecx,dword ptr [si]          ; ECX is keeping the start address of wakeup buffer\r
+\r
+        db 0FAh                       ; cli\r
+        db 0BEh\r
+        dw GdtrProfile                ; mov        si, GdtrProfile\r
+        db 66h                        ; db         66h\r
+        db 2Eh,0Fh, 01h, 14h          ; lgdt       fword ptr cs:[si]\r
+        \r
+        db 33h, 0C0h                  ; xor        ax,  ax\r
+        db 8Eh, 0D8h                  ; mov        ds,  ax\r
+        db 0Fh, 20h, 0C0h             ; mov        eax, cr0                    ; Get control register 0\r
+        db 66h, 83h, 0C8h, 01h        ; or         eax, 000000001h             ; Set PE bit (bit #0)\r
+        db 0Fh, 22h, 0C0h             ; mov        cr0, eax\r
+\r
+\r
+FLAT32_JUMP::\r
+        FJMP32  010h,0h               ; Far jmp using code segment descriptor\r
+\r
+ProtectedModeStart::                  ; protected mode entry point\r
+\r
+        mov         ax,  8h\r
+        mov         ds,  ax\r
+        mov         es,  ax\r
+        mov         fs,  ax\r
+        mov         gs,  ax\r
+        mov         ss,  ax           ; Flat mode setup.\r
+\r
+\r
+        mov         edi, esi\r
+        add         edi, LockLocation\r
+        mov         al,  NotVacantFlag\r
+TestLock::\r
+        xchg        byte ptr [edi], al\r
+        cmp         al,  NotVacantFlag\r
+        jz          TestLock\r
+\r
+ProgramStack::\r
+\r
+        mov         edi, esi\r
+        add         edi, StackSize\r
+        mov         eax, dword ptr [edi]\r
+        mov         edi, esi\r
+        add         edi, StackStart\r
+        add         eax, dword ptr [edi]\r
+        mov         esp, eax\r
+        mov         dword ptr [edi], eax\r
+\r
+Releaselock::\r
+        mov         al,  VacantFlag\r
+        mov         edi, esi\r
+        add         edi, LockLocation\r
+        xchg        byte ptr [edi], al\r
+\r
+        ;\r
+        ; Call C Function\r
+        ;\r
+        mov         edi, esi\r
+        add         edi, RendezvousProc\r
+        mov         ebx, dword ptr [edi]\r
+\r
+        test        ebx, ebx\r
+        jz          GoToSleep\r
+        call        ebx                           ; Call C function\r
+\r
+GoToSleep::\r
+\r
+        cli\r
+        hlt\r
+        jmp         $-2\r
+        \r
+RendezvousFunnelProc   ENDP\r
+RendezvousFunnelProcEnd::\r
+;-------------------------------------------------------------------------------------\r
+;  AsmGetAddressMap (&AddressMap);\r
+;-------------------------------------------------------------------------------------\r
+AsmGetAddressMap   PROC  near C  PUBLIC\r
+\r
+        pushad\r
+        mov         ebp,esp\r
+   \r
+        mov         ebx, dword ptr [ebp+24h]\r
+        mov         dword ptr [ebx], RendezvousFunnelProcStart\r
+        mov         dword ptr [ebx+4h], ProtectedModeStart - RendezvousFunnelProcStart\r
+        mov         dword ptr [ebx+8h], FLAT32_JUMP - RendezvousFunnelProcStart\r
+        mov         dword ptr [ebx+0ch], 0\r
+        mov         dword ptr [ebx+10h], 0\r
+        mov         dword ptr [ebx+14h], RendezvousFunnelProcEnd - RendezvousFunnelProcStart\r
+        \r
+        popad\r
+        ret\r
+AsmGetAddressMap   ENDP\r
+\r
+END\r
diff --git a/EdkCompatibilityPkg/Compatibility/MpServicesOnFrameworkMpServicesThunk/MpServicesOnFrameworkMpServicesThunk.c b/EdkCompatibilityPkg/Compatibility/MpServicesOnFrameworkMpServicesThunk/MpServicesOnFrameworkMpServicesThunk.c
new file mode 100644 (file)
index 0000000..fcb3373
--- /dev/null
@@ -0,0 +1,1616 @@
+/** @file\r
+Produces PI MP Services Protocol on top of Framework MP Services Protocol.\r
+\r
+Intel's Framework MP Services Protocol is replaced by EFI_MP_SERVICES_PROTOCOL in PI 1.1.\r
+This module produces PI MP Services Protocol on top of Framework MP Services Protocol.\r
+\r
+Copyright (c) 2009 Intel Corporation. <BR>\r
+All rights reserved. This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution.  The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+Module Name:\r
+\r
+**/\r
+\r
+#include "MpServicesOnFrameworkMpServicesThunk.h"\r
+\r
+EFI_HANDLE                          mHandle = NULL;\r
+MP_SYSTEM_DATA                      mMPSystemData;\r
+EFI_PHYSICAL_ADDRESS                mStartupVector;\r
+MP_CPU_EXCHANGE_INFO                *mExchangeInfo;\r
+VOID                                *mStackStartAddress;\r
+BOOLEAN                             mStopCheckAPsStatus = FALSE;\r
+UINTN                               mNumberOfProcessors;\r
+EFI_GENERIC_MEMORY_TEST_PROTOCOL    *mGenMemoryTest;\r
+\r
+FRAMEWORK_EFI_MP_SERVICES_PROTOCOL  *mFrameworkMpService;\r
+EFI_MP_SERVICES_PROTOCOL            mMpService = {\r
+  GetNumberOfProcessors,\r
+  GetProcessorInfo,\r
+  StartupAllAPs,\r
+  StartupThisAP,\r
+  SwitchBSP,\r
+  EnableDisableAP,\r
+  WhoAmI\r
+};\r
+\r
+\r
+/**\r
+  Implementation of GetNumberOfProcessors() service of MP Services Protocol.\r
+\r
+  This service retrieves the number of logical processor in the platform\r
+  and the number of those logical processors that are enabled on this boot.\r
+  This service may only be called from the BSP.\r
+\r
+  @param  This                       A pointer to the EFI_MP_SERVICES_PROTOCOL instance.\r
+  @param  NumberOfProcessors         Pointer to the total number of logical processors in the system,\r
+                                     including the BSP and disabled APs.\r
+  @param  NumberOfEnabledProcessors  Pointer to the number of enabled logical processors that exist\r
+                                     in system, including the BSP.\r
+\r
+  @retval EFI_SUCCESS               Number of logical processors and enabled logical processors retrieved..\r
+  @retval EFI_DEVICE_ERROR           Caller processor is AP.\r
+  @retval EFI_INVALID_PARAMETER      NumberOfProcessors is NULL\r
+  @retval EFI_INVALID_PARAMETER      NumberOfEnabledProcessors is NULL\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+GetNumberOfProcessors (\r
+  IN  EFI_MP_SERVICES_PROTOCOL     *This,\r
+  OUT UINTN                        *NumberOfProcessors,\r
+  OUT UINTN                        *NumberOfEnabledProcessors\r
+  )\r
+{\r
+  EFI_STATUS      Status;\r
+  UINTN           CallerNumber;\r
+\r
+  //\r
+  // Check whether caller processor is BSP\r
+  //\r
+  WhoAmI (This, &CallerNumber);\r
+  if (CallerNumber != GetBspNumber ()) {\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
+\r
+  //\r
+  // Check parameter NumberOfProcessors\r
+  //\r
+  if (NumberOfProcessors == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  //\r
+  // Check parameter NumberOfEnabledProcessors\r
+  //\r
+  if (NumberOfEnabledProcessors == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  Status = mFrameworkMpService->GetGeneralMPInfo (\r
+                                  mFrameworkMpService,\r
+                                  NumberOfProcessors,\r
+                                  NULL,\r
+                                  NumberOfEnabledProcessors,\r
+                                  NULL,\r
+                                  NULL\r
+                                  );\r
+  ASSERT_EFI_ERROR (Status);\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Implementation of GetNumberOfProcessors() service of MP Services Protocol.\r
+\r
+  Gets detailed MP-related information on the requested processor at the\r
+  instant this call is made. This service may only be called from the BSP.\r
+\r
+  @param  This                  A pointer to the EFI_MP_SERVICES_PROTOCOL instance.\r
+  @param  ProcessorNumber       The handle number of processor.\r
+  @param  ProcessorInfoBuffer   A pointer to the buffer where information for the requested processor is deposited.\r
+\r
+  @retval EFI_SUCCESS           Processor information successfully returned.\r
+  @retval EFI_DEVICE_ERROR      Caller processor is AP.\r
+  @retval EFI_INVALID_PARAMETER ProcessorInfoBuffer is NULL\r
+  @retval EFI_NOT_FOUND         Processor with the handle specified by ProcessorNumber does not exist. \r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+GetProcessorInfo (\r
+  IN       EFI_MP_SERVICES_PROTOCOL     *This,\r
+  IN       UINTN                        ProcessorNumber,\r
+  OUT      EFI_PROCESSOR_INFORMATION    *ProcessorInfoBuffer\r
+  )\r
+{\r
+  EFI_STATUS                 Status;\r
+  UINTN                      CallerNumber;\r
+  UINTN                      BufferSize;\r
+  EFI_MP_PROC_CONTEXT        ProcessorContextBuffer;\r
+\r
+  //\r
+  // Check whether caller processor is BSP\r
+  //\r
+  WhoAmI (This, &CallerNumber);\r
+  if (CallerNumber != GetBspNumber ()) {\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
+\r
+  //\r
+  // Check parameter ProcessorInfoBuffer\r
+  //\r
+  if (ProcessorInfoBuffer == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  //\r
+  // Check whether processor with the handle specified by ProcessorNumber exists\r
+  //\r
+  if (ProcessorNumber >= mNumberOfProcessors) {\r
+    return EFI_NOT_FOUND;\r
+  }\r
+\r
+  BufferSize = sizeof (EFI_MP_PROC_CONTEXT);\r
+  Status = mFrameworkMpService->GetProcessorContext (\r
+                                  mFrameworkMpService,\r
+                                  ProcessorNumber,\r
+                                  &BufferSize,\r
+                                  &ProcessorContextBuffer\r
+                                  );\r
+  ASSERT_EFI_ERROR (Status);\r
+\r
+  ProcessorInfoBuffer->ProcessorId = (UINT64) ProcessorContextBuffer.ApicID;\r
+  \r
+  //\r
+  // Get Status Flag of specified processor\r
+  //\r
+  ProcessorInfoBuffer->StatusFlag = 0;\r
+\r
+  if (ProcessorContextBuffer.Enabled) {\r
+    ProcessorInfoBuffer->StatusFlag |= PROCESSOR_ENABLED_BIT;\r
+  }\r
+\r
+  if (ProcessorContextBuffer.Designation == EfiCpuBSP) {\r
+    ProcessorInfoBuffer->StatusFlag |= PROCESSOR_AS_BSP_BIT;\r
+  }\r
+\r
+  if (ProcessorContextBuffer.Health.Flags.Uint32 == 0) {\r
+    ProcessorInfoBuffer->StatusFlag |= PROCESSOR_HEALTH_STATUS_BIT;\r
+  }\r
+\r
+  ProcessorInfoBuffer->Location.Package = (UINT32) ProcessorContextBuffer.PackageNumber;\r
+  ProcessorInfoBuffer->Location.Core    = (UINT32) ProcessorContextBuffer.NumberOfCores;\r
+  ProcessorInfoBuffer->Location.Thread  = (UINT32) ProcessorContextBuffer.NumberOfThreads;\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Implementation of StartupAllAPs() service of MP Services Protocol.\r
+\r
+  This service lets the caller get all enabled APs to execute a caller-provided function.\r
+  This service may only be called from the BSP.\r
+\r
+  @param  This                  A pointer to the EFI_MP_SERVICES_PROTOCOL instance.\r
+  @param  Procedure             A pointer to the function to be run on enabled APs of the system.\r
+  @param  SingleThread          Indicates whether to execute the function simultaneously or one by one..\r
+  @param  WaitEvent             The event created by the caller.\r
+                                If it is NULL, then execute in blocking mode.\r
+                                If it is not NULL, then execute in non-blocking mode.\r
+  @param  TimeoutInMicroSeconds The time limit in microseconds for this AP to finish the function.\r
+                                Zero means infinity.\r
+  @param  ProcedureArgument     Pointer to the optional parameter of the assigned function.\r
+  @param  FailedCpuList         The list of processor numbers that fail to finish the function before\r
+                                TimeoutInMicrosecsond expires.\r
+\r
+  @retval EFI_SUCCESS           In blocking mode, all APs have finished before the timeout expired. \r
+  @retval EFI_SUCCESS           In non-blocking mode, function has been dispatched to all enabled APs.\r
+  @retval EFI_DEVICE_ERROR      Caller processor is AP.\r
+  @retval EFI_NOT_STARTED       No enabled AP exists in the system.\r
+  @retval EFI_NOT_READY         Any enabled AP is busy.\r
+  @retval EFI_TIMEOUT           In blocking mode, The timeout expired before all enabled APs have finished.\r
+  @retval EFI_INVALID_PARAMETER Procedure is NULL.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+StartupAllAPs (\r
+  IN  EFI_MP_SERVICES_PROTOCOL   *This,\r
+  IN  EFI_AP_PROCEDURE           Procedure,\r
+  IN  BOOLEAN                    SingleThread,\r
+  IN  EFI_EVENT                  WaitEvent             OPTIONAL,\r
+  IN  UINTN                      TimeoutInMicroSeconds,\r
+  IN  VOID                       *ProcedureArgument    OPTIONAL,\r
+  OUT UINTN                      **FailedCpuList       OPTIONAL\r
+  )\r
+{\r
+  EFI_STATUS      Status;\r
+  UINTN           ProcessorNumber;\r
+  CPU_DATA_BLOCK  *CpuData;\r
+  BOOLEAN         Blocking;\r
+  UINTN           BspNumber;\r
+\r
+  if (FailedCpuList != NULL) {\r
+    *FailedCpuList = NULL;\r
+  }\r
+\r
+  //\r
+  // Check whether caller processor is BSP\r
+  //\r
+  BspNumber = GetBspNumber ();\r
+  WhoAmI (This, &ProcessorNumber);\r
+  if (ProcessorNumber != BspNumber) {\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
+\r
+  //\r
+  // Check parameter Procedure\r
+  //\r
+  if (Procedure == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  //\r
+  // Temporarily suppress CheckAPsStatus()\r
+  //\r
+  mStopCheckAPsStatus = TRUE;\r
+\r
+  //\r
+  // Check whether all enabled APs are idle.\r
+  // If any enabled AP is not idle, return EFI_NOT_READY.\r
+  //\r
+  for (ProcessorNumber = 0; ProcessorNumber < mNumberOfProcessors; ProcessorNumber++) {\r
+\r
+    CpuData = &mMPSystemData.CpuData[ProcessorNumber];\r
+\r
+    mMPSystemData.CpuList[ProcessorNumber] = FALSE;\r
+    if (ProcessorNumber != BspNumber) {\r
+      if (CpuData->State != CpuStateDisabled) {\r
+        if (CpuData->State != CpuStateIdle) {\r
+          mStopCheckAPsStatus = FALSE;\r
+          return EFI_NOT_READY;\r
+        } else {\r
+          //     \r
+          // Mark this processor as responsible for current calling.\r
+          //\r
+          mMPSystemData.CpuList[ProcessorNumber] = TRUE;\r
+        }\r
+      }\r
+    }\r
+  }\r
+\r
+  mMPSystemData.FinishCount = 0;\r
+  mMPSystemData.StartCount  = 0;\r
+  Blocking                  = FALSE;\r
+  //\r
+  // Go through all enabled APs to wakeup them for Procedure.\r
+  // If in Single Thread mode, then only one AP is woken up, and others are waiting.\r
+  //\r
+  for (ProcessorNumber = 0; ProcessorNumber < mNumberOfProcessors; ProcessorNumber++) {\r
+\r
+    CpuData = &mMPSystemData.CpuData[ProcessorNumber];\r
+    //\r
+    // Check whether this processor is responsible for current calling.\r
+    //\r
+    if (mMPSystemData.CpuList[ProcessorNumber]) {\r
+\r
+      mMPSystemData.StartCount++;\r
+\r
+      AcquireSpinLock (&CpuData->CpuDataLock);\r
+      CpuData->State = CpuStateReady;\r
+      ReleaseSpinLock (&CpuData->CpuDataLock);\r
+\r
+      if (!Blocking) {\r
+        WakeUpAp (\r
+          ProcessorNumber,\r
+          Procedure,\r
+          ProcedureArgument\r
+          );\r
+      }\r
+\r
+      if (SingleThread) {\r
+        Blocking = TRUE;\r
+      }\r
+    }\r
+  }\r
+  \r
+  //\r
+  // If no enabled AP exists, return EFI_NOT_STARTED.\r
+  //\r
+  if (mMPSystemData.StartCount == 0) {\r
+    mStopCheckAPsStatus = FALSE;\r
+    return EFI_NOT_STARTED;\r
+  }\r
+\r
+  //\r
+  // If WaitEvent is not NULL, execute in non-blocking mode.\r
+  // BSP saves data for CheckAPsStatus(), and returns EFI_SUCCESS.\r
+  // CheckAPsStatus() will check completion and timeout periodically.\r
+  //\r
+  mMPSystemData.Procedure      = Procedure;\r
+  mMPSystemData.ProcArguments  = ProcedureArgument;\r
+  mMPSystemData.SingleThread   = SingleThread;\r
+  mMPSystemData.FailedCpuList  = FailedCpuList;\r
+  mMPSystemData.ExpectedTime   = CalculateTimeout (TimeoutInMicroSeconds, &mMPSystemData.CurrentTime);\r
+  mMPSystemData.WaitEvent      = WaitEvent;\r
+\r
+  //\r
+  // Allow CheckAPsStatus()\r
+  //\r
+  mStopCheckAPsStatus = FALSE;\r
+\r
+  if (WaitEvent != NULL) {\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
+  //\r
+  // If WaitEvent is NULL, execute in blocking mode.\r
+  // BSP checks APs'state until all APs finish or TimeoutInMicrosecsond expires.\r
+  //\r
+  do {\r
+    Status = CheckAllAPs ();\r
+  } while (Status == EFI_NOT_READY);\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Implementation of StartupThisAP() service of MP Services Protocol.\r
+\r
+  This service lets the caller get one enabled AP to execute a caller-provided function.\r
+  This service may only be called from the BSP.\r
+\r
+  @param  This                  A pointer to the EFI_MP_SERVICES_PROTOCOL instance.\r
+  @param  Procedure             A pointer to the function to be run on the designated AP.\r
+  @param  ProcessorNumber       The handle number of AP..\r
+  @param  WaitEvent             The event created by the caller.\r
+                                If it is NULL, then execute in blocking mode.\r
+                                If it is not NULL, then execute in non-blocking mode.\r
+  @param  TimeoutInMicroseconds The time limit in microseconds for this AP to finish the function.\r
+                                Zero means infinity.\r
+  @param  ProcedureArgument     Pointer to the optional parameter of the assigned function.\r
+  @param  Finished              Indicates whether AP has finished assigned function.\r
+                                In blocking mode, it is ignored.\r
+\r
+  @retval EFI_SUCCESS           In blocking mode, specified AP has finished before the timeout expires.\r
+  @retval EFI_SUCCESS           In non-blocking mode, function has been dispatched to specified AP.\r
+  @retval EFI_DEVICE_ERROR      Caller processor is AP.\r
+  @retval EFI_TIMEOUT           In blocking mode, the timeout expires before specified AP has finished.\r
+  @retval EFI_NOT_READY         Specified AP is busy.\r
+  @retval EFI_NOT_FOUND         Processor with the handle specified by ProcessorNumber does not exist.\r
+  @retval EFI_INVALID_PARAMETER ProcessorNumber specifies the BSP or disabled AP.\r
+  @retval EFI_INVALID_PARAMETER Procedure is NULL.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+StartupThisAP (\r
+  IN  EFI_MP_SERVICES_PROTOCOL   *This,\r
+  IN  EFI_AP_PROCEDURE           Procedure,\r
+  IN  UINTN                      ProcessorNumber,\r
+  IN  EFI_EVENT                  WaitEvent OPTIONAL,\r
+  IN  UINTN                      TimeoutInMicroseconds,\r
+  IN  VOID                       *ProcedureArgument OPTIONAL,\r
+  OUT BOOLEAN                    *Finished OPTIONAL\r
+  )\r
+{\r
+  CPU_DATA_BLOCK  *CpuData;\r
+  UINTN           CallerNumber;\r
+  EFI_STATUS      Status;\r
+  UINTN           BspNumber;\r
+\r
+  if (Finished != NULL) {\r
+    *Finished = TRUE;\r
+  }\r
+\r
+  //\r
+  // Check whether caller processor is BSP\r
+  //\r
+  BspNumber = GetBspNumber ();\r
+  WhoAmI (This, &CallerNumber);\r
+  if (CallerNumber != BspNumber) {\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
+\r
+  //\r
+  // Check whether processor with the handle specified by ProcessorNumber exists\r
+  //\r
+  if (ProcessorNumber >= mNumberOfProcessors) {\r
+    return EFI_NOT_FOUND;\r
+  }\r
+\r
+  //\r
+  // Check whether specified processor is BSP\r
+  //\r
+  if (ProcessorNumber == BspNumber) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  //\r
+  // Check parameter Procedure\r
+  //\r
+  if (Procedure == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  CpuData = &mMPSystemData.CpuData[ProcessorNumber];\r
+\r
+  //\r
+  // Temporarily suppress CheckAPsStatus()\r
+  //\r
+  mStopCheckAPsStatus = TRUE;\r
+\r
+  //\r
+  // Check whether specified AP is disabled\r
+  //\r
+  if (CpuData->State == CpuStateDisabled) {\r
+    mStopCheckAPsStatus = FALSE;\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  //\r
+  // Check whether specified AP is busy\r
+  //\r
+  if (CpuData->State != CpuStateIdle) {\r
+    mStopCheckAPsStatus = FALSE;\r
+    return EFI_NOT_READY;\r
+  }\r
+\r
+  //\r
+  // Wakeup specified AP for Procedure.\r
+  //\r
+  AcquireSpinLock (&CpuData->CpuDataLock);\r
+  CpuData->State = CpuStateReady;\r
+  ReleaseSpinLock (&CpuData->CpuDataLock);\r
+\r
+  WakeUpAp (\r
+    ProcessorNumber,\r
+    Procedure,\r
+    ProcedureArgument\r
+    );\r
+\r
+  //\r
+  // If WaitEvent is not NULL, execute in non-blocking mode.\r
+  // BSP saves data for CheckAPsStatus(), and returns EFI_SUCCESS.\r
+  // CheckAPsStatus() will check completion and timeout periodically.\r
+  //\r
+  CpuData->WaitEvent      = WaitEvent;\r
+  CpuData->Finished       = Finished;\r
+  CpuData->ExpectedTime   = CalculateTimeout (TimeoutInMicroseconds, &CpuData->CurrentTime);\r
+\r
+  //\r
+  // Allow CheckAPsStatus()\r
+  //\r
+  mStopCheckAPsStatus = FALSE;\r
+\r
+  if (WaitEvent != NULL) {\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
+  //\r
+  // If WaitEvent is NULL, execute in blocking mode.\r
+  // BSP checks AP's state until it finishes or TimeoutInMicrosecsond expires.\r
+  //\r
+  do {\r
+    Status = CheckThisAP (ProcessorNumber);\r
+  } while (Status == EFI_NOT_READY);\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Implementation of SwitchBSP() service of MP Services Protocol.\r
+\r
+  This service switches the requested AP to be the BSP from that point onward.\r
+  This service may only be called from the current BSP.\r
+\r
+  @param  This                  A pointer to the EFI_MP_SERVICES_PROTOCOL instance.\r
+  @param  ProcessorNumber       The handle number of processor.\r
+  @param  EnableOldBSP          Whether to enable or disable the original BSP.\r
+\r
+  @retval EFI_SUCCESS           BSP successfully switched.\r
+  @retval EFI_DEVICE_ERROR      Caller processor is AP.\r
+  @retval EFI_NOT_FOUND         Processor with the handle specified by ProcessorNumber does not exist.\r
+  @retval EFI_INVALID_PARAMETER ProcessorNumber specifies the BSP or disabled AP.\r
+  @retval EFI_NOT_READY         Specified AP is busy.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SwitchBSP (\r
+  IN  EFI_MP_SERVICES_PROTOCOL            *This,\r
+  IN  UINTN                               ProcessorNumber,\r
+  IN  BOOLEAN                             EnableOldBSP\r
+  )\r
+{\r
+  EFI_STATUS            Status;\r
+  CPU_DATA_BLOCK        *CpuData;\r
+  UINTN                 CallerNumber;\r
+  UINTN                 BspNumber;\r
+\r
+  //\r
+  // Check whether caller processor is BSP\r
+  //\r
+  BspNumber = GetBspNumber ();\r
+  WhoAmI (This, &CallerNumber);\r
+  if (CallerNumber != BspNumber) {\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
+\r
+  //\r
+  // Check whether processor with the handle specified by ProcessorNumber exists\r
+  //\r
+  if (ProcessorNumber >= mNumberOfProcessors) {\r
+    return EFI_NOT_FOUND;\r
+  }\r
+\r
+  //\r
+  // Check whether specified processor is BSP\r
+  //\r
+  if (ProcessorNumber == BspNumber) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  CpuData = &mMPSystemData.CpuData[ProcessorNumber];\r
+\r
+  //\r
+  // Check whether specified AP is disabled\r
+  //\r
+  if (CpuData->State == CpuStateDisabled) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  //\r
+  // Check whether specified AP is busy\r
+  //\r
+  if (CpuData->State != CpuStateIdle) {\r
+    return EFI_NOT_READY;\r
+  }\r
+\r
+  Status = mFrameworkMpService->SwitchBSP (\r
+                                  mFrameworkMpService,\r
+                                  ProcessorNumber,\r
+                                  EnableOldBSP\r
+                                  );\r
+  ASSERT_EFI_ERROR (Status);\r
+\r
+  ChangeCpuState (BspNumber, EnableOldBSP);\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Implementation of EnableDisableAP() service of MP Services Protocol.\r
+\r
+  This service lets the caller enable or disable an AP.\r
+  This service may only be called from the BSP.\r
+\r
+  @param  This                   A pointer to the EFI_MP_SERVICES_PROTOCOL instance.\r
+  @param  ProcessorNumber        The handle number of processor.\r
+  @param  EnableAP               Indicates whether the newstate of the AP is enabled or disabled.\r
+  @param  HealthFlag             Indicates new health state of the AP..\r
+\r
+  @retval EFI_SUCCESS            AP successfully enabled or disabled.\r
+  @retval EFI_DEVICE_ERROR       Caller processor is AP.\r
+  @retval EFI_NOT_FOUND          Processor with the handle specified by ProcessorNumber does not exist.\r
+  @retval EFI_INVALID_PARAMETERS ProcessorNumber specifies the BSP.\r
+  \r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+EnableDisableAP (\r
+  IN  EFI_MP_SERVICES_PROTOCOL            *This,\r
+  IN  UINTN                               ProcessorNumber,\r
+  IN  BOOLEAN                             EnableAP,\r
+  IN  UINT32                              *HealthFlag OPTIONAL\r
+  )\r
+{\r
+  EFI_STATUS      Status;\r
+  UINTN           CallerNumber;\r
+  EFI_MP_HEALTH   HealthState;\r
+  EFI_MP_HEALTH   *HealthStatePointer;\r
+  UINTN           BspNumber;\r
+\r
+  //\r
+  // Check whether caller processor is BSP\r
+  //\r
+  BspNumber = GetBspNumber ();\r
+  WhoAmI (This, &CallerNumber);\r
+  if (CallerNumber != BspNumber) {\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
+\r
+  //\r
+  // Check whether processor with the handle specified by ProcessorNumber exists\r
+  //\r
+  if (ProcessorNumber >= mNumberOfProcessors) {\r
+    return EFI_NOT_FOUND;\r
+  }\r
+\r
+  //\r
+  // Check whether specified processor is BSP\r
+  //\r
+  if (ProcessorNumber == BspNumber) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  if (HealthFlag == NULL) {\r
+    HealthStatePointer = NULL;\r
+  } else {\r
+    if ((*HealthFlag & PROCESSOR_HEALTH_STATUS_BIT) == 0) {\r
+      HealthState.Flags.Uint32 = 1;\r
+    } else {\r
+      HealthState.Flags.Uint32 = 0;\r
+    }\r
+    HealthState.TestStatus = 0;\r
+\r
+    HealthStatePointer = &HealthState;\r
+  }\r
+\r
+  Status = mFrameworkMpService->EnableDisableAP (\r
+                                  mFrameworkMpService,\r
+                                  ProcessorNumber,\r
+                                  EnableAP,\r
+                                  HealthStatePointer\r
+                                  );\r
+  ASSERT_EFI_ERROR (Status);\r
+\r
+  ChangeCpuState (ProcessorNumber, EnableAP);\r
+  \r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Implementation of WhoAmI() service of MP Services Protocol.\r
+\r
+  This service lets the caller processor get its handle number.\r
+  This service may be called from the BSP and APs.\r
+\r
+  @param  This                  A pointer to the EFI_MP_SERVICES_PROTOCOL instance.\r
+  @param  ProcessorNumber       Pointer to the handle number of AP.\r
+\r
+  @retval EFI_SUCCESS           Processor number successfully returned.\r
+  @retval EFI_INVALID_PARAMETER ProcessorNumber is NULL\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+WhoAmI (\r
+  IN  EFI_MP_SERVICES_PROTOCOL            *This,\r
+  OUT UINTN                               *ProcessorNumber\r
+  )\r
+{\r
+  EFI_STATUS  Status;\r
+\r
+  if (ProcessorNumber == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  Status = mFrameworkMpService->WhoAmI (\r
+                                  mFrameworkMpService,\r
+                                  ProcessorNumber\r
+                                  );\r
+  ASSERT_EFI_ERROR (Status);\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Checks APs' status periodically.\r
+\r
+  This function is triggerred by timer perodically to check the\r
+  state of APs for StartupAllAPs() and StartupThisAP() executed\r
+  in non-blocking mode.\r
+\r
+  @param  Event    Event triggered.\r
+  @param  Context  Parameter passed with the event.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+CheckAPsStatus (\r
+  IN  EFI_EVENT                           Event,\r
+  IN  VOID                                *Context\r
+  )\r
+{\r
+  UINTN           ProcessorNumber;\r
+  CPU_DATA_BLOCK  *CpuData;\r
+  EFI_STATUS      Status;\r
+  \r
+  //\r
+  // If CheckAPsStatus() is stopped, then return immediately.\r
+  //\r
+  if (mStopCheckAPsStatus) {\r
+    return;\r
+  }\r
+\r
+  //\r
+  // First, check whether pending StartupAllAPs() exists.\r
+  //\r
+  if (mMPSystemData.WaitEvent != NULL) {\r
+\r
+    Status = CheckAllAPs ();\r
+    //\r
+    // If all APs finish for StartupAllAPs(), signal the WaitEvent for it..\r
+    //\r
+    if (Status != EFI_NOT_READY) {\r
+      Status = gBS->SignalEvent (mMPSystemData.WaitEvent);\r
+      mMPSystemData.WaitEvent = NULL;\r
+    }\r
+  }\r
+\r
+  //\r
+  // Second, check whether pending StartupThisAPs() callings exist.\r
+  //\r
+  for (ProcessorNumber = 0; ProcessorNumber < mNumberOfProcessors; ProcessorNumber++) {\r
+\r
+    CpuData = &mMPSystemData.CpuData[ProcessorNumber];\r
+\r
+    if (CpuData->WaitEvent == NULL) {\r
+      continue;\r
+    }\r
+\r
+    Status = CheckThisAP (ProcessorNumber);\r
+\r
+    if (Status != EFI_NOT_READY) {\r
+      gBS->SignalEvent (CpuData->WaitEvent);\r
+      CpuData->WaitEvent = NULL;\r
+    }\r
+  }\r
+  return ;\r
+}\r
+\r
+/**\r
+  Checks status of all APs.\r
+\r
+  This function checks whether all APs have finished task assigned by StartupAllAPs(),\r
+  and whether timeout expires.\r
+\r
+  @retval EFI_SUCCESS           All APs have finished task assigned by StartupAllAPs().\r
+  @retval EFI_TIMEOUT           The timeout expires.\r
+  @retval EFI_NOT_READY         APs have not finished task and timeout has not expired.\r
+\r
+**/\r
+EFI_STATUS\r
+CheckAllAPs (\r
+  VOID\r
+  )\r
+{\r
+  UINTN           ProcessorNumber;\r
+  UINTN           NextProcessorNumber;\r
+  UINTN           ListIndex;\r
+  EFI_STATUS      Status;\r
+  CPU_STATE       CpuState;\r
+  CPU_DATA_BLOCK  *CpuData;\r
+\r
+  NextProcessorNumber = 0;\r
+\r
+  //\r
+  // Go through all APs that are responsible for the StartupAllAPs().\r
+  //\r
+  for (ProcessorNumber = 0; ProcessorNumber < mNumberOfProcessors; ProcessorNumber++) {\r
+    if (!mMPSystemData.CpuList[ProcessorNumber]) {\r
+      continue;\r
+    }\r
+\r
+    CpuData = &mMPSystemData.CpuData[ProcessorNumber];\r
+\r
+    //\r
+    //  Check the CPU state of AP. If it is CpuStateFinished, then the AP has finished its task.\r
+    //  Only BSP and corresponding AP access this unit of CPU Data. This means the AP will not modify the\r
+    //  value of state after setting the it to CpuStateFinished, so BSP can safely make use of its value.\r
+    //\r
+    AcquireSpinLock (&CpuData->CpuDataLock);\r
+    CpuState = CpuData->State;\r
+    ReleaseSpinLock (&CpuData->CpuDataLock);\r
+\r
+    if (CpuState == CpuStateFinished) {\r
+      mMPSystemData.FinishCount++;\r
+      mMPSystemData.CpuList[ProcessorNumber] = FALSE;\r
+\r
+      AcquireSpinLock (&CpuData->CpuDataLock);\r
+      CpuData->State = CpuStateIdle;\r
+      ReleaseSpinLock (&CpuData->CpuDataLock);\r
+\r
+      //\r
+      // If in Single Thread mode, then search for the next waiting AP for execution.\r
+      //\r
+      if (mMPSystemData.SingleThread) {\r
+        Status = GetNextWaitingProcessorNumber (&NextProcessorNumber);\r
+\r
+        if (!EFI_ERROR (Status)) {\r
+          WakeUpAp (\r
+            NextProcessorNumber,\r
+            mMPSystemData.Procedure,\r
+            mMPSystemData.ProcArguments\r
+            );\r
+        }\r
+      }\r
+    }\r
+  }\r
+\r
+  //\r
+  // If all APs finish, return EFI_SUCCESS.\r
+  //\r
+  if (mMPSystemData.FinishCount == mMPSystemData.StartCount) {\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
+  //\r
+  // If timeout expires, report timeout.\r
+  //\r
+  if (CheckTimeout (&mMPSystemData.CurrentTime, &mMPSystemData.TotalTime, mMPSystemData.ExpectedTime)) {\r
+    //\r
+    // If FailedCpuList is not NULL, record all failed APs in it.\r
+    //\r
+    if (mMPSystemData.FailedCpuList != NULL) {\r
+      *mMPSystemData.FailedCpuList = AllocatePool ((mMPSystemData.StartCount - mMPSystemData.FinishCount + 1) * sizeof(UINTN));\r
+      ASSERT (*mMPSystemData.FailedCpuList != NULL);\r
+    }\r
+    ListIndex = 0;\r
\r
+    for (ProcessorNumber = 0; ProcessorNumber < mNumberOfProcessors; ProcessorNumber++) {\r
+      //\r
+      // Check whether this processor is responsible for StartupAllAPs().\r
+      //\r
+      if (mMPSystemData.CpuList[ProcessorNumber]) {\r
+        //\r
+        // Reset failed APs to idle state\r
+        //\r
+        ResetProcessorToIdleState (ProcessorNumber);\r
+        mMPSystemData.CpuList[ProcessorNumber] = FALSE;\r
+        if (mMPSystemData.FailedCpuList != NULL) {\r
+          (*mMPSystemData.FailedCpuList)[ListIndex++] = ProcessorNumber;\r
+        }\r
+      }\r
+    }\r
+    if (mMPSystemData.FailedCpuList != NULL) {\r
+      (*mMPSystemData.FailedCpuList)[ListIndex] = END_OF_CPU_LIST;\r
+    }\r
+    return EFI_TIMEOUT;\r
+  }\r
+  return EFI_NOT_READY;\r
+}\r
+\r
+/**\r
+  Checks status of specified AP.\r
+\r
+  This function checks whether specified AP has finished task assigned by StartupThisAP(),\r
+  and whether timeout expires.\r
+\r
+  @param  ProcessorNumber       The handle number of processor.\r
+\r
+  @retval EFI_SUCCESS           Specified AP has finished task assigned by StartupThisAPs().\r
+  @retval EFI_TIMEOUT           The timeout expires.\r
+  @retval EFI_NOT_READY         Specified AP has not finished task and timeout has not expired.\r
+\r
+**/\r
+EFI_STATUS\r
+CheckThisAP (\r
+  UINTN  ProcessorNumber\r
+  )\r
+{\r
+  CPU_DATA_BLOCK  *CpuData;\r
+  CPU_STATE       CpuState;\r
+\r
+  CpuData = &mMPSystemData.CpuData[ProcessorNumber];\r
+\r
+  //\r
+  //  Check the CPU state of AP. If it is CpuStateFinished, then the AP has finished its task.\r
+  //  Only BSP and corresponding AP access this unit of CPU Data. This means the AP will not modify the\r
+  //  value of state after setting the it to CpuStateFinished, so BSP can safely make use of its value.\r
+  //\r
+  AcquireSpinLock (&CpuData->CpuDataLock);\r
+  CpuState = CpuData->State;\r
+  ReleaseSpinLock (&CpuData->CpuDataLock);\r
+\r
+  //\r
+  // If the APs finishes for StartupThisAP(), return EFI_SUCCESS.\r
+  //\r
+  if (CpuState == CpuStateFinished) {\r
+\r
+    AcquireSpinLock (&CpuData->CpuDataLock);\r
+    CpuData->State = CpuStateIdle;\r
+    ReleaseSpinLock (&CpuData->CpuDataLock);\r
+    \r
+    if (CpuData->Finished != NULL) {\r
+      *(CpuData->Finished) = TRUE;\r
+    }\r
+    return EFI_SUCCESS;\r
+  } else {\r
+    //\r
+    // If timeout expires for StartupThisAP(), report timeout.\r
+    //\r
+    if (CheckTimeout (&CpuData->CurrentTime, &CpuData->TotalTime, CpuData->ExpectedTime)) {\r
+\r
+      if (CpuData->Finished != NULL) {\r
+        *(CpuData->Finished) = FALSE;\r
+      }\r
+      //\r
+      // Reset failed AP to idle state\r
+      //\r
+      ResetProcessorToIdleState (ProcessorNumber);\r
+\r
+      return EFI_TIMEOUT;\r
+    }\r
+  }\r
+  return EFI_NOT_READY;\r
+}\r
+\r
+/**\r
+  Calculate timeout value and return the current performance counter value.\r
+\r
+  Calculate the number of performance counter ticks required for a timeout.\r
+  If TimeoutInMicroseconds is 0, return value is also 0, which is recognized\r
+  as infinity.\r
+\r
+  @param  TimeoutInMicroseconds   Timeout value in microseconds.\r
+  @param  CurrentTime             Returns the current value of the performance counter.\r
+\r
+  @return Expected timestamp counter for timeout.\r
+          If TimeoutInMicroseconds is 0, return value is also 0, which is recognized\r
+          as infinity.\r
+\r
+**/\r
+UINT64\r
+CalculateTimeout (\r
+  IN  UINTN   TimeoutInMicroseconds,\r
+  OUT UINT64  *CurrentTime\r
+  )\r
+{\r
+  //\r
+  // Read the current value of the performance counter\r
+  //\r
+  *CurrentTime = GetPerformanceCounter ();\r
+\r
+  //\r
+  // If TimeoutInMicroseconds is 0, return value is also 0, which is recognized\r
+  // as infinity.\r
+  //\r
+  if (TimeoutInMicroseconds == 0) {\r
+    return 0;\r
+  }\r
+\r
+  //\r
+  // GetPerformanceCounterProperties () returns the timestamp counter's frequency\r
+  // in Hz. So multiply the return value with TimeoutInMicroseconds and then divide\r
+  // it by 1,000,000, to get the number of ticks for the timeout value.\r
+  //\r
+  return DivU64x32 (\r
+           MultU64x64 (\r
+             GetPerformanceCounterProperties (NULL, NULL),\r
+             TimeoutInMicroseconds\r
+             ),\r
+           1000000\r
+           );\r
+}\r
+\r
+/**\r
+  Checks whether timeout expires.\r
+\r
+  Check whether the number of ellapsed performance counter ticks required for a timeout condition\r
+  has been reached.  If Timeout is zero, which means infinity, return value is always FALSE.\r
+\r
+  @param  PreviousTime         On input, the value of the performance counter when it was last read.\r
+                               On output, the current value of the performance counter\r
+  @param  TotalTime            The total amount of ellapsed time in performance counter ticks.\r
+  @param  Timeout              The number of performance counter ticks required to reach a timeout condition.\r
+\r
+  @retval TRUE                 A timeout condition has been reached.\r
+  @retval FALSE                A timeout condition has not been reached.\r
+\r
+**/\r
+BOOLEAN\r
+CheckTimeout (\r
+  IN OUT UINT64  *PreviousTime,\r
+  IN     UINT64  *TotalTime,\r
+  IN     UINT64  Timeout\r
+  )\r
+{\r
+  UINT64  Start;\r
+  UINT64  End;\r
+  UINT64  CurrentTime;\r
+  INT64   Delta;\r
+  INT64   Cycle;\r
+\r
+  if (Timeout == 0) {\r
+    return FALSE;\r
+  }\r
+  GetPerformanceCounterProperties (&Start, &End);\r
+  Cycle = End - Start;\r
+  if (Cycle < 0) {\r
+    Cycle = -Cycle;\r
+  }\r
+  Cycle++;\r
+  CurrentTime = GetPerformanceCounter();\r
+  Delta = (INT64) (CurrentTime - *PreviousTime);\r
+  if (Start > End) {\r
+    Delta = -Delta;\r
+  }\r
+  if (Delta < 0) {\r
+    Delta += Cycle;\r
+  }\r
+  *TotalTime += Delta;\r
+  *PreviousTime = CurrentTime;\r
+  if (*TotalTime > Timeout) {\r
+    return TRUE;\r
+  }\r
+  return FALSE;\r
+}\r
+\r
+/**\r
+  Searches for the next waiting AP.\r
+\r
+  Search for the next AP that is put in waiting state by single-threaded StartupAllAPs().\r
+\r
+  @param  NextProcessorNumber  Pointer to the processor number of the next waiting AP.\r
+\r
+  @retval EFI_SUCCESS          The next waiting AP has been found.\r
+  @retval EFI_NOT_FOUND        No waiting AP exists.\r
+\r
+**/\r
+EFI_STATUS\r
+GetNextWaitingProcessorNumber (\r
+  OUT UINTN                               *NextProcessorNumber\r
+  )\r
+{\r
+  UINTN           ProcessorNumber;\r
+\r
+  for (ProcessorNumber = 0; ProcessorNumber < mNumberOfProcessors; ProcessorNumber++) {\r
+\r
+    if (mMPSystemData.CpuList[ProcessorNumber]) {\r
+      *NextProcessorNumber = ProcessorNumber;\r
+      return EFI_SUCCESS;\r
+    }\r
+  }\r
+\r
+  return EFI_NOT_FOUND;\r
+}\r
+\r
+/**\r
+  Wrapper function for all procedures assigned to AP.\r
+\r
+  Wrapper function for all procedures assigned to AP via MP service protocol.\r
+  It controls states of AP and invokes assigned precedure.\r
+\r
+**/\r
+VOID\r
+ApProcWrapper (\r
+  VOID\r
+  )\r
+{\r
+  EFI_AP_PROCEDURE      Procedure;\r
+  VOID                  *Parameter;\r
+  UINTN                 ProcessorNumber;\r
+  CPU_DATA_BLOCK        *CpuData;\r
+\r
+  WhoAmI (&mMpService, &ProcessorNumber);\r
+  CpuData = &mMPSystemData.CpuData[ProcessorNumber];\r
+\r
+  AcquireSpinLock (&CpuData->CpuDataLock);\r
+  CpuData->State = CpuStateBusy;\r
+  ReleaseSpinLock (&CpuData->CpuDataLock);\r
+\r
+  //\r
+  // Now let us check it out.\r
+  //\r
+  AcquireSpinLock (&CpuData->CpuDataLock);\r
+  Procedure = CpuData->Procedure;\r
+  Parameter = CpuData->Parameter;\r
+  ReleaseSpinLock (&CpuData->CpuDataLock);\r
+\r
+  if (Procedure != NULL) {\r
+\r
+    Procedure (Parameter);\r
+\r
+    //\r
+    // if BSP is switched to AP, it continue execute from here, but it carries register state\r
+    // of the old AP, so need to reload CpuData (might be stored in a register after compiler\r
+    // optimization) to make sure it points to the right data\r
+    //\r
+    WhoAmI (&mMpService, &ProcessorNumber);\r
+    CpuData = &mMPSystemData.CpuData[ProcessorNumber];\r
+\r
+    AcquireSpinLock (&CpuData->CpuDataLock);\r
+    CpuData->Procedure = NULL;\r
+    ReleaseSpinLock (&CpuData->CpuDataLock);\r
+  }\r
+\r
+  AcquireSpinLock (&CpuData->CpuDataLock);\r
+  CpuData->State = CpuStateFinished;\r
+  ReleaseSpinLock (&CpuData->CpuDataLock);\r
+}\r
+\r
+/**\r
+  Sends INIT-SIPI-SIPI to AP.\r
+\r
+  This function sends INIT-SIPI-SIPI to AP, and assign procedure specified by ApFunction.\r
+\r
+  @param  Broadcast   If TRUE, broadcase IPI to all APs; otherwise, send to specified AP.\r
+  @param  ApicID      The Local APIC ID of the specified AP. If Broadcast is TRUE, it is ignored.\r
+  @param  ApFunction  The procedure for AP to work on.\r
+\r
+**/\r
+VOID\r
+SendInitSipiSipi (\r
+  IN BOOLEAN            Broadcast,\r
+  IN UINT32             ApicID,\r
+  IN VOID               *ApFunction\r
+  )\r
+{\r
+  UINTN                 ApicBase;\r
+  UINT32                ICRLow;\r
+  UINT32                ICRHigh;\r
+  \r
+  UINT32                VectorNumber;\r
+  UINT32                DeliveryMode;\r
+\r
+  mExchangeInfo->ApFunction = ApFunction;\r
+  mExchangeInfo->StackStart = mStackStartAddress;\r
+\r
+  if (Broadcast) {\r
+    ICRHigh = 0;\r
+    ICRLow  = BROADCAST_MODE_ALL_EXCLUDING_SELF_BIT | TRIGGER_MODE_LEVEL_BIT | ASSERT_BIT;\r
+  } else {\r
+    ICRHigh = ApicID << 24;\r
+    ICRLow  = SPECIFY_CPU_MODE_BIT | TRIGGER_MODE_LEVEL_BIT | ASSERT_BIT;\r
+  }\r
+\r
+  VectorNumber = 0;\r
+  DeliveryMode = DELIVERY_MODE_INIT;\r
+  ICRLow      |= VectorNumber | (DeliveryMode << 8);\r
+\r
+  ApicBase = 0xfee00000;\r
+\r
+  //\r
+  // Write Interrupt Command Registers to send INIT IPI.\r
+  //\r
+  MmioWrite32 (ApicBase + APIC_REGISTER_ICR_HIGH_OFFSET, ICRHigh);\r
+  MmioWrite32 (ApicBase + APIC_REGISTER_ICR_LOW_OFFSET, ICRLow);\r
+\r
+  MicroSecondDelay (10);\r
+\r
+  VectorNumber = (UINT32) RShiftU64 (mStartupVector, 12);\r
+  DeliveryMode = DELIVERY_MODE_SIPI;\r
+  if (Broadcast) {\r
+    ICRLow = BROADCAST_MODE_ALL_EXCLUDING_SELF_BIT | TRIGGER_MODE_LEVEL_BIT | ASSERT_BIT;\r
+  } else {\r
+    ICRLow = SPECIFY_CPU_MODE_BIT | TRIGGER_MODE_LEVEL_BIT | ASSERT_BIT;\r
+  }\r
+\r
+  ICRLow |= VectorNumber | (DeliveryMode << 8);\r
+\r
+  //\r
+  // Write Interrupt Command Register to send first SIPI IPI.\r
+  //\r
+  MmioWrite32 (ApicBase + APIC_REGISTER_ICR_LOW_OFFSET, ICRLow);\r
+\r
+  MicroSecondDelay (200);\r
+\r
+  //\r
+  // Write Interrupt Command Register to send second SIPI IPI.\r
+  //\r
+  MmioWrite32 (ApicBase + APIC_REGISTER_ICR_LOW_OFFSET, ICRLow);\r
+}\r
+\r
+/**\r
+  Function to wake up a specified AP and assign procedure to it.\r
+  \r
+  @param  ProcessorNumber  Handle number of the specified processor.\r
+  @param  Procedure        Procedure to assign.\r
+  @param  ProcArguments    Argument for Procedure.\r
+\r
+**/\r
+VOID\r
+WakeUpAp (\r
+  IN   UINTN                 ProcessorNumber,\r
+  IN   EFI_AP_PROCEDURE      Procedure,\r
+  IN   VOID                  *ProcArguments\r
+  )\r
+{\r
+  EFI_STATUS                   Status;\r
+  CPU_DATA_BLOCK               *CpuData;\r
+  EFI_PROCESSOR_INFORMATION    ProcessorInfoBuffer;\r
+\r
+  CpuData = &mMPSystemData.CpuData[ProcessorNumber];\r
+\r
+  AcquireSpinLock (&CpuData->CpuDataLock);\r
+  CpuData->Parameter  = ProcArguments;\r
+  CpuData->Procedure  = Procedure;\r
+  ReleaseSpinLock (&CpuData->CpuDataLock);\r
+\r
+  Status = GetProcessorInfo (\r
+             &mMpService,\r
+             ProcessorNumber,\r
+             &ProcessorInfoBuffer\r
+             );\r
+  ASSERT_EFI_ERROR (Status);\r
+\r
+  SendInitSipiSipi (\r
+    FALSE,\r
+    (UINT32) ProcessorInfoBuffer.ProcessorId,\r
+    (VOID *) (UINTN) ApProcWrapper\r
+    );\r
+}\r
+\r
+/**\r
+  Terminate AP's task and set it to idle state.\r
+  \r
+  This function terminates AP's task due to timeout by sending INIT-SIPI,\r
+  and sends it to idle state.\r
+\r
+  @param  ProcessorNumber  Handle number of the specified processor.\r
+\r
+**/\r
+VOID\r
+ResetProcessorToIdleState (\r
+  UINTN      ProcessorNumber\r
+  )\r
+{\r
+  EFI_STATUS                   Status;\r
+  CPU_DATA_BLOCK               *CpuData;\r
+  EFI_PROCESSOR_INFORMATION    ProcessorInfoBuffer;\r
+\r
+  Status = GetProcessorInfo (\r
+             &mMpService,\r
+             ProcessorNumber,\r
+             &ProcessorInfoBuffer\r
+             );\r
+  ASSERT_EFI_ERROR (Status);\r
+\r
+  SendInitSipiSipi (\r
+    FALSE,\r
+    (UINT32) ProcessorInfoBuffer.ProcessorId,\r
+    NULL\r
+    );\r
+\r
+  CpuData = &mMPSystemData.CpuData[ProcessorNumber];\r
+\r
+  AcquireSpinLock (&CpuData->CpuDataLock);\r
+  CpuData->State = CpuStateIdle;\r
+  ReleaseSpinLock (&CpuData->CpuDataLock);\r
+}\r
+\r
+/**\r
+  Worker function of EnableDisableAP ()\r
+\r
+  Worker function of EnableDisableAP (). Changes state of specified processor.\r
+\r
+  @param  ProcessorNumber Processor number of specified AP.\r
+  @param  NewState        Desired state of the specified AP.\r
+\r
+  @retval EFI_SUCCESS     AP's state successfully changed.\r
+\r
+**/\r
+EFI_STATUS\r
+ChangeCpuState (\r
+  IN     UINTN                      ProcessorNumber,\r
+  IN     BOOLEAN                    NewState\r
+  )\r
+{\r
+  CPU_DATA_BLOCK  *CpuData;\r
+\r
+  CpuData = &mMPSystemData.CpuData[ProcessorNumber];\r
+\r
+  if (!NewState) {\r
+    AcquireSpinLock (&CpuData->CpuDataLock);\r
+    CpuData->State = CpuStateDisabled;\r
+    ReleaseSpinLock (&CpuData->CpuDataLock);\r
+  } else {\r
+    AcquireSpinLock (&CpuData->CpuDataLock);\r
+    CpuData->State = CpuStateIdle;\r
+    ReleaseSpinLock (&CpuData->CpuDataLock);\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Test memory region of EfiGcdMemoryTypeReserved.\r
+\r
+  @param  Length           The length of memory region to test.\r
+\r
+  @retval EFI_SUCCESS      The memory region passes test.\r
+  @retval EFI_NOT_FOUND    The memory region is not reserved memory.\r
+  @retval EFI_DEVICE_ERROR The memory fails on test.\r
+\r
+**/\r
+EFI_STATUS\r
+TestReservedMemory (\r
+  UINTN  Length\r
+  )\r
+{\r
+  EFI_STATUS                       Status;\r
+  EFI_GCD_MEMORY_SPACE_DESCRIPTOR  Descriptor;\r
+  EFI_PHYSICAL_ADDRESS             Address;\r
+  UINTN                            LengthCovered;\r
+  UINTN                            RemainingLength;\r
+\r
+  //\r
+  // Walk through the memory descriptors covering the memory range.\r
+  //\r
+  Address         = mStartupVector;\r
+  RemainingLength = Length;\r
+  while (Address < mStartupVector + Length) {\r
+    Status = gDS->GetMemorySpaceDescriptor(\r
+                    Address,\r
+                    &Descriptor\r
+                    );\r
+    if (EFI_ERROR (Status)) {\r
+      return EFI_NOT_FOUND;\r
+    }\r
+\r
+    if (Descriptor.GcdMemoryType != EfiGcdMemoryTypeReserved) {\r
+      return EFI_NOT_FOUND;\r
+    }\r
+    //\r
+    // Calculated the length of the intersected range.\r
+    //\r
+    LengthCovered = (UINTN) (Descriptor.BaseAddress + Descriptor.Length - Address);\r
+    if (LengthCovered > RemainingLength) {\r
+      LengthCovered = RemainingLength;\r
+    }\r
+\r
+    Status = mGenMemoryTest->CompatibleRangeTest (\r
+                               mGenMemoryTest,\r
+                               Address,\r
+                               LengthCovered\r
+                               );\r
+    if (EFI_ERROR (Status)) {\r
+      return EFI_DEVICE_ERROR;\r
+    }\r
+\r
+    Address         += LengthCovered;\r
+    RemainingLength -= LengthCovered;\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Allocates startup vector for APs.\r
+\r
+  This function allocates Startup vector for APs.\r
+\r
+  @param  Size  The size of startup vector.\r
+\r
+**/\r
+VOID\r
+AllocateStartupVector (\r
+  UINTN   Size\r
+  )\r
+{\r
+  EFI_STATUS                            Status;\r
+\r
+  Status = gBS->LocateProtocol (\r
+                  &gEfiGenericMemTestProtocolGuid,\r
+                  NULL,\r
+                  (VOID **) &mGenMemoryTest\r
+                  );\r
+  if (EFI_ERROR (Status)) {\r
+    mGenMemoryTest = NULL;\r
+  }\r
+\r
+  for (mStartupVector = 0x7F000; mStartupVector >= 0x2000; mStartupVector -= EFI_PAGE_SIZE) {\r
+    if (mGenMemoryTest != NULL) {\r
+      //\r
+      // Test memory if it is EfiGcdMemoryTypeReserved.\r
+      //\r
+      Status = TestReservedMemory (EFI_SIZE_TO_PAGES (Size) * EFI_PAGE_SIZE);\r
+      if (Status == EFI_DEVICE_ERROR) {\r
+        continue;\r
+      }\r
+    }\r
+\r
+    Status = gBS->AllocatePages (\r
+                    AllocateAddress,\r
+                    EfiBootServicesCode,\r
+                    EFI_SIZE_TO_PAGES (Size),\r
+                    &mStartupVector\r
+                    );\r
+\r
+    if (!EFI_ERROR (Status)) {\r
+      break;\r
+    }\r
+  }\r
+\r
+  ASSERT_EFI_ERROR (Status);\r
+}\r
+\r
+/**\r
+  Prepares Startup Vector for APs.\r
+\r
+  This function prepares Startup Vector for APs.\r
+\r
+**/\r
+VOID\r
+PrepareAPStartupVector (\r
+  VOID\r
+  )\r
+{\r
+  MP_ASSEMBLY_ADDRESS_MAP   AddressMap;\r
+  IA32_DESCRIPTOR           GdtrForBSP;\r
+\r
+  //\r
+  // Get the address map of startup code for AP,\r
+  // including code size, and offset of long jump instructions to redirect.\r
+  //\r
+  AsmGetAddressMap (&AddressMap);\r
+\r
+  //\r
+  // Allocate a 4K-aligned region under 1M for startup vector for AP.\r
+  // The region contains AP startup code and exchange data between BSP and AP.\r
+  //\r
+  AllocateStartupVector (AddressMap.Size + sizeof (MP_CPU_EXCHANGE_INFO));\r
+\r
+  //\r
+  // Copy AP startup code to startup vector, and then redirect the long jump\r
+  // instructions for mode switching.\r
+  //\r
+  CopyMem ((VOID *) (UINTN) mStartupVector, AddressMap.RendezvousFunnelAddress, AddressMap.Size);\r
+  *(UINT32 *) (UINTN) (mStartupVector + AddressMap.FlatJumpOffset + 3) = (UINT32) (mStartupVector + AddressMap.PModeEntryOffset);\r
+  //\r
+  // For IA32 mode, LongJumpOffset is filled with zero. If non-zero, then we are in X64 mode, so further redirect for long mode switch.\r
+  //\r
+  if (AddressMap.LongJumpOffset != 0) {\r
+    *(UINT32 *) (UINTN) (mStartupVector + AddressMap.LongJumpOffset + 2) = (UINT32) (mStartupVector + AddressMap.LModeEntryOffset);\r
+  }\r
+\r
+  //\r
+  // Get the start address of exchange data between BSP and AP.\r
+  //\r
+  mExchangeInfo = (MP_CPU_EXCHANGE_INFO *) (UINTN) (mStartupVector + AddressMap.Size);\r
+\r
+  ZeroMem ((VOID *) mExchangeInfo, sizeof (MP_CPU_EXCHANGE_INFO));\r
+\r
+  mStackStartAddress = AllocatePages (EFI_SIZE_TO_PAGES (MAX_CPU_NUMBER * AP_STACK_SIZE));\r
+  mExchangeInfo->StackSize  = AP_STACK_SIZE;\r
+\r
+  AsmReadGdtr (&GdtrForBSP);\r
+  mExchangeInfo->GdtrProfile.Base  = GdtrForBSP.Base;\r
+  mExchangeInfo->GdtrProfile.Limit = GdtrForBSP.Limit;\r
+\r
+  mExchangeInfo->BufferStart = (UINT32) mStartupVector;\r
+  mExchangeInfo->Cr3         = (UINT32) (AsmReadCr3 ());\r
+}\r
+\r
+/**\r
+  Prepares memory region for processor configuration.\r
+  \r
+  This function prepares memory region for processor configuration.\r
+\r
+**/\r
+VOID\r
+PrepareMemoryForConfiguration (\r
+  VOID\r
+  )\r
+{\r
+  UINTN                Index;\r
+\r
+  //\r
+  // Initialize Spin Locks for system\r
+  //\r
+  InitializeSpinLock (&mMPSystemData.APSerializeLock);\r
+  for (Index = 0; Index < MAX_CPU_NUMBER; Index++) {\r
+    InitializeSpinLock (&mMPSystemData.CpuData[Index].CpuDataLock);\r
+  }\r
+  \r
+  PrepareAPStartupVector ();\r
+}\r
+\r
+/**\r
+  Gets the processor number of BSP.\r
+  \r
+  @return  The processor number of BSP.\r
+\r
+**/\r
+UINTN\r
+GetBspNumber (\r
+  VOID\r
+  )\r
+{\r
+  UINTN                      ProcessorNumber;\r
+  EFI_MP_PROC_CONTEXT        ProcessorContextBuffer;\r
+  EFI_STATUS                 Status;\r
+  UINTN                      BufferSize;\r
+\r
+  BufferSize = sizeof (EFI_MP_PROC_CONTEXT);\r
+\r
+  for (ProcessorNumber = 0; ProcessorNumber < mNumberOfProcessors; ProcessorNumber++) {\r
+    Status = mFrameworkMpService->GetProcessorContext (\r
+                                    mFrameworkMpService,\r
+                                    ProcessorNumber,\r
+                                    &BufferSize,\r
+                                    &ProcessorContextBuffer\r
+                                    );\r
+    ASSERT_EFI_ERROR (Status);\r
+    \r
+    if (ProcessorContextBuffer.Designation == EfiCpuBSP) {\r
+      break;\r
+    }\r
+  }\r
+  ASSERT (ProcessorNumber < mNumberOfProcessors);\r
+\r
+  return ProcessorNumber;\r
+}\r
+\r
+/**\r
+  Entrypoint of MP Services Protocol thunk driver.\r
+\r
+  @param[in] ImageHandle    The firmware allocated handle for the EFI image.  \r
+  @param[in] SystemTable    A pointer to the EFI System Table.\r
+  \r
+  @retval EFI_SUCCESS       The entry point is executed successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+InitializeMpServicesProtocol (\r
+  IN EFI_HANDLE        ImageHandle,\r
+  IN EFI_SYSTEM_TABLE  *SystemTable\r
+  )\r
+{\r
+  EFI_STATUS Status;\r
+\r
+  PrepareMemoryForConfiguration ();\r
+\r
+  //\r
+  // Locates Framework version MP Services Protocol\r
+  //\r
+  Status = gBS->LocateProtocol (\r
+                  &gFrameworkEfiMpServiceProtocolGuid, \r
+                  NULL, \r
+                  (VOID **) &mFrameworkMpService\r
+                  );\r
+  ASSERT_EFI_ERROR (Status);\r
+\r
+  Status = mFrameworkMpService->GetGeneralMPInfo (\r
+                                  mFrameworkMpService,\r
+                                  &mNumberOfProcessors,\r
+                                  NULL,\r
+                                  NULL,\r
+                                  NULL,\r
+                                  NULL\r
+                                  );\r
+  ASSERT_EFI_ERROR (Status);\r
+\r
+  //\r
+  // Create timer event to check AP state for non-blocking execution.\r
+  //\r
+  Status = gBS->CreateEvent (\r
+                  EVT_TIMER | EVT_NOTIFY_SIGNAL,\r
+                  TPL_CALLBACK,\r
+                  CheckAPsStatus,\r
+                  NULL,\r
+                  &mMPSystemData.CheckAPsEvent\r
+                  );\r
+  ASSERT_EFI_ERROR (Status);\r
+\r
+  //\r
+  // Now install the MP services protocol.\r
+  //\r
+  Status = gBS->InstallProtocolInterface (\r
+                  &mHandle,\r
+                  &gEfiMpServiceProtocolGuid,\r
+                  EFI_NATIVE_INTERFACE,\r
+                  &mMpService\r
+                  );\r
+  ASSERT_EFI_ERROR (Status);\r
+\r
+  //\r
+  // Launch the timer event to check AP state.\r
+  //\r
+  Status = gBS->SetTimer (\r
+                  mMPSystemData.CheckAPsEvent,\r
+                  TimerPeriodic,\r
+                  100000\r
+                  );\r
+  ASSERT_EFI_ERROR (Status);\r
+\r
+  return EFI_SUCCESS;\r
+}\r
diff --git a/EdkCompatibilityPkg/Compatibility/MpServicesOnFrameworkMpServicesThunk/MpServicesOnFrameworkMpServicesThunk.h b/EdkCompatibilityPkg/Compatibility/MpServicesOnFrameworkMpServicesThunk/MpServicesOnFrameworkMpServicesThunk.h
new file mode 100644 (file)
index 0000000..5b42071
--- /dev/null
@@ -0,0 +1,516 @@
+/** @file\r
+Include file for PI MP Services Protocol Thunk.\r
+\r
+Copyright (c) 2009 Intel Corporation. <BR>\r
+All rights reserved. This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution.  The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+Module Name:\r
+\r
+**/\r
+\r
+#ifndef _MP_SERVICES_ON_FRAMEWORK_MP_SERVICES_THUNK_\r
+#define _MP_SERVICES_ON_FRAMEWORK_MP_SERVICES_THUNK_\r
+\r
+#include <Protocol/MpService.h>\r
+#include <Protocol/FrameworkMpService.h>\r
+#include <Protocol/GenericMemoryTest.h>\r
+\r
+#include <Library/BaseLib.h>\r
+#include <Library/SynchronizationLib.h>\r
+#include <Library/DebugLib.h>\r
+#include <Library/UefiLib.h>\r
+#include <Library/BaseMemoryLib.h>\r
+#include <Library/UefiDriverEntryPoint.h>\r
+#include <Library/MemoryAllocationLib.h>\r
+#include <Library/UefiBootServicesTableLib.h>\r
+#include <Library/DxeServicesTableLib.h>\r
+#include <Library/IoLib.h>\r
+#include <Library/TimerLib.h>\r
+\r
+#define AP_STACK_SIZE                         0x8000\r
+#define MAX_CPU_NUMBER                        256\r
+\r
+//\r
+// Bit definition for IPI\r
+//\r
+#define BROADCAST_MODE_ALL_EXCLUDING_SELF_BIT  0xC0000\r
+#define SPECIFY_CPU_MODE_BIT                   0x00000\r
+#define TRIGGER_MODE_LEVEL_BIT                 0x08000\r
+#define ASSERT_BIT                             0x04000\r
+\r
+//\r
+// Local APIC register definition for IPI.\r
+//\r
+#define APIC_REGISTER_ICR_LOW_OFFSET          0x300\r
+#define APIC_REGISTER_ICR_HIGH_OFFSET         0x310\r
+\r
+typedef struct {\r
+  UINTN             Lock;\r
+  VOID              *StackStart;\r
+  UINTN             StackSize;\r
+  VOID              *ApFunction;\r
+  IA32_DESCRIPTOR   GdtrProfile;\r
+  UINT32            BufferStart;\r
+  UINT32            Cr3;\r
+} MP_CPU_EXCHANGE_INFO;\r
+\r
+typedef struct {\r
+  UINT8 *RendezvousFunnelAddress;\r
+  UINTN PModeEntryOffset;\r
+  UINTN FlatJumpOffset;\r
+  UINTN LModeEntryOffset;\r
+  UINTN LongJumpOffset;\r
+  UINTN Size;\r
+} MP_ASSEMBLY_ADDRESS_MAP;\r
+\r
+typedef enum {\r
+  CpuStateIdle,\r
+  CpuStateReady,\r
+  CpuStateBusy,\r
+  CpuStateFinished,\r
+  CpuStateDisabled\r
+} CPU_STATE;\r
+\r
+//\r
+// Define Individual Processor Data block.\r
+//\r
+typedef struct {\r
+  EFI_AP_PROCEDURE volatile      Procedure;\r
+  VOID* volatile                 Parameter;\r
+\r
+  EFI_EVENT                      WaitEvent;\r
+  BOOLEAN                        *Finished;\r
+  UINT64                         ExpectedTime;\r
+  UINT64                         CurrentTime;\r
+  UINT64                         TotalTime;\r
+\r
+  SPIN_LOCK                      CpuDataLock;\r
+  CPU_STATE volatile             State;\r
+\r
+} CPU_DATA_BLOCK;\r
+\r
+//\r
+// Define MP data block which consumes individual processor block.\r
+//\r
+typedef struct {\r
+  SPIN_LOCK                   APSerializeLock;\r
+\r
+  EFI_EVENT                   CheckAPsEvent;\r
+\r
+  UINTN                       FinishCount;\r
+  UINTN                       StartCount;\r
+\r
+  BOOLEAN                     CpuList[MAX_CPU_NUMBER];\r
+\r
+  EFI_AP_PROCEDURE            Procedure;\r
+  VOID                        *ProcArguments;\r
+  BOOLEAN                     SingleThread;\r
+  EFI_EVENT                   WaitEvent;\r
+  UINTN                       **FailedCpuList;\r
+  UINT64                      ExpectedTime;\r
+  UINT64                      CurrentTime;\r
+  UINT64                      TotalTime;\r
+\r
+  CPU_DATA_BLOCK              CpuData[MAX_CPU_NUMBER];\r
+} MP_SYSTEM_DATA;\r
+\r
+/**\r
+  Implementation of GetNumberOfProcessors() service of MP Services Protocol.\r
+\r
+  This service retrieves the number of logical processor in the platform\r
+  and the number of those logical processors that are enabled on this boot.\r
+  This service may only be called from the BSP.\r
+\r
+  @param  This                       A pointer to the EFI_MP_SERVICES_PROTOCOL instance.\r
+  @param  NumberOfProcessors         Pointer to the total number of logical processors in the system,\r
+                                     including the BSP and disabled APs.\r
+  @param  NumberOfEnabledProcessors  Pointer to the number of enabled logical processors that exist\r
+                                     in system, including the BSP.\r
+\r
+  @retval EFI_SUCCESS               Number of logical processors and enabled logical processors retrieved..\r
+  @retval EFI_DEVICE_ERROR           Caller processor is AP.\r
+  @retval EFI_INVALID_PARAMETER      NumberOfProcessors is NULL\r
+  @retval EFI_INVALID_PARAMETER      NumberOfEnabledProcessors is NULL\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+GetNumberOfProcessors (\r
+  IN  EFI_MP_SERVICES_PROTOCOL     *This,\r
+  OUT UINTN                        *NumberOfProcessors,\r
+  OUT UINTN                        *NumberOfEnabledProcessors\r
+  );\r
+\r
+/**\r
+  Implementation of GetNumberOfProcessors() service of MP Services Protocol.\r
+\r
+  Gets detailed MP-related information on the requested processor at the\r
+  instant this call is made. This service may only be called from the BSP.\r
+\r
+  @param  This                  A pointer to the EFI_MP_SERVICES_PROTOCOL instance.\r
+  @param  ProcessorNumber       The handle number of processor.\r
+  @param  ProcessorInfoBuffer   A pointer to the buffer where information for the requested processor is deposited.\r
+\r
+  @retval EFI_SUCCESS           Processor information successfully returned.\r
+  @retval EFI_DEVICE_ERROR      Caller processor is AP.\r
+  @retval EFI_INVALID_PARAMETER ProcessorInfoBuffer is NULL\r
+  @retval EFI_NOT_FOUND         Processor with the handle specified by ProcessorNumber does not exist. \r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+GetProcessorInfo (\r
+  IN       EFI_MP_SERVICES_PROTOCOL     *This,\r
+  IN       UINTN                        ProcessorNumber,\r
+  OUT      EFI_PROCESSOR_INFORMATION    *ProcessorInfoBuffer\r
+  );\r
+\r
+/**\r
+  Implementation of StartupAllAPs() service of MP Services Protocol.\r
+\r
+  This service lets the caller get all enabled APs to execute a caller-provided function.\r
+  This service may only be called from the BSP.\r
+\r
+  @param  This                  A pointer to the EFI_MP_SERVICES_PROTOCOL instance.\r
+  @param  Procedure             A pointer to the function to be run on enabled APs of the system.\r
+  @param  SingleThread          Indicates whether to execute the function simultaneously or one by one..\r
+  @param  WaitEvent             The event created by the caller.\r
+                                If it is NULL, then execute in blocking mode.\r
+                                If it is not NULL, then execute in non-blocking mode.\r
+  @param  TimeoutInMicroSeconds The time limit in microseconds for this AP to finish the function.\r
+                                Zero means infinity.\r
+  @param  ProcedureArgument     Pointer to the optional parameter of the assigned function.\r
+  @param  FailedCpuList         The list of processor numbers that fail to finish the function before\r
+                                TimeoutInMicrosecsond expires.\r
+\r
+  @retval EFI_SUCCESS           In blocking mode, all APs have finished before the timeout expired. \r
+  @retval EFI_SUCCESS           In non-blocking mode, function has been dispatched to all enabled APs.\r
+  @retval EFI_DEVICE_ERROR      Caller processor is AP.\r
+  @retval EFI_NOT_STARTED       No enabled AP exists in the system.\r
+  @retval EFI_NOT_READY         Any enabled AP is busy.\r
+  @retval EFI_TIMEOUT           In blocking mode, The timeout expired before all enabled APs have finished.\r
+  @retval EFI_INVALID_PARAMETER Procedure is NULL.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+StartupAllAPs (\r
+  IN  EFI_MP_SERVICES_PROTOCOL   *This,\r
+  IN  EFI_AP_PROCEDURE           Procedure,\r
+  IN  BOOLEAN                    SingleThread,\r
+  IN  EFI_EVENT                  WaitEvent             OPTIONAL,\r
+  IN  UINTN                      TimeoutInMicroSeconds,\r
+  IN  VOID                       *ProcedureArgument    OPTIONAL,\r
+  OUT UINTN                      **FailedCpuList       OPTIONAL\r
+  );\r
+\r
+/**\r
+  Implementation of StartupThisAP() service of MP Services Protocol.\r
+\r
+  This service lets the caller get one enabled AP to execute a caller-provided function.\r
+  This service may only be called from the BSP.\r
+\r
+  @param  This                  A pointer to the EFI_MP_SERVICES_PROTOCOL instance.\r
+  @param  Procedure             A pointer to the function to be run on the designated AP.\r
+  @param  ProcessorNumber       The handle number of AP..\r
+  @param  WaitEvent             The event created by the caller.\r
+                                If it is NULL, then execute in blocking mode.\r
+                                If it is not NULL, then execute in non-blocking mode.\r
+  @param  TimeoutInMicroseconds The time limit in microseconds for this AP to finish the function.\r
+                                Zero means infinity.\r
+  @param  ProcedureArgument     Pointer to the optional parameter of the assigned function.\r
+  @param  Finished              Indicates whether AP has finished assigned function.\r
+                                In blocking mode, it is ignored.\r
+\r
+  @retval EFI_SUCCESS           In blocking mode, specified AP has finished before the timeout expires.\r
+  @retval EFI_SUCCESS           In non-blocking mode, function has been dispatched to specified AP.\r
+  @retval EFI_DEVICE_ERROR      Caller processor is AP.\r
+  @retval EFI_TIMEOUT           In blocking mode, the timeout expires before specified AP has finished.\r
+  @retval EFI_NOT_READY         Specified AP is busy.\r
+  @retval EFI_NOT_FOUND         Processor with the handle specified by ProcessorNumber does not exist.\r
+  @retval EFI_INVALID_PARAMETER ProcessorNumber specifies the BSP or disabled AP.\r
+  @retval EFI_INVALID_PARAMETER Procedure is NULL.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+StartupThisAP (\r
+  IN  EFI_MP_SERVICES_PROTOCOL   *This,\r
+  IN  EFI_AP_PROCEDURE           Procedure,\r
+  IN  UINTN                      ProcessorNumber,\r
+  IN  EFI_EVENT                  WaitEvent OPTIONAL,\r
+  IN  UINTN                      TimeoutInMicroseconds,\r
+  IN  VOID                       *ProcedureArgument OPTIONAL,\r
+  OUT BOOLEAN                    *Finished OPTIONAL\r
+  );\r
+\r
+/**\r
+  Implementation of SwitchBSP() service of MP Services Protocol.\r
+\r
+  This service switches the requested AP to be the BSP from that point onward.\r
+  This service may only be called from the current BSP.\r
+\r
+  @param  This                  A pointer to the EFI_MP_SERVICES_PROTOCOL instance.\r
+  @param  ProcessorNumber       The handle number of processor.\r
+  @param  EnableOldBSP          Whether to enable or disable the original BSP.\r
+\r
+  @retval EFI_SUCCESS           BSP successfully switched.\r
+  @retval EFI_DEVICE_ERROR      Caller processor is AP.\r
+  @retval EFI_NOT_FOUND         Processor with the handle specified by ProcessorNumber does not exist.\r
+  @retval EFI_INVALID_PARAMETER ProcessorNumber specifies the BSP or disabled AP.\r
+  @retval EFI_NOT_READY         Specified AP is busy.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SwitchBSP (\r
+  IN  EFI_MP_SERVICES_PROTOCOL            *This,\r
+  IN  UINTN                               ProcessorNumber,\r
+  IN  BOOLEAN                             EnableOldBSP\r
+  );\r
+\r
+/**\r
+  Implementation of EnableDisableAP() service of MP Services Protocol.\r
+\r
+  This service lets the caller enable or disable an AP.\r
+  This service may only be called from the BSP.\r
+\r
+  @param  This                   A pointer to the EFI_MP_SERVICES_PROTOCOL instance.\r
+  @param  ProcessorNumber        The handle number of processor.\r
+  @param  EnableAP               Indicates whether the newstate of the AP is enabled or disabled.\r
+  @param  HealthFlag             Indicates new health state of the AP..\r
+\r
+  @retval EFI_SUCCESS            AP successfully enabled or disabled.\r
+  @retval EFI_DEVICE_ERROR       Caller processor is AP.\r
+  @retval EFI_NOT_FOUND          Processor with the handle specified by ProcessorNumber does not exist.\r
+  @retval EFI_INVALID_PARAMETERS ProcessorNumber specifies the BSP.\r
+  \r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+EnableDisableAP (\r
+  IN  EFI_MP_SERVICES_PROTOCOL            *This,\r
+  IN  UINTN                               ProcessorNumber,\r
+  IN  BOOLEAN                             EnableAP,\r
+  IN  UINT32                              *HealthFlag OPTIONAL\r
+  );\r
+\r
+/**\r
+  Implementation of WhoAmI() service of MP Services Protocol.\r
+\r
+  This service lets the caller processor get its handle number.\r
+  This service may be called from the BSP and APs.\r
+\r
+  @param  This                  A pointer to the EFI_MP_SERVICES_PROTOCOL instance.\r
+  @param  ProcessorNumber       Pointer to the handle number of AP.\r
+\r
+  @retval EFI_SUCCESS           Processor number successfully returned.\r
+  @retval EFI_INVALID_PARAMETER ProcessorNumber is NULL\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+WhoAmI (\r
+  IN  EFI_MP_SERVICES_PROTOCOL            *This,\r
+  OUT UINTN                               *ProcessorNumber\r
+  );\r
+\r
+/**\r
+  Checks APs' status periodically.\r
+\r
+  This function is triggerred by timer perodically to check the\r
+  state of APs for StartupAllAPs() and StartupThisAP() executed\r
+  in non-blocking mode.\r
+\r
+  @param  Event    Event triggered.\r
+  @param  Context  Parameter passed with the event.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+CheckAPsStatus (\r
+  IN  EFI_EVENT                           Event,\r
+  IN  VOID                                *Context\r
+  );\r
+\r
+/**\r
+  Checks status of all APs.\r
+\r
+  This function checks whether all APs have finished task assigned by StartupAllAPs(),\r
+  and whether timeout expires.\r
+\r
+  @retval EFI_SUCCESS           All APs have finished task assigned by StartupAllAPs().\r
+  @retval EFI_TIMEOUT           The timeout expires.\r
+  @retval EFI_NOT_READY         APs have not finished task and timeout has not expired.\r
+\r
+**/\r
+EFI_STATUS\r
+CheckAllAPs (\r
+  VOID\r
+  );\r
+\r
+/**\r
+  Checks status of specified AP.\r
+\r
+  This function checks whether specified AP has finished task assigned by StartupThisAP(),\r
+  and whether timeout expires.\r
+\r
+  @param  ProcessorNumber       The handle number of processor.\r
+\r
+  @retval EFI_SUCCESS           Specified AP has finished task assigned by StartupThisAPs().\r
+  @retval EFI_TIMEOUT           The timeout expires.\r
+  @retval EFI_NOT_READY         Specified AP has not finished task and timeout has not expired.\r
+\r
+**/\r
+EFI_STATUS\r
+CheckThisAP (\r
+  UINTN  ProcessorNumber\r
+  );\r
+\r
+/**\r
+  Calculate timeout value and return the current performance counter value.\r
+\r
+  Calculate the number of performance counter ticks required for a timeout.\r
+  If TimeoutInMicroseconds is 0, return value is also 0, which is recognized\r
+  as infinity.\r
+\r
+  @param  TimeoutInMicroseconds   Timeout value in microseconds.\r
+  @param  CurrentTime             Returns the current value of the performance counter.\r
+\r
+  @return Expected timestamp counter for timeout.\r
+          If TimeoutInMicroseconds is 0, return value is also 0, which is recognized\r
+          as infinity.\r
+\r
+**/\r
+UINT64\r
+CalculateTimeout (\r
+  IN  UINTN   TimeoutInMicroseconds,\r
+  OUT UINT64  *CurrentTime\r
+  );\r
+\r
+/**\r
+  Checks whether timeout expires.\r
+\r
+  Check whether the number of ellapsed performance counter ticks required for a timeout condition\r
+  has been reached.  If Timeout is zero, which means infinity, return value is always FALSE.\r
+\r
+  @param  PreviousTime         On input, the value of the performance counter when it was last read.\r
+                               On output, the current value of the performance counter\r
+  @param  TotalTime            The total amount of ellapsed time in performance counter ticks.\r
+  @param  Timeout              The number of performance counter ticks required to reach a timeout condition.\r
+\r
+  @retval TRUE                 A timeout condition has been reached.\r
+  @retval FALSE                A timeout condition has not been reached.\r
+\r
+**/\r
+BOOLEAN\r
+CheckTimeout (\r
+  IN OUT UINT64  *PreviousTime,\r
+  IN     UINT64  *TotalTime,\r
+  IN     UINT64  Timeout\r
+  );\r
+\r
+/**\r
+  Searches for the next waiting AP.\r
+\r
+  Search for the next AP that is put in waiting state by single-threaded StartupAllAPs().\r
+\r
+  @param  NextProcessorNumber  Pointer to the processor number of the next waiting AP.\r
+\r
+  @retval EFI_SUCCESS          The next waiting AP has been found.\r
+  @retval EFI_NOT_FOUND        No waiting AP exists.\r
+\r
+**/\r
+EFI_STATUS\r
+GetNextWaitingProcessorNumber (\r
+  OUT UINTN                               *NextProcessorNumber\r
+  );\r
+\r
+/**\r
+  Wrapper function for all procedures assigned to AP.\r
+\r
+  Wrapper function for all procedures assigned to AP via MP service protocol.\r
+  It controls states of AP and invokes assigned precedure.\r
+\r
+**/\r
+VOID\r
+ApProcWrapper (\r
+  VOID\r
+  );\r
+\r
+/**\r
+  Function to wake up a specified AP and assign procedure to it.\r
+  \r
+  @param  ProcessorNumber  Handle number of the specified processor.\r
+  @param  Procedure        Procedure to assign.\r
+  @param  ProcArguments    Argument for Procedure.\r
+\r
+**/\r
+VOID\r
+WakeUpAp (\r
+  IN   UINTN                 ProcessorNumber,\r
+  IN   EFI_AP_PROCEDURE      Procedure,\r
+  IN   VOID                  *ProcArguments\r
+  );\r
+\r
+/**\r
+  Terminate AP's task and set it to idle state.\r
+  \r
+  This function terminates AP's task due to timeout by sending INIT-SIPI,\r
+  and sends it to idle state.\r
+\r
+  @param  ProcessorNumber  Handle number of the specified processor.\r
+\r
+**/\r
+VOID\r
+ResetProcessorToIdleState (\r
+  UINTN      ProcessorNumber\r
+  );\r
+\r
+/**\r
+  Worker function of EnableDisableAP ()\r
+\r
+  Worker function of EnableDisableAP (). Changes state of specified processor.\r
+\r
+  @param  ProcessorNumber Processor number of specified AP.\r
+  @param  NewState        Desired state of the specified AP.\r
+\r
+  @retval EFI_SUCCESS     AP's state successfully changed.\r
+\r
+**/\r
+EFI_STATUS\r
+ChangeCpuState (\r
+  IN     UINTN                      ProcessorNumber,\r
+  IN     BOOLEAN                    NewState\r
+  );\r
+\r
+/**\r
+  Gets the processor number of BSP.\r
+  \r
+  @return  The processor number of BSP.\r
+\r
+**/\r
+UINTN\r
+GetBspNumber (\r
+  VOID\r
+  );\r
+\r
+/**\r
+  Get address map of RendezvousFunnelProc.\r
+\r
+  This function gets address map of RendezvousFunnelProc.\r
+\r
+  @param  AddressMap   Output buffer for address map information\r
+\r
+**/\r
+VOID\r
+AsmGetAddressMap (\r
+  OUT MP_ASSEMBLY_ADDRESS_MAP    *AddressMap\r
+  );\r
+\r
+#endif\r
diff --git a/EdkCompatibilityPkg/Compatibility/MpServicesOnFrameworkMpServicesThunk/MpServicesOnFrameworkMpServicesThunk.inf b/EdkCompatibilityPkg/Compatibility/MpServicesOnFrameworkMpServicesThunk/MpServicesOnFrameworkMpServicesThunk.inf
new file mode 100644 (file)
index 0000000..66ad83f
--- /dev/null
@@ -0,0 +1,68 @@
+#/** @file\r
+# Produces PI MP Services Protocol on top of Framework MP Services Protocol.\r
+#\r
+# Intel's Framework MP Services Protocol is replaced by EFI_MP_SERVICES_PROTOCOL in PI 1.1.\r
+# This module produces PI MP Services Protocol on top of Framework MP Services Protocol.\r
+#\r
+# Copyright (c) 2009, Intel Corporation\r
+#\r
+#  All rights reserved. This program and the accompanying materials\r
+#  are licensed and made available under the terms and conditions of the BSD License\r
+#  which accompanies this distribution. The full text of the license may be found at\r
+#  http://opensource.org/licenses/bsd-license.php\r
+#  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+#  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+#\r
+#\r
+#**/\r
+\r
+[Defines]\r
+  INF_VERSION                    = 0x00010005\r
+  BASE_NAME                      = MpServicesOnFrameworkMpServicesThunk\r
+  FILE_GUID                      = 51739E2A-A022-4D73-ADB9-91F0C9BC7142\r
+  MODULE_TYPE                    = DXE_DRIVER\r
+  ENTRY_POINT                    = InitializeMpServicesProtocol\r
+\r
+#\r
+# The following information is for reference only and not required by the build tools.\r
+#\r
+#  VALID_ARCHITECTURES           = IA32 X64\r
+#\r
+\r
+[Sources.common]\r
+  MpServicesOnFrameworkMpServicesThunk.c\r
+  MpServicesOnFrameworkMpServicesThunk.h\r
+\r
+[Sources.X64]\r
+  X64/MpFuncs.asm\r
+  X64/MpFuncs.S\r
+\r
+[Sources.IA32]\r
+  IA32/MpFuncs.asm\r
+  IA32/MpFuncs.S\r
+\r
+[Packages]\r
+  MdePkg/MdePkg.dec\r
+  MdeModulePkg/MdeModulePkg.dec\r
+  IntelFrameworkPkg/IntelFrameworkPkg.dec\r
+\r
+[LibraryClasses]\r
+  TimerLib\r
+  IoLib\r
+  UefiBootServicesTableLib\r
+  DxeServicesTableLib\r
+  MemoryAllocationLib\r
+  UefiDriverEntryPoint\r
+  BaseMemoryLib\r
+  UefiLib\r
+  DebugLib\r
+  BaseLib\r
+  SynchronizationLib\r
+\r
+[Protocols]\r
+  gEfiMpServiceProtocolGuid                   ## PRODUCES\r
+  gFrameworkEfiMpServiceProtocolGuid          ## CONSUMES\r
+  gEfiGenericMemTestProtocolGuid              ## SOMETIMES_CONSUMES\r
+\r
+[Depex]\r
+  gFrameworkEfiMpServiceProtocolGuid\r
diff --git a/EdkCompatibilityPkg/Compatibility/MpServicesOnFrameworkMpServicesThunk/X64/AsmInclude.inc b/EdkCompatibilityPkg/Compatibility/MpServicesOnFrameworkMpServicesThunk/X64/AsmInclude.inc
new file mode 100644 (file)
index 0000000..79889bf
--- /dev/null
@@ -0,0 +1,26 @@
+;------------------------------------------------------------------------------\r
+; Include file for X64 MpFuncs.asm\r
+;\r
+; Copyright (c) 2009, Intel Corporation\r
+; All rights reserved. This program and the accompanying materials\r
+; are licensed and made available under the terms and conditions of the BSD License\r
+; which accompanies this distribution.  The full text of the license may be found at\r
+; http://opensource.org/licenses/bsd-license.php\r
+;\r
+; THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+; WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+;\r
+;------------------------------------------------------------------------------\r
+\r
+VacantFlag             Equ   00h\r
+NotVacantFlag          Equ   0ffh\r
+\r
+LockLocation                  equ        RendezvousFunnelProcEnd - RendezvousFunnelProcStart\r
+StackStartAddressLocation     equ        LockLocation + 08h\r
+StackSizeLocation             equ        LockLocation + 10h\r
+CProcedureLocation            equ        LockLocation + 18h\r
+GdtrLocation                  equ        LockLocation + 20h\r
+BufferStartLocation           equ        LockLocation + 2Ch\r
+Cr3OffsetLocation             equ        LockLocation + 30h\r
+\r
+;-------------------------------------------------------------------------------\r
diff --git a/EdkCompatibilityPkg/Compatibility/MpServicesOnFrameworkMpServicesThunk/X64/MpFuncs.S b/EdkCompatibilityPkg/Compatibility/MpServicesOnFrameworkMpServicesThunk/X64/MpFuncs.S
new file mode 100644 (file)
index 0000000..5b34cba
--- /dev/null
@@ -0,0 +1,189 @@
+#------------------------------------------------------------------------------\r
+# X64 assembly file for AP startup vector.\r
+#\r
+# Copyright (c) 2009, Intel Corporation\r
+# All rights reserved. This program and the accompanying materials\r
+# are licensed and made available under the terms and conditions of the BSD License\r
+# which accompanies this distribution.  The full text of the license may be found at\r
+# http://opensource.org/licenses/bsd-license.php\r
+#\r
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+#\r
+#------------------------------------------------------------------------------\r
+\r
+\r
+.equ                   VacantFlag,       0x0\r
+.equ                   NotVacantFlag,    0xff\r
+\r
+.equ                   LockLocation,              RendezvousFunnelProcEnd - RendezvousFunnelProcStart\r
+.equ                   StackStartAddressLocation, RendezvousFunnelProcEnd - RendezvousFunnelProcStart + 0x08\r
+.equ                   StackSizeLocation,         RendezvousFunnelProcEnd - RendezvousFunnelProcStart + 0x10\r
+.equ                   CProcedureLocation,        RendezvousFunnelProcEnd - RendezvousFunnelProcStart + 0x18\r
+.equ                   GdtrLocation,              RendezvousFunnelProcEnd - RendezvousFunnelProcStart + 0x20\r
+.equ                   BufferStartLocation,       RendezvousFunnelProcEnd - RendezvousFunnelProcStart + 0x2C\r
+.equ                   Cr3OffsetLocation,         RendezvousFunnelProcEnd - RendezvousFunnelProcStart + 0x30\r
+\r
+#-------------------------------------------------------------------------------------\r
+\r
+#-------------------------------------------------------------------------------------\r
+#RendezvousFunnelProc  procedure follows. All APs execute their procedure. This\r
+#procedure serializes all the AP processors through an Init sequence. It must be\r
+#noted that APs arrive here very raw...ie: real mode, no stack.\r
+#ALSO THIS PROCEDURE IS EXECUTED BY APs ONLY ON 16 BIT MODE. HENCE THIS PROC\r
+#IS IN MACHINE CODE.\r
+#-------------------------------------------------------------------------------------\r
+#RendezvousFunnelProc (&WakeUpBuffer,MemAddress);\r
+\r
+.text\r
+\r
+ASM_GLOBAL ASM_PFX(RendezvousFunnelProc)\r
+ASM_PFX(RendezvousFunnelProc):\r
+RendezvousFunnelProcStart:\r
+\r
+# At this point CS = 0x(vv00) and ip= 0x0.\r
+\r
+        .byte 0x8c,0xc8               # mov        ax,  cs\r
+        .byte 0x8e,0xd8               # mov        ds,  ax\r
+        .byte 0x8e,0xc0               # mov        es,  ax\r
+        .byte 0x8e,0xd0               # mov        ss,  ax \r
+        .byte 0x33,0xc0               # xor        ax,  ax\r
+        .byte 0x8e,0xe0               # mov        fs,  ax\r
+        .byte 0x8e,0xe8               # mov        gs,  ax\r
+\r
+# Switch to flat mode.\r
+\r
+        .byte 0xBE\r
+        .word BufferStartLocation\r
+        .byte 0x66,0x8B,0x14          # mov        edx,dword ptr [si]          ; EDX is keeping the start address of wakeup buffer\r
+\r
+        .byte 0xBE\r
+        .word Cr3OffsetLocation\r
+        .byte 0x66,0x8B,0xC           # mov        ecx,dword ptr [si]          ; ECX is keeping the value of CR3\r
+\r
+        .byte 0xBE\r
+        .word GdtrLocation\r
+        .byte 0x66                    # db         66h\r
+        .byte 0x2E,0xF,0x1,0x14       # lgdt       fword ptr cs:[si]\r
+\r
+        .byte 0x33,0xC0               # xor        ax,  ax\r
+        .byte 0x8E,0xD8               # mov        ds,  ax\r
+\r
+        .byte 0xF,0x20,0xC0           # mov        eax, cr0                    ; Get control register 0\r
+        .byte 0x66,0x83,0xC8,0x1      # or         eax, 000000001h             ; Set PE bit (bit #0)\r
+        .byte 0xF,0x22,0xC0           # mov        cr0, eax\r
+\r
+FLAT32_JUMP:\r
+\r
+        .byte 0x66,0x67,0xEA          # far jump\r
+        .long 0x0                     # 32-bit offset\r
+        .word 0x20                    # 16-bit selector\r
+\r
+ProtectedModeStart:\r
+\r
+        .byte 0x66,0xB8,0x18,0x0      # mov        ax,  18h\r
+        .byte 0x66,0x8E,0xD8          # mov        ds,  ax\r
+        .byte 0x66,0x8E,0xC0          # mov        es,  ax\r
+        .byte 0x66,0x8E,0xE0          # mov        fs,  ax\r
+        .byte 0x66,0x8E,0xE8          # mov        gs,  ax\r
+        .byte 0x66,0x8E,0xD0          # mov        ss,  ax                     ; Flat mode setup.\r
+\r
+        .byte 0xF,0x20,0xE0           # mov        eax, cr4\r
+        .byte 0xF,0xBA,0xE8,0x5       # bts        eax, 5\r
+        .byte 0xF,0x22,0xE0           # mov        cr4, eax\r
+\r
+        .byte 0xF,0x22,0xD9           # mov        cr3, ecx\r
+\r
+        .byte 0x8B,0xF2               # mov        esi, edx                    ; Save wakeup buffer address\r
+\r
+        .byte 0xB9\r
+        .long 0xC0000080              # mov        ecx, 0c0000080h             ; EFER MSR number.\r
+        .byte 0xF,0x32                # rdmsr                                  ; Read EFER.\r
+        .byte 0xF,0xBA,0xE8,0x8       # bts        eax, 8                      ; Set LME=1.\r
+        .byte 0xF,0x30                # wrmsr                                  ; Write EFER.\r
+\r
+        .byte 0xF,0x20,0xC0           # mov        eax, cr0                    ; Read CR0.\r
+        .byte 0xF,0xBA,0xE8,0x1F      # bts        eax, 31                     ; Set PG=1.\r
+        .byte 0xF,0x22,0xC0           # mov        cr0, eax                    ; Write CR0.\r
+\r
+LONG_JUMP:\r
+\r
+        .byte 0x67,0xEA               # far jump\r
+        .long 0x0                     # 32-bit offset\r
+        .word 0x38                    # 16-bit selector\r
+\r
+LongModeStart:\r
+\r
+        movw        $0x30,%ax\r
+        .byte       0x66\r
+        movw        %ax,%ds\r
+        .byte       0x66\r
+        movw        %ax,%es\r
+        .byte       0x66\r
+        movw        %ax,%ss\r
+\r
+        movl        %esi, %edi\r
+        addl        $LockLocation, %edi\r
+        movb        $NotVacantFlag, %al\r
+TestLock:\r
+        xchgb       (%edi), %al\r
+        cmpb        $NotVacantFlag, %al\r
+        jz          TestLock\r
+\r
+ProgramStack:\r
+\r
+        movl        %esi, %edi\r
+        addl        $StackSizeLocation, %edi \r
+        movq        (%edi), %rax\r
+        movl        %esi, %edi\r
+        addl        $StackStartAddressLocation, %edi\r
+        addq        (%edi), %rax\r
+        movq        %rax, %rsp\r
+        movq        %rax, (%edi) \r
+\r
+Releaselock:\r
+\r
+        movb        $VacantFlag, %al\r
+        movl        %esi, %edi\r
+        addl        $LockLocation, %edi\r
+        xchgb       (%edi), %al\r
+\r
+        #\r
+        # Call C Function\r
+        #\r
+        movl        %esi,%edi\r
+        addl        $CProcedureLocation, %edi\r
+        movq        (%edi), %rax\r
+\r
+        testq       %rax, %rax\r
+        jz          GoToSleep\r
+\r
+        subq        $0x20, %rsp\r
+        call        *%rax\r
+        addq        $0x20, %rsp\r
+\r
+GoToSleep:\r
+\r
+        cli\r
+        hlt\r
+        jmp         .-2\r
+\r
+RendezvousFunnelProcEnd:\r
+\r
+\r
+#-------------------------------------------------------------------------------------\r
+#  AsmGetAddressMap (&AddressMap);\r
+#-------------------------------------------------------------------------------------\r
+# comments here for definition of address map\r
+ASM_GLOBAL ASM_PFX(AsmGetAddressMap)\r
+ASM_PFX(AsmGetAddressMap):\r
+\r
+        movq         $RendezvousFunnelProcStart, %rax\r
+        movq         %rax, (%rcx)\r
+        movq         $(ProtectedModeStart - RendezvousFunnelProcStart), 0x08(%rcx)\r
+        movq         $(FLAT32_JUMP - RendezvousFunnelProcStart), 0x10(%rcx)\r
+        movq         $(LongModeStart - RendezvousFunnelProcStart), 0x18(%rcx)\r
+        movq         $(LONG_JUMP - RendezvousFunnelProcStart), 0x20(%rcx)\r
+        movq         $(RendezvousFunnelProcEnd - RendezvousFunnelProcStart), 0x28(%rcx)\r
+\r
+        ret\r
diff --git a/EdkCompatibilityPkg/Compatibility/MpServicesOnFrameworkMpServicesThunk/X64/MpFuncs.asm b/EdkCompatibilityPkg/Compatibility/MpServicesOnFrameworkMpServicesThunk/X64/MpFuncs.asm
new file mode 100644 (file)
index 0000000..5b6fc45
--- /dev/null
@@ -0,0 +1,177 @@
+;------------------------------------------------------------------------------\r
+; X64 assembly file for AP startup vector.\r
+;\r
+; Copyright (c) 2009, Intel Corporation\r
+; All rights reserved. This program and the accompanying materials\r
+; are licensed and made available under the terms and conditions of the BSD License\r
+; which accompanies this distribution.  The full text of the license may be found at\r
+; http://opensource.org/licenses/bsd-license.php\r
+;\r
+; THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+; WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+;\r
+;------------------------------------------------------------------------------\r
+\r
+.code\r
+\r
+include  AsmInclude.inc \r
+;-------------------------------------------------------------------------------------\r
+\r
+;-------------------------------------------------------------------------------------\r
+;RendezvousFunnelProc  procedure follows. All APs execute their procedure. This\r
+;procedure serializes all the AP processors through an Init sequence. It must be\r
+;noted that APs arrive here very raw...ie: real mode, no stack.\r
+;ALSO THIS PROCEDURE IS EXECUTED BY APs ONLY ON 16 BIT MODE. HENCE THIS PROC\r
+;IS IN MACHINE CODE.\r
+;-------------------------------------------------------------------------------------\r
+;RendezvousFunnelProc (&WakeUpBuffer,MemAddress);\r
+\r
+RendezvousFunnelProc   PROC  PUBLIC\r
+RendezvousFunnelProcStart::\r
+\r
+; At this point CS = 0x(vv00) and ip= 0x0.\r
+\r
+        db 8ch,  0c8h                 ; mov        ax,  cs\r
+        db 8eh,  0d8h                 ; mov        ds,  ax\r
+        db 8eh,  0c0h                 ; mov        es,  ax\r
+        db 8eh,  0d0h                 ; mov        ss,  ax \r
+        db 33h,  0c0h                 ; xor        ax,  ax\r
+        db 8eh,  0e0h                 ; mov        fs,  ax\r
+        db 8eh,  0e8h                 ; mov        gs,  ax\r
+\r
+; Switch to flat mode.\r
+\r
+        db 0BEh\r
+        dw BufferStartLocation        ; mov        si, BufferStartLocation\r
+        db 66h,  8Bh, 14h             ; mov        edx,dword ptr [si]          ; EDX is keeping the start address of wakeup buffer\r
+\r
+        db 0BEh\r
+        dw Cr3OffsetLocation          ; mov        si, Cr3Location\r
+        db 66h,  8Bh, 0Ch             ; mov        ecx,dword ptr [si]          ; ECX is keeping the value of CR3\r
+        \r
+        db 0BEh\r
+        dw GdtrLocation               ; mov        si, GdtrProfile\r
+        db 66h                        ; db         66h\r
+        db 2Eh,  0Fh, 01h, 14h        ; lgdt       fword ptr cs:[si]\r
+\r
+        db 33h,  0C0h                 ; xor        ax,  ax\r
+        db 8Eh,  0D8h                 ; mov        ds,  ax\r
+        \r
+        db 0Fh,  20h, 0C0h            ; mov        eax, cr0                    ; Get control register 0\r
+        db 66h,  83h, 0C8h, 01h       ; or         eax, 000000001h             ; Set PE bit (bit #0)\r
+        db 0Fh,  22h, 0C0h            ; mov        cr0, eax\r
+\r
+FLAT32_JUMP::\r
+\r
+        db 66h,  67h, 0EAh            ; far jump\r
+        dd 0h                         ; 32-bit offset\r
+        dw 20h                        ; 16-bit selector\r
+\r
+ProtectedModeStart::\r
+\r
+        db 66h,  0B8h, 18h,  00h      ; mov        ax,  18h\r
+        db 66h,  8Eh,  0D8h           ; mov        ds,  ax\r
+        db 66h,  8Eh,  0C0h           ; mov        es,  ax\r
+        db 66h,  8Eh,  0E0h           ; mov        fs,  ax\r
+        db 66h,  8Eh,  0E8h           ; mov        gs,  ax\r
+        db 66h,  8Eh,  0D0h           ; mov        ss,  ax                     ; Flat mode setup.\r
+\r
+        db 0Fh,  20h,  0E0h           ; mov        eax, cr4\r
+        db 0Fh,  0BAh, 0E8h, 05h      ; bts        eax, 5\r
+        db 0Fh,  22h,  0E0h           ; mov        cr4, eax\r
+\r
+        db 0Fh,  22h,  0D9h           ; mov        cr3, ecx\r
+        \r
+        db 8Bh,  0F2h                 ; mov        esi, edx                    ; Save wakeup buffer address\r
+        \r
+        db 0B9h\r
+        dd 0C0000080h                 ; mov        ecx, 0c0000080h             ; EFER MSR number.\r
+        db 0Fh,  32h                  ; rdmsr                                  ; Read EFER.\r
+        db 0Fh,  0BAh, 0E8h, 08h      ; bts        eax, 8                      ; Set LME=1.\r
+        db 0Fh,  30h                  ; wrmsr                                  ; Write EFER.\r
+        \r
+        db 0Fh,  20h,  0C0h           ; mov        eax, cr0                    ; Read CR0.\r
+        db 0Fh,  0BAh, 0E8h, 1Fh      ; bts        eax, 31                     ; Set PG=1.\r
+        db 0Fh,  22h,  0C0h           ; mov        cr0, eax                    ; Write CR0.\r
+\r
+LONG_JUMP::\r
+        \r
+        db 67h,  0EAh                 ; far jump\r
+        dd 0h                         ; 32-bit offset\r
+        dw 38h                        ; 16-bit selector\r
+        \r
+LongModeStart::\r
+\r
+        mov         ax,  30h\r
+        mov         ds,  ax\r
+        mov         es,  ax\r
+        mov         ss,  ax\r
+\r
+        mov         edi, esi\r
+        add         edi, LockLocation\r
+        mov         al,  NotVacantFlag\r
+TestLock::\r
+        xchg        byte ptr [edi], al\r
+        cmp         al, NotVacantFlag\r
+        jz          TestLock\r
+\r
+ProgramStack::\r
+\r
+        mov         edi, esi\r
+        add         edi, StackSizeLocation\r
+        mov         rax, qword ptr [edi]\r
+        mov         edi, esi\r
+        add         edi, StackStartAddressLocation\r
+        add         rax, qword ptr [edi]\r
+        mov         rsp, rax\r
+        mov         qword ptr [edi], rax\r
+\r
+Releaselock::\r
+\r
+        mov         al,  VacantFlag\r
+        mov         edi, esi\r
+        add         edi, LockLocation\r
+        xchg        byte ptr [edi], al\r
+\r
+        ;\r
+        ; Call C Function\r
+        ;\r
+        mov         edi, esi\r
+        add         edi, CProcedureLocation\r
+        mov         rax, qword ptr [edi]\r
+\r
+        test        rax, rax\r
+        jz          GoToSleep\r
+\r
+        sub         rsp, 20h\r
+        call        rax\r
+        add         rsp, 20h\r
+        \r
+GoToSleep::\r
+\r
+        cli\r
+        hlt\r
+        jmp         $-2\r
+        \r
+RendezvousFunnelProc   ENDP\r
+RendezvousFunnelProcEnd::\r
+\r
+\r
+;-------------------------------------------------------------------------------------\r
+;  AsmGetAddressMap (&AddressMap);\r
+;-------------------------------------------------------------------------------------\r
+AsmGetAddressMap   PROC  \r
+\r
+        mov         rax, offset RendezvousFunnelProcStart\r
+        mov         qword ptr [rcx], rax\r
+        mov         qword ptr [rcx+8h], ProtectedModeStart - RendezvousFunnelProcStart\r
+        mov         qword ptr [rcx+10h], FLAT32_JUMP - RendezvousFunnelProcStart\r
+        mov         qword ptr [rcx+18h], LongModeStart - RendezvousFunnelProcStart\r
+        mov         qword ptr [rcx+20h], LONG_JUMP - RendezvousFunnelProcStart\r
+        mov         qword ptr [rcx+28h], RendezvousFunnelProcEnd - RendezvousFunnelProcStart\r
+        \r
+        ret\r
+        \r
+AsmGetAddressMap   ENDP\r
+\r
+END\r
index 98c79b107a3554fe9f0a4987189139459e8a8256..a0fe66460ca97f2a8583cb432324ac491abbc67a 100644 (file)
@@ -62,7 +62,8 @@ define GCC_MACRO                 = -DEFI_SPECIFICATION_VERSION=0x00020000 -DPI_S
   PeiServicesLib|MdePkg/Library/PeiServicesLib/PeiServicesLib.inf\r
   PeiServicesTablePointerLib|MdePkg/Library/PeiServicesTablePointerLib/PeiServicesTablePointerLib.inf\r
   LanguageLib|EdkCompatibilityPkg/Compatibility/Library/UefiLanguageLib/UefiLanguageLib.inf\r
-    \r
+  DxeServicesTableLib|MdePkg/Library/DxeServicesTableLib/DxeServicesTableLib.inf\r
+\r
 [LibraryClasses.common.PEIM]\r
   HobLib|MdePkg/Library/PeiHobLib/PeiHobLib.inf\r
   MemoryAllocationLib|MdePkg/Library/PeiMemoryAllocationLib/PeiMemoryAllocationLib.inf\r
@@ -242,6 +243,7 @@ define GCC_MACRO                 = -DEFI_SPECIFICATION_VERSION=0x00020000 -DPI_S
   EdkCompatibilityPkg/Compatibility/UcOnUc2Thunk/UcOnUc2Thunk.inf\r
   EdkCompatibilityPkg/Compatibility/PrintThunk/PrintThunk.inf\r
   EdkCompatibilityPkg/Compatibility/LegacyRegion2OnLegacyRegionThunk/LegacyRegion2OnLegacyRegionThunk.inf\r
+  EdkCompatibilityPkg/Compatibility/MpServicesOnFrameworkMpServicesThunk/MpServicesOnFrameworkMpServicesThunk.inf\r
   EdkCompatibilityPkg/Compatibility/CpuIo2OnCpuIoThunk/CpuIo2OnCpuIoThunk.inf\r
 \r
   #\r