]> git.proxmox.com Git - mirror_edk2.git/blame - UefiCpuPkg/Library/SmmCpuFeaturesLib/IntelSmmCpuFeaturesLib.c
UefiCpuPkg: Move AsmRelocateApLoopStart from Mpfuncs.nasm to AmdSev.nasm
[mirror_edk2.git] / UefiCpuPkg / Library / SmmCpuFeaturesLib / IntelSmmCpuFeaturesLib.c
CommitLineData
a9764e68 1/** @file\r
61dc3b33 2Implementation shared across all library instances.\r
a9764e68 3\r
f6b86eec 4Copyright (c) 2010 - 2023, Intel Corporation. All rights reserved.<BR>\r
2002e950 5Copyright (c) Microsoft Corporation.<BR>\r
0acd8697 6SPDX-License-Identifier: BSD-2-Clause-Patent\r
a9764e68
MK
7\r
8**/\r
9\r
ae62a6e4
AC
10#include "CpuFeaturesLib.h"\r
11\r
a9764e68 12#include <Library/MtrrLib.h>\r
01acb06c
RN
13#include <Register/Intel/Cpuid.h>\r
14#include <Register/Intel/SmramSaveStateMap.h>\r
a9764e68
MK
15\r
16//\r
17// Machine Specific Registers (MSRs)\r
18//\r
19#define SMM_FEATURES_LIB_IA32_MTRR_CAP 0x0FE\r
20#define SMM_FEATURES_LIB_IA32_FEATURE_CONTROL 0x03A\r
21#define SMM_FEATURES_LIB_IA32_SMRR_PHYSBASE 0x1F2\r
22#define SMM_FEATURES_LIB_IA32_SMRR_PHYSMASK 0x1F3\r
23#define SMM_FEATURES_LIB_IA32_CORE_SMRR_PHYSBASE 0x0A0\r
24#define SMM_FEATURES_LIB_IA32_CORE_SMRR_PHYSMASK 0x0A1\r
25#define EFI_MSR_SMRR_MASK 0xFFFFF000\r
26#define EFI_MSR_SMRR_PHYS_MASK_VALID BIT11\r
d26a7a3f 27#define SMM_FEATURES_LIB_SMM_FEATURE_CONTROL 0x4E0\r
a9764e68 28\r
4ab4e20f
JF
29//\r
30// MSRs required for configuration of SMM Code Access Check\r
31//\r
053e878b
MK
32#define SMM_FEATURES_LIB_IA32_MCA_CAP 0x17D\r
33#define SMM_CODE_ACCESS_CHK_BIT BIT58\r
4ab4e20f 34\r
a9764e68
MK
35//\r
36// Set default value to assume IA-32 Architectural MSRs are used\r
37//\r
38UINT32 mSmrrPhysBaseMsr = SMM_FEATURES_LIB_IA32_SMRR_PHYSBASE;\r
39UINT32 mSmrrPhysMaskMsr = SMM_FEATURES_LIB_IA32_SMRR_PHYSMASK;\r
40\r
f6b86eec
WJ
41//\r
42// Indicate SmBase for each Processors has been relocated or not. If TRUE,\r
43// means no need to do the relocation in SmmCpuFeaturesInitializeProcessor().\r
44//\r
45BOOLEAN mSmmCpuFeaturesSmmRelocated;\r
46\r
a9764e68
MK
47//\r
48// Set default value to assume MTRRs need to be configured on each SMI\r
49//\r
50BOOLEAN mNeedConfigureMtrrs = TRUE;\r
51\r
52//\r
53// Array for state of SMRR enable on all CPUs\r
54//\r
55BOOLEAN *mSmrrEnabled;\r
56\r
57/**\r
2002e950 58 Performs library initialization.\r
a9764e68 59\r
2002e950
MK
60 This initialization function contains common functionality shared betwen all\r
61 library instance constructors.\r
a9764e68
MK
62\r
63**/\r
2002e950
MK
64VOID\r
65CpuFeaturesLibInitialization (\r
66 VOID\r
a9764e68
MK
67 )\r
68{\r
69 UINT32 RegEax;\r
70 UINT32 RegEdx;\r
71 UINTN FamilyId;\r
72 UINTN ModelId;\r
73\r
74 //\r
75 // Retrieve CPU Family and Model\r
76 //\r
77 AsmCpuid (CPUID_VERSION_INFO, &RegEax, NULL, NULL, &RegEdx);\r
78 FamilyId = (RegEax >> 8) & 0xf;\r
79 ModelId = (RegEax >> 4) & 0xf;\r
053e878b 80 if ((FamilyId == 0x06) || (FamilyId == 0x0f)) {\r
a9764e68
MK
81 ModelId = ModelId | ((RegEax >> 12) & 0xf0);\r
82 }\r
83\r
84 //\r
85 // Check CPUID(CPUID_VERSION_INFO).EDX[12] for MTRR capability\r
86 //\r
87 if ((RegEdx & BIT12) != 0) {\r
88 //\r
89 // Check MTRR_CAP MSR bit 11 for SMRR support\r
90 //\r
91 if ((AsmReadMsr64 (SMM_FEATURES_LIB_IA32_MTRR_CAP) & BIT11) != 0) {\r
76ec1752 92 ASSERT (FeaturePcdGet (PcdSmrrEnable));\r
a9764e68
MK
93 }\r
94 }\r
95\r
96 //\r
97 // Intel(R) 64 and IA-32 Architectures Software Developer's Manual\r
98 // Volume 3C, Section 35.3 MSRs in the Intel(R) Atom(TM) Processor Family\r
99 //\r
100 // If CPU Family/Model is 06_1CH, 06_26H, 06_27H, 06_35H or 06_36H, then\r
101 // SMRR Physical Base and SMM Physical Mask MSRs are not available.\r
102 //\r
103 if (FamilyId == 0x06) {\r
053e878b 104 if ((ModelId == 0x1C) || (ModelId == 0x26) || (ModelId == 0x27) || (ModelId == 0x35) || (ModelId == 0x36)) {\r
76ec1752 105 ASSERT (!FeaturePcdGet (PcdSmrrEnable));\r
a9764e68
MK
106 }\r
107 }\r
108\r
109 //\r
110 // Intel(R) 64 and IA-32 Architectures Software Developer's Manual\r
111 // Volume 3C, Section 35.2 MSRs in the Intel(R) Core(TM) 2 Processor Family\r
112 //\r
113 // If CPU Family/Model is 06_0F or 06_17, then use Intel(R) Core(TM) 2\r
114 // Processor Family MSRs\r
115 //\r
116 if (FamilyId == 0x06) {\r
053e878b 117 if ((ModelId == 0x17) || (ModelId == 0x0f)) {\r
a9764e68
MK
118 mSmrrPhysBaseMsr = SMM_FEATURES_LIB_IA32_CORE_SMRR_PHYSBASE;\r
119 mSmrrPhysMaskMsr = SMM_FEATURES_LIB_IA32_CORE_SMRR_PHYSMASK;\r
120 }\r
121 }\r
122\r
123 //\r
124 // Intel(R) 64 and IA-32 Architectures Software Developer's Manual\r
125 // Volume 3C, Section 34.4.2 SMRAM Caching\r
126 // An IA-32 processor does not automatically write back and invalidate its\r
127 // caches before entering SMM or before exiting SMM. Because of this behavior,\r
128 // care must be taken in the placement of the SMRAM in system memory and in\r
129 // the caching of the SMRAM to prevent cache incoherence when switching back\r
130 // and forth between SMM and protected mode operation.\r
131 //\r
132 // An IA-32 processor is a processor that does not support the Intel 64\r
133 // Architecture. Support for the Intel 64 Architecture can be detected from\r
134 // CPUID(CPUID_EXTENDED_CPU_SIG).EDX[29]\r
135 //\r
136 // If an IA-32 processor is detected, then set mNeedConfigureMtrrs to TRUE,\r
137 // so caches are flushed on SMI entry and SMI exit, the interrupted code\r
138 // MTRRs are saved/restored, and MTRRs for SMM are loaded.\r
139 //\r
140 AsmCpuid (CPUID_EXTENDED_FUNCTION, &RegEax, NULL, NULL, NULL);\r
141 if (RegEax >= CPUID_EXTENDED_CPU_SIG) {\r
142 AsmCpuid (CPUID_EXTENDED_CPU_SIG, NULL, NULL, NULL, &RegEdx);\r
143 if ((RegEdx & BIT29) != 0) {\r
144 mNeedConfigureMtrrs = FALSE;\r
145 }\r
146 }\r
147\r
148 //\r
149 // Allocate array for state of SMRR enable on all CPUs\r
150 //\r
e542e05d 151 mSmrrEnabled = (BOOLEAN *)AllocatePool (sizeof (BOOLEAN) * GetCpuMaxLogicalProcessorNumber ());\r
a9764e68 152 ASSERT (mSmrrEnabled != NULL);\r
f6b86eec
WJ
153\r
154 //\r
155 // If gSmmBaseHobGuid found, means SmBase info has been relocated and recorded\r
156 // in the SmBase array.\r
157 //\r
158 mSmmCpuFeaturesSmmRelocated = (BOOLEAN)(GetFirstGuidHob (&gSmmBaseHobGuid) != NULL);\r
a9764e68
MK
159}\r
160\r
161/**\r
162 Called during the very first SMI into System Management Mode to initialize\r
163 CPU features, including SMBASE, for the currently executing CPU. Since this\r
164 is the first SMI, the SMRAM Save State Map is at the default address of\r
165 SMM_DEFAULT_SMBASE + SMRAM_SAVE_STATE_MAP_OFFSET. The currently executing\r
166 CPU is specified by CpuIndex and CpuIndex can be used to access information\r
167 about the currently executing CPU in the ProcessorInfo array and the\r
168 HotPlugCpuData data structure.\r
169\r
170 @param[in] CpuIndex The index of the CPU to initialize. The value\r
171 must be between 0 and the NumberOfCpus field in\r
172 the System Management System Table (SMST).\r
173 @param[in] IsMonarch TRUE if the CpuIndex is the index of the CPU that\r
174 was elected as monarch during System Management\r
175 Mode initialization.\r
176 FALSE if the CpuIndex is not the index of the CPU\r
177 that was elected as monarch during System\r
178 Management Mode initialization.\r
179 @param[in] ProcessorInfo Pointer to an array of EFI_PROCESSOR_INFORMATION\r
180 structures. ProcessorInfo[CpuIndex] contains the\r
181 information for the currently executing CPU.\r
182 @param[in] CpuHotPlugData Pointer to the CPU_HOT_PLUG_DATA structure that\r
183 contains the ApidId and SmBase arrays.\r
184**/\r
185VOID\r
186EFIAPI\r
187SmmCpuFeaturesInitializeProcessor (\r
188 IN UINTN CpuIndex,\r
189 IN BOOLEAN IsMonarch,\r
190 IN EFI_PROCESSOR_INFORMATION *ProcessorInfo,\r
191 IN CPU_HOT_PLUG_DATA *CpuHotPlugData\r
192 )\r
193{\r
194 SMRAM_SAVE_STATE_MAP *CpuState;\r
195 UINT64 FeatureControl;\r
4ab4e20f
JF
196 UINT32 RegEax;\r
197 UINT32 RegEdx;\r
198 UINTN FamilyId;\r
199 UINTN ModelId;\r
a9764e68
MK
200\r
201 //\r
f6b86eec 202 // No need to configure SMBASE if SmBase relocation has been done.\r
a9764e68 203 //\r
f6b86eec
WJ
204 if (!mSmmCpuFeaturesSmmRelocated) {\r
205 //\r
206 // Configure SMBASE.\r
207 //\r
208 CpuState = (SMRAM_SAVE_STATE_MAP *)(UINTN)(SMM_DEFAULT_SMBASE + SMRAM_SAVE_STATE_MAP_OFFSET);\r
209 CpuState->x86.SMBASE = (UINT32)CpuHotPlugData->SmBase[CpuIndex];\r
210 }\r
a9764e68
MK
211\r
212 //\r
213 // Intel(R) 64 and IA-32 Architectures Software Developer's Manual\r
214 // Volume 3C, Section 35.2 MSRs in the Intel(R) Core(TM) 2 Processor Family\r
215 //\r
216 // If Intel(R) Core(TM) Core(TM) 2 Processor Family MSRs are being used, then\r
217 // make sure SMRR Enable(BIT3) of MSR_FEATURE_CONTROL MSR(0x3A) is set before\r
218 // accessing SMRR base/mask MSRs. If Lock(BIT0) of MSR_FEATURE_CONTROL MSR(0x3A)\r
219 // is set, then the MSR is locked and can not be modified.\r
220 //\r
76ec1752 221 if ((FeaturePcdGet (PcdSmrrEnable)) && (mSmrrPhysBaseMsr == SMM_FEATURES_LIB_IA32_CORE_SMRR_PHYSBASE)) {\r
a9764e68
MK
222 FeatureControl = AsmReadMsr64 (SMM_FEATURES_LIB_IA32_FEATURE_CONTROL);\r
223 if ((FeatureControl & BIT3) == 0) {\r
76ec1752 224 ASSERT ((FeatureControl & BIT0) == 0);\r
a9764e68
MK
225 if ((FeatureControl & BIT0) == 0) {\r
226 AsmWriteMsr64 (SMM_FEATURES_LIB_IA32_FEATURE_CONTROL, FeatureControl | BIT3);\r
a9764e68
MK
227 }\r
228 }\r
229 }\r
230\r
231 //\r
232 // If SMRR is supported, then program SMRR base/mask MSRs.\r
233 // The EFI_MSR_SMRR_PHYS_MASK_VALID bit is not set until the first normal SMI.\r
234 // The code that initializes SMM environment is running in normal mode\r
235 // from SMRAM region. If SMRR is enabled here, then the SMRAM region\r
236 // is protected and the normal mode code execution will fail.\r
237 //\r
76ec1752 238 if (FeaturePcdGet (PcdSmrrEnable)) {\r
728de7a0
MK
239 //\r
240 // SMRR size cannot be less than 4-KBytes\r
241 // SMRR size must be of length 2^n\r
242 // SMRR base alignment cannot be less than SMRR length\r
243 //\r
244 if ((CpuHotPlugData->SmrrSize < SIZE_4KB) ||\r
245 (CpuHotPlugData->SmrrSize != GetPowerOfTwo32 (CpuHotPlugData->SmrrSize)) ||\r
053e878b
MK
246 ((CpuHotPlugData->SmrrBase & ~(CpuHotPlugData->SmrrSize - 1)) != CpuHotPlugData->SmrrBase))\r
247 {\r
728de7a0
MK
248 //\r
249 // Print message and halt if CPU is Monarch\r
250 //\r
251 if (IsMonarch) {\r
4c6351db 252 DEBUG ((DEBUG_ERROR, "SMM Base/Size does not meet alignment/size requirement!\n"));\r
728de7a0
MK
253 CpuDeadLoop ();\r
254 }\r
255 } else {\r
256 AsmWriteMsr64 (mSmrrPhysBaseMsr, CpuHotPlugData->SmrrBase | MTRR_CACHE_WRITE_BACK);\r
257 AsmWriteMsr64 (mSmrrPhysMaskMsr, (~(CpuHotPlugData->SmrrSize - 1) & EFI_MSR_SMRR_MASK));\r
258 mSmrrEnabled[CpuIndex] = FALSE;\r
259 }\r
a9764e68 260 }\r
4ab4e20f
JF
261\r
262 //\r
263 // Retrieve CPU Family and Model\r
264 //\r
265 AsmCpuid (CPUID_VERSION_INFO, &RegEax, NULL, NULL, &RegEdx);\r
266 FamilyId = (RegEax >> 8) & 0xf;\r
267 ModelId = (RegEax >> 4) & 0xf;\r
053e878b 268 if ((FamilyId == 0x06) || (FamilyId == 0x0f)) {\r
4ab4e20f
JF
269 ModelId = ModelId | ((RegEax >> 12) & 0xf0);\r
270 }\r
271\r
272 //\r
273 // Intel(R) 64 and IA-32 Architectures Software Developer's Manual\r
274 // Volume 3C, Section 35.10.1 MSRs in 4th Generation Intel(R) Core(TM)\r
275 // Processor Family.\r
276 //\r
277 // If CPU Family/Model is 06_3C, 06_45, or 06_46 then use 4th Generation\r
278 // Intel(R) Core(TM) Processor Family MSRs.\r
279 //\r
280 if (FamilyId == 0x06) {\r
053e878b
MK
281 if ((ModelId == 0x3C) || (ModelId == 0x45) || (ModelId == 0x46) ||\r
282 (ModelId == 0x3D) || (ModelId == 0x47) || (ModelId == 0x4E) || (ModelId == 0x4F) ||\r
283 (ModelId == 0x3F) || (ModelId == 0x56) || (ModelId == 0x57) || (ModelId == 0x5C) ||\r
284 (ModelId == 0x8C))\r
285 {\r
4ab4e20f
JF
286 //\r
287 // Check to see if the CPU supports the SMM Code Access Check feature\r
288 // Do not access this MSR unless the CPU supports the SmmRegFeatureControl\r
289 //\r
290 if ((AsmReadMsr64 (SMM_FEATURES_LIB_IA32_MCA_CAP) & SMM_CODE_ACCESS_CHK_BIT) != 0) {\r
76ec1752 291 ASSERT (FeaturePcdGet (PcdSmmFeatureControlEnable));\r
4ab4e20f
JF
292 }\r
293 }\r
294 }\r
4c6351db
MK
295\r
296 //\r
297 // Call internal worker function that completes the CPU initialization\r
298 //\r
299 FinishSmmCpuFeaturesInitializeProcessor ();\r
a9764e68
MK
300}\r
301\r
a9764e68
MK
302/**\r
303 Determines if MTRR registers must be configured to set SMRAM cache-ability\r
304 when executing in System Management Mode.\r
305\r
306 @retval TRUE MTRR registers must be configured to set SMRAM cache-ability.\r
307 @retval FALSE MTRR registers do not need to be configured to set SMRAM\r
308 cache-ability.\r
309**/\r
310BOOLEAN\r
311EFIAPI\r
312SmmCpuFeaturesNeedConfigureMtrrs (\r
313 VOID\r
314 )\r
315{\r
316 return mNeedConfigureMtrrs;\r
317}\r
318\r
319/**\r
320 Disable SMRR register if SMRR is supported and SmmCpuFeaturesNeedConfigureMtrrs()\r
321 returns TRUE.\r
322**/\r
323VOID\r
324EFIAPI\r
325SmmCpuFeaturesDisableSmrr (\r
326 VOID\r
327 )\r
328{\r
76ec1752 329 if (FeaturePcdGet (PcdSmrrEnable) && mNeedConfigureMtrrs) {\r
053e878b 330 AsmWriteMsr64 (mSmrrPhysMaskMsr, AsmReadMsr64 (mSmrrPhysMaskMsr) & ~EFI_MSR_SMRR_PHYS_MASK_VALID);\r
a9764e68
MK
331 }\r
332}\r
333\r
334/**\r
335 Enable SMRR register if SMRR is supported and SmmCpuFeaturesNeedConfigureMtrrs()\r
336 returns TRUE.\r
337**/\r
338VOID\r
339EFIAPI\r
340SmmCpuFeaturesReenableSmrr (\r
341 VOID\r
342 )\r
343{\r
76ec1752 344 if (FeaturePcdGet (PcdSmrrEnable) && mNeedConfigureMtrrs) {\r
053e878b 345 AsmWriteMsr64 (mSmrrPhysMaskMsr, AsmReadMsr64 (mSmrrPhysMaskMsr) | EFI_MSR_SMRR_PHYS_MASK_VALID);\r
a9764e68
MK
346 }\r
347}\r
348\r
349/**\r
350 Processor specific hook point each time a CPU enters System Management Mode.\r
351\r
352 @param[in] CpuIndex The index of the CPU that has entered SMM. The value\r
353 must be between 0 and the NumberOfCpus field in the\r
354 System Management System Table (SMST).\r
355**/\r
356VOID\r
357EFIAPI\r
358SmmCpuFeaturesRendezvousEntry (\r
359 IN UINTN CpuIndex\r
360 )\r
361{\r
362 //\r
363 // If SMRR is supported and this is the first normal SMI, then enable SMRR\r
364 //\r
76ec1752 365 if (FeaturePcdGet (PcdSmrrEnable) && !mSmrrEnabled[CpuIndex]) {\r
a9764e68
MK
366 AsmWriteMsr64 (mSmrrPhysMaskMsr, AsmReadMsr64 (mSmrrPhysMaskMsr) | EFI_MSR_SMRR_PHYS_MASK_VALID);\r
367 mSmrrEnabled[CpuIndex] = TRUE;\r
368 }\r
369}\r
370\r
a9764e68
MK
371/**\r
372 Returns the current value of the SMM register for the specified CPU.\r
373 If the SMM register is not supported, then 0 is returned.\r
374\r
375 @param[in] CpuIndex The index of the CPU to read the SMM register. The\r
376 value must be between 0 and the NumberOfCpus field in\r
377 the System Management System Table (SMST).\r
378 @param[in] RegName Identifies the SMM register to read.\r
379\r
380 @return The value of the SMM register specified by RegName from the CPU\r
381 specified by CpuIndex.\r
382**/\r
383UINT64\r
384EFIAPI\r
385SmmCpuFeaturesGetSmmRegister (\r
386 IN UINTN CpuIndex,\r
387 IN SMM_REG_NAME RegName\r
388 )\r
389{\r
76ec1752 390 if (FeaturePcdGet (PcdSmmFeatureControlEnable) && (RegName == SmmRegFeatureControl)) {\r
d26a7a3f
MK
391 return AsmReadMsr64 (SMM_FEATURES_LIB_SMM_FEATURE_CONTROL);\r
392 }\r
053e878b 393\r
a9764e68
MK
394 return 0;\r
395}\r
396\r
397/**\r
398 Sets the value of an SMM register on a specified CPU.\r
399 If the SMM register is not supported, then no action is performed.\r
400\r
401 @param[in] CpuIndex The index of the CPU to write the SMM register. The\r
402 value must be between 0 and the NumberOfCpus field in\r
403 the System Management System Table (SMST).\r
404 @param[in] RegName Identifies the SMM register to write.\r
405 registers are read-only.\r
406 @param[in] Value The value to write to the SMM register.\r
407**/\r
408VOID\r
409EFIAPI\r
410SmmCpuFeaturesSetSmmRegister (\r
411 IN UINTN CpuIndex,\r
412 IN SMM_REG_NAME RegName,\r
413 IN UINT64 Value\r
414 )\r
415{\r
76ec1752 416 if (FeaturePcdGet (PcdSmmFeatureControlEnable) && (RegName == SmmRegFeatureControl)) {\r
d26a7a3f
MK
417 AsmWriteMsr64 (SMM_FEATURES_LIB_SMM_FEATURE_CONTROL, Value);\r
418 }\r
a9764e68 419}\r