VirtualBox

source: vbox/trunk/src/VBox/Devices/EFI/FirmwareNew/UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.c@ 109019

Last change on this file since 109019 was 108794, checked in by vboxsync, 4 weeks ago

Devices/EFI/FirmwareNew: Merge edk2-stable202502 from the vendor branch and make it build for the important platforms, bugref:4643

  • Property svn:eol-style set to native
File size: 10.7 KB
Line 
1/** @file
2Agent Module to load other modules to deploy SMM Entry Vector for X86 CPU.
3
4Copyright (c) 2009 - 2024, Intel Corporation. All rights reserved.<BR>
5Copyright (c) 2017, AMD Incorporated. All rights reserved.<BR>
6Copyright (C) 2023 - 2024 Advanced Micro Devices, Inc. All rights reserved.<BR>
7
8SPDX-License-Identifier: BSD-2-Clause-Patent
9
10**/
11
12#include "PiSmmCpuCommon.h"
13#include <Library/UefiBootServicesTableLib.h>
14
15//
16// TRUE to indicate it's the MM_STANDALONE MM CPU driver.
17// FALSE to indicate it's the DXE_SMM_DRIVER SMM CPU driver.
18//
19const BOOLEAN mIsStandaloneMm = FALSE;
20
21//
22// SMM ready to lock flag
23//
24BOOLEAN mSmmReadyToLock = FALSE;
25
26/**
27 Check SmmProfile is enabled or not.
28
29 @return TRUE SmmProfile is enabled.
30 FALSE SmmProfile is not enabled.
31
32**/
33BOOLEAN
34IsSmmProfileEnabled (
35 VOID
36 )
37{
38 return FeaturePcdGet (PcdCpuSmmProfileEnable);
39}
40
41/**
42 Perform the remaining tasks.
43
44**/
45VOID
46PerformRemainingTasks (
47 VOID
48 )
49{
50 EDKII_PI_SMM_MEMORY_ATTRIBUTES_TABLE *MemoryAttributesTable;
51
52 if (mSmmReadyToLock) {
53 PERF_FUNCTION_BEGIN ();
54
55 //
56 // Start SMM Profile feature
57 //
58 if (mSmmProfileEnabled) {
59 SmmProfileStart ();
60 }
61
62 //
63 // Check if all Aps enter SMM. In Relaxed-AP Sync Mode, BSP will not wait for
64 // all Aps arrive. However,PerformRemainingTasks() needs to wait all Aps arrive before calling
65 // SetMemMapAttributes() and ConfigSmmCodeAccessCheck() when mSmmReadyToLock
66 // is true. In SetMemMapAttributes(), SmmSetMemoryAttributesEx() will call
67 // FlushTlbForAll() that need to start up the aps. So it need to let all
68 // aps arrive. Same as SetMemMapAttributes(), ConfigSmmCodeAccessCheck()
69 // also will start up the aps.
70 //
71 if (EFI_ERROR (SmmCpuRendezvous (NULL, TRUE))) {
72 DEBUG ((DEBUG_ERROR, "PerformRemainingTasks: fail to wait for all AP check in SMM!\n"));
73 }
74
75 //
76 // Update Page Table for outside SMRAM.
77 //
78 if (mSmmProfileEnabled) {
79 SmmProfileUpdateMemoryAttributes ();
80 } else {
81 UpdateUefiMemMapAttributes ();
82 }
83
84 //
85 // gEdkiiPiSmmMemoryAttributesTableGuid should have been published at EndOfDxe by SmmCore
86 // Note: gEdkiiPiSmmMemoryAttributesTableGuid is not always installed since it depends on
87 // the memory protection attribute setting in MM Core.
88 //
89 SmmGetSystemConfigurationTable (&gEdkiiPiSmmMemoryAttributesTableGuid, (VOID **)&MemoryAttributesTable);
90
91 //
92 // Set critical region attribute in page table according to the MemoryAttributesTable
93 //
94 if (MemoryAttributesTable != NULL) {
95 SetMemMapAttributes (MemoryAttributesTable);
96 }
97
98 //
99 // Set page table itself to be read-only
100 //
101 SetPageTableAttributes ();
102
103 //
104 // Configure SMM Code Access Check feature if available.
105 //
106 ConfigSmmCodeAccessCheck ();
107
108 //
109 // Measure performance of SmmCpuFeaturesCompleteSmmReadyToLock() from caller side
110 // as the implementation is provided by platform.
111 //
112 PERF_START (NULL, "SmmCompleteReadyToLock", NULL, 0);
113 SmmCpuFeaturesCompleteSmmReadyToLock ();
114 PERF_END (NULL, "SmmCompleteReadyToLock", NULL, 0);
115
116 //
117 // Clean SMM ready to lock flag
118 //
119 mSmmReadyToLock = FALSE;
120
121 PERF_FUNCTION_END ();
122 }
123}
124
125/**
126 To get system port address of the SMI Command Port in FADT table.
127
128**/
129VOID
130GetSmiCommandPort (
131 VOID
132 )
133{
134 EFI_ACPI_2_0_FIXED_ACPI_DESCRIPTION_TABLE *Fadt;
135
136 Fadt = (EFI_ACPI_2_0_FIXED_ACPI_DESCRIPTION_TABLE *)EfiLocateFirstAcpiTable (
137 EFI_ACPI_2_0_FIXED_ACPI_DESCRIPTION_TABLE_SIGNATURE
138 );
139
140 if (Fadt == NULL) {
141 ASSERT (Fadt != NULL);
142 return;
143 }
144
145 mSmiCommandPort = Fadt->SmiCmd;
146 DEBUG ((DEBUG_INFO, "mSmiCommandPort = %x\n", mSmiCommandPort));
147}
148
149/**
150 SMM Ready To Lock event notification handler.
151
152 mSmmReadyToLock is set to perform additional lock actions that must be
153 performed from SMM on the next SMI.
154
155 @param[in] Protocol Points to the protocol's unique identifier.
156 @param[in] Interface Points to the interface instance.
157 @param[in] Handle The handle on which the interface was installed.
158
159 @retval EFI_SUCCESS Notification handler runs successfully.
160 **/
161EFI_STATUS
162EFIAPI
163SmmReadyToLockEventNotify (
164 IN CONST EFI_GUID *Protocol,
165 IN VOID *Interface,
166 IN EFI_HANDLE Handle
167 )
168{
169 //
170 // Cache a copy of UEFI memory map before we start profiling feature.
171 //
172 GetUefiMemoryMap ();
173
174 //
175 // Skip SMM profile initialization if feature is disabled
176 //
177 if (mSmmProfileEnabled) {
178 //
179 // Get Software SMI from FADT
180 //
181 GetSmiCommandPort ();
182
183 //
184 // Initialize protected memory range for patching page table later.
185 //
186 InitProtectedMemRange ();
187 }
188
189 //
190 // Set SMM ready to lock flag and return
191 //
192 mSmmReadyToLock = TRUE;
193 return EFI_SUCCESS;
194}
195
196/**
197 Get SmmCpuSyncConfig data: RelaxedMode, SyncTimeout, SyncTimeout2.
198
199 @param[in,out] RelaxedMode It indicates if Relaxed CPU synchronization method or
200 traditional CPU synchronization method is used when processing an SMI.
201 @param[in,out] SyncTimeout It indicates the 1st BSP/AP synchronization timeout value in SMM.
202 @param[in,out] SyncTimeout2 It indicates the 2nd BSP/AP synchronization timeout value in SMM.
203
204 **/
205VOID
206GetSmmCpuSyncConfigData (
207 IN OUT BOOLEAN *RelaxedMode, OPTIONAL
208 IN OUT UINT64 *SyncTimeout, OPTIONAL
209 IN OUT UINT64 *SyncTimeout2 OPTIONAL
210 )
211{
212 if (RelaxedMode != NULL) {
213 *RelaxedMode = (BOOLEAN)(PcdGet8 (PcdCpuSmmSyncMode) == MmCpuSyncModeRelaxedAp);
214 }
215
216 if (SyncTimeout != NULL) {
217 *SyncTimeout = PcdGet64 (PcdCpuSmmApSyncTimeout);
218 }
219
220 if (SyncTimeout2 != NULL) {
221 *SyncTimeout2 = PcdGet64 (PcdCpuSmmApSyncTimeout2);
222 }
223}
224
225/**
226 Get ACPI S3 enable flag.
227
228**/
229VOID
230GetAcpiS3EnableFlag (
231 VOID
232 )
233{
234 mAcpiS3Enable = PcdGetBool (PcdAcpiS3Enable);
235}
236
237/**
238 Get the maximum number of logical processors supported by the system.
239
240 @retval The maximum number of logical processors supported by the system
241 is indicated by the return value.
242**/
243UINTN
244GetSupportedMaxLogicalProcessorNumber (
245 VOID
246 )
247{
248 return PcdGet32 (PcdCpuMaxLogicalProcessorNumber);
249}
250
251/**
252 Extract NumberOfCpus, MaxNumberOfCpus and EFI_PROCESSOR_INFORMATION for all CPU from gEfiMpServiceProtocolGuid.
253
254 @param[out] NumberOfCpus Pointer to NumberOfCpus.
255 @param[out] MaxNumberOfCpus Pointer to MaxNumberOfCpus.
256
257 @retval ProcessorInfo Pointer to EFI_PROCESSOR_INFORMATION buffer.
258**/
259EFI_PROCESSOR_INFORMATION *
260GetMpInformationFromMpServices (
261 OUT UINTN *NumberOfCpus,
262 OUT UINTN *MaxNumberOfCpus
263 )
264{
265 EFI_STATUS Status;
266 UINTN Index;
267 UINTN NumberOfEnabledProcessors;
268 UINTN NumberOfProcessors;
269 EFI_MP_SERVICES_PROTOCOL *MpService;
270 EFI_PROCESSOR_INFORMATION *ProcessorInfo;
271
272 if ((NumberOfCpus == NULL) || (MaxNumberOfCpus == NULL)) {
273 ASSERT_EFI_ERROR (EFI_INVALID_PARAMETER);
274 return NULL;
275 }
276
277 ProcessorInfo = NULL;
278 *NumberOfCpus = 0;
279 *MaxNumberOfCpus = 0;
280
281 /// Get the MP Services Protocol
282 Status = gBS->LocateProtocol (&gEfiMpServiceProtocolGuid, NULL, (VOID **)&MpService);
283 if (EFI_ERROR (Status)) {
284 ASSERT_EFI_ERROR (Status);
285 return NULL;
286 }
287
288 /// Get the number of processors
289 Status = MpService->GetNumberOfProcessors (MpService, &NumberOfProcessors, &NumberOfEnabledProcessors);
290 if (EFI_ERROR (Status)) {
291 ASSERT_EFI_ERROR (Status);
292 return NULL;
293 }
294
295 ASSERT (NumberOfProcessors <= GetSupportedMaxLogicalProcessorNumber ());
296
297 /// Allocate buffer for processor information
298 ProcessorInfo = AllocateZeroPool (sizeof (EFI_PROCESSOR_INFORMATION) * NumberOfProcessors);
299 if (ProcessorInfo == NULL) {
300 ASSERT_EFI_ERROR (EFI_OUT_OF_RESOURCES);
301 return NULL;
302 }
303
304 /// Get processor information
305 for (Index = 0; Index < NumberOfProcessors; Index++) {
306 Status = MpService->GetProcessorInfo (MpService, Index | CPU_V2_EXTENDED_TOPOLOGY, &ProcessorInfo[Index]);
307 if (EFI_ERROR (Status)) {
308 FreePool (ProcessorInfo);
309 DEBUG ((DEBUG_ERROR, "%a: Failed to get processor information for processor %d\n", __func__, Index));
310 ASSERT_EFI_ERROR (Status);
311 return NULL;
312 }
313 }
314
315 *NumberOfCpus = NumberOfEnabledProcessors;
316
317 ASSERT (*NumberOfCpus <= GetSupportedMaxLogicalProcessorNumber ());
318 //
319 // If support CPU hot plug, we need to allocate resources for possibly hot-added processors
320 //
321 if (FeaturePcdGet (PcdCpuHotPlugSupport)) {
322 *MaxNumberOfCpus = GetSupportedMaxLogicalProcessorNumber ();
323 } else {
324 *MaxNumberOfCpus = *NumberOfCpus;
325 }
326
327 return ProcessorInfo;
328}
329
330/**
331 The module Entry Point of the CPU SMM driver.
332
333 @param ImageHandle The firmware allocated handle for the EFI image.
334 @param SystemTable A pointer to the EFI System Table.
335
336 @retval EFI_SUCCESS The entry point is executed successfully.
337 @retval Other Some error occurs when executing this entry point.
338
339**/
340EFI_STATUS
341EFIAPI
342PiCpuSmmEntry (
343 IN EFI_HANDLE ImageHandle,
344 IN EFI_SYSTEM_TABLE *SystemTable
345 )
346{
347 EFI_STATUS Status;
348 VOID *Registration;
349
350 //
351 // Save the PcdPteMemoryEncryptionAddressOrMask value into a global variable.
352 // Make sure AddressEncMask is contained to smallest supported address field.
353 //
354 mAddressEncMask = PcdGet64 (PcdPteMemoryEncryptionAddressOrMask) & PAGING_1G_ADDRESS_MASK_64;
355 DEBUG ((DEBUG_INFO, "mAddressEncMask = 0x%lx\n", mAddressEncMask));
356
357 Status = PiSmmCpuEntryCommon ();
358
359 ASSERT_EFI_ERROR (Status);
360
361 //
362 // Install the SMM Configuration Protocol onto a new handle on the handle database.
363 // The entire SMM Configuration Protocol is allocated from SMRAM, so only a pointer
364 // to an SMRAM address will be present in the handle database
365 //
366 Status = SystemTable->BootServices->InstallMultipleProtocolInterfaces (
367 &gSmmCpuPrivate->SmmCpuHandle,
368 &gEfiSmmConfigurationProtocolGuid,
369 &gSmmCpuPrivate->SmmConfiguration,
370 NULL
371 );
372 ASSERT_EFI_ERROR (Status);
373
374 //
375 // Expose address of CPU Hot Plug Data structure if CPU hot plug is supported.
376 //
377 if (FeaturePcdGet (PcdCpuHotPlugSupport)) {
378 Status = PcdSet64S (PcdCpuHotPlugDataAddress, (UINT64)(UINTN)&mCpuHotPlugData);
379 ASSERT_EFI_ERROR (Status);
380 }
381
382 //
383 // Register SMM Ready To Lock Protocol notification
384 //
385 Status = gMmst->MmRegisterProtocolNotify (
386 &gEfiSmmReadyToLockProtocolGuid,
387 SmmReadyToLockEventNotify,
388 &Registration
389 );
390 ASSERT_EFI_ERROR (Status);
391
392 return Status;
393}
Note: See TracBrowser for help on using the repository browser.

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