/** @file Cpu driver, which initializes CPU and implements CPU Architecture Protocol as defined in Framework specification. @copyright Copyright (c) 1999 - 2013 Intel Corporation. All rights reserved This software and associated documentation (if any) is furnished under a license and may only be used or copied in accordance with the terms of the license. Except as permitted by such license, no part of this software or documentation may be reproduced, stored in a retrieval system, or transmitted in any form or by any means without the express written consent of Intel Corporation. This file contains an 'Intel Peripheral Driver' and uniquely identified as "Intel Reference Module" and is licensed for Intel CPUs and chipsets under the terms of your license agreement with Intel or your vendor. This file may be modified by the user, subject to additional terms of the license agreement **/ #if !defined(EDK_RELEASE_VERSION) || (EDK_RELEASE_VERSION < 0x00020000) #include "EdkIIGlueDxe.h" #include "CpuInitDxe.h" #include "ProcessorData.h" #include "CacheData.h" #include "Exception.h" #include "PfatDefinitions.h" #include "BootGuardLibrary.h" #include "BootGuardRevocationLib.h" #define SAMPLE_TICK_COUNT 1000 #endif #include extern UINT64 mValidMtrrAddressMask; extern UINT64 mValidMtrrBitsMask; extern EFI_CPU_MICROCODE_HEADER **mMicrocodePointerBuffer; extern UINT8 CpuInitDxeStrings[]; #if (EFI_SPECIFICATION_VERSION >= 0x2000A) EFI_HANDLE mDriverHandle; EFI_HII_DATABASE_PROTOCOL *mHiiDatabase; #else EFI_HII_PROTOCOL *mHii; #endif EFI_SMM_BASE_PROTOCOL *mSmmBaseProtocol = NULL; VOID *mSmmBaseRegistration; EFI_METRONOME_ARCH_PROTOCOL *mMetronome; DXE_CPU_PLATFORM_POLICY_PROTOCOL *mPlatformCpu = NULL; EFI_HII_HANDLE mStringHandle; BOOLEAN mIsFlushingGCD = TRUE; UINT8 mSmmbaseSwSmiNumber; BOOLEAN mVariableMtrrChanged; BOOLEAN mFixedMtrrChanged; UINT64 mCpuFrequency = 0; EFI_EVENT gReadyToBootEvent; 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 }; /** Decide if the CPU is executing in SMM mode @retval TRUE - The CPU is executing in SMM mode @retval FALSE - The CPU is not executing in SMM mode **/ BOOLEAN ExecutionInSmm ( VOID ) { EFI_STATUS Status; BOOLEAN InSmm; if (mSmmBaseProtocol == NULL) { return FALSE; } Status = mSmmBaseProtocol->InSmm (mSmmBaseProtocol, &InSmm); ASSERT_EFI_ERROR (Status); return InSmm; } /** 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 @exception 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) { EfiInvd (); 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 ) { if (!ExecutionInSmm ()) { 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. **/ 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[in] 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. @exception 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. @exception 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; } EFI_STATUS EFIAPI GetTimerValue ( IN EFI_CPU_ARCH_PROTOCOL *This, IN UINT32 TimerIndex, OUT UINT64 *TimerValue, OUT UINT64 *TimerPeriod OPTIONAL ) /** 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[in] TimerValue - Pointer to the returned timer value. @param[in] 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. @exception 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. **/ { UINT64 Actual; if (TimerValue == NULL) { return EFI_INVALID_PARAMETER; } if (TimerIndex != 0) { return EFI_INVALID_PARAMETER; } *TimerValue = EfiReadTsc (); 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 @exception EFI_UNSUPPORTED - If the desired operation cannot be done @retval 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; UINTN MtrrNumber; BOOLEAN Positive; BOOLEAN OverLap; #define SKIP_ALIGN_CHECK 0 #if SKIP_ALIGN_CHECK UINT32 Remainder; #endif EFI_MP_SERVICES_PROTOCOL *MpService; EFI_STATUS Status1; UINT32 VariableMtrrLimit; UINT32 SmiEnVal; BOOLEAN InterruptState; UINT8 MasterIrq,SlaveIrq; mFixedMtrrChanged = FALSE; mVariableMtrrChanged = FALSE; VariableMtrrLimit = (UINT32) (AsmReadMsr64 (IA32_MTRR_CAP) & B_IA32_MTRR_VARIABLE_SUPPORT); 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 = CACHE_UNCACHEABLE; break; case EFI_MEMORY_WC: Attributes = CACHE_WRITECOMBINING; break; case EFI_MEMORY_WT: Attributes = CACHE_WRITETHROUGH; break; case EFI_MEMORY_WP: Attributes = CACHE_WRITEPROTECTED; break; case EFI_MEMORY_WB: Attributes = CACHE_WRITEBACK; break; default: return EFI_UNSUPPORTED; } /// /// Check if Fixed MTRR /// Status = EFI_SUCCESS; while ((BaseAddress < (1 << 20)) && (Length > 0) && Status == EFI_SUCCESS) { Status = CalculateFixedMtrr (Attributes, &BaseAddress, &Length); if (EFI_ERROR (Status)) { return Status; } } MasterIrq = IoRead8(0x21); //save current irq mask SlaveIrq = IoRead8(0xA1); IoWrite8(0x21,0xFF); IoWrite8(0xA1,0xFF); CpuGetInterruptState (&gCpu, &InterruptState); if (InterruptState) { DisableInterrupt (&gCpu); } SmiEnVal = IoRead32(PM_BASE_ADDRESS + 0x30); // Save SMI Control and Enable Reg. IoWrite32(PM_BASE_ADDRESS + 0x30, 0); // Disable SMI if (mFixedMtrrChanged) { ProgramFixedMtrr (); } 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 /// #if SKIP_ALIGN_CHECK DivU64x32Remainder (BaseAddress, (UINT32) Power2MaxMemory (LShiftU64 (Length, 1)), &Remainder); if (Remainder != 0) { DivU64x32Remainder (BaseAddress, (UINT32) Power2MaxMemory (Length), &Remainder); if (Remainder != 0) { Status = EFI_UNSUPPORTED; goto Done; } } #endif /// /// 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 == CACHE_UNCACHEABLE) { Status = EFI_SUCCESS; goto Done; } } /// /// Program Variable MTRRs /// if (mUsedMtrr >= VariableMtrrLimit) { Status = EFI_OUT_OF_RESOURCES; goto Done; } /// /// Find first unused MTRR /// for (MsrNum = CACHE_VARIABLE_MTRR_BASE; MsrNum < (CACHE_VARIABLE_MTRR_BASE + VariableMtrrLimit * 2 - 1); MsrNum += 2) { if ((AsmReadMsr64 (MsrNum + 1) & B_CACHE_MTRR_VALID) == 0) { break; } } TempQword = Length; if (TempQword == Power2MaxMemory (TempQword)) { ProgramVariableMtrr ( MsrNum, BaseAddress, Length, Attributes ); } else { GetDirection (TempQword, &MtrrNumber, &Positive); if ((mUsedMtrr + MtrrNumber) > VariableMtrrLimit) { goto Done; } if (!Positive) { Length = Power2MaxMemory (LShiftU64 (TempQword, 1)); ProgramVariableMtrr ( MsrNum, BaseAddress, Length, Attributes ); BaseAddress += TempQword; TempQword = Length - TempQword; Attributes = CACHE_UNCACHEABLE; } do { /// /// Find unused MTRR /// for (; MsrNum < (CACHE_VARIABLE_MTRR_BASE + VariableMtrrLimit * 2 - 1); MsrNum += 2) { if ((AsmReadMsr64 (MsrNum + 1) & B_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)) { if (mVariableMtrrChanged || mFixedMtrrChanged) { /// /// PERF_START (NULL, L"CacheSync", NULL, 0); /// ReadMtrrRegisters (); Status1 = MpService->StartupAllAPs ( MpService, MpMtrrSynchUp, FALSE, NULL, 0, NULL, NULL ); /// /// PERF_END (NULL, L"CacheSync", NULL, 0); /// } } IoWrite32(PM_BASE_ADDRESS + 0x30, SmiEnVal); // Restore SMI Control and Enable Reg. if (InterruptState) { EnableInterrupt (&gCpu); } IoWrite8(0x21,MasterIrq); //restore irq mask IoWrite8(0xA1,SlaveIrq); return Status; } /** Initialize the SmmBase pointer when SmmBase protocol get installed @param[in] Event - Event whose notification function is being invoked. @param[in] Context - Pointer to the notification functions context, which is implementation dependent. **/ VOID EFIAPI InitializeSmmBasePtr ( IN EFI_EVENT Event, IN VOID *Context ) { EFI_STATUS Status; Status = gBS->LocateProtocol (&gEfiSmmBaseProtocolGuid, NULL, (VOID **) &mSmmBaseProtocol); if (EFI_ERROR (Status)) { mSmmBaseProtocol = NULL; } } /** Call back function to publish Hii data @param[in] Event - The triggered event. @param[in] Context - Context for this event. **/ VOID EFIAPI HiiCallback ( IN EFI_EVENT Event, IN VOID *Context ) { #if (EFI_SPECIFICATION_VERSION >= 0x2000A) EFI_HII_PACKAGE_LIST_HEADER *PackageList; #else EFI_HII_PACKAGES *PackageList; #endif EFI_STATUS Status; /// /// Initialize strings to HII database /// #if (EFI_SPECIFICATION_VERSION >= 0x0002000A) Status = gBS->LocateProtocol ( &gEfiHiiDatabaseProtocolGuid, NULL, &mHiiDatabase ); if (EFI_ERROR (Status)) { return; } /// /// Create driver handle used by HII database /// Status = CreateHiiDriverHandle (&mDriverHandle); if (EFI_ERROR (Status)) { return; } /// /// Publish our HII data /// PackageList = PreparePackageList (1, &gProcessorProducerGuid, CpuInitDxeStrings); if (PackageList == NULL) { return; } Status = mHiiDatabase->NewPackageList ( mHiiDatabase, PackageList, mDriverHandle, &mStringHandle ); ASSERT_EFI_ERROR (Status); #else /// /// There should only be one HII protocol /// Status = gBS->LocateProtocol ( &gEfiHiiProtocolGuid, NULL, (VOID **) &mHii ); if (EFI_ERROR (Status)) { return; } PackageList = PreparePackages (1, &gProcessorProducerGuid, CpuInitDxeStrings); Status = mHii->NewPack (mHii, PackageList, &mStringHandle); FreePool (PackageList); #endif } /** Create SMBIOS Table type - FviSmbiosType, when ExitPmAuth event is signaled @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 InitializeFviDataCallback ( IN EFI_EVENT Event, IN VOID *Context ) { EFI_STATUS Status; VOID *ProtocolPointer; UINT32 uCodeRevision; Status = gBS->LocateProtocol (&gExitPmAuthProtocolGuid, NULL, &ProtocolPointer); if (EFI_SUCCESS != Status) { return; } gBS->CloseEvent (Event); if (mPlatformCpu->CpuConfig->FviReport) { InitFviDataHubCbContext ( mPlatformCpu->CpuConfig->FviSmbiosType, (UINT8) mCpuFviElements, &mCpuFviVersionData ); uCodeRevision = GetCpuUcodeRevision (); mCpuFviElementsData[UCODE_VER].Element.Version.MajorVersion = (UINT8) ((uCodeRevision & 0xFF000000) >> 24); mCpuFviElementsData[UCODE_VER].Element.Version.MinorVersion = (UINT8) ((uCodeRevision & 0x00FF0000) >> 16); mCpuFviElementsData[UCODE_VER].Element.Version.Revision = (UINT8) ((uCodeRevision & 0x0000FF00) >> 8); mCpuFviElementsData[UCODE_VER].Element.Version.BuildNum = (UINT16) (uCodeRevision & 0x000000FF); CreateRcFviDatahub (&mCpuFviVersionData); } return; } /** 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 @retval EFI_OUT_OF_RESOURCES - cannot allocate protocol data structure @retval 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 NewHandle1; VOID *Registration; /// /// Initialize the Global Descriptor Table /// InitializeSelectors (); /// /// Setup Cache attributes and Interrupt Tables /// PrepareMemory (); /// /// Initialize Exception Handlers /// InitializeException (&gCpu); /// /// Install CPU Architectural Protocol /// NewHandle1 = NULL; Status = gBS->InstallProtocolInterface ( &NewHandle1, &gEfiCpuArchProtocolGuid, EFI_NATIVE_INTERFACE, &gCpu ); ASSERT_EFI_ERROR (Status); /// /// Refresh memory space attributes according to MTRRs /// Status = RefreshGcdMemoryAttributes (); mIsFlushingGCD = FALSE; if (EFI_ERROR (Status)) { return Status; } /// /// Locate DxeCpuPlatformPolicy protocol instance and assign it to a global variable /// Status = gBS->LocateProtocol (&gDxeCpuPlatformPolicyProtocolGuid, NULL, (VOID **) &mPlatformCpu); if (EFI_ERROR (Status)) { DEBUG((EFI_D_ERROR,"Failed to locate DxeCpuPlatformPolicy Protocol\n")); return Status; } // // Dump Cpu platform policy // CpuDxePolicyDump(); /// /// Initialize the global SmmBase SWSMI number /// mSmmbaseSwSmiNumber = mPlatformCpu->CpuConfig->SmmbaseSwSmiNumber; /// /// Load the microcode if needed /// Status = LoadAllMicrocodeUpdates (); Status = gBS->LocateProtocol (&gEfiMetronomeArchProtocolGuid, NULL, (VOID **) &mMetronome); if (EFI_ERROR (Status)) { return Status; } #if (EFI_SPECIFICATION_VERSION >= 0x2000A) EfiLibCreateProtocolNotifyEvent ( &gEfiHiiDatabaseProtocolGuid, EFI_TPL_CALLBACK, HiiCallback, NULL, &Registration ); #else EfiLibCreateProtocolNotifyEvent ( &gEfiHiiProtocolGuid, EFI_TPL_CALLBACK, HiiCallback, NULL, &Registration ); #endif /// /// Create an SmmBase protocol call back event to initialize /// Smm Base pointer, during SMM mode /// EfiCreateProtocolNotifyEvent ( &gEfiSmmBaseProtocolGuid, TPL_CALLBACK, InitializeSmmBasePtr, NULL, &mSmmBaseRegistration ); /// /// Initialize MP Support if necessary /// Status = InitializeMpSupport (); if (EFI_ERROR(Status)) { DEBUG((EFI_D_ERROR,"Failed to initialize MPs\n")); } /// /// Create an ExitPmAuth protocol callback event to generate SMBIOS table - FviSmbiosType /// EfiCreateProtocolNotifyEvent ( &gExitPmAuthProtocolGuid, EFI_TPL_CALLBACK, InitializeFviDataCallback, NULL, &Registration ); /// /// Create an ExitPmAuth protocol callback event for PFAT. /// EfiCreateProtocolNotifyEvent ( &gExitPmAuthProtocolGuid, EFI_TPL_CALLBACK, InitializePfatToolsIntCallback, NULL, &Registration ); /// /// Verify if Boot Guard is supported /// if (IsBootGuardSupported()){ /// /// Identify if Revocation is requested by Boot Guard ACM /// if (AsmReadMsr64 (MSR_BOOT_GUARD_SACM_INFO) & BIT7) { /// /// Create an ExitPmAuth protocol call back event if one or more of Boot Guard modules are revoked. /// EfiCreateProtocolNotifyEvent ( &gExitPmAuthProtocolGuid, TPL_CALLBACK, BootGuardRevocationCallback, NULL, &Registration ); } } return EFI_SUCCESS; } /** Returns the actual CPU core frequency in MHz. @param[in] Metronome - Metronome protocol @param[in] 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; UINT64 TotalValue; UINT32 TickCount; BOOLEAN InterruptState; EFI_STATUS Status; if (Metronome == NULL || Frequency == NULL) { return EFI_INVALID_PARAMETER; } if (mCpuFrequency == 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 1000 ticks, thus the error can be control to be /// lower than 1%. /// TickCount = SAMPLE_TICK_COUNT; CpuGetInterruptState (&gCpu, &InterruptState); if (InterruptState) { DisableInterrupt (&gCpu); } /// /// In DxeCis-0.91 specs. /// Metronome->WaitForTick is possible for interrupt processing, /// or exception processing to interrupt the execution of the WaitForTick() function. /// Depending on the hardware source for the ticks, it is possible for a tick to be missed. /// This function cannot guarantee that ticks will not be missed. /// while (TRUE) { BeginValue = EfiReadTsc (); Status = Metronome->WaitForTick (Metronome, TickCount); EndValue = EfiReadTsc (); if (!EFI_ERROR (Status)) { TotalValue = EndValue - BeginValue; break; } } if (InterruptState) { EnableInterrupt (&gCpu); } mCpuFrequency = MultU64x32 (TotalValue, 10); mCpuFrequency = DivU64x32 (mCpuFrequency, Metronome->TickPeriod * TickCount); } *Frequency = mCpuFrequency; return EFI_SUCCESS; } /** Dump RC CPU and PPM platform policies **/ VOID CpuDxePolicyDump ( VOID ) { #ifdef EFI_DEBUG CPU_CONFIG *CpuConfig; POWER_MGMT_CONFIG *PowerMgmtConfig; SECURITY_CONFIG *SecurityConfig; CpuConfig = mPlatformCpu->CpuConfig; PowerMgmtConfig = mPlatformCpu->PowerMgmtConfig; SecurityConfig = mPlatformCpu->SecurityConfig; // // Dump Cpu Platform policy // DEBUG ((EFI_D_INFO, "\n------------------------ DXE CpuPlatformPolicy Dump Begin -----------------\n")); // // Cpu config // DEBUG ((EFI_D_INFO, " CPU:: HtState : 0x%X \n", CpuConfig->HtState)); DEBUG ((EFI_D_INFO, " CPU:: LimitCpuidMaximumValue : 0x%X\n", CpuConfig->LimitCpuidMaximumValue)); DEBUG ((EFI_D_INFO, " CPU:: ExecuteDisableBit : 0x%X\n", CpuConfig->ExecuteDisableBit)); DEBUG ((EFI_D_INFO, " CPU:: VmxEnable : 0x%X\n", CpuConfig->VmxEnable)); DEBUG ((EFI_D_INFO, " CPU:: SmxEnable : 0x%X\n", CpuConfig->SmxEnable)); DEBUG ((EFI_D_INFO, " CPU:: MachineCheckEnable : 0x%X\n", CpuConfig->MachineCheckEnable)); DEBUG ((EFI_D_INFO, " CPU:: MonitorMwaitEnable : 0x%X\n", CpuConfig->MonitorMwaitEnable)); DEBUG ((EFI_D_INFO, " CPU:: XapicEnable : 0x%X\n", CpuConfig->XapicEnable)); DEBUG ((EFI_D_INFO, " CPU:: IsColdReset : 0x%X\n", CpuConfig->IsColdReset)); DEBUG ((EFI_D_INFO, " CPU:: MlcStreamerPrefetcher : 0x%X\n", CpuConfig->MlcStreamerPrefetcher)); DEBUG ((EFI_D_INFO, " CPU:: EnableDts : 0x%X\n", CpuConfig->EnableDts)); DEBUG ((EFI_D_INFO, " CPU:: FviReport : 0x%X\n", CpuConfig->FviReport)); DEBUG ((EFI_D_INFO, " CPU:: AesEnable : 0x%X\n", CpuConfig->AesEnable)); DEBUG ((EFI_D_INFO, " CPU:: DebugInterfaceEnable : 0x%X\n", CpuConfig->DebugInterfaceEnable)); DEBUG ((EFI_D_INFO, " CPU:: DebugInterfaceLockEnable : 0x%X\n", CpuConfig->DebugInterfaceLockEnable)); DEBUG ((EFI_D_INFO, " CPU:: ApIdleManner : 0x%X\n", CpuConfig->ApIdleManner)); DEBUG ((EFI_D_INFO, " CPU:: ApHandoffManner : 0x%X\n", CpuConfig->ApHandoffManner)); DEBUG ((EFI_D_INFO, " CPU:: BspSelection : 0x%X\n", CpuConfig->BspSelection)); DEBUG ((EFI_D_INFO, " CPU:: SmmbaseSwSmiNumber : 0x%X\n", CpuConfig->SmmbaseSwSmiNumber)); DEBUG ((EFI_D_INFO, " CPU:: FviSmbiosType; : 0x%X\n", CpuConfig->FviSmbiosType)); // // SECURITY_CONFIG : TXT_FUNCTION_CONFIG // DEBUG ((EFI_D_INFO, " CPU:: SECURITY_CONFIG:TXT_FUNCTION_CONFIG : ResetAux : 0x%X\n", SecurityConfig->TxtFunctionConfig->ResetAux)); DEBUG ((EFI_D_INFO, "\n------------------------ DXE CpuPlatformPolicy Dump End -----------------\n")); #endif } /** Initialize the global DataHub pointer @param[in] DataHub - Pointer to the DataHub protocol as output @retval EFI_SUCCESS - If the DataHub pointer is initialized successfully **/ EFI_STATUS InitializeDataHubPtr ( OUT EFI_DATA_HUB_PROTOCOL **DataHub ) { EFI_STATUS Status; Status = gBS->LocateProtocol (&gEfiDataHubProtocolGuid, NULL, (VOID **) DataHub); return Status; } /** Drop into SMM to register IOTRAP for pfat tools interface @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 InitializePfatToolsIntCallback ( IN EFI_EVENT Event, IN VOID *Context ) { EFI_STATUS Status; VOID *ProtocolPointer; EFI_PHYSICAL_ADDRESS BaseAddress; PFAT_HOB *PfatHobPtr; EFI_GUID PfatHobGuid = PFAT_HOB_GUID; Status = gBS->LocateProtocol (&gExitPmAuthProtocolGuid, NULL, &ProtocolPointer); if (EFI_SUCCESS != Status) { return; } PfatHobPtr = GetFirstGuidHob (&PfatHobGuid); if (PfatHobPtr != NULL) { BaseAddress = (EFI_PHYSICAL_ADDRESS) PfatHobPtr->PfatToolsIntIoTrapAdd; /// /// IOTRAP TO SMM /// IoRead8 (BaseAddress); } return; } /** Register callback function for Boot Guard revocation flow. @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 EFIAPI BootGuardRevocationCallback ( IN EFI_EVENT Event, IN VOID *Context ) { EFI_STATUS Status; VOID *ProtocolPointer; // // Check whether this is real ExitPmAuth notification, or just a SignalEvent // Status = gBS->LocateProtocol (&gExitPmAuthProtocolGuid, NULL, (VOID **) &ProtocolPointer); if (EFI_ERROR (Status)) { return; } BootGuardOemRevocationHook(); // // Closed the event to avoid call twice // gBS->CloseEvent (Event); return; }