diff options
Diffstat (limited to 'Core/EM/SMM/SmmDispatcher.c')
-rw-r--r-- | Core/EM/SMM/SmmDispatcher.c | 1533 |
1 files changed, 1533 insertions, 0 deletions
diff --git a/Core/EM/SMM/SmmDispatcher.c b/Core/EM/SMM/SmmDispatcher.c new file mode 100644 index 0000000..c510cc7 --- /dev/null +++ b/Core/EM/SMM/SmmDispatcher.c @@ -0,0 +1,1533 @@ +//************************************************************************* +//************************************************************************* +//** ** +//** (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. +// +// +//********************************************************************** + +//<AMI_FHDR_START> +//--------------------------------------------------------------------------- +// +// Name: SmmDispatcher.c +// +// Description: Contains the SMM dispatcher code for BSP & APs +// +//--------------------------------------------------------------------------- +//<AMI_FHDR_END> + +//This include should be first. +#include "SmmPrivateShared.h" +#include <Protocol\SmmThunk.h> +#include <AmiSmm.h> +#include <Protocol\SmmCpuState.h> +#include <Protocol\AmiSmmInfo.h> +#if SMM_USE_PI +#include "SmmPi.h" +#include <Protocol\SmmCpu.h> +#include <Protocol\SmmControl2.h> +#else +#include <smm.h> +#include <Protocol\SmmControl.h> +#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 +); + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Procedure: CommonEntry +// +// Description: BSP and APs start here from SmmEntry.asm. +// +// Input: +// IN SMM_ENTRY_INIT_STRUCT *SmmEntryInit +// +// Output: +// VOID +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +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. +} + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// 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 +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +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. +} + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// 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 +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +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(); +} + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Procedure: SmmBspEntry +// +// Description: Call Smm call back or dispatch handlers. +// +// Input: +// IN SMM_ENTRY_INIT_STRUCT *SmmEntryInit +// +// Output: +// VOID +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +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. +} + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Procedure: SmmApEntry +// +// Description: APs after switching to protected mode will jump here. +// +// Input: +// IN SMM_ENTRY_INIT_STRUCT *SmmEntryInit +// +// Output: +// VOID +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +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 + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// 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 +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +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; +} + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// 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 +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> +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 + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Procedure: InitInterrupts +// +// Description: +// Install Interrupt Handlers. Initialize the interrupt descriptors. +// +// Input: VOID +// +// Output: VOID +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +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 +} + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Procedure: StartTimeout +// +// Description: +// Initialize timeout for a specified about of time in uS. +// +// Input: +// OUT SMM_TIMEOUT *Timeout +// IN UINT32 Time +// +// Output: EFI_STATUS +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +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; +} + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Procedure: HasItTimedOut +// +// Description: +// Return EFI_TIMEOUT if timer has expired. +// +// Input: +// IN OUT SMM_TIMEOUT *Timeout +// +// Output: EFI_STATUS +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +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 +}; + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Procedure: InitializeDispatcher +// +// Description: Initialize Dispatcher. +// +// Input: +// IN EFI_HANDLE ImageHandle +// IN EFI_SYSTEM_TABLE *SystemTable +// +// Output: +// EFI_STATUS +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> +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 ** +//** ** +//************************************************************************* +//************************************************************************* |