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