2 SMM STM support functions
4 Copyright (c) 2015 - 2018, Intel Corporation. All rights reserved.<BR>
5 SPDX-License-Identifier: BSD-2-Clause-Patent
10 #include <Library/BaseLib.h>
11 #include <Library/BaseMemoryLib.h>
12 #include <Library/MemoryAllocationLib.h>
13 #include <Library/HobLib.h>
14 #include <Library/DebugLib.h>
15 #include <Library/UefiBootServicesTableLib.h>
16 #include <Library/SmmServicesTableLib.h>
17 #include <Library/TpmMeasurementLib.h>
18 #include <Register/Cpuid.h>
19 #include <Register/ArchitecturalMsr.h>
20 #include <Register/SmramSaveStateMap.h>
22 #include <Protocol/MpService.h>
26 #define TXT_EVTYPE_BASE 0x400
27 #define TXT_EVTYPE_STM_HASH (TXT_EVTYPE_BASE + 14)
33 The constructor function
35 @param[in] ImageHandle The firmware allocated handle for the EFI image.
36 @param[in] SystemTable A pointer to the EFI System Table.
38 @retval EFI_SUCCESS The constructor always returns EFI_SUCCESS.
43 SmmCpuFeaturesLibConstructor (
44 IN EFI_HANDLE ImageHandle
,
45 IN EFI_SYSTEM_TABLE
*SystemTable
48 EFI_HANDLE mStmSmmCpuHandle
= NULL
;
50 BOOLEAN mLockLoadMonitor
= FALSE
;
53 // Template of STM_RSC_END structure for copying.
55 GLOBAL_REMOVE_IF_UNREFERENCED STM_RSC_END mRscEndNode
= {
56 {END_OF_RESOURCES
, sizeof (STM_RSC_END
)},
59 GLOBAL_REMOVE_IF_UNREFERENCED UINT8
*mStmResourcesPtr
= NULL
;
60 GLOBAL_REMOVE_IF_UNREFERENCED UINTN mStmResourceTotalSize
= 0x0;
61 GLOBAL_REMOVE_IF_UNREFERENCED UINTN mStmResourceSizeUsed
= 0x0;
62 GLOBAL_REMOVE_IF_UNREFERENCED UINTN mStmResourceSizeAvailable
= 0x0;
64 GLOBAL_REMOVE_IF_UNREFERENCED UINT32 mStmState
= 0;
67 // System Configuration Table pointing to STM Configuration Table
69 GLOBAL_REMOVE_IF_UNREFERENCED
70 EFI_SM_MONITOR_INIT_PROTOCOL mSmMonitorInitProtocol
= {
81 #define CPUID1_EDX_XD_SUPPORT 0x100000
84 // External global variables associated with SMI Handler Template
86 extern CONST TXT_PROCESSOR_SMM_DESCRIPTOR gcStmPsd
;
87 extern UINT32 gStmSmbase
;
88 extern volatile UINT32 gStmSmiStack
;
89 extern UINT32 gStmSmiCr3
;
90 extern volatile UINT8 gcStmSmiHandlerTemplate
[];
91 extern CONST UINT16 gcStmSmiHandlerSize
;
92 extern UINT16 gcStmSmiHandlerOffset
;
93 extern BOOLEAN gStmXdSupported
;
96 // Variables used by SMI Handler
98 IA32_DESCRIPTOR gStmSmiHandlerIdtr
;
101 // MP Services Protocol
103 EFI_MP_SERVICES_PROTOCOL
*mSmmCpuFeaturesLibMpService
= NULL
;
106 // MSEG Base and Length in SMRAM
111 BOOLEAN mStmConfigurationTableInitialized
= FALSE
;
114 The constructor function
116 @param[in] ImageHandle The firmware allocated handle for the EFI image.
117 @param[in] SystemTable A pointer to the EFI System Table.
119 @retval EFI_SUCCESS The constructor always returns EFI_SUCCESS.
124 SmmCpuFeaturesLibStmConstructor (
125 IN EFI_HANDLE ImageHandle
,
126 IN EFI_SYSTEM_TABLE
*SystemTable
130 CPUID_VERSION_INFO_ECX RegEcx
;
131 EFI_HOB_GUID_TYPE
*GuidHob
;
132 EFI_SMRAM_DESCRIPTOR
*SmramDescriptor
;
135 // Initialize address fixup
137 SmmCpuFeaturesLibStmSmiEntryFixupAddress ();
140 // Call the common constructor function
142 Status
= SmmCpuFeaturesLibConstructor (ImageHandle
, SystemTable
);
143 ASSERT_EFI_ERROR (Status
);
146 // Lookup the MP Services Protocol
148 Status
= gBS
->LocateProtocol (
149 &gEfiMpServiceProtocolGuid
,
151 (VOID
**)&mSmmCpuFeaturesLibMpService
153 ASSERT_EFI_ERROR (Status
);
156 // If CPU supports VMX, then determine SMRAM range for MSEG.
158 AsmCpuid (CPUID_VERSION_INFO
, NULL
, NULL
, &RegEcx
.Uint32
, NULL
);
159 if (RegEcx
.Bits
.VMX
== 1) {
160 GuidHob
= GetFirstGuidHob (&gMsegSmramGuid
);
161 if (GuidHob
!= NULL
) {
163 // Retrieve MSEG location from MSEG SRAM HOB
165 SmramDescriptor
= (EFI_SMRAM_DESCRIPTOR
*) GET_GUID_HOB_DATA (GuidHob
);
166 if (SmramDescriptor
->PhysicalSize
> 0) {
167 mMsegBase
= (UINTN
)SmramDescriptor
->CpuStart
;
168 mMsegSize
= (UINTN
)SmramDescriptor
->PhysicalSize
;
170 } else if (PcdGet32 (PcdCpuMsegSize
) > 0) {
172 // Allocate MSEG from SMRAM memory
174 mMsegBase
= (UINTN
)AllocatePages (EFI_SIZE_TO_PAGES (PcdGet32 (PcdCpuMsegSize
)));
176 mMsegSize
= ALIGN_VALUE (PcdGet32 (PcdCpuMsegSize
), EFI_PAGE_SIZE
);
178 DEBUG ((DEBUG_ERROR
, "Not enough SMRAM resource to allocate MSEG size %08x\n", PcdGet32 (PcdCpuMsegSize
)));
182 DEBUG ((DEBUG_INFO
, "MsegBase: 0x%08x, MsegSize: 0x%08x\n", mMsegBase
, mMsegSize
));
190 Internal worker function that is called to complete CPU initialization at the
191 end of SmmCpuFeaturesInitializeProcessor().
195 FinishSmmCpuFeaturesInitializeProcessor (
199 MSR_IA32_SMM_MONITOR_CTL_REGISTER SmmMonitorCtl
;
202 // Set MSEG Base Address in SMM Monitor Control MSR.
205 SmmMonitorCtl
.Uint64
= 0;
206 SmmMonitorCtl
.Bits
.MsegBase
= (UINT32
)mMsegBase
>> 12;
207 SmmMonitorCtl
.Bits
.Valid
= 1;
208 AsmWriteMsr64 (MSR_IA32_SMM_MONITOR_CTL
, SmmMonitorCtl
.Uint64
);
213 Return the size, in bytes, of a custom SMI Handler in bytes. If 0 is
214 returned, then a custom SMI handler is not provided by this library,
215 and the default SMI handler must be used.
217 @retval 0 Use the default SMI handler.
218 @retval > 0 Use the SMI handler installed by SmmCpuFeaturesInstallSmiHandler()
219 The caller is required to allocate enough SMRAM for each CPU to
220 support the size of the custom SMI handler.
224 SmmCpuFeaturesGetSmiHandlerSize (
228 return gcStmSmiHandlerSize
;
232 Install a custom SMI handler for the CPU specified by CpuIndex. This function
233 is only called if SmmCpuFeaturesGetSmiHandlerSize() returns a size is greater
234 than zero and is called by the CPU that was elected as monarch during System
235 Management Mode initialization.
237 @param[in] CpuIndex The index of the CPU to install the custom SMI handler.
238 The value must be between 0 and the NumberOfCpus field
239 in the System Management System Table (SMST).
240 @param[in] SmBase The SMBASE address for the CPU specified by CpuIndex.
241 @param[in] SmiStack The stack to use when an SMI is processed by the
242 the CPU specified by CpuIndex.
243 @param[in] StackSize The size, in bytes, if the stack used when an SMI is
244 processed by the CPU specified by CpuIndex.
245 @param[in] GdtBase The base address of the GDT to use when an SMI is
246 processed by the CPU specified by CpuIndex.
247 @param[in] GdtSize The size, in bytes, of the GDT used when an SMI is
248 processed by the CPU specified by CpuIndex.
249 @param[in] IdtBase The base address of the IDT to use when an SMI is
250 processed by the CPU specified by CpuIndex.
251 @param[in] IdtSize The size, in bytes, of the IDT used when an SMI is
252 processed by the CPU specified by CpuIndex.
253 @param[in] Cr3 The base address of the page tables to use when an SMI
254 is processed by the CPU specified by CpuIndex.
258 SmmCpuFeaturesInstallSmiHandler (
271 TXT_PROCESSOR_SMM_DESCRIPTOR
*Psd
;
275 EFI_PROCESSOR_INFORMATION ProcessorInfo
;
277 CopyMem ((VOID
*)((UINTN
)SmBase
+ TXT_SMM_PSD_OFFSET
), &gcStmPsd
, sizeof (gcStmPsd
));
278 Psd
= (TXT_PROCESSOR_SMM_DESCRIPTOR
*)(VOID
*)((UINTN
)SmBase
+ TXT_SMM_PSD_OFFSET
);
279 Psd
->SmmGdtPtr
= GdtBase
;
280 Psd
->SmmGdtSize
= (UINT32
)GdtSize
;
283 // Initialize values in template before copy
285 gStmSmiStack
= (UINT32
)((UINTN
)SmiStack
+ StackSize
- sizeof (UINTN
));
288 gStmSmiHandlerIdtr
.Base
= IdtBase
;
289 gStmSmiHandlerIdtr
.Limit
= (UINT16
)(IdtSize
- 1);
291 if (gStmXdSupported
) {
292 AsmCpuid (CPUID_EXTENDED_FUNCTION
, &RegEax
, NULL
, NULL
, NULL
);
293 if (RegEax
<= CPUID_EXTENDED_FUNCTION
) {
295 // Extended CPUID functions are not supported on this processor.
297 gStmXdSupported
= FALSE
;
300 AsmCpuid (CPUID_EXTENDED_CPU_SIG
, NULL
, NULL
, NULL
, &RegEdx
);
301 if ((RegEdx
& CPUID1_EDX_XD_SUPPORT
) == 0) {
303 // Execute Disable Bit feature is not supported on this processor.
305 gStmXdSupported
= FALSE
;
310 // Set the value at the top of the CPU stack to the CPU Index
312 *(UINTN
*)(UINTN
)gStmSmiStack
= CpuIndex
;
315 // Copy template to CPU specific SMI handler location
318 (VOID
*)((UINTN
)SmBase
+ SMM_HANDLER_OFFSET
),
319 (VOID
*)gcStmSmiHandlerTemplate
,
323 Psd
->SmmSmiHandlerRip
= SmBase
+ SMM_HANDLER_OFFSET
+ gcStmSmiHandlerOffset
;
324 Psd
->SmmSmiHandlerRsp
= (UINTN
)SmiStack
+ StackSize
- sizeof(UINTN
);
327 DEBUG((DEBUG_INFO
, "CpuSmmStmExceptionStackSize - %x\n", PcdGet32(PcdCpuSmmStmExceptionStackSize
)));
328 DEBUG((DEBUG_INFO
, "Pages - %x\n", EFI_SIZE_TO_PAGES(PcdGet32(PcdCpuSmmStmExceptionStackSize
))));
329 Psd
->StmProtectionExceptionHandler
.SpeRsp
= (UINT64
)(UINTN
)AllocatePages (EFI_SIZE_TO_PAGES (PcdGet32 (PcdCpuSmmStmExceptionStackSize
)));
330 Psd
->StmProtectionExceptionHandler
.SpeRsp
+= EFI_PAGES_TO_SIZE (EFI_SIZE_TO_PAGES (PcdGet32 (PcdCpuSmmStmExceptionStackSize
)));
332 Psd
->BiosHwResourceRequirementsPtr
= (UINT64
)(UINTN
)GetStmResource ();
335 // Get the APIC ID for the CPU specified by CpuIndex
337 Status
= mSmmCpuFeaturesLibMpService
->GetProcessorInfo (
338 mSmmCpuFeaturesLibMpService
,
342 ASSERT_EFI_ERROR (Status
);
344 Psd
->LocalApicId
= (UINT32
)ProcessorInfo
.ProcessorId
;
347 Hob
= GetFirstHob (EFI_HOB_TYPE_CPU
);
349 Psd
->PhysicalAddressBits
= ((EFI_HOB_CPU
*) Hob
)->SizeOfMemorySpace
;
351 AsmCpuid (0x80000000, &RegEax
, NULL
, NULL
, NULL
);
352 if (RegEax
>= 0x80000008) {
353 AsmCpuid (0x80000008, &RegEax
, NULL
, NULL
, NULL
);
354 Psd
->PhysicalAddressBits
= (UINT8
) RegEax
;
356 Psd
->PhysicalAddressBits
= 36;
360 if (!mStmConfigurationTableInitialized
) {
361 StmSmmConfigurationTableInit ();
362 mStmConfigurationTableInitialized
= TRUE
;
367 SMM End Of Dxe event notification handler.
369 STM support need patch AcpiRsdp in TXT_PROCESSOR_SMM_DESCRIPTOR.
371 @param[in] Protocol Points to the protocol's unique identifier.
372 @param[in] Interface Points to the interface instance.
373 @param[in] Handle The handle on which the interface was installed.
375 @retval EFI_SUCCESS Notification handler runs successfully.
379 SmmEndOfDxeEventNotify (
380 IN CONST EFI_GUID
*Protocol
,
387 TXT_PROCESSOR_SMM_DESCRIPTOR
*Psd
;
389 DEBUG ((DEBUG_INFO
, "SmmEndOfDxeEventNotify\n"));
392 // found ACPI table RSD_PTR from system table
395 for (Index
= 0; Index
< gST
->NumberOfTableEntries
; Index
++) {
396 if (CompareGuid (&(gST
->ConfigurationTable
[Index
].VendorGuid
), &gEfiAcpi20TableGuid
)) {
398 // A match was found.
400 Rsdp
= gST
->ConfigurationTable
[Index
].VendorTable
;
405 for (Index
= 0; Index
< gST
->NumberOfTableEntries
; Index
++) {
406 if (CompareGuid (&(gST
->ConfigurationTable
[Index
].VendorGuid
), &gEfiAcpi10TableGuid
)) {
408 // A match was found.
410 Rsdp
= gST
->ConfigurationTable
[Index
].VendorTable
;
416 for (Index
= 0; Index
< gSmst
->NumberOfCpus
; Index
++) {
417 Psd
= (TXT_PROCESSOR_SMM_DESCRIPTOR
*)((UINTN
)gSmst
->CpuSaveState
[Index
] - SMRAM_SAVE_STATE_MAP_OFFSET
+ TXT_SMM_PSD_OFFSET
);
418 DEBUG ((DEBUG_INFO
, "Index=%d Psd=%p Rsdp=%p\n", Index
, Psd
, Rsdp
));
419 Psd
->AcpiRsdp
= (UINT64
)(UINTN
)Rsdp
;
422 mLockLoadMonitor
= TRUE
;
428 This function initializes the STM configuration table.
431 StmSmmConfigurationTableInit (
438 Status
= gSmst
->SmmInstallProtocolInterface (
440 &gEfiSmMonitorInitProtocolGuid
,
441 EFI_NATIVE_INTERFACE
,
442 &mSmMonitorInitProtocol
444 ASSERT_EFI_ERROR (Status
);
448 // Register SMM End of DXE Event
450 Status
= gSmst
->SmmRegisterProtocolNotify (
451 &gEfiSmmEndOfDxeProtocolGuid
,
452 SmmEndOfDxeEventNotify
,
455 ASSERT_EFI_ERROR (Status
);
476 Handle single Resource to see if it can be merged into Record.
478 @param Resource A pointer to resource node to be added
479 @param Record A pointer to record node to be merged
481 @retval TRUE resource handled
482 @retval FALSE resource is not handled
486 HandleSingleResource (
487 IN STM_RSC
*Resource
,
502 // Calling code is responsible for making sure that
503 // Resource->Header.RscType == (*Record)->Header.RscType
504 // thus we use just one of them as switch variable.
506 switch (Resource
->Header
.RscType
) {
509 ResourceLo
= Resource
->Mem
.Base
;
510 ResourceHi
= Resource
->Mem
.Base
+ Resource
->Mem
.Length
;
511 RecordLo
= Record
->Mem
.Base
;
512 RecordHi
= Record
->Mem
.Base
+ Record
->Mem
.Length
;
513 if (Resource
->Mem
.RWXAttributes
!= Record
->Mem
.RWXAttributes
) {
514 if ((ResourceLo
== RecordLo
) && (ResourceHi
== RecordHi
)) {
515 Record
->Mem
.RWXAttributes
= Resource
->Mem
.RWXAttributes
| Record
->Mem
.RWXAttributes
;
523 case TRAPPED_IO_RANGE
:
524 ResourceLo
= (UINT64
) Resource
->Io
.Base
;
525 ResourceHi
= (UINT64
) Resource
->Io
.Base
+ (UINT64
) Resource
->Io
.Length
;
526 RecordLo
= (UINT64
) Record
->Io
.Base
;
527 RecordHi
= (UINT64
) Record
->Io
.Base
+ (UINT64
) Record
->Io
.Length
;
530 if ((Resource
->PciCfg
.OriginatingBusNumber
!= Record
->PciCfg
.OriginatingBusNumber
) ||
531 (Resource
->PciCfg
.LastNodeIndex
!= Record
->PciCfg
.LastNodeIndex
)) {
534 if (CompareMem (Resource
->PciCfg
.PciDevicePath
, Record
->PciCfg
.PciDevicePath
, sizeof(STM_PCI_DEVICE_PATH_NODE
) * (Resource
->PciCfg
.LastNodeIndex
+ 1)) != 0) {
537 ResourceLo
= (UINT64
) Resource
->PciCfg
.Base
;
538 ResourceHi
= (UINT64
) Resource
->PciCfg
.Base
+ (UINT64
) Resource
->PciCfg
.Length
;
539 RecordLo
= (UINT64
) Record
->PciCfg
.Base
;
540 RecordHi
= (UINT64
) Record
->PciCfg
.Base
+ (UINT64
) Record
->PciCfg
.Length
;
541 if (Resource
->PciCfg
.RWAttributes
!= Record
->PciCfg
.RWAttributes
) {
542 if ((ResourceLo
== RecordLo
) && (ResourceHi
== RecordHi
)) {
543 Record
->PciCfg
.RWAttributes
= Resource
->PciCfg
.RWAttributes
| Record
->PciCfg
.RWAttributes
;
550 case MACHINE_SPECIFIC_REG
:
552 // Special case - merge MSR masks in place.
554 if (Resource
->Msr
.MsrIndex
!= Record
->Msr
.MsrIndex
) {
557 Record
->Msr
.ReadMask
|= Resource
->Msr
.ReadMask
;
558 Record
->Msr
.WriteMask
|= Resource
->Msr
.WriteMask
;
564 // If resources are disjoint
566 if ((ResourceHi
< RecordLo
) || (ResourceLo
> RecordHi
)) {
571 // If resource is consumed by record.
573 if ((ResourceLo
>= RecordLo
) && (ResourceHi
<= RecordHi
)) {
577 // Resources are overlapping.
578 // Resource and record are merged.
580 ResourceLo
= (ResourceLo
< RecordLo
) ? ResourceLo
: RecordLo
;
581 ResourceHi
= (ResourceHi
> RecordHi
) ? ResourceHi
: RecordHi
;
583 switch (Resource
->Header
.RscType
) {
586 Record
->Mem
.Base
= ResourceLo
;
587 Record
->Mem
.Length
= ResourceHi
- ResourceLo
;
590 case TRAPPED_IO_RANGE
:
591 Record
->Io
.Base
= (UINT16
) ResourceLo
;
592 Record
->Io
.Length
= (UINT16
) (ResourceHi
- ResourceLo
);
595 Record
->PciCfg
.Base
= (UINT16
) ResourceLo
;
596 Record
->PciCfg
.Length
= (UINT16
) (ResourceHi
- ResourceLo
);
609 @param Resource A pointer to resource node to be added
619 Record
= (STM_RSC
*)mStmResourcesPtr
;
622 if (Record
->Header
.RscType
== END_OF_RESOURCES
) {
626 // Go to next record if resource and record types don't match.
628 if (Resource
->Header
.RscType
!= Record
->Header
.RscType
) {
629 Record
= (STM_RSC
*)((UINTN
)Record
+ Record
->Header
.Length
);
633 // Record is handled inside of procedure - don't adjust.
635 if (HandleSingleResource (Resource
, Record
)) {
638 Record
= (STM_RSC
*)((UINTN
)Record
+ Record
->Header
.Length
);
642 // Add resource to the end of area.
645 mStmResourcesPtr
+ mStmResourceSizeUsed
- sizeof(mRscEndNode
),
647 Resource
->Header
.Length
650 mStmResourcesPtr
+ mStmResourceSizeUsed
- sizeof(mRscEndNode
) + Resource
->Header
.Length
,
654 mStmResourceSizeUsed
+= Resource
->Header
.Length
;
655 mStmResourceSizeAvailable
= mStmResourceTotalSize
- mStmResourceSizeUsed
;
664 @param ResourceList A pointer to resource list to be added
665 @param NumEntries Optional number of entries.
666 If 0, list must be terminated by END_OF_RESOURCES.
671 IN STM_RSC
*ResourceList
,
672 IN UINT32 NumEntries OPTIONAL
679 if (NumEntries
== 0) {
685 Resource
= ResourceList
;
687 for (Index
= 0; Index
< Count
; Index
++) {
688 if (Resource
->Header
.RscType
== END_OF_RESOURCES
) {
691 AddSingleResource (Resource
);
692 Resource
= (STM_RSC
*)((UINTN
)Resource
+ Resource
->Header
.Length
);
699 Validate resource list.
701 @param ResourceList A pointer to resource list to be added
702 @param NumEntries Optional number of entries.
703 If 0, list must be terminated by END_OF_RESOURCES.
705 @retval TRUE resource valid
706 @retval FALSE resource invalid
711 IN STM_RSC
*ResourceList
,
712 IN UINT32 NumEntries OPTIONAL
721 // If NumEntries == 0 make it very big. Scan will be terminated by
724 if (NumEntries
== 0) {
731 // Start from beginning of resource list.
733 Resource
= ResourceList
;
735 for (Index
= 0; Index
< Count
; Index
++) {
736 DEBUG ((DEBUG_INFO
, "ValidateResource (%d) - RscType(%x)\n", Index
, Resource
->Header
.RscType
));
738 // Validate resource.
740 switch (Resource
->Header
.RscType
) {
741 case END_OF_RESOURCES
:
742 if (Resource
->Header
.Length
!= sizeof (STM_RSC_END
)) {
746 // If we are passed actual number of resources to add,
747 // END_OF_RESOURCES structure between them is considered an
748 // error. If NumEntries == 0 END_OF_RESOURCES is a termination.
750 if (NumEntries
!= 0) {
754 // If NumEntries == 0 and list reached end - return success.
762 if (Resource
->Header
.Length
!= sizeof (STM_RSC_MEM_DESC
)) {
766 if (Resource
->Mem
.RWXAttributes
> FULL_ACCS
) {
772 case TRAPPED_IO_RANGE
:
773 if (Resource
->Header
.Length
!= sizeof (STM_RSC_IO_DESC
)) {
777 if ((Resource
->Io
.Base
+ Resource
->Io
.Length
) > 0xFFFF) {
783 DEBUG ((DEBUG_INFO
, "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
));
784 if (Resource
->Header
.Length
!= sizeof (STM_RSC_PCI_CFG_DESC
) + (sizeof(STM_PCI_DEVICE_PATH_NODE
) * Resource
->PciCfg
.LastNodeIndex
)) {
787 for (SubIndex
= 0; SubIndex
<= Resource
->PciCfg
.LastNodeIndex
; SubIndex
++) {
788 if ((Resource
->PciCfg
.PciDevicePath
[SubIndex
].PciDevice
> 0x1F) || (Resource
->PciCfg
.PciDevicePath
[SubIndex
].PciFunction
> 7)) {
792 if ((Resource
->PciCfg
.Base
+ Resource
->PciCfg
.Length
) > 0x1000) {
797 case MACHINE_SPECIFIC_REG
:
798 if (Resource
->Header
.Length
!= sizeof (STM_RSC_MSR_DESC
)) {
804 DEBUG ((DEBUG_ERROR
, "ValidateResource - Unknown RscType(%x)\n", Resource
->Header
.RscType
));
807 Resource
= (STM_RSC
*)((UINTN
)Resource
+ Resource
->Header
.Length
);
815 EndResource is excluded.
817 @param ResourceList A pointer to resource list to be added
818 @param NumEntries Optional number of entries.
819 If 0, list must be terminated by END_OF_RESOURCES.
821 @retval TRUE resource valid
822 @retval FALSE resource invalid
827 IN STM_RSC
*ResourceList
,
828 IN UINT32 NumEntries OPTIONAL
835 Resource
= ResourceList
;
838 // If NumEntries == 0 make it very big. Scan will be terminated by
841 if (NumEntries
== 0) {
848 // Start from beginning of resource list.
850 Resource
= ResourceList
;
852 for (Index
= 0; Index
< Count
; Index
++) {
853 if (Resource
->Header
.RscType
== END_OF_RESOURCES
) {
856 Resource
= (STM_RSC
*)((UINTN
)Resource
+ Resource
->Header
.Length
);
859 return (UINTN
)Resource
- (UINTN
)ResourceList
;
864 Add resources in list to database. Allocate new memory areas as needed.
866 @param ResourceList A pointer to resource list to be added
867 @param NumEntries Optional number of entries.
868 If 0, list must be terminated by END_OF_RESOURCES.
870 @retval EFI_SUCCESS If resources are added
871 @retval EFI_INVALID_PARAMETER If nested procedure detected resource failer
872 @retval EFI_OUT_OF_RESOURCES If nested procedure returned it and we cannot allocate more areas.
878 IN STM_RSC
*ResourceList
,
879 IN UINT32 NumEntries OPTIONAL
884 EFI_PHYSICAL_ADDRESS NewResource
;
885 UINTN NewResourceSize
;
887 DEBUG ((DEBUG_INFO
, "AddPiResource - Enter\n"));
889 if (!ValidateResource (ResourceList
, NumEntries
)) {
890 return EFI_INVALID_PARAMETER
;
893 ResourceSize
= GetResourceSize (ResourceList
, NumEntries
);
894 DEBUG ((DEBUG_INFO
, "ResourceSize - 0x%08x\n", ResourceSize
));
895 if (ResourceSize
== 0) {
896 return EFI_INVALID_PARAMETER
;
899 if (mStmResourcesPtr
== NULL
) {
901 // First time allocation
903 NewResourceSize
= EFI_PAGES_TO_SIZE (EFI_SIZE_TO_PAGES (ResourceSize
+ sizeof(mRscEndNode
)));
904 DEBUG ((DEBUG_INFO
, "Allocate - 0x%08x\n", NewResourceSize
));
905 Status
= gSmst
->SmmAllocatePages (
907 EfiRuntimeServicesData
,
908 EFI_SIZE_TO_PAGES (NewResourceSize
),
911 if (EFI_ERROR (Status
)) {
916 // Copy EndResource for intialization
918 mStmResourcesPtr
= (UINT8
*)(UINTN
)NewResource
;
919 mStmResourceTotalSize
= NewResourceSize
;
920 CopyMem (mStmResourcesPtr
, &mRscEndNode
, sizeof(mRscEndNode
));
921 mStmResourceSizeUsed
= sizeof(mRscEndNode
);
922 mStmResourceSizeAvailable
= mStmResourceTotalSize
- sizeof(mRscEndNode
);
925 // Let SmmCore change resource ptr
927 NotifyStmResourceChange (mStmResourcesPtr
);
928 } else if (mStmResourceSizeAvailable
< ResourceSize
) {
932 NewResourceSize
= mStmResourceTotalSize
+ (ResourceSize
- mStmResourceSizeAvailable
);
933 NewResourceSize
= EFI_PAGES_TO_SIZE (EFI_SIZE_TO_PAGES (NewResourceSize
));
934 DEBUG ((DEBUG_INFO
, "ReAllocate - 0x%08x\n", NewResourceSize
));
935 Status
= gSmst
->SmmAllocatePages (
937 EfiRuntimeServicesData
,
938 EFI_SIZE_TO_PAGES (NewResourceSize
),
941 if (EFI_ERROR (Status
)) {
944 CopyMem ((VOID
*)(UINTN
)NewResource
, mStmResourcesPtr
, mStmResourceSizeUsed
);
945 mStmResourceSizeAvailable
= NewResourceSize
- mStmResourceSizeUsed
;
947 gSmst
->SmmFreePages (
948 (EFI_PHYSICAL_ADDRESS
)(UINTN
)mStmResourcesPtr
,
949 EFI_SIZE_TO_PAGES (mStmResourceTotalSize
)
952 mStmResourceTotalSize
= NewResourceSize
;
953 mStmResourcesPtr
= (UINT8
*)(UINTN
)NewResource
;
956 // Let SmmCore change resource ptr
958 NotifyStmResourceChange (mStmResourcesPtr
);
964 AddResource (ResourceList
, NumEntries
);
971 Delete resources in list to database.
973 @param ResourceList A pointer to resource list to be deleted
974 NULL means delete all resources.
975 @param NumEntries Optional number of entries.
976 If 0, list must be terminated by END_OF_RESOURCES.
978 @retval EFI_SUCCESS If resources are deleted
979 @retval EFI_INVALID_PARAMETER If nested procedure detected resource failer
985 IN STM_RSC
*ResourceList
,
986 IN UINT32 NumEntries OPTIONAL
989 if (ResourceList
!= NULL
) {
992 return EFI_UNSUPPORTED
;
997 CopyMem (mStmResourcesPtr
, &mRscEndNode
, sizeof(mRscEndNode
));
998 mStmResourceSizeUsed
= sizeof(mRscEndNode
);
999 mStmResourceSizeAvailable
= mStmResourceTotalSize
- sizeof(mRscEndNode
);
1007 @param ResourceList A pointer to resource list to be filled
1008 @param ResourceSize On input it means size of resource list input.
1009 On output it means size of resource list filled,
1010 or the size of resource list to be filled if size of too small.
1012 @retval EFI_SUCCESS If resources are returned.
1013 @retval EFI_BUFFER_TOO_SMALL If resource list buffer is too small to hold the whole resources.
1019 OUT STM_RSC
*ResourceList
,
1020 IN OUT UINT32
*ResourceSize
1023 if (*ResourceSize
< mStmResourceSizeUsed
) {
1024 *ResourceSize
= (UINT32
)mStmResourceSizeUsed
;
1025 return EFI_BUFFER_TOO_SMALL
;
1028 CopyMem (ResourceList
, mStmResourcesPtr
, mStmResourceSizeUsed
);
1029 *ResourceSize
= (UINT32
)mStmResourceSizeUsed
;
1035 Set valid bit for MSEG MSR.
1037 @param Buffer Ap function buffer. (not used)
1046 MSR_IA32_SMM_MONITOR_CTL_REGISTER SmmMonitorCtl
;
1048 SmmMonitorCtl
.Uint64
= AsmReadMsr64 (MSR_IA32_SMM_MONITOR_CTL
);
1049 SmmMonitorCtl
.Bits
.Valid
= 1;
1050 AsmWriteMsr64 (MSR_IA32_SMM_MONITOR_CTL
, SmmMonitorCtl
.Uint64
);
1055 Get 4K page aligned VMCS size.
1057 @return 4K page aligned VMCS size
1065 MSR_IA32_VMX_BASIC_REGISTER VmxBasic
;
1068 // Read VMCS size and and align to 4KB
1070 VmxBasic
.Uint64
= AsmReadMsr64 (MSR_IA32_VMX_BASIC
);
1071 return ALIGN_VALUE (VmxBasic
.Bits
.VmcsSize
, SIZE_4KB
);
1076 Check STM image size.
1078 @param StmImage STM image
1079 @param StmImageSize STM image size
1081 @retval TRUE check pass
1082 @retval FALSE check fail
1086 IN EFI_PHYSICAL_ADDRESS StmImage
,
1087 IN UINTN StmImageSize
1091 STM_HEADER
*StmHeader
;
1092 IA32_VMX_MISC_REGISTER VmxMiscMsr
;
1095 // Check to see if STM image is compatible with CPU
1097 StmHeader
= (STM_HEADER
*)(UINTN
)StmImage
;
1098 VmxMiscMsr
.Uint64
= AsmReadMsr64 (MSR_IA32_VMX_MISC
);
1099 if (StmHeader
->HwStmHdr
.MsegHeaderRevision
!= VmxMiscMsr
.Bits
.MsegRevisionIdentifier
) {
1100 DEBUG ((DEBUG_ERROR
, "STM Image not compatible with CPU\n"));
1101 DEBUG ((DEBUG_ERROR
, " StmHeader->HwStmHdr.MsegHeaderRevision = %08x\n", StmHeader
->HwStmHdr
.MsegHeaderRevision
));
1102 DEBUG ((DEBUG_ERROR
, " VmxMiscMsr.Bits.MsegRevisionIdentifier = %08x\n", VmxMiscMsr
.Bits
.MsegRevisionIdentifier
));
1107 // Get Minimal required Mseg size
1109 MinMsegSize
= (EFI_PAGES_TO_SIZE (EFI_SIZE_TO_PAGES (StmHeader
->SwStmHdr
.StaticImageSize
)) +
1110 StmHeader
->SwStmHdr
.AdditionalDynamicMemorySize
+
1111 (StmHeader
->SwStmHdr
.PerProcDynamicMemorySize
+ GetVmcsSize () * 2) * gSmst
->NumberOfCpus
);
1112 if (MinMsegSize
< StmImageSize
) {
1113 MinMsegSize
= StmImageSize
;
1116 if (StmHeader
->HwStmHdr
.Cr3Offset
>= StmHeader
->SwStmHdr
.StaticImageSize
) {
1118 // We will create page table, just in case that SINIT does not create it.
1120 if (MinMsegSize
< StmHeader
->HwStmHdr
.Cr3Offset
+ EFI_PAGES_TO_SIZE(6)) {
1121 MinMsegSize
= StmHeader
->HwStmHdr
.Cr3Offset
+ EFI_PAGES_TO_SIZE(6);
1126 // Check if it exceeds MSEG size
1128 if (MinMsegSize
> mMsegSize
) {
1129 DEBUG ((DEBUG_ERROR
, "MSEG too small. Min MSEG Size = %08x Current MSEG Size = %08x\n", MinMsegSize
, mMsegSize
));
1130 DEBUG ((DEBUG_ERROR
, " StmHeader->SwStmHdr.StaticImageSize = %08x\n", StmHeader
->SwStmHdr
.StaticImageSize
));
1131 DEBUG ((DEBUG_ERROR
, " StmHeader->SwStmHdr.AdditionalDynamicMemorySize = %08x\n", StmHeader
->SwStmHdr
.AdditionalDynamicMemorySize
));
1132 DEBUG ((DEBUG_ERROR
, " StmHeader->SwStmHdr.PerProcDynamicMemorySize = %08x\n", StmHeader
->SwStmHdr
.PerProcDynamicMemorySize
));
1133 DEBUG ((DEBUG_ERROR
, " VMCS Size = %08x\n", GetVmcsSize ()));
1134 DEBUG ((DEBUG_ERROR
, " Max CPUs = %08x\n", gSmst
->NumberOfCpus
));
1135 DEBUG ((DEBUG_ERROR
, " StmHeader->HwStmHdr.Cr3Offset = %08x\n", StmHeader
->HwStmHdr
.Cr3Offset
));
1144 Load STM image to MSEG.
1146 @param StmImage STM image
1147 @param StmImageSize STM image size
1152 IN EFI_PHYSICAL_ADDRESS StmImage
,
1153 IN UINTN StmImageSize
1156 MSR_IA32_SMM_MONITOR_CTL_REGISTER SmmMonitorCtl
;
1158 STM_HEADER
*StmHeader
;
1161 // Get MSEG base address from MSR_IA32_SMM_MONITOR_CTL
1163 SmmMonitorCtl
.Uint64
= AsmReadMsr64 (MSR_IA32_SMM_MONITOR_CTL
);
1164 MsegBase
= SmmMonitorCtl
.Bits
.MsegBase
<< 12;
1167 // Zero all of MSEG base address
1169 ZeroMem ((VOID
*)(UINTN
)MsegBase
, mMsegSize
);
1172 // Copy STM Image into MSEG
1174 CopyMem ((VOID
*)(UINTN
)MsegBase
, (VOID
*)(UINTN
)StmImage
, StmImageSize
);
1177 // STM Header is at the beginning of the STM Image
1179 StmHeader
= (STM_HEADER
*)(UINTN
)StmImage
;
1181 StmGen4GPageTable ((UINTN
)MsegBase
+ StmHeader
->HwStmHdr
.Cr3Offset
);
1186 Load STM image to MSEG.
1188 @param StmImage STM image
1189 @param StmImageSize STM image size
1191 @retval EFI_SUCCESS Load STM to MSEG successfully
1192 @retval EFI_ALREADY_STARTED STM image is already loaded to MSEG
1193 @retval EFI_BUFFER_TOO_SMALL MSEG is smaller than minimal requirement of STM image
1194 @retval EFI_UNSUPPORTED MSEG is not enabled
1200 IN EFI_PHYSICAL_ADDRESS StmImage
,
1201 IN UINTN StmImageSize
1204 MSR_IA32_SMM_MONITOR_CTL_REGISTER SmmMonitorCtl
;
1206 if (mLockLoadMonitor
) {
1207 return EFI_ACCESS_DENIED
;
1210 SmmMonitorCtl
.Uint64
= AsmReadMsr64 (MSR_IA32_SMM_MONITOR_CTL
);
1211 if (SmmMonitorCtl
.Bits
.MsegBase
== 0) {
1212 return EFI_UNSUPPORTED
;
1215 if (!StmCheckStmImage (StmImage
, StmImageSize
)) {
1216 return EFI_BUFFER_TOO_SMALL
;
1219 // Record STM_HASH to PCR 0, just in case it is NOT TXT launch, we still need provide the evidence.
1220 TpmMeasureAndLogData(
1222 TXT_EVTYPE_STM_HASH
, // EventType
1225 (VOID
*)(UINTN
)StmImage
, // HashData
1226 StmImageSize
// HashDataLen
1229 StmLoadStmImage (StmImage
, StmImageSize
);
1231 mStmState
|= EFI_SM_MONITOR_STATE_ENABLED
;
1237 This function return BIOS STM resource.
1239 Comsumed by SmmMpService when Init.
1241 @return BIOS STM resource
1249 return mStmResourcesPtr
;
1253 This function notify STM resource change.
1255 @param StmResource BIOS STM resource
1259 NotifyStmResourceChange (
1264 TXT_PROCESSOR_SMM_DESCRIPTOR
*Psd
;
1266 for (Index
= 0; Index
< gSmst
->NumberOfCpus
; Index
++) {
1267 Psd
= (TXT_PROCESSOR_SMM_DESCRIPTOR
*)((UINTN
)gSmst
->CpuSaveState
[Index
] - SMRAM_SAVE_STATE_MAP_OFFSET
+ TXT_SMM_PSD_OFFSET
);
1268 Psd
->BiosHwResourceRequirementsPtr
= (UINT64
)(UINTN
)StmResource
;
1275 This is STM setup BIOS callback.
1283 mStmState
|= EFI_SM_MONITOR_STATE_ACTIVATED
;
1287 This is STM teardown BIOS callback.
1295 mStmState
&= ~EFI_SM_MONITOR_STATE_ACTIVATED
;