2 SMM STM support functions
4 Copyright (c) 2015 - 2018, Intel Corporation. All rights reserved.<BR>
5 This program and the accompanying materials
6 are licensed and made available under the terms and conditions of the BSD License
7 which accompanies this distribution. The full text of the license may be found at
8 http://opensource.org/licenses/bsd-license.php.
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
16 #include <Library/BaseLib.h>
17 #include <Library/BaseMemoryLib.h>
18 #include <Library/MemoryAllocationLib.h>
19 #include <Library/HobLib.h>
20 #include <Library/DebugLib.h>
21 #include <Library/UefiBootServicesTableLib.h>
22 #include <Library/SmmServicesTableLib.h>
23 #include <Library/TpmMeasurementLib.h>
24 #include <Register/Cpuid.h>
25 #include <Register/ArchitecturalMsr.h>
26 #include <Register/SmramSaveStateMap.h>
28 #include <Protocol/MpService.h>
32 #define TXT_EVTYPE_BASE 0x400
33 #define TXT_EVTYPE_STM_HASH (TXT_EVTYPE_BASE + 14)
39 The constructor function
41 @param[in] ImageHandle The firmware allocated handle for the EFI image.
42 @param[in] SystemTable A pointer to the EFI System Table.
44 @retval EFI_SUCCESS The constructor always returns EFI_SUCCESS.
49 SmmCpuFeaturesLibConstructor (
50 IN EFI_HANDLE ImageHandle
,
51 IN EFI_SYSTEM_TABLE
*SystemTable
54 EFI_HANDLE mStmSmmCpuHandle
= NULL
;
56 BOOLEAN mLockLoadMonitor
= FALSE
;
59 // Template of STM_RSC_END structure for copying.
61 GLOBAL_REMOVE_IF_UNREFERENCED STM_RSC_END mRscEndNode
= {
62 {END_OF_RESOURCES
, sizeof (STM_RSC_END
)},
65 GLOBAL_REMOVE_IF_UNREFERENCED UINT8
*mStmResourcesPtr
= NULL
;
66 GLOBAL_REMOVE_IF_UNREFERENCED UINTN mStmResourceTotalSize
= 0x0;
67 GLOBAL_REMOVE_IF_UNREFERENCED UINTN mStmResourceSizeUsed
= 0x0;
68 GLOBAL_REMOVE_IF_UNREFERENCED UINTN mStmResourceSizeAvailable
= 0x0;
70 GLOBAL_REMOVE_IF_UNREFERENCED UINT32 mStmState
= 0;
73 // System Configuration Table pointing to STM Configuration Table
75 GLOBAL_REMOVE_IF_UNREFERENCED
76 EFI_SM_MONITOR_INIT_PROTOCOL mSmMonitorInitProtocol
= {
87 #define CPUID1_EDX_XD_SUPPORT 0x100000
90 // External global variables associated with SMI Handler Template
92 extern CONST TXT_PROCESSOR_SMM_DESCRIPTOR gcStmPsd
;
93 extern UINT32 gStmSmbase
;
94 extern volatile UINT32 gStmSmiStack
;
95 extern UINT32 gStmSmiCr3
;
96 extern volatile UINT8 gcStmSmiHandlerTemplate
[];
97 extern CONST UINT16 gcStmSmiHandlerSize
;
98 extern UINT16 gcStmSmiHandlerOffset
;
99 extern BOOLEAN gStmXdSupported
;
102 // Variables used by SMI Handler
104 IA32_DESCRIPTOR gStmSmiHandlerIdtr
;
107 // MP Services Protocol
109 EFI_MP_SERVICES_PROTOCOL
*mSmmCpuFeaturesLibMpService
= NULL
;
112 // MSEG Base and Length in SMRAM
117 BOOLEAN mStmConfigurationTableInitialized
= FALSE
;
120 The constructor function
122 @param[in] ImageHandle The firmware allocated handle for the EFI image.
123 @param[in] SystemTable A pointer to the EFI System Table.
125 @retval EFI_SUCCESS The constructor always returns EFI_SUCCESS.
130 SmmCpuFeaturesLibStmConstructor (
131 IN EFI_HANDLE ImageHandle
,
132 IN EFI_SYSTEM_TABLE
*SystemTable
136 CPUID_VERSION_INFO_ECX RegEcx
;
137 EFI_HOB_GUID_TYPE
*GuidHob
;
138 EFI_SMRAM_DESCRIPTOR
*SmramDescriptor
;
141 // Initialize address fixup
143 SmmCpuFeaturesLibStmSmiEntryFixupAddress ();
146 // Call the common constructor function
148 Status
= SmmCpuFeaturesLibConstructor (ImageHandle
, SystemTable
);
149 ASSERT_EFI_ERROR (Status
);
152 // Lookup the MP Services Protocol
154 Status
= gBS
->LocateProtocol (
155 &gEfiMpServiceProtocolGuid
,
157 (VOID
**)&mSmmCpuFeaturesLibMpService
159 ASSERT_EFI_ERROR (Status
);
162 // If CPU supports VMX, then determine SMRAM range for MSEG.
164 AsmCpuid (CPUID_VERSION_INFO
, NULL
, NULL
, &RegEcx
.Uint32
, NULL
);
165 if (RegEcx
.Bits
.VMX
== 1) {
166 GuidHob
= GetFirstGuidHob (&gMsegSmramGuid
);
167 if (GuidHob
!= NULL
) {
169 // Retrieve MSEG location from MSEG SRAM HOB
171 SmramDescriptor
= (EFI_SMRAM_DESCRIPTOR
*) GET_GUID_HOB_DATA (GuidHob
);
172 if (SmramDescriptor
->PhysicalSize
> 0) {
173 mMsegBase
= (UINTN
)SmramDescriptor
->CpuStart
;
174 mMsegSize
= (UINTN
)SmramDescriptor
->PhysicalSize
;
176 } else if (PcdGet32 (PcdCpuMsegSize
) > 0) {
178 // Allocate MSEG from SMRAM memory
180 mMsegBase
= (UINTN
)AllocatePages (EFI_SIZE_TO_PAGES (PcdGet32 (PcdCpuMsegSize
)));
182 mMsegSize
= ALIGN_VALUE (PcdGet32 (PcdCpuMsegSize
), EFI_PAGE_SIZE
);
184 DEBUG ((DEBUG_ERROR
, "Not enough SMRAM resource to allocate MSEG size %08x\n", PcdGet32 (PcdCpuMsegSize
)));
188 DEBUG ((DEBUG_INFO
, "MsegBase: 0x%08x, MsegSize: 0x%08x\n", mMsegBase
, mMsegSize
));
196 Internal worker function that is called to complete CPU initialization at the
197 end of SmmCpuFeaturesInitializeProcessor().
201 FinishSmmCpuFeaturesInitializeProcessor (
205 MSR_IA32_SMM_MONITOR_CTL_REGISTER SmmMonitorCtl
;
208 // Set MSEG Base Address in SMM Monitor Control MSR.
211 SmmMonitorCtl
.Uint64
= 0;
212 SmmMonitorCtl
.Bits
.MsegBase
= (UINT32
)mMsegBase
>> 12;
213 SmmMonitorCtl
.Bits
.Valid
= 1;
214 AsmWriteMsr64 (MSR_IA32_SMM_MONITOR_CTL
, SmmMonitorCtl
.Uint64
);
219 Return the size, in bytes, of a custom SMI Handler in bytes. If 0 is
220 returned, then a custom SMI handler is not provided by this library,
221 and the default SMI handler must be used.
223 @retval 0 Use the default SMI handler.
224 @retval > 0 Use the SMI handler installed by SmmCpuFeaturesInstallSmiHandler()
225 The caller is required to allocate enough SMRAM for each CPU to
226 support the size of the custom SMI handler.
230 SmmCpuFeaturesGetSmiHandlerSize (
234 return gcStmSmiHandlerSize
;
238 Install a custom SMI handler for the CPU specified by CpuIndex. This function
239 is only called if SmmCpuFeaturesGetSmiHandlerSize() returns a size is greater
240 than zero and is called by the CPU that was elected as monarch during System
241 Management Mode initialization.
243 @param[in] CpuIndex The index of the CPU to install the custom SMI handler.
244 The value must be between 0 and the NumberOfCpus field
245 in the System Management System Table (SMST).
246 @param[in] SmBase The SMBASE address for the CPU specified by CpuIndex.
247 @param[in] SmiStack The stack to use when an SMI is processed by the
248 the CPU specified by CpuIndex.
249 @param[in] StackSize The size, in bytes, if the stack used when an SMI is
250 processed by the CPU specified by CpuIndex.
251 @param[in] GdtBase The base address of the GDT to use when an SMI is
252 processed by the CPU specified by CpuIndex.
253 @param[in] GdtSize The size, in bytes, of the GDT used when an SMI is
254 processed by the CPU specified by CpuIndex.
255 @param[in] IdtBase The base address of the IDT to use when an SMI is
256 processed by the CPU specified by CpuIndex.
257 @param[in] IdtSize The size, in bytes, of the IDT used when an SMI is
258 processed by the CPU specified by CpuIndex.
259 @param[in] Cr3 The base address of the page tables to use when an SMI
260 is processed by the CPU specified by CpuIndex.
264 SmmCpuFeaturesInstallSmiHandler (
277 TXT_PROCESSOR_SMM_DESCRIPTOR
*Psd
;
281 EFI_PROCESSOR_INFORMATION ProcessorInfo
;
283 CopyMem ((VOID
*)((UINTN
)SmBase
+ TXT_SMM_PSD_OFFSET
), &gcStmPsd
, sizeof (gcStmPsd
));
284 Psd
= (TXT_PROCESSOR_SMM_DESCRIPTOR
*)(VOID
*)((UINTN
)SmBase
+ TXT_SMM_PSD_OFFSET
);
285 Psd
->SmmGdtPtr
= GdtBase
;
286 Psd
->SmmGdtSize
= (UINT32
)GdtSize
;
289 // Initialize values in template before copy
291 gStmSmiStack
= (UINT32
)((UINTN
)SmiStack
+ StackSize
- sizeof (UINTN
));
294 gStmSmiHandlerIdtr
.Base
= IdtBase
;
295 gStmSmiHandlerIdtr
.Limit
= (UINT16
)(IdtSize
- 1);
297 if (gStmXdSupported
) {
298 AsmCpuid (CPUID_EXTENDED_FUNCTION
, &RegEax
, NULL
, NULL
, NULL
);
299 if (RegEax
<= CPUID_EXTENDED_FUNCTION
) {
301 // Extended CPUID functions are not supported on this processor.
303 gStmXdSupported
= FALSE
;
306 AsmCpuid (CPUID_EXTENDED_CPU_SIG
, NULL
, NULL
, NULL
, &RegEdx
);
307 if ((RegEdx
& CPUID1_EDX_XD_SUPPORT
) == 0) {
309 // Execute Disable Bit feature is not supported on this processor.
311 gStmXdSupported
= FALSE
;
316 // Set the value at the top of the CPU stack to the CPU Index
318 *(UINTN
*)(UINTN
)gStmSmiStack
= CpuIndex
;
321 // Copy template to CPU specific SMI handler location
324 (VOID
*)((UINTN
)SmBase
+ SMM_HANDLER_OFFSET
),
325 (VOID
*)gcStmSmiHandlerTemplate
,
329 Psd
->SmmSmiHandlerRip
= SmBase
+ SMM_HANDLER_OFFSET
+ gcStmSmiHandlerOffset
;
330 Psd
->SmmSmiHandlerRsp
= (UINTN
)SmiStack
+ StackSize
- sizeof(UINTN
);
333 DEBUG((DEBUG_INFO
, "CpuSmmStmExceptionStackSize - %x\n", PcdGet32(PcdCpuSmmStmExceptionStackSize
)));
334 DEBUG((DEBUG_INFO
, "Pages - %x\n", EFI_SIZE_TO_PAGES(PcdGet32(PcdCpuSmmStmExceptionStackSize
))));
335 Psd
->StmProtectionExceptionHandler
.SpeRsp
= (UINT64
)(UINTN
)AllocatePages (EFI_SIZE_TO_PAGES (PcdGet32 (PcdCpuSmmStmExceptionStackSize
)));
336 Psd
->StmProtectionExceptionHandler
.SpeRsp
+= EFI_PAGES_TO_SIZE (EFI_SIZE_TO_PAGES (PcdGet32 (PcdCpuSmmStmExceptionStackSize
)));
338 Psd
->BiosHwResourceRequirementsPtr
= (UINT64
)(UINTN
)GetStmResource ();
341 // Get the APIC ID for the CPU specified by CpuIndex
343 Status
= mSmmCpuFeaturesLibMpService
->GetProcessorInfo (
344 mSmmCpuFeaturesLibMpService
,
348 ASSERT_EFI_ERROR (Status
);
350 Psd
->LocalApicId
= (UINT32
)ProcessorInfo
.ProcessorId
;
353 Hob
= GetFirstHob (EFI_HOB_TYPE_CPU
);
355 Psd
->PhysicalAddressBits
= ((EFI_HOB_CPU
*) Hob
)->SizeOfMemorySpace
;
357 AsmCpuid (0x80000000, &RegEax
, NULL
, NULL
, NULL
);
358 if (RegEax
>= 0x80000008) {
359 AsmCpuid (0x80000008, &RegEax
, NULL
, NULL
, NULL
);
360 Psd
->PhysicalAddressBits
= (UINT8
) RegEax
;
362 Psd
->PhysicalAddressBits
= 36;
366 if (!mStmConfigurationTableInitialized
) {
367 StmSmmConfigurationTableInit ();
368 mStmConfigurationTableInitialized
= TRUE
;
373 SMM End Of Dxe event notification handler.
375 STM support need patch AcpiRsdp in TXT_PROCESSOR_SMM_DESCRIPTOR.
377 @param[in] Protocol Points to the protocol's unique identifier.
378 @param[in] Interface Points to the interface instance.
379 @param[in] Handle The handle on which the interface was installed.
381 @retval EFI_SUCCESS Notification handler runs successfully.
385 SmmEndOfDxeEventNotify (
386 IN CONST EFI_GUID
*Protocol
,
393 TXT_PROCESSOR_SMM_DESCRIPTOR
*Psd
;
395 DEBUG ((DEBUG_INFO
, "SmmEndOfDxeEventNotify\n"));
398 // found ACPI table RSD_PTR from system table
401 for (Index
= 0; Index
< gST
->NumberOfTableEntries
; Index
++) {
402 if (CompareGuid (&(gST
->ConfigurationTable
[Index
].VendorGuid
), &gEfiAcpi20TableGuid
)) {
404 // A match was found.
406 Rsdp
= gST
->ConfigurationTable
[Index
].VendorTable
;
411 for (Index
= 0; Index
< gST
->NumberOfTableEntries
; Index
++) {
412 if (CompareGuid (&(gST
->ConfigurationTable
[Index
].VendorGuid
), &gEfiAcpi10TableGuid
)) {
414 // A match was found.
416 Rsdp
= gST
->ConfigurationTable
[Index
].VendorTable
;
422 for (Index
= 0; Index
< gSmst
->NumberOfCpus
; Index
++) {
423 Psd
= (TXT_PROCESSOR_SMM_DESCRIPTOR
*)((UINTN
)gSmst
->CpuSaveState
[Index
] - SMRAM_SAVE_STATE_MAP_OFFSET
+ TXT_SMM_PSD_OFFSET
);
424 DEBUG ((DEBUG_INFO
, "Index=%d Psd=%p Rsdp=%p\n", Index
, Psd
, Rsdp
));
425 Psd
->AcpiRsdp
= (UINT64
)(UINTN
)Rsdp
;
428 mLockLoadMonitor
= TRUE
;
434 This function initializes the STM configuration table.
437 StmSmmConfigurationTableInit (
444 Status
= gSmst
->SmmInstallProtocolInterface (
446 &gEfiSmMonitorInitProtocolGuid
,
447 EFI_NATIVE_INTERFACE
,
448 &mSmMonitorInitProtocol
450 ASSERT_EFI_ERROR (Status
);
454 // Register SMM End of DXE Event
456 Status
= gSmst
->SmmRegisterProtocolNotify (
457 &gEfiSmmEndOfDxeProtocolGuid
,
458 SmmEndOfDxeEventNotify
,
461 ASSERT_EFI_ERROR (Status
);
482 Handle single Resource to see if it can be merged into Record.
484 @param Resource A pointer to resource node to be added
485 @param Record A pointer to record node to be merged
487 @retval TRUE resource handled
488 @retval FALSE resource is not handled
492 HandleSingleResource (
493 IN STM_RSC
*Resource
,
508 // Calling code is responsible for making sure that
509 // Resource->Header.RscType == (*Record)->Header.RscType
510 // thus we use just one of them as switch variable.
512 switch (Resource
->Header
.RscType
) {
515 ResourceLo
= Resource
->Mem
.Base
;
516 ResourceHi
= Resource
->Mem
.Base
+ Resource
->Mem
.Length
;
517 RecordLo
= Record
->Mem
.Base
;
518 RecordHi
= Record
->Mem
.Base
+ Record
->Mem
.Length
;
519 if (Resource
->Mem
.RWXAttributes
!= Record
->Mem
.RWXAttributes
) {
520 if ((ResourceLo
== RecordLo
) && (ResourceHi
== RecordHi
)) {
521 Record
->Mem
.RWXAttributes
= Resource
->Mem
.RWXAttributes
| Record
->Mem
.RWXAttributes
;
529 case TRAPPED_IO_RANGE
:
530 ResourceLo
= (UINT64
) Resource
->Io
.Base
;
531 ResourceHi
= (UINT64
) Resource
->Io
.Base
+ (UINT64
) Resource
->Io
.Length
;
532 RecordLo
= (UINT64
) Record
->Io
.Base
;
533 RecordHi
= (UINT64
) Record
->Io
.Base
+ (UINT64
) Record
->Io
.Length
;
536 if ((Resource
->PciCfg
.OriginatingBusNumber
!= Record
->PciCfg
.OriginatingBusNumber
) ||
537 (Resource
->PciCfg
.LastNodeIndex
!= Record
->PciCfg
.LastNodeIndex
)) {
540 if (CompareMem (Resource
->PciCfg
.PciDevicePath
, Record
->PciCfg
.PciDevicePath
, sizeof(STM_PCI_DEVICE_PATH_NODE
) * (Resource
->PciCfg
.LastNodeIndex
+ 1)) != 0) {
543 ResourceLo
= (UINT64
) Resource
->PciCfg
.Base
;
544 ResourceHi
= (UINT64
) Resource
->PciCfg
.Base
+ (UINT64
) Resource
->PciCfg
.Length
;
545 RecordLo
= (UINT64
) Record
->PciCfg
.Base
;
546 RecordHi
= (UINT64
) Record
->PciCfg
.Base
+ (UINT64
) Record
->PciCfg
.Length
;
547 if (Resource
->PciCfg
.RWAttributes
!= Record
->PciCfg
.RWAttributes
) {
548 if ((ResourceLo
== RecordLo
) && (ResourceHi
== RecordHi
)) {
549 Record
->PciCfg
.RWAttributes
= Resource
->PciCfg
.RWAttributes
| Record
->PciCfg
.RWAttributes
;
556 case MACHINE_SPECIFIC_REG
:
558 // Special case - merge MSR masks in place.
560 if (Resource
->Msr
.MsrIndex
!= Record
->Msr
.MsrIndex
) {
563 Record
->Msr
.ReadMask
|= Resource
->Msr
.ReadMask
;
564 Record
->Msr
.WriteMask
|= Resource
->Msr
.WriteMask
;
570 // If resources are disjoint
572 if ((ResourceHi
< RecordLo
) || (ResourceLo
> RecordHi
)) {
577 // If resource is consumed by record.
579 if ((ResourceLo
>= RecordLo
) && (ResourceHi
<= RecordHi
)) {
583 // Resources are overlapping.
584 // Resource and record are merged.
586 ResourceLo
= (ResourceLo
< RecordLo
) ? ResourceLo
: RecordLo
;
587 ResourceHi
= (ResourceHi
> RecordHi
) ? ResourceHi
: RecordHi
;
589 switch (Resource
->Header
.RscType
) {
592 Record
->Mem
.Base
= ResourceLo
;
593 Record
->Mem
.Length
= ResourceHi
- ResourceLo
;
596 case TRAPPED_IO_RANGE
:
597 Record
->Io
.Base
= (UINT16
) ResourceLo
;
598 Record
->Io
.Length
= (UINT16
) (ResourceHi
- ResourceLo
);
601 Record
->PciCfg
.Base
= (UINT16
) ResourceLo
;
602 Record
->PciCfg
.Length
= (UINT16
) (ResourceHi
- ResourceLo
);
615 @param Resource A pointer to resource node to be added
625 Record
= (STM_RSC
*)mStmResourcesPtr
;
628 if (Record
->Header
.RscType
== END_OF_RESOURCES
) {
632 // Go to next record if resource and record types don't match.
634 if (Resource
->Header
.RscType
!= Record
->Header
.RscType
) {
635 Record
= (STM_RSC
*)((UINTN
)Record
+ Record
->Header
.Length
);
639 // Record is handled inside of procedure - don't adjust.
641 if (HandleSingleResource (Resource
, Record
)) {
644 Record
= (STM_RSC
*)((UINTN
)Record
+ Record
->Header
.Length
);
648 // Add resource to the end of area.
651 mStmResourcesPtr
+ mStmResourceSizeUsed
- sizeof(mRscEndNode
),
653 Resource
->Header
.Length
656 mStmResourcesPtr
+ mStmResourceSizeUsed
- sizeof(mRscEndNode
) + Resource
->Header
.Length
,
660 mStmResourceSizeUsed
+= Resource
->Header
.Length
;
661 mStmResourceSizeAvailable
= mStmResourceTotalSize
- mStmResourceSizeUsed
;
670 @param ResourceList A pointer to resource list to be added
671 @param NumEntries Optional number of entries.
672 If 0, list must be terminated by END_OF_RESOURCES.
677 IN STM_RSC
*ResourceList
,
678 IN UINT32 NumEntries OPTIONAL
685 if (NumEntries
== 0) {
691 Resource
= ResourceList
;
693 for (Index
= 0; Index
< Count
; Index
++) {
694 if (Resource
->Header
.RscType
== END_OF_RESOURCES
) {
697 AddSingleResource (Resource
);
698 Resource
= (STM_RSC
*)((UINTN
)Resource
+ Resource
->Header
.Length
);
705 Validate resource list.
707 @param ResourceList A pointer to resource list to be added
708 @param NumEntries Optional number of entries.
709 If 0, list must be terminated by END_OF_RESOURCES.
711 @retval TRUE resource valid
712 @retval FALSE resource invalid
717 IN STM_RSC
*ResourceList
,
718 IN UINT32 NumEntries OPTIONAL
727 // If NumEntries == 0 make it very big. Scan will be terminated by
730 if (NumEntries
== 0) {
737 // Start from beginning of resource list.
739 Resource
= ResourceList
;
741 for (Index
= 0; Index
< Count
; Index
++) {
742 DEBUG ((DEBUG_INFO
, "ValidateResource (%d) - RscType(%x)\n", Index
, Resource
->Header
.RscType
));
744 // Validate resource.
746 switch (Resource
->Header
.RscType
) {
747 case END_OF_RESOURCES
:
748 if (Resource
->Header
.Length
!= sizeof (STM_RSC_END
)) {
752 // If we are passed actual number of resources to add,
753 // END_OF_RESOURCES structure between them is considered an
754 // error. If NumEntries == 0 END_OF_RESOURCES is a termination.
756 if (NumEntries
!= 0) {
760 // If NumEntries == 0 and list reached end - return success.
768 if (Resource
->Header
.Length
!= sizeof (STM_RSC_MEM_DESC
)) {
772 if (Resource
->Mem
.RWXAttributes
> FULL_ACCS
) {
778 case TRAPPED_IO_RANGE
:
779 if (Resource
->Header
.Length
!= sizeof (STM_RSC_IO_DESC
)) {
783 if ((Resource
->Io
.Base
+ Resource
->Io
.Length
) > 0xFFFF) {
789 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
));
790 if (Resource
->Header
.Length
!= sizeof (STM_RSC_PCI_CFG_DESC
) + (sizeof(STM_PCI_DEVICE_PATH_NODE
) * Resource
->PciCfg
.LastNodeIndex
)) {
793 for (SubIndex
= 0; SubIndex
<= Resource
->PciCfg
.LastNodeIndex
; SubIndex
++) {
794 if ((Resource
->PciCfg
.PciDevicePath
[SubIndex
].PciDevice
> 0x1F) || (Resource
->PciCfg
.PciDevicePath
[SubIndex
].PciFunction
> 7)) {
798 if ((Resource
->PciCfg
.Base
+ Resource
->PciCfg
.Length
) > 0x1000) {
803 case MACHINE_SPECIFIC_REG
:
804 if (Resource
->Header
.Length
!= sizeof (STM_RSC_MSR_DESC
)) {
810 DEBUG ((DEBUG_ERROR
, "ValidateResource - Unknown RscType(%x)\n", Resource
->Header
.RscType
));
813 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
) {
862 Resource
= (STM_RSC
*)((UINTN
)Resource
+ Resource
->Header
.Length
);
865 return (UINTN
)Resource
- (UINTN
)ResourceList
;
870 Add resources in list to database. Allocate new memory areas as needed.
872 @param ResourceList A pointer to resource list to be added
873 @param NumEntries Optional number of entries.
874 If 0, list must be terminated by END_OF_RESOURCES.
876 @retval EFI_SUCCESS If resources are added
877 @retval EFI_INVALID_PARAMETER If nested procedure detected resource failer
878 @retval EFI_OUT_OF_RESOURCES If nested procedure returned it and we cannot allocate more areas.
884 IN STM_RSC
*ResourceList
,
885 IN UINT32 NumEntries OPTIONAL
890 EFI_PHYSICAL_ADDRESS NewResource
;
891 UINTN NewResourceSize
;
893 DEBUG ((DEBUG_INFO
, "AddPiResource - Enter\n"));
895 if (!ValidateResource (ResourceList
, NumEntries
)) {
896 return EFI_INVALID_PARAMETER
;
899 ResourceSize
= GetResourceSize (ResourceList
, NumEntries
);
900 DEBUG ((DEBUG_INFO
, "ResourceSize - 0x%08x\n", ResourceSize
));
901 if (ResourceSize
== 0) {
902 return EFI_INVALID_PARAMETER
;
905 if (mStmResourcesPtr
== NULL
) {
907 // First time allocation
909 NewResourceSize
= EFI_PAGES_TO_SIZE (EFI_SIZE_TO_PAGES (ResourceSize
+ sizeof(mRscEndNode
)));
910 DEBUG ((DEBUG_INFO
, "Allocate - 0x%08x\n", NewResourceSize
));
911 Status
= gSmst
->SmmAllocatePages (
913 EfiRuntimeServicesData
,
914 EFI_SIZE_TO_PAGES (NewResourceSize
),
917 if (EFI_ERROR (Status
)) {
922 // Copy EndResource for intialization
924 mStmResourcesPtr
= (UINT8
*)(UINTN
)NewResource
;
925 mStmResourceTotalSize
= NewResourceSize
;
926 CopyMem (mStmResourcesPtr
, &mRscEndNode
, sizeof(mRscEndNode
));
927 mStmResourceSizeUsed
= sizeof(mRscEndNode
);
928 mStmResourceSizeAvailable
= mStmResourceTotalSize
- sizeof(mRscEndNode
);
931 // Let SmmCore change resource ptr
933 NotifyStmResourceChange (mStmResourcesPtr
);
934 } else if (mStmResourceSizeAvailable
< ResourceSize
) {
938 NewResourceSize
= mStmResourceTotalSize
+ (ResourceSize
- mStmResourceSizeAvailable
);
939 NewResourceSize
= EFI_PAGES_TO_SIZE (EFI_SIZE_TO_PAGES (NewResourceSize
));
940 DEBUG ((DEBUG_INFO
, "ReAllocate - 0x%08x\n", NewResourceSize
));
941 Status
= gSmst
->SmmAllocatePages (
943 EfiRuntimeServicesData
,
944 EFI_SIZE_TO_PAGES (NewResourceSize
),
947 if (EFI_ERROR (Status
)) {
950 CopyMem ((VOID
*)(UINTN
)NewResource
, mStmResourcesPtr
, mStmResourceSizeUsed
);
951 mStmResourceSizeAvailable
= NewResourceSize
- mStmResourceSizeUsed
;
953 gSmst
->SmmFreePages (
954 (EFI_PHYSICAL_ADDRESS
)(UINTN
)mStmResourcesPtr
,
955 EFI_SIZE_TO_PAGES (mStmResourceTotalSize
)
958 mStmResourceTotalSize
= NewResourceSize
;
959 mStmResourcesPtr
= (UINT8
*)(UINTN
)NewResource
;
962 // Let SmmCore change resource ptr
964 NotifyStmResourceChange (mStmResourcesPtr
);
970 AddResource (ResourceList
, NumEntries
);
977 Delete resources in list to database.
979 @param ResourceList A pointer to resource list to be deleted
980 NULL means delete all resources.
981 @param NumEntries Optional number of entries.
982 If 0, list must be terminated by END_OF_RESOURCES.
984 @retval EFI_SUCCESS If resources are deleted
985 @retval EFI_INVALID_PARAMETER If nested procedure detected resource failer
991 IN STM_RSC
*ResourceList
,
992 IN UINT32 NumEntries OPTIONAL
995 if (ResourceList
!= NULL
) {
998 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 Comsumed 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
;