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
= {
63 #define CPUID1_EDX_XD_SUPPORT 0x100000
66 // External global variables associated with SMI Handler Template
68 extern CONST TXT_PROCESSOR_SMM_DESCRIPTOR gcStmPsd
;
69 extern UINT32 gStmSmbase
;
70 extern volatile UINT32 gStmSmiStack
;
71 extern UINT32 gStmSmiCr3
;
72 extern volatile UINT8 gcStmSmiHandlerTemplate
[];
73 extern CONST UINT16 gcStmSmiHandlerSize
;
74 extern UINT16 gcStmSmiHandlerOffset
;
75 extern BOOLEAN gStmXdSupported
;
78 // Variables used by SMI Handler
80 IA32_DESCRIPTOR gStmSmiHandlerIdtr
;
83 // MP Services Protocol
85 EFI_MP_SERVICES_PROTOCOL
*mSmmCpuFeaturesLibMpService
= NULL
;
88 // MSEG Base and Length in SMRAM
93 BOOLEAN mStmConfigurationTableInitialized
= FALSE
;
96 The constructor function for the Traditional MM library instance with STM.
98 @param[in] ImageHandle The firmware allocated handle for the EFI image.
99 @param[in] SystemTable A pointer to the EFI System Table.
101 @retval EFI_SUCCESS The constructor always returns EFI_SUCCESS.
106 SmmCpuFeaturesLibStmConstructor (
107 IN EFI_HANDLE ImageHandle
,
108 IN EFI_SYSTEM_TABLE
*SystemTable
112 CPUID_VERSION_INFO_ECX RegEcx
;
113 EFI_HOB_GUID_TYPE
*GuidHob
;
114 EFI_SMRAM_DESCRIPTOR
*SmramDescriptor
;
117 // Initialize address fixup
119 SmmCpuFeaturesLibStmSmiEntryFixupAddress ();
122 // Perform library initialization common across all instances
124 CpuFeaturesLibInitialization ();
127 // Lookup the MP Services Protocol
129 Status
= gBS
->LocateProtocol (
130 &gEfiMpServiceProtocolGuid
,
132 (VOID
**)&mSmmCpuFeaturesLibMpService
134 ASSERT_EFI_ERROR (Status
);
137 // If CPU supports VMX, then determine SMRAM range for MSEG.
139 AsmCpuid (CPUID_VERSION_INFO
, NULL
, NULL
, &RegEcx
.Uint32
, NULL
);
140 if (RegEcx
.Bits
.VMX
== 1) {
141 GuidHob
= GetFirstGuidHob (&gMsegSmramGuid
);
142 if (GuidHob
!= NULL
) {
144 // Retrieve MSEG location from MSEG SRAM HOB
146 SmramDescriptor
= (EFI_SMRAM_DESCRIPTOR
*)GET_GUID_HOB_DATA (GuidHob
);
147 if (SmramDescriptor
->PhysicalSize
> 0) {
148 mMsegBase
= (UINTN
)SmramDescriptor
->CpuStart
;
149 mMsegSize
= (UINTN
)SmramDescriptor
->PhysicalSize
;
151 } else if (PcdGet32 (PcdCpuMsegSize
) > 0) {
153 // Allocate MSEG from SMRAM memory
155 mMsegBase
= (UINTN
)AllocatePages (EFI_SIZE_TO_PAGES (PcdGet32 (PcdCpuMsegSize
)));
157 mMsegSize
= ALIGN_VALUE (PcdGet32 (PcdCpuMsegSize
), EFI_PAGE_SIZE
);
159 DEBUG ((DEBUG_ERROR
, "Not enough SMRAM resource to allocate MSEG size %08x\n", PcdGet32 (PcdCpuMsegSize
)));
164 DEBUG ((DEBUG_INFO
, "MsegBase: 0x%08x, MsegSize: 0x%08x\n", mMsegBase
, mMsegSize
));
172 Internal worker function that is called to complete CPU initialization at the
173 end of SmmCpuFeaturesInitializeProcessor().
177 FinishSmmCpuFeaturesInitializeProcessor (
181 MSR_IA32_SMM_MONITOR_CTL_REGISTER SmmMonitorCtl
;
184 // Set MSEG Base Address in SMM Monitor Control MSR.
187 SmmMonitorCtl
.Uint64
= 0;
188 SmmMonitorCtl
.Bits
.MsegBase
= (UINT32
)mMsegBase
>> 12;
189 SmmMonitorCtl
.Bits
.Valid
= 1;
190 AsmWriteMsr64 (MSR_IA32_SMM_MONITOR_CTL
, SmmMonitorCtl
.Uint64
);
195 Return the size, in bytes, of a custom SMI Handler in bytes. If 0 is
196 returned, then a custom SMI handler is not provided by this library,
197 and the default SMI handler must be used.
199 @retval 0 Use the default SMI handler.
200 @retval > 0 Use the SMI handler installed by SmmCpuFeaturesInstallSmiHandler()
201 The caller is required to allocate enough SMRAM for each CPU to
202 support the size of the custom SMI handler.
206 SmmCpuFeaturesGetSmiHandlerSize (
210 return gcStmSmiHandlerSize
;
214 Install a custom SMI handler for the CPU specified by CpuIndex. This function
215 is only called if SmmCpuFeaturesGetSmiHandlerSize() returns a size is greater
216 than zero and is called by the CPU that was elected as monarch during System
217 Management Mode initialization.
219 @param[in] CpuIndex The index of the CPU to install the custom SMI handler.
220 The value must be between 0 and the NumberOfCpus field
221 in the System Management System Table (SMST).
222 @param[in] SmBase The SMBASE address for the CPU specified by CpuIndex.
223 @param[in] SmiStack The stack to use when an SMI is processed by the
224 the CPU specified by CpuIndex.
225 @param[in] StackSize The size, in bytes, if the stack used when an SMI is
226 processed by the CPU specified by CpuIndex.
227 @param[in] GdtBase The base address of the GDT to use when an SMI is
228 processed by the CPU specified by CpuIndex.
229 @param[in] GdtSize The size, in bytes, of the GDT used when an SMI is
230 processed by the CPU specified by CpuIndex.
231 @param[in] IdtBase The base address of the IDT to use when an SMI is
232 processed by the CPU specified by CpuIndex.
233 @param[in] IdtSize The size, in bytes, of the IDT used when an SMI is
234 processed by the CPU specified by CpuIndex.
235 @param[in] Cr3 The base address of the page tables to use when an SMI
236 is processed by the CPU specified by CpuIndex.
240 SmmCpuFeaturesInstallSmiHandler (
253 TXT_PROCESSOR_SMM_DESCRIPTOR
*Psd
;
257 EFI_PROCESSOR_INFORMATION ProcessorInfo
;
259 CopyMem ((VOID
*)((UINTN
)SmBase
+ TXT_SMM_PSD_OFFSET
), &gcStmPsd
, sizeof (gcStmPsd
));
260 Psd
= (TXT_PROCESSOR_SMM_DESCRIPTOR
*)(VOID
*)((UINTN
)SmBase
+ TXT_SMM_PSD_OFFSET
);
261 Psd
->SmmGdtPtr
= GdtBase
;
262 Psd
->SmmGdtSize
= (UINT32
)GdtSize
;
265 // Initialize values in template before copy
267 gStmSmiStack
= (UINT32
)((UINTN
)SmiStack
+ StackSize
- sizeof (UINTN
));
270 gStmSmiHandlerIdtr
.Base
= IdtBase
;
271 gStmSmiHandlerIdtr
.Limit
= (UINT16
)(IdtSize
- 1);
273 if (gStmXdSupported
) {
274 AsmCpuid (CPUID_EXTENDED_FUNCTION
, &RegEax
, NULL
, NULL
, NULL
);
275 if (RegEax
<= CPUID_EXTENDED_FUNCTION
) {
277 // Extended CPUID functions are not supported on this processor.
279 gStmXdSupported
= FALSE
;
282 AsmCpuid (CPUID_EXTENDED_CPU_SIG
, NULL
, NULL
, NULL
, &RegEdx
);
283 if ((RegEdx
& CPUID1_EDX_XD_SUPPORT
) == 0) {
285 // Execute Disable Bit feature is not supported on this processor.
287 gStmXdSupported
= FALSE
;
292 // Set the value at the top of the CPU stack to the CPU Index
294 *(UINTN
*)(UINTN
)gStmSmiStack
= CpuIndex
;
297 // Copy template to CPU specific SMI handler location
300 (VOID
*)((UINTN
)SmBase
+ SMM_HANDLER_OFFSET
),
301 (VOID
*)gcStmSmiHandlerTemplate
,
305 Psd
->SmmSmiHandlerRip
= SmBase
+ SMM_HANDLER_OFFSET
+ gcStmSmiHandlerOffset
;
306 Psd
->SmmSmiHandlerRsp
= (UINTN
)SmiStack
+ StackSize
- sizeof (UINTN
);
309 DEBUG ((DEBUG_INFO
, "CpuSmmStmExceptionStackSize - %x\n", PcdGet32 (PcdCpuSmmStmExceptionStackSize
)));
310 DEBUG ((DEBUG_INFO
, "Pages - %x\n", EFI_SIZE_TO_PAGES (PcdGet32 (PcdCpuSmmStmExceptionStackSize
))));
311 Psd
->StmProtectionExceptionHandler
.SpeRsp
= (UINT64
)(UINTN
)AllocatePages (EFI_SIZE_TO_PAGES (PcdGet32 (PcdCpuSmmStmExceptionStackSize
)));
312 Psd
->StmProtectionExceptionHandler
.SpeRsp
+= EFI_PAGES_TO_SIZE (EFI_SIZE_TO_PAGES (PcdGet32 (PcdCpuSmmStmExceptionStackSize
)));
314 Psd
->BiosHwResourceRequirementsPtr
= (UINT64
)(UINTN
)GetStmResource ();
317 // Get the APIC ID for the CPU specified by CpuIndex
319 Status
= mSmmCpuFeaturesLibMpService
->GetProcessorInfo (
320 mSmmCpuFeaturesLibMpService
,
324 ASSERT_EFI_ERROR (Status
);
326 Psd
->LocalApicId
= (UINT32
)ProcessorInfo
.ProcessorId
;
329 Hob
= GetFirstHob (EFI_HOB_TYPE_CPU
);
331 Psd
->PhysicalAddressBits
= ((EFI_HOB_CPU
*)Hob
)->SizeOfMemorySpace
;
333 AsmCpuid (0x80000000, &RegEax
, NULL
, NULL
, NULL
);
334 if (RegEax
>= 0x80000008) {
335 AsmCpuid (0x80000008, &RegEax
, NULL
, NULL
, NULL
);
336 Psd
->PhysicalAddressBits
= (UINT8
)RegEax
;
338 Psd
->PhysicalAddressBits
= 36;
342 if (!mStmConfigurationTableInitialized
) {
343 StmSmmConfigurationTableInit ();
344 mStmConfigurationTableInitialized
= TRUE
;
349 SMM End Of Dxe event notification handler.
351 STM support need patch AcpiRsdp in TXT_PROCESSOR_SMM_DESCRIPTOR.
353 @param[in] Protocol Points to the protocol's unique identifier.
354 @param[in] Interface Points to the interface instance.
355 @param[in] Handle The handle on which the interface was installed.
357 @retval EFI_SUCCESS Notification handler runs successfully.
361 SmmEndOfDxeEventNotify (
362 IN CONST EFI_GUID
*Protocol
,
369 TXT_PROCESSOR_SMM_DESCRIPTOR
*Psd
;
371 DEBUG ((DEBUG_INFO
, "SmmEndOfDxeEventNotify\n"));
374 // found ACPI table RSD_PTR from system table
377 for (Index
= 0; Index
< gST
->NumberOfTableEntries
; Index
++) {
378 if (CompareGuid (&(gST
->ConfigurationTable
[Index
].VendorGuid
), &gEfiAcpi20TableGuid
)) {
380 // A match was found.
382 Rsdp
= gST
->ConfigurationTable
[Index
].VendorTable
;
388 for (Index
= 0; Index
< gST
->NumberOfTableEntries
; Index
++) {
389 if (CompareGuid (&(gST
->ConfigurationTable
[Index
].VendorGuid
), &gEfiAcpi10TableGuid
)) {
391 // A match was found.
393 Rsdp
= gST
->ConfigurationTable
[Index
].VendorTable
;
399 for (Index
= 0; Index
< gSmst
->NumberOfCpus
; Index
++) {
400 Psd
= (TXT_PROCESSOR_SMM_DESCRIPTOR
*)((UINTN
)gSmst
->CpuSaveState
[Index
] - SMRAM_SAVE_STATE_MAP_OFFSET
+ TXT_SMM_PSD_OFFSET
);
401 DEBUG ((DEBUG_INFO
, "Index=%d Psd=%p Rsdp=%p\n", Index
, Psd
, Rsdp
));
402 Psd
->AcpiRsdp
= (UINT64
)(UINTN
)Rsdp
;
405 mLockLoadMonitor
= TRUE
;
411 This function initializes the STM configuration table.
414 StmSmmConfigurationTableInit (
421 Status
= gSmst
->SmmInstallProtocolInterface (
423 &gEfiSmMonitorInitProtocolGuid
,
424 EFI_NATIVE_INTERFACE
,
425 &mSmMonitorInitProtocol
427 ASSERT_EFI_ERROR (Status
);
431 // Register SMM End of DXE Event
433 Status
= gSmst
->SmmRegisterProtocolNotify (
434 &gEfiSmmEndOfDxeProtocolGuid
,
435 SmmEndOfDxeEventNotify
,
438 ASSERT_EFI_ERROR (Status
);
459 Handle single Resource to see if it can be merged into Record.
461 @param Resource A pointer to resource node to be added
462 @param Record A pointer to record node to be merged
464 @retval TRUE resource handled
465 @retval FALSE resource is not handled
469 HandleSingleResource (
470 IN STM_RSC
*Resource
,
485 // Calling code is responsible for making sure that
486 // Resource->Header.RscType == (*Record)->Header.RscType
487 // thus we use just one of them as switch variable.
489 switch (Resource
->Header
.RscType
) {
492 ResourceLo
= Resource
->Mem
.Base
;
493 ResourceHi
= Resource
->Mem
.Base
+ Resource
->Mem
.Length
;
494 RecordLo
= Record
->Mem
.Base
;
495 RecordHi
= Record
->Mem
.Base
+ Record
->Mem
.Length
;
496 if (Resource
->Mem
.RWXAttributes
!= Record
->Mem
.RWXAttributes
) {
497 if ((ResourceLo
== RecordLo
) && (ResourceHi
== RecordHi
)) {
498 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
))
520 if (CompareMem (Resource
->PciCfg
.PciDevicePath
, Record
->PciCfg
.PciDevicePath
, sizeof (STM_PCI_DEVICE_PATH_NODE
) * (Resource
->PciCfg
.LastNodeIndex
+ 1)) != 0) {
524 ResourceLo
= (UINT64
)Resource
->PciCfg
.Base
;
525 ResourceHi
= (UINT64
)Resource
->PciCfg
.Base
+ (UINT64
)Resource
->PciCfg
.Length
;
526 RecordLo
= (UINT64
)Record
->PciCfg
.Base
;
527 RecordHi
= (UINT64
)Record
->PciCfg
.Base
+ (UINT64
)Record
->PciCfg
.Length
;
528 if (Resource
->PciCfg
.RWAttributes
!= Record
->PciCfg
.RWAttributes
) {
529 if ((ResourceLo
== RecordLo
) && (ResourceHi
== RecordHi
)) {
530 Record
->PciCfg
.RWAttributes
= Resource
->PciCfg
.RWAttributes
| Record
->PciCfg
.RWAttributes
;
538 case MACHINE_SPECIFIC_REG
:
540 // Special case - merge MSR masks in place.
542 if (Resource
->Msr
.MsrIndex
!= Record
->Msr
.MsrIndex
) {
546 Record
->Msr
.ReadMask
|= Resource
->Msr
.ReadMask
;
547 Record
->Msr
.WriteMask
|= Resource
->Msr
.WriteMask
;
554 // If resources are disjoint
556 if ((ResourceHi
< RecordLo
) || (ResourceLo
> RecordHi
)) {
561 // If resource is consumed by record.
563 if ((ResourceLo
>= RecordLo
) && (ResourceHi
<= RecordHi
)) {
568 // Resources are overlapping.
569 // Resource and record are merged.
571 ResourceLo
= (ResourceLo
< RecordLo
) ? ResourceLo
: RecordLo
;
572 ResourceHi
= (ResourceHi
> RecordHi
) ? ResourceHi
: RecordHi
;
574 switch (Resource
->Header
.RscType
) {
577 Record
->Mem
.Base
= ResourceLo
;
578 Record
->Mem
.Length
= ResourceHi
- ResourceLo
;
581 case TRAPPED_IO_RANGE
:
582 Record
->Io
.Base
= (UINT16
)ResourceLo
;
583 Record
->Io
.Length
= (UINT16
)(ResourceHi
- ResourceLo
);
586 Record
->PciCfg
.Base
= (UINT16
)ResourceLo
;
587 Record
->PciCfg
.Length
= (UINT16
)(ResourceHi
- ResourceLo
);
600 @param Resource A pointer to resource node to be added
610 Record
= (STM_RSC
*)mStmResourcesPtr
;
613 if (Record
->Header
.RscType
== END_OF_RESOURCES
) {
618 // Go to next record if resource and record types don't match.
620 if (Resource
->Header
.RscType
!= Record
->Header
.RscType
) {
621 Record
= (STM_RSC
*)((UINTN
)Record
+ Record
->Header
.Length
);
626 // Record is handled inside of procedure - don't adjust.
628 if (HandleSingleResource (Resource
, Record
)) {
632 Record
= (STM_RSC
*)((UINTN
)Record
+ Record
->Header
.Length
);
636 // Add resource to the end of area.
639 mStmResourcesPtr
+ mStmResourceSizeUsed
- sizeof (mRscEndNode
),
641 Resource
->Header
.Length
644 mStmResourcesPtr
+ mStmResourceSizeUsed
- sizeof (mRscEndNode
) + Resource
->Header
.Length
,
648 mStmResourceSizeUsed
+= Resource
->Header
.Length
;
649 mStmResourceSizeAvailable
= mStmResourceTotalSize
- mStmResourceSizeUsed
;
658 @param ResourceList A pointer to resource list to be added
659 @param NumEntries Optional number of entries.
660 If 0, list must be terminated by END_OF_RESOURCES.
665 IN STM_RSC
*ResourceList
,
666 IN UINT32 NumEntries OPTIONAL
673 if (NumEntries
== 0) {
679 Resource
= ResourceList
;
681 for (Index
= 0; Index
< Count
; Index
++) {
682 if (Resource
->Header
.RscType
== END_OF_RESOURCES
) {
686 AddSingleResource (Resource
);
687 Resource
= (STM_RSC
*)((UINTN
)Resource
+ Resource
->Header
.Length
);
695 Validate resource list.
697 @param ResourceList A pointer to resource list to be added
698 @param NumEntries Optional number of entries.
699 If 0, list must be terminated by END_OF_RESOURCES.
701 @retval TRUE resource valid
702 @retval FALSE resource invalid
707 IN STM_RSC
*ResourceList
,
708 IN UINT32 NumEntries OPTIONAL
717 // If NumEntries == 0 make it very big. Scan will be terminated by
720 if (NumEntries
== 0) {
727 // Start from beginning of resource list.
729 Resource
= ResourceList
;
731 for (Index
= 0; Index
< Count
; Index
++) {
732 DEBUG ((DEBUG_INFO
, "ValidateResource (%d) - RscType(%x)\n", Index
, Resource
->Header
.RscType
));
734 // Validate resource.
736 switch (Resource
->Header
.RscType
) {
737 case END_OF_RESOURCES
:
738 if (Resource
->Header
.Length
!= sizeof (STM_RSC_END
)) {
743 // If we are passed actual number of resources to add,
744 // END_OF_RESOURCES structure between them is considered an
745 // error. If NumEntries == 0 END_OF_RESOURCES is a termination.
747 if (NumEntries
!= 0) {
751 // If NumEntries == 0 and list reached end - return success.
760 if (Resource
->Header
.Length
!= sizeof (STM_RSC_MEM_DESC
)) {
764 if (Resource
->Mem
.RWXAttributes
> FULL_ACCS
) {
771 case TRAPPED_IO_RANGE
:
772 if (Resource
->Header
.Length
!= sizeof (STM_RSC_IO_DESC
)) {
776 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
)) {
788 for (SubIndex
= 0; SubIndex
<= Resource
->PciCfg
.LastNodeIndex
; SubIndex
++) {
789 if ((Resource
->PciCfg
.PciDevicePath
[SubIndex
].PciDevice
> 0x1F) || (Resource
->PciCfg
.PciDevicePath
[SubIndex
].PciFunction
> 7)) {
794 if ((Resource
->PciCfg
.Base
+ Resource
->PciCfg
.Length
) > 0x1000) {
800 case MACHINE_SPECIFIC_REG
:
801 if (Resource
->Header
.Length
!= sizeof (STM_RSC_MSR_DESC
)) {
808 DEBUG ((DEBUG_ERROR
, "ValidateResource - Unknown RscType(%x)\n", Resource
->Header
.RscType
));
812 Resource
= (STM_RSC
*)((UINTN
)Resource
+ Resource
->Header
.Length
);
821 EndResource is excluded.
823 @param ResourceList A pointer to resource list to be added
824 @param NumEntries Optional number of entries.
825 If 0, list must be terminated by END_OF_RESOURCES.
827 @retval TRUE resource valid
828 @retval FALSE resource invalid
833 IN STM_RSC
*ResourceList
,
834 IN UINT32 NumEntries OPTIONAL
841 Resource
= ResourceList
;
844 // If NumEntries == 0 make it very big. Scan will be terminated by
847 if (NumEntries
== 0) {
854 // Start from beginning of resource list.
856 Resource
= ResourceList
;
858 for (Index
= 0; Index
< Count
; Index
++) {
859 if (Resource
->Header
.RscType
== END_OF_RESOURCES
) {
863 Resource
= (STM_RSC
*)((UINTN
)Resource
+ Resource
->Header
.Length
);
866 return (UINTN
)Resource
- (UINTN
)ResourceList
;
871 Add resources in list to database. Allocate new memory areas as needed.
873 @param ResourceList A pointer to resource list to be added
874 @param NumEntries Optional number of entries.
875 If 0, list must be terminated by END_OF_RESOURCES.
877 @retval EFI_SUCCESS If resources are added
878 @retval EFI_INVALID_PARAMETER If nested procedure detected resource failer
879 @retval EFI_OUT_OF_RESOURCES If nested procedure returned it and we cannot allocate more areas.
885 IN STM_RSC
*ResourceList
,
886 IN UINT32 NumEntries OPTIONAL
891 EFI_PHYSICAL_ADDRESS NewResource
;
892 UINTN NewResourceSize
;
894 DEBUG ((DEBUG_INFO
, "AddPiResource - Enter\n"));
896 if (!ValidateResource (ResourceList
, NumEntries
)) {
897 return EFI_INVALID_PARAMETER
;
900 ResourceSize
= GetResourceSize (ResourceList
, NumEntries
);
901 DEBUG ((DEBUG_INFO
, "ResourceSize - 0x%08x\n", ResourceSize
));
902 if (ResourceSize
== 0) {
903 return EFI_INVALID_PARAMETER
;
906 if (mStmResourcesPtr
== NULL
) {
908 // First time allocation
910 NewResourceSize
= EFI_PAGES_TO_SIZE (EFI_SIZE_TO_PAGES (ResourceSize
+ sizeof (mRscEndNode
)));
911 DEBUG ((DEBUG_INFO
, "Allocate - 0x%08x\n", NewResourceSize
));
912 Status
= gSmst
->SmmAllocatePages (
914 EfiRuntimeServicesData
,
915 EFI_SIZE_TO_PAGES (NewResourceSize
),
918 if (EFI_ERROR (Status
)) {
923 // Copy EndResource for initialization
925 mStmResourcesPtr
= (UINT8
*)(UINTN
)NewResource
;
926 mStmResourceTotalSize
= NewResourceSize
;
927 CopyMem (mStmResourcesPtr
, &mRscEndNode
, sizeof (mRscEndNode
));
928 mStmResourceSizeUsed
= sizeof (mRscEndNode
);
929 mStmResourceSizeAvailable
= mStmResourceTotalSize
- sizeof (mRscEndNode
);
932 // Let SmmCore change resource ptr
934 NotifyStmResourceChange (mStmResourcesPtr
);
935 } else if (mStmResourceSizeAvailable
< ResourceSize
) {
939 NewResourceSize
= mStmResourceTotalSize
+ (ResourceSize
- mStmResourceSizeAvailable
);
940 NewResourceSize
= EFI_PAGES_TO_SIZE (EFI_SIZE_TO_PAGES (NewResourceSize
));
941 DEBUG ((DEBUG_INFO
, "ReAllocate - 0x%08x\n", NewResourceSize
));
942 Status
= gSmst
->SmmAllocatePages (
944 EfiRuntimeServicesData
,
945 EFI_SIZE_TO_PAGES (NewResourceSize
),
948 if (EFI_ERROR (Status
)) {
952 CopyMem ((VOID
*)(UINTN
)NewResource
, mStmResourcesPtr
, mStmResourceSizeUsed
);
953 mStmResourceSizeAvailable
= NewResourceSize
- mStmResourceSizeUsed
;
955 gSmst
->SmmFreePages (
956 (EFI_PHYSICAL_ADDRESS
)(UINTN
)mStmResourcesPtr
,
957 EFI_SIZE_TO_PAGES (mStmResourceTotalSize
)
960 mStmResourceTotalSize
= NewResourceSize
;
961 mStmResourcesPtr
= (UINT8
*)(UINTN
)NewResource
;
964 // Let SmmCore change resource ptr
966 NotifyStmResourceChange (mStmResourcesPtr
);
972 AddResource (ResourceList
, NumEntries
);
979 Delete resources in list to database.
981 @param ResourceList A pointer to resource list to be deleted
982 NULL means delete all resources.
983 @param NumEntries Optional number of entries.
984 If 0, list must be terminated by END_OF_RESOURCES.
986 @retval EFI_SUCCESS If resources are deleted
987 @retval EFI_INVALID_PARAMETER If nested procedure detected resource failer
993 IN STM_RSC
*ResourceList
,
994 IN UINT32 NumEntries OPTIONAL
997 if (ResourceList
!= NULL
) {
1000 return EFI_UNSUPPORTED
;
1006 CopyMem (mStmResourcesPtr
, &mRscEndNode
, sizeof (mRscEndNode
));
1007 mStmResourceSizeUsed
= sizeof (mRscEndNode
);
1008 mStmResourceSizeAvailable
= mStmResourceTotalSize
- sizeof (mRscEndNode
);
1016 @param ResourceList A pointer to resource list to be filled
1017 @param ResourceSize On input it means size of resource list input.
1018 On output it means size of resource list filled,
1019 or the size of resource list to be filled if size of too small.
1021 @retval EFI_SUCCESS If resources are returned.
1022 @retval EFI_BUFFER_TOO_SMALL If resource list buffer is too small to hold the whole resources.
1028 OUT STM_RSC
*ResourceList
,
1029 IN OUT UINT32
*ResourceSize
1032 if (*ResourceSize
< mStmResourceSizeUsed
) {
1033 *ResourceSize
= (UINT32
)mStmResourceSizeUsed
;
1034 return EFI_BUFFER_TOO_SMALL
;
1037 CopyMem (ResourceList
, mStmResourcesPtr
, mStmResourceSizeUsed
);
1038 *ResourceSize
= (UINT32
)mStmResourceSizeUsed
;
1044 Set valid bit for MSEG MSR.
1046 @param Buffer Ap function buffer. (not used)
1055 MSR_IA32_SMM_MONITOR_CTL_REGISTER SmmMonitorCtl
;
1057 SmmMonitorCtl
.Uint64
= AsmReadMsr64 (MSR_IA32_SMM_MONITOR_CTL
);
1058 SmmMonitorCtl
.Bits
.Valid
= 1;
1059 AsmWriteMsr64 (MSR_IA32_SMM_MONITOR_CTL
, SmmMonitorCtl
.Uint64
);
1064 Get 4K page aligned VMCS size.
1066 @return 4K page aligned VMCS size
1074 MSR_IA32_VMX_BASIC_REGISTER VmxBasic
;
1077 // Read VMCS size and and align to 4KB
1079 VmxBasic
.Uint64
= AsmReadMsr64 (MSR_IA32_VMX_BASIC
);
1080 return ALIGN_VALUE (VmxBasic
.Bits
.VmcsSize
, SIZE_4KB
);
1085 Check STM image size.
1087 @param StmImage STM image
1088 @param StmImageSize STM image size
1090 @retval TRUE check pass
1091 @retval FALSE check fail
1095 IN EFI_PHYSICAL_ADDRESS StmImage
,
1096 IN UINTN StmImageSize
1100 STM_HEADER
*StmHeader
;
1101 IA32_VMX_MISC_REGISTER VmxMiscMsr
;
1104 // Check to see if STM image is compatible with CPU
1106 StmHeader
= (STM_HEADER
*)(UINTN
)StmImage
;
1107 VmxMiscMsr
.Uint64
= AsmReadMsr64 (MSR_IA32_VMX_MISC
);
1108 if (StmHeader
->HwStmHdr
.MsegHeaderRevision
!= VmxMiscMsr
.Bits
.MsegRevisionIdentifier
) {
1109 DEBUG ((DEBUG_ERROR
, "STM Image not compatible with CPU\n"));
1110 DEBUG ((DEBUG_ERROR
, " StmHeader->HwStmHdr.MsegHeaderRevision = %08x\n", StmHeader
->HwStmHdr
.MsegHeaderRevision
));
1111 DEBUG ((DEBUG_ERROR
, " VmxMiscMsr.Bits.MsegRevisionIdentifier = %08x\n", VmxMiscMsr
.Bits
.MsegRevisionIdentifier
));
1116 // Get Minimal required Mseg size
1118 MinMsegSize
= (EFI_PAGES_TO_SIZE (EFI_SIZE_TO_PAGES (StmHeader
->SwStmHdr
.StaticImageSize
)) +
1119 StmHeader
->SwStmHdr
.AdditionalDynamicMemorySize
+
1120 (StmHeader
->SwStmHdr
.PerProcDynamicMemorySize
+ GetVmcsSize () * 2) * gSmst
->NumberOfCpus
);
1121 if (MinMsegSize
< StmImageSize
) {
1122 MinMsegSize
= StmImageSize
;
1125 if (StmHeader
->HwStmHdr
.Cr3Offset
>= StmHeader
->SwStmHdr
.StaticImageSize
) {
1127 // We will create page table, just in case that SINIT does not create it.
1129 if (MinMsegSize
< StmHeader
->HwStmHdr
.Cr3Offset
+ EFI_PAGES_TO_SIZE (6)) {
1130 MinMsegSize
= StmHeader
->HwStmHdr
.Cr3Offset
+ EFI_PAGES_TO_SIZE (6);
1135 // Check if it exceeds MSEG size
1137 if (MinMsegSize
> mMsegSize
) {
1138 DEBUG ((DEBUG_ERROR
, "MSEG too small. Min MSEG Size = %08x Current MSEG Size = %08x\n", MinMsegSize
, mMsegSize
));
1139 DEBUG ((DEBUG_ERROR
, " StmHeader->SwStmHdr.StaticImageSize = %08x\n", StmHeader
->SwStmHdr
.StaticImageSize
));
1140 DEBUG ((DEBUG_ERROR
, " StmHeader->SwStmHdr.AdditionalDynamicMemorySize = %08x\n", StmHeader
->SwStmHdr
.AdditionalDynamicMemorySize
));
1141 DEBUG ((DEBUG_ERROR
, " StmHeader->SwStmHdr.PerProcDynamicMemorySize = %08x\n", StmHeader
->SwStmHdr
.PerProcDynamicMemorySize
));
1142 DEBUG ((DEBUG_ERROR
, " VMCS Size = %08x\n", GetVmcsSize ()));
1143 DEBUG ((DEBUG_ERROR
, " Max CPUs = %08x\n", gSmst
->NumberOfCpus
));
1144 DEBUG ((DEBUG_ERROR
, " StmHeader->HwStmHdr.Cr3Offset = %08x\n", StmHeader
->HwStmHdr
.Cr3Offset
));
1153 Load STM image to MSEG.
1155 @param StmImage STM image
1156 @param StmImageSize STM image size
1161 IN EFI_PHYSICAL_ADDRESS StmImage
,
1162 IN UINTN StmImageSize
1165 MSR_IA32_SMM_MONITOR_CTL_REGISTER SmmMonitorCtl
;
1167 STM_HEADER
*StmHeader
;
1170 // Get MSEG base address from MSR_IA32_SMM_MONITOR_CTL
1172 SmmMonitorCtl
.Uint64
= AsmReadMsr64 (MSR_IA32_SMM_MONITOR_CTL
);
1173 MsegBase
= SmmMonitorCtl
.Bits
.MsegBase
<< 12;
1176 // Zero all of MSEG base address
1178 ZeroMem ((VOID
*)(UINTN
)MsegBase
, mMsegSize
);
1181 // Copy STM Image into MSEG
1183 CopyMem ((VOID
*)(UINTN
)MsegBase
, (VOID
*)(UINTN
)StmImage
, StmImageSize
);
1186 // STM Header is at the beginning of the STM Image
1188 StmHeader
= (STM_HEADER
*)(UINTN
)StmImage
;
1190 StmGen4GPageTable ((UINTN
)MsegBase
+ StmHeader
->HwStmHdr
.Cr3Offset
);
1195 Load STM image to MSEG.
1197 @param StmImage STM image
1198 @param StmImageSize STM image size
1200 @retval EFI_SUCCESS Load STM to MSEG successfully
1201 @retval EFI_ALREADY_STARTED STM image is already loaded to MSEG
1202 @retval EFI_BUFFER_TOO_SMALL MSEG is smaller than minimal requirement of STM image
1203 @retval EFI_UNSUPPORTED MSEG is not enabled
1209 IN EFI_PHYSICAL_ADDRESS StmImage
,
1210 IN UINTN StmImageSize
1213 MSR_IA32_SMM_MONITOR_CTL_REGISTER SmmMonitorCtl
;
1215 if (mLockLoadMonitor
) {
1216 return EFI_ACCESS_DENIED
;
1219 SmmMonitorCtl
.Uint64
= AsmReadMsr64 (MSR_IA32_SMM_MONITOR_CTL
);
1220 if (SmmMonitorCtl
.Bits
.MsegBase
== 0) {
1221 return EFI_UNSUPPORTED
;
1224 if (!StmCheckStmImage (StmImage
, StmImageSize
)) {
1225 return EFI_BUFFER_TOO_SMALL
;
1228 // Record STM_HASH to PCR 0, just in case it is NOT TXT launch, we still need provide the evidence.
1229 TpmMeasureAndLogData (
1231 TXT_EVTYPE_STM_HASH
, // EventType
1234 (VOID
*)(UINTN
)StmImage
, // HashData
1235 StmImageSize
// HashDataLen
1238 StmLoadStmImage (StmImage
, StmImageSize
);
1240 mStmState
|= EFI_SM_MONITOR_STATE_ENABLED
;
1246 This function return BIOS STM resource.
1248 Consumed by SmmMpService when Init.
1250 @return BIOS STM resource
1258 return mStmResourcesPtr
;
1262 This function notify STM resource change.
1264 @param StmResource BIOS STM resource
1268 NotifyStmResourceChange (
1273 TXT_PROCESSOR_SMM_DESCRIPTOR
*Psd
;
1275 for (Index
= 0; Index
< gSmst
->NumberOfCpus
; Index
++) {
1276 Psd
= (TXT_PROCESSOR_SMM_DESCRIPTOR
*)((UINTN
)gSmst
->CpuSaveState
[Index
] - SMRAM_SAVE_STATE_MAP_OFFSET
+ TXT_SMM_PSD_OFFSET
);
1277 Psd
->BiosHwResourceRequirementsPtr
= (UINT64
)(UINTN
)StmResource
;
1284 This is STM setup BIOS callback.
1292 mStmState
|= EFI_SM_MONITOR_STATE_ACTIVATED
;
1296 This is STM teardown BIOS callback.
1304 mStmState
&= ~EFI_SM_MONITOR_STATE_ACTIVATED
;