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