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