From 9dfd62064d1d1a6344165febb44c7b0d0f3a6a1e Mon Sep 17 00:00:00 2001 From: Guo Mang Date: Wed, 3 Aug 2016 11:46:45 +0800 Subject: BraswellPlatformPkg: Move IntelSiliconBasic to Common/Silicon/IntelSiliconBasic Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Guo Mang Reviewed-by: David Wei --- .../Common/Silicon/IntelSiliconBasic/CpuInit/Cpu.c | 999 +++++++++++ .../IntelSiliconBasic/CpuInit/CpuDataStruct.h | 121 ++ .../Silicon/IntelSiliconBasic/CpuInit/CpuDxe.h | 240 +++ .../Silicon/IntelSiliconBasic/CpuInit/CpuRegs.h | 410 +++++ .../Silicon/IntelSiliconBasic/CpuInit/Exception.h | 71 + .../IntelSiliconBasic/CpuInit/Ia32/CpuAsm.asm | 693 ++++++++ .../IntelSiliconBasic/CpuInit/Ia32/CpuAsm.s | 761 +++++++++ .../IntelSiliconBasic/CpuInit/Ia32/Exception.c | 337 ++++ .../IntelSiliconBasic/CpuInit/Ia32/Htequ.inc | 40 + .../IntelSiliconBasic/CpuInit/Ia32/InitializeFpu.s | 72 + .../IntelSiliconBasic/CpuInit/Ia32/MPFuncs32.asm | 426 +++++ .../IntelSiliconBasic/CpuInit/Ia32/MPFuncs32.s | 444 +++++ .../CpuInit/Ia32/MemoryOperation.c | 380 +++++ .../IntelSiliconBasic/CpuInit/Ia32/MpCommon32.asm | 103 ++ .../IntelSiliconBasic/CpuInit/Ia32/MpCommon32.s | 114 ++ .../Silicon/IntelSiliconBasic/CpuInit/Ia32/MpCpu.c | 90 + .../IntelSiliconBasic/CpuInit/Ia32/MpProc.asm | 83 + .../IntelSiliconBasic/CpuInit/Ia32/MpProc.s | 69 + .../IntelSiliconBasic/CpuInit/Ia32/ProcessorDef.h | 56 + .../IntelSiliconBasic/CpuInit/MemoryAttribute.c | 975 +++++++++++ .../IntelSiliconBasic/CpuInit/MemoryAttribute.h | 136 ++ .../Silicon/IntelSiliconBasic/CpuInit/Microcode.c | 483 ++++++ .../Silicon/IntelSiliconBasic/CpuInit/MiscFuncs.c | 103 ++ .../Silicon/IntelSiliconBasic/CpuInit/MiscFuncs.h | 45 + .../Silicon/IntelSiliconBasic/CpuInit/MpCommon.c | 879 ++++++++++ .../Silicon/IntelSiliconBasic/CpuInit/MpCommon.h | 425 +++++ .../Silicon/IntelSiliconBasic/CpuInit/MpCpu.inf | 143 ++ .../Silicon/IntelSiliconBasic/CpuInit/MpService.c | 1781 ++++++++++++++++++++ .../Silicon/IntelSiliconBasic/CpuInit/MtrrSync.c | 233 +++ .../IntelSiliconBasic/CpuInit/PlatformMpService.h | 636 +++++++ .../Silicon/IntelSiliconBasic/CpuInit/x64/Cpu.asm | 199 +++ .../IntelSiliconBasic/CpuInit/x64/CpuAsm.asm | 462 +++++ .../CpuInit/x64/CpuInitDxeGccDummy.c | 184 ++ .../IntelSiliconBasic/CpuInit/x64/Exception.c | 319 ++++ .../IntelSiliconBasic/CpuInit/x64/Htequ.inc | 44 + .../CpuInit/x64/MemoryOperation.c | 718 ++++++++ .../Silicon/IntelSiliconBasic/CpuInit/x64/MpCpu.c | 76 + .../IntelSiliconBasic/CpuInit/x64/MpFuncs.asm | 604 +++++++ .../IntelSiliconBasic/CpuInit/x64/PlatformCpuLib.h | 135 ++ .../IntelSiliconBasic/CpuInit/x64/ProcessorDef.h | 57 + .../IntelSiliconBasic/CpuInit/x64/VirtualMemory.h | 147 ++ .../IntelSiliconBasic/Include/AcpiCpuData.h | 35 + .../IntelSiliconBasic/Include/CpuHotPlugData.h | 35 + .../Include/Library/CpuConfigLib.h | 686 ++++++++ .../Include/Library/SmmCpuPlatformHookLib.h | 107 ++ .../Include/Library/SocketLga775Lib.h | 314 ++++ .../Include/Protocol/SmmCpuService.h | 209 +++ .../Include/Protocol/SmmCpuSync.h | 107 ++ .../Include/Protocol/SmmCpuSync2.h | 186 ++ .../Library/CpuConfigLib/CpuConfig.c | 961 +++++++++++ .../Library/CpuConfigLib/CpuConfig.h | 65 + .../Library/CpuConfigLib/CpuConfigLib.inf | 57 + .../SmmCpuPlatformHookLibNull.c | 109 ++ .../SmmCpuPlatformHookLibNull.inf | 45 + .../PciHostBridge/PciHostBridge.c | 1105 ++++++++++++ .../PciHostBridge/PciHostBridge.h | 157 ++ .../PciHostBridge/PciHostBridge.inf | 82 + .../PciHostBridge/PciRootBridge.h | 155 ++ .../PciHostBridge/PciRootBridgeIo.c | 1459 ++++++++++++++++ .../PiSmmCommunication/PiSmmCommunicationPei.c | 424 +++++ .../PiSmmCommunication/PiSmmCommunicationPei.inf | 67 + .../PiSmmCommunication/PiSmmCommunicationPrivate.h | 31 + .../PiSmmCommunication/PiSmmCommunicationSmm.c | 288 ++++ .../PiSmmCommunication/PiSmmCommunicationSmm.inf | 78 + .../IntelSiliconBasic/PiSmmCpuDxeSmm/CpuS3.c | 435 +++++ .../IntelSiliconBasic/PiSmmCpuDxeSmm/CpuService.c | 484 ++++++ .../IntelSiliconBasic/PiSmmCpuDxeSmm/CpuService.h | 198 +++ .../PiSmmCpuDxeSmm/Ia32/MpFuncs.S | 159 ++ .../PiSmmCpuDxeSmm/Ia32/MpFuncs.asm | 163 ++ .../PiSmmCpuDxeSmm/Ia32/PageTbl.c | 96 ++ .../PiSmmCpuDxeSmm/Ia32/Semaphore.c | 62 + .../PiSmmCpuDxeSmm/Ia32/SmiEntry.S | 153 ++ .../PiSmmCpuDxeSmm/Ia32/SmiEntry.asm | 156 ++ .../PiSmmCpuDxeSmm/Ia32/SmiException.S | 1172 +++++++++++++ .../PiSmmCpuDxeSmm/Ia32/SmiException.asm | 858 ++++++++++ .../PiSmmCpuDxeSmm/Ia32/SmmInit.S | 94 ++ .../PiSmmCpuDxeSmm/Ia32/SmmInit.asm | 104 ++ .../PiSmmCpuDxeSmm/Ia32/SmmProfileArch.c | 66 + .../PiSmmCpuDxeSmm/Ia32/SmmProfileArch.h | 98 ++ .../IntelSiliconBasic/PiSmmCpuDxeSmm/MpService.c | 1759 +++++++++++++++++++ .../PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.c | 1596 ++++++++++++++++++ .../PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.h | 780 +++++++++ .../PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.inf | 195 +++ .../IntelSiliconBasic/PiSmmCpuDxeSmm/SmmFeatures.c | 492 ++++++ .../IntelSiliconBasic/PiSmmCpuDxeSmm/SmmFeatures.h | 220 +++ .../IntelSiliconBasic/PiSmmCpuDxeSmm/SmmProfile.c | 1369 +++++++++++++++ .../IntelSiliconBasic/PiSmmCpuDxeSmm/SmmProfile.h | 76 + .../PiSmmCpuDxeSmm/SmmProfileInternal.h | 190 +++ .../IntelSiliconBasic/PiSmmCpuDxeSmm/SyncTimer.c | 111 ++ .../IntelSiliconBasic/PiSmmCpuDxeSmm/X64/MpFuncs.S | 198 +++ .../PiSmmCpuDxeSmm/X64/MpFuncs.asm | 201 +++ .../IntelSiliconBasic/PiSmmCpuDxeSmm/X64/PageTbl.c | 647 +++++++ .../PiSmmCpuDxeSmm/X64/Semaphore.c | 104 ++ .../PiSmmCpuDxeSmm/X64/SmiEntry.S | 236 +++ .../PiSmmCpuDxeSmm/X64/SmiEntry.asm | 232 +++ .../PiSmmCpuDxeSmm/X64/SmiException.S | 822 +++++++++ .../PiSmmCpuDxeSmm/X64/SmiException.asm | 504 ++++++ .../IntelSiliconBasic/PiSmmCpuDxeSmm/X64/SmmInit.S | 123 ++ .../PiSmmCpuDxeSmm/X64/SmmInit.asm | 140 ++ .../PiSmmCpuDxeSmm/X64/SmmProfileArch.c | 302 ++++ .../PiSmmCpuDxeSmm/X64/SmmProfileArch.h | 106 ++ 101 files changed, 35756 insertions(+) create mode 100644 BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/CpuInit/Cpu.c create mode 100644 BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/CpuInit/CpuDataStruct.h create mode 100644 BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/CpuInit/CpuDxe.h create mode 100644 BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/CpuInit/CpuRegs.h create mode 100644 BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/CpuInit/Exception.h create mode 100644 BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/CpuInit/Ia32/CpuAsm.asm create mode 100644 BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/CpuInit/Ia32/CpuAsm.s create mode 100644 BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/CpuInit/Ia32/Exception.c create mode 100644 BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/CpuInit/Ia32/Htequ.inc create mode 100644 BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/CpuInit/Ia32/InitializeFpu.s create mode 100644 BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/CpuInit/Ia32/MPFuncs32.asm create mode 100644 BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/CpuInit/Ia32/MPFuncs32.s create mode 100644 BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/CpuInit/Ia32/MemoryOperation.c create mode 100644 BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/CpuInit/Ia32/MpCommon32.asm create mode 100644 BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/CpuInit/Ia32/MpCommon32.s create mode 100644 BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/CpuInit/Ia32/MpCpu.c create mode 100644 BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/CpuInit/Ia32/MpProc.asm create mode 100644 BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/CpuInit/Ia32/MpProc.s create mode 100644 BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/CpuInit/Ia32/ProcessorDef.h create mode 100644 BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/CpuInit/MemoryAttribute.c create mode 100644 BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/CpuInit/MemoryAttribute.h create mode 100644 BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/CpuInit/Microcode.c create mode 100644 BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/CpuInit/MiscFuncs.c create mode 100644 BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/CpuInit/MiscFuncs.h create mode 100644 BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/CpuInit/MpCommon.c create mode 100644 BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/CpuInit/MpCommon.h create mode 100644 BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/CpuInit/MpCpu.inf create mode 100644 BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/CpuInit/MpService.c create mode 100644 BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/CpuInit/MtrrSync.c create mode 100644 BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/CpuInit/PlatformMpService.h create mode 100644 BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/CpuInit/x64/Cpu.asm create mode 100644 BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/CpuInit/x64/CpuAsm.asm create mode 100644 BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/CpuInit/x64/CpuInitDxeGccDummy.c create mode 100644 BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/CpuInit/x64/Exception.c create mode 100644 BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/CpuInit/x64/Htequ.inc create mode 100644 BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/CpuInit/x64/MemoryOperation.c create mode 100644 BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/CpuInit/x64/MpCpu.c create mode 100644 BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/CpuInit/x64/MpFuncs.asm create mode 100644 BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/CpuInit/x64/PlatformCpuLib.h create mode 100644 BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/CpuInit/x64/ProcessorDef.h create mode 100644 BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/CpuInit/x64/VirtualMemory.h create mode 100644 BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/Include/AcpiCpuData.h create mode 100644 BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/Include/CpuHotPlugData.h create mode 100644 BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/Include/Library/CpuConfigLib.h create mode 100644 BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/Include/Library/SmmCpuPlatformHookLib.h create mode 100644 BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/Include/Library/SocketLga775Lib.h create mode 100644 BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/Include/Protocol/SmmCpuService.h create mode 100644 BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/Include/Protocol/SmmCpuSync.h create mode 100644 BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/Include/Protocol/SmmCpuSync2.h create mode 100644 BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/Library/CpuConfigLib/CpuConfig.c create mode 100644 BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/Library/CpuConfigLib/CpuConfig.h create mode 100644 BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/Library/CpuConfigLib/CpuConfigLib.inf create mode 100644 BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/Library/SmmCpuPlatformHookLibNull/SmmCpuPlatformHookLibNull.c create mode 100644 BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/Library/SmmCpuPlatformHookLibNull/SmmCpuPlatformHookLibNull.inf create mode 100644 BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/PciHostBridge/PciHostBridge.c create mode 100644 BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/PciHostBridge/PciHostBridge.h create mode 100644 BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/PciHostBridge/PciHostBridge.inf create mode 100644 BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/PciHostBridge/PciRootBridge.h create mode 100644 BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/PciHostBridge/PciRootBridgeIo.c create mode 100644 BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/PiSmmCommunication/PiSmmCommunicationPei.c create mode 100644 BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/PiSmmCommunication/PiSmmCommunicationPei.inf create mode 100644 BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/PiSmmCommunication/PiSmmCommunicationPrivate.h create mode 100644 BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/PiSmmCommunication/PiSmmCommunicationSmm.c create mode 100644 BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/PiSmmCommunication/PiSmmCommunicationSmm.inf create mode 100644 BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/PiSmmCpuDxeSmm/CpuS3.c create mode 100644 BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/PiSmmCpuDxeSmm/CpuService.c create mode 100644 BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/PiSmmCpuDxeSmm/CpuService.h create mode 100644 BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/PiSmmCpuDxeSmm/Ia32/MpFuncs.S create mode 100644 BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/PiSmmCpuDxeSmm/Ia32/MpFuncs.asm create mode 100644 BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/PiSmmCpuDxeSmm/Ia32/PageTbl.c create mode 100644 BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/PiSmmCpuDxeSmm/Ia32/Semaphore.c create mode 100644 BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/PiSmmCpuDxeSmm/Ia32/SmiEntry.S create mode 100644 BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/PiSmmCpuDxeSmm/Ia32/SmiEntry.asm create mode 100644 BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/PiSmmCpuDxeSmm/Ia32/SmiException.S create mode 100644 BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/PiSmmCpuDxeSmm/Ia32/SmiException.asm create mode 100644 BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/PiSmmCpuDxeSmm/Ia32/SmmInit.S create mode 100644 BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/PiSmmCpuDxeSmm/Ia32/SmmInit.asm create mode 100644 BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/PiSmmCpuDxeSmm/Ia32/SmmProfileArch.c create mode 100644 BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/PiSmmCpuDxeSmm/Ia32/SmmProfileArch.h create mode 100644 BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/PiSmmCpuDxeSmm/MpService.c create mode 100644 BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.c create mode 100644 BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.h create mode 100644 BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.inf create mode 100644 BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/PiSmmCpuDxeSmm/SmmFeatures.c create mode 100644 BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/PiSmmCpuDxeSmm/SmmFeatures.h create mode 100644 BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/PiSmmCpuDxeSmm/SmmProfile.c create mode 100644 BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/PiSmmCpuDxeSmm/SmmProfile.h create mode 100644 BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/PiSmmCpuDxeSmm/SmmProfileInternal.h create mode 100644 BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/PiSmmCpuDxeSmm/SyncTimer.c create mode 100644 BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/PiSmmCpuDxeSmm/X64/MpFuncs.S create mode 100644 BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/PiSmmCpuDxeSmm/X64/MpFuncs.asm create mode 100644 BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/PiSmmCpuDxeSmm/X64/PageTbl.c create mode 100644 BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/PiSmmCpuDxeSmm/X64/Semaphore.c create mode 100644 BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/PiSmmCpuDxeSmm/X64/SmiEntry.S create mode 100644 BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/PiSmmCpuDxeSmm/X64/SmiEntry.asm create mode 100644 BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/PiSmmCpuDxeSmm/X64/SmiException.S create mode 100644 BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/PiSmmCpuDxeSmm/X64/SmiException.asm create mode 100644 BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/PiSmmCpuDxeSmm/X64/SmmInit.S create mode 100644 BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/PiSmmCpuDxeSmm/X64/SmmInit.asm create mode 100644 BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/PiSmmCpuDxeSmm/X64/SmmProfileArch.c create mode 100644 BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/PiSmmCpuDxeSmm/X64/SmmProfileArch.h (limited to 'BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic') 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.
+ + 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 +#include + +#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.
+ + 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 +// +// 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.
+ + 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 + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#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.
+ + 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.
+ + 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 + +#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.
+; +; 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.
+# +# 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.
+ + 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.
+; +; 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.
+# +# 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.
+; +; 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.
+# +# 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.
+ + 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.
+; +; 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.
+# +# 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.
+ + 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.
+; +; 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.
+# +# 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.
+ + 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.
+ + 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.
+ + 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.
+ + 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.
+ + 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.
+ + 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.
+ + 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 +#include +#include + +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.
+ + 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.
+# +# 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.
+ + 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.
+ + 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.
+ + 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.
+; +; 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.
+; +; 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.
+ + 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.
+ + 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.
+; +; 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.
+ + 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.
+ + 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.
+; +; 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.
+ + 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.
+ + 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.
+ + 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.
+ + 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.
+ + 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.
+ + 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 + +// +// 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.
+ + 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.
+ + 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.
+ + 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 +#include + +#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.
+ + 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.
+ + 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.
+ + 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.
+ + 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 + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +/** + 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.
+# +# 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.
+ + 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 + +/** + 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.
+# +# 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.
+ + 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.
+ + 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.
+# +# 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.
+ + 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 +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// +// 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.
+ + 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 + +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.
+ + 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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.
+# +# 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.
+ + 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.
+ + 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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.
+# +# 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.
+ + 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.
+ + 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.
+ + 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.
+# +# 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.
+; +; 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.
+ + 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.
+ + 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.
+# +# 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.
+; +; 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.
+# +# 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.
+; +; 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.
+# +# 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.
+; +; 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.
+ + 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.
+ + 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.
+ + 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.
+ + 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.
+ + 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 +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#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.
+# +# 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.
+ + 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 + +#include +#include +#include +#include +#include +#include +#include + +#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.
+ + 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.
+ + 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.
+ + 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.
+ + 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 +#include +#include +#include +#include +#include +#include + +#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.
+ + 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.
+# +# 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.
+; +; 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.
+ + 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.
+ + 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.
+# +# 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.
+; +; 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.
+# +# 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.
+; +; 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.
+# +# 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.
+; +; 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.
+ + 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.
+ + 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_ -- cgit v1.2.3