]> git.proxmox.com Git - mirror_edk2.git/blame_incremental - UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.c
UefiCpuPkg/dec: Add PcdCpuSmmStaticPageTable.
[mirror_edk2.git] / UefiCpuPkg / PiSmmCpuDxeSmm / PiSmmCpuDxeSmm.c
... / ...
CommitLineData
1/** @file\r
2Agent Module to load other modules to deploy SMM Entry Vector for X86 CPU.\r
3\r
4Copyright (c) 2009 - 2016, Intel Corporation. All rights reserved.<BR>\r
5This program and the accompanying materials\r
6are licensed and made available under the terms and conditions of the BSD License\r
7which accompanies this distribution. The full text of the license may be found at\r
8http://opensource.org/licenses/bsd-license.php\r
9\r
10THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
11WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
12\r
13**/\r
14\r
15#include "PiSmmCpuDxeSmm.h"\r
16\r
17//\r
18// SMM CPU Private Data structure that contains SMM Configuration Protocol\r
19// along its supporting fields.\r
20//\r
21SMM_CPU_PRIVATE_DATA mSmmCpuPrivateData = {\r
22 SMM_CPU_PRIVATE_DATA_SIGNATURE, // Signature\r
23 NULL, // SmmCpuHandle\r
24 NULL, // Pointer to ProcessorInfo array\r
25 NULL, // Pointer to Operation array\r
26 NULL, // Pointer to CpuSaveStateSize array\r
27 NULL, // Pointer to CpuSaveState array\r
28 { {0} }, // SmmReservedSmramRegion\r
29 {\r
30 SmmStartupThisAp, // SmmCoreEntryContext.SmmStartupThisAp\r
31 0, // SmmCoreEntryContext.CurrentlyExecutingCpu\r
32 0, // SmmCoreEntryContext.NumberOfCpus\r
33 NULL, // SmmCoreEntryContext.CpuSaveStateSize\r
34 NULL // SmmCoreEntryContext.CpuSaveState\r
35 },\r
36 NULL, // SmmCoreEntry\r
37 {\r
38 mSmmCpuPrivateData.SmmReservedSmramRegion, // SmmConfiguration.SmramReservedRegions\r
39 RegisterSmmEntry // SmmConfiguration.RegisterSmmEntry\r
40 },\r
41};\r
42\r
43CPU_HOT_PLUG_DATA mCpuHotPlugData = {\r
44 CPU_HOT_PLUG_DATA_REVISION_1, // Revision\r
45 0, // Array Length of SmBase and APIC ID\r
46 NULL, // Pointer to APIC ID array\r
47 NULL, // Pointer to SMBASE array\r
48 0, // Reserved\r
49 0, // SmrrBase\r
50 0 // SmrrSize\r
51};\r
52\r
53//\r
54// Global pointer used to access mSmmCpuPrivateData from outside and inside SMM\r
55//\r
56SMM_CPU_PRIVATE_DATA *gSmmCpuPrivate = &mSmmCpuPrivateData;\r
57\r
58//\r
59// SMM Relocation variables\r
60//\r
61volatile BOOLEAN *mRebased;\r
62volatile BOOLEAN mIsBsp;\r
63\r
64///\r
65/// Handle for the SMM CPU Protocol\r
66///\r
67EFI_HANDLE mSmmCpuHandle = NULL;\r
68\r
69///\r
70/// SMM CPU Protocol instance\r
71///\r
72EFI_SMM_CPU_PROTOCOL mSmmCpu = {\r
73 SmmReadSaveState,\r
74 SmmWriteSaveState\r
75};\r
76\r
77EFI_CPU_INTERRUPT_HANDLER mExternalVectorTable[EXCEPTION_VECTOR_NUMBER];\r
78\r
79//\r
80// SMM stack information\r
81//\r
82UINTN mSmmStackArrayBase;\r
83UINTN mSmmStackArrayEnd;\r
84UINTN mSmmStackSize;\r
85\r
86UINTN mMaxNumberOfCpus = 1;\r
87UINTN mNumberOfCpus = 1;\r
88\r
89//\r
90// SMM ready to lock flag\r
91//\r
92BOOLEAN mSmmReadyToLock = FALSE;\r
93\r
94//\r
95// Global used to cache PCD for SMM Code Access Check enable\r
96//\r
97BOOLEAN mSmmCodeAccessCheckEnable = FALSE;\r
98\r
99//\r
100// Spin lock used to serialize setting of SMM Code Access Check feature\r
101//\r
102SPIN_LOCK *mConfigSmmCodeAccessCheckLock = NULL;\r
103\r
104/**\r
105 Initialize IDT to setup exception handlers for SMM.\r
106\r
107**/\r
108VOID\r
109InitializeSmmIdt (\r
110 VOID\r
111 )\r
112{\r
113 EFI_STATUS Status;\r
114 BOOLEAN InterruptState;\r
115 IA32_DESCRIPTOR DxeIdtr;\r
116 //\r
117 // Disable Interrupt and save DXE IDT table\r
118 //\r
119 InterruptState = SaveAndDisableInterrupts ();\r
120 AsmReadIdtr (&DxeIdtr);\r
121 //\r
122 // Load SMM temporary IDT table\r
123 //\r
124 AsmWriteIdtr (&gcSmiIdtr);\r
125 //\r
126 // Setup SMM default exception handlers, SMM IDT table\r
127 // will be updated and saved in gcSmiIdtr\r
128 //\r
129 Status = InitializeCpuExceptionHandlers (NULL);\r
130 ASSERT_EFI_ERROR (Status);\r
131 //\r
132 // Restore DXE IDT table and CPU interrupt\r
133 //\r
134 AsmWriteIdtr ((IA32_DESCRIPTOR *) &DxeIdtr);\r
135 SetInterruptState (InterruptState);\r
136}\r
137\r
138/**\r
139 Search module name by input IP address and output it.\r
140\r
141 @param CallerIpAddress Caller instruction pointer.\r
142\r
143**/\r
144VOID\r
145DumpModuleInfoByIp (\r
146 IN UINTN CallerIpAddress\r
147 )\r
148{\r
149 UINTN Pe32Data;\r
150 EFI_IMAGE_DOS_HEADER *DosHdr;\r
151 EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr;\r
152 VOID *PdbPointer;\r
153 UINT64 DumpIpAddress;\r
154\r
155 //\r
156 // Find Image Base\r
157 //\r
158 Pe32Data = CallerIpAddress & ~(SIZE_4KB - 1);\r
159 while (Pe32Data != 0) {\r
160 DosHdr = (EFI_IMAGE_DOS_HEADER *) Pe32Data;\r
161 if (DosHdr->e_magic == EFI_IMAGE_DOS_SIGNATURE) {\r
162 //\r
163 // DOS image header is present, so read the PE header after the DOS image header.\r
164 //\r
165 Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *)(Pe32Data + (UINTN) ((DosHdr->e_lfanew) & 0x0ffff));\r
166 //\r
167 // Make sure PE header address does not overflow and is less than the initial address.\r
168 //\r
169 if (((UINTN)Hdr.Pe32 > Pe32Data) && ((UINTN)Hdr.Pe32 < CallerIpAddress)) {\r
170 if (Hdr.Pe32->Signature == EFI_IMAGE_NT_SIGNATURE) {\r
171 //\r
172 // It's PE image.\r
173 //\r
174 break;\r
175 }\r
176 }\r
177 }\r
178\r
179 //\r
180 // Not found the image base, check the previous aligned address\r
181 //\r
182 Pe32Data -= SIZE_4KB;\r
183 }\r
184\r
185 DumpIpAddress = CallerIpAddress;\r
186 DEBUG ((EFI_D_ERROR, "It is invoked from the instruction before IP(0x%lx)", DumpIpAddress));\r
187\r
188 if (Pe32Data != 0) {\r
189 PdbPointer = PeCoffLoaderGetPdbPointer ((VOID *) Pe32Data);\r
190 if (PdbPointer != NULL) {\r
191 DEBUG ((EFI_D_ERROR, " in module (%a)", PdbPointer));\r
192 }\r
193 }\r
194}\r
195\r
196/**\r
197 Read information from the CPU save state.\r
198\r
199 @param This EFI_SMM_CPU_PROTOCOL instance\r
200 @param Width The number of bytes to read from the CPU save state.\r
201 @param Register Specifies the CPU register to read form the save state.\r
202 @param CpuIndex Specifies the zero-based index of the CPU save state.\r
203 @param Buffer Upon return, this holds the CPU register value read from the save state.\r
204\r
205 @retval EFI_SUCCESS The register was read from Save State\r
206 @retval EFI_NOT_FOUND The register is not defined for the Save State of Processor\r
207 @retval EFI_INVALID_PARAMTER This or Buffer is NULL.\r
208\r
209**/\r
210EFI_STATUS\r
211EFIAPI\r
212SmmReadSaveState (\r
213 IN CONST EFI_SMM_CPU_PROTOCOL *This,\r
214 IN UINTN Width,\r
215 IN EFI_SMM_SAVE_STATE_REGISTER Register,\r
216 IN UINTN CpuIndex,\r
217 OUT VOID *Buffer\r
218 )\r
219{\r
220 EFI_STATUS Status;\r
221\r
222 //\r
223 // Retrieve pointer to the specified CPU's SMM Save State buffer\r
224 //\r
225 if ((CpuIndex >= gSmst->NumberOfCpus) || (Buffer == NULL)) {\r
226 return EFI_INVALID_PARAMETER;\r
227 }\r
228\r
229 //\r
230 // Check for special EFI_SMM_SAVE_STATE_REGISTER_PROCESSOR_ID\r
231 //\r
232 if (Register == EFI_SMM_SAVE_STATE_REGISTER_PROCESSOR_ID) {\r
233 //\r
234 // The pseudo-register only supports the 64-bit size specified by Width.\r
235 //\r
236 if (Width != sizeof (UINT64)) {\r
237 return EFI_INVALID_PARAMETER;\r
238 }\r
239 //\r
240 // If the processor is in SMM at the time the SMI occurred,\r
241 // the pseudo register value for EFI_SMM_SAVE_STATE_REGISTER_PROCESSOR_ID is returned in Buffer.\r
242 // Otherwise, EFI_NOT_FOUND is returned.\r
243 //\r
244 if (*(mSmmMpSyncData->CpuData[CpuIndex].Present)) {\r
245 *(UINT64 *)Buffer = gSmmCpuPrivate->ProcessorInfo[CpuIndex].ProcessorId;\r
246 return EFI_SUCCESS;\r
247 } else {\r
248 return EFI_NOT_FOUND;\r
249 }\r
250 }\r
251\r
252 if (!(*(mSmmMpSyncData->CpuData[CpuIndex].Present))) {\r
253 return EFI_INVALID_PARAMETER;\r
254 }\r
255\r
256 Status = SmmCpuFeaturesReadSaveStateRegister (CpuIndex, Register, Width, Buffer);\r
257 if (Status == EFI_UNSUPPORTED) {\r
258 Status = ReadSaveStateRegister (CpuIndex, Register, Width, Buffer);\r
259 }\r
260 return Status;\r
261}\r
262\r
263/**\r
264 Write data to the CPU save state.\r
265\r
266 @param This EFI_SMM_CPU_PROTOCOL instance\r
267 @param Width The number of bytes to read from the CPU save state.\r
268 @param Register Specifies the CPU register to write to the save state.\r
269 @param CpuIndex Specifies the zero-based index of the CPU save state\r
270 @param Buffer Upon entry, this holds the new CPU register value.\r
271\r
272 @retval EFI_SUCCESS The register was written from Save State\r
273 @retval EFI_NOT_FOUND The register is not defined for the Save State of Processor\r
274 @retval EFI_INVALID_PARAMTER ProcessorIndex or Width is not correct\r
275\r
276**/\r
277EFI_STATUS\r
278EFIAPI\r
279SmmWriteSaveState (\r
280 IN CONST EFI_SMM_CPU_PROTOCOL *This,\r
281 IN UINTN Width,\r
282 IN EFI_SMM_SAVE_STATE_REGISTER Register,\r
283 IN UINTN CpuIndex,\r
284 IN CONST VOID *Buffer\r
285 )\r
286{\r
287 EFI_STATUS Status;\r
288\r
289 //\r
290 // Retrieve pointer to the specified CPU's SMM Save State buffer\r
291 //\r
292 if ((CpuIndex >= gSmst->NumberOfCpus) || (Buffer == NULL)) {\r
293 return EFI_INVALID_PARAMETER;\r
294 }\r
295\r
296 //\r
297 // Writes to EFI_SMM_SAVE_STATE_REGISTER_PROCESSOR_ID are ignored\r
298 //\r
299 if (Register == EFI_SMM_SAVE_STATE_REGISTER_PROCESSOR_ID) {\r
300 return EFI_SUCCESS;\r
301 }\r
302\r
303 if (!mSmmMpSyncData->CpuData[CpuIndex].Present) {\r
304 return EFI_INVALID_PARAMETER;\r
305 }\r
306\r
307 Status = SmmCpuFeaturesWriteSaveStateRegister (CpuIndex, Register, Width, Buffer);\r
308 if (Status == EFI_UNSUPPORTED) {\r
309 Status = WriteSaveStateRegister (CpuIndex, Register, Width, Buffer);\r
310 }\r
311 return Status;\r
312}\r
313\r
314\r
315/**\r
316 C function for SMI handler. To change all processor's SMMBase Register.\r
317\r
318**/\r
319VOID\r
320EFIAPI\r
321SmmInitHandler (\r
322 VOID\r
323 )\r
324{\r
325 UINT32 ApicId;\r
326 UINTN Index;\r
327\r
328 //\r
329 // Update SMM IDT entries' code segment and load IDT\r
330 //\r
331 AsmWriteIdtr (&gcSmiIdtr);\r
332 ApicId = GetApicId ();\r
333\r
334 ASSERT (mNumberOfCpus <= PcdGet32 (PcdCpuMaxLogicalProcessorNumber));\r
335\r
336 for (Index = 0; Index < mNumberOfCpus; Index++) {\r
337 if (ApicId == (UINT32)gSmmCpuPrivate->ProcessorInfo[Index].ProcessorId) {\r
338 //\r
339 // Initialize SMM specific features on the currently executing CPU\r
340 //\r
341 SmmCpuFeaturesInitializeProcessor (\r
342 Index,\r
343 mIsBsp,\r
344 gSmmCpuPrivate->ProcessorInfo,\r
345 &mCpuHotPlugData\r
346 );\r
347\r
348 if (!mSmmS3Flag) {\r
349 //\r
350 // Check XD and BTS features on each processor on normal boot\r
351 //\r
352 CheckFeatureSupported ();\r
353 }\r
354\r
355 if (mIsBsp) {\r
356 //\r
357 // BSP rebase is already done above.\r
358 // Initialize private data during S3 resume\r
359 //\r
360 InitializeMpSyncData ();\r
361 }\r
362\r
363 //\r
364 // Hook return after RSM to set SMM re-based flag\r
365 //\r
366 SemaphoreHook (Index, &mRebased[Index]);\r
367\r
368 return;\r
369 }\r
370 }\r
371 ASSERT (FALSE);\r
372}\r
373\r
374/**\r
375 Relocate SmmBases for each processor.\r
376\r
377 Execute on first boot and all S3 resumes\r
378\r
379**/\r
380VOID\r
381EFIAPI\r
382SmmRelocateBases (\r
383 VOID\r
384 )\r
385{\r
386 UINT8 BakBuf[BACK_BUF_SIZE];\r
387 SMRAM_SAVE_STATE_MAP BakBuf2;\r
388 SMRAM_SAVE_STATE_MAP *CpuStatePtr;\r
389 UINT8 *U8Ptr;\r
390 UINT32 ApicId;\r
391 UINTN Index;\r
392 UINTN BspIndex;\r
393\r
394 //\r
395 // Make sure the reserved size is large enough for procedure SmmInitTemplate.\r
396 //\r
397 ASSERT (sizeof (BakBuf) >= gcSmmInitSize);\r
398\r
399 //\r
400 // Patch ASM code template with current CR0, CR3, and CR4 values\r
401 //\r
402 gSmmCr0 = (UINT32)AsmReadCr0 ();\r
403 gSmmCr3 = (UINT32)AsmReadCr3 ();\r
404 gSmmCr4 = (UINT32)AsmReadCr4 ();\r
405\r
406 //\r
407 // Patch GDTR for SMM base relocation\r
408 //\r
409 gcSmiInitGdtr.Base = gcSmiGdtr.Base;\r
410 gcSmiInitGdtr.Limit = gcSmiGdtr.Limit;\r
411\r
412 U8Ptr = (UINT8*)(UINTN)(SMM_DEFAULT_SMBASE + SMM_HANDLER_OFFSET);\r
413 CpuStatePtr = (SMRAM_SAVE_STATE_MAP *)(UINTN)(SMM_DEFAULT_SMBASE + SMRAM_SAVE_STATE_MAP_OFFSET);\r
414\r
415 //\r
416 // Backup original contents at address 0x38000\r
417 //\r
418 CopyMem (BakBuf, U8Ptr, sizeof (BakBuf));\r
419 CopyMem (&BakBuf2, CpuStatePtr, sizeof (BakBuf2));\r
420\r
421 //\r
422 // Load image for relocation\r
423 //\r
424 CopyMem (U8Ptr, gcSmmInitTemplate, gcSmmInitSize);\r
425\r
426 //\r
427 // Retrieve the local APIC ID of current processor\r
428 //\r
429 ApicId = GetApicId ();\r
430\r
431 //\r
432 // Relocate SM bases for all APs\r
433 // This is APs' 1st SMI - rebase will be done here, and APs' default SMI handler will be overridden by gcSmmInitTemplate\r
434 //\r
435 mIsBsp = FALSE;\r
436 BspIndex = (UINTN)-1;\r
437 for (Index = 0; Index < mNumberOfCpus; Index++) {\r
438 mRebased[Index] = FALSE;\r
439 if (ApicId != (UINT32)gSmmCpuPrivate->ProcessorInfo[Index].ProcessorId) {\r
440 SendSmiIpi ((UINT32)gSmmCpuPrivate->ProcessorInfo[Index].ProcessorId);\r
441 //\r
442 // Wait for this AP to finish its 1st SMI\r
443 //\r
444 while (!mRebased[Index]);\r
445 } else {\r
446 //\r
447 // BSP will be Relocated later\r
448 //\r
449 BspIndex = Index;\r
450 }\r
451 }\r
452\r
453 //\r
454 // Relocate BSP's SMM base\r
455 //\r
456 ASSERT (BspIndex != (UINTN)-1);\r
457 mIsBsp = TRUE;\r
458 SendSmiIpi (ApicId);\r
459 //\r
460 // Wait for the BSP to finish its 1st SMI\r
461 //\r
462 while (!mRebased[BspIndex]);\r
463\r
464 //\r
465 // Restore contents at address 0x38000\r
466 //\r
467 CopyMem (CpuStatePtr, &BakBuf2, sizeof (BakBuf2));\r
468 CopyMem (U8Ptr, BakBuf, sizeof (BakBuf));\r
469}\r
470\r
471/**\r
472 SMM Ready To Lock event notification handler.\r
473\r
474 The CPU S3 data is copied to SMRAM for security and mSmmReadyToLock is set to\r
475 perform additional lock actions that must be performed from SMM on the next SMI.\r
476\r
477 @param[in] Protocol Points to the protocol's unique identifier.\r
478 @param[in] Interface Points to the interface instance.\r
479 @param[in] Handle The handle on which the interface was installed.\r
480\r
481 @retval EFI_SUCCESS Notification handler runs successfully.\r
482 **/\r
483EFI_STATUS\r
484EFIAPI\r
485SmmReadyToLockEventNotify (\r
486 IN CONST EFI_GUID *Protocol,\r
487 IN VOID *Interface,\r
488 IN EFI_HANDLE Handle\r
489 )\r
490{\r
491 GetAcpiCpuData ();\r
492\r
493 //\r
494 // Set SMM ready to lock flag and return\r
495 //\r
496 mSmmReadyToLock = TRUE;\r
497 return EFI_SUCCESS;\r
498}\r
499\r
500/**\r
501 The module Entry Point of the CPU SMM driver.\r
502\r
503 @param ImageHandle The firmware allocated handle for the EFI image.\r
504 @param SystemTable A pointer to the EFI System Table.\r
505\r
506 @retval EFI_SUCCESS The entry point is executed successfully.\r
507 @retval Other Some error occurs when executing this entry point.\r
508\r
509**/\r
510EFI_STATUS\r
511EFIAPI\r
512PiCpuSmmEntry (\r
513 IN EFI_HANDLE ImageHandle,\r
514 IN EFI_SYSTEM_TABLE *SystemTable\r
515 )\r
516{\r
517 EFI_STATUS Status;\r
518 EFI_MP_SERVICES_PROTOCOL *MpServices;\r
519 UINTN NumberOfEnabledProcessors;\r
520 UINTN Index;\r
521 VOID *Buffer;\r
522 UINTN BufferPages;\r
523 UINTN TileCodeSize;\r
524 UINTN TileDataSize;\r
525 UINTN TileSize;\r
526 UINT8 *Stacks;\r
527 VOID *Registration;\r
528 UINT32 RegEax;\r
529 UINT32 RegEdx;\r
530 UINTN FamilyId;\r
531 UINTN ModelId;\r
532 UINT32 Cr3;\r
533\r
534 //\r
535 // Initialize Debug Agent to support source level debug in SMM code\r
536 //\r
537 InitializeDebugAgent (DEBUG_AGENT_INIT_SMM, NULL, NULL);\r
538\r
539 //\r
540 // Report the start of CPU SMM initialization.\r
541 //\r
542 REPORT_STATUS_CODE (\r
543 EFI_PROGRESS_CODE,\r
544 EFI_COMPUTING_UNIT_HOST_PROCESSOR | EFI_CU_HP_PC_SMM_INIT\r
545 );\r
546\r
547 //\r
548 // Fix segment address of the long-mode-switch jump\r
549 //\r
550 if (sizeof (UINTN) == sizeof (UINT64)) {\r
551 gSmmJmpAddr.Segment = LONG_MODE_CODE_SEGMENT;\r
552 }\r
553\r
554 //\r
555 // Find out SMRR Base and SMRR Size\r
556 //\r
557 FindSmramInfo (&mCpuHotPlugData.SmrrBase, &mCpuHotPlugData.SmrrSize);\r
558\r
559 //\r
560 // Get MP Services Protocol\r
561 //\r
562 Status = SystemTable->BootServices->LocateProtocol (&gEfiMpServiceProtocolGuid, NULL, (VOID **)&MpServices);\r
563 ASSERT_EFI_ERROR (Status);\r
564\r
565 //\r
566 // Use MP Services Protocol to retrieve the number of processors and number of enabled processors\r
567 //\r
568 Status = MpServices->GetNumberOfProcessors (MpServices, &mNumberOfCpus, &NumberOfEnabledProcessors);\r
569 ASSERT_EFI_ERROR (Status);\r
570 ASSERT (mNumberOfCpus <= PcdGet32 (PcdCpuMaxLogicalProcessorNumber));\r
571\r
572 //\r
573 // If support CPU hot plug, PcdCpuSmmEnableBspElection should be set to TRUE.\r
574 // A constant BSP index makes no sense because it may be hot removed.\r
575 //\r
576 DEBUG_CODE (\r
577 if (FeaturePcdGet (PcdCpuHotPlugSupport)) {\r
578\r
579 ASSERT (FeaturePcdGet (PcdCpuSmmEnableBspElection));\r
580 }\r
581 );\r
582\r
583 //\r
584 // Save the PcdCpuSmmCodeAccessCheckEnable value into a global variable.\r
585 //\r
586 mSmmCodeAccessCheckEnable = PcdGetBool (PcdCpuSmmCodeAccessCheckEnable);\r
587 DEBUG ((EFI_D_INFO, "PcdCpuSmmCodeAccessCheckEnable = %d\n", mSmmCodeAccessCheckEnable));\r
588\r
589 //\r
590 // If support CPU hot plug, we need to allocate resources for possibly hot-added processors\r
591 //\r
592 if (FeaturePcdGet (PcdCpuHotPlugSupport)) {\r
593 mMaxNumberOfCpus = PcdGet32 (PcdCpuMaxLogicalProcessorNumber);\r
594 } else {\r
595 mMaxNumberOfCpus = mNumberOfCpus;\r
596 }\r
597 gSmmCpuPrivate->SmmCoreEntryContext.NumberOfCpus = mMaxNumberOfCpus;\r
598\r
599 //\r
600 // The CPU save state and code for the SMI entry point are tiled within an SMRAM\r
601 // allocated buffer. The minimum size of this buffer for a uniprocessor system\r
602 // is 32 KB, because the entry point is SMBASE + 32KB, and CPU save state area\r
603 // just below SMBASE + 64KB. If more than one CPU is present in the platform,\r
604 // then the SMI entry point and the CPU save state areas can be tiles to minimize\r
605 // the total amount SMRAM required for all the CPUs. The tile size can be computed\r
606 // by adding the // CPU save state size, any extra CPU specific context, and\r
607 // the size of code that must be placed at the SMI entry point to transfer\r
608 // control to a C function in the native SMM execution mode. This size is\r
609 // rounded up to the nearest power of 2 to give the tile size for a each CPU.\r
610 // The total amount of memory required is the maximum number of CPUs that\r
611 // platform supports times the tile size. The picture below shows the tiling,\r
612 // where m is the number of tiles that fit in 32KB.\r
613 //\r
614 // +-----------------------------+ <-- 2^n offset from Base of allocated buffer\r
615 // | CPU m+1 Save State |\r
616 // +-----------------------------+\r
617 // | CPU m+1 Extra Data |\r
618 // +-----------------------------+\r
619 // | Padding |\r
620 // +-----------------------------+\r
621 // | CPU 2m SMI Entry |\r
622 // +#############################+ <-- Base of allocated buffer + 64 KB\r
623 // | CPU m-1 Save State |\r
624 // +-----------------------------+\r
625 // | CPU m-1 Extra Data |\r
626 // +-----------------------------+\r
627 // | Padding |\r
628 // +-----------------------------+\r
629 // | CPU 2m-1 SMI Entry |\r
630 // +=============================+ <-- 2^n offset from Base of allocated buffer\r
631 // | . . . . . . . . . . . . |\r
632 // +=============================+ <-- 2^n offset from Base of allocated buffer\r
633 // | CPU 2 Save State |\r
634 // +-----------------------------+\r
635 // | CPU 2 Extra Data |\r
636 // +-----------------------------+\r
637 // | Padding |\r
638 // +-----------------------------+\r
639 // | CPU m+1 SMI Entry |\r
640 // +=============================+ <-- Base of allocated buffer + 32 KB\r
641 // | CPU 1 Save State |\r
642 // +-----------------------------+\r
643 // | CPU 1 Extra Data |\r
644 // +-----------------------------+\r
645 // | Padding |\r
646 // +-----------------------------+\r
647 // | CPU m SMI Entry |\r
648 // +#############################+ <-- Base of allocated buffer + 32 KB == CPU 0 SMBASE + 64 KB\r
649 // | CPU 0 Save State |\r
650 // +-----------------------------+\r
651 // | CPU 0 Extra Data |\r
652 // +-----------------------------+\r
653 // | Padding |\r
654 // +-----------------------------+\r
655 // | CPU m-1 SMI Entry |\r
656 // +=============================+ <-- 2^n offset from Base of allocated buffer\r
657 // | . . . . . . . . . . . . |\r
658 // +=============================+ <-- 2^n offset from Base of allocated buffer\r
659 // | Padding |\r
660 // +-----------------------------+\r
661 // | CPU 1 SMI Entry |\r
662 // +=============================+ <-- 2^n offset from Base of allocated buffer\r
663 // | Padding |\r
664 // +-----------------------------+\r
665 // | CPU 0 SMI Entry |\r
666 // +#############################+ <-- Base of allocated buffer == CPU 0 SMBASE + 32 KB\r
667 //\r
668\r
669 //\r
670 // Retrieve CPU Family\r
671 //\r
672 AsmCpuid (CPUID_VERSION_INFO, &RegEax, NULL, NULL, NULL);\r
673 FamilyId = (RegEax >> 8) & 0xf;\r
674 ModelId = (RegEax >> 4) & 0xf;\r
675 if (FamilyId == 0x06 || FamilyId == 0x0f) {\r
676 ModelId = ModelId | ((RegEax >> 12) & 0xf0);\r
677 }\r
678\r
679 RegEdx = 0;\r
680 AsmCpuid (CPUID_EXTENDED_FUNCTION, &RegEax, NULL, NULL, NULL);\r
681 if (RegEax >= CPUID_EXTENDED_CPU_SIG) {\r
682 AsmCpuid (CPUID_EXTENDED_CPU_SIG, NULL, NULL, NULL, &RegEdx);\r
683 }\r
684 //\r
685 // Determine the mode of the CPU at the time an SMI occurs\r
686 // Intel(R) 64 and IA-32 Architectures Software Developer's Manual\r
687 // Volume 3C, Section 34.4.1.1\r
688 //\r
689 mSmmSaveStateRegisterLma = EFI_SMM_SAVE_STATE_REGISTER_LMA_32BIT;\r
690 if ((RegEdx & BIT29) != 0) {\r
691 mSmmSaveStateRegisterLma = EFI_SMM_SAVE_STATE_REGISTER_LMA_64BIT;\r
692 }\r
693 if (FamilyId == 0x06) {\r
694 if (ModelId == 0x17 || ModelId == 0x0f || ModelId == 0x1c) {\r
695 mSmmSaveStateRegisterLma = EFI_SMM_SAVE_STATE_REGISTER_LMA_64BIT;\r
696 }\r
697 }\r
698\r
699 //\r
700 // Compute tile size of buffer required to hold the CPU SMRAM Save State Map, extra CPU\r
701 // specific context in a PROCESSOR_SMM_DESCRIPTOR, and the SMI entry point. This size\r
702 // is rounded up to nearest power of 2.\r
703 //\r
704 TileCodeSize = GetSmiHandlerSize ();\r
705 TileCodeSize = ALIGN_VALUE(TileCodeSize, SIZE_4KB);\r
706 TileDataSize = sizeof (SMRAM_SAVE_STATE_MAP) + sizeof (PROCESSOR_SMM_DESCRIPTOR);\r
707 TileDataSize = ALIGN_VALUE(TileDataSize, SIZE_4KB);\r
708 TileSize = TileDataSize + TileCodeSize - 1;\r
709 TileSize = 2 * GetPowerOfTwo32 ((UINT32)TileSize);\r
710 DEBUG ((EFI_D_INFO, "SMRAM TileSize = 0x%08x (0x%08x, 0x%08x)\n", TileSize, TileCodeSize, TileDataSize));\r
711\r
712 //\r
713 // If the TileSize is larger than space available for the SMI Handler of CPU[i],\r
714 // the PROCESSOR_SMM_DESCRIPTOR of CPU[i+1] and the SMRAM Save State Map of CPU[i+1],\r
715 // the ASSERT(). If this ASSERT() is triggered, then the SMI Handler size must be\r
716 // reduced.\r
717 //\r
718 ASSERT (TileSize <= (SMRAM_SAVE_STATE_MAP_OFFSET + sizeof (SMRAM_SAVE_STATE_MAP) - SMM_HANDLER_OFFSET));\r
719\r
720 //\r
721 // Allocate buffer for all of the tiles.\r
722 //\r
723 // Intel(R) 64 and IA-32 Architectures Software Developer's Manual\r
724 // Volume 3C, Section 34.11 SMBASE Relocation\r
725 // For Pentium and Intel486 processors, the SMBASE values must be\r
726 // aligned on a 32-KByte boundary or the processor will enter shutdown\r
727 // state during the execution of a RSM instruction.\r
728 //\r
729 // Intel486 processors: FamilyId is 4\r
730 // Pentium processors : FamilyId is 5\r
731 //\r
732 BufferPages = EFI_SIZE_TO_PAGES (SIZE_32KB + TileSize * (mMaxNumberOfCpus - 1));\r
733 if ((FamilyId == 4) || (FamilyId == 5)) {\r
734 Buffer = AllocateAlignedPages (BufferPages, SIZE_32KB);\r
735 } else {\r
736 Buffer = AllocateAlignedPages (BufferPages, SIZE_4KB);\r
737 }\r
738 ASSERT (Buffer != NULL);\r
739 DEBUG ((EFI_D_INFO, "SMRAM SaveState Buffer (0x%08x, 0x%08x)\n", Buffer, EFI_PAGES_TO_SIZE(BufferPages)));\r
740\r
741 //\r
742 // Allocate buffer for pointers to array in SMM_CPU_PRIVATE_DATA.\r
743 //\r
744 gSmmCpuPrivate->ProcessorInfo = (EFI_PROCESSOR_INFORMATION *)AllocatePool (sizeof (EFI_PROCESSOR_INFORMATION) * mMaxNumberOfCpus);\r
745 ASSERT (gSmmCpuPrivate->ProcessorInfo != NULL);\r
746\r
747 gSmmCpuPrivate->Operation = (SMM_CPU_OPERATION *)AllocatePool (sizeof (SMM_CPU_OPERATION) * mMaxNumberOfCpus);\r
748 ASSERT (gSmmCpuPrivate->Operation != NULL);\r
749\r
750 gSmmCpuPrivate->CpuSaveStateSize = (UINTN *)AllocatePool (sizeof (UINTN) * mMaxNumberOfCpus);\r
751 ASSERT (gSmmCpuPrivate->CpuSaveStateSize != NULL);\r
752\r
753 gSmmCpuPrivate->CpuSaveState = (VOID **)AllocatePool (sizeof (VOID *) * mMaxNumberOfCpus);\r
754 ASSERT (gSmmCpuPrivate->CpuSaveState != NULL);\r
755\r
756 mSmmCpuPrivateData.SmmCoreEntryContext.CpuSaveStateSize = gSmmCpuPrivate->CpuSaveStateSize;\r
757 mSmmCpuPrivateData.SmmCoreEntryContext.CpuSaveState = gSmmCpuPrivate->CpuSaveState;\r
758\r
759 //\r
760 // Allocate buffer for pointers to array in CPU_HOT_PLUG_DATA.\r
761 //\r
762 mCpuHotPlugData.ApicId = (UINT64 *)AllocatePool (sizeof (UINT64) * mMaxNumberOfCpus);\r
763 ASSERT (mCpuHotPlugData.ApicId != NULL);\r
764 mCpuHotPlugData.SmBase = (UINTN *)AllocatePool (sizeof (UINTN) * mMaxNumberOfCpus);\r
765 ASSERT (mCpuHotPlugData.SmBase != NULL);\r
766 mCpuHotPlugData.ArrayLength = (UINT32)mMaxNumberOfCpus;\r
767\r
768 //\r
769 // Retrieve APIC ID of each enabled processor from the MP Services protocol.\r
770 // Also compute the SMBASE address, CPU Save State address, and CPU Save state\r
771 // size for each CPU in the platform\r
772 //\r
773 for (Index = 0; Index < mMaxNumberOfCpus; Index++) {\r
774 mCpuHotPlugData.SmBase[Index] = (UINTN)Buffer + Index * TileSize - SMM_HANDLER_OFFSET;\r
775 gSmmCpuPrivate->CpuSaveStateSize[Index] = sizeof(SMRAM_SAVE_STATE_MAP);\r
776 gSmmCpuPrivate->CpuSaveState[Index] = (VOID *)(mCpuHotPlugData.SmBase[Index] + SMRAM_SAVE_STATE_MAP_OFFSET);\r
777 gSmmCpuPrivate->Operation[Index] = SmmCpuNone;\r
778\r
779 if (Index < mNumberOfCpus) {\r
780 Status = MpServices->GetProcessorInfo (MpServices, Index, &gSmmCpuPrivate->ProcessorInfo[Index]);\r
781 ASSERT_EFI_ERROR (Status);\r
782 mCpuHotPlugData.ApicId[Index] = gSmmCpuPrivate->ProcessorInfo[Index].ProcessorId;\r
783\r
784 DEBUG ((EFI_D_INFO, "CPU[%03x] APIC ID=%04x SMBASE=%08x SaveState=%08x Size=%08x\n",\r
785 Index,\r
786 (UINT32)gSmmCpuPrivate->ProcessorInfo[Index].ProcessorId,\r
787 mCpuHotPlugData.SmBase[Index],\r
788 gSmmCpuPrivate->CpuSaveState[Index],\r
789 gSmmCpuPrivate->CpuSaveStateSize[Index]\r
790 ));\r
791 } else {\r
792 gSmmCpuPrivate->ProcessorInfo[Index].ProcessorId = INVALID_APIC_ID;\r
793 mCpuHotPlugData.ApicId[Index] = INVALID_APIC_ID;\r
794 }\r
795 }\r
796\r
797 //\r
798 // Allocate SMI stacks for all processors.\r
799 //\r
800 if (FeaturePcdGet (PcdCpuSmmStackGuard)) {\r
801 //\r
802 // 2 more pages is allocated for each processor.\r
803 // one is guard page and the other is known good stack.\r
804 //\r
805 // +-------------------------------------------+-----+-------------------------------------------+\r
806 // | Known Good Stack | Guard Page | SMM Stack | ... | Known Good Stack | Guard Page | SMM Stack |\r
807 // +-------------------------------------------+-----+-------------------------------------------+\r
808 // | | | |\r
809 // |<-------------- Processor 0 -------------->| |<-------------- Processor n -------------->|\r
810 //\r
811 mSmmStackSize = EFI_PAGES_TO_SIZE (EFI_SIZE_TO_PAGES (PcdGet32 (PcdCpuSmmStackSize)) + 2);\r
812 Stacks = (UINT8 *) AllocatePages (gSmmCpuPrivate->SmmCoreEntryContext.NumberOfCpus * (EFI_SIZE_TO_PAGES (PcdGet32 (PcdCpuSmmStackSize)) + 2));\r
813 ASSERT (Stacks != NULL);\r
814 mSmmStackArrayBase = (UINTN)Stacks;\r
815 mSmmStackArrayEnd = mSmmStackArrayBase + gSmmCpuPrivate->SmmCoreEntryContext.NumberOfCpus * mSmmStackSize - 1;\r
816 } else {\r
817 mSmmStackSize = PcdGet32 (PcdCpuSmmStackSize);\r
818 Stacks = (UINT8 *) AllocatePages (EFI_SIZE_TO_PAGES (gSmmCpuPrivate->SmmCoreEntryContext.NumberOfCpus * mSmmStackSize));\r
819 ASSERT (Stacks != NULL);\r
820 }\r
821\r
822 //\r
823 // Set SMI stack for SMM base relocation\r
824 //\r
825 gSmmInitStack = (UINTN) (Stacks + mSmmStackSize - sizeof (UINTN));\r
826\r
827 //\r
828 // Initialize IDT\r
829 //\r
830 InitializeSmmIdt ();\r
831\r
832 //\r
833 // Relocate SMM Base addresses to the ones allocated from SMRAM\r
834 //\r
835 mRebased = (BOOLEAN *)AllocateZeroPool (sizeof (BOOLEAN) * mMaxNumberOfCpus);\r
836 ASSERT (mRebased != NULL);\r
837 SmmRelocateBases ();\r
838\r
839 //\r
840 // Call hook for BSP to perform extra actions in normal mode after all\r
841 // SMM base addresses have been relocated on all CPUs\r
842 //\r
843 SmmCpuFeaturesSmmRelocationComplete ();\r
844\r
845 //\r
846 // SMM Time initialization\r
847 //\r
848 InitializeSmmTimer ();\r
849\r
850 //\r
851 // Initialize MP globals\r
852 //\r
853 Cr3 = InitializeMpServiceData (Stacks, mSmmStackSize);\r
854\r
855 //\r
856 // Fill in SMM Reserved Regions\r
857 //\r
858 gSmmCpuPrivate->SmmReservedSmramRegion[0].SmramReservedStart = 0;\r
859 gSmmCpuPrivate->SmmReservedSmramRegion[0].SmramReservedSize = 0;\r
860\r
861 //\r
862 // Install the SMM Configuration Protocol onto a new handle on the handle database.\r
863 // The entire SMM Configuration Protocol is allocated from SMRAM, so only a pointer\r
864 // to an SMRAM address will be present in the handle database\r
865 //\r
866 Status = SystemTable->BootServices->InstallMultipleProtocolInterfaces (\r
867 &gSmmCpuPrivate->SmmCpuHandle,\r
868 &gEfiSmmConfigurationProtocolGuid, &gSmmCpuPrivate->SmmConfiguration,\r
869 NULL\r
870 );\r
871 ASSERT_EFI_ERROR (Status);\r
872\r
873 //\r
874 // Install the SMM CPU Protocol into SMM protocol database\r
875 //\r
876 Status = gSmst->SmmInstallProtocolInterface (\r
877 &mSmmCpuHandle,\r
878 &gEfiSmmCpuProtocolGuid,\r
879 EFI_NATIVE_INTERFACE,\r
880 &mSmmCpu\r
881 );\r
882 ASSERT_EFI_ERROR (Status);\r
883\r
884 //\r
885 // Expose address of CPU Hot Plug Data structure if CPU hot plug is supported.\r
886 //\r
887 if (FeaturePcdGet (PcdCpuHotPlugSupport)) {\r
888 Status = PcdSet64S (PcdCpuHotPlugDataAddress, (UINT64)(UINTN)&mCpuHotPlugData);\r
889 ASSERT_EFI_ERROR (Status);\r
890 }\r
891\r
892 //\r
893 // Initialize SMM CPU Services Support\r
894 //\r
895 Status = InitializeSmmCpuServices (mSmmCpuHandle);\r
896 ASSERT_EFI_ERROR (Status);\r
897\r
898 //\r
899 // register SMM Ready To Lock Protocol notification\r
900 //\r
901 Status = gSmst->SmmRegisterProtocolNotify (\r
902 &gEfiSmmReadyToLockProtocolGuid,\r
903 SmmReadyToLockEventNotify,\r
904 &Registration\r
905 );\r
906 ASSERT_EFI_ERROR (Status);\r
907\r
908 //\r
909 // Initialize SMM Profile feature\r
910 //\r
911 InitSmmProfile (Cr3);\r
912\r
913 GetAcpiS3EnableFlag ();\r
914 InitSmmS3ResumeState (Cr3);\r
915\r
916 DEBUG ((EFI_D_INFO, "SMM CPU Module exit from SMRAM with EFI_SUCCESS\n"));\r
917\r
918 return EFI_SUCCESS;\r
919}\r
920\r
921/**\r
922\r
923 Find out SMRAM information including SMRR base and SMRR size.\r
924\r
925 @param SmrrBase SMRR base\r
926 @param SmrrSize SMRR size\r
927\r
928**/\r
929VOID\r
930FindSmramInfo (\r
931 OUT UINT32 *SmrrBase,\r
932 OUT UINT32 *SmrrSize\r
933 )\r
934{\r
935 EFI_STATUS Status;\r
936 UINTN Size;\r
937 EFI_SMM_ACCESS2_PROTOCOL *SmmAccess;\r
938 EFI_SMRAM_DESCRIPTOR *CurrentSmramRange;\r
939 EFI_SMRAM_DESCRIPTOR *SmramRanges;\r
940 UINTN SmramRangeCount;\r
941 UINTN Index;\r
942 UINT64 MaxSize;\r
943 BOOLEAN Found;\r
944\r
945 //\r
946 // Get SMM Access Protocol\r
947 //\r
948 Status = gBS->LocateProtocol (&gEfiSmmAccess2ProtocolGuid, NULL, (VOID **)&SmmAccess);\r
949 ASSERT_EFI_ERROR (Status);\r
950\r
951 //\r
952 // Get SMRAM information\r
953 //\r
954 Size = 0;\r
955 Status = SmmAccess->GetCapabilities (SmmAccess, &Size, NULL);\r
956 ASSERT (Status == EFI_BUFFER_TOO_SMALL);\r
957\r
958 SmramRanges = (EFI_SMRAM_DESCRIPTOR *)AllocatePool (Size);\r
959 ASSERT (SmramRanges != NULL);\r
960\r
961 Status = SmmAccess->GetCapabilities (SmmAccess, &Size, SmramRanges);\r
962 ASSERT_EFI_ERROR (Status);\r
963\r
964 SmramRangeCount = Size / sizeof (EFI_SMRAM_DESCRIPTOR);\r
965\r
966 //\r
967 // Find the largest SMRAM range between 1MB and 4GB that is at least 256K - 4K in size\r
968 //\r
969 CurrentSmramRange = NULL;\r
970 for (Index = 0, MaxSize = SIZE_256KB - EFI_PAGE_SIZE; Index < SmramRangeCount; Index++) {\r
971 //\r
972 // Skip any SMRAM region that is already allocated, needs testing, or needs ECC initialization\r
973 //\r
974 if ((SmramRanges[Index].RegionState & (EFI_ALLOCATED | EFI_NEEDS_TESTING | EFI_NEEDS_ECC_INITIALIZATION)) != 0) {\r
975 continue;\r
976 }\r
977\r
978 if (SmramRanges[Index].CpuStart >= BASE_1MB) {\r
979 if ((SmramRanges[Index].CpuStart + SmramRanges[Index].PhysicalSize) <= BASE_4GB) {\r
980 if (SmramRanges[Index].PhysicalSize >= MaxSize) {\r
981 MaxSize = SmramRanges[Index].PhysicalSize;\r
982 CurrentSmramRange = &SmramRanges[Index];\r
983 }\r
984 }\r
985 }\r
986 }\r
987\r
988 ASSERT (CurrentSmramRange != NULL);\r
989\r
990 *SmrrBase = (UINT32)CurrentSmramRange->CpuStart;\r
991 *SmrrSize = (UINT32)CurrentSmramRange->PhysicalSize;\r
992\r
993 do {\r
994 Found = FALSE;\r
995 for (Index = 0; Index < SmramRangeCount; Index++) {\r
996 if (SmramRanges[Index].CpuStart < *SmrrBase && *SmrrBase == (SmramRanges[Index].CpuStart + SmramRanges[Index].PhysicalSize)) {\r
997 *SmrrBase = (UINT32)SmramRanges[Index].CpuStart;\r
998 *SmrrSize = (UINT32)(*SmrrSize + SmramRanges[Index].PhysicalSize);\r
999 Found = TRUE;\r
1000 } else if ((*SmrrBase + *SmrrSize) == SmramRanges[Index].CpuStart && SmramRanges[Index].PhysicalSize > 0) {\r
1001 *SmrrSize = (UINT32)(*SmrrSize + SmramRanges[Index].PhysicalSize);\r
1002 Found = TRUE;\r
1003 }\r
1004 }\r
1005 } while (Found);\r
1006\r
1007 FreePool (SmramRanges);\r
1008 DEBUG ((EFI_D_INFO, "SMRR Base: 0x%x, SMRR Size: 0x%x\n", *SmrrBase, *SmrrSize));\r
1009}\r
1010\r
1011/**\r
1012Configure SMM Code Access Check feature on an AP.\r
1013SMM Feature Control MSR will be locked after configuration.\r
1014\r
1015@param[in,out] Buffer Pointer to private data buffer.\r
1016**/\r
1017VOID\r
1018EFIAPI\r
1019ConfigSmmCodeAccessCheckOnCurrentProcessor (\r
1020 IN OUT VOID *Buffer\r
1021 )\r
1022{\r
1023 UINTN CpuIndex;\r
1024 UINT64 SmmFeatureControlMsr;\r
1025 UINT64 NewSmmFeatureControlMsr;\r
1026\r
1027 //\r
1028 // Retrieve the CPU Index from the context passed in\r
1029 //\r
1030 CpuIndex = *(UINTN *)Buffer;\r
1031\r
1032 //\r
1033 // Get the current SMM Feature Control MSR value\r
1034 //\r
1035 SmmFeatureControlMsr = SmmCpuFeaturesGetSmmRegister (CpuIndex, SmmRegFeatureControl);\r
1036\r
1037 //\r
1038 // Compute the new SMM Feature Control MSR value\r
1039 //\r
1040 NewSmmFeatureControlMsr = SmmFeatureControlMsr;\r
1041 if (mSmmCodeAccessCheckEnable) {\r
1042 NewSmmFeatureControlMsr |= SMM_CODE_CHK_EN_BIT;\r
1043 if (FeaturePcdGet (PcdCpuSmmFeatureControlMsrLock)) {\r
1044 NewSmmFeatureControlMsr |= SMM_FEATURE_CONTROL_LOCK_BIT;\r
1045 }\r
1046 }\r
1047\r
1048 //\r
1049 // Only set the SMM Feature Control MSR value if the new value is different than the current value\r
1050 //\r
1051 if (NewSmmFeatureControlMsr != SmmFeatureControlMsr) {\r
1052 SmmCpuFeaturesSetSmmRegister (CpuIndex, SmmRegFeatureControl, NewSmmFeatureControlMsr);\r
1053 }\r
1054\r
1055 //\r
1056 // Release the spin lock user to serialize the updates to the SMM Feature Control MSR\r
1057 //\r
1058 ReleaseSpinLock (mConfigSmmCodeAccessCheckLock);\r
1059}\r
1060\r
1061/**\r
1062Configure SMM Code Access Check feature for all processors.\r
1063SMM Feature Control MSR will be locked after configuration.\r
1064**/\r
1065VOID\r
1066ConfigSmmCodeAccessCheck (\r
1067 VOID\r
1068 )\r
1069{\r
1070 UINTN Index;\r
1071 EFI_STATUS Status;\r
1072\r
1073 //\r
1074 // Check to see if the Feature Control MSR is supported on this CPU\r
1075 //\r
1076 Index = gSmmCpuPrivate->SmmCoreEntryContext.CurrentlyExecutingCpu;\r
1077 if (!SmmCpuFeaturesIsSmmRegisterSupported (Index, SmmRegFeatureControl)) {\r
1078 mSmmCodeAccessCheckEnable = FALSE;\r
1079 return;\r
1080 }\r
1081\r
1082 //\r
1083 // Check to see if the CPU supports the SMM Code Access Check feature\r
1084 // Do not access this MSR unless the CPU supports the SmmRegFeatureControl\r
1085 //\r
1086 if ((AsmReadMsr64 (EFI_MSR_SMM_MCA_CAP) & SMM_CODE_ACCESS_CHK_BIT) == 0) {\r
1087 mSmmCodeAccessCheckEnable = FALSE;\r
1088 return;\r
1089 }\r
1090\r
1091 //\r
1092 // Initialize the lock used to serialize the MSR programming in BSP and all APs\r
1093 //\r
1094 InitializeSpinLock (mConfigSmmCodeAccessCheckLock);\r
1095\r
1096 //\r
1097 // Acquire Config SMM Code Access Check spin lock. The BSP will release the\r
1098 // spin lock when it is done executing ConfigSmmCodeAccessCheckOnCurrentProcessor().\r
1099 //\r
1100 AcquireSpinLock (mConfigSmmCodeAccessCheckLock);\r
1101\r
1102 //\r
1103 // Enable SMM Code Access Check feature on the BSP.\r
1104 //\r
1105 ConfigSmmCodeAccessCheckOnCurrentProcessor (&Index);\r
1106\r
1107 //\r
1108 // Enable SMM Code Access Check feature for the APs.\r
1109 //\r
1110 for (Index = 0; Index < gSmst->NumberOfCpus; Index++) {\r
1111 if (Index != gSmmCpuPrivate->SmmCoreEntryContext.CurrentlyExecutingCpu) {\r
1112\r
1113 //\r
1114 // Acquire Config SMM Code Access Check spin lock. The AP will release the\r
1115 // spin lock when it is done executing ConfigSmmCodeAccessCheckOnCurrentProcessor().\r
1116 //\r
1117 AcquireSpinLock (mConfigSmmCodeAccessCheckLock);\r
1118\r
1119 //\r
1120 // Call SmmStartupThisAp() to enable SMM Code Access Check on an AP.\r
1121 //\r
1122 Status = gSmst->SmmStartupThisAp (ConfigSmmCodeAccessCheckOnCurrentProcessor, Index, &Index);\r
1123 ASSERT_EFI_ERROR (Status);\r
1124\r
1125 //\r
1126 // Wait for the AP to release the Config SMM Code Access Check spin lock.\r
1127 //\r
1128 while (!AcquireSpinLockOrFail (mConfigSmmCodeAccessCheckLock)) {\r
1129 CpuPause ();\r
1130 }\r
1131\r
1132 //\r
1133 // Release the Config SMM Code Access Check spin lock.\r
1134 //\r
1135 ReleaseSpinLock (mConfigSmmCodeAccessCheckLock);\r
1136 }\r
1137 }\r
1138}\r
1139\r
1140/**\r
1141 This API provides a way to allocate memory for page table.\r
1142\r
1143 This API can be called more once to allocate memory for page tables.\r
1144\r
1145 Allocates the number of 4KB pages of type EfiRuntimeServicesData and returns a pointer to the\r
1146 allocated buffer. The buffer returned is aligned on a 4KB boundary. If Pages is 0, then NULL\r
1147 is returned. If there is not enough memory remaining to satisfy the request, then NULL is\r
1148 returned.\r
1149\r
1150 @param Pages The number of 4 KB pages to allocate.\r
1151\r
1152 @return A pointer to the allocated buffer or NULL if allocation fails.\r
1153\r
1154**/\r
1155VOID *\r
1156AllocatePageTableMemory (\r
1157 IN UINTN Pages\r
1158 )\r
1159{\r
1160 VOID *Buffer;\r
1161\r
1162 Buffer = SmmCpuFeaturesAllocatePageTableMemory (Pages);\r
1163 if (Buffer != NULL) {\r
1164 return Buffer;\r
1165 }\r
1166 return AllocatePages (Pages);\r
1167}\r
1168\r
1169/**\r
1170 Perform the remaining tasks.\r
1171\r
1172**/\r
1173VOID\r
1174PerformRemainingTasks (\r
1175 VOID\r
1176 )\r
1177{\r
1178 if (mSmmReadyToLock) {\r
1179 //\r
1180 // Start SMM Profile feature\r
1181 //\r
1182 if (FeaturePcdGet (PcdCpuSmmProfileEnable)) {\r
1183 SmmProfileStart ();\r
1184 }\r
1185 //\r
1186 // Create a mix of 2MB and 4KB page table. Update some memory ranges absent and execute-disable.\r
1187 //\r
1188 InitPaging ();\r
1189 //\r
1190 // Configure SMM Code Access Check feature if available.\r
1191 //\r
1192 ConfigSmmCodeAccessCheck ();\r
1193\r
1194 SmmCpuFeaturesCompleteSmmReadyToLock ();\r
1195\r
1196 //\r
1197 // Clean SMM ready to lock flag\r
1198 //\r
1199 mSmmReadyToLock = FALSE;\r
1200 }\r
1201}\r
1202\r
1203/**\r
1204 Perform the pre tasks.\r
1205\r
1206**/\r
1207VOID\r
1208PerformPreTasks (\r
1209 VOID\r
1210 )\r
1211{\r
1212 RestoreSmmConfigurationInS3 ();\r
1213}\r