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
))
248 // Print message and halt if CPU is Monarch
251 DEBUG ((DEBUG_ERROR
, "SMM Base/Size does not meet alignment/size requirement!\n"));
255 AsmWriteMsr64 (mSmrrPhysBaseMsr
, CpuHotPlugData
->SmrrBase
| MTRR_CACHE_WRITE_BACK
);
256 AsmWriteMsr64 (mSmrrPhysMaskMsr
, (~(CpuHotPlugData
->SmrrSize
- 1) & EFI_MSR_SMRR_MASK
));
257 mSmrrEnabled
[CpuIndex
] = FALSE
;
262 // Retrieve CPU Family and Model
264 AsmCpuid (CPUID_VERSION_INFO
, &RegEax
, NULL
, NULL
, &RegEdx
);
265 FamilyId
= (RegEax
>> 8) & 0xf;
266 ModelId
= (RegEax
>> 4) & 0xf;
267 if ((FamilyId
== 0x06) || (FamilyId
== 0x0f)) {
268 ModelId
= ModelId
| ((RegEax
>> 12) & 0xf0);
272 // Intel(R) 64 and IA-32 Architectures Software Developer's Manual
273 // Volume 3C, Section 35.10.1 MSRs in 4th Generation Intel(R) Core(TM)
276 // If CPU Family/Model is 06_3C, 06_45, or 06_46 then use 4th Generation
277 // Intel(R) Core(TM) Processor Family MSRs.
279 if (FamilyId
== 0x06) {
280 if ((ModelId
== 0x3C) || (ModelId
== 0x45) || (ModelId
== 0x46) ||
281 (ModelId
== 0x3D) || (ModelId
== 0x47) || (ModelId
== 0x4E) || (ModelId
== 0x4F) ||
282 (ModelId
== 0x3F) || (ModelId
== 0x56) || (ModelId
== 0x57) || (ModelId
== 0x5C) ||
286 // Check to see if the CPU supports the SMM Code Access Check feature
287 // Do not access this MSR unless the CPU supports the SmmRegFeatureControl
289 if ((AsmReadMsr64 (SMM_FEATURES_LIB_IA32_MCA_CAP
) & SMM_CODE_ACCESS_CHK_BIT
) != 0) {
290 mSmmFeatureControlSupported
= TRUE
;
296 // Call internal worker function that completes the CPU initialization
298 FinishSmmCpuFeaturesInitializeProcessor ();
302 This function updates the SMRAM save state on the currently executing CPU
303 to resume execution at a specific address after an RSM instruction. This
304 function must evaluate the SMRAM save state to determine the execution mode
305 the RSM instruction resumes and update the resume execution address with
306 either NewInstructionPointer32 or NewInstructionPoint. The auto HALT restart
307 flag in the SMRAM save state must always be cleared. This function returns
308 the value of the instruction pointer from the SMRAM save state that was
309 replaced. If this function returns 0, then the SMRAM save state was not
312 This function is called during the very first SMI on each CPU after
313 SmmCpuFeaturesInitializeProcessor() to set a flag in normal execution mode
314 to signal that the SMBASE of each CPU has been updated before the default
315 SMBASE address is used for the first SMI to the next CPU.
317 @param[in] CpuIndex The index of the CPU to hook. The value
318 must be between 0 and the NumberOfCpus
319 field in the System Management System Table
321 @param[in] CpuState Pointer to SMRAM Save State Map for the
322 currently executing CPU.
323 @param[in] NewInstructionPointer32 Instruction pointer to use if resuming to
324 32-bit execution mode from 64-bit SMM.
325 @param[in] NewInstructionPointer Instruction pointer to use if resuming to
326 same execution mode as SMM.
328 @retval 0 This function did modify the SMRAM save state.
329 @retval > 0 The original instruction pointer value from the SMRAM save state
330 before it was replaced.
334 SmmCpuFeaturesHookReturnFromSmm (
336 IN SMRAM_SAVE_STATE_MAP
*CpuState
,
337 IN UINT64 NewInstructionPointer32
,
338 IN UINT64 NewInstructionPointer
345 Hook point in normal execution mode that allows the one CPU that was elected
346 as monarch during System Management Mode initialization to perform additional
347 initialization actions immediately after all of the CPUs have processed their
348 first SMI and called SmmCpuFeaturesInitializeProcessor() relocating SMBASE
349 into a buffer in SMRAM and called SmmCpuFeaturesHookReturnFromSmm().
353 SmmCpuFeaturesSmmRelocationComplete (
360 Determines if MTRR registers must be configured to set SMRAM cache-ability
361 when executing in System Management Mode.
363 @retval TRUE MTRR registers must be configured to set SMRAM cache-ability.
364 @retval FALSE MTRR registers do not need to be configured to set SMRAM
369 SmmCpuFeaturesNeedConfigureMtrrs (
373 return mNeedConfigureMtrrs
;
377 Disable SMRR register if SMRR is supported and SmmCpuFeaturesNeedConfigureMtrrs()
382 SmmCpuFeaturesDisableSmrr (
386 if (mSmrrSupported
&& mNeedConfigureMtrrs
) {
387 AsmWriteMsr64 (mSmrrPhysMaskMsr
, AsmReadMsr64 (mSmrrPhysMaskMsr
) & ~EFI_MSR_SMRR_PHYS_MASK_VALID
);
392 Enable SMRR register if SMRR is supported and SmmCpuFeaturesNeedConfigureMtrrs()
397 SmmCpuFeaturesReenableSmrr (
401 if (mSmrrSupported
&& mNeedConfigureMtrrs
) {
402 AsmWriteMsr64 (mSmrrPhysMaskMsr
, AsmReadMsr64 (mSmrrPhysMaskMsr
) | EFI_MSR_SMRR_PHYS_MASK_VALID
);
407 Processor specific hook point each time a CPU enters System Management Mode.
409 @param[in] CpuIndex The index of the CPU that has entered SMM. The value
410 must be between 0 and the NumberOfCpus field in the
411 System Management System Table (SMST).
415 SmmCpuFeaturesRendezvousEntry (
420 // If SMRR is supported and this is the first normal SMI, then enable SMRR
422 if (mSmrrSupported
&& !mSmrrEnabled
[CpuIndex
]) {
423 AsmWriteMsr64 (mSmrrPhysMaskMsr
, AsmReadMsr64 (mSmrrPhysMaskMsr
) | EFI_MSR_SMRR_PHYS_MASK_VALID
);
424 mSmrrEnabled
[CpuIndex
] = TRUE
;
429 Processor specific hook point each time a CPU exits System Management Mode.
431 @param[in] CpuIndex The index of the CPU that is exiting SMM. The value must
432 be between 0 and the NumberOfCpus field in the System
433 Management System Table (SMST).
437 SmmCpuFeaturesRendezvousExit (
444 Check to see if an SMM register is supported by a specified CPU.
446 @param[in] CpuIndex The index of the CPU to check for SMM register support.
447 The value must be between 0 and the NumberOfCpus field
448 in the System Management System Table (SMST).
449 @param[in] RegName Identifies the SMM register to check for support.
451 @retval TRUE The SMM register specified by RegName is supported by the CPU
452 specified by CpuIndex.
453 @retval FALSE The SMM register specified by RegName is not supported by the
454 CPU specified by CpuIndex.
458 SmmCpuFeaturesIsSmmRegisterSupported (
460 IN SMM_REG_NAME RegName
463 if (mSmmFeatureControlSupported
&& (RegName
== SmmRegFeatureControl
)) {
471 Returns the current value of the SMM register for the specified CPU.
472 If the SMM register is not supported, then 0 is returned.
474 @param[in] CpuIndex The index of the CPU to read the SMM register. The
475 value must be between 0 and the NumberOfCpus field in
476 the System Management System Table (SMST).
477 @param[in] RegName Identifies the SMM register to read.
479 @return The value of the SMM register specified by RegName from the CPU
480 specified by CpuIndex.
484 SmmCpuFeaturesGetSmmRegister (
486 IN SMM_REG_NAME RegName
489 if (mSmmFeatureControlSupported
&& (RegName
== SmmRegFeatureControl
)) {
490 return AsmReadMsr64 (SMM_FEATURES_LIB_SMM_FEATURE_CONTROL
);
497 Sets the value of an SMM register on a specified CPU.
498 If the SMM register is not supported, then no action is performed.
500 @param[in] CpuIndex The index of the CPU to write the SMM register. The
501 value must be between 0 and the NumberOfCpus field in
502 the System Management System Table (SMST).
503 @param[in] RegName Identifies the SMM register to write.
504 registers are read-only.
505 @param[in] Value The value to write to the SMM register.
509 SmmCpuFeaturesSetSmmRegister (
511 IN SMM_REG_NAME RegName
,
515 if (mSmmFeatureControlSupported
&& (RegName
== SmmRegFeatureControl
)) {
516 AsmWriteMsr64 (SMM_FEATURES_LIB_SMM_FEATURE_CONTROL
, Value
);
521 Read an SMM Save State register on the target processor. If this function
522 returns EFI_UNSUPPORTED, then the caller is responsible for reading the
523 SMM Save Sate register.
525 @param[in] CpuIndex The index of the CPU to read the SMM Save State. The
526 value must be between 0 and the NumberOfCpus field in
527 the System Management System Table (SMST).
528 @param[in] Register The SMM Save State register to read.
529 @param[in] Width The number of bytes to read from the CPU save state.
530 @param[out] Buffer Upon return, this holds the CPU register value read
533 @retval EFI_SUCCESS The register was read from Save State.
534 @retval EFI_INVALID_PARAMETER Buffer is NULL.
535 @retval EFI_UNSUPPORTED This function does not support reading Register.
540 SmmCpuFeaturesReadSaveStateRegister (
542 IN EFI_SMM_SAVE_STATE_REGISTER Register
,
547 return EFI_UNSUPPORTED
;
551 Writes an SMM Save State register on the target processor. If this function
552 returns EFI_UNSUPPORTED, then the caller is responsible for writing the
553 SMM Save Sate register.
555 @param[in] CpuIndex The index of the CPU to write the SMM Save State. The
556 value must be between 0 and the NumberOfCpus field in
557 the System Management System Table (SMST).
558 @param[in] Register The SMM Save State register to write.
559 @param[in] Width The number of bytes to write to the CPU save state.
560 @param[in] Buffer Upon entry, this holds the new CPU register value.
562 @retval EFI_SUCCESS The register was written to Save State.
563 @retval EFI_INVALID_PARAMETER Buffer is NULL.
564 @retval EFI_UNSUPPORTED This function does not support writing Register.
568 SmmCpuFeaturesWriteSaveStateRegister (
570 IN EFI_SMM_SAVE_STATE_REGISTER Register
,
572 IN CONST VOID
*Buffer
575 return EFI_UNSUPPORTED
;
579 This function is hook point called after the gEfiSmmReadyToLockProtocolGuid
580 notification is completely processed.
584 SmmCpuFeaturesCompleteSmmReadyToLock (
591 This API provides a method for a CPU to allocate a specific region for storing page tables.
593 This API can be called more once to allocate memory for page tables.
595 Allocates the number of 4KB pages of type EfiRuntimeServicesData and returns a pointer to the
596 allocated buffer. The buffer returned is aligned on a 4KB boundary. If Pages is 0, then NULL
597 is returned. If there is not enough memory remaining to satisfy the request, then NULL is
600 This function can also return NULL if there is no preference on where the page tables are allocated in SMRAM.
602 @param Pages The number of 4 KB pages to allocate.
604 @return A pointer to the allocated buffer for page tables.
605 @retval NULL Fail to allocate a specific region for storing page tables,
606 Or there is no preference on where the page tables are allocated in SMRAM.
611 SmmCpuFeaturesAllocatePageTableMemory (