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