2 SMM STM support functions
4 Copyright (c) 2015 - 2023, Intel Corporation. All rights reserved.<BR>
5 SPDX-License-Identifier: BSD-2-Clause-Patent
10 #include <Library/BaseMemoryLib.h>
11 #include <Library/UefiBootServicesTableLib.h>
12 #include <Library/SmmServicesTableLib.h>
13 #include <Library/TpmMeasurementLib.h>
14 #include <Register/Intel/Cpuid.h>
15 #include <Register/Intel/ArchitecturalMsr.h>
16 #include <Register/Intel/SmramSaveStateMap.h>
18 #include <Protocol/MpService.h>
20 #include "CpuFeaturesLib.h"
23 #define TXT_EVTYPE_BASE 0x400
24 #define TXT_EVTYPE_STM_HASH (TXT_EVTYPE_BASE + 14)
29 EFI_HANDLE mStmSmmCpuHandle
= NULL
;
31 BOOLEAN mLockLoadMonitor
= FALSE
;
34 // Template of STM_RSC_END structure for copying.
36 GLOBAL_REMOVE_IF_UNREFERENCED STM_RSC_END mRscEndNode
= {
37 { END_OF_RESOURCES
, sizeof (STM_RSC_END
) },
40 GLOBAL_REMOVE_IF_UNREFERENCED UINT8
*mStmResourcesPtr
= NULL
;
41 GLOBAL_REMOVE_IF_UNREFERENCED UINTN mStmResourceTotalSize
= 0x0;
42 GLOBAL_REMOVE_IF_UNREFERENCED UINTN mStmResourceSizeUsed
= 0x0;
43 GLOBAL_REMOVE_IF_UNREFERENCED UINTN mStmResourceSizeAvailable
= 0x0;
45 GLOBAL_REMOVE_IF_UNREFERENCED UINT32 mStmState
= 0;
48 // System Configuration Table pointing to STM Configuration Table
50 GLOBAL_REMOVE_IF_UNREFERENCED
51 EFI_SM_MONITOR_INIT_PROTOCOL mSmMonitorInitProtocol
= {
59 #define CPUID1_EDX_XD_SUPPORT 0x100000
62 // External global variables associated with SMI Handler Template
64 extern CONST TXT_PROCESSOR_SMM_DESCRIPTOR gcStmPsd
;
65 extern UINT32 gStmSmbase
;
66 extern volatile UINT32 gStmSmiStack
;
67 extern UINT32 gStmSmiCr3
;
68 extern volatile UINT8 gcStmSmiHandlerTemplate
[];
69 extern CONST UINT16 gcStmSmiHandlerSize
;
70 extern UINT16 gcStmSmiHandlerOffset
;
71 extern BOOLEAN gStmXdSupported
;
74 // Variables used by SMI Handler
76 IA32_DESCRIPTOR gStmSmiHandlerIdtr
;
79 // MP Services Protocol
81 EFI_MP_SERVICES_PROTOCOL
*mSmmCpuFeaturesLibMpService
= NULL
;
84 // MSEG Base and Length in SMRAM
89 BOOLEAN mStmConfigurationTableInitialized
= FALSE
;
92 The constructor function for the Traditional MM library instance with STM.
94 @param[in] ImageHandle The firmware allocated handle for the EFI image.
95 @param[in] SystemTable A pointer to the EFI System Table.
97 @retval EFI_SUCCESS The constructor always returns EFI_SUCCESS.
102 SmmCpuFeaturesLibStmConstructor (
103 IN EFI_HANDLE ImageHandle
,
104 IN EFI_SYSTEM_TABLE
*SystemTable
108 CPUID_VERSION_INFO_ECX RegEcx
;
109 EFI_HOB_GUID_TYPE
*GuidHob
;
110 EFI_SMRAM_DESCRIPTOR
*SmramDescriptor
;
113 // Initialize address fixup
115 SmmCpuFeaturesLibStmSmiEntryFixupAddress ();
118 // Perform library initialization common across all instances
120 CpuFeaturesLibInitialization ();
123 // Lookup the MP Services Protocol
125 Status
= gBS
->LocateProtocol (
126 &gEfiMpServiceProtocolGuid
,
128 (VOID
**)&mSmmCpuFeaturesLibMpService
130 ASSERT_EFI_ERROR (Status
);
133 // If CPU supports VMX, then determine SMRAM range for MSEG.
135 AsmCpuid (CPUID_VERSION_INFO
, NULL
, NULL
, &RegEcx
.Uint32
, NULL
);
136 if (RegEcx
.Bits
.VMX
== 1) {
137 GuidHob
= GetFirstGuidHob (&gMsegSmramGuid
);
138 if (GuidHob
!= NULL
) {
140 // Retrieve MSEG location from MSEG SRAM HOB
142 SmramDescriptor
= (EFI_SMRAM_DESCRIPTOR
*)GET_GUID_HOB_DATA (GuidHob
);
143 if (SmramDescriptor
->PhysicalSize
> 0) {
144 mMsegBase
= (UINTN
)SmramDescriptor
->CpuStart
;
145 mMsegSize
= (UINTN
)SmramDescriptor
->PhysicalSize
;
147 } else if (PcdGet32 (PcdCpuMsegSize
) > 0) {
149 // Allocate MSEG from SMRAM memory
151 mMsegBase
= (UINTN
)AllocatePages (EFI_SIZE_TO_PAGES (PcdGet32 (PcdCpuMsegSize
)));
153 mMsegSize
= ALIGN_VALUE (PcdGet32 (PcdCpuMsegSize
), EFI_PAGE_SIZE
);
155 DEBUG ((DEBUG_ERROR
, "Not enough SMRAM resource to allocate MSEG size %08x\n", PcdGet32 (PcdCpuMsegSize
)));
160 DEBUG ((DEBUG_INFO
, "MsegBase: 0x%08x, MsegSize: 0x%08x\n", mMsegBase
, mMsegSize
));
168 Internal worker function that is called to complete CPU initialization at the
169 end of SmmCpuFeaturesInitializeProcessor().
173 FinishSmmCpuFeaturesInitializeProcessor (
177 MSR_IA32_SMM_MONITOR_CTL_REGISTER SmmMonitorCtl
;
180 // Set MSEG Base Address in SMM Monitor Control MSR.
183 SmmMonitorCtl
.Uint64
= 0;
184 SmmMonitorCtl
.Bits
.MsegBase
= (UINT32
)mMsegBase
>> 12;
185 SmmMonitorCtl
.Bits
.Valid
= 1;
186 AsmWriteMsr64 (MSR_IA32_SMM_MONITOR_CTL
, SmmMonitorCtl
.Uint64
);
191 Return the size, in bytes, of a custom SMI Handler in bytes. If 0 is
192 returned, then a custom SMI handler is not provided by this library,
193 and the default SMI handler must be used.
195 @retval 0 Use the default SMI handler.
196 @retval > 0 Use the SMI handler installed by SmmCpuFeaturesInstallSmiHandler()
197 The caller is required to allocate enough SMRAM for each CPU to
198 support the size of the custom SMI handler.
202 SmmCpuFeaturesGetSmiHandlerSize (
206 return gcStmSmiHandlerSize
;
210 Install a custom SMI handler for the CPU specified by CpuIndex. This function
211 is only called if SmmCpuFeaturesGetSmiHandlerSize() returns a size is greater
212 than zero and is called by the CPU that was elected as monarch during System
213 Management Mode initialization.
215 @param[in] CpuIndex The index of the CPU to install the custom SMI handler.
216 The value must be between 0 and the NumberOfCpus field
217 in the System Management System Table (SMST).
218 @param[in] SmBase The SMBASE address for the CPU specified by CpuIndex.
219 @param[in] SmiStack The stack to use when an SMI is processed by the
220 the CPU specified by CpuIndex.
221 @param[in] StackSize The size, in bytes, if the stack used when an SMI is
222 processed by the CPU specified by CpuIndex.
223 @param[in] GdtBase The base address of the GDT to use when an SMI is
224 processed by the CPU specified by CpuIndex.
225 @param[in] GdtSize The size, in bytes, of the GDT used when an SMI is
226 processed by the CPU specified by CpuIndex.
227 @param[in] IdtBase The base address of the IDT to use when an SMI is
228 processed by the CPU specified by CpuIndex.
229 @param[in] IdtSize The size, in bytes, of the IDT used when an SMI is
230 processed by the CPU specified by CpuIndex.
231 @param[in] Cr3 The base address of the page tables to use when an SMI
232 is processed by the CPU specified by CpuIndex.
236 SmmCpuFeaturesInstallSmiHandler (
249 TXT_PROCESSOR_SMM_DESCRIPTOR
*Psd
;
253 EFI_PROCESSOR_INFORMATION ProcessorInfo
;
255 CopyMem ((VOID
*)((UINTN
)SmBase
+ TXT_SMM_PSD_OFFSET
), &gcStmPsd
, sizeof (gcStmPsd
));
256 Psd
= (TXT_PROCESSOR_SMM_DESCRIPTOR
*)(VOID
*)((UINTN
)SmBase
+ TXT_SMM_PSD_OFFSET
);
257 Psd
->SmmGdtPtr
= GdtBase
;
258 Psd
->SmmGdtSize
= (UINT32
)GdtSize
;
261 // Initialize values in template before copy
263 gStmSmiStack
= (UINT32
)((UINTN
)SmiStack
+ StackSize
- sizeof (UINTN
));
266 gStmSmiHandlerIdtr
.Base
= IdtBase
;
267 gStmSmiHandlerIdtr
.Limit
= (UINT16
)(IdtSize
- 1);
269 if (gStmXdSupported
) {
270 AsmCpuid (CPUID_EXTENDED_FUNCTION
, &RegEax
, NULL
, NULL
, NULL
);
271 if (RegEax
<= CPUID_EXTENDED_FUNCTION
) {
273 // Extended CPUID functions are not supported on this processor.
275 gStmXdSupported
= FALSE
;
278 AsmCpuid (CPUID_EXTENDED_CPU_SIG
, NULL
, NULL
, NULL
, &RegEdx
);
279 if ((RegEdx
& CPUID1_EDX_XD_SUPPORT
) == 0) {
281 // Execute Disable Bit feature is not supported on this processor.
283 gStmXdSupported
= FALSE
;
288 // Set the value at the top of the CPU stack to the CPU Index
290 *(UINTN
*)(UINTN
)gStmSmiStack
= CpuIndex
;
293 // Copy template to CPU specific SMI handler location
296 (VOID
*)((UINTN
)SmBase
+ SMM_HANDLER_OFFSET
),
297 (VOID
*)gcStmSmiHandlerTemplate
,
301 Psd
->SmmSmiHandlerRip
= SmBase
+ SMM_HANDLER_OFFSET
+ gcStmSmiHandlerOffset
;
302 Psd
->SmmSmiHandlerRsp
= (UINTN
)SmiStack
+ StackSize
- sizeof (UINTN
);
305 DEBUG ((DEBUG_INFO
, "CpuSmmStmExceptionStackSize - %x\n", PcdGet32 (PcdCpuSmmStmExceptionStackSize
)));
306 DEBUG ((DEBUG_INFO
, "Pages - %x\n", EFI_SIZE_TO_PAGES (PcdGet32 (PcdCpuSmmStmExceptionStackSize
))));
307 Psd
->StmProtectionExceptionHandler
.SpeRsp
= (UINT64
)(UINTN
)AllocatePages (EFI_SIZE_TO_PAGES (PcdGet32 (PcdCpuSmmStmExceptionStackSize
)));
308 Psd
->StmProtectionExceptionHandler
.SpeRsp
+= EFI_PAGES_TO_SIZE (EFI_SIZE_TO_PAGES (PcdGet32 (PcdCpuSmmStmExceptionStackSize
)));
310 Psd
->BiosHwResourceRequirementsPtr
= (UINT64
)(UINTN
)GetStmResource ();
313 // Get the APIC ID for the CPU specified by CpuIndex
315 Status
= mSmmCpuFeaturesLibMpService
->GetProcessorInfo (
316 mSmmCpuFeaturesLibMpService
,
320 ASSERT_EFI_ERROR (Status
);
322 Psd
->LocalApicId
= (UINT32
)ProcessorInfo
.ProcessorId
;
325 Hob
= GetFirstHob (EFI_HOB_TYPE_CPU
);
327 Psd
->PhysicalAddressBits
= ((EFI_HOB_CPU
*)Hob
)->SizeOfMemorySpace
;
329 AsmCpuid (0x80000000, &RegEax
, NULL
, NULL
, NULL
);
330 if (RegEax
>= 0x80000008) {
331 AsmCpuid (0x80000008, &RegEax
, NULL
, NULL
, NULL
);
332 Psd
->PhysicalAddressBits
= (UINT8
)RegEax
;
334 Psd
->PhysicalAddressBits
= 36;
338 if (!mStmConfigurationTableInitialized
) {
339 StmSmmConfigurationTableInit ();
340 mStmConfigurationTableInitialized
= TRUE
;
345 SMM End Of Dxe event notification handler.
347 STM support need patch AcpiRsdp in TXT_PROCESSOR_SMM_DESCRIPTOR.
349 @param[in] Protocol Points to the protocol's unique identifier.
350 @param[in] Interface Points to the interface instance.
351 @param[in] Handle The handle on which the interface was installed.
353 @retval EFI_SUCCESS Notification handler runs successfully.
357 SmmEndOfDxeEventNotify (
358 IN CONST EFI_GUID
*Protocol
,
365 TXT_PROCESSOR_SMM_DESCRIPTOR
*Psd
;
367 DEBUG ((DEBUG_INFO
, "SmmEndOfDxeEventNotify\n"));
370 // found ACPI table RSD_PTR from system table
373 for (Index
= 0; Index
< gST
->NumberOfTableEntries
; Index
++) {
374 if (CompareGuid (&(gST
->ConfigurationTable
[Index
].VendorGuid
), &gEfiAcpi20TableGuid
)) {
376 // A match was found.
378 Rsdp
= gST
->ConfigurationTable
[Index
].VendorTable
;
384 for (Index
= 0; Index
< gST
->NumberOfTableEntries
; Index
++) {
385 if (CompareGuid (&(gST
->ConfigurationTable
[Index
].VendorGuid
), &gEfiAcpi10TableGuid
)) {
387 // A match was found.
389 Rsdp
= gST
->ConfigurationTable
[Index
].VendorTable
;
395 for (Index
= 0; Index
< gSmst
->NumberOfCpus
; Index
++) {
396 Psd
= (TXT_PROCESSOR_SMM_DESCRIPTOR
*)((UINTN
)gSmst
->CpuSaveState
[Index
] - SMRAM_SAVE_STATE_MAP_OFFSET
+ TXT_SMM_PSD_OFFSET
);
397 DEBUG ((DEBUG_INFO
, "Index=%d Psd=%p Rsdp=%p\n", Index
, Psd
, Rsdp
));
398 Psd
->AcpiRsdp
= (UINT64
)(UINTN
)Rsdp
;
401 mLockLoadMonitor
= TRUE
;
407 This function initializes the STM configuration table.
410 StmSmmConfigurationTableInit (
417 Status
= gSmst
->SmmInstallProtocolInterface (
419 &gEfiSmMonitorInitProtocolGuid
,
420 EFI_NATIVE_INTERFACE
,
421 &mSmMonitorInitProtocol
423 ASSERT_EFI_ERROR (Status
);
427 // Register SMM End of DXE Event
429 Status
= gSmst
->SmmRegisterProtocolNotify (
430 &gEfiSmmEndOfDxeProtocolGuid
,
431 SmmEndOfDxeEventNotify
,
434 ASSERT_EFI_ERROR (Status
);
455 Handle single Resource to see if it can be merged into Record.
457 @param Resource A pointer to resource node to be added
458 @param Record A pointer to record node to be merged
460 @retval TRUE resource handled
461 @retval FALSE resource is not handled
465 HandleSingleResource (
466 IN STM_RSC
*Resource
,
481 // Calling code is responsible for making sure that
482 // Resource->Header.RscType == (*Record)->Header.RscType
483 // thus we use just one of them as switch variable.
485 switch (Resource
->Header
.RscType
) {
488 ResourceLo
= Resource
->Mem
.Base
;
489 ResourceHi
= Resource
->Mem
.Base
+ Resource
->Mem
.Length
;
490 RecordLo
= Record
->Mem
.Base
;
491 RecordHi
= Record
->Mem
.Base
+ Record
->Mem
.Length
;
492 if (Resource
->Mem
.RWXAttributes
!= Record
->Mem
.RWXAttributes
) {
493 if ((ResourceLo
== RecordLo
) && (ResourceHi
== RecordHi
)) {
494 Record
->Mem
.RWXAttributes
= Resource
->Mem
.RWXAttributes
| Record
->Mem
.RWXAttributes
;
503 case TRAPPED_IO_RANGE
:
504 ResourceLo
= (UINT64
)Resource
->Io
.Base
;
505 ResourceHi
= (UINT64
)Resource
->Io
.Base
+ (UINT64
)Resource
->Io
.Length
;
506 RecordLo
= (UINT64
)Record
->Io
.Base
;
507 RecordHi
= (UINT64
)Record
->Io
.Base
+ (UINT64
)Record
->Io
.Length
;
510 if ((Resource
->PciCfg
.OriginatingBusNumber
!= Record
->PciCfg
.OriginatingBusNumber
) ||
511 (Resource
->PciCfg
.LastNodeIndex
!= Record
->PciCfg
.LastNodeIndex
))
516 if (CompareMem (Resource
->PciCfg
.PciDevicePath
, Record
->PciCfg
.PciDevicePath
, sizeof (STM_PCI_DEVICE_PATH_NODE
) * (Resource
->PciCfg
.LastNodeIndex
+ 1)) != 0) {
520 ResourceLo
= (UINT64
)Resource
->PciCfg
.Base
;
521 ResourceHi
= (UINT64
)Resource
->PciCfg
.Base
+ (UINT64
)Resource
->PciCfg
.Length
;
522 RecordLo
= (UINT64
)Record
->PciCfg
.Base
;
523 RecordHi
= (UINT64
)Record
->PciCfg
.Base
+ (UINT64
)Record
->PciCfg
.Length
;
524 if (Resource
->PciCfg
.RWAttributes
!= Record
->PciCfg
.RWAttributes
) {
525 if ((ResourceLo
== RecordLo
) && (ResourceHi
== RecordHi
)) {
526 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
) {
542 Record
->Msr
.ReadMask
|= Resource
->Msr
.ReadMask
;
543 Record
->Msr
.WriteMask
|= Resource
->Msr
.WriteMask
;
550 // If resources are disjoint
552 if ((ResourceHi
< RecordLo
) || (ResourceLo
> RecordHi
)) {
557 // If resource is consumed by record.
559 if ((ResourceLo
>= RecordLo
) && (ResourceHi
<= RecordHi
)) {
564 // Resources are overlapping.
565 // Resource and record are merged.
567 ResourceLo
= (ResourceLo
< RecordLo
) ? ResourceLo
: RecordLo
;
568 ResourceHi
= (ResourceHi
> RecordHi
) ? ResourceHi
: RecordHi
;
570 switch (Resource
->Header
.RscType
) {
573 Record
->Mem
.Base
= ResourceLo
;
574 Record
->Mem
.Length
= ResourceHi
- ResourceLo
;
577 case TRAPPED_IO_RANGE
:
578 Record
->Io
.Base
= (UINT16
)ResourceLo
;
579 Record
->Io
.Length
= (UINT16
)(ResourceHi
- ResourceLo
);
582 Record
->PciCfg
.Base
= (UINT16
)ResourceLo
;
583 Record
->PciCfg
.Length
= (UINT16
)(ResourceHi
- ResourceLo
);
596 @param Resource A pointer to resource node to be added
606 Record
= (STM_RSC
*)mStmResourcesPtr
;
609 if (Record
->Header
.RscType
== END_OF_RESOURCES
) {
614 // Go to next record if resource and record types don't match.
616 if (Resource
->Header
.RscType
!= Record
->Header
.RscType
) {
617 Record
= (STM_RSC
*)((UINTN
)Record
+ Record
->Header
.Length
);
622 // Record is handled inside of procedure - don't adjust.
624 if (HandleSingleResource (Resource
, Record
)) {
628 Record
= (STM_RSC
*)((UINTN
)Record
+ Record
->Header
.Length
);
632 // Add resource to the end of area.
635 mStmResourcesPtr
+ mStmResourceSizeUsed
- sizeof (mRscEndNode
),
637 Resource
->Header
.Length
640 mStmResourcesPtr
+ mStmResourceSizeUsed
- sizeof (mRscEndNode
) + Resource
->Header
.Length
,
644 mStmResourceSizeUsed
+= Resource
->Header
.Length
;
645 mStmResourceSizeAvailable
= mStmResourceTotalSize
- mStmResourceSizeUsed
;
654 @param ResourceList A pointer to resource list to be added
655 @param NumEntries Optional number of entries.
656 If 0, list must be terminated by END_OF_RESOURCES.
661 IN STM_RSC
*ResourceList
,
662 IN UINT32 NumEntries OPTIONAL
669 if (NumEntries
== 0) {
675 Resource
= ResourceList
;
677 for (Index
= 0; Index
< Count
; Index
++) {
678 if (Resource
->Header
.RscType
== END_OF_RESOURCES
) {
682 AddSingleResource (Resource
);
683 Resource
= (STM_RSC
*)((UINTN
)Resource
+ Resource
->Header
.Length
);
691 Validate resource list.
693 @param ResourceList A pointer to resource list to be added
694 @param NumEntries Optional number of entries.
695 If 0, list must be terminated by END_OF_RESOURCES.
697 @retval TRUE resource valid
698 @retval FALSE resource invalid
703 IN STM_RSC
*ResourceList
,
704 IN UINT32 NumEntries OPTIONAL
713 // If NumEntries == 0 make it very big. Scan will be terminated by
716 if (NumEntries
== 0) {
723 // Start from beginning of resource list.
725 Resource
= ResourceList
;
727 for (Index
= 0; Index
< Count
; Index
++) {
728 DEBUG ((DEBUG_INFO
, "ValidateResource (%d) - RscType(%x)\n", Index
, Resource
->Header
.RscType
));
730 // Validate resource.
732 switch (Resource
->Header
.RscType
) {
733 case END_OF_RESOURCES
:
734 if (Resource
->Header
.Length
!= sizeof (STM_RSC_END
)) {
739 // If we are passed actual number of resources to add,
740 // END_OF_RESOURCES structure between them is considered an
741 // error. If NumEntries == 0 END_OF_RESOURCES is a termination.
743 if (NumEntries
!= 0) {
747 // If NumEntries == 0 and list reached end - return success.
756 if (Resource
->Header
.Length
!= sizeof (STM_RSC_MEM_DESC
)) {
760 if (Resource
->Mem
.RWXAttributes
> FULL_ACCS
) {
767 case TRAPPED_IO_RANGE
:
768 if (Resource
->Header
.Length
!= sizeof (STM_RSC_IO_DESC
)) {
772 if ((Resource
->Io
.Base
+ Resource
->Io
.Length
) > 0xFFFF) {
779 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
));
780 if (Resource
->Header
.Length
!= sizeof (STM_RSC_PCI_CFG_DESC
) + (sizeof (STM_PCI_DEVICE_PATH_NODE
) * Resource
->PciCfg
.LastNodeIndex
)) {
784 for (SubIndex
= 0; SubIndex
<= Resource
->PciCfg
.LastNodeIndex
; SubIndex
++) {
785 if ((Resource
->PciCfg
.PciDevicePath
[SubIndex
].PciDevice
> 0x1F) || (Resource
->PciCfg
.PciDevicePath
[SubIndex
].PciFunction
> 7)) {
790 if ((Resource
->PciCfg
.Base
+ Resource
->PciCfg
.Length
) > 0x1000) {
796 case MACHINE_SPECIFIC_REG
:
797 if (Resource
->Header
.Length
!= sizeof (STM_RSC_MSR_DESC
)) {
804 DEBUG ((DEBUG_ERROR
, "ValidateResource - Unknown RscType(%x)\n", Resource
->Header
.RscType
));
808 Resource
= (STM_RSC
*)((UINTN
)Resource
+ Resource
->Header
.Length
);
817 EndResource is excluded.
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.
823 @retval TRUE resource valid
824 @retval FALSE resource invalid
829 IN STM_RSC
*ResourceList
,
830 IN UINT32 NumEntries OPTIONAL
837 Resource
= ResourceList
;
840 // If NumEntries == 0 make it very big. Scan will be terminated by
843 if (NumEntries
== 0) {
850 // Start from beginning of resource list.
852 Resource
= ResourceList
;
854 for (Index
= 0; Index
< Count
; Index
++) {
855 if (Resource
->Header
.RscType
== END_OF_RESOURCES
) {
859 Resource
= (STM_RSC
*)((UINTN
)Resource
+ Resource
->Header
.Length
);
862 return (UINTN
)Resource
- (UINTN
)ResourceList
;
867 Add resources in list to database. Allocate new memory areas as needed.
869 @param ResourceList A pointer to resource list to be added
870 @param NumEntries Optional number of entries.
871 If 0, list must be terminated by END_OF_RESOURCES.
873 @retval EFI_SUCCESS If resources are added
874 @retval EFI_INVALID_PARAMETER If nested procedure detected resource failer
875 @retval EFI_OUT_OF_RESOURCES If nested procedure returned it and we cannot allocate more areas.
881 IN STM_RSC
*ResourceList
,
882 IN UINT32 NumEntries OPTIONAL
887 EFI_PHYSICAL_ADDRESS NewResource
;
888 UINTN NewResourceSize
;
890 DEBUG ((DEBUG_INFO
, "AddPiResource - Enter\n"));
892 if (!ValidateResource (ResourceList
, NumEntries
)) {
893 return EFI_INVALID_PARAMETER
;
896 ResourceSize
= GetResourceSize (ResourceList
, NumEntries
);
897 DEBUG ((DEBUG_INFO
, "ResourceSize - 0x%08x\n", ResourceSize
));
898 if (ResourceSize
== 0) {
899 return EFI_INVALID_PARAMETER
;
902 if (mStmResourcesPtr
== NULL
) {
904 // First time allocation
906 NewResourceSize
= EFI_PAGES_TO_SIZE (EFI_SIZE_TO_PAGES (ResourceSize
+ sizeof (mRscEndNode
)));
907 DEBUG ((DEBUG_INFO
, "Allocate - 0x%08x\n", NewResourceSize
));
908 Status
= gSmst
->SmmAllocatePages (
910 EfiRuntimeServicesData
,
911 EFI_SIZE_TO_PAGES (NewResourceSize
),
914 if (EFI_ERROR (Status
)) {
919 // Copy EndResource for initialization
921 mStmResourcesPtr
= (UINT8
*)(UINTN
)NewResource
;
922 mStmResourceTotalSize
= NewResourceSize
;
923 CopyMem (mStmResourcesPtr
, &mRscEndNode
, sizeof (mRscEndNode
));
924 mStmResourceSizeUsed
= sizeof (mRscEndNode
);
925 mStmResourceSizeAvailable
= mStmResourceTotalSize
- sizeof (mRscEndNode
);
928 // Let SmmCore change resource ptr
930 NotifyStmResourceChange (mStmResourcesPtr
);
931 } else if (mStmResourceSizeAvailable
< ResourceSize
) {
935 NewResourceSize
= mStmResourceTotalSize
+ (ResourceSize
- mStmResourceSizeAvailable
);
936 NewResourceSize
= EFI_PAGES_TO_SIZE (EFI_SIZE_TO_PAGES (NewResourceSize
));
937 DEBUG ((DEBUG_INFO
, "ReAllocate - 0x%08x\n", NewResourceSize
));
938 Status
= gSmst
->SmmAllocatePages (
940 EfiRuntimeServicesData
,
941 EFI_SIZE_TO_PAGES (NewResourceSize
),
944 if (EFI_ERROR (Status
)) {
948 CopyMem ((VOID
*)(UINTN
)NewResource
, mStmResourcesPtr
, mStmResourceSizeUsed
);
949 mStmResourceSizeAvailable
= NewResourceSize
- mStmResourceSizeUsed
;
951 gSmst
->SmmFreePages (
952 (EFI_PHYSICAL_ADDRESS
)(UINTN
)mStmResourcesPtr
,
953 EFI_SIZE_TO_PAGES (mStmResourceTotalSize
)
956 mStmResourceTotalSize
= NewResourceSize
;
957 mStmResourcesPtr
= (UINT8
*)(UINTN
)NewResource
;
960 // Let SmmCore change resource ptr
962 NotifyStmResourceChange (mStmResourcesPtr
);
968 AddResource (ResourceList
, NumEntries
);
975 Delete resources in list to database.
977 @param ResourceList A pointer to resource list to be deleted
978 NULL means delete all resources.
979 @param NumEntries Optional number of entries.
980 If 0, list must be terminated by END_OF_RESOURCES.
982 @retval EFI_SUCCESS If resources are deleted
983 @retval EFI_INVALID_PARAMETER If nested procedure detected resource failer
989 IN STM_RSC
*ResourceList
,
990 IN UINT32 NumEntries OPTIONAL
993 if (ResourceList
!= NULL
) {
996 return EFI_UNSUPPORTED
;
1002 CopyMem (mStmResourcesPtr
, &mRscEndNode
, sizeof (mRscEndNode
));
1003 mStmResourceSizeUsed
= sizeof (mRscEndNode
);
1004 mStmResourceSizeAvailable
= mStmResourceTotalSize
- sizeof (mRscEndNode
);
1012 @param ResourceList A pointer to resource list to be filled
1013 @param ResourceSize On input it means size of resource list input.
1014 On output it means size of resource list filled,
1015 or the size of resource list to be filled if size of too small.
1017 @retval EFI_SUCCESS If resources are returned.
1018 @retval EFI_BUFFER_TOO_SMALL If resource list buffer is too small to hold the whole resources.
1024 OUT STM_RSC
*ResourceList
,
1025 IN OUT UINT32
*ResourceSize
1028 if (*ResourceSize
< mStmResourceSizeUsed
) {
1029 *ResourceSize
= (UINT32
)mStmResourceSizeUsed
;
1030 return EFI_BUFFER_TOO_SMALL
;
1033 CopyMem (ResourceList
, mStmResourcesPtr
, mStmResourceSizeUsed
);
1034 *ResourceSize
= (UINT32
)mStmResourceSizeUsed
;
1040 Set valid bit for MSEG MSR.
1042 @param Buffer Ap function buffer. (not used)
1051 MSR_IA32_SMM_MONITOR_CTL_REGISTER SmmMonitorCtl
;
1053 SmmMonitorCtl
.Uint64
= AsmReadMsr64 (MSR_IA32_SMM_MONITOR_CTL
);
1054 SmmMonitorCtl
.Bits
.Valid
= 1;
1055 AsmWriteMsr64 (MSR_IA32_SMM_MONITOR_CTL
, SmmMonitorCtl
.Uint64
);
1060 Get 4K page aligned VMCS size.
1062 @return 4K page aligned VMCS size
1070 MSR_IA32_VMX_BASIC_REGISTER VmxBasic
;
1073 // Read VMCS size and and align to 4KB
1075 VmxBasic
.Uint64
= AsmReadMsr64 (MSR_IA32_VMX_BASIC
);
1076 return ALIGN_VALUE (VmxBasic
.Bits
.VmcsSize
, SIZE_4KB
);
1081 Check STM image size.
1083 @param StmImage STM image
1084 @param StmImageSize STM image size
1086 @retval TRUE check pass
1087 @retval FALSE check fail
1091 IN EFI_PHYSICAL_ADDRESS StmImage
,
1092 IN UINTN StmImageSize
1096 STM_HEADER
*StmHeader
;
1097 IA32_VMX_MISC_REGISTER VmxMiscMsr
;
1100 // Check to see if STM image is compatible with CPU
1102 StmHeader
= (STM_HEADER
*)(UINTN
)StmImage
;
1103 VmxMiscMsr
.Uint64
= AsmReadMsr64 (MSR_IA32_VMX_MISC
);
1104 if (StmHeader
->HwStmHdr
.MsegHeaderRevision
!= VmxMiscMsr
.Bits
.MsegRevisionIdentifier
) {
1105 DEBUG ((DEBUG_ERROR
, "STM Image not compatible with CPU\n"));
1106 DEBUG ((DEBUG_ERROR
, " StmHeader->HwStmHdr.MsegHeaderRevision = %08x\n", StmHeader
->HwStmHdr
.MsegHeaderRevision
));
1107 DEBUG ((DEBUG_ERROR
, " VmxMiscMsr.Bits.MsegRevisionIdentifier = %08x\n", VmxMiscMsr
.Bits
.MsegRevisionIdentifier
));
1112 // Get Minimal required Mseg size
1114 MinMsegSize
= (EFI_PAGES_TO_SIZE (EFI_SIZE_TO_PAGES (StmHeader
->SwStmHdr
.StaticImageSize
)) +
1115 StmHeader
->SwStmHdr
.AdditionalDynamicMemorySize
+
1116 (StmHeader
->SwStmHdr
.PerProcDynamicMemorySize
+ GetVmcsSize () * 2) * gSmst
->NumberOfCpus
);
1117 if (MinMsegSize
< StmImageSize
) {
1118 MinMsegSize
= StmImageSize
;
1121 if (StmHeader
->HwStmHdr
.Cr3Offset
>= StmHeader
->SwStmHdr
.StaticImageSize
) {
1123 // We will create page table, just in case that SINIT does not create it.
1125 if (MinMsegSize
< StmHeader
->HwStmHdr
.Cr3Offset
+ EFI_PAGES_TO_SIZE (6)) {
1126 MinMsegSize
= StmHeader
->HwStmHdr
.Cr3Offset
+ EFI_PAGES_TO_SIZE (6);
1131 // Check if it exceeds MSEG size
1133 if (MinMsegSize
> mMsegSize
) {
1134 DEBUG ((DEBUG_ERROR
, "MSEG too small. Min MSEG Size = %08x Current MSEG Size = %08x\n", MinMsegSize
, mMsegSize
));
1135 DEBUG ((DEBUG_ERROR
, " StmHeader->SwStmHdr.StaticImageSize = %08x\n", StmHeader
->SwStmHdr
.StaticImageSize
));
1136 DEBUG ((DEBUG_ERROR
, " StmHeader->SwStmHdr.AdditionalDynamicMemorySize = %08x\n", StmHeader
->SwStmHdr
.AdditionalDynamicMemorySize
));
1137 DEBUG ((DEBUG_ERROR
, " StmHeader->SwStmHdr.PerProcDynamicMemorySize = %08x\n", StmHeader
->SwStmHdr
.PerProcDynamicMemorySize
));
1138 DEBUG ((DEBUG_ERROR
, " VMCS Size = %08x\n", GetVmcsSize ()));
1139 DEBUG ((DEBUG_ERROR
, " Max CPUs = %08x\n", gSmst
->NumberOfCpus
));
1140 DEBUG ((DEBUG_ERROR
, " StmHeader->HwStmHdr.Cr3Offset = %08x\n", StmHeader
->HwStmHdr
.Cr3Offset
));
1149 Load STM image to MSEG.
1151 @param StmImage STM image
1152 @param StmImageSize STM image size
1157 IN EFI_PHYSICAL_ADDRESS StmImage
,
1158 IN UINTN StmImageSize
1161 MSR_IA32_SMM_MONITOR_CTL_REGISTER SmmMonitorCtl
;
1163 STM_HEADER
*StmHeader
;
1166 // Get MSEG base address from MSR_IA32_SMM_MONITOR_CTL
1168 SmmMonitorCtl
.Uint64
= AsmReadMsr64 (MSR_IA32_SMM_MONITOR_CTL
);
1169 MsegBase
= SmmMonitorCtl
.Bits
.MsegBase
<< 12;
1172 // Zero all of MSEG base address
1174 ZeroMem ((VOID
*)(UINTN
)MsegBase
, mMsegSize
);
1177 // Copy STM Image into MSEG
1179 CopyMem ((VOID
*)(UINTN
)MsegBase
, (VOID
*)(UINTN
)StmImage
, StmImageSize
);
1182 // STM Header is at the beginning of the STM Image
1184 StmHeader
= (STM_HEADER
*)(UINTN
)StmImage
;
1186 StmGen4GPageTable ((UINTN
)MsegBase
+ StmHeader
->HwStmHdr
.Cr3Offset
);
1191 Load STM image to MSEG.
1193 @param StmImage STM image
1194 @param StmImageSize STM image size
1196 @retval EFI_SUCCESS Load STM to MSEG successfully
1197 @retval EFI_ALREADY_STARTED STM image is already loaded to MSEG
1198 @retval EFI_BUFFER_TOO_SMALL MSEG is smaller than minimal requirement of STM image
1199 @retval EFI_UNSUPPORTED MSEG is not enabled
1205 IN EFI_PHYSICAL_ADDRESS StmImage
,
1206 IN UINTN StmImageSize
1209 MSR_IA32_SMM_MONITOR_CTL_REGISTER SmmMonitorCtl
;
1211 if (mLockLoadMonitor
) {
1212 return EFI_ACCESS_DENIED
;
1215 SmmMonitorCtl
.Uint64
= AsmReadMsr64 (MSR_IA32_SMM_MONITOR_CTL
);
1216 if (SmmMonitorCtl
.Bits
.MsegBase
== 0) {
1217 return EFI_UNSUPPORTED
;
1220 if (!StmCheckStmImage (StmImage
, StmImageSize
)) {
1221 return EFI_BUFFER_TOO_SMALL
;
1224 // Record STM_HASH to PCR 0, just in case it is NOT TXT launch, we still need provide the evidence.
1225 TpmMeasureAndLogData (
1227 TXT_EVTYPE_STM_HASH
, // EventType
1230 (VOID
*)(UINTN
)StmImage
, // HashData
1231 StmImageSize
// HashDataLen
1234 StmLoadStmImage (StmImage
, StmImageSize
);
1236 mStmState
|= EFI_SM_MONITOR_STATE_ENABLED
;
1242 This function return BIOS STM resource.
1244 Consumed by SmmMpService when Init.
1246 @return BIOS STM resource
1254 return mStmResourcesPtr
;
1258 This function notify STM resource change.
1260 @param StmResource BIOS STM resource
1264 NotifyStmResourceChange (
1269 TXT_PROCESSOR_SMM_DESCRIPTOR
*Psd
;
1271 for (Index
= 0; Index
< gSmst
->NumberOfCpus
; Index
++) {
1272 Psd
= (TXT_PROCESSOR_SMM_DESCRIPTOR
*)((UINTN
)gSmst
->CpuSaveState
[Index
] - SMRAM_SAVE_STATE_MAP_OFFSET
+ TXT_SMM_PSD_OFFSET
);
1273 Psd
->BiosHwResourceRequirementsPtr
= (UINT64
)(UINTN
)StmResource
;
1280 This is STM setup BIOS callback.
1288 mStmState
|= EFI_SM_MONITOR_STATE_ACTIVATED
;
1292 This is STM teardown BIOS callback.
1300 mStmState
&= ~EFI_SM_MONITOR_STATE_ACTIVATED
;