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