2 SMM STM support functions
4 Copyright (c) 2015 - 2017, 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
;
121 The constructor function
123 @param[in] ImageHandle The firmware allocated handle for the EFI image.
124 @param[in] SystemTable A pointer to the EFI System Table.
126 @retval EFI_SUCCESS The constructor always returns EFI_SUCCESS.
131 SmmCpuFeaturesLibStmConstructor (
132 IN EFI_HANDLE ImageHandle
,
133 IN EFI_SYSTEM_TABLE
*SystemTable
137 CPUID_VERSION_INFO_ECX RegEcx
;
138 EFI_HOB_GUID_TYPE
*GuidHob
;
139 EFI_SMRAM_DESCRIPTOR
*SmramDescriptor
;
142 // Call the common constructor function
144 Status
= SmmCpuFeaturesLibConstructor (ImageHandle
, SystemTable
);
145 ASSERT_EFI_ERROR (Status
);
148 // Lookup the MP Services Protocol
150 Status
= gBS
->LocateProtocol (
151 &gEfiMpServiceProtocolGuid
,
153 (VOID
**)&mSmmCpuFeaturesLibMpService
155 ASSERT_EFI_ERROR (Status
);
158 // If CPU supports VMX, then determine SMRAM range for MSEG.
160 AsmCpuid (CPUID_VERSION_INFO
, NULL
, NULL
, &RegEcx
.Uint32
, NULL
);
161 if (RegEcx
.Bits
.VMX
== 1) {
162 GuidHob
= GetFirstGuidHob (&gMsegSmramGuid
);
163 if (GuidHob
!= NULL
) {
165 // Retrieve MSEG location from MSEG SRAM HOB
167 SmramDescriptor
= (EFI_SMRAM_DESCRIPTOR
*) GET_GUID_HOB_DATA (GuidHob
);
168 if (SmramDescriptor
->PhysicalSize
> 0) {
169 mMsegBase
= (UINTN
)SmramDescriptor
->CpuStart
;
170 mMsegSize
= (UINTN
)SmramDescriptor
->PhysicalSize
;
172 } else if (PcdGet32 (PcdCpuMsegSize
) > 0) {
174 // Allocate MSEG from SMRAM memory
176 mMsegBase
= (UINTN
)AllocatePages (EFI_SIZE_TO_PAGES (PcdGet32 (PcdCpuMsegSize
)));
178 mMsegSize
= ALIGN_VALUE (PcdGet32 (PcdCpuMsegSize
), EFI_PAGE_SIZE
);
180 DEBUG ((DEBUG_ERROR
, "Not enough SMRAM resource to allocate MSEG size %08x\n", PcdGet32 (PcdCpuMsegSize
)));
184 DEBUG ((DEBUG_INFO
, "MsegBase: 0x%08x, MsegSize: 0x%08x\n", mMsegBase
, mMsegSize
));
192 Internal worker function that is called to complete CPU initialization at the
193 end of SmmCpuFeaturesInitializeProcessor().
197 FinishSmmCpuFeaturesInitializeProcessor (
201 MSR_IA32_SMM_MONITOR_CTL_REGISTER SmmMonitorCtl
;
204 // Set MSEG Base Address in SMM Monitor Control MSR.
207 SmmMonitorCtl
.Uint64
= 0;
208 SmmMonitorCtl
.Bits
.MsegBase
= (UINT32
)mMsegBase
>> 12;
209 SmmMonitorCtl
.Bits
.Valid
= 1;
210 AsmWriteMsr64 (MSR_IA32_SMM_MONITOR_CTL
, SmmMonitorCtl
.Uint64
);
215 Return the size, in bytes, of a custom SMI Handler in bytes. If 0 is
216 returned, then a custom SMI handler is not provided by this library,
217 and the default SMI handler must be used.
219 @retval 0 Use the default SMI handler.
220 @retval > 0 Use the SMI handler installed by SmmCpuFeaturesInstallSmiHandler()
221 The caller is required to allocate enough SMRAM for each CPU to
222 support the size of the custom SMI handler.
226 SmmCpuFeaturesGetSmiHandlerSize (
230 return gcStmSmiHandlerSize
;
234 Install a custom SMI handler for the CPU specified by CpuIndex. This function
235 is only called if SmmCpuFeaturesGetSmiHandlerSize() returns a size is greater
236 than zero and is called by the CPU that was elected as monarch during System
237 Management Mode initialization.
239 @param[in] CpuIndex The index of the CPU to install the custom SMI handler.
240 The value must be between 0 and the NumberOfCpus field
241 in the System Management System Table (SMST).
242 @param[in] SmBase The SMBASE address for the CPU specified by CpuIndex.
243 @param[in] SmiStack The stack to use when an SMI is processed by the
244 the CPU specified by CpuIndex.
245 @param[in] StackSize The size, in bytes, if the stack used when an SMI is
246 processed by the CPU specified by CpuIndex.
247 @param[in] GdtBase The base address of the GDT to use when an SMI is
248 processed by the CPU specified by CpuIndex.
249 @param[in] GdtSize The size, in bytes, of the GDT used when an SMI is
250 processed by the CPU specified by CpuIndex.
251 @param[in] IdtBase The base address of the IDT to use when an SMI is
252 processed by the CPU specified by CpuIndex.
253 @param[in] IdtSize The size, in bytes, of the IDT used when an SMI is
254 processed by the CPU specified by CpuIndex.
255 @param[in] Cr3 The base address of the page tables to use when an SMI
256 is processed by the CPU specified by CpuIndex.
260 SmmCpuFeaturesInstallSmiHandler (
273 TXT_PROCESSOR_SMM_DESCRIPTOR
*Psd
;
277 EFI_PROCESSOR_INFORMATION ProcessorInfo
;
279 CopyMem ((VOID
*)((UINTN
)SmBase
+ TXT_SMM_PSD_OFFSET
), &gcStmPsd
, sizeof (gcStmPsd
));
280 Psd
= (TXT_PROCESSOR_SMM_DESCRIPTOR
*)(VOID
*)((UINTN
)SmBase
+ TXT_SMM_PSD_OFFSET
);
281 Psd
->SmmGdtPtr
= GdtBase
;
282 Psd
->SmmGdtSize
= (UINT32
)GdtSize
;
285 // Initialize values in template before copy
287 gStmSmiStack
= (UINT32
)((UINTN
)SmiStack
+ StackSize
- sizeof (UINTN
));
290 gStmSmiHandlerIdtr
.Base
= IdtBase
;
291 gStmSmiHandlerIdtr
.Limit
= (UINT16
)(IdtSize
- 1);
293 if (gStmXdSupported
) {
294 AsmCpuid (CPUID_EXTENDED_FUNCTION
, &RegEax
, NULL
, NULL
, NULL
);
295 if (RegEax
<= CPUID_EXTENDED_FUNCTION
) {
297 // Extended CPUID functions are not supported on this processor.
299 gStmXdSupported
= FALSE
;
302 AsmCpuid (CPUID_EXTENDED_CPU_SIG
, NULL
, NULL
, NULL
, &RegEdx
);
303 if ((RegEdx
& CPUID1_EDX_XD_SUPPORT
) == 0) {
305 // Execute Disable Bit feature is not supported on this processor.
307 gStmXdSupported
= FALSE
;
312 // Set the value at the top of the CPU stack to the CPU Index
314 *(UINTN
*)(UINTN
)gStmSmiStack
= CpuIndex
;
317 // Copy template to CPU specific SMI handler location
320 (VOID
*)((UINTN
)SmBase
+ SMM_HANDLER_OFFSET
),
321 (VOID
*)gcStmSmiHandlerTemplate
,
325 Psd
->SmmSmiHandlerRip
= SmBase
+ SMM_HANDLER_OFFSET
+ gcStmSmiHandlerOffset
;
326 Psd
->SmmSmiHandlerRsp
= (UINTN
)SmiStack
+ StackSize
- sizeof(UINTN
);
329 DEBUG((DEBUG_INFO
, "CpuSmmStmExceptionStackSize - %x\n", PcdGet32(PcdCpuSmmStmExceptionStackSize
)));
330 DEBUG((DEBUG_INFO
, "Pages - %x\n", EFI_SIZE_TO_PAGES(PcdGet32(PcdCpuSmmStmExceptionStackSize
))));
331 Psd
->StmProtectionExceptionHandler
.SpeRsp
= (UINT64
)(UINTN
)AllocatePages (EFI_SIZE_TO_PAGES (PcdGet32 (PcdCpuSmmStmExceptionStackSize
)));
332 Psd
->StmProtectionExceptionHandler
.SpeRsp
+= EFI_PAGES_TO_SIZE (EFI_SIZE_TO_PAGES (PcdGet32 (PcdCpuSmmStmExceptionStackSize
)));
334 Psd
->BiosHwResourceRequirementsPtr
= (UINT64
)(UINTN
)GetStmResource ();
337 // Get the APIC ID for the CPU specified by CpuIndex
339 Status
= mSmmCpuFeaturesLibMpService
->GetProcessorInfo (
340 mSmmCpuFeaturesLibMpService
,
344 ASSERT_EFI_ERROR (Status
);
346 Psd
->LocalApicId
= (UINT32
)ProcessorInfo
.ProcessorId
;
349 Hob
= GetFirstHob (EFI_HOB_TYPE_CPU
);
351 Psd
->PhysicalAddressBits
= ((EFI_HOB_CPU
*) Hob
)->SizeOfMemorySpace
;
353 AsmCpuid (0x80000000, &RegEax
, NULL
, NULL
, NULL
);
354 if (RegEax
>= 0x80000008) {
355 AsmCpuid (0x80000008, &RegEax
, NULL
, NULL
, NULL
);
356 Psd
->PhysicalAddressBits
= (UINT8
) RegEax
;
358 Psd
->PhysicalAddressBits
= 36;
362 if (!mStmConfigurationTableInitialized
) {
363 StmSmmConfigurationTableInit ();
364 mStmConfigurationTableInitialized
= TRUE
;
369 SMM End Of Dxe event notification handler.
371 STM support need patch AcpiRsdp in TXT_PROCESSOR_SMM_DESCRIPTOR.
373 @param[in] Protocol Points to the protocol's unique identifier.
374 @param[in] Interface Points to the interface instance.
375 @param[in] Handle The handle on which the interface was installed.
377 @retval EFI_SUCCESS Notification handler runs successfully.
381 SmmEndOfDxeEventNotify (
382 IN CONST EFI_GUID
*Protocol
,
389 TXT_PROCESSOR_SMM_DESCRIPTOR
*Psd
;
391 DEBUG ((DEBUG_INFO
, "SmmEndOfDxeEventNotify\n"));
394 // found ACPI table RSD_PTR from system table
397 for (Index
= 0; Index
< gST
->NumberOfTableEntries
; Index
++) {
398 if (CompareGuid (&(gST
->ConfigurationTable
[Index
].VendorGuid
), &gEfiAcpi20TableGuid
)) {
400 // A match was found.
402 Rsdp
= gST
->ConfigurationTable
[Index
].VendorTable
;
407 for (Index
= 0; Index
< gST
->NumberOfTableEntries
; Index
++) {
408 if (CompareGuid (&(gST
->ConfigurationTable
[Index
].VendorGuid
), &gEfiAcpi10TableGuid
)) {
410 // A match was found.
412 Rsdp
= gST
->ConfigurationTable
[Index
].VendorTable
;
418 for (Index
= 0; Index
< gSmst
->NumberOfCpus
; Index
++) {
419 Psd
= (TXT_PROCESSOR_SMM_DESCRIPTOR
*)((UINTN
)gSmst
->CpuSaveState
[Index
] - SMRAM_SAVE_STATE_MAP_OFFSET
+ TXT_SMM_PSD_OFFSET
);
420 DEBUG ((DEBUG_INFO
, "Index=%d Psd=%p Rsdp=%p\n", Index
, Psd
, Rsdp
));
421 Psd
->AcpiRsdp
= (UINT64
)(UINTN
)Rsdp
;
424 mLockLoadMonitor
= TRUE
;
430 This function initializes the STM configuration table.
433 StmSmmConfigurationTableInit (
440 Status
= gSmst
->SmmInstallProtocolInterface (
442 &gEfiSmMonitorInitProtocolGuid
,
443 EFI_NATIVE_INTERFACE
,
444 &mSmMonitorInitProtocol
446 ASSERT_EFI_ERROR (Status
);
450 // Register SMM End of DXE Event
452 Status
= gSmst
->SmmRegisterProtocolNotify (
453 &gEfiSmmEndOfDxeProtocolGuid
,
454 SmmEndOfDxeEventNotify
,
457 ASSERT_EFI_ERROR (Status
);
478 Handle single Resource to see if it can be merged into Record.
480 @param Resource A pointer to resource node to be added
481 @param Record A pointer to record node to be merged
483 @retval TRUE resource handled
484 @retval FALSE resource is not handled
488 HandleSingleResource (
489 IN STM_RSC
*Resource
,
504 // Calling code is responsible for making sure that
505 // Resource->Header.RscType == (*Record)->Header.RscType
506 // thus we use just one of them as switch variable.
508 switch (Resource
->Header
.RscType
) {
511 ResourceLo
= Resource
->Mem
.Base
;
512 ResourceHi
= Resource
->Mem
.Base
+ Resource
->Mem
.Length
;
513 RecordLo
= Record
->Mem
.Base
;
514 RecordHi
= Record
->Mem
.Base
+ Record
->Mem
.Length
;
515 if (Resource
->Mem
.RWXAttributes
!= Record
->Mem
.RWXAttributes
) {
516 if ((ResourceLo
== RecordLo
) && (ResourceHi
== RecordHi
)) {
517 Record
->Mem
.RWXAttributes
= Resource
->Mem
.RWXAttributes
| Record
->Mem
.RWXAttributes
;
525 case TRAPPED_IO_RANGE
:
526 ResourceLo
= (UINT64
) Resource
->Io
.Base
;
527 ResourceHi
= (UINT64
) Resource
->Io
.Base
+ (UINT64
) Resource
->Io
.Length
;
528 RecordLo
= (UINT64
) Record
->Io
.Base
;
529 RecordHi
= (UINT64
) Record
->Io
.Base
+ (UINT64
) Record
->Io
.Length
;
532 if ((Resource
->PciCfg
.OriginatingBusNumber
!= Record
->PciCfg
.OriginatingBusNumber
) ||
533 (Resource
->PciCfg
.LastNodeIndex
!= Record
->PciCfg
.LastNodeIndex
)) {
536 if (CompareMem (Resource
->PciCfg
.PciDevicePath
, Record
->PciCfg
.PciDevicePath
, sizeof(STM_PCI_DEVICE_PATH_NODE
) * (Resource
->PciCfg
.LastNodeIndex
+ 1)) != 0) {
539 ResourceLo
= (UINT64
) Resource
->PciCfg
.Base
;
540 ResourceHi
= (UINT64
) Resource
->PciCfg
.Base
+ (UINT64
) Resource
->PciCfg
.Length
;
541 RecordLo
= (UINT64
) Record
->PciCfg
.Base
;
542 RecordHi
= (UINT64
) Record
->PciCfg
.Base
+ (UINT64
) Record
->PciCfg
.Length
;
543 if (Resource
->PciCfg
.RWAttributes
!= Record
->PciCfg
.RWAttributes
) {
544 if ((ResourceLo
== RecordLo
) && (ResourceHi
== RecordHi
)) {
545 Record
->PciCfg
.RWAttributes
= Resource
->PciCfg
.RWAttributes
| Record
->PciCfg
.RWAttributes
;
552 case MACHINE_SPECIFIC_REG
:
554 // Special case - merge MSR masks in place.
556 if (Resource
->Msr
.MsrIndex
!= Record
->Msr
.MsrIndex
) {
559 Record
->Msr
.ReadMask
|= Resource
->Msr
.ReadMask
;
560 Record
->Msr
.WriteMask
|= Resource
->Msr
.WriteMask
;
566 // If resources are disjoint
568 if ((ResourceHi
< RecordLo
) || (ResourceLo
> RecordHi
)) {
573 // If resource is consumed by record.
575 if ((ResourceLo
>= RecordLo
) && (ResourceHi
<= RecordHi
)) {
579 // Resources are overlapping.
580 // Resource and record are merged.
582 ResourceLo
= (ResourceLo
< RecordLo
) ? ResourceLo
: RecordLo
;
583 ResourceHi
= (ResourceHi
> RecordHi
) ? ResourceHi
: RecordHi
;
585 switch (Resource
->Header
.RscType
) {
588 Record
->Mem
.Base
= ResourceLo
;
589 Record
->Mem
.Length
= ResourceHi
- ResourceLo
;
592 case TRAPPED_IO_RANGE
:
593 Record
->Io
.Base
= (UINT16
) ResourceLo
;
594 Record
->Io
.Length
= (UINT16
) (ResourceHi
- ResourceLo
);
597 Record
->PciCfg
.Base
= (UINT16
) ResourceLo
;
598 Record
->PciCfg
.Length
= (UINT16
) (ResourceHi
- ResourceLo
);
611 @param Resource A pointer to resource node to be added
621 Record
= (STM_RSC
*)mStmResourcesPtr
;
624 if (Record
->Header
.RscType
== END_OF_RESOURCES
) {
628 // Go to next record if resource and record types don't match.
630 if (Resource
->Header
.RscType
!= Record
->Header
.RscType
) {
631 Record
= (STM_RSC
*)((UINTN
)Record
+ Record
->Header
.Length
);
635 // Record is handled inside of procedure - don't adjust.
637 if (HandleSingleResource (Resource
, Record
)) {
640 Record
= (STM_RSC
*)((UINTN
)Record
+ Record
->Header
.Length
);
644 // Add resource to the end of area.
647 mStmResourcesPtr
+ mStmResourceSizeUsed
- sizeof(mRscEndNode
),
649 Resource
->Header
.Length
652 mStmResourcesPtr
+ mStmResourceSizeUsed
- sizeof(mRscEndNode
) + Resource
->Header
.Length
,
656 mStmResourceSizeUsed
+= Resource
->Header
.Length
;
657 mStmResourceSizeAvailable
= mStmResourceTotalSize
- mStmResourceSizeUsed
;
666 @param ResourceList A pointer to resource list to be added
667 @param NumEntries Optional number of entries.
668 If 0, list must be terminated by END_OF_RESOURCES.
673 IN STM_RSC
*ResourceList
,
674 IN UINT32 NumEntries OPTIONAL
681 if (NumEntries
== 0) {
687 Resource
= ResourceList
;
689 for (Index
= 0; Index
< Count
; Index
++) {
690 if (Resource
->Header
.RscType
== END_OF_RESOURCES
) {
693 AddSingleResource (Resource
);
694 Resource
= (STM_RSC
*)((UINTN
)Resource
+ Resource
->Header
.Length
);
701 Validate resource list.
703 @param ResourceList A pointer to resource list to be added
704 @param NumEntries Optional number of entries.
705 If 0, list must be terminated by END_OF_RESOURCES.
707 @retval TRUE resource valid
708 @retval FALSE resource invalid
713 IN STM_RSC
*ResourceList
,
714 IN UINT32 NumEntries OPTIONAL
723 // If NumEntries == 0 make it very big. Scan will be terminated by
726 if (NumEntries
== 0) {
733 // Start from beginning of resource list.
735 Resource
= ResourceList
;
737 for (Index
= 0; Index
< Count
; Index
++) {
738 DEBUG ((DEBUG_INFO
, "ValidateResource (%d) - RscType(%x)\n", Index
, Resource
->Header
.RscType
));
740 // Validate resource.
742 switch (Resource
->Header
.RscType
) {
743 case END_OF_RESOURCES
:
744 if (Resource
->Header
.Length
!= sizeof (STM_RSC_END
)) {
748 // If we are passed actual number of resources to add,
749 // END_OF_RESOURCES structure between them is considered an
750 // error. If NumEntries == 0 END_OF_RESOURCES is a termination.
752 if (NumEntries
!= 0) {
756 // If NumEntries == 0 and list reached end - return success.
764 if (Resource
->Header
.Length
!= sizeof (STM_RSC_MEM_DESC
)) {
768 if (Resource
->Mem
.RWXAttributes
> FULL_ACCS
) {
774 case TRAPPED_IO_RANGE
:
775 if (Resource
->Header
.Length
!= sizeof (STM_RSC_IO_DESC
)) {
779 if ((Resource
->Io
.Base
+ Resource
->Io
.Length
) > 0xFFFF) {
785 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
));
786 if (Resource
->Header
.Length
!= sizeof (STM_RSC_PCI_CFG_DESC
) + (sizeof(STM_PCI_DEVICE_PATH_NODE
) * Resource
->PciCfg
.LastNodeIndex
)) {
789 for (SubIndex
= 0; SubIndex
<= Resource
->PciCfg
.LastNodeIndex
; SubIndex
++) {
790 if ((Resource
->PciCfg
.PciDevicePath
[SubIndex
].PciDevice
> 0x1F) || (Resource
->PciCfg
.PciDevicePath
[SubIndex
].PciFunction
> 7)) {
794 if ((Resource
->PciCfg
.Base
+ Resource
->PciCfg
.Length
) > 0x1000) {
799 case MACHINE_SPECIFIC_REG
:
800 if (Resource
->Header
.Length
!= sizeof (STM_RSC_MSR_DESC
)) {
806 DEBUG ((DEBUG_ERROR
, "ValidateResource - Unknown RscType(%x)\n", Resource
->Header
.RscType
));
809 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
) {
858 Resource
= (STM_RSC
*)((UINTN
)Resource
+ Resource
->Header
.Length
);
861 return (UINTN
)Resource
- (UINTN
)ResourceList
;
866 Add resources in list to database. Allocate new memory areas as needed.
868 @param ResourceList A pointer to resource list to be added
869 @param NumEntries Optional number of entries.
870 If 0, list must be terminated by END_OF_RESOURCES.
872 @retval EFI_SUCCESS If resources are added
873 @retval EFI_INVALID_PARAMETER If nested procedure detected resource failer
874 @retval EFI_OUT_OF_RESOURCES If nested procedure returned it and we cannot allocate more areas.
880 IN STM_RSC
*ResourceList
,
881 IN UINT32 NumEntries OPTIONAL
886 EFI_PHYSICAL_ADDRESS NewResource
;
887 UINTN NewResourceSize
;
889 DEBUG ((DEBUG_INFO
, "AddPiResource - Enter\n"));
891 if (!ValidateResource (ResourceList
, NumEntries
)) {
892 return EFI_INVALID_PARAMETER
;
895 ResourceSize
= GetResourceSize (ResourceList
, NumEntries
);
896 DEBUG ((DEBUG_INFO
, "ResourceSize - 0x%08x\n", ResourceSize
));
897 if (ResourceSize
== 0) {
898 return EFI_INVALID_PARAMETER
;
901 if (mStmResourcesPtr
== NULL
) {
903 // First time allocation
905 NewResourceSize
= EFI_PAGES_TO_SIZE (EFI_SIZE_TO_PAGES (ResourceSize
+ sizeof(mRscEndNode
)));
906 DEBUG ((DEBUG_INFO
, "Allocate - 0x%08x\n", NewResourceSize
));
907 Status
= gSmst
->SmmAllocatePages (
909 EfiRuntimeServicesData
,
910 EFI_SIZE_TO_PAGES (NewResourceSize
),
913 if (EFI_ERROR (Status
)) {
918 // Copy EndResource for intialization
920 mStmResourcesPtr
= (UINT8
*)(UINTN
)NewResource
;
921 mStmResourceTotalSize
= NewResourceSize
;
922 CopyMem (mStmResourcesPtr
, &mRscEndNode
, sizeof(mRscEndNode
));
923 mStmResourceSizeUsed
= sizeof(mRscEndNode
);
924 mStmResourceSizeAvailable
= mStmResourceTotalSize
- sizeof(mRscEndNode
);
927 // Let SmmCore change resource ptr
929 NotifyStmResourceChange (mStmResourcesPtr
);
930 } else if (mStmResourceSizeAvailable
< ResourceSize
) {
934 NewResourceSize
= mStmResourceTotalSize
+ (ResourceSize
- mStmResourceSizeAvailable
);
935 NewResourceSize
= EFI_PAGES_TO_SIZE (EFI_SIZE_TO_PAGES (NewResourceSize
));
936 DEBUG ((DEBUG_INFO
, "ReAllocate - 0x%08x\n", NewResourceSize
));
937 Status
= gSmst
->SmmAllocatePages (
939 EfiRuntimeServicesData
,
940 EFI_SIZE_TO_PAGES (NewResourceSize
),
943 if (EFI_ERROR (Status
)) {
946 CopyMem ((VOID
*)(UINTN
)NewResource
, mStmResourcesPtr
, mStmResourceSizeUsed
);
947 mStmResourceSizeAvailable
= NewResourceSize
- mStmResourceSizeUsed
;
949 gSmst
->SmmFreePages (
950 (EFI_PHYSICAL_ADDRESS
)(UINTN
)mStmResourcesPtr
,
951 EFI_SIZE_TO_PAGES (mStmResourceTotalSize
)
954 mStmResourceTotalSize
= NewResourceSize
;
955 mStmResourcesPtr
= (UINT8
*)(UINTN
)NewResource
;
958 // Let SmmCore change resource ptr
960 NotifyStmResourceChange (mStmResourcesPtr
);
966 AddResource (ResourceList
, NumEntries
);
973 Delete resources in list to database.
975 @param ResourceList A pointer to resource list to be deleted
976 NULL means delete all resources.
977 @param NumEntries Optional number of entries.
978 If 0, list must be terminated by END_OF_RESOURCES.
980 @retval EFI_SUCCESS If resources are deleted
981 @retval EFI_INVALID_PARAMETER If nested procedure detected resource failer
987 IN STM_RSC
*ResourceList
,
988 IN UINT32 NumEntries OPTIONAL
991 if (ResourceList
!= NULL
) {
994 return EFI_UNSUPPORTED
;
999 CopyMem (mStmResourcesPtr
, &mRscEndNode
, sizeof(mRscEndNode
));
1000 mStmResourceSizeUsed
= sizeof(mRscEndNode
);
1001 mStmResourceSizeAvailable
= mStmResourceTotalSize
- sizeof(mRscEndNode
);
1009 @param ResourceList A pointer to resource list to be filled
1010 @param ResourceSize On input it means size of resource list input.
1011 On output it means size of resource list filled,
1012 or the size of resource list to be filled if size of too small.
1014 @retval EFI_SUCCESS If resources are returned.
1015 @retval EFI_BUFFER_TOO_SMALL If resource list buffer is too small to hold the whole resources.
1021 OUT STM_RSC
*ResourceList
,
1022 IN OUT UINT32
*ResourceSize
1025 if (*ResourceSize
< mStmResourceSizeUsed
) {
1026 *ResourceSize
= (UINT32
)mStmResourceSizeUsed
;
1027 return EFI_BUFFER_TOO_SMALL
;
1030 CopyMem (ResourceList
, mStmResourcesPtr
, mStmResourceSizeUsed
);
1031 *ResourceSize
= (UINT32
)mStmResourceSizeUsed
;
1037 Set valid bit for MSEG MSR.
1039 @param Buffer Ap function buffer. (not used)
1048 MSR_IA32_SMM_MONITOR_CTL_REGISTER SmmMonitorCtl
;
1050 SmmMonitorCtl
.Uint64
= AsmReadMsr64 (MSR_IA32_SMM_MONITOR_CTL
);
1051 SmmMonitorCtl
.Bits
.Valid
= 1;
1052 AsmWriteMsr64 (MSR_IA32_SMM_MONITOR_CTL
, SmmMonitorCtl
.Uint64
);
1057 Get 4K page aligned VMCS size.
1059 @return 4K page aligned VMCS size
1067 MSR_IA32_VMX_BASIC_REGISTER VmxBasic
;
1070 // Read VMCS size and and align to 4KB
1072 VmxBasic
.Uint64
= AsmReadMsr64 (MSR_IA32_VMX_BASIC
);
1073 return ALIGN_VALUE (VmxBasic
.Bits
.VmcsSize
, SIZE_4KB
);
1078 Check STM image size.
1080 @param StmImage STM image
1081 @param StmImageSize STM image size
1083 @retval TRUE check pass
1084 @retval FALSE check fail
1088 IN EFI_PHYSICAL_ADDRESS StmImage
,
1089 IN UINTN StmImageSize
1093 STM_HEADER
*StmHeader
;
1094 IA32_VMX_MISC_REGISTER VmxMiscMsr
;
1097 // Check to see if STM image is compatible with CPU
1099 StmHeader
= (STM_HEADER
*)(UINTN
)StmImage
;
1100 VmxMiscMsr
.Uint64
= AsmReadMsr64 (MSR_IA32_VMX_MISC
);
1101 if (StmHeader
->HwStmHdr
.MsegHeaderRevision
!= VmxMiscMsr
.Bits
.MsegRevisionIdentifier
) {
1102 DEBUG ((DEBUG_ERROR
, "STM Image not compatible with CPU\n"));
1103 DEBUG ((DEBUG_ERROR
, " StmHeader->HwStmHdr.MsegHeaderRevision = %08x\n", StmHeader
->HwStmHdr
.MsegHeaderRevision
));
1104 DEBUG ((DEBUG_ERROR
, " VmxMiscMsr.Bits.MsegRevisionIdentifier = %08x\n", VmxMiscMsr
.Bits
.MsegRevisionIdentifier
));
1109 // Get Minimal required Mseg size
1111 MinMsegSize
= (EFI_PAGES_TO_SIZE (EFI_SIZE_TO_PAGES (StmHeader
->SwStmHdr
.StaticImageSize
)) +
1112 StmHeader
->SwStmHdr
.AdditionalDynamicMemorySize
+
1113 (StmHeader
->SwStmHdr
.PerProcDynamicMemorySize
+ GetVmcsSize () * 2) * gSmst
->NumberOfCpus
);
1114 if (MinMsegSize
< StmImageSize
) {
1115 MinMsegSize
= StmImageSize
;
1118 if (StmHeader
->HwStmHdr
.Cr3Offset
>= StmHeader
->SwStmHdr
.StaticImageSize
) {
1120 // We will create page table, just in case that SINIT does not create it.
1122 if (MinMsegSize
< StmHeader
->HwStmHdr
.Cr3Offset
+ EFI_PAGES_TO_SIZE(6)) {
1123 MinMsegSize
= StmHeader
->HwStmHdr
.Cr3Offset
+ EFI_PAGES_TO_SIZE(6);
1128 // Check if it exceeds MSEG size
1130 if (MinMsegSize
> mMsegSize
) {
1131 DEBUG ((DEBUG_ERROR
, "MSEG too small. Min MSEG Size = %08x Current MSEG Size = %08x\n", MinMsegSize
, mMsegSize
));
1132 DEBUG ((DEBUG_ERROR
, " StmHeader->SwStmHdr.StaticImageSize = %08x\n", StmHeader
->SwStmHdr
.StaticImageSize
));
1133 DEBUG ((DEBUG_ERROR
, " StmHeader->SwStmHdr.AdditionalDynamicMemorySize = %08x\n", StmHeader
->SwStmHdr
.AdditionalDynamicMemorySize
));
1134 DEBUG ((DEBUG_ERROR
, " StmHeader->SwStmHdr.PerProcDynamicMemorySize = %08x\n", StmHeader
->SwStmHdr
.PerProcDynamicMemorySize
));
1135 DEBUG ((DEBUG_ERROR
, " VMCS Size = %08x\n", GetVmcsSize ()));
1136 DEBUG ((DEBUG_ERROR
, " Max CPUs = %08x\n", gSmst
->NumberOfCpus
));
1137 DEBUG ((DEBUG_ERROR
, " StmHeader->HwStmHdr.Cr3Offset = %08x\n", StmHeader
->HwStmHdr
.Cr3Offset
));
1146 Load STM image to MSEG.
1148 @param StmImage STM image
1149 @param StmImageSize STM image size
1154 IN EFI_PHYSICAL_ADDRESS StmImage
,
1155 IN UINTN StmImageSize
1158 MSR_IA32_SMM_MONITOR_CTL_REGISTER SmmMonitorCtl
;
1160 STM_HEADER
*StmHeader
;
1163 // Get MSEG base address from MSR_IA32_SMM_MONITOR_CTL
1165 SmmMonitorCtl
.Uint64
= AsmReadMsr64 (MSR_IA32_SMM_MONITOR_CTL
);
1166 MsegBase
= SmmMonitorCtl
.Bits
.MsegBase
<< 12;
1169 // Zero all of MSEG base address
1171 ZeroMem ((VOID
*)(UINTN
)MsegBase
, mMsegSize
);
1174 // Copy STM Image into MSEG
1176 CopyMem ((VOID
*)(UINTN
)MsegBase
, (VOID
*)(UINTN
)StmImage
, StmImageSize
);
1179 // STM Header is at the beginning of the STM Image
1181 StmHeader
= (STM_HEADER
*)(UINTN
)StmImage
;
1183 StmGen4GPageTable ((UINTN
)MsegBase
+ StmHeader
->HwStmHdr
.Cr3Offset
);
1188 Load STM image to MSEG.
1190 @param StmImage STM image
1191 @param StmImageSize STM image size
1193 @retval EFI_SUCCESS Load STM to MSEG successfully
1194 @retval EFI_ALREADY_STARTED STM image is already loaded to MSEG
1195 @retval EFI_BUFFER_TOO_SMALL MSEG is smaller than minimal requirement of STM image
1196 @retval EFI_UNSUPPORTED MSEG is not enabled
1202 IN EFI_PHYSICAL_ADDRESS StmImage
,
1203 IN UINTN StmImageSize
1206 MSR_IA32_SMM_MONITOR_CTL_REGISTER SmmMonitorCtl
;
1208 if (mLockLoadMonitor
) {
1209 return EFI_ACCESS_DENIED
;
1212 SmmMonitorCtl
.Uint64
= AsmReadMsr64 (MSR_IA32_SMM_MONITOR_CTL
);
1213 if (SmmMonitorCtl
.Bits
.MsegBase
== 0) {
1214 return EFI_UNSUPPORTED
;
1217 if (!StmCheckStmImage (StmImage
, StmImageSize
)) {
1218 return EFI_BUFFER_TOO_SMALL
;
1221 // Record STM_HASH to PCR 0, just in case it is NOT TXT launch, we still need provide the evidence.
1222 TpmMeasureAndLogData(
1224 TXT_EVTYPE_STM_HASH
, // EventType
1227 (VOID
*)(UINTN
)StmImage
, // HashData
1228 StmImageSize
// HashDataLen
1231 StmLoadStmImage (StmImage
, StmImageSize
);
1233 mStmState
|= EFI_SM_MONITOR_STATE_ENABLED
;
1239 This function return BIOS STM resource.
1241 Comsumed by SmmMpService when Init.
1243 @return BIOS STM resource
1251 return mStmResourcesPtr
;
1255 This function notify STM resource change.
1257 @param StmResource BIOS STM resource
1261 NotifyStmResourceChange (
1266 TXT_PROCESSOR_SMM_DESCRIPTOR
*Psd
;
1268 for (Index
= 0; Index
< gSmst
->NumberOfCpus
; Index
++) {
1269 Psd
= (TXT_PROCESSOR_SMM_DESCRIPTOR
*)((UINTN
)gSmst
->CpuSaveState
[Index
] - SMRAM_SAVE_STATE_MAP_OFFSET
+ TXT_SMM_PSD_OFFSET
);
1270 Psd
->BiosHwResourceRequirementsPtr
= (UINT64
)(UINTN
)StmResource
;
1277 This is STM setup BIOS callback.
1285 mStmState
|= EFI_SM_MONITOR_STATE_ACTIVATED
;
1289 This is STM teardown BIOS callback.
1297 mStmState
&= ~EFI_SM_MONITOR_STATE_ACTIVATED
;