//************************************************************************* //************************************************************************* //** ** //** (C)Copyright 1985-2011, American Megatrends, Inc. ** //** ** //** All Rights Reserved. ** //** ** //** 5555 Oakbrook Parkway, Suite 200, Norcross, GA 30093 ** //** ** //** Phone: (770)-246-8600 ** //** ** //************************************************************************* //************************************************************************* //********************************************************************** // $Header: /Alaska/Projects/Intel/Haswell/LynxPoint_SharkBay-DT_Crb_1AQQW/Core/EM/SMM/SmmDispatcher.c 5 6/17/16 4:14a Chienhsieh $ // // $Revision: 5 $ // // $Date: 6/17/16 4:14a $ //********************************************************************** // Revision History // ---------------- // $Log: /Alaska/Projects/Intel/Haswell/LynxPoint_SharkBay-DT_Crb_1AQQW/Core/EM/SMM/SmmDispatcher.c $ // // 5 6/17/16 4:14a Chienhsieh // Roll back #if condition: "ENABLE_SEND_SMI_IPI_IN_SMM" as Rev.3 // // 4 7/08/15 4:26a Chienhsieh // // 3 12/19/12 6:25a Wesleychen // Set a #if condition: "ENABLE_SEND_SMI_IPI_IN_SMM" to isolate send SMI // IPI in SMM for avoid system stay in an unstable state when numerous // SMI# are generated. // // 2 10/31/12 6:30a Wesleychen // Modify SMM InterruptManage function to execute Non-PI handler after PI // handler. // // 75 10/03/11 2:53p Markw // Add SMM Machine Check handler. // Files: SmmDispatcher.c, SmmDispatcherAsm.asm // // 74 9/28/11 4:52p Markw // [TAG] EIP71122 // [Category] Bug Fix // [Severity] Critical // [Symptom] System may hang randomly in PI 1.1 mode. // [RootCause] PI 1.1 SMST was initialized using uninitialized gSmmBase. // [Solution] Initialize gSmmBase before initializing PI 1.1 SMST. // [Files] SmmDispatcher.c // // 73 6/01/11 3:09p Markw // [TAG] EIP61586 // [Category] Bug Fix // [Severity] Minor // [Symptom] None // [RootCause] SMM security issue. Need ITP, specific board, and memory // to exploit. // SMM Dispatcher reads a pointer out of SMM. It uses this pointer to // access outside of SMM. // To exploit, the pointer would have to modified to write inside of SMM // to update code to allow SMM code to access the function call outside of // SMM. // Then, the exploit would have update a callback structure with an // address outside of SMM. // [Solution] Copy the pointer inside of SMM. Thus, a direct write // outside of SMM without reading a pointer outside of SMM first. // [Files] SmmDispatcher.c // // 72 4/15/11 4:39p Markw // [TAG] EIP57440 // [Category] New Feature // [Description] PI 1.1 update of Manage function from previous // check-in. // [Files] SmmDispatcher.c // // 71 3/31/11 6:44p Markw // [TAG] EIP57440 // [Category] Improvement // [Description] Separate Framework and PI 1.1 registered SMI source // handlers function return status checking. // [Files] SmmDispatcher.c // // 69 2/07/11 3:29p Markw // [TAG] EIP53481 // [Category] New Feature // [Description] Add PIWG 1.1 SMM support // [Files] Smm.sdl, SmmPrivateShared.h, SmmDispatcher.mak, // SmmDispatcher.h, SmmDispatcher.c, // Smst.c, SmmPiSmst.c, SmmInit.c, SmmBase.c, SmmBase2.c, // SmmDriverDispatcher.c, Smm Framewwork Protocol files, SmmPi.h, // Smm Pi Protocol files, SmmPciRbio files // // 67 10/13/10 1:15p Markw // Fix compiler warning form Timeout->EndValue = ((UINT32)EndValue) & ((1 // << NUM_BITS_IN_ACPI_TIMER) - 1); // // 66 9/10/10 5:05p Markw // Typecase to UINT8 when comparing savestate eax with SW SMI number. // // 65 4/29/10 11:23a Markw // Added some additional asserts on allocating SMM memory during SMM // initialization. // // 64 4/27/10 7:28p Markw // EIP 37921 - Update timeout functions to fix boundary condition in // timeout. // // 63 3/02/10 1:49p Markw // Added functions/structures for Save/Restore CPU state in SMM. // // 62 2/25/10 5:24p Markw // Install AmiSmmInfo Protocol. // // 61 2/18/10 4:31p Markw // EIP 34991 - Update CPU detection of CPU that generated SW SMI. It is // possible that multiple SW SMI may be generated simutaneously. // The CPU reported as generated the SW SMI by SwSMiCpuTrigger will the // first CPU that matches SW_SMI_IO_ADDRESS not just the first CPU found // that generated a SW SMI. // // 60 11/23/09 11:27a Markw // Remove ASSERT when SBSP not in SMM. // // 59 11/23/09 10:59a Markw // Renamed TIMEOUT to SMM_TIMEOUT. // // 58 9/09/09 5:17p Markw // EIP #25506 - Use token for x2apic support. // // 57 8/05/09 3:03p Markw // EIP #24914 - Add early local x2APIC support. // // 56 7/08/09 8:04p Markw // Update headers. // // 55 5/12/09 7:22p Markw // Fix mismatch #if/#endif when updating AMI_DEBUGGER_SUPPORT. // // 54 5/12/09 7:04p Markw // EIP #22087 - When AMI Debugger enabled, save IDT for IDT // re-initialization in SmmEntry.asm. // // 53 1/22/09 1:03p Markw // EIP #18671 (OPEN) Clear SW SMI status and set EOS inside SMM. Also // check for private SW SMI as well as private function. Call Clear // function inside SMM. // // 52 12/24/08 10:54a Markw // EIP #18423: Adjust EBDA location as more EBDA data is allocated. // // 51 12/01/08 1:55p Markw // // 50 11/25/08 4:09p Markw // Remove TRACE. Hangs during runtime OS. // // 49 11/25/08 11:25a Markw // Reinitialize the InSmm variable. // // 48 11/24/08 7:13p Markw // Save/restore upper byte of Interrupt command register. Check if no IPI // pending before issuing interrupt. // // 47 11/21/08 4:59p Markw // SBSP if available dispatches. S3 reinitialization. User ACPI timer for // time.out. // // 46 11/12/08 4:57p Markw // Dynamically update the CurrentlyExecutingCpu in SMM SYSTEM TABLE. // // 45 10/03/08 9:45a Markw // Fix race condindition when sync APs with BSP. Under some conditions // some APs skip the SmmStartupAp control loop. // // 44 9/26/08 4:52p Markw // The Private InSmm is now a pointer. // // 43 9/09/08 3:06p Markw // Align Dispatcher to 4k. // // 42 9/07/08 12:44a Markw // Separate SMM Private structure into inside SMM and outside SMM // structure. // // 41 9/04/08 12:26a Markw // Always have timeout on AP. Check SMM IPI pending status. // // 40 8/28/08 3:54p Markw // // 39 8/28/08 3:52p Markw // // 38 8/12/08 5:58p Markw // Use SMM instance BSP, not not runtime BSP. Call dispatcher even for SMM // software SMIs. // // 37 6/10/08 6:45p Markw // Disable SMM Thunk, if SMM is in TSEG and no CSM. // // 36 6/09/08 5:51p Markw // Any CPU can be BSP now. Created a Common Entry. Start APs that have not // started yet. // // 35 5/23/08 11:19a Markw // Don't allow callbacks once the flag is set. // // 34 3/03/08 6:58p Markw // Add 32-bit registers to SMM 16-bit thunk. // // 33 11/21/07 1:06p Markw // Header updates. // // 32 11/21/07 12:56p Markw // Always install thunk protocol. // // 31 11/14/07 2:02p Markw // Added SMRR support and updated SMM Cache for non-SMRR. // Updated SMM interrupt handeling because of complier optimization bug. // // 30 10/29/07 3:38p Markw // // 29 10/29/07 10:58a Markw // Smm Thunk: // * Code and data different segments. // * Code position independent. // * Switch for CSM for code and EBDA for data. // // 28 10/24/07 12:02p Markw // SMM Thunk code position independent. Data in a separate segment than // code in Smm Thunk. // Combined BSP and AP SmmEntry. // // 27 9/10/07 1:39p Markw // Add Interrupt Handling in SMM. // // 26 7/25/07 2:11p Markw // Limit number of CPUs in SMM to maximum in case system shutsdown in SMM. // // 25 6/14/07 11:01a Markw // Comment change. // // 24 4/13/07 11:03a Markw // Update header. // // 23 3/27/07 11:42a Markw // Fix get SmmBases in dispatcher for APs if BSP is in TSEG. // // 22 3/14/07 5:58p Markw // Allow the BSP to service the SMI if APs time-out. // // 21 2/07/07 11:06a Markw // Add Smm Cpu State protocol. // // 20 1/30/07 11:58a Markw // Added code to exit if not all CPUs enter SMM. // // 19 1/11/07 12:29p Markw // Use switch to enable/disable legacy code during build. // // 18 1/10/07 5:29p Markw // Only install SMM Thunk if BSP entry below 1MB. // // 17 1/09/07 6:45p Markw // Remove dependencies on SMM_BSP_BASE. Use SMM Hob. // // //********************************************************************** // //--------------------------------------------------------------------------- // // Name: SmmDispatcher.c // // Description: Contains the SMM dispatcher code for BSP & APs // //--------------------------------------------------------------------------- // //This include should be first. #include "SmmPrivateShared.h" #include #include #include #include #if SMM_USE_PI #include "SmmPi.h" #include #include #else #include #include #endif #include "AmiCspLib.h" //CPU APIC includes #define APIC_ALL_EXCLUDING_SELF (3 << 18) #define APIC_SIPI (6 << 8) #define APIC_INIT (5 << 8) #define APIC_SMI (2 << 8) #define APIC_DELIVERY_STATUS (1 << 12) #define APIC_LEVEL_ASSERT (1 << 14) #define APIC_LEVEL_DEASSERT (0 << 14) #define APIC_NO_SHORT_HAND (0 << 18) #define MSR_EXT_XAPIC_ICR 0x830 EFI_GUID gEfiSmmThunkProtocolGuid = EFI_SMM_THUNK_PROTOCOL_GUID; EFI_GUID gSwSmiCpuTriggerGuid = SW_SMI_CPU_TRIGGER_GUID; EFI_GUID gEfiSmmCpuSaveStateProtocolGuid = EFI_SMM_CPU_SAVE_STATE_PROTOCOL_GUID; EFI_GUID gAmiSmmInfoProtcolGuid = AMI_SMM_INFO_PROTOCOL_GUID; #if SMM_USE_PI EFI_GUID gEfiCpuIo2ProtocolGuid = EFI_SMM_CPU_IO2_PROTOCOL_GUID; #endif UINT8 **gSmmBase; SMM_ENTRY_INIT_STRUCT *gSmmEntryData; SW_SMI_CPU_TRIGGER *gSwSmiCpuTrigger; EFI_SMM_CPU_SAVE_STATE_PROTOCOL gEfiSmmCpuSaveState; SMM_BASE_PRIVATE_STRUCT *gBasePrivate; SMM_DISPATCHER_PRIVATE_STRUCT *gDispatcherPrivate; volatile BOOLEAN gEntrySemaphore = FALSE; volatile BOOLEAN gUseSbsp; UINT32 gSbsp; volatile BOOLEAN gReleaseStartedCpus = FALSE; volatile UINT32 gNumCpusReady = 0; volatile BOOLEAN gAllCpusInSync = FALSE; volatile BOOLEAN gReadyForApsToExecute; volatile UINT8 gInitSemaphore = 0; BOOLEAN *gInSmm; #if SMM_USE_FRAMEWORK extern EFI_SMM_SYSTEM_TABLE gSmmSystemTable; #endif #if SMM_USE_PI extern EFI_SMM_SYSTEM_TABLE2 gSmmSystemTable2; extern EFI_SMM_CPU_PROTOCOL gEfiSmmCpuProtocol; #endif EFI_SMM_SAVE_RESTORE_FUNCTION SmmSaveRestoreFunctionTable[] = { SmmSaveRestoreEnvironment NULL }; #if SMM_USE_PI EFI_SMM_ENTRY_CONTEXT gEfiSmmEntryContext; //For now, hardcode. UINTN gEfiSmmEntryContextSize = sizeof(EFI_SMM_ENTRY_CONTEXT); #endif void * Allocate( IN VOID *Address OPTIONAL, IN UINTN Size, UINTN Alignment OPTIONAL ); VOID InitializeMemoryManager(SMM_BASE_PRIVATE_STRUCT *Private); VOID InitializeSmmSystemTable(); VOID InitializeSmmPiSystemTable(); BOOLEAN IsSwSmiTrigger(UINT8 *SmmBase, UINT16 SwSmiPort); VOID StartAllCpus(SMM_ENTRY_INIT_STRUCT *SmmEntryInit); VOID HoldStartedCpus(SMM_ENTRY_INIT_STRUCT *SmmEntryInit); VOID SmmBspEntry(SMM_ENTRY_INIT_STRUCT *SmmEntryInit); VOID SmmApEntry(SMM_ENTRY_INIT_STRUCT *SmmEntryInit); UINT32 LockInc32(UINT32 *); VOID LockDec32(UINT32 *); VOID MachineCheckHandler(); VOID InitCrc(); EFI_STATUS InterruptManage( IN CONST EFI_GUID *HandlerType, IN CONST VOID *Context OPTIONAL, IN OUT VOID *CommBuffer OPTIONAL, IN OUT UINTN *CommBufferSize OPTIONAL ); typedef struct { UINT32 OverFlow; UINT32 EndValue; UINT32 OldTimerValue; } SMM_TIMEOUT; EFI_STATUS StartTimeout(SMM_TIMEOUT *Timeout, UINT32 Time); EFI_STATUS HasItTimedOut(SMM_TIMEOUT *Timeout); BOOLEAN EfiSmmFarCall86Ex( IN EFI_SMM_THUNK_PROTOCOL *This, IN UINT16 Segment, IN UINT16 Offset, IN SMM_THUNK_IA32_REGISTER_SET_EX *Regs, IN VOID *Stack, IN UINTN StackSize ); //TODOx64: move it to a library header VOID CPULib_Pause(); BOOLEAN Xchg8(IN OUT volatile UINT8 *, IN UINT8); //This typedef is the same as EFI_SMM_HANDLER_ENTRY_POINT2 in SmmPi.h. typedef EFI_STATUS (EFIAPI *SMM_HANDLER_ENTRY) ( IN EFI_HANDLE DispatchHandle, IN CONST VOID *Context OPTIONAL, IN OUT VOID *CommBuffer OPTIONAL, IN OUT UINTN *CommBufferSize OPTIONAL ); // //--------------------------------------------------------------------------- // // Procedure: CommonEntry // // Description: BSP and APs start here from SmmEntry.asm. // // Input: // IN SMM_ENTRY_INIT_STRUCT *SmmEntryInit // // Output: // VOID // //--------------------------------------------------------------------------- // VOID CommonEntry(IN SMM_ENTRY_INIT_STRUCT *SmmEntryInit) { //Two groups of CPUs where come through this function. //1. The initial group all at once. They race for the semaphore. // The winning CPU will try to start any other that has not been started. //2. The CPUs that got started or stragglers after the time-out. // //The SMM Dispatcher will be run by the SBSP if it has been started. //Otherwise, the winning CPU in #1 will run the Dispatcher. // //If SMM generates S3, flags will not be reset. UINT32 CpuNo = SmmEntryInit->CpuNo; volatile UINT8 IsNotFirstCpu = TRUE; CPU_LIB_SMM_SAVE_RESTORE_DATA CpuSaveRestoreData; CpuLib_SmmSaveCpuState(&CpuSaveRestoreData); //This not save state area. //Use gSmmEntryData, so all CPUs use the same SmmInit. //Re-initialize the variables on first entry and S3 resume. if (gSmmEntryData->SmmInit) { volatile UINT8 HoldCpus = 1; HoldCpus = Xchg8(&gInitSemaphore, HoldCpus); if (!HoldCpus) { UINT8 i; gDispatcherPrivate->NumCpusInSmm = 0; gNumCpusReady = 0; gAllCpusInSync = FALSE; gEntrySemaphore = FALSE; //This be reset once, or all CPUs go into hold loop. for(i = 0; i < gDispatcherPrivate->NumCpus; ++i) { gDispatcherPrivate->SmmCpuInfo[i].InSmm = FALSE; } gSmmEntryData->SmmInit = 0; //This must be last; it releases the other CPUs. } else { while (gSmmEntryData->SmmInit) CPULib_Pause(); } } //InSmm must be before LockIn32, otherwise StartAllCpus fucntion could //exit time-out loop, and InSmm would be false, so BSP would not execute //dispatcher. gDispatcherPrivate->SmmCpuInfo[CpuNo].InSmm = TRUE; LockInc32(&gDispatcherPrivate->NumCpusInSmm); if (gEntrySemaphore == 0) { //This if causes fewer memory exchanges. IsNotFirstCpu = Xchg8(&gEntrySemaphore, IsNotFirstCpu); } if (!IsNotFirstCpu) { //This is the first CPU. StartAllCpus(SmmEntryInit); } else { HoldStartedCpus(SmmEntryInit); } gDispatcherPrivate->SmmCpuInfo[CpuNo].InSmm = FALSE; CpuLib_SmmRestoreCpuState(&CpuSaveRestoreData); //This not save state area. } // //--------------------------------------------------------------------------- // // Procedure: StartAllCpus // // Description: // One random CPU enters here. Waits for CPUs to sync. If no sync, tries to // start CPUs that didn't enter SMM. // // Input: // IN SMM_ENTRY_INIT_STRUCT *SmmEntryInit // // Output: // VOID // //--------------------------------------------------------------------------- // VOID StartAllCpus(IN SMM_ENTRY_INIT_STRUCT *SmmEntryInit) { SMM_TIMEOUT Timeout; UINT32 i; //Wait until all APs and BSP are synced. StartTimeout(&Timeout, SMM_TIME_OUT_US); while(gDispatcherPrivate->NumCpusInSmm < gDispatcherPrivate->NumCpus && !EFI_ERROR(HasItTimedOut(&Timeout))) CPULib_Pause(); //If not all CPUs get control in SMM, try to start other CPUs. if (gDispatcherPrivate->NumCpusInSmm < gDispatcherPrivate->NumCpus) { for (i = 0; i < gDispatcherPrivate->NumCpus; ++i) { if (!gDispatcherPrivate->SmmCpuInfo[i].InSmm) { UINT32 ApicId = gDispatcherPrivate->SmmCpuInfo[i].ApicId; #if LOCAL_X2APIC_SUPPORT if (CPULib_IsLocalX2ApicEnabled()) { while(ReadMsr(MSR_EXT_XAPIC_ICR) & APIC_DELIVERY_STATUS); //Wait until idle. ReadWriteMsr(MSR_EXT_XAPIC_ICR, Shl64(ApicId, 32) + APIC_NO_SHORT_HAND + APIC_LEVEL_ASSERT + APIC_SMI, 0xfff32000); } else { #endif #if ENABLE_SEND_SMI_IPI_IN_SMM UINT32 SaveHighByte = *(UINT32*)(LOCAL_APIC_BASE + APIC_ICR_HIGH_REGISTER); //Wait until IPI is Idle while( MemRead32((UINT32*)(LOCAL_APIC_BASE + APIC_ICR_LOW_REGISTER)) & APIC_DELIVERY_STATUS ); //Send IPI to APIC ID. MemReadWrite32( (UINT32*)(LOCAL_APIC_BASE + APIC_ICR_HIGH_REGISTER), ApicId << 24, 0x00ffffff ); MemReadWrite32( (UINT32*)(LOCAL_APIC_BASE + APIC_ICR_LOW_REGISTER), (0 << 18) + (1 << 14) + (2 << 8), 0 ); //Restore high byte. Before SMI, BIOS, OS, etc may have *(UINT32*)(LOCAL_APIC_BASE + APIC_ICR_HIGH_REGISTER) = SaveHighByte; #endif #if LOCAL_X2APIC_SUPPORT } #endif } } //If not all CPUs get control in SMM. StartTimeout(&Timeout, SMM_TIME_OUT_US); //uS while(gDispatcherPrivate->NumCpusInSmm < gDispatcherPrivate->NumCpus && !EFI_ERROR(HasItTimedOut(&Timeout))) CPULib_Pause(); } //Has SBSP been started. gUseSbsp = gDispatcherPrivate->SmmCpuInfo[gSbsp].InSmm; //The ASSERT below is to signal SBSP not in SMM when testing SMM. //It is generally not an error when the ASSERT below is triggered. It is triggered when debugging, non-SMM errors, etc. //The SMM Dispatcher is designed to process correctly if SBSP is not in SMM. //DEBUG ASSERT(gUseSbsp); gReleaseStartedCpus = TRUE; if (gUseSbsp) { if (SmmEntryInit->CpuNo == gSbsp) SmmBspEntry(SmmEntryInit); else SmmApEntry(SmmEntryInit); } else { SmmBspEntry(SmmEntryInit); //BSP has not started, so use this as the BSP. } //reset flags before exiting. gEntrySemaphore = FALSE; gReleaseStartedCpus = FALSE; //This must be reset last because this releases APs to resume. } // //--------------------------------------------------------------------------- // // Procedure: HoldStartedCpus // // Description: // Hold loop for CPU to sync. All but one CPU will enter here. // // Input: // IN SMM_ENTRY_INIT_STRUCT *SmmEntryInit // // Output: // VOID // //--------------------------------------------------------------------------- // VOID HoldStartedCpus(IN SMM_ENTRY_INIT_STRUCT *SmmEntryInit) { //Wait until trying to start all CPUs. while(!gReleaseStartedCpus) CPULib_Pause(); //All CPUs have been started. if (gUseSbsp) { if (SmmEntryInit->CpuNo == gSbsp) SmmBspEntry(SmmEntryInit); else SmmApEntry(SmmEntryInit); } else { SmmApEntry(SmmEntryInit); } //Wait until flags are reset by First CPU. while (gReleaseStartedCpus) CPULib_Pause(); } // //--------------------------------------------------------------------------- // // Procedure: SmmBspEntry // // Description: Call Smm call back or dispatch handlers. // // Input: // IN SMM_ENTRY_INIT_STRUCT *SmmEntryInit // // Output: // VOID // //--------------------------------------------------------------------------- // VOID SmmBspEntry(IN SMM_ENTRY_INIT_STRUCT *SmmEntryInit) { static BOOLEAN DisallowCallbacks = FALSE; UINT32 i; #if INTEL_MP_SW_SMI_PATCH == 1 EFI_SMM_CPU_SAVE_STATE *OrigCpuSaveState = 0; #endif UINT32 CpuNo = SmmEntryInit->CpuNo; BOOLEAN IsCallBackFunction = FALSE; #if SMM_USE_FRAMEWORK gSmmSystemTable.CurrentlyExecutingCpu = CpuNo + 1; #endif gDispatcherPrivate->SmmBspNumber = CpuNo; #if SMM_USE_PI gEfiSmmEntryContext.CurrentlyExecutingCpu = CpuNo; gSmmSystemTable2.CurrentlyExecutingCpu = CpuNo; //This 0-based, Framework is 1-based. #endif //Copy save state area. #if SMM_USE_FRAMEWORK CPU_GetSaveState(gSmmBase[CpuNo], &gSmmSystemTable.CpuSaveState[CpuNo].Ia32SaveState); #endif //Indicates APs can execute function for a driver when released. gReadyForApsToExecute = TRUE; LockInc32((UINT32*)&gNumCpusReady); while (gNumCpusReady < gDispatcherPrivate->NumCpusInSmm) CPULib_Pause(); gAllCpusInSync = TRUE; //Make OEM Call to save state. for (i = 0; SmmSaveRestoreFunctionTable[i] != NULL; ++i) SmmSaveRestoreFunctionTable[i](TRUE); //Check if software smi, and the CPU that caused it. gSwSmiCpuTrigger->Cpu = (UINTN)-1; for(i = 0; i < gDispatcherPrivate->NumCpus; ++i) { if (IsSwSmiTrigger(gSmmBase[i], SW_SMI_IO_ADDRESS)) { UINT8 SwSmi = IoRead8(SW_SMI_IO_ADDRESS); #if SMM_USE_FRAMEWORK if ( SwSmi == (UINT8)gSmmSystemTable.CpuSaveState[i].Ia32SaveState.EAX) { #else UINT8 RegAl; EFI_STATUS Status; Status = gEfiSmmCpuProtocol.ReadSaveState( &gEfiSmmCpuProtocol, 1, EFI_SMM_SAVE_STATE_REGISTER_RAX, i, &RegAl ); if (EFI_ERROR(Status) || SwSmi == RegAl) { //Assume if error, then this is the correct CPU. #endif gSwSmiCpuTrigger->Cpu = i; break; } } } //Intel only uses save state CpuSaveState[0] for software SMIs, event though it may //be generated by a AP. If INTEL_MP_SW_SMI_PATCH is enabled, it will temporarily, //set CpuSaveState[0] to the AP that generated SMI. However, this means CpuSaveState[x] //may be invalid. // //The PIWG should come up with a permanent solution. // #if INTEL_MP_SW_SMI_PATCH == 1 if ((INTN)gSwSmiCpuTrigger->Cpu > 0) { OrigCpuSaveState = gSmmSystemTable.CpuSaveState; gSmmSystemTable.CpuSaveState = &OrigCpuSaveState[gSwSmiCpuTrigger->Cpu]; gSwSmiCpuTrigger->Cpu = 0; } #endif if (gDispatcherPrivate->FloatingPointSave) { //The XMM is already before executing C because of possible optimizations. // _asm FXSAVE gSmmSystemTable.CpuOptionalFloatingPointState //Save Floating Point Context; } *gInSmm = TRUE; //SMM BASE protocol InSmm function returns this variable. //This CallBackFunc is only called during boot services before shell. if (!DisallowCallbacks) { //Check both CallBackFunc and software smi. //This is done in case asynchronous SMI occurs between setting up CallBackFunc and SW SMI. IsCallBackFunction = gBasePrivate->CallBackFunc && IoRead8(SW_SMI_IO_ADDRESS) == SMMBASE_CALLBACK; if (IsCallBackFunction) { gBasePrivate->CallBackFunc(); gBasePrivate->CallBackFunc = 0; if (gBasePrivate->DisallowCallbacks) DisallowCallbacks = TRUE; } } gInitSemaphore = 0; //Clear this away from loop to be sure 2 CPUs don't do xchg. #if SMM_USE_PI InterruptManage(NULL, NULL, &gEfiSmmEntryContext, &gEfiSmmEntryContextSize); //Execute root handlers #else InterruptManage(NULL, NULL, NULL, NULL); //Execute root handlers #endif *gInSmm = FALSE; //SMM BASE protocol InSmm function returns this variable. if (gDispatcherPrivate->FloatingPointSave) { //The XMM is already before executing C because of possible optimizations. // _asm FXRSTOR gSmmSystemTable.CpuOptionalFloatingPointState //Restore Floating Point Context; } if (IsCallBackFunction) { //This will clear the SW SMI Status. This is done last in case an incorrect // implementation Clear, clears all statuses. // //This will not be called during runtime. #if SMM_USE_PI ((EFI_SMM_CONTROL2_PROTOCOL*)gDispatcherPrivate->SmmControl)->Clear((EFI_SMM_CONTROL2_PROTOCOL*)gDispatcherPrivate->SmmControl, FALSE); #else ((EFI_SMM_CONTROL_PROTOCOL*)gDispatcherPrivate->SmmControl)->Clear((EFI_SMM_CONTROL_PROTOCOL*)gDispatcherPrivate->SmmControl, FALSE); #endif } //Restore CpuSaveState. #if INTEL_MP_SW_SMI_PATCH == 1 if(OrigCpuSaveState) gSmmSystemTable.CpuSaveState = OrigCpuSaveState; #endif //Make OEM Call to restore state. for (i = 0; SmmSaveRestoreFunctionTable[i] != NULL; ++i) SmmSaveRestoreFunctionTable[i](FALSE); #if SMM_USE_FRAMEWORK //Copy save state area. CPU_RestoreSaveState(gSmmBase[CpuNo], &gSmmSystemTable.CpuSaveState[CpuNo].Ia32SaveState); #endif gReadyForApsToExecute = FALSE; //Used to indicate that BSP is exiting SMM mode. LockDec32(&gDispatcherPrivate->NumCpusInSmm); while(gDispatcherPrivate->NumCpusInSmm > 0) CPULib_Pause(); gNumCpusReady = 0; //Initialize count. gAllCpusInSync = FALSE; //This must be set last. Releases CPUs from SmmApEntry. } // //--------------------------------------------------------------------------- // // Procedure: SmmApEntry // // Description: APs after switching to protected mode will jump here. // // Input: // IN SMM_ENTRY_INIT_STRUCT *SmmEntryInit // // Output: // VOID // //--------------------------------------------------------------------------- // VOID SmmApEntry(IN SMM_ENTRY_INIT_STRUCT *SmmEntryInit) { volatile SMM_AP_CPU_CONTROL *SmmApCpuControl = &gDispatcherPrivate->SmmApCpuControl[SmmEntryInit->CpuNo]; UINT32 CpuNo = SmmEntryInit->CpuNo; //Copy save state area. #if SMM_USE_FRAMEWORK CPU_GetSaveState(gSmmBase[CpuNo], &gSmmSystemTable.CpuSaveState[CpuNo].Ia32SaveState); #endif LockInc32((UINT32*)&gNumCpusReady); while(!gAllCpusInSync) CPULib_Pause(); while(gReadyForApsToExecute) { if (SmmApCpuControl->Procedure) { SmmApCpuControl->Procedure(SmmApCpuControl->ProcArguments); SmmApCpuControl->Procedure = 0; } CPULib_Pause(); } #if SMM_USE_FRAMEWORK CPU_RestoreSaveState( (UINT8*)SmmEntryInit->SmmEntryStart - 0x8000, &gSmmSystemTable.CpuSaveState[SmmEntryInit->CpuNo].Ia32SaveState ); #endif LockDec32(&gDispatcherPrivate->NumCpusInSmm); while(gAllCpusInSync) CPULib_Pause(); //Wait until BSP is ready. } //******************************************************* //EFI SMM Handler Return Code //******************************************************* #define EFI_HANDLER_SUCCESS 0x0000 #define EFI_HANDLER_CRITICAL_EXIT 0x0001 #define EFI_HANDLER_SOURCE_QUIESCED 0x0002 #define EFI_HANDLER_SOURCE_PENDING 0x0003 EFI_STATUS InterruptManage( IN CONST EFI_GUID *HandlerType, IN CONST VOID *Context OPTIONAL, IN OUT VOID *CommBuffer OPTIONAL, IN OUT UINTN *CommBufferSize OPTIONAL ) { HANDLER_LIST *Link; #if SMM_USE_PI EFI_STATUS Status = EFI_INTERRUPT_PENDING; //Default: Interrupt not handled. #else EFI_STATUS Status = EFI_HANDLER_SUCCESS; #endif EFI_STATUS HdlrStatus; for (Link = gDispatcherPrivate->HandlerListHead; Link; Link = Link->Link) { if (HandlerType == NULL) { if (!Link->IsRoot) continue; } else { if (Link->IsRoot || (guidcmp((EFI_GUID*)HandlerType, &Link->HandlerType) != 0)) continue; } #if SMM_USE_PI if(Link->IsPi) { HdlrStatus = ((SMM_HANDLER_ENTRY)Link->EntryPoint)( Link->SmmImageHandle, Context, CommBuffer, CommBufferSize ); //TODO: PI 1.1 spec SmiManage function EFI_SUCCESS description questionable. //Review with PI work group. switch(HdlrStatus) { case EFI_WARN_INTERRUPT_SOURCE_PENDING: break; //TODO: Comment out for now because of build error related to core header files. //case EFI_INTERRUPT_PENDING: // return EFI_INTERRUPT_PENDING; case EFI_WARN_INTERRUPT_SOURCE_QUIESCED: Status = EFI_WARN_INTERRUPT_SOURCE_QUIESCED; //Change status to interrupt handled. break; case EFI_SUCCESS: if (Link->IsRoot) { Status = EFI_WARN_INTERRUPT_SOURCE_QUIESCED; //Change status to interrupt handled. break; //Continue checking other root handlers. } return EFI_WARN_INTERRUPT_SOURCE_QUIESCED; default: break; } } #endif #if 0//SMM_USE_FRAMEWORK if (!Link->IsPi) { HdlrStatus = ((EFI_SMM_CALLBACK_ENTRY_POINT)Link->EntryPoint)( Link->SmmImageHandle, Link->CommunicationBuffer, Link->SourceSize ); switch(HdlrStatus) { case EFI_HANDLER_CRITICAL_EXIT: case EFI_HANDLER_SOURCE_QUIESCED: return EFI_HANDLER_CRITICAL_EXIT; case EFI_HANDLER_SUCCESS: case EFI_HANDLER_SOURCE_PENDING: default: Status = EFI_SUCCESS; break; } } #endif } #if SMM_USE_FRAMEWORK if (HandlerType == NULL) { for (Link = gDispatcherPrivate->HandlerListHead; Link; Link = Link->Link) { if (!Link->IsRoot) continue; if (!Link->IsPi) { HdlrStatus = ((EFI_SMM_CALLBACK_ENTRY_POINT)Link->EntryPoint)(Link->SmmImageHandle, Link->CommunicationBuffer, Link->SourceSize); switch(HdlrStatus) { case EFI_HANDLER_CRITICAL_EXIT: case EFI_HANDLER_SOURCE_QUIESCED: return EFI_HANDLER_CRITICAL_EXIT; case EFI_HANDLER_SUCCESS: case EFI_HANDLER_SOURCE_PENDING: default: Status = EFI_SUCCESS; break; } } } } #endif return Status; } //SMM thunk either requires AB Segment of CSM. #if SMM_THUNK_NO_AB_SEG == 0 || SMM_THUNK_IN_CSM == 1 // //--------------------------------------------------------------------------- // // Procedure: EfiSmmFarCall86Ex // // Description: // Smm Thunk call. If no stack, this will push flags to simulate int call. // // Input: // IN EFI_SMM_THUNK_PROTOCOL *This, // IN UINT16 Segment -16-bit segment to call // IN UINT16 Offset -16-bit offset to call // IN SMM_THUNK_IA32_REGISTER_SET_EX *Regs -Preload registers before call // IN VOID *Stack -Stack before call optional // IN UINTN StackSize - if no stack, this should be zero. // // Output: BOOLEAN // //--------------------------------------------------------------------------- // BOOLEAN EfiSmmFarCall86Ex( IN EFI_SMM_THUNK_PROTOCOL *This, IN UINT16 Segment, IN UINT16 Offset, IN SMM_THUNK_IA32_REGISTER_SET_EX *Regs, IN VOID *Stack, IN UINTN StackSize ) { SMM_THUNK_DATA *SmmThunkData = gDispatcherPrivate->SmmThunkData; #if SMM_THUNK_IN_CSM == 1 if (gDispatcherPrivate->EbdaStartOffset) { UINT32 CurrentEbda = (UINT32)(UINTN)(*(UINT16*)0x40e << 4); SmmThunkData =(SMM_THUNK_DATA *) (CurrentEbda + gDispatcherPrivate->EbdaStartOffset); } #endif SmmThunkData->FarCall.Segment = Segment; SmmThunkData->FarCall.Offset = Offset; //Copy address for stack if (Stack) { SmmThunkData->Stack.Stack = (UINT32)Stack; SmmThunkData->Stack.StackSize = (UINT32)StackSize; } else SmmThunkData->Stack.StackSize = 0; //Copy thunk registers. SmmThunkData->Regs = *Regs; gDispatcherPrivate->SmmThunkProc(); //Do Far call. //Restore thunk registers. *Regs = SmmThunkData->Regs; return TRUE; } // //--------------------------------------------------------------------------- // // Procedure: EfiSmmFarCall86 // // Description: // Smm Thunk call. If no stack, this will push flags to simulate int call. // // Input: // IN EFI_SMM_THUNK_PROTOCOL *This, // IN UINT16 Segment -16-bit segment to call // IN UINT16 Offset -16-bit offset to call // IN SMM_THUNK_IA32_REGISTER_SET *Regs -Preload registers before call // IN VOID *Stack -Stack before call optional // IN UINTN StackSize - if no stack, this should be zero. // // Output: BOOLEAN // //--------------------------------------------------------------------------- // BOOLEAN EfiSmmFarCall86( IN EFI_SMM_THUNK_PROTOCOL *This, IN UINT16 Segment, IN UINT16 Offset, IN SMM_THUNK_IA32_REGISTER_SET *Regs, IN VOID *Stack, IN UINTN StackSize ) { SMM_THUNK_IA32_REGISTER_SET_EX RegsEx; BOOLEAN RetValue; RegsEx.X.AX = Regs->X.AX; RegsEx.X.BX = Regs->X.BX; RegsEx.X.CX = Regs->X.CX; RegsEx.X.DX = Regs->X.DX; RegsEx.X.SI = Regs->X.SI; RegsEx.X.DI = Regs->X.DI; RegsEx.X.Flags = Regs->X.Flags; RegsEx.X.ES = Regs->X.ES; RegsEx.X.CS = Regs->X.CS; RegsEx.X.SS = Regs->X.SS; RegsEx.X.DS = Regs->X.DS; RegsEx.X.BP = Regs->X.BP; RetValue = EfiSmmFarCall86Ex( This, Segment, Offset, &RegsEx, Stack, StackSize ); Regs->X.AX = RegsEx.X.AX; Regs->X.BX = RegsEx.X.BX; Regs->X.CX = RegsEx.X.CX; Regs->X.DX = RegsEx.X.DX; Regs->X.SI = RegsEx.X.SI; Regs->X.DI = RegsEx.X.DI; Regs->X.Flags = RegsEx.X.Flags; Regs->X.ES = RegsEx.X.ES; Regs->X.CS = RegsEx.X.CS; Regs->X.SS = RegsEx.X.SS; Regs->X.DS = RegsEx.X.DS; Regs->X.BP = RegsEx.X.BP; return RetValue; } EFI_SMM_THUNK_PROTOCOL EfiSmmThunkProtocol = {EfiSmmFarCall86, EfiSmmFarCall86Ex}; #endif #pragma pack (1) typedef struct { UINT16 LoOffset; UINT16 Segment; UINT16 DescBits; //Will be set to 0x0f00 Present=1, DPL = 0, D = 1 (32bit) UINT16 HiOffset; #ifdef EFIx64 UINT32 Hi32Offset; UINT32 Rsv; #endif } INTR_GATE_DESC; typedef struct { UINT8 MovAlOp; UINT8 InterruptNum; UINT8 JmpOp; UINT8 RelOffset; } INT_ENTRY_POINT; INT_ENTRY_POINT gIntEntryTemplate = { //No global memory 0xb0, //mov al, Int 0, //Int 0xeb, //jmp 0xfe // to itself }; typedef struct { UINT8 PushEaxOp; UINT8 MovAlOp; UINT8 MovAlValue; UINT8 OutAlOp; UINT8 OutAlValue; UINT8 PopEaxOp; #ifdef EFIx64 UINT8 Ext64Op; #endif UINT8 IretValue; } EOI_TEMPLATE; EOI_TEMPLATE EoiTemplate = { 0x50, //push eax/rax 0xb0, 0x20, //mov al, 20h ;EOI 0xe6, 0x20, //out 20h, al ;Sent Master EOI to interrupt controller. 0x58, //pop eax/rax #ifdef EFIx64 0x48, //Ext 64-bit Opcode. #endif 0xcf //iret }; #pragma pack() #define NUM_EXCEPTIONS 19 // //--------------------------------------------------------------------------- // // Procedure: InitInterrupts // // Description: // Install Interrupt Handlers. Initialize the interrupt descriptors. // // Input: VOID // // Output: VOID // //--------------------------------------------------------------------------- // VOID InitInterrupts() { #if AMI_DEBUGGER_SUPPORT CPULib_SaveIdt(&gDispatcherPrivate->Idt); return; #else UINT32 i; UINT16 Segment; INT_ENTRY_POINT *IntEntryPoint; INTR_GATE_DESC *IntGateDescs; #ifdef EFIx64 UINT16 *DummyIrqHandler; #else UINT8 *DummyIrqHandler; #endif //Allocate memory for addresses of interrupt Handlers. DummyIrqHandler = Allocate(0, sizeof(*DummyIrqHandler), 0); ASSERT(DummyIrqHandler != NULL); #ifdef EFIx64 *DummyIrqHandler = 0xcf48; //IRET #else *DummyIrqHandler = 0xcf; #endif IntEntryPoint = Allocate(0, sizeof(INT_ENTRY_POINT) * NUM_EXCEPTIONS, 0); ASSERT(IntEntryPoint != NULL); //Initialize interrupt entry points using template. for(i = 0; i < NUM_EXCEPTIONS; ++i) { gIntEntryTemplate.InterruptNum = i; IntEntryPoint[i] = gIntEntryTemplate; } //Alocate space for Interrupt Descriptor Table. 256 entries/8 bytes. IntGateDescs = Allocate(0, 256 * sizeof(*IntGateDescs),0); ASSERT(IntGateDescs != NULL); Segment = GetCsSegment(); //Setup halts for exceptions. for (i = 0 ; i < NUM_EXCEPTIONS; ++i) { UINTN IntHndlrAddr = (UINTN)&IntEntryPoint[i]; if (i == 18) IntHndlrAddr = (UINTN)MachineCheckHandler; IntGateDescs[i].LoOffset=(UINT16)IntHndlrAddr; IntGateDescs[i].HiOffset=(UINT16)((UINT32)IntHndlrAddr >> 16); IntGateDescs[i].Segment=Segment; IntGateDescs[i].DescBits=0x8e00; //Present=1, DPL = 0, D = 1 (32bit) #ifdef EFIx64 IntGateDescs[i].Hi32Offset = 0; IntGateDescs[i].Rsv = 0; #endif } //Initialize the rest for dummy irets except timer to be overwritten below. for (; i < 256 ; ++i) { IntGateDescs[i].LoOffset=(UINT16)DummyIrqHandler; IntGateDescs[i].HiOffset=(UINT16)((UINT32)DummyIrqHandler >> 16); IntGateDescs[i].Segment=Segment; IntGateDescs[i].DescBits=0x8e00; //Present=1, DPL = 0, D = 1 (32bit) #ifdef EFIx64 IntGateDescs[i].Hi32Offset = 0; IntGateDescs[i].Rsv = 0; #endif } //Setup EOI for timer interrupt. { VOID *TimerEoi = Allocate(0, sizeof(EOI_TEMPLATE), 0); ASSERT(TimerEoi != NULL); MemCpy(TimerEoi, &EoiTemplate, sizeof(EOI_TEMPLATE)); IntGateDescs[MASTER_INTERRUPT_BASE].LoOffset=*(UINT16*)&TimerEoi; IntGateDescs[MASTER_INTERRUPT_BASE].HiOffset=*(((UINT16*)&TimerEoi)+1); } gDispatcherPrivate->Idt.Base=(UINT32)(UINTN)IntGateDescs; #ifdef EFIx64 gDispatcherPrivate->Idt.Limit=16*256-1; #else gDispatcherPrivate->Idt.Limit=8*256-1; #endif #endif } // //--------------------------------------------------------------------------- // // Procedure: StartTimeout // // Description: // Initialize timeout for a specified about of time in uS. // // Input: // OUT SMM_TIMEOUT *Timeout // IN UINT32 Time // // Output: EFI_STATUS // //--------------------------------------------------------------------------- // EFI_STATUS StartTimeout(OUT SMM_TIMEOUT *Timeout, IN UINT32 Time) //uS { UINT64 TicksNeeded; UINT64 EndValue; // // There are 3.58 ticks per us. // // TicksNeeded = Time * 358 / 100 // TicksNeeded = Div64 (Mul64 (Time, 358), 100, NULL); // Read ACPI Timer Timeout->OldTimerValue = IoRead32(PM_TMR_BLK_ADDRESS); EndValue = TicksNeeded + Timeout->OldTimerValue; // // Calculate Overflow and EndValue from FullEndValue, // based on number of bits in ACPI Timer // Timeout->OverFlow = (UINT32)Shr64 (EndValue, NUM_BITS_IN_ACPI_TIMER); Timeout->EndValue = ((UINT32)EndValue) & (UINT32)(((UINT64)1 << NUM_BITS_IN_ACPI_TIMER) - 1); return EFI_SUCCESS; } // //--------------------------------------------------------------------------- // // Procedure: HasItTimedOut // // Description: // Return EFI_TIMEOUT if timer has expired. // // Input: // IN OUT SMM_TIMEOUT *Timeout // // Output: EFI_STATUS // //--------------------------------------------------------------------------- // EFI_STATUS HasItTimedOut(IN OUT SMM_TIMEOUT *Timeout) { UINT32 TimerValue; //Read ACPI Timer TimerValue = IoRead32(PM_TMR_BLK_ADDRESS); if (Timeout->OverFlow > 0) { // // See if the current timer value is less than the previous value. // If it is, then the timer had wrapped around. // if (TimerValue < Timeout->OldTimerValue) { --Timeout->OverFlow; } // Update OldTimerValue Timeout->OldTimerValue = TimerValue; return EFI_SUCCESS; } // // See if the current timer value is less than the previous value. // If it is, then we are done. // if (TimerValue < Timeout->OldTimerValue) return EFI_TIMEOUT; // If we passed the EndValue, we are done. if (TimerValue >= Timeout->EndValue) return EFI_TIMEOUT; // Update OldTimerValue Timeout->OldTimerValue = TimerValue; return EFI_SUCCESS; } EFI_STATUS GetNumOfCpusInsideSmm( IN AMI_SMM_INFO_PROTOCOL *This, OUT UINT32 *Cpus ) { if (Cpus == NULL) return EFI_INVALID_PARAMETER; *Cpus = gDispatcherPrivate->NumCpusInSmm; return EFI_SUCCESS; } AMI_SMM_INFO_PROTOCOL gAmiSmmInfo = { 0, //Protocol Ver GetNumOfCpusInsideSmm }; // //--------------------------------------------------------------------------- // // Procedure: InitializeDispatcher // // Description: Initialize Dispatcher. // // Input: // IN EFI_HANDLE ImageHandle // IN EFI_SYSTEM_TABLE *SystemTable // // Output: // EFI_STATUS // //--------------------------------------------------------------------------- // EFI_STATUS InitializeDispatcher( IN EFI_HANDLE ImageHandle, IN EFI_SYSTEM_TABLE *SystemTable, IN SMM_BASE_PRIVATE_STRUCT *BasePrivate, IN SMM_DISPATCHER_PRIVATE_STRUCT *DispatcherPrivate, OUT VOID **SmstTable, OUT VOID **SmstTable2 ) { //SwSmiCpuTrigger is temporary. When installed in the configuration table // a copy will be made. The copy will be used. SW_SMI_CPU_TRIGGER SwSmiCpuTrigger = {(UINTN)-1}; VOID *Address; UINT8 *SmmAllocMemoryStart = BasePrivate->SmmAllocMemoryStart; SMM_HOB *SmmHob = BasePrivate->SmmHob; EFI_HANDLE Handle=NULL; EFI_STATUS Status; UINT32 i; //------------------------------- InitAmiLib(ImageHandle, SystemTable); gBasePrivate = BasePrivate; gDispatcherPrivate = DispatcherPrivate; gInSmm = gBasePrivate->InSmm; //Initialize pointer SMM BASE function InSmm to notify if inside of SMM. InitializeMemoryManager(BasePrivate); //Allocate Image Address = Allocate(gBasePrivate->Pe32DispatcherImage, BasePrivate->Pe32DispatcherImageSize, 0); ASSERT(Address != NULL); InitInterrupts(); gSmmBase = (UINT8**)Allocate(0, sizeof(UINT8**) * SmmHob->NumCpus, 0); ASSERT(gSmmBase != NULL); gEfiSmmCpuSaveState.CpuSaveState = (EFI_SMM_CPU_STATE**)Allocate(0, sizeof(EFI_SMM_CPU_STATE*) * SmmHob->NumCpus, 0); ASSERT(gEfiSmmCpuSaveState.CpuSaveState != NULL); /* //Any Cpu number can be BSP. for(i = 0; i < SmmHob->NumCpus; ++i) { gSmmBase[i] = (UINT8*)(SmmHob->SmmBase[i]); gEfiSmmCpuSaveState.CpuSaveState[i] = (EFI_SMM_CPU_STATE*)(SmmHob->SmmBase[i] + 0x10000-0x400); } */ //CPU Number 0 must be BSP. gSmmBase[0] = (UINT8*)(SmmHob->SmmBase[SmmHob->Bsp]); gEfiSmmCpuSaveState.CpuSaveState[0] = (EFI_SMM_CPU_STATE*)(SmmHob->SmmBase[SmmHob->Bsp] + 0x10000-0x400); for(i = 0; i < SmmHob->NumCpus; ++i) { static UINT32 ApNum = 0; //BSP is given CPU #0, and APs 1,2... if (i == SmmHob->Bsp) continue; ++ApNum; gSmmBase[ApNum] = (UINT8*)(SmmHob->SmmBase[i]); gEfiSmmCpuSaveState.CpuSaveState[ApNum] = (EFI_SMM_CPU_STATE*)(SmmHob->SmmBase[i] + 0x10000-0x400); } gSmmEntryData = (SMM_ENTRY_INIT_STRUCT *) (gSmmBase[0] + 0x8004); gSmmEntryData->DispatcherEntry = CommonEntry; gSmmEntryData->DispatcherPrivate = DispatcherPrivate; gSbsp = 0;//SmmHob->Bsp; InitCrc(); #if SMM_USE_PI InitializeSmmPiSystemTable(); #endif #if SMM_USE_FRAMEWORK InitializeSmmSystemTable(); #endif //If installed, it will install on both SMST tables. #if SMM_USE_PI Status = gSmmSystemTable2.SmmInstallConfigurationTable( &gSmmSystemTable2, &gSwSmiCpuTriggerGuid, &SwSmiCpuTrigger, sizeof(SW_SMI_CPU_TRIGGER) ); ASSERT_EFI_ERROR(Status); #else Status = gSmmSystemTable.SmmInstallConfigurationTable( &gSmmSystemTable, &gSwSmiCpuTriggerGuid, &SwSmiCpuTrigger, sizeof(SW_SMI_CPU_TRIGGER) ); ASSERT_EFI_ERROR(Status); #endif #if SMM_USE_PI gSwSmiCpuTrigger = gSmmSystemTable2.SmmConfigurationTable[0].VendorTable; #else gSwSmiCpuTrigger = gSmmSystemTable.SmmConfigurationTable[0].VendorTable; #endif #if SMM_USE_FRAMEWORK *SmstTable = &gSmmSystemTable; #endif #if SMM_USE_PI *SmstTable2 = &gSmmSystemTable2; #endif #if SMM_USE_FRAMEWORK pBS->InstallMultipleProtocolInterfaces ( &Handle, &gAmiSmmInfoProtcolGuid, &gAmiSmmInfo, &gEfiSmmCpuSaveStateProtocolGuid, &gEfiSmmCpuSaveState, //SMM thunk either requires AB Segment or CSM. #if SMM_THUNK_NO_AB_SEG == 0 || SMM_THUNK_IN_CSM == 1 &gEfiSmmThunkProtocolGuid, &EfiSmmThunkProtocol, #endif NULL ); #endif #if SMM_USE_PI Handle = NULL; gSmmSystemTable2.SmmInstallProtocolInterface( &Handle, &gAmiSmmInfoProtcolGuid, EFI_NATIVE_INTERFACE, &gAmiSmmInfo ); Handle = NULL; gSmmSystemTable2.SmmInstallProtocolInterface( &Handle, &gEfiSmmCpuSaveStateProtocolGuid, EFI_NATIVE_INTERFACE, &gEfiSmmCpuSaveState ); #if SMM_THUNK_NO_AB_SEG == 0 || SMM_THUNK_IN_CSM == 1 Handle = NULL; gSmmSystemTable2.SmmInstallProtocolInterface( &Handle, &gEfiSmmThunkProtocolGuid, EFI_NATIVE_INTERFACE, &EfiSmmThunkProtocol ); #endif Handle = NULL; gSmmSystemTable2.SmmInstallProtocolInterface( &Handle, &gEfiCpuIo2ProtocolGuid, EFI_NATIVE_INTERFACE, &gSmmSystemTable2.SmmIo ); Handle = NULL; gSmmSystemTable2.SmmInstallProtocolInterface( &Handle, &gEfiCpuProtocolGuid, EFI_NATIVE_INTERFACE, &gEfiSmmCpuProtocol ); #endif return EFI_SUCCESS; } //************************************************************************* //************************************************************************* //** ** //** (C)Copyright 1985-2011, American Megatrends, Inc. ** //** ** //** All Rights Reserved. ** //** ** //** 5555 Oakbrook Parkway, Suite 200, Norcross, GA 30093 ** //** ** //** Phone: (770)-246-8600 ** //** ** //************************************************************************* //*************************************************************************