670 lines
19 KiB
C
670 lines
19 KiB
C
/** @file
|
|
CPU Common Lib implementation.
|
|
|
|
@copyright
|
|
INTEL CONFIDENTIAL
|
|
Copyright 2014 - 2021 Intel Corporation.
|
|
|
|
The source code contained or described herein and all documents related to the
|
|
source code ("Material") are owned by Intel Corporation or its suppliers or
|
|
licensors. Title to the Material remains with Intel Corporation or its suppliers
|
|
and licensors. The Material may contain trade secrets and proprietary and
|
|
confidential information of Intel Corporation and its suppliers and licensors,
|
|
and is protected by worldwide copyright and trade secret laws and treaty
|
|
provisions. No part of the Material may be used, copied, reproduced, modified,
|
|
published, uploaded, posted, transmitted, distributed, or disclosed in any way
|
|
without Intel's prior express written permission.
|
|
|
|
No license under any patent, copyright, trade secret or other intellectual
|
|
property right is granted to or conferred upon you by disclosure or delivery
|
|
of the Materials, either expressly, by implication, inducement, estoppel or
|
|
otherwise. Any license under such intellectual property rights must be
|
|
express and approved by Intel in writing.
|
|
|
|
Unless otherwise agreed by Intel in writing, you may not remove or alter
|
|
this notice or any other notice embedded in Materials by Intel or
|
|
Intel's suppliers or licensors in any way.
|
|
|
|
This file contains an 'Intel Peripheral Driver' and is 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.
|
|
|
|
@par Specification Reference:
|
|
**/
|
|
#include <Uefi.h>
|
|
#include <Library/BaseLib.h>
|
|
#include <Library/CpuLib.h>
|
|
#include <Library/DebugLib.h>
|
|
#include <Library/IoLib.h>
|
|
#include <Library/PcdLib.h>
|
|
#include <Library/BaseMemoryLib.h>
|
|
#include <Library/TimerLib.h>
|
|
#include <Library/CpuPlatformLib.h>
|
|
#include <Library/CpuMailboxLib.h>
|
|
#include <Library/BootGuardLibVer1.h>
|
|
#include <Register/Cpuid.h>
|
|
#include <Register/Msr.h>
|
|
#include <Register/LocalApic.h>
|
|
#include <Library/CpuCommonLib.h>
|
|
#include <Register/CommonMsr.h>
|
|
#include <Library/CpuInfoFruLib.h>
|
|
#include <CpuRegs.h>
|
|
|
|
#define INTERRUPT_VECTOR_NUMBER 256
|
|
|
|
///
|
|
/// Table to convert Seconds into equivalent MSR values
|
|
/// This table is used for PL1, Pl2 and RATL TDP Time Window programming
|
|
///
|
|
GLOBAL_REMOVE_IF_UNREFERENCED UINT16 mSecondsToMsrValueMapTable[][2] = {
|
|
///
|
|
/// Seconds, MSR Value
|
|
///
|
|
{ 1, 0x0A },
|
|
{ 2, 0x0B },
|
|
{ 3, 0x4B },
|
|
{ 4, 0x0C },
|
|
{ 5, 0x2C },
|
|
{ 6, 0x4C },
|
|
{ 7, 0x6C },
|
|
{ 8, 0x0D },
|
|
{ 10, 0x2D },
|
|
{ 12, 0x4D },
|
|
{ 14, 0x6D },
|
|
{ 16, 0x0E },
|
|
{ 20, 0x2E },
|
|
{ 24, 0x4E },
|
|
{ 28, 0x6E },
|
|
{ 32, 0x0F },
|
|
{ 40, 0x2F },
|
|
{ 48, 0x4F },
|
|
{ 56, 0x6F },
|
|
{ 64, 0x10 },
|
|
{ 80, 0x30 },
|
|
{ 96, 0x50 },
|
|
{ 112, 0x70 },
|
|
{ 128, 0x11 },
|
|
{ 160, 0x31 },
|
|
{ 192, 0x51 },
|
|
{ 224, 0x71 },
|
|
{ 256, 0x12 },
|
|
{ 320, 0x32 },
|
|
{ 384, 0x52 },
|
|
{ 448, 0x72 },
|
|
{ END_OF_TIMETABLE, END_OF_TIMETABLE }
|
|
};
|
|
|
|
///
|
|
/// Table to convert Milli Seconds into equivalent MSR values
|
|
/// This table is used for Pl3 and RATL TDP Time Window programming
|
|
///
|
|
GLOBAL_REMOVE_IF_UNREFERENCED UINT16 mMilliSecondsToMsrValueMapTable[][2] = {
|
|
///
|
|
/// MilliSeconds, MSR Value
|
|
///
|
|
{ 3, 0x41 },
|
|
{ 4, 0x02 },
|
|
{ 5, 0x22 },
|
|
{ 6, 0x42 },
|
|
{ 7, 0x62 },
|
|
{ 8, 0x03 },
|
|
{ 10, 0x23 },
|
|
{ 12, 0x43 },
|
|
{ 14, 0x63 },
|
|
{ 16, 0x04 },
|
|
{ 20, 0x24 },
|
|
{ 24, 0x44 },
|
|
{ 28, 0x64 },
|
|
{ 32, 0x05 },
|
|
{ 40, 0x25 },
|
|
{ 48, 0x45 },
|
|
{ 55, 0x65 },
|
|
{ 56, 0x65 },
|
|
{ 64, 0x06 },
|
|
{ 156, 0x27 },
|
|
{ 375, 0x48 },
|
|
{ 500, 0x09 },
|
|
{ 750, 0x49 },
|
|
{ END_OF_TIMETABLE, END_OF_TIMETABLE }
|
|
};
|
|
|
|
/**
|
|
Set up flags in CR4 for XMM instruction enabling
|
|
**/
|
|
VOID
|
|
EFIAPI
|
|
XmmInit (
|
|
VOID
|
|
)
|
|
{
|
|
CPUID_VERSION_INFO_EDX CpuidVersionInfoEdx;
|
|
UINTN Cr0;
|
|
UINTN Cr4;
|
|
|
|
///
|
|
/// Read the CPUID information
|
|
///
|
|
AsmCpuid (CPUID_VERSION_INFO, NULL, NULL, NULL, &CpuidVersionInfoEdx.Uint32);
|
|
|
|
///
|
|
/// Check whether SSE2 is supported
|
|
///
|
|
if (CpuidVersionInfoEdx.Bits.SSE2 == 1) {
|
|
///
|
|
/// Enable XMM
|
|
///
|
|
Cr0 = AsmReadCr0 ();
|
|
Cr0 |= BIT1;
|
|
AsmWriteCr0 (Cr0);
|
|
|
|
Cr4 = AsmReadCr4 ();
|
|
Cr4 |= (UINTN) (BIT9 | BIT10);
|
|
AsmWriteCr4 (Cr4);
|
|
}
|
|
}
|
|
|
|
/**
|
|
Private helper function to convert various Turbo Power Limit Time from Seconds to CPU units
|
|
|
|
@param[in] TimeInSeconds Time in seconds
|
|
@param[in] TimeWindowConvType Time Window Convert Type
|
|
|
|
@retval UINT8 Converted time in CPU units
|
|
**/
|
|
UINT8
|
|
GetConvertedTime (
|
|
IN UINT32 TimeInSeconds,
|
|
IN TIME_WINDOW_CONV TimeWindowConvType
|
|
)
|
|
{
|
|
UINT8 ConvertedPowerLimitTime;
|
|
UINT8 Index;
|
|
|
|
///
|
|
/// Convert seconds to MSR value. Since not all values are programmable, we'll select
|
|
/// the entry from mapping table which is either equal to the user selected value. OR to a value in the mapping table
|
|
/// which is closest (but less than) to the user-selected value.
|
|
///
|
|
ConvertedPowerLimitTime = 0;
|
|
switch (TimeWindowConvType) {
|
|
case SecondsTimeWindowConvert:
|
|
ConvertedPowerLimitTime = (UINT8) mSecondsToMsrValueMapTable[0][1];
|
|
for (Index = 0; mSecondsToMsrValueMapTable[Index][0] != END_OF_TIMETABLE; Index++) {
|
|
if (TimeInSeconds == mSecondsToMsrValueMapTable[Index][0]) {
|
|
ConvertedPowerLimitTime = (UINT8) mSecondsToMsrValueMapTable[Index][1];
|
|
break;
|
|
}
|
|
if (TimeInSeconds > mSecondsToMsrValueMapTable[Index][0]) {
|
|
ConvertedPowerLimitTime = (UINT8) mSecondsToMsrValueMapTable[Index][1];
|
|
} else {
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
case MilliSecondsTimeWindowConvert:
|
|
ConvertedPowerLimitTime = (UINT8) mMilliSecondsToMsrValueMapTable[0][1];
|
|
for (Index = 0; mMilliSecondsToMsrValueMapTable[Index][0] != END_OF_TIMETABLE; Index++) {
|
|
if (TimeInSeconds == mMilliSecondsToMsrValueMapTable[Index][0]) {
|
|
ConvertedPowerLimitTime = (UINT8) mMilliSecondsToMsrValueMapTable[Index][1];
|
|
break;
|
|
}
|
|
if (TimeInSeconds > mMilliSecondsToMsrValueMapTable[Index][0]) {
|
|
ConvertedPowerLimitTime = (UINT8) mMilliSecondsToMsrValueMapTable[Index][1];
|
|
} else {
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return ConvertedPowerLimitTime;
|
|
}
|
|
|
|
/**
|
|
Get APIC ID of processor
|
|
|
|
@retval APIC ID of processor
|
|
**/
|
|
UINT32
|
|
GetCpuApicId (
|
|
VOID
|
|
)
|
|
{
|
|
CPUID_VERSION_INFO_EBX CpuidVersionInfoEbx;
|
|
|
|
AsmCpuid (
|
|
CPUID_VERSION_INFO,
|
|
NULL,
|
|
&CpuidVersionInfoEbx.Uint32,
|
|
NULL,
|
|
NULL
|
|
);
|
|
return (UINT32) (CpuidVersionInfoEbx.Bits.InitialLocalApicId);
|
|
}
|
|
|
|
/**
|
|
Programs XAPIC registers.
|
|
|
|
@param[in] Bsp - Is this BSP?
|
|
**/
|
|
VOID
|
|
ProgramXApic (
|
|
BOOLEAN Bsp
|
|
)
|
|
{
|
|
UINT64 ApicBaseReg;
|
|
EFI_PHYSICAL_ADDRESS ApicBase;
|
|
volatile UINT32 *EntryAddress;
|
|
UINT32 EntryValue;
|
|
|
|
ApicBaseReg = AsmReadMsr64 (MSR_IA32_APIC_BASE);
|
|
ApicBase = ApicBaseReg & 0xffffff000ULL;
|
|
|
|
///
|
|
/// Program the spurious vector entry
|
|
///
|
|
EntryAddress = (UINT32 *) (UINTN) (ApicBase + XAPIC_SPURIOUS_VECTOR_OFFSET);
|
|
EntryValue = *EntryAddress;
|
|
EntryValue &= 0xFFFFFD0F;
|
|
EntryValue |= 0x10F;
|
|
*EntryAddress = EntryValue;
|
|
|
|
///
|
|
/// Program the LINT1 vector entry as extINT
|
|
///
|
|
EntryAddress = (UINT32 *) (UINTN) (ApicBase + XAPIC_LVT_LINT0_OFFSET);
|
|
EntryValue = *EntryAddress;
|
|
|
|
if (Bsp) {
|
|
EntryValue &= 0xFFFE00FF;
|
|
EntryValue |= 0x700;
|
|
} else {
|
|
EntryValue |= 0x10000;
|
|
}
|
|
|
|
*EntryAddress = EntryValue;
|
|
|
|
///
|
|
/// Program the LINT1 vector entry as NMI
|
|
///
|
|
EntryAddress = (UINT32 *) (UINTN) (ApicBase + XAPIC_LVT_LINT1_OFFSET);
|
|
EntryValue = *EntryAddress;
|
|
EntryValue &= 0xFFFE00FF;
|
|
if (Bsp) {
|
|
EntryValue |= 0x400;
|
|
} else {
|
|
EntryValue |= 0x10400;
|
|
}
|
|
|
|
*EntryAddress = EntryValue;
|
|
}
|
|
|
|
/**
|
|
This function returns the maximum number of cores supported in this physical processor package
|
|
by leverging CPUID_CACHE_PARAMS with offset 26.
|
|
|
|
@retval Maximum number of supported cores in the package.
|
|
**/
|
|
UINT8
|
|
EFIAPI
|
|
GetMaxSupportedCoreCount (
|
|
VOID
|
|
)
|
|
{
|
|
CPUID_CACHE_PARAMS_EAX CpuidCacheParamsEax;
|
|
|
|
AsmCpuidEx (
|
|
CPUID_CACHE_PARAMS,
|
|
0,
|
|
&CpuidCacheParamsEax.Uint32,
|
|
NULL,
|
|
NULL,
|
|
NULL
|
|
);
|
|
|
|
return (UINT8) (CpuidCacheParamsEax.Bits.MaximumAddressableIdsForProcessorCores) + 1;
|
|
}
|
|
|
|
/**
|
|
This function returns the supported number of threads per core,
|
|
and supported total threads in the physical processor package
|
|
by leverging CPUID_EXTENDED_TOPOLOGY with index 1 & 2.
|
|
|
|
@param[out] *ThreadsPerCore - variable that will store Maximum enabled threads per core.
|
|
@param[out] *Threads - variable that will store supported total threads.
|
|
**/
|
|
VOID
|
|
EFIAPI
|
|
GetSupportedThreadCount (
|
|
OUT UINT8 *ThreadsPerCore, OPTIONAL
|
|
OUT UINT8 *Threads OPTIONAL
|
|
)
|
|
{
|
|
CPUID_EXTENDED_TOPOLOGY_EBX CpuidExtendedTopologyEbx;
|
|
|
|
AsmCpuidEx (CPUID_EXTENDED_TOPOLOGY, 0, NULL, &CpuidExtendedTopologyEbx.Uint32, NULL, NULL);
|
|
|
|
if (ThreadsPerCore != NULL) {
|
|
*ThreadsPerCore = (UINT8) CpuidExtendedTopologyEbx.Uint32;
|
|
}
|
|
|
|
if (Threads != NULL) {
|
|
AsmCpuidEx (CPUID_EXTENDED_TOPOLOGY, 1, NULL, &CpuidExtendedTopologyEbx.Uint32, NULL, NULL);
|
|
*Threads = (UINT8) CpuidExtendedTopologyEbx.Uint32;
|
|
}
|
|
}
|
|
|
|
/**
|
|
This function returns the enabled Cores and Threads
|
|
by leverging MSR_CORE_THREAD_COUNT.
|
|
|
|
@param[out] *CoreCount - variable that will store enabled cores.
|
|
@param[out] *ThreadCount - variable that will store enabled threads.
|
|
**/
|
|
VOID
|
|
EFIAPI
|
|
GetEnabledCoreThreadCount (
|
|
OUT UINT8 *CoreCount, OPTIONAL
|
|
OUT UINT8 *ThreadCount OPTIONAL
|
|
)
|
|
{
|
|
MSR_CORE_THREAD_COUNT_REGISTER MsrCoreThreadCount;
|
|
///
|
|
/// Read MSR_CORE_THREAD_COUNT (0x35)
|
|
///
|
|
MsrCoreThreadCount.Uint64 = AsmReadMsr64 (MSR_CORE_THREAD_COUNT);
|
|
if (CoreCount != NULL) {
|
|
*CoreCount = (UINT8) MsrCoreThreadCount.Bits.Corecount;
|
|
}
|
|
|
|
if (ThreadCount != NULL) {
|
|
*ThreadCount = (UINT8) MsrCoreThreadCount.Bits.Threadcount;
|
|
}
|
|
}
|
|
|
|
/**
|
|
This function returns the maximum number of dies and packages.
|
|
Currently, the number of dies and packages will be one for client.
|
|
|
|
@param[out] *NumberOfDiesPerPackage - variable that will store Maximum dies per package
|
|
@param[out] *NumberOfPackages - variable that will store Maximum Packages
|
|
**/
|
|
VOID
|
|
EFIAPI
|
|
CpuGetNumberofDiesAndPackages (
|
|
OUT UINT16 *NumberOfDiesPerPackage, OPTIONAL
|
|
OUT UINT16 *NumberOfPackages OPTIONAL
|
|
)
|
|
{
|
|
///
|
|
/// For client, the number of dies and packages will be one
|
|
///
|
|
if (NumberOfDiesPerPackage != NULL) {
|
|
*NumberOfDiesPerPackage = 1;
|
|
}
|
|
|
|
if (NumberOfPackages != NULL) {
|
|
*NumberOfPackages = 1;
|
|
}
|
|
}
|
|
|
|
/**
|
|
Check to see if the executing thread is BSP
|
|
|
|
@retval TRUE Executing thread is BSP
|
|
@retval FALSE Executing thread is AP
|
|
**/
|
|
BOOLEAN
|
|
IsBsp (
|
|
VOID
|
|
)
|
|
{
|
|
MSR_IA32_APIC_BASE_REGISTER Msr;
|
|
|
|
Msr.Uint64 = AsmReadMsr64 (MSR_IA32_APIC_BASE);
|
|
return (BOOLEAN) (Msr.Bits.BSP == 1);
|
|
}
|
|
|
|
/**
|
|
Stop PBE timer if system is in Boot Guard boot
|
|
|
|
@retval EFI_SUCCESS - Stop PBE timer
|
|
@retval EFI_UNSUPPORTED - Not in Boot Guard boot mode.
|
|
**/
|
|
EFI_STATUS
|
|
StopPbeTimer (
|
|
VOID
|
|
)
|
|
{
|
|
UINT64 BootGuardBootStatus;
|
|
UINT64 BootGuardOperationMode;
|
|
MSR_ANC_INITIAL_BOOT_BLOCK_COMPLETE_REGISTER MsrAncInitialBootBlockComplete;
|
|
|
|
if (IsBootGuardSupported ()) {
|
|
BootGuardBootStatus = (*(UINT64 *) (UINTN) (TXT_PUBLIC_BASE + R_CPU_BOOT_GUARD_BOOTSTATUS) & (BIT63|BIT62));
|
|
BootGuardOperationMode = AsmReadMsr64 (MSR_BOOT_GUARD_SACM_INFO) & (B_BOOT_GUARD_SACM_INFO_MEASURED_BOOT | B_BOOT_GUARD_SACM_INFO_VERIFIED_BOOT);
|
|
|
|
//
|
|
// Stop PBET if Verified/Measured/NEM bit is set in MSR 0x13A or
|
|
// Boot Guard fails to launch or fails to execute successfully for avoiding brick platform
|
|
//
|
|
|
|
if (BootGuardBootStatus == V_CPU_BOOT_GUARD_LOAD_ACM_SUCCESS) {
|
|
if (BootGuardOperationMode == 0) {
|
|
DEBUG ((DEBUG_INFO, "Platform is in Legacy boot mode.\n"));
|
|
return EFI_UNSUPPORTED;
|
|
} else {
|
|
DEBUG ((DEBUG_INFO, "Platform in Boot Guard Boot mode.\n"));
|
|
}
|
|
} else {
|
|
DEBUG ((DEBUG_ERROR, "Boot Guard ACM launch failed or ACM execution failed.\n"));
|
|
}
|
|
|
|
DEBUG ((DEBUG_INFO, "Disable PBET\n"));
|
|
MsrAncInitialBootBlockComplete.Uint64 = 0;
|
|
MsrAncInitialBootBlockComplete.Bits.Done = 1;
|
|
AsmWriteMsr64 (MSR_ANC_INITIAL_BOOT_BLOCK_COMPLETE, MsrAncInitialBootBlockComplete.Uint64);
|
|
} else {
|
|
DEBUG ((DEBUG_WARN, "Boot Guard is not supported.\n"));
|
|
return EFI_UNSUPPORTED;
|
|
}
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
Return if C6DRAM is Enabled.
|
|
|
|
@retval TRUE - C6DRAM is enabled.
|
|
@retval FALSE - C6DRAM is disabled.
|
|
**/
|
|
BOOLEAN
|
|
GetC6DramStatus (
|
|
VOID
|
|
)
|
|
{
|
|
UINT32 MailboxStatus;
|
|
UINT32 MailboxData;
|
|
EFI_STATUS Status;
|
|
PCODE_MAILBOX_INTERFACE MailboxCommand;
|
|
|
|
///
|
|
/// If C6DRAM is enabled, PCODE mailbox returns mailbox data bit 0 = 1.
|
|
///
|
|
MailboxCommand.InterfaceData = 0;
|
|
MailboxCommand.Fields.Command = MAILBOX_PCODE_CMD_READ_C6DRAM_CONFIG;
|
|
Status = MailboxRead (MAILBOX_TYPE_PCODE, MailboxCommand.InterfaceData, &MailboxData, &MailboxStatus);
|
|
if (Status != EFI_SUCCESS || MailboxStatus != EFI_SUCCESS) {
|
|
DEBUG ((DEBUG_ERROR, "Mailbox write command failed unexpectedly, C6DRAM is not supported. MailboxStatus = %x, Mailbox command return status %r \n", MailboxStatus, Status));
|
|
return FALSE;
|
|
}
|
|
|
|
return (MailboxData & B_MAILBOX_BIOS_ALLOW_C6DRAM) == B_MAILBOX_BIOS_ALLOW_C6DRAM;
|
|
}
|
|
|
|
/**
|
|
Set C6DRAM Enable/Disable and return if enabled or not.
|
|
|
|
@param[in] C6DramStateRequest - Policy setting of C6DRAM
|
|
|
|
@retval TRUE - C6DRAM is enabled.
|
|
@retval FALSE - C6DRAM is disabled.
|
|
**/
|
|
BOOLEAN
|
|
SetC6Dram (
|
|
UINT32 C6DramStateRequest
|
|
)
|
|
{
|
|
UINT32 MailboxStatus;
|
|
UINT32 MailboxData;
|
|
EFI_STATUS Status;
|
|
PCODE_MAILBOX_INTERFACE MailboxCommand;
|
|
|
|
MailboxData = 0x0;
|
|
|
|
//
|
|
// Returning Heuristics Policy Data for C6DRAM.
|
|
//
|
|
if (C6DramStateRequest) {
|
|
MailboxData = B_MAILBOX_BIOS_ALLOW_C6DRAM;
|
|
}
|
|
|
|
MailboxCommand.InterfaceData = 0;
|
|
MailboxCommand.Fields.Command = MAILBOX_PCODE_CMD_WRITE_C6DRAM_CONFIG;
|
|
Status = MailboxWrite (MAILBOX_TYPE_PCODE, MailboxCommand.InterfaceData, MailboxData, &MailboxStatus);
|
|
if (Status != EFI_SUCCESS || MailboxStatus != EFI_SUCCESS) {
|
|
DEBUG ((DEBUG_ERROR, "Mailbox write command failed, C6DRAM is not supported. MailboxStatus = %x, Mailbox command return status %x \n", MailboxStatus, Status));
|
|
return FALSE;
|
|
}
|
|
|
|
return GetC6DramStatus ();
|
|
}
|
|
|
|
/**
|
|
Check on the processor if PRMRR is supported.
|
|
|
|
@param[in] IsBspInt Check to see if the executing thread is BSP.
|
|
|
|
@retval TRUE if PRMRR supported
|
|
@retval FALSE if PRMRR is not supported
|
|
**/
|
|
BOOLEAN
|
|
IsPrmrrSupported (
|
|
BOOLEAN IsBspInt
|
|
)
|
|
{
|
|
///
|
|
/// PRMRR configuration enabled, MSR IA32_MTRRCAP (FEh) [12] == 1
|
|
///
|
|
if ((AsmReadMsr64 (MSR_IA32_MTRRCAP) & BIT12) != 0) {
|
|
return TRUE;
|
|
}
|
|
//
|
|
// Continue patch load without PRMRR initialization.
|
|
//
|
|
if (IsBspInt) {
|
|
DEBUG ((DEBUG_INFO, "PRMRR configuration not supported.\n"));
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
/**
|
|
Set the PRMRR MSRs.
|
|
|
|
@param PrmrrBase PRMRR base address
|
|
@param PrmrrSize PRMRR size
|
|
|
|
@retval RETURN_SUCCESS PRMRR MSRs are set successfully.
|
|
@retval RETURN_UNSUPPORTED PRMRR is not supported.
|
|
@retval RETURN_ACCESS_DENIED PRMRR MSRs are already locked and cannot be changed.
|
|
*/
|
|
RETURN_STATUS
|
|
SetPrmrrMsr (
|
|
UINT64 PrmrrBase,
|
|
UINT32 PrmrrSize
|
|
)
|
|
{
|
|
UINT64 ValidPrmrrBitsMask;
|
|
UINT64 PrmrrMask;
|
|
UINT32 MaxExtendedFunction;
|
|
CPUID_VIR_PHY_ADDRESS_SIZE_EAX VirPhyAddressSize;
|
|
MSR_PRMRR_MASK_REGISTER MsrPrmrrMask;
|
|
MSR_PRMRR_BASE_0_REGISTER MsrPrmrrBase0;
|
|
|
|
if (!IsPrmrrSupported (TRUE)) {
|
|
return RETURN_UNSUPPORTED;
|
|
}
|
|
|
|
MsrPrmrrMask.Uint64 = AsmReadMsr64 (MSR_PRMRR_MASK);
|
|
ASSERT (MsrPrmrrMask.Bits.L == 0);
|
|
if (MsrPrmrrMask.Bits.L != 0) {
|
|
DEBUG ((DEBUG_ERROR, "PRMRR region is already locked and cannot be changed!\n"));
|
|
return RETURN_ACCESS_DENIED;
|
|
}
|
|
|
|
//
|
|
// If PRMRR size is 0, only need to set bit lock on MSR 0x1f5
|
|
//
|
|
if (PrmrrSize == 0) {
|
|
//
|
|
// Need to lock mask MSRs even if PRMRR size is zero
|
|
//
|
|
DEBUG ((DEBUG_INFO, "PRMRR size is zero, only Locking PRMRR MASK MSR\n"));
|
|
MsrPrmrrMask.Bits.L = 1;
|
|
AsmWriteMsr64 (MSR_PRMRR_MASK, MsrPrmrrMask.Uint64);
|
|
} else {
|
|
|
|
VirPhyAddressSize.Bits.PhysicalAddressBits = 36;
|
|
//
|
|
// Check whether CPU supports to return max physical address size
|
|
//
|
|
AsmCpuid (CPUID_EXTENDED_FUNCTION, &MaxExtendedFunction, NULL, NULL, NULL);
|
|
if (MaxExtendedFunction >= CPUID_VIR_PHY_ADDRESS_SIZE) {
|
|
//
|
|
// PRMRR Mask should always use the Physical Address bits returned from SoC Capabilities - CPUID.80000008H:EAX
|
|
//
|
|
AsmCpuid (CPUID_VIR_PHY_ADDRESS_SIZE, &VirPhyAddressSize.Uint32, NULL, NULL, NULL);
|
|
}
|
|
|
|
ValidPrmrrBitsMask = (LShiftU64 (1, VirPhyAddressSize.Bits.PhysicalAddressBits) - 1) & 0xfffffffffffff000;
|
|
PrmrrMask = ValidPrmrrBitsMask & (~((UINT64) (PrmrrSize - 1)));
|
|
//
|
|
// Set the PRMRR Base MSR with base, memory type, and configured status.Set PRMRR Mask MSR with the mask and lock bit.
|
|
// The valid bit on PRMRR Mask MSR will be set later by the microcode.
|
|
//
|
|
MsrPrmrrBase0.Uint64 = PrmrrBase;
|
|
MsrPrmrrBase0.Bits.Memtype = CACHE_WRITEBACK;
|
|
MsrPrmrrBase0.Bits.Configured = 1;
|
|
AsmWriteMsr64 (GetPrmrrBaseMsrAddress (), MsrPrmrrBase0.Uint64);
|
|
MsrPrmrrMask.Uint64 = PrmrrMask;
|
|
MsrPrmrrMask.Bits.L = 1;
|
|
AsmWriteMsr64 (MSR_PRMRR_MASK, MsrPrmrrMask.Uint64);
|
|
}
|
|
return RETURN_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
This function is to check if CPU support XSAVE or not.
|
|
@param[in]
|
|
|
|
@retval TRUE XSAVE is supported.
|
|
@retval FALSE XSAVE is unsupported.
|
|
**/
|
|
BOOLEAN
|
|
IsCpuSupportXsave (
|
|
VOID
|
|
)
|
|
{
|
|
CPUID_VERSION_INFO_ECX Ecx;
|
|
|
|
AsmCpuid (CPUID_VERSION_INFO, NULL, NULL, &Ecx.Uint32, NULL);
|
|
|
|
///
|
|
/// Check if cpu supported XSAVE.
|
|
///
|
|
return (BOOLEAN) (Ecx.Bits.XSAVE == 1);
|
|
}
|