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