TianoCore EDK2 master
Loading...
Searching...
No Matches
SmmCpuSyncLib.c
Go to the documentation of this file.
1
30#include <Library/BaseLib.h>
31#include <Library/DebugLib.h>
33#include <Library/SafeIntLib.h>
36#include <Uefi.h>
37
41typedef volatile UINT32 SMM_CPU_SYNC_SEMAPHORE;
42
43typedef struct {
49
58 VOID *SemBuffer;
79};
80
95UINT32
97 IN OUT volatile UINT32 *Sem
98 )
99{
100 UINT32 Value;
101
102 for ( ; ;) {
103 Value = *Sem;
104 if (Value == MAX_UINT32) {
105 return Value;
106 }
107
108 if ((Value != 0) &&
110 (UINT32 *)Sem,
111 Value,
112 Value - 1
113 ) == Value))
114 {
115 break;
116 }
117
118 CpuPause ();
119 }
120
121 return Value - 1;
122}
123
137STATIC
138UINT32
140 IN OUT volatile UINT32 *Sem
141 )
142{
143 UINT32 Value;
144
145 do {
146 Value = *Sem;
147 } while (Value + 1 != 0 &&
149 (UINT32 *)Sem,
150 Value,
151 Value + 1
152 ) != Value);
153
154 if (Value == MAX_UINT32) {
155 return Value;
156 }
157
158 return Value + 1;
159}
160
172STATIC
173UINT32
175 IN OUT volatile UINT32 *Sem
176 )
177{
178 UINT32 Value;
179
180 do {
181 Value = *Sem;
183 (UINT32 *)Sem,
184 Value,
185 (UINT32)-1
186 ) != Value);
187
188 return Value;
189}
190
206RETURN_STATUS
207EFIAPI
209 IN UINTN NumberOfCpus,
210 OUT SMM_CPU_SYNC_CONTEXT **Context
211 )
212{
213 RETURN_STATUS Status;
214 UINTN ContextSize;
215 UINTN OneSemSize;
216 UINTN NumSem;
217 UINTN TotalSemSize;
218 UINTN SemAddr;
219 UINTN CpuIndex;
221
222 ASSERT (Context != NULL);
223
224 //
225 // Calculate ContextSize
226 //
227 Status = SafeUintnMult (NumberOfCpus, sizeof (SMM_CPU_SYNC_SEMAPHORE_FOR_EACH_CPU), &ContextSize);
228 if (RETURN_ERROR (Status)) {
229 return Status;
230 }
231
232 Status = SafeUintnAdd (ContextSize, sizeof (SMM_CPU_SYNC_CONTEXT), &ContextSize);
233 if (RETURN_ERROR (Status)) {
234 return Status;
235 }
236
237 //
238 // Allocate Buffer for Context
239 //
240 *Context = AllocatePool (ContextSize);
241 if (*Context == NULL) {
243 }
244
245 (*Context)->ArrivedCpuCountUponLock = 0;
246
247 //
248 // Save NumberOfCpus
249 //
250 (*Context)->NumberOfCpus = NumberOfCpus;
251
252 //
253 // Calculate total semaphore size
254 //
255 OneSemSize = GetSpinLockProperties ();
256 ASSERT (sizeof (SMM_CPU_SYNC_SEMAPHORE) <= OneSemSize);
257
258 Status = SafeUintnAdd (1, NumberOfCpus, &NumSem);
259 if (RETURN_ERROR (Status)) {
260 goto ON_ERROR;
261 }
262
263 Status = SafeUintnMult (NumSem, OneSemSize, &TotalSemSize);
264 if (RETURN_ERROR (Status)) {
265 goto ON_ERROR;
266 }
267
268 //
269 // Allocate for Semaphores in the *Context
270 //
271 (*Context)->SemBufferPages = EFI_SIZE_TO_PAGES (TotalSemSize);
272 (*Context)->SemBuffer = AllocatePages ((*Context)->SemBufferPages);
273 if ((*Context)->SemBuffer == NULL) {
275 goto ON_ERROR;
276 }
277
278 //
279 // Assign Global Semaphore pointer
280 //
281 SemAddr = (UINTN)(*Context)->SemBuffer;
282 (*Context)->CpuCount = (SMM_CPU_SYNC_SEMAPHORE *)SemAddr;
283 *(*Context)->CpuCount = 0;
284
285 SemAddr += OneSemSize;
286
287 //
288 // Assign CPU Semaphore pointer
289 //
290 CpuSem = (*Context)->CpuSem;
291 for (CpuIndex = 0; CpuIndex < NumberOfCpus; CpuIndex++) {
292 CpuSem->Run = (SMM_CPU_SYNC_SEMAPHORE *)SemAddr;
293 *CpuSem->Run = 0;
294
295 CpuSem++;
296 SemAddr += OneSemSize;
297 }
298
299 return RETURN_SUCCESS;
300
301ON_ERROR:
302 FreePool (*Context);
303 return Status;
304}
305
315VOID
316EFIAPI
319 )
320{
321 ASSERT (Context != NULL);
322
323 FreePages (Context->SemBuffer, Context->SemBufferPages);
324
325 FreePool (Context);
326}
327
339VOID
340EFIAPI
343 )
344{
345 ASSERT (Context != NULL);
346
347 Context->ArrivedCpuCountUponLock = 0;
348 *Context->CpuCount = 0;
349}
350
364UINTN
365EFIAPI
367 IN SMM_CPU_SYNC_CONTEXT *Context
368 )
369{
370 UINT32 Value;
371
372 ASSERT (Context != NULL);
373
374 Value = *Context->CpuCount;
375
376 if (Value == (UINT32)-1) {
377 return Context->ArrivedCpuCountUponLock;
378 }
379
380 return Value;
381}
382
398RETURN_STATUS
399EFIAPI
401 IN OUT SMM_CPU_SYNC_CONTEXT *Context,
402 IN UINTN CpuIndex
403 )
404{
405 ASSERT (Context != NULL);
406
407 ASSERT (CpuIndex < Context->NumberOfCpus);
408
409 //
410 // Check to return if CpuCount has already been locked.
411 //
412 if (InternalReleaseSemaphore (Context->CpuCount) == MAX_UINT32) {
413 return RETURN_ABORTED;
414 }
415
416 return RETURN_SUCCESS;
417}
418
435RETURN_STATUS
436EFIAPI
438 IN OUT SMM_CPU_SYNC_CONTEXT *Context,
439 IN UINTN CpuIndex
440 )
441{
442 ASSERT (Context != NULL);
443
444 ASSERT (CpuIndex < Context->NumberOfCpus);
445
446 if (InternalWaitForSemaphore (Context->CpuCount) == MAX_UINT32) {
447 return RETURN_ABORTED;
448 }
449
450 return RETURN_SUCCESS;
451}
452
470VOID
471EFIAPI
473 IN OUT SMM_CPU_SYNC_CONTEXT *Context,
474 IN UINTN CpuIndex,
475 OUT UINTN *CpuCount
476 )
477{
478 ASSERT (Context != NULL);
479
480 ASSERT (CpuCount != NULL);
481
482 ASSERT (CpuIndex < Context->NumberOfCpus);
483
484 //
485 // Temporarily record the CpuCount into the ArrivedCpuCountUponLock before lock door.
486 // Recording before lock door is to avoid the Context->CpuCount is locked but possible
487 // Context->ArrivedCpuCountUponLock is not updated.
488 //
489 Context->ArrivedCpuCountUponLock = *Context->CpuCount;
490
491 //
492 // Lock door operation
493 //
494 *CpuCount = InternalLockdownSemaphore (Context->CpuCount);
495
496 //
497 // Update the ArrivedCpuCountUponLock
498 //
499 Context->ArrivedCpuCountUponLock = *CpuCount;
500}
501
523VOID
524EFIAPI
526 IN OUT SMM_CPU_SYNC_CONTEXT *Context,
527 IN UINTN NumberOfAPs,
528 IN UINTN BspIndex
529 )
530{
531 UINTN Arrived;
532
533 ASSERT (Context != NULL);
534
535 ASSERT (NumberOfAPs < Context->NumberOfCpus);
536
537 ASSERT (BspIndex < Context->NumberOfCpus);
538
539 for (Arrived = 0; Arrived < NumberOfAPs; Arrived++) {
540 InternalWaitForSemaphore (Context->CpuSem[BspIndex].Run);
541 }
542}
543
560VOID
561EFIAPI
563 IN OUT SMM_CPU_SYNC_CONTEXT *Context,
564 IN UINTN CpuIndex,
565 IN UINTN BspIndex
566 )
567{
568 ASSERT (Context != NULL);
569
570 ASSERT (BspIndex != CpuIndex);
571
572 ASSERT (CpuIndex < Context->NumberOfCpus);
573
574 ASSERT (BspIndex < Context->NumberOfCpus);
575
576 InternalReleaseSemaphore (Context->CpuSem[CpuIndex].Run);
577}
578
600VOID
601EFIAPI
603 IN OUT SMM_CPU_SYNC_CONTEXT *Context,
604 IN UINTN CpuIndex,
605 IN UINTN BspIndex
606 )
607{
608 ASSERT (Context != NULL);
609
610 ASSERT (BspIndex != CpuIndex);
611
612 ASSERT (CpuIndex < Context->NumberOfCpus);
613
614 ASSERT (BspIndex < Context->NumberOfCpus);
615
616 InternalWaitForSemaphore (Context->CpuSem[CpuIndex].Run);
617}
618
635VOID
636EFIAPI
638 IN OUT SMM_CPU_SYNC_CONTEXT *Context,
639 IN UINTN CpuIndex,
640 IN UINTN BspIndex
641 )
642{
643 ASSERT (Context != NULL);
644
645 ASSERT (BspIndex != CpuIndex);
646
647 ASSERT (CpuIndex < Context->NumberOfCpus);
648
649 ASSERT (BspIndex < Context->NumberOfCpus);
650
651 InternalReleaseSemaphore (Context->CpuSem[BspIndex].Run);
652}
UINT64 UINTN
VOID EFIAPI CpuPause(VOID)
VOID EFIAPI FreePages(IN VOID *Buffer, IN UINTN Pages)
VOID EFIAPI FreePool(IN VOID *Buffer)
#define NULL
Definition: Base.h:319
#define STATIC
Definition: Base.h:264
#define RETURN_ERROR(StatusCode)
Definition: Base.h:1061
#define RETURN_ABORTED
Definition: Base.h:1177
#define RETURN_OUT_OF_RESOURCES
Definition: Base.h:1114
#define RETURN_SUCCESS
Definition: Base.h:1066
#define IN
Definition: Base.h:279
#define OUT
Definition: Base.h:284
VOID *EFIAPI AllocatePool(IN UINTN AllocationSize)
VOID *EFIAPI AllocatePages(IN UINTN Pages)
RETURN_STATUS EFIAPI SafeUintnAdd(IN UINTN Augend, IN UINTN Addend, OUT UINTN *Result)
Definition: SafeIntLib32.c:338
RETURN_STATUS EFIAPI SafeUintnMult(IN UINTN Multiplicand, IN UINTN Multiplier, OUT UINTN *Result)
Definition: SafeIntLib32.c:430
VOID EFIAPI SmmCpuSyncWaitForBsp(IN OUT SMM_CPU_SYNC_CONTEXT *Context, IN UINTN CpuIndex, IN UINTN BspIndex)
RETURN_STATUS EFIAPI SmmCpuSyncCheckOutCpu(IN OUT SMM_CPU_SYNC_CONTEXT *Context, IN UINTN CpuIndex)
STATIC UINT32 InternalLockdownSemaphore(IN OUT volatile UINT32 *Sem)
VOID EFIAPI SmmCpuSyncContextDeinit(IN OUT SMM_CPU_SYNC_CONTEXT *Context)
volatile UINT32 SMM_CPU_SYNC_SEMAPHORE
Definition: SmmCpuSyncLib.c:41
VOID EFIAPI SmmCpuSyncContextReset(IN OUT SMM_CPU_SYNC_CONTEXT *Context)
VOID EFIAPI SmmCpuSyncWaitForAPs(IN OUT SMM_CPU_SYNC_CONTEXT *Context, IN UINTN NumberOfAPs, IN UINTN BspIndex)
VOID EFIAPI SmmCpuSyncLockDoor(IN OUT SMM_CPU_SYNC_CONTEXT *Context, IN UINTN CpuIndex, OUT UINTN *CpuCount)
RETURN_STATUS EFIAPI SmmCpuSyncContextInit(IN UINTN NumberOfCpus, OUT SMM_CPU_SYNC_CONTEXT **Context)
VOID EFIAPI SmmCpuSyncReleaseBsp(IN OUT SMM_CPU_SYNC_CONTEXT *Context, IN UINTN CpuIndex, IN UINTN BspIndex)
UINTN EFIAPI SmmCpuSyncGetArrivedCpuCount(IN SMM_CPU_SYNC_CONTEXT *Context)
STATIC UINT32 InternalWaitForSemaphore(IN OUT volatile UINT32 *Sem)
Definition: SmmCpuSyncLib.c:96
VOID EFIAPI SmmCpuSyncReleaseOneAp(IN OUT SMM_CPU_SYNC_CONTEXT *Context, IN UINTN CpuIndex, IN UINTN BspIndex)
RETURN_STATUS EFIAPI SmmCpuSyncCheckInCpu(IN OUT SMM_CPU_SYNC_CONTEXT *Context, IN UINTN CpuIndex)
STATIC UINT32 InternalReleaseSemaphore(IN OUT volatile UINT32 *Sem)
UINTN EFIAPI GetSpinLockProperties(VOID)
UINT32 EFIAPI InterlockedCompareExchange32(IN OUT volatile UINT32 *Value, IN UINT32 CompareValue, IN UINT32 ExchangeValue)
#define EFI_SIZE_TO_PAGES(Size)
Definition: UefiBaseType.h:200
SMM_CPU_SYNC_SEMAPHORE * CpuCount
Definition: SmmCpuSyncLib.c:72
SMM_CPU_SYNC_SEMAPHORE_FOR_EACH_CPU CpuSem[]
Definition: SmmCpuSyncLib.c:78
SMM_CPU_SYNC_SEMAPHORE * Run
Definition: SmmCpuSyncLib.c:47