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