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