• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /** @file
2 Code for Processor S3 restoration
3 
4 Copyright (c) 2006 - 2016, Intel Corporation. All rights reserved.<BR>
5 This program and the accompanying materials
6 are licensed and made available under the terms and conditions of the BSD License
7 which accompanies this distribution.  The full text of the license may be found at
8 http://opensource.org/licenses/bsd-license.php
9 
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
12 
13 **/
14 
15 #include "PiSmmCpuDxeSmm.h"
16 
17 typedef struct {
18   UINTN             Lock;
19   VOID              *StackStart;
20   UINTN             StackSize;
21   VOID              *ApFunction;
22   IA32_DESCRIPTOR   GdtrProfile;
23   IA32_DESCRIPTOR   IdtrProfile;
24   UINT32            BufferStart;
25   UINT32            Cr3;
26 } MP_CPU_EXCHANGE_INFO;
27 
28 typedef struct {
29   UINT8 *RendezvousFunnelAddress;
30   UINTN PModeEntryOffset;
31   UINTN FlatJumpOffset;
32   UINTN Size;
33   UINTN LModeEntryOffset;
34   UINTN LongJumpOffset;
35 } MP_ASSEMBLY_ADDRESS_MAP;
36 
37 //
38 // Spin lock used to serialize MemoryMapped operation
39 //
40 SPIN_LOCK                *mMemoryMappedLock = NULL;
41 
42 /**
43   Get starting address and size of the rendezvous entry for APs.
44   Information for fixing a jump instruction in the code is also returned.
45 
46   @param AddressMap  Output buffer for address map information.
47 **/
48 VOID *
49 EFIAPI
50 AsmGetAddressMap (
51   MP_ASSEMBLY_ADDRESS_MAP                     *AddressMap
52   );
53 
54 #define LEGACY_REGION_SIZE    (2 * 0x1000)
55 #define LEGACY_REGION_BASE    (0xA0000 - LEGACY_REGION_SIZE)
56 
57 ACPI_CPU_DATA                mAcpiCpuData;
58 volatile UINT32              mNumberToFinish;
59 MP_CPU_EXCHANGE_INFO         *mExchangeInfo;
60 BOOLEAN                      mRestoreSmmConfigurationInS3 = FALSE;
61 VOID                         *mGdtForAp = NULL;
62 VOID                         *mIdtForAp = NULL;
63 VOID                         *mMachineCheckHandlerForAp = NULL;
64 MP_MSR_LOCK                  *mMsrSpinLocks = NULL;
65 UINTN                        mMsrSpinLockCount;
66 UINTN                        mMsrCount = 0;
67 
68 //
69 // S3 boot flag
70 //
71 BOOLEAN                      mSmmS3Flag = FALSE;
72 
73 //
74 // Pointer to structure used during S3 Resume
75 //
76 SMM_S3_RESUME_STATE          *mSmmS3ResumeState = NULL;
77 
78 BOOLEAN                      mAcpiS3Enable = TRUE;
79 
80 UINT8                        *mApHltLoopCode = NULL;
81 UINT8                        mApHltLoopCodeTemplate[] = {
82                                0x8B, 0x44, 0x24, 0x04,  // mov  eax, dword ptr [esp+4]
83                                0xF0, 0xFF, 0x08,        // lock dec  dword ptr [eax]
84                                0xFA,                    // cli
85                                0xF4,                    // hlt
86                                0xEB, 0xFC               // jmp $-2
87                                };
88 
89 /**
90   Get MSR spin lock by MSR index.
91 
92   @param  MsrIndex       MSR index value.
93 
94   @return Pointer to MSR spin lock.
95 
96 **/
97 SPIN_LOCK *
GetMsrSpinLockByIndex(IN UINT32 MsrIndex)98 GetMsrSpinLockByIndex (
99   IN UINT32      MsrIndex
100   )
101 {
102   UINTN     Index;
103   for (Index = 0; Index < mMsrCount; Index++) {
104     if (MsrIndex == mMsrSpinLocks[Index].MsrIndex) {
105       return mMsrSpinLocks[Index].SpinLock;
106     }
107   }
108   return NULL;
109 }
110 
111 /**
112   Initialize MSR spin lock by MSR index.
113 
114   @param  MsrIndex       MSR index value.
115 
116 **/
117 VOID
InitMsrSpinLockByIndex(IN UINT32 MsrIndex)118 InitMsrSpinLockByIndex (
119   IN UINT32      MsrIndex
120   )
121 {
122   UINTN    MsrSpinLockCount;
123   UINTN    NewMsrSpinLockCount;
124   UINTN    Index;
125   UINTN    AddedSize;
126 
127   if (mMsrSpinLocks == NULL) {
128     MsrSpinLockCount = mSmmCpuSemaphores.SemaphoreMsr.AvailableCounter;
129     mMsrSpinLocks = (MP_MSR_LOCK *) AllocatePool (sizeof (MP_MSR_LOCK) * MsrSpinLockCount);
130     ASSERT (mMsrSpinLocks != NULL);
131     for (Index = 0; Index < MsrSpinLockCount; Index++) {
132       mMsrSpinLocks[Index].SpinLock =
133        (SPIN_LOCK *)((UINTN)mSmmCpuSemaphores.SemaphoreMsr.Msr + Index * mSemaphoreSize);
134       mMsrSpinLocks[Index].MsrIndex = (UINT32)-1;
135     }
136     mMsrSpinLockCount = MsrSpinLockCount;
137     mSmmCpuSemaphores.SemaphoreMsr.AvailableCounter = 0;
138   }
139   if (GetMsrSpinLockByIndex (MsrIndex) == NULL) {
140     //
141     // Initialize spin lock for MSR programming
142     //
143     mMsrSpinLocks[mMsrCount].MsrIndex = MsrIndex;
144     InitializeSpinLock (mMsrSpinLocks[mMsrCount].SpinLock);
145     mMsrCount ++;
146     if (mMsrCount == mMsrSpinLockCount) {
147       //
148       // If MSR spin lock buffer is full, enlarge it
149       //
150       AddedSize = SIZE_4KB;
151       mSmmCpuSemaphores.SemaphoreMsr.Msr =
152                         AllocatePages (EFI_SIZE_TO_PAGES(AddedSize));
153       ASSERT (mSmmCpuSemaphores.SemaphoreMsr.Msr != NULL);
154       NewMsrSpinLockCount = mMsrSpinLockCount + AddedSize / mSemaphoreSize;
155       mMsrSpinLocks = ReallocatePool (
156                         sizeof (MP_MSR_LOCK) * mMsrSpinLockCount,
157                         sizeof (MP_MSR_LOCK) * NewMsrSpinLockCount,
158                         mMsrSpinLocks
159                         );
160       ASSERT (mMsrSpinLocks != NULL);
161       mMsrSpinLockCount = NewMsrSpinLockCount;
162       for (Index = mMsrCount; Index < mMsrSpinLockCount; Index++) {
163         mMsrSpinLocks[Index].SpinLock =
164                  (SPIN_LOCK *)((UINTN)mSmmCpuSemaphores.SemaphoreMsr.Msr +
165                  (Index - mMsrCount)  * mSemaphoreSize);
166         mMsrSpinLocks[Index].MsrIndex = (UINT32)-1;
167       }
168     }
169   }
170 }
171 
172 /**
173   Sync up the MTRR values for all processors.
174 
175   @param MtrrTable  Table holding fixed/variable MTRR values to be loaded.
176 **/
177 VOID
178 EFIAPI
LoadMtrrData(EFI_PHYSICAL_ADDRESS MtrrTable)179 LoadMtrrData (
180   EFI_PHYSICAL_ADDRESS       MtrrTable
181   )
182 /*++
183 
184 Routine Description:
185 
186   Sync up the MTRR values for all processors.
187 
188 Arguments:
189 
190 Returns:
191     None
192 
193 --*/
194 {
195   MTRR_SETTINGS   *MtrrSettings;
196 
197   MtrrSettings = (MTRR_SETTINGS *) (UINTN) MtrrTable;
198   MtrrSetAllMtrrs (MtrrSettings);
199 }
200 
201 /**
202   Programs registers for the calling processor.
203 
204   This function programs registers for the calling processor.
205 
206   @param  RegisterTable Pointer to register table of the running processor.
207 
208 **/
209 VOID
SetProcessorRegister(IN CPU_REGISTER_TABLE * RegisterTable)210 SetProcessorRegister (
211   IN CPU_REGISTER_TABLE        *RegisterTable
212   )
213 {
214   CPU_REGISTER_TABLE_ENTRY  *RegisterTableEntry;
215   UINTN                     Index;
216   UINTN                     Value;
217   SPIN_LOCK                 *MsrSpinLock;
218 
219   //
220   // Traverse Register Table of this logical processor
221   //
222   RegisterTableEntry = (CPU_REGISTER_TABLE_ENTRY *) (UINTN) RegisterTable->RegisterTableEntry;
223   for (Index = 0; Index < RegisterTable->TableLength; Index++, RegisterTableEntry++) {
224     //
225     // Check the type of specified register
226     //
227     switch (RegisterTableEntry->RegisterType) {
228     //
229     // The specified register is Control Register
230     //
231     case ControlRegister:
232       switch (RegisterTableEntry->Index) {
233       case 0:
234         Value = AsmReadCr0 ();
235         Value = (UINTN) BitFieldWrite64 (
236                           Value,
237                           RegisterTableEntry->ValidBitStart,
238                           RegisterTableEntry->ValidBitStart + RegisterTableEntry->ValidBitLength - 1,
239                           (UINTN) RegisterTableEntry->Value
240                           );
241         AsmWriteCr0 (Value);
242         break;
243       case 2:
244         Value = AsmReadCr2 ();
245         Value = (UINTN) BitFieldWrite64 (
246                           Value,
247                           RegisterTableEntry->ValidBitStart,
248                           RegisterTableEntry->ValidBitStart + RegisterTableEntry->ValidBitLength - 1,
249                           (UINTN) RegisterTableEntry->Value
250                           );
251         AsmWriteCr2 (Value);
252         break;
253       case 3:
254         Value = AsmReadCr3 ();
255         Value = (UINTN) BitFieldWrite64 (
256                           Value,
257                           RegisterTableEntry->ValidBitStart,
258                           RegisterTableEntry->ValidBitStart + RegisterTableEntry->ValidBitLength - 1,
259                           (UINTN) RegisterTableEntry->Value
260                           );
261         AsmWriteCr3 (Value);
262         break;
263       case 4:
264         Value = AsmReadCr4 ();
265         Value = (UINTN) BitFieldWrite64 (
266                           Value,
267                           RegisterTableEntry->ValidBitStart,
268                           RegisterTableEntry->ValidBitStart + RegisterTableEntry->ValidBitLength - 1,
269                           (UINTN) RegisterTableEntry->Value
270                           );
271         AsmWriteCr4 (Value);
272         break;
273       default:
274         break;
275       }
276       break;
277     //
278     // The specified register is Model Specific Register
279     //
280     case Msr:
281       //
282       // If this function is called to restore register setting after INIT signal,
283       // there is no need to restore MSRs in register table.
284       //
285       if (RegisterTableEntry->ValidBitLength >= 64) {
286         //
287         // If length is not less than 64 bits, then directly write without reading
288         //
289         AsmWriteMsr64 (
290           RegisterTableEntry->Index,
291           RegisterTableEntry->Value
292           );
293       } else {
294         //
295         // Get lock to avoid Package/Core scope MSRs programming issue in parallel execution mode
296         // to make sure MSR read/write operation is atomic.
297         //
298         MsrSpinLock = GetMsrSpinLockByIndex (RegisterTableEntry->Index);
299         AcquireSpinLock (MsrSpinLock);
300         //
301         // Set the bit section according to bit start and length
302         //
303         AsmMsrBitFieldWrite64 (
304           RegisterTableEntry->Index,
305           RegisterTableEntry->ValidBitStart,
306           RegisterTableEntry->ValidBitStart + RegisterTableEntry->ValidBitLength - 1,
307           RegisterTableEntry->Value
308           );
309         ReleaseSpinLock (MsrSpinLock);
310       }
311       break;
312     //
313     // MemoryMapped operations
314     //
315     case MemoryMapped:
316       AcquireSpinLock (mMemoryMappedLock);
317       MmioBitFieldWrite32 (
318         RegisterTableEntry->Index,
319         RegisterTableEntry->ValidBitStart,
320         RegisterTableEntry->ValidBitStart + RegisterTableEntry->ValidBitLength - 1,
321         (UINT32)RegisterTableEntry->Value
322         );
323       ReleaseSpinLock (mMemoryMappedLock);
324       break;
325     //
326     // Enable or disable cache
327     //
328     case CacheControl:
329       //
330       // If value of the entry is 0, then disable cache.  Otherwise, enable cache.
331       //
332       if (RegisterTableEntry->Value == 0) {
333         AsmDisableCache ();
334       } else {
335         AsmEnableCache ();
336       }
337       break;
338 
339     default:
340       break;
341     }
342   }
343 }
344 
345 /**
346   AP initialization before SMBASE relocation in the S3 boot path.
347 **/
348 VOID
EarlyMPRendezvousProcedure(VOID)349 EarlyMPRendezvousProcedure (
350   VOID
351   )
352 {
353   CPU_REGISTER_TABLE         *RegisterTableList;
354   UINT32                     InitApicId;
355   UINTN                      Index;
356 
357   LoadMtrrData (mAcpiCpuData.MtrrTable);
358 
359   //
360   // Find processor number for this CPU.
361   //
362   RegisterTableList = (CPU_REGISTER_TABLE *) (UINTN) mAcpiCpuData.PreSmmInitRegisterTable;
363   InitApicId = GetInitialApicId ();
364   for (Index = 0; Index < mAcpiCpuData.NumberOfCpus; Index++) {
365     if (RegisterTableList[Index].InitialApicId == InitApicId) {
366       SetProcessorRegister (&RegisterTableList[Index]);
367       break;
368     }
369   }
370 
371   //
372   // Count down the number with lock mechanism.
373   //
374   InterlockedDecrement (&mNumberToFinish);
375 }
376 
377 /**
378   AP initialization after SMBASE relocation in the S3 boot path.
379 **/
380 VOID
MPRendezvousProcedure(VOID)381 MPRendezvousProcedure (
382   VOID
383   )
384 {
385   CPU_REGISTER_TABLE         *RegisterTableList;
386   UINT32                     InitApicId;
387   UINTN                      Index;
388   UINTN                      TopOfStack;
389   UINT8                      Stack[128];
390 
391   ProgramVirtualWireMode ();
392   DisableLvtInterrupts ();
393 
394   RegisterTableList = (CPU_REGISTER_TABLE *) (UINTN) mAcpiCpuData.RegisterTable;
395   InitApicId = GetInitialApicId ();
396   for (Index = 0; Index < mAcpiCpuData.NumberOfCpus; Index++) {
397     if (RegisterTableList[Index].InitialApicId == InitApicId) {
398       SetProcessorRegister (&RegisterTableList[Index]);
399       break;
400     }
401   }
402 
403   //
404   // Place AP into the safe code, count down the number with lock mechanism in the safe code.
405   //
406   TopOfStack  = (UINTN) Stack + sizeof (Stack);
407   TopOfStack &= ~(UINTN) (CPU_STACK_ALIGNMENT - 1);
408   CopyMem ((VOID *) (UINTN) mApHltLoopCode, mApHltLoopCodeTemplate, sizeof (mApHltLoopCodeTemplate));
409   TransferApToSafeState ((UINTN)mApHltLoopCode, TopOfStack, (UINTN)&mNumberToFinish);
410 }
411 
412 /**
413   Prepares startup vector for APs.
414 
415   This function prepares startup vector for APs.
416 
417   @param  WorkingBuffer  The address of the work buffer.
418 **/
419 VOID
PrepareApStartupVector(EFI_PHYSICAL_ADDRESS WorkingBuffer)420 PrepareApStartupVector (
421   EFI_PHYSICAL_ADDRESS  WorkingBuffer
422   )
423 {
424   EFI_PHYSICAL_ADDRESS                        StartupVector;
425   MP_ASSEMBLY_ADDRESS_MAP                     AddressMap;
426 
427   //
428   // Get the address map of startup code for AP,
429   // including code size, and offset of long jump instructions to redirect.
430   //
431   ZeroMem (&AddressMap, sizeof (AddressMap));
432   AsmGetAddressMap (&AddressMap);
433 
434   StartupVector = WorkingBuffer;
435 
436   //
437   // Copy AP startup code to startup vector, and then redirect the long jump
438   // instructions for mode switching.
439   //
440   CopyMem ((VOID *) (UINTN) StartupVector, AddressMap.RendezvousFunnelAddress, AddressMap.Size);
441   *(UINT32 *) (UINTN) (StartupVector + AddressMap.FlatJumpOffset + 3) = (UINT32) (StartupVector + AddressMap.PModeEntryOffset);
442   if (AddressMap.LongJumpOffset != 0) {
443     *(UINT32 *) (UINTN) (StartupVector + AddressMap.LongJumpOffset + 2) = (UINT32) (StartupVector + AddressMap.LModeEntryOffset);
444   }
445 
446   //
447   // Get the start address of exchange data between BSP and AP.
448   //
449   mExchangeInfo = (MP_CPU_EXCHANGE_INFO *) (UINTN) (StartupVector + AddressMap.Size);
450   ZeroMem ((VOID *) mExchangeInfo, sizeof (MP_CPU_EXCHANGE_INFO));
451 
452   CopyMem ((VOID *) (UINTN) &mExchangeInfo->GdtrProfile, (VOID *) (UINTN) mAcpiCpuData.GdtrProfile, sizeof (IA32_DESCRIPTOR));
453   CopyMem ((VOID *) (UINTN) &mExchangeInfo->IdtrProfile, (VOID *) (UINTN) mAcpiCpuData.IdtrProfile, sizeof (IA32_DESCRIPTOR));
454 
455   //
456   // Copy AP's GDT, IDT and Machine Check handler from SMRAM to ACPI NVS memory
457   //
458   CopyMem ((VOID *) mExchangeInfo->GdtrProfile.Base, mGdtForAp, mExchangeInfo->GdtrProfile.Limit + 1);
459   CopyMem ((VOID *) mExchangeInfo->IdtrProfile.Base, mIdtForAp, mExchangeInfo->IdtrProfile.Limit + 1);
460   CopyMem ((VOID *)(UINTN) mAcpiCpuData.ApMachineCheckHandlerBase, mMachineCheckHandlerForAp, mAcpiCpuData.ApMachineCheckHandlerSize);
461 
462   mExchangeInfo->StackStart  = (VOID *) (UINTN) mAcpiCpuData.StackAddress;
463   mExchangeInfo->StackSize   = mAcpiCpuData.StackSize;
464   mExchangeInfo->BufferStart = (UINT32) StartupVector;
465   mExchangeInfo->Cr3         = (UINT32) (AsmReadCr3 ());
466 }
467 
468 /**
469   The function is invoked before SMBASE relocation in S3 path to restores CPU status.
470 
471   The function is invoked before SMBASE relocation in S3 path. It does first time microcode load
472   and restores MTRRs for both BSP and APs.
473 
474 **/
475 VOID
EarlyInitializeCpu(VOID)476 EarlyInitializeCpu (
477   VOID
478   )
479 {
480   CPU_REGISTER_TABLE         *RegisterTableList;
481   UINT32                     InitApicId;
482   UINTN                      Index;
483 
484   LoadMtrrData (mAcpiCpuData.MtrrTable);
485 
486   //
487   // Find processor number for this CPU.
488   //
489   RegisterTableList = (CPU_REGISTER_TABLE *) (UINTN) mAcpiCpuData.PreSmmInitRegisterTable;
490   InitApicId = GetInitialApicId ();
491   for (Index = 0; Index < mAcpiCpuData.NumberOfCpus; Index++) {
492     if (RegisterTableList[Index].InitialApicId == InitApicId) {
493       SetProcessorRegister (&RegisterTableList[Index]);
494       break;
495     }
496   }
497 
498   ProgramVirtualWireMode ();
499 
500   PrepareApStartupVector (mAcpiCpuData.StartupVector);
501 
502   mNumberToFinish = mAcpiCpuData.NumberOfCpus - 1;
503   mExchangeInfo->ApFunction  = (VOID *) (UINTN) EarlyMPRendezvousProcedure;
504 
505   //
506   // Send INIT IPI - SIPI to all APs
507   //
508   SendInitSipiSipiAllExcludingSelf ((UINT32)mAcpiCpuData.StartupVector);
509 
510   while (mNumberToFinish > 0) {
511     CpuPause ();
512   }
513 }
514 
515 /**
516   The function is invoked after SMBASE relocation in S3 path to restores CPU status.
517 
518   The function is invoked after SMBASE relocation in S3 path. It restores configuration according to
519   data saved by normal boot path for both BSP and APs.
520 
521 **/
522 VOID
InitializeCpu(VOID)523 InitializeCpu (
524   VOID
525   )
526 {
527   CPU_REGISTER_TABLE         *RegisterTableList;
528   UINT32                     InitApicId;
529   UINTN                      Index;
530 
531   RegisterTableList = (CPU_REGISTER_TABLE *) (UINTN) mAcpiCpuData.RegisterTable;
532   InitApicId = GetInitialApicId ();
533   for (Index = 0; Index < mAcpiCpuData.NumberOfCpus; Index++) {
534     if (RegisterTableList[Index].InitialApicId == InitApicId) {
535       SetProcessorRegister (&RegisterTableList[Index]);
536       break;
537     }
538   }
539 
540   mNumberToFinish = mAcpiCpuData.NumberOfCpus - 1;
541   //
542   // StackStart was updated when APs were waken up in EarlyInitializeCpu.
543   // Re-initialize StackAddress to original beginning address.
544   //
545   mExchangeInfo->StackStart  = (VOID *) (UINTN) mAcpiCpuData.StackAddress;
546   mExchangeInfo->ApFunction  = (VOID *) (UINTN) MPRendezvousProcedure;
547 
548   //
549   // Send INIT IPI - SIPI to all APs
550   //
551   SendInitSipiSipiAllExcludingSelf ((UINT32)mAcpiCpuData.StartupVector);
552 
553   while (mNumberToFinish > 0) {
554     CpuPause ();
555   }
556 }
557 
558 /**
559   Restore SMM Configuration in S3 boot path.
560 
561 **/
562 VOID
RestoreSmmConfigurationInS3(VOID)563 RestoreSmmConfigurationInS3 (
564   VOID
565   )
566 {
567   if (!mAcpiS3Enable) {
568     return;
569   }
570 
571   //
572   // Restore SMM Configuration in S3 boot path.
573   //
574   if (mRestoreSmmConfigurationInS3) {
575     //
576     // Need make sure gSmst is correct because below function may use them.
577     //
578     gSmst->SmmStartupThisAp      = gSmmCpuPrivate->SmmCoreEntryContext.SmmStartupThisAp;
579     gSmst->CurrentlyExecutingCpu = gSmmCpuPrivate->SmmCoreEntryContext.CurrentlyExecutingCpu;
580     gSmst->NumberOfCpus          = gSmmCpuPrivate->SmmCoreEntryContext.NumberOfCpus;
581     gSmst->CpuSaveStateSize      = gSmmCpuPrivate->SmmCoreEntryContext.CpuSaveStateSize;
582     gSmst->CpuSaveState          = gSmmCpuPrivate->SmmCoreEntryContext.CpuSaveState;
583 
584     //
585     // Configure SMM Code Access Check feature if available.
586     //
587     ConfigSmmCodeAccessCheck ();
588 
589     SmmCpuFeaturesCompleteSmmReadyToLock ();
590 
591     mRestoreSmmConfigurationInS3 = FALSE;
592   }
593 }
594 
595 /**
596   Perform SMM initialization for all processors in the S3 boot path.
597 
598   For a native platform, MP initialization in the S3 boot path is also performed in this function.
599 **/
600 VOID
601 EFIAPI
SmmRestoreCpu(VOID)602 SmmRestoreCpu (
603   VOID
604   )
605 {
606   SMM_S3_RESUME_STATE           *SmmS3ResumeState;
607   IA32_DESCRIPTOR               Ia32Idtr;
608   IA32_DESCRIPTOR               X64Idtr;
609   IA32_IDT_GATE_DESCRIPTOR      IdtEntryTable[EXCEPTION_VECTOR_NUMBER];
610   EFI_STATUS                    Status;
611 
612   DEBUG ((EFI_D_INFO, "SmmRestoreCpu()\n"));
613 
614   mSmmS3Flag = TRUE;
615 
616   InitializeSpinLock (mMemoryMappedLock);
617 
618   //
619   // See if there is enough context to resume PEI Phase
620   //
621   if (mSmmS3ResumeState == NULL) {
622     DEBUG ((EFI_D_ERROR, "No context to return to PEI Phase\n"));
623     CpuDeadLoop ();
624   }
625 
626   SmmS3ResumeState = mSmmS3ResumeState;
627   ASSERT (SmmS3ResumeState != NULL);
628 
629   if (SmmS3ResumeState->Signature == SMM_S3_RESUME_SMM_64) {
630     //
631     // Save the IA32 IDT Descriptor
632     //
633     AsmReadIdtr ((IA32_DESCRIPTOR *) &Ia32Idtr);
634 
635     //
636     // Setup X64 IDT table
637     //
638     ZeroMem (IdtEntryTable, sizeof (IA32_IDT_GATE_DESCRIPTOR) * 32);
639     X64Idtr.Base = (UINTN) IdtEntryTable;
640     X64Idtr.Limit = (UINT16) (sizeof (IA32_IDT_GATE_DESCRIPTOR) * 32 - 1);
641     AsmWriteIdtr ((IA32_DESCRIPTOR *) &X64Idtr);
642 
643     //
644     // Setup the default exception handler
645     //
646     Status = InitializeCpuExceptionHandlers (NULL);
647     ASSERT_EFI_ERROR (Status);
648 
649     //
650     // Initialize Debug Agent to support source level debug
651     //
652     InitializeDebugAgent (DEBUG_AGENT_INIT_THUNK_PEI_IA32TOX64, (VOID *)&Ia32Idtr, NULL);
653   }
654 
655   //
656   // Skip initialization if mAcpiCpuData is not valid
657   //
658   if (mAcpiCpuData.NumberOfCpus > 0) {
659     //
660     // First time microcode load and restore MTRRs
661     //
662     EarlyInitializeCpu ();
663   }
664 
665   //
666   // Restore SMBASE for BSP and all APs
667   //
668   SmmRelocateBases ();
669 
670   //
671   // Skip initialization if mAcpiCpuData is not valid
672   //
673   if (mAcpiCpuData.NumberOfCpus > 0) {
674     //
675     // Restore MSRs for BSP and all APs
676     //
677     InitializeCpu ();
678   }
679 
680   //
681   // Set a flag to restore SMM configuration in S3 path.
682   //
683   mRestoreSmmConfigurationInS3 = TRUE;
684 
685   DEBUG (( EFI_D_INFO, "SMM S3 Return CS                = %x\n", SmmS3ResumeState->ReturnCs));
686   DEBUG (( EFI_D_INFO, "SMM S3 Return Entry Point       = %x\n", SmmS3ResumeState->ReturnEntryPoint));
687   DEBUG (( EFI_D_INFO, "SMM S3 Return Context1          = %x\n", SmmS3ResumeState->ReturnContext1));
688   DEBUG (( EFI_D_INFO, "SMM S3 Return Context2          = %x\n", SmmS3ResumeState->ReturnContext2));
689   DEBUG (( EFI_D_INFO, "SMM S3 Return Stack Pointer     = %x\n", SmmS3ResumeState->ReturnStackPointer));
690 
691   //
692   // If SMM is in 32-bit mode, then use SwitchStack() to resume PEI Phase
693   //
694   if (SmmS3ResumeState->Signature == SMM_S3_RESUME_SMM_32) {
695     DEBUG ((EFI_D_INFO, "Call SwitchStack() to return to S3 Resume in PEI Phase\n"));
696 
697     SwitchStack (
698       (SWITCH_STACK_ENTRY_POINT)(UINTN)SmmS3ResumeState->ReturnEntryPoint,
699       (VOID *)(UINTN)SmmS3ResumeState->ReturnContext1,
700       (VOID *)(UINTN)SmmS3ResumeState->ReturnContext2,
701       (VOID *)(UINTN)SmmS3ResumeState->ReturnStackPointer
702       );
703   }
704 
705   //
706   // If SMM is in 64-bit mode, then use AsmDisablePaging64() to resume PEI Phase
707   //
708   if (SmmS3ResumeState->Signature == SMM_S3_RESUME_SMM_64) {
709     DEBUG ((EFI_D_INFO, "Call AsmDisablePaging64() to return to S3 Resume in PEI Phase\n"));
710     //
711     // Disable interrupt of Debug timer, since new IDT table is for IA32 and will not work in long mode.
712     //
713     SaveAndSetDebugTimerInterrupt (FALSE);
714     //
715     // Restore IA32 IDT table
716     //
717     AsmWriteIdtr ((IA32_DESCRIPTOR *) &Ia32Idtr);
718     AsmDisablePaging64 (
719       SmmS3ResumeState->ReturnCs,
720       (UINT32)SmmS3ResumeState->ReturnEntryPoint,
721       (UINT32)SmmS3ResumeState->ReturnContext1,
722       (UINT32)SmmS3ResumeState->ReturnContext2,
723       (UINT32)SmmS3ResumeState->ReturnStackPointer
724       );
725   }
726 
727   //
728   // Can not resume PEI Phase
729   //
730   DEBUG ((EFI_D_ERROR, "No context to return to PEI Phase\n"));
731   CpuDeadLoop ();
732 }
733 
734 /**
735   Initialize SMM S3 resume state structure used during S3 Resume.
736 
737   @param[in] Cr3    The base address of the page tables to use in SMM.
738 
739 **/
740 VOID
InitSmmS3ResumeState(IN UINT32 Cr3)741 InitSmmS3ResumeState (
742   IN UINT32  Cr3
743   )
744 {
745   VOID                       *GuidHob;
746   EFI_SMRAM_DESCRIPTOR       *SmramDescriptor;
747   SMM_S3_RESUME_STATE        *SmmS3ResumeState;
748   EFI_PHYSICAL_ADDRESS       Address;
749   EFI_STATUS                 Status;
750 
751   if (!mAcpiS3Enable) {
752     return;
753   }
754 
755   GuidHob = GetFirstGuidHob (&gEfiAcpiVariableGuid);
756   if (GuidHob != NULL) {
757     SmramDescriptor = (EFI_SMRAM_DESCRIPTOR *) GET_GUID_HOB_DATA (GuidHob);
758 
759     DEBUG ((EFI_D_INFO, "SMM S3 SMRAM Structure = %x\n", SmramDescriptor));
760     DEBUG ((EFI_D_INFO, "SMM S3 Structure = %x\n", SmramDescriptor->CpuStart));
761 
762     SmmS3ResumeState = (SMM_S3_RESUME_STATE *)(UINTN)SmramDescriptor->CpuStart;
763     ZeroMem (SmmS3ResumeState, sizeof (SMM_S3_RESUME_STATE));
764 
765     mSmmS3ResumeState = SmmS3ResumeState;
766     SmmS3ResumeState->Smst = (EFI_PHYSICAL_ADDRESS)(UINTN)gSmst;
767 
768     SmmS3ResumeState->SmmS3ResumeEntryPoint = (EFI_PHYSICAL_ADDRESS)(UINTN)SmmRestoreCpu;
769 
770     SmmS3ResumeState->SmmS3StackSize = SIZE_32KB;
771     SmmS3ResumeState->SmmS3StackBase = (EFI_PHYSICAL_ADDRESS)(UINTN)AllocatePages (EFI_SIZE_TO_PAGES ((UINTN)SmmS3ResumeState->SmmS3StackSize));
772     if (SmmS3ResumeState->SmmS3StackBase == 0) {
773       SmmS3ResumeState->SmmS3StackSize = 0;
774     }
775 
776     SmmS3ResumeState->SmmS3Cr0 = gSmmCr0;
777     SmmS3ResumeState->SmmS3Cr3 = Cr3;
778     SmmS3ResumeState->SmmS3Cr4 = gSmmCr4;
779 
780     if (sizeof (UINTN) == sizeof (UINT64)) {
781       SmmS3ResumeState->Signature = SMM_S3_RESUME_SMM_64;
782     }
783     if (sizeof (UINTN) == sizeof (UINT32)) {
784       SmmS3ResumeState->Signature = SMM_S3_RESUME_SMM_32;
785     }
786   }
787 
788   //
789   // Patch SmmS3ResumeState->SmmS3Cr3
790   //
791   InitSmmS3Cr3 ();
792 
793   //
794   // Allocate safe memory in ACPI NVS for AP to execute hlt loop in
795   // protected mode on S3 path
796   //
797   Address = BASE_4GB - 1;
798   Status  = gBS->AllocatePages (
799                    AllocateMaxAddress,
800                    EfiACPIMemoryNVS,
801                    EFI_SIZE_TO_PAGES (sizeof (mApHltLoopCodeTemplate)),
802                    &Address
803                    );
804   ASSERT_EFI_ERROR (Status);
805   mApHltLoopCode = (UINT8 *) (UINTN) Address;
806 }
807 
808 /**
809   Copy register table from ACPI NVS memory into SMRAM.
810 
811   @param[in] DestinationRegisterTableList  Points to destination register table.
812   @param[in] SourceRegisterTableList       Points to source register table.
813   @param[in] NumberOfCpus                  Number of CPUs.
814 
815 **/
816 VOID
CopyRegisterTable(IN CPU_REGISTER_TABLE * DestinationRegisterTableList,IN CPU_REGISTER_TABLE * SourceRegisterTableList,IN UINT32 NumberOfCpus)817 CopyRegisterTable (
818   IN CPU_REGISTER_TABLE         *DestinationRegisterTableList,
819   IN CPU_REGISTER_TABLE         *SourceRegisterTableList,
820   IN UINT32                     NumberOfCpus
821   )
822 {
823   UINTN                      Index;
824   UINTN                      Index1;
825   CPU_REGISTER_TABLE_ENTRY   *RegisterTableEntry;
826 
827   CopyMem (DestinationRegisterTableList, SourceRegisterTableList, NumberOfCpus * sizeof (CPU_REGISTER_TABLE));
828   for (Index = 0; Index < NumberOfCpus; Index++) {
829     DestinationRegisterTableList[Index].RegisterTableEntry = AllocatePool (DestinationRegisterTableList[Index].AllocatedSize);
830     ASSERT (DestinationRegisterTableList[Index].RegisterTableEntry != NULL);
831     CopyMem (DestinationRegisterTableList[Index].RegisterTableEntry, SourceRegisterTableList[Index].RegisterTableEntry, DestinationRegisterTableList[Index].AllocatedSize);
832     //
833     // Go though all MSRs in register table to initialize MSR spin lock
834     //
835     RegisterTableEntry = DestinationRegisterTableList[Index].RegisterTableEntry;
836     for (Index1 = 0; Index1 < DestinationRegisterTableList[Index].TableLength; Index1++, RegisterTableEntry++) {
837       if ((RegisterTableEntry->RegisterType == Msr) && (RegisterTableEntry->ValidBitLength < 64)) {
838         //
839         // Initialize MSR spin lock only for those MSRs need bit field writing
840         //
841         InitMsrSpinLockByIndex (RegisterTableEntry->Index);
842       }
843     }
844   }
845 }
846 
847 /**
848   Get ACPI CPU data.
849 
850 **/
851 VOID
GetAcpiCpuData(VOID)852 GetAcpiCpuData (
853   VOID
854   )
855 {
856   ACPI_CPU_DATA              *AcpiCpuData;
857   IA32_DESCRIPTOR            *Gdtr;
858   IA32_DESCRIPTOR            *Idtr;
859 
860   if (!mAcpiS3Enable) {
861     return;
862   }
863 
864   //
865   // Prevent use of mAcpiCpuData by initialize NumberOfCpus to 0
866   //
867   mAcpiCpuData.NumberOfCpus = 0;
868 
869   //
870   // If PcdCpuS3DataAddress was never set, then do not copy CPU S3 Data into SMRAM
871   //
872   AcpiCpuData = (ACPI_CPU_DATA *)(UINTN)PcdGet64 (PcdCpuS3DataAddress);
873   if (AcpiCpuData == 0) {
874     return;
875   }
876 
877   //
878   // For a native platform, copy the CPU S3 data into SMRAM for use on CPU S3 Resume.
879   //
880   CopyMem (&mAcpiCpuData, AcpiCpuData, sizeof (mAcpiCpuData));
881 
882   mAcpiCpuData.MtrrTable = (EFI_PHYSICAL_ADDRESS)(UINTN)AllocatePool (sizeof (MTRR_SETTINGS));
883   ASSERT (mAcpiCpuData.MtrrTable != 0);
884 
885   CopyMem ((VOID *)(UINTN)mAcpiCpuData.MtrrTable, (VOID *)(UINTN)AcpiCpuData->MtrrTable, sizeof (MTRR_SETTINGS));
886 
887   mAcpiCpuData.GdtrProfile = (EFI_PHYSICAL_ADDRESS)(UINTN)AllocatePool (sizeof (IA32_DESCRIPTOR));
888   ASSERT (mAcpiCpuData.GdtrProfile != 0);
889 
890   CopyMem ((VOID *)(UINTN)mAcpiCpuData.GdtrProfile, (VOID *)(UINTN)AcpiCpuData->GdtrProfile, sizeof (IA32_DESCRIPTOR));
891 
892   mAcpiCpuData.IdtrProfile = (EFI_PHYSICAL_ADDRESS)(UINTN)AllocatePool (sizeof (IA32_DESCRIPTOR));
893   ASSERT (mAcpiCpuData.IdtrProfile != 0);
894 
895   CopyMem ((VOID *)(UINTN)mAcpiCpuData.IdtrProfile, (VOID *)(UINTN)AcpiCpuData->IdtrProfile, sizeof (IA32_DESCRIPTOR));
896 
897   mAcpiCpuData.PreSmmInitRegisterTable = (EFI_PHYSICAL_ADDRESS)(UINTN)AllocatePool (mAcpiCpuData.NumberOfCpus * sizeof (CPU_REGISTER_TABLE));
898   ASSERT (mAcpiCpuData.PreSmmInitRegisterTable != 0);
899 
900   CopyRegisterTable (
901     (CPU_REGISTER_TABLE *)(UINTN)mAcpiCpuData.PreSmmInitRegisterTable,
902     (CPU_REGISTER_TABLE *)(UINTN)AcpiCpuData->PreSmmInitRegisterTable,
903     mAcpiCpuData.NumberOfCpus
904     );
905 
906   mAcpiCpuData.RegisterTable = (EFI_PHYSICAL_ADDRESS)(UINTN)AllocatePool (mAcpiCpuData.NumberOfCpus * sizeof (CPU_REGISTER_TABLE));
907   ASSERT (mAcpiCpuData.RegisterTable != 0);
908 
909   CopyRegisterTable (
910     (CPU_REGISTER_TABLE *)(UINTN)mAcpiCpuData.RegisterTable,
911     (CPU_REGISTER_TABLE *)(UINTN)AcpiCpuData->RegisterTable,
912     mAcpiCpuData.NumberOfCpus
913     );
914 
915   //
916   // Copy AP's GDT, IDT and Machine Check handler into SMRAM.
917   //
918   Gdtr = (IA32_DESCRIPTOR *)(UINTN)mAcpiCpuData.GdtrProfile;
919   Idtr = (IA32_DESCRIPTOR *)(UINTN)mAcpiCpuData.IdtrProfile;
920 
921   mGdtForAp = AllocatePool ((Gdtr->Limit + 1) + (Idtr->Limit + 1) +  mAcpiCpuData.ApMachineCheckHandlerSize);
922   ASSERT (mGdtForAp != NULL);
923   mIdtForAp = (VOID *) ((UINTN)mGdtForAp + (Gdtr->Limit + 1));
924   mMachineCheckHandlerForAp = (VOID *) ((UINTN)mIdtForAp + (Idtr->Limit + 1));
925 
926   CopyMem (mGdtForAp, (VOID *)Gdtr->Base, Gdtr->Limit + 1);
927   CopyMem (mIdtForAp, (VOID *)Idtr->Base, Idtr->Limit + 1);
928   CopyMem (mMachineCheckHandlerForAp, (VOID *)(UINTN)mAcpiCpuData.ApMachineCheckHandlerBase, mAcpiCpuData.ApMachineCheckHandlerSize);
929 }
930 
931 /**
932   Get ACPI S3 enable flag.
933 
934 **/
935 VOID
GetAcpiS3EnableFlag(VOID)936 GetAcpiS3EnableFlag (
937   VOID
938   )
939 {
940   mAcpiS3Enable = PcdGetBool (PcdAcpiS3Enable);
941 }
942