Home | History | Annotate | Download | only in SmmCpuFeaturesLib
      1 /** @file
      2 The CPU specific programming for PiSmmCpuDxeSmm module.
      3 
      4 Copyright (c) 2010 - 2015, Intel Corporation. All rights reserved.<BR>
      5 This program and the accompanying materials
      6 are licensed and made available under the terms and conditions of the BSD License
      7 which accompanies this distribution.  The full text of the license may be found at
      8 http://opensource.org/licenses/bsd-license.php
      9 
     10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
     11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
     12 
     13 **/
     14 
     15 #include <PiSmm.h>
     16 #include <Library/SmmCpuFeaturesLib.h>
     17 #include <Library/BaseLib.h>
     18 #include <Library/MtrrLib.h>
     19 #include <Library/PcdLib.h>
     20 #include <Library/MemoryAllocationLib.h>
     21 #include <Library/DebugLib.h>
     22 #include <Register/Cpuid.h>
     23 #include <Register/SmramSaveStateMap.h>
     24 
     25 //
     26 // Machine Specific Registers (MSRs)
     27 //
     28 #define  SMM_FEATURES_LIB_IA32_MTRR_CAP            0x0FE
     29 #define  SMM_FEATURES_LIB_IA32_FEATURE_CONTROL     0x03A
     30 #define  SMM_FEATURES_LIB_IA32_SMRR_PHYSBASE       0x1F2
     31 #define  SMM_FEATURES_LIB_IA32_SMRR_PHYSMASK       0x1F3
     32 #define  SMM_FEATURES_LIB_IA32_CORE_SMRR_PHYSBASE  0x0A0
     33 #define  SMM_FEATURES_LIB_IA32_CORE_SMRR_PHYSMASK  0x0A1
     34 #define    EFI_MSR_SMRR_MASK                       0xFFFFF000
     35 #define    EFI_MSR_SMRR_PHYS_MASK_VALID            BIT11
     36 #define  SMM_FEATURES_LIB_SMM_FEATURE_CONTROL      0x4E0
     37 
     38 //
     39 // MSRs required for configuration of SMM Code Access Check
     40 //
     41 #define SMM_FEATURES_LIB_IA32_MCA_CAP              0x17D
     42 #define   SMM_CODE_ACCESS_CHK_BIT                  BIT58
     43 
     44 //
     45 // Set default value to assume SMRR is not supported
     46 //
     47 BOOLEAN  mSmrrSupported = FALSE;
     48 
     49 //
     50 // Set default value to assume MSR_SMM_FEATURE_CONTROL is not supported
     51 //
     52 BOOLEAN  mSmmFeatureControlSupported = FALSE;
     53 
     54 //
     55 // Set default value to assume IA-32 Architectural MSRs are used
     56 //
     57 UINT32  mSmrrPhysBaseMsr = SMM_FEATURES_LIB_IA32_SMRR_PHYSBASE;
     58 UINT32  mSmrrPhysMaskMsr = SMM_FEATURES_LIB_IA32_SMRR_PHYSMASK;
     59 
     60 //
     61 // Set default value to assume MTRRs need to be configured on each SMI
     62 //
     63 BOOLEAN  mNeedConfigureMtrrs = TRUE;
     64 
     65 //
     66 // Array for state of SMRR enable on all CPUs
     67 //
     68 BOOLEAN  *mSmrrEnabled;
     69 
     70 /**
     71   The constructor function
     72 
     73   @param[in]  ImageHandle  The firmware allocated handle for the EFI image.
     74   @param[in]  SystemTable  A pointer to the EFI System Table.
     75 
     76   @retval EFI_SUCCESS      The constructor always returns EFI_SUCCESS.
     77 
     78 **/
     79 EFI_STATUS
     80 EFIAPI
     81 SmmCpuFeaturesLibConstructor (
     82   IN EFI_HANDLE        ImageHandle,
     83   IN EFI_SYSTEM_TABLE  *SystemTable
     84   )
     85 {
     86   UINT32  RegEax;
     87   UINT32  RegEdx;
     88   UINTN   FamilyId;
     89   UINTN   ModelId;
     90 
     91   //
     92   // Retrieve CPU Family and Model
     93   //
     94   AsmCpuid (CPUID_VERSION_INFO, &RegEax, NULL, NULL, &RegEdx);
     95   FamilyId = (RegEax >> 8) & 0xf;
     96   ModelId  = (RegEax >> 4) & 0xf;
     97   if (FamilyId == 0x06 || FamilyId == 0x0f) {
     98     ModelId = ModelId | ((RegEax >> 12) & 0xf0);
     99   }
    100 
    101   //
    102   // Check CPUID(CPUID_VERSION_INFO).EDX[12] for MTRR capability
    103   //
    104   if ((RegEdx & BIT12) != 0) {
    105     //
    106     // Check MTRR_CAP MSR bit 11 for SMRR support
    107     //
    108     if ((AsmReadMsr64 (SMM_FEATURES_LIB_IA32_MTRR_CAP) & BIT11) != 0) {
    109       mSmrrSupported = TRUE;
    110     }
    111   }
    112 
    113   //
    114   // Intel(R) 64 and IA-32 Architectures Software Developer's Manual
    115   // Volume 3C, Section 35.3 MSRs in the Intel(R) Atom(TM) Processor Family
    116   //
    117   // If CPU Family/Model is 06_1CH, 06_26H, 06_27H, 06_35H or 06_36H, then
    118   // SMRR Physical Base and SMM Physical Mask MSRs are not available.
    119   //
    120   if (FamilyId == 0x06) {
    121     if (ModelId == 0x1C || ModelId == 0x26 || ModelId == 0x27 || ModelId == 0x35 || ModelId == 0x36) {
    122       mSmrrSupported = FALSE;
    123     }
    124   }
    125 
    126   //
    127   // Intel(R) 64 and IA-32 Architectures Software Developer's Manual
    128   // Volume 3C, Section 35.2 MSRs in the Intel(R) Core(TM) 2 Processor Family
    129   //
    130   // If CPU Family/Model is 06_0F or 06_17, then use Intel(R) Core(TM) 2
    131   // Processor Family MSRs
    132   //
    133   if (FamilyId == 0x06) {
    134     if (ModelId == 0x17 || ModelId == 0x0f) {
    135       mSmrrPhysBaseMsr = SMM_FEATURES_LIB_IA32_CORE_SMRR_PHYSBASE;
    136       mSmrrPhysMaskMsr = SMM_FEATURES_LIB_IA32_CORE_SMRR_PHYSMASK;
    137     }
    138   }
    139 
    140   //
    141   // Intel(R) 64 and IA-32 Architectures Software Developer's Manual
    142   // Volume 3C, Section 34.4.2 SMRAM Caching
    143   //   An IA-32 processor does not automatically write back and invalidate its
    144   //   caches before entering SMM or before exiting SMM. Because of this behavior,
    145   //   care must be taken in the placement of the SMRAM in system memory and in
    146   //   the caching of the SMRAM to prevent cache incoherence when switching back
    147   //   and forth between SMM and protected mode operation.
    148   //
    149   // An IA-32 processor is a processor that does not support the Intel 64
    150   // Architecture.  Support for the Intel 64 Architecture can be detected from
    151   // CPUID(CPUID_EXTENDED_CPU_SIG).EDX[29]
    152   //
    153   // If an IA-32 processor is detected, then set mNeedConfigureMtrrs to TRUE,
    154   // so caches are flushed on SMI entry and SMI exit, the interrupted code
    155   // MTRRs are saved/restored, and MTRRs for SMM are loaded.
    156   //
    157   AsmCpuid (CPUID_EXTENDED_FUNCTION, &RegEax, NULL, NULL, NULL);
    158   if (RegEax >= CPUID_EXTENDED_CPU_SIG) {
    159     AsmCpuid (CPUID_EXTENDED_CPU_SIG, NULL, NULL, NULL, &RegEdx);
    160     if ((RegEdx & BIT29) != 0) {
    161       mNeedConfigureMtrrs = FALSE;
    162     }
    163   }
    164 
    165   //
    166   // Allocate array for state of SMRR enable on all CPUs
    167   //
    168   mSmrrEnabled = (BOOLEAN *)AllocatePool (sizeof (BOOLEAN) * PcdGet32 (PcdCpuMaxLogicalProcessorNumber));
    169   ASSERT (mSmrrEnabled != NULL);
    170 
    171   return EFI_SUCCESS;
    172 }
    173 
    174 /**
    175   Called during the very first SMI into System Management Mode to initialize
    176   CPU features, including SMBASE, for the currently executing CPU.  Since this
    177   is the first SMI, the SMRAM Save State Map is at the default address of
    178   SMM_DEFAULT_SMBASE + SMRAM_SAVE_STATE_MAP_OFFSET.  The currently executing
    179   CPU is specified by CpuIndex and CpuIndex can be used to access information
    180   about the currently executing CPU in the ProcessorInfo array and the
    181   HotPlugCpuData data structure.
    182 
    183   @param[in] CpuIndex        The index of the CPU to initialize.  The value
    184                              must be between 0 and the NumberOfCpus field in
    185                              the System Management System Table (SMST).
    186   @param[in] IsMonarch       TRUE if the CpuIndex is the index of the CPU that
    187                              was elected as monarch during System Management
    188                              Mode initialization.
    189                              FALSE if the CpuIndex is not the index of the CPU
    190                              that was elected as monarch during System
    191                              Management Mode initialization.
    192   @param[in] ProcessorInfo   Pointer to an array of EFI_PROCESSOR_INFORMATION
    193                              structures.  ProcessorInfo[CpuIndex] contains the
    194                              information for the currently executing CPU.
    195   @param[in] CpuHotPlugData  Pointer to the CPU_HOT_PLUG_DATA structure that
    196                              contains the ApidId and SmBase arrays.
    197 **/
    198 VOID
    199 EFIAPI
    200 SmmCpuFeaturesInitializeProcessor (
    201   IN UINTN                      CpuIndex,
    202   IN BOOLEAN                    IsMonarch,
    203   IN EFI_PROCESSOR_INFORMATION  *ProcessorInfo,
    204   IN CPU_HOT_PLUG_DATA          *CpuHotPlugData
    205   )
    206 {
    207   SMRAM_SAVE_STATE_MAP  *CpuState;
    208   UINT64                FeatureControl;
    209   UINT32                RegEax;
    210   UINT32                RegEdx;
    211   UINTN                 FamilyId;
    212   UINTN                 ModelId;
    213 
    214   //
    215   // Configure SMBASE.
    216   //
    217   CpuState = (SMRAM_SAVE_STATE_MAP *)(UINTN)(SMM_DEFAULT_SMBASE + SMRAM_SAVE_STATE_MAP_OFFSET);
    218   CpuState->x86.SMBASE = (UINT32)CpuHotPlugData->SmBase[CpuIndex];
    219 
    220   //
    221   // Intel(R) 64 and IA-32 Architectures Software Developer's Manual
    222   // Volume 3C, Section 35.2 MSRs in the Intel(R) Core(TM) 2 Processor Family
    223   //
    224   // If Intel(R) Core(TM) Core(TM) 2 Processor Family MSRs are being used, then
    225   // make sure SMRR Enable(BIT3) of MSR_FEATURE_CONTROL MSR(0x3A) is set before
    226   // accessing SMRR base/mask MSRs.  If Lock(BIT0) of MSR_FEATURE_CONTROL MSR(0x3A)
    227   // is set, then the MSR is locked and can not be modified.
    228   //
    229   if (mSmrrSupported && mSmrrPhysBaseMsr == SMM_FEATURES_LIB_IA32_CORE_SMRR_PHYSBASE) {
    230     FeatureControl = AsmReadMsr64 (SMM_FEATURES_LIB_IA32_FEATURE_CONTROL);
    231     if ((FeatureControl & BIT3) == 0) {
    232       if ((FeatureControl & BIT0) == 0) {
    233         AsmWriteMsr64 (SMM_FEATURES_LIB_IA32_FEATURE_CONTROL, FeatureControl | BIT3);
    234       } else {
    235         mSmrrSupported = FALSE;
    236       }
    237     }
    238   }
    239 
    240   //
    241   // If SMRR is supported, then program SMRR base/mask MSRs.
    242   // The EFI_MSR_SMRR_PHYS_MASK_VALID bit is not set until the first normal SMI.
    243   // The code that initializes SMM environment is running in normal mode
    244   // from SMRAM region.  If SMRR is enabled here, then the SMRAM region
    245   // is protected and the normal mode code execution will fail.
    246   //
    247   if (mSmrrSupported) {
    248     AsmWriteMsr64 (mSmrrPhysBaseMsr, CpuHotPlugData->SmrrBase | MTRR_CACHE_WRITE_BACK);
    249     AsmWriteMsr64 (mSmrrPhysMaskMsr, (~(CpuHotPlugData->SmrrSize - 1) & EFI_MSR_SMRR_MASK));
    250     mSmrrEnabled[CpuIndex] = FALSE;
    251   }
    252 
    253   //
    254   // Retrieve CPU Family and Model
    255   //
    256   AsmCpuid (CPUID_VERSION_INFO, &RegEax, NULL, NULL, &RegEdx);
    257   FamilyId = (RegEax >> 8) & 0xf;
    258   ModelId  = (RegEax >> 4) & 0xf;
    259   if (FamilyId == 0x06 || FamilyId == 0x0f) {
    260     ModelId = ModelId | ((RegEax >> 12) & 0xf0);
    261   }
    262 
    263   //
    264   // Intel(R) 64 and IA-32 Architectures Software Developer's Manual
    265   // Volume 3C, Section 35.10.1 MSRs in 4th Generation Intel(R) Core(TM)
    266   // Processor Family.
    267   //
    268   // If CPU Family/Model is 06_3C, 06_45, or 06_46 then use 4th Generation
    269   // Intel(R) Core(TM) Processor Family MSRs.
    270   //
    271   if (FamilyId == 0x06) {
    272     if (ModelId == 0x3C || ModelId == 0x45 || ModelId == 0x46) {
    273       //
    274       // Check to see if the CPU supports the SMM Code Access Check feature
    275       // Do not access this MSR unless the CPU supports the SmmRegFeatureControl
    276       //
    277       if ((AsmReadMsr64 (SMM_FEATURES_LIB_IA32_MCA_CAP) & SMM_CODE_ACCESS_CHK_BIT) != 0) {
    278         mSmmFeatureControlSupported = TRUE;
    279       }
    280     }
    281   }
    282 }
    283 
    284 /**
    285   This function updates the SMRAM save state on the currently executing CPU
    286   to resume execution at a specific address after an RSM instruction.  This
    287   function must evaluate the SMRAM save state to determine the execution mode
    288   the RSM instruction resumes and update the resume execution address with
    289   either NewInstructionPointer32 or NewInstructionPoint.  The auto HALT restart
    290   flag in the SMRAM save state must always be cleared.  This function returns
    291   the value of the instruction pointer from the SMRAM save state that was
    292   replaced.  If this function returns 0, then the SMRAM save state was not
    293   modified.
    294 
    295   This function is called during the very first SMI on each CPU after
    296   SmmCpuFeaturesInitializeProcessor() to set a flag in normal execution mode
    297   to signal that the SMBASE of each CPU has been updated before the default
    298   SMBASE address is used for the first SMI to the next CPU.
    299 
    300   @param[in] CpuIndex                 The index of the CPU to hook.  The value
    301                                       must be between 0 and the NumberOfCpus
    302                                       field in the System Management System Table
    303                                       (SMST).
    304   @param[in] CpuState                 Pointer to SMRAM Save State Map for the
    305                                       currently executing CPU.
    306   @param[in] NewInstructionPointer32  Instruction pointer to use if resuming to
    307                                       32-bit execution mode from 64-bit SMM.
    308   @param[in] NewInstructionPointer    Instruction pointer to use if resuming to
    309                                       same execution mode as SMM.
    310 
    311   @retval 0    This function did modify the SMRAM save state.
    312   @retval > 0  The original instruction pointer value from the SMRAM save state
    313                before it was replaced.
    314 **/
    315 UINT64
    316 EFIAPI
    317 SmmCpuFeaturesHookReturnFromSmm (
    318   IN UINTN                 CpuIndex,
    319   IN SMRAM_SAVE_STATE_MAP  *CpuState,
    320   IN UINT64                NewInstructionPointer32,
    321   IN UINT64                NewInstructionPointer
    322   )
    323 {
    324   return 0;
    325 }
    326 
    327 /**
    328   Hook point in normal execution mode that allows the one CPU that was elected
    329   as monarch during System Management Mode initialization to perform additional
    330   initialization actions immediately after all of the CPUs have processed their
    331   first SMI and called SmmCpuFeaturesInitializeProcessor() relocating SMBASE
    332   into a buffer in SMRAM and called SmmCpuFeaturesHookReturnFromSmm().
    333 **/
    334 VOID
    335 EFIAPI
    336 SmmCpuFeaturesSmmRelocationComplete (
    337   VOID
    338   )
    339 {
    340 }
    341 
    342 /**
    343   Return the size, in bytes, of a custom SMI Handler in bytes.  If 0 is
    344   returned, then a custom SMI handler is not provided by this library,
    345   and the default SMI handler must be used.
    346 
    347   @retval 0    Use the default SMI handler.
    348   @retval > 0  Use the SMI handler installed by SmmCpuFeaturesInstallSmiHandler()
    349                The caller is required to allocate enough SMRAM for each CPU to
    350                support the size of the custom SMI handler.
    351 **/
    352 UINTN
    353 EFIAPI
    354 SmmCpuFeaturesGetSmiHandlerSize (
    355   VOID
    356   )
    357 {
    358   return 0;
    359 }
    360 
    361 /**
    362   Install a custom SMI handler for the CPU specified by CpuIndex.  This function
    363   is only called if SmmCpuFeaturesGetSmiHandlerSize() returns a size is greater
    364   than zero and is called by the CPU that was elected as monarch during System
    365   Management Mode initialization.
    366 
    367   @param[in] CpuIndex   The index of the CPU to install the custom SMI handler.
    368                         The value must be between 0 and the NumberOfCpus field
    369                         in the System Management System Table (SMST).
    370   @param[in] SmBase     The SMBASE address for the CPU specified by CpuIndex.
    371   @param[in] SmiStack   The stack to use when an SMI is processed by the
    372                         the CPU specified by CpuIndex.
    373   @param[in] StackSize  The size, in bytes, if the stack used when an SMI is
    374                         processed by the CPU specified by CpuIndex.
    375   @param[in] GdtBase    The base address of the GDT to use when an SMI is
    376                         processed by the CPU specified by CpuIndex.
    377   @param[in] GdtSize    The size, in bytes, of the GDT used when an SMI is
    378                         processed by the CPU specified by CpuIndex.
    379   @param[in] IdtBase    The base address of the IDT to use when an SMI is
    380                         processed by the CPU specified by CpuIndex.
    381   @param[in] IdtSize    The size, in bytes, of the IDT used when an SMI is
    382                         processed by the CPU specified by CpuIndex.
    383   @param[in] Cr3        The base address of the page tables to use when an SMI
    384                         is processed by the CPU specified by CpuIndex.
    385 **/
    386 VOID
    387 EFIAPI
    388 SmmCpuFeaturesInstallSmiHandler (
    389   IN UINTN   CpuIndex,
    390   IN UINT32  SmBase,
    391   IN VOID    *SmiStack,
    392   IN UINTN   StackSize,
    393   IN UINTN   GdtBase,
    394   IN UINTN   GdtSize,
    395   IN UINTN   IdtBase,
    396   IN UINTN   IdtSize,
    397   IN UINT32  Cr3
    398   )
    399 {
    400 }
    401 
    402 /**
    403   Determines if MTRR registers must be configured to set SMRAM cache-ability
    404   when executing in System Management Mode.
    405 
    406   @retval TRUE   MTRR registers must be configured to set SMRAM cache-ability.
    407   @retval FALSE  MTRR registers do not need to be configured to set SMRAM
    408                  cache-ability.
    409 **/
    410 BOOLEAN
    411 EFIAPI
    412 SmmCpuFeaturesNeedConfigureMtrrs (
    413   VOID
    414   )
    415 {
    416   return mNeedConfigureMtrrs;
    417 }
    418 
    419 /**
    420   Disable SMRR register if SMRR is supported and SmmCpuFeaturesNeedConfigureMtrrs()
    421   returns TRUE.
    422 **/
    423 VOID
    424 EFIAPI
    425 SmmCpuFeaturesDisableSmrr (
    426   VOID
    427   )
    428 {
    429   if (mSmrrSupported && mNeedConfigureMtrrs) {
    430     AsmWriteMsr64 (mSmrrPhysMaskMsr, AsmReadMsr64(mSmrrPhysMaskMsr) & ~EFI_MSR_SMRR_PHYS_MASK_VALID);
    431   }
    432 }
    433 
    434 /**
    435   Enable SMRR register if SMRR is supported and SmmCpuFeaturesNeedConfigureMtrrs()
    436   returns TRUE.
    437 **/
    438 VOID
    439 EFIAPI
    440 SmmCpuFeaturesReenableSmrr (
    441   VOID
    442   )
    443 {
    444   if (mSmrrSupported && mNeedConfigureMtrrs) {
    445     AsmWriteMsr64 (mSmrrPhysMaskMsr, AsmReadMsr64(mSmrrPhysMaskMsr) | EFI_MSR_SMRR_PHYS_MASK_VALID);
    446   }
    447 }
    448 
    449 /**
    450   Processor specific hook point each time a CPU enters System Management Mode.
    451 
    452   @param[in] CpuIndex  The index of the CPU that has entered SMM.  The value
    453                        must be between 0 and the NumberOfCpus field in the
    454                        System Management System Table (SMST).
    455 **/
    456 VOID
    457 EFIAPI
    458 SmmCpuFeaturesRendezvousEntry (
    459   IN UINTN  CpuIndex
    460   )
    461 {
    462   //
    463   // If SMRR is supported and this is the first normal SMI, then enable SMRR
    464   //
    465   if (mSmrrSupported && !mSmrrEnabled[CpuIndex]) {
    466     AsmWriteMsr64 (mSmrrPhysMaskMsr, AsmReadMsr64 (mSmrrPhysMaskMsr) | EFI_MSR_SMRR_PHYS_MASK_VALID);
    467     mSmrrEnabled[CpuIndex] = TRUE;
    468   }
    469 }
    470 
    471 /**
    472   Processor specific hook point each time a CPU exits System Management Mode.
    473 
    474   @param[in] CpuIndex  The index of the CPU that is exiting SMM.  The value must
    475                        be between 0 and the NumberOfCpus field in the System
    476                        Management System Table (SMST).
    477 **/
    478 VOID
    479 EFIAPI
    480 SmmCpuFeaturesRendezvousExit (
    481   IN UINTN  CpuIndex
    482   )
    483 {
    484 }
    485 
    486 /**
    487   Check to see if an SMM register is supported by a specified CPU.
    488 
    489   @param[in] CpuIndex  The index of the CPU to check for SMM register support.
    490                        The value must be between 0 and the NumberOfCpus field
    491                        in the System Management System Table (SMST).
    492   @param[in] RegName   Identifies the SMM register to check for support.
    493 
    494   @retval TRUE   The SMM register specified by RegName is supported by the CPU
    495                  specified by CpuIndex.
    496   @retval FALSE  The SMM register specified by RegName is not supported by the
    497                  CPU specified by CpuIndex.
    498 **/
    499 BOOLEAN
    500 EFIAPI
    501 SmmCpuFeaturesIsSmmRegisterSupported (
    502   IN UINTN         CpuIndex,
    503   IN SMM_REG_NAME  RegName
    504   )
    505 {
    506   if (mSmmFeatureControlSupported && RegName == SmmRegFeatureControl) {
    507     return TRUE;
    508   }
    509   return FALSE;
    510 }
    511 
    512 /**
    513   Returns the current value of the SMM register for the specified CPU.
    514   If the SMM register is not supported, then 0 is returned.
    515 
    516   @param[in] CpuIndex  The index of the CPU to read the SMM register.  The
    517                        value must be between 0 and the NumberOfCpus field in
    518                        the System Management System Table (SMST).
    519   @param[in] RegName   Identifies the SMM register to read.
    520 
    521   @return  The value of the SMM register specified by RegName from the CPU
    522            specified by CpuIndex.
    523 **/
    524 UINT64
    525 EFIAPI
    526 SmmCpuFeaturesGetSmmRegister (
    527   IN UINTN         CpuIndex,
    528   IN SMM_REG_NAME  RegName
    529   )
    530 {
    531   if (mSmmFeatureControlSupported && RegName == SmmRegFeatureControl) {
    532     return AsmReadMsr64 (SMM_FEATURES_LIB_SMM_FEATURE_CONTROL);
    533   }
    534   return 0;
    535 }
    536 
    537 /**
    538   Sets the value of an SMM register on a specified CPU.
    539   If the SMM register is not supported, then no action is performed.
    540 
    541   @param[in] CpuIndex  The index of the CPU to write the SMM register.  The
    542                        value must be between 0 and the NumberOfCpus field in
    543                        the System Management System Table (SMST).
    544   @param[in] RegName   Identifies the SMM register to write.
    545                        registers are read-only.
    546   @param[in] Value     The value to write to the SMM register.
    547 **/
    548 VOID
    549 EFIAPI
    550 SmmCpuFeaturesSetSmmRegister (
    551   IN UINTN         CpuIndex,
    552   IN SMM_REG_NAME  RegName,
    553   IN UINT64        Value
    554   )
    555 {
    556   if (mSmmFeatureControlSupported && RegName == SmmRegFeatureControl) {
    557     AsmWriteMsr64 (SMM_FEATURES_LIB_SMM_FEATURE_CONTROL, Value);
    558   }
    559 }
    560 
    561 /**
    562   Read an SMM Save State register on the target processor.  If this function
    563   returns EFI_UNSUPPORTED, then the caller is responsible for reading the
    564   SMM Save Sate register.
    565 
    566   @param[in]  CpuIndex  The index of the CPU to read the SMM Save State.  The
    567                         value must be between 0 and the NumberOfCpus field in
    568                         the System Management System Table (SMST).
    569   @param[in]  Register  The SMM Save State register to read.
    570   @param[in]  Width     The number of bytes to read from the CPU save state.
    571   @param[out] Buffer    Upon return, this holds the CPU register value read
    572                         from the save state.
    573 
    574   @retval EFI_SUCCESS           The register was read from Save State.
    575   @retval EFI_INVALID_PARAMTER  Buffer is NULL.
    576   @retval EFI_UNSUPPORTED       This function does not support reading Register.
    577 
    578 **/
    579 EFI_STATUS
    580 EFIAPI
    581 SmmCpuFeaturesReadSaveStateRegister (
    582   IN  UINTN                        CpuIndex,
    583   IN  EFI_SMM_SAVE_STATE_REGISTER  Register,
    584   IN  UINTN                        Width,
    585   OUT VOID                         *Buffer
    586   )
    587 {
    588   return EFI_UNSUPPORTED;
    589 }
    590 
    591 /**
    592   Writes an SMM Save State register on the target processor.  If this function
    593   returns EFI_UNSUPPORTED, then the caller is responsible for writing the
    594   SMM Save Sate register.
    595 
    596   @param[in] CpuIndex  The index of the CPU to write the SMM Save State.  The
    597                        value must be between 0 and the NumberOfCpus field in
    598                        the System Management System Table (SMST).
    599   @param[in] Register  The SMM Save State register to write.
    600   @param[in] Width     The number of bytes to write to the CPU save state.
    601   @param[in] Buffer    Upon entry, this holds the new CPU register value.
    602 
    603   @retval EFI_SUCCESS           The register was written to Save State.
    604   @retval EFI_INVALID_PARAMTER  Buffer is NULL.
    605   @retval EFI_UNSUPPORTED       This function does not support writing Register.
    606 **/
    607 EFI_STATUS
    608 EFIAPI
    609 SmmCpuFeaturesWriteSaveStateRegister (
    610   IN UINTN                        CpuIndex,
    611   IN EFI_SMM_SAVE_STATE_REGISTER  Register,
    612   IN UINTN                        Width,
    613   IN CONST VOID                   *Buffer
    614   )
    615 {
    616   return EFI_UNSUPPORTED;
    617 }
    618 
    619 /**
    620   This function is hook point called after the gEfiSmmReadyToLockProtocolGuid
    621   notification is completely processed.
    622 **/
    623 VOID
    624 EFIAPI
    625 SmmCpuFeaturesCompleteSmmReadyToLock (
    626   VOID
    627   )
    628 {
    629 }
    630 
    631 /**
    632   This API provides a method for a CPU to allocate a specific region for storing page tables.
    633 
    634   This API can be called more once to allocate memory for page tables.
    635 
    636   Allocates the number of 4KB pages of type EfiRuntimeServicesData and returns a pointer to the
    637   allocated buffer.  The buffer returned is aligned on a 4KB boundary.  If Pages is 0, then NULL
    638   is returned.  If there is not enough memory remaining to satisfy the request, then NULL is
    639   returned.
    640 
    641   This function can also return NULL if there is no preference on where the page tables are allocated in SMRAM.
    642 
    643   @param  Pages                 The number of 4 KB pages to allocate.
    644 
    645   @return A pointer to the allocated buffer for page tables.
    646   @retval NULL      Fail to allocate a specific region for storing page tables,
    647                     Or there is no preference on where the page tables are allocated in SMRAM.
    648 
    649 **/
    650 VOID *
    651 EFIAPI
    652 SmmCpuFeaturesAllocatePageTableMemory (
    653   IN UINTN           Pages
    654   )
    655 {
    656   return NULL;
    657 }
    658 
    659