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/Intel/Cpuid.h>
19 #include <Register/Intel/ArchitecturalMsr.h>
20 #include <Register/Intel/SmramSaveStateMap.h>
22 #include <Protocol/MpService.h>
24 #include "CpuFeaturesLib.h"
27 #define TXT_EVTYPE_BASE 0x400
28 #define TXT_EVTYPE_STM_HASH (TXT_EVTYPE_BASE + 14)
33 EFI_HANDLE mStmSmmCpuHandle
= NULL
;
35 BOOLEAN mLockLoadMonitor
= FALSE
;
38 // Template of STM_RSC_END structure for copying.
40 GLOBAL_REMOVE_IF_UNREFERENCED STM_RSC_END mRscEndNode
= {
41 {END_OF_RESOURCES
, sizeof (STM_RSC_END
)},
44 GLOBAL_REMOVE_IF_UNREFERENCED UINT8
*mStmResourcesPtr
= NULL
;
45 GLOBAL_REMOVE_IF_UNREFERENCED UINTN mStmResourceTotalSize
= 0x0;
46 GLOBAL_REMOVE_IF_UNREFERENCED UINTN mStmResourceSizeUsed
= 0x0;
47 GLOBAL_REMOVE_IF_UNREFERENCED UINTN mStmResourceSizeAvailable
= 0x0;
49 GLOBAL_REMOVE_IF_UNREFERENCED UINT32 mStmState
= 0;
52 // System Configuration Table pointing to STM Configuration Table
54 GLOBAL_REMOVE_IF_UNREFERENCED
55 EFI_SM_MONITOR_INIT_PROTOCOL mSmMonitorInitProtocol
= {
66 #define CPUID1_EDX_XD_SUPPORT 0x100000
69 // External global variables associated with SMI Handler Template
71 extern CONST TXT_PROCESSOR_SMM_DESCRIPTOR gcStmPsd
;
72 extern UINT32 gStmSmbase
;
73 extern volatile UINT32 gStmSmiStack
;
74 extern UINT32 gStmSmiCr3
;
75 extern volatile UINT8 gcStmSmiHandlerTemplate
[];
76 extern CONST UINT16 gcStmSmiHandlerSize
;
77 extern UINT16 gcStmSmiHandlerOffset
;
78 extern BOOLEAN gStmXdSupported
;
81 // Variables used by SMI Handler
83 IA32_DESCRIPTOR gStmSmiHandlerIdtr
;
86 // MP Services Protocol
88 EFI_MP_SERVICES_PROTOCOL
*mSmmCpuFeaturesLibMpService
= NULL
;
91 // MSEG Base and Length in SMRAM
96 BOOLEAN mStmConfigurationTableInitialized
= FALSE
;
99 The constructor function for the Traditional MM library instance with STM.
101 @param[in] ImageHandle The firmware allocated handle for the EFI image.
102 @param[in] SystemTable A pointer to the EFI System Table.
104 @retval EFI_SUCCESS The constructor always returns EFI_SUCCESS.
109 SmmCpuFeaturesLibStmConstructor (
110 IN EFI_HANDLE ImageHandle
,
111 IN EFI_SYSTEM_TABLE
*SystemTable
115 CPUID_VERSION_INFO_ECX RegEcx
;
116 EFI_HOB_GUID_TYPE
*GuidHob
;
117 EFI_SMRAM_DESCRIPTOR
*SmramDescriptor
;
120 // Initialize address fixup
122 SmmCpuFeaturesLibStmSmiEntryFixupAddress ();
125 // Perform library initialization common across all instances
127 CpuFeaturesLibInitialization ();
130 // Lookup the MP Services Protocol
132 Status
= gBS
->LocateProtocol (
133 &gEfiMpServiceProtocolGuid
,
135 (VOID
**)&mSmmCpuFeaturesLibMpService
137 ASSERT_EFI_ERROR (Status
);
140 // If CPU supports VMX, then determine SMRAM range for MSEG.
142 AsmCpuid (CPUID_VERSION_INFO
, NULL
, NULL
, &RegEcx
.Uint32
, NULL
);
143 if (RegEcx
.Bits
.VMX
== 1) {
144 GuidHob
= GetFirstGuidHob (&gMsegSmramGuid
);
145 if (GuidHob
!= NULL
) {
147 // Retrieve MSEG location from MSEG SRAM HOB
149 SmramDescriptor
= (EFI_SMRAM_DESCRIPTOR
*) GET_GUID_HOB_DATA (GuidHob
);
150 if (SmramDescriptor
->PhysicalSize
> 0) {
151 mMsegBase
= (UINTN
)SmramDescriptor
->CpuStart
;
152 mMsegSize
= (UINTN
)SmramDescriptor
->PhysicalSize
;
154 } else if (PcdGet32 (PcdCpuMsegSize
) > 0) {
156 // Allocate MSEG from SMRAM memory
158 mMsegBase
= (UINTN
)AllocatePages (EFI_SIZE_TO_PAGES (PcdGet32 (PcdCpuMsegSize
)));
160 mMsegSize
= ALIGN_VALUE (PcdGet32 (PcdCpuMsegSize
), EFI_PAGE_SIZE
);
162 DEBUG ((DEBUG_ERROR
, "Not enough SMRAM resource to allocate MSEG size %08x\n", PcdGet32 (PcdCpuMsegSize
)));
166 DEBUG ((DEBUG_INFO
, "MsegBase: 0x%08x, MsegSize: 0x%08x\n", mMsegBase
, mMsegSize
));
174 Internal worker function that is called to complete CPU initialization at the
175 end of SmmCpuFeaturesInitializeProcessor().
179 FinishSmmCpuFeaturesInitializeProcessor (
183 MSR_IA32_SMM_MONITOR_CTL_REGISTER SmmMonitorCtl
;
186 // Set MSEG Base Address in SMM Monitor Control MSR.
189 SmmMonitorCtl
.Uint64
= 0;
190 SmmMonitorCtl
.Bits
.MsegBase
= (UINT32
)mMsegBase
>> 12;
191 SmmMonitorCtl
.Bits
.Valid
= 1;
192 AsmWriteMsr64 (MSR_IA32_SMM_MONITOR_CTL
, SmmMonitorCtl
.Uint64
);
197 Return the size, in bytes, of a custom SMI Handler in bytes. If 0 is
198 returned, then a custom SMI handler is not provided by this library,
199 and the default SMI handler must be used.
201 @retval 0 Use the default SMI handler.
202 @retval > 0 Use the SMI handler installed by SmmCpuFeaturesInstallSmiHandler()
203 The caller is required to allocate enough SMRAM for each CPU to
204 support the size of the custom SMI handler.
208 SmmCpuFeaturesGetSmiHandlerSize (
212 return gcStmSmiHandlerSize
;
216 Install a custom SMI handler for the CPU specified by CpuIndex. This function
217 is only called if SmmCpuFeaturesGetSmiHandlerSize() returns a size is greater
218 than zero and is called by the CPU that was elected as monarch during System
219 Management Mode initialization.
221 @param[in] CpuIndex The index of the CPU to install the custom SMI handler.
222 The value must be between 0 and the NumberOfCpus field
223 in the System Management System Table (SMST).
224 @param[in] SmBase The SMBASE address for the CPU specified by CpuIndex.
225 @param[in] SmiStack The stack to use when an SMI is processed by the
226 the CPU specified by CpuIndex.
227 @param[in] StackSize The size, in bytes, if the stack used when an SMI is
228 processed by the CPU specified by CpuIndex.
229 @param[in] GdtBase The base address of the GDT to use when an SMI is
230 processed by the CPU specified by CpuIndex.
231 @param[in] GdtSize The size, in bytes, of the GDT used when an SMI is
232 processed by the CPU specified by CpuIndex.
233 @param[in] IdtBase The base address of the IDT to use when an SMI is
234 processed by the CPU specified by CpuIndex.
235 @param[in] IdtSize The size, in bytes, of the IDT used when an SMI is
236 processed by the CPU specified by CpuIndex.
237 @param[in] Cr3 The base address of the page tables to use when an SMI
238 is processed by the CPU specified by CpuIndex.
242 SmmCpuFeaturesInstallSmiHandler (
255 TXT_PROCESSOR_SMM_DESCRIPTOR
*Psd
;
259 EFI_PROCESSOR_INFORMATION ProcessorInfo
;
261 CopyMem ((VOID
*)((UINTN
)SmBase
+ TXT_SMM_PSD_OFFSET
), &gcStmPsd
, sizeof (gcStmPsd
));
262 Psd
= (TXT_PROCESSOR_SMM_DESCRIPTOR
*)(VOID
*)((UINTN
)SmBase
+ TXT_SMM_PSD_OFFSET
);
263 Psd
->SmmGdtPtr
= GdtBase
;
264 Psd
->SmmGdtSize
= (UINT32
)GdtSize
;
267 // Initialize values in template before copy
269 gStmSmiStack
= (UINT32
)((UINTN
)SmiStack
+ StackSize
- sizeof (UINTN
));
272 gStmSmiHandlerIdtr
.Base
= IdtBase
;
273 gStmSmiHandlerIdtr
.Limit
= (UINT16
)(IdtSize
- 1);
275 if (gStmXdSupported
) {
276 AsmCpuid (CPUID_EXTENDED_FUNCTION
, &RegEax
, NULL
, NULL
, NULL
);
277 if (RegEax
<= CPUID_EXTENDED_FUNCTION
) {
279 // Extended CPUID functions are not supported on this processor.
281 gStmXdSupported
= FALSE
;
284 AsmCpuid (CPUID_EXTENDED_CPU_SIG
, NULL
, NULL
, NULL
, &RegEdx
);
285 if ((RegEdx
& CPUID1_EDX_XD_SUPPORT
) == 0) {
287 // Execute Disable Bit feature is not supported on this processor.
289 gStmXdSupported
= FALSE
;
294 // Set the value at the top of the CPU stack to the CPU Index
296 *(UINTN
*)(UINTN
)gStmSmiStack
= CpuIndex
;
299 // Copy template to CPU specific SMI handler location
302 (VOID
*)((UINTN
)SmBase
+ SMM_HANDLER_OFFSET
),
303 (VOID
*)gcStmSmiHandlerTemplate
,
307 Psd
->SmmSmiHandlerRip
= SmBase
+ SMM_HANDLER_OFFSET
+ gcStmSmiHandlerOffset
;
308 Psd
->SmmSmiHandlerRsp
= (UINTN
)SmiStack
+ StackSize
- sizeof(UINTN
);
311 DEBUG((DEBUG_INFO
, "CpuSmmStmExceptionStackSize - %x\n", PcdGet32(PcdCpuSmmStmExceptionStackSize
)));
312 DEBUG((DEBUG_INFO
, "Pages - %x\n", EFI_SIZE_TO_PAGES(PcdGet32(PcdCpuSmmStmExceptionStackSize
))));
313 Psd
->StmProtectionExceptionHandler
.SpeRsp
= (UINT64
)(UINTN
)AllocatePages (EFI_SIZE_TO_PAGES (PcdGet32 (PcdCpuSmmStmExceptionStackSize
)));
314 Psd
->StmProtectionExceptionHandler
.SpeRsp
+= EFI_PAGES_TO_SIZE (EFI_SIZE_TO_PAGES (PcdGet32 (PcdCpuSmmStmExceptionStackSize
)));
316 Psd
->BiosHwResourceRequirementsPtr
= (UINT64
)(UINTN
)GetStmResource ();
319 // Get the APIC ID for the CPU specified by CpuIndex
321 Status
= mSmmCpuFeaturesLibMpService
->GetProcessorInfo (
322 mSmmCpuFeaturesLibMpService
,
326 ASSERT_EFI_ERROR (Status
);
328 Psd
->LocalApicId
= (UINT32
)ProcessorInfo
.ProcessorId
;
331 Hob
= GetFirstHob (EFI_HOB_TYPE_CPU
);
333 Psd
->PhysicalAddressBits
= ((EFI_HOB_CPU
*) Hob
)->SizeOfMemorySpace
;
335 AsmCpuid (0x80000000, &RegEax
, NULL
, NULL
, NULL
);
336 if (RegEax
>= 0x80000008) {
337 AsmCpuid (0x80000008, &RegEax
, NULL
, NULL
, NULL
);
338 Psd
->PhysicalAddressBits
= (UINT8
) RegEax
;
340 Psd
->PhysicalAddressBits
= 36;
344 if (!mStmConfigurationTableInitialized
) {
345 StmSmmConfigurationTableInit ();
346 mStmConfigurationTableInitialized
= TRUE
;
351 SMM End Of Dxe event notification handler.
353 STM support need patch AcpiRsdp in TXT_PROCESSOR_SMM_DESCRIPTOR.
355 @param[in] Protocol Points to the protocol's unique identifier.
356 @param[in] Interface Points to the interface instance.
357 @param[in] Handle The handle on which the interface was installed.
359 @retval EFI_SUCCESS Notification handler runs successfully.
363 SmmEndOfDxeEventNotify (
364 IN CONST EFI_GUID
*Protocol
,
371 TXT_PROCESSOR_SMM_DESCRIPTOR
*Psd
;
373 DEBUG ((DEBUG_INFO
, "SmmEndOfDxeEventNotify\n"));
376 // found ACPI table RSD_PTR from system table
379 for (Index
= 0; Index
< gST
->NumberOfTableEntries
; Index
++) {
380 if (CompareGuid (&(gST
->ConfigurationTable
[Index
].VendorGuid
), &gEfiAcpi20TableGuid
)) {
382 // A match was found.
384 Rsdp
= gST
->ConfigurationTable
[Index
].VendorTable
;
389 for (Index
= 0; Index
< gST
->NumberOfTableEntries
; Index
++) {
390 if (CompareGuid (&(gST
->ConfigurationTable
[Index
].VendorGuid
), &gEfiAcpi10TableGuid
)) {
392 // A match was found.
394 Rsdp
= gST
->ConfigurationTable
[Index
].VendorTable
;
400 for (Index
= 0; Index
< gSmst
->NumberOfCpus
; Index
++) {
401 Psd
= (TXT_PROCESSOR_SMM_DESCRIPTOR
*)((UINTN
)gSmst
->CpuSaveState
[Index
] - SMRAM_SAVE_STATE_MAP_OFFSET
+ TXT_SMM_PSD_OFFSET
);
402 DEBUG ((DEBUG_INFO
, "Index=%d Psd=%p Rsdp=%p\n", Index
, Psd
, Rsdp
));
403 Psd
->AcpiRsdp
= (UINT64
)(UINTN
)Rsdp
;
406 mLockLoadMonitor
= TRUE
;
412 This function initializes the STM configuration table.
415 StmSmmConfigurationTableInit (
422 Status
= gSmst
->SmmInstallProtocolInterface (
424 &gEfiSmMonitorInitProtocolGuid
,
425 EFI_NATIVE_INTERFACE
,
426 &mSmMonitorInitProtocol
428 ASSERT_EFI_ERROR (Status
);
432 // Register SMM End of DXE Event
434 Status
= gSmst
->SmmRegisterProtocolNotify (
435 &gEfiSmmEndOfDxeProtocolGuid
,
436 SmmEndOfDxeEventNotify
,
439 ASSERT_EFI_ERROR (Status
);
460 Handle single Resource to see if it can be merged into Record.
462 @param Resource A pointer to resource node to be added
463 @param Record A pointer to record node to be merged
465 @retval TRUE resource handled
466 @retval FALSE resource is not handled
470 HandleSingleResource (
471 IN STM_RSC
*Resource
,
486 // Calling code is responsible for making sure that
487 // Resource->Header.RscType == (*Record)->Header.RscType
488 // thus we use just one of them as switch variable.
490 switch (Resource
->Header
.RscType
) {
493 ResourceLo
= Resource
->Mem
.Base
;
494 ResourceHi
= Resource
->Mem
.Base
+ Resource
->Mem
.Length
;
495 RecordLo
= Record
->Mem
.Base
;
496 RecordHi
= Record
->Mem
.Base
+ Record
->Mem
.Length
;
497 if (Resource
->Mem
.RWXAttributes
!= Record
->Mem
.RWXAttributes
) {
498 if ((ResourceLo
== RecordLo
) && (ResourceHi
== RecordHi
)) {
499 Record
->Mem
.RWXAttributes
= Resource
->Mem
.RWXAttributes
| Record
->Mem
.RWXAttributes
;
507 case TRAPPED_IO_RANGE
:
508 ResourceLo
= (UINT64
) Resource
->Io
.Base
;
509 ResourceHi
= (UINT64
) Resource
->Io
.Base
+ (UINT64
) Resource
->Io
.Length
;
510 RecordLo
= (UINT64
) Record
->Io
.Base
;
511 RecordHi
= (UINT64
) Record
->Io
.Base
+ (UINT64
) Record
->Io
.Length
;
514 if ((Resource
->PciCfg
.OriginatingBusNumber
!= Record
->PciCfg
.OriginatingBusNumber
) ||
515 (Resource
->PciCfg
.LastNodeIndex
!= Record
->PciCfg
.LastNodeIndex
)) {
518 if (CompareMem (Resource
->PciCfg
.PciDevicePath
, Record
->PciCfg
.PciDevicePath
, sizeof(STM_PCI_DEVICE_PATH_NODE
) * (Resource
->PciCfg
.LastNodeIndex
+ 1)) != 0) {
521 ResourceLo
= (UINT64
) Resource
->PciCfg
.Base
;
522 ResourceHi
= (UINT64
) Resource
->PciCfg
.Base
+ (UINT64
) Resource
->PciCfg
.Length
;
523 RecordLo
= (UINT64
) Record
->PciCfg
.Base
;
524 RecordHi
= (UINT64
) Record
->PciCfg
.Base
+ (UINT64
) Record
->PciCfg
.Length
;
525 if (Resource
->PciCfg
.RWAttributes
!= Record
->PciCfg
.RWAttributes
) {
526 if ((ResourceLo
== RecordLo
) && (ResourceHi
== RecordHi
)) {
527 Record
->PciCfg
.RWAttributes
= Resource
->PciCfg
.RWAttributes
| Record
->PciCfg
.RWAttributes
;
534 case MACHINE_SPECIFIC_REG
:
536 // Special case - merge MSR masks in place.
538 if (Resource
->Msr
.MsrIndex
!= Record
->Msr
.MsrIndex
) {
541 Record
->Msr
.ReadMask
|= Resource
->Msr
.ReadMask
;
542 Record
->Msr
.WriteMask
|= Resource
->Msr
.WriteMask
;
548 // If resources are disjoint
550 if ((ResourceHi
< RecordLo
) || (ResourceLo
> RecordHi
)) {
555 // If resource is consumed by record.
557 if ((ResourceLo
>= RecordLo
) && (ResourceHi
<= RecordHi
)) {
561 // Resources are overlapping.
562 // Resource and record are merged.
564 ResourceLo
= (ResourceLo
< RecordLo
) ? ResourceLo
: RecordLo
;
565 ResourceHi
= (ResourceHi
> RecordHi
) ? ResourceHi
: RecordHi
;
567 switch (Resource
->Header
.RscType
) {
570 Record
->Mem
.Base
= ResourceLo
;
571 Record
->Mem
.Length
= ResourceHi
- ResourceLo
;
574 case TRAPPED_IO_RANGE
:
575 Record
->Io
.Base
= (UINT16
) ResourceLo
;
576 Record
->Io
.Length
= (UINT16
) (ResourceHi
- ResourceLo
);
579 Record
->PciCfg
.Base
= (UINT16
) ResourceLo
;
580 Record
->PciCfg
.Length
= (UINT16
) (ResourceHi
- ResourceLo
);
593 @param Resource A pointer to resource node to be added
603 Record
= (STM_RSC
*)mStmResourcesPtr
;
606 if (Record
->Header
.RscType
== END_OF_RESOURCES
) {
610 // Go to next record if resource and record types don't match.
612 if (Resource
->Header
.RscType
!= Record
->Header
.RscType
) {
613 Record
= (STM_RSC
*)((UINTN
)Record
+ Record
->Header
.Length
);
617 // Record is handled inside of procedure - don't adjust.
619 if (HandleSingleResource (Resource
, Record
)) {
622 Record
= (STM_RSC
*)((UINTN
)Record
+ Record
->Header
.Length
);
626 // Add resource to the end of area.
629 mStmResourcesPtr
+ mStmResourceSizeUsed
- sizeof(mRscEndNode
),
631 Resource
->Header
.Length
634 mStmResourcesPtr
+ mStmResourceSizeUsed
- sizeof(mRscEndNode
) + Resource
->Header
.Length
,
638 mStmResourceSizeUsed
+= Resource
->Header
.Length
;
639 mStmResourceSizeAvailable
= mStmResourceTotalSize
- mStmResourceSizeUsed
;
648 @param ResourceList A pointer to resource list to be added
649 @param NumEntries Optional number of entries.
650 If 0, list must be terminated by END_OF_RESOURCES.
655 IN STM_RSC
*ResourceList
,
656 IN UINT32 NumEntries OPTIONAL
663 if (NumEntries
== 0) {
669 Resource
= ResourceList
;
671 for (Index
= 0; Index
< Count
; Index
++) {
672 if (Resource
->Header
.RscType
== END_OF_RESOURCES
) {
675 AddSingleResource (Resource
);
676 Resource
= (STM_RSC
*)((UINTN
)Resource
+ Resource
->Header
.Length
);
683 Validate resource list.
685 @param ResourceList A pointer to resource list to be added
686 @param NumEntries Optional number of entries.
687 If 0, list must be terminated by END_OF_RESOURCES.
689 @retval TRUE resource valid
690 @retval FALSE resource invalid
695 IN STM_RSC
*ResourceList
,
696 IN UINT32 NumEntries OPTIONAL
705 // If NumEntries == 0 make it very big. Scan will be terminated by
708 if (NumEntries
== 0) {
715 // Start from beginning of resource list.
717 Resource
= ResourceList
;
719 for (Index
= 0; Index
< Count
; Index
++) {
720 DEBUG ((DEBUG_INFO
, "ValidateResource (%d) - RscType(%x)\n", Index
, Resource
->Header
.RscType
));
722 // Validate resource.
724 switch (Resource
->Header
.RscType
) {
725 case END_OF_RESOURCES
:
726 if (Resource
->Header
.Length
!= sizeof (STM_RSC_END
)) {
730 // If we are passed actual number of resources to add,
731 // END_OF_RESOURCES structure between them is considered an
732 // error. If NumEntries == 0 END_OF_RESOURCES is a termination.
734 if (NumEntries
!= 0) {
738 // If NumEntries == 0 and list reached end - return success.
746 if (Resource
->Header
.Length
!= sizeof (STM_RSC_MEM_DESC
)) {
750 if (Resource
->Mem
.RWXAttributes
> FULL_ACCS
) {
756 case TRAPPED_IO_RANGE
:
757 if (Resource
->Header
.Length
!= sizeof (STM_RSC_IO_DESC
)) {
761 if ((Resource
->Io
.Base
+ Resource
->Io
.Length
) > 0xFFFF) {
767 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
));
768 if (Resource
->Header
.Length
!= sizeof (STM_RSC_PCI_CFG_DESC
) + (sizeof(STM_PCI_DEVICE_PATH_NODE
) * Resource
->PciCfg
.LastNodeIndex
)) {
771 for (SubIndex
= 0; SubIndex
<= Resource
->PciCfg
.LastNodeIndex
; SubIndex
++) {
772 if ((Resource
->PciCfg
.PciDevicePath
[SubIndex
].PciDevice
> 0x1F) || (Resource
->PciCfg
.PciDevicePath
[SubIndex
].PciFunction
> 7)) {
776 if ((Resource
->PciCfg
.Base
+ Resource
->PciCfg
.Length
) > 0x1000) {
781 case MACHINE_SPECIFIC_REG
:
782 if (Resource
->Header
.Length
!= sizeof (STM_RSC_MSR_DESC
)) {
788 DEBUG ((DEBUG_ERROR
, "ValidateResource - Unknown RscType(%x)\n", Resource
->Header
.RscType
));
791 Resource
= (STM_RSC
*)((UINTN
)Resource
+ Resource
->Header
.Length
);
799 EndResource is excluded.
801 @param ResourceList A pointer to resource list to be added
802 @param NumEntries Optional number of entries.
803 If 0, list must be terminated by END_OF_RESOURCES.
805 @retval TRUE resource valid
806 @retval FALSE resource invalid
811 IN STM_RSC
*ResourceList
,
812 IN UINT32 NumEntries OPTIONAL
819 Resource
= ResourceList
;
822 // If NumEntries == 0 make it very big. Scan will be terminated by
825 if (NumEntries
== 0) {
832 // Start from beginning of resource list.
834 Resource
= ResourceList
;
836 for (Index
= 0; Index
< Count
; Index
++) {
837 if (Resource
->Header
.RscType
== END_OF_RESOURCES
) {
840 Resource
= (STM_RSC
*)((UINTN
)Resource
+ Resource
->Header
.Length
);
843 return (UINTN
)Resource
- (UINTN
)ResourceList
;
848 Add resources in list to database. Allocate new memory areas as needed.
850 @param ResourceList A pointer to resource list to be added
851 @param NumEntries Optional number of entries.
852 If 0, list must be terminated by END_OF_RESOURCES.
854 @retval EFI_SUCCESS If resources are added
855 @retval EFI_INVALID_PARAMETER If nested procedure detected resource failer
856 @retval EFI_OUT_OF_RESOURCES If nested procedure returned it and we cannot allocate more areas.
862 IN STM_RSC
*ResourceList
,
863 IN UINT32 NumEntries OPTIONAL
868 EFI_PHYSICAL_ADDRESS NewResource
;
869 UINTN NewResourceSize
;
871 DEBUG ((DEBUG_INFO
, "AddPiResource - Enter\n"));
873 if (!ValidateResource (ResourceList
, NumEntries
)) {
874 return EFI_INVALID_PARAMETER
;
877 ResourceSize
= GetResourceSize (ResourceList
, NumEntries
);
878 DEBUG ((DEBUG_INFO
, "ResourceSize - 0x%08x\n", ResourceSize
));
879 if (ResourceSize
== 0) {
880 return EFI_INVALID_PARAMETER
;
883 if (mStmResourcesPtr
== NULL
) {
885 // First time allocation
887 NewResourceSize
= EFI_PAGES_TO_SIZE (EFI_SIZE_TO_PAGES (ResourceSize
+ sizeof(mRscEndNode
)));
888 DEBUG ((DEBUG_INFO
, "Allocate - 0x%08x\n", NewResourceSize
));
889 Status
= gSmst
->SmmAllocatePages (
891 EfiRuntimeServicesData
,
892 EFI_SIZE_TO_PAGES (NewResourceSize
),
895 if (EFI_ERROR (Status
)) {
900 // Copy EndResource for initialization
902 mStmResourcesPtr
= (UINT8
*)(UINTN
)NewResource
;
903 mStmResourceTotalSize
= NewResourceSize
;
904 CopyMem (mStmResourcesPtr
, &mRscEndNode
, sizeof(mRscEndNode
));
905 mStmResourceSizeUsed
= sizeof(mRscEndNode
);
906 mStmResourceSizeAvailable
= mStmResourceTotalSize
- sizeof(mRscEndNode
);
909 // Let SmmCore change resource ptr
911 NotifyStmResourceChange (mStmResourcesPtr
);
912 } else if (mStmResourceSizeAvailable
< ResourceSize
) {
916 NewResourceSize
= mStmResourceTotalSize
+ (ResourceSize
- mStmResourceSizeAvailable
);
917 NewResourceSize
= EFI_PAGES_TO_SIZE (EFI_SIZE_TO_PAGES (NewResourceSize
));
918 DEBUG ((DEBUG_INFO
, "ReAllocate - 0x%08x\n", NewResourceSize
));
919 Status
= gSmst
->SmmAllocatePages (
921 EfiRuntimeServicesData
,
922 EFI_SIZE_TO_PAGES (NewResourceSize
),
925 if (EFI_ERROR (Status
)) {
928 CopyMem ((VOID
*)(UINTN
)NewResource
, mStmResourcesPtr
, mStmResourceSizeUsed
);
929 mStmResourceSizeAvailable
= NewResourceSize
- mStmResourceSizeUsed
;
931 gSmst
->SmmFreePages (
932 (EFI_PHYSICAL_ADDRESS
)(UINTN
)mStmResourcesPtr
,
933 EFI_SIZE_TO_PAGES (mStmResourceTotalSize
)
936 mStmResourceTotalSize
= NewResourceSize
;
937 mStmResourcesPtr
= (UINT8
*)(UINTN
)NewResource
;
940 // Let SmmCore change resource ptr
942 NotifyStmResourceChange (mStmResourcesPtr
);
948 AddResource (ResourceList
, NumEntries
);
955 Delete resources in list to database.
957 @param ResourceList A pointer to resource list to be deleted
958 NULL means delete all resources.
959 @param NumEntries Optional number of entries.
960 If 0, list must be terminated by END_OF_RESOURCES.
962 @retval EFI_SUCCESS If resources are deleted
963 @retval EFI_INVALID_PARAMETER If nested procedure detected resource failer
969 IN STM_RSC
*ResourceList
,
970 IN UINT32 NumEntries OPTIONAL
973 if (ResourceList
!= NULL
) {
976 return EFI_UNSUPPORTED
;
981 CopyMem (mStmResourcesPtr
, &mRscEndNode
, sizeof(mRscEndNode
));
982 mStmResourceSizeUsed
= sizeof(mRscEndNode
);
983 mStmResourceSizeAvailable
= mStmResourceTotalSize
- sizeof(mRscEndNode
);
991 @param ResourceList A pointer to resource list to be filled
992 @param ResourceSize On input it means size of resource list input.
993 On output it means size of resource list filled,
994 or the size of resource list to be filled if size of too small.
996 @retval EFI_SUCCESS If resources are returned.
997 @retval EFI_BUFFER_TOO_SMALL If resource list buffer is too small to hold the whole resources.
1003 OUT STM_RSC
*ResourceList
,
1004 IN OUT UINT32
*ResourceSize
1007 if (*ResourceSize
< mStmResourceSizeUsed
) {
1008 *ResourceSize
= (UINT32
)mStmResourceSizeUsed
;
1009 return EFI_BUFFER_TOO_SMALL
;
1012 CopyMem (ResourceList
, mStmResourcesPtr
, mStmResourceSizeUsed
);
1013 *ResourceSize
= (UINT32
)mStmResourceSizeUsed
;
1019 Set valid bit for MSEG MSR.
1021 @param Buffer Ap function buffer. (not used)
1030 MSR_IA32_SMM_MONITOR_CTL_REGISTER SmmMonitorCtl
;
1032 SmmMonitorCtl
.Uint64
= AsmReadMsr64 (MSR_IA32_SMM_MONITOR_CTL
);
1033 SmmMonitorCtl
.Bits
.Valid
= 1;
1034 AsmWriteMsr64 (MSR_IA32_SMM_MONITOR_CTL
, SmmMonitorCtl
.Uint64
);
1039 Get 4K page aligned VMCS size.
1041 @return 4K page aligned VMCS size
1049 MSR_IA32_VMX_BASIC_REGISTER VmxBasic
;
1052 // Read VMCS size and and align to 4KB
1054 VmxBasic
.Uint64
= AsmReadMsr64 (MSR_IA32_VMX_BASIC
);
1055 return ALIGN_VALUE (VmxBasic
.Bits
.VmcsSize
, SIZE_4KB
);
1060 Check STM image size.
1062 @param StmImage STM image
1063 @param StmImageSize STM image size
1065 @retval TRUE check pass
1066 @retval FALSE check fail
1070 IN EFI_PHYSICAL_ADDRESS StmImage
,
1071 IN UINTN StmImageSize
1075 STM_HEADER
*StmHeader
;
1076 IA32_VMX_MISC_REGISTER VmxMiscMsr
;
1079 // Check to see if STM image is compatible with CPU
1081 StmHeader
= (STM_HEADER
*)(UINTN
)StmImage
;
1082 VmxMiscMsr
.Uint64
= AsmReadMsr64 (MSR_IA32_VMX_MISC
);
1083 if (StmHeader
->HwStmHdr
.MsegHeaderRevision
!= VmxMiscMsr
.Bits
.MsegRevisionIdentifier
) {
1084 DEBUG ((DEBUG_ERROR
, "STM Image not compatible with CPU\n"));
1085 DEBUG ((DEBUG_ERROR
, " StmHeader->HwStmHdr.MsegHeaderRevision = %08x\n", StmHeader
->HwStmHdr
.MsegHeaderRevision
));
1086 DEBUG ((DEBUG_ERROR
, " VmxMiscMsr.Bits.MsegRevisionIdentifier = %08x\n", VmxMiscMsr
.Bits
.MsegRevisionIdentifier
));
1091 // Get Minimal required Mseg size
1093 MinMsegSize
= (EFI_PAGES_TO_SIZE (EFI_SIZE_TO_PAGES (StmHeader
->SwStmHdr
.StaticImageSize
)) +
1094 StmHeader
->SwStmHdr
.AdditionalDynamicMemorySize
+
1095 (StmHeader
->SwStmHdr
.PerProcDynamicMemorySize
+ GetVmcsSize () * 2) * gSmst
->NumberOfCpus
);
1096 if (MinMsegSize
< StmImageSize
) {
1097 MinMsegSize
= StmImageSize
;
1100 if (StmHeader
->HwStmHdr
.Cr3Offset
>= StmHeader
->SwStmHdr
.StaticImageSize
) {
1102 // We will create page table, just in case that SINIT does not create it.
1104 if (MinMsegSize
< StmHeader
->HwStmHdr
.Cr3Offset
+ EFI_PAGES_TO_SIZE(6)) {
1105 MinMsegSize
= StmHeader
->HwStmHdr
.Cr3Offset
+ EFI_PAGES_TO_SIZE(6);
1110 // Check if it exceeds MSEG size
1112 if (MinMsegSize
> mMsegSize
) {
1113 DEBUG ((DEBUG_ERROR
, "MSEG too small. Min MSEG Size = %08x Current MSEG Size = %08x\n", MinMsegSize
, mMsegSize
));
1114 DEBUG ((DEBUG_ERROR
, " StmHeader->SwStmHdr.StaticImageSize = %08x\n", StmHeader
->SwStmHdr
.StaticImageSize
));
1115 DEBUG ((DEBUG_ERROR
, " StmHeader->SwStmHdr.AdditionalDynamicMemorySize = %08x\n", StmHeader
->SwStmHdr
.AdditionalDynamicMemorySize
));
1116 DEBUG ((DEBUG_ERROR
, " StmHeader->SwStmHdr.PerProcDynamicMemorySize = %08x\n", StmHeader
->SwStmHdr
.PerProcDynamicMemorySize
));
1117 DEBUG ((DEBUG_ERROR
, " VMCS Size = %08x\n", GetVmcsSize ()));
1118 DEBUG ((DEBUG_ERROR
, " Max CPUs = %08x\n", gSmst
->NumberOfCpus
));
1119 DEBUG ((DEBUG_ERROR
, " StmHeader->HwStmHdr.Cr3Offset = %08x\n", StmHeader
->HwStmHdr
.Cr3Offset
));
1128 Load STM image to MSEG.
1130 @param StmImage STM image
1131 @param StmImageSize STM image size
1136 IN EFI_PHYSICAL_ADDRESS StmImage
,
1137 IN UINTN StmImageSize
1140 MSR_IA32_SMM_MONITOR_CTL_REGISTER SmmMonitorCtl
;
1142 STM_HEADER
*StmHeader
;
1145 // Get MSEG base address from MSR_IA32_SMM_MONITOR_CTL
1147 SmmMonitorCtl
.Uint64
= AsmReadMsr64 (MSR_IA32_SMM_MONITOR_CTL
);
1148 MsegBase
= SmmMonitorCtl
.Bits
.MsegBase
<< 12;
1151 // Zero all of MSEG base address
1153 ZeroMem ((VOID
*)(UINTN
)MsegBase
, mMsegSize
);
1156 // Copy STM Image into MSEG
1158 CopyMem ((VOID
*)(UINTN
)MsegBase
, (VOID
*)(UINTN
)StmImage
, StmImageSize
);
1161 // STM Header is at the beginning of the STM Image
1163 StmHeader
= (STM_HEADER
*)(UINTN
)StmImage
;
1165 StmGen4GPageTable ((UINTN
)MsegBase
+ StmHeader
->HwStmHdr
.Cr3Offset
);
1170 Load STM image to MSEG.
1172 @param StmImage STM image
1173 @param StmImageSize STM image size
1175 @retval EFI_SUCCESS Load STM to MSEG successfully
1176 @retval EFI_ALREADY_STARTED STM image is already loaded to MSEG
1177 @retval EFI_BUFFER_TOO_SMALL MSEG is smaller than minimal requirement of STM image
1178 @retval EFI_UNSUPPORTED MSEG is not enabled
1184 IN EFI_PHYSICAL_ADDRESS StmImage
,
1185 IN UINTN StmImageSize
1188 MSR_IA32_SMM_MONITOR_CTL_REGISTER SmmMonitorCtl
;
1190 if (mLockLoadMonitor
) {
1191 return EFI_ACCESS_DENIED
;
1194 SmmMonitorCtl
.Uint64
= AsmReadMsr64 (MSR_IA32_SMM_MONITOR_CTL
);
1195 if (SmmMonitorCtl
.Bits
.MsegBase
== 0) {
1196 return EFI_UNSUPPORTED
;
1199 if (!StmCheckStmImage (StmImage
, StmImageSize
)) {
1200 return EFI_BUFFER_TOO_SMALL
;
1203 // Record STM_HASH to PCR 0, just in case it is NOT TXT launch, we still need provide the evidence.
1204 TpmMeasureAndLogData(
1206 TXT_EVTYPE_STM_HASH
, // EventType
1209 (VOID
*)(UINTN
)StmImage
, // HashData
1210 StmImageSize
// HashDataLen
1213 StmLoadStmImage (StmImage
, StmImageSize
);
1215 mStmState
|= EFI_SM_MONITOR_STATE_ENABLED
;
1221 This function return BIOS STM resource.
1223 Consumed by SmmMpService when Init.
1225 @return BIOS STM resource
1233 return mStmResourcesPtr
;
1237 This function notify STM resource change.
1239 @param StmResource BIOS STM resource
1243 NotifyStmResourceChange (
1248 TXT_PROCESSOR_SMM_DESCRIPTOR
*Psd
;
1250 for (Index
= 0; Index
< gSmst
->NumberOfCpus
; Index
++) {
1251 Psd
= (TXT_PROCESSOR_SMM_DESCRIPTOR
*)((UINTN
)gSmst
->CpuSaveState
[Index
] - SMRAM_SAVE_STATE_MAP_OFFSET
+ TXT_SMM_PSD_OFFSET
);
1252 Psd
->BiosHwResourceRequirementsPtr
= (UINT64
)(UINTN
)StmResource
;
1259 This is STM setup BIOS callback.
1267 mStmState
|= EFI_SM_MONITOR_STATE_ACTIVATED
;
1271 This is STM teardown BIOS callback.
1279 mStmState
&= ~EFI_SM_MONITOR_STATE_ACTIVATED
;