1 /** @file
2   SMM STM support functions
3 
4   Copyright (c) 2015 - 2016, Intel Corporation. All rights reserved.<BR>
5   This program and the accompanying materials
6   are licensed and made available under the terms and conditions of the BSD License
7   which accompanies this distribution.  The full text of the license may be found at
8   http://opensource.org/licenses/bsd-license.php.
9 
10   THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11   WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
12 
13 **/
14 
15 #include <PiSmm.h>
16 #include <Library/BaseLib.h>
17 #include <Library/BaseMemoryLib.h>
18 #include <Library/MemoryAllocationLib.h>
19 #include <Library/HobLib.h>
20 #include <Library/DebugLib.h>
21 #include <Library/UefiBootServicesTableLib.h>
22 #include <Library/SmmServicesTableLib.h>
23 #include <Library/TpmMeasurementLib.h>
24 #include <Register/Cpuid.h>
25 #include <Register/ArchitecturalMsr.h>
26 #include <Register/SmramSaveStateMap.h>
27 
28 #include <Protocol/MpService.h>
29 
30 #include "SmmStm.h"
31 
32 #define TXT_EVTYPE_BASE                  0x400
33 #define TXT_EVTYPE_STM_HASH              (TXT_EVTYPE_BASE + 14)
34 
35 #define RDWR_ACCS             3
36 #define FULL_ACCS             7
37 
38 /**
39   The constructor function
40 
41   @param[in]  ImageHandle  The firmware allocated handle for the EFI image.
42   @param[in]  SystemTable  A pointer to the EFI System Table.
43 
44   @retval EFI_SUCCESS      The constructor always returns EFI_SUCCESS.
45 
46 **/
47 EFI_STATUS
48 EFIAPI
49 SmmCpuFeaturesLibConstructor (
50   IN EFI_HANDLE        ImageHandle,
51   IN EFI_SYSTEM_TABLE  *SystemTable
52   );
53 
54 EFI_HANDLE  mStmSmmCpuHandle = NULL;
55 
56 BOOLEAN mLockLoadMonitor = FALSE;
57 
58 //
59 // Template of STM_RSC_END structure for copying.
60 //
61 GLOBAL_REMOVE_IF_UNREFERENCED STM_RSC_END mRscEndNode = {
62   {END_OF_RESOURCES, sizeof (STM_RSC_END)},
63 };
64 
65 GLOBAL_REMOVE_IF_UNREFERENCED UINT8  *mStmResourcesPtr         = NULL;
66 GLOBAL_REMOVE_IF_UNREFERENCED UINTN  mStmResourceTotalSize     = 0x0;
67 GLOBAL_REMOVE_IF_UNREFERENCED UINTN  mStmResourceSizeUsed      = 0x0;
68 GLOBAL_REMOVE_IF_UNREFERENCED UINTN  mStmResourceSizeAvailable = 0x0;
69 
70 GLOBAL_REMOVE_IF_UNREFERENCED UINT32  mStmState = 0;
71 
72 //
73 // System Configuration Table pointing to STM Configuration Table
74 //
75 GLOBAL_REMOVE_IF_UNREFERENCED
76 EFI_SM_MONITOR_INIT_PROTOCOL mSmMonitorInitProtocol = {
77   LoadMonitor,
78   AddPiResource,
79   DeletePiResource,
80   GetPiResource,
81   GetMonitorState,
82 };
83 
84 
85 
86 
87 #define   CPUID1_EDX_XD_SUPPORT      0x100000
88 
89 //
90 // External global variables associated with SMI Handler Template
91 //
92 extern CONST TXT_PROCESSOR_SMM_DESCRIPTOR  gcStmPsd;
93 extern UINT32                              gStmSmbase;
94 extern volatile UINT32                     gStmSmiStack;
95 extern UINT32                              gStmSmiCr3;
96 extern volatile UINT8                      gcStmSmiHandlerTemplate[];
97 extern CONST UINT16                        gcStmSmiHandlerSize;
98 extern UINT16                              gcStmSmiHandlerOffset;
99 extern BOOLEAN                             gStmXdSupported;
100 
101 //
102 // Variables used by SMI Handler
103 //
104 IA32_DESCRIPTOR  gStmSmiHandlerIdtr;
105 
106 //
107 // MP Services Protocol
108 //
109 EFI_MP_SERVICES_PROTOCOL  *mSmmCpuFeaturesLibMpService = NULL;
110 
111 //
112 // MSEG Base and Length in SMRAM
113 //
114 UINTN  mMsegBase = 0;
115 UINTN  mMsegSize = 0;
116 
117 BOOLEAN  mStmConfigurationTableInitialized = FALSE;
118 
119 
120 /**
121   The constructor function
122 
123   @param[in]  ImageHandle  The firmware allocated handle for the EFI image.
124   @param[in]  SystemTable  A pointer to the EFI System Table.
125 
126   @retval EFI_SUCCESS      The constructor always returns EFI_SUCCESS.
127 
128 **/
129 EFI_STATUS
130 EFIAPI
SmmCpuFeaturesLibStmConstructor(IN EFI_HANDLE ImageHandle,IN EFI_SYSTEM_TABLE * SystemTable)131 SmmCpuFeaturesLibStmConstructor (
132   IN EFI_HANDLE        ImageHandle,
133   IN EFI_SYSTEM_TABLE  *SystemTable
134   )
135 {
136   EFI_STATUS              Status;
137   CPUID_VERSION_INFO_ECX  RegEcx;
138   EFI_HOB_GUID_TYPE       *GuidHob;
139   EFI_SMRAM_DESCRIPTOR    *SmramDescriptor;
140 
141   //
142   // Call the common constructor function
143   //
144   Status = SmmCpuFeaturesLibConstructor (ImageHandle, SystemTable);
145   ASSERT_EFI_ERROR (Status);
146 
147   //
148   // Lookup the MP Services Protocol
149   //
150   Status = gBS->LocateProtocol (
151                   &gEfiMpServiceProtocolGuid,
152                   NULL,
153                   (VOID **)&mSmmCpuFeaturesLibMpService
154                   );
155   ASSERT_EFI_ERROR (Status);
156 
157   //
158   // If CPU supports VMX, then determine SMRAM range for MSEG.
159   //
160   AsmCpuid (CPUID_VERSION_INFO, NULL, NULL, &RegEcx.Uint32, NULL);
161   if (RegEcx.Bits.VMX == 1) {
162     GuidHob = GetFirstGuidHob (&gMsegSmramGuid);
163     if (GuidHob != NULL) {
164       //
165       // Retrieve MSEG location from MSEG SRAM HOB
166       //
167       SmramDescriptor = (EFI_SMRAM_DESCRIPTOR *) GET_GUID_HOB_DATA (GuidHob);
168       if (SmramDescriptor->PhysicalSize > 0) {
169         mMsegBase       = (UINTN)SmramDescriptor->CpuStart;
170         mMsegSize       = (UINTN)SmramDescriptor->PhysicalSize;
171       }
172     } else if (PcdGet32 (PcdCpuMsegSize) > 0) {
173       //
174       // Allocate MSEG from SMRAM memory
175       //
176       mMsegBase = (UINTN)AllocatePages (EFI_SIZE_TO_PAGES (PcdGet32 (PcdCpuMsegSize)));
177       if (mMsegBase > 0) {
178         mMsegSize = ALIGN_VALUE (PcdGet32 (PcdCpuMsegSize), EFI_PAGE_SIZE);
179       } else {
180         DEBUG ((DEBUG_ERROR, "Not enough SMRAM resource to allocate MSEG size %08x\n", PcdGet32 (PcdCpuMsegSize)));
181       }
182     }
183     if (mMsegBase > 0) {
184       DEBUG ((DEBUG_INFO, "MsegBase: 0x%08x, MsegSize: 0x%08x\n", mMsegBase, mMsegSize));
185     }
186   }
187 
188   return EFI_SUCCESS;
189 }
190 
191 /**
192   Internal worker function that is called to complete CPU initialization at the
193   end of SmmCpuFeaturesInitializeProcessor().
194 
195 **/
196 VOID
FinishSmmCpuFeaturesInitializeProcessor(VOID)197 FinishSmmCpuFeaturesInitializeProcessor (
198   VOID
199   )
200 {
201   MSR_IA32_SMM_MONITOR_CTL_REGISTER  SmmMonitorCtl;
202 
203   //
204   // Set MSEG Base Address in SMM Monitor Control MSR.
205   //
206   if (mMsegBase > 0) {
207     SmmMonitorCtl.Uint64        = 0;
208     SmmMonitorCtl.Bits.MsegBase = (UINT32)mMsegBase >> 12;
209     SmmMonitorCtl.Bits.Valid    = 1;
210     AsmWriteMsr64 (MSR_IA32_SMM_MONITOR_CTL, SmmMonitorCtl.Uint64);
211   }
212 }
213 
214 /**
215   Return the size, in bytes, of a custom SMI Handler in bytes.  If 0 is
216   returned, then a custom SMI handler is not provided by this library,
217   and the default SMI handler must be used.
218 
219   @retval 0    Use the default SMI handler.
220   @retval > 0  Use the SMI handler installed by SmmCpuFeaturesInstallSmiHandler()
221                The caller is required to allocate enough SMRAM for each CPU to
222                support the size of the custom SMI handler.
223 **/
224 UINTN
225 EFIAPI
SmmCpuFeaturesGetSmiHandlerSize(VOID)226 SmmCpuFeaturesGetSmiHandlerSize (
227   VOID
228   )
229 {
230   return gcStmSmiHandlerSize;
231 }
232 
233 /**
234   Install a custom SMI handler for the CPU specified by CpuIndex.  This function
235   is only called if SmmCpuFeaturesGetSmiHandlerSize() returns a size is greater
236   than zero and is called by the CPU that was elected as monarch during System
237   Management Mode initialization.
238 
239   @param[in] CpuIndex   The index of the CPU to install the custom SMI handler.
240                         The value must be between 0 and the NumberOfCpus field
241                         in the System Management System Table (SMST).
242   @param[in] SmBase     The SMBASE address for the CPU specified by CpuIndex.
243   @param[in] SmiStack   The stack to use when an SMI is processed by the
244                         the CPU specified by CpuIndex.
245   @param[in] StackSize  The size, in bytes, if the stack used when an SMI is
246                         processed by the CPU specified by CpuIndex.
247   @param[in] GdtBase    The base address of the GDT to use when an SMI is
248                         processed by the CPU specified by CpuIndex.
249   @param[in] GdtSize    The size, in bytes, of the GDT used when an SMI is
250                         processed by the CPU specified by CpuIndex.
251   @param[in] IdtBase    The base address of the IDT to use when an SMI is
252                         processed by the CPU specified by CpuIndex.
253   @param[in] IdtSize    The size, in bytes, of the IDT used when an SMI is
254                         processed by the CPU specified by CpuIndex.
255   @param[in] Cr3        The base address of the page tables to use when an SMI
256                         is processed by the CPU specified by CpuIndex.
257 **/
258 VOID
259 EFIAPI
SmmCpuFeaturesInstallSmiHandler(IN UINTN CpuIndex,IN UINT32 SmBase,IN VOID * SmiStack,IN UINTN StackSize,IN UINTN GdtBase,IN UINTN GdtSize,IN UINTN IdtBase,IN UINTN IdtSize,IN UINT32 Cr3)260 SmmCpuFeaturesInstallSmiHandler (
261   IN UINTN   CpuIndex,
262   IN UINT32  SmBase,
263   IN VOID    *SmiStack,
264   IN UINTN   StackSize,
265   IN UINTN   GdtBase,
266   IN UINTN   GdtSize,
267   IN UINTN   IdtBase,
268   IN UINTN   IdtSize,
269   IN UINT32  Cr3
270   )
271 {
272   EFI_STATUS                     Status;
273   TXT_PROCESSOR_SMM_DESCRIPTOR   *Psd;
274   VOID                           *Hob;
275   UINT32                         RegEax;
276   UINT32                         RegEdx;
277   EFI_PROCESSOR_INFORMATION      ProcessorInfo;
278 
279   CopyMem ((VOID *)(UINTN)(SmBase + TXT_SMM_PSD_OFFSET), &gcStmPsd, sizeof (gcStmPsd));
280   Psd = (TXT_PROCESSOR_SMM_DESCRIPTOR *)(VOID *)(UINTN)(SmBase + TXT_SMM_PSD_OFFSET);
281   Psd->SmmGdtPtr = GdtBase;
282   Psd->SmmGdtSize = (UINT32)GdtSize;
283 
284   //
285   // Initialize values in template before copy
286   //
287   gStmSmiStack             = (UINT32)((UINTN)SmiStack + StackSize - sizeof (UINTN));
288   gStmSmiCr3               = Cr3;
289   gStmSmbase               = SmBase;
290   gStmSmiHandlerIdtr.Base  = IdtBase;
291   gStmSmiHandlerIdtr.Limit = (UINT16)(IdtSize - 1);
292 
293   if (gStmXdSupported) {
294     AsmCpuid (CPUID_EXTENDED_FUNCTION, &RegEax, NULL, NULL, NULL);
295     if (RegEax <= CPUID_EXTENDED_FUNCTION) {
296       //
297       // Extended CPUID functions are not supported on this processor.
298       //
299       gStmXdSupported = FALSE;
300     }
301 
302     AsmCpuid (CPUID_EXTENDED_CPU_SIG, NULL, NULL, NULL, &RegEdx);
303     if ((RegEdx & CPUID1_EDX_XD_SUPPORT) == 0) {
304       //
305       // Execute Disable Bit feature is not supported on this processor.
306       //
307       gStmXdSupported = FALSE;
308     }
309   }
310 
311   //
312   // Set the value at the top of the CPU stack to the CPU Index
313   //
314   *(UINTN*)(UINTN)gStmSmiStack = CpuIndex;
315 
316   //
317   // Copy template to CPU specific SMI handler location
318   //
319   CopyMem (
320     (VOID*)(UINTN)(SmBase + SMM_HANDLER_OFFSET),
321     (VOID*)gcStmSmiHandlerTemplate,
322     gcStmSmiHandlerSize
323     );
324 
325   Psd->SmmSmiHandlerRip = SmBase + SMM_HANDLER_OFFSET + gcStmSmiHandlerOffset;
326   Psd->SmmSmiHandlerRsp = (UINTN)SmiStack + StackSize - sizeof(UINTN);
327   Psd->SmmCr3           = Cr3;
328 
329   DEBUG((DEBUG_ERROR, "CpuSmmStmExceptionStackSize - %x\n", PcdGet32(PcdCpuSmmStmExceptionStackSize)));
330   DEBUG((DEBUG_ERROR, "Pages - %x\n", EFI_SIZE_TO_PAGES(PcdGet32(PcdCpuSmmStmExceptionStackSize))));
331   Psd->StmProtectionExceptionHandler.SpeRsp = (UINT64)(UINTN)AllocatePages (EFI_SIZE_TO_PAGES (PcdGet32 (PcdCpuSmmStmExceptionStackSize)));
332   Psd->StmProtectionExceptionHandler.SpeRsp += EFI_PAGES_TO_SIZE (EFI_SIZE_TO_PAGES (PcdGet32 (PcdCpuSmmStmExceptionStackSize)));
333 
334   Psd->BiosHwResourceRequirementsPtr        = (UINT64)(UINTN)GetStmResource ();
335 
336   //
337   // Get the APIC ID for the CPU specified by CpuIndex
338   //
339   Status = mSmmCpuFeaturesLibMpService->GetProcessorInfo (
340              mSmmCpuFeaturesLibMpService,
341              CpuIndex,
342              &ProcessorInfo
343              );
344   ASSERT_EFI_ERROR (Status);
345 
346   Psd->LocalApicId = (UINT32)ProcessorInfo.ProcessorId;
347   Psd->AcpiRsdp = 0;
348 
349   Hob = GetFirstHob (EFI_HOB_TYPE_CPU);
350   if (Hob != NULL) {
351     Psd->PhysicalAddressBits = ((EFI_HOB_CPU *) Hob)->SizeOfMemorySpace;
352   } else {
353     AsmCpuid (0x80000000, &RegEax, NULL, NULL, NULL);
354     if (RegEax >= 0x80000008) {
355       AsmCpuid (0x80000008, &RegEax, NULL, NULL, NULL);
356       Psd->PhysicalAddressBits = (UINT8) RegEax;
357     } else {
358       Psd->PhysicalAddressBits = 36;
359     }
360   }
361 
362   if (!mStmConfigurationTableInitialized) {
363     StmSmmConfigurationTableInit ();
364     mStmConfigurationTableInitialized = TRUE;
365   }
366 }
367 
368 /**
369   SMM End Of Dxe event notification handler.
370 
371   STM support need patch AcpiRsdp in TXT_PROCESSOR_SMM_DESCRIPTOR.
372 
373   @param[in] Protocol   Points to the protocol's unique identifier.
374   @param[in] Interface  Points to the interface instance.
375   @param[in] Handle     The handle on which the interface was installed.
376 
377   @retval EFI_SUCCESS   Notification handler runs successfully.
378 **/
379 EFI_STATUS
380 EFIAPI
SmmEndOfDxeEventNotify(IN CONST EFI_GUID * Protocol,IN VOID * Interface,IN EFI_HANDLE Handle)381 SmmEndOfDxeEventNotify (
382   IN CONST EFI_GUID  *Protocol,
383   IN VOID            *Interface,
384   IN EFI_HANDLE      Handle
385   )
386 {
387   VOID                          *Rsdp;
388   UINTN                         Index;
389   TXT_PROCESSOR_SMM_DESCRIPTOR  *Psd;
390 
391   DEBUG ((DEBUG_INFO, "SmmEndOfDxeEventNotify\n"));
392 
393   //
394   // found ACPI table RSD_PTR from system table
395   //
396   Rsdp = NULL;
397   for (Index = 0; Index < gST->NumberOfTableEntries; Index++) {
398     if (CompareGuid (&(gST->ConfigurationTable[Index].VendorGuid), &gEfiAcpi20TableGuid)) {
399       //
400       // A match was found.
401       //
402       Rsdp = gST->ConfigurationTable[Index].VendorTable;
403       break;
404     }
405   }
406   if (Rsdp == NULL) {
407     for (Index = 0; Index < gST->NumberOfTableEntries; Index++) {
408       if (CompareGuid (&(gST->ConfigurationTable[Index].VendorGuid), &gEfiAcpi10TableGuid)) {
409         //
410         // A match was found.
411         //
412         Rsdp = gST->ConfigurationTable[Index].VendorTable;
413         break;
414       }
415     }
416   }
417 
418   for (Index = 0; Index < gSmst->NumberOfCpus; Index++) {
419     Psd = (TXT_PROCESSOR_SMM_DESCRIPTOR *)((UINTN)gSmst->CpuSaveState[Index] - SMRAM_SAVE_STATE_MAP_OFFSET + TXT_SMM_PSD_OFFSET);
420     DEBUG ((DEBUG_INFO, "Index=%d  Psd=%p  Rsdp=%p\n", Index, Psd, Rsdp));
421     Psd->AcpiRsdp = (UINT64)(UINTN)Rsdp;
422   }
423 
424   mLockLoadMonitor = TRUE;
425 
426   return EFI_SUCCESS;
427 }
428 
429 /**
430   This function initializes the STM configuration table.
431 **/
432 VOID
StmSmmConfigurationTableInit(VOID)433 StmSmmConfigurationTableInit (
434   VOID
435   )
436 {
437   EFI_STATUS    Status;
438     VOID        *Registration;
439 
440   Status = gSmst->SmmInstallProtocolInterface (
441                     &mStmSmmCpuHandle,
442                     &gEfiSmMonitorInitProtocolGuid,
443                     EFI_NATIVE_INTERFACE,
444                     &mSmMonitorInitProtocol
445                     );
446   ASSERT_EFI_ERROR (Status);
447 
448   //
449   //
450   // Register SMM End of DXE Event
451   //
452   Status = gSmst->SmmRegisterProtocolNotify (
453                     &gEfiSmmEndOfDxeProtocolGuid,
454                     SmmEndOfDxeEventNotify,
455                     &Registration
456                     );
457   ASSERT_EFI_ERROR (Status);
458 }
459 
460 /**
461 
462   Get STM state.
463 
464   @return STM state
465 
466 **/
467 EFI_SM_MONITOR_STATE
468 EFIAPI
GetMonitorState(VOID)469 GetMonitorState (
470   VOID
471   )
472 {
473   return mStmState;
474 }
475 
476 /**
477 
478   Handle single Resource to see if it can be merged into Record.
479 
480   @param Resource  A pointer to resource node to be added
481   @param Record    A pointer to record node to be merged
482 
483   @retval TRUE  resource handled
484   @retval FALSE resource is not handled
485 
486 **/
487 BOOLEAN
HandleSingleResource(IN STM_RSC * Resource,IN STM_RSC * Record)488 HandleSingleResource (
489   IN  STM_RSC      *Resource,
490   IN  STM_RSC      *Record
491   )
492 {
493   UINT64      ResourceLo;
494   UINT64      ResourceHi;
495   UINT64      RecordLo;
496   UINT64      RecordHi;
497 
498   ResourceLo = 0;
499   ResourceHi = 0;
500   RecordLo = 0;
501   RecordHi = 0;
502 
503   //
504   // Calling code is responsible for making sure that
505   // Resource->Header.RscType == (*Record)->Header.RscType
506   // thus we use just one of them as switch variable.
507   //
508   switch (Resource->Header.RscType) {
509   case MEM_RANGE:
510   case MMIO_RANGE:
511     ResourceLo = Resource->Mem.Base;
512     ResourceHi = Resource->Mem.Base + Resource->Mem.Length;
513     RecordLo = Record->Mem.Base;
514     RecordHi = Record->Mem.Base + Record->Mem.Length;
515     if (Resource->Mem.RWXAttributes != Record->Mem.RWXAttributes) {
516       if ((ResourceLo == RecordLo) && (ResourceHi == RecordHi)) {
517         Record->Mem.RWXAttributes = Resource->Mem.RWXAttributes | Record->Mem.RWXAttributes;
518         return TRUE;
519       } else {
520         return FALSE;
521       }
522     }
523     break;
524   case IO_RANGE:
525   case TRAPPED_IO_RANGE:
526     ResourceLo = (UINT64) Resource->Io.Base;
527     ResourceHi = (UINT64) Resource->Io.Base + (UINT64) Resource->Io.Length;
528     RecordLo = (UINT64) Record->Io.Base;
529     RecordHi = (UINT64) Record->Io.Base + (UINT64) Record->Io.Length;
530     break;
531   case PCI_CFG_RANGE:
532     if ((Resource->PciCfg.OriginatingBusNumber != Record->PciCfg.OriginatingBusNumber) ||
533         (Resource->PciCfg.LastNodeIndex != Record->PciCfg.LastNodeIndex)) {
534       return FALSE;
535     }
536     if (CompareMem (Resource->PciCfg.PciDevicePath, Record->PciCfg.PciDevicePath, sizeof(STM_PCI_DEVICE_PATH_NODE) * (Resource->PciCfg.LastNodeIndex + 1)) != 0) {
537       return FALSE;
538     }
539     ResourceLo = (UINT64) Resource->PciCfg.Base;
540     ResourceHi = (UINT64) Resource->PciCfg.Base + (UINT64) Resource->PciCfg.Length;
541     RecordLo = (UINT64) Record->PciCfg.Base;
542     RecordHi = (UINT64) Record->PciCfg.Base + (UINT64) Record->PciCfg.Length;
543     if (Resource->PciCfg.RWAttributes != Record->PciCfg.RWAttributes) {
544       if ((ResourceLo == RecordLo) && (ResourceHi == RecordHi)) {
545         Record->PciCfg.RWAttributes = Resource->PciCfg.RWAttributes | Record->PciCfg.RWAttributes;
546         return TRUE;
547       } else {
548         return FALSE;
549       }
550     }
551     break;
552   case MACHINE_SPECIFIC_REG:
553     //
554     // Special case - merge MSR masks in place.
555     //
556     if (Resource->Msr.MsrIndex != Record->Msr.MsrIndex) {
557       return FALSE;
558     }
559     Record->Msr.ReadMask |= Resource->Msr.ReadMask;
560     Record->Msr.WriteMask |= Resource->Msr.WriteMask;
561     return TRUE;
562   default:
563     return FALSE;
564   }
565   //
566   // If resources are disjoint
567   //
568   if ((ResourceHi < RecordLo) || (ResourceLo > RecordHi)) {
569     return FALSE;
570   }
571 
572   //
573   // If resource is consumed by record.
574   //
575   if ((ResourceLo >= RecordLo) && (ResourceHi <= RecordHi)) {
576     return TRUE;
577   }
578   //
579   // Resources are overlapping.
580   // Resource and record are merged.
581   //
582   ResourceLo = (ResourceLo < RecordLo) ? ResourceLo : RecordLo;
583   ResourceHi = (ResourceHi > RecordHi) ? ResourceHi : RecordHi;
584 
585   switch (Resource->Header.RscType) {
586   case MEM_RANGE:
587   case MMIO_RANGE:
588     Record->Mem.Base = ResourceLo;
589     Record->Mem.Length = ResourceHi - ResourceLo;
590     break;
591   case IO_RANGE:
592   case TRAPPED_IO_RANGE:
593     Record->Io.Base = (UINT16) ResourceLo;
594     Record->Io.Length = (UINT16) (ResourceHi - ResourceLo);
595     break;
596   case PCI_CFG_RANGE:
597     Record->PciCfg.Base = (UINT16) ResourceLo;
598     Record->PciCfg.Length = (UINT16) (ResourceHi - ResourceLo);
599     break;
600   default:
601     return FALSE;
602   }
603 
604   return TRUE;
605 }
606 
607 /**
608 
609   Add resource node.
610 
611   @param Resource  A pointer to resource node to be added
612 
613 **/
614 VOID
AddSingleResource(IN STM_RSC * Resource)615 AddSingleResource (
616   IN  STM_RSC    *Resource
617   )
618 {
619   STM_RSC    *Record;
620 
621   Record = (STM_RSC *)mStmResourcesPtr;
622 
623   while (TRUE) {
624     if (Record->Header.RscType == END_OF_RESOURCES) {
625       break;
626     }
627     //
628     // Go to next record if resource and record types don't match.
629     //
630     if (Resource->Header.RscType != Record->Header.RscType) {
631       Record = (STM_RSC *)((UINTN)Record + Record->Header.Length);
632       continue;
633     }
634     //
635     // Record is handled inside of procedure - don't adjust.
636     //
637     if (HandleSingleResource (Resource, Record)) {
638       return ;
639     }
640     Record = (STM_RSC *)((UINTN)Record + Record->Header.Length);
641   }
642 
643   //
644   // Add resource to the end of area.
645   //
646   CopyMem (
647     mStmResourcesPtr + mStmResourceSizeUsed - sizeof(mRscEndNode),
648     Resource,
649     Resource->Header.Length
650     );
651   CopyMem (
652     mStmResourcesPtr + mStmResourceSizeUsed - sizeof(mRscEndNode) + Resource->Header.Length,
653     &mRscEndNode,
654     sizeof(mRscEndNode)
655     );
656   mStmResourceSizeUsed += Resource->Header.Length;
657   mStmResourceSizeAvailable = mStmResourceTotalSize - mStmResourceSizeUsed;
658 
659   return ;
660 }
661 
662 /**
663 
664   Add resource list.
665 
666   @param ResourceList  A pointer to resource list to be added
667   @param NumEntries    Optional number of entries.
668                        If 0, list must be terminated by END_OF_RESOURCES.
669 
670 **/
671 VOID
AddResource(IN STM_RSC * ResourceList,IN UINT32 NumEntries OPTIONAL)672 AddResource (
673   IN  STM_RSC    *ResourceList,
674   IN  UINT32      NumEntries OPTIONAL
675   )
676 {
677   UINT32      Count;
678   UINTN       Index;
679   STM_RSC    *Resource;
680 
681   if (NumEntries == 0) {
682     Count = 0xFFFFFFFF;
683   } else {
684     Count = NumEntries;
685   }
686 
687   Resource = ResourceList;
688 
689   for (Index = 0; Index < Count; Index++) {
690     if (Resource->Header.RscType == END_OF_RESOURCES) {
691       return ;
692     }
693     AddSingleResource (Resource);
694     Resource = (STM_RSC *)((UINTN)Resource + Resource->Header.Length);
695   }
696   return ;
697 }
698 
699 /**
700 
701   Validate resource list.
702 
703   @param ResourceList  A pointer to resource list to be added
704   @param NumEntries    Optional number of entries.
705                        If 0, list must be terminated by END_OF_RESOURCES.
706 
707   @retval TRUE  resource valid
708   @retval FALSE resource invalid
709 
710 **/
711 BOOLEAN
ValidateResource(IN STM_RSC * ResourceList,IN UINT32 NumEntries OPTIONAL)712 ValidateResource (
713   IN  STM_RSC    *ResourceList,
714   IN  UINT32      NumEntries OPTIONAL
715   )
716 {
717   UINT32      Count;
718   UINTN       Index;
719   STM_RSC    *Resource;
720   UINTN       SubIndex;
721 
722   //
723   // If NumEntries == 0 make it very big. Scan will be terminated by
724   // END_OF_RESOURCES.
725   //
726   if (NumEntries == 0) {
727     Count = 0xFFFFFFFF;
728   } else {
729     Count = NumEntries;
730   }
731 
732   //
733   // Start from beginning of resource list.
734   //
735   Resource = ResourceList;
736 
737   for (Index = 0; Index < Count; Index++) {
738     DEBUG ((DEBUG_ERROR, "ValidateResource (%d) - RscType(%x)\n", Index, Resource->Header.RscType));
739     //
740     // Validate resource.
741     //
742     switch (Resource->Header.RscType) {
743       case END_OF_RESOURCES:
744         if (Resource->Header.Length != sizeof (STM_RSC_END)) {
745           return  FALSE;
746         }
747         //
748         // If we are passed actual number of resources to add,
749         // END_OF_RESOURCES structure between them is considered an
750         // error. If NumEntries == 0 END_OF_RESOURCES is a termination.
751         //
752         if (NumEntries != 0) {
753           return  FALSE;
754         } else {
755           //
756           // If NumEntries == 0 and list reached end - return success.
757           //
758           return TRUE;
759         }
760         break;
761 
762       case MEM_RANGE:
763       case MMIO_RANGE:
764         if (Resource->Header.Length != sizeof (STM_RSC_MEM_DESC)) {
765           return FALSE;
766         }
767 
768         if (Resource->Mem.RWXAttributes > FULL_ACCS) {
769           return FALSE;
770         }
771         break;
772 
773       case IO_RANGE:
774       case TRAPPED_IO_RANGE:
775         if (Resource->Header.Length != sizeof (STM_RSC_IO_DESC)) {
776           return FALSE;
777         }
778 
779         if ((Resource->Io.Base + Resource->Io.Length) > 0xFFFF) {
780           return FALSE;
781         }
782         break;
783 
784       case PCI_CFG_RANGE:
785         DEBUG ((DEBUG_ERROR, "ValidateResource - PCI (0x%02x, 0x%08x, 0x%02x, 0x%02x)\n", Resource->PciCfg.OriginatingBusNumber, Resource->PciCfg.LastNodeIndex, Resource->PciCfg.PciDevicePath[0].PciDevice, Resource->PciCfg.PciDevicePath[0].PciFunction));
786         if (Resource->Header.Length != sizeof (STM_RSC_PCI_CFG_DESC) + (sizeof(STM_PCI_DEVICE_PATH_NODE) * Resource->PciCfg.LastNodeIndex)) {
787           return FALSE;
788         }
789         for (SubIndex = 0; SubIndex <= Resource->PciCfg.LastNodeIndex; SubIndex++) {
790           if ((Resource->PciCfg.PciDevicePath[SubIndex].PciDevice > 0x1F) || (Resource->PciCfg.PciDevicePath[SubIndex].PciFunction > 7)) {
791             return FALSE;
792           }
793         }
794         if ((Resource->PciCfg.Base + Resource->PciCfg.Length) > 0x1000) {
795           return FALSE;
796         }
797         break;
798 
799       case MACHINE_SPECIFIC_REG:
800         if (Resource->Header.Length != sizeof (STM_RSC_MSR_DESC)) {
801           return FALSE;
802         }
803         break;
804 
805       default :
806         DEBUG ((DEBUG_ERROR, "ValidateResource - Unknown RscType(%x)\n", Resource->Header.RscType));
807         return FALSE;
808     }
809     Resource = (STM_RSC *)((UINTN)Resource + Resource->Header.Length);
810   }
811   return TRUE;
812 }
813 
814 /**
815 
816   Get resource list.
817   EndResource is excluded.
818 
819   @param ResourceList  A pointer to resource list to be added
820   @param NumEntries    Optional number of entries.
821                        If 0, list must be terminated by END_OF_RESOURCES.
822 
823   @retval TRUE  resource valid
824   @retval FALSE resource invalid
825 
826 **/
827 UINTN
GetResourceSize(IN STM_RSC * ResourceList,IN UINT32 NumEntries OPTIONAL)828 GetResourceSize (
829   IN  STM_RSC    *ResourceList,
830   IN  UINT32      NumEntries OPTIONAL
831   )
832 {
833   UINT32      Count;
834   UINTN       Index;
835   STM_RSC    *Resource;
836 
837   Resource = ResourceList;
838 
839   //
840   // If NumEntries == 0 make it very big. Scan will be terminated by
841   // END_OF_RESOURCES.
842   //
843   if (NumEntries == 0) {
844     Count = 0xFFFFFFFF;
845   } else {
846     Count = NumEntries;
847   }
848 
849   //
850   // Start from beginning of resource list.
851   //
852   Resource = ResourceList;
853 
854   for (Index = 0; Index < Count; Index++) {
855     if (Resource->Header.RscType == END_OF_RESOURCES) {
856       break;
857     }
858     Resource = (STM_RSC *)((UINTN)Resource + Resource->Header.Length);
859   }
860 
861   return (UINTN)Resource - (UINTN)ResourceList;
862 }
863 
864 /**
865 
866   Add resources in list to database. Allocate new memory areas as needed.
867 
868   @param ResourceList  A pointer to resource list to be added
869   @param NumEntries    Optional number of entries.
870                        If 0, list must be terminated by END_OF_RESOURCES.
871 
872   @retval EFI_SUCCESS            If resources are added
873   @retval EFI_INVALID_PARAMETER  If nested procedure detected resource failer
874   @retval EFI_OUT_OF_RESOURCES   If nested procedure returned it and we cannot allocate more areas.
875 
876 **/
877 EFI_STATUS
878 EFIAPI
AddPiResource(IN STM_RSC * ResourceList,IN UINT32 NumEntries OPTIONAL)879 AddPiResource (
880   IN  STM_RSC    *ResourceList,
881   IN  UINT32      NumEntries OPTIONAL
882   )
883 {
884   EFI_STATUS            Status;
885   UINTN                 ResourceSize;
886   EFI_PHYSICAL_ADDRESS  NewResource;
887   UINTN                 NewResourceSize;
888 
889   DEBUG ((DEBUG_INFO, "AddPiResource - Enter\n"));
890 
891   if (!ValidateResource (ResourceList, NumEntries)) {
892     return EFI_INVALID_PARAMETER;
893   }
894 
895   ResourceSize = GetResourceSize (ResourceList, NumEntries);
896   DEBUG ((DEBUG_INFO, "ResourceSize - 0x%08x\n", ResourceSize));
897   if (ResourceSize == 0) {
898     return EFI_INVALID_PARAMETER;
899   }
900 
901   if (mStmResourcesPtr == NULL) {
902     //
903     // First time allocation
904     //
905     NewResourceSize = EFI_PAGES_TO_SIZE (EFI_SIZE_TO_PAGES (ResourceSize + sizeof(mRscEndNode)));
906     DEBUG ((DEBUG_INFO, "Allocate - 0x%08x\n", NewResourceSize));
907     Status = gSmst->SmmAllocatePages (
908                       AllocateAnyPages,
909                       EfiRuntimeServicesData,
910                       EFI_SIZE_TO_PAGES (NewResourceSize),
911                       &NewResource
912                       );
913     if (EFI_ERROR (Status)) {
914       return Status;
915     }
916 
917     //
918     // Copy EndResource for intialization
919     //
920     mStmResourcesPtr = (UINT8 *)(UINTN)NewResource;
921     mStmResourceTotalSize = NewResourceSize;
922     CopyMem (mStmResourcesPtr, &mRscEndNode, sizeof(mRscEndNode));
923     mStmResourceSizeUsed      = sizeof(mRscEndNode);
924     mStmResourceSizeAvailable = mStmResourceTotalSize - sizeof(mRscEndNode);
925 
926     //
927     // Let SmmCore change resource ptr
928     //
929     NotifyStmResourceChange (mStmResourcesPtr);
930   } else if (mStmResourceSizeAvailable < ResourceSize) {
931     //
932     // Need enlarge
933     //
934     NewResourceSize = mStmResourceTotalSize + (ResourceSize - mStmResourceSizeAvailable);
935     NewResourceSize = EFI_PAGES_TO_SIZE (EFI_SIZE_TO_PAGES (NewResourceSize));
936     DEBUG ((DEBUG_INFO, "ReAllocate - 0x%08x\n", NewResourceSize));
937     Status = gSmst->SmmAllocatePages (
938                       AllocateAnyPages,
939                       EfiRuntimeServicesData,
940                       EFI_SIZE_TO_PAGES (NewResourceSize),
941                       &NewResource
942                       );
943     if (EFI_ERROR (Status)) {
944       return Status;
945     }
946     CopyMem ((VOID *)(UINTN)NewResource, mStmResourcesPtr, mStmResourceSizeUsed);
947     mStmResourceSizeAvailable = NewResourceSize - mStmResourceSizeUsed;
948 
949     gSmst->SmmFreePages (
950              (EFI_PHYSICAL_ADDRESS)(UINTN)mStmResourcesPtr,
951              EFI_SIZE_TO_PAGES (mStmResourceTotalSize)
952              );
953 
954     mStmResourceTotalSize = NewResourceSize;
955     mStmResourcesPtr = (UINT8 *)(UINTN)NewResource;
956 
957     //
958     // Let SmmCore change resource ptr
959     //
960     NotifyStmResourceChange (mStmResourcesPtr);
961   }
962 
963   //
964   // Check duplication
965   //
966   AddResource (ResourceList, NumEntries);
967 
968   return EFI_SUCCESS;
969 }
970 
971 /**
972 
973   Delete resources in list to database.
974 
975   @param ResourceList  A pointer to resource list to be deleted
976                        NULL means delete all resources.
977   @param NumEntries    Optional number of entries.
978                        If 0, list must be terminated by END_OF_RESOURCES.
979 
980   @retval EFI_SUCCESS            If resources are deleted
981   @retval EFI_INVALID_PARAMETER  If nested procedure detected resource failer
982 
983 **/
984 EFI_STATUS
985 EFIAPI
DeletePiResource(IN STM_RSC * ResourceList,IN UINT32 NumEntries OPTIONAL)986 DeletePiResource (
987   IN  STM_RSC    *ResourceList,
988   IN  UINT32      NumEntries OPTIONAL
989   )
990 {
991   if (ResourceList != NULL) {
992     // TBD
993     ASSERT (FALSE);
994     return EFI_UNSUPPORTED;
995   }
996   //
997   // Delete all
998   //
999   CopyMem (mStmResourcesPtr, &mRscEndNode, sizeof(mRscEndNode));
1000   mStmResourceSizeUsed      = sizeof(mRscEndNode);
1001   mStmResourceSizeAvailable = mStmResourceTotalSize - sizeof(mRscEndNode);
1002   return EFI_SUCCESS;
1003 }
1004 
1005 /**
1006 
1007   Get BIOS resources.
1008 
1009   @param ResourceList  A pointer to resource list to be filled
1010   @param ResourceSize  On input it means size of resource list input.
1011                        On output it means size of resource list filled,
1012                        or the size of resource list to be filled if size of too small.
1013 
1014   @retval EFI_SUCCESS            If resources are returned.
1015   @retval EFI_BUFFER_TOO_SMALL   If resource list buffer is too small to hold the whole resources.
1016 
1017 **/
1018 EFI_STATUS
1019 EFIAPI
GetPiResource(OUT STM_RSC * ResourceList,IN OUT UINT32 * ResourceSize)1020 GetPiResource (
1021   OUT    STM_RSC *ResourceList,
1022   IN OUT UINT32  *ResourceSize
1023   )
1024 {
1025   if (*ResourceSize < mStmResourceSizeUsed) {
1026     *ResourceSize = (UINT32)mStmResourceSizeUsed;
1027     return EFI_BUFFER_TOO_SMALL;
1028   }
1029 
1030   CopyMem (ResourceList, mStmResourcesPtr, mStmResourceSizeUsed);
1031   *ResourceSize = (UINT32)mStmResourceSizeUsed;
1032   return EFI_SUCCESS;
1033 }
1034 
1035 /**
1036 
1037   Set valid bit for MSEG MSR.
1038 
1039   @param Buffer Ap function buffer. (not used)
1040 
1041 **/
1042 VOID
1043 EFIAPI
EnableMsegMsr(IN VOID * Buffer)1044 EnableMsegMsr (
1045   IN VOID  *Buffer
1046   )
1047 {
1048   MSR_IA32_SMM_MONITOR_CTL_REGISTER  SmmMonitorCtl;
1049 
1050   SmmMonitorCtl.Uint64 = AsmReadMsr64 (MSR_IA32_SMM_MONITOR_CTL);
1051   SmmMonitorCtl.Bits.Valid = 1;
1052   AsmWriteMsr64 (MSR_IA32_SMM_MONITOR_CTL, SmmMonitorCtl.Uint64);
1053 }
1054 
1055 /**
1056 
1057   Get 4K page aligned VMCS size.
1058 
1059   @return 4K page aligned VMCS size
1060 
1061 **/
1062 UINT32
GetVmcsSize(VOID)1063 GetVmcsSize (
1064   VOID
1065   )
1066 {
1067   MSR_IA32_VMX_BASIC_REGISTER  VmxBasic;
1068 
1069   //
1070   // Read VMCS size and and align to 4KB
1071   //
1072   VmxBasic.Uint64 = AsmReadMsr64 (MSR_IA32_VMX_BASIC);
1073   return ALIGN_VALUE (VmxBasic.Bits.VmcsSize, SIZE_4KB);
1074 }
1075 
1076 /**
1077 
1078   Check STM image size.
1079 
1080   @param StmImage      STM image
1081   @param StmImageSize  STM image size
1082 
1083   @retval TRUE  check pass
1084   @retval FALSE check fail
1085 **/
1086 BOOLEAN
StmCheckStmImage(IN EFI_PHYSICAL_ADDRESS StmImage,IN UINTN StmImageSize)1087 StmCheckStmImage (
1088   IN EFI_PHYSICAL_ADDRESS StmImage,
1089   IN UINTN                StmImageSize
1090   )
1091 {
1092   UINTN                     MinMsegSize;
1093   STM_HEADER                *StmHeader;
1094   IA32_VMX_MISC_REGISTER    VmxMiscMsr;
1095 
1096   //
1097   // Check to see if STM image is compatible with CPU
1098   //
1099   StmHeader = (STM_HEADER *)(UINTN)StmImage;
1100   VmxMiscMsr.Uint64 = AsmReadMsr64 (MSR_IA32_VMX_MISC);
1101   if (StmHeader->HwStmHdr.MsegHeaderRevision != VmxMiscMsr.Bits.MsegRevisionIdentifier) {
1102     DEBUG ((DEBUG_ERROR, "STM Image not compatible with CPU\n"));
1103     DEBUG ((DEBUG_ERROR, "  StmHeader->HwStmHdr.MsegHeaderRevision = %08x\n", StmHeader->HwStmHdr.MsegHeaderRevision));
1104     DEBUG ((DEBUG_ERROR, "  VmxMiscMsr.Bits.MsegRevisionIdentifier = %08x\n", VmxMiscMsr.Bits.MsegRevisionIdentifier));
1105     return FALSE;
1106   }
1107 
1108   //
1109   // Get Minimal required Mseg size
1110   //
1111   MinMsegSize = (EFI_PAGES_TO_SIZE (EFI_SIZE_TO_PAGES (StmHeader->SwStmHdr.StaticImageSize)) +
1112                  StmHeader->SwStmHdr.AdditionalDynamicMemorySize +
1113                  (StmHeader->SwStmHdr.PerProcDynamicMemorySize + GetVmcsSize () * 2) * gSmst->NumberOfCpus);
1114   if (MinMsegSize < StmImageSize) {
1115     MinMsegSize = StmImageSize;
1116   }
1117 
1118   if (StmHeader->HwStmHdr.Cr3Offset >= StmHeader->SwStmHdr.StaticImageSize) {
1119     //
1120     // We will create page table, just in case that SINIT does not create it.
1121     //
1122     if (MinMsegSize < StmHeader->HwStmHdr.Cr3Offset + EFI_PAGES_TO_SIZE(6)) {
1123       MinMsegSize = StmHeader->HwStmHdr.Cr3Offset + EFI_PAGES_TO_SIZE(6);
1124     }
1125   }
1126 
1127   //
1128   // Check if it exceeds MSEG size
1129   //
1130   if (MinMsegSize > mMsegSize) {
1131     DEBUG ((DEBUG_ERROR, "MSEG too small.  Min MSEG Size = %08x  Current MSEG Size = %08x\n", MinMsegSize, mMsegSize));
1132     DEBUG ((DEBUG_ERROR, "  StmHeader->SwStmHdr.StaticImageSize             = %08x\n", StmHeader->SwStmHdr.StaticImageSize));
1133     DEBUG ((DEBUG_ERROR, "  StmHeader->SwStmHdr.AdditionalDynamicMemorySize = %08x\n", StmHeader->SwStmHdr.AdditionalDynamicMemorySize));
1134     DEBUG ((DEBUG_ERROR, "  StmHeader->SwStmHdr.PerProcDynamicMemorySize    = %08x\n", StmHeader->SwStmHdr.PerProcDynamicMemorySize));
1135     DEBUG ((DEBUG_ERROR, "  VMCS Size                                       = %08x\n", GetVmcsSize ()));
1136     DEBUG ((DEBUG_ERROR, "  Max CPUs                                        = %08x\n", gSmst->NumberOfCpus));
1137     DEBUG ((DEBUG_ERROR, "  StmHeader->HwStmHdr.Cr3Offset                   = %08x\n", StmHeader->HwStmHdr.Cr3Offset));
1138     return FALSE;
1139   }
1140 
1141   return TRUE;
1142 }
1143 
1144 /**
1145 
1146   Load STM image to MSEG.
1147 
1148   @param StmImage      STM image
1149   @param StmImageSize  STM image size
1150 
1151 **/
1152 VOID
StmLoadStmImage(IN EFI_PHYSICAL_ADDRESS StmImage,IN UINTN StmImageSize)1153 StmLoadStmImage (
1154   IN EFI_PHYSICAL_ADDRESS StmImage,
1155   IN UINTN                StmImageSize
1156   )
1157 {
1158   MSR_IA32_SMM_MONITOR_CTL_REGISTER  SmmMonitorCtl;
1159   UINT32                             MsegBase;
1160   STM_HEADER                         *StmHeader;
1161 
1162   //
1163   // Get MSEG base address from MSR_IA32_SMM_MONITOR_CTL
1164   //
1165   SmmMonitorCtl.Uint64 = AsmReadMsr64 (MSR_IA32_SMM_MONITOR_CTL);
1166   MsegBase = SmmMonitorCtl.Bits.MsegBase << 12;
1167 
1168   //
1169   // Zero all of MSEG base address
1170   //
1171   ZeroMem ((VOID *)(UINTN)MsegBase, mMsegSize);
1172 
1173   //
1174   // Copy STM Image into MSEG
1175   //
1176   CopyMem ((VOID *)(UINTN)MsegBase, (VOID *)(UINTN)StmImage, StmImageSize);
1177 
1178   //
1179   // STM Header is at the beginning of the STM Image
1180   //
1181   StmHeader = (STM_HEADER *)(UINTN)StmImage;
1182 
1183   StmGen4GPageTable ((UINTN)MsegBase + StmHeader->HwStmHdr.Cr3Offset);
1184 }
1185 
1186 /**
1187 
1188   Load STM image to MSEG.
1189 
1190   @param StmImage      STM image
1191   @param StmImageSize  STM image size
1192 
1193   @retval EFI_SUCCESS            Load STM to MSEG successfully
1194   @retval EFI_ALREADY_STARTED    STM image is already loaded to MSEG
1195   @retval EFI_BUFFER_TOO_SMALL   MSEG is smaller than minimal requirement of STM image
1196   @retval EFI_UNSUPPORTED        MSEG is not enabled
1197 
1198 **/
1199 EFI_STATUS
1200 EFIAPI
LoadMonitor(IN EFI_PHYSICAL_ADDRESS StmImage,IN UINTN StmImageSize)1201 LoadMonitor (
1202   IN EFI_PHYSICAL_ADDRESS StmImage,
1203   IN UINTN                StmImageSize
1204   )
1205 {
1206   MSR_IA32_SMM_MONITOR_CTL_REGISTER  SmmMonitorCtl;
1207 
1208   if (mLockLoadMonitor) {
1209     return EFI_ACCESS_DENIED;
1210   }
1211 
1212   SmmMonitorCtl.Uint64 = AsmReadMsr64 (MSR_IA32_SMM_MONITOR_CTL);
1213   if (SmmMonitorCtl.Bits.MsegBase == 0) {
1214     return EFI_UNSUPPORTED;
1215   }
1216 
1217   if (!StmCheckStmImage (StmImage, StmImageSize)) {
1218     return EFI_BUFFER_TOO_SMALL;
1219   }
1220 
1221   // Record STM_HASH to PCR 0, just in case it is NOT TXT launch, we still need provide the evidence.
1222   TpmMeasureAndLogData(
1223     0,                        // PcrIndex
1224     TXT_EVTYPE_STM_HASH,      // EventType
1225     NULL,                     // EventLog
1226     0,                        // LogLen
1227     (VOID *)(UINTN)StmImage,  // HashData
1228     StmImageSize              // HashDataLen
1229     );
1230 
1231   StmLoadStmImage (StmImage, StmImageSize);
1232 
1233   mStmState |= EFI_SM_MONITOR_STATE_ENABLED;
1234 
1235   return EFI_SUCCESS;
1236 }
1237 
1238 /**
1239   This function return BIOS STM resource.
1240   Produced by SmmStm.
1241   Comsumed by SmmMpService when Init.
1242 
1243   @return BIOS STM resource
1244 
1245 **/
1246 VOID *
GetStmResource(VOID)1247 GetStmResource(
1248   VOID
1249   )
1250 {
1251   return mStmResourcesPtr;
1252 }
1253 
1254 /**
1255   This function notify STM resource change.
1256 
1257   @param StmResource BIOS STM resource
1258 
1259 **/
1260 VOID
NotifyStmResourceChange(VOID * StmResource)1261 NotifyStmResourceChange (
1262   VOID *StmResource
1263   )
1264 {
1265   UINTN                         Index;
1266   TXT_PROCESSOR_SMM_DESCRIPTOR  *Psd;
1267 
1268   for (Index = 0; Index < gSmst->NumberOfCpus; Index++) {
1269     Psd = (TXT_PROCESSOR_SMM_DESCRIPTOR *)((UINTN)gSmst->CpuSaveState[Index] - SMRAM_SAVE_STATE_MAP_OFFSET + TXT_SMM_PSD_OFFSET);
1270     Psd->BiosHwResourceRequirementsPtr = (UINT64)(UINTN)StmResource;
1271   }
1272   return ;
1273 }
1274 
1275 
1276 /**
1277   This is STM setup BIOS callback.
1278 **/
1279 VOID
1280 EFIAPI
SmmStmSetup(VOID)1281 SmmStmSetup (
1282   VOID
1283   )
1284 {
1285   mStmState |= EFI_SM_MONITOR_STATE_ACTIVATED;
1286 }
1287 
1288 /**
1289   This is STM teardown BIOS callback.
1290 **/
1291 VOID
1292 EFIAPI
SmmStmTeardown(VOID)1293 SmmStmTeardown (
1294   VOID
1295   )
1296 {
1297   mStmState &= ~EFI_SM_MONITOR_STATE_ACTIVATED;
1298 }
1299 
1300