VirtualBox

source: vbox/trunk/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/SmmCpuFeaturesLib/IntelSmmCpuFeaturesLib.c

Last change on this file was 101291, checked in by vboxsync, 14 months ago

EFI/FirmwareNew: Make edk2-stable202308 build on all supported platforms (using gcc at least, msvc not tested yet), bugref:4643

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

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette