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/BaseMemoryLib.h>
11 #include <Library/HobLib.h>
12 #include <Library/UefiBootServicesTableLib.h>
13 #include <Library/SmmServicesTableLib.h>
14 #include <Library/TpmMeasurementLib.h>
15 #include <Register/Intel/Cpuid.h>
16 #include <Register/Intel/ArchitecturalMsr.h>
17 #include <Register/Intel/SmramSaveStateMap.h>
19 #include <Protocol/MpService.h>
21 #include "CpuFeaturesLib.h"
24 #define TXT_EVTYPE_BASE 0x400
25 #define TXT_EVTYPE_STM_HASH (TXT_EVTYPE_BASE + 14)
30 EFI_HANDLE mStmSmmCpuHandle
= NULL
;
32 BOOLEAN mLockLoadMonitor
= FALSE
;
35 // Template of STM_RSC_END structure for copying.
37 GLOBAL_REMOVE_IF_UNREFERENCED STM_RSC_END mRscEndNode
= {
38 { END_OF_RESOURCES
, sizeof (STM_RSC_END
) },
41 GLOBAL_REMOVE_IF_UNREFERENCED UINT8
*mStmResourcesPtr
= NULL
;
42 GLOBAL_REMOVE_IF_UNREFERENCED UINTN mStmResourceTotalSize
= 0x0;
43 GLOBAL_REMOVE_IF_UNREFERENCED UINTN mStmResourceSizeUsed
= 0x0;
44 GLOBAL_REMOVE_IF_UNREFERENCED UINTN mStmResourceSizeAvailable
= 0x0;
46 GLOBAL_REMOVE_IF_UNREFERENCED UINT32 mStmState
= 0;
49 // System Configuration Table pointing to STM Configuration Table
51 GLOBAL_REMOVE_IF_UNREFERENCED
52 EFI_SM_MONITOR_INIT_PROTOCOL mSmMonitorInitProtocol
= {
60 #define CPUID1_EDX_XD_SUPPORT 0x100000
63 // External global variables associated with SMI Handler Template
65 extern CONST TXT_PROCESSOR_SMM_DESCRIPTOR gcStmPsd
;
66 extern UINT32 gStmSmbase
;
67 extern volatile UINT32 gStmSmiStack
;
68 extern UINT32 gStmSmiCr3
;
69 extern volatile UINT8 gcStmSmiHandlerTemplate
[];
70 extern CONST UINT16 gcStmSmiHandlerSize
;
71 extern UINT16 gcStmSmiHandlerOffset
;
72 extern BOOLEAN gStmXdSupported
;
75 // Variables used by SMI Handler
77 IA32_DESCRIPTOR gStmSmiHandlerIdtr
;
80 // MP Services Protocol
82 EFI_MP_SERVICES_PROTOCOL
*mSmmCpuFeaturesLibMpService
= NULL
;
85 // MSEG Base and Length in SMRAM
90 BOOLEAN mStmConfigurationTableInitialized
= FALSE
;
93 The constructor function for the Traditional MM library instance with STM.
95 @param[in] ImageHandle The firmware allocated handle for the EFI image.
96 @param[in] SystemTable A pointer to the EFI System Table.
98 @retval EFI_SUCCESS The constructor always returns EFI_SUCCESS.
103 SmmCpuFeaturesLibStmConstructor (
104 IN EFI_HANDLE ImageHandle
,
105 IN EFI_SYSTEM_TABLE
*SystemTable
109 CPUID_VERSION_INFO_ECX RegEcx
;
110 EFI_HOB_GUID_TYPE
*GuidHob
;
111 EFI_SMRAM_DESCRIPTOR
*SmramDescriptor
;
114 // Initialize address fixup
116 SmmCpuFeaturesLibStmSmiEntryFixupAddress ();
119 // Perform library initialization common across all instances
121 CpuFeaturesLibInitialization ();
124 // Lookup the MP Services Protocol
126 Status
= gBS
->LocateProtocol (
127 &gEfiMpServiceProtocolGuid
,
129 (VOID
**)&mSmmCpuFeaturesLibMpService
131 ASSERT_EFI_ERROR (Status
);
134 // If CPU supports VMX, then determine SMRAM range for MSEG.
136 AsmCpuid (CPUID_VERSION_INFO
, NULL
, NULL
, &RegEcx
.Uint32
, NULL
);
137 if (RegEcx
.Bits
.VMX
== 1) {
138 GuidHob
= GetFirstGuidHob (&gMsegSmramGuid
);
139 if (GuidHob
!= NULL
) {
141 // Retrieve MSEG location from MSEG SRAM HOB
143 SmramDescriptor
= (EFI_SMRAM_DESCRIPTOR
*)GET_GUID_HOB_DATA (GuidHob
);
144 if (SmramDescriptor
->PhysicalSize
> 0) {
145 mMsegBase
= (UINTN
)SmramDescriptor
->CpuStart
;
146 mMsegSize
= (UINTN
)SmramDescriptor
->PhysicalSize
;
148 } else if (PcdGet32 (PcdCpuMsegSize
) > 0) {
150 // Allocate MSEG from SMRAM memory
152 mMsegBase
= (UINTN
)AllocatePages (EFI_SIZE_TO_PAGES (PcdGet32 (PcdCpuMsegSize
)));
154 mMsegSize
= ALIGN_VALUE (PcdGet32 (PcdCpuMsegSize
), EFI_PAGE_SIZE
);
156 DEBUG ((DEBUG_ERROR
, "Not enough SMRAM resource to allocate MSEG size %08x\n", PcdGet32 (PcdCpuMsegSize
)));
161 DEBUG ((DEBUG_INFO
, "MsegBase: 0x%08x, MsegSize: 0x%08x\n", mMsegBase
, mMsegSize
));
169 Internal worker function that is called to complete CPU initialization at the
170 end of SmmCpuFeaturesInitializeProcessor().
174 FinishSmmCpuFeaturesInitializeProcessor (
178 MSR_IA32_SMM_MONITOR_CTL_REGISTER SmmMonitorCtl
;
181 // Set MSEG Base Address in SMM Monitor Control MSR.
184 SmmMonitorCtl
.Uint64
= 0;
185 SmmMonitorCtl
.Bits
.MsegBase
= (UINT32
)mMsegBase
>> 12;
186 SmmMonitorCtl
.Bits
.Valid
= 1;
187 AsmWriteMsr64 (MSR_IA32_SMM_MONITOR_CTL
, SmmMonitorCtl
.Uint64
);
192 Return the size, in bytes, of a custom SMI Handler in bytes. If 0 is
193 returned, then a custom SMI handler is not provided by this library,
194 and the default SMI handler must be used.
196 @retval 0 Use the default SMI handler.
197 @retval > 0 Use the SMI handler installed by SmmCpuFeaturesInstallSmiHandler()
198 The caller is required to allocate enough SMRAM for each CPU to
199 support the size of the custom SMI handler.
203 SmmCpuFeaturesGetSmiHandlerSize (
207 return gcStmSmiHandlerSize
;
211 Install a custom SMI handler for the CPU specified by CpuIndex. This function
212 is only called if SmmCpuFeaturesGetSmiHandlerSize() returns a size is greater
213 than zero and is called by the CPU that was elected as monarch during System
214 Management Mode initialization.
216 @param[in] CpuIndex The index of the CPU to install the custom SMI handler.
217 The value must be between 0 and the NumberOfCpus field
218 in the System Management System Table (SMST).
219 @param[in] SmBase The SMBASE address for the CPU specified by CpuIndex.
220 @param[in] SmiStack The stack to use when an SMI is processed by the
221 the CPU specified by CpuIndex.
222 @param[in] StackSize The size, in bytes, if the stack used when an SMI is
223 processed by the CPU specified by CpuIndex.
224 @param[in] GdtBase The base address of the GDT to use when an SMI is
225 processed by the CPU specified by CpuIndex.
226 @param[in] GdtSize The size, in bytes, of the GDT used when an SMI is
227 processed by the CPU specified by CpuIndex.
228 @param[in] IdtBase The base address of the IDT to use when an SMI is
229 processed by the CPU specified by CpuIndex.
230 @param[in] IdtSize The size, in bytes, of the IDT used when an SMI is
231 processed by the CPU specified by CpuIndex.
232 @param[in] Cr3 The base address of the page tables to use when an SMI
233 is processed by the CPU specified by CpuIndex.
237 SmmCpuFeaturesInstallSmiHandler (
250 TXT_PROCESSOR_SMM_DESCRIPTOR
*Psd
;
254 EFI_PROCESSOR_INFORMATION ProcessorInfo
;
256 CopyMem ((VOID
*)((UINTN
)SmBase
+ TXT_SMM_PSD_OFFSET
), &gcStmPsd
, sizeof (gcStmPsd
));
257 Psd
= (TXT_PROCESSOR_SMM_DESCRIPTOR
*)(VOID
*)((UINTN
)SmBase
+ TXT_SMM_PSD_OFFSET
);
258 Psd
->SmmGdtPtr
= GdtBase
;
259 Psd
->SmmGdtSize
= (UINT32
)GdtSize
;
262 // Initialize values in template before copy
264 gStmSmiStack
= (UINT32
)((UINTN
)SmiStack
+ StackSize
- sizeof (UINTN
));
267 gStmSmiHandlerIdtr
.Base
= IdtBase
;
268 gStmSmiHandlerIdtr
.Limit
= (UINT16
)(IdtSize
- 1);
270 if (gStmXdSupported
) {
271 AsmCpuid (CPUID_EXTENDED_FUNCTION
, &RegEax
, NULL
, NULL
, NULL
);
272 if (RegEax
<= CPUID_EXTENDED_FUNCTION
) {
274 // Extended CPUID functions are not supported on this processor.
276 gStmXdSupported
= FALSE
;
279 AsmCpuid (CPUID_EXTENDED_CPU_SIG
, NULL
, NULL
, NULL
, &RegEdx
);
280 if ((RegEdx
& CPUID1_EDX_XD_SUPPORT
) == 0) {
282 // Execute Disable Bit feature is not supported on this processor.
284 gStmXdSupported
= FALSE
;
289 // Set the value at the top of the CPU stack to the CPU Index
291 *(UINTN
*)(UINTN
)gStmSmiStack
= CpuIndex
;
294 // Copy template to CPU specific SMI handler location
297 (VOID
*)((UINTN
)SmBase
+ SMM_HANDLER_OFFSET
),
298 (VOID
*)gcStmSmiHandlerTemplate
,
302 Psd
->SmmSmiHandlerRip
= SmBase
+ SMM_HANDLER_OFFSET
+ gcStmSmiHandlerOffset
;
303 Psd
->SmmSmiHandlerRsp
= (UINTN
)SmiStack
+ StackSize
- sizeof (UINTN
);
306 DEBUG ((DEBUG_INFO
, "CpuSmmStmExceptionStackSize - %x\n", PcdGet32 (PcdCpuSmmStmExceptionStackSize
)));
307 DEBUG ((DEBUG_INFO
, "Pages - %x\n", EFI_SIZE_TO_PAGES (PcdGet32 (PcdCpuSmmStmExceptionStackSize
))));
308 Psd
->StmProtectionExceptionHandler
.SpeRsp
= (UINT64
)(UINTN
)AllocatePages (EFI_SIZE_TO_PAGES (PcdGet32 (PcdCpuSmmStmExceptionStackSize
)));
309 Psd
->StmProtectionExceptionHandler
.SpeRsp
+= EFI_PAGES_TO_SIZE (EFI_SIZE_TO_PAGES (PcdGet32 (PcdCpuSmmStmExceptionStackSize
)));
311 Psd
->BiosHwResourceRequirementsPtr
= (UINT64
)(UINTN
)GetStmResource ();
314 // Get the APIC ID for the CPU specified by CpuIndex
316 Status
= mSmmCpuFeaturesLibMpService
->GetProcessorInfo (
317 mSmmCpuFeaturesLibMpService
,
321 ASSERT_EFI_ERROR (Status
);
323 Psd
->LocalApicId
= (UINT32
)ProcessorInfo
.ProcessorId
;
326 Hob
= GetFirstHob (EFI_HOB_TYPE_CPU
);
328 Psd
->PhysicalAddressBits
= ((EFI_HOB_CPU
*)Hob
)->SizeOfMemorySpace
;
330 AsmCpuid (0x80000000, &RegEax
, NULL
, NULL
, NULL
);
331 if (RegEax
>= 0x80000008) {
332 AsmCpuid (0x80000008, &RegEax
, NULL
, NULL
, NULL
);
333 Psd
->PhysicalAddressBits
= (UINT8
)RegEax
;
335 Psd
->PhysicalAddressBits
= 36;
339 if (!mStmConfigurationTableInitialized
) {
340 StmSmmConfigurationTableInit ();
341 mStmConfigurationTableInitialized
= TRUE
;
346 SMM End Of Dxe event notification handler.
348 STM support need patch AcpiRsdp in TXT_PROCESSOR_SMM_DESCRIPTOR.
350 @param[in] Protocol Points to the protocol's unique identifier.
351 @param[in] Interface Points to the interface instance.
352 @param[in] Handle The handle on which the interface was installed.
354 @retval EFI_SUCCESS Notification handler runs successfully.
358 SmmEndOfDxeEventNotify (
359 IN CONST EFI_GUID
*Protocol
,
366 TXT_PROCESSOR_SMM_DESCRIPTOR
*Psd
;
368 DEBUG ((DEBUG_INFO
, "SmmEndOfDxeEventNotify\n"));
371 // found ACPI table RSD_PTR from system table
374 for (Index
= 0; Index
< gST
->NumberOfTableEntries
; Index
++) {
375 if (CompareGuid (&(gST
->ConfigurationTable
[Index
].VendorGuid
), &gEfiAcpi20TableGuid
)) {
377 // A match was found.
379 Rsdp
= gST
->ConfigurationTable
[Index
].VendorTable
;
385 for (Index
= 0; Index
< gST
->NumberOfTableEntries
; Index
++) {
386 if (CompareGuid (&(gST
->ConfigurationTable
[Index
].VendorGuid
), &gEfiAcpi10TableGuid
)) {
388 // A match was found.
390 Rsdp
= gST
->ConfigurationTable
[Index
].VendorTable
;
396 for (Index
= 0; Index
< gSmst
->NumberOfCpus
; Index
++) {
397 Psd
= (TXT_PROCESSOR_SMM_DESCRIPTOR
*)((UINTN
)gSmst
->CpuSaveState
[Index
] - SMRAM_SAVE_STATE_MAP_OFFSET
+ TXT_SMM_PSD_OFFSET
);
398 DEBUG ((DEBUG_INFO
, "Index=%d Psd=%p Rsdp=%p\n", Index
, Psd
, Rsdp
));
399 Psd
->AcpiRsdp
= (UINT64
)(UINTN
)Rsdp
;
402 mLockLoadMonitor
= TRUE
;
408 This function initializes the STM configuration table.
411 StmSmmConfigurationTableInit (
418 Status
= gSmst
->SmmInstallProtocolInterface (
420 &gEfiSmMonitorInitProtocolGuid
,
421 EFI_NATIVE_INTERFACE
,
422 &mSmMonitorInitProtocol
424 ASSERT_EFI_ERROR (Status
);
428 // Register SMM End of DXE Event
430 Status
= gSmst
->SmmRegisterProtocolNotify (
431 &gEfiSmmEndOfDxeProtocolGuid
,
432 SmmEndOfDxeEventNotify
,
435 ASSERT_EFI_ERROR (Status
);
456 Handle single Resource to see if it can be merged into Record.
458 @param Resource A pointer to resource node to be added
459 @param Record A pointer to record node to be merged
461 @retval TRUE resource handled
462 @retval FALSE resource is not handled
466 HandleSingleResource (
467 IN STM_RSC
*Resource
,
482 // Calling code is responsible for making sure that
483 // Resource->Header.RscType == (*Record)->Header.RscType
484 // thus we use just one of them as switch variable.
486 switch (Resource
->Header
.RscType
) {
489 ResourceLo
= Resource
->Mem
.Base
;
490 ResourceHi
= Resource
->Mem
.Base
+ Resource
->Mem
.Length
;
491 RecordLo
= Record
->Mem
.Base
;
492 RecordHi
= Record
->Mem
.Base
+ Record
->Mem
.Length
;
493 if (Resource
->Mem
.RWXAttributes
!= Record
->Mem
.RWXAttributes
) {
494 if ((ResourceLo
== RecordLo
) && (ResourceHi
== RecordHi
)) {
495 Record
->Mem
.RWXAttributes
= Resource
->Mem
.RWXAttributes
| Record
->Mem
.RWXAttributes
;
504 case TRAPPED_IO_RANGE
:
505 ResourceLo
= (UINT64
)Resource
->Io
.Base
;
506 ResourceHi
= (UINT64
)Resource
->Io
.Base
+ (UINT64
)Resource
->Io
.Length
;
507 RecordLo
= (UINT64
)Record
->Io
.Base
;
508 RecordHi
= (UINT64
)Record
->Io
.Base
+ (UINT64
)Record
->Io
.Length
;
511 if ((Resource
->PciCfg
.OriginatingBusNumber
!= Record
->PciCfg
.OriginatingBusNumber
) ||
512 (Resource
->PciCfg
.LastNodeIndex
!= Record
->PciCfg
.LastNodeIndex
))
517 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
;
535 case MACHINE_SPECIFIC_REG
:
537 // Special case - merge MSR masks in place.
539 if (Resource
->Msr
.MsrIndex
!= Record
->Msr
.MsrIndex
) {
543 Record
->Msr
.ReadMask
|= Resource
->Msr
.ReadMask
;
544 Record
->Msr
.WriteMask
|= Resource
->Msr
.WriteMask
;
551 // If resources are disjoint
553 if ((ResourceHi
< RecordLo
) || (ResourceLo
> RecordHi
)) {
558 // If resource is consumed by record.
560 if ((ResourceLo
>= RecordLo
) && (ResourceHi
<= RecordHi
)) {
565 // Resources are overlapping.
566 // Resource and record are merged.
568 ResourceLo
= (ResourceLo
< RecordLo
) ? ResourceLo
: RecordLo
;
569 ResourceHi
= (ResourceHi
> RecordHi
) ? ResourceHi
: RecordHi
;
571 switch (Resource
->Header
.RscType
) {
574 Record
->Mem
.Base
= ResourceLo
;
575 Record
->Mem
.Length
= ResourceHi
- ResourceLo
;
578 case TRAPPED_IO_RANGE
:
579 Record
->Io
.Base
= (UINT16
)ResourceLo
;
580 Record
->Io
.Length
= (UINT16
)(ResourceHi
- ResourceLo
);
583 Record
->PciCfg
.Base
= (UINT16
)ResourceLo
;
584 Record
->PciCfg
.Length
= (UINT16
)(ResourceHi
- ResourceLo
);
597 @param Resource A pointer to resource node to be added
607 Record
= (STM_RSC
*)mStmResourcesPtr
;
610 if (Record
->Header
.RscType
== END_OF_RESOURCES
) {
615 // Go to next record if resource and record types don't match.
617 if (Resource
->Header
.RscType
!= Record
->Header
.RscType
) {
618 Record
= (STM_RSC
*)((UINTN
)Record
+ Record
->Header
.Length
);
623 // Record is handled inside of procedure - don't adjust.
625 if (HandleSingleResource (Resource
, Record
)) {
629 Record
= (STM_RSC
*)((UINTN
)Record
+ Record
->Header
.Length
);
633 // Add resource to the end of area.
636 mStmResourcesPtr
+ mStmResourceSizeUsed
- sizeof (mRscEndNode
),
638 Resource
->Header
.Length
641 mStmResourcesPtr
+ mStmResourceSizeUsed
- sizeof (mRscEndNode
) + Resource
->Header
.Length
,
645 mStmResourceSizeUsed
+= Resource
->Header
.Length
;
646 mStmResourceSizeAvailable
= mStmResourceTotalSize
- mStmResourceSizeUsed
;
655 @param ResourceList A pointer to resource list to be added
656 @param NumEntries Optional number of entries.
657 If 0, list must be terminated by END_OF_RESOURCES.
662 IN STM_RSC
*ResourceList
,
663 IN UINT32 NumEntries OPTIONAL
670 if (NumEntries
== 0) {
676 Resource
= ResourceList
;
678 for (Index
= 0; Index
< Count
; Index
++) {
679 if (Resource
->Header
.RscType
== END_OF_RESOURCES
) {
683 AddSingleResource (Resource
);
684 Resource
= (STM_RSC
*)((UINTN
)Resource
+ Resource
->Header
.Length
);
692 Validate resource list.
694 @param ResourceList A pointer to resource list to be added
695 @param NumEntries Optional number of entries.
696 If 0, list must be terminated by END_OF_RESOURCES.
698 @retval TRUE resource valid
699 @retval FALSE resource invalid
704 IN STM_RSC
*ResourceList
,
705 IN UINT32 NumEntries OPTIONAL
714 // If NumEntries == 0 make it very big. Scan will be terminated by
717 if (NumEntries
== 0) {
724 // Start from beginning of resource list.
726 Resource
= ResourceList
;
728 for (Index
= 0; Index
< Count
; Index
++) {
729 DEBUG ((DEBUG_INFO
, "ValidateResource (%d) - RscType(%x)\n", Index
, Resource
->Header
.RscType
));
731 // Validate resource.
733 switch (Resource
->Header
.RscType
) {
734 case END_OF_RESOURCES
:
735 if (Resource
->Header
.Length
!= sizeof (STM_RSC_END
)) {
740 // If we are passed actual number of resources to add,
741 // END_OF_RESOURCES structure between them is considered an
742 // error. If NumEntries == 0 END_OF_RESOURCES is a termination.
744 if (NumEntries
!= 0) {
748 // If NumEntries == 0 and list reached end - return success.
757 if (Resource
->Header
.Length
!= sizeof (STM_RSC_MEM_DESC
)) {
761 if (Resource
->Mem
.RWXAttributes
> FULL_ACCS
) {
768 case TRAPPED_IO_RANGE
:
769 if (Resource
->Header
.Length
!= sizeof (STM_RSC_IO_DESC
)) {
773 if ((Resource
->Io
.Base
+ Resource
->Io
.Length
) > 0xFFFF) {
780 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
));
781 if (Resource
->Header
.Length
!= sizeof (STM_RSC_PCI_CFG_DESC
) + (sizeof (STM_PCI_DEVICE_PATH_NODE
) * Resource
->PciCfg
.LastNodeIndex
)) {
785 for (SubIndex
= 0; SubIndex
<= Resource
->PciCfg
.LastNodeIndex
; SubIndex
++) {
786 if ((Resource
->PciCfg
.PciDevicePath
[SubIndex
].PciDevice
> 0x1F) || (Resource
->PciCfg
.PciDevicePath
[SubIndex
].PciFunction
> 7)) {
791 if ((Resource
->PciCfg
.Base
+ Resource
->PciCfg
.Length
) > 0x1000) {
797 case MACHINE_SPECIFIC_REG
:
798 if (Resource
->Header
.Length
!= sizeof (STM_RSC_MSR_DESC
)) {
805 DEBUG ((DEBUG_ERROR
, "ValidateResource - Unknown RscType(%x)\n", Resource
->Header
.RscType
));
809 Resource
= (STM_RSC
*)((UINTN
)Resource
+ Resource
->Header
.Length
);
818 EndResource is excluded.
820 @param ResourceList A pointer to resource list to be added
821 @param NumEntries Optional number of entries.
822 If 0, list must be terminated by END_OF_RESOURCES.
824 @retval TRUE resource valid
825 @retval FALSE resource invalid
830 IN STM_RSC
*ResourceList
,
831 IN UINT32 NumEntries OPTIONAL
838 Resource
= ResourceList
;
841 // If NumEntries == 0 make it very big. Scan will be terminated by
844 if (NumEntries
== 0) {
851 // Start from beginning of resource list.
853 Resource
= ResourceList
;
855 for (Index
= 0; Index
< Count
; Index
++) {
856 if (Resource
->Header
.RscType
== END_OF_RESOURCES
) {
860 Resource
= (STM_RSC
*)((UINTN
)Resource
+ Resource
->Header
.Length
);
863 return (UINTN
)Resource
- (UINTN
)ResourceList
;
868 Add resources in list to database. Allocate new memory areas as needed.
870 @param ResourceList A pointer to resource list to be added
871 @param NumEntries Optional number of entries.
872 If 0, list must be terminated by END_OF_RESOURCES.
874 @retval EFI_SUCCESS If resources are added
875 @retval EFI_INVALID_PARAMETER If nested procedure detected resource failer
876 @retval EFI_OUT_OF_RESOURCES If nested procedure returned it and we cannot allocate more areas.
882 IN STM_RSC
*ResourceList
,
883 IN UINT32 NumEntries OPTIONAL
888 EFI_PHYSICAL_ADDRESS NewResource
;
889 UINTN NewResourceSize
;
891 DEBUG ((DEBUG_INFO
, "AddPiResource - Enter\n"));
893 if (!ValidateResource (ResourceList
, NumEntries
)) {
894 return EFI_INVALID_PARAMETER
;
897 ResourceSize
= GetResourceSize (ResourceList
, NumEntries
);
898 DEBUG ((DEBUG_INFO
, "ResourceSize - 0x%08x\n", ResourceSize
));
899 if (ResourceSize
== 0) {
900 return EFI_INVALID_PARAMETER
;
903 if (mStmResourcesPtr
== NULL
) {
905 // First time allocation
907 NewResourceSize
= EFI_PAGES_TO_SIZE (EFI_SIZE_TO_PAGES (ResourceSize
+ sizeof (mRscEndNode
)));
908 DEBUG ((DEBUG_INFO
, "Allocate - 0x%08x\n", NewResourceSize
));
909 Status
= gSmst
->SmmAllocatePages (
911 EfiRuntimeServicesData
,
912 EFI_SIZE_TO_PAGES (NewResourceSize
),
915 if (EFI_ERROR (Status
)) {
920 // Copy EndResource for initialization
922 mStmResourcesPtr
= (UINT8
*)(UINTN
)NewResource
;
923 mStmResourceTotalSize
= NewResourceSize
;
924 CopyMem (mStmResourcesPtr
, &mRscEndNode
, sizeof (mRscEndNode
));
925 mStmResourceSizeUsed
= sizeof (mRscEndNode
);
926 mStmResourceSizeAvailable
= mStmResourceTotalSize
- sizeof (mRscEndNode
);
929 // Let SmmCore change resource ptr
931 NotifyStmResourceChange (mStmResourcesPtr
);
932 } else if (mStmResourceSizeAvailable
< ResourceSize
) {
936 NewResourceSize
= mStmResourceTotalSize
+ (ResourceSize
- mStmResourceSizeAvailable
);
937 NewResourceSize
= EFI_PAGES_TO_SIZE (EFI_SIZE_TO_PAGES (NewResourceSize
));
938 DEBUG ((DEBUG_INFO
, "ReAllocate - 0x%08x\n", NewResourceSize
));
939 Status
= gSmst
->SmmAllocatePages (
941 EfiRuntimeServicesData
,
942 EFI_SIZE_TO_PAGES (NewResourceSize
),
945 if (EFI_ERROR (Status
)) {
949 CopyMem ((VOID
*)(UINTN
)NewResource
, mStmResourcesPtr
, mStmResourceSizeUsed
);
950 mStmResourceSizeAvailable
= NewResourceSize
- mStmResourceSizeUsed
;
952 gSmst
->SmmFreePages (
953 (EFI_PHYSICAL_ADDRESS
)(UINTN
)mStmResourcesPtr
,
954 EFI_SIZE_TO_PAGES (mStmResourceTotalSize
)
957 mStmResourceTotalSize
= NewResourceSize
;
958 mStmResourcesPtr
= (UINT8
*)(UINTN
)NewResource
;
961 // Let SmmCore change resource ptr
963 NotifyStmResourceChange (mStmResourcesPtr
);
969 AddResource (ResourceList
, NumEntries
);
976 Delete resources in list to database.
978 @param ResourceList A pointer to resource list to be deleted
979 NULL means delete all resources.
980 @param NumEntries Optional number of entries.
981 If 0, list must be terminated by END_OF_RESOURCES.
983 @retval EFI_SUCCESS If resources are deleted
984 @retval EFI_INVALID_PARAMETER If nested procedure detected resource failer
990 IN STM_RSC
*ResourceList
,
991 IN UINT32 NumEntries OPTIONAL
994 if (ResourceList
!= NULL
) {
997 return EFI_UNSUPPORTED
;
1003 CopyMem (mStmResourcesPtr
, &mRscEndNode
, sizeof (mRscEndNode
));
1004 mStmResourceSizeUsed
= sizeof (mRscEndNode
);
1005 mStmResourceSizeAvailable
= mStmResourceTotalSize
- sizeof (mRscEndNode
);
1013 @param ResourceList A pointer to resource list to be filled
1014 @param ResourceSize On input it means size of resource list input.
1015 On output it means size of resource list filled,
1016 or the size of resource list to be filled if size of too small.
1018 @retval EFI_SUCCESS If resources are returned.
1019 @retval EFI_BUFFER_TOO_SMALL If resource list buffer is too small to hold the whole resources.
1025 OUT STM_RSC
*ResourceList
,
1026 IN OUT UINT32
*ResourceSize
1029 if (*ResourceSize
< mStmResourceSizeUsed
) {
1030 *ResourceSize
= (UINT32
)mStmResourceSizeUsed
;
1031 return EFI_BUFFER_TOO_SMALL
;
1034 CopyMem (ResourceList
, mStmResourcesPtr
, mStmResourceSizeUsed
);
1035 *ResourceSize
= (UINT32
)mStmResourceSizeUsed
;
1041 Set valid bit for MSEG MSR.
1043 @param Buffer Ap function buffer. (not used)
1052 MSR_IA32_SMM_MONITOR_CTL_REGISTER SmmMonitorCtl
;
1054 SmmMonitorCtl
.Uint64
= AsmReadMsr64 (MSR_IA32_SMM_MONITOR_CTL
);
1055 SmmMonitorCtl
.Bits
.Valid
= 1;
1056 AsmWriteMsr64 (MSR_IA32_SMM_MONITOR_CTL
, SmmMonitorCtl
.Uint64
);
1061 Get 4K page aligned VMCS size.
1063 @return 4K page aligned VMCS size
1071 MSR_IA32_VMX_BASIC_REGISTER VmxBasic
;
1074 // Read VMCS size and and align to 4KB
1076 VmxBasic
.Uint64
= AsmReadMsr64 (MSR_IA32_VMX_BASIC
);
1077 return ALIGN_VALUE (VmxBasic
.Bits
.VmcsSize
, SIZE_4KB
);
1082 Check STM image size.
1084 @param StmImage STM image
1085 @param StmImageSize STM image size
1087 @retval TRUE check pass
1088 @retval FALSE check fail
1092 IN EFI_PHYSICAL_ADDRESS StmImage
,
1093 IN UINTN StmImageSize
1097 STM_HEADER
*StmHeader
;
1098 IA32_VMX_MISC_REGISTER VmxMiscMsr
;
1101 // Check to see if STM image is compatible with CPU
1103 StmHeader
= (STM_HEADER
*)(UINTN
)StmImage
;
1104 VmxMiscMsr
.Uint64
= AsmReadMsr64 (MSR_IA32_VMX_MISC
);
1105 if (StmHeader
->HwStmHdr
.MsegHeaderRevision
!= VmxMiscMsr
.Bits
.MsegRevisionIdentifier
) {
1106 DEBUG ((DEBUG_ERROR
, "STM Image not compatible with CPU\n"));
1107 DEBUG ((DEBUG_ERROR
, " StmHeader->HwStmHdr.MsegHeaderRevision = %08x\n", StmHeader
->HwStmHdr
.MsegHeaderRevision
));
1108 DEBUG ((DEBUG_ERROR
, " VmxMiscMsr.Bits.MsegRevisionIdentifier = %08x\n", VmxMiscMsr
.Bits
.MsegRevisionIdentifier
));
1113 // Get Minimal required Mseg size
1115 MinMsegSize
= (EFI_PAGES_TO_SIZE (EFI_SIZE_TO_PAGES (StmHeader
->SwStmHdr
.StaticImageSize
)) +
1116 StmHeader
->SwStmHdr
.AdditionalDynamicMemorySize
+
1117 (StmHeader
->SwStmHdr
.PerProcDynamicMemorySize
+ GetVmcsSize () * 2) * gSmst
->NumberOfCpus
);
1118 if (MinMsegSize
< StmImageSize
) {
1119 MinMsegSize
= StmImageSize
;
1122 if (StmHeader
->HwStmHdr
.Cr3Offset
>= StmHeader
->SwStmHdr
.StaticImageSize
) {
1124 // We will create page table, just in case that SINIT does not create it.
1126 if (MinMsegSize
< StmHeader
->HwStmHdr
.Cr3Offset
+ EFI_PAGES_TO_SIZE (6)) {
1127 MinMsegSize
= StmHeader
->HwStmHdr
.Cr3Offset
+ EFI_PAGES_TO_SIZE (6);
1132 // Check if it exceeds MSEG size
1134 if (MinMsegSize
> mMsegSize
) {
1135 DEBUG ((DEBUG_ERROR
, "MSEG too small. Min MSEG Size = %08x Current MSEG Size = %08x\n", MinMsegSize
, mMsegSize
));
1136 DEBUG ((DEBUG_ERROR
, " StmHeader->SwStmHdr.StaticImageSize = %08x\n", StmHeader
->SwStmHdr
.StaticImageSize
));
1137 DEBUG ((DEBUG_ERROR
, " StmHeader->SwStmHdr.AdditionalDynamicMemorySize = %08x\n", StmHeader
->SwStmHdr
.AdditionalDynamicMemorySize
));
1138 DEBUG ((DEBUG_ERROR
, " StmHeader->SwStmHdr.PerProcDynamicMemorySize = %08x\n", StmHeader
->SwStmHdr
.PerProcDynamicMemorySize
));
1139 DEBUG ((DEBUG_ERROR
, " VMCS Size = %08x\n", GetVmcsSize ()));
1140 DEBUG ((DEBUG_ERROR
, " Max CPUs = %08x\n", gSmst
->NumberOfCpus
));
1141 DEBUG ((DEBUG_ERROR
, " StmHeader->HwStmHdr.Cr3Offset = %08x\n", StmHeader
->HwStmHdr
.Cr3Offset
));
1150 Load STM image to MSEG.
1152 @param StmImage STM image
1153 @param StmImageSize STM image size
1158 IN EFI_PHYSICAL_ADDRESS StmImage
,
1159 IN UINTN StmImageSize
1162 MSR_IA32_SMM_MONITOR_CTL_REGISTER SmmMonitorCtl
;
1164 STM_HEADER
*StmHeader
;
1167 // Get MSEG base address from MSR_IA32_SMM_MONITOR_CTL
1169 SmmMonitorCtl
.Uint64
= AsmReadMsr64 (MSR_IA32_SMM_MONITOR_CTL
);
1170 MsegBase
= SmmMonitorCtl
.Bits
.MsegBase
<< 12;
1173 // Zero all of MSEG base address
1175 ZeroMem ((VOID
*)(UINTN
)MsegBase
, mMsegSize
);
1178 // Copy STM Image into MSEG
1180 CopyMem ((VOID
*)(UINTN
)MsegBase
, (VOID
*)(UINTN
)StmImage
, StmImageSize
);
1183 // STM Header is at the beginning of the STM Image
1185 StmHeader
= (STM_HEADER
*)(UINTN
)StmImage
;
1187 StmGen4GPageTable ((UINTN
)MsegBase
+ StmHeader
->HwStmHdr
.Cr3Offset
);
1192 Load STM image to MSEG.
1194 @param StmImage STM image
1195 @param StmImageSize STM image size
1197 @retval EFI_SUCCESS Load STM to MSEG successfully
1198 @retval EFI_ALREADY_STARTED STM image is already loaded to MSEG
1199 @retval EFI_BUFFER_TOO_SMALL MSEG is smaller than minimal requirement of STM image
1200 @retval EFI_UNSUPPORTED MSEG is not enabled
1206 IN EFI_PHYSICAL_ADDRESS StmImage
,
1207 IN UINTN StmImageSize
1210 MSR_IA32_SMM_MONITOR_CTL_REGISTER SmmMonitorCtl
;
1212 if (mLockLoadMonitor
) {
1213 return EFI_ACCESS_DENIED
;
1216 SmmMonitorCtl
.Uint64
= AsmReadMsr64 (MSR_IA32_SMM_MONITOR_CTL
);
1217 if (SmmMonitorCtl
.Bits
.MsegBase
== 0) {
1218 return EFI_UNSUPPORTED
;
1221 if (!StmCheckStmImage (StmImage
, StmImageSize
)) {
1222 return EFI_BUFFER_TOO_SMALL
;
1225 // Record STM_HASH to PCR 0, just in case it is NOT TXT launch, we still need provide the evidence.
1226 TpmMeasureAndLogData (
1228 TXT_EVTYPE_STM_HASH
, // EventType
1231 (VOID
*)(UINTN
)StmImage
, // HashData
1232 StmImageSize
// HashDataLen
1235 StmLoadStmImage (StmImage
, StmImageSize
);
1237 mStmState
|= EFI_SM_MONITOR_STATE_ENABLED
;
1243 This function return BIOS STM resource.
1245 Consumed by SmmMpService when Init.
1247 @return BIOS STM resource
1255 return mStmResourcesPtr
;
1259 This function notify STM resource change.
1261 @param StmResource BIOS STM resource
1265 NotifyStmResourceChange (
1270 TXT_PROCESSOR_SMM_DESCRIPTOR
*Psd
;
1272 for (Index
= 0; Index
< gSmst
->NumberOfCpus
; Index
++) {
1273 Psd
= (TXT_PROCESSOR_SMM_DESCRIPTOR
*)((UINTN
)gSmst
->CpuSaveState
[Index
] - SMRAM_SAVE_STATE_MAP_OFFSET
+ TXT_SMM_PSD_OFFSET
);
1274 Psd
->BiosHwResourceRequirementsPtr
= (UINT64
)(UINTN
)StmResource
;
1281 This is STM setup BIOS callback.
1289 mStmState
|= EFI_SM_MONITOR_STATE_ACTIVATED
;
1293 This is STM teardown BIOS callback.
1301 mStmState
&= ~EFI_SM_MONITOR_STATE_ACTIVATED
;