]> git.proxmox.com Git - mirror_edk2.git/blob - UefiCpuPkg/Library/SmmCpuFeaturesLib/SmmStm.c
UefiCpuPkg/SmmCpuFeaturesLib: Clean up header file inclusion in SmmStm.c
[mirror_edk2.git] / UefiCpuPkg / Library / SmmCpuFeaturesLib / SmmStm.c
1 /** @file
2 SMM STM support functions
3
4 Copyright (c) 2015 - 2018, Intel Corporation. All rights reserved.<BR>
5 SPDX-License-Identifier: BSD-2-Clause-Patent
6
7 **/
8
9 #include <PiMm.h>
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>
18
19 #include <Protocol/MpService.h>
20
21 #include "CpuFeaturesLib.h"
22 #include "SmmStm.h"
23
24 #define TXT_EVTYPE_BASE 0x400
25 #define TXT_EVTYPE_STM_HASH (TXT_EVTYPE_BASE + 14)
26
27 #define RDWR_ACCS 3
28 #define FULL_ACCS 7
29
30 EFI_HANDLE mStmSmmCpuHandle = NULL;
31
32 BOOLEAN mLockLoadMonitor = FALSE;
33
34 //
35 // Template of STM_RSC_END structure for copying.
36 //
37 GLOBAL_REMOVE_IF_UNREFERENCED STM_RSC_END mRscEndNode = {
38 { END_OF_RESOURCES, sizeof (STM_RSC_END) },
39 };
40
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;
45
46 GLOBAL_REMOVE_IF_UNREFERENCED UINT32 mStmState = 0;
47
48 //
49 // System Configuration Table pointing to STM Configuration Table
50 //
51 GLOBAL_REMOVE_IF_UNREFERENCED
52 EFI_SM_MONITOR_INIT_PROTOCOL mSmMonitorInitProtocol = {
53 LoadMonitor,
54 AddPiResource,
55 DeletePiResource,
56 GetPiResource,
57 GetMonitorState,
58 };
59
60 #define CPUID1_EDX_XD_SUPPORT 0x100000
61
62 //
63 // External global variables associated with SMI Handler Template
64 //
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;
73
74 //
75 // Variables used by SMI Handler
76 //
77 IA32_DESCRIPTOR gStmSmiHandlerIdtr;
78
79 //
80 // MP Services Protocol
81 //
82 EFI_MP_SERVICES_PROTOCOL *mSmmCpuFeaturesLibMpService = NULL;
83
84 //
85 // MSEG Base and Length in SMRAM
86 //
87 UINTN mMsegBase = 0;
88 UINTN mMsegSize = 0;
89
90 BOOLEAN mStmConfigurationTableInitialized = FALSE;
91
92 /**
93 The constructor function for the Traditional MM library instance with STM.
94
95 @param[in] ImageHandle The firmware allocated handle for the EFI image.
96 @param[in] SystemTable A pointer to the EFI System Table.
97
98 @retval EFI_SUCCESS The constructor always returns EFI_SUCCESS.
99
100 **/
101 EFI_STATUS
102 EFIAPI
103 SmmCpuFeaturesLibStmConstructor (
104 IN EFI_HANDLE ImageHandle,
105 IN EFI_SYSTEM_TABLE *SystemTable
106 )
107 {
108 EFI_STATUS Status;
109 CPUID_VERSION_INFO_ECX RegEcx;
110 EFI_HOB_GUID_TYPE *GuidHob;
111 EFI_SMRAM_DESCRIPTOR *SmramDescriptor;
112
113 //
114 // Initialize address fixup
115 //
116 SmmCpuFeaturesLibStmSmiEntryFixupAddress ();
117
118 //
119 // Perform library initialization common across all instances
120 //
121 CpuFeaturesLibInitialization ();
122
123 //
124 // Lookup the MP Services Protocol
125 //
126 Status = gBS->LocateProtocol (
127 &gEfiMpServiceProtocolGuid,
128 NULL,
129 (VOID **)&mSmmCpuFeaturesLibMpService
130 );
131 ASSERT_EFI_ERROR (Status);
132
133 //
134 // If CPU supports VMX, then determine SMRAM range for MSEG.
135 //
136 AsmCpuid (CPUID_VERSION_INFO, NULL, NULL, &RegEcx.Uint32, NULL);
137 if (RegEcx.Bits.VMX == 1) {
138 GuidHob = GetFirstGuidHob (&gMsegSmramGuid);
139 if (GuidHob != NULL) {
140 //
141 // Retrieve MSEG location from MSEG SRAM HOB
142 //
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;
147 }
148 } else if (PcdGet32 (PcdCpuMsegSize) > 0) {
149 //
150 // Allocate MSEG from SMRAM memory
151 //
152 mMsegBase = (UINTN)AllocatePages (EFI_SIZE_TO_PAGES (PcdGet32 (PcdCpuMsegSize)));
153 if (mMsegBase > 0) {
154 mMsegSize = ALIGN_VALUE (PcdGet32 (PcdCpuMsegSize), EFI_PAGE_SIZE);
155 } else {
156 DEBUG ((DEBUG_ERROR, "Not enough SMRAM resource to allocate MSEG size %08x\n", PcdGet32 (PcdCpuMsegSize)));
157 }
158 }
159
160 if (mMsegBase > 0) {
161 DEBUG ((DEBUG_INFO, "MsegBase: 0x%08x, MsegSize: 0x%08x\n", mMsegBase, mMsegSize));
162 }
163 }
164
165 return EFI_SUCCESS;
166 }
167
168 /**
169 Internal worker function that is called to complete CPU initialization at the
170 end of SmmCpuFeaturesInitializeProcessor().
171
172 **/
173 VOID
174 FinishSmmCpuFeaturesInitializeProcessor (
175 VOID
176 )
177 {
178 MSR_IA32_SMM_MONITOR_CTL_REGISTER SmmMonitorCtl;
179
180 //
181 // Set MSEG Base Address in SMM Monitor Control MSR.
182 //
183 if (mMsegBase > 0) {
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);
188 }
189 }
190
191 /**
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.
195
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.
200 **/
201 UINTN
202 EFIAPI
203 SmmCpuFeaturesGetSmiHandlerSize (
204 VOID
205 )
206 {
207 return gcStmSmiHandlerSize;
208 }
209
210 /**
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.
215
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.
234 **/
235 VOID
236 EFIAPI
237 SmmCpuFeaturesInstallSmiHandler (
238 IN UINTN CpuIndex,
239 IN UINT32 SmBase,
240 IN VOID *SmiStack,
241 IN UINTN StackSize,
242 IN UINTN GdtBase,
243 IN UINTN GdtSize,
244 IN UINTN IdtBase,
245 IN UINTN IdtSize,
246 IN UINT32 Cr3
247 )
248 {
249 EFI_STATUS Status;
250 TXT_PROCESSOR_SMM_DESCRIPTOR *Psd;
251 VOID *Hob;
252 UINT32 RegEax;
253 UINT32 RegEdx;
254 EFI_PROCESSOR_INFORMATION ProcessorInfo;
255
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;
260
261 //
262 // Initialize values in template before copy
263 //
264 gStmSmiStack = (UINT32)((UINTN)SmiStack + StackSize - sizeof (UINTN));
265 gStmSmiCr3 = Cr3;
266 gStmSmbase = SmBase;
267 gStmSmiHandlerIdtr.Base = IdtBase;
268 gStmSmiHandlerIdtr.Limit = (UINT16)(IdtSize - 1);
269
270 if (gStmXdSupported) {
271 AsmCpuid (CPUID_EXTENDED_FUNCTION, &RegEax, NULL, NULL, NULL);
272 if (RegEax <= CPUID_EXTENDED_FUNCTION) {
273 //
274 // Extended CPUID functions are not supported on this processor.
275 //
276 gStmXdSupported = FALSE;
277 }
278
279 AsmCpuid (CPUID_EXTENDED_CPU_SIG, NULL, NULL, NULL, &RegEdx);
280 if ((RegEdx & CPUID1_EDX_XD_SUPPORT) == 0) {
281 //
282 // Execute Disable Bit feature is not supported on this processor.
283 //
284 gStmXdSupported = FALSE;
285 }
286 }
287
288 //
289 // Set the value at the top of the CPU stack to the CPU Index
290 //
291 *(UINTN *)(UINTN)gStmSmiStack = CpuIndex;
292
293 //
294 // Copy template to CPU specific SMI handler location
295 //
296 CopyMem (
297 (VOID *)((UINTN)SmBase + SMM_HANDLER_OFFSET),
298 (VOID *)gcStmSmiHandlerTemplate,
299 gcStmSmiHandlerSize
300 );
301
302 Psd->SmmSmiHandlerRip = SmBase + SMM_HANDLER_OFFSET + gcStmSmiHandlerOffset;
303 Psd->SmmSmiHandlerRsp = (UINTN)SmiStack + StackSize - sizeof (UINTN);
304 Psd->SmmCr3 = Cr3;
305
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)));
310
311 Psd->BiosHwResourceRequirementsPtr = (UINT64)(UINTN)GetStmResource ();
312
313 //
314 // Get the APIC ID for the CPU specified by CpuIndex
315 //
316 Status = mSmmCpuFeaturesLibMpService->GetProcessorInfo (
317 mSmmCpuFeaturesLibMpService,
318 CpuIndex,
319 &ProcessorInfo
320 );
321 ASSERT_EFI_ERROR (Status);
322
323 Psd->LocalApicId = (UINT32)ProcessorInfo.ProcessorId;
324 Psd->AcpiRsdp = 0;
325
326 Hob = GetFirstHob (EFI_HOB_TYPE_CPU);
327 if (Hob != NULL) {
328 Psd->PhysicalAddressBits = ((EFI_HOB_CPU *)Hob)->SizeOfMemorySpace;
329 } else {
330 AsmCpuid (0x80000000, &RegEax, NULL, NULL, NULL);
331 if (RegEax >= 0x80000008) {
332 AsmCpuid (0x80000008, &RegEax, NULL, NULL, NULL);
333 Psd->PhysicalAddressBits = (UINT8)RegEax;
334 } else {
335 Psd->PhysicalAddressBits = 36;
336 }
337 }
338
339 if (!mStmConfigurationTableInitialized) {
340 StmSmmConfigurationTableInit ();
341 mStmConfigurationTableInitialized = TRUE;
342 }
343 }
344
345 /**
346 SMM End Of Dxe event notification handler.
347
348 STM support need patch AcpiRsdp in TXT_PROCESSOR_SMM_DESCRIPTOR.
349
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.
353
354 @retval EFI_SUCCESS Notification handler runs successfully.
355 **/
356 EFI_STATUS
357 EFIAPI
358 SmmEndOfDxeEventNotify (
359 IN CONST EFI_GUID *Protocol,
360 IN VOID *Interface,
361 IN EFI_HANDLE Handle
362 )
363 {
364 VOID *Rsdp;
365 UINTN Index;
366 TXT_PROCESSOR_SMM_DESCRIPTOR *Psd;
367
368 DEBUG ((DEBUG_INFO, "SmmEndOfDxeEventNotify\n"));
369
370 //
371 // found ACPI table RSD_PTR from system table
372 //
373 Rsdp = NULL;
374 for (Index = 0; Index < gST->NumberOfTableEntries; Index++) {
375 if (CompareGuid (&(gST->ConfigurationTable[Index].VendorGuid), &gEfiAcpi20TableGuid)) {
376 //
377 // A match was found.
378 //
379 Rsdp = gST->ConfigurationTable[Index].VendorTable;
380 break;
381 }
382 }
383
384 if (Rsdp == NULL) {
385 for (Index = 0; Index < gST->NumberOfTableEntries; Index++) {
386 if (CompareGuid (&(gST->ConfigurationTable[Index].VendorGuid), &gEfiAcpi10TableGuid)) {
387 //
388 // A match was found.
389 //
390 Rsdp = gST->ConfigurationTable[Index].VendorTable;
391 break;
392 }
393 }
394 }
395
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;
400 }
401
402 mLockLoadMonitor = TRUE;
403
404 return EFI_SUCCESS;
405 }
406
407 /**
408 This function initializes the STM configuration table.
409 **/
410 VOID
411 StmSmmConfigurationTableInit (
412 VOID
413 )
414 {
415 EFI_STATUS Status;
416 VOID *Registration;
417
418 Status = gSmst->SmmInstallProtocolInterface (
419 &mStmSmmCpuHandle,
420 &gEfiSmMonitorInitProtocolGuid,
421 EFI_NATIVE_INTERFACE,
422 &mSmMonitorInitProtocol
423 );
424 ASSERT_EFI_ERROR (Status);
425
426 //
427 //
428 // Register SMM End of DXE Event
429 //
430 Status = gSmst->SmmRegisterProtocolNotify (
431 &gEfiSmmEndOfDxeProtocolGuid,
432 SmmEndOfDxeEventNotify,
433 &Registration
434 );
435 ASSERT_EFI_ERROR (Status);
436 }
437
438 /**
439
440 Get STM state.
441
442 @return STM state
443
444 **/
445 EFI_SM_MONITOR_STATE
446 EFIAPI
447 GetMonitorState (
448 VOID
449 )
450 {
451 return mStmState;
452 }
453
454 /**
455
456 Handle single Resource to see if it can be merged into Record.
457
458 @param Resource A pointer to resource node to be added
459 @param Record A pointer to record node to be merged
460
461 @retval TRUE resource handled
462 @retval FALSE resource is not handled
463
464 **/
465 BOOLEAN
466 HandleSingleResource (
467 IN STM_RSC *Resource,
468 IN STM_RSC *Record
469 )
470 {
471 UINT64 ResourceLo;
472 UINT64 ResourceHi;
473 UINT64 RecordLo;
474 UINT64 RecordHi;
475
476 ResourceLo = 0;
477 ResourceHi = 0;
478 RecordLo = 0;
479 RecordHi = 0;
480
481 //
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.
485 //
486 switch (Resource->Header.RscType) {
487 case MEM_RANGE:
488 case MMIO_RANGE:
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;
496 return TRUE;
497 } else {
498 return FALSE;
499 }
500 }
501
502 break;
503 case IO_RANGE:
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;
509 break;
510 case PCI_CFG_RANGE:
511 if ((Resource->PciCfg.OriginatingBusNumber != Record->PciCfg.OriginatingBusNumber) ||
512 (Resource->PciCfg.LastNodeIndex != Record->PciCfg.LastNodeIndex))
513 {
514 return FALSE;
515 }
516
517 if (CompareMem (Resource->PciCfg.PciDevicePath, Record->PciCfg.PciDevicePath, sizeof (STM_PCI_DEVICE_PATH_NODE) * (Resource->PciCfg.LastNodeIndex + 1)) != 0) {
518 return FALSE;
519 }
520
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;
528 return TRUE;
529 } else {
530 return FALSE;
531 }
532 }
533
534 break;
535 case MACHINE_SPECIFIC_REG:
536 //
537 // Special case - merge MSR masks in place.
538 //
539 if (Resource->Msr.MsrIndex != Record->Msr.MsrIndex) {
540 return FALSE;
541 }
542
543 Record->Msr.ReadMask |= Resource->Msr.ReadMask;
544 Record->Msr.WriteMask |= Resource->Msr.WriteMask;
545 return TRUE;
546 default:
547 return FALSE;
548 }
549
550 //
551 // If resources are disjoint
552 //
553 if ((ResourceHi < RecordLo) || (ResourceLo > RecordHi)) {
554 return FALSE;
555 }
556
557 //
558 // If resource is consumed by record.
559 //
560 if ((ResourceLo >= RecordLo) && (ResourceHi <= RecordHi)) {
561 return TRUE;
562 }
563
564 //
565 // Resources are overlapping.
566 // Resource and record are merged.
567 //
568 ResourceLo = (ResourceLo < RecordLo) ? ResourceLo : RecordLo;
569 ResourceHi = (ResourceHi > RecordHi) ? ResourceHi : RecordHi;
570
571 switch (Resource->Header.RscType) {
572 case MEM_RANGE:
573 case MMIO_RANGE:
574 Record->Mem.Base = ResourceLo;
575 Record->Mem.Length = ResourceHi - ResourceLo;
576 break;
577 case IO_RANGE:
578 case TRAPPED_IO_RANGE:
579 Record->Io.Base = (UINT16)ResourceLo;
580 Record->Io.Length = (UINT16)(ResourceHi - ResourceLo);
581 break;
582 case PCI_CFG_RANGE:
583 Record->PciCfg.Base = (UINT16)ResourceLo;
584 Record->PciCfg.Length = (UINT16)(ResourceHi - ResourceLo);
585 break;
586 default:
587 return FALSE;
588 }
589
590 return TRUE;
591 }
592
593 /**
594
595 Add resource node.
596
597 @param Resource A pointer to resource node to be added
598
599 **/
600 VOID
601 AddSingleResource (
602 IN STM_RSC *Resource
603 )
604 {
605 STM_RSC *Record;
606
607 Record = (STM_RSC *)mStmResourcesPtr;
608
609 while (TRUE) {
610 if (Record->Header.RscType == END_OF_RESOURCES) {
611 break;
612 }
613
614 //
615 // Go to next record if resource and record types don't match.
616 //
617 if (Resource->Header.RscType != Record->Header.RscType) {
618 Record = (STM_RSC *)((UINTN)Record + Record->Header.Length);
619 continue;
620 }
621
622 //
623 // Record is handled inside of procedure - don't adjust.
624 //
625 if (HandleSingleResource (Resource, Record)) {
626 return;
627 }
628
629 Record = (STM_RSC *)((UINTN)Record + Record->Header.Length);
630 }
631
632 //
633 // Add resource to the end of area.
634 //
635 CopyMem (
636 mStmResourcesPtr + mStmResourceSizeUsed - sizeof (mRscEndNode),
637 Resource,
638 Resource->Header.Length
639 );
640 CopyMem (
641 mStmResourcesPtr + mStmResourceSizeUsed - sizeof (mRscEndNode) + Resource->Header.Length,
642 &mRscEndNode,
643 sizeof (mRscEndNode)
644 );
645 mStmResourceSizeUsed += Resource->Header.Length;
646 mStmResourceSizeAvailable = mStmResourceTotalSize - mStmResourceSizeUsed;
647
648 return;
649 }
650
651 /**
652
653 Add resource list.
654
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.
658
659 **/
660 VOID
661 AddResource (
662 IN STM_RSC *ResourceList,
663 IN UINT32 NumEntries OPTIONAL
664 )
665 {
666 UINT32 Count;
667 UINTN Index;
668 STM_RSC *Resource;
669
670 if (NumEntries == 0) {
671 Count = 0xFFFFFFFF;
672 } else {
673 Count = NumEntries;
674 }
675
676 Resource = ResourceList;
677
678 for (Index = 0; Index < Count; Index++) {
679 if (Resource->Header.RscType == END_OF_RESOURCES) {
680 return;
681 }
682
683 AddSingleResource (Resource);
684 Resource = (STM_RSC *)((UINTN)Resource + Resource->Header.Length);
685 }
686
687 return;
688 }
689
690 /**
691
692 Validate resource list.
693
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.
697
698 @retval TRUE resource valid
699 @retval FALSE resource invalid
700
701 **/
702 BOOLEAN
703 ValidateResource (
704 IN STM_RSC *ResourceList,
705 IN UINT32 NumEntries OPTIONAL
706 )
707 {
708 UINT32 Count;
709 UINTN Index;
710 STM_RSC *Resource;
711 UINTN SubIndex;
712
713 //
714 // If NumEntries == 0 make it very big. Scan will be terminated by
715 // END_OF_RESOURCES.
716 //
717 if (NumEntries == 0) {
718 Count = 0xFFFFFFFF;
719 } else {
720 Count = NumEntries;
721 }
722
723 //
724 // Start from beginning of resource list.
725 //
726 Resource = ResourceList;
727
728 for (Index = 0; Index < Count; Index++) {
729 DEBUG ((DEBUG_INFO, "ValidateResource (%d) - RscType(%x)\n", Index, Resource->Header.RscType));
730 //
731 // Validate resource.
732 //
733 switch (Resource->Header.RscType) {
734 case END_OF_RESOURCES:
735 if (Resource->Header.Length != sizeof (STM_RSC_END)) {
736 return FALSE;
737 }
738
739 //
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.
743 //
744 if (NumEntries != 0) {
745 return FALSE;
746 } else {
747 //
748 // If NumEntries == 0 and list reached end - return success.
749 //
750 return TRUE;
751 }
752
753 break;
754
755 case MEM_RANGE:
756 case MMIO_RANGE:
757 if (Resource->Header.Length != sizeof (STM_RSC_MEM_DESC)) {
758 return FALSE;
759 }
760
761 if (Resource->Mem.RWXAttributes > FULL_ACCS) {
762 return FALSE;
763 }
764
765 break;
766
767 case IO_RANGE:
768 case TRAPPED_IO_RANGE:
769 if (Resource->Header.Length != sizeof (STM_RSC_IO_DESC)) {
770 return FALSE;
771 }
772
773 if ((Resource->Io.Base + Resource->Io.Length) > 0xFFFF) {
774 return FALSE;
775 }
776
777 break;
778
779 case PCI_CFG_RANGE:
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)) {
782 return FALSE;
783 }
784
785 for (SubIndex = 0; SubIndex <= Resource->PciCfg.LastNodeIndex; SubIndex++) {
786 if ((Resource->PciCfg.PciDevicePath[SubIndex].PciDevice > 0x1F) || (Resource->PciCfg.PciDevicePath[SubIndex].PciFunction > 7)) {
787 return FALSE;
788 }
789 }
790
791 if ((Resource->PciCfg.Base + Resource->PciCfg.Length) > 0x1000) {
792 return FALSE;
793 }
794
795 break;
796
797 case MACHINE_SPECIFIC_REG:
798 if (Resource->Header.Length != sizeof (STM_RSC_MSR_DESC)) {
799 return FALSE;
800 }
801
802 break;
803
804 default:
805 DEBUG ((DEBUG_ERROR, "ValidateResource - Unknown RscType(%x)\n", Resource->Header.RscType));
806 return FALSE;
807 }
808
809 Resource = (STM_RSC *)((UINTN)Resource + Resource->Header.Length);
810 }
811
812 return TRUE;
813 }
814
815 /**
816
817 Get resource list.
818 EndResource is excluded.
819
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.
823
824 @retval TRUE resource valid
825 @retval FALSE resource invalid
826
827 **/
828 UINTN
829 GetResourceSize (
830 IN STM_RSC *ResourceList,
831 IN UINT32 NumEntries OPTIONAL
832 )
833 {
834 UINT32 Count;
835 UINTN Index;
836 STM_RSC *Resource;
837
838 Resource = ResourceList;
839
840 //
841 // If NumEntries == 0 make it very big. Scan will be terminated by
842 // END_OF_RESOURCES.
843 //
844 if (NumEntries == 0) {
845 Count = 0xFFFFFFFF;
846 } else {
847 Count = NumEntries;
848 }
849
850 //
851 // Start from beginning of resource list.
852 //
853 Resource = ResourceList;
854
855 for (Index = 0; Index < Count; Index++) {
856 if (Resource->Header.RscType == END_OF_RESOURCES) {
857 break;
858 }
859
860 Resource = (STM_RSC *)((UINTN)Resource + Resource->Header.Length);
861 }
862
863 return (UINTN)Resource - (UINTN)ResourceList;
864 }
865
866 /**
867
868 Add resources in list to database. Allocate new memory areas as needed.
869
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.
873
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.
877
878 **/
879 EFI_STATUS
880 EFIAPI
881 AddPiResource (
882 IN STM_RSC *ResourceList,
883 IN UINT32 NumEntries OPTIONAL
884 )
885 {
886 EFI_STATUS Status;
887 UINTN ResourceSize;
888 EFI_PHYSICAL_ADDRESS NewResource;
889 UINTN NewResourceSize;
890
891 DEBUG ((DEBUG_INFO, "AddPiResource - Enter\n"));
892
893 if (!ValidateResource (ResourceList, NumEntries)) {
894 return EFI_INVALID_PARAMETER;
895 }
896
897 ResourceSize = GetResourceSize (ResourceList, NumEntries);
898 DEBUG ((DEBUG_INFO, "ResourceSize - 0x%08x\n", ResourceSize));
899 if (ResourceSize == 0) {
900 return EFI_INVALID_PARAMETER;
901 }
902
903 if (mStmResourcesPtr == NULL) {
904 //
905 // First time allocation
906 //
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 (
910 AllocateAnyPages,
911 EfiRuntimeServicesData,
912 EFI_SIZE_TO_PAGES (NewResourceSize),
913 &NewResource
914 );
915 if (EFI_ERROR (Status)) {
916 return Status;
917 }
918
919 //
920 // Copy EndResource for initialization
921 //
922 mStmResourcesPtr = (UINT8 *)(UINTN)NewResource;
923 mStmResourceTotalSize = NewResourceSize;
924 CopyMem (mStmResourcesPtr, &mRscEndNode, sizeof (mRscEndNode));
925 mStmResourceSizeUsed = sizeof (mRscEndNode);
926 mStmResourceSizeAvailable = mStmResourceTotalSize - sizeof (mRscEndNode);
927
928 //
929 // Let SmmCore change resource ptr
930 //
931 NotifyStmResourceChange (mStmResourcesPtr);
932 } else if (mStmResourceSizeAvailable < ResourceSize) {
933 //
934 // Need enlarge
935 //
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 (
940 AllocateAnyPages,
941 EfiRuntimeServicesData,
942 EFI_SIZE_TO_PAGES (NewResourceSize),
943 &NewResource
944 );
945 if (EFI_ERROR (Status)) {
946 return Status;
947 }
948
949 CopyMem ((VOID *)(UINTN)NewResource, mStmResourcesPtr, mStmResourceSizeUsed);
950 mStmResourceSizeAvailable = NewResourceSize - mStmResourceSizeUsed;
951
952 gSmst->SmmFreePages (
953 (EFI_PHYSICAL_ADDRESS)(UINTN)mStmResourcesPtr,
954 EFI_SIZE_TO_PAGES (mStmResourceTotalSize)
955 );
956
957 mStmResourceTotalSize = NewResourceSize;
958 mStmResourcesPtr = (UINT8 *)(UINTN)NewResource;
959
960 //
961 // Let SmmCore change resource ptr
962 //
963 NotifyStmResourceChange (mStmResourcesPtr);
964 }
965
966 //
967 // Check duplication
968 //
969 AddResource (ResourceList, NumEntries);
970
971 return EFI_SUCCESS;
972 }
973
974 /**
975
976 Delete resources in list to database.
977
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.
982
983 @retval EFI_SUCCESS If resources are deleted
984 @retval EFI_INVALID_PARAMETER If nested procedure detected resource failer
985
986 **/
987 EFI_STATUS
988 EFIAPI
989 DeletePiResource (
990 IN STM_RSC *ResourceList,
991 IN UINT32 NumEntries OPTIONAL
992 )
993 {
994 if (ResourceList != NULL) {
995 // TBD
996 ASSERT (FALSE);
997 return EFI_UNSUPPORTED;
998 }
999
1000 //
1001 // Delete all
1002 //
1003 CopyMem (mStmResourcesPtr, &mRscEndNode, sizeof (mRscEndNode));
1004 mStmResourceSizeUsed = sizeof (mRscEndNode);
1005 mStmResourceSizeAvailable = mStmResourceTotalSize - sizeof (mRscEndNode);
1006 return EFI_SUCCESS;
1007 }
1008
1009 /**
1010
1011 Get BIOS resources.
1012
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.
1017
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.
1020
1021 **/
1022 EFI_STATUS
1023 EFIAPI
1024 GetPiResource (
1025 OUT STM_RSC *ResourceList,
1026 IN OUT UINT32 *ResourceSize
1027 )
1028 {
1029 if (*ResourceSize < mStmResourceSizeUsed) {
1030 *ResourceSize = (UINT32)mStmResourceSizeUsed;
1031 return EFI_BUFFER_TOO_SMALL;
1032 }
1033
1034 CopyMem (ResourceList, mStmResourcesPtr, mStmResourceSizeUsed);
1035 *ResourceSize = (UINT32)mStmResourceSizeUsed;
1036 return EFI_SUCCESS;
1037 }
1038
1039 /**
1040
1041 Set valid bit for MSEG MSR.
1042
1043 @param Buffer Ap function buffer. (not used)
1044
1045 **/
1046 VOID
1047 EFIAPI
1048 EnableMsegMsr (
1049 IN VOID *Buffer
1050 )
1051 {
1052 MSR_IA32_SMM_MONITOR_CTL_REGISTER SmmMonitorCtl;
1053
1054 SmmMonitorCtl.Uint64 = AsmReadMsr64 (MSR_IA32_SMM_MONITOR_CTL);
1055 SmmMonitorCtl.Bits.Valid = 1;
1056 AsmWriteMsr64 (MSR_IA32_SMM_MONITOR_CTL, SmmMonitorCtl.Uint64);
1057 }
1058
1059 /**
1060
1061 Get 4K page aligned VMCS size.
1062
1063 @return 4K page aligned VMCS size
1064
1065 **/
1066 UINT32
1067 GetVmcsSize (
1068 VOID
1069 )
1070 {
1071 MSR_IA32_VMX_BASIC_REGISTER VmxBasic;
1072
1073 //
1074 // Read VMCS size and and align to 4KB
1075 //
1076 VmxBasic.Uint64 = AsmReadMsr64 (MSR_IA32_VMX_BASIC);
1077 return ALIGN_VALUE (VmxBasic.Bits.VmcsSize, SIZE_4KB);
1078 }
1079
1080 /**
1081
1082 Check STM image size.
1083
1084 @param StmImage STM image
1085 @param StmImageSize STM image size
1086
1087 @retval TRUE check pass
1088 @retval FALSE check fail
1089 **/
1090 BOOLEAN
1091 StmCheckStmImage (
1092 IN EFI_PHYSICAL_ADDRESS StmImage,
1093 IN UINTN StmImageSize
1094 )
1095 {
1096 UINTN MinMsegSize;
1097 STM_HEADER *StmHeader;
1098 IA32_VMX_MISC_REGISTER VmxMiscMsr;
1099
1100 //
1101 // Check to see if STM image is compatible with CPU
1102 //
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));
1109 return FALSE;
1110 }
1111
1112 //
1113 // Get Minimal required Mseg size
1114 //
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;
1120 }
1121
1122 if (StmHeader->HwStmHdr.Cr3Offset >= StmHeader->SwStmHdr.StaticImageSize) {
1123 //
1124 // We will create page table, just in case that SINIT does not create it.
1125 //
1126 if (MinMsegSize < StmHeader->HwStmHdr.Cr3Offset + EFI_PAGES_TO_SIZE (6)) {
1127 MinMsegSize = StmHeader->HwStmHdr.Cr3Offset + EFI_PAGES_TO_SIZE (6);
1128 }
1129 }
1130
1131 //
1132 // Check if it exceeds MSEG size
1133 //
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));
1142 return FALSE;
1143 }
1144
1145 return TRUE;
1146 }
1147
1148 /**
1149
1150 Load STM image to MSEG.
1151
1152 @param StmImage STM image
1153 @param StmImageSize STM image size
1154
1155 **/
1156 VOID
1157 StmLoadStmImage (
1158 IN EFI_PHYSICAL_ADDRESS StmImage,
1159 IN UINTN StmImageSize
1160 )
1161 {
1162 MSR_IA32_SMM_MONITOR_CTL_REGISTER SmmMonitorCtl;
1163 UINT32 MsegBase;
1164 STM_HEADER *StmHeader;
1165
1166 //
1167 // Get MSEG base address from MSR_IA32_SMM_MONITOR_CTL
1168 //
1169 SmmMonitorCtl.Uint64 = AsmReadMsr64 (MSR_IA32_SMM_MONITOR_CTL);
1170 MsegBase = SmmMonitorCtl.Bits.MsegBase << 12;
1171
1172 //
1173 // Zero all of MSEG base address
1174 //
1175 ZeroMem ((VOID *)(UINTN)MsegBase, mMsegSize);
1176
1177 //
1178 // Copy STM Image into MSEG
1179 //
1180 CopyMem ((VOID *)(UINTN)MsegBase, (VOID *)(UINTN)StmImage, StmImageSize);
1181
1182 //
1183 // STM Header is at the beginning of the STM Image
1184 //
1185 StmHeader = (STM_HEADER *)(UINTN)StmImage;
1186
1187 StmGen4GPageTable ((UINTN)MsegBase + StmHeader->HwStmHdr.Cr3Offset);
1188 }
1189
1190 /**
1191
1192 Load STM image to MSEG.
1193
1194 @param StmImage STM image
1195 @param StmImageSize STM image size
1196
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
1201
1202 **/
1203 EFI_STATUS
1204 EFIAPI
1205 LoadMonitor (
1206 IN EFI_PHYSICAL_ADDRESS StmImage,
1207 IN UINTN StmImageSize
1208 )
1209 {
1210 MSR_IA32_SMM_MONITOR_CTL_REGISTER SmmMonitorCtl;
1211
1212 if (mLockLoadMonitor) {
1213 return EFI_ACCESS_DENIED;
1214 }
1215
1216 SmmMonitorCtl.Uint64 = AsmReadMsr64 (MSR_IA32_SMM_MONITOR_CTL);
1217 if (SmmMonitorCtl.Bits.MsegBase == 0) {
1218 return EFI_UNSUPPORTED;
1219 }
1220
1221 if (!StmCheckStmImage (StmImage, StmImageSize)) {
1222 return EFI_BUFFER_TOO_SMALL;
1223 }
1224
1225 // Record STM_HASH to PCR 0, just in case it is NOT TXT launch, we still need provide the evidence.
1226 TpmMeasureAndLogData (
1227 0, // PcrIndex
1228 TXT_EVTYPE_STM_HASH, // EventType
1229 NULL, // EventLog
1230 0, // LogLen
1231 (VOID *)(UINTN)StmImage, // HashData
1232 StmImageSize // HashDataLen
1233 );
1234
1235 StmLoadStmImage (StmImage, StmImageSize);
1236
1237 mStmState |= EFI_SM_MONITOR_STATE_ENABLED;
1238
1239 return EFI_SUCCESS;
1240 }
1241
1242 /**
1243 This function return BIOS STM resource.
1244 Produced by SmmStm.
1245 Consumed by SmmMpService when Init.
1246
1247 @return BIOS STM resource
1248
1249 **/
1250 VOID *
1251 GetStmResource (
1252 VOID
1253 )
1254 {
1255 return mStmResourcesPtr;
1256 }
1257
1258 /**
1259 This function notify STM resource change.
1260
1261 @param StmResource BIOS STM resource
1262
1263 **/
1264 VOID
1265 NotifyStmResourceChange (
1266 VOID *StmResource
1267 )
1268 {
1269 UINTN Index;
1270 TXT_PROCESSOR_SMM_DESCRIPTOR *Psd;
1271
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;
1275 }
1276
1277 return;
1278 }
1279
1280 /**
1281 This is STM setup BIOS callback.
1282 **/
1283 VOID
1284 EFIAPI
1285 SmmStmSetup (
1286 VOID
1287 )
1288 {
1289 mStmState |= EFI_SM_MONITOR_STATE_ACTIVATED;
1290 }
1291
1292 /**
1293 This is STM teardown BIOS callback.
1294 **/
1295 VOID
1296 EFIAPI
1297 SmmStmTeardown (
1298 VOID
1299 )
1300 {
1301 mStmState &= ~EFI_SM_MONITOR_STATE_ACTIVATED;
1302 }