summaryrefslogtreecommitdiff
path: root/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic
diff options
context:
space:
mode:
authorGuo Mang <mang.guo@intel.com>2016-08-03 11:46:45 +0800
committerGuo Mang <mang.guo@intel.com>2016-08-04 10:33:10 +0800
commit9dfd62064d1d1a6344165febb44c7b0d0f3a6a1e (patch)
treee6734a38a607f96255aff50d13b92809779ff737 /BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic
parent177e76bd8e9a863b4bd06a95f0e7cb5e4851812f (diff)
downloadedk2-platforms-9dfd62064d1d1a6344165febb44c7b0d0f3a6a1e.tar.xz
BraswellPlatformPkg: Move IntelSiliconBasic to Common/Silicon/IntelSiliconBasic
Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Guo Mang <mang.guo@intel.com> Reviewed-by: David Wei <david.wei@intel.com>
Diffstat (limited to 'BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic')
-rw-r--r--BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/CpuInit/Cpu.c999
-rw-r--r--BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/CpuInit/CpuDataStruct.h121
-rw-r--r--BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/CpuInit/CpuDxe.h240
-rw-r--r--BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/CpuInit/CpuRegs.h410
-rw-r--r--BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/CpuInit/Exception.h71
-rw-r--r--BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/CpuInit/Ia32/CpuAsm.asm693
-rw-r--r--BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/CpuInit/Ia32/CpuAsm.s761
-rw-r--r--BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/CpuInit/Ia32/Exception.c337
-rw-r--r--BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/CpuInit/Ia32/Htequ.inc40
-rw-r--r--BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/CpuInit/Ia32/InitializeFpu.s72
-rw-r--r--BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/CpuInit/Ia32/MPFuncs32.asm426
-rw-r--r--BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/CpuInit/Ia32/MPFuncs32.s444
-rw-r--r--BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/CpuInit/Ia32/MemoryOperation.c380
-rw-r--r--BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/CpuInit/Ia32/MpCommon32.asm103
-rw-r--r--BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/CpuInit/Ia32/MpCommon32.s114
-rw-r--r--BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/CpuInit/Ia32/MpCpu.c90
-rw-r--r--BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/CpuInit/Ia32/MpProc.asm83
-rw-r--r--BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/CpuInit/Ia32/MpProc.s69
-rw-r--r--BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/CpuInit/Ia32/ProcessorDef.h56
-rw-r--r--BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/CpuInit/MemoryAttribute.c975
-rw-r--r--BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/CpuInit/MemoryAttribute.h136
-rw-r--r--BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/CpuInit/Microcode.c483
-rw-r--r--BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/CpuInit/MiscFuncs.c103
-rw-r--r--BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/CpuInit/MiscFuncs.h45
-rw-r--r--BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/CpuInit/MpCommon.c879
-rw-r--r--BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/CpuInit/MpCommon.h425
-rw-r--r--BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/CpuInit/MpCpu.inf143
-rw-r--r--BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/CpuInit/MpService.c1781
-rw-r--r--BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/CpuInit/MtrrSync.c233
-rw-r--r--BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/CpuInit/PlatformMpService.h636
-rw-r--r--BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/CpuInit/x64/Cpu.asm199
-rw-r--r--BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/CpuInit/x64/CpuAsm.asm462
-rw-r--r--BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/CpuInit/x64/CpuInitDxeGccDummy.c184
-rw-r--r--BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/CpuInit/x64/Exception.c319
-rw-r--r--BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/CpuInit/x64/Htequ.inc44
-rw-r--r--BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/CpuInit/x64/MemoryOperation.c718
-rw-r--r--BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/CpuInit/x64/MpCpu.c76
-rw-r--r--BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/CpuInit/x64/MpFuncs.asm604
-rw-r--r--BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/CpuInit/x64/PlatformCpuLib.h135
-rw-r--r--BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/CpuInit/x64/ProcessorDef.h57
-rw-r--r--BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/CpuInit/x64/VirtualMemory.h147
-rw-r--r--BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/Include/AcpiCpuData.h35
-rw-r--r--BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/Include/CpuHotPlugData.h35
-rw-r--r--BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/Include/Library/CpuConfigLib.h686
-rw-r--r--BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/Include/Library/SmmCpuPlatformHookLib.h107
-rw-r--r--BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/Include/Library/SocketLga775Lib.h314
-rw-r--r--BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/Include/Protocol/SmmCpuService.h209
-rw-r--r--BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/Include/Protocol/SmmCpuSync.h107
-rw-r--r--BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/Include/Protocol/SmmCpuSync2.h186
-rw-r--r--BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/Library/CpuConfigLib/CpuConfig.c961
-rw-r--r--BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/Library/CpuConfigLib/CpuConfig.h65
-rw-r--r--BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/Library/CpuConfigLib/CpuConfigLib.inf57
-rw-r--r--BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/Library/SmmCpuPlatformHookLibNull/SmmCpuPlatformHookLibNull.c109
-rw-r--r--BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/Library/SmmCpuPlatformHookLibNull/SmmCpuPlatformHookLibNull.inf45
-rw-r--r--BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/PciHostBridge/PciHostBridge.c1105
-rw-r--r--BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/PciHostBridge/PciHostBridge.h157
-rw-r--r--BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/PciHostBridge/PciHostBridge.inf82
-rw-r--r--BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/PciHostBridge/PciRootBridge.h155
-rw-r--r--BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/PciHostBridge/PciRootBridgeIo.c1459
-rw-r--r--BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/PiSmmCommunication/PiSmmCommunicationPei.c424
-rw-r--r--BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/PiSmmCommunication/PiSmmCommunicationPei.inf67
-rw-r--r--BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/PiSmmCommunication/PiSmmCommunicationPrivate.h31
-rw-r--r--BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/PiSmmCommunication/PiSmmCommunicationSmm.c288
-rw-r--r--BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/PiSmmCommunication/PiSmmCommunicationSmm.inf78
-rw-r--r--BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/PiSmmCpuDxeSmm/CpuS3.c435
-rw-r--r--BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/PiSmmCpuDxeSmm/CpuService.c484
-rw-r--r--BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/PiSmmCpuDxeSmm/CpuService.h198
-rw-r--r--BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/PiSmmCpuDxeSmm/Ia32/MpFuncs.S159
-rw-r--r--BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/PiSmmCpuDxeSmm/Ia32/MpFuncs.asm163
-rw-r--r--BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/PiSmmCpuDxeSmm/Ia32/PageTbl.c96
-rw-r--r--BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/PiSmmCpuDxeSmm/Ia32/Semaphore.c62
-rw-r--r--BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/PiSmmCpuDxeSmm/Ia32/SmiEntry.S153
-rw-r--r--BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/PiSmmCpuDxeSmm/Ia32/SmiEntry.asm156
-rw-r--r--BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/PiSmmCpuDxeSmm/Ia32/SmiException.S1172
-rw-r--r--BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/PiSmmCpuDxeSmm/Ia32/SmiException.asm858
-rw-r--r--BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/PiSmmCpuDxeSmm/Ia32/SmmInit.S94
-rw-r--r--BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/PiSmmCpuDxeSmm/Ia32/SmmInit.asm104
-rw-r--r--BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/PiSmmCpuDxeSmm/Ia32/SmmProfileArch.c66
-rw-r--r--BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/PiSmmCpuDxeSmm/Ia32/SmmProfileArch.h98
-rw-r--r--BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/PiSmmCpuDxeSmm/MpService.c1759
-rw-r--r--BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.c1596
-rw-r--r--BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.h780
-rw-r--r--BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.inf195
-rw-r--r--BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/PiSmmCpuDxeSmm/SmmFeatures.c492
-rw-r--r--BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/PiSmmCpuDxeSmm/SmmFeatures.h220
-rw-r--r--BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/PiSmmCpuDxeSmm/SmmProfile.c1369
-rw-r--r--BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/PiSmmCpuDxeSmm/SmmProfile.h76
-rw-r--r--BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/PiSmmCpuDxeSmm/SmmProfileInternal.h190
-rw-r--r--BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/PiSmmCpuDxeSmm/SyncTimer.c111
-rw-r--r--BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/PiSmmCpuDxeSmm/X64/MpFuncs.S198
-rw-r--r--BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/PiSmmCpuDxeSmm/X64/MpFuncs.asm201
-rw-r--r--BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/PiSmmCpuDxeSmm/X64/PageTbl.c647
-rw-r--r--BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/PiSmmCpuDxeSmm/X64/Semaphore.c104
-rw-r--r--BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/PiSmmCpuDxeSmm/X64/SmiEntry.S236
-rw-r--r--BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/PiSmmCpuDxeSmm/X64/SmiEntry.asm232
-rw-r--r--BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/PiSmmCpuDxeSmm/X64/SmiException.S822
-rw-r--r--BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/PiSmmCpuDxeSmm/X64/SmiException.asm504
-rw-r--r--BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/PiSmmCpuDxeSmm/X64/SmmInit.S123
-rw-r--r--BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/PiSmmCpuDxeSmm/X64/SmmInit.asm140
-rw-r--r--BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/PiSmmCpuDxeSmm/X64/SmmProfileArch.c302
-rw-r--r--BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/PiSmmCpuDxeSmm/X64/SmmProfileArch.h106
101 files changed, 35756 insertions, 0 deletions
diff --git a/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/CpuInit/Cpu.c b/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/CpuInit/Cpu.c
new file mode 100644
index 0000000000..e8ef367545
--- /dev/null
+++ b/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/CpuInit/Cpu.c
@@ -0,0 +1,999 @@
+/** @file
+ Cpu driver, which initializes CPU and implements CPU Architecture
+ Protocol as defined in Framework specification.
+
+ Copyright (c) 1999 - 2015, 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 "CpuDxe.h"
+#include "Exception.h"
+#include "MiscFuncs.h"
+#include "MemoryAttribute.h"
+#include <Library/IoLib.h>
+#include <Library/PcdLib.h>
+
+#define SAMPLE_TICK_COUNT 100
+
+extern UINT64 mValidMtrrAddressMask;
+extern UINT64 mValidMtrrBitsMask;
+extern EFI_CPU_MICROCODE_HEADER **mMicrocodePointerBuffer;
+
+VOID *mSmmBaseRegistration;
+EFI_METRONOME_ARCH_PROTOCOL *mMetronome;
+BOOLEAN mIsFlushingGCD = TRUE;
+UINT64 mCpuFrequency = 0;
+
+
+CONST UINT16 miFSBFrequencyTable[] = {
+ 83, // 83.4MHz
+ 100, // 100MHz
+ 133, // 133.4MHz
+ 116, // 116.5MHz
+ 83, // 83.3MHz
+ 100, // 100MHz
+ 133, // 133.3MHz
+ 116, // 116.7MHz
+
+ 80, // 80MHz
+ 93, // 93.3MHz
+ 90, // 90MHz
+ 88, // 88.9MHz
+ 87 // 87.5MHz
+};
+
+//
+// Function declarations
+//
+EFI_STATUS
+EFIAPI
+InitializeCpu (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ );
+
+EFI_STATUS
+PrepareMemory (
+ VOID
+ );
+
+EFI_STATUS
+EFIAPI
+FlushCpuDataCache (
+ IN EFI_CPU_ARCH_PROTOCOL *This,
+ IN EFI_PHYSICAL_ADDRESS Start,
+ IN UINT64 Length,
+ IN EFI_CPU_FLUSH_TYPE FlushType
+ );
+
+EFI_STATUS
+EFIAPI
+EnableInterrupt (
+ IN EFI_CPU_ARCH_PROTOCOL *This
+ );
+
+EFI_STATUS
+EFIAPI
+DisableInterrupt (
+ IN EFI_CPU_ARCH_PROTOCOL *This
+ );
+
+EFI_STATUS
+EFIAPI
+CpuGetInterruptState (
+ IN EFI_CPU_ARCH_PROTOCOL *This,
+ OUT BOOLEAN *State
+ );
+
+EFI_STATUS
+EFIAPI
+Init (
+ IN EFI_CPU_ARCH_PROTOCOL *This,
+ IN EFI_CPU_INIT_TYPE InitType
+ );
+
+EFI_STATUS
+EFIAPI
+RegisterInterruptHandler (
+ IN EFI_CPU_ARCH_PROTOCOL *This,
+ IN EFI_EXCEPTION_TYPE InterruptType,
+ IN EFI_CPU_INTERRUPT_HANDLER InterruptHandler
+ );
+
+EFI_STATUS
+EFIAPI
+GetTimerValue (
+ IN EFI_CPU_ARCH_PROTOCOL *This,
+ IN UINT32 TimerIndex,
+ OUT UINT64 *TimerValue,
+ OUT UINT64 *TimerPeriod OPTIONAL
+ );
+
+EFI_STATUS
+EFIAPI
+SetMemoryAttributes (
+ IN EFI_CPU_ARCH_PROTOCOL *This,
+ IN EFI_PHYSICAL_ADDRESS BaseAddress,
+ IN UINT64 Length,
+ IN UINT64 Attributes
+ );
+
+//
+// Global Variables
+//
+EFI_CPU_INTERRUPT_HANDLER mExternalVectorTable[0x100];
+
+BOOLEAN mInterruptState = FALSE;
+
+//
+// The Cpu Architectural Protocol that this Driver produces
+//
+EFI_CPU_ARCH_PROTOCOL gCpu = {
+ FlushCpuDataCache,
+ EnableInterrupt,
+ DisableInterrupt,
+ CpuGetInterruptState,
+ Init,
+ RegisterInterruptHandler,
+ GetTimerValue,
+ SetMemoryAttributes,
+ 1, // NumberOfTimers
+ 4, // DmaBufferAlignment
+};
+
+/**
+ Flush CPU data cache. If the instruction cache is fully coherent
+ with all DMA operations then function can just return EFI_SUCCESS.
+
+ @param[in] This Protocol instance structure
+ @param[in] Start Physical address to start flushing from.
+ @param[in] Length Number of bytes to flush. Round up to chipset granularity.
+ @param[in] FlushType Specifies the type of flush operation to perform.
+
+ @retval EFI_SUCCESS If cache was flushed
+ @retval EFI_UNSUPPORTED If flush type is not supported.
+ @retval EFI_DEVICE_ERROR If requested range could not be flushed.
+
+**/
+EFI_STATUS
+EFIAPI
+FlushCpuDataCache (
+ IN EFI_CPU_ARCH_PROTOCOL *This,
+ IN EFI_PHYSICAL_ADDRESS Start,
+ IN UINT64 Length,
+ IN EFI_CPU_FLUSH_TYPE FlushType
+ )
+{
+ if (FlushType == EfiCpuFlushTypeWriteBackInvalidate) {
+ AsmWbinvd ();
+ return EFI_SUCCESS;
+ } else if (FlushType == EfiCpuFlushTypeInvalidate) {
+ AsmInvd ();
+ return EFI_SUCCESS;
+ } else {
+ return EFI_UNSUPPORTED;
+ }
+}
+
+/**
+ Enables CPU interrupts.
+
+ @param[in] This Protocol instance structure
+
+ @retval EFI_SUCCESS If interrupts were enabled in the CPU
+ @retval EFI_DEVICE_ERROR If interrupts could not be enabled on the CPU.
+
+**/
+EFI_STATUS
+EFIAPI
+EnableInterrupt (
+ IN EFI_CPU_ARCH_PROTOCOL *This
+ )
+{
+ CpuEnableInterrupt ();
+ mInterruptState = TRUE;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Disables CPU interrupts.
+
+ @param[in] This Protocol instance structure
+
+ @retval EFI_SUCCESS If interrupts were disabled in the CPU.
+ @retval EFI_DEVICE_ERROR If interrupts could not be disabled on the CPU.
+
+**/
+EFI_STATUS
+EFIAPI
+DisableInterrupt (
+ IN EFI_CPU_ARCH_PROTOCOL *This
+ )
+{
+ CpuDisableInterrupt ();
+ mInterruptState = FALSE;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Return the state of interrupts.
+
+ @param[in] This Protocol instance structure
+ @param[out] State Pointer to the CPU's current interrupt state
+
+ @retval EFI_SUCCESS If interrupts were disabled in the CPU.
+ @retval EFI_INVALID_PARAMETER State is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+CpuGetInterruptState (
+ IN EFI_CPU_ARCH_PROTOCOL *This,
+ OUT BOOLEAN *State
+ )
+{
+ if (State == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ *State = mInterruptState;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Generates an INIT to the CPU
+
+ @param[in] This Protocol instance structure
+ @param[in] InitType Type of CPU INIT to perform
+
+ @retval EFI_SUCCESS If CPU INIT occurred. This value should never be seen.
+ @retval EFI_DEVICE_ERROR If CPU INIT failed.
+ @retval EFI_UNSUPPORTED Requested type of CPU INIT not supported.
+
+**/
+EFI_STATUS
+EFIAPI
+Init (
+ IN EFI_CPU_ARCH_PROTOCOL *This,
+ IN EFI_CPU_INIT_TYPE InitType
+ )
+{
+ return EFI_UNSUPPORTED;
+}
+
+/**
+ Registers a function to be called from the CPU interrupt handler.
+
+ @param[in] This Protocol instance structure
+ @param[in] InterruptType Defines which interrupt to hook. IA-32 valid range
+ is 0x00 through 0xFF
+ @param[in] InterruptHandler A pointer to a function of type
+ EFI_CPU_INTERRUPT_HANDLER that is called when a
+ processor interrupt occurs. A null pointer
+ is an error condition.
+
+ @retval EFI_SUCCESS If handler installed or uninstalled.
+
+ @retval EFI_ALREADY_STARTED InterruptHandler is not NULL, and a handler for
+ InterruptType was previously installed
+
+ @retval EFI_INVALID_PARAMETER InterruptHandler is NULL, and a handler for
+ InterruptType was not previously installed.
+
+ @retval EFI_UNSUPPORTED The interrupt specified by InterruptType is not
+ supported.
+
+**/
+EFI_STATUS
+EFIAPI
+RegisterInterruptHandler (
+ IN EFI_CPU_ARCH_PROTOCOL *This,
+ IN EFI_EXCEPTION_TYPE InterruptType,
+ IN EFI_CPU_INTERRUPT_HANDLER InterruptHandler
+ )
+{
+ if (InterruptType < 0 || InterruptType > 0xff) {
+ return EFI_UNSUPPORTED;
+ }
+
+ if (InterruptHandler == NULL && mExternalVectorTable[InterruptType] == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (InterruptHandler != NULL && mExternalVectorTable[InterruptType] != NULL) {
+ return EFI_ALREADY_STARTED;
+ }
+
+ mExternalVectorTable[InterruptType] = InterruptHandler;
+ return EFI_SUCCESS;
+}
+
+/**
+ Returns the CPU core to processor bus frequency ratio.
+
+ @param[out] Ratio Pointer to the CPU core to processor bus frequency ratio.
+
+ @retval EFI_SUCCESS If the ratio is returned successfully
+ @retval EFI_UNSUPPORTED If the ratio cannot be measured
+ @retval EFI_INVALID_PARAMETER If the input parameter is not valid
+
+**/
+EFI_STATUS
+GetCpuBusRatio (
+ OUT UINT32 *Ratio
+ )
+{
+ UINT64 TempQword;
+
+ if (Ratio == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ TempQword = AsmReadMsr64 (EFI_MSR_IA32_PERF_STS);
+ *Ratio = (UINT32) (RShiftU64 (TempQword, 8) & 0x1F);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Returns a timer value from one of the CPU's internal timers. There is no
+ inherent time interval between ticks but is a function of the CPU frequency.
+
+ @param[in] This Protocol instance structure.
+ @param[in] TimerIndex Specifies which CPU timer is requested.
+ @param[out] TimerValue Pointer to the returned timer value.
+ @param[out] TimerPeriod A pointer to the amount of time that passes in femtoseconds (10-15) for each
+ increment of TimerValue. If TimerValue does not increment at a predictable
+ rate, then 0 is returned. The amount of time that has passed between two calls to
+ GetTimerValue() can be calculated with the formula
+ (TimerValue2 - TimerValue1) * TimerPeriod. This parameter is optional and may be NULL.
+
+ @retval EFI_SUCCESS If the CPU timer count was returned.
+ @retval EFI_UNSUPPORTED If the CPU does not have any readable timers.
+ @retval EFI_DEVICE_ERROR If an error occurred while reading the timer.
+ @retval EFI_INVALID_PARAMETER TimerIndex is not valid or TimerValue is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+GetTimerValue (
+ IN EFI_CPU_ARCH_PROTOCOL *This,
+ IN UINT32 TimerIndex,
+ OUT UINT64 *TimerValue,
+ OUT UINT64 *TimerPeriod OPTIONAL
+ )
+{
+ UINT64 Actual;
+
+ if (TimerValue == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (TimerIndex != 0) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ *TimerValue = AsmReadTsc ();
+
+ if (TimerPeriod != NULL) {
+ GetActualFrequency (mMetronome, &Actual);
+ *TimerPeriod = DivU64x32 (1000000000, (UINT32) Actual);
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Set memory cacheability attributes for given range of memeory
+
+ @param[in] This Protocol instance structure
+ @param[in] BaseAddress Specifies the start address of the memory range
+ @param[in] Length Specifies the length of the memory range
+ @param[in] Attributes The memory cacheability for the memory range
+
+ @retval
+
+ EFI_SUCCESS If the cacheability of that memory range is set successfully
+ EFI_UNSUPPORTED If the desired operation cannot be done
+ EFI_INVALID_PARAMETER The input parameter is not correct, such as Length = 0
+
+**/
+EFI_STATUS
+EFIAPI
+SetMemoryAttributes (
+ IN EFI_CPU_ARCH_PROTOCOL *This,
+ IN EFI_PHYSICAL_ADDRESS BaseAddress,
+ IN UINT64 Length,
+ IN UINT64 Attributes
+ )
+{
+ EFI_STATUS Status;
+ UINT64 TempQword;
+ UINT32 MsrNum, MsrNumEnd;
+ UINTN MtrrNumber;
+ BOOLEAN Positive;
+ BOOLEAN OverLap;
+ UINTN Remainder;
+ EFI_MP_SERVICES_PROTOCOL *MpService;
+ EFI_STATUS Status1;
+
+ if (mIsFlushingGCD) {
+ return EFI_SUCCESS;
+ }
+
+ TempQword = 0;
+
+ //
+ // Check for invalid parameter
+ //
+ if (Length == 0) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if ((BaseAddress &~mValidMtrrAddressMask) != 0 || (Length &~mValidMtrrAddressMask) != 0) {
+ return EFI_UNSUPPORTED;
+ }
+
+ switch (Attributes) {
+ case EFI_MEMORY_UC:
+ Attributes = EFI_CACHE_UNCACHEABLE;
+ break;
+
+ case EFI_MEMORY_WC:
+ Attributes = EFI_CACHE_WRITECOMBINING;
+ break;
+
+ case EFI_MEMORY_WT:
+ Attributes = EFI_CACHE_WRITETHROUGH;
+ break;
+
+ case EFI_MEMORY_WP:
+ Attributes = EFI_CACHE_WRITEPROTECTED;
+ break;
+
+ case EFI_MEMORY_WB:
+ Attributes = EFI_CACHE_WRITEBACK;
+ break;
+
+ default:
+ return EFI_UNSUPPORTED;
+ }
+ //
+ // Check if Fixed MTRR
+ //
+ Status = EFI_SUCCESS;
+ while ((BaseAddress < (1 << 20)) && (Length > 0) && Status == EFI_SUCCESS) {
+ PreMtrrChange ();
+ Status = ProgramFixedMtrr (Attributes, &BaseAddress, &Length);
+ PostMtrrChange ();
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ }
+
+ if (Length == 0) {
+ //
+ // Just Fixed MTRR. NO need to go through Variable MTRR
+ //
+ goto Done;
+ }
+
+ //
+ // since mem below 1m will be override by fixed mtrr, we can set it to 0 to save mtrr.
+ //
+ if (BaseAddress == 0x100000) {
+ BaseAddress = 0;
+ Length += 0x100000;
+ }
+
+ //
+ // Check memory base address alignment
+ //
+ Remainder = ModU64x32(BaseAddress, (UINT32) Power2MaxMemory (LShiftU64 (Length, 1)));
+ if (Remainder != 0) {
+ Remainder = ModU64x32 (BaseAddress, (UINT32) Power2MaxMemory (Length));
+ if (Remainder != 0) {
+ Status = EFI_UNSUPPORTED;
+ goto Done;
+ }
+ }
+
+ //
+ // Check overlap
+ //
+ GetMemoryAttribute ();
+ OverLap = CheckMemoryAttributeOverlap (BaseAddress, BaseAddress + Length - 1);
+ if (OverLap) {
+ Status = CombineMemoryAttribute (Attributes, &BaseAddress, &Length);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ if (Length == 0) {
+ //
+ // combine successfully
+ //
+ Status = EFI_SUCCESS;
+ goto Done;
+ }
+ } else {
+ if (Attributes == EFI_CACHE_UNCACHEABLE) {
+ Status = EFI_SUCCESS;
+ goto Done;
+ }
+ }
+
+ //
+ // Program Variable MTRRs
+ //
+ if (mUsedMtrr >= 6) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Done;
+ }
+
+ //
+ // Find first unused MTRR
+ //
+ MsrNumEnd = EFI_MSR_CACHE_VARIABLE_MTRR_BASE + (2 * (UINT32)(AsmReadMsr64(EFI_MSR_IA32_MTRR_CAP) & B_EFI_MSR_IA32_MTRR_CAP_VARIABLE_SUPPORT));
+ for (MsrNum = EFI_MSR_CACHE_VARIABLE_MTRR_BASE; MsrNum < MsrNumEnd; MsrNum += 2) {
+ if ((AsmReadMsr64 (MsrNum + 1) & B_EFI_MSR_CACHE_MTRR_VALID) == 0) {
+ break;
+ }
+ }
+
+ TempQword = Length;
+
+ if (TempQword == Power2MaxMemory (TempQword)) {
+ ProgramVariableMtrr (
+ MsrNum,
+ BaseAddress,
+ Length,
+ Attributes
+ );
+ } else {
+
+ GetDirection (TempQword, &MtrrNumber, &Positive);
+
+ if ((mUsedMtrr + MtrrNumber) > 6) {
+ goto Done;
+ }
+
+ if (!Positive) {
+ Length = Power2MaxMemory (LShiftU64 (TempQword, 1));
+ ProgramVariableMtrr (
+ MsrNum,
+ BaseAddress,
+ Length,
+ Attributes
+ );
+ BaseAddress += TempQword;
+ TempQword = Length - TempQword;
+ Attributes = EFI_CACHE_UNCACHEABLE;
+ }
+
+ do {
+ //
+ // Find unused MTRR
+ //
+ for (; MsrNum < MsrNumEnd; MsrNum += 2) {
+ if ((AsmReadMsr64 (MsrNum + 1) & B_EFI_MSR_CACHE_MTRR_VALID) == 0) {
+ break;
+ }
+ }
+
+ Length = Power2MaxMemory (TempQword);
+ ProgramVariableMtrr (
+ MsrNum,
+ BaseAddress,
+ Length,
+ Attributes
+ );
+ BaseAddress += Length;
+ TempQword -= Length;
+
+ } while (TempQword);
+
+ }
+
+Done:
+ Status1 = gBS->LocateProtocol (
+ &gEfiMpServiceProtocolGuid,
+ NULL,
+ (VOID **) &MpService
+ );
+ if (!EFI_ERROR (Status1)) {
+ ReadMtrrRegisters ();
+ Status1 = MpService->StartupAllAPs (
+ MpService,
+ MpMtrrSynchUp,
+ TRUE,
+ NULL,
+ 0,
+ NULL,
+ NULL
+ );
+ }
+
+ return Status;
+}
+
+/**
+ @todo Add structure description
+
+**/
+typedef struct {
+ UINT8 Bus;
+ UINT8 Device;
+ UINT8 Function;
+} PCI_CONTROLLER_BITMAP;
+
+PCI_CONTROLLER_BITMAP mHostBus[] =
+{
+ {0, 0, 0},
+ {0, 27, 0},
+ {0, 30, 0},
+ {0, 30, 1},
+ {0, 30, 2},
+ {0, 30, 3},
+ {0, 30, 4},
+ {0, 30, 5},
+ {0, 30, 6},
+ {0, 30, 7},
+ {0, 31, 3},
+ {0, 16, 0},
+ {0, 17, 0},
+ {0, 18, 0},
+ {0, 26, 0},
+ {0, 26, 1},
+ {0, 31, 0},
+ {0, 21, 0} ,
+ {0, 19, 0} ,
+ {0, 2, 0},
+ {0, 29, 0},
+ {0, 20, 0} ,
+ {0, 22, 0},
+ {0, 3, 0},
+ {0, 24, 0},
+ {0, 24, 1} ,
+ {0, 24, 2},
+ {0, 24, 3} ,
+ {0, 24, 4},
+ {0, 24, 5},
+ {0, 24, 6} ,
+ {0, 24, 7} ,
+ {0, 28, 0},
+ {0, 28, 1} ,
+ {0, 28, 2},
+ {0, 28, 3} ,
+ {0, 23, 0},
+ {0, 25, 0} ,
+};
+
+/**
+ Initialize the state information for the CPU Architectural Protocol
+
+ @param[in] ImageHandle Image handle of the loaded driver
+ @param[in] SystemTable Pointer to the System Table
+
+ @retval
+
+ EFI_SUCCESS Thread can be successfully created
+ EFI_OUT_OF_RESOURCES Cannot allocate protocol data structure
+ EFI_DEVICE_ERROR Cannot create the thread
+
+**/
+EFI_STATUS
+EFIAPI
+InitializeCpu (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+ EFI_HANDLE NewHandle;
+ EFI_EVENT LegacyBootEvent;
+ EFI_EVENT EndOfDxeEvent = NULL;
+
+ //
+ // DXE CPU Post Codes are defined in PostCode.c, variable mPort80Table[]
+ //
+ Status = REPORT_STATUS_CODE_EX (
+ EFI_PROGRESS_CODE,
+ EFI_COMPUTING_UNIT_HOST_PROCESSOR | EFI_CU_HP_PC_DXE_INIT,
+ 0,
+ &gEfiCallerIdGuid,
+ NULL,
+ NULL,
+ 0
+ );
+
+ //
+ // Initialize the Global Descriptor Table
+ //
+ InitializeSelectors ();
+
+ Status = PrepareMemory ();
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Initialize Exception Handlers
+ //
+ Status = InitializeException (&gCpu);
+
+ //
+ // Install CPU Architectural Protocol
+ //
+ NewHandle = NULL;
+ Status = gBS->InstallProtocolInterface (
+ &NewHandle,
+ &gEfiCpuArchProtocolGuid,
+ EFI_NATIVE_INTERFACE,
+ &gCpu
+ );
+
+ ASSERT_EFI_ERROR (Status);
+
+ Status = REPORT_STATUS_CODE_EX (
+ EFI_PROGRESS_CODE,
+ EFI_COMPUTING_UNIT_HOST_PROCESSOR | EFI_CU_HP_PC_DXE_STEP1,
+ 0,
+ &gEfiCallerIdGuid,
+ NULL,
+ NULL,
+ 0
+ );
+
+ //
+ // Refresh memory space attributes according to MTRRs
+ //
+ Status = RefreshGcdMemoryAttributes ();
+ mIsFlushingGCD = FALSE;
+ if (EFI_ERROR(Status)) {
+ return Status;
+ }
+
+ Status = REPORT_STATUS_CODE_EX (
+ EFI_PROGRESS_CODE,
+ EFI_COMPUTING_UNIT_HOST_PROCESSOR | EFI_CU_HP_PC_DXE_STEP2,
+ 0,
+ &gEfiCallerIdGuid,
+ NULL,
+ NULL,
+ 0
+ );
+
+ Status = gBS->LocateProtocol (&gEfiMetronomeArchProtocolGuid, NULL, (VOID **) &mMetronome);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = REPORT_STATUS_CODE_EX (
+ EFI_PROGRESS_CODE,
+ EFI_COMPUTING_UNIT_HOST_PROCESSOR | EFI_CU_HP_PC_DXE_STEP3,
+ 0,
+ &gEfiCallerIdGuid,
+ NULL,
+ NULL,
+ 0
+ );
+
+ Status = REPORT_STATUS_CODE_EX (
+ EFI_PROGRESS_CODE,
+ EFI_COMPUTING_UNIT_HOST_PROCESSOR | EFI_CU_HP_PC_DXE_STEP4,
+ 0,
+ &gEfiCallerIdGuid,
+ NULL,
+ NULL,
+ 0
+ );
+
+ //
+ // Initialize MP Support if necessary
+ //
+ Status = InitializeMpSupport (ImageHandle, SystemTable);
+
+ Status = REPORT_STATUS_CODE_EX (
+ EFI_PROGRESS_CODE,
+ EFI_COMPUTING_UNIT_HOST_PROCESSOR | EFI_CU_HP_PC_DXE_END,
+ 0,
+ &gEfiCallerIdGuid,
+ NULL,
+ NULL,
+ 0
+ );
+ //
+ // Create an EndOfDxe protocol callback event
+ //
+ Status = gBS->CreateEventEx (
+ EVT_NOTIFY_SIGNAL,
+ TPL_NOTIFY,
+ (EFI_EVENT_NOTIFY) CpuInitBeforeBoot,
+ NULL,
+ &gEfiEndOfDxeEventGroupGuid,
+ &EndOfDxeEvent
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ Status = EfiCreateEventLegacyBootEx (
+ TPL_CALLBACK,
+ (EFI_EVENT_NOTIFY) CpuInitBeforeBoot,
+ NULL,
+ &LegacyBootEvent
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Determine the processor core frequency
+
+ @retval Processor core frequency multiplied by 3
+
+**/
+UINT16
+DetermineiFsbFromMsr (
+ VOID
+ )
+{
+ UINT64 FrequencyIndex;
+
+ //
+ // Determine the processor core frequency
+ //
+ FrequencyIndex = (AsmReadMsr64 (BSEL_CR_OVERCLOCK_CONTROL)) & FUSE_BSEL_MASK;
+ if (AsmReadMsr64 (BSEL_CR_OVERCLOCK_CONTROL) & BIT5) {
+ //
+ //maybe change to (FrequencyIndex&0x3)+12 if Lookup table size increases on B-Step
+ //
+ return miFSBFrequencyTable[12];
+ } else if (AsmReadMsr64 (BSEL_CR_OVERCLOCK_CONTROL) & BIT28) {
+ //
+ // Bit 28 combined with bits[0:1] gives us unique lookup value.
+ // When BIT28 is set, Table offset will be 8 + bits[1:0] of MSR
+ //
+ return miFSBFrequencyTable[(FrequencyIndex&0x3)+8];
+ } else {
+ return miFSBFrequencyTable[FrequencyIndex];
+ }
+}
+
+/**
+ Returns the actual CPU core frequency in MHz.
+
+ @param[in] Metronome Metronome protocol
+ @param[out] Frequency Pointer to the CPU core frequency
+
+ @retval EFI_SUCCESS If the frequency is returned successfully
+ @retval EFI_INVALID_PARAMETER If the input parameter is wrong
+
+**/
+EFI_STATUS
+GetActualFrequency (
+ IN EFI_METRONOME_ARCH_PROTOCOL *Metronome,
+ OUT UINT64 *Frequency
+ )
+{
+ UINT64 BeginValue;
+ UINT64 EndValue;
+ UINTN TickCount;
+ BOOLEAN mInterruptState;
+ EFI_STATUS Status;
+ UINT64 TotalValue;
+
+ if (Metronome == NULL || Frequency == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+ if (mCpuFrequency == 0) {
+ *Frequency = 0;
+
+ //
+ // In order to calculate the actual CPU frequency, we keep track of the CPU Tsc value (which
+ // increases by 1 for every cycle) for a know period of time. The Metronome is not accurate
+ // for the 1st tick, so I choose to wait for 100 ticks, thus the error can be control to be
+ // lower than 1%.
+ //
+ CpuGetInterruptState (&gCpu, &mInterruptState);
+ if (mInterruptState) {
+ DisableInterrupt (&gCpu);
+ }
+ //
+ // Wait for 3000us = 3ms for the calculation
+ // It needs a precise timer to calculate the ticks
+ //
+ TickCount = SAMPLE_TICK_COUNT *4;
+ while (TRUE) {
+ BeginValue = AsmReadTsc ();
+ Status = Metronome->WaitForTick (Metronome, (UINT32)TickCount);
+ EndValue = AsmReadTsc ();
+ if (!EFI_ERROR (Status)) {
+ TotalValue = EndValue - BeginValue;
+ break;
+ }
+ }
+ if (mInterruptState) {
+ EnableInterrupt (&gCpu);
+ }
+
+ mCpuFrequency = MultU64x32 (TotalValue, 10);
+ mCpuFrequency = DivU64x32 (mCpuFrequency, Metronome->TickPeriod * (UINT32)TickCount);
+
+ }
+ *Frequency = mCpuFrequency;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Create Perform Final Init before boot to OS
+
+ @param[in] Event A pointer to the Event that triggered the callback.
+ @param[in] Context A pointer to private data registered with the callback function.
+
+**/
+VOID
+CpuInitBeforeBoot (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ EFI_STATUS Status;
+ VOID *ProtocolPointer;
+ EFI_MP_SERVICES_PROTOCOL *MpService;
+
+ Status = gBS->LocateProtocol (&gEfiDxeSmmReadyToLockProtocolGuid, NULL, (VOID **) &ProtocolPointer);
+ if (EFI_SUCCESS != Status) {
+ return ;
+ }
+
+ Status = gBS->LocateProtocol (
+ &gEfiMpServiceProtocolGuid,
+ NULL,
+ (VOID **) &MpService
+ );
+ if (!EFI_ERROR (Status)) {
+ //
+ // Configure for BSP first
+ //
+ ApCpuInitBeforeBoot();
+ //
+ // Confiture the rest APs
+ //
+ Status = MpService->StartupAllAPs (
+ MpService,
+ (EFI_AP_PROCEDURE) ApCpuInitBeforeBoot,
+ TRUE,
+ NULL,
+ 0,
+ NULL,
+ NULL
+ );
+ }
+
+ return ;
+}
+
+/**
+ Perform final Inititialization before boot to OS
+
+ @param[in] None
+
+ @retval None
+**/
+VOID
+ApCpuInitBeforeBoot (
+ VOID
+ )
+{
+}
diff --git a/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/CpuInit/CpuDataStruct.h b/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/CpuInit/CpuDataStruct.h
new file mode 100644
index 0000000000..5d61762969
--- /dev/null
+++ b/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/CpuInit/CpuDataStruct.h
@@ -0,0 +1,121 @@
+/** @file
+
+ Copyright (c) 1999 - 2015, 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 _CPU_DATA_STRUCT_H
+#define _CPU_DATA_STRUCT_H
+
+#include <Guid/AcpiVariableCompatibility.h>
+//
+// The data saved in SMRAM.
+// In S3 path, CPUS3 runs before SMMS3. SMRAM is open at that time.
+//
+
+#define EFI_SMRAM_CPU_NVS_HEADER_GUID \
+ { \
+ 0x429501d9, 0xe447, 0x40f4, 0x86, 0x7b, 0x75, 0xc9, 0x3a, 0x1d, 0xb5, 0x4e \
+ }
+
+typedef struct {
+ //
+ // Guid as Signature.
+ //
+ EFI_GUID HeaderGuid;
+ EFI_PHYSICAL_ADDRESS AcpiCpuPointer;
+ ACPI_CPU_DATA_COMPATIBILITY AcpiCpuData;
+
+ //
+ // It points the data defined below.
+ //
+ EFI_PHYSICAL_ADDRESS GdtrProfileOffset;
+ EFI_PHYSICAL_ADDRESS GdtOffset;
+ EFI_PHYSICAL_ADDRESS IdtrProfileOffset;
+ EFI_PHYSICAL_ADDRESS IdtOffset;
+ EFI_PHYSICAL_ADDRESS CpuPrivateDataOffset;
+ EFI_PHYSICAL_ADDRESS S3BootScriptTableOffset;
+ EFI_PHYSICAL_ADDRESS S3BspMtrrTableOffset;
+ EFI_PHYSICAL_ADDRESS MicrocodePointerBufferOffset; // It is pointer to pointer array.
+ EFI_PHYSICAL_ADDRESS MicrocodeDataBufferOffset; // It is pointer to the data.
+
+ //
+ // We need put all the data buffer here as well.
+ // These data will be copied to original location in S3.
+ //
+
+ //
+ // DataBuffer size
+ //
+ UINT32 GdtrProfileSize;
+ UINT32 GdtSize;
+ UINT32 IdtrProfileSize;
+ UINT32 IdtSize;
+ UINT32 CpuPrivateDataSize;
+ UINT32 S3BootScriptTableSize;
+ UINT32 S3BspMtrrTableSize;
+ UINT32 MicrocodePointerBufferSize;
+ UINT32 MicrocodeDataBufferSize;
+} SMRAM_CPU_DATA;
+
+typedef struct {
+ UINT32 RegEax;
+ UINT32 RegEbx;
+ UINT32 RegEcx;
+ UINT32 RegEdx;
+} EFI_CPUID_REGISTER;
+
+typedef struct {
+ UINT32 HeaderVersion;
+ UINT32 UpdateRevision;
+ UINT32 Date;
+ UINT32 ProcessorId;
+ UINT32 Checksum;
+ UINT32 LoaderRevision;
+ UINT32 ProcessorFlags;
+ UINT32 DataSize;
+ UINT32 TotalSize;
+ UINT8 Reserved[12];
+} EFI_CPU_MICROCODE_HEADER;
+
+typedef struct {
+ UINT32 ExtSigCount;
+ UINT32 ExtChecksum;
+ UINT8 Reserved[12];
+ UINT32 ProcessorId;
+ UINT32 ProcessorFlags;
+ UINT32 Checksum;
+} EFI_CPU_MICROCODE_EXT_HEADER;
+
+typedef struct {
+ UINT32 ExtendedSignatureCount;
+ UINT32 ExtendedTableChecksum;
+ UINT8 Reserved[12];
+} EFI_CPU_MICROCODE_EXTENDED_TABLE_HEADER;
+
+typedef struct {
+ UINT32 ProcessorSignature;
+ UINT32 ProcessorFlag;
+ UINT32 ProcessorChecksum;
+} EFI_CPU_MICROCODE_EXTENDED_TABLE;
+
+typedef struct {
+ UINT32 Stepping : 4;
+ UINT32 Model : 4;
+ UINT32 Family : 4;
+ UINT32 Type : 2;
+ UINT32 Reserved1 : 2;
+ UINT32 ExtendedModel : 4;
+ UINT32 ExtendedFamily : 8;
+ UINT32 Reserved2 : 4;
+} EFI_CPU_VERSION;
+
+#endif
diff --git a/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/CpuInit/CpuDxe.h b/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/CpuInit/CpuDxe.h
new file mode 100644
index 0000000000..9ead237ffe
--- /dev/null
+++ b/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/CpuInit/CpuDxe.h
@@ -0,0 +1,240 @@
+/** @file
+ Private data structures.
+
+ Copyright (c) 1999 - 2015, 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 _CPU_DXE_H
+#define _CPU_DXE_H
+
+#include <PiDxe.h>
+
+#include <Guid/StatusCodeDataTypeId.h>
+#include <Guid/AcpiVariableCompatibility.h>
+#include <Guid/GlobalVariable.h>
+#include <Guid/EventGroup.h>
+
+#include <Protocol/Cpu.h>
+#include <Protocol/MpService.h>
+#include <Protocol/Metronome.h>
+#include <Protocol/SmmBase2.h>
+#include <Protocol/SmmAccess2.h>
+#include <Protocol/SmmControl2.h>
+#include <Protocol/ExitPmAuth.h>
+#include <Protocol/DxeSmmReadyToLock.h>
+
+#include <Library/BaseMemoryLib.h>
+#include <Library/DebugLib.h>
+#include <Library/ReportStatusCodeLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiRuntimeServicesTableLib.h>
+#include <Library/BaseLib.h>
+#include <Library/UefiLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/HobLib.h>
+#include <Library/DxeServicesTableLib.h>
+
+#include <IndustryStandard/SmBios.h>
+
+#include "CpuRegs.h"
+#include "CpuDataStruct.h"
+
+#define BSEL_CR_OVERCLOCK_CONTROL 0xCD
+#define FUSE_BSEL_MASK 0x07
+
+#define INTERRUPT_VECTOR_NUMBER 256
+#define INTERRUPT_GATE_ATTRIBUTE 0x8e00
+#define NUMBER_OF_MICROCODE_UPDATE 10
+
+extern EFI_GUID gEfiHtBistHobGuid;
+
+#define TRIGGER_MODE_EDGE 0x0
+#define TRIGGER_MODE_LEVEL 0x1
+#define SINGLE_THREAD_BOOT_FLAG 0
+
+#define EfiProcessorFamilyIntelAtom 0x2B
+
+#define SMM_FROM_SMBASE_DRIVER 0x55
+
+#define SMM_FROM_SMBASE_DRIVER_BOOTTIME 0x0
+#define SMM_FROM_SMBASE_DRIVER_RUNTIME 0x1
+#define SMM_FROM_SMBASE_DRIVER_LOCK 0x2
+//
+// This value should be same as the one in CPU driver.
+//
+#define SMM_FROM_CPU_DRIVER_SAVE_INFO 0x81
+
+#define EFI_CU_HP_PC_DXE_INIT (EFI_SUBCLASS_SPECIFIC | 0x00000020)
+#define EFI_CU_HP_PC_DXE_STEP1 (EFI_SUBCLASS_SPECIFIC | 0x00000021)
+#define EFI_CU_HP_PC_DXE_STEP2 (EFI_SUBCLASS_SPECIFIC | 0x00000022)
+#define EFI_CU_HP_PC_DXE_STEP3 (EFI_SUBCLASS_SPECIFIC | 0x00000023)
+#define EFI_CU_HP_PC_DXE_STEP4 (EFI_SUBCLASS_SPECIFIC | 0x00000024)
+#define EFI_CU_HP_PC_DXE_END (EFI_SUBCLASS_SPECIFIC | 0x0000002F)
+#define EfiMakeCpuVersion(f, m, s) \
+ (((UINT32) (f) << 16) | ((UINT32) (m) << 8) | ((UINT32) (s)))
+
+extern
+VOID
+InitializeSelectors (
+ VOID
+ );
+
+//
+// This is the string tool generated data representing our strings.
+//
+extern UINT8 STRING_ARRAY_NAME[];
+
+typedef struct {
+ VOID *Start;
+ UINTN Size;
+ UINTN FixOffset;
+} INTERRUPT_HANDLER_TEMPLATE_MAP;
+
+//
+// Function declarations
+//
+EFI_STATUS
+InitializeMicrocode (
+ IN EFI_CPU_MICROCODE_HEADER **MicrocodePointerBuffer,
+ OUT UINT32 *FailedRevision,
+ IN BOOLEAN IsBsp
+ );
+
+EFI_STATUS
+InitializeMpSupport (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ );
+
+VOID
+ReadMtrrRegisters (
+ VOID
+ );
+
+VOID
+EFIAPI
+MpMtrrSynchUp (
+ IN VOID *Buffer
+ );
+
+EFI_STATUS
+LoadAllMicrocodeUpdates (
+ VOID
+ );
+
+VOID
+FreeAllMicrocodeUpdates (
+ VOID
+ );
+
+EFI_STATUS
+CheckIncompatibleFsb (
+ IN UINTN CpuNumber,
+ IN UINT64 ActualFsb,
+ IN UINT64 IntendFsb
+ );
+
+EFI_STATUS
+CheckBspBusSpeed (
+ IN EFI_METRONOME_ARCH_PROTOCOL *Metronome
+ );
+
+EFI_STATUS
+GetActualFrequency (
+ IN EFI_METRONOME_ARCH_PROTOCOL *Metronome,
+ OUT UINT64 *Frequency
+ );
+UINT16
+DetermineiFsbFromMsr (
+ VOID
+ );
+
+EFI_STATUS
+Actual2StandardFrequency (
+ IN UINT64 Actual,
+ IN UINT32 Ratio,
+ OUT UINT64 *Standard
+ );
+
+EFI_STATUS
+EnableCpuIdMaximumValueLimit (
+ BOOLEAN LimitCpuidMaximumValue
+ );
+
+EFI_STATUS
+CheckMicrocodeUpdate (
+ IN UINTN CpuNumber,
+ IN EFI_STATUS Status,
+ IN UINT32 FailedRevision
+ );
+
+VOID
+GetTemplateAddressMap (
+ OUT INTERRUPT_HANDLER_TEMPLATE_MAP *AddressMap
+ );
+
+VOID
+CpuEnableInterrupt (
+ VOID
+ );
+
+VOID
+CpuDisableInterrupt (
+ VOID
+ );
+
+UINT16
+GetCodeSegment (
+ VOID
+ );
+
+VOID
+CpuInitFloatPointUnit (
+ VOID
+ );
+
+//
+// Structures
+//
+typedef struct {
+ EFI_HANDLE Handle;
+
+ EFI_CPU_ARCH_PROTOCOL Cpu;
+
+ //
+ // Local Data for CPU interface goes here
+ //
+} CPU_ARCH_PROTOCOL_PRIVATE;
+
+VOID
+CpuInitBeforeBoot (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ );
+
+VOID
+ApCpuInitBeforeBoot ();
+
+VOID
+PCIConfigWA (
+ EFI_EVENT Event,
+ VOID *Context
+ );
+
+#define CPU_ARCH_PROTOCOL_PRIVATE_DATA_FROM_THIS(a) \
+ CR (a, \
+ CPU_ARCH_PROTOCOL_PRIVATE, \
+ Cpu, \
+ CPU_ARCH_PROT_PRIVATE_SIGNATURE \
+ )
+
+#endif
diff --git a/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/CpuInit/CpuRegs.h b/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/CpuInit/CpuRegs.h
new file mode 100644
index 0000000000..5dd1d959e0
--- /dev/null
+++ b/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/CpuInit/CpuRegs.h
@@ -0,0 +1,410 @@
+/** @file
+ Definitions of CPU registers
+
+@brief
+
+ Conventions:
+
+ - Prefixes:
+ Definitions beginning with "MSR_" are MSRs
+ Definitions beginning with "R_" are registers
+ Definitions beginning with "B_" are bits within registers
+ Definitions beginning with "V_" are meaningful values of bits within the registers
+ Definitions beginning with "S_" are register sizes
+ Definitions beginning with "N_" are the bit position
+
+ Copyright (c) 2004 - 2015, 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 _CPU_REGS_H_
+#define _CPU_REGS_H_
+
+//
+// Local APIC defines
+//
+#define APIC_REGISTER_LOCAL_ID_OFFSET 0x00000020
+#define APIC_REGISTER_APIC_VERSION_OFFSET 0x00000030
+#define APIC_REGISTER_SPURIOUS_VECTOR_OFFSET 0x000000F0
+#define APIC_REGISTER_ICR_LOW_OFFSET 0x00000300
+#define APIC_REGISTER_ICR_HIGH_OFFSET 0x00000310
+#define APIC_REGISTER_LINT0_VECTOR_OFFSET 0x00000350
+#define APIC_REGISTER_LINT1_VECTOR_OFFSET 0x00000360
+
+#define BROADCAST_MODE_SPECIFY_CPU 0x00
+#define BROADCAST_MODE_ALL_INCLUDING_SELF 0x01
+#define BROADCAST_MODE_ALL_EXCLUDING_SELF 0x02
+
+#ifndef DELIVERY_MODE_FIXED
+#define DELIVERY_MODE_FIXED 0x0
+#endif
+#ifndef DELIVERY_MODE_LOWEST_PRIORITY
+#define DELIVERY_MODE_LOWEST_PRIORITY 0x1
+#endif
+#ifndef DELIVERY_MODE_SMI
+#define DELIVERY_MODE_SMI 0x2
+#endif
+#ifndef DELIVERY_MODE_REMOTE_READ
+#define DELIVERY_MODE_REMOTE_READ 0x3
+#endif
+#ifndef DELIVERY_MODE_NMI
+#define DELIVERY_MODE_NMI 0x4
+#endif
+#ifndef DELIVERY_MODE_INIT
+#define DELIVERY_MODE_INIT 0x5
+#endif
+#ifndef DELIVERY_MODE_SIPI
+#define DELIVERY_MODE_SIPI 0x6
+#endif
+#ifndef DELIVERY_MODE_MAX
+#define DELIVERY_MODE_MAX 0x7
+#endif
+
+#define EFI_CACHE_UNCACHEABLE 0
+#define EFI_CACHE_WRITECOMBINING 1
+#define EFI_CACHE_WRITETHROUGH 4
+#define EFI_CACHE_WRITEPROTECTED 5
+#define EFI_CACHE_WRITEBACK 6
+
+//
+// CPUID defines
+//
+#define EFI_CPUID_SIGNATURE 0x0
+
+#define EFI_CPUID_VERSION_INFO 0x1
+#define B_EFI_CPUID_VERSION_INFO_EAX_MASK 0x0FFF0FFF
+#define B_EFI_CPUID_VERSION_INFO_EAX_FULL_FAMILY_MODEL_MASK 0x0FFF0FF0
+#define B_EFI_CPUID_VERSION_INFO_EAX_EXT_FAMILY_ID_MASK 0x0FF00000
+#define B_EFI_CPUID_VERSION_INFO_EAX_EXT_MODEL_ID_MASK 0x000F0000
+#define N_EFI_CPUID_VERSION_INFO_EAX_EXT_FAMILY_ID 20
+#define N_EFI_CPUID_VERSION_INFO_EAX_EXT_MODEL_ID 16
+#define N_EFI_CPUID_VERSION_INFO_EAX_TYPE 12
+#define N_EFI_CPUID_VERSION_INFO_EAX_FAMILY_ID 8
+#define N_EFI_CPUID_VERSION_INFO_EAX_MODEL 4
+#define N_EFI_CPUID_VERSION_INFO_EAX_STEPPING_ID 0
+#define B_EFI_CPUID_VERSION_INFO_EBX_DEFAULT_APIC_ID (BIT31 | BIT30 | BIT29 | BIT28 | BIT27 | BIT26 | BIT25 | BIT24)
+#define B_EFI_CPUID_VERSION_INFO_EBX_LOGICAL_CPU_PER_PACKAGE (BIT23 | BIT22 | BIT21 | BIT20 | BIT19 | BIT18 | BIT17 | BIT16)
+#define B_EFI_CPUID_VERSION_INFO_EBX_CLFLUSH_CHUNK_COUNT (BIT15 | BIT14 | BIT13 | BIT12 | BIT11 | BIT10 | BIT9 | BIT8)
+#define B_EFI_CPUID_VERSION_INFO_ECX_AES BIT25
+#define B_EFI_CPUID_VERSION_INFO_ECX_XAPIC BIT21
+#define B_EFI_CPUID_VERSION_INFO_ECX_SSE4_2 BIT20
+#define B_EFI_CPUID_VERSION_INFO_ECX_SSE4_1 BIT19
+#define B_EFI_CPUID_VERSION_INFO_ECX_DCA BIT18
+#define B_EFI_CPUID_VERSION_INFO_ECX_XTPR_UPDATE BIT14
+#define B_EFI_CPUID_VERSION_INFO_ECX_CMPXCHG16B BIT13
+#define B_EFI_CPUID_VERSION_INFO_ECX_L1_CONTEXT_ID BIT10
+#define B_EFI_CPUID_VERSION_INFO_ECX_SUP_SSE3 BIT9
+#define B_EFI_CPUID_VERSION_INFO_ECX_TM2 BIT8
+#define B_EFI_CPUID_VERSION_INFO_ECX_EIST BIT7
+#define B_EFI_CPUID_VERSION_INFO_ECX_SME BIT6
+#define B_EFI_CPUID_VERSION_INFO_ECX_VME BIT5
+#define B_EFI_CPUID_VERSION_INFO_ECX_QPL BIT4
+#define B_EFI_CPUID_VERSION_INFO_ECX_MWAIT BIT3
+#define B_EFI_CPUID_VERSION_INFO_ECX_SSE3 BIT0
+#define B_EFI_CPUID_VERSION_INFO_EDX_PBE BIT31
+#define B_EFI_CPUID_VERSION_INFO_EDX_THERMAL_CLOCK_CONTROL BIT29
+#define B_EFI_CPUID_VERSION_INFO_EDX_HT BIT28
+#define B_EFI_CPUID_VERSION_INFO_EDX_SELF_SNOOP BIT27
+#define B_EFI_CPUID_VERSION_INFO_EDX_SSE2 BIT26
+#define B_EFI_CPUID_VERSION_INFO_EDX_SSE BIT25
+#define B_EFI_CPUID_VERSION_INFO_EDX_FAST_SAVE_RESTORE BIT24
+#define B_EFI_CPUID_VERSION_INFO_EDX_MMX BIT23
+#define B_EFI_CPUID_VERSION_INFO_EDX_ACPI_SUPPORT BIT22
+#define B_EFI_CPUID_VERSION_INFO_EDX_DEBUG_TRACE_STORE BIT21
+#define B_EFI_CPUID_VERSION_INFO_EDX_CLFLUSH_INTR BIT19
+#define B_EFI_CPUID_VERSION_INFO_EDX_CPU_SERIAL_NUMBER BIT18
+#define B_EFI_CPUID_VERSION_INFO_EDX_PSE BIT17
+#define B_EFI_CPUID_VERSION_INFO_EDX_PAT BIT16
+#define B_EFI_CPUID_VERSION_INFO_EDX_CON_MOVE_INTR BIT15
+#define B_EFI_CPUID_VERSION_INFO_EDX_MCA BIT14
+#define B_EFI_CPUID_VERSION_INFO_EDX_PGE BIT13
+#define B_EFI_CPUID_VERSION_INFO_EDX_MTRR BIT12
+#define B_EFI_CPUID_VERSION_INFO_EDX_SEP BIT11
+#define B_EFI_CPUID_VERSION_INFO_EDX_ON_CHIP_APIC BIT9
+#define B_EFI_CPUID_VERSION_INFO_EDX_CMPXCHG8 BIT8
+#define B_EFI_CPUID_VERSION_INFO_EDX_MCE BIT7
+#define B_EFI_CPUID_VERSION_INFO_EDX_PAE BIT6
+#define B_EFI_CPUID_VERSION_INFO_EDX_MSR BIT5
+#define B_EFI_CPUID_VERSION_INFO_EDX_TIME_STAMP_COUNTER BIT4
+#define B_EFI_CPUID_VERSION_INFO_EDX_PAGE_SIZE_EXT BIT3
+#define B_EFI_CPUID_VERSION_INFO_EDX_DEBUG_EXT BIT2
+#define B_EFI_CPUID_VERSION_INFO_EDX_VME_8086 BIT1
+#define B_EFI_CPUID_VERSION_INFO_EDX_FP_386 BIT0
+
+#define EFI_CPUID_CACHE_INFO 0x2
+#define EFI_CPUID_SERIAL_NUMBER 0x3
+
+#define EFI_CPUID_CACHE_PARAMS 0x4
+#define B_EFI_CPUID_CACHE_PARAMS_EAX_MAX_CORES_IN_PACKAGE (BIT31 | BIT30 | BIT29 | BIT28 | BIT27 | BIT26)
+#define B_EFI_CPUID_CACHE_PARAMS_EAX_TOTAL_THREADS_SHARE_CACHE (BIT25 | BIT24 | BIT23 | BIT22 | BIT21 | BIT20 | BIT19 | BIT18 | BIT17 | BIT16 | BIT15 | BIT14)
+#define B_EFI_CPUID_CACHE_PARAMS_EAX_FULLY_ASSOCIATIVE_CACHE BIT9
+#define B_EFI_CPUID_CACHE_PARAMS_EAX_SELF_INITIALIZING BIT8
+#define B_EFI_CPUID_CACHE_PARAMS_EAX_CACHE_LEVEL (BIT7 | BIT6 | BIT5)
+#define B_EFI_CPUID_CACHE_PARAMS_EAX_CACHE_TYPE (BIT4 | BIT3 | BIT2 | BIT1 | BIT0)
+#define B_EFI_CPUID_CACHE_PARAMS_EBX_WAYS_OF_ASSOCIATIVITY (BIT31 | BIT30 | BIT29 | BIT28 | BIT27 | BIT26 | BIT25 | BIT24 | BIT23 | BIT22)
+#define B_EFI_CPUID_CACHE_PARAMS_EBX_PHYSICAL_LINE_PARTITIONS (BIT21 | BIT20 | BIT19 | BIT18 | BIT17 | BIT16 | BIT15 | BIT14 | BIT13 | BIT12)
+#define B_EFI_CPUID_CACHE_PARAMS_EBX_SYSTEM_COHERENCY_LINE_SIZE (BIT11 | BIT10 | BIT9 | BIT8 | BIT7 | BIT6 | BIT5 | BIT4 | BIT3 | BIT2 | BIT1 | BIT0)
+#define B_EFI_CPUID_CACHE_PARAMS_EDX_CACHE_INCLUSIVE_IN_LOWER_CACHE BIT1
+#define B_EFI_CPUID_CACHE_PARAMS_EDX_WBINVD_INVD_ON_LOWER_CACHE BIT0
+#define V_CPUID_CACHE_TYPE_MASK 0x1F
+#define B_CPUID_CACHE_TYPE_DATA 0x1
+#define B_CPUID_CACHE_TYPE_INSTRUCTION 0x2
+#define B_CPUID_CACHE_TYPE_UNIFIED 0x3
+#define V_CPUID_CACHE_LEVEL_MASK 0xE0
+#define B_CPUID_CACHE_LEVEL_SHIFT 5
+#define B_CPUID_CACHE_PARAMS_WAYS_SHIFT 22
+#define B_CPUID_CACHE_PARAMS_PARTITIONS_SHIFT 12
+
+#define EFI_CPUID_MONITOR_MWAIT_PARAMS 0x5
+#define B_EFI_CPUID_MONITOR_MWAIT_ECX_INTERRUPTS_BREAK_MWAIT BIT1
+#define B_EFI_CPUID_MONITOR_MWAIT_ECX_MWAIT_SUPPORT BIT0
+#define B_EFI_CPUID_MONITOR_MWAIT_EDX_PARAMS_C7 (BIT31 | BIT30 | BIT29 | BIT28)
+#define N_EFI_CPUID_MONITOR_MWAIT_EDX_PARAMS_C7 28
+#define B_EFI_CPUID_MONITOR_MWAIT_EDX_PARAMS_C6 (BIT27 | BIT26 | BIT25 | BIT24)
+#define N_EFI_CPUID_MONITOR_MWAIT_EDX_PARAMS_C6 24
+#define B_EFI_CPUID_MONITOR_MWAIT_EDX_PARAMS_C5 (BIT23 | BIT22 | BIT21 | BIT20)
+#define N_EFI_CPUID_MONITOR_MWAIT_EDX_PARAMS_C5 20
+#define B_EFI_CPUID_MONITOR_MWAIT_EDX_PARAMS_C4 (BIT19 | BIT18 | BIT17 | BIT16)
+#define N_EFI_CPUID_MONITOR_MWAIT_EDX_PARAMS_C4 16
+#define B_EFI_CPUID_MONITOR_MWAIT_EDX_PARAMS_C3 (BIT15 | BIT14 | BIT13 | BIT12)
+#define N_EFI_CPUID_MONITOR_MWAIT_EDX_PARAMS_C3 12
+#define B_EFI_CPUID_MONITOR_MWAIT_EDX_PARAMS_C2 (BIT11 | BIT10 | BIT9 | BIT8)
+#define N_EFI_CPUID_MONITOR_MWAIT_EDX_PARAMS_C2 8
+#define B_EFI_CPUID_MONITOR_MWAIT_EDX_PARAMS_C1 (BIT7 | BIT6 | BIT5 | BIT4)
+#define N_EFI_CPUID_MONITOR_MWAIT_EDX_PARAMS_C1 4
+#define B_EFI_CPUID_MONITOR_MWAIT_EDX_PARAMS_C0 (BIT3 | BIT2 | BIT1 | BIT0)
+#define N_EFI_CPUID_MONITOR_MWAIT_EDX_PARAMS_C0 0
+
+#define EFI_CPUID_POWER_MANAGEMENT_PARAMS 0x6
+#define EFI_CPUID_POWER_MANAGEMENT_EAX_DTS BIT0
+#define EFI_CPUID_POWER_MANAGEMENT_EBX_NUM_INT_THRESHOLDS (BIT3 | BIT2 | BIT1 | BIT0)
+#define EFI_CPUID_POWER_MANAGEMENT_ECX_HW_COORDINATION_FEEDBACK BIT0
+
+#define EFI_CPUID_REV7 0x7
+#define EFI_CPUID_REV8 0x8
+#define EFI_CPUID_DCA_PARAMS 0x9
+#define EFI_CPUID_ARCH_PERF_MON 0xA
+#define EFI_CPUID_CORE_TOPOLOGY 0xB
+
+#define EFI_CPUID_EXTENDED_FUNCTION 0x80000000
+
+#define EFI_CPUID_EXTENDED_FEATURE_BITS 0x80000001
+#define EFI_CPUID_EXTENDED_FEATURE_BITS_ECX_LAHF_SAHF BIT0
+#define EFI_CPUID_EXTENDED_FEATURE_BITS_EDX_XD BIT20
+#define EFI_CPUID_EXTENDED_FEATURE_BITS_EDX_SYSCALL BIT11
+
+//
+// This constant defines the maximum length of the CPU brand string. According to the
+// IA manual, the brand string is in EAX through EDX (thus 16 bytes) after executing
+// the CPUID instructions with EAX as 80000002, 80000003, 80000004.
+//
+#define MAXIMUM_CPU_BRAND_STRING_LENGTH 48
+
+#define EFI_CPUID_BRAND_STRING1 0x80000002
+#define EFI_CPUID_BRAND_STRING2 0x80000003
+#define EFI_CPUID_BRAND_STRING3 0x80000004
+
+#define EFI_CPUID_ADVANCED_POWER_MANAGEMENT 0x80000007
+#define EFI_CPUID_ADVANCED_POWER_MANAGEMENT_EDX_TSC_INVARIANCE BIT8
+
+#define EFI_CPUID_VIRT_PHYS_ADDRESS_SIZE 0x80000008
+#define B_EFI_CPUID_VIRTUAL_ADDRESS_BITS (BIT15 | BIT14 | BIT13 | BIT12 | BIT11 | BIT10 | BIT9 | BIT8)
+#define B_EFI_CPUID_PHYSICAL_ADDRESS_BITS (BIT7 | BIT6 | BIT5 | BIT4 | BIT3 | BIT2 | BIT1 | BIT0)
+
+//
+// Common MSR
+//
+#define EFI_MSR_IA32_PLATFORM_ID 0x00000017
+#define N_EFI_MSR_IA32_PLATFORM_ID_PLATFORM_ID_BITS 50
+#define B_EFI_MSR_IA32_PLATFORM_ID_PLATFORM_ID_BITS_MASK (BIT52 | BIT51 | BIT50)
+#define N_EFI_MSR_IA32_PLATFORM_ID_PLATFORM_ID_BITS_MASK_START 50
+#define N_EFI_MSR_IA32_PLATFORM_ID_PLATFORM_ID_BITS_MASK_END 52
+
+#ifndef EFI_MSR_IA32_APIC_BASE
+#define EFI_MSR_IA32_APIC_BASE 0x0000001B
+
+#define B_EFI_MSR_IA32_APIC_BASE_APIC_BASE_ADDRESS 0xFFFFFF000 //For Nehalem, base address can be up to 43 bits but not cover here yet
+#define B_EFI_MSR_IA32_APIC_BASE_APIC_GLOBAL_ENABLE BIT11
+#define B_EFI_MSR_IA32_APIC_BASE_M_XAPIC BIT10
+#define B_EFI_MSR_IA32_APIC_BASE_BSP BIT8
+#endif // EFI_MSR_IA32_APIC_BASE
+//
+// Local APIC defines, offset from APIC base address
+//
+#define APIC_REGISTER_LOCAL_ID_OFFSET 0x00000020
+#define N_APIC_REGISTER_LOCAL_ID_OFFSET_XAPIC_ID_MASK 24
+#define B_APIC_REGISTER_LOCAL_ID_OFFSET_XAPIC_ID_MASK 0xFF000000
+
+#define APIC_REGISTER_APIC_VERSION_OFFSET 0x00000030
+#define B_APIC_REGISTER_APIC_VERSION_OFFSET_VERSION_MASK 0xFF
+
+#define APIC_REGISTER_SPURIOUS_VECTOR_OFFSET 0x000000F0
+#define APIC_REGISTER_ICR_LOW_OFFSET 0x00000300
+#define APIC_REGISTER_ICR_HIGH_OFFSET 0x00000310
+#define APIC_REGISTER_LINT0_VECTOR_OFFSET 0x00000350
+#define APIC_REGISTER_LINT1_VECTOR_OFFSET 0x00000360
+
+#define EFI_MSR_IA32_FEATURE_CONTROL 0x0000003A
+#define B_EFI_MSR_IA32_FEATURE_CONTROL_SGE BIT15
+#define B_EFI_MSR_IA32_FEATURE_CONTROL_SLFE (BIT14 | BIT13 | BIT12 | BIT11 | BIT10 | BIT9 | BIT8)
+#define B_EFI_MSR_IA32_FEATURE_CONTROL_SMRR BIT3
+#define B_EFI_MSR_IA32_FEATURE_CONTROL_EVT BIT2
+#define B_EFI_MSR_IA32_FEATURE_CONTROL_ELT BIT1
+#define B_EFI_MSR_IA32_FEATURE_CONTROL_LOCK BIT0
+#define B_EFI_MSR_IA32_FEATURE_CONTROL_VT_SECURE 0x0000FF02
+
+#ifndef EFI_MSR_IA32_BIOS_UPDT_TRIG
+#define EFI_MSR_IA32_BIOS_UPDT_TRIG 0x00000079
+#endif
+#ifndef EFI_MSR_IA32_BIOS_SIGN_ID
+#define EFI_MSR_IA32_BIOS_SIGN_ID 0x0000008B
+#endif
+
+#define EFI_MSR_PMG_CST_CONFIG 0x000000E2
+#define B_EFI_MSR_PMG_CST_CONFIG_CST_CONTROL_LOCK BIT15
+#define B_EFI_MSR_PMG_CST_CONFIG_IO_MWAIT_REDIRECTION_ENABLE BIT10
+#define B_EFI_MSR_PMG_CST_CONFIG_PACKAGE_C_STATE_LIMIT (BIT2 | BIT1 | BIT0)
+
+#define EFI_MSR_PMG_IO_CAPTURE_ADDR 0x000000E4 //For Nehalem Spec: EFI_IA32_PMG_IO_CAPTURE_BASE
+#define N_EFI_MSR_PMG_IO_CAPTURE_ADDR_CST_RANGE 16
+#define B_EFI_MSR_PMG_IO_CAPTURE_ADDR_LVL_2_BASE_ADDRESS_MASK 0xFFFF
+
+#define EFI_MSR_IA32_MPERF 0x000000E7
+#define EFI_MSR_IA32_APERF 0x000000E8
+
+#define EFI_MSR_IA32_MTRR_CAP 0x000000FE
+#define B_EFI_MSR_IA32_MTRR_CAP_EMRR_SUPPORT BIT12
+#define B_EFI_MSR_IA32_MTRR_CAP_SMRR_SUPPORT BIT11
+#define B_EFI_MSR_IA32_MTRR_CAP_WC_SUPPORT BIT10
+#define B_EFI_MSR_IA32_MTRR_CAP_FIXED_SUPPORT BIT8
+#define B_EFI_MSR_IA32_MTRR_CAP_VARIABLE_SUPPORT (BIT7 | BIT6 | BIT5 | BIT4 | BIT3 | BIT2 | BIT1 | BIT0)
+
+#define EFI_MSR_IA32_MCG_CAP 0x00000179
+#define EFI_MSR_IA32_MCG_STATUS 0x0000017A
+
+#define EFI_MSR_IA32_PERF_STS 0x00000198
+#define EFI_MSR_IA32_PERF_CTRL 0x00000199
+
+#ifndef EFI_MSR_IA32_THERM_INTERRUPT
+#define EFI_MSR_IA32_THERM_INTERRUPT 0x0000019B
+#endif
+
+#define B_EFI_MSR_IA32_THERM_INTERRUPT_VIE BIT4
+
+#ifndef EFI_MSR_IA32_THERM_STATUS
+#define EFI_MSR_IA32_THERM_STATUS 0x0000019C
+#endif
+
+#ifndef EFI_MSR_IA32_MISC_ENABLE
+#define EFI_MSR_IA32_MISC_ENABLE 0x000001A0
+#endif
+
+#define B_EFI_MSR_IA32_MISC_ENABLE_XD BIT34
+#define B_EFI_MSR_IA32_MISC_ENABLE_CPUID_MAX BIT22
+#define B_EFI_MSR_IA32_MISC_ENABLE_MONITOR BIT18
+#define B_EFI_MSR_IA32_MISC_ENABLE_TM1_EN BIT3
+
+#define EFI_MSR_SMRR_PHYS_BASE 0x000001F2
+#define EFI_MSR_SMRR_PHYS_MASK 0x000001F3
+
+#define EFI_MSR_CACHE_VARIABLE_MTRR_BASE 0x00000200
+#define EFI_MSR_CACHE_VARIABLE_MTRR_END 0x0000020F
+#define V_EFI_FIXED_MTRR_NUMBER 11
+
+#define EFI_MSR_IA32_MTRR_FIX64K_00000 0x00000250
+#define EFI_MSR_IA32_MTRR_FIX16K_80000 0x00000258
+#define EFI_MSR_IA32_MTRR_FIX16K_A0000 0x00000259
+#define EFI_MSR_IA32_MTRR_FIX4K_C0000 0x00000268
+#define EFI_MSR_IA32_MTRR_FIX4K_C8000 0x00000269
+#define EFI_MSR_IA32_MTRR_FIX4K_D0000 0x0000026A
+#define EFI_MSR_IA32_MTRR_FIX4K_D8000 0x0000026B
+#define EFI_MSR_IA32_MTRR_FIX4K_E0000 0x0000026C
+#define EFI_MSR_IA32_MTRR_FIX4K_E8000 0x0000026D
+#define EFI_MSR_IA32_MTRR_FIX4K_F0000 0x0000026E
+#define EFI_MSR_IA32_MTRR_FIX4K_F8000 0x0000026F
+#define EFI_MSR_CACHE_IA32_MTRR_DEF_TYPE 0x000002FF
+#define B_EFI_MSR_CACHE_MTRR_VALID BIT11
+#define B_EFI_MSR_GLOBAL_MTRR_ENABLE BIT11
+#define B_EFI_MSR_FIXED_MTRR_ENABLE BIT10
+#define B_EFI_MSR_CACHE_MEMORY_TYPE (BIT2 | BIT1 | BIT0)
+
+#define EFI_MSR_VALID_MASK 0xFFFFFFFFF
+#define EFI_CACHE_VALID_ADDRESS 0xFFFFFF000
+#define EFI_SMRR_CACHE_VALID_ADDRESS 0xFFFFF000
+#define EFI_CACHE_VALID_EXTENDED_ADDRESS 0xFFFFFFFFFF000
+
+// Leave one MTRR pairs for OS use
+#define EFI_CACHE_NUM_VAR_MTRR_PAIRS_FOR_OS 1
+#define EFI_CACHE_LAST_VARIABLE_MTRR_FOR_BIOS (EFI_MSR_CACHE_VARIABLE_MTRR_END) - \
+ (EFI_CACHE_NUM_VAR_MTRR_PAIRS_FOR_OS * 2)
+
+#define EFI_MSR_IA32_MC0_CTL 0x00000400
+#define EFI_MSR_IA32_MC0_STATUS 0x00000401
+#define EFI_MSR_IA32_MC0_ADDR 0x00000402
+#define EFI_MSR_IA32_MC0_MISC 0x00000403
+#define EFI_MSR_IA32_MC8_CTL (EFI_IA32_MC0_CTL + (8*4))
+#define EFI_MSR_IA32_MC8_STATUS (EFI_IA32_MC0_STATUS + (8*4))
+
+#define EFI_MSR_APIC_GLOBAL_ENABLE 0x00000800
+#define EFI_MSR_EXT_XAPIC_LOGICAL_APIC_ID 0x00000802
+#define EFI_MSR_EXT_XAPIC_VERSION 0x00000803
+#define B_EFI_MSR_EXT_XAPIC_VERSION_VERSION 0xFF
+#define EFI_MSR_EXT_XAPIC_SVR 0x0000080F
+#define EFI_MSR_EXT_XAPIC_ICR 0x00000830
+#define EFI_MSR_EXT_XAPIC_LVT_LINT0 0x00000835
+#define EFI_MSR_EXT_XAPIC_LVT_LINT1 0x00000836
+
+#define EFI_MSR_IA32_EFER 0xC0000080
+#define B_EFI_MSR_IA32_EFER_NXE BIT11
+#define B_EFI_MSR_IA32_EFER_LMA BIT10
+#define B_EFI_MSR_IA32_EFER_LME BIT8
+#define B_EFI_MSR_IA32_EFER_SCE BIT0
+
+#pragma pack(1)
+
+typedef enum {
+ EnumCpuUarchUnknown = 0,
+ EnumNehalemUarch,
+} EFI_CPU_UARCH;
+
+typedef enum {
+ EnumCpuPlatformUnknown = 0,
+ EnumDesktop,
+ EnumMobile,
+ EnumServer,
+ EnumNetTop
+} EFI_CPU_PLATFORM;
+
+typedef enum {
+ EnumCpuTypeUnknown = 0,
+ EnumAtom,
+ EnumNehalemEx,
+ EnumBloomfield,
+ EnumGainestown,
+ EnumHavendale,
+ EnumLynnfield,
+ EnumAuburndale,
+ EnumClarksfield,
+ EnumPineview,
+ EnumCedarview,
+ EnumValleyview,
+ EnumClarkdale // Havendale 32nm
+} EFI_CPU_TYPE;
+
+typedef enum {
+ EnumCpuFamilyUnknown = 0,
+ EnumFamilyField,
+ EnumFamilyDale
+} EFI_CPU_FAMILY;
+
+#pragma pack()
+
+#endif
diff --git a/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/CpuInit/Exception.h b/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/CpuInit/Exception.h
new file mode 100644
index 0000000000..695670458a
--- /dev/null
+++ b/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/CpuInit/Exception.h
@@ -0,0 +1,71 @@
+/** @file
+ IA32 Exception Includes.
+
+ Copyright (c) 1999 - 2015, 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 _IA32EXCEPTION_H
+#define _IA32EXCEPTION_H
+
+//
+// Driver Consumed Protocol Prototypes
+//
+#include <Protocol/Cpu.h>
+
+#define EFI_STATUS_CODE_DATA_TYPE_EXCEPTION_HANDLER_GUID \
+ { \
+ 0x3BC2BD12, 0xAD2E, 0x11D5, {0x87, 0xDD, 0x00, 0x06, 0x29, 0x45, 0xC3, 0xB9} \
+ }
+
+#define INTERRUPT_HANDLER_DIVIDE_ZERO 0x00
+#define INTERRUPT_HANDLER_DEBUG 0x01
+#define INTERRUPT_HANDLER_NMI 0x02
+#define INTERRUPT_HANDLER_BREAKPOINT 0x03
+#define INTERRUPT_HANDLER_OVERFLOW 0x04
+#define INTERRUPT_HANDLER_BOUND 0x05
+#define INTERRUPT_HANDLER_INVALID_OPCODE 0x06
+#define INTERRUPT_HANDLER_DEVICE_NOT_AVAILABLE 0x07
+#define INTERRUPT_HANDLER_DOUBLE_FAULT 0x08
+#define INTERRUPT_HANDLER_COPROCESSOR_OVERRUN 0x09
+#define INTERRUPT_HANDLER_INVALID_TSS 0x0A
+#define INTERRUPT_HANDLER_SEGMENT_NOT_PRESENT 0x0B
+#define INTERRUPT_HANDLER_STACK_SEGMENT_FAULT 0x0C
+#define INTERRUPT_HANDLER_GP_FAULT 0x0D
+#define INTERRUPT_HANDLER_PAGE_FAULT 0x0E
+#define INTERRUPT_HANDLER_RESERVED 0x0F
+#define INTERRUPT_HANDLER_MATH_FAULT 0x10
+#define INTERRUPT_HANDLER_ALIGNMENT_FAULT 0x11
+#define INTERRUPT_HANDLER_MACHINE_CHECK 0x12
+#define INTERRUPT_HANDLER_STREAMING_SIMD 0x13
+/**
+ @todo add structure description
+
+**/
+typedef struct {
+ EFI_STATUS_CODE_DATA Header;
+ union {
+ EFI_SYSTEM_CONTEXT_IA32 SystemContextIa32;
+ EFI_SYSTEM_CONTEXT_X64 SystemContextX64;
+ } SystemContext;
+} CPU_STATUS_CODE_TEMPLATE;
+
+VOID
+EFIAPI
+CommonExceptionHandler (
+ IN EFI_EXCEPTION_TYPE InterruptType,
+ IN EFI_SYSTEM_CONTEXT SystemContext
+ );
+
+EFI_STATUS
+InitializeException (
+ IN EFI_CPU_ARCH_PROTOCOL *CpuProtocol
+ );
+#endif
diff --git a/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/CpuInit/Ia32/CpuAsm.asm b/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/CpuInit/Ia32/CpuAsm.asm
new file mode 100644
index 0000000000..dfc81eeed8
--- /dev/null
+++ b/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/CpuInit/Ia32/CpuAsm.asm
@@ -0,0 +1,693 @@
+;; @file
+; Assembly code that supports IA32 CPU architectural protocol
+;
+; Copyright (c) 1999 - 2015, 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.
+;;
+ page ,132
+ title CPU ARCHITECTURAL DXE PROTOCOL ASSEMBLY HOOKS
+.686p
+.model flat
+
+.data
+ExternalVectorTablePtr DD ? ; Table of call backs
+CommonInterruptEntry DD CommonEntry ; Address of CommonEntry
+Idtr DW ? ; FWORD for IDT register
+Idtr1 DD ? ; MUST BE IMMEDIATELY AFTER Idtr
+
+EXTRN _mErrorCodeFlag:DWORD ; Error code flags for exceptions
+
+.stack
+.code
+.MMX
+.XMM
+
+include Htequ.inc
+
+UINT8 TYPEDEF BYTE
+UINT16 TYPEDEF WORD
+UINT32 TYPEDEF DWORD
+UINT64 TYPEDEF QWORD
+UINTN TYPEDEF UINT32
+
+;---------------------------------------;
+; _InitializeIdt ;
+;----------------------------------------------------------------------------;
+;
+; Protocol prototype
+; InitializeIdt (
+; IN EFI_CPU_INTERRUPT_HANDLER TableStart,
+; IN UINTN *IdtTablePtr,
+; IN UINT16 IdtLimit
+; )
+;
+; Routine Description:
+;
+; Creates an IDT table starting at IdtTablPtr. It has IdtLimit/8 entries.
+; Table is initialized to intxx where xx is from 00 to number of entries or
+; 100h, whichever is smaller. After table has been initialized the LIDT
+; instruction is invoked.
+;
+; TableStart is the pointer to the callback table and is not used by
+; InitializedIdt but by commonEntry. CommonEntry handles all interrupts,
+; does the context save and calls the callback entry, if non-NULL.
+; It is the responsibility of the callback routine to do hardware EOIs.
+;
+; Arguments:
+;
+; TableStart - Pointer to interrupt callback table
+;
+; IdtTablePtr - Pointer to IDT table
+;
+; IdtLimit - IDT Table limit = number of interrupt entries * 8
+;
+; Returns:
+;
+; Nothing
+;
+;
+; Input: [ebp][0] = Original ebp
+; [ebp][4] = Return address
+; [ebp][8] = TableStart
+; [ebp][0c] = *IdtTablePtr
+; [ebp][10] = IdtLimit
+;
+; Output: Nothing
+;
+; Destroys: Nothing
+;-----------------------------------------------------------------------------;
+
+_InitializeIdt proc near public
+ push ebp ; C prolog
+ mov ebp, esp
+ push edi
+
+ mov eax, [ebp+8] ; Get ExternalVectorTable Address
+ mov ExternalVectorTablePtr, eax
+
+ mov ax, [ebp+10h] ; Get IDT Table limit
+ dec ax
+ mov Idtr, ax
+
+ mov eax, [ebp+0ch] ; Get Start of IDT
+ mov Idtr1, eax
+
+ mov edi, OFFSET Idtr ; Load IDT register
+ lidt FWORD PTR es:[edi]
+
+ pop edi
+ pop ebp
+ ret
+_InitializeIdt endp
+
+;----------------------------------------------------------------------------;
+;
+; Protocol prototype
+; None
+;
+; Routine Description:
+;
+; These routines handle the individual interrupts. These routines always
+; gain control on any interrupt or exception. They save EAX and place
+; the interrupt number in EAX. CommonEntry is then jumped to.
+; instruction is invoked.
+;
+; CommonEntry handles all interrupts,does the context save and calls the
+; callback entry, if non-NULL. It is the responsibility of the callback
+; routine to do hardware EOIs. Callbacks are entered into the table
+; located at TableStart. Entries are modified by the InstallInterruptHandler
+; and UninstallInterruptHandler protocols.
+;
+; Arguments to CommonEntry:
+;
+; EAX - Interrupt or exception number
+;
+; TableStart - Pointer to interrupt callback table
+;
+; Returns:
+;
+; Nothing
+;
+;
+; Output: Nothing
+;
+; Destroys: Nothing
+;-----------------------------------------------------------------------------;
+
+TemplateStart:
+ push eax
+
+ ;mov eax, 0nnh (nn stands for vector number, which will be fixed at runtime
+ DB 0b8h
+VectorNumber:
+ DD 00h
+
+ jmp dword ptr [CommonInterruptEntry];
+TemplateEnd:
+
+CommonEntry:
+
+;---------------------------------------;
+; _CommonEntry ;
+;----------------------------------------------------------------------------;
+; The follow algorithm is used for the common interrupt routine.
+; Entry from each interrupt with a push eax and eax=interrupt number
+
+;
+; +---------------------+
+; + EFlags +
+; +---------------------+
+; + CS +
+; +---------------------+
+; + EIP +
+; +---------------------+
+; + Error Code +
+; +---------------------+
+; + EAX / Vector Number +
+; +---------------------+
+; + EBP +
+; +---------------------+ <-- EBP
+;
+
+ cli
+ ;
+ ; All interrupt handlers are invoked through interrupt gates, so
+ ; IF flag automatically cleared at the entry point
+ ;
+ cmp eax, 32 ; Intel reserved vector for exceptions?
+ jae NoErrorCode
+ bt cs:_mErrorCodeFlag, eax
+ jc @F
+
+NoErrorCode:
+ ;
+ ; Push a dummy error code on the stack
+ ; to maintain coherent stack map
+ ;
+ push [esp]
+ mov dword ptr [esp + 4], 0
+@@:
+ push ebp
+ mov ebp, esp
+
+ ;
+ ; Align stack to make sure that EFI_FX_SAVE_STATE_IA32 of EFI_SYSTEM_CONTEXT_IA32
+ ; is 16-byte aligned
+ ;
+ and esp, 0fffffff0h
+ sub esp, 12
+
+;; UINT32 Edi, Esi, Ebp, Esp, Ebx, Edx, Ecx, Eax;
+ push dword ptr [ebp + 4] ; EAX
+ push ecx
+ push edx
+ push ebx
+ lea ecx, [ebp + 24]
+ push ecx ; ESP
+ push dword ptr [ebp] ; EBP
+ push esi
+ push edi
+
+ mov [ebp + 4], eax ; save vector number
+
+;; UINT32 Gs, Fs, Es, Ds, Cs, Ss;
+ mov eax, ss
+ push eax
+ movzx eax, word ptr [ebp + 16]
+ push eax
+ mov eax, ds
+ push eax
+ mov eax, es
+ push eax
+ mov eax, fs
+ push eax
+ mov eax, gs
+ push eax
+
+;; UINT32 Eip;
+ push dword ptr [ebp + 12]
+
+;; UINT32 Gdtr[2], Idtr[2];
+ sub esp, 8
+ sidt fword ptr [esp]
+ sub esp, 8
+ sgdt fword ptr [esp]
+
+;; UINT32 Ldtr, Tr;
+ xor eax, eax
+ str ax
+ push eax
+ sldt ax
+ push eax
+
+;; UINT32 EFlags;
+ push dword ptr [ebp + 20]
+
+;; UINT32 Cr0, Cr1, Cr2, Cr3, Cr4;
+ mov eax, cr4
+ or eax, 208h
+ mov cr4, eax
+ push eax
+ mov eax, cr3
+ push eax
+ mov eax, cr2
+ push eax
+ xor eax, eax
+ push eax
+ mov eax, cr0
+ push eax
+
+;; UINT32 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7;
+ mov eax, dr7
+ push eax
+;; clear Dr7 while executing debugger itself
+ xor eax, eax
+ mov dr7, eax
+
+ mov eax, dr6
+ push eax
+;; insure all status bits in dr6 are clear...
+ xor eax, eax
+ mov dr6, eax
+
+ mov eax, dr3
+ push eax
+ mov eax, dr2
+ push eax
+ mov eax, dr1
+ push eax
+ mov eax, dr0
+ push eax
+
+;; FX_SAVE_STATE_IA32 FxSaveState;
+ sub esp, 512
+ mov edi, esp
+ db 0fh, 0aeh, 00000111y ;fxsave [edi]
+
+;; UINT32 ExceptionData;
+ push dword ptr [ebp + 8]
+
+;; call into exception handler
+ mov ebx, [ebp + 4]
+ mov eax, ExternalVectorTablePtr
+ mov eax, [eax + ebx * 4]
+ or eax, eax ; NULL?
+ je nonNullValue;
+
+;; Prepare parameter and call
+ mov edx, esp
+ push edx
+ push ebx
+ call eax
+ add esp, 8
+
+nonNullValue:
+ cli
+;; UINT32 ExceptionData;
+ add esp, 4
+
+;; FX_SAVE_STATE_IA32 FxSaveState;
+ mov esi, esp
+ db 0fh, 0aeh, 00001110y ; fxrstor [esi]
+ add esp, 512
+
+;; UINT32 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7;
+ pop eax
+ mov dr0, eax
+ pop eax
+ mov dr1, eax
+ pop eax
+ mov dr2, eax
+ pop eax
+ mov dr3, eax
+;; skip restore of dr6. We cleared dr6 during the context save.
+ add esp, 4
+ pop eax
+ mov dr7, eax
+
+;; UINT32 Cr0, Cr1, Cr2, Cr3, Cr4;
+ pop eax
+ mov cr0, eax
+ add esp, 4 ; not for Cr1
+ pop eax
+ mov cr2, eax
+ pop eax
+ mov cr3, eax
+ pop eax
+ mov cr4, eax
+
+;; UINT32 EFlags;
+ pop dword ptr [ebp + 20]
+
+;; UINT32 Ldtr, Tr;
+;; UINT32 Gdtr[2], Idtr[2];
+;; Best not let anyone mess with these particular registers...
+ add esp, 24
+
+;; UINT32 Eip;
+ pop dword ptr [ebp + 12]
+
+;; UINT32 Gs, Fs, Es, Ds, Cs, Ss;
+;; NOTE - modified segment registers could hang the debugger... We
+;; could attempt to insulate ourselves against this possibility,
+;; but that poses risks as well.
+;;
+ pop gs
+ pop fs
+ pop es
+ pop ds
+ pop dword ptr [ebp + 16]
+ pop ss
+
+;; UINT32 Edi, Esi, Ebp, Esp, Ebx, Edx, Ecx, Eax;
+ pop edi
+ pop esi
+ add esp, 4 ; not for ebp
+ add esp, 4 ; not for esp
+ pop ebx
+ pop edx
+ pop ecx
+ pop eax
+
+ mov esp, ebp
+ pop ebp
+ add esp, 8
+ iretd
+
+
+;---------------------------------------;
+; _GetTemplateAddressMap ;
+;----------------------------------------------------------------------------;
+;
+; Protocol prototype
+; GetTemplateAddressMap (
+; INTERRUPT_HANDLER_TEMPLATE_MAP *AddressMap
+; );
+;
+; Routine Description:
+;
+; Return address map of interrupt handler template so that C code can generate
+; interrupt handlers, and dynamically do address fix.
+;
+; Arguments:
+;
+;
+; Returns:
+;
+; Nothing
+;
+;
+; Input: [ebp][0] = Original ebp
+; [ebp][4] = Return address
+;
+; Output: Nothing
+;
+; Destroys: Nothing
+;-----------------------------------------------------------------------------;
+_GetTemplateAddressMap proc near public
+ push ebp ; C prolog
+ mov ebp, esp
+ pushad
+
+ mov ebx, dword ptr [ebp+08h]
+ mov dword ptr [ebx], TemplateStart
+ mov dword ptr [ebx+4h], TemplateEnd - TemplateStart
+
+ ; if code in Template is updated, the value fills into the 3rd parameter
+ ; also needs update
+ mov dword ptr [ebx+8h], VectorNumber - TemplateStart
+
+ popad
+ pop ebp
+ ret
+_GetTemplateAddressMap endp
+
+
+
+;---------------------------------------;
+; _InitializeSelectors ;
+;----------------------------------------------------------------------------;
+;
+; Protocol prototype
+; InitializeSelectors (
+; )
+;
+; Routine Description:
+;
+; Creates an new GDT in RAM. The problem is that our former selectors
+; were ROM based and the EFI OS Loader does not manipulate the machine state
+; to change them (as it would for a 16-bit PC/AT startup code that had to
+; go from Real Mode to flat mode).
+;
+; Arguments:
+;
+;
+; Returns:
+;
+; Nothing
+;
+;
+; Input: [ebp][0] = Original ebp
+; [ebp][4] = Return address
+;
+; Output: Nothing
+;
+; Destroys: Nothing
+;-----------------------------------------------------------------------------;
+
+CODE_SELECTOR EQU 10h
+DATA_SELECTOR EQU 18h
+
+_InitializeSelectors proc near public
+ push ebp ; C prolog
+ mov ebp, esp
+ pushad
+ mov edi, OFFSET Gdtr ; Load GDT register
+
+ mov ax,cs ; Get the selector data from our code image
+ mov es,ax
+ lgdt FWORD PTR es:[edi] ; and update the GDTR
+
+ db 067h
+ db 0eah ; Far Jump Offset:Selector to reload CS
+ dd OFFSET SelectorRld; Offset is ensuing instruction boundary
+ dw CODE_SELECTOR ; Selector is our code selector, 10h
+SelectorRld::
+ mov ax, DATA_SELECTOR ; Update the Base for the new selectors, too
+ mov ds, ax
+ mov es, ax
+ mov fs, ax
+ mov gs, ax
+ mov ss, ax
+
+ popad
+ pop ebp
+ ret
+_InitializeSelectors endp
+
+;------------------------------------------------------------------------------
+; VOID
+; CpuEnableInterrupt (
+; VOID
+; )
+;------------------------------------------------------------------------------
+CpuEnableInterrupt PROC C PUBLIC
+ sti
+ ret
+CpuEnableInterrupt ENDP
+
+
+;------------------------------------------------------------------------------
+; VOID
+; CpuDisableInterrupt (
+; VOID
+; )
+;------------------------------------------------------------------------------
+CpuDisableInterrupt PROC C PUBLIC
+ cli
+ ret
+CpuDisableInterrupt ENDP
+
+;------------------------------------------------------------------------------
+; VOID
+; CpuInitFloatPointUnit (
+; VOID
+; )
+;------------------------------------------------------------------------------
+CpuInitFloatPointUnit PROC C PUBLIC
+ finit
+ ret
+CpuInitFloatPointUnit ENDP
+
+;------------------------------------------------------------------------------
+; UINT16
+; GetCodeSegment (
+; VOID
+; )
+;------------------------------------------------------------------------------
+GetCodeSegment PROC C PUBLIC
+ mov ax,cs
+ ret
+GetCodeSegment ENDP
+
+
+;------------------------------------------------------------------------------
+; VOID
+; EfiWbinvd (
+; VOID
+; )
+;------------------------------------------------------------------------------
+EfiWbinvd PROC PUBLIC
+ wbinvd
+ ret
+EfiWbinvd ENDP
+
+
+;------------------------------------------------------------------------------
+; VOID
+; EfiInvd (
+; VOID
+; )
+;------------------------------------------------------------------------------
+EfiInvd PROC PUBLIC
+ invd
+ ret
+EfiInvd ENDP
+
+;------------------------------------------------------------------------------
+; VOID
+; GetIdt (
+; IDT_INFORMATION *IdtInfo
+; )
+;------------------------------------------------------------------------------
+_GetIdt proc near public
+ push ebp ; C prolog
+
+ mov ebp, esp
+ mov eax, [ebp+8]
+ sidt FWORD PTR [eax]
+
+ pop ebp
+ ret
+_GetIdt ENDP
+
+GetCoreNumber PROC C PUBLIC
+
+ push ebx
+
+ mov eax, 4
+ mov ecx, 0
+ cpuid
+
+ shr eax, 26
+ and eax, 3fh
+ inc al
+
+ pop ebx
+
+ ret
+
+GetCoreNumber ENDP
+
+
+;-----------------------------------------------------------------------------;
+; data
+;-----------------------------------------------------------------------------;
+
+ align 16
+
+gdtr dw GDT_END - GDT_BASE - 1 ; GDT limit
+ dd OFFSET GDT_BASE ; (GDT base gets set above)
+
+;-----------------------------------------------------------------------------;
+; global descriptor table (GDT)
+;-----------------------------------------------------------------------------;
+
+ align 16
+
+public GDT_BASE
+GDT_BASE:
+; null descriptor
+NULL_SEL equ $-GDT_BASE ; Selector [0]
+ dw 0 ; limit 15:0
+ dw 0 ; base 15:0
+ db 0 ; base 23:16
+ db 0 ; type
+ db 0 ; limit 19:16, flags
+ db 0 ; base 31:24
+
+; linear data segment descriptor
+LINEAR_SEL equ $-GDT_BASE ; Selector [0x8]
+ dw 0FFFFh ; limit 0xFFFFF
+ dw 0 ; base 0
+ db 0
+ db 092h ; present, ring 0, data, expand-up, writable
+ db 0CFh ; page-granular, 32-bit
+ db 0
+
+; linear code segment descriptor
+LINEAR_CODE_SEL equ $-GDT_BASE ; Selector [0x10]
+ dw 0FFFFh ; limit 0xFFFFF
+ dw 0 ; base 0
+ db 0
+ db 09Ah ; present, ring 0, data, expand-up, writable
+ db 0CFh ; page-granular, 32-bit
+ db 0
+
+; system data segment descriptor
+SYS_DATA_SEL equ $-GDT_BASE ; Selector [0x18]
+ dw 0FFFFh ; limit 0xFFFFF
+ dw 0 ; base 0
+ db 0
+ db 092h ; present, ring 0, data, expand-up, writable
+ db 0CFh ; page-granular, 32-bit
+ db 0
+
+; system code segment descriptor
+SYS_CODE_SEL equ $-GDT_BASE
+ dw 0FFFFh ; limit 0xFFFFF
+ dw 0 ; base 0
+ db 0
+ db 09Ah ; present, ring 0, data, expand-up, writable
+ db 0CFh ; page-granular, 32-bit
+ db 0
+
+; spare segment descriptor
+SPARE3_SEL equ $-GDT_BASE
+ dw 0 ; limit 0xFFFFF
+ dw 0 ; base 0
+ db 0
+ db 0 ; present, ring 0, data, expand-up, writable
+ db 0 ; page-granular, 32-bit
+ db 0
+
+; spare segment descriptor
+SPARE4_SEL equ $-GDT_BASE
+ dw 0 ; limit 0xFFFFF
+ dw 0 ; base 0
+ db 0
+ db 0 ; present, ring 0, data, expand-up, writable
+ db 0 ; page-granular, 32-bit
+ db 0
+
+; spare segment descriptor
+SPARE5_SEL equ $-GDT_BASE
+ dw 0 ; limit 0xFFFFF
+ dw 0 ; base 0
+ db 0
+ db 0 ; present, ring 0, data, expand-up, writable
+ db 0 ; page-granular, 32-bit
+ db 0
+
+GDT_END:
+
+
+ end
+
diff --git a/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/CpuInit/Ia32/CpuAsm.s b/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/CpuInit/Ia32/CpuAsm.s
new file mode 100644
index 0000000000..9b62ca1688
--- /dev/null
+++ b/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/CpuInit/Ia32/CpuAsm.s
@@ -0,0 +1,761 @@
+## @file
+# Assembly code that supports IA32 CPU architectural protocol.
+#
+# Copyright (c) 1999 - 2015, 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
+#
+##
+
+.data
+
+ExternalVectorTablePtr: .space 4
+CommonInterruptEntry: .long CommonEntry
+Idtr: .space 2
+Idtr1: .space 4
+
+##include Htequ.inc
+
+.equ VacantFlag , 0x00
+.equ NotVacantFlag , 0xff
+.equ StartupApSignal , 0x6E750000
+.equ MonitorFilterSize, 0x10
+.equ ApCounterInit , 0
+.equ ApInHltLoop , 1
+.equ ApInMwaitLoop , 2
+.equ ApInRunLoop , 3
+
+.equ LockLocation , 0x1000 - 0x0400
+.equ StackStart , LockLocation + 0x4
+.equ StackSize , LockLocation + 0x8
+.equ RendezvousProc , LockLocation + 0x0C
+.equ GdtrProfile , LockLocation + 0x10
+.equ IdtrProfile , LockLocation + 0x16
+.equ BufferStart , LockLocation + 0x1C
+.equ Cr3Location , LockLocation + 0x20
+.equ InitFlag , LockLocation + 0x24
+.equ WakeUpApManner , LockLocation + 0x28
+.equ BistBuffer , LockLocation + 0x2C
+
+.macro PAUSE32
+ .byte 0xF3
+ .byte 0x90
+.endm
+
+.text
+
+#---------------------------------------#
+# _InitializeIdt #
+#----------------------------------------------------------------------------#
+#
+# Protocol prototype
+# InitializeIdt (
+# IN EFI_CPU_INTERRUPT_HANDLER TableStart,
+# IN UINTN *IdtTablePtr,
+# IN UINT16 IdtLimit
+# )
+#
+# Routine Description:
+#
+# Creates an IDT table starting at IdtTablPtr. It has IdtLimit/8 entries.
+# Table is initialized to intxx where xx is from 00 to number of entries or
+# 100h, whichever is smaller. After table has been initialized the LIDT
+# instruction is invoked.
+#
+# TableStart is the pointer to the callback table and is not used by
+# InitializedIdt but by commonEntry. CommonEntry handles all interrupts,
+# does the context save and calls the callback entry, if non-NULL.
+# It is the responsibility of the callback routine to do hardware EOIs.
+#
+# Arguments:
+#
+# TableStart - Pointer to interrupt callback table
+#
+# IdtTablePtr - Pointer to IDT table
+#
+# IdtLimit - IDT Table limit = number of interrupt entries * 8
+#
+# Returns:
+#
+# Nothing
+#
+#
+# Input: [ebp][0] = Original ebp
+# [ebp][4] = Return address
+# [ebp][8] = TableStart
+# [ebp][0c] = *IdtTablePtr
+# [ebp][10] = IdtLimit
+#
+# Output: Nothing
+#
+# Destroys: Nothing
+#-----------------------------------------------------------------------------#
+
+ASM_GLOBAL ASM_PFX(InitializeIdt)
+ASM_PFX(InitializeIdt):
+ pushl %ebp # C prolog
+ movl %esp,%ebp
+ pushl %edi
+
+ movl 8(%ebp),%eax # Get ExternalVectorTable Address
+ movl %eax, ExternalVectorTablePtr
+
+ movw 0x10(%ebp),%ax # Get IDT Table limit
+ decw %ax
+ movw %ax, Idtr # Store %ax to Idtr
+
+ movl 0xc(%ebp),%eax # Get Start of IDT
+ movl %eax, Idtr1
+
+ movl $Idtr, %edi # Addr of Idtr -> %edi
+ lidt %es:(%edi)
+
+ popl %edi
+ popl %ebp
+ ret
+
+#----------------------------------------------------------------------------#
+#
+# Protocol prototype
+# None
+#
+# Routine Description:
+#
+# These routines handle the individual interrupts. These routines always
+# gain control on any interrupt or exception. They save EAX and place
+# the interrupt number in EAX. CommonEntry is then jumped to.
+# instruction is invoked.
+#
+# CommonEntry handles all interrupts,does the context save and calls the
+# callback entry, if non-NULL. It is the responsibility of the callback
+# routine to do hardware EOIs. Callbacks are entered into the table
+# located at TableStart. Entries are modified by the InstallInterruptHandler
+# and UninstallInterruptHandler protocols.
+#
+# Arguments to CommonEntry:
+#
+# EAX - Interrupt or exception number
+#
+# TableStart - Pointer to interrupt callback table
+#
+# Returns:
+#
+# Nothing
+#
+#
+# Output: Nothing
+#
+# Destroys: Nothing
+#-----------------------------------------------------------------------------#
+
+TemplateStart:
+ pushl %eax
+
+ #mov eax, 0nnh (nn stands for vector number, which will be fixed at runtime
+ .byte 0xb8
+VectorNumber:
+ .long 0x0
+
+ jmp *CommonInterruptEntry
+TemplateEnd:
+
+CommonEntry:
+
+#---------------------------------------#
+# _CommonEntry #
+#----------------------------------------------------------------------------#
+# The follow algorithm is used for the common interrupt routine.
+# Entry from each interrupt with a push eax and eax=interrupt number
+
+#
+# +---------------------+
+# + EFlags +
+# +---------------------+
+# + CS +
+# +---------------------+
+# + EIP +
+# +---------------------+
+# + Error Code +
+# +---------------------+
+# + EAX / Vector Number +
+# +---------------------+
+# + EBP +
+# +---------------------+ <-- EBP
+#
+
+ cli
+ #
+ # All interrupt handlers are invoked through interrupt gates, so
+ # IF flag automatically cleared at the entry point
+ #
+ cmpl $32,%eax # Intel reserved vector for exceptions?
+ jae NoErrorCode
+ btl %eax, %cs:ASM_PFX(mErrorCodeFlag)
+ jc L1
+
+NoErrorCode:
+ #
+ # Push a dummy error code on the stack
+ # to maintain coherent stack map
+ #
+ pushl (%esp) # Push the value %esp pointing to
+ movl $0, 4(%esp)
+L1:
+ pushl %ebp
+ movl %esp,%ebp
+
+ #
+ # Align stack to make sure that EFI_FX_SAVE_STATE_IA32 of EFI_SYSTEM_CONTEXT_IA32
+ # is 16-byte aligned
+ #
+ andl $0xfffffff0,%esp
+ subl $12,%esp
+
+## UINT32 Edi, Esi, Ebp, Esp, Ebx, Edx, Ecx, Eax#
+ pushl 0x4(%ebp)
+ pushl %ecx
+ pushl %edx
+ pushl %ebx
+ leal 24(%ebp),%ecx
+ pushl %ecx # ESP
+ pushl (%ebp)
+ pushl %esi
+ pushl %edi
+
+ movl %eax,4(%ebp) # save vector number
+
+## UINT32 Gs, Fs, Es, Ds, Cs, Ss#
+ movl %ss,%eax
+ pushl %eax
+ movzwl 16(%ebp), %eax
+ pushl %eax
+ movl %ds,%eax
+ pushl %eax
+ movl %es,%eax
+ pushl %eax
+ movl %fs,%eax
+ pushl %eax
+ movl %gs,%eax
+ pushl %eax
+
+## UINT32 Eip#
+ pushl 12(%ebp)
+
+## UINT32 Gdtr[2], Idtr[2]#
+ subl $8,%esp
+ sidt (%esp)
+ subl $8,%esp
+ sgdt (%esp)
+
+## UINT32 Ldtr, Tr#
+ xorl %eax,%eax
+ strl %eax
+ pushl %eax
+ sldtl %eax
+ pushl %eax
+
+## UINT32 EFlags#
+ pushl 20(%ebp)
+
+## UINT32 Cr0, Cr1, Cr2, Cr3, Cr4#
+ movl %cr4, %eax
+ orl $0x208,%eax
+ movl %eax, %cr4
+ pushl %eax
+ movl %cr3, %eax
+ pushl %eax
+ movl %cr2, %eax
+ pushl %eax
+ xorl %eax,%eax
+ pushl %eax
+ movl %cr0, %eax
+ pushl %eax
+
+## UINT32 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7#
+ movl %dr7, %eax
+ pushl %eax
+## clear Dr7 while executing debugger itself
+ xorl %eax, %eax
+ movl %eax, %dr7
+
+ movl %dr6, %eax
+ pushl %eax
+## insure all status bits in dr6 are clear...
+ xorl %eax, %eax
+ movl %eax, %dr6
+
+ movl %dr3, %eax
+ pushl %eax
+ movl %dr2, %eax
+ pushl %eax
+ movl %dr1, %eax
+ pushl %eax
+ movl %dr0, %eax
+ pushl %eax
+
+## FX_SAVE_STATE_IA32 FxSaveState#
+ subl $512, %esp
+ movl %esp, %edi
+ .byte 0x0f, 0xae, 0x07
+
+## UEFI calling convention for IA32 requires that Direction flag in EFLAGs is clear
+ cld
+
+## UINT32 ExceptionData#
+ pushl 8(%ebp)
+
+## call into exception handler
+ movl 4(%ebp), %ebx
+ movl ExternalVectorTablePtr, %eax
+ movl (%eax,%ebx,4), %eax
+ orl %eax, %eax # NULL?
+ je nonNullValue #
+
+## Prepare parameter and call
+ movl %esp, %edx
+ pushl %edx
+ pushl %ebx
+ call *%eax
+ addl $8, %esp
+
+nonNullValue:
+ cli
+
+## UINT32 ExceptionData#
+ addl $4,%esp
+
+## FX_SAVE_STATE_IA32 FxSaveState#
+ movl %esp, %esi
+ .byte 0x0f, 0xae, 0x0e
+ addl $512, %esp
+
+## UINT32 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7#
+ popl %eax
+ movl %eax, %dr0
+ popl %eax
+ movl %eax, %dr1
+ popl %eax
+ movl %eax, %dr2
+ popl %eax
+ movl %eax, %dr3
+## skip restore of dr6. We cleared dr6 during the context save.
+ addl $4, %esp
+ popl %eax
+ movl %eax, %dr7
+
+## UINT32 Cr0, Cr1, Cr2, Cr3, Cr4#
+ popl %eax
+ movl %eax, %cr0
+ addl $4,%esp # not for Cr1
+ popl %eax
+ movl %eax, %cr2
+ popl %eax
+ movl %eax, %cr3
+ popl %eax
+ movl %eax, %cr4
+
+## UINT32 EFlags#
+ popl 20(%ebp)
+
+## UINT32 Ldtr, Tr#
+## UINT32 Gdtr[2], Idtr[2]#
+## Best not let anyone mess with these particular registers...
+ addl $24,%esp
+
+## UINT32 Eip#
+ pop 12(%ebp)
+
+## UINT32 Gs, Fs, Es, Ds, Cs, Ss#
+## NOTE - modified segment registers could hang the debugger... We
+## could attempt to insulate ourselves against this possibility,
+## but that poses risks as well.
+##
+ popl %gs
+ popl %fs
+ popl %es
+ popl %ds
+ popl 16(%ebp)
+ popl %ss
+
+## UINT32 Edi, Esi, Ebp, Esp, Ebx, Edx, Ecx, Eax#
+ popl %edi
+ popl %esi
+ addl $4, %esp # not for ebp
+ addl $4, %esp # not for esp
+ popl %ebx
+ popl %edx
+ popl %ecx
+ popl %eax
+
+ movl %ebp, %esp
+ popl %ebp
+ addl $8,%esp
+ iretl
+
+
+#---------------------------------------#
+# _GetTemplateAddressMap #
+#----------------------------------------------------------------------------#
+#
+# Protocol prototype
+# GetTemplateAddressMap (
+# INTERRUPT_HANDLER_TEMPLATE_MAP *AddressMap
+# )#
+#
+# Routine Description:
+#
+# Return address map of interrupt handler template so that C code can generate
+# interrupt handlers, and dynamically do address fix.
+#
+# Arguments:
+#
+#
+# Returns:
+#
+# Nothing
+#
+#
+# Input: [ebp][0] = Original ebp
+# [ebp][4] = Return address
+#
+# Output: Nothing
+#
+# Destroys: Nothing
+#-----------------------------------------------------------------------------#
+ASM_GLOBAL ASM_PFX(GetTemplateAddressMap)
+ASM_PFX(GetTemplateAddressMap):
+ pushl %ebp # C prolog
+ movl %esp,%ebp
+ pushal
+
+ movl 8(%ebp), %ebx
+ movl $TemplateStart, (%ebx)
+ movl $(TemplateEnd - TemplateStart), 4(%ebx)
+
+ # Note: if code in Template is updated, the value fills into the 3rd parameter
+ # also needs update
+ movl $(VectorNumber - TemplateStart), 8(%ebx)
+
+ popal
+ popl %ebp
+ ret
+
+
+
+#---------------------------------------#
+# _InitializeSelectors #
+#----------------------------------------------------------------------------#
+#
+# Protocol prototype
+# InitializeSelectors (
+# )
+#
+# Routine Description:
+#
+# Creates an new GDT in RAM. The problem is that our former selectors
+# were ROM based and the EFI OS Loader does not manipulate the machine state
+# to change them (as it would for a 16-bit PC/AT startup code that had to
+# go from Real Mode to flat mode).
+#
+# Arguments:
+#
+#
+# Returns:
+#
+# Nothing
+#
+#
+# Input: [ebp][0] = Original ebp
+# [ebp][4] = Return address
+#
+# Output: Nothing
+#
+# Destroys: Nothing
+#-----------------------------------------------------------------------------#
+
+.equ CODE_SELECTOR, 0x10
+.equ DATA_SELECTOR, 0x18
+
+ASM_GLOBAL ASM_PFX(InitializeSelectors)
+ASM_PFX(InitializeSelectors):
+ pushl %ebp # C prolog
+ movl %esp,%ebp
+ pushal
+ movl $Gdtr, %edi
+
+ movw %cs,%ax # Get the selector data from our code image
+ .byte 0x66
+ movw %ax,%es
+ lgdt %es:(%edi)
+
+ .byte 0x67
+ .byte 0xea # Far Jump Offset:Selector to reload CS
+ .long SelectorRld
+ .word CODE_SELECTOR
+SelectorRld:
+ movw $DATA_SELECTOR, %ax # Update the Base for the new selectors, too
+ .byte 0x66
+ movw %ax,%ds
+ .byte 0x66
+ movw %ax,%es
+ .byte 0x66
+ movw %ax,%fs
+ .byte 0x66
+ movw %ax,%gs
+ .byte 0x66
+ movw %ax,%ss
+
+ popal
+ popl %ebp
+ ret
+
+#------------------------------------------------------------------------------
+# VOID
+# CpuEnableInterrupt (
+# VOID
+# )
+#------------------------------------------------------------------------------
+ASM_GLOBAL ASM_PFX(CpuEnableInterrupt)
+ASM_PFX(CpuEnableInterrupt):
+ sti
+ ret
+#CpuEnableInterrupt ENDP
+
+
+#------------------------------------------------------------------------------
+# VOID
+# CpuDisableInterrupt (
+# VOID
+# )
+#------------------------------------------------------------------------------
+ASM_GLOBAL ASM_PFX(CpuDisableInterrupt)
+ASM_PFX(CpuDisableInterrupt):
+ cli
+ ret
+#CpuDisableInterrupt ENDP
+
+#------------------------------------------------------------------------------
+# VOID
+# CpuInitFloatPointUnit (
+# VOID
+# )
+#------------------------------------------------------------------------------
+ASM_GLOBAL ASM_PFX(CpuInitFloatPointUnit)
+ASM_PFX(CpuInitFloatPointUnit):
+ finit
+ ret
+#CpuInitFloatPointUnit ENDP
+
+#------------------------------------------------------------------------------
+# UINT16
+# GetCodeSegment (
+# VOID
+# )
+#------------------------------------------------------------------------------
+ASM_GLOBAL ASM_PFX(GetCodeSegment)
+ASM_PFX(GetCodeSegment):
+ movw %cs, %ax
+ ret
+#GetCodeSegment ENDP
+
+
+#------------------------------------------------------------------------------
+# VOID
+# EfiWbinvd (
+# VOID
+# )
+#------------------------------------------------------------------------------
+ASM_GLOBAL ASM_PFX(EfiWbinvd)
+ASM_PFX(EfiWbinvd):
+ wbinvd
+ ret
+#EfiWbinvd ENDP
+
+#------------------------------------------------------------------------------
+# VOID
+# EfiInvd (
+# VOID
+# )
+#------------------------------------------------------------------------------
+ASM_GLOBAL ASM_PFX(EfiInvd)
+ASM_PFX(EfiInvd):
+ invd
+ ret
+#EfiInvd ENDP
+
+#------------------------------------------------------------------------------
+# VOID
+# GetIdt (
+# IDT_INFORMATION *IdtInfo
+# )
+#------------------------------------------------------------------------------
+ASM_GLOBAL ASM_PFX(GetIdt)
+ASM_PFX(GetIdt):
+ push %ebp # C prolog
+
+ movl %esp, %ebp
+ movl 8(%ebp), %eax
+ sidt (%eax)
+
+ popl %ebp
+ ret
+#GetIdt ENDP
+
+#------------------------------------------------------------------------------
+# VOID
+# C1eExceptionHandler (
+# VOID
+# )
+#------------------------------------------------------------------------------
+ASM_GLOBAL ASM_PFX(C1eExceptionHandler)
+ASM_PFX(C1eExceptionHandler):
+ pushl %ebp # C prolog
+ movl %esp, %ebp
+ pushfl
+ cli
+ pushal
+
+ # Verify if GPE was caused by C1e write.
+ # If not, pass control to real exception handler.
+ cmp $0, ASM_PFX(mWroteMsr)
+ je notourexception
+
+ # Fix the return address on stack to skip offending
+ # code which caused the exception.
+ movl 8(%ebp), %eax
+ addl $2, %eax
+ movl %eax, 8(%ebp)
+ jmp exit
+
+notourexception:
+ popal
+ popfl
+ popl %ebp
+
+ jmp ASM_PFX(mOriginalInt13)
+
+exit:
+
+ popal
+ popfl
+ popl %ebp
+ addl $4, %esp
+ iretl
+#C1eExceptionHandler ENDP
+
+
+ASM_GLOBAL ASM_PFX(GetCoreNumber)
+ASM_PFX(GetCoreNumber):
+
+ pushl %ebx
+
+ movl $4, %eax
+ movl $0, %ecx
+ cpuid
+
+ shrl $26, %eax
+ andl $0x3f, %eax
+ incb %al
+
+ popl %ebx
+
+ ret
+
+#GetCoreNumber ENDP
+
+#-----------------------------------------------------------------------------#
+# data
+#-----------------------------------------------------------------------------#
+
+ .p2align 4
+
+Gdtr: .word GDT_END - GDT_BASE - 1
+ .long GDT_BASE
+
+#-----------------------------------------------------------------------------#
+# global descriptor table (GDT)
+#-----------------------------------------------------------------------------#
+
+ .p2align 4
+
+GDT_BASE:
+# null descriptor
+# .equ NULL_SEL, $-GDT_BASE # Selector [0]
+ .word 0 # limit 15:0
+ .word 0 # base 15:0
+ .byte 0 # base 23:16
+ .byte 0 # type
+ .byte 0 # limit 19:16, flags
+ .byte 0 # base 31:24
+
+# linear data segment descriptor
+# .equ LINEAR_SEL, $-GDT_BASE # Selector [0x8]
+ .word 0xFFFF # limit 0xFFFFF
+ .word 0 # base 0
+ .byte 0
+ .byte 0x92 # present, ring 0, data, expand-up, writable
+ .byte 0xCF # page-granular, 32-bit
+ .byte 0
+
+# linear code segment descriptor
+# .equ LINEAR_CODE_SEL, $-GDT_BASE # Selector [0x10]
+ .word 0xFFFF # limit 0xFFFFF
+ .word 0 # base 0
+ .byte 0
+ .byte 0x9A # present, ring 0, data, expand-up, writable
+ .byte 0xCF # page-granular, 32-bit
+ .byte 0
+
+# system data segment descriptor
+# .equ SYS_DATA_SEL, $-GDT_BASE # Selector [0x18]
+ .word 0xFFFF # limit 0xFFFFF
+ .word 0 # base 0
+ .byte 0
+ .byte 0x92 # present, ring 0, data, expand-up, writable
+ .byte 0xCF # page-granular, 32-bit
+ .byte 0
+
+# system code segment descriptor
+# .equ SYS_CODE_SEL, $-GDT_BASE
+ .word 0xFFFF # limit 0xFFFFF
+ .word 0 # base 0
+ .byte 0
+ .byte 0x9A # present, ring 0, data, expand-up, writable
+ .byte 0xCF # page-granular, 32-bit
+ .byte 0
+
+# spare segment descriptor
+# .equ SPARE3_SEL, $-GDT_BASE
+ .word 0 # limit 0xFFFFF
+ .word 0 # base 0
+ .byte 0
+ .byte 0 # present, ring 0, data, expand-up, writable
+ .byte 0 # page-granular, 32-bit
+ .byte 0
+
+# spare segment descriptor
+# .equ SPARE4_SEL, $-GDT_BASE
+ .word 0 # limit 0xFFFFF
+ .word 0 # base 0
+ .byte 0
+ .byte 0 # present, ring 0, data, expand-up, writable
+ .byte 0 # page-granular, 32-bit
+ .byte 0
+
+# spare segment descriptor
+# .equ SPARE5_SEL, $-GDT_BASE
+ .word 0 # limit 0xFFFFF
+ .word 0 # base 0
+ .byte 0
+ .byte 0 # present, ring 0, data, expand-up, writable
+ .byte 0 # page-granular, 32-bit
+ .byte 0
+
+GDT_END:
+
diff --git a/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/CpuInit/Ia32/Exception.c b/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/CpuInit/Ia32/Exception.c
new file mode 100644
index 0000000000..89734ddfe2
--- /dev/null
+++ b/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/CpuInit/Ia32/Exception.c
@@ -0,0 +1,337 @@
+/** @file
+ IA-32 Exception Handler.
+
+ Copyright (c) 1999 - 2015, 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 "CpuDxe.h"
+#include "MpCommon.h"
+#include "Exception.h"
+
+typedef
+VOID
+(*EFI_INSTALL_EXCEPTION) (
+ IN UINT32 InterruptType,
+ IN VOID *SystemContext
+ );
+/**
+ @todo No description
+
+**/
+typedef struct {
+ UINT32 ErrorMessage;
+ UINT8 Interrupt;
+} EFI_EXCEPTION_HANDLER;
+
+//
+// Error code flag indicating whether or not an error code will be
+// pushed on the stack if an exception occurs.
+//
+// 1 means an error code will be pushed, otherwise 0
+//
+// bit 0 - exception 0
+// bit 1 - exception 1
+// etc.
+//
+UINT32 mErrorCodeFlag = 0x00027d00;
+
+//
+// Local Table
+//
+EFI_EXCEPTION_HANDLER mExceptionTable[] = {
+ {
+ EFI_SW_EC_IA32_DIVIDE_ERROR,
+ INTERRUPT_HANDLER_DIVIDE_ZERO
+ },
+ {
+ EFI_SW_EC_IA32_DEBUG,
+ INTERRUPT_HANDLER_DEBUG
+ },
+ {
+ EFI_SW_EC_IA32_NMI,
+ INTERRUPT_HANDLER_NMI
+ },
+ {
+ EFI_SW_EC_IA32_BREAKPOINT,
+ INTERRUPT_HANDLER_BREAKPOINT
+ },
+ {
+ EFI_SW_EC_IA32_OVERFLOW,
+ INTERRUPT_HANDLER_OVERFLOW
+ },
+ {
+ EFI_SW_EC_IA32_BOUND,
+ INTERRUPT_HANDLER_BOUND
+ },
+ {
+ EFI_SW_EC_IA32_INVALID_OPCODE,
+ INTERRUPT_HANDLER_INVALID_OPCODE
+ },
+ //
+ // Interrupt 7, 9, 15 not defined in the debug support protocol. Hence no status codes for them!
+ //
+ {
+ EFI_SW_EC_IA32_DOUBLE_FAULT,
+ INTERRUPT_HANDLER_DOUBLE_FAULT
+ },
+ {
+ EFI_SW_EC_IA32_INVALID_TSS,
+ INTERRUPT_HANDLER_INVALID_TSS
+ },
+ {
+ EFI_SW_EC_IA32_SEG_NOT_PRESENT,
+ INTERRUPT_HANDLER_SEGMENT_NOT_PRESENT
+ },
+ {
+ EFI_SW_EC_IA32_STACK_FAULT,
+ INTERRUPT_HANDLER_STACK_SEGMENT_FAULT
+ },
+ {
+ EFI_SW_EC_IA32_GP_FAULT,
+ INTERRUPT_HANDLER_GP_FAULT
+ },
+ {
+ EFI_SW_EC_IA32_PAGE_FAULT,
+ INTERRUPT_HANDLER_PAGE_FAULT
+ },
+ {
+ EFI_SW_EC_IA32_FP_ERROR,
+ INTERRUPT_HANDLER_MATH_FAULT
+ },
+ {
+ EFI_SW_EC_IA32_ALIGNMENT_CHECK,
+ INTERRUPT_HANDLER_ALIGNMENT_FAULT
+ },
+ {
+ EFI_SW_EC_IA32_MACHINE_CHECK,
+ INTERRUPT_HANDLER_MACHINE_CHECK
+ },
+ {
+ EFI_SW_EC_IA32_SIMD,
+ INTERRUPT_HANDLER_STREAMING_SIMD
+ }
+};
+
+UINTN mExceptionNumber = sizeof (mExceptionTable) / sizeof (EFI_EXCEPTION_HANDLER);
+
+CPU_STATUS_CODE_TEMPLATE mStatusCodeData = {
+ {
+ sizeof (EFI_STATUS_CODE_DATA),
+ sizeof (EFI_SYSTEM_CONTEXT_IA32),
+ EFI_STATUS_CODE_DATA_TYPE_EXCEPTION_HANDLER_GUID
+ },
+ {
+ 0
+ }
+};
+
+/**
+ Report StatusCode for Exception
+
+ @param[in] InterruptType Interrupt type
+ @param[in] SystemContext EFI_SYSTEM_CONTEXT
+
+ @retval EFI_SUCCESS
+
+**/
+EFI_STATUS
+ReportData (
+ IN EFI_EXCEPTION_TYPE InterruptType,
+ IN EFI_SYSTEM_CONTEXT SystemContext
+ )
+{
+ UINT32 ErrorMessage;
+ UINT32 Index;
+
+ CopyMem (
+ &mStatusCodeData.SystemContext.SystemContextIa32,
+ SystemContext.SystemContextIa32,
+ sizeof (EFI_SYSTEM_CONTEXT_IA32)
+ );
+
+ ErrorMessage = EFI_SOFTWARE_DXE_BS_DRIVER;
+ for (Index = 0; Index < mExceptionNumber; Index++) {
+ if (mExceptionTable[Index].Interrupt == InterruptType) {
+ ErrorMessage |= mExceptionTable[Index].ErrorMessage;
+ break;
+ }
+ }
+
+ REPORT_STATUS_CODE_EX (
+ (EFI_ERROR_CODE | EFI_ERROR_UNRECOVERED),
+ EFI_SOFTWARE_UNSPECIFIED | ErrorMessage,
+ 0,
+ &gEfiCallerIdGuid,
+ NULL,
+ (EFI_STATUS_CODE_DATA *)&mStatusCodeData,
+ sizeof(CPU_STATUS_CODE_TEMPLATE)
+ );
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Common exception handler
+
+ @param[in] InterruptType Exception type
+ @param[in] SystemContext EFI_SYSTEM_CONTEXT
+**/
+VOID
+EFIAPI
+CommonExceptionHandler (
+ IN EFI_EXCEPTION_TYPE InterruptType,
+ IN EFI_SYSTEM_CONTEXT SystemContext
+ )
+{
+ DEBUG ((
+ EFI_D_ERROR,
+ "!!!! IA32 Exception Type - %08x !!!!\n",
+ InterruptType
+ ));
+ DEBUG ((
+ EFI_D_ERROR,
+ "EIP - %08x, CS - %08x, EFLAGS - %08x\n",
+ SystemContext.SystemContextIa32->Eip,
+ SystemContext.SystemContextIa32->Cs,
+ SystemContext.SystemContextIa32->Eflags
+ ));
+ if (mErrorCodeFlag & (1 << InterruptType)) {
+ DEBUG ((
+ EFI_D_ERROR,
+ "ExceptionData - %08x\n",
+ SystemContext.SystemContextIa32->ExceptionData
+ ));
+ }
+ DEBUG ((
+ EFI_D_ERROR,
+ "EAX - %08x, ECX - %08x, EDX - %08x, EBX - %08x\n",
+ SystemContext.SystemContextIa32->Eax,
+ SystemContext.SystemContextIa32->Ecx,
+ SystemContext.SystemContextIa32->Edx,
+ SystemContext.SystemContextIa32->Ebx
+ ));
+ DEBUG ((
+ EFI_D_ERROR,
+ "ESP - %08x, EBP - %08x, ESI - %08x, EDI - %08x\n",
+ SystemContext.SystemContextIa32->Esp,
+ SystemContext.SystemContextIa32->Ebp,
+ SystemContext.SystemContextIa32->Esi,
+ SystemContext.SystemContextIa32->Edi
+ ));
+ DEBUG ((
+ EFI_D_ERROR,
+ "DS - %08x, ES - %08x, FS - %08x, GS - %08x, SS - %08x\n",
+ SystemContext.SystemContextIa32->Ds,
+ SystemContext.SystemContextIa32->Es,
+ SystemContext.SystemContextIa32->Fs,
+ SystemContext.SystemContextIa32->Gs,
+ SystemContext.SystemContextIa32->Ss
+ ));
+ DEBUG ((
+ EFI_D_ERROR,
+ "GDTR - %08x %08x, IDTR - %08x %08x\n",
+ SystemContext.SystemContextIa32->Gdtr[0],
+ SystemContext.SystemContextIa32->Gdtr[1],
+ SystemContext.SystemContextIa32->Idtr[0],
+ SystemContext.SystemContextIa32->Idtr[1]
+ ));
+ DEBUG ((
+ EFI_D_ERROR,
+ "LDTR - %08x, TR - %08x\n",
+ SystemContext.SystemContextIa32->Ldtr,
+ SystemContext.SystemContextIa32->Tr
+ ));
+ DEBUG ((
+ EFI_D_ERROR,
+ "CR0 - %08x, CR2 - %08x, CR3 - %08x, CR4 - %08x\n",
+ SystemContext.SystemContextIa32->Cr0,
+ SystemContext.SystemContextIa32->Cr2,
+ SystemContext.SystemContextIa32->Cr3,
+ SystemContext.SystemContextIa32->Cr4
+ ));
+ DEBUG ((
+ EFI_D_ERROR,
+ "DR0 - %08x, DR1 - %08x, DR2 - %08x, DR3 - %08x\n",
+ SystemContext.SystemContextIa32->Dr0,
+ SystemContext.SystemContextIa32->Dr1,
+ SystemContext.SystemContextIa32->Dr2,
+ SystemContext.SystemContextIa32->Dr3
+ ));
+ DEBUG ((
+ EFI_D_ERROR,
+ "DR6 - %08x, DR7 - %08x\n",
+ SystemContext.SystemContextIa32->Dr6,
+ SystemContext.SystemContextIa32->Dr7
+ ));
+
+ //
+ // Report Status Code
+ //
+ ReportData (InterruptType, SystemContext);
+
+ //
+ // Use this macro to hang so that the compiler does not optimize out
+ // the following RET instructions. This allows us to return if we
+ // have a debugger attached.
+ //
+ CpuDeadLoop ();
+
+ return ;
+}
+
+/**
+ Install the IA-32 Exception Handler.
+ The current operation (which likely will change) will uninstall all the
+ pertinent exception handlers (0-7, 10-14, 16-19) except for Int8 which the timer
+ is currently sitting on (or soon will be).
+
+ It then installs all the appropriate handlers for each exception.
+
+ The handler then calls gRT->ReportStatusCode with a specific progress code. The
+ progress codes for now start at 0x200 for IA-32 processors. See Status Code
+ Specification for details. The Status code Specification uses the enumeration from
+ the EFI 1.1 Debug Support Protocol.
+
+ @param[in] *CpuProtocol Instance of CPU Arch Protocol
+
+ @retval EFI_STATUS
+
+**/
+EFI_STATUS
+InitializeException (
+ IN EFI_CPU_ARCH_PROTOCOL *CpuProtocol
+ )
+{
+ EFI_STATUS Status;
+ UINTN Index;
+
+ Status = CpuProtocol->DisableInterrupt (CpuProtocol);
+
+ for (Index = 0; Index < mExceptionNumber; Index++) {
+ Status = CpuProtocol->RegisterInterruptHandler (
+ CpuProtocol,
+ mExceptionTable[Index].Interrupt,
+ NULL
+ );
+
+ Status = CpuProtocol->RegisterInterruptHandler (
+ CpuProtocol,
+ mExceptionTable[Index].Interrupt,
+ CommonExceptionHandler
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ }
+
+ return Status;
+}
diff --git a/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/CpuInit/Ia32/Htequ.inc b/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/CpuInit/Ia32/Htequ.inc
new file mode 100644
index 0000000000..5554cefd42
--- /dev/null
+++ b/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/CpuInit/Ia32/Htequ.inc
@@ -0,0 +1,40 @@
+;; @file
+;
+; Copyright (c) 2010 - 2015, 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
+StartupApSignal Equ 6E750000h
+MonitorFilterSize Equ 10h
+ApCounterInit Equ 0
+ApInHltLoop Equ 1
+ApInMwaitLoop Equ 2
+ApInRunLoop Equ 3
+
+LockLocation equ 1000h - 0400h
+StackStart equ LockLocation + 4h
+StackSize equ LockLocation + 8h
+RendezvousProc equ LockLocation + 0Ch
+GdtrProfile equ LockLocation + 10h
+IdtrProfile equ LockLocation + 16h
+BufferStart equ LockLocation + 1Ch
+Cr3Location equ LockLocation + 20h
+InitFlag equ LockLocation + 24h
+WakeUpApManner equ LockLocation + 28h
+BistBuffer equ LockLocation + 2Ch
+PAUSE32 MACRO
+ DB 0F3h
+ DB 090h
+ ENDM
+
+;-------------------------------------------------------------------------------
diff --git a/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/CpuInit/Ia32/InitializeFpu.s b/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/CpuInit/Ia32/InitializeFpu.s
new file mode 100644
index 0000000000..782eb00bb6
--- /dev/null
+++ b/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/CpuInit/Ia32/InitializeFpu.s
@@ -0,0 +1,72 @@
+## @file
+# Copyright (c) 2009 - 2015, 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
+#
+##
+
+#
+# Float control word initial value:
+# all exceptions masked, double-precision, round-to-nearest
+#
+ASM_PFX(mFpuControlWord): .word 0x027F
+#
+# Multimedia-extensions control word:
+# all exceptions masked, round-to-nearest, flush to zero for masked underflow
+#
+ASM_PFX(mMmxControlWord): .long 0x01F80
+
+#
+# Initializes floating point units for requirement of UEFI specification.
+#
+# This function initializes floating-point control word to 0x027F (all exceptions
+# masked,double-precision, round-to-nearest) and multimedia-extensions control word
+# (if supported) to 0x1F80 (all exceptions masked, round-to-nearest, flush to zero
+# for masked underflow).
+#
+ASM_GLOBAL ASM_PFX(InitializeFloatingPointUnits)
+ASM_PFX(InitializeFloatingPointUnits):
+
+ pushl %ebx
+
+ #
+ # Initialize floating point units
+ #
+ finit
+ fldcw ASM_PFX(mFpuControlWord)
+
+ #
+ # Use CpuId instructuion (CPUID.01H:EDX.SSE[bit 25] = 1) to test
+ # whether the processor supports SSE instruction.
+ #
+ movl $1, %eax
+ cpuid
+ btl $25, %edx
+ jnc Done
+
+ #
+ # Set OSFXSR bit 9 in CR4
+ #
+ movl %cr4, %eax
+ or $0x200, %eax
+ movl %eax, %cr4
+
+ #
+ # The processor should support SSE instruction and we can use
+ # ldmxcsr instruction
+ #
+ ldmxcsr ASM_PFX(mMmxControlWord)
+
+Done:
+ popl %ebx
+
+ ret
+
+#END
+
diff --git a/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/CpuInit/Ia32/MPFuncs32.asm b/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/CpuInit/Ia32/MPFuncs32.asm
new file mode 100644
index 0000000000..1350addb7d
--- /dev/null
+++ b/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/CpuInit/Ia32/MPFuncs32.asm
@@ -0,0 +1,426 @@
+;; @file
+; This is the assembly code for MP (Multiple-processor) support
+;
+; Copyright (c) 1999 - 2015, 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.
+;
+;;
+
+.686p
+.model flat
+.code
+
+include Htequ.inc
+;-------------------------------------------------------------------------------------
+FJMP32 MACRO Selector, Offset
+ DB 066h
+ DB 067h
+ DB 0EAh ; far jump
+ DD Offset ; 32-bit offset
+ DW Selector ; 16-bit selector
+ ENDM
+FCALL32 MACRO Selector, Offset
+ DB 09Ah
+ DD Offset ; 32-bit offset
+ DW Selector ; 16-bit selector
+ ENDM
+;-------------------------------------------------------------------------------------
+;RendezvousFunnelProc procedure follows. All APs execute their procedure. This
+;procedure serializes all the AP processors through an Init sequence. It must be
+;noted that APs arrive here very raw...ie: real mode, no stack.
+;ALSO THIS PROCEDURE IS EXECUTED BY APs ONLY ON 16 BIT MODE. HENCE THIS PROC
+;IS IN MACHINE CODE.
+;-------------------------------------------------------------------------------------
+;RendezvousFunnelProc (&WakeUpBuffer,MemAddress);
+
+RendezvousFunnelProc PROC near C PUBLIC
+RendezvousFunnelProcStart::
+
+
+; At this point CS = 0x(vv00) and ip= 0x0.
+
+ db 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 keeping APIC ID
+
+; If it is the first time AP wakes up, just record AP's BIST
+; Otherwise, switch to flat mode
+
+ db 0BEh, 24h, 0Ch ; mov si, InitFlag
+ db 66h, 83h, 3Ch, 01h ; cmp dword ptr [si], 1
+ db 75h, 18h ; jnz flat32Start
+
+; Record BIST information
+;
+ db 0B0h, 08h ; mov al, 8
+ db 0F6h, 0E3h ; mul bl
+
+ db 0BEh, 2Ch, 0Ch ; mov si, BistBuffer
+ 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
+
+ cli
+ hlt
+ jmp $-2
+
+; Switch to flat mode.
+
+flat32Start::
+
+ db 0BEh, 1Ch, 0Ch ; mov si, BufferStart
+ db 66h, 8Bh, 0Ch ; mov ecx,dword ptr [si] ; ECX is keeping the start address of wakeup buffer
+
+ db 0FAh ; cli
+ db 0BEh, 10h, 0Ch ; mov si, GdtrProfile
+ db 66h ; db 66h
+ db 2Eh,0Fh, 01h, 14h ; lgdt fword ptr cs:[si]
+
+ db 0BEh, 16h, 0Ch ; 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, 01h ; or eax, 000000001h ; Set PE bit (bit #0)
+ db 0Fh, 22h, 0C0h ; mov cr0, eax
+
+
+;step-4:
+
+FLAT32_JUMP::
+ FJMP32 010h,0h ; Far jmp using code segment descriptor
+
+PMODE_ENTRY:: ; protected mode entry point
+
+ mov ax, 8h
+ mov ds, ax
+ mov es, ax
+ mov fs, ax
+ mov gs, ax
+ mov ss, ax ; Flat mode setup.
+
+ mov esi, ecx
+
+ mov edi, esi
+ add edi, InitFlag
+ cmp dword ptr [edi], 2 ; Check whether in S3 boot path
+ jz ProgramDynamicStack
+
+ProgramStaticStack::
+
+ xor ecx, ecx
+ mov edi, esi
+ add edi, BistBuffer
+ mov ecx, dword ptr [edi + 8 * ebx] ; EBX = CpuNumber
+
+ mov edi, esi
+ add edi, StackSize
+ mov eax, dword ptr [edi]
+ inc ecx
+ mul ecx ; EAX = StackSize * (CpuNumber + 1)
+
+ mov edi, esi
+ add edi, StackStart
+ mov edx, dword ptr [edi]
+ add eax, edx ; EAX = StackStart + StackSize * (CpuNumber + 1)
+
+ mov esp, eax
+ sub esp, MonitorFilterSize ; Reserved Monitor data space
+ or ebx, StartupApSignal ; ebx = #Cpu run signature
+ jmp ProgramLocalApic
+
+ProgramDynamicStack::
+
+ mov edi, esi
+ add edi, LockLocation
+ mov al, NotVacantFlag
+TestLock::
+ xchg byte ptr [edi], al
+ cmp al, NotVacantFlag
+ jz TestLock
+
+ mov edi, esi
+ add edi, StackSize
+ mov eax, dword ptr [edi]
+ mov edi, esi
+ add edi, StackStart
+ add eax, dword ptr [edi]
+ mov esp, eax
+ mov dword ptr [edi], eax
+
+Releaselock::
+ mov al, VacantFlag
+ mov edi, esi
+ add edi, LockLocation
+ xchg byte ptr [edi], al
+
+ProgramLocalApic::
+
+ mov edi, 0FEE000F0h
+ mov eax, dword ptr [edi]
+ and eax, 0FFFFFD0Fh
+ or eax, 10Fh
+ mov dword ptr [edi], eax
+
+ mov edi, 0FEE00350h
+ mov eax, dword ptr [edi]
+ and eax, 0FFFE00FFh
+ or eax, 700h
+ mov dword ptr [edi], eax
+
+ mov edi, 0FEE00360h
+ mov eax, dword ptr [edi]
+ and eax, 0FFFE00FFh
+ or eax, 10400h
+ mov dword ptr [edi], eax
+
+EnableXmm::
+ mov eax, 1
+ cpuid
+ bt edx,1Ah
+ jnc @F
+ ;
+ ; Enable XMM
+ ;
+ mov eax,cr0
+ or eax, 2
+ mov cr0, eax
+ mov eax, cr4
+ or eax, 600h
+ mov cr4, eax
+
+@@:
+ ;
+ ; Call C Function
+ ;
+ mov edi, esi
+ add edi, RendezvousProc
+ add esi, WakeUpApManner ; esi = WakeUpApManner Address Location
+
+WakeUpThisAp::
+
+ mov eax, dword ptr [edi]
+
+ test eax, eax
+ jz CheckWakeUpCounterInit
+
+ push ebx
+ push ebx
+ push esi
+ push edi
+
+ sub esp, 20h
+ call eax ; Call C function
+ add esp, 20h
+
+ pop edi
+ pop esi
+ pop ebx
+ pop ebx
+
+CheckWakeUpCounterInit::
+ cmp dword ptr [esi], ApCounterInit
+ jnz CheckWakeUpManner
+
+;
+; Initialize MONITOR_MWAIT_DATA data structure per thread
+;
+ xor ecx, ecx
+ mov dword ptr [esp + 0], ecx ; BreakToRunApSignal
+ mov dword ptr [esp + 4], ecx ; HltLoopBreakCounter
+ mov dword ptr [esp + 8], ecx ; MwaitLoopBreakCounter
+ mov dword ptr [esp + 12], ecx ; RunLoopBreakCounter
+ mov dword ptr [esp + 16], ecx ; WakeUpApVectorChangeFlag
+ mov dword ptr [esp + 20], ecx ; MwaitTargetCstate
+
+CheckWakeUpManner::
+
+ cmp dword ptr [esi], ApInHltLoop
+ jz HltApLoop
+
+ cmp dword ptr [esi], ApInMwaitLoop
+ jnz CheckRunSignal
+
+ApMwaitLoop::
+
+ cli
+ mov eax, esp ; Set Monitor Address
+ xor ecx, ecx
+ xor edx, edx
+ DB 0fh, 1, 0c8h ; MONITOR
+ mov eax, dword ptr [esp + 20] ; Mwait Target C-State per rax[7:4]
+ DB 0fh, 1, 0c9h ; MWAIT
+
+CheckRunSignal::
+
+ cmp dword ptr [esp], ebx ; Check if run signal correct?
+ jnz CheckWakeUpManner ; Unknown break, go checking run manner
+
+ jmp WakeUpThisAp ; Jmp to execute AP task
+
+HltApLoop::
+
+ cli
+ hlt
+ jmp HltApLoop
+
+RendezvousFunnelProc ENDP
+RendezvousFunnelProcEnd::
+;-------------------------------------------------------------------------------------
+; AsmGetAddressMap (&AddressMap);
+;-------------------------------------------------------------------------------------
+AsmGetAddressMap PROC near C PUBLIC
+
+ pushad
+ mov ebp,esp
+
+ mov ebx, dword ptr [ebp+24h]
+ mov dword ptr [ebx], RendezvousFunnelProcStart
+ mov dword ptr [ebx+4h], PMODE_ENTRY - RendezvousFunnelProcStart
+ mov dword ptr [ebx+8h], FLAT32_JUMP - RendezvousFunnelProcStart
+ mov dword ptr [ebx+0ch], RendezvousFunnelProcEnd - RendezvousFunnelProcStart
+
+ popad
+ ret
+AsmGetAddressMap 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 al, NotVacantFlag
+TryLock1:
+ db 0f0h ; opcode for lock instruction
+ xchg al, byte ptr [esi]
+ cmp al, VacantFlag
+ jz LockObtained1
+ PAUSE32
+ jmp TryLock1
+
+LockObtained1:
+ mov byte ptr [esi+1], CPU_SWITCH_STATE_STORED
+ db 0f0h ; opcode for lock instruction
+ xchg al, byte ptr [esi]
+
+WaitForOtherStored::
+ ; wait until the other CPU finish storing its state
+ mov al, NotVacantFlag
+TryLock2:
+ db 0f0h ; opcode for lock instruction
+ xchg al, byte ptr [edi]
+ cmp al, VacantFlag
+ jz LockObtained2
+ PAUSE32
+ jmp TryLock2
+
+LockObtained2:
+ mov bl, byte ptr [edi+1]
+ db 0f0h ; opcode for lock instruction
+ xchg al, byte ptr [edi]
+ cmp bl, CPU_SWITCH_STATE_STORED
+ jb WaitForOtherStored
+
+ ; 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 its switch state to LOADED
+ mov al, NotVacantFlag
+TryLock3:
+ db 0f0h ; opcode for lock instruction
+ xchg al, byte ptr [esi]
+ cmp al, VacantFlag
+ jz LockObtained3
+ PAUSE32
+ jmp TryLock3
+
+LockObtained3:
+ mov byte ptr [esi+1], CPU_SWITCH_STATE_LOADED
+ db 0f0h ; opcode for lock instruction
+ xchg al, byte ptr [esi]
+
+WaitForOtherLoaded::
+ ; wait until the other CPU finish loading new state,
+ ; otherwise the data in stack may corrupt
+ mov al, NotVacantFlag
+TryLock4:
+ db 0f0h ; opcode for lock instruction
+ xchg al, byte ptr [edi]
+ cmp al, VacantFlag
+ jz LockObtained4
+ PAUSE32
+ jmp TryLock4
+
+LockObtained4:
+ mov bl, byte ptr [edi+1]
+ db 0f0h ; opcode for lock instruction
+ xchg al, byte ptr [edi]
+ cmp bl, CPU_SWITCH_STATE_LOADED
+ jb WaitForOtherLoaded
+
+ ; since the other CPU already get the data it want, leave this procedure
+ popfd
+
+ popad
+ ret
+AsmExchangeRole ENDP
+END
diff --git a/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/CpuInit/Ia32/MPFuncs32.s b/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/CpuInit/Ia32/MPFuncs32.s
new file mode 100644
index 0000000000..fd44beae0b
--- /dev/null
+++ b/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/CpuInit/Ia32/MPFuncs32.s
@@ -0,0 +1,444 @@
+## @file
+# This is the assembly code for MP (Multiple-processor) support.
+#
+# Copyright (c) 1999 - 2015, 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 Htequ.inc
+
+.equ VacantFlag , 0x00
+.equ NotVacantFlag , 0xff
+.equ StartupApSignal , 0x6E750000
+.equ MonitorFilterSize, 0x10
+.equ ApCounterInit , 0
+.equ ApInHltLoop , 1
+.equ ApInMwaitLoop , 2
+.equ ApInRunLoop , 3
+
+.equ LockLocation , 0x1000 - 0x0400
+.equ StackStart , LockLocation + 0x4
+.equ StackSize , LockLocation + 0x8
+.equ RendezvousProc , LockLocation + 0x0C
+.equ GdtrProfile , LockLocation + 0x10
+.equ IdtrProfile , LockLocation + 0x16
+.equ BufferStart , LockLocation + 0x1C
+.equ Cr3Location , LockLocation + 0x20
+.equ InitFlag , LockLocation + 0x24
+.equ WakeUpApManner , LockLocation + 0x28
+.equ BistBuffer , LockLocation + 0x2C
+
+#-------------------------------------------------------------------------------------
+
+.macro PAUSE32
+ .byte 0xF3
+ .byte 0x90
+.endm
+
+.macro FJMP32 Selector, Offset
+ .byte 0x066
+ .byte 0x067
+ .byte 0x0EA # far jump
+ .long \Offset # 32-bit offset
+ .word \Selector # 16-bit selector
+.endm
+
+.macro FCALL32 Selector, Offset
+ .byte 0x09A
+ .long \Offset # 32-bit offset
+ .word \Selector # 16-bit selector
+.endm
+
+#-------------------------------------------------------------------------------------
+#RendezvousFunnelProc procedure follows. All APs execute their procedure. This
+#procedure serializes all the AP processors through an Init sequence. It must be
+#noted that APs arrive here very raw...ie: real mode, no stack.
+#ALSO THIS PROCEDURE IS EXECUTED BY APs ONLY ON 16 BIT MODE. HENCE THIS PROC
+#IS IN MACHINE CODE.
+#-------------------------------------------------------------------------------------
+#RendezvousFunnelProc (&WakeUpBuffer,MemAddress)
+
+ASM_GLOBAL ASM_PFX(RendezvousFunnelProc)
+ASM_PFX(RendezvousFunnelProc):
+RendezvousFunnelProcStart:
+
+# At this point CS = 0x(vv00) and ip= 0x0.
+
+ .byte 0x66,0x8b,0xe8 # mov ebp, eax
+
+ .byte 0x8c,0xc8 # mov ax, cs
+ .byte 0x8e,0xd8 # mov ds, ax
+ .byte 0x8e,0xc0 # mov es, ax
+ .byte 0x8e,0xd0 # mov ss, ax
+ .byte 0x33,0xc0 # xor ax, ax
+ .byte 0x8e,0xe0 # mov fs, ax
+ .byte 0x8e,0xe8 # mov gs, ax
+
+# Get APIC ID
+#
+ .byte 0x66, 0xB8
+ .long 0x00000001 # mov %eax, 1
+ .byte 0x0F, 0xA2 # cpuid
+ .byte 0x66, 0xC1, 0xEB, 0x18 # shr %ebx, 24
+ .byte 0x66, 0x81, 0xE3
+ .long 0x000000FF # and %ebx, 0ffh # EBX is keeping APIC ID
+
+# If it is the first time AP wakes up, just record AP's BIST
+# Otherwise, switch to flat mode
+
+ .byte 0xBE, 0x24, 0x0C # mov si, InitFlag
+ .byte 0x66, 0x83, 0x3C, 0x01 # cmp dword ptr [si], 1
+ .byte 0x75, 0x18 # jnz flat32Start
+
+# Record BIST information
+#
+ .byte 0xB0, 0x08 # mov al, 8
+ .byte 0xF6, 0xE3 # mul bl
+
+ .byte 0xBE, 0x2C, 0x0C # mov si, BistBuffer
+ .byte 0x03, 0xF0 # add si, ax
+
+ .byte 0x66, 0xC7, 0x04
+ .byte 0x00000001 # mov dword ptr [si], 1 # Set Valid Flag
+ .byte 0x66, 0x89, 0x6C, 0x04 # mov dword ptr [si + 4], ebp # Store BIST value
+
+ cli
+ hlt
+ jmp .-2
+
+# Switch to flat mode.
+
+flat32Start:
+
+ .byte 0xBE, 0x1C, 0x0C # mov si, BufferStart
+ .byte 0x66, 0x8B, 0x0C # mov ecx,dword ptr [si] # ECX is keeping the start address of wakeup buffer
+
+ .byte 0xFA # cli
+ .byte 0xBE, 0x10, 0x0C # mov si, GdtrProfile
+ .byte 0x66 # db 66h
+ .byte 0x2E, 0x0F, 0x01, 0x14 # lgdt fword ptr cs:[si]
+
+ .byte 0xBE, 0x16, 0x0C # mov si, IdtrProfile
+ .byte 0x66 # db 66h
+ .byte 0x2E, 0x0F, 0x01, 0x1C # lidt fword ptr cs:[si]
+
+
+ .byte 0x33, 0xC0 # xor ax, ax
+ .byte 0x8E, 0xD8 # mov ds, ax
+ .byte 0x0F, 0x20, 0xC0 # mov eax, cr0 # Get control register 0
+ .byte 0x66, 0x83, 0xC8, 0x01 # or eax, 000000001h # Set PE bit (bit #0)
+ .byte 0x0F, 0x22, 0xC0 # mov cr0, eax
+
+
+#step-4:
+
+FLAT32_JUMP:
+ FJMP32 0x010, 0x0 # Far jmp using code segment descriptor
+
+PMODE_ENTRY: # protected mode entry point
+
+ movw $0x8,%ax
+ movw %ax,%ds
+ movw %ax,%es
+ movw %ax,%fs
+ movw %ax,%gs
+ movw %ax,%ss # Flat mode setup.
+
+ movl %ecx,%esi
+
+ movl %esi,%edi
+ addl $InitFlag, %edi
+ cmpl $2, (%edi) # Check whether in S3 boot path
+ jz ProgramDynamicStack
+
+ProgramStaticStack:
+
+ xorl %ecx, %ecx
+ movl %esi, %edi
+ addl $BistBuffer, %edi
+ movl (%edi, %ebx, 8), %ecx # EBX = CpuNumber
+
+ movl %esi, %edi
+ addl $StackSize, %edi
+ movl (%edi), %eax
+ incl %ecx
+ mull %ecx # EAX = StackSize * (CpuNumber + 1)
+
+ movl %esi, %edi
+ addl $StackStart, %edi
+ movl (%edi), %edx
+ addl %edx, %eax # EAX = StackStart + StackSize * (CpuNumber + 1)
+
+ movl %eax, %esp
+ subl $MonitorFilterSize, %esp # Reserved Monitor data space
+ orl $StartupApSignal, %ebx # EBX = #Cpu run signature
+ jmp ProgramLocalApic
+
+ProgramDynamicStack:
+
+ movl %esi, %edi
+ addl $LockLocation, %edi
+ movb $NotVacantFlag, %al
+TestLock:
+ xchgb %al, (%edi)
+ cmpb $NotVacantFlag, %al
+ jz TestLock
+
+ movl %esi, %edi
+ addl $StackSize, %edi
+ movl (%edi), %eax
+ movl %esi, %edi
+ addl $StackStart, %edi
+ addl (%edi), %eax
+ movl %eax, %esp
+ movl %eax, (%edi)
+
+Releaselock:
+ movb $VacantFlag, %al
+ movl %esi, %edi
+ addl $LockLocation, %edi
+ xchgb %al, (%edi)
+
+ProgramLocalApic:
+
+ movl $0x0FEE000F0, %edi
+ movl (%edi), %eax
+ andl $0x0FFFFFD0F, %eax
+ orl $0x10F, %eax
+ movl %eax, (%edi)
+
+ movl $0x0FEE00350, %edi
+ movl (%edi), %eax
+ andl $0x0FFFE00FF, %eax
+ orl $0x700, %eax
+ movl %eax, (%edi)
+
+ movl $0x0FEE00360, %edi
+ movl (%edi), %eax
+ andl $0x0FFFE00FF, %eax
+ orl $0x10400, %eax
+ movl %eax, (%edi)
+EnableXmm:
+ movl $1, %eax
+ cpuid
+ btl $0x1A, %edx
+ jnc L1
+ #
+ # Enable XMM
+ #
+ movl %cr0, %eax
+ orl $2, %eax
+ movl %eax, %cr0
+ movl %cr4, %eax
+ orl $0x600, %eax
+ movl %eax, %cr4
+
+L1:
+ #
+ # Call C Function
+ #
+ movl %esi, %edi
+ addl $RendezvousProc, %edi
+ addl $WakeUpApManner, %esi # esi = WakeUpApManner Address Location
+
+WakeUpThisAp:
+
+ movl (%edi), %eax
+
+ testl %eax, %eax
+ jz CheckWakeUpCounterInit
+
+ push %ebx
+ push %ebx
+ push %esi
+ push %edi
+
+ subl $0x20, %esp
+ call *%eax # Call C function
+ addl $0x20, %esp
+
+ pop %edi
+ pop %esi
+ pop %ebx
+ pop %ebx
+
+CheckWakeUpCounterInit:
+ cmpl $ApCounterInit, (%esi)
+ jnz CheckWakeUpManner
+
+#
+# Initi%alize MONITOR_MWAIT_DATA data structure per thread
+#
+ xorl %ecx, %ecx
+ movl %ecx, 0(%esp) # BreakToRunApSignal
+ movl %ecx, 4(%esp) # HltLoopBreakCounter
+ movl %ecx, 8(%esp) # MwaitLoopBreakCounter
+ movl %ecx, 12(%esp) # RunLoopBreakCounter
+ movl %ecx, 16(%esp) # WakeUpApVectorChangeFlag
+ movl %ecx, 20(%esp) # MwaitTargetCstate
+
+CheckWakeUpManner:
+
+ cmpl $ApInHltLoop, (%esi)
+ jz HltApLoop
+
+ cmpl $ApInMwaitLoop, (%esi)
+ jnz CheckRunSignal
+
+ApMwaitLoop:
+
+ cli
+ movl %esp, %eax # Set Monitor Address
+ xorl %ecx, %ecx
+ xorl %edx, %edx
+ .byte 0x0f, 0x1, 0xc8 # MONITOR
+ movl 20(%esp), %eax # Mwait Target C-State per rax[7:4]
+ .byte 0x0f, 0x1, 0xc9 # MWAIT
+
+CheckRunSignal:
+
+ cmpl %ebx, (%esp) # Check if run sign%al correct?
+ jnz CheckWakeUpManner # Unknown break, go checking run manner
+
+ jmp WakeUpThisAp # Jmp to execute AP task
+
+HltApLoop:
+
+ cli
+ hlt
+ jmp HltApLoop
+
+#RendezvousFunnelProc ENDP
+RendezvousFunnelProcEnd:
+
+#-------------------------------------------------------------------------------------
+# AsmGetAddressMap (&AddressMap)
+#-------------------------------------------------------------------------------------
+ASM_GLOBAL ASM_PFX(AsmGetAddressMap)
+ASM_PFX(AsmGetAddressMap):
+ pushal
+ movl %esp, %ebp
+
+ movl 0x24(%ebp), %ebx
+ movl $RendezvousFunnelProcStart, (%ebx)
+ movl $(PMODE_ENTRY - RendezvousFunnelProcStart), 0x4(%ebx)
+ movl $(FLAT32_JUMP - RendezvousFunnelProcStart), 0x8(%ebx)
+ movl $(RendezvousFunnelProcEnd - RendezvousFunnelProcStart), 0xc(%ebx)
+
+ popal
+ ret
+#AsmGetAddressMap 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)#
+#-------------------------------------------------------------------------------------
+.equ CPU_SWITCH_STATE_IDLE, 0
+.equ CPU_SWITCH_STATE_STORED, 1
+.equ CPU_SWITCH_STATE_LOADED, 2
+
+ASM_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.
+ pushal
+ movl %esp, %ebp
+
+ # %esi contains MyInfo pointer
+ movl 0x24(%ebp), %esi
+
+ # %edi contains OthersInfo pointer
+ movl 0x28(%ebp), %edi
+
+ #Store EFLAGS, GDTR and IDTR regiter to stack
+ pushfl
+ sgdt 8(%esi)
+ sidt 14(%esi)
+
+ # Store the its StackPointer
+ movl %esp, 4(%esi)
+
+ # update its switch state to STORED
+ movb $NotVacantFlag, %al
+TryLock1:
+ lock xchgb (%esi), %al
+ cmpb $VacantFlag, %al
+ jz LockObtained1
+ PAUSE32
+ jmp TryLock1
+
+LockObtained1:
+ movb $CPU_SWITCH_STATE_STORED, 1(%esi)
+ lock xchgb (%esi), %al
+WaitForOtherStored:
+ # wait until the other CPU finish storing its state
+ movb $NotVacantFlag, %al
+TryLock2:
+ lock xchgb (%edi), %al
+ cmpb $VacantFlag, %al
+ jz LockObtained2
+ PAUSE32
+ jmp TryLock2
+
+LockObtained2:
+ movb 1(%edi), %bl
+ lock xchgb (%edi), %al
+ cmpb $CPU_SWITCH_STATE_STORED, %bl
+ jb 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
+ movl 4(%edi), %esp
+
+ # update its switch state to LOADED
+ movb $NotVacantFlag, %al
+TryLock3:
+ lock xchgb (%esi), %al
+ cmpb $VacantFlag, %al
+ jz LockObtained3
+ PAUSE32
+ jmp TryLock3
+
+LockObtained3:
+ movb $CPU_SWITCH_STATE_LOADED, 1(%esi)
+ lock xchgb (%esi), %al
+
+WaitForOtherLoaded:
+ # wait until the other CPU finish loading new state,
+ # otherwise the data in stack may corrupt
+ movb $NotVacantFlag, %al
+TryLock4:
+ lock xchgb (%edi), %al
+ cmpb $VacantFlag, %al
+ jz LockObtained4
+ PAUSE32
+ jmp TryLock4
+
+LockObtained4:
+ movb 1(%edi), %bl
+ lock xchgb (%edi), %al
+ cmpb $CPU_SWITCH_STATE_LOADED, %bl
+ jb WaitForOtherLoaded
+
+ # since the other CPU already get the data it want, leave this procedure
+ popfl
+
+ popal
+ ret
+#AsmExchangeRole ENDP
+
diff --git a/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/CpuInit/Ia32/MemoryOperation.c b/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/CpuInit/Ia32/MemoryOperation.c
new file mode 100644
index 0000000000..ab196d140b
--- /dev/null
+++ b/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/CpuInit/Ia32/MemoryOperation.c
@@ -0,0 +1,380 @@
+/** @file
+ Memory Operation Functions for IA32 Architecture.
+
+ Copyright (c) 2014 - 2015, 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 "CpuDxe.h"
+#include "MpCommon.h"
+#include "PlatformMpService.h"
+
+VOID
+InitializeIdt (
+ IN EFI_CPU_INTERRUPT_HANDLER *TableStart,
+ IN UINTN *IdtTablePtr,
+ IN UINT16 IdtTableLimit
+ );
+
+extern EFI_CPU_INTERRUPT_HANDLER mExternalVectorTable[];
+extern EFI_PHYSICAL_ADDRESS mBackupBuffer;
+
+UINT64 mValidMtrrAddressMask = EFI_CACHE_VALID_ADDRESS;
+UINT64 mValidMtrrBitsMask = EFI_MSR_VALID_MASK;
+
+/**
+ Slick around interrupt routines.
+
+ @retval EFI_SUCCESS - If interrupt settings are initialized successfully
+
+**/
+EFI_STATUS
+InitializeSlick (
+ VOID
+ )
+{
+ INTERRUPT_GATE_DESCRIPTOR *IdtTable;
+ INTERRUPT_HANDLER_TEMPLATE_MAP TemplateMap;
+ UINT16 CodeSegment;
+ INTERRUPT_GATE_DESCRIPTOR *IdtEntry;
+ UINT8 *InterruptHandler;
+ UINT8 *CurrentHandler;
+ UINTN Index;
+
+ IdtTable = AllocatePool (sizeof (INTERRUPT_GATE_DESCRIPTOR) * INTERRUPT_VECTOR_NUMBER);
+ ASSERT(IdtTable != NULL);
+ IdtEntry = IdtTable;
+
+ GetTemplateAddressMap (&TemplateMap);
+ InterruptHandler = AllocatePool (TemplateMap.Size * INTERRUPT_VECTOR_NUMBER);
+ ASSERT(InterruptHandler != NULL);
+ CurrentHandler = InterruptHandler;
+
+ CodeSegment = GetCodeSegment ();
+
+ for (Index = 0; Index < INTERRUPT_VECTOR_NUMBER; Index++) {
+ CopyMem (CurrentHandler, TemplateMap.Start, TemplateMap.Size);
+ *(UINT32 *) (CurrentHandler + TemplateMap.FixOffset) = Index;
+
+ IdtEntry[Index].OffsetLow = (UINT16) (UINTN) CurrentHandler;
+ IdtEntry[Index].SegmentSelector = CodeSegment;
+ IdtEntry[Index].Attributes = INTERRUPT_GATE_ATTRIBUTE;
+ //
+ // 8e00;
+ //
+ IdtEntry[Index].OffsetHigh = (UINT16) ((UINTN) CurrentHandler >> 16);
+
+ CurrentHandler += TemplateMap.Size;
+ }
+
+ InitializeIdt (
+ &(mExternalVectorTable[0]),
+ (UINTN *) IdtTable,
+ sizeof (INTERRUPT_GATE_DESCRIPTOR) * INTERRUPT_VECTOR_NUMBER
+ );
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Prepare memory for essential system tables.
+
+ @retval EFI_SUCCESS Memory successfully prepared.
+ @retval Other Error occurred while initializating memory.
+
+**/
+EFI_STATUS
+PrepareMemory (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+
+ ZeroMem (mExternalVectorTable, 0x100 * 4);
+
+ //
+ // Initialize the Interrupt Descriptor Table
+ //
+ Status = InitializeSlick ();
+
+ return Status;
+}
+
+/**
+ Prepare Wakeup Buffer and stack for APs.
+
+ @param[out] WakeUpBuffer - Pointer to the address of wakeup buffer for output.
+ @param[out] 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;
+ MP_ASSEMBLY_ADDRESS_MAP AddressMap;
+
+ //
+ // Release All APs with a lock and wait for them to retire to rendezvous procedure.
+ // We need a 64 aligned 4K aligned area for IA-32 to use broadcast APIs. But we need it only
+ // on a temporary basis.
+ //
+ Status = AllocateWakeUpBuffer (WakeUpBuffer);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Claim memory for AP stack.
+ //
+ Status = gBS->AllocatePool (
+ EfiACPIMemoryNVS,
+ MaximumCPUsForThisSystem * STACK_SIZE_PER_PROC,
+ StackAddressStart
+ );
+ if (EFI_ERROR (Status)) {
+ gBS->FreePages (*WakeUpBuffer, 1);
+ return Status;
+ }
+
+ AsmGetAddressMap (&AddressMap);
+ CopyMem ((VOID *) (UINTN) *WakeUpBuffer, AddressMap.RendezvousFunnelAddress, AddressMap.Size);
+ *(UINT32 *) (UINTN) (*WakeUpBuffer + AddressMap.FlatJumpOffset + 3) = (UINT32) (*WakeUpBuffer + AddressMap.PModeEntryOffset);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Prepare exchange information for APs.
+
+ @param[out] *ExchangeInfo - Pointer to the exchange info buffer for output.
+ @param[in] *StackAddressStart - Start address of APs' stacks.
+ @param[in] *ApFunction - Address of function assigned to AP.
+ @param[in] WakeUpBuffer - Pointer to the address of wakeup buffer.
+
+ @retval EFI_SUCCESS - Exchange Info successfully prepared for APs.
+
+**/
+EFI_STATUS
+PrepareExchangeInfo (
+ OUT MP_CPU_EXCHANGE_INFO *ExchangeInfo,
+ IN VOID *StackAddressStart,
+ IN VOID *ApFunction,
+ IN EFI_PHYSICAL_ADDRESS WakeUpBuffer
+ )
+{
+ gBS->SetMem ((VOID *) ExchangeInfo, EFI_PAGE_SIZE - MP_CPU_EXCHANGE_INFO_OFFSET, 0);
+
+ ExchangeInfo->Lock = VacantFlag;
+ ExchangeInfo->StackStart = StackAddressStart;
+ ExchangeInfo->StackSize = STACK_SIZE_PER_PROC;
+ ExchangeInfo->ApFunction = ApFunction;
+
+ CopyMem (&ExchangeInfo->GdtrProfile, (VOID *) (UINTN) mAcpiCpuData->GdtrProfile, sizeof (IA32_DESCRIPTOR));
+ CopyMem (&ExchangeInfo->IdtrProfile, (VOID *) (UINTN) mAcpiCpuData->IdtrProfile, sizeof (IA32_DESCRIPTOR));
+
+ ExchangeInfo->BufferStart = (UINT32) WakeUpBuffer;
+ ExchangeInfo->InitFlag = 1;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Prepare Wakeup Buffer and stack for APs during S3.
+
+ @param[out] WakeUpBuffer - Pointer to the address of wakeup buffer for output.
+ @param[out] StackAddressStart - Pointer to the stack address of APs for output.
+
+ @retval EFI_SUCCESS - Memory successfully prepared for APs.
+
+**/
+EFI_STATUS
+S3PrepareMemoryForAPs (
+ OUT EFI_PHYSICAL_ADDRESS *WakeUpBuffer,
+ OUT VOID **StackAddressStart
+ )
+{
+ MP_ASSEMBLY_ADDRESS_MAP AddressMap;
+
+ *WakeUpBuffer = mAcpiCpuData->WakeUpBuffer;
+ *StackAddressStart = (VOID *) (UINTN) mAcpiCpuData->StackAddress;
+
+ AsmGetAddressMap (&AddressMap);
+ CopyMem ((VOID *) (UINTN) *WakeUpBuffer, AddressMap.RendezvousFunnelAddress, AddressMap.Size);
+ *(UINT32 *) (UINTN) (*WakeUpBuffer + AddressMap.FlatJumpOffset + 3) = (UINT32) (*WakeUpBuffer + AddressMap.PModeEntryOffset);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Prepare exchange information for APs during S3.
+
+ @param[out] ExchangeInfo - Pointer to the exchange info for output.
+ @param[in] StackAddressStart - Start address of APs' stacks.
+ @param[in] ApFunction - Address of function assigned to AP.
+ @param[in] WakeUpBuffer - Pointer to the address of wakeup buffer.
+
+ @retval EFI_SUCCESS - Exchange Info successfully prepared for APs.
+
+**/
+EFI_STATUS
+S3PrepareExchangeInfo (
+ OUT MP_CPU_EXCHANGE_INFO *ExchangeInfo,
+ IN VOID *StackAddressStart,
+ IN VOID *ApFunction,
+ IN EFI_PHYSICAL_ADDRESS WakeUpBuffer
+ )
+{
+ ExchangeInfo->Lock = VacantFlag;
+ ExchangeInfo->StackStart = (VOID *) (UINTN) StackAddressStart;
+ ExchangeInfo->StackSize = STACK_SIZE_PER_PROC;
+ ExchangeInfo->ApFunction = ApFunction;
+
+ CopyMem (&ExchangeInfo->GdtrProfile, (VOID *) (UINTN) mAcpiCpuData->GdtrProfile, sizeof (IA32_DESCRIPTOR));
+ CopyMem (&ExchangeInfo->IdtrProfile, (VOID *) (UINTN) mAcpiCpuData->IdtrProfile, sizeof (IA32_DESCRIPTOR));
+
+ ExchangeInfo->BufferStart = (UINT32) WakeUpBuffer;
+ ExchangeInfo->InitFlag = 2;
+
+ //
+ // There is no need to initialize CpuNumber and BistBuffer fields in ExchangeInfo here.
+ //
+ return EFI_SUCCESS;
+}
+
+/**
+ Dynamically write the far jump destination in APs' wakeup buffer,
+ in order to refresh APs' CS registers for mode switching.
+
+**/
+VOID
+RedirectFarJump (
+ VOID
+ )
+{
+ MP_ASSEMBLY_ADDRESS_MAP AddressMap;
+
+ AsmGetAddressMap (&AddressMap);
+ *(UINT32 *) (UINTN) (mAcpiCpuData->WakeUpBuffer + AddressMap.FlatJumpOffset + 3) = (UINT32) (mAcpiCpuData->WakeUpBuffer + AddressMap.PModeEntryOffset);
+ return;
+}
+
+/**
+ Set specified IDT entry with given function pointer.
+
+ @param[in] FunctionPointer - Function pointer for IDT entry.
+ @param[out] IdtEntry - The IDT entry to update.
+
+ @retval - The original IDT entry value.
+
+**/
+UINTN
+SetIdtEntry (
+ IN UINTN FunctionPointer,
+ OUT INTERRUPT_GATE_DESCRIPTOR *IdtEntry
+)
+{
+ UINTN OriginalEntry;
+
+ OriginalEntry = ((UINT32) IdtEntry->OffsetHigh << 16) + IdtEntry->OffsetLow;
+
+ IdtEntry->OffsetLow = (UINT16) FunctionPointer;
+ IdtEntry->OffsetHigh = (UINT16) (FunctionPointer >> 16);
+
+ return OriginalEntry;
+}
+
+/**
+ @todo Add function description
+
+ @param[out] *Gdtr - @todo add argument description
+ @param[out] *Idtr - @todo add argument description
+
+ @retval EFI_SUCCESS - @todo Add description for return value
+
+**/
+EFI_STATUS
+PrepareGdtIdtForAP (
+ OUT IA32_DESCRIPTOR *Gdtr,
+ OUT IA32_DESCRIPTOR *Idtr
+ )
+{
+ INTERRUPT_GATE_DESCRIPTOR *IdtForAP;
+ SEGMENT_DESCRIPTOR *GdtForAP;
+ IA32_DESCRIPTOR *IdtrForBSP;
+ IA32_DESCRIPTOR *GdtrForBSP;
+ UINT8 *MceHandler;
+ EFI_STATUS Status;
+
+ AsmGetGdtrIdtr (&GdtrForBSP, &IdtrForBSP);
+
+ //
+ // Allocate reserved memory for IDT
+ //
+ Status = AllocateAlignedReservedMemory (
+ IdtrForBSP->Limit + 1,
+ 8,
+ (VOID **) &IdtForAP
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Allocate reserved memory for GDT
+ //
+ Status = AllocateAlignedReservedMemory (
+ GdtrForBSP->Limit + 1,
+ 8,
+ (VOID **) &GdtForAP
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ Status = gBS->AllocatePool (
+ EfiACPIMemoryNVS,
+ SIZE_OF_MCE_HANDLER,
+ (VOID **) &MceHandler
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // McheHandler content: iret (opcode = 0xcf)
+ //
+ *MceHandler = 0xCF;
+
+ CopyMem (GdtForAP, (VOID *) GdtrForBSP->Base, GdtrForBSP->Limit + 1);
+ CopyMem (IdtForAP, (VOID *) IdtrForBSP->Base, IdtrForBSP->Limit + 1);
+
+ IdtForAP[INTERRUPT_HANDLER_MACHINE_CHECK].OffsetLow = (UINT16) (UINTN) MceHandler;
+ IdtForAP[INTERRUPT_HANDLER_MACHINE_CHECK].OffsetHigh = (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;
+}
+
diff --git a/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/CpuInit/Ia32/MpCommon32.asm b/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/CpuInit/Ia32/MpCommon32.asm
new file mode 100644
index 0000000000..25434ad41f
--- /dev/null
+++ b/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/CpuInit/Ia32/MpCommon32.asm
@@ -0,0 +1,103 @@
+;; @file
+; This is the assembly code for MP/HT (Multiple-processor / Hyper-threading) support
+;
+; Copyright (c) 1999 - 2015, 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.
+;
+;;
+
+.686p
+.model flat
+.data
+.stack
+.code
+.MMX
+.XMM
+
+ include Htequ.inc
+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:
+ db 0f0h ; opcode for lock instruction
+ 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]
+ db 0f0h ; opcode for lock instruction
+ xchg al, byte ptr [ebx]
+
+ popad
+ ret
+AsmReleaseMPLock ENDP
+
+;-------------------------------------------------------------------------------
+; AsmGetGdtrIdtr (&Gdt, &Idt);
+;-------------------------------------------------------------------------------------
+AsmGetGdtrIdtr PROC near C PUBLIC
+
+ pushad
+ mov ebp,esp
+
+ sgdt fword ptr GdtDesc
+ lea esi, GdtDesc
+ mov edi, dword ptr [ebp+24h]
+ mov dword ptr [edi], esi
+
+ sidt fword ptr IdtDesc
+ lea esi, IdtDesc
+ mov edi, dword ptr [ebp+28h]
+ mov dword ptr [edi], esi
+
+ popad
+ ret
+AsmGetGdtrIdtr ENDP
+
+GdtDesc:: ; GDT descriptor
+ DW 03fh ; GDT limit
+ DW 0h ; GDT base and limit will be
+ DW 0h ; filled using sgdt
+
+IdtDesc:: ; IDT descriptor
+ DW 0h ; IDT limit
+ DW 0h ; IDT base and limit will be
+ DW 0h ; filled using sidt
+
+END
diff --git a/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/CpuInit/Ia32/MpCommon32.s b/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/CpuInit/Ia32/MpCommon32.s
new file mode 100644
index 0000000000..dc110da96a
--- /dev/null
+++ b/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/CpuInit/Ia32/MpCommon32.s
@@ -0,0 +1,114 @@
+## @file
+# This is the assembly code for MP/HT (Multiple-processor / Hyper-threading) support
+#
+# Copyright (c) 1999 - 2015, 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 Htequ.inc
+
+.equ VacantFlag , 0x00
+.equ NotVacantFlag , 0xff
+.equ StartupApSignal , 0x6E750000
+.equ MonitorFilterSize, 0x10
+.equ ApCounterInit , 0
+.equ ApInHltLoop , 1
+.equ ApInMwaitLoop , 2
+.equ ApInRunLoop , 3
+
+.equ LockLocation , 0x1000 - 0x0400
+.equ StackStart , LockLocation + 0x4
+.equ StackSize , LockLocation + 0x8
+.equ RendezvousProc , LockLocation + 0x0C
+.equ GdtrProfile , LockLocation + 0x10
+.equ IdtrProfile , LockLocation + 0x16
+.equ BufferStart , LockLocation + 0x1C
+.equ Cr3Location , LockLocation + 0x20
+.equ InitFlag , LockLocation + 0x24
+.equ WakeUpApManner , LockLocation + 0x28
+.equ BistBuffer , LockLocation + 0x2C
+
+.macro PAUSE32
+ .byte 0xF3
+ .byte 0x90
+.endm
+
+
+#-------------------------------------------------------------------------------
+# AsmAcquireMPLock (&Lock)
+#-------------------------------------------------------------------------------
+ASM_GLOBAL ASM_PFX(AsmAcquireMPLock)
+ASM_PFX(AsmAcquireMPLock):
+ pushal
+ movl %esp, %ebp
+
+ movb $NotVacantFlag, %al
+ movl 0x24(%ebp), %ebx
+TryGetLock:
+ lock xchgb (%ebx), %al
+ cmpb $VacantFlag, %al
+ jz LockObtained
+
+ PAUSE32
+
+ jmp TryGetLock
+
+LockObtained:
+ popal
+ ret
+#AsmAcquireMPLock ENDP
+
+#-------------------------------------------------------------------------------
+# AsmReleaseMPLock (&Lock)
+#-------------------------------------------------------------------------------
+ASM_GLOBAL ASM_PFX(AsmReleaseMPLock)
+ASM_PFX(AsmReleaseMPLock):
+ pushal
+ movl %esp, %ebp
+
+ movb $VacantFlag, %al
+ movl 0x24(%ebp), %ebx
+ lock xchgb (%ebx), %al
+
+ popal
+ ret
+#AsmReleaseMPLock ENDP
+
+#-------------------------------------------------------------------------------
+# AsmGetGdtrIdtr (&Gdt, &Idt)#
+#-------------------------------------------------------------------------------------
+ASM_GLOBAL ASM_PFX(AsmGetGdtrIdtr)
+ASM_PFX(AsmGetGdtrIdtr):
+ pushal
+ movl %esp, %ebp
+ sgdt GdtDesc
+ leal GdtDesc, %esi
+ movl 0x24(%ebp), %edi
+ movl %esi, (%edi)
+
+ sidt IdtDesc
+ leal IdtDesc, %esi
+ movl 0x28(%ebp), %edi
+ movl %esi, (%edi)
+
+ popal
+ ret
+#AsmGetGdtrIdtr ENDP
+
+GdtDesc: # GDT descriptor
+ .word 0x03f # GDT limit
+ .word 0x0 # GDT base and limit will be
+ .word 0x0 # filled using sgdt
+
+IdtDesc: # IDT descriptor
+ .word 0x0 # IDT limit
+ .word 0x0 # IDT base and limit will be
+ .word 0x0 # filled using sidt
diff --git a/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/CpuInit/Ia32/MpCpu.c b/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/CpuInit/Ia32/MpCpu.c
new file mode 100644
index 0000000000..133e10c57b
--- /dev/null
+++ b/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/CpuInit/Ia32/MpCpu.c
@@ -0,0 +1,90 @@
+/** @file
+ MP Support driver.
+
+ Copyright (c) 1999 - 2015, 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 "CpuDxe.h"
+#include "MpCommon.h"
+#include "PlatformMpService.h"
+
+extern EFI_CPU_MICROCODE_HEADER **mMicrocodePointerBuffer;
+
+ACPI_CPU_DATA_COMPATIBILITY *mAcpiCpuData;
+MP_SYSTEM_DATA *mMPSystemData;
+
+EFI_DEVICE_PATH_PROTOCOL *
+AppendDevicePath (
+ IN EFI_DEVICE_PATH_PROTOCOL *Src1,
+ IN EFI_DEVICE_PATH_PROTOCOL *Src2
+ );
+
+UINTN
+DevicePathSize (
+ IN EFI_DEVICE_PATH_PROTOCOL *DevicePath
+ );
+
+/**
+ Initializes MP support in the system.
+
+ @param[in] ImageHandle Image handle of the loaded driver
+ @param[in] *SystemTable Pointer to the System Table
+
+ @retval EFI_SUCCESS Multiple processors are initialized successfully.
+ @retval EFI_NOT_FOUND The ACPI variable is not found in S3 boot path.
+ @retval EFI_OUT_OF_RESOURCES No enough resoruces (such as out of memory).
+
+**/
+EFI_STATUS
+InitializeMpSupport (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+ MP_CPU_RESERVED_DATA *MpCpuReservedData;
+
+ MpCpuReservedData = NULL;
+
+ if (ImageHandle != NULL) {
+
+ Status = AllocateReservedMemoryBelow4G (
+ sizeof (MP_CPU_RESERVED_DATA),
+ (VOID **) &MpCpuReservedData
+ );
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ ZeroMem (MpCpuReservedData, sizeof (MP_CPU_RESERVED_DATA));
+
+ mMPSystemData = &(MpCpuReservedData->MPSystemData);
+ mAcpiCpuData = &(MpCpuReservedData->AcpiCpuData);
+
+ CopyMem (
+ MpCpuReservedData->MicrocodePointerBuffer,
+ mMicrocodePointerBuffer,
+ sizeof (EFI_CPU_MICROCODE_HEADER *) * (NUMBER_OF_MICROCODE_UPDATE + 1)
+ );
+
+ mAcpiCpuData->CpuPrivateData = (EFI_PHYSICAL_ADDRESS)(UINTN)(&(mMPSystemData->S3DataPointer));
+ mAcpiCpuData->S3BootPath = FALSE;
+ mAcpiCpuData->MicrocodePointerBuffer = (EFI_PHYSICAL_ADDRESS)(UINTN)(MpCpuReservedData->MicrocodePointerBuffer);
+ mAcpiCpuData->GdtrProfile = (EFI_PHYSICAL_ADDRESS)(UINTN)(&(MpCpuReservedData->GdtrProfile));
+ mAcpiCpuData->IdtrProfile = (EFI_PHYSICAL_ADDRESS)(UINTN)(&(MpCpuReservedData->IdtrProfile));
+
+ MpServiceInitialize ();
+ }
+
+ return EFI_SUCCESS;
+}
diff --git a/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/CpuInit/Ia32/MpProc.asm b/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/CpuInit/Ia32/MpProc.asm
new file mode 100644
index 0000000000..e07056d304
--- /dev/null
+++ b/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/CpuInit/Ia32/MpProc.asm
@@ -0,0 +1,83 @@
+;; @file
+; This is the code that supports MP.
+;
+; Copyright (c) 1999 - 2015, 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.
+;
+;;
+ page ,132
+ title MP ASSEMBLY HOOKS
+.686p
+.model flat
+.data
+.stack
+.code
+.MMX
+.XMM
+_MpMtrrSynchUpEntry PROC NEAR PUBLIC
+ ;
+ ; Enter no fill cache mode, CD=1(Bit30), NW=0 (Bit29)
+ ;
+ mov eax, cr0
+ and eax, 0DFFFFFFFh
+ or eax, 040000000h
+ mov cr0, eax
+ ;
+ ; Flush cache
+ ;
+ wbinvd
+ ;
+ ; Clear PGE flag Bit 7
+ ;
+ mov eax, cr4
+ mov edx, eax
+ and eax, 0FFFFFF7Fh
+ mov cr4, eax
+ ;
+ ; Flush all TLBs
+ ;
+ mov eax, cr3
+ mov cr3, eax
+
+ mov eax, edx
+
+ ret
+
+_MpMtrrSynchUpEntry ENDP
+
+_MpMtrrSynchUpExit PROC NEAR PUBLIC
+
+ push ebp ; C prolog
+ mov ebp, esp
+ ;
+ ; Flush all TLBs the second time
+ ;
+ mov eax, cr3
+ mov cr3, eax
+ ;
+ ; Enable Normal Mode caching CD=NW=0, CD(Bit30), NW(Bit29)
+ ;
+ mov eax, cr0
+ and eax, 09FFFFFFFh
+ mov cr0, eax
+ ;
+ ; Set PGE Flag in CR4 if set
+ ;
+ mov eax, dword ptr [ebp + 8]
+ mov cr4, eax
+
+ pop ebp
+
+ ret
+
+_MpMtrrSynchUpExit ENDP
+
+ END
+
diff --git a/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/CpuInit/Ia32/MpProc.s b/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/CpuInit/Ia32/MpProc.s
new file mode 100644
index 0000000000..73ebd1cf2e
--- /dev/null
+++ b/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/CpuInit/Ia32/MpProc.s
@@ -0,0 +1,69 @@
+## @file
+# This is the code that supports MP.
+#
+# Copyright (c) 1999 - 2015, 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.
+#
+##
+
+ASM_GLOBAL ASM_PFX(MpMtrrSynchUpEntry)
+ASM_PFX(MpMtrrSynchUpEntry):
+ #
+ # Enter no fill cache mode, CD=1(Bit30), NW=0 (Bit29)
+ #
+ movl %cr0, %eax
+ andl 0x0DFFFFFFF, %eax
+ orl 0x040000000, %eax
+ movl %eax, %cr0
+ #
+ # Flush cache
+ #
+ wbinvd
+ #
+ # Clear PGE flag Bit 7
+ #
+ movl %cr4, %eax
+ movl %eax, %edx
+ andl 0x0FFFFFF7F, %eax
+ movl %eax, %cr4
+ #
+ # Flush all TLBs
+ #
+ movl %cr3, %eax
+ movl %eax, %cr3
+
+ movl %edx, %eax
+ ret
+#MpMtrrSynchUpEntry ENDP
+
+ASM_GLOBAL ASM_PFX(MpMtrrSynchUpExit)
+ASM_PFX(MpMtrrSynchUpExit):
+ push %ebp # C prolog
+ movl %esp, %ebp
+ #
+ # Flush all TLBs the second time
+ #
+ movl %cr3, %eax
+ movl %eax, %cr3
+ #
+ # Enable Normal Mode caching CD=NW=0, CD(Bit30), NW(Bit29)
+ #
+ movl %cr0, %eax
+ andl 0x09FFFFFFF, %eax
+ movl %eax, %cr0
+ #
+ # Set PGE Flag in CR4 if set
+ #
+ movl 8(%ebp), %eax
+ movl %eax, %cr4
+
+ pop %ebp
+ ret
+#MpMtrrSynchUpExit ENDP
diff --git a/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/CpuInit/Ia32/ProcessorDef.h b/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/CpuInit/Ia32/ProcessorDef.h
new file mode 100644
index 0000000000..c150ba60b7
--- /dev/null
+++ b/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/CpuInit/Ia32/ProcessorDef.h
@@ -0,0 +1,56 @@
+/** @file
+ Definition for IA32 processor.
+
+ Copyright (c) 2014 - 2015, 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 _PROCESSOR_DEF_H
+#define _PROCESSOR_DEF_H
+
+
+#pragma pack(1)
+/**
+ @todo No structure description
+
+**/
+typedef struct {
+ UINT16 OffsetLow;
+ UINT16 SegmentSelector;
+ UINT16 Attributes;
+ UINT16 OffsetHigh;
+} INTERRUPT_GATE_DESCRIPTOR;
+
+#pragma pack()
+
+/**
+ @todo No structure description
+
+**/
+
+typedef struct {
+ UINT8 *RendezvousFunnelAddress;
+ UINTN PModeEntryOffset;
+ UINTN FlatJumpOffset;
+ UINTN Size;
+} MP_ASSEMBLY_ADDRESS_MAP;
+
+/**
+ Get address map of RendezvousFunnelProc.
+
+ @param[in] AddressMap - Output buffer for address map information
+**/
+VOID
+AsmGetAddressMap (
+ OUT MP_ASSEMBLY_ADDRESS_MAP *AddressMap
+ );
+
+#endif
diff --git a/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/CpuInit/MemoryAttribute.c b/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/CpuInit/MemoryAttribute.c
new file mode 100644
index 0000000000..ddf4f56536
--- /dev/null
+++ b/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/CpuInit/MemoryAttribute.c
@@ -0,0 +1,975 @@
+/** @file
+ The function of Memory Attribute.
+
+ Copyright (c) 1999 - 2015, 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 "CpuDxe.h"
+#include "MemoryAttribute.h"
+
+EFI_FIXED_MTRR mFixedMtrrTable[] = {
+ { EFI_MSR_IA32_MTRR_FIX64K_00000, 0, 0x10000},
+ { EFI_MSR_IA32_MTRR_FIX16K_80000, 0x80000, 0x4000},
+ { EFI_MSR_IA32_MTRR_FIX16K_A0000, 0xA0000, 0x4000},
+ { EFI_MSR_IA32_MTRR_FIX4K_C0000, 0xC0000, 0x1000},
+ { EFI_MSR_IA32_MTRR_FIX4K_C8000, 0xC8000, 0x1000},
+ { EFI_MSR_IA32_MTRR_FIX4K_D0000, 0xD0000, 0x1000},
+ { EFI_MSR_IA32_MTRR_FIX4K_D8000, 0xD8000, 0x1000},
+ { EFI_MSR_IA32_MTRR_FIX4K_E0000, 0xE0000, 0x1000},
+ { EFI_MSR_IA32_MTRR_FIX4K_E8000, 0xE8000, 0x1000},
+ { EFI_MSR_IA32_MTRR_FIX4K_F0000, 0xF0000, 0x1000},
+ { EFI_MSR_IA32_MTRR_FIX4K_F8000, 0xF8000, 0x1000}
+};
+
+EFI_VARIABLE_MTRR mVariableMtrr[6];
+UINT32 mUsedMtrr;
+UINT8 mDefaultMemoryType = EFI_MEMORY_UC;
+extern UINT64 mValidMtrrAddressMask;
+extern UINT64 mValidMtrrBitsMask;
+
+/**
+ @todo Add function description
+
+ @retval @todo add return values
+
+**/
+VOID
+PreMtrrChange (
+ VOID
+ )
+{
+ UINT64 TempQword;
+
+ AsmDisableCache ();
+ //
+ // Disable Cache MTRR
+ //
+ TempQword = AsmReadMsr64 (EFI_MSR_CACHE_IA32_MTRR_DEF_TYPE);
+ TempQword = TempQword & ~B_EFI_MSR_GLOBAL_MTRR_ENABLE & ~B_EFI_MSR_FIXED_MTRR_ENABLE;
+ AsmWriteMsr64 (EFI_MSR_CACHE_IA32_MTRR_DEF_TYPE, TempQword);
+}
+
+/**
+ @todo Add function description
+
+ @retval @todo add return values
+
+**/
+VOID
+PostMtrrChange (
+ VOID
+ )
+{
+ UINT64 TempQword;
+
+ TempQword = 0;
+ //
+ // Enable Cache MTRR
+ //
+ TempQword = AsmReadMsr64 (EFI_MSR_CACHE_IA32_MTRR_DEF_TYPE);
+ AsmWriteMsr64 (EFI_MSR_CACHE_IA32_MTRR_DEF_TYPE, TempQword | B_EFI_MSR_GLOBAL_MTRR_ENABLE | B_EFI_MSR_FIXED_MTRR_ENABLE);
+
+ AsmEnableCache ();
+}
+
+/**
+ @todo Add function description
+
+ @param[in] MemoryCacheType - @todo add argument description
+ @param[in] Base - @todo add argument description
+ @param[in] Length - @todo add argument description
+
+ @retval EFI_UNSUPPORTED - @todo Add description for return value
+ @retval EFI_UNSUPPORTED - @todo Add description for return value
+ @retval EFI_UNSUPPORTED - @todo Add description for return value
+ @retval EFI_SUCCESS - @todo Add description for return value
+
+**/
+EFI_STATUS
+ProgramFixedMtrr (
+ IN UINT64 MemoryCacheType,
+ IN UINT64 *Base,
+ IN UINT64 *Length
+ )
+{
+ UINT32 MsrNum;
+ UINT32 ByteShift;
+ UINT64 TempQword;
+ UINT64 OrMask;
+ UINT64 ClearMask;
+
+ TempQword = 0;
+ OrMask = 0;
+ ClearMask = 0;
+
+ for (MsrNum = 0; MsrNum < V_EFI_FIXED_MTRR_NUMBER; MsrNum++) {
+ if ((*Base >= mFixedMtrrTable[MsrNum].BaseAddress) &&
+ (*Base < (mFixedMtrrTable[MsrNum].BaseAddress + 8 * mFixedMtrrTable[MsrNum].Length))
+ ) {
+ break;
+ }
+ }
+
+ if (MsrNum == V_EFI_FIXED_MTRR_NUMBER) {
+ return EFI_UNSUPPORTED;
+ }
+ //
+ // We found the fixed MTRR to be programmed
+ //
+ for (ByteShift = 0; ByteShift < 8; ByteShift++) {
+ if (*Base == (mFixedMtrrTable[MsrNum].BaseAddress + ByteShift * mFixedMtrrTable[MsrNum].Length)) {
+ break;
+ }
+ }
+
+ if (ByteShift == 8) {
+ return EFI_UNSUPPORTED;
+ }
+
+ for (; ((ByteShift < 8) && (*Length >= mFixedMtrrTable[MsrNum].Length)); ByteShift++) {
+ OrMask |= LShiftU64 ((UINT64) MemoryCacheType, (UINT32) (ByteShift * 8));
+ ClearMask |= LShiftU64 ((UINT64) 0xFF, (UINT32) (ByteShift * 8));
+ *Length -= mFixedMtrrTable[MsrNum].Length;
+ *Base += mFixedMtrrTable[MsrNum].Length;
+ }
+
+ if (ByteShift < 8 && (*Length != 0)) {
+ return EFI_UNSUPPORTED;
+ }
+
+ TempQword = ((AsmReadMsr64 (mFixedMtrrTable[MsrNum].Msr) & ~ClearMask) | OrMask);
+ AsmWriteMsr64 (mFixedMtrrTable[MsrNum].Msr, TempQword);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ @todo Add function description
+
+ @retval EFI_SUCCESS - @todo Add description for return value
+
+**/
+EFI_STATUS
+GetMemoryAttribute (
+ VOID
+ )
+{
+ UINTN Index;
+ UINT32 MsrNum, MsrNumEnd;
+ UINT64 MsrValue;
+
+ //
+ // Get Default Mtrr Type
+ //
+ MsrValue = AsmReadMsr64 (EFI_MSR_CACHE_IA32_MTRR_DEF_TYPE);
+ mDefaultMemoryType = (UINT8) MsrValue;
+
+ //
+ // Get Variable Mtrr
+ //
+ ZeroMem (mVariableMtrr, sizeof (EFI_VARIABLE_MTRR) * 6);
+ mUsedMtrr = 0;
+ MsrNumEnd = EFI_MSR_CACHE_VARIABLE_MTRR_BASE + (2 * (UINT32)(AsmReadMsr64(EFI_MSR_IA32_MTRR_CAP) & B_EFI_MSR_IA32_MTRR_CAP_VARIABLE_SUPPORT));
+ for (MsrNum = EFI_MSR_CACHE_VARIABLE_MTRR_BASE, Index = 0;
+ ((MsrNum < MsrNumEnd) && (Index < 6));
+ MsrNum += 2) {
+ if ((AsmReadMsr64 (MsrNum + 1) & B_EFI_MSR_CACHE_MTRR_VALID) != 0) {
+ mVariableMtrr[Index].Msr = MsrNum;
+ mVariableMtrr[Index].BaseAddress = (AsmReadMsr64 (MsrNum) & mValidMtrrAddressMask);
+ mVariableMtrr[Index].Length = ((~((AsmReadMsr64 (MsrNum + 1) & mValidMtrrAddressMask))) & mValidMtrrBitsMask) + 1;
+ mVariableMtrr[Index].Type = (AsmReadMsr64 (MsrNum) & B_EFI_MSR_CACHE_MEMORY_TYPE);
+ mVariableMtrr[Index].Valid = TRUE;
+ mUsedMtrr++;
+ Index++;
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ @todo Add function description
+
+ @param[in] Start - @todo add argument description
+ @param[in] End - @todo add argument description
+
+ @retval - @todo add return values
+
+**/
+BOOLEAN
+CheckMemoryAttributeOverlap (
+ IN EFI_PHYSICAL_ADDRESS Start,
+ IN EFI_PHYSICAL_ADDRESS End
+ )
+{
+ UINT32 Index;
+
+ for (Index = 0; Index < 6; Index++) {
+ if (mVariableMtrr[Index].Valid &&
+ !(
+ Start > (mVariableMtrr[Index].BaseAddress + mVariableMtrr[Index].Length - 1) ||
+ (End < mVariableMtrr[Index].BaseAddress)
+ )
+ ) {
+
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
+/**
+ @todo Add function description
+
+ @param[in] Attributes - @todo add argument description
+ @param[in] Base - @todo add argument description
+ @param[in] Length - @todo add argument description
+
+ @retval EFI_SUCCESS - @todo Add description for return value
+ @retval EFI_SUCCESS - @todo Add description for return value
+ @retval EFI_ACCESS_DENIED - @todo Add description for return value
+ @retval EFI_SUCCESS - @todo Add description for return value
+
+**/
+EFI_STATUS
+CombineMemoryAttribute (
+ IN UINT64 Attributes,
+ IN UINT64 *Base,
+ IN UINT64 *Length
+ )
+{
+ UINT32 Index;
+ UINT64 CombineStart;
+ UINT64 CombineEnd;
+ UINT64 MtrrEnd;
+ UINT64 EndAddress;
+ BOOLEAN InvalidMTRRs[6];
+
+ EndAddress = *Base +*Length - 1;
+
+ for (Index = 0; Index < 6; Index++) {
+ InvalidMTRRs[Index] = FALSE;
+ }
+
+ Index = 0;
+ while (Index < 6) {
+ MtrrEnd = mVariableMtrr[Index].BaseAddress + mVariableMtrr[Index].Length - 1;
+
+ //
+ // The MTRR is marked invalid or the ranges are not intersected.
+ //
+ if (InvalidMTRRs[Index] ||
+ !mVariableMtrr[Index].Valid ||
+ (*Base > (MtrrEnd) || (EndAddress < mVariableMtrr[Index].BaseAddress))) {
+ Index++;
+ continue;
+ }
+
+ //
+ // if the requested range contains MTRR range, invalidate this MTRR
+ //
+ if (mVariableMtrr[Index].BaseAddress >= *Base && MtrrEnd <= EndAddress) {
+ InvalidMTRRs[Index] = TRUE;
+ Index++;
+ continue;
+ }
+
+ if (Attributes == mVariableMtrr[Index].Type) {
+ //
+ // if the Mtrr range contain the request range, return EFI_SUCCESS
+ //
+ if (mVariableMtrr[Index].BaseAddress <= *Base && MtrrEnd >= EndAddress) {
+ *Length = 0;
+ return EFI_SUCCESS;
+ }
+
+ //
+ // invalid this MTRR, and program the combine range
+ //
+ CombineStart = (*Base) < mVariableMtrr[Index].BaseAddress ? (*Base) : mVariableMtrr[Index].BaseAddress;
+ CombineEnd = EndAddress > MtrrEnd ? EndAddress : MtrrEnd;
+
+ //
+ // Record this MTRR as invalid
+ //
+ InvalidMTRRs[Index] = TRUE;
+
+ //
+ // The range is modified, retry from the first MTRR
+ //
+ if (*Base != CombineStart || *Length != CombineEnd - CombineStart + 1) {
+ Index = 0;
+ } else {
+ Index++;
+ }
+ *Base = CombineStart;
+ *Length = CombineEnd - CombineStart + 1;
+ EndAddress = CombineEnd;
+ continue;
+ }
+
+ if ((Attributes == EFI_CACHE_UNCACHEABLE) ||
+ (Attributes == EFI_CACHE_WRITETHROUGH && mVariableMtrr[Index].Type == EFI_CACHE_WRITEBACK) ||
+ (Attributes == EFI_CACHE_WRITEBACK && mVariableMtrr[Index].Type == EFI_CACHE_WRITETHROUGH) ||
+ (Attributes == EFI_CACHE_WRITETHROUGH && mVariableMtrr[Index].Type == EFI_CACHE_UNCACHEABLE) ||
+ (Attributes == EFI_CACHE_WRITEBACK && mVariableMtrr[Index].Type == EFI_CACHE_UNCACHEABLE)
+ ) {
+ Index++;
+ continue;
+ }
+
+ //
+ // Other type memory overlap is invalid
+ //
+ return EFI_ACCESS_DENIED;
+ }
+
+ //
+ // Finally invalidate recorded MTRRs
+ //
+ for (Index = 0; Index < 6; Index++) {
+ if (InvalidMTRRs[Index]) {
+ InvariableMtrr (mVariableMtrr[Index].Msr, Index);
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Given the input, check if the number of MTRR is lesser
+ if positive or subtractive
+
+ @param[in] Input - Length of Memory to program MTRR
+ @param[in] MtrrNumber - return needed Mtrr number
+ @param[in] Direction - TRUE: do positive
+ FALSE: do subtractive
+ @retval @todo Return values are defined as:
+ Zero, do positive
+ Non-Zero, do subractive. is this OK?
+ @todo EFI_SUCCESS - add return value to function comment
+
+**/
+EFI_STATUS
+GetDirection (
+ IN UINT64 Input,
+ IN UINTN *MtrrNumber,
+ IN BOOLEAN *Direction
+ )
+{
+ UINT64 TempQword;
+ UINT32 Positive;
+ UINT32 Subtractive;
+
+ TempQword = Input;
+ Positive = 0;
+ Subtractive = 0;
+
+ do {
+ TempQword -= Power2MaxMemory (TempQword);
+ Positive++;
+
+ } while (TempQword != 0);
+
+ TempQword = Power2MaxMemory (LShiftU64 (Input, 1)) - Input;
+ Subtractive++;
+ do {
+ TempQword -= Power2MaxMemory (TempQword);
+ Subtractive++;
+
+ } while (TempQword != 0);
+
+ if (Positive <= Subtractive) {
+ *Direction = TRUE;
+ *MtrrNumber = Positive;
+ } else {
+ *Direction = FALSE;
+ *MtrrNumber = Subtractive;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ @todo Add function description
+
+ @param[in] MemoryLength - @todo add argument description
+
+ @retval @todo add return values
+
+**/
+UINT64
+Power2MaxMemory (
+ IN UINT64 MemoryLength
+ )
+{
+ UINT64 Result;
+
+ if (RShiftU64 (MemoryLength, 32)) {
+ Result = LShiftU64 ((UINT64) GetPowerOfTwo64 ((UINT32) RShiftU64 (MemoryLength, 32)), 32);
+ } else {
+ Result = (UINT64) GetPowerOfTwo64 ((UINT32) MemoryLength);
+ }
+
+ return Result;
+}
+
+/**
+ @todo Add function description
+
+ @param[in] MtrrNumber - @todo add argument description
+ @param[in] Index - @todo add argument description
+
+ @retval EFI_SUCCESS - @todo Add description for return value
+
+**/
+EFI_STATUS
+InvariableMtrr (
+ IN UINTN MtrrNumber,
+ IN UINTN Index
+ )
+{
+ PreMtrrChange ();
+ mVariableMtrr[Index].Valid = FALSE;
+ AsmWriteMsr64 ((UINT32) MtrrNumber, 0);
+ AsmWriteMsr64 ((UINT32) (MtrrNumber + 1), 0);
+ mUsedMtrr--;
+ PostMtrrChange ();
+
+ return EFI_SUCCESS;
+}
+
+/**
+ @todo Add function description
+
+ @param[in] MtrrNumber - @todo add argument description
+ @param[in] BaseAddress - @todo add argument description
+ @param[in] Length - @todo add argument description
+ @param[in] MemoryCacheType - @todo add argument description
+
+ @retval EFI_SUCCESS - @todo Add description for return value
+
+**/
+EFI_STATUS
+ProgramVariableMtrr (
+ IN UINTN MtrrNumber,
+ IN EFI_PHYSICAL_ADDRESS BaseAddress,
+ IN UINT64 Length,
+ IN UINT64 MemoryCacheType
+ )
+{
+ UINT64 TempQword;
+
+ PreMtrrChange ();
+
+ //
+ // MTRR Physical Base
+ //
+ TempQword = (BaseAddress & mValidMtrrAddressMask) | MemoryCacheType;
+ AsmWriteMsr64 ((UINT32) MtrrNumber, TempQword);
+
+ //
+ // MTRR Physical Mask
+ //
+ TempQword = ~(Length - 1);
+ AsmWriteMsr64 ((UINT32) (MtrrNumber + 1), (TempQword & mValidMtrrAddressMask) | B_EFI_MSR_CACHE_MTRR_VALID);
+
+ PostMtrrChange ();
+
+ return EFI_SUCCESS;
+}
+
+/**
+ @todo Add function description
+
+ @retval EFI_SUCCESS - @todo Add description for return value
+ @retval EFI_OUT_OF_RESOURCES - @todo Add description for return value
+ @retval EFI_SUCCESS - @todo Add description for return value
+
+**/
+EFI_STATUS
+CleanupVariableMtrr (
+ VOID
+ )
+{
+ BOOLEAN Cleaned;
+ BOOLEAN EverCleaned;
+ UINTN Index;
+ UINTN Index2;
+ BOOLEAN MtrrModified[6];
+ UINTN MtrrNumber;
+ UINTN MsrNum, MsrNumEnd;
+ EFI_PHYSICAL_ADDRESS BaseAddress;
+ UINT64 Length;
+ UINT64 TempQword;
+ UINT64 Attributes;
+ BOOLEAN Positive;
+
+ for (Index = 0; Index < 6; Index++) {
+ MtrrModified[Index] = FALSE;
+ }
+
+ GetMemoryAttribute ();
+
+ //
+ // After the do-while, mVariableMtrr is NO longer the value read from MTRR regisrer!!!
+ //
+ EverCleaned = FALSE;
+
+ do {
+ Cleaned = FALSE;
+
+ for (Index = 0; Index < 6; Index++) {
+ if (mVariableMtrr[Index].Type == EFI_CACHE_UNCACHEABLE && mVariableMtrr[Index].Valid) {
+ for (Index2 = 0; Index2 < 6; Index2++) {
+ if (mVariableMtrr[Index2].Type == EFI_CACHE_WRITEBACK && mVariableMtrr[Index2].Valid) {
+ //
+ // the Uncacheble just inside the WB and at the edge.
+ // if so, we can clean the UC entry and decrease the WB entry
+ //
+ if (mVariableMtrr[Index].BaseAddress == mVariableMtrr[Index2].BaseAddress) {
+ Cleaned = TRUE;
+ EverCleaned = TRUE;
+ if (mVariableMtrr[Index].Length >= mVariableMtrr[Index2].Length) {
+ //
+ // we can invalidate WB entry, since nothing left
+ //
+ InvariableMtrr (mVariableMtrr[Index2].Msr, Index2);
+ mVariableMtrr[Index].BaseAddress = mVariableMtrr[Index].BaseAddress + mVariableMtrr[Index2].Length;
+ mVariableMtrr[Index].Length -= mVariableMtrr[Index2].Length;
+ MtrrModified[Index] = TRUE;
+ if (mVariableMtrr[Index].Length == 0) {
+ InvariableMtrr (mVariableMtrr[Index].Msr, Index);
+ }
+
+ } else {
+ //
+ // we can invalidate UC entry, since nothing left
+ //
+ InvariableMtrr (mVariableMtrr[Index].Msr, Index);
+ mVariableMtrr[Index2].BaseAddress = mVariableMtrr[Index].BaseAddress + mVariableMtrr[Index].Length;
+ mVariableMtrr[Index2].Length -= mVariableMtrr[Index].Length;
+ MtrrModified[Index2] = TRUE;
+ }
+
+ }
+
+ if (mVariableMtrr[Index].BaseAddress +
+ mVariableMtrr[Index].Length == mVariableMtrr[Index2].BaseAddress +
+ mVariableMtrr[Index2].Length
+ ) {
+ Cleaned = TRUE;
+ EverCleaned = TRUE;
+
+ if (mVariableMtrr[Index].Length >= mVariableMtrr[Index2].Length) {
+ //
+ // we can invalidate WB entry, since nothing left
+ //
+ InvariableMtrr (mVariableMtrr[Index2].Msr, Index2);
+ mVariableMtrr[Index].Length -= mVariableMtrr[Index2].Length;
+ MtrrModified[Index] = TRUE;
+ if (mVariableMtrr[Index].Length == 0) {
+ InvariableMtrr (mVariableMtrr[Index].Msr, Index);
+ }
+
+ } else {
+ //
+ // we can invalidate UC entry, since nothing left
+ //
+ InvariableMtrr (mVariableMtrr[Index].Msr, Index);
+ mVariableMtrr[Index2].Length -= mVariableMtrr[Index].Length;
+ MtrrModified[Index2] = TRUE;
+ }
+
+ }
+ }
+ //
+ // end WB
+ //
+ }
+ //
+ // end of Index2
+ //
+ }
+ //
+ // Endof UC
+ //
+ }
+ //
+ // endof Index
+ //
+ } while (Cleaned);
+
+ if (!EverCleaned) {
+ return EFI_SUCCESS;
+ }
+
+ MsrNumEnd = EFI_MSR_CACHE_VARIABLE_MTRR_BASE + (2 * (UINT32)(AsmReadMsr64(EFI_MSR_IA32_MTRR_CAP) & B_EFI_MSR_IA32_MTRR_CAP_VARIABLE_SUPPORT));
+
+ //
+ // Begin to program the MTRR again
+ //
+ for (Index = 0; Index < 6; Index++) {
+ if (MtrrModified[Index] && mVariableMtrr[Index].Valid) {
+ //
+ // Program the new MTRR
+ //
+ TempQword = mVariableMtrr[Index].Length;
+ MsrNum = EFI_MSR_CACHE_VARIABLE_MTRR_BASE + 2 * Index;
+ BaseAddress = mVariableMtrr[Index].BaseAddress;
+ Length = mVariableMtrr[Index].Length;
+ Attributes = mVariableMtrr[Index].Type;
+
+ if (TempQword == Power2MaxMemory (TempQword)) {
+ //
+ // if it's two's power
+ // no need to request a new mtrr,
+ // just program this one
+ //
+ ProgramVariableMtrr (
+ MsrNum,
+ BaseAddress,
+ Length,
+ Attributes
+ );
+ } else {
+ GetDirection (TempQword, &MtrrNumber, &Positive);
+ //
+ // we already has one that can use, so 6+1
+ //
+ if ((mUsedMtrr + MtrrNumber) > 6 + 1) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ if (!Positive) {
+ Length = Power2MaxMemory (LShiftU64 (TempQword, 1));
+ ProgramVariableMtrr (
+ MsrNum,
+ BaseAddress,
+ Length,
+ Attributes
+ );
+ BaseAddress += TempQword;
+ TempQword = Length - TempQword;
+ Attributes = EFI_CACHE_UNCACHEABLE;
+ }
+
+ do {
+ //
+ // Find unused MTRR
+ //
+ for (MsrNum = EFI_MSR_CACHE_VARIABLE_MTRR_BASE; MsrNum < MsrNumEnd; MsrNum += 2) {
+ if ((AsmReadMsr64 ((UINT32) (MsrNum + 1)) & B_EFI_MSR_CACHE_MTRR_VALID) == 0) {
+ break;
+ }
+ }
+
+ Length = Power2MaxMemory (TempQword);
+ ProgramVariableMtrr (
+ MsrNum,
+ BaseAddress,
+ Length,
+ Attributes
+ );
+ BaseAddress += Length;
+ TempQword -= Length;
+
+ } while (TempQword);
+
+ }
+ //
+ // endof Powerof
+ //
+ }
+ //
+ // endof Modified
+ //
+ }
+ //
+ // endof for
+ //
+ return EFI_SUCCESS;
+}
+
+/**
+ Get GCD Mem Space type from Mtrr Type.
+
+ @param[in] MtrrAttribute - Mtrr type
+
+ @retval GCD Mem Space typed (64-bit)
+
+**/
+UINT64
+GetMemorySpaceAttributeFromMtrrType (
+ IN UINT8 MtrrAttributes
+ )
+{
+ switch (MtrrAttributes) {
+ case EFI_CACHE_UNCACHEABLE:
+ return EFI_MEMORY_UC;
+ case EFI_CACHE_WRITECOMBINING:
+ return EFI_MEMORY_WC;
+ case EFI_CACHE_WRITETHROUGH:
+ return EFI_MEMORY_WT;
+ case EFI_CACHE_WRITEPROTECTED:
+ return EFI_MEMORY_WP;
+ case EFI_CACHE_WRITEBACK:
+ return EFI_MEMORY_WB;
+ default:
+ return 0;
+ }
+}
+
+/**
+ Refresh the GCD Memory Space Attributes according to MTRRs
+
+**/
+EFI_STATUS
+RefreshGcdMemoryAttributes (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ UINTN Index;
+ UINTN SubIndex;
+ UINT64 RegValue;
+ EFI_PHYSICAL_ADDRESS BaseAddress;
+ UINT64 Length;
+ UINT64 Attributes;
+ UINT64 CurrentAttributes;
+ UINT8 MtrrType;
+ UINTN NumberOfDescriptors;
+ EFI_GCD_MEMORY_SPACE_DESCRIPTOR *MemorySpaceMap;
+ UINT64 DefaultAttributes;
+
+ MemorySpaceMap = NULL;
+
+ Status = GetMemoryAttribute ();
+ if (EFI_ERROR(Status)) {
+ goto Done;
+ }
+
+ Status = gDS->GetMemorySpaceMap (
+ &NumberOfDescriptors,
+ &MemorySpaceMap
+ );
+ if (EFI_ERROR(Status)) {
+ goto Done;
+ }
+
+ DefaultAttributes = GetMemorySpaceAttributeFromMtrrType (mDefaultMemoryType);
+
+ //
+ // Set default attributes to all spaces.
+ //
+ for (Index = 0; Index < NumberOfDescriptors; Index++) {
+ if (MemorySpaceMap[Index].GcdMemoryType == EfiGcdMemoryTypeNonExistent) {
+ continue;
+ }
+ gDS->SetMemorySpaceAttributes (
+ MemorySpaceMap[Index].BaseAddress,
+ MemorySpaceMap[Index].Length,
+ ((MemorySpaceMap[Index].Attributes & ~EFI_MEMORY_CACHETYPE_MASK) |
+ (MemorySpaceMap[Index].Capabilities & DefaultAttributes))
+ );
+ }
+
+ //
+ // Go for variable MTRRs, WB first, Other types second
+ //
+ for (Index = 0; Index < 6; Index++) {
+ if (mVariableMtrr[Index].Valid &&
+ mVariableMtrr[Index].Type == EFI_CACHE_WRITEBACK) {
+ SetGcdMemorySpaceAttributes (
+ MemorySpaceMap,
+ NumberOfDescriptors,
+ mVariableMtrr[Index].BaseAddress,
+ mVariableMtrr[Index].Length,
+ EFI_MEMORY_WB
+ );
+ }
+ }
+ for (Index = 0; Index < 6; Index++) {
+ if (mVariableMtrr[Index].Valid &&
+ mVariableMtrr[Index].Type != EFI_CACHE_WRITEBACK) {
+ Attributes = GetMemorySpaceAttributeFromMtrrType ((UINT8) mVariableMtrr[Index].Type);
+ SetGcdMemorySpaceAttributes (
+ MemorySpaceMap,
+ NumberOfDescriptors,
+ mVariableMtrr[Index].BaseAddress,
+ mVariableMtrr[Index].Length,
+ Attributes
+ );
+ }
+ }
+
+ //
+ // Go for fixed MTRRs
+ //
+ Attributes = 0;
+ BaseAddress = 0;
+ Length = 0;
+ for (Index = 0; Index < V_EFI_FIXED_MTRR_NUMBER; Index++) {
+ RegValue = AsmReadMsr64 (mFixedMtrrTable[Index].Msr);
+ for (SubIndex = 0; SubIndex < 8; SubIndex++) {
+ MtrrType = (UINT8) RShiftU64 (RegValue, SubIndex * 8);
+ CurrentAttributes = GetMemorySpaceAttributeFromMtrrType (MtrrType);
+ if (Length == 0) {
+ Attributes = CurrentAttributes;
+ } else {
+ if (CurrentAttributes != Attributes) {
+ SetGcdMemorySpaceAttributes (
+ MemorySpaceMap,
+ NumberOfDescriptors,
+ BaseAddress,
+ Length,
+ Attributes
+ );
+ BaseAddress = mFixedMtrrTable[Index].BaseAddress + mFixedMtrrTable[Index].Length * SubIndex;
+ Length = 0;
+ Attributes = CurrentAttributes;
+ }
+ }
+ Length += mFixedMtrrTable[Index].Length;
+ }
+ }
+ //
+ // handle the last region
+ //
+ SetGcdMemorySpaceAttributes (
+ MemorySpaceMap,
+ NumberOfDescriptors,
+ BaseAddress,
+ Length,
+ Attributes
+ );
+
+ Done:
+ if (MemorySpaceMap != NULL) {
+ gBS->FreePool (MemorySpaceMap);
+ }
+
+ return Status;
+}
+
+/**
+ Search into the Gcd Memory Space for descriptors (from StartIndex
+ to EndIndex) that contains the memory range specified by BaseAddress
+ and Length.
+
+ @param[in] MemorySpaceMap Gcd Memory Space Map as array
+ @param[in] NumberOfDescriptors Number of descriptors in map
+ @param[in] BaseAddress BaseAddress for the requested range
+ @param[in] Length Length for the requested range
+ @param[out] *StartIndex Start index into the Gcd Memory Space Map
+ @param[out] *EndIndex End index into the Gcd Memory Space Map
+
+ @retval EFI_SUCCESS Search successfully
+ @retval EFI_NOT_FOUND The requested descriptors not exist
+
+**/
+EFI_STATUS
+SearchGcdMemorySpaces (
+ IN EFI_GCD_MEMORY_SPACE_DESCRIPTOR *MemorySpaceMap,
+ IN UINTN NumberOfDescriptors,
+ IN EFI_PHYSICAL_ADDRESS BaseAddress,
+ IN UINT64 Length,
+ OUT UINTN *StartIndex,
+ OUT UINTN *EndIndex
+ )
+{
+ UINTN Index;
+
+ *StartIndex = 0;
+ *EndIndex = 0;
+
+ for (Index = 0; Index < NumberOfDescriptors; Index++) {
+ if (BaseAddress >= MemorySpaceMap[Index].BaseAddress &&
+ BaseAddress < MemorySpaceMap[Index].BaseAddress + MemorySpaceMap[Index].Length) {
+ *StartIndex = Index;
+ }
+ if (BaseAddress + Length - 1 >= MemorySpaceMap[Index].BaseAddress &&
+ BaseAddress + Length - 1 < MemorySpaceMap[Index].BaseAddress + MemorySpaceMap[Index].Length) {
+ *EndIndex = Index;
+ return EFI_SUCCESS;
+ }
+ }
+
+ return EFI_NOT_FOUND;
+}
+
+/**
+ Set the attributes for a specified range in Gcd Memory Space Map.
+
+ @param[in] MemorySpaceMap Gcd Memory Space Map as array
+ @param[in] NumberOfDescriptors Number of descriptors in map
+ @param[in] BaseAddress BaseAddress for the range
+ @param[in] Length Length for the range
+ @param[in] Attributes Attributes to set
+
+ @retval EFI_SUCCESS Set successfully
+ @retval EFI_NOT_FOUND The specified range does not exist in Gcd Memory Space
+
+**/
+EFI_STATUS
+SetGcdMemorySpaceAttributes (
+ IN EFI_GCD_MEMORY_SPACE_DESCRIPTOR *MemorySpaceMap,
+ IN UINTN NumberOfDescriptors,
+ IN EFI_PHYSICAL_ADDRESS BaseAddress,
+ IN UINT64 Length,
+ IN UINT64 Attributes
+ )
+{
+ EFI_STATUS Status;
+ UINTN Index;
+ UINTN StartIndex;
+ UINTN EndIndex;
+ EFI_PHYSICAL_ADDRESS RegionStart;
+ UINT64 RegionLength;
+
+ Status = SearchGcdMemorySpaces (
+ MemorySpaceMap,
+ NumberOfDescriptors,
+ BaseAddress,
+ Length,
+ &StartIndex,
+ &EndIndex
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ for (Index = StartIndex; Index <= EndIndex; Index++) {
+ if (MemorySpaceMap[Index].GcdMemoryType == EfiGcdMemoryTypeNonExistent) {
+ continue;
+ }
+ if (BaseAddress >= MemorySpaceMap[Index].BaseAddress) {
+ RegionStart = BaseAddress;
+ } else {
+ RegionStart = MemorySpaceMap[Index].BaseAddress;
+ }
+ if (BaseAddress + Length - 1 < MemorySpaceMap[Index].BaseAddress + MemorySpaceMap[Index].Length) {
+ RegionLength = BaseAddress + Length - RegionStart;
+ } else {
+ RegionLength = MemorySpaceMap[Index].BaseAddress + MemorySpaceMap[Index].Length - RegionStart;
+ }
+ gDS->SetMemorySpaceAttributes (
+ RegionStart,
+ RegionLength,
+ ((MemorySpaceMap[Index].Attributes & ~EFI_MEMORY_CACHETYPE_MASK) |
+ (MemorySpaceMap[Index].Capabilities & Attributes))
+ );
+ }
+
+ return EFI_SUCCESS;
+}
diff --git a/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/CpuInit/MemoryAttribute.h b/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/CpuInit/MemoryAttribute.h
new file mode 100644
index 0000000000..eb70d66252
--- /dev/null
+++ b/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/CpuInit/MemoryAttribute.h
@@ -0,0 +1,136 @@
+/** @file
+ The definition of Memory Attribute.
+
+ Copyright (c) 1999 - 2015, 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 _EFI_MEMORY_ATTRIB_H
+#define _EFI_MEMORY_ATTRIB_H
+
+extern UINT32 mUsedMtrr;
+/**
+ @todo add description
+
+**/
+typedef struct {
+ UINT32 Msr;
+ UINT32 BaseAddress;
+ UINT32 Length;
+} EFI_FIXED_MTRR;
+/**
+ @todo add description
+
+**/
+typedef struct {
+ UINT64 BaseAddress;
+ UINT64 Length;
+ UINT64 Type;
+ UINT32 Msr;
+ BOOLEAN Valid;
+} EFI_VARIABLE_MTRR;
+
+#define EFI_MEMORY_CACHETYPE_MASK (EFI_MEMORY_UC | EFI_MEMORY_WC | EFI_MEMORY_WT | EFI_MEMORY_WB | EFI_MEMORY_UCE)
+
+EFI_STATUS
+ProgramFixedMtrr (
+ IN UINT64 MemoryCacheType,
+ IN UINT64 *Base,
+ IN UINT64 *Length
+ );
+
+VOID
+PreMtrrChange (
+ VOID
+ );
+VOID
+PostMtrrChange (
+ VOID
+ );
+
+EFI_STATUS
+GetMemoryAttribute (
+ VOID
+ );
+
+BOOLEAN
+CheckMemoryAttributeOverlap (
+ IN EFI_PHYSICAL_ADDRESS Start,
+ IN EFI_PHYSICAL_ADDRESS End
+ );
+
+EFI_STATUS
+CombineMemoryAttribute (
+ IN UINT64 Attribute,
+ IN UINT64 *Base,
+ IN UINT64 *Length
+ );
+
+EFI_STATUS
+GetDirection (
+ IN UINT64 Input,
+ IN UINTN *MtrrNumber,
+ IN BOOLEAN *Direction
+ );
+
+UINT64
+Power2MaxMemory (
+ IN UINT64 MemoryLength
+ );
+
+EFI_STATUS
+InvariableMtrr (
+ IN UINTN MtrrNumber,
+ IN UINTN Index
+ );
+
+EFI_STATUS
+ProgramVariableMtrr (
+ IN UINTN MtrrNumber,
+ IN EFI_PHYSICAL_ADDRESS BaseAddress,
+ IN UINT64 Length,
+ IN UINT64 MemoryCacheType
+ );
+
+EFI_STATUS
+CleanupVariableMtrr (
+ VOID
+ );
+
+UINT64
+GetMemorySpaceAttributeFromMtrrType (
+ IN UINT8 MtrrAttribute
+ );
+
+EFI_STATUS
+RefreshGcdMemoryAttributes (
+ VOID
+ );
+
+EFI_STATUS
+SearchGcdMemorySpaces (
+ IN EFI_GCD_MEMORY_SPACE_DESCRIPTOR *MemorySpaceMap,
+ IN UINTN NumberOfDescriptors,
+ IN EFI_PHYSICAL_ADDRESS BaseAddress,
+ IN UINT64 Length,
+ OUT UINTN *StartIndex,
+ OUT UINTN *EndIndex
+ );
+
+EFI_STATUS
+SetGcdMemorySpaceAttributes (
+ IN EFI_GCD_MEMORY_SPACE_DESCRIPTOR *MemorySpaceMap,
+ IN UINTN NumberOfDescriptors,
+ IN EFI_PHYSICAL_ADDRESS BaseAddress,
+ IN UINT64 Length,
+ IN UINT64 Attributes
+ );
+#endif
diff --git a/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/CpuInit/Microcode.c b/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/CpuInit/Microcode.c
new file mode 100644
index 0000000000..61b7227a4e
--- /dev/null
+++ b/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/CpuInit/Microcode.c
@@ -0,0 +1,483 @@
+/** @file
+ The function of Microcode.
+
+ Copyright (c) 1999 - 2015, 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 "CpuDxe.h"
+#include "MpCommon.h"
+
+//
+// Array of pointers which each points to 1 microcode update binary (in memory)
+//
+EFI_CPU_MICROCODE_HEADER **mMicrocodePointerBuffer;
+BOOLEAN mVerifyMicrocodeChecksum = TRUE;
+
+//
+// Function declaration
+//
+EFI_STATUS
+FindLoadMicrocode (
+ IN UINT32 Cpuid,
+ IN EFI_CPU_MICROCODE_HEADER **MicrocodePointerBuffer,
+ IN OUT UINT32 *Revision
+ );
+
+/**
+ Returns the processor microcode revision of the processor installed in the system.
+
+ @retval Processor Microcode Revision
+
+**/
+UINT32
+GetCpuUcodeRevision (
+ VOID
+ )
+{
+ AsmWriteMsr64 (EFI_MSR_IA32_BIOS_SIGN_ID, 0);
+ AsmCpuid (EFI_CPUID_VERSION_INFO, NULL, NULL, NULL, NULL);
+ return (UINT32) RShiftU64 (AsmReadMsr64 (EFI_MSR_IA32_BIOS_SIGN_ID), 32);
+}
+
+/**
+ This will locate a processor microcode and if it finds a newer revision, it will
+ load it to the processor.
+
+ @param[in] MicrocodePointerBuffer The Array of pointers which each points to 1 microcode update binary (in memory)
+ @param[out] FailedRevision The microcode revision that fails to be loaded
+ @param[in] IsBsp Add parameter description
+
+ @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 EFI_CPU_MICROCODE_HEADER **MicrocodePointerBuffer,
+ OUT UINT32 *FailedRevision,
+ IN BOOLEAN IsBsp
+ )
+{
+ EFI_STATUS Status;
+ UINT32 Cpuid_RegEax;
+ UINT32 UcodeRevision;
+
+ AsmCpuid (EFI_CPUID_VERSION_INFO, &Cpuid_RegEax, NULL, NULL, NULL);
+
+ if (IsBsp) {
+ //
+ // Force Microcode to be loaded for BSP anyway
+ //
+ UcodeRevision = 0;
+ } else {
+ UcodeRevision = GetCpuUcodeRevision ();
+ }
+
+ Status = FindLoadMicrocode (Cpuid_RegEax, MicrocodePointerBuffer, &UcodeRevision);
+ *FailedRevision = UcodeRevision;
+
+ return Status;
+}
+
+/**
+ This will load the microcode to all the processors.
+
+ @param[in] MicrocodeEntryPoint The microcode update pointer
+ @param[in] Revision The current (before load this microcode update) microcode revision
+
+ @retval EFI_SUCCESS Microcode loaded
+ @retval EFI_LOAD_ERROR Microcode not loaded
+
+**/
+EFI_STATUS
+LoadMicrocode (
+ IN EFI_CPU_MICROCODE_HEADER *MicrocodeEntryPoint,
+ IN UINT32 *Revision
+ )
+{
+ //
+ // Load the Processor Microcode
+ //
+ AsmWriteMsr64 (
+ EFI_MSR_IA32_BIOS_UPDT_TRIG,
+ (UINT64) ((UINTN) MicrocodeEntryPoint + sizeof (EFI_CPU_MICROCODE_HEADER))
+ );
+
+ //
+ // Verify that the microcode has been loaded
+ //
+ if (GetCpuUcodeRevision () == *Revision) {
+ return EFI_LOAD_ERROR;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Verify the DWORD type checksum
+
+ @param[in] ChecksumAddr The start address to be checkumed
+ @param[in] ChecksumType The type of data to be checksumed
+
+ @retval EFI_SUCCESS Checksum correct
+ @retval EFI_CRC_ERROR Checksum incorrect
+
+**/
+EFI_STATUS
+Checksum32Verify (
+ IN UINT32 *ChecksumAddr,
+ IN UINT32 ChecksumLen
+ )
+{
+ UINT32 Checksum;
+ UINT32 Index;
+
+ Checksum = 0;
+
+ for (Index = 0; Index < ChecksumLen; Index ++) {
+ Checksum += ChecksumAddr[Index];
+ }
+
+ return (Checksum == 0) ? EFI_SUCCESS : EFI_CRC_ERROR;
+}
+
+/**
+ This will locate a processor microcode and if it finds a newer revision, it will
+ load it to the processor.
+
+ @param[in] Cpuid Data returned by cpuid instruction
+ @param[in] **MicrocodePointerBuffer The Array of pointers which each points to 1 microcode update binary (in memory)
+ @param[in, out] *Revision As input parameter, the current microcode revision;
+ as output parameter, the microcode revision after microcode update is loaded
+
+ @retval EFI_SUCCESS A new microcode update is loaded
+ @retval Other Due to some reason, no new microcode update is loaded
+
+**/
+EFI_STATUS
+FindLoadMicrocode (
+ IN UINT32 Cpuid,
+ IN EFI_CPU_MICROCODE_HEADER **MicrocodePointerBuffer,
+ IN OUT UINT32 *Revision
+ )
+{
+ EFI_STATUS Status;
+ EFI_CPU_MICROCODE_HEADER *MicrocodeEntryPoint;
+ UINT8 Index;
+ UINT8 Index2;
+ UINT8 MsrPlatform;
+ UINT32 ExtendedTableLength;
+ UINT32 ExtendedTableCount;
+ BOOLEAN CorrectMicrocode;
+ EFI_CPU_MICROCODE_EXTENDED_TABLE *ExtendedTable;
+ EFI_CPU_MICROCODE_EXTENDED_TABLE_HEADER *ExtendedTableHeader;
+
+ Status = EFI_NOT_FOUND;
+ ExtendedTableLength = 0;
+
+ //
+ // The index of platform information resides in bits 50:52 of MSR IA32_PLATFORM_ID
+ //
+ MsrPlatform = (UINT8) (RShiftU64 ((AsmReadMsr64 (EFI_MSR_IA32_PLATFORM_ID) & B_EFI_MSR_IA32_PLATFORM_ID_PLATFORM_ID_BITS_MASK), \
+ N_EFI_MSR_IA32_PLATFORM_ID_PLATFORM_ID_BITS));
+
+ Index = 0;
+ while (MicrocodePointerBuffer[Index] != NULL) {
+ MicrocodeEntryPoint = MicrocodePointerBuffer[Index];
+ CorrectMicrocode = FALSE;
+ //
+ // Check if the microcode is for the Cpu and the version is newer
+ // and the update can be processed on the platform
+ //
+ if (MicrocodeEntryPoint->HeaderVersion == 0x00000001) {
+ if ((MicrocodeEntryPoint->ProcessorId == Cpuid) &&
+ (MicrocodeEntryPoint->UpdateRevision >= *Revision) &&
+ (MicrocodeEntryPoint->ProcessorFlags & (1 << MsrPlatform)) ) {
+ if (mVerifyMicrocodeChecksum == TRUE) {
+ if (MicrocodeEntryPoint->DataSize == 0) {
+ Status = Checksum32Verify ((UINT32 *)MicrocodeEntryPoint, 2048 / sizeof(UINT32));
+ } else {
+ Status = Checksum32Verify ((UINT32 *)MicrocodeEntryPoint, (MicrocodeEntryPoint->DataSize + sizeof(EFI_CPU_MICROCODE_HEADER)) / sizeof(UINT32));
+ }
+ if (!EFI_ERROR (Status)) {
+ mVerifyMicrocodeChecksum = FALSE;
+ CorrectMicrocode = TRUE;
+ }
+ } else {
+ CorrectMicrocode = TRUE;
+ }
+ } else if ((MicrocodeEntryPoint->DataSize !=0) && (MicrocodeEntryPoint->UpdateRevision > *Revision)) {
+ //
+ // Check the Extended Signature if the entended signature exist
+ // Only the data size != 0 the extended signature may exist
+ //
+ ExtendedTableLength = MicrocodeEntryPoint->TotalSize - (MicrocodeEntryPoint->DataSize + sizeof (EFI_CPU_MICROCODE_HEADER));
+ if (ExtendedTableLength != 0) {
+ //
+ // Extended Table exist, check if the CPU in support list
+ //
+ ExtendedTableHeader = (EFI_CPU_MICROCODE_EXTENDED_TABLE_HEADER *)((UINT8 *)(MicrocodeEntryPoint) + MicrocodeEntryPoint->DataSize + 48);
+ //
+ // Calulate Extended Checksum
+ //
+ if ((ExtendedTableLength % 4) == 0) {
+ Status = Checksum32Verify ((UINT32 *)ExtendedTableHeader, ExtendedTableLength / sizeof(UINT32));
+ if (!EFI_ERROR (Status)) {
+ //
+ // Checksum correct
+ //
+ ExtendedTableCount = ExtendedTableHeader->ExtendedSignatureCount;
+ ExtendedTable = (EFI_CPU_MICROCODE_EXTENDED_TABLE *)(ExtendedTableHeader + 1);
+ for (Index2 = 0; Index2 < ExtendedTableCount; Index2 ++) {
+ Status = Checksum32Verify ((UINT32 *)ExtendedTable, sizeof(EFI_CPU_MICROCODE_EXTENDED_TABLE) / sizeof(UINT32));
+ if (!EFI_ERROR (Status)) {
+ //
+ // Verify Header
+ //
+ if ((ExtendedTable->ProcessorSignature == Cpuid) &&
+ (ExtendedTable->ProcessorFlag & (1 << MsrPlatform)) ) {
+ //
+ // Find one
+ //
+ CorrectMicrocode = TRUE;
+ break;
+ }
+ }
+ ExtendedTable ++;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if (CorrectMicrocode) {
+ Status = LoadMicrocode (MicrocodeEntryPoint, Revision);
+ *Revision = MicrocodeEntryPoint->UpdateRevision;
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ }
+
+ Index++;
+ }
+
+ return Status;
+}
+
+/**
+ Get the microcode patch.
+
+ @param[in] This Driver context.
+ @param[out] MicrocodeData Retrieved image of the microcode.
+
+ @retval EFI_SUCCESS Image found.
+ @retval EFI_NOT_FOUND Image not found.
+
+**/
+EFI_STATUS
+EFIAPI
+PlatformCpuRetrieveMicrocode (
+ OUT UINT8 **MicrocodeData
+ )
+{
+ EFI_CPU_MICROCODE_HEADER *Microcode;
+ UINTN MicrocodeStart;
+ UINTN MicrocodeEnd;
+ UINTN TotalSize;
+
+ DEBUG ((EFI_D_INFO, "PcdFlashMicroCodeRegionBase - 0x%x\n", PcdGet32 (PcdFlashMicroCodeRegionBase)));
+ DEBUG ((EFI_D_INFO, "PcdFlashMicroCodeOffset - 0x%x\n", PcdGet32 (PcdFlashMicroCodeOffset)));
+ DEBUG ((EFI_D_INFO, "PcdFlashMicroCodeRegionSize - 0x%x\n", PcdGet32 (PcdFlashMicroCodeRegionSize)));
+
+ MicrocodeStart =(UINTN)PcdGet32 (PcdFlashMicroCodeRegionBase) + PcdGet32 (PcdFlashMicroCodeOffset);
+ MicrocodeEnd = (UINTN)PcdGet32 (PcdFlashMicroCodeRegionBase) + (UINTN)PcdGet32 (PcdFlashMicroCodeRegionSize);
+
+ if (*MicrocodeData == NULL) {
+ *MicrocodeData = (UINT8 *) (UINTN) MicrocodeStart;
+ } else {
+ if (*MicrocodeData < (UINT8 *) (UINTN) MicrocodeStart) {
+ return EFI_NOT_FOUND;
+ }
+
+ TotalSize = (UINTN) (((EFI_CPU_MICROCODE_HEADER *) *MicrocodeData)->TotalSize);
+ if (TotalSize == 0) {
+ TotalSize = 2048;
+ }
+ //
+ // Add alignment check - begin
+ //
+ if ((TotalSize & 0x7FF) != 0) {
+ TotalSize = (TotalSize & 0xFFFFF800) + 0x800;
+ }
+ //
+ // Add alignment check - end
+ //
+ *MicrocodeData += TotalSize;
+ Microcode = (EFI_CPU_MICROCODE_HEADER *) *MicrocodeData;
+ if (*MicrocodeData >= (UINT8 *) (UINTN) (MicrocodeEnd) || Microcode->TotalSize == (UINT32) -1) {
+ return EFI_NOT_FOUND;
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Load all microcode updates to memory. Since in S3 resume boot path, CPUs should be
+ patched again, these microcode updates are copied to OS reserved memory.
+
+ @retval EFI_SUCCESS All microcode updates are loaded to memory successfully
+ @retval EFI_OUT_OF_RESOURCES Not enough memory to accomodate all the microcode updates
+
+**/
+EFI_STATUS
+LoadAllMicrocodeUpdates (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ EFI_CPU_MICROCODE_HEADER *MicrocodeEntryPoint;
+ EFI_CPU_MICROCODE_HEADER *MicrocodeBuffer;
+ UINTN MicrocodeNumber;
+ UINTN Index;
+ UINTN TotalSize[NUMBER_OF_MICROCODE_UPDATE + 1];
+
+ MicrocodeNumber = 0;
+ Status = gBS->AllocatePool (
+ EfiACPIMemoryNVS,
+ sizeof (EFI_CPU_MICROCODE_HEADER *) * (NUMBER_OF_MICROCODE_UPDATE + 1),
+ (VOID *) (&mMicrocodePointerBuffer)
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ ZeroMem (mMicrocodePointerBuffer, sizeof (EFI_CPU_MICROCODE_HEADER *) * (NUMBER_OF_MICROCODE_UPDATE + 1));
+ ZeroMem (TotalSize, sizeof(TotalSize));
+
+ MicrocodeEntryPoint = NULL;
+ MicrocodeBuffer = NULL;
+ while (TRUE) {
+ //
+ // Continue to try to find patch
+ //
+ Status = PlatformCpuRetrieveMicrocode ((VOID *) &MicrocodeEntryPoint);
+
+ if (EFI_ERROR (Status)) {
+ if (Status == EFI_NOT_FOUND) {
+ Status = EFI_SUCCESS;
+ }
+ break;
+
+ } else {
+ if (MicrocodeNumber >= NUMBER_OF_MICROCODE_UPDATE) {
+ DEBUG ((EFI_D_ERROR, "CPU Too Many Microcode available > %d\n", (UINTN)NUMBER_OF_MICROCODE_UPDATE));
+ Status = EFI_SUCCESS;
+ break;
+ }
+
+ if (MicrocodeEntryPoint->DataSize == 0) {
+ TotalSize[MicrocodeNumber] = 2048;
+ } else {
+ TotalSize[MicrocodeNumber] = MicrocodeEntryPoint->TotalSize;
+ }
+
+ Status = AllocateReservedMemoryBelow4G (
+ TotalSize[MicrocodeNumber],
+ (VOID **) &MicrocodeBuffer
+ );
+ if (EFI_ERROR (Status)) {
+ break;
+ }
+
+ CopyMem (MicrocodeBuffer, MicrocodeEntryPoint, TotalSize[MicrocodeNumber]);
+ mMicrocodePointerBuffer[MicrocodeNumber] = MicrocodeBuffer;
+ MicrocodeNumber++;
+ }
+ }
+
+ if (EFI_ERROR (Status)) {
+ Index = 0;
+ while (mMicrocodePointerBuffer[Index] != NULL) {
+ gBS->FreePages (
+ (EFI_PHYSICAL_ADDRESS)(UINTN)mMicrocodePointerBuffer[Index],
+ EFI_SIZE_TO_PAGES(TotalSize[Index])
+ );
+ mMicrocodePointerBuffer[Index] = NULL;
+ Index++;
+ }
+ }
+
+ return Status;
+}
+
+/**
+ Check if loading microcode update fails, if so, report proper status code
+
+ @param[in] CpuNumber The CPU number
+ @param[in] Status The return value of InitializeMicrocode()
+ @param[in] FailedRevision The revision of the microcode update that failed to be loaded
+
+ @retval EFI_SUCCESS The status is check and proper status code is reported
+
+**/
+EFI_STATUS
+CheckMicrocodeUpdate (
+ IN UINTN CpuNumber,
+ IN EFI_STATUS Status,
+ IN UINT32 FailedRevision
+ )
+{
+ EFI_STATUS_CODE_VALUE StatusCode;
+ EFI_STATUS_CODE_DATA *ErrorDataPointer;
+ EFI_COMPUTING_UNIT_MICROCODE_UPDATE_ERROR_DATA ErrorData;
+ UINTN DataSize;
+ if (!EFI_ERROR (Status)) {
+ return EFI_SUCCESS;
+ }
+
+ if (Status == EFI_LOAD_ERROR) {
+ ErrorData.DataHeader.HeaderSize = sizeof (EFI_STATUS_CODE_DATA);
+ ErrorData.DataHeader.Size = sizeof (EFI_COMPUTING_UNIT_MICROCODE_UPDATE_ERROR_DATA) - sizeof (EFI_STATUS_CODE_DATA);
+
+ CopyMem (&ErrorData.DataHeader.Type, &gEfiStatusCodeSpecificDataGuid, sizeof (EFI_GUID));
+ ErrorData.Version = FailedRevision;
+ StatusCode = EFI_COMPUTING_UNIT_HOST_PROCESSOR | EFI_CU_HP_EC_MICROCODE_UPDATE;
+ ErrorDataPointer = (EFI_STATUS_CODE_DATA *) &ErrorData;
+ } else if (Status == EFI_NOT_FOUND) {
+ if (GetCpuUcodeRevision () != 0) {
+ //
+ // Some other driver (for example, SEC) already updated CPU microcode
+ //
+ return EFI_SUCCESS;
+ }
+
+ StatusCode = EFI_COMPUTING_UNIT_HOST_PROCESSOR | EFI_CU_HP_EC_NO_MICROCODE_UPDATE;
+ ErrorDataPointer = NULL;
+
+ } else {
+ return Status;
+ }
+ if (ErrorDataPointer == NULL) {
+ DataSize = 0;
+ } else {
+ DataSize = sizeof(EFI_COMPUTING_UNIT_MICROCODE_UPDATE_ERROR_DATA);
+ }
+ return REPORT_STATUS_CODE_EX (
+ EFI_ERROR_MINOR | EFI_ERROR_CODE,
+ StatusCode,
+ (UINT32) CpuNumber,
+ &gEfiCallerIdGuid,
+ NULL,
+ ErrorDataPointer,
+ DataSize
+ );
+}
diff --git a/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/CpuInit/MiscFuncs.c b/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/CpuInit/MiscFuncs.c
new file mode 100644
index 0000000000..975907fa39
--- /dev/null
+++ b/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/CpuInit/MiscFuncs.c
@@ -0,0 +1,103 @@
+/** @file
+ Provide the misc functions to enable some CPU features.
+
+ Copyright (c) 1999 - 2015, 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 "CpuDxe.h"
+#include "PlatformMpService.h"
+#include "MiscFuncs.h"
+
+extern MP_SYSTEM_DATA *mMPSystemData;
+
+/**
+ @todo add description
+
+**/
+VOID
+EfiWriteToScript (
+ IN UINT32 Index,
+ IN UINT64 Value
+ )
+{
+ UINTN TableIndex;
+
+ if (mMPSystemData == NULL) {
+ ASSERT(mMPSystemData != NULL);
+ return;
+ }
+
+ //
+ // Save it into script
+ //
+ AsmAcquireMPLock (&(mMPSystemData->S3BootScriptLock));
+ TableIndex = mMPSystemData->S3BootScriptCount++;
+ AsmReleaseMPLock (&(mMPSystemData->S3BootScriptLock));
+
+ ASSERT (TableIndex < MAX_CPU_S3_TABLE_SIZE - 1);
+ mMPSystemData->S3BootScriptTable[TableIndex].ApicId = GetApicID (NULL, NULL);
+ mMPSystemData->S3BootScriptTable[TableIndex].MsrIndex = Index;
+ mMPSystemData->S3BootScriptTable[TableIndex].MsrValue = Value;
+}
+
+/**
+ @todo add description
+
+**/
+VOID
+EfiWriteMsrWithScript (
+ IN UINT32 Index,
+ IN UINT64 Value
+ )
+{
+ AsmWriteMsr64 (Index, Value);
+ EfiWriteToScript (Index, Value);
+}
+
+/**
+ Provide access to the CPU misc enables MSR
+
+ @param[in] Enable -Enable or Disable Misc Features
+
+**/
+VOID
+CpuMiscEnable (
+ BOOLEAN Enable,
+ UINT64 BitMask
+)
+{
+ UINT64 MsrValue;
+
+ MsrValue = AsmReadMsr64 (EFI_MSR_IA32_MISC_ENABLE);
+ if (Enable) {
+ MsrValue |= BitMask;
+ } else {
+ MsrValue &= ~BitMask;
+ }
+ AsmWriteMsr64 (EFI_MSR_IA32_MISC_ENABLE, MsrValue);
+}
+
+/**
+ @todo add description
+
+**/
+VOID
+ProgramProcessorFuncs (
+ IN MP_SYSTEM_DATA *MPSystemData
+ )
+{
+ //
+ // Initialize some misc functions
+ //
+ CpuMiscEnable (MPSystemData->MonitorMwaitEnable, B_EFI_MSR_IA32_MISC_ENABLE_MONITOR);
+
+}
diff --git a/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/CpuInit/MiscFuncs.h b/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/CpuInit/MiscFuncs.h
new file mode 100644
index 0000000000..c64c2d1dcc
--- /dev/null
+++ b/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/CpuInit/MiscFuncs.h
@@ -0,0 +1,45 @@
+/** @file
+ Provide the misc functions to enable some CPU features.
+
+ Copyright (c) 1999 - 2015, 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 _MISC_FUNCS_H_
+#define _MISC_FUNCS_H_
+
+#include "CpuDxe.h"
+#include "PlatformMpService.h"
+
+VOID
+EfiWriteToScript (
+ IN UINT32 Index,
+ IN UINT64 Value
+ );
+
+VOID
+EfiWriteMsrWithScript (
+ IN UINT32 Index,
+ IN UINT64 Value
+ );
+
+VOID
+ProgramProcessorFuncs (
+ IN MP_SYSTEM_DATA *MPSystemData
+ );
+
+VOID
+CpuMiscEnable (
+ BOOLEAN Enable,
+ UINT64 BitMask
+);
+
+#endif
diff --git a/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/CpuInit/MpCommon.c b/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/CpuInit/MpCommon.c
new file mode 100644
index 0000000000..ad98d91a56
--- /dev/null
+++ b/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/CpuInit/MpCommon.c
@@ -0,0 +1,879 @@
+/** @file
+ Code which support multi-processor.
+
+ Copyright (c) 1999 - 2015, 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 "MpCommon.h"
+#include "CpuDxe.h"
+#include "MiscFuncs.h"
+#include <Library/IoLib.h>
+#include <Protocol/SmmControl2.h>
+#include <Protocol/SmmAccess2.h>
+
+extern MP_SYSTEM_DATA *mMPSystemData;
+extern EFI_PHYSICAL_ADDRESS mOriginalBuffer;
+extern EFI_PHYSICAL_ADDRESS mBackupBuffer;
+extern EFI_METRONOME_ARCH_PROTOCOL *mMetronome;
+volatile UINTN mSwitchToLegacyRegionCount = 0;
+
+EFI_GUID mSmramCpuNvsHeaderGuid = EFI_SMRAM_CPU_NVS_HEADER_GUID;
+CHAR16 EfiPlatformCpuInfoVariable[] = L"PlatformCpuInfo";
+
+/**
+ @todo add description
+
+**/
+BOOLEAN
+IsXapicEnabled (
+ VOID
+ )
+{
+ UINT64 MsrValue;
+
+ MsrValue = AsmReadMsr64 (EFI_MSR_IA32_APIC_BASE);
+ if (MsrValue & B_EFI_MSR_IA32_APIC_BASE_APIC_GLOBAL_ENABLE) {
+ if (MsrValue & B_EFI_MSR_IA32_APIC_BASE_M_XAPIC) {
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+/**
+ @todo Add function description
+
+ @param[in] @todo add argument description
+
+ @retval @todo add return values
+
+**/
+UINT64
+ReadApicMsrOrMemory (
+ BOOLEAN XapicEnabled,
+ UINT32 MsrIndex,
+ UINT64 MemoryMappedIo
+)
+{
+ UINT64 Value;
+
+ if (XapicEnabled) {
+ Value = AsmReadMsr64 (MsrIndex);
+ } else {
+ Value = (UINT64)*(volatile UINT32 *)(UINTN)MemoryMappedIo;
+ }
+
+ return Value;
+}
+
+/**
+ @todo Add function description
+
+ @param[in] BSP - @todo add argument description
+
+ @retval @todo add return values
+
+**/
+VOID
+WriteApicMsrOrMemory (
+ BOOLEAN XapicEnabled,
+ UINT32 MsrIndex,
+ UINT64 MemoryMappedIo,
+ UINT64 Value
+)
+{
+ if (XapicEnabled) {
+ AsmWriteMsr64 (MsrIndex, Value);
+ } else {
+ if (MsrIndex == EFI_MSR_EXT_XAPIC_ICR) {
+ *(volatile UINT32 *)(UINTN)(MemoryMappedIo - APIC_REGISTER_ICR_LOW_OFFSET + APIC_REGISTER_ICR_HIGH_OFFSET) = (UINT32)(Value >> 32);
+ }
+ *(volatile UINT32 *)(UINTN)MemoryMappedIo = (UINT32)Value;
+ }
+}
+
+/**
+ @todo Add function description
+
+ @param[in] BroadcastMode - @todo add argument description
+ @param[in] ApicID - @todo add argument description
+ @param[in] VectorNumber - @todo add argument description
+ @param[in] DeliveryMode - @todo add argument description
+ @param[in] TriggerMode - @todo add argument description
+ @param[in] Assert - @todo add argument description
+
+ @retval EFI_INVALID_PARAMETER - @todo Add description for return value
+ @retval EFI_NOT_READY - @todo Add description for return value
+ @retval EFI_SUCCESS - @todo Add description for return value
+
+**/
+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;
+ BOOLEAN XapicEnabled;
+
+ if (SINGLE_THREAD_BOOT_FLAG != 0) {
+ //
+ // Only for Debug to use Single Thread Boot
+ //
+ return EFI_SUCCESS;
+ }
+
+ //
+ // 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;
+ }
+
+ XapicEnabled = IsXapicEnabled ();
+
+ switch (BroadcastMode) {
+ case BROADCAST_MODE_SPECIFY_CPU:
+ if (XapicEnabled) {
+ ICRHigh = (UINT32)ApicID;
+ } else {
+ 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 (EFI_MSR_IA32_APIC_BASE);
+ ApicBase = ApicBaseReg & B_EFI_MSR_IA32_APIC_BASE_APIC_BASE_ADDRESS;
+
+ //
+ // According Nehalem BWG, if Extended XAPIC Mode is enabled,
+ // legacy xAPIC is no longer working.
+ // So, previous MMIO offset must be transferred to MSR offset R/W.
+ // ----------------------------------------------------------------
+ // MMIO Offset MSR Offset Register Name
+ // ----------------------------------------------------------------
+ // 300h-310h 830h Interrupt Command Register [63:0]
+ // 831h [Reserved]
+ // ----------------------------------------------------------------
+ //
+ WriteApicMsrOrMemory (XapicEnabled, EFI_MSR_EXT_XAPIC_ICR, ApicBase + APIC_REGISTER_ICR_LOW_OFFSET, (((UINT64)ICRHigh << 32) | (UINT64)ICRLow));
+
+ gBS->Stall (10);
+
+ ICRLow = (UINT32)ReadApicMsrOrMemory (XapicEnabled, EFI_MSR_EXT_XAPIC_ICR, ApicBase + APIC_REGISTER_ICR_LOW_OFFSET);
+
+ if (ICRLow & 0x1000) {
+ return EFI_NOT_READY;
+ }
+
+ gBS->Stall (100);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ @todo Add function description
+
+ @param[out] *ApicBase OPTIONAL - @todo add argument description
+ @param[out] *ApicVersion OPTIONAL - @todo add argument description
+
+ @retval - @todo add return values
+
+**/
+UINT32
+GetApicID (
+ OUT EFI_PHYSICAL_ADDRESS *ApicBase OPTIONAL,
+ OUT UINT32 *ApicVersion OPTIONAL
+ )
+{
+ UINT64 ApicBaseReg;
+ UINT32 ApicID;
+ UINT32 LocalApicVersion;
+ UINT64 LocalApicBase;
+ UINTN MsrValue;
+ BOOLEAN XapicEnabled;
+
+ XapicEnabled = IsXapicEnabled ();
+
+ if (XapicEnabled) {
+ //
+ // According to Nehalem BWG, if Extended XAPIC Mode
+ // is enabled, legacy xAPIC is no longer working.
+ // So, previous MMIO offset must be transfered
+ // to MSR offset R/W.
+ // MMIO Offset MSR Offset Register Name
+ // 020h 802h EFI_EXT_XAPIC_LOGICAL_APIC_ID
+ // 030h 803h EFI_EXT_XAPIC_VERSION
+ //
+ MsrValue = (UINTN) AsmReadMsr64 (EFI_MSR_EXT_XAPIC_VERSION);
+ *ApicVersion = (UINT32) (MsrValue & B_EFI_MSR_EXT_XAPIC_VERSION_VERSION);
+ *ApicBase = 0;
+
+ MsrValue = (UINTN) AsmReadMsr64 (EFI_MSR_EXT_XAPIC_LOGICAL_APIC_ID);
+ ApicID = (UINT32) MsrValue;
+ return (ApicID);
+ }
+
+ ApicBaseReg = AsmReadMsr64 (EFI_MSR_IA32_APIC_BASE);
+ LocalApicBase = ApicBaseReg & B_EFI_MSR_IA32_APIC_BASE_APIC_BASE_ADDRESS;
+ if (ApicBase) {
+ *ApicBase = LocalApicBase;
+ }
+ //
+ // if Apic is not enabled yet, enable it here
+ //
+ if ((ApicBaseReg & B_EFI_MSR_IA32_APIC_BASE_APIC_GLOBAL_ENABLE) == 0) {
+ ApicBaseReg |= B_EFI_MSR_IA32_APIC_BASE_APIC_GLOBAL_ENABLE;
+ AsmWriteMsr64 (EFI_MSR_IA32_APIC_BASE, ApicBaseReg);
+ }
+
+ if (ApicVersion) {
+ LocalApicVersion = *(volatile UINT32 *) (UINTN) (LocalApicBase + APIC_REGISTER_APIC_VERSION_OFFSET);
+ *ApicVersion = LocalApicVersion & B_APIC_REGISTER_APIC_VERSION_OFFSET_VERSION_MASK;
+ }
+
+ ApicID = *(volatile UINT32 *) (UINTN) (LocalApicBase + APIC_REGISTER_LOCAL_ID_OFFSET);
+ return ((ApicID & B_APIC_REGISTER_LOCAL_ID_OFFSET_XAPIC_ID_MASK) >> N_APIC_REGISTER_LOCAL_ID_OFFSET_XAPIC_ID_MASK);
+}
+
+/**
+ @todo Add function description
+
+ @param[in] BSP - @todo add argument description
+
+ @retval - @todo add return values
+
+**/
+VOID
+ProgramVirtualWireMode (
+ BOOLEAN BSP
+ )
+{
+ UINT64 ApicBaseReg;
+ EFI_PHYSICAL_ADDRESS ApicBase;
+ UINT64 EntryValue;
+ BOOLEAN XapicEnabled;
+ UINT32 VirtualWire;
+
+ VirtualWire = 0;
+
+ ApicBaseReg = AsmReadMsr64 (EFI_MSR_IA32_APIC_BASE);
+ ApicBase = ApicBaseReg & B_EFI_MSR_IA32_APIC_BASE_APIC_BASE_ADDRESS;
+
+ XapicEnabled = IsXapicEnabled ();
+
+ //
+ // Program the Spurious Vector entry if XAPIC is enabled
+ //
+ EntryValue = ReadApicMsrOrMemory (XapicEnabled, EFI_MSR_EXT_XAPIC_SVR, ApicBase + APIC_REGISTER_SPURIOUS_VECTOR_OFFSET);
+ EntryValue &= 0xFFFFFD0F;
+ EntryValue |= 0x10F;
+ WriteApicMsrOrMemory (XapicEnabled, EFI_MSR_EXT_XAPIC_SVR, ApicBase + APIC_REGISTER_SPURIOUS_VECTOR_OFFSET, EntryValue);
+
+ //
+ // Double check if it is BSP
+ //
+ if (!BSP) {
+ CpuDisableInterrupt ();
+ }
+
+ //
+ // Program the LINT0 vector entry as EntInt
+ //
+ EntryValue = ReadApicMsrOrMemory (XapicEnabled, EFI_MSR_EXT_XAPIC_LVT_LINT0, ApicBase + APIC_REGISTER_LINT0_VECTOR_OFFSET);
+ if ((VirtualWire == VIRT_WIRE_A) && BSP) {
+ EntryValue &= 0xFFFE00FF;
+ EntryValue |= 0x700;
+ } else {
+ EntryValue |= 0x10000; // set bit 16 as mask for LINT0
+ }
+ WriteApicMsrOrMemory (XapicEnabled, EFI_MSR_EXT_XAPIC_LVT_LINT0, ApicBase + APIC_REGISTER_LINT0_VECTOR_OFFSET, EntryValue);
+
+ if ((VirtualWire != VIRT_WIRE_A) && BSP) {
+ //
+ // Initialize the IOXApic RT table
+ //
+ *(volatile UINT8 *)(UINTN)IO_APIC_INDEX_REGISTER = 0x10;
+ *(volatile UINT32 *)(UINTN)IO_APIC_DATA_REGISTER = 0x0700;
+ *(volatile UINT8 *)(UINTN)IO_APIC_INDEX_REGISTER = 0x11;
+ *(volatile UINT32 *)(UINTN)IO_APIC_DATA_REGISTER = (GetApicID (NULL, NULL) << 24);
+ }
+}
+
+/**
+ @todo Add function description
+
+ @param[out] WakeUpBuffer - @todo add argument description
+
+ @retval - @todo add return values
+
+**/
+EFI_STATUS
+AllocateWakeUpBuffer (
+ OUT EFI_PHYSICAL_ADDRESS *WakeUpBuffer
+ )
+{
+ EFI_STATUS Status;
+
+ Status = EFI_SUCCESS;
+ for (*WakeUpBuffer = 0x8F000; *WakeUpBuffer >= 0x2000; *WakeUpBuffer -= 0x1000) {
+ Status = gBS->AllocatePages (
+ AllocateAddress,
+ EfiACPIMemoryNVS,
+ 1,
+ WakeUpBuffer
+ );
+
+ if (!EFI_ERROR (Status)) {
+ break;
+ }
+ }
+
+ return Status;
+}
+
+/**
+ @todo Add function description
+
+ @param[in] Size - @todo add argument description
+ @param[in] Alignment - @todo add argument description
+ @param[out] **Pointer - @todo add argument description
+
+ @retval EFI_SUCCESS - @todo Add description for return value
+
+**/
+EFI_STATUS
+AllocateAlignedReservedMemory (
+ IN UINTN Size,
+ IN UINTN Alignment,
+ OUT VOID **Pointer
+ )
+{
+ EFI_STATUS Status;
+ UINTN PointerValue;
+
+ Status = AllocateReservedMemoryBelow4G (
+ Size + Alignment - 1,
+ (VOID **) Pointer
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ PointerValue = (UINTN) *Pointer;
+ PointerValue = (PointerValue + Alignment - 1) / Alignment * Alignment;
+
+ *Pointer = (VOID *) PointerValue;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Allocate EfiACPIMemoryNVS below 4G memory address.
+
+ @param[in] Size Size of memory to allocate.
+ @param[out] Buffer Allocated address for output.
+
+ @retval EFI_SUCCESS Memory successfully allocated.
+ @retval Other Other errors occur.
+
+**/
+EFI_STATUS
+AllocateReservedMemoryBelow4G (
+ IN UINTN Size,
+ OUT VOID **Buffer
+ )
+{
+ UINTN Pages;
+ EFI_PHYSICAL_ADDRESS Address;
+ EFI_STATUS Status;
+
+ Pages = EFI_SIZE_TO_PAGES (Size);
+ Address = 0xffffffff;
+
+ Status = gBS->AllocatePages (
+ AllocateMaxAddress,
+ EfiACPIMemoryNVS,
+ Pages,
+ &Address
+ );
+
+ *Buffer = (VOID *) (UINTN) Address;
+
+ return Status;
+}
+
+#ifdef __GNUC__
+#define _ReadWriteBarrier() do { __asm__ __volatile__ ("": : : "memory"); } while(0)
+
+int _outp(
+ unsigned short port,
+ int databyte
+ )
+{
+ __asm__ __volatile__ ("outb %b0,%w1" : : "a" (databyte), "d" ((UINT16)port));
+ return databyte;
+}
+#else
+#pragma intrinsic(_outp, _ReadWriteBarrier)
+#endif
+
+/**
+ @todo add description
+
+**/
+VOID
+EFIAPI
+CpuIoWrite8 (
+ IN UINT16 Port,
+ IN UINT32 Data
+ )
+{
+ _ReadWriteBarrier();
+ _outp (Port, (int)Data);
+}
+
+/**
+ This function is invoked when SMM_BASE protocol is installed, then we
+ allocate SMRAM and save all information there.
+
+ @param[in] Event The triggered event.
+ @param[in] Context Context for this event.
+
+**/
+VOID
+EFIAPI
+InitSmramDataContent (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ EFI_SMM_ACCESS2_PROTOCOL *SmmAccess;
+ EFI_SMRAM_DESCRIPTOR *SmramRanges;
+ UINTN Size;
+ SMRAM_CPU_DATA SmramCpuDataTemplate;
+ UINTN LockBoxSize;
+ IA32_DESCRIPTOR *Idtr;
+ IA32_DESCRIPTOR *Gdtr;
+ UINTN MicrocodeSize;
+ EFI_CPU_MICROCODE_HEADER **Microcode;
+ UINT8 *LockBoxMicrocode;
+ UINTN Index;
+ EFI_STATUS Status;
+ EFI_SMM_CONTROL2_PROTOCOL *SmmControl;
+ UINT8 *SmramCpuData;
+ UINTN VarSize;
+ UINT64 VarData[3];
+ UINTN ArgBufferSize;
+ UINT8 ArgBuffer;
+
+ DEBUG ((EFI_D_ERROR, "InitSmramDataContent\n"));
+ Status = gBS->LocateProtocol(&gEfiSmmAccess2ProtocolGuid, NULL, (VOID **) &SmmAccess);
+ ASSERT_EFI_ERROR (Status);
+
+ Status = gBS->LocateProtocol(&gEfiSmmControl2ProtocolGuid, NULL, (VOID **) &SmmControl);
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Get SMRAM information
+ //
+ Size = 0;
+ Status = SmmAccess->GetCapabilities (SmmAccess, &Size, NULL);
+ ASSERT (Status == EFI_BUFFER_TOO_SMALL);
+
+ Status = gBS->AllocatePool (
+ EfiBootServicesData,
+ Size,
+ (VOID **)&SmramRanges
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ Status = SmmAccess->GetCapabilities (
+ SmmAccess,
+ &Size,
+ SmramRanges
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Open all SMRAM ranges
+ //
+ Size /= sizeof (*SmramRanges);
+ Status = SmmAccess->Open (SmmAccess);
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Init
+ //
+ CopyMem (&SmramCpuDataTemplate.HeaderGuid, &mSmramCpuNvsHeaderGuid, sizeof(EFI_GUID));
+ SmramCpuDataTemplate.AcpiCpuPointer = (EFI_PHYSICAL_ADDRESS)(UINTN)mAcpiCpuData;
+ CopyMem (&SmramCpuDataTemplate.AcpiCpuData, mAcpiCpuData, sizeof(ACPI_CPU_DATA_COMPATIBILITY));
+
+ //
+ // Calculate size
+ //
+ SmramCpuDataTemplate.GdtrProfileSize = sizeof (IA32_DESCRIPTOR);
+ Gdtr = (IA32_DESCRIPTOR *)(UINTN)mAcpiCpuData->GdtrProfile;
+ SmramCpuDataTemplate.GdtSize = Gdtr->Limit + 1;
+ SmramCpuDataTemplate.IdtrProfileSize = sizeof (IA32_DESCRIPTOR);
+ Idtr = (IA32_DESCRIPTOR *)(UINTN)mAcpiCpuData->GdtrProfile;
+ SmramCpuDataTemplate.IdtSize = Idtr->Limit + 1;
+ SmramCpuDataTemplate.CpuPrivateDataSize = sizeof(MP_CPU_S3_DATA_POINTER);
+ SmramCpuDataTemplate.S3BootScriptTableSize = sizeof(mMPSystemData->S3BootScriptTable);
+ SmramCpuDataTemplate.S3BspMtrrTableSize = sizeof(mMPSystemData->S3BspMtrrTable);
+ //
+ // Record best match for each CPU Microcode and NULL for end
+ //
+ SmramCpuDataTemplate.MicrocodePointerBufferSize = sizeof(UINT32) * (mAcpiCpuData->NumberOfCpus + 1);
+ //
+ // Calculate Microcode DataSize
+ //
+ SmramCpuDataTemplate.MicrocodeDataBufferSize = 0;
+ Microcode = (VOID *)(UINTN)mAcpiCpuData->MicrocodePointerBuffer;
+ if (Microcode != NULL) {
+ Index = 0;
+ MicrocodeSize = 0;
+ while (Microcode[Index] != NULL) {
+ if (Microcode[Index]->DataSize == 0) {
+ MicrocodeSize = 2048;
+ } else {
+ MicrocodeSize = Microcode[Index]->TotalSize;
+ }
+ SmramCpuDataTemplate.MicrocodeDataBufferSize += (UINT32)MicrocodeSize;
+ Index ++;
+ }
+ }
+
+ SmramCpuDataTemplate.GdtrProfileOffset = sizeof(SMRAM_CPU_DATA);
+ SmramCpuDataTemplate.GdtOffset = SmramCpuDataTemplate.GdtrProfileOffset +
+ SmramCpuDataTemplate.GdtrProfileSize;
+ SmramCpuDataTemplate.IdtrProfileOffset = SmramCpuDataTemplate.GdtOffset +
+ SmramCpuDataTemplate.GdtSize;
+ SmramCpuDataTemplate.IdtOffset = SmramCpuDataTemplate.IdtrProfileOffset +
+ SmramCpuDataTemplate.IdtrProfileSize;
+ SmramCpuDataTemplate.CpuPrivateDataOffset = SmramCpuDataTemplate.IdtOffset +
+ SmramCpuDataTemplate.IdtSize;
+ SmramCpuDataTemplate.S3BootScriptTableOffset = SmramCpuDataTemplate.CpuPrivateDataOffset +
+ SmramCpuDataTemplate.CpuPrivateDataSize;
+ SmramCpuDataTemplate.S3BspMtrrTableOffset = SmramCpuDataTemplate.S3BootScriptTableOffset +
+ SmramCpuDataTemplate.S3BootScriptTableSize;
+ SmramCpuDataTemplate.MicrocodePointerBufferOffset = SmramCpuDataTemplate.S3BspMtrrTableOffset +
+ SmramCpuDataTemplate.S3BspMtrrTableSize;
+ SmramCpuDataTemplate.MicrocodeDataBufferOffset = SmramCpuDataTemplate.MicrocodePointerBufferOffset +
+ SmramCpuDataTemplate.MicrocodePointerBufferSize;
+
+ LockBoxSize = sizeof(SMRAM_CPU_DATA) +
+ SmramCpuDataTemplate.GdtrProfileSize +
+ SmramCpuDataTemplate.GdtSize +
+ SmramCpuDataTemplate.IdtrProfileSize +
+ SmramCpuDataTemplate.IdtSize +
+ SmramCpuDataTemplate.CpuPrivateDataSize +
+ SmramCpuDataTemplate.S3BootScriptTableSize +
+ SmramCpuDataTemplate.S3BspMtrrTableSize +
+ SmramCpuDataTemplate.MicrocodePointerBufferSize +
+ SmramCpuDataTemplate.MicrocodeDataBufferSize;
+
+ DEBUG ((EFI_D_ERROR, "LockBoxSize - %x\n", LockBoxSize));
+ DEBUG ((EFI_D_ERROR, "SmramCpuData.GdtrProfileSize - %x\n", SmramCpuDataTemplate.GdtrProfileSize));
+ DEBUG ((EFI_D_ERROR, "SmramCpuData.GdtSize - %x\n", SmramCpuDataTemplate.GdtSize));
+ DEBUG ((EFI_D_ERROR, "SmramCpuData.IdtrProfileSize - %x\n", SmramCpuDataTemplate.IdtrProfileSize));
+ DEBUG ((EFI_D_ERROR, "SmramCpuData.IdtSize - %x\n", SmramCpuDataTemplate.IdtSize));
+ DEBUG ((EFI_D_ERROR, "SmramCpuData.CpuPrivateDataSize - %x\n", SmramCpuDataTemplate.CpuPrivateDataSize));
+ DEBUG ((EFI_D_ERROR, "SmramCpuData.S3BootScriptTableSize - %x\n", SmramCpuDataTemplate.S3BootScriptTableSize));
+ DEBUG ((EFI_D_ERROR, "SmramCpuData.S3BspMtrrTableSize - %x\n", SmramCpuDataTemplate.S3BspMtrrTableSize));
+ DEBUG ((EFI_D_ERROR, "SmramCpuData.MicrocodePointerBufferSize - %x\n", SmramCpuDataTemplate.MicrocodePointerBufferSize));
+ DEBUG ((EFI_D_ERROR, "SmramCpuData.MicrocodeDataBufferSize - %x\n", SmramCpuDataTemplate.MicrocodeDataBufferSize));
+
+ DEBUG ((EFI_D_ERROR, "SmramCpuData.GdtrProfileOffset - %x\n", SmramCpuDataTemplate.GdtrProfileOffset));
+ DEBUG ((EFI_D_ERROR, "SmramCpuData.GdtOffset - %x\n", SmramCpuDataTemplate.GdtOffset));
+ DEBUG ((EFI_D_ERROR, "SmramCpuData.IdtrProfileOffset - %x\n", SmramCpuDataTemplate.IdtrProfileOffset));
+ DEBUG ((EFI_D_ERROR, "SmramCpuData.IdtOffset - %x\n", SmramCpuDataTemplate.IdtOffset));
+ DEBUG ((EFI_D_ERROR, "SmramCpuData.CpuPrivateDataOffset - %x\n", SmramCpuDataTemplate.CpuPrivateDataOffset));
+ DEBUG ((EFI_D_ERROR, "SmramCpuData.S3BootScriptTableOffset - %x\n", SmramCpuDataTemplate.S3BootScriptTableOffset));
+ DEBUG ((EFI_D_ERROR, "SmramCpuData.S3BspMtrrTableOffset - %x\n", SmramCpuDataTemplate.S3BspMtrrTableOffset));
+ DEBUG ((EFI_D_ERROR, "SmramCpuData.MicrocodePointerBufferOffset - %x\n", SmramCpuDataTemplate.MicrocodePointerBufferOffset));
+ DEBUG ((EFI_D_ERROR, "SmramCpuData.MicrocodeDataBufferOffset - %x\n", SmramCpuDataTemplate.MicrocodeDataBufferOffset));
+
+ //
+ // Allocate Normal Memory
+ //
+ Status = gBS->AllocatePool (
+ EfiBootServicesData,
+ LockBoxSize,
+ (VOID **)&SmramCpuData
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Allocate SMRAM
+ //
+ //
+ // Copy data buffer
+ //
+ CopyMem (SmramCpuData, &SmramCpuDataTemplate, sizeof(SmramCpuDataTemplate));
+
+ CopyMem (
+ SmramCpuData + SmramCpuDataTemplate.GdtrProfileOffset,
+ (VOID *)(UINTN)mAcpiCpuData->GdtrProfile,
+ SmramCpuDataTemplate.GdtrProfileSize
+ );
+ CopyMem (
+ SmramCpuData + SmramCpuDataTemplate.GdtOffset,
+ (VOID *)(UINTN)Gdtr->Base,
+ SmramCpuDataTemplate.GdtSize
+ );
+ CopyMem (
+ SmramCpuData + SmramCpuDataTemplate.IdtrProfileOffset,
+ (VOID *)(UINTN)mAcpiCpuData->IdtrProfile,
+ SmramCpuDataTemplate.IdtrProfileSize
+ );
+ CopyMem (
+ SmramCpuData + SmramCpuDataTemplate.IdtOffset,
+ (VOID *)(UINTN)Idtr->Base,
+ SmramCpuDataTemplate.IdtSize
+ );
+ CopyMem (
+ SmramCpuData + SmramCpuDataTemplate.CpuPrivateDataOffset,
+ (VOID *)(UINTN)mAcpiCpuData->CpuPrivateData,
+ SmramCpuDataTemplate.CpuPrivateDataSize
+ );
+ CopyMem (
+ SmramCpuData + SmramCpuDataTemplate.S3BootScriptTableOffset,
+ (VOID *)(UINTN)mMPSystemData->S3DataPointer.S3BootScriptTable,
+ SmramCpuDataTemplate.S3BootScriptTableSize
+ );
+ CopyMem (
+ SmramCpuData + SmramCpuDataTemplate.S3BspMtrrTableOffset,
+ (VOID *)(UINTN)mMPSystemData->S3DataPointer.S3BspMtrrTable,
+ SmramCpuDataTemplate.S3BspMtrrTableSize
+ );
+ CopyMem (
+ SmramCpuData + SmramCpuDataTemplate.MicrocodePointerBufferOffset,
+ (VOID *)(UINTN)mAcpiCpuData->MicrocodePointerBuffer,
+ SmramCpuDataTemplate.MicrocodePointerBufferSize
+ );
+ //
+ // Copy Microcode
+ //
+ LockBoxMicrocode = SmramCpuData + SmramCpuDataTemplate.MicrocodeDataBufferOffset;
+ Microcode = (VOID *)(UINTN)mAcpiCpuData->MicrocodePointerBuffer;
+ if (Microcode != NULL) {
+ Index = 0;
+ MicrocodeSize = 0;
+ while (Microcode[Index] != NULL) {
+ if (Microcode[Index]->DataSize == 0) {
+ MicrocodeSize = 2048;
+ } else {
+ MicrocodeSize = Microcode[Index]->TotalSize;
+ }
+ CopyMem (LockBoxMicrocode, Microcode[Index], MicrocodeSize);
+ LockBoxMicrocode += MicrocodeSize;
+ Index ++;
+ }
+ }
+
+ //
+ // Copy to SMRAM
+ //
+ //
+ // We have to use SMI to copy SMRAM, because we can not access SMRAM after SMRR enabled.
+ // SMM_ACCESS.Open () takes no effect.
+ //
+ VarSize = sizeof(VarData);
+ VarData[0] = 0;
+ VarData[1] = (UINT64)(UINTN)SmramCpuData;
+ VarData[2] = (UINT64)LockBoxSize;
+ Status = gRT->SetVariable (
+ L"SmramCpuNvs",
+ &mSmramCpuNvsHeaderGuid,
+ EFI_VARIABLE_BOOTSERVICE_ACCESS,
+ VarSize,
+ VarData
+ );
+ ASSERT_EFI_ERROR (Status);
+ ///
+ /// Fill SMI data port
+ ///
+ IoWrite8 (0xB3, 0x81);
+
+ //
+ // Trigger SMI
+ //
+ ArgBufferSize = sizeof (ArgBuffer);
+ ArgBuffer = 0x55;
+ Status = SmmControl->Trigger (SmmControl, (UINT8 *)&ArgBuffer, (UINT8 *)&ArgBufferSize, FALSE, 0);
+ Status = SmmControl->Clear (SmmControl, 0);
+
+ //
+ // Close all SMRAM ranges
+ //
+ Status = SmmAccess->Close (SmmAccess);
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Free resource
+ //
+ gBS->FreePool (SmramRanges);
+
+ //
+ // Done
+ //
+ return ;
+}
+
+/**
+ This function is invoked when LegacyBios protocol is installed, we must
+ allocate reserved memory under 1M for AP.
+
+ @param[in] Event The triggered event.
+ @param[in] Context Context for this event.
+
+ @retval None
+
+**/
+VOID
+EFIAPI
+ReAllocateMemoryForAP (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ EFI_PHYSICAL_ADDRESS LegacyRegion;
+ EFI_STATUS Status;
+ MP_CPU_EXCHANGE_INFO *ExchangeInfo;
+
+ STATIC BOOLEAN InitDone = FALSE;
+ if (InitDone) {
+ return ;
+ }
+ InitDone = TRUE;
+
+ while (ApRunning()) {
+ CpuPause ();
+ }
+
+ {
+ //
+ // The BackBuffer is 4k.
+ // Allocate 0x2000 bytes from below 640K memory to make sure I can
+ // get a 4k aligned spaces of 0x1000 bytes, since Alignment argument does not work.
+ //
+ LegacyRegion = 0x9FFFF;
+ Status = gBS->AllocatePages (
+ AllocateMaxAddress,
+ EfiReservedMemoryType,
+ EFI_SIZE_TO_PAGES (0x2000),
+ &LegacyRegion
+ );
+ ASSERT_EFI_ERROR (Status);
+ DEBUG ((EFI_D_ERROR, "LegacyRegion NonCSM - %x\n", LegacyRegion));
+ if (EFI_ERROR (Status)) {
+ return ;
+ }
+ }
+
+ DEBUG((EFI_D_INFO, "LegacyRegion: 0x%08x\r\n", (UINT32)(UINTN)LegacyRegion));
+ //
+ // This address should be less than A seg.
+ // And it should be aligned to 4K
+ //
+ ASSERT (!((UINTN)LegacyRegion & 0x0FFF) && ((UINTN)LegacyRegion < 0xA0000));
+
+ mAcpiCpuData->WakeUpBuffer = (EFI_PHYSICAL_ADDRESS) LegacyRegion;
+ mAcpiCpuData->WakeUpBuffer = (mAcpiCpuData->WakeUpBuffer + 0x0fff) & 0x0fffff000;
+
+ ExchangeInfo = (MP_CPU_EXCHANGE_INFO *) (UINTN) (mBackupBuffer + MP_CPU_EXCHANGE_INFO_OFFSET);
+ ExchangeInfo->BufferStart = (UINT32) mAcpiCpuData->WakeUpBuffer;
+ ExchangeInfo->ApFunction = (VOID *) (UINTN) LegacyRegionAPCount;
+
+ gBS->CopyMem (
+ (VOID *) (UINTN) mAcpiCpuData->WakeUpBuffer,
+ (VOID *) (UINTN) mBackupBuffer,
+ EFI_PAGE_SIZE
+ );
+ RedirectFarJump();
+
+ //
+ // Do final intialization for APs
+ // Is it neccessary?
+ //
+ SendInterrupt (BROADCAST_MODE_ALL_EXCLUDING_SELF, 0, 0, DELIVERY_MODE_INIT, TRIGGER_MODE_EDGE, TRUE);
+ SendInterrupt (
+ BROADCAST_MODE_ALL_EXCLUDING_SELF,
+ 0,
+ (UINT32) RShiftU64 (mAcpiCpuData->WakeUpBuffer, 12),
+ DELIVERY_MODE_SIPI,
+ TRIGGER_MODE_EDGE,
+ TRUE
+ );
+ //
+ // Wait until all APs finish
+ //
+ while (mSwitchToLegacyRegionCount < mAcpiCpuData->NumberOfCpus - 1) {
+ CpuPause ();
+ }
+
+ ExchangeInfo->ApFunction = (VOID *) (UINTN) ApProcWrapper;
+ gBS->CopyMem (
+ (VOID *) (UINTN) mAcpiCpuData->WakeUpBuffer,
+ (VOID *) (UINTN) mBackupBuffer,
+ EFI_PAGE_SIZE
+ );
+ RedirectFarJump();
+
+ InitSmramDataContent (NULL, NULL);
+}
+
+/**
+ This function is invoked by EFI_EVENT_SIGNAL_LEGACY_BOOT.
+ Before booting to legacy OS, reset AP's wakeup buffer address,
+ preparing for S3 usage.
+
+ @param[in] Event The triggered event.
+ @param[in] Context Context for this event.
+
+ @retval None
+
+**/
+VOID
+ResetAPs (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+}
diff --git a/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/CpuInit/MpCommon.h b/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/CpuInit/MpCommon.h
new file mode 100644
index 0000000000..33840aa76e
--- /dev/null
+++ b/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/CpuInit/MpCommon.h
@@ -0,0 +1,425 @@
+/** @file
+ Some definitions for MP and HT driver.
+
+ Copyright (c) 1999 - 2015, 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_COMMON_
+#define _MP_COMMON_
+
+#include "CpuDxe.h"
+#include "Exception.h"
+#include "ProcessorDef.h"
+
+#define EFI_CPU_CAUSE_NOT_DISABLED 0x0000
+#define EFI_CPU_CAUSE_INTERNAL_ERROR 0x0001
+#define EFI_CPU_CAUSE_THERMAL_ERROR 0x0002
+#define EFI_CPU_CAUSE_SELFTEST_FAILURE 0x0004
+#define EFI_CPU_CAUSE_PREBOOT_TIMEOUT 0x0008
+#define EFI_CPU_CAUSE_FAILED_TO_START 0x0010
+#define EFI_CPU_CAUSE_CONFIG_ERROR 0x0020
+#define EFI_CPU_CAUSE_USER_SELECTION 0x0080
+#define EFI_CPU_CAUSE_BY_ASSOCIATION 0x0100
+#define EFI_CPU_CAUSE_UNSPECIFIED 0x8000
+
+#define VacantFlag 0x00
+#define NotVacantFlag 0xff
+
+#define MICROSECOND 10
+
+#define MAXIMUM_CPU_NUMBER 0x40
+#define STACK_SIZE_PER_PROC 0x8000
+
+#define IO_APIC_INDEX_REGISTER 0xFEC00000
+#define IO_APIC_DATA_REGISTER 0xFEC00010
+#define VIRT_WIRE_A 0
+
+//
+// Data structure used in MP/HT driver
+//
+#define MP_CPU_EXCHANGE_INFO_OFFSET (0x1000 - 0x400)
+#define MP_CPU_LEGACY_RESET_INFO_OFFSET (0x100 - 0x20)
+
+#pragma pack(1)
+#define SIZE_OF_MCE_HANDLER 16
+
+/**
+ @todo add description
+
+**/
+typedef struct {
+ UINT16 LimitLow;
+ UINT16 BaseLow;
+ UINT8 BaseMiddle;
+ UINT16 Attributes;
+ UINT8 BaseHigh;
+} SEGMENT_DESCRIPTOR;
+
+#pragma pack()
+
+/**
+ @todo add description
+
+**/
+typedef struct {
+ UINT32 Number;
+ UINT32 BIST;
+} BIST_INFO;
+
+typedef enum {
+ WakeUpApCounterInit = 0,
+ WakeUpApPerHltLoop = 1,
+ WakeUpApPerMwaitLoop= 2,
+ WakeUpApPerRunLoop = 3
+} WAKEUP_AP_MANNER;
+
+/**
+ @todo add description
+
+**/
+typedef struct {
+ UINTN Lock;
+ VOID *StackStart;
+ UINTN StackSize;
+ VOID *ApFunction;
+ IA32_DESCRIPTOR GdtrProfile;
+ IA32_DESCRIPTOR IdtrProfile;
+ UINT32 BufferStart;
+ UINT32 Cr3;
+ UINT32 InitFlag;
+ WAKEUP_AP_MANNER WakeUpApManner;
+ BIST_INFO BistBuffer[MAXIMUM_CPU_NUMBER];
+} MP_CPU_EXCHANGE_INFO;
+
+extern ACPI_CPU_DATA_COMPATIBILITY *mAcpiCpuData;
+
+//
+// Protocol interface functions
+//
+/**
+ Implementation of GetNumberOfProcessors() service of MP Services Protocol.
+
+ This service retrieves the number of logical processor in the platform
+ and the number of those logical processors that are enabled on this boot.
+ This service may only be called from the BSP.
+
+ @param[in] This A pointer to the EFI_MP_SERVICES_PROTOCOL instance.
+ @param[in] NumberOfProcessors Pointer to the total number of logical processors in the system,
+ including the BSP and disabled APs.
+ @param[in] NumberOfEnabledProcessors Pointer to the number of enabled logical processors that exist
+ in system, including the BSP.
+
+ @retval EFI_SUCCESS Number of logical processors and enabled logical processors retrieved..
+ @retval EFI_DEVICE_ERROR Caller processor is AP.
+ @retval EFI_INVALID_PARAMETER NumberOfProcessors is NULL.
+ @retval EFI_INVALID_PARAMETER NumberOfEnabledProcessors is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+GetNumberOfProcessors (
+ IN EFI_MP_SERVICES_PROTOCOL *This,
+ OUT UINTN *NumberOfProcessors,
+ OUT UINTN *NumberOfEnabledProcessors
+ );
+
+/**
+ Implementation of GetProcessorInfo() service of MP Services Protocol.
+
+ Gets detailed MP-related information on the requested processor at the
+ instant this call is made. This service may only be called from the BSP.
+
+ @param[in] This A pointer to the EFI_MP_SERVICES_PROTOCOL instance.
+ @param[in] ProcessorNumber The handle number of processor.
+ @param[in] ProcessorInfoBuffer A pointer to the buffer where information for the requested processor is deposited.
+
+ @retval EFI_SUCCESS Processor information successfully returned.
+ @retval EFI_DEVICE_ERROR Caller processor is AP.
+ @retval EFI_INVALID_PARAMETER ProcessorInfoBuffer is NULL
+ @retval EFI_NOT_FOUND Processor with the handle specified by ProcessorNumber does not exist.
+
+**/
+EFI_STATUS
+EFIAPI
+GetProcessorInfo (
+ IN EFI_MP_SERVICES_PROTOCOL *This,
+ IN UINTN ProcessorNumber,
+ OUT EFI_PROCESSOR_INFORMATION *ProcessorInfoBuffer
+ );
+
+/**
+ MP Service to get specified application processor (AP)
+ to execute a caller-provided code stream.
+
+ @param[in] This Pointer to MP Service Protocol
+ @param[in] Procedure The procedure to be assigned to AP.
+ @param[in] ProcessorNumber Cpu number
+ @param[in] WaitEvent If timeout, the event to be triggered after this AP finishes.
+ @param[in] TimeoutInMicroSecs The timeout value in microsecond. Zero means infinity.
+ @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_MP_SERVICES_PROTOCOL *This,
+ IN EFI_AP_PROCEDURE Procedure,
+ IN UINTN ProcessorNumber,
+ IN EFI_EVENT WaitEvent OPTIONAL,
+ IN UINTN TimeoutInMicroSecs OPTIONAL,
+ IN VOID *ProcArguments OPTIONAL,
+ OUT BOOLEAN *Finished OPTIONAL
+ );
+
+/**
+ MP Service to get all the available application processors (APs)
+ to execute a caller-provided code stream.
+
+ @param[in] This Pointer to MP Service Protocol
+ @param[in] Procedure The procedure to be assigned to APs.
+ @param[in] SingleThread If true, all APs execute in block mode.
+ Otherwise, all APs exceute in non-block mode.
+ @param[in] WaitEvent If timeout, the event to be triggered after all APs finish.
+ @param[in] TimeoutInMicroSecs The timeout value in microsecond. Zero means infinity.
+ @param[in] ProcArguments Argument for Procedure.
+ @param[in] FailedCPUList If not NULL, all APs that fail to start will be recorded in the list.
+
+ @retval EFI_INVALID_PARAMETER Procudure is NULL.
+ @retval EFI_SUCCESS Only 1 logical processor exists.
+ @retval EFI_SUCCESS All APs have finished.
+ @retval EFI_TIMEOUT Time goes out before all APs have finished.
+
+**/
+EFI_STATUS
+EFIAPI
+StartupAllAPs (
+ IN EFI_MP_SERVICES_PROTOCOL *This,
+ IN EFI_AP_PROCEDURE Procedure,
+ IN BOOLEAN SingleThread,
+ IN EFI_EVENT WaitEvent OPTIONAL,
+ IN UINTN TimeoutInMicroSecs,
+ IN VOID *ProcArguments OPTIONAL,
+ OUT UINTN **FailedCPUList OPTIONAL
+ );
+
+/**
+ 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] This Pointer to MP Service Protocol.
+ @param[in] ProcessorNumber The handle number of processor.
+ @param[in] OldBSPState 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 EFI_MP_SERVICES_PROTOCOL *This,
+ IN UINTN ProcessorNumber,
+ IN BOOLEAN OldBSPState
+ );
+
+/**
+ This procedure enables or disables APs.
+
+ @param[in] This Pointer to MP Service Protocol.
+ @param[in] ProcessorNumber The handle number of processor.
+ @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 EFI_MP_SERVICES_PROTOCOL *This,
+ IN UINTN ProcessorNumber,
+ IN BOOLEAN NewAPState,
+ IN UINT32 *HealthState OPTIONAL
+ );
+
+/**
+ Implementation of WhoAmI() service of MP Services Protocol.
+
+ This service lets the caller processor get its handle number.
+ This service may be called from the BSP and APs.
+
+ @param[in] This A pointer to the EFI_MP_SERVICES_PROTOCOL instance.
+ @param[in] ProcessorNumber Pointer to the handle number of AP.
+
+ @retval EFI_SUCCESS Processor number successfully returned.
+ @retval EFI_INVALID_PARAMETER ProcessorNumber is NULL
+
+**/
+EFI_STATUS
+EFIAPI
+WhoAmI (
+ IN EFI_MP_SERVICES_PROTOCOL *This,
+ OUT UINTN *CpuNumber
+ );
+
+//
+// Functions shared in MP/HT drivers
+//
+EFI_STATUS
+SendInterrupt (
+ IN UINT32 BroadcastMode,
+ IN UINT32 ApicID,
+ IN UINT32 VectorNumber,
+ IN UINT32 DeliveryMode,
+ IN UINT32 TriggerMode,
+ IN BOOLEAN Assert
+ );
+
+UINT32
+GetApicID (
+ OUT EFI_PHYSICAL_ADDRESS *ApicBase OPTIONAL,
+ OUT UINT32 *ApicVersionNumber OPTIONAL
+ );
+
+VOID
+ProgramVirtualWireMode (
+ IN BOOLEAN BSP
+ );
+
+EFI_STATUS
+AllocateWakeUpBuffer (
+ OUT EFI_PHYSICAL_ADDRESS *WakeUpBuffer
+ );
+
+//
+// Assembly functions implemented in MP/HT drivers
+//
+VOID
+AsmAcquireMPLock (
+ IN UINT8 *Lock
+ );
+
+VOID
+AsmReleaseMPLock (
+ IN UINT8 *Lock
+ );
+
+VOID
+AsmGetGdtrIdtr (
+ OUT IA32_DESCRIPTOR **Gdt,
+ OUT IA32_DESCRIPTOR **Idt
+ );
+
+EFI_STATUS
+PrepareGdtIdtForAP (
+ OUT IA32_DESCRIPTOR *GDTR,
+ OUT IA32_DESCRIPTOR *IDTR
+ );
+
+EFI_STATUS
+AllocateAlignedReservedMemory (
+ IN UINTN Size,
+ IN UINTN Alignment,
+ OUT VOID **Pointer
+ );
+
+UINT64
+AsmGetCr3 (
+ VOID
+ );
+
+VOID
+EFIAPI
+ReAllocateMemoryForAP (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ );
+
+VOID
+ResetAPs (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ );
+
+EFI_STATUS
+PrepareMemoryForAPs (
+ OUT EFI_PHYSICAL_ADDRESS *WakeUpBuffer,
+ OUT VOID **StackAddressStart,
+ IN UINTN MaximumCPUsForThisSystem
+ );
+
+EFI_STATUS
+PrepareExchangeInfo (
+ OUT MP_CPU_EXCHANGE_INFO *ExchangeInfo,
+ IN VOID *StackAddressStart,
+ IN VOID *ApFunction,
+ IN EFI_PHYSICAL_ADDRESS WakeUpBuffer
+ );
+
+EFI_STATUS
+S3PrepareMemoryForAPs (
+ OUT EFI_PHYSICAL_ADDRESS *WakeUpBuffer,
+ OUT VOID **StackAddressStart
+ );
+
+EFI_STATUS
+S3PrepareExchangeInfo (
+ OUT MP_CPU_EXCHANGE_INFO *ExchangeInfo,
+ IN VOID *StackAddressStart,
+ IN VOID *ApFunction,
+ IN EFI_PHYSICAL_ADDRESS WakeUpBuffer
+ );
+
+BOOLEAN
+ApRunning (
+ VOID
+ );
+
+VOID
+ApProcWrapper (
+ VOID
+);
+
+UINTN
+SetIdtEntry (
+ IN UINTN FunctionPointer,
+ OUT INTERRUPT_GATE_DESCRIPTOR *IdtEntry
+);
+
+EFI_STATUS
+AllocateReservedMemoryBelow4G (
+ IN UINTN Size,
+ OUT VOID **Buffer
+ );
+
+VOID
+RedirectFarJump (
+ VOID
+ );
+
+VOID
+LegacyRegionAPCount (
+ VOID
+ );
+
+#endif
diff --git a/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/CpuInit/MpCpu.inf b/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/CpuInit/MpCpu.inf
new file mode 100644
index 0000000000..dfade3f5c5
--- /dev/null
+++ b/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/CpuInit/MpCpu.inf
@@ -0,0 +1,143 @@
+## @file
+# Component description file for MP Cpu module.
+#
+# This DXE Driver does processor initialization, configures multi-processor environment,
+# logs data to SMBIOS table for processor subclass and cache subclass, and installs
+# MP Services Protocol.
+#
+# Copyright (c) 1999 - 2015, 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 = 0x00010005
+ BASE_NAME = MpCpu
+ FILE_GUID = 4715BA19-6C49-46e0-B5DA-DE7CB9E059E2
+ MODULE_TYPE = DXE_DRIVER
+ VERSION_STRING = 1.0
+ ENTRY_POINT = InitializeCpu
+
+
+[sources.ia32]
+ Ia32/CpuAsm.asm
+ Ia32/CpuAsm.s | GCC
+ Ia32/MpProc.asm
+ Ia32/MpProc.s | GCC
+ Ia32/MPFuncs32.asm
+ Ia32/MPFuncs32.s | GCC
+ Ia32/MpCommon32.asm
+ Ia32/MpCommon32.s | GCC
+ Ia32/MemoryOperation.c
+ Ia32/Exception.c
+ Ia32/MpCpu.c
+ Ia32/InitializeFpu.s | GCC
+
+[sources.x64]
+ x64/Cpu.asm
+ x64/CpuAsm.asm
+ x64/Exception.c
+ x64/MemoryOperation.c
+ x64/MpCpu.c
+ x64/MpFuncs.asm
+ x64/CpuInitDxeGccDummy.c | GCC
+
+[sources]
+ Cpu.c
+ CpuDxe.h
+ MemoryAttribute.c
+ Microcode.c
+ MpCommon.c
+ MpService.c
+ MtrrSync.c
+ MiscFuncs.c
+
+[Protocols]
+ ## CONSUMES
+ gEfiMetronomeArchProtocolGuid
+
+ ## CONSUMES
+ ## PRODUCES
+ gEfiMpServiceProtocolGuid
+
+ ## CONSUMES
+ ## PRODUCES
+ gEfiCpuArchProtocolGuid
+
+ ## NOTIFY
+ gExitPmAuthProtocolGuid
+
+ ## CONSUMES
+ gEfiDxeSmmReadyToLockProtocolGuid
+
+ ## CONSUMES
+ gEfiSmmAccess2ProtocolGuid
+
+ ## CONSUMES
+ gEfiSmmControl2ProtocolGuid
+
+[Guids]
+ ## SOMETIMES_CONSUMES ## HOB
+ gEfiHtBistHobGuid
+
+ ## PRODUCES ## GUID
+ gEfiStatusCodeSpecificDataGuid
+
+ ## CONSUMES ## Event
+ gEfiEndOfDxeEventGroupGuid
+
+[Packages]
+ MdePkg/MdePkg.dec
+ IntelFrameworkModulePkg/IntelFrameworkModulePkg.dec
+ BraswellPlatformPkg/BraswellPlatformPkg.dec
+
+[LibraryClasses]
+ BaseMemoryLib
+ DebugLib
+ ReportStatusCodeLib
+ BaseLib
+ UefiBootServicesTableLib
+ UefiRuntimeServicesTableLib
+ UefiLib
+ MemoryAllocationLib
+ DxeServicesTableLib
+ HobLib
+ UefiDriverEntryPoint
+ PcdLib
+ IoLib
+
+[Pcd.common]
+ ## SOMETIMES_CONSUMES
+ gIntelSiBasicPkgTokenSpaceGuid.CpuNumberOfThreadsPerCore
+
+ ## SOMETIMES_CONSUMES
+ gIntelSiBasicPkgTokenSpaceGuid.CpuNumberOfCoresPerDie
+
+ ## SOMETIMES_CONSUMES
+ gIntelSiBasicPkgTokenSpaceGuid.CpuNumberOfDiesPerPackage
+
+ ## SOMETIMES_CONSUMES
+ gIntelSiBasicPkgTokenSpaceGuid.CpuNumberOfPackages
+
+ ## SOMETIMES_CONSUMES
+ gIntelSiBasicPkgTokenSpaceGuid.PcdFlashMicroCodeRegionBase
+
+ ## SOMETIMES_CONSUMES
+ gIntelSiBasicPkgTokenSpaceGuid.PcdFlashMicroCodeRegionSize
+
+ ## SOMETIMES_CONSUMES
+ gIntelSiBasicPkgTokenSpaceGuid.PcdFlashMicroCodeOffset
+
+[Depex]
+ gEfiCpuIo2ProtocolGuid AND
+ gEfiVariableArchProtocolGuid AND
+ gEfiVariableWriteArchProtocolGuid
+
+
diff --git a/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/CpuInit/MpService.c b/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/CpuInit/MpService.c
new file mode 100644
index 0000000000..5157e766ae
--- /dev/null
+++ b/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/CpuInit/MpService.c
@@ -0,0 +1,1781 @@
+/** @file
+ Code which support multi-processor.
+
+ Copyright (c) 1999 - 2015, 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 "CpuDxe.h"
+#include "PlatformMpService.h"
+#include "MiscFuncs.h"
+
+#define MODULE_1_CPU0_APICID 4
+
+/**
+ @todo Add function description
+
+ @param[in] Event @todo Add argument description
+ @param[in] *Context @todo Add argument description
+
+**/
+VOID
+EFIAPI
+InitSmramDataContent (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ );
+
+extern EFI_METRONOME_ARCH_PROTOCOL *mMetronome;
+extern MP_SYSTEM_DATA *mMPSystemData;
+extern UINTN mCommonFeatures;
+extern volatile UINTN mSwitchToLegacyRegionCount;
+extern UINT32 mCommonCStateValue;
+
+static EFI_HANDLE mHandle = NULL;
+static volatile UINTN mFinishedCount = 0;
+
+EFI_MP_SERVICES_PROTOCOL mMpService = {
+ GetNumberOfProcessors,
+ GetProcessorInfo,
+ StartupAllAPs,
+ StartupThisAP,
+ SwitchBSP,
+ EnableDisableAP,
+ WhoAmI
+};
+
+EFI_PHYSICAL_ADDRESS mOriginalBuffer;
+EFI_PHYSICAL_ADDRESS mBackupBuffer;
+
+/**
+ Initialize the state information for the MP DXE Protocol.
+
+**/
+VOID
+EFIAPI
+MpServiceInitialize (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ EFI_EVENT LegacyBootEvent;
+ EFI_EVENT ExitBootServicesEvent;
+ EFI_EVENT ReAllocLegacyEvent;
+ EFI_EVENT ReAllocExitPmAuthEvent;
+ VOID *RegistrationLegacy;
+ VOID *RegistrationExitPmAuth;
+
+ LegacyBootEvent = NULL;
+ ExitBootServicesEvent = NULL;
+ ReAllocLegacyEvent = NULL;
+ ReAllocExitPmAuthEvent = NULL;
+ RegistrationLegacy = NULL;
+ RegistrationExitPmAuth = NULL;
+
+ //
+ // Save Mtrr Registers in global data areas
+ //
+ ReadMtrrRegisters ();
+
+ Status = InitializeMpSystemData ();
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+#if defined EFI_S3_RESUME
+ Status = gBS->CreateEvent (
+ EVT_NOTIFY_SIGNAL,
+ TPL_CALLBACK,
+ ReAllocateMemoryForAP,
+ NULL,
+ &ReAllocExitPmAuthEvent
+ );
+ ASSERT_EFI_ERROR (Status);
+ Status = gBS->RegisterProtocolNotify (
+ &gExitPmAuthProtocolGuid,
+ ReAllocExitPmAuthEvent,
+ &RegistrationExitPmAuth
+ );
+#else
+ Status = gBS->CreateEvent (
+ EVT_NOTIFY_SIGNAL,
+ TPL_CALLBACK,
+ ReAllocateMemoryForAP,
+ NULL,
+ &ReAllocExitPmAuthEvent
+ );
+ ASSERT_EFI_ERROR (Status);
+ Status = gBS->RegisterProtocolNotify (
+ &gExitPmAuthProtocolGuid,
+ ReAllocExitPmAuthEvent,
+ &RegistrationExitPmAuth
+ );
+ Status = gBS->CreateEvent (
+ EVT_NOTIFY_SIGNAL,
+ TPL_CALLBACK,
+ ReAllocateMemoryForAP,
+ NULL,
+ &ReAllocLegacyEvent
+ );
+ ASSERT_EFI_ERROR (Status);
+#endif
+ Status = EfiCreateEventLegacyBootEx (
+ TPL_CALLBACK,
+ (EFI_EVENT_NOTIFY)ResetAPs,
+ NULL,
+ &LegacyBootEvent
+ );
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ Status = gBS->CreateEvent (
+ EVT_SIGNAL_EXIT_BOOT_SERVICES,
+ TPL_CALLBACK,
+ (EFI_EVENT_NOTIFY)ResetAPs,
+ NULL,
+ &ExitBootServicesEvent
+ );
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ //
+ // Now install the MP services protocol.
+ //
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &mHandle,
+ &gEfiMpServiceProtocolGuid,
+ &mMpService,
+ NULL
+ );
+
+ if (EFI_ERROR (Status)) {
+
+Done:
+ if (LegacyBootEvent != NULL) {
+ gBS->CloseEvent (LegacyBootEvent);
+ }
+ if (ExitBootServicesEvent != NULL) {
+ gBS->CloseEvent (ExitBootServicesEvent);
+ }
+ gBS->FreePool (mMPSystemData);
+ }
+}
+
+/**
+ Implementation of GetNumberOfProcessors() service of MP Services Protocol.
+
+ This service retrieves the number of logical processor in the platform
+ and the number of those logical processors that are enabled on this boot.
+ This service may only be called from the BSP.
+
+ @param[in] This A pointer to the EFI_MP_SERVICES_PROTOCOL instance.
+ @param[out] NumberOfProcessors Pointer to the total number of logical processors in the system,
+ including the BSP and disabled APs.
+ @param[out] NumberOfEnabledProcessors Pointer to the number of enabled logical processors that exist
+ in system, including the BSP.
+
+ @retval EFI_SUCCESS Number of logical processors and enabled logical processors retrieved..
+ @retval EFI_DEVICE_ERROR Caller processor is AP.
+ @retval EFI_INVALID_PARAMETER NumberOfProcessors is NULL.
+ @retval EFI_INVALID_PARAMETER NumberOfEnabledProcessors is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+GetNumberOfProcessors (
+ IN EFI_MP_SERVICES_PROTOCOL *This,
+ OUT UINTN *NumberOfProcessors,
+ OUT UINTN *NumberOfEnabledProcessors
+ )
+{
+ UINTN CallerNumber;
+ UINTN Index;
+ CPU_DATA_BLOCK *CpuData;
+
+ //
+ // Check whether caller processor is BSP
+ //
+ WhoAmI (&mMpService, &CallerNumber);
+ if (CallerNumber != mMPSystemData->BSP) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ //
+ // Check parameter NumberOfProcessors and NumberOfEnabledProcessors
+ //
+ if (NumberOfProcessors == NULL || NumberOfEnabledProcessors == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ *NumberOfProcessors = mMPSystemData->NumberOfCpus;
+ *NumberOfEnabledProcessors = 0;
+ for (Index = 0; Index < mMPSystemData->NumberOfCpus; Index++) {
+ CpuData = &mMPSystemData->CpuData[Index];
+ if (mMPSystemData->EnableSecondaryCpu) {
+ if (CpuData->State != CPU_STATE_DISABLED) {
+ (*NumberOfEnabledProcessors)++;
+ }
+ } else {
+ if (CpuData->State != CPU_STATE_DISABLED && !mMPSystemData->CpuData[Index].SecondaryCpu) {
+ (*NumberOfEnabledProcessors)++;
+ }
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Implementation of GetProcessorInfo() service of MP Services Protocol.
+
+ Gets detailed MP-related information on the requested processor at the
+ instant this call is made. This service may only be called from the BSP.
+
+ @param[in] This A pointer to the EFI_MP_SERVICES_PROTOCOL instance.
+ @param[in] ProcessorNumber The handle number of processor.
+ @param[out] ProcessorInfoBuffer A pointer to the buffer where information for the requested processor is deposited.
+
+ @retval EFI_SUCCESS Processor information successfully returned.
+ @retval EFI_DEVICE_ERROR Caller processor is AP.
+ @retval EFI_INVALID_PARAMETER ProcessorInfoBuffer is NULL
+ @retval EFI_NOT_FOUND Processor with the handle specified by ProcessorNumber does not exist.
+
+**/
+EFI_STATUS
+EFIAPI
+GetProcessorInfo (
+ IN EFI_MP_SERVICES_PROTOCOL *This,
+ IN UINTN ProcessorNumber,
+ OUT EFI_PROCESSOR_INFORMATION *ProcessorInfoBuffer
+ )
+{
+ UINTN CallerNumber;
+ CPU_DATA_BLOCK *CpuData;
+
+ //
+ // Check whether caller processor is BSP
+ //
+ WhoAmI (&mMpService, &CallerNumber);
+ if (CallerNumber != mMPSystemData->BSP) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ //
+ // Check parameter ProcessorInfoBuffer
+ //
+ if (ProcessorInfoBuffer == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Check whether processor with the handle specified by ProcessorNumber exists
+ //
+ if (ProcessorNumber >= mMPSystemData->NumberOfCpus) {
+ return EFI_NOT_FOUND;
+ }
+
+ CpuData = &mMPSystemData->CpuData[ProcessorNumber];
+
+ ProcessorInfoBuffer->ProcessorId = (UINT64) CpuData->ApicID;
+
+ //
+ // Get Status Flag of specified processor
+ //
+ ProcessorInfoBuffer->StatusFlag = 0;
+
+ ProcessorInfoBuffer->StatusFlag |= PROCESSOR_ENABLED_BIT;
+ if (!mMPSystemData->EnableSecondaryCpu) {
+ if (CpuData->SecondaryCpu) {
+ ProcessorInfoBuffer->StatusFlag &= ~PROCESSOR_ENABLED_BIT;
+ }
+ }
+
+ if (ProcessorNumber == mMPSystemData->BSP) {
+ ProcessorInfoBuffer->StatusFlag |= PROCESSOR_AS_BSP_BIT;
+ }
+
+ if (CpuData->Health == 0) {
+ ProcessorInfoBuffer->StatusFlag |= PROCESSOR_HEALTH_STATUS_BIT;
+ }
+
+ ProcessorInfoBuffer->Location.Package = (UINT32) CpuData->PhysicalLocation.Package;
+ ProcessorInfoBuffer->Location.Core = (UINT32) CpuData->PhysicalLocation.Core;
+ ProcessorInfoBuffer->Location.Thread = (UINT32) CpuData->PhysicalLocation.Thread;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ MP Service to get specified application processor (AP)
+ to execute a caller-provided code stream.
+
+ @param[in] This Pointer to MP Service Protocol
+ @param[in] Procedure The procedure to be assigned to AP.
+ @param[in] CpuNumber Number of the specified processor.
+ @param[in] WaitEvent If timeout, the event to be triggered after this AP finishes.
+ @param[in] TimeoutInMicroSecs The timeout value in microsecond. Zero means infinity.
+ @param[in] ProcArguments Argument for Procedure.
+ @param[out] Finished @todo Add argument description
+
+ @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_MP_SERVICES_PROTOCOL *This,
+ IN EFI_AP_PROCEDURE Procedure,
+ IN UINTN CpuNumber,
+ IN EFI_EVENT WaitEvent OPTIONAL,
+ IN UINTN TimeoutInMicroSecs OPTIONAL,
+ IN VOID *ProcArguments OPTIONAL,
+ OUT BOOLEAN *Finished OPTIONAL
+ )
+{
+ EFI_STATUS Status;
+ CPU_DATA_BLOCK *CpuData;
+ UINT64 ExpectedTime;
+
+ //
+ // Check for invalid CPU number
+ //
+ if ((CpuNumber >= mMPSystemData->NumberOfCpus) || (CpuNumber == mMPSystemData->BSP)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (Procedure == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (Finished != NULL) {
+ *Finished = TRUE;
+ }
+
+ CpuData = &mMPSystemData->CpuData[CpuNumber];
+
+ //
+ // As a first step, check if processor is OK to start up code stream.
+ //
+ if (CpuData->State != CPU_STATE_IDLE) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ ExpectedTime = CalculateTimeout (TimeoutInMicroSecs);
+
+ mMPSystemData->StartCount = 1;
+ mMPSystemData->FinishCount = 0;
+
+ WakeUpAp (
+ CpuData,
+ Procedure,
+ ProcArguments
+ );
+
+ while (TRUE) {
+ AsmAcquireMPLock (&CpuData->StateLock);
+ if (CpuData->State == CPU_STATE_FINISHED) {
+ CpuData->State = CPU_STATE_IDLE;
+ AsmReleaseMPLock (&CpuData->StateLock);
+ break;
+ }
+
+ AsmReleaseMPLock (&CpuData->StateLock);
+
+ if (CheckTimeout (ExpectedTime)) {
+ //
+ // Save data into private data structure, and create timer to poll AP state before exiting
+ //
+ mMPSystemData->StartedCpuNumber = CpuNumber;
+ mMPSystemData->WaitEvent = WaitEvent;
+ Status = gBS->SetTimer (
+ mMPSystemData->CheckThisAPEvent,
+ TimerPeriodic,
+ CPU_CHECK_AP_INTERVAL * MICROSECOND
+ );
+ return EFI_TIMEOUT;
+ }
+
+ gBS->Stall (CPU_CHECK_AP_INTERVAL * MICROSECOND);
+ }
+
+ CpuData->Finished = Finished;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ MP Service to get all the available application processors (APs)
+ to execute a caller-provided code stream.
+
+ @param[in] This Pointer to MP Service Protocol
+ @param[in] Procedure The procedure to be assigned to APs.
+ @param[in] SingleThread If true, all APs execute in block mode.
+ Otherwise, all APs exceute in non-block mode.
+ @param[in] WaitEvent If timeout, the event to be triggered after all APs finish.
+ @param[in] TimeoutInMicroSecs The timeout value in microsecond. Zero means infinity.
+ @param[in] ProcArguments Argument for Procedure.
+ @param[out] FailedCPUList If not NULL, all APs that fail to start will be recorded in the list.
+
+ @retval EFI_INVALID_PARAMETER Procudure is NULL.
+ @retval EFI_SUCCESS Only 1 logical processor exists.
+ @retval EFI_SUCCESS All APs have finished.
+ @retval EFI_TIMEOUT Time goes out before all APs have finished.
+
+**/
+EFI_STATUS
+EFIAPI
+StartupAllAPs (
+ IN EFI_MP_SERVICES_PROTOCOL *This,
+ IN EFI_AP_PROCEDURE Procedure,
+ IN BOOLEAN SingleThread,
+ IN EFI_EVENT WaitEvent OPTIONAL,
+ IN UINTN TimeoutInMicroSecs,
+ IN VOID *ProcArguments OPTIONAL,
+ OUT UINTN **FailedCPUList OPTIONAL
+ )
+{
+ EFI_STATUS Status;
+ CPU_DATA_BLOCK *CpuData;
+ CPU_DATA_BLOCK *NextCpuData;
+ UINTN ListIndex;
+ UINTN CpuNumber;
+ UINTN NextCpuNumber;
+ UINT64 ExpectedTime;
+ CPU_STATE APInitialState;
+ CPU_STATE CpuState;
+
+ //
+ // Check for valid procedure for APs
+ //
+ if (Procedure == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (mMPSystemData->NumberOfCpus == 1) {
+ return EFI_SUCCESS;
+ }
+
+ ExpectedTime = CalculateTimeout (TimeoutInMicroSecs);
+
+ ListIndex = 0;
+ CpuData = NULL;
+
+ mMPSystemData->FinishCount = 0;
+ mMPSystemData->StartCount = 0;
+ APInitialState = CPU_STATE_READY;
+
+ for (CpuNumber = 0; CpuNumber < mMPSystemData->NumberOfCpus; CpuNumber++) {
+ CpuData = &mMPSystemData->CpuData[CpuNumber];
+
+ //
+ // Get APs prepared, and put failing APs into FailedCPUList
+ // If "SingleThread", one AP will be put to ready state.
+ // Once this AP finishes its task, the next AP is put to Ready state.
+ // This process continues until all APs are put into Ready State
+ // if not "SingleThread", all APs are put to ready state at the same time
+ //
+ if (CpuNumber != mMPSystemData->BSP) {
+ if (CpuData->State == CPU_STATE_IDLE) {
+ mMPSystemData->StartCount++;
+
+ AsmAcquireMPLock (&CpuData->StateLock);
+ CpuData->State = APInitialState;
+ AsmReleaseMPLock (&CpuData->StateLock);
+
+ if (SingleThread) {
+ APInitialState = CPU_STATE_BLOCKED;
+ }
+
+ } else if (FailedCPUList != NULL) {
+ *FailedCPUList[ListIndex] = CpuNumber;
+ ListIndex++;
+ }
+ }
+ }
+
+ while (TRUE) {
+ for (CpuNumber = 0; CpuNumber < mMPSystemData->NumberOfCpus; CpuNumber++) {
+ CpuData = &mMPSystemData->CpuData[CpuNumber];
+ if (CpuNumber == mMPSystemData->BSP) {
+ continue;
+ }
+ CpuState = CpuData->State;
+ switch (CpuState) {
+ case CPU_STATE_READY:
+ WakeUpAp (
+ CpuData,
+ Procedure,
+ ProcArguments
+ );
+ break;
+
+ case CPU_STATE_FINISHED:
+ mMPSystemData->FinishCount++;
+ if (SingleThread) {
+ Status = GetNextBlockedCpuNumber (&NextCpuNumber);
+ if (!EFI_ERROR (Status)) {
+ NextCpuData = &mMPSystemData->CpuData[NextCpuNumber];
+ AsmAcquireMPLock (&NextCpuData->StateLock);
+ NextCpuData->State = CPU_STATE_READY;
+ AsmReleaseMPLock (&NextCpuData->StateLock);
+ }
+ }
+ AsmAcquireMPLock (&CpuData->StateLock);
+ CpuData->State = CPU_STATE_IDLE;
+ AsmReleaseMPLock (&CpuData->StateLock);
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ if (mMPSystemData->FinishCount == mMPSystemData->StartCount) {
+ return EFI_SUCCESS;
+ }
+
+ if (CheckTimeout (ExpectedTime)) {
+ //
+ // Save data into private data structure, and create timer to poll AP state before exiting
+ //
+ mMPSystemData->Procedure = Procedure;
+ mMPSystemData->ProcArguments = ProcArguments;
+ mMPSystemData->SingleThread = SingleThread;
+ mMPSystemData->WaitEvent = WaitEvent;
+
+ Status = gBS->SetTimer (
+ mMPSystemData->CheckAllAPsEvent,
+ TimerPeriodic,
+ CPU_CHECK_AP_INTERVAL * MICROSECOND
+ );
+ return EFI_TIMEOUT;
+ }
+
+ gBS->Stall (CPU_CHECK_AP_INTERVAL * MICROSECOND);
+ }
+
+ 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] This Pointer to MP Service Protocol.
+ @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 EFI_MP_SERVICES_PROTOCOL *This,
+ IN UINTN CpuNumber,
+ IN BOOLEAN EnableOldBSP
+ )
+{
+ EFI_STATUS Status;
+ EFI_CPU_ARCH_PROTOCOL *CpuArch;
+ BOOLEAN OldInterruptState;
+ CPU_DATA_BLOCK *CpuData;
+ CPU_STATE CpuState;
+
+ //
+ // 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.
+ //
+ CpuArch = mMPSystemData->CpuArch;
+ (CpuArch->GetInterruptState)(CpuArch, &OldInterruptState);
+ if (OldInterruptState) {
+ Status = CpuArch->DisableInterrupt (CpuArch);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ }
+
+ //
+ // Unprogram virtual wire mode for the old BSP
+ //
+ ProgramVirtualWireMode (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)
+ //
+ WakeUpAp (
+ CpuData,
+ (EFI_AP_PROCEDURE)FutureBSPProc,
+ mMPSystemData
+ );
+
+ 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);
+ ProgramVirtualWireMode (TRUE);
+
+ if (OldInterruptState) {
+ Status = CpuArch->EnableInterrupt (CpuArch);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ }
+
+ 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, EFI_CPU_CAUSE_NOT_DISABLED);
+ mMPSystemData->BSP = CpuNumber;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ This procedure enables Or disables APs.
+
+ @param[in] This Pointer to MP Service Protocol.
+ @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 EFI_MP_SERVICES_PROTOCOL *This,
+ IN UINTN CpuNumber,
+ IN BOOLEAN NewAPState,
+ IN UINT32 *HealthState OPTIONAL
+ )
+{
+ EFI_STATUS Status;
+ CPU_DATA_BLOCK *CpuData;
+
+ //
+ // Check for valid input parameters.
+ //
+ if (CpuNumber >= mMPSystemData->NumberOfCpus || CpuNumber == mMPSystemData->BSP) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ CpuData = &mMPSystemData->CpuData[CpuNumber];
+ Status = ChangeCpuState (CpuNumber, NewAPState, EFI_CPU_CAUSE_USER_SELECTION);
+
+ if (HealthState != NULL) {
+ CopyMem (&CpuData->Health, HealthState, sizeof (UINT32));
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ This procedure returns the calling CPU handle.
+
+ @param[in] This Pointer to MP Service Protocol.
+ @param[out] CpuNumber The number of the specified AP.
+
+ @retval EFI_SUCCESS Function completed successfully.
+
+**/
+EFI_STATUS
+EFIAPI
+WhoAmI (
+ IN EFI_MP_SERVICES_PROTOCOL *This,
+ OUT UINTN *CpuNumber
+ )
+{
+ UINTN ApicID;
+ UINTN NumOfCpus;
+ UINTN Index;
+
+ ApicID = GetApicID (NULL, NULL);
+
+ NumOfCpus = mMPSystemData->NumberOfCpus;
+
+ for (Index = 0; Index < NumOfCpus; Index++) {
+ if (ApicID == mMPSystemData->CpuData[Index].ApicID) {
+ break;
+ }
+ }
+
+ *CpuNumber = Index;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Searches the HOB list provided by the core to find
+ if a MP guided HOB list exists or not. If it does, it copies it to the driver
+ data area, else returns 0
+
+ @param[in] MPSystemData Pointer to an MP_SYSTEM_DATA structure
+
+ @retval EFI_SUCCESS Success
+ @retval Others HOB not found or else
+
+**/
+EFI_STATUS
+GetMpBistStatus (
+ IN MP_SYSTEM_DATA *MPSystemData
+ )
+{
+ EFI_STATUS Status;
+ VOID *DataInHob;
+ UINTN DataSize;
+ EFI_PEI_HOB_POINTERS GuidHob;
+
+ //
+ // Get Hob list
+ //
+ DataInHob = NULL;
+ DataSize = 0;
+ GuidHob.Raw = GetHobList ();
+
+ if (GuidHob.Raw == NULL) {
+ DEBUG ((EFI_D_ERROR, "No HOBs found\n"));
+ return EFI_NOT_FOUND;
+ }
+
+ //
+ // Check for MP Data Hob.
+ //
+ GuidHob.Raw = GetNextGuidHob (&gEfiHtBistHobGuid, GuidHob.Raw);
+ if (GuidHob.Raw != NULL) {
+ DataInHob = GET_GUID_HOB_DATA (GuidHob.Guid);
+ DataSize = GET_GUID_HOB_DATA_SIZE(GuidHob.Guid);
+ Status = EFI_SUCCESS;
+ } else {
+ Status = EFI_NOT_FOUND;
+ }
+
+ //
+ // This is the MP HOB. So, copy all the data.
+ //
+ if (!(EFI_ERROR (Status))) {
+ if(NULL == MPSystemData->BistHobData){
+ gBS->AllocatePool(
+ EfiACPIMemoryNVS,
+ DataSize,
+ (VOID **)&MPSystemData->BistHobData
+ );
+ }
+ gBS->CopyMem (MPSystemData->BistHobData, DataInHob, DataSize);
+ MPSystemData->BistHobSize = DataSize;
+ }
+
+ return Status;
+}
+
+/**
+ Allocate data pool for MP information and fill data in it.
+
+ @param[out] WakeUpBuffer The address of wakeup buffer.
+ @param[out] 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
+AllocateMemoryAndFillData (
+ OUT EFI_PHYSICAL_ADDRESS WakeUpBuffer,
+ OUT VOID *StackAddressStart,
+ IN UINTN MaximumCPUsForThisSystem
+ )
+{
+ EFI_STATUS Status;
+
+ //
+ // 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.
+ //
+ gBS->SetMem (mMPSystemData, sizeof (MP_SYSTEM_DATA), 0);
+
+ Status = GetMpBistStatus (mMPSystemData);
+
+ mAcpiCpuData->CpuPrivateData = (EFI_PHYSICAL_ADDRESS)(UINTN)(&(mMPSystemData->S3DataPointer));
+ mAcpiCpuData->APState = 1;
+ mAcpiCpuData->WakeUpBuffer = WakeUpBuffer;
+ mAcpiCpuData->StackAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)(StackAddressStart);
+
+ Status = PrepareGdtIdtForAP ((IA32_DESCRIPTOR *) (UINTN) mAcpiCpuData->GdtrProfile, (IA32_DESCRIPTOR *) (UINTN) mAcpiCpuData->IdtrProfile);
+
+ //
+ // First BSP fills and inits all known values, including it's own records.
+ //
+ mMPSystemData->APSerializeLock = VacantFlag;
+ mMPSystemData->NumberOfCpus = 1;
+ mMPSystemData->EnableSecondaryCpu = 1;
+
+ //
+ // Record these CPU configuration data (both for normal boot and for S3 use)
+ //
+ mMPSystemData->CpuArch = NULL;
+ gBS->LocateProtocol (&gEfiCpuArchProtocolGuid, NULL, (VOID **) &mMPSystemData->CpuArch);
+
+ mMPSystemData->MaximumCpusForThisSystem = MaximumCPUsForThisSystem;
+
+ mMPSystemData->BSP = 0;
+
+ FillInProcessorInformation (mMPSystemData, TRUE, 0);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Wake up APs for the first time to count their number and collect BIST data.
+
+ @param[in] WakeUpBuffer Address of the wakeup buffer.
+
+ @retval EFI_SUCCESS Function successfully finishes.
+
+**/
+EFI_STATUS
+CountApNumberAndCollectBist (
+ IN EFI_PHYSICAL_ADDRESS WakeUpBuffer
+ )
+{
+ MP_CPU_EXCHANGE_INFO *ExchangeInfo;
+ UINTN Index;
+
+ //
+ // Send INIT IPI - SIPI to all APs
+ //
+ SendInterrupt (BROADCAST_MODE_ALL_EXCLUDING_SELF, 0, 0, DELIVERY_MODE_INIT, TRIGGER_MODE_EDGE, TRUE);
+ SendInterrupt (
+ BROADCAST_MODE_ALL_EXCLUDING_SELF,
+ 0,
+ (UINT32) RShiftU64 (WakeUpBuffer, 12),
+ DELIVERY_MODE_SIPI,
+ TRIGGER_MODE_EDGE,
+ TRUE
+ );
+
+ //
+ // Wait for task to complete and then exit.
+ //
+ gBS->Stall (200 * MICROSECOND);
+
+ ExchangeInfo = (MP_CPU_EXCHANGE_INFO *) (UINTN) (WakeUpBuffer + MP_CPU_EXCHANGE_INFO_OFFSET);
+
+ for (Index = 0; Index < MAXIMUM_CPU_NUMBER; Index++) {
+ if (ExchangeInfo->BistBuffer[Index].Number == 1) {
+ ExchangeInfo->BistBuffer[Index].Number = (UINT32) mMPSystemData->NumberOfCpus++;
+ }
+ }
+ mAcpiCpuData->NumberOfCpus = (UINT32) mMPSystemData->NumberOfCpus;
+
+ ExchangeInfo->InitFlag = 0;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Wake up APs for the second time to collect detailed information.
+
+ @param[in] WakeUpBuffer Address of the wakeup buffer.
+
+ @retval EFI_SUCCESS Function successfully finishes.
+
+**/
+EFI_STATUS
+PollForInitialization (
+ IN EFI_PHYSICAL_ADDRESS WakeUpBuffer
+ )
+{
+ MP_CPU_EXCHANGE_INFO *ExchangeInfo;
+
+ ExchangeInfo = (MP_CPU_EXCHANGE_INFO *) (UINTN) (WakeUpBuffer + MP_CPU_EXCHANGE_INFO_OFFSET);
+ ExchangeInfo->ApFunction = (VOID *) (UINTN) DetailedInitialization;
+
+ SendInterrupt (BROADCAST_MODE_ALL_EXCLUDING_SELF, 0, 0, DELIVERY_MODE_INIT, TRIGGER_MODE_EDGE, TRUE);
+ SendInterrupt (
+ BROADCAST_MODE_ALL_EXCLUDING_SELF,
+ 0,
+ (UINT32) RShiftU64 (WakeUpBuffer, 12),
+ DELIVERY_MODE_SIPI,
+ TRIGGER_MODE_EDGE,
+ TRUE
+ );
+
+ //
+ // Wait until all APs finish
+ //
+ while (mFinishedCount < mAcpiCpuData->NumberOfCpus - 1) {
+ CpuPause ();
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ @todo Add function description
+
+ @param[in] Location @todo Add argument description
+
+ @retval EFI_SUCCESS @todo Add argument description
+
+**/
+EFI_STATUS
+FillInCpuLocation (
+ IN EFI_CPU_PHYSICAL_LOCATION *Location
+ )
+{
+ UINT32 ApicId;
+ UINT32 LevelType;
+ UINT32 LevelBits;
+ UINT32 RegEax;
+ UINT32 RegEbx;
+ UINT32 RegEcx;
+ UINT8 Shift;
+ UINT8 Bits;
+ UINT32 Mask;
+ BOOLEAN HyperThreadingEnabled;
+
+ AsmCpuid (EFI_CPUID_VERSION_INFO, NULL, &RegEbx, NULL, NULL);
+ ApicId = (RegEbx >> 24);
+
+ AsmCpuid (EFI_CPUID_SIGNATURE, &RegEax, NULL, NULL, NULL);
+ if (RegEax >= EFI_CPUID_CORE_TOPOLOGY) {
+ LevelBits = 0;
+ LevelType = 0;
+ do {
+ AsmCpuidEx (EFI_CPUID_CORE_TOPOLOGY, LevelType, &RegEax, &RegEbx, &RegEcx, NULL);
+ LevelType = ((RegEcx >> 8) & 0xFF);
+ switch (LevelType) {
+ case 1: //Thread
+ Location->Thread = ApicId & ((1 << (RegEax & 0x0F)) - 1);
+ Location->Thread >>= LevelBits;
+ LevelBits = RegEax & 0x0F;
+ break;
+ case 2: //Core
+ Location->Core = ApicId & ((1 << (RegEax & 0x0F)) - 1);
+ Location->Core >>= LevelBits;
+ LevelBits = RegEax & 0x0F;
+ break;
+ default: //End of Level
+ Location->Package = ApicId >> LevelBits;
+ break;
+ }
+ } while (!(RegEax == 0 && RegEbx == 0));
+ } else {
+
+ AsmCpuid (EFI_CPUID_VERSION_INFO, NULL, &RegEbx, NULL, NULL);
+ Bits = 0;
+ Shift = (UINT8)((RegEbx >> 16) & 0xFF);
+
+ Mask = Shift - 1;
+ while (Shift > 1) {
+ Shift >>= 1;
+ Bits++;
+ }
+
+ HyperThreadingEnabled = FALSE;
+ AsmCpuidEx (EFI_CPUID_CACHE_PARAMS, 0, &RegEax, NULL, NULL, NULL);
+ if (Mask > (RegEax >> 26)) {
+ HyperThreadingEnabled = TRUE;
+ }
+
+ Location->Package = (ApicId >> Bits);
+ if (HyperThreadingEnabled) {
+ Location->Core = (ApicId & Mask) >> 1;
+ Location->Thread = (ApicId & Mask) & 1;
+ } else {
+ Location->Core = (ApicId & Mask);
+ Location->Thread = 0;
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Initialize multiple processors and collect MP related data
+
+ @retval EFI_SUCCESS Multiple processors get initialized and data collected successfully
+
+ @retval Other The operation failed due to some reason
+
+**/
+EFI_STATUS
+InitializeMpSystemData (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ UINT32 MaxThreadsPerCore;
+ UINT32 MaxCoresPerDie;
+ UINT32 MaxDiesPerPackage;
+ UINT32 MaxPackages;
+ VOID *StackAddressStart;
+ EFI_PHYSICAL_ADDRESS WakeUpBuffer;
+ MP_CPU_EXCHANGE_INFO *ExchangeInfo;
+ UINTN Index;
+ EFI_CPU_ARCH_PROTOCOL *CpuArch;
+ BOOLEAN mInterruptState;
+ CPU_DATA_BLOCK *CpuData;
+ UINTN MaximumCPUsForThisSystem;
+
+ ProgramVirtualWireMode (TRUE);
+ MaxThreadsPerCore = PcdGet32 (CpuNumberOfThreadsPerCore);
+ MaxCoresPerDie = PcdGet32(CpuNumberOfCoresPerDie);
+ MaxDiesPerPackage = PcdGet32(CpuNumberOfDiesPerPackage);
+ MaxPackages = PcdGet32(CpuNumberOfPackages);
+
+ MaximumCPUsForThisSystem = MaxThreadsPerCore * MaxCoresPerDie * MaxDiesPerPackage * MaxPackages;
+
+ Status = PrepareMemoryForAPs (
+ &WakeUpBuffer,
+ &StackAddressStart,
+ MaximumCPUsForThisSystem
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ mOriginalBuffer = WakeUpBuffer;
+
+ Status = gBS->AllocatePages (
+ AllocateAnyPages,
+ EfiBootServicesData,
+ 1,
+ &mBackupBuffer
+ );
+
+ Status = AllocateMemoryAndFillData (
+ WakeUpBuffer,
+ StackAddressStart,
+ MaximumCPUsForThisSystem
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ ExchangeInfo = (MP_CPU_EXCHANGE_INFO *) (UINTN) (WakeUpBuffer + MP_CPU_EXCHANGE_INFO_OFFSET);
+ Status = PrepareExchangeInfo (
+ ExchangeInfo,
+ StackAddressStart,
+ NULL,
+ WakeUpBuffer
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ CpuArch = mMPSystemData->CpuArch;
+ CpuArch->GetInterruptState (CpuArch, &mInterruptState);
+ CpuArch->DisableInterrupt (CpuArch);
+
+ //
+ // For B stepping and above use broadcast
+ //
+ CountApNumberAndCollectBist (WakeUpBuffer);
+ ExchangeInfo->WakeUpApManner = WakeUpApCounterInit;
+ PollForInitialization (WakeUpBuffer);
+
+ ExchangeInfo->WakeUpApManner = (WAKEUP_AP_MANNER) WakeUpApPerHltLoop;
+ ExchangeInfo->ApFunction = (VOID *) (UINTN) ApProcWrapper;
+ if (mInterruptState) {
+ CpuArch->EnableInterrupt (CpuArch);
+ }
+
+ for (Index = 1; Index < mMPSystemData->NumberOfCpus; Index++) {
+ CpuData = &mMPSystemData->CpuData[Index];
+ if (CpuData->Health != 0) {
+ REPORT_STATUS_CODE_EX (
+ EFI_ERROR_MAJOR | EFI_ERROR_CODE,
+ EFI_COMPUTING_UNIT_HOST_PROCESSOR | EFI_CU_HP_EC_SELF_TEST,
+ (UINT32) Index,
+ &gEfiCallerIdGuid,
+ NULL,
+ NULL,
+ 0
+ );
+ }
+
+ }
+
+ Status = gBS->CreateEvent (
+ EVT_TIMER | EVT_NOTIFY_SIGNAL,
+ TPL_CALLBACK,
+ (EFI_EVENT_NOTIFY)CheckAllAPsStatus,
+ NULL,
+ &mMPSystemData->CheckAllAPsEvent
+ );
+ Status = gBS->CreateEvent (
+ EVT_TIMER | EVT_NOTIFY_SIGNAL,
+ TPL_CALLBACK,
+ (EFI_EVENT_NOTIFY)CheckThisAPStatus,
+ NULL,
+ &mMPSystemData->CheckThisAPEvent
+ );
+
+ SaveBspMtrrForS3 ();
+ CopyMem ((VOID *) (UINTN) mBackupBuffer, (VOID *) (UINTN) mOriginalBuffer, EFI_PAGE_SIZE);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Wrapper function for all procedures assigned to AP via MP service protocol.
+ It controls states of AP and invokes assigned precedure.
+
+**/
+VOID
+ApProcWrapper (
+ VOID
+ )
+{
+ EFI_AP_PROCEDURE Procedure;
+ VOID *Parameter;
+ UINTN CpuNumber;
+ CPU_DATA_BLOCK *CpuData;
+
+ WhoAmI (&mMpService, &CpuNumber);
+ CpuData = &mMPSystemData->CpuData[CpuNumber];
+
+ //
+ // Now let us check it out.
+ //
+ AsmAcquireMPLock (&CpuData->ProcedureLock);
+ Procedure = CpuData->Procedure;
+ Parameter = CpuData->Parameter;
+ AsmReleaseMPLock (&CpuData->ProcedureLock);
+
+ if (Procedure != NULL) {
+ AsmAcquireMPLock (&CpuData->StateLock);
+ CpuData->State = CPU_STATE_BUSY;
+ AsmReleaseMPLock (&CpuData->StateLock);
+
+ Procedure (Parameter);
+
+ //
+ // if BSP is switched to AP, it continue execute from here, but it carries register state
+ // of the old AP, so need to reload CpuData (might be stored in a register after compiler
+ // optimization) to make sure it points to the right data
+ //
+ WhoAmI (&mMpService, &CpuNumber);
+ CpuData = &mMPSystemData->CpuData[CpuNumber];
+
+ AsmAcquireMPLock (&CpuData->ProcedureLock);
+ CpuData->Procedure = NULL;
+ AsmReleaseMPLock (&CpuData->ProcedureLock);
+
+ AsmAcquireMPLock (&CpuData->StateLock);
+ CpuData->State = CPU_STATE_FINISHED;
+ AsmReleaseMPLock (&CpuData->StateLock);
+ }
+}
+
+/**
+ Procedure for detailed initialization of APs. It will be assigned to all APs while
+ they are waken up for the second time.
+
+**/
+VOID
+DetailedInitialization (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ UINT32 FailedRevision;
+
+ CpuInitFloatPointUnit ();
+
+ AsmAcquireMPLock (&mMPSystemData->APSerializeLock);
+
+ Status = InitializeMicrocode (
+ (EFI_CPU_MICROCODE_HEADER **) (UINTN) mAcpiCpuData->MicrocodePointerBuffer,
+ &FailedRevision,
+ FALSE
+ );
+
+ //
+ // Save Mtrr Registers in global data areas
+ //
+ MpMtrrSynchUp (NULL);
+
+ ProgramVirtualWireMode (FALSE);
+
+ FillInProcessorInformation (mMPSystemData, FALSE, 0);
+
+ mFinishedCount++;
+
+ AsmReleaseMPLock (&mMPSystemData->APSerializeLock);
+}
+
+/**
+ @todo Add function description
+
+ @param[in] MPSystemData - @todo add argument description
+
+ @retval - @todo add return values
+
+**/
+VOID
+FutureBSPProc (
+ IN MP_SYSTEM_DATA *MPSystemData
+ )
+{
+ AsmExchangeRole (&MPSystemData->APInfo, &MPSystemData->BSPInfo);
+ return ;
+}
+
+/**
+ This function is called by all processors (both BSP and AP) once and collects MP related data
+
+ @param[in] MPSystemData Pointer to the data structure containing 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 MP_SYSTEM_DATA *MPSystemData,
+ IN BOOLEAN BSP,
+ IN UINT32 BistParam
+ )
+{
+ UINT32 Health;
+ UINT32 ApicID;
+ CPU_DATA_BLOCK *CpuData;
+ UINT32 BIST;
+ UINTN CpuNumber;
+ UINTN Index;
+ UINTN Count;
+ MP_CPU_EXCHANGE_INFO *ExchangeInfo;
+
+ ApicID = GetApicID (NULL, NULL);
+ BIST = 0;
+
+ if (BSP) {
+ CpuNumber = 0;
+ BIST = BistParam;
+ } else {
+ ExchangeInfo = (MP_CPU_EXCHANGE_INFO *) (UINTN) (mAcpiCpuData->WakeUpBuffer + MP_CPU_EXCHANGE_INFO_OFFSET);
+ CpuNumber = ExchangeInfo->BistBuffer[ApicID].Number;
+ BIST = ExchangeInfo->BistBuffer[ApicID].BIST;
+ }
+
+ CpuData = &MPSystemData->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;
+ Count = MPSystemData->BistHobSize / sizeof(BIST_HOB_DATA);
+ for (Index = 0; Index < Count; Index++) {
+ if (ApicID == MPSystemData->BistHobData[Index].ApicId) {
+ Health = MPSystemData->BistHobData[Index].Health;
+ }
+ }
+
+ if (Health > 0) {
+ CpuData->State = CPU_STATE_DISABLED;
+ MPSystemData->DisableCause[CpuNumber] = EFI_CPU_CAUSE_SELFTEST_FAILURE;
+ } else {
+ MPSystemData->DisableCause[CpuNumber] = EFI_CPU_CAUSE_NOT_DISABLED;
+ }
+
+ //
+ // Get Core and Thread number
+ //
+ CpuData->NumberOfCores = PcdGet32(CpuNumberOfCoresPerDie);
+
+ CpuData->NumberOfThreads = PcdGet32(CpuNumberOfThreadsPerCore);
+
+ FillInCpuLocation (&CpuData->PhysicalLocation);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ @todo Add function description
+
+ @param[in] Enable - @todo add argument description
+
+ @retval EFI_SUCCESS - @todo Add description for return value
+
+**/
+EFI_STATUS
+SetApicBSPBit (
+ IN BOOLEAN Enable
+ )
+{
+ UINT64 ApicBaseReg;
+
+ ApicBaseReg = AsmReadMsr64 (EFI_MSR_IA32_APIC_BASE);
+
+ if (Enable) {
+ ApicBaseReg |= B_EFI_MSR_IA32_APIC_BASE_BSP;
+ } else {
+ ApicBaseReg &= (~(UINT64)(B_EFI_MSR_IA32_APIC_BASE_BSP | 0xFF));
+ }
+
+ AsmWriteMsr64 (EFI_MSR_IA32_APIC_BASE, ApicBaseReg);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ @todo Add function description
+
+ @param[in] CpuNumber - @todo add argument description
+ @param[in] NewState - @todo add argument description
+ @param[in] Cause - @todo add argument description
+
+ @retval EFI_SUCCESS - @todo Add description for return value
+
+**/
+EFI_STATUS
+ChangeCpuState (
+ IN UINTN CpuNumber,
+ IN BOOLEAN NewState,
+ IN EFI_CPU_STATE_CHANGE_CAUSE Cause
+ )
+{
+ CPU_DATA_BLOCK *CpuData;
+ EFI_COMPUTING_UNIT_CPU_DISABLED_ERROR_DATA ErrorData;
+
+ CpuData = &mMPSystemData->CpuData[CpuNumber];
+
+ mMPSystemData->DisableCause[CpuNumber] = Cause;
+
+ if (!NewState) {
+ AsmAcquireMPLock (&CpuData->StateLock);
+ CpuData->State = CPU_STATE_DISABLED;
+ AsmReleaseMPLock (&CpuData->StateLock);
+
+ ErrorData.DataHeader.HeaderSize = sizeof (EFI_STATUS_CODE_DATA);
+ ErrorData.DataHeader.Size = sizeof (EFI_COMPUTING_UNIT_CPU_DISABLED_ERROR_DATA) - sizeof (EFI_STATUS_CODE_DATA);
+ CopyMem (
+ &ErrorData.DataHeader.Type,
+ &gEfiStatusCodeSpecificDataGuid,
+ sizeof (EFI_GUID)
+ );
+ ErrorData.Cause = Cause;
+ ErrorData.SoftwareDisabled = TRUE;
+ REPORT_STATUS_CODE_EX (
+ EFI_ERROR_MINOR | EFI_ERROR_CODE,
+ EFI_COMPUTING_UNIT_HOST_PROCESSOR | EFI_CU_EC_DISABLED,
+ (UINT32) CpuNumber,
+ &gEfiCallerIdGuid,
+ NULL,
+ (EFI_STATUS_CODE_DATA *) &ErrorData,
+ sizeof(EFI_COMPUTING_UNIT_CPU_DISABLED_ERROR_DATA)
+ );
+ } else {
+ AsmAcquireMPLock (&CpuData->StateLock);
+ CpuData->State = CPU_STATE_IDLE;
+ AsmReleaseMPLock (&CpuData->StateLock);
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ @todo Add function description
+
+ @retval @todo add return values
+
+**/
+BOOLEAN
+IsSecondaryThread (
+ VOID
+ )
+{
+ UINT32 ApicID;
+ UINT8 CpuPerCore;
+ UINT32 Mask;
+
+ ApicID = GetApicID (NULL, NULL);
+
+ CpuPerCore = (UINT8)PcdGet32(CpuNumberOfThreadsPerCore);
+ if (CpuPerCore == 1) {
+ return FALSE;
+ }
+
+ //
+ // 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) {
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+/**
+ If timeout occurs in StartupAllAps(), a timer is set, which invokes this
+ procedure periodically to check whether all APs have finished.
+
+ @param[in] Event Event triggered.
+ @param[in] Context Parameter passed with the event.
+
+**/
+VOID
+CheckAllAPsStatus (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ UINTN CpuNumber;
+ UINTN NextCpuNumber;
+ CPU_DATA_BLOCK *CpuData;
+ CPU_DATA_BLOCK *NextCpuData;
+ EFI_STATUS Status;
+ CPU_STATE CpuState;
+
+ for (CpuNumber = 0; CpuNumber < mMPSystemData->NumberOfCpus; CpuNumber++) {
+ CpuData = &mMPSystemData->CpuData[CpuNumber];
+ if (CpuNumber == mMPSystemData->BSP) {
+ continue;
+ }
+
+ AsmAcquireMPLock (&CpuData->StateLock);
+ CpuState = CpuData->State;
+ AsmReleaseMPLock (&CpuData->StateLock);
+
+ switch (CpuState) {
+ case CPU_STATE_READY:
+ WakeUpAp (
+ CpuData,
+ mMPSystemData->Procedure,
+ mMPSystemData->ProcArguments
+ );
+ break;
+
+ case CPU_STATE_FINISHED:
+ if (mMPSystemData->SingleThread) {
+ Status = GetNextBlockedCpuNumber (&NextCpuNumber);
+ if (!EFI_ERROR (Status)) {
+ NextCpuData = &mMPSystemData->CpuData[NextCpuNumber];
+
+ AsmAcquireMPLock (&NextCpuData->ProcedureLock);
+ NextCpuData->State = CPU_STATE_READY;
+ AsmReleaseMPLock (&NextCpuData->ProcedureLock);
+
+ WakeUpAp (
+ NextCpuData,
+ mMPSystemData->Procedure,
+ mMPSystemData->ProcArguments
+ );
+ }
+ }
+
+ CpuData->State = CPU_STATE_IDLE;
+ mMPSystemData->FinishCount++;
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ if (mMPSystemData->FinishCount == mMPSystemData->StartCount) {
+ gBS->SetTimer (
+ mMPSystemData->CheckAllAPsEvent,
+ TimerCancel,
+ 0
+ );
+ Status = gBS->SignalEvent (mMPSystemData->WaitEvent);
+ }
+
+ return ;
+}
+
+/**
+ @todo Add function description
+
+ @param[in] Event - @todo add argument description
+ @param[in] *Context - @todo add argument description
+
+**/
+VOID
+CheckThisAPStatus (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ CPU_DATA_BLOCK *CpuData;
+ EFI_STATUS Status;
+ CPU_STATE CpuState;
+
+ CpuData = &mMPSystemData->CpuData[mMPSystemData->StartedCpuNumber];
+
+ AsmAcquireMPLock (&CpuData->StateLock);
+ CpuState = CpuData->State;
+ AsmReleaseMPLock (&CpuData->StateLock);
+
+ if (CpuState == CPU_STATE_FINISHED) {
+ gBS->SetTimer (
+ mMPSystemData->CheckThisAPEvent,
+ TimerCancel,
+ 0
+ );
+ Status = gBS->SignalEvent (mMPSystemData->WaitEvent);
+ AsmAcquireMPLock (&CpuData->StateLock);
+ CpuData->State = CPU_STATE_IDLE;
+ AsmReleaseMPLock (&CpuData->StateLock);
+ }
+
+ return ;
+}
+
+/**
+ @todo Add function description
+
+ @param[in] TimeoutInMicroSecs - @todo add argument description
+
+ @retval - @todo add return values
+
+**/
+UINT64
+CalculateTimeout (
+ IN UINTN TimeoutInMicroSecs
+ )
+{
+ UINT64 CurrentTsc;
+ UINT64 ExpectedTsc;
+ UINT64 Frequency;
+ EFI_STATUS Status;
+
+ if (TimeoutInMicroSecs == 0) {
+ return 0xffffffffffff;
+ }
+
+ CurrentTsc = AsmReadTsc ();
+
+ Status = GetActualFrequency (mMetronome, &Frequency);
+
+ ExpectedTsc = CurrentTsc + MultU64x32 (Frequency, (UINT32)TimeoutInMicroSecs);
+
+ return ExpectedTsc;
+}
+
+/**
+ @todo Add function description
+
+ @param[in] ExpectedTsc - @todo add argument description
+
+ @retval - @todo add return values
+
+**/
+BOOLEAN
+CheckTimeout (
+ IN UINT64 ExpectedTsc
+ )
+{
+ UINT64 CurrentTsc;
+
+ CurrentTsc = AsmReadTsc ();
+ if (CurrentTsc >= ExpectedTsc) {
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+/**
+ @todo Add function description
+
+ @param[out] NextCpuNumber - @todo add argument description
+
+ @retval EFI_SUCCESS - @todo Add description for return value
+ @retval EFI_NOT_FOUND - @todo Add description for return value
+
+**/
+EFI_STATUS
+GetNextBlockedCpuNumber (
+ OUT UINTN *NextCpuNumber
+ )
+{
+ UINTN CpuNumber;
+ CPU_STATE CpuState;
+ CPU_DATA_BLOCK *CpuData;
+
+ for (CpuNumber = 0; CpuNumber < mMPSystemData->NumberOfCpus; CpuNumber++) {
+ if (CpuNumber == mMPSystemData->BSP) {
+ continue;
+ }
+
+ CpuData = &mMPSystemData->CpuData[CpuNumber];
+
+ AsmAcquireMPLock (&CpuData->StateLock);
+ CpuState = CpuData->State;
+ AsmReleaseMPLock (&CpuData->StateLock);
+
+ if (CpuState == CPU_STATE_BLOCKED) {
+ *NextCpuNumber = CpuNumber;
+ return EFI_SUCCESS;
+ }
+ }
+
+ return EFI_NOT_FOUND;
+}
+
+/**
+ Function to wake up a specified AP and assign procedure to it.
+
+ @param[in] CpuData CPU data block for the specified AP.
+ @param[in] Procedure Procedure to assign.
+ @param[in] ProcArguments Argument for Procedure.
+
+**/
+VOID
+WakeUpAp (
+ IN CPU_DATA_BLOCK *CpuData,
+ IN EFI_AP_PROCEDURE Procedure,
+ IN VOID *ProcArguments
+ )
+{
+ AsmAcquireMPLock (&CpuData->ProcedureLock);
+ CpuData->Parameter = ProcArguments;
+ CpuData->Procedure = Procedure;
+ AsmReleaseMPLock (&CpuData->ProcedureLock);
+
+ SendInterrupt (
+ BROADCAST_MODE_SPECIFY_CPU,
+ CpuData->ApicID,
+ 0,
+ DELIVERY_MODE_INIT,
+ TRIGGER_MODE_EDGE,
+ TRUE
+ );
+ SendInterrupt (
+ BROADCAST_MODE_SPECIFY_CPU,
+ CpuData->ApicID,
+ (UINT32) RShiftU64 (mAcpiCpuData->WakeUpBuffer, 12),
+ DELIVERY_MODE_SIPI,
+ TRIGGER_MODE_EDGE,
+ TRUE
+ );
+ CpuData->StateLock = 0;
+}
+
+/**
+ Check whether any AP is running for assigned task.
+
+ @retval TRUE - Some APs are running.
+ @retval FALSE - No AP is running.
+
+**/
+BOOLEAN
+ApRunning (
+ VOID
+ )
+{
+ CPU_DATA_BLOCK *CpuData;
+ UINTN CpuNumber;
+
+ for (CpuNumber = 0; CpuNumber < mMPSystemData->NumberOfCpus; CpuNumber++) {
+ CpuData = &mMPSystemData->CpuData[CpuNumber];
+
+ if (CpuNumber != mMPSystemData->BSP) {
+ if (CpuData->State == CPU_STATE_READY || CpuData->State == CPU_STATE_BUSY) {
+ return TRUE;
+ }
+ }
+ }
+
+ return FALSE;
+}
+
+/**
+ Count the number of APs that have been switched
+ to E0000 or F0000 segments by ReAllocateMemoryForAP().
+
+**/
+VOID
+LegacyRegionAPCount (
+ VOID
+ )
+{
+ AsmAcquireMPLock (&mMPSystemData->APSerializeLock);
+
+ mSwitchToLegacyRegionCount++;
+
+ AsmReleaseMPLock (&mMPSystemData->APSerializeLock);
+}
diff --git a/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/CpuInit/MtrrSync.c b/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/CpuInit/MtrrSync.c
new file mode 100644
index 0000000000..daf3f5dc60
--- /dev/null
+++ b/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/CpuInit/MtrrSync.c
@@ -0,0 +1,233 @@
+/** @file
+ Code which support multi-processor.
+
+ Copyright (c) 1999 - 2015, 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 "PlatformMpService.h"
+#include "MiscFuncs.h"
+#include "CpuRegs.h"
+
+extern MP_SYSTEM_DATA *mMPSystemData;
+
+EFI_MTRR_VALUES mFixedMtrrValues[] = {
+ { EFI_MSR_IA32_MTRR_FIX64K_00000, 0 },
+ { EFI_MSR_IA32_MTRR_FIX16K_80000, 0 },
+ { EFI_MSR_IA32_MTRR_FIX16K_A0000, 0 },
+ { EFI_MSR_IA32_MTRR_FIX4K_C0000, 0 },
+ { EFI_MSR_IA32_MTRR_FIX4K_C8000, 0 },
+ { EFI_MSR_IA32_MTRR_FIX4K_D0000, 0 },
+ { EFI_MSR_IA32_MTRR_FIX4K_D8000, 0 },
+ { EFI_MSR_IA32_MTRR_FIX4K_E0000, 0 },
+ { EFI_MSR_IA32_MTRR_FIX4K_E8000, 0 },
+ { EFI_MSR_IA32_MTRR_FIX4K_F0000, 0 },
+ { EFI_MSR_IA32_MTRR_FIX4K_F8000, 0 }
+};
+
+EFI_MTRR_VALUES mMtrrDefType[] = { { EFI_MSR_CACHE_IA32_MTRR_DEF_TYPE, 0 } };
+
+EFI_MTRR_VALUES mVariableMtrrValues[] = {
+ { EFI_MSR_CACHE_VARIABLE_MTRR_BASE, 0 },
+ { EFI_MSR_CACHE_VARIABLE_MTRR_BASE + 1, 0 },
+ { EFI_MSR_CACHE_VARIABLE_MTRR_BASE + 2, 0 },
+ { EFI_MSR_CACHE_VARIABLE_MTRR_BASE + 3, 0 },
+ { EFI_MSR_CACHE_VARIABLE_MTRR_BASE + 4, 0 },
+ { EFI_MSR_CACHE_VARIABLE_MTRR_BASE + 5, 0 },
+ { EFI_MSR_CACHE_VARIABLE_MTRR_BASE + 6, 0 },
+ { EFI_MSR_CACHE_VARIABLE_MTRR_BASE + 7, 0 },
+ { EFI_MSR_CACHE_VARIABLE_MTRR_BASE + 8, 0 },
+ { EFI_MSR_CACHE_VARIABLE_MTRR_BASE + 9, 0 },
+ { EFI_MSR_CACHE_VARIABLE_MTRR_BASE + 10, 0 },
+ { EFI_MSR_CACHE_VARIABLE_MTRR_BASE + 11, 0 },
+ { EFI_MSR_CACHE_VARIABLE_MTRR_BASE + 12, 0 },
+ { EFI_MSR_CACHE_VARIABLE_MTRR_BASE + 13, 0 },
+ { EFI_MSR_CACHE_VARIABLE_MTRR_BASE + 14, 0 },
+ { EFI_MSR_CACHE_VARIABLE_MTRR_END, 0 }
+};
+
+/**
+ Save the MTRR registers to global variables
+
+**/
+VOID
+ReadMtrrRegisters (
+ VOID
+ )
+{
+ UINT32 Index, IndexEnd;
+
+ //
+ // Read Fixed Mtrrs
+ //
+ for (Index = 0; Index < sizeof (mFixedMtrrValues) / sizeof (EFI_MTRR_VALUES); Index++) {
+ mFixedMtrrValues[Index].Value = AsmReadMsr64 (mFixedMtrrValues[Index].Index);
+ }
+
+ //
+ // Read def type Fixed Mtrrs
+ //
+ mMtrrDefType[0].Value = AsmReadMsr64 (EFI_MSR_CACHE_IA32_MTRR_DEF_TYPE);
+
+ //
+ // Read Variable Mtrr
+ //
+ IndexEnd = 2 * (UINT32)(AsmReadMsr64(EFI_MSR_IA32_MTRR_CAP) & B_EFI_MSR_IA32_MTRR_CAP_VARIABLE_SUPPORT);
+ for (Index = 0; Index < IndexEnd; Index++) {
+ if (Index < (sizeof (mVariableMtrrValues) / sizeof (EFI_MTRR_VALUES))) {
+ mVariableMtrrValues[Index].Value = AsmReadMsr64 (mVariableMtrrValues[Index].Index);
+ }
+ }
+
+ return ;
+}
+
+/**
+ Synch up the MTRR values for all processors
+
+ @param[in] Buffer - Not used.
+
+**/
+VOID
+EFIAPI
+MpMtrrSynchUp (
+ IN VOID *Buffer
+ )
+{
+ UINT32 Index, IndexEnd;
+ UINTN Cr4;
+ UINT64 MsrValue;
+ UINT64 ValidMtrrAddressMask;
+ EFI_CPUID_REGISTER FeatureInfo;
+ EFI_CPUID_REGISTER FunctionInfo;
+ UINT8 PhysicalAddressBits;
+
+ //
+ // ASM code to setup processor register before synching up the MTRRs
+ //
+ Cr4 = MpMtrrSynchUpEntry ();
+
+ //
+ // Get physical CPU MTRR width in case of difference from BSP
+ //
+ AsmCpuid (
+ EFI_CPUID_EXTENDED_FUNCTION,
+ &FunctionInfo.RegEax,
+ &FunctionInfo.RegEbx,
+ &FunctionInfo.RegEcx,
+ &FunctionInfo.RegEdx
+ );
+ PhysicalAddressBits = 36;
+ if (FunctionInfo.RegEax >= EFI_CPUID_VIRT_PHYS_ADDRESS_SIZE) {
+ AsmCpuid (
+ EFI_CPUID_VIRT_PHYS_ADDRESS_SIZE,
+ &FeatureInfo.RegEax,
+ &FeatureInfo.RegEbx,
+ &FeatureInfo.RegEcx,
+ &FeatureInfo.RegEdx
+ );
+ PhysicalAddressBits = (UINT8) FeatureInfo.RegEax;
+ }
+
+ ValidMtrrAddressMask = (LShiftU64( 1, PhysicalAddressBits) - 1) & 0xfffffffffffff000;
+
+ //
+ // Disable Fixed Mtrrs
+ //
+ AsmWriteMsr64 (EFI_MSR_CACHE_IA32_MTRR_DEF_TYPE, mMtrrDefType[0].Value & 0xFFFFF7FF);
+
+ //
+ // Update Fixed Mtrrs
+ //
+ for (Index = 0; Index < sizeof (mFixedMtrrValues) / sizeof (EFI_MTRR_VALUES); Index++) {
+ AsmWriteMsr64 (mFixedMtrrValues[Index].Index, mFixedMtrrValues[Index].Value);
+ }
+
+ //
+ // Synchup def type Fixed Mtrrs
+ //
+ AsmWriteMsr64 (EFI_MSR_CACHE_IA32_MTRR_DEF_TYPE, mMtrrDefType[0].Value);
+
+ //
+ // Synchup Base Variable Mtrr
+ //
+ IndexEnd = 2 * (UINT32)(AsmReadMsr64(EFI_MSR_IA32_MTRR_CAP) & B_EFI_MSR_IA32_MTRR_CAP_VARIABLE_SUPPORT);
+ for (Index = 0; Index < IndexEnd; Index += 2) {
+ if (Index < (sizeof (mVariableMtrrValues) / sizeof (EFI_MTRR_VALUES))) {
+ MsrValue = (mVariableMtrrValues[Index].Value & 0x0FFF) | (mVariableMtrrValues[Index].Value & ValidMtrrAddressMask);
+ AsmWriteMsr64 (mVariableMtrrValues[Index].Index, MsrValue);
+ }
+ }
+
+ //
+ // Synchup Mask Variable Mtrr including valid bit
+ //
+ for (Index = 1; Index < IndexEnd; Index += 2) {
+ if (Index < (sizeof (mVariableMtrrValues) / sizeof (EFI_MTRR_VALUES))) {
+ MsrValue = (mVariableMtrrValues[Index].Value & 0x0FFF) | (mVariableMtrrValues[Index].Value & ValidMtrrAddressMask);
+ AsmWriteMsr64 (mVariableMtrrValues[Index].Index, MsrValue);
+ }
+ }
+
+ //
+ // ASM code to setup processor register after synching up the MTRRs
+ //
+ MpMtrrSynchUpExit (Cr4);
+}
+
+/**
+ @todo add description
+
+**/
+VOID
+SaveBspMtrrForS3 (
+ )
+{
+ UINTN Index, IndexEnd;
+ UINTN TableIndex;
+
+ TableIndex = 0;
+
+ for (Index = 0; Index < sizeof (mFixedMtrrValues) / sizeof (mFixedMtrrValues[0]); Index++) {
+ mMPSystemData->S3BspMtrrTable[TableIndex].Index = mFixedMtrrValues[Index].Index;
+ mMPSystemData->S3BspMtrrTable[TableIndex].Value = mFixedMtrrValues[Index].Value;
+ TableIndex++;
+ }
+
+ IndexEnd = 2 * (UINT32)(AsmReadMsr64(EFI_MSR_IA32_MTRR_CAP) & B_EFI_MSR_IA32_MTRR_CAP_VARIABLE_SUPPORT);
+ for (Index = 0; Index < IndexEnd; Index ++) {
+ if (TableIndex < (sizeof (mMPSystemData->S3BspMtrrTable) / sizeof (mMPSystemData->S3BspMtrrTable[0]))) {
+ if (Index < (sizeof (mVariableMtrrValues) / sizeof (mVariableMtrrValues[0]))) {
+ mMPSystemData->S3BspMtrrTable[TableIndex].Index = mVariableMtrrValues[Index].Index;
+ mMPSystemData->S3BspMtrrTable[TableIndex].Value = mVariableMtrrValues[Index].Value;
+ TableIndex++;
+ }
+ }
+ }
+
+ if( TableIndex < ( (sizeof(mMPSystemData->S3BspMtrrTable) / sizeof(mMPSystemData->S3BspMtrrTable[0]) - 2) )) {
+ mMPSystemData->S3BspMtrrTable[TableIndex].Index = mMtrrDefType[0].Index;
+ mMPSystemData->S3BspMtrrTable[TableIndex].Value = mMtrrDefType[0].Value;
+ TableIndex++;
+
+ //
+ // To terminate the table during S3 resume for MTRR synch up
+ //
+ mMPSystemData->S3BspMtrrTable[TableIndex].Index = 0;
+ } else if( TableIndex < ( (sizeof(mMPSystemData->S3BspMtrrTable) / sizeof(mMPSystemData->S3BspMtrrTable[0]) - 1) )) {
+ //
+ // To terminate the table during S3 resume for MTRR synch up
+ //
+ mMPSystemData->S3BspMtrrTable[TableIndex].Index = 0;
+ }
+
+ ASSERT (TableIndex < MAX_CPU_S3_MTRR_ENTRY);
+}
diff --git a/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/CpuInit/PlatformMpService.h b/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/CpuInit/PlatformMpService.h
new file mode 100644
index 0000000000..aaac6ceb8a
--- /dev/null
+++ b/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/CpuInit/PlatformMpService.h
@@ -0,0 +1,636 @@
+/** @file
+ some definitions for MP services Protocol.
+
+ Copyright (c) 1999 - 2015, 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 _PLATFORM_MP_SERVICE_H_
+#define _PLATFORM_MP_SERVICE_H_
+
+#include "CpuDxe.h"
+#include "MpCommon.h"
+
+/**
+ @todo add description
+
+**/
+typedef struct {
+ UINT32 Package;
+ UINT32 Die;
+ UINT32 Core;
+ UINT32 Thread;
+} PHYSICAL_LOCATION;
+
+//
+// Constant definitions
+//
+#define FOURGB 0x100000000
+#define ONEPAGE 0x1000
+
+#define RENDEZVOUS_PROC_LENGTH 0x1000
+#define STACK_SIZE_PER_PROC 0x8000
+#define MAX_CPU_S3_MTRR_ENTRY 0x0020
+#define MAX_CPU_S3_TABLE_SIZE 0x0400
+
+#define AP_HALT_CODE_SIZE 10
+
+#define CPU_CHECK_AP_INTERVAL 0x10 // microseconds
+//
+// The MP data structure follows.
+//
+#define CPU_SWITCH_STATE_IDLE 0
+#define CPU_SWITCH_STATE_STORED 1
+#define CPU_SWITCH_STATE_LOADED 2
+
+#define MSR_L3_CACHE_DISABLE 0x40
+
+/**
+ @todo add description
+
+**/
+typedef struct {
+ UINT8 Lock; // offset 0
+ UINT8 State; // offset 1
+ UINTN StackPointer; // offset 4 / 8
+ IA32_DESCRIPTOR Gdtr; // offset 8 / 16
+ IA32_DESCRIPTOR Idtr; // offset 14 / 26
+} CPU_EXCHANGE_ROLE_INFO;
+
+/**
+ MTRR table definitions
+**/
+typedef struct {
+ UINT16 Index;
+ UINT64 Value;
+} EFI_MTRR_VALUES;
+
+typedef enum {
+ CPU_STATE_IDLE,
+ CPU_STATE_BLOCKED,
+ CPU_STATE_READY,
+ CPU_STATE_BUSY,
+ CPU_STATE_FINISHED,
+ CPU_STATE_DISABLED
+} CPU_STATE;
+
+//
+// Define CPU feature information
+//
+#define MAX_FEATURE_NUM 6
+
+/**
+ @todo add description
+
+**/
+typedef struct {
+ UINTN Index;
+ UINT32 ApicId;
+ UINT32 Version;
+ UINT32 FeatureDelta;
+ UINT32 Features[MAX_FEATURE_NUM];
+} LEAST_FEATURE_PROC;
+
+/**
+// Define Individual Processor Data block.
+**/
+typedef struct {
+ UINT32 ApicID;
+ EFI_AP_PROCEDURE Procedure;
+ VOID *Parameter;
+ UINT8 StateLock;
+ UINT8 ProcedureLock;
+ UINT32 Health;
+ BOOLEAN SecondaryCpu;
+ UINTN NumberOfCores;
+ UINTN NumberOfThreads;
+ UINT64 ActualFsbFrequency;
+ EFI_STATUS MicrocodeStatus;
+ UINT32 FailedRevision;
+ EFI_CPU_PHYSICAL_LOCATION PhysicalLocation;
+ CPU_STATE State;
+ //
+ // for PI MP Services Protocol
+ //
+ BOOLEAN *Finished;
+ UINT64 ExpectedTime;
+ EFI_EVENT WaitEvent;
+ EFI_EVENT CheckThisAPEvent;
+} CPU_DATA_BLOCK;
+
+/**
+ @todo add description
+
+**/
+typedef struct {
+ UINT32 ApicId;
+ UINT32 MsrIndex;
+ UINT64 MsrValue;
+} MP_CPU_S3_SCRIPT_DATA;
+
+/**
+ @todo add description
+
+**/
+typedef struct {
+ UINT32 S3BootScriptTable;
+ UINT32 S3BspMtrrTable;
+ UINT32 VirtualWireMode;
+} MP_CPU_S3_DATA_POINTER;
+
+/**
+ @todo add description
+
+**/
+#pragma pack (1)
+typedef struct {
+ UINT32 ApicId;
+ UINT32 Health;
+} BIST_HOB_DATA;
+#pragma pack ()
+
+/**
+ Define MP data block which consumes individual processor block.
+**/
+typedef struct {
+ UINT8 APSerializeLock;
+
+ UINT8 Tm2Core2BusRatio; // for thermal monitor 2 initialization
+ UINT8 Tm2Vid; // for thermal monitor 2 initialization
+ BOOLEAN LimitCpuidMaximumValue; // make processor look like < F40
+ BOOLEAN EnableL3Cache;
+ BOOLEAN IsC1eSupported;
+ BOOLEAN C1eEnable;
+ BOOLEAN AesEnable;
+ BOOLEAN PeciEnable;
+ BOOLEAN ProcessorVmxEnable;
+ BOOLEAN ProcessorBistEnable;
+ BOOLEAN ProcessorMsrLockControl;
+ BOOLEAN Processor3StrikeControl;
+ BOOLEAN LtEnable;
+ BOOLEAN EchoTprDisable;
+ BOOLEAN MonitorMwaitEnable;
+ BOOLEAN FastString;
+ BOOLEAN TurboModeEnable;
+ BOOLEAN ExtremeEnable;
+ BOOLEAN XapicEnable;
+ BOOLEAN MachineCheckEnable;
+ BOOLEAN MLCSpatialPrefetcherEnable;
+ BOOLEAN MLCStreamerPrefetcherEnable;
+ BOOLEAN DCUStreamerPrefetcherEnable;
+ BOOLEAN DCUIPPrefetcherEnable;
+ BOOLEAN CcxEnable;
+ BOOLEAN C1AutoDemotion;
+ BOOLEAN C3AutoDemotion;
+ BOOLEAN Vr11Enable;
+ UINT8 PackageCState;
+
+ BOOLEAN Gv3Enable;
+ BOOLEAN PsdState;
+ BOOLEAN EnableSecondaryCpu;
+ BOOLEAN DcaEnable;
+ UINTN DcaPrefetchDelayValue;
+
+ BOOLEAN DCUModeSelection;
+ BOOLEAN BiDirectionalProchot;
+
+ UINTN NumberOfCpus;
+ UINTN MaximumCpusForThisSystem;
+
+ CPU_EXCHANGE_ROLE_INFO BSPInfo;
+ CPU_EXCHANGE_ROLE_INFO APInfo;
+
+ EFI_CPU_ARCH_PROTOCOL *CpuArch;
+ EFI_EVENT CheckThisAPEvent;
+ EFI_EVENT CheckAllAPsEvent;
+ EFI_EVENT WaitEvent;
+ UINTN BSP;
+ BIST_HOB_DATA *BistHobData;
+ UINTN BistHobSize;
+
+ UINTN FinishCount;
+ UINTN StartCount;
+ EFI_AP_PROCEDURE Procedure;
+ VOID *ProcArguments;
+ BOOLEAN SingleThread;
+ UINTN StartedCpuNumber;
+ UINT8 Pad;
+
+ CPU_DATA_BLOCK CpuData[MAXIMUM_CPU_NUMBER];
+ EFI_CPU_STATE_CHANGE_CAUSE DisableCause[MAXIMUM_CPU_NUMBER];
+
+ UINT8 S3BootScriptLock;
+ UINT32 S3BootScriptCount;
+ MP_CPU_S3_DATA_POINTER S3DataPointer;
+ MP_CPU_S3_SCRIPT_DATA S3BootScriptTable[MAX_CPU_S3_TABLE_SIZE];
+ EFI_MTRR_VALUES S3BspMtrrTable[MAX_CPU_S3_MTRR_ENTRY];
+ UINT8 ActiveProcessorCores;
+} MP_SYSTEM_DATA;
+
+#pragma pack (1)
+
+/**
+ @todo add description
+
+**/
+typedef struct {
+ ACPI_CPU_DATA_COMPATIBILITY AcpiCpuData;
+ MP_SYSTEM_DATA MPSystemData;
+ IA32_DESCRIPTOR GdtrProfile;
+ IA32_DESCRIPTOR IdtrProfile;
+ EFI_CPU_MICROCODE_HEADER* MicrocodePointerBuffer[NUMBER_OF_MICROCODE_UPDATE + 1];
+} MP_CPU_RESERVED_DATA;
+
+#define CPU_MP_SERVICE_PRIVATE_SIGNATURE EFI_SIGNATURE_32 ('m', 'p', '3', '2')
+
+/**
+ @todo add description
+
+**/
+typedef struct {
+ UINTN Signature;
+ EFI_HANDLE Handle;
+ EFI_MP_SERVICES_PROTOCOL MpService;
+ MP_SYSTEM_DATA MPSystemData;
+} CPU_MP_SERVICE_PROTOCOL_PRIVATE;
+
+#define CPU_MP_SERVICE_PRIVATE_DATA_FROM_THIS(a) \
+ CR (a, \
+ CPU_MP_SERVICE_PROTOCOL_PRIVATE, \
+ MpService, \
+ CPU_MP_SERVICE_PRIVATE_SIGNATURE \
+ )
+#pragma pack ()
+
+extern CPU_MP_SERVICE_PROTOCOL_PRIVATE *Private;
+extern MP_SYSTEM_DATA *mMPSystemData;
+extern ACPI_CPU_DATA_COMPATIBILITY *mAcpiCpuData;
+
+//
+// Prototypes.
+//
+EFI_STATUS
+MpInitialize (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+;
+
+/**
+ Implementation of GetNumberOfProcessors() service of MP Services Protocol.
+
+ This service retrieves the number of logical processor in the platform
+ and the number of those logical processors that are enabled on this boot.
+ This service may only be called from the BSP.
+
+ @param[in] This A pointer to the EFI_MP_SERVICES_PROTOCOL instance.
+ @param[in] NumberOfProcessors Pointer to the total number of logical processors in the system,
+ including the BSP and disabled APs.
+ @param[in] NumberOfEnabledProcessors Pointer to the number of enabled logical processors that exist
+ in system, including the BSP.
+
+ @retval EFI_SUCCESS Number of logical processors and enabled logical processors retrieved..
+ @retval EFI_DEVICE_ERROR Caller processor is AP.
+ @retval EFI_INVALID_PARAMETER NumberOfProcessors is NULL.
+ @retval EFI_INVALID_PARAMETER NumberOfEnabledProcessors is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+GetNumberOfProcessors (
+ IN EFI_MP_SERVICES_PROTOCOL *This,
+ OUT UINTN *NumberOfProcessors,
+ OUT UINTN *NumberOfEnabledProcessors
+ );
+
+/**
+ Implementation of GetProcessorInfo() service of MP Services Protocol.
+
+ Gets detailed MP-related information on the requested processor at the
+ instant this call is made. This service may only be called from the BSP.
+
+ @param[in] This A pointer to the EFI_MP_SERVICES_PROTOCOL instance.
+ @param[in] ProcessorNumber The handle number of processor.
+ @param[in] ProcessorInfoBuffer A pointer to the buffer where information for the requested processor is deposited.
+
+ @retval EFI_SUCCESS Processor information successfully returned.
+ @retval EFI_DEVICE_ERROR Caller processor is AP.
+ @retval EFI_INVALID_PARAMETER ProcessorInfoBuffer is NULL
+ @retval EFI_NOT_FOUND Processor with the handle specified by ProcessorNumber does not exist.
+
+**/
+EFI_STATUS
+EFIAPI
+GetProcessorInfo (
+ IN EFI_MP_SERVICES_PROTOCOL *This,
+ IN UINTN ProcessorNumber,
+ OUT EFI_PROCESSOR_INFORMATION *ProcessorInfoBuffer
+ );
+
+/**
+ MP Service to get specified application processor (AP)
+ to execute a caller-provided code stream.
+
+ @param[in] This Pointer to MP Service Protocol
+ @param[in] Procedure The procedure to be assigned to AP.
+ @param[in] ProcessorNumber The handle number of processor.
+ @param[in] WaitEvent If timeout, the event to be triggered after this AP finishes.
+ @param[in] TimeoutInMicroSecs The timeout value in microsecond. Zero means infinity.
+ @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_MP_SERVICES_PROTOCOL *This,
+ IN EFI_AP_PROCEDURE Procedure,
+ IN UINTN ProcessorNumber,
+ IN EFI_EVENT WaitEvent OPTIONAL,
+ IN UINTN TimeoutInMicroSecs OPTIONAL,
+ IN VOID *ProcArguments OPTIONAL,
+ OUT BOOLEAN *Finished OPTIONAL
+ );
+
+/**
+ MP Service to get all the available application processors (APs)
+ to execute a caller-provided code stream.
+
+ @param[in] This Pointer to MP Service Protocol
+ @param[in] Procedure The procedure to be assigned to APs.
+ @param[in] SingleThread If true, all APs execute in block mode.
+ Otherwise, all APs exceute in non-block mode.
+ @param[in] WaitEvent If timeout, the event to be triggered after all APs finish.
+ @param[in] TimeoutInMicroSecs The timeout value in microsecond. Zero means infinity.
+ @param[in] ProcArguments Argument for Procedure.
+ @param[in] FailedCPUList If not NULL, all APs that fail to start will be recorded in the list.
+
+ @retval EFI_INVALID_PARAMETER Procudure is NULL.
+ @retval EFI_SUCCESS Only 1 logical processor exists.
+ @retval EFI_SUCCESS All APs have finished.
+ @retval EFI_TIMEOUT Time goes out before all APs have finished.
+
+**/
+EFI_STATUS
+EFIAPI
+StartupAllAPs (
+ IN EFI_MP_SERVICES_PROTOCOL *This,
+ IN EFI_AP_PROCEDURE Procedure,
+ IN BOOLEAN SingleThread,
+ IN EFI_EVENT WaitEvent OPTIONAL,
+ IN UINTN TimeoutInMicroSecs,
+ IN VOID *ProcArguments OPTIONAL,
+ OUT UINTN **FailedCPUList OPTIONAL
+ );
+
+/**
+ 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] This Pointer to MP Service Protocol.
+ @param[in] ProcessorNumber The handle number of processor.
+ @param[in] EnableOldBSPState 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 EFI_MP_SERVICES_PROTOCOL *This,
+ IN UINTN ProcessorNumber,
+ IN BOOLEAN EnableOldBSPState
+ );
+
+/**
+ Implementation of EnableDisableAP() service of MP Services Protocol.
+
+ This service lets the caller enable or disable an AP.
+ This service may only be called from the BSP.
+
+ @param[in] This A pointer to the EFI_MP_SERVICES_PROTOCOL instance.
+ @param[in] ProcessorNumber The handle number of processor.
+ @param[in] NewAPState Indicates whether the newstate of the AP is enabled or disabled.
+ @param[in] HealthState Indicates new health state of the AP..
+
+ @retval EFI_SUCCESS AP successfully enabled or disabled.
+ @retval EFI_DEVICE_ERROR Caller processor is AP.
+ @retval EFI_NOT_FOUND Processor with the handle specified by ProcessorNumber does not exist.
+ @retval EFI_INVALID_PARAMETERS ProcessorNumber specifies the BSP.
+
+**/
+EFI_STATUS
+EFIAPI
+EnableDisableAP (
+ IN EFI_MP_SERVICES_PROTOCOL *This,
+ IN UINTN ProcessorNumber,
+ IN BOOLEAN NewAPState,
+ IN UINT32 *HealthState OPTIONAL
+ );
+
+EFI_STATUS
+EFIAPI
+WhoAmI (
+ IN EFI_MP_SERVICES_PROTOCOL *This,
+ OUT UINTN *CpuNumber
+ );
+
+EFI_STATUS
+GetMPDataBlocks (
+ IN MP_SYSTEM_DATA *MPSystemData
+ );
+
+EFI_STATUS
+InitializeMpSystemData (
+ VOID
+ );
+
+//
+// Assembly stub definitions.
+//
+VOID
+AsmGetProcsParams1 (
+ OUT UINTN MyGlobalID,
+ OUT UINTN MyNumberOfProcessorCores,
+ OUT UINTN MyNumberOfProcessorThreads,
+ OUT UINTN RendezIntNumber
+ );
+
+VOID
+AsmGetProcsParams2 (
+ OUT UINTN MyHealthStatus,
+ OUT UINTN MyNodeNumber,
+ OUT UINTN MyNodeMemSize,
+ OUT UINTN MyProcessorCompatibility
+ );
+
+VOID
+AsmGetProcsParams3 (
+ OUT UINTN MyProcessorTestMask,
+ OUT UINTN MyProcessorSlotNumber,
+ OUT UINTN MyProcessorPackageNumber
+ );
+
+VOID
+AsmFlushProgData (
+ IN UINTN MemAddress,
+ IN UINTN Count
+ );
+
+VOID
+AsmWakeUpAPs (
+ IN UINTN *WakeUpBuffer,
+ IN UINTN MemAddress,
+ IN UINTN *StackAddressStart,
+ IN UINTN StackSize,
+ IN UINTN *APDoneSemaphore,
+ IN UINTN *GDTPageAddress
+ );
+
+EFI_STATUS
+WakeUpAPs (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ );
+
+VOID
+AsmExchangeRole (
+ IN CPU_EXCHANGE_ROLE_INFO *MyInfo,
+ IN CPU_EXCHANGE_ROLE_INFO *OthersInfo
+ );
+
+VOID
+FutureBSPProc (
+ IN MP_SYSTEM_DATA *MPSystemData
+ );
+
+EFI_STATUS
+GetMpBistStatus (
+ IN MP_SYSTEM_DATA *MPSystemData
+ );
+
+//
+// Function declarations
+//
+VOID
+InitializeMpData (
+ IN UINTN ProcessorInstance
+ );
+
+VOID
+EFIAPI
+MpServiceInitialize (
+ VOID
+ );
+
+UINTN
+MpMtrrSynchUpEntry (
+ VOID
+ );
+
+VOID
+MpMtrrSynchUpExit (
+ UINTN Cr4
+ );
+
+VOID
+SaveBspMtrrForS3 (
+ );
+
+EFI_STATUS
+FillInProcessorInformation (
+ IN MP_SYSTEM_DATA *MPSystemData,
+ IN BOOLEAN BSP,
+ IN UINT32 BistParam
+ );
+
+VOID
+APFinishTask (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ );
+
+EFI_STATUS
+SetApicBSPBit (
+ IN BOOLEAN Enable
+ );
+
+EFI_STATUS
+ChangeCpuState (
+ IN UINTN CpuNumber,
+ IN BOOLEAN NewState,
+ IN EFI_CPU_STATE_CHANGE_CAUSE Cause
+ );
+
+BOOLEAN
+IsSecondaryThread (
+ VOID
+ );
+
+VOID
+CheckAllAPsStatus (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ );
+
+VOID
+CheckThisAPStatus (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ );
+
+UINT64
+CalculateTimeout (
+ IN UINTN TimeoutInMicroSecs
+ );
+
+BOOLEAN
+CheckTimeout (
+ IN UINT64 ExpectedTsc
+ );
+
+EFI_STATUS
+GetNextBlockedCpuNumber (
+ OUT UINTN *NextCpuNumber
+ );
+
+EFI_STATUS
+FillInCpuLocation (
+ IN EFI_CPU_PHYSICAL_LOCATION *Location
+ );
+
+VOID
+DetailedInitialization (
+ VOID
+ );
+
+VOID
+WakeUpAp (
+ IN CPU_DATA_BLOCK *CpuData,
+ IN EFI_AP_PROCEDURE Procedure,
+ IN VOID *Parameter
+ );
+
+UINT8
+GetCoreNumber (
+ VOID
+ );
+
+#endif
diff --git a/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/CpuInit/x64/Cpu.asm b/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/CpuInit/x64/Cpu.asm
new file mode 100644
index 0000000000..c621e28bfb
--- /dev/null
+++ b/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/CpuInit/x64/Cpu.asm
@@ -0,0 +1,199 @@
+;; @file
+; Assembly code for the IA-32 resources.
+;
+; Copyright (c) 2005 - 2015, 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.
+;
+;;
+
+text SEGMENT
+
+
+
+
+;------------------------------------------------------------------------------
+; UINTN
+; CpuReadCr0 (
+; VOID
+; )
+;------------------------------------------------------------------------------
+CpuReadCr0 PROC PUBLIC
+ mov rax, cr0
+ ret
+CpuReadCr0 ENDP
+
+;------------------------------------------------------------------------------
+; VOID
+; CpuWriteCr0 (
+; UINTN Value
+; )
+;------------------------------------------------------------------------------
+CpuWriteCr0 PROC PUBLIC
+ mov cr0, rcx
+ ret
+CpuWriteCr0 ENDP
+
+;------------------------------------------------------------------------------
+; UINTN
+; CpuReadCr3 (
+; VOID
+; )
+;------------------------------------------------------------------------------
+CpuReadCr3 PROC PUBLIC
+ mov rax, cr3
+ ret
+CpuReadCr3 ENDP
+
+;------------------------------------------------------------------------------
+; UINTN
+; CpuWriteCr3 (
+; VOID
+; )
+;------------------------------------------------------------------------------
+CpuWriteCr3 PROC PUBLIC
+ mov cr3, rcx
+ ret
+CpuWriteCr3 ENDP
+
+
+;------------------------------------------------------------------------------
+; UINTN
+; CpuFlushTlb (
+; VOID
+; )
+;------------------------------------------------------------------------------
+CpuFlushTlb PROC PUBLIC
+ mov rax, cr3
+ mov cr3, rax
+ ret
+CpuFlushTlb ENDP
+
+
+;------------------------------------------------------------------------------
+; UINTN
+; CpuSetPower2 (
+; IN UINTN Input
+; );
+;------------------------------------------------------------------------------
+CpuSetPower2 PROC PUBLIC
+ bsr rdx, rcx
+ bts rax, rdx
+ ret
+CpuSetPower2 ENDP
+
+;------------------------------------------------------------------------------
+; UINT64
+; CpuReadTsc (
+; VOID
+; );
+;------------------------------------------------------------------------------
+CpuReadTsc PROC PUBLIC
+ rdtsc
+ ret
+CpuReadTsc ENDP
+
+;------------------------------------------------------------------------------
+; UINT64
+; CpuSwitchStacks (
+; IN UINTN EntryPoint, // rcx
+; IN UINTN Parameter1, // rdx
+; IN UINTN NewStack, // r8
+; IN UINTN NewBsp // r9 - Only used on IPF
+; );
+;------------------------------------------------------------------------------
+CpuSwitchStacks PROC PUBLIC
+ mov rsp, r8 ; rsp = NewStack
+ push rdx ; Parameter1
+ call rcx ; rcx = EntryPoint
+ ;
+ ; no ret as we have a new stack and we jumped to the new location
+ ;
+CpuSwitchStacks ENDP
+
+;------------------------------------------------------------------------------
+; UINT64
+; CpuSwitchStacks2Args (
+; IN UINTN EntryPoint, // rcx
+; IN UINTN Parameter1, // rdx
+; IN UINTN Parameter2, // r8
+; IN UINTN NewStack, // r9
+; IN UINTN Bsp // Only used on IPF
+; );
+;
+; BSP not used on IA-32
+;
+;------------------------------------------------------------------------------
+CpuSwitchStacks2Args PROC PUBLIC
+ mov rsp, r8 ; rsp = NewStack
+ push r8 ; Parameter2
+ push rdx ; Parameter1
+ call rcx ; rcx = EntryPoint
+ ;
+ ; no ret as we have a new stack and we jumped to the new location
+ ;
+ CpuSwitchStacks2Args ENDP
+
+
+;------------------------------------------------------------------------------
+; UINT16
+; CpuCodeSegment (
+; VOID
+; );
+;------------------------------------------------------------------------------
+CpuCodeSegment PROC PUBLIC
+ xor eax, eax
+ mov eax, cs
+ ret
+CpuCodeSegment ENDP
+
+
+;------------------------------------------------------------------------------
+; VOID
+; CpuBreak (
+; VOID
+; );
+;------------------------------------------------------------------------------
+CpuBreak PROC PUBLIC
+ int 3
+ ret
+CpuBreak ENDP
+
+
+;------------------------------------------------------------------------------
+; VOID
+; CpuLoadGlobalDescriptorTable (
+; VOID *Table16ByteAligned
+; );
+;------------------------------------------------------------------------------
+CpuLoadGlobalDescriptorTable PROC PUBLIC
+ lgdt FWORD PTR [rcx]
+ ret
+CpuLoadGlobalDescriptorTable ENDP
+
+CpuInitSelectors PROC PUBLIC
+ int 68h
+ ret
+CpuInitSelectors ENDP
+;------------------------------------------------------------------------------
+; VOID
+; CpuLoadInterruptDescriptorTable (
+; VOID *Table16ByteAligned
+; );
+;------------------------------------------------------------------------------
+CpuLoadInterruptDescriptorTable PROC PUBLIC
+ lidt FWORD PTR [rcx]
+ ret
+CpuLoadInterruptDescriptorTable ENDP
+
+
+text ENDS
+END
+
+
diff --git a/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/CpuInit/x64/CpuAsm.asm b/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/CpuInit/x64/CpuAsm.asm
new file mode 100644
index 0000000000..1082001fc4
--- /dev/null
+++ b/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/CpuInit/x64/CpuAsm.asm
@@ -0,0 +1,462 @@
+;; @file
+; Assembly code of the implementation of X64 CPU architectural protocol
+;
+; Copyright (c) 2005 - 2015, 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.
+;
+;;
+
+
+.code
+
+EXTRN mErrorCodeFlag:DWORD ; Error code flags for exceptions
+
+ExternalVectorTablePtr QWORD 0 ; point to the external interrupt vector table
+
+InitializeExternalVectorTablePtr PROC PUBLIC
+ mov ExternalVectorTablePtr, rcx
+ ret
+InitializeExternalVectorTablePtr ENDP
+;
+;
+;
+;------------------------------------------------------------------------------
+; Generic IDT Vector Handlers for the Host. They are all the same so they
+; will compress really well.
+;
+; By knowing the return address for Vector 00 you can can calculate the
+; vector number by looking at the call CommonInterruptEntry return address.
+; (return address - (AsmIdtVector00 + 5))/8 == IDT index
+;
+;------------------------------------------------------------------------------
+
+ALIGN 8
+
+PUBLIC AsmIdtVector00
+
+AsmIdtVector00 LABEL BYTE
+REPEAT 256
+ call CommonInterruptEntry
+ dw ( $ - AsmIdtVector00 - 5 ) / 8 ; vector number
+ nop
+ENDM
+
+
+;---------------------------------------;
+; CommonInterruptEntry ;
+;---------------------------------------;
+; The follow algorithm is used for the common interrupt routine.
+
+;
+; +---------------------+ <-- 16-byte aligned ensured by processor
+; + Old SS +
+; +---------------------+
+; + Old RSP +
+; +---------------------+
+; + RFlags +
+; +---------------------+
+; + CS +
+; +---------------------+
+; + RIP +
+; +---------------------+
+; + Error Code +
+; +---------------------+
+; + RCX / Vector Number +
+; +---------------------+
+; + RBP +
+; +---------------------+ <-- RBP, 16-byte aligned
+;
+
+CommonInterruptEntry PROC PUBLIC
+ cli
+ ;
+ ; All interrupt handlers are invoked through interrupt gates, so
+ ; IF flag automatically cleared at the entry point
+ ;
+ ;
+ ; Calculate vector number
+ ;
+ xchg rcx, [rsp] ; get the return address of call, actually, it is the address of vector number.
+ movzx ecx, word ptr [rcx]
+ cmp ecx, 32 ; Intel reserved vector for exceptions?
+ jae NoErrorCode
+ bt mErrorCodeFlag, ecx
+ jc @F
+
+NoErrorCode:
+ ;
+ ; Push a dummy error code on the stack
+ ; to maintain coherent stack map
+ ;
+ push [rsp]
+ mov qword ptr [rsp + 8], 0
+@@:
+ push rbp
+ mov rbp, rsp
+
+ ;
+ ; Since here the stack pointer is 16-byte aligned, so
+ ; EFI_FX_SAVE_STATE_X64 of EFI_SYSTEM_CONTEXT_x64
+ ; is 16-byte aligned
+ ;
+
+;; UINT64 Rdi, Rsi, Rbp, Rsp, Rbx, Rdx, Rcx, Rax;
+;; UINT64 R8, R9, R10, R11, R12, R13, R14, R15;
+ push r15
+ push r14
+ push r13
+ push r12
+ push r11
+ push r10
+ push r9
+ push r8
+ push rax
+ push qword ptr [rbp + 8] ; RCX
+ push rdx
+ push rbx
+ push qword ptr [rbp + 48] ; RSP
+ push qword ptr [rbp] ; RBP
+ push rsi
+ push rdi
+
+;; UINT64 Gs, Fs, Es, Ds, Cs, Ss; insure high 16 bits of each is zero
+ movzx rax, word ptr [rbp + 56]
+ push rax ; for ss
+ movzx rax, word ptr [rbp + 32]
+ push rax ; for cs
+ mov rax, ds
+ push rax
+ mov rax, es
+ push rax
+ mov rax, fs
+ push rax
+ mov rax, gs
+ push rax
+
+ mov [rbp + 8], rcx ; save vector number
+
+;; UINT64 Rip;
+ push qword ptr [rbp + 24]
+
+;; UINT64 Gdtr[2], Idtr[2];
+ sub rsp, 16
+ sidt fword ptr [rsp]
+ sub rsp, 16
+ sgdt fword ptr [rsp]
+
+;; UINT64 Ldtr, Tr;
+ xor rax, rax
+ str ax
+ push rax
+ sldt ax
+ push rax
+
+;; UINT64 RFlags;
+ push qword ptr [rbp + 40]
+
+;; UINT64 Cr0, Cr1, Cr2, Cr3, Cr4, Cr8;
+ mov rax, cr8
+ push rax
+ mov rax, cr4
+ or rax, 208h
+ mov cr4, rax
+ push rax
+ mov rax, cr3
+ push rax
+ mov rax, cr2
+ push rax
+ xor rax, rax
+ push rax
+ mov rax, cr0
+ push rax
+
+;; UINT64 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7;
+ mov rax, dr7
+ push rax
+;; clear Dr7 while executing debugger itself
+ xor rax, rax
+ mov dr7, rax
+
+ mov rax, dr6
+ push rax
+;; insure all status bits in dr6 are clear...
+ xor rax, rax
+ mov dr6, rax
+
+ mov rax, dr3
+ push rax
+ mov rax, dr2
+ push rax
+ mov rax, dr1
+ push rax
+ mov rax, dr0
+ push rax
+
+;; FX_SAVE_STATE_X64 FxSaveState;
+
+ sub rsp, 512
+ mov rdi, rsp
+ db 0fh, 0aeh, 00000111y ;fxsave [rdi]
+
+;; UINT32 ExceptionData;
+ push qword ptr [rbp + 16]
+
+;; call into exception handler
+ mov rcx, [rbp + 8]
+ mov rax, ExternalVectorTablePtr ; get the interrupt vectors base
+ mov rax, [rax + rcx * 8]
+ or rax, rax ; NULL?
+
+ je nonNullValue;
+
+;; Prepare parameter and call
+; mov rcx, [rbp + 8]
+ mov rdx, rsp
+ ;
+ ; Per X64 calling convention, allocate maximum parameter stack space
+ ; and make sure RSP is 16-byte aligned
+ ;
+ sub rsp, 4 * 8 + 8
+ call rax
+ add rsp, 4 * 8 + 8
+
+nonNullValue:
+ cli
+;; UINT64 ExceptionData;
+ add rsp, 8
+
+;; FX_SAVE_STATE_X64 FxSaveState;
+
+ mov rsi, rsp
+ db 0fh, 0aeh, 00001110y ; fxrstor [rsi]
+ add rsp, 512
+
+;; UINT64 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7;
+ pop rax
+ mov dr0, rax
+ pop rax
+ mov dr1, rax
+ pop rax
+ mov dr2, rax
+ pop rax
+ mov dr3, rax
+;; skip restore of dr6. We cleared dr6 during the context save.
+ add rsp, 8
+ pop rax
+ mov dr7, rax
+
+;; UINT64 Cr0, Cr1, Cr2, Cr3, Cr4, Cr8;
+ pop rax
+ mov cr0, rax
+ add rsp, 8 ; not for Cr1
+ pop rax
+ mov cr2, rax
+ pop rax
+ mov cr3, rax
+ pop rax
+ mov cr4, rax
+ pop rax
+ mov cr8, rax
+
+;; UINT64 RFlags;
+ pop qword ptr [rbp + 40]
+
+;; UINT64 Ldtr, Tr;
+;; UINT64 Gdtr[2], Idtr[2];
+;; Best not let anyone mess with these particular registers...
+ add rsp, 48
+
+;; UINT64 Rip;
+ pop qword ptr [rbp + 24]
+
+;; UINT64 Gs, Fs, Es, Ds, Cs, Ss;
+ pop rax
+ ; mov gs, rax ; not for gs
+ pop rax
+ ; mov fs, rax ; not for fs
+ ; (X64 will not use fs and gs, so we do not restore it)
+ pop rax
+ mov es, rax
+ pop rax
+ mov ds, rax
+ pop qword ptr [rbp + 32] ; for cs
+ pop qword ptr [rbp + 56] ; for ss
+
+;; UINT64 Rdi, Rsi, Rbp, Rsp, Rbx, Rdx, Rcx, Rax;
+;; UINT64 R8, R9, R10, R11, R12, R13, R14, R15;
+ pop rdi
+ pop rsi
+ add rsp, 8 ; not for rbp
+ pop qword ptr [rbp + 48] ; for rsp
+ pop rbx
+ pop rdx
+ pop rcx
+ pop rax
+ pop r8
+ pop r9
+ pop r10
+ pop r11
+ pop r12
+ pop r13
+ pop r14
+ pop r15
+
+ mov rsp, rbp
+ pop rbp
+ add rsp, 16
+ iretq
+
+CommonInterruptEntry ENDP
+
+
+LongMode PROC PUBLIC
+
+in_long_mode::
+ ;
+ ; Debug Stop
+ ;
+ jmp in_long_mode
+
+ ;
+ ; We're in long mode, so marshall the arguments to call the
+ ; passed in function pointers
+ ; Recall
+ ; [ebp][10h] = HobStart
+ ; [ebp][18h] = Stack
+ ; [ebp][20h] = PpisNeededByDxeIplEntryPoint <--- Call this first (for each call, pass HOB pointer)
+ ; [ebp][28h] = DxeCoreEntryPoint <--- Call this second
+ ;
+ mov rbx, [rbp+18h] ; Setup the stack
+ mov rsp, rbx ; On a new stack now
+
+ mov rcx, [rbp+10h] ; Pass Hob Start in RCX
+ mov rax, [rbp+20h] ; Get the function pointer for
+ ; PpisNeededByDxeIplEntryPoint into EAX
+ call fword ptr [rax] ; Make the call into PpisNeededByDxeIplEntryPoint
+
+ mov ecx, [rbp+10h] ; Pass Hob Start in RCX
+ mov eax, [rbp+28h] ; Get the function pointer for
+ ; DxeCoreEntryPoint into EAX
+ call fword ptr [rax] ; Make the call into Dxe Core
+
+ call CommonInterruptEntry
+
+ mov rdi, CommonInterruptEntry
+
+ lgdt fword ptr [rdi]
+
+ lidt fword ptr [rdi]
+
+ call near ptr [rax] ; Make the call into PpisNeededByDxeIplEntryPoint
+
+ call rax
+
+ ;
+ ; Should never get here.
+ ;
+no_long_mode:
+ jmp no_long_mode
+ ;
+ ; WE SHOULD NEVER GET HERE!!!!!!!!!!!!!
+ ;
+LongMode endp
+
+MpMtrrSynchUpEntry PROC PUBLIC
+ ;
+ ; Enter no fill cache mode, CD=1(Bit30), NW=0 (Bit29)
+ ;
+ mov rax, cr0
+ and rax, 0DFFFFFFFh
+ or rax, 040000000h
+ mov cr0, rax
+ ;
+ ; Flush cache
+ ;
+ wbinvd
+ ;
+ ; Clear PGE flag Bit 7
+ ;
+ mov rax, cr4
+ mov rdx, rax
+ and rax, 0FFFFFF7Fh
+ mov cr4, rax
+ ;
+ ; Flush all TLBs
+ ;
+ mov rax, cr3
+ mov cr3, rax
+
+ mov rax, rdx
+
+ ret
+
+MpMtrrSynchUpEntry ENDP
+
+MpMtrrSynchUpExit PROC PUBLIC
+ ;
+ ; Flush all TLBs the second time
+ ;
+ mov rax, cr3
+ mov cr3, rax
+ ;
+ ; Enable Normal Mode caching CD=NW=0, CD(Bit30), NW(Bit29)
+ ;
+ mov rax, cr0
+ and rax, 09FFFFFFFh
+ mov cr0, rax
+ ;
+ ; Set PGE Flag in CR4 if set
+ ;
+ mov cr4, rcx
+ ret
+
+MpMtrrSynchUpExit ENDP
+
+CpuInitFloatPointUnit PROC PUBLIC
+
+ ; bugbug
+ ; finit
+ ret
+
+CpuInitFloatPointUnit ENDP
+
+CpuDisableInterrupt PROC PUBLIC
+
+ cli
+ ret
+
+CpuDisableInterrupt ENDP
+
+CpuEnableInterrupt PROC PUBLIC
+
+ sti
+ ret
+
+CpuEnableInterrupt ENDP
+
+GetCoreNumber PROC PUBLIC
+
+ push rbx
+
+ mov eax, 4
+ mov ecx, 0
+ cpuid
+
+ shr eax, 26
+ and eax, 3fh
+ inc al
+
+ pop rbx
+
+ ret
+
+GetCoreNumber ENDP
+
+END
diff --git a/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/CpuInit/x64/CpuInitDxeGccDummy.c b/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/CpuInit/x64/CpuInitDxeGccDummy.c
new file mode 100644
index 0000000000..116497d3a9
--- /dev/null
+++ b/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/CpuInit/x64/CpuInitDxeGccDummy.c
@@ -0,0 +1,184 @@
+/** @file
+ CPU Dxe Gcc Support - Dummy functions.
+
+ Copyright (c) 1999 - 2015, 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.
+
+**/
+
+UINTN AsmIdtVector00;
+
+///
+/// Function declarations
+///
+/**
+ This is dummy function equivelant to the asm function CpuEnableInterrupt(), made for GCC build.
+**/
+VOID
+CpuEnableInterrupt (
+ VOID
+ )
+{
+ return;
+}
+
+/**
+ This is dummy function equivelant to the asm function CpuDisableInterrupt(), made for GCC build.
+**/
+VOID
+CpuDisableInterrupt (
+ VOID
+ )
+{
+ return;
+}
+
+/**
+ This is dummy function equivelant to the asm function AsmAcquireMPLock(), made for GCC build.
+**/
+VOID
+AsmAcquireMPLock (
+ VOID
+ )
+{
+ return;
+}
+
+/**
+ This is dummy function equivelant to the asm function AsmReleaseMPLock(), made for GCC build.
+**/
+VOID
+AsmReleaseMPLock (
+ VOID
+ )
+{
+ return;
+}
+
+/**
+ This is dummy function equivelant to the asm function AsmExchangeRole(), made for GCC build.
+**/
+VOID
+AsmExchangeRole (
+ VOID
+ )
+{
+ return;
+}
+
+/**
+ This is dummy function equivelant to the asm function CpuInitFloatPointUnit(), made for GCC build.
+**/
+VOID
+CpuInitFloatPointUnit (
+ VOID
+ )
+{
+ return;
+}
+
+/**
+ This is dummy function equivelant to the asm function MpMtrrSynchUpEntry(), made for GCC build.
+**/
+VOID
+MpMtrrSynchUpEntry (
+ VOID
+ )
+{
+ return;
+}
+
+/**
+ This is dummy function equivelant to the asm function MpMtrrSynchUpExit(), made for GCC build.
+**/
+VOID
+MpMtrrSynchUpExit (
+ VOID
+ )
+{
+ return;
+}
+
+/**
+ This is dummy function equivelant to the asm function CpuLoadGlobalDescriptorTable(), made for GCC build.
+**/
+VOID
+CpuLoadGlobalDescriptorTable (
+ VOID
+ )
+{
+ return;
+}
+
+/**
+ This is dummy function equivelant to the asm function CpuLoadInterruptDescriptorTable(), made for GCC build.
+**/
+VOID
+CpuLoadInterruptDescriptorTable (
+ VOID
+ )
+{
+ return;
+}
+
+/**
+ This is dummy function equivelant to the asm function InitializeExternalVectorTablePtr(), made for GCC build.
+**/
+VOID
+InitializeExternalVectorTablePtr (
+ VOID
+ )
+{
+ return;
+}
+
+/**
+ This is dummy function equivelant to the asm function CpuCodeSegment(), made for GCC build.
+**/
+VOID
+CpuCodeSegment (
+ VOID
+ )
+{
+ return;
+}
+
+/**
+ This is dummy function equivelant to the asm function AsmGetAddressMap(), made for GCC build.
+**/
+VOID
+AsmGetAddressMap (
+ VOID
+ )
+{
+ return;
+}
+
+/**
+ This is dummy function equivelant to the asm function AsmGetGdtrIdtr(), made for GCC build.
+**/
+VOID
+AsmGetGdtrIdtr (
+ VOID
+ )
+{
+ return;
+}
+
+/**
+ This is dummy function equivelant to the asm function AsmGetCr3(), made for GCC build.
+**/
+VOID
+AsmGetCr3 (
+ VOID
+ )
+{
+ return;
+}
diff --git a/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/CpuInit/x64/Exception.c b/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/CpuInit/x64/Exception.c
new file mode 100644
index 0000000000..4e4d4ed1c0
--- /dev/null
+++ b/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/CpuInit/x64/Exception.c
@@ -0,0 +1,319 @@
+/** @file
+ EM64T Exception Handler.
+
+ Copyright (c) 2014 - 2015, 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 "CpuDxe.h"
+#include "MpCommon.h"
+#include "Exception.h"
+
+typedef
+VOID
+(*EFI_INSTALL_EXCEPTION) (
+ IN UINT32 InterruptType,
+ IN VOID *SystemContext
+ );
+/**
+ @todo No structure description
+
+**/
+typedef struct {
+ UINT32 ErrorMessage;
+ UINT8 Interrupt;
+} EFI_EXCEPTION_HANDLER;
+
+//
+// Error code flag indicating whether or not an error code will be
+// pushed on the stack if an exception occurs.
+//
+// 1 means an error code will be pushed, otherwise 0
+//
+// bit 0 - exception 0
+// bit 1 - exception 1
+// etc.
+//
+UINT32 mErrorCodeFlag = 0x00027d00;
+
+//
+// Local Table
+//
+EFI_EXCEPTION_HANDLER mExceptionTable[] = {
+ { EFI_SW_EC_IA32_DIVIDE_ERROR, INTERRUPT_HANDLER_DIVIDE_ZERO },
+ { EFI_SW_EC_IA32_DEBUG, INTERRUPT_HANDLER_DEBUG },
+ { EFI_SW_EC_IA32_NMI, INTERRUPT_HANDLER_NMI },
+ { EFI_SW_EC_IA32_BREAKPOINT, INTERRUPT_HANDLER_BREAKPOINT },
+ { EFI_SW_EC_IA32_OVERFLOW, INTERRUPT_HANDLER_OVERFLOW },
+ { EFI_SW_EC_IA32_BOUND, INTERRUPT_HANDLER_BOUND },
+ { EFI_SW_EC_IA32_INVALID_OPCODE, INTERRUPT_HANDLER_INVALID_OPCODE },
+//
+// Interrupt 7, 9, 15 not defined in the debug support protocol. Hence no status codes for them!
+//
+ { EFI_SW_EC_IA32_DOUBLE_FAULT, INTERRUPT_HANDLER_DOUBLE_FAULT },
+ { EFI_SW_EC_IA32_INVALID_TSS, INTERRUPT_HANDLER_INVALID_TSS },
+ { EFI_SW_EC_IA32_SEG_NOT_PRESENT, INTERRUPT_HANDLER_SEGMENT_NOT_PRESENT },
+ { EFI_SW_EC_IA32_STACK_FAULT, INTERRUPT_HANDLER_STACK_SEGMENT_FAULT },
+ { EFI_SW_EC_IA32_GP_FAULT, INTERRUPT_HANDLER_GP_FAULT },
+ { EFI_SW_EC_IA32_PAGE_FAULT, INTERRUPT_HANDLER_PAGE_FAULT },
+ { EFI_SW_EC_IA32_FP_ERROR, INTERRUPT_HANDLER_MATH_FAULT },
+ { EFI_SW_EC_IA32_ALIGNMENT_CHECK, INTERRUPT_HANDLER_ALIGNMENT_FAULT },
+ { EFI_SW_EC_IA32_MACHINE_CHECK, INTERRUPT_HANDLER_MACHINE_CHECK },
+ { EFI_SW_EC_IA32_SIMD, INTERRUPT_HANDLER_STREAMING_SIMD }
+ };
+
+UINTN mExceptionNumber = sizeof (mExceptionTable) / sizeof (EFI_EXCEPTION_HANDLER);
+
+CPU_STATUS_CODE_TEMPLATE mStatusCodeData = {
+ {
+ sizeof (EFI_STATUS_CODE_DATA),
+ sizeof (EFI_SYSTEM_CONTEXT_X64),
+ EFI_STATUS_CODE_DATA_TYPE_EXCEPTION_HANDLER_GUID
+ },
+ {
+ 0
+ }
+};
+
+UINT8 mExceptionLock = 0;
+/**
+ Report StatusCode for Exception
+
+ @param[in] InterruptType Interrupt type
+ @param[in] SystemContext EFI_SYSTEM_CONTEXT
+
+ @retval EFI_SUCCESS
+
+**/
+EFI_STATUS
+ReportData (
+ IN EFI_EXCEPTION_TYPE InterruptType,
+ IN EFI_SYSTEM_CONTEXT SystemContext
+ )
+{
+ UINT32 ErrorMessage;
+ UINT32 Index;
+
+ CopyMem (
+ &mStatusCodeData.SystemContext.SystemContextX64,
+ SystemContext.SystemContextX64,
+ sizeof (EFI_SYSTEM_CONTEXT_X64)
+ );
+
+ ErrorMessage = EFI_SOFTWARE_DXE_BS_DRIVER;
+ for (Index = 0; Index < mExceptionNumber; Index++) {
+ if (mExceptionTable[Index].Interrupt == InterruptType) {
+ ErrorMessage |= mExceptionTable[Index].ErrorMessage;
+ break;
+ }
+ }
+
+ REPORT_STATUS_CODE_EX (
+ (EFI_ERROR_CODE | EFI_ERROR_UNRECOVERED),
+ EFI_SOFTWARE_UNSPECIFIED | ErrorMessage,
+ 0,
+ &gEfiCallerIdGuid,
+ NULL,
+ (EFI_STATUS_CODE_DATA *)&mStatusCodeData,
+ sizeof(CPU_STATUS_CODE_TEMPLATE)
+ );
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Common exception handler
+
+ @param[in] InterruptType Exception type
+ @param[in] SystemContext EFI_SYSTEM_CONTEXT
+
+**/
+VOID
+EFIAPI
+CommonExceptionHandler (
+ IN EFI_EXCEPTION_TYPE InterruptType,
+ IN EFI_SYSTEM_CONTEXT SystemContext
+ )
+{
+ AsmAcquireMPLock (&mExceptionLock);
+
+ DEBUG ((
+ DEBUG_ERROR,
+ "!!!! X64 Exception Type - %016lx CPU Apic ID - %08x!!!!\n",
+ InterruptType,
+ GetApicID (NULL, NULL)
+ ));
+ DEBUG ((
+ DEBUG_ERROR,
+ "RIP - %016lx, CS - %016lx, RFLAGS - %016lx\n",
+ SystemContext.SystemContextX64->Rip,
+ SystemContext.SystemContextX64->Cs,
+ SystemContext.SystemContextX64->Rflags
+ ));
+ if (mErrorCodeFlag & (1 << InterruptType)) {
+ DEBUG ((
+ DEBUG_ERROR,
+ "ExceptionData - %016lx\n",
+ SystemContext.SystemContextX64->ExceptionData
+ ));
+ }
+ DEBUG ((
+ DEBUG_ERROR,
+ "RAX - %016lx, RCX - %016lx, RDX - %016lx\n",
+ SystemContext.SystemContextX64->Rax,
+ SystemContext.SystemContextX64->Rcx,
+ SystemContext.SystemContextX64->Rdx
+ ));
+ DEBUG ((
+ DEBUG_ERROR,
+ "RBX - %016lx, RSP - %016lx, RBP - %016lx\n",
+ SystemContext.SystemContextX64->Rbx,
+ SystemContext.SystemContextX64->Rsp,
+ SystemContext.SystemContextX64->Rbp
+ ));
+ DEBUG ((
+ DEBUG_ERROR,
+ "RSI - %016lx, RDI - %016lx\n",
+ SystemContext.SystemContextX64->Rsi,
+ SystemContext.SystemContextX64->Rdi
+ ));
+ DEBUG ((
+ DEBUG_ERROR,
+ "R8 - %016lx, R9 - %016lx, R10 - %016lx\n",
+ SystemContext.SystemContextX64->R8,
+ SystemContext.SystemContextX64->R9,
+ SystemContext.SystemContextX64->R10
+ ));
+ DEBUG ((
+ DEBUG_ERROR,
+ "R11 - %016lx, R12 - %016lx, R13 - %016lx\n",
+ SystemContext.SystemContextX64->R11,
+ SystemContext.SystemContextX64->R12,
+ SystemContext.SystemContextX64->R13
+ ));
+ DEBUG ((
+ DEBUG_ERROR,
+ "R14 - %016lx, R15 - %016lx\n",
+ SystemContext.SystemContextX64->R14,
+ SystemContext.SystemContextX64->R15
+ ));
+ DEBUG ((
+ DEBUG_ERROR,
+ "DS - %016lx, ES - %016lx, FS - %016lx\n",
+ SystemContext.SystemContextX64->Ds,
+ SystemContext.SystemContextX64->Es,
+ SystemContext.SystemContextX64->Fs
+ ));
+ DEBUG ((
+ DEBUG_ERROR,
+ "GS - %016lx, SS - %016lx\n",
+ SystemContext.SystemContextX64->Gs,
+ SystemContext.SystemContextX64->Ss
+ ));
+ DEBUG ((
+ DEBUG_ERROR,
+ "GDTR - %016lx %016lx, LDTR - %016lx\n",
+ SystemContext.SystemContextX64->Gdtr[0],
+ SystemContext.SystemContextX64->Gdtr[1],
+ SystemContext.SystemContextX64->Ldtr
+ ));
+ DEBUG ((
+ DEBUG_ERROR,
+ "IDTR - %016lx %016lx, TR - %016lx\n",
+ SystemContext.SystemContextX64->Idtr[0],
+ SystemContext.SystemContextX64->Idtr[1],
+ SystemContext.SystemContextX64->Tr
+ ));
+ DEBUG ((
+ DEBUG_ERROR,
+ "CR0 - %016lx, CR2 - %016lx, CR3 - %016lx\n",
+ SystemContext.SystemContextX64->Cr0,
+ SystemContext.SystemContextX64->Cr2,
+ SystemContext.SystemContextX64->Cr3
+ ));
+ DEBUG ((
+ DEBUG_ERROR,
+ "CR4 - %016lx, CR8 - %016lx\n",
+ SystemContext.SystemContextX64->Cr4,
+ SystemContext.SystemContextX64->Cr8
+ ));
+ DEBUG ((
+ DEBUG_ERROR,
+ "DR0 - %016lx, DR1 - %016lx, DR2 - %016lx\n",
+ SystemContext.SystemContextX64->Dr0,
+ SystemContext.SystemContextX64->Dr1,
+ SystemContext.SystemContextX64->Dr2
+ ));
+ DEBUG ((
+ DEBUG_ERROR,
+ "DR3 - %016lx, DR6 - %016lx, DR7 - %016lx\n",
+ SystemContext.SystemContextX64->Dr3,
+ SystemContext.SystemContextX64->Dr6,
+ SystemContext.SystemContextX64->Dr7
+ ));
+
+ //
+ // Report Status Code
+ //
+ ReportData (InterruptType, SystemContext);
+
+ AsmReleaseMPLock (&mExceptionLock);
+
+ //
+ // Use this macro to hang so that the compiler does not optimize out
+ // the following RET instructions. This allows us to return if we
+ // have a debugger attached.
+ //
+ CpuDeadLoop ();
+
+ return ;
+}
+
+/**
+ Install the IA-32 EM64T Exception Handler.
+ The current operation (which likely will change) will uninstall all the
+ pertinent exception handlers (0-7, 10-14, 16-19) except for Int8 which the timer
+ is currently sitting on (or soon will be).
+
+ It then installs all the appropriate handlers for each exception.
+
+ The handler then calls gRT->ReportStatusCode with a specific progress code. The
+ progress codes for now start at 0x200 for IA-32 processors. See Status Code
+ Specification for details. The Status code Specification uses the enumeration from
+ the EFI 1.1 Debug Support Protocol.
+
+ @param[in] CpuProtocol - Instance of CPU Arch Protocol
+
+ @retval EFI_STATUS
+
+**/
+EFI_STATUS
+InitializeException (
+ IN EFI_CPU_ARCH_PROTOCOL *CpuProtocol
+ )
+{
+ EFI_STATUS Status;
+ UINTN Index;
+
+ Status = CpuProtocol->DisableInterrupt (CpuProtocol);
+
+ for (Index = 0; Index < mExceptionNumber; Index++) {
+ Status = CpuProtocol->RegisterInterruptHandler (CpuProtocol, mExceptionTable[Index].Interrupt, NULL);
+ //
+ // Add in our handler
+ //
+ Status = CpuProtocol->RegisterInterruptHandler (CpuProtocol, mExceptionTable[Index].Interrupt, CommonExceptionHandler);
+ ASSERT_EFI_ERROR (Status);
+ }
+
+ return EFI_SUCCESS;
+}
+
diff --git a/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/CpuInit/x64/Htequ.inc b/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/CpuInit/x64/Htequ.inc
new file mode 100644
index 0000000000..d8a94ca9ea
--- /dev/null
+++ b/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/CpuInit/x64/Htequ.inc
@@ -0,0 +1,44 @@
+;; @file
+;
+; Copyright (c) 2005 - 2015, 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
+BreakToRunApSignal Equ 6E750000h
+
+MonitorFilterSize Equ 40h
+WakeUpApCounterInit Equ 0
+WakeUpApPerHltLoop Equ 1
+WakeUpApPerMwaitLoop Equ 2
+WakeUpApPerRunLoop Equ 3
+WakeUpApPerMwaitLoop32 Equ 4
+WakeUpApPerRunLoop32 Equ 5
+
+LockLocation equ 1000h - 0400h
+StackStartAddressLocation equ LockLocation + 08h
+StackSizeLocation equ LockLocation + 10h
+CProcedureLocation equ LockLocation + 18h
+GdtrLocation equ LockLocation + 20h
+IdtrLocation equ LockLocation + 2Ah
+BufferStartLocation equ LockLocation + 34h
+Cr3OffsetLocation equ LockLocation + 38h
+InitFlagLocation equ LockLocation + 3Ch
+WakeUpApManner equ LockLocation + 40h
+BistBuffer equ LockLocation + 44h
+
+PAUSE32 MACRO
+ DB 0F3h
+ DB 090h
+ ENDM
+
+;-------------------------------------------------------------------------------
diff --git a/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/CpuInit/x64/MemoryOperation.c b/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/CpuInit/x64/MemoryOperation.c
new file mode 100644
index 0000000000..83bfa8bf05
--- /dev/null
+++ b/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/CpuInit/x64/MemoryOperation.c
@@ -0,0 +1,718 @@
+/** @file
+ Memory Operation Functions for IA32 Architecture.
+
+ Copyright (c) 2014 - 2015, 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 "CpuDxe.h"
+#include "PlatformCpuLib.h"
+#include "MpCommon.h"
+#include "VirtualMemory.h"
+#include "MemoryAttribute.h"
+#include "CpuRegs.h"
+
+/**
+ This functions Initializes External Vector Table Pointer
+
+ @param[in] *VectorTable Pointer to Vector Table
+
+**/
+VOID
+InitializeExternalVectorTablePtr (
+ EFI_CPU_INTERRUPT_HANDLER* VectorTable
+);
+
+extern EFI_CPU_INTERRUPT_HANDLER mExternalVectorTable[];
+extern EFI_PHYSICAL_ADDRESS mBackupBuffer;
+
+UINT8 *mPageStore = NULL;
+UINTN mPageStoreSize = 16;
+UINTN mPageStoreIndex = 0;
+
+UINT64 mValidMtrrAddressMask;
+UINT64 mValidMtrrBitsMask;
+
+#if defined (__GNUC__)
+#define ALINE_16BYTE_BOUNDRY __attribute__ ((aligned (16)))
+#else
+#define ALINE_16BYTE_BOUNDRY __declspec (align (16))
+#endif
+
+#pragma pack (1)
+/**
+ @todo add description
+
+**/
+typedef struct {
+ UINT16 LimitLow;
+ UINT16 BaseLow;
+ UINT8 BaseMiddle;
+ UINT8 Attributes1;
+ UINT8 Attributes2;
+ UINT8 BaseHigh;
+} SEGMENT_DESCRIPTOR_x64;
+
+/**
+ @todo Add description
+
+**/
+
+typedef struct {
+ UINT16 Limit;
+ UINTN Base;
+} PSEUDO_DESCRIPTOR_x64;
+
+#pragma pack()
+
+ALINE_16BYTE_BOUNDRY SEGMENT_DESCRIPTOR_x64 gGdt[] = {
+ { // NULL Selector: selector[0]
+ 0, // limit 15:0
+ 0, // base 15:0
+ 0, // base 23:16
+ 0, //
+ 0, // type & limit 19:16
+ 0, // base 31:24
+ },
+ { // Linear Selector: selector[8]
+ 0xffff, // limit 15:0
+ 0, // base 15:0
+ 0, // base 23:16
+ 0x92, // present, ring 0, data, expand-up writable
+ 0xcf, // type & limit 19:16
+ 0, // base 31:24
+ },
+ { // Linear code Selector: selector[10]
+ 0xffff, // limit 15:0
+ 0, // base 15:0
+ 0, // base 23:16
+ 0x9a, // present, ring 0, code, expand-up writable
+ 0xaf, // type & limit 19:16
+ 0, // base 31:24
+ },
+ { // Compatibility mode data Selector: selector[18]
+ 0xffff, // limit 15:0
+ 0, // base 15:0
+ 0, // base 23:16
+ 0x92, // type & limit 19:16
+ 0xcf,
+ 0, // base 31:24
+ },
+ { // Compatibility code Selector: selector[20]
+ 0xffff, // limit 15:0
+ 0, // base 15:0
+ 0, // base 23:16
+ 0x9a, // type & limit 19:16
+ 0xcf,
+ 0, // base 31:24
+ },
+ { // Spare3 Selector: selector[28]
+ 0, // limit 15:0
+ 0, // base 15:0
+ 0, // base 23:16
+ 0, // type & limit 19:16
+ 0, // base 31:24
+ 0,
+ },
+ { // 64-bit data Selector:selector[30]
+ 0xffff, // limit 15:0
+ 0, // base 15:0
+ 0, // base 23:16
+ 0x92, // type & limit 19:16
+ 0xcf,
+ 0, // base 31:24
+ },
+ { // 64-bit code Selector: selector[38]
+ 0xffff, // limit 15:0
+ 0, // base 15:0
+ 0, // base 23:16
+ 0x9a, // type & limit 19:16
+ 0xaf,
+ 0, // base 31:24
+ },
+ { // Spare3 Selector: selector[40]
+ 0, // limit 15:0
+ 0, // base 15:0
+ 0, // base 23:16
+ 0, // type & limit 19:16
+ 0, // base 31:24
+ 0,
+ }
+};
+
+ALINE_16BYTE_BOUNDRY PSEUDO_DESCRIPTOR_x64 gGdtPseudoDescriptor = {
+ sizeof (gGdt) - 1,
+ (UINTN)gGdt
+};
+
+INTERRUPT_GATE_DESCRIPTOR gIdtTable[INTERRUPT_VECTOR_NUMBER] = { 0 };
+
+ALINE_16BYTE_BOUNDRY PSEUDO_DESCRIPTOR_x64 gLidtPseudoDescriptor = {
+ sizeof (gIdtTable) - 1,
+ (UINTN)gIdtTable
+};
+
+/**
+ @todo add function description
+
+**/
+VOID
+InitializeSelectors (
+ VOID
+ )
+{
+ CpuLoadGlobalDescriptorTable (&gGdtPseudoDescriptor);
+}
+
+VOID
+AsmIdtVector00 (
+ VOID
+ );
+/**
+ Slick around interrupt routines.
+
+**/
+VOID
+InitializeInterruptTables (
+ VOID
+ )
+{
+ UINT16 CodeSegment;
+ INTERRUPT_GATE_DESCRIPTOR *IdtEntry;
+ UINT8 *CurrentHandler;
+ UINT32 Index;
+
+ CodeSegment = CpuCodeSegment ();
+
+ IdtEntry = gIdtTable;
+ CurrentHandler = (UINT8 *)(UINTN)AsmIdtVector00;
+ for (Index = 0; Index < INTERRUPT_VECTOR_NUMBER; Index ++) {
+ IdtEntry[Index].Offset15To0 = (UINT16)(UINTN)CurrentHandler;
+ IdtEntry[Index].SegmentSelector = CodeSegment;
+ IdtEntry[Index].Attributes = INTERRUPT_GATE_ATTRIBUTE; //8e00;
+ IdtEntry[Index].Offset31To16 = (UINT16)((UINTN)CurrentHandler >> 16);
+ IdtEntry[Index].Offset63To32 = (UINT32)((UINTN)CurrentHandler >> 32);
+
+ CurrentHandler += 0x8;
+ }
+
+ CpuLoadInterruptDescriptorTable (&gLidtPseudoDescriptor);
+
+ return;
+}
+
+/**
+ @todo add function description
+
+**/
+VOID
+InitailizeMemoryAttributes (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ EFI_PHYSICAL_ADDRESS Page;
+ EFI_CPUID_REGISTER FeatureInfo;
+ EFI_CPUID_REGISTER FunctionInfo;
+ UINT8 PhysicalAddressBits;
+ UINT32 MsrNum, MsrNumEnd;
+ UINT64 TempQword;
+ UINT64 ComplementBits;
+
+ Status = gBS->AllocatePages (
+ AllocateAnyPages,
+ EfiBootServicesData,
+ mPageStoreSize,
+ &Page
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ mPageStore = (UINT8 *)(UINTN)Page;
+
+ ZeroMem (mPageStore, 0x1000 * mPageStoreSize);
+
+ ///
+ /// Check returned value of Eax for extended CPUID functions
+ ///
+ AsmCpuid (
+ EFI_CPUID_EXTENDED_FUNCTION,
+ &FunctionInfo.RegEax,
+ &FunctionInfo.RegEbx,
+ &FunctionInfo.RegEcx,
+ &FunctionInfo.RegEdx
+ );
+
+ PhysicalAddressBits = 36;
+
+ ///
+ /// If CPU supports extended functions, get the Physical Address size by reading EAX[7:0]
+ ///
+ if (FunctionInfo.RegEax > EFI_CPUID_VIRT_PHYS_ADDRESS_SIZE) {
+ AsmCpuid (
+ EFI_CPUID_VIRT_PHYS_ADDRESS_SIZE,
+ &FeatureInfo.RegEax,
+ &FeatureInfo.RegEbx,
+ &FeatureInfo.RegEcx,
+ &FeatureInfo.RegEdx
+ );
+ PhysicalAddressBits = (UINT8) FeatureInfo.RegEax;
+ }
+
+ mValidMtrrBitsMask = (((UINT64) 1) << PhysicalAddressBits) - 1;
+ mValidMtrrAddressMask = mValidMtrrBitsMask & 0xfffffffffffff000;
+
+ MsrNumEnd = EFI_MSR_CACHE_VARIABLE_MTRR_BASE + (2 * (UINT32)(AsmReadMsr64(EFI_MSR_IA32_MTRR_CAP) & B_EFI_MSR_IA32_MTRR_CAP_VARIABLE_SUPPORT)); //803 is put after PreMtrrChange()
+ ComplementBits = mValidMtrrBitsMask & 0xfffffff000000000;
+ if (ComplementBits != 0) {
+ PreMtrrChange ();
+ for (MsrNum = EFI_MSR_CACHE_VARIABLE_MTRR_BASE; MsrNum < MsrNumEnd; MsrNum += 2) {
+ TempQword = AsmReadMsr64 (MsrNum + 1);
+ if ((TempQword & B_EFI_MSR_CACHE_MTRR_VALID) != 0) {
+ //
+ // MTRR Physical Mask
+ //
+ TempQword = TempQword | ComplementBits;
+ AsmWriteMsr64 (MsrNum + 1, TempQword);
+ }
+ }
+ PostMtrrChange ();
+ }
+}
+
+/**
+ @todo add function description
+
+**/
+VOID *
+AllocateZeroedPage (
+ VOID
+ )
+{
+ if (mPageStoreIndex >= mPageStoreSize) {
+ //
+ // We are out of space
+ //
+ return NULL;
+ }
+
+ return (VOID *)(UINTN)&mPageStore[0x1000 * mPageStoreIndex++];
+}
+
+/**
+ This function converts 2 MB page to 4K pages
+
+ @param[in] PageAddress
+ @param[in] **PageDirectoryToConvert
+
+ @todo review parameters and description
+
+**/
+VOID
+Convert2MBPageTo4KPages (
+ IN EFI_PHYSICAL_ADDRESS PageAddress,
+ IN OUT x64_PAGE_TABLE_ENTRY **PageDirectoryToConvert
+ )
+{
+ UINTN Index;
+ EFI_PHYSICAL_ADDRESS WorkingAddress;
+ x64_PAGE_TABLE_ENTRY_4K *PageTableEntry;
+ x64_PAGE_TABLE_ENTRY Attributes;
+
+ //
+ // Save the attributes of the 2MB table
+ //
+ Attributes.Page2Mb.Uint64 = (*PageDirectoryToConvert)->Page2Mb.Uint64;
+
+ //
+ // Convert PageDirectoryEntry2MB into a 4K Page Directory
+ //
+ PageTableEntry = AllocateZeroedPage ();
+
+ if (PageTableEntry == NULL) {
+ ASSERT(PageTableEntry != NULL);
+ return;
+ }
+
+ (*PageDirectoryToConvert)->Page2Mb.Uint64 = (UINT64)PageTableEntry;
+ (*PageDirectoryToConvert)->Page2Mb.Bits.ReadWrite = 1;
+ (*PageDirectoryToConvert)->Page2Mb.Bits.Present = 1;
+
+ WorkingAddress = PageAddress;
+ for (Index = 0; Index < 512; Index++, PageTableEntry++, WorkingAddress += 0x1000) {
+ PageTableEntry->Uint64 = (UINT64)WorkingAddress;
+ PageTableEntry->Bits.Present = 1;
+
+ //
+ // Update the new page to have the same attributes as the 2MB page
+ //
+ PageTableEntry->Bits.ReadWrite = Attributes.Common.ReadWrite;
+ PageTableEntry->Bits.CacheDisabled = Attributes.Common.CacheDisabled;
+ PageTableEntry->Bits.WriteThrough = Attributes.Common.WriteThrough;
+
+ if (WorkingAddress == PageAddress) {
+ //
+ // Return back the 4K page that matches the Working addresss
+ //
+ *PageDirectoryToConvert = (x64_PAGE_TABLE_ENTRY *)PageTableEntry;
+ }
+ }
+}
+
+/**
+ @todo Add description to function
+
+ @param[in] BaseAddress @todo Add parameter description
+ @param[out] PageTable @todo Add parameter description
+ @param[out] Page2MBytes @todo Add parameter description
+
+ @retval @todo Add return value description
+
+**/
+EFI_STATUS
+GetCurrentMapping (
+ IN EFI_PHYSICAL_ADDRESS BaseAddress,
+ OUT x64_PAGE_TABLE_ENTRY **PageTable,
+ OUT BOOLEAN *Page2MBytes
+ )
+{
+ UINT64 Cr3;
+ x64_PAGE_MAP_AND_DIRECTORY_POINTER_2MB_4K *PageMapLevel4Entry;
+ x64_PAGE_MAP_AND_DIRECTORY_POINTER_2MB_4K *PageDirectoryPointerEntry;
+ x64_PAGE_TABLE_ENTRY_2M *PageTableEntry2Mb;
+ x64_PAGE_DIRECTORY_ENTRY_4K *PageDirectoryEntry4k;
+ x64_PAGE_TABLE_ENTRY_4K *PageTableEntry4k;
+ UINTN Pml4Index;
+ UINTN PdpIndex;
+ UINTN Pde2MbIndex;
+ UINTN PteIndex;
+
+ Cr3 = CpuReadCr3 ();
+
+ PageMapLevel4Entry = (x64_PAGE_MAP_AND_DIRECTORY_POINTER_2MB_4K *)(Cr3 & 0x000ffffffffff000);
+
+ Pml4Index = (UINTN)RShiftU64 (BaseAddress, 39) & 0x1ff;
+ if (PageMapLevel4Entry[Pml4Index].Bits.Present == 0) {
+ return EFI_NOT_FOUND;
+ }
+ PageDirectoryPointerEntry = (x64_PAGE_MAP_AND_DIRECTORY_POINTER_2MB_4K *)(PageMapLevel4Entry[Pml4Index].Uint64 & 0x000ffffffffff000);
+ PdpIndex = (UINTN)RShiftU64 (BaseAddress, 30) & 0x1ff;
+ if (PageDirectoryPointerEntry[PdpIndex].Bits.Present == 0) {
+ return EFI_NOT_FOUND;
+ }
+
+ PageTableEntry2Mb = (x64_PAGE_TABLE_ENTRY_2M *)(PageDirectoryPointerEntry[PdpIndex].Uint64 & 0x000ffffffffff000);
+ Pde2MbIndex = (UINTN)RShiftU64 (BaseAddress, 21) & 0x1ff;
+ if (PageTableEntry2Mb[Pde2MbIndex].Bits.Present == 0) {
+ return EFI_NOT_FOUND;
+ }
+
+ if (PageTableEntry2Mb[Pde2MbIndex].Bits.MustBe1 == 1) {
+ //
+ // We found a 2MByte page so lets return it
+ //
+ *Page2MBytes = TRUE;
+ *PageTable = (x64_PAGE_TABLE_ENTRY *)&PageTableEntry2Mb[Pde2MbIndex].Uint64;
+ return EFI_SUCCESS;
+ }
+
+ //
+ // 4K page so keep walking
+ //
+ PageDirectoryEntry4k = (x64_PAGE_DIRECTORY_ENTRY_4K *)&PageTableEntry2Mb[Pde2MbIndex].Uint64;
+
+ PageTableEntry4k = (x64_PAGE_TABLE_ENTRY_4K *)(PageDirectoryEntry4k[Pde2MbIndex].Uint64 & 0x000ffffffffff000);
+ PteIndex = (UINTN)RShiftU64 (BaseAddress, 12) & 0x1ff;
+ if (PageTableEntry4k[PteIndex].Bits.Present == 0) {
+ return EFI_NOT_FOUND;
+ }
+
+ *Page2MBytes = FALSE;
+ *PageTable = (x64_PAGE_TABLE_ENTRY *)&PageTableEntry4k[PteIndex];
+ return EFI_SUCCESS;
+}
+
+/**
+ Prepare memory for essential system tables.
+
+ @retval EFI_SUCCESS Memory successfully prepared.
+
+**/
+EFI_STATUS
+PrepareMemory (
+ VOID
+ )
+{
+ //
+ // Allocate space to convert 2MB page tables to 4K tables.
+ // This can not be done a call time as the TPL level will
+ // not be correct.
+ //
+ InitailizeMemoryAttributes ();
+
+ InitializeExternalVectorTablePtr (mExternalVectorTable);
+ //
+ // Initialize the Interrupt Descriptor Table
+ //
+ InitializeInterruptTables ();
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Prepare Wakeup Buffer and stack for APs.
+
+ @param[out] 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;
+ MP_ASSEMBLY_ADDRESS_MAP AddressMap;
+
+ //
+ // Release All APs with a lock and wait for them to retire to rendezvous procedure.
+ // We need a 64 aligned 4K aligned area for IA-32 to use broadcast APIs. But we need it only
+ // on a temporary basis.
+ //
+ Status = AllocateWakeUpBuffer (WakeUpBuffer);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ //
+ // Claim memory for AP stack.
+ //
+ Status = AllocateReservedMemoryBelow4G (
+ (MaximumCPUsForThisSystem + 1) * STACK_SIZE_PER_PROC,
+ (VOID **) StackAddressStart
+ );
+
+ if (EFI_ERROR (Status)) {
+ gBS->FreePages (*WakeUpBuffer, 1);
+ return Status;
+ }
+
+ AsmGetAddressMap (&AddressMap);
+ CopyMem ((VOID *) (UINTN) *WakeUpBuffer, AddressMap.RendezvousFunnelAddress, AddressMap.Size);
+ *(UINT32 *) (UINTN) (*WakeUpBuffer + AddressMap.FlatJumpOffset + 3) = (UINT32) (*WakeUpBuffer + AddressMap.PModeEntryOffset);
+ *(UINT32 *) (UINTN) (*WakeUpBuffer + AddressMap.LongJumpOffset + 2) = (UINT32) (*WakeUpBuffer + AddressMap.LModeEntryOffset);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Prepare exchange information for APs.
+
+ @param[out] ExchangeInfo Pointer to the exchange info buffer for output.
+ @param[in] StackAddressStart Start address of APs' stacks.
+ @param[in] ApFunction Address of function assigned to AP.
+ @param[in] WakeUpBuffer Pointer to the address of wakeup buffer.
+
+ @retval EFI_SUCCESS Exchange Info successfully prepared for APs.
+
+**/
+EFI_STATUS
+PrepareExchangeInfo (
+ OUT MP_CPU_EXCHANGE_INFO *ExchangeInfo,
+ IN VOID *StackAddressStart,
+ IN VOID *ApFunction,
+ IN EFI_PHYSICAL_ADDRESS WakeUpBuffer
+ )
+{
+ gBS->SetMem ((VOID *) ExchangeInfo, EFI_PAGE_SIZE - MP_CPU_EXCHANGE_INFO_OFFSET, 0);
+
+ ExchangeInfo->Lock = VacantFlag;
+ ExchangeInfo->StackStart = StackAddressStart;
+ ExchangeInfo->StackSize = STACK_SIZE_PER_PROC;
+ ExchangeInfo->ApFunction = ApFunction;
+
+ CopyMem ((VOID *) (UINTN) &ExchangeInfo->GdtrProfile, (VOID *) (UINTN) mAcpiCpuData->GdtrProfile, sizeof (IA32_DESCRIPTOR));
+ CopyMem ((VOID *) (UINTN) &ExchangeInfo->IdtrProfile, (VOID *) (UINTN) mAcpiCpuData->IdtrProfile, sizeof (IA32_DESCRIPTOR));
+
+ ExchangeInfo->BufferStart = (UINT32) WakeUpBuffer;
+ ExchangeInfo->Cr3 = (UINT32) (AsmGetCr3 ());
+ ExchangeInfo->InitFlag = 1;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Prepare Wakeup Buffer and stack for APs.
+
+ @param[out] WakeUpBuffer Pointer to the address of wakeup buffer for output.
+ @param[out] StackAddressStart Pointer to the stack address of APs for output.
+
+ @retval EFI_SUCCESS Memory successfully prepared for APs.
+
+**/
+EFI_STATUS
+S3PrepareMemoryForAPs (
+ OUT EFI_PHYSICAL_ADDRESS *WakeUpBuffer,
+ OUT VOID **StackAddressStart
+ )
+{
+ return EFI_SUCCESS;
+}
+
+/**
+ Prepare exchange information for APs.
+
+ @param[out] ExchangeInfo Pointer to the exchange info for output.
+ @param[in] StackAddressStart Start address of APs' stacks.
+ @param[in] ApFunction Address of function assigned to AP.
+ @param[in] WakeUpBuffer Pointer to the address of wakeup buffer.
+
+ @retval EFI_SUCCESS Exchange Info successfully prepared for APs.
+
+**/
+EFI_STATUS
+S3PrepareExchangeInfo (
+ OUT MP_CPU_EXCHANGE_INFO *ExchangeInfo,
+ IN VOID *StackAddressStart,
+ IN VOID *ApFunction,
+ IN EFI_PHYSICAL_ADDRESS WakeUpBuffer
+ )
+{
+ return EFI_SUCCESS;
+}
+
+/**
+ Dynamically write the far jump destination in APs' wakeup buffer,
+ in order to refresh APs' CS registers for mode switching.
+
+**/
+VOID
+RedirectFarJump (
+ VOID
+ )
+{
+ MP_ASSEMBLY_ADDRESS_MAP AddressMap;
+
+ AsmGetAddressMap (&AddressMap);
+ *(UINT32 *) (UINTN) (mAcpiCpuData->WakeUpBuffer + AddressMap.FlatJumpOffset + 3) = (UINT32) (mAcpiCpuData->WakeUpBuffer + AddressMap.PModeEntryOffset);
+ *(UINT32 *) (UINTN) (mAcpiCpuData->WakeUpBuffer + AddressMap.LongJumpOffset + 2) = (UINT32) (mAcpiCpuData->WakeUpBuffer + AddressMap.LModeEntryOffset);
+
+ return;
+}
+
+/**
+ Set specified IDT entry with given function pointer.
+
+ @param[in] FunctionPointer Function pointer for IDT entry.
+ @param[out] IdtEntry The IDT entry to update.
+
+ @retval The original IDT entry value.
+
+**/
+UINTN
+SetIdtEntry (
+ IN UINTN FunctionPointer,
+ OUT INTERRUPT_GATE_DESCRIPTOR *IdtEntry
+)
+{
+ UINTN OriginalEntry;
+
+ OriginalEntry = ((UINT64) IdtEntry->Offset63To32 << 32) + ((UINT32) IdtEntry->Offset31To16 << 16) + IdtEntry->Offset15To0;
+
+ IdtEntry->Offset15To0 = (UINT16) FunctionPointer;
+ IdtEntry->Offset31To16 = (UINT16) (FunctionPointer >> 16);
+ IdtEntry->Offset63To32 = (UINT32) (FunctionPointer >> 32);
+
+ return OriginalEntry;
+}
+
+/**
+ @todo Add function description
+
+ @param[in] Gdtr @todo add argument description for *Gdtr
+ @param[in] Idtr @todo add argument description for *Idtr
+
+ @retval EFI_SUCCESS This function completed successfully
+
+**/
+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;
+ EFI_STATUS Status;
+
+ AsmGetGdtrIdtr (&GdtrForBSP, &IdtrForBSP);
+
+ //
+ // Allocate reserved memory for IDT
+ //
+ Status = AllocateAlignedReservedMemory (
+ IdtrForBSP->Limit + 1,
+ 8,
+ (VOID **) &IdtForAP
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ //
+ // Allocate reserved memory for GDT
+ //
+ Status = AllocateAlignedReservedMemory (
+ GdtrForBSP->Limit + 1,
+ 8,
+ (VOID **) &GdtForAP
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = gBS->AllocatePool (
+ EfiACPIMemoryNVS,
+ SIZE_OF_MCE_HANDLER,
+ (VOID **)&MceHandler
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ //
+ // McheHandler 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);
+ IdtForAP[INTERRUPT_HANDLER_MACHINE_CHECK].Offset63To32 = (UINT32) ((UINTN) MceHandler >> 32);
+
+ //
+ // Create Gdtr, IDTR profile
+ //
+ Gdtr->Base = (UINTN) GdtForAP;
+ Gdtr->Limit = GdtrForBSP->Limit;
+
+ Idtr->Base = (UINTN) IdtForAP;
+ Idtr->Limit = IdtrForBSP->Limit;
+
+ return EFI_SUCCESS;
+}
diff --git a/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/CpuInit/x64/MpCpu.c b/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/CpuInit/x64/MpCpu.c
new file mode 100644
index 0000000000..7ef2f43ba1
--- /dev/null
+++ b/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/CpuInit/x64/MpCpu.c
@@ -0,0 +1,76 @@
+/** @file
+ MP Support driver.
+
+ Copyright (c) 2007 - 2015, 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 "CpuDxe.h"
+#include "MpCommon.h"
+#include "PlatformMpService.h"
+
+extern EFI_CPU_MICROCODE_HEADER **mMicrocodePointerBuffer;
+
+ACPI_CPU_DATA_COMPATIBILITY *mAcpiCpuData;
+MP_SYSTEM_DATA *mMPSystemData;
+
+/**
+ Initializes MP support in the system.
+
+ @param[in] ImageHandle Image handle of the loaded driver
+ @param[in] SystemTable Pointer to the System Table
+
+ @retval EFI_SUCCESS Multiple processors are initialized successfully.
+ @retval EFI_NOT_FOUND The ACPI variable is not found in S3 boot path.
+ @retval EFI_OUT_OF_RESOURCES No enough resoruces (such as out of memory).
+
+**/
+EFI_STATUS
+InitializeMpSupport (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+ MP_CPU_RESERVED_DATA *MpCpuReservedData;
+
+ MpCpuReservedData = NULL;
+
+ Status = AllocateReservedMemoryBelow4G (
+ sizeof (MP_CPU_RESERVED_DATA),
+ (VOID **) &MpCpuReservedData
+ );
+
+ if ((EFI_ERROR (Status)) || (MpCpuReservedData == NULL)) {
+ return Status;
+ }
+
+ ZeroMem (MpCpuReservedData, sizeof (MP_CPU_RESERVED_DATA));
+
+ mMPSystemData = &(MpCpuReservedData->MPSystemData);
+ mAcpiCpuData = &(MpCpuReservedData->AcpiCpuData);
+
+ CopyMem (
+ MpCpuReservedData->MicrocodePointerBuffer,
+ mMicrocodePointerBuffer,
+ sizeof (EFI_CPU_MICROCODE_HEADER *) * (NUMBER_OF_MICROCODE_UPDATE + 1)
+ );
+
+ mAcpiCpuData->CpuPrivateData = (EFI_PHYSICAL_ADDRESS)(UINTN)(&(mMPSystemData->S3DataPointer));
+ mAcpiCpuData->S3BootPath = FALSE;
+ mAcpiCpuData->MicrocodePointerBuffer = (EFI_PHYSICAL_ADDRESS) MpCpuReservedData->MicrocodePointerBuffer;
+ mAcpiCpuData->GdtrProfile = (EFI_PHYSICAL_ADDRESS) & (MpCpuReservedData->GdtrProfile);
+ mAcpiCpuData->IdtrProfile = (EFI_PHYSICAL_ADDRESS) & (MpCpuReservedData->IdtrProfile);
+
+ MpServiceInitialize ();
+
+ return EFI_SUCCESS;
+}
diff --git a/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/CpuInit/x64/MpFuncs.asm b/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/CpuInit/x64/MpFuncs.asm
new file mode 100644
index 0000000000..9970dfba48
--- /dev/null
+++ b/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/CpuInit/x64/MpFuncs.asm
@@ -0,0 +1,604 @@
+;; @file
+; This is the assembly code for EM64T MP support.
+;
+; Copyright (c) 1999 - 2015, 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 Htequ.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);
+
+text SEGMENT
+
+RendezvousFunnelProc PROC PUBLIC
+RendezvousFunnelProcStart::
+
+; 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 InitFlagLocation ; mov si, InitFlag
+ db 66h, 83h, 3Ch, 00h ; cmp dword ptr [si], 0
+ db 74h ; opcode of jz
+ db flat32Start - ($ + 1) ; jz flat32Start
+
+; Record BIST information
+;
+ db 0B0h, 08h ; mov al, 8
+ db 0F6h, 0E3h ; mul bl
+
+ db 0BEh ; opcode of mov si, imm16
+ dw BistBuffer ; mov si, BistBuffer
+ 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
+
+ cli
+ hlt
+ jmp $-2
+
+;
+; Switch to flat mode.
+;
+flat32Start::
+
+ db 0BFh ; opcode of mov di, imm16
+ dw BufferStartLocation ; mov di, BufferStartLocation
+ db 66h, 8Bh, 35h ; mov esi,dword ptr [di] ; ESI is keeping the start address of wakeup buffer
+
+ db 0BFh ; opcode of mov di, imm16
+ dw Cr3OffsetLocation ; mov di, Cr3Location
+ db 66h, 8Bh, 0Dh ; mov ecx,dword ptr [di] ; ECX is keeping the value of CR3
+
+ db 0BFh ; opcode of mov di, imm16
+ dw GdtrLocation ; mov di, GdtrProfile
+ db 66h ; db 66h
+ db 2Eh, 0Fh, 01h, 15h ; lgdt fword ptr cs:[di]
+
+ db 0BFh ; opcode of mov di, imm16
+ dw IdtrLocation ; mov di, IdtrProfile
+ db 66h ; db 66h
+ db 2Eh, 0Fh, 01h, 1Dh ; lidt fword ptr cs:[di]
+
+ db 0BFh ; opcode of mov di, imm16
+ dw LongModeStartJump - RendezvousFunnelProcStart ; Get offset of LongModeStartJump
+ db 66h, 8Bh, 3Dh ; mov edi,dword ptr [di] ; EDI is keeping the LongModeStart Jump Address
+
+ db 31h, 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) and MP
+ db 0Fh, 22h, 0C0h ; mov cr0, eax
+
+FLAT32_JUMP::
+
+ db 66h, 67h, 0EAh ; far jump
+ dd 0h ; 32-bit offset
+ dw 20h ; 16-bit selector
+
+NemInit:: ; 32-bits protected mode entry point
+
+ db 66h, 0B8h, 18h, 00h ; mov ax, 18h
+ db 66h, 8Eh, 0D8h ; mov ds, ax
+ db 66h, 8Eh, 0C0h ; mov es, ax
+ db 66h, 8Eh, 0E0h ; mov fs, ax
+ db 66h, 8Eh, 0E8h ; mov gs, ax
+ db 66h, 8Eh, 0D0h ; mov ss, ax ; Flat mode setup.
+
+
+PrepareToGoLongMode64::
+
+ db 0Fh, 20h, 0E0h ; mov eax, cr4
+ db 66h, 0Dh, 020h, 06h ; or ax, 0620h ; Set PAE=1, OSFXSR=1, OSXMMEXCPT=1.
+ db 0Fh, 22h, 0E0h ; mov cr4, eax
+
+ db 0Fh, 22h, 0D9h ; mov cr3, ecx
+
+ db 0B9h
+ dd 0C0000080h ; mov ecx, 0c0000080h ; EFER MSR number.
+ db 0Fh, 32h ; rdmsr ; Read EFER.
+ db 0Fh, 0BAh, 0E8h, 08h ; bts eax, 8 ; Set LME=1.
+ db 0Fh, 30h ; wrmsr ; Write EFER.
+
+ db 0Fh, 20h, 0C0h ; mov eax, cr0 ; Read CR0.
+ db 0Fh, 0BAh, 0E8h, 1Fh ; bts eax, 31 ; Set PG=1.
+ db 0Fh, 22h, 0C0h ; mov cr0, eax ; Write CR0.
+
+LONG_JUMP::
+
+ db 67h, 0EAh ; far jump
+
+LongModeStartJump:
+
+ dd 0h ; 32-bit offset
+ dw 38h ; 16-bit selector
+
+
+LongModeStart::
+
+ mov ax, 30h
+ mov ds, ax
+ mov es, ax
+ mov ss, ax
+;
+; Patch Addresses for jumping between RUN and MONITOR MWAIT loops 32-bits and Long Monde Procedure 64-bits
+; Based on the running address of LongModeStart in physic memory which was actually copied by CPU DXE INIT
+;
+ xor rdx, rdx
+ mov eax, edi
+ add eax, RunLoopAndMwaitLoop32 - LongModeStart
+ mov edx, edi
+ add edx, RunLoopAndMwaitLoop32Jump - LongModeStart
+ mov dword ptr [rdx], eax
+
+ mov rbp, rdx ; RBP = 32-bits compatibility mode FAR JUMP m16:32 operand pointer
+
+ mov eax, edi
+ add eax, RunLoopAndMwaitLoop64 - LongModeStart
+ mov edx, edi
+ add edx, RunLoopAndMwaitLoop64Jump - LongModeStart
+ mov dword ptr [rdx], eax
+
+;
+; ProgramStack
+;
+ xor rcx, rcx
+ mov edi, esi
+ add edi, BistBuffer
+ mov ecx, dword ptr [edi + 8 * ebx] ; RCX = CpuNumber
+
+ mov edi, esi
+ add edi, StackSizeLocation
+ mov rax, qword ptr [edi]
+ inc rcx
+ mul rcx ; RAX = StackSize * (CpuNumber + 1)
+
+ mov edi, esi
+ add edi, StackStartAddressLocation
+ mov rdx, qword ptr [edi]
+ add rax, rdx ; RAX = StackStart + StackSize * (CpuNumber + 1)
+
+ mov rsp, rax
+ sub rsp, MonitorFilterSize ; Reserved Monitor data space
+ or ebx, BreakToRunApSignal ; ebx = #Cpu run signature
+
+;
+; Load C Function pointer and wakeup manner location
+;
+ mov edi, esi
+ add edi, CProcedureLocation
+ add esi, WakeUpApManner ; esi = WakeUpApManner Address Location
+
+WakeUpThisAp64::
+
+ mov rax, qword ptr [edi]
+
+ test rax, rax
+ jz CheckWakeUpCounterInit64
+
+ push rbp
+ push rbx
+ push rsi
+ push rdi
+
+ sub rsp, 20h
+ call rax
+ add rsp, 20h
+
+ pop rdi
+ pop rsi
+ pop rbx
+ pop rbp
+
+CheckWakeUpCounterInit64::
+
+ cmp dword ptr [esi], WakeUpApCounterInit
+ jnz CheckWakeUpManner64
+
+;
+; Initialize MONITOR_MWAIT_DATA data structure per thread
+;
+ xor rcx, rcx
+ mov qword ptr [rsp + 0], rcx ; BreakToRunApSignal
+ mov qword ptr [rsp + 8], rcx ; HltLoopBreakCounter
+ mov qword ptr [rsp + 16], rcx ; MwaitLoopBreakCounter
+ mov qword ptr [rsp + 24], rcx ; RunLoopBreakCounter
+ mov qword ptr [rsp + 32], rcx ; MwaitLoopBreakCounter32
+ mov qword ptr [rsp + 40], rcx ; RunLoopBreakCounter32
+ mov qword ptr [rsp + 48], rcx ; WakeUpApVectorChangeFlag
+ mov qword ptr [rsp + 56], rcx ; MwaitTargetCstate
+
+WaitWakeUpMannerAssigned::
+
+ pause
+ cmp dword ptr [esi], WakeUpApCounterInit
+ jz WaitWakeUpMannerAssigned
+
+CheckWakeUpManner64::
+
+ pause
+ mov edx, dword ptr [esi]
+ cmp edx, WakeUpApPerHltLoop
+ jz HltApLoop64
+
+ cmp edx, WakeUpApPerMwaitLoop
+ jz ApMwaitLoop64
+
+ cmp edx, WakeUpApPerRunLoop
+ jz CheckRunSignal64
+
+ jmp JumpToCompatibility32Mode
+
+ApMwaitLoop64::
+
+ cli
+ mov rax, rsp ; Set Monitor Address
+ xor rcx, rcx
+ xor rdx, rdx
+ DB 0fh, 1, 0c8h ; MONITOR
+ mov rax, qword ptr [rsp + 56] ; Mwait Target C-State per rax[7:4]
+ DB 0fh, 1, 0c9h ; MWAIT
+
+CheckRunSignal64::
+
+ cmp qword ptr [rsp], rbx ; Check if run signal correct?
+ jnz CheckWakeUpManner64 ; Unknown break, go checking run manner
+
+ jmp WakeUpThisAp64 ; Jmp to execute AP task
+
+HltApLoop64::
+
+ cli
+ hlt
+ jmp HltApLoop64 ; Jump to halt loop
+
+
+JumpToCompatibility32Mode::
+
+ db 0FFh, 6Dh, 0 ; jmp pword ptr [rbp+0] ; Far jump to m16:32 for 32-bits compatibility mode
+
+RunLoopAndMwaitLoop32Jump:
+
+ dd 0h ; m32 part of m16:32
+ dw 20h ; m16 part of m16:32
+
+RunLoopAndMwaitLoop32::
+
+ db 66h, 0B8h, 18h, 00h ; mov ax, 18h
+ db 66h, 8Eh, 0D8h ; mov ds, ax
+ db 8eh, 0d0h ; mov ss, ax
+
+ db 0Fh, 20h, 0C0h ; mov eax, cr0 ; Read CR0.
+ db 0Fh, 0BAh, 0F0h, 1Fh ; btr eax, 31 ; Reset PG=0.
+ db 0Fh, 22h, 0C0h ; mov cr0, eax ; Write CR0.
+
+ db 0B9h
+ dd 0C0000080h ; mov ecx, 0c0000080h ; EFER MSR number.
+ db 0Fh, 32h ; rdmsr ; Read EFER.
+ db 0Fh, 0BAh, 0F0h, 08h ; btr eax, 8 ; Reset LME=0.
+ db 0Fh, 30h ; wrmsr ; Write EFER.
+
+ db 0Fh, 20h, 0E0h ; mov eax, cr4
+ db 24h, 0DFh ; and al, 0DFh ; Reset PAE=0 in CR4 bit 5
+ db 0Fh, 22h, 0E0h ; mov cr4, eax
+
+CheckWakeUpManner32::
+
+ pause
+ cmp dword ptr [rsi], WakeUpApPerMwaitLoop32 ; Use rsi for esi per compling in 64-bits mode
+ jnz CheckRunSignal32
+
+ cli
+ mov eax, esp ; Set Monitor Address
+ xor ecx, ecx
+ xor edx, edx
+ DB 0fh, 1, 0c8h ; MONITOR
+ mov eax, dword ptr [rsp + 56] ; Mwait Target C-State per eax[7:4]
+ DB 0fh, 1, 0c9h ; MWAIT
+
+
+CheckRunSignal32::
+
+ cmp dword ptr [rsp], ebx ; Check if run signal correct?
+ jnz CheckWakeUpManner32 ; Unknown break, go checking run manner
+
+ db 0Fh, 20h, 0E0h ; mov eax, cr4
+ db 0Ch, 20h ; or al, 20h ; Set PAE=1 in CR4 bit 5
+ db 0Fh, 22h, 0E0h ; mov cr4, eax
+
+ db 0B9h
+ dd 0C0000080h ; mov ecx, 0c0000080h ; EFER MSR number.
+ db 0Fh, 32h ; rdmsr ; Read EFER.
+ db 0Fh, 0BAh, 0E8h, 08h ; bts eax, 8 ; Set LME=1.
+ db 0Fh, 30h ; wrmsr ; Write EFER.
+
+ db 0Fh, 20h, 0C0h ; mov eax, cr0 ; Read CR0.
+ db 0Fh, 0BAh, 0E8h, 1Fh ; bts eax, 31 ; Set PG=1.
+ db 0Fh, 22h, 0C0h ; mov cr0, eax ; Write CR0.
+
+ db 67h, 0EAh ; far jump back to 64-bits long mode
+
+RunLoopAndMwaitLoop64Jump:
+
+ dd 0h ; 32-bit offset
+ dw 38h ; 16-bit selector
+
+RunLoopAndMwaitLoop64::
+
+ mov ax, 30h
+ mov ds, ax
+ mov ss, ax
+
+ jmp WakeUpThisAp64
+
+RendezvousFunnelProc ENDP
+RendezvousFunnelProcEnd::
+
+
+;-------------------------------------------------------------------------------------
+; AsmGetAddressMap (&AddressMap);
+;-------------------------------------------------------------------------------------
+AsmGetAddressMap PROC PUBLIC
+
+ mov rax, offset RendezvousFunnelProcStart
+ mov qword ptr [rcx], rax
+ mov qword ptr [rcx+8h], NemInit - RendezvousFunnelProcStart
+ mov qword ptr [rcx+10h], FLAT32_JUMP - RendezvousFunnelProcStart
+ mov qword ptr [rcx+18h], LongModeStart - RendezvousFunnelProcStart
+ mov qword ptr [rcx+20h], LONG_JUMP - RendezvousFunnelProcStart
+ mov qword ptr [rcx+28h], RendezvousFunnelProcEnd - RendezvousFunnelProcStart
+
+ ret
+
+AsmGetAddressMap ENDP
+
+AsmGetGdtrIdtr PROC PUBLIC
+
+ sgdt GdtDesc
+ lea rax, GdtDesc
+ mov [rcx], rax
+
+ sidt IdtDesc
+ lea rax, IdtDesc
+ mov [rdx], rax
+
+ ret
+
+AsmGetGdtrIdtr ENDP
+
+AsmGetCr3 PROC PUBLIC
+
+ mov rax, cr3
+ ret
+
+AsmGetCr3 ENDP
+
+
+AsmAcquireMPLock PROC PUBLIC
+
+ mov al, NotVacantFlag
+TryGetLock:
+ xchg al, byte ptr [rcx]
+ cmp al, VacantFlag
+ jz LockObtained
+
+ pause
+ jmp TryGetLock
+
+LockObtained:
+ ret
+
+AsmAcquireMPLock ENDP
+
+AsmReleaseMPLock PROC PUBLIC
+
+ mov al, VacantFlag
+ xchg al, byte ptr [rcx]
+
+ ret
+
+AsmReleaseMPLock 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 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.
+
+ push rax
+ push rbx
+ push rcx
+ push rdx
+ push rsi
+ push rdi
+ push rbp
+ push r8
+ push r9
+ push r10
+ push r11
+ push r12
+ push r13
+ push r14
+ push r15
+
+ mov rax, cr0
+ push rax
+
+ mov rax, cr4
+ push rax
+
+ ; rsi contains MyInfo pointer
+ mov rsi, rcx
+
+ ; rdi contains OthersInfo pointer
+ mov rdi, rdx
+
+ ;Store EFLAGS, GDTR and IDTR regiter to stack
+ pushfq
+ sgdt fword ptr [rsi + 16]
+ sidt fword ptr [rsi + 26]
+
+ ; Store the its StackPointer
+ mov qword ptr [rsi + 8], rsp
+
+ ; update its switch state to STORED
+ mov al, NotVacantFlag
+TryLock1:
+ db 0f0h ; opcode for lock instruction
+ xchg al, byte ptr [rsi]
+ cmp al, VacantFlag
+ jz LockObtained1
+ pause
+ jmp TryLock1
+
+LockObtained1:
+ mov byte ptr [rsi + 1], CPU_SWITCH_STATE_STORED
+ db 0f0h ; opcode for lock instruction
+ xchg al, byte ptr [rsi]
+
+WaitForOtherStored::
+ ; wait until the other CPU finish storing its state
+ mov al, NotVacantFlag
+TryLock2:
+ db 0f0h ; opcode for lock instruction
+ xchg al, byte ptr [rdi]
+ cmp al, VacantFlag
+ jz LockObtained2
+ PAUSE32
+ jmp TryLock2
+
+LockObtained2:
+ mov bl, byte ptr [rdi + 1]
+ db 0f0h ; opcode for lock instruction
+ xchg al, byte ptr [rdi]
+ cmp bl, CPU_SWITCH_STATE_STORED
+ jb WaitForOtherStored
+
+ ; Since another CPU already stored its state, load them
+ ; load GDTR value
+ lgdt fword ptr [rdi + 16]
+
+ ; load IDTR value
+ lidt fword ptr [rdi + 26]
+
+ ; load its future StackPointer
+ mov rsp, qword ptr [rdi + 8]
+
+ ; update its switch state to LOADED
+ mov al, NotVacantFlag
+TryLock3:
+ db 0f0h ; opcode for lock instruction
+ xchg al, byte ptr [rsi]
+ cmp al, VacantFlag
+ jz LockObtained3
+ PAUSE32
+ jmp TryLock3
+
+LockObtained3:
+ mov byte ptr [rsi+1], CPU_SWITCH_STATE_LOADED
+ db 0f0h ; opcode for lock instruction
+ xchg al, byte ptr [rsi]
+
+WaitForOtherLoaded::
+ ; wait until the other CPU finish loading new state,
+ ; otherwise the data in stack may corrupt
+ mov al, NotVacantFlag
+TryLock4:
+ db 0f0h ; opcode for lock instruction
+ xchg al, byte ptr [rdi]
+ cmp al, VacantFlag
+ jz LockObtained4
+ PAUSE32
+ jmp TryLock4
+
+LockObtained4:
+ mov bl, byte ptr [rdi+1]
+ db 0f0h ; opcode for lock instruction
+ xchg al, byte ptr [rdi]
+ cmp bl, CPU_SWITCH_STATE_LOADED
+ jb WaitForOtherLoaded
+
+ ; since the other CPU already get the data it want, leave this procedure
+ popfq
+
+ pop rax
+ mov cr4, rax
+
+ pop rax
+ mov cr0, rax
+
+ pop r15
+ pop r14
+ pop r13
+ pop r12
+ pop r11
+ pop r10
+ pop r9
+ pop r8
+ pop rbp
+ pop rdi
+ pop rsi
+ pop rdx
+ pop rcx
+ pop rbx
+ pop rax
+
+ ret
+AsmExchangeRole ENDP
+
+GdtDesc QWORD 0
+ WORD 0
+
+IdtDesc QWORD 0
+ WORD 0
+
+text ENDS
+
+END
diff --git a/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/CpuInit/x64/PlatformCpuLib.h b/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/CpuInit/x64/PlatformCpuLib.h
new file mode 100644
index 0000000000..33fc064199
--- /dev/null
+++ b/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/CpuInit/x64/PlatformCpuLib.h
@@ -0,0 +1,135 @@
+/** @file
+ Library functions that can be called in both PEI and DXE phase.
+
+ Copyright (c) 2004 - 2015, 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 _PLATFORM_CPU_LIB_H_
+#define _PLATFORM_CPU_LIB_H_
+
+UINTN
+CpuReadCr0 (
+ VOID
+ );
+
+VOID
+CpuWriteCr0 (
+ UINTN Value
+ );
+
+UINTN
+CpuReadCr3 (
+ VOID
+ );
+
+VOID
+CpuWriteCr3 (
+ UINTN Value
+ );
+
+UINT8
+CpuMemRead8 (
+ IN EFI_PHYSICAL_ADDRESS Address
+ );
+
+UINT16
+CpuMemRead16 (
+ IN EFI_PHYSICAL_ADDRESS Address
+ );
+
+UINT32
+CpuMemRead32 (
+ IN EFI_PHYSICAL_ADDRESS Address
+ );
+
+UINT64
+CpuMemRead64 (
+ IN EFI_PHYSICAL_ADDRESS Address
+ );
+
+VOID
+CpuMemWrite8 (
+ IN EFI_PHYSICAL_ADDRESS Address,
+ IN UINT8 Data
+ );
+
+VOID
+CpuMemWrite16 (
+ IN EFI_PHYSICAL_ADDRESS Address,
+ IN UINT16 Data
+ );
+
+VOID
+CpuMemWrite32 (
+ IN EFI_PHYSICAL_ADDRESS Address,
+ IN UINT32 Data
+ );
+
+VOID
+CpuMemWrite64 (
+ IN EFI_PHYSICAL_ADDRESS Address,
+ IN UINT64 Data
+ );
+
+UINTN
+CpuSetPower2 (
+ IN UINTN Input
+ );
+
+UINT64
+CpuReadTsc (
+ VOID
+ );
+
+VOID
+CpuSwitchStacks (
+ IN UINTN EntryPoint,
+ IN UINTN Parameter,
+ IN UINTN NewStack,
+ IN UINTN NewBsp
+ );
+
+VOID
+CpuSwitchStacks2Args (
+ IN UINTN EntryPoint,
+ IN UINTN Parameter1,
+ IN UINTN Parameter2,
+ IN UINTN NewStack,
+ IN UINTN NewBsp
+ );
+
+UINT16
+CpuCodeSegment (
+ VOID
+ );
+
+VOID
+CpuBreak (
+ VOID
+ );
+
+VOID
+CpuLoadGlobalDescriptorTable (
+ VOID *Table16ByteAligned
+ );
+
+VOID
+CpuInitSelectors (
+ VOID
+ );
+
+VOID
+CpuLoadInterruptDescriptorTable (
+ VOID *Table16ByteAligned
+ );
+
+#endif
diff --git a/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/CpuInit/x64/ProcessorDef.h b/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/CpuInit/x64/ProcessorDef.h
new file mode 100644
index 0000000000..328a12fdd0
--- /dev/null
+++ b/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/CpuInit/x64/ProcessorDef.h
@@ -0,0 +1,57 @@
+/** @file
+ Definition for EM64T processor.
+
+ Copyright (c) 2004 - 2015, 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 _PROCESSOR_DEF_H
+#define _PROCESSOR_DEF_H
+
+#pragma pack(1)
+/**
+ @todo @todo add structure description
+
+**/
+typedef struct {
+ UINT16 Offset15To0;
+ UINT16 SegmentSelector;
+ UINT16 Attributes;
+ UINT16 Offset31To16;
+ UINT32 Offset63To32;
+ UINT32 Reserved;
+} INTERRUPT_GATE_DESCRIPTOR;
+
+#pragma pack()
+/**
+ @todo @todo add structure description
+
+**/
+typedef struct {
+ UINT8 *RendezvousFunnelAddress;
+ UINTN PModeEntryOffset;
+ UINTN FlatJumpOffset;
+ UINTN LModeEntryOffset;
+ UINTN LongJumpOffset;
+ UINTN Size;
+} MP_ASSEMBLY_ADDRESS_MAP;
+/**
+ Get address map of RendezvousFunnelProc.
+
+ @param[out] AddressMap - Output buffer for address map information
+
+**/
+VOID
+AsmGetAddressMap (
+ OUT MP_ASSEMBLY_ADDRESS_MAP *AddressMap
+ );
+
+#endif
diff --git a/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/CpuInit/x64/VirtualMemory.h b/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/CpuInit/x64/VirtualMemory.h
new file mode 100644
index 0000000000..e8ef0afc82
--- /dev/null
+++ b/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/CpuInit/x64/VirtualMemory.h
@@ -0,0 +1,147 @@
+/** @file
+ x64 Long Mode Virtual Memory Management Definitions.
+
+ References:
+ 1) IA-32 Intel(R) Atchitecture Software Developer's Manual Volume 1:Basic Architecture, Intel
+ 2) IA-32 Intel(R) Atchitecture Software Developer's Manual Volume 2:Instruction Set Reference, Intel
+ 3) IA-32 Intel(R) Atchitecture Software Developer's Manual Volume 3:System Programmer's Guide, Intel
+ 4) AMD64 Architecture Programmer's Manual Volume 2: System Programming
+
+ Copyright (c) 2004 - 2015, 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 _VIRTUAL_MEMORY_H_
+#define _VIRTUAL_MEMORY_H_
+
+#pragma pack(1)
+
+/**
+ Page-Map Level-4 Offset (PML4) and
+///Page-Directory-Pointer Offset (PDPE) entries 4K & 2MB
+
+**/
+typedef union {
+ struct {
+ UINT64 Present:1; // 0 = Not present in memory, 1 = Present in memory
+ UINT64 ReadWrite:1; // 0 = Read-Only, 1= Read/Write
+ UINT64 UserSupervisor:1; // 0 = Supervisor, 1=User
+ UINT64 WriteThrough:1; // 0 = Write-Back caching, 1=Write-Through caching
+ UINT64 CacheDisabled:1; // 0 = Cached, 1=Non-Cached
+ UINT64 Accessed:1; // 0 = Not accessed, 1 = Accessed (set by CPU)
+ UINT64 Reserved:1; // Reserved
+ UINT64 MustBeZero:2; // Must Be Zero
+ UINT64 Available:3; // Available for use by system software
+ UINT64 PageTableBaseAddress:40; // Page Table Base Address
+ UINT64 AvabilableHigh:11; // Available for use by system software
+ UINT64 Nx:1; // No Execute bit
+ } Bits;
+ UINT64 Uint64;
+} x64_PAGE_MAP_AND_DIRECTORY_POINTER_2MB_4K;
+
+/**
+ Page-Directory Offset 4K
+
+**/
+typedef union {
+ struct {
+ UINT64 Present:1; // 0 = Not present in memory, 1 = Present in memory
+ UINT64 ReadWrite:1; // 0 = Read-Only, 1= Read/Write
+ UINT64 UserSupervisor:1; // 0 = Supervisor, 1=User
+ UINT64 WriteThrough:1; // 0 = Write-Back caching, 1=Write-Through caching
+ UINT64 CacheDisabled:1; // 0 = Cached, 1=Non-Cached
+ UINT64 Accessed:1; // 0 = Not accessed, 1 = Accessed (set by CPU)
+ UINT64 Reserved:1; // Reserved
+ UINT64 MustBeZero:1; // Must Be Zero
+ UINT64 Reserved2:1; // Reserved
+ UINT64 Available:3; // Available for use by system software
+ UINT64 PageTableBaseAddress:40; // Page Table Base Address
+ UINT64 AvabilableHigh:11; // Available for use by system software
+ UINT64 Nx:1; // No Execute bit
+ } Bits;
+ UINT64 Uint64;
+} x64_PAGE_DIRECTORY_ENTRY_4K;
+
+/**
+ Page Table Entry 4K.
+
+**/
+typedef union {
+ struct {
+ UINT64 Present:1; // 0 = Not present in memory, 1 = Present in memory
+ UINT64 ReadWrite:1; // 0 = Read-Only, 1= Read/Write
+ UINT64 UserSupervisor:1; // 0 = Supervisor, 1=User
+ UINT64 WriteThrough:1; // 0 = Write-Back caching, 1=Write-Through caching
+ UINT64 CacheDisabled:1; // 0 = Cached, 1=Non-Cached
+ UINT64 Accessed:1; // 0 = Not accessed, 1 = Accessed (set by CPU)
+ UINT64 Dirty:1; // 0 = Not Dirty, 1 = written by processor on access to page
+ UINT64 PAT:1; // 0 = Ignore Page Attribute Table
+ UINT64 Global:1; // 0 = Not global page, 1 = global page TLB not cleared on CR3 write
+ UINT64 Available:3; // Available for use by system software
+ UINT64 PageTableBaseAddress:40; // Page Table Base Address
+ UINT64 AvabilableHigh:11; // Available for use by system software
+ UINT64 Nx:1; // 0 = Execute Code, 1 = No Code Execution
+ } Bits;
+ UINT64 Uint64;
+} x64_PAGE_TABLE_ENTRY_4K;
+
+/**
+ Page Table Entry 2MB.
+
+**/
+typedef union {
+ struct {
+ UINT64 Present:1; // 0 = Not present in memory, 1 = Present in memory
+ UINT64 ReadWrite:1; // 0 = Read-Only, 1= Read/Write
+ UINT64 UserSupervisor:1; // 0 = Supervisor, 1=User
+ UINT64 WriteThrough:1; // 0 = Write-Back caching, 1=Write-Through caching
+ UINT64 CacheDisabled:1; // 0 = Cached, 1=Non-Cached
+ UINT64 Accessed:1; // 0 = Not accessed, 1 = Accessed (set by CPU)
+ UINT64 Dirty:1; // 0 = Not Dirty, 1 = written by processor on access to page
+ UINT64 MustBe1:1; // Must be 1
+ UINT64 Global:1; // 0 = Not global page, 1 = global page TLB not cleared on CR3 write
+ UINT64 Available:3; // Available for use by system software
+ UINT64 PAT:1; //
+ UINT64 MustBeZero:8; // Must be zero;
+ UINT64 PageTableBaseAddress:31; // Page Table Base Address
+ UINT64 AvabilableHigh:11; // Available for use by system software
+ UINT64 Nx:1; // 0 = Execute Code, 1 = No Code Execution
+ } Bits;
+ UINT64 Uint64;
+} x64_PAGE_TABLE_ENTRY_2M;
+/**
+ @todo Add union description
+
+**/
+typedef union {
+ UINT64 Present:1; // 0 = Not present in memory, 1 = Present in memory
+ UINT64 ReadWrite:1; // 0 = Read-Only, 1= Read/Write
+ UINT64 UserSupervisor:1; // 0 = Supervisor, 1=User
+ UINT64 WriteThrough:1; // 0 = Write-Back caching, 1=Write-Through caching
+ UINT64 CacheDisabled:1; // 0 = Cached, 1=Non-Cached
+ UINT64 Accessed:1; // 0 = Not accessed, 1 = Accessed (set by CPU)
+ UINT64 Dirty:1; // 0 = Not Dirty, 1 = written by processor on access to page
+ UINT64 Reserved:57;
+} x64_PAGE_TABLE_ENTRY_COMMON;
+/**
+ @todo Add union description
+
+**/
+typedef union {
+ x64_PAGE_TABLE_ENTRY_4K Page4k;
+ x64_PAGE_TABLE_ENTRY_2M Page2Mb;
+ x64_PAGE_TABLE_ENTRY_COMMON Common;
+} x64_PAGE_TABLE_ENTRY;
+
+
+#pragma pack()
+
+#endif
diff --git a/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/Include/AcpiCpuData.h b/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/Include/AcpiCpuData.h
new file mode 100644
index 0000000000..fb3f069dd2
--- /dev/null
+++ b/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/Include/AcpiCpuData.h
@@ -0,0 +1,35 @@
+/** @file
+ Definitions for CPU S3 data.
+
+ Copyright (c) 2011 - 2015, 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 _ACPI_CPU_DATA_H_
+#define _ACPI_CPU_DATA_H_
+
+typedef struct {
+ BOOLEAN APState;
+ EFI_PHYSICAL_ADDRESS StartupVector;
+ EFI_PHYSICAL_ADDRESS GdtrProfile;
+ EFI_PHYSICAL_ADDRESS IdtrProfile;
+ EFI_PHYSICAL_ADDRESS StackAddress;
+ UINT32 StackSize;
+ UINT32 NumberOfCpus;
+ EFI_PHYSICAL_ADDRESS MtrrTable;
+ EFI_PHYSICAL_ADDRESS PreSmmInitRegisterTable;
+ EFI_PHYSICAL_ADDRESS RegisterTable;
+ EFI_PHYSICAL_ADDRESS ApMachineCheckHandlerBase;
+ UINT32 ApMachineCheckHandlerSize;
+} ACPI_CPU_DATA;
+
+#endif
+
diff --git a/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/Include/CpuHotPlugData.h b/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/Include/CpuHotPlugData.h
new file mode 100644
index 0000000000..eb71a98877
--- /dev/null
+++ b/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/Include/CpuHotPlugData.h
@@ -0,0 +1,35 @@
+/** @file
+ Definition for a struture sharing information for CPU hot plug.
+
+ Copyright (c) 2011 - 2015, 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 _CPU_HOT_PLUG_DATA_H_
+#define _CPU_HOT_PLUG_DATA_H_
+
+#define CPU_HOT_PLUG_DATA_REVISION_1 0x00000001
+
+typedef struct {
+ UINT32 Revision; // Used for version identification for this structure
+ UINT32 ArrayLength; // The entries number of the following ApicId array and SmBase array
+ //
+ // Data required for SMBASE relocation
+ //
+ UINT64 *ApicId; // Pointer to ApicId array
+ UINTN *SmBase; // Pointer to SmBase array
+ UINT32 IEDBase;
+ UINT32 SmrrBase;
+ UINT32 SmrrSize;
+} CPU_HOT_PLUG_DATA;
+
+#endif
+
diff --git a/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/Include/Library/CpuConfigLib.h b/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/Include/Library/CpuConfigLib.h
new file mode 100644
index 0000000000..bbe631ed07
--- /dev/null
+++ b/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/Include/Library/CpuConfigLib.h
@@ -0,0 +1,686 @@
+/** @file
+ Public include file for the CPU Configuration Library
+
+ Copyright (c) 2006 - 2015, 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 _CPU_CONFIG_LIB_H_
+#define _CPU_CONFIG_LIB_H_
+
+#include <Protocol/MpService.h>
+
+//
+// Bits definition of PcdProcessorFeatureUserConfiguration,
+// PcdProcessorFeatureCapability, and PcdProcessorFeatureSetting
+//
+#define PCD_CPU_HT_BIT 0x00000001
+#define PCD_CPU_CMP_BIT 0x00000002
+#define PCD_CPU_L2_CACHE_BIT 0x00000004
+#define PCD_CPU_L2_ECC_BIT 0x00000008
+#define PCD_CPU_VT_BIT 0x00000010
+#define PCD_CPU_LT_BIT 0x00000020
+#define PCD_CPU_EXECUTE_DISABLE_BIT 0x00000040
+#define PCD_CPU_L3_CACHE_BIT 0x00000080
+#define PCD_CPU_MAX_CPUID_VALUE_LIMIT_BIT 0x00000100
+#define PCD_CPU_FAST_STRING_BIT 0x00000200
+#define PCD_CPU_FERR_SIGNAL_BREAK_BIT 0x00000400
+#define PCD_CPU_PECI_BIT 0x00000800
+#define PCD_CPU_HARDWARE_PREFETCHER_BIT 0x00001000
+#define PCD_CPU_ADJACENT_CACHE_LINE_PREFETCH_BIT 0x00002000
+#define PCD_CPU_DCU_PREFETCHER_BIT 0x00004000
+#define PCD_CPU_IP_PREFETCHER_BIT 0x00008000
+#define PCD_CPU_MACHINE_CHECK_BIT 0x00010000
+#define PCD_CPU_THERMAL_MANAGEMENT_BIT 0x00040000
+#define PCD_CPU_EIST_BIT 0x00080000
+#define PCD_CPU_C1E_BIT 0x00200000
+#define PCD_CPU_C2E_BIT 0x00400000
+#define PCD_CPU_C3E_BIT 0x00800000
+#define PCD_CPU_C4E_BIT 0x01000000
+#define PCD_CPU_HARD_C4E_BIT 0x02000000
+#define PCD_CPU_DEEP_C4_BIT 0x04000000
+#define PCD_CPU_A20M_DISABLE_BIT 0x08000000
+#define PCD_CPU_MONITOR_MWAIT_BIT 0x10000000
+#define PCD_CPU_TSTATE_BIT 0x20000000
+#define PCD_CPU_TURBO_MODE_BIT 0x80000000
+
+//
+// Bits definition of PcdProcessorFeatureUserConfigurationEx1,
+// PcdProcessorFeatureCapabilityEx1, and PcdProcessorFeatureSettingEx1
+//
+#define PCD_CPU_C_STATE_BIT 0x00000001
+#define PCD_CPU_C1_AUTO_DEMOTION_BIT 0x00000002
+#define PCD_CPU_C3_AUTO_DEMOTION_BIT 0x00000004
+#define PCD_CPU_MLC_STREAMER_PREFETCHER_BIT 0x00000008
+#define PCD_CPU_MLC_SPATIAL_PREFETCHER_BIT 0x00000010
+#define PCD_CPU_THREE_STRIKE_COUNTER_BIT 0x00000020
+#define PCD_CPU_ENERGY_PERFORMANCE_BIAS_BIT 0x00000040
+#define PCD_CPU_DCA_BIT 0x00000080
+#define PCD_CPU_X2APIC_BIT 0x00000100
+#define PCD_CPU_AES_BIT 0x00000200
+#define PCD_CPU_APIC_TPR_UPDATE_MESSAGE_BIT 0x00000400
+#define PCD_CPU_SOCKET_ID_REASSIGNMENT_BIT 0x00000800
+#define PCD_CPU_PECI_DOWNSTREAM_WRITE_BIT 0x00001000
+
+//
+// Value definition for PcdCpuCallbackSignal
+//
+#define CPU_BYPASS_SIGNAL 0x00000000
+#define CPU_DATA_COLLECTION_SIGNAL 0x00000001
+#define CPU_PROCESSOR_FEATURE_LIST_CONFIG_SIGNAL 0x00000002
+#define CPU_REGISTER_TABLE_TRANSLATION_SIGNAL 0x00000003
+#define CPU_PROCESSOR_SETTING_SIGNAL 0x00000004
+#define CPU_PROCESSOR_SETTING_END_SIGNAL 0x00000005
+
+typedef struct {
+ UINT32 RegEax;
+ UINT32 RegEbx;
+ UINT32 RegEcx;
+ UINT32 RegEdx;
+} EFI_CPUID_REGISTER;
+
+//
+// Enumeration of processor features
+//
+typedef enum {
+ Ht,
+ Cmp,
+ Vt,
+ ExecuteDisableBit,
+ L3Cache,
+ MaxCpuidValueLimit,
+ FastString,
+ FerrSignalBreak,
+ Peci,
+ HardwarePrefetcher,
+ AdjacentCacheLinePrefetch,
+ DcuPrefetcher,
+ IpPrefetcher,
+ ThermalManagement,
+ Eist,
+ BiDirectionalProchot,
+ Forcepr,
+ C1e,
+ C2e,
+ C3e,
+ C4e,
+ HardC4e,
+ DeepC4,
+ Microcode,
+ Microcode2,
+ MachineCheck,
+ GateA20MDisable,
+ MonitorMwait,
+ TState,
+ TurboMode,
+ CState,
+ C1AutoDemotion,
+ C3AutoDemotion,
+ MlcStreamerPrefetcher,
+ MlcSpatialPrefetcher,
+ ThreeStrikeCounter,
+ EnergyPerformanceBias,
+ Dca,
+ X2Apic,
+ Aes,
+ ApicTprUpdateMessage,
+ TccActivation,
+ PeciDownstreamWrite,
+ CpuFeatureMaximum
+} CPU_FEATURE_ID;
+
+//
+// Structure for collected processor feature capability,
+// and feature-specific attribute.
+//
+typedef struct {
+ BOOLEAN Capability;
+ VOID *Attribute;
+} CPU_FEATURE_DATA;
+
+//
+// Structure for collected CPUID data.
+//
+typedef struct {
+ EFI_CPUID_REGISTER *CpuIdLeaf;
+ UINTN NumberOfBasicCpuidLeafs;
+ UINTN NumberOfExtendedCpuidLeafs;
+ UINTN NumberOfCacheAndTlbCpuidLeafs;
+ UINTN NumberOfDeterministicCacheParametersCpuidLeafs;
+ UINTN NumberOfExtendedTopologyEnumerationLeafs;
+} CPU_CPUID_DATA;
+
+typedef struct {
+ UINTN Ratio;
+ UINTN Vid;
+ UINTN Power;
+ UINTN TransitionLatency;
+ UINTN BusMasterLatency;
+} FVID_ENTRY;
+
+//
+// Miscellaneous processor data
+//
+typedef struct {
+ //
+ // Local Apic Data
+ //
+ UINT32 InitialApicID; ///< Initial APIC ID
+ UINT32 ApicID; ///< Current APIC ID
+ EFI_PHYSICAL_ADDRESS ApicBase;
+ UINT32 ApicVersion;
+ //
+ // Frequency data
+ //
+ UINTN IntendedFsbFrequency;
+ UINTN ActualFsbFrequency;
+ BOOLEAN FrequencyLocked;
+ UINTN MaxCoreToBusRatio;
+ UINTN MinCoreToBusRatio;
+ UINTN MaxTurboRatio;
+ UINTN MaxVid;
+ UINTN MinVid;
+ UINTN PackageTdp;
+ UINTN CoreTdp;
+ UINTN NumberOfPStates;
+ FVID_ENTRY *FvidTable;
+ //
+ // Config TDP data
+ //
+ UINTN PkgMinPwrLvl1;
+ UINTN PkgMaxPwrLvl1;
+ UINTN ConfigTDPLvl1Ratio;
+ UINTN PkgTDPLvl1;
+ UINTN PkgMinPwrLvl2;
+ UINTN PkgMaxPwrLvl2;
+ UINTN ConfigTDPLvl2Ratio;
+ UINTN PkgTDPLvl2;
+
+ //
+ // Other data
+ //
+ UINT32 PlatformRequirement;
+ UINT64 HealthData;
+ UINT32 MicrocodeRevision;
+} CPU_MISC_DATA;
+
+//
+// Structure for all collected processor data
+//
+typedef struct {
+ CPU_CPUID_DATA CpuidData;
+ EFI_CPU_PHYSICAL_LOCATION ProcessorLocation;
+ CPU_MISC_DATA CpuMiscData;
+ CPU_FEATURE_DATA FeatureData[CpuFeatureMaximum];
+ UINT8 PackageIdBitOffset;
+ BOOLEAN PackageBsp;
+} CPU_COLLECTED_DATA;
+
+#define GET_CPU_MISC_DATA(ProcessorNumber, Item) \
+ ((mCpuConfigLibConfigConextBuffer->CollectedDataBuffer[ProcessorNumber]).CpuMiscData.Item)
+
+//
+// Signature for feature list entry
+//
+#define EFI_CPU_FEATURE_ENTRY_SIGNATURE SIGNATURE_32 ('C', 'f', 't', 'r')
+
+//
+// Node of processor feature list
+//
+typedef struct {
+ UINT32 Signature;
+ CPU_FEATURE_ID FeatureID;
+ VOID *Attribute;
+ LIST_ENTRY Link;
+} CPU_FEATURE_ENTRY;
+
+#define CPU_FEATURE_ENTRY_FROM_LINK(link) CR (link, CPU_FEATURE_ENTRY, Link, EFI_CPU_FEATURE_ENTRY_SIGNATURE)
+
+//
+// Register types in register table
+//
+typedef enum _REGISTER_TYPE {
+ Msr,
+ ControlRegister,
+ MemoryMapped,
+ CacheControl
+} REGISTER_TYPE;
+
+//
+// Element of register table entry
+//
+typedef struct {
+ REGISTER_TYPE RegisterType;
+ UINT32 Index;
+ UINT8 ValidBitStart;
+ UINT8 ValidBitLength;
+ UINT64 Value;
+} CPU_REGISTER_TABLE_ENTRY;
+
+//
+// Register table definition, including current table length,
+// allocated size of this table, and pointer to the list of table entries.
+//
+typedef struct {
+ UINT32 TableLength;
+ UINT32 NumberBeforeReset;
+ UINT32 AllocatedSize;
+ UINT32 InitialApicId;
+ CPU_REGISTER_TABLE_ENTRY *RegisterTableEntry;
+} CPU_REGISTER_TABLE;
+
+//
+// Definition of Processor Configuration Context Buffer
+//
+typedef struct {
+ UINTN NumberOfProcessors;
+ UINTN BspNumber;
+ CPU_COLLECTED_DATA *CollectedDataBuffer;
+ LIST_ENTRY *FeatureLinkListEntry;
+ CPU_REGISTER_TABLE *PreSmmInitRegisterTable;
+ CPU_REGISTER_TABLE *RegisterTable;
+ UINTN *SettingSequence;
+} CPU_CONFIG_CONTEXT_BUFFER;
+
+//
+// Structure conveying socket ID configuration information.
+//
+typedef struct {
+ UINT8 DefaultSocketId;
+ UINT8 NewSocketId;
+} CPU_SOCKET_ID_INFO;
+
+extern CPU_CONFIG_CONTEXT_BUFFER *mCpuConfigLibConfigConextBuffer;
+
+/**
+ Set feature capability and related attribute.
+
+ This function sets the feature capability and its attribute.
+
+ @param ProcessorNumber Handle number of specified logical processor
+ @param FeatureID The ID of the feature.
+ @param Attribute Feature-specific data.
+
+**/
+VOID
+EFIAPI
+SetProcessorFeatureCapability (
+ IN UINTN ProcessorNumber,
+ IN CPU_FEATURE_ID FeatureID,
+ IN VOID *Attribute
+ );
+
+/**
+ Clears feature capability and related attribute.
+
+ This function clears the feature capability and its attribute.
+
+ @param ProcessorNumber Handle number of specified logical processor
+ @param FeatureID The ID of the feature.
+
+**/
+VOID
+EFIAPI
+ClearProcessorFeatureCapability (
+ IN UINTN ProcessorNumber,
+ IN CPU_FEATURE_ID FeatureID
+ );
+
+/**
+ Get feature capability and related attribute.
+
+ This function gets the feature capability and its attribute.
+
+ @param ProcessorNumber Handle number of specified logical processor
+ @param FeatureID The ID of the feature.
+ @param Attribute Pointer to the output feature-specific data.
+
+ @retval TRUE The feature is supported by the processor
+ @retval FALSE The feature is not supported by the processor
+
+**/
+BOOLEAN
+EFIAPI
+GetProcessorFeatureCapability (
+ IN UINTN ProcessorNumber,
+ IN CPU_FEATURE_ID FeatureID,
+ OUT VOID **Attribute OPTIONAL
+ );
+
+typedef enum {
+ BasicCpuidLeaf,
+ ExtendedCpuidLeaf,
+ CacheAndTlbCpuidLeafs,
+ DeterministicCacheParametersCpuidLeafs,
+ ExtendedTopologyEnumerationCpuidLeafs
+} CPUID_TYPE;
+
+/**
+ Get the number of CPUID leafs of various types.
+
+ This function get the number of CPUID leafs of various types.
+
+ @param ProcessorNumber Handle number of specified logical processor
+ @param CpuidType The type of the CPU id.
+
+ @return Maximal index of CPUID instruction for basic leafs.
+
+**/
+UINTN
+EFIAPI
+GetNumberOfCpuidLeafs (
+ IN UINTN ProcessorNumber,
+ IN CPUID_TYPE CpuidType
+ );
+
+/**
+ Get the pointer to specified CPUID leaf.
+
+ This function gets the pointer to specified CPUID leaf.
+
+ @param ProcessorNumber Handle number of specified logical processor
+ @param Index Index of the CPUID leaf.
+
+ @return Pointer to specified CPUID leaf
+
+**/
+EFI_CPUID_REGISTER*
+EFIAPI
+GetProcessorCpuid (
+ IN UINTN ProcessorNumber,
+ IN UINTN Index
+ );
+
+/**
+ Get the pointer to specified CPUID leaf of cache and TLB parameters.
+
+ This function gets the pointer to specified CPUID leaf of cache and TLB parameters.
+
+ @param ProcessorNumber Handle number of specified logical processor
+ @param Index Index of the CPUID leaf.
+
+ @return Pointer to specified CPUID leaf.
+
+**/
+EFI_CPUID_REGISTER*
+EFIAPI
+GetCacheAndTlbCpuidLeaf (
+ IN UINTN ProcessorNumber,
+ IN UINTN Index
+ );
+
+/**
+ Get the pointer to specified CPUID leaf of deterministic cache parameters.
+
+ This function gets the pointer to specified CPUID leaf of deterministic cache parameters.
+
+ @param ProcessorNumber Handle number of specified logical processor
+ @param Index Index of the CPUID leaf.
+
+ @return Pointer to specified CPUID leaf.
+
+**/
+EFI_CPUID_REGISTER*
+EFIAPI
+GetDeterministicCacheParametersCpuidLeaf (
+ IN UINTN ProcessorNumber,
+ IN UINTN Index
+ );
+
+/**
+ Get the pointer to specified CPUID leaf of Extended Topology Enumeration.
+
+ This function gets the pointer to specified CPUID leaf of Extended Topology Enumeration.
+
+ @param ProcessorNumber Handle number of specified logical processor.
+ @param Index Index of the CPUID leaf.
+
+ @return Pointer to specified CPUID leaf.
+
+**/
+EFI_CPUID_REGISTER*
+EFIAPI
+GetExtendedTopologyEnumerationCpuidLeafs (
+ IN UINTN ProcessorNumber,
+ IN UINTN Index
+ );
+
+/**
+ Get the version information of specified logical processor.
+
+ This function gets the version information of specified logical processor,
+ including family ID, model ID, stepping ID and processor type.
+
+ @param ProcessorNumber Handle number of specified logical processor
+ @param DisplayedFamily Pointer to family ID for output
+ @param DisplayedModel Pointer to model ID for output
+ @param SteppingId Pointer to stepping ID for output
+ @param ProcessorType Pointer to processor type for output
+
+**/
+VOID
+EFIAPI
+GetProcessorVersionInfo (
+ IN UINTN ProcessorNumber,
+ OUT UINT32 *DisplayedFamily OPTIONAL,
+ OUT UINT32 *DisplayedModel OPTIONAL,
+ OUT UINT32 *SteppingId OPTIONAL,
+ OUT UINT32 *ProcessorType OPTIONAL
+ );
+
+/**
+ Get initial local APIC ID of specified logical processor
+
+ This function gets initial local APIC ID of specified logical processor.
+
+ @param ProcessorNumber Handle number of specified logical processor
+
+ @return Initial local APIC ID of specified logical processor
+
+**/
+UINT32
+EFIAPI
+GetInitialLocalApicId (
+ UINTN ProcessorNumber
+ );
+
+/**
+ Get the location of specified processor.
+
+ This function gets the location of specified processor, including
+ package number, core number within package, thread number within core.
+
+ @param ProcessorNumber Handle number of specified logical processor.
+ @param PackageNumber Pointer to the output package number.
+ @param CoreNumber Pointer to the output core number.
+ @param ThreadNumber Pointer to the output thread number.
+
+**/
+VOID
+EFIAPI
+GetProcessorLocation (
+ IN UINTN ProcessorNumber,
+ OUT UINT32 *PackageNumber OPTIONAL,
+ OUT UINT32 *CoreNumber OPTIONAL,
+ OUT UINT32 *ThreadNumber OPTIONAL
+ );
+
+/**
+ Get the Feature entry at specified position in a feature list.
+
+ This function gets the Feature entry at specified position in a feature list.
+
+ @param ProcessorNumber Handle number of specified logical processor
+ @param FeatureIndex The index of the node in feature list.
+ @param Attribute Pointer to output feature-specific attribute
+
+ @return Feature ID of specified feature. CpuFeatureMaximum means not found
+
+**/
+CPU_FEATURE_ID
+EFIAPI
+GetProcessorFeatureEntry (
+ IN UINTN ProcessorNumber,
+ IN UINTN FeatureIndex,
+ OUT VOID **Attribute OPTIONAL
+ );
+
+/**
+ Append a feature entry at the end of a feature list.
+
+ This function appends a feature entry at the end of a feature list.
+
+ @param ProcessorNumber Handle number of specified logical processor
+ @param FeatureID ID of the specified feature.
+ @param Attribute Feature-specific attribute.
+
+ @retval EFI_SUCCESS This function always return EFI_SUCCESS
+
+**/
+EFI_STATUS
+EFIAPI
+AppendProcessorFeatureIntoList (
+ IN UINTN ProcessorNumber,
+ IN CPU_FEATURE_ID FeatureID,
+ IN VOID *Attribute
+ );
+
+/**
+ Delete a feature entry in a feature list.
+
+ This function deletes a feature entry in a feature list.
+
+ @param ProcessorNumber Handle number of specified logical processor
+ @param FeatureIndex The index of the node in feature list.
+
+ @retval EFI_SUCCESS The feature node successfully removed.
+ @retval EFI_INVALID_PARAMETER Index surpasses the length of list.
+
+**/
+EFI_STATUS
+EFIAPI
+DeleteProcessorFeatureFromList (
+ IN UINTN ProcessorNumber,
+ IN UINTN FeatureIndex
+ );
+
+/**
+ Insert a feature entry into a feature list.
+
+ This function insert a feature entry into a feature list before a node specified by FeatureIndex.
+
+ @param ProcessorNumber Handle number of specified logical processor
+ @param FeatureIndex The index of the new node in feature list.
+ @param FeatureID ID of the specified feature.
+ @param Attribute Feature-specific attribute.
+
+ @retval EFI_SUCCESS The feature node successfully inserted.
+ @retval EFI_INVALID_PARAMETER Index surpasses the length of list.
+
+**/
+EFI_STATUS
+EFIAPI
+InsertProcessorFeatureIntoList (
+ IN UINTN ProcessorNumber,
+ IN UINTN FeatureIndex,
+ IN CPU_FEATURE_ID FeatureID,
+ IN VOID *Attribute
+ );
+
+/**
+ Add an entry in the post-SMM-init register table.
+
+ This function adds an entry in the post-SMM-init register table, with given register type,
+ register index, bit section and value.
+
+ @param ProcessorNumber Handle number of specified logical processor
+ @param RegisterType Type of the register to program
+ @param Index Index of the register to program
+ @param ValidBitStart Start of the bit section
+ @param ValidBitLength Length of the bit section
+ @param Value Value to write
+
+**/
+VOID
+EFIAPI
+WriteRegisterTable (
+ IN UINTN ProcessorNumber,
+ IN REGISTER_TYPE RegisterType,
+ IN UINT32 Index,
+ IN UINT8 ValidBitStart,
+ IN UINT8 ValidBitLength,
+ IN UINT64 Value
+ );
+
+/**
+ Add an entry in the pre-SMM-init register table.
+
+ This function adds an entry in the pre-SMM-init register table, with given register type,
+ register index, bit section and value.
+
+ @param ProcessorNumber Handle number of specified logical processor
+ @param RegisterType Type of the register to program
+ @param Index Index of the register to program
+ @param ValidBitStart Start of the bit section
+ @param ValidBitLength Length of the bit section
+ @param Value Value to write
+
+**/
+VOID
+EFIAPI
+WritePreSmmInitRegisterTable (
+ IN UINTN ProcessorNumber,
+ IN REGISTER_TYPE RegisterType,
+ IN UINT32 Index,
+ IN UINT8 ValidBitStart,
+ IN UINT8 ValidBitLength,
+ IN UINT64 Value
+ );
+
+/**
+ Set the sequence of processor setting.
+
+ This function sets the a processor setting at the position in
+ setting sequence specified by Index.
+
+ @param Index The zero-based index in the sequence.
+ @param ProcessorNumber Handle number of the processor to set.
+
+ @retval EFI_SUCCESS The sequence successfully modified.
+ @retval EFI_INVALID_PARAMETER Index surpasses the boundary of sequence.
+ @retval EFI_NOT_FOUND Processor specified by ProcessorNumber does not exist.
+
+**/
+EFI_STATUS
+SetSettingSequence (
+ IN UINTN Index,
+ IN UINTN ProcessorNumber
+ );
+
+/**
+ Set PcdCpuCallbackSignal, and then read the value back.
+
+ This function sets PCD entry PcdCpuCallbackSignal. If there is callback
+ function registered on it, the callback function will be triggered, and
+ it may change the value of PcdCpuCallbackSignal. This function then reads
+ the value of PcdCpuCallbackSignal back, the check whether it has been changed.
+
+ @param Value The value to set to PcdCpuCallbackSignal.
+
+ @return The value of PcdCpuCallbackSignal read back.
+
+**/
+UINT8
+SetAndReadCpuCallbackSignal (
+ IN UINT8 Value
+ );
+
+#endif
diff --git a/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/Include/Library/SmmCpuPlatformHookLib.h b/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/Include/Library/SmmCpuPlatformHookLib.h
new file mode 100644
index 0000000000..25d3299226
--- /dev/null
+++ b/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/Include/Library/SmmCpuPlatformHookLib.h
@@ -0,0 +1,107 @@
+/** @file
+ Public include file for the SMM CPU Platform Hook Library.
+
+ Copyright (c) 2010 - 2015, 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 __SMM_CPU_PLATFORM_HOOK_LIB_H__
+#define __SMM_CPU_PLATFORM_HOOK_LIB_H__
+
+/**
+ Checks if platform produces a valid SMI.
+
+ This function checks if platform produces a valid SMI. This function is
+ called at SMM entry to detect if this is a spurious SMI. This function
+ must be implemented in an MP safe way because it is called by multiple CPU
+ threads.
+
+ @retval TRUE There is a valid SMI
+ @retval FALSE There is no valid SMI
+
+**/
+BOOLEAN
+EFIAPI
+PlatformValidSmi (
+ VOID
+ );
+
+/**
+ Clears platform top level SMI status bit.
+
+ This function clears platform top level SMI status bit.
+
+ @retval TRUE The platform top level SMI status is cleared.
+ @retval FALSE The paltform top level SMI status cannot be cleared.
+
+**/
+BOOLEAN
+EFIAPI
+ClearTopLevelSmiStatus (
+ VOID
+ );
+
+/**
+ Performs platform specific way of SMM BSP election.
+
+ This function performs platform specific way of SMM BSP election.
+
+ @param[out] IsBsp Output parameter. TRUE: the CPU this function executes
+ on is elected to be the SMM BSP. FALSE: the CPU this
+ function executes on is to be SMM AP.
+
+ @retval EFI_SUCCESS The function executes successfully.
+ @retval EFI_NOT_READY The function does not determine whether this CPU should be
+ BSP or AP. This may occur if hardware init sequence to
+ enable the determination is yet to be done, or the function
+ chooses not to do BSP election and will let SMM CPU driver to
+ use its default BSP election process.
+ @retval EFI_DEVICE_ERROR The function cannot determine whether this CPU should be
+ BSP or AP due to hardware error.
+
+**/
+EFI_STATUS
+EFIAPI
+PlatformSmmBspElection (
+ OUT BOOLEAN *IsBsp
+ );
+
+typedef enum {
+ SmmPageSize4K,
+ SmmPageSize2M,
+ SmmPageSize1G,
+ MaxSmmPageSizeType
+} SMM_PAGE_SIZE_TYPE;
+
+/**
+ Get platform page table attribute.
+
+ This function gets page table attribute of platform.
+
+ @param[in] Address Obtain the page table entries attribute on this address.
+ @param[in][out] PageSize The size of the page.
+ @param[in][out] NumOfPages Number of page.
+ @param[in][out] PageAttribute Paging Attributes (WB, UC, etc).
+
+ @retval EFI_SUCCESS The platform page table attribute from the address is determined.
+ @retval EFI_UNSUPPORTED The paltform not supoort to get page table attribute from the address.
+
+**/
+EFI_STATUS
+EFIAPI
+GetPlatformPageTableAttribute (
+ IN UINT64 Address,
+ OUT SMM_PAGE_SIZE_TYPE *PageSize,
+ OUT UINTN *NumOfPages,
+ OUT UINTN *PageAttribute
+ );
+
+#endif
diff --git a/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/Include/Library/SocketLga775Lib.h b/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/Include/Library/SocketLga775Lib.h
new file mode 100644
index 0000000000..98922d3a73
--- /dev/null
+++ b/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/Include/Library/SocketLga775Lib.h
@@ -0,0 +1,314 @@
+/** @file
+ Public include file for CPU definitions and CPU library functions that
+ apply to CPUs that fit into an LGA775 spocket.
+
+ Copyright (c) 2010 - 2015, 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 __SOCKET_LGA_775_H__
+#define __SOCKET_LGA_775_H__
+
+//
+// Definition for CPUID Index
+//
+#define EFI_CPUID_SIGNATURE 0x0
+#define EFI_CPUID_VERSION_INFO 0x1
+#define EFI_CPUID_CACHE_INFO 0x2
+#define EFI_CPUID_SERIAL_NUMBER 0x3
+#define EFI_CPUID_CACHE_PARAMS 0x4
+#define EFI_CPUID_EXTENDED_TOPOLOGY 0xB
+#define EFI_CPUID_EXTENDED_TOPOLOGY_LEVEL_TYPE_INVALID 0x0
+#define EFI_CPUID_EXTENDED_TOPOLOGY_LEVEL_TYPE_SMT 0x1
+#define EFI_CPUID_EXTENDED_TOPOLOGY_LEVEL_TYPE_CORE 0x2
+
+#define EFI_CPUID_EXTENDED_FUNCTION 0x80000000
+#define EFI_CPUID_EXTENDED_CPU_SIG 0x80000001
+#define EFI_CPUID_BRAND_STRING1 0x80000002
+#define EFI_CPUID_BRAND_STRING2 0x80000003
+#define EFI_CPUID_BRAND_STRING3 0x80000004
+#define EFI_CPUID_ADDRESS_SIZE 0x80000008
+
+//
+// Definition for MSR address
+//
+#define EFI_MSR_IA32_TIME_STAMP_COUNTER 0x10
+#define EFI_MSR_IA32_PLATFORM_ID 0x17
+#define EFI_MSR_IA32_APIC_BASE 0x1B
+#define EFI_MSR_EBC_HARD_POWERON 0x2A
+#define EFI_MSR_EBC_SOFT_POWERON 0x2B
+#define EFI_MSR_EBC_FREQUENCY_ID 0x2C
+#define MSR_IA32_FEATURE_CONTROL 0x3A
+#define EFI_MSR_IA32_BIOS_UPDT_TRIG 0x79
+#define EFI_MSR_IA32_BIOS_SIGN_ID 0x8B
+#define EFI_MSR_PSB_CLOCK_STATUS 0xCD
+#define MSR_EXT_CONFIG 0xEE
+#define EFI_IA32_MCG_CAP 0x179
+#define EFI_IA32_MCG_CTL 0x17B
+
+#define EFI_MSR_IA32_PERF_STS 0x198
+#define EFI_MSR_IA32_PERF_CTL 0x199
+#define EFI_MSR_IA32_CLOCK_MODULATION 0x19A
+#define MSR_IA32_THERMAL_INTERRUPT 0x19B
+#define EFI_MSR_IA32_THERM_STATUS 0x19C
+#define EFI_MSR_GV_THERM 0x19D
+#define MSR_IA32_MISC_ENABLE 0x1A0
+#define MSR_PIC_SENS_CFG 0x1AA
+
+#define EFI_IA32_MC0_CTL 0x400
+#define EFI_IA32_MC0_STATUS 0x401
+#define MSR_PECI_CONTROL 0x5A0
+
+//
+// Definition for Local APIC registers and related values
+//
+#define LOCAL_APIC_LVT_TIMER 0x320
+#define LOCAL_APIC_TIMER_INIT_COUNT 0x380
+#define LOCAL_APIC_TIMER_COUNT 0x390
+#define LOCAL_APIC_TIMER_DIVIDE 0x3E0
+
+#define DELIVERY_MODE_FIXED 0x0
+#define DELIVERY_MODE_LOWEST_PRIORITY 0x1
+#define DELIVERY_MODE_SMI 0x2
+#define DELIVERY_MODE_REMOTE_READ 0x3
+#define DELIVERY_MODE_NMI 0x4
+#define DELIVERY_MODE_INIT 0x5
+#define DELIVERY_MODE_SIPI 0x6
+
+#define IA32_PG_P 1u
+#define IA32_PG_RW (1u << 1)
+#define IA32_PG_USR (1u << 2)
+#define IA32_PG_WT (1u << 3)
+#define IA32_PG_CD (1u << 4)
+#define IA32_PG_A (1u << 5)
+#define IA32_PG_D (1u << 6)
+#define IA32_PG_PS (1u << 7)
+#define IA32_PG_G (1u << 8)
+#define IA32_PG_AVL1 (7u << 9)
+#define IA32_PG_PAT_2M (1u << 12)
+#define IA32_PG_PAT_4K IA32_PG_PS
+#define IA32_PG_AVL2 (0x7ffull << 52)
+
+#define IA32_CPUID_SS 0x08000000
+
+#define IA32_MTRRCAP 0xfe
+
+#define SMM_DEFAULT_SMBASE 0x30000
+#define SMM_HANDLER_OFFSET 0x8000
+#define SMM_PSD_OFFSET 0xfb00
+#define SMM_CPU_STATE_OFFSET 0xfc00
+
+#define SMM_CPU_INTERVAL SIZE_2KB
+
+#pragma pack (1)
+
+typedef struct {
+ UINT64 Signature; // Offset 0x00
+ UINT16 Reserved1; // Offset 0x08
+ UINT16 Reserved2; // Offset 0x0A
+ UINT16 Reserved3; // Offset 0x0C
+ UINT16 SmmCs; // Offset 0x0E
+ UINT16 SmmDs; // Offset 0x10
+ UINT16 SmmSs; // Offset 0x12
+ UINT16 SmmOtherSegment; // Offset 0x14
+ UINT16 Reserved4; // Offset 0x16
+ UINT64 Reserved5; // Offset 0x18
+ UINT64 Reserved6; // Offset 0x20
+ UINT64 Reserved7; // Offset 0x28
+ UINT64 SmmGdtPtr; // Offset 0x30
+ UINT32 SmmGdtSize; // Offset 0x38
+ UINT32 Reserved8; // Offset 0x3C
+ UINT64 Reserved9; // Offset 0x40
+ UINT64 Reserved10; // Offset 0x48
+ UINT16 Reserved11; // Offset 0x50
+ UINT16 Reserved12; // Offset 0x52
+ UINT32 Reserved13; // Offset 0x54
+ UINT64 MtrrBaseMaskPtr; // Offset 0x58
+} PROCESSOR_SMM_DESCRIPTOR;
+
+///
+///
+///
+#define SOCKET_LGA_775_SMM_MIN_REV_ID_IOMISC 0x30004
+#define SOCKET_LGA_775_SMM_MIN_REV_ID_x64 0x30006
+
+///
+/// SMM Save State IOMisc related defines
+///
+//
+// I/O Length BitMap
+//
+#define SMM_IO_LENGTH_BYTE 0x01
+#define SMM_IO_LENGTH_WORD 0x02
+#define SMM_IO_LENGTH_DWORD 0x04
+
+//
+// I/O Instruction Type BitMap
+//
+#define SMM_IO_TYPE_IN_IMMEDIATE 0x9
+#define SMM_IO_TYPE_IN_DX 0x1
+#define SMM_IO_TYPE_OUT_IMMEDIATE 0x8
+#define SMM_IO_TYPE_OUT_DX 0x0
+#define SMM_IO_TYPE_INS 0x3
+#define SMM_IO_TYPE_OUTS 0x2
+#define SMM_IO_TYPE_REP_INS 0x7
+#define SMM_IO_TYPE_REP_OUTS 0x6
+
+typedef union {
+ struct {
+ UINT32 SmiFlag:1;
+ UINT32 Length:3;
+ UINT32 Type:4;
+ UINT32 Reserved1:8;
+ UINT32 Port:16;
+ } Bits;
+ UINT32 Uint32;
+} SOCKET_LGA_775_SMM_CPU_STATE_IOMISC;
+
+///
+/// CPU save-state strcuture for IA32.
+///
+typedef struct {
+ UINT8 Reserved[0x200]; // fc00h
+ UINT8 Reserved1[0xf8]; // fe00h
+ UINT32 SMBASE; // fef8h
+ UINT32 SMMRevId; // fefch
+ UINT16 IORestart; // ff00h
+ UINT16 AutoHALTRestart; // ff02h
+ UINT32 IEDBASE; // ff04h
+ UINT8 Reserved2[0x98]; // ff08h
+ UINT32 IOMemAddr; // ffa0h
+ UINT32 IOMisc; // ffa4h
+ UINT32 _ES;
+ UINT32 _CS;
+ UINT32 _SS;
+ UINT32 _DS;
+ UINT32 _FS;
+ UINT32 _GS;
+ UINT32 Reserved3;
+ UINT32 _TR;
+ UINT32 _DR7;
+ UINT32 _DR6;
+ UINT32 _EAX;
+ UINT32 _ECX;
+ UINT32 _EDX;
+ UINT32 _EBX;
+ UINT32 _ESP;
+ UINT32 _EBP;
+ UINT32 _ESI;
+ UINT32 _EDI;
+ UINT32 _EIP;
+ UINT32 _EFLAGS;
+ UINT32 _CR3;
+ UINT32 _CR0;
+} SOCKET_LGA_775_SMM_CPU_STATE32;
+
+///
+/// CPU save-state strcuture for X64.
+///
+typedef struct {
+ UINT8 Reserved1[0x1d0]; // fc00h
+ UINT32 GdtBaseHiDword; // fdd0h
+ UINT32 LdtBaseHiDword; // fdd4h
+ UINT32 IdtBaseHiDword; // fdd8h
+ UINT8 Reserved2[0xc]; // fddch
+ UINT64 IO_EIP; // fde8h
+ UINT8 Reserved3[0x50]; // fdf0h
+ UINT32 _CR4; // fe40h
+ UINT8 Reserved4[0x48]; // fe44h
+ UINT32 GdtBaseLoDword; // fe8ch
+ UINT32 GdtLimit; // fe90h
+ UINT32 IdtBaseLoDword; // fe94h
+ UINT32 IdtLimit; // fe98h
+ UINT32 LdtBaseLoDword; // fe9ch
+ UINT32 LdtLimit; // fea0h
+ UINT32 LdtInfo; // fea4h
+ UINT8 Reserved5[0x50]; // fea8h
+ UINT32 SMBASE; // fef8h
+ UINT32 SMMRevId; // fefch
+ UINT16 IORestart; // ff00h
+ UINT16 AutoHALTRestart; // ff02h
+ UINT32 IEDBASE; // ff04h
+ UINT8 Reserved6[0x14]; // ff08h
+ UINT64 _R15; // ff1ch
+ UINT64 _R14;
+ UINT64 _R13;
+ UINT64 _R12;
+ UINT64 _R11;
+ UINT64 _R10;
+ UINT64 _R9;
+ UINT64 _R8;
+ UINT64 _RAX; // ff5ch
+ UINT64 _RCX;
+ UINT64 _RDX;
+ UINT64 _RBX;
+ UINT64 _RSP;
+ UINT64 _RBP;
+ UINT64 _RSI;
+ UINT64 _RDI;
+ UINT64 IOMemAddr; // ff9ch
+ UINT32 IOMisc; // ffa4h
+ UINT32 _ES; // ffa8h
+ UINT32 _CS;
+ UINT32 _SS;
+ UINT32 _DS;
+ UINT32 _FS;
+ UINT32 _GS;
+ UINT32 _LDTR; // ffc0h
+ UINT32 _TR;
+ UINT64 _DR7; // ffc8h
+ UINT64 _DR6;
+ UINT64 _RIP; // ffd8h
+ UINT64 IA32_EFER; // ffe0h
+ UINT64 _RFLAGS; // ffe8h
+ UINT64 _CR3; // fff0h
+ UINT64 _CR0; // fff8h
+} SOCKET_LGA_775_SMM_CPU_STATE64;
+
+///
+/// Union of CPU save-state strcutures for IA32 and X64.
+///
+typedef union {
+ SOCKET_LGA_775_SMM_CPU_STATE32 x86;
+ SOCKET_LGA_775_SMM_CPU_STATE64 x64;
+} SOCKET_LGA_775_SMM_CPU_STATE;
+
+//
+// Definition for IA32 microcode format
+//
+typedef struct {
+ UINT32 HeaderVersion;
+ UINT32 UpdateRevision;
+ UINT32 Date;
+ UINT32 ProcessorId;
+ UINT32 Checksum;
+ UINT32 LoaderRevision;
+ UINT32 ProcessorFlags;
+ UINT32 DataSize;
+ UINT32 TotalSize;
+ UINT8 Reserved[12];
+} EFI_CPU_MICROCODE_HEADER;
+
+typedef struct {
+ UINT32 ExtendedSignatureCount;
+ UINT32 ExtendedTableChecksum;
+ UINT8 Reserved[12];
+} EFI_CPU_MICROCODE_EXTENDED_TABLE_HEADER;
+
+typedef struct {
+ UINT32 ProcessorSignature;
+ UINT32 ProcessorFlag;
+ UINT32 ProcessorChecksum;
+} EFI_CPU_MICROCODE_EXTENDED_TABLE;
+
+#pragma pack ()
+
+#endif
diff --git a/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/Include/Protocol/SmmCpuService.h b/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/Include/Protocol/SmmCpuService.h
new file mode 100644
index 0000000000..4f41d6f068
--- /dev/null
+++ b/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/Include/Protocol/SmmCpuService.h
@@ -0,0 +1,209 @@
+/** @file
+ Smm CPU Service protocol definition.
+
+ Copyright (c) 2011 - 2015, 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 _SMM_CPU_SERVICE_PROTOCOL_H_
+#define _SMM_CPU_SERVICE_PROTOCOL_H_
+
+//
+// Share some definitions with MP Services and CPU Arch Protocol
+//
+#include <Protocol/MpService.h>
+#include <Protocol/Cpu.h>
+
+#define EFI_SMM_CPU_SERVICE_PROTOCOL_GUID \
+ { \
+ 0x1d202cab, 0xc8ab, 0x4d5c, { 0x94, 0xf7, 0x3c, 0xfc, 0xc0, 0xd3, 0xd3, 0x35 } \
+ }
+
+typedef struct _EFI_SMM_CPU_SERVICE_PROTOCOL EFI_SMM_CPU_SERVICE_PROTOCOL;
+
+//
+// Protocol functions
+//
+
+/**
+ Gets processor information on the requested processor at the
+ instant this call is made. This service may only be called from the BSP.
+
+ @param[in] This A pointer to the EFI_SMM_CPU_SERVICE_PROTOCOL
+ instance.
+ @param[in] ProcessorNumber The handle number of processor.
+ @param[out] ProcessorInfoBuffer A pointer to the buffer where information for
+ the requested processor is deposited.
+
+ @retval EFI_SUCCESS Processor information was returned.
+ @retval EFI_DEVICE_ERROR The calling processor is an AP.
+ @retval EFI_INVALID_PARAMETER ProcessorInfoBuffer is NULL.
+ @retval EFI_NOT_FOUND The processor with the handle specified by
+ ProcessorNumber does not exist in the platform.
+**/
+typedef
+EFI_STATUS
+(EFIAPI * EFI_SMM_GET_PROCESSOR_INFO) (
+ IN CONST EFI_SMM_CPU_SERVICE_PROTOCOL *This,
+ IN UINTN ProcessorNumber,
+ OUT EFI_PROCESSOR_INFORMATION *ProcessorInfoBuffer
+ );
+
+/**
+ This service switches the requested AP to be the BSP from that point onward.
+ This service changes the BSP for all purposes. This call can only be performed
+ by the current BSP.
+
+ This service switches the requested AP to be the BSP from that point onward.
+ This service changes the BSP for all purposes. The new BSP can take over the
+ execution of the old BSP and continue seamlessly from where the old one left
+ off.
+
+ If the BSP cannot be switched prior to the return from this service, then
+ EFI_UNSUPPORTED must be returned.
+
+ @param[in] This A pointer to the EFI_SMM_CPU_SERVICE_PROTOCOL instance.
+ @param[in] ProcessorNumber The handle number of AP that is to become the new
+ BSP. The range is from 0 to the total number of
+ logical processors minus 1.
+
+ @retval EFI_SUCCESS BSP successfully switched.
+ @retval EFI_UNSUPPORTED Switching the BSP cannot be completed prior to
+ this service returning.
+ @retval EFI_UNSUPPORTED Switching the BSP is not supported.
+ @retval EFI_SUCCESS The calling processor is an AP.
+ @retval EFI_NOT_FOUND The processor with the handle specified by
+ ProcessorNumber does not exist.
+ @retval EFI_INVALID_PARAMETER ProcessorNumber specifies the current BSP or
+ a disabled AP.
+ @retval EFI_NOT_READY The specified AP is busy.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI * EFI_SMM_SWITCH_BSP) (
+ IN CONST EFI_SMM_CPU_SERVICE_PROTOCOL *This,
+ IN UINTN ProcessorNumber
+ );
+
+/**
+ Notify that a new processor has been added to the system.
+ The SMM CPU driver should add the processor to the SMM CPU list.
+ If the processor is disabled it won't participate any SMI handler during subsequent SMIs.
+
+ @param[in] This A pointer to the EFI_SMM_CPU_SERVICE_PROTOCOL instance.
+ @param[in] ProcessorId The hardware ID of the processor.
+ @param[in] ProcessorNumber The handle number of processor.
+
+ @retval EFI_SUCCESS The function completed successfully.
+ @retval EFI_ALREADY_STARTED Processor already present.
+ @retval EFI_NOT_READY Space for a new handle could not be allocated.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_SMM_ADD_PROCESSOR) (
+ IN CONST EFI_SMM_CPU_SERVICE_PROTOCOL *This,
+ IN UINT64 ProcessorId,
+ OUT UINTN *ProcessorNumber
+ );
+
+/**
+ Notify that a processor is hot-removed.
+
+ Remove a processor from the CPU list of the SMM CPU driver. After this API is called, the removed processor
+ must not respond to SMIs in the coherence domain.
+
+ @param[in] This A pointer to the EFI_SMM_CPU_SERVICE_PROTOCOL instance.
+ @param[in] ProcessorId The hardware ID of the processor.
+ @param[in] ProcessorNumber The handle number of processor.
+
+ @retval EFI_SUCCESS The function completed successfully.
+ @retval EFI_NOT_FOUND Processor with the hardware ID specified by ProcessorId does not exist.
+ @retval EFI_NOT_READY Specified AP is busy.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_SMM_REMOVE_PROCESSOR) (
+ IN CONST EFI_SMM_CPU_SERVICE_PROTOCOL *This,
+ IN UINTN ProcessorNumber
+ );
+
+/**
+ This return the handle number for the calling processor. This service may be
+ called from the BSP and APs.
+
+ This service returns the processor handle number for the calling processor.
+ The returned value is in the range from 0 to the total number of logical
+ processors minus 1. This service may be called from the BSP and APs.
+ If ProcessorNumber is NULL, then EFI_INVALID_PARAMETER
+ is returned. Otherwise, the current processors handle number is returned in
+ ProcessorNumber, and EFI_SUCCESS is returned.
+
+ @param[in] This A pointer to the EFI_SMM_CPU_SERVICE_PROTOCOL instance.
+ @param[in] ProcessorNumber The handle number of AP that is to become the new
+ BSP. The range is from 0 to the total number of
+ logical processors minus 1.
+
+ @retval EFI_SUCCESS The current processor handle number was returned
+ in ProcessorNumber.
+ @retval EFI_INVALID_PARAMETER ProcessorNumber is NULL.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI * EFI_SMM_WHOAMI) (
+ IN CONST EFI_SMM_CPU_SERVICE_PROTOCOL *This,
+ OUT UINTN *ProcessorNumber
+ );
+
+/**
+ Register exception handler.
+
+ @param[in] This A pointer to the SMM_CPU_SERVICE_PROTOCOL instance.
+ @param[in] ExceptionType Defines which interrupt or exception to hook. Type EFI_EXCEPTION_TYPE and
+ the valid values for this parameter are defined in EFI_DEBUG_SUPPORT_PROTOCOL
+ of the UEFI 2.0 specification.
+ @param[in] InterruptHandler A pointer to a function of type EFI_CPU_INTERRUPT_HANDLER
+ that is called when a processor interrupt occurs.
+ If this parameter is NULL, then the handler will be uninstalled.
+
+ @retval EFI_SUCCESS The handler for the processor interrupt was successfully installed or uninstalled.
+ @retval EFI_ALREADY_STARTED InterruptHandler is not NULL, and a handler for InterruptType was previously installed.
+ @retval EFI_INVALID_PARAMETER InterruptHandler is NULL, and a handler for InterruptType was not previously installed.
+ @retval EFI_UNSUPPORTED The interrupt specified by InterruptType is not supported.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_SMM_REGISTER_EXCEPTION_HANDLER) (
+ IN EFI_SMM_CPU_SERVICE_PROTOCOL *This,
+ IN EFI_EXCEPTION_TYPE ExceptionType,
+ IN EFI_CPU_INTERRUPT_HANDLER InterruptHandler
+ );
+
+//
+// This protocol provides CPU services from SMM.
+//
+struct _EFI_SMM_CPU_SERVICE_PROTOCOL {
+ EFI_SMM_GET_PROCESSOR_INFO GetProcessorInfo;
+ EFI_SMM_SWITCH_BSP SwitchBsp;
+ EFI_SMM_ADD_PROCESSOR AddProcessor;
+ EFI_SMM_REMOVE_PROCESSOR RemoveProcessor;
+ EFI_SMM_WHOAMI WhoAmI;
+ EFI_SMM_REGISTER_EXCEPTION_HANDLER RegisterExceptionHandler;
+};
+
+extern EFI_GUID gEfiSmmCpuServiceProtocolGuid;
+
+#endif
+
diff --git a/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/Include/Protocol/SmmCpuSync.h b/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/Include/Protocol/SmmCpuSync.h
new file mode 100644
index 0000000000..a0de096e61
--- /dev/null
+++ b/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/Include/Protocol/SmmCpuSync.h
@@ -0,0 +1,107 @@
+/** @file
+ Smm CPU Sync protocol definition.
+
+ Copyright (c) 2006 - 2015, 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 _SMM_CPU_SYNC_PROTOCOL_H_
+#define _SMM_CPU_SYNC_PROTOCOL_H_
+
+#define SMM_CPU_SYNC_PROTOCOL_GUID \
+ { \
+ 0xd5950985, 0x8be3, 0x4b1c, { 0xb6, 0x3f, 0x95, 0xd1, 0x5a, 0xb3, 0xb6, 0x5f } \
+ }
+
+typedef struct _SMM_CPU_SYNC_PROTOCOL SMM_CPU_SYNC_PROTOCOL;
+
+//
+// Data structures
+//
+
+typedef enum {
+ SmmCpuSyncModeTradition,
+ SmmCpuSyncModeRelaxedAp,
+ SmmCpuSyncModeMax
+} SMM_CPU_SYNC_MODE;
+
+//
+// Protocol functions
+//
+
+/**
+ Given timeout constraint, wait for all APs to arrive, and insure if this function returns EFI_SUCCESS, then
+ no AP will execute normal mode code before entering SMM, so it is safe to access shared hardware resource
+ between SMM and normal mode. Note if there are SMI disabled APs, this function will return EFI_NOT_READY.
+
+ @param[in] This A pointer to the SMM_CPU_SYNC_PROTOCOL instance.
+
+ @retval EFI_SUCCESS No AP will execute normal mode code before entering SMM, so it is safe to access
+ shared hardware resource between SMM and normal mode
+ @retval EFI_NOT_READY One or more CPUs may still execute normal mode code
+ @retval EFI_DEVICE_ERROR Error occured in obtaining CPU status.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *SMM_CPU_SYNC_CHECK_AP_ARRIVAL) (
+ IN SMM_CPU_SYNC_PROTOCOL *This
+ );
+
+/**
+ Set SMM synchronization mode starting from the next SMI run.
+
+ @param[in] This A pointer to the SMM_CPU_SYNC_PROTOCOL instance.
+ @param[in] SyncMode The SMM synchronization mode to be set and effective from the next SMI run.
+
+ @retval EFI_SUCCESS The function completes successfully.
+ @retval EFI_INVALID_PARAMETER SynMode is not valid.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *SMM_CPU_SYNC_SET_MODE) (
+ IN SMM_CPU_SYNC_PROTOCOL *This,
+ IN SMM_CPU_SYNC_MODE SyncMode
+ );
+
+/**
+ Get current effective SMM synchronization mode.
+
+ @param[in] This A pointer to the SMM_CPU_SYNC_PROTOCOL instance.
+ @param[in] SyncMode Output parameter. The current effective SMM synchronization mode.
+
+ @retval EFI_SUCCESS The SMM synchronization mode has been retrieved successfully.
+ @retval EFI_INVALID_PARAMETER SyncMode is NULL.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *SMM_CPU_SYNC_GET_MODE) (
+ IN SMM_CPU_SYNC_PROTOCOL *This,
+ OUT SMM_CPU_SYNC_MODE *SyncMode
+ );
+
+/**
+ This protocol provides services on SMM CPU syncrhonization related status and controls
+**/
+struct _SMM_CPU_SYNC_PROTOCOL {
+ SMM_CPU_SYNC_CHECK_AP_ARRIVAL CheckApArrival;
+ SMM_CPU_SYNC_SET_MODE SetMode;
+ SMM_CPU_SYNC_GET_MODE GetMode;
+};
+
+//
+// Extern the GUID for protocol users.
+//
+extern EFI_GUID gSmmCpuSyncProtocolGuid;
+
+#endif
diff --git a/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/Include/Protocol/SmmCpuSync2.h b/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/Include/Protocol/SmmCpuSync2.h
new file mode 100644
index 0000000000..b742e536e7
--- /dev/null
+++ b/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/Include/Protocol/SmmCpuSync2.h
@@ -0,0 +1,186 @@
+/** @file
+ Smm CPU Sync2 protocol definition.
+
+ Copyright (c) 2006 - 2015, 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 _SMM_CPU_SYNC2_PROTOCOL_H_
+#define _SMM_CPU_SYNC2_PROTOCOL_H_
+
+#include "SmmCpuSync.h"
+
+#define SMM_CPU_SYNC2_PROTOCOL_GUID \
+ { \
+ 0x9db72e22, 0x9262, 0x4a18, { 0x8f, 0xe0, 0x85, 0xe0, 0x3d, 0xfa, 0x96, 0x73 } \
+ }
+
+typedef struct _SMM_CPU_SYNC2_PROTOCOL SMM_CPU_SYNC2_PROTOCOL;
+
+typedef enum {
+ SmmCpuSync2StateNormal,
+ SmmCpuSync2StateDelayed,
+ SmmCpuSync2StateBlocked,
+ SmmCpuSync2StateDisabled,
+ SmmCpuSync2StateMax
+} SMM_CPU_SYNC2_CPU_STATE;
+
+//
+// Protocol functions
+//
+
+/**
+ Given timeout constraint, wait for all APs to arrive, and insure if this function returns EFI_SUCCESS, then
+ no AP will execute normal mode code before entering SMM, so it is safe to access shared hardware resource
+ between SMM and normal mode. Note if there are SMI disabled APs, this function will return EFI_NOT_READY.
+
+ @param[in] This A pointer to the SMM_CPU_SYNC_PROTOCOL instance.
+
+ @retval EFI_SUCCESS No AP will execute normal mode code before entering SMM, so it is safe to access
+ shared hardware resource between SMM and normal mode
+ @retval EFI_NOT_READY One or more CPUs may still execute normal mode code
+ @retval EFI_DEVICE_ERROR Error occured in obtaining CPU status.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *SMM_CPU_SYNC2_CHECK_AP_ARRIVAL) (
+ IN SMM_CPU_SYNC2_PROTOCOL *This
+ );
+
+/**
+ Set SMM synchronization mode starting from the next SMI run.
+
+ @param[in] This A pointer to the SMM_CPU_SYNC_PROTOCOL instance.
+ @param[in] SyncMode The SMM synchronization mode to be set and effective from the next SMI run.
+
+ @retval EFI_SUCCESS The function completes successfully.
+ @retval EFI_INVALID_PARAMETER SynMode is not valid.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *SMM_CPU_SYNC2_SET_MODE) (
+ IN SMM_CPU_SYNC2_PROTOCOL *This,
+ IN SMM_CPU_SYNC_MODE SyncMode
+ );
+
+/**
+ Get current effective SMM synchronization mode.
+
+ @param This A pointer to the SMM_CPU_SYNC_PROTOCOL instance.
+ @param SyncMode Output parameter. The current effective SMM synchronization mode.
+
+ @retval EFI_SUCCESS The SMM synchronization mode has been retrieved successfully.
+ @retval EFI_INVALID_PARAMETER SyncMode is NULL.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *SMM_CPU_SYNC2_GET_MODE) (
+ IN SMM_CPU_SYNC2_PROTOCOL *This,
+ OUT SMM_CPU_SYNC_MODE *SyncMode
+ );
+
+/**
+ Checks CPU SMM synchronization state
+
+ @param[in] This A pointer to the SMM_CPU_SYNC_PROTOCOL instance.
+ @param[in] CpuIndex Index of the CPU for which the state is to be retrieved.
+ @param[out] CpuState The state of the CPU
+
+ @retval EFI_SUCCESS Returns EFI_SUCCESS if the CPU's state is retrieved.
+ @retval EFI_INVALID_PARAMETER Returns EFI_INVALID_PARAMETER if CpuIndex is invalid or CpuState is NULL
+ @retval EFI_DEVICE_ERROR Error occured in obtaining CPU status.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *SMM_CPU_SYNC2_CHECK_CPU_STATE) (
+ IN SMM_CPU_SYNC2_PROTOCOL *This,
+ IN UINTN CpuIndex,
+ OUT SMM_CPU_SYNC2_CPU_STATE *CpuState
+ );
+
+/**
+ Change CPU's SMM enabling state.
+
+ @param[in] This A pointer to the SMM_CPU_SYNC_PROTOCOL instance.
+ @param[in] CpuIndex Index of the CPU to enable / disable SMM
+ @param[in] Enable If TRUE, enable SMM; if FALSE disable SMM
+
+ @retval EFI_SUCCESS The CPU's SMM enabling state is changed.
+ @retval EFI_INVALID_PARAMETER Returns EFI_INVALID_PARAMETER if CpuIndex is invalid
+ @retval EFI_UNSUPPORTED Returns EFI_UNSUPPORTED the CPU does not support dynamically enabling / disabling SMI
+ @retval EFI_DEVICE_ERROR Error occured in changing SMM enabling state.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *SMM_CPU_SYNC2_CHANGE_SMM_ENABLING) (
+ IN SMM_CPU_SYNC2_PROTOCOL *This,
+ IN UINTN CpuIndex,
+ IN BOOLEAN Enable
+ );
+
+/**
+ Send SMI IPI to a specific CPU
+
+ @param[in] This A pointer to the SMM_CPU_SYNC_PROTOCOL instance.
+ @param[in] CpuIndex Index of the CPU to send SMI to. "-1" means all-exclude-self.
+
+ @retval EFI_SUCCESS The SMI IPI is sent successfully.
+ @retval EFI_INVALID_PARAMETER Returns EFI_INVALID_PARAMETER if CpuIndex is invalid
+ @retval EFI_DEVICE_ERROR Error occured in sending SMI IPI.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *SMM_CPU_SYNC2_SEND_SMI) (
+ IN SMM_CPU_SYNC2_PROTOCOL *This,
+ IN UINTN CpuIndex
+ );
+
+/**
+ Send SMI IPI to all CPUs excluding self
+
+ @param[in] This A pointer to the SMM_CPU_SYNC_PROTOCOL instance.
+
+ @retval EFI_SUCCESS The SMI IPI is sent successfully.
+ @retval EFI_INVALID_PARAMETER Returns EFI_INVALID_PARAMETER if CpuIndex is invalid
+ @retval EFI_DEVICE_ERROR Error occured in sending SMI IPI.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *SMM_CPU_SYNC2_SEND_SMI_ALL_EXCLUDING_SELF) (
+ IN SMM_CPU_SYNC2_PROTOCOL *This
+ );
+
+/**
+ This protocol provides services on SMM CPU syncrhonization related status and controls
+**/
+struct _SMM_CPU_SYNC2_PROTOCOL {
+ SMM_CPU_SYNC2_CHECK_AP_ARRIVAL CheckApArrival;
+ SMM_CPU_SYNC2_SET_MODE SetMode;
+ SMM_CPU_SYNC2_GET_MODE GetMode;
+ SMM_CPU_SYNC2_CHECK_CPU_STATE CheckCpuState;
+ SMM_CPU_SYNC2_CHANGE_SMM_ENABLING ChangeSmmEnabling;
+ SMM_CPU_SYNC2_SEND_SMI SendSmi;
+ SMM_CPU_SYNC2_SEND_SMI_ALL_EXCLUDING_SELF SendSmiAllExcludingSelf;
+};
+
+//
+// Extern the GUID for protocol users.
+//
+extern EFI_GUID gSmmCpuSync2ProtocolGuid;
+
+#endif
diff --git a/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/Library/CpuConfigLib/CpuConfig.c b/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/Library/CpuConfigLib/CpuConfig.c
new file mode 100644
index 0000000000..b9b81f92ce
--- /dev/null
+++ b/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/Library/CpuConfigLib/CpuConfig.c
@@ -0,0 +1,961 @@
+/** @file
+ CPU Configuration Library.
+
+ Copyright (c) 2006 - 2015, 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 "CpuConfig.h"
+
+CPU_CONFIG_CONTEXT_BUFFER *mCpuConfigLibConfigConextBuffer;
+
+/**
+ The constructor function of CPU Configuration Library.
+ The constructor function caches the value of PCD entry PcdCpuConfigContextBuffer.
+
+ @param[in] ImageHandle The firmware allocated handle for the EFI image.
+ @param[in] SystemTable A pointer to the EFI System Table.
+
+ @retval EFI_SUCCESS The constructor always returns EFI_SUCCESS.
+
+**/
+EFI_STATUS
+EFIAPI
+CpuConfigLibConstructor (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ //
+ // Get the pointer to CPU Configuration Context Buffer from PcdCpuConfigContextBuffer.
+ // This PCD entry is set by CPU driver.
+ //
+ mCpuConfigLibConfigConextBuffer = (CPU_CONFIG_CONTEXT_BUFFER *) (UINTN) PcdGet64 (PcdCpuConfigContextBuffer);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Set feature capability and related attribute.
+ This function sets the feature capability and its attribute.
+
+ @param[in] ProcessorNumber Handle number of specified logical processor
+ @param[in] FeatureID The ID of the feature.
+ @param[in] Attribute Feature-specific data.
+
+**/
+VOID
+EFIAPI
+SetProcessorFeatureCapability (
+ IN UINTN ProcessorNumber,
+ IN CPU_FEATURE_ID FeatureID,
+ IN VOID *Attribute
+ )
+{
+ CPU_COLLECTED_DATA *CpuCollectedData;
+
+ ASSERT (mCpuConfigLibConfigConextBuffer != NULL);
+ CpuCollectedData = &mCpuConfigLibConfigConextBuffer->CollectedDataBuffer[ProcessorNumber];
+
+ //
+ // Set the feature capability of the specified processor as TRUE,
+ // and set feature-specified attribute for the feature.
+ //
+ CpuCollectedData->FeatureData[FeatureID].Capability = TRUE;
+ CpuCollectedData->FeatureData[FeatureID].Attribute = Attribute;
+}
+
+/**
+ Clears feature capability and related attribute.
+ This function clears the feature capability and its attribute.
+
+ @param[in] ProcessorNumber Handle number of specified logical processor
+ @param[in] FeatureID The ID of the feature.
+
+**/
+VOID
+EFIAPI
+ClearProcessorFeatureCapability (
+ IN UINTN ProcessorNumber,
+ IN CPU_FEATURE_ID FeatureID
+ )
+{
+ CPU_COLLECTED_DATA *CpuCollectedData;
+
+ ASSERT (mCpuConfigLibConfigConextBuffer != NULL);
+ CpuCollectedData = &mCpuConfigLibConfigConextBuffer->CollectedDataBuffer[ProcessorNumber];
+
+ //
+ // Set the feature capability of the specified processor as FALSE,
+ // and clears feature-specified attribute for the feature.
+ //
+ CpuCollectedData->FeatureData[FeatureID].Capability = FALSE;
+ CpuCollectedData->FeatureData[FeatureID].Attribute = NULL;
+}
+
+/**
+ Get feature capability and related attribute.
+ This function gets the feature capability and its attribute.
+
+ @param[in] ProcessorNumber Handle number of specified logical processor
+ @param[in] FeatureID The ID of the feature.
+ @param[out] Attribute Pointer to the output feature-specific data.
+
+ @retval TRUE The feature is supported by the processor
+ @retval FALSE The feature is not supported by the processor
+
+**/
+BOOLEAN
+EFIAPI
+GetProcessorFeatureCapability (
+ IN UINTN ProcessorNumber,
+ IN CPU_FEATURE_ID FeatureID,
+ OUT VOID **Attribute OPTIONAL
+ )
+{
+ CPU_COLLECTED_DATA *CpuCollectedData;
+
+ ASSERT (mCpuConfigLibConfigConextBuffer != NULL);
+ CpuCollectedData = &mCpuConfigLibConfigConextBuffer->CollectedDataBuffer[ProcessorNumber];
+
+ //
+ // If Attribute is not NULL, set feature-specified attribute to it.
+ //
+ if (Attribute != NULL) {
+ *Attribute = CpuCollectedData->FeatureData[FeatureID].Attribute;
+ }
+
+ return CpuCollectedData->FeatureData[FeatureID].Capability;
+}
+
+/**
+ Get the number of CPUID leafs of various types.
+ This function get the number of CPUID leafs of various types.
+
+ @param[in] ProcessorNumber Handle number of specified logical processor
+ @param[in] CpuidType The type of the cpu id.
+
+ @retval NumberOfLeafs Maximal index of CPUID instruction for basic leafs.
+
+**/
+UINTN
+EFIAPI
+GetNumberOfCpuidLeafs (
+ IN UINTN ProcessorNumber,
+ IN CPUID_TYPE CpuidType
+ )
+{
+ UINTN NumberOfLeafs;
+ CPU_CPUID_DATA *CpuidData;
+
+ ASSERT (mCpuConfigLibConfigConextBuffer != NULL);
+ CpuidData = &(mCpuConfigLibConfigConextBuffer->CollectedDataBuffer[ProcessorNumber].CpuidData);
+
+ switch (CpuidType) {
+ case BasicCpuidLeaf:
+ NumberOfLeafs = CpuidData->NumberOfBasicCpuidLeafs;
+ break;
+ case ExtendedCpuidLeaf:
+ NumberOfLeafs = CpuidData->NumberOfExtendedCpuidLeafs;
+ break;
+ case CacheAndTlbCpuidLeafs:
+ NumberOfLeafs = CpuidData->NumberOfCacheAndTlbCpuidLeafs;
+ break;
+ case DeterministicCacheParametersCpuidLeafs:
+ NumberOfLeafs = CpuidData->NumberOfDeterministicCacheParametersCpuidLeafs;
+ break;
+ case ExtendedTopologyEnumerationCpuidLeafs:
+ NumberOfLeafs = CpuidData->NumberOfExtendedTopologyEnumerationLeafs;
+ break;
+ default:
+ NumberOfLeafs = 0;
+ break;
+ }
+
+ return NumberOfLeafs;
+}
+
+/**
+ Get the pointer to specified CPUID leaf.
+ This function gets the pointer to specified CPUID leaf.
+
+ @param[in] ProcessorNumber Handle number of specified logical processor
+ @param[in] Index Index of the CPUID leaf.
+
+ @retval EFI_CPUID_REGISTER Pointer to specified CPUID leaf
+
+**/
+EFI_CPUID_REGISTER*
+EFIAPI
+GetProcessorCpuid (
+ IN UINTN ProcessorNumber,
+ IN UINTN Index
+)
+{
+ CPU_CPUID_DATA *CpuidData;
+
+ ASSERT (mCpuConfigLibConfigConextBuffer != NULL);
+ CpuidData = &(mCpuConfigLibConfigConextBuffer->CollectedDataBuffer[ProcessorNumber].CpuidData);
+
+ //
+ // If Index specifies basic CPUID leafs, then locate basic leaf to return.
+ //
+ if (Index < CpuidData->NumberOfBasicCpuidLeafs) {
+ return (&CpuidData->CpuIdLeaf[Index]);
+ }
+
+ //
+ // If Index specifies extended CPUID leafs, then locate extended leaf to return.
+ //
+ if (Index >= 0x80000000 && Index < 0x80000000 + CpuidData->NumberOfExtendedCpuidLeafs) {
+ return (&CpuidData->CpuIdLeaf[Index - 0x80000000 + CpuidData->NumberOfBasicCpuidLeafs]);
+ }
+
+ //
+ // If Index specifies invalid CPUID index, then return NULL.
+ //
+ return NULL;
+}
+
+/**
+ Get the pointer to specified CPUID leaf of cache and TLB parameters.
+ This function gets the pointer to specified CPUID leaf of cache and TLB parameters.
+
+ @param[in] ProcessorNumber Handle number of specified logical processor
+ @param[in] Index Index of the CPUID leaf.
+
+ @retval EFI_CPUID_REGISTER Pointer to specified CPUID leaf.
+
+**/
+EFI_CPUID_REGISTER*
+EFIAPI
+GetCacheAndTlbCpuidLeaf (
+ IN UINTN ProcessorNumber,
+ IN UINTN Index
+)
+{
+ UINTN StartIndex;
+ CPU_CPUID_DATA *CpuidData;
+
+ ASSERT (mCpuConfigLibConfigConextBuffer != NULL);
+ CpuidData = &(mCpuConfigLibConfigConextBuffer->CollectedDataBuffer[ProcessorNumber].CpuidData);
+
+ //
+ // The first leaf resides in basic leaf 2
+ //
+ if (Index == 0) {
+ return (&CpuidData->CpuIdLeaf[2]);
+ }
+
+ //
+ // If index is greater than zero, calculate the start index of deterministic cache CPUID leafs.
+ //
+ StartIndex = CpuidData->NumberOfBasicCpuidLeafs + CpuidData->NumberOfExtendedCpuidLeafs;
+
+ return (&CpuidData->CpuIdLeaf[Index + StartIndex - 1]);
+}
+
+/**
+ Get the pointer to specified CPUID leaf of deterministic cache parameters.
+ This function gets the pointer to specified CPUID leaf of deterministic cache parameters.
+
+ @param[in] ProcessorNumber Handle number of specified logical processor
+ @param[in] Index Index of the CPUID leaf.
+
+ @retval EFI_CPUID_REGISTER Pointer to specified CPUID leaf.
+
+**/
+EFI_CPUID_REGISTER*
+EFIAPI
+GetDeterministicCacheParametersCpuidLeaf (
+ IN UINTN ProcessorNumber,
+ IN UINTN Index
+)
+{
+ UINTN StartIndex;
+ CPU_CPUID_DATA *CpuidData;
+
+ ASSERT (mCpuConfigLibConfigConextBuffer != NULL);
+ CpuidData = &(mCpuConfigLibConfigConextBuffer->CollectedDataBuffer[ProcessorNumber].CpuidData);
+
+ //
+ // Calculate the start index of deterministic cache CPUID leafs.
+ //
+ StartIndex = CpuidData->NumberOfBasicCpuidLeafs;
+ StartIndex += CpuidData->NumberOfExtendedCpuidLeafs;
+ StartIndex += CpuidData->NumberOfCacheAndTlbCpuidLeafs - 1;
+
+ return (&CpuidData->CpuIdLeaf[Index + StartIndex]);
+}
+
+/**
+ Get the pointer to specified CPUID leaf of Extended Topology Enumeration.
+ This function gets the pointer to specified CPUID leaf of Extended Topology Enumeration.
+
+ @param[in] ProcessorNumber Handle number of specified logical processor.
+ @param[in] Index Index of the CPUID leaf.
+
+ @retval EFI_CPUID_REGISTER Pointer to specified CPUID leaf.
+
+**/
+EFI_CPUID_REGISTER*
+EFIAPI
+GetExtendedTopologyEnumerationCpuidLeafs (
+ IN UINTN ProcessorNumber,
+ IN UINTN Index
+ )
+{
+ UINTN StartIndex;
+ CPU_CPUID_DATA *CpuidData;
+
+ ASSERT (mCpuConfigLibConfigConextBuffer != NULL);
+ CpuidData = &(mCpuConfigLibConfigConextBuffer->CollectedDataBuffer[ProcessorNumber].CpuidData);
+
+ //
+ // Calculate the start index of Extended Topology Enumeration CPUID leafs.
+ //
+ StartIndex = CpuidData->NumberOfBasicCpuidLeafs;
+ StartIndex += CpuidData->NumberOfExtendedCpuidLeafs;
+ StartIndex += CpuidData->NumberOfCacheAndTlbCpuidLeafs - 1;
+ StartIndex += CpuidData->NumberOfDeterministicCacheParametersCpuidLeafs;
+
+ return (&CpuidData->CpuIdLeaf[Index + StartIndex]);
+}
+
+/**
+ Get the version information of specified logical processor.
+ This function gets the version information of specified logical processor,
+ including family ID, model ID, stepping ID and processor type.
+
+ @param[in] ProcessorNumber Handle number of specified logical processor
+ @param[out] DisplayedFamily Pointer to family ID for output
+ @param[out] DisplayedModel Pointer to model ID for output
+ @param[out] SteppingId Pointer to stepping ID for output
+ @param[out] ProcessorType Pointer to processor type for output
+
+**/
+VOID
+EFIAPI
+GetProcessorVersionInfo (
+ IN UINTN ProcessorNumber,
+ OUT UINT32 *DisplayedFamily OPTIONAL,
+ OUT UINT32 *DisplayedModel OPTIONAL,
+ OUT UINT32 *SteppingId OPTIONAL,
+ OUT UINT32 *ProcessorType OPTIONAL
+ )
+{
+ EFI_CPUID_REGISTER *VersionInfo;
+ UINT32 RegEax;
+ UINT32 FamilyId;
+ UINT32 ExtendedFamilyId;
+ UINT32 ExtendedModelId;
+
+ //
+ // Get CPUID(1).EAX
+ //
+ VersionInfo = GetProcessorCpuid (ProcessorNumber, EFI_CPUID_VERSION_INFO);
+ ASSERT (VersionInfo != NULL);
+ RegEax = VersionInfo->RegEax;
+
+ //
+ // Processor Type is CPUID(1).EAX[12:13]
+ //
+ if (ProcessorType != NULL) {
+ *ProcessorType = BitFieldRead32 (RegEax, 12, 13);
+ }
+
+ //
+ // Stepping ID is CPUID(1).EAX[0:3]
+ //
+ if (SteppingId != NULL) {
+ *SteppingId = BitFieldRead32 (RegEax, 0, 3);
+ }
+
+ //
+ // The Extended Family ID needs to be examined only when the Family ID is 0FH.
+ // If Family ID is 0FH, Displayed Family ID = Family ID + Extended Family ID.
+ // Otherwise, Displayed Family ID is Family ID
+ //
+ FamilyId = BitFieldRead32 (RegEax, 8, 11);
+ if (DisplayedFamily != NULL) {
+ *DisplayedFamily = FamilyId;
+ if (FamilyId == 0x0f) {
+ ExtendedFamilyId = BitFieldRead32 (RegEax, 20, 27);
+ *DisplayedFamily += ExtendedFamilyId;
+ }
+ }
+
+ //
+ // The Extended Model ID needs to be examined only when the Family ID is 06H or 0FH.
+ // If Family ID is 06H or 0FH, Displayed Model ID = Model ID + (Extended Model ID << 4).
+ // Otherwise, Displayed Model ID is Model ID.
+ //
+ if (DisplayedModel != NULL) {
+ *DisplayedModel = BitFieldRead32 (RegEax, 4, 7);
+ if (FamilyId == 0x06 || FamilyId == 0x0f) {
+ ExtendedModelId = BitFieldRead32 (RegEax, 16, 19);
+ *DisplayedModel += (ExtendedModelId << 4);
+ }
+ }
+}
+
+/**
+ Get initial local APIC ID of specified logical processor
+ This function gets initial local APIC ID of specified logical processor.
+
+ @param[in] ProcessorNumber Handle number of specified logical processor
+
+ @retval Initial local APIC ID of specified logical processor
+
+**/
+UINT32
+EFIAPI
+GetInitialLocalApicId (
+ UINTN ProcessorNumber
+ )
+{
+ CPU_COLLECTED_DATA *CpuCollectedData;
+
+ ASSERT (mCpuConfigLibConfigConextBuffer != NULL);
+ CpuCollectedData = &mCpuConfigLibConfigConextBuffer->CollectedDataBuffer[ProcessorNumber];
+
+ return (CpuCollectedData->CpuidData.CpuIdLeaf[1].RegEbx >> 24) & 0xff;
+}
+
+/**
+ Get the location of specified processor.
+
+ This function gets the location of specified processor, including
+ package number, core number within package, thread number within core.
+
+ @param[in] ProcessorNumber Handle number of specified logical processor.
+ @param[out] PackageNumber Pointer to the output package number.
+ @param[out] CoreNumber Pointer to the output core number.
+ @param[out] ThreadNumber Pointer to the output thread number.
+
+**/
+VOID
+EFIAPI
+GetProcessorLocation (
+ IN UINTN ProcessorNumber,
+ OUT UINT32 *PackageNumber OPTIONAL,
+ OUT UINT32 *CoreNumber OPTIONAL,
+ OUT UINT32 *ThreadNumber OPTIONAL
+)
+{
+ CPU_COLLECTED_DATA *CpuCollectedData;
+
+ ASSERT (mCpuConfigLibConfigConextBuffer != NULL);
+ CpuCollectedData = &mCpuConfigLibConfigConextBuffer->CollectedDataBuffer[ProcessorNumber];
+
+ //
+ // If PackageNumber is not NULL, set the package number of the specified processor to it.
+ //
+ if (PackageNumber != NULL) {
+ *PackageNumber = CpuCollectedData->ProcessorLocation.Package;
+ }
+
+ //
+ // If CoreNumber is not NULL, set the core number within package to it.
+ //
+ if (CoreNumber != NULL) {
+ *CoreNumber = CpuCollectedData->ProcessorLocation.Core;
+ }
+
+ //
+ // If ThreadNumber is not NULL, set the thread number within core to it.
+ //
+ if (ThreadNumber != NULL) {
+ *ThreadNumber = CpuCollectedData->ProcessorLocation.Thread;
+ }
+}
+
+/**
+ Get the Feature entry at specified position in a feature list.
+ This function gets the Feature entry at specified position in a feature list.
+
+ @param[in] ProcessorNumber Handle number of specified logical processor
+ @param[in] FeatureIndex The index of the node in feature list.
+ @param[out] Attribute Pointer to output feature-specific attribute
+
+ @retval CPU_FEATURE_ID Feature ID of specified feature. CpuFeatureMaximum means not found
+
+**/
+CPU_FEATURE_ID
+EFIAPI
+GetProcessorFeatureEntry (
+ IN UINTN ProcessorNumber,
+ IN UINTN FeatureIndex,
+ OUT VOID **Attribute OPTIONAL
+ )
+{
+ CPU_FEATURE_ENTRY *FeatureEntry;
+
+ ASSERT (mCpuConfigLibConfigConextBuffer != NULL);
+
+ if (Attribute != NULL) {
+ *Attribute = NULL;
+ }
+
+ //
+ // Search for specified entry. If not found, return CpuFeatureMaximum.
+ //
+ FeatureEntry = SearchFeatureEntry (ProcessorNumber, FeatureIndex);
+ if (FeatureEntry == NULL) {
+ return CpuFeatureMaximum;
+ }
+
+ //
+ // If Attribute is not NULL, set the feature-specified attribute to it.
+ //
+ if (Attribute != NULL) {
+ *Attribute = FeatureEntry->Attribute;
+ }
+
+ return (FeatureEntry->FeatureID);
+}
+
+/**
+ Append a feature entry at the end of a feature list.
+ This function appends a feature entry at the end of a feature list.
+
+ @param[in] ProcessorNumber Handle number of specified logical processor
+ @param[in] FeatureID ID of the specified feature.
+ @param[in] Attribute Feature-specific attribute.
+
+ @retval EFI_SUCCESS This function always return EFI_SUCCESS
+
+**/
+EFI_STATUS
+EFIAPI
+AppendProcessorFeatureIntoList (
+ IN UINTN ProcessorNumber,
+ IN CPU_FEATURE_ID FeatureID,
+ IN VOID *Attribute
+ )
+{
+ LIST_ENTRY *List;
+ CPU_FEATURE_ENTRY *NewEntry;
+
+ ASSERT (mCpuConfigLibConfigConextBuffer != NULL);
+ List = &mCpuConfigLibConfigConextBuffer->FeatureLinkListEntry[ProcessorNumber];
+
+ //
+ // Create a new feature node with given Feature ID and feature-specific attribute
+ //
+ NewEntry = CreateFeatureEntry (FeatureID, Attribute);
+
+ //
+ // Append the new node at the end of the list
+ //
+ InsertTailList (List, &(NewEntry->Link));
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Delete a feature entry in a feature list.
+ This function deletes a feature entry in a feature list.
+
+ @param[in] ProcessorNumber Handle number of specified logical processor
+ @param[in] FeatureIndex The index of the node in feature list.
+
+ @retval EFI_SUCCESS The feature node successfully removed.
+ @retval EFI_INVALID_PARAMETER FeatureIndex surpasses the length of list.
+
+**/
+EFI_STATUS
+EFIAPI
+DeleteProcessorFeatureFromList (
+ IN UINTN ProcessorNumber,
+ IN UINTN FeatureIndex
+ )
+{
+ CPU_FEATURE_ENTRY *FeatureEntry;
+
+ ASSERT (mCpuConfigLibConfigConextBuffer != NULL);
+
+ //
+ // Search for specified entry. If SearchFeatureEntry() returns NULL, then
+ // it means FeatureIndex surpasses the length of list.
+ // Return EFI_INVALID_PARAMETER.
+ //
+ FeatureEntry = SearchFeatureEntry (ProcessorNumber, FeatureIndex);
+ if (FeatureEntry == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Remove the entry from list, and free its memory region.
+ //
+ RemoveEntryList (&(FeatureEntry->Link));
+ FreePool (FeatureEntry);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Insert a feature entry into a feature list.
+ This function insert a feature entry into a feature list before a node specified by Feature Index.
+
+ @param[in] ProcessorNumber Handle number of specified logical processor
+ @param[in] FeatureIndex The index of the new node in feature list.
+ @param[in] FeatureID ID of the specified feature.
+ @param[in] Attribute Feature-specific attribute.
+
+ @retval EFI_SUCCESS The feature node successfully inserted.
+ @retval EFI_INVALID_PARAMETER FeatureIndex surpasses the length of list.
+
+**/
+EFI_STATUS
+EFIAPI
+InsertProcessorFeatureIntoList (
+ IN UINTN ProcessorNumber,
+ IN UINTN FeatureIndex,
+ IN CPU_FEATURE_ID FeatureID,
+ IN VOID *Attribute
+ )
+{
+ CPU_FEATURE_ENTRY *FeatureEntry;
+ CPU_FEATURE_ENTRY *NewEntry;
+
+ //
+ // Search for specified entry. If SearchFeatureEntry() returns NULL, then
+ // it means FeatureIndex surpasses the length of list.
+ // Return EFI_INVALID_PARAMETER.
+ //
+ FeatureEntry = SearchFeatureEntry (ProcessorNumber, FeatureIndex);
+ if (FeatureEntry == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Create a new feature node with given Feature ID and feature-specific attribute
+ //
+ NewEntry = CreateFeatureEntry (FeatureID, Attribute);
+
+ //
+ // Insert the new node before specified feature entry.
+ //
+ InsertHeadList (&(FeatureEntry->Link), &(NewEntry->Link));
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Add an entry in specified register table.
+ This function adds an entry in specified register table, with given register type,
+ register index, bit section and value.
+
+ @param[in] PreSmmInit Specify the target register table.
+ If TRUE, the target is the pre-SMM-init register table.
+ If FALSE, the target is the post-SMM-init register table.
+ @param[in] ProcessorNumber Handle number of specified logical processor
+ @param[in] RegisterType Type of the register to program
+ @param[in] Index Index of the register to program
+ @param[in] ValidBitStart Start of the bit section
+ @param[in] ValidBitLength Length of the bit section
+ @param[in] Value Value to write
+
+**/
+VOID
+EFIAPI
+WriteRegisterTableEx (
+ IN BOOLEAN PreSmmInit,
+ IN UINTN ProcessorNumber,
+ IN REGISTER_TYPE RegisterType,
+ IN UINT32 Index,
+ IN UINT8 ValidBitStart,
+ IN UINT8 ValidBitLength,
+ IN UINT64 Value
+ )
+{
+ EFI_STATUS Status;
+ CPU_REGISTER_TABLE *RegisterTable;
+ EFI_PHYSICAL_ADDRESS Address;
+ UINTN AllocatePages;
+
+ ASSERT (mCpuConfigLibConfigConextBuffer != NULL);
+
+ if (PreSmmInit) {
+ RegisterTable = &mCpuConfigLibConfigConextBuffer->PreSmmInitRegisterTable[ProcessorNumber];
+ } else {
+ RegisterTable = &mCpuConfigLibConfigConextBuffer->RegisterTable[ProcessorNumber];
+ }
+
+ //
+ // If register table is full, allocate one more page for it.
+ // It must be in ACPI NVS memory under 4G, for consumption by S3 resume.
+ //
+ if (RegisterTable->TableLength == RegisterTable->AllocatedSize / sizeof (CPU_REGISTER_TABLE_ENTRY)) {
+ Address = 0xffffffff;
+ AllocatePages = RegisterTable->AllocatedSize / EFI_PAGE_SIZE;
+ Status = gBS->AllocatePages (
+ AllocateMaxAddress,
+ EfiACPIMemoryNVS,
+ AllocatePages + 1,
+ &Address
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // If there are records existing in the register table, then copy its contents
+ // to new region and free the old one.
+ //
+ if (RegisterTable->AllocatedSize > 0) {
+ CopyMem (
+ (VOID *) (UINTN) Address,
+ RegisterTable->RegisterTableEntry,
+ RegisterTable->AllocatedSize
+ );
+ //
+ // RegisterTableEntry is allocated by gBS AllocatePages() service.
+ // So, gBS FreePages() servcie is used to free it.
+ //
+ gBS->FreePages (
+ (EFI_PHYSICAL_ADDRESS) (UINTN) (VOID *) RegisterTable->RegisterTableEntry,
+ AllocatePages
+ );
+ }
+
+ //
+ // Adjust the allocated size and register table base address.
+ //
+ RegisterTable->AllocatedSize += EFI_PAGE_SIZE;
+ RegisterTable->RegisterTableEntry = (CPU_REGISTER_TABLE_ENTRY *) (UINTN) Address;
+ }
+
+ //
+ // Append entry in the register table.
+ //
+ RegisterTable->RegisterTableEntry[RegisterTable->TableLength].RegisterType = RegisterType;
+ RegisterTable->RegisterTableEntry[RegisterTable->TableLength].Index = Index;
+ RegisterTable->RegisterTableEntry[RegisterTable->TableLength].ValidBitStart = ValidBitStart;
+ RegisterTable->RegisterTableEntry[RegisterTable->TableLength].ValidBitLength = ValidBitLength;
+ RegisterTable->RegisterTableEntry[RegisterTable->TableLength].Value = Value;
+
+ RegisterTable->TableLength++;
+}
+
+/**
+ Add an entry in the post-SMM-init register table.
+ This function adds an entry in the post-SMM-init register table, with given register type,
+ register index, bit section and value.
+
+ @param[in] ProcessorNumber Handle number of specified logical processor
+ @param[in] RegisterType Type of the register to program
+ @param[in] Index Index of the register to program
+ @param[in] ValidBitStart Start of the bit section
+ @param[in] ValidBitLength Length of the bit section
+ @param[in] Value Value to write
+
+**/
+VOID
+EFIAPI
+WriteRegisterTable (
+ IN UINTN ProcessorNumber,
+ IN REGISTER_TYPE RegisterType,
+ IN UINT32 Index,
+ IN UINT8 ValidBitStart,
+ IN UINT8 ValidBitLength,
+ IN UINT64 Value
+ )
+{
+ WriteRegisterTableEx (
+ FALSE,
+ ProcessorNumber,
+ RegisterType,
+ Index,
+ ValidBitStart,
+ ValidBitLength,
+ Value
+ );
+}
+
+/**
+ Add an entry in the pre-SMM-init register table.
+ This function adds an entry in the pre-SMM-init register table, with given register type,
+ register index, bit section and value.
+
+ @param[in] ProcessorNumber Handle number of specified logical processor
+ @param[in] RegisterType Type of the register to program
+ @param[in] Index Index of the register to program
+ @param[in] ValidBitStart Start of the bit section
+ @param[in] ValidBitLength Length of the bit section
+ @param[in] Value Value to write
+
+**/
+VOID
+EFIAPI
+WritePreSmmInitRegisterTable (
+ IN UINTN ProcessorNumber,
+ IN REGISTER_TYPE RegisterType,
+ IN UINT32 Index,
+ IN UINT8 ValidBitStart,
+ IN UINT8 ValidBitLength,
+ IN UINT64 Value
+ )
+{
+ WriteRegisterTableEx (
+ TRUE,
+ ProcessorNumber,
+ RegisterType,
+ Index,
+ ValidBitStart,
+ ValidBitLength,
+ Value
+ );
+}
+
+/**
+ Set the sequence of processor setting.
+
+ This function sets the a processor setting at the position in
+ setting sequence specified by Index.
+
+ @param[in] Index The zero-based index in the sequence.
+ @param[in] ProcessorNumber Handle number of the processor to set.
+
+ @retval EFI_SUCCESS The sequence successfully modified.
+ @retval EFI_INVALID_PARAMETER Index surpasses the boundary of sequence.
+ @retval EFI_NOT_FOUND Processor specified by ProcessorNumber does not exist.
+
+**/
+EFI_STATUS
+SetSettingSequence (
+ IN UINTN Index,
+ IN UINTN ProcessorNumber
+ )
+{
+ ASSERT (mCpuConfigLibConfigConextBuffer != NULL);
+
+ //
+ // Check whether parameter Index is valid.
+ //
+ if (Index >= mCpuConfigLibConfigConextBuffer->NumberOfProcessors) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Check whether parameter ProcessorNumber is valid.
+ //
+ if (ProcessorNumber >= mCpuConfigLibConfigConextBuffer->NumberOfProcessors) {
+ return EFI_NOT_FOUND;
+ }
+
+ mCpuConfigLibConfigConextBuffer->SettingSequence[Index] = ProcessorNumber;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Set PcdCpuCallbackSignal, and then read the value back.
+
+ This function sets PCD entry PcdCpuCallbackSignal. If there is callback
+ function registered on it, the callback function will be triggered, and
+ it may change the value of PcdCpuCallbackSignal. This function then reads
+ the value of PcdCpuCallbackSignal back, the check whether it has been changed.
+
+ @param[in] Value The value to set to PcdCpuCallbackSignal.
+
+ @retval The value of PcdCpuCallbackSignal read back.
+
+**/
+UINT8
+SetAndReadCpuCallbackSignal (
+ IN UINT8 Value
+ )
+{
+ //
+ // Set PcdCpuCallbackSignal, and trigger callback function
+ //
+ PcdSet8 (PcdCpuCallbackSignal, Value);
+ //
+ // Read the value of PcdCpuCallbackSignal back. It may have been
+ // changed by callback function.
+ //
+ return (PcdGet8 (PcdCpuCallbackSignal));
+}
+
+/**
+ Worker function to create a new feature entry.
+ This is a worker function to create a new feature entry. The new entry is added to
+ the feature list by other functions in the library.
+
+ @param[in] FeatureID The ID of the feature.
+ @param[in] Attribute Feature-specific data.
+
+ @retval CPU_FEATURE_ENTRY Pointer to the created entry.
+
+**/
+CPU_FEATURE_ENTRY *
+CreateFeatureEntry (
+ IN CPU_FEATURE_ID FeatureID,
+ IN VOID *Attribute
+ )
+{
+ CPU_FEATURE_ENTRY *Node;
+
+ Node = AllocateZeroPool (sizeof (CPU_FEATURE_ENTRY));
+ ASSERT (Node != NULL);
+
+ Node->Signature = EFI_CPU_FEATURE_ENTRY_SIGNATURE;
+ Node->FeatureID = FeatureID;
+ Node->Attribute = Attribute;
+
+ return Node;
+}
+
+/**
+ Worker function to search for a feature entry in processor feature list.
+ This is a worker function to search for a feature entry in processor feature list.
+
+ @param[in] ProcessorNumber Handle number of specified logical processor
+ @param[in] FeatureIndex The index of the node in feature list.
+
+ @retval CPU_FEATURE_ENTRY Pointer to the feature node.
+ If FeatureIndex surpasses the length of list, NULL is returned.
+
+**/
+CPU_FEATURE_ENTRY *
+SearchFeatureEntry (
+ IN UINTN ProcessorNumber,
+ IN UINTN FeatureIndex
+ )
+{
+ LIST_ENTRY *List;
+ LIST_ENTRY *Link;
+ CPU_FEATURE_ENTRY *FeatureEntry;
+ UINTN Index;
+
+ List = &mCpuConfigLibConfigConextBuffer->FeatureLinkListEntry[ProcessorNumber];
+
+ //
+ // Get the first node in list. If list is empty, return NULL.
+ //
+ Link = GetFirstNode (List);
+ if (IsNull (List, Link)) {
+ return NULL;
+ }
+
+ //
+ // Try to get the node specified by Index. If not found, return NULL.
+ //
+ for (Index = 1; Index < FeatureIndex; Index++) {
+ Link = GetNextNode (List, Link);
+ if (IsNull (List, Link)) {
+ return NULL;
+ }
+ }
+
+ FeatureEntry = CPU_FEATURE_ENTRY_FROM_LINK (Link);
+ return FeatureEntry;
+}
diff --git a/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/Library/CpuConfigLib/CpuConfig.h b/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/Library/CpuConfigLib/CpuConfig.h
new file mode 100644
index 0000000000..d3dd0a6fdd
--- /dev/null
+++ b/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/Library/CpuConfigLib/CpuConfig.h
@@ -0,0 +1,65 @@
+/** @file
+ Header for the status code data hub logging component
+
+ Copyright (c) 2006 - 2015, 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 _CPU_CONFIG_H_
+#define _CPU_CONFIG_H_
+
+#include <PiDxe.h>
+
+#include <Protocol/MpService.h>
+
+#include <Library/CpuConfigLib.h>
+#include <Library/DebugLib.h>
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/PcdLib.h>
+#include <Library/SocketLga775Lib.h>
+
+/**
+ Worker function to create a new feature entry.
+ This is a worker function to create a new feature entry. The new entry is added to
+ the feature list by other functions in the library.
+
+ @param[in] FeatureID The ID of the feature.
+ @param[in] Attribute Feature-specific data.
+
+ @return CPU_FEATURE_ENTRY The address of the created entry.
+
+**/
+CPU_FEATURE_ENTRY *
+CreateFeatureEntry (
+ IN CPU_FEATURE_ID FeatureID,
+ IN VOID *Attribute
+ );
+
+/**
+ Worker function to search for a feature entry in processor feature list.
+ This is a worker function to search for a feature entry in processor feature list.
+
+ @param[in] ProcessorNumber Handle number of specified logical processor
+ @param[in] FeatureIndex The index of the new node in feature list.
+
+ @retval CPU_FEATURE_ENTRY Pointer to the feature node. If not found, NULL is returned.
+
+**/
+CPU_FEATURE_ENTRY *
+SearchFeatureEntry (
+ IN UINTN ProcessorNumber,
+ IN UINTN FeatureIndex
+ );
+
+#endif
diff --git a/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/Library/CpuConfigLib/CpuConfigLib.inf b/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/Library/CpuConfigLib/CpuConfigLib.inf
new file mode 100644
index 0000000000..cd2e231796
--- /dev/null
+++ b/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/Library/CpuConfigLib/CpuConfigLib.inf
@@ -0,0 +1,57 @@
+## @file
+# Component description file for CPU Configuration Library.
+# CPU Configuration Library implementation that retrieves data in Processor
+# Configuration Context Buffer.
+#
+# Copyright (c) 2006 - 2015, 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 = 0x00010005
+ BASE_NAME = CpuConfigLib
+ FILE_GUID = 041bf780-dc3e-49ab-1111-4b8607540000
+ MODULE_TYPE = DXE_DRIVER
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = CpuConfigLib
+
+ CONSTRUCTOR = CpuConfigLibConstructor
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64
+#
+
+[Sources]
+ CpuConfig.h
+ CpuConfig.c
+
+
+[Packages]
+ MdePkg/MdePkg.dec
+ BraswellPlatformPkg/BraswellPlatformPkg.dec
+
+[LibraryClasses]
+ PcdLib
+ MemoryAllocationLib
+ UefiBootServicesTableLib
+ BaseMemoryLib
+ BaseLib
+ DebugLib
+
+[Pcd]
+ ## SOMETIMES_PRODUCES
+ ## SOMETIMES_CONSUMES
+ gEfiCpuTokenSpaceGuid.PcdCpuCallbackSignal
+
+ ## CONSUMES
+ gEfiCpuTokenSpaceGuid.PcdCpuConfigContextBuffer
diff --git a/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/Library/SmmCpuPlatformHookLibNull/SmmCpuPlatformHookLibNull.c b/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/Library/SmmCpuPlatformHookLibNull/SmmCpuPlatformHookLibNull.c
new file mode 100644
index 0000000000..bd4417da80
--- /dev/null
+++ b/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/Library/SmmCpuPlatformHookLibNull/SmmCpuPlatformHookLibNull.c
@@ -0,0 +1,109 @@
+/** @file
+ CPU Configuration Library.
+
+ Copyright (c) 2006 - 2015, 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 <Library/SmmCpuPlatformHookLib.h>
+
+/**
+ Checks if platform produces a valid SMI.
+
+ This function checks if platform produces a valid SMI. This function is
+ called at SMM entry to detect if this is a spurious SMI. This function
+ must be implemented in an MP safe way because it is called by multiple CPU
+ threads.
+
+ @retval TRUE There is a valid SMI
+ @retval FALSE There is no valid SMI
+
+**/
+BOOLEAN
+EFIAPI
+PlatformValidSmi (
+ VOID
+ )
+{
+ return TRUE;
+}
+
+/**
+ Clears platform top level SMI status bit.
+
+ This function clears platform top level SMI status bit.
+
+ @retval TRUE The platform top level SMI status is cleared.
+ @retval FALSE The paltform top level SMI status cannot be cleared.
+
+**/
+BOOLEAN
+EFIAPI
+ClearTopLevelSmiStatus (
+ VOID
+ )
+{
+ return TRUE;
+}
+
+/**
+ Performs platform specific way of SMM BSP election.
+
+ This function performs platform specific way of SMM BSP election.
+
+ @param[out] IsBsp Output parameter. TRUE: the CPU this function executes
+ on is elected to be the SMM BSP. FALSE: the CPU this
+ function executes on is to be SMM AP.
+
+ @retval EFI_SUCCESS The function executes successfully.
+ @retval EFI_NOT_READY The function does not determine whether this CPU should be
+ BSP or AP. This may occur if hardware init sequence to
+ enable the determination is yet to be done, or the function
+ chooses not to do BSP election and will let SMM CPU driver to
+ use its default BSP election process.
+ @retval EFI_DEVICE_ERROR The function cannot determine whether this CPU should be
+ BSP or AP due to hardware error.
+
+**/
+EFI_STATUS
+EFIAPI
+PlatformSmmBspElection (
+ OUT BOOLEAN *IsBsp
+ )
+{
+ return EFI_NOT_READY;
+}
+
+/**
+ Get platform page table attribute.
+
+ This function gets page table attribute of platform.
+
+ @param[in] Address Obtain the page table entries attribute on this address.
+ @param[in][out] PageSize The size of the page.
+ @param[in][out] NumOfPages Number of page.
+ @param[in][out] PageAttribute Paging Attributes (WB, UC, etc).
+
+ @retval EFI_SUCCESS The platform page table attribute from the address is determined.
+ @retval EFI_UNSUPPORTED The paltform not supoort to get page table attribute from the address.
+
+**/
+EFI_STATUS
+EFIAPI
+GetPlatformPageTableAttribute (
+ IN UINT64 Address,
+ IN OUT SMM_PAGE_SIZE_TYPE *PageSize,
+ IN OUT UINTN *NumOfPages,
+ IN OUT UINTN *PageAttribute
+ )
+{
+ return EFI_UNSUPPORTED;
+}
diff --git a/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/Library/SmmCpuPlatformHookLibNull/SmmCpuPlatformHookLibNull.inf b/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/Library/SmmCpuPlatformHookLibNull/SmmCpuPlatformHookLibNull.inf
new file mode 100644
index 0000000000..127feca553
--- /dev/null
+++ b/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/Library/SmmCpuPlatformHookLibNull/SmmCpuPlatformHookLibNull.inf
@@ -0,0 +1,45 @@
+## @file
+# Component description file for CPU Configuration Library.
+# CPU Configuration Library implementation that retrieves data in Processor
+# Configuration Context Buffer.
+#
+# Copyright (c) 2006 - 2015, 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 Section - statements that will be processed to create a Makefile.
+#
+################################################################################
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = SmmCpuPlatformHookLibNull
+ FILE_GUID = 1328AEBC-010B-46ec-832E-1DB2890C2452
+ MODULE_TYPE = DXE_DRIVER
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = SmmCpuPlatformHookLib
+
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64
+#
+
+
+[Sources]
+ SmmCpuPlatformHookLibNull.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ BraswellPlatformPkg/BraswellPlatformPkg.dec
diff --git a/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/PciHostBridge/PciHostBridge.c b/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/PciHostBridge/PciHostBridge.c
new file mode 100644
index 0000000000..66fbf7c3d2
--- /dev/null
+++ b/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/PciHostBridge/PciHostBridge.c
@@ -0,0 +1,1105 @@
+/** @file
+ Pci Host Bridge driver:
+ Provides the basic interfaces to abstract a PCI Host Bridge Resource Allocation
+
+ Copyright (c) 1999 - 2015, 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 "PciRootBridge.h"
+#include "PciHostBridge.h"
+
+//
+// Hard code: Root Bridge Number within the host bridge
+// Root Bridge's attribute
+// Root Bridge's device path
+// Root Bridge's resource appeture
+//
+static UINTN RootBridgeNumber[1] = { 1 };
+
+static UINT64 RootBridgeAttribute[1][1] = { EFI_PCI_HOST_BRIDGE_COMBINE_MEM_PMEM };
+
+static EFI_PCI_ROOT_BRIDGE_DEVICE_PATH mEfiPciRootBridgeDevicePath[1][1] = {
+ {
+ ACPI_DEVICE_PATH,
+ ACPI_DP,
+ (UINT8) (sizeof (ACPI_HID_DEVICE_PATH)),
+ (UINT8) ((sizeof (ACPI_HID_DEVICE_PATH)) >> 8),
+ EISA_PNP_ID(0x0A03),
+ 0,
+ END_DEVICE_PATH_TYPE,
+ END_ENTIRE_DEVICE_PATH_SUBTYPE,
+ END_DEVICE_PATH_LENGTH,
+ 0
+ }
+};
+
+static PCI_ROOT_BRIDGE_RESOURCE_APPETURE mResAppeture[1][1] = { { 0, 255, 0, 0xffffffff, 0, 1 << 16 } };
+
+static EFI_HANDLE mDriverImageHandle;
+
+//
+// Implementation
+//
+/**
+ Entry point of this driver
+
+ @param[in] ImageHandle @todo add description
+ @param[in] SystemTable @todo add description
+
+ @retval EFI_DEVICE_ERROR Start Failed
+ @retval EFI_SUCCESS Driver Start OK
+
+**/
+EFI_STATUS
+EFIAPI
+PciHostBridgeEntryPoint (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+ UINTN Loop1;
+ UINTN Loop2;
+ PCI_HOST_BRIDGE_INSTANCE *HostBridge;
+ PCI_ROOT_BRIDGE_INSTANCE *PrivateData;
+ EFI_PHYSICAL_ADDRESS PciBaseAddress;
+ UINT64 Length;
+ UINTN ResMemLimit1;
+
+ mDriverImageHandle = ImageHandle;
+
+ //
+ // This system has one Host Bridge (one Root Bridge in this Host Bridge)
+ //
+ //
+ // Create Host Bridge Device Handle
+ //
+ for (Loop1 = 0; Loop1 < HOST_BRIDGE_NUMBER; Loop1++) {
+
+ HostBridge = AllocatePool(sizeof (PCI_HOST_BRIDGE_INSTANCE));
+ if (HostBridge == NULL) {
+ ASSERT (FALSE);
+ return EFI_BUFFER_TOO_SMALL;
+ }
+
+ HostBridge->Signature = PCI_HOST_BRIDGE_SIGNATURE;
+ HostBridge->RootBridgeNumber = RootBridgeNumber[Loop1];
+ HostBridge->ResourceSubmited = FALSE;
+ HostBridge->CanRestarted = TRUE;
+
+ //
+ // InitializeListHead (&HostBridge->Head);
+ //
+ HostBridge->ResAlloc.NotifyPhase = NotifyPhase;
+ HostBridge->ResAlloc.GetNextRootBridge = GetNextRootBridge;
+ HostBridge->ResAlloc.GetAllocAttributes = GetAttributes;
+ HostBridge->ResAlloc.StartBusEnumeration = StartBusEnumeration;
+ HostBridge->ResAlloc.SetBusNumbers = SetBusNumbers;
+ HostBridge->ResAlloc.SubmitResources = SubmitResources;
+ HostBridge->ResAlloc.GetProposedResources = GetProposedResources;
+ HostBridge->ResAlloc.PreprocessController = PreprocessController;
+
+ HostBridge->HostBridgeHandle = NULL;
+ Status = gBS->InstallProtocolInterface (
+ &HostBridge->HostBridgeHandle,
+ &gEfiPciHostBridgeResourceAllocationProtocolGuid,
+ EFI_NATIVE_INTERFACE,
+ &HostBridge->ResAlloc
+ );
+
+ if (EFI_ERROR (Status)) {
+ FreePool(HostBridge);
+ return EFI_DEVICE_ERROR;
+ }
+
+ //
+ // Create Root Bridge Device Handle in this Host Bridge
+ //
+ InitializeListHead (&HostBridge->Head);
+
+ for (Loop2 = 0; Loop2 < HostBridge->RootBridgeNumber; Loop2++) {
+
+ PrivateData = AllocatePool(sizeof (PCI_ROOT_BRIDGE_INSTANCE));
+ if (PrivateData == NULL) {
+ ASSERT (FALSE);
+ return EFI_BUFFER_TOO_SMALL;
+ }
+ PrivateData->Signature = PCI_ROOT_BRIDGE_SIGNATURE;
+
+ PrivateData->DevicePath = (EFI_DEVICE_PATH_PROTOCOL *) &mEfiPciRootBridgeDevicePath[Loop1][Loop2];
+ RootBridgeConstructor (
+ &PrivateData->Io,
+ HostBridge->HostBridgeHandle,
+ RootBridgeAttribute[Loop1][Loop2],
+ &mResAppeture[Loop1][Loop2]
+ );
+
+ PrivateData->Handle = NULL;
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &PrivateData->Handle,
+ &gEfiDevicePathProtocolGuid,
+ PrivateData->DevicePath,
+ &gEfiPciRootBridgeIoProtocolGuid,
+ &PrivateData->Io,
+ NULL
+ );
+ if (EFI_ERROR (Status)) {
+ FreePool(PrivateData);
+ return EFI_DEVICE_ERROR;
+ }
+
+ InsertTailList (&HostBridge->Head, &PrivateData->Link);
+ }
+ }
+
+ Status = gDS->AddIoSpace (
+ EfiGcdIoTypeIo,
+ PcdGet16 (PcdPciReservedIobase),
+ PcdGet16 (PcdPciReservedIoLimit) - PcdGet16 (PcdPciReservedIobase) + 1
+ );
+
+ //
+ // PCI memory space from top of usable DRAM to TOP of supported memory 3.5GBytes.
+ //
+ PciBaseAddress = PcdGet32 (PcdMmioBase);
+
+ ResMemLimit1 = PcdGet32 (PcdPciReservedMemLimit);
+ if (ResMemLimit1 == 0) {
+ ResMemLimit1 = (UINTN) PcdGet64 (PcdPciExpressBaseAddress);
+ }
+
+ Length = ResMemLimit1 - PciBaseAddress;
+
+ if (Length) {
+ DEBUG ((EFI_D_ERROR, " Allocating PCI space from 0x%X to 0x%X\n", (UINT32) PciBaseAddress, (UINT32) (PciBaseAddress + Length - 1)));
+ Status = gDS->AddMemorySpace (
+ EfiGcdMemoryTypeMemoryMappedIo,
+ PciBaseAddress,
+ Length,
+ 0
+ );
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Enter a certain phase of the PCI enumeration process.
+
+ @param[in] This The EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL instance
+ @param[in] Phase The phase during enumeration
+
+ @retval EFI_SUCCESS
+ @retval EFI_INVALID_PARAMETER
+
+**/
+EFI_STATUS
+EFIAPI
+NotifyPhase (
+ IN EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL *This,
+ IN EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PHASE Phase
+ )
+{
+ PCI_HOST_BRIDGE_INSTANCE *HostBridgeInstance;
+ PCI_ROOT_BRIDGE_INSTANCE *RootBridgeInstance;
+ PCI_RESOURCE_TYPE Index;
+ LIST_ENTRY *List;
+ EFI_PHYSICAL_ADDRESS BaseAddress;
+ UINT64 AddrLen;
+ UINTN BitsOfAlignment;
+ UINT64 Alignment;
+ EFI_STATUS Status;
+ EFI_STATUS ReturnStatus;
+
+ HostBridgeInstance = INSTANCE_FROM_RESOURCE_ALLOCATION_THIS (This);
+
+ switch (Phase) {
+ case EfiPciHostBridgeBeginEnumeration:
+ if (HostBridgeInstance->CanRestarted) {
+ //
+ // Reset the Each Root Bridge
+ //
+ List = HostBridgeInstance->Head.ForwardLink;
+
+ while (List != &HostBridgeInstance->Head) {
+ RootBridgeInstance = DRIVER_INSTANCE_FROM_LIST_ENTRY (List);
+ for (Index = TypeIo; Index < TypeMax; Index++) {
+ RootBridgeInstance->ResAllocNode[Index].Type = Index;
+ RootBridgeInstance->ResAllocNode[Index].Base = 0;
+ RootBridgeInstance->ResAllocNode[Index].Length = 0;
+ RootBridgeInstance->ResAllocNode[Index].Status = ResNone;
+ }
+
+ List = List->ForwardLink;
+ }
+
+ HostBridgeInstance->ResourceSubmited = FALSE;
+ HostBridgeInstance->CanRestarted = TRUE;
+ } else {
+ //
+ // Can not restart
+ //
+ return EFI_NOT_READY;
+ }
+ break;
+
+ case EfiPciHostBridgeEndEnumeration:
+ break;
+
+ case EfiPciHostBridgeBeginBusAllocation:
+ //
+ // No specific action is required here, can perform any chipset specific programing
+ //
+ HostBridgeInstance->CanRestarted = FALSE;
+ return EFI_SUCCESS;
+ break;
+
+ case EfiPciHostBridgeEndBusAllocation:
+ //
+ // No specific action is required here, can perform any chipset specific programing
+ //
+ return EFI_SUCCESS;
+ break;
+
+ case EfiPciHostBridgeBeginResourceAllocation:
+ //
+ // No specific action is required here, can perform any chipset specific programing
+ //
+ return EFI_SUCCESS;
+ break;
+
+ case EfiPciHostBridgeAllocateResources:
+ ReturnStatus = EFI_SUCCESS;
+ if (HostBridgeInstance->ResourceSubmited) {
+ //
+ // Take care of the resource dependencies between the root bridges
+ //
+ List = HostBridgeInstance->Head.ForwardLink;
+
+ while (List != &HostBridgeInstance->Head) {
+ RootBridgeInstance = DRIVER_INSTANCE_FROM_LIST_ENTRY (List);
+ for (Index = TypeIo; Index < TypeBus; Index++) {
+ if (RootBridgeInstance->ResAllocNode[Index].Status != ResNone) {
+
+ AddrLen = RootBridgeInstance->ResAllocNode[Index].Length;
+ Alignment = RootBridgeInstance->ResAllocNode[Index].Alignment;
+
+ //
+ // Get the number of '1' in Alignment.
+ //
+ for (BitsOfAlignment = 0; Alignment != 0; BitsOfAlignment++) {
+ Alignment = RShiftU64 (Alignment, 1);
+ }
+
+ switch (Index) {
+ case TypeIo:
+ //
+ // It is impossible for this chipset to align 0xFFFF for IO16
+ // So clear it
+ //
+ if (BitsOfAlignment >= 16) {
+ BitsOfAlignment = 0;
+ }
+
+ Status = gDS->AllocateIoSpace (
+ EfiGcdAllocateAnySearchBottomUp,
+ EfiGcdIoTypeIo,
+ BitsOfAlignment,
+ AddrLen,
+ &BaseAddress,
+ mDriverImageHandle,
+ NULL
+ );
+
+ if (!EFI_ERROR (Status)) {
+ RootBridgeInstance->ResAllocNode[Index].Base = (UINTN) BaseAddress;
+ RootBridgeInstance->ResAllocNode[Index].Status = ResAllocated;
+ } else {
+ ReturnStatus = Status;
+ if (Status != EFI_OUT_OF_RESOURCES) {
+ RootBridgeInstance->ResAllocNode[Index].Length = 0;
+ }
+ }
+
+ break;
+
+ case TypeMem32:
+ //
+ // It is impossible for this chipset to align 0xFFFFFFFF for Mem32
+ // So clear it
+ //
+ if (BitsOfAlignment >= 32) {
+ BitsOfAlignment = 0;
+ }
+
+ Status = gDS->AllocateMemorySpace (
+ EfiGcdAllocateAnySearchBottomUp,
+ EfiGcdMemoryTypeMemoryMappedIo,
+ BitsOfAlignment,
+ AddrLen,
+ &BaseAddress,
+ mDriverImageHandle,
+ NULL
+ );
+
+ if (!EFI_ERROR (Status)) {
+ //
+ // We were able to allocate the PCI memory
+ //
+ RootBridgeInstance->ResAllocNode[Index].Base = (UINTN) BaseAddress;
+ RootBridgeInstance->ResAllocNode[Index].Status = ResAllocated;
+
+ } else {
+ //
+ // Not able to allocate enough PCI memory
+ //
+ ReturnStatus = Status;
+
+ if (Status != EFI_OUT_OF_RESOURCES) {
+ RootBridgeInstance->ResAllocNode[Index].Length = 0;
+ }
+ //
+ // Reset
+ //
+ gRT->ResetSystem (EfiResetCold, EFI_SUCCESS, 0, NULL);
+
+ }
+ break;
+
+ case TypePMem32:
+ case TypeMem64:
+ case TypePMem64:
+ ReturnStatus = EFI_ABORTED;
+ break;
+ default:
+ break;
+ }
+ //
+ // end switch
+ //
+ }
+ }
+
+ List = List->ForwardLink;
+ }
+
+ return ReturnStatus;
+
+ } else {
+ return EFI_NOT_READY;
+ }
+ break;
+
+ case EfiPciHostBridgeSetResources:
+ break;
+
+ case EfiPciHostBridgeFreeResources:
+ ReturnStatus = EFI_SUCCESS;
+ List = HostBridgeInstance->Head.ForwardLink;
+ while (List != &HostBridgeInstance->Head) {
+ RootBridgeInstance = DRIVER_INSTANCE_FROM_LIST_ENTRY (List);
+ for (Index = TypeIo; Index < TypeBus; Index++) {
+ if (RootBridgeInstance->ResAllocNode[Index].Status == ResAllocated) {
+ AddrLen = RootBridgeInstance->ResAllocNode[Index].Length;
+ BaseAddress = RootBridgeInstance->ResAllocNode[Index].Base;
+ switch (Index) {
+ case TypeIo:
+ Status = gDS->FreeIoSpace (BaseAddress, AddrLen);
+ if (EFI_ERROR (Status)) {
+ ReturnStatus = Status;
+ }
+ break;
+
+ case TypeMem32:
+ Status = gDS->FreeMemorySpace (BaseAddress, AddrLen);
+ if (EFI_ERROR (Status)) {
+ ReturnStatus = Status;
+ }
+ break;
+
+ case TypePMem32:
+ break;
+
+ case TypeMem64:
+ break;
+
+ case TypePMem64:
+ break;
+ default:
+ break;
+ }
+ //
+ // end switch
+ //
+ RootBridgeInstance->ResAllocNode[Index].Type = Index;
+ RootBridgeInstance->ResAllocNode[Index].Base = 0;
+ RootBridgeInstance->ResAllocNode[Index].Length = 0;
+ RootBridgeInstance->ResAllocNode[Index].Status = ResNone;
+ }
+ }
+
+ List = List->ForwardLink;
+ }
+
+ HostBridgeInstance->ResourceSubmited = FALSE;
+ HostBridgeInstance->CanRestarted = TRUE;
+ return ReturnStatus;
+ break;
+
+ case EfiPciHostBridgeEndResourceAllocation:
+ HostBridgeInstance->CanRestarted = FALSE;
+ break;
+
+ default:
+ return EFI_INVALID_PARAMETER;
+ }
+ //
+ // end switch
+ //
+ return EFI_SUCCESS;
+}
+
+/**
+ @todo add description
+
+**/
+EFI_STATUS
+EFIAPI
+GetNextRootBridge (
+ IN EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL *This,
+ IN OUT EFI_HANDLE *RootBridgeHandle
+ )
+{
+ BOOLEAN NoRootBridge;
+ LIST_ENTRY *List;
+ PCI_HOST_BRIDGE_INSTANCE *HostBridgeInstance;
+ PCI_ROOT_BRIDGE_INSTANCE *RootBridgeInstance;
+
+ NoRootBridge = TRUE;
+ HostBridgeInstance = INSTANCE_FROM_RESOURCE_ALLOCATION_THIS (This);
+ List = HostBridgeInstance->Head.ForwardLink;
+
+ while (List != &HostBridgeInstance->Head) {
+ NoRootBridge = FALSE;
+ RootBridgeInstance = DRIVER_INSTANCE_FROM_LIST_ENTRY (List);
+ if (*RootBridgeHandle == NULL) {
+ //
+ // Return the first Root Bridge Handle of the Host Bridge
+ //
+ *RootBridgeHandle = RootBridgeInstance->Handle;
+ return EFI_SUCCESS;
+ } else {
+ if (*RootBridgeHandle == RootBridgeInstance->Handle) {
+ //
+ // Get next if have
+ //
+ List = List->ForwardLink;
+ if (List != &HostBridgeInstance->Head) {
+ RootBridgeInstance = DRIVER_INSTANCE_FROM_LIST_ENTRY (List);
+ *RootBridgeHandle = RootBridgeInstance->Handle;
+ return EFI_SUCCESS;
+ } else {
+ return EFI_NOT_FOUND;
+ }
+ }
+ }
+
+ List = List->ForwardLink;
+ }
+ //
+ // end while
+ //
+ if (NoRootBridge) {
+ return EFI_NOT_FOUND;
+ } else {
+ return EFI_INVALID_PARAMETER;
+ }
+}
+
+/**
+ Returns the attributes of a PCI Root Bridge.
+
+ @param[in] This The EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_ PROTOCOL instance
+ @param[in] RootBridgeHandle The device handle of the PCI Root Bridge
+ that the caller is interested in
+ @param[out] Attribute The pointer to attributes of the PCI Root Bridge
+
+ @retval
+
+**/
+EFI_STATUS
+EFIAPI
+GetAttributes (
+ IN EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL *This,
+ IN EFI_HANDLE RootBridgeHandle,
+ OUT UINT64 *Attributes
+ )
+{
+ LIST_ENTRY *List;
+ PCI_HOST_BRIDGE_INSTANCE *HostBridgeInstance;
+ PCI_ROOT_BRIDGE_INSTANCE *RootBridgeInstance;
+
+ if (Attributes == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ HostBridgeInstance = INSTANCE_FROM_RESOURCE_ALLOCATION_THIS (This);
+ List = HostBridgeInstance->Head.ForwardLink;
+
+ while (List != &HostBridgeInstance->Head) {
+ RootBridgeInstance = DRIVER_INSTANCE_FROM_LIST_ENTRY (List);
+ if (RootBridgeHandle == RootBridgeInstance->Handle) {
+ *Attributes = RootBridgeInstance->RootBridgeAttrib;
+ return EFI_SUCCESS;
+ }
+
+ List = List->ForwardLink;
+ }
+ //
+ // RootBridgeHandle is not an EFI_HANDLE
+ // that was returned on a previous call to GetNextRootBridge()
+ //
+ return EFI_INVALID_PARAMETER;
+}
+
+/**
+ This is the request from the PCI enumerator to set up
+ the specified PCI Root Bridge for bus enumeration process.
+
+ @param[in] This The EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_ PROTOCOL instance
+ @param[in] RootBridgeHandle The PCI Root Bridge to be set up
+ @param[in] Configuration Pointer to the pointer to the PCI bus resource descriptor
+
+ @retval EFI_OUT_OF_RESOURCES
+ @retval EFI_SUCCESS
+ @retval EFI_INVALID_PARAMETER
+
+**/
+EFI_STATUS
+EFIAPI
+StartBusEnumeration (
+ IN EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL *This,
+ IN EFI_HANDLE RootBridgeHandle,
+ OUT VOID **Configuration
+ )
+{
+ LIST_ENTRY *List;
+ PCI_HOST_BRIDGE_INSTANCE *HostBridgeInstance;
+ PCI_ROOT_BRIDGE_INSTANCE *RootBridgeInstance;
+ VOID *Buffer;
+ UINT8 *Temp;
+ UINT64 BusStart;
+ UINT64 BusEnd;
+
+ HostBridgeInstance = INSTANCE_FROM_RESOURCE_ALLOCATION_THIS (This);
+ List = HostBridgeInstance->Head.ForwardLink;
+
+ while (List != &HostBridgeInstance->Head) {
+ RootBridgeInstance = DRIVER_INSTANCE_FROM_LIST_ENTRY (List);
+ if (RootBridgeHandle == RootBridgeInstance->Handle) {
+ //
+ // Set up the Root Bridge for Bus Enumeration
+ //
+ BusStart = RootBridgeInstance->BusBase;
+ BusEnd = RootBridgeInstance->BusLimit;
+ //
+ // Program the Hardware(if needed) if error return EFI_DEVICE_ERROR
+ //
+
+ Buffer = AllocatePool(sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR) + sizeof (EFI_ACPI_END_TAG_DESCRIPTOR));
+ if (!Buffer) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ Temp = (UINT8 *) Buffer;
+
+ ((EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *) Temp)->Desc = 0x8A;
+ ((EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *) Temp)->Len = 0x2B;
+ ((EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *) Temp)->ResType = 2;
+ ((EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *) Temp)->GenFlag = 0;
+ ((EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *) Temp)->SpecificFlag = 0;
+ ((EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *) Temp)->AddrSpaceGranularity = 0;
+ ((EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *) Temp)->AddrRangeMin = BusStart;
+ ((EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *) Temp)->AddrRangeMax = 0;
+ ((EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *) Temp)->AddrTranslationOffset = 0;
+ ((EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *) Temp)->AddrLen = BusEnd - BusStart + 1;
+
+ Temp = Temp + sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR);
+ ((EFI_ACPI_END_TAG_DESCRIPTOR *) Temp)->Desc = 0x79;
+ ((EFI_ACPI_END_TAG_DESCRIPTOR *) Temp)->Checksum = 0x0;
+
+ *Configuration = Buffer;
+ return EFI_SUCCESS;
+ }
+
+ List = List->ForwardLink;
+ }
+
+ return EFI_INVALID_PARAMETER;
+}
+
+/**
+ This function programs the PCI Root Bridge hardware so that
+ it decodes the specified PCI bus range
+
+ @param[in] This The EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_ PROTOCOL instance
+ @param[in] RootBridgeHandle The PCI Root Bridge whose bus range is to be programmed
+ @param[in] Configuration The pointer to the PCI bus resource descriptor
+
+ @retval EFI_SUCCESS
+ @retval EFI_INVALID_PARAMETER
+
+**/
+EFI_STATUS
+EFIAPI
+SetBusNumbers (
+ IN EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL *This,
+ IN EFI_HANDLE RootBridgeHandle,
+ IN VOID *Configuration
+ )
+{
+ LIST_ENTRY *List;
+ PCI_HOST_BRIDGE_INSTANCE *HostBridgeInstance;
+ PCI_ROOT_BRIDGE_INSTANCE *RootBridgeInstance;
+ UINT8 *Ptr;
+ UINTN BusStart;
+ UINTN BusEnd;
+ UINTN BusLen;
+
+ if (Configuration == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Ptr = Configuration;
+
+ //
+ // Check the Configuration is valid
+ //
+ if (*Ptr != ACPI_ADDRESS_SPACE_DESCRIPTOR) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (((EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *) Ptr)->ResType != 2) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Ptr += sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR);
+ if (*Ptr != ACPI_END_TAG_DESCRIPTOR) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ HostBridgeInstance = INSTANCE_FROM_RESOURCE_ALLOCATION_THIS (This);
+ List = HostBridgeInstance->Head.ForwardLink;
+
+ Ptr = Configuration;
+
+ while (List != &HostBridgeInstance->Head) {
+ RootBridgeInstance = DRIVER_INSTANCE_FROM_LIST_ENTRY (List);
+ if (RootBridgeHandle == RootBridgeInstance->Handle) {
+ BusStart = (UINTN) ((EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *) Ptr)->AddrRangeMin;
+ BusLen = (UINTN) ((EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *) Ptr)->AddrLen;
+ BusEnd = BusStart + BusLen - 1;
+
+ if (BusStart > BusEnd) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if ((BusStart < RootBridgeInstance->BusBase) || (BusEnd > RootBridgeInstance->BusLimit)) {
+ return EFI_INVALID_PARAMETER;
+ }
+ //
+ // Update the Bus Range
+ //
+ RootBridgeInstance->ResAllocNode[TypeBus].Base = BusStart;
+ RootBridgeInstance->ResAllocNode[TypeBus].Length = BusLen;
+ RootBridgeInstance->ResAllocNode[TypeBus].Status = ResAllocated;
+
+ //
+ // Program the Root Bridge Hardware
+ //
+ return EFI_SUCCESS;
+ }
+
+ List = List->ForwardLink;
+ }
+
+ return EFI_INVALID_PARAMETER;
+}
+
+/**
+ Submits the I/O and memory resource requirements for the specified PCI Root Bridge
+
+ @param[in] This The EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_ PROTOCOL instance
+ @param[in] RootBridgeHandle The PCI Root Bridge whose I/O and memory resource requirements
+ are being submitted
+ @param[in] Configuration The pointer to the PCI I/O and PCI memory resource descriptor
+
+ @retval EFI_SUCCESS
+ @retval EFI_INVALID_PARAMETER
+
+**/
+EFI_STATUS
+EFIAPI
+SubmitResources (
+ IN EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL *This,
+ IN EFI_HANDLE RootBridgeHandle,
+ IN VOID *Configuration
+ )
+{
+ LIST_ENTRY *List;
+ PCI_HOST_BRIDGE_INSTANCE *HostBridgeInstance;
+ PCI_ROOT_BRIDGE_INSTANCE *RootBridgeInstance;
+ UINT8 *Temp;
+ EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *ptr;
+ UINT64 AddrLen;
+ UINT64 Alignment;
+
+ //
+ // Check the input parameter: Configuration
+ //
+ if (Configuration == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ HostBridgeInstance = INSTANCE_FROM_RESOURCE_ALLOCATION_THIS (This);
+ List = HostBridgeInstance->Head.ForwardLink;
+
+ Temp = (UINT8 *) Configuration;
+ while (*Temp == 0x8A) {
+ Temp += sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR);
+ }
+
+ if (*Temp != 0x79) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Temp = (UINT8 *) Configuration;
+ while (List != &HostBridgeInstance->Head) {
+ RootBridgeInstance = DRIVER_INSTANCE_FROM_LIST_ENTRY (List);
+ if (RootBridgeHandle == RootBridgeInstance->Handle) {
+ while (*Temp == 0x8A) {
+ ptr = (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *) Temp;
+
+ //
+ // Check Address Length
+ //
+ if (ptr->AddrLen > 0xffffffff) {
+ return EFI_INVALID_PARAMETER;
+ }
+ //
+ // Check address range alignment
+ //
+ if (ptr->AddrRangeMax >= 0xffffffff || ptr->AddrRangeMax != (Power2MaxMemory (ptr->AddrRangeMax + 1) - 1)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ switch (ptr->ResType) {
+ case 0:
+ //
+ // Check invalid Address Sapce Granularity
+ //
+ if (ptr->AddrSpaceGranularity != 32) {
+ return EFI_INVALID_PARAMETER;
+ }
+ //
+ // check the memory resource request is supported by PCI root bridge
+ //
+ if (RootBridgeInstance->RootBridgeAttrib == EFI_PCI_HOST_BRIDGE_COMBINE_MEM_PMEM && ptr->SpecificFlag == 0x06) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ AddrLen = ptr->AddrLen;
+ Alignment = ptr->AddrRangeMax;
+ if (ptr->AddrSpaceGranularity == 32) {
+ if (ptr->SpecificFlag == 0x06) {
+ //
+ // Apply from GCD
+ //
+ RootBridgeInstance->ResAllocNode[TypePMem32].Status = ResSubmitted;
+ } else {
+ RootBridgeInstance->ResAllocNode[TypeMem32].Length = AddrLen;
+ RootBridgeInstance->ResAllocNode[TypeMem32].Alignment = Alignment;
+ RootBridgeInstance->ResAllocNode[TypeMem32].Status = ResRequested;
+ HostBridgeInstance->ResourceSubmited = TRUE;
+ }
+ }
+
+ if (ptr->AddrSpaceGranularity == 64) {
+ if (ptr->SpecificFlag == 0x06) {
+ RootBridgeInstance->ResAllocNode[TypePMem64].Status = ResSubmitted;
+ } else {
+ RootBridgeInstance->ResAllocNode[TypeMem64].Status = ResSubmitted;
+ }
+ }
+ break;
+
+ case 1:
+ AddrLen = (UINTN) ptr->AddrLen;
+ Alignment = (UINTN) ptr->AddrRangeMax;
+ RootBridgeInstance->ResAllocNode[TypeIo].Length = AddrLen;
+ RootBridgeInstance->ResAllocNode[TypeIo].Alignment = Alignment;
+ RootBridgeInstance->ResAllocNode[TypeIo].Status = ResRequested;
+ HostBridgeInstance->ResourceSubmited = TRUE;
+ break;
+
+ default:
+ break;
+ }
+
+ Temp += sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR);
+ }
+
+ return EFI_SUCCESS;
+ }
+
+ List = List->ForwardLink;
+ }
+
+ return EFI_INVALID_PARAMETER;
+}
+
+/**
+ This function returns the proposed resource settings for the specified
+ PCI Root Bridge.
+
+ @param[in] This The EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_ PROTOCOL instance
+ @param[in] RootBridgeHandle The PCI Root Bridge handle
+ @param[in] Configuration The pointer to the pointer to the PCI I/O
+ and memory resource descriptor
+
+ @retval EFI_SUCCESS
+ @retval EFI_OUT_OF_RESOURCES
+ @retval EFI_INVALID_PARAMETER
+
+**/
+EFI_STATUS
+EFIAPI
+GetProposedResources (
+ IN EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL *This,
+ IN EFI_HANDLE RootBridgeHandle,
+ OUT VOID **Configuration
+ )
+{
+ LIST_ENTRY *List;
+ PCI_HOST_BRIDGE_INSTANCE *HostBridgeInstance;
+ PCI_ROOT_BRIDGE_INSTANCE *RootBridgeInstance;
+ UINTN Index;
+ UINTN Number;
+ VOID *Buffer;
+ UINT8 *Temp;
+ EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *ptr;
+ UINT64 ResStatus;
+
+ Buffer = NULL;
+ Number = 0;
+
+ //
+ // Get the Host Bridge Instance from the resource allocation protocol
+ //
+ HostBridgeInstance = INSTANCE_FROM_RESOURCE_ALLOCATION_THIS (This);
+ List = HostBridgeInstance->Head.ForwardLink;
+
+ //
+ // Enumerate the root bridges in this host bridge
+ //
+ while (List != &HostBridgeInstance->Head) {
+ RootBridgeInstance = DRIVER_INSTANCE_FROM_LIST_ENTRY (List);
+ if (RootBridgeHandle == RootBridgeInstance->Handle) {
+ for (Index = 0; Index < TypeBus; Index++) {
+ if (RootBridgeInstance->ResAllocNode[Index].Status != ResNone) {
+ Number++;
+ }
+ }
+
+ if (Number > 0) {
+
+ Buffer = AllocateZeroPool(Number * sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR) + sizeof (EFI_ACPI_END_TAG_DESCRIPTOR));
+
+ if (!Buffer) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ }
+ else {
+ return EFI_NOT_FOUND;
+ }
+
+ Temp = Buffer;
+ for (Index = 0; Index < TypeBus; Index++) {
+ if (RootBridgeInstance->ResAllocNode[Index].Status != ResNone) {
+ ptr = (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *) Temp;
+ ResStatus = RootBridgeInstance->ResAllocNode[Index].Status;
+
+ switch (Index) {
+ case TypeIo:
+ //
+ // Io
+ //
+ ptr->Desc = 0x8A;
+ ptr->Len = 0x2B;
+ ptr->ResType = 1;
+ ptr->GenFlag = 0;
+ ptr->SpecificFlag = 0;
+ ptr->AddrRangeMin = RootBridgeInstance->ResAllocNode[Index].Base;
+ ptr->AddrRangeMax = 0;
+ ptr->AddrTranslationOffset = (ResStatus == ResAllocated) ? EFI_RESOURCE_SATISFIED : EFI_RESOURCE_LESS;
+ ptr->AddrLen = RootBridgeInstance->ResAllocNode[Index].Length;
+ break;
+
+ case TypeMem32:
+ //
+ // Memory 32
+ //
+ ptr->Desc = 0x8A;
+ ptr->Len = 0x2B;
+ ptr->ResType = 0;
+ ptr->GenFlag = 0;
+ ptr->SpecificFlag = 0;
+ ptr->AddrSpaceGranularity = 32;
+ ptr->AddrRangeMin = RootBridgeInstance->ResAllocNode[Index].Base;
+ ptr->AddrRangeMax = 0;
+ ptr->AddrTranslationOffset = (ResStatus == ResAllocated) ? EFI_RESOURCE_SATISFIED : EFI_RESOURCE_LESS;
+ ptr->AddrLen = RootBridgeInstance->ResAllocNode[Index].Length;
+ break;
+
+ case TypePMem32:
+ //
+ // Prefetch memory 32
+ //
+ ptr->Desc = 0x8A;
+ ptr->Len = 0x2B;
+ ptr->ResType = 0;
+ ptr->GenFlag = 0;
+ ptr->SpecificFlag = 6;
+ ptr->AddrSpaceGranularity = 32;
+ ptr->AddrRangeMin = 0;
+ ptr->AddrRangeMax = 0;
+ ptr->AddrTranslationOffset = EFI_RESOURCE_NONEXISTENT;
+ ptr->AddrLen = 0;
+ break;
+
+ case TypeMem64:
+ //
+ // Memory 64
+ //
+ ptr->Desc = 0x8A;
+ ptr->Len = 0x2B;
+ ptr->ResType = 0;
+ ptr->GenFlag = 0;
+ ptr->SpecificFlag = 0;
+ ptr->AddrSpaceGranularity = 64;
+ ptr->AddrRangeMin = 0;
+ ptr->AddrRangeMax = 0;
+ ptr->AddrTranslationOffset = EFI_RESOURCE_NONEXISTENT;
+ ptr->AddrLen = 0;
+ break;
+
+ case TypePMem64:
+ //
+ // Prefetch memory 64
+ //
+ ptr->Desc = 0x8A;
+ ptr->Len = 0x2B;
+ ptr->ResType = 0;
+ ptr->GenFlag = 0;
+ ptr->SpecificFlag = 6;
+ ptr->AddrSpaceGranularity = 64;
+ ptr->AddrRangeMin = 0;
+ ptr->AddrRangeMax = 0;
+ ptr->AddrTranslationOffset = EFI_RESOURCE_NONEXISTENT;
+ ptr->AddrLen = 0;
+ break;
+ }
+
+ Temp += sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR);
+ }
+ }
+
+ ((EFI_ACPI_END_TAG_DESCRIPTOR *) Temp)->Desc = 0x79;
+ ((EFI_ACPI_END_TAG_DESCRIPTOR *) Temp)->Checksum = 0x0;
+
+ *Configuration = Buffer;
+
+ return EFI_SUCCESS;
+ }
+
+ List = List->ForwardLink;
+ }
+
+ return EFI_INVALID_PARAMETER;
+}
+
+/**
+ This function is called for all the PCI controllers that the PCI
+ bus driver finds. Can be used to Preprogram the controller.
+
+ @param[in] This The EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_ PROTOCOL instance
+ @param[in] RootBridgeHandle The PCI Root Bridge handle
+ @param[in] PciBusAddress Address of the controller on the PCI bus
+ @param[in] Phase The Phase during resource allocation
+
+ @retval EFI_SUCCESS
+
+**/
+EFI_STATUS
+EFIAPI
+PreprocessController (
+ IN EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL *This,
+ IN EFI_HANDLE RootBridgeHandle,
+ IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_PCI_ADDRESS PciAddress,
+ IN EFI_PCI_CONTROLLER_RESOURCE_ALLOCATION_PHASE Phase
+ )
+{
+ PCI_HOST_BRIDGE_INSTANCE *HostBridgeInstance;
+ PCI_ROOT_BRIDGE_INSTANCE *RootBridgeInstance;
+ LIST_ENTRY *List;
+
+ HostBridgeInstance = INSTANCE_FROM_RESOURCE_ALLOCATION_THIS (This);
+ List = HostBridgeInstance->Head.ForwardLink;
+
+ //
+ // Enumerate the root bridges in this host bridge
+ //
+ while (List != &HostBridgeInstance->Head) {
+ RootBridgeInstance = DRIVER_INSTANCE_FROM_LIST_ENTRY (List);
+ if (RootBridgeHandle == RootBridgeInstance->Handle) {
+ return EFI_SUCCESS;
+ }
+
+ List = List->ForwardLink;
+ }
+
+ return EFI_INVALID_PARAMETER;
+}
+
+/**
+ @todo Add function description
+
+ @param[in] MemoryLength - @todo add argument description
+
+ @retval @todo add return values
+
+**/
+UINT64
+Power2MaxMemory (
+ IN UINT64 MemoryLength
+ )
+{
+ UINT64 Result;
+
+ if (RShiftU64 (MemoryLength, 32)) {
+ Result = LShiftU64 ((UINT64) GetPowerOfTwo64 ( RShiftU64 (MemoryLength, 32)), 32);
+ } else {
+ Result = (UINT64) GetPowerOfTwo64 ( MemoryLength);
+ }
+
+ return Result;
+}
diff --git a/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/PciHostBridge/PciHostBridge.h b/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/PciHostBridge/PciHostBridge.h
new file mode 100644
index 0000000000..a6d1f09d1f
--- /dev/null
+++ b/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/PciHostBridge/PciHostBridge.h
@@ -0,0 +1,157 @@
+/** @file
+ The Header file of the Pci Host Bridge Driver.
+
+ Copyright (c) 1999 - 2015, 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 _PCI_HOST_BRIDGE_H_
+#define _PCI_HOST_BRIDGE_H_
+
+//
+// Disable the warning since LIST_ENTRY was defined in EDKII
+// and EFI_LIST_ENTRY was defined in PCI_HOST_BRIDGE_INSTANCE
+//
+#ifndef __GNUC__
+#pragma warning(disable: 4133)
+#endif
+
+//
+// Hard code the host bridge number in the platform.
+// In this chipset, there is only one host bridge.
+//
+#define HOST_BRIDGE_NUMBER 1
+
+#define PCI_HOST_BRIDGE_SIGNATURE SIGNATURE_32 ('e', 'h', 's', 't')
+typedef struct {
+ UINTN Signature;
+ EFI_HANDLE HostBridgeHandle;
+ UINTN RootBridgeNumber;
+ LIST_ENTRY Head;
+ BOOLEAN ResourceSubmited;
+ BOOLEAN CanRestarted;
+
+ EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL ResAlloc;
+} PCI_HOST_BRIDGE_INSTANCE;
+
+#define INSTANCE_FROM_RESOURCE_ALLOCATION_THIS(a) CR (a, PCI_HOST_BRIDGE_INSTANCE, ResAlloc, PCI_HOST_BRIDGE_SIGNATURE)
+
+//
+// HostBridge Resource Allocation interface
+//
+/**
+ @todo add description
+
+**/
+EFI_STATUS
+EFIAPI
+NotifyPhase (
+ IN EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL *This,
+ IN EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PHASE Phase
+ );
+
+/**
+ @todo add description
+
+**/
+EFI_STATUS
+EFIAPI
+GetNextRootBridge (
+ IN EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL *This,
+ IN OUT EFI_HANDLE *RootBridgeHandle
+ );
+
+/**
+ @todo add description
+
+**/
+EFI_STATUS
+EFIAPI
+GetAttributes (
+ IN EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL *This,
+ IN EFI_HANDLE RootBridgeHandle,
+ OUT UINT64 *Attributes
+ );
+
+/**
+ @todo add description
+
+**/
+EFI_STATUS
+EFIAPI
+StartBusEnumeration (
+ IN EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL *This,
+ IN EFI_HANDLE RootBridgeHandle,
+ OUT VOID **Configuration
+ );
+
+/**
+ @todo add description
+
+**/
+EFI_STATUS
+EFIAPI
+SetBusNumbers (
+ IN EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL *This,
+ IN EFI_HANDLE RootBridgeHandle,
+ IN VOID *Configuration
+ );
+
+/**
+ @todo add description
+
+**/
+EFI_STATUS
+EFIAPI
+SubmitResources (
+ IN EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL *This,
+ IN EFI_HANDLE RootBridgeHandle,
+ IN VOID *Configuration
+ );
+
+/**
+ @todo add description
+
+**/
+EFI_STATUS
+EFIAPI
+GetProposedResources (
+ IN EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL *This,
+ IN EFI_HANDLE RootBridgeHandle,
+ OUT VOID **Configuration
+ );
+
+/**
+ @todo add description
+
+**/
+EFI_STATUS
+EFIAPI
+PreprocessController (
+ IN struct _EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL *This,
+ IN EFI_HANDLE RootBridgeHandle,
+ IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_PCI_ADDRESS PciAddress,
+ IN EFI_PCI_CONTROLLER_RESOURCE_ALLOCATION_PHASE Phase
+ );
+
+//
+// Help function
+//
+/**
+ @todo add description
+
+**/
+UINT64
+Power2MaxMemory (
+ IN UINT64 MemoryLength
+ );
+
+#endif
diff --git a/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/PciHostBridge/PciHostBridge.inf b/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/PciHostBridge/PciHostBridge.inf
new file mode 100644
index 0000000000..be1bccc8e9
--- /dev/null
+++ b/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/PciHostBridge/PciHostBridge.inf
@@ -0,0 +1,82 @@
+## @file
+# Component description file for PciHostBridge module
+#
+# Provides the basic interfaces to abstract a PCI Host Bridge
+# Resource Allocation.
+#
+# Copyright (c) 1999 - 2015, 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 = 0x00010005
+ BASE_NAME = PciHostBridge
+ FILE_GUID = 2A42291A-A6A3-4729-A682-3329222175F1
+ MODULE_TYPE = DXE_DRIVER
+ VERSION_STRING = 1.0
+ ENTRY_POINT = PciHostBridgeEntryPoint
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 IPF EBC
+#
+
+[Sources]
+ PciHostBridge.h
+ PciHostBridge.c
+ PciRootBridge.h
+ PciRootBridgeIo.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ BraswellPlatformPkg/BraswellPlatformPkg.dec
+
+[LibraryClasses]
+ UefiDriverEntryPoint
+ UefiBootServicesTableLib
+ DebugLib
+ S3BootScriptLib
+ DxeServicesTableLib
+
+[Pcd]
+ ## SOMETIMES_CONSUMES
+ gEfiMdePkgTokenSpaceGuid.PcdPciExpressBaseAddress
+
+ ## SOMETIMES_CONSUMES
+ gIntelSiBasicPkgTokenSpaceGuid.PcdPciReservedIobase
+
+ ## SOMETIMES_CONSUMES
+ gIntelSiBasicPkgTokenSpaceGuid.PcdPciReservedIoLimit
+
+ ## SOMETIMES_CONSUMES
+ gIntelSiBasicPkgTokenSpaceGuid.PcdMmioBase
+
+ ## SOMETIMES_CONSUMES
+ gIntelSiBasicPkgTokenSpaceGuid.PcdPciReservedMemLimit
+
+[Protocols]
+ ## PRODUCES
+ gEfiPciRootBridgeIoProtocolGuid
+
+ ## PRODUCES
+ gEfiPciHostBridgeResourceAllocationProtocolGuid
+
+ ## CONSUMES
+ gEfiMetronomeArchProtocolGuid
+
+ ## CONSUMES
+ gEfiCpuIo2ProtocolGuid
+
+[Depex]
+ gEfiCpuIo2ProtocolGuid AND
+ gEfiMetronomeArchProtocolGuid
+
diff --git a/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/PciHostBridge/PciRootBridge.h b/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/PciHostBridge/PciRootBridge.h
new file mode 100644
index 0000000000..31ded9386f
--- /dev/null
+++ b/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/PciHostBridge/PciRootBridge.h
@@ -0,0 +1,155 @@
+/** @file
+ The driver for the host to pci bridge (root bridge).
+
+ Copyright (c) 1999 - 2015, 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 _PCI_ROOT_BRIDGE_H_
+#define _PCI_ROOT_BRIDGE_H_
+
+#include <PiDxe.h>
+#include <IndustryStandard/Acpi.h>
+#include <Library/S3BootScriptLib.h>
+#include <Protocol/PciHostBridgeResourceAllocation.h>
+#include <Protocol/Metronome.h>
+#include <Protocol/CpuIo2.h>
+
+#include <Library/UefiLib.h>
+#include <Library/DevicePathLib.h>
+#include <Library/DebugLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/DxeServicesTableLib.h>
+#include <Library/UefiRuntimeServicesTableLib.h>
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/PciExpressLib.h>
+
+//
+// Define resource status constant
+//
+#define EFI_RESOURCE_NONEXISTENT 0xFFFFFFFFFFFFFFFF
+#define EFI_RESOURCE_LESS 0xFFFFFFFFFFFFFFFE
+
+//
+// Driver Instance Data Prototypes
+//
+typedef struct {
+ EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_OPERATION Operation;
+ UINTN NumberOfBytes;
+ UINTN NumberOfPages;
+ EFI_PHYSICAL_ADDRESS HostAddress;
+ EFI_PHYSICAL_ADDRESS MappedHostAddress;
+} MAP_INFO;
+
+typedef struct {
+ ACPI_HID_DEVICE_PATH AcpiDevicePath;
+ EFI_DEVICE_PATH_PROTOCOL EndDevicePath;
+} EFI_PCI_ROOT_BRIDGE_DEVICE_PATH;
+
+typedef struct {
+ UINT64 BusBase;
+ UINT64 BusLimit;
+
+ UINT64 MemBase;
+ UINT64 MemLimit;
+
+ UINT64 IoBase;
+ UINT64 IoLimit;
+} PCI_ROOT_BRIDGE_RESOURCE_APPETURE;
+
+typedef enum {
+ TypeIo = 0,
+ TypeMem32,
+ TypePMem32,
+ TypeMem64,
+ TypePMem64,
+ TypeBus,
+ TypeMax
+} PCI_RESOURCE_TYPE;
+
+typedef enum {
+ ResNone = 0,
+ ResSubmitted,
+ ResRequested,
+ ResAllocated,
+ ResStatusMax
+} RES_STATUS;
+
+typedef struct {
+ PCI_RESOURCE_TYPE Type;
+ UINT64 Base;
+ UINT64 Length;
+ UINT64 Alignment;
+ RES_STATUS Status;
+} PCI_RES_NODE;
+
+#define PCI_ROOT_BRIDGE_SIGNATURE SIGNATURE_32 ('e', '2', 'p', 'b')
+
+typedef struct {
+ UINT32 Signature;
+ LIST_ENTRY Link;
+ EFI_HANDLE Handle;
+ UINT64 RootBridgeAttrib;
+ UINT64 Attributes;
+ UINT64 Supports;
+
+ //
+ // Specific for this memory controller: Bus, I/O, Mem
+ //
+ PCI_RES_NODE ResAllocNode[6];
+
+ //
+ // Addressing for Memory and I/O and Bus arrange
+ //
+ UINT64 BusBase;
+ UINT64 MemBase;
+ UINT64 IoBase;
+ UINT64 BusLimit;
+ UINT64 MemLimit;
+ UINT64 IoLimit;
+
+ EFI_LOCK PciLock;
+ UINTN PciAddress;
+ UINTN PciData;
+
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;
+ EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL Io;
+
+} PCI_ROOT_BRIDGE_INSTANCE;
+
+//
+// Driver Instance Data Macros
+//
+#define DRIVER_INSTANCE_FROM_PCI_ROOT_BRIDGE_IO_THIS(a) CR (a, PCI_ROOT_BRIDGE_INSTANCE, Io, PCI_ROOT_BRIDGE_SIGNATURE)
+
+#define DRIVER_INSTANCE_FROM_LIST_ENTRY(a) CR (a, PCI_ROOT_BRIDGE_INSTANCE, Link, PCI_ROOT_BRIDGE_SIGNATURE)
+
+/**
+ @todo Add function description
+
+ @param[in] Protocol - @todo add argument description
+ @param[in] HostBridgeHandle - @todo add argument description
+ @param[in] Attri - @todo add argument description
+ @param[in] ResAppeture - @todo add argument description
+
+ @retval - @todo add return values
+
+**/
+EFI_STATUS
+RootBridgeConstructor (
+ IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *Protocol,
+ IN EFI_HANDLE HostBridgeHandle,
+ IN UINT64 Attri,
+ IN PCI_ROOT_BRIDGE_RESOURCE_APPETURE *ResAppeture
+ );
+#endif
diff --git a/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/PciHostBridge/PciRootBridgeIo.c b/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/PciHostBridge/PciRootBridgeIo.c
new file mode 100644
index 0000000000..5ce22cd215
--- /dev/null
+++ b/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/PciHostBridge/PciRootBridgeIo.c
@@ -0,0 +1,1459 @@
+/** @file
+ EFI Memory Controller PCI Root Bridge Io Protocol
+
+ Copyright (c) 1999 - 2015, 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 "PciRootBridge.h"
+#include <IndustryStandard/Pci22.h>
+
+typedef struct {
+ EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR SpaceDesp[TypeMax];
+ EFI_ACPI_END_TAG_DESCRIPTOR EndDesp;
+} RESOURCE_CONFIGURATION;
+
+RESOURCE_CONFIGURATION Configuration = {
+ {
+ {
+ 0x8A,
+ 0x2B,
+ 1,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0
+ },
+ {
+ 0x8A,
+ 0x2B,
+ 0,
+ 0,
+ 0,
+ 32,
+ 0,
+ 0,
+ 0,
+ 0
+ },
+ {
+ 0x8A,
+ 0x2B,
+ 0,
+ 0,
+ 6,
+ 32,
+ 0,
+ 0,
+ 0,
+ 0
+ },
+ {
+ 0x8A,
+ 0x2B,
+ 0,
+ 0,
+ 0,
+ 64,
+ 0,
+ 0,
+ 0,
+ 0
+ },
+ {
+ 0x8A,
+ 0x2B,
+ 0,
+ 0,
+ 6,
+ 64,
+ 0,
+ 0,
+ 0,
+ 0
+ },
+ {
+ 0x8A,
+ 0x2B,
+ 2,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0
+ }
+ },
+ {
+ 0x79,
+ 0
+ }
+};
+
+//
+// Protocol Member Function Prototypes
+//
+EFI_STATUS
+EFIAPI
+RootBridgeIoPollMem (
+ IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This,
+ IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width,
+ IN UINT64 Address,
+ IN UINT64 Mask,
+ IN UINT64 Value,
+ IN UINT64 Delay,
+ OUT UINT64 *Result
+ );
+
+EFI_STATUS
+EFIAPI
+RootBridgeIoPollIo (
+ IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This,
+ IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width,
+ IN UINT64 Address,
+ IN UINT64 Mask,
+ IN UINT64 Value,
+ IN UINT64 Delay,
+ OUT UINT64 *Result
+ );
+
+EFI_STATUS
+EFIAPI
+RootBridgeIoMemRead (
+ IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This,
+ IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width,
+ IN UINT64 Address,
+ IN UINTN Count,
+ IN OUT VOID *Buffer
+ );
+
+EFI_STATUS
+EFIAPI
+RootBridgeIoMemWrite (
+ IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This,
+ IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width,
+ IN UINT64 Address,
+ IN UINTN Count,
+ IN OUT VOID *Buffer
+ );
+
+EFI_STATUS
+EFIAPI
+RootBridgeIoIoRead (
+ IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This,
+ IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width,
+ IN UINT64 UserAddress,
+ IN UINTN Count,
+ IN OUT VOID *UserBuffer
+ );
+
+EFI_STATUS
+EFIAPI
+RootBridgeIoIoWrite (
+ IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This,
+ IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width,
+ IN UINT64 UserAddress,
+ IN UINTN Count,
+ IN OUT VOID *UserBuffer
+ );
+
+EFI_STATUS
+EFIAPI
+RootBridgeIoCopyMem (
+ IN struct _EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This,
+ IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width,
+ IN UINT64 DestAddress,
+ IN UINT64 SrcAddress,
+ IN UINTN Count
+ );
+
+EFI_STATUS
+EFIAPI
+RootBridgeIoPciRead (
+ IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This,
+ IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width,
+ IN UINT64 Address,
+ IN UINTN Count,
+ IN OUT VOID *Buffer
+ );
+
+EFI_STATUS
+EFIAPI
+RootBridgeIoPciWrite (
+ IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This,
+ IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width,
+ IN UINT64 Address,
+ IN UINTN Count,
+ IN OUT VOID *Buffer
+ );
+
+EFI_STATUS
+EFIAPI
+RootBridgeIoMap (
+ IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This,
+ IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_OPERATION Operation,
+ IN VOID *HostAddress,
+ IN OUT UINTN *NumberOfBytes,
+ OUT EFI_PHYSICAL_ADDRESS *DeviceAddress,
+ OUT VOID **Mapping
+ );
+
+EFI_STATUS
+EFIAPI
+RootBridgeIoUnmap (
+ IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This,
+ IN VOID *Mapping
+ );
+
+EFI_STATUS
+EFIAPI
+RootBridgeIoAllocateBuffer (
+ IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This,
+ IN EFI_ALLOCATE_TYPE Type,
+ IN EFI_MEMORY_TYPE MemoryType,
+ IN UINTN Pages,
+ OUT VOID **HostAddress,
+ IN UINT64 Attributes
+ );
+
+EFI_STATUS
+EFIAPI
+RootBridgeIoFreeBuffer (
+ IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This,
+ IN UINTN Pages,
+ OUT VOID *HostAddress
+ );
+
+EFI_STATUS
+EFIAPI
+RootBridgeIoFlush (
+ IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This
+ );
+
+EFI_STATUS
+EFIAPI
+RootBridgeIoGetAttributes (
+ IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This,
+ OUT UINT64 *Supported,
+ OUT UINT64 *Attributes
+ );
+
+EFI_STATUS
+EFIAPI
+RootBridgeIoSetAttributes (
+ IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This,
+ IN UINT64 Attributes,
+ IN OUT UINT64 *ResourceBase,
+ IN OUT UINT64 *ResourceLength
+ );
+
+EFI_STATUS
+EFIAPI
+RootBridgeIoConfiguration (
+ IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This,
+ OUT VOID **Resources
+ );
+
+//
+// Sub Function Prototypes
+//
+typedef union {
+ UINT8 volatile *buf;
+ UINT8 volatile *ui8;
+ UINT16 volatile *ui16;
+ UINT32 volatile *ui32;
+ UINT64 volatile *ui64;
+ UINTN volatile ui;
+} PTR;
+
+STATIC
+EFI_STATUS
+RootBridgeIoPciRW (
+ IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This,
+ IN BOOLEAN Write,
+ IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width,
+ IN UINT64 UserAddress,
+ IN UINTN Count,
+ IN OUT VOID *UserBuffer
+ );
+
+//
+// Memory Controller Pci Root Bridge Io Module Variables
+//
+EFI_METRONOME_ARCH_PROTOCOL *mMetronome;
+EFI_CPU_IO2_PROTOCOL *mCpuIo;
+
+/**
+ Construct the Pci Root Bridge Io protocol
+
+ @param[in] Protocol protocol to initialize
+ @param[in] HostBridgeHandle Host Bridge Handle
+ @param[in] Attri Host Bridge Attribute
+ @param[in] ResAppeture Host Bridge resource appeture
+
+ @retval EFI_SUCCESS Pci Root Bridge Io protocol was constructed successfully.
+
+**/
+EFI_STATUS
+RootBridgeConstructor (
+ IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *Protocol,
+ IN EFI_HANDLE HostBridgeHandle,
+ IN UINT64 Attri,
+ IN PCI_ROOT_BRIDGE_RESOURCE_APPETURE *ResAppeture
+ )
+{
+ EFI_STATUS Status;
+ PCI_ROOT_BRIDGE_INSTANCE *PrivateData;
+ PCI_RESOURCE_TYPE Index;
+
+ PrivateData = DRIVER_INSTANCE_FROM_PCI_ROOT_BRIDGE_IO_THIS (Protocol);
+
+ //
+ // The host to pci bridge, the host memory and io addresses are
+ // direct mapped to pci addresses, so no need translate, set bases to 0.
+ //
+ PrivateData->MemBase = ResAppeture->MemBase;
+ PrivateData->IoBase = ResAppeture->IoBase;
+
+ //
+ // The host bridge only supports 32bit addressing for memory
+ // and standard IA32 16bit io
+ //
+ PrivateData->MemLimit = ResAppeture->MemLimit;
+ PrivateData->IoLimit = ResAppeture->IoLimit;
+
+ //
+ // Bus Appeture for this Root Bridge (Possible Range)
+ //
+ PrivateData->BusBase = ResAppeture->BusBase;
+ PrivateData->BusLimit = ResAppeture->BusLimit;
+
+ //
+ // Specific for this chipset
+ //
+ for (Index = TypeIo; Index < TypeMax; Index++) {
+ PrivateData->ResAllocNode[Index].Type = Index;
+ PrivateData->ResAllocNode[Index].Base = 0;
+ PrivateData->ResAllocNode[Index].Length = 0;
+ PrivateData->ResAllocNode[Index].Status = ResNone;
+ }
+
+ EfiInitializeLock (&PrivateData->PciLock, TPL_HIGH_LEVEL);
+ PrivateData->PciAddress = 0xCF8;
+ PrivateData->PciData = 0xCFC;
+
+ PrivateData->RootBridgeAttrib = Attri;
+
+ PrivateData->Attributes = 0;
+ PrivateData->Supports = EFI_PCI_ATTRIBUTE_IDE_PRIMARY_IO |
+ EFI_PCI_ATTRIBUTE_ISA_IO |
+ EFI_PCI_ATTRIBUTE_VGA_PALETTE_IO |
+ EFI_PCI_ATTRIBUTE_VGA_MEMORY |
+ EFI_PCI_ATTRIBUTE_VGA_IO;
+
+ Protocol->ParentHandle = HostBridgeHandle;
+
+ Protocol->PollMem = RootBridgeIoPollMem;
+ Protocol->PollIo = RootBridgeIoPollIo;
+
+ Protocol->Mem.Read = RootBridgeIoMemRead;
+ Protocol->Mem.Write = RootBridgeIoMemWrite;
+
+ Protocol->Io.Read = RootBridgeIoIoRead;
+ Protocol->Io.Write = RootBridgeIoIoWrite;
+
+ Protocol->CopyMem = RootBridgeIoCopyMem;
+
+ Protocol->Pci.Read = RootBridgeIoPciRead;
+ Protocol->Pci.Write = RootBridgeIoPciWrite;
+
+ Protocol->Map = RootBridgeIoMap;
+ Protocol->Unmap = RootBridgeIoUnmap;
+
+ Protocol->AllocateBuffer = RootBridgeIoAllocateBuffer;
+ Protocol->FreeBuffer = RootBridgeIoFreeBuffer;
+
+ Protocol->Flush = RootBridgeIoFlush;
+
+ Protocol->GetAttributes = RootBridgeIoGetAttributes;
+ Protocol->SetAttributes = RootBridgeIoSetAttributes;
+
+ Protocol->Configuration = RootBridgeIoConfiguration;
+
+ Protocol->SegmentNumber = 0;
+
+ Status = gBS->LocateProtocol (&gEfiMetronomeArchProtocolGuid, NULL, (VOID **)&mMetronome);
+ ASSERT_EFI_ERROR (Status);
+
+ Status = gBS->LocateProtocol (&gEfiCpuIo2ProtocolGuid, NULL, (VOID **) &mCpuIo);
+ ASSERT_EFI_ERROR (Status);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ @todo add description
+
+**/
+/**
+ Memory Poll
+// @todo This - add argument and description to function comment
+// @todo Width - add argument and description to function comment
+// @todo Address - add argument and description to function comment
+// @todo Mask - add argument and description to function comment
+// @todo Value - add argument and description to function comment
+// @todo Delay - add argument and description to function comment
+// @todo Result - add argument and description to function comment
+// @todo EFI_INVALID_PARAMETER - add return value to function comment
+// @todo EFI_INVALID_PARAMETER - add return value to function comment
+// @todo EFI_SUCCESS - add return value to function comment
+// @todo EFI_SUCCESS - add return value to function comment
+// @todo EFI_SUCCESS - add return value to function comment
+// @todo EFI_TIMEOUT - add return value to function comment
+**/
+EFI_STATUS
+EFIAPI
+RootBridgeIoPollMem (
+ IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This,
+ IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width,
+ IN UINT64 Address,
+ IN UINT64 Mask,
+ IN UINT64 Value,
+ IN UINT64 Delay,
+ OUT UINT64 *Result
+ )
+{
+ EFI_STATUS Status;
+ UINT64 NumberOfTicks;
+ UINTN Remainder;
+
+ if (Result == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (Width < 0 || Width > EfiPciWidthUint64) {
+ return EFI_INVALID_PARAMETER;
+ }
+ //
+ // No matter what, always do a single poll.
+ //
+ Status = This->Mem.Read (This, Width, Address, 1, Result);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ if ((*Result & Mask) == Value) {
+ return EFI_SUCCESS;
+ }
+
+ if (Delay == 0) {
+ return EFI_SUCCESS;
+
+ } else {
+ //
+ // Determine the proper # of metronome ticks to wait for polling the
+ // location. The nuber of ticks is Roundup (Delay / mMetronome->TickPeriod)+1
+ // The "+1" to account for the possibility of the first tick being short
+ // because we started in the middle of a tick.
+ //
+ // BugBug: overriding mMetronome->TickPeriod with UINT32 until Metronome
+ // protocol definition is updated.
+ //
+ NumberOfTicks = DivU64x32Remainder (Delay, (UINT32) mMetronome->TickPeriod, (UINT32 *)&Remainder);
+ if (Remainder != 0) {
+ NumberOfTicks += 1;
+ }
+
+ NumberOfTicks += 1;
+
+ while (NumberOfTicks) {
+
+ mMetronome->WaitForTick (mMetronome, 1);
+
+ Status = This->Mem.Read (This, Width, Address, 1, Result);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ if ((*Result & Mask) == Value) {
+ return EFI_SUCCESS;
+ }
+
+ NumberOfTicks -= 1;
+ }
+ }
+
+ return EFI_TIMEOUT;
+}
+
+/**
+ @todo add description
+
+**/
+/**
+ Io Poll
+// @todo This - add argument and description to function comment
+// @todo Width - add argument and description to function comment
+// @todo Address - add argument and description to function comment
+// @todo Mask - add argument and description to function comment
+// @todo Value - add argument and description to function comment
+// @todo Delay - add argument and description to function comment
+// @todo Result - add argument and description to function comment
+// @todo EFI_INVALID_PARAMETER - add return value to function comment
+// @todo EFI_INVALID_PARAMETER - add return value to function comment
+// @todo EFI_SUCCESS - add return value to function comment
+// @todo EFI_SUCCESS - add return value to function comment
+// @todo EFI_SUCCESS - add return value to function comment
+// @todo EFI_TIMEOUT - add return value to function comment
+
+**/
+EFI_STATUS
+EFIAPI
+RootBridgeIoPollIo (
+ IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This,
+ IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width,
+ IN UINT64 Address,
+ IN UINT64 Mask,
+ IN UINT64 Value,
+ IN UINT64 Delay,
+ OUT UINT64 *Result
+ )
+{
+ EFI_STATUS Status;
+ UINT64 NumberOfTicks;
+ UINTN Remainder;
+
+ //
+ // No matter what, always do a single poll.
+ //
+ if (Result == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (Width < 0 || Width > EfiPciWidthUint64) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Status = This->Io.Read (This, Width, Address, 1, Result);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ if ((*Result & Mask) == Value) {
+ return EFI_SUCCESS;
+ }
+
+ if (Delay == 0) {
+ return EFI_SUCCESS;
+
+ } else {
+ //
+ // Determine the proper # of metronome ticks to wait for polling the
+ // location. The number of ticks is Roundup (Delay / mMetronome->TickPeriod)+1
+ // The "+1" to account for the possibility of the first tick being short
+ // because we started in the middle of a tick.
+ //
+ NumberOfTicks = DivU64x32Remainder (Delay, (UINT32) mMetronome->TickPeriod, (UINT32 *)&Remainder);
+ if (Remainder != 0) {
+ NumberOfTicks += 1;
+ }
+
+ NumberOfTicks += 1;
+
+ while (NumberOfTicks) {
+
+ mMetronome->WaitForTick (mMetronome, 1);
+
+ Status = This->Io.Read (This, Width, Address, 1, Result);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ if ((*Result & Mask) == Value) {
+ return EFI_SUCCESS;
+ }
+
+ NumberOfTicks -= 1;
+ }
+ }
+
+ return EFI_TIMEOUT;
+}
+
+/**
+ @todo add description
+
+**/
+/**
+ Memory read
+// @todo This - add argument and description to function comment
+// @todo Width - add argument and description to function comment
+// @todo Address - add argument and description to function comment
+// @todo Count - add argument and description to function comment
+// @todo Buffer - add argument and description to function comment
+// @todo EFI_INVALID_PARAMETER - add return value to function comment
+// @todo EFI_INVALID_PARAMETER - add return value to function comment
+// @todo EFI_INVALID_PARAMETER - add return value to function comment
+// @todo EFI_INVALID_PARAMETER - add return value to function comment
+**/
+EFI_STATUS
+EFIAPI
+RootBridgeIoMemRead (
+ IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This,
+ IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width,
+ IN UINT64 Address,
+ IN UINTN Count,
+ IN OUT VOID *Buffer
+ )
+{
+ PCI_ROOT_BRIDGE_INSTANCE *PrivateData;
+ EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH OldWidth;
+ UINTN OldCount;
+
+ if (Buffer == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (Width < 0 || Width >= EfiPciWidthMaximum) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ PrivateData = DRIVER_INSTANCE_FROM_PCI_ROOT_BRIDGE_IO_THIS (This);
+
+ //
+ // Check memory access limit
+ //
+ if (Address < PrivateData->MemBase) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ OldWidth = Width;
+ OldCount = Count;
+
+ if (Width >= EfiPciWidthFifoUint8 && Width <= EfiPciWidthFifoUint64) {
+ Count = 1;
+ }
+
+ Width &= 0x03;
+
+ if (Address + MultU64x32 (LShiftU64(1, Width), (UINT32)Count) - 1 > PrivateData->MemLimit) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ return mCpuIo->Mem.Read (
+ mCpuIo,
+ (EFI_CPU_IO_PROTOCOL_WIDTH) OldWidth,
+ Address,
+ OldCount,
+ Buffer
+ );
+}
+
+/**
+ @todo add description
+
+**/
+/**
+ Memory write
+// @todo This - add argument and description to function comment
+// @todo Width - add argument and description to function comment
+// @todo Address - add argument and description to function comment
+// @todo Count - add argument and description to function comment
+// @todo Buffer - add argument and description to function comment
+// @todo EFI_INVALID_PARAMETER - add return value to function comment
+// @todo EFI_INVALID_PARAMETER - add return value to function comment
+// @todo EFI_INVALID_PARAMETER - add return value to function comment
+// @todo EFI_INVALID_PARAMETER - add return value to function comment
+
+
+**/
+EFI_STATUS
+EFIAPI
+RootBridgeIoMemWrite (
+ IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This,
+ IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width,
+ IN UINT64 Address,
+ IN UINTN Count,
+ IN OUT VOID *Buffer
+ )
+{
+ PCI_ROOT_BRIDGE_INSTANCE *PrivateData;
+ EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH OldWidth;
+ UINTN OldCount;
+
+ if (Buffer == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (Width < 0 || Width >= EfiPciWidthMaximum) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ PrivateData = DRIVER_INSTANCE_FROM_PCI_ROOT_BRIDGE_IO_THIS (This);
+
+ //
+ // Check memory access limit
+ //
+ if (Address < PrivateData->MemBase) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ OldWidth = Width;
+ OldCount = Count;
+ if (Width >= EfiPciWidthFifoUint8 && Width <= EfiPciWidthFifoUint64) {
+ Count = 1;
+ }
+
+ Width &= 0x03;
+
+ if (Address + MultU64x32 (LShiftU64(1, Width), (UINT32)Count) - 1 > PrivateData->MemLimit) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ return mCpuIo->Mem.Write (
+ mCpuIo,
+ (EFI_CPU_IO_PROTOCOL_WIDTH) OldWidth,
+ Address,
+ OldCount,
+ Buffer
+ );
+}
+
+/**
+ @todo add description
+
+**/
+/**
+ Io read
+// @todo This - add argument and description to function comment
+// @todo Width - add argument and description to function comment
+// @todo Address - add argument and description to function comment
+// @todo Count - add argument and description to function comment
+// @todo Buffer - add argument and description to function comment
+// @todo EFI_INVALID_PARAMETER - add return value to function comment
+// @todo EFI_INVALID_PARAMETER - add return value to function comment
+// @todo EFI_INVALID_PARAMETER - add return value to function comment
+// @todo EFI_INVALID_PARAMETER - add return value to function comment
+// @todo EFI_INVALID_PARAMETER - add return value to function comment
+
+**/
+EFI_STATUS
+EFIAPI
+RootBridgeIoIoRead (
+ IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This,
+ IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width,
+ IN UINT64 Address,
+ IN UINTN Count,
+ IN OUT VOID *Buffer
+ )
+{
+
+ UINTN AlignMask;
+ PCI_ROOT_BRIDGE_INSTANCE *PrivateData;
+ EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH OldWidth;
+ UINTN OldCount;
+
+ if (Buffer == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (Width < 0 || Width >= EfiPciWidthMaximum) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ PrivateData = DRIVER_INSTANCE_FROM_PCI_ROOT_BRIDGE_IO_THIS (This);
+
+ //
+ // AlignMask = (1 << Width) - 1;
+ //
+ AlignMask = (1 << (Width & 0x03)) - 1;
+
+ //
+ // check Io access limit
+ //
+ if (Address < PrivateData->IoBase) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ OldWidth = Width;
+ OldCount = Count;
+ if (Width >= EfiPciWidthFifoUint8 && Width <= EfiPciWidthFifoUint64) {
+ Count = 1;
+ }
+
+ Width &= 0x03;
+
+ if (Address + MultU64x32 (LShiftU64(1, Width), (UINT32)Count) - 1 >= PrivateData->IoLimit) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (Address & AlignMask) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ return mCpuIo->Io.Read (
+ mCpuIo,
+ (EFI_CPU_IO_PROTOCOL_WIDTH) OldWidth,
+ Address,
+ OldCount,
+ Buffer
+ );
+
+}
+
+/**
+ @todo add description
+
+**/
+/**
+ Io write
+// @todo This - add argument and description to function comment
+// @todo Width - add argument and description to function comment
+// @todo Address - add argument and description to function comment
+// @todo Count - add argument and description to function comment
+// @todo Buffer - add argument and description to function comment
+// @todo EFI_INVALID_PARAMETER - add return value to function comment
+// @todo EFI_INVALID_PARAMETER - add return value to function comment
+// @todo EFI_INVALID_PARAMETER - add return value to function comment
+// @todo EFI_INVALID_PARAMETER - add return value to function comment
+// @todo EFI_INVALID_PARAMETER - add return value to function comment
+
+**/
+EFI_STATUS
+EFIAPI
+RootBridgeIoIoWrite (
+ IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This,
+ IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width,
+ IN UINT64 Address,
+ IN UINTN Count,
+ IN OUT VOID *Buffer
+ )
+{
+ UINTN AlignMask;
+ PCI_ROOT_BRIDGE_INSTANCE *PrivateData;
+ EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH OldWidth;
+ UINTN OldCount;
+
+ if (Buffer == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (Width < 0 || Width >= EfiPciWidthMaximum) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ PrivateData = DRIVER_INSTANCE_FROM_PCI_ROOT_BRIDGE_IO_THIS (This);
+
+ //
+ // AlignMask = (1 << Width) - 1;
+ //
+ AlignMask = (1 << (Width & 0x03)) - 1;
+
+ //
+ // Check Io access limit
+ //
+ if (Address < PrivateData->IoBase) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ OldWidth = Width;
+ OldCount = Count;
+ if (Width >= EfiPciWidthFifoUint8 && Width <= EfiPciWidthFifoUint64) {
+ Count = 1;
+ }
+
+ Width &= 0x03;
+
+ if (Address + MultU64x32 (LShiftU64(1, Width), (UINT32)Count) - 1 >= PrivateData->IoLimit) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (Address & AlignMask) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ return mCpuIo->Io.Write (
+ mCpuIo,
+ (EFI_CPU_IO_PROTOCOL_WIDTH) OldWidth,
+ Address,
+ OldCount,
+ Buffer
+ );
+
+}
+
+/**
+ @todo add description
+
+**/
+/**
+ Memory copy
+// @todo This - add argument and description to function comment
+// @todo Width - add argument and description to function comment
+// @todo DestAddress - add argument and description to function comment
+// @todo SrcAddress - add argument and description to function comment
+// @todo Count - add argument and description to function comment
+// @todo EFI_INVALID_PARAMETER - add return value to function comment
+// @todo EFI_SUCCESS - add return value to function comment
+// @todo EFI_SUCCESS - add return value to function comment
+
+**/
+EFI_STATUS
+EFIAPI
+RootBridgeIoCopyMem (
+ IN struct _EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This,
+ IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width,
+ IN UINT64 DestAddress,
+ IN UINT64 SrcAddress,
+ IN UINTN Count
+ )
+{
+ EFI_STATUS Status;
+ BOOLEAN Direction;
+ UINTN Stride;
+ UINTN Index;
+ UINT64 Result;
+
+ if (Width < 0 || Width > EfiPciWidthUint64) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (DestAddress == SrcAddress) {
+ return EFI_SUCCESS;
+ }
+
+ Stride = (UINTN) (LShiftU64 (1, Width));
+
+ Direction = TRUE;
+ if ((DestAddress > SrcAddress) && (DestAddress < (SrcAddress + Count * Stride))) {
+ Direction = FALSE;
+ SrcAddress = SrcAddress + (Count - 1) * Stride;
+ DestAddress = DestAddress + (Count - 1) * Stride;
+ }
+
+ for (Index = 0; Index < Count; Index++) {
+ Status = RootBridgeIoMemRead (
+ This,
+ Width,
+ SrcAddress,
+ 1,
+ &Result
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = RootBridgeIoMemWrite (
+ This,
+ Width,
+ DestAddress,
+ 1,
+ &Result
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ if (Direction) {
+ SrcAddress += Stride;
+ DestAddress += Stride;
+ } else {
+ SrcAddress -= Stride;
+ DestAddress -= Stride;
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ @todo add description
+
+**/
+/**
+ Pci read
+// @todo This - add argument and description to function comment
+// @todo Width - add argument and description to function comment
+// @todo Address - add argument and description to function comment
+// @todo Count - add argument and description to function comment
+// @todo Buffer - add argument and description to function comment
+// @todo EFI_INVALID_PARAMETER - add return value to function comment
+// @todo EFI_INVALID_PARAMETER - add return value to function comment
+**/
+EFI_STATUS
+EFIAPI
+RootBridgeIoPciRead (
+ IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This,
+ IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width,
+ IN UINT64 Address,
+ IN UINTN Count,
+ IN OUT VOID *Buffer
+ )
+{
+
+ if (Buffer == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (Width < 0 || Width >= EfiPciWidthMaximum) {
+ return EFI_INVALID_PARAMETER;
+ }
+ //
+ // Read Pci configuration space
+ //
+ return RootBridgeIoPciRW (This, FALSE, Width, Address, Count, Buffer);
+}
+
+/**
+ @todo add description
+
+**/
+/**
+ Pci write
+// @todo This - add argument and description to function comment
+// @todo Width - add argument and description to function comment
+// @todo Address - add argument and description to function comment
+// @todo Count - add argument and description to function comment
+// @todo Buffer - add argument and description to function comment
+// @todo EFI_INVALID_PARAMETER - add return value to function comment
+// @todo EFI_INVALID_PARAMETER - add return value to function comment
+**/
+EFI_STATUS
+EFIAPI
+RootBridgeIoPciWrite (
+ IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This,
+ IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width,
+ IN UINT64 Address,
+ IN UINTN Count,
+ IN OUT VOID *Buffer
+ )
+{
+
+ if (Buffer == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (Width < 0 || Width >= EfiPciWidthMaximum) {
+ return EFI_INVALID_PARAMETER;
+ }
+ //
+ // Write Pci configuration space
+ //
+ return RootBridgeIoPciRW (This, TRUE, Width, Address, Count, Buffer);
+}
+
+/**
+ @todo Add function description
+
+ @param[in] This - @todo add argument description
+ @param[in] Operation - @todo add argument description
+ @param[in] HostAddress - @todo add argument description
+ @param[in,out] NumberOfBytes - @todo add argument description
+ @param[out] DeviceAddress - @todo add argument description
+ @param[out] Mapping - @todo add argument description
+
+ @retval EFI_INVALID_PARAMETER - @todo Add description for return value
+ @retval EFI_INVALID_PARAMETER - @todo Add description for return value
+ @retval EFI_UNSUPPORTED - @todo Add description for return value
+ @retval EFI_SUCCESS - @todo Add description for return value
+
+**/
+EFI_STATUS
+EFIAPI
+RootBridgeIoMap (
+ IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This,
+ IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_OPERATION Operation,
+ IN VOID *HostAddress,
+ IN OUT UINTN *NumberOfBytes,
+ OUT EFI_PHYSICAL_ADDRESS *DeviceAddress,
+ OUT VOID **Mapping
+ )
+{
+ //
+ // Make sure inputs are valid
+ //
+ if (HostAddress == NULL || NumberOfBytes == NULL || DeviceAddress == NULL || Mapping == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+ //
+ // Make sure that Operation is valid
+ //
+ if (Operation < 0 || Operation >= EfiPciOperationMaximum) {
+ return EFI_INVALID_PARAMETER;
+ }
+ //
+ // No mapping required
+ //
+ *Mapping = NULL;
+ *DeviceAddress = (EFI_PHYSICAL_ADDRESS) (UINTN) HostAddress;
+ return EFI_SUCCESS;
+}
+
+/**
+ @todo Add function description
+
+ @param[in] This - @todo add argument description
+ @param[in] Mapping - @todo add argument description
+
+ @retval EFI_SUCCESS - @todo Add description for return value
+
+**/
+EFI_STATUS
+EFIAPI
+RootBridgeIoUnmap (
+ IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This,
+ IN VOID *Mapping
+ )
+{
+ MAP_INFO *MapInfo;
+
+ //
+ // See if the Map() operation associated with this Unmap() required a mapping buffer.
+ // If a mapping buffer was not required, then this function simply returns EFI_SUCCESS.
+ //
+ if (Mapping != NULL) {
+ //
+ // Get the MAP_INFO structure from Mapping
+ //
+ MapInfo = (MAP_INFO *) Mapping;
+
+ //
+ // If this is a write operation from the Bus Master's point of view,
+ // then copy the contents of the mapped buffer into the real buffer
+ // so the processor can read the contents of the real buffer.
+ //
+ if (MapInfo->Operation == EfiPciOperationBusMasterWrite || MapInfo->Operation == EfiPciOperationBusMasterWrite64) {
+ CopyMem (
+ (VOID *) (UINTN) MapInfo->HostAddress,
+ (VOID *) (UINTN) MapInfo->MappedHostAddress,
+ MapInfo->NumberOfBytes
+ );
+ }
+ //
+ // Free the mapped buffer and the MAP_INFO structure.
+ //
+#ifndef __GNUC__
+#pragma warning (disable: 4305)
+#endif
+ FreePages((VOID *)(UINTN)MapInfo->MappedHostAddress, MapInfo->NumberOfPages);
+#ifndef __GNUC__
+#pragma warning (default: 4305)
+#endif
+ FreePool(Mapping);
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ @todo Add function description
+
+ @param[in] This - @todo add argument description
+ @param[in] Type - @todo add argument description
+ @param[in] MemoryType - @todo add argument description
+ @param[in] Pages - @todo add argument description
+ @param[out] HostAddress - @todo add argument description
+ @param[in] Attributes - @todo add argument description
+
+ @retval EFI_UNSUPPORTED - @todo Add description for return value
+ @retval EFI_INVALID_PARAMETER - @todo Add description for return value
+ @retval EFI_UNSUPPORTED - @todo Add description for return value
+ @retval EFI_INVALID_PARAMETER - @todo Add description for return value
+ @retval EFI_SUCCESS - @todo Add description for return value
+
+**/
+EFI_STATUS
+EFIAPI
+RootBridgeIoAllocateBuffer (
+ IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This,
+ IN EFI_ALLOCATE_TYPE Type,
+ IN EFI_MEMORY_TYPE MemoryType,
+ IN UINTN Pages,
+ OUT VOID **HostAddress,
+ IN UINT64 Attributes
+ )
+{
+ EFI_PHYSICAL_ADDRESS PhysicalAddress;
+
+ //
+ // Validate Attributes
+ //
+ if (Attributes & EFI_PCI_ATTRIBUTE_INVALID_FOR_ALLOCATE_BUFFER) {
+ return EFI_UNSUPPORTED;
+ }
+ //
+ // Check for invalid inputs
+ //
+ if (HostAddress == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if ((EFI_PHYSICAL_ADDRESS) ((UINTN)*HostAddress) > 0xffffffff) {
+ return EFI_UNSUPPORTED;
+ }
+ //
+ // The only valid memory types are EfiBootServicesData and EfiRuntimeServicesData
+ //
+ if (MemoryType != EfiBootServicesData && MemoryType != EfiRuntimeServicesData) {
+ return EFI_INVALID_PARAMETER;
+ }
+ //
+ // Limit allocations to memory below 4GB
+ //
+ PhysicalAddress = (EFI_PHYSICAL_ADDRESS) (0xffffffff);
+
+ PhysicalAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)AllocatePages(Pages);
+ if (!PhysicalAddress) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ *HostAddress = (VOID *) (UINTN) PhysicalAddress;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ @todo Add function description
+
+ @param[in] This - @todo add argument description
+ @param[in] Pages - @todo add argument description
+ @param[out] HostAddress - @todo add argument description
+
+ @retval - @todo add return values
+
+**/
+EFI_STATUS
+EFIAPI
+RootBridgeIoFreeBuffer (
+ IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This,
+ IN UINTN Pages,
+ OUT VOID *HostAddress
+ )
+{
+ FreePages ((VOID *) HostAddress, Pages);
+ return EFI_SUCCESS;
+}
+
+/**
+ @todo add description
+
+**/
+/**
+// @todo This - add argument and description to function comment
+// @todo EFI_SUCCESS - add return value to function comment
+
+**/
+EFI_STATUS
+EFIAPI
+RootBridgeIoFlush (
+ IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This
+ )
+{
+ //
+ // not supported yet
+ //
+ return EFI_SUCCESS;
+}
+
+/**
+ @todo add description
+
+**/
+/**
+// @todo This - add argument and description to function comment
+// @todo Supported - add argument and description to function comment
+// @todo Attributes - add argument and description to function comment
+// @todo EFI_INVALID_PARAMETER - add return value to function comment
+// @todo EFI_SUCCESS - add return value to function comment
+
+**/
+EFI_STATUS
+EFIAPI
+RootBridgeIoGetAttributes (
+ IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This,
+ OUT UINT64 *Supported,
+ OUT UINT64 *Attributes
+ )
+{
+ PCI_ROOT_BRIDGE_INSTANCE *PrivateData;
+
+ PrivateData = DRIVER_INSTANCE_FROM_PCI_ROOT_BRIDGE_IO_THIS (This);
+
+ if (Attributes == NULL && Supported == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+ //
+ // Set the return value for Supported and Attributes
+ //
+ if (Supported) {
+ *Supported = PrivateData->Supports;
+ }
+
+ if (Attributes) {
+ *Attributes = PrivateData->Attributes;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+// @todo This - add argument and description to function comment
+// @todo Attributes - add argument and description to function comment
+// @todo ResourceBase - add argument and description to function comment
+// @todo ResourceLength - add argument and description to function comment
+// @todo EFI_UNSUPPORTED - add return value to function comment
+// @todo EFI_SUCCESS - add return value to function comment
+// @todo EFI_SUCCESS - add return value to function comment
+
+**/
+EFI_STATUS
+EFIAPI
+RootBridgeIoSetAttributes (
+ IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This,
+ IN UINT64 Attributes,
+ IN OUT UINT64 *ResourceBase,
+ IN OUT UINT64 *ResourceLength
+ )
+{
+ PCI_ROOT_BRIDGE_INSTANCE *PrivateData;
+ PrivateData = DRIVER_INSTANCE_FROM_PCI_ROOT_BRIDGE_IO_THIS (This);
+
+ if (Attributes) {
+ if ((Attributes & (~(PrivateData->Supports))) != 0) {
+ return EFI_UNSUPPORTED;
+ }
+ }
+
+ if (Attributes == PrivateData->Attributes) {
+ return EFI_SUCCESS;
+ }
+ //
+ // It is just a trick for some attribute can only be enabled or disabled
+ // otherwise it can impact on other devices
+ //
+ PrivateData->Attributes = Attributes;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ @todo add description
+
+**/
+/**
+// @todo This - add argument and description to function comment
+// @todo Resources - add argument and description to function comment
+// @todo EFI_SUCCESS - add return value to function comment
+
+**/
+EFI_STATUS
+EFIAPI
+RootBridgeIoConfiguration (
+ IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This,
+ OUT VOID **Resources
+ )
+{
+ PCI_ROOT_BRIDGE_INSTANCE *PrivateData;
+ UINTN Index;
+
+ PrivateData = DRIVER_INSTANCE_FROM_PCI_ROOT_BRIDGE_IO_THIS (This);
+
+ for (Index = 0; Index < TypeMax; Index++) {
+ if (PrivateData->ResAllocNode[Index].Status == ResAllocated) {
+ Configuration.SpaceDesp[Index].AddrRangeMin = PrivateData->ResAllocNode[Index].Base;
+ Configuration.SpaceDesp[Index].AddrRangeMax = PrivateData->ResAllocNode[Index].Base +
+ PrivateData->ResAllocNode[Index].Length -
+ 1;
+ Configuration.SpaceDesp[Index].AddrLen = PrivateData->ResAllocNode[Index].Length;
+ }
+ }
+
+ *Resources = &Configuration;
+ return EFI_SUCCESS;
+}
+
+/**
+ @todo add description
+
+**/
+/**
+// @todo This - add argument and description to function comment
+// @todo Write - add argument and description to function comment
+// @todo Width - add argument and description to function comment
+// @todo UserAddress - add argument and description to function comment
+// @todo Count - add argument and description to function comment
+// @todo UserBuffer - add argument and description to function comment
+// @todo EFI_INVALID_PARAMETER - add return value to function comment
+// @todo EFI_SUCCESS - add return value to function comment
+
+**/
+STATIC
+EFI_STATUS
+RootBridgeIoPciRW (
+ IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This,
+ IN BOOLEAN Write,
+ IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width,
+ IN UINT64 UserAddress,
+ IN UINTN Count,
+ IN OUT VOID *UserBuffer
+ )
+{
+ UINT32 InStride;
+ UINT32 OutStride;
+ EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_PCI_ADDRESS *PciRbAddr;
+ UINT8 *PcieRegAddr;
+
+ if ((Width & 0x03) >= EfiPciWidthUint64) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ InStride = 1 << (Width & 0x03);
+ OutStride = InStride;
+ if (Width >= (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH)EfiCpuIoWidthFifoUint8 && Width <= (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH)EfiCpuIoWidthFifoUint64) {
+ InStride = 0;
+ }
+
+ if (Width >= (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH)EfiCpuIoWidthFillUint8 && Width <= (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH)EfiCpuIoWidthFillUint64) {
+ OutStride = 0;
+ }
+
+ PciRbAddr = (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_PCI_ADDRESS *) &UserAddress;
+
+ PcieRegAddr = (UINT8 *) (UINTN) (PcdGet64 (PcdPciExpressBaseAddress) +
+ PCI_EXPRESS_LIB_ADDRESS(PciRbAddr->Bus, PciRbAddr->Device, PciRbAddr->Function, 0));
+
+ //
+ // Add the register offset to the address
+ //
+ if (PciRbAddr->ExtendedRegister != 0) {
+ PcieRegAddr += PciRbAddr->ExtendedRegister;
+ } else {
+ PcieRegAddr += PciRbAddr->Register;
+ }
+
+ while (Count) {
+ if (Write) {
+ This->Mem.Write (This, Width, (UINTN) PcieRegAddr, 1, UserBuffer);
+ } else {
+ This->Mem.Read (This, Width, (UINTN) PcieRegAddr, 1, UserBuffer);
+ }
+
+ UserBuffer = ((UINT8 *) UserBuffer) + OutStride;
+ PcieRegAddr += InStride;
+ Count -= 1;
+ }
+
+ return EFI_SUCCESS;
+}
diff --git a/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/PiSmmCommunication/PiSmmCommunicationPei.c b/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/PiSmmCommunication/PiSmmCommunicationPei.c
new file mode 100644
index 0000000000..d546181ca5
--- /dev/null
+++ b/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/PiSmmCommunication/PiSmmCommunicationPei.c
@@ -0,0 +1,424 @@
+/** @file
+ PiSmmCommunication PEI Driver.
+
+ Copyright (c) 2010 - 2015, 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 <PiPei.h>
+#include <PiDxe.h>
+#include <PiSmm.h>
+#include <Library/PeiServicesTablePointerLib.h>
+#include <Library/PeiServicesLib.h>
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/HobLib.h>
+#include <Library/DebugLib.h>
+#include <Protocol/SmmCommunication.h>
+#include <Ppi/SmmCommunication.h>
+#include <Ppi/SmmAccess.h>
+#include <Ppi/SmmControl.h>
+#include <Guid/AcpiS3Context.h>
+
+#include "PiSmmCommunicationPrivate.h"
+
+/**
+ the whole picture is below:
+
+ +----------------------------------+
+ | ACPI_VARIABLE_HOB |
+ | SmramDescriptor | <- DRAM
+ | CpuStart |
+ +----------------------------------+---
+ |
+ +----------------------------------+<--
+ | SMM_S3_RESUME_STATE |
+ | Signature | <- SMRAM
+ | Smst |
+ +----------------------------------+---
+ |
+ +----------------------------------+<--
+ | EFI_SMM_SYSTEM_TABLE2 |
+ | NumberOfTableEntries | <- SMRAM
+ | SmmConfigurationTable |
+ +----------------------------------+---
+ |
+ +----------------------------------+<--
+ | EFI_SMM_COMMUNICATION_CONTEXT |
+ | SwSmiNumber | <- SMRAM
+ | AcpiTableAddress |
+ +----------------------------------+---
+ |
+ +----------------------------------+<--
+ | EFI_SMM_COMMUNICATION_ACPI_TABLE |
+ | SwSmiNumber | <- AcpiNvs
+ | BufferPtrAddress |
+ +----------------------------------+---
+ |
+ +----------------------------------+<--
+ | EFI_SMM_COMMUNICATE_HEADER |
+ | HeaderGuid | <- DRAM
+ | MessageLength |
+ +----------------------------------+
+
+**/
+
+#if defined (MDE_CPU_IA32)
+typedef struct {
+ EFI_TABLE_HEADER Hdr;
+ UINT64 SmmFirmwareVendor;
+ UINT64 SmmFirmwareRevision;
+ UINT64 SmmInstallConfigurationTable;
+ UINT64 SmmIoMemRead;
+ UINT64 SmmIoMemWrite;
+ UINT64 SmmIoIoRead;
+ UINT64 SmmIoIoWrite;
+ UINT64 SmmAllocatePool;
+ UINT64 SmmFreePool;
+ UINT64 SmmAllocatePages;
+ UINT64 SmmFreePages;
+ UINT64 SmmStartupThisAp;
+ UINT64 CurrentlyExecutingCpu;
+ UINT64 NumberOfCpus;
+ UINT64 CpuSaveStateSize;
+ UINT64 CpuSaveState;
+ UINT64 NumberOfTableEntries;
+ UINT64 SmmConfigurationTable;
+} EFI_SMM_SYSTEM_TABLE2_64;
+
+typedef struct {
+ EFI_GUID VendorGuid;
+ UINT64 VendorTable;
+} EFI_CONFIGURATION_TABLE64;
+#endif
+
+#if defined (MDE_CPU_X64)
+typedef EFI_SMM_SYSTEM_TABLE2 EFI_SMM_SYSTEM_TABLE2_64;
+typedef EFI_CONFIGURATION_TABLE EFI_CONFIGURATION_TABLE64;
+#endif
+
+/**
+ Communicates with a registered handler.
+
+ This function provides a service to send and receive messages from a registered UEFI service.
+
+ @param[in] This The EFI_PEI_SMM_COMMUNICATION_PPI instance.
+ @param[in, out] CommBuffer A pointer to the buffer to convey into SMRAM.
+ @param[in, out] CommSize The size of the data buffer being passed in.On exit, the size of data
+ being returned. Zero if the handler does not wish to reply with any data.
+
+ @retval EFI_SUCCESS The message was successfully posted.
+ @retval EFI_INVALID_PARAMETER The CommBuffer was NULL.
+ @retval EFI_NOT_STARTED The service is NOT started.
+**/
+EFI_STATUS
+EFIAPI
+Communicate (
+ IN CONST EFI_PEI_SMM_COMMUNICATION_PPI *This,
+ IN OUT VOID *CommBuffer,
+ IN OUT UINTN *CommSize
+ );
+
+EFI_PEI_SMM_COMMUNICATION_PPI mSmmCommunicationPpi = { Communicate };
+
+EFI_PEI_PPI_DESCRIPTOR mPpiList = {
+ (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
+ &gEfiPeiSmmCommunicationPpiGuid,
+ &mSmmCommunicationPpi
+};
+
+/**
+ Get SMM communication context.
+
+ @return SMM communication context.
+**/
+EFI_SMM_COMMUNICATION_CONTEXT *
+GetCommunicationContext (
+ VOID
+ )
+{
+ EFI_HOB_GUID_TYPE *GuidHob;
+ EFI_SMM_COMMUNICATION_CONTEXT *SmmCommunicationContext;
+
+ GuidHob = GetFirstGuidHob (&gEfiPeiSmmCommunicationPpiGuid);
+ ASSERT (GuidHob != NULL);
+
+ SmmCommunicationContext = (EFI_SMM_COMMUNICATION_CONTEXT *)GET_GUID_HOB_DATA (GuidHob);
+
+ return SmmCommunicationContext;
+}
+
+/**
+ Set SMM communication context.
+
+ @param SmmCommunicationContext SMM communication context.
+**/
+VOID
+SetCommunicationContext (
+ IN EFI_SMM_COMMUNICATION_CONTEXT *SmmCommunicationContext
+ )
+{
+ EFI_PEI_HOB_POINTERS Hob;
+ UINTN BufferSize;
+
+ BufferSize = sizeof (*SmmCommunicationContext);
+ Hob.Raw = BuildGuidHob (
+ &gEfiPeiSmmCommunicationPpiGuid,
+ BufferSize
+ );
+ ASSERT (Hob.Raw);
+
+ CopyMem ((VOID *)Hob.Raw, SmmCommunicationContext, sizeof(*SmmCommunicationContext));
+}
+
+/**
+ Get VendorTable by VendorGuid in Smst.
+
+ @param Signature Signature of SMM_S3_RESUME_STATE
+ @param Smst SMM system table
+ @param VendorGuid vendor guid
+
+ @return vendor table.
+**/
+VOID *
+InternalSmstGetVendorTableByGuid (
+ IN UINT64 Signature,
+ IN EFI_SMM_SYSTEM_TABLE2 *Smst,
+ IN EFI_GUID *VendorGuid
+ )
+{
+ EFI_CONFIGURATION_TABLE *SmmConfigurationTable;
+ UINTN NumberOfTableEntries;
+ UINTN Index;
+ EFI_SMM_SYSTEM_TABLE2_64 *Smst64;
+ EFI_CONFIGURATION_TABLE64 *SmmConfigurationTable64;
+
+ if ((sizeof(UINTN) == sizeof(UINT32)) && (Signature == SMM_S3_RESUME_SMM_64)) {
+ //
+ // 32 PEI + 64 DXE
+ //
+ Smst64 = (EFI_SMM_SYSTEM_TABLE2_64 *)Smst;
+ DEBUG ((EFI_D_INFO, "InitCommunicationContext - SmmConfigurationTable: %x\n", Smst64->SmmConfigurationTable));
+ DEBUG ((EFI_D_INFO, "InitCommunicationContext - NumberOfTableEntries: %x\n", Smst64->NumberOfTableEntries));
+ SmmConfigurationTable64 = (EFI_CONFIGURATION_TABLE64 *)(UINTN)Smst64->SmmConfigurationTable;
+ NumberOfTableEntries = (UINTN)Smst64->NumberOfTableEntries;
+ for (Index = 0; Index < NumberOfTableEntries; Index++) {
+ if (CompareGuid (&SmmConfigurationTable64[Index].VendorGuid, VendorGuid)) {
+ return (VOID *)(UINTN)SmmConfigurationTable64[Index].VendorTable;
+ }
+ }
+ return NULL;
+ } else {
+ DEBUG ((EFI_D_INFO, "InitCommunicationContext - SmmConfigurationTable: %x\n", Smst->SmmConfigurationTable));
+ DEBUG ((EFI_D_INFO, "InitCommunicationContext - NumberOfTableEntries: %x\n", Smst->NumberOfTableEntries));
+ SmmConfigurationTable = Smst->SmmConfigurationTable;
+ NumberOfTableEntries = Smst->NumberOfTableEntries;
+ for (Index = 0; Index < NumberOfTableEntries; Index++) {
+ if (CompareGuid (&SmmConfigurationTable[Index].VendorGuid, VendorGuid)) {
+ return (VOID *)SmmConfigurationTable[Index].VendorTable;
+ }
+ }
+ return NULL;
+ }
+}
+
+/**
+ Init SMM communication context.
+**/
+VOID
+InitCommunicationContext (
+ VOID
+ )
+{
+ EFI_SMRAM_DESCRIPTOR *SmramDescriptor;
+ SMM_S3_RESUME_STATE *SmmS3ResumeState;
+ VOID *GuidHob;
+ EFI_SMM_COMMUNICATION_CONTEXT *SmmCommunicationContext;
+
+ GuidHob = GetFirstGuidHob (&gEfiAcpiVariableGuid);
+ ASSERT (GuidHob != NULL);
+ SmramDescriptor = (EFI_SMRAM_DESCRIPTOR *) GET_GUID_HOB_DATA (GuidHob);
+ SmmS3ResumeState = (SMM_S3_RESUME_STATE *)(UINTN)SmramDescriptor->CpuStart;
+
+ DEBUG ((EFI_D_INFO, "InitCommunicationContext - SmmS3ResumeState: %x\n", SmmS3ResumeState));
+ DEBUG ((EFI_D_INFO, "InitCommunicationContext - Smst: %x\n", SmmS3ResumeState->Smst));
+
+ SmmCommunicationContext = (EFI_SMM_COMMUNICATION_CONTEXT *)InternalSmstGetVendorTableByGuid (
+ SmmS3ResumeState->Signature,
+ (EFI_SMM_SYSTEM_TABLE2 *)(UINTN)SmmS3ResumeState->Smst,
+ &gEfiPeiSmmCommunicationPpiGuid
+ );
+ ASSERT (SmmCommunicationContext != NULL);
+
+ SetCommunicationContext (SmmCommunicationContext);
+
+ return ;
+}
+
+/**
+ Communicates with a registered handler.
+
+ This function provides a service to send and receive messages from a registered UEFI service.
+
+ @param[in] This The EFI_PEI_SMM_COMMUNICATION_PPI instance.
+ @param[in, out] CommBuffer A pointer to the buffer to convey into SMRAM.
+ @param[in, out] CommSize The size of the data buffer being passed in.On exit, the size of data
+ being returned. Zero if the handler does not wish to reply with any data.
+
+ @retval EFI_SUCCESS The message was successfully posted.
+ @retval EFI_INVALID_PARAMETER The CommBuffer was NULL.
+ @retval EFI_NOT_STARTED The service is NOT started.
+**/
+EFI_STATUS
+EFIAPI
+Communicate (
+ IN CONST EFI_PEI_SMM_COMMUNICATION_PPI *This,
+ IN OUT VOID *CommBuffer,
+ IN OUT UINTN *CommSize
+ )
+{
+ EFI_STATUS Status;
+ PEI_SMM_CONTROL_PPI *SmmControl;
+ PEI_SMM_ACCESS_PPI *SmmAccess;
+ UINT8 SmiCommand;
+ UINTN Size;
+ EFI_SMM_COMMUNICATION_CONTEXT *SmmCommunicationContext;
+ EFI_SMM_COMMUNICATION_ACPI_TABLE *SmmCommunicationAcpiTable;
+
+ DEBUG ((EFI_D_INFO, "PiSmmCommunicationPei Communicate Enter\n"));
+
+ if (CommBuffer == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Get needed resource
+ //
+ Status = PeiServicesLocatePpi (
+ &gPeiSmmControlPpiGuid,
+ 0,
+ NULL,
+ (VOID **)&SmmControl
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_NOT_STARTED;
+ }
+
+ Status = PeiServicesLocatePpi (
+ &gPeiSmmAccessPpiGuid,
+ 0,
+ NULL,
+ (VOID **)&SmmAccess
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_NOT_STARTED;
+ }
+
+ //
+ // Check SMRAM locked, it should be done after SMRAM lock.
+ //
+ if (!SmmAccess->LockState) {
+ DEBUG ((EFI_D_INFO, "PiSmmCommunicationPei LockState - %x\n", (UINTN)SmmAccess->LockState));
+ return EFI_NOT_STARTED;
+ }
+
+ SmmCommunicationContext = GetCommunicationContext ();
+ DEBUG ((EFI_D_INFO, "PiSmmCommunicationPei AcpiTableAddress - %x\n", (UINTN)SmmCommunicationContext->AcpiTableAddress));
+
+ SmmCommunicationAcpiTable = (EFI_SMM_COMMUNICATION_ACPI_TABLE *)(UINTN)SmmCommunicationContext->AcpiTableAddress;
+ //
+ // No need to check if BufferPtrAddress is 0, because it is in PEI phase.
+ //
+ SmmCommunicationAcpiTable->BufferPtrAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)CommBuffer;
+ DEBUG ((EFI_D_INFO, "PiSmmCommunicationPei CommBuffer - %x\n", (UINTN)CommBuffer));
+
+ //
+ // Send command
+ //
+ SmiCommand = (UINT8)SmmCommunicationContext->SwSmiNumber;
+ Size = sizeof(SmiCommand);
+ Status = SmmControl->Trigger (
+ (EFI_PEI_SERVICES **)GetPeiServicesTablePointer (),
+ SmmControl,
+ (INT8 *)&SmiCommand,
+ &Size,
+ FALSE,
+ 0
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Setting BufferPtrAddress to 0 means this transaction is done.
+ //
+ SmmCommunicationAcpiTable->BufferPtrAddress = 0;
+
+ DEBUG ((EFI_D_INFO, "PiSmmCommunicationPei Communicate Exit\n"));
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Entry Point for PI SMM communication PEIM.
+
+ @param FileHandle Handle of the file being invoked.
+ @param PeiServices Pointer to PEI Services table.
+
+ @retval EFI_SUCEESS
+ @return Others Some error occurs.
+**/
+EFI_STATUS
+EFIAPI
+PiSmmCommunicationPeiEntryPoint (
+ IN EFI_PEI_FILE_HANDLE FileHandle,
+ IN CONST EFI_PEI_SERVICES **PeiServices
+ )
+{
+ EFI_STATUS Status;
+ PEI_SMM_ACCESS_PPI *SmmAccess;
+ EFI_BOOT_MODE BootMode;
+ UINTN Index;
+
+ BootMode = GetBootModeHob ();
+ if (BootMode != BOOT_ON_S3_RESUME) {
+ return EFI_UNSUPPORTED;
+ }
+
+ Status = PeiServicesLocatePpi (
+ &gPeiSmmAccessPpiGuid,
+ 0,
+ NULL,
+ (VOID **)&SmmAccess
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_NOT_STARTED;
+ }
+
+ //
+ // Check SMRAM locked, it should be done before SMRAM lock.
+ //
+ if (SmmAccess->LockState) {
+ DEBUG ((EFI_D_INFO, "PiSmmCommunicationPei LockState - %x\n", (UINTN)SmmAccess->LockState));
+ return EFI_ACCESS_DENIED;
+ }
+
+ //
+ // Open all SMRAM
+ //
+ for (Index = 0; !EFI_ERROR (Status); Index++) {
+ Status = SmmAccess->Open ((EFI_PEI_SERVICES **)GetPeiServicesTablePointer (), SmmAccess, Index);
+ }
+
+ InitCommunicationContext ();
+
+ PeiServicesInstallPpi (&mPpiList);
+
+ return RETURN_SUCCESS;
+}
diff --git a/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/PiSmmCommunication/PiSmmCommunicationPei.inf b/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/PiSmmCommunication/PiSmmCommunicationPei.inf
new file mode 100644
index 0000000000..fd1cb31264
--- /dev/null
+++ b/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/PiSmmCommunication/PiSmmCommunicationPei.inf
@@ -0,0 +1,67 @@
+## @file
+# PI SMM Communication PEIM which produces PEI SMM Communication PPI.
+#
+# This PEIM retrieves the SMM communication context and produces PEI SMM
+# Communication PPIin the S3 boot mode.
+#
+# Copyright (c) 2010 - 2015, 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 = 0x00010018
+ BASE_NAME = PiSmmCommunicationPei
+ FILE_GUID = 1C8B7F78-1699-40e6-AF33-9B995D16B043
+ MODULE_TYPE = PEIM
+ VERSION_STRING = 1.0
+ ENTRY_POINT = PiSmmCommunicationPeiEntryPoint
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64
+#
+
+[Sources]
+ PiSmmCommunicationPei.c
+ PiSmmCommunicationPrivate.h
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+ PeimEntryPoint
+ PeiServicesTablePointerLib
+ PeiServicesLib
+ BaseLib
+ BaseMemoryLib
+ HobLib
+ DebugLib
+
+[Guids]
+ gEfiAcpiVariableGuid ## CONSUMES ## HOB
+
+[Ppis]
+ ## PRODUCES
+ ## UNDEFINED # HOB # SMM Configuration Table
+ gEfiPeiSmmCommunicationPpiGuid
+ gPeiSmmAccessPpiGuid ## CONSUMES
+ gPeiSmmControlPpiGuid ## CONSUMES
+
+# [BootMode]
+# S3_RESUME ## CONSUMES
+
+[Depex]
+ gPeiSmmAccessPpiGuid AND
+ gPeiSmmControlPpiGuid AND
+ gEfiPeiMasterBootModePpiGuid
+
diff --git a/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/PiSmmCommunication/PiSmmCommunicationPrivate.h b/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/PiSmmCommunication/PiSmmCommunicationPrivate.h
new file mode 100644
index 0000000000..1001aa2416
--- /dev/null
+++ b/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/PiSmmCommunication/PiSmmCommunicationPrivate.h
@@ -0,0 +1,31 @@
+/** @file
+ PiSmmCommunication private data structure
+
+ Copyright (c) 2010 - 2015, 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 _SMM_COMMUNICATION_PRIVATE_H_
+#define _SMM_COMMUNICATION_PRIVATE_H_
+
+#pragma pack(push, 1)
+
+#define SMM_COMMUNICATION_SIGNATURE SIGNATURE_32 ('S','M','M','C')
+
+typedef struct {
+ UINT32 Signature;
+ UINT32 SwSmiNumber;
+ EFI_PHYSICAL_ADDRESS AcpiTableAddress;
+} EFI_SMM_COMMUNICATION_CONTEXT;
+
+#pragma pack(pop)
+
+#endif
diff --git a/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/PiSmmCommunication/PiSmmCommunicationSmm.c b/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/PiSmmCommunication/PiSmmCommunicationSmm.c
new file mode 100644
index 0000000000..7d2091bb02
--- /dev/null
+++ b/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/PiSmmCommunication/PiSmmCommunicationSmm.c
@@ -0,0 +1,288 @@
+/** @file
+ PiSmmCommunication SMM Driver.
+
+ Copyright (c) 2010 - 2015, 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 <PiSmm.h>
+#include <Library/UefiDriverEntryPoint.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiRuntimeServicesTableLib.h>
+#include <Library/SmmServicesTableLib.h>
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/HobLib.h>
+#include <Library/DebugLib.h>
+#include <Library/PcdLib.h>
+#include <Protocol/SmmSwDispatch2.h>
+#include <Protocol/SmmReadyToLock.h>
+#include <Protocol/SmmCommunication.h>
+#include <Protocol/AcpiTable.h>
+#include <Ppi/SmmCommunication.h>
+#include <Guid/Acpi.h>
+
+#include "PiSmmCommunicationPrivate.h"
+
+EFI_SMM_COMMUNICATION_CONTEXT mSmmCommunicationContext = {
+ SMM_COMMUNICATION_SIGNATURE
+};
+
+EFI_SMM_COMMUNICATION_ACPI_TABLE mSmmCommunicationAcpiTable = {
+ {
+ {
+ EFI_ACPI_4_0_UEFI_ACPI_DATA_TABLE_SIGNATURE,
+ sizeof (EFI_SMM_COMMUNICATION_ACPI_TABLE),
+ 0x1, // Revision
+ 0x0, // Checksum
+ {0x0}, // OemId[6]
+ 0x0, // OemTableId
+ 0x0, // OemRevision
+ 0x0, // CreatorId
+ 0x0 // CreatorRevision
+ },
+ {0x0}, // Identifier
+ OFFSET_OF (EFI_SMM_COMMUNICATION_ACPI_TABLE, SwSmiNumber) // DataOffset
+ },
+ 0x0, // SwSmiNumber
+ 0x0 // BufferPtrAddress
+};
+
+/**
+ Set SMM communication context.
+**/
+VOID
+SetCommunicationContext (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+
+ Status = gSmst->SmmInstallConfigurationTable (
+ gSmst,
+ &gEfiPeiSmmCommunicationPpiGuid,
+ &mSmmCommunicationContext,
+ sizeof(mSmmCommunicationContext)
+ );
+ ASSERT_EFI_ERROR (Status);
+}
+
+/**
+ Get SMM communication ACPI table address.
+
+ @return SMM communication ACPI table address.
+**/
+EFI_PHYSICAL_ADDRESS
+GetSmmCommunicationAcpiTableAddress (
+ VOID
+ )
+{
+ EFI_ACPI_4_0_ROOT_SYSTEM_DESCRIPTION_POINTER *Rsdp;
+ EFI_ACPI_DESCRIPTION_HEADER *Rsdt;
+ EFI_ACPI_DESCRIPTION_HEADER *Xsdt;
+ UINTN Index;
+ UINT32 *TableAddress;
+ UINT64 *XTableAddress;
+ UINTN TableCount;
+ EFI_SMM_COMMUNICATION_ACPI_TABLE *SmmAcpi;
+
+ Rsdp = NULL;
+ for (Index = 0; Index < gST->NumberOfTableEntries; Index++) {
+ if (CompareGuid (&(gST->ConfigurationTable[Index].VendorGuid), &gEfiAcpi20TableGuid) ||
+ CompareGuid (&(gST->ConfigurationTable[Index].VendorGuid), &gEfiAcpi10TableGuid) ||
+ CompareGuid (&(gST->ConfigurationTable[Index].VendorGuid), &gEfiAcpiTableGuid) ) {
+ //
+ // A match was found.
+ //
+ Rsdp = (EFI_ACPI_4_0_ROOT_SYSTEM_DESCRIPTION_POINTER *) gST->ConfigurationTable[Index].VendorTable;
+ break;
+ }
+ }
+
+ ASSERT (Rsdp != NULL);
+ if (Rsdp == NULL) {
+ return 0;
+ }
+
+ Rsdt = (EFI_ACPI_DESCRIPTION_HEADER *) (UINTN) Rsdp->RsdtAddress;
+ TableCount = (Rsdt->Length - sizeof(EFI_ACPI_DESCRIPTION_HEADER)) / sizeof(UINT32);
+ TableAddress = (UINT32 *)(Rsdt + 1);
+ for (Index = 0; Index < TableCount; Index++) {
+ SmmAcpi = (EFI_SMM_COMMUNICATION_ACPI_TABLE *)(UINTN)TableAddress[Index];
+ if (SmmAcpi == NULL) {
+ continue;
+ }
+ if ((SmmAcpi->UefiAcpiDataTable.Header.Signature == EFI_ACPI_4_0_UEFI_ACPI_DATA_TABLE_SIGNATURE) &&
+ (SmmAcpi->UefiAcpiDataTable.Header.Length == sizeof (EFI_SMM_COMMUNICATION_ACPI_TABLE)) &&
+ CompareGuid (&(SmmAcpi->UefiAcpiDataTable.Identifier), &gEfiSmmCommunicationProtocolGuid) ) {
+ return (EFI_PHYSICAL_ADDRESS)(UINTN)SmmAcpi;
+ }
+ }
+
+ if (Rsdp->Revision >= 2) {
+ Xsdt = (EFI_ACPI_DESCRIPTION_HEADER *) (UINTN) Rsdp->XsdtAddress;
+ TableCount = (Rsdt->Length - sizeof(EFI_ACPI_DESCRIPTION_HEADER)) / sizeof(UINT64);
+ XTableAddress = (UINT64 *)(Xsdt + 1);
+ for (Index = 0; Index < TableCount; Index++) {
+ SmmAcpi = (EFI_SMM_COMMUNICATION_ACPI_TABLE *)(UINTN)XTableAddress[Index];
+ if (SmmAcpi == NULL) {
+ continue;
+ }
+ if ((SmmAcpi->UefiAcpiDataTable.Header.Signature == EFI_ACPI_4_0_UEFI_ACPI_DATA_TABLE_SIGNATURE) &&
+ (SmmAcpi->UefiAcpiDataTable.Header.Length == sizeof (EFI_SMM_COMMUNICATION_ACPI_TABLE)) &&
+ CompareGuid (&(SmmAcpi->UefiAcpiDataTable.Identifier), &gEfiSmmCommunicationProtocolGuid) ) {
+ return (EFI_PHYSICAL_ADDRESS)(UINTN)SmmAcpi;
+ }
+ }
+ }
+
+ ASSERT(FALSE);
+ return 0;
+}
+
+/**
+ Dispatch function for a Software SMI handler.
+
+ @param DispatchHandle The unique handle assigned to this handler by SmiHandlerRegister().
+ @param Context Points to an optional handler context which was specified when the
+ handler was registered.
+ @param CommBuffer A pointer to a collection of data in memory that will
+ be conveyed from a non-SMM environment into an SMM environment.
+ @param CommBufferSize The size of the CommBuffer.
+
+ @retval EFI_SUCCESS Command is handled successfully.
+
+**/
+EFI_STATUS
+EFIAPI
+PiSmmCommunicationHandler (
+ IN EFI_HANDLE DispatchHandle,
+ IN CONST VOID *Context OPTIONAL,
+ IN OUT VOID *CommBuffer OPTIONAL,
+ IN OUT UINTN *CommBufferSize OPTIONAL
+ )
+{
+ EFI_SMM_COMMUNICATION_ACPI_TABLE *SmmCommunicationAcpiTable;
+ UINTN CommSize;
+ EFI_STATUS Status;
+ EFI_SMM_COMMUNICATE_HEADER *CommunicateHeader;
+
+ DEBUG ((EFI_D_INFO, "PiSmmCommunicationHandler Enter\n"));
+
+ SmmCommunicationAcpiTable = (EFI_SMM_COMMUNICATION_ACPI_TABLE *)(UINTN)mSmmCommunicationContext.AcpiTableAddress;
+ CommunicateHeader = (EFI_SMM_COMMUNICATE_HEADER *)(UINTN)SmmCommunicationAcpiTable->BufferPtrAddress;
+ DEBUG ((EFI_D_INFO, "PiSmmCommunicationHandler CommunicateHeader - %x\n", CommunicateHeader));
+ if (CommunicateHeader == NULL) {
+ DEBUG ((EFI_D_INFO, "PiSmmCommunicationHandler is NULL, needn't to call dispatch function\n"));
+ Status = EFI_SUCCESS;
+ } else {
+ CommSize = (UINTN)CommunicateHeader->MessageLength;
+
+ //
+ // Call dispatch function
+ //
+ DEBUG ((EFI_D_INFO, "PiSmmCommunicationHandler Data - %x\n", &CommunicateHeader->Data[0]));
+ Status = gSmst->SmiManage (
+ &CommunicateHeader->HeaderGuid,
+ NULL,
+ &CommunicateHeader->Data[0],
+ &CommSize
+ );
+ }
+ DEBUG ((EFI_D_INFO, "PiSmmCommunicationHandler %r\n", Status));
+ DEBUG ((EFI_D_INFO, "PiSmmCommunicationHandler Exit\n"));
+
+ return (Status == EFI_SUCCESS) ? EFI_SUCCESS : EFI_INTERRUPT_PENDING;
+}
+
+/**
+ Entry Point for PI SMM communication SMM driver.
+
+ @param[in] ImageHandle Image handle of this driver.
+ @param[in] SystemTable A Pointer to the EFI System Table.
+
+ @retval EFI_SUCEESS
+ @return Others Some error occurs.
+**/
+EFI_STATUS
+EFIAPI
+PiSmmCommunicationSmmEntryPoint (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+ EFI_SMM_SW_DISPATCH2_PROTOCOL *SmmSwDispatch2;
+ EFI_SMM_SW_REGISTER_CONTEXT SmmSwDispatchContext;
+ EFI_HANDLE DispatchHandle;
+ EFI_ACPI_TABLE_PROTOCOL *AcpiTableProtocol;
+ UINTN TableKey;
+ UINT64 OemTableId;
+
+ CopyMem (
+ mSmmCommunicationAcpiTable.UefiAcpiDataTable.Header.OemId,
+ PcdGetPtr (PcdAcpiDefaultOemId),
+ sizeof (mSmmCommunicationAcpiTable.UefiAcpiDataTable.Header.OemId)
+ );
+ OemTableId = PcdGet64 (PcdAcpiDefaultOemTableId);
+ CopyMem (&mSmmCommunicationAcpiTable.UefiAcpiDataTable.Header.OemTableId, &OemTableId, sizeof (UINT64));
+ mSmmCommunicationAcpiTable.UefiAcpiDataTable.Header.OemRevision = PcdGet32 (PcdAcpiDefaultOemRevision);
+ mSmmCommunicationAcpiTable.UefiAcpiDataTable.Header.CreatorId = PcdGet32 (PcdAcpiDefaultCreatorId);
+ mSmmCommunicationAcpiTable.UefiAcpiDataTable.Header.CreatorRevision = PcdGet32 (PcdAcpiDefaultCreatorRevision);
+
+ //
+ // Register software SMI handler
+ //
+ Status = gSmst->SmmLocateProtocol (
+ &gEfiSmmSwDispatch2ProtocolGuid,
+ NULL,
+ (VOID **)&SmmSwDispatch2
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ SmmSwDispatchContext.SwSmiInputValue = (UINTN)-1;
+ Status = SmmSwDispatch2->Register (
+ SmmSwDispatch2,
+ PiSmmCommunicationHandler,
+ &SmmSwDispatchContext,
+ &DispatchHandle
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ DEBUG ((EFI_D_INFO, "SmmCommunication SwSmi: %x\n", (UINTN)SmmSwDispatchContext.SwSmiInputValue));
+
+ //
+ // Set ACPI table
+ //
+ Status = gBS->LocateProtocol (&gEfiAcpiTableProtocolGuid, NULL, (VOID **) &AcpiTableProtocol);
+ ASSERT_EFI_ERROR (Status);
+
+ mSmmCommunicationAcpiTable.SwSmiNumber = (UINT32)SmmSwDispatchContext.SwSmiInputValue;
+ CopyMem (&mSmmCommunicationAcpiTable.UefiAcpiDataTable.Identifier, &gEfiSmmCommunicationProtocolGuid, sizeof(gEfiSmmCommunicationProtocolGuid));
+
+ Status = AcpiTableProtocol->InstallAcpiTable (
+ AcpiTableProtocol,
+ &mSmmCommunicationAcpiTable,
+ sizeof(mSmmCommunicationAcpiTable),
+ &TableKey
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Save context
+ //
+ mSmmCommunicationContext.SwSmiNumber = (UINT32)SmmSwDispatchContext.SwSmiInputValue;
+ mSmmCommunicationContext.AcpiTableAddress = GetSmmCommunicationAcpiTableAddress ();
+ DEBUG ((EFI_D_INFO, "SmmCommunicationAcpiTable: %x\n", mSmmCommunicationContext.AcpiTableAddress));
+ SetCommunicationContext ();
+
+ return Status;
+}
diff --git a/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/PiSmmCommunication/PiSmmCommunicationSmm.inf b/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/PiSmmCommunication/PiSmmCommunicationSmm.inf
new file mode 100644
index 0000000000..22a61ee147
--- /dev/null
+++ b/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/PiSmmCommunication/PiSmmCommunicationSmm.inf
@@ -0,0 +1,78 @@
+## @file
+# PI SMM Communication SMM driver that installs the SMM Communication ACPI Table.
+#
+# This SMM driver installs the SMM Communication ACPI Table defined in the UEFI spec
+# which provides a mechanism that can be used in the OS present environment by
+# non-firmware agents for inter-mode communication with SMM agents. It also saves
+# SMM communication context for use by SMM Communication PEIM in the S3 boot mode.
+#
+# Copyright (c) 2010 - 2015, 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 = 0x00010018
+ BASE_NAME = PiSmmCommunicationSmm
+ FILE_GUID = E21F35A8-42FF-4050-82D6-93F7CDFA7073
+ MODULE_TYPE = DXE_SMM_DRIVER
+ VERSION_STRING = 1.0
+ PI_SPECIFICATION_VERSION = 0x0001000A
+ ENTRY_POINT = PiSmmCommunicationSmmEntryPoint
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64
+#
+
+[Sources]
+ PiSmmCommunicationSmm.c
+ PiSmmCommunicationPrivate.h
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+ UefiDriverEntryPoint
+ UefiBootServicesTableLib
+ UefiRuntimeServicesTableLib
+ SmmServicesTableLib
+ BaseLib
+ BaseMemoryLib
+ HobLib
+ DebugLib
+ PcdLib
+
+[Guids]
+ gEfiAcpi20TableGuid ## SOMETIMES_CONSUMES ## SystemTable
+ gEfiAcpi10TableGuid ## SOMETIMES_CONSUMES ## SystemTable
+ gEfiAcpiTableGuid ## SOMETIMES_CONSUMES ## SystemTable
+
+[Ppis]
+ gEfiPeiSmmCommunicationPpiGuid ## UNDEFINED # SMM Configuration Table
+
+[Protocols]
+ gEfiSmmSwDispatch2ProtocolGuid ## CONSUMES
+ gEfiSmmCommunicationProtocolGuid ## UNDEFINED # SMM Communication ACPI Table GUID
+ gEfiAcpiTableProtocolGuid ## CONSUMES
+
+[Pcd]
+ gEfiMdeModulePkgTokenSpaceGuid.PcdAcpiDefaultOemId ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdAcpiDefaultOemTableId ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdAcpiDefaultOemRevision ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdAcpiDefaultCreatorId ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdAcpiDefaultCreatorRevision ## CONSUMES
+
+[Depex]
+ gEfiSmmSwDispatch2ProtocolGuid AND
+ gEfiAcpiTableProtocolGuid
+
diff --git a/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/PiSmmCpuDxeSmm/CpuS3.c b/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/PiSmmCpuDxeSmm/CpuS3.c
new file mode 100644
index 0000000000..6f577ed183
--- /dev/null
+++ b/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/PiSmmCpuDxeSmm/CpuS3.c
@@ -0,0 +1,435 @@
+/** @file
+ Code for Processor S3 restoration
+
+ Copyright (c) 2006 - 2015, 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 "PiSmmCpuDxeSmm.h"
+
+typedef struct {
+ UINTN Lock;
+ VOID *StackStart;
+ UINTN StackSize;
+ VOID *ApFunction;
+ IA32_DESCRIPTOR GdtrProfile;
+ IA32_DESCRIPTOR IdtrProfile;
+ UINT32 BufferStart;
+ UINT32 Cr3;
+} MP_CPU_EXCHANGE_INFO;
+
+typedef struct {
+ UINT8 *RendezvousFunnelAddress;
+ UINTN PModeEntryOffset;
+ UINTN FlatJumpOffset;
+ UINTN Size;
+ UINTN LModeEntryOffset;
+ UINTN LongJumpOffset;
+} MP_ASSEMBLY_ADDRESS_MAP;
+
+/**
+ Get starting address and size of the rendezvous entry for APs.
+ Information for fixing a jump instruction in the code is also returned.
+
+ @param AddressMap Output buffer for address map information.
+
+**/
+VOID *
+EFIAPI
+AsmGetAddressMap (
+ MP_ASSEMBLY_ADDRESS_MAP *AddressMap
+ );
+
+#define LEGACY_REGION_SIZE (2 * 0x1000)
+#define LEGACY_REGION_BASE (0xA0000 - LEGACY_REGION_SIZE)
+
+ACPI_CPU_DATA mAcpiCpuData;
+UINT32 mNumberToFinish;
+MP_CPU_EXCHANGE_INFO *mExchangeInfo;
+BOOLEAN mRestoreSmmConfigurationInS3 = FALSE;
+VOID *mGdtForAp = NULL;
+VOID *mIdtForAp = NULL;
+VOID *mMachineCheckHandlerForAp = NULL;
+SPIN_LOCK mMsrLock;
+
+/**
+ Synch up the MTRR values for all processors.
+
+ @param MtrrTable Table holding fixed/variable MTRR values to be loaded.
+
+ @retval None
+
+**/
+VOID
+EFIAPI
+LoadMtrrData (
+ EFI_PHYSICAL_ADDRESS MtrrTable
+ )
+{
+ MTRR_SETTINGS *MtrrSettings;
+
+ MtrrSettings = (MTRR_SETTINGS *) (UINTN) MtrrTable;
+ MtrrSetAllMtrrs (MtrrSettings);
+}
+
+/**
+ Programs registers for the calling processor.
+ This function programs registers for the calling processor.
+
+ @param RegisterTable Pointer to register table of the running processor.
+
+**/
+VOID
+SetProcessorRegister (
+ CPU_REGISTER_TABLE *RegisterTable
+ )
+{
+ CPU_REGISTER_TABLE_ENTRY *RegisterTableEntry;
+ UINTN Index;
+ UINTN Value;
+
+ //
+ // Traverse Register Table of this logical processor
+ //
+ RegisterTableEntry = (CPU_REGISTER_TABLE_ENTRY *) (UINTN) RegisterTable->RegisterTableEntry;
+ for (Index = 0; Index < RegisterTable->TableLength; Index++, RegisterTableEntry++) {
+ //
+ // Check the type of specified register
+ //
+ switch (RegisterTableEntry->RegisterType) {
+ //
+ // The specified register is Control Register
+ //
+ case ControlRegister:
+ switch (RegisterTableEntry->Index) {
+ case 0:
+ Value = AsmReadCr0 ();
+ Value = (UINTN) BitFieldWrite64 (
+ Value,
+ RegisterTableEntry->ValidBitStart,
+ RegisterTableEntry->ValidBitStart + RegisterTableEntry->ValidBitLength - 1,
+ (UINTN) RegisterTableEntry->Value
+ );
+ AsmWriteCr0 (Value);
+ break;
+ case 2:
+ Value = AsmReadCr2 ();
+ Value = (UINTN) BitFieldWrite64 (
+ Value,
+ RegisterTableEntry->ValidBitStart,
+ RegisterTableEntry->ValidBitStart + RegisterTableEntry->ValidBitLength - 1,
+ (UINTN) RegisterTableEntry->Value
+ );
+ AsmWriteCr2 (Value);
+ break;
+ case 3:
+ Value = AsmReadCr3 ();
+ Value = (UINTN) BitFieldWrite64 (
+ Value,
+ RegisterTableEntry->ValidBitStart,
+ RegisterTableEntry->ValidBitStart + RegisterTableEntry->ValidBitLength - 1,
+ (UINTN) RegisterTableEntry->Value
+ );
+ AsmWriteCr3 (Value);
+ break;
+ case 4:
+ Value = AsmReadCr4 ();
+ Value = (UINTN) BitFieldWrite64 (
+ Value,
+ RegisterTableEntry->ValidBitStart,
+ RegisterTableEntry->ValidBitStart + RegisterTableEntry->ValidBitLength - 1,
+ (UINTN) RegisterTableEntry->Value
+ );
+ AsmWriteCr4 (Value);
+ break;
+ default:
+ break;
+ }
+ break;
+ //
+ // The specified register is Model Specific Register
+ //
+ case Msr:
+ //
+ // Get lock to avoid Package/Core scope MSRs programming issue in parallel execution mode
+ //
+ AcquireSpinLock (&mMsrLock);
+ //
+ // If this function is called to restore register setting after INIT signal,
+ // there is no need to restore MSRs in register table.
+ //
+ if (RegisterTableEntry->ValidBitLength >= 64) {
+ //
+ // If length is not less than 64 bits, then directly write without reading
+ //
+ AsmWriteMsr64 (
+ RegisterTableEntry->Index,
+ RegisterTableEntry->Value
+ );
+ } else {
+ //
+ // Set the bit section according to bit start and length
+ //
+ AsmMsrBitFieldWrite64 (
+ RegisterTableEntry->Index,
+ RegisterTableEntry->ValidBitStart,
+ RegisterTableEntry->ValidBitStart + RegisterTableEntry->ValidBitLength - 1,
+ RegisterTableEntry->Value
+ );
+ }
+ ReleaseSpinLock (&mMsrLock);
+ break;
+ //
+ // Enable or disable cache
+ //
+ case CacheControl:
+ //
+ // If value of the entry is 0, then disable cache. Otherwise, enable cache.
+ //
+ if (RegisterTableEntry->Value == 0) {
+ AsmDisableCache ();
+ } else {
+ AsmEnableCache ();
+ }
+ break;
+
+ default:
+ break;
+ }
+ }
+}
+
+/**
+ AP initialization before SMBASE relocation in the S3 boot path.
+**/
+VOID
+EarlyMPRendezvousProcedure (
+ VOID
+ )
+{
+ CPU_REGISTER_TABLE *RegisterTableList;
+ UINT32 InitApicId;
+ UINTN Index;
+
+ LoadMtrrData (mAcpiCpuData.MtrrTable);
+
+ //
+ // Find processor number for this CPU.
+ //
+ RegisterTableList = (CPU_REGISTER_TABLE *) (UINTN) mAcpiCpuData.PreSmmInitRegisterTable;
+ InitApicId = GetInitialApicId ();
+ for (Index = 0; Index < mAcpiCpuData.NumberOfCpus; Index++) {
+ if (RegisterTableList[Index].InitialApicId == InitApicId) {
+ SetProcessorRegister (&RegisterTableList[Index]);
+ break;
+ }
+ }
+
+ //
+ // Count down the number with lock mechanism.
+ //
+ InterlockedDecrement (&mNumberToFinish);
+}
+
+/**
+ AP initialization after SMBASE relocation in the S3 boot path.
+**/
+VOID
+MPRendezvousProcedure (
+ VOID
+ )
+{
+ CPU_REGISTER_TABLE *RegisterTableList;
+ UINT32 InitApicId;
+ UINTN Index;
+
+ ProgramVirtualWireMode ();
+ DisableLvtInterrupts ();
+
+ RegisterTableList = (CPU_REGISTER_TABLE *) (UINTN) mAcpiCpuData.RegisterTable;
+ InitApicId = GetInitialApicId ();
+ for (Index = 0; Index < mAcpiCpuData.NumberOfCpus; Index++) {
+ if (RegisterTableList[Index].InitialApicId == InitApicId) {
+ SetProcessorRegister (&RegisterTableList[Index]);
+ break;
+ }
+ }
+
+ //
+ // Count down the number with lock mechanism.
+ //
+ InterlockedDecrement (&mNumberToFinish);
+}
+
+/**
+ Prepares startup vector for APs.
+ This function prepares startup vector for APs.
+
+ @param WorkingBuffer The address of the work buffer.
+
+**/
+VOID
+PrepareAPStartupVector (
+ EFI_PHYSICAL_ADDRESS WorkingBuffer
+ )
+{
+ EFI_PHYSICAL_ADDRESS StartupVector;
+ MP_ASSEMBLY_ADDRESS_MAP AddressMap;
+
+ //
+ // Get the address map of startup code for AP,
+ // including code size, and offset of long jump instructions to redirect.
+ //
+ ZeroMem (&AddressMap, sizeof (AddressMap));
+ AsmGetAddressMap (&AddressMap);
+
+ StartupVector = WorkingBuffer;
+
+ //
+ // Copy AP startup code to startup vector, and then redirect the long jump
+ // instructions for mode switching.
+ //
+ CopyMem ((VOID *) (UINTN) StartupVector, AddressMap.RendezvousFunnelAddress, AddressMap.Size);
+ *(UINT32 *) (UINTN) (StartupVector + AddressMap.FlatJumpOffset + 3) = (UINT32) (StartupVector + AddressMap.PModeEntryOffset);
+ if (AddressMap.LongJumpOffset != 0) {
+ *(UINT32 *) (UINTN) (StartupVector + AddressMap.LongJumpOffset + 2) = (UINT32) (StartupVector + AddressMap.LModeEntryOffset);
+ }
+
+ //
+ // Get the start address of exchange data between BSP and AP.
+ //
+ mExchangeInfo = (MP_CPU_EXCHANGE_INFO *) (UINTN) (StartupVector + AddressMap.Size);
+ ZeroMem ((VOID *) mExchangeInfo, sizeof (MP_CPU_EXCHANGE_INFO));
+
+ CopyMem ((VOID *) (UINTN) &mExchangeInfo->GdtrProfile, (VOID *) (UINTN) mAcpiCpuData.GdtrProfile, sizeof (IA32_DESCRIPTOR));
+ CopyMem ((VOID *) (UINTN) &mExchangeInfo->IdtrProfile, (VOID *) (UINTN) mAcpiCpuData.IdtrProfile, sizeof (IA32_DESCRIPTOR));
+
+ //
+ // Copy AP's GDT, IDT and Machine Check handler from SMRAM to ACPI NVS memory
+ //
+ CopyMem ((VOID *) mExchangeInfo->GdtrProfile.Base, mGdtForAp, mExchangeInfo->GdtrProfile.Limit + 1);
+ CopyMem ((VOID *) mExchangeInfo->IdtrProfile.Base, mIdtForAp, mExchangeInfo->IdtrProfile.Limit + 1);
+ CopyMem ((VOID *)(UINTN) mAcpiCpuData.ApMachineCheckHandlerBase, mMachineCheckHandlerForAp, mAcpiCpuData.ApMachineCheckHandlerSize);
+
+ mExchangeInfo->StackStart = (VOID *) (UINTN) mAcpiCpuData.StackAddress;
+ mExchangeInfo->StackSize = mAcpiCpuData.StackSize;
+ mExchangeInfo->BufferStart = (UINT32) StartupVector;
+ mExchangeInfo->Cr3 = (UINT32) (AsmReadCr3 ());
+}
+
+/**
+ The function is invoked before SMBASE relocation in S3 path to restors CPU status.
+
+ The function is invoked before SMBASE relocation in S3 path. It does first time microcode load
+ and restores MTRRs for both BSP and APs.
+
+**/
+VOID
+EarlyInitializeCpu (
+ VOID
+ )
+{
+ CPU_REGISTER_TABLE *RegisterTableList;
+ UINT32 InitApicId;
+ UINTN Index;
+
+ //
+ // Initialize spin lock for MSR programming
+ //
+ InitializeSpinLock (&mMsrLock);
+
+ LoadMtrrData (mAcpiCpuData.MtrrTable);
+
+ //
+ // Find processor number for this CPU.
+ //
+ RegisterTableList = (CPU_REGISTER_TABLE *) (UINTN) mAcpiCpuData.PreSmmInitRegisterTable;
+ InitApicId = GetInitialApicId ();
+ for (Index = 0; Index < mAcpiCpuData.NumberOfCpus; Index++) {
+ if (RegisterTableList[Index].InitialApicId == InitApicId) {
+ SetProcessorRegister (&RegisterTableList[Index]);
+ break;
+ }
+ }
+
+ ProgramVirtualWireMode ();
+
+ PrepareAPStartupVector (mAcpiCpuData.StartupVector);
+
+ mNumberToFinish = mAcpiCpuData.NumberOfCpus - 1;
+ mExchangeInfo->ApFunction = (VOID *) (UINTN) EarlyMPRendezvousProcedure;
+
+ //
+ // Send INIT IPI - SIPI to all APs
+ //
+ SendInitSipiSipiAllExcludingSelf ((UINT32)mAcpiCpuData.StartupVector);
+
+ while (mNumberToFinish > 0) {
+ CpuPause ();
+ }
+}
+
+/**
+ The function is invoked after SMBASE relocation in S3 path to restors CPU status.
+
+ The function is invoked after SMBASE relocation in S3 path. It restores configuration according to
+ data saved by normal boot path for both BSP and APs.
+
+**/
+VOID
+InitializeCpu (
+ VOID
+ )
+{
+ CPU_REGISTER_TABLE *RegisterTableList;
+ UINT32 InitApicId;
+ UINTN Index;
+
+ RegisterTableList = (CPU_REGISTER_TABLE *) (UINTN) mAcpiCpuData.RegisterTable;
+ InitApicId = GetInitialApicId ();
+ for (Index = 0; Index < mAcpiCpuData.NumberOfCpus; Index++) {
+ if (RegisterTableList[Index].InitialApicId == InitApicId) {
+ SetProcessorRegister (&RegisterTableList[Index]);
+ break;
+ }
+ }
+
+ mNumberToFinish = mAcpiCpuData.NumberOfCpus - 1;
+ mExchangeInfo->ApFunction = (VOID *) (UINTN) MPRendezvousProcedure;
+
+ //
+ // Send INIT IPI - SIPI to all APs
+ //
+ SendInitSipiSipiAllExcludingSelf ((UINT32)mAcpiCpuData.StartupVector);
+
+ while (mNumberToFinish > 0) {
+ CpuPause ();
+ }
+}
+
+/**
+ Restore SMM Configuration for Haswell enhance SMM features in S3 boot path.
+**/
+VOID
+RestoreSmmConfigurationInS3 (
+ VOID
+ )
+{
+ if (mRestoreSmmConfigurationInS3) {
+ //
+ // Configure SMM Code Access Check feature if available.
+ //
+ ConfigSmmCodeAccessCheck ();
+
+ mRestoreSmmConfigurationInS3 = FALSE;
+ }
+}
+
diff --git a/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/PiSmmCpuDxeSmm/CpuService.c b/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/PiSmmCpuDxeSmm/CpuService.c
new file mode 100644
index 0000000000..1c75c1b67a
--- /dev/null
+++ b/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/PiSmmCpuDxeSmm/CpuService.c
@@ -0,0 +1,484 @@
+/** @file
+ Implementation of SMM CPU Services Protocol.
+
+ Copyright (c) 2011 - 2015, 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 "PiSmmCpuDxeSmm.h"
+
+#define CPUID_EXTENDED_TOPOLOGY 0xb
+#define CPUID_CACHE_PARAMS 0x4
+#define CPUID_EXTENDED_TOPOLOGY_LEVEL_TYPE_INVALID 0x0
+#define CPUID_EXTENDED_TOPOLOGY_LEVEL_TYPE_SMT 0x1
+#define CPUID_EXTENDED_TOPOLOGY_LEVEL_TYPE_CORE 0x2
+
+extern EFI_CPU_INTERRUPT_HANDLER mExternalVectorTable[];
+
+//
+// SMM CPU Service Protocol instance
+//
+EFI_SMM_CPU_SERVICE_PROTOCOL mSmmCpuService = {
+ SmmGetProcessorInfo,
+ SmmSwitchBsp,
+ SmmAddProcessor,
+ SmmRemoveProcessor,
+ SmmWhoAmI,
+ SmmRegisterExceptionHandler
+};
+
+/**
+ Get Package ID/Core ID/Thread ID of a processor.
+ APIC ID must be an initial APIC ID.
+ The algorithm below assumes the target system has symmetry across physical package boundaries
+ with respect to the number of logical processors per package, number of cores per package.
+
+ @param[in] ApicId APIC ID of the target logical processor.
+ @param[out] Location Returns the processor location information.
+
+**/
+VOID
+SmmGetProcessorLocation (
+ IN UINT32 ApicId,
+ OUT EFI_CPU_PHYSICAL_LOCATION *Location
+ )
+{
+ UINTN ThreadBits;
+ UINTN CoreBits;
+ UINT32 RegEax;
+ UINT32 RegEbx;
+ UINT32 RegEcx;
+ UINT32 RegEdx;
+ UINT32 MaxCpuIdIndex;
+ UINT32 SubIndex;
+ UINTN LevelType;
+ UINT32 MaxLogicProcessorsPerPackage;
+ UINT32 MaxCoresPerPackage;
+
+ ASSERT (Location != NULL);
+
+ //
+ // Check if the processor is capable of supporting more than one logical processor.
+ //
+ AsmCpuid (EFI_CPUID_VERSION_INFO, NULL, NULL, NULL, &RegEdx);
+ ASSERT ((RegEdx & BIT28) != 0);
+
+ //
+ // Assume three-level mapping of APIC ID: Package:Core:SMT.
+ //
+
+ //
+ // Get the max index of basic CPUID
+ //
+ AsmCpuid (EFI_CPUID_SIGNATURE, &MaxCpuIdIndex, NULL, NULL, NULL);
+
+ if (MaxCpuIdIndex >= CPUID_EXTENDED_TOPOLOGY) {
+ AsmCpuidEx (CPUID_EXTENDED_TOPOLOGY, 0, &RegEax, &RegEbx, NULL, NULL);
+ if ((RegEbx & 0xffff) != 0) {
+ //
+ // x2APIC ID
+ //
+
+ ThreadBits = RegEax & 0x1f;
+
+ CoreBits = 0;
+ SubIndex = 1;
+ do {
+ AsmCpuidEx (CPUID_EXTENDED_TOPOLOGY, SubIndex, &RegEax, NULL, &RegEcx, NULL);
+ LevelType = (RegEcx >> 8) & 0xff;
+ if (LevelType == CPUID_EXTENDED_TOPOLOGY_LEVEL_TYPE_CORE) {
+ CoreBits = (RegEax & 0x1f) - ThreadBits;
+ break;
+ }
+ SubIndex++;
+ } while (LevelType != CPUID_EXTENDED_TOPOLOGY_LEVEL_TYPE_INVALID);
+
+ Location->Thread = ApicId & ~((-1) << ThreadBits);
+ Location->Core = (ApicId >> ThreadBits) & ~((-1) << CoreBits);
+ Location->Package = (ApicId >> (ThreadBits+ CoreBits));
+ }
+ }
+ //
+ // xAPIC ID
+ //
+
+ AsmCpuid (EFI_CPUID_VERSION_INFO, NULL, &RegEbx, NULL, NULL);
+ MaxLogicProcessorsPerPackage = (RegEbx >> 16) & 0xff;
+ if (MaxCpuIdIndex >= CPUID_CACHE_PARAMS) {
+ AsmCpuidEx (CPUID_CACHE_PARAMS, 0, &RegEax, NULL, NULL, NULL);
+ MaxCoresPerPackage = (RegEax >> 26) + 1;
+ } else {
+ MaxCoresPerPackage = 1;
+ }
+
+ ThreadBits = (UINTN) (HighBitSet32 (MaxLogicProcessorsPerPackage / MaxCoresPerPackage - 1) + 1);
+ CoreBits = (UINTN) (HighBitSet32 (MaxCoresPerPackage - 1) + 1);
+
+ Location->Thread = ApicId & ~((-1) << ThreadBits);
+ Location->Core = (ApicId >> ThreadBits) & ~((-1) << CoreBits);
+ Location->Package = (ApicId >> (ThreadBits+ CoreBits));
+}
+
+/**
+ Gets processor information on the requested processor at the instant this call is made.
+
+ @param[in] This A pointer to the EFI_SMM_CPU_SERVICE_PROTOCOL instance.
+ @param[in] ProcessorNumber The handle number of processor.
+ @param[out] ProcessorInfoBuffer A pointer to the buffer where information for
+ the requested processor is deposited.
+
+ @retval EFI_SUCCESS Processor information was returned.
+ @retval EFI_INVALID_PARAMETER ProcessorInfoBuffer is NULL.
+ @retval EFI_INVALID_PARAMETER ProcessorNumber is invalid.
+ @retval EFI_NOT_FOUND The processor with the handle specified by
+ ProcessorNumber does not exist in the platform.
+
+**/
+EFI_STATUS
+EFIAPI
+SmmGetProcessorInfo (
+ IN CONST EFI_SMM_CPU_SERVICE_PROTOCOL *This,
+ IN UINTN ProcessorNumber,
+ OUT EFI_PROCESSOR_INFORMATION *ProcessorInfoBuffer
+ )
+{
+ //
+ // Check parameter
+ //
+ if (ProcessorNumber >= mMaxNumberOfCpus || ProcessorInfoBuffer == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (gSmmCpuPrivate->ProcessorInfo[ProcessorNumber].ProcessorId == INVALID_APIC_ID) {
+ return EFI_NOT_FOUND;
+ }
+
+ //
+ // Fill in processor information
+ //
+ CopyMem (ProcessorInfoBuffer, &gSmmCpuPrivate->ProcessorInfo[ProcessorNumber], sizeof (EFI_PROCESSOR_INFORMATION));
+ return EFI_SUCCESS;
+}
+
+/**
+ This service switches the requested AP to be the BSP since the next SMI.
+
+ @param[in] This A pointer to the EFI_SMM_CPU_SERVICE_PROTOCOL instance.
+ @param[in] ProcessorNumber The handle number of AP that is to become the new BSP.
+
+ @retval EFI_SUCCESS BSP will be switched in next SMI.
+ @retval EFI_UNSUPPORTED Switching the BSP or a processor to be hot-removed is not supported.
+ @retval EFI_NOT_FOUND The processor with the handle specified by ProcessorNumber does not exist.
+ @retval EFI_INVALID_PARAMETER ProcessorNumber is invalid.
+
+**/
+EFI_STATUS
+EFIAPI
+SmmSwitchBsp (
+ IN CONST EFI_SMM_CPU_SERVICE_PROTOCOL *This,
+ IN UINTN ProcessorNumber
+ )
+{
+ //
+ // Check parameter
+ //
+ if (ProcessorNumber >= mMaxNumberOfCpus) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (gSmmCpuPrivate->ProcessorInfo[ProcessorNumber].ProcessorId == INVALID_APIC_ID) {
+ return EFI_NOT_FOUND;
+ }
+
+ if (gSmmCpuPrivate->Operation[ProcessorNumber] != SmmCpuNone ||
+ gSmst->CurrentlyExecutingCpu == ProcessorNumber) {
+ return EFI_UNSUPPORTED;
+ }
+
+ //
+ // Setting of the BSP for next SMI is pending until all SMI handlers are finished
+ //
+ gSmmCpuPrivate->Operation[ProcessorNumber] = SmmCpuSwitchBsp;
+ return EFI_SUCCESS;
+}
+
+/**
+ Notify that a processor was hot-added.
+
+ @param[in] This A pointer to the EFI_SMM_CPU_SERVICE_PROTOCOL instance.
+ @param[in] ProcessorId Local APIC ID of the hot-added processor.
+ @param[out] ProcessorNumber The handle number of the hot-added processor.
+
+ @retval EFI_SUCCESS The hot-addition of the specified processos was succesfully notified.
+ @retval EFI_UNSUPPORTED Hot addition of processor is not supported.
+ @retval EFI_NOT_FOUND The processor with the handle specified by ProcessorNumber does not exist.
+ @retval EFI_INVALID_PARAMETER ProcessorNumber is invalid.
+ @retval EFI_ALREADY_STARTED The processor is already online in the system.
+
+**/
+EFI_STATUS
+EFIAPI
+SmmAddProcessor (
+ IN CONST EFI_SMM_CPU_SERVICE_PROTOCOL *This,
+ IN UINT64 ProcessorId,
+ OUT UINTN *ProcessorNumber
+ )
+{
+ UINTN Index;
+
+ if (!FeaturePcdGet (PcdCpuHotPlugSupport)) {
+ return EFI_UNSUPPORTED;
+ }
+
+ //
+ // Check parameter
+ //
+ if (ProcessorNumber == NULL || ProcessorId == INVALID_APIC_ID) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Check if the processor already exists
+ //
+
+ for (Index = 0; Index < mMaxNumberOfCpus; Index++) {
+ if (gSmmCpuPrivate->ProcessorInfo[Index].ProcessorId == ProcessorId) {
+ return EFI_ALREADY_STARTED;
+ }
+ }
+
+ //
+ // Check CPU hot plug data. The CPU RAS handler should have created the mapping
+ // of the APIC ID to SMBASE.
+ //
+ for (Index = 0; Index < mMaxNumberOfCpus; Index++) {
+ if (mCpuHotPlugData.ApicId[Index] == ProcessorId &&
+ gSmmCpuPrivate->ProcessorInfo[Index].ProcessorId == INVALID_APIC_ID) {
+ gSmmCpuPrivate->ProcessorInfo[Index].ProcessorId = ProcessorId;
+ gSmmCpuPrivate->ProcessorInfo[Index].StatusFlag = 0;
+ SmmGetProcessorLocation ((UINT32)ProcessorId, &gSmmCpuPrivate->ProcessorInfo[Index].Location);
+
+ *ProcessorNumber = Index;
+ gSmmCpuPrivate->Operation[Index] = SmmCpuAdd;
+ return EFI_SUCCESS;
+ }
+ }
+
+ return EFI_INVALID_PARAMETER;
+}
+
+/**
+ Notify that a processor was hot-removed.
+
+ @param[in] This A pointer to the EFI_SMM_CPU_SERVICE_PROTOCOL instance.
+ @param[in] ProcessorNumber The handle number of the hot-added processor.
+
+ @retval EFI_SUCCESS The hot-removal of the specified processos was succesfully notified.
+ @retval EFI_UNSUPPORTED Hot removal of processor is not supported.
+ @retval EFI_UNSUPPORTED Hot removal of BSP is not supported.
+ @retval EFI_UNSUPPORTED Hot removal of a processor with pending hot-plug operation is not supported.
+ @retval EFI_INVALID_PARAMETER ProcessorNumber is invalid.
+
+**/
+EFI_STATUS
+EFIAPI
+SmmRemoveProcessor (
+ IN CONST EFI_SMM_CPU_SERVICE_PROTOCOL *This,
+ IN UINTN ProcessorNumber
+ )
+{
+ if (!FeaturePcdGet (PcdCpuHotPlugSupport)) {
+ return EFI_UNSUPPORTED;
+ }
+
+ //
+ // Check parameter
+ //
+ if (ProcessorNumber >= mMaxNumberOfCpus ||
+ gSmmCpuPrivate->ProcessorInfo[ProcessorNumber].ProcessorId == INVALID_APIC_ID) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Can't remove BSP
+ //
+ if (ProcessorNumber == gSmmCpuPrivate->SmmCoreEntryContext.CurrentlyExecutingCpu) {
+ return EFI_UNSUPPORTED;
+ }
+
+ if (gSmmCpuPrivate->Operation[ProcessorNumber] != SmmCpuNone) {
+ return EFI_UNSUPPORTED;
+ }
+
+ gSmmCpuPrivate->ProcessorInfo[ProcessorNumber].ProcessorId = INVALID_APIC_ID;
+ mCpuHotPlugData.ApicId[ProcessorNumber] = INVALID_APIC_ID;
+
+ //
+ // Removal of the processor from the CPU list is pending until all SMI handlers are finished
+ //
+ gSmmCpuPrivate->Operation[ProcessorNumber] = SmmCpuRemove;
+ return EFI_SUCCESS;
+}
+
+/**
+ This return the handle number for the calling processor.
+
+ @param[in] This A pointer to the EFI_SMM_CPU_SERVICE_PROTOCOL instance.
+ @param[out] ProcessorNumber The handle number of currently executing processor.
+
+ @retval EFI_SUCCESS The current processor handle number was returned
+ in ProcessorNumber.
+ @retval EFI_INVALID_PARAMETER ProcessorNumber is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+SmmWhoAmI (
+ IN CONST EFI_SMM_CPU_SERVICE_PROTOCOL *This,
+ OUT UINTN *ProcessorNumber
+ )
+{
+ UINTN Index;
+ UINT64 ApicId;
+
+ //
+ // Check parameter
+ //
+ if (ProcessorNumber == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ ApicId = GetApicId ();
+
+ for (Index = 0; Index < mMaxNumberOfCpus; Index++) {
+ if (gSmmCpuPrivate->ProcessorInfo[Index].ProcessorId == ApicId) {
+ *ProcessorNumber = Index;
+ return EFI_SUCCESS;
+ }
+ }
+ //
+ // This should not happen
+ //
+ ASSERT (FALSE);
+ return EFI_NOT_FOUND;
+}
+
+/**
+ Update the SMM CPU list per the pending operation.
+
+ This function is called after return from SMI handlers.
+**/
+VOID
+SmmCpuUpdate (
+ VOID
+ )
+{
+ UINTN Index;
+
+ //
+ // Handle pending BSP switch operations
+ //
+ for (Index = 0; Index < mMaxNumberOfCpus; Index++) {
+ if (gSmmCpuPrivate->Operation[Index] == SmmCpuSwitchBsp) {
+ gSmmCpuPrivate->Operation[Index] = SmmCpuNone;
+ mSmmMpSyncData->SwitchBsp = TRUE;
+ mSmmMpSyncData->CandidateBsp[Index] = TRUE;
+ }
+ }
+
+ //
+ // Handle pending hot-add operations
+ //
+ for (Index = 0; Index < mMaxNumberOfCpus; Index++) {
+ if (gSmmCpuPrivate->Operation[Index] == SmmCpuAdd) {
+ gSmmCpuPrivate->Operation[Index] = SmmCpuNone;
+ mNumberOfCpus++;
+ }
+ }
+
+ //
+ // Handle pending hot-remove operations
+ //
+ for (Index = 0; Index < mMaxNumberOfCpus; Index++) {
+ if (gSmmCpuPrivate->Operation[Index] == SmmCpuRemove) {
+ gSmmCpuPrivate->Operation[Index] = SmmCpuNone;
+ mNumberOfCpus--;
+ }
+ }
+}
+
+/**
+ Register exception handler.
+
+ @param This A pointer to the SMM_CPU_SERVICE_PROTOCOL instance.
+ @param ExceptionType Defines which interrupt or exception to hook. Type EFI_EXCEPTION_TYPE and
+ the valid values for this parameter are defined in EFI_DEBUG_SUPPORT_PROTOCOL
+ of the UEFI 2.0 specification.
+ @param InterruptHandler A pointer to a function of type EFI_CPU_INTERRUPT_HANDLER
+ that is called when a processor interrupt occurs.
+ If this parameter is NULL, then the handler will be uninstalled.
+
+ @retval EFI_SUCCESS The handler for the processor interrupt was successfully installed or uninstalled.
+ @retval EFI_ALREADY_STARTED InterruptHandler is not NULL, and a handler for InterruptType was previously installed.
+ @retval EFI_INVALID_PARAMETER InterruptHandler is NULL, and a handler for InterruptType was not previously installed.
+ @retval EFI_UNSUPPORTED The interrupt specified by InterruptType is not supported.
+
+**/
+EFI_STATUS
+EFIAPI
+SmmRegisterExceptionHandler (
+ IN EFI_SMM_CPU_SERVICE_PROTOCOL *This,
+ IN EFI_EXCEPTION_TYPE ExceptionType,
+ IN EFI_CPU_INTERRUPT_HANDLER InterruptHandler
+ )
+{
+ if (ExceptionType < 0 || ExceptionType >= EXCEPTION_VECTOR_NUMBER) {
+ return EFI_UNSUPPORTED;
+ }
+
+ if (InterruptHandler == NULL && mExternalVectorTable[ExceptionType] == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (InterruptHandler != NULL && mExternalVectorTable[ExceptionType] != NULL) {
+ return EFI_ALREADY_STARTED;
+ }
+
+ mExternalVectorTable[ExceptionType] = InterruptHandler;
+ return EFI_SUCCESS;
+}
+
+/**
+ Initialize SMM CPU Services.
+ It installs EFI SMM CPU Services Protocol.
+
+ @param[in] Handle The firmware allocated handle for the EFI image.
+
+ @retval EFI_SUCCESS EFI SMM CPU Services Protocol was installed successfully.
+
+**/
+EFI_STATUS
+InitializeSmmCpuServices (
+ IN EFI_HANDLE Handle
+ )
+{
+ EFI_STATUS Status;
+
+ Status = gSmst->SmmInstallProtocolInterface (
+ &Handle,
+ &gEfiSmmCpuServiceProtocolGuid,
+ EFI_NATIVE_INTERFACE,
+ &mSmmCpuService
+ );
+ ASSERT_EFI_ERROR (Status);
+ return Status;
+}
+
diff --git a/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/PiSmmCpuDxeSmm/CpuService.h b/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/PiSmmCpuDxeSmm/CpuService.h
new file mode 100644
index 0000000000..18cc8f8be2
--- /dev/null
+++ b/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/PiSmmCpuDxeSmm/CpuService.h
@@ -0,0 +1,198 @@
+/** @file
+ Include file for SMM RAS Services protocol implementation.
+
+ Copyright (c) 2011 - 2015, 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 _CPU_SERVICE_H_
+#define _CPU_SERVICE_H_
+
+typedef enum {
+ SmmCpuNone,
+ SmmCpuAdd,
+ SmmCpuRemove,
+ SmmCpuSwitchBsp
+} SMM_CPU_OPERATION;
+
+//
+// SMM CPU Service Protocol function prototypes.
+//
+
+/**
+ Gets processor information on the requested processor at the instant this call is made.
+
+ @param[in] This A pointer to the EFI_SMM_CPU_SERVICE_PROTOCOL instance.
+ @param[in] ProcessorNumber The handle number of processor.
+ @param[out] ProcessorInfoBuffer A pointer to the buffer where information for
+ the requested processor is deposited.
+
+ @retval EFI_SUCCESS Processor information was returned.
+ @retval EFI_INVALID_PARAMETER ProcessorInfoBuffer is NULL.
+ @retval EFI_INVALID_PARAMETER ProcessorNumber is invalid.
+ @retval EFI_NOT_FOUND The processor with the handle specified by
+ ProcessorNumber does not exist in the platform.
+
+**/
+EFI_STATUS
+EFIAPI
+SmmGetProcessorInfo (
+ IN CONST EFI_SMM_CPU_SERVICE_PROTOCOL *This,
+ IN UINTN ProcessorNumber,
+ OUT EFI_PROCESSOR_INFORMATION *ProcessorInfoBuffer
+ );
+
+/**
+ This service switches the requested AP to be the BSP since the next SMI.
+
+ @param[in] This A pointer to the EFI_SMM_CPU_SERVICE_PROTOCOL instance.
+ @param[in] ProcessorNumber The handle number of AP that is to become the new BSP.
+
+ @retval EFI_SUCCESS BSP will be switched in next SMI.
+ @retval EFI_UNSUPPORTED Switching the BSP or a processor to be hot-removed is not supported.
+ @retval EFI_NOT_FOUND The processor with the handle specified by ProcessorNumber does not exist.
+ @retval EFI_INVALID_PARAMETER ProcessorNumber is invalid.
+
+**/
+EFI_STATUS
+EFIAPI
+SmmSwitchBsp (
+ IN CONST EFI_SMM_CPU_SERVICE_PROTOCOL *This,
+ IN UINTN ProcessorNumber
+ );
+
+/**
+ Notify that a processor was hot-added.
+
+ @param[in] This A pointer to the EFI_SMM_CPU_SERVICE_PROTOCOL instance.
+ @param[in] ProcessorId Local APIC ID of the hot-added processor.
+ @param[out] ProcessorNumber The handle number of the hot-added processor.
+
+ @retval EFI_SUCCESS The hot-addition of the specified processos was succesfully notified.
+ @retval EFI_UNSUPPORTED Hot addition of processor is not supported.
+ @retval EFI_NOT_FOUND The processor with the handle specified by ProcessorNumber does not exist.
+ @retval EFI_INVALID_PARAMETER ProcessorNumber is invalid.
+ @retval EFI_ALREADY_STARTED The processor is already online in the system.
+
+**/
+EFI_STATUS
+EFIAPI
+SmmAddProcessor (
+ IN CONST EFI_SMM_CPU_SERVICE_PROTOCOL *This,
+ IN UINT64 ProcessorId,
+ OUT UINTN *ProcessorNumber
+ );
+
+/**
+ Notify that a processor was hot-removed.
+
+ @param[in] This A pointer to the EFI_SMM_CPU_SERVICE_PROTOCOL instance.
+ @param[in] ProcessorNumber The handle number of the hot-added processor.
+
+ @retval EFI_SUCCESS The hot-removal of the specified processos was succesfully notified.
+ @retval EFI_UNSUPPORTED Hot removal of processor is not supported.
+ @retval EFI_UNSUPPORTED Hot removal of BSP is not supported.
+ @retval EFI_UNSUPPORTED Hot removal of a processor with pending hot-plug operation is not supported.
+ @retval EFI_INVALID_PARAMETER ProcessorNumber is invalid.
+
+**/
+EFI_STATUS
+EFIAPI
+SmmRemoveProcessor (
+ IN CONST EFI_SMM_CPU_SERVICE_PROTOCOL *This,
+ IN UINTN ProcessorNumber
+ );
+
+/**
+ This return the handle number for the calling processor.
+
+ @param[in] This A pointer to the EFI_SMM_CPU_SERVICE_PROTOCOL instance.
+ @param[out] ProcessorNumber The handle number of currently executing processor.
+
+ @retval EFI_SUCCESS The current processor handle number was returned
+ in ProcessorNumber.
+ @retval EFI_INVALID_PARAMETER ProcessorNumber is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+SmmWhoAmI (
+ IN CONST EFI_SMM_CPU_SERVICE_PROTOCOL *This,
+ OUT UINTN *ProcessorNumber
+ );
+
+/**
+ Register exception handler.
+
+ @param This A pointer to the SMM_CPU_SERVICE_PROTOCOL instance.
+ @param ExceptionType Defines which interrupt or exception to hook. Type EFI_EXCEPTION_TYPE and
+ the valid values for this parameter are defined in EFI_DEBUG_SUPPORT_PROTOCOL
+ of the UEFI 2.0 specification.
+ @param InterruptHandler A pointer to a function of type EFI_CPU_INTERRUPT_HANDLER
+ that is called when a processor interrupt occurs.
+ If this parameter is NULL, then the handler will be uninstalled.
+
+ @retval EFI_SUCCESS The handler for the processor interrupt was successfully installed or uninstalled.
+ @retval EFI_ALREADY_STARTED InterruptHandler is not NULL, and a handler for InterruptType was previously installed.
+ @retval EFI_INVALID_PARAMETER InterruptHandler is NULL, and a handler for InterruptType was not previously installed.
+ @retval EFI_UNSUPPORTED The interrupt specified by InterruptType is not supported.
+
+**/
+EFI_STATUS
+EFIAPI
+SmmRegisterExceptionHandler (
+ IN EFI_SMM_CPU_SERVICE_PROTOCOL *This,
+ IN EFI_EXCEPTION_TYPE ExceptionType,
+ IN EFI_CPU_INTERRUPT_HANDLER InterruptHandler
+ );
+
+//
+// Internal function prototypes
+//
+
+/**
+ Initializes the pointer to the external exception vector table.
+
+ @param VectorTable Address of the external exception vector table.
+
+**/
+VOID
+EFIAPI
+InitializeSmmExternalVectorTablePtr (
+ EFI_CPU_INTERRUPT_HANDLER *VectorTable
+ );
+
+/**
+ Update the SMM CPU list per the pending operation.
+
+ This function is called after return from SMI handlers.
+**/
+VOID
+SmmCpuUpdate (
+ VOID
+ );
+
+/**
+ Initialize SMM CPU Services.
+ It installs EFI SMM CPU Services Protocol.
+
+ @param ImageHandle The firmware allocated handle for the EFI image.
+
+ @retval EFI_SUCCESS EFI SMM CPU Services Protocol was installed successfully.
+
+**/
+EFI_STATUS
+InitializeSmmCpuServices (
+ IN EFI_HANDLE Handle
+ );
+
+#endif
+
diff --git a/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/PiSmmCpuDxeSmm/Ia32/MpFuncs.S b/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/PiSmmCpuDxeSmm/Ia32/MpFuncs.S
new file mode 100644
index 0000000000..7d29b44385
--- /dev/null
+++ b/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/PiSmmCpuDxeSmm/Ia32/MpFuncs.S
@@ -0,0 +1,159 @@
+## @file
+# This is the assembly code for Multi-processor S3 support
+#
+# Copyright (c) 2006 - 2015, 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
+#
+##
+
+.equ VacantFlag, 0x0
+.equ NotVacantFlag, 0xff
+
+.equ LockLocation, RendezvousFunnelProcEnd - RendezvousFunnelProcStart
+.equ StackStart, RendezvousFunnelProcEnd - RendezvousFunnelProcStart + 0x04
+.equ StackSize, RendezvousFunnelProcEnd - RendezvousFunnelProcStart + 0x08
+.equ RendezvousProc, RendezvousFunnelProcEnd - RendezvousFunnelProcStart + 0x0C
+.equ GdtrProfile, RendezvousFunnelProcEnd - RendezvousFunnelProcStart + 0x10
+.equ IdtrProfile, RendezvousFunnelProcEnd - RendezvousFunnelProcStart + 0x16
+.equ BufferStart, RendezvousFunnelProcEnd - RendezvousFunnelProcStart + 0x1C
+
+#-------------------------------------------------------------------------------------
+#RendezvousFunnelProc procedure follows. All APs execute their procedure. This
+#procedure serializes all the AP processors through an Init sequence. It must be
+#noted that APs arrive here very raw...ie: real mode, no stack.
+#ALSO THIS PROCEDURE IS EXECUTED BY APs ONLY ON 16 BIT MODE. HENCE THIS PROC
+#IS IN MACHINE CODE.
+#-------------------------------------------------------------------------------------
+#RendezvousFunnelProc (&WakeUpBuffer,MemAddress);
+
+ASM_GLOBAL ASM_PFX(RendezvousFunnelProc)
+ASM_PFX(RendezvousFunnelProc):
+RendezvousFunnelProcStart:
+
+# At this point CS = 0x(vv00) and ip= 0x0.
+
+ .byte 0x8c,0xc8 # mov ax, cs
+ .byte 0x8e,0xd8 # mov ds, ax
+ .byte 0x8e,0xc0 # mov es, ax
+ .byte 0x8e,0xd0 # mov ss, ax
+ .byte 0x33,0xc0 # xor ax, ax
+ .byte 0x8e,0xe0 # mov fs, ax
+ .byte 0x8e,0xe8 # mov gs, ax
+
+flat32Start:
+
+ .byte 0xBE
+ .word BufferStart
+ .byte 0x66,0x8B,0x14 # mov edx,dword ptr [si] ; EDX is keeping the start address of wakeup buffer
+
+ .byte 0xBE
+ .word GdtrProfile
+ .byte 0x66 # db 66h
+ .byte 0x2E,0xF,0x1,0x14 # lgdt fword ptr cs:[si]
+
+ .byte 0xBE
+ .word IdtrProfile
+ .byte 0x66 # db 66h
+ .byte 0x2E,0xF,0x1,0x1C # lidt fword ptr cs:[si]
+
+ .byte 0x33,0xC0 # xor ax, ax
+ .byte 0x8E,0xD8 # mov ds, ax
+
+ .byte 0xF,0x20,0xC0 # mov eax, cr0 ; Get control register 0
+ .byte 0x66,0x83,0xC8,0x1 # or eax, 000000001h ; Set PE bit (bit #0)
+ .byte 0xF,0x22,0xC0 # mov cr0, eax
+
+FLAT32_JUMP:
+
+ .byte 0x66,0x67,0xEA # far jump
+ .long 0x0 # 32-bit offset
+ .word 0x20 # 16-bit selector
+
+PMODE_ENTRY: # protected mode entry point
+
+ movw $0x8,%ax
+ .byte 0x66
+ movw %ax,%ds
+ .byte 0x66
+ movw %ax,%es
+ .byte 0x66
+ movw %ax,%fs
+ .byte 0x66
+ movw %ax,%gs
+ .byte 0x66
+ movw %ax,%ss # Flat mode setup.
+
+ movl %edx,%esi
+
+ movl %esi,%edi
+ addl $LockLocation, %edi
+ movb $NotVacantFlag, %al
+TestLock:
+ xchgb (%edi), %al
+ cmpb $NotVacantFlag, %al
+ jz TestLock
+
+ProgramStack:
+
+ movl %esi,%edi
+ addl $StackSize, %edi
+ movl (%edi),%eax
+ movl %esi,%edi
+ addl $StackStart, %edi
+ addl (%edi),%eax
+ movl %eax,%esp
+ movl %eax,(%edi)
+
+Releaselock:
+
+ movb $VacantFlag, %al
+ movl %esi,%edi
+ addl $LockLocation, %edi
+ xchgb (%edi), %al
+
+ #
+ # Call assembly function to initialize FPU.
+ #
+ lea ASM_PFX(InitializeFloatingPointUnits), %ebx
+ call *%ebx
+ #
+ # Call C Function
+ #
+ movl %esi,%edi
+ addl $RendezvousProc, %edi
+ movl (%edi),%eax
+
+ testl %eax,%eax
+ jz GoToSleep
+ call *%eax # Call C function
+
+GoToSleep:
+ cli
+ hlt
+ jmp GoToSleep
+
+RendezvousFunnelProcEnd:
+#-------------------------------------------------------------------------------------
+# AsmGetAddressMap (&AddressMap);
+#-------------------------------------------------------------------------------------
+ASM_GLOBAL ASM_PFX(AsmGetAddressMap)
+ASM_PFX(AsmGetAddressMap):
+
+ pushal
+ movl %esp,%ebp
+
+ movl 0x24(%ebp), %ebx
+ movl $RendezvousFunnelProcStart, (%ebx)
+ movl $(PMODE_ENTRY - RendezvousFunnelProcStart), 0x4(%ebx)
+ movl $(FLAT32_JUMP - RendezvousFunnelProcStart), 0x8(%ebx)
+ movl $(RendezvousFunnelProcEnd - RendezvousFunnelProcStart), 0x0c(%ebx)
+
+ popal
+ ret
diff --git a/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/PiSmmCpuDxeSmm/Ia32/MpFuncs.asm b/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/PiSmmCpuDxeSmm/Ia32/MpFuncs.asm
new file mode 100644
index 0000000000..9cfb54e4fa
--- /dev/null
+++ b/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/PiSmmCpuDxeSmm/Ia32/MpFuncs.asm
@@ -0,0 +1,163 @@
+;; @file
+; This is the assembly code for Multi-processor S3 support
+;
+; Copyright (c) 2006 - 2015, 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.
+;
+;;
+
+.686p
+.model flat,C
+.code
+
+EXTERN InitializeFloatingPointUnits:PROC
+
+VacantFlag Equ 00h
+NotVacantFlag Equ 0ffh
+
+LockLocation equ RendezvousFunnelProcEnd - RendezvousFunnelProcStart
+StackStart equ LockLocation + 4h
+StackSize equ LockLocation + 8h
+RendezvousProc equ LockLocation + 0Ch
+GdtrProfile equ LockLocation + 10h
+IdtrProfile equ LockLocation + 16h
+BufferStart equ LockLocation + 1Ch
+
+;-------------------------------------------------------------------------------------
+;RendezvousFunnelProc procedure follows. All APs execute their procedure. This
+;procedure serializes all the AP processors through an Init sequence. It must be
+;noted that APs arrive here very raw...ie: real mode, no stack.
+;ALSO THIS PROCEDURE IS EXECUTED BY APs ONLY ON 16 BIT MODE. HENCE THIS PROC
+;IS IN MACHINE CODE.
+;-------------------------------------------------------------------------------------
+;RendezvousFunnelProc (&WakeUpBuffer,MemAddress);
+
+RendezvousFunnelProc PROC near C PUBLIC
+RendezvousFunnelProcStart::
+
+; At this point CS = 0x(vv00) and ip= 0x0.
+
+ db 8ch, 0c8h ; mov ax, cs
+ db 8eh, 0d8h ; mov ds, ax
+ db 8eh, 0c0h ; mov es, ax
+ db 8eh, 0d0h ; mov ss, ax
+ db 33h, 0c0h ; xor ax, ax
+ db 8eh, 0e0h ; mov fs, ax
+ db 8eh, 0e8h ; mov gs, ax
+
+flat32Start::
+
+ db 0BEh
+ dw BufferStart ; mov si, BufferStart
+ db 66h, 8Bh, 14h ; mov edx,dword ptr [si] ; EDX is keeping the start address of wakeup buffer
+
+ db 0BEh
+ dw GdtrProfile ; mov si, GdtrProfile
+ db 66h ; db 66h
+ db 2Eh, 0Fh, 01h, 14h ; lgdt fword ptr cs:[si]
+
+ db 0BEh
+ dw IdtrProfile ; 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, 01h ; or eax, 000000001h ; Set PE bit (bit #0)
+ db 0Fh, 22h, 0C0h ; mov cr0, eax
+
+FLAT32_JUMP::
+
+ db 66h, 67h, 0EAh ; far jump
+ dd 0h ; 32-bit offset
+ dw 20h ; 16-bit selector
+
+PMODE_ENTRY:: ; protected mode entry point
+
+ mov ax, 8h
+ mov ds, ax
+ mov es, ax
+ mov fs, ax
+ mov gs, ax
+ mov ss, ax ; Flat mode setup.
+
+ mov esi, edx
+
+ mov edi, esi
+ add edi, LockLocation
+ mov al, NotVacantFlag
+TestLock::
+ xchg byte ptr [edi], al
+ cmp al, NotVacantFlag
+ jz TestLock
+
+ProgramStack::
+
+ mov edi, esi
+ add edi, StackSize
+ mov eax, dword ptr [edi]
+ mov edi, esi
+ add edi, StackStart
+ add eax, dword ptr [edi]
+ mov esp, eax
+ mov dword ptr [edi], eax
+
+Releaselock::
+
+ mov al, VacantFlag
+ mov edi, esi
+ add edi, LockLocation
+ xchg byte ptr [edi], al
+
+ ;
+ ; Call assembly function to initialize FPU.
+ ;
+ mov ebx, InitializeFloatingPointUnits
+ call ebx
+ ;
+ ; Call C Function
+ ;
+ mov edi, esi
+ add edi, RendezvousProc
+ mov eax, dword ptr [edi]
+
+ test eax, eax
+ jz GoToSleep
+ call eax ; Call C function
+
+GoToSleep::
+ cli
+ hlt
+ jmp $-2
+
+RendezvousFunnelProc ENDP
+RendezvousFunnelProcEnd::
+;-------------------------------------------------------------------------------------
+; AsmGetAddressMap (&AddressMap);
+;-------------------------------------------------------------------------------------
+AsmGetAddressMap PROC near C PUBLIC
+
+ pushad
+ mov ebp,esp
+
+ mov ebx, dword ptr [ebp+24h]
+ mov dword ptr [ebx], RendezvousFunnelProcStart
+ mov dword ptr [ebx+4h], PMODE_ENTRY - RendezvousFunnelProcStart
+ mov dword ptr [ebx+8h], FLAT32_JUMP - RendezvousFunnelProcStart
+ mov dword ptr [ebx+0ch], RendezvousFunnelProcEnd - RendezvousFunnelProcStart
+
+ popad
+ ret
+
+AsmGetAddressMap ENDP
+
+END
diff --git a/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/PiSmmCpuDxeSmm/Ia32/PageTbl.c b/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/PiSmmCpuDxeSmm/Ia32/PageTbl.c
new file mode 100644
index 0000000000..264b4533d1
--- /dev/null
+++ b/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/PiSmmCpuDxeSmm/Ia32/PageTbl.c
@@ -0,0 +1,96 @@
+/** @file
+ Page table manipulation functions for IA-32 processors
+
+ Copyright (c) 2009 - 2015, 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 "PiSmmCpuDxeSmm.h"
+
+SPIN_LOCK mPFLock;
+
+/**
+ Create PageTable for SMM use.
+
+ @return PageTable Address
+
+**/
+UINT32
+SmmInitPageTable (
+ VOID
+ )
+{
+ //
+ // Initialize spin lock
+ //
+ InitializeSpinLock (&mPFLock);
+
+ //
+ // Register Smm Page Fault Handler
+ //
+ SmmRegisterExceptionHandler (&mSmmCpuService, EXCEPT_IA32_PAGE_FAULT, SmiPFHandler);
+
+ return Gen4GPageTable (0);
+}
+
+/**
+ Page Fault handler for SMM use.
+
+**/
+VOID
+SmiDefaultPFHandler (
+ VOID
+ )
+{
+ CpuDeadLoop ();
+}
+
+/**
+ ThePage Fault handler wrapper for SMM use.
+
+ @param[in] InterruptType Defines the type of interrupt or exception that
+ occurred on the processor.This parameter is processor architecture specific.
+ @param[in] SystemContext A pointer to the processor context when
+ the interrupt occurred on the processor.
+**/
+VOID
+EFIAPI
+SmiPFHandler (
+ IN EFI_EXCEPTION_TYPE InterruptType,
+ IN EFI_SYSTEM_CONTEXT SystemContext
+ )
+{
+ UINTN PFAddress;
+
+ ASSERT (InterruptType == EXCEPT_IA32_PAGE_FAULT);
+
+ AcquireSpinLock (&mPFLock);
+
+ PFAddress = AsmReadCr2 ();
+
+ if ((FeaturePcdGet (PcdCpuSmmStackGuard)) &&
+ (PFAddress >= mCpuHotPlugData.SmrrBase) &&
+ (PFAddress < (mCpuHotPlugData.SmrrBase + mCpuHotPlugData.SmrrSize))) {
+ DEBUG ((EFI_D_ERROR, "SMM stack overflow!\n"));
+ CpuDeadLoop ();
+ }
+
+ if (FeaturePcdGet (PcdCpuSmmProfileEnable)) {
+ SmmProfilePFHandler (
+ SystemContext.SystemContextIa32->Eip,
+ SystemContext.SystemContextIa32->ExceptionData
+ );
+ } else {
+ SmiDefaultPFHandler ();
+ }
+
+ ReleaseSpinLock (&mPFLock);
+}
diff --git a/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/PiSmmCpuDxeSmm/Ia32/Semaphore.c b/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/PiSmmCpuDxeSmm/Ia32/Semaphore.c
new file mode 100644
index 0000000000..30e56083f5
--- /dev/null
+++ b/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/PiSmmCpuDxeSmm/Ia32/Semaphore.c
@@ -0,0 +1,62 @@
+/** @file
+ Semaphore mechanism to indicate to the BSP that an AP has exited SMM
+ after SMBASE relocation.
+
+ Copyright (c) 2009 - 2015, 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 "PiSmmCpuDxeSmm.h"
+
+UINTN mSmmRelocationOriginalAddress;
+BOOLEAN *mRebasedFlag;
+
+/**
+ Hook return address of SMM Save State so that semaphore code
+ can be executed immediately after AP exits SMM to indicate to
+ the BSP that an AP has exited SMM after SMBASE relocation.
+
+ @param CpuIndex The processor index.
+**/
+VOID
+SemaphoreHook (
+ IN UINTN CpuIndex
+ )
+{
+ SOCKET_LGA_775_SMM_CPU_STATE *CpuState;
+
+ mRebasedFlag = (BOOLEAN *) &mRebased[CpuIndex];
+
+ {
+ CpuState = (SOCKET_LGA_775_SMM_CPU_STATE *)(UINTN)(SMM_DEFAULT_SMBASE + SMM_CPU_STATE_OFFSET);
+
+ //
+ // The offset of EIP/RIP is different depending on the SMMRevId
+ //
+ if (CpuState->x86.SMMRevId < SOCKET_LGA_775_SMM_MIN_REV_ID_x64) {
+ mSmmRelocationOriginalAddress = (UINTN) CpuState->x86._EIP;
+ CpuState->x86._EIP = (UINT32) (UINTN) &SmmRelocationSemaphoreComplete;
+ } else {
+ mSmmRelocationOriginalAddress = (UINTN) CpuState->x64._RIP;
+ CpuState->x64._RIP = (UINT64) (UINTN) &SmmRelocationSemaphoreComplete;
+ }
+
+ if (CpuState->x86.AutoHALTRestart & BIT0) {
+ //
+ // Clear the auto HALT restart flag so the RSM instruction returns
+ // program control to the instruction following the HLT instruction,
+ // actually returns to SmmRelocationSemaphoreComplete
+ //
+ CpuState->x86.AutoHALTRestart &= ~BIT0;
+ }
+ }
+}
+
diff --git a/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/PiSmmCpuDxeSmm/Ia32/SmiEntry.S b/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/PiSmmCpuDxeSmm/Ia32/SmiEntry.S
new file mode 100644
index 0000000000..f2f81a1991
--- /dev/null
+++ b/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/PiSmmCpuDxeSmm/Ia32/SmiEntry.S
@@ -0,0 +1,153 @@
+## @file
+# Code template of the SMI handler for a particular processor
+#
+# Copyright (c) 2009 - 2015, 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
+#
+##
+
+
+ASM_GLOBAL ASM_PFX(gcSmiHandlerTemplate)
+ASM_GLOBAL ASM_PFX(gcSmiHandlerSize)
+ASM_GLOBAL ASM_PFX(gSmiCr3)
+ASM_GLOBAL ASM_PFX(gcSmiHandlerOffset)
+ASM_GLOBAL ASM_PFX(gSmiStack)
+ASM_GLOBAL ASM_PFX(gSmbase)
+ASM_GLOBAL ASM_PFX(FeaturePcdGet (PcdCpuSmmDebug))
+ASM_GLOBAL ASM_PFX(FeaturePcdGet (PcdCpuSmmStackGuard))
+
+.equ DSC_OFFSET, 0xfb00
+.equ DSC_GDTPTR, 0x30
+.equ DSC_GDTSIZ, 0x38
+.equ DSC_CS, 14
+.equ DSC_DS, 16
+.equ DSC_SS, 18
+.equ DSC_OTHERSEG, 20
+
+.equ MSR_DR6, 0x0c05
+.equ MSR_DR7, 0x0c06
+
+.equ TSS_SEGMENT, 0x40
+
+ .data
+
+ ASM_PFX(gcSmiHandlerOffset): .word _SmiHandler - _SmiEntryPoint + 0x8000
+
+ .text
+
+ASM_PFX(gcSmiHandlerTemplate):
+
+_SmiEntryPoint:
+ .byte 0xbb # mov bx, imm16
+ .word _GdtDesc - _SmiEntryPoint + 0x8000
+ .byte 0x2e,0xa1 # mov ax, cs:[offset16]
+ .word DSC_OFFSET + DSC_GDTSIZ
+ decl %eax
+ movl %eax, %cs:(%edi) # mov cs:[bx], ax
+ .byte 0x66,0x2e,0xa1 # mov eax, cs:[offset16]
+ .word DSC_OFFSET + DSC_GDTPTR
+ movw %ax, %cs:2(%edi)
+ movw %ax, %bp # ebp = GDT base
+ .byte 0x66
+ lgdt %cs:(%edi)
+ .byte 0x66,0xb8 # mov eax, imm32
+ASM_PFX(gSmiCr3): .space 4
+ movl %eax, %cr3
+ .byte 0x66
+ movl $0x668,%eax # as cr4.PGE is not set here, refresh cr3
+ movl %eax, %cr4 # in PreModifyMtrrs() to flush TLB.
+ .byte 0x2e,0xa1 # mov ax, cs:[offset16]
+ .word DSC_OFFSET + DSC_CS
+ movl %eax, %cs:-2(%edi)
+ .byte 0x66, 0xbf # mov edi, SMBASE
+ASM_PFX(gSmbase): .space 4
+ .byte 0x67
+ lea ((Start32bit - _SmiEntryPoint) + 0x8000)(%edi), %ax
+ movw %ax, %cs:-6(%edi)
+ movl %cr0, %ebx
+ .byte 0x66
+ andl $0x9ffafff3, %ebx
+ .byte 0x66
+ orl $0x80000023, %ebx
+ movl %ebx, %cr0
+ .byte 0x66,0xea
+ .space 4
+ .space 2
+_GdtDesc: .space 4
+ .space 2
+Start32bit:
+ leal DSC_OFFSET(%edi),%ebx
+ movw DSC_DS(%ebx),%ax
+ movl %eax,%ds
+ movw DSC_OTHERSEG(%ebx),%ax
+ movl %eax,%es
+ movl %eax,%fs
+ movl %eax,%gs
+ movw DSC_SS(%ebx),%ax
+ movl %eax,%ss
+
+ cmpb $0, ASM_PFX(FeaturePcdGet (PcdCpuSmmStackGuard))
+ jz L5
+
+# Load TSS
+ movb $0x89, (TSS_SEGMENT + 5)(%ebp) # clear busy flag
+
+ movl $TSS_SEGMENT, %eax
+ ltrw %ax
+L5:
+
+# jmp _SmiHandler # instruction is not needed
+
+_SmiHandler:
+ .byte 0xbc # mov esp, imm32
+ASM_PFX(gSmiStack): .space 4
+ cmpb $0, ASM_PFX(FeaturePcdGet (PcdCpuSmmDebug))
+ jz L3
+ jz L6
+
+L6:
+ call L1
+L1:
+ popl %ebp
+ movl $0x80000001, %eax
+ cpuid
+ btl $29, %edx # check cpuid to identify X64 or IA32
+ leal (0x7fc8 - (L1 - _SmiEntryPoint))(%ebp), %edi
+ leal 4(%edi), %esi
+ jnc L2
+ addl $4, %esi
+L2:
+ movl (%esi), %ecx
+ movl (%edi), %edx
+L7:
+ movl %ecx, %dr6
+ movl %edx, %dr7 # restore DR6 & DR7 before running C code
+L3:
+
+ pushl (%esp)
+
+ movl $ASM_PFX(SmiRendezvous), %eax
+ call *%eax
+ popl %ecx
+
+
+ cmpb $0, ASM_PFX(FeaturePcdGet (PcdCpuSmmDebug))
+ jz L4
+
+ movl %dr6, %ecx
+ movl %dr7, %edx
+ movl %ecx, (%esi)
+ movl %edx, (%edi)
+L4:
+
+ rsm
+
+ASM_PFX(gcSmiHandlerSize): .word . - _SmiEntryPoint
+
diff --git a/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/PiSmmCpuDxeSmm/Ia32/SmiEntry.asm b/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/PiSmmCpuDxeSmm/Ia32/SmiEntry.asm
new file mode 100644
index 0000000000..3bd34376f8
--- /dev/null
+++ b/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/PiSmmCpuDxeSmm/Ia32/SmiEntry.asm
@@ -0,0 +1,156 @@
+;; @file
+; Code template of the SMI handler for a particular processor
+;
+; Copyright (c) 2009 - 2015, 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.
+;
+;;
+
+ .686p
+ .model flat,C
+ .xmm
+
+DSC_OFFSET EQU 0fb00h
+DSC_GDTPTR EQU 30h
+DSC_GDTSIZ EQU 38h
+DSC_CS EQU 14
+DSC_DS EQU 16
+DSC_SS EQU 18
+DSC_OTHERSEG EQU 20
+MSR_DR6 EQU 0c05h
+MSR_DR7 EQU 0c06h
+
+TSS_SEGMENT EQU 40h
+
+SmiRendezvous PROTO C
+
+EXTERNDEF gcSmiHandlerTemplate:BYTE
+EXTERNDEF gcSmiHandlerSize:WORD
+EXTERNDEF gSmiCr3:DWORD
+EXTERNDEF gcSmiHandlerOffset:WORD
+EXTERNDEF gSmiStack:DWORD
+EXTERNDEF gSmbase:DWORD
+EXTERNDEF FeaturePcdGet (PcdCpuSmmDebug):BYTE
+EXTERNDEF FeaturePcdGet (PcdCpuSmmStackGuard):BYTE
+
+ .const
+
+gcSmiHandlerOffset DW _SmiHandler - _SmiEntryPoint + 8000h
+
+ .code
+
+gcSmiHandlerTemplate LABEL BYTE
+
+_SmiEntryPoint PROC
+ DB 0bbh ; mov bx, imm16
+ DW offset _GdtDesc - _SmiEntryPoint + 8000h
+ DB 2eh, 0a1h ; mov ax, cs:[offset16]
+ DW DSC_OFFSET + DSC_GDTSIZ
+ dec eax
+ mov cs:[edi], eax ; mov cs:[bx], ax
+ DB 66h, 2eh, 0a1h ; mov eax, cs:[offset16]
+ DW DSC_OFFSET + DSC_GDTPTR
+ mov cs:[edi + 2], ax ; mov cs:[bx + 2], eax
+ mov bp, ax ; ebp = GDT base
+ DB 66h
+ lgdt fword ptr cs:[edi] ; lgdt fword ptr cs:[bx]
+ DB 66h, 0b8h ; mov eax, imm32
+gSmiCr3 DD ?
+ mov cr3, eax
+ DB 66h
+ mov eax, 668h ; as cr4.PGE is not set here, refresh cr3
+ mov cr4, eax ; in PreModifyMtrrs() to flush TLB.
+ DB 2eh, 0a1h ; mov ax, cs:[offset16]
+ DW DSC_OFFSET + DSC_CS
+ mov cs:[edi - 2], eax ; mov cs:[bx - 2], ax
+ DB 66h, 0bfh ; mov edi, SMBASE
+gSmbase DD ?
+ DB 67h
+ lea ax, [edi + (@32bit - _SmiEntryPoint) + 8000h]
+ mov cs:[edi - 6], ax ; mov cs:[bx - 6], eax
+ mov ebx, cr0
+ DB 66h
+ and ebx, 9ffafff3h
+ DB 66h
+ or ebx, 80000023h
+ mov cr0, ebx
+ DB 66h, 0eah
+ DD ?
+ DW ?
+_GdtDesc FWORD ?
+@32bit:
+ lea ebx, [edi + DSC_OFFSET]
+ mov ax, [ebx + DSC_DS]
+ mov ds, eax
+ mov ax, [ebx + DSC_OTHERSEG]
+ mov es, eax
+ mov fs, eax
+ mov gs, eax
+ mov ax, [ebx + DSC_SS]
+ mov ss, eax
+
+ cmp FeaturePcdGet (PcdCpuSmmStackGuard), 0
+ jz @F
+
+; Load TSS
+ mov byte ptr [ebp + TSS_SEGMENT + 5], 89h ; clear busy flag
+
+ mov eax, TSS_SEGMENT
+ ltr ax
+@@:
+; jmp _SmiHandler ; instruction is not needed
+_SmiEntryPoint ENDP
+
+_SmiHandler PROC
+ DB 0bch ; mov esp, imm32
+gSmiStack DD ?
+ cmp FeaturePcdGet (PcdCpuSmmDebug), 0
+ jz @3
+ jz @F
+
+@@:
+ call @1
+@1:
+ pop ebp
+ mov eax, 80000001h
+ cpuid
+ bt edx, 29 ; check cpuid to identify X64 or IA32
+ lea edi, [ebp - (@1 - _SmiEntryPoint) + 7fc8h]
+ lea esi, [edi + 4]
+ jnc @2
+ add esi, 4
+@2:
+ mov ecx, [esi]
+ mov edx, [edi]
+@5:
+ mov dr6, ecx
+ mov dr7, edx ; restore DR6 & DR7 before running C code
+@3:
+ mov ecx, [esp] ; CPU Index
+
+ push ecx
+ mov eax, SmiRendezvous
+ call eax
+ pop ecx
+
+ cmp FeaturePcdGet (PcdCpuSmmDebug), 0
+ jz @4
+
+ mov ecx, dr6
+ mov edx, dr7
+ mov [esi], ecx
+ mov [edi], edx
+@4:
+ rsm
+_SmiHandler ENDP
+
+gcSmiHandlerSize DW $ - _SmiEntryPoint
+
+ END
diff --git a/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/PiSmmCpuDxeSmm/Ia32/SmiException.S b/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/PiSmmCpuDxeSmm/Ia32/SmiException.S
new file mode 100644
index 0000000000..4650437d71
--- /dev/null
+++ b/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/PiSmmCpuDxeSmm/Ia32/SmiException.S
@@ -0,0 +1,1172 @@
+## @file
+# Exception handlers used in SM mode
+#
+# Copyright (c) 2009 - 2015, 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
+#
+##
+
+
+ASM_GLOBAL ASM_PFX(gSmiMtrrs)
+ASM_GLOBAL ASM_PFX(gcSmiIdtr)
+ASM_GLOBAL ASM_PFX(gcSmiGdtr)
+ASM_GLOBAL ASM_PFX(gcPsd)
+ASM_GLOBAL ASM_PFX(FeaturePcdGet (PcdCpuSmmStackGuard))
+ASM_GLOBAL ASM_PFX(gSavedPageFaultIdtEntry)
+ASM_GLOBAL ASM_PFX(gSavedDebugExceptionIdtEntry)
+ASM_GLOBAL ASM_PFX(FeaturePcdGet (PcdCpuSmmProfileEnable))
+ASM_GLOBAL ASM_PFX(InitializeSmmExternalVectorTablePtr)
+
+ .data
+
+NullSeg: .quad 0
+ .quad 0 # reserved for future use
+CodeSeg32:
+ .word -1 # LimitLow
+ .word 0 # BaseLow
+ .byte 0 # BaseMid
+ .byte 0x9b
+ .byte 0xcf # LimitHigh
+ .byte 0 # BaseHigh
+DataSeg32:
+ .word -1 # LimitLow
+ .word 0 # BaseLow
+ .byte 0 # BaseMid
+ .byte 0x93
+ .byte 0xcf # LimitHigh
+ .byte 0 # BaseHigh
+ .quad 0 # reserved for future use
+CodeSeg16:
+ .word -1
+ .word 0
+ .byte 0
+ .byte 0x9b
+ .byte 0x8f
+ .byte 0
+DataSeg16:
+ .word -1
+ .word 0
+ .byte 0
+ .byte 0x93
+ .byte 0x8f
+ .byte 0
+CodeSeg64:
+ .word -1 # LimitLow
+ .word 0 # BaseLow
+ .byte 0 # BaseMid
+ .byte 0x9b
+ .byte 0xaf # LimitHigh
+ .byte 0 # BaseHigh
+.equ GDT_SIZE, .- NullSeg
+
+TssSeg:
+ .word TSS_DESC_SIZE # LimitLow
+ .word 0 # BaseLow
+ .byte 0 # BaseMid
+ .byte 0x89
+ .byte 0x80 # LimitHigh
+ .byte 0 # BaseHigh
+ExceptionTssSeg:
+ .word TSS_DESC_SIZE # LimitLow
+ .word 0 # BaseLow
+ .byte 0 # BaseMid
+ .byte 0x89
+ .byte 0x80 # LimitHigh
+ .byte 0 # BaseHigh
+
+.equ CODE_SEL, CodeSeg32 - NullSeg
+.equ DATA_SEL, DataSeg32 - NullSeg
+.equ TSS_SEL, TssSeg - NullSeg
+.equ EXCEPTION_TSS_SEL, ExceptionTssSeg - NullSeg
+
+# IA32 TSS fields
+.equ TSS_ESP0, 4
+.equ TSS_SS0, 8
+.equ TSS_ESP1, 12
+.equ TSS_SS1, 16
+.equ TSS_ESP2, 20
+.equ TSS_SS2, 24
+.equ TSS_CR3, 28
+.equ TSS_EIP, 32
+.equ TSS_EFLAGS, 36
+.equ TSS_EAX, 40
+.equ TSS_ECX, 44
+.equ TSS_EDX, 48
+.equ TSS_EBX, 52
+.equ TSS_ESP, 56
+.equ TSS_EBP, 60
+.equ TSS_ESI, 64
+.equ TSS_EDI, 68
+.equ TSS_ES, 72
+.equ TSS_CS, 76
+.equ TSS_SS, 80
+.equ TSS_DS, 84
+.equ TSS_FS, 88
+.equ TSS_GS, 92
+.equ TSS_LDT, 96
+
+# Create 2 TSS segments just after GDT
+TssDescriptor:
+ .word 0 # PreviousTaskLink
+ .word 0 # Reserved
+ .long 0 # ESP0
+ .word 0 # SS0
+ .word 0 # Reserved
+ .long 0 # ESP1
+ .word 0 # SS1
+ .word 0 # Reserved
+ .long 0 # ESP2
+ .word 0 # SS2
+ .word 0 # Reserved
+ .long 0 # CR3
+ .long 0 # EIP
+ .long 0 # EFLAGS
+ .long 0 # EAX
+ .long 0 # ECX
+ .long 0 # EDX
+ .long 0 # EBX
+ .long 0 # ESP
+ .long 0 # EBP
+ .long 0 # ESI
+ .long 0 # EDI
+ .word 0 # ES
+ .word 0 # Reserved
+ .word 0 # CS
+ .word 0 # Reserved
+ .word 0 # SS
+ .word 0 # Reserved
+ .word 0 # DS
+ .word 0 # Reserved
+ .word 0 # FS
+ .word 0 # Reserved
+ .word 0 # GS
+ .word 0 # Reserved
+ .word 0 # LDT Selector
+ .word 0 # Reserved
+ .word 0 # T
+ .word 0 # I/O Map Base
+.equ TSS_DESC_SIZE, . - TssDescriptor
+
+ExceptionTssDescriptor:
+ .word 0 # PreviousTaskLink
+ .word 0 # Reserved
+ .long 0 # ESP0
+ .word 0 # SS0
+ .word 0 # Reserved
+ .long 0 # ESP1
+ .word 0 # SS1
+ .word 0 # Reserved
+ .long 0 # ESP2
+ .word 0 # SS2
+ .word 0 # Reserved
+ .long 0 # CR3
+ .long PFHandlerEntry # EIP
+ .long 00000002 # EFLAGS
+ .long 0 # EAX
+ .long 0 # ECX
+ .long 0 # EDX
+ .long 0 # EBX
+ .long 0 # ESP
+ .long 0 # EBP
+ .long 0 # ESI
+ .long 0 # EDI
+ .word DATA_SEL # ES
+ .word 0 # Reserved
+ .word CODE_SEL # CS
+ .word 0 # Reserved
+ .word DATA_SEL # SS
+ .word 0 # Reserved
+ .word DATA_SEL # DS
+ .word 0 # Reserved
+ .word DATA_SEL # FS
+ .word 0 # Reserved
+ .word DATA_SEL # GS
+ .word 0 # Reserved
+ .word 0 # LDT Selector
+ .word 0 # Reserved
+ .word 0 # T
+ .word 0 # I/O Map Base
+
+ASM_PFX(gcPsd):
+ .ascii "PSDSIG "
+ .word PSD_SIZE
+ .word 2
+ .word 1 << 2
+ .word CODE_SEL
+ .word DATA_SEL
+ .word DATA_SEL
+ .word DATA_SEL
+ .word 0
+ .long 0
+ .long 0
+ .long 0
+ .long 0
+ .quad 0
+ .long NullSeg
+ .long 0
+ .long GDT_SIZE
+ .long 0
+ .space 24, 0
+ .long ASM_PFX(gSmiMtrrs)
+ .long 0
+.equ PSD_SIZE, . - ASM_PFX(gcPsd)
+
+ASM_PFX(gcSmiGdtr): .word GDT_SIZE - 1
+ .long NullSeg
+
+ASM_PFX(gcSmiIdtr): .word IDT_SIZE - 1
+ .long _SmiIDT
+
+_SmiIDT:
+# The following segment repeats 32 times:
+# No. 1
+ .word 0 # Offset 0:15
+ .word CODE_SEL
+ .byte 0 # Unused
+ .byte 0x8e # Interrupt Gate, Present
+ .word 0 # Offset 16:31
+# No. 2
+ .word 0 # Offset 0:15
+ .word CODE_SEL
+ .byte 0 # Unused
+ .byte 0x8e # Interrupt Gate, Present
+ .word 0 # Offset 16:31
+# No. 3
+ .word 0 # Offset 0:15
+ .word CODE_SEL
+ .byte 0 # Unused
+ .byte 0x8e # Interrupt Gate, Present
+ .word 0 # Offset 16:31
+# No. 4
+ .word 0 # Offset 0:15
+ .word CODE_SEL
+ .byte 0 # Unused
+ .byte 0x8e # Interrupt Gate, Present
+ .word 0 # Offset 16:31
+# No. 5
+ .word 0 # Offset 0:15
+ .word CODE_SEL
+ .byte 0 # Unused
+ .byte 0x8e # Interrupt Gate, Present
+ .word 0 # Offset 16:31
+# No. 6
+ .word 0 # Offset 0:15
+ .word CODE_SEL
+ .byte 0 # Unused
+ .byte 0x8e # Interrupt Gate, Present
+ .word 0 # Offset 16:31
+# No. 7
+ .word 0 # Offset 0:15
+ .word CODE_SEL
+ .byte 0 # Unused
+ .byte 0x8e # Interrupt Gate, Present
+ .word 0 # Offset 16:31
+# No. 8
+ .word 0 # Offset 0:15
+ .word CODE_SEL
+ .byte 0 # Unused
+ .byte 0x8e # Interrupt Gate, Present
+ .word 0 # Offset 16:31
+# No. 9
+ .word 0 # Offset 0:15
+ .word CODE_SEL
+ .byte 0 # Unused
+ .byte 0x8e # Interrupt Gate, Present
+ .word 0 # Offset 16:31
+# No. 10
+ .word 0 # Offset 0:15
+ .word CODE_SEL
+ .byte 0 # Unused
+ .byte 0x8e # Interrupt Gate, Present
+ .word 0 # Offset 16:31
+# No. 11
+ .word 0 # Offset 0:15
+ .word CODE_SEL
+ .byte 0 # Unused
+ .byte 0x8e # Interrupt Gate, Present
+ .word 0 # Offset 16:31
+# No. 12
+ .word 0 # Offset 0:15
+ .word CODE_SEL
+ .byte 0 # Unused
+ .byte 0x8e # Interrupt Gate, Present
+ .word 0 # Offset 16:31
+# No. 13
+ .word 0 # Offset 0:15
+ .word CODE_SEL
+ .byte 0 # Unused
+ .byte 0x8e # Interrupt Gate, Present
+ .word 0 # Offset 16:31
+# No. 14
+ .word 0 # Offset 0:15
+ .word CODE_SEL
+ .byte 0 # Unused
+ .byte 0x8e # Interrupt Gate, Present
+ .word 0 # Offset 16:31
+# No. 15
+ .word 0 # Offset 0:15
+ .word CODE_SEL
+ .byte 0 # Unused
+ .byte 0x8e # Interrupt Gate, Present
+ .word 0 # Offset 16:31
+# No. 16
+ .word 0 # Offset 0:15
+ .word CODE_SEL
+ .byte 0 # Unused
+ .byte 0x8e # Interrupt Gate, Present
+ .word 0 # Offset 16:31
+# No. 17
+ .word 0 # Offset 0:15
+ .word CODE_SEL
+ .byte 0 # Unused
+ .byte 0x8e # Interrupt Gate, Present
+ .word 0 # Offset 16:31
+# No. 18
+ .word 0 # Offset 0:15
+ .word CODE_SEL
+ .byte 0 # Unused
+ .byte 0x8e # Interrupt Gate, Present
+ .word 0 # Offset 16:31
+# No. 19
+ .word 0 # Offset 0:15
+ .word CODE_SEL
+ .byte 0 # Unused
+ .byte 0x8e # Interrupt Gate, Present
+ .word 0 # Offset 16:31
+# No. 20
+ .word 0 # Offset 0:15
+ .word CODE_SEL
+ .byte 0 # Unused
+ .byte 0x8e # Interrupt Gate, Present
+ .word 0 # Offset 16:31
+# No. 21
+ .word 0 # Offset 0:15
+ .word CODE_SEL
+ .byte 0 # Unused
+ .byte 0x8e # Interrupt Gate, Present
+ .word 0 # Offset 16:31
+# No. 22
+ .word 0 # Offset 0:15
+ .word CODE_SEL
+ .byte 0 # Unused
+ .byte 0x8e # Interrupt Gate, Present
+ .word 0 # Offset 16:31
+# No. 23
+ .word 0 # Offset 0:15
+ .word CODE_SEL
+ .byte 0 # Unused
+ .byte 0x8e # Interrupt Gate, Present
+ .word 0 # Offset 16:31
+# No. 24
+ .word 0 # Offset 0:15
+ .word CODE_SEL
+ .byte 0 # Unused
+ .byte 0x8e # Interrupt Gate, Present
+ .word 0 # Offset 16:31
+# No. 25
+ .word 0 # Offset 0:15
+ .word CODE_SEL
+ .byte 0 # Unused
+ .byte 0x8e # Interrupt Gate, Present
+ .word 0 # Offset 16:31
+# No. 26
+ .word 0 # Offset 0:15
+ .word CODE_SEL
+ .byte 0 # Unused
+ .byte 0x8e # Interrupt Gate, Present
+ .word 0 # Offset 16:31
+# No. 27
+ .word 0 # Offset 0:15
+ .word CODE_SEL
+ .byte 0 # Unused
+ .byte 0x8e # Interrupt Gate, Present
+ .word 0 # Offset 16:31
+# No. 28
+ .word 0 # Offset 0:15
+ .word CODE_SEL
+ .byte 0 # Unused
+ .byte 0x8e # Interrupt Gate, Present
+ .word 0 # Offset 16:31
+# No. 29
+ .word 0 # Offset 0:15
+ .word CODE_SEL
+ .byte 0 # Unused
+ .byte 0x8e # Interrupt Gate, Present
+ .word 0 # Offset 16:31
+# No. 30
+ .word 0 # Offset 0:15
+ .word CODE_SEL
+ .byte 0 # Unused
+ .byte 0x8e # Interrupt Gate, Present
+ .word 0 # Offset 16:31
+# No. 31
+ .word 0 # Offset 0:15
+ .word CODE_SEL
+ .byte 0 # Unused
+ .byte 0x8e # Interrupt Gate, Present
+ .word 0 # Offset 16:31
+# No. 32
+ .word 0 # Offset 0:15
+ .word CODE_SEL
+ .byte 0 # Unused
+ .byte 0x8e # Interrupt Gate, Present
+ .word 0 # Offset 16:31
+
+.equ IDT_SIZE, . - _SmiIDT
+
+TaskGateDescriptor:
+ .word 0 # Reserved
+ .word EXCEPTION_TSS_SEL # TSS Segment selector
+ .byte 0 # Reserved
+ .byte 0x85 # Task Gate, present, DPL = 0
+ .word 0 # Reserved
+
+# point to the external interrupt vector table
+
+ExternalVectorTablePtr: .long 0
+
+#
+# Saved IDT Entry for Page Fault
+#
+ASM_PFX(gSavedPageFaultIdtEntry):
+ .long 0
+ .long 0
+
+#
+# Saved IDT Entry for INT 1
+#
+ASM_PFX(gSavedDebugExceptionIdtEntry):
+ .long 0
+ .long 0
+
+ .text
+
+ASM_PFX(InitializeSmmExternalVectorTablePtr):
+ movl 4(%esp), %eax
+ movl %eax, ExternalVectorTablePtr
+ ret
+
+#------------------------------------------------------------------------------
+# Exception handlers
+#------------------------------------------------------------------------------
+_SmiExceptionHandlers:
+.equ IHDLRIDX, 0
+# The following segment repeats 8 times:
+# No. 1
+ pushl %eax # dummy error code
+ pushl $IHDLRIDX
+ .byte 0xe9 # jmp disp32
+ .long _SmiExceptionEntryPoint - (. + 4)
+.equ IHDLRIDX, IHDLRIDX + 1
+# No. 2
+ pushl %eax # dummy error code
+ pushl $IHDLRIDX
+ .byte 0xe9 # jmp disp32
+ .long _SmiExceptionEntryPoint - (. + 4)
+.equ IHDLRIDX, IHDLRIDX + 1
+# No. 3
+ pushl %eax # dummy error code
+ pushl $IHDLRIDX
+ .byte 0xe9 # jmp disp32
+ .long _SmiExceptionEntryPoint - (. + 4)
+.equ IHDLRIDX, IHDLRIDX + 1
+# No. 4
+ pushl %eax # dummy error code
+ pushl $IHDLRIDX
+ .byte 0xe9 # jmp disp32
+ .long _SmiExceptionEntryPoint - (. + 4)
+.equ IHDLRIDX, IHDLRIDX + 1
+# No. 5
+ pushl %eax # dummy error code
+ pushl $IHDLRIDX
+ .byte 0xe9 # jmp disp32
+ .long _SmiExceptionEntryPoint - (. + 4)
+.equ IHDLRIDX, IHDLRIDX + 1
+# No. 6
+ pushl %eax # dummy error code
+ pushl $IHDLRIDX
+ .byte 0xe9 # jmp disp32
+ .long _SmiExceptionEntryPoint - (. + 4)
+.equ IHDLRIDX, IHDLRIDX + 1
+# No. 7
+ pushl %eax # dummy error code
+ pushl $IHDLRIDX
+ .byte 0xe9 # jmp disp32
+ .long _SmiExceptionEntryPoint - (. + 4)
+.equ IHDLRIDX, IHDLRIDX + 1
+# No. 8
+ pushl %eax # dummy error code
+ pushl $IHDLRIDX
+ .byte 0xe9 # jmp disp32
+ .long _SmiExceptionEntryPoint - (. + 4)
+.equ IHDLRIDX, IHDLRIDX + 1
+
+ pushl $IHDLRIDX
+ .byte 0xe9 # jmp disp32
+ .long _SmiExceptionEntryPoint - (. + 4)
+ int $3
+.equ IHDLRIDX, IHDLRIDX + 1
+
+ pushl %eax # dummy error code
+ pushl $IHDLRIDX
+ .byte 0xe9 # jmp disp32
+ .long _SmiExceptionEntryPoint - (. + 4)
+.equ IHDLRIDX, IHDLRIDX + 1
+
+# The following segment repeats 5 times:
+# No. 1
+ pushl $IHDLRIDX
+ .byte 0xe9 # jmp disp32
+ .long _SmiExceptionEntryPoint - (. + 4)
+ int $3
+.equ IHDLRIDX, IHDLRIDX + 1
+# No. 2
+ pushl $IHDLRIDX
+ .byte 0xe9 # jmp disp32
+ .long _SmiExceptionEntryPoint - (. + 4)
+ int $3
+.equ IHDLRIDX, IHDLRIDX + 1
+# No. 3
+ pushl $IHDLRIDX
+ .byte 0xe9 # jmp disp32
+ .long _SmiExceptionEntryPoint - (. + 4)
+ int $3
+.equ IHDLRIDX, IHDLRIDX + 1
+# No. 4
+ pushl $IHDLRIDX
+ .byte 0xe9 # jmp disp32
+ .long _SmiExceptionEntryPoint - (. + 4)
+ int $3
+.equ IHDLRIDX, IHDLRIDX + 1
+# No. 5
+ pushl $IHDLRIDX
+ .byte 0xe9 # jmp disp32
+ .long _SmiExceptionEntryPoint - (. + 4)
+ int $3
+.equ IHDLRIDX, IHDLRIDX + 1
+
+# The following segment repeats 2 times:
+# No. 1
+ pushl %eax # dummy error code
+ pushl $IHDLRIDX
+ .byte 0xe9 # jmp disp32
+ .long _SmiExceptionEntryPoint - (. + 4)
+.equ IHDLRIDX, IHDLRIDX + 1
+# No. 2
+ pushl %eax # dummy error code
+ pushl $IHDLRIDX
+ .byte 0xe9 # jmp disp32
+ .long _SmiExceptionEntryPoint - (. + 4)
+.equ IHDLRIDX, IHDLRIDX + 1
+
+ pushl $IHDLRIDX
+ .byte 0xe9 # jmp disp32
+ .long _SmiExceptionEntryPoint - (. + 4)
+ int $3
+.equ IHDLRIDX, IHDLRIDX + 1
+
+# The following segment repeats 14 times:
+# No. 1
+ pushl %eax # dummy error code
+ pushl $IHDLRIDX
+ .byte 0xe9 # jmp disp32
+ .long _SmiExceptionEntryPoint - (. + 4)
+.equ IHDLRIDX, IHDLRIDX + 1
+# No. 2
+ pushl %eax # dummy error code
+ pushl $IHDLRIDX
+ .byte 0xe9 # jmp disp32
+ .long _SmiExceptionEntryPoint - (. + 4)
+.equ IHDLRIDX, IHDLRIDX + 1
+# No. 3
+ pushl %eax # dummy error code
+ pushl $IHDLRIDX
+ .byte 0xe9 # jmp disp32
+ .long _SmiExceptionEntryPoint - (. + 4)
+.equ IHDLRIDX, IHDLRIDX + 1
+# No. 4
+ pushl %eax # dummy error code
+ pushl $IHDLRIDX
+ .byte 0xe9 # jmp disp32
+ .long _SmiExceptionEntryPoint - (. + 4)
+.equ IHDLRIDX, IHDLRIDX + 1
+# No. 5
+ pushl %eax # dummy error code
+ pushl $IHDLRIDX
+ .byte 0xe9 # jmp disp32
+ .long _SmiExceptionEntryPoint - (. + 4)
+.equ IHDLRIDX, IHDLRIDX + 1
+# No. 6
+ pushl %eax # dummy error code
+ pushl $IHDLRIDX
+ .byte 0xe9 # jmp disp32
+ .long _SmiExceptionEntryPoint - (. + 4)
+.equ IHDLRIDX, IHDLRIDX + 1
+# No. 7
+ pushl %eax # dummy error code
+ pushl $IHDLRIDX
+ .byte 0xe9 # jmp disp32
+ .long _SmiExceptionEntryPoint - (. + 4)
+.equ IHDLRIDX, IHDLRIDX + 1
+# No. 8
+ pushl %eax # dummy error code
+ pushl $IHDLRIDX
+ .byte 0xe9 # jmp disp32
+ .long _SmiExceptionEntryPoint - (. + 4)
+.equ IHDLRIDX, IHDLRIDX + 1
+# No. 9
+ pushl %eax # dummy error code
+ pushl $IHDLRIDX
+ .byte 0xe9 # jmp disp32
+ .long _SmiExceptionEntryPoint - (. + 4)
+.equ IHDLRIDX, IHDLRIDX + 1
+# No. 10
+ pushl %eax # dummy error code
+ pushl $IHDLRIDX
+ .byte 0xe9 # jmp disp32
+ .long _SmiExceptionEntryPoint - (. + 4)
+.equ IHDLRIDX, IHDLRIDX + 1
+# No. 11
+ pushl %eax # dummy error code
+ pushl $IHDLRIDX
+ .byte 0xe9 # jmp disp32
+ .long _SmiExceptionEntryPoint - (. + 4)
+.equ IHDLRIDX, IHDLRIDX + 1
+# No. 12
+ pushl %eax # dummy error code
+ pushl $IHDLRIDX
+ .byte 0xe9 # jmp disp32
+ .long _SmiExceptionEntryPoint - (. + 4)
+.equ IHDLRIDX, IHDLRIDX + 1
+# No. 13
+ pushl %eax # dummy error code
+ pushl $IHDLRIDX
+ .byte 0xe9 # jmp disp32
+ .long _SmiExceptionEntryPoint - (. + 4)
+.equ IHDLRIDX, IHDLRIDX + 1
+# No. 14
+ pushl %eax # dummy error code
+ pushl $IHDLRIDX
+ .byte 0xe9 # jmp disp32
+ .long _SmiExceptionEntryPoint - (. + 4)
+.equ IHDLRIDX, IHDLRIDX + 1
+
+
+#------------------------------------------------------------------------------
+# _SmiExceptionEntryPoint is the entry point for all exceptions
+#
+# Stack:
+#+---------------------+
+#+ EFlags +
+#+---------------------+
+#+ CS +
+#+---------------------+
+#+ EIP +
+#+---------------------+
+#+ Error Code +
+#+---------------------+
+#+ Vector Number +
+#+---------------------+
+#+ EBP +
+#+---------------------+ <-- EBP
+#
+# RSP set to odd multiple of 8 means ErrCode PRESENT
+#------------------------------------------------------------------------------
+_SmiExceptionEntryPoint:
+ pushl %ebp
+ movl %esp, %ebp
+
+
+ #
+ # Align stack to make sure that EFI_FX_SAVE_STATE_IA32 of EFI_SYSTEM_CONTEXT_IA32
+ # is 16-byte aligned
+ #
+ andl $0xfffffff0, %esp
+ subl $12, %esp
+
+## UINT32 Edi, Esi, Ebp, Esp, Ebx, Edx, Ecx, Eax;
+ pushl %eax
+ pushl %ecx
+ pushl %edx
+ pushl %ebx
+ leal (6*4)(%ebp), %ecx
+ pushl %ecx # ESP
+ pushl (%ebp) # EBP
+ pushl %esi
+ pushl %edi
+
+## UINT32 Gs, Fs, Es, Ds, Cs, Ss;
+ movl %ss, %eax
+ pushl %eax
+ movzwl (4*4)(%ebp), %eax
+ pushl %eax
+ movl %ds, %eax
+ pushl %eax
+ movl %es, %eax
+ pushl %eax
+ movl %fs, %eax
+ pushl %eax
+ movl %gs, %eax
+ pushl %eax
+
+## UINT32 Eip;
+ movl (3*4)(%ebp), %eax
+ pushl %eax
+
+## UINT32 Gdtr[2], Idtr[2];
+ subl $8, %esp
+ sidt (%esp)
+ movl 2(%esp), %eax
+ xchgl (%esp), %eax
+ andl $0xffff, %eax
+ movl %eax, 4(%esp)
+
+ subl $8, %esp
+ sgdt (%esp)
+ movl 2(%esp), %eax
+ xchgl (%esp), %eax
+ andl $0xffff, %eax
+ movl %eax, 4(%esp)
+
+## UINT32 Ldtr, Tr;
+ xorl %eax, %eax
+ strw %ax
+ pushl %eax
+ sldtw %ax
+ pushl %eax
+
+## UINT32 EFlags;
+ movl (5*4)(%ebp), %eax
+ pushl %eax
+
+## UINT32 Cr0, Cr1, Cr2, Cr3, Cr4;
+ movl %cr4, %eax
+ orl $0x208, %eax
+ movl %eax, %cr4
+ pushl %eax
+ movl %cr3, %eax
+ pushl %eax
+ movl %cr2, %eax
+ pushl %eax
+ xorl %eax, %eax
+ pushl %eax
+ movl %cr0, %eax
+ pushl %eax
+
+## UINT32 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7;
+ movl %dr7, %eax
+ pushl %eax
+ movl %dr6, %eax
+ pushl %eax
+ movl %dr3, %eax
+ pushl %eax
+ movl %dr2, %eax
+ pushl %eax
+ movl %dr1, %eax
+ pushl %eax
+ movl %dr0, %eax
+ pushl %eax
+
+## FX_SAVE_STATE_IA32 FxSaveState;
+ subl $512, %esp
+ movl %esp, %edi
+ .byte 0x0f, 0xae, 0x07 #fxsave [edi]
+
+# UEFI calling convention for IA32 requires that Direction flag in EFLAGs is clear
+ cld
+
+## UINT32 ExceptionData;
+ pushl (2*4)(%ebp)
+
+## call into exception handler
+ movl ExternalVectorTablePtr, %eax # get the interrupt vectors base
+ orl %eax, %eax # NULL?
+ jz nullExternalExceptionHandler
+
+ movl 4(%ebp), %ecx
+ movl (%eax, %ecx, 4), %eax
+ orl %eax, %eax # NULL?
+ jz nullExternalExceptionHandler
+
+## Prepare parameter and call
+ movl %esp, %edx
+ pushl %edx
+ movl (1*4)(%ebp), %edx
+ pushl %edx
+
+ #
+ # Call External Exception Handler
+ #
+ call *%eax
+ addl $8, %esp
+ jmp L4
+
+nullExternalExceptionHandler:
+# CpuDeadLoop() is the default exception handler since it preserves the processor
+# branch log.
+ call ASM_PFX(CpuDeadLoop)
+
+L4:
+## UINT32 ExceptionData;
+ addl $4, %esp
+
+## FX_SAVE_STATE_IA32 FxSaveState;
+ movl %esp, %esi
+ .byte 0xf, 0xae, 0xe # fxrstor [esi]
+ addl $512, %esp
+
+## UINT32 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7;
+## Skip restoration of DRx registers to support in-circuit emualators
+## or debuggers set breakpoint in interrupt/exception context
+ addl $4*6, %esp
+
+## UINT32 Cr0, Cr1, Cr2, Cr3, Cr4;
+ popl %eax
+ movl %eax, %cr0
+ addl $4, %esp # not for Cr1
+ popl %eax
+ movl %eax, %cr2
+ popl %eax
+ movl %eax, %cr3
+ popl %eax
+ movl %eax, %cr4
+
+## UINT32 EFlags;
+ popl (5*4)(%ebp)
+
+## UINT32 Ldtr, Tr;
+## UINT32 Gdtr[2], Idtr[2];
+## Best not let anyone mess with these particular registers...
+ addl $24, %esp
+
+## UINT32 Eip;
+ popl (3*4)(%ebp)
+
+## UINT32 Gs, Fs, Es, Ds, Cs, Ss;
+## NOTE - modified segment registers could hang the debugger... We
+## could attempt to insulate ourselves against this possibility,
+## but that poses risks as well.
+##
+ popl %gs
+ popl %fs
+ popl %es
+ popl %ds
+ popl (4*4)(%ebp)
+ popl %ss
+
+## UINT32 Edi, Esi, Ebp, Esp, Ebx, Edx, Ecx, Eax;
+ popl %edi
+ popl %esi
+ addl $4, %esp # not for ebp
+ addl $4, %esp # not for esp
+ popl %ebx
+ popl %edx
+ popl %ecx
+ popl %eax
+
+ movl %ebp, %esp
+ popl %ebp
+
+# Set single step DB# if SMM profile is enabled and page fault exception happens
+ cmpb $0, ASM_PFX(FeaturePcdGet (PcdCpuSmmProfileEnable))
+ jz Done
+# Check if this is page fault exception
+ cmpl $0xe, (%esp)
+ jnz L5
+# Enable TF bit after page fault handler runs
+ btsl $8, 16(%esp) # EFLAGS
+ jmp Done
+L5:
+# Check if this is INT 1 exception
+ cmpl $1, (%esp)
+ jnz Done
+# Clear TF bit after INT1 handler runs
+ btcl $8, 16(%esp) # EFLAGS
+Done:
+
+ addl $8, %esp # skip INT# & ErrCode
+Return:
+ iret
+#
+# Page Fault Exception Handler entry when SMM Stack Guard is enabled
+# Executiot starts here after a task switch
+#
+PFHandlerEntry:
+#
+# Get this processor's TSS
+#
+ subl $8, %esp
+ sgdt 2(%esp)
+ movl 4(%esp), %eax # GDT base
+ addl $8, %esp
+ movl (TSS_SEL+2)(%eax), %ecx
+ shll $8, %ecx
+ movb (TSS_SEL+7)(%eax), %cl
+ rorl $8, %ecx # ecx = TSS base
+
+ movl %esp, %ebp
+
+ #
+ # Align stack to make sure that EFI_FX_SAVE_STATE_IA32 of EFI_SYSTEM_CONTEXT_IA32
+ # is 16-byte aligned
+ #
+ andl $0xfffffff0, %esp
+ subl $12, %esp
+
+## UINT32 Edi, Esi, Ebp, Esp, Ebx, Edx, Ecx, Eax;
+ pushl TSS_EAX(%ecx)
+ pushl TSS_ECX(%ecx)
+ pushl TSS_EDX(%ecx)
+ pushl TSS_EBX(%ecx)
+ pushl TSS_ESP(%ecx)
+ pushl TSS_EBP(%ecx)
+ pushl TSS_ESI(%ecx)
+ pushl TSS_EDI(%ecx)
+
+## UINT32 Gs, Fs, Es, Ds, Cs, Ss;
+ movzwl TSS_SS(%ecx), %eax
+ pushl %eax
+ movzwl TSS_CS(%ecx), %eax
+ pushl %eax
+ movzwl TSS_DS(%ecx), %eax
+ pushl %eax
+ movzwl TSS_ES(%ecx), %eax
+ pushl %eax
+ movzwl TSS_FS(%ecx), %eax
+ pushl %eax
+ movzwl TSS_GS(%ecx), %eax
+ pushl %eax
+
+## UINT32 Eip;
+ pushl TSS_EIP(%ecx)
+
+## UINT32 Gdtr[2], Idtr[2];
+ subl $8, %esp
+ sidt (%esp)
+ movl 2(%esp), %eax
+ xchgl (%esp), %eax
+ andl $0xFFFF, %eax
+ movl %eax, 4(%esp)
+
+ subl $8, %esp
+ sgdt (%esp)
+ movl 2(%esp), %eax
+ xchgl (%esp), %eax
+ andl $0xFFFF, %eax
+ movl %eax, 4(%esp)
+
+## UINT32 Ldtr, Tr;
+ movl TSS_SEL, %eax
+ pushl %eax
+ movzwl TSS_LDT(%ecx), %eax
+ pushl %eax
+
+## UINT32 EFlags;
+ pushl TSS_EFLAGS(%ecx)
+
+## UINT32 Cr0, Cr1, Cr2, Cr3, Cr4;
+ movl %cr4, %eax
+ orl $0x208, %eax
+ movl %eax, %cr4
+ pushl %eax
+ movl %cr3, %eax
+ pushl %eax
+ movl %cr2, %eax
+ pushl %eax
+ xorl %eax, %eax
+ pushl %eax
+ movl %cr0, %eax
+ pushl %eax
+
+## UINT32 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7;
+ movl %dr7, %eax
+ pushl %eax
+ movl %dr6, %eax
+ pushl %eax
+ movl %dr3, %eax
+ pushl %eax
+ movl %dr2, %eax
+ pushl %eax
+ movl %dr1, %eax
+ pushl %eax
+ movl %dr0, %eax
+ pushl %eax
+
+## FX_SAVE_STATE_IA32 FxSaveState;
+ subl $512, %esp
+ movl %esp, %edi
+ .byte 0x0f, 0xae, 0x07 #fxsave [edi]
+
+# UEFI calling convention for IA32 requires that Direction flag in EFLAGs is clear
+ cld
+
+## UINT32 ExceptionData;
+ pushl (%ebp)
+
+## call into exception handler
+ movl ExternalVectorTablePtr, %eax # get the interrupt vectors base
+ orl %eax, %eax # NULL?
+ jz nullExternalExceptionHandler
+
+ movl %ecx, %ebx
+ mov $14, %ecx
+ movl (%eax, %ecx, 4), %eax
+ orl %eax, %eax # NULL?
+ jz nullExternalExceptionHandler
+
+## Prepare parameter and call
+ movl %esp, %edx
+ pushl %edx
+ movl $14, %edx
+ pushl %edx
+
+ #
+ # Call External Exception Handler
+ #
+ call *%eax
+ addl $8, %esp
+
+ movl %ebx, %ecx
+## UINT32 ExceptionData;
+ addl $4, %esp
+
+## FX_SAVE_STATE_IA32 FxSaveState;
+ movl %esp, %esi
+ .byte 0xf, 0xae, 0xe # fxrstor [esi]
+ addl $512, %esp
+
+## UINT32 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7;
+## Skip restoration of DRx registers to support in-circuit emualators
+## or debuggers set breakpoint in interrupt/exception context
+ addl $4*6, %esp
+
+## UINT32 Cr0, Cr1, Cr2, Cr3, Cr4;
+ popl %eax
+ movl %eax, %cr0
+ addl $4, %esp # not for Cr1
+ popl %eax
+ movl %eax, %cr2
+ popl %eax
+ movl %eax, TSS_CR3(%ecx)
+ popl %eax
+ movl %eax, %cr4
+
+## UINT32 EFlags;
+ popl TSS_EFLAGS(%ecx)
+
+## UINT32 Ldtr, Tr;
+## UINT32 Gdtr[2], Idtr[2];
+## Best not let anyone mess with these particular registers...
+ addl $24, %esp
+
+## UINT32 Eip;
+ popl TSS_EIP(%ecx)
+
+## UINT32 Gs, Fs, Es, Ds, Cs, Ss;
+## NOTE - modified segment registers could hang the debugger... We
+## could attempt to insulate ourselves against this possibility,
+## but that poses risks as well.
+##
+ popl %eax
+ movw %ax, TSS_GS(%ecx)
+ popl %eax
+ movw %ax, TSS_FS(%ecx)
+ popl %eax
+ movw %ax, TSS_ES(%ecx)
+ popl %eax
+ movw %ax, TSS_DS(%ecx)
+ popl %eax
+ movw %ax, TSS_CS(%ecx)
+ popl %eax
+ movw %ax, TSS_SS(%ecx)
+
+## UINT32 Edi, Esi, Ebp, Esp, Ebx, Edx, Ecx, Eax;
+ popl TSS_EDI(%ecx)
+ popl TSS_ESI(%ecx)
+ addl $4, %esp # not for ebp
+ addl $4, %esp # not for esp
+ popl TSS_EBX(%ecx)
+ popl TSS_EDX(%ecx)
+ popl TSS_ECX(%ecx)
+ popl TSS_EAX(%ecx)
+
+ movl %ebp, %esp
+
+# Set single step DB# if SMM profile is enabled and page fault exception happens
+ cmpb $0, ASM_PFX(FeaturePcdGet (PcdCpuSmmProfileEnable))
+ jz Done2
+# Enable TF bit after page fault handler runs
+ btsl $8, TSS_EFLAGS(%ecx) # EFLAGS
+
+Done2:
+
+ addl 4, %esp # skip ErrCode
+
+ jmp Return
+
+ASM_GLOBAL ASM_PFX(InitializeIDT)
+ASM_PFX(InitializeIDT):
+ pushl %ebx
+ lea _SmiIDT - 8, %edx
+# push IDT_SIZE / 8
+ .byte 0x68 # push /id
+ .long IDT_SIZE / 8
+ lea _SmiExceptionHandlers - 8, %ebx
+ popl %ecx
+L1:
+ leal (%ebx,%ecx,8),%eax
+ movw %ax,(%edx,%ecx,8)
+ shrl $16,%eax
+ movw %ax, 6(%edx, %ecx, 8)
+ loop L1
+
+ cmpb $0, ASM_PFX(FeaturePcdGet (PcdCpuSmmStackGuard))
+ jz L2
+
+#
+# If SMM Stack Guard feature is enabled, the Page Fault Exception entry in IDT
+# is a Task Gate Descriptor so that when a Page Fault Exception occurrs,
+# the processors can use a known good stack in case stack ran out.
+#
+ leal _SmiIDT + 14 * 8, %ebx
+ leal TaskGateDescriptor, %edx
+ movl (%edx), %eax
+ movl %eax, (%ebx)
+ movl 4(%edx), %eax
+ movl %eax, 4(%ebx)
+
+L2:
+#
+# Save Page Fault IDT entry in gPageFaultIdtEntry
+#
+ leal _SmiIDT + 14 * 8, %ebx
+ leal ASM_PFX(gSavedPageFaultIdtEntry), %edx
+ movl (%ebx), %eax
+ movl %eax, (%edx)
+ movl 4(%ebx), %eax
+ movl %eax, 4(%edx)
+
+ cmpb $0, ASM_PFX(FeaturePcdGet (PcdCpuSmmProfileEnable))
+ jz L3
+
+#
+# Save INT 1 IDT entry in gSavedDebugExceptionIdtEntry
+#
+ leal _SmiIDT + 1 * 8, %ebx
+ leal ASM_PFX(gSavedDebugExceptionIdtEntry), %edx
+ movl (%ebx), %eax
+ movl %eax, (%edx)
+ movl 4(%ebx), %eax
+ movl %eax, 4(%edx)
+
+L3:
+ popl %ebx
+ ret
+
diff --git a/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/PiSmmCpuDxeSmm/Ia32/SmiException.asm b/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/PiSmmCpuDxeSmm/Ia32/SmiException.asm
new file mode 100644
index 0000000000..33b4d8387f
--- /dev/null
+++ b/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/PiSmmCpuDxeSmm/Ia32/SmiException.asm
@@ -0,0 +1,858 @@
+;; @file
+; Exception handlers used in SM mode
+;
+; Copyright (c) 2009 - 2015, 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.
+;
+;;
+
+ .686p
+ .model flat,C
+
+CpuDeadLoop PROTO C
+
+EXTERNDEF gSmiMtrrs:QWORD
+EXTERNDEF gcSmiIdtr:FWORD
+EXTERNDEF gcSmiGdtr:FWORD
+EXTERNDEF gcPsd:BYTE
+EXTERNDEF FeaturePcdGet (PcdCpuSmmStackGuard):BYTE
+EXTERNDEF gSavedPageFaultIdtEntry:DWORD
+EXTERNDEF gSavedDebugExceptionIdtEntry:DWORD
+EXTERNDEF FeaturePcdGet (PcdCpuSmmProfileEnable):BYTE
+
+
+ .data
+
+NullSeg DQ 0 ; reserved by architecture
+ DQ 0 ; reserved for future use
+CodeSeg32 LABEL QWORD
+ DW -1 ; LimitLow
+ DW 0 ; BaseLow
+ DB 0 ; BaseMid
+ DB 9bh
+ DB 0cfh ; LimitHigh
+ DB 0 ; BaseHigh
+DataSeg32 LABEL QWORD
+ DW -1 ; LimitLow
+ DW 0 ; BaseLow
+ DB 0 ; BaseMid
+ DB 93h
+ DB 0cfh ; LimitHigh
+ DB 0 ; BaseHigh
+ DQ 0 ; reserved for future use
+CodeSeg16 LABEL QWORD
+ DW -1
+ DW 0
+ DB 0
+ DB 9bh
+ DB 8fh
+ DB 0
+DataSeg16 LABEL QWORD
+ DW -1
+ DW 0
+ DB 0
+ DB 93h
+ DB 8fh
+ DB 0
+CodeSeg64 LABEL QWORD
+ DW -1 ; LimitLow
+ DW 0 ; BaseLow
+ DB 0 ; BaseMid
+ DB 9bh
+ DB 0afh ; LimitHigh
+ DB 0 ; BaseHigh
+GDT_SIZE = $ - offset NullSeg
+
+TssSeg LABEL QWORD
+ DW TSS_DESC_SIZE ; LimitLow
+ DW 0 ; BaseLow
+ DB 0 ; BaseMid
+ DB 89h
+ DB 080h ; LimitHigh
+ DB 0 ; BaseHigh
+ExceptionTssSeg LABEL QWORD
+ DW TSS_DESC_SIZE ; LimitLow
+ DW 0 ; BaseLow
+ DB 0 ; BaseMid
+ DB 89h
+ DB 080h ; LimitHigh
+ DB 0 ; BaseHigh
+
+CODE_SEL = offset CodeSeg32 - offset NullSeg
+DATA_SEL = offset DataSeg32 - offset NullSeg
+TSS_SEL = offset TssSeg - offset NullSeg
+EXCEPTION_TSS_SEL = offset ExceptionTssSeg - offset NullSeg
+
+IA32_TSS STRUC
+ DW ?
+ DW ?
+ ESP0 DD ?
+ SS0 DW ?
+ DW ?
+ ESP1 DD ?
+ SS1 DW ?
+ DW ?
+ ESP2 DD ?
+ SS2 DW ?
+ DW ?
+ _CR3 DD ?
+ EIP DD ?
+ EFLAGS DD ?
+ _EAX DD ?
+ _ECX DD ?
+ _EDX DD ?
+ _EBX DD ?
+ _ESP DD ?
+ _EBP DD ?
+ _ESI DD ?
+ _EDI DD ?
+ _ES DW ?
+ DW ?
+ _CS DW ?
+ DW ?
+ _SS DW ?
+ DW ?
+ _DS DW ?
+ DW ?
+ _FS DW ?
+ DW ?
+ _GS DW ?
+ DW ?
+ LDT DW ?
+ DW ?
+ DW ?
+ DW ?
+IA32_TSS ENDS
+
+; Create 2 TSS segments just after GDT
+TssDescriptor LABEL BYTE
+ DW 0 ; PreviousTaskLink
+ DW 0 ; Reserved
+ DD 0 ; ESP0
+ DW 0 ; SS0
+ DW 0 ; Reserved
+ DD 0 ; ESP1
+ DW 0 ; SS1
+ DW 0 ; Reserved
+ DD 0 ; ESP2
+ DW 0 ; SS2
+ DW 0 ; Reserved
+ DD 0 ; CR3
+ DD 0 ; EIP
+ DD 0 ; EFLAGS
+ DD 0 ; EAX
+ DD 0 ; ECX
+ DD 0 ; EDX
+ DD 0 ; EBX
+ DD 0 ; ESP
+ DD 0 ; EBP
+ DD 0 ; ESI
+ DD 0 ; EDI
+ DW 0 ; ES
+ DW 0 ; Reserved
+ DW 0 ; CS
+ DW 0 ; Reserved
+ DW 0 ; SS
+ DW 0 ; Reserved
+ DW 0 ; DS
+ DW 0 ; Reserved
+ DW 0 ; FS
+ DW 0 ; Reserved
+ DW 0 ; GS
+ DW 0 ; Reserved
+ DW 0 ; LDT Selector
+ DW 0 ; Reserved
+ DW 0 ; T
+ DW 0 ; I/O Map Base
+TSS_DESC_SIZE = $ - offset TssDescriptor
+
+ExceptionTssDescriptor LABEL BYTE
+ DW 0 ; PreviousTaskLink
+ DW 0 ; Reserved
+ DD 0 ; ESP0
+ DW 0 ; SS0
+ DW 0 ; Reserved
+ DD 0 ; ESP1
+ DW 0 ; SS1
+ DW 0 ; Reserved
+ DD 0 ; ESP2
+ DW 0 ; SS2
+ DW 0 ; Reserved
+ DD 0 ; CR3
+ DD offset PFHandlerEntry ; EIP
+ DD 00000002 ; EFLAGS
+ DD 0 ; EAX
+ DD 0 ; ECX
+ DD 0 ; EDX
+ DD 0 ; EBX
+ DD 0 ; ESP
+ DD 0 ; EBP
+ DD 0 ; ESI
+ DD 0 ; EDI
+ DW DATA_SEL ; ES
+ DW 0 ; Reserved
+ DW CODE_SEL ; CS
+ DW 0 ; Reserved
+ DW DATA_SEL ; SS
+ DW 0 ; Reserved
+ DW DATA_SEL ; DS
+ DW 0 ; Reserved
+ DW DATA_SEL ; FS
+ DW 0 ; Reserved
+ DW DATA_SEL ; GS
+ DW 0 ; Reserved
+ DW 0 ; LDT Selector
+ DW 0 ; Reserved
+ DW 0 ; T
+ DW 0 ; I/O Map Base
+
+gcPsd LABEL BYTE
+ DB 'PSDSIG '
+ DW PSD_SIZE
+ DW 2
+ DW 1 SHL 2
+ DW CODE_SEL
+ DW DATA_SEL
+ DW DATA_SEL
+ DW DATA_SEL
+ DW 0
+ DQ 0
+ DQ 0
+ DQ 0
+ DQ offset NullSeg
+ DD GDT_SIZE
+ DD 0
+ DB 24 dup (0)
+ DQ offset gSmiMtrrs
+PSD_SIZE = $ - offset gcPsd
+
+gcSmiGdtr LABEL FWORD
+ DW GDT_SIZE - 1
+ DD offset NullSeg
+
+gcSmiIdtr LABEL FWORD
+ DW IDT_SIZE - 1
+ DD offset _SmiIDT
+
+_SmiIDT LABEL QWORD
+REPEAT 32
+ DW 0 ; Offset 0:15
+ DW CODE_SEL ; Segment selector
+ DB 0 ; Unused
+ DB 8eh ; Interrupt Gate, Present
+ DW 0 ; Offset 16:31
+ ENDM
+IDT_SIZE = $ - offset _SmiIDT
+
+TaskGateDescriptor LABEL DWORD
+ DW 0 ; Reserved
+ DW EXCEPTION_TSS_SEL ; TSS Segment selector
+ DB 0 ; Reserved
+ DB 85h ; Task Gate, present, DPL = 0
+ DW 0 ; Reserved
+
+;
+; point to the external interrupt vector table
+;
+ExternalVectorTablePtr DWORD 0
+
+;
+; Saved IDT Entry for Page Fault
+;
+gSavedPageFaultIdtEntry LABEL DWORD
+ DD 0
+ DD 0
+
+;
+; Saved IDT Entry for INT 1
+;
+gSavedDebugExceptionIdtEntry LABEL DWORD
+ DD 0
+ DD 0
+
+
+ .code
+
+InitializeSmmExternalVectorTablePtr PROC PUBLIC
+ mov eax, [esp+4]
+ mov ExternalVectorTablePtr, eax
+ ret
+InitializeSmmExternalVectorTablePtr ENDP
+
+;------------------------------------------------------------------------------
+; Exception handlers
+;------------------------------------------------------------------------------
+_SmiExceptionHandlers PROC
+IHDLRIDX = 0
+REPEAT 8 ; INT0 ~ INT7
+ push eax ; dummy error code
+ push IHDLRIDX
+ DB 0e9h ; jmp disp32
+ DD _SmiExceptionEntryPoint - ($ + 4)
+IHDLRIDX = IHDLRIDX + 1
+ ENDM
+REPEAT 1 ; INT8
+ push IHDLRIDX
+ DB 0e9h ; jmp disp32
+ DD _SmiExceptionEntryPoint - ($ + 4)
+ int 3
+IHDLRIDX = IHDLRIDX + 1
+ ENDM
+REPEAT 1 ; INT9
+ push eax ; dummy error code
+ push IHDLRIDX
+ DB 0e9h ; jmp disp32
+ DD _SmiExceptionEntryPoint - ($ + 4)
+IHDLRIDX = IHDLRIDX + 1
+ ENDM
+REPEAT 5 ; INT10 ~ INT14
+ push IHDLRIDX
+ DB 0e9h ; jmp disp32
+ DD _SmiExceptionEntryPoint - ($ + 4)
+ int 3
+IHDLRIDX = IHDLRIDX + 1
+ ENDM
+REPEAT 2 ; INT15 ~ INT16
+ push eax ; dummy error code
+ push IHDLRIDX
+ DB 0e9h ; jmp disp32
+ DD _SmiExceptionEntryPoint - ($ + 4)
+IHDLRIDX = IHDLRIDX + 1
+ ENDM
+REPEAT 1 ; INT17
+ push IHDLRIDX
+ DB 0e9h ; jmp disp32
+ DD _SmiExceptionEntryPoint - ($ + 4)
+ int 3
+IHDLRIDX = IHDLRIDX + 1
+ ENDM
+REPEAT 14 ; INT18 ~ INT31
+ push eax ; dummy error code
+ push IHDLRIDX
+ DB 0e9h ; jmp disp32
+ DD _SmiExceptionEntryPoint - ($ + 4)
+IHDLRIDX = IHDLRIDX + 1
+ ENDM
+_SmiExceptionHandlers ENDP
+
+;------------------------------------------------------------------------------
+; _SmiExceptionEntryPoint is the entry point for all exceptions
+;
+;
+; Stack:
+; +---------------------+
+; + EFlags +
+; +---------------------+
+; + CS +
+; +---------------------+
+; + EIP +
+; +---------------------+
+; + Error Code +
+; +---------------------+
+; + Vector Number +
+; +---------------------+
+; + EBP +
+; +---------------------+ <-- EBP
+;
+;
+;------------------------------------------------------------------------------
+_SmiExceptionEntryPoint PROC
+
+
+ push ebp
+ mov ebp, esp
+
+
+ ;
+ ; Align stack to make sure that EFI_FX_SAVE_STATE_IA32 of EFI_SYSTEM_CONTEXT_IA32
+ ; is 16-byte aligned
+ ;
+ and esp, 0fffffff0h
+ sub esp, 12
+
+;; UINT32 Edi, Esi, Ebp, Esp, Ebx, Edx, Ecx, Eax;
+ push eax
+ push ecx
+ push edx
+ push ebx
+ lea ecx, [ebp + 6 * 4]
+ push ecx ; ESP
+ push dword ptr [ebp] ; EBP
+ push esi
+ push edi
+
+;; UINT32 Gs, Fs, Es, Ds, Cs, Ss;
+ mov eax, ss
+ push eax
+ movzx eax, word ptr [ebp + 4 * 4]
+ push eax
+ mov eax, ds
+ push eax
+ mov eax, es
+ push eax
+ mov eax, fs
+ push eax
+ mov eax, gs
+ push eax
+
+;; UINT32 Eip;
+ mov eax, [ebp + 3 * 4]
+ push eax
+
+;; UINT32 Gdtr[2], Idtr[2];
+ sub esp, 8
+ sidt [esp]
+ mov eax, [esp + 2]
+ xchg eax, [esp]
+ and eax, 0FFFFh
+ mov [esp+4], eax
+
+ sub esp, 8
+ sgdt [esp]
+ mov eax, [esp + 2]
+ xchg eax, [esp]
+ and eax, 0FFFFh
+ mov [esp+4], eax
+
+;; UINT32 Ldtr, Tr;
+ xor eax, eax
+ str ax
+ push eax
+ sldt ax
+ push eax
+
+;; UINT32 EFlags;
+ mov eax, [ebp + 5 * 4]
+ push eax
+
+;; UINT32 Cr0, Cr1, Cr2, Cr3, Cr4;
+ mov eax, cr4
+ or eax, 208h
+ mov cr4, eax
+ push eax
+ mov eax, cr3
+ push eax
+ mov eax, cr2
+ push eax
+ xor eax, eax
+ push eax
+ mov eax, cr0
+ push eax
+
+;; UINT32 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7;
+ mov eax, dr7
+ push eax
+ mov eax, dr6
+ push eax
+ mov eax, dr3
+ push eax
+ mov eax, dr2
+ push eax
+ mov eax, dr1
+ push eax
+ mov eax, dr0
+ push eax
+
+;; FX_SAVE_STATE_IA32 FxSaveState;
+ sub esp, 512
+ mov edi, esp
+ db 0fh, 0aeh, 07h ;fxsave [edi]
+
+; UEFI calling convention for IA32 requires that Direction flag in EFLAGs is clear
+ cld
+
+;; UINT32 ExceptionData;
+ push dword ptr [ebp + 2 * 4]
+
+;; call into exception handler
+ mov eax, ExternalVectorTablePtr ; get the interrupt vectors base
+ or eax, eax ; NULL?
+ jz nullExternalExceptionHandler
+
+ mov ecx, [ebp + 4]
+ mov eax, [eax + ecx * 4]
+ or eax, eax ; NULL?
+ jz nullExternalExceptionHandler
+
+;; Prepare parameter and call
+ mov edx, esp
+ push edx
+ mov edx, dword ptr [ebp + 1 * 4]
+ push edx
+
+ ;
+ ; Call External Exception Handler
+ ;
+ call eax
+ add esp, 8
+ jmp @F
+
+nullExternalExceptionHandler:
+; CpuDeadLoop() is the default exception handler since it preserves the processor
+; branch log.
+ call CpuDeadLoop
+
+@@:
+;; UINT32 ExceptionData;
+ add esp, 4
+
+;; FX_SAVE_STATE_IA32 FxSaveState;
+ mov esi, esp
+ db 0fh, 0aeh, 0eh ; fxrstor [esi]
+ add esp, 512
+
+;; UINT32 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7;
+;; Skip restoration of DRx registers to support in-circuit emualators
+;; or debuggers set breakpoint in interrupt/exception context
+ add esp, 4 * 6
+
+;; UINT32 Cr0, Cr1, Cr2, Cr3, Cr4;
+ pop eax
+ mov cr0, eax
+ add esp, 4 ; not for Cr1
+ pop eax
+ mov cr2, eax
+ pop eax
+ mov cr3, eax
+ pop eax
+ mov cr4, eax
+
+;; UINT32 EFlags;
+ pop dword ptr [ebp + 5 * 4]
+
+;; UINT32 Ldtr, Tr;
+;; UINT32 Gdtr[2], Idtr[2];
+;; Best not let anyone mess with these particular registers...
+ add esp, 24
+
+;; UINT32 Eip;
+ pop dword ptr [ebp + 3 * 4]
+
+;; UINT32 Gs, Fs, Es, Ds, Cs, Ss;
+;; NOTE - modified segment registers could hang the debugger... We
+;; could attempt to insulate ourselves against this possibility,
+;; but that poses risks as well.
+;;
+ pop gs
+ pop fs
+ pop es
+ pop ds
+ pop dword ptr [ebp + 4 * 4]
+ pop ss
+
+;; UINT32 Edi, Esi, Ebp, Esp, Ebx, Edx, Ecx, Eax;
+ pop edi
+ pop esi
+ add esp, 4 ; not for ebp
+ add esp, 4 ; not for esp
+ pop ebx
+ pop edx
+ pop ecx
+ pop eax
+
+ mov esp, ebp
+ pop ebp
+
+; Set single step DB# if SMM profile is enabled and page fault exception happens
+ cmp FeaturePcdGet (PcdCpuSmmProfileEnable), 0
+ jz @Done
+; Check if this is page fault exception
+ cmp dword ptr [esp], 0eh
+ jnz @F
+; Enable TF bit after page fault handler runs
+ bts dword ptr [esp + 16], 8 ; EFLAGS
+ jmp @Done
+@@:
+; Check if this is INT 1 exception
+ cmp dword ptr [esp], 1
+ jnz @Done
+; Clear TF bit after INT1 handler runs
+ btc dword ptr [esp + 16], 8 ; EFLAGS
+@Done:
+
+ add esp, 8 ; skip INT# & ErrCode
+Return:
+ iretd
+;
+; Page Fault Exception Handler entry when SMM Stack Guard is enabled
+; Executiot starts here after a task switch
+;
+PFHandlerEntry::
+;
+; Get this processor's TSS
+;
+ sub esp, 8
+ sgdt [esp + 2]
+ mov eax, [esp + 4] ; GDT base
+ add esp, 8
+ mov ecx, [eax + TSS_SEL + 2]
+ shl ecx, 8
+ mov cl, [eax + TSS_SEL + 7]
+ ror ecx, 8 ; ecx = TSS base
+
+ mov ebp, esp
+
+ ;
+ ; Align stack to make sure that EFI_FX_SAVE_STATE_IA32 of EFI_SYSTEM_CONTEXT_IA32
+ ; is 16-byte aligned
+ ;
+ and esp, 0fffffff0h
+ sub esp, 12
+
+;; UINT32 Edi, Esi, Ebp, Esp, Ebx, Edx, Ecx, Eax;
+ push (IA32_TSS ptr [ecx])._EAX
+ push (IA32_TSS ptr [ecx])._ECX
+ push (IA32_TSS ptr [ecx])._EDX
+ push (IA32_TSS ptr [ecx])._EBX
+ push (IA32_TSS ptr [ecx])._ESP
+ push (IA32_TSS ptr [ecx])._EBP
+ push (IA32_TSS ptr [ecx])._ESI
+ push (IA32_TSS ptr [ecx])._EDI
+
+;; UINT32 Gs, Fs, Es, Ds, Cs, Ss;
+ movzx eax, (IA32_TSS ptr [ecx])._SS
+ push eax
+ movzx eax, (IA32_TSS ptr [ecx])._CS
+ push eax
+ movzx eax, (IA32_TSS ptr [ecx])._DS
+ push eax
+ movzx eax, (IA32_TSS ptr [ecx])._ES
+ push eax
+ movzx eax, (IA32_TSS ptr [ecx])._FS
+ push eax
+ movzx eax, (IA32_TSS ptr [ecx])._GS
+ push eax
+
+;; UINT32 Eip;
+ push (IA32_TSS ptr [ecx]).EIP
+
+;; UINT32 Gdtr[2], Idtr[2];
+ sub esp, 8
+ sidt [esp]
+ mov eax, [esp + 2]
+ xchg eax, [esp]
+ and eax, 0FFFFh
+ mov [esp+4], eax
+
+ sub esp, 8
+ sgdt [esp]
+ mov eax, [esp + 2]
+ xchg eax, [esp]
+ and eax, 0FFFFh
+ mov [esp+4], eax
+
+;; UINT32 Ldtr, Tr;
+ mov eax, TSS_SEL
+ push eax
+ movzx eax, (IA32_TSS ptr [ecx]).LDT
+ push eax
+
+;; UINT32 EFlags;
+ push (IA32_TSS ptr [ecx]).EFLAGS
+
+;; UINT32 Cr0, Cr1, Cr2, Cr3, Cr4;
+ mov eax, cr4
+ or eax, 208h
+ mov cr4, eax
+ push eax
+ mov eax, cr3
+ push eax
+ mov eax, cr2
+ push eax
+ xor eax, eax
+ push eax
+ mov eax, cr0
+ push eax
+
+;; UINT32 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7;
+ mov eax, dr7
+ push eax
+ mov eax, dr6
+ push eax
+ mov eax, dr3
+ push eax
+ mov eax, dr2
+ push eax
+ mov eax, dr1
+ push eax
+ mov eax, dr0
+ push eax
+
+;; FX_SAVE_STATE_IA32 FxSaveState;
+ sub esp, 512
+ mov edi, esp
+ db 0fh, 0aeh, 07h ;fxsave [edi]
+
+; UEFI calling convention for IA32 requires that Direction flag in EFLAGs is clear
+ cld
+
+;; UINT32 ExceptionData;
+ push dword ptr [ebp]
+
+;; call into exception handler
+ mov eax, ExternalVectorTablePtr ; get the interrupt vectors base
+ or eax, eax ; NULL?
+ jz nullExternalExceptionHandler
+
+ mov ebx, ecx
+ mov ecx, 14
+ mov eax, [eax + ecx * 4]
+ or eax, eax ; NULL?
+ jz nullExternalExceptionHandler
+
+;; Prepare parameter and call
+ mov edx, esp
+ push edx
+ mov edx, 14
+ push edx
+
+ ;
+ ; Call External Exception Handler
+ ;
+ call eax
+ add esp, 8
+
+ mov ecx, ebx
+;; UINT32 ExceptionData;
+ add esp, 4
+
+;; FX_SAVE_STATE_IA32 FxSaveState;
+ mov esi, esp
+ db 0fh, 0aeh, 0eh ; fxrstor [esi]
+ add esp, 512
+
+;; UINT32 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7;
+;; Skip restoration of DRx registers to support in-circuit emualators
+;; or debuggers set breakpoint in interrupt/exception context
+ add esp, 4 * 6
+
+;; UINT32 Cr0, Cr1, Cr2, Cr3, Cr4;
+ pop eax
+ mov cr0, eax
+ add esp, 4 ; not for Cr1
+ pop eax
+ mov cr2, eax
+ pop eax
+ mov (IA32_TSS ptr [ecx])._CR3, eax
+ pop eax
+ mov cr4, eax
+
+;; UINT32 EFlags;
+ pop (IA32_TSS ptr [ecx]).EFLAGS
+
+;; UINT32 Ldtr, Tr;
+;; UINT32 Gdtr[2], Idtr[2];
+;; Best not let anyone mess with these particular registers...
+ add esp, 24
+
+;; UINT32 Eip;
+ pop (IA32_TSS ptr [ecx]).EIP
+
+;; UINT32 Gs, Fs, Es, Ds, Cs, Ss;
+;; NOTE - modified segment registers could hang the debugger... We
+;; could attempt to insulate ourselves against this possibility,
+;; but that poses risks as well.
+;;
+ pop eax
+ mov (IA32_TSS ptr [ecx])._GS, ax
+ pop eax
+ mov (IA32_TSS ptr [ecx])._FS, ax
+ pop eax
+ mov (IA32_TSS ptr [ecx])._ES, ax
+ pop eax
+ mov (IA32_TSS ptr [ecx])._DS, ax
+ pop eax
+ mov (IA32_TSS ptr [ecx])._CS, ax
+ pop eax
+ mov (IA32_TSS ptr [ecx])._SS, ax
+
+;; UINT32 Edi, Esi, Ebp, Esp, Ebx, Edx, Ecx, Eax;
+ pop (IA32_TSS ptr [ecx])._EDI
+ pop (IA32_TSS ptr [ecx])._ESI
+ add esp, 4 ; not for ebp
+ add esp, 4 ; not for esp
+ pop (IA32_TSS ptr [ecx])._EBX
+ pop (IA32_TSS ptr [ecx])._EDX
+ pop (IA32_TSS ptr [ecx])._ECX
+ pop (IA32_TSS ptr [ecx])._EAX
+
+ mov esp, ebp
+
+; Set single step DB# if SMM profile is enabled and page fault exception happens
+ cmp FeaturePcdGet (PcdCpuSmmProfileEnable), 0
+ jz @Done2
+; Enable TF bit after page fault handler runs
+ bts (IA32_TSS ptr [ecx]).EFLAGS, 8 ; EFLAGS
+
+@Done2:
+
+ add esp, 4 ; skip ErrCode
+
+ jmp Return
+_SmiExceptionEntryPoint ENDP
+
+InitializeIDT PROC USES ebx
+ lea edx, _SmiIDT - 8
+; push IDT_SIZE / 8
+ DB 68h ; push /id
+ DD IDT_SIZE / 8
+ lea ebx, _SmiExceptionHandlers - 8
+ pop ecx
+@@:
+ lea eax, [ebx + ecx*8]
+ mov [edx + ecx*8], ax
+ shr eax, 16
+ mov [edx + ecx*8 + 6], ax
+ loop @B
+
+ cmp FeaturePcdGet (PcdCpuSmmStackGuard), 0
+ jz @F
+
+;
+; If SMM Stack Guard feature is enabled, the Page Fault Exception entry in IDT
+; is a Task Gate Descriptor so that when a Page Fault Exception occurrs,
+; the processors can use a known good stack in case stack is ran out.
+;
+ lea ebx, _SmiIDT + 14 * 8
+ lea edx, TaskGateDescriptor
+ mov eax, [edx]
+ mov [ebx], eax
+ mov eax, [edx + 4]
+ mov [ebx + 4], eax
+
+@@:
+;
+; Save Page Fault IDT entry in gPageFaultIdtEntry
+;
+ lea ebx, _SmiIDT + 14 * 8
+ lea edx, gSavedPageFaultIdtEntry
+ mov eax, [ebx]
+ mov [edx], eax
+ mov eax, [ebx + 4]
+ mov [edx + 4], eax
+
+ cmp FeaturePcdGet (PcdCpuSmmProfileEnable), 0
+ jz @F
+
+;
+; Save INT 1 IDT entry in gSavedDebugExceptionIdtEntry
+;
+ lea ebx, _SmiIDT + 1 * 8
+ lea edx, gSavedDebugExceptionIdtEntry
+ mov eax, [ebx]
+ mov [edx], eax
+ mov eax, [ebx + 4]
+ mov [edx + 4], eax
+
+@@:
+ ret
+InitializeIDT ENDP
+
+ END
diff --git a/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/PiSmmCpuDxeSmm/Ia32/SmmInit.S b/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/PiSmmCpuDxeSmm/Ia32/SmmInit.S
new file mode 100644
index 0000000000..0a19a3949e
--- /dev/null
+++ b/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/PiSmmCpuDxeSmm/Ia32/SmmInit.S
@@ -0,0 +1,94 @@
+## @file
+# Functions for relocating SMBASE's for all processors
+#
+# Copyright (c) 2009 - 2015, 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
+#
+##
+
+
+ASM_GLOBAL ASM_PFX(gSmmCr0)
+ASM_GLOBAL ASM_PFX(gSmmCr3)
+ASM_GLOBAL ASM_PFX(gSmmCr4)
+ASM_GLOBAL ASM_PFX(gcSmmInitTemplate)
+ASM_GLOBAL ASM_PFX(gcSmmInitSize)
+ASM_GLOBAL ASM_PFX(gSmmJmpAddr)
+ASM_GLOBAL ASM_PFX(SmmRelocationSemaphoreComplete)
+ASM_GLOBAL ASM_PFX(gSmmInitStack)
+
+ .data
+
+NullSeg: .quad 0
+DataSeg32:
+ .word -1 # LimitLow
+ .word 0 # BaseLow
+ .byte 0 # BaseMid
+ .byte 0x93
+ .byte 0xcf # LimitHigh
+ .byte 0 # BaseHigh
+CodeSeg32:
+ .word -1 # LimitLow
+ .word 0 # BaseLow
+ .byte 0 # BaseMid
+ .byte 0x9b
+ .byte 0xcf # LimitHigh
+ .byte 0 # BaseHigh
+.equ GDT_SIZE, . - NullSeg
+
+ .text
+
+GdtDesc:
+ .word GDT_SIZE
+ .long NullSeg
+
+SmmStartup:
+ .byte 0x66,0xb8
+ASM_PFX(gSmmCr3): .space 4
+ movl %eax, %cr3
+ .byte 0x67,0x66
+ lgdt %cs:(GdtDesc - SmmStartup)(%ebp)
+ .byte 0x66,0xb8
+ASM_PFX(gSmmCr4): .space 4
+ movl %eax, %cr4
+ .byte 0x66,0xb8
+ASM_PFX(gSmmCr0): .space 4
+ .byte 0xbf,8,0 # mov di, 8
+ movl %eax, %cr0
+ .byte 0x66,0xea # jmp far [ptr48]
+ASM_PFX(gSmmJmpAddr): .long Start32bit
+ .word 0x10
+Start32bit:
+ movl %edi,%ds
+ movl %edi,%es
+ movl %edi,%fs
+ movl %edi,%gs
+ movl %edi,%ss
+ .byte 0xbc # mov esp, imm32
+ASM_PFX(gSmmInitStack): .space 4
+ call ASM_PFX(SmmInitHandler)
+ rsm
+
+ASM_PFX(gcSmmInitTemplate):
+
+_SmmInitTemplate:
+ .byte 0x66
+ movl $SmmStartup, %ebp
+ .byte 0x66, 0x81, 0xed, 0, 0, 3, 0 # sub ebp, 0x30000
+ jmp *%bp # jmp ebp actually
+
+ASM_PFX(gcSmmInitSize): .word . - ASM_PFX(gcSmmInitTemplate)
+
+
+ASM_PFX(SmmRelocationSemaphoreComplete):
+ pushl %eax
+ movl ASM_PFX(mRebasedFlag), %eax
+ movb $1, (%eax)
+ popl %eax
+ jmp *ASM_PFX(mSmmRelocationOriginalAddress)
diff --git a/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/PiSmmCpuDxeSmm/Ia32/SmmInit.asm b/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/PiSmmCpuDxeSmm/Ia32/SmmInit.asm
new file mode 100644
index 0000000000..1eed4ba2bb
--- /dev/null
+++ b/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/PiSmmCpuDxeSmm/Ia32/SmmInit.asm
@@ -0,0 +1,104 @@
+;; @file
+; Functions for relocating SMBASE's for all processors
+;
+; Copyright (c) 2009 - 2015, 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.
+;
+;;
+
+ .686p
+ .xmm
+ .model flat,C
+
+SmmInitHandler PROTO C
+
+EXTERNDEF C gSmmCr0:DWORD
+EXTERNDEF C gSmmCr3:DWORD
+EXTERNDEF C gSmmCr4:DWORD
+EXTERNDEF C gcSmmInitTemplate:BYTE
+EXTERNDEF C gcSmmInitSize:WORD
+EXTERNDEF C gSmmJmpAddr:QWORD
+EXTERNDEF C mRebasedFlag:PTR BYTE
+EXTERNDEF C mSmmRelocationOriginalAddress:DWORD
+EXTERNDEF C gSmmInitStack:DWORD
+
+ .data
+
+NullSeg DQ 0 ; reserved by architecture
+DataSeg32 LABEL QWORD
+ DW -1 ; LimitLow
+ DW 0 ; BaseLow
+ DB 0 ; BaseMid
+ DB 93h
+ DB 0cfh ; LimitHigh
+ DB 0 ; BaseHigh
+CodeSeg32 LABEL QWORD
+ DW -1 ; LimitLow
+ DW 0 ; BaseLow
+ DB 0 ; BaseMid
+ DB 9bh
+ DB 0cfh ; LimitHigh
+ DB 0 ; BaseHigh
+GDT_SIZE = $ - offset NullSeg
+
+ .code
+
+GdtDesc LABEL FWORD
+ DW GDT_SIZE
+ DD offset NullSeg
+
+SmmStartup PROC
+ DB 66h, 0b8h
+gSmmCr3 DD ?
+ mov cr3, eax
+ DB 67h, 66h
+ lgdt fword ptr cs:[ebp + (offset GdtDesc - SmmStartup)]
+ DB 66h, 0b8h
+gSmmCr4 DD ?
+ mov cr4, eax
+ DB 66h, 0b8h
+gSmmCr0 DD ?
+ DB 0bfh, 8, 0 ; mov di, 8
+ mov cr0, eax
+ DB 66h, 0eah ; jmp far [ptr48]
+gSmmJmpAddr LABEL QWORD
+ DD @32bit
+ DW 10h
+@32bit:
+ mov ds, edi
+ mov es, edi
+ mov fs, edi
+ mov gs, edi
+ mov ss, edi
+ DB 0bch ; mov esp, imm32
+gSmmInitStack DD ?
+ call SmmInitHandler
+ rsm
+SmmStartup ENDP
+
+gcSmmInitTemplate LABEL BYTE
+
+_SmmInitTemplate PROC
+ DB 66h
+ mov ebp, SmmStartup
+ DB 66h, 81h, 0edh, 00h, 00h, 03h, 00 ; sub ebp, 30000h
+ jmp bp ; jmp ebp actually
+_SmmInitTemplate ENDP
+
+gcSmmInitSize DW $ - gcSmmInitTemplate
+
+SmmRelocationSemaphoreComplete PROC
+ push eax
+ mov eax, mRebasedFlag
+ mov byte ptr [eax], 1
+ pop eax
+ jmp [mSmmRelocationOriginalAddress]
+SmmRelocationSemaphoreComplete ENDP
+ END
diff --git a/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/PiSmmCpuDxeSmm/Ia32/SmmProfileArch.c b/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/PiSmmCpuDxeSmm/Ia32/SmmProfileArch.c
new file mode 100644
index 0000000000..fbca8c4afe
--- /dev/null
+++ b/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/PiSmmCpuDxeSmm/Ia32/SmmProfileArch.c
@@ -0,0 +1,66 @@
+/** @file
+ IA-32 processor specific functions to enable SMM profile.
+
+ Copyright (c) 2012 - 2015, 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 "PiSmmCpuDxeSmm.h"
+#include "SmmProfileInternal.h"
+
+/**
+ Create SMM page table for S3 path.
+
+**/
+VOID
+InitSmmS3Cr3 (
+ VOID
+ )
+{
+ mSmmS3ResumeState->SmmS3Cr3 = Gen4GPageTable (0);
+
+ return ;
+}
+
+/**
+ Allocate pages for creating 4KB-page based on 2MB-page when page fault happens.
+ 32-bit firmware does not need it.
+
+**/
+VOID
+InitPagesForPFHandler (
+ VOID
+ )
+{
+}
+
+/**
+ Update page table to map the memory correctly in order to make the instruction
+ which caused page fault execute successfully. And it also save the original page
+ table to be restored in single-step exception. 32-bit firmware does not need it.
+
+ @param PageTable PageTable Address.
+ @param PFAddress The memory address which caused page fault exception.
+ @param CpuIndex The index of the processor.
+ @param ErrorCode The Error code of exception.
+ @param IsValidPFAddress The flag indicates if SMM profile data need be added.
+
+**/
+VOID
+RestorePageTableAbove4G (
+ UINT64 *PageTable,
+ UINT64 PFAddress,
+ UINTN CpuIndex,
+ UINTN ErrorCode,
+ BOOLEAN *IsValidPFAddress
+ )
+{
+}
diff --git a/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/PiSmmCpuDxeSmm/Ia32/SmmProfileArch.h b/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/PiSmmCpuDxeSmm/Ia32/SmmProfileArch.h
new file mode 100644
index 0000000000..e41949563c
--- /dev/null
+++ b/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/PiSmmCpuDxeSmm/Ia32/SmmProfileArch.h
@@ -0,0 +1,98 @@
+/** @file
+ IA-32 processor specific header file.
+
+ Copyright (c) 2012 - 2015, 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 _SMM_PROFILE_ARCH_H_
+#define _SMM_PROFILE_ARCH_H_
+
+#pragma pack (1)
+
+typedef struct _MSR_DS_AREA_STRUCT {
+ UINT32 BTSBufferBase;
+ UINT32 BTSIndex;
+ UINT32 BTSAbsoluteMaximum;
+ UINT32 BTSInterruptThreshold;
+ UINT32 PEBSBufferBase;
+ UINT32 PEBSIndex;
+ UINT32 PEBSAbsoluteMaximum;
+ UINT32 PEBSInterruptThreshold;
+ UINT32 PEBSCounterReset[4];
+ UINT32 Reserved;
+} MSR_DS_AREA_STRUCT;
+
+typedef struct _BRANCH_TRACE_RECORD {
+ UINT32 LastBranchFrom;
+ UINT32 LastBranchTo;
+ UINT32 Rsvd0 : 4;
+ UINT32 BranchPredicted : 1;
+ UINT32 Rsvd1 : 27;
+} BRANCH_TRACE_RECORD;
+
+typedef struct _PEBS_RECORD {
+ UINT32 Eflags;
+ UINT32 LinearIP;
+ UINT32 Eax;
+ UINT32 Ebx;
+ UINT32 Ecx;
+ UINT32 Edx;
+ UINT32 Esi;
+ UINT32 Edi;
+ UINT32 Ebp;
+ UINT32 Esp;
+} PEBS_RECORD;
+
+#pragma pack ()
+
+#define PHYSICAL_ADDRESS_MASK ((1ull << 32) - SIZE_4KB)
+
+/**
+ Update page table to map the memory correctly in order to make the instruction
+ which caused page fault execute successfully. And it also save the original page
+ table to be restored in single-step exception. 32-bit firmware does not need it.
+
+ @param PageTable PageTable Address.
+ @param PFAddress The memory address which caused page fault exception.
+ @param CpuIndex The index of the processor.
+ @param ErrorCode The Error code of exception.
+ @param IsValidPFAddress The flag indicates if SMM profile data need be added.
+
+**/
+VOID
+RestorePageTableAbove4G (
+ UINT64 *PageTable,
+ UINT64 PFAddress,
+ UINTN CpuIndex,
+ UINTN ErrorCode,
+ BOOLEAN *IsValidPFAddress
+ );
+
+/**
+ Create SMM page table for S3 path.
+
+**/
+VOID
+InitSmmS3Cr3 (
+ VOID
+ );
+
+/**
+ Allocate pages for creating 4KB-page based on 2MB-page when page fault happens.
+
+**/
+VOID
+InitPagesForPFHandler (
+ VOID
+ );
+
+#endif // _SMM_PROFILE_ARCH_H_
diff --git a/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/PiSmmCpuDxeSmm/MpService.c b/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/PiSmmCpuDxeSmm/MpService.c
new file mode 100644
index 0000000000..76fd20dc1b
--- /dev/null
+++ b/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/PiSmmCpuDxeSmm/MpService.c
@@ -0,0 +1,1759 @@
+/** @file
+ SMM MP service inplementation
+
+ Copyright (c) 2009 - 2015, 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 "PiSmmCpuDxeSmm.h"
+
+//
+// Slots for all MTRR( FIXED MTRR + VARIABLE MTRR + MTRR_LIB_IA32_MTRR_DEF_TYPE)
+//
+UINT64 gSmiMtrrs[MTRR_NUMBER_OF_FIXED_MTRR + 2 * MTRR_NUMBER_OF_VARIABLE_MTRR + 1];
+UINT64 gPhyMask;
+SMM_DISPATCHER_MP_SYNC_DATA *mSmmMpSyncData = NULL;
+BOOLEAN mExceptionHandlerReady = FALSE;
+SPIN_LOCK mIdtTableLock;
+
+/**
+ Performs an atomic compare exchange operation to get semaphore.
+ The compare exchange operation must be performed using
+ MP safe mechanisms.
+
+ @param[in, out] Sem IN: 32-bit unsigned integer
+ OUT: original integer - 1
+ @return Orignal integer - 1
+
+**/
+UINT32
+WaitForSemaphore (
+ IN OUT volatile UINT32 *Sem
+ )
+{
+ UINT32 Value;
+
+ do {
+ Value = *Sem;
+ } while (Value == 0 ||
+ InterlockedCompareExchange32 (
+ (UINT32*)Sem,
+ Value,
+ Value - 1
+ ) != Value);
+ return Value - 1;
+}
+
+/**
+ Performs an atomic compare exchange operation to release semaphore.
+ The compare exchange operation must be performed using
+ MP safe mechanisms.
+
+ @param[in, out] Sem IN: 32-bit unsigned integer
+ OUT: original integer + 1
+ @return Orignal integer + 1
+
+**/
+UINT32
+ReleaseSemaphore (
+ IN OUT volatile UINT32 *Sem
+ )
+{
+ UINT32 Value;
+
+ do {
+ Value = *Sem;
+ } while (Value + 1 != 0 &&
+ InterlockedCompareExchange32 (
+ (UINT32*)Sem,
+ Value,
+ Value + 1
+ ) != Value);
+ return Value + 1;
+}
+
+/**
+ Performs an atomic compare exchange operation to lock semaphore.
+ The compare exchange operation must be performed using
+ MP safe mechanisms.
+
+ @param[in, out] Sem IN: 32-bit unsigned integer
+ OUT: -1
+ @return Orignal integer
+
+**/
+UINT32
+LockdownSemaphore (
+ IN OUT volatile UINT32 *Sem
+ )
+{
+ UINT32 Value;
+
+ do {
+ Value = *Sem;
+ } while (InterlockedCompareExchange32 (
+ (UINT32*)Sem,
+ Value, (UINT32)-1
+ ) != Value);
+ return Value;
+}
+
+/**
+ Wait all APs to performs an atomic compare exchange operation to release semaphore.
+
+ @param[in] NumberOfAPs AP number
+
+**/
+VOID
+WaitForAllAPs (
+ IN UINTN NumberOfAPs
+ )
+{
+ UINTN BspIndex;
+
+ BspIndex = mSmmMpSyncData->BspIndex;
+ while (NumberOfAPs-- > 0) {
+ WaitForSemaphore (&mSmmMpSyncData->CpuData[BspIndex].Run);
+ }
+}
+
+/**
+ Performs an atomic compare exchange operation to release semaphore
+ for each AP.
+
+**/
+VOID
+ReleaseAllAPs (
+ VOID
+ )
+{
+ UINTN Index;
+ UINTN BspIndex;
+
+ BspIndex = mSmmMpSyncData->BspIndex;
+ for (Index = mMaxNumberOfCpus; Index-- > 0;) {
+ if (Index != BspIndex && mSmmMpSyncData->CpuData[Index].Present) {
+ ReleaseSemaphore (&mSmmMpSyncData->CpuData[Index].Run);
+ }
+ }
+}
+
+/**
+ Checks if all CPUs (with certain exceptions) have checked in for this SMI run
+
+ NOTE: for Haswell's exceptions checking, only single-socket CPU is supported
+
+ @param Exceptions CPU Arrival exception flags.
+
+ @retval TRUE if all CPUs the have checked in.
+ @retval FALSE if at least one Normal AP hasn't checked in.
+
+**/
+BOOLEAN
+AllCpusInSmmWithExceptions (
+ SMM_CPU_ARRIVAL_EXCEPTIONS Exceptions
+ )
+{
+ UINTN Index;
+ SMM_CPU_SYNC_FEATURE *SyncFeature;
+ SMM_CPU_SYNC_FEATURE *SmmSyncFeatures;
+ UINT64 LogProcEnBit;
+ SMM_CPU_DATA_BLOCK *CpuData;
+ EFI_PROCESSOR_INFORMATION *ProcessorInfo;
+
+ ASSERT (mSmmMpSyncData->Counter <= mNumberOfCpus);
+
+ if (mSmmMpSyncData->Counter == mNumberOfCpus) {
+ return TRUE;
+ }
+
+ CpuData = mSmmMpSyncData->CpuData;
+ ProcessorInfo = gSmmCpuPrivate->ProcessorInfo;
+ SmmSyncFeatures = gSmmCpuPrivate->SmmSyncFeature;
+ for (Index = mMaxNumberOfCpus; Index-- > 0;) {
+ if (!CpuData[Index].Present && ProcessorInfo[Index].ProcessorId != INVALID_APIC_ID) {
+ SyncFeature = &(SmmSyncFeatures[Index]);
+ LogProcEnBit = SyncFeature->HaswellLogProcEnBit;
+ if (((Exceptions & ARRIVAL_EXCEPTION_DELAYED) != 0) && SyncFeature->DelayIndicationSupported && (SmmReadReg64 (Index, SmmRegSmmDelayed) & LogProcEnBit)) {
+ continue;
+ }
+ if (((Exceptions & ARRIVAL_EXCEPTION_BLOCKED) != 0) && SyncFeature->BlockIndicationSupported && (SmmReadReg64 (Index, SmmRegSmmBlocked) & LogProcEnBit)) {
+ continue;
+ }
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+}
+
+/**
+ Given timeout constraint, wait for all APs to arrive, and insure when this function returns, no AP will execute normal mode code before
+ entering SMM, except SMI disabled APs.
+
+**/
+VOID
+SmmWaitForApArrival (
+ VOID
+ )
+{
+ UINT64 Timer;
+ UINTN Index;
+
+ ASSERT (mSmmMpSyncData->Counter <= mNumberOfCpus);
+
+ //
+ // Platform implementor should choose a timeout value appropriately:
+ // - The timeout value should balance the SMM time constrains and the likelihood that delayed CPUs are excluded in the SMM run. Note
+ // the SMI Handlers must ALWAYS take into account the cases that not all APs are available in an SMI run.
+ // - The timeout value must, in the case of 2nd timeout, be at least long enough to give time for all APs to receive the SMI IPI
+ // and either enter SMM or buffer the SMI, to insure there is no CPU running normal mode code when SMI handling starts. This will
+ // be TRUE even if a blocked CPU is brought out of the blocked state by a normal mode CPU (before the normal mode CPU received the
+ // SMI IPI), because with a buffered SMI, and CPU will enter SMM immediately after it is brought out of the blocked state.
+ // - The timeout value must be longer than longest possible IO operation in the system
+ // (BTW, ** to confirm **, Is Slow I/O operation reported as an SMM Delayed status in Haswell?)
+ //
+
+ //
+ // Sync with APs 1st timeout
+ //
+ for (Timer = StartSyncTimer ();
+ !IsSyncTimerTimeout (Timer) &&
+ !AllCpusInSmmWithExceptions (ARRIVAL_EXCEPTION_BLOCKED | ARRIVAL_EXCEPTION_SMI_DISABLED );
+ ) {
+ CpuPause ();
+ }
+
+ //
+ // Not all APs have arrived, so we need 2nd round of timeout. IPIs should be sent to ALL none present APs,
+ // because:
+ // a) Delayed AP may have just come out of the delayed state. Blocked AP may have just been brought out of blocked state by some AP running
+ // normal mode code. These APs need to be guaranteed to have an SMI pending to insure that once they are out of delayed / blocked state, they
+ // enter SMI immediately without executing instructions in normal mode. Note traditional flow requires there are no APs doing normal mode
+ // work while SMI handling is on-going.
+ // b) As a consequence of SMI IPI sending, (spurious) SMI may occur after this SMM run.
+ // c) ** NOTE **: Use SMI disabling feature VERY CAREFULLY (if at all) for traditional flow, because a processor in SMI-disabled state
+ // will execute normal mode code, which breaks the traditional SMI handlers' assumption that no APs are doing normal
+ // mode work while SMI handling is on-going.
+ // d) We don't add code to check SMI disabling status to skip sending IPI to SMI disabled APs, because:
+ // - In traditional flow, SMI disabling is discouraged.
+ // - In relaxed flow, CheckApArrival() will check SMI disabling status before calling this function.
+ // In both cases, adding SMI-disabling checking code increases overhead.
+ //
+ if (mSmmMpSyncData->Counter < mNumberOfCpus) {
+ //
+ // Send SMI IPIs to bring outside processors in
+ //
+ for (Index = mMaxNumberOfCpus; Index-- > 0;) {
+ if (!mSmmMpSyncData->CpuData[Index].Present && gSmmCpuPrivate->ProcessorInfo[Index].ProcessorId != INVALID_APIC_ID) {
+ SendSmiIpi ((UINT32)gSmmCpuPrivate->ProcessorInfo[Index].ProcessorId);
+ }
+ }
+
+ //
+ // Sync with APs 2nd timeout.
+ //
+ for (Timer = StartSyncTimer ();
+ !IsSyncTimerTimeout (Timer) &&
+ !AllCpusInSmmWithExceptions (ARRIVAL_EXCEPTION_BLOCKED | ARRIVAL_EXCEPTION_SMI_DISABLED );
+ ) {
+ CpuPause ();
+ }
+ }
+
+ return;
+}
+
+/**
+ Replace OS MTRR's with SMI MTRR's.
+
+ @param[in] CpuIndex Processor Index
+
+**/
+VOID
+ReplaceOSMtrrs (
+ IN UINTN CpuIndex
+ )
+{
+ PROCESSOR_SMM_DESCRIPTOR *Psd;
+ UINT64 *SmiMtrrs;
+ MTRR_SETTINGS *BiosMtrr;
+
+ Psd = (PROCESSOR_SMM_DESCRIPTOR*)(mCpuHotPlugData.SmBase[CpuIndex] + SMM_PSD_OFFSET);
+ SmiMtrrs = (UINT64*)(UINTN)Psd->MtrrBaseMaskPtr;
+
+ //
+ // Replace all MTRRs registers
+ //
+ BiosMtrr = (MTRR_SETTINGS*)SmiMtrrs;
+ MtrrSetAllMtrrs(BiosMtrr);
+}
+
+/**
+ SMI handler for BSP.
+
+ @param[in] CpuIndex BSP processor Index
+ @param[in] SyncMode SMM MP sync mode
+
+**/
+VOID
+BSPHandler (
+ IN UINTN CpuIndex,
+ IN SMM_CPU_SYNC_MODE SyncMode
+ )
+{
+ UINTN Index;
+ MTRR_SETTINGS Mtrrs;
+ UINTN ApCount;
+ BOOLEAN ClearTopLevelSmiResult;
+ UINTN PresentCount;
+
+ ASSERT (CpuIndex == mSmmMpSyncData->BspIndex);
+ ApCount = 0;
+
+ //
+ // Flag BSP's presence
+ //
+ mSmmMpSyncData->InsideSmm = TRUE;
+
+ //
+ // Initialize Debug Agent to start source level debug in BSP handler
+ //
+ InitializeDebugAgent (DEBUG_AGENT_INIT_ENTER_SMI, NULL, NULL);
+
+ //
+ // Mark this processor's presence
+ //
+ mSmmMpSyncData->CpuData[CpuIndex].Present = TRUE;
+
+ //
+ // Clear platform top level SMI status bit before calling SMI handlers. If
+ // we cleared it after SMI handlers are run, we would miss the SMI that
+ // occurs after SMI handlers are done and before SMI status bit is cleared.
+ //
+ ClearTopLevelSmiResult = ClearTopLevelSmiStatus();
+ ASSERT (ClearTopLevelSmiResult == TRUE);
+
+ //
+ // Set running processor index
+ //
+ gSmmCpuPrivate->SmmCoreEntryContext.CurrentlyExecutingCpu = CpuIndex;
+
+ //
+ // If Traditional Sync Mode or need to configure MTRRs: gather all available APs.
+ // To-Do: make NeedConfigureMtrrs a PCD?
+ //
+ if (SyncMode == SmmCpuSyncModeTradition || NeedConfigureMtrrs()) {
+
+ //
+ // Wait for APs to arrive
+ //
+ SmmWaitForApArrival();
+
+ //
+ // Lock the counter down and retrieve the number of APs
+ //
+ mSmmMpSyncData->AllCpusInSync = TRUE;
+ ApCount = LockdownSemaphore (&mSmmMpSyncData->Counter) - 1;
+
+ //
+ // Wait for all APs to get ready for programming MTRRs
+ //
+ WaitForAllAPs (ApCount);
+
+ if (NeedConfigureMtrrs()) {
+ //
+ // Signal all APs it's time for backup MTRRs
+ //
+ ReleaseAllAPs ();
+
+ //
+ // WaitForSemaphore() may wait for ever if an AP happens to enter SMM at
+ // exactly this point. Please make sure PcdCpuSmmMaxSyncLoops has been set
+ // to a large enough value to avoid this situation.
+ // Note: For HT capable CPUs, threads within a core share the same set of MTRRs.
+ // We do the backup first and then set MTRR to avoid race condition for threads
+ // in the same core.
+ //
+ MtrrGetAllMtrrs(&Mtrrs);
+
+ //
+ // Wait for all APs to complete their MTRR saving
+ //
+ WaitForAllAPs (ApCount);
+
+ //
+ // Let all processors program SMM MTRRs together
+ //
+ ReleaseAllAPs ();
+
+ //
+ // WaitForSemaphore() may wait for ever if an AP happens to enter SMM at
+ // exactly this point. Please make sure PcdCpuSmmMaxSyncLoops has been set
+ // to a large enough value to avoid this situation.
+ //
+ ReplaceOSMtrrs (CpuIndex);
+
+ //
+ // Wait for all APs to complete their MTRR programming
+ //
+ WaitForAllAPs (ApCount);
+ }
+ }
+
+ //
+ // The BUSY lock is initialized to Acquired state
+ //
+ AcquireSpinLockOrFail (&mSmmMpSyncData->CpuData[CpuIndex].Busy);
+
+ //
+ // Special handlement for S3 boot path.
+ //
+ RestoreSmmConfigurationInS3 ();
+
+ //
+ // Invoke SMM Foundation EntryPoint with the processor information context.
+ //
+ gSmmCpuPrivate->SmmCoreEntry (&gSmmCpuPrivate->SmmCoreEntryContext);
+
+ //
+ // Make sure all APs have completed their pending none-block tasks
+ //
+ for (Index = mMaxNumberOfCpus; Index-- > 0;) {
+ if (Index != CpuIndex && mSmmMpSyncData->CpuData[Index].Present) {
+ AcquireSpinLock (&mSmmMpSyncData->CpuData[Index].Busy);
+ ReleaseSpinLock (&mSmmMpSyncData->CpuData[Index].Busy);;
+ }
+ }
+
+ //
+ // Perform the remaining tasks
+ //
+ PerformRemainingTasks ();
+
+ //
+ // Set the EOS bit before SMI resume.
+ //
+ // BUGBUG: The following is a chipset specific action from a CPU module.
+ //
+ ClearSmi();
+
+ //
+ // If Relaxed-AP Sync Mode: gather all available APs after BSP SMM handlers are done, and
+ // make those APs to exit SMI synchronously. APs which arrive later will be excluded and
+ // will run through freely.
+ //
+ if (SyncMode != SmmCpuSyncModeTradition && !NeedConfigureMtrrs()) {
+
+ //
+ // Lock the counter down and retrieve the number of APs
+ //
+ mSmmMpSyncData->AllCpusInSync = TRUE;
+ ApCount = LockdownSemaphore (&mSmmMpSyncData->Counter) - 1;
+ //
+ // Make sure all APs have their Present flag set
+ //
+ while (TRUE) {
+ PresentCount = 0;
+ for (Index = mMaxNumberOfCpus; Index-- > 0;) {
+ if (mSmmMpSyncData->CpuData[Index].Present) {
+ PresentCount ++;
+ }
+ }
+ if (PresentCount > ApCount) {
+ break;
+ }
+ }
+ }
+
+ //
+ // Notify all APs to exit
+ //
+ mSmmMpSyncData->InsideSmm = FALSE;
+ ReleaseAllAPs ();
+
+ //
+ // Wait for all APs to complete their pending tasks
+ //
+ WaitForAllAPs (ApCount);
+
+ //
+ // Set the effective Sync Mode for next SMI run.
+ // Note this setting must be performed in the window where no APs can check in.
+ //
+ mSmmMpSyncData->EffectiveSyncMode = mSmmMpSyncData->SyncModeToBeSet;
+
+ if (NeedConfigureMtrrs()) {
+ //
+ // Signal APs to restore MTRRs
+ //
+ ReleaseAllAPs ();
+
+ //
+ // Restore OS MTRRs
+ //
+ MtrrSetAllMtrrs(&Mtrrs);
+
+ //
+ // Wait for all APs to complete MTRR programming
+ //
+ WaitForAllAPs (ApCount);
+ }
+
+ //
+ // Stop source level debug in BSP handler, the code below will not be
+ // debugged.
+ //
+ InitializeDebugAgent (DEBUG_AGENT_INIT_EXIT_SMI, NULL, NULL);
+
+ //
+ // Signal APs to Reset states/semaphore for this processor
+ //
+ ReleaseAllAPs ();
+
+ //
+ // Perform pending operations for hot-plug
+ //
+ SmmCpuUpdate ();
+
+ //
+ // Clear the Present flag of BSP
+ //
+ mSmmMpSyncData->CpuData[CpuIndex].Present = FALSE;
+
+ //
+ // Gather APs to exit SMM synchronously. Note the Present flag is cleared by now but
+ // WaitForAllAps does not depend on the Present flag.
+ //
+ WaitForAllAPs (ApCount);
+
+ //
+ // Reset BspIndex to -1, meaning BSP has not been elected.
+ //
+ if (FeaturePcdGet (PcdCpuSmmEnableBspElection)) {
+ mSmmMpSyncData->BspIndex = (UINT32)-1;
+ }
+
+ //
+ // Allow APs to check in from this point on
+ //
+ mSmmMpSyncData->Counter = 0;
+ mSmmMpSyncData->AllCpusInSync = FALSE;
+}
+
+/**
+ SMI handler for AP.
+
+ @param[in] CpuIndex AP processor Index.
+ @param[in] ValidSmi Indicates that current SMI is a valid SMI or not.
+ @param[in] SyncMode SMM MP sync mode.
+
+**/
+VOID
+APHandler (
+ IN UINTN CpuIndex,
+ IN BOOLEAN ValidSmi,
+ IN SMM_CPU_SYNC_MODE SyncMode
+ )
+{
+ UINT64 Timer;
+ UINTN BspIndex;
+ MTRR_SETTINGS Mtrrs;
+
+ //
+ // Timeout BSP
+ //
+ for (Timer = StartSyncTimer ();
+ !IsSyncTimerTimeout (Timer) &&
+ !mSmmMpSyncData->InsideSmm;
+ ) {
+ CpuPause ();
+ }
+
+ if (!mSmmMpSyncData->InsideSmm) {
+ //
+ // BSP timeout in the first round
+ //
+ if (mSmmMpSyncData->BspIndex != -1) {
+ //
+ // BSP Index is known
+ //
+ BspIndex = mSmmMpSyncData->BspIndex;
+ ASSERT (CpuIndex != BspIndex);
+
+ //
+ // Send SMI IPI to bring BSP in
+ //
+ SendSmiIpi ((UINT32)gSmmCpuPrivate->ProcessorInfo[BspIndex].ProcessorId);
+
+ //
+ // Now clock BSP for the 2nd time
+ //
+ for (Timer = StartSyncTimer ();
+ !IsSyncTimerTimeout (Timer) &&
+ !mSmmMpSyncData->InsideSmm;
+ ) {
+ CpuPause ();
+ }
+
+ if (!mSmmMpSyncData->InsideSmm) {
+ //
+ // Give up since BSP is unable to enter SMM
+ // and signal the completion of this AP
+ WaitForSemaphore (&mSmmMpSyncData->Counter);
+ return;
+ }
+ } else {
+ //
+ // Don't know BSP index. Give up without sending IPI to BSP.
+ //
+ WaitForSemaphore (&mSmmMpSyncData->Counter);
+ return;
+ }
+ }
+
+ //
+ // BSP is available
+ //
+ BspIndex = mSmmMpSyncData->BspIndex;
+ ASSERT (CpuIndex != BspIndex);
+
+ //
+ // Mark this processor's presence
+ //
+ mSmmMpSyncData->CpuData[CpuIndex].Present = TRUE;
+
+ if (SyncMode == SmmCpuSyncModeTradition || NeedConfigureMtrrs()) {
+ //
+ // Notify BSP of arrival at this point
+ //
+ ReleaseSemaphore (&mSmmMpSyncData->CpuData[BspIndex].Run);
+ }
+
+ if (NeedConfigureMtrrs()) {
+ //
+ // Wait for the signal from BSP to backup MTRRs
+ //
+ WaitForSemaphore (&mSmmMpSyncData->CpuData[CpuIndex].Run);
+
+ //
+ // Backup OS MTRRs
+ //
+ MtrrGetAllMtrrs(&Mtrrs);
+
+ //
+ // Signal BSP the completion of this AP
+ //
+ ReleaseSemaphore (&mSmmMpSyncData->CpuData[BspIndex].Run);
+
+ //
+ // Wait for BSP's signal to program MTRRs
+ //
+ WaitForSemaphore (&mSmmMpSyncData->CpuData[CpuIndex].Run);
+
+ //
+ // Replace OS MTRRs with SMI MTRRs
+ //
+ ReplaceOSMtrrs (CpuIndex);
+
+ //
+ // Signal BSP the completion of this AP
+ //
+ ReleaseSemaphore (&mSmmMpSyncData->CpuData[BspIndex].Run);
+ }
+
+ while (TRUE) {
+ //
+ // Wait for something to happen
+ //
+ WaitForSemaphore (&mSmmMpSyncData->CpuData[CpuIndex].Run);
+
+ //
+ // Check if BSP wants to exit SMM
+ //
+ if (!mSmmMpSyncData->InsideSmm) {
+ break;
+ }
+
+ //
+ // BUSY should be acquired by SmmStartupThisAp()
+ //
+ ASSERT (
+ !AcquireSpinLockOrFail (&mSmmMpSyncData->CpuData[CpuIndex].Busy)
+ );
+
+ //
+ // Invoke the scheduled procedure
+ //
+ (*mSmmMpSyncData->CpuData[CpuIndex].Procedure) (
+ (VOID*)mSmmMpSyncData->CpuData[CpuIndex].Parameter
+ );
+
+ //
+ // Release BUSY
+ //
+ ReleaseSpinLock (&mSmmMpSyncData->CpuData[CpuIndex].Busy);
+ }
+
+ if (NeedConfigureMtrrs()) {
+ //
+ // Notify BSP the readiness of this AP to program MTRRs
+ //
+ ReleaseSemaphore (&mSmmMpSyncData->CpuData[BspIndex].Run);
+
+ //
+ // Wait for the signal from BSP to program MTRRs
+ //
+ WaitForSemaphore (&mSmmMpSyncData->CpuData[CpuIndex].Run);
+
+ //
+ // Restore OS MTRRs
+ //
+ MtrrSetAllMtrrs(&Mtrrs);
+ }
+
+ //
+ // Notify BSP the readiness of this AP to Reset states/semaphore for this processor
+ //
+ ReleaseSemaphore (&mSmmMpSyncData->CpuData[BspIndex].Run);
+
+ //
+ // Wait for the signal from BSP to Reset states/semaphore for this processor
+ //
+ WaitForSemaphore (&mSmmMpSyncData->CpuData[CpuIndex].Run);
+
+ //
+ // Reset states/semaphore for this processor
+ //
+ mSmmMpSyncData->CpuData[CpuIndex].Present = FALSE;
+
+ //
+ // Notify BSP the readiness of this AP to exit SMM
+ //
+ ReleaseSemaphore (&mSmmMpSyncData->CpuData[BspIndex].Run);
+
+}
+
+/**
+ Create 4G PageTable in SMRAM.
+
+ @param[in] ExtraPages Additional page numbers besides for 4G memory
+ @return PageTable Address
+
+**/
+UINT32
+Gen4GPageTable (
+ IN UINTN ExtraPages
+ )
+{
+ VOID *PageTable;
+ UINTN Index;
+ UINT64 *Pte;
+ UINTN PagesNeeded;
+ UINTN Low2MBoundary;
+ UINTN High2MBoundary;
+ UINTN Pages;
+ UINTN GuardPage;
+ UINT64 *Pdpte;
+ UINTN PageIndex;
+ UINTN PageAddress;
+
+ Low2MBoundary = 0;
+ High2MBoundary = 0;
+ PagesNeeded = 0;
+ if (FeaturePcdGet (PcdCpuSmmStackGuard)) {
+ //
+ // Add one more page for known good stack, then find the lower 2MB aligned address.
+ //
+ Low2MBoundary = (mSmmStackArrayBase + EFI_PAGE_SIZE) & ~(SIZE_2MB-1);
+ //
+ // Add two more pages for known good stack and stack guard page,
+ // then find the lower 2MB aligned address.
+ //
+ High2MBoundary = (mSmmStackArrayEnd - mSmmStackSize + EFI_PAGE_SIZE * 2) & ~(SIZE_2MB-1);
+ PagesNeeded = ((High2MBoundary - Low2MBoundary) / SIZE_2MB) + 1;
+ }
+ //
+ // Allocate the page table
+ //
+ PageTable = AllocatePages (ExtraPages + 5 + PagesNeeded);
+ ASSERT (PageTable != NULL);
+
+ PageTable = (VOID *)((UINTN)PageTable + EFI_PAGES_TO_SIZE (ExtraPages));
+ Pte = (UINT64*)PageTable;
+
+ //
+ // Zero out all page table entries first
+ //
+ ZeroMem (Pte, EFI_PAGES_TO_SIZE (1));
+
+ //
+ // Set Page Directory Pointers
+ //
+ for (Index = 0; Index < 4; Index++) {
+ Pte[Index] = (UINTN)PageTable + EFI_PAGE_SIZE * (Index + 1) + IA32_PG_P;
+ }
+ Pte += EFI_PAGE_SIZE / sizeof (*Pte);
+
+ //
+ // Fill in Page Directory Entries
+ //
+ for (Index = 0; Index < EFI_PAGE_SIZE * 4 / sizeof (*Pte); Index++) {
+ Pte[Index] = (Index << 21) + IA32_PG_PS + IA32_PG_RW + IA32_PG_P;
+ }
+
+ if (FeaturePcdGet (PcdCpuSmmStackGuard)) {
+ Pages = (UINTN)PageTable + EFI_PAGES_TO_SIZE (5);
+ GuardPage = mSmmStackArrayBase + EFI_PAGE_SIZE;
+ Pdpte = (UINT64*)PageTable;
+ for (PageIndex = Low2MBoundary; PageIndex <= High2MBoundary; PageIndex += SIZE_2MB) {
+ Pte = (UINT64*)(UINTN)(Pdpte[BitFieldRead32 ((UINT32)PageIndex, 30, 31)] & ~(EFI_PAGE_SIZE - 1));
+ Pte[BitFieldRead32 ((UINT32)PageIndex, 21, 29)] = (UINT64)Pages + IA32_PG_RW + IA32_PG_P;
+ //
+ // Fill in Page Table Entries
+ //
+ Pte = (UINT64*)Pages;
+ PageAddress = PageIndex;
+ for (Index = 0; Index < EFI_PAGE_SIZE / sizeof (*Pte); Index++) {
+ if (PageAddress == GuardPage) {
+ //
+ // Mark the guard page as non-present
+ //
+ Pte[Index] = PageAddress;
+ GuardPage += mSmmStackSize;
+ if (GuardPage > mSmmStackArrayEnd) {
+ GuardPage = 0;
+ }
+ } else {
+ Pte[Index] = PageAddress + IA32_PG_RW + IA32_PG_P;
+ }
+ PageAddress+= EFI_PAGE_SIZE;
+ }
+ Pages += EFI_PAGE_SIZE;
+ }
+ }
+
+ return (UINT32)(UINTN)PageTable;
+}
+
+/**
+ Set memory cache ability.
+
+ @param[in] PageTable PageTable Address
+ @param[in] Address Memory Address to change cache ability
+ @param[in] Cacheability Cache ability to set
+
+**/
+VOID
+SetCacheability (
+ IN UINT64 *PageTable,
+ IN UINTN Address,
+ IN UINT8 Cacheability
+ )
+{
+ UINTN PTIndex;
+ VOID *NewPageTableAddress;
+ UINT64 *NewPageTable;
+ UINTN Index;
+
+ ASSERT ((Address & EFI_PAGE_MASK) == 0);
+
+ if (sizeof (UINTN) == sizeof (UINT64)) {
+ PTIndex = (UINTN)RShiftU64 (Address, 39) & 0x1ff;
+ ASSERT (PageTable[PTIndex] & IA32_PG_P);
+ PageTable = (UINT64*)(UINTN)(PageTable[PTIndex] & gPhyMask);
+ }
+
+ PTIndex = (UINTN)RShiftU64 (Address, 30) & 0x1ff;
+ ASSERT (PageTable[PTIndex] & IA32_PG_P);
+ PageTable = (UINT64*)(UINTN)(PageTable[PTIndex] & gPhyMask);
+
+ //
+ // A perfect implementation should check the original cacheability with the
+ // one being set, and break a 2M page entry into pieces only when they
+ // disagreed.
+ //
+ PTIndex = (UINTN)RShiftU64 (Address, 21) & 0x1ff;
+ if ((PageTable[PTIndex] & IA32_PG_PS) != 0) {
+ //
+ // Allocate a page from SMRAM
+ //
+ NewPageTableAddress = AllocatePages (1);
+ ASSERT (NewPageTableAddress != NULL);
+
+ NewPageTable = (UINT64 *)NewPageTableAddress;
+
+ for (Index = 0; Index < 0x200; Index++) {
+ NewPageTable[Index] = PageTable[PTIndex];
+ if ((NewPageTable[Index] & IA32_PG_PAT_2M) != 0) {
+ NewPageTable[Index] &= ~IA32_PG_PAT_2M;
+ NewPageTable[Index] |= IA32_PG_PAT_4K;
+ }
+ NewPageTable[Index] |= Index << EFI_PAGE_SHIFT;
+ }
+
+ PageTable[PTIndex] = ((UINTN)NewPageTableAddress & gPhyMask) | IA32_PG_P;
+ }
+
+ ASSERT (PageTable[PTIndex] & IA32_PG_P);
+ PageTable = (UINT64*)(UINTN)(PageTable[PTIndex] & gPhyMask);
+
+ PTIndex = (UINTN)RShiftU64 (Address, 12) & 0x1ff;
+ ASSERT (PageTable[PTIndex] & IA32_PG_P);
+ PageTable[PTIndex] &= ~(IA32_PG_PAT_4K | IA32_PG_CD | IA32_PG_WT);
+ PageTable[PTIndex] |= Cacheability;
+}
+
+/**
+ Schedule a procedure to run on the specified CPU.
+
+ @param[in] Procedure The address of the procedure to run
+ @param[in] CpuIndex Target CPU Index
+ @param[in, out] ProcArguments The parameter to pass to the procedure
+
+ @retval EFI_INVALID_PARAMETER CpuNumber not valid
+ @retval EFI_INVALID_PARAMETER CpuNumber specifying BSP
+ @retval EFI_INVALID_PARAMETER The AP specified by CpuNumber did not enter SMM
+ @retval EFI_INVALID_PARAMETER The AP specified by CpuNumber is busy
+ @retval EFI_SUCCESS The procedure has been successfully scheduled
+
+**/
+EFI_STATUS
+EFIAPI
+SmmStartupThisAp (
+ IN EFI_AP_PROCEDURE Procedure,
+ IN UINTN CpuIndex,
+ IN OUT VOID *ProcArguments OPTIONAL
+ )
+{
+ if (CpuIndex >= gSmmCpuPrivate->SmmCoreEntryContext.NumberOfCpus ||
+ CpuIndex == gSmmCpuPrivate->SmmCoreEntryContext.CurrentlyExecutingCpu ||
+ !mSmmMpSyncData->CpuData[CpuIndex].Present ||
+ gSmmCpuPrivate->Operation[CpuIndex] == SmmCpuRemove ||
+ !AcquireSpinLockOrFail (&mSmmMpSyncData->CpuData[CpuIndex].Busy)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ mSmmMpSyncData->CpuData[CpuIndex].Procedure = Procedure;
+ mSmmMpSyncData->CpuData[CpuIndex].Parameter = ProcArguments;
+ ReleaseSemaphore (&mSmmMpSyncData->CpuData[CpuIndex].Run);
+
+ if (FeaturePcdGet (PcdCpuSmmBlockStartupThisAp)) {
+ AcquireSpinLock (&mSmmMpSyncData->CpuData[CpuIndex].Busy);
+ ReleaseSpinLock (&mSmmMpSyncData->CpuData[CpuIndex].Busy);
+ }
+ return EFI_SUCCESS;
+}
+
+/**
+ Schedule a procedure to run on the specified CPU in a blocking fashion.
+
+ @param[in] Procedure The address of the procedure to run
+ @param[in] CpuIndex Target CPU Index
+ @param[in, out] ProcArguments The parameter to pass to the procedure
+
+ @retval EFI_INVALID_PARAMETER CpuNumber not valid
+ @retval EFI_INVALID_PARAMETER CpuNumber specifying BSP
+ @retval EFI_INVALID_PARAMETER The AP specified by CpuNumber did not enter SMM
+ @retval EFI_INVALID_PARAMETER The AP specified by CpuNumber is busy
+ @retval EFI_SUCCESS The procedure has been successfully scheduled
+
+**/
+EFI_STATUS
+EFIAPI
+SmmBlockingStartupThisAp (
+ IN EFI_AP_PROCEDURE Procedure,
+ IN UINTN CpuIndex,
+ IN OUT VOID *ProcArguments OPTIONAL
+ )
+{
+ if (CpuIndex >= gSmmCpuPrivate->SmmCoreEntryContext.NumberOfCpus ||
+ CpuIndex == gSmmCpuPrivate->SmmCoreEntryContext.CurrentlyExecutingCpu ||
+ !mSmmMpSyncData->CpuData[CpuIndex].Present ||
+ gSmmCpuPrivate->Operation[CpuIndex] == SmmCpuRemove ||
+ !AcquireSpinLockOrFail (&mSmmMpSyncData->CpuData[CpuIndex].Busy)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ mSmmMpSyncData->CpuData[CpuIndex].Procedure = Procedure;
+ mSmmMpSyncData->CpuData[CpuIndex].Parameter = ProcArguments;
+ ReleaseSemaphore (&mSmmMpSyncData->CpuData[CpuIndex].Run);
+
+ AcquireSpinLock (&mSmmMpSyncData->CpuData[CpuIndex].Busy);
+ ReleaseSpinLock (&mSmmMpSyncData->CpuData[CpuIndex].Busy);
+ return EFI_SUCCESS;
+}
+
+/**
+ C function for SMI entry, each processor comes here upon SMI trigger.
+
+ @param[in] CpuIndex Cpu Index
+
+**/
+VOID
+EFIAPI
+SmiRendezvous (
+ IN UINTN CpuIndex
+ )
+{
+ EFI_STATUS Status;
+ BOOLEAN ValidSmi;
+ BOOLEAN IsBsp;
+ BOOLEAN BspInProgress;
+ UINTN Index;
+ UINTN Cr2;
+
+ //
+ // Save Cr2 because Page Fault exception in SMM may override its value
+ //
+ Cr2 = AsmReadCr2 ();
+
+ //
+ // Enable exception table by load IDTR
+ //
+ AsmWriteIdtr (&gcSmiIdtr);
+ if (!mExceptionHandlerReady) {
+ //
+ // If the default CPU exception handlers were not ready
+ //
+ AcquireSpinLock (&mIdtTableLock);
+ if (!mExceptionHandlerReady) {
+ //
+ // Update the IDT entry to handle Page Fault exception
+ //
+ CopyMem (
+ ((IA32_IDT_GATE_DESCRIPTOR *) (gcSmiIdtr.Base + sizeof (IA32_IDT_GATE_DESCRIPTOR) * 14)),
+ &gSavedPageFaultIdtEntry,
+ sizeof (IA32_IDT_GATE_DESCRIPTOR));
+ //
+ // Update the IDT entry to handle debug exception library for smm profile
+ //
+ if (FeaturePcdGet (PcdCpuSmmProfileEnable)) {
+ CopyMem (
+ ((IA32_IDT_GATE_DESCRIPTOR *) (gcSmiIdtr.Base + sizeof (IA32_IDT_GATE_DESCRIPTOR) * 1)),
+ &gSavedDebugExceptionIdtEntry,
+ sizeof (IA32_IDT_GATE_DESCRIPTOR));
+ }
+ //
+ // Set CPU exception handlers ready flag
+ //
+ mExceptionHandlerReady = TRUE;
+ }
+ ReleaseSpinLock (&mIdtTableLock);
+ }
+
+ //
+ // Enable XMM instructions & exceptions
+ //
+ AsmWriteCr4 (AsmReadCr4 () | 0x600);
+
+ //
+ // Perform CPU specific entry hooks
+ //
+ SmmRendezvousEntry (CpuIndex);
+
+ //
+ // Determine if this is a valid Smi
+ //
+ ValidSmi = PlatformValidSmi();
+
+ //
+ // Determine if BSP has been already in progress. Note this must be checked after
+ // ValidSmi because BSP may clear a valid SMI source after checking in.
+ //
+ BspInProgress = mSmmMpSyncData->InsideSmm;
+
+ if (!BspInProgress && !ValidSmi) {
+ //
+ // If we reach here, it means when we sampled the ValidSmi flag, SMI status had not
+ // been cleared by BSP in a new SMI run (so we have a truly invalid SMI), or SMI
+ // status had been cleared by BSP and an existing SMI run has almost ended. (Note
+ // we sampled ValidSmi flag BEFORE judging BSP-in-progress status.) In both cases, there
+ // is nothing we need to do.
+ //
+ goto Exit;
+ } else {
+ //
+ // Signal presence of this processor
+ //
+ if (ReleaseSemaphore (&mSmmMpSyncData->Counter) == 0) {
+ //
+ // BSP has already ended the synchronization, so QUIT!!!
+ //
+
+ //
+ // Wait for BSP's signal to finish SMI
+ //
+ while (mSmmMpSyncData->AllCpusInSync) {
+ CpuPause ();
+ }
+ goto Exit;
+ } else {
+
+ //
+ // The BUSY lock is initialized to Released state.
+ // This needs to be done early enough to be ready for BSP's SmmStartupThisAp() call.
+ // E.g., with Relaxed AP flow, SmmStartupThisAp() may be called immediately
+ // after AP's present flag is detected.
+ //
+ InitializeSpinLock (&mSmmMpSyncData->CpuData[CpuIndex].Busy);
+ }
+
+ if (FeaturePcdGet (PcdCpuSmmProfileEnable)) {
+ ActivateSmmProfile (CpuIndex);
+ }
+
+ if (BspInProgress) {
+ //
+ // BSP has been elected. Follow AP path, regardless of ValidSmi flag
+ // as BSP may have cleared the SMI status
+ //
+ APHandler (CpuIndex, ValidSmi, mSmmMpSyncData->EffectiveSyncMode);
+ } else {
+ //
+ // We have a valid SMI
+ //
+
+ //
+ // Elect BSP
+ //
+ IsBsp = FALSE;
+ if (FeaturePcdGet (PcdCpuSmmEnableBspElection)) {
+ if (!mSmmMpSyncData->SwitchBsp || mSmmMpSyncData->CandidateBsp[CpuIndex]) {
+ //
+ // Call platform hook to do BSP election
+ //
+ Status = PlatformSmmBspElection (&IsBsp);
+ if (EFI_SUCCESS == Status) {
+ //
+ // Platform hook determines successfully
+ //
+ if (IsBsp) {
+ mSmmMpSyncData->BspIndex = (UINT32)CpuIndex;
+ }
+ } else {
+ //
+ // Platform hook fails to determine, use default BSP election method
+ //
+ InterlockedCompareExchange32 (
+ (UINT32*)&mSmmMpSyncData->BspIndex,
+ (UINT32)-1,
+ (UINT32)CpuIndex
+ );
+ }
+ }
+ }
+
+ //
+ // "mSmmMpSyncData->BspIndex == CpuIndex" means this is the BSP
+ //
+ if (mSmmMpSyncData->BspIndex == CpuIndex) {
+
+ //
+ // Clear last request for SwitchBsp.
+ //
+ if (mSmmMpSyncData->SwitchBsp) {
+ mSmmMpSyncData->SwitchBsp = FALSE;
+ for (Index = 0; Index < mMaxNumberOfCpus; Index++) {
+ mSmmMpSyncData->CandidateBsp[Index] = FALSE;
+ }
+ }
+
+ if (FeaturePcdGet (PcdCpuSmmProfileEnable)) {
+ SmmProfileRecordSmiNum ();
+ }
+
+ //
+ // BSP Handler is always called with a ValidSmi == TRUE
+ //
+ BSPHandler (CpuIndex, mSmmMpSyncData->EffectiveSyncMode);
+
+ } else {
+ APHandler (CpuIndex, ValidSmi, mSmmMpSyncData->EffectiveSyncMode);
+ }
+ }
+
+ ASSERT (mSmmMpSyncData->CpuData[CpuIndex].Run == 0);
+
+ //
+ // Wait for BSP's signal to exit SMI
+ //
+ while (mSmmMpSyncData->AllCpusInSync) {
+ CpuPause ();
+ }
+ }
+
+Exit:
+ SmmRendezvousExit (CpuIndex);
+ //
+ // Restore Cr2
+ //
+ AsmWriteCr2 (Cr2);
+}
+
+/**
+ Initialize un-cacheable data.
+
+**/
+VOID
+EFIAPI
+InitializeMpSyncData (
+ VOID
+ )
+{
+ if (mSmmMpSyncData != NULL) {
+ ZeroMem (mSmmMpSyncData, sizeof (*mSmmMpSyncData));
+ if (FeaturePcdGet (PcdCpuSmmEnableBspElection)) {
+ //
+ // Enable BSP election by setting BspIndex to -1
+ //
+ mSmmMpSyncData->BspIndex = (UINT32)-1;
+ }
+ mSmmMpSyncData->SyncModeToBeSet = SmmCpuSyncModeTradition;
+ mSmmMpSyncData->EffectiveSyncMode = SmmCpuSyncModeTradition;
+ }
+}
+
+/**
+ Initialize global data for MP synchronization.
+
+ @param[in] ImageHandle File Image Handle.
+ @param[in] Stacks Base address of SMI stack buffer for all processors.
+ @param[in] StackSize Stack size for each processor in SMM.
+
+**/
+VOID
+InitializeMpServiceData (
+ IN EFI_HANDLE ImageHandle,
+ IN VOID *Stacks,
+ IN UINTN StackSize
+ )
+{
+ UINTN Index;
+ MTRR_SETTINGS *Mtrr;
+ PROCESSOR_SMM_DESCRIPTOR *Psd;
+ UINTN GdtTssTableSize;
+ UINT8 *GdtTssTables;
+ IA32_SEGMENT_DESCRIPTOR *GdtDescriptor;
+ UINTN TssBase;
+
+ //
+ // Initialize physical address mask
+ // NOTE: Physical memory above virtual address limit is not supported !!!
+ //
+ AsmCpuid (0x80000008, (UINT32*)&Index, NULL, NULL, NULL);
+ gPhyMask = LShiftU64 (1, (UINT8)Index) - 1;
+ gPhyMask &= (1ull << 48) - EFI_PAGE_SIZE;
+
+ InitializeSmmMtrrManager ();
+ //
+ // Create page tables
+ //
+ gSmiCr3 = SmmInitPageTable ();
+
+ //
+ // Initialize spin lock for setting up CPU exception handler
+ //
+ InitializeSpinLock (&mIdtTableLock);
+
+ //
+ // Initialize SMM startup code & PROCESSOR_SMM_DESCRIPTOR structures
+ //
+ gSmiStack = (UINTN)Stacks + StackSize - sizeof (UINTN);
+
+ //
+ // The Smi Handler of CPU[i] and PSD of CPU[i+x] are in the same SMM_CPU_INTERVAL,
+ // and they cannot overlap.
+ //
+ ASSERT (gcSmiHandlerSize + 0x10000 - SMM_PSD_OFFSET < SMM_CPU_INTERVAL);
+ ASSERT (SMM_HANDLER_OFFSET % SMM_CPU_INTERVAL == 0);
+
+ GdtTssTables = NULL;
+ GdtTssTableSize = 0;
+ //
+ // For X64 SMM, we allocate separate GDT/TSS for each CPUs to avoid TSS load contention
+ // on each SMI entry.
+ //
+ if (EFI_IMAGE_MACHINE_TYPE_SUPPORTED(EFI_IMAGE_MACHINE_X64)) {
+ GdtTssTableSize = (gcSmiGdtr.Limit + 1 + TSS_SIZE + 7) & ~7; // 8 bytes aligned
+ GdtTssTables = (UINT8*)AllocatePages (EFI_SIZE_TO_PAGES (GdtTssTableSize * gSmmCpuPrivate->SmmCoreEntryContext.NumberOfCpus));
+ ASSERT (GdtTssTables != NULL);
+
+ for (Index = 0; Index < gSmmCpuPrivate->SmmCoreEntryContext.NumberOfCpus; Index++) {
+ CopyMem (GdtTssTables + GdtTssTableSize * Index, (VOID*)(UINTN)gcSmiGdtr.Base, gcSmiGdtr.Limit + 1 + TSS_SIZE);
+ if (FeaturePcdGet (PcdCpuSmmStackGuard)) {
+ //
+ // Setup top of known good stack as IST1 for each processor.
+ //
+ *(UINTN *)(GdtTssTables + GdtTssTableSize * Index + gcSmiGdtr.Limit + 1 + TSS_X64_IST1_OFFSET) = (mSmmStackArrayBase + EFI_PAGE_SIZE + Index * mSmmStackSize);
+ }
+ }
+ } else if (FeaturePcdGet (PcdCpuSmmStackGuard)) {
+
+ //
+ // For IA32 SMM, if SMM Stack Guard feature is enabled, we use 2 TSS.
+ // in this case, we allocate separate GDT/TSS for each CPUs to avoid TSS load contention
+ // on each SMI entry.
+ //
+
+ //
+ // Enlarge GDT to contain 2 TSS descriptors
+ //
+ gcSmiGdtr.Limit += (UINT16)(2 * sizeof (IA32_SEGMENT_DESCRIPTOR));
+
+ GdtTssTableSize = (gcSmiGdtr.Limit + 1 + TSS_SIZE * 2 + 7) & ~7; // 8 bytes aligned
+ GdtTssTables = (UINT8*)AllocatePages (EFI_SIZE_TO_PAGES (GdtTssTableSize * gSmmCpuPrivate->SmmCoreEntryContext.NumberOfCpus));
+ ASSERT (GdtTssTables != NULL);
+
+ for (Index = 0; Index < gSmmCpuPrivate->SmmCoreEntryContext.NumberOfCpus; Index++) {
+ CopyMem (GdtTssTables + GdtTssTableSize * Index, (VOID*)(UINTN)gcSmiGdtr.Base, gcSmiGdtr.Limit + 1 + TSS_SIZE * 2);
+ //
+ // Fixup TSS descriptors
+ //
+ TssBase = (UINTN)(GdtTssTables + GdtTssTableSize * Index + gcSmiGdtr.Limit + 1);
+ GdtDescriptor = (IA32_SEGMENT_DESCRIPTOR *)(TssBase) - 2;
+ GdtDescriptor->Bits.BaseLow = (UINT16)TssBase;
+ GdtDescriptor->Bits.BaseMid = (UINT8)(TssBase >> 16);
+ GdtDescriptor->Bits.BaseHigh = (UINT8)(TssBase >> 24);
+
+ TssBase += TSS_SIZE;
+ GdtDescriptor++;
+ GdtDescriptor->Bits.BaseLow = (UINT16)TssBase;
+ GdtDescriptor->Bits.BaseMid = (UINT8)(TssBase >> 16);
+ GdtDescriptor->Bits.BaseHigh = (UINT8)(TssBase >> 24);
+ //
+ // Fixup TSS segments
+ //
+ // ESP as known good stack
+ //
+ *(UINTN *)(TssBase + TSS_IA32_ESP_OFFSET) = mSmmStackArrayBase + EFI_PAGE_SIZE + Index * mSmmStackSize;
+ *(UINT32 *)(TssBase + TSS_IA32_CR3_OFFSET) = gSmiCr3;
+ }
+ }
+
+ for (Index = 0; Index < mMaxNumberOfCpus; Index++) {
+ *(UINTN*)gSmiStack = Index;
+ gSmbase = (UINT32)mCpuHotPlugData.SmBase[Index];
+ CopyMem (
+ (VOID*)(UINTN)(mCpuHotPlugData.SmBase[Index] + SMM_HANDLER_OFFSET),
+ (VOID*)gcSmiHandlerTemplate,
+ gcSmiHandlerSize
+ );
+
+ Psd = (PROCESSOR_SMM_DESCRIPTOR*)(VOID*)(UINTN)(mCpuHotPlugData.SmBase[Index] + SMM_PSD_OFFSET);
+ CopyMem (Psd, &gcPsd, sizeof (gcPsd));
+ if (EFI_IMAGE_MACHINE_TYPE_SUPPORTED(EFI_IMAGE_MACHINE_X64)) {
+ //
+ // For X64 SMM, set GDT to the copy allocated above.
+ //
+ Psd->SmmGdtPtr = (UINT64)(UINTN)(GdtTssTables + GdtTssTableSize * Index);
+ } else if (FeaturePcdGet (PcdCpuSmmStackGuard)) {
+ //
+ // For IA32 SMM, if SMM Stack Guard feature is enabled, set GDT to the copy allocated above.
+ //
+ Psd->SmmGdtPtr = (UINT64)(UINTN)(GdtTssTables + GdtTssTableSize * Index);
+ Psd->SmmGdtSize = gcSmiGdtr.Limit + 1;
+ }
+
+ gSmiStack += StackSize;
+ }
+
+ //
+ // Initialize mSmmMpSyncData
+ //
+ mSmmMpSyncData = (SMM_DISPATCHER_MP_SYNC_DATA*) AllocatePages (EFI_SIZE_TO_PAGES (sizeof (*mSmmMpSyncData)));
+ ASSERT (mSmmMpSyncData != NULL);
+ InitializeMpSyncData ();
+
+ if (FeaturePcdGet (PcdCpuSmmUncacheCpuSyncData)) {
+ //
+ // mSmmMpSyncData should resides in un-cached RAM
+ //
+ SetCacheability ((UINT64*)(UINTN)gSmiCr3, (UINTN)mSmmMpSyncData, IA32_PG_CD);
+ }
+
+ //
+ // Record current MTRR settings
+ //
+ ZeroMem(gSmiMtrrs, sizeof (gSmiMtrrs));
+ Mtrr = (MTRR_SETTINGS*)gSmiMtrrs;
+ MtrrGetAllMtrrs (Mtrr);
+
+}
+
+/**
+ Register the SMM Foundation entry point.
+
+ @param[in] This Pointer to EFI_SMM_CONFIGURATION_PROTOCOL instance
+ @param[in] SmmEntryPoint SMM Foundation EntryPoint
+
+ @retval EFI_SUCCESS Successfully to register SMM foundation entry point
+
+**/
+EFI_STATUS
+EFIAPI
+RegisterSmmEntry (
+ IN CONST EFI_SMM_CONFIGURATION_PROTOCOL *This,
+ IN EFI_SMM_ENTRY_POINT SmmEntryPoint
+ )
+{
+ //
+ // Record SMM Foundation EntryPoint, later invoke it on SMI entry vector.
+ //
+ gSmmCpuPrivate->SmmCoreEntry = SmmEntryPoint;
+ return EFI_SUCCESS;
+}
+
+/**
+ Set SMM synchronization mode starting from the next SMI run.
+
+ @param[in] SyncMode The SMM synchronization mode to be set and effective from the next SMI run.
+
+ @retval EFI_SUCCESS The function completes successfully.
+ @retval EFI_INVALID_PARAMETER SynMode is not valid.
+
+**/
+EFI_STATUS
+SmmSyncSetModeWorker (
+ IN SMM_CPU_SYNC_MODE SyncMode
+ )
+{
+ if (SyncMode >= SmmCpuSyncModeMax) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Sync Mode effective from next SMI run
+ //
+ mSmmMpSyncData->SyncModeToBeSet = SyncMode;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Get current effective SMM synchronization mode.
+
+ @param[out] SyncMode Output parameter. The current effective SMM synchronization mode.
+
+ @retval EFI_SUCCESS The SMM synchronization mode has been retrieved successfully.
+ @retval EFI_INVALID_PARAMETER SyncMode is NULL.
+
+**/
+EFI_STATUS
+SmmSyncGetModeWorker (
+ OUT SMM_CPU_SYNC_MODE *SyncMode
+ )
+{
+ if (SyncMode == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+ *SyncMode = mSmmMpSyncData->EffectiveSyncMode;
+ return EFI_SUCCESS;
+}
+
+/**
+ Given timeout constraint, wait for all APs to arrive. If this function returns EFI_SUCCESS, then
+ no AP will execute normal mode code before entering SMM, so it is safe to access shared hardware resource
+ between SMM and normal mode. Note if there are SMI disabled APs, this function will return EFI_NOT_READY.
+
+ @retval EFI_SUCCESS No AP will execute normal mode code before entering SMM, so it is safe to access
+ shared hardware resource between SMM and normal mode
+ @retval EFI_NOT_READY One or more CPUs may still execute normal mode code
+ @retval EFI_DEVICE_ERROR Error occured in obtaining CPU status.
+
+**/
+EFI_STATUS
+SmmCpuSyncCheckApArrivalWorker (
+ VOID
+ )
+{
+ ASSERT (mSmmMpSyncData->Counter <= mNumberOfCpus);
+
+ if (mSmmMpSyncData->Counter == mNumberOfCpus) {
+ return EFI_SUCCESS;
+ }
+
+ //
+ // Wait for APs to arrive
+ //
+ SmmWaitForApArrival();
+
+ //
+ // If there are CPUs in SMI Disabled Statue, we return EFI_NOT_READY because this is not a safe environment for accessing shared
+ // hardware resource between SMM and normal mode.
+ //
+ if (AllCpusInSmmWithExceptions (ARRIVAL_EXCEPTION_BLOCKED)) {
+ return EFI_SUCCESS;
+ } else {
+ return EFI_NOT_READY;
+ }
+}
+
+/**
+ Given timeout constraint, wait for all APs to arrive. If this function returns EFI_SUCCESS, then
+ no AP will execute normal mode code before entering SMM, so it is safe to access shared hardware resource
+ between SMM and normal mode. Note if there are SMI disabled APs, this function will return EFI_NOT_READY.
+
+ @param[in] This A pointer to the SMM_CPU_SYNC_PROTOCOL instance.
+
+ @retval EFI_SUCCESS No AP will execute normal mode code before entering SMM, so it is safe to access
+ shared hardware resource between SMM and normal mode
+ @retval EFI_NOT_READY One or more CPUs may still execute normal mode code
+ @retval EFI_DEVICE_ERROR Error occured in obtaining CPU status.
+
+**/
+EFI_STATUS
+EFIAPI
+SmmCpuSyncCheckApArrival (
+ IN SMM_CPU_SYNC_PROTOCOL *This
+ )
+{
+ return SmmCpuSyncCheckApArrivalWorker();
+}
+
+/**
+ Given timeout constraint, wait for all APs to arrive, and insure if this function returns EFI_SUCCESS, then
+ no AP will execute normal mode code before entering SMM, so it is safe to access shared hardware resource
+ between SMM and normal mode. Note if there are SMI disabled APs, this function will return EFI_NOT_READY.
+
+ @param[in] This A pointer to the SMM_CPU_SYNC_PROTOCOL instance.
+
+ @retval EFI_SUCCESS No AP will execute normal mode code before entering SMM, so it is safe to access
+ shared hardware resource between SMM and normal mode
+ @retval EFI_NOT_READY One or more CPUs may still execute normal mode code
+ @retval EFI_DEVICE_ERROR Error occured in obtaining CPU status.
+
+**/
+EFI_STATUS
+EFIAPI
+SmmCpuSync2CheckApArrival (
+ IN SMM_CPU_SYNC2_PROTOCOL *This
+ )
+{
+ return SmmCpuSyncCheckApArrivalWorker();
+}
+
+/**
+ Set SMM synchronization mode starting from the next SMI run.
+
+ @param[in] This A pointer to the SMM_CPU_SYNC_PROTOCOL instance.
+ @param[in] SyncMode The SMM synchronization mode to be set and effective from the next SMI run.
+
+ @retval EFI_SUCCESS The function completes successfully.
+ @retval EFI_INVALID_PARAMETER SynMode is not valid.
+
+**/
+EFI_STATUS
+EFIAPI
+SmmCpuSyncSetMode (
+ IN SMM_CPU_SYNC_PROTOCOL *This,
+ IN SMM_CPU_SYNC_MODE SyncMode
+ )
+{
+ return SmmSyncSetModeWorker(SyncMode);
+}
+
+/**
+ Set SMM synchronization mode starting from the next SMI run.
+
+ @param[in] This A pointer to the SMM_CPU_SYNC_PROTOCOL instance.
+ @param[in] SyncMode The SMM synchronization mode to be set and effective from the next SMI run.
+
+ @retval EFI_SUCCESS The function completes successfully.
+ @retval EFI_INVALID_PARAMETER SynMode is not valid.
+
+**/
+EFI_STATUS
+EFIAPI
+SmmCpuSync2SetMode (
+ IN SMM_CPU_SYNC2_PROTOCOL *This,
+ IN SMM_CPU_SYNC_MODE SyncMode
+ )
+{
+ return SmmSyncSetModeWorker(SyncMode);
+}
+
+/**
+ Get current effective SMM synchronization mode.
+
+ @param[in] This A pointer to the SMM_CPU_SYNC_PROTOCOL instance.
+ @param[out] SyncMode Output parameter. The current effective SMM synchronization mode.
+
+ @retval EFI_SUCCESS The SMM synchronization mode has been retrieved successfully.
+ @retval EFI_INVALID_PARAMETER SyncMode is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+SmmCpuSyncGetMode (
+ IN SMM_CPU_SYNC_PROTOCOL *This,
+ OUT SMM_CPU_SYNC_MODE *SyncMode
+ )
+{
+ return SmmSyncGetModeWorker(SyncMode);
+}
+
+/**
+ Get current effective SMM synchronization mode.
+
+ @param[in] This A pointer to the SMM_CPU_SYNC_PROTOCOL instance.
+ @param[out] SyncMode Output parameter. The current effective SMM synchronization mode.
+
+ @retval EFI_SUCCESS The SMM synchronization mode has been retrieved successfully.
+ @retval EFI_INVALID_PARAMETER SyncMode is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+SmmCpuSync2GetMode (
+ IN SMM_CPU_SYNC2_PROTOCOL *This,
+ OUT SMM_CPU_SYNC_MODE *SyncMode
+ )
+{
+ return SmmSyncGetModeWorker(SyncMode);
+}
+
+/**
+ Checks CPU SMM synchronization state
+
+ @param[in] This A pointer to the SMM_CPU_SYNC_PROTOCOL instance.
+ @param[in] CpuIndex Index of the CPU for which the state is to be retrieved.
+ @param[out] CpuState The state of the CPU
+
+ @retval EFI_SUCCESS Returns EFI_SUCCESS if the CPU's state is retrieved.
+ @retval EFI_INVALID_PARAMETER Returns EFI_INVALID_PARAMETER if CpuIndex is invalid or CpuState is NULL
+ @retval EFI_DEVICE_ERROR Error occured in obtaining CPU status.
+
+**/
+EFI_STATUS
+EFIAPI
+SmmCpuSync2CheckCpuState (
+ IN SMM_CPU_SYNC2_PROTOCOL *This,
+ IN UINTN CpuIndex,
+ OUT SMM_CPU_SYNC2_CPU_STATE *CpuState
+ )
+{
+ SMM_CPU_SYNC_FEATURE *SyncFeature;
+ UINT64 LogProcEnBit;
+
+ if (CpuIndex >= mMaxNumberOfCpus) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (gSmmCpuPrivate->ProcessorInfo[CpuIndex].ProcessorId == INVALID_APIC_ID) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (CpuState == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ *CpuState = SmmCpuSync2StateNormal;
+ SyncFeature = &(gSmmCpuPrivate->SmmSyncFeature[CpuIndex]);
+ LogProcEnBit = SyncFeature->HaswellLogProcEnBit;
+
+ if (SyncFeature->DelayIndicationSupported && (SmmReadReg64 (CpuIndex, SmmRegSmmDelayed) & LogProcEnBit)) {
+ *CpuState = SmmCpuSync2StateDelayed;
+ } else if (SyncFeature->BlockIndicationSupported && (SmmReadReg64 (CpuIndex, SmmRegSmmBlocked) & LogProcEnBit)) {
+ *CpuState = SmmCpuSync2StateBlocked;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Change CPU's SMM enabling state.
+
+ @param[in] This A pointer to the SMM_CPU_SYNC_PROTOCOL instance.
+ @param[in] CpuIndex Index of the CPU to enable / disable SMM
+ @param[in] Enable If TRUE, enable SMM; if FALSE disable SMM
+
+ @retval EFI_SUCCESS The CPU's SMM enabling state is changed.
+ @retval EFI_INVALID_PARAMETER Returns EFI_INVALID_PARAMETER if CpuIndex is invalid
+ @retval EFI_UNSUPPORTED Returns EFI_UNSUPPORTED the CPU does not support dynamically enabling / disabling SMI
+ @retval EFI_DEVICE_ERROR Error occured in changing SMM enabling state.
+
+**/
+EFI_STATUS
+EFIAPI
+SmmCpuSync2ChangeSmmEnabling (
+ IN SMM_CPU_SYNC2_PROTOCOL *This,
+ IN UINTN CpuIndex,
+ IN BOOLEAN Enable
+ )
+{
+ SMM_CPU_SYNC_FEATURE *SyncFeature;
+ UINT64 LogProcEnBit;
+
+ if (CpuIndex >= mMaxNumberOfCpus) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (gSmmCpuPrivate->ProcessorInfo[CpuIndex].ProcessorId == INVALID_APIC_ID) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ SyncFeature = &(gSmmCpuPrivate->SmmSyncFeature[CpuIndex]);
+ LogProcEnBit = SyncFeature->HaswellLogProcEnBit;
+
+ return EFI_UNSUPPORTED;
+}
+
+/**
+ Send SMI IPI to a specific CPU.
+
+ @param[in] This A pointer to the SMM_CPU_SYNC_PROTOCOL instance.
+ @param[in] CpuIndex Index of the CPU to send SMI to.
+
+ @retval EFI_SUCCESS The SMI IPI is sent successfully.
+ @retval EFI_INVALID_PARAMETER Returns EFI_INVALID_PARAMETER if CpuIndex is invalid
+ @retval EFI_DEVICE_ERROR Error occured in sending SMI IPI.
+
+**/
+EFI_STATUS
+EFIAPI
+SmmCpuSync2SendSmi (
+ IN SMM_CPU_SYNC2_PROTOCOL *This,
+ IN UINTN CpuIndex
+ )
+{
+ if (CpuIndex >= mMaxNumberOfCpus) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (gSmmCpuPrivate->ProcessorInfo[CpuIndex].ProcessorId == INVALID_APIC_ID) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ SendSmiIpi ((UINT32)gSmmCpuPrivate->ProcessorInfo[CpuIndex].ProcessorId);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Send SMI IPI to all CPUs excluding self
+
+ @param[in] This A pointer to the SMM_CPU_SYNC_PROTOCOL instance.
+
+ @retval EFI_SUCCESS The SMI IPI is sent successfully.
+ @retval EFI_INVALID_PARAMETER Returns EFI_INVALID_PARAMETER if CpuIndex is invalid
+ @retval EFI_DEVICE_ERROR Error occured in sending SMI IPI.
+
+**/
+EFI_STATUS
+EFIAPI
+SmmCpuSync2SendSmiAllExcludingSelf (
+ IN SMM_CPU_SYNC2_PROTOCOL *This
+ )
+{
+ SendSmiIpiAllExcludingSelf();
+ return EFI_SUCCESS;
+}
diff --git a/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.c b/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.c
new file mode 100644
index 0000000000..d4ab88dff8
--- /dev/null
+++ b/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.c
@@ -0,0 +1,1596 @@
+/** @file
+ Agent Module to load other modules to deploy SMM Entry Vector for X86 CPU.
+
+ Copyright (c) 2009 - 2015, 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 "PiSmmCpuDxeSmm.h"
+
+//
+// SMM CPU Private Data structure that contains SMM Configuration Protocol
+// along its supporting fields.
+//
+SMM_CPU_PRIVATE_DATA mSmmCpuPrivateData = {
+ SMM_CPU_PRIVATE_DATA_SIGNATURE, // Signature
+ NULL, // SmmCpuHandle
+ { {0} }, // ProcessorInfo array
+ { SmmCpuNone }, // Operation array
+ { 0 }, // CpuSaveStateSize array
+ { NULL }, // CpuSaveState array
+ { 0 }, // TstateMsr array
+ { {0} }, // SmmSyncFeature array
+ { {0} }, // SmmReservedSmramRegion
+ {
+ SmmStartupThisAp, // SmmCoreEntryContext.SmmStartupThisAp
+ 0, // SmmCoreEntryContext.CurrentlyExecutingCpu
+ 0, // SmmCoreEntryContext.NumberOfCpus
+ mSmmCpuPrivateData.CpuSaveStateSize, // SmmCoreEntryContext.CpuSaveStateSize
+ mSmmCpuPrivateData.CpuSaveState // SmmCoreEntryContext.CpuSaveStateSize
+ },
+ NULL, // SmmCoreEntry
+ {
+ mSmmCpuPrivateData.SmmReservedSmramRegion, // SmmConfiguration.SmramReservedRegions
+ RegisterSmmEntry // SmmConfiguration.RegisterSmmEntry
+ },
+};
+
+CPU_HOT_PLUG_DATA mCpuHotPlugData = {
+ CPU_HOT_PLUG_DATA_REVISION_1, // Revision
+ 0, // Array Length of SmBase and APIC ID
+ NULL, // Pointer to APIC ID array
+ NULL, // Pointer to SMBASE array
+ 0, // IEDBase
+ 0, // SmrrBase
+ 0 // SmrrSize
+};
+
+//
+// Global pointer used to access mSmmCpuPrivateData from outside and inside SMM
+//
+SMM_CPU_PRIVATE_DATA *gSmmCpuPrivate = &mSmmCpuPrivateData;
+
+//
+// SMM Reloc variables
+//
+volatile BOOLEAN mRebased[FixedPcdGet32 (PcdCpuMaxLogicalProcessorNumber)];
+volatile BOOLEAN mIsBsp;
+
+///
+/// Handle for the SMM CPU Protocol
+///
+EFI_HANDLE mSmmCpuHandle = NULL;
+
+///
+/// SMM CPU Protocol instance
+///
+EFI_SMM_CPU_PROTOCOL mSmmCpu = {
+ SmmReadSaveState,
+ SmmWriteSaveState
+};
+
+EFI_CPU_INTERRUPT_HANDLER mExternalVectorTable[EXCEPTION_VECTOR_NUMBER];
+
+///
+/// SMM CPU Sync Protocol instance
+///
+SMM_CPU_SYNC_PROTOCOL mSmmCpuSync = {
+ SmmCpuSyncCheckApArrival,
+ SmmCpuSyncSetMode,
+ SmmCpuSyncGetMode
+};
+
+///
+/// SMM CPU Sync2 Protocol instance
+///
+SMM_CPU_SYNC2_PROTOCOL mSmmCpuSync2 = {
+ SmmCpuSync2CheckApArrival,
+ SmmCpuSync2SetMode,
+ SmmCpuSync2GetMode,
+ SmmCpuSync2CheckCpuState,
+ SmmCpuSync2ChangeSmmEnabling,
+ SmmCpuSync2SendSmi,
+ SmmCpuSync2SendSmiAllExcludingSelf
+};
+
+///
+/// SMM CPU Save State Protocol instance
+///
+EFI_SMM_CPU_SAVE_STATE_PROTOCOL mSmmCpuSaveState = {
+ (EFI_SMM_CPU_STATE **)mSmmCpuPrivateData.CpuSaveState
+};
+
+//
+// SMM stack information
+//
+UINTN mSmmStackArrayBase;
+UINTN mSmmStackArrayEnd;
+UINTN mSmmStackSize;
+
+//
+// Pointer to structure used during S3 Resume
+//
+SMM_S3_RESUME_STATE *mSmmS3ResumeState = NULL;
+
+UINTN mMaxNumberOfCpus = 1;
+UINTN mNumberOfCpus = 1;
+
+//
+// SMM ready to lock flag
+//
+BOOLEAN mSmmReadyToLock = FALSE;
+
+///
+/// Macro used to simplfy the lookup table entries of type CPU_SMM_SAVE_STATE_LOOKUP_ENTRY
+///
+#define SMM_CPU_OFFSET(Field) OFFSET_OF (SOCKET_LGA_775_SMM_CPU_STATE, Field)
+
+///
+/// Macro used to simplfy the lookup table entries of type CPU_SMM_SAVE_STATE_REGISTER_RANGE
+///
+#define SMM_REGISTER_RANGE(Start, End) { Start, End, End - Start + 1 }
+
+///
+/// Table used by GetRegisterIndex() to convert an EFI_SMM_SAVE_STATE_REGISTER
+/// value to an index into a table of type CPU_SMM_SAVE_STATE_LOOKUP_ENTRY
+///
+CONST CPU_SMM_SAVE_STATE_REGISTER_RANGE mSmmCpuRegisterRanges[] = {
+ SMM_REGISTER_RANGE (EFI_SMM_SAVE_STATE_REGISTER_GDTBASE, EFI_SMM_SAVE_STATE_REGISTER_LDTINFO),
+ SMM_REGISTER_RANGE (EFI_SMM_SAVE_STATE_REGISTER_ES, EFI_SMM_SAVE_STATE_REGISTER_RIP),
+ SMM_REGISTER_RANGE (EFI_SMM_SAVE_STATE_REGISTER_RFLAGS, EFI_SMM_SAVE_STATE_REGISTER_CR4),
+ { (EFI_SMM_SAVE_STATE_REGISTER)0, (EFI_SMM_SAVE_STATE_REGISTER)0, 0 }
+};
+
+///
+/// Lookup table used to retrieve the widths and offsets associated with each
+/// supported EFI_SMM_SAVE_STATE_REGISTER value
+///
+CONST CPU_SMM_SAVE_STATE_LOOKUP_ENTRY mSmmCpuWidthOffset[] = {
+ {0, 0, 0, 0, 0, FALSE}, // Reserved
+
+ //
+ // Internally defined CPU Save State Registers. Not defined in PI SMM CPU Protocol.
+ //
+ {4, 4, SMM_CPU_OFFSET (x86.SMMRevId) , SMM_CPU_OFFSET (x64.SMMRevId) , 0 , FALSE}, // SMM_SAVE_STATE_REGISTER_SMMREVID_INDEX = 1
+ {4, 4, SMM_CPU_OFFSET (x86.IOMisc) , SMM_CPU_OFFSET (x64.IOMisc) , 0 , FALSE}, // SMM_SAVE_STATE_REGISTER_IOMISC_INDEX = 2
+ {4, 8, SMM_CPU_OFFSET (x86.IOMemAddr) , SMM_CPU_OFFSET (x64.IOMemAddr) , SMM_CPU_OFFSET (x64.IOMemAddr) + 4, FALSE}, // SMM_SAVE_STATE_REGISTER_IOMEMADDR_INDEX = 3
+ {4, 4, SMM_CPU_OFFSET (x64.SMBASE) , SMM_CPU_OFFSET (x64.SMBASE) , 0 , TRUE }, // EFI_SMM_SAVE_STATE_REGISTER_SMBASE = 11
+
+ //
+ // CPU Save State registers defined in PI SMM CPU Protocol.
+ //
+ {0, 8, 0 , SMM_CPU_OFFSET (x64.GdtBaseLoDword) , SMM_CPU_OFFSET (x64.GdtBaseHiDword), FALSE}, // EFI_SMM_SAVE_STATE_REGISTER_GDTBASE = 4
+ {0, 8, 0 , SMM_CPU_OFFSET (x64.IdtBaseLoDword) , SMM_CPU_OFFSET (x64.IdtBaseHiDword), FALSE}, // EFI_SMM_SAVE_STATE_REGISTER_IDTBASE = 5
+ {0, 8, 0 , SMM_CPU_OFFSET (x64.LdtBaseLoDword) , SMM_CPU_OFFSET (x64.LdtBaseHiDword), FALSE}, // EFI_SMM_SAVE_STATE_REGISTER_LDTBASE = 6
+ {0, 4, 0 , SMM_CPU_OFFSET (x64.GdtLimit) , 0 , FALSE}, // EFI_SMM_SAVE_STATE_REGISTER_GDTLIMIT = 7
+ {0, 4, 0 , SMM_CPU_OFFSET (x64.IdtLimit) , 0 , FALSE}, // EFI_SMM_SAVE_STATE_REGISTER_IDTLIMIT = 8
+ {0, 4, 0 , SMM_CPU_OFFSET (x64.LdtLimit) , 0 , FALSE}, // EFI_SMM_SAVE_STATE_REGISTER_LDTLIMIT = 9
+ {0, 4, 0 , SMM_CPU_OFFSET (x64.LdtInfo) , 0 , FALSE}, // EFI_SMM_SAVE_STATE_REGISTER_LDTINFO = 10
+
+ {4, 4, SMM_CPU_OFFSET (x86._ES) , SMM_CPU_OFFSET (x64._ES) , 0 , FALSE}, // EFI_SMM_SAVE_STATE_REGISTER_ES = 20
+ {4, 4, SMM_CPU_OFFSET (x86._CS) , SMM_CPU_OFFSET (x64._CS) , 0 , FALSE}, // EFI_SMM_SAVE_STATE_REGISTER_CS = 21
+ {4, 4, SMM_CPU_OFFSET (x86._SS) , SMM_CPU_OFFSET (x64._SS) , 0 , FALSE}, // EFI_SMM_SAVE_STATE_REGISTER_SS = 22
+ {4, 4, SMM_CPU_OFFSET (x86._DS) , SMM_CPU_OFFSET (x64._DS) , 0 , FALSE}, // EFI_SMM_SAVE_STATE_REGISTER_DS = 23
+ {4, 4, SMM_CPU_OFFSET (x86._FS) , SMM_CPU_OFFSET (x64._FS) , 0 , FALSE}, // EFI_SMM_SAVE_STATE_REGISTER_FS = 24
+ {4, 4, SMM_CPU_OFFSET (x86._GS) , SMM_CPU_OFFSET (x64._GS) , 0 , FALSE}, // EFI_SMM_SAVE_STATE_REGISTER_GS = 25
+ {0, 4, 0 , SMM_CPU_OFFSET (x64._LDTR) , 0 , FALSE}, // EFI_SMM_SAVE_STATE_REGISTER_LDTR_SEL = 26
+ {4, 4, SMM_CPU_OFFSET (x86._TR) , SMM_CPU_OFFSET (x64._TR) , 0 , FALSE}, // EFI_SMM_SAVE_STATE_REGISTER_TR_SEL = 27
+ {4, 8, SMM_CPU_OFFSET (x86._DR7) , SMM_CPU_OFFSET (x64._DR7) , SMM_CPU_OFFSET (x64._DR7) + 4, FALSE}, // EFI_SMM_SAVE_STATE_REGISTER_DR7 = 28
+ {4, 8, SMM_CPU_OFFSET (x86._DR6) , SMM_CPU_OFFSET (x64._DR6) , SMM_CPU_OFFSET (x64._DR6) + 4, FALSE}, // EFI_SMM_SAVE_STATE_REGISTER_DR6 = 29
+ {0, 8, 0 , SMM_CPU_OFFSET (x64._R8) , SMM_CPU_OFFSET (x64._R8) + 4, TRUE }, // EFI_SMM_SAVE_STATE_REGISTER_R8 = 30
+ {0, 8, 0 , SMM_CPU_OFFSET (x64._R9) , SMM_CPU_OFFSET (x64._R9) + 4, TRUE }, // EFI_SMM_SAVE_STATE_REGISTER_R9 = 31
+ {0, 8, 0 , SMM_CPU_OFFSET (x64._R10) , SMM_CPU_OFFSET (x64._R10) + 4, TRUE }, // EFI_SMM_SAVE_STATE_REGISTER_R10 = 32
+ {0, 8, 0 , SMM_CPU_OFFSET (x64._R11) , SMM_CPU_OFFSET (x64._R11) + 4, TRUE }, // EFI_SMM_SAVE_STATE_REGISTER_R11 = 33
+ {0, 8, 0 , SMM_CPU_OFFSET (x64._R12) , SMM_CPU_OFFSET (x64._R12) + 4, TRUE }, // EFI_SMM_SAVE_STATE_REGISTER_R12 = 34
+ {0, 8, 0 , SMM_CPU_OFFSET (x64._R13) , SMM_CPU_OFFSET (x64._R13) + 4, TRUE }, // EFI_SMM_SAVE_STATE_REGISTER_R13 = 35
+ {0, 8, 0 , SMM_CPU_OFFSET (x64._R14) , SMM_CPU_OFFSET (x64._R14) + 4, TRUE }, // EFI_SMM_SAVE_STATE_REGISTER_R14 = 36
+ {0, 8, 0 , SMM_CPU_OFFSET (x64._R15) , SMM_CPU_OFFSET (x64._R15) + 4, TRUE }, // EFI_SMM_SAVE_STATE_REGISTER_R15 = 37
+ {4, 8, SMM_CPU_OFFSET (x86._EAX) , SMM_CPU_OFFSET (x64._RAX) , SMM_CPU_OFFSET (x64._RAX) + 4, TRUE }, // EFI_SMM_SAVE_STATE_REGISTER_RAX = 38
+ {4, 8, SMM_CPU_OFFSET (x86._EBX) , SMM_CPU_OFFSET (x64._RBX) , SMM_CPU_OFFSET (x64._RBX) + 4, TRUE }, // EFI_SMM_SAVE_STATE_REGISTER_RBX = 39
+ {4, 8, SMM_CPU_OFFSET (x86._ECX) , SMM_CPU_OFFSET (x64._RCX) , SMM_CPU_OFFSET (x64._RCX) + 4, TRUE }, // EFI_SMM_SAVE_STATE_REGISTER_RCX = 40
+ {4, 8, SMM_CPU_OFFSET (x86._EDX) , SMM_CPU_OFFSET (x64._RDX) , SMM_CPU_OFFSET (x64._RDX) + 4, TRUE }, // EFI_SMM_SAVE_STATE_REGISTER_RDX = 41
+ {4, 8, SMM_CPU_OFFSET (x86._ESP) , SMM_CPU_OFFSET (x64._RSP) , SMM_CPU_OFFSET (x64._RSP) + 4, TRUE }, // EFI_SMM_SAVE_STATE_REGISTER_RSP = 42
+ {4, 8, SMM_CPU_OFFSET (x86._EBP) , SMM_CPU_OFFSET (x64._RBP) , SMM_CPU_OFFSET (x64._RBP) + 4, TRUE }, // EFI_SMM_SAVE_STATE_REGISTER_RBP = 43
+ {4, 8, SMM_CPU_OFFSET (x86._ESI) , SMM_CPU_OFFSET (x64._RSI) , SMM_CPU_OFFSET (x64._RSI) + 4, TRUE }, // EFI_SMM_SAVE_STATE_REGISTER_RSI = 44
+ {4, 8, SMM_CPU_OFFSET (x86._EDI) , SMM_CPU_OFFSET (x64._RDI) , SMM_CPU_OFFSET (x64._RDI) + 4, TRUE }, // EFI_SMM_SAVE_STATE_REGISTER_RDI = 45
+ {4, 8, SMM_CPU_OFFSET (x86._EIP) , SMM_CPU_OFFSET (x64._RIP) , SMM_CPU_OFFSET (x64._RIP) + 4, TRUE }, // EFI_SMM_SAVE_STATE_REGISTER_RIP = 46
+
+ {4, 8, SMM_CPU_OFFSET (x86._EFLAGS) , SMM_CPU_OFFSET (x64._RFLAGS) , SMM_CPU_OFFSET (x64._RFLAGS) + 4, TRUE }, // EFI_SMM_SAVE_STATE_REGISTER_RFLAGS = 51
+ {4, 8, SMM_CPU_OFFSET (x86._CR0) , SMM_CPU_OFFSET (x64._CR0) , SMM_CPU_OFFSET (x64._CR0) + 4, FALSE}, // EFI_SMM_SAVE_STATE_REGISTER_CR0 = 52
+ {4, 8, SMM_CPU_OFFSET (x86._CR3) , SMM_CPU_OFFSET (x64._CR3) , SMM_CPU_OFFSET (x64._CR3) + 4, FALSE}, // EFI_SMM_SAVE_STATE_REGISTER_CR3 = 53
+ {0, 4, 0 , SMM_CPU_OFFSET (x64._CR4) , 0 , FALSE}, // EFI_SMM_SAVE_STATE_REGISTER_CR4 = 54
+};
+
+///
+/// Lookup table for the IOMisc width information
+///
+CONST CPU_SMM_SAVE_STATE_IO_WIDTH mSmmCpuIoWidth[] = {
+ { 0, EFI_SMM_SAVE_STATE_IO_WIDTH_UINT8 }, // Undefined = 0
+ { 1, EFI_SMM_SAVE_STATE_IO_WIDTH_UINT8 }, // SMM_IO_LENGTH_BYTE = 1
+ { 2, EFI_SMM_SAVE_STATE_IO_WIDTH_UINT16 }, // SMM_IO_LENGTH_WORD = 2
+ { 0, EFI_SMM_SAVE_STATE_IO_WIDTH_UINT8 }, // Undefined = 3
+ { 4, EFI_SMM_SAVE_STATE_IO_WIDTH_UINT32 }, // SMM_IO_LENGTH_DWORD = 4
+ { 0, EFI_SMM_SAVE_STATE_IO_WIDTH_UINT8 }, // Undefined = 5
+ { 0, EFI_SMM_SAVE_STATE_IO_WIDTH_UINT8 }, // Undefined = 6
+ { 0, EFI_SMM_SAVE_STATE_IO_WIDTH_UINT8 } // Undefined = 7
+};
+
+///
+/// Lookup table for the IOMisc type information
+///
+CONST EFI_SMM_SAVE_STATE_IO_TYPE mSmmCpuIoType[] = {
+ EFI_SMM_SAVE_STATE_IO_TYPE_OUTPUT, // SMM_IO_TYPE_OUT_DX = 0
+ EFI_SMM_SAVE_STATE_IO_TYPE_INPUT, // SMM_IO_TYPE_IN_DX = 1
+ EFI_SMM_SAVE_STATE_IO_TYPE_STRING, // SMM_IO_TYPE_OUTS = 2
+ EFI_SMM_SAVE_STATE_IO_TYPE_STRING, // SMM_IO_TYPE_INS = 3
+ (EFI_SMM_SAVE_STATE_IO_TYPE)0, // Undefined = 4
+ (EFI_SMM_SAVE_STATE_IO_TYPE)0, // Undefined = 5
+ EFI_SMM_SAVE_STATE_IO_TYPE_REP_PREFIX, // SMM_IO_TYPE_REP_OUTS = 6
+ EFI_SMM_SAVE_STATE_IO_TYPE_REP_PREFIX, // SMM_IO_TYPE_REP_INS = 7
+ EFI_SMM_SAVE_STATE_IO_TYPE_OUTPUT, // SMM_IO_TYPE_OUT_IMMEDIATE = 8
+ EFI_SMM_SAVE_STATE_IO_TYPE_INPUT, // SMM_IO_TYPE_OUT_IMMEDIATE = 9
+ (EFI_SMM_SAVE_STATE_IO_TYPE)0, // Undefined = 10
+ (EFI_SMM_SAVE_STATE_IO_TYPE)0, // Undefined = 11
+ (EFI_SMM_SAVE_STATE_IO_TYPE)0, // Undefined = 12
+ (EFI_SMM_SAVE_STATE_IO_TYPE)0, // Undefined = 13
+ (EFI_SMM_SAVE_STATE_IO_TYPE)0, // Undefined = 14
+ (EFI_SMM_SAVE_STATE_IO_TYPE)0 // Undefined = 15
+};
+
+/**
+ Read information from the CPU save state.
+
+ @param Register Specifies the CPU register to read form the save state.
+
+ @retval 0 Register is not valid
+ @retval >0 Index into mSmmCpuWidthOffset[] associated with Register
+
+**/
+UINTN
+GetRegisterIndex (
+ IN EFI_SMM_SAVE_STATE_REGISTER Register
+ )
+{
+ UINTN Index;
+ UINTN Offset;
+
+ for (Index = 0, Offset = SMM_SAVE_STATE_REGISTER_MAX_INDEX; mSmmCpuRegisterRanges[Index].Length != 0; Index++) {
+ if (Register >= mSmmCpuRegisterRanges[Index].Start && Register <= mSmmCpuRegisterRanges[Index].End) {
+ return Register - mSmmCpuRegisterRanges[Index].Start + Offset;
+ }
+ Offset += mSmmCpuRegisterRanges[Index].Length;
+ }
+ return 0;
+}
+
+/**
+ Read a CPU Save State register on the target processor.
+
+ This function abstracts the differences that whether the CPU Save State register is in the IA32 Cpu Save State Map
+ or x64 Cpu Save State Map or a CPU Save State MSR.
+
+ This function supports reading a CPU Save State register in SMBase relocation handler.
+
+ @param[in] CpuIndex Specifies the zero-based index of the CPU save state.
+ @param[in] RegisterIndex Index into mSmmCpuWidthOffset[] look up table.
+ @param[in] Width The number of bytes to read from the CPU save state.
+ @param[out] Buffer Upon return, this holds the CPU register value read from the save state.
+
+ @retval EFI_SUCCESS The register was read from Save State.
+ @retval EFI_NOT_FOUND The register is not defined for the Save State of Processor.
+ @retval EFI_INVALID_PARAMTER This or Buffer is NULL.
+ @retval EFI_UNSUPPORTED The register has no corresponding MSR.
+
+**/
+EFI_STATUS
+ReadSaveStateRegister (
+ IN UINTN CpuIndex,
+ IN UINTN RegisterIndex,
+ IN UINTN Width,
+ OUT VOID *Buffer
+ )
+{
+ UINT32 SmmRevId;
+ SOCKET_LGA_775_SMM_CPU_STATE *CpuSaveState;
+
+ CpuSaveState = NULL;
+
+ {
+ CpuSaveState = gSmst->CpuSaveState[CpuIndex];
+ SmmRevId = CpuSaveState->x86.SMMRevId;
+ }
+
+ if (RegisterIndex == SMM_SAVE_STATE_REGISTER_SMMREVID_INDEX) {
+ *(UINT32 *)Buffer = SmmRevId;
+ return EFI_SUCCESS;
+ }
+
+ if (SmmRevId < SOCKET_LGA_775_SMM_MIN_REV_ID_x64) {
+ //
+ // If 32-bit mode width is zero, then the specified register can not be accessed
+ //
+ if (mSmmCpuWidthOffset[RegisterIndex].Width32 == 0) {
+ return EFI_NOT_FOUND;
+ }
+
+ //
+ // If Width is bigger than the 32-bit mode width, then the specified register can not be accessed
+ //
+ if (Width > mSmmCpuWidthOffset[RegisterIndex].Width32) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Write return buffer
+ //
+ ASSERT (CpuSaveState != NULL);
+ CopyMem(Buffer, (UINT8 *)CpuSaveState + mSmmCpuWidthOffset[RegisterIndex].Offset32, Width);
+ } else {
+ //
+ // If 64-bit mode width is zero, then the specified register can not be accessed
+ //
+ if (mSmmCpuWidthOffset[RegisterIndex].Width64 == 0) {
+ return EFI_NOT_FOUND;
+ }
+
+ //
+ // If Width is bigger than the 64-bit mode width, then the specified register can not be accessed
+ //
+ if (Width > mSmmCpuWidthOffset[RegisterIndex].Width64) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ {
+ //
+ // Write lower 32-bits of return buffer
+ //
+ CopyMem(Buffer, (UINT8 *)CpuSaveState + mSmmCpuWidthOffset[RegisterIndex].Offset64Lo, MIN (4, Width));
+ if (Width >= 4) {
+ //
+ // Write upper 32-bits of return buffer
+ //
+ CopyMem((UINT8 *)Buffer + 4, (UINT8 *)CpuSaveState + mSmmCpuWidthOffset[RegisterIndex].Offset64Hi, Width - 4);
+ }
+ }
+ }
+ return EFI_SUCCESS;
+}
+
+/**
+ Write value to a CPU Save State register on the target processor.
+
+ This function abstracts the differences that whether the CPU Save State register is in the IA32 Cpu Save State Map
+ or x64 Cpu Save State Map or a CPU Save State MSR.
+
+ This function supports writing a CPU Save State register in SMBase relocation handler.
+
+ @param[in] CpuIndex Specifies the zero-based index of the CPU save state.
+ @param[in] RegisterIndex Index into mSmmCpuWidthOffset[] look up table.
+ @param[in] Width The number of bytes to read from the CPU save state.
+ @param[in] Buffer Upon entry, this holds the new CPU register value.
+
+ @retval EFI_SUCCESS The register was written to Save State.
+ @retval EFI_NOT_FOUND The register is not defined for the Save State of Processor.
+ @retval EFI_INVALID_PARAMTER ProcessorIndex or Width is not correct.
+ @retval EFI_UNSUPPORTED The register is read-only, cannot be written, or has no corresponding MSR.
+
+**/
+EFI_STATUS
+WriteSaveStateRegister (
+ IN UINTN CpuIndex,
+ IN UINTN RegisterIndex,
+ IN UINTN Width,
+ IN CONST VOID *Buffer
+ )
+{
+ UINT32 SmmRevId;
+ SOCKET_LGA_775_SMM_CPU_STATE *CpuSaveState;
+
+ CpuSaveState = NULL;
+
+ //
+ // Do not write non-writeable SaveState.
+ //
+ if (!mSmmCpuWidthOffset[RegisterIndex].Writeable) {
+ return EFI_UNSUPPORTED;
+ }
+
+ //
+ // Get SMMRevId first.
+ //
+ {
+ CpuSaveState = gSmst->CpuSaveState[CpuIndex];
+ SmmRevId = CpuSaveState->x86.SMMRevId;
+ }
+
+ //
+ // Check CPU mode
+ //
+ if (SmmRevId < SOCKET_LGA_775_SMM_MIN_REV_ID_x64) {
+ //
+ // If 32-bit mode width is zero, then the specified register can not be accessed
+ //
+ if (mSmmCpuWidthOffset[RegisterIndex].Width32 == 0) {
+ return EFI_NOT_FOUND;
+ }
+
+ //
+ // If Width is bigger than the 32-bit mode width, then the specified register can not be accessed
+ //
+ if (Width > mSmmCpuWidthOffset[RegisterIndex].Width32) {
+ return EFI_INVALID_PARAMETER;
+ }
+ //
+ // Write SMM State register
+ //
+ ASSERT (CpuSaveState != NULL);
+ CopyMem((UINT8 *)CpuSaveState + mSmmCpuWidthOffset[RegisterIndex].Offset32, Buffer, Width);
+ } else {
+ //
+ // If 64-bit mode width is zero, then the specified register can not be accessed
+ //
+ if (mSmmCpuWidthOffset[RegisterIndex].Width64 == 0) {
+ return EFI_NOT_FOUND;
+ }
+
+ //
+ // If Width is bigger than the 64-bit mode width, then the specified register can not be accessed
+ //
+ if (Width > mSmmCpuWidthOffset[RegisterIndex].Width64) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ {
+ //
+ // Write lower 32-bits of SMM State register
+ //
+ CopyMem((UINT8 *)CpuSaveState + mSmmCpuWidthOffset[RegisterIndex].Offset64Lo, Buffer, MIN (4, Width));
+ if (Width >= 4) {
+ //
+ // Write upper 32-bits of SMM State register
+ //
+ CopyMem((UINT8 *)CpuSaveState + mSmmCpuWidthOffset[RegisterIndex].Offset64Hi, (UINT8 *)Buffer + 4, Width - 4);
+ }
+ }
+ }
+ return EFI_SUCCESS;
+}
+
+/**
+ Read information from the CPU save state.
+
+ @param This EFI_SMM_CPU_PROTOCOL instance
+ @param Width The number of bytes to read from the CPU save state.
+ @param Register Specifies the CPU register to read form the save state.
+ @param CpuIndex Specifies the zero-based index of the CPU save state.
+ @param Buffer Upon return, this holds the CPU register value read from the save state.
+
+ @retval EFI_SUCCESS The register was read from Save State
+ @retval EFI_NOT_FOUND The register is not defined for the Save State of Processor
+ @retval EFI_INVALID_PARAMTER This or Buffer is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+SmmReadSaveState (
+ IN CONST EFI_SMM_CPU_PROTOCOL *This,
+ IN UINTN Width,
+ IN EFI_SMM_SAVE_STATE_REGISTER Register,
+ IN UINTN CpuIndex,
+ OUT VOID *Buffer
+ )
+{
+ UINT32 SmmRevId;
+ SOCKET_LGA_775_SMM_CPU_STATE_IOMISC IoMisc;
+ EFI_SMM_SAVE_STATE_IO_INFO *IoInfo;
+ UINTN RegisterIndex;
+ VOID *IoMemAddr;
+
+ //
+ // Retrieve pointer to the specified CPU's SMM Save State buffer
+ //
+ if ((CpuIndex >= gSmst->NumberOfCpus) || (Buffer == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Check for special EFI_SMM_SAVE_STATE_REGISTER_PROCESSOR_ID
+ //
+ if (Register == EFI_SMM_SAVE_STATE_REGISTER_PROCESSOR_ID) {
+ //
+ // The pseudo-register only supports the 64-bit size specified by Width.
+ //
+ if (Width != sizeof (UINT64)) {
+ return EFI_INVALID_PARAMETER;
+ }
+ //
+ // If the processor is in SMM at the time the SMI occurred,
+ // the pseudo register value for EFI_SMM_SAVE_STATE_REGISTER_PROCESSOR_ID is returned in Buffer.
+ // Otherwise, EFI_NOT_FOUND is returned.
+ //
+ if (mSmmMpSyncData->CpuData[CpuIndex].Present) {
+ *(UINT64 *)Buffer = gSmmCpuPrivate->ProcessorInfo[CpuIndex].ProcessorId;
+ return EFI_SUCCESS;
+ } else {
+ return EFI_NOT_FOUND;
+ }
+ }
+
+ if (!mSmmMpSyncData->CpuData[CpuIndex].Present) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Check for special EFI_SMM_SAVE_STATE_REGISTER_LMA
+ //
+ if (Register == EFI_SMM_SAVE_STATE_REGISTER_LMA) {
+ //
+ // Only byte access is supported for this register
+ //
+ if (Width != 1) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ ReadSaveStateRegister (CpuIndex, SMM_SAVE_STATE_REGISTER_SMMREVID_INDEX, sizeof (SmmRevId), &SmmRevId);
+
+ if ((SmmRevId < SOCKET_LGA_775_SMM_MIN_REV_ID_x64)) {
+ *(UINT8 *)Buffer = EFI_SMM_SAVE_STATE_REGISTER_LMA_32BIT;
+ } else {
+ *(UINT8 *)Buffer = EFI_SMM_SAVE_STATE_REGISTER_LMA_64BIT;
+ }
+
+ return EFI_SUCCESS;
+ }
+
+ //
+ // Check for special EFI_SMM_SAVE_STATE_REGISTER_IO
+ //
+ if (Register == EFI_SMM_SAVE_STATE_REGISTER_IO) {
+ ReadSaveStateRegister (CpuIndex, SMM_SAVE_STATE_REGISTER_SMMREVID_INDEX, sizeof (SmmRevId), &SmmRevId);
+
+ //
+ // See if the CPU supports the IOMisc register in the save state
+ //
+ if (SmmRevId < SOCKET_LGA_775_SMM_MIN_REV_ID_IOMISC) {
+ return EFI_NOT_FOUND;
+ }
+
+ //
+ // Get the IOMisc register value
+ //
+ ReadSaveStateRegister (CpuIndex, SMM_SAVE_STATE_REGISTER_IOMISC_INDEX, sizeof (IoMisc.Uint32), &IoMisc.Uint32);
+
+ //
+ // Check for the SMI_FLAG in IOMisc
+ //
+ if (IoMisc.Bits.SmiFlag == 0) {
+ return EFI_NOT_FOUND;
+ }
+
+ //
+ // Compute index for the I/O Length and I/O Type lookup tables
+ //
+ if (mSmmCpuIoWidth[IoMisc.Bits.Length].Width == 0 || mSmmCpuIoType[IoMisc.Bits.Type] == 0) {
+ return EFI_NOT_FOUND;
+ }
+
+ //
+ // Zero the IoInfo structure that will be returned in Buffer
+ //
+ IoInfo = (EFI_SMM_SAVE_STATE_IO_INFO *)Buffer;
+ ZeroMem (IoInfo, sizeof (EFI_SMM_SAVE_STATE_IO_INFO));
+
+ //
+ // Use lookup tables to help fill in all the fields of the IoInfo structure
+ //
+ IoInfo->IoPort = (UINT16)IoMisc.Bits.Port;
+ IoInfo->IoWidth = mSmmCpuIoWidth[IoMisc.Bits.Length].IoWidth;
+ IoInfo->IoType = mSmmCpuIoType[IoMisc.Bits.Type];
+ if (IoInfo->IoType == EFI_SMM_SAVE_STATE_IO_TYPE_INPUT || IoInfo->IoType == EFI_SMM_SAVE_STATE_IO_TYPE_OUTPUT) {
+ ReadSaveStateRegister (CpuIndex, GetRegisterIndex (EFI_SMM_SAVE_STATE_REGISTER_RAX), mSmmCpuIoWidth[IoMisc.Bits.Length].Width, &IoInfo->IoData);
+ } else {
+ ReadSaveStateRegister (CpuIndex, SMM_SAVE_STATE_REGISTER_IOMEMADDR_INDEX, sizeof (IoMemAddr), &IoMemAddr);
+ CopyMem (&IoInfo->IoData, IoMemAddr, mSmmCpuIoWidth[IoMisc.Bits.Length].Width);
+ }
+ return EFI_SUCCESS;
+ }
+
+ //
+ // Convert Register to a register lookup table index
+ //
+ RegisterIndex = GetRegisterIndex (Register);
+ if (RegisterIndex == 0) {
+ return EFI_NOT_FOUND;
+ }
+
+ return ReadSaveStateRegister (CpuIndex, RegisterIndex, Width, Buffer);
+}
+
+/**
+ Write data to the CPU save state.
+
+ @param This EFI_SMM_CPU_PROTOCOL instance
+ @param Width The number of bytes to read from the CPU save state.
+ @param Register Specifies the CPU register to write to the save state.
+ @param CpuIndex Specifies the zero-based index of the CPU save state
+ @param Buffer Upon entry, this holds the new CPU register value.
+
+ @retval EFI_SUCCESS The register was written from Save State
+ @retval EFI_NOT_FOUND The register is not defined for the Save State of Processor
+ @retval EFI_INVALID_PARAMTER ProcessorIndex or Width is not correct
+
+**/
+EFI_STATUS
+EFIAPI
+SmmWriteSaveState (
+ IN CONST EFI_SMM_CPU_PROTOCOL *This,
+ IN UINTN Width,
+ IN EFI_SMM_SAVE_STATE_REGISTER Register,
+ IN UINTN CpuIndex,
+ IN CONST VOID *Buffer
+ )
+{
+ UINTN RegisterIndex;
+
+ //
+ // Retrieve pointer to the specified CPU's SMM Save State buffer
+ //
+ if ((CpuIndex >= gSmst->NumberOfCpus) || (Buffer == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Writes to EFI_SMM_SAVE_STATE_REGISTER_PROCESSOR_ID are ignored
+ //
+ if (Register == EFI_SMM_SAVE_STATE_REGISTER_PROCESSOR_ID) {
+ return EFI_SUCCESS;
+ }
+
+ if (!mSmmMpSyncData->CpuData[CpuIndex].Present) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Writes to EFI_SMM_SAVE_STATE_REGISTER_LMA are ignored
+ //
+ if (Register == EFI_SMM_SAVE_STATE_REGISTER_LMA) {
+ return EFI_SUCCESS;
+ }
+
+ //
+ // Writes to EFI_SMM_SAVE_STATE_REGISTER_IO are not supported
+ //
+ if (Register == EFI_SMM_SAVE_STATE_REGISTER_IO) {
+ return EFI_NOT_FOUND;
+ }
+
+ //
+ // Convert Register to a register lookup table index
+ //
+ RegisterIndex = GetRegisterIndex (Register);
+ if (RegisterIndex == 0) {
+ //
+ // If Register is not valie, then return EFI_NOT_FOUND
+ //
+ return EFI_NOT_FOUND;
+ }
+
+ return WriteSaveStateRegister (CpuIndex, RegisterIndex, Width, Buffer);
+}
+
+/**
+ C function for SMI handler. To change all processor's SMMBase Register.
+
+**/
+VOID
+EFIAPI
+SmmInitHandler (
+ VOID
+ )
+{
+ UINT32 ApicId;
+ UINTN Index;
+ IA32_DESCRIPTOR X64Idtr;
+ IA32_IDT_GATE_DESCRIPTOR IdtEntryTable[EXCEPTION_VECTOR_NUMBER];
+
+ //
+ // Set up X64 IDT table
+ //
+ ZeroMem (IdtEntryTable, sizeof (IA32_IDT_GATE_DESCRIPTOR) * EXCEPTION_VECTOR_NUMBER);
+ X64Idtr.Base = (UINTN) IdtEntryTable;
+ X64Idtr.Limit = (UINT16) (sizeof (IA32_IDT_GATE_DESCRIPTOR) * EXCEPTION_VECTOR_NUMBER - 1);
+ AsmWriteIdtr ((IA32_DESCRIPTOR *) &X64Idtr);
+
+ ApicId = GetApicId ();
+
+ ASSERT (mNumberOfCpus <= FixedPcdGet32 (PcdCpuMaxLogicalProcessorNumber));
+
+ for (Index = 0; Index < mNumberOfCpus; Index++) {
+ if (ApicId == (UINT32)gSmmCpuPrivate->ProcessorInfo[Index].ProcessorId) {
+ SmmInitiFeatures (Index, mCpuHotPlugData.SmrrBase, mCpuHotPlugData.SmrrSize, (UINT32)mCpuHotPlugData.SmBase[Index], mIsBsp);
+
+ if (!mIsBsp) {
+ SemaphoreHook (Index);
+ } else {
+ //
+ // BSP rebase is already done above.
+ // Initialize private data during S3 resume
+ //
+ InitializeMpSyncData ();
+ }
+ return;
+ }
+ }
+ ASSERT (FALSE);
+}
+
+/**
+ Relocate SmmBases for each processor.
+
+ Execute on first boot and all S3 resumes
+
+**/
+VOID
+EFIAPI
+SmmRelocateBases (
+ VOID
+ )
+{
+ UINT8 BakBuf[BACK_BUF_SIZE];
+ SOCKET_LGA_775_SMM_CPU_STATE BakBuf2;
+ SOCKET_LGA_775_SMM_CPU_STATE *CpuStatePtr;
+ UINT8 *U8Ptr;
+ UINT32 ApicId;
+ UINTN Index;
+
+ //
+ // Make sure the reserved size is large enough for procedure SmmInitTemplate.
+ //
+ ASSERT (sizeof (BakBuf) >= gcSmmInitSize);
+
+ //
+ // Patch ASM code template with current CR0, CR3, and CR4 values
+ //
+ gSmmCr0 = (UINT32)AsmReadCr0 ();
+ gSmmCr3 = (UINT32)AsmReadCr3 ();
+ gSmmCr4 = (UINT32)AsmReadCr4 ();
+
+ U8Ptr = (UINT8*)(UINTN)(SMM_DEFAULT_SMBASE + SMM_HANDLER_OFFSET);
+ CpuStatePtr = (SOCKET_LGA_775_SMM_CPU_STATE *)(UINTN)(SMM_DEFAULT_SMBASE + SMM_CPU_STATE_OFFSET);
+
+ //
+ // Backup original contents @ 0x38000
+ //
+ CopyMem (BakBuf, U8Ptr, sizeof (BakBuf));
+ CopyMem (&BakBuf2, CpuStatePtr, sizeof (BakBuf2));
+
+ //
+ // Load image for relocation
+ //
+ CopyMem (U8Ptr, gcSmmInitTemplate, gcSmmInitSize);
+
+ //
+ // Retrieve the local APIC ID of current processor
+ //
+ ApicId = GetApicId ();
+
+ //
+ // Relocate SM bases for all APs
+ // This is APs' 1st SMI - rebase will be done here, and APs' default SMI handler will be overriden by gcSmmInitTemplate
+ //
+ mIsBsp = FALSE;
+ for (Index = 0; Index < mNumberOfCpus; Index++) {
+ if (ApicId != (UINT32)gSmmCpuPrivate->ProcessorInfo[Index].ProcessorId) {
+ mRebased[Index] = FALSE;
+ SendSmiIpi ((UINT32)gSmmCpuPrivate->ProcessorInfo[Index].ProcessorId);
+
+ //
+ // Wait for this AP to finish its 1st SMI
+ //
+ while (!mRebased[Index]);
+ }
+ }
+
+ //
+ // Relocate BSP's SM base
+ //
+ mIsBsp = TRUE;
+ SendSmiIpi (ApicId);
+
+ //
+ // Restore contents @ 0x38000
+ //
+ CopyMem (CpuStatePtr, &BakBuf2, sizeof (BakBuf2));
+ CopyMem (U8Ptr, BakBuf, sizeof (BakBuf));
+}
+
+/**
+ Perform SMM initialization for all processors in the S3 boot path.
+
+ For a native platform, MP initialization in the S3 boot path is also performed in this function.
+**/
+VOID
+SmmRestoreCpu (
+ VOID
+ )
+{
+ SMM_S3_RESUME_STATE *SmmS3ResumeState;
+ IA32_DESCRIPTOR Ia32Idtr;
+ IA32_DESCRIPTOR X64Idtr;
+ IA32_IDT_GATE_DESCRIPTOR IdtEntryTable[EXCEPTION_VECTOR_NUMBER];
+
+ DEBUG ((EFI_D_ERROR, "SmmRestoreCpu()\n"));
+
+ //
+ // See if there is enough context to resume PEI Phase
+ //
+ if (mSmmS3ResumeState == NULL) {
+ DEBUG ((EFI_D_ERROR, "No context to return to PEI Phase\n"));
+ CpuDeadLoop ();
+ }
+
+ SmmS3ResumeState = mSmmS3ResumeState;
+ ASSERT (SmmS3ResumeState != NULL);
+
+ if (SmmS3ResumeState->Signature == SMM_S3_RESUME_SMM_64) {
+ //
+ // Save the IA32 IDT Descriptor
+ //
+ AsmReadIdtr ((IA32_DESCRIPTOR *) &Ia32Idtr);
+
+ //
+ // Setup X64 IDT table
+ //
+ ZeroMem (IdtEntryTable, sizeof (IA32_IDT_GATE_DESCRIPTOR) * 32);
+ X64Idtr.Base = (UINTN) IdtEntryTable;
+ X64Idtr.Limit = (UINT16) (sizeof (IA32_IDT_GATE_DESCRIPTOR) * 32 - 1);
+ AsmWriteIdtr ((IA32_DESCRIPTOR *) &X64Idtr);
+
+
+ //
+ // Initialize Debug Agent to support source level debug
+ //
+ InitializeDebugAgent (DEBUG_AGENT_INIT_THUNK_PEI_IA32TOX64, (VOID *)&Ia32Idtr, NULL);
+ }
+
+ //
+ // Do below CPU things for native platform only
+ //
+ if (!FeaturePcdGet(PcdFrameworkCompatibilitySupport)) {
+ //
+ // First time microcode load and restore MTRRs
+ //
+ // TODO EarlyInitializeCpu ();
+ }
+
+ //
+ // Restore SMBASE for BSP and all APs
+ //
+ SmmRelocateBases ();
+
+ //
+ // Do below CPU things for native platform only
+ //
+ if (!FeaturePcdGet(PcdFrameworkCompatibilitySupport)) {
+ //
+ // Restore MSRs for BSP and all APs
+ //
+ // TODO InitializeCpu ();
+ }
+
+ if (mSmmCodeAccessCheckEnable || FeaturePcdGet (PcdCpuSmmFeatureControlMsrLock)) {
+ //
+ // Set a flag to restore SMM configuration in S3 path.
+ //
+ mRestoreSmmConfigurationInS3 = TRUE;
+ }
+
+ DEBUG (( EFI_D_ERROR, "SMM S3 Return CS = %x\n", SmmS3ResumeState->ReturnCs));
+ DEBUG (( EFI_D_ERROR, "SMM S3 Return Entry Point = %x\n", SmmS3ResumeState->ReturnEntryPoint));
+ DEBUG (( EFI_D_ERROR, "SMM S3 Return Context1 = %x\n", SmmS3ResumeState->ReturnContext1));
+ DEBUG (( EFI_D_ERROR, "SMM S3 Return Context2 = %x\n", SmmS3ResumeState->ReturnContext2));
+ DEBUG (( EFI_D_ERROR, "SMM S3 Return Stack Pointer = %x\n", SmmS3ResumeState->ReturnStackPointer));
+
+ //
+ // If SMM is in 32-bit mode, then use SwitchStack() to resume PEI Phase
+ //
+ if (SmmS3ResumeState->Signature == SMM_S3_RESUME_SMM_32) {
+ DEBUG ((EFI_D_ERROR, "Call SwitchStack() to return to S3 Resume in PEI Phase\n"));
+
+ SwitchStack (
+ (SWITCH_STACK_ENTRY_POINT)(UINTN)SmmS3ResumeState->ReturnEntryPoint,
+ (VOID *)(UINTN)SmmS3ResumeState->ReturnContext1,
+ (VOID *)(UINTN)SmmS3ResumeState->ReturnContext2,
+ (VOID *)(UINTN)SmmS3ResumeState->ReturnStackPointer
+ );
+ }
+
+ //
+ // If SMM is in 64-bit mode, then use AsmDisablePaging64() to resume PEI Phase
+ //
+ if (SmmS3ResumeState->Signature == SMM_S3_RESUME_SMM_64) {
+ DEBUG ((EFI_D_ERROR, "Call AsmDisablePaging64() to return to S3 Resume in PEI Phase\n"));
+ //
+ // Disable interrupt of Debug timer, since new IDT table is for IA32 and will not work in long mode.
+ //
+ SaveAndSetDebugTimerInterrupt (FALSE);
+ //
+ // Restore IA32 IDT table
+ //
+ AsmWriteIdtr ((IA32_DESCRIPTOR *) &Ia32Idtr);
+ AsmDisablePaging64 (
+ SmmS3ResumeState->ReturnCs,
+ (UINT32)SmmS3ResumeState->ReturnEntryPoint,
+ (UINT32)SmmS3ResumeState->ReturnContext1,
+ (UINT32)SmmS3ResumeState->ReturnContext2,
+ (UINT32)SmmS3ResumeState->ReturnStackPointer
+ );
+ }
+
+ //
+ // Can not resume PEI Phase
+ //
+ DEBUG ((EFI_D_ERROR, "No context to return to PEI Phase\n"));
+ CpuDeadLoop ();
+}
+
+/**
+ Copy register table from ACPI NVS memory into SMRAM.
+
+ @param[in] DestinationRegisterTableList Points to destination register table.
+ @param[in] SourceRegisterTableList Points to source register table.
+ @param[in] NumberOfCpus Number of CPUs.
+
+**/
+VOID
+CopyRegisterTable (
+ IN CPU_REGISTER_TABLE *DestinationRegisterTableList,
+ IN CPU_REGISTER_TABLE *SourceRegisterTableList,
+ IN UINT32 NumberOfCpus
+ )
+{
+ UINTN Index;
+
+ CopyMem (DestinationRegisterTableList, SourceRegisterTableList, NumberOfCpus * sizeof (CPU_REGISTER_TABLE));
+ for (Index = 0; Index < NumberOfCpus; Index++) {
+ DestinationRegisterTableList[Index].RegisterTableEntry = AllocatePool (DestinationRegisterTableList[Index].AllocatedSize);
+ ASSERT (DestinationRegisterTableList[Index].RegisterTableEntry != NULL);
+ if (DestinationRegisterTableList[Index].RegisterTableEntry == NULL) {
+ return;
+ }
+ CopyMem (DestinationRegisterTableList[Index].RegisterTableEntry, SourceRegisterTableList[Index].RegisterTableEntry, DestinationRegisterTableList[Index].AllocatedSize);
+ }
+}
+
+/**
+ Smm Ready To Lock event notification handler.
+
+ The CPU S3 data is copied to SMRAM for security. SMM Code Access Check feature is enabled if available.
+
+ @param[in] Protocol Points to the protocol's unique identifier.
+ @param[in] Interface Points to the interface instance.
+ @param[in] Handle The handle on which the interface was installed.
+
+ @retval EFI_SUCCESS Notification handler runs successfully.
+ **/
+EFI_STATUS
+EFIAPI
+SmmReadyToLockEventNotify (
+ IN CONST EFI_GUID *Protocol,
+ IN VOID *Interface,
+ IN EFI_HANDLE Handle
+ )
+{
+ ACPI_CPU_DATA *AcpiCpuData;
+ IA32_DESCRIPTOR *Gdtr;
+ IA32_DESCRIPTOR *Idtr;
+
+ //
+ // For a native platform, copy the CPU S3 data into SMRAM for security.
+ //
+ if (!FeaturePcdGet (PcdFrameworkCompatibilitySupport) && (PcdGet64 (PcdCpuS3DataAddress) != 0)) {
+ //
+ // Get CPU S3 data address
+ //
+ AcpiCpuData = (ACPI_CPU_DATA *)(UINTN)PcdGet64 (PcdCpuS3DataAddress);
+
+ //
+ // Copy CPU S3 data into SMRAM for use on CPU S3 Resume.
+ //
+ CopyMem (&mAcpiCpuData, AcpiCpuData, sizeof (mAcpiCpuData));
+
+ mAcpiCpuData.MtrrTable = (EFI_PHYSICAL_ADDRESS)(UINTN)AllocatePool (sizeof (MTRR_SETTINGS));
+ ASSERT (mAcpiCpuData.MtrrTable != 0);
+
+ CopyMem ((VOID *)(UINTN)mAcpiCpuData.MtrrTable, (VOID *)(UINTN)AcpiCpuData->MtrrTable, sizeof (MTRR_SETTINGS));
+
+ mAcpiCpuData.GdtrProfile = (EFI_PHYSICAL_ADDRESS)(UINTN)AllocatePool (sizeof (IA32_DESCRIPTOR));
+ ASSERT (mAcpiCpuData.GdtrProfile != 0);
+
+ CopyMem ((VOID *)(UINTN)mAcpiCpuData.GdtrProfile, (VOID *)(UINTN)AcpiCpuData->GdtrProfile, sizeof (IA32_DESCRIPTOR));
+
+ mAcpiCpuData.IdtrProfile = (EFI_PHYSICAL_ADDRESS)(UINTN)AllocatePool (sizeof (IA32_DESCRIPTOR));
+ ASSERT (mAcpiCpuData.IdtrProfile != 0);
+
+ CopyMem ((VOID *)(UINTN)mAcpiCpuData.IdtrProfile, (VOID *)(UINTN)AcpiCpuData->IdtrProfile, sizeof (IA32_DESCRIPTOR));
+
+ mAcpiCpuData.PreSmmInitRegisterTable = (EFI_PHYSICAL_ADDRESS)(UINTN)AllocatePool (mAcpiCpuData.NumberOfCpus * sizeof (CPU_REGISTER_TABLE));
+ ASSERT (mAcpiCpuData.PreSmmInitRegisterTable != 0);
+
+ CopyRegisterTable (
+ (CPU_REGISTER_TABLE *)(UINTN)mAcpiCpuData.PreSmmInitRegisterTable,
+ (CPU_REGISTER_TABLE *)(UINTN)AcpiCpuData->PreSmmInitRegisterTable,
+ mAcpiCpuData.NumberOfCpus
+ );
+
+ mAcpiCpuData.RegisterTable = (EFI_PHYSICAL_ADDRESS)(UINTN)AllocatePool (mAcpiCpuData.NumberOfCpus * sizeof (CPU_REGISTER_TABLE));
+ ASSERT (mAcpiCpuData.RegisterTable != 0);
+
+ CopyRegisterTable (
+ (CPU_REGISTER_TABLE *)(UINTN)mAcpiCpuData.RegisterTable,
+ (CPU_REGISTER_TABLE *)(UINTN)AcpiCpuData->RegisterTable,
+ mAcpiCpuData.NumberOfCpus
+ );
+
+ //
+ // Copy AP's GDT, IDT and Machine Check handler into SMRAM.
+ //
+ Gdtr = (IA32_DESCRIPTOR *)(UINTN)mAcpiCpuData.GdtrProfile;
+ Idtr = (IA32_DESCRIPTOR *)(UINTN)mAcpiCpuData.IdtrProfile;
+
+ mGdtForAp = AllocatePool ((Gdtr->Limit + 1) + (Idtr->Limit + 1) + mAcpiCpuData.ApMachineCheckHandlerSize);
+ ASSERT (mGdtForAp != NULL);
+ mIdtForAp = (VOID *) ((UINTN)mGdtForAp + (Gdtr->Limit + 1));
+ mMachineCheckHandlerForAp = (VOID *) ((UINTN)mIdtForAp + (Idtr->Limit + 1));
+
+ CopyMem (mGdtForAp, (VOID *)Gdtr->Base, Gdtr->Limit + 1);
+ CopyMem (mIdtForAp, (VOID *)Idtr->Base, Idtr->Limit + 1);
+ CopyMem (mMachineCheckHandlerForAp, (VOID *)(UINTN)mAcpiCpuData.ApMachineCheckHandlerBase, mAcpiCpuData.ApMachineCheckHandlerSize);
+ }
+
+ //
+ // Save the PcdCpuSmmCodeAccessCheckEnable value into a global variable.
+ //
+ mSmmCodeAccessCheckEnable = PcdGetBool (PcdCpuSmmCodeAccessCheckEnable);
+
+ //
+ // Set SMM ready to lock flag
+ //
+ mSmmReadyToLock = TRUE;
+ return EFI_SUCCESS;
+}
+
+/**
+ The module Entry Point of the CPU SMM driver.
+
+ @param ImageHandle The firmware allocated handle for the EFI image.
+ @param SystemTable A pointer to the EFI System Table.
+
+ @retval EFI_SUCCESS The entry point is executed successfully.
+ @retval Other Some error occurs when executing this entry point.
+
+**/
+EFI_STATUS
+EFIAPI
+PiCpuSmmEntry (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+ EFI_MP_SERVICES_PROTOCOL *MpServices;
+ UINTN NumberOfEnabledProcessors;
+ UINTN Index;
+ VOID *Buffer;
+ UINTN TileSize;
+ VOID *GuidHob;
+ EFI_SMRAM_DESCRIPTOR *SmramDescriptor;
+ SMM_S3_RESUME_STATE *SmmS3ResumeState;
+ UINT8 *Stacks;
+ VOID *Registration;
+
+ //
+ // Initialize Debug Agent to support source level debug in SMM code
+ //
+ InitializeDebugAgent (DEBUG_AGENT_INIT_SMM, NULL, NULL);
+
+ //
+ // Report thhe start of CPU SMM initialization.
+ //
+ REPORT_STATUS_CODE (
+ EFI_PROGRESS_CODE,
+ EFI_COMPUTING_UNIT_HOST_PROCESSOR | EFI_CU_HP_PC_SMM_INIT
+ );
+
+ //
+ // Fix segment address of the long-mode-switch jmp
+ //
+ if (sizeof (UINTN) == sizeof (UINT64)) {
+ gSmmJmpAddr.Segment = 8;
+ }
+
+ //
+ // Find out SMRR Base and Size and IED Base
+ //
+ FindSmramInfo (&mCpuHotPlugData.SmrrBase, &mCpuHotPlugData.SmrrSize);
+
+ //
+ // Get MP Services Protocol
+ //
+ Status = SystemTable->BootServices->LocateProtocol (&gEfiMpServiceProtocolGuid, NULL, (VOID **)&MpServices);
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Use MP Services Protocol to retrieve the number of processors and number of enabled processors
+ //
+ Status = MpServices->GetNumberOfProcessors (MpServices, &mNumberOfCpus, &NumberOfEnabledProcessors);
+ ASSERT_EFI_ERROR (Status);
+ ASSERT (mNumberOfCpus <= FixedPcdGet32 (PcdCpuMaxLogicalProcessorNumber));
+
+ //
+ // If support CPU hot plug, PcdCpuSmmEnableBspElection should be set to TRUE.
+ // A constant BSP index makes no sense because it may be hot removed.
+ //
+ DEBUG_CODE (
+ if (FeaturePcdGet (PcdCpuHotPlugSupport)) {
+
+ ASSERT (FeaturePcdGet (PcdCpuSmmEnableBspElection));
+ }
+ );
+
+ //
+ // If support CPU hot plug, we need to allocate resources for possibly hot-added processors
+ //
+ if (FeaturePcdGet (PcdCpuHotPlugSupport)) {
+ mMaxNumberOfCpus = PcdGet32 (PcdCpuMaxLogicalProcessorNumber);
+ } else {
+ mMaxNumberOfCpus = mNumberOfCpus;
+ }
+ gSmmCpuPrivate->SmmCoreEntryContext.NumberOfCpus = mMaxNumberOfCpus;
+
+ //
+ // The CPU save state and code for the SMI entry point are tiled within an SMRAM
+ // allocated buffer. The miniumu size of this buffer for a uniprocessor system
+ // is 32 KB, because the entry point is SMBASE + 32KB, and CPU save state area
+ // just below SMBASE + 64KB. If more than one CPU is present in the platform,
+ // then the SMI entry point and the CPU save state areas can be tiles to minimize
+ // the total amount SMRAM required for all the CPUs. The tile size can be computed
+ // by adding the // CPU save state size, any extra CPU specific context, and
+ // the size of code that must be placed at the SMI entry point to transfer
+ // control to a C function in the native SMM execution mode. This size is
+ // rounded up to the nearest power of 2 to give the tile size for a each CPU.
+ // The total amount of memory required is the maximum number of CPUs that
+ // platform supports times the tile size. The picture below shows the tiling,
+ // where m is the number of tiles that fit in 32KB.
+ //
+ // +-----------------------------+ <-- 2^n offset from Base of allocated buffer
+ // | CPU m+1 Save State |
+ // +-----------------------------+
+ // | CPU m+1 Extra Data |
+ // +-----------------------------+
+ // | Padding |
+ // +-----------------------------+
+ // | CPU 2m SMI Entry |
+ // +#############################+ <-- Base of allocated buffer + 64 KB
+ // | CPU m-1 Save State |
+ // +-----------------------------+
+ // | CPU m-1 Extra Data |
+ // +-----------------------------+
+ // | Padding |
+ // +-----------------------------+
+ // | CPU 2m-1 SMI Entry |
+ // +=============================+ <-- 2^n offset from Base of allocated buffer
+ // | . . . . . . . . . . . . |
+ // +=============================+ <-- 2^n offset from Base of allocated buffer
+ // | CPU 2 Save State |
+ // +-----------------------------+
+ // | CPU 2 Extra Data |
+ // +-----------------------------+
+ // | Padding |
+ // +-----------------------------+
+ // | CPU m+1 SMI Entry |
+ // +=============================+ <-- Base of allocated buffer + 32 KB
+ // | CPU 1 Save State |
+ // +-----------------------------+
+ // | CPU 1 Extra Data |
+ // +-----------------------------+
+ // | Padding |
+ // +-----------------------------+
+ // | CPU m SMI Entry |
+ // +#############################+ <-- Base of allocated buffer + 32 KB == CPU 0 SMBASE + 64 KB
+ // | CPU 0 Save State |
+ // +-----------------------------+
+ // | CPU 0 Extra Data |
+ // +-----------------------------+
+ // | Padding |
+ // +-----------------------------+
+ // | CPU m-1 SMI Entry |
+ // +=============================+ <-- 2^n offset from Base of allocated buffer
+ // | . . . . . . . . . . . . |
+ // +=============================+ <-- 2^n offset from Base of allocated buffer
+ // | Padding |
+ // +-----------------------------+
+ // | CPU 1 SMI Entry |
+ // +=============================+ <-- 2^n offset from Base of allocated buffer
+ // | Padding |
+ // +-----------------------------+
+ // | CPU 0 SMI Entry |
+ // +#############################+ <-- Base of allocated buffer == CPU 0 SMBASE + 32 KB
+ //
+
+ //
+ // Compute tile size of buffer required to hold CPU save state, any extra CPU
+ // specific context, and the SMI entry point. This size of rounded up to
+ // nearest power of 2.
+ //
+ TileSize = 2 * GetPowerOfTwo32 (sizeof (SOCKET_LGA_775_SMM_CPU_STATE) + sizeof (PROCESSOR_SMM_DESCRIPTOR) + gcSmiHandlerSize - 1);
+
+ //
+ // Allocate buffer for all of the tiles.
+ //
+ Buffer = AllocatePages (EFI_SIZE_TO_PAGES (SIZE_32KB + TileSize * (mMaxNumberOfCpus - 1)));
+ ASSERT (Buffer != NULL);
+
+ //
+ // Allocate buffer for pointers to array in CPU_HOT_PLUG_DATA.
+ //
+ mCpuHotPlugData.ApicId = (UINT64 *)AllocatePool (sizeof (UINT64) * mMaxNumberOfCpus);
+ ASSERT (mCpuHotPlugData.ApicId != NULL);
+ mCpuHotPlugData.SmBase = (UINTN *)AllocatePool (sizeof (UINTN) * mMaxNumberOfCpus);
+ ASSERT (mCpuHotPlugData.SmBase != NULL);
+ mCpuHotPlugData.ArrayLength = (UINT32)mMaxNumberOfCpus;
+
+ //
+ // Retrieve APIC ID of each enabled processor from the MP Services protocol.
+ // Also compute the SMBASE address, CPU Save State address, and CPU Save state
+ // size for each CPU in the platform
+ //
+ for (Index = 0; Index < mMaxNumberOfCpus; Index++) {
+ mCpuHotPlugData.SmBase[Index] = (UINTN)Buffer + Index * TileSize - SIZE_32KB;
+ gSmmCpuPrivate->CpuSaveStateSize[Index] = sizeof(SOCKET_LGA_775_SMM_CPU_STATE);
+ gSmmCpuPrivate->CpuSaveState[Index] = (VOID *)(mCpuHotPlugData.SmBase[Index] + SIZE_64KB - gSmmCpuPrivate->CpuSaveStateSize[Index]);
+ gSmmCpuPrivate->Operation[Index] = SmmCpuNone;
+
+ if (Index < mNumberOfCpus) {
+ Status = MpServices->GetProcessorInfo (MpServices, Index, &gSmmCpuPrivate->ProcessorInfo[Index]);
+ ASSERT_EFI_ERROR (Status);
+ mCpuHotPlugData.ApicId[Index] = gSmmCpuPrivate->ProcessorInfo[Index].ProcessorId;
+
+ DEBUG ((EFI_D_ERROR, "CPU[%03x] APIC ID=%04x SMBASE=%08x SaveState=%08x Size=%08x\n",
+ Index,
+ (UINT32)gSmmCpuPrivate->ProcessorInfo[Index].ProcessorId,
+ mCpuHotPlugData.SmBase[Index],
+ gSmmCpuPrivate->CpuSaveState[Index],
+ gSmmCpuPrivate->CpuSaveStateSize[Index]
+ ));
+ } else {
+ gSmmCpuPrivate->ProcessorInfo[Index].ProcessorId = INVALID_APIC_ID;
+ mCpuHotPlugData.ApicId[Index] = INVALID_APIC_ID;
+ }
+ }
+
+ //
+ // Allocate SMI stacks for all processors.
+ //
+ if (FeaturePcdGet (PcdCpuSmmStackGuard)) {
+ //
+ // 2 more pages is allocated for each processor.
+ // one is guard page and the other is known good stack.
+ //
+ // +-------------------------------------------+-----+-------------------------------------------+
+ // | Known Good Stack | Guard Page | SMM Stack | ... | Known Good Stack | Guard Page | SMM Stack |
+ // +-------------------------------------------+-----+-------------------------------------------+
+ // | | | |
+ // |<-------------- Processor 0 -------------->| |<-------------- Processor n -------------->|
+ //
+ mSmmStackSize = EFI_PAGES_TO_SIZE (EFI_SIZE_TO_PAGES (PcdGet32 (PcdCpuSmmStackSize)) + 2);
+ Stacks = (UINT8 *) AllocatePages (gSmmCpuPrivate->SmmCoreEntryContext.NumberOfCpus * (EFI_SIZE_TO_PAGES (PcdGet32 (PcdCpuSmmStackSize)) + 2));
+ ASSERT (Stacks != NULL);
+ mSmmStackArrayBase = (UINTN)Stacks;
+ mSmmStackArrayEnd = mSmmStackArrayBase + gSmmCpuPrivate->SmmCoreEntryContext.NumberOfCpus * mSmmStackSize - 1;
+ } else {
+ mSmmStackSize = PcdGet32 (PcdCpuSmmStackSize);
+ Stacks = (UINT8 *) AllocatePages (EFI_SIZE_TO_PAGES (gSmmCpuPrivate->SmmCoreEntryContext.NumberOfCpus * mSmmStackSize));
+ ASSERT (Stacks != NULL);
+ }
+
+ //
+ // Set SMI stack for SMM base relocation
+ //
+ gSmmInitStack = (UINTN) (Stacks + mSmmStackSize - sizeof (UINTN));
+
+ //
+ // PcdGetXXX() functions can't be used in SmmRelocateBases() called in both normal and S3 boot path.
+ // Related PCD values are retrieved into global variables.
+ //
+
+ mSmmUseDelayIndication = PcdGetBool (PcdCpuSmmUseDelayIndication);
+ mSmmUseBlockIndication = PcdGetBool (PcdCpuSmmUseBlockIndication);
+
+ //
+ // Relocate SMM Base addresses to the ones allocated from SMRAM
+ // BUGBUG: Work on later
+ //
+ SmmRelocateBases ();
+
+ //
+ // SMM Init
+ // BUGBUG: Work on later
+ //
+ InitializeSmmTimer ();
+
+ //
+ // Initialize IDT
+ // BUGBUG: Work on later
+ //
+ InitializeIDT ();
+
+ SetMem (mExternalVectorTable, sizeof(mExternalVectorTable), 0);
+ //
+ // Set the pointer to the array of C based exception handling routines.
+ //
+ InitializeSmmExternalVectorTablePtr (mExternalVectorTable);
+
+ //
+ // Initialize MP globals
+ //
+ InitializeMpServiceData (ImageHandle, Stacks, mSmmStackSize);
+
+ //
+ // Fill in SMM Reserved Regions
+ //
+ gSmmCpuPrivate->SmmReservedSmramRegion[0].SmramReservedStart = 0;
+ gSmmCpuPrivate->SmmReservedSmramRegion[0].SmramReservedSize = 0;
+
+ //
+ // Install the SMM Configuration Protocol onto a new handle on the handle database.
+ // The entire SMM Configuration Protocol is allocated from SMRAM, so only a pointer
+ // to an SMRAM address will be present in the handle database
+ //
+ Status = SystemTable->BootServices->InstallMultipleProtocolInterfaces (
+ &gSmmCpuPrivate->SmmCpuHandle,
+ &gEfiSmmConfigurationProtocolGuid, &gSmmCpuPrivate->SmmConfiguration,
+ NULL
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Install the SMM CPU Protocol into SMM protocol database
+ //
+ Status = gSmst->SmmInstallProtocolInterface (
+ &mSmmCpuHandle,
+ &gEfiSmmCpuProtocolGuid,
+ EFI_NATIVE_INTERFACE,
+ &mSmmCpu
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Install Smm CPU Sync protocol
+ //
+ Status = gSmst->SmmInstallProtocolInterface (
+ &mSmmCpuHandle,
+ &gSmmCpuSyncProtocolGuid,
+ EFI_NATIVE_INTERFACE,
+ &mSmmCpuSync
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Install Smm CPU Sync2 protocol
+ //
+ Status = gSmst->SmmInstallProtocolInterface (
+ &mSmmCpuHandle,
+ &gSmmCpuSync2ProtocolGuid,
+ EFI_NATIVE_INTERFACE,
+ &mSmmCpuSync2
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Expose address of CPU Hot Plug Data structure if CPU hot plug is supported.
+ //
+ if (FeaturePcdGet (PcdCpuHotPlugSupport)) {
+ PcdSet64 (PcdCpuHotPlugDataAddress, (UINT64)(UINTN)&mCpuHotPlugData);
+ }
+
+ //
+ // Initialize SMM CPU Services Support
+ //
+ Status = InitializeSmmCpuServices (mSmmCpuHandle);
+ ASSERT_EFI_ERROR (Status);
+
+ if (FeaturePcdGet (PcdFrameworkCompatibilitySupport)) {
+ //
+ // Install Framework SMM Save State Protocol into UEFI protocol database for backward compatibility
+ //
+ Status = SystemTable->BootServices->InstallMultipleProtocolInterfaces (
+ &gSmmCpuPrivate->SmmCpuHandle,
+ &gEfiSmmCpuSaveStateProtocolGuid,
+ &mSmmCpuSaveState,
+ NULL
+ );
+ ASSERT_EFI_ERROR (Status);
+ //
+ // The SmmStartupThisAp service in Framework SMST should always be non-null.
+ // Update SmmStartupThisAp pointer in PI SMST here so that PI/Framework SMM thunk
+ // can have it ready when constructing Framework SMST.
+ //
+ gSmst->SmmStartupThisAp = SmmStartupThisAp;
+ }
+
+ //
+ // register SMM Ready To Lock Protocol notification
+ //
+ Status = gSmst->SmmRegisterProtocolNotify (
+ &gEfiSmmReadyToLockProtocolGuid,
+ SmmReadyToLockEventNotify,
+ &Registration
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ GuidHob = GetFirstGuidHob (&gEfiAcpiVariableGuid);
+ if (GuidHob != NULL) {
+ SmramDescriptor = (EFI_SMRAM_DESCRIPTOR *) GET_GUID_HOB_DATA (GuidHob);
+
+ DEBUG ((EFI_D_ERROR, "SMM S3 SMRAM Structure = %x\n", SmramDescriptor));
+ DEBUG ((EFI_D_ERROR, "SMM S3 Structure = %x\n", SmramDescriptor->CpuStart));
+
+ SmmS3ResumeState = (SMM_S3_RESUME_STATE *)(UINTN)SmramDescriptor->CpuStart;
+ ZeroMem (SmmS3ResumeState, sizeof (SMM_S3_RESUME_STATE));
+
+ mSmmS3ResumeState = SmmS3ResumeState;
+ SmmS3ResumeState->Smst = (EFI_PHYSICAL_ADDRESS)(UINTN)gSmst;
+
+ SmmS3ResumeState->SmmS3ResumeEntryPoint = (EFI_PHYSICAL_ADDRESS)(UINTN)SmmRestoreCpu;
+
+ SmmS3ResumeState->SmmS3StackSize = SIZE_32KB;
+ SmmS3ResumeState->SmmS3StackBase = (EFI_PHYSICAL_ADDRESS)(UINTN)AllocatePages (EFI_SIZE_TO_PAGES ((UINTN)SmmS3ResumeState->SmmS3StackSize));
+ if (SmmS3ResumeState->SmmS3StackBase == 0) {
+ SmmS3ResumeState->SmmS3StackSize = 0;
+ }
+
+ SmmS3ResumeState->SmmS3Cr0 = gSmmCr0;
+ SmmS3ResumeState->SmmS3Cr3 = gSmiCr3;
+ SmmS3ResumeState->SmmS3Cr4 = gSmmCr4;
+
+ if (sizeof (UINTN) == sizeof (UINT64)) {
+ SmmS3ResumeState->Signature = SMM_S3_RESUME_SMM_64;
+ }
+ if (sizeof (UINTN) == sizeof (UINT32)) {
+ SmmS3ResumeState->Signature = SMM_S3_RESUME_SMM_32;
+ }
+ }
+ if (FeaturePcdGet (PcdCpuSmmProfileEnable)) {
+ InitSmmProfile ();
+ }
+ DEBUG ((EFI_D_ERROR, "SMM CPU Module exit from SMRAM with EFI_SUCCESS\n"));
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Find out SMRAM information including SMRR base, SMRR size.
+
+ @param SmrrBase SMRR base
+ @param SmrrSize SMRR size
+
+**/
+VOID
+FindSmramInfo (
+ OUT UINT32 *SmrrBase,
+ OUT UINT32 *SmrrSize
+ )
+{
+ EFI_STATUS Status;
+ UINTN Size;
+ EFI_SMM_ACCESS2_PROTOCOL *SmmAccess;
+ EFI_SMRAM_DESCRIPTOR *CurrentSmramRange;
+ EFI_SMRAM_DESCRIPTOR *SmramRanges;
+ UINTN SmramRangeCount;
+ UINTN Index;
+ UINT64 MaxSize;
+ BOOLEAN Found;
+
+ //
+ // Get SMM Access Protocol
+ //
+ Status = gBS->LocateProtocol (&gEfiSmmAccess2ProtocolGuid, NULL, (VOID **)&SmmAccess);
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Get SMRAM information
+ //
+ Size = 0;
+ Status = SmmAccess->GetCapabilities (SmmAccess, &Size, NULL);
+ ASSERT (Status == EFI_BUFFER_TOO_SMALL);
+
+ SmramRanges = (EFI_SMRAM_DESCRIPTOR *)AllocatePool (Size);
+ ASSERT (SmramRanges != NULL);
+
+ Status = SmmAccess->GetCapabilities (SmmAccess, &Size, SmramRanges);
+ ASSERT_EFI_ERROR (Status);
+
+ SmramRangeCount = Size / sizeof (EFI_SMRAM_DESCRIPTOR);
+
+ //
+ // Find the largest SMRAM range between 1MB and 4GB that is at least 256K - 4K in size
+ //
+ CurrentSmramRange = NULL;
+ for (Index = 0, MaxSize = SIZE_256KB - EFI_PAGE_SIZE; Index < SmramRangeCount; Index++) {
+ //
+ // Skip any SMRAM region that is already allocated, needs testing, or needs ECC initialization
+ //
+ if ((SmramRanges[Index].RegionState & (EFI_ALLOCATED | EFI_NEEDS_TESTING | EFI_NEEDS_ECC_INITIALIZATION)) != 0) {
+ continue;
+ }
+
+ if (SmramRanges[Index].CpuStart >= BASE_1MB) {
+ if ((SmramRanges[Index].CpuStart + SmramRanges[Index].PhysicalSize) <= BASE_4GB) {
+ if (SmramRanges[Index].PhysicalSize >= MaxSize) {
+ MaxSize = SmramRanges[Index].PhysicalSize;
+ CurrentSmramRange = &SmramRanges[Index];
+ }
+ }
+ }
+ }
+
+ ASSERT (CurrentSmramRange != NULL);
+
+ *SmrrBase = (UINT32)CurrentSmramRange->CpuStart;
+ *SmrrSize = (UINT32)CurrentSmramRange->PhysicalSize;
+
+ do {
+ Found = FALSE;
+ for (Index = 0; Index < SmramRangeCount; Index++) {
+ if (SmramRanges[Index].CpuStart < *SmrrBase && *SmrrBase == (SmramRanges[Index].CpuStart + SmramRanges[Index].PhysicalSize)) {
+ *SmrrBase = (UINT32)SmramRanges[Index].CpuStart;
+ *SmrrSize = (UINT32)(*SmrrSize + SmramRanges[Index].PhysicalSize);
+ Found = TRUE;
+ } else if ((*SmrrBase + *SmrrSize) == SmramRanges[Index].CpuStart && SmramRanges[Index].PhysicalSize > 0) {
+ *SmrrSize = (UINT32)(*SmrrSize + SmramRanges[Index].PhysicalSize);
+ Found = TRUE;
+ }
+ }
+ } while (Found);
+
+ DEBUG ((DEBUG_INFO, "SMRR Base: 0x%x, SMRR Size: 0x%x\n", *SmrrBase, *SmrrSize));
+}
+
+/**
+ Perform the remaining tasks.
+
+**/
+VOID
+PerformRemainingTasks (
+ VOID
+ )
+{
+ if (mSmmReadyToLock) {
+ //
+ // Start SMM Profile feature
+ //
+ if (FeaturePcdGet (PcdCpuSmmProfileEnable)) {
+ SmmProfileStart ();
+ }
+ //
+ // Configure SMM Code Access Check feature if available.
+ //
+ if (mSmmCodeAccessCheckEnable || FeaturePcdGet (PcdCpuSmmFeatureControlMsrLock)) {
+ ConfigSmmCodeAccessCheck ();
+ }
+
+ //
+ // Clean SMM ready to lock flag
+ //
+ mSmmReadyToLock = FALSE;
+ }
+}
diff --git a/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.h b/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.h
new file mode 100644
index 0000000000..39c7ba5049
--- /dev/null
+++ b/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.h
@@ -0,0 +1,780 @@
+/** @file
+ Agent Module to load other modules to deploy SMM Entry Vector for X86 CPU.
+
+ Copyright (c) 2009 - 2015, 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 _CPU_PISMMCPUDXESMM_H_
+#define _CPU_PISMMCPUDXESMM_H_
+#include <PiSmm.h>
+#include <AcpiCpuData.h>
+
+#include <Protocol/MpService.h>
+#include <Protocol/SmmConfiguration.h>
+#include <Protocol/SmmCpu.h>
+#include <Protocol/SmmAccess2.h>
+#include <Protocol/SmmCpuSaveState.h>
+#include <Protocol/SmmReadyToLock.h>
+#include <Protocol/SmmCpuSync.h>
+#include <Protocol/SmmCpuSync2.h>
+#include <Protocol/SmmCpuService.h>
+
+#include <Guid/AcpiS3Context.h>
+
+#include <Library/BaseLib.h>
+#include <Library/IoLib.h>
+#include <Library/TimerLib.h>
+#include <Library/SmmLib.h>
+#include <Library/SynchronizationLib.h>
+#include <Library/DebugLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/PcdLib.h>
+#include <Library/CacheMaintenanceLib.h>
+#include <Library/MtrrLib.h>
+#include <Library/SocketLga775Lib.h>
+#include <Library/SmmCpuPlatformHookLib.h>
+#include <Library/SmmServicesTableLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiRuntimeServicesTableLib.h>
+#include <Library/DebugAgentLib.h>
+#include <Library/HobLib.h>
+#include <Library/CpuConfigLib.h>
+#include <Library/LocalApicLib.h>
+#include <Library/UefiCpuLib.h>
+#include <Library/ReportStatusCodeLib.h>
+
+#include <CpuHotPlugData.h>
+
+#include "SmmFeatures.h"
+#include "CpuService.h"
+#include "SmmProfile.h"
+
+//
+// Size of Task-State Segment defined in IA32 Manual
+//
+#define TSS_SIZE 104
+#define TSS_X64_IST1_OFFSET 36
+#define TSS_IA32_CR3_OFFSET 28
+#define TSS_IA32_ESP_OFFSET 56
+
+//
+// The size 0x20 must be bigger than
+// the size of template code of SmmInit. Currently,
+// the size of SmmInit requires the 0x16 Bytes buffer
+// at least.
+//
+#define BACK_BUF_SIZE 0x20
+
+#define EXCEPTION_VECTOR_NUMBER 0x20
+
+#define INVALID_APIC_ID 0xFFFFFFFFFFFFFFFFULL
+
+//
+// SMM CPU synchronization features available on a processor
+//
+typedef struct {
+ BOOLEAN DelayIndicationSupported;
+ BOOLEAN BlockIndicationSupported;
+ //
+ // This processor's LOG_PROC_EN bit used in SMM_DELAYED, and SMM_BLOCKED MSRs
+ // (introduced in Haswell processor).
+ // Value of "-1" indicates this field is invalid (i.e. LOG_PROC_EN bit is not
+ // supported)
+ //
+ UINT64 HaswellLogProcEnBit;
+} SMM_CPU_SYNC_FEATURE;
+
+typedef UINT32 SMM_CPU_ARRIVAL_EXCEPTIONS;
+#define ARRIVAL_EXCEPTION_BLOCKED 0x1
+#define ARRIVAL_EXCEPTION_DELAYED 0x2
+#define ARRIVAL_EXCEPTION_SMI_DISABLED 0x4
+
+//
+// Private structure for the SMM CPU module that is stored in DXE Runtime memory
+// Contains the SMM Configuration Protocols that is produced.
+// Contains a mix of DXE and SMM contents. All the fields must be used properly.
+//
+#define SMM_CPU_PRIVATE_DATA_SIGNATURE SIGNATURE_32 ('s', 'c', 'p', 'u')
+
+typedef struct {
+ UINTN Signature;
+
+ EFI_HANDLE SmmCpuHandle;
+
+ EFI_PROCESSOR_INFORMATION ProcessorInfo [FixedPcdGet32 (PcdCpuMaxLogicalProcessorNumber)];
+ SMM_CPU_OPERATION Operation [FixedPcdGet32 (PcdCpuMaxLogicalProcessorNumber)];
+ UINTN CpuSaveStateSize [FixedPcdGet32 (PcdCpuMaxLogicalProcessorNumber)];
+ VOID *CpuSaveState [FixedPcdGet32 (PcdCpuMaxLogicalProcessorNumber)];
+ UINT64 TstateMsr [FixedPcdGet32 (PcdCpuMaxLogicalProcessorNumber)];
+ SMM_CPU_SYNC_FEATURE SmmSyncFeature [FixedPcdGet32 (PcdCpuMaxLogicalProcessorNumber)];
+
+ EFI_SMM_RESERVED_SMRAM_REGION SmmReservedSmramRegion[1];
+ EFI_SMM_ENTRY_CONTEXT SmmCoreEntryContext;
+ EFI_SMM_ENTRY_POINT SmmCoreEntry;
+
+ EFI_SMM_CONFIGURATION_PROTOCOL SmmConfiguration;
+} SMM_CPU_PRIVATE_DATA;
+
+extern SMM_CPU_PRIVATE_DATA *gSmmCpuPrivate;
+extern CPU_HOT_PLUG_DATA mCpuHotPlugData;
+extern UINTN mMaxNumberOfCpus;
+extern UINTN mNumberOfCpus;
+extern volatile BOOLEAN mRebased[FixedPcdGet32 (PcdCpuMaxLogicalProcessorNumber)];
+extern UINT32 gSmbase;
+extern BOOLEAN mRestoreSmmConfigurationInS3;
+extern EFI_SMM_CPU_PROTOCOL mSmmCpu;
+
+//
+// SMM CPU Protocol function prototypes.
+//
+
+/**
+ Read information from the CPU save state.
+
+ @param This EFI_SMM_CPU_PROTOCOL instance
+ @param Widthe The number of bytes to read from the CPU save state.
+ @param Register Specifies the CPU register to read form the save state.
+ @param CpuIndex Specifies the zero-based index of the CPU save state
+ @param Buffer Upon return, this holds the CPU register value read from the save state.
+
+ @retval EFI_SUCCESS The register was read from Save State
+ @retval EFI_NOT_FOUND The register is not defined for the Save State of Processor
+ @retval EFI_INVALID_PARAMTER This or Buffer is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+SmmReadSaveState (
+ IN CONST EFI_SMM_CPU_PROTOCOL *This,
+ IN UINTN Width,
+ IN EFI_SMM_SAVE_STATE_REGISTER Register,
+ IN UINTN CpuIndex,
+ OUT VOID *Buffer
+ );
+
+/**
+ Write data to the CPU save state.
+
+ @param This EFI_SMM_CPU_PROTOCOL instance
+ @param Widthe The number of bytes to read from the CPU save state.
+ @param Register Specifies the CPU register to write to the save state.
+ @param CpuIndex Specifies the zero-based index of the CPU save state
+ @param Buffer Upon entry, this holds the new CPU register value.
+
+ @retval EFI_SUCCESS The register was written from Save State
+ @retval EFI_NOT_FOUND The register is not defined for the Save State of Processor
+ @retval EFI_INVALID_PARAMTER ProcessorIndex or Width is not correct
+
+**/
+EFI_STATUS
+EFIAPI
+SmmWriteSaveState (
+ IN CONST EFI_SMM_CPU_PROTOCOL *This,
+ IN UINTN Width,
+ IN EFI_SMM_SAVE_STATE_REGISTER Register,
+ IN UINTN CpuIndex,
+ IN CONST VOID *Buffer
+ );
+
+//
+// SMM CPU Sync Protocol and SMM CPU Sync2 Protocol function prototypes.
+//
+
+/**
+ Given timeout constraint, wait for all APs to arrive. If this function returns EFI_SUCCESS, then
+ no AP will execute normal mode code before entering SMM, so it is safe to access shared hardware resource
+ between SMM and normal mode. Note if there are SMI disabled APs, this function will return EFI_NOT_READY.
+
+ @param This A pointer to the SMM_CPU_SYNC_PROTOCOL instance.
+
+ @retval EFI_SUCCESS No AP will execute normal mode code before entering SMM, so it is safe to access
+ shared hardware resource between SMM and normal mode
+ @retval EFI_NOT_READY One or more CPUs may still execute normal mode code
+ @retval EFI_DEVICE_ERROR Error occured in obtaining CPU status.
+
+**/
+EFI_STATUS
+EFIAPI
+SmmCpuSyncCheckApArrival (
+ IN SMM_CPU_SYNC_PROTOCOL *This
+ );
+
+/**
+ Given timeout constraint, wait for all APs to arrive. If this function returns EFI_SUCCESS, then
+ no AP will execute normal mode code before entering SMM, so it is safe to access shared hardware resource
+ between SMM and normal mode. Note if there are SMI disabled APs, this function will return EFI_NOT_READY.
+
+ @param This A pointer to the SMM_CPU_SYNC_PROTOCOL instance.
+
+ @retval EFI_SUCCESS No AP will execute normal mode code before entering SMM, so it is safe to access
+ shared hardware resource between SMM and normal mode
+ @retval EFI_NOT_READY One or more CPUs may still execute normal mode code
+ @retval EFI_DEVICE_ERROR Error occured in obtaining CPU status.
+
+**/
+EFI_STATUS
+EFIAPI
+SmmCpuSync2CheckApArrival (
+ IN SMM_CPU_SYNC2_PROTOCOL *This
+ );
+
+/**
+ Set SMM synchronization mode starting from the next SMI run.
+
+ @param This A pointer to the SMM_CPU_SYNC_PROTOCOL instance.
+ @param SyncMode The SMM synchronization mode to be set and effective from the next SMI run.
+
+ @retval EFI_SUCCESS The function completes successfully.
+ @retval EFI_INVALID_PARAMETER SynMode is not valid.
+
+**/
+EFI_STATUS
+EFIAPI
+SmmCpuSyncSetMode (
+ IN SMM_CPU_SYNC_PROTOCOL *This,
+ IN SMM_CPU_SYNC_MODE SyncMode
+ );
+
+/**
+ Set SMM synchronization mode starting from the next SMI run.
+
+ @param This A pointer to the SMM_CPU_SYNC_PROTOCOL instance.
+ @param SyncMode The SMM synchronization mode to be set and effective from the next SMI run.
+
+ @retval EFI_SUCCESS The function completes successfully.
+ @retval EFI_INVALID_PARAMETER SynMode is not valid.
+
+**/
+EFI_STATUS
+EFIAPI
+SmmCpuSync2SetMode (
+ IN SMM_CPU_SYNC2_PROTOCOL *This,
+ IN SMM_CPU_SYNC_MODE SyncMode
+ );
+
+/**
+ Get current effective SMM synchronization mode.
+
+ @param This A pointer to the SMM_CPU_SYNC_PROTOCOL instance.
+ @param SyncMode Output parameter. The current effective SMM synchronization mode.
+
+ @retval EFI_SUCCESS The SMM synchronization mode has been retrieved successfully.
+ @retval EFI_INVALID_PARAMETER SyncMode is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+SmmCpuSyncGetMode (
+ IN SMM_CPU_SYNC_PROTOCOL *This,
+ OUT SMM_CPU_SYNC_MODE *SyncMode
+ );
+
+/**
+ Get current effective SMM synchronization mode.
+
+ @param This A pointer to the SMM_CPU_SYNC_PROTOCOL instance.
+ @param SyncMode Output parameter. The current effective SMM synchronization mode.
+
+ @retval EFI_SUCCESS The SMM synchronization mode has been retrieved successfully.
+ @retval EFI_INVALID_PARAMETER SyncMode is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+SmmCpuSync2GetMode (
+ IN SMM_CPU_SYNC2_PROTOCOL *This,
+ OUT SMM_CPU_SYNC_MODE *SyncMode
+ );
+
+/**
+ Checks CPU SMM synchronization state
+
+ @param This A pointer to the SMM_CPU_SYNC_PROTOCOL instance.
+ @param CpuIndex Index of the CPU for which the state is to be retrieved.
+ @param CpuState The state of the CPU
+
+ @retval EFI_SUCCESS Returns EFI_SUCCESS if the CPU's state is retrieved.
+ @retval EFI_INVALID_PARAMETER Returns EFI_INVALID_PARAMETER if CpuIndex is invalid or CpuState is NULL
+ @retval EFI_DEVICE_ERROR Error occured in obtaining CPU status.
+**/
+EFI_STATUS
+EFIAPI
+SmmCpuSync2CheckCpuState (
+ IN SMM_CPU_SYNC2_PROTOCOL *This,
+ IN UINTN CpuIndex,
+ OUT SMM_CPU_SYNC2_CPU_STATE *CpuState
+ );
+
+/**
+ Change CPU's SMM enabling state.
+
+ @param This A pointer to the SMM_CPU_SYNC_PROTOCOL instance.
+ @param CpuIndex Index of the CPU to enable / disable SMM
+ @param Enable If TRUE, enable SMM; if FALSE disable SMM
+
+ @retval EFI_SUCCESS The CPU's SMM enabling state is changed.
+ @retval EFI_INVALID_PARAMETER Returns EFI_INVALID_PARAMETER if CpuIndex is invalid
+ @retval EFI_UNSUPPORTED Returns EFI_UNSUPPORTED the CPU does not support dynamically enabling / disabling SMI
+ @retval EFI_DEVICE_ERROR Error occured in changing SMM enabling state.
+**/
+EFI_STATUS
+EFIAPI
+SmmCpuSync2ChangeSmmEnabling (
+ IN SMM_CPU_SYNC2_PROTOCOL *This,
+ IN UINTN CpuIndex,
+ IN BOOLEAN Enable
+ );
+
+/**
+ Send SMI IPI to a specific CPU.
+
+ @param This A pointer to the SMM_CPU_SYNC_PROTOCOL instance.
+ @param CpuIndex Index of the CPU to send SMI to.
+
+ @retval EFI_SUCCESS The SMI IPI is sent successfully.
+ @retval EFI_INVALID_PARAMETER Returns EFI_INVALID_PARAMETER if CpuIndex is invalid
+ @retval EFI_DEVICE_ERROR Error occured in sending SMI IPI.
+**/
+EFI_STATUS
+EFIAPI
+SmmCpuSync2SendSmi (
+ IN SMM_CPU_SYNC2_PROTOCOL *This,
+ IN UINTN CpuIndex
+ );
+
+/**
+ Send SMI IPI to all CPUs excluding self
+
+ @param This A pointer to the SMM_CPU_SYNC_PROTOCOL instance.
+
+ @retval EFI_SUCCESS The SMI IPI is sent successfully.
+ @retval EFI_INVALID_PARAMETER Returns EFI_INVALID_PARAMETER if CpuIndex is invalid
+ @retval EFI_DEVICE_ERROR Error occured in sending SMI IPI.
+**/
+EFI_STATUS
+EFIAPI
+SmmCpuSync2SendSmiAllExcludingSelf (
+ IN SMM_CPU_SYNC2_PROTOCOL *This
+ );
+
+///
+/// Structure used to describe a range of registers
+///
+typedef struct {
+ EFI_SMM_SAVE_STATE_REGISTER Start;
+ EFI_SMM_SAVE_STATE_REGISTER End;
+ UINTN Length;
+} CPU_SMM_SAVE_STATE_REGISTER_RANGE;
+
+///
+/// Structure used to build a lookup table to retrieve the widths and offsets
+/// associated with each supported EFI_SMM_SAVE_STATE_REGISTER value
+///
+
+#define SMM_SAVE_STATE_REGISTER_SMMREVID_INDEX 1
+#define SMM_SAVE_STATE_REGISTER_IOMISC_INDEX 2
+#define SMM_SAVE_STATE_REGISTER_IOMEMADDR_INDEX 3
+#define SMM_SAVE_STATE_REGISTER_MAX_INDEX 4
+
+typedef struct {
+ UINT8 Width32;
+ UINT8 Width64;
+ UINT16 Offset32;
+ UINT16 Offset64Lo;
+ UINT16 Offset64Hi;
+ BOOLEAN Writeable;
+} CPU_SMM_SAVE_STATE_LOOKUP_ENTRY;
+
+///
+/// Structure used to build a lookup table for the IOMisc width information
+///
+typedef struct {
+ UINT8 Width;
+ EFI_SMM_SAVE_STATE_IO_WIDTH IoWidth;
+} CPU_SMM_SAVE_STATE_IO_WIDTH;
+
+typedef struct {
+ UINT32 MsrIndex;
+ UINT64 MsrValue;
+} MSR_INFO;
+
+//
+//
+//
+typedef struct {
+ UINT32 Offset;
+ UINT16 Segment;
+ UINT16 Reserved;
+} IA32_FAR_ADDRESS;
+
+extern IA32_FAR_ADDRESS gSmmJmpAddr;
+
+extern CONST UINT8 gcSmmInitTemplate[];
+extern CONST UINT16 gcSmmInitSize;
+extern UINT32 gSmmCr0;
+extern UINT32 gSmmCr3;
+extern UINT32 gSmmCr4;
+extern UINTN gSmmInitStack;
+
+/**
+ Seamphore operation for all processor relocate SMMBase.
+**/
+VOID
+EFIAPI
+SmmRelocationSemaphoreComplete (
+ VOID
+ );
+
+/**
+ Hook return address of SMM Save State so that semaphore code
+ can be executed immediately after AP exits SMM to indicate to
+ the BSP that an AP has exited SMM after SMBASE relocation.
+
+ @param CpuIndex The processor index.
+**/
+VOID
+SemaphoreHook (
+ IN UINTN CpuIndex
+ );
+
+///
+/// The type of SMM CPU Information
+///
+typedef struct {
+ SPIN_LOCK Busy;
+ volatile EFI_AP_PROCEDURE Procedure;
+ volatile VOID *Parameter;
+ volatile UINT32 Run;
+ volatile BOOLEAN Present;
+} SMM_CPU_DATA_BLOCK;
+
+typedef struct {
+ SMM_CPU_DATA_BLOCK CpuData[FixedPcdGet32 (PcdCpuMaxLogicalProcessorNumber)];
+ volatile UINT32 Counter;
+ volatile UINT32 BspIndex;
+ volatile BOOLEAN InsideSmm;
+ volatile BOOLEAN AllCpusInSync;
+ SMM_CPU_SYNC_MODE SyncModeToBeSet;
+ volatile SMM_CPU_SYNC_MODE EffectiveSyncMode;
+ volatile BOOLEAN SwitchBsp;
+ volatile BOOLEAN CandidateBsp[FixedPcdGet32 (PcdCpuMaxLogicalProcessorNumber)];
+} SMM_DISPATCHER_MP_SYNC_DATA;
+
+extern IA32_DESCRIPTOR gcSmiGdtr;
+extern CONST IA32_DESCRIPTOR gcSmiIdtr;
+extern UINT32 gSmiCr3;
+extern volatile UINTN gSmiStack;
+extern CONST PROCESSOR_SMM_DESCRIPTOR gcPsd;
+extern volatile UINT8 gcSmiHandlerTemplate[];
+extern CONST UINT16 gcSmiHandlerSize;
+extern CONST UINT16 gcSmiHandlerOffset;
+extern UINT64 gPhyMask;
+extern ACPI_CPU_DATA mAcpiCpuData;
+extern SMM_DISPATCHER_MP_SYNC_DATA *mSmmMpSyncData;
+extern VOID *mGdtForAp;
+extern VOID *mIdtForAp;
+extern VOID *mMachineCheckHandlerForAp;
+extern UINTN mSmmStackArrayBase;
+extern UINTN mSmmStackArrayEnd;
+extern UINTN mSmmStackSize;
+extern IA32_IDT_GATE_DESCRIPTOR gSavedPageFaultIdtEntry;
+extern IA32_IDT_GATE_DESCRIPTOR gSavedDebugExceptionIdtEntry;
+extern EFI_SMM_CPU_SERVICE_PROTOCOL mSmmCpuService;
+
+/**
+ Create 4G PageTable in SMRAM.
+
+ @param ExtraPages Additional page numbers besides for 4G memory
+ @return PageTable Address
+
+**/
+UINT32
+Gen4GPageTable (
+ IN UINTN ExtraPages
+ );
+
+/**
+ Initialize global data for MP synchronization.
+
+ @param ImageHandle File Image Handle.
+ @param Stacks Base address of SMI stack buffer for all processors.
+ @param StackSize Stack size for each processor in SMM.
+
+**/
+VOID
+InitializeMpServiceData (
+ IN EFI_HANDLE ImageHandle,
+ IN VOID *Stacks,
+ IN UINTN StackSize
+ );
+
+/**
+ Initialize Timer for Smm AP Sync.
+
+**/
+VOID
+InitializeSmmTimer (
+ VOID
+ );
+
+/**
+ Start Timer for Smm AP Sync.
+
+**/
+UINT64
+EFIAPI
+StartSyncTimer (
+ VOID
+ );
+
+/**
+ Check if the Smm AP Sync timer is timeout.
+
+ @param Timer The start timer from the begin.
+
+**/
+BOOLEAN
+EFIAPI
+IsSyncTimerTimeout (
+ IN UINT64 Timer
+ );
+
+/**
+ Initialize IDT for SM mode.
+
+**/
+VOID
+EFIAPI
+InitializeIDT (
+ VOID
+ );
+
+/**
+ Register the SMM Foundation entry point.
+
+ @param This Pointer to EFI_SMM_CONFIGURATION_PROTOCOL instance
+ @param SmmEntryPoint SMM Foundation EntryPoint
+
+ @retval EFI_SUCCESS Successfully to register SMM foundation entry point
+
+**/
+EFI_STATUS
+EFIAPI
+RegisterSmmEntry (
+ IN CONST EFI_SMM_CONFIGURATION_PROTOCOL *This,
+ IN EFI_SMM_ENTRY_POINT SmmEntryPoint
+ );
+
+/**
+ Create PageTable for SMM use.
+
+ @return PageTable Address
+
+**/
+UINT32
+SmmInitPageTable (
+ VOID
+ );
+
+/**
+ Schedule a procedure to run on the specified CPU.
+
+ @param Procedure The address of the procedure to run
+ @param CpuIndex Target CPU number
+ @param ProcArguments The parameter to pass to the procedure
+
+ @retval EFI_INVALID_PARAMETER CpuNumber not valid
+ @retval EFI_INVALID_PARAMETER CpuNumber specifying BSP
+ @retval EFI_INVALID_PARAMETER The AP specified by CpuNumber did not enter SMM
+ @retval EFI_INVALID_PARAMETER The AP specified by CpuNumber is busy
+ @retval EFI_SUCCESS - The procedure has been successfully scheduled
+
+**/
+EFI_STATUS
+EFIAPI
+SmmStartupThisAp (
+ IN EFI_AP_PROCEDURE Procedure,
+ IN UINTN CpuIndex,
+ IN OUT VOID *ProcArguments OPTIONAL
+ );
+
+/**
+ Schedule a procedure to run on the specified CPU in a blocking fashion.
+
+ @param Procedure The address of the procedure to run
+ @param CpuIndex Target CPU Index
+ @param ProcArguments The parameter to pass to the procedure
+
+ @retval EFI_INVALID_PARAMETER CpuNumber not valid
+ @retval EFI_INVALID_PARAMETER CpuNumber specifying BSP
+ @retval EFI_INVALID_PARAMETER The AP specified by CpuNumber did not enter SMM
+ @retval EFI_INVALID_PARAMETER The AP specified by CpuNumber is busy
+ @retval EFI_SUCCESS The procedure has been successfully scheduled
+
+**/
+EFI_STATUS
+EFIAPI
+SmmBlockingStartupThisAp (
+ IN EFI_AP_PROCEDURE Procedure,
+ IN UINTN CpuIndex,
+ IN OUT VOID *ProcArguments OPTIONAL
+ );
+
+/**
+ Initialize MP synchronization data.
+
+**/
+VOID
+EFIAPI
+InitializeMpSyncData (
+ VOID
+ );
+
+/**
+ Find out SMRAM information including SMRR base, SMRR size.
+
+ @param SmrrBase SMRR base
+ @param SmrrSize SMRR size
+
+**/
+VOID
+FindSmramInfo (
+ OUT UINT32 *SmrrBase,
+ OUT UINT32 *SmrrSize
+ );
+
+/**
+ The function is invoked before SMBASE relocation in S3 path to restors CPU status.
+
+ The function is invoked before SMBASE relocation in S3 path. It does first time microcode load
+ and restores MTRRs for both BSP and APs.
+
+**/
+VOID
+EarlyInitializeCpu (
+ VOID
+ );
+
+/**
+ The function is invoked after SMBASE relocation in S3 path to restors CPU status.
+
+ The function is invoked after SMBASE relocation in S3 path. It restores configuration according to
+ data saved by normal boot path for both BSP and APs.
+
+**/
+VOID
+InitializeCpu (
+ VOID
+ );
+
+/**
+ Page Fault handler for SMM use.
+
+ @param InterruptType Defines the type of interrupt or exception that
+ occurred on the processor.This parameter is processor architecture specific.
+ @param SystemContext A pointer to the processor context when
+ the interrupt occurred on the processor.
+**/
+VOID
+EFIAPI
+SmiPFHandler (
+ IN EFI_EXCEPTION_TYPE InterruptType,
+ IN EFI_SYSTEM_CONTEXT SystemContext
+ );
+
+/**
+ Restore SMM Configuration for Haswell enhance SMM features in S3 boot path.
+**/
+VOID
+RestoreSmmConfigurationInS3 (
+ VOID
+ );
+
+/**
+ Read a CPU Save State register on the target processor.
+
+ This function abstracts the differences that whether the CPU Save State register is in the IA32 Cpu Save State Map
+ or x64 Cpu Save State Map or a CPU Save State MSR.
+
+ This function supports reading a CPU Save State register in SMBase relocation handler.
+
+ @param[in] CpuIndex Specifies the zero-based index of the CPU save state.
+ @param[in] RegisterIndex Index into mSmmCpuWidthOffset[] look up table.
+ @param[in] Width The number of bytes to read from the CPU save state.
+ @param[out] Buffer Upon return, this holds the CPU register value read from the save state.
+
+ @retval EFI_SUCCESS The register was read from Save State.
+ @retval EFI_NOT_FOUND The register is not defined for the Save State of Processor.
+ @retval EFI_INVALID_PARAMTER This or Buffer is NULL.
+ @retval EFI_UNSUPPORTED The register has no corresponding MSR.
+
+**/
+EFI_STATUS
+ReadSaveStateRegister (
+ IN UINTN CpuIndex,
+ IN UINTN RegisterIndex,
+ IN UINTN Width,
+ OUT VOID *Buffer
+ );
+
+/**
+ Write value to a CPU Save State register on the target processor.
+
+ This function abstracts the differences that whether the CPU Save State register is in the IA32 Cpu Save State Map
+ or x64 Cpu Save State Map or a CPU Save State MSR.
+
+ This function supports writing a CPU Save State register in SMBase relocation handler.
+
+ @param[in] CpuIndex Specifies the zero-based index of the CPU save state.
+ @param[in] RegisterIndex Index into mSmmCpuWidthOffset[] look up table.
+ @param[in] Width The number of bytes to read from the CPU save state.
+ @param[in] Buffer Upon entry, this holds the new CPU register value.
+
+ @retval EFI_SUCCESS The register was written to Save State.
+ @retval EFI_NOT_FOUND The register is not defined for the Save State of Processor.
+ @retval EFI_INVALID_PARAMTER ProcessorIndex or Width is not correct.
+ @retval EFI_UNSUPPORTED The register is read-only, cannot be written, or has no corresponding MSR.
+
+**/
+EFI_STATUS
+WriteSaveStateRegister (
+ IN UINTN CpuIndex,
+ IN UINTN RegisterIndex,
+ IN UINTN Width,
+ IN CONST VOID *Buffer
+ );
+
+/**
+ Read information from the CPU save state.
+
+ @param Register Specifies the CPU register to read form the save state.
+
+ @retval 0 Register is not valid
+ @retval >0 Index into mSmmCpuWidthOffset[] associated with Register
+
+**/
+UINTN
+GetRegisterIndex (
+ IN EFI_SMM_SAVE_STATE_REGISTER Register
+ );
+
+/**
+ Perform the remaining tasks.
+
+**/
+VOID
+PerformRemainingTasks (
+ VOID
+ );
+
+#endif
diff --git a/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.inf b/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.inf
new file mode 100644
index 0000000000..fd497ac2b8
--- /dev/null
+++ b/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.inf
@@ -0,0 +1,195 @@
+## @file
+# Agent Module to load other modules to deploy SMM Entry Vector for X86 CPU.
+#
+# Copyright (c) 2009 - 2015, 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 = 0x00010005
+ BASE_NAME = PiSmmCpuDxeSmm
+ FILE_GUID = E730A001-4DE6-4901-BBE4-7265BE0FCD8D
+ MODULE_TYPE = DXE_SMM_DRIVER
+ VERSION_STRING = 1.0
+ PI_SPECIFICATION_VERSION = 0x0001000A
+ ENTRY_POINT = PiCpuSmmEntry
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64
+#
+
+[Sources]
+ PiSmmCpuDxeSmm.c
+ PiSmmCpuDxeSmm.h
+ SmmFeatures.c
+ SmmFeatures.h
+ MpService.c
+ SyncTimer.c
+ CpuS3.c
+ CpuService.c
+ CpuService.h
+ SmmProfile.c
+
+[Sources.Ia32]
+ Ia32/Semaphore.c
+ Ia32/PageTbl.c
+ Ia32/SmmProfileArch.c
+ Ia32/SmmInit.asm | MSFT
+ Ia32/SmiException.asm | MSFT
+ Ia32/SmiEntry.asm | MSFT
+ Ia32/MpFuncs.asm | MSFT
+
+ Ia32/SmmInit.asm | INTEL
+ Ia32/SmiException.asm | INTEL
+ Ia32/SmiEntry.asm | INTEL
+ Ia32/MpFuncs.asm | INTEL
+
+ Ia32/SmmInit.S | GCC
+ Ia32/SmiException.S | GCC
+ Ia32/SmiEntry.S | GCC
+ Ia32/MpFuncs.S | GCC
+
+[Sources.X64]
+ X64/Semaphore.c
+ X64/PageTbl.c
+ X64/SmmProfileArch.c
+ X64/SmmInit.asm | MSFT
+ X64/SmiException.asm | MSFT
+ X64/SmiEntry.asm | MSFT
+ X64/MpFuncs.asm | MSFT
+
+ X64/SmmInit.asm | INTEL
+ X64/SmiException.asm | INTEL
+ X64/SmiEntry.asm | INTEL
+ X64/MpFuncs.asm | INTEL
+
+ X64/SmmInit.S | GCC
+ X64/SmiException.S | GCC
+ X64/SmiEntry.S | GCC
+ X64/MpFuncs.S | GCC
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+ UefiCpuPkg/UefiCpuPkg.dec
+ IntelFrameworkPkg/IntelFrameworkPkg.dec
+ BraswellPlatformPkg/BraswellPlatformPkg.dec
+
+[LibraryClasses]
+ UefiDriverEntryPoint
+ UefiRuntimeServicesTableLib
+ CacheMaintenanceLib
+ PcdLib
+ DebugLib
+ BaseLib
+ SynchronizationLib
+ BaseMemoryLib
+ MtrrLib
+ SmmLib
+ IoLib
+ TimerLib
+ SmmServicesTableLib
+ MemoryAllocationLib
+ DebugAgentLib
+ HobLib
+ CpuConfigLib
+ PciLib
+ LocalApicLib
+ UefiCpuLib
+ SmmCpuPlatformHookLib
+ UefiLib
+ DxeServicesTableLib
+ CpuLib
+ ReportStatusCodeLib
+
+[Protocols]
+ ## CONSUMES
+ gEfiSmmAccess2ProtocolGuid
+
+ ## CONSUMES
+ gEfiMpServiceProtocolGuid
+
+ ## PRODUCES
+ gEfiSmmConfigurationProtocolGuid
+
+ ## PRODUCES
+ gEfiSmmCpuProtocolGuid
+
+ ## NOTIFY
+ gEfiSmmReadyToLockProtocolGuid
+
+ ## PRODUCES
+ gSmmCpuSyncProtocolGuid
+
+ ## PRODUCES
+ gSmmCpuSync2ProtocolGuid
+
+ ## PRODUCES
+ gEfiSmmCpuServiceProtocolGuid
+
+ ## PRODUCES
+ gEfiSmmCpuSaveStateProtocolGuid
+
+[Guids]
+ ## SOMETIMES_CONSUMES ## HOB
+ gEfiAcpiVariableGuid
+
+ ## SOMETIMES_CONSUMES ## SystemTable
+ gEfiAcpi20TableGuid
+
+ ## SOMETIMES_CONSUMES ## SystemTable
+ gEfiAcpi10TableGuid
+
+[FeaturePcd]
+ gEfiMdeModulePkgTokenSpaceGuid.PcdFrameworkCompatibilitySupport ## CONSUMES
+ gEfiCpuTokenSpaceGuid.PcdCpuSmmBlockStartupThisAp ## CONSUMES
+ gEfiCpuTokenSpaceGuid.PcdCpuSmmEnableBspElection ## CONSUMES
+ gEfiCpuTokenSpaceGuid.PcdCpuSmmDebug ## CONSUMES
+ gEfiCpuTokenSpaceGuid.PcdCpuSmmUncacheCpuSyncData ## CONSUMES
+ gEfiCpuTokenSpaceGuid.PcdCpuHotPlugSupport ## CONSUMES
+ gEfiCpuTokenSpaceGuid.PcdCpuSmmStackGuard ## CONSUMES
+ gEfiCpuTokenSpaceGuid.PcdCpuSmmProfileEnable ## CONSUMES
+ gEfiCpuTokenSpaceGuid.PcdCpuSmmProfileRingBuffer ## CONSUMES
+ gEfiCpuTokenSpaceGuid.PcdCpuSmmFeatureControlMsrLock ## CONSUMES
+
+[FixedPcd]
+ ## CONSUMES
+ gEfiCpuTokenSpaceGuid.PcdCpuMaxLogicalProcessorNumber
+
+ ## CONSUMES
+ gEfiCpuTokenSpaceGuid.PcdCpuSmmProfileSize
+
+[Pcd]
+ ## SOMETIMES_CONSUMES
+ gEfiCpuTokenSpaceGuid.PcdCpuSmmStackSize
+
+ ## SOMETIMES_CONSUMES
+ gEfiCpuTokenSpaceGuid.PcdCpuSmmApSyncTimeout
+
+ ## SOMETIMES_CONSUMES
+ gEfiCpuTokenSpaceGuid.PcdCpuS3DataAddress
+
+ ## SOMETIMES_PRODUCES
+ gEfiCpuTokenSpaceGuid.PcdCpuHotPlugDataAddress
+
+ ## SOMETIMES_CONSUMES
+ gEfiCpuTokenSpaceGuid.PcdCpuSmmCodeAccessCheckEnable
+
+ ## SOMETIMES_CONSUMES
+ gEfiCpuTokenSpaceGuid.PcdCpuSmmUseDelayIndication
+
+ ## SOMETIMES_CONSUMES
+ gEfiCpuTokenSpaceGuid.PcdCpuSmmUseBlockIndication
+
+[Depex]
+ gEfiMpServiceProtocolGuid
diff --git a/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/PiSmmCpuDxeSmm/SmmFeatures.c b/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/PiSmmCpuDxeSmm/SmmFeatures.c
new file mode 100644
index 0000000000..2441d7e7a0
--- /dev/null
+++ b/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/PiSmmCpuDxeSmm/SmmFeatures.c
@@ -0,0 +1,492 @@
+/** @file
+ The CPU specific programming for PiSmmCpuDxeSmm module, such as SMRR, EMRR, IED.
+ Currently below CPUs are supported.
+
+ Copyright (c) 2010 - 2015, 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 <Base.h>
+
+#include <Library/PcdLib.h>
+#include <Library/BaseLib.h>
+#include <Library/CpuLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/DebugLib.h>
+#include <Library/PciLib.h>
+#include <Library/LocalApicLib.h>
+
+#include "PiSmmCpuDxeSmm.h"
+#include "SmmFeatures.h"
+
+//
+// The CPUID mapping for CherryView
+//
+
+CPUID_MAPPING mCherryViewMap[] = {
+ {CPUID_SIGNATURE_CHERRYVIEW, CPUID_MASK_NO_STEPPING},
+};
+
+//
+// The CLASS for CherryView
+//
+CPU_SMM_CLASS mCherryViewClass = {
+ CpuCherryView,
+ sizeof(mCherryViewMap)/sizeof(mCherryViewMap[0]),
+ mCherryViewMap,
+ };
+
+//
+// This table defines supported CPU class
+//
+CPU_SMM_CLASS *mCpuClasstable[] = {
+ &mCherryViewClass
+ };
+
+////////
+// Below section is common definition
+////////
+
+//
+// Assumes UP, or MP with identical feature set
+//
+CPU_SMM_FEATURE_CONTEXT mFeatureContext;
+
+CPU_SMM_CLASS *mThisCpu;
+BOOLEAN mSmmCodeAccessCheckEnable = FALSE;
+BOOLEAN mSmmUseDelayIndication;
+BOOLEAN mSmmUseBlockIndication;
+
+/**
+ Return if SMRR is supported
+
+ @retval TRUE SMRR is supported.
+ @retval FALSE SMRR is not supported.
+
+**/
+BOOLEAN
+IsSmrrSupported (
+ VOID
+ )
+{
+ UINT64 MtrrCap;
+
+ MtrrCap = AsmReadMsr64(EFI_MSR_IA32_MTRR_CAP);
+ if ((MtrrCap & IA32_MTRR_SMRR_SUPPORT_BIT) == 0) {
+ return FALSE;
+ } else {
+ return TRUE;
+ }
+}
+
+/**
+ Initialize SMRR in SMM relocate.
+
+ @param SmrrBase The base address of SMRR.
+ @param SmrrSize The size of SMRR.
+**/
+VOID
+InitSmrr (
+ IN UINT32 SmrrBase,
+ IN UINT32 SmrrSize
+ )
+{
+ AsmWriteMsr64 (EFI_MSR_SMRR_PHYS_BASE, SmrrBase| CACHE_WRITE_BACK);
+ AsmWriteMsr64 (EFI_MSR_SMRR_PHYS_MASK, (~(SmrrSize - 1) & EFI_MSR_SMRR_MASK)); // Valid bit will be set in ConfigSmrr() at first SMI
+}
+
+/**
+ Configure SMRR register at each SMM entry.
+**/
+VOID
+ConfigSmrr (
+ VOID
+ )
+{
+ UINT64 SmrrMask;
+
+ SmrrMask = AsmReadMsr64 (EFI_MSR_SMRR_PHYS_MASK);
+ if ((SmrrMask & EFI_MSR_SMRR_PHYS_MASK_VALID) == 0) {
+ AsmWriteMsr64(EFI_MSR_SMRR_PHYS_MASK, SmrrMask | EFI_MSR_SMRR_PHYS_MASK_VALID);
+ }
+}
+
+////////
+// Below section is definition for the supported class
+////////
+
+/**
+ This function will return current CPU_SMM_CLASS accroding to CPUID mapping.
+
+ @return The point to current CPU_SMM_CLASS
+
+**/
+CPU_SMM_CLASS *
+GetCpuFamily (
+ VOID
+ )
+{
+ UINT32 ClassIndex;
+ UINT32 Index;
+ UINT32 Count;
+ CPUID_MAPPING *CpuMapping;
+ UINT32 RegEax;
+
+ AsmCpuid (EFI_CPUID_VERSION_INFO, &RegEax, NULL, NULL, NULL);
+ for (ClassIndex = 0; ClassIndex < sizeof(mCpuClasstable)/sizeof(mCpuClasstable[0]); ClassIndex++) {
+ CpuMapping = mCpuClasstable[ClassIndex]->MappingTable;
+ Count = mCpuClasstable[ClassIndex]->MappingCount;
+ for (Index = 0; Index < Count; Index++) {
+ if ((CpuMapping[Index].Signature & CpuMapping[Index].Mask) == (RegEax & CpuMapping[Index].Mask)) {
+ return mCpuClasstable[ClassIndex];
+ }
+ }
+ }
+
+ // Not found!!! Should not happen
+ ASSERT (FALSE);
+ return NULL;
+}
+
+////////
+// Below section is external function
+////////
+/**
+ Read MSR or CSR based on the CPU type Register to read.
+
+ NOTE: Since platform may uses I/O ports 0xCF8 and 0xCFC to access
+ CSR, we need to use SPIN_LOCK to avoid collision on MP System.
+
+ @param[in] CpuIndex The processor index.
+ @param[in] RegName Register name.
+
+ @return 64-bit value read from register.
+
+**/
+UINT64
+SmmReadReg64 (
+ IN UINTN CpuIndex,
+ IN SMM_REG_NAME RegName
+ )
+{
+ UINT64 RetVal;
+
+ RetVal = 0;
+ switch (RegName) {
+ //
+ // Client uses MSR
+ //
+ case SmmRegFeatureControl:
+ RetVal = AsmReadMsr64 (EFI_MSR_HASWELL_SMM_FEATURE_CONTROL);
+ break;
+ case SmmRegSmmDelayed:
+ RetVal = AsmReadMsr64 (EFI_MSR_HASWELL_SMM_DELAYED);
+ break;
+ case SmmRegSmmBlocked:
+ RetVal = AsmReadMsr64 (EFI_MSR_HASWELL_SMM_BLOCKED);
+ break;
+ default:
+ ASSERT (FALSE);
+ }
+ return RetVal;
+}
+
+/**
+ Write MSR or CSR based on the CPU type Register to write.
+
+ NOTE: Since platform may uses I/O ports 0xCF8 and 0xCFC to access
+ CSR, we need to use SPIN_LOCK to avoid collision on MP System.
+
+ @param[in] CpuIndex The processor index.
+ @param[in] RegName Register name.
+ @param[in] RegValue 64-bit Register value.
+
+**/
+VOID
+SmmWriteReg64 (
+ IN UINTN CpuIndex,
+ IN SMM_REG_NAME RegName,
+ IN UINT64 RegValue
+ )
+{
+ switch (RegName) {
+ //
+ // Client uses MSR
+ //
+ case SmmRegFeatureControl:
+ AsmWriteMsr64 (EFI_MSR_HASWELL_SMM_FEATURE_CONTROL, RegValue);
+ break;
+ default:
+ ASSERT (FALSE);
+ }
+}
+
+/**
+ This function will return logical processor index in package.
+
+ @param[in] ProcessorNumber The processor number.
+ @param[out] LogProcIndexPackage The logical processor index.
+
+ @retval EFI_NOT_FOUND Cannot find the specified processor by ProcessorNumber.
+ @retval EFI_SUCCESS Logical processor index return in LogProcIndexPackage.
+
+**/
+EFI_STATUS
+GetLogProcIndexInPackage (
+ IN UINTN ProcessorNumber,
+ OUT UINT16 *LogProcIndexPackage
+ )
+{
+ UINT64 ProcessorId;
+ UINT32 PackageId;
+ UINTN Index;
+ UINT16 LogProcIndex;
+
+ ProcessorId = gSmmCpuPrivate->ProcessorInfo[ProcessorNumber].ProcessorId;
+ if (ProcessorId == INVALID_APIC_ID) {
+ return EFI_NOT_FOUND;
+ }
+
+ PackageId = gSmmCpuPrivate->ProcessorInfo[ProcessorNumber].Location.Package;
+ LogProcIndex = 0;
+ for (Index = 0; Index < mMaxNumberOfCpus; Index++) {
+ if (gSmmCpuPrivate->ProcessorInfo[Index].Location.Package == PackageId) {
+ if (gSmmCpuPrivate->ProcessorInfo[Index].ProcessorId < ProcessorId) {
+ //
+ // The logical processor number in the same packet
+ //
+ LogProcIndex++;
+ }
+ }
+ }
+
+ *LogProcIndexPackage = LogProcIndex;
+ return EFI_SUCCESS;
+}
+
+/**
+ Return if it is needed to configure MTRR to set TSEG cacheability.
+
+ @retval TRUE - we need configure MTRR
+ @retval FALSE - we do not need configure MTRR
+**/
+BOOLEAN
+NeedConfigureMtrrs (
+ VOID
+ )
+{
+ ASSERT (mThisCpu != NULL);
+
+ switch (mThisCpu->Family) {
+ case CpuCherryView:
+ return FALSE;
+ default:
+ return TRUE;
+ }
+}
+
+/**
+ Processor specific hook point at each SMM entry.
+
+ @param CpuIndex The index of the cpu which need to check.
+
+**/
+VOID
+SmmRendezvousEntry (
+ IN UINTN CpuIndex
+ )
+{
+
+ ASSERT (mThisCpu != NULL);
+
+ switch (mThisCpu->Family) {
+ case CpuCherryView:
+ if (mFeatureContext.SmrrEnabled) {
+ ConfigSmrr ();
+ }
+ return;
+ default:
+ return ;
+ }
+}
+
+/**
+ Processor specific hook point at each SMM exit.
+
+ @param CpuIndex The index of the cpu which need to check.
+**/
+VOID
+SmmRendezvousExit (
+ IN UINTN CpuIndex
+ )
+{
+
+ ASSERT (mThisCpu != NULL);
+
+ switch (mThisCpu->Family) {
+ case CpuCherryView:
+ default:
+ return ;
+ }
+}
+
+/**
+ Initialize SMRR context in SMM Init.
+**/
+VOID
+InitializeSmmMtrrManager (
+ VOID
+ )
+{
+ mThisCpu = GetCpuFamily ();
+ ASSERT (mThisCpu != NULL);
+
+ switch (mThisCpu->Family) {
+ case CpuCherryView:
+ if (!IsSmrrSupported ()) {
+ return ;
+ }
+ mFeatureContext.SmrrEnabled = TRUE;
+ return ;
+ default:
+ return ;
+ }
+}
+
+/**
+ Initialize SMRR/SMBASE/SMM Sync features in SMM Relocate.
+
+ @param ProcessorNumber The processor number
+ @param SmrrBase The base address of SMRR.
+ @param SmrrSize The size of SMRR.
+ @param SmBase The SMBASE value.
+ @param IsBsp If this processor treated as BSP.
+**/
+VOID
+SmmInitiFeatures (
+ IN UINTN ProcessorNumber,
+ IN UINT32 SmrrBase,
+ IN UINT32 SmrrSize,
+ IN UINT32 SmBase,
+ IN BOOLEAN IsBsp
+ )
+{
+ SOCKET_LGA_775_SMM_CPU_STATE *CpuState;
+ SMM_CPU_SYNC_FEATURE *SyncFeature;
+
+ SyncFeature = &(gSmmCpuPrivate->SmmSyncFeature[ProcessorNumber]);
+ SyncFeature->DelayIndicationSupported = FALSE;
+ SyncFeature->BlockIndicationSupported = FALSE;
+ SyncFeature->HaswellLogProcEnBit = (UINT64)(INT64)(-1);
+
+ mThisCpu = GetCpuFamily ();
+ ASSERT (mThisCpu != NULL);
+
+ //
+ // Configure SMBASE.
+ //
+ switch (mThisCpu->Family) {
+ case CpuCherryView:
+ //
+ // Fall back to legacy SMBASE setup.
+ //
+ CpuState = (SOCKET_LGA_775_SMM_CPU_STATE *)(UINTN)(SMM_DEFAULT_SMBASE + SMM_CPU_STATE_OFFSET);
+ CpuState->x86.SMBASE = SmBase;
+ break ;
+ default:
+ return ;
+ }
+
+ switch (mThisCpu->Family) {
+ case CpuCherryView:
+ if (IsSmrrSupported ()) {
+ InitSmrr (SmrrBase, SmrrSize);
+ }
+ return ;
+ default:
+ ASSERT (FALSE);
+ return ;
+ }
+}
+
+/**
+ Configure SMM Code Access Check feature on an AP.
+ SMM Feature Control MSR will be locked after configuration.
+
+ @param[in,out] Buffer Pointer to private data buffer.
+**/
+VOID
+EFIAPI
+ConfigSmmCodeAccessCheckOnCurrentProcessor (
+ IN OUT VOID *Buffer
+ )
+{
+ UINT64 SmmFeatureControlMsr;
+ UINTN CpuIndex;
+
+ CpuIndex = *(UINTN *)Buffer;
+
+ SmmFeatureControlMsr = SmmReadReg64 (CpuIndex, SmmRegFeatureControl);
+ //
+ // The SMM Feature Control MSR is package scope. If lock bit is set, don't set it again.
+ //
+ if ((SmmFeatureControlMsr & SMM_FEATURE_CONTROL_LOCK_BIT) == 0) {
+ if (mSmmCodeAccessCheckEnable) {
+ SmmFeatureControlMsr |= SMM_CODE_CHK_EN_BIT;
+ }
+ if (FeaturePcdGet (PcdCpuSmmFeatureControlMsrLock)) {
+ SmmFeatureControlMsr |=SMM_FEATURE_CONTROL_LOCK_BIT;
+ }
+ SmmWriteReg64 (CpuIndex, SmmRegFeatureControl, SmmFeatureControlMsr);
+ }
+}
+
+/**
+ Configure SMM Code Access Check feature for all processors.
+ SMM Feature Control MSR will be locked after configuration.
+**/
+VOID
+ConfigSmmCodeAccessCheck (
+ VOID
+ )
+{
+ UINTN Index;
+ EFI_STATUS Status;
+
+ //
+ // SMM Code Access Check feature is supported since Haswell.
+ //
+ if (FALSE /*mThisCpu->Family == CpuHaswell*/) {
+ if ((AsmReadMsr64 (EFI_MSR_HASWELL_SMM_MCA_CAP) & SMM_CODE_ACCESS_CHK_BIT) == 0) {
+ mSmmCodeAccessCheckEnable = FALSE;
+ if (!FeaturePcdGet (PcdCpuSmmFeatureControlMsrLock)) {
+ return;
+ }
+ }
+ //
+ // Enable SMM Code Access Check feature for the BSP.
+ //
+ ConfigSmmCodeAccessCheckOnCurrentProcessor (NULL);
+ //
+ // Enable SMM Code Access Check feature for the APs.
+ //
+ for (Index = 0; Index < mNumberOfCpus; Index++) {
+ if (Index != gSmmCpuPrivate->SmmCoreEntryContext.CurrentlyExecutingCpu) {
+ //
+ // Don't call gSmst->SmmStartupThisAp() because it may be implemented in a blocking or non-blocking fashion.
+ //
+ Status = SmmBlockingStartupThisAp (ConfigSmmCodeAccessCheckOnCurrentProcessor, Index, NULL);
+ ASSERT_EFI_ERROR (Status);
+ }
+ }
+ }
+}
+
diff --git a/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/PiSmmCpuDxeSmm/SmmFeatures.h b/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/PiSmmCpuDxeSmm/SmmFeatures.h
new file mode 100644
index 0000000000..2eabc82e50
--- /dev/null
+++ b/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/PiSmmCpuDxeSmm/SmmFeatures.h
@@ -0,0 +1,220 @@
+/** @file
+ The CPU specific programming for PiSmmCpuDxeSmm module.
+
+ Copyright (c) 2010 - 2015, 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 __SMM_FEATURES_H__
+#define __SMM_FEATURES_H__
+
+////////
+// Below definition is from IA32 SDM
+////////
+#define EFI_CPUID_VERSION_INFO 0x1
+#define EFI_CPUID_CORE_TOPOLOGY 0x0B
+#define EFI_CPUID_EXTENDED_FUNCTION 0x80000000
+#define EFI_CPUID_VIR_PHY_ADDRESS_SIZE 0x80000008
+
+#define EFI_MSR_IA32_MTRR_CAP 0xFE
+#define IA32_MTRR_SMRR_SUPPORT_BIT BIT11
+
+#define EFI_MSR_IA32_FEATURE_CONTROL 0x3A
+#define IA32_SMRR_ENABLE_BIT BIT3
+
+#define EFI_MSR_SMRR_PHYS_MASK_VALID BIT11
+#define EFI_MSR_SMRR_MASK 0xFFFFF000
+
+#define EFI_MSR_SMRR_PHYS_BASE 0x1F2
+#define EFI_MSR_SMRR_PHYS_MASK 0x1F3
+#define CACHE_WRITE_PROTECT 5
+#define CACHE_WRITE_BACK 6
+#define SMM_DEFAULT_SMBASE 0x30000
+
+#define EFI_MSR_HASWELL_SMM_MCA_CAP 0x17D
+#define SMM_CODE_ACCESS_CHK_BIT BIT58
+#define LONG_FLOW_INDICATION_BIT BIT59
+
+#define EFI_MSR_HASWELL_SMM_FEATURE_CONTROL 0x4E0
+#define SMM_FEATURE_CONTROL_LOCK_BIT BIT0
+#define SMM_CODE_CHK_EN_BIT BIT2
+
+#define SMM_HASWELL_CLIENT_LOG_PROC_EN_BIT_LENGTH 12
+
+#define EFI_MSR_HASWELL_SMM_DELAYED 0x4E2
+
+#define EFI_MSR_HASWELL_SMM_BLOCKED 0x4E3
+
+////////
+// Below section is definition for CPU SMM Feature context
+////////
+
+//
+// Structure to describe CPU identification mapping
+// if ((CPUID_EAX(1) & Mask) == (Signature & Mask)), it means matched.
+//
+typedef struct {
+ UINT32 Signature;
+ UINT32 Mask;
+} CPUID_MAPPING;
+
+//
+// CPU SMM familiy
+//
+typedef enum {
+ CpuCherryView,
+ CpuSmmFamilyMax
+} CPU_SMM_FAMILY;
+
+//
+// Structure to describe CPU SMM class
+//
+typedef struct {
+ CPU_SMM_FAMILY Family;
+ UINT32 MappingCount;
+ CPUID_MAPPING *MappingTable;
+} CPU_SMM_CLASS;
+
+//
+// Structure to describe CPU_SMM_FEATURE_CONTEXT
+//
+typedef struct {
+ BOOLEAN SmrrEnabled;
+} CPU_SMM_FEATURE_CONTEXT;
+
+//
+// ATOM CPUID signatures
+//
+#define CPUID_SIGNATURE_CHERRYVIEW 0x000406C0
+
+//
+// CPUID masks
+//
+#define CPUID_MASK_NO_STEPPING 0x0FFF0FF0
+#define CPUID_MASK_NO_STEPPING_MODEL 0x0FFF0F00
+
+//
+// Enumerate registers which differ between client and server
+//
+typedef enum {
+ SmmRegFeatureControl,
+ SmmRegSmmDelayed,
+ SmmRegSmmBlocked
+} SMM_REG_NAME;
+
+extern BOOLEAN mSmmCodeAccessCheckEnable;
+extern BOOLEAN mSmmUseDelayIndication;
+extern BOOLEAN mSmmUseBlockIndication;
+extern CPU_SMM_CLASS *mThisCpu;
+
+/**
+ Return if it is needed to configure MTRR to set TSEG cacheability.
+
+ @retval TRUE - we need configure MTRR
+ @retval FALSE - we do not need configure MTRR
+**/
+BOOLEAN
+NeedConfigureMtrrs (
+ VOID
+ );
+
+/**
+ Processor specific hook point at each SMM entry.
+
+ @param CpuIndex The index of the cpu which need to check.
+**/
+VOID
+SmmRendezvousEntry (
+ IN UINTN CpuIndex
+ );
+
+/**
+ Processor specific hook point at each SMM exit.
+
+ @param CpuIndex The index of the cpu which need to check.
+**/
+VOID
+SmmRendezvousExit (
+ IN UINTN CpuIndex
+ );
+
+/**
+ Initialize SMRR context in SMM Init.
+**/
+VOID
+InitializeSmmMtrrManager (
+ VOID
+ );
+
+/**
+ Initialize SMRR/SMBASE/SMM Sync features in SMM Relocate.
+
+ @param ProcessorNumber The processor number
+ @param SmrrBase The base address of SMRR.
+ @param SmrrSize The size of SMRR.
+ @param SmBase The SMBASE value.
+ @param IsBsp If this processor treated as BSP.
+**/
+VOID
+SmmInitiFeatures (
+ IN UINTN ProcessorNumber,
+ IN UINT32 SmrrBase,
+ IN UINT32 SmrrSize,
+ IN UINT32 SmBase,
+ IN BOOLEAN IsBsp
+ );
+
+/**
+ Configure SMM Code Access Check feature for all processors.
+ SMM Feature Control MSR will be locked after configuration.
+**/
+VOID
+ConfigSmmCodeAccessCheck (
+ VOID
+ );
+
+/**
+ Read MSR or CSR based on the CPU type Register to read.
+
+ NOTE: Since platform may uses I/O ports 0xCF8 and 0xCFC to access
+ CSR, we need to use SPIN_LOCK to avoid collision on MP System.
+
+ @param[in] CpuIndex The processor index.
+ @param[in] RegName Register name.
+
+ @return 64-bit value read from register.
+
+**/
+UINT64
+SmmReadReg64 (
+ IN UINTN CpuIndex,
+ IN SMM_REG_NAME RegName
+ );
+
+/**
+ Write MSR or CSR based on the CPU type Register to write.
+
+ NOTE: Since platform may uses I/O ports 0xCF8 and 0xCFC to access
+ CSR, we need to use SPIN_LOCK to avoid collision on MP System.
+
+ @param[in] CpuIndex The processor index.
+ @param[in] RegName Register name.
+ @param[in] RegValue 64-bit Register value.
+
+**/
+VOID
+SmmWriteReg64 (
+ IN UINTN CpuIndex,
+ IN SMM_REG_NAME RegName,
+ IN UINT64 RegValue
+ );
+
+#endif
diff --git a/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/PiSmmCpuDxeSmm/SmmProfile.c b/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/PiSmmCpuDxeSmm/SmmProfile.c
new file mode 100644
index 0000000000..b781d2032b
--- /dev/null
+++ b/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/PiSmmCpuDxeSmm/SmmProfile.c
@@ -0,0 +1,1369 @@
+/** @file
+ Enable SMM profile.
+
+ Copyright (c) 2012 - 2015, 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 "PiSmmCpuDxeSmm.h"
+#include "SmmProfileInternal.h"
+
+#define MSR_IA32_MISC_ENABLE 0x1A0
+
+SMM_PROFILE_HEADER *mSmmProfileBase;
+MSR_DS_AREA_STRUCT *mMsrDsAreaBase;
+//
+// The buffer to store SMM profile data.
+//
+UINTN mSmmProfileSize = FixedPcdGet32 (PcdCpuSmmProfileSize);
+
+//
+// The buffer to enable branch trace store.
+//
+UINTN mMsrDsAreaSize = SMM_PROFILE_DTS_SIZE;
+
+//
+// The flag indicates if execute-disable is supported by processor.
+//
+BOOLEAN mXdSupported = FALSE;
+
+//
+// The flag indicates if BTS is supported by processor.
+//
+BOOLEAN mBtsSupported = FALSE;
+
+//
+// The flag indicates if SMM profile starts to record data.
+//
+BOOLEAN mSmmProfileStart = FALSE;
+
+//
+// Record the page fault exception count for one instruction execution.
+//
+UINTN mPFEntryCount[FixedPcdGet32 (PcdCpuMaxLogicalProcessorNumber)];
+
+UINT64 mLastPFEntryValue[FixedPcdGet32 (PcdCpuMaxLogicalProcessorNumber)][MAX_PF_ENTRY_COUNT];
+UINT64 *mLastPFEntryPointer[FixedPcdGet32 (PcdCpuMaxLogicalProcessorNumber)][MAX_PF_ENTRY_COUNT];
+
+MSR_DS_AREA_STRUCT *mMsrDsArea[FixedPcdGet32 (PcdCpuMaxLogicalProcessorNumber)];
+BRANCH_TRACE_RECORD *mMsrBTSRecord[FixedPcdGet32 (PcdCpuMaxLogicalProcessorNumber)];
+UINTN mBTSRecordNumber;
+PEBS_RECORD *mMsrPEBSRecord[FixedPcdGet32 (PcdCpuMaxLogicalProcessorNumber)];
+
+//
+// These memory ranges are always present, they does not generate the access type of page fault exception,
+// but they possibly generate instruction fetch type of page fault exception.
+//
+MEMORY_PROTECTION_RANGE *mProtectionMemRange = NULL;
+UINTN mProtectionMemRangeCount = 0;
+
+//
+// Some pre-defined memory ranges.
+//
+MEMORY_PROTECTION_RANGE mProtectionMemRangeTemplate[] = {
+ //
+ // SMRAM range (to be fixed in runtime).
+ // It is always present and instruction fetches are allowed.
+ //
+ {{0x00000000, 0x00000000},TRUE,FALSE},
+
+ //
+ // SMM profile data range( to be fixed in runtime).
+ // It is always present and instruction fetches are not allowed.
+ //
+ {{0x00000000, 0x00000000},TRUE,TRUE},
+
+ //
+ // Future exended range could be added here.
+ //
+
+ //
+ // PCI MMIO ranges (to be added in runtime).
+ // They are always present and instruction fetches are not allowed.
+ //
+};
+
+//
+// These memory ranges are mapped by 4KB-page instead of 2MB-page.
+//
+MEMORY_RANGE *mSplitMemRange = NULL;
+UINTN mSplitMemRangeCount = 0;
+
+//
+// SMI command port.
+//
+UINT32 mSmiCommandPort;
+
+/**
+ Disable branch trace store.
+
+**/
+VOID
+DisableBTS (
+ VOID
+ )
+{
+ AsmMsrAnd64 (MSR_DEBUG_CTL, ~((UINT64)(MSR_DEBUG_CTL_BTS | MSR_DEBUG_CTL_TR)));
+}
+
+/**
+ Enable branch trace store.
+
+**/
+VOID
+EnableBTS (
+ VOID
+ )
+{
+ AsmMsrOr64 (MSR_DEBUG_CTL, (MSR_DEBUG_CTL_BTS | MSR_DEBUG_CTL_TR));
+}
+
+/**
+ Get CPU Index from Apic ID.
+
+**/
+UINTN
+GetCpuIndex (
+ VOID
+ )
+{
+ UINTN Index;
+ UINT32 ApicId;
+
+ ApicId = GetApicId ();
+
+ for (Index = 0; Index < FixedPcdGet32 (PcdCpuMaxLogicalProcessorNumber); Index++) {
+ if (gSmmCpuPrivate->ProcessorInfo[Index].ProcessorId == ApicId) {
+ return Index;
+ }
+ }
+ ASSERT (FALSE);
+ return 0;
+}
+
+/**
+ Get the source of IP after execute-disable exception is triggered.
+
+ @param CpuIndex The index of CPU.
+ @param DestinationIP The destination address.
+
+**/
+UINT64
+GetSourceFromDestinationOnBts (
+ UINTN CpuIndex,
+ UINT64 DestinationIP
+ )
+{
+ BRANCH_TRACE_RECORD *CurrentBTSRecord;
+ UINTN Index;
+ BOOLEAN FirstMatch;
+
+ FirstMatch = FALSE;
+
+ CurrentBTSRecord = (BRANCH_TRACE_RECORD *)mMsrDsArea[CpuIndex]->BTSIndex;
+ for (Index = 0; Index < mBTSRecordNumber; Index++) {
+ if ((UINTN)CurrentBTSRecord < (UINTN)mMsrBTSRecord[CpuIndex]) {
+ //
+ // Underflow
+ //
+ CurrentBTSRecord = (BRANCH_TRACE_RECORD *)((UINTN)mMsrDsArea[CpuIndex]->BTSAbsoluteMaximum - 1);
+ CurrentBTSRecord --;
+ }
+ if (CurrentBTSRecord->LastBranchTo == DestinationIP) {
+ //
+ // Good! find 1st one, then find 2nd one.
+ //
+ if (!FirstMatch) {
+ //
+ // The first one is DEBUG exception
+ //
+ FirstMatch = TRUE;
+ } else {
+ //
+ // Good find proper one.
+ //
+ return CurrentBTSRecord->LastBranchFrom;
+ }
+ }
+ CurrentBTSRecord--;
+ }
+
+ return 0;
+}
+
+/**
+ SMM profile specific INT 1 (single-step) exception handler.
+
+ @param InterruptType Defines the type of interrupt or exception that
+ occurred on the processor.This parameter is processor architecture specific.
+ @param SystemContext A pointer to the processor context when
+ the interrupt occurred on the processor.
+**/
+VOID
+EFIAPI
+DebugExceptionHandler (
+ IN EFI_EXCEPTION_TYPE InterruptType,
+ IN EFI_SYSTEM_CONTEXT SystemContext
+ )
+{
+ UINTN CpuIndex;
+ UINTN PFEntry;
+
+ if (!mSmmProfileStart) {
+ return;
+ }
+ CpuIndex = GetCpuIndex ();
+
+ //
+ // Clear last PF entries
+ //
+ for (PFEntry = 0; PFEntry < mPFEntryCount[CpuIndex]; PFEntry++) {
+ *mLastPFEntryPointer[CpuIndex][PFEntry] = mLastPFEntryValue[CpuIndex][PFEntry];
+ }
+
+ //
+ // Reset page fault exception count for next page fault.
+ //
+ mPFEntryCount[CpuIndex] = 0;
+
+ //
+ // Flush TLB
+ //
+ CpuFlushTlb ();
+}
+
+/**
+ Check if the memory address will be mapped by 4KB-page.
+
+ @param Address The address of Memory.
+ @param Nx The flag indicates if the memory is execute-disable.
+
+**/
+BOOLEAN
+IsAddressValid (
+ IN EFI_PHYSICAL_ADDRESS Address,
+ IN BOOLEAN *Nx
+ )
+{
+ UINTN Index;
+
+ //
+ // Check config
+ //
+ for (Index = 0; Index < mProtectionMemRangeCount; Index++) {
+ if ((Address >= mProtectionMemRange[Index].Range.Base) && (Address < mProtectionMemRange[Index].Range.Top)) {
+ *Nx = mProtectionMemRange[Index].Nx;
+ return mProtectionMemRange[Index].Present;
+ }
+ }
+
+ //
+ // Return default
+ //
+ *Nx = FALSE;
+ return FALSE;
+}
+
+/**
+ Check if the memory address will be mapped by 4KB-page.
+
+ @param Address The address of Memory.
+
+**/
+BOOLEAN
+IsAddressSplit (
+ IN EFI_PHYSICAL_ADDRESS Address
+ )
+{
+ UINTN Index;
+
+ //
+ // Check config
+ //
+ for (Index = 0; Index < mSplitMemRangeCount; Index++) {
+ if ((Address >= mSplitMemRange[Index].Base) && (Address < mSplitMemRange[Index].Top)) {
+ return TRUE;
+ }
+ }
+
+ //
+ // Return default
+ //
+ return FALSE;
+}
+
+/**
+ Initialize the protected memory ranges and the 4KB-page mapped memory ranges.
+
+**/
+VOID
+InitProtectedMemRange (
+ VOID
+ )
+{
+ UINTN Index;
+ UINTN NumberOfDescriptors;
+ UINTN NumberOfMmioDescriptors;
+ UINTN NumberOfProtectRange;
+ UINTN NumberOfSpliteRange;
+ EFI_GCD_MEMORY_SPACE_DESCRIPTOR *MemorySpaceMap;
+ UINTN TotalSize;
+ EFI_STATUS Status;
+ EFI_PHYSICAL_ADDRESS ProtectBaseAddress;
+ EFI_PHYSICAL_ADDRESS ProtectEndAddress;
+ EFI_PHYSICAL_ADDRESS Top2MBAlignedAddress;
+ EFI_PHYSICAL_ADDRESS Base2MBAlignedAddress;
+ UINT64 High4KBPageSize;
+ UINT64 Low4KBPageSize;
+
+ NumberOfDescriptors = 0;
+ NumberOfMmioDescriptors = 0;
+ NumberOfSpliteRange = 0;
+ MemorySpaceMap = NULL;
+
+ //
+ // Get MMIO ranges from GCD and add them into protected memory ranges.
+ //
+ Status = gDS->GetMemorySpaceMap (
+ &NumberOfDescriptors,
+ &MemorySpaceMap
+ );
+ for (Index = 0; Index < NumberOfDescriptors; Index++) {
+ if (MemorySpaceMap[Index].GcdMemoryType == EfiGcdMemoryTypeMemoryMappedIo) {
+ NumberOfMmioDescriptors++;
+ }
+ }
+
+ if (NumberOfMmioDescriptors != 0) {
+ TotalSize = NumberOfMmioDescriptors * sizeof (MEMORY_PROTECTION_RANGE) + sizeof (mProtectionMemRangeTemplate);
+ mProtectionMemRange = (MEMORY_PROTECTION_RANGE *) AllocateZeroPool (TotalSize);
+ ASSERT (mProtectionMemRange != NULL);
+ mProtectionMemRangeCount = TotalSize / sizeof (MEMORY_PROTECTION_RANGE);
+
+ //
+ // Copy existing ranges.
+ //
+ CopyMem (mProtectionMemRange, mProtectionMemRangeTemplate, sizeof (mProtectionMemRangeTemplate));
+
+ //
+ // Create split ranges which come from protected ranges.
+ //
+ TotalSize = (TotalSize / sizeof (MEMORY_PROTECTION_RANGE)) * sizeof (MEMORY_RANGE);
+ mSplitMemRange = (MEMORY_RANGE *) AllocateZeroPool (TotalSize);
+ ASSERT (mSplitMemRange != NULL);
+
+ //
+ // Create MMIO ranges which are set to present and execution-disable.
+ //
+ NumberOfProtectRange = sizeof (mProtectionMemRangeTemplate) / sizeof (MEMORY_PROTECTION_RANGE);
+ for (Index = 0; Index < NumberOfDescriptors; Index++) {
+ if (MemorySpaceMap[Index].GcdMemoryType != EfiGcdMemoryTypeMemoryMappedIo) {
+ continue;
+ }
+ mProtectionMemRange[NumberOfProtectRange].Range.Base = MemorySpaceMap[Index].BaseAddress;
+ mProtectionMemRange[NumberOfProtectRange].Range.Top = MemorySpaceMap[Index].BaseAddress + MemorySpaceMap[Index].Length;
+ mProtectionMemRange[NumberOfProtectRange].Present = TRUE;
+ mProtectionMemRange[NumberOfProtectRange].Nx = TRUE;
+ NumberOfProtectRange++;
+ }
+ }
+
+ //
+ // According to protected ranges, create the ranges which will be mapped by 2KB page.
+ //
+ NumberOfSpliteRange = 0;
+ NumberOfProtectRange = mProtectionMemRangeCount;
+ for (Index = 0; Index < NumberOfProtectRange; Index++) {
+ //
+ // If MMIO base address is not 2MB alignment, make 2MB alignment for create 4KB page in page table.
+ //
+ ProtectBaseAddress = mProtectionMemRange[Index].Range.Base;
+ ProtectEndAddress = mProtectionMemRange[Index].Range.Top;
+ if (((ProtectBaseAddress & (SIZE_2MB - 1)) != 0) || ((ProtectEndAddress & (SIZE_2MB - 1)) != 0)) {
+ //
+ // Check if it is possible to create 4KB-page for not 2MB-aligned range and to create 2MB-page for 2MB-aligned range.
+ // A mix of 4KB and 2MB page could save SMRAM space.
+ //
+ Top2MBAlignedAddress = ProtectEndAddress & ~(SIZE_2MB - 1);
+ Base2MBAlignedAddress = (ProtectBaseAddress + SIZE_2MB - 1) & ~(SIZE_2MB - 1);
+ if ((Top2MBAlignedAddress > Base2MBAlignedAddress) &&
+ ((Top2MBAlignedAddress - Base2MBAlignedAddress) >= SIZE_2MB)) {
+ //
+ // There is an range which could be mapped by 2MB-page.
+ //
+ High4KBPageSize = ((ProtectEndAddress + SIZE_2MB - 1) & ~(SIZE_2MB - 1)) - (ProtectEndAddress & ~(SIZE_2MB - 1));
+ Low4KBPageSize = ((ProtectBaseAddress + SIZE_2MB - 1) & ~(SIZE_2MB - 1)) - (ProtectBaseAddress & ~(SIZE_2MB - 1));
+ if (High4KBPageSize != 0) {
+ //
+ // Add not 2MB-aligned range to be mapped by 4KB-page.
+ //
+ mSplitMemRange[NumberOfSpliteRange].Base = ProtectEndAddress & ~(SIZE_2MB - 1);
+ mSplitMemRange[NumberOfSpliteRange].Top = (ProtectEndAddress + SIZE_2MB - 1) & ~(SIZE_2MB - 1);
+ NumberOfSpliteRange++;
+ }
+ if (Low4KBPageSize != 0) {
+ //
+ // Add not 2MB-aligned range to be mapped by 4KB-page.
+ //
+ mSplitMemRange[NumberOfSpliteRange].Base = ProtectBaseAddress & ~(SIZE_2MB - 1);
+ mSplitMemRange[NumberOfSpliteRange].Top = (ProtectBaseAddress + SIZE_2MB - 1) & ~(SIZE_2MB - 1);
+ NumberOfSpliteRange++;
+ }
+ } else {
+ //
+ // The range could only be mapped by 4KB-page.
+ //
+ mSplitMemRange[NumberOfSpliteRange].Base = ProtectBaseAddress & ~(SIZE_2MB - 1);
+ mSplitMemRange[NumberOfSpliteRange].Top = (ProtectEndAddress + SIZE_2MB - 1) & ~(SIZE_2MB - 1);
+ NumberOfSpliteRange++;
+ }
+ }
+ }
+
+ mSplitMemRangeCount = NumberOfSpliteRange;
+
+ DEBUG ((EFI_D_INFO, "SMM Profile Memory Ranges:\n"));
+ for (Index = 0; Index < mProtectionMemRangeCount; Index++) {
+ DEBUG ((EFI_D_INFO, "mProtectionMemRange[%d].Base = %lx\n", Index, mProtectionMemRange[Index].Range.Base));
+ DEBUG ((EFI_D_INFO, "mProtectionMemRange[%d].Top = %lx\n", Index, mProtectionMemRange[Index].Range.Top));
+ }
+ for (Index = 0; Index < mSplitMemRangeCount; Index++) {
+ DEBUG ((EFI_D_INFO, "mSplitMemRange[%d].Base = %lx\n", Index, mSplitMemRange[Index].Base));
+ DEBUG ((EFI_D_INFO, "mSplitMemRange[%d].Top = %lx\n", Index, mSplitMemRange[Index].Top));
+ }
+}
+
+/**
+ Update page table according to protected memory ranges and the 4KB-page mapped memory ranges.
+
+**/
+VOID
+InitPaging (
+ VOID
+ )
+{
+ UINT64 *Pml4;
+ UINT64 *Pde;
+ UINT64 *Pte;
+ UINT64 *Pt;
+ UINTN Address;
+ UINTN Level1;
+ UINTN Level2;
+ UINTN Level3;
+ UINTN Level4;
+ UINTN NumberOfPdpEntries;
+ UINTN NumberOfPml4Entries;
+ UINTN SizeOfMemorySpace;
+ BOOLEAN Nx;
+
+ if (sizeof (UINTN) == sizeof (UINT64)) {
+ Pml4 = (UINT64*)(UINTN)gSmiCr3;
+ SizeOfMemorySpace = HighBitSet64 (gPhyMask) + 1;
+ //
+ // Calculate the table entries of PML4E and PDPTE.
+ //
+ if (SizeOfMemorySpace <= 39 ) {
+ NumberOfPml4Entries = 1;
+ NumberOfPdpEntries = (UINT32)LShiftU64 (1, (SizeOfMemorySpace - 30));
+ } else {
+ NumberOfPml4Entries = (UINT32)LShiftU64 (1, (SizeOfMemorySpace - 39));
+ NumberOfPdpEntries = 512;
+ }
+ } else {
+ NumberOfPml4Entries = 1;
+ NumberOfPdpEntries = 4;
+ }
+
+ //
+ // Go through page table and change 2MB-page into 4KB-page.
+ //
+ for (Level1 = 0; Level1 < NumberOfPml4Entries; Level1++) {
+ if (sizeof (UINTN) == sizeof (UINT64)) {
+ Pde = (UINT64 *)(UINTN)(Pml4[Level1] & PHYSICAL_ADDRESS_MASK);
+ } else {
+ Pde = (UINT64*)(UINTN)gSmiCr3;
+ }
+ for (Level2 = 0; Level2 < NumberOfPdpEntries; Level2++, Pde++) {
+ Pte = (UINT64 *)(UINTN)(*Pde & PHYSICAL_ADDRESS_MASK);
+ if (Pte == 0) {
+ continue;
+ }
+ for (Level3 = 0; Level3 < SIZE_4KB / sizeof (*Pte); Level3++, Pte++) {
+ Address = (((Level2 << 9) + Level3) << 21);
+
+ //
+ // if it is 2M page, check IsAddressSplit()
+ //
+ if (((*Pte & IA32_PG_PS) != 0) && IsAddressSplit (Address)) {
+ //
+ // Based on current page table, create 4KB page table for split area.
+ //
+ ASSERT (Address == (*Pte & PHYSICAL_ADDRESS_MASK));
+
+ Pt = AllocatePages (1);
+ ASSERT (Pt != NULL);
+
+ *Pte = (UINTN)Pt | IA32_PG_RW | IA32_PG_P;
+
+ // Split it
+ for (Level4 = 0; Level4 < SIZE_4KB / sizeof(*Pt); Level4++, Pt++) {
+ *Pt = Address + ((Level4 << 12) | IA32_PG_RW | IA32_PG_P);
+ } // end for PT
+ } // end if IsAddressSplit
+ } // end for PTE
+ } // end for PDE
+ }
+
+ //
+ // Go through page table and set several page table entries to absent or execute-disable.
+ //
+ DEBUG ((EFI_D_INFO, "Patch page table start ...\n"));
+ for (Level1 = 0; Level1 < NumberOfPml4Entries; Level1++) {
+ if (sizeof (UINTN) == sizeof (UINT64)) {
+ Pde = (UINT64 *)(UINTN)(Pml4[Level1] & PHYSICAL_ADDRESS_MASK);
+ } else {
+ Pde = (UINT64*)(UINTN)gSmiCr3;
+ }
+ for (Level2 = 0; Level2 < NumberOfPdpEntries; Level2++, Pde++) {
+ Pte = (UINT64 *)(UINTN)(*Pde & PHYSICAL_ADDRESS_MASK);
+ if (Pte == 0) {
+ continue;
+ }
+ for (Level3 = 0; Level3 < SIZE_4KB / sizeof (*Pte); Level3++, Pte++) {
+ Address = (((Level2 << 9) + Level3) << 21);
+
+ if ((*Pte & IA32_PG_PS) != 0) {
+ // 2MB page
+
+ if (!IsAddressValid (Address, &Nx)) {
+ //
+ // Patch to remove present flag and rw flag
+ //
+ *Pte = *Pte & (INTN)(INT32)(~(IA32_PG_RW | IA32_PG_P));
+ }
+ if (Nx && mXdSupported) {
+ *Pte = *Pte | IA32_PG_NX;
+ }
+ } else {
+ // 4KB page
+ Pt = (UINT64 *)(UINTN)(*Pte & PHYSICAL_ADDRESS_MASK);
+ if (Pt == 0) {
+ continue;
+ }
+ for (Level4 = 0; Level4 < SIZE_4KB / sizeof(*Pt); Level4++, Pt++) {
+ if (!IsAddressValid (Address, &Nx)) {
+ *Pt = *Pt & (INTN)(INT32)(~(IA32_PG_RW | IA32_PG_P));
+ }
+ if (Nx && mXdSupported) {
+ *Pt = *Pt | IA32_PG_NX;
+ }
+ Address += SIZE_4KB;
+ } // end for PT
+ } // end if PS
+ } // end for PTE
+ } // end for PDE
+ }
+
+ //
+ // Flush TLB
+ //
+ CpuFlushTlb ();
+ DEBUG ((EFI_D_INFO, "Patch page table done!\n"));
+
+ return ;
+}
+
+/**
+ To find Fadt in Acpi tables.
+
+ @param AcpiTableGuid The guid used to find ACPI table in UEFI ConfigurationTable.
+
+ @return Fadt table pointer.
+**/
+EFI_ACPI_2_0_FIXED_ACPI_DESCRIPTION_TABLE *
+FindAcpiFadtTableByAcpiGuid (
+ IN EFI_GUID *AcpiTableGuid
+ )
+{
+ EFI_ACPI_2_0_ROOT_SYSTEM_DESCRIPTION_POINTER *Rsdp;
+ EFI_ACPI_DESCRIPTION_HEADER *Rsdt;
+ EFI_ACPI_2_0_FIXED_ACPI_DESCRIPTION_TABLE *Fadt;
+ UINTN Index;
+ UINT32 Data32;
+ Rsdp = NULL;
+ Rsdt = NULL;
+ Fadt = NULL;
+ //
+ // found ACPI table RSD_PTR from system table
+ //
+ for (Index = 0; Index < gST->NumberOfTableEntries; Index++) {
+ if (CompareGuid (&(gST->ConfigurationTable[Index].VendorGuid), AcpiTableGuid)) {
+ //
+ // A match was found.
+ //
+ Rsdp = gST->ConfigurationTable[Index].VendorTable;
+ break;
+ }
+ }
+
+ if (Rsdp == NULL) {
+ return NULL;
+ }
+
+ Rsdt = (EFI_ACPI_DESCRIPTION_HEADER *)(UINTN) Rsdp->RsdtAddress;
+ if (Rsdt == NULL || Rsdt->Signature != EFI_ACPI_2_0_ROOT_SYSTEM_DESCRIPTION_TABLE_SIGNATURE) {
+ return NULL;
+ }
+
+ for (Index = sizeof (EFI_ACPI_DESCRIPTION_HEADER); Index < Rsdt->Length; Index = Index + sizeof (UINT32)) {
+
+ Data32 = *(UINT32 *) ((UINT8 *) Rsdt + Index);
+ Fadt = (EFI_ACPI_2_0_FIXED_ACPI_DESCRIPTION_TABLE *) (UINT32 *) (UINTN) Data32;
+ if (Fadt->Header.Signature == EFI_ACPI_2_0_FIXED_ACPI_DESCRIPTION_TABLE_SIGNATURE) {
+ break;
+ }
+ }
+
+ if (Fadt == NULL || Fadt->Header.Signature != EFI_ACPI_2_0_FIXED_ACPI_DESCRIPTION_TABLE_SIGNATURE) {
+ return NULL;
+ }
+
+ return Fadt;
+}
+
+/**
+ To find Fadt in Acpi tables.
+
+ @return Fadt table pointer.
+**/
+EFI_ACPI_2_0_FIXED_ACPI_DESCRIPTION_TABLE *
+FindAcpiFadtTable (
+ VOID
+ )
+{
+ EFI_ACPI_2_0_FIXED_ACPI_DESCRIPTION_TABLE *Fadt;
+
+ Fadt = FindAcpiFadtTableByAcpiGuid (&gEfiAcpi20TableGuid);
+ if (Fadt != NULL) {
+ return Fadt;
+ }
+
+ return FindAcpiFadtTableByAcpiGuid (&gEfiAcpi10TableGuid);
+}
+
+/**
+ To get system port address of the SMI Command Port in FADT table.
+
+**/
+VOID
+GetSmiCommandPort (
+ VOID
+ )
+{
+ EFI_ACPI_2_0_FIXED_ACPI_DESCRIPTION_TABLE *Fadt;
+
+ Fadt = FindAcpiFadtTable ();
+ ASSERT (Fadt != NULL);
+
+ mSmiCommandPort = Fadt->SmiCmd;
+ DEBUG ((EFI_D_ERROR, "mSmiCommandPort = %x\n", mSmiCommandPort));
+}
+
+/**
+ Updates page table to make some memory ranges (like system memory) absent
+ and make some memory ranges (like MMIO) present and execute disable. It also
+ update 2MB-page to 4KB-page for some memory ranges.
+
+**/
+VOID
+SmmProfileStart (
+ VOID
+ )
+{
+ //
+ // Create a mix of 2MB and 4KB page table. Update some memory ranges absent and execute-disable.
+ //
+ InitPaging ();
+
+ //
+ // The flag indicates SMM profile starts to work.
+ //
+ mSmmProfileStart = TRUE;
+}
+
+/**
+ Initialize SMM profile in SmmReadyToLock protocol callback function.
+
+ @param Protocol Points to the protocol's unique identifier.
+ @param Interface Points to the interface instance.
+ @param Handle The handle on which the interface was installed.
+
+ @retval EFI_SUCCESS SmmReadyToLock protocol callback runs successfully.
+**/
+EFI_STATUS
+EFIAPI
+InitSmmProfileCallBack (
+ IN CONST EFI_GUID *Protocol,
+ IN VOID *Interface,
+ IN EFI_HANDLE Handle
+ )
+{
+ EFI_STATUS Status;
+
+ //
+ // Save to variable so that SMM profile data can be found.
+ //
+ Status = gRT->SetVariable (
+ SMM_PROFILE_NAME,
+ &gEfiCallerIdGuid,
+ EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
+ sizeof(mSmmProfileBase),
+ &mSmmProfileBase
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Get Software SMI from Fadt
+ //
+ GetSmiCommandPort ();
+
+ //
+ // Init protected mem range for patching page table later.
+ //
+ InitProtectedMemRange ();
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Initialize SMM profile data structures.
+
+**/
+VOID
+InitSmmProfileInternal (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ EFI_PHYSICAL_ADDRESS Base;
+ VOID *Registration;
+ UINTN Index;
+ UINTN MsrDsAreaSizePerCpu;
+ UINTN TotalSize;
+
+ //
+ // Allocate memory for SmmProfile below 4GB.
+ // The base address
+ //
+ ASSERT ((mSmmProfileSize & 0xFFF) == 0);
+
+ if (mBtsSupported) {
+ TotalSize = mSmmProfileSize + mMsrDsAreaSize;
+ } else {
+ TotalSize = mSmmProfileSize;
+ }
+
+ Base = 0xFFFFFFFF;
+ Status = gBS->AllocatePages (
+ AllocateMaxAddress,
+ EfiReservedMemoryType,
+ EFI_SIZE_TO_PAGES (TotalSize),
+ &Base
+ );
+ ASSERT_EFI_ERROR (Status);
+ ZeroMem ((VOID *)(UINTN)Base, TotalSize);
+ mSmmProfileBase = (SMM_PROFILE_HEADER *)(UINTN)Base;
+
+ //
+ // Initialize SMM profile data header.
+ //
+ mSmmProfileBase->HeaderSize = sizeof (SMM_PROFILE_HEADER);
+ mSmmProfileBase->MaxDataEntries = (UINT64)((mSmmProfileSize - sizeof(SMM_PROFILE_HEADER)) / sizeof (SMM_PROFILE_ENTRY));
+ mSmmProfileBase->MaxDataSize = MultU64x64 (mSmmProfileBase->MaxDataEntries, sizeof(SMM_PROFILE_ENTRY));
+ mSmmProfileBase->CurDataEntries = 0;
+ mSmmProfileBase->CurDataSize = 0;
+ mSmmProfileBase->TsegStart = mCpuHotPlugData.SmrrBase;
+ mSmmProfileBase->TsegSize = mCpuHotPlugData.SmrrSize;
+ mSmmProfileBase->NumSmis = 0;
+ mSmmProfileBase->NumCpus = gSmmCpuPrivate->SmmCoreEntryContext.NumberOfCpus;
+
+ if (mBtsSupported) {
+ mMsrDsAreaBase = (MSR_DS_AREA_STRUCT *)((UINTN)Base + mSmmProfileSize);
+ MsrDsAreaSizePerCpu = mMsrDsAreaSize / FixedPcdGet32 (PcdCpuMaxLogicalProcessorNumber);
+ mBTSRecordNumber = (MsrDsAreaSizePerCpu - sizeof(PEBS_RECORD) * PEBS_RECORD_NUMBER - sizeof(MSR_DS_AREA_STRUCT)) / sizeof(BRANCH_TRACE_RECORD);
+ for (Index = 0; Index < FixedPcdGet32 (PcdCpuMaxLogicalProcessorNumber); Index++) {
+ mMsrDsArea[Index] = (MSR_DS_AREA_STRUCT *)((UINTN)mMsrDsAreaBase + MsrDsAreaSizePerCpu * Index);
+ mMsrBTSRecord[Index] = (BRANCH_TRACE_RECORD *)((UINTN)mMsrDsArea[Index] + sizeof(MSR_DS_AREA_STRUCT));
+ mMsrPEBSRecord[Index] = (PEBS_RECORD *)((UINTN)mMsrDsArea[Index] + MsrDsAreaSizePerCpu - sizeof(PEBS_RECORD) * PEBS_RECORD_NUMBER);
+
+ mMsrDsArea[Index]->BTSBufferBase = (UINTN)mMsrBTSRecord[Index];
+ mMsrDsArea[Index]->BTSIndex = mMsrDsArea[Index]->BTSBufferBase;
+ mMsrDsArea[Index]->BTSAbsoluteMaximum = mMsrDsArea[Index]->BTSBufferBase + mBTSRecordNumber * sizeof(BRANCH_TRACE_RECORD) + 1;
+ mMsrDsArea[Index]->BTSInterruptThreshold = mMsrDsArea[Index]->BTSAbsoluteMaximum + 1;
+
+ mMsrDsArea[Index]->PEBSBufferBase = (UINTN)mMsrPEBSRecord[Index];
+ mMsrDsArea[Index]->PEBSIndex = mMsrDsArea[Index]->PEBSBufferBase;
+ mMsrDsArea[Index]->PEBSAbsoluteMaximum = mMsrDsArea[Index]->PEBSBufferBase + PEBS_RECORD_NUMBER * sizeof(PEBS_RECORD) + 1;
+ mMsrDsArea[Index]->PEBSInterruptThreshold = mMsrDsArea[Index]->PEBSAbsoluteMaximum + 1;
+ }
+ }
+
+ mProtectionMemRange = mProtectionMemRangeTemplate;
+ mProtectionMemRangeCount = sizeof (mProtectionMemRangeTemplate) / sizeof (MEMORY_PROTECTION_RANGE);
+
+ //
+ // Update TSeg entry.
+ //
+ mProtectionMemRange[0].Range.Base = mCpuHotPlugData.SmrrBase;
+ mProtectionMemRange[0].Range.Top = mCpuHotPlugData.SmrrBase + mCpuHotPlugData.SmrrSize;
+
+ //
+ // Update SMM profile entry.
+ //
+ mProtectionMemRange[1].Range.Base = (EFI_PHYSICAL_ADDRESS)(UINTN)mSmmProfileBase;
+ mProtectionMemRange[1].Range.Top = (EFI_PHYSICAL_ADDRESS)(UINTN)mSmmProfileBase + TotalSize;
+
+ //
+ // Allocate memory reserved for creating 4KB pages.
+ //
+ InitPagesForPFHandler ();
+
+ //
+ // Start SMM profile when SmmReadyToLock protocol is installed.
+ //
+ Status = gSmst->SmmRegisterProtocolNotify (
+ &gEfiSmmReadyToLockProtocolGuid,
+ InitSmmProfileCallBack,
+ &Registration
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ return ;
+}
+
+/**
+ Check if XD feature is supported by a processor.
+
+**/
+VOID
+CheckFeatureSupported (
+ VOID
+ )
+{
+ UINT32 RegEax;
+ UINT32 RegEdx;
+
+ if (mXdSupported) {
+ AsmCpuid (EFI_CPUID_EXTENDED_FUNCTION, &RegEax, NULL, NULL, NULL);
+ if (RegEax <= EFI_CPUID_EXTENDED_FUNCTION) {
+ //
+ // Entended CPUID functions are not supported on this processor.
+ //
+ mXdSupported = FALSE;
+ }
+
+ AsmCpuid (EFI_CPUID_EXTENDED_CPU_SIG, NULL, NULL, NULL, &RegEdx);
+ if ((RegEdx & CPUID1_EDX_XD_SUPPORT) == 0) {
+ //
+ // Execute Disable Bit feature is not supported on this processor.
+ //
+ mXdSupported = FALSE;
+ }
+ }
+
+ if (mBtsSupported) {
+ AsmCpuid (EFI_CPUID_VERSION_INFO, NULL, NULL, NULL, &RegEdx);
+ if ((RegEdx & CPUID1_EDX_BTS_AVAILABLE) != 0) {
+ //
+ // Per IA32 manuals:
+ // When CPUID.1:EDX[21] is set, the following BTS facilities are available:
+ // 1. The BTS_UNAVAILABLE flag in the IA32_MISC_ENABLE MSR indicates the
+ // availability of the BTS facilities, including the ability to set the BTS and
+ // BTINT bits in the MSR_DEBUGCTLA MSR.
+ // 2. The IA32_DS_AREA MSR can be programmed to point to the DS save area.
+ //
+ if ((AsmMsrBitFieldRead64 (MSR_IA32_MISC_ENABLE, 11, 11) == 0) &&
+ (AsmMsrBitFieldRead64 (MSR_IA32_MISC_ENABLE, 12, 12) == 0)) {
+ //
+ // BTS facilities is supported.
+ //
+ mBtsSupported = FALSE;
+ }
+ }
+ }
+}
+
+/**
+ Check if XD and BTS features are supported by all processors.
+
+ @param MpServices The MP services protocol.
+
+**/
+VOID
+CheckProcessorFeature (
+ IN EFI_MP_SERVICES_PROTOCOL *MpServices
+ )
+{
+ mXdSupported = TRUE;
+ mBtsSupported = TRUE;
+
+ //
+ // Check if XD and BTS are supported on all processors.
+ //
+ CheckFeatureSupported ();
+
+ //
+ //Check on other processors if BSP supports this
+ //
+ if (mXdSupported || mBtsSupported) {
+ MpServices->StartupAllAPs (
+ MpServices,
+ (EFI_AP_PROCEDURE) CheckFeatureSupported,
+ TRUE,
+ NULL,
+ 0,
+ NULL,
+ NULL
+ );
+ }
+}
+
+/**
+ Enable XD feature.
+
+**/
+VOID
+ActivateXd (
+ VOID
+ )
+{
+ UINT64 MsrRegisters;
+
+ MsrRegisters = AsmReadMsr64 (MSR_EFER);
+ if ((MsrRegisters & MSR_EFER_XD) != 0) {
+ return ;
+ }
+ MsrRegisters |= MSR_EFER_XD;
+ AsmWriteMsr64 (MSR_EFER, MsrRegisters);
+}
+
+/**
+ Enable single step.
+
+**/
+VOID
+ActivateSingleStepDB (
+ VOID
+ )
+{
+ UINTN Dr6;
+
+ Dr6 = AsmReadDr6 ();
+ if ((Dr6 & DR6_SINGLE_STEP) != 0) {
+ return;
+ }
+ Dr6 |= DR6_SINGLE_STEP;
+ AsmWriteDr6 (Dr6);
+}
+
+/**
+ Enable last branch.
+
+**/
+VOID
+ActivateLBR (
+ VOID
+ )
+{
+ UINT64 DebugCtl;
+
+ DebugCtl = AsmReadMsr64 (MSR_DEBUG_CTL);
+ if ((DebugCtl & MSR_DEBUG_CTL_LBR) != 0) {
+ return ;
+ }
+ AsmWriteMsr64 (MSR_LER_FROM_LIP, 0);
+ AsmWriteMsr64 (MSR_LER_TO_LIP, 0);
+ DebugCtl |= MSR_DEBUG_CTL_LBR;
+ AsmWriteMsr64 (MSR_DEBUG_CTL, DebugCtl);
+}
+
+/**
+ Enable branch trace store.
+
+ @param CpuIndex The index of the processor.
+
+**/
+VOID
+ActivateBTS (
+ IN UINTN CpuIndex
+ )
+{
+ UINT64 DebugCtl;
+
+ DebugCtl = AsmReadMsr64 (MSR_DEBUG_CTL);
+ if ((DebugCtl & MSR_DEBUG_CTL_BTS) != 0) {
+ return ;
+ }
+
+ AsmWriteMsr64 (MSR_DS_AREA, (UINT64)(UINTN)mMsrDsArea[CpuIndex]);
+ DebugCtl |= (MSR_DEBUG_CTL_BTS | MSR_DEBUG_CTL_TR);
+ DebugCtl &= ~MSR_DEBUG_CTL_BTINT;
+ AsmWriteMsr64 (MSR_DEBUG_CTL, DebugCtl);
+}
+
+/**
+ Increase SMI number in each SMI entry.
+
+**/
+VOID
+SmmProfileRecordSmiNum (
+ VOID
+ )
+{
+ if (mSmmProfileStart) {
+ mSmmProfileBase->NumSmis++;
+ }
+}
+
+/**
+ Initialize processor environment for SMM profile.
+
+ @param CpuIndex The index of the processor.
+
+**/
+VOID
+ActivateSmmProfile (
+ IN UINTN CpuIndex
+ )
+{
+ //
+ // Try to enable NX
+ //
+ if (mXdSupported) {
+ ActivateXd ();
+ }
+
+ //
+ // Enable Single Step DB#
+ //
+ ActivateSingleStepDB ();
+
+ if (mBtsSupported) {
+ //
+ // We can not get useful information from LER, so we have to use BTS.
+ //
+ ActivateLBR ();
+
+ //
+ // Enable BTS
+ //
+ ActivateBTS (CpuIndex);
+ }
+}
+
+/**
+ Initialize SMM profile in SMM CPU entrypoint.
+
+**/
+VOID
+InitSmmProfile (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ EFI_MP_SERVICES_PROTOCOL *MpServices;
+
+ Status = gBS->LocateProtocol (&gEfiMpServiceProtocolGuid, NULL, (VOID **)&MpServices);
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // First detect if XD and BTS are supported
+ //
+ CheckProcessorFeature (MpServices);
+
+ //
+ // Init SmmProfile here
+ //
+ InitSmmProfileInternal ();
+
+ //
+ // Init profile IDT.
+ //
+ InitIdtr ();
+
+ //
+ // Patch SmmS3ResumeState->SmmS3Cr3
+ //
+ InitSmmS3Cr3 ();
+}
+
+/**
+ Update page table to map the memory correctly in order to make the instruction
+ which caused page fault execute successfully. And it also save the original page
+ table to be restored in single-step exception.
+
+ @param PageTable PageTable Address.
+ @param PFAddress The memory address which caused page fault exception.
+ @param CpuIndex The index of the processor.
+ @param ErrorCode The Error code of exception.
+
+**/
+VOID
+RestorePageTableBelow4G (
+ UINT64 *PageTable,
+ UINT64 PFAddress,
+ UINTN CpuIndex,
+ UINTN ErrorCode
+ )
+{
+ UINTN PTIndex;
+ UINTN PFIndex;
+
+ //
+ // PML4
+ //
+ if (sizeof(UINT64) == sizeof(UINTN)) {
+ PTIndex = (UINTN)BitFieldRead64 (PFAddress, 39, 47);
+ ASSERT (PageTable[PTIndex] != 0);
+ PageTable = (UINT64*)(UINTN)(PageTable[PTIndex] & PHYSICAL_ADDRESS_MASK);
+ }
+
+ //
+ // PDPTE
+ //
+ PTIndex = (UINTN)BitFieldRead64 (PFAddress, 30, 38);
+ ASSERT (PageTable[PTIndex] != 0);
+ PageTable = (UINT64*)(UINTN)(PageTable[PTIndex] & PHYSICAL_ADDRESS_MASK);
+
+ //
+ // PD
+ //
+ PTIndex = (UINTN)BitFieldRead64 (PFAddress, 21, 29);
+ if ((PageTable[PTIndex] & IA32_PG_PS) != 0) {
+ //
+ // Large page
+ //
+
+ //
+ // Record old entries with non-present status
+ // Old entries include the memory which instruction is at and the memory which instruction access.
+ //
+ //
+ ASSERT (mPFEntryCount[CpuIndex] < MAX_PF_ENTRY_COUNT);
+ if (mPFEntryCount[CpuIndex] < MAX_PF_ENTRY_COUNT) {
+ PFIndex = mPFEntryCount[CpuIndex];
+ mLastPFEntryValue[CpuIndex][PFIndex] = PageTable[PTIndex];
+ mLastPFEntryPointer[CpuIndex][PFIndex] = &PageTable[PTIndex];
+ mPFEntryCount[CpuIndex]++;
+ }
+
+ //
+ // Set new entry
+ //
+ PageTable[PTIndex] = (PFAddress & ~((1ull << 21) - 1));
+ PageTable[PTIndex] |= IA32_PG_PS;
+ PageTable[PTIndex] |= IA32_PG_RW | IA32_PG_P;
+ if ((ErrorCode & IA32_PF_EC_ID) != 0) {
+ PageTable[PTIndex] &= ~IA32_PG_NX;
+ }
+ } else {
+ //
+ // Small page
+ //
+ ASSERT (PageTable[PTIndex] != 0);
+ PageTable = (UINT64*)(UINTN)(PageTable[PTIndex] & PHYSICAL_ADDRESS_MASK);
+
+ //
+ // 4K PTE
+ //
+ PTIndex = (UINTN)BitFieldRead64 (PFAddress, 12, 20);
+
+ //
+ // Record old entries with non-present status
+ // Old entries include the memory which instruction is at and the memory which instruction access.
+ //
+ //
+ ASSERT (mPFEntryCount[CpuIndex] < MAX_PF_ENTRY_COUNT);
+ if (mPFEntryCount[CpuIndex] < MAX_PF_ENTRY_COUNT) {
+ PFIndex = mPFEntryCount[CpuIndex];
+ mLastPFEntryValue[CpuIndex][PFIndex] = PageTable[PTIndex];
+ mLastPFEntryPointer[CpuIndex][PFIndex] = &PageTable[PTIndex];
+ mPFEntryCount[CpuIndex]++;
+ }
+
+ //
+ // Set new entry
+ //
+ PageTable[PTIndex] = (PFAddress & ~((1ull << 12) - 1));
+ PageTable[PTIndex] |= IA32_PG_RW | IA32_PG_P;
+ if ((ErrorCode & IA32_PF_EC_ID) != 0) {
+ PageTable[PTIndex] &= ~IA32_PG_NX;
+ }
+ }
+}
+
+/**
+ The Page fault handler to save SMM profile data.
+
+ @param Rip The RIP when exception happens.
+ @param ErrorCode The Error code of exception.
+
+**/
+VOID
+SmmProfilePFHandler (
+ UINTN Rip,
+ UINTN ErrorCode
+ )
+{
+ UINT64 *PageTable;
+ UINT64 PFAddress;
+ UINTN CpuIndex;
+ UINTN Index;
+ UINT64 InstructionAddress;
+ UINTN MaxEntryNumber;
+ UINTN CurrentEntryNumber;
+ BOOLEAN IsValidPFAddress;
+ SMM_PROFILE_ENTRY *SmmProfileEntry;
+ UINT64 SmiCommand;
+ EFI_STATUS Status;
+ UINTN SwSmiCpuIndex;
+ UINT8 SoftSmiValue;
+ EFI_SMM_SAVE_STATE_IO_INFO IoInfo;
+
+ if (!mSmmProfileStart) {
+ //
+ // If SMM profile does not start, call original page fault handler.
+ //
+ SmiDefaultPFHandler ();
+ return;
+ }
+
+ if (mBtsSupported) {
+ DisableBTS ();
+ }
+
+ IsValidPFAddress = FALSE;
+ PageTable = (UINT64 *)AsmReadCr3 ();
+ PFAddress = AsmReadCr2 ();
+ CpuIndex = GetCpuIndex ();
+
+ if (PFAddress <= 0xFFFFFFFF) {
+ RestorePageTableBelow4G (PageTable, PFAddress, CpuIndex, ErrorCode);
+ } else {
+ RestorePageTableAbove4G (PageTable, PFAddress, CpuIndex, ErrorCode, &IsValidPFAddress);
+ }
+
+ if (!IsValidPFAddress) {
+ InstructionAddress = Rip;
+ if ((ErrorCode & IA32_PF_EC_ID) != 0 && (mBtsSupported)) {
+ //
+ // If it is instruction fetch failure, get the correct IP from BTS.
+ //
+ InstructionAddress = GetSourceFromDestinationOnBts (CpuIndex, Rip);
+ if (InstructionAddress == 0) {
+ //
+ // It indicates the instruction which caused page fault is not a jump instruction,
+ // set instruction address same as the page fault address.
+ //
+ InstructionAddress = PFAddress;
+ }
+ }
+
+ //
+ // Try to find which CPU trigger SWSMI
+ //
+ SwSmiCpuIndex = 0;
+ //
+ // Indicate it is not software SMI
+ //
+ SmiCommand = 0xFFFFFFFFFFFFFFFFULL;
+ for (Index = 0; Index < gSmst->NumberOfCpus; Index++) {
+ Status = SmmReadSaveState(&mSmmCpu, sizeof(IoInfo), EFI_SMM_SAVE_STATE_REGISTER_IO, Index, &IoInfo);
+ if (EFI_ERROR (Status)) {
+ continue;
+ }
+ if (IoInfo.IoPort == mSmiCommandPort) {
+ //
+ // Great! Find it.
+ //
+ SwSmiCpuIndex = Index;
+ //
+ // A software SMI triggered by SMI command port has been found, get SmiCommand from SMI command port.
+ //
+ SoftSmiValue = IoRead8 (mSmiCommandPort);
+ SmiCommand = (UINT64)SoftSmiValue;
+ break;
+ }
+ }
+
+ SmmProfileEntry = (SMM_PROFILE_ENTRY *)(UINTN)(mSmmProfileBase + 1);
+ //
+ // Check if there is already a same entry in profile data.
+ //
+ for (Index = 0; Index < (UINTN) mSmmProfileBase->CurDataEntries; Index++) {
+ if ((SmmProfileEntry[Index].ErrorCode == (UINT64)ErrorCode) &&
+ (SmmProfileEntry[Index].Address == PFAddress) &&
+ (SmmProfileEntry[Index].CpuNum == (UINT64)CpuIndex) &&
+ (SmmProfileEntry[Index].Instruction == InstructionAddress) &&
+ (SmmProfileEntry[Index].SmiCmd == SmiCommand)) {
+ //
+ // Same record exist, need not save again.
+ //
+ break;
+ }
+ }
+ if (Index == mSmmProfileBase->CurDataEntries) {
+ CurrentEntryNumber = (UINTN) mSmmProfileBase->CurDataEntries;
+ MaxEntryNumber = (UINTN) mSmmProfileBase->MaxDataEntries;
+ if (FeaturePcdGet (PcdCpuSmmProfileRingBuffer)) {
+ CurrentEntryNumber = CurrentEntryNumber % MaxEntryNumber;
+ }
+ if (CurrentEntryNumber < MaxEntryNumber) {
+ //
+ // Log the new entry
+ //
+ SmmProfileEntry[CurrentEntryNumber].SmiNum = mSmmProfileBase->NumSmis;
+ SmmProfileEntry[CurrentEntryNumber].ErrorCode = (UINT64)ErrorCode;
+ SmmProfileEntry[CurrentEntryNumber].ApicId = (UINT64)GetApicId ();
+ SmmProfileEntry[CurrentEntryNumber].CpuNum = (UINT64)CpuIndex;
+ SmmProfileEntry[CurrentEntryNumber].Address = PFAddress;
+ SmmProfileEntry[CurrentEntryNumber].Instruction = InstructionAddress;
+ SmmProfileEntry[CurrentEntryNumber].SmiCmd = SmiCommand;
+ //
+ // Update current entry index and data size in the header.
+ //
+ mSmmProfileBase->CurDataEntries++;
+ mSmmProfileBase->CurDataSize = MultU64x64 (mSmmProfileBase->CurDataEntries, sizeof (SMM_PROFILE_ENTRY));
+ }
+ }
+ }
+ //
+ // Flush TLB
+ //
+ CpuFlushTlb ();
+
+ if (mBtsSupported) {
+ EnableBTS ();
+ }
+}
+
+/**
+ Replace INT1 exception handler to restore page table to absent/execute-diable state
+ in order to trigger page fault again to save SMM profile data..
+
+**/
+VOID
+InitIdtr (
+ VOID
+ )
+{
+ SmmRegisterExceptionHandler (&mSmmCpuService, EXCEPT_IA32_DEBUG, DebugExceptionHandler);
+}
diff --git a/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/PiSmmCpuDxeSmm/SmmProfile.h b/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/PiSmmCpuDxeSmm/SmmProfile.h
new file mode 100644
index 0000000000..0c5411b7ba
--- /dev/null
+++ b/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/PiSmmCpuDxeSmm/SmmProfile.h
@@ -0,0 +1,76 @@
+/** @file
+ SMM profile header file.
+
+ Copyright (c) 2012 - 2015, 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 _SMM_PROFILE_H_
+#define _SMM_PROFILE_H_
+
+//
+// External functions
+//
+
+/**
+ Initialize processor environment for SMM profile.
+
+ @param CpuIndex The index of the processor.
+
+**/
+VOID
+ActivateSmmProfile (
+ IN UINTN CpuIndex
+ );
+
+/**
+ Initialize SMM profile in SMM CPU entrypoint.
+
+**/
+VOID
+InitSmmProfile (
+ VOID
+ );
+
+/**
+ Increase SMI number in each SMI entry.
+
+**/
+VOID
+SmmProfileRecordSmiNum (
+ VOID
+ );
+
+/**
+ The Page fault handler to save SMM profile data.
+
+ @param Rip The RIP when exception happens.
+ @param ErrorCode The Error code of exception.
+
+**/
+VOID
+SmmProfilePFHandler (
+ UINTN Rip,
+ UINTN ErrorCode
+ );
+
+/**
+ Updates page table to make some memory ranges (like system memory) absent
+ and make some memory ranges (like MMIO) present and execute disable. It also
+ update 2MB-page to 4KB-page for some memory ranges.
+
+**/
+VOID
+SmmProfileStart (
+ VOID
+ );
+
+#endif // _SMM_PROFILE_H_
diff --git a/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/PiSmmCpuDxeSmm/SmmProfileInternal.h b/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/PiSmmCpuDxeSmm/SmmProfileInternal.h
new file mode 100644
index 0000000000..7403c4fc46
--- /dev/null
+++ b/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/PiSmmCpuDxeSmm/SmmProfileInternal.h
@@ -0,0 +1,190 @@
+/** @file
+ SMM profile internal header file.
+
+ Copyright (c) 2012 - 2015, 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 _SMM_PROFILE_INTERNAL_H_
+#define _SMM_PROFILE_INTERNAL_H_
+
+#include <Guid/GlobalVariable.h>
+#include <Guid/Acpi.h>
+#include <Protocol/SmmReadyToLock.h>
+#include <Library/UefiRuntimeServicesTableLib.h>
+#include <Library/DxeServicesTableLib.h>
+#include <Library/CpuLib.h>
+#include <IndustryStandard/Acpi.h>
+
+#include "SmmProfileArch.h"
+
+//
+// Config the SMM_PROFILE DTS region size
+//
+#define SMM_PROFILE_DTS_SIZE (4 * 1024 * 1024) // 4M
+
+#define MAX_PF_PAGE_COUNT 0x2
+
+#define PEBS_RECORD_NUMBER 0x2
+
+#define MAX_PF_ENTRY_COUNT 10
+
+//
+// This MACRO just enable unit test for the profile
+// Please disable it.
+//
+
+#define IA32_PF_EC_P (1u << 0)
+#define IA32_PF_EC_WR (1u << 1)
+#define IA32_PF_EC_US (1u << 2)
+#define IA32_PF_EC_RSVD (1u << 3)
+#define IA32_PF_EC_ID (1u << 4)
+
+#define SMM_PROFILE_NAME L"SmmProfileData"
+
+//
+// CPU generic definition
+//
+#define IA32_PG_NX (1ll << 63)
+
+#define IA32_CPUID_SS 0x08000000
+
+#define CPUID1_EDX_XD_SUPPORT 0x100000
+#define MSR_EFER 0xc0000080
+#define MSR_EFER_XD 0x800
+
+#define CPUID1_EDX_BTS_AVAILABLE 0x200000
+
+#define DR6_SINGLE_STEP 0x4000
+#define RFLAG_TF 0x100
+
+#define MSR_DEBUG_CTL 0x1D9
+#define MSR_DEBUG_CTL_LBR 0x1
+#define MSR_DEBUG_CTL_TR 0x40
+#define MSR_DEBUG_CTL_BTS 0x80
+#define MSR_DEBUG_CTL_BTINT 0x100
+#define MSR_LASTBRANCH_TOS 0x1C9
+#define MSR_LER_FROM_LIP 0x1DD
+#define MSR_LER_TO_LIP 0x1DE
+#define MSR_DS_AREA 0x600
+
+//
+// CPU generic definition
+//
+#define IA32_PG_NX (1ll << 63)
+
+#define IA32_CPUID_SS 0x08000000
+
+#define CPUID1_EDX_XD_SUPPORT 0x100000
+#define MSR_EFER 0xc0000080
+#define MSR_EFER_XD 0x800
+
+#define DR6_SINGLE_STEP 0x4000
+#define RFLAG_TF 0x100
+
+#define MSR_DEBUG_CTL 0x1D9
+#define MSR_DEBUG_CTL_LBR 0x1
+#define MSR_DEBUG_CTL_TR 0x40
+#define MSR_DEBUG_CTL_BTS 0x80
+#define MSR_DEBUG_CTL_BTINT 0x100
+#define MSR_LASTBRANCH_TOS 0x1C9
+#define MSR_LER_FROM_LIP 0x1DD
+#define MSR_LER_TO_LIP 0x1DE
+#define MSR_DS_AREA 0x600
+
+typedef struct {
+ EFI_PHYSICAL_ADDRESS Base;
+ EFI_PHYSICAL_ADDRESS Top;
+} MEMORY_RANGE;
+
+typedef struct {
+ MEMORY_RANGE Range;
+ BOOLEAN Present;
+ BOOLEAN Nx;
+} MEMORY_PROTECTION_RANGE;
+
+typedef struct {
+ UINT64 HeaderSize;
+ UINT64 MaxDataEntries;
+ UINT64 MaxDataSize;
+ UINT64 CurDataEntries;
+ UINT64 CurDataSize;
+ UINT64 TsegStart;
+ UINT64 TsegSize;
+ UINT64 NumSmis;
+ UINT64 NumCpus;
+} SMM_PROFILE_HEADER;
+
+typedef struct {
+ UINT64 SmiNum;
+ UINT64 CpuNum;
+ UINT64 ApicId;
+ UINT64 ErrorCode;
+ UINT64 Instruction;
+ UINT64 Address;
+ UINT64 SmiCmd;
+} SMM_PROFILE_ENTRY;
+
+extern SMM_S3_RESUME_STATE *mSmmS3ResumeState;
+extern UINTN gSmiExceptionHandlers[];
+extern BOOLEAN mXdSupported;
+extern UINTN mPFEntryCount[FixedPcdGet32 (PcdCpuMaxLogicalProcessorNumber)];
+extern UINT64 mLastPFEntryValue[FixedPcdGet32 (PcdCpuMaxLogicalProcessorNumber)][MAX_PF_ENTRY_COUNT];
+extern UINT64 *mLastPFEntryPointer[FixedPcdGet32 (PcdCpuMaxLogicalProcessorNumber)][MAX_PF_ENTRY_COUNT];
+
+//
+// Internal functions
+//
+
+/**
+ Update IDT table to replace page fault handler and INT 1 handler.
+
+**/
+VOID
+InitIdtr (
+ VOID
+ );
+
+/**
+ Check if the memory address will be mapped by 4KB-page.
+
+ @param Address The address of Memory.
+
+**/
+BOOLEAN
+IsAddressSplit (
+ IN EFI_PHYSICAL_ADDRESS Address
+ );
+
+/**
+ Check if the memory address will be mapped by 4KB-page.
+
+ @param Address The address of Memory.
+ @param Nx The flag indicates if the memory is execute-disable.
+
+**/
+BOOLEAN
+IsAddressValid (
+ IN EFI_PHYSICAL_ADDRESS Address,
+ IN BOOLEAN *Nx
+ );
+
+/**
+ Page Fault handler for SMM use.
+
+**/
+VOID
+EFIAPI
+SmiDefaultPFHandler (
+ VOID
+ );
+
+#endif // _SMM_PROFILE_H_
diff --git a/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/PiSmmCpuDxeSmm/SyncTimer.c b/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/PiSmmCpuDxeSmm/SyncTimer.c
new file mode 100644
index 0000000000..a2c2f1e75b
--- /dev/null
+++ b/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/PiSmmCpuDxeSmm/SyncTimer.c
@@ -0,0 +1,111 @@
+/** @file
+
+ Copyright (c) 2012 - 2015, 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 "PiSmmCpuDxeSmm.h"
+
+UINT64 mTimeoutTicker = 0;
+//
+// Number of counts in a roll-over cycle of the performance counter.
+//
+UINT64 mCycle = 0;
+//
+// Flag to indicate the performance counter is count-up or count-down.
+//
+BOOLEAN mCountDown;
+
+/**
+ Initialize Timer for Smm AP Sync.
+
+**/
+VOID
+InitializeSmmTimer (
+ VOID
+ )
+{
+ UINT64 TimerFrequency;
+ UINT64 Start;
+ UINT64 End;
+
+ TimerFrequency = GetPerformanceCounterProperties (&Start, &End);
+ mTimeoutTicker = DivU64x32 (
+ MultU64x64(TimerFrequency, PcdGet64 (PcdCpuSmmApSyncTimeout)),
+ 1000 * 1000
+ );
+ if (End < Start) {
+ mCountDown = TRUE;
+ mCycle = Start - End;
+ } else {
+ mCountDown = FALSE;
+ mCycle = End - Start;
+ }
+}
+
+/**
+ Start Timer for Smm AP Sync.
+
+**/
+UINT64
+EFIAPI
+StartSyncTimer (
+ VOID
+ )
+{
+ return GetPerformanceCounter ();
+}
+
+/**
+ Check if the Smm AP Sync timer is timeout.
+
+ @param Timer The start timer from the begin.
+
+**/
+BOOLEAN
+EFIAPI
+IsSyncTimerTimeout (
+ IN UINT64 Timer
+ )
+{
+ UINT64 CurrentTimer;
+ UINT64 Delta;
+
+ CurrentTimer = GetPerformanceCounter ();
+
+ if (mCountDown) {
+ //
+ // The performance counter counts down. Check for roll over condition.
+ //
+ if (CurrentTimer < Timer) {
+ Delta = Timer - CurrentTimer;
+ } else {
+ //
+ // Handle one roll-over.
+ //
+ Delta = mCycle - (CurrentTimer - Timer);
+ }
+ } else {
+ //
+ // The performance counter counts up. Check for roll over condition.
+ //
+ if (CurrentTimer > Timer) {
+ Delta = CurrentTimer - Timer;
+ } else {
+ //
+ // Handle one roll-over.
+ //
+ Delta = mCycle - (Timer - CurrentTimer);
+ }
+ }
+
+ return (BOOLEAN) (Delta >= mTimeoutTicker);
+}
diff --git a/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/PiSmmCpuDxeSmm/X64/MpFuncs.S b/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/PiSmmCpuDxeSmm/X64/MpFuncs.S
new file mode 100644
index 0000000000..c311568a17
--- /dev/null
+++ b/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/PiSmmCpuDxeSmm/X64/MpFuncs.S
@@ -0,0 +1,198 @@
+## @file
+# This is the assembly code for Multi-processor S3 support
+#
+# Copyright (c) 2006 - 2015, 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
+#
+##
+
+.equ VacantFlag, 0x0
+.equ NotVacantFlag, 0xff
+
+.equ LockLocation, RendezvousFunnelProcEnd - RendezvousFunnelProcStart
+.equ StackStartAddressLocation, RendezvousFunnelProcEnd - RendezvousFunnelProcStart + 0x08
+.equ StackSizeLocation, RendezvousFunnelProcEnd - RendezvousFunnelProcStart + 0x10
+.equ CProcedureLocation, RendezvousFunnelProcEnd - RendezvousFunnelProcStart + 0x18
+.equ GdtrLocation, RendezvousFunnelProcEnd - RendezvousFunnelProcStart + 0x20
+.equ IdtrLocation, RendezvousFunnelProcEnd - RendezvousFunnelProcStart + 0x2A
+.equ BufferStartLocation, RendezvousFunnelProcEnd - RendezvousFunnelProcStart + 0x34
+.equ Cr3OffsetLocation, RendezvousFunnelProcEnd - RendezvousFunnelProcStart + 0x38
+
+#-------------------------------------------------------------------------------------
+#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);
+
+.code:
+
+ASM_GLOBAL ASM_PFX(RendezvousFunnelProc)
+ASM_PFX(RendezvousFunnelProc):
+RendezvousFunnelProcStart:
+
+# At this point CS = 0x(vv00) and ip= 0x0.
+
+ .byte 0x8c,0xc8 # mov ax, cs
+ .byte 0x8e,0xd8 # mov ds, ax
+ .byte 0x8e,0xc0 # mov es, ax
+ .byte 0x8e,0xd0 # mov ss, ax
+ .byte 0x33,0xc0 # xor ax, ax
+ .byte 0x8e,0xe0 # mov fs, ax
+ .byte 0x8e,0xe8 # mov gs, ax
+
+flat32Start:
+
+ .byte 0xBE
+ .word BufferStartLocation
+ .byte 0x66,0x8B,0x14 # mov edx,dword ptr [si] ; EDX is keeping the start address of wakeup buffer
+
+ .byte 0xBE
+ .word Cr3OffsetLocation
+ .byte 0x66,0x8B,0xC # mov ecx,dword ptr [si] ; ECX is keeping the value of CR3
+
+ .byte 0xBE
+ .word GdtrLocation
+ .byte 0x66 # db 66h
+ .byte 0x2E,0xF,0x1,0x14 # lgdt fword ptr cs:[si]
+
+ .byte 0xBE
+ .word IdtrLocation
+ .byte 0x66 # db 66h
+ .byte 0x2E,0xF,0x1,0x1C # lidt fword ptr cs:[si]
+
+ .byte 0x33,0xC0 # xor ax, ax
+ .byte 0x8E,0xD8 # mov ds, ax
+
+ .byte 0xF,0x20,0xC0 # mov eax, cr0 ; Get control register 0
+ .byte 0x66,0x83,0xC8,0x1 # or eax, 000000001h ; Set PE bit (bit #0)
+ .byte 0xF,0x22,0xC0 # mov cr0, eax
+
+FLAT32_JUMP:
+
+ .byte 0x66,0x67,0xEA # far jump
+ .long 0x0 # 32-bit offset
+ .word 0x20 # 16-bit selector
+
+NemInit: # protected mode entry point
+
+ .byte 0x66,0xB8,0x18,0x0 # mov ax, 18h
+ .byte 0x66,0x8E,0xD8 # mov ds, ax
+ .byte 0x66,0x8E,0xC0 # mov es, ax
+ .byte 0x66,0x8E,0xE0 # mov fs, ax
+ .byte 0x66,0x8E,0xE8 # mov gs, ax
+ .byte 0x66,0x8E,0xD0 # mov ss, ax ; Flat mode setup.
+
+ .byte 0xF,0x20,0xE0 # mov eax, cr4
+ .byte 0xF,0xBA,0xE8,0x5 # bts eax, 5
+ .byte 0xF,0x22,0xE0 # mov cr4, eax
+
+ .byte 0xF,0x22,0xD9 # mov cr3, ecx
+
+ .byte 0x8B,0xF2 # mov esi, edx ; Save wakeup buffer address
+
+ .byte 0xB9
+ .long 0xC0000080 # mov ecx, 0c0000080h ; EFER MSR number.
+ .byte 0xF,0x32 # rdmsr ; Read EFER.
+ .byte 0xF,0xBA,0xE8,0x8 # bts eax, 8 ; Set LME=1.
+ .byte 0xF,0x30 # wrmsr ; Write EFER.
+
+ .byte 0xF,0x20,0xC0 # mov eax, cr0 ; Read CR0.
+ .byte 0xF,0xBA,0xE8,0x1F # bts eax, 31 ; Set PG=1.
+ .byte 0xF,0x22,0xC0 # mov cr0, eax ; Write CR0.
+
+LONG_JUMP:
+
+ .byte 0x67,0xEA # far jump
+ .long 0x0 # 32-bit offset
+ .word 0x38 # 16-bit selector
+
+LongModeStart:
+
+ movw $0x30,%ax
+ .byte 0x66
+ movw %ax,%ds
+ .byte 0x66
+ movw %ax,%es
+ .byte 0x66
+ movw %ax,%ss
+
+ movl %esi,%edi
+ addl $LockLocation, %edi
+ movb $NotVacantFlag, %al
+TestLock:
+ xchgb (%edi), %al
+ cmpb $NotVacantFlag, %al
+ jz TestLock
+
+ProgramStack:
+
+ movl %esi,%edi
+ addl $StackSizeLocation, %edi
+ movq (%edi), %rax
+ movl %esi,%edi
+ addl $StackStartAddressLocation, %edi
+ addq (%edi), %rax
+ movq %rax, %rsp
+ movq %rax, (%edi)
+
+Releaselock:
+
+ movb $VacantFlag, %al
+ movl %esi,%edi
+ addl $LockLocation, %edi
+ xchgb (%edi), %al
+
+ #
+ # Call assembly function to initialize FPU.
+ #
+ movabsq $ASM_PFX(InitializeFloatingPointUnits), %rax
+ subq $0x20, %rsp
+ call *%rax
+ addq $0x20, %rsp
+ #
+ # Call C Function
+ #
+ movl %esi,%edi
+ addl $CProcedureLocation, %edi
+ movq (%edi), %rax
+
+ testq %rax, %rax
+ jz GoToSleep
+
+ subq $0x20, %rsp
+ call *%rax
+ addq $0x20, %rsp
+
+GoToSleep:
+ cli
+ hlt
+ jmp .-2
+
+RendezvousFunnelProcEnd:
+
+
+#-------------------------------------------------------------------------------------
+# AsmGetAddressMap (&AddressMap);
+#-------------------------------------------------------------------------------------
+# comments here for definition of address map
+ASM_GLOBAL ASM_PFX(AsmGetAddressMap)
+ASM_PFX(AsmGetAddressMap):
+ movabsq $RendezvousFunnelProcStart, %rax
+ movq %rax, (%rcx)
+ movq $(NemInit - RendezvousFunnelProcStart), 0x08(%rcx)
+ movq $(FLAT32_JUMP - RendezvousFunnelProcStart), 0x10(%rcx)
+ movq $(RendezvousFunnelProcEnd - RendezvousFunnelProcStart), 0x18(%rcx)
+ movq $(LongModeStart - RendezvousFunnelProcStart), 0x20(%rcx)
+ movq $(LONG_JUMP - RendezvousFunnelProcStart), 0x28(%rcx)
+ ret
+
diff --git a/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/PiSmmCpuDxeSmm/X64/MpFuncs.asm b/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/PiSmmCpuDxeSmm/X64/MpFuncs.asm
new file mode 100644
index 0000000000..f0a0bc3f89
--- /dev/null
+++ b/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/PiSmmCpuDxeSmm/X64/MpFuncs.asm
@@ -0,0 +1,201 @@
+;; @file
+; This is the assembly code for Multi-processor S3 support
+;
+; Copyright (c) 2006 - 2015, 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.
+;
+;;
+
+EXTERN InitializeFloatingPointUnits:PROC
+
+VacantFlag Equ 00h
+NotVacantFlag Equ 0ffh
+
+LockLocation equ RendezvousFunnelProcEnd - RendezvousFunnelProcStart
+StackStartAddressLocation equ LockLocation + 08h
+StackSizeLocation equ LockLocation + 10h
+CProcedureLocation equ LockLocation + 18h
+GdtrLocation equ LockLocation + 20h
+IdtrLocation equ LockLocation + 2Ah
+BufferStartLocation equ LockLocation + 34h
+Cr3OffsetLocation equ LockLocation + 38h
+
+;-------------------------------------------------------------------------------------
+;RendezvousFunnelProc procedure follows. All APs execute their procedure. This
+;procedure serializes all the AP processors through an Init sequence. It must be
+;noted that APs arrive here very raw...ie: real mode, no stack.
+;ALSO THIS PROCEDURE IS EXECUTED BY APs ONLY ON 16 BIT MODE. HENCE THIS PROC
+;IS IN MACHINE CODE.
+;-------------------------------------------------------------------------------------
+;RendezvousFunnelProc (&WakeUpBuffer,MemAddress);
+
+;text SEGMENT
+.code
+
+RendezvousFunnelProc PROC
+RendezvousFunnelProcStart::
+
+; At this point CS = 0x(vv00) and ip= 0x0.
+
+ db 8ch, 0c8h ; mov ax, cs
+ db 8eh, 0d8h ; mov ds, ax
+ db 8eh, 0c0h ; mov es, ax
+ db 8eh, 0d0h ; mov ss, ax
+ db 33h, 0c0h ; xor ax, ax
+ db 8eh, 0e0h ; mov fs, ax
+ db 8eh, 0e8h ; mov gs, ax
+
+flat32Start::
+
+ db 0BEh
+ dw BufferStartLocation ; mov si, BufferStartLocation
+ db 66h, 8Bh, 14h ; mov edx,dword ptr [si] ; EDX is keeping the start address of wakeup buffer
+
+ db 0BEh
+ dw Cr3OffsetLocation ; mov si, Cr3Location
+ db 66h, 8Bh, 0Ch ; mov ecx,dword ptr [si] ; ECX is keeping the value of CR3
+
+ db 0BEh
+ dw GdtrLocation ; mov si, GdtrProfile
+ db 66h ; db 66h
+ db 2Eh, 0Fh, 01h, 14h ; lgdt fword ptr cs:[si]
+
+ db 0BEh
+ 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, 01h ; or eax, 000000001h ; Set PE bit (bit #0)
+ db 0Fh, 22h, 0C0h ; mov cr0, eax
+
+FLAT32_JUMP::
+
+ db 66h, 67h, 0EAh ; far jump
+ dd 0h ; 32-bit offset
+ dw 20h ; 16-bit selector
+
+NemInit:: ; protected mode entry point
+
+ db 66h, 0B8h, 18h, 00h ; mov ax, 18h
+ db 66h, 8Eh, 0D8h ; mov ds, ax
+ db 66h, 8Eh, 0C0h ; mov es, ax
+ db 66h, 8Eh, 0E0h ; mov fs, ax
+ db 66h, 8Eh, 0E8h ; mov gs, ax
+ db 66h, 8Eh, 0D0h ; mov ss, ax ; Flat mode setup.
+
+ db 0Fh, 20h, 0E0h ; mov eax, cr4
+ db 0Fh, 0BAh, 0E8h, 05h ; bts eax, 5
+ db 0Fh, 22h, 0E0h ; mov cr4, eax
+
+ db 0Fh, 22h, 0D9h ; mov cr3, ecx
+
+ db 8Bh, 0F2h ; mov esi, edx ; Save wakeup buffer address
+
+ db 0B9h
+ dd 0C0000080h ; mov ecx, 0c0000080h ; EFER MSR number.
+ db 0Fh, 32h ; rdmsr ; Read EFER.
+ db 0Fh, 0BAh, 0E8h, 08h ; bts eax, 8 ; Set LME=1.
+ db 0Fh, 30h ; wrmsr ; Write EFER.
+
+ db 0Fh, 20h, 0C0h ; mov eax, cr0 ; Read CR0.
+ db 0Fh, 0BAh, 0E8h, 1Fh ; bts eax, 31 ; Set PG=1.
+ db 0Fh, 22h, 0C0h ; mov cr0, eax ; Write CR0.
+
+LONG_JUMP::
+
+ db 67h, 0EAh ; far jump
+ dd 0h ; 32-bit offset
+ dw 38h ; 16-bit selector
+
+LongModeStart::
+
+ mov ax, 30h
+ mov ds, ax
+ mov es, ax
+ mov ss, ax
+
+ mov edi, esi
+ add edi, LockLocation
+ mov al, NotVacantFlag
+TestLock::
+ xchg byte ptr [edi], al
+ cmp al, NotVacantFlag
+ jz TestLock
+
+ProgramStack::
+
+ mov edi, esi
+ add edi, StackSizeLocation
+ mov rax, qword ptr [edi]
+ mov edi, esi
+ add edi, StackStartAddressLocation
+ add rax, qword ptr [edi]
+ mov rsp, rax
+ mov qword ptr [edi], rax
+
+Releaselock::
+
+ mov al, VacantFlag
+ mov edi, esi
+ add edi, LockLocation
+ xchg byte ptr [edi], al
+
+ ;
+ ; Call assembly function to initialize FPU.
+ ;
+ mov rax, InitializeFloatingPointUnits
+ sub rsp, 20h
+ call rax
+ add rsp, 20h
+
+ ;
+ ; Call C Function
+ ;
+ mov edi, esi
+ add edi, CProcedureLocation
+ mov rax, qword ptr [edi]
+
+ test rax, rax
+ jz GoToSleep
+
+ sub rsp, 20h
+ call rax
+ add rsp, 20h
+
+GoToSleep::
+ cli
+ hlt
+ jmp $-2
+
+RendezvousFunnelProcEnd::
+RendezvousFunnelProc ENDP
+
+
+;-------------------------------------------------------------------------------------
+; AsmGetAddressMap (&AddressMap);
+;-------------------------------------------------------------------------------------
+; comments here for definition of address map
+AsmGetAddressMap PROC
+ mov rax, offset RendezvousFunnelProcStart
+ mov qword ptr [rcx], rax
+ mov qword ptr [rcx+8h], NemInit - RendezvousFunnelProcStart
+ mov qword ptr [rcx+10h], FLAT32_JUMP - RendezvousFunnelProcStart
+ mov qword ptr [rcx+18h], RendezvousFunnelProcEnd - RendezvousFunnelProcStart
+ mov qword ptr [rcx+20h], LongModeStart - RendezvousFunnelProcStart
+ mov qword ptr [rcx+28h], LONG_JUMP - RendezvousFunnelProcStart
+ ret
+
+AsmGetAddressMap ENDP
+
+END
diff --git a/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/PiSmmCpuDxeSmm/X64/PageTbl.c b/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/PiSmmCpuDxeSmm/X64/PageTbl.c
new file mode 100644
index 0000000000..11f2660a6d
--- /dev/null
+++ b/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/PiSmmCpuDxeSmm/X64/PageTbl.c
@@ -0,0 +1,647 @@
+/** @file
+ Page Fault (#PF) handler for X64 processors
+
+ Copyright (c) 2009 - 2015, 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 "PiSmmCpuDxeSmm.h"
+
+#define PAGE_TABLE_PAGES 8
+#define IA32_PG_PMNT (1ull << 62)
+#define ACC_MAX_BIT BIT3
+LIST_ENTRY mPagePool = INITIALIZE_LIST_HEAD_VARIABLE (mPagePool);
+SPIN_LOCK mPFLock;
+BOOLEAN m1GPageTableSupport = FALSE;
+
+/**
+ Check if 1-GByte pages is supported by processor or not.
+
+ @retval TRUE 1-GByte pages is supported.
+ @retval FALSE 1-GByte pages is not supported.
+
+**/
+BOOLEAN
+Is1GPageSupport (
+ VOID
+ )
+{
+ UINT32 RegEax;
+ UINT32 RegEdx;
+ UINT64 mPhyMask;
+
+ AsmCpuid (0x80000008, &RegEax, NULL, NULL, NULL);
+ mPhyMask = LShiftU64 (1, (UINT8)RegEax) - 1;
+ mPhyMask &= (1ull << 48) - SIZE_4KB;
+
+ AsmCpuid (0x80000000, &RegEax, NULL, NULL, NULL);
+ if (RegEax >= 0x80000001) {
+ AsmCpuid (0x80000001, NULL, NULL, NULL, &RegEdx);
+ if ((RegEdx & BIT26) != 0) {
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+/**
+ Set sub-entries number in entry.
+
+ @param[in, out] Entry Pointer to entry
+ @param[in] SubEntryNum Sub-entries number based on 0:
+ 0 means there is 1 sub-entry under this entry
+ 0x1ff means there is 512 sub-entries under this entry
+
+**/
+VOID
+SetSubEntriesNum (
+ IN OUT UINT64 *Entry,
+ IN UINT64 SubEntryNum
+ )
+{
+ //
+ // Sub-entries number is saved in BIT52 to BIT60 (reserved field) in Entry
+ //
+ *Entry = BitFieldWrite64 (*Entry, 52, 60, SubEntryNum);
+}
+
+/**
+ Return sub-entries number in entry.
+
+ @param[in] Entry Pointer to entry
+
+ @return Sub-entries number based on 0:
+ 0 means there is 1 sub-entry under this entry
+ 0x1ff means there is 512 sub-entries under this entry
+**/
+UINT64
+GetSubEntriesNum (
+ IN UINT64 *Entry
+ )
+{
+ //
+ // Sub-entries number is saved in BIT52 to BIT60 (reserved field) in Entry
+ //
+ return BitFieldRead64 (*Entry, 52, 60);
+}
+
+/**
+ Create PageTable for SMM use.
+
+ @return The address of PML4 (to set CR3).
+
+**/
+UINT32
+SmmInitPageTable (
+ VOID
+ )
+{
+ EFI_PHYSICAL_ADDRESS Pages;
+ UINT64 *PTEntry;
+ LIST_ENTRY *FreePage;
+ UINTN Index;
+
+ //
+ // Initialize spin lock
+ //
+ InitializeSpinLock (&mPFLock);
+
+ m1GPageTableSupport = Is1GPageSupport ();
+ //
+ // Generate PAE page table for the first 4GB memory space
+ //
+ Pages = Gen4GPageTable (PAGE_TABLE_PAGES + 1);
+
+ //
+ // Set IA32_PG_PMNT bit to mask this entry
+ //
+ PTEntry = (UINT64*)(UINTN)Pages;
+ for (Index = 0; Index < 4; Index++) {
+ PTEntry[Index] |= IA32_PG_PMNT;
+ }
+
+ //
+ // Fill Page-Table-Level4 (PML4) entry
+ //
+ PTEntry = (UINT64*)(UINTN)(Pages - EFI_PAGES_TO_SIZE (PAGE_TABLE_PAGES + 1));
+ *PTEntry = Pages + IA32_PG_P;
+ ZeroMem (PTEntry + 1, EFI_PAGE_SIZE - sizeof (*PTEntry));
+ //
+ // Set sub-entries number
+ //
+ SetSubEntriesNum (PTEntry, 3);
+
+ //
+ // Add remaining pages to page pool
+ //
+ FreePage = (LIST_ENTRY*)(PTEntry + EFI_PAGE_SIZE / sizeof (*PTEntry));
+ while ((UINTN)FreePage < Pages) {
+ InsertTailList (&mPagePool, FreePage);
+ FreePage += EFI_PAGE_SIZE / sizeof (*FreePage);
+ }
+
+ //
+ // Register Smm Page Fault Handler
+ //
+ SmmRegisterExceptionHandler (&mSmmCpuService, EXCEPT_IA32_PAGE_FAULT, SmiPFHandler);
+
+ //
+ // Return the address of PML4 (to set CR3)
+ //
+ return (UINT32)(UINTN)PTEntry;
+}
+
+/**
+ Set access record in entry.
+
+ @param[in, out] Entry Pointer to entry
+ @param[in] Acc Access record value
+
+**/
+VOID
+SetAccNum (
+ IN OUT UINT64 *Entry,
+ IN UINT64 Acc
+ )
+{
+ //
+ // Access record is saved in BIT9 to BIT11 (reserved field) in Entry
+ //
+ *Entry = BitFieldWrite64 (*Entry, 9, 11, Acc);
+}
+
+/**
+ Return access record in entry.
+
+ @param[in] Entry Pointer to entry
+
+ @return Access record value.
+
+**/
+UINT64
+GetAccNum (
+ IN UINT64 *Entry
+ )
+{
+ //
+ // Access record is saved in BIT9 to BIT11 (reserved field) in Entry
+ //
+ return BitFieldRead64 (*Entry, 9, 11);
+}
+
+/**
+ Return and update the access record in entry.
+
+ @param[in, out] Entry Pointer to entry
+
+ @return Access record value.
+
+**/
+UINT64
+GetAndUpdateAccNum (
+ IN OUT UINT64 *Entry
+ )
+{
+ UINT64 Acc;
+
+ Acc = GetAccNum (Entry);
+ if ((*Entry & IA32_PG_A) != 0) {
+ //
+ // If this entry has been accessed, clear access flag in Entry and update access record
+ // to the initializ value 7, adding ACC_MAX_BIT is to make it larger than others
+ //
+ *Entry &= ~(UINT64)(UINTN)IA32_PG_A;
+ SetAccNum (Entry, 0x7);
+ return (0x7 + ACC_MAX_BIT);
+ } else {
+ if (Acc != 0) {
+ //
+ // If the access record is not the smallest value 0, minus 1 and update the access record field
+ //
+ SetAccNum (Entry, Acc - 1);
+ }
+ }
+ return Acc;
+}
+
+/**
+ Reclaim free pages for PageFault handler.
+
+ Search the whole entries tree to find the leaf entry that has the smallest
+ access record value. Insert the page pointed by this leaf entry into the
+ page pool. And check its upper entries if need to be inserted into the page
+ pool or not.
+
+**/
+VOID
+ReclaimPages (
+ VOID
+ )
+{
+ UINT64 *Pml4;
+ UINT64 *Pdpt;
+ UINT64 *Pdt;
+ UINTN Pml4Index;
+ UINTN PdptIndex;
+ UINTN PdtIndex;
+ UINTN MinPml4;
+ UINTN MinPdpt;
+ UINTN MinPdt;
+ UINT64 MinAcc;
+ UINT64 Acc;
+ UINT64 SubEntriesNum;
+ BOOLEAN PML4EIgnore;
+ BOOLEAN PDPTEIgnore;
+ UINT64 *ReleasePageAddress;
+
+ Pml4 = NULL;
+ Pdpt = NULL;
+ Pdt = NULL;
+ MinAcc = (UINT64)-1;
+ MinPml4 = (UINTN)-1;
+ MinPdpt = (UINTN)-1;
+ MinPdt = (UINTN)-1;
+ Acc = 0;
+ ReleasePageAddress = 0;
+
+ //
+ // Fristly, find the leaf entry has the smallest access record value
+ //
+ Pml4 = (UINT64*)(UINTN)(AsmReadCr3 () & gPhyMask);
+ for (Pml4Index = 0; Pml4Index < EFI_PAGE_SIZE / sizeof (*Pml4); Pml4Index++) {
+ if ((Pml4[Pml4Index] & IA32_PG_P) == 0 || (Pml4[Pml4Index] & IA32_PG_PMNT) != 0) {
+ //
+ // If the PML4 entry is not present or is masked, skip it
+ //
+ continue;
+ }
+ Pdpt = (UINT64*)(UINTN)(Pml4[Pml4Index] & gPhyMask);
+ PML4EIgnore = FALSE;
+ for (PdptIndex = 0; PdptIndex < EFI_PAGE_SIZE / sizeof (*Pdpt); PdptIndex++) {
+ if ((Pdpt[PdptIndex] & IA32_PG_P) == 0 || (Pdpt[PdptIndex] & IA32_PG_PMNT) != 0) {
+ //
+ // If the PDPT entry is not present or is masked, skip it
+ //
+ if ((Pdpt[PdptIndex] & IA32_PG_PMNT) != 0) {
+ //
+ // If the PDPT entry is masked, we will ignore checking the PML4 entry
+ //
+ PML4EIgnore = TRUE;
+ }
+ continue;
+ }
+ if ((Pdpt[PdptIndex] & IA32_PG_PS) == 0) {
+ //
+ // It's not 1-GByte pages entry, it should be a PDPT entry,
+ // we will not check PML4 entry more
+ //
+ PML4EIgnore = TRUE;
+ Pdt = (UINT64*)(UINTN)(Pdpt[PdptIndex] & gPhyMask);
+ PDPTEIgnore = FALSE;
+ for (PdtIndex = 0; PdtIndex < EFI_PAGE_SIZE / sizeof(*Pdt); PdtIndex++) {
+ if ((Pdt[PdtIndex] & IA32_PG_P) == 0 || (Pdt[PdtIndex] & IA32_PG_PMNT) != 0) {
+ //
+ // If the PD entry is not present or is masked, skip it
+ //
+ if ((Pdt[PdtIndex] & IA32_PG_PMNT) != 0) {
+ //
+ // If the PD entry is masked, we will not PDPT entry more
+ //
+ PDPTEIgnore = TRUE;
+ }
+ continue;
+ }
+ if ((Pdt[PdtIndex] & IA32_PG_PS) == 0) {
+ //
+ // It's not 2 MByte page table entry, it should be PD entry
+ // we will find the entry has the smallest access record value
+ //
+ PDPTEIgnore = TRUE;
+ Acc = GetAndUpdateAccNum (Pdt + PdtIndex);
+ if (Acc < MinAcc) {
+ //
+ // If the PD entry has the smallest access record value,
+ // save the Page address to be released
+ //
+ MinAcc = Acc;
+ MinPml4 = Pml4Index;
+ MinPdpt = PdptIndex;
+ MinPdt = PdtIndex;
+ ReleasePageAddress = Pdt + PdtIndex;
+ }
+ }
+ }
+ if (!PDPTEIgnore) {
+ //
+ // If this PDPT entry has no PDT entries pointer to 4 KByte pages,
+ // it should only has the entries point to 2 MByte Pages
+ //
+ Acc = GetAndUpdateAccNum (Pdpt + PdptIndex);
+ if (Acc < MinAcc) {
+ //
+ // If the PDPT entry has the smallest access record value,
+ // save the Page address to be released
+ //
+ MinAcc = Acc;
+ MinPml4 = Pml4Index;
+ MinPdpt = PdptIndex;
+ MinPdt = (UINTN)-1;
+ ReleasePageAddress = Pdpt + PdptIndex;
+ }
+ }
+ }
+ }
+ if (!PML4EIgnore) {
+ //
+ // If PML4 entry has no the PDPT entry pointer to 2 MByte pages,
+ // it should only has the entries point to 1 GByte Pages
+ //
+ Acc = GetAndUpdateAccNum (Pml4 + Pml4Index);
+ if (Acc < MinAcc) {
+ //
+ // If the PML4 entry has the smallest access record value,
+ // save the Page address to be released
+ //
+ MinAcc = Acc;
+ MinPml4 = Pml4Index;
+ MinPdpt = (UINTN)-1;
+ MinPdt = (UINTN)-1;
+ ReleasePageAddress = Pml4 + Pml4Index;
+ }
+ }
+ }
+ //
+ // Make sure one PML4/PDPT/PD entry is selected
+ //
+ ASSERT (MinAcc != (UINT64)-1);
+
+ //
+ // Secondly, insert the page pointed by this entry into page pool and clear this entry
+ //
+ InsertTailList (&mPagePool, (LIST_ENTRY*)(UINTN)(*ReleasePageAddress & gPhyMask));
+ *ReleasePageAddress = 0;
+
+ //
+ // Lastly, check this entry's upper entries if need to be inserted into page pool
+ // or not
+ //
+ while (TRUE) {
+ if (MinPdt != (UINTN)-1) {
+ //
+ // If 4 KByte Page Table is released, check the PDPT entry
+ //
+ Pdpt = (UINT64*)(UINTN)(Pml4[MinPml4] & gPhyMask);
+ SubEntriesNum = GetSubEntriesNum(Pdpt + MinPdpt);
+ if (SubEntriesNum == 0) {
+ //
+ // Release the empty Page Directory table if there was no more 4 KByte Page Table entry
+ // clear the Page directory entry
+ //
+ InsertTailList (&mPagePool, (LIST_ENTRY*)(UINTN)(Pdpt[MinPdpt] & gPhyMask));
+ Pdpt[MinPdpt] = 0;
+ //
+ // Go on checking the PML4 table
+ //
+ MinPdt = (UINTN)-1;
+ continue;
+ }
+ //
+ // Update the sub-entries filed in PDPT entry and exit
+ //
+ SetSubEntriesNum (Pdpt + MinPdpt, SubEntriesNum - 1);
+ break;
+ }
+ if (MinPdpt != (UINTN)-1) {
+ //
+ // One 2MB Page Table is released or Page Directory table is released, check the PML4 entry
+ //
+ SubEntriesNum = GetSubEntriesNum (Pml4 + MinPml4);
+ if (SubEntriesNum == 0) {
+ //
+ // Release the empty PML4 table if there was no more 1G KByte Page Table entry
+ // clear the Page directory entry
+ //
+ InsertTailList (&mPagePool, (LIST_ENTRY*)(UINTN)(Pml4[MinPml4] & gPhyMask));
+ Pml4[MinPml4] = 0;
+ MinPdpt = (UINTN)-1;
+ continue;
+ }
+ //
+ // Update the sub-entries filed in PML4 entry and exit
+ //
+ SetSubEntriesNum (Pml4 + MinPml4, SubEntriesNum - 1);
+ break;
+ }
+ //
+ // PLM4 table has been released before, exit it
+ //
+ break;
+ }
+}
+
+/**
+ Allocate free Page for PageFault handler use.
+
+ @return Page address.
+
+**/
+UINT64
+AllocPage (
+ VOID
+ )
+{
+ UINT64 RetVal;
+
+ if (IsListEmpty (&mPagePool)) {
+ //
+ // If page pool is empty, reclaim the used pages and insert one into page pool
+ //
+ ReclaimPages ();
+ }
+
+ //
+ // Get one free page and remove it from page pool
+ //
+ RetVal = (UINT64)(UINTN)mPagePool.ForwardLink;
+ RemoveEntryList (mPagePool.ForwardLink);
+ //
+ // Clean this page and return
+ //
+ ZeroMem ((VOID*)(UINTN)RetVal, EFI_PAGE_SIZE);
+ return RetVal;
+}
+
+/**
+ Page Fault handler for SMM use.
+
+**/
+VOID
+SmiDefaultPFHandler (
+ VOID
+ )
+{
+ UINT64 *PageTable;
+ UINT64 *Pml4;
+ UINT64 PFAddress;
+ UINTN StartBit;
+ UINTN EndBit;
+ UINT64 PTIndex;
+ UINTN Index;
+ SMM_PAGE_SIZE_TYPE PageSize;
+ UINTN NumOfPages;
+ UINTN PageAttribute;
+ EFI_STATUS Status;
+ UINT64 *UpperEntry;
+
+ EndBit = 0;
+ Pml4 = (UINT64*)(AsmReadCr3 () & gPhyMask);
+ PFAddress = AsmReadCr2 ();
+
+ Status = GetPlatformPageTableAttribute (PFAddress, &PageSize, &NumOfPages, &PageAttribute);
+ //
+ // If platform not support page table attribute, set default SMM page attribute
+ //
+ if (Status != EFI_SUCCESS) {
+ PageSize = SmmPageSize2M;
+ NumOfPages = 1;
+ PageAttribute = 0;
+ }
+ if (PageSize >= MaxSmmPageSizeType) {
+ PageSize = SmmPageSize2M;
+ }
+ if (NumOfPages > 512) {
+ NumOfPages = 512;
+ }
+
+ switch (PageSize) {
+ case SmmPageSize4K:
+ //
+ // BIT12 to BIT20 is Page Table index
+ //
+ EndBit = 12;
+ break;
+ case SmmPageSize2M:
+ //
+ // BIT21 to BIT29 is Page Directory index
+ //
+ EndBit = 21;
+ PageAttribute |= IA32_PG_PS;
+ break;
+ case SmmPageSize1G:
+ if (!m1GPageTableSupport) {
+ DEBUG ((EFI_D_ERROR, "1-GByte pages is not supported!"));
+ ASSERT (FALSE);
+ }
+ //
+ // BIT30 to BIT38 is Page Directory Pointer Table index
+ //
+ EndBit = 30;
+ PageAttribute |= IA32_PG_PS;
+ break;
+ default:
+ ASSERT (FALSE);
+ }
+
+ for (Index = 0; Index < NumOfPages; Index++) {
+ PageTable = Pml4;
+ UpperEntry = NULL;
+ for (StartBit = 39; StartBit > EndBit; StartBit -= 9) {
+ PTIndex = BitFieldRead64 (PFAddress, StartBit, StartBit + 8);
+ if ((PageTable[PTIndex] & IA32_PG_P) == 0) {
+ //
+ // If the entry is not present, allocate one page from page pool for it
+ //
+ PageTable[PTIndex] = AllocPage () | IA32_PG_RW | IA32_PG_P;
+ } else {
+ //
+ // Save the upper entry address
+ //
+ UpperEntry = PageTable + PTIndex;
+ }
+ //
+ // BIT9 to BIT11 of entry is used to save access record,
+ // initailze value is 7
+ //
+ PageTable[PTIndex] |= IA32_PG_A;
+ SetAccNum (PageTable + PTIndex, 7);
+ PageTable = (UINT64*)(UINTN)(PageTable[PTIndex] & gPhyMask);
+ }
+
+ PTIndex = BitFieldRead64 (PFAddress, StartBit, StartBit + 8);
+ if ((PageTable[PTIndex] & IA32_PG_P) != 0) {
+ //
+ // Check if the entry has already existed, this issue may occur when the different
+ // size page entries created under the same entry
+ //
+ DEBUG ((EFI_D_ERROR, "PageTable = %lx, PTIndex = %x, PageTable[PTIndex] = %lx\n", PageTable, PTIndex, PageTable[PTIndex]));
+ DEBUG ((EFI_D_ERROR, "New page table overlapped with old page table!\n"));
+ ASSERT (FALSE);
+ }
+ //
+ // Fill the new entry
+ //
+ PageTable[PTIndex] = (PFAddress & gPhyMask & ~((1ull << EndBit) - 1)) |
+ PageAttribute | IA32_PG_A | IA32_PG_RW | IA32_PG_P;
+ if (UpperEntry != NULL) {
+ SetSubEntriesNum (UpperEntry, GetSubEntriesNum (UpperEntry) + 1);
+ }
+ //
+ // Get the next page address if we need to create more page tables
+ //
+ PFAddress += (1ull << EndBit);
+ }
+}
+
+/**
+ ThePage Fault handler wrapper for SMM use.
+
+ @param InterruptType Defines the type of interrupt or exception that
+ occurred on the processor.This parameter is processor architecture specific.
+ @param SystemContext A pointer to the processor context when
+ the interrupt occurred on the processor.
+**/
+VOID
+EFIAPI
+SmiPFHandler (
+ IN EFI_EXCEPTION_TYPE InterruptType,
+ IN EFI_SYSTEM_CONTEXT SystemContext
+ )
+{
+ UINTN PFAddress;
+
+ ASSERT (InterruptType == EXCEPT_IA32_PAGE_FAULT);
+
+ AcquireSpinLock (&mPFLock);
+
+ PFAddress = AsmReadCr2 ();
+
+ //
+ // If a page fault occurrs in SMRAM range, it should be in a SMM stack guard page.
+ //
+ if ((FeaturePcdGet (PcdCpuSmmStackGuard)) &&
+ (PFAddress >= mCpuHotPlugData.SmrrBase) &&
+ (PFAddress < (mCpuHotPlugData.SmrrBase + mCpuHotPlugData.SmrrSize))) {
+ DEBUG ((EFI_D_ERROR, "SMM stack overflow!\n"));
+ CpuDeadLoop ();
+ }
+
+ if (FeaturePcdGet (PcdCpuSmmProfileEnable)) {
+ SmmProfilePFHandler (
+ SystemContext.SystemContextX64->Rip,
+ SystemContext.SystemContextX64->ExceptionData
+ );
+ } else {
+ SmiDefaultPFHandler ();
+ }
+
+ ReleaseSpinLock (&mPFLock);
+}
+
diff --git a/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/PiSmmCpuDxeSmm/X64/Semaphore.c b/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/PiSmmCpuDxeSmm/X64/Semaphore.c
new file mode 100644
index 0000000000..534fe480b0
--- /dev/null
+++ b/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/PiSmmCpuDxeSmm/X64/Semaphore.c
@@ -0,0 +1,104 @@
+/** @file
+ Semaphore mechanism to indicate to the BSP that an AP has exited SMM
+ after SMBASE relocation.
+
+ Copyright (c) 2009 - 2015, 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 "PiSmmCpuDxeSmm.h"
+
+#define LMA BIT10
+
+UINTN mSmmRelocationOriginalAddress;
+BOOLEAN *mRebasedFlag;
+extern UINT32 mSmmRelocationOriginalAddressPtr32;
+extern UINT32 mRebasedFlagAddr32;
+
+/**
+ AP Seamphore operation in 32-bit mode while BSP runs in 64-bit mode.
+**/
+VOID
+SmmRelocationSemaphoreComplete32 (
+ VOID
+ );
+
+/**
+ Hook return address of SMM Save State so that semaphore code
+ can be executed immediately after AP exits SMM to indicate to
+ the BSP that an AP has exited SMM after SMBASE relocation.
+
+ @param[in] CpuIndex The processor index.
+
+**/
+VOID
+SemaphoreHook (
+ IN UINTN CpuIndex
+ )
+{
+ UINTN FunctionPointer;
+ UINT64 Efer;
+ UINT16 AutoHaltRestart;
+ SOCKET_LGA_775_SMM_CPU_STATE *CpuState;
+ UINTN TempValue;
+
+ mRebasedFlag = (BOOLEAN *) &mRebased[CpuIndex];
+
+ //
+ // If BSP runs in 64-bit mode executing boot script while APs rendezvous
+ // in 32-bit mode. In this case semaphore code should be 32-bit code instead of x64 code.
+ //
+ // Note that this module is loaded below 4G, so truncation of 64-bit address to 32-bit for 32-bit semaphore
+ // code is safe.
+ //
+ CpuState = NULL;
+
+ {
+ CpuState = (SOCKET_LGA_775_SMM_CPU_STATE *)(UINTN)(SMM_DEFAULT_SMBASE + SMM_CPU_STATE_OFFSET);
+
+ //
+ // We are now in 64-bit mode, so SMM Save State Map must be x64 format.
+ //
+
+ mSmmRelocationOriginalAddress = CpuState->x64._RIP;
+ Efer = CpuState->x64.IA32_EFER;
+ AutoHaltRestart = CpuState->x86.AutoHALTRestart;
+ }
+
+ if ((Efer & LMA) == 0) {
+ //
+ // Use temp value to fix ICC complier warning
+ //
+ TempValue = (UINTN)&mSmmRelocationOriginalAddress;
+ mSmmRelocationOriginalAddressPtr32 = (UINT32)TempValue;
+ mRebasedFlagAddr32 = (UINT32)(UINTN)mRebasedFlag;
+
+ FunctionPointer = (UINTN)&SmmRelocationSemaphoreComplete32;
+ } else {
+ FunctionPointer = (UINTN)&SmmRelocationSemaphoreComplete;
+ }
+
+ {
+ CpuState->x64._RIP = FunctionPointer;
+ }
+
+ if ((AutoHaltRestart & BIT0) != 0) {
+ //
+ // Clear the auto HALT restart flag so the RSM instruction returns
+ // program control to the instruction following the HLT instruction,
+ // actually returns to SmmRelocationSemaphoreComplete
+ //
+ {
+ CpuState->x86.AutoHALTRestart &= ~BIT0;
+ }
+ }
+}
+
diff --git a/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/PiSmmCpuDxeSmm/X64/SmiEntry.S b/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/PiSmmCpuDxeSmm/X64/SmiEntry.S
new file mode 100644
index 0000000000..9648594e78
--- /dev/null
+++ b/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/PiSmmCpuDxeSmm/X64/SmiEntry.S
@@ -0,0 +1,236 @@
+## @file
+# Code template of the SMI handler for a particular processor
+#
+# Copyright (c) 2009 - 2015, 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
+#
+##
+
+
+ASM_GLOBAL ASM_PFX(gcSmiHandlerTemplate)
+ASM_GLOBAL ASM_PFX(gcSmiHandlerSize)
+ASM_GLOBAL ASM_PFX(gSmiCr3)
+ASM_GLOBAL ASM_PFX(gcSmiHandlerOffset)
+ASM_GLOBAL ASM_PFX(gSmiStack)
+ASM_GLOBAL ASM_PFX(gSmbase)
+ASM_GLOBAL ASM_PFX(FeaturePcdGet (PcdCpuSmmDebug))
+
+#
+# Constants relating to PROCESSOR_SMM_DESCRIPTOR
+#
+.equ DSC_OFFSET, 0xfb00
+.equ DSC_GDTPTR, 0x30
+.equ DSC_GDTSIZ, 0x38
+.equ DSC_CS, 14
+.equ DSC_DS, 16
+.equ DSC_SS, 18
+.equ DSC_OTHERSEG, 20
+.equ MSR_DR6, 0x0c05
+.equ MSR_DR7, 0x0c06
+
+.equ PROTECT_MODE_CS, 0x10
+.equ PROTECT_MODE_DS, 0x18
+.equ TSS_SEGMENT, 0x40
+.equ GDT_SIZE, 0x50
+
+#
+# Constants relating to CPU State Save Area
+#
+.equ SSM_DR6, 0xffd0
+.equ SSM_DR7, 0xffc8
+
+
+ .data
+
+ ASM_PFX(gcSmiHandlerOffset): .word _SmiHandler - _SmiEntryPoint + 0x8000
+
+ .text
+
+ASM_PFX(gcSmiHandlerTemplate):
+
+_SmiEntryPoint:
+ #
+ # The encoding of BX in 16-bit addressing mode is the same as of RDI in 64-
+ # bit addressing mode. And that coincidence has been used in the following
+ # "64-bit like" 16-bit code. Be aware that once RDI is referrenced as a
+ # base address register, it is actually BX that is referrenced.
+ #
+ .byte 0xbb # mov bx, imm16
+ .word _GdtDesc - _SmiEntryPoint + 0x8000
+ #
+ # fix GDT TSS table
+ #
+ .byte 0x66, 0x2e, 0xa1 # mov eax, cs:[offset16] ; eax = GDT base
+ .word DSC_OFFSET + DSC_GDTPTR
+ movw %ax, %dx
+ movw %ax, %bp # ebp = GDT base
+ addw $GDT_SIZE, %dx # edx = TSS descriptor base
+ movl %edx, (TSS_SEGMENT+2)(%eax)
+ shr $16, %dx
+ movb %dl, (TSS_SEGMENT + 4)(%eax)
+ movb %dh, (TSS_SEGMENT + 7)(%eax)
+ #
+ # fix GDT descriptor
+ #
+ .byte 0x2e,0xa1 # mov ax, cs:[offset16]
+ .word DSC_OFFSET + DSC_GDTSIZ
+ .byte 0x48 # dec ax
+ .byte 0x2e
+ movl %eax, (%rdi) # mov cs:[bx], ax
+ .byte 0x66,0x2e,0xa1 # mov eax, cs:[offset16]
+ .word DSC_OFFSET + DSC_GDTPTR
+ .byte 0x2e
+ movw %ax, 2(%rdi)
+ .byte 0x66,0x2e
+ lgdt (%rdi)
+ .byte 0x66,0xb8 # mov eax, imm32
+ASM_PFX(gSmiCr3): .space 4
+ movq %rax, %cr3
+ .byte 0x66
+ movl $0x668,%eax # as cr4.PGE is not set here, refresh cr3
+ movq %rax, %cr4 # in PreModifyMtrrs() to flush TLB.
+ #
+ # Patch LongMode Segment
+ #
+ .byte 0x2e,0xa1 # mov ax, cs:[offset16]
+ .word DSC_OFFSET + DSC_CS
+ .byte 0x2e
+ movl %eax, (LongMode - ProtectedMode + 4)(%rdi)
+ #
+ # Patch ProtectedMode Segment
+ #
+ .byte 0xb8
+ .word PROTECT_MODE_CS
+ .byte 0x2e
+ movl %eax, -2(%rdi)
+ #
+ # Patch LongMode entry
+ #
+ .byte 0x66, 0xbf # mov edi, SMBASE
+ASM_PFX(gSmbase): .space 4
+ lea ((LongMode - _SmiEntryPoint) + 0x8000)(%edi), %ax
+ .byte 0x2e
+ movw %ax, (LongMode - ProtectedMode)(%rdi)
+ #
+ # Patch ProtectedMode entry
+ #
+ lea ((ProtectedMode - _SmiEntryPoint) + 0x8000)(%edi), %ax
+ .byte 0x2e
+ movw %ax, -6(%rdi)
+ #
+ # Switch into ProtectedMode
+ #
+ .byte 0x66
+ movl $0xc0000080,%ecx
+
+ movq %cr0, %rbx
+ .byte 0x66
+ andl $0x9ffafff3, %ebx
+ .byte 0x66
+ orl $0x00000023, %ebx
+
+ movq %rbx, %cr0
+ .byte 0x66, 0xea
+ .space 6
+
+_GdtDesc: .space 6
+
+ProtectedMode:
+ movw $PROTECT_MODE_DS, %ax
+ movl %eax, %ds
+ movl %eax, %es
+ movl %eax, %ss
+
+ #
+ # Load TSS
+ #
+ movl %ebp, %eax # ebp = GDT base
+ movl %eax, %edx
+ movb $0x89, %dl
+ movb %dl, (TSS_SEGMENT + 5)(%rax) # clear busy flag
+ movl $TSS_SEGMENT, %eax
+ ltr %ax
+
+ #
+ # Switch to LongMode
+ #
+ rdmsr
+ orb $1,%ah
+ wrmsr
+ btsl $31, %ebx
+ movq %rbx, %cr0
+ .byte 0x67, 0xea
+ .space 6
+
+LongMode: # long mode (64-bit code) starts here
+ lea (DSC_OFFSET)(%rdi), %ebx
+ movw DSC_DS(%rbx), %ax
+ movl %eax,%ds
+ movw DSC_OTHERSEG(%rbx), %ax
+ movl %eax,%es
+ movl %eax,%fs
+ movl %eax,%gs
+ movw DSC_SS(%rbx), %ax
+ movl %eax,%ss
+# jmp _SmiHandler ; instruction is not needed
+
+_SmiHandler:
+ .byte 0x48,0xbc # mov rsp, imm64
+ASM_PFX(gSmiStack): .space 8
+ movabsq $ASM_PFX(FeaturePcdGet (PcdCpuSmmDebug)), %rax
+ cmpb $0, (%rax)
+ jz L1
+
+ jz L3
+
+L3:
+ .byte 0x48, 0x8b, 0x0d # mov rcx, [rip + disp32]
+ .long SSM_DR6 - (. + 4 - _SmiEntryPoint + 0x8000)
+ .byte 0x48, 0x8b, 0x15 # mov rdx, [rip + disp32]
+ .long SSM_DR7 - (. + 4 - _SmiEntryPoint + 0x8000)
+L4:
+ movq %rcx, %dr6
+ movq %rdx, %dr7
+L1:
+
+ movabsq $ASM_PFX(SmiRendezvous), %rax
+ movq (%rsp), %rcx
+ # Save FP registers
+
+ subq $0x208, %rsp
+ .byte 0x48 # FXSAVE64
+ fxsave (%rsp)
+
+ addq $-0x20, %rsp
+ call *%rax
+ addq $0x20, %rsp
+
+ #
+ # Restore FP registers
+ #
+ .byte 0x48 # FXRSTOR64
+ fxrstor (%rsp)
+
+ movabsq $ASM_PFX(FeaturePcdGet (PcdCpuSmmDebug)), %rax
+ cmpb $0, (%rax)
+ jz L2
+
+ movq %dr7, %rdx
+ movq %dr6, %rcx
+ .byte 0x48, 0x89, 0x15 # mov [rip + disp32], rdx
+ .long SSM_DR7 - (. + 4 - _SmiEntryPoint + 0x8000)
+ .byte 0x48, 0x89, 0x0d # mov [rip + disp32], rcx
+ .long SSM_DR6 - (. + 4 - _SmiEntryPoint + 0x8000)
+L2:
+
+ rsm
+
+ASM_PFX(gcSmiHandlerSize): .word . - _SmiEntryPoint
+
diff --git a/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/PiSmmCpuDxeSmm/X64/SmiEntry.asm b/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/PiSmmCpuDxeSmm/X64/SmiEntry.asm
new file mode 100644
index 0000000000..7e174b2373
--- /dev/null
+++ b/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/PiSmmCpuDxeSmm/X64/SmiEntry.asm
@@ -0,0 +1,232 @@
+;; @file
+; Code template of the SMI handler for a particular processor
+;
+; Copyright (c) 2009 - 2015, 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.
+;
+;;
+
+;
+; Constants relating to PROCESSOR_SMM_DESCRIPTOR
+;
+DSC_OFFSET EQU 0fb00h
+DSC_GDTPTR EQU 30h
+DSC_GDTSIZ EQU 38h
+DSC_CS EQU 14
+DSC_DS EQU 16
+DSC_SS EQU 18
+DSC_OTHERSEG EQU 20
+MSR_DR6 EQU 0c05h
+MSR_DR7 EQU 0c06h
+;
+; Constants relating to CPU State Save Area
+;
+SSM_DR6 EQU 0ffd0h
+SSM_DR7 EQU 0ffc8h
+
+;
+; Variables referrenced by C code
+;
+EXTERNDEF SmiRendezvous:PROC
+EXTERNDEF gcSmiHandlerTemplate:BYTE
+EXTERNDEF gcSmiHandlerSize:WORD
+EXTERNDEF gSmiCr3:DWORD
+EXTERNDEF gcSmiHandlerOffset:WORD
+EXTERNDEF gSmiStack:QWORD
+EXTERNDEF gSmbase:DWORD
+EXTERNDEF FeaturePcdGet (PcdCpuSmmDebug):BYTE
+
+PROTECT_MODE_CS EQU 10h
+PROTECT_MODE_DS EQU 18h
+TSS_SEGMENT EQU 40h
+GDT_SIZE EQU 50h
+
+ .const
+
+gcSmiHandlerOffset DW _SmiHandler - _SmiEntryPoint + 8000h
+
+ .code
+
+gcSmiHandlerTemplate LABEL BYTE
+
+_SmiEntryPoint PROC
+ ;
+ ; The encoding of BX in 16-bit addressing mode is the same as of RDI in 64-
+ ; bit addressing mode. And that coincidence has been used in the following
+ ; "64-bit like" 16-bit code. Be aware that once RDI is referrenced as a
+ ; base address register, it is actually BX that is referrenced.
+ ;
+ DB 0bbh ; mov bx, imm16
+ DW offset _GdtDesc - _SmiEntryPoint + 8000h ; bx = GdtDesc offset
+
+; fix GDT TSS table
+ DB 66h, 2eh, 0a1h ; mov eax, cs:[offset16] ; eax = GDT base
+ DW DSC_OFFSET + DSC_GDTPTR
+ mov dx, ax
+ mov bp, ax ; ebp = GDT base
+ add dx, GDT_SIZE ; edx = TSS descriptor base
+ mov [eax + TSS_SEGMENT + 2],edx
+ shr dx, 16
+ mov [eax + TSS_SEGMENT + 4], dl
+ mov [eax + TSS_SEGMENT + 7], dh
+; fix GDT descriptor
+ DB 2eh, 0a1h ; mov ax, cs:[offset16]
+ DW DSC_OFFSET + DSC_GDTSIZ
+ DB 48h ; dec ax
+ DB 2eh
+ mov [rdi], eax ; mov cs:[bx], ax
+ DB 66h, 2eh, 0a1h ; mov eax, cs:[offset16]
+ DW DSC_OFFSET + DSC_GDTPTR
+ DB 2eh
+ mov [rdi + 2], ax ; mov cs:[bx + 2], eax
+ DB 66h, 2eh
+ lgdt fword ptr [rdi] ; lgdt fword ptr cs:[bx]
+ DB 66h, 0b8h ; mov eax, imm32
+gSmiCr3 DD ?
+ mov cr3, rax
+ DB 66h
+ mov eax, 668h ; as cr4.PGE is not set here, refresh cr3
+ mov cr4, rax ; in PreModifyMtrrs() to flush TLB.
+; Patch LongMode Segment
+ DB 2eh, 0a1h ; mov ax, cs:[offset16]
+ DW DSC_OFFSET + DSC_CS
+ DB 2eh
+ mov [rdi + (sizeof (FWORD) + (@LongMode - @ProtectedMode)) - 2], eax ; mov cs:[bx - 2], ax
+; Patch ProtectedMode Segment
+ DB 0b8h ; mov ax, imm16
+ DW PROTECT_MODE_CS ; set AX for segment directly
+ DB 2eh
+ mov [rdi - 2], eax ; mov cs:[bx - 2], ax
+; Patch LongMode entry
+ DB 66h, 0bfh ; mov edi, SMBASE
+gSmbase DD ?
+ lea ax, [edi + (@LongMode - _SmiEntryPoint) + 8000h]
+ DB 2eh
+ mov [rdi + (sizeof (FWORD) + (@LongMode - @ProtectedMode)) - 6], ax ; mov cs:[bx - 6], eax
+; Patch ProtectedMode entry
+ lea ax, [edi + (@ProtectedMode - _SmiEntryPoint) + 8000h]
+ DB 2eh
+ mov [rdi - 6], ax ; mov cs:[bx - 6], eax
+; Switch into @ProtectedMode
+ DB 66h
+ mov ecx, 0c0000080h
+ mov rbx, cr0
+ DB 66h
+ and ebx, 9ffafff3h
+ DB 66h
+ or ebx, 00000023h
+
+ mov cr0, rbx
+ DB 66h, 0eah
+ DD ?
+ DW ?
+
+_GdtDesc FWORD ?
+@ProtectedMode:
+ mov ax, PROTECT_MODE_DS
+ mov ds, eax
+ mov es, eax
+ mov ss, eax
+
+; Load TSS
+ mov eax, ebp ; ebp = GDT base
+ mov edx, eax
+ mov dl, 89h
+ mov [rax + TSS_SEGMENT + 5], dl ; clear busy flag
+
+ mov eax, TSS_SEGMENT
+ ltr ax
+
+; Switch into @LongMode
+ rdmsr
+ or ah, 1
+ wrmsr
+ bts ebx, 31
+ mov cr0, rbx
+ DB 67h, 0eah
+ DD ?
+ DW ?
+
+@LongMode: ; long mode (64-bit code) starts here
+ lea ebx, [rdi + DSC_OFFSET]
+ mov ax, [rbx + DSC_DS]
+ mov ds, eax
+ mov ax, [rbx + DSC_OTHERSEG]
+ mov es, eax
+ mov fs, eax
+ mov gs, eax
+ mov ax, [rbx + DSC_SS]
+ mov ss, eax
+; jmp _SmiHandler ; instruction is not needed
+_SmiEntryPoint ENDP
+
+_SmiHandler PROC
+ DB 48h, 0bch ; mov rsp, imm64
+gSmiStack DQ ?
+;
+; The following lines restore DR6 & DR7 before running C code. They are useful
+; when you want to enable hardware breakpoints in SMM without setting
+; smmentrybreak=true in ITP.
+;
+; NOTE: These lines might not be appreciated in runtime since they might
+; conflict with OS debugging facilities. Turn them off in RELEASE.
+;
+ mov rax, offset FeaturePcdGet (PcdCpuSmmDebug) ;Get absolute address. Avoid RIP relative addressing
+ cmp byte ptr [rax], 0
+ jz @1
+
+ jz @F
+
+@@:
+ DB 48h, 8bh, 0dh ; mov rcx, [rip + disp32]
+ DD SSM_DR6 - ($ + 4 - _SmiEntryPoint + 8000h)
+ DB 48h, 8bh, 15h ; mov rdx, [rip + disp32]
+ DD SSM_DR7 - ($ + 4 - _SmiEntryPoint + 8000h)
+@3:
+ mov dr6, rcx
+ mov dr7, rdx
+@1:
+ mov rcx, [rsp] ; rcx <- CpuIndex
+ mov rax, SmiRendezvous ; rax <- absolute addr of SmiRedezvous
+
+ ;
+ ; Save FP registers
+ ;
+ sub rsp, 208h
+ DB 48h ; FXSAVE64
+ fxsave [rsp]
+
+ add rsp, -20h
+ call rax
+ add rsp, 20h
+
+ ;
+ ; Restore FP registers
+ ;
+ DB 48h ; FXRSTOR64
+ fxrstor [rsp]
+
+ mov rax, offset FeaturePcdGet (PcdCpuSmmDebug) ;Get absolute address. Avoid RIP relative addressing
+ cmp byte ptr [rax], 0
+ jz @2
+
+ mov rdx, dr7
+ mov rcx, dr6
+ DB 48h, 89h, 15h ; mov [rip + disp32], rdx
+ DD SSM_DR7 - ($ + 4 - _SmiEntryPoint + 8000h)
+ DB 48h, 89h, 0dh ; mov [rip + disp32], rcx
+ DD SSM_DR6 - ($ + 4 - _SmiEntryPoint + 8000h)
+@2:
+ rsm
+_SmiHandler ENDP
+
+gcSmiHandlerSize DW $ - _SmiEntryPoint
+
+ END
diff --git a/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/PiSmmCpuDxeSmm/X64/SmiException.S b/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/PiSmmCpuDxeSmm/X64/SmiException.S
new file mode 100644
index 0000000000..e786a4395d
--- /dev/null
+++ b/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/PiSmmCpuDxeSmm/X64/SmiException.S
@@ -0,0 +1,822 @@
+## @file
+# Exception handlers used in SM mode
+#
+# Copyright (c) 2009 - 2015, 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
+#
+##
+
+
+ASM_GLOBAL ASM_PFX(gSmiMtrrs)
+ASM_GLOBAL ASM_PFX(gcSmiIdtr)
+ASM_GLOBAL ASM_PFX(gcSmiGdtr)
+ASM_GLOBAL ASM_PFX(gcPsd)
+ASM_GLOBAL ASM_PFX(FeaturePcdGet (PcdCpuSmmStackGuard))
+ASM_GLOBAL ASM_PFX(gSavedPageFaultIdtEntry)
+ASM_GLOBAL ASM_PFX(gSavedDebugExceptionIdtEntry)
+ASM_GLOBAL ASM_PFX(FeaturePcdGet (PcdCpuSmmProfileEnable))
+ASM_GLOBAL ASM_PFX(InitializeSmmExternalVectorTablePtr)
+
+ .data
+
+NullSeg: .quad 0
+ .quad 0 # reserved for future use
+CodeSeg32:
+ .word -1 # LimitLow
+ .word 0 # BaseLow
+ .byte 0 # BaseMid
+ .byte 0x9b
+ .byte 0xcf # LimitHigh
+ .byte 0 # BaseHigh
+DataSeg32:
+ .word -1 # LimitLow
+ .word 0 # BaseLow
+ .byte 0 # BaseMid
+ .byte 0x93
+ .byte 0xcf # LimitHigh
+ .byte 0 # BaseHigh
+ .quad 0 # reserved for future use
+CodeSeg16:
+ .word -1
+ .word 0
+ .byte 0
+ .byte 0x9b
+ .byte 0x8f
+ .byte 0
+DataSeg16:
+ .word -1
+ .word 0
+ .byte 0
+ .byte 0x93
+ .byte 0x8f
+ .byte 0
+CodeSeg64:
+ .word -1 # LimitLow
+ .word 0 # BaseLow
+ .byte 0 # BaseMid
+ .byte 0x9b
+ .byte 0xaf # LimitHigh
+ .byte 0 # BaseHigh
+# TSS Segment for X64 specially
+TssSeg:
+ .word TSS_DESC_SIZE # LimitLow
+ .word 0 # BaseLow
+ .byte 0 # BaseMid
+ .byte 0x89
+ .byte 0xDB # LimitHigh
+ .byte 0 # BaseHigh
+ .long 0 # BaseUpper
+ .long 0 # Reserved
+.equ GDT_SIZE, .- NullSeg
+
+TssDescriptor:
+ .space 104, 0
+.equ TSS_DESC_SIZE, .- TssDescriptor
+
+#
+# This structure serves as a template for all processors.
+#
+ASM_PFX(gcPsd):
+ .ascii "PSDSIG "
+ .word PSD_SIZE
+ .word 2
+ .word 1 << 2
+ .word CODE_SEL
+ .word DATA_SEL
+ .word DATA_SEL
+ .word DATA_SEL
+ .word 0
+ .quad 0
+ .quad 0
+ .quad 0 # fixed in InitializeMpServiceData()
+ .quad NullSeg
+ .long GDT_SIZE
+ .long 0
+ .space 24, 0
+ .quad ASM_PFX(gSmiMtrrs)
+.equ PSD_SIZE, . - ASM_PFX(gcPsd)
+
+#
+# CODE & DATA segments for SMM runtime
+#
+.equ CODE_SEL, CodeSeg64 - NullSeg
+.equ DATA_SEL, DataSeg32 - NullSeg
+
+ASM_PFX(gcSmiGdtr):
+ .word GDT_SIZE - 1
+ .quad NullSeg
+
+ASM_PFX(gcSmiIdtr):
+ .word IDT_SIZE - 1
+ .quad _SmiIDT
+
+
+#
+# Here is the IDT. There are 32 (not 255) entries in it since only processor
+# generated exceptions will be handled.
+#
+_SmiIDT:
+# The following segment repeats 32 times:
+# No. 1
+ .word 0 # Offset 0:15
+ .word CODE_SEL
+ .byte 0 # Unused
+ .byte 0x8e # Interrupt Gate, Present
+ .word 0 # Offset 16:31
+ .quad 0 # Offset 32:63
+# No. 2
+ .word 0 # Offset 0:15
+ .word CODE_SEL
+ .byte 0 # Unused
+ .byte 0x8e # Interrupt Gate, Present
+ .word 0 # Offset 16:31
+ .quad 0 # Offset 32:63
+# No. 3
+ .word 0 # Offset 0:15
+ .word CODE_SEL
+ .byte 0 # Unused
+ .byte 0x8e # Interrupt Gate, Present
+ .word 0 # Offset 16:31
+ .quad 0 # Offset 32:63
+# No. 4
+ .word 0 # Offset 0:15
+ .word CODE_SEL
+ .byte 0 # Unused
+ .byte 0x8e # Interrupt Gate, Present
+ .word 0 # Offset 16:31
+ .quad 0 # Offset 32:63
+# No. 5
+ .word 0 # Offset 0:15
+ .word CODE_SEL
+ .byte 0 # Unused
+ .byte 0x8e # Interrupt Gate, Present
+ .word 0 # Offset 16:31
+ .quad 0 # Offset 32:63
+# No. 6
+ .word 0 # Offset 0:15
+ .word CODE_SEL
+ .byte 0 # Unused
+ .byte 0x8e # Interrupt Gate, Present
+ .word 0 # Offset 16:31
+ .quad 0 # Offset 32:63
+# No. 7
+ .word 0 # Offset 0:15
+ .word CODE_SEL
+ .byte 0 # Unused
+ .byte 0x8e # Interrupt Gate, Present
+ .word 0 # Offset 16:31
+ .quad 0 # Offset 32:63
+# No. 8
+ .word 0 # Offset 0:15
+ .word CODE_SEL
+ .byte 0 # Unused
+ .byte 0x8e # Interrupt Gate, Present
+ .word 0 # Offset 16:31
+ .quad 0 # Offset 32:63
+# No. 9
+ .word 0 # Offset 0:15
+ .word CODE_SEL
+ .byte 0 # Unused
+ .byte 0x8e # Interrupt Gate, Present
+ .word 0 # Offset 16:31
+ .quad 0 # Offset 32:63
+# No. 10
+ .word 0 # Offset 0:15
+ .word CODE_SEL
+ .byte 0 # Unused
+ .byte 0x8e # Interrupt Gate, Present
+ .word 0 # Offset 16:31
+ .quad 0 # Offset 32:63
+# No. 11
+ .word 0 # Offset 0:15
+ .word CODE_SEL
+ .byte 0 # Unused
+ .byte 0x8e # Interrupt Gate, Present
+ .word 0 # Offset 16:31
+ .quad 0 # Offset 32:63
+# No. 12
+ .word 0 # Offset 0:15
+ .word CODE_SEL
+ .byte 0 # Unused
+ .byte 0x8e # Interrupt Gate, Present
+ .word 0 # Offset 16:31
+ .quad 0 # Offset 32:63
+# No. 13
+ .word 0 # Offset 0:15
+ .word CODE_SEL
+ .byte 0 # Unused
+ .byte 0x8e # Interrupt Gate, Present
+ .word 0 # Offset 16:31
+ .quad 0 # Offset 32:63
+# No. 14
+ .word 0 # Offset 0:15
+ .word CODE_SEL
+ .byte 0 # Unused
+ .byte 0x8e # Interrupt Gate, Present
+ .word 0 # Offset 16:31
+ .quad 0 # Offset 32:63
+# No. 15
+ .word 0 # Offset 0:15
+ .word CODE_SEL
+ .byte 0 # Unused
+ .byte 0x8e # Interrupt Gate, Present
+ .word 0 # Offset 16:31
+ .quad 0 # Offset 32:63
+# No. 16
+ .word 0 # Offset 0:15
+ .word CODE_SEL
+ .byte 0 # Unused
+ .byte 0x8e # Interrupt Gate, Present
+ .word 0 # Offset 16:31
+ .quad 0 # Offset 32:63
+# No. 17
+ .word 0 # Offset 0:15
+ .word CODE_SEL
+ .byte 0 # Unused
+ .byte 0x8e # Interrupt Gate, Present
+ .word 0 # Offset 16:31
+ .quad 0 # Offset 32:63
+# No. 18
+ .word 0 # Offset 0:15
+ .word CODE_SEL
+ .byte 0 # Unused
+ .byte 0x8e # Interrupt Gate, Present
+ .word 0 # Offset 16:31
+ .quad 0 # Offset 32:63
+# No. 19
+ .word 0 # Offset 0:15
+ .word CODE_SEL
+ .byte 0 # Unused
+ .byte 0x8e # Interrupt Gate, Present
+ .word 0 # Offset 16:31
+ .quad 0 # Offset 32:63
+# No. 20
+ .word 0 # Offset 0:15
+ .word CODE_SEL
+ .byte 0 # Unused
+ .byte 0x8e # Interrupt Gate, Present
+ .word 0 # Offset 16:31
+ .quad 0 # Offset 32:63
+# No. 21
+ .word 0 # Offset 0:15
+ .word CODE_SEL
+ .byte 0 # Unused
+ .byte 0x8e # Interrupt Gate, Present
+ .word 0 # Offset 16:31
+ .quad 0 # Offset 32:63
+# No. 22
+ .word 0 # Offset 0:15
+ .word CODE_SEL
+ .byte 0 # Unused
+ .byte 0x8e # Interrupt Gate, Present
+ .word 0 # Offset 16:31
+ .quad 0 # Offset 32:63
+# No. 23
+ .word 0 # Offset 0:15
+ .word CODE_SEL
+ .byte 0 # Unused
+ .byte 0x8e # Interrupt Gate, Present
+ .word 0 # Offset 16:31
+ .quad 0 # Offset 32:63
+# No. 24
+ .word 0 # Offset 0:15
+ .word CODE_SEL
+ .byte 0 # Unused
+ .byte 0x8e # Interrupt Gate, Present
+ .word 0 # Offset 16:31
+ .quad 0 # Offset 32:63
+# No. 25
+ .word 0 # Offset 0:15
+ .word CODE_SEL
+ .byte 0 # Unused
+ .byte 0x8e # Interrupt Gate, Present
+ .word 0 # Offset 16:31
+ .quad 0 # Offset 32:63
+# No. 26
+ .word 0 # Offset 0:15
+ .word CODE_SEL
+ .byte 0 # Unused
+ .byte 0x8e # Interrupt Gate, Present
+ .word 0 # Offset 16:31
+ .quad 0 # Offset 32:63
+# No. 27
+ .word 0 # Offset 0:15
+ .word CODE_SEL
+ .byte 0 # Unused
+ .byte 0x8e # Interrupt Gate, Present
+ .word 0 # Offset 16:31
+ .quad 0 # Offset 32:63
+# No. 28
+ .word 0 # Offset 0:15
+ .word CODE_SEL
+ .byte 0 # Unused
+ .byte 0x8e # Interrupt Gate, Present
+ .word 0 # Offset 16:31
+ .quad 0 # Offset 32:63
+# No. 29
+ .word 0 # Offset 0:15
+ .word CODE_SEL
+ .byte 0 # Unused
+ .byte 0x8e # Interrupt Gate, Present
+ .word 0 # Offset 16:31
+ .quad 0 # Offset 32:63
+# No. 30
+ .word 0 # Offset 0:15
+ .word CODE_SEL
+ .byte 0 # Unused
+ .byte 0x8e # Interrupt Gate, Present
+ .word 0 # Offset 16:31
+ .quad 0 # Offset 32:63
+# No. 31
+ .word 0 # Offset 0:15
+ .word CODE_SEL
+ .byte 0 # Unused
+ .byte 0x8e # Interrupt Gate, Present
+ .word 0 # Offset 16:31
+ .quad 0 # Offset 32:63
+# No. 32
+ .word 0 # Offset 0:15
+ .word CODE_SEL
+ .byte 0 # Unused
+ .byte 0x8e # Interrupt Gate, Present
+ .word 0 # Offset 16:31
+ .quad 0 # Offset 32:63
+
+_SmiIDTEnd:
+
+.equ IDT_SIZE, (_SmiIDTEnd - _SmiIDT)
+
+#
+# Saved IDT Entry for Page Fault
+#
+ASM_PFX(gSavedPageFaultIdtEntry):
+ .quad 0
+ .quad 0
+
+#
+# Saved IDT Entry for INT 1
+#
+ASM_PFX(gSavedDebugExceptionIdtEntry):
+ .quad 0
+ .quad 0
+
+ExternalVectorTablePtr: .quad 0 # point to the external interrupt vector table
+
+#
+# Here are the global variables used by #PF exception handler.
+#
+_PFPML4: .long 0
+_PFPDP: .long 0
+_PFLOCK: .byte 0
+
+ .text
+
+ASM_PFX(InitializeSmmExternalVectorTablePtr):
+ movq %rcx, ExternalVectorTablePtr(%rip)
+ ret
+
+#------------------------------------------------------------------------------
+# _SmiExceptionEntryPoints is the collection of exception entrypoints followed
+# by a common exception handler.
+#
+# Stack frame would be as follows as specified in IA32 manuals:
+# +---------------------+ <-- 16-byte aligned ensured by processor
+# + Old SS +
+# +---------------------+
+# + Old RSP +
+# +---------------------+
+# + RFlags +
+# +---------------------+
+# + CS +
+# +---------------------+
+# + RIP +
+# +---------------------+
+# + Error Code +
+# +---------------------+
+# + Vector Number +
+# +---------------------+
+# + RBP +
+# +---------------------+ <-- RBP, 16-byte aligned
+#
+# RSP set to odd multiple of 8 at @CommonEntryPoint means ErrCode PRESENT
+#------------------------------------------------------------------------------
+_SmiExceptionEntryPoints:
+.equ IHDLRIDX, 0
+# The following segment repeats 31 times:
+# No. 1
+ pushq $IHDLRIDX
+ jmp CommonEntryPoint
+.equ IHDLRIDX, IHDLRIDX + 1
+# No. 2
+ pushq $IHDLRIDX
+ jmp CommonEntryPoint
+.equ IHDLRIDX, IHDLRIDX + 1
+# No. 3
+ pushq $IHDLRIDX
+ jmp CommonEntryPoint
+.equ IHDLRIDX, IHDLRIDX + 1
+# No. 4
+ pushq $IHDLRIDX
+ jmp CommonEntryPoint
+.equ IHDLRIDX, IHDLRIDX + 1
+# No. 5
+ pushq $IHDLRIDX
+ jmp CommonEntryPoint
+.equ IHDLRIDX, IHDLRIDX + 1
+# No. 6
+ pushq $IHDLRIDX
+ jmp CommonEntryPoint
+.equ IHDLRIDX, IHDLRIDX + 1
+# No. 7
+ pushq $IHDLRIDX
+ jmp CommonEntryPoint
+.equ IHDLRIDX, IHDLRIDX + 1
+# No. 8
+ pushq $IHDLRIDX
+ jmp CommonEntryPoint
+.equ IHDLRIDX, IHDLRIDX + 1
+# No. 9
+ pushq $IHDLRIDX
+ jmp CommonEntryPoint
+.equ IHDLRIDX, IHDLRIDX + 1
+# No. 10
+ pushq $IHDLRIDX
+ jmp CommonEntryPoint
+.equ IHDLRIDX, IHDLRIDX + 1
+# No. 11
+ pushq $IHDLRIDX
+ jmp CommonEntryPoint
+.equ IHDLRIDX, IHDLRIDX + 1
+# No. 12
+ pushq $IHDLRIDX
+ jmp CommonEntryPoint
+.equ IHDLRIDX, IHDLRIDX + 1
+# No. 13
+ pushq $IHDLRIDX
+ jmp CommonEntryPoint
+.equ IHDLRIDX, IHDLRIDX + 1
+# No. 14
+ pushq $IHDLRIDX
+ jmp CommonEntryPoint
+.equ IHDLRIDX, IHDLRIDX + 1
+# No. 15
+ pushq $IHDLRIDX
+ jmp CommonEntryPoint
+.equ IHDLRIDX, IHDLRIDX + 1
+# No. 16
+ pushq $IHDLRIDX
+ jmp CommonEntryPoint
+.equ IHDLRIDX, IHDLRIDX + 1
+# No. 17
+ pushq $IHDLRIDX
+ jmp CommonEntryPoint
+.equ IHDLRIDX, IHDLRIDX + 1
+# No. 18
+ pushq $IHDLRIDX
+ jmp CommonEntryPoint
+.equ IHDLRIDX, IHDLRIDX + 1
+# No. 19
+ pushq $IHDLRIDX
+ jmp CommonEntryPoint
+.equ IHDLRIDX, IHDLRIDX + 1
+# No. 20
+ pushq $IHDLRIDX
+ jmp CommonEntryPoint
+.equ IHDLRIDX, IHDLRIDX + 1
+# No. 21
+ pushq $IHDLRIDX
+ jmp CommonEntryPoint
+.equ IHDLRIDX, IHDLRIDX + 1
+# No. 22
+ pushq $IHDLRIDX
+ jmp CommonEntryPoint
+.equ IHDLRIDX, IHDLRIDX + 1
+# No. 23
+ pushq $IHDLRIDX
+ jmp CommonEntryPoint
+.equ IHDLRIDX, IHDLRIDX + 1
+# No. 24
+ pushq $IHDLRIDX
+ jmp CommonEntryPoint
+.equ IHDLRIDX, IHDLRIDX + 1
+# No. 25
+ pushq $IHDLRIDX
+ jmp CommonEntryPoint
+.equ IHDLRIDX, IHDLRIDX + 1
+# No. 26
+ pushq $IHDLRIDX
+ jmp CommonEntryPoint
+.equ IHDLRIDX, IHDLRIDX + 1
+# No. 27
+ pushq $IHDLRIDX
+ jmp CommonEntryPoint
+.equ IHDLRIDX, IHDLRIDX + 1
+# No. 28
+ pushq $IHDLRIDX
+ jmp CommonEntryPoint
+.equ IHDLRIDX, IHDLRIDX + 1
+# No. 29
+ pushq $IHDLRIDX
+ jmp CommonEntryPoint
+.equ IHDLRIDX, IHDLRIDX + 1
+# No. 30
+ pushq $IHDLRIDX
+ jmp CommonEntryPoint
+.equ IHDLRIDX, IHDLRIDX + 1
+# No. 31
+ pushq $IHDLRIDX
+ jmp CommonEntryPoint
+.equ IHDLRIDX, IHDLRIDX + 1
+
+
+ pushq $IHDLRIDX
+CommonEntryPoint:
+ .byte 0x40, 0xf6, 0xc4, 0x08 #test spl, 8
+ jnz L1
+ pushq (%rsp)
+ movq $0, 8(%rsp)
+L1:
+ pushq %rbp
+ movq %rsp, %rbp
+
+ #
+ # Since here the stack pointer is 16-byte aligned, so
+ # EFI_FX_SAVE_STATE_X64 of EFI_SYSTEM_CONTEXT_x64
+ # is 16-byte aligned
+ #
+
+## UINT64 Rdi, Rsi, Rbp, Rsp, Rbx, Rdx, Rcx, Rax;
+## UINT64 R8, R9, R10, R11, R12, R13, R14, R15;
+ pushq %r15
+ pushq %r14
+ pushq %r13
+ pushq %r12
+ pushq %r11
+ pushq %r10
+ pushq %r9
+ pushq %r8
+ pushq %rax
+ pushq %rcx
+ pushq %rdx
+ pushq %rbx
+ pushq 48(%rbp) # RSP
+ pushq (%rbp) # RBP
+ pushq %rsi
+ pushq %rdi
+
+## UINT64 Gs, Fs, Es, Ds, Cs, Ss; insure high 16 bits of each is zero
+ movzwq 56(%rbp), %rax
+ pushq %rax # for ss
+ movzwq 32(%rbp), %rax
+ pushq %rax # for cs
+ movq %ds, %rax
+ pushq %rax
+ movq %es, %rax
+ pushq %rax
+ movq %fs, %rax
+ pushq %rax
+ movq %gs, %rax
+ pushq %rax
+
+## UINT64 Rip;
+ pushq 24(%rbp)
+
+## UINT64 Gdtr[2], Idtr[2];
+ subq $16, %rsp
+ sidt (%rsp)
+ subq $16, %rsp
+ sgdt (%rsp)
+
+## UINT64 Ldtr, Tr;
+ xorq %rax, %rax
+ strw %ax
+ pushq %rax
+ sldtw %ax
+ pushq %rax
+
+## UINT64 RFlags;
+ pushq 40(%rbp)
+
+## UINT64 Cr0, Cr1, Cr2, Cr3, Cr4, Cr8;
+ movq %cr8, %rax
+ pushq %rax
+ movq %cr4, %rax
+ orq $0x208, %rax
+ movq %rax, %cr4
+ pushq %rax
+ movq %cr3, %rax
+ pushq %rax
+ movq %cr2, %rax
+ pushq %rax
+ xorq %rax, %rax
+ pushq %rax
+ movq %cr0, %rax
+ pushq %rax
+
+## UINT64 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7;
+ movq %dr7, %rax
+ pushq %rax
+ movq %dr6, %rax
+ pushq %rax
+ movq %dr3, %rax
+ pushq %rax
+ movq %dr2, %rax
+ pushq %rax
+ movq %dr1, %rax
+ pushq %rax
+ movq %dr0, %rax
+ pushq %rax
+
+## FX_SAVE_STATE_X64 FxSaveState;
+
+ subq $512, %rsp
+ movq %rsp, %rdi
+ .byte 0xf, 0xae, 0x7 # fxsave [rdi]
+
+# UEFI calling convention for x64 requires that Direction flag in EFLAGs is clear
+ cld
+
+## UINT32 ExceptionData;
+ pushq 16(%rbp)
+
+## call into exception handler
+ movq 8(%rbp), %rcx
+ movq ExternalVectorTablePtr, %rax # get the interrupt vectors base
+ movq (%rax, %rcx, 8), %rax
+ orq %rax, %rax # NULL?
+
+ je nonNullValue;
+
+## Prepare parameter and call
+ movq %rsp, %rdx
+ #
+ # Per X64 calling convention, allocate maximum parameter stack space
+ # and make sure RSP is 16-byte aligned
+ #
+ subq $4 * 8 + 8, %rsp
+ call *%rax
+ addq $4 * 8 + 8, %rsp
+ jmp L5
+
+nonNullValue:
+# CpuDeadLoop() is the default exception handler since it preserves the processor
+# branch log.
+ call ASM_PFX(CpuDeadLoop)
+
+L5:
+## UINT64 ExceptionData;
+ addq $8, %rsp
+
+## FX_SAVE_STATE_X64 FxSaveState;
+
+ movq %rsp, %rsi
+ .byte 0xf, 0xae, 0xe # fxrstor [rsi]
+ addq $512, %rsp
+
+## UINT64 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7;
+## Skip restoration of DRx registers to support in-circuit emualators
+## or debuggers set breakpoint in interrupt/exception context
+ addq $8 * 6, %rsp
+
+## UINT64 Cr0, Cr1, Cr2, Cr3, Cr4, Cr8;
+ popq %rax
+ movq %rax, %cr0
+ addq $8, %rsp # not for Cr1
+ popq %rax
+ movq %rax, %cr2
+ popq %rax
+ movq %rax, %cr3
+ popq %rax
+ movq %rax, %cr4
+ popq %rax
+ movq %rax, %cr8
+
+## UINT64 RFlags;
+ popq 40(%rbp)
+
+## UINT64 Ldtr, Tr;
+## UINT64 Gdtr[2], Idtr[2];
+## Best not let anyone mess with these particular registers...
+ addq $48, %rsp
+
+## UINT64 Rip;
+ popq 24(%rbp)
+
+## UINT64 Gs, Fs, Es, Ds, Cs, Ss;
+ popq %rax
+ # mov gs, rax ; not for gs
+ popq %rax
+ # mov fs, rax ; not for fs
+ # (X64 will not use fs and gs, so we do not restore it)
+ popq %rax
+ movq %rax, %es
+ popq %rax
+ movq %rax, %ds
+ popq 32(%rbp) # for cs
+ popq 56(%rbp) # for ss
+
+## UINT64 Rdi, Rsi, Rbp, Rsp, Rbx, Rdx, Rcx, Rax;
+## UINT64 R8, R9, R10, R11, R12, R13, R14, R15;
+ popq %rdi
+ popq %rsi
+ addq $8, %rsp # not for rbp
+ popq 48(%rbp) # for rsp
+ popq %rbx
+ popq %rdx
+ popq %rcx
+ popq %rax
+ popq %r8
+ popq %r9
+ popq %r10
+ popq %r11
+ popq %r12
+ popq %r13
+ popq %r14
+ popq %r15
+
+ movq %rbp, %rsp
+
+# Set single step DB# if SMM profile is enabled and page fault exception happens
+ movabsq $ASM_PFX(FeaturePcdGet (PcdCpuSmmProfileEnable)), %rbp
+ cmpb $0, (%rbp)
+ jz Done
+# Check if this is page fault exception
+ cmpq $0xe, 8(%rsp)
+ jnz L6
+# Enable TF bit after page fault handler runs
+ btsl $8, 40(%rsp) #RFLAGS
+ jmp Done
+L6:
+# Check if this is INT 1 exception
+ cmpq $1, 8(%rsp)
+ jnz Done
+# Clear TF bit after INT1 handler runs
+ btcl $8, 40(%rsp) #RFLAGS
+
+Done:
+
+ popq %rbp
+ addq $16, %rsp # skip INT# & ErrCode
+ iretq
+
+ASM_GLOBAL ASM_PFX(InitializeIDT)
+ASM_PFX(InitializeIDT):
+ movl $((_SmiIDTEnd - _SmiIDT) >> 2), %ecx
+ movabsq $_SmiIDT - 16, %rdx
+ movabsq $_SmiExceptionEntryPoints - 4, %r10
+L2:
+ lea (%r10, %rcx), %rax
+ movw %ax, (%rdx, %rcx, 4)
+ shr $16, %rax
+ movw %ax, 6(%rdx, %rcx, 4)
+ shr $16, %rax
+ movl %eax, 8(%rdx, %rcx, 4)
+ addl $-4, %ecx
+ jnz L2
+
+
+# Get absolute address.
+ movabsq $ASM_PFX(FeaturePcdGet (PcdCpuSmmStackGuard)), %rax
+ cmpb $0, (%rax)
+ jz L3
+
+#
+# If SMM Stack Guard feature is enabled, set the IST field of
+# the interrupe gate for Page Fault Exception to be 1
+#
+ movabsq $_SmiIDT + 14 * 16, %rax
+ movb $1, 4(%rax)
+L3:
+#
+# Save Page Fault IDT entry in gPageFaultIdtEntry
+#
+ movabsq $_SmiIDT + 14 * 16, %rcx
+ movabsq $ASM_PFX(gSavedPageFaultIdtEntry), %rdx
+ movq (%rcx), %rax
+ movq %rax, (%rdx)
+ movq 8(%rcx), %rax
+ movq %rax, 8(%rdx)
+
+ movabsq $ASM_PFX(FeaturePcdGet (PcdCpuSmmProfileEnable)), %rax
+ cmpb $0, (%rax)
+ jz L4
+
+#
+# Save INT 1 IDT entry in gSavedDebugExceptionIdtEntry
+#
+ movabsq $_SmiIDT + 1 * 16, %rcx
+ movabsq $ASM_PFX(gSavedDebugExceptionIdtEntry), %rdx
+ movq (%rcx), %rax
+ movq %rax, (%rdx)
+ movq 8(%rcx), %rax
+ movq %rax, 8(%rdx)
+
+L4:
+ ret
diff --git a/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/PiSmmCpuDxeSmm/X64/SmiException.asm b/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/PiSmmCpuDxeSmm/X64/SmiException.asm
new file mode 100644
index 0000000000..551f179848
--- /dev/null
+++ b/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/PiSmmCpuDxeSmm/X64/SmiException.asm
@@ -0,0 +1,504 @@
+;; @file
+; Exception handlers used in SM mode
+;
+; Copyright (c) 2009 - 2015, 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.
+;
+;;
+
+EXTERNDEF gSmiMtrrs:QWORD
+EXTERNDEF gcSmiIdtr:FWORD
+EXTERNDEF gcSmiGdtr:FWORD
+EXTERNDEF gcPsd:BYTE
+EXTERNDEF gPhyMask:QWORD
+EXTERNDEF FeaturePcdGet (PcdCpuSmmStackGuard):BYTE
+EXTERNDEF gSavedPageFaultIdtEntry:QWORD
+EXTERNDEF gSavedDebugExceptionIdtEntry:QWORD
+EXTERNDEF FeaturePcdGet (PcdCpuSmmProfileEnable):BYTE
+
+CpuDeadLoop PROTO
+
+ .const
+
+NullSeg DQ 0 ; reserved by architecture
+ DQ 0 ; reserved for future use
+CodeSeg32 LABEL QWORD
+ DW -1 ; LimitLow
+ DW 0 ; BaseLow
+ DB 0 ; BaseMid
+ DB 9bh
+ DB 0cfh ; LimitHigh
+ DB 0 ; BaseHigh
+DataSeg32 LABEL QWORD
+ DW -1 ; LimitLow
+ DW 0 ; BaseLow
+ DB 0 ; BaseMid
+ DB 93h
+ DB 0cfh ; LimitHigh
+ DB 0 ; BaseHigh
+ DQ 0 ; reserved for future use
+CodeSeg16 LABEL QWORD
+ DW -1
+ DW 0
+ DB 0
+ DB 9bh
+ DB 8fh
+ DB 0
+DataSeg16 LABEL QWORD
+ DW -1
+ DW 0
+ DB 0
+ DB 93h
+ DB 8fh
+ DB 0
+CodeSeg64 LABEL QWORD
+ DW -1 ; LimitLow
+ DW 0 ; BaseLow
+ DB 0 ; BaseMid
+ DB 9bh
+ DB 0afh ; LimitHigh
+ DB 0 ; BaseHigh
+; TSS Segment for X64 specially
+TssSeg LABEL QWORD
+ DW TSS_DESC_SIZE ; LimitLow
+ DW 0 ; BaseLow
+ DB 0 ; BaseMid
+ DB 89h
+ DB 080h ; LimitHigh
+ DB 0 ; BaseHigh
+ DD 0 ; BaseUpper
+ DD 0 ; Reserved
+GDT_SIZE = $ - offset NullSeg
+
+; Create TSS Descriptor just after GDT
+TssDescriptor LABEL BYTE
+ DD 0 ; Reserved
+ DQ 0 ; RSP0
+ DQ 0 ; RSP1
+ DQ 0 ; RSP2
+ DD 0 ; Reserved
+ DD 0 ; Reserved
+ DQ 0 ; IST1
+ DQ 0 ; IST2
+ DQ 0 ; IST3
+ DQ 0 ; IST4
+ DQ 0 ; IST5
+ DQ 0 ; IST6
+ DQ 0 ; IST7
+ DD 0 ; Reserved
+ DD 0 ; Reserved
+ DW 0 ; Reserved
+ DW 0 ; I/O Map Base Address
+TSS_DESC_SIZE = $ - offset TssDescriptor
+
+;
+; This structure serves as a template for all processors.
+;
+gcPsd LABEL BYTE
+ DB 'PSDSIG '
+ DW PSD_SIZE
+ DW 2
+ DW 1 SHL 2
+ DW CODE_SEL
+ DW DATA_SEL
+ DW DATA_SEL
+ DW DATA_SEL
+ DW 0
+ DQ 0
+ DQ 0
+ DQ 0 ; fixed in InitializeMpServiceData()
+ DQ offset NullSeg
+ DD GDT_SIZE
+ DD 0
+ DB 24 dup (0)
+ DQ offset gSmiMtrrs
+PSD_SIZE = $ - offset gcPsd
+
+;
+; CODE & DATA segments for SMM runtime
+;
+CODE_SEL = offset CodeSeg64 - offset NullSeg
+DATA_SEL = offset DataSeg32 - offset NullSeg
+
+gcSmiGdtr LABEL FWORD
+ DW GDT_SIZE - 1
+ DQ offset NullSeg
+
+gcSmiIdtr LABEL FWORD
+ DW IDT_SIZE - 1
+ DQ offset _SmiIDT
+
+ .data
+
+;
+; Here is the IDT. There are 32 (not 255) entries in it since only processor
+; generated exceptions will be handled.
+;
+_SmiIDT:
+REPEAT 32
+ DW 0 ; Offset 0:15
+ DW CODE_SEL ; Segment selector
+ DB 0 ; Unused
+ DB 8eh ; Interrupt Gate, Present
+ DW 0 ; Offset 16:31
+ DQ 0 ; Offset 32:63
+ ENDM
+_SmiIDTEnd:
+
+IDT_SIZE = (offset _SmiIDTEnd - offset _SmiIDT)
+
+;
+; Saved IDT Entry for Page Fault
+;
+gSavedPageFaultIdtEntry LABEL QWORD
+ DQ 0
+ DQ 0
+
+;
+; Saved IDT Entry for INT 1
+;
+gSavedDebugExceptionIdtEntry LABEL QWORD
+ DQ 0
+ DQ 0
+
+ExternalVectorTablePtr QWORD 0 ; point to the external interrupt vector table
+
+;
+; Here are the global variables used by #PF exception handler.
+;
+_PFPML4 DD 0
+_PFPDP DD 0
+_PFLOCK DB 0
+
+ .code
+
+InitializeSmmExternalVectorTablePtr PROC
+ mov ExternalVectorTablePtr, rcx
+ ret
+InitializeSmmExternalVectorTablePtr ENDP
+
+;------------------------------------------------------------------------------
+; _SmiExceptionEntryPoints is the collection of exception entrypoints followed
+; by a common exception handler.
+;
+; Stack frame would be as follows as specified in IA32 manuals:
+;
+; +---------------------+ <-- 16-byte aligned ensured by processor
+; + Old SS +
+; +---------------------+
+; + Old RSP +
+; +---------------------+
+; + RFlags +
+; +---------------------+
+; + CS +
+; +---------------------+
+; + RIP +
+; +---------------------+
+; + Error Code +
+; +---------------------+
+; + Vector Number +
+; +---------------------+
+; + RBP +
+; +---------------------+ <-- RBP, 16-byte aligned
+;
+; RSP set to odd multiple of 8 at @CommonEntryPoint means ErrCode PRESENT
+;------------------------------------------------------------------------------
+_SmiExceptionEntryPoints PROC
+IHDLRIDX = 0
+REPEAT 31 ; handler for INT0~INT30
+ push IHDLRIDX
+ jmp @CommonEntryPoint
+IHDLRIDX = IHDLRIDX + 1
+ ENDM
+ push IHDLRIDX ; handler for INT31
+@CommonEntryPoint:
+ test spl, 8 ; odd multiple of 8 => ErrCode present
+ jnz @F
+ push [rsp] ; duplicate INT# if no ErrCode
+ mov qword ptr [rsp + 8], 0
+@@:
+ push rbp
+ mov rbp, rsp
+
+ ;
+ ; Since here the stack pointer is 16-byte aligned, so
+ ; EFI_FX_SAVE_STATE_X64 of EFI_SYSTEM_CONTEXT_x64
+ ; is 16-byte aligned
+ ;
+
+;; UINT64 Rdi, Rsi, Rbp, Rsp, Rbx, Rdx, Rcx, Rax;
+;; UINT64 R8, R9, R10, R11, R12, R13, R14, R15;
+ push r15
+ push r14
+ push r13
+ push r12
+ push r11
+ push r10
+ push r9
+ push r8
+ push rax
+ push rcx
+ push rdx
+ push rbx
+ push qword ptr [rbp + 48] ; RSP
+ push qword ptr [rbp] ; RBP
+ push rsi
+ push rdi
+
+;; UINT64 Gs, Fs, Es, Ds, Cs, Ss; insure high 16 bits of each is zero
+ movzx rax, word ptr [rbp + 56]
+ push rax ; for ss
+ movzx rax, word ptr [rbp + 32]
+ push rax ; for cs
+ mov rax, ds
+ push rax
+ mov rax, es
+ push rax
+ mov rax, fs
+ push rax
+ mov rax, gs
+ push rax
+
+;; UINT64 Rip;
+ push qword ptr [rbp + 24]
+
+;; UINT64 Gdtr[2], Idtr[2];
+ sub rsp, 16
+ sidt fword ptr [rsp]
+ sub rsp, 16
+ sgdt fword ptr [rsp]
+
+;; UINT64 Ldtr, Tr;
+ xor rax, rax
+ str ax
+ push rax
+ sldt ax
+ push rax
+
+;; UINT64 RFlags;
+ push qword ptr [rbp + 40]
+
+;; UINT64 Cr0, Cr1, Cr2, Cr3, Cr4, Cr8;
+ mov rax, cr8
+ push rax
+ mov rax, cr4
+ or rax, 208h
+ mov cr4, rax
+ push rax
+ mov rax, cr3
+ push rax
+ mov rax, cr2
+ push rax
+ xor rax, rax
+ push rax
+ mov rax, cr0
+ push rax
+
+;; UINT64 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7;
+ mov rax, dr7
+ push rax
+ mov rax, dr6
+ push rax
+ mov rax, dr3
+ push rax
+ mov rax, dr2
+ push rax
+ mov rax, dr1
+ push rax
+ mov rax, dr0
+ push rax
+
+;; FX_SAVE_STATE_X64 FxSaveState;
+
+ sub rsp, 512
+ mov rdi, rsp
+ db 0fh, 0aeh, 00000111y ;fxsave [rdi]
+
+; UEFI calling convention for x64 requires that Direction flag in EFLAGs is clear
+ cld
+
+;; UINT32 ExceptionData;
+ push qword ptr [rbp + 16]
+
+;; call into exception handler
+ mov rcx, [rbp + 8]
+ mov rax, ExternalVectorTablePtr ; get the interrupt vectors base
+ mov rax, [rax + rcx * 8]
+ or rax, rax ; NULL?
+
+ je nonNullValue;
+
+;; Prepare parameter and call
+ mov rdx, rsp
+ ;
+ ; Per X64 calling convention, allocate maximum parameter stack space
+ ; and make sure RSP is 16-byte aligned
+ ;
+ sub rsp, 4 * 8 + 8
+ call rax
+ add rsp, 4 * 8 + 8
+ jmp @F
+
+nonNullValue:
+; CpuDeadLoop() is the default exception handler since it preserves the processor
+; branch log.
+ call CpuDeadLoop
+
+@@:
+;; UINT64 ExceptionData;
+ add rsp, 8
+
+;; FX_SAVE_STATE_X64 FxSaveState;
+
+ mov rsi, rsp
+ db 0fh, 0aeh, 00001110y ; fxrstor [rsi]
+ add rsp, 512
+
+;; UINT64 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7;
+;; Skip restoration of DRx registers to support in-circuit emualators
+;; or debuggers set breakpoint in interrupt/exception context
+ add rsp, 8 * 6
+
+;; UINT64 Cr0, Cr1, Cr2, Cr3, Cr4, Cr8;
+ pop rax
+ mov cr0, rax
+ add rsp, 8 ; not for Cr1
+ pop rax
+ mov cr2, rax
+ pop rax
+ mov cr3, rax
+ pop rax
+ mov cr4, rax
+ pop rax
+ mov cr8, rax
+
+;; UINT64 RFlags;
+ pop qword ptr [rbp + 40]
+
+;; UINT64 Ldtr, Tr;
+;; UINT64 Gdtr[2], Idtr[2];
+;; Best not let anyone mess with these particular registers...
+ add rsp, 48
+
+;; UINT64 Rip;
+ pop qword ptr [rbp + 24]
+
+;; UINT64 Gs, Fs, Es, Ds, Cs, Ss;
+ pop rax
+ ; mov gs, rax ; not for gs
+ pop rax
+ ; mov fs, rax ; not for fs
+ ; (X64 will not use fs and gs, so we do not restore it)
+ pop rax
+ mov es, rax
+ pop rax
+ mov ds, rax
+ pop qword ptr [rbp + 32] ; for cs
+ pop qword ptr [rbp + 56] ; for ss
+
+;; UINT64 Rdi, Rsi, Rbp, Rsp, Rbx, Rdx, Rcx, Rax;
+;; UINT64 R8, R9, R10, R11, R12, R13, R14, R15;
+ pop rdi
+ pop rsi
+ add rsp, 8 ; not for rbp
+ pop qword ptr [rbp + 48] ; for rsp
+ pop rbx
+ pop rdx
+ pop rcx
+ pop rax
+ pop r8
+ pop r9
+ pop r10
+ pop r11
+ pop r12
+ pop r13
+ pop r14
+ pop r15
+
+ mov rsp, rbp
+
+; Set single step DB# if SMM profile is enabled and page fault exception happens
+ mov rbp, offset FeaturePcdGet (PcdCpuSmmProfileEnable)
+ cmp byte ptr [rbp], 0
+ jz @Done
+; Check if this is page fault exception
+ cmp qword ptr [rsp + 8], 0eh
+ jnz @F
+; Enable TF bit after page fault handler runs
+ bts dword ptr [rsp + 40], 8 ;RFLAGS
+ jmp @Done
+@@:
+; Check if this is INT 1 exception
+ cmp qword ptr [rsp + 8], 1
+ jnz @Done
+; Clear TF bit after INT1 handler runs
+ btc dword ptr [rsp + 40], 8 ;RFLAGS
+
+@Done:
+
+ pop rbp
+ add rsp, 16 ; skip INT# & ErrCode
+ iretq
+_SmiExceptionEntryPoints ENDP
+
+InitializeIDT PROC
+ mov ecx, (_SmiIDTEnd - _SmiIDT) SHR 2
+ lea rdx, _SmiIDT - 16
+ lea r10, _SmiExceptionEntryPoints - 4
+@@:
+ lea rax, [r10 + rcx] ; rax <- handler address
+ mov [rdx + rcx*4], ax
+ shr rax, 16
+ mov [rdx + rcx*4 + 6], ax
+ shr rax, 16
+ mov [rdx + rcx*4 + 8], eax
+ add ecx, -4
+ jnz @B
+
+; Get absolute address. Avoid RIP relative addressing
+ mov rax, offset FeaturePcdGet (PcdCpuSmmStackGuard)
+ cmp byte ptr [rax], 0
+ jz @F
+
+;
+; If SMM Stack Guard feature is enabled, set the IST field of
+; the interrupe gate for Page Fault Exception to be 1
+;
+ lea rax, _SmiIDT + 14 * 16
+ mov byte ptr [rax + 4], 1
+@@:
+;
+; Save Page Fault IDT entry in gPageFaultIdtEntry
+;
+ lea rcx, _SmiIDT + 14 * 16
+ lea rdx, gSavedPageFaultIdtEntry
+ mov rax, [rcx]
+ mov [rdx], rax
+ mov rax, [rcx + 8]
+ mov [rdx + 8], rax
+
+ mov rax, offset FeaturePcdGet (PcdCpuSmmProfileEnable)
+ cmp byte ptr [rax], 0
+ jz @F
+
+;
+; Save INT 1 IDT entry in gSavedDebugExceptionIdtEntry
+;
+ lea rcx, _SmiIDT + 1 * 16
+ lea rdx, gSavedDebugExceptionIdtEntry
+ mov rax, [rcx]
+ mov [rdx], rax
+ mov rax, [rcx + 8]
+ mov [rdx + 8], rax
+@@:
+ ret
+InitializeIDT ENDP
+
+ END
diff --git a/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/PiSmmCpuDxeSmm/X64/SmmInit.S b/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/PiSmmCpuDxeSmm/X64/SmmInit.S
new file mode 100644
index 0000000000..1d1c7a5a2f
--- /dev/null
+++ b/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/PiSmmCpuDxeSmm/X64/SmmInit.S
@@ -0,0 +1,123 @@
+## @file
+# Functions for relocating SMBASE's for all processors
+#
+# Copyright (c) 2009 - 2015, 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
+#
+##
+
+
+ASM_GLOBAL ASM_PFX(gSmmCr0)
+ASM_GLOBAL ASM_PFX(gSmmCr3)
+ASM_GLOBAL ASM_PFX(gSmmCr4)
+ASM_GLOBAL ASM_PFX(gcSmmInitTemplate)
+ASM_GLOBAL ASM_PFX(gcSmmInitSize)
+ASM_GLOBAL ASM_PFX(gSmmJmpAddr)
+ASM_GLOBAL ASM_PFX(SmmRelocationSemaphoreComplete)
+ASM_GLOBAL ASM_PFX(SmmRelocationSemaphoreComplete32)
+ASM_GLOBAL ASM_PFX(mRebasedFlagAddr32)
+ASM_GLOBAL ASM_PFX(mSmmRelocationOriginalAddressPtr32)
+ASM_GLOBAL ASM_PFX(gSmmInitStack)
+
+ .data
+
+NullSeg: .quad 0
+CodeSeg64:
+ .word -1 # LimitLow
+ .word 0 # BaseLow
+ .byte 0 # BaseMid
+ .byte 0x9b
+ .byte 0xaf # LimitHigh
+ .byte 0 # BaseHigh
+.equ GDT_SIZE, . - NullSeg
+
+ .text
+
+GdtDesc:
+ .word GDT_SIZE
+ .quad NullSeg
+
+SmmStartup:
+ .byte 0x66,0xb8 # mov eax, imm32
+ASM_PFX(gSmmCr3): .space 4
+ movq %rax, %cr3
+ .byte 0x66,0x2e
+ lgdt (GdtDesc - SmmStartup)(%ebp)
+ .byte 0x66,0xb8 # mov eax, imm32
+ASM_PFX(gSmmCr4): .space 4
+ movq %rax, %cr4
+ .byte 0x66
+ movl $0xc0000080,%ecx # IA32_EFER MSR
+ rdmsr
+ orb $1,%ah # set LME bit
+ wrmsr
+ .byte 0x66,0xb8 # mov eax, imm32
+ASM_PFX(gSmmCr0): .space 4
+ movq %rax, %cr0
+ .byte 0x66,0xea # far jmp to long mode
+ASM_PFX(gSmmJmpAddr): .quad LongMode
+LongMode: # long-mode starts here
+ .byte 0x48,0xbc # mov rsp, imm64
+ASM_PFX(gSmmInitStack): .space 8
+ andw $0xfff0, %sp # make sure RSP is 16-byte aligned
+ addq $-0x20, %rsp
+ call ASM_PFX(SmmInitHandler)
+ addq $0x20, %rsp
+ rsm
+
+ASM_PFX(gcSmmInitTemplate):
+
+_SmmInitTemplate:
+ .byte 0x66,0x2e,0x8b,0x2e # mov ebp, cs:[@F]
+ .word L1 - _SmmInitTemplate + 0x8000
+ .byte 0x66, 0x81, 0xed, 0, 0, 3, 0 # sub ebp, 0x30000
+ jmp *%bp # jmp ebp actually
+L1:
+ .quad SmmStartup
+
+ASM_PFX(gcSmmInitSize): .word . - ASM_PFX(gcSmmInitTemplate)
+
+ASM_PFX(SmmRelocationSemaphoreComplete):
+ # Create a simple stack frame to store RAX and the original RSM location
+ pushq %rax # Used to store return address
+ pushq %rax
+
+ # Load the original RSM location onto stack
+ movabsq $ASM_PFX(mSmmRelocationOriginalAddress), %rax
+ movq (%rax), %rax
+ movq %rax, 0x08(%rsp)
+
+ # Update rebase flag
+ movabsq $ASM_PFX(mRebasedFlag), %rax
+ movq (%rax), %rax
+ movb $1, (%rax)
+
+ #restore RAX and return to original RSM location
+ popq %rax
+ retq
+
+#
+# Semaphore code running in 32-bit mode
+#
+ASM_PFX(SmmRelocationSemaphoreComplete32):
+ #
+ # movb $1, ()
+ #
+ .byte 0xc6, 0x05
+ASM_PFX(mRebasedFlagAddr32):
+ .long 0
+ .byte 1
+ #
+ # jmpd ()
+ #
+ .byte 0xff, 0x25
+ASM_PFX(mSmmRelocationOriginalAddressPtr32):
+ .long 0
+
diff --git a/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/PiSmmCpuDxeSmm/X64/SmmInit.asm b/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/PiSmmCpuDxeSmm/X64/SmmInit.asm
new file mode 100644
index 0000000000..b5724d53c6
--- /dev/null
+++ b/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/PiSmmCpuDxeSmm/X64/SmmInit.asm
@@ -0,0 +1,140 @@
+;; @file
+; Functions for relocating SMBASE's for all processors
+;
+; Copyright (c) 2009 - 2015, 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.
+;
+;;
+
+SSM_SMBAS EQU 0fef8h
+SSM_IEDBAS EQU 0ff04h
+
+EXTERNDEF SmmInitHandler:PROC
+EXTERNDEF gSmmCr0:DWORD
+EXTERNDEF gSmmCr3:DWORD
+EXTERNDEF gSmmCr4:DWORD
+EXTERNDEF gSmmJmpAddr:QWORD
+EXTERNDEF gcSmmInitTemplate:BYTE
+EXTERNDEF gcSmmInitSize:WORD
+EXTERNDEF mRebasedFlag:PTR BYTE
+EXTERNDEF mSmmRelocationOriginalAddress:QWORD
+EXTERNDEF mRebasedFlagAddr32:DWORD
+EXTERNDEF mSmmRelocationOriginalAddressPtr32:DWORD
+EXTERNDEF gSmmInitStack:QWORD
+
+ .data
+
+NullSeg DQ 0 ; reserved by architecture
+CodeSeg64 LABEL QWORD
+ DW -1 ; LimitLow
+ DW 0 ; BaseLow
+ DB 0 ; BaseMid
+ DB 9bh
+ DB 0afh ; LimitHigh
+ DB 0 ; BaseHigh
+GDT_SIZE = $ - offset NullSeg
+
+ .code
+
+GdtDesc LABEL FWORD
+ DW GDT_SIZE
+ DQ offset NullSeg
+
+SmmStartup PROC
+ DB 66h, 0b8h ; mov eax, imm32
+gSmmCr3 DD ?
+ mov cr3, rax
+ DB 66h, 2eh
+ lgdt fword ptr [ebp + (offset GdtDesc - SmmStartup)]
+ DB 66h, 0b8h ; mov eax, imm32
+gSmmCr4 DD ?
+ mov cr4, rax
+ DB 66h
+ mov ecx, 0c0000080h ; IA32_EFER MSR
+ rdmsr
+ or ah, 1 ; set LME bit
+ wrmsr
+ DB 66h, 0b8h ; mov eax, imm32
+gSmmCr0 DD ?
+ mov cr0, rax ; enable protected mode & paging
+ DB 66h, 0eah ; far jmp to long mode
+gSmmJmpAddr DQ @LongMode
+@LongMode: ; long-mode starts here
+ DB 48h, 0bch ; mov rsp, imm64
+gSmmInitStack DQ ?
+ and sp, 0fff0h ; make sure RSP is 16-byte aligned
+ ;
+ ; Accoring to X64 calling convention, XMM0~5 are volatile, we need to save
+ ; them before calling C-function.
+ ;
+ sub rsp, 60h
+ movdqa [rsp], xmm0
+ movdqa [rsp + 10h], xmm1
+ movdqa [rsp + 20h], xmm2
+ movdqa [rsp + 30h], xmm3
+ movdqa [rsp + 40h], xmm4
+ movdqa [rsp + 50h], xmm5
+
+ add rsp, -20h
+ call SmmInitHandler
+ add rsp, 20h
+
+ ;
+ ; Restore XMM0~5 after calling C-function.
+ ;
+ movdqa xmm0, [rsp]
+ movdqa xmm1, [rsp + 10h]
+ movdqa xmm2, [rsp + 20h]
+ movdqa xmm3, [rsp + 30h]
+ movdqa xmm4, [rsp + 40h]
+ movdqa xmm5, [rsp + 50h]
+
+ rsm
+SmmStartup ENDP
+
+gcSmmInitTemplate LABEL BYTE
+
+_SmmInitTemplate PROC
+ DB 66h, 2eh, 8bh, 2eh ; mov ebp, cs:[@F]
+ DW @L1 - _SmmInitTemplate + 8000h
+ DB 66h, 81h, 0edh, 00h, 00h, 03h, 00 ; sub ebp, 30000h
+ jmp bp ; jmp ebp actually
+@L1:
+ DQ SmmStartup
+_SmmInitTemplate ENDP
+
+gcSmmInitSize DW $ - gcSmmInitTemplate
+
+SmmRelocationSemaphoreComplete PROC
+ push rax
+ mov rax, mRebasedFlag
+ mov byte ptr [rax], 1
+ pop rax
+ jmp [mSmmRelocationOriginalAddress]
+SmmRelocationSemaphoreComplete ENDP
+
+;
+; Semaphore code running in 32-bit mode
+;
+SmmRelocationSemaphoreComplete32 PROC
+ ;
+ ; mov byte ptr [], 1
+ ;
+ db 0c6h, 05h
+mRebasedFlagAddr32 dd 0
+ db 1
+ ;
+ ; jmp dword ptr []
+ ;
+ db 0ffh, 25h
+mSmmRelocationOriginalAddressPtr32 dd 0
+SmmRelocationSemaphoreComplete32 ENDP
+
+ END
diff --git a/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/PiSmmCpuDxeSmm/X64/SmmProfileArch.c b/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/PiSmmCpuDxeSmm/X64/SmmProfileArch.c
new file mode 100644
index 0000000000..535ee7f231
--- /dev/null
+++ b/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/PiSmmCpuDxeSmm/X64/SmmProfileArch.c
@@ -0,0 +1,302 @@
+/** @file
+ X64 processor specific functions to enable SMM profile.
+
+ Copyright (c) 2012 - 2015, 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 "PiSmmCpuDxeSmm.h"
+#include "SmmProfileInternal.h"
+
+//
+// Current page index.
+//
+UINTN mPFPageIndex;
+
+//
+// Pool for dynamically creating page table in page fault handler.
+//
+UINT64 mPFPageBuffer;
+
+//
+// Store the uplink information for each page being used.
+//
+UINT64 *mPFPageUplink[MAX_PF_PAGE_COUNT];
+
+/**
+ Create SMM page table for S3 path.
+
+**/
+VOID
+InitSmmS3Cr3 (
+ VOID
+ )
+{
+ EFI_PHYSICAL_ADDRESS Pages;
+ UINT64 *PTEntry;
+
+ //
+ // Generate PAE page table for the first 4GB memory space
+ //
+ Pages = Gen4GPageTable (1);
+
+ //
+ // Fill Page-Table-Level4 (PML4) entry
+ //
+ PTEntry = (UINT64*)(UINTN)(Pages - EFI_PAGES_TO_SIZE (1));
+ *PTEntry = Pages + IA32_PG_P;
+ ZeroMem (PTEntry + 1, EFI_PAGE_SIZE - sizeof (*PTEntry));
+
+ //
+ // Return the address of PML4 (to set CR3)
+ //
+ mSmmS3ResumeState->SmmS3Cr3 = (UINT32)(UINTN)PTEntry;
+
+ return ;
+}
+
+/**
+ Allocate pages for creating 4KB-page based on 2MB-page when page fault happens.
+
+**/
+VOID
+InitPagesForPFHandler (
+ VOID
+ )
+{
+ VOID *Address;
+
+ //
+ // Pre-Allocate memory for page fault handler
+ //
+ Address = NULL;
+ Address = AllocatePages (MAX_PF_PAGE_COUNT);
+ ASSERT_EFI_ERROR (Address != NULL);
+
+ mPFPageBuffer = (UINT64)(UINTN) Address;
+ mPFPageIndex = 0;
+ ZeroMem ((VOID *) (UINTN) mPFPageBuffer, EFI_PAGE_SIZE * MAX_PF_PAGE_COUNT);
+ ZeroMem (mPFPageUplink, sizeof (mPFPageUplink));
+
+ return;
+}
+
+/**
+ Allocate one page for creating 4KB-page based on 2MB-page.
+
+ @param Uplink The address of Page-Directory entry.
+
+**/
+VOID
+AcquirePage (
+ UINT64 *Uplink
+ )
+{
+ UINT64 Address;
+
+ //
+ // Get the buffer
+ //
+ Address = mPFPageBuffer + EFI_PAGES_TO_SIZE (mPFPageIndex);
+ ZeroMem ((VOID *) (UINTN) Address, EFI_PAGE_SIZE);
+
+ //
+ // Cut the previous uplink if it exists and wasn't overwritten
+ //
+ if ((mPFPageUplink[mPFPageIndex] != NULL) && ((*mPFPageUplink[mPFPageIndex] & PHYSICAL_ADDRESS_MASK) == Address)) {
+ *mPFPageUplink[mPFPageIndex] = 0;
+ }
+
+ //
+ // Link & Record the current uplink
+ //
+ *Uplink = Address | IA32_PG_P | IA32_PG_RW;
+ mPFPageUplink[mPFPageIndex] = Uplink;
+
+ mPFPageIndex = (mPFPageIndex + 1) % MAX_PF_PAGE_COUNT;
+}
+
+/**
+ Update page table to map the memory correctly in order to make the instruction
+ which caused page fault execute successfully. And it also save the original page
+ table to be restored in single-step exception.
+
+ @param PageTable PageTable Address.
+ @param PFAddress The memory address which caused page fault exception.
+ @param CpuIndex The index of the processor.
+ @param ErrorCode The Error code of exception.
+ @param IsValidPFAddress The flag indicates if SMM profile data need be added.
+
+**/
+VOID
+RestorePageTableAbove4G (
+ UINT64 *PageTable,
+ UINT64 PFAddress,
+ UINTN CpuIndex,
+ UINTN ErrorCode,
+ BOOLEAN *IsValidPFAddress
+ )
+{
+ UINTN PTIndex;
+ UINT64 Address;
+ BOOLEAN Nx;
+ BOOLEAN Existed;
+ UINTN Index;
+ UINTN PFIndex;
+
+ ASSERT ((PageTable != NULL) && (IsValidPFAddress != NULL));
+
+ //
+ // If page fault address is 4GB above.
+ //
+
+ //
+ // Check if page fault address has existed in page table.
+ // If it exists in page table but page fault is generated,
+ // there are 2 possible reasons: 1. present flag is set to 0; 2. instruction fetch in protected memory range.
+ //
+ Existed = FALSE;
+ PageTable = (UINT64*)(AsmReadCr3 () & PHYSICAL_ADDRESS_MASK);
+ PTIndex = BitFieldRead64 (PFAddress, 39, 47);
+ if ((PageTable[PTIndex] & IA32_PG_P) != 0) {
+ // PML4E
+ PageTable = (UINT64*)(UINTN)(PageTable[PTIndex] & PHYSICAL_ADDRESS_MASK);
+ PTIndex = BitFieldRead64 (PFAddress, 30, 38);
+ if ((PageTable[PTIndex] & IA32_PG_P) != 0) {
+ // PDPTE
+ PageTable = (UINT64*)(UINTN)(PageTable[PTIndex] & PHYSICAL_ADDRESS_MASK);
+ PTIndex = BitFieldRead64 (PFAddress, 21, 29);
+ // PD
+ if ((PageTable[PTIndex] & IA32_PG_PS) != 0) {
+ //
+ // 2MB page
+ //
+ Address = (UINT64)(PageTable[PTIndex] & PHYSICAL_ADDRESS_MASK);
+ if ((Address & PHYSICAL_ADDRESS_MASK & ~((1ull << 21) - 1)) == ((PFAddress & PHYSICAL_ADDRESS_MASK & ~((1ull << 21) - 1)))) {
+ Existed = TRUE;
+ }
+ } else {
+ //
+ // 4KB page
+ //
+ PageTable = (UINT64*)(UINTN)(PageTable[PTIndex] & PHYSICAL_ADDRESS_MASK);
+ if (PageTable != 0) {
+ //
+ // When there is a valid entry to map to 4KB page, need not create a new entry to map 2MB.
+ //
+ PTIndex = BitFieldRead64 (PFAddress, 12, 20);
+ Address = (UINT64)(PageTable[PTIndex] & PHYSICAL_ADDRESS_MASK);
+ if ((Address & PHYSICAL_ADDRESS_MASK & ~((1ull << 12) - 1)) == (PFAddress & PHYSICAL_ADDRESS_MASK & ~((1ull << 12) - 1))) {
+ Existed = TRUE;
+ }
+ }
+ }
+ }
+ }
+
+ //
+ // If page entry does not existed in page table at all, create a new entry.
+ //
+ if (!Existed) {
+
+ if (IsAddressValid (PFAddress, &Nx)) {
+ //
+ // If page fault address above 4GB is in protected range but it causes a page fault exception,
+ // Will create a page entry for this page fault address, make page table entry as present/rw and execution-disable.
+ // this access is not saved into SMM profile data.
+ //
+ *IsValidPFAddress = TRUE;
+ }
+
+ //
+ // Create one entry in page table for page fault address.
+ //
+ SmiDefaultPFHandler ();
+ //
+ // Find the page table entry created just now.
+ //
+ PageTable = (UINT64*)(AsmReadCr3 () & PHYSICAL_ADDRESS_MASK);
+ PFAddress = AsmReadCr2 ();
+ // PML4E
+ PTIndex = BitFieldRead64 (PFAddress, 39, 47);
+ PageTable = (UINT64*)(UINTN)(PageTable[PTIndex] & PHYSICAL_ADDRESS_MASK);
+ // PDPTE
+ PTIndex = BitFieldRead64 (PFAddress, 30, 38);
+ PageTable = (UINT64*)(UINTN)(PageTable[PTIndex] & PHYSICAL_ADDRESS_MASK);
+ // PD
+ PTIndex = BitFieldRead64 (PFAddress, 21, 29);
+ Address = PageTable[PTIndex] & PHYSICAL_ADDRESS_MASK;
+ //
+ // Check if 2MB-page entry need be changed to 4KB-page entry.
+ //
+ if (IsAddressSplit (Address)) {
+ AcquirePage (&PageTable[PTIndex]);
+
+ // PTE
+ PageTable = (UINT64*)(UINTN)(PageTable[PTIndex] & PHYSICAL_ADDRESS_MASK);
+ for (Index = 0; Index < 512; Index++) {
+ PageTable[Index] = Address | IA32_PG_RW | IA32_PG_P;
+ if (!IsAddressValid (Address, &Nx)) {
+ PageTable[Index] = PageTable[Index] & (INTN)(INT32)(~(IA32_PG_RW | IA32_PG_P));
+ }
+ if (Nx && mXdSupported) {
+ PageTable[Index] = PageTable[Index] | IA32_PG_NX;
+ }
+ if (Address == (PFAddress & PHYSICAL_ADDRESS_MASK & ~((1ull << 12) - 1))) {
+ PTIndex = Index;
+ }
+ Address += SIZE_4KB;
+ } // end for PT
+ } else {
+ //
+ // Update 2MB page entry.
+ //
+ if (!IsAddressValid (Address, &Nx)) {
+ //
+ // Patch to remove present flag and rw flag.
+ //
+ PageTable[PTIndex] = PageTable[PTIndex] & (INTN)(INT32)(~(IA32_PG_RW | IA32_PG_P));
+ }
+ //
+ // Set XD bit to 1
+ //
+ if (Nx && mXdSupported) {
+ PageTable[PTIndex] = PageTable[PTIndex] | IA32_PG_NX;
+ }
+ }
+ }
+
+ //
+ // Record old entries with non-present status
+ // Old entries include the memory which instruction is at and the memory which instruction access.
+ //
+ //
+ ASSERT (mPFEntryCount[CpuIndex] < MAX_PF_ENTRY_COUNT);
+ if (mPFEntryCount[CpuIndex] < MAX_PF_ENTRY_COUNT) {
+ PFIndex = mPFEntryCount[CpuIndex];
+ mLastPFEntryValue[CpuIndex][PFIndex] = PageTable[PTIndex];
+ mLastPFEntryPointer[CpuIndex][PFIndex] = &PageTable[PTIndex];
+ mPFEntryCount[CpuIndex]++;
+ }
+
+ //
+ // Add present flag or clear XD flag to make page fault handler succeed.
+ //
+ PageTable[PTIndex] |= IA32_PG_RW | IA32_PG_P;
+ if ((ErrorCode & IA32_PF_EC_ID) != 0) {
+ //
+ // If page fault is caused by instruction fetch, clear XD bit in the entry.
+ //
+ PageTable[PTIndex] &= ~IA32_PG_NX;
+ }
+
+ return;
+}
diff --git a/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/PiSmmCpuDxeSmm/X64/SmmProfileArch.h b/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/PiSmmCpuDxeSmm/X64/SmmProfileArch.h
new file mode 100644
index 0000000000..ea43d143a6
--- /dev/null
+++ b/BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/PiSmmCpuDxeSmm/X64/SmmProfileArch.h
@@ -0,0 +1,106 @@
+/** @file
+ X64 processor specific header file.
+
+ Copyright (c) 2012 - 2015, 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 _SMM_PROFILE_ARCH_H_
+#define _SMM_PROFILE_ARCH_H_
+
+#pragma pack (1)
+
+typedef struct _MSR_DS_AREA_STRUCT {
+ UINT64 BTSBufferBase;
+ UINT64 BTSIndex;
+ UINT64 BTSAbsoluteMaximum;
+ UINT64 BTSInterruptThreshold;
+ UINT64 PEBSBufferBase;
+ UINT64 PEBSIndex;
+ UINT64 PEBSAbsoluteMaximum;
+ UINT64 PEBSInterruptThreshold;
+ UINT64 PEBSCounterReset[2];
+ UINT64 Reserved;
+} MSR_DS_AREA_STRUCT;
+
+typedef struct _BRANCH_TRACE_RECORD {
+ UINT64 LastBranchFrom;
+ UINT64 LastBranchTo;
+ UINT64 Rsvd0 : 4;
+ UINT64 BranchPredicted : 1;
+ UINT64 Rsvd1 : 59;
+} BRANCH_TRACE_RECORD;
+
+typedef struct _PEBS_RECORD {
+ UINT64 Rflags;
+ UINT64 LinearIP;
+ UINT64 Rax;
+ UINT64 Rbx;
+ UINT64 Rcx;
+ UINT64 Rdx;
+ UINT64 Rsi;
+ UINT64 Rdi;
+ UINT64 Rbp;
+ UINT64 Rsp;
+ UINT64 R8;
+ UINT64 R9;
+ UINT64 R10;
+ UINT64 R11;
+ UINT64 R12;
+ UINT64 R13;
+ UINT64 R14;
+ UINT64 R15;
+} PEBS_RECORD;
+
+#pragma pack ()
+
+#define PHYSICAL_ADDRESS_MASK ((1ull << 52) - SIZE_4KB)
+
+/**
+ Update page table to map the memory correctly in order to make the instruction
+ which caused page fault execute successfully. And it also save the original page
+ table to be restored in single-step exception.
+
+ @param PageTable PageTable Address.
+ @param PFAddress The memory address which caused page fault exception.
+ @param CpuIndex The index of the processor.
+ @param ErrorCode The Error code of exception.
+ @param IsValidPFAddress The flag indicates if SMM profile data need be added.
+
+**/
+VOID
+RestorePageTableAbove4G (
+ UINT64 *PageTable,
+ UINT64 PFAddress,
+ UINTN CpuIndex,
+ UINTN ErrorCode,
+ BOOLEAN *IsValidPFAddress
+ );
+
+/**
+ Create SMM page table for S3 path.
+
+**/
+VOID
+InitSmmS3Cr3 (
+ VOID
+ );
+
+/**
+ Allocate pages for creating 4KB-page based on 2MB-page when page fault happens.
+
+**/
+VOID
+InitPagesForPFHandler (
+ VOID
+ );
+
+#endif // _SMM_PROFILE_ARCH_H_