2 Implementation shared across all library instances.
4 Copyright (c) 2010 - 2019, Intel Corporation. All rights reserved.<BR>
5 Copyright (c) Microsoft Corporation.<BR>
6 SPDX-License-Identifier: BSD-2-Clause-Patent
11 #include <Library/SmmCpuFeaturesLib.h>
12 #include <Library/BaseLib.h>
13 #include <Library/MtrrLib.h>
14 #include <Library/PcdLib.h>
15 #include <Library/MemoryAllocationLib.h>
16 #include <Library/DebugLib.h>
17 #include <Register/Intel/Cpuid.h>
18 #include <Register/Intel/SmramSaveStateMap.h>
19 #include "CpuFeaturesLib.h"
22 // Machine Specific Registers (MSRs)
24 #define SMM_FEATURES_LIB_IA32_MTRR_CAP 0x0FE
25 #define SMM_FEATURES_LIB_IA32_FEATURE_CONTROL 0x03A
26 #define SMM_FEATURES_LIB_IA32_SMRR_PHYSBASE 0x1F2
27 #define SMM_FEATURES_LIB_IA32_SMRR_PHYSMASK 0x1F3
28 #define SMM_FEATURES_LIB_IA32_CORE_SMRR_PHYSBASE 0x0A0
29 #define SMM_FEATURES_LIB_IA32_CORE_SMRR_PHYSMASK 0x0A1
30 #define EFI_MSR_SMRR_MASK 0xFFFFF000
31 #define EFI_MSR_SMRR_PHYS_MASK_VALID BIT11
32 #define SMM_FEATURES_LIB_SMM_FEATURE_CONTROL 0x4E0
35 // MSRs required for configuration of SMM Code Access Check
37 #define SMM_FEATURES_LIB_IA32_MCA_CAP 0x17D
38 #define SMM_CODE_ACCESS_CHK_BIT BIT58
41 // Set default value to assume SMRR is not supported
43 BOOLEAN mSmrrSupported
= FALSE
;
46 // Set default value to assume MSR_SMM_FEATURE_CONTROL is not supported
48 BOOLEAN mSmmFeatureControlSupported
= FALSE
;
51 // Set default value to assume IA-32 Architectural MSRs are used
53 UINT32 mSmrrPhysBaseMsr
= SMM_FEATURES_LIB_IA32_SMRR_PHYSBASE
;
54 UINT32 mSmrrPhysMaskMsr
= SMM_FEATURES_LIB_IA32_SMRR_PHYSMASK
;
57 // Set default value to assume MTRRs need to be configured on each SMI
59 BOOLEAN mNeedConfigureMtrrs
= TRUE
;
62 // Array for state of SMRR enable on all CPUs
64 BOOLEAN
*mSmrrEnabled
;
67 Performs library initialization.
69 This initialization function contains common functionality shared betwen all
70 library instance constructors.
74 CpuFeaturesLibInitialization (
84 // Retrieve CPU Family and Model
86 AsmCpuid (CPUID_VERSION_INFO
, &RegEax
, NULL
, NULL
, &RegEdx
);
87 FamilyId
= (RegEax
>> 8) & 0xf;
88 ModelId
= (RegEax
>> 4) & 0xf;
89 if (FamilyId
== 0x06 || FamilyId
== 0x0f) {
90 ModelId
= ModelId
| ((RegEax
>> 12) & 0xf0);
94 // Check CPUID(CPUID_VERSION_INFO).EDX[12] for MTRR capability
96 if ((RegEdx
& BIT12
) != 0) {
98 // Check MTRR_CAP MSR bit 11 for SMRR support
100 if ((AsmReadMsr64 (SMM_FEATURES_LIB_IA32_MTRR_CAP
) & BIT11
) != 0) {
101 mSmrrSupported
= TRUE
;
106 // Intel(R) 64 and IA-32 Architectures Software Developer's Manual
107 // Volume 3C, Section 35.3 MSRs in the Intel(R) Atom(TM) Processor Family
109 // If CPU Family/Model is 06_1CH, 06_26H, 06_27H, 06_35H or 06_36H, then
110 // SMRR Physical Base and SMM Physical Mask MSRs are not available.
112 if (FamilyId
== 0x06) {
113 if (ModelId
== 0x1C || ModelId
== 0x26 || ModelId
== 0x27 || ModelId
== 0x35 || ModelId
== 0x36) {
114 mSmrrSupported
= FALSE
;
119 // Intel(R) 64 and IA-32 Architectures Software Developer's Manual
120 // Volume 3C, Section 35.2 MSRs in the Intel(R) Core(TM) 2 Processor Family
122 // If CPU Family/Model is 06_0F or 06_17, then use Intel(R) Core(TM) 2
123 // Processor Family MSRs
125 if (FamilyId
== 0x06) {
126 if (ModelId
== 0x17 || ModelId
== 0x0f) {
127 mSmrrPhysBaseMsr
= SMM_FEATURES_LIB_IA32_CORE_SMRR_PHYSBASE
;
128 mSmrrPhysMaskMsr
= SMM_FEATURES_LIB_IA32_CORE_SMRR_PHYSMASK
;
133 // Intel(R) 64 and IA-32 Architectures Software Developer's Manual
134 // Volume 3C, Section 34.4.2 SMRAM Caching
135 // An IA-32 processor does not automatically write back and invalidate its
136 // caches before entering SMM or before exiting SMM. Because of this behavior,
137 // care must be taken in the placement of the SMRAM in system memory and in
138 // the caching of the SMRAM to prevent cache incoherence when switching back
139 // and forth between SMM and protected mode operation.
141 // An IA-32 processor is a processor that does not support the Intel 64
142 // Architecture. Support for the Intel 64 Architecture can be detected from
143 // CPUID(CPUID_EXTENDED_CPU_SIG).EDX[29]
145 // If an IA-32 processor is detected, then set mNeedConfigureMtrrs to TRUE,
146 // so caches are flushed on SMI entry and SMI exit, the interrupted code
147 // MTRRs are saved/restored, and MTRRs for SMM are loaded.
149 AsmCpuid (CPUID_EXTENDED_FUNCTION
, &RegEax
, NULL
, NULL
, NULL
);
150 if (RegEax
>= CPUID_EXTENDED_CPU_SIG
) {
151 AsmCpuid (CPUID_EXTENDED_CPU_SIG
, NULL
, NULL
, NULL
, &RegEdx
);
152 if ((RegEdx
& BIT29
) != 0) {
153 mNeedConfigureMtrrs
= FALSE
;
158 // Allocate array for state of SMRR enable on all CPUs
160 mSmrrEnabled
= (BOOLEAN
*)AllocatePool (sizeof (BOOLEAN
) * GetCpuMaxLogicalProcessorNumber ());
161 ASSERT (mSmrrEnabled
!= NULL
);
165 Called during the very first SMI into System Management Mode to initialize
166 CPU features, including SMBASE, for the currently executing CPU. Since this
167 is the first SMI, the SMRAM Save State Map is at the default address of
168 SMM_DEFAULT_SMBASE + SMRAM_SAVE_STATE_MAP_OFFSET. The currently executing
169 CPU is specified by CpuIndex and CpuIndex can be used to access information
170 about the currently executing CPU in the ProcessorInfo array and the
171 HotPlugCpuData data structure.
173 @param[in] CpuIndex The index of the CPU to initialize. The value
174 must be between 0 and the NumberOfCpus field in
175 the System Management System Table (SMST).
176 @param[in] IsMonarch TRUE if the CpuIndex is the index of the CPU that
177 was elected as monarch during System Management
179 FALSE if the CpuIndex is not the index of the CPU
180 that was elected as monarch during System
181 Management Mode initialization.
182 @param[in] ProcessorInfo Pointer to an array of EFI_PROCESSOR_INFORMATION
183 structures. ProcessorInfo[CpuIndex] contains the
184 information for the currently executing CPU.
185 @param[in] CpuHotPlugData Pointer to the CPU_HOT_PLUG_DATA structure that
186 contains the ApidId and SmBase arrays.
190 SmmCpuFeaturesInitializeProcessor (
192 IN BOOLEAN IsMonarch
,
193 IN EFI_PROCESSOR_INFORMATION
*ProcessorInfo
,
194 IN CPU_HOT_PLUG_DATA
*CpuHotPlugData
197 SMRAM_SAVE_STATE_MAP
*CpuState
;
198 UINT64 FeatureControl
;
207 CpuState
= (SMRAM_SAVE_STATE_MAP
*)(UINTN
)(SMM_DEFAULT_SMBASE
+ SMRAM_SAVE_STATE_MAP_OFFSET
);
208 CpuState
->x86
.SMBASE
= (UINT32
)CpuHotPlugData
->SmBase
[CpuIndex
];
211 // Intel(R) 64 and IA-32 Architectures Software Developer's Manual
212 // Volume 3C, Section 35.2 MSRs in the Intel(R) Core(TM) 2 Processor Family
214 // If Intel(R) Core(TM) Core(TM) 2 Processor Family MSRs are being used, then
215 // make sure SMRR Enable(BIT3) of MSR_FEATURE_CONTROL MSR(0x3A) is set before
216 // accessing SMRR base/mask MSRs. If Lock(BIT0) of MSR_FEATURE_CONTROL MSR(0x3A)
217 // is set, then the MSR is locked and can not be modified.
219 if (mSmrrSupported
&& mSmrrPhysBaseMsr
== SMM_FEATURES_LIB_IA32_CORE_SMRR_PHYSBASE
) {
220 FeatureControl
= AsmReadMsr64 (SMM_FEATURES_LIB_IA32_FEATURE_CONTROL
);
221 if ((FeatureControl
& BIT3
) == 0) {
222 if ((FeatureControl
& BIT0
) == 0) {
223 AsmWriteMsr64 (SMM_FEATURES_LIB_IA32_FEATURE_CONTROL
, FeatureControl
| BIT3
);
225 mSmrrSupported
= FALSE
;
231 // If SMRR is supported, then program SMRR base/mask MSRs.
232 // The EFI_MSR_SMRR_PHYS_MASK_VALID bit is not set until the first normal SMI.
233 // The code that initializes SMM environment is running in normal mode
234 // from SMRAM region. If SMRR is enabled here, then the SMRAM region
235 // is protected and the normal mode code execution will fail.
237 if (mSmrrSupported
) {
239 // SMRR size cannot be less than 4-KBytes
240 // SMRR size must be of length 2^n
241 // SMRR base alignment cannot be less than SMRR length
243 if ((CpuHotPlugData
->SmrrSize
< SIZE_4KB
) ||
244 (CpuHotPlugData
->SmrrSize
!= GetPowerOfTwo32 (CpuHotPlugData
->SmrrSize
)) ||
245 ((CpuHotPlugData
->SmrrBase
& ~(CpuHotPlugData
->SmrrSize
- 1)) != CpuHotPlugData
->SmrrBase
)) {
247 // Print message and halt if CPU is Monarch
250 DEBUG ((DEBUG_ERROR
, "SMM Base/Size does not meet alignment/size requirement!\n"));
254 AsmWriteMsr64 (mSmrrPhysBaseMsr
, CpuHotPlugData
->SmrrBase
| MTRR_CACHE_WRITE_BACK
);
255 AsmWriteMsr64 (mSmrrPhysMaskMsr
, (~(CpuHotPlugData
->SmrrSize
- 1) & EFI_MSR_SMRR_MASK
));
256 mSmrrEnabled
[CpuIndex
] = FALSE
;
261 // Retrieve CPU Family and Model
263 AsmCpuid (CPUID_VERSION_INFO
, &RegEax
, NULL
, NULL
, &RegEdx
);
264 FamilyId
= (RegEax
>> 8) & 0xf;
265 ModelId
= (RegEax
>> 4) & 0xf;
266 if (FamilyId
== 0x06 || FamilyId
== 0x0f) {
267 ModelId
= ModelId
| ((RegEax
>> 12) & 0xf0);
271 // Intel(R) 64 and IA-32 Architectures Software Developer's Manual
272 // Volume 3C, Section 35.10.1 MSRs in 4th Generation Intel(R) Core(TM)
275 // If CPU Family/Model is 06_3C, 06_45, or 06_46 then use 4th Generation
276 // Intel(R) Core(TM) Processor Family MSRs.
278 if (FamilyId
== 0x06) {
279 if (ModelId
== 0x3C || ModelId
== 0x45 || ModelId
== 0x46 ||
280 ModelId
== 0x3D || ModelId
== 0x47 || ModelId
== 0x4E || ModelId
== 0x4F ||
281 ModelId
== 0x3F || ModelId
== 0x56 || ModelId
== 0x57 || ModelId
== 0x5C ||
284 // Check to see if the CPU supports the SMM Code Access Check feature
285 // Do not access this MSR unless the CPU supports the SmmRegFeatureControl
287 if ((AsmReadMsr64 (SMM_FEATURES_LIB_IA32_MCA_CAP
) & SMM_CODE_ACCESS_CHK_BIT
) != 0) {
288 mSmmFeatureControlSupported
= TRUE
;
294 // Call internal worker function that completes the CPU initialization
296 FinishSmmCpuFeaturesInitializeProcessor ();
300 This function updates the SMRAM save state on the currently executing CPU
301 to resume execution at a specific address after an RSM instruction. This
302 function must evaluate the SMRAM save state to determine the execution mode
303 the RSM instruction resumes and update the resume execution address with
304 either NewInstructionPointer32 or NewInstructionPoint. The auto HALT restart
305 flag in the SMRAM save state must always be cleared. This function returns
306 the value of the instruction pointer from the SMRAM save state that was
307 replaced. If this function returns 0, then the SMRAM save state was not
310 This function is called during the very first SMI on each CPU after
311 SmmCpuFeaturesInitializeProcessor() to set a flag in normal execution mode
312 to signal that the SMBASE of each CPU has been updated before the default
313 SMBASE address is used for the first SMI to the next CPU.
315 @param[in] CpuIndex The index of the CPU to hook. The value
316 must be between 0 and the NumberOfCpus
317 field in the System Management System Table
319 @param[in] CpuState Pointer to SMRAM Save State Map for the
320 currently executing CPU.
321 @param[in] NewInstructionPointer32 Instruction pointer to use if resuming to
322 32-bit execution mode from 64-bit SMM.
323 @param[in] NewInstructionPointer Instruction pointer to use if resuming to
324 same execution mode as SMM.
326 @retval 0 This function did modify the SMRAM save state.
327 @retval > 0 The original instruction pointer value from the SMRAM save state
328 before it was replaced.
332 SmmCpuFeaturesHookReturnFromSmm (
334 IN SMRAM_SAVE_STATE_MAP
*CpuState
,
335 IN UINT64 NewInstructionPointer32
,
336 IN UINT64 NewInstructionPointer
343 Hook point in normal execution mode that allows the one CPU that was elected
344 as monarch during System Management Mode initialization to perform additional
345 initialization actions immediately after all of the CPUs have processed their
346 first SMI and called SmmCpuFeaturesInitializeProcessor() relocating SMBASE
347 into a buffer in SMRAM and called SmmCpuFeaturesHookReturnFromSmm().
351 SmmCpuFeaturesSmmRelocationComplete (
358 Determines if MTRR registers must be configured to set SMRAM cache-ability
359 when executing in System Management Mode.
361 @retval TRUE MTRR registers must be configured to set SMRAM cache-ability.
362 @retval FALSE MTRR registers do not need to be configured to set SMRAM
367 SmmCpuFeaturesNeedConfigureMtrrs (
371 return mNeedConfigureMtrrs
;
375 Disable SMRR register if SMRR is supported and SmmCpuFeaturesNeedConfigureMtrrs()
380 SmmCpuFeaturesDisableSmrr (
384 if (mSmrrSupported
&& mNeedConfigureMtrrs
) {
385 AsmWriteMsr64 (mSmrrPhysMaskMsr
, AsmReadMsr64(mSmrrPhysMaskMsr
) & ~EFI_MSR_SMRR_PHYS_MASK_VALID
);
390 Enable SMRR register if SMRR is supported and SmmCpuFeaturesNeedConfigureMtrrs()
395 SmmCpuFeaturesReenableSmrr (
399 if (mSmrrSupported
&& mNeedConfigureMtrrs
) {
400 AsmWriteMsr64 (mSmrrPhysMaskMsr
, AsmReadMsr64(mSmrrPhysMaskMsr
) | EFI_MSR_SMRR_PHYS_MASK_VALID
);
405 Processor specific hook point each time a CPU enters System Management Mode.
407 @param[in] CpuIndex The index of the CPU that has entered SMM. The value
408 must be between 0 and the NumberOfCpus field in the
409 System Management System Table (SMST).
413 SmmCpuFeaturesRendezvousEntry (
418 // If SMRR is supported and this is the first normal SMI, then enable SMRR
420 if (mSmrrSupported
&& !mSmrrEnabled
[CpuIndex
]) {
421 AsmWriteMsr64 (mSmrrPhysMaskMsr
, AsmReadMsr64 (mSmrrPhysMaskMsr
) | EFI_MSR_SMRR_PHYS_MASK_VALID
);
422 mSmrrEnabled
[CpuIndex
] = TRUE
;
427 Processor specific hook point each time a CPU exits System Management Mode.
429 @param[in] CpuIndex The index of the CPU that is exiting SMM. The value must
430 be between 0 and the NumberOfCpus field in the System
431 Management System Table (SMST).
435 SmmCpuFeaturesRendezvousExit (
442 Check to see if an SMM register is supported by a specified CPU.
444 @param[in] CpuIndex The index of the CPU to check for SMM register support.
445 The value must be between 0 and the NumberOfCpus field
446 in the System Management System Table (SMST).
447 @param[in] RegName Identifies the SMM register to check for support.
449 @retval TRUE The SMM register specified by RegName is supported by the CPU
450 specified by CpuIndex.
451 @retval FALSE The SMM register specified by RegName is not supported by the
452 CPU specified by CpuIndex.
456 SmmCpuFeaturesIsSmmRegisterSupported (
458 IN SMM_REG_NAME RegName
461 if (mSmmFeatureControlSupported
&& RegName
== SmmRegFeatureControl
) {
468 Returns the current value of the SMM register for the specified CPU.
469 If the SMM register is not supported, then 0 is returned.
471 @param[in] CpuIndex The index of the CPU to read the SMM register. The
472 value must be between 0 and the NumberOfCpus field in
473 the System Management System Table (SMST).
474 @param[in] RegName Identifies the SMM register to read.
476 @return The value of the SMM register specified by RegName from the CPU
477 specified by CpuIndex.
481 SmmCpuFeaturesGetSmmRegister (
483 IN SMM_REG_NAME RegName
486 if (mSmmFeatureControlSupported
&& RegName
== SmmRegFeatureControl
) {
487 return AsmReadMsr64 (SMM_FEATURES_LIB_SMM_FEATURE_CONTROL
);
493 Sets the value of an SMM register on a specified CPU.
494 If the SMM register is not supported, then no action is performed.
496 @param[in] CpuIndex The index of the CPU to write the SMM register. The
497 value must be between 0 and the NumberOfCpus field in
498 the System Management System Table (SMST).
499 @param[in] RegName Identifies the SMM register to write.
500 registers are read-only.
501 @param[in] Value The value to write to the SMM register.
505 SmmCpuFeaturesSetSmmRegister (
507 IN SMM_REG_NAME RegName
,
511 if (mSmmFeatureControlSupported
&& RegName
== SmmRegFeatureControl
) {
512 AsmWriteMsr64 (SMM_FEATURES_LIB_SMM_FEATURE_CONTROL
, Value
);
517 Read an SMM Save State register on the target processor. If this function
518 returns EFI_UNSUPPORTED, then the caller is responsible for reading the
519 SMM Save Sate register.
521 @param[in] CpuIndex The index of the CPU to read the SMM Save State. The
522 value must be between 0 and the NumberOfCpus field in
523 the System Management System Table (SMST).
524 @param[in] Register The SMM Save State register to read.
525 @param[in] Width The number of bytes to read from the CPU save state.
526 @param[out] Buffer Upon return, this holds the CPU register value read
529 @retval EFI_SUCCESS The register was read from Save State.
530 @retval EFI_INVALID_PARAMETER Buffer is NULL.
531 @retval EFI_UNSUPPORTED This function does not support reading Register.
536 SmmCpuFeaturesReadSaveStateRegister (
538 IN EFI_SMM_SAVE_STATE_REGISTER Register
,
543 return EFI_UNSUPPORTED
;
547 Writes an SMM Save State register on the target processor. If this function
548 returns EFI_UNSUPPORTED, then the caller is responsible for writing the
549 SMM Save Sate register.
551 @param[in] CpuIndex The index of the CPU to write the SMM Save State. The
552 value must be between 0 and the NumberOfCpus field in
553 the System Management System Table (SMST).
554 @param[in] Register The SMM Save State register to write.
555 @param[in] Width The number of bytes to write to the CPU save state.
556 @param[in] Buffer Upon entry, this holds the new CPU register value.
558 @retval EFI_SUCCESS The register was written to Save State.
559 @retval EFI_INVALID_PARAMETER Buffer is NULL.
560 @retval EFI_UNSUPPORTED This function does not support writing Register.
564 SmmCpuFeaturesWriteSaveStateRegister (
566 IN EFI_SMM_SAVE_STATE_REGISTER Register
,
568 IN CONST VOID
*Buffer
571 return EFI_UNSUPPORTED
;
575 This function is hook point called after the gEfiSmmReadyToLockProtocolGuid
576 notification is completely processed.
580 SmmCpuFeaturesCompleteSmmReadyToLock (
587 This API provides a method for a CPU to allocate a specific region for storing page tables.
589 This API can be called more once to allocate memory for page tables.
591 Allocates the number of 4KB pages of type EfiRuntimeServicesData and returns a pointer to the
592 allocated buffer. The buffer returned is aligned on a 4KB boundary. If Pages is 0, then NULL
593 is returned. If there is not enough memory remaining to satisfy the request, then NULL is
596 This function can also return NULL if there is no preference on where the page tables are allocated in SMRAM.
598 @param Pages The number of 4 KB pages to allocate.
600 @return A pointer to the allocated buffer for page tables.
601 @retval NULL Fail to allocate a specific region for storing page tables,
602 Or there is no preference on where the page tables are allocated in SMRAM.
607 SmmCpuFeaturesAllocatePageTableMemory (