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