//************************************************************************* //************************************************************************* //** ** //** (C)Copyright 1985-2011, American Megatrends, Inc. ** //** ** //** All Rights Reserved. ** //** ** //** 5555 Oakbrook Parkway, Suite 200, Norcross, GA 30093 ** //** ** //** Phone: (770)-246-8600 ** //** ** //************************************************************************* //************************************************************************* /** SmmPiSmst.c - Protocol functions are modified verision from Intel's SMM source. Copyright (c) 2009, Intel Corporation All rights reserved. This program and the accompanying materials are licensed and made available under the terms and conditions of the BSD License which accompanies this distribution. The full text of the license may be found at http://opensource.org/licenses/bsd-license.php THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. **/ //********************************************************************** // $Header: /Alaska/SOURCE/Modules/SMM/SMMDispatcher/SmmPiSmst.c 6 3/31/11 6:52p Markw $ // // $Revision: 6 $ // // $Date: 3/31/11 6:52p $ //********************************************************************** // Revision History // ---------------- // $Log: /Alaska/SOURCE/Modules/SMM/SMMDispatcher/SmmPiSmst.c $ // // 6 3/31/11 6:52p Markw // Add back revisions 2 to 4. // // 5 3/31/11 6:45p Markw // [TAG] EIP57440 // [Category] New Feature // [Description] Add PI 1.1 SMM support for reading/writing floating // point/smm save state. // // [Files] CpuCspLib.h, CpuCspLib.c, SmmPiSmst.c // // 4 3/15/11 2:35p Markw // Copyright header update. // // 3 3/14/11 3:19p Markw // Update for EIP 53481. // Rename gSmmFirmwareVender to gSmmFirmwareVendor. // For gSmmFirmwareVendor use CONVERT_TO_WSTRING(CORE_VENDOR); instead of // AMI. // // 2 3/08/11 2:00p Markw // Update headers and spacing. // // 1 2/07/11 3:28p 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 // //********************************************************************** // //--------------------------------------------------------------------------- // // Name: SmmPiSmst.c // // Description: PI Smst functions. // //--------------------------------------------------------------------------- // //This include should come first. //#include "SmmPi.h" #include "SmmPrivateShared.h" #include #include #if SMM_USE_PI #include "SmmDispatcher.h" #include #include #endif CHAR16 gSmmFirmwareVendor[] = CONVERT_TO_WSTRING(CORE_VENDOR); extern UINT8 **gSmmBase; //TODOx64: move it to a library header VOID CPULib_Pause(); VOID *Allocate(VOID *Base, UINTN Size,UINTN Alignment); EFI_STATUS AllocateABSegPages( IN EFI_ALLOCATE_TYPE Type, IN UINTN NumberOfPages, IN OUT EFI_PHYSICAL_ADDRESS *Memory ); EFI_STATUS FreeABSegPages( IN EFI_PHYSICAL_ADDRESS Memory, IN UINTN NumberOfPages ); BOOLEAN Free(VOID *Buffer); BOOLEAN Free4kPages(VOID *StartAddress,UINTN Pages); EFI_STATUS InterruptManage( IN CONST EFI_GUID *HandlerType, IN CONST VOID *Context OPTIONAL, IN OUT VOID *CommBuffer OPTIONAL, IN OUT UINTN *CommBufferSize OPTIONAL ); VOID UpdateFrameworkSmmConfigTable(IN EFI_CONFIGURATION_TABLE *SmmConfigurationTable, IN UINTN NumberOfTableEntries); UINT8* Align2n(UINT8 *Value,UINTN Alignment); #if SMM_USE_FRAMEWORK extern EFI_SMM_SYSTEM_TABLE gSmmSystemTable; #endif #if SMM_USE_PI extern EFI_SMM_SYSTEM_TABLE2 gSmmSystemTable2; extern EFI_SMM_ENTRY_CONTEXT gEfiSmmEntryContext; //For now, hardcode. #endif extern SMM_DISPATCHER_PRIVATE_STRUCT *gDispatcherPrivate; #if SMM_USE_PI EFI_STATUS SmmMemRead( IN CONST EFI_SMM_CPU_IO2_PROTOCOL *This, IN EFI_SMM_IO_WIDTH Width, IN UINT64 Address, IN UINTN Count, IN OUT VOID *Buffer ); EFI_STATUS SmmMemWrite( IN CONST EFI_SMM_CPU_IO2_PROTOCOL *This, IN EFI_SMM_IO_WIDTH Width, IN UINT64 Address, IN UINTN Count, IN OUT VOID *Buffer ); EFI_STATUS SmmIoRead( IN CONST EFI_SMM_CPU_IO2_PROTOCOL *This, IN EFI_SMM_IO_WIDTH Width, IN UINT64 Address, IN UINTN Count, IN OUT VOID *Buffer ); EFI_STATUS SmmIoWrite( IN CONST EFI_SMM_CPU_IO2_PROTOCOL *This, IN EFI_SMM_IO_WIDTH Width, IN UINT64 Address, IN UINTN Count, IN OUT VOID *Buffer ); EFI_STATUS SmmSmstAllocatePages( IN EFI_ALLOCATE_TYPE Type, IN EFI_MEMORY_TYPE MemoryType, IN UINTN NumberOfPages, IN OUT EFI_PHYSICAL_ADDRESS *Memory ); EFI_STATUS SmmSmstFreePages( IN EFI_PHYSICAL_ADDRESS Memory, IN UINTN NumberOfPages ); EFI_STATUS SmmStartupThisAp( IN EFI_AP_PROCEDURE Procedure, IN UINTN CpuNumber, IN OUT VOID *ProcArguments OPTIONAL ); #endif EFI_STATUS SmmSmstAllocatePool( IN EFI_MEMORY_TYPE PoolType, IN UINTN Size, OUT VOID **Buffer ); EFI_STATUS SmmSmstFreePool( IN VOID *Buffer ); EFI_STATUS CalculateCrc32( IN VOID *Data, IN UINTN DataSize, OUT UINT32 *Crc32 ); #if SMM_USE_PI EFI_STATUS SmmInstallConfigurationTable( IN EFI_SMM_SYSTEM_TABLE2 *SystemTable, IN EFI_GUID *Guid, IN VOID *Table, IN UINTN TableSize ); EFI_STATUS ReadSaveState( IN CONST EFI_SMM_CPU_PROTOCOL *This, IN UINTN Width, IN EFI_SMM_SAVE_STATE_REGISTER Register, IN UINTN CpuIndex, OUT VOID *Buffer ) { UINT8 *SmmBase; #if SMM_USE_FRAMEWORK UINT8 *SstSaveState; #endif if (CpuIndex >= gDispatcherPrivate->NumCpus) return EFI_INVALID_PARAMETER; SmmBase = gSmmBase[CpuIndex]; #if SMM_USE_FRAMEWORK SstSaveState = (UINT8*)&gSmmSystemTable.CpuSaveState[CpuIndex]; #endif if (Register >= EFI_SMM_SAVE_STATE_REGISTER_FCW && Register <= EFI_SMM_SAVE_STATE_REGISTER_XMM15) { return CpuLib_SmmReadSaveStateFxSave( gDispatcherPrivate->SmmXmmSave[CpuIndex], (UINT8)Width, Register, (VOID*)Buffer ); } return CPULib_SmmReadSaveState( SmmBase, #if SMM_USE_FRAMEWORK SstSaveState, TRUE, #else NULL, FALSE, #endif (UINT8)Width, Register, Buffer ); } EFI_STATUS WriteSaveState( IN CONST EFI_SMM_CPU_PROTOCOL *This, IN UINTN Width, IN EFI_SMM_SAVE_STATE_REGISTER Register, IN UINTN CpuIndex, IN CONST VOID *Buffer ) { UINT8 *SmmBase; #if SMM_USE_FRAMEWORK UINT8 *SstSaveState; #endif if (CpuIndex >= gDispatcherPrivate->NumCpus) return EFI_INVALID_PARAMETER; SmmBase = gSmmBase[CpuIndex]; #if SMM_USE_FRAMEWORK SstSaveState = (UINT8*)&gSmmSystemTable.CpuSaveState[CpuIndex]; #endif if (Register >= EFI_SMM_SAVE_STATE_REGISTER_FCW && Register <= EFI_SMM_SAVE_STATE_REGISTER_XMM15) { return CpuLib_SmmWriteSaveStateFxSave( gDispatcherPrivate->SmmXmmSave[CpuIndex], (UINT8)Width, Register, (VOID*)Buffer ); } return CPULib_SmmWriteSaveState( SmmBase, #if SMM_USE_FRAMEWORK SstSaveState, TRUE, #else NULL, FALSE, #endif (UINT8)Width, Register, Buffer ); } EFI_SMM_CPU_PROTOCOL gEfiSmmCpuProtocol = { ReadSaveState, WriteSaveState }; static EFI_LIST_ENTRY SmmProtocolDatabase = INITIALIZE_LIST_HEAD_VARIABLE (SmmProtocolDatabase); EFI_LIST_ENTRY SmmHandleList = INITIALIZE_LIST_HEAD_VARIABLE (SmmHandleList); UINTN mEfiLocateHandleRequest = 0; // Added for SmmSmstLocateProtocol EFI_LIST_ENTRY mRootSmiHandlerList = INITIALIZE_LIST_HEAD_VARIABLE (mRootSmiHandlerList); EFI_LIST_ENTRY mSmiEntryList = INITIALIZE_LIST_HEAD_VARIABLE (mSmiEntryList); SMM_IHANDLE *SmmGetNextLocateByRegisterNotify( IN OUT SMM_LOCATE_POSITION *Position, OUT VOID **Interface ); SMM_IHANDLE *SmmGetNextLocateByProtocol ( IN OUT SMM_LOCATE_POSITION *Position, OUT VOID **Interface ); SMM_IHANDLE *SmmGetNextLocateAllHandles ( IN OUT SMM_LOCATE_POSITION *Position, OUT VOID **Interface ); // //--------------------------------------------------------------------------- // // Procedure: SmmValidateHandle // // Description: Check whether a handle is a valid EFI_HANDLE. // // Input: // IN EFI_HANDLE UserHandle // Output: // EFI_STATUS //---------------------------------------------------------------------------- // EFI_STATUS SmmValidateHandle ( IN EFI_HANDLE UserHandle ) { SMM_IHANDLE *Handle; Handle = (SMM_IHANDLE *)UserHandle; if (Handle == NULL) { return EFI_INVALID_PARAMETER; } if (Handle->Signature != SMM_EFI_HANDLE_SIGNATURE) { return EFI_INVALID_PARAMETER; } return EFI_SUCCESS; } // //--------------------------------------------------------------------------- // // Procedure: SmmFindProtocolEntry // // Description: Finds the protocol entry for the requested protocol. // // Input: // IN EFI_GUID *Protocol // IN BOOLEAN Create // // Output: // Protocol entry //---------------------------------------------------------------------------- // SMM_PROTOCOL_ENTRY * SmmFindProtocolEntry ( IN EFI_GUID *Protocol, IN BOOLEAN Create ) { EFI_LIST_ENTRY *Link; SMM_PROTOCOL_ENTRY *Item; SMM_PROTOCOL_ENTRY *ProtEntry; EFI_STATUS Status; // // Search the database for the matching GUID // ProtEntry = NULL; for (Link = SmmProtocolDatabase.ForwardLink; Link != &SmmProtocolDatabase; Link = Link->ForwardLink ) { Item = CR(Link, SMM_PROTOCOL_ENTRY, AllEntries, SMM_PROTOCOL_ENTRY_SIGNATURE); if ( !guidcmp (&Item->ProtocolID, Protocol)) { // // This is the protocol entry // ProtEntry = Item; break; } } // // If the protocol entry was not found and Create is TRUE, then // allocate a new entry // if ((ProtEntry == NULL) && Create) { Status = SmmSmstAllocatePool(0,sizeof(SMM_PROTOCOL_ENTRY),&ProtEntry); // ********** Probe whether it works? Typecast to VOID** to make it go thro SmmPiAllocatePool. if (ProtEntry != NULL) { // // Initialize new protocol entry structure // ProtEntry->Signature = SMM_PROTOCOL_ENTRY_SIGNATURE; ProtEntry->ProtocolID = *Protocol; // This done as Core Handle.C function implementation. InitializeListHead (&ProtEntry->Protocols); InitializeListHead (&ProtEntry->Notify); // // Add it to protocol database // InsertTailList (&SmmProtocolDatabase, &ProtEntry->AllEntries); } } return ProtEntry; } // //--------------------------------------------------------------------------- // // Procedure: SmmFindProtocolInterface // // Description: // Finds the protocol instance for the requested handle and protocol. // Note: This function doesn't do parameters checking, it's caller's responsibility // to pass in valid parameters. // // Input: // IN SMM_IHANDLE *Handle, // IN EFI_GUID *Protocol // IN VOID *Interface // // Output: // Protocol instance (NULL: Not found) //---------------------------------------------------------------------------- // SMM_PROTOCOL_INTERFACE * SmmFindProtocolInterface ( IN SMM_IHANDLE *Handle, IN EFI_GUID *Protocol, IN VOID *Interface ) { SMM_PROTOCOL_INTERFACE *Prot; SMM_PROTOCOL_ENTRY *ProtEntry; EFI_LIST_ENTRY *Link; Prot = NULL; // // Lookup the protocol entry for this protocol ID // ProtEntry = SmmFindProtocolEntry (Protocol, FALSE); if (ProtEntry != NULL) { // // Look at each protocol interface for any matches // for (Link = Handle->Protocols.ForwardLink; Link != &Handle->Protocols; Link=Link->ForwardLink) { // // If this protocol interface matches, remove it // Prot = CR(Link, SMM_PROTOCOL_INTERFACE, Link, SMM_PROTOCOL_INTERFACE_SIGNATURE); if (Prot->Interface == Interface && Prot->Protocol == ProtEntry) { break; } Prot = NULL; } } return Prot; } // //--------------------------------------------------------------------------- // // Procedure: SmmNotifyProtocol // // Description: Signal event for every protocol in protocol entry. // // Input: // IN SMM_PROTOCOL_INTERFACE *Prot // Output: // VOID //---------------------------------------------------------------------------- // VOID SmmNotifyProtocol ( IN SMM_PROTOCOL_INTERFACE *Prot ) { SMM_PROTOCOL_ENTRY *ProtEntry; SMM_PROTOCOL_NOTIFY *ProtNotify; EFI_LIST_ENTRY *Link; ProtEntry = Prot->Protocol; for (Link=ProtEntry->Notify.ForwardLink; Link != &ProtEntry->Notify; Link=Link->ForwardLink) { ProtNotify = CR(Link, SMM_PROTOCOL_NOTIFY, Link, SMM_PROTOCOL_NOTIFY_SIGNATURE); ProtNotify->Function (&ProtEntry->ProtocolID, Prot->Interface, Prot->Handle); } } // //--------------------------------------------------------------------------- // // Procedure: SmmSmstInstallProtocolInterface // // Description: // Wrapper function to SmmInstallProtocolInterfaceNotify. This is the public API which // Calls the private one which contains a BOOLEAN parameter for notifications // // Input: // IN OUT EFI_HANDLE *Handle // IN EFI_GUID *Protocol // IN EFI_INTERFACE_TYPE InterfaceType // IN VOID Interface // // Output: EFI_STATUS //--------------------------------------------------------------------------- // EFI_STATUS SmmSmstInstallProtocolInterface ( IN OUT EFI_HANDLE *UserHandle, IN EFI_GUID *Protocol, IN EFI_INTERFACE_TYPE InterfaceType, IN VOID *Interface ) { return SmmSmstInstallProtocolInterfaceNotify ( UserHandle, Protocol, InterfaceType, Interface, TRUE ); } // //--------------------------------------------------------------------------- // // Procedure: SmmSmstInstallProtocolInterfaceNotify // // Description: Installs a protocol interface into the boot services environment. // Input: // IN OUT EFI_HANDLE *UserHandle, // IN EFI_GUID *Protocol, // IN EFI_INTERFACE_TYPE InterfaceType, // IN VOID *Interface, // IN BOOLEAN Notify // // Output: EFI_STATUS //--------------------------------------------------------------------------- // EFI_STATUS SmmSmstInstallProtocolInterfaceNotify ( IN OUT EFI_HANDLE *UserHandle, IN EFI_GUID *Protocol, IN EFI_INTERFACE_TYPE InterfaceType, IN VOID *Interface, IN BOOLEAN Notify ) { SMM_PROTOCOL_INTERFACE *Prot; SMM_PROTOCOL_ENTRY *ProtEntry; SMM_IHANDLE *Handle; EFI_STATUS Status; VOID *ExistingInterface; // // returns EFI_INVALID_PARAMETER if InterfaceType is invalid. // Also added check for invalid UserHandle and Protocol pointers. // if (UserHandle == NULL || Protocol == NULL) { return EFI_INVALID_PARAMETER; } if (InterfaceType != EFI_NATIVE_INTERFACE) { return EFI_INVALID_PARAMETER; } // // Print debug message // //DEBUG((DEBUG_LOAD | DEBUG_INFO, "SmmInstallProtocolInterface: %g %p\n", Protocol, Interface)); Status = EFI_OUT_OF_RESOURCES; Prot = NULL; Handle = NULL; if (*UserHandle != NULL) { Status = SmmSmstHandleProtocol(*UserHandle, Protocol, (VOID **)&ExistingInterface); if (!EFI_ERROR (Status)) { return EFI_INVALID_PARAMETER; } } // // Lookup the Protocol Entry for the requested protocol // ProtEntry = SmmFindProtocolEntry (Protocol, TRUE); if (ProtEntry == NULL) { goto Done; } // // Allocate a new protocol interface structure // Status = SmmSmstAllocatePool(0,sizeof(SMM_PROTOCOL_INTERFACE),&Prot); MemSet(Prot,(Prot == NULL) ? 0 : sizeof(SMM_PROTOCOL_INTERFACE), 0); if (Prot == NULL) { Status = EFI_OUT_OF_RESOURCES; goto Done; } // // If caller didn't supply a handle, allocate a new one // Handle = (SMM_IHANDLE *)*UserHandle; if (Handle == NULL) { Status = SmmSmstAllocatePool(0,sizeof(SMM_IHANDLE),&Handle); MemSet(Handle,(Handle == NULL) ? 0 : sizeof(SMM_IHANDLE), 0); if (Handle == NULL) { Status = EFI_OUT_OF_RESOURCES; goto Done; } // // Initialize new handler structure // Handle->Signature = SMM_EFI_HANDLE_SIGNATURE; InitializeListHead (&Handle->Protocols); // // Add this handle to the list global list of all handles // in the system // InsertTailList (&SmmHandleList, &Handle->AllHandles); } Status = SmmValidateHandle (Handle); if (EFI_ERROR (Status)) { goto Done; } // // Each interface that is added must be unique // ASSERT (SmmFindProtocolInterface (Handle, Protocol, Interface) == NULL); // // Initialize the protocol interface structure // Prot->Signature = SMM_PROTOCOL_INTERFACE_SIGNATURE; Prot->Handle = Handle; Prot->Protocol = ProtEntry; Prot->Interface = Interface; // // Add this protocol interface to the head of the supported // protocol list for this handle // InsertHeadList (&Handle->Protocols, &Prot->Link); // // Add this protocol interface to the tail of the // protocol entry // InsertTailList (&ProtEntry->Protocols, &Prot->ByProtocol); // // Notify the notification list for this protocol // if (Notify) { SmmNotifyProtocol (Prot); } Status = EFI_SUCCESS; Done: if (!EFI_ERROR (Status)) { // // Return the new handle back to the caller // *UserHandle = Handle; } else { // // There was an error, clean up // if (Prot != NULL) { SmmSmstFreePool (Prot); } } return Status; } // //--------------------------------------------------------------------------- // // Procedure: SmmSmstUninstallProtocolInterface // // Description: // Uninstalls all instances of a protocol:interfacer from a handle. // If the last protocol interface is remove from the handle, the // handle is freed. // // Input: // IN OUT EFI_HANDLE UserHandle // IN EFI_GUID *Protocol // IN VOID *Interface // // Output: EFI_STATUS //--------------------------------------------------------------------------- // EFI_STATUS SmmSmstUninstallProtocolInterface ( IN OUT EFI_HANDLE UserHandle, IN EFI_GUID *Protocol, IN VOID *Interface ) { EFI_STATUS Status; SMM_IHANDLE *Handle; SMM_PROTOCOL_INTERFACE *Prot; // // Check that Protocol is valid // if (Protocol == NULL) { return EFI_INVALID_PARAMETER; } // // Check that UserHandle is a valid handle // Status = SmmValidateHandle (UserHandle); if (EFI_ERROR (Status)) { return Status; } // // Check that Protocol exists on UserHandle, and Interface matches the interface in the database // Prot = SmmFindProtocolInterface (UserHandle, Protocol, Interface); if (Prot == NULL) { return EFI_NOT_FOUND; } // // Remove the protocol interface from the protocol // Status = EFI_NOT_FOUND; Handle = (SMM_IHANDLE *)UserHandle; Prot = SmmRemoveInterfaceFromProtocol (Handle, Protocol, Interface); if (Prot != NULL) { // // Remove the protocol interface from the handle // RemoveEntryList (&Prot->Link); // // Free the memory // Prot->Signature = 0; SmmSmstFreePool(Prot); Status = EFI_SUCCESS; } // // If there are no more handlers for the handle, free the handle // if (IsListEmpty (&Handle->Protocols)) { Handle->Signature = 0; RemoveEntryList (&Handle->AllHandles); SmmSmstFreePool (Handle); } return Status; } // //--------------------------------------------------------------------------- // // Procedure: SmmRemoveInterfaceFromProtocol // // Description: Removes Protocol from the protocol list (but not the handle list). // // Input: // IN SMM_IHANDLE *Handle, // IN EFI_GUID *Protocol // IN VOID *Interface // // Output: Protocol Entry //--------------------------------------------------------------------------- // SMM_PROTOCOL_INTERFACE * SmmRemoveInterfaceFromProtocol ( IN SMM_IHANDLE *Handle, IN EFI_GUID *Protocol, IN VOID *Interface ) { SMM_PROTOCOL_INTERFACE *Prot; SMM_PROTOCOL_NOTIFY *ProtNotify; SMM_PROTOCOL_ENTRY *ProtEntry; EFI_LIST_ENTRY *Link; Prot = SmmFindProtocolInterface (Handle, Protocol, Interface); if (Prot != NULL) { ProtEntry = Prot->Protocol; // // If there's a protocol notify location pointing to this entry, back it up one // for(Link = ProtEntry->Notify.ForwardLink; Link != &ProtEntry->Notify; Link=Link->ForwardLink) { ProtNotify = CR(Link, SMM_PROTOCOL_NOTIFY, Link, SMM_PROTOCOL_NOTIFY_SIGNATURE); if (ProtNotify->Position == &Prot->ByProtocol) { ProtNotify->Position = Prot->ByProtocol.BackLink; } } // // Remove the protocol interface entry // RemoveEntryList (&Prot->ByProtocol); } return Prot; } // //--------------------------------------------------------------------------- // // Procedure: SmmGetProtocolInterface // // Description: Locate a certain GUID protocol interface in a Handle's protocols. // // Input: // IN EFI_HANDLE UserHandle, // IN EFI_GUID *Protocol // // Output: // The requested protocol interface for the handle. //--------------------------------------------------------------------------- // SMM_PROTOCOL_INTERFACE * SmmGetProtocolInterface ( IN EFI_HANDLE UserHandle, IN EFI_GUID *Protocol ) { EFI_STATUS Status; SMM_PROTOCOL_ENTRY *ProtEntry; SMM_PROTOCOL_INTERFACE *Prot; SMM_IHANDLE *Handle; EFI_LIST_ENTRY *Link; Status = SmmValidateHandle (UserHandle); if (EFI_ERROR (Status)) { return NULL; } Handle = (SMM_IHANDLE *)UserHandle; // // Look at each protocol interface for a match // for (Link = Handle->Protocols.ForwardLink; Link != &Handle->Protocols; Link = Link->ForwardLink) { Prot = CR(Link, SMM_PROTOCOL_INTERFACE, Link, SMM_PROTOCOL_INTERFACE_SIGNATURE); ProtEntry = Prot->Protocol; if (!guidcmp(&ProtEntry->ProtocolID, Protocol)) { return Prot; } } return NULL; } // //--------------------------------------------------------------------------- // // Procedure: SmmSmstHandleProtocol // // Description: Queries a handle to determine if it supports a specified protocol. // // Input: // IN OUT EFI_HANDLE UserHandle // IN EFI_GUID *Protocol // OUT VOID **Interface // // Output: // EFI_STATUS //--------------------------------------------------------------------------- // EFI_STATUS SmmSmstHandleProtocol ( IN OUT EFI_HANDLE UserHandle, IN EFI_GUID *Protocol, OUT VOID **Interface ) { EFI_STATUS Status; SMM_PROTOCOL_INTERFACE *Prot; // // Check for invalid Protocol // if (Protocol == NULL) { return EFI_INVALID_PARAMETER; } // // Check for invalid Interface // if (Interface == NULL) { return EFI_INVALID_PARAMETER; } else { *Interface = NULL; } // // Check for invalid UserHandle // Status = SmmValidateHandle (UserHandle); if (EFI_ERROR (Status)) { return Status; } // // Look at each protocol interface for a match // Prot = SmmGetProtocolInterface (UserHandle, Protocol); if (Prot == NULL) { return EFI_UNSUPPORTED; } // // This is the protocol interface entry for this protocol // *Interface = Prot->Interface; return EFI_SUCCESS; } // //--------------------------------------------------------------------------- // // Procedure: SmmSmstRegisterProtocolNotify // // Description: Add a new protocol notification record for the request protocol. // // Input: // IN EFI_GUID *Protocol // IN EFI_SMM_NOTIFY_FN Function // OUT VOID **Registration // // Output: // EFI_STATUS //--------------------------------------------------------------------------- // EFI_STATUS SmmSmstRegisterProtocolNotify ( IN CONST EFI_GUID *Protocol, IN EFI_SMM_NOTIFY_FN Function, OUT VOID **Registration) { SMM_PROTOCOL_ENTRY *ProtEntry=NULL; SMM_PROTOCOL_NOTIFY *ProtNotify=NULL; EFI_LIST_ENTRY *Link; // EFI_GUID *protocol=(EFI_GUID*)Protocol; EFI_STATUS Status; if ((Protocol == NULL) || (Function == NULL) || (Registration == NULL)) { return EFI_INVALID_PARAMETER; } ProtNotify = NULL; // // Get the protocol entry to add the notification too // ProtEntry = SmmFindProtocolEntry ((EFI_GUID *) Protocol, TRUE); if (ProtEntry != NULL) { // // Find whether notification already exist // for (Link = ProtEntry->Notify.ForwardLink; Link != &ProtEntry->Notify; Link = Link->ForwardLink) { ProtNotify = CR(Link, SMM_PROTOCOL_NOTIFY, Link, SMM_PROTOCOL_NOTIFY_SIGNATURE); if ((!guidcmp(&ProtNotify->Protocol->ProtocolID, (EFI_GUID*)Protocol)) && (ProtNotify->Function == Function) ) { // // Notification already exist // *Registration = ProtNotify; return EFI_SUCCESS; } } // // Allocate a new notification record // Status = SmmSmstAllocatePool(0,sizeof(SMM_PROTOCOL_NOTIFY),&ProtNotify); ASSERT_EFI_ERROR(Status); if (ProtNotify != NULL) { ProtNotify->Signature = SMM_PROTOCOL_NOTIFY_SIGNATURE; ProtNotify->Protocol = ProtEntry; ProtNotify->Function = Function; // // Start at the ending // ProtNotify->Position = ProtEntry->Protocols.BackLink; InsertTailList (&ProtEntry->Notify, &ProtNotify->Link); } } // // Done. If we have a protocol notify entry, then return it. // Otherwise, we must have run out of resources trying to add one // Status = EFI_OUT_OF_RESOURCES; if (ProtNotify != NULL) { *Registration = ProtNotify; Status = EFI_SUCCESS; } return Status; } // //--------------------------------------------------------------------------- // // Procedure: SmmSmstLocateHandle // // Description: Locates the requested handle(s) and returns them in Buffer. // // Input: // IN EFI_LOCATE_SEARCH_TYPE SearchType // IN EFI_GUID *Protocol OPTIONAL // IN VOID *SearchKey OPTIONAL // IN OUT UINTN *BufferSize // OUT EFI_HANDLE *Buffer // // Output: // EFI_STATUS //--------------------------------------------------------------------------- // EFI_STATUS SmmSmstLocateHandle ( IN EFI_LOCATE_SEARCH_TYPE SearchType, IN EFI_GUID *Protocol OPTIONAL, IN VOID *SearchKey OPTIONAL, IN OUT UINTN *BufferSize, OUT EFI_HANDLE *Buffer ) { EFI_STATUS Status; SMM_LOCATE_POSITION Position; SMM_PROTOCOL_NOTIFY *ProtNotify; SMM_CORE_GET_NEXT GetNext; UINTN ResultSize; SMM_IHANDLE *Handle; SMM_IHANDLE **ResultBuffer; VOID *Interface; if (BufferSize == NULL) { return EFI_INVALID_PARAMETER; } if ((*BufferSize > 0) && (Buffer == NULL)) { return EFI_INVALID_PARAMETER; } GetNext = NULL; // // Set initial position // Position.Protocol = Protocol; Position.SearchKey = SearchKey; Position.Position = &SmmHandleList; ResultSize = 0; ResultBuffer = (SMM_IHANDLE **) Buffer; Status = EFI_SUCCESS; // // Get the search function based on type // switch (SearchType) { case AllHandles: GetNext = SmmGetNextLocateAllHandles; break; case ByRegisterNotify: GetNext = SmmGetNextLocateByRegisterNotify; // // Must have SearchKey for locate ByRegisterNotify // if (SearchKey == NULL) { Status = EFI_INVALID_PARAMETER; } break; case ByProtocol: GetNext = SmmGetNextLocateByProtocol; if (Protocol == NULL) { Status = EFI_INVALID_PARAMETER; break; } // // Look up the protocol entry and set the head pointer // Position.ProtEntry = SmmFindProtocolEntry (Protocol, FALSE); if (Position.ProtEntry == NULL) { Status = EFI_NOT_FOUND; break; } Position.Position = &Position.ProtEntry->Protocols; break; default: Status = EFI_INVALID_PARAMETER; break; } if (EFI_ERROR(Status)) { return Status; } // // Enumerate out the matching handles // mEfiLocateHandleRequest += 1; for (; ;) { // // Get the next handle. If no more handles, stop // Handle = GetNext (&Position, &Interface); if (NULL == Handle) { break; } // // Increase the resulting buffer size, and if this handle // fits return it // ResultSize += sizeof(Handle); if (ResultSize <= *BufferSize) { *ResultBuffer = Handle; ResultBuffer += 1; } } // // If the result is a zero length buffer, then there were no // matching handles // if (ResultSize == 0) { Status = EFI_NOT_FOUND; } else { // // Return the resulting buffer size. If it's larger than what // was passed, then set the error code // if (ResultSize > *BufferSize) { Status = EFI_BUFFER_TOO_SMALL; } *BufferSize = ResultSize; if (SearchType == ByRegisterNotify && !EFI_ERROR(Status)) { ASSERT (SearchKey != NULL); // // If this is a search by register notify and a handle was // returned, update the register notification position // ProtNotify = SearchKey; ProtNotify->Position = ProtNotify->Position->ForwardLink; } } return Status; } // //--------------------------------------------------------------------------- // // Procedure: SmmSmstLocateProtocol // // Description: // Return the first Protocol Interface that matches the Protocol GUID. If // Registration is passed in, return a Protocol Instance that was just add // to the system. If Registration is NULL return the first Protocol Interface // you find. // // Input: // IN EFI_GUID *Protocol, // IN VOID *Registration OPTIONAL // OUT VOID **Interface // // Output: // EFI_STATUS //--------------------------------------------------------------------------- // EFI_STATUS SmmSmstLocateProtocol ( IN EFI_GUID *Protocol, IN VOID *Registration OPTIONAL, OUT VOID **Interface ) { EFI_STATUS Status; SMM_LOCATE_POSITION Position; SMM_PROTOCOL_NOTIFY *ProtNotify; SMM_IHANDLE *Handle; if (Interface == NULL) { return EFI_INVALID_PARAMETER; } if (Protocol == NULL) { return EFI_NOT_FOUND; } *Interface = NULL; Status = EFI_SUCCESS; // // Set initial position // Position.Protocol = Protocol; Position.SearchKey = Registration; Position.Position = &SmmHandleList; mEfiLocateHandleRequest += 1; if (Registration == NULL) { // // Look up the protocol entry and set the head pointer // Position.ProtEntry = SmmFindProtocolEntry (Protocol, FALSE); if (Position.ProtEntry == NULL) { return EFI_NOT_FOUND; } Position.Position = &Position.ProtEntry->Protocols; Handle = SmmGetNextLocateByProtocol (&Position, Interface); } else { Handle = SmmGetNextLocateByRegisterNotify (&Position, Interface); } if (Handle == NULL) { Status = EFI_NOT_FOUND; } else if (Registration != NULL) { // // If this is a search by register notify and a handle was // returned, update the register notification position // ProtNotify = Registration; ProtNotify->Position = ProtNotify->Position->ForwardLink; } return Status; } // //--------------------------------------------------------------------------- // // Procedure: SmmGetNextLocateAllHandles // // Description: // Find next handle. // // Input: // IN OUT SMM_LOCATE_POSITION *Position, // OUT VOID **Interface // // Output: // SMM_IHANDLE //--------------------------------------------------------------------------- // SMM_IHANDLE *SmmGetNextLocateAllHandles ( IN OUT SMM_LOCATE_POSITION *Position, OUT VOID **Interface ) { SMM_IHANDLE *Handle; // // Next handle // Position->Position = Position->Position->ForwardLink; // // If not at the end of the list, get the handle // Handle = NULL; *Interface = NULL; if (Position->Position != &SmmHandleList) { Handle = CR (Position->Position, SMM_IHANDLE, AllHandles, SMM_EFI_HANDLE_SIGNATURE); } return Handle; } // //--------------------------------------------------------------------------- // // Procedure: SmmGetNextLocateByRegisterNotify // // Description: Routine to get the next Handle, when you are searching for register protocol // notifies. // // Input: // IN OUT SMM_LOCATE_POSITION *Position // OUT VOID **Interface // // Output: // An pointer to SMM_IHANDLE if the next Position is not the end of the list. // Otherwise,NULL is returned. //--------------------------------------------------------------------------- // SMM_IHANDLE *SmmGetNextLocateByRegisterNotify ( IN OUT SMM_LOCATE_POSITION *Position, OUT VOID **Interface ) { SMM_IHANDLE *Handle; SMM_PROTOCOL_NOTIFY *ProtNotify; SMM_PROTOCOL_INTERFACE *Prot; EFI_LIST_ENTRY *Link; Handle = NULL; *Interface = NULL; ProtNotify = Position->SearchKey; // // If this is the first request, get the next handle // if (ProtNotify != NULL) { ASSERT(ProtNotify->Signature == SMM_PROTOCOL_NOTIFY_SIGNATURE); Position->SearchKey = NULL; // // If not at the end of the list, get the next handle // Link = ProtNotify->Position->ForwardLink; if (Link != &ProtNotify->Protocol->Protocols) { Prot = CR (Link, SMM_PROTOCOL_INTERFACE, ByProtocol, SMM_PROTOCOL_INTERFACE_SIGNATURE); Handle = Prot->Handle; *Interface = Prot->Interface; } } return Handle; } // //--------------------------------------------------------------------------- // // Procedure: SmmGetNextLocateByProtocol // // Description: Routine to get the next Handle, when you are searching for a given protocol. // // Input: // IN OUT SMM_LOCATE_POSITION *Position // OUT VOID **Interface // // Output: // An pointer to SMM_IHANDLE if the next Position is not the end of the list. // Otherwise,NULL is returned. //--------------------------------------------------------------------------- // SMM_IHANDLE *SmmGetNextLocateByProtocol ( IN OUT SMM_LOCATE_POSITION *Position, OUT VOID **Interface ) { SMM_IHANDLE *Handle; EFI_LIST_ENTRY *Link; SMM_PROTOCOL_INTERFACE *Prot; Handle = NULL; *Interface = NULL; for (; ;) { // // Next entry // Link = Position->Position->ForwardLink; Position->Position = Link; // // If not at the end, return the handle // if (Link == &Position->ProtEntry->Protocols) { Handle = NULL; break; } // // Get the handle // Prot = CR(Link, SMM_PROTOCOL_INTERFACE, ByProtocol, SMM_PROTOCOL_INTERFACE_SIGNATURE); Handle = Prot->Handle; *Interface = Prot->Interface; // // If this handle has not been returned this request, then // return it now // if (Handle->LocateRequest != mEfiLocateHandleRequest) { Handle->LocateRequest = mEfiLocateHandleRequest; break; } } return Handle; } // //--------------------------------------------------------------------------- // // Procedure: SmmCoreFindSmiEntry // // Description: Find Smi Entry // // Input: // IN EFI_GUID *HandlerType // IN BOOLEAN Create // // Output: SMM_SMI_ENTRY //--------------------------------------------------------------------------- // SMM_SMI_ENTRY* SmmCoreFindSmiEntry ( IN EFI_GUID *HandlerType, IN BOOLEAN Create ) { EFI_LIST_ENTRY *Link; SMM_SMI_ENTRY *Item; SMM_SMI_ENTRY *SmiEntry; EFI_STATUS Status; // // Search the SMI entry list for the matching GUID // SmiEntry = NULL; for (Link = mSmiEntryList.ForwardLink; Link != &mSmiEntryList; Link = Link->ForwardLink) { Item = CR (Link, SMM_SMI_ENTRY, AllEntries, SMI_ENTRY_SIGNATURE); if (!guidcmp(&Item->HandlerType, HandlerType)) { // // This is the SMI entry // SmiEntry = Item; break; } } // // If the protocol entry was not found and Create is TRUE, then // allocate a new entry // if ((SmiEntry == NULL) && Create) { Status = SmmSmstAllocatePool (0,sizeof(SMM_SMI_ENTRY),&SmiEntry); if (EFI_ERROR(Status) || (SmiEntry != NULL)) { // // Initialize new SMI entry structure // SmiEntry->Signature = SMI_ENTRY_SIGNATURE; MemCpy((VOID *)&SmiEntry->HandlerType, HandlerType, sizeof(EFI_GUID)); InitializeListHead (&SmiEntry->SmiHandlers); // Add it to SMI entry list InsertTailList (&mSmiEntryList, &SmiEntry->AllEntries); } } return SmiEntry; } // //--------------------------------------------------------------------------- // // Procedure: SmiHandlerRegister // // Description: Register SMI Handle // // Input: // IN EFI_SMM_HANDLER_ENTRY_POINT2 Handler, // IN CONST EFI_GUID *HandlerType OPTIONAL, // OUT EFI_HANDLE *DispatchHandle // // Output: EFI_STATUS //--------------------------------------------------------------------------- // EFI_STATUS SmiHandlerRegister( IN EFI_SMM_HANDLER_ENTRY_POINT2 Handler, IN CONST EFI_GUID *HandlerType OPTIONAL, OUT EFI_HANDLE *DispatchHandle ) { HANDLER_LIST *HandlerInfo, *Link; if (gSmmSystemTable2.SmmAllocatePool(0, sizeof(HANDLER_LIST), &HandlerInfo) != EFI_SUCCESS) return EFI_OUT_OF_RESOURCES; HandlerInfo->IsPi = TRUE; HandlerInfo->EntryPoint = Handler; HandlerInfo->SmmImageHandle = HandlerInfo; if (HandlerType) { MemCpy(&HandlerInfo->HandlerType, (EFI_GUID*)HandlerType, sizeof(EFI_GUID)); HandlerInfo->IsRoot = FALSE; } else HandlerInfo->IsRoot = TRUE; HandlerInfo->Link = 0; //If very first add. if (!gDispatcherPrivate->HandlerListHead) { gDispatcherPrivate->HandlerListHead = HandlerInfo; return EFI_SUCCESS; } //Add to end of list. for (Link = gDispatcherPrivate->HandlerListHead; Link->Link; Link = Link->Link); //Find end of list Link->Link = HandlerInfo; return EFI_SUCCESS; } EFI_STATUS SmiHandlerUnRegister(IN EFI_HANDLE DispatchHandle) { HANDLER_LIST *Link = gDispatcherPrivate->HandlerListHead; HANDLER_LIST *PrevLink; while (Link != 0) { if (Link->SmmImageHandle == DispatchHandle) { if (Link == gDispatcherPrivate->HandlerListHead) { gDispatcherPrivate->HandlerListHead = Link->Link; } else { PrevLink->Link = Link->Link; } SmmSmstFreePool(Link); return EFI_SUCCESS; } PrevLink = Link; Link = Link->Link; } return EFI_INVALID_PARAMETER; } EFI_SMM_SYSTEM_TABLE2 gSmmSystemTable2 = { { //Header SMM_SMST_SIGNATURE2, //Signature EFI_SMM_SYSTEM_TABLE_REVISION2, //Revison will show 1.1 sizeof(EFI_SMM_SYSTEM_TABLE2), //Header size 0, //CRC32 0 //Reserved }, gSmmFirmwareVendor, //Vendor 0, //Vendor version SmmInstallConfigurationTable, { { SmmMemRead, SmmMemWrite }, { SmmIoRead, SmmIoWrite } }, SmmSmstAllocatePool, SmmSmstFreePool, SmmSmstAllocatePages, SmmSmstFreePages, SmmStartupThisAp, 1, //Executing CPU 1, //Number of CPUs 0, //CpuSaveStateSize...PI 1.1 0, //Cpu Save State 0, //Number of Table Entries 0, //Table pointer SmmSmstInstallProtocolInterface, SmmSmstUninstallProtocolInterface, SmmSmstHandleProtocol, SmmSmstRegisterProtocolNotify, SmmSmstLocateHandle, SmmSmstLocateProtocol, InterruptManage, SmiHandlerRegister, SmiHandlerUnRegister }; // //--------------------------------------------------------------------------- // // Procedure: InsertTailList // // Description: // Insert a Node into the end of a doubly linked list. The list must have // been initialized with InitializeListHead () before using this function. // // // Input: // IN EFI_LIST_ENTRY *ListHead // IN EFI_LIST_ENTRY *Entry // // Output: VOID //--------------------------------------------------------------------------- // VOID InsertTailList ( IN EFI_LIST_ENTRY *ListHead, IN EFI_LIST_ENTRY *Entry ) { EFI_LIST_ENTRY *_ListHead; EFI_LIST_ENTRY *_BackLink; _ListHead = ListHead; _BackLink = _ListHead->BackLink; Entry->ForwardLink = _ListHead; Entry->BackLink = _BackLink; _BackLink->ForwardLink = Entry; _ListHead->BackLink = Entry; } // //--------------------------------------------------------------------------- // // Procedure: InsertHeadList // // Description: // Insert a Node into the start of a doubly linked list. The list must have // been initialized with InitializeListHead () before using this function. // // Input: // IN EFI_LIST_ENTRY *ListHead // IN EFI_LIST_ENTRY *Entry // // Output: VOID //--------------------------------------------------------------------------- // VOID InsertHeadList ( IN EFI_LIST_ENTRY *ListHead, IN EFI_LIST_ENTRY *Entry ) { EFI_LIST_ENTRY *_ListHead; EFI_LIST_ENTRY *_ForwardLink; _ListHead = ListHead; _ForwardLink = _ListHead->ForwardLink; Entry->ForwardLink = _ForwardLink; Entry->BackLink = _ListHead; _ForwardLink->BackLink = Entry; _ListHead->ForwardLink = Entry; } // //--------------------------------------------------------------------------- // // Procedure: InitializeListHead // // Description: // Initialize the head of the List. The caller must allocate the memory // for the EFI_LIST. This function must be called before the other linked // list macros can be used. // // Input: // IN EFI_LIST_ENTRY *List // // Output: VOID //--------------------------------------------------------------------------- // VOID InitializeListHead ( IN EFI_LIST_ENTRY *List ) { List->ForwardLink = List; List->BackLink = List; } // //--------------------------------------------------------------------------- // // Procedure: IsListEmpty // // Description: // Return TRUE is the list contains zero nodes. Otherwise return FALSE. // The list must have been initialized with InitializeListHead () before using // this function. // // Input: // IN EFI_LIST_ENTRY *List // // Output: VOID //--------------------------------------------------------------------------- // BOOLEAN IsListEmpty ( IN EFI_LIST_ENTRY *List ) { return (BOOLEAN)(List->ForwardLink == List); } // //--------------------------------------------------------------------------- // // Procedure: RemoveEntryList // // Description: // Remove Node from the doubly linked list. It is the caller's responsibility // to free any memory used by the entry if needed. The list must have been // initialized with InitializeListHead () before using this function. // // Input: // IN EFI_LIST_ENTRY *Entry // // Output: VOID //--------------------------------------------------------------------------- // VOID RemoveEntryList ( EFI_LIST_ENTRY *Entry ) { EFI_LIST_ENTRY *_ForwardLink; EFI_LIST_ENTRY *_BackLink; _ForwardLink = Entry->ForwardLink; _BackLink = Entry->BackLink; _BackLink->ForwardLink = _ForwardLink; _ForwardLink->BackLink = _BackLink; #if EFI_DEBUG Entry->ForwardLink = (EFI_LIST_ENTRY *) 0xAFAFAFAF; Entry->BackLink = (EFI_LIST_ENTRY *) 0xAFAFAFAF; #endif } // //--------------------------------------------------------------------------- // // Procedure: InitializeSmmPiSystemTable // // Description: // Initialize SMM PI System Table. // // Input: VOID // // Output: VOID //--------------------------------------------------------------------------- // VOID InitializeSmmPiSystemTable() { UINT32 CRC32; UINT32 NumCpus = gDispatcherPrivate->NumCpus; UINT32 i; gSmmSystemTable2.NumberOfCpus = NumCpus; gSmmSystemTable2.CpuSaveStateSize = Allocate(0,sizeof(UINTN) * NumCpus,0); for (i = 0; i < NumCpus; ++i) gSmmSystemTable2.CpuSaveStateSize[i] = MAX_SMM_SAVE_STATE_SIZE; gSmmSystemTable2.CpuSaveState = Allocate(0,sizeof(VOID*) * NumCpus,0); for (i = 0; i < NumCpus; ++i) { gSmmSystemTable2.CpuSaveState[i] = (VOID*)(gSmmBase[i] + 0x10000 - MAX_SMM_SAVE_STATE_SIZE); } CalculateCrc32(&gSmmSystemTable2, sizeof(EFI_SMM_SYSTEM_TABLE2), &CRC32); gSmmSystemTable2.Hdr.CRC32 = CRC32; gEfiSmmEntryContext.SmmStartupThisAp = gSmmSystemTable2.SmmStartupThisAp; gEfiSmmEntryContext.NumberOfCpus = gSmmSystemTable2.NumberOfCpus; gEfiSmmEntryContext.CpuSaveStateSize = gSmmSystemTable2.CpuSaveStateSize; gEfiSmmEntryContext.CpuSaveState = gSmmSystemTable2.CpuSaveState; } #endif //************************************************************************* //************************************************************************* //** ** //** (C)Copyright 1985-2011, American Megatrends, Inc. ** //** ** //** All Rights Reserved. ** //** ** //** 5555 Oakbrook Parkway, Suite 200, Norcross, GA 30093 ** //** ** //** Phone: (770)-246-8600 ** //** ** //************************************************************************* //*************************************************************************