1 /** @file
2 Agent Module to load other modules to deploy SMM Entry Vector for X86 CPU.
3 
4 Copyright (c) 2009 - 2015, 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 //
18 // SMM CPU Private Data structure that contains SMM Configuration Protocol
19 // along its supporting fields.
20 //
21 SMM_CPU_PRIVATE_DATA  mSmmCpuPrivateData = {
22   SMM_CPU_PRIVATE_DATA_SIGNATURE,               // Signature
23   NULL,                                         // SmmCpuHandle
24   NULL,                                         // Pointer to ProcessorInfo array
25   NULL,                                         // Pointer to Operation array
26   NULL,                                         // Pointer to CpuSaveStateSize array
27   NULL,                                         // Pointer to CpuSaveState array
28   { {0} },                                      // SmmReservedSmramRegion
29   {
30     SmmStartupThisAp,                           // SmmCoreEntryContext.SmmStartupThisAp
31     0,                                          // SmmCoreEntryContext.CurrentlyExecutingCpu
32     0,                                          // SmmCoreEntryContext.NumberOfCpus
33     NULL,                                       // SmmCoreEntryContext.CpuSaveStateSize
34     NULL                                        // SmmCoreEntryContext.CpuSaveState
35   },
36   NULL,                                         // SmmCoreEntry
37   {
38     mSmmCpuPrivateData.SmmReservedSmramRegion,  // SmmConfiguration.SmramReservedRegions
39     RegisterSmmEntry                            // SmmConfiguration.RegisterSmmEntry
40   },
41 };
42 
43 CPU_HOT_PLUG_DATA mCpuHotPlugData = {
44   CPU_HOT_PLUG_DATA_REVISION_1,                 // Revision
45   0,                                            // Array Length of SmBase and APIC ID
46   NULL,                                         // Pointer to APIC ID array
47   NULL,                                         // Pointer to SMBASE array
48   0,                                            // Reserved
49   0,                                            // SmrrBase
50   0                                             // SmrrSize
51 };
52 
53 //
54 // Global pointer used to access mSmmCpuPrivateData from outside and inside SMM
55 //
56 SMM_CPU_PRIVATE_DATA  *gSmmCpuPrivate = &mSmmCpuPrivateData;
57 
58 //
59 // SMM Relocation variables
60 //
61 volatile BOOLEAN  *mRebased;
62 volatile BOOLEAN  mIsBsp;
63 
64 ///
65 /// Handle for the SMM CPU Protocol
66 ///
67 EFI_HANDLE  mSmmCpuHandle = NULL;
68 
69 ///
70 /// SMM CPU Protocol instance
71 ///
72 EFI_SMM_CPU_PROTOCOL  mSmmCpu  = {
73   SmmReadSaveState,
74   SmmWriteSaveState
75 };
76 
77 EFI_CPU_INTERRUPT_HANDLER   mExternalVectorTable[EXCEPTION_VECTOR_NUMBER];
78 
79 //
80 // SMM stack information
81 //
82 UINTN mSmmStackArrayBase;
83 UINTN mSmmStackArrayEnd;
84 UINTN mSmmStackSize;
85 
86 //
87 // Pointer to structure used during S3 Resume
88 //
89 SMM_S3_RESUME_STATE *mSmmS3ResumeState = NULL;
90 
91 UINTN mMaxNumberOfCpus = 1;
92 UINTN mNumberOfCpus = 1;
93 
94 //
95 // SMM ready to lock flag
96 //
97 BOOLEAN mSmmReadyToLock = FALSE;
98 
99 //
100 // Global used to cache PCD for SMM Code Access Check enable
101 //
102 BOOLEAN                  mSmmCodeAccessCheckEnable = FALSE;
103 
104 //
105 // Spin lock used to serialize setting of SMM Code Access Check feature
106 //
107 SPIN_LOCK                mConfigSmmCodeAccessCheckLock;
108 
109 /**
110   Initialize IDT to setup exception handlers for SMM.
111 
112 **/
113 VOID
InitializeSmmIdt(VOID)114 InitializeSmmIdt (
115   VOID
116   )
117 {
118   EFI_STATUS               Status;
119   BOOLEAN                  InterruptState;
120   IA32_DESCRIPTOR          DxeIdtr;
121   //
122   // Disable Interrupt and save DXE IDT table
123   //
124   InterruptState = SaveAndDisableInterrupts ();
125   AsmReadIdtr (&DxeIdtr);
126   //
127   // Load SMM temporary IDT table
128   //
129   AsmWriteIdtr (&gcSmiIdtr);
130   //
131   // Setup SMM default exception handlers, SMM IDT table
132   // will be updated and saved in gcSmiIdtr
133   //
134   Status = InitializeCpuExceptionHandlers (NULL);
135   ASSERT_EFI_ERROR (Status);
136   //
137   // Restore DXE IDT table and CPU interrupt
138   //
139   AsmWriteIdtr ((IA32_DESCRIPTOR *) &DxeIdtr);
140   SetInterruptState (InterruptState);
141 }
142 
143 /**
144   Search module name by input IP address and output it.
145 
146   @param CallerIpAddress   Caller instruction pointer.
147 
148 **/
149 VOID
DumpModuleInfoByIp(IN UINTN CallerIpAddress)150 DumpModuleInfoByIp (
151   IN  UINTN              CallerIpAddress
152   )
153 {
154   UINTN                                Pe32Data;
155   EFI_IMAGE_DOS_HEADER                 *DosHdr;
156   EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION  Hdr;
157   VOID                                 *PdbPointer;
158   UINT64                               DumpIpAddress;
159 
160   //
161   // Find Image Base
162   //
163   Pe32Data = CallerIpAddress & ~(SIZE_4KB - 1);
164   while (Pe32Data != 0) {
165     DosHdr = (EFI_IMAGE_DOS_HEADER *) Pe32Data;
166     if (DosHdr->e_magic == EFI_IMAGE_DOS_SIGNATURE) {
167       //
168       // DOS image header is present, so read the PE header after the DOS image header.
169       //
170       Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *)(Pe32Data + (UINTN) ((DosHdr->e_lfanew) & 0x0ffff));
171       //
172       // Make sure PE header address does not overflow and is less than the initial address.
173       //
174       if (((UINTN)Hdr.Pe32 > Pe32Data) && ((UINTN)Hdr.Pe32 < CallerIpAddress)) {
175         if (Hdr.Pe32->Signature == EFI_IMAGE_NT_SIGNATURE) {
176           //
177           // It's PE image.
178           //
179           break;
180         }
181       }
182     }
183 
184     //
185     // Not found the image base, check the previous aligned address
186     //
187     Pe32Data -= SIZE_4KB;
188   }
189 
190   DumpIpAddress = CallerIpAddress;
191   DEBUG ((EFI_D_ERROR, "It is invoked from the instruction before IP(0x%lx)", DumpIpAddress));
192 
193   if (Pe32Data != 0) {
194     PdbPointer = PeCoffLoaderGetPdbPointer ((VOID *) Pe32Data);
195     if (PdbPointer != NULL) {
196       DEBUG ((EFI_D_ERROR, " in module (%a)", PdbPointer));
197     }
198   }
199 }
200 
201 /**
202   Read information from the CPU save state.
203 
204   @param  This      EFI_SMM_CPU_PROTOCOL instance
205   @param  Width     The number of bytes to read from the CPU save state.
206   @param  Register  Specifies the CPU register to read form the save state.
207   @param  CpuIndex  Specifies the zero-based index of the CPU save state.
208   @param  Buffer    Upon return, this holds the CPU register value read from the save state.
209 
210   @retval EFI_SUCCESS   The register was read from Save State
211   @retval EFI_NOT_FOUND The register is not defined for the Save State of Processor
212   @retval EFI_INVALID_PARAMTER   This or Buffer is NULL.
213 
214 **/
215 EFI_STATUS
216 EFIAPI
SmmReadSaveState(IN CONST EFI_SMM_CPU_PROTOCOL * This,IN UINTN Width,IN EFI_SMM_SAVE_STATE_REGISTER Register,IN UINTN CpuIndex,OUT VOID * Buffer)217 SmmReadSaveState (
218   IN CONST EFI_SMM_CPU_PROTOCOL         *This,
219   IN UINTN                              Width,
220   IN EFI_SMM_SAVE_STATE_REGISTER        Register,
221   IN UINTN                              CpuIndex,
222   OUT VOID                              *Buffer
223   )
224 {
225   EFI_STATUS  Status;
226 
227   //
228   // Retrieve pointer to the specified CPU's SMM Save State buffer
229   //
230   if ((CpuIndex >= gSmst->NumberOfCpus) || (Buffer == NULL)) {
231     return EFI_INVALID_PARAMETER;
232   }
233 
234   //
235   // Check for special EFI_SMM_SAVE_STATE_REGISTER_PROCESSOR_ID
236   //
237   if (Register == EFI_SMM_SAVE_STATE_REGISTER_PROCESSOR_ID) {
238     //
239     // The pseudo-register only supports the 64-bit size specified by Width.
240     //
241     if (Width != sizeof (UINT64)) {
242       return EFI_INVALID_PARAMETER;
243     }
244     //
245     // If the processor is in SMM at the time the SMI occurred,
246     // the pseudo register value for EFI_SMM_SAVE_STATE_REGISTER_PROCESSOR_ID is returned in Buffer.
247     // Otherwise, EFI_NOT_FOUND is returned.
248     //
249     if (mSmmMpSyncData->CpuData[CpuIndex].Present) {
250       *(UINT64 *)Buffer = gSmmCpuPrivate->ProcessorInfo[CpuIndex].ProcessorId;
251       return EFI_SUCCESS;
252     } else {
253       return EFI_NOT_FOUND;
254     }
255   }
256 
257   if (!mSmmMpSyncData->CpuData[CpuIndex].Present) {
258     return EFI_INVALID_PARAMETER;
259   }
260 
261   Status = SmmCpuFeaturesReadSaveStateRegister (CpuIndex, Register, Width, Buffer);
262   if (Status == EFI_UNSUPPORTED) {
263     Status = ReadSaveStateRegister (CpuIndex, Register, Width, Buffer);
264   }
265   return Status;
266 }
267 
268 /**
269   Write data to the CPU save state.
270 
271   @param  This      EFI_SMM_CPU_PROTOCOL instance
272   @param  Width     The number of bytes to read from the CPU save state.
273   @param  Register  Specifies the CPU register to write to the save state.
274   @param  CpuIndex  Specifies the zero-based index of the CPU save state
275   @param  Buffer    Upon entry, this holds the new CPU register value.
276 
277   @retval EFI_SUCCESS   The register was written from Save State
278   @retval EFI_NOT_FOUND The register is not defined for the Save State of Processor
279   @retval EFI_INVALID_PARAMTER   ProcessorIndex or Width is not correct
280 
281 **/
282 EFI_STATUS
283 EFIAPI
SmmWriteSaveState(IN CONST EFI_SMM_CPU_PROTOCOL * This,IN UINTN Width,IN EFI_SMM_SAVE_STATE_REGISTER Register,IN UINTN CpuIndex,IN CONST VOID * Buffer)284 SmmWriteSaveState (
285   IN CONST EFI_SMM_CPU_PROTOCOL         *This,
286   IN UINTN                              Width,
287   IN EFI_SMM_SAVE_STATE_REGISTER        Register,
288   IN UINTN                              CpuIndex,
289   IN CONST VOID                         *Buffer
290   )
291 {
292   EFI_STATUS  Status;
293 
294   //
295   // Retrieve pointer to the specified CPU's SMM Save State buffer
296   //
297   if ((CpuIndex >= gSmst->NumberOfCpus) || (Buffer == NULL)) {
298     return EFI_INVALID_PARAMETER;
299   }
300 
301   //
302   // Writes to EFI_SMM_SAVE_STATE_REGISTER_PROCESSOR_ID are ignored
303   //
304   if (Register == EFI_SMM_SAVE_STATE_REGISTER_PROCESSOR_ID) {
305     return EFI_SUCCESS;
306   }
307 
308   if (!mSmmMpSyncData->CpuData[CpuIndex].Present) {
309     return EFI_INVALID_PARAMETER;
310   }
311 
312   Status = SmmCpuFeaturesWriteSaveStateRegister (CpuIndex, Register, Width, Buffer);
313   if (Status == EFI_UNSUPPORTED) {
314     Status = WriteSaveStateRegister (CpuIndex, Register, Width, Buffer);
315   }
316   return Status;
317 }
318 
319 
320 /**
321   C function for SMI handler. To change all processor's SMMBase Register.
322 
323 **/
324 VOID
325 EFIAPI
SmmInitHandler(VOID)326 SmmInitHandler (
327   VOID
328   )
329 {
330   UINT32                            ApicId;
331   UINTN                             Index;
332 
333   //
334   // Update SMM IDT entries' code segment and load IDT
335   //
336   AsmWriteIdtr (&gcSmiIdtr);
337   ApicId = GetApicId ();
338 
339   ASSERT (mNumberOfCpus <= PcdGet32 (PcdCpuMaxLogicalProcessorNumber));
340 
341   for (Index = 0; Index < mNumberOfCpus; Index++) {
342     if (ApicId == (UINT32)gSmmCpuPrivate->ProcessorInfo[Index].ProcessorId) {
343       //
344       // Initialize SMM specific features on the currently executing CPU
345       //
346       SmmCpuFeaturesInitializeProcessor (
347         Index,
348         mIsBsp,
349         gSmmCpuPrivate->ProcessorInfo,
350         &mCpuHotPlugData
351         );
352 
353       if (mIsBsp) {
354         //
355         // BSP rebase is already done above.
356         // Initialize private data during S3 resume
357         //
358         InitializeMpSyncData ();
359       }
360 
361       //
362       // Hook return after RSM to set SMM re-based flag
363       //
364       SemaphoreHook (Index, &mRebased[Index]);
365 
366       return;
367     }
368   }
369   ASSERT (FALSE);
370 }
371 
372 /**
373   Relocate SmmBases for each processor.
374 
375   Execute on first boot and all S3 resumes
376 
377 **/
378 VOID
379 EFIAPI
SmmRelocateBases(VOID)380 SmmRelocateBases (
381   VOID
382   )
383 {
384   UINT8                 BakBuf[BACK_BUF_SIZE];
385   SMRAM_SAVE_STATE_MAP  BakBuf2;
386   SMRAM_SAVE_STATE_MAP  *CpuStatePtr;
387   UINT8                 *U8Ptr;
388   UINT32                ApicId;
389   UINTN                 Index;
390   UINTN                 BspIndex;
391 
392   //
393   // Make sure the reserved size is large enough for procedure SmmInitTemplate.
394   //
395   ASSERT (sizeof (BakBuf) >= gcSmmInitSize);
396 
397   //
398   // Patch ASM code template with current CR0, CR3, and CR4 values
399   //
400   gSmmCr0 = (UINT32)AsmReadCr0 ();
401   gSmmCr3 = (UINT32)AsmReadCr3 ();
402   gSmmCr4 = (UINT32)AsmReadCr4 ();
403 
404   //
405   // Patch GDTR for SMM base relocation
406   //
407   gcSmiInitGdtr.Base  = gcSmiGdtr.Base;
408   gcSmiInitGdtr.Limit = gcSmiGdtr.Limit;
409 
410   U8Ptr = (UINT8*)(UINTN)(SMM_DEFAULT_SMBASE + SMM_HANDLER_OFFSET);
411   CpuStatePtr = (SMRAM_SAVE_STATE_MAP *)(UINTN)(SMM_DEFAULT_SMBASE + SMRAM_SAVE_STATE_MAP_OFFSET);
412 
413   //
414   // Backup original contents at address 0x38000
415   //
416   CopyMem (BakBuf, U8Ptr, sizeof (BakBuf));
417   CopyMem (&BakBuf2, CpuStatePtr, sizeof (BakBuf2));
418 
419   //
420   // Load image for relocation
421   //
422   CopyMem (U8Ptr, gcSmmInitTemplate, gcSmmInitSize);
423 
424   //
425   // Retrieve the local APIC ID of current processor
426   //
427   ApicId = GetApicId ();
428 
429   //
430   // Relocate SM bases for all APs
431   // This is APs' 1st SMI - rebase will be done here, and APs' default SMI handler will be overridden by gcSmmInitTemplate
432   //
433   mIsBsp   = FALSE;
434   BspIndex = (UINTN)-1;
435   for (Index = 0; Index < mNumberOfCpus; Index++) {
436     mRebased[Index] = FALSE;
437     if (ApicId != (UINT32)gSmmCpuPrivate->ProcessorInfo[Index].ProcessorId) {
438       SendSmiIpi ((UINT32)gSmmCpuPrivate->ProcessorInfo[Index].ProcessorId);
439       //
440       // Wait for this AP to finish its 1st SMI
441       //
442       while (!mRebased[Index]);
443     } else {
444       //
445       // BSP will be Relocated later
446       //
447       BspIndex = Index;
448     }
449   }
450 
451   //
452   // Relocate BSP's SMM base
453   //
454   ASSERT (BspIndex != (UINTN)-1);
455   mIsBsp = TRUE;
456   SendSmiIpi (ApicId);
457   //
458   // Wait for the BSP to finish its 1st SMI
459   //
460   while (!mRebased[BspIndex]);
461 
462   //
463   // Restore contents at address 0x38000
464   //
465   CopyMem (CpuStatePtr, &BakBuf2, sizeof (BakBuf2));
466   CopyMem (U8Ptr, BakBuf, sizeof (BakBuf));
467 }
468 
469 /**
470   Perform SMM initialization for all processors in the S3 boot path.
471 
472   For a native platform, MP initialization in the S3 boot path is also performed in this function.
473 **/
474 VOID
475 EFIAPI
SmmRestoreCpu(VOID)476 SmmRestoreCpu (
477   VOID
478   )
479 {
480   SMM_S3_RESUME_STATE           *SmmS3ResumeState;
481   IA32_DESCRIPTOR               Ia32Idtr;
482   IA32_DESCRIPTOR               X64Idtr;
483   IA32_IDT_GATE_DESCRIPTOR      IdtEntryTable[EXCEPTION_VECTOR_NUMBER];
484   EFI_STATUS                    Status;
485 
486   DEBUG ((EFI_D_INFO, "SmmRestoreCpu()\n"));
487 
488   //
489   // See if there is enough context to resume PEI Phase
490   //
491   if (mSmmS3ResumeState == NULL) {
492     DEBUG ((EFI_D_ERROR, "No context to return to PEI Phase\n"));
493     CpuDeadLoop ();
494   }
495 
496   SmmS3ResumeState = mSmmS3ResumeState;
497   ASSERT (SmmS3ResumeState != NULL);
498 
499   if (SmmS3ResumeState->Signature == SMM_S3_RESUME_SMM_64) {
500     //
501     // Save the IA32 IDT Descriptor
502     //
503     AsmReadIdtr ((IA32_DESCRIPTOR *) &Ia32Idtr);
504 
505     //
506     // Setup X64 IDT table
507     //
508     ZeroMem (IdtEntryTable, sizeof (IA32_IDT_GATE_DESCRIPTOR) * 32);
509     X64Idtr.Base = (UINTN) IdtEntryTable;
510     X64Idtr.Limit = (UINT16) (sizeof (IA32_IDT_GATE_DESCRIPTOR) * 32 - 1);
511     AsmWriteIdtr ((IA32_DESCRIPTOR *) &X64Idtr);
512 
513     //
514     // Setup the default exception handler
515     //
516     Status = InitializeCpuExceptionHandlers (NULL);
517     ASSERT_EFI_ERROR (Status);
518 
519     //
520     // Initialize Debug Agent to support source level debug
521     //
522     InitializeDebugAgent (DEBUG_AGENT_INIT_THUNK_PEI_IA32TOX64, (VOID *)&Ia32Idtr, NULL);
523   }
524 
525   //
526   // Skip initialization if mAcpiCpuData is not valid
527   //
528   if (mAcpiCpuData.NumberOfCpus > 0) {
529     //
530     // First time microcode load and restore MTRRs
531     //
532     EarlyInitializeCpu ();
533   }
534 
535   //
536   // Restore SMBASE for BSP and all APs
537   //
538   SmmRelocateBases ();
539 
540   //
541   // Skip initialization if mAcpiCpuData is not valid
542   //
543   if (mAcpiCpuData.NumberOfCpus > 0) {
544     //
545     // Restore MSRs for BSP and all APs
546     //
547     InitializeCpu ();
548   }
549 
550   //
551   // Set a flag to restore SMM configuration in S3 path.
552   //
553   mRestoreSmmConfigurationInS3 = TRUE;
554 
555   DEBUG (( EFI_D_INFO, "SMM S3 Return CS                = %x\n", SmmS3ResumeState->ReturnCs));
556   DEBUG (( EFI_D_INFO, "SMM S3 Return Entry Point       = %x\n", SmmS3ResumeState->ReturnEntryPoint));
557   DEBUG (( EFI_D_INFO, "SMM S3 Return Context1          = %x\n", SmmS3ResumeState->ReturnContext1));
558   DEBUG (( EFI_D_INFO, "SMM S3 Return Context2          = %x\n", SmmS3ResumeState->ReturnContext2));
559   DEBUG (( EFI_D_INFO, "SMM S3 Return Stack Pointer     = %x\n", SmmS3ResumeState->ReturnStackPointer));
560 
561   //
562   // If SMM is in 32-bit mode, then use SwitchStack() to resume PEI Phase
563   //
564   if (SmmS3ResumeState->Signature == SMM_S3_RESUME_SMM_32) {
565     DEBUG ((EFI_D_INFO, "Call SwitchStack() to return to S3 Resume in PEI Phase\n"));
566 
567     SwitchStack (
568       (SWITCH_STACK_ENTRY_POINT)(UINTN)SmmS3ResumeState->ReturnEntryPoint,
569       (VOID *)(UINTN)SmmS3ResumeState->ReturnContext1,
570       (VOID *)(UINTN)SmmS3ResumeState->ReturnContext2,
571       (VOID *)(UINTN)SmmS3ResumeState->ReturnStackPointer
572       );
573   }
574 
575   //
576   // If SMM is in 64-bit mode, then use AsmDisablePaging64() to resume PEI Phase
577   //
578   if (SmmS3ResumeState->Signature == SMM_S3_RESUME_SMM_64) {
579     DEBUG ((EFI_D_INFO, "Call AsmDisablePaging64() to return to S3 Resume in PEI Phase\n"));
580     //
581     // Disable interrupt of Debug timer, since new IDT table is for IA32 and will not work in long mode.
582     //
583     SaveAndSetDebugTimerInterrupt (FALSE);
584     //
585     // Restore IA32 IDT table
586     //
587     AsmWriteIdtr ((IA32_DESCRIPTOR *) &Ia32Idtr);
588     AsmDisablePaging64 (
589       SmmS3ResumeState->ReturnCs,
590       (UINT32)SmmS3ResumeState->ReturnEntryPoint,
591       (UINT32)SmmS3ResumeState->ReturnContext1,
592       (UINT32)SmmS3ResumeState->ReturnContext2,
593       (UINT32)SmmS3ResumeState->ReturnStackPointer
594       );
595   }
596 
597   //
598   // Can not resume PEI Phase
599   //
600   DEBUG ((EFI_D_ERROR, "No context to return to PEI Phase\n"));
601   CpuDeadLoop ();
602 }
603 
604 /**
605   Copy register table from ACPI NVS memory into SMRAM.
606 
607   @param[in] DestinationRegisterTableList  Points to destination register table.
608   @param[in] SourceRegisterTableList       Points to source register table.
609   @param[in] NumberOfCpus                  Number of CPUs.
610 
611 **/
612 VOID
CopyRegisterTable(IN CPU_REGISTER_TABLE * DestinationRegisterTableList,IN CPU_REGISTER_TABLE * SourceRegisterTableList,IN UINT32 NumberOfCpus)613 CopyRegisterTable (
614   IN CPU_REGISTER_TABLE         *DestinationRegisterTableList,
615   IN CPU_REGISTER_TABLE         *SourceRegisterTableList,
616   IN UINT32                     NumberOfCpus
617   )
618 {
619   UINTN                      Index;
620   UINTN                      Index1;
621   CPU_REGISTER_TABLE_ENTRY   *RegisterTableEntry;
622 
623   CopyMem (DestinationRegisterTableList, SourceRegisterTableList, NumberOfCpus * sizeof (CPU_REGISTER_TABLE));
624   for (Index = 0; Index < NumberOfCpus; Index++) {
625     DestinationRegisterTableList[Index].RegisterTableEntry = AllocatePool (DestinationRegisterTableList[Index].AllocatedSize);
626     ASSERT (DestinationRegisterTableList[Index].RegisterTableEntry != NULL);
627     CopyMem (DestinationRegisterTableList[Index].RegisterTableEntry, SourceRegisterTableList[Index].RegisterTableEntry, DestinationRegisterTableList[Index].AllocatedSize);
628     //
629     // Go though all MSRs in register table to initialize MSR spin lock
630     //
631     RegisterTableEntry = DestinationRegisterTableList[Index].RegisterTableEntry;
632     for (Index1 = 0; Index1 < DestinationRegisterTableList[Index].TableLength; Index1++, RegisterTableEntry++) {
633       if ((RegisterTableEntry->RegisterType == Msr) && (RegisterTableEntry->ValidBitLength < 64)) {
634         //
635         // Initialize MSR spin lock only for those MSRs need bit field writing
636         //
637         InitMsrSpinLockByIndex (RegisterTableEntry->Index);
638       }
639     }
640   }
641 }
642 
643 /**
644   SMM Ready To Lock event notification handler.
645 
646   The CPU S3 data is copied to SMRAM for security and mSmmReadyToLock is set to
647   perform additional lock actions that must be performed from SMM on the next SMI.
648 
649   @param[in] Protocol   Points to the protocol's unique identifier.
650   @param[in] Interface  Points to the interface instance.
651   @param[in] Handle     The handle on which the interface was installed.
652 
653   @retval EFI_SUCCESS   Notification handler runs successfully.
654  **/
655 EFI_STATUS
656 EFIAPI
SmmReadyToLockEventNotify(IN CONST EFI_GUID * Protocol,IN VOID * Interface,IN EFI_HANDLE Handle)657 SmmReadyToLockEventNotify (
658   IN CONST EFI_GUID  *Protocol,
659   IN VOID            *Interface,
660   IN EFI_HANDLE      Handle
661   )
662 {
663   ACPI_CPU_DATA              *AcpiCpuData;
664   IA32_DESCRIPTOR            *Gdtr;
665   IA32_DESCRIPTOR            *Idtr;
666 
667   //
668   // Prevent use of mAcpiCpuData by initialize NumberOfCpus to 0
669   //
670   mAcpiCpuData.NumberOfCpus = 0;
671 
672   //
673   // If PcdCpuS3DataAddress was never set, then do not copy CPU S3 Data into SMRAM
674   //
675   AcpiCpuData = (ACPI_CPU_DATA *)(UINTN)PcdGet64 (PcdCpuS3DataAddress);
676   if (AcpiCpuData == 0) {
677     goto Done;
678   }
679 
680   //
681   // For a native platform, copy the CPU S3 data into SMRAM for use on CPU S3 Resume.
682   //
683   CopyMem (&mAcpiCpuData, AcpiCpuData, sizeof (mAcpiCpuData));
684 
685   mAcpiCpuData.MtrrTable = (EFI_PHYSICAL_ADDRESS)(UINTN)AllocatePool (sizeof (MTRR_SETTINGS));
686   ASSERT (mAcpiCpuData.MtrrTable != 0);
687 
688   CopyMem ((VOID *)(UINTN)mAcpiCpuData.MtrrTable, (VOID *)(UINTN)AcpiCpuData->MtrrTable, sizeof (MTRR_SETTINGS));
689 
690   mAcpiCpuData.GdtrProfile = (EFI_PHYSICAL_ADDRESS)(UINTN)AllocatePool (sizeof (IA32_DESCRIPTOR));
691   ASSERT (mAcpiCpuData.GdtrProfile != 0);
692 
693   CopyMem ((VOID *)(UINTN)mAcpiCpuData.GdtrProfile, (VOID *)(UINTN)AcpiCpuData->GdtrProfile, sizeof (IA32_DESCRIPTOR));
694 
695   mAcpiCpuData.IdtrProfile = (EFI_PHYSICAL_ADDRESS)(UINTN)AllocatePool (sizeof (IA32_DESCRIPTOR));
696   ASSERT (mAcpiCpuData.IdtrProfile != 0);
697 
698   CopyMem ((VOID *)(UINTN)mAcpiCpuData.IdtrProfile, (VOID *)(UINTN)AcpiCpuData->IdtrProfile, sizeof (IA32_DESCRIPTOR));
699 
700   mAcpiCpuData.PreSmmInitRegisterTable = (EFI_PHYSICAL_ADDRESS)(UINTN)AllocatePool (mAcpiCpuData.NumberOfCpus * sizeof (CPU_REGISTER_TABLE));
701   ASSERT (mAcpiCpuData.PreSmmInitRegisterTable != 0);
702 
703   CopyRegisterTable (
704     (CPU_REGISTER_TABLE *)(UINTN)mAcpiCpuData.PreSmmInitRegisterTable,
705     (CPU_REGISTER_TABLE *)(UINTN)AcpiCpuData->PreSmmInitRegisterTable,
706     mAcpiCpuData.NumberOfCpus
707     );
708 
709   mAcpiCpuData.RegisterTable = (EFI_PHYSICAL_ADDRESS)(UINTN)AllocatePool (mAcpiCpuData.NumberOfCpus * sizeof (CPU_REGISTER_TABLE));
710   ASSERT (mAcpiCpuData.RegisterTable != 0);
711 
712   CopyRegisterTable (
713     (CPU_REGISTER_TABLE *)(UINTN)mAcpiCpuData.RegisterTable,
714     (CPU_REGISTER_TABLE *)(UINTN)AcpiCpuData->RegisterTable,
715     mAcpiCpuData.NumberOfCpus
716     );
717 
718   //
719   // Copy AP's GDT, IDT and Machine Check handler into SMRAM.
720   //
721   Gdtr = (IA32_DESCRIPTOR *)(UINTN)mAcpiCpuData.GdtrProfile;
722   Idtr = (IA32_DESCRIPTOR *)(UINTN)mAcpiCpuData.IdtrProfile;
723 
724   mGdtForAp = AllocatePool ((Gdtr->Limit + 1) + (Idtr->Limit + 1) +  mAcpiCpuData.ApMachineCheckHandlerSize);
725   ASSERT (mGdtForAp != NULL);
726   mIdtForAp = (VOID *) ((UINTN)mGdtForAp + (Gdtr->Limit + 1));
727   mMachineCheckHandlerForAp = (VOID *) ((UINTN)mIdtForAp + (Idtr->Limit + 1));
728 
729   CopyMem (mGdtForAp, (VOID *)Gdtr->Base, Gdtr->Limit + 1);
730   CopyMem (mIdtForAp, (VOID *)Idtr->Base, Idtr->Limit + 1);
731   CopyMem (mMachineCheckHandlerForAp, (VOID *)(UINTN)mAcpiCpuData.ApMachineCheckHandlerBase, mAcpiCpuData.ApMachineCheckHandlerSize);
732 
733 Done:
734   //
735   // Set SMM ready to lock flag and return
736   //
737   mSmmReadyToLock = TRUE;
738   return EFI_SUCCESS;
739 }
740 
741 /**
742   The module Entry Point of the CPU SMM driver.
743 
744   @param  ImageHandle    The firmware allocated handle for the EFI image.
745   @param  SystemTable    A pointer to the EFI System Table.
746 
747   @retval EFI_SUCCESS    The entry point is executed successfully.
748   @retval Other          Some error occurs when executing this entry point.
749 
750 **/
751 EFI_STATUS
752 EFIAPI
PiCpuSmmEntry(IN EFI_HANDLE ImageHandle,IN EFI_SYSTEM_TABLE * SystemTable)753 PiCpuSmmEntry (
754   IN EFI_HANDLE        ImageHandle,
755   IN EFI_SYSTEM_TABLE  *SystemTable
756   )
757 {
758   EFI_STATUS                 Status;
759   EFI_MP_SERVICES_PROTOCOL   *MpServices;
760   UINTN                      NumberOfEnabledProcessors;
761   UINTN                      Index;
762   VOID                       *Buffer;
763   UINTN                      BufferPages;
764   UINTN                      TileCodeSize;
765   UINTN                      TileDataSize;
766   UINTN                      TileSize;
767   VOID                       *GuidHob;
768   EFI_SMRAM_DESCRIPTOR       *SmramDescriptor;
769   SMM_S3_RESUME_STATE        *SmmS3ResumeState;
770   UINT8                      *Stacks;
771   VOID                       *Registration;
772   UINT32                     RegEax;
773   UINT32                     RegEdx;
774   UINTN                      FamilyId;
775   UINTN                      ModelId;
776   UINT32                     Cr3;
777 
778   //
779   // Initialize Debug Agent to support source level debug in SMM code
780   //
781   InitializeDebugAgent (DEBUG_AGENT_INIT_SMM, NULL, NULL);
782 
783   //
784   // Report the start of CPU SMM initialization.
785   //
786   REPORT_STATUS_CODE (
787     EFI_PROGRESS_CODE,
788     EFI_COMPUTING_UNIT_HOST_PROCESSOR | EFI_CU_HP_PC_SMM_INIT
789     );
790 
791   //
792   // Fix segment address of the long-mode-switch jump
793   //
794   if (sizeof (UINTN) == sizeof (UINT64)) {
795     gSmmJmpAddr.Segment = LONG_MODE_CODE_SEGMENT;
796   }
797 
798   //
799   // Find out SMRR Base and SMRR Size
800   //
801   FindSmramInfo (&mCpuHotPlugData.SmrrBase, &mCpuHotPlugData.SmrrSize);
802 
803   //
804   // Get MP Services Protocol
805   //
806   Status = SystemTable->BootServices->LocateProtocol (&gEfiMpServiceProtocolGuid, NULL, (VOID **)&MpServices);
807   ASSERT_EFI_ERROR (Status);
808 
809   //
810   // Use MP Services Protocol to retrieve the number of processors and number of enabled processors
811   //
812   Status = MpServices->GetNumberOfProcessors (MpServices, &mNumberOfCpus, &NumberOfEnabledProcessors);
813   ASSERT_EFI_ERROR (Status);
814   ASSERT (mNumberOfCpus <= PcdGet32 (PcdCpuMaxLogicalProcessorNumber));
815 
816   //
817   // If support CPU hot plug, PcdCpuSmmEnableBspElection should be set to TRUE.
818   // A constant BSP index makes no sense because it may be hot removed.
819   //
820   DEBUG_CODE (
821     if (FeaturePcdGet (PcdCpuHotPlugSupport)) {
822 
823       ASSERT (FeaturePcdGet (PcdCpuSmmEnableBspElection));
824     }
825   );
826 
827   //
828   // Save the PcdCpuSmmCodeAccessCheckEnable value into a global variable.
829   //
830   mSmmCodeAccessCheckEnable = PcdGetBool (PcdCpuSmmCodeAccessCheckEnable);
831   DEBUG ((EFI_D_INFO, "PcdCpuSmmCodeAccessCheckEnable = %d\n", mSmmCodeAccessCheckEnable));
832 
833   //
834   // If support CPU hot plug, we need to allocate resources for possibly hot-added processors
835   //
836   if (FeaturePcdGet (PcdCpuHotPlugSupport)) {
837     mMaxNumberOfCpus = PcdGet32 (PcdCpuMaxLogicalProcessorNumber);
838   } else {
839     mMaxNumberOfCpus = mNumberOfCpus;
840   }
841   gSmmCpuPrivate->SmmCoreEntryContext.NumberOfCpus = mMaxNumberOfCpus;
842 
843   //
844   // The CPU save state and code for the SMI entry point are tiled within an SMRAM
845   // allocated buffer.  The minimum size of this buffer for a uniprocessor system
846   // is 32 KB, because the entry point is SMBASE + 32KB, and CPU save state area
847   // just below SMBASE + 64KB.  If more than one CPU is present in the platform,
848   // then the SMI entry point and the CPU save state areas can be tiles to minimize
849   // the total amount SMRAM required for all the CPUs.  The tile size can be computed
850   // by adding the   // CPU save state size, any extra CPU specific context, and
851   // the size of code that must be placed at the SMI entry point to transfer
852   // control to a C function in the native SMM execution mode.  This size is
853   // rounded up to the nearest power of 2 to give the tile size for a each CPU.
854   // The total amount of memory required is the maximum number of CPUs that
855   // platform supports times the tile size.  The picture below shows the tiling,
856   // where m is the number of tiles that fit in 32KB.
857   //
858   //  +-----------------------------+  <-- 2^n offset from Base of allocated buffer
859   //  |   CPU m+1 Save State        |
860   //  +-----------------------------+
861   //  |   CPU m+1 Extra Data        |
862   //  +-----------------------------+
863   //  |   Padding                   |
864   //  +-----------------------------+
865   //  |   CPU 2m  SMI Entry         |
866   //  +#############################+  <-- Base of allocated buffer + 64 KB
867   //  |   CPU m-1 Save State        |
868   //  +-----------------------------+
869   //  |   CPU m-1 Extra Data        |
870   //  +-----------------------------+
871   //  |   Padding                   |
872   //  +-----------------------------+
873   //  |   CPU 2m-1 SMI Entry        |
874   //  +=============================+  <-- 2^n offset from Base of allocated buffer
875   //  |   . . . . . . . . . . . .   |
876   //  +=============================+  <-- 2^n offset from Base of allocated buffer
877   //  |   CPU 2 Save State          |
878   //  +-----------------------------+
879   //  |   CPU 2 Extra Data          |
880   //  +-----------------------------+
881   //  |   Padding                   |
882   //  +-----------------------------+
883   //  |   CPU m+1 SMI Entry         |
884   //  +=============================+  <-- Base of allocated buffer + 32 KB
885   //  |   CPU 1 Save State          |
886   //  +-----------------------------+
887   //  |   CPU 1 Extra Data          |
888   //  +-----------------------------+
889   //  |   Padding                   |
890   //  +-----------------------------+
891   //  |   CPU m SMI Entry           |
892   //  +#############################+  <-- Base of allocated buffer + 32 KB == CPU 0 SMBASE + 64 KB
893   //  |   CPU 0 Save State          |
894   //  +-----------------------------+
895   //  |   CPU 0 Extra Data          |
896   //  +-----------------------------+
897   //  |   Padding                   |
898   //  +-----------------------------+
899   //  |   CPU m-1 SMI Entry         |
900   //  +=============================+  <-- 2^n offset from Base of allocated buffer
901   //  |   . . . . . . . . . . . .   |
902   //  +=============================+  <-- 2^n offset from Base of allocated buffer
903   //  |   Padding                   |
904   //  +-----------------------------+
905   //  |   CPU 1 SMI Entry           |
906   //  +=============================+  <-- 2^n offset from Base of allocated buffer
907   //  |   Padding                   |
908   //  +-----------------------------+
909   //  |   CPU 0 SMI Entry           |
910   //  +#############################+  <-- Base of allocated buffer == CPU 0 SMBASE + 32 KB
911   //
912 
913   //
914   // Retrieve CPU Family
915   //
916   AsmCpuid (CPUID_VERSION_INFO, &RegEax, NULL, NULL, NULL);
917   FamilyId = (RegEax >> 8) & 0xf;
918   ModelId = (RegEax >> 4) & 0xf;
919   if (FamilyId == 0x06 || FamilyId == 0x0f) {
920     ModelId = ModelId | ((RegEax >> 12) & 0xf0);
921   }
922 
923   RegEdx = 0;
924   AsmCpuid (CPUID_EXTENDED_FUNCTION, &RegEax, NULL, NULL, NULL);
925   if (RegEax >= CPUID_EXTENDED_CPU_SIG) {
926     AsmCpuid (CPUID_EXTENDED_CPU_SIG, NULL, NULL, NULL, &RegEdx);
927   }
928   //
929   // Determine the mode of the CPU at the time an SMI occurs
930   //   Intel(R) 64 and IA-32 Architectures Software Developer's Manual
931   //   Volume 3C, Section 34.4.1.1
932   //
933   mSmmSaveStateRegisterLma = EFI_SMM_SAVE_STATE_REGISTER_LMA_32BIT;
934   if ((RegEdx & BIT29) != 0) {
935     mSmmSaveStateRegisterLma = EFI_SMM_SAVE_STATE_REGISTER_LMA_64BIT;
936   }
937   if (FamilyId == 0x06) {
938     if (ModelId == 0x17 || ModelId == 0x0f || ModelId == 0x1c) {
939       mSmmSaveStateRegisterLma = EFI_SMM_SAVE_STATE_REGISTER_LMA_64BIT;
940     }
941   }
942 
943   //
944   // Compute tile size of buffer required to hold the CPU SMRAM Save State Map, extra CPU
945   // specific context in a PROCESSOR_SMM_DESCRIPTOR, and the SMI entry point.  This size
946   // is rounded up to nearest power of 2.
947   //
948   TileCodeSize = GetSmiHandlerSize ();
949   TileCodeSize = ALIGN_VALUE(TileCodeSize, SIZE_4KB);
950   TileDataSize = sizeof (SMRAM_SAVE_STATE_MAP) + sizeof (PROCESSOR_SMM_DESCRIPTOR);
951   TileDataSize = ALIGN_VALUE(TileDataSize, SIZE_4KB);
952   TileSize = TileDataSize + TileCodeSize - 1;
953   TileSize = 2 * GetPowerOfTwo32 ((UINT32)TileSize);
954   DEBUG ((EFI_D_INFO, "SMRAM TileSize = 0x%08x (0x%08x, 0x%08x)\n", TileSize, TileCodeSize, TileDataSize));
955 
956   //
957   // If the TileSize is larger than space available for the SMI Handler of CPU[i],
958   // the PROCESSOR_SMM_DESCRIPTOR of CPU[i+1] and the SMRAM Save State Map of CPU[i+1],
959   // the ASSERT().  If this ASSERT() is triggered, then the SMI Handler size must be
960   // reduced.
961   //
962   ASSERT (TileSize <= (SMRAM_SAVE_STATE_MAP_OFFSET + sizeof (SMRAM_SAVE_STATE_MAP) - SMM_HANDLER_OFFSET));
963 
964   //
965   // Allocate buffer for all of the tiles.
966   //
967   // Intel(R) 64 and IA-32 Architectures Software Developer's Manual
968   // Volume 3C, Section 34.11 SMBASE Relocation
969   //   For Pentium and Intel486 processors, the SMBASE values must be
970   //   aligned on a 32-KByte boundary or the processor will enter shutdown
971   //   state during the execution of a RSM instruction.
972   //
973   // Intel486 processors: FamilyId is 4
974   // Pentium processors : FamilyId is 5
975   //
976   BufferPages = EFI_SIZE_TO_PAGES (SIZE_32KB + TileSize * (mMaxNumberOfCpus - 1));
977   if ((FamilyId == 4) || (FamilyId == 5)) {
978     Buffer = AllocateAlignedPages (BufferPages, SIZE_32KB);
979   } else {
980     Buffer = AllocateAlignedPages (BufferPages, SIZE_4KB);
981   }
982   ASSERT (Buffer != NULL);
983   DEBUG ((EFI_D_INFO, "SMRAM SaveState Buffer (0x%08x, 0x%08x)\n", Buffer, EFI_PAGES_TO_SIZE(BufferPages)));
984 
985   //
986   // Allocate buffer for pointers to array in  SMM_CPU_PRIVATE_DATA.
987   //
988   gSmmCpuPrivate->ProcessorInfo = (EFI_PROCESSOR_INFORMATION *)AllocatePool (sizeof (EFI_PROCESSOR_INFORMATION) * mMaxNumberOfCpus);
989   ASSERT (gSmmCpuPrivate->ProcessorInfo != NULL);
990 
991   gSmmCpuPrivate->Operation = (SMM_CPU_OPERATION *)AllocatePool (sizeof (SMM_CPU_OPERATION) * mMaxNumberOfCpus);
992   ASSERT (gSmmCpuPrivate->Operation != NULL);
993 
994   gSmmCpuPrivate->CpuSaveStateSize = (UINTN *)AllocatePool (sizeof (UINTN) * mMaxNumberOfCpus);
995   ASSERT (gSmmCpuPrivate->CpuSaveStateSize != NULL);
996 
997   gSmmCpuPrivate->CpuSaveState = (VOID **)AllocatePool (sizeof (VOID *) * mMaxNumberOfCpus);
998   ASSERT (gSmmCpuPrivate->CpuSaveState != NULL);
999 
1000   mSmmCpuPrivateData.SmmCoreEntryContext.CpuSaveStateSize = gSmmCpuPrivate->CpuSaveStateSize;
1001   mSmmCpuPrivateData.SmmCoreEntryContext.CpuSaveState     = gSmmCpuPrivate->CpuSaveState;
1002 
1003   //
1004   // Allocate buffer for pointers to array in CPU_HOT_PLUG_DATA.
1005   //
1006   mCpuHotPlugData.ApicId = (UINT64 *)AllocatePool (sizeof (UINT64) * mMaxNumberOfCpus);
1007   ASSERT (mCpuHotPlugData.ApicId != NULL);
1008   mCpuHotPlugData.SmBase = (UINTN *)AllocatePool (sizeof (UINTN) * mMaxNumberOfCpus);
1009   ASSERT (mCpuHotPlugData.SmBase != NULL);
1010   mCpuHotPlugData.ArrayLength = (UINT32)mMaxNumberOfCpus;
1011 
1012   //
1013   // Retrieve APIC ID of each enabled processor from the MP Services protocol.
1014   // Also compute the SMBASE address, CPU Save State address, and CPU Save state
1015   // size for each CPU in the platform
1016   //
1017   for (Index = 0; Index < mMaxNumberOfCpus; Index++) {
1018     mCpuHotPlugData.SmBase[Index]          = (UINTN)Buffer + Index * TileSize - SMM_HANDLER_OFFSET;
1019     gSmmCpuPrivate->CpuSaveStateSize[Index] = sizeof(SMRAM_SAVE_STATE_MAP);
1020     gSmmCpuPrivate->CpuSaveState[Index]     = (VOID *)(mCpuHotPlugData.SmBase[Index] + SMRAM_SAVE_STATE_MAP_OFFSET);
1021     gSmmCpuPrivate->Operation[Index] = SmmCpuNone;
1022 
1023     if (Index < mNumberOfCpus) {
1024       Status = MpServices->GetProcessorInfo (MpServices, Index, &gSmmCpuPrivate->ProcessorInfo[Index]);
1025       ASSERT_EFI_ERROR (Status);
1026       mCpuHotPlugData.ApicId[Index] = gSmmCpuPrivate->ProcessorInfo[Index].ProcessorId;
1027 
1028       DEBUG ((EFI_D_INFO, "CPU[%03x]  APIC ID=%04x  SMBASE=%08x  SaveState=%08x  Size=%08x\n",
1029         Index,
1030         (UINT32)gSmmCpuPrivate->ProcessorInfo[Index].ProcessorId,
1031         mCpuHotPlugData.SmBase[Index],
1032         gSmmCpuPrivate->CpuSaveState[Index],
1033         gSmmCpuPrivate->CpuSaveStateSize[Index]
1034         ));
1035     } else {
1036       gSmmCpuPrivate->ProcessorInfo[Index].ProcessorId = INVALID_APIC_ID;
1037       mCpuHotPlugData.ApicId[Index] = INVALID_APIC_ID;
1038     }
1039   }
1040 
1041   //
1042   // Allocate SMI stacks for all processors.
1043   //
1044   if (FeaturePcdGet (PcdCpuSmmStackGuard)) {
1045     //
1046     // 2 more pages is allocated for each processor.
1047     // one is guard page and the other is known good stack.
1048     //
1049     // +-------------------------------------------+-----+-------------------------------------------+
1050     // | Known Good Stack | Guard Page | SMM Stack | ... | Known Good Stack | Guard Page | SMM Stack |
1051     // +-------------------------------------------+-----+-------------------------------------------+
1052     // |                                           |     |                                           |
1053     // |<-------------- Processor 0 -------------->|     |<-------------- Processor n -------------->|
1054     //
1055     mSmmStackSize = EFI_PAGES_TO_SIZE (EFI_SIZE_TO_PAGES (PcdGet32 (PcdCpuSmmStackSize)) + 2);
1056     Stacks = (UINT8 *) AllocatePages (gSmmCpuPrivate->SmmCoreEntryContext.NumberOfCpus * (EFI_SIZE_TO_PAGES (PcdGet32 (PcdCpuSmmStackSize)) + 2));
1057     ASSERT (Stacks != NULL);
1058     mSmmStackArrayBase = (UINTN)Stacks;
1059     mSmmStackArrayEnd = mSmmStackArrayBase + gSmmCpuPrivate->SmmCoreEntryContext.NumberOfCpus * mSmmStackSize - 1;
1060   } else {
1061     mSmmStackSize = PcdGet32 (PcdCpuSmmStackSize);
1062     Stacks = (UINT8 *) AllocatePages (EFI_SIZE_TO_PAGES (gSmmCpuPrivate->SmmCoreEntryContext.NumberOfCpus * mSmmStackSize));
1063     ASSERT (Stacks != NULL);
1064   }
1065 
1066   //
1067   // Set SMI stack for SMM base relocation
1068   //
1069   gSmmInitStack = (UINTN) (Stacks + mSmmStackSize - sizeof (UINTN));
1070 
1071   //
1072   // Initialize IDT
1073   //
1074   InitializeSmmIdt ();
1075 
1076   //
1077   // Relocate SMM Base addresses to the ones allocated from SMRAM
1078   //
1079   mRebased = (BOOLEAN *)AllocateZeroPool (sizeof (BOOLEAN) * mMaxNumberOfCpus);
1080   ASSERT (mRebased != NULL);
1081   SmmRelocateBases ();
1082 
1083   //
1084   // Call hook for BSP to perform extra actions in normal mode after all
1085   // SMM base addresses have been relocated on all CPUs
1086   //
1087   SmmCpuFeaturesSmmRelocationComplete ();
1088 
1089   //
1090   // SMM Time initialization
1091   //
1092   InitializeSmmTimer ();
1093 
1094   //
1095   // Initialize MP globals
1096   //
1097   Cr3 = InitializeMpServiceData (Stacks, mSmmStackSize);
1098 
1099   //
1100   // Fill in SMM Reserved Regions
1101   //
1102   gSmmCpuPrivate->SmmReservedSmramRegion[0].SmramReservedStart = 0;
1103   gSmmCpuPrivate->SmmReservedSmramRegion[0].SmramReservedSize  = 0;
1104 
1105   //
1106   // Install the SMM Configuration Protocol onto a new handle on the handle database.
1107   // The entire SMM Configuration Protocol is allocated from SMRAM, so only a pointer
1108   // to an SMRAM address will be present in the handle database
1109   //
1110   Status = SystemTable->BootServices->InstallMultipleProtocolInterfaces (
1111                                         &gSmmCpuPrivate->SmmCpuHandle,
1112                                         &gEfiSmmConfigurationProtocolGuid, &gSmmCpuPrivate->SmmConfiguration,
1113                                         NULL
1114                                         );
1115   ASSERT_EFI_ERROR (Status);
1116 
1117   //
1118   // Install the SMM CPU Protocol into SMM protocol database
1119   //
1120   Status = gSmst->SmmInstallProtocolInterface (
1121                     &mSmmCpuHandle,
1122                     &gEfiSmmCpuProtocolGuid,
1123                     EFI_NATIVE_INTERFACE,
1124                     &mSmmCpu
1125                     );
1126   ASSERT_EFI_ERROR (Status);
1127 
1128   //
1129   // Expose address of CPU Hot Plug Data structure if CPU hot plug is supported.
1130   //
1131   if (FeaturePcdGet (PcdCpuHotPlugSupport)) {
1132     Status = PcdSet64S (PcdCpuHotPlugDataAddress, (UINT64)(UINTN)&mCpuHotPlugData);
1133     ASSERT_EFI_ERROR (Status);
1134   }
1135 
1136   //
1137   // Initialize SMM CPU Services Support
1138   //
1139   Status = InitializeSmmCpuServices (mSmmCpuHandle);
1140   ASSERT_EFI_ERROR (Status);
1141 
1142   //
1143   // register SMM Ready To Lock Protocol notification
1144   //
1145   Status = gSmst->SmmRegisterProtocolNotify (
1146                     &gEfiSmmReadyToLockProtocolGuid,
1147                     SmmReadyToLockEventNotify,
1148                     &Registration
1149                     );
1150   ASSERT_EFI_ERROR (Status);
1151 
1152   GuidHob = GetFirstGuidHob (&gEfiAcpiVariableGuid);
1153   if (GuidHob != NULL) {
1154     SmramDescriptor = (EFI_SMRAM_DESCRIPTOR *) GET_GUID_HOB_DATA (GuidHob);
1155 
1156     DEBUG ((EFI_D_INFO, "SMM S3 SMRAM Structure = %x\n", SmramDescriptor));
1157     DEBUG ((EFI_D_INFO, "SMM S3 Structure = %x\n", SmramDescriptor->CpuStart));
1158 
1159     SmmS3ResumeState = (SMM_S3_RESUME_STATE *)(UINTN)SmramDescriptor->CpuStart;
1160     ZeroMem (SmmS3ResumeState, sizeof (SMM_S3_RESUME_STATE));
1161 
1162     mSmmS3ResumeState = SmmS3ResumeState;
1163     SmmS3ResumeState->Smst = (EFI_PHYSICAL_ADDRESS)(UINTN)gSmst;
1164 
1165     SmmS3ResumeState->SmmS3ResumeEntryPoint = (EFI_PHYSICAL_ADDRESS)(UINTN)SmmRestoreCpu;
1166 
1167     SmmS3ResumeState->SmmS3StackSize = SIZE_32KB;
1168     SmmS3ResumeState->SmmS3StackBase = (EFI_PHYSICAL_ADDRESS)(UINTN)AllocatePages (EFI_SIZE_TO_PAGES ((UINTN)SmmS3ResumeState->SmmS3StackSize));
1169     if (SmmS3ResumeState->SmmS3StackBase == 0) {
1170       SmmS3ResumeState->SmmS3StackSize = 0;
1171     }
1172 
1173     SmmS3ResumeState->SmmS3Cr0 = gSmmCr0;
1174     SmmS3ResumeState->SmmS3Cr3 = Cr3;
1175     SmmS3ResumeState->SmmS3Cr4 = gSmmCr4;
1176 
1177     if (sizeof (UINTN) == sizeof (UINT64)) {
1178       SmmS3ResumeState->Signature = SMM_S3_RESUME_SMM_64;
1179     }
1180     if (sizeof (UINTN) == sizeof (UINT32)) {
1181       SmmS3ResumeState->Signature = SMM_S3_RESUME_SMM_32;
1182     }
1183   }
1184 
1185   //
1186   // Check XD and BTS features
1187   //
1188   CheckProcessorFeature ();
1189 
1190   //
1191   // Initialize SMM Profile feature
1192   //
1193   InitSmmProfile (Cr3);
1194 
1195   //
1196   // Patch SmmS3ResumeState->SmmS3Cr3
1197   //
1198   InitSmmS3Cr3 ();
1199 
1200   DEBUG ((EFI_D_INFO, "SMM CPU Module exit from SMRAM with EFI_SUCCESS\n"));
1201 
1202   return EFI_SUCCESS;
1203 }
1204 
1205 /**
1206 
1207   Find out SMRAM information including SMRR base and SMRR size.
1208 
1209   @param          SmrrBase          SMRR base
1210   @param          SmrrSize          SMRR size
1211 
1212 **/
1213 VOID
FindSmramInfo(OUT UINT32 * SmrrBase,OUT UINT32 * SmrrSize)1214 FindSmramInfo (
1215   OUT UINT32   *SmrrBase,
1216   OUT UINT32   *SmrrSize
1217   )
1218 {
1219   EFI_STATUS                        Status;
1220   UINTN                             Size;
1221   EFI_SMM_ACCESS2_PROTOCOL          *SmmAccess;
1222   EFI_SMRAM_DESCRIPTOR              *CurrentSmramRange;
1223   EFI_SMRAM_DESCRIPTOR              *SmramRanges;
1224   UINTN                             SmramRangeCount;
1225   UINTN                             Index;
1226   UINT64                            MaxSize;
1227   BOOLEAN                           Found;
1228 
1229   //
1230   // Get SMM Access Protocol
1231   //
1232   Status = gBS->LocateProtocol (&gEfiSmmAccess2ProtocolGuid, NULL, (VOID **)&SmmAccess);
1233   ASSERT_EFI_ERROR (Status);
1234 
1235   //
1236   // Get SMRAM information
1237   //
1238   Size = 0;
1239   Status = SmmAccess->GetCapabilities (SmmAccess, &Size, NULL);
1240   ASSERT (Status == EFI_BUFFER_TOO_SMALL);
1241 
1242   SmramRanges = (EFI_SMRAM_DESCRIPTOR *)AllocatePool (Size);
1243   ASSERT (SmramRanges != NULL);
1244 
1245   Status = SmmAccess->GetCapabilities (SmmAccess, &Size, SmramRanges);
1246   ASSERT_EFI_ERROR (Status);
1247 
1248   SmramRangeCount = Size / sizeof (EFI_SMRAM_DESCRIPTOR);
1249 
1250   //
1251   // Find the largest SMRAM range between 1MB and 4GB that is at least 256K - 4K in size
1252   //
1253   CurrentSmramRange = NULL;
1254   for (Index = 0, MaxSize = SIZE_256KB - EFI_PAGE_SIZE; Index < SmramRangeCount; Index++) {
1255     //
1256     // Skip any SMRAM region that is already allocated, needs testing, or needs ECC initialization
1257     //
1258     if ((SmramRanges[Index].RegionState & (EFI_ALLOCATED | EFI_NEEDS_TESTING | EFI_NEEDS_ECC_INITIALIZATION)) != 0) {
1259       continue;
1260     }
1261 
1262     if (SmramRanges[Index].CpuStart >= BASE_1MB) {
1263       if ((SmramRanges[Index].CpuStart + SmramRanges[Index].PhysicalSize) <= BASE_4GB) {
1264         if (SmramRanges[Index].PhysicalSize >= MaxSize) {
1265           MaxSize = SmramRanges[Index].PhysicalSize;
1266           CurrentSmramRange = &SmramRanges[Index];
1267         }
1268       }
1269     }
1270   }
1271 
1272   ASSERT (CurrentSmramRange != NULL);
1273 
1274   *SmrrBase = (UINT32)CurrentSmramRange->CpuStart;
1275   *SmrrSize = (UINT32)CurrentSmramRange->PhysicalSize;
1276 
1277   do {
1278     Found = FALSE;
1279     for (Index = 0; Index < SmramRangeCount; Index++) {
1280       if (SmramRanges[Index].CpuStart < *SmrrBase && *SmrrBase == (SmramRanges[Index].CpuStart + SmramRanges[Index].PhysicalSize)) {
1281         *SmrrBase = (UINT32)SmramRanges[Index].CpuStart;
1282         *SmrrSize = (UINT32)(*SmrrSize + SmramRanges[Index].PhysicalSize);
1283         Found = TRUE;
1284       } else if ((*SmrrBase + *SmrrSize) == SmramRanges[Index].CpuStart && SmramRanges[Index].PhysicalSize > 0) {
1285         *SmrrSize = (UINT32)(*SmrrSize + SmramRanges[Index].PhysicalSize);
1286         Found = TRUE;
1287       }
1288     }
1289   } while (Found);
1290 
1291   DEBUG ((EFI_D_INFO, "SMRR Base: 0x%x, SMRR Size: 0x%x\n", *SmrrBase, *SmrrSize));
1292 }
1293 
1294 /**
1295 Configure SMM Code Access Check feature on an AP.
1296 SMM Feature Control MSR will be locked after configuration.
1297 
1298 @param[in,out] Buffer  Pointer to private data buffer.
1299 **/
1300 VOID
1301 EFIAPI
ConfigSmmCodeAccessCheckOnCurrentProcessor(IN OUT VOID * Buffer)1302 ConfigSmmCodeAccessCheckOnCurrentProcessor (
1303   IN OUT VOID  *Buffer
1304   )
1305 {
1306   UINTN   CpuIndex;
1307   UINT64  SmmFeatureControlMsr;
1308   UINT64  NewSmmFeatureControlMsr;
1309 
1310   //
1311   // Retrieve the CPU Index from the context passed in
1312   //
1313   CpuIndex = *(UINTN *)Buffer;
1314 
1315   //
1316   // Get the current SMM Feature Control MSR value
1317   //
1318   SmmFeatureControlMsr = SmmCpuFeaturesGetSmmRegister (CpuIndex, SmmRegFeatureControl);
1319 
1320   //
1321   // Compute the new SMM Feature Control MSR value
1322   //
1323   NewSmmFeatureControlMsr = SmmFeatureControlMsr;
1324   if (mSmmCodeAccessCheckEnable) {
1325     NewSmmFeatureControlMsr |= SMM_CODE_CHK_EN_BIT;
1326     if (FeaturePcdGet (PcdCpuSmmFeatureControlMsrLock)) {
1327       NewSmmFeatureControlMsr |= SMM_FEATURE_CONTROL_LOCK_BIT;
1328     }
1329   }
1330 
1331   //
1332   // Only set the SMM Feature Control MSR value if the new value is different than the current value
1333   //
1334   if (NewSmmFeatureControlMsr != SmmFeatureControlMsr) {
1335     SmmCpuFeaturesSetSmmRegister (CpuIndex, SmmRegFeatureControl, NewSmmFeatureControlMsr);
1336   }
1337 
1338   //
1339   // Release the spin lock user to serialize the updates to the SMM Feature Control MSR
1340   //
1341   ReleaseSpinLock (&mConfigSmmCodeAccessCheckLock);
1342 }
1343 
1344 /**
1345 Configure SMM Code Access Check feature for all processors.
1346 SMM Feature Control MSR will be locked after configuration.
1347 **/
1348 VOID
ConfigSmmCodeAccessCheck(VOID)1349 ConfigSmmCodeAccessCheck (
1350   VOID
1351   )
1352 {
1353   UINTN       Index;
1354   EFI_STATUS  Status;
1355 
1356   //
1357   // Check to see if the Feature Control MSR is supported on this CPU
1358   //
1359   Index = gSmmCpuPrivate->SmmCoreEntryContext.CurrentlyExecutingCpu;
1360   if (!SmmCpuFeaturesIsSmmRegisterSupported (Index, SmmRegFeatureControl)) {
1361     mSmmCodeAccessCheckEnable = FALSE;
1362     return;
1363   }
1364 
1365   //
1366   // Check to see if the CPU supports the SMM Code Access Check feature
1367   // Do not access this MSR unless the CPU supports the SmmRegFeatureControl
1368   //
1369   if ((AsmReadMsr64 (EFI_MSR_SMM_MCA_CAP) & SMM_CODE_ACCESS_CHK_BIT) == 0) {
1370     mSmmCodeAccessCheckEnable = FALSE;
1371     return;
1372   }
1373 
1374   //
1375   // Initialize the lock used to serialize the MSR programming in BSP and all APs
1376   //
1377   InitializeSpinLock (&mConfigSmmCodeAccessCheckLock);
1378 
1379   //
1380   // Acquire Config SMM Code Access Check spin lock.  The BSP will release the
1381   // spin lock when it is done executing ConfigSmmCodeAccessCheckOnCurrentProcessor().
1382   //
1383   AcquireSpinLock (&mConfigSmmCodeAccessCheckLock);
1384 
1385   //
1386   // Enable SMM Code Access Check feature on the BSP.
1387   //
1388   ConfigSmmCodeAccessCheckOnCurrentProcessor (&Index);
1389 
1390   //
1391   // Enable SMM Code Access Check feature for the APs.
1392   //
1393   for (Index = 0; Index < gSmst->NumberOfCpus; Index++) {
1394     if (Index != gSmmCpuPrivate->SmmCoreEntryContext.CurrentlyExecutingCpu) {
1395 
1396       //
1397       // Acquire Config SMM Code Access Check spin lock.  The AP will release the
1398       // spin lock when it is done executing ConfigSmmCodeAccessCheckOnCurrentProcessor().
1399       //
1400       AcquireSpinLock (&mConfigSmmCodeAccessCheckLock);
1401 
1402       //
1403       // Call SmmStartupThisAp() to enable SMM Code Access Check on an AP.
1404       //
1405       Status = gSmst->SmmStartupThisAp (ConfigSmmCodeAccessCheckOnCurrentProcessor, Index, &Index);
1406       ASSERT_EFI_ERROR (Status);
1407 
1408       //
1409       // Wait for the AP to release the Config SMM Code Access Check spin lock.
1410       //
1411       while (!AcquireSpinLockOrFail (&mConfigSmmCodeAccessCheckLock)) {
1412         CpuPause ();
1413       }
1414 
1415       //
1416       // Release the Config SMM Code Access Check spin lock.
1417       //
1418       ReleaseSpinLock (&mConfigSmmCodeAccessCheckLock);
1419     }
1420   }
1421 }
1422 
1423 /**
1424   This API provides a way to allocate memory for page table.
1425 
1426   This API can be called more once to allocate memory for page tables.
1427 
1428   Allocates the number of 4KB pages of type EfiRuntimeServicesData and returns a pointer to the
1429   allocated buffer.  The buffer returned is aligned on a 4KB boundary.  If Pages is 0, then NULL
1430   is returned.  If there is not enough memory remaining to satisfy the request, then NULL is
1431   returned.
1432 
1433   @param  Pages                 The number of 4 KB pages to allocate.
1434 
1435   @return A pointer to the allocated buffer or NULL if allocation fails.
1436 
1437 **/
1438 VOID *
AllocatePageTableMemory(IN UINTN Pages)1439 AllocatePageTableMemory (
1440   IN UINTN           Pages
1441   )
1442 {
1443   VOID  *Buffer;
1444 
1445   Buffer = SmmCpuFeaturesAllocatePageTableMemory (Pages);
1446   if (Buffer != NULL) {
1447     return Buffer;
1448   }
1449   return AllocatePages (Pages);
1450 }
1451 
1452 /**
1453   Perform the remaining tasks.
1454 
1455 **/
1456 VOID
PerformRemainingTasks(VOID)1457 PerformRemainingTasks (
1458   VOID
1459   )
1460 {
1461   if (mSmmReadyToLock) {
1462     //
1463     // Start SMM Profile feature
1464     //
1465     if (FeaturePcdGet (PcdCpuSmmProfileEnable)) {
1466       SmmProfileStart ();
1467     }
1468     //
1469     // Create a mix of 2MB and 4KB page table. Update some memory ranges absent and execute-disable.
1470     //
1471     InitPaging ();
1472     //
1473     // Configure SMM Code Access Check feature if available.
1474     //
1475     ConfigSmmCodeAccessCheck ();
1476 
1477     SmmCpuFeaturesCompleteSmmReadyToLock ();
1478 
1479     //
1480     // Clean SMM ready to lock flag
1481     //
1482     mSmmReadyToLock = FALSE;
1483   }
1484 }
1485 
1486 /**
1487   Perform the pre tasks.
1488 
1489 **/
1490 VOID
PerformPreTasks(VOID)1491 PerformPreTasks (
1492   VOID
1493   )
1494 {
1495   //
1496   // Restore SMM Configuration in S3 boot path.
1497   //
1498   if (mRestoreSmmConfigurationInS3) {
1499     //
1500     // Need make sure gSmst is correct because below function may use them.
1501     //
1502     gSmst->SmmStartupThisAp      = gSmmCpuPrivate->SmmCoreEntryContext.SmmStartupThisAp;
1503     gSmst->CurrentlyExecutingCpu = gSmmCpuPrivate->SmmCoreEntryContext.CurrentlyExecutingCpu;
1504     gSmst->NumberOfCpus          = gSmmCpuPrivate->SmmCoreEntryContext.NumberOfCpus;
1505     gSmst->CpuSaveStateSize      = gSmmCpuPrivate->SmmCoreEntryContext.CpuSaveStateSize;
1506     gSmst->CpuSaveState          = gSmmCpuPrivate->SmmCoreEntryContext.CpuSaveState;
1507 
1508     //
1509     // Configure SMM Code Access Check feature if available.
1510     //
1511     ConfigSmmCodeAccessCheck ();
1512 
1513     SmmCpuFeaturesCompleteSmmReadyToLock ();
1514 
1515     mRestoreSmmConfigurationInS3 = FALSE;
1516   }
1517 }
1518