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