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