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 ++ 41 files changed, 14293 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 (limited to 'BraswellPlatformPkg/Common/Silicon/IntelSiliconBasic/CpuInit') 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 -- cgit v1.2.3