]> git.proxmox.com Git - mirror_edk2.git/blame - UefiCpuPkg/PiSmmCpuDxeSmm/MpService.c
UefiCpuPkg: Replace Opcode with the corresponding instructions.
[mirror_edk2.git] / UefiCpuPkg / PiSmmCpuDxeSmm / MpService.c
CommitLineData
529a5a86
MK
1/** @file\r
2SMM MP service implementation\r
3\r
54ba08c6 4Copyright (c) 2009 - 2021, Intel Corporation. All rights reserved.<BR>\r
241f9149
LD
5Copyright (c) 2017, AMD Incorporated. All rights reserved.<BR>\r
6\r
0acd8697 7SPDX-License-Identifier: BSD-2-Clause-Patent\r
529a5a86
MK
8\r
9**/\r
10\r
11#include "PiSmmCpuDxeSmm.h"\r
12\r
13//\r
14// Slots for all MTRR( FIXED MTRR + VARIABLE MTRR + MTRR_LIB_IA32_MTRR_DEF_TYPE)\r
15//\r
053e878b
MK
16MTRR_SETTINGS gSmiMtrrs;\r
17UINT64 gPhyMask;\r
18SMM_DISPATCHER_MP_SYNC_DATA *mSmmMpSyncData = NULL;\r
19UINTN mSmmMpSyncDataSize;\r
20SMM_CPU_SEMAPHORES mSmmCpuSemaphores;\r
21UINTN mSemaphoreSize;\r
22SPIN_LOCK *mPFLock = NULL;\r
23SMM_CPU_SYNC_MODE mCpuSmmSyncMode;\r
24BOOLEAN mMachineCheckSupported = FALSE;\r
25MM_COMPLETION mSmmStartupThisApToken;\r
26\r
27extern UINTN mSmmShadowStackSize;\r
ef91b073 28\r
529a5a86
MK
29/**\r
30 Performs an atomic compare exchange operation to get semaphore.\r
31 The compare exchange operation must be performed using\r
32 MP safe mechanisms.\r
33\r
34 @param Sem IN: 32-bit unsigned integer\r
35 OUT: original integer - 1\r
36 @return Original integer - 1\r
37\r
38**/\r
39UINT32\r
40WaitForSemaphore (\r
053e878b 41 IN OUT volatile UINT32 *Sem\r
529a5a86
MK
42 )\r
43{\r
053e878b 44 UINT32 Value;\r
529a5a86 45\r
053e878b 46 for ( ; ;) {\r
529a5a86 47 Value = *Sem;\r
053e878b
MK
48 if ((Value != 0) &&\r
49 (InterlockedCompareExchange32 (\r
50 (UINT32 *)Sem,\r
51 Value,\r
52 Value - 1\r
53 ) == Value))\r
54 {\r
9001b750
LE
55 break;\r
56 }\r
053e878b 57\r
9001b750
LE
58 CpuPause ();\r
59 }\r
053e878b 60\r
529a5a86
MK
61 return Value - 1;\r
62}\r
63\r
529a5a86
MK
64/**\r
65 Performs an atomic compare exchange operation to release semaphore.\r
66 The compare exchange operation must be performed using\r
67 MP safe mechanisms.\r
68\r
69 @param Sem IN: 32-bit unsigned integer\r
70 OUT: original integer + 1\r
71 @return Original integer + 1\r
72\r
73**/\r
74UINT32\r
75ReleaseSemaphore (\r
053e878b 76 IN OUT volatile UINT32 *Sem\r
529a5a86
MK
77 )\r
78{\r
053e878b 79 UINT32 Value;\r
529a5a86
MK
80\r
81 do {\r
82 Value = *Sem;\r
83 } while (Value + 1 != 0 &&\r
84 InterlockedCompareExchange32 (\r
053e878b 85 (UINT32 *)Sem,\r
529a5a86
MK
86 Value,\r
87 Value + 1\r
88 ) != Value);\r
053e878b 89\r
529a5a86
MK
90 return Value + 1;\r
91}\r
92\r
93/**\r
94 Performs an atomic compare exchange operation to lock semaphore.\r
95 The compare exchange operation must be performed using\r
96 MP safe mechanisms.\r
97\r
98 @param Sem IN: 32-bit unsigned integer\r
99 OUT: -1\r
100 @return Original integer\r
101\r
102**/\r
103UINT32\r
104LockdownSemaphore (\r
053e878b 105 IN OUT volatile UINT32 *Sem\r
529a5a86
MK
106 )\r
107{\r
053e878b 108 UINT32 Value;\r
529a5a86
MK
109\r
110 do {\r
111 Value = *Sem;\r
112 } while (InterlockedCompareExchange32 (\r
053e878b
MK
113 (UINT32 *)Sem,\r
114 Value,\r
115 (UINT32)-1\r
529a5a86 116 ) != Value);\r
053e878b 117\r
529a5a86
MK
118 return Value;\r
119}\r
120\r
121/**\r
122 Wait all APs to performs an atomic compare exchange operation to release semaphore.\r
123\r
124 @param NumberOfAPs AP number\r
125\r
126**/\r
127VOID\r
128WaitForAllAPs (\r
053e878b 129 IN UINTN NumberOfAPs\r
529a5a86
MK
130 )\r
131{\r
053e878b 132 UINTN BspIndex;\r
529a5a86
MK
133\r
134 BspIndex = mSmmMpSyncData->BspIndex;\r
135 while (NumberOfAPs-- > 0) {\r
ed3d5ecb 136 WaitForSemaphore (mSmmMpSyncData->CpuData[BspIndex].Run);\r
529a5a86
MK
137 }\r
138}\r
139\r
140/**\r
141 Performs an atomic compare exchange operation to release semaphore\r
142 for each AP.\r
143\r
144**/\r
145VOID\r
146ReleaseAllAPs (\r
147 VOID\r
148 )\r
149{\r
053e878b 150 UINTN Index;\r
529a5a86 151\r
70911f1f 152 for (Index = 0; Index < mMaxNumberOfCpus; Index++) {\r
51dd408a 153 if (IsPresentAp (Index)) {\r
ed3d5ecb 154 ReleaseSemaphore (mSmmMpSyncData->CpuData[Index].Run);\r
529a5a86
MK
155 }\r
156 }\r
157}\r
158\r
159/**\r
160 Checks if all CPUs (with certain exceptions) have checked in for this SMI run\r
161\r
162 @param Exceptions CPU Arrival exception flags.\r
163\r
164 @retval TRUE if all CPUs the have checked in.\r
165 @retval FALSE if at least one Normal AP hasn't checked in.\r
166\r
167**/\r
168BOOLEAN\r
169AllCpusInSmmWithExceptions (\r
170 SMM_CPU_ARRIVAL_EXCEPTIONS Exceptions\r
171 )\r
172{\r
053e878b
MK
173 UINTN Index;\r
174 SMM_CPU_DATA_BLOCK *CpuData;\r
175 EFI_PROCESSOR_INFORMATION *ProcessorInfo;\r
529a5a86 176\r
fe3a75bc 177 ASSERT (*mSmmMpSyncData->Counter <= mNumberOfCpus);\r
529a5a86 178\r
fe3a75bc 179 if (*mSmmMpSyncData->Counter == mNumberOfCpus) {\r
529a5a86
MK
180 return TRUE;\r
181 }\r
182\r
053e878b 183 CpuData = mSmmMpSyncData->CpuData;\r
529a5a86 184 ProcessorInfo = gSmmCpuPrivate->ProcessorInfo;\r
70911f1f 185 for (Index = 0; Index < mMaxNumberOfCpus; Index++) {\r
053e878b
MK
186 if (!(*(CpuData[Index].Present)) && (ProcessorInfo[Index].ProcessorId != INVALID_APIC_ID)) {\r
187 if (((Exceptions & ARRIVAL_EXCEPTION_DELAYED) != 0) && (SmmCpuFeaturesGetSmmRegister (Index, SmmRegSmmDelayed) != 0)) {\r
529a5a86
MK
188 continue;\r
189 }\r
053e878b
MK
190\r
191 if (((Exceptions & ARRIVAL_EXCEPTION_BLOCKED) != 0) && (SmmCpuFeaturesGetSmmRegister (Index, SmmRegSmmBlocked) != 0)) {\r
529a5a86
MK
192 continue;\r
193 }\r
053e878b
MK
194\r
195 if (((Exceptions & ARRIVAL_EXCEPTION_SMI_DISABLED) != 0) && (SmmCpuFeaturesGetSmmRegister (Index, SmmRegSmmEnable) != 0)) {\r
529a5a86
MK
196 continue;\r
197 }\r
053e878b 198\r
529a5a86
MK
199 return FALSE;\r
200 }\r
201 }\r
202\r
529a5a86
MK
203 return TRUE;\r
204}\r
205\r
12c66382
ED
206/**\r
207 Has OS enabled Lmce in the MSR_IA32_MCG_EXT_CTL\r
7367cc6c 208\r
12c66382
ED
209 @retval TRUE Os enable lmce.\r
210 @retval FALSE Os not enable lmce.\r
211\r
212**/\r
213BOOLEAN\r
214IsLmceOsEnabled (\r
215 VOID\r
216 )\r
217{\r
218 MSR_IA32_MCG_CAP_REGISTER McgCap;\r
219 MSR_IA32_FEATURE_CONTROL_REGISTER FeatureCtrl;\r
220 MSR_IA32_MCG_EXT_CTL_REGISTER McgExtCtrl;\r
221\r
222 McgCap.Uint64 = AsmReadMsr64 (MSR_IA32_MCG_CAP);\r
223 if (McgCap.Bits.MCG_LMCE_P == 0) {\r
224 return FALSE;\r
225 }\r
226\r
227 FeatureCtrl.Uint64 = AsmReadMsr64 (MSR_IA32_FEATURE_CONTROL);\r
228 if (FeatureCtrl.Bits.LmceOn == 0) {\r
229 return FALSE;\r
230 }\r
231\r
232 McgExtCtrl.Uint64 = AsmReadMsr64 (MSR_IA32_MCG_EXT_CTL);\r
053e878b 233 return (BOOLEAN)(McgExtCtrl.Bits.LMCE_EN == 1);\r
12c66382
ED
234}\r
235\r
236/**\r
7367cc6c 237 Return if Local machine check exception signaled.\r
12c66382 238\r
7367cc6c 239 Indicates (when set) that a local machine check exception was generated. This indicates that the current machine-check event was\r
12c66382
ED
240 delivered to only the logical processor.\r
241\r
242 @retval TRUE LMCE was signaled.\r
243 @retval FALSE LMCE was not signaled.\r
244\r
245**/\r
246BOOLEAN\r
247IsLmceSignaled (\r
248 VOID\r
249 )\r
250{\r
053e878b 251 MSR_IA32_MCG_STATUS_REGISTER McgStatus;\r
12c66382
ED
252\r
253 McgStatus.Uint64 = AsmReadMsr64 (MSR_IA32_MCG_STATUS);\r
053e878b 254 return (BOOLEAN)(McgStatus.Bits.LMCE_S == 1);\r
12c66382 255}\r
529a5a86
MK
256\r
257/**\r
258 Given timeout constraint, wait for all APs to arrive, and insure when this function returns, no AP will execute normal mode code before\r
259 entering SMM, except SMI disabled APs.\r
260\r
261**/\r
262VOID\r
263SmmWaitForApArrival (\r
264 VOID\r
265 )\r
266{\r
053e878b
MK
267 UINT64 Timer;\r
268 UINTN Index;\r
269 BOOLEAN LmceEn;\r
270 BOOLEAN LmceSignal;\r
529a5a86 271\r
fe3a75bc 272 ASSERT (*mSmmMpSyncData->Counter <= mNumberOfCpus);\r
529a5a86 273\r
ba40cb31
MK
274 LmceEn = FALSE;\r
275 LmceSignal = FALSE;\r
276 if (mMachineCheckSupported) {\r
277 LmceEn = IsLmceOsEnabled ();\r
053e878b 278 LmceSignal = IsLmceSignaled ();\r
ba40cb31 279 }\r
12c66382 280\r
529a5a86
MK
281 //\r
282 // Platform implementor should choose a timeout value appropriately:\r
283 // - The timeout value should balance the SMM time constrains and the likelihood that delayed CPUs are excluded in the SMM run. Note\r
284 // the SMI Handlers must ALWAYS take into account the cases that not all APs are available in an SMI run.\r
285 // - The timeout value must, in the case of 2nd timeout, be at least long enough to give time for all APs to receive the SMI IPI\r
286 // and either enter SMM or buffer the SMI, to insure there is no CPU running normal mode code when SMI handling starts. This will\r
287 // be TRUE even if a blocked CPU is brought out of the blocked state by a normal mode CPU (before the normal mode CPU received the\r
288 // SMI IPI), because with a buffered SMI, and CPU will enter SMM immediately after it is brought out of the blocked state.\r
289 // - The timeout value must be longer than longest possible IO operation in the system\r
290 //\r
291\r
292 //\r
293 // Sync with APs 1st timeout\r
294 //\r
295 for (Timer = StartSyncTimer ();\r
12c66382 296 !IsSyncTimerTimeout (Timer) && !(LmceEn && LmceSignal) &&\r
053e878b
MK
297 !AllCpusInSmmWithExceptions (ARRIVAL_EXCEPTION_BLOCKED | ARRIVAL_EXCEPTION_SMI_DISABLED);\r
298 )\r
299 {\r
529a5a86
MK
300 CpuPause ();\r
301 }\r
302\r
303 //\r
304 // Not all APs have arrived, so we need 2nd round of timeout. IPIs should be sent to ALL none present APs,\r
305 // because:\r
306 // a) Delayed AP may have just come out of the delayed state. Blocked AP may have just been brought out of blocked state by some AP running\r
307 // normal mode code. These APs need to be guaranteed to have an SMI pending to insure that once they are out of delayed / blocked state, they\r
308 // enter SMI immediately without executing instructions in normal mode. Note traditional flow requires there are no APs doing normal mode\r
309 // work while SMI handling is on-going.\r
310 // b) As a consequence of SMI IPI sending, (spurious) SMI may occur after this SMM run.\r
311 // c) ** NOTE **: Use SMI disabling feature VERY CAREFULLY (if at all) for traditional flow, because a processor in SMI-disabled state\r
312 // will execute normal mode code, which breaks the traditional SMI handlers' assumption that no APs are doing normal\r
313 // mode work while SMI handling is on-going.\r
314 // d) We don't add code to check SMI disabling status to skip sending IPI to SMI disabled APs, because:\r
315 // - In traditional flow, SMI disabling is discouraged.\r
316 // - In relaxed flow, CheckApArrival() will check SMI disabling status before calling this function.\r
317 // In both cases, adding SMI-disabling checking code increases overhead.\r
318 //\r
fe3a75bc 319 if (*mSmmMpSyncData->Counter < mNumberOfCpus) {\r
529a5a86
MK
320 //\r
321 // Send SMI IPIs to bring outside processors in\r
322 //\r
70911f1f 323 for (Index = 0; Index < mMaxNumberOfCpus; Index++) {\r
053e878b 324 if (!(*(mSmmMpSyncData->CpuData[Index].Present)) && (gSmmCpuPrivate->ProcessorInfo[Index].ProcessorId != INVALID_APIC_ID)) {\r
529a5a86
MK
325 SendSmiIpi ((UINT32)gSmmCpuPrivate->ProcessorInfo[Index].ProcessorId);\r
326 }\r
327 }\r
328\r
329 //\r
330 // Sync with APs 2nd timeout.\r
331 //\r
332 for (Timer = StartSyncTimer ();\r
333 !IsSyncTimerTimeout (Timer) &&\r
053e878b
MK
334 !AllCpusInSmmWithExceptions (ARRIVAL_EXCEPTION_BLOCKED | ARRIVAL_EXCEPTION_SMI_DISABLED);\r
335 )\r
336 {\r
529a5a86
MK
337 CpuPause ();\r
338 }\r
339 }\r
340\r
341 return;\r
342}\r
343\r
529a5a86
MK
344/**\r
345 Replace OS MTRR's with SMI MTRR's.\r
346\r
347 @param CpuIndex Processor Index\r
348\r
349**/\r
350VOID\r
351ReplaceOSMtrrs (\r
053e878b 352 IN UINTN CpuIndex\r
529a5a86
MK
353 )\r
354{\r
529a5a86
MK
355 SmmCpuFeaturesDisableSmrr ();\r
356\r
357 //\r
358 // Replace all MTRRs registers\r
359 //\r
26ab5ac3 360 MtrrSetAllMtrrs (&gSmiMtrrs);\r
529a5a86
MK
361}\r
362\r
51dd408a
ED
363/**\r
364 Wheck whether task has been finished by all APs.\r
365\r
366 @param BlockMode Whether did it in block mode or non-block mode.\r
367\r
368 @retval TRUE Task has been finished by all APs.\r
369 @retval FALSE Task not has been finished by all APs.\r
370\r
371**/\r
372BOOLEAN\r
373WaitForAllAPsNotBusy (\r
053e878b 374 IN BOOLEAN BlockMode\r
51dd408a
ED
375 )\r
376{\r
053e878b 377 UINTN Index;\r
51dd408a 378\r
70911f1f 379 for (Index = 0; Index < mMaxNumberOfCpus; Index++) {\r
51dd408a
ED
380 //\r
381 // Ignore BSP and APs which not call in SMM.\r
382 //\r
053e878b 383 if (!IsPresentAp (Index)) {\r
51dd408a
ED
384 continue;\r
385 }\r
386\r
387 if (BlockMode) {\r
053e878b
MK
388 AcquireSpinLock (mSmmMpSyncData->CpuData[Index].Busy);\r
389 ReleaseSpinLock (mSmmMpSyncData->CpuData[Index].Busy);\r
51dd408a
ED
390 } else {\r
391 if (AcquireSpinLockOrFail (mSmmMpSyncData->CpuData[Index].Busy)) {\r
053e878b 392 ReleaseSpinLock (mSmmMpSyncData->CpuData[Index].Busy);\r
51dd408a
ED
393 } else {\r
394 return FALSE;\r
395 }\r
396 }\r
397 }\r
398\r
399 return TRUE;\r
400}\r
401\r
402/**\r
403 Check whether it is an present AP.\r
404\r
405 @param CpuIndex The AP index which calls this function.\r
406\r
407 @retval TRUE It's a present AP.\r
408 @retval TRUE This is not an AP or it is not present.\r
409\r
410**/\r
411BOOLEAN\r
412IsPresentAp (\r
053e878b 413 IN UINTN CpuIndex\r
51dd408a
ED
414 )\r
415{\r
416 return ((CpuIndex != gSmmCpuPrivate->SmmCoreEntryContext.CurrentlyExecutingCpu) &&\r
053e878b 417 *(mSmmMpSyncData->CpuData[CpuIndex].Present));\r
51dd408a
ED
418}\r
419\r
51dd408a
ED
420/**\r
421 Clean up the status flags used during executing the procedure.\r
422\r
423 @param CpuIndex The AP index which calls this function.\r
424\r
425**/\r
426VOID\r
427ReleaseToken (\r
053e878b 428 IN UINTN CpuIndex\r
51dd408a
ED
429 )\r
430{\r
053e878b 431 PROCEDURE_TOKEN *Token;\r
51dd408a 432\r
a457823f
ED
433 Token = mSmmMpSyncData->CpuData[CpuIndex].Token;\r
434\r
435 if (InterlockedDecrement (&Token->RunningApCount) == 0) {\r
436 ReleaseSpinLock (Token->SpinLock);\r
51dd408a 437 }\r
a457823f
ED
438\r
439 mSmmMpSyncData->CpuData[CpuIndex].Token = NULL;\r
51dd408a
ED
440}\r
441\r
442/**\r
443 Free the tokens in the maintained list.\r
444\r
445**/\r
446VOID\r
b948a496 447ResetTokens (\r
51dd408a
ED
448 VOID\r
449 )\r
450{\r
3fdc47c6
RN
451 //\r
452 // Reset the FirstFreeToken to the beginning of token list upon exiting SMI.\r
453 //\r
454 gSmmCpuPrivate->FirstFreeToken = GetFirstNode (&gSmmCpuPrivate->TokenList);\r
51dd408a
ED
455}\r
456\r
529a5a86
MK
457/**\r
458 SMI handler for BSP.\r
459\r
460 @param CpuIndex BSP processor Index\r
461 @param SyncMode SMM MP sync mode\r
462\r
463**/\r
464VOID\r
465BSPHandler (\r
053e878b
MK
466 IN UINTN CpuIndex,\r
467 IN SMM_CPU_SYNC_MODE SyncMode\r
529a5a86
MK
468 )\r
469{\r
053e878b
MK
470 UINTN Index;\r
471 MTRR_SETTINGS Mtrrs;\r
472 UINTN ApCount;\r
473 BOOLEAN ClearTopLevelSmiResult;\r
474 UINTN PresentCount;\r
529a5a86
MK
475\r
476 ASSERT (CpuIndex == mSmmMpSyncData->BspIndex);\r
477 ApCount = 0;\r
478\r
479 //\r
480 // Flag BSP's presence\r
481 //\r
fe3a75bc 482 *mSmmMpSyncData->InsideSmm = TRUE;\r
529a5a86
MK
483\r
484 //\r
485 // Initialize Debug Agent to start source level debug in BSP handler\r
486 //\r
487 InitializeDebugAgent (DEBUG_AGENT_INIT_ENTER_SMI, NULL, NULL);\r
488\r
489 //\r
490 // Mark this processor's presence\r
491 //\r
ed3d5ecb 492 *(mSmmMpSyncData->CpuData[CpuIndex].Present) = TRUE;\r
529a5a86
MK
493\r
494 //\r
495 // Clear platform top level SMI status bit before calling SMI handlers. If\r
496 // we cleared it after SMI handlers are run, we would miss the SMI that\r
497 // occurs after SMI handlers are done and before SMI status bit is cleared.\r
498 //\r
053e878b 499 ClearTopLevelSmiResult = ClearTopLevelSmiStatus ();\r
529a5a86
MK
500 ASSERT (ClearTopLevelSmiResult == TRUE);\r
501\r
502 //\r
503 // Set running processor index\r
504 //\r
505 gSmmCpuPrivate->SmmCoreEntryContext.CurrentlyExecutingCpu = CpuIndex;\r
506\r
507 //\r
508 // If Traditional Sync Mode or need to configure MTRRs: gather all available APs.\r
509 //\r
053e878b 510 if ((SyncMode == SmmCpuSyncModeTradition) || SmmCpuFeaturesNeedConfigureMtrrs ()) {\r
529a5a86
MK
511 //\r
512 // Wait for APs to arrive\r
513 //\r
053e878b 514 SmmWaitForApArrival ();\r
529a5a86
MK
515\r
516 //\r
517 // Lock the counter down and retrieve the number of APs\r
518 //\r
fe3a75bc 519 *mSmmMpSyncData->AllCpusInSync = TRUE;\r
053e878b 520 ApCount = LockdownSemaphore (mSmmMpSyncData->Counter) - 1;\r
529a5a86
MK
521\r
522 //\r
523 // Wait for all APs to get ready for programming MTRRs\r
524 //\r
525 WaitForAllAPs (ApCount);\r
526\r
053e878b 527 if (SmmCpuFeaturesNeedConfigureMtrrs ()) {\r
529a5a86
MK
528 //\r
529 // Signal all APs it's time for backup MTRRs\r
530 //\r
531 ReleaseAllAPs ();\r
532\r
533 //\r
534 // WaitForSemaphore() may wait for ever if an AP happens to enter SMM at\r
535 // exactly this point. Please make sure PcdCpuSmmMaxSyncLoops has been set\r
536 // to a large enough value to avoid this situation.\r
537 // Note: For HT capable CPUs, threads within a core share the same set of MTRRs.\r
538 // We do the backup first and then set MTRR to avoid race condition for threads\r
539 // in the same core.\r
540 //\r
053e878b 541 MtrrGetAllMtrrs (&Mtrrs);\r
529a5a86
MK
542\r
543 //\r
544 // Wait for all APs to complete their MTRR saving\r
545 //\r
546 WaitForAllAPs (ApCount);\r
547\r
548 //\r
549 // Let all processors program SMM MTRRs together\r
550 //\r
551 ReleaseAllAPs ();\r
552\r
553 //\r
554 // WaitForSemaphore() may wait for ever if an AP happens to enter SMM at\r
555 // exactly this point. Please make sure PcdCpuSmmMaxSyncLoops has been set\r
556 // to a large enough value to avoid this situation.\r
557 //\r
558 ReplaceOSMtrrs (CpuIndex);\r
559\r
560 //\r
561 // Wait for all APs to complete their MTRR programming\r
562 //\r
563 WaitForAllAPs (ApCount);\r
564 }\r
565 }\r
566\r
567 //\r
568 // The BUSY lock is initialized to Acquired state\r
569 //\r
170a3c1e 570 AcquireSpinLock (mSmmMpSyncData->CpuData[CpuIndex].Busy);\r
529a5a86
MK
571\r
572 //\r
9f419739 573 // Perform the pre tasks\r
529a5a86 574 //\r
9f419739 575 PerformPreTasks ();\r
529a5a86
MK
576\r
577 //\r
578 // Invoke SMM Foundation EntryPoint with the processor information context.\r
579 //\r
580 gSmmCpuPrivate->SmmCoreEntry (&gSmmCpuPrivate->SmmCoreEntryContext);\r
581\r
582 //\r
583 // Make sure all APs have completed their pending none-block tasks\r
584 //\r
51dd408a 585 WaitForAllAPsNotBusy (TRUE);\r
529a5a86
MK
586\r
587 //\r
588 // Perform the remaining tasks\r
589 //\r
590 PerformRemainingTasks ();\r
591\r
592 //\r
593 // If Relaxed-AP Sync Mode: gather all available APs after BSP SMM handlers are done, and\r
594 // make those APs to exit SMI synchronously. APs which arrive later will be excluded and\r
595 // will run through freely.\r
596 //\r
053e878b 597 if ((SyncMode != SmmCpuSyncModeTradition) && !SmmCpuFeaturesNeedConfigureMtrrs ()) {\r
529a5a86
MK
598 //\r
599 // Lock the counter down and retrieve the number of APs\r
600 //\r
fe3a75bc 601 *mSmmMpSyncData->AllCpusInSync = TRUE;\r
053e878b 602 ApCount = LockdownSemaphore (mSmmMpSyncData->Counter) - 1;\r
529a5a86
MK
603 //\r
604 // Make sure all APs have their Present flag set\r
605 //\r
606 while (TRUE) {\r
607 PresentCount = 0;\r
70911f1f 608 for (Index = 0; Index < mMaxNumberOfCpus; Index++) {\r
ed3d5ecb 609 if (*(mSmmMpSyncData->CpuData[Index].Present)) {\r
053e878b 610 PresentCount++;\r
529a5a86
MK
611 }\r
612 }\r
053e878b 613\r
529a5a86
MK
614 if (PresentCount > ApCount) {\r
615 break;\r
616 }\r
617 }\r
618 }\r
619\r
620 //\r
621 // Notify all APs to exit\r
622 //\r
fe3a75bc 623 *mSmmMpSyncData->InsideSmm = FALSE;\r
529a5a86
MK
624 ReleaseAllAPs ();\r
625\r
626 //\r
627 // Wait for all APs to complete their pending tasks\r
628 //\r
629 WaitForAllAPs (ApCount);\r
630\r
053e878b 631 if (SmmCpuFeaturesNeedConfigureMtrrs ()) {\r
529a5a86
MK
632 //\r
633 // Signal APs to restore MTRRs\r
634 //\r
635 ReleaseAllAPs ();\r
636\r
637 //\r
638 // Restore OS MTRRs\r
639 //\r
640 SmmCpuFeaturesReenableSmrr ();\r
053e878b 641 MtrrSetAllMtrrs (&Mtrrs);\r
529a5a86
MK
642\r
643 //\r
644 // Wait for all APs to complete MTRR programming\r
645 //\r
646 WaitForAllAPs (ApCount);\r
647 }\r
648\r
649 //\r
650 // Stop source level debug in BSP handler, the code below will not be\r
651 // debugged.\r
652 //\r
653 InitializeDebugAgent (DEBUG_AGENT_INIT_EXIT_SMI, NULL, NULL);\r
654\r
655 //\r
656 // Signal APs to Reset states/semaphore for this processor\r
657 //\r
658 ReleaseAllAPs ();\r
659\r
660 //\r
661 // Perform pending operations for hot-plug\r
662 //\r
663 SmmCpuUpdate ();\r
664\r
665 //\r
666 // Clear the Present flag of BSP\r
667 //\r
ed3d5ecb 668 *(mSmmMpSyncData->CpuData[CpuIndex].Present) = FALSE;\r
529a5a86
MK
669\r
670 //\r
671 // Gather APs to exit SMM synchronously. Note the Present flag is cleared by now but\r
672 // WaitForAllAps does not depend on the Present flag.\r
673 //\r
674 WaitForAllAPs (ApCount);\r
675\r
51dd408a 676 //\r
b948a496 677 // Reset the tokens buffer.\r
51dd408a 678 //\r
b948a496 679 ResetTokens ();\r
51dd408a 680\r
529a5a86
MK
681 //\r
682 // Reset BspIndex to -1, meaning BSP has not been elected.\r
683 //\r
684 if (FeaturePcdGet (PcdCpuSmmEnableBspElection)) {\r
685 mSmmMpSyncData->BspIndex = (UINT32)-1;\r
686 }\r
687\r
688 //\r
689 // Allow APs to check in from this point on\r
690 //\r
053e878b 691 *mSmmMpSyncData->Counter = 0;\r
fe3a75bc 692 *mSmmMpSyncData->AllCpusInSync = FALSE;\r
529a5a86
MK
693}\r
694\r
695/**\r
696 SMI handler for AP.\r
697\r
698 @param CpuIndex AP processor Index.\r
699 @param ValidSmi Indicates that current SMI is a valid SMI or not.\r
700 @param SyncMode SMM MP sync mode.\r
701\r
702**/\r
703VOID\r
704APHandler (\r
053e878b
MK
705 IN UINTN CpuIndex,\r
706 IN BOOLEAN ValidSmi,\r
707 IN SMM_CPU_SYNC_MODE SyncMode\r
529a5a86
MK
708 )\r
709{\r
053e878b
MK
710 UINT64 Timer;\r
711 UINTN BspIndex;\r
712 MTRR_SETTINGS Mtrrs;\r
713 EFI_STATUS ProcedureStatus;\r
529a5a86
MK
714\r
715 //\r
716 // Timeout BSP\r
717 //\r
718 for (Timer = StartSyncTimer ();\r
719 !IsSyncTimerTimeout (Timer) &&\r
fe3a75bc 720 !(*mSmmMpSyncData->InsideSmm);\r
053e878b
MK
721 )\r
722 {\r
529a5a86
MK
723 CpuPause ();\r
724 }\r
725\r
fe3a75bc 726 if (!(*mSmmMpSyncData->InsideSmm)) {\r
529a5a86
MK
727 //\r
728 // BSP timeout in the first round\r
729 //\r
730 if (mSmmMpSyncData->BspIndex != -1) {\r
731 //\r
732 // BSP Index is known\r
733 //\r
734 BspIndex = mSmmMpSyncData->BspIndex;\r
735 ASSERT (CpuIndex != BspIndex);\r
736\r
737 //\r
738 // Send SMI IPI to bring BSP in\r
739 //\r
740 SendSmiIpi ((UINT32)gSmmCpuPrivate->ProcessorInfo[BspIndex].ProcessorId);\r
741\r
742 //\r
743 // Now clock BSP for the 2nd time\r
744 //\r
745 for (Timer = StartSyncTimer ();\r
746 !IsSyncTimerTimeout (Timer) &&\r
fe3a75bc 747 !(*mSmmMpSyncData->InsideSmm);\r
053e878b
MK
748 )\r
749 {\r
529a5a86
MK
750 CpuPause ();\r
751 }\r
752\r
fe3a75bc 753 if (!(*mSmmMpSyncData->InsideSmm)) {\r
529a5a86
MK
754 //\r
755 // Give up since BSP is unable to enter SMM\r
756 // and signal the completion of this AP\r
fe3a75bc 757 WaitForSemaphore (mSmmMpSyncData->Counter);\r
529a5a86
MK
758 return;\r
759 }\r
760 } else {\r
761 //\r
762 // Don't know BSP index. Give up without sending IPI to BSP.\r
763 //\r
fe3a75bc 764 WaitForSemaphore (mSmmMpSyncData->Counter);\r
529a5a86
MK
765 return;\r
766 }\r
767 }\r
768\r
769 //\r
770 // BSP is available\r
771 //\r
772 BspIndex = mSmmMpSyncData->BspIndex;\r
773 ASSERT (CpuIndex != BspIndex);\r
774\r
775 //\r
776 // Mark this processor's presence\r
777 //\r
ed3d5ecb 778 *(mSmmMpSyncData->CpuData[CpuIndex].Present) = TRUE;\r
529a5a86 779\r
053e878b 780 if ((SyncMode == SmmCpuSyncModeTradition) || SmmCpuFeaturesNeedConfigureMtrrs ()) {\r
529a5a86
MK
781 //\r
782 // Notify BSP of arrival at this point\r
783 //\r
ed3d5ecb 784 ReleaseSemaphore (mSmmMpSyncData->CpuData[BspIndex].Run);\r
529a5a86
MK
785 }\r
786\r
053e878b 787 if (SmmCpuFeaturesNeedConfigureMtrrs ()) {\r
529a5a86
MK
788 //\r
789 // Wait for the signal from BSP to backup MTRRs\r
790 //\r
ed3d5ecb 791 WaitForSemaphore (mSmmMpSyncData->CpuData[CpuIndex].Run);\r
529a5a86
MK
792\r
793 //\r
794 // Backup OS MTRRs\r
795 //\r
053e878b 796 MtrrGetAllMtrrs (&Mtrrs);\r
529a5a86
MK
797\r
798 //\r
799 // Signal BSP the completion of this AP\r
800 //\r
ed3d5ecb 801 ReleaseSemaphore (mSmmMpSyncData->CpuData[BspIndex].Run);\r
529a5a86
MK
802\r
803 //\r
804 // Wait for BSP's signal to program MTRRs\r
805 //\r
ed3d5ecb 806 WaitForSemaphore (mSmmMpSyncData->CpuData[CpuIndex].Run);\r
529a5a86
MK
807\r
808 //\r
809 // Replace OS MTRRs with SMI MTRRs\r
810 //\r
811 ReplaceOSMtrrs (CpuIndex);\r
812\r
813 //\r
814 // Signal BSP the completion of this AP\r
815 //\r
ed3d5ecb 816 ReleaseSemaphore (mSmmMpSyncData->CpuData[BspIndex].Run);\r
529a5a86
MK
817 }\r
818\r
819 while (TRUE) {\r
820 //\r
821 // Wait for something to happen\r
822 //\r
ed3d5ecb 823 WaitForSemaphore (mSmmMpSyncData->CpuData[CpuIndex].Run);\r
529a5a86
MK
824\r
825 //\r
826 // Check if BSP wants to exit SMM\r
827 //\r
fe3a75bc 828 if (!(*mSmmMpSyncData->InsideSmm)) {\r
529a5a86
MK
829 break;\r
830 }\r
831\r
832 //\r
833 // BUSY should be acquired by SmmStartupThisAp()\r
834 //\r
835 ASSERT (\r
ed3d5ecb 836 !AcquireSpinLockOrFail (mSmmMpSyncData->CpuData[CpuIndex].Busy)\r
529a5a86
MK
837 );\r
838\r
839 //\r
840 // Invoke the scheduled procedure\r
841 //\r
053e878b
MK
842 ProcedureStatus = (*mSmmMpSyncData->CpuData[CpuIndex].Procedure)(\r
843 (VOID *)mSmmMpSyncData->CpuData[CpuIndex].Parameter\r
844 );\r
51dd408a
ED
845 if (mSmmMpSyncData->CpuData[CpuIndex].Status != NULL) {\r
846 *mSmmMpSyncData->CpuData[CpuIndex].Status = ProcedureStatus;\r
847 }\r
529a5a86 848\r
a457823f
ED
849 if (mSmmMpSyncData->CpuData[CpuIndex].Token != NULL) {\r
850 ReleaseToken (CpuIndex);\r
851 }\r
852\r
529a5a86
MK
853 //\r
854 // Release BUSY\r
855 //\r
ed3d5ecb 856 ReleaseSpinLock (mSmmMpSyncData->CpuData[CpuIndex].Busy);\r
529a5a86
MK
857 }\r
858\r
053e878b 859 if (SmmCpuFeaturesNeedConfigureMtrrs ()) {\r
529a5a86
MK
860 //\r
861 // Notify BSP the readiness of this AP to program MTRRs\r
862 //\r
ed3d5ecb 863 ReleaseSemaphore (mSmmMpSyncData->CpuData[BspIndex].Run);\r
529a5a86
MK
864\r
865 //\r
866 // Wait for the signal from BSP to program MTRRs\r
867 //\r
ed3d5ecb 868 WaitForSemaphore (mSmmMpSyncData->CpuData[CpuIndex].Run);\r
529a5a86
MK
869\r
870 //\r
871 // Restore OS MTRRs\r
872 //\r
873 SmmCpuFeaturesReenableSmrr ();\r
053e878b 874 MtrrSetAllMtrrs (&Mtrrs);\r
529a5a86
MK
875 }\r
876\r
877 //\r
878 // Notify BSP the readiness of this AP to Reset states/semaphore for this processor\r
879 //\r
ed3d5ecb 880 ReleaseSemaphore (mSmmMpSyncData->CpuData[BspIndex].Run);\r
529a5a86
MK
881\r
882 //\r
883 // Wait for the signal from BSP to Reset states/semaphore for this processor\r
884 //\r
ed3d5ecb 885 WaitForSemaphore (mSmmMpSyncData->CpuData[CpuIndex].Run);\r
529a5a86
MK
886\r
887 //\r
888 // Reset states/semaphore for this processor\r
889 //\r
ed3d5ecb 890 *(mSmmMpSyncData->CpuData[CpuIndex].Present) = FALSE;\r
529a5a86
MK
891\r
892 //\r
893 // Notify BSP the readiness of this AP to exit SMM\r
894 //\r
ed3d5ecb 895 ReleaseSemaphore (mSmmMpSyncData->CpuData[BspIndex].Run);\r
529a5a86
MK
896}\r
897\r
898/**\r
899 Create 4G PageTable in SMRAM.\r
900\r
717fb604 901 @param[in] Is32BitPageTable Whether the page table is 32-bit PAE\r
529a5a86
MK
902 @return PageTable Address\r
903\r
904**/\r
905UINT32\r
906Gen4GPageTable (\r
053e878b 907 IN BOOLEAN Is32BitPageTable\r
529a5a86
MK
908 )\r
909{\r
910 VOID *PageTable;\r
911 UINTN Index;\r
912 UINT64 *Pte;\r
913 UINTN PagesNeeded;\r
914 UINTN Low2MBoundary;\r
915 UINTN High2MBoundary;\r
916 UINTN Pages;\r
917 UINTN GuardPage;\r
918 UINT64 *Pdpte;\r
919 UINTN PageIndex;\r
920 UINTN PageAddress;\r
921\r
053e878b 922 Low2MBoundary = 0;\r
529a5a86 923 High2MBoundary = 0;\r
053e878b 924 PagesNeeded = 0;\r
529a5a86
MK
925 if (FeaturePcdGet (PcdCpuSmmStackGuard)) {\r
926 //\r
927 // Add one more page for known good stack, then find the lower 2MB aligned address.\r
928 //\r
929 Low2MBoundary = (mSmmStackArrayBase + EFI_PAGE_SIZE) & ~(SIZE_2MB-1);\r
930 //\r
931 // Add two more pages for known good stack and stack guard page,\r
932 // then find the lower 2MB aligned address.\r
933 //\r
ef91b073 934 High2MBoundary = (mSmmStackArrayEnd - mSmmStackSize - mSmmShadowStackSize + EFI_PAGE_SIZE * 2) & ~(SIZE_2MB-1);\r
053e878b 935 PagesNeeded = ((High2MBoundary - Low2MBoundary) / SIZE_2MB) + 1;\r
529a5a86 936 }\r
053e878b 937\r
529a5a86
MK
938 //\r
939 // Allocate the page table\r
940 //\r
717fb604 941 PageTable = AllocatePageTableMemory (5 + PagesNeeded);\r
529a5a86
MK
942 ASSERT (PageTable != NULL);\r
943\r
717fb604 944 PageTable = (VOID *)((UINTN)PageTable);\r
053e878b 945 Pte = (UINT64 *)PageTable;\r
529a5a86
MK
946\r
947 //\r
948 // Zero out all page table entries first\r
949 //\r
950 ZeroMem (Pte, EFI_PAGES_TO_SIZE (1));\r
951\r
952 //\r
953 // Set Page Directory Pointers\r
954 //\r
955 for (Index = 0; Index < 4; Index++) {\r
e62a0eb6 956 Pte[Index] = ((UINTN)PageTable + EFI_PAGE_SIZE * (Index + 1)) | mAddressEncMask |\r
053e878b 957 (Is32BitPageTable ? IA32_PAE_PDPTE_ATTRIBUTE_BITS : PAGE_ATTRIBUTE_BITS);\r
529a5a86 958 }\r
053e878b 959\r
529a5a86
MK
960 Pte += EFI_PAGE_SIZE / sizeof (*Pte);\r
961\r
962 //\r
963 // Fill in Page Directory Entries\r
964 //\r
965 for (Index = 0; Index < EFI_PAGE_SIZE * 4 / sizeof (*Pte); Index++) {\r
241f9149 966 Pte[Index] = (Index << 21) | mAddressEncMask | IA32_PG_PS | PAGE_ATTRIBUTE_BITS;\r
529a5a86
MK
967 }\r
968\r
053e878b 969 Pdpte = (UINT64 *)PageTable;\r
529a5a86 970 if (FeaturePcdGet (PcdCpuSmmStackGuard)) {\r
053e878b 971 Pages = (UINTN)PageTable + EFI_PAGES_TO_SIZE (5);\r
529a5a86 972 GuardPage = mSmmStackArrayBase + EFI_PAGE_SIZE;\r
529a5a86 973 for (PageIndex = Low2MBoundary; PageIndex <= High2MBoundary; PageIndex += SIZE_2MB) {\r
053e878b 974 Pte = (UINT64 *)(UINTN)(Pdpte[BitFieldRead32 ((UINT32)PageIndex, 30, 31)] & ~mAddressEncMask & ~(EFI_PAGE_SIZE - 1));\r
241f9149 975 Pte[BitFieldRead32 ((UINT32)PageIndex, 21, 29)] = (UINT64)Pages | mAddressEncMask | PAGE_ATTRIBUTE_BITS;\r
529a5a86
MK
976 //\r
977 // Fill in Page Table Entries\r
978 //\r
053e878b 979 Pte = (UINT64 *)Pages;\r
529a5a86
MK
980 PageAddress = PageIndex;\r
981 for (Index = 0; Index < EFI_PAGE_SIZE / sizeof (*Pte); Index++) {\r
982 if (PageAddress == GuardPage) {\r
983 //\r
984 // Mark the guard page as non-present\r
985 //\r
241f9149 986 Pte[Index] = PageAddress | mAddressEncMask;\r
ef91b073 987 GuardPage += (mSmmStackSize + mSmmShadowStackSize);\r
529a5a86
MK
988 if (GuardPage > mSmmStackArrayEnd) {\r
989 GuardPage = 0;\r
990 }\r
991 } else {\r
241f9149 992 Pte[Index] = PageAddress | mAddressEncMask | PAGE_ATTRIBUTE_BITS;\r
529a5a86 993 }\r
053e878b
MK
994\r
995 PageAddress += EFI_PAGE_SIZE;\r
529a5a86 996 }\r
053e878b 997\r
529a5a86
MK
998 Pages += EFI_PAGE_SIZE;\r
999 }\r
1000 }\r
1001\r
f8c1133b 1002 if ((PcdGet8 (PcdNullPointerDetectionPropertyMask) & BIT1) != 0) {\r
053e878b 1003 Pte = (UINT64 *)(UINTN)(Pdpte[0] & ~mAddressEncMask & ~(EFI_PAGE_SIZE - 1));\r
f8c1133b
JW
1004 if ((Pte[0] & IA32_PG_PS) == 0) {\r
1005 // 4K-page entries are already mapped. Just hide the first one anyway.\r
053e878b 1006 Pte = (UINT64 *)(UINTN)(Pte[0] & ~mAddressEncMask & ~(EFI_PAGE_SIZE - 1));\r
79da2d28 1007 Pte[0] &= ~(UINT64)IA32_PG_P; // Hide page 0\r
f8c1133b
JW
1008 } else {\r
1009 // Create 4K-page entries\r
1010 Pages = (UINTN)AllocatePageTableMemory (1);\r
1011 ASSERT (Pages != 0);\r
1012\r
1013 Pte[0] = (UINT64)(Pages | mAddressEncMask | PAGE_ATTRIBUTE_BITS);\r
1014\r
053e878b 1015 Pte = (UINT64 *)Pages;\r
f8c1133b 1016 PageAddress = 0;\r
053e878b 1017 Pte[0] = PageAddress | mAddressEncMask; // Hide page 0 but present left\r
f8c1133b
JW
1018 for (Index = 1; Index < EFI_PAGE_SIZE / sizeof (*Pte); Index++) {\r
1019 PageAddress += EFI_PAGE_SIZE;\r
053e878b 1020 Pte[Index] = PageAddress | mAddressEncMask | PAGE_ATTRIBUTE_BITS;\r
f8c1133b
JW
1021 }\r
1022 }\r
1023 }\r
1024\r
529a5a86
MK
1025 return (UINT32)(UINTN)PageTable;\r
1026}\r
1027\r
51dd408a
ED
1028/**\r
1029 Checks whether the input token is the current used token.\r
1030\r
1031 @param[in] Token This parameter describes the token that was passed into DispatchProcedure or\r
1032 BroadcastProcedure.\r
1033\r
1034 @retval TRUE The input token is the current used token.\r
1035 @retval FALSE The input token is not the current used token.\r
1036**/\r
1037BOOLEAN\r
1038IsTokenInUse (\r
053e878b 1039 IN SPIN_LOCK *Token\r
51dd408a
ED
1040 )\r
1041{\r
053e878b
MK
1042 LIST_ENTRY *Link;\r
1043 PROCEDURE_TOKEN *ProcToken;\r
51dd408a
ED
1044\r
1045 if (Token == NULL) {\r
1046 return FALSE;\r
1047 }\r
1048\r
1049 Link = GetFirstNode (&gSmmCpuPrivate->TokenList);\r
d84f090f
ED
1050 //\r
1051 // Only search used tokens.\r
1052 //\r
1053 while (Link != gSmmCpuPrivate->FirstFreeToken) {\r
51dd408a
ED
1054 ProcToken = PROCEDURE_TOKEN_FROM_LINK (Link);\r
1055\r
d84f090f 1056 if (ProcToken->SpinLock == Token) {\r
51dd408a
ED
1057 return TRUE;\r
1058 }\r
1059\r
1060 Link = GetNextNode (&gSmmCpuPrivate->TokenList, Link);\r
1061 }\r
1062\r
1063 return FALSE;\r
1064}\r
1065\r
1066/**\r
b948a496 1067 Allocate buffer for the SPIN_LOCK and PROCEDURE_TOKEN.\r
51dd408a 1068\r
3fdc47c6 1069 @return First token of the token buffer.\r
51dd408a 1070**/\r
3fdc47c6 1071LIST_ENTRY *\r
b948a496
ED
1072AllocateTokenBuffer (\r
1073 VOID\r
51dd408a
ED
1074 )\r
1075{\r
053e878b
MK
1076 UINTN SpinLockSize;\r
1077 UINT32 TokenCountPerChunk;\r
1078 UINTN Index;\r
1079 SPIN_LOCK *SpinLock;\r
1080 UINT8 *SpinLockBuffer;\r
1081 PROCEDURE_TOKEN *ProcTokens;\r
51dd408a
ED
1082\r
1083 SpinLockSize = GetSpinLockProperties ();\r
b948a496 1084\r
9caaa79d 1085 TokenCountPerChunk = FixedPcdGet32 (PcdCpuSmmMpTokenCountPerChunk);\r
b948a496
ED
1086 ASSERT (TokenCountPerChunk != 0);\r
1087 if (TokenCountPerChunk == 0) {\r
1088 DEBUG ((DEBUG_ERROR, "PcdCpuSmmMpTokenCountPerChunk should not be Zero!\n"));\r
1089 CpuDeadLoop ();\r
1090 }\r
053e878b 1091\r
b948a496 1092 DEBUG ((DEBUG_INFO, "CpuSmm: SpinLock Size = 0x%x, PcdCpuSmmMpTokenCountPerChunk = 0x%x\n", SpinLockSize, TokenCountPerChunk));\r
9caaa79d 1093\r
b948a496
ED
1094 //\r
1095 // Separate the Spin_lock and Proc_token because the alignment requires by Spin_Lock.\r
1096 //\r
1097 SpinLockBuffer = AllocatePool (SpinLockSize * TokenCountPerChunk);\r
1098 ASSERT (SpinLockBuffer != NULL);\r
9caaa79d 1099\r
3fdc47c6
RN
1100 ProcTokens = AllocatePool (sizeof (PROCEDURE_TOKEN) * TokenCountPerChunk);\r
1101 ASSERT (ProcTokens != NULL);\r
b948a496
ED
1102\r
1103 for (Index = 0; Index < TokenCountPerChunk; Index++) {\r
1104 SpinLock = (SPIN_LOCK *)(SpinLockBuffer + SpinLockSize * Index);\r
1105 InitializeSpinLock (SpinLock);\r
1106\r
3fdc47c6
RN
1107 ProcTokens[Index].Signature = PROCEDURE_TOKEN_SIGNATURE;\r
1108 ProcTokens[Index].SpinLock = SpinLock;\r
3fdc47c6 1109 ProcTokens[Index].RunningApCount = 0;\r
b948a496 1110\r
3fdc47c6 1111 InsertTailList (&gSmmCpuPrivate->TokenList, &ProcTokens[Index].Link);\r
b948a496 1112 }\r
9caaa79d 1113\r
3fdc47c6 1114 return &ProcTokens[0].Link;\r
b948a496
ED
1115}\r
1116\r
1117/**\r
1118 Get the free token.\r
1119\r
1120 If no free token, allocate new tokens then return the free one.\r
1121\r
e1879256
ED
1122 @param RunningApsCount The Running Aps count for this token.\r
1123\r
b948a496 1124 @retval return the first free PROCEDURE_TOKEN.\r
9caaa79d 1125\r
b948a496
ED
1126**/\r
1127PROCEDURE_TOKEN *\r
1128GetFreeToken (\r
053e878b 1129 IN UINT32 RunningApsCount\r
b948a496
ED
1130 )\r
1131{\r
1132 PROCEDURE_TOKEN *NewToken;\r
51dd408a 1133\r
3fdc47c6
RN
1134 //\r
1135 // If FirstFreeToken meets the end of token list, enlarge the token list.\r
1136 // Set FirstFreeToken to the first free token.\r
1137 //\r
1138 if (gSmmCpuPrivate->FirstFreeToken == &gSmmCpuPrivate->TokenList) {\r
1139 gSmmCpuPrivate->FirstFreeToken = AllocateTokenBuffer ();\r
b948a496 1140 }\r
053e878b
MK
1141\r
1142 NewToken = PROCEDURE_TOKEN_FROM_LINK (gSmmCpuPrivate->FirstFreeToken);\r
3fdc47c6 1143 gSmmCpuPrivate->FirstFreeToken = GetNextNode (&gSmmCpuPrivate->TokenList, gSmmCpuPrivate->FirstFreeToken);\r
51dd408a 1144\r
b948a496
ED
1145 NewToken->RunningApCount = RunningApsCount;\r
1146 AcquireSpinLock (NewToken->SpinLock);\r
51dd408a 1147\r
b948a496 1148 return NewToken;\r
51dd408a
ED
1149}\r
1150\r
1151/**\r
1152 Checks status of specified AP.\r
1153\r
1154 This function checks whether the specified AP has finished the task assigned\r
1155 by StartupThisAP(), and whether timeout expires.\r
1156\r
1157 @param[in] Token This parameter describes the token that was passed into DispatchProcedure or\r
1158 BroadcastProcedure.\r
1159\r
1160 @retval EFI_SUCCESS Specified AP has finished task assigned by StartupThisAPs().\r
1161 @retval EFI_NOT_READY Specified AP has not finished task and timeout has not expired.\r
1162**/\r
1163EFI_STATUS\r
1164IsApReady (\r
053e878b 1165 IN SPIN_LOCK *Token\r
51dd408a
ED
1166 )\r
1167{\r
1168 if (AcquireSpinLockOrFail (Token)) {\r
1169 ReleaseSpinLock (Token);\r
1170 return EFI_SUCCESS;\r
1171 }\r
1172\r
1173 return EFI_NOT_READY;\r
1174}\r
1175\r
529a5a86
MK
1176/**\r
1177 Schedule a procedure to run on the specified CPU.\r
1178\r
717fb604
JY
1179 @param[in] Procedure The address of the procedure to run\r
1180 @param[in] CpuIndex Target CPU Index\r
51dd408a
ED
1181 @param[in,out] ProcArguments The parameter to pass to the procedure\r
1182 @param[in] Token This is an optional parameter that allows the caller to execute the\r
1183 procedure in a blocking or non-blocking fashion. If it is NULL the\r
1184 call is blocking, and the call will not return until the AP has\r
1185 completed the procedure. If the token is not NULL, the call will\r
1186 return immediately. The caller can check whether the procedure has\r
1187 completed with CheckOnProcedure or WaitForProcedure.\r
1188 @param[in] TimeoutInMicroseconds Indicates the time limit in microseconds for the APs to finish\r
1189 execution of Procedure, either for blocking or non-blocking mode.\r
1190 Zero means infinity. If the timeout expires before all APs return\r
1191 from Procedure, then Procedure on the failed APs is terminated. If\r
1192 the timeout expires in blocking mode, the call returns EFI_TIMEOUT.\r
1193 If the timeout expires in non-blocking mode, the timeout determined\r
1194 can be through CheckOnProcedure or WaitForProcedure.\r
1195 Note that timeout support is optional. Whether an implementation\r
1196 supports this feature can be determined via the Attributes data\r
1197 member.\r
1198 @param[in,out] CpuStatus This optional pointer may be used to get the status code returned\r
1199 by Procedure when it completes execution on the target AP, or with\r
1200 EFI_TIMEOUT if the Procedure fails to complete within the optional\r
1201 timeout. The implementation will update this variable with\r
1202 EFI_NOT_READY prior to starting Procedure on the target AP.\r
529a5a86
MK
1203\r
1204 @retval EFI_INVALID_PARAMETER CpuNumber not valid\r
1205 @retval EFI_INVALID_PARAMETER CpuNumber specifying BSP\r
1206 @retval EFI_INVALID_PARAMETER The AP specified by CpuNumber did not enter SMM\r
1207 @retval EFI_INVALID_PARAMETER The AP specified by CpuNumber is busy\r
1208 @retval EFI_SUCCESS The procedure has been successfully scheduled\r
1209\r
1210**/\r
1211EFI_STATUS\r
717fb604 1212InternalSmmStartupThisAp (\r
053e878b
MK
1213 IN EFI_AP_PROCEDURE2 Procedure,\r
1214 IN UINTN CpuIndex,\r
1215 IN OUT VOID *ProcArguments OPTIONAL,\r
1216 IN MM_COMPLETION *Token,\r
1217 IN UINTN TimeoutInMicroseconds,\r
1218 IN OUT EFI_STATUS *CpuStatus\r
529a5a86
MK
1219 )\r
1220{\r
053e878b 1221 PROCEDURE_TOKEN *ProcToken;\r
a457823f 1222\r
717fb604 1223 if (CpuIndex >= gSmmCpuPrivate->SmmCoreEntryContext.NumberOfCpus) {\r
053e878b 1224 DEBUG ((DEBUG_ERROR, "CpuIndex(%d) >= gSmmCpuPrivate->SmmCoreEntryContext.NumberOfCpus(%d)\n", CpuIndex, gSmmCpuPrivate->SmmCoreEntryContext.NumberOfCpus));\r
717fb604
JY
1225 return EFI_INVALID_PARAMETER;\r
1226 }\r
053e878b 1227\r
717fb604 1228 if (CpuIndex == gSmmCpuPrivate->SmmCoreEntryContext.CurrentlyExecutingCpu) {\r
053e878b 1229 DEBUG ((DEBUG_ERROR, "CpuIndex(%d) == gSmmCpuPrivate->SmmCoreEntryContext.CurrentlyExecutingCpu\n", CpuIndex));\r
529a5a86
MK
1230 return EFI_INVALID_PARAMETER;\r
1231 }\r
053e878b 1232\r
b7025df8
JF
1233 if (gSmmCpuPrivate->ProcessorInfo[CpuIndex].ProcessorId == INVALID_APIC_ID) {\r
1234 return EFI_INVALID_PARAMETER;\r
1235 }\r
053e878b 1236\r
717fb604
JY
1237 if (!(*(mSmmMpSyncData->CpuData[CpuIndex].Present))) {\r
1238 if (mSmmMpSyncData->EffectiveSyncMode == SmmCpuSyncModeTradition) {\r
053e878b 1239 DEBUG ((DEBUG_ERROR, "!mSmmMpSyncData->CpuData[%d].Present\n", CpuIndex));\r
717fb604 1240 }\r
053e878b 1241\r
717fb604
JY
1242 return EFI_INVALID_PARAMETER;\r
1243 }\r
053e878b 1244\r
717fb604
JY
1245 if (gSmmCpuPrivate->Operation[CpuIndex] == SmmCpuRemove) {\r
1246 if (!FeaturePcdGet (PcdCpuHotPlugSupport)) {\r
053e878b 1247 DEBUG ((DEBUG_ERROR, "gSmmCpuPrivate->Operation[%d] == SmmCpuRemove\n", CpuIndex));\r
717fb604 1248 }\r
053e878b 1249\r
717fb604
JY
1250 return EFI_INVALID_PARAMETER;\r
1251 }\r
053e878b 1252\r
51dd408a
ED
1253 if ((TimeoutInMicroseconds != 0) && ((mSmmMp.Attributes & EFI_MM_MP_TIMEOUT_SUPPORTED) == 0)) {\r
1254 return EFI_INVALID_PARAMETER;\r
1255 }\r
053e878b 1256\r
51dd408a
ED
1257 if (Procedure == NULL) {\r
1258 return EFI_INVALID_PARAMETER;\r
1259 }\r
717fb604 1260\r
832c4c7a 1261 AcquireSpinLock (mSmmMpSyncData->CpuData[CpuIndex].Busy);\r
51dd408a 1262\r
529a5a86
MK
1263 mSmmMpSyncData->CpuData[CpuIndex].Procedure = Procedure;\r
1264 mSmmMpSyncData->CpuData[CpuIndex].Parameter = ProcArguments;\r
51dd408a 1265 if (Token != NULL) {\r
54ba08c6
RN
1266 if (Token != &mSmmStartupThisApToken) {\r
1267 //\r
1268 // When Token points to mSmmStartupThisApToken, this routine is called\r
1269 // from SmmStartupThisAp() in non-blocking mode (PcdCpuSmmBlockStartupThisAp == FALSE).\r
1270 //\r
1271 // In this case, caller wants to startup AP procedure in non-blocking\r
1272 // mode and cannot get the completion status from the Token because there\r
1273 // is no way to return the Token to caller from SmmStartupThisAp().\r
1274 // Caller needs to use its implementation specific way to query the completion status.\r
1275 //\r
1276 // There is no need to allocate a token for such case so the 3 overheads\r
1277 // can be avoided:\r
1278 // 1. Call AllocateTokenBuffer() when there is no free token.\r
1279 // 2. Get a free token from the token buffer.\r
1280 // 3. Call ReleaseToken() in APHandler().\r
1281 //\r
053e878b 1282 ProcToken = GetFreeToken (1);\r
54ba08c6 1283 mSmmMpSyncData->CpuData[CpuIndex].Token = ProcToken;\r
053e878b 1284 *Token = (MM_COMPLETION)ProcToken->SpinLock;\r
54ba08c6 1285 }\r
51dd408a 1286 }\r
053e878b
MK
1287\r
1288 mSmmMpSyncData->CpuData[CpuIndex].Status = CpuStatus;\r
51dd408a
ED
1289 if (mSmmMpSyncData->CpuData[CpuIndex].Status != NULL) {\r
1290 *mSmmMpSyncData->CpuData[CpuIndex].Status = EFI_NOT_READY;\r
1291 }\r
1292\r
ed3d5ecb 1293 ReleaseSemaphore (mSmmMpSyncData->CpuData[CpuIndex].Run);\r
529a5a86 1294\r
51dd408a 1295 if (Token == NULL) {\r
ed3d5ecb
JF
1296 AcquireSpinLock (mSmmMpSyncData->CpuData[CpuIndex].Busy);\r
1297 ReleaseSpinLock (mSmmMpSyncData->CpuData[CpuIndex].Busy);\r
529a5a86 1298 }\r
51dd408a
ED
1299\r
1300 return EFI_SUCCESS;\r
1301}\r
1302\r
1303/**\r
1304 Worker function to execute a caller provided function on all enabled APs.\r
1305\r
1306 @param[in] Procedure A pointer to the function to be run on\r
1307 enabled APs of the system.\r
1308 @param[in] TimeoutInMicroseconds Indicates the time limit in microseconds for\r
1309 APs to return from Procedure, either for\r
1310 blocking or non-blocking mode.\r
1311 @param[in,out] ProcedureArguments The parameter passed into Procedure for\r
1312 all APs.\r
1313 @param[in,out] Token This is an optional parameter that allows the caller to execute the\r
1314 procedure in a blocking or non-blocking fashion. If it is NULL the\r
1315 call is blocking, and the call will not return until the AP has\r
1316 completed the procedure. If the token is not NULL, the call will\r
1317 return immediately. The caller can check whether the procedure has\r
1318 completed with CheckOnProcedure or WaitForProcedure.\r
1319 @param[in,out] CPUStatus This optional pointer may be used to get the status code returned\r
1320 by Procedure when it completes execution on the target AP, or with\r
1321 EFI_TIMEOUT if the Procedure fails to complete within the optional\r
1322 timeout. The implementation will update this variable with\r
1323 EFI_NOT_READY prior to starting Procedure on the target AP.\r
1324\r
1325\r
1326 @retval EFI_SUCCESS In blocking mode, all APs have finished before\r
1327 the timeout expired.\r
1328 @retval EFI_SUCCESS In non-blocking mode, function has been dispatched\r
1329 to all enabled APs.\r
1330 @retval others Failed to Startup all APs.\r
1331\r
1332**/\r
1333EFI_STATUS\r
1334InternalSmmStartupAllAPs (\r
053e878b
MK
1335 IN EFI_AP_PROCEDURE2 Procedure,\r
1336 IN UINTN TimeoutInMicroseconds,\r
1337 IN OUT VOID *ProcedureArguments OPTIONAL,\r
1338 IN OUT MM_COMPLETION *Token,\r
1339 IN OUT EFI_STATUS *CPUStatus\r
51dd408a
ED
1340 )\r
1341{\r
053e878b
MK
1342 UINTN Index;\r
1343 UINTN CpuCount;\r
1344 PROCEDURE_TOKEN *ProcToken;\r
51dd408a
ED
1345\r
1346 if ((TimeoutInMicroseconds != 0) && ((mSmmMp.Attributes & EFI_MM_MP_TIMEOUT_SUPPORTED) == 0)) {\r
1347 return EFI_INVALID_PARAMETER;\r
1348 }\r
053e878b 1349\r
51dd408a
ED
1350 if (Procedure == NULL) {\r
1351 return EFI_INVALID_PARAMETER;\r
1352 }\r
1353\r
1354 CpuCount = 0;\r
70911f1f 1355 for (Index = 0; Index < mMaxNumberOfCpus; Index++) {\r
51dd408a 1356 if (IsPresentAp (Index)) {\r
053e878b 1357 CpuCount++;\r
51dd408a
ED
1358\r
1359 if (gSmmCpuPrivate->Operation[Index] == SmmCpuRemove) {\r
1360 return EFI_INVALID_PARAMETER;\r
1361 }\r
1362\r
053e878b 1363 if (!AcquireSpinLockOrFail (mSmmMpSyncData->CpuData[Index].Busy)) {\r
51dd408a
ED
1364 return EFI_NOT_READY;\r
1365 }\r
053e878b 1366\r
51dd408a
ED
1367 ReleaseSpinLock (mSmmMpSyncData->CpuData[Index].Busy);\r
1368 }\r
1369 }\r
053e878b 1370\r
51dd408a
ED
1371 if (CpuCount == 0) {\r
1372 return EFI_NOT_STARTED;\r
1373 }\r
1374\r
1375 if (Token != NULL) {\r
b948a496 1376 ProcToken = GetFreeToken ((UINT32)mMaxNumberOfCpus);\r
053e878b 1377 *Token = (MM_COMPLETION)ProcToken->SpinLock;\r
a457823f
ED
1378 } else {\r
1379 ProcToken = NULL;\r
51dd408a
ED
1380 }\r
1381\r
1382 //\r
1383 // Make sure all BUSY should be acquired.\r
1384 //\r
1385 // Because former code already check mSmmMpSyncData->CpuData[***].Busy for each AP.\r
1386 // Here code always use AcquireSpinLock instead of AcquireSpinLockOrFail for not\r
1387 // block mode.\r
1388 //\r
70911f1f 1389 for (Index = 0; Index < mMaxNumberOfCpus; Index++) {\r
51dd408a
ED
1390 if (IsPresentAp (Index)) {\r
1391 AcquireSpinLock (mSmmMpSyncData->CpuData[Index].Busy);\r
1392 }\r
1393 }\r
1394\r
70911f1f 1395 for (Index = 0; Index < mMaxNumberOfCpus; Index++) {\r
51dd408a 1396 if (IsPresentAp (Index)) {\r
053e878b 1397 mSmmMpSyncData->CpuData[Index].Procedure = (EFI_AP_PROCEDURE2)Procedure;\r
51dd408a 1398 mSmmMpSyncData->CpuData[Index].Parameter = ProcedureArguments;\r
a457823f 1399 if (ProcToken != NULL) {\r
053e878b 1400 mSmmMpSyncData->CpuData[Index].Token = ProcToken;\r
51dd408a 1401 }\r
053e878b 1402\r
51dd408a 1403 if (CPUStatus != NULL) {\r
053e878b 1404 mSmmMpSyncData->CpuData[Index].Status = &CPUStatus[Index];\r
51dd408a
ED
1405 if (mSmmMpSyncData->CpuData[Index].Status != NULL) {\r
1406 *mSmmMpSyncData->CpuData[Index].Status = EFI_NOT_READY;\r
1407 }\r
1408 }\r
1409 } else {\r
1410 //\r
1411 // PI spec requirement:\r
1412 // For every excluded processor, the array entry must contain a value of EFI_NOT_STARTED.\r
1413 //\r
1414 if (CPUStatus != NULL) {\r
1415 CPUStatus[Index] = EFI_NOT_STARTED;\r
1416 }\r
a457823f
ED
1417\r
1418 //\r
1419 // Decrease the count to mark this processor(AP or BSP) as finished.\r
1420 //\r
1421 if (ProcToken != NULL) {\r
1422 WaitForSemaphore (&ProcToken->RunningApCount);\r
1423 }\r
51dd408a
ED
1424 }\r
1425 }\r
1426\r
1427 ReleaseAllAPs ();\r
1428\r
1429 if (Token == NULL) {\r
1430 //\r
1431 // Make sure all APs have completed their tasks.\r
1432 //\r
1433 WaitForAllAPsNotBusy (TRUE);\r
1434 }\r
1435\r
1436 return EFI_SUCCESS;\r
1437}\r
1438\r
1439/**\r
1440 ISO C99 6.5.2.2 "Function calls", paragraph 9:\r
1441 If the function is defined with a type that is not compatible with\r
1442 the type (of the expression) pointed to by the expression that\r
1443 denotes the called function, the behavior is undefined.\r
1444\r
1445 So add below wrapper function to convert between EFI_AP_PROCEDURE\r
1446 and EFI_AP_PROCEDURE2.\r
1447\r
1448 Wrapper for Procedures.\r
1449\r
1450 @param[in] Buffer Pointer to PROCEDURE_WRAPPER buffer.\r
1451\r
1452**/\r
1453EFI_STATUS\r
1454EFIAPI\r
1455ProcedureWrapper (\r
053e878b 1456 IN VOID *Buffer\r
51dd408a
ED
1457 )\r
1458{\r
053e878b 1459 PROCEDURE_WRAPPER *Wrapper;\r
51dd408a
ED
1460\r
1461 Wrapper = Buffer;\r
1462 Wrapper->Procedure (Wrapper->ProcedureArgument);\r
1463\r
529a5a86
MK
1464 return EFI_SUCCESS;\r
1465}\r
1466\r
717fb604
JY
1467/**\r
1468 Schedule a procedure to run on the specified CPU in blocking mode.\r
1469\r
1470 @param[in] Procedure The address of the procedure to run\r
1471 @param[in] CpuIndex Target CPU Index\r
1472 @param[in, out] ProcArguments The parameter to pass to the procedure\r
1473\r
1474 @retval EFI_INVALID_PARAMETER CpuNumber not valid\r
1475 @retval EFI_INVALID_PARAMETER CpuNumber specifying BSP\r
1476 @retval EFI_INVALID_PARAMETER The AP specified by CpuNumber did not enter SMM\r
1477 @retval EFI_INVALID_PARAMETER The AP specified by CpuNumber is busy\r
1478 @retval EFI_SUCCESS The procedure has been successfully scheduled\r
1479\r
1480**/\r
1481EFI_STATUS\r
1482EFIAPI\r
1483SmmBlockingStartupThisAp (\r
053e878b
MK
1484 IN EFI_AP_PROCEDURE Procedure,\r
1485 IN UINTN CpuIndex,\r
1486 IN OUT VOID *ProcArguments OPTIONAL\r
717fb604
JY
1487 )\r
1488{\r
51dd408a
ED
1489 PROCEDURE_WRAPPER Wrapper;\r
1490\r
053e878b 1491 Wrapper.Procedure = Procedure;\r
51dd408a
ED
1492 Wrapper.ProcedureArgument = ProcArguments;\r
1493\r
1494 //\r
1495 // Use wrapper function to convert EFI_AP_PROCEDURE to EFI_AP_PROCEDURE2.\r
1496 //\r
1497 return InternalSmmStartupThisAp (ProcedureWrapper, CpuIndex, &Wrapper, NULL, 0, NULL);\r
717fb604
JY
1498}\r
1499\r
1500/**\r
1501 Schedule a procedure to run on the specified CPU.\r
1502\r
1503 @param Procedure The address of the procedure to run\r
1504 @param CpuIndex Target CPU Index\r
1505 @param ProcArguments The parameter to pass to the procedure\r
1506\r
1507 @retval EFI_INVALID_PARAMETER CpuNumber not valid\r
1508 @retval EFI_INVALID_PARAMETER CpuNumber specifying BSP\r
1509 @retval EFI_INVALID_PARAMETER The AP specified by CpuNumber did not enter SMM\r
1510 @retval EFI_INVALID_PARAMETER The AP specified by CpuNumber is busy\r
1511 @retval EFI_SUCCESS The procedure has been successfully scheduled\r
1512\r
1513**/\r
1514EFI_STATUS\r
1515EFIAPI\r
1516SmmStartupThisAp (\r
053e878b
MK
1517 IN EFI_AP_PROCEDURE Procedure,\r
1518 IN UINTN CpuIndex,\r
1519 IN OUT VOID *ProcArguments OPTIONAL\r
717fb604
JY
1520 )\r
1521{\r
053e878b 1522 gSmmCpuPrivate->ApWrapperFunc[CpuIndex].Procedure = Procedure;\r
51dd408a
ED
1523 gSmmCpuPrivate->ApWrapperFunc[CpuIndex].ProcedureArgument = ProcArguments;\r
1524\r
1525 //\r
1526 // Use wrapper function to convert EFI_AP_PROCEDURE to EFI_AP_PROCEDURE2.\r
1527 //\r
1528 return InternalSmmStartupThisAp (\r
053e878b
MK
1529 ProcedureWrapper,\r
1530 CpuIndex,\r
1531 &gSmmCpuPrivate->ApWrapperFunc[CpuIndex],\r
1532 FeaturePcdGet (PcdCpuSmmBlockStartupThisAp) ? NULL : &mSmmStartupThisApToken,\r
1533 0,\r
1534 NULL\r
1535 );\r
717fb604
JY
1536}\r
1537\r
f45f2d4a 1538/**\r
3eed6dda 1539 This function sets DR6 & DR7 according to SMM save state, before running SMM C code.\r
f45f2d4a
JY
1540 They are useful when you want to enable hardware breakpoints in SMM without entry SMM mode.\r
1541\r
1542 NOTE: It might not be appreciated in runtime since it might\r
1543 conflict with OS debugging facilities. Turn them off in RELEASE.\r
1544\r
1545 @param CpuIndex CPU Index\r
1546\r
1547**/\r
1548VOID\r
1549EFIAPI\r
1550CpuSmmDebugEntry (\r
1551 IN UINTN CpuIndex\r
1552 )\r
1553{\r
053e878b 1554 SMRAM_SAVE_STATE_MAP *CpuSaveState;\r
7367cc6c 1555\r
f45f2d4a 1556 if (FeaturePcdGet (PcdCpuSmmDebug)) {\r
053e878b 1557 ASSERT (CpuIndex < mMaxNumberOfCpus);\r
3eed6dda 1558 CpuSaveState = (SMRAM_SAVE_STATE_MAP *)gSmmCpuPrivate->CpuSaveState[CpuIndex];\r
f45f2d4a
JY
1559 if (mSmmSaveStateRegisterLma == EFI_SMM_SAVE_STATE_REGISTER_LMA_32BIT) {\r
1560 AsmWriteDr6 (CpuSaveState->x86._DR6);\r
1561 AsmWriteDr7 (CpuSaveState->x86._DR7);\r
1562 } else {\r
1563 AsmWriteDr6 ((UINTN)CpuSaveState->x64._DR6);\r
1564 AsmWriteDr7 ((UINTN)CpuSaveState->x64._DR7);\r
1565 }\r
1566 }\r
1567}\r
1568\r
1569/**\r
3eed6dda 1570 This function restores DR6 & DR7 to SMM save state.\r
f45f2d4a
JY
1571\r
1572 NOTE: It might not be appreciated in runtime since it might\r
1573 conflict with OS debugging facilities. Turn them off in RELEASE.\r
1574\r
1575 @param CpuIndex CPU Index\r
1576\r
1577**/\r
1578VOID\r
1579EFIAPI\r
1580CpuSmmDebugExit (\r
1581 IN UINTN CpuIndex\r
1582 )\r
1583{\r
053e878b 1584 SMRAM_SAVE_STATE_MAP *CpuSaveState;\r
f45f2d4a
JY
1585\r
1586 if (FeaturePcdGet (PcdCpuSmmDebug)) {\r
053e878b 1587 ASSERT (CpuIndex < mMaxNumberOfCpus);\r
3eed6dda 1588 CpuSaveState = (SMRAM_SAVE_STATE_MAP *)gSmmCpuPrivate->CpuSaveState[CpuIndex];\r
f45f2d4a
JY
1589 if (mSmmSaveStateRegisterLma == EFI_SMM_SAVE_STATE_REGISTER_LMA_32BIT) {\r
1590 CpuSaveState->x86._DR7 = (UINT32)AsmReadDr7 ();\r
1591 CpuSaveState->x86._DR6 = (UINT32)AsmReadDr6 ();\r
1592 } else {\r
1593 CpuSaveState->x64._DR7 = AsmReadDr7 ();\r
1594 CpuSaveState->x64._DR6 = AsmReadDr6 ();\r
1595 }\r
1596 }\r
1597}\r
1598\r
529a5a86
MK
1599/**\r
1600 C function for SMI entry, each processor comes here upon SMI trigger.\r
1601\r
1602 @param CpuIndex CPU Index\r
1603\r
1604**/\r
1605VOID\r
1606EFIAPI\r
1607SmiRendezvous (\r
053e878b 1608 IN UINTN CpuIndex\r
529a5a86
MK
1609 )\r
1610{\r
053e878b
MK
1611 EFI_STATUS Status;\r
1612 BOOLEAN ValidSmi;\r
1613 BOOLEAN IsBsp;\r
1614 BOOLEAN BspInProgress;\r
1615 UINTN Index;\r
1616 UINTN Cr2;\r
717fb604 1617\r
053e878b 1618 ASSERT (CpuIndex < mMaxNumberOfCpus);\r
529a5a86
MK
1619\r
1620 //\r
37f9fea5
VN
1621 // Save Cr2 because Page Fault exception in SMM may override its value,\r
1622 // when using on-demand paging for above 4G memory.\r
529a5a86 1623 //\r
37f9fea5
VN
1624 Cr2 = 0;\r
1625 SaveCr2 (&Cr2);\r
529a5a86 1626\r
51dd408a
ED
1627 //\r
1628 // Call the user register Startup function first.\r
1629 //\r
1630 if (mSmmMpSyncData->StartupProcedure != NULL) {\r
1631 mSmmMpSyncData->StartupProcedure (mSmmMpSyncData->StartupProcArgs);\r
1632 }\r
1633\r
529a5a86
MK
1634 //\r
1635 // Perform CPU specific entry hooks\r
1636 //\r
1637 SmmCpuFeaturesRendezvousEntry (CpuIndex);\r
1638\r
1639 //\r
1640 // Determine if this is a valid SMI\r
1641 //\r
053e878b 1642 ValidSmi = PlatformValidSmi ();\r
529a5a86
MK
1643\r
1644 //\r
1645 // Determine if BSP has been already in progress. Note this must be checked after\r
1646 // ValidSmi because BSP may clear a valid SMI source after checking in.\r
1647 //\r
fe3a75bc 1648 BspInProgress = *mSmmMpSyncData->InsideSmm;\r
529a5a86
MK
1649\r
1650 if (!BspInProgress && !ValidSmi) {\r
1651 //\r
1652 // If we reach here, it means when we sampled the ValidSmi flag, SMI status had not\r
1653 // been cleared by BSP in a new SMI run (so we have a truly invalid SMI), or SMI\r
1654 // status had been cleared by BSP and an existing SMI run has almost ended. (Note\r
1655 // we sampled ValidSmi flag BEFORE judging BSP-in-progress status.) In both cases, there\r
1656 // is nothing we need to do.\r
1657 //\r
1658 goto Exit;\r
1659 } else {\r
1660 //\r
1661 // Signal presence of this processor\r
1662 //\r
fe3a75bc 1663 if (ReleaseSemaphore (mSmmMpSyncData->Counter) == 0) {\r
529a5a86
MK
1664 //\r
1665 // BSP has already ended the synchronization, so QUIT!!!\r
1666 //\r
1667\r
1668 //\r
1669 // Wait for BSP's signal to finish SMI\r
1670 //\r
fe3a75bc 1671 while (*mSmmMpSyncData->AllCpusInSync) {\r
529a5a86
MK
1672 CpuPause ();\r
1673 }\r
053e878b 1674\r
529a5a86
MK
1675 goto Exit;\r
1676 } else {\r
529a5a86
MK
1677 //\r
1678 // The BUSY lock is initialized to Released state.\r
1679 // This needs to be done early enough to be ready for BSP's SmmStartupThisAp() call.\r
1680 // E.g., with Relaxed AP flow, SmmStartupThisAp() may be called immediately\r
1681 // after AP's present flag is detected.\r
1682 //\r
ed3d5ecb 1683 InitializeSpinLock (mSmmMpSyncData->CpuData[CpuIndex].Busy);\r
529a5a86
MK
1684 }\r
1685\r
529a5a86
MK
1686 if (FeaturePcdGet (PcdCpuSmmProfileEnable)) {\r
1687 ActivateSmmProfile (CpuIndex);\r
1688 }\r
1689\r
1690 if (BspInProgress) {\r
1691 //\r
1692 // BSP has been elected. Follow AP path, regardless of ValidSmi flag\r
1693 // as BSP may have cleared the SMI status\r
1694 //\r
1695 APHandler (CpuIndex, ValidSmi, mSmmMpSyncData->EffectiveSyncMode);\r
1696 } else {\r
1697 //\r
1698 // We have a valid SMI\r
1699 //\r
1700\r
1701 //\r
1702 // Elect BSP\r
1703 //\r
1704 IsBsp = FALSE;\r
1705 if (FeaturePcdGet (PcdCpuSmmEnableBspElection)) {\r
1706 if (!mSmmMpSyncData->SwitchBsp || mSmmMpSyncData->CandidateBsp[CpuIndex]) {\r
1707 //\r
1708 // Call platform hook to do BSP election\r
1709 //\r
1710 Status = PlatformSmmBspElection (&IsBsp);\r
1711 if (EFI_SUCCESS == Status) {\r
1712 //\r
1713 // Platform hook determines successfully\r
1714 //\r
1715 if (IsBsp) {\r
1716 mSmmMpSyncData->BspIndex = (UINT32)CpuIndex;\r
1717 }\r
1718 } else {\r
1719 //\r
1720 // Platform hook fails to determine, use default BSP election method\r
1721 //\r
1722 InterlockedCompareExchange32 (\r
053e878b 1723 (UINT32 *)&mSmmMpSyncData->BspIndex,\r
529a5a86
MK
1724 (UINT32)-1,\r
1725 (UINT32)CpuIndex\r
1726 );\r
1727 }\r
1728 }\r
1729 }\r
1730\r
1731 //\r
1732 // "mSmmMpSyncData->BspIndex == CpuIndex" means this is the BSP\r
1733 //\r
1734 if (mSmmMpSyncData->BspIndex == CpuIndex) {\r
529a5a86
MK
1735 //\r
1736 // Clear last request for SwitchBsp.\r
1737 //\r
1738 if (mSmmMpSyncData->SwitchBsp) {\r
1739 mSmmMpSyncData->SwitchBsp = FALSE;\r
1740 for (Index = 0; Index < mMaxNumberOfCpus; Index++) {\r
1741 mSmmMpSyncData->CandidateBsp[Index] = FALSE;\r
1742 }\r
1743 }\r
1744\r
1745 if (FeaturePcdGet (PcdCpuSmmProfileEnable)) {\r
1746 SmmProfileRecordSmiNum ();\r
1747 }\r
1748\r
1749 //\r
1750 // BSP Handler is always called with a ValidSmi == TRUE\r
1751 //\r
1752 BSPHandler (CpuIndex, mSmmMpSyncData->EffectiveSyncMode);\r
529a5a86
MK
1753 } else {\r
1754 APHandler (CpuIndex, ValidSmi, mSmmMpSyncData->EffectiveSyncMode);\r
1755 }\r
1756 }\r
1757\r
ed3d5ecb 1758 ASSERT (*mSmmMpSyncData->CpuData[CpuIndex].Run == 0);\r
529a5a86
MK
1759\r
1760 //\r
1761 // Wait for BSP's signal to exit SMI\r
1762 //\r
fe3a75bc 1763 while (*mSmmMpSyncData->AllCpusInSync) {\r
529a5a86
MK
1764 CpuPause ();\r
1765 }\r
1766 }\r
1767\r
1768Exit:\r
1769 SmmCpuFeaturesRendezvousExit (CpuIndex);\r
37f9fea5 1770\r
529a5a86
MK
1771 //\r
1772 // Restore Cr2\r
1773 //\r
37f9fea5 1774 RestoreCr2 (Cr2);\r
529a5a86
MK
1775}\r
1776\r
51dd408a
ED
1777/**\r
1778 Allocate buffer for SpinLock and Wrapper function buffer.\r
1779\r
1780**/\r
1781VOID\r
1782InitializeDataForMmMp (\r
1783 VOID\r
1784 )\r
1785{\r
1786 gSmmCpuPrivate->ApWrapperFunc = AllocatePool (sizeof (PROCEDURE_WRAPPER) * gSmmCpuPrivate->SmmCoreEntryContext.NumberOfCpus);\r
1787 ASSERT (gSmmCpuPrivate->ApWrapperFunc != NULL);\r
1788\r
1789 InitializeListHead (&gSmmCpuPrivate->TokenList);\r
b948a496 1790\r
3fdc47c6 1791 gSmmCpuPrivate->FirstFreeToken = AllocateTokenBuffer ();\r
51dd408a
ED
1792}\r
1793\r
1d648531
JF
1794/**\r
1795 Allocate buffer for all semaphores and spin locks.\r
1796\r
1797**/\r
1798VOID\r
1799InitializeSmmCpuSemaphores (\r
1800 VOID\r
1801 )\r
1802{\r
053e878b
MK
1803 UINTN ProcessorCount;\r
1804 UINTN TotalSize;\r
1805 UINTN GlobalSemaphoresSize;\r
1806 UINTN CpuSemaphoresSize;\r
1807 UINTN SemaphoreSize;\r
1808 UINTN Pages;\r
1809 UINTN *SemaphoreBlock;\r
1810 UINTN SemaphoreAddr;\r
1811\r
1812 SemaphoreSize = GetSpinLockProperties ();\r
1813 ProcessorCount = gSmmCpuPrivate->SmmCoreEntryContext.NumberOfCpus;\r
1d648531 1814 GlobalSemaphoresSize = (sizeof (SMM_CPU_SEMAPHORE_GLOBAL) / sizeof (VOID *)) * SemaphoreSize;\r
4e920581 1815 CpuSemaphoresSize = (sizeof (SMM_CPU_SEMAPHORE_CPU) / sizeof (VOID *)) * ProcessorCount * SemaphoreSize;\r
053e878b
MK
1816 TotalSize = GlobalSemaphoresSize + CpuSemaphoresSize;\r
1817 DEBUG ((DEBUG_INFO, "One Semaphore Size = 0x%x\n", SemaphoreSize));\r
1818 DEBUG ((DEBUG_INFO, "Total Semaphores Size = 0x%x\n", TotalSize));\r
1819 Pages = EFI_SIZE_TO_PAGES (TotalSize);\r
1d648531
JF
1820 SemaphoreBlock = AllocatePages (Pages);\r
1821 ASSERT (SemaphoreBlock != NULL);\r
1822 ZeroMem (SemaphoreBlock, TotalSize);\r
1823\r
053e878b 1824 SemaphoreAddr = (UINTN)SemaphoreBlock;\r
1d648531 1825 mSmmCpuSemaphores.SemaphoreGlobal.Counter = (UINT32 *)SemaphoreAddr;\r
053e878b 1826 SemaphoreAddr += SemaphoreSize;\r
1d648531 1827 mSmmCpuSemaphores.SemaphoreGlobal.InsideSmm = (BOOLEAN *)SemaphoreAddr;\r
053e878b 1828 SemaphoreAddr += SemaphoreSize;\r
1d648531 1829 mSmmCpuSemaphores.SemaphoreGlobal.AllCpusInSync = (BOOLEAN *)SemaphoreAddr;\r
053e878b 1830 SemaphoreAddr += SemaphoreSize;\r
1d648531 1831 mSmmCpuSemaphores.SemaphoreGlobal.PFLock = (SPIN_LOCK *)SemaphoreAddr;\r
053e878b 1832 SemaphoreAddr += SemaphoreSize;\r
1d648531 1833 mSmmCpuSemaphores.SemaphoreGlobal.CodeAccessCheckLock\r
053e878b 1834 = (SPIN_LOCK *)SemaphoreAddr;\r
6c4c15fa 1835 SemaphoreAddr += SemaphoreSize;\r
6c4c15fa 1836\r
053e878b 1837 SemaphoreAddr = (UINTN)SemaphoreBlock + GlobalSemaphoresSize;\r
4e920581 1838 mSmmCpuSemaphores.SemaphoreCpu.Busy = (SPIN_LOCK *)SemaphoreAddr;\r
053e878b 1839 SemaphoreAddr += ProcessorCount * SemaphoreSize;\r
4e920581 1840 mSmmCpuSemaphores.SemaphoreCpu.Run = (UINT32 *)SemaphoreAddr;\r
053e878b 1841 SemaphoreAddr += ProcessorCount * SemaphoreSize;\r
4e920581
JF
1842 mSmmCpuSemaphores.SemaphoreCpu.Present = (BOOLEAN *)SemaphoreAddr;\r
1843\r
fe3a75bc
JF
1844 mPFLock = mSmmCpuSemaphores.SemaphoreGlobal.PFLock;\r
1845 mConfigSmmCodeAccessCheckLock = mSmmCpuSemaphores.SemaphoreGlobal.CodeAccessCheckLock;\r
1846\r
1d648531
JF
1847 mSemaphoreSize = SemaphoreSize;\r
1848}\r
529a5a86
MK
1849\r
1850/**\r
1851 Initialize un-cacheable data.\r
1852\r
1853**/\r
1854VOID\r
1855EFIAPI\r
1856InitializeMpSyncData (\r
1857 VOID\r
1858 )\r
1859{\r
053e878b 1860 UINTN CpuIndex;\r
8b9311b7 1861\r
529a5a86 1862 if (mSmmMpSyncData != NULL) {\r
e78a2a49
JF
1863 //\r
1864 // mSmmMpSyncDataSize includes one structure of SMM_DISPATCHER_MP_SYNC_DATA, one\r
1865 // CpuData array of SMM_CPU_DATA_BLOCK and one CandidateBsp array of BOOLEAN.\r
1866 //\r
1867 ZeroMem (mSmmMpSyncData, mSmmMpSyncDataSize);\r
053e878b 1868 mSmmMpSyncData->CpuData = (SMM_CPU_DATA_BLOCK *)((UINT8 *)mSmmMpSyncData + sizeof (SMM_DISPATCHER_MP_SYNC_DATA));\r
529a5a86
MK
1869 mSmmMpSyncData->CandidateBsp = (BOOLEAN *)(mSmmMpSyncData->CpuData + gSmmCpuPrivate->SmmCoreEntryContext.NumberOfCpus);\r
1870 if (FeaturePcdGet (PcdCpuSmmEnableBspElection)) {\r
1871 //\r
1872 // Enable BSP election by setting BspIndex to -1\r
1873 //\r
1874 mSmmMpSyncData->BspIndex = (UINT32)-1;\r
1875 }\r
053e878b 1876\r
b43dd229 1877 mSmmMpSyncData->EffectiveSyncMode = mCpuSmmSyncMode;\r
1d648531 1878\r
8b9311b7
JF
1879 mSmmMpSyncData->Counter = mSmmCpuSemaphores.SemaphoreGlobal.Counter;\r
1880 mSmmMpSyncData->InsideSmm = mSmmCpuSemaphores.SemaphoreGlobal.InsideSmm;\r
1881 mSmmMpSyncData->AllCpusInSync = mSmmCpuSemaphores.SemaphoreGlobal.AllCpusInSync;\r
053e878b
MK
1882 ASSERT (\r
1883 mSmmMpSyncData->Counter != NULL && mSmmMpSyncData->InsideSmm != NULL &&\r
1884 mSmmMpSyncData->AllCpusInSync != NULL\r
1885 );\r
8b9311b7
JF
1886 *mSmmMpSyncData->Counter = 0;\r
1887 *mSmmMpSyncData->InsideSmm = FALSE;\r
1888 *mSmmMpSyncData->AllCpusInSync = FALSE;\r
1889\r
053e878b
MK
1890 for (CpuIndex = 0; CpuIndex < gSmmCpuPrivate->SmmCoreEntryContext.NumberOfCpus; CpuIndex++) {\r
1891 mSmmMpSyncData->CpuData[CpuIndex].Busy =\r
8b9311b7 1892 (SPIN_LOCK *)((UINTN)mSmmCpuSemaphores.SemaphoreCpu.Busy + mSemaphoreSize * CpuIndex);\r
053e878b 1893 mSmmMpSyncData->CpuData[CpuIndex].Run =\r
8b9311b7
JF
1894 (UINT32 *)((UINTN)mSmmCpuSemaphores.SemaphoreCpu.Run + mSemaphoreSize * CpuIndex);\r
1895 mSmmMpSyncData->CpuData[CpuIndex].Present =\r
1896 (BOOLEAN *)((UINTN)mSmmCpuSemaphores.SemaphoreCpu.Present + mSemaphoreSize * CpuIndex);\r
56e4a7d7
JF
1897 *(mSmmMpSyncData->CpuData[CpuIndex].Busy) = 0;\r
1898 *(mSmmMpSyncData->CpuData[CpuIndex].Run) = 0;\r
1899 *(mSmmMpSyncData->CpuData[CpuIndex].Present) = FALSE;\r
8b9311b7 1900 }\r
529a5a86
MK
1901 }\r
1902}\r
1903\r
1904/**\r
1905 Initialize global data for MP synchronization.\r
1906\r
3eb69b08
JY
1907 @param Stacks Base address of SMI stack buffer for all processors.\r
1908 @param StackSize Stack size for each processor in SMM.\r
1909 @param ShadowStackSize Shadow Stack size for each processor in SMM.\r
529a5a86
MK
1910\r
1911**/\r
1912UINT32\r
1913InitializeMpServiceData (\r
053e878b
MK
1914 IN VOID *Stacks,\r
1915 IN UINTN StackSize,\r
1916 IN UINTN ShadowStackSize\r
529a5a86
MK
1917 )\r
1918{\r
29e300ff
RN
1919 UINT32 Cr3;\r
1920 UINTN Index;\r
1921 UINT8 *GdtTssTables;\r
1922 UINTN GdtTableStepSize;\r
1923 CPUID_VERSION_INFO_EDX RegEdx;\r
1924 UINT32 MaxExtendedFunction;\r
1925 CPUID_VIR_PHY_ADDRESS_SIZE_EAX VirPhyAddressSize;\r
ba40cb31
MK
1926\r
1927 //\r
1928 // Determine if this CPU supports machine check\r
1929 //\r
1930 AsmCpuid (CPUID_VERSION_INFO, NULL, NULL, NULL, &RegEdx.Uint32);\r
1931 mMachineCheckSupported = (BOOLEAN)(RegEdx.Bits.MCA == 1);\r
529a5a86 1932\r
8b9311b7
JF
1933 //\r
1934 // Allocate memory for all locks and semaphores\r
1935 //\r
1936 InitializeSmmCpuSemaphores ();\r
1937\r
d67b73cc
JF
1938 //\r
1939 // Initialize mSmmMpSyncData\r
1940 //\r
1941 mSmmMpSyncDataSize = sizeof (SMM_DISPATCHER_MP_SYNC_DATA) +\r
1942 (sizeof (SMM_CPU_DATA_BLOCK) + sizeof (BOOLEAN)) * gSmmCpuPrivate->SmmCoreEntryContext.NumberOfCpus;\r
053e878b 1943 mSmmMpSyncData = (SMM_DISPATCHER_MP_SYNC_DATA *)AllocatePages (EFI_SIZE_TO_PAGES (mSmmMpSyncDataSize));\r
d67b73cc 1944 ASSERT (mSmmMpSyncData != NULL);\r
b43dd229 1945 mCpuSmmSyncMode = (SMM_CPU_SYNC_MODE)PcdGet8 (PcdCpuSmmSyncMode);\r
d67b73cc
JF
1946 InitializeMpSyncData ();\r
1947\r
529a5a86
MK
1948 //\r
1949 // Initialize physical address mask\r
1950 // NOTE: Physical memory above virtual address limit is not supported !!!\r
1951 //\r
29e300ff
RN
1952 AsmCpuid (CPUID_EXTENDED_FUNCTION, &MaxExtendedFunction, NULL, NULL, NULL);\r
1953 if (MaxExtendedFunction >= CPUID_VIR_PHY_ADDRESS_SIZE) {\r
1954 AsmCpuid (CPUID_VIR_PHY_ADDRESS_SIZE, &VirPhyAddressSize.Uint32, NULL, NULL, NULL);\r
1955 } else {\r
1956 VirPhyAddressSize.Bits.PhysicalAddressBits = 36;\r
1957 }\r
053e878b
MK
1958\r
1959 gPhyMask = LShiftU64 (1, VirPhyAddressSize.Bits.PhysicalAddressBits) - 1;\r
29e300ff
RN
1960 //\r
1961 // Clear the low 12 bits\r
1962 //\r
1963 gPhyMask &= 0xfffffffffffff000ULL;\r
529a5a86
MK
1964\r
1965 //\r
1966 // Create page tables\r
1967 //\r
1968 Cr3 = SmmInitPageTable ();\r
1969\r
fe5f1949 1970 GdtTssTables = InitGdt (Cr3, &GdtTableStepSize);\r
529a5a86
MK
1971\r
1972 //\r
f12367a0 1973 // Install SMI handler for each CPU\r
529a5a86
MK
1974 //\r
1975 for (Index = 0; Index < mMaxNumberOfCpus; Index++) {\r
529a5a86
MK
1976 InstallSmiHandler (\r
1977 Index,\r
1978 (UINT32)mCpuHotPlugData.SmBase[Index],\r
053e878b 1979 (VOID *)((UINTN)Stacks + (StackSize + ShadowStackSize) * Index),\r
529a5a86 1980 StackSize,\r
f12367a0
MK
1981 (UINTN)(GdtTssTables + GdtTableStepSize * Index),\r
1982 gcSmiGdtr.Limit + 1,\r
529a5a86
MK
1983 gcSmiIdtr.Base,\r
1984 gcSmiIdtr.Limit + 1,\r
1985 Cr3\r
1986 );\r
1987 }\r
1988\r
529a5a86
MK
1989 //\r
1990 // Record current MTRR settings\r
1991 //\r
26ab5ac3
MK
1992 ZeroMem (&gSmiMtrrs, sizeof (gSmiMtrrs));\r
1993 MtrrGetAllMtrrs (&gSmiMtrrs);\r
529a5a86
MK
1994\r
1995 return Cr3;\r
1996}\r
1997\r
1998/**\r
1999\r
2000 Register the SMM Foundation entry point.\r
2001\r
2002 @param This Pointer to EFI_SMM_CONFIGURATION_PROTOCOL instance\r
2003 @param SmmEntryPoint SMM Foundation EntryPoint\r
2004\r
2005 @retval EFI_SUCCESS Successfully to register SMM foundation entry point\r
2006\r
2007**/\r
2008EFI_STATUS\r
2009EFIAPI\r
2010RegisterSmmEntry (\r
2011 IN CONST EFI_SMM_CONFIGURATION_PROTOCOL *This,\r
2012 IN EFI_SMM_ENTRY_POINT SmmEntryPoint\r
2013 )\r
2014{\r
2015 //\r
2016 // Record SMM Foundation EntryPoint, later invoke it on SMI entry vector.\r
2017 //\r
2018 gSmmCpuPrivate->SmmCoreEntry = SmmEntryPoint;\r
2019 return EFI_SUCCESS;\r
2020}\r
51dd408a
ED
2021\r
2022/**\r
2023\r
2024 Register the SMM Foundation entry point.\r
2025\r
2026 @param[in] Procedure A pointer to the code stream to be run on the designated target AP\r
2027 of the system. Type EFI_AP_PROCEDURE is defined below in Volume 2\r
2028 with the related definitions of\r
2029 EFI_MP_SERVICES_PROTOCOL.StartupAllAPs.\r
2030 If caller may pass a value of NULL to deregister any existing\r
2031 startup procedure.\r
073f2ced 2032 @param[in,out] ProcedureArguments Allows the caller to pass a list of parameters to the code that is\r
51dd408a
ED
2033 run by the AP. It is an optional common mailbox between APs and\r
2034 the caller to share information\r
2035\r
2036 @retval EFI_SUCCESS The Procedure has been set successfully.\r
2037 @retval EFI_INVALID_PARAMETER The Procedure is NULL but ProcedureArguments not NULL.\r
2038\r
2039**/\r
2040EFI_STATUS\r
2041RegisterStartupProcedure (\r
053e878b
MK
2042 IN EFI_AP_PROCEDURE Procedure,\r
2043 IN OUT VOID *ProcedureArguments OPTIONAL\r
51dd408a
ED
2044 )\r
2045{\r
053e878b 2046 if ((Procedure == NULL) && (ProcedureArguments != NULL)) {\r
51dd408a
ED
2047 return EFI_INVALID_PARAMETER;\r
2048 }\r
053e878b 2049\r
51dd408a
ED
2050 if (mSmmMpSyncData == NULL) {\r
2051 return EFI_NOT_READY;\r
2052 }\r
2053\r
2054 mSmmMpSyncData->StartupProcedure = Procedure;\r
2055 mSmmMpSyncData->StartupProcArgs = ProcedureArguments;\r
2056\r
2057 return EFI_SUCCESS;\r
2058}\r