--- /dev/null
+;------------------------------------------------------------------------------\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
--- /dev/null
+#------------------------------------------------------------------------------\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
--- /dev/null
+;------------------------------------------------------------------------------\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
--- /dev/null
+/** @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
--- /dev/null
+/** @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
--- /dev/null
+#/** @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
--- /dev/null
+;------------------------------------------------------------------------------\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
--- /dev/null
+#------------------------------------------------------------------------------\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
--- /dev/null
+;------------------------------------------------------------------------------\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
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
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