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
SmmCpuFeaturesLibConstructor(IN EFI_HANDLE ImageHandle,IN EFI_SYSTEM_TABLE * SystemTable)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
SmmCpuFeaturesInitializeProcessor(IN UINTN CpuIndex,IN BOOLEAN IsMonarch,IN EFI_PROCESSOR_INFORMATION * ProcessorInfo,IN CPU_HOT_PLUG_DATA * CpuHotPlugData)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
SmmCpuFeaturesHookReturnFromSmm(IN UINTN CpuIndex,IN SMRAM_SAVE_STATE_MAP * CpuState,IN UINT64 NewInstructionPointer32,IN UINT64 NewInstructionPointer)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
SmmCpuFeaturesSmmRelocationComplete(VOID)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
SmmCpuFeaturesGetSmiHandlerSize(VOID)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
SmmCpuFeaturesInstallSmiHandler(IN UINTN CpuIndex,IN UINT32 SmBase,IN VOID * SmiStack,IN UINTN StackSize,IN UINTN GdtBase,IN UINTN GdtSize,IN UINTN IdtBase,IN UINTN IdtSize,IN UINT32 Cr3)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
SmmCpuFeaturesNeedConfigureMtrrs(VOID)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
SmmCpuFeaturesDisableSmrr(VOID)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
SmmCpuFeaturesReenableSmrr(VOID)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
SmmCpuFeaturesRendezvousEntry(IN UINTN CpuIndex)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
SmmCpuFeaturesRendezvousExit(IN UINTN CpuIndex)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
SmmCpuFeaturesIsSmmRegisterSupported(IN UINTN CpuIndex,IN SMM_REG_NAME RegName)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
SmmCpuFeaturesGetSmmRegister(IN UINTN CpuIndex,IN SMM_REG_NAME RegName)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
SmmCpuFeaturesSetSmmRegister(IN UINTN CpuIndex,IN SMM_REG_NAME RegName,IN UINT64 Value)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
SmmCpuFeaturesReadSaveStateRegister(IN UINTN CpuIndex,IN EFI_SMM_SAVE_STATE_REGISTER Register,IN UINTN Width,OUT VOID * Buffer)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
SmmCpuFeaturesWriteSaveStateRegister(IN UINTN CpuIndex,IN EFI_SMM_SAVE_STATE_REGISTER Register,IN UINTN Width,IN CONST VOID * Buffer)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
SmmCpuFeaturesCompleteSmmReadyToLock(VOID)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
SmmCpuFeaturesAllocatePageTableMemory(IN UINTN Pages)652 SmmCpuFeaturesAllocatePageTableMemory (
653   IN UINTN           Pages
654   )
655 {
656   return NULL;
657 }
658 
659