From 768e2a903b5edd380f04df141af621db92bd32a1 Mon Sep 17 00:00:00 2001 From: xli24 Date: Tue, 15 Dec 2009 03:00:49 +0000 Subject: [PATCH] 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 --- .../IA32/AsmInclude.inc | 25 + .../IA32/MpFuncs.S | 154 ++ .../IA32/MpFuncs.asm | 148 ++ .../MpServicesOnFrameworkMpServicesThunk.c | 1616 +++++++++++++++++ .../MpServicesOnFrameworkMpServicesThunk.h | 516 ++++++ .../MpServicesOnFrameworkMpServicesThunk.inf | 68 + .../X64/AsmInclude.inc | 26 + .../X64/MpFuncs.S | 189 ++ .../X64/MpFuncs.asm | 177 ++ EdkCompatibilityPkg/EdkCompatibilityPkg.dsc | 4 +- 10 files changed, 2922 insertions(+), 1 deletion(-) create mode 100644 EdkCompatibilityPkg/Compatibility/MpServicesOnFrameworkMpServicesThunk/IA32/AsmInclude.inc create mode 100644 EdkCompatibilityPkg/Compatibility/MpServicesOnFrameworkMpServicesThunk/IA32/MpFuncs.S create mode 100644 EdkCompatibilityPkg/Compatibility/MpServicesOnFrameworkMpServicesThunk/IA32/MpFuncs.asm create mode 100644 EdkCompatibilityPkg/Compatibility/MpServicesOnFrameworkMpServicesThunk/MpServicesOnFrameworkMpServicesThunk.c create mode 100644 EdkCompatibilityPkg/Compatibility/MpServicesOnFrameworkMpServicesThunk/MpServicesOnFrameworkMpServicesThunk.h create mode 100644 EdkCompatibilityPkg/Compatibility/MpServicesOnFrameworkMpServicesThunk/MpServicesOnFrameworkMpServicesThunk.inf create mode 100644 EdkCompatibilityPkg/Compatibility/MpServicesOnFrameworkMpServicesThunk/X64/AsmInclude.inc create mode 100644 EdkCompatibilityPkg/Compatibility/MpServicesOnFrameworkMpServicesThunk/X64/MpFuncs.S create mode 100644 EdkCompatibilityPkg/Compatibility/MpServicesOnFrameworkMpServicesThunk/X64/MpFuncs.asm 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.
+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.
+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 +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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 diff --git a/EdkCompatibilityPkg/EdkCompatibilityPkg.dsc b/EdkCompatibilityPkg/EdkCompatibilityPkg.dsc index 98c79b107a..a0fe66460c 100644 --- a/EdkCompatibilityPkg/EdkCompatibilityPkg.dsc +++ b/EdkCompatibilityPkg/EdkCompatibilityPkg.dsc @@ -62,7 +62,8 @@ define GCC_MACRO = -DEFI_SPECIFICATION_VERSION=0x00020000 -DPI_S PeiServicesLib|MdePkg/Library/PeiServicesLib/PeiServicesLib.inf PeiServicesTablePointerLib|MdePkg/Library/PeiServicesTablePointerLib/PeiServicesTablePointerLib.inf LanguageLib|EdkCompatibilityPkg/Compatibility/Library/UefiLanguageLib/UefiLanguageLib.inf - + DxeServicesTableLib|MdePkg/Library/DxeServicesTableLib/DxeServicesTableLib.inf + [LibraryClasses.common.PEIM] HobLib|MdePkg/Library/PeiHobLib/PeiHobLib.inf MemoryAllocationLib|MdePkg/Library/PeiMemoryAllocationLib/PeiMemoryAllocationLib.inf @@ -242,6 +243,7 @@ define GCC_MACRO = -DEFI_SPECIFICATION_VERSION=0x00020000 -DPI_S EdkCompatibilityPkg/Compatibility/UcOnUc2Thunk/UcOnUc2Thunk.inf EdkCompatibilityPkg/Compatibility/PrintThunk/PrintThunk.inf EdkCompatibilityPkg/Compatibility/LegacyRegion2OnLegacyRegionThunk/LegacyRegion2OnLegacyRegionThunk.inf + EdkCompatibilityPkg/Compatibility/MpServicesOnFrameworkMpServicesThunk/MpServicesOnFrameworkMpServicesThunk.inf EdkCompatibilityPkg/Compatibility/CpuIo2OnCpuIoThunk/CpuIo2OnCpuIoThunk.inf # -- 2.39.2