summaryrefslogtreecommitdiff
path: root/Silicon/BroxtonSoC/BroxtonSiPkg/Cpu/Library/Private/PeiMpServiceLib
diff options
context:
space:
mode:
Diffstat (limited to 'Silicon/BroxtonSoC/BroxtonSiPkg/Cpu/Library/Private/PeiMpServiceLib')
-rw-r--r--Silicon/BroxtonSoC/BroxtonSiPkg/Cpu/Library/Private/PeiMpServiceLib/Features.h120
-rw-r--r--Silicon/BroxtonSoC/BroxtonSiPkg/Cpu/Library/Private/PeiMpServiceLib/Ia32/MpEqu.h45
-rw-r--r--Silicon/BroxtonSoC/BroxtonSiPkg/Cpu/Library/Private/PeiMpServiceLib/Ia32/MpEqu.inc49
-rw-r--r--Silicon/BroxtonSoC/BroxtonSiPkg/Cpu/Library/Private/PeiMpServiceLib/Ia32/MpEquNasm.inc49
-rw-r--r--Silicon/BroxtonSoC/BroxtonSiPkg/Cpu/Library/Private/PeiMpServiceLib/Ia32/MpFuncs.S316
-rw-r--r--Silicon/BroxtonSoC/BroxtonSiPkg/Cpu/Library/Private/PeiMpServiceLib/Ia32/MpFuncs.asm365
-rw-r--r--Silicon/BroxtonSoC/BroxtonSiPkg/Cpu/Library/Private/PeiMpServiceLib/Ia32/MpFuncs.nasm361
-rw-r--r--Silicon/BroxtonSoC/BroxtonSiPkg/Cpu/Library/Private/PeiMpServiceLib/Microcode.c221
-rw-r--r--Silicon/BroxtonSoC/BroxtonSiPkg/Cpu/Library/Private/PeiMpServiceLib/MpService.c1756
-rw-r--r--Silicon/BroxtonSoC/BroxtonSiPkg/Cpu/Library/Private/PeiMpServiceLib/MpService.h211
-rw-r--r--Silicon/BroxtonSoC/BroxtonSiPkg/Cpu/Library/Private/PeiMpServiceLib/MtrrSync.c273
-rw-r--r--Silicon/BroxtonSoC/BroxtonSiPkg/Cpu/Library/Private/PeiMpServiceLib/PeiMpServiceLib.inf65
12 files changed, 3831 insertions, 0 deletions
diff --git a/Silicon/BroxtonSoC/BroxtonSiPkg/Cpu/Library/Private/PeiMpServiceLib/Features.h b/Silicon/BroxtonSoC/BroxtonSiPkg/Cpu/Library/Private/PeiMpServiceLib/Features.h
new file mode 100644
index 0000000000..52209a5df4
--- /dev/null
+++ b/Silicon/BroxtonSoC/BroxtonSiPkg/Cpu/Library/Private/PeiMpServiceLib/Features.h
@@ -0,0 +1,120 @@
+/** @file
+ Header file of CPU feature control module.
+
+ Copyright (c) 1999 - 2016, Intel Corporation. All rights reserved.<BR>
+
+ This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php.
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef _FEATURES_H_
+#define _FEATURES_H_
+
+#include <Private/Library/MpServiceLib.h>
+
+///
+/// Processor feature definitions.
+///
+#define TXT_SUPPORT 1
+#define VMX_SUPPORT (1 << 1)
+#define XD_SUPPORT (1 << 2)
+#define DCA_SUPPORT (1 << 3)
+#define X2APIC_SUPPORT (1 << 4)
+#define AES_SUPPORT (1 << 5)
+#define HT_SUPPORT (1 << 6)
+#define DEBUG_SUPPORT (1 << 7)
+#define DEBUG_LOCK_SUPPORT (1 << 8)
+#define PROC_TRACE_SUPPORT (1 << 9)
+
+#define OPTION_FEATURE_RESERVED_MASK 0xFFFB00F8 ///< bits 30:16, 18, 7:3
+#define OPTION_FEATURE_CONFIG_RESERVED_MASK 0xFFFFFFFC ///< bits 2:31
+
+#define MAX_TOPA_ENTRY_COUNT 2
+
+typedef struct {
+ UINT64 TopaEntry[MAX_TOPA_ENTRY_COUNT];
+} PROC_TRACE_TOPA_TABLE;
+
+/**
+ Create feature control structure which will be used to program each feature on each core.
+
+**/
+VOID
+InitializeFeaturePerSetup (
+ VOID
+ );
+
+/**
+ Program all processor features basing on desired settings
+
+**/
+VOID
+EFIAPI
+ProgramProcessorFeature (
+ VOID
+ );
+
+/**
+ Program CPUID Limit before booting to OS
+
+**/
+VOID
+EFIAPI
+ProgramCpuidLimit (
+ VOID
+ );
+
+/**
+ Initialize prefetcher settings
+
+ @param[in] MlcStreamerprefecterEnabled Enable/Disable MLC streamer prefetcher
+ @param[in] MlcSpatialPrefetcherEnabled Enable/Disable MLC spatial prefetcher
+
+**/
+VOID
+InitializeProcessorsPrefetcher (
+ IN UINTN MlcStreamerprefecterEnabled,
+ IN UINTN MlcSpatialPrefetcherEnabled
+ );
+
+/**
+ Detect each processor feature and log all supported features
+
+**/
+VOID
+EFIAPI
+CollectProcessorFeature (
+ VOID
+ );
+
+/**
+ Lock VMX/TXT feature bits on the processor.
+ Set "CFG Lock" (MSR 0E2h Bit[15]
+
+**/
+VOID
+LockFeatureBit (
+ VOID
+ );
+
+
+/**
+ Provide access to the CPU misc enables MSR
+
+ @param[in] Enable Enable or Disable Misc Features
+ @param[in] BitMask The register bit offset of MSR MSR_IA32_MISC_ENABLE
+
+**/
+VOID
+CpuMiscEnable (
+ BOOLEAN Enable,
+ UINT64 BitMask
+ );
+#endif
+
diff --git a/Silicon/BroxtonSoC/BroxtonSiPkg/Cpu/Library/Private/PeiMpServiceLib/Ia32/MpEqu.h b/Silicon/BroxtonSoC/BroxtonSiPkg/Cpu/Library/Private/PeiMpServiceLib/Ia32/MpEqu.h
new file mode 100644
index 0000000000..df13a04a58
--- /dev/null
+++ b/Silicon/BroxtonSoC/BroxtonSiPkg/Cpu/Library/Private/PeiMpServiceLib/Ia32/MpEqu.h
@@ -0,0 +1,45 @@
+/** @file
+ This is the equates file for HT (Hyper-threading) support.
+
+ Copyright (c) 1999 - 2016, Intel Corporation. All rights reserved.<BR>
+
+ This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php.
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#define VacantFlag 0x00
+#define NotVacantFlag 0xff
+
+#define LockLocation (0x1000 - 0x0400)
+#define StackStartAddressLocation (LockLocation + 0x04)
+#define StackSizeLocation (LockLocation + 0x08)
+#define CProcedureLocation (LockLocation + 0x0C)
+#define GdtrLocation (LockLocation + 0x10)
+#define IdtrLocation (LockLocation + 0x16)
+#define BufferStartLocation (LockLocation + 0x1C)
+#define PmodeOffsetLocation (LockLocation + 0x20)
+#define AcpiCpuDataAddressLocation (LockLocation + 0x24)
+#define MtrrValuesAddressLocation (LockLocation + 0x28)
+#define FinishedCountAddressLocation (LockLocation + 0x2C)
+#define WakeupCountAddressLocation (LockLocation + 0x30)
+#define SerializeLockAddressLocation (LockLocation + 0x34)
+#define MicrocodeAddressLocation (LockLocation + 0x38)
+#define BootScriptAddressLocation (LockLocation + 0x3C)
+#define StartStateLocation (LockLocation + 0x40)
+#define VirtualWireMode (LockLocation + 0x44)
+#define SemaphoreCheck (LockLocation + 0x48)
+#define PeiServices (LockLocation + 0x4C)
+#define PeiStall (LockLocation + 0x50)
+#define CpuPerfCtrlValue (LockLocation + 0x54)
+#define SiCpuPolicyPpi (LockLocation + 0x5C)
+#define MpSystemDataAddressLocation (LockLocation + 0x64)
+#define MpServicePpiAddressLocation (LockLocation + 0x68)
+#define CArgumentLocation (LockLocation + 0x6C)
+#define BistBufferLocation (LockLocation + 0x70)
+
diff --git a/Silicon/BroxtonSoC/BroxtonSiPkg/Cpu/Library/Private/PeiMpServiceLib/Ia32/MpEqu.inc b/Silicon/BroxtonSoC/BroxtonSiPkg/Cpu/Library/Private/PeiMpServiceLib/Ia32/MpEqu.inc
new file mode 100644
index 0000000000..196019fefb
--- /dev/null
+++ b/Silicon/BroxtonSoC/BroxtonSiPkg/Cpu/Library/Private/PeiMpServiceLib/Ia32/MpEqu.inc
@@ -0,0 +1,49 @@
+;; @file
+; This is the equates file used in MpFuncs.asm, for MP support.
+;
+; Copyright (c) 1999 - 2016, Intel Corporation. All rights reserved.<BR>
+;
+; This program and the accompanying materials
+; are licensed and made available under the terms and conditions of the BSD License
+; which accompanies this distribution. The full text of the license may be found at
+; http://opensource.org/licenses/bsd-license.php.
+;
+; THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+; WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED
+;
+;;
+
+VacantFlag Equ 00h
+NotVacantFlag Equ 0ffh
+
+LockLocation equ 1000h - 0400h
+StackStartAddressLocation equ LockLocation + 04h
+StackSizeLocation equ LockLocation + 08h
+CProcedureLocation equ LockLocation + 0Ch
+GdtrLocation equ LockLocation + 10h
+IdtrLocation equ LockLocation + 16h
+BufferStartLocation equ LockLocation + 1Ch
+PmodeOffsetLocation equ LockLocation + 20h
+AcpiCpuDataAddressLocation equ LockLocation + 24h
+MtrrValuesAddressLocation equ LockLocation + 28h
+FinishedCountAddressLocation equ LockLocation + 2Ch
+WakeupCountAddressLocation equ LockLocation + 30h
+SerializeLockAddressLocation equ LockLocation + 34h
+MicrocodeAddressLocation equ LockLocation + 38h
+BootScriptAddressLocation equ LockLocation + 3Ch
+StartStateLocation equ LockLocation + 40h
+VirtualWireMode equ LockLocation + 44h
+SemaphoreCheck equ LockLocation + 48h
+PeiServices equ LockLocation + 4Ch
+PeiStall equ LockLocation + 50h
+CpuPerfCtrlValue equ LockLocation + 54h
+SiCpuPolicyPpi equ LockLocation + 5Ch
+MpSystemDataAddressLocation equ LockLocation + 64h
+MpServicePpiAddressLocation equ LockLocation + 68h
+CArgumentLocation equ LockLocation + 6Ch
+BistBufferLocation equ LockLocation + 70h
+
+PAUSE32 MACRO
+ DB 0F3h
+ DB 090h
+ ENDM
diff --git a/Silicon/BroxtonSoC/BroxtonSiPkg/Cpu/Library/Private/PeiMpServiceLib/Ia32/MpEquNasm.inc b/Silicon/BroxtonSoC/BroxtonSiPkg/Cpu/Library/Private/PeiMpServiceLib/Ia32/MpEquNasm.inc
new file mode 100644
index 0000000000..0590cd88de
--- /dev/null
+++ b/Silicon/BroxtonSoC/BroxtonSiPkg/Cpu/Library/Private/PeiMpServiceLib/Ia32/MpEquNasm.inc
@@ -0,0 +1,49 @@
+;; @file
+; This is the equates file used in MpFuncs.asm, for MP support.
+;
+; Copyright (c) 1999 - 2016, Intel Corporation. All rights reserved.<BR>
+;
+; This program and the accompanying materials
+; are licensed and made available under the terms and conditions of the BSD License
+; which accompanies this distribution. The full text of the license may be found at
+; http://opensource.org/licenses/bsd-license.php.
+;
+; THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+; WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED
+;
+;;
+
+%define VacantFlag 0x0
+%define NotVacantFlag 0xff
+
+%define LockLocation 0x1000 - 0x400
+%define StackStartAddressLocation LockLocation + 0x4
+%define StackSizeLocation LockLocation + 0x8
+%define CProcedureLocation LockLocation + 0xC
+%define GdtrLocation LockLocation + 0x10
+%define IdtrLocation LockLocation + 0x16
+%define BufferStartLocation LockLocation + 0x1C
+%define PmodeOffsetLocation LockLocation + 0x20
+%define AcpiCpuDataAddressLocation LockLocation + 0x24
+%define MtrrValuesAddressLocation LockLocation + 0x28
+%define FinishedCountAddressLocation LockLocation + 0x2C
+%define WakeupCountAddressLocation LockLocation + 0x30
+%define SerializeLockAddressLocation LockLocation + 0x34
+%define MicrocodeAddressLocation LockLocation + 0x38
+%define BootScriptAddressLocation LockLocation + 0x3C
+%define StartStateLocation LockLocation + 0x40
+%define VirtualWireMode LockLocation + 0x44
+%define SemaphoreCheck LockLocation + 0x48
+%define PeiServices LockLocation + 0x4C
+%define PeiStall LockLocation + 0x50
+%define CpuPerfCtrlValue LockLocation + 0x54
+%define SiCpuPolicyPpi LockLocation + 0x5C
+%define MpSystemDataAddressLocation LockLocation + 0x64
+%define MpServicePpiAddressLocation LockLocation + 0x68
+%define CArgumentLocation LockLocation + 0x6C
+%define BistBufferLocation LockLocation + 0x70
+
+%macro PAUSE32 0
+ DB 0xF3
+ DB 0x90
+ %endmacro
diff --git a/Silicon/BroxtonSoC/BroxtonSiPkg/Cpu/Library/Private/PeiMpServiceLib/Ia32/MpFuncs.S b/Silicon/BroxtonSoC/BroxtonSiPkg/Cpu/Library/Private/PeiMpServiceLib/Ia32/MpFuncs.S
new file mode 100644
index 0000000000..91ca56e85a
--- /dev/null
+++ b/Silicon/BroxtonSoC/BroxtonSiPkg/Cpu/Library/Private/PeiMpServiceLib/Ia32/MpFuncs.S
@@ -0,0 +1,316 @@
+## @file
+# This is the assembly code for MP support.
+#
+# Copyright (c) 1999 - 2016, Intel Corporation. All rights reserved.<BR>
+#
+# This program and the accompanying materials
+# are licensed and made available under the terms and conditions of the BSD License
+# which accompanies this distribution. The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php.
+#
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED
+#
+##
+
+#include "MpEqu.h"
+
+ .text
+ ASM_FUNCTION_REMOVE_IF_UNREFERENCED
+
+//-------------------------------------------------------------------------------
+// AsmAcquireMPLock (&Lock);
+//-------------------------------------------------------------------------------
+.globl ASM_PFX(AsmAcquireMPLock)
+ASM_PFX(AsmAcquireMPLock):
+
+ pusha
+ mov %esp, %ebp
+
+ mov $NotVacantFlag, %al
+ mov 0x24(%ebp), %ebx
+L_TryGetLock:
+ xchg (%ebx), %al
+ cmp $VacantFlag, %al
+ jz L_LockObtained
+
+ pause
+ jmp L_TryGetLock
+
+L_LockObtained:
+ popa
+ ret
+
+//-------------------------------------------------------------------------------
+// AsmReleaseMPLock (&Lock);
+//-------------------------------------------------------------------------------------
+.globl ASM_PFX(AsmReleaseMPLock)
+ASM_PFX(AsmReleaseMPLock):
+
+ pusha
+ mov %esp, %ebp
+
+ mov $VacantFlag, %al
+ movl 0x24(%ebp), %ebx
+ xchg (%ebx), %al
+
+ popa
+ ret
+
+//-------------------------------------------------------------------------------------
+//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);
+
+.globl ASM_PFX(RendezvousFunnelProc)
+ASM_PFX(RendezvousFunnelProc):
+L_RendezvousFunnelProcStart:
+
+ .code16
+
+// At this point CS = 0x(vv00) and ip= 0x0.
+ mov %eax, %ebp
+ mov %cs, %ax
+ mov %ax, %ds
+ mov %ax, %es
+ mov %ax, %ss
+ xor %ax, %ax
+ mov %ax, %fs
+ mov %ax, %gs
+
+// Get APIC ID
+ mov $1, %eax
+ cpuid
+ shr $24, %ebx
+ and $0xff, %ebx // EBX is APIC ID
+
+// If it is the first time AP wakes up, just record AP's BIST
+// Otherwise, switch to protected mode.
+
+ mov $StartStateLocation, %si
+ cmpl $0, (%si)
+ jnz L_SkipRecordBist
+
+// Record BIST information
+//
+ mov $8, %al
+ mul %bl
+ mov $BistBufferLocation, %si
+ add %ax, %si
+
+ movl $1, (%si) // Set Valid Flag
+ mov %ebp, 4(%si) // Store BIST value
+
+L_SkipRecordBist:
+// Switch to flat mode.
+
+ mov $BufferStartLocation, %si
+ mov (%si), %ebx
+
+ mov $PmodeOffsetLocation, %di
+ mov (%di), %eax
+ mov %ax, %di
+ sub $6, %di
+ add %ebx, %eax
+ mov %eax, (%di)
+
+ mov $0, %esi
+ mov $GdtrLocation, %si
+ lgdtl %cs:(%esi)
+
+ xor %ax, %ax
+ mov %ax, %ds
+
+ mov %cr0, %eax
+ or $0x00000003, %eax
+ mov %eax, %cr0
+
+ .byte 0x66, 0x67, 0xea // far jump
+ .long 0x00 // 32-bit offset
+ .short 0x20 // 16-bit selector
+
+ .code32
+L_NemInit: // protected mode entry point
+ mov $0x18, %ax
+ mov %ax, %ds
+ mov %ax, %es
+ mov %ax, %fs
+ mov %ax, %gs
+ mov %ax, %ss
+
+ mov %ebx, %esi
+
+ mov %esi, %edi
+ add $StartStateLocation, %edi
+ mov $1, %eax
+ movl %eax, (%edi)
+
+ mov %esi, %edi
+ add $LockLocation, %edi
+ mov $NotVacantFlag, %eax
+L_TestLock:
+ xchg %eax, (%edi)
+ cmp $NotVacantFlag, %eax
+ jz L_TestLock
+
+L_ProgramStack:
+
+ mov %esi, %edi
+ add $StackSizeLocation, %edi
+ mov (%edi), %eax
+ mov %esi, %edi
+ add $StackStartAddressLocation, %edi
+ add (%edi), %eax
+ mov %eax, %esp
+ movl %eax, (%edi)
+
+L_Releaselock:
+
+ mov $VacantFlag, %eax
+ mov %esi, %edi
+ add $LockLocation, %edi
+ xchg %eax, (%edi)
+
+L_CProcedureInvoke:
+
+ mov %esi, %edi
+ add $CArgumentLocation, %edi
+ mov (%edi), %eax
+ push %eax
+
+ mov %esi, %edi
+ add $CProcedureLocation, %edi
+ mov (%edi), %eax
+
+ call *%eax
+ add $4, %esp
+
+L_InterlockedIncrementFinishedCount:
+ mov %esi, %edi
+ add $FinishedCountAddressLocation, %edi
+ lock incl (%edi)
+
+1:
+ cli
+
+ hlt
+ jmp 1b
+
+
+//-------------------------------------------------------------------------------------
+// SemaphoreStartAddress
+//-------------------------------------------------------------------------------------
+
+L_SemaphoreStartAddress:
+ push %ebp
+ mov %esp, %ebp
+ mov 0x8(%ebp), %eax
+1:
+ cmpl $0, (%eax)
+ jz 1f
+
+ pause
+ jmp 1b
+
+1:
+ pop %ebp
+ ret
+
+//-------------------------------------------------------------------------------
+// AsmGetAddressMap
+//-------------------------------------------------------------------------------------
+.set L_NemInitOffset, L_NemInit - L_RendezvousFunnelProcStart
+.set L_SemaphoreOffset, L_SemaphoreStartAddress - L_RendezvousFunnelProcStart
+
+.globl ASM_PFX(AsmGetAddressMap)
+ASM_PFX(AsmGetAddressMap):
+ mov $L_RendezvousFunnelProcStart, %eax
+ ret
+
+
+//-------------------------------------------------------------------------------
+// AsmGetPmodeOffset
+//-------------------------------------------------------------------------------------
+.globl ASM_PFX(AsmGetPmodeOffset)
+ASM_PFX(AsmGetPmodeOffset):
+ mov $L_NemInitOffset, %eax
+ ret
+
+//-------------------------------------------------------------------------------
+// AsmGetSemaphoreCheckOffset
+//-------------------------------------------------------------------------------------
+.globl ASM_PFX(AsmGetSemaphoreCheckOffset)
+ASM_PFX(AsmGetSemaphoreCheckOffset):
+ mov $L_SemaphoreOffset, %eax
+ ret
+
+//-------------------------------------------------------------------------------------
+//AsmExchangeRole procedure follows. This procedure executed by current BSP, that is
+//about to become an AP. It switches it'stack with the current AP.
+//AsmExchangeRole (IN CPU_EXCHANGE_INFO *MyInfo, IN CPU_EXCHANGE_INFO *OthersInfo);
+//-------------------------------------------------------------------------------------
+#define CPU_SWITCH_STATE_IDLE 0
+#define CPU_SWITCH_STATE_STORED 1
+#define CPU_SWITCH_STATE_LOADED 2
+
+.globl ASM_PFX(AsmExchangeRole)
+ASM_PFX(AsmExchangeRole):
+ // DO NOT call other functions in this function, since 2 CPU may use 1 stack
+ // at the same time. If 1 CPU try to call a functiosn, stack will be corrupted.
+
+ pusha
+ mov %ebp, %esp
+
+
+ // esi contains MyInfo pointer
+ mov %ecx, %esi
+
+ // edi contains OthersInfo pointer
+ mov %edx, %edi
+
+ //Store EFLAGS, GDTR and IDTR regiter to stack
+ pushf
+ sgdt 8(%esi)
+ sidt 14(%esi)
+
+ // Store the its StackPointer
+ mov %esp, 4(%esi)
+
+ // update its switch state to STORED
+ movb $CPU_SWITCH_STATE_STORED, 1(%esi)
+ xchg %al, (%esi)
+
+L_WaitForOtherStored:
+ // wait until the other CPU finish storing its state
+ cmp $CPU_SWITCH_STATE_STORED, %edi
+ jb L_WaitForOtherStored
+
+ // Since another CPU already stored its state, load them
+ // load GDTR value
+ lgdt 8(%edi)
+
+ // load IDTR value
+ lidt 14(%edi)
+
+ // load its future StackPointer
+ mov 4(%edi), %esp
+
+ // update its switch state to LOADED
+ movb $CPU_SWITCH_STATE_LOADED, 1(%edi)
+ xchg %al, (%edi)
+
+L_WaitForOtherLoaded:
+ // wait until the other CPU finish loading new state,
+ // otherwise the data in stack may corrupt
+ cmp $CPU_SWITCH_STATE_LOADED, %esi
+ jb L_WaitForOtherLoaded
+
+ // since the other CPU already get the data it want, leave this procedure
+ popf
+
+ popa
+ ret
diff --git a/Silicon/BroxtonSoC/BroxtonSiPkg/Cpu/Library/Private/PeiMpServiceLib/Ia32/MpFuncs.asm b/Silicon/BroxtonSoC/BroxtonSiPkg/Cpu/Library/Private/PeiMpServiceLib/Ia32/MpFuncs.asm
new file mode 100644
index 0000000000..58a481d091
--- /dev/null
+++ b/Silicon/BroxtonSoC/BroxtonSiPkg/Cpu/Library/Private/PeiMpServiceLib/Ia32/MpFuncs.asm
@@ -0,0 +1,365 @@
+;; @file
+; This is the assembly code for MP support.
+;
+; Copyright (c) 1999 - 2016, Intel Corporation. All rights reserved.<BR>
+;
+; This program and the accompanying materials
+; are licensed and made available under the terms and conditions of the BSD License
+; which accompanies this distribution. The full text of the license may be found at
+; http://opensource.org/licenses/bsd-license.php.
+;
+; THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+; WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED
+;
+;;
+
+include MpEqu.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);
+
+.686p
+.model flat
+.code
+
+PAUSE32 MACRO
+ DB 0F3h
+ DB 090h
+ ENDM
+
+;-------------------------------------------------------------------------------
+; AsmAcquireMPLock (&Lock);
+;-------------------------------------------------------------------------------
+AsmAcquireMPLock PROC near C PUBLIC
+
+ pushad
+ mov ebp,esp
+
+ mov al, NotVacantFlag
+ mov ebx, dword ptr [ebp+24h]
+TryGetLock:
+ xchg al, byte ptr [ebx]
+ cmp al, VacantFlag
+ jz LockObtained
+
+ PAUSE32
+ jmp TryGetLock
+
+LockObtained:
+ popad
+ ret
+AsmAcquireMPLock ENDP
+
+;-------------------------------------------------------------------------------
+; AsmReleaseMPLock (&Lock);
+;-------------------------------------------------------------------------------------
+AsmReleaseMPLock PROC near C PUBLIC
+
+ pushad
+ mov ebp,esp
+
+ mov al, VacantFlag
+ mov ebx, dword ptr [ebp+24h]
+ xchg al, byte ptr [ebx]
+
+ popad
+ ret
+AsmReleaseMPLock ENDP
+
+RendezvousFunnelProc PROC PUBLIC
+RendezvousFunnelProcStart::
+
+;Step-1: Grab a lock. At this point CS = 0x(vv00) and ip= 0x0.
+ db 66h, 08bh, 0e8h ; mov ebp, eax
+ 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
+; Get APIC ID
+;
+ db 66h, 0B8h
+ dd 00000001h ; mov eax, 1
+ db 0Fh, 0A2h ; cpuid
+ db 66h, 0C1h, 0EBh, 18h ; shr ebx, 24
+ db 66h, 81h, 0E3h
+ dd 000000FFh ; and ebx, 0ffh ; EBX is APIC ID
+
+; If it is the first time AP wakes up, just record AP's BIST
+; Otherwise, switch to protected mode.
+
+ db 0BEh ; opcode of mov si, imm16
+ dw StartStateLocation ; mov si, StartState
+ db 66h, 83h, 3Ch, 00h ; cmp dword ptr [si], 0
+ db 75h ; opcode of jnz
+ db SkipRecordBist - ($ + 1) ; jnz SkipRecordBist
+
+; Record BIST information
+;
+ db 0B0h, 08h ; mov al, 8
+ db 0F6h, 0E3h ; mul bl
+
+ db 0BEh ; opcode of mov si, imm16
+ dw BistBufferLocation ; mov si, BistBufferLocation
+ db 03h, 0F0h ; add si, ax
+
+ db 66h, 0C7h, 04h
+ dd 00000001h ; mov dword ptr [si], 1 ; Set Valid Flag
+ db 66h, 89h, 6Ch, 04h ; mov dword ptr [si + 4], ebp ; Store BIST value
+
+SkipRecordBist::
+ db 0BEh ; opcode of mov si, mem16
+ dw BufferStartLocation ; mov si, BufferStartLocation
+ db 66h, 8Bh, 1Ch ; mov ebx,dword ptr [si]
+
+ db 0BFh ; opcode of mov di, mem16
+ dw PmodeOffsetLocation ; mov di, PmodeOffsetLocation
+ db 66h, 8Bh, 05h ; mov eax,dword ptr [di]
+ db 8Bh, 0F8h ; mov di, ax
+ db 83h, 0EFh,06h ; sub di, 06h
+ db 66h, 03h, 0C3h ; add eax, ebx
+ db 66h, 89h, 05h ; mov dword ptr [di],eax
+
+ db 0BEh ; opcode of mov si, mem16
+ dw GdtrLocation ; mov si, GdtrLocation
+ db 66h ; db 66h
+ db 2Eh, 0Fh, 01h, 14h ; lgdt fword ptr cs:[si]
+
+ db 0BEh ; opcode of mov si, mem16
+ dw IdtrLocation ; mov si, IdtrProfile
+ db 66h ; db 66h
+ db 2Eh, 0Fh, 01h, 1Ch ; lidt 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, 03h ; or eax, 000000003h ;Set PE bit (bit #0) & MP
+ db 0Fh, 22h, 0C0h ; mov cr0, eax
+
+ db 66h, 67h, 0EAh ; far jump
+ dd 0h ; 32-bit offset
+BspCS::
+ dw 00h ; 16-bit selector
+
+NemInit:: ; protected mode entry point
+
+ db 66h, 0B8h ; mov ax, 18h
+BspDS::
+ dw 00h
+ 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.
+
+ mov esi, ebx
+
+ mov edi, esi
+ add edi, StartStateLocation
+ mov eax, 1
+ mov dword ptr [edi], eax
+
+ mov edi, esi
+ add edi, LockLocation
+ mov eax, NotVacantFlag
+TestLock::
+ xchg dword ptr [edi], eax
+ cmp eax, NotVacantFlag
+ jz TestLock
+
+ProgramStack::
+
+ mov edi, esi
+ add edi, StackSizeLocation
+ mov eax, dword ptr [edi]
+ mov edi, esi
+ add edi, StackStartAddressLocation
+ add eax, dword ptr [edi]
+ mov esp, eax
+ mov dword ptr [edi], eax
+
+Releaselock::
+
+ mov eax, VacantFlag
+ mov edi, esi
+ add edi, LockLocation
+ xchg dword ptr [edi], eax
+
+CProcedureInvoke::
+
+ mov edi, esi
+ add edi, CArgumentLocation
+ mov eax, dword ptr [edi]
+ push eax
+
+ mov edi, esi
+ add edi, CProcedureLocation
+ mov eax, dword ptr [edi]
+
+
+ push ecx
+ push eax
+ push edx
+
+ mov ecx, 0121h
+ rdmsr
+ test eax, eax
+ jnz SkipAcpiTimerWA
+ mov eax, 00010408h ; Bit 16 is enable and 15:0 address
+ mov edx, 2FBA2E25h
+ wrmsr
+SkipAcpiTimerWA:
+ pop edx
+ pop eax
+ pop ecx
+
+
+ call eax
+ add esp, 4
+
+InterlockedIncrementFinishedCount::
+ mov edi, esi
+ add edi, FinishedCountAddressLocation
+ lock inc dword ptr [edi]
+ cli
+ hlt
+ jmp $-2
+
+RendezvousFunnelProc ENDP
+
+SemaphoreStartAddress PROC C, SemaphoreAddress:PTR DWORD
+ mov eax, SemaphoreAddress
+@@:
+ cmp dword ptr [eax], 0
+ jz @F
+
+ PAUSE32
+ jmp @B
+@@:
+ ret
+SemaphoreStartAddress ENDP
+
+RendezvousFunnelProcEnd::
+
+
+;-------------------------------------------------------------------------------------
+; AsmGetAddressMap (&AddressMap);
+;-------------------------------------------------------------------------------------
+AsmGetAddressMap PROC near C PUBLIC
+
+ mov eax, RendezvousFunnelProcStart
+ ret
+
+AsmGetAddressMap ENDP
+
+AsmGetPmodeOffset PROC near C PUBLIC
+
+ mov eax, NemInit - RendezvousFunnelProcStart
+ ret
+
+AsmGetPmodeOffset ENDP
+
+AsmGetSemaphoreCheckOffset PROC near C PUBLIC
+ mov eax, SemaphoreStartAddress - RendezvousFunnelProcStart
+ ret
+AsmGetSemaphoreCheckOffset ENDP
+
+AsmPatchRendezvousCode PROC near C PUBLIC
+ mov eax, dword ptr [esp + 4]
+ push esi
+ push edi
+ mov edi, eax
+ mov ax, cs
+ mov esi, edi
+ add esi, BspCS - RendezvousFunnelProcStart
+ mov word ptr [esi], ax
+ mov ax, ds
+ mov esi, edi
+ add esi, BspDS - RendezvousFunnelProcStart
+ mov word ptr [esi], ax
+ pop edi
+ pop esi
+ xor eax, eax
+ ret
+AsmPatchRendezvousCode ENDP
+
+;-------------------------------------------------------------------------------------
+;AsmExchangeRole procedure follows. This procedure executed by current BSP, that is
+;about to become an AP. It switches it'stack with the current AP.
+;AsmExchangeRole (IN CPU_EXCHANGE_INFO *MyInfo, IN CPU_EXCHANGE_INFO *OthersInfo);
+;-------------------------------------------------------------------------------------
+CPU_SWITCH_STATE_IDLE equ 0
+CPU_SWITCH_STATE_STORED equ 1
+CPU_SWITCH_STATE_LOADED equ 2
+
+AsmExchangeRole PROC near C PUBLIC
+ ; DO NOT call other functions in this function, since 2 CPU may use 1 stack
+ ; at the same time. If 1 CPU try to call a functiosn, stack will be corrupted.
+ pushad
+ mov ebp,esp
+
+ ; esi contains MyInfo pointer
+ mov esi, dword ptr [ebp+24h]
+
+ ; edi contains OthersInfo pointer
+ mov edi, dword ptr [ebp+28h]
+
+ ;Store EFLAGS, GDTR and IDTR regiter to stack
+ pushfd
+ sgdt fword ptr [esi+8]
+ sidt fword ptr [esi+14]
+
+ ; Store the its StackPointer
+ mov dword ptr [esi+4],esp
+
+ ; update its switch state to STORED
+ mov byte ptr [esi], CPU_SWITCH_STATE_STORED
+
+WaitForOtherStored::
+ ; wait until the other CPU finish storing its state
+ cmp byte ptr [edi], CPU_SWITCH_STATE_STORED
+ jz OtherStored
+ PAUSE32
+ jmp WaitForOtherStored
+
+OtherStored::
+ ; Since another CPU already stored its state, load them
+ ; load GDTR value
+ lgdt fword ptr [edi+8]
+
+ ; load IDTR value
+ lidt fword ptr [edi+14]
+
+ ; load its future StackPointer
+ mov esp, dword ptr [edi+4]
+
+ ; update the other CPU's switch state to LOADED
+ mov byte ptr [edi], CPU_SWITCH_STATE_LOADED
+
+WaitForOtherLoaded::
+ ; wait until the other CPU finish loading new state,
+ ; otherwise the data in stack may corrupt
+ cmp byte ptr [esi], CPU_SWITCH_STATE_LOADED
+ jz OtherLoaded
+ PAUSE32
+ jmp WaitForOtherLoaded
+
+OtherLoaded::
+ ; since the other CPU already get the data it want, leave this procedure
+ popfd
+
+ popad
+ ret
+AsmExchangeRole ENDP
+
+END
+
diff --git a/Silicon/BroxtonSoC/BroxtonSiPkg/Cpu/Library/Private/PeiMpServiceLib/Ia32/MpFuncs.nasm b/Silicon/BroxtonSoC/BroxtonSiPkg/Cpu/Library/Private/PeiMpServiceLib/Ia32/MpFuncs.nasm
new file mode 100644
index 0000000000..deb580b6bb
--- /dev/null
+++ b/Silicon/BroxtonSoC/BroxtonSiPkg/Cpu/Library/Private/PeiMpServiceLib/Ia32/MpFuncs.nasm
@@ -0,0 +1,361 @@
+;; @file
+; This is the assembly code for MP support.
+;
+; Copyright (c) 2005 - 2016, Intel Corporation. All rights reserved.<BR>
+;
+; This program and the accompanying materials
+; are licensed and made available under the terms and conditions of the BSD License
+; which accompanies this distribution. The full text of the license may be found at
+; http://opensource.org/licenses/bsd-license.php.
+;
+; THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+; WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED
+;
+;;
+
+%include "MpEquNasm.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);
+
+SECTION .text
+
+%macro PAUSE32 0
+ DB 0xF3
+ DB 0x90
+ %endmacro
+
+;-------------------------------------------------------------------------------
+; AsmAcquireMPLock (&Lock);
+;-------------------------------------------------------------------------------
+global ASM_PFX(AsmAcquireMPLock)
+ASM_PFX(AsmAcquireMPLock):
+
+ pushad
+ mov ebp,esp
+
+ mov al, NotVacantFlag
+ mov ebx, dword [ebp+0x24]
+L_TryGetLock:
+ xchg al, byte [ebx]
+ cmp al, VacantFlag
+ jz L_LockObtained
+
+ PAUSE32
+ jmp L_TryGetLock
+
+L_LockObtained:
+ popad
+ ret
+
+;-------------------------------------------------------------------------------
+; AsmReleaseMPLock (&Lock);
+;-------------------------------------------------------------------------------------
+global ASM_PFX(AsmReleaseMPLock)
+ASM_PFX(AsmReleaseMPLock):
+
+ pushad
+ mov ebp,esp
+
+ mov al, VacantFlag
+ mov ebx, dword [ebp+0x24]
+ xchg al, byte [ebx]
+
+ popad
+ ret
+
+global ASM_PFX(RendezvousFunnelProc)
+ASM_PFX(RendezvousFunnelProc):
+L_RendezvousFunnelProcStart:
+
+;Step-1: Grab a lock. At this point CS = 0x(vv00) and ip= 0x0.
+ db 0x66, 0x8b, 0xe8 ; mov ebp, eax
+ db 0x8c,0xc8 ; mov ax,cs
+ db 0x8e,0xd8 ; mov ds,ax
+ db 0x8e,0xc0 ; mov es,ax
+ db 0x8e,0xd0 ; mov ss,ax
+ db 0x33,0xc0 ; xor ax,ax
+ db 0x8e,0xe0 ; mov fs,ax
+ db 0x8e,0xe8 ; mov gs,ax
+; Get APIC ID
+;
+ db 0x66, 0xB8
+ dd 0x1 ; mov eax, 1
+ db 0xF, 0xA2 ; cpuid
+ db 0x66, 0xC1, 0xEB, 0x18 ; shr ebx, 24
+ db 0x66, 0x81, 0xE3
+ dd 0xFF ; and ebx, 0ffh ; EBX is APIC ID
+
+; If it is the first time AP wakes up, just record AP's BIST
+; Otherwise, switch to protected mode.
+
+ db 0xBE ; opcode of mov si, imm16
+ dw StartStateLocation ; mov si, StartState
+ db 0x66, 0x83, 0x3C, 0x0 ; cmp dword ptr [si], 0
+ db 0x75 ; opcode of jnz
+ db L_SkipRecordBist - ($ + 1) ; jnz SkipRecordBist
+
+; Record BIST information
+;
+ db 0xB0, 0x8 ; mov al, 8
+ db 0xF6, 0xE3 ; mul bl
+
+ db 0xBE ; opcode of mov si, imm16
+ dw BistBufferLocation ; mov si, BistBufferLocation
+ db 0x3, 0xF0 ; add si, ax
+
+ db 0x66, 0xC7, 0x4
+ dd 0x1 ; mov dword ptr [si], 1 ; Set Valid Flag
+ db 0x66, 0x89, 0x6C, 0x4 ; mov dword ptr [si + 4], ebp ; Store BIST value
+
+L_SkipRecordBist:
+ db 0xBE ; opcode of mov si, mem16
+ dw BufferStartLocation ; mov si, BufferStartLocation
+ db 0x66, 0x8B, 0x1C ; mov ebx,dword ptr [si]
+
+ db 0xBF ; opcode of mov di, mem16
+ dw PmodeOffsetLocation ; mov di, PmodeOffsetLocation
+ db 0x66, 0x8B, 0x5 ; mov eax,dword ptr [di]
+ db 0x8B, 0xF8 ; mov di, ax
+ db 0x83, 0xEF,0x6 ; sub di, 06h
+ db 0x66, 0x3, 0xC3 ; add eax, ebx
+ db 0x66, 0x89, 0x5 ; mov dword ptr [di],eax
+
+ db 0xBE ; opcode of mov si, mem16
+ dw GdtrLocation ; mov si, GdtrLocation
+ db 0x66 ; db 66h
+ db 0x2E, 0xF, 0x1, 0x14 ; lgdt fword ptr cs:[si]
+
+ db 0xBE ; opcode of mov si, mem16
+ dw IdtrLocation ; mov si, IdtrProfile
+ db 0x66 ; db 66h
+ db 0x2E, 0xF, 0x1, 0x1C ; lidt fword ptr cs:[si]
+
+ db 0x33, 0xC0 ; xor ax, ax
+ db 0x8E, 0xD8 ; mov ds, ax
+
+ db 0xF, 0x20, 0xC0 ; mov eax, cr0 ;Get control register 0
+ db 0x66, 0x83, 0xC8, 0x3 ; or eax, 000000003h ;Set PE bit (bit #0) & MP
+ db 0xF, 0x22, 0xC0 ; mov cr0, eax
+
+ db 0x66, 0x67, 0xEA ; far jump
+ dd 0x0 ; 32-bit offset
+BspCS:
+ dw 0x0 ; 16-bit selector
+
+L_NemInit: ; protected mode entry point
+
+ db 0x66, 0xB8 ; mov ax, 18h
+BspDS:
+ dw 0x0
+ db 0x66, 0x8E, 0xD8 ; mov ds, ax
+ db 0x66, 0x8E, 0xC0 ; mov es, ax
+ db 0x66, 0x8E, 0xE0 ; mov fs, ax
+ db 0x66, 0x8E, 0xE8 ; mov gs, ax
+ db 0x66, 0x8E, 0xD0 ; mov ss, ax ; Flat mode setup.
+
+ mov esi, ebx
+
+ mov edi, esi
+ add edi, StartStateLocation
+ mov eax, 1
+ mov dword [edi], eax
+
+ mov edi, esi
+ add edi, LockLocation
+ mov eax, NotVacantFlag
+L_TestLock:
+ xchg dword [edi], eax
+ cmp eax, NotVacantFlag
+ jz L_TestLock
+
+ProgramStack:
+
+ mov edi, esi
+ add edi, StackSizeLocation
+ mov eax, dword [edi]
+ mov edi, esi
+ add edi, StackStartAddressLocation
+ add eax, dword [edi]
+ mov esp, eax
+ mov dword [edi], eax
+
+L_Releaselock:
+
+ mov eax, VacantFlag
+ mov edi, esi
+ add edi, LockLocation
+ xchg dword [edi], eax
+
+L_CProcedureInvoke:
+
+ mov edi, esi
+ add edi, CArgumentLocation
+ mov eax, dword [edi]
+ push eax
+
+ mov edi, esi
+ add edi, CProcedureLocation
+ mov eax, dword [edi]
+
+;
+; reserved for SV_HOOKS START
+; itp.threads[n].msr(0x121, 0x2FBA2E2500010408)
+; WA for ACPI PM1 timer BXT 0 and 1
+ push ecx
+ push eax
+ push edx
+
+ mov ecx, 0x121
+ rdmsr
+ test eax, eax
+ jnz SkipAcpiTimerWA
+ mov eax, 0x10408 ; Bit 16 is enable and 15:0 address
+ mov edx, 0x2FBA2E25
+ wrmsr
+SkipAcpiTimerWA:
+ pop edx
+ pop eax
+ pop ecx
+;
+; Reserved for SV_HOOKS END
+
+ call eax
+ add esp, 4
+
+L_InterlockedIncrementFinishedCount:
+ mov edi, esi
+ add edi, FinishedCountAddressLocation
+ lock inc dword [edi]
+ cli
+ hlt
+ jmp $-2
+
+global ASM_PFX(SemaphoreStartAddress)
+ASM_PFX(SemaphoreStartAddress):
+ push ebp
+ mov ebp, esp
+ mov eax, dword [ebp + 0x8]
+.0:
+ cmp dword [eax], 0
+ jz .1
+
+ PAUSE32
+ jmp .0
+.1:
+ ret
+
+
+;-------------------------------------------------------------------------------------
+; AsmGetAddressMap (&AddressMap);
+;-------------------------------------------------------------------------------------
+global ASM_PFX(AsmGetAddressMap)
+ASM_PFX(AsmGetAddressMap):
+
+ mov eax, L_RendezvousFunnelProcStart
+ ret
+
+global ASM_PFX(AsmGetPmodeOffset)
+ASM_PFX(AsmGetPmodeOffset):
+
+ mov eax, L_NemInit - L_RendezvousFunnelProcStart
+ ret
+
+global ASM_PFX(AsmGetSemaphoreCheckOffset)
+ASM_PFX(AsmGetSemaphoreCheckOffset):
+ mov eax, SemaphoreStartAddress - L_RendezvousFunnelProcStart
+ ret
+
+global ASM_PFX(AsmPatchRendezvousCode)
+ASM_PFX(AsmPatchRendezvousCode):
+ mov eax, dword [esp + 4]
+ push esi
+ push edi
+ mov edi, eax
+ mov ax, cs
+ mov esi, edi
+ add esi, BspCS - L_RendezvousFunnelProcStart
+ mov word [esi], ax
+ mov ax, ds
+ mov esi, edi
+ add esi, BspDS - L_RendezvousFunnelProcStart
+ mov word [esi], ax
+ pop edi
+ pop esi
+ xor eax, eax
+ ret
+
+;-------------------------------------------------------------------------------------
+;AsmExchangeRole procedure follows. This procedure executed by current BSP, that is
+;about to become an AP. It switches it'stack with the current AP.
+;AsmExchangeRole (IN CPU_EXCHANGE_INFO *MyInfo, IN CPU_EXCHANGE_INFO *OthersInfo);
+;-------------------------------------------------------------------------------------
+%define CPU_SWITCH_STATE_IDLE 0
+%define CPU_SWITCH_STATE_STORED 1
+%define CPU_SWITCH_STATE_LOADED 2
+
+global ASM_PFX(AsmExchangeRole)
+ASM_PFX(AsmExchangeRole):
+ ; DO NOT call other functions in this function, since 2 CPU may use 1 stack
+ ; at the same time. If 1 CPU try to call a functiosn, stack will be corrupted.
+ pushad
+ mov ebp,esp
+
+ ; esi contains MyInfo pointer
+ mov esi, dword [ebp+0x24]
+
+ ; edi contains OthersInfo pointer
+ mov edi, dword [ebp+0x28]
+
+ ;Store EFLAGS, GDTR and IDTR regiter to stack
+ pushfd
+ sgdt [esi+8]
+ sidt [esi+14]
+
+ ; Store the its StackPointer
+ mov dword [esi+4],esp
+
+ ; update its switch state to STORED
+ mov byte [esi], CPU_SWITCH_STATE_STORED
+
+L_WaitForOtherStored:
+ ; wait until the other CPU finish storing its state
+ cmp byte [edi], CPU_SWITCH_STATE_STORED
+ jz L_OtherStored
+ PAUSE32
+ jmp L_WaitForOtherStored
+
+L_OtherStored:
+ ; Since another CPU already stored its state, load them
+ ; load GDTR value
+ lgdt [edi+8]
+
+ ; load IDTR value
+ lidt [edi+14]
+
+ ; load its future StackPointer
+ mov esp, dword [edi+4]
+
+ ; update the other CPU's switch state to LOADED
+ mov byte [edi], CPU_SWITCH_STATE_LOADED
+
+L_WaitForOtherLoaded:
+ ; wait until the other CPU finish loading new state,
+ ; otherwise the data in stack may corrupt
+ cmp byte [esi], CPU_SWITCH_STATE_LOADED
+ jz L_OtherLoaded
+ PAUSE32
+ jmp L_WaitForOtherLoaded
+
+L_OtherLoaded:
+ ; since the other CPU already get the data it want, leave this procedure
+ popfd
+
+ popad
+ ret
diff --git a/Silicon/BroxtonSoC/BroxtonSiPkg/Cpu/Library/Private/PeiMpServiceLib/Microcode.c b/Silicon/BroxtonSoC/BroxtonSiPkg/Cpu/Library/Private/PeiMpServiceLib/Microcode.c
new file mode 100644
index 0000000000..1b4a0b581e
--- /dev/null
+++ b/Silicon/BroxtonSoC/BroxtonSiPkg/Cpu/Library/Private/PeiMpServiceLib/Microcode.c
@@ -0,0 +1,221 @@
+/** @file
+ CPU microcode update library.
+
+ Copyright (c) 1999 - 2016, Intel Corporation. All rights reserved.<BR>
+
+ This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php.
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include <Private/Library/MpServiceLib.h>
+#include <CpuRegs.h>
+
+/**
+ Check if this is non-core processor - HT AP thread
+
+ @retval TRUE If this is HT AP thread
+ @retval FALSE If this is core thread
+
+**/
+BOOLEAN
+IsSecondaryThread (
+ VOID
+ )
+{
+ UINT32 ApicID;
+ EFI_CPUID_REGISTER CpuidRegisters;
+ UINT8 CpuCount;
+ UINT8 CoreCount;
+ UINT8 CpuPerCore;
+ UINT32 Mask;
+
+ ApicID = GetCpuApicId ();
+
+ AsmCpuid (
+ CPUID_VERSION_INFO,
+ &CpuidRegisters.RegEax,
+ &CpuidRegisters.RegEbx,
+ &CpuidRegisters.RegEcx,
+ &CpuidRegisters.RegEdx
+ );
+ if ((CpuidRegisters.RegEdx & 0x10000000) == 0) {
+ return FALSE;
+ }
+
+ CpuCount = (UINT8) ((CpuidRegisters.RegEbx >> 16) & 0xff);
+ if (CpuCount == 1) {
+ return FALSE;
+ }
+
+ AsmCpuid (
+ CPUID_SIGNATURE,
+ &CpuidRegisters.RegEax,
+ &CpuidRegisters.RegEbx,
+ &CpuidRegisters.RegEcx,
+ &CpuidRegisters.RegEdx
+ );
+ if (CpuidRegisters.RegEax > 3) {
+
+ CoreCount = GetMaxSupportedCoreCount ();
+ } else {
+ CoreCount = 1;
+ }
+ //
+ // Assumes there is symmetry across core boundary, i.e. each core within a package has the same number of logical processors
+ //
+ if (CpuCount == CoreCount) {
+ return FALSE;
+ }
+
+ CpuPerCore = CpuCount / CoreCount;
+
+ //
+ // Assume 1 Core has no more than 8 threads
+ //
+ if (CpuPerCore == 2) {
+ Mask = 0x1;
+ } else if (CpuPerCore <= 4) {
+ Mask = 0x3;
+ } else {
+ Mask = 0x7;
+ }
+
+ if ((ApicID & Mask) == 0) {
+ return FALSE;
+ } else {
+ return TRUE;
+ }
+}
+
+
+/**
+ Wait until all primary threads are done with the microcode load.
+
+ @param[in] ExchangeInfo Pointer to the exchange info buffer for output.
+
+**/
+VOID
+WaitForPrimaryThreadMcuUpdate (
+ IN MP_CPU_EXCHANGE_INFO *ExchangeInfo
+ )
+{
+ UINTN CoreNumber;
+
+ CoreNumber = (UINTN) ((RShiftU64 (AsmReadMsr64 (MSR_CORE_THREAD_COUNT), 16)) & 0xffff);
+ if (IsSecondaryThread ()) {
+ while (ExchangeInfo->McuLoadCount < CoreNumber) {
+ CpuPause ();
+ }
+ }
+}
+
+
+/**
+ This will load the microcode to the processors.
+
+ @param[in] MicrocodeEntryPoint The microcode update pointer
+ @param[in, out] Revision The current (before load this microcode update) microcode revision
+ as output parameter, the microcode revision after microcode update is loaded
+
+ @retval EFI_SUCCESS Microcode loaded
+ @retval EFI_LOAD_ERROR Microcode not loaded
+
+**/
+EFI_STATUS
+LoadMicrocode (
+ IN CPU_MICROCODE_HEADER *MicrocodeEntryPoint,
+ IN OUT UINT32 *Revision
+ )
+{
+ EFI_STATUS Status;
+ UINT32 NewRevision;
+
+ Status = EFI_SUCCESS;
+
+#ifdef EFI_DEBUG
+ if (IsBsp()) {
+ DEBUG ((DEBUG_INFO, "LoadMicrocode: Before load, revision = 0x%x\n", *Revision));
+ }
+#endif
+
+ //
+ // Load the Processor Microcode
+ //
+ AsmWriteMsr64 (
+ MSR_IA32_BIOS_UPDT_TRIG,
+ (UINT64) ((UINTN) MicrocodeEntryPoint + sizeof (CPU_MICROCODE_HEADER))
+ );
+
+ NewRevision = GetCpuUcodeRevision ();
+
+#ifdef EFI_DEBUG
+ if (IsBsp ()) {
+ DEBUG ((DEBUG_INFO, "LoadMicrocode: After load, revision = 0x%x\n", NewRevision));
+ }
+#endif
+
+ //
+ // Verify that the microcode has been loaded
+ //
+ if (NewRevision == *Revision) {
+ return EFI_LOAD_ERROR;
+ }
+ *Revision = MicrocodeEntryPoint->UpdateRevision;
+
+ return Status;
+}
+
+
+/**
+ This will check if the microcode address is valid for this processor, and if so, it will
+ load it to the processor.
+
+ @param[in] ExchangeInfo Pointer to the exchange info buffer for output.
+ @param[in] MicrocodeAddress The address of the microcode update binary (in memory).
+ @param[out] FailedRevision The microcode revision that fails to be loaded.
+
+ @retval EFI_SUCCESS A new microcode update is loaded.
+ @retval Other Due to some reason, no new microcode update is loaded.
+
+**/
+EFI_STATUS
+InitializeMicrocode (
+ IN MP_CPU_EXCHANGE_INFO *ExchangeInfo,
+ IN CPU_MICROCODE_HEADER *MicrocodeAddress,
+ OUT UINT32 *FailedRevision
+ )
+{
+ EFI_STATUS Status;
+ EFI_CPUID_REGISTER Cpuid;
+ UINT32 UcodeRevision;
+ ACPI_CPU_DATA *mAcpiCpuData;
+
+ Status = EFI_NOT_FOUND;
+
+ mAcpiCpuData = (ACPI_CPU_DATA *) (ExchangeInfo->AcpiCpuDataAddress);
+ AsmCpuid (
+ CPUID_VERSION_INFO,
+ &Cpuid.RegEax,
+ &Cpuid.RegEbx,
+ &Cpuid.RegEcx,
+ &Cpuid.RegEdx
+ );
+
+ WaitForPrimaryThreadMcuUpdate (ExchangeInfo);
+ UcodeRevision = GetCpuUcodeRevision ();
+
+ if (CheckMicrocode (Cpuid.RegEax, MicrocodeAddress, &UcodeRevision)) {
+ Status = LoadMicrocode (MicrocodeAddress, &UcodeRevision);
+ *FailedRevision = UcodeRevision;
+ }
+ InterlockedIncrement (&(ExchangeInfo->McuLoadCount));
+
+ return Status;
+}
+
diff --git a/Silicon/BroxtonSoC/BroxtonSiPkg/Cpu/Library/Private/PeiMpServiceLib/MpService.c b/Silicon/BroxtonSoC/BroxtonSiPkg/Cpu/Library/Private/PeiMpServiceLib/MpService.c
new file mode 100644
index 0000000000..55e38c632b
--- /dev/null
+++ b/Silicon/BroxtonSoC/BroxtonSiPkg/Cpu/Library/Private/PeiMpServiceLib/MpService.c
@@ -0,0 +1,1756 @@
+/** @file
+ PEIM to initialize multi-processor.
+
+ Copyright (c) 2013 - 2016, Intel Corporation. All rights reserved.<BR>
+
+ This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php.
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include <Private/Library/CpuCommonLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Ppi/MasterBootMode.h>
+#include <Library/HobLib.h>
+#include <Library/TimerLib.h>
+#include "MpService.h"
+#include <Ppi/CpuPolicy.h>
+#include <Private/CpuInitDataHob.h>
+#include <Features.h>
+#include <Library/CpuPolicyLib.h>
+#include <Library/PostCodeLib.h>
+#include <Library/MtrrLib.h>
+
+GLOBAL_REMOVE_IF_UNREFERENCED MP_CPU_RUNTIME_DATA *mMpCpuRuntimeData = NULL;
+GLOBAL_REMOVE_IF_UNREFERENCED MP_SYSTEM_DATA *mMpSystemData = NULL;
+GLOBAL_REMOVE_IF_UNREFERENCED SI_CPU_POLICY_PPI *mSiCpuPolicyPpi = NULL;
+GLOBAL_REMOVE_IF_UNREFERENCED CPU_CONFIG *mCpuConfig = NULL;
+GLOBAL_REMOVE_IF_UNREFERENCED CPU_CONFIG_PREMEM *mCpuConfigPreMem = NULL;
+GLOBAL_REMOVE_IF_UNREFERENCED POWER_MGMT_CONFIG *mPowerMgmtConfig = NULL;
+
+
+/**
+ This function handles CPU MP service task at the end of PEI
+
+ @param[in] PeiServices Pointer to PEI Services Table.
+ @param[in] NotifyDesc Pointer to the descriptor for the Notification event that
+ caused this function to execute.
+ @param[in] Ppi Pointer to the PPI data associated with this function.
+
+ @retval EFI_STATUS Always return EFI_SUCCESS
+
+**/
+STATIC
+EFI_STATUS
+CpuMpServiceAtEndOfPei (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDesc,
+ IN VOID *Ppi
+ );
+
+STATIC EFI_PEI_NOTIFY_DESCRIPTOR mCpuMpServiceNotifyDesc = {
+ (EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
+ &gEfiEndOfPeiSignalPpiGuid,
+ CpuMpServiceAtEndOfPei
+};
+
+
+/**
+ Allocate a temporary memory under 1MB for MP Init to perform INIT-SIPI.
+ This buffer also provides memory for stack/data to run MP routine.
+
+ @param[in] WakeUpBuffer - Return buffer location
+
+ @retval EFI_SUCCESS if ok to get a memory under 1MB for MP running.
+**/
+EFI_STATUS
+AllocateWakeUpBuffer (
+ OUT EFI_PHYSICAL_ADDRESS *WakeUpBuffer
+ )
+{
+ EFI_STATUS Status;
+
+ Status = EFI_SUCCESS;
+ *WakeUpBuffer = 0x58000;
+
+ return Status;
+}
+
+
+/**
+ Prepare Wakeup Buffer and stack for APs.
+
+ @param[in] WakeUpBuffer Pointer to the address of wakeup buffer for output.
+ @param[in] StackAddressStart Pointer to the stack address of APs for output.
+ @param[in] MaximumCPUsForThisSystem Maximum CPUs in this system.
+
+ @retval EFI_SUCCESS Memory successfully prepared for APs.
+ @retval Other Error occurred while allocating memory.
+
+**/
+EFI_STATUS
+PrepareMemoryForAPs (
+ OUT EFI_PHYSICAL_ADDRESS *WakeUpBuffer,
+ OUT VOID **StackAddressStart,
+ IN UINTN MaximumCPUsForThisSystem
+ )
+{
+ EFI_STATUS Status;
+
+ //
+ // Release All APs with a lock and wait for them to retire to rendezvous procedure.
+ // We need a page (4KB) of memory for IA-32 to use broadcast APIs, on a temporary basis.
+ //
+ Status = AllocateWakeUpBuffer (WakeUpBuffer);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Claim memory for AP stack
+ //
+ *StackAddressStart = AllocateRuntimePool (MaximumCPUsForThisSystem * STACK_SIZE_PER_PROC);
+
+ if (*StackAddressStart == NULL) {
+ FreePool (WakeUpBuffer);
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Prepare GDTR and IDTR for AP
+
+ @param[in] Gdtr The GDTR profile
+ @param[in] Idtr The IDTR profile
+
+ @retval EFI_STATUS Status returned by each sub-routine
+ @retval EFI_SUCCESS GDTR and IDTR has been prepared for AP
+
+**/
+EFI_STATUS
+PrepareGdtIdtForAP (
+ OUT IA32_DESCRIPTOR *Gdtr,
+ OUT IA32_DESCRIPTOR *Idtr
+ )
+{
+ INTERRUPT_GATE_DESCRIPTOR *IdtForAP;
+ SEGMENT_DESCRIPTOR *GdtForAP;
+ IA32_DESCRIPTOR IdtrForBSP;
+ IA32_DESCRIPTOR GdtrForBSP;
+ UINT16 *MceHandler;
+
+ //
+ // Get Global Descriptor Table Register(GDTR) descriptor
+ //
+ AsmReadGdtr (&GdtrForBSP);
+
+ //
+ // Get Interrupt Descriptor Table Register(IDTR) descriptor
+ //
+ AsmReadIdtr (&IdtrForBSP);
+
+ //
+ // Allocate reserved memory for IDT
+ //
+ IdtForAP = (INTERRUPT_GATE_DESCRIPTOR *) AllocateAlignedRuntimePages (EFI_SIZE_TO_PAGES (IdtrForBSP.Limit + 1), sizeof (INTERRUPT_GATE_DESCRIPTOR));
+ if (IdtForAP == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ //
+ // Allocate reserved memory for GDT
+ //
+ GdtForAP = (SEGMENT_DESCRIPTOR *) AllocateAlignedRuntimePages (EFI_SIZE_TO_PAGES (GdtrForBSP.Limit + 1), sizeof (SEGMENT_DESCRIPTOR));
+ if (GdtForAP == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ MceHandler = AllocateRuntimePool (SIZE_OF_MCE_HANDLER);
+ if (MceHandler == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ //
+ // MceHandler content: iret (opcode = 0xcf)
+ //
+ *MceHandler = 0xCF48;
+
+ CopyMem (GdtForAP, (VOID *) GdtrForBSP.Base, GdtrForBSP.Limit + 1);
+ CopyMem (IdtForAP, (VOID *) IdtrForBSP.Base, IdtrForBSP.Limit + 1);
+
+ IdtForAP[INTERRUPT_HANDLER_MACHINE_CHECK].Offset15To0 = (UINT16) (UINTN) MceHandler;
+ IdtForAP[INTERRUPT_HANDLER_MACHINE_CHECK].Offset31To16 = (UINT16) ((UINTN) MceHandler >> 16);
+
+ //
+ // Create Gdtr, IDTR profile
+ //
+ Gdtr->Base = (UINTN) GdtForAP;
+ Gdtr->Limit = GdtrForBSP.Limit;
+
+ Idtr->Base = (UINTN) IdtForAP;
+ Idtr->Limit = IdtrForBSP.Limit;
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Initialize CPU Data Hob
+
+ @retval EFI_SUCCESS The driver installes/initialized correctly.
+ @retval EFI_OUT_OF_RESOURCES Allocation of the hob failed.
+
+**/
+EFI_STATUS
+InitializeCpuDataHob (
+ VOID
+ )
+{
+ CPU_INIT_DATA_HOB *CpuInitDataHob;
+ CPU_CONFIG *CpuConfig;
+ POWER_MGMT_CONFIG *PowerMgmtConfig;
+ VOID *Hob;
+
+ PostCode (0xC3B);
+
+ //
+ // Initial cpu data into one hob, it will be used by MP CPU DXE.
+ //
+ CpuInitDataHob = AllocateRuntimeZeroPool (sizeof (CPU_INIT_DATA_HOB));
+ if (CpuInitDataHob == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ CpuConfig = &mMpCpuRuntimeData->CpuConfig;
+ PowerMgmtConfig = &mMpCpuRuntimeData->PowerMgmtConfig;
+
+ CopyMem (
+ (VOID *) (UINTN) PowerMgmtConfig,
+ (VOID *) (UINTN) mPowerMgmtConfig,
+ sizeof (POWER_MGMT_CONFIG)
+ );
+ CopyMem (
+ (VOID *) (UINTN) CpuConfig,
+ (VOID *) (UINTN) mCpuConfig,
+ sizeof (CPU_CONFIG)
+ );
+
+ CpuInitDataHob->CpuConfig = (EFI_PHYSICAL_ADDRESS) (UINTN) &mMpCpuRuntimeData->CpuConfig;
+ CpuInitDataHob->PowerMgmtConfig = (EFI_PHYSICAL_ADDRESS) (UINTN) &mMpCpuRuntimeData->PowerMgmtConfig;
+
+ CpuInitDataHob->MpData = (EFI_PHYSICAL_ADDRESS) (UINTN) &mMpCpuRuntimeData->AcpiCpuData;
+ CpuInitDataHob->FvidTable = (EFI_PHYSICAL_ADDRESS) (UINTN) &mMpCpuRuntimeData->FvidTable;
+
+ Hob = BuildGuidDataHob (
+ &gCpuInitDataHobGuid,
+ (VOID *) CpuInitDataHob,
+ (UINTN) sizeof (CPU_INIT_DATA_HOB)
+ );
+ ASSERT (Hob != NULL);
+
+ PostCode (0xC3E);
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Initialize multi-processor service.
+
+**/
+EFI_STATUS
+InitializeMpServices (
+ IN SI_CPU_POLICY_PPI *SiCpuPolicyPpi
+ )
+{
+ EFI_STATUS Status;
+ UINTN Index;
+ EFI_BOOT_MODE BootMode;
+ UINT64 *MtrrValues;
+ MP_CPU_EXCHANGE_INFO *ExchangeInfo;
+ VOID *StackAddressStart;
+ EFI_PHYSICAL_ADDRESS WakeUpBuffer;
+ MTRR_SETTINGS MtrrSetting;
+ UINT16 MaxEnabledThreadsPerCore;
+ UINT16 MaxEnabledCoresPerDie;
+ UINT16 MaxDiesPerPackage;
+ UINT16 MaxPackages;
+ UINTN MaximumCPUsForThisSystem;
+ UINT32 ResponseProcessorCount;
+
+ Status = PeiServicesGetBootMode (&BootMode);
+ DEBUG ((DEBUG_INFO, "InitializeMpServices: BootMode = %X\n", BootMode));
+ if ((Status == EFI_SUCCESS) && (BootMode == BOOT_ON_S3_RESUME)) {
+ return EFI_SUCCESS;
+ }
+
+ DEBUG ((DEBUG_INFO, "Set Cpu MP Service Environment entry point\n"));
+ PostCode (0xC20);
+
+ //
+ // Allocate MP data structure memory.
+ //
+ mMpCpuRuntimeData = (MP_CPU_RUNTIME_DATA *) AllocateRuntimeZeroPool (sizeof (MP_CPU_RUNTIME_DATA));
+ if (mMpCpuRuntimeData == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ //
+ // Initialize ACPI_CPU_DATA data
+ //
+ mMpCpuRuntimeData->AcpiCpuData.GdtrProfile = (EFI_PHYSICAL_ADDRESS) (UINTN) &mMpCpuRuntimeData->GdtrProfile;
+ mMpCpuRuntimeData->AcpiCpuData.IdtrProfile = (EFI_PHYSICAL_ADDRESS) (UINTN) &mMpCpuRuntimeData->IdtrProfile;
+ mMpCpuRuntimeData->AcpiCpuData.S3BootPath = FALSE;
+
+ mSiCpuPolicyPpi = SiCpuPolicyPpi;
+
+ Status = GetConfigBlock ((CONFIG_BLOCK_TABLE_HEADER *) SiCpuPolicyPpi, &gCpuConfigGuid , (VOID *)&mCpuConfig);
+ ASSERT_EFI_ERROR (Status);
+
+ Status = GetConfigBlock ((CONFIG_BLOCK_TABLE_HEADER *) SiCpuPolicyPpi, &gPowerMgmtConfigGuid , (VOID *)&mPowerMgmtConfig);
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Save the MTRR registers to global variables
+ //
+ MtrrValues = mMpCpuRuntimeData->MtrrValues;
+ ReadMtrrRegisters (MtrrValues);
+
+ //
+ // Get information on enabled threads, cores, dies and package for the CPU(s) on this platform
+ //
+ GetEnabledCount (
+ &MaxEnabledThreadsPerCore,
+ &MaxEnabledCoresPerDie,
+ &MaxDiesPerPackage,
+ &MaxPackages
+ );
+
+ //
+ // Get the total CPU count
+ //
+ MaximumCPUsForThisSystem = MaxEnabledThreadsPerCore * MaxEnabledCoresPerDie * MaxDiesPerPackage * MaxPackages;
+
+ //
+ // Prepare Wakeup Buffer and Stack for APs
+ //
+ Status = PrepareMemoryForAPs (
+ &WakeUpBuffer,
+ &StackAddressStart,
+ MaximumCPUsForThisSystem
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ DEBUG ((DEBUG_INFO, "Specify memory cacheable type as Write Back Start\n"));
+
+ //
+ // Set specify memory cacheable type as Write Back
+ //
+ Status = MtrrSetMemoryAttributeInMtrrSettings (
+ &MtrrSetting,
+ 0x50000,
+ 0x10000,
+ CacheWriteBack
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Fill MP Data
+ //
+ Status = FillMpData (
+ (UINTN) WakeUpBuffer,
+ StackAddressStart,
+ MaximumCPUsForThisSystem
+ );
+
+ ExchangeInfo = (MP_CPU_EXCHANGE_INFO *) (UINTN) (WakeUpBuffer + MP_CPU_EXCHANGE_INFO_OFFSET);
+
+ //
+ // Wake up all APs at the first time
+ //
+ WakeUpAPs (MtrrValues, (EFI_AP_PROCEDURE) InitialMpProcedure);
+
+ //
+ // Program XApic register
+ //
+ ProgramXApic (TRUE);
+
+ //
+ // Wait for all APs to complete
+ //
+ while (ExchangeInfo->FinishedCount < mMpCpuRuntimeData->AcpiCpuData.NumberOfCpus - 1) {
+ CpuPause ();
+ }
+
+ //
+ // Collect all APs BIST status
+ //
+ for (Index = 1, ResponseProcessorCount = 1; Index < MAXIMUM_CPU_NUMBER; Index++) {
+ if (ExchangeInfo->BistBuffer[Index].Number == 1) {
+ ExchangeInfo->BistBuffer[Index].Number = ResponseProcessorCount++;
+ }
+ }
+
+ //
+ // Switch BSP to Lowest Feature Processor (LFP)
+ //
+ Status = SwitchToLowestFeatureProcess ();
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Register notification for CPU MP service task at the End of PEI
+ //
+ Status = PeiServicesNotifyPpi (&mCpuMpServiceNotifyDesc);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ DEBUG ((DEBUG_INFO, "Cpu MP Service End\n"));
+ PostCode (0xC9F);
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Get general MP information
+
+ @param[in] NumberOfCpus Number of processors
+ @param[in] MaximumNumberOfCpus Max supported number of processors
+ @param[in] NumberOfEnabledCpus Number of processors enabled
+ @param[in] RendezvousIntNumber Number of Rendezvous procedure
+ @param[in] RendezvousProcLength Length of Rendezvous procedure
+
+ @retval EFI_SUCCESS Always return success
+
+**/
+EFI_STATUS
+EFIAPI
+GetGeneralMpInfo (
+ OUT UINTN *NumberOfCpus,
+ OUT UINTN *MaximumNumberOfCpus,
+ OUT UINTN *NumberOfEnabledCpus,
+ OUT UINTN *RendezvousIntNumber,
+ OUT UINTN *RendezvousProcLength
+ )
+{
+ UINTN Index;
+ CPU_DATA_BLOCK *CpuData;
+
+ if (NumberOfCpus) {
+ *NumberOfCpus = mMpSystemData->NumberOfCpus;
+ }
+
+ if (MaximumNumberOfCpus) {
+ *MaximumNumberOfCpus = mMpSystemData->MaximumCpusForThisSystem;
+ }
+
+ if (RendezvousProcLength) {
+ *RendezvousProcLength = RENDEZVOUS_PROC_LENGTH;
+ }
+
+ if (RendezvousIntNumber) {
+ *RendezvousIntNumber = 0;
+ }
+
+ if (NumberOfEnabledCpus) {
+ *NumberOfEnabledCpus = mMpSystemData->NumberOfCpus;
+ for (Index = 0; Index < mMpSystemData->NumberOfCpus; Index++) {
+ CpuData = &mMpSystemData->CpuData[Index];
+ if (mMpSystemData->EnableSecondaryCpu) {
+ if (CpuData->State != CPU_STATE_DISABLED) {
+ (*NumberOfEnabledCpus)++;
+ }
+ } else {
+ if (CpuData->State != CPU_STATE_DISABLED && !mMpSystemData->CpuData[Index].SecondaryCpu) {
+ (*NumberOfEnabledCpus)++;
+ }
+ }
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Get processor context
+
+ @param[in] CpuNumber Cpu number
+ @param[in] BufferLength Buffer length
+ @param[in] ProcessorContextBuffer Pointer to the buffer that will be updated
+
+ @retval EFI_INVALID_PARAMETER Buffer is NULL or CpuNumber our of range
+ @retval EFI_BUFFER_TOO_SMALL Buffer too small
+ @retval EFI_SUCCESS Got processor context successfully
+
+**/
+EFI_STATUS
+EFIAPI
+GetProcessorContext (
+ IN UINTN CpuNumber,
+ IN OUT UINTN *BufferLength,
+ IN OUT EFI_MP_PROC_CONTEXT *ProcessorContextBuffer
+ )
+{
+ EFI_MP_PROC_CONTEXT *ProcessorBuffer;
+ CPU_DATA_BLOCK *CpuData;
+
+ if (BufferLength == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (*BufferLength < sizeof (EFI_MP_PROC_CONTEXT)) {
+ *BufferLength = sizeof (EFI_MP_PROC_CONTEXT);
+ return EFI_BUFFER_TOO_SMALL;
+ }
+
+ if ((mMpSystemData->NumberOfCpus <= CpuNumber) || (ProcessorContextBuffer == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ CpuData = &mMpSystemData->CpuData[CpuNumber];
+
+ *BufferLength = sizeof (EFI_MP_PROC_CONTEXT);
+ ProcessorBuffer = ProcessorContextBuffer;
+
+ ProcessorBuffer->ApicID = CpuData->ApicID;
+
+ ProcessorBuffer->Enabled = TRUE;
+ if (!mMpSystemData->EnableSecondaryCpu) {
+ if (CpuData->SecondaryCpu) {
+ ProcessorBuffer->Enabled = FALSE;
+ }
+ }
+
+ if (CpuData->State == CPU_STATE_DISABLED) {
+ ProcessorBuffer->Enabled = FALSE;
+ }
+
+ if (CpuNumber == mMpSystemData->BSP) {
+ ProcessorBuffer->Designation = EfiCpuBSP;
+ } else {
+ ProcessorBuffer->Designation = EfiCpuAP;
+ }
+
+ ProcessorBuffer->Health.Flags = CpuData->Health;
+ ProcessorBuffer->Health.TestStatus = 0;
+
+ ProcessorBuffer->PackageNumber = CpuData->PhysicalLocation.Package;
+ ProcessorBuffer->NumberOfCores = CpuData->PhysicalLocation.Core;
+ ProcessorBuffer->NumberOfThreads = CpuData->PhysicalLocation.Thread;
+
+ ProcessorBuffer->ProcessorTestMask = 0;
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ MP Service to get specified application processor (AP)
+ to execute a caller-provided code stream.
+
+ @param[in] Function The procedure to be assigned to AP.
+ @param[in] CpuNumber Number of the specified processor.
+ @param[in] ProcArguments Argument for Procedure.
+
+ @retval EFI_INVALID_PARAMETER Procudure is NULL.
+ @retval EFI_INVALID_PARAMETER Number of CPU out of range, or it belongs to BSP.
+ @retval EFI_INVALID_PARAMETER Specified CPU is not idle.
+ @retval EFI_SUCCESS The AP has finished.
+ @retval EFI_TIMEOUT Time goes out before the AP has finished.
+
+**/
+EFI_STATUS
+EFIAPI
+StartupThisAP (
+ IN EFI_AP_PROCEDURE Function,
+ IN UINTN CpuNumber,
+ IN OUT VOID *ProcArguments OPTIONAL
+ )
+{
+ EFI_PHYSICAL_ADDRESS WakeUpBuffer;
+ MP_CPU_EXCHANGE_INFO *ExchangeInfo;
+ UINT64 *MtrrValues;
+
+ WakeUpBuffer = mMpCpuRuntimeData->AcpiCpuData.WakeUpBuffer;
+ MtrrValues = mMpCpuRuntimeData->MtrrValues;
+ ReadMtrrRegisters (MtrrValues);
+ ExchangeInfo = (MP_CPU_EXCHANGE_INFO *) (UINTN) (WakeUpBuffer + MP_CPU_EXCHANGE_INFO_OFFSET);
+ ExchangeInfo->Lock = 0;
+ ExchangeInfo->ApFunction = (UINT32) Function;
+ ExchangeInfo->ApArgument = (UINT32) ProcArguments;
+ ExchangeInfo->MtrrValuesAddress = (UINT32) MtrrValues;
+ ExchangeInfo->FinishedCount = (UINT32) 0;
+ ExchangeInfo->SerializeLock = (UINT32) 0;
+ ExchangeInfo->StartState = (UINT32) 0;
+ ExchangeInfo->StackStart = (UINTN) ((ACPI_CPU_DATA *) (ExchangeInfo->AcpiCpuDataAddress))->StackAddress;
+
+ //
+ // Send INIT IPI - SIPI to the AP
+ //
+ SendInterrupt (
+ BROADCAST_MODE_SPECIFY_CPU,
+ CpuNumber,
+ 0,
+ DELIVERY_MODE_INIT,
+ TRIGGER_MODE_EDGE,
+ TRUE
+ );
+
+ SendInterrupt (
+ BROADCAST_MODE_SPECIFY_CPU,
+ CpuNumber,
+ (UINT32) RShiftU64 (WakeUpBuffer, 12),
+ DELIVERY_MODE_SIPI,
+ TRIGGER_MODE_EDGE,
+ TRUE
+ );
+
+ //
+ // Wait for the AP to complete
+ //
+ while (ExchangeInfo->FinishedCount != 1) {
+ CpuPause ();
+ }
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Wake up all the application processors
+
+ @param[in] Function The procedure to be assigned to AP.
+ @param[in] ProcArguments Argument for Procedure.
+
+ @retval EFI_SUCCESS APs are successfully waked up
+
+**/
+EFI_STATUS
+StartupAllAps (
+ IN EFI_AP_PROCEDURE Function,
+ IN OUT VOID *ProcArguments OPTIONAL
+ )
+{
+ EFI_PHYSICAL_ADDRESS WakeUpBuffer;
+ MP_CPU_EXCHANGE_INFO *ExchangeInfo;
+ UINT64 *MtrrValues;
+ UINTN NumberOfCpus;
+
+ WakeUpBuffer = mMpCpuRuntimeData->AcpiCpuData.WakeUpBuffer;
+ MtrrValues = mMpCpuRuntimeData->MtrrValues;
+ ReadMtrrRegisters (MtrrValues);
+ ExchangeInfo = (MP_CPU_EXCHANGE_INFO *) (UINTN) (WakeUpBuffer + MP_CPU_EXCHANGE_INFO_OFFSET);
+ ExchangeInfo->Lock = 0;
+ ExchangeInfo->ApFunction = (UINT32) Function;
+ ExchangeInfo->ApArgument = (UINT32) ProcArguments;
+ ExchangeInfo->MtrrValuesAddress = (UINT32) MtrrValues;
+ ExchangeInfo->FinishedCount = (UINT32) 0;
+ ExchangeInfo->SerializeLock = (UINT32) 0;
+ ExchangeInfo->StackStart = (UINTN) ((ACPI_CPU_DATA *) (ExchangeInfo->AcpiCpuDataAddress))->StackAddress;
+ NumberOfCpus = ((ACPI_CPU_DATA *) (ExchangeInfo->AcpiCpuDataAddress))->NumberOfCpus;
+
+ //
+ // Send INIT IPI - SIPI to all APs
+ //
+ SendInterrupt (
+ BROADCAST_MODE_ALL_EXCLUDING_SELF,
+ 0,
+ 0,
+ DELIVERY_MODE_INIT,
+ TRIGGER_MODE_EDGE,
+ TRUE
+ );
+ MicroSecondDelay (10 * STALL_ONE_MILLI_SECOND); ///< 10ms
+
+ SendInterrupt (
+ BROADCAST_MODE_ALL_EXCLUDING_SELF,
+ 0,
+ (UINT32) RShiftU64 (WakeUpBuffer, 12),
+ DELIVERY_MODE_SIPI,
+ TRIGGER_MODE_EDGE,
+ TRUE
+ );
+ MicroSecondDelay (200 * STALL_ONE_MICRO_SECOND); ///< 200us
+
+ SendInterrupt (
+ BROADCAST_MODE_ALL_EXCLUDING_SELF,
+ 0,
+ (UINT32) RShiftU64 (WakeUpBuffer, 12),
+ DELIVERY_MODE_SIPI,
+ TRIGGER_MODE_EDGE,
+ TRUE
+ );
+
+ //
+ // Wait for all APs to complete
+ //
+ DEBUG ((DEBUG_INFO, "FinishedCount = %x, NumberOfCpus = %x\n", ExchangeInfo->FinishedCount, NumberOfCpus));
+ while (ExchangeInfo->FinishedCount < NumberOfCpus - 1) {
+ CpuPause ();
+ }
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ MP Service to makes the current BSP into an AP and then switches the
+ designated AP into the AP. This procedure is usually called after a CPU
+ test that has found that BSP is not healthy to continue it's responsbilities.
+
+ @param[in] CpuNumber The number of the specified AP.
+ @param[in] EnableOldBsp Whether to enable or disable the original BSP.
+
+ @retval EFI_INVALID_PARAMETER Number for Specified AP out of range.
+ @retval EFI_INVALID_PARAMETER Number of specified CPU belongs to BSP.
+ @retval EFI_NOT_READY Specified AP is not idle.
+ @retval EFI_SUCCESS BSP successfully switched.
+
+**/
+EFI_STATUS
+EFIAPI
+SwitchBsp (
+ IN UINTN CpuNumber,
+ IN BOOLEAN EnableOldBsp
+ )
+{
+ EFI_STATUS Status;
+ CPU_DATA_BLOCK *CpuData;
+ CPU_STATE CpuState;
+ UINT64 *MtrrValues;
+
+ MtrrValues = mMpCpuRuntimeData->MtrrValues;
+ ReadMtrrRegisters (MtrrValues);
+
+ //
+ // Check if the specified CPU number is valid
+ //
+ if (CpuNumber >= mMpSystemData->NumberOfCpus) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Check if the specified CPU is already BSP
+ //
+ if (CpuNumber == mMpSystemData->BSP) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ CpuData = &mMpSystemData->CpuData[CpuNumber];
+ if (CpuData->State != CPU_STATE_IDLE) {
+ return EFI_NOT_READY;
+ }
+
+ //
+ // Before send both BSP and AP to a procedure to exchange their roles,
+ // interrupt must be disabled. This is because during the exchange role
+ // process, 2 CPU may use 1 stack. If interrupt happens, the stack will
+ // be corrputed, since interrupt return address will be pushed to stack
+ // by hardware.
+ //
+ DisableInterrupts ();
+
+ //
+ // Unprogram virtual wire mode for the old BSP
+ //
+ ProgramXApic (FALSE);
+ SetApicBspBit (FALSE);
+
+ mMpSystemData->BspInfo.State = CPU_SWITCH_STATE_IDLE;
+ mMpSystemData->BspInfo.Lock = VacantFlag;
+ mMpSystemData->ApInfo.State = CPU_SWITCH_STATE_IDLE;
+ mMpSystemData->ApInfo.Lock = VacantFlag;
+
+ //
+ // Need to wakeUp AP (future BSP)
+ //
+ WakeUpAPs (MtrrValues, (EFI_AP_PROCEDURE) FutureBspProc);
+
+ AsmExchangeRole (&mMpSystemData->BspInfo, &mMpSystemData->ApInfo);
+
+ //
+ // The new BSP has come out. Since it carries the register value of the AP, need
+ // to pay attention to variable which are stored in registers (due to optimization)
+ //
+ SetApicBspBit (TRUE);
+ ProgramXApic (TRUE);
+
+ EnableInterrupts ();
+
+ CpuData = &mMpSystemData->CpuData[mMpSystemData->BSP];
+ while (TRUE) {
+ AsmAcquireMPLock (&CpuData->StateLock);
+ CpuState = CpuData->State;
+ AsmReleaseMPLock (&CpuData->StateLock);
+
+ if (CpuState == CPU_STATE_FINISHED) {
+ break;
+ }
+ }
+
+ Status = ChangeCpuState (mMpSystemData->BSP, EnableOldBsp, CPU_CAUSE_NOT_DISABLED);
+ mMpSystemData->BSP = CpuNumber;
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ This procedure enables Or disables APs.
+
+ @param[in] CpuNumber The number of the specified AP.
+ @param[in] NewApState Indicate new desired AP state
+ @param[in] HealthState If not NULL, it points to the value that specifies
+ the new health status of the AP. If it is NULL,
+ this parameter is ignored.
+
+ @retval EFI_INVALID_PARAMETER Input paramters were not correct.
+ @retval EFI_SUCCESS Function completed successfully.
+
+**/
+EFI_STATUS
+EFIAPI
+EnableDisableAp (
+ IN UINTN CpuNumber,
+ IN BOOLEAN NewApState,
+ IN EFI_MP_HEALTH *HealthState OPTIONAL
+ )
+{
+ CPU_DATA_BLOCK *CpuData;
+
+ //
+ // Check for valid input parameters.
+ //
+ if (CpuNumber >= mMpSystemData->NumberOfCpus || CpuNumber == mMpSystemData->BSP) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ CpuData = &mMpSystemData->CpuData[CpuNumber];
+
+ if (HealthState != NULL) {
+ CopyMem (&CpuData->Health, HealthState, sizeof (EFI_MP_HEALTH));
+ }
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ This procedure returns the calling CPU handle.
+
+ @dot
+ digraph G {
+ subgraph cluster_c0 {
+ node [shape = box];
+ b1[label="GetApicID ()" fontsize=12 style=filled color=lightblue];
+ b2[label="Index + 1" fontsize=12 style=filled color=lightblue];
+ b3[label="*CpuNumber = Index" fontsize=12 style=filled color=lightblue];
+
+ node [shape = ellipse];
+ e1[label="Start" fontsize=12 style=filled color=lightblue];
+ e2[label="End" fontsize=12 style=filled color=lightblue];
+
+ node [shape = diamond,style=filled,color=lightblue];
+ d1[label="Index < NumOfCpus" fontsize=12];
+ d2[label="Is ApicID equal to\n mMpSystemData->CpuData[Index].ApicID" fontsize=12];
+
+ label = "WhoAmI Flow"; fontsize=15; fontcolor=black; color=lightblue;
+ e1 -> b1
+ b1 -> d1
+ d1 -> d2 [label="Yes" fontsize=9]
+ d1 -> b3 [label="No" fontsize=9]
+ d2 -> b3 [label="Yes" fontsize=9]
+ d2 -> b2 [label="No" fontsize=9]
+ b2 -> d1
+ b3 -> e2
+
+ }
+ }
+ @enddot
+
+ @param[out] CpuNumber The number of the specified AP.
+
+ @retval EFI_SUCCESS Function completed successfully.
+
+**/
+EFI_STATUS
+EFIAPI
+WhoAmI (
+ OUT UINTN *CpuNumber
+ )
+{
+ UINTN ApicID;
+ UINTN NumOfCpus;
+ UINTN Index;
+
+ ApicID = GetCpuApicId ();
+ NumOfCpus = mMpSystemData->NumberOfCpus;
+
+ for (Index = 0; Index < NumOfCpus; Index++) {
+ if (ApicID == mMpSystemData->CpuData[Index].ApicID) {
+ break;
+ }
+ }
+ *CpuNumber = Index;
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ This function handles CPU MP service task at the end of PEI
+
+ @param[in] PeiServices Pointer to PEI Services Table.
+ @param[in] NotifyDesc Pointer to the descriptor for the Notification event that
+ caused this function to execute.
+ @param[in] Ppi Pointer to the PPI data associated with this function.
+
+ @retval EFI_STATUS Always return EFI_SUCCESS
+
+**/
+STATIC
+EFI_STATUS
+CpuMpServiceAtEndOfPei (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDesc,
+ IN VOID *Ppi
+ )
+{
+ EFI_STATUS Status;
+
+ //
+ // Send INIT IPI - to all APs
+ //
+ Status = SendInterrupt (
+ BROADCAST_MODE_ALL_EXCLUDING_SELF,
+ 0,
+ 0,
+ DELIVERY_MODE_INIT,
+ TRIGGER_MODE_EDGE,
+ TRUE
+ );
+
+ return Status;
+}
+
+
+/**
+ AP initialization
+
+**/
+VOID
+InitialMpProcedure (
+ VOID
+ )
+{
+ MP_CPU_EXCHANGE_INFO *ExchangeInfo;
+ UINT64 *MtrrValues;
+ EFI_CPUID_REGISTER CpuidRegisters;
+
+ AsmCpuid (
+ CPUID_VERSION_INFO,
+ &CpuidRegisters.RegEax,
+ &CpuidRegisters.RegEbx,
+ &CpuidRegisters.RegEcx,
+ &CpuidRegisters.RegEdx
+ );
+
+ ExchangeInfo = (MP_CPU_EXCHANGE_INFO *) (UINTN) (mMpCpuRuntimeData->AcpiCpuData.WakeUpBuffer + MP_CPU_EXCHANGE_INFO_OFFSET);
+
+ //
+ // Init XMM
+ //
+ XmmInit ();
+
+ MtrrValues = (UINT64 *)ExchangeInfo->MtrrValuesAddress;
+ ProgramXApic (FALSE);
+
+ MpMtrrSynchUp (MtrrValues);
+}
+
+
+/**
+ Get CPU platform features settings to fill MP data.
+
+ @param[in] WakeUpBuffer The address of wakeup buffer.
+ @param[in] StackAddressStart The start address of APs's stacks.
+ @param[in] MaximumCPUsForThisSystem Maximum CPUs in this system.
+
+ @retval EFI_SUCCESS Function successfully executed.
+ @retval Other Error occurred while allocating memory.
+
+**/
+EFI_STATUS
+EFIAPI
+FillMpData (
+ IN UINTN WakeUpBuffer,
+ IN VOID *StackAddressStart,
+ IN UINTN MaximumCPUsForThisSystem
+ )
+{
+ EFI_STATUS Status;
+ BOOLEAN HyperThreadingEnabled;
+
+ mMpSystemData = &mMpCpuRuntimeData->MpSystemData;
+
+ //
+ // First check if the MP data structures and AP rendezvous routine have been
+ // supplied by the PEIMs that executed in early boot stage.
+ //
+ //
+ // Clear the data structure area first.
+ //
+ ZeroMem (mMpSystemData, sizeof (MP_SYSTEM_DATA));
+ HyperThreadingEnabled = FALSE;
+
+ mMpCpuRuntimeData->AcpiCpuData.CpuPrivateData = (EFI_PHYSICAL_ADDRESS) (UINTN) (&mMpSystemData->S3DataPointer);
+ mMpCpuRuntimeData->AcpiCpuData.WakeUpBuffer = WakeUpBuffer;
+ mMpCpuRuntimeData->AcpiCpuData.NumberOfCpus = MaximumCPUsForThisSystem;
+ mMpCpuRuntimeData->AcpiCpuData.APState = HyperThreadingEnabled;
+ mMpCpuRuntimeData->AcpiCpuData.StackAddress = (EFI_PHYSICAL_ADDRESS) (UINTN) StackAddressStart;
+
+ Status = PrepareGdtIdtForAP (
+ (IA32_DESCRIPTOR *) (UINTN) mMpCpuRuntimeData->AcpiCpuData.GdtrProfile,
+ (IA32_DESCRIPTOR *) (UINTN) mMpCpuRuntimeData->AcpiCpuData.IdtrProfile
+ );
+
+ //
+ // First BSP fills and inits all known values, including it's own records.
+ //
+ mMpSystemData->ApSerializeLock = VacantFlag;
+ mMpSystemData->NumberOfCpus = MaximumCPUsForThisSystem;
+ mMpSystemData->EnableSecondaryCpu = HyperThreadingEnabled;
+
+ mMpSystemData->VmxEnable = (BOOLEAN) mCpuConfig->VmxEnable;
+ mMpSystemData->TxtEnable = (BOOLEAN) mCpuConfig->SmxEnable;
+ mMpSystemData->MonitorMwaitEnable = (BOOLEAN) mCpuConfig->MonitorMwaitEnable;
+ mMpSystemData->MachineCheckEnable = (BOOLEAN) mCpuConfig->MachineCheckEnable;
+ mMpSystemData->AesEnable = (BOOLEAN) mCpuConfig->AesEnable;
+ mMpSystemData->DebugInterfaceEnable = (BOOLEAN) mCpuConfig->DebugInterfaceEnable;
+ mMpSystemData->DebugInterfaceLockEnable = (BOOLEAN) mCpuConfig->DebugInterfaceLockEnable;
+
+ mMpSystemData->ProcTraceMemSize = mCpuConfig->ProcTraceMemSize;
+ mMpSystemData->ProcTraceEnable = (BOOLEAN) mCpuConfig->ProcTraceEnable;
+ mMpSystemData->ProcTraceOutputScheme = (UINT8) mCpuConfig->ProcTraceOutputScheme;
+ mMpSystemData->HyperThreadingEnable = (BOOLEAN) mCpuConfig->HyperThreading;
+
+ mMpSystemData->S3DataPointer.S3BootScriptTable = (UINT32) (UINTN) mMpSystemData->S3BootScriptTable;
+ mMpSystemData->S3DataPointer.S3BspMtrrTable = (UINT32) (UINTN) mMpSystemData->S3BspMtrrTable;
+
+ mMpSystemData->MaximumCpusForThisSystem = MaximumCPUsForThisSystem;
+
+ mMpSystemData->BSP = 0;
+
+ //
+ // Collect CPU_DATA_BLOCK for BSP. All APs call ones, too.
+ //
+ FillInProcessorInformation (TRUE, 0);
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Get CPU platform features settings to fill MP data.
+
+ @retval MP_SYSTEM_DATA* Return MpSystemData pointer.
+
+**/
+MP_SYSTEM_DATA *
+EFIAPI
+GetMpSystemData (
+ VOID
+ )
+{
+ EFI_PHYSICAL_ADDRESS WakeUpBuffer;
+ MP_CPU_EXCHANGE_INFO *ExchangeInfo;
+
+ WakeUpBuffer = 0x58000;
+ ExchangeInfo = (MP_CPU_EXCHANGE_INFO *) (UINTN) (WakeUpBuffer + MP_CPU_EXCHANGE_INFO_OFFSET);
+
+ return (MP_SYSTEM_DATA *) (VOID *) ExchangeInfo->MpSystemDataAddress;
+}
+
+
+/**
+ This function is called by all processors (both BSP and AP) once and collects MP related data.
+
+ @param[in] BSP TRUE if the CPU is BSP
+ @param[in] BistParam BIST (build-in self test) data for the processor. This data
+ is only valid for processors that are waked up for the 1ast
+ time in this CPU DXE driver.
+
+ @retval EFI_SUCCESS Data for the processor collected and filled in.
+
+**/
+EFI_STATUS
+FillInProcessorInformation (
+ IN BOOLEAN BSP,
+ IN UINT32 BistParam
+ )
+{
+ UINT32 Health;
+ UINT32 ApicID;
+ CPU_DATA_BLOCK *CpuData;
+ UINT32 BIST;
+ UINTN CpuNumber;
+ ACPI_CPU_DATA *AcpiCpuData;
+ MP_CPU_EXCHANGE_INFO *ExchangeInfo;
+
+ AcpiCpuData = &mMpCpuRuntimeData->AcpiCpuData;
+ ApicID = GetCpuApicId ();
+ BIST = 0;
+
+ if (BSP) {
+ CpuNumber = 0;
+ BIST = BistParam;
+ } else {
+ ExchangeInfo = (MP_CPU_EXCHANGE_INFO *) (UINTN) (AcpiCpuData->WakeUpBuffer + MP_CPU_EXCHANGE_INFO_OFFSET);
+ CpuNumber = ExchangeInfo->BistBuffer[ApicID].Number;
+ BIST = ExchangeInfo->BistBuffer[ApicID].BIST;
+ }
+
+ CpuData = &mMpSystemData->CpuData[CpuNumber];
+ CpuData->SecondaryCpu = IsSecondaryThread ();
+ CpuData->ApicID = ApicID;
+ CpuData->Procedure = NULL;
+ CpuData->Parameter = NULL;
+ CpuData->StateLock = VacantFlag;
+ CpuData->ProcedureLock = VacantFlag;
+ CpuData->State = CPU_STATE_IDLE;
+
+ Health = BIST;
+ if (Health > 0) {
+ CpuData->State = CPU_STATE_DISABLED;
+ mMpSystemData->DisableCause[CpuNumber] = CPU_CAUSE_SELFTEST_FAILURE;
+ } else {
+ mMpSystemData->DisableCause[CpuNumber] = CPU_CAUSE_NOT_DISABLED;
+ }
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Wake up all the application processors
+
+ @param[in] MtrrValues Pointer to a buffer which stored MTRR settings
+ @param[in] Function Pointer to AP Procedure Function
+
+ @retval EFI_SUCCESS APs are successfully waked up
+
+**/
+EFI_STATUS
+WakeUpAPs (
+ UINT64 *MtrrValues,
+ EFI_AP_PROCEDURE Function
+ )
+{
+ EFI_PHYSICAL_ADDRESS WakeUpBuffer;
+ MP_CPU_EXCHANGE_INFO *ExchangeInfo;
+ MP_CPU_S3_DATA_POINTER *CpuS3DataPtr;
+ ACPI_CPU_DATA *AcpiCpuData;
+
+ AcpiCpuData = &mMpCpuRuntimeData->AcpiCpuData;
+ WakeUpBuffer = AcpiCpuData->WakeUpBuffer;
+ CopyMem (
+ (VOID *) (UINTN) WakeUpBuffer,
+ AsmGetAddressMap (),
+ MP_CPU_EXCHANGE_INFO_OFFSET
+ );
+ AsmPatchRendezvousCode ((VOID *) (UINTN) WakeUpBuffer);
+
+ ExchangeInfo = (MP_CPU_EXCHANGE_INFO *) (UINTN) (WakeUpBuffer + MP_CPU_EXCHANGE_INFO_OFFSET);
+
+ ExchangeInfo->Lock = 0;
+ ExchangeInfo->StackStart = (UINTN) AcpiCpuData->StackAddress;
+ ExchangeInfo->StackSize = STACK_SIZE_PER_PROC;
+ ExchangeInfo->ApFunction = (UINT32) Function;
+ ExchangeInfo->ApArgument = 0;
+ ExchangeInfo->BufferStart = (UINT32) WakeUpBuffer;
+ ExchangeInfo->PmodeOffset = (UINT32) (AsmGetPmodeOffset ());
+ ExchangeInfo->SemaphoreCheck = (VOID (*)(UINT32 *)) (AsmGetSemaphoreCheckOffset () + (UINT32) WakeUpBuffer);
+ ExchangeInfo->AcpiCpuDataAddress = (UINT32) AcpiCpuData;
+ ExchangeInfo->MtrrValuesAddress = (UINT32) MtrrValues;
+ ExchangeInfo->FinishedCount = (UINT32) 0;
+ ExchangeInfo->SerializeLock = (UINT32) 0;
+ ExchangeInfo->StartState = (UINT32) 0;
+
+ CpuS3DataPtr = (MP_CPU_S3_DATA_POINTER *) (UINTN) AcpiCpuData->CpuPrivateData;
+ ExchangeInfo->S3BootScriptTable = (MP_CPU_S3_SCRIPT_DATA *) (UINTN) CpuS3DataPtr->S3BootScriptTable;
+ ExchangeInfo->VirtualWireMode = CpuS3DataPtr->VirtualWireMode;
+ ExchangeInfo->CpuPerfCtrlValue = AsmReadMsr64 (MSR_IA32_PERF_CTRL);
+ ExchangeInfo->McuLoadCount = 0;
+ ExchangeInfo->MpSystemDataAddress = (UINT32) &mMpCpuRuntimeData->MpSystemData;
+ ExchangeInfo->MpServicePpiAddress = 0;
+ ExchangeInfo->SiCpuPolicyPpi = mSiCpuPolicyPpi;
+
+ CopyMem (
+ (VOID *) (UINTN) &ExchangeInfo->GdtrProfile,
+ (VOID *) (UINTN) AcpiCpuData->GdtrProfile,
+ sizeof (IA32_DESCRIPTOR)
+ );
+ CopyMem (
+ (VOID *) (UINTN) &ExchangeInfo->IdtrProfile,
+ (VOID *) (UINTN) AcpiCpuData->IdtrProfile,
+ sizeof (IA32_DESCRIPTOR)
+ );
+
+ //
+ // Don't touch MPCPU private data
+ // Here we use ExchangeInfo instead
+ //
+ //
+ // Send INIT IPI - SIPI to all APs
+ //
+ SendInterrupt (
+ BROADCAST_MODE_ALL_EXCLUDING_SELF,
+ 0,
+ 0,
+ DELIVERY_MODE_INIT,
+ TRIGGER_MODE_EDGE,
+ TRUE
+ );
+
+ MicroSecondDelay (10 * STALL_ONE_MILLI_SECOND); //< 10ms
+
+ SendInterrupt (
+ BROADCAST_MODE_ALL_EXCLUDING_SELF,
+ 0,
+ (UINT32) RShiftU64 (WakeUpBuffer, 12),
+ DELIVERY_MODE_SIPI,
+ TRIGGER_MODE_EDGE,
+ TRUE
+ );
+
+ MicroSecondDelay (200 * STALL_ONE_MICRO_SECOND); //< 200us
+
+ SendInterrupt (
+ BROADCAST_MODE_ALL_EXCLUDING_SELF,
+ 0,
+ (UINT32) RShiftU64 (WakeUpBuffer, 12),
+ DELIVERY_MODE_SIPI,
+ TRIGGER_MODE_EDGE,
+ TRUE
+ );
+
+ MicroSecondDelay (200 * STALL_ONE_MICRO_SECOND); //< 200us
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Send interrupt to CPU
+
+ @param[in] BroadcastMode Interrupt broadcast mode
+ @param[in] ApicID APIC ID for sending interrupt
+ @param[in] VectorNumber Vector number
+ @param[in] DeliveryMode Interrupt delivery mode
+ @param[in] TriggerMode Interrupt trigger mode
+ @param[in] Assert Interrupt pin polarity
+
+ @retval EFI_INVALID_PARAMETER Input parameter not correct
+ @retval EFI_NOT_READY There was a pending interrupt
+ @retval EFI_SUCCESS Interrupt sent successfully
+
+**/
+EFI_STATUS
+SendInterrupt (
+ IN UINT32 BroadcastMode,
+ IN UINT32 ApicID,
+ IN UINT32 VectorNumber,
+ IN UINT32 DeliveryMode,
+ IN UINT32 TriggerMode,
+ IN BOOLEAN Assert
+ )
+{
+ UINT64 ApicBaseReg;
+ EFI_PHYSICAL_ADDRESS ApicBase;
+ UINT32 IcrLow;
+ UINT32 IcrHigh;
+
+ //
+ // Initialze ICR high dword, since P6 family processor needs
+ // the destination field to be 0x0F when it is a broadcast
+ //
+ IcrHigh = 0x0f000000;
+ IcrLow = VectorNumber | (DeliveryMode << 8);
+
+ if (TriggerMode == TRIGGER_MODE_LEVEL) {
+ IcrLow |= 0x8000;
+ }
+
+ if (Assert) {
+ IcrLow |= 0x4000;
+ }
+
+ switch (BroadcastMode) {
+ case BROADCAST_MODE_SPECIFY_CPU:
+ IcrHigh = ApicID << 24;
+ break;
+
+ case BROADCAST_MODE_ALL_INCLUDING_SELF:
+ IcrLow |= 0x80000;
+ break;
+
+ case BROADCAST_MODE_ALL_EXCLUDING_SELF:
+ IcrLow |= 0xC0000;
+ break;
+
+ default:
+ return EFI_INVALID_PARAMETER;
+ }
+
+ ApicBaseReg = AsmReadMsr64 (MSR_IA32_APIC_BASE);
+ ApicBase = ApicBaseReg & 0xffffff000ULL;
+
+ *(volatile UINT32 *) (UINTN) (ApicBase + APIC_REGISTER_ICR_HIGH_OFFSET) = IcrHigh;
+ *(volatile UINT32 *) (UINTN) (ApicBase + APIC_REGISTER_ICR_LOW_OFFSET) = IcrLow;
+
+ MicroSecondDelay (10 * STALL_ONE_MICRO_SECOND);
+
+ IcrLow = *(volatile UINT32 *) (UINTN) (ApicBase + APIC_REGISTER_ICR_LOW_OFFSET);
+ if (IcrLow & 0x1000) {
+ return EFI_NOT_READY;
+ }
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Switch BSP to the processor which has least features
+
+ @retval EFI_STATUS Status code returned from each sub-routines
+
+**/
+EFI_STATUS
+EFIAPI
+SwitchToLowestFeatureProcess (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ UINTN CurrentProcessor;
+
+ Status = WhoAmI (&CurrentProcessor);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ ReportStatusCode (
+ EFI_PROGRESS_CODE,
+ EFI_COMPUTING_UNIT_HOST_PROCESSOR | EFI_CU_HP_PC_BSP_SELECT
+ );
+
+ //
+ // Take current BSP as the least feature
+ //
+ UpdateProcessorInfo (CurrentProcessor, &mMpSystemData->LeastFeatureProcessor);
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Get processor feature
+
+ @param[in] Features Pointer to a buffer which stores feature information
+
+**/
+VOID
+EFIAPI
+GetProcessorFeatures (
+ IN UINT32 *Features
+ )
+{
+ EFI_CPUID_REGISTER CpuidRegisters;
+
+ AsmCpuid (
+ CPUID_VERSION_INFO,
+ &CpuidRegisters.RegEax,
+ &CpuidRegisters.RegEbx,
+ &CpuidRegisters.RegEcx,
+ &CpuidRegisters.RegEdx
+ );
+ Features[0] = CpuidRegisters.RegEcx;
+ Features[1] = CpuidRegisters.RegEdx;
+ AsmCpuid (
+ CPUID_EXTENDED_CPU_SIG,
+ &CpuidRegisters.RegEax,
+ &CpuidRegisters.RegEbx,
+ &CpuidRegisters.RegEcx,
+ &CpuidRegisters.RegEdx
+ );
+ Features[2] = CpuidRegisters.RegEax;
+ Features[3] = CpuidRegisters.RegEbx;
+ Features[4] = CpuidRegisters.RegEcx;
+ Features[5] = CpuidRegisters.RegEdx;
+
+ return;
+}
+
+
+/**
+ Find out the common features supported by all core/threads
+
+**/
+VOID
+EFIAPI
+GetProcessorCommonFeature (
+ VOID
+ )
+{
+ UINTN Index;
+ UINT32 Features[MAX_FEATURE_NUM];
+
+ GetProcessorFeatures (Features);
+ AsmAcquireMPLock (&mMpSystemData->Lock);
+
+ for (Index = 0; Index < MAX_FEATURE_NUM; Index++) {
+ mMpSystemData->LeastFeatureProcessor.Features[Index] &= Features[Index];
+ }
+ AsmReleaseMPLock (&mMpSystemData->Lock);
+}
+
+
+/**
+ Get the processor data with least features
+
+**/
+VOID
+EFIAPI
+GetProcessorWithLeastFeature (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ UINTN CurrentProcessor;
+ LEAST_FEATURE_PROC LeastFeatureProcessor;
+
+ Status = WhoAmI (&CurrentProcessor);
+ ASSERT_EFI_ERROR (Status);
+
+ GetProcessorFeatures (mMpSystemData->LeastFeatureProcessor.Features);
+ LeastFeatureProcessor.FeatureDelta = GetProcessorFeatureDelta (
+ LeastFeatureProcessor.Features,
+ mMpSystemData->LeastFeatureProcessor.Features
+ );
+
+ AsmAcquireMPLock (&mMpSystemData->Lock);
+ if (LeastFeatureProcessor.FeatureDelta < mMpSystemData->LeastFeatureProcessor.FeatureDelta) {
+ mMpSystemData->LeastFeatureProcessor.FeatureDelta = LeastFeatureProcessor.FeatureDelta;
+ UpdateProcessorInfo (CurrentProcessor, &mMpSystemData->LeastFeatureProcessor);
+ } else if (LeastFeatureProcessor.FeatureDelta == mMpSystemData->LeastFeatureProcessor.FeatureDelta) {
+ UpdateProcessorInfo (CurrentProcessor, &LeastFeatureProcessor);
+ if (LeastFeatureProcessor.Version < mMpSystemData->LeastFeatureProcessor.Version) {
+ UpdateProcessorInfo (CurrentProcessor, &mMpSystemData->LeastFeatureProcessor);
+ } else if (LeastFeatureProcessor.Version == mMpSystemData->LeastFeatureProcessor.Version) {
+ if (LeastFeatureProcessor.ApicId < mMpSystemData->LeastFeatureProcessor.ApicId) {
+ UpdateProcessorInfo (CurrentProcessor, &mMpSystemData->LeastFeatureProcessor);
+ }
+ }
+ }
+
+ AsmReleaseMPLock (&mMpSystemData->Lock);
+}
+
+
+/**
+ Extract CPU detail version infomation
+
+ @param[in] FamilyId FamilyId, including ExtendedFamilyId
+ @param[in] Model Model, including ExtendedModel
+ @param[in] SteppingId SteppingId
+ @param[in] Processor Processor
+
+**/
+VOID
+EFIAPI
+EfiCpuVersion (
+ IN OUT UINT16 *FamilyId, OPTIONAL
+ IN OUT UINT8 *Model, OPTIONAL
+ IN OUT UINT8 *SteppingId, OPTIONAL
+ IN OUT UINT8 *Processor OPTIONAL
+ )
+{
+ EFI_CPUID_REGISTER Register;
+ UINT8 TempFamilyId;
+
+ AsmCpuid (
+ CPUID_VERSION_INFO,
+ &Register.RegEax,
+ &Register.RegEbx,
+ &Register.RegEcx,
+ &Register.RegEdx
+ );
+
+ if (SteppingId != NULL) {
+ *SteppingId = (UINT8) (Register.RegEax & 0xF);
+ }
+
+ if (Processor != NULL) {
+ *Processor = (UINT8) ((Register.RegEax >> 12) & 0x3);
+ }
+
+ if (Model != NULL || FamilyId != NULL) {
+ TempFamilyId = (UINT8) ((Register.RegEax >> 8) & 0xF);
+
+ if (Model != NULL) {
+ *Model = (UINT8) ((Register.RegEax >> 4) & 0xF);
+ if (TempFamilyId == 0x6 || TempFamilyId == 0xF) {
+ *Model |= (Register.RegEax >> 12) & 0xF0;
+ }
+ }
+
+ if (FamilyId != NULL) {
+ *FamilyId = TempFamilyId;
+ if (TempFamilyId == 0xF) {
+ *FamilyId = *FamilyId + (UINT16) ((Register.RegEax >> 20) & 0xFF);
+ }
+ }
+ }
+}
+
+
+/**
+ Update some processor info into LEAST_FEATURE_PROC data structure.
+
+ @param[in] Index Indicate which processor calling this routine
+ @param[in] LeastFeatureProcessor The data structure that will be updated
+
+**/
+VOID
+EFIAPI
+UpdateProcessorInfo (
+ IN UINTN Index,
+ IN LEAST_FEATURE_PROC *LeastFeatureProcessor
+ )
+{
+ UINT16 FamilyId;
+ UINT8 Model;
+ UINT8 SteppingId;
+
+ EfiCpuVersion (&FamilyId, &Model, &SteppingId, NULL);
+ LeastFeatureProcessor->Index = Index;
+ LeastFeatureProcessor->ApicId = GetCpuApicId ();
+ LeastFeatureProcessor->Version = EfiMakeCpuVersion (FamilyId, Model, SteppingId);
+}
+
+
+/**
+ Get processor feature delta
+
+ @param[in] FeaturesInput Supported features for input processor
+ @param[in] CommonFeatures Supported features for processor (subset of FeaturesInput)
+
+ @retval The least of processor features
+
+**/
+UINT32
+EFIAPI
+GetProcessorFeatureDelta (
+ IN UINT32 *FeaturesInput,
+ IN UINT32 *CommonFeatures
+ )
+{
+ UINT32 Delta;
+ UINTN Index;
+
+ //
+ // CommonFeatures is the subset of FeaturesInput
+ //
+ Delta = 0;
+ for (Index = 0; Index < MAX_FEATURE_NUM; Index++) {
+ Delta += GetBitsNumberOfOne (FeaturesInput[Index] - CommonFeatures[Index]);
+ }
+
+ return 0;
+}
+
+
+/**
+ Calculate how many bits are one from given number
+
+ @param[in] Value Number that will be calculated bits
+
+ @retval Number of bits
+
+**/
+UINT32
+EFIAPI
+GetBitsNumberOfOne (
+ IN UINT32 Value
+ )
+{
+ UINT32 Result;
+
+ Result = 0;
+ while (Value) {
+ if (Value & 1) {
+ Result++;
+ }
+ Value >>= 1;
+ }
+
+ return Result;
+}
+
+
+/**
+ Write 64bits MSR with script
+
+ @param[in] Index MSR index that will be written
+ @param[in] Value Value written to MSR
+
+**/
+VOID
+AsmWriteMsr64WithScript (
+ IN UINT32 Index,
+ IN UINT64 Value
+ )
+{
+ AsmWriteMsr64 (Index, Value);
+ WriteMsr64ToScript (Index, Value);
+}
+
+/**
+ Write 64bits MSR to script
+
+ @param[in] Index MSR index that will be written
+ @param[in] Value Value written to MSR
+
+**/
+VOID
+WriteMsr64ToScript (
+ IN UINT32 Index,
+ IN UINT64 Value
+ )
+{
+ UINTN TableIndex;
+ MP_SYSTEM_DATA *MpSystemData;
+
+ MpSystemData = GetMpSystemData ();
+ if (MpSystemData == NULL) {
+ ASSERT (FALSE);
+ return;
+ }
+
+ //
+ // Save it into script
+ //
+ AsmAcquireMPLock (&MpSystemData->S3BootScriptLock);
+ TableIndex = MpSystemData->S3BootScriptCount++;
+ AsmReleaseMPLock (&MpSystemData->S3BootScriptLock);
+
+ ASSERT (TableIndex < MAX_CPU_S3_TABLE_SIZE - 1);
+ MpSystemData->S3BootScriptTable[TableIndex].ApicId = GetCpuApicId ();
+ MpSystemData->S3BootScriptTable[TableIndex].MsrIndex = Index;
+ MpSystemData->S3BootScriptTable[TableIndex].MsrValue = Value;
+}
+
+
+/**
+ Set APIC BSP bit
+
+ @param[in] Enable Enable as BSP or not
+
+ @retval EFI_SUCCESS Always return success
+
+**/
+EFI_STATUS
+SetApicBspBit (
+ IN BOOLEAN Enable
+ )
+{
+ UINT64 ApicBaseReg;
+
+ ApicBaseReg = AsmReadMsr64 (MSR_IA32_APIC_BASE);
+
+ if (Enable) {
+ ApicBaseReg |= 0x100;
+ } else {
+ ApicBaseReg &= 0xfffffffffffffe00;
+ }
+
+ AsmWriteMsr64 (MSR_IA32_APIC_BASE, ApicBaseReg);
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Switch current BSP processor to AP
+
+ @param[in] MPSystemData Pointer to the data structure containing MP related data
+
+**/
+VOID
+EFIAPI
+FutureBspProc (
+ VOID
+ )
+{
+ AsmExchangeRole (&mMpSystemData->ApInfo, &mMpSystemData->BspInfo);
+ return;
+}
+
+
+/**
+ Change CPU state
+
+ @param[in] CpuNumber CPU number
+ @param[in] NewState The new state that will be changed to
+ @param[in] Cause Cause
+
+ @retval EFI_SUCCESS Always return success
+
+**/
+EFI_STATUS
+ChangeCpuState (
+ IN UINTN CpuNumber,
+ IN BOOLEAN NewState,
+ IN CPU_STATE_CHANGE_CAUSE Cause
+ )
+{
+ CPU_DATA_BLOCK *CpuData;
+
+ CpuData = &mMpSystemData->CpuData[CpuNumber];
+
+ mMpSystemData->DisableCause[CpuNumber] = Cause;
+
+ if (!NewState) {
+ AsmAcquireMPLock (&CpuData->StateLock);
+ CpuData->State = CPU_STATE_DISABLED;
+ AsmReleaseMPLock (&CpuData->StateLock);
+
+ ReportStatusCode (
+ EFI_ERROR_MINOR | EFI_ERROR_CODE,
+ EFI_COMPUTING_UNIT_HOST_PROCESSOR | EFI_CU_EC_DISABLED
+ );
+ } else {
+ AsmAcquireMPLock (&CpuData->StateLock);
+ CpuData->State = CPU_STATE_IDLE;
+ AsmReleaseMPLock (&CpuData->StateLock);
+ }
+
+ return EFI_SUCCESS;
+}
+
diff --git a/Silicon/BroxtonSoC/BroxtonSiPkg/Cpu/Library/Private/PeiMpServiceLib/MpService.h b/Silicon/BroxtonSoC/BroxtonSiPkg/Cpu/Library/Private/PeiMpServiceLib/MpService.h
new file mode 100644
index 0000000000..16cd80e538
--- /dev/null
+++ b/Silicon/BroxtonSoC/BroxtonSiPkg/Cpu/Library/Private/PeiMpServiceLib/MpService.h
@@ -0,0 +1,211 @@
+/** @file
+ Some definitions for MP services Ppi.
+
+ Copyright (c) 2013 - 2016, Intel Corporation. All rights reserved.<BR>
+
+ This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php.
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef _MP_SERVICE_H_
+#define _MP_SERVICE_H_
+
+#include <Library/ReportStatusCodeLib.h>
+#include <Private/Library/MpServiceLib.h>
+
+///
+/// Combine f(FamilyId), m(Model), s(SteppingId) to a single 32 bit number
+///
+#define EfiMakeCpuVersion(f, m, s) (((UINT32) (f) << 16) | ((UINT32) (m) << 8) | ((UINT32) (s)))
+
+/**
+ Get CPU platform features settings to fill MP data.
+
+ @param[in] WakeUpBuffer The address of wakeup buffer.
+ @param[in] StackAddressStart The start address of APs's stacks.
+ @param[in] MaximumCPUsForThisSystem Maximum CPUs in this system.
+
+ @retval EFI_SUCCESS Function successfully executed.
+ @retval Other Error occurred while allocating memory.
+
+**/
+EFI_STATUS
+EFIAPI
+FillMpData (
+ IN UINTN WakeUpBuffer,
+ IN VOID *StackAddressStart,
+ IN UINTN MaximumCPUsForThisSystem
+ );
+
+/**
+ This function is called by all processors (both BSP and AP) once and collects MP related data
+
+ @param[in] BSP TRUE if the CPU is BSP
+ @param[in] BistParam BIST (build-in self test) data for the processor. This data
+ is only valid for processors that are waked up for the 1st
+ time in this CPU DXE driver.
+
+ @retval EFI_SUCCESS Data for the processor collected and filled in
+
+**/
+EFI_STATUS
+FillInProcessorInformation (
+ IN BOOLEAN BSP,
+ IN UINT32 BistParam
+ );
+
+/**
+ Notification function that gets called once permanent memory installed to take care
+ of MP CPU related activities in PEI phase
+
+ @param[in] PeiServices Indirect reference to the PEI Services Table
+ @param[in] NotifyDesc Pointer to the descriptor for the Notification event that
+ caused this function to execute.
+ @param[in] Ppi Pointer to the PPI data associated with this function.
+
+ @retval EFI_SUCCESS Multiple processors are intialized successfully
+
+**/
+EFI_STATUS
+InitializeMpSupport (
+ IN EFI_PEI_FILE_HANDLE FileHandle,
+ IN CONST EFI_PEI_SERVICES **PeiServices
+ );
+
+/**
+ Re-load microcode patch.
+
+ @retval EFI_SUCCESS Multiple processors re-load microcode patch
+
+**/
+EFI_STATUS
+ReloadMicrocode (
+ IN MP_CPU_EXCHANGE_INFO *ExchangeInfo
+ );
+
+/**
+ Get processor feature
+
+ @param[in] Features Pointer to a buffer which stores feature information
+
+**/
+VOID
+EFIAPI
+GetProcessorFeatures (
+ IN UINT32 *Features
+ );
+
+/**
+ Switch BSP to the processor which has least features
+
+ @retval EFI_STATUS Status code returned from each sub-routines
+
+**/
+EFI_STATUS
+EFIAPI
+SwitchToLowestFeatureProcess (
+ VOID
+ );
+
+/**
+ Find out the common features supported by all core/threads
+
+**/
+VOID
+EFIAPI
+GetProcessorCommonFeature (
+ VOID
+ );
+
+/**
+ Get the processor data with least features
+
+**/
+VOID
+EFIAPI
+GetProcessorWithLeastFeature (
+ VOID
+ );
+
+/**
+ Extract CPU detail version infomation
+
+ @param[in] FamilyId FamilyId, including ExtendedFamilyId
+ @param[in] Model Model, including ExtendedModel
+ @param[in] SteppingId SteppingId
+ @param[in] Processor Processor
+
+**/
+VOID
+EFIAPI
+EfiCpuVersion (
+ IN OUT UINT16 *FamilyId, OPTIONAL
+ IN OUT UINT8 *Model, OPTIONAL
+ IN OUT UINT8 *SteppingId, OPTIONAL
+ IN OUT UINT8 *Processor OPTIONAL
+ );
+
+/**
+ Update some processor info into LEAST_FEATURE_PROC data structure.
+
+ @param[in] Index Indicate which processor calling this routine
+ @param[in] LeastFeatureProcessor The data structure that will be updated
+
+**/
+VOID
+EFIAPI
+UpdateProcessorInfo (
+ IN UINTN Index,
+ IN LEAST_FEATURE_PROC *LeastFeatureProcessor
+ );
+
+/**
+ Get processor feature delta
+
+ @param[in] FeaturesInput Supported features for input processor
+ @param[in] CommonFeatures Supported features for processor (subset of FeaturesInput)
+
+ @retval The least of processor features
+
+**/
+UINT32
+EFIAPI
+GetProcessorFeatureDelta (
+ IN UINT32 *FeaturesInput,
+ IN UINT32 *CommonFeatures
+ );
+
+/**
+ Calculate how many bits are one from given number
+
+ @param[in] Value Number that will be calculated bits
+
+ @retval Number of bits
+
+**/
+UINT32
+EFIAPI
+GetBitsNumberOfOne (
+ IN UINT32 Value
+ );
+
+/**
+ Exchange 2 processors (BSP to AP or AP to BSP)
+
+ @param[in] MyInfo CPU info for current processor
+ @param[in] OthersInfo CPU info that will be exchanged with
+
+**/
+VOID
+AsmExchangeRole (
+ IN CPU_EXCHANGE_ROLE_INFO *MyInfo,
+ IN CPU_EXCHANGE_ROLE_INFO *OthersInfo
+ );
+#endif
+
diff --git a/Silicon/BroxtonSoC/BroxtonSiPkg/Cpu/Library/Private/PeiMpServiceLib/MtrrSync.c b/Silicon/BroxtonSoC/BroxtonSiPkg/Cpu/Library/Private/PeiMpServiceLib/MtrrSync.c
new file mode 100644
index 0000000000..5c33674367
--- /dev/null
+++ b/Silicon/BroxtonSoC/BroxtonSiPkg/Cpu/Library/Private/PeiMpServiceLib/MtrrSync.c
@@ -0,0 +1,273 @@
+/** @file
+ Synchronization of MTRRs on S3 boot path.
+
+ Copyright (c) 2005 - 2016, Intel Corporation. All rights reserved.<BR>
+
+ This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php.
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+///
+/// External include files do NOT need to be explicitly specified in real EDKII
+/// environment
+///
+#include "CpuAccess.h"
+#include <Private/Library/MpServiceLib.h>
+
+UINTN
+MpMtrrSynchUpEntry (
+ VOID
+ );
+
+VOID
+MpMtrrSynchUpExit (
+ UINTN Cr4
+ );
+
+GLOBAL_REMOVE_IF_UNREFERENCED UINT16 mFixedMtrrIndex[] = {
+ IA32_MTRR_FIX64K_00000,
+ IA32_MTRR_FIX16K_80000,
+ IA32_MTRR_FIX16K_A0000,
+ IA32_MTRR_FIX4K_C0000,
+ IA32_MTRR_FIX4K_C8000,
+ IA32_MTRR_FIX4K_D0000,
+ IA32_MTRR_FIX4K_D8000,
+ IA32_MTRR_FIX4K_E0000,
+ IA32_MTRR_FIX4K_E8000,
+ IA32_MTRR_FIX4K_F0000,
+ IA32_MTRR_FIX4K_F8000,
+};
+
+GLOBAL_REMOVE_IF_UNREFERENCED UINT16 mMtrrDefType[] = { CACHE_IA32_MTRR_DEF_TYPE };
+
+GLOBAL_REMOVE_IF_UNREFERENCED UINT16 mVariableMtrrIndex[] = {
+ CACHE_VARIABLE_MTRR_BASE,
+ CACHE_VARIABLE_MTRR_BASE + 1,
+ CACHE_VARIABLE_MTRR_BASE + 2,
+ CACHE_VARIABLE_MTRR_BASE + 3,
+ CACHE_VARIABLE_MTRR_BASE + 4,
+ CACHE_VARIABLE_MTRR_BASE + 5,
+ CACHE_VARIABLE_MTRR_BASE + 6,
+ CACHE_VARIABLE_MTRR_BASE + 7,
+ CACHE_VARIABLE_MTRR_BASE + 8,
+ CACHE_VARIABLE_MTRR_BASE + 9,
+ CACHE_VARIABLE_MTRR_BASE + 10,
+ CACHE_VARIABLE_MTRR_BASE + 11,
+ CACHE_VARIABLE_MTRR_BASE + 12,
+ CACHE_VARIABLE_MTRR_BASE + 13,
+ CACHE_VARIABLE_MTRR_BASE + 14,
+ CACHE_VARIABLE_MTRR_BASE + 15,
+ CACHE_VARIABLE_MTRR_BASE + 16,
+ CACHE_VARIABLE_MTRR_BASE + 17,
+ CACHE_VARIABLE_MTRR_BASE + 18,
+ CACHE_VARIABLE_MTRR_BASE + 19,
+ ///
+ /// CACHE_VARIABLE_MTRR_END,
+ ///
+};
+
+GLOBAL_REMOVE_IF_UNREFERENCED UINTN FixedMtrrNumber = sizeof (mFixedMtrrIndex) / sizeof (UINT16);
+GLOBAL_REMOVE_IF_UNREFERENCED UINTN MtrrDefTypeNumber = sizeof (mMtrrDefType) / sizeof (UINT16);
+
+/**
+ Save the MTRR registers to global variables
+
+ @param[in] MtrrValues Pointer to the buffer which stores MTRR settings
+
+**/
+VOID
+ReadMtrrRegisters (
+ IN UINT64 *MtrrValues
+ )
+{
+ UINT32 Index;
+ UINT32 VariableMtrrNumber;
+
+ //
+ // Read all Mtrrs
+ //
+ for (Index = 0; Index < FixedMtrrNumber; Index++) {
+ *MtrrValues = AsmReadMsr64 (mFixedMtrrIndex[Index]);
+ MtrrValues++;
+ }
+
+ for (Index = 0; Index < MtrrDefTypeNumber; Index++) {
+ *MtrrValues = AsmReadMsr64 (mMtrrDefType[Index]);
+ MtrrValues++;
+ }
+
+ VariableMtrrNumber = ((UINT32) (AsmReadMsr64 (IA32_MTRR_CAP) & B_IA32_MTRR_VARIABLE_SUPPORT));
+ if (VariableMtrrNumber > V_MAXIMUM_VARIABLE_MTRR_NUMBER) {
+ VariableMtrrNumber = V_MAXIMUM_VARIABLE_MTRR_NUMBER;
+ }
+ for (Index = 0; Index < VariableMtrrNumber * 2; Index++) {
+ *MtrrValues = AsmReadMsr64 (mVariableMtrrIndex[Index]);
+ MtrrValues++;
+ }
+
+ return;
+}
+
+
+/**
+ Synch up the MTRR values for all processors
+
+ @param[in] MtrrValues Pointer to the buffer which stores MTRR settings
+
+**/
+VOID
+MpMtrrSynchUp (
+ UINT64 *MtrrValues
+ )
+{
+ UINT32 Index;
+ UINT32 VariableMtrrNumber;
+ UINTN Cr4;
+ UINT64 *FixedMtrr;
+ UINT64 *MtrrDefType;
+ UINT64 *VariableMtrr;
+ UINT64 ValidMtrrAddressMask;
+ EFI_CPUID_REGISTER FeatureInfo;
+ EFI_CPUID_REGISTER FunctionInfo;
+ UINT8 PhysicalAddressBits;
+
+ //
+ // Get physical CPU MTRR width in case of difference from BSP
+ //
+ AsmCpuid (
+ CPUID_EXTENDED_FUNCTION,
+ &FunctionInfo.RegEax,
+ &FunctionInfo.RegEbx,
+ &FunctionInfo.RegEcx,
+ &FunctionInfo.RegEdx
+ );
+ PhysicalAddressBits = 36;
+ if (FunctionInfo.RegEax >= CPUID_VIR_PHY_ADDRESS_SIZE) {
+ AsmCpuid (
+ CPUID_VIR_PHY_ADDRESS_SIZE,
+ &FeatureInfo.RegEax,
+ &FeatureInfo.RegEbx,
+ &FeatureInfo.RegEcx,
+ &FeatureInfo.RegEdx
+ );
+ PhysicalAddressBits = (UINT8) FeatureInfo.RegEax;
+ }
+
+ ValidMtrrAddressMask = (LShiftU64 (1, PhysicalAddressBits) - 1) & 0xfffffffffffff000ULL;
+
+ FixedMtrr = MtrrValues;
+ MtrrDefType = MtrrValues + FixedMtrrNumber;
+ VariableMtrr = MtrrValues + FixedMtrrNumber + MtrrDefTypeNumber;
+
+ //
+ // ASM code to setup processor register before synching up the MTRRs
+ //
+ Cr4 = MpMtrrSynchUpEntry ();
+
+ //
+ // Disable Fixed Mtrrs
+ //
+ AsmWriteMsr64 (CACHE_IA32_MTRR_DEF_TYPE, MtrrDefType[0] & 0xFFFFF7FF);
+
+ //
+ // Update Fixed Mtrrs
+ //
+ for (Index = 0; Index < FixedMtrrNumber; Index++) {
+ AsmWriteMsr64 (mFixedMtrrIndex[Index], FixedMtrr[Index]);
+ }
+ //
+ // Synchup Base Variable Mtrr
+ //
+ VariableMtrrNumber = (UINT32) (AsmReadMsr64 (IA32_MTRR_CAP) & B_IA32_MTRR_VARIABLE_SUPPORT);
+ if (VariableMtrrNumber > V_MAXIMUM_VARIABLE_MTRR_NUMBER) {
+ VariableMtrrNumber = V_MAXIMUM_VARIABLE_MTRR_NUMBER;
+ }
+
+ for (Index = 0; Index < VariableMtrrNumber * 2; Index++) {
+ AsmWriteMsr64 (
+ mVariableMtrrIndex[Index],
+ (VariableMtrr[Index] & 0x0FFF) | (VariableMtrr[Index] & ValidMtrrAddressMask)
+ );
+ }
+ //
+ // Synchup def type Fixed Mtrrs
+ //
+ AsmWriteMsr64 (CACHE_IA32_MTRR_DEF_TYPE, MtrrDefType[0]);
+
+ //
+ // ASM code to setup processor register after synching up the MTRRs
+ //
+ MpMtrrSynchUpExit (Cr4);
+
+ return;
+}
+
+
+/**
+ Set MTRR registers
+
+ @param[in] MtrrArray Buffer with MTRR settings
+
+**/
+VOID
+SetMtrrRegisters (
+ IN EFI_MTRR_VALUES *MtrrArray
+ )
+{
+ UINT32 Index;
+ UINTN Cr4;
+
+ //
+ // ASM code to setup processor register before synching up the MTRRs
+ //
+ Cr4 = MpMtrrSynchUpEntry ();
+
+ Index = 0;
+ while ((MtrrArray[Index].Index != 0) && (MtrrArray[Index].Index >= CACHE_VARIABLE_MTRR_BASE)) {
+ AsmWriteMsr64 (MtrrArray[Index].Index, MtrrArray[Index].Value);
+ Index++;
+ }
+ //
+ // ASM code to setup processor register after synching up the MTRRs
+ //
+ MpMtrrSynchUpExit (Cr4);
+}
+
+
+#ifdef EFI_DEBUG
+/**
+ Print MTRR settings in debug build BIOS
+
+ @param[in] MtrrArray Buffer with MTRR settings
+**/
+VOID
+ShowMtrrRegisters (
+ IN EFI_MTRR_VALUES *MtrrArray
+ )
+{
+ UINT32 Index;
+
+ Index = 0;
+ while ((MtrrArray[Index].Index != 0) && (MtrrArray[Index].Index >= CACHE_VARIABLE_MTRR_BASE)) {
+ DEBUG ((DEBUG_INFO, "MTRR: MtrrArray Index = %x\n", Index));
+ DEBUG (
+ (DEBUG_INFO,
+ "MTRR: MtrrArray[%x].Index = %x MtrrArray[%x].Value = %x\n",
+ Index,
+ MtrrArray[Index].Index,
+ Index,
+ MtrrArray[Index].Value)
+ );
+ Index++;
+ }
+
+ DEBUG ((DEBUG_INFO, "MTRR: Total Index = %x\n", Index));
+}
+#endif
+
diff --git a/Silicon/BroxtonSoC/BroxtonSiPkg/Cpu/Library/Private/PeiMpServiceLib/PeiMpServiceLib.inf b/Silicon/BroxtonSoC/BroxtonSiPkg/Cpu/Library/Private/PeiMpServiceLib/PeiMpServiceLib.inf
new file mode 100644
index 0000000000..ef76dd49b5
--- /dev/null
+++ b/Silicon/BroxtonSoC/BroxtonSiPkg/Cpu/Library/Private/PeiMpServiceLib/PeiMpServiceLib.inf
@@ -0,0 +1,65 @@
+## @file
+# Component information file for CPU module.
+#
+# Copyright (c) 2014 - 2016, Intel Corporation. All rights reserved.<BR>
+#
+# This program and the accompanying materials
+# are licensed and made available under the terms and conditions of the BSD License
+# which accompanies this distribution. The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php.
+#
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010017
+ BASE_NAME = PeiMpServiceLib
+ FILE_GUID = 59E4C67A-59A8-4DEA-9072-F9CDB6CA3E2C
+ VERSION_STRING = 1.0
+ MODULE_TYPE = PEIM
+ LIBRARY_CLASS = MpServiceLib
+
+[BuildOptions]
+################################################################################
+#
+# Package Dependency Section - list of Package files that are required for
+# this module.
+#
+################################################################################
+
+
+[LibraryClasses]
+ HobLib
+ CpuPlatformLib
+ DebugLib
+ BaseLib
+ PeiServicesLib
+ BaseMemoryLib
+ SynchronizationLib
+ ReportStatusCodeLib
+ MemoryAllocationLib
+ TimerLib
+ PostCodeLib
+ MtrrLib
+
+[Packages]
+ MdePkg/MdePkg.dec
+ BroxtonSiPkg/BroxtonSiPkg.dec
+ BroxtonSiPkg/BroxtonSiPrivate.dec
+ UefiCpuPkg/UefiCpuPkg.dec
+
+[Sources]
+ MtrrSync.c
+ Microcode.c
+ MpService.c
+ Ia32/MpFuncs.asm|MSFT
+ Ia32/MpFuncs.nasm|GCC
+
+[Ppis]
+ gEfiEndOfPeiSignalPpiGuid ## NOTIFY
+
+[Guids]
+ gCpuInitDataHobGuid ## UNDEFINED
+ gMicroCodepointerGuid ## UNDEFINED