diff options
author | raywu <raywu0301@gmail.com> | 2018-06-15 00:00:50 +0800 |
---|---|---|
committer | raywu <raywu0301@gmail.com> | 2018-06-15 00:00:50 +0800 |
commit | b7c51c9cf4864df6aabb99a1ae843becd577237c (patch) | |
tree | eebe9b0d0ca03062955223097e57da84dd618b9a /Core/EM/SMM | |
download | zprj-master.tar.xz |
Diffstat (limited to 'Core/EM/SMM')
31 files changed, 12906 insertions, 0 deletions
diff --git a/Core/EM/SMM/SMM.cif b/Core/EM/SMM/SMM.cif new file mode 100644 index 0000000..2a6a922 --- /dev/null +++ b/Core/EM/SMM/SMM.cif @@ -0,0 +1,19 @@ +<component> + name = "SMM" + category = eModule + LocalRoot = "Core\EM\SMM" + RefName = "SMM" +[files] +"SMM.sdl" +"SmmPrivateShared.h" +"SmmHdr.equ" +"Smm.chm" +[parts] +"SmmDispatcher" +"SmmBase" +"SmmCommunicate" +"SmmProtocols" +"SmmPiIncludes" +"SmmPiProtocols" +"PowerButton" +<endComponent> diff --git a/Core/EM/SMM/SMM.sdl b/Core/EM/SMM/SMM.sdl new file mode 100644 index 0000000..2923eaa --- /dev/null +++ b/Core/EM/SMM/SMM.sdl @@ -0,0 +1,101 @@ +TOKEN + Name = "SMM_SUPPORT" + Value = "1" + Help = "Main switch to enable SMM support in Project" + TokenType = Boolean + TargetEQU = Yes + TargetMAK = Yes + TargetH = Yes + Master = Yes +End + +TOKEN + Name = "SMM_MAJOR_VER" + Value = "00" + Help = "SMM Major Version Number. Do not change" + TokenType = Integer + TargetEQU = Yes + TargetMAK = Yes + TargetH = Yes + Lock = Yes +End + +TOKEN + Name = "SMM_MINOR_VER" + Value = "0x46" + Help = "SMM Minor Version Number. Do not change" + TokenType = Integer + TargetEQU = Yes + TargetMAK = Yes + TargetH = Yes + Lock = Yes +End + +TOKEN + Name = "SMM_PAGING_MAX_ADDRESS_LINES" + Value = "32" + Help = "For x64, maximum number of address lines to page.\Each additional line doubles the page table size." + TokenType = Integer + TargetH = Yes +End + +TOKEN + Name = "SMM_CACHE_SUPPORT" + Value = "1" + Help = "Enable/disable SMM Cache Support" + TokenType = Boolean + TargetEQU = Yes + TargetH = Yes +End + +TOKEN + Name = "SMM_THUNK_NO_AB_SEG" + Value = "1" + Help = "Enable/disable using A & B segment for SMM Thunk.\Some CPUs don't provide support for SMM THUNK in A&B segment." + TokenType = Boolean + TargetEQU = Yes + TargetH = Yes +End + +TOKEN + Name = "SMM_THUNK_IN_CSM" + Value = "0" + Help = "Enable/disable SMM Thunk in CSM" + TokenType = Boolean + TargetEQU = Yes + TargetH = Yes + Token = "CSM_SUPPORT" "=" "1" +End + +TOKEN + Name = "SMM_TIME_OUT_US" + Value = "1000" + Help = "uS Timeout waiting for BSP and APs to sync." + TokenType = Integer + TargetH = Yes +End + +TOKEN + Name = "BSP_SMM_STACK_SIZE" + Value = "16384" + Help = "Must be 4k byte alligned." + TokenType = Integer + TargetH = Yes +End + +TOKEN + Name = "AP_SMM_STACK_SIZE" + Value = "16384" + Help = "Must be 4k byte alligned." + TokenType = Integer + TargetH = Yes +End + +TOKEN + Name = "INTEL_MP_SW_SMI_PATCH" + Value = "0" + Help = "INTEL drivers always read Save State Copy 0.\When this is enabled, an AP generated sw smi will\appear as CPU 0.\Further, Save State Copies of other CPUs may be invalid." + TokenType = Boolean + TargetH = Yes +End + diff --git a/Core/EM/SMM/Smm.chm b/Core/EM/SMM/Smm.chm Binary files differnew file mode 100644 index 0000000..dd76d80 --- /dev/null +++ b/Core/EM/SMM/Smm.chm diff --git a/Core/EM/SMM/SmmBase.c b/Core/EM/SMM/SmmBase.c new file mode 100644 index 0000000..219e405 --- /dev/null +++ b/Core/EM/SMM/SmmBase.c @@ -0,0 +1,911 @@ +//************************************************************************* +//************************************************************************* +//** ** +//** (C)Copyright 1985-2011, American Megatrends, Inc. ** +//** ** +//** All Rights Reserved. ** +//** ** +//** 5555 Oakbrook Parkway, Suite 200, Norcross, GA 30093 ** +//** ** +//** Phone: (770)-246-8600 ** +//** ** +//************************************************************************* +//************************************************************************* + +//********************************************************************** +// $Header: /Alaska/SOURCE/Modules/SMM/SMMBase/SmmBase.c 73 2/13/12 4:41p Markw $ +// +// $Revision: 73 $ +// +// $Date: 2/13/12 4:41p $ +//********************************************************************** +// Revision History +// ---------------- +// $Log: /Alaska/SOURCE/Modules/SMM/SMMBase/SmmBase.c $ +// +// 73 2/13/12 4:41p Markw +// [TAG] EIP83005 +// [Category] Improvement +// [Description] Some framework based SMM libraries expect a DXE image +// handle on input. However, PI 1.1 SMM drivers expect a SMM handle on +// input. +// Update code to provide proper EFI_HANDLE when calling SMM functions. +// [Files] SmmBase.c, SmmDriverDispatcher.c +// +// 72 8/25/11 10:29a Markw +// [TAG] EIP64115 +// [Category] Bug Fix +// [Severity] Normal +// [Symptom] PI 1.1 - unable to install protocol on image handle. +// [RootCause] Image handle is created by AMI code, but protocol handles +// are created by Intel code. +// [Solution] Create a new dummy handle from Intel's code and use that a +// the image handle in the entry point. +// [Files] SmmBase.c +// +// 71 2/07/11 3:35p 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 +// +// 70 12/28/09 11:07a Markw +// EIP #32378 - Use SDL token to determine how much memory to page to be +// able to page above 4GB. +// +// 69 11/23/09 11:04a Markw +// Add back SMM Communicate function. Smm runtime module needed this. +// +// 68 11/05/09 4:31p Markw +// SMM Base functions pre-initalize Status to EFI_DEVICE_ERROR in case sw +// smi doesn't happen. +// +// 67 10/13/09 3:42p Markw +// EIP #27823 - Fix allocating SMM driver below 1MB if out of SMM memory. +// +// 66 8/11/09 11:47a Markw +// Removed Legacy registration. This is removed from latest PI and not +// used by projects. +// +// 65 8/05/09 2:59p Markw +// When functions aren't available in BDS for SMM security, return proper +// error of EFI_UNSUPPORTED. +// +// 64 7/17/09 4:19p Markw +// Added back changes 60 and 61. +// +// 63 7/16/09 8:12p Markw +// EIP #24284 - Correct order SmmCpuInfo structure. It's was ordered +// incorrectly the same as CpuInfo. Thus, the wrong APIC ID could be used +// when starting unstarted APs if the BSP was changed. +// +// 62 7/08/09 8:03p Markw +// Update headers. +// +// 61 6/25/09 4:15p Markw +// Move setting gDispatcherPrivate->SmrrEnable outside condition. +// +// 60 6/10/09 3:17p Markw +// Remove extra freepool. +// +// 59 1/26/09 5:29p Markw +// EIP 14800: Aptio 4.x SMI Code vulnerablity. Disable call back inside +// SMM before BDS can launch option roms. +// +// 58 1/22/09 1:07p Markw +// EIP #18671 (OPEN) Clear SW SMI status and set EOS inside SMM. Move +// Clear from Base function. +// +// 57 12/24/08 10:55a Markw +// EIP #18423: Adjust EBDA location as more EBDA data is allocated. +// +// 56 12/23/08 2:19p Markw +// EIP #17900 Set up TSS. Borland C in DOS hangs otherwise. +// +// 55 11/21/08 5:02p Markw +// Use 32-bit CPU Count. +// +// 54 10/06/08 6:27p Markw +// Add generic Smm Memory libary hook. +// +// 53 9/26/08 4:51p Markw +// InSmm is now a runtime function. +// +// 52 9/15/08 4:00p Markw +// Initialize HandlerListHead and FloatingPointSave in Dispatcher Private +// structure. +// +// 51 9/09/08 3:06p Markw +// Align Dispatcher to 4k. +// +// 50 9/07/08 12:47a Markw +// Separate SMM Private structure into inside SMM and outside SMM +// structure. +// +// 49 8/27/08 9:07p Markw +// Nehalem SMRR is not WB. Fix VIA not supporting cpuid 0x80000008. +// +// 47 6/10/08 6:46p Markw +// Disable SMM Thunk if no A & B seg, and no CSM. +// +// 46 6/10/08 1:30p Markw +// Update gdt for Smm Thunk for APs. +// +// 45 6/09/08 5:42p Markw +// Provide support for any CPU to be BSP by providing APIC for each CPU +// and allowing CPU 0 to have a structure for controlling as an Ap. +// +// 44 5/23/08 5:28p Markw +// Undo change from previous revision to lock smm before os with AMI +// debugger. +// +// 43 5/23/08 12:25p Markw +// Disallow registering now disallows all callbacks. +// +// 42 4/04/08 6:23p Markw +// Change SMM base here instead of CPU module. +// +// 41 3/18/08 4:59p Markw +// Change 64-bit pages to have the first 2MB as 4k pages. This is so +// different MTRR types will not overlap a page. +// +// 40 3/11/08 12:46p Markw +// +// 39 3/04/08 9:01a Markw +// Updated EBDA allocation for SMM THUNK to use the changed protocol from +// 4.5.3_CSM.6.43_56. +// +//********************************************************************** + +//<AMI_FHDR_START> +//--------------------------------------------------------------------------- +// +// Name: SmmBase.c +// +// Description: Provide functions to register drivers with SMM, +// determine if driver is in SMM Mode, register call backs, +// provide callback buffer, return SMST table pointer, +// and allocate memory. +// +//--------------------------------------------------------------------------- +//<AMI_FHDR_END> + + +//This include should be first. +#include "SmmPrivateShared.h" + +#include <Protocol\LoadPe32Image.h> +#include <Protocol\LoadedImage.h> +#include <token.h> +#include <Ffs.h> +#include <AmiDxeLib.h> + +#if SMM_USE_FRAMEWORK +#include <Smm.h> +#include <Protocol\SmmBase.h> +#endif + +#if SMM_USE_PI +#include <SmmPi.h> +#include <Protocol\SmmReadyToLock.h> +#endif + +UINT8 gDisallowCallbacks = FALSE; +BOOLEAN gRegisterForPi = FALSE; + +VOID SmmRegisterHandler(); + +#if SMM_USE_FRAMEWORK +VOID SmmUnregisterHandler(); +VOID SmmCommunicate(); +VOID SmmAllocatePool(); +VOID SmmFreePool(); + +extern EFI_SMM_SYSTEM_TABLE *gSmstTable; +#endif + +#if SMM_USE_PI +extern EFI_SMM_SYSTEM_TABLE2 *gSmstTable2; +#endif + +extern EFI_HANDLE gThisImageHandle; +extern SMM_BASE_PRIVATE_STRUCT *gBasePrivate; +extern EFI_PE32_IMAGE_PROTOCOL *gPe32Image; +extern SMM_DISPATCHER_PRIVATE_STRUCT *gDispatcherPrivate; + +EFI_GUID gEfiLoadedImageProtocolGuid = EFI_LOADED_IMAGE_PROTOCOL_GUID; + + +#if SMM_USE_PI +//EFI_GUID gEfiSmmReadyToLockProtocolGuid = EFI_SMM_READY_TO_LOCK_PROTOCOL_GUID; +EFI_GUID gSmmImageHandleDummyGuid = {0x33aa4ba3, 0x5439, 0x4658, 0x89, 0x51, 0xe2, 0xe7, 0xea, 0xf8, 0x1c, 0x49}; +#endif + +VOID CallFuncInSmm(IN VOID func()); + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// +// Procedure: SetDisallowRegistering +// +// Description: Don't allow registering handlers from SMM. +// +// Input: VOID +// +// Output: +// None +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> + +VOID SetDisallowRegistering() +{ +#if SMM_USE_PI + EFI_HANDLE Handle = NULL; +#endif + + //Dispatcher has a private variable, is set after this. + //Thus, once DisallowCallbacks is set, it can not be unset. + gBasePrivate->DisallowCallbacks = TRUE; + gDisallowCallbacks = TRUE; + +#if SMM_USE_PI + gSmstTable2->SmmInstallProtocolInterface( + &Handle, + &gEfiSmmReadyToLockProtocolGuid, + EFI_NATIVE_INTERFACE, + NULL + ); +#endif +} + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// +// Procedure: EfiSmmRegister +// +// Description: Register a driver with the SMM Handler. +// * Loads SMM PE32 Driver into SMM memory and give control to the entry point. +// * Or, loads SMM 16-bit driver into SMM memory. It is given control during SMM mode. +// +// Input: +// IN EFI_SMM_BASE_PROTOCOL *This +// IN EFI_DEVICE_PATH_PROTOCOL *FilePath +// IN VOID *SourceBuffer OPTIONAL +// IN UINTN SourceSize +// OUT EFI_HANDLE *ImageHandle +// IN BOOLEAN LegacyIA32Binary OPTIONAL +// +// Output: +// EFI_STATUS +// * EFI_SUCCESS - Driver was registered. +// * EFI_OUT_OF_RESOURCES - No additional resources to load handler. +// * EFI_INVALID_PARAMETER - Invalid inputs. +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> + +EFI_STATUS EfiSmmRegister( + IN EFI_SMM_BASE_PROTOCOL *This, + IN EFI_DEVICE_PATH_PROTOCOL *FilePath, + IN VOID *SourceBuffer OPTIONAL, + IN UINTN SourceSize, + OUT EFI_HANDLE *ImageHandle, + IN BOOLEAN LegacyIA32Binary OPTIONAL + ) +{ + + if (gDisallowCallbacks) return EFI_UNSUPPORTED; + if (LegacyIA32Binary) return EFI_UNSUPPORTED; + + gBasePrivate->CallbackParameters.RegisterHandler.FilePath = FilePath; + gBasePrivate->CallbackParameters.RegisterHandler.SourceBuffer = SourceBuffer; + gBasePrivate->CallbackParameters.RegisterHandler.SourceSize = SourceSize; + gBasePrivate->CallbackParameters.RegisterHandler.ImageHandle = ImageHandle; + gBasePrivate->CallbackParameters.RegisterHandler.LegacyIA32Binary = FALSE; + gBasePrivate->CallbackStatus = EFI_DEVICE_ERROR; //Pre-init - SW SMI didn't happen. + + CallFuncInSmm(SmmRegisterHandler); + + return gBasePrivate->CallbackStatus; +} + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// +// Procedure: SmmRegisterHandler +// +// Description: Does the actual work for EfiSmmRegisterHandler. +// +// Input: VOID +// +// Output: +// None +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> + +//Can Legacy and PE32 handle overlap? +VOID SmmRegisterHandler() +{ + EFI_PHYSICAL_ADDRESS EntryPoint, DstBuffer; + UINTN NumberOfPages,RealNumberOfPages; + EFI_STATUS Status; + EFI_HANDLE NewImageHandle; + EFI_HANDLE SmmImageHandle; + + //Pre-allocate plenty of pages for the SMM driver, so LoadPeImage will only decompress the driver once. + //If memory is not enough, the number of pages will returned and enough memory allocated, + // then LoadPeImage will decompress the driver again. + //Any extra pages will be freed and not wasted. +#define DEFAULT_SMM_DRIVER_PAGES 16 + NumberOfPages = DEFAULT_SMM_DRIVER_PAGES; +#if SMM_USE_FRAMEWORK + Status = gSmstTable->SmmAllocatePages( +#else + Status = gSmstTable2->SmmAllocatePages( +#endif + AllocateAnyPages, 0, NumberOfPages, &DstBuffer + ); + if (EFI_ERROR(Status)) { + //If allocation failed, so try the minimum of 1 page. + NumberOfPages = 1; +#if SMM_USE_FRAMEWORK + Status = gSmstTable->SmmAllocatePages( +#else + Status = gSmstTable2->SmmAllocatePages( +#endif + AllocateAnyPages, 0, NumberOfPages, &DstBuffer + ); + ASSERT_EFI_ERROR(Status); + if (EFI_ERROR(Status)) { + gBasePrivate->CallbackStatus = Status; + return; + } + } + + //DstBuffer can't be 0, or LoadPeImage will allocate non-SMM memory. + RealNumberOfPages = NumberOfPages; + Status=gPe32Image->LoadPeImage( + gPe32Image, gThisImageHandle, + gBasePrivate->CallbackParameters.RegisterHandler.FilePath, //Either DevicePath or + gBasePrivate->CallbackParameters.RegisterHandler.SourceBuffer, //Buffer. This will be zero if DevicePath. + gBasePrivate->CallbackParameters.RegisterHandler.SourceSize, + DstBuffer, &RealNumberOfPages, + &NewImageHandle, + &EntryPoint, EFI_LOAD_PE_IMAGE_ATTRIBUTE_NONE + ); + //If Image has been loaded, let's free extra memory + if (!EFI_ERROR(Status) && RealNumberOfPages<NumberOfPages) { +#if SMM_USE_FRAMEWORK + gSmstTable->SmmFreePages( +#else + gSmstTable2->SmmFreePages( +#endif + DstBuffer+EFI_PAGES_TO_SIZE(RealNumberOfPages), + NumberOfPages-RealNumberOfPages + ); + //If it's not enough memory, let's allocate new chunk and try again. + } else if (Status==EFI_BUFFER_TOO_SMALL) { + //Free Old Buffer +#if SMM_USE_FRAMEWORK + gSmstTable->SmmFreePages( +#else + gSmstTable2->SmmFreePages( +#endif + DstBuffer, NumberOfPages); + //Allocate New Buffer +#if SMM_USE_FRAMEWORK + Status = gSmstTable->SmmAllocatePages( +#else + Status = gSmstTable2->SmmAllocatePages( +#endif + AllocateAnyPages, 0, RealNumberOfPages, &DstBuffer + ); + if (!EFI_ERROR(Status)) + Status=gPe32Image->LoadPeImage( + gPe32Image, gThisImageHandle, + gBasePrivate->CallbackParameters.RegisterHandler.FilePath, //Either DevicePath or + gBasePrivate->CallbackParameters.RegisterHandler.SourceBuffer, //Buffer. This will be zero if DevicePath. + gBasePrivate->CallbackParameters.RegisterHandler.SourceSize, + DstBuffer, &RealNumberOfPages, + &NewImageHandle, + &EntryPoint, EFI_LOAD_PE_IMAGE_ATTRIBUTE_NONE + ); + } + if (!EFI_ERROR(Status)) { + EFI_LOADED_IMAGE_PROTOCOL *LoadedImage; + //EFI_IMAGE_ENTRY_POINT EntryPoint; + + Status = pBS->HandleProtocol(NewImageHandle, &gEfiLoadedImageProtocolGuid, &LoadedImage); + ASSERT_EFI_ERROR(Status); + + TRACE((TRACE_ALWAYS,"SMM.")); +#ifdef EFI_DEBUG +{ +//Debug message: name/entry point of the module being started +BOOLEAN GetImageName(EFI_HANDLE, CHAR8 *); +VOID Trace(UINTN Level, CHAR8 *sFormat,...); +CHAR8 sName[0x100]; + + GetImageName(NewImageHandle, sName); + TRACE((TRACE_ALWAYS, "%s.Entry(%X)\n", sName, EntryPoint)); +} +#endif + + SmmImageHandle = NewImageHandle; +#if SMM_USE_PI + if (gRegisterForPi) { + //Create an Image Handle for SMM driver, so the handle can be used to install new handles on. + SmmImageHandle = NULL; + Status = gSmstTable2->SmmInstallProtocolInterface( + &SmmImageHandle, + &gSmmImageHandleDummyGuid, + EFI_NATIVE_INTERFACE, + NULL //Dummy + ); + ASSERT_EFI_ERROR(Status); + } +#endif + + gBasePrivate->CallbackParameters.RegisterHandler.ImageHandle = SmmImageHandle; + + Status = ((EFI_IMAGE_ENTRY_POINT)EntryPoint)(SmmImageHandle, pST); + if (EFI_ERROR(Status)) +#if SMM_USE_FRAMEWORK + gSmstTable->SmmFreePages( +#else + gSmstTable2->SmmFreePages( +#endif + DstBuffer, RealNumberOfPages + ); + } + gBasePrivate->CallbackStatus = Status; +} + +#if SMM_USE_FRAMEWORK + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// +// Procedure: EfiSmmUnregister +// +// Description: Removes handler from being called in SMM. +// +// Input: +// IN EFI_SMM_BASE_PROTOCOL *This +// IN EFI_HANDLE ImageHandle +// +// Output: +// EFI_STATUS +// * EFI_SUCCESS - Driver was unregistered. +// * EFI_INVALID_PARAMETER - Image Handle doesn't exist. +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> + +EFI_STATUS EfiSmmUnregister( + IN EFI_SMM_BASE_PROTOCOL *This, + IN EFI_HANDLE ImageHandle + ) +{ + if (gDisallowCallbacks) return EFI_UNSUPPORTED; + + gBasePrivate->CallbackParameters.UnregisterHandler.ImageHandle = ImageHandle; + gBasePrivate->CallbackStatus = EFI_DEVICE_ERROR; //Pre-init - SW SMI didn't happen. + + CallFuncInSmm(SmmUnregisterHandler); + + return gBasePrivate->CallbackStatus; +} + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// +// Procedure: SmmUnregisterHandler +// +// Description: Does the actual work for EfiSmmUnregisterHandler. +// +// Input: VOID +// +// Output: +// VOID +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> + +VOID SmmUnregisterHandler() +{ + gBasePrivate->CallbackStatus = EFI_UNSUPPORTED; +} + + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// +// Procedure: EfiSmmCommunicate +// +// Description: Buffer location for EFI Call Back function. +// +// Input: +// IN EFI_SMM_BASE_PROTOCOL *This +// IN EFI_HANDLE ImageHandle +// IN OUT VOID *CommunicationBuffer +// IN OUT UINTN *SourceSize +// +// Output: +// EFI_STATUS +// * EFI_SUCCESS - Buffer is set. +// * EFI_INVALID_PARAMETER - Buffer is NULL +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> + +EFI_STATUS EfiSmmCommunicate( + IN EFI_SMM_BASE_PROTOCOL *This, + IN EFI_HANDLE ImageHandle, + IN OUT VOID *CommunicationBuffer, + IN OUT UINTN *SourceSize + ) +{ + if (gDisallowCallbacks) return EFI_UNSUPPORTED; + + if (!CommunicationBuffer) return EFI_INVALID_PARAMETER; + + gBasePrivate->CallbackParameters.Communicate.ImageHandle = ImageHandle; + gBasePrivate->CallbackParameters.Communicate.CommunicationBuffer = CommunicationBuffer; + gBasePrivate->CallbackParameters.Communicate.SourceSize = SourceSize; + gBasePrivate->CallbackStatus = EFI_DEVICE_ERROR; //Pre-init - SW SMI didn't happen. + + CallFuncInSmm(SmmCommunicate); + + return gBasePrivate->CallbackStatus; +} + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// +// Procedure: SmmCommunicate +// +// Description: Does the actual work for EfiSmmCommunicate. +// +// Input: VOID +// +// Output: +// VOID +// +// Notes: +// A runtime driver will have to call this function again for a virtual address. +// Currently, virtual address are not automatically fixed up. +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> + +VOID SmmCommunicate() +{ +// A runtime driver will have to call this function again for a virtual address. +// Currently, virtual address are not automaically fixed up. Also, no runtime drivers are +// using this. + + HANDLER_LIST *Link; + for (Link = gDispatcherPrivate->HandlerListHead;Link; Link = Link->Link) { + if (Link->SmmImageHandle == gBasePrivate->CallbackParameters.Communicate.ImageHandle) { + Link->CommunicationBuffer = gBasePrivate->CallbackParameters.Communicate.CommunicationBuffer; + Link->SourceSize = gBasePrivate->CallbackParameters.Communicate.SourceSize; + gBasePrivate->CallbackStatus = EFI_SUCCESS; + return; + } + } + gBasePrivate->CallbackStatus = EFI_NOT_FOUND; +} + + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// +// Procedure: EfiSmmCallBackService +// +// Description: Function for the SMM to call back. +// +// Input: +// IN EFI_SMM_BASE_PROTOCOL *This +// IN EFI_HANDLE SmmImageHandle +// IN EFI_SMM_CALLBACK_ENTRY_POINT CallbackAddress +// IN BOOLEAN MakeLast OPTIONAL +// IN BOOLEAN FloatingPointSave OPTIONAL +// +// Output: +// EFI_STATUS +// * EFI_SUCCESS - Call back function set for Handle. +// * EFI_OUT_OF_RESOURCES - Not enough memory to add callback. +// * EFI_UNSUPPORTED - Caller not in SMM. +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> + +EFI_STATUS EfiSmmCallBackService( + IN EFI_SMM_BASE_PROTOCOL *This, + IN EFI_HANDLE SmmImageHandle, + IN EFI_SMM_CALLBACK_ENTRY_POINT CallbackAddress, + IN BOOLEAN MakeLast OPTIONAL, + IN BOOLEAN FloatingPointSave OPTIONAL + ) +{ + HANDLER_LIST *Handler,*Link; + + if (!*gBasePrivate->InSmm) return EFI_UNSUPPORTED; + + if (gSmstTable->SmmAllocatePool(0,sizeof(HANDLER_LIST),&Handler) != EFI_SUCCESS) + return EFI_OUT_OF_RESOURCES; + + Handler->EntryPoint = CallbackAddress; + Handler->SmmImageHandle = SmmImageHandle; + Handler->CommunicationBuffer = 0; + Handler->SourceSize = 0; + Handler->IsRoot = TRUE; + Handler->IsPi = FALSE; + Handler->Link = 0; + + if (FloatingPointSave) gDispatcherPrivate->FloatingPointSave = TRUE; + + //If very first add. + if (!gDispatcherPrivate->HandlerListHead) { + gDispatcherPrivate->HandlerListHead = Handler; + return EFI_SUCCESS; + } + + //If not MakeLast, add to beginning of list. + if (!MakeLast) { + Handler->Link = gDispatcherPrivate->HandlerListHead; + gDispatcherPrivate->HandlerListHead = Handler; + return EFI_SUCCESS; + } + + //Add to end of list. + for (Link = gDispatcherPrivate->HandlerListHead; Link->Link; Link = Link->Link); //Find end of list + Link->Link = Handler; + return EFI_SUCCESS; +} + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// +// Procedure: EfiSmmAllocatePool +// +// Description: Allocate buffer from SMM Memory. +// +// Input: +// IN EFI_SMM_BASE_PROTOCOL *This +// IN EFI_MEMORY_TYPE PoolType +// IN UINTN Size +// OUT VOID **Buffer +// +// Output: +// EFI_STATUS +// * EFI_SUCCESS - Allocation successful. +// * EFI_OUT_OF_RESOURCES - Not enough space. +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> + +EFI_STATUS EfiSmmAllocatePool( + IN EFI_SMM_BASE_PROTOCOL *This, + IN EFI_MEMORY_TYPE PoolType, + IN UINTN Size, + OUT VOID **Buffer + ) +{ + if (gDisallowCallbacks) return EFI_UNSUPPORTED; + + gBasePrivate->CallbackParameters.AllocatePool.Size = Size; + gBasePrivate->CallbackParameters.AllocatePool.Buffer = Buffer; + gBasePrivate->CallbackStatus = EFI_DEVICE_ERROR; //Pre-init - SW SMI didn't happen. + + CallFuncInSmm(SmmAllocatePool); + + return gBasePrivate->CallbackStatus; +} + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// +// Procedure: SmmAllocatePool +// +// Description: Does the actual work for EfiSmmAllocatePool. +// +// Input: VOID +// +// Output: +// None +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> + +VOID SmmAllocatePool() +{ + gBasePrivate->CallbackStatus = gSmstTable->SmmAllocatePool( + 0, + gBasePrivate->CallbackParameters.AllocatePool.Size, + gBasePrivate->CallbackParameters.AllocatePool.Buffer + ); +} + + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// +// Procedure: EfiSmmFreePool +// +// Description: Free pool of memory. +// +// Input: +// IN EFI_SMM_BASE_PROTOCOL *This +// IN VOID *Buffer +// +// Output: +// EFI_STATUS +// * EFI_SUCCESS - Buffer freed +// * EFI_INVALID_PARAMETER - Buffer invalid. +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> + +EFI_STATUS EfiSmmFreePool( + IN EFI_SMM_BASE_PROTOCOL *This, + IN VOID *Buffer + ) +{ + if (gDisallowCallbacks) return EFI_UNSUPPORTED; + + gBasePrivate->CallbackParameters.FreePool.Buffer = Buffer; + gBasePrivate->CallbackStatus = EFI_DEVICE_ERROR; //Pre-init - SW SMI didn't happen. + + CallFuncInSmm(SmmFreePool); + + return gBasePrivate->CallbackStatus; +} + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// +// Procedure: SmmFreePool +// +// Description: Does the actual work for EfiSmmFreePool. +// +// Input: VOID +// +// Output: +// None +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> + +VOID SmmFreePool() +{ + gBasePrivate->CallbackStatus = gSmstTable->SmmFreePool( + gBasePrivate->CallbackParameters.FreePool.Buffer); +} + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// +// Procedure: EfiSmmGetSmstLocation +// +// Description: Returns a pointer to the Smst. +// +// Input: +// IN EFI_SMM_BASE_PROTOCOL *This +// IN OUT EFI_SMM_SYSTEM_TABLE **Smst +// +// Output: +// EFI_STATUS +// * EFI_SUCCESS - SMST address saved in *Smst. +// * EFI_INVALID_PARAMETER - Smst = NULL. +// * EFI_UNSUPPORTED - Not in SMM. +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> + +EFI_STATUS EfiSmmGetSmstLocation( + IN EFI_SMM_BASE_PROTOCOL *This, + IN OUT EFI_SMM_SYSTEM_TABLE **Smst + ) +{ + if (!*gBasePrivate->InSmm) return EFI_UNSUPPORTED; + if (Smst == NULL) return EFI_INVALID_PARAMETER; + + *Smst = gSmstTable; + return EFI_SUCCESS; +} + +EFI_SMM_BASE_PROTOCOL gEfiSmmBase = { + EfiSmmRegister, + EfiSmmUnregister, + EfiSmmCommunicate, + EfiSmmCallBackService, + NULL, //EfiSmmInSmm is runtime function. This will be updated. + EfiSmmAllocatePool, + EfiSmmFreePool, + EfiSmmGetSmstLocation, +}; + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// +// Procedure: EfiSmmRegisterUnsupported +// +// Description: +// The SMM Base Protocol function Register return unsupported after +// BIOS is done executing. +// +// Input: +// IN EFI_SMM_BASE_PROTOCOL *This +// IN EFI_DEVICE_PATH_PROTOCOL *FilePath +// IN VOID *SourceBuffer OPTIONAL, +// IN UINTN SourceSize +// OUT EFI_HANDLE *ImageHandle +// IN BOOLEAN LegacyIA32Binary OPTIONAL +// +// Output: +// EFI_STATUS +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> + +EFI_STATUS EfiSmmRegisterUnsupported( + IN EFI_SMM_BASE_PROTOCOL *This, + IN EFI_DEVICE_PATH_PROTOCOL *FilePath, + IN VOID *SourceBuffer OPTIONAL, + IN UINTN SourceSize, + OUT EFI_HANDLE *ImageHandle, + IN BOOLEAN LegacyIA32Binary OPTIONAL + ) +{ + return EFI_UNSUPPORTED; +} + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// +// Procedure: EfiSmmUnregisterUnsupported +// +// Description: +// The SMM Base Protocol function UnRegister return unsupported after +// BIOS is done executing. +// +// Input: +// IN EFI_SMM_BASE_PROTOCOL *This +// IN EFI_HANDLE ImageHandle +// +// Output: +// EFI_STATUS +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> + +EFI_STATUS EfiSmmUnregisterUnsupported( + IN EFI_SMM_BASE_PROTOCOL *This, + IN EFI_HANDLE ImageHandle + ) +{ + return EFI_UNSUPPORTED; +} +#endif + +//************************************************************************* +//************************************************************************* +//** ** +//** (C)Copyright 1985-2010, American Megatrends, Inc. ** +//** ** +//** All Rights Reserved. ** +//** ** +//** 5555 Oakbrook Parkway, Suite 200, Norcross, GA 30093 ** +//** ** +//** Phone: (770)-246-8600 ** +//** ** +//************************************************************************* +//************************************************************************* diff --git a/Core/EM/SMM/SmmBase.cif b/Core/EM/SMM/SmmBase.cif new file mode 100644 index 0000000..79d6ba1 --- /dev/null +++ b/Core/EM/SMM/SmmBase.cif @@ -0,0 +1,15 @@ +<component> + name = "SmmBase" + category = ModulePart + LocalRoot = "Core\EM\SMM" + RefName = "SmmBase" +[files] +"SmmBase.sdl" +"SmmBase.mak" +"SmmInit.c" +"SmmBase.c" +"SmmBase2.c" +"SmmDriverDispatcher.c" +"SmmBase.dxs" +"SmmBaseAsm.asm" +<endComponent> diff --git a/Core/EM/SMM/SmmBase.dxs b/Core/EM/SMM/SmmBase.dxs new file mode 100644 index 0000000..b6bc561 --- /dev/null +++ b/Core/EM/SMM/SmmBase.dxs @@ -0,0 +1,107 @@ +//************************************************************************* +//************************************************************************* +//** ** +//** (C)Copyright 1985-2011, American Megatrends, Inc. ** +//** ** +//** All Rights Reserved. ** +//** ** +//** 5555 Oakbrook Parkway, Suite 200, Norcross, GA 30093 ** +//** ** +//** Phone: (770)-246-8600 ** +//** ** +//************************************************************************* +//************************************************************************* + +//********************************************************************** +// $Header: /Alaska/SOURCE/Modules/SMM/SMMBase/SmmBase.dxs 8 4/01/11 10:36a Markw $ +// +// $Revision: 8 $ +// +// $Date: 4/01/11 10:36a $ +//********************************************************************** +// Revision History +// ---------------- +// $Log: /Alaska/SOURCE/Modules/SMM/SMMBase/SmmBase.dxs $ +// +// 8 4/01/11 10:36a Markw +// [TAG] EIP57440 +// [Category] New Feature +// [Description] Update for PI 1.1 +// [Files] SmmBase.dxs +// +// 7 7/08/09 8:03p Markw +// Update headers. +// +// 6 8/28/08 2:04p Markw +// +// 5 10/29/07 3:38p Markw +// +// 4 10/29/07 11:21a Markw +// Smm Thunk: +// * Code and data different segments. +// * Code position independent. +// * Switch for CSM for code and EBDA for data. +// +// 3 3/14/06 10:02a Felixp +// +// +//********************************************************************** + +//<AMI_FHDR_START> +//--------------------------------------------------------------------------- +// +// Name: SmmBase.dxs +// +// Description: Dependency file for the SMM base driver +// +//--------------------------------------------------------------------------- +//<AMI_FHDR_END> + +#include <Token.h> +#if PI_SPECIFICATION_VERSION >= 0x0001000a +#include <Protocol\SmmAccess2.h> +#include <Protocol\smmcontrol2.h> +#else +#include <Protocol\SmmAccess.h> +#include <Protocol\smmcontrol.h> +#endif +#include <Protocol\FirmwareVolume.h > +#include <Protocol\Variable.h> + +#if SMM_THUNK_IN_CSM == 1 +#include <Protocol\LegacyBiosExt.h> +#include <Protocol\LegacyBios.h> +#endif + +DEPENDENCY_START +#if PI_SPECIFICATION_VERSION >= 0x0001000a + EFI_SMM_ACCESS2_PROTOCOL_GUID AND + EFI_SMM_CONTROL2_PROTOCOL_GUID AND +#else + EFI_SMM_ACCESS_PROTOCOL_GUID AND + EFI_SMM_CONTROL_PROTOCOL_GUID AND +#endif + EFI_FIRMWARE_VOLUME_PROTOCOL_GUID AND + EFI_VARIABLE_ARCH_PROTOCOL_GUID AND +#if SMM_THUNK_IN_CSM == 0 + EFI_VARIABLE_WRITE_ARCH_PROTOCOL_GUID +#else + EFI_VARIABLE_WRITE_ARCH_PROTOCOL_GUID AND + EFI_LEGACY_BIOS_EXT_PROTOCOL_GUID AND + EFI_LEGACY_BIOS_PROTOCOL_GUID +#endif +DEPENDENCY_END + +//************************************************************************* +//************************************************************************* +//** ** +//** (C)Copyright 1985-2011, American Megatrends, Inc. ** +//** ** +//** All Rights Reserved. ** +//** ** +//** 5555 Oakbrook Parkway, Suite 200, Norcross, GA 30093 ** +//** ** +//** Phone: (770)-246-8600 ** +//** ** +//************************************************************************* +//************************************************************************* diff --git a/Core/EM/SMM/SmmBase.mak b/Core/EM/SMM/SmmBase.mak new file mode 100644 index 0000000..1d57955 --- /dev/null +++ b/Core/EM/SMM/SmmBase.mak @@ -0,0 +1,84 @@ +#************************************************************************* +#************************************************************************* +#** ** +#** (C)Copyright 1985-2008, American Megatrends, Inc. ** +#** ** +#** All Rights Reserved. ** +#** ** +#** 5555 Oakbrook Parkway, Suite 200, Norcross, GA 30093 ** +#** ** +#** Phone: (770)-246-8600 ** +#** ** +#************************************************************************* +#************************************************************************* + +#********************************************************************** +# $Header: /Alaska/SOURCE/Modules/SMM/SMMBase/SmmBase.mak 4 2/07/11 3:35p Markw $ +# +# $Revision: 4 $ +# +# $Date: 2/07/11 3:35p $ +#********************************************************************** +# Revision History +# ---------------- +# $Log: /Alaska/SOURCE/Modules/SMM/SMMBase/SmmBase.mak $ +# +# 4 2/07/11 3:35p 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 +# +# 3 7/08/09 8:26p Markw +# Updated headers. +# +# 2 12/02/05 11:48a Felixp +# +# 1 1/28/05 4:31p Sivagarn +# SMM Base Component - Initial check in +# +# +#********************************************************************** + +#<AMI_FHDR_START> +#--------------------------------------------------------------------------- +# +# Name: SmmBase.MAK +# +# Description: Make file for the SMM base code +# +#--------------------------------------------------------------------------- +#<AMI_FHDR_END> + +all : SmmBase + +SmmBase : $(BUILD_DIR)\SmmBase.mak SmmBaseBin + +$(BUILD_DIR)\SmmBase.mak : $(SMM_BASE_DIR)\SmmBase.cif $(SMM_BASE_DIR)\$(@B).mak $(BUILD_RULES) + $(CIF2MAK) $(SMM_BASE_DIR)\SmmBase.cif $(CIF2MAK_DEFAULTS) + +SmmBaseBin : $(AMIDXELIB) $(AMICSPLib) + $(MAKE) /$(MAKEFLAGS) $(BUILD_DEFAULTS)\ + /f $(BUILD_DIR)\SmmBase.mak all\ + GUID=D0632C90-AFD7-4492-B186-257C63143C61\ + ENTRY_POINT=SmmInitEntry\ + TYPE=BS_DRIVER \ + COMPRESS=1 + +#************************************************************************* +#************************************************************************* +#** ** +#** (C)Copyright 1985-2008, American Megatrends, Inc. ** +#** ** +#** All Rights Reserved. ** +#** ** +#** 5555 Oakbrook Parkway, Suite 200, Norcross, GA 30093 ** +#** ** +#** Phone: (770)-246-8600 ** +#** ** +#************************************************************************* +#************************************************************************* diff --git a/Core/EM/SMM/SmmBase.sdl b/Core/EM/SMM/SmmBase.sdl new file mode 100644 index 0000000..449d117 --- /dev/null +++ b/Core/EM/SMM/SmmBase.sdl @@ -0,0 +1,25 @@ +TOKEN + Name = "SmmBase_SUPPORT" + Value = "1" + Help = "Main switch to enable SmmBase support in Project" + TokenType = Boolean + TargetEQU = Yes + TargetMAK = Yes + Master = Yes +End + +PATH + Name = "SMM_BASE_DIR" +End + +MODULE + Help = "Includes SmmBase.mak to Project" + File = "SmmBase.mak" +End + +ELINK + Name = "$(BUILD_DIR)\SmmBase.ffs" + Parent = "FV_MAIN" + InvokeOrder = AfterParent +End + diff --git a/Core/EM/SMM/SmmBase2.c b/Core/EM/SMM/SmmBase2.c new file mode 100644 index 0000000..679b880 --- /dev/null +++ b/Core/EM/SMM/SmmBase2.c @@ -0,0 +1,102 @@ +//************************************************************************* +//************************************************************************* +//** ** +//** (C)Copyright 1985-20011 American Megatrends, Inc. ** +//** ** +//** All Rights Reserved. ** +//** ** +//** 5555 Oakbrook Parkway, Suite 200, Norcross, GA 30093 ** +//** ** +//** Phone: (770)-246-8600 ** +//** ** +//************************************************************************* +//************************************************************************* + +//********************************************************************** +// $Header: /Alaska/SOURCE/Modules/SMM/SMMBase/SmmBase2.c 1 2/07/11 3:35p Markw $ +// +// $Revision: 1 $ +// +// $Date: 2/07/11 3:35p $ +//********************************************************************** +// Revision History +// ---------------- +// $Log: /Alaska/SOURCE/Modules/SMM/SMMBase/SmmBase2.c $ +// +// 1 2/07/11 3:35p 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 +// +//********************************************************************** + +//<AMI_FHDR_START> +//--------------------------------------------------------------------------- +// +// Name: SmmBase2.c +// +// Description: SmmBase2 Protocol +// +//--------------------------------------------------------------------------- +//<AMI_FHDR_END> + +#include "SmmPrivateShared.h" +#if SMM_USE_PI +#include <SmmPi.h> +#include <Protocol\SmmBase2.h> +#include <AmiDxeLib.h> + +EFI_SMM_SYSTEM_TABLE2 *gSmstTable2; + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// +// Procedure: EfiSmmGetSmstLocation2 +// +// Description: Retruns a pointer to the Smst. +// +// Input: +// IN EFI_SMM_BASE_PROTOCOL *This +// IN OUT EFI_SMM_SYSTEM_TABLE **Smst +// +// Output: +// EFI_STATUS +// * EFI_SUCCESS - SMST address saved in *Smst. +// * EFI_INVALID_PARAMETER - Smst = NULL. +// * EFI_UNSUPPORTED - Not in SMM. +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> +EFI_STATUS EfiSmmGetSmstLocation2( + IN CONST EFI_SMM_BASE2_PROTOCOL *This, + IN OUT EFI_SMM_SYSTEM_TABLE2 **Smst + ) +{ + *Smst = gSmstTable2; + return EFI_SUCCESS; +} + +EFI_SMM_BASE2_PROTOCOL gEfiSmmBase2 = { + NULL, //This will be updated dynamically. + EfiSmmGetSmstLocation2 +}; +#endif + +//************************************************************************* +//************************************************************************* +//** ** +//** (C)Copyright 1985-2011, American Megatrends, Inc. ** +//** ** +//** All Rights Reserved. ** +//** ** +//** 5555 Oakbrook Parkway, Suite 200, Norcross, GA 30093 ** +//** ** +//** Phone: (770)-246-8600 ** +//** ** +//************************************************************************* +//************************************************************************* diff --git a/Core/EM/SMM/SmmBaseAsm.asm b/Core/EM/SMM/SmmBaseAsm.asm new file mode 100644 index 0000000..cdaa37b --- /dev/null +++ b/Core/EM/SMM/SmmBaseAsm.asm @@ -0,0 +1,139 @@ +;************************************************************************* +;************************************************************************* +;** ** +;** (C)Copyright 1985-2008, American Megatrends, Inc. ** +;** ** +;** All Rights Reserved. ** +;** ** +;** 5555 Oakbrook Parkway, Suite 200, Norcross, GA 30093 ** +;** ** +;** Phone: (770)-246-8600 ** +;** ** +;************************************************************************* +;************************************************************************* + +;********************************************************************** +; $Header: /Alaska/SOURCE/Modules/SMM/SMMBase/SmmBaseAsm.asm 2 7/14/09 12:16p Markw $ +; +; $Revision: 2 $ +; +; $Date: 7/14/09 12:16p $ +;********************************************************************** +; Revision History +; ---------------- +; $Log: /Alaska/SOURCE/Modules/SMM/SMMBase/SmmBaseAsm.asm $ +; +; 2 7/14/09 12:16p Markw +; Update headers. +; +; 1 9/26/08 4:48p Markw +; +; 1 6/09/08 5:56p Markw +; Assembly functions for Dispatcher. +; +;********************************************************************** + +;<AMI_FHDR_START> +;---------------------------------------------------------------------------- +; +; Name: SmmDispatcher.asm +; +; Description: File that contains assembly for Smm Dispatcher. +; +;---------------------------------------------------------------------------- +;<AMI_FHDR_END> + +IFDEF EFIx64 +.code +include token.equ + +public EfiSmmInSmm + +public InSmmFuncOffset +public InSmmFuncLength + +InSmmFuncOffset dd InSmmFixup - InSmmStart +InSmmFuncLength dd InSmmEnd - InSmmStart + +;<AMI_PHDR_START> +;---------------------------------------------------------------------------- +; +; Procedure: InSmm +; +; Description: Updates if *InSmm if in SMM. +; +; Input: +; IN EFI_SMM_BASE_PROTOCOL *This, +; OUT BOOLEAN *InSmm +; +; Output: EFI_STATUS +; +; Modified: Nothing +; +;---------------------------------------------------------------------------- +;<AMI_PHDR_END> + +EfiSmmInSmm proc +InSmmStart EQU $ + or rdx, rdx + jnz @f + mov rax, 8000000000000002h + ret +@@: + ;mov al, 0 + db 0b0h +InSmmFixup EQU $ + db 0 + mov [rdx], al + mov rax, 0 + ret +InSmmEnd EQU $ +EfiSmmInSmm endp + +ELSE ;32-bits +.586p +.model small +.code + +public _InSmmFuncOffset +public _InSmmFuncLength + +_InSmmFuncOffset dd InSmmFixup - InSmmStart +_InSmmFuncLength dd InSmmEnd - InSmmStart + +_EfiSmmInSmm proc public +InSmmStart EQU $ + or dword ptr [esp + 8], 0 + jnz @f + mov eax, 80000002h + ret +@@: + ;mov al, 0 + db 0b0h +InSmmFixup EQU $ + db 0 + push ebx + mov ebx, [esp + 12] + mov [ebx], al + pop ebx + xor eax, eax + ret +InSmmEnd EQU $ +_EfiSmmInSmm endp +ENDIF + +end + +;************************************************************************* +;************************************************************************* +;** ** +;** (C)Copyright 1985-2008, American Megatrends, Inc. ** +;** ** +;** All Rights Reserved. ** +;** ** +;** 5555 Oakbrook Parkway, Suite 200, Norcross, GA 30093 ** +;** ** +;** Phone: (770)-246-8600 ** +;** ** +;************************************************************************* +;************************************************************************* diff --git a/Core/EM/SMM/SmmCommunicate.c b/Core/EM/SMM/SmmCommunicate.c new file mode 100644 index 0000000..929118e --- /dev/null +++ b/Core/EM/SMM/SmmCommunicate.c @@ -0,0 +1,462 @@ +//************************************************************************* +//************************************************************************* +//** ** +//** (C)Copyright 1985-2011 American Megatrends, Inc. ** +//** ** +//** All Rights Reserved. ** +//** ** +//** 5555 Oakbrook Parkway, Suite 200, Norcross, GA 30093 ** +//** ** +//** Phone: (770)-246-8600 ** +//** ** +//************************************************************************* +//************************************************************************* + +//********************************************************************** +// $Header: /Alaska/SOURCE/Modules/SMM/SmmCommunicate/SmmCommunicate.c 5 3/22/12 11:38a Markw $ +// +// $Revision: 5 $ +// +// $Date: 3/22/12 11:38a $ +//********************************************************************** +// Revision History +// ---------------- +// $Log: /Alaska/SOURCE/Modules/SMM/SmmCommunicate/SmmCommunicate.c $ +// +// 5 3/22/12 11:38a Markw +// [TAG] EIP84198 +// [Category] Bug Fix +// [Severity] Important +// [Symptom] Using SMM Communication can cause OS to hang +// [RootCause] SMM Communication Protocol’s Communicate API does not +// function in UEFI OS after Exit boot services event because +// ConvertPointer() did not convert SMM_COMMUNICATE_DATA *gCommunicateData +// pointer from a Physical Memory Map Pointer to a Virtual Memory Map +// Pointer. gCommunicateData is allocated in EfiACPIMemoryNVS. +// [Solution] Allocate memory gCommunicateData as Runtime Services Data. +// [Files] SmmCommunicate.c +// +// 4 10/03/11 3:56p Markw +// Use tokens for SW SMI. Comment publishing ACPI table until ready. +// Files: SmmCommunicate.sdl, SmmCommunicate.c +// +// 3 9/14/11 11:30a Markw +// Add comment for pRS->GetVariable in CommunicateCallback, and in SMM +// Communcate generating SW SMI. +// +// 2 9/12/11 9:58a Markw +// [TAG] EIP64115 +// [Category] Bug Fix +// [Severity] Normal +// [Symptom] SmmCommuncate hangs in OS. +// [RootCause] SMM Communciate not available in OS. +// [Solution] Update SMM Communicate to work under OS by making it a +// runtime driver and converting pointers to virtual points on +// EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE. +// +// [Files] SmmCommunicate.c, SmmCommunicate.mak +// +// 1 4/18/11 12:03p Markw +// [TAG] EIP57440 +// [Category] New Feature +// [Description] Add SMM PI 1.1 Communicate Support. +// [Files] SmmCommunicate.cif +// SmmCommunicate.sdl +// SmmCommunicate.c +// SmmCommunicate.dxs +// SmmDxeCommunicate.dxs +// SmmCommunicate.mak +// +// +//********************************************************************** + +//<AMI_FHDR_START> +//--------------------------------------------------------------------------- +// +// Name: SmmCommunicate.c +// +// Description: Provide SMM Communicate Protocol +// +//--------------------------------------------------------------------------- +//<AMI_FHDR_END> + +#include <Efi.h> +#include <Acpi.h> +#include <AmiDxeLib.h> +#include <SmmPi.h> +#include <Protocol\SmmBase2.h> +#include <Protocol\SmmCommunication.h> +#include <Protocol\SmmSwDispatch2.h> +#include <Protocol\AcpiSupport.h> +#include <Protocol\AmiInternalSmmComm.h> +#include <Token.h> + +typedef struct { + VOID *CommBuffer; + UINTN *CommSize; + EFI_STATUS Status; +} SMM_COMMUNICATE_DATA; + +#define SMM_COMMUNICATE_DATA_VARIABLE L"SMM_COMMUNICATE_DATA" + +// {08F10CB6-3131-4919-9D70-5C8A17366EE8} +#define SMM_COMMUNICATE_DATA_GUID \ + {0x8f10cb6, 0x3131, 0x4919, 0x9d, 0x70, 0x5c, 0x8a, 0x17, 0x36, 0x6e, 0xe8} + +EFI_HANDLE gImageHandle; + +EFI_GUID gEfiSmmBase2ProtocolGuid = EFI_SMM_BASE2_PROTOCOL_GUID; +EFI_GUID gEfiSmmCommunicationProtocolGuid = EFI_SMM_COMMUNICATION_PROTOCOL_GUID; +EFI_GUID gAmiIntSmmCommProtocolGuid = AMI_INT_SMM_COMM_PROTOCOL_GUID; +EFI_GUID gSmmCommunicateDataGuid = SMM_COMMUNICATE_DATA_GUID; +EFI_GUID gEfiAcpiSupportGuid = EFI_ACPI_SUPPORT_GUID; + + +EFI_SMM_BASE2_PROTOCOL *gSmmBase2; + + +SMM_COMMUNICATE_DATA *gCommunicateData = NULL; + +/////////////////////SMM////////////////// +EFI_GUID gEfiSmmSwDispatch2ProtocolGuid = EFI_SMM_SW_DISPATCH2_PROTOCOL_GUID; + +EFI_SMM_SW_DISPATCH2_PROTOCOL *gSmmSw2; +EFI_SMM_SYSTEM_TABLE2 *Smst2; + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Procedure: CommunicateCallBack +// +// Description: Sw SMI callback to call communicate functions. +// +// Input: +// IN EFI_HANDLE DispatchHandle - Unused +// IN CONST VOID *Context OPTIONAL - Unused +// IN OUT VOID *CommBuffer OPTIONAL - Unused +// IN OUT UINTN *CommBufferSize OPTIONAL - Unused +// +// Output: EFI_STATUS +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +EFI_STATUS CommunicateCallBack( + IN EFI_HANDLE DispatchHandle, + IN CONST VOID *Context OPTIONAL, + IN OUT VOID *CommBuffer OPTIONAL, + IN OUT UINTN *CommBufferSize OPTIONAL +) +{ + EFI_SMM_COMMUNICATE_HEADER *Header; + EFI_STATUS Status; + + if (gCommunicateData == NULL) { + UINTN VariableSize = sizeof(EFI_SMM_COMMUNICATE_HEADER*); + + //SMM_COMMUNICATE_DATA_VARIABLE variable is not available during + // SMM entry. When this variable is set in DXE before BDS, + // a SW SMI is executed, and gCommunicateData is initialized + // before SMM Communciate protocol is published. + Status = pRS->GetVariable( + SMM_COMMUNICATE_DATA_VARIABLE, + &gSmmCommunicateDataGuid, + NULL, + &VariableSize, + &gCommunicateData + ); + ASSERT_EFI_ERROR(Status); + if (!EFI_ERROR(Status)) gCommunicateData->Status = Status; + return EFI_SUCCESS; + } + + if (gCommunicateData->CommBuffer == NULL) { + gCommunicateData->Status = EFI_INVALID_PARAMETER; + return EFI_SUCCESS; + } + + gCommunicateData->Status = EFI_NOT_FOUND; //Default no handler found. + + Header = (EFI_SMM_COMMUNICATE_HEADER*)(gCommunicateData->CommBuffer); + Status = Smst2->SmiManage(&Header->HeaderGuid, NULL, Header->Data, &Header->MessageLength); + + //Default Status of SmiManage is EFI_INTERRUPT_PENDING. Thus, no handler found. + if (Status != EFI_INTERRUPT_PENDING) gCommunicateData->Status = EFI_SUCCESS; + return EFI_SUCCESS; +} + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Procedure: InitSmm +// +// Description: Initialize SMM part of SMM Communicate. +// +// Input: VOID +// +// Output: EFI_STATUS +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +EFI_STATUS InitSmm() +{ + EFI_STATUS Status; + EFI_SMM_SW_REGISTER_CONTEXT RegisterContext = {SMM_COMM_SW_SMI}; + EFI_HANDLE ImageHandle = NULL; + EFI_HANDLE DispatchHandle; + + Status = gSmmBase2->GetSmstLocation(gSmmBase2, &Smst2); + ASSERT_EFI_ERROR(Status); + + Status = Smst2->SmmLocateProtocol(&gEfiSmmSwDispatch2ProtocolGuid, NULL, &gSmmSw2); + ASSERT_EFI_ERROR(Status); + + Status = gSmmSw2->Register( + gSmmSw2, + CommunicateCallBack, + &RegisterContext, + &DispatchHandle + ); + ASSERT_EFI_ERROR(Status); + if (EFI_ERROR(Status)) return Status; + + +//Signal that Handler is ready + Status = pBS->InstallMultipleProtocolInterfaces( + &ImageHandle, + &gAmiIntSmmCommProtocolGuid, NULL, + NULL + ); + + return Status; +} + + +/////////////////////ACPI////////////////// + +#pragma pack(push, 1) +typedef struct { + ACPI_HDR Hdr; + EFI_GUID Identifier; + UINT16 DataOffset; + UINT32 SwSmi; + UINT64 BufferPtr; +} ACPI_SMM_COMM_TABLE; +#pragma pack(pop) + +ACPI_SMM_COMM_TABLE gAcpiSmmCommTable = +{ + 'UEFI', + sizeof(ACPI_SMM_COMM_TABLE), + 1, //Revision + 0, //Checksum + CONVERT_TO_STRING(T_ACPI_OEM_ID), + CONVERT_TO_STRING(T_ACPI_OEM_TBL_ID), + ACPI_OEM_REV, + 0, //Creator ID + 0, //Creator Revision, + EFI_SMM_COMMUNICATION_PROTOCOL_GUID, + EFI_FIELD_OFFSET(ACPI_SMM_COMM_TABLE, SwSmi), + SMM_COMM_SW_SMI, + 0 +}; + +EFI_ACPI_SUPPORT_PROTOCOL *gAcpiSupport; + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Procedure: InitAcpi +// +// Description: Initialize Acpi SMM Communicate part. +// +// Input: VOID +// +// Output: EFI_STATUS +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +EFI_STATUS InitAcpi() +{ +//TODO: Proper support for ACPI SMM communicate will be in SMM label 45. +#if 0 + EFI_STATUS Status; + UINTN AcpiHandle = 0; + + Status = pBS->LocateProtocol(&gEfiAcpiSupportGuid, NULL, &gAcpiSupport); + ASSERT_EFI_ERROR(Status); + if (EFI_ERROR(Status)) return Status; + + Status = gAcpiSupport->SetAcpiTable( + gAcpiSupport, + &gAcpiSmmCommTable, + TRUE, + EFI_ACPI_TABLE_VERSION_ALL, + &AcpiHandle + ); + ASSERT_EFI_ERROR(Status); + if (EFI_ERROR(Status)) return Status; +#endif + + return EFI_SUCCESS; +} + +/////////////////////DXE////////////////// + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Procedure: SmmCommunicate +// +// Description: SmmCommunicate Protocol function. This will generate SW SMI. +// +// Input: +// IN CONST EFI_SMM_COMMUNICATION_PROTOCOL *This, +// IN OUT VOID *CommBuffer, +// IN OUT UINTN *CommSize +// +// Output: EFI_STATUS +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +EFI_STATUS SmmCommunicate( + IN CONST EFI_SMM_COMMUNICATION_PROTOCOL *This, + IN OUT VOID *CommBuffer, + IN OUT UINTN *CommSize +) +{ + gCommunicateData->CommBuffer = CommBuffer; + gCommunicateData->CommSize = CommSize; + gCommunicateData->Status = EFI_DEVICE_ERROR; //Pre-initialize status in case SMI doesn't happen. + + //Execute SW SMI to initialize + IoWrite8(SW_SMI_IO_ADDRESS, SMM_COMM_SW_SMI); + + return gCommunicateData->Status; +} + +EFI_SMM_COMMUNICATION_PROTOCOL gEfiSmmCommunicationProtocol = { + SmmCommunicate +}; + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Procedure: VirtAddrChg +// +// Description: Change pointer of gCommunicateData to virtual address. +// +// Input: +// IN EFI_EVENT Event +// IN VOID *Context +// +// Output: VOID +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +VOID VirtAddrChg(IN EFI_EVENT Event, IN VOID *Context) +{ + pRS->ConvertPointer(0, (VOID**)&gCommunicateData); +} + + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Procedure: InitDxe +// +// Description: Initialize DXE SMM Communicate part. +// +// Input: VOID +// +// Output: EFI_STATUS +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +EFI_STATUS InitDxe() +{ + EFI_STATUS Status; + EFI_EVENT VirtAddrChgEvt; + + Status = pBS->AllocatePool(EfiRuntimeServicesData, sizeof(SMM_COMMUNICATE_DATA), &gCommunicateData); + ASSERT_EFI_ERROR(Status); + + //Pass gCommunicateData to SMM Dispatcher. + gCommunicateData->Status = EFI_DEVICE_ERROR; //Pre-initialize status in case SMI doesn't happen. + + //Set Value + Status = pRS->SetVariable( + SMM_COMMUNICATE_DATA_VARIABLE, + &gSmmCommunicateDataGuid, + EFI_VARIABLE_BOOTSERVICE_ACCESS, + sizeof(SMM_COMMUNICATE_DATA*), + &gCommunicateData + ); + + IoWrite8(SW_SMI_IO_ADDRESS, SMM_COMM_SW_SMI); + + if (gCommunicateData->Status == EFI_DEVICE_ERROR) return EFI_DEVICE_ERROR; + + InitAcpi(); + + Status = pBS->CreateEvent( + EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE, + TPL_CALLBACK, + &VirtAddrChg, + NULL, + &VirtAddrChgEvt + ); + ASSERT_EFI_ERROR(Status); + + + Status = pBS->InstallMultipleProtocolInterfaces( + &gImageHandle, + &gEfiSmmCommunicationProtocolGuid, &gEfiSmmCommunicationProtocol, + NULL + ); + + return Status; +} + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Procedure: SmmCommunicateEntry +// +// Description: Smm Communciation entry point to initialize provide SMM Communicate Protocol. +// +// Input: +// IN EFI_HANDLE ImageHandle, +// IN EFI_SYSTEM_TABLE *SystemTable +// +// Output: EFI_STATUS +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +EFI_STATUS SmmCommunicateEntry( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable +) +{ + EFI_STATUS Status; + BOOLEAN InSmram; + + InitAmiLib(ImageHandle,SystemTable); + + gImageHandle = ImageHandle; + + Status = pBS->LocateProtocol(&gEfiSmmBase2ProtocolGuid, NULL, &gSmmBase2); + ASSERT_EFI_ERROR(Status); + + Status = gSmmBase2->InSmm(gSmmBase2, &InSmram); + ASSERT_EFI_ERROR(Status); + + if (InSmram) return InitSmm(); + return InitDxe(); +} diff --git a/Core/EM/SMM/SmmCommunicate.cif b/Core/EM/SMM/SmmCommunicate.cif new file mode 100644 index 0000000..3d086cd --- /dev/null +++ b/Core/EM/SMM/SmmCommunicate.cif @@ -0,0 +1,12 @@ +<component> + name = "SmmCommunicate" + category = ModulePart + LocalRoot = "Core\EM\SMM\" + RefName = "SmmCommunicate" +[files] +"SmmCommunicate.sdl" +"SmmCommunicate.c" +"SmmCommunicate.dxs" +"SmmDxeCommunicate.dxs" +"SmmCommunicate.mak" +<endComponent> diff --git a/Core/EM/SMM/SmmCommunicate.dxs b/Core/EM/SMM/SmmCommunicate.dxs new file mode 100644 index 0000000..4eb6b47 --- /dev/null +++ b/Core/EM/SMM/SmmCommunicate.dxs @@ -0,0 +1,67 @@ +//************************************************************************* +//************************************************************************* +//** ** +//** (C)Copyright 1985-2011, American Megatrends, Inc. ** +//** ** +//** All Rights Reserved. ** +//** ** +//** 5555 Oakbrook Parkway, Suite 200, Norcross, GA 30093 ** +//** ** +//** Phone: (770)-246-8600 ** +//** ** +//************************************************************************* +//************************************************************************* + +//********************************************************************** +// $Header: /Alaska/SOURCE/Modules/SMM/SmmCommunicate/SmmCommunicate.dxs 1 4/18/11 12:03p Markw $ +// +// $Revision: 1 $ +// +// $Date: 4/18/11 12:03p $ +//********************************************************************** +// Revision History +// ---------------- +// $Log: /Alaska/SOURCE/Modules/SMM/SmmCommunicate/SmmCommunicate.dxs $ +// +// 1 4/18/11 12:03p Markw +// [TAG] EIP57440 +// [Category] New Feature +// [Description] Add SMM PI 1.1 Communicate Support. +// [Files] SmmCommunicate.cif +// SmmCommunicate.sdl +// SmmCommunicate.c +// SmmCommunicate.dxs +// SmmDxeCommunicate.dxs +// SmmCommunicate.mak +// +//********************************************************************** + +//<AMI_FHDR_START> +//--------------------------------------------------------------------------- +// +// Name: SmmCommunicate.dxs +// +// Description: Dependency file for the SMM Communicate driver +// +//--------------------------------------------------------------------------- +//<AMI_FHDR_END> + +#include <Protocol\SmmSwDispatch2.h> + +DEPENDENCY_START + EFI_SMM_SW_DISPATCH2_PROTOCOL_GUID +DEPENDENCY_END + +//************************************************************************* +//************************************************************************* +//** ** +//** (C)Copyright 1985-2011, American Megatrends, Inc. ** +//** ** +//** All Rights Reserved. ** +//** ** +//** 5555 Oakbrook Parkway, Suite 200, Norcross, GA 30093 ** +//** ** +//** Phone: (770)-246-8600 ** +//** ** +//************************************************************************* +//************************************************************************* diff --git a/Core/EM/SMM/SmmCommunicate.mak b/Core/EM/SMM/SmmCommunicate.mak new file mode 100644 index 0000000..b0b4918 --- /dev/null +++ b/Core/EM/SMM/SmmCommunicate.mak @@ -0,0 +1,91 @@ +#************************************************************************* +#************************************************************************* +#** ** +#** (C)Copyright 1985-2011, American Megatrends, Inc. ** +#** ** +#** All Rights Reserved. ** +#** ** +#** 5555 Oakbrook Parkway, Suite 200, Norcross, GA 30093 ** +#** ** +#** Phone: (770)-246-8600 ** +#** ** +#************************************************************************* +#************************************************************************* + +#********************************************************************** +# $Header: /Alaska/SOURCE/Modules/SMM/SmmCommunicate/SmmCommunicate.mak 2 9/12/11 9:59a Markw $ +# +# $Revision: 2 $ +# +# $Date: 9/12/11 9:59a $ +#********************************************************************** +# Revision History +# ---------------- +# $Log: /Alaska/SOURCE/Modules/SMM/SmmCommunicate/SmmCommunicate.mak $ +# +# 2 9/12/11 9:59a Markw +# [TAG] EIP64115 +# [Category] Bug Fix +# [Severity] Normal +# [Symptom] SmmCommuncate hangs in OS. +# [RootCause] SmmCommunicate not supported in OS. +# [Solution] Update SMM Communicate to work under OS by making it a +# runtime driver and converting pointers to virtual points on +# EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE. +# +# [Files] SmmCommunicate.c, SmmCommunicate.mak +# +# 1 4/18/11 12:03p Markw +# [TAG] EIP57440 +# [Category] New Feature +# [Description] Add SMM PI 1.1 Communicate Support. +# [Files] SmmCommunicate.cif +# SmmCommunicate.sdl +# SmmCommunicate.c +# SmmCommunicate.dxs +# SmmDxeCommunicate.dxs +# SmmCommunicate.mak +# +#********************************************************************** + +#<AMI_FHDR_START> +#--------------------------------------------------------------------------- +# +# Name: SmmCommunicate.mak +# +# Description: Make file for the SMM Communicate code +# +#--------------------------------------------------------------------------- +#<AMI_FHDR_END> + +all : SmmCommunicate +SmmCommunicate : $(BUILD_DIR)\SmmCommunicate.mak SmmCommunicateBin + +$(BUILD_DIR)\SmmCommunicate.mak : $(SMM_COMMUNICATE_DIR)\SmmCommunicate.cif $(SMM_COMMUNICATE_DIR)\$(@B).mak $(BUILD_RULES) + $(CIF2MAK) $(SMM_COMMUNICATE_DIR)\SmmCommunicate.cif $(CIF2MAK_DEFAULTS) + +SmmCommunicateBin : $(AMIDXELIB) $(AMICSPLib) + $(MAKE) /$(MAKEFLAGS) $(BUILD_DEFAULTS)\ + /f $(BUILD_DIR)\SmmCommunicate.mak all\ + GUID=7E2D983F-F703-4a29-9761-77B51F5354ED\ + ENTRY_POINT=SmmCommunicateEntry\ + TYPE=DXESMM_DRIVER PE_TYPE=RT_DRIVER\ + DEPEX1=$(SMM_COMMUNICATE_DIR)\SmmCommunicate.dxs \ + DEPEX1_TYPE=EFI_SECTION_SMM_DEPEX \ + DEPEX2=$(SMM_COMMUNICATE_DIR)\SmmDxeCommunicate.dxs \ + DEPEX2_TYPE=EFI_SECTION_DXE_DEPEX \ + COMPRESS=1 + +#************************************************************************* +#************************************************************************* +#** ** +#** (C)Copyright 1985-2011, American Megatrends, Inc. ** +#** ** +#** All Rights Reserved. ** +#** ** +#** 5555 Oakbrook Parkway, Suite 200, Norcross, GA 30093 ** +#** ** +#** Phone: (770)-246-8600 ** +#** ** +#************************************************************************* +#************************************************************************* diff --git a/Core/EM/SMM/SmmCommunicate.sdl b/Core/EM/SMM/SmmCommunicate.sdl new file mode 100644 index 0000000..7ac66cc --- /dev/null +++ b/Core/EM/SMM/SmmCommunicate.sdl @@ -0,0 +1,44 @@ +TOKEN + Name = "SMM_COMMUNICATE_SUPPORT" + Value = "1" + Help = "Main switch to enable SmmBase support in Project" + TokenType = Boolean + TargetEQU = Yes + TargetMAK = Yes + Master = Yes + Token = "PI_SPECIFICATION_VERSION" ">=" "0x1000A" +End + +TOKEN + Name = "SMM_COMM_SW_SMI" + Value = "0xdd" + Help = "SMM Communicate function SW SMI. Do not change" + TokenType = Integer + TargetH = Yes + Lock = Yes +End + +TOKEN + Name = "SMM_COMM_ACPI_SW_SMI" + Value = "0xde" + Help = "SMM Communicate ACPI SW SMI. Do not change" + TokenType = Integer + TargetH = Yes + Lock = Yes +End + +PATH + Name = "SMM_COMMUNICATE_DIR" +End + +MODULE + Help = "Includes SmmCommunicate.mak to Project" + File = "SmmCommunicate.mak" +End + +ELINK + Name = "$(BUILD_DIR)\SmmCommunicate.ffs" + Parent = "FV_MAIN" + InvokeOrder = AfterParent +End + 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 ** +//** ** +//************************************************************************* +//************************************************************************* diff --git a/Core/EM/SMM/SmmDispatcher.cif b/Core/EM/SMM/SmmDispatcher.cif new file mode 100644 index 0000000..cada3c7 --- /dev/null +++ b/Core/EM/SMM/SmmDispatcher.cif @@ -0,0 +1,17 @@ +<component> + name = "SmmDispatcher" + category = ModulePart + LocalRoot = "Core\EM\SMM" + RefName = "SmmDispatcher" +[files] +"SmmDispatcher.sdl" +"SmmDispatcher.mak" +"SmmEntry.asm" +"SmmDispatcher.h" +"SmmDispatcher.c" +"Smst.c" +"SmmPiSmst.c" +"SmmMemoryManager.c" +"SmmDispatcherAsm.asm" +"SmmDispatcher.dxs" +<endComponent> diff --git a/Core/EM/SMM/SmmDispatcher.dxs b/Core/EM/SMM/SmmDispatcher.dxs new file mode 100644 index 0000000..fd931d5 --- /dev/null +++ b/Core/EM/SMM/SmmDispatcher.dxs @@ -0,0 +1,59 @@ +//************************************************************************* +//************************************************************************* +//** ** +//** (C)Copyright 1985-2009, American Megatrends, Inc. ** +//** ** +//** All Rights Reserved. ** +//** ** +//** 5555 Oakbrook Parkway, Suite 200, Norcross, GA 30093 ** +//** ** +//** Phone: (770)-246-8600 ** +//** ** +//************************************************************************* +//************************************************************************* + +//********************************************************************** +//********************************************************************** +// $Header: /Alaska/SOURCE/Modules/SMM/SMMDispatcher/SmmDispatcher.dxs 2 8/05/09 3:04p Markw $ +// +// $Revision: 2 $ +// +// $Date: 8/05/09 3:04p $ +//********************************************************************** +// Revision History +// ---------------- +// $Log: /Alaska/SOURCE/Modules/SMM/SMMDispatcher/SmmDispatcher.dxs $ +// +// 2 8/05/09 3:04p Markw +// +// +//********************************************************************** + +//<AMI_FHDR_START> +//--------------------------------------------------------------------------- +// +// Name: SmmDispatcher.dxs +// +// Description: Dependency file for the SMM dispatcher +// +//--------------------------------------------------------------------------- +//<AMI_FHDR_END> + + +DEPENDENCY_START + FALSE +DEPENDENCY_END + +//************************************************************************* +//************************************************************************* +//** ** +//** (C)Copyright 1985-2009, American Megatrends, Inc. ** +//** ** +//** All Rights Reserved. ** +//** ** +//** 5555 Oakbrook Parkway, Suite 200, Norcross, GA 30093 ** +//** ** +//** Phone: (770)-246-8600 ** +//** ** +//************************************************************************* +//************************************************************************* diff --git a/Core/EM/SMM/SmmDispatcher.h b/Core/EM/SMM/SmmDispatcher.h new file mode 100644 index 0000000..2b0f07c --- /dev/null +++ b/Core/EM/SMM/SmmDispatcher.h @@ -0,0 +1,253 @@ +//************************************************************************* +//************************************************************************* +//** ** +//** (C)Copyright 1985-2009, American Megatrends, Inc. ** +//** ** +//** All Rights Reserved. ** +//** ** +//** 5555 Oakbrook Parkway, Suite 200, Norcross, GA 30093 ** +//** ** +//** Phone: (770)-246-8600 ** +//** ** +//************************************************************************* +//************************************************************************* + +//********************************************************************** +// $Header: /Alaska/SOURCE/Modules/SMM/SMMDispatcher/SmmDispatcher.h 2 2/07/11 3:29p Markw $ +// +// $Revision: 2 $ +// +// $Date: 2/07/11 3:29p $ +//********************************************************************** +// Revision History +// ---------------- +// $Log: /Alaska/SOURCE/Modules/SMM/SMMDispatcher/SmmDispatcher.h $ +// +// 2 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 +// +//********************************************************************** + +//<AMI_FHDR_START> +//--------------------------------------------------------------------------- +// +// Name: SmmDispatcher.h +// +// Description: SmmDispatcher header file +// +//--------------------------------------------------------------------------- +//<AMI_FHDR_END> + +#ifndef __SMM_DISPATCHER__H__ +#define __SMM_DISPATCHER__H__ + +#include <SmmPi.h> +#include <AmiLib.h> + +// +// CONTAINING_RECORD - returns a pointer to the structure +// from one of it's elements. +// +#ifndef _CR +#define _CR(Record, TYPE, Field) ((TYPE *) ((CHAR8 *) (Record) - (CHAR8 *) &(((TYPE *) 0)->Field))) +#endif + +#ifndef CR +#define CR(record, TYPE, field, signature) _CR(record, TYPE, field) +#endif + +// +// Define macros to build data structure signatures from characters. +// +#define SIGNATURE_16(A, B) ((A) | (B << 8)) +#define SIGNATURE_32(A, B, C, D) (SIGNATURE_16 (A, B) | (SIGNATURE_16 (C, D) << 16)) +#define SIGNATURE_64(A, B, C, D, E, F, G, H) \ + (SIGNATURE_32 (A, B, C, D) | ((UINT64) (SIGNATURE_32 (E, F, G, H)) << 32)) +//---- Added from Core\Tiano.h + + +// +// SMM_HANDLER - used for each SMM handler +// + +#define SMI_ENTRY_SIGNATURE SIGNATURE_32('s','m','i','e') + + typedef struct { + UINTN Signature; + EFI_LIST_ENTRY AllEntries; // All entries + + EFI_GUID HandlerType; // Type of interrupt + EFI_LIST_ENTRY SmiHandlers; // All handlers +} SMM_SMI_ENTRY; + +#define SMI_HANDLER_SIGNATURE SIGNATURE_32('s','m','i','h') + +typedef struct { + UINTN Signature; + EFI_LIST_ENTRY Link; // Link on SMI_ENTRY.SmiHandlers + EFI_SMM_HANDLER_ENTRY_POINT2 Handler; // The smm handler's entry point + SMM_SMI_ENTRY *SmiEntry; +} SMM_SMI_HANDLER; + + + + +#define SMM_EFI_HANDLE_SIGNATURE SIGNATURE_32('S','h','n','d') +//#define ASSERT_IS_HANDLE(a) ASSERT((a)->Signature == EFI_HANDLE_SIGNATURE) + +#define SMM_PROTOCOL_ENTRY_SIGNATURE SIGNATURE_32('S','p','r','E') + +#define SMM_SMST_SIGNATURE2 SIGNATURE_32('S','M','T','2') + + +#ifndef EFI_LIST_ENTRY_DEFINED +#define EFI_LIST_ENTRY_DEFINED +typedef struct _EFI_LIST_ENTRY { + struct _EFI_LIST_ENTRY *ForwardLink; + struct _EFI_LIST_ENTRY *BackLink; +} EFI_LIST_ENTRY; +#endif + + +typedef struct { + UINTN Signature; + /// All handles list of IHANDLE + EFI_LIST_ENTRY AllHandles; + /// List of PROTOCOL_INTERFACE's for this handle + EFI_LIST_ENTRY Protocols; + UINTN LocateRequest; +} SMM_IHANDLE; + + + +typedef struct { + UINTN Signature; + /// Link Entry inserted to mProtocolDatabase + EFI_LIST_ENTRY AllEntries; + /// ID of the protocol + EFI_GUID ProtocolID; + /// All protocol interfaces + EFI_LIST_ENTRY Protocols; + /// Registerd notification handlers + EFI_LIST_ENTRY Notify; +} SMM_PROTOCOL_ENTRY; + + +#define SMM_PROTOCOL_INTERFACE_SIGNATURE SIGNATURE_32('S','p','i','f') + +typedef struct { + UINTN Signature; + /// Link on IHANDLE.Protocols + EFI_LIST_ENTRY Link; + /// Back pointer + SMM_IHANDLE *Handle; + /// Link on PROTOCOL_ENTRY.Protocols + EFI_LIST_ENTRY ByProtocol; + /// The protocol ID + SMM_PROTOCOL_ENTRY *Protocol; + /// The interface value + VOID *Interface; +} SMM_PROTOCOL_INTERFACE; + +#define SMM_PROTOCOL_NOTIFY_SIGNATURE ('S','p','r','n') + +typedef struct { + UINTN Signature; + SMM_PROTOCOL_ENTRY *Protocol; + /// All notifications for this protocol + EFI_LIST_ENTRY Link; + /// Notification function + EFI_SMM_NOTIFY_FN Function; + /// Last position notified + EFI_LIST_ENTRY *Position; +} SMM_PROTOCOL_NOTIFY; + +typedef struct { + EFI_GUID *Protocol; + VOID *SearchKey; + EFI_LIST_ENTRY *Position; + SMM_PROTOCOL_ENTRY *ProtEntry; +} SMM_LOCATE_POSITION; + +typedef +SMM_IHANDLE * +(* SMM_CORE_GET_NEXT) ( + IN OUT SMM_LOCATE_POSITION *Position, + OUT VOID **Interface + ); + +VOID +SmmNotifyProtocol ( + IN SMM_PROTOCOL_INTERFACE *Prot + ); + +EFI_STATUS +SmmSmstInstallProtocolInterfaceNotify ( + IN OUT EFI_HANDLE *UserHandle, + IN EFI_GUID *Protocol, + IN EFI_INTERFACE_TYPE InterfaceType, + IN VOID *Interface, + IN BOOLEAN Notify + ); + +EFI_STATUS +EFIAPI +SmmSmstHandleProtocol ( + IN EFI_HANDLE UserHandle, + IN EFI_GUID *Protocol, + OUT VOID **Interface + ); + + +EFI_STATUS +EFIAPI +SmmSmstLocateProtocol ( + IN EFI_GUID *Protocol, + IN VOID *Registration OPTIONAL, + OUT VOID **Interface + ); + +EFI_STATUS +EFIAPI +SmmUninstallProtocolInterface ( + IN EFI_HANDLE UserHandle, + IN EFI_GUID *Protocol, + IN VOID *Interface + ); + +SMM_PROTOCOL_INTERFACE * +SmmRemoveInterfaceFromProtocol ( + IN SMM_IHANDLE *Handle, + IN EFI_GUID *Protocol, + IN VOID *Interface + ); + + + + +/****** DO NOT WRITE BELOW THIS LINE *******/ +#ifdef __cplusplus +} +#endif +#endif + +//************************************************************************* +//************************************************************************* +//** ** +//** (C)Copyright 1985-2009, American Megatrends, Inc. ** +//** ** +//** All Rights Reserved. ** +//** ** +//** 5555 Oakbrook Parkway, Suite 200, Norcross, GA 30093 ** +//** ** +//** Phone: (770)-246-8600 ** +//** ** +//************************************************************************* +//************************************************************************* diff --git a/Core/EM/SMM/SmmDispatcher.mak b/Core/EM/SMM/SmmDispatcher.mak new file mode 100644 index 0000000..241d939 --- /dev/null +++ b/Core/EM/SMM/SmmDispatcher.mak @@ -0,0 +1,127 @@ +#************************************************************************* +#************************************************************************* +#** ** +#** (C)Copyright 1985-2008, American Megatrends, Inc. ** +#** ** +#** All Rights Reserved. ** +#** ** +#** 5555 Oakbrook Parkway, Suite 200, Norcross, GA 30093 ** +#** ** +#** Phone: (770)-246-8600 ** +#** ** +#************************************************************************* +#************************************************************************* + +#********************************************************************** +# $Header: /Alaska/SOURCE/Modules/SMM/SMMDispatcher/SmmDispatcher.mak 9 2/07/11 3:29p Markw $ +# +# $Revision: 9 $ +# +# $Date: 2/07/11 3:29p $ +#********************************************************************** +# Revision History +# ---------------- +# $Log: /Alaska/SOURCE/Modules/SMM/SMMDispatcher/SmmDispatcher.mak $ +# +# 9 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 +# +# 8 7/08/09 9:28p Markw +# Update headers. +# +# 7 3/05/09 5:20p Fasihm +# Rolled back accidental check-in. +# +# 5 8/28/08 3:52p Markw +# +# 4 6/09/08 5:48p Markw +# Add SmmDispatcherBoard.obj and SmmDispatcherAsm.obj to be linked. +# +# 3 10/24/07 12:01p Markw +# Combined BSP and AP SmmEntry. +# +# 2 8/24/06 3:28p Felixp +# Preliminary x64 support (work in progress) +# +# 1 1/28/05 4:32p Sivagarn +# SMM Dispatcher Component - Initial check in +# +# +#********************************************************************** + +#<AMI_FHDR_START> +#--------------------------------------------------------------------------- +# +# Name: SmmDispatcher.mak +# +# Description: Make file for the SMM Dispatcher +# +#--------------------------------------------------------------------------- +#<AMI_FHDR_END> +SMM_DISPATCHER_BUILD_DIR = $(BUILD_DIR)\$(SMM_DISPATCHER_DIR) + +all : SmmDispatcher SmmEntry + +SMM_DISPATCHER_OBJECTS = \ + $(SMM_DISPATCHER_BUILD_DIR)\SmmDispatcher.obj \ + $(SMM_DISPATCHER_BUILD_DIR)\Smst.obj \ + $(SMM_DISPATCHER_BUILD_DIR)\SmmPiSmst.obj \ + $(SMM_DISPATCHER_BUILD_DIR)\SmmMemoryManager.obj \ + $(SMM_DISPATCHER_BUILD_DIR)\SmmDispatcherAsm.obj + +SmmDispatcher : $(BUILD_DIR)\SmmDispatcher.mak SmmDispatcherBin +SmmEntry : $(BUILD_DIR)\SmmDispatcher.mak SmmEntryBin + +$(BUILD_DIR)\SmmDispatcher.mak : $(SMM_DISPATCHER_DIR)\$(@B).cif $(SMM_DISPATCHER_DIR)\$(@B).mak $(BUILD_RULES) + $(CIF2MAK) $(SMM_DISPATCHER_DIR)\$(@B).cif $(CIF2MAK_DEFAULTS) + +!IFNDEF PI_SPECIFICATION_VERSION +PI_SPECIFICATION_VERSION = 0 +!ENDIF + +SmmDispatcherBin : $(AMIDXELIB) $(AMICSPLib) + $(MAKE) /$(MAKEFLAGS) $(BUILD_DEFAULTS)\ + /f $(BUILD_DIR)\SmmDispatcher.mak all\ +# Don't change the GUID. SmmBase driver expects this GUID. + GUID=4A37320B-3FB3-4365-9730-9E89C600395D\ + ENTRY_POINT=InitializeDispatcher \ +!IF $(PI_SPECIFICATION_VERSION) >= 0x00001000A + TYPE=SMM_CORE \ +!ELSE + TYPE=BS_DRIVER \ +!ENDIF + "OBJECTS=$(SMM_DISPATCHER_OBJECTS)"\ + "EXT_HEADERS=$(SMM_DISPATCHER_DIR)\SmmPrivateShared.h"\ + "CFLAGS=$(CFLAGS) /D\"SmmSaveRestoreEnvironment=$(SmmSaveRestoreEnvironment)\""\ + COMPRESS=1\ + +SmmEntryBin : + $(MAKE) /$(MAKEFLAGS) $(BUILD_DEFAULTS)\ + /f $(BUILD_DIR)\SmmDispatcher.mak all\ +# Don't change the GUID. SmmBase driver expects this GUID. + GUID=D2596F82-F0E1-49fa-95BC-62012C795728\ + MAKEFILE=$(SMM_DISPATCHER_DIR)\SmmDispatcher.mak \ + TYPE=LEGACY16 NAME=SmmEntry DEPEX1= \ + "OBJECTS=$(SMM_DISPATCHER_BUILD_DIR)\SmmEntry.obj"\ + COMPRESS=1\ + +#************************************************************************* +#************************************************************************* +#** ** +#** (C)Copyright 1985-2008, American Megatrends, Inc. ** +#** ** +#** All Rights Reserved. ** +#** ** +#** 5555 Oakbrook Parkway, Suite 200, Norcross, GA 30093 ** +#** ** +#** Phone: (770)-246-8600 ** +#** ** +#************************************************************************* +#************************************************************************* diff --git a/Core/EM/SMM/SmmDispatcher.sdl b/Core/EM/SMM/SmmDispatcher.sdl new file mode 100644 index 0000000..5ec4c24 --- /dev/null +++ b/Core/EM/SMM/SmmDispatcher.sdl @@ -0,0 +1,35 @@ +TOKEN + Name = "SmmDispatcher_SUPPORT" + Value = "1" + Help = "Main switch to enable SmmDispatcher support in Project" + TokenType = Boolean + TargetEQU = Yes + TargetMAK = Yes + Master = Yes +End + +PATH + Name = "SMM_DISPATCHER_DIR" +End + +MODULE + Help = "Includes SmmDispatcher.mak to Project" + File = "SmmDispatcher.mak" +End + +ELINK + Name = "$(BUILD_DIR)\SmmDispatcher.ffs" + Parent = "FV_MAIN" + InvokeOrder = AfterParent +End + +ELINK + Name = "$(BUILD_DIR)\SmmEntry.ffs" + Parent = "FV_MAIN" + InvokeOrder = AfterParent +End + +ELINK + Name = "SmmSaveRestoreEnvironment" + InvokeOrder = ReplaceParent +End diff --git a/Core/EM/SMM/SmmDispatcherAsm.asm b/Core/EM/SMM/SmmDispatcherAsm.asm new file mode 100644 index 0000000..1abc682 --- /dev/null +++ b/Core/EM/SMM/SmmDispatcherAsm.asm @@ -0,0 +1,196 @@ +;************************************************************************* +;************************************************************************* +;** ** +;** (C)Copyright 1985-2009, American Megatrends, Inc. ** +;** ** +;** All Rights Reserved. ** +;** ** +;** 5555 Oakbrook Parkway, Suite 200, Norcross, GA 30093 ** +;** ** +;** Phone: (770)-246-8600 ** +;** ** +;************************************************************************* +;************************************************************************* + +;********************************************************************** +; $Header: /Alaska/SOURCE/Modules/SMM/SMMDispatcher/SmmDispatcherAsm.asm 4 10/03/11 2:53p Markw $ +; +; $Revision: 4 $ +; +; $Date: 10/03/11 2:53p $ +;********************************************************************** +; Revision History +; ---------------- +; $Log: /Alaska/SOURCE/Modules/SMM/SMMDispatcher/SmmDispatcherAsm.asm $ +; +; 4 10/03/11 2:53p Markw +; Add SMM Machine Check handler. +; Files: SmmDispatcher.c, SmmDispatcherAsm.asm +; +; 3 7/08/09 8:18p Markw +; Update headers. +; +; 2 11/21/08 5:00p Markw +; Add LockInc32 and LockDec32. +; +; 1 6/09/08 5:56p Markw +; Assembly functions for Dispatcher. +; +;********************************************************************** + +;<AMI_FHDR_START> +;---------------------------------------------------------------------------- +; +; Name: SmmDispatcher.asm +; +; Description: File that contains assembly for Smm Dispatcher. +; +;---------------------------------------------------------------------------- +;<AMI_FHDR_END> + +IFDEF EFIx64 +.code +include token.equ + +;<AMI_PHDR_START> +;---------------------------------------------------------------------------- +; +; Procedure: Xchg8 +; +; Description: Exchange a value with a pointer and return the exchanged value. +; +; Input: +; IN OUT volatile UINT8 * Pointer to value to exchange. +; IN UINT8 Value to exchange. +; +; Output: UINT8 Exchanged Value +; +; Modified: Nothing +; +;---------------------------------------------------------------------------- +;<AMI_PHDR_END> +Xchg8 proc public + xchg dl, [rcx] + mov al, dl + ret +Xchg8 endp + +;<AMI_PHDR_START> +;--------------------------------------------------------------------------- +; +; Procedure: LockInc32 +; +; Description: Increment value at pointer locking address. +; +; Input: IN OUT UINT32 *ptr +; +; Output: None +;--------------------------------------------------------------------------- +;<AMI_PHDR_END> + +LockInc32 proc public + lock inc dword ptr [rcx] + ret +LockInc32 endp + +;<AMI_PHDR_START> +;--------------------------------------------------------------------------- +; +; Procedure: LockDec32 +; +; Description: Decrement value at pointer locking address. +; +; Input: IN OUT UINT32 *ptr +; +; Output: None +;--------------------------------------------------------------------------- +;<AMI_PHDR_END> + +LockDec32 proc public + lock dec dword ptr [rcx] + ret +LockDec32 endp + +;<AMI_PHDR_START> +;--------------------------------------------------------------------------- +; +; Procedure: MachineCheckHandler +; +; Description: SMM Machine Check Handler +; +; Input: VOID +; +; Output: VOID +;--------------------------------------------------------------------------- +;<AMI_PHDR_END> + +MachineCheckHandler proc public + push rax + push rcx + push rdx + mov ecx, 17ah ;IA32_MCG_STATUS + rdmsr + btr eax, 2 ;MCIP + wrmsr + pop rdx + pop rcx + pop rax + iretq +MachineCheckHandler endp + +ELSE ;32-bits +.586p +.model small +.code + +_Xchg8 proc public + mov al, [esp + 8] + mov edx, [esp + 4] + xchg al, [edx] + ret +_Xchg8 endp + +_LockInc32 proc public + mov eax, [esp + 4] + lock inc dword ptr [eax] + ret +_LockInc32 endp + + +_LockDec32 proc public + mov eax, [esp + 4] + lock dec dword ptr [eax] + ret +_LockDec32 endp + +_MachineCheckHandler proc public + push eax + push ecx + push edx + mov ecx, 17ah ;IA32_MCG_STATUS + rdmsr + btr eax, 2 ;MCIP + wrmsr + pop edx + pop ecx + pop eax + iretd +_MachineCheckHandler endp + +ENDIF + +end + +;************************************************************************* +;************************************************************************* +;** ** +;** (C)Copyright 1985-2008, American Megatrends, Inc. ** +;** ** +;** All Rights Reserved. ** +;** ** +;** 5555 Oakbrook Parkway, Suite 200, Norcross, GA 30093 ** +;** ** +;** Phone: (770)-246-8600 ** +;** ** +;************************************************************************* +;************************************************************************* diff --git a/Core/EM/SMM/SmmDriverDispatcher.c b/Core/EM/SMM/SmmDriverDispatcher.c new file mode 100644 index 0000000..c5b4431 --- /dev/null +++ b/Core/EM/SMM/SmmDriverDispatcher.c @@ -0,0 +1,1694 @@ +//************************************************************************* +//************************************************************************* +//** ** +//** (C)Copyright 1985-2011, American Megatrends, Inc. ** +//** ** +//** All Rights Reserved. ** +//** ** +//** 5555 Oakbrook Parkway, Suite 200, Norcross, GA 30093 ** +//** ** +//** Phone: (770)-246-8600 ** +//** ** +//************************************************************************* +//************************************************************************* + +/** SmmDriverDispatcher.c - Modified 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/SMMBase/SmmDriverDispatcher.c 6 2/13/12 4:42p Markw $ +// +// $Revision: 6 $ +// +// $Date: 2/13/12 4:42p $ +//********************************************************************** +// Revision History +// ---------------- +// $Log: /Alaska/SOURCE/Modules/SMM/SMMBase/SmmDriverDispatcher.c $ +// +// 6 2/13/12 4:42p Markw +// [TAG] EIP83005 +// [Category] Improvement +// [Description] Some framework based SMM libraries expect a DXE image +// handle on input. However, PI 1.1 SMM drivers expect a SMM handle on +// input. +// Update code to provide proper EFI_HANDLE when calling SMM functions. +// +// [Files] SmmBase.c, SmmDriverDispatcher.c +// +// 5 1/10/12 12:58p Markw +// [TAG] EIP78978 +// [Category] Improvement +// [Description] Cleanup of SmmLoadImage function - removing unused and +// removing unneeded variable initialization. +// [Files] SmmDriverDispatcher.c +// +// 4 1/09/12 3:06p Markw +// [TAG] EIP78978 +// [Category] Bug Fix +// [Severity] Normal +// [Symptom] SMM driver will authentication failed. +// [RootCause] Incorrect device path as input parameter when checking +// authentication. +// +// [Solution] Authentication is done twice. Remove redundant code. +// Second authentication check is using the correct original device path. +// +// [Files] SmmDriverDispatcher.c +// +// 3 3/15/11 2:37p Markw +// Copyright header update. +// +// 2 3/08/11 4:57p Markw +// Header and spacing updates. +// +// 1 2/07/11 3:34p 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 +// +//********************************************************************** + +//<AMI_FHDR_START> +//--------------------------------------------------------------------------- +// +// Name: SmmDriverDispatcher.c +// +// Description: Dispatch SMM Drivers +// +//--------------------------------------------------------------------------- +//<AMI_FHDR_END> + +//This include should come first. +#include "SmmPrivateShared.h" +#if SMM_USE_PI +#include <SmmPi.h> +#include <Protocol\DevicePath.h> +#include <Protocol\Security.h> +#include <Dxe.h> +#include <Protocol\FirmwareVolume2.h> +#include <Protocol\LoadedImage.h> +#include <AmiDxeLib.h> +#include <AmiLib.h> + +extern EFI_SMM_SYSTEM_TABLE2 *gSmstTable2; +extern SMM_BASE_PRIVATE_STRUCT *gBasePrivate; +extern BOOLEAN gRegisterForPi; + +// +// CONTAINING_RECORD - returns a pointer to the structure +// from one of it's elements. +// +#ifndef _CR +#define _CR(Record, TYPE, Field) ((TYPE *) ((CHAR8 *) (Record) - (CHAR8 *) &(((TYPE *) 0)->Field))) +#endif + +#ifndef CR +#define CR(record, TYPE, field, signature) _CR(record, TYPE, field) +#endif + + +// +// Define macros to build data structure signatures from characters. +// +#define SIGNATURE_16(A, B) ((A) | (B << 8)) +#define SIGNATURE_32(A, B, C, D) (SIGNATURE_16 (A, B) | (SIGNATURE_16 (C, D) << 16)) +#define SIGNATURE_64(A, B, C, D, E, F, G, H) \ + (SIGNATURE_32 (A, B, C, D) | ((UINT64) (SIGNATURE_32 (E, F, G, H)) << 32)) +//---- Added from Core\Tiano.h + + +// EFI_DEP_REPLACE_TRUE - Used to dynamically patch the dependency expression +// to save time. A EFI_DEP_PUSH is evaluated one an +// replaced with EFI_DEP_REPLACE_TRUE. If PI spec's Vol 2 +// Driver Execution Environment Core Interface use 0xff +// as new DEPEX opcode. EFI_DEP_REPLACE_TRUE should be +// defined to a new value that is not conflicting with PI spec. +// +#define EFI_DEP_REPLACE_TRUE 0xff + +/// Define the initial size of the dependency expression evaluation stack +#define DEPEX_STACK_SIZE_INCREMENT 0x1000 + +// +// +// EFI_DEP_BEFORE - If present, it must be the first and only opcode +// EFI_DEP_AFTER - If present, it must be the first and only opcode +// EFI_DEP_SOR - If present, it must be the first opcode +// EFI_DEP_REPLACE_TRUE - Used to dynamically patch the dependency expression +// to save time. A EFI_DEP_PUSH is evaluated one an +// replaced with EFI_DEP_REPLACE_TRUE +// +#define EFI_DEP_BEFORE 0x00 +#define EFI_DEP_AFTER 0x01 +#define EFI_DEP_PUSH 0x02 +#define EFI_DEP_AND 0x03 +#define EFI_DEP_OR 0x04 +#define EFI_DEP_NOT 0x05 +#define EFI_DEP_TRUE 0x06 +#define EFI_DEP_FALSE 0x07 +#define EFI_DEP_END 0x08 +#define EFI_DEP_SOR 0x09 +#define EFI_DEP_REPLACE_TRUE 0xff + + +// Global stack used to evaluate dependency expressions +BOOLEAN *mDepexEvaluationStack = NULL; +BOOLEAN *mDepexEvaluationStackEnd = NULL; +BOOLEAN *mDepexEvaluationStackPointer = NULL; + +#define LIST_ENTRY EFI_LIST_ENTRY + +// +// The Driver List contains one copy of every driver that has been discovered. +// Items are never removed from the driver list. List of EFI_SMM_DRIVER_ENTRY +// +LIST_ENTRY mDiscoveredList = INITIALIZE_LIST_HEAD_VARIABLE (mDiscoveredList); + +// +// Queue of drivers that are ready to dispatch. This queue is a subset of the +// mDiscoveredList.list of EFI_SMM_DRIVER_ENTRY. +// +LIST_ENTRY mScheduledQueue = INITIALIZE_LIST_HEAD_VARIABLE (mScheduledQueue); + +// +// List of handles who's Fv's have been parsed and added to the mFwDriverList. +// +LIST_ENTRY mFvHandleList = INITIALIZE_LIST_HEAD_VARIABLE (mFvHandleList); + +// +// Flag for the SMM Dispacher. TRUE if dispatcher is executing. +// +BOOLEAN gDispatcherRunning = FALSE; + +// +// Flag for the SMM Dispacher. TRUE if there is one or more SMM drivers ready to be dispatched +// +BOOLEAN gRequestDispatch = FALSE; + +// +// List of file types supported by dispatcher +// +EFI_FV_FILETYPE mSmmFileTypes[] = { + EFI_FV_FILETYPE_SMM, + EFI_FV_FILETYPE_COMBINED_SMM_DXE + // + // Note: DXE core will process the FV image file, so skip it in SMM core + // EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE + // +}; + +typedef struct { + MEDIA_FW_VOL_FILEPATH_DEVICE_PATH File; + EFI_DEVICE_PATH_PROTOCOL End; +} FV_FILEPATH_DEVICE_PATH; + +FV_FILEPATH_DEVICE_PATH mFvDevicePath; + +// +// DXE Architecture Protocols +// +EFI_SECURITY_ARCH_PROTOCOL *mSecurity = NULL; + +// +// SMM Dispatcher Data structures +// +#define KNOWN_HANDLE_SIGNATURE SIGNATURE_32('k','n','o','w') +typedef struct { + UINTN Signature; + LIST_ENTRY Link; // mFvHandleList + EFI_HANDLE Handle; +} KNOWN_HANDLE; + +// +// Structure for recording the state of an SMM Driver +// +#define EFI_SMM_DRIVER_ENTRY_SIGNATURE SIGNATURE_32('s', 'd','r','v') + +#define LIST_ENTRY EFI_LIST_ENTRY + +typedef struct { + UINTN Signature; + LIST_ENTRY Link; // mDriverList + + LIST_ENTRY ScheduledLink; // mScheduledQueue + + EFI_HANDLE FvHandle; + EFI_GUID FileName; + EFI_DEVICE_PATH_PROTOCOL *FvFileDevicePath; + EFI_FIRMWARE_VOLUME2_PROTOCOL *Fv; + + VOID *Depex; + UINTN DepexSize; + + BOOLEAN Before; + BOOLEAN After; + EFI_GUID BeforeAfterGuid; + + BOOLEAN Dependent; + BOOLEAN Unrequested; + BOOLEAN Scheduled; + BOOLEAN Untrusted; + BOOLEAN Initialized; + BOOLEAN DepexProtocolError; + + EFI_HANDLE ImageHandle; + EFI_LOADED_IMAGE_PROTOCOL *LoadedImage; + // + // Image EntryPoint in SMRAM + // + EFI_PHYSICAL_ADDRESS ImageEntryPoint; + // + // Image Buffer in SMRAM + // + EFI_PHYSICAL_ADDRESS ImageBuffer; + // + // Image Page Number + // + UINTN NumberOfPage; +} EFI_SMM_DRIVER_ENTRY; + +EFI_GUID gAprioriGuid=EFI_APRIORI_GUID; + +EFI_STATUS SmmDispatcher(); + +EFI_HANDLE gThisImageHandle; + +EFI_STATUS EfiSmmRegister( + IN VOID *This, + IN EFI_DEVICE_PATH_PROTOCOL *FilePath, + IN VOID *SourceBuffer OPTIONAL, + IN UINTN SourceSize, + OUT EFI_HANDLE *ImageHandle, + IN BOOLEAN LegacyIA32Binary OPTIONAL +); + +////////////////////////////////////////////////////////////////////// +// ----- PI 1.1 --------------------------------------------- START // +////////////////////////////////////////////////////////////////////// + +#define SetDevicePathNodeLength(a,l) { \ + (a)->Length[0] = (UINT8) (l); \ + (a)->Length[1] = (UINT8) ((l) >> 8); \ + } + +#define SetDevicePathEndNode(a) { \ + (a)->Type = END_DEVICE_PATH; \ + (a)->SubType = END_ENTIRE_SUBTYPE; \ + (a)->Length[0] = sizeof(EFI_DEVICE_PATH_PROTOCOL); \ + (a)->Length[1] = 0; \ + } + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Procedure: AllocatePool +// +// Description: Allocate memory. +// +// Input: +// IN UINTN Size +// +// Output: VOID * - Address +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +VOID *AllocatePool(UINTN Size){ + return Malloc(Size); +} + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Procedure: GrowDepexStack +// +// Description: Increase Depex Stack.. +// +// Input: VOID +// +// Output: EFI_STATUS +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +EFI_STATUS GrowDepexStack(VOID) +{ + BOOLEAN *NewStack; + UINTN Size; + + Size = DEPEX_STACK_SIZE_INCREMENT; + if (mDepexEvaluationStack != NULL) { + Size = Size + (mDepexEvaluationStackEnd - mDepexEvaluationStack); + } + + NewStack = AllocatePool (Size * sizeof(BOOLEAN)); + if (NewStack == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + if (mDepexEvaluationStack != NULL) { + // + // Copy to Old Stack to the New Stack + // + + MemCpy( + NewStack, + mDepexEvaluationStack, + (mDepexEvaluationStackEnd - mDepexEvaluationStack) * sizeof (BOOLEAN) + ); + + // + // Free The Old Stack + // + pBS->FreePool (mDepexEvaluationStack); + } + + // + // Make the Stack pointer point to the old data in the new stack + // + mDepexEvaluationStackPointer = NewStack + (mDepexEvaluationStackPointer - mDepexEvaluationStack); + mDepexEvaluationStack = NewStack; + mDepexEvaluationStackEnd = NewStack + Size; + + return EFI_SUCCESS; +} + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Procedure: PushBool +// +// Description: Push boolean value to stack. +// +// Input: IN BOOLEAN Value +// +// Output: EFI_STATUS +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +EFI_STATUS PushBool(IN BOOLEAN Value) +{ + EFI_STATUS Status; + + // + // Check for a stack overflow condition + // + if (mDepexEvaluationStackPointer == mDepexEvaluationStackEnd) { + // + // Grow the stack + // + Status = GrowDepexStack (); + if (EFI_ERROR (Status)) { + return Status; + } + } + + // + // Push the item onto the stack + // + *mDepexEvaluationStackPointer = Value; + mDepexEvaluationStackPointer++; + + return EFI_SUCCESS; +} + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Procedure: PopBool +// +// Description: Pop boolean value to stack. +// +// Input: OUT BOOLEAN *Value +// +// Output: EFI_STATUS +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +EFI_STATUS PopBool(OUT BOOLEAN *Value) +{ + // + // Check for a stack underflow condition + // + if (mDepexEvaluationStackPointer == mDepexEvaluationStack) { + return EFI_ACCESS_DENIED; + } + + // + // Pop the item off the stack + // + mDepexEvaluationStackPointer--; + *Value = *mDepexEvaluationStackPointer; + return EFI_SUCCESS; +} + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Procedure: SmmIsSchedulable +// +// Description: Check if driver meets dependencies. +// +// Input: IN EFI_SMM_DRIVER_ENTRY *DriverEntry +// +// Output: BOOLEAN +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +BOOLEAN SmmIsSchedulable (IN EFI_SMM_DRIVER_ENTRY *DriverEntry) +{ + EFI_STATUS Status; + UINT8 *Iterator; + BOOLEAN Operator; + BOOLEAN Operator2; + EFI_GUID DriverGuid; + VOID *Interface; + + Operator = FALSE; + Operator2 = FALSE; + + if (DriverEntry->After || DriverEntry->Before) { + // + // If Before or After Depex skip as SmmInsertOnScheduledQueueWhileProcessingBeforeAndAfter () + // processes them. + // + return FALSE; + } + + if (DriverEntry->Depex == NULL) { + // + // A NULL Depex means that the SMM driver is schedulable. + // + //ASSERT (FALSE); + return TRUE; + } + + // + // Clean out memory leaks in Depex Boolean stack. Leaks are only caused by + // incorrectly formed DEPEX expressions + // + mDepexEvaluationStackPointer = mDepexEvaluationStack; + + Iterator = DriverEntry->Depex; + + while (TRUE) { + // + // Check to see if we are attempting to fetch dependency expression instructions + // past the end of the dependency expression. + // + if (((UINTN)Iterator - (UINTN)DriverEntry->Depex) >= DriverEntry->DepexSize) { + return FALSE; + } + + // + // Look at the opcode of the dependency expression instruction. + // + switch (*Iterator) { + case EFI_DEP_BEFORE: + case EFI_DEP_AFTER: + // + // For a well-formed Dependency Expression, the code should never get here. + // The BEFORE and AFTER are processed prior to this routine's invocation. + // If the code flow arrives at this point, there was a BEFORE or AFTER + // that were not the first opcodes. + // + ASSERT (FALSE); + case EFI_DEP_SOR: + // + // These opcodes can only appear once as the first opcode. If it is found + // at any other location, then the dependency expression evaluates to FALSE + // + if (Iterator != DriverEntry->Depex) { + return FALSE; + } + // + // Otherwise, it is the first opcode and should be treated as a NOP. + // + break; + case EFI_DEP_PUSH: + // + // Push operator is followed by a GUID. Test to see if the GUID protocol + // is installed and push the boolean result on the stack. + // + + MemCpy (&DriverGuid, Iterator + 1, sizeof (EFI_GUID)); + + Status = gSmstTable2->SmmLocateProtocol (&DriverGuid, NULL, &Interface); + if (EFI_ERROR (Status)) { + // + // For SMM Driver, it may depend on uefi protocols + // + Status = pBS->LocateProtocol (&DriverGuid, NULL, &Interface); + } + + if (EFI_ERROR (Status)) { + Status = PushBool (FALSE); + } else { + *Iterator = EFI_DEP_REPLACE_TRUE; + Status = PushBool (TRUE); + } + if (EFI_ERROR (Status)) { + return FALSE; + } + + Iterator += sizeof (EFI_GUID); + break; + case EFI_DEP_AND: + Status = PopBool (&Operator); + if (EFI_ERROR (Status)) { + return FALSE; + } + + Status = PopBool (&Operator2); + if (EFI_ERROR (Status)) { + return FALSE; + } + + Status = PushBool ((BOOLEAN)(Operator && Operator2)); + if (EFI_ERROR (Status)) { + return FALSE; + } + break; + case EFI_DEP_OR: + Status = PopBool (&Operator); + if (EFI_ERROR (Status)) { + return FALSE; + } + + Status = PopBool (&Operator2); + if (EFI_ERROR (Status)) { + return FALSE; + } + + Status = PushBool ((BOOLEAN)(Operator || Operator2)); + if (EFI_ERROR (Status)) { + return FALSE; + } + break; + case EFI_DEP_NOT: + Status = PopBool (&Operator); + if (EFI_ERROR (Status)) { + return FALSE; + } + + Status = PushBool ((BOOLEAN)(!Operator)); + if (EFI_ERROR (Status)) { + return FALSE; + } + break; + case EFI_DEP_TRUE: + Status = PushBool (TRUE); + if (EFI_ERROR (Status)) { + return FALSE; + } + break; + case EFI_DEP_FALSE: + Status = PushBool (FALSE); + if (EFI_ERROR (Status)) { + return FALSE; + } + break; + case EFI_DEP_END: + Status = PopBool (&Operator); + if (EFI_ERROR (Status)) { + return FALSE; + } + return Operator; + case EFI_DEP_REPLACE_TRUE: + Status = PushBool (TRUE); + if (EFI_ERROR (Status)) { + return FALSE; + } + + Iterator += sizeof (EFI_GUID); + break; + default: + goto Done; + } + + // + // Skip over the Dependency Op Code we just processed in the switch. + // The math is done out of order, but it should not matter. That is + // we may add in the sizeof (EFI_GUID) before we account for the OP Code. + // This is not an issue, since we just need the correct end result. You + // need to be careful using Iterator in the loop as it's intermediate value + // may be strange. + // + Iterator++; + } + + Done: + return FALSE; +} + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Procedure: EfiInitializeFwVolDevicepathNode +// +// Description: Create Firmware volume device path. +// +// Input: +// IN OUT MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *FvDevicePathNode, +// IN EFI_GUID *NameGuid + +// +// Output: VOID +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +VOID EFIAPI EfiInitializeFwVolDevicepathNode ( + IN OUT MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *FvDevicePathNode, + IN EFI_GUID *NameGuid +) +{ + // + // EFI Specification extension on Media Device Path. MEDIA_FW_VOL_FILEPATH_DEVICE_PATH is adopted by UEFI later and added in UEFI2.10. + // In EdkCompatibility Package, we only support MEDIA_FW_VOL_FILEPATH_DEVICE_PATH that complies with + // EFI 1.10 and UEFI 2.10. + // + + FvDevicePathNode->Header.Type = MEDIA_DEVICE_PATH; + FvDevicePathNode->Header.SubType = MEDIA_FV_FILEPATH_DP; + SetDevicePathNodeLength (&FvDevicePathNode->Header, sizeof (MEDIA_FW_VOL_FILEPATH_DEVICE_PATH)); + + MemCpy (&FvDevicePathNode->NameGuid, NameGuid, sizeof(EFI_GUID)); +} + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Procedure: SmmDisplayDiscoveredNotDispatched +// +// Description: Display to debug output drivers discovered, but not loaded. +// +// Input: VOID +// +// Output: VOID +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +VOID SmmDisplayDiscoveredNotDispatched(VOID) +{ + LIST_ENTRY *Link; + EFI_SMM_DRIVER_ENTRY *DriverEntry; + + for (Link = mDiscoveredList.ForwardLink;Link !=&mDiscoveredList; Link = Link->ForwardLink) { + DriverEntry = CR(Link, EFI_SMM_DRIVER_ENTRY, Link, EFI_SMM_DRIVER_ENTRY_SIGNATURE); + if (DriverEntry->Dependent) { + TRACE ((-1, "SMM Driver %g was discovered but not loaded!!\n", &DriverEntry->FileName)); + } + } +} + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Procedure: FvHasBeenProcessed +// +// Description: +// +// Input: +// +// Output: +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +BOOLEAN FvHasBeenProcessed (IN EFI_HANDLE FvHandle) +{ + LIST_ENTRY *Link; + KNOWN_HANDLE *KnownHandle; + + for (Link = mFvHandleList.ForwardLink; Link != &mFvHandleList; Link = Link->ForwardLink) { + KnownHandle = CR(Link, KNOWN_HANDLE, Link, KNOWN_HANDLE_SIGNATURE); + if (KnownHandle->Handle == FvHandle) { + return TRUE; + } + } + return FALSE; +} + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Procedure: FvIsBeingProcesssed +// +// Description: This firmware volume is marked as being processed. +// +// Input: IN EFI_HANDLE FvHandle +// +// Output: VOID +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +VOID FvIsBeingProcesssed(IN EFI_HANDLE FvHandle) +{ + KNOWN_HANDLE *KnownHandle; + + KnownHandle = AllocatePool (sizeof (KNOWN_HANDLE)); + ASSERT (KnownHandle != NULL); + + KnownHandle->Signature = KNOWN_HANDLE_SIGNATURE; + KnownHandle->Handle = FvHandle; + InsertTailList (&mFvHandleList, &KnownHandle->Link); +} + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Procedure: SmmFvToDevicePath +// +// Description: Create device path for Driver. +// +// Input: +// IN EFI_FIRMWARE_VOLUME2_PROTOCOL *Fv +// IN EFI_HANDLE FvHandle +// IN EFI_GUID *DriverName +// +// Output: EFI_DEVICE_PATH_PROTOCOL * +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +EFI_DEVICE_PATH_PROTOCOL * SmmFvToDevicePath ( + IN EFI_FIRMWARE_VOLUME2_PROTOCOL *Fv, + IN EFI_HANDLE FvHandle, + IN EFI_GUID *DriverName +) +{ + EFI_STATUS Status; + EFI_DEVICE_PATH_PROTOCOL *FvDevicePath; + EFI_DEVICE_PATH_PROTOCOL *FileNameDevicePath; + + // + // Remember the device path of the FV + // + Status = pBS->HandleProtocol(FvHandle, &gEfiDevicePathProtocolGuid, (VOID **)&FvDevicePath); + if (EFI_ERROR (Status)) { + FileNameDevicePath = NULL; + } else { + // + // Build a device path to the file in the FV to pass into gBS->LoadImage + // + EfiInitializeFwVolDevicepathNode (&mFvDevicePath.File, DriverName); + SetDevicePathEndNode (&mFvDevicePath.End); + + // + // Note: FileNameDevicePath is in DXE memory + // + FileNameDevicePath = DPAdd ( + FvDevicePath, + (EFI_DEVICE_PATH_PROTOCOL *)&mFvDevicePath + ); + } + return FileNameDevicePath; +} + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Procedure: SmmPreProcessDepex +// +// Description: Check driver dependencies for SOR, BEFORE, or AFTER, and update DriverEntry. +// +// Input: IN OUT EFI_SMM_DRIVER_ENTRY *DriverEntry +// +// Output: EFI_STATUS +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +EFI_STATUS SmmPreProcessDepex ( + IN OUT EFI_SMM_DRIVER_ENTRY *DriverEntry +) +{ + UINT8 *Iterator; + + Iterator = DriverEntry->Depex; + if (*Iterator == EFI_DEP_SOR) { + DriverEntry->Unrequested = TRUE; + } else { + DriverEntry->Dependent = TRUE; + } + + if (*Iterator == EFI_DEP_BEFORE) { + DriverEntry->Before = TRUE; + } else if (*Iterator == EFI_DEP_AFTER) { + DriverEntry->After = TRUE; + } + + if (DriverEntry->Before || DriverEntry->After) { + MemCpy (&DriverEntry->BeforeAfterGuid, Iterator + 1, sizeof (EFI_GUID)); + } + + return EFI_SUCCESS; +} + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Procedure: SmmGetDepexSectionAndPreProccess +// +// Description: Get driver depex section. +// +// Input: IN OUT EFI_SMM_DRIVER_ENTRY *DriverEntry +// +// Output: EFI_STATUS +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +EFI_STATUS SmmGetDepexSectionAndPreProccess ( + IN OUT EFI_SMM_DRIVER_ENTRY *DriverEntry +) +{ + EFI_STATUS Status; + EFI_SECTION_TYPE SectionType; + UINT32 AuthenticationStatus; + EFI_FIRMWARE_VOLUME2_PROTOCOL *Fv; + + Fv = DriverEntry->Fv; + + // + // Grab Depex info, it will never be free'ed. + // (Note: DriverEntry->Depex is in DXE memory) + // + SectionType = EFI_SECTION_SMM_DEPEX; + Status = Fv->ReadSection ( + DriverEntry->Fv, + &DriverEntry->FileName, + SectionType, + 0, + &DriverEntry->Depex, + (UINTN *)&DriverEntry->DepexSize, + &AuthenticationStatus + ); + if (EFI_ERROR (Status)) { + if (Status == EFI_PROTOCOL_ERROR) { + // + // The section extraction protocol failed so set protocol error flag + // + DriverEntry->DepexProtocolError = TRUE; + } else { + // + // If no Depex assume depend on all architectural protocols + // + DriverEntry->Depex = NULL; + DriverEntry->Dependent = TRUE; + DriverEntry->DepexProtocolError = FALSE; + } + } else { + // + // Set Before, After, and Unrequested state information based on Depex + // Driver will be put in Dependent or Unrequested state + // + SmmPreProcessDepex (DriverEntry); + DriverEntry->DepexProtocolError = FALSE; + } + return Status; +} + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Procedure: SmmAddToDriverList +// +// Description: Add Driver to database for processing. +// +// Input: +// IN EFI_FIRMWARE_VOLUME2_PROTOCOL *Fv +// IN EFI_HANDLE FvHandle +// IN EFI_GUID *DriverName +// +// Output: EFI_STATUS +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +EFI_STATUS SmmAddToDriverList ( + IN EFI_FIRMWARE_VOLUME2_PROTOCOL *Fv, + IN EFI_HANDLE FvHandle, + IN EFI_GUID *DriverName +) +{ + EFI_SMM_DRIVER_ENTRY *DriverEntry; + + // + // Create the Driver Entry for the list. ZeroPool initializes lots of variables to + // NULL or FALSE. + // + DriverEntry = MallocZ(sizeof (EFI_SMM_DRIVER_ENTRY)); + ASSERT (DriverEntry != NULL); + + DriverEntry->Signature = EFI_SMM_DRIVER_ENTRY_SIGNATURE; + MemCpy(&DriverEntry->FileName, DriverName, sizeof(EFI_GUID)); + DriverEntry->FvHandle = FvHandle; + DriverEntry->Fv = Fv; + DriverEntry->FvFileDevicePath = SmmFvToDevicePath (Fv, FvHandle, DriverName); + + SmmGetDepexSectionAndPreProccess (DriverEntry); + + InsertTailList (&mDiscoveredList, &DriverEntry->Link); + gRequestDispatch = TRUE; + + return EFI_SUCCESS; +} + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Procedure: SmmLoadImage +// +// Description: Load driver into memory and give control. +// +// Input: IN OUT EFI_SMM_DRIVER_ENTRY *DriverEntry +// +// Output: EFI_STATUS +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +EFI_STATUS EFIAPI SmmLoadImage ( + IN OUT EFI_SMM_DRIVER_ENTRY *DriverEntry +) +{ + UINT32 AuthenticationStatus; + VOID *Buffer; + UINTN Size; + //UINTN PageCount; + EFI_GUID *NameGuid; + EFI_STATUS Status; + //EFI_HANDLE DeviceHandle; + //EFI_PHYSICAL_ADDRESS DstBuffer; + EFI_DEVICE_PATH_PROTOCOL *FilePath; + EFI_FIRMWARE_VOLUME2_PROTOCOL *Fv; + //PE_COFF_LOADER_IMAGE_CONTEXT ImageContext; + + Buffer = NULL; + Size = 0; + Fv = DriverEntry->Fv; + NameGuid = &DriverEntry->FileName; + FilePath = DriverEntry->FvFileDevicePath; + + AuthenticationStatus = 0; + + // + // Try reading PE32 section firstly + // + Status = Fv->ReadSection ( + Fv, + NameGuid, + EFI_SECTION_PE32, + 0, + &Buffer, + &Size, + &AuthenticationStatus + ); + +/* + if (EFI_ERROR (Status)) { + // + // Try reading TE section secondly + // + Buffer = NULL; + Size = 0; + Status = Fv->ReadSection ( + Fv, + NameGuid, + EFI_SECTION_TE, + 0, + &Buffer, + &Size, + &AuthenticationStatus + ); + } +*/ + + if (EFI_ERROR (Status)) { + if (Buffer != NULL) { + Status = pBS->FreePool (Buffer); + } + return Status; + } + + gRegisterForPi = TRUE; + Status=EfiSmmRegister(NULL, FilePath, Buffer, Size, + &DriverEntry->ImageHandle, FALSE); + gRegisterForPi = FALSE; +/* + // + // Initialize ImageContext + // + ImageContext.Handle = Buffer; + ImageContext.ImageRead = PeCoffLoaderImageReadFromMemory; + + // + // Get information about the image being loaded + // + Status = PeCoffLoaderGetImageInfo (&ImageContext); + if (EFI_ERROR (Status)) { + if (Buffer != NULL) { + Status = gBS->FreePool (Buffer); + } + return Status; + } + // + // if Loading module at Fixed Address feature is enabled, then cut out a memory range started from TESG BASE + // to hold the Smm driver code + // + if (PcdGet64(PcdLoadModuleAtFixAddressEnable) != 0) { + // + // Get the fixed loading address assigned by Build tool + // + Status = GetPeCoffImageFixLoadingAssignedAddress (&ImageContext); + if (!EFI_ERROR (Status)) { + // + // Since the memory range to load Smm core alreay been cut out, so no need to allocate and free this range + // following statements is to bypass SmmFreePages + // + PageCount = 0; + DstBuffer = (UINTN)gLoadModuleAtFixAddressSmramBase; + } else { + DEBUG ((EFI_D_INFO|EFI_D_LOAD, "LOADING MODULE FIXED ERROR: Failed to load module at fixed address. \n")); + // + // allocate the memory to load the SMM driver + // + PageCount = (UINTN)EFI_SIZE_TO_PAGES(ImageContext.ImageSize + ImageContext.SectionAlignment); + DstBuffer = (UINTN)(-1); + + Status = SmmAllocatePages ( + AllocateMaxAddress, + EfiRuntimeServicesCode, + PageCount, + &DstBuffer + ); + if (EFI_ERROR (Status)) { + if (Buffer != NULL) { + Status = gBS->FreePool (Buffer); + } + return Status; + } + ImageContext.ImageAddress = (EFI_PHYSICAL_ADDRESS)DstBuffer; + } + } else { + PageCount = (UINTN)EFI_SIZE_TO_PAGES(ImageContext.ImageSize + ImageContext.SectionAlignment); + DstBuffer = (UINTN)(-1); + + Status = SmmAllocatePages ( + AllocateMaxAddress, + EfiRuntimeServicesCode, + PageCount, + &DstBuffer + ); + if (EFI_ERROR (Status)) { + if (Buffer != NULL) { + Status = gBS->FreePool (Buffer); + } + return Status; + } + + ImageContext.ImageAddress = (EFI_PHYSICAL_ADDRESS)DstBuffer; + } + // + // Align buffer on section boundary + // + ImageContext.ImageAddress += ImageContext.SectionAlignment - 1; + ImageContext.ImageAddress &= ~(ImageContext.SectionAlignment - 1); + + // + // Load the image to our new buffer + // + Status = PeCoffLoaderLoadImage (&ImageContext); + if (EFI_ERROR (Status)) { + if (Buffer != NULL) { + Status = gBS->FreePool (Buffer); + } + SmmFreePages (DstBuffer, PageCount); + return Status; + } + + // + // Relocate the image in our new buffer + // + Status = PeCoffLoaderRelocateImage (&ImageContext); + if (EFI_ERROR (Status)) { + if (Buffer != NULL) { + Status = gBS->FreePool (Buffer); + } + SmmFreePages (DstBuffer, PageCount); + return Status; + } + + // + // Flush the instruction cache so the image data are written before we execute it + // + InvalidateInstructionCacheRange ((VOID *)(UINTN) ImageContext.ImageAddress, (UINTN) ImageContext.ImageSize); + + // + // Save Image EntryPoint in DriverEntry + // + DriverEntry->ImageEntryPoint = ImageContext.EntryPoint; + DriverEntry->ImageBuffer = DstBuffer; + DriverEntry->NumberOfPage = PageCount; + + // + // Allocate a Loaded Image Protocol in EfiBootServicesData + // + Status = gBS->AllocatePool (EfiBootServicesData, sizeof (EFI_LOADED_IMAGE_PROTOCOL), (VOID **)&DriverEntry->LoadedImage); + if (EFI_ERROR (Status)) { + if (Buffer != NULL) { + Status = gBS->FreePool (Buffer); + } + SmmFreePages (DstBuffer, PageCount); + return Status; + } + + // + // Fill in the remaining fields of the Loaded Image Protocol instance. + // Note: ImageBase is an SMRAM address that can not be accessed outside of SMRAM if SMRAM window is closed. + // + DriverEntry->LoadedImage->Revision = EFI_LOADED_IMAGE_PROTOCOL_REVISION; + DriverEntry->LoadedImage->ParentHandle = gThisImageHandle; + DriverEntry->LoadedImage->SystemTable = pST; + DriverEntry->LoadedImage->DeviceHandle = DeviceHandle; + + // + // Make an EfiBootServicesData buffer copy of FilePath + // + Status = gBS->AllocatePool (EfiBootServicesData, GetDevicePathSize (FilePath), (VOID **)&DriverEntry->LoadedImage->FilePath); + if (EFI_ERROR (Status)) { + if (Buffer != NULL) { + Status = gBS->FreePool (Buffer); + } + SmmFreePages (DstBuffer, PageCount); + return Status; + } + CopyMem (DriverEntry->LoadedImage->FilePath, FilePath, GetDevicePathSize (FilePath)); + + DriverEntry->LoadedImage->ImageBase = (VOID *)(UINTN)DriverEntry->ImageBuffer; + DriverEntry->LoadedImage->ImageSize = ImageContext.ImageSize; + DriverEntry->LoadedImage->ImageCodeType = EfiRuntimeServicesCode; + DriverEntry->LoadedImage->ImageDataType = EfiRuntimeServicesData; + + // + // Create a new image handle in the UEFI handle database for the SMM Driver + // + DriverEntry->ImageHandle = NULL; + Status = gBS->InstallMultipleProtocolInterfaces ( + &DriverEntry->ImageHandle, + &gEfiLoadedImageProtocolGuid, DriverEntry->LoadedImage, + NULL + ); + + // + // Print the load address and the PDB file name if it is available + // + + // DEBUG_CODE_BEGIN (); +#if EFI_DEBUG + { + UINTN Index; + UINTN StartIndex; + CHAR8 EfiFileName[256]; + + + TRACE ((-1, + "Loading driver at 0x%11p EntryPoint=0x%11p ", + (VOID *)(UINTN) ImageContext.ImageAddress, + FUNCTION_ENTRY_POINT (ImageContext.EntryPoint))); + + + // + // Print Module Name by Pdb file path. + // Windows and Unix style file path are all trimmed correctly. + // + if (ImageContext.PdbPointer != NULL) { + StartIndex = 0; + for (Index = 0; ImageContext.PdbPointer[Index] != 0; Index++) { + if ((ImageContext.PdbPointer[Index] == '\\') || (ImageContext.PdbPointer[Index] == '/')) { + StartIndex = Index + 1; + } + } + // + // Copy the PDB file name to our temporary string, and replace .pdb with .efi + // The PDB file name is limited in the range of 0~255. + // If the length is bigger than 255, trim the redudant characters to avoid overflow in array boundary. + // + for (Index = 0; Index < sizeof (EfiFileName) - 4; Index++) { + EfiFileName[Index] = ImageContext.PdbPointer[Index + StartIndex]; + if (EfiFileName[Index] == 0) { + EfiFileName[Index] = '.'; + } + if (EfiFileName[Index] == '.') { + EfiFileName[Index + 1] = 'e'; + EfiFileName[Index + 2] = 'f'; + EfiFileName[Index + 3] = 'i'; + EfiFileName[Index + 4] = 0; + break; + } + } + + if (Index == sizeof (EfiFileName) - 4) { + EfiFileName[Index] = 0; + } + TRACE ((-1, "%a", EfiFileName)); // &Image->ImageContext.PdbPointer[StartIndex])); + } + TRACE ((-1, "\n")); + } +// DEBUG_CODE_END (); +#endif + + // + // Free buffer allocated by Fv->ReadSection. + // + // The UEFI Boot Services FreePool() function must be used because Fv->ReadSection + // used the UEFI Boot Services AllocatePool() function + // +*/ + Status = pBS->FreePool(Buffer); + return Status; +} + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Procedure: SmmInsertOnScheduledQueueWhileProcessingBeforeAndAfter +// +// Description: Add drivers on queue with before or after dependencies. +// +// Input: IN EFI_SMM_DRIVER_ENTRY *InsertedDriverEntry +// +// Output: VOID +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +VOID SmmInsertOnScheduledQueueWhileProcessingBeforeAndAfter ( + IN EFI_SMM_DRIVER_ENTRY *InsertedDriverEntry +) +{ + LIST_ENTRY *Link; + EFI_SMM_DRIVER_ENTRY *DriverEntry; + + // + // Process Before Dependency + // + for (Link = mDiscoveredList.ForwardLink; Link != &mDiscoveredList; Link = Link->ForwardLink) { + DriverEntry = CR(Link, EFI_SMM_DRIVER_ENTRY, Link, EFI_SMM_DRIVER_ENTRY_SIGNATURE); + if (DriverEntry->Before && DriverEntry->Dependent) { + if (! guidcmp (&InsertedDriverEntry->FileName, &DriverEntry->BeforeAfterGuid)) { + // + // Recursively process BEFORE + // + SmmInsertOnScheduledQueueWhileProcessingBeforeAndAfter (DriverEntry); + } + } + } + + // + // Convert driver from Dependent to Scheduled state + // + + InsertedDriverEntry->Dependent = FALSE; + InsertedDriverEntry->Scheduled = TRUE; + InsertTailList (&mScheduledQueue, &InsertedDriverEntry->ScheduledLink); + + // + // Process After Dependency + // + for (Link = mDiscoveredList.ForwardLink; Link != &mDiscoveredList; Link = Link->ForwardLink) { + DriverEntry = CR(Link, EFI_SMM_DRIVER_ENTRY, Link, EFI_SMM_DRIVER_ENTRY_SIGNATURE); + if (DriverEntry->After && DriverEntry->Dependent) { + if (!guidcmp (&InsertedDriverEntry->FileName, &DriverEntry->BeforeAfterGuid)) { + // + // Recursively process AFTER + // + SmmInsertOnScheduledQueueWhileProcessingBeforeAndAfter (DriverEntry); + } + } + } +} + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Procedure: SmmDispatcher +// +// Description: Dispatch drivers that dependencies are met. +// +// Input: VOID +// +// Output: VOID +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +EFI_STATUS SmmDispatcher(VOID) +{ + EFI_STATUS Status; + EFI_STATUS ReturnStatus; + LIST_ENTRY *Link; + EFI_SMM_DRIVER_ENTRY *DriverEntry; + BOOLEAN ReadyToRun; + + if (!gRequestDispatch) { + return EFI_NOT_FOUND; + } + + if (gDispatcherRunning) { + // + // If the dispatcher is running don't let it be restarted. + // + return EFI_ALREADY_STARTED; + } + + gDispatcherRunning = TRUE; + ReturnStatus = EFI_NOT_FOUND; + + do { + // + // Drain the Scheduled Queue + // + while (!IsListEmpty (&mScheduledQueue)) { + DriverEntry = CR ( + mScheduledQueue.ForwardLink, + EFI_SMM_DRIVER_ENTRY, + ScheduledLink, + EFI_SMM_DRIVER_ENTRY_SIGNATURE + ); + + // + // Load the SMM Driver image into memory. If the Driver was transitioned from + // Untrusted to Scheduled it would have already been loaded so we may need to + // skip the LoadImage + // + if (DriverEntry->ImageHandle == NULL) { + Status = SmmLoadImage (DriverEntry); + + // + // Update the driver state to reflect that it's been loaded + // + if (EFI_ERROR (Status)) { + if (Status == EFI_SECURITY_VIOLATION) { + // + // Take driver from Scheduled to Untrusted state + // + DriverEntry->Untrusted = TRUE; + } else { + // + // The SMM Driver could not be loaded, and do not attempt to load or start it again. + // Take driver from Scheduled to Initialized. + // + // This case include the Never Trusted state if EFI_ACCESS_DENIED is returned + // + DriverEntry->Initialized = TRUE; + } + + DriverEntry->Scheduled = FALSE; + RemoveEntryList (&DriverEntry->ScheduledLink); + + // + // If it's an error don't try the StartImage + // + continue; + } + } + + DriverEntry->Scheduled = FALSE; + DriverEntry->Initialized = TRUE; + RemoveEntryList (&DriverEntry->ScheduledLink); +/* + REPORT_STATUS_CODE_WITH_EXTENDED_DATA ( + EFI_PROGRESS_CODE, + EFI_SOFTWARE_SMM_DRIVER | EFI_SW_PC_INIT_BEGIN, + &DriverEntry->ImageHandle, + sizeof(DriverEntry->ImageHandle) + ); + + // + // For each SMM driver, pass NULL as ImageHandle + // + Status = ((EFI_IMAGE_ENTRY_POINT)(UINTN)DriverEntry->ImageEntryPoint)(DriverEntry->ImageHandle, pST); + if (EFI_ERROR(Status)){ + SmmFreePages(DriverEntry->ImageBuffer, DriverEntry->NumberOfPage); + } + + REPORT_STATUS_CODE_WITH_EXTENDED_DATA ( + EFI_PROGRESS_CODE, + EFI_SOFTWARE_SMM_DRIVER | EFI_SW_PC_INIT_END, + &DriverEntry->ImageHandle, + sizeof(DriverEntry->ImageHandle) + ); +*/ + ReturnStatus = EFI_SUCCESS; + } + + // + // Search DriverList for items to place on Scheduled Queue + // + ReadyToRun = FALSE; + for (Link = mDiscoveredList.ForwardLink; Link != &mDiscoveredList; Link = Link->ForwardLink) { + DriverEntry = CR (Link, EFI_SMM_DRIVER_ENTRY, Link, EFI_SMM_DRIVER_ENTRY_SIGNATURE); + + if (DriverEntry->DepexProtocolError){ + // + // If Section Extraction Protocol did not let the Depex be read before retry the read + // + Status = SmmGetDepexSectionAndPreProccess (DriverEntry); + } + + if (DriverEntry->Dependent) { + if (SmmIsSchedulable (DriverEntry)) { + SmmInsertOnScheduledQueueWhileProcessingBeforeAndAfter (DriverEntry); + ReadyToRun = TRUE; + } + } + } + } while (ReadyToRun); + + // + // If there is no more SMM driver to dispatch, stop the dispatch request + // + gRequestDispatch = FALSE; + for (Link = mDiscoveredList.ForwardLink; Link != &mDiscoveredList; Link = Link->ForwardLink) { + DriverEntry = CR (Link, EFI_SMM_DRIVER_ENTRY, Link, EFI_SMM_DRIVER_ENTRY_SIGNATURE); + + if (!DriverEntry->Initialized){ + // + // We have SMM driver pending to dispatch + // + gRequestDispatch = TRUE; + break; + } + } + + gDispatcherRunning = FALSE; + + return ReturnStatus; +} + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Procedure: SmmDriverDispatchHandler +// +// Description: Dispatch SMM drivers +// +// Input: VOID +// +// Output: VOID +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +VOID SmmDriverDispatchHandler () +{ + EFI_STATUS Status; + UINTN HandleCount; + EFI_HANDLE *HandleBuffer; + EFI_STATUS GetNextFileStatus; + EFI_STATUS SecurityStatus; + EFI_FIRMWARE_VOLUME2_PROTOCOL *Fv; + EFI_DEVICE_PATH_PROTOCOL *FvDevicePath; + EFI_HANDLE FvHandle; + EFI_GUID NameGuid; + UINTN Key; + EFI_FV_FILETYPE Type; + EFI_FV_FILE_ATTRIBUTES Attributes; + UINTN Size; + EFI_SMM_DRIVER_ENTRY *DriverEntry; + EFI_GUID *AprioriFile; + UINTN AprioriEntryCount; + UINTN Index; + LIST_ENTRY *Link; + UINT32 AuthenticationStatus; + UINTN SizeOfBuffer; + + HandleBuffer = NULL; + Status = pBS->LocateHandleBuffer ( + ByProtocol, + &gEfiFirmwareVolume2ProtocolGuid, + NULL, + &HandleCount, + &HandleBuffer + ); + if (EFI_ERROR (Status)) return; //return EFI_NOT_FOUND; + + for (Index = 0; Index < HandleCount; Index++) { + FvHandle = HandleBuffer[Index]; + + if (FvHasBeenProcessed (FvHandle)) { + // + // This Fv has already been processed so lets skip it! + // + continue; + } + + // + // Since we are about to process this Fv mark it as processed. + // + FvIsBeingProcesssed (FvHandle); + + Status = pBS->HandleProtocol (FvHandle, &gEfiFirmwareVolume2ProtocolGuid, (VOID **)&Fv); + if (EFI_ERROR (Status)) { + // + // FvHandle must have a Firmware Volume2 Protocol thus we should never get here. + // + ASSERT (FALSE); + continue; + } + + Status = pBS->HandleProtocol (FvHandle, &gEfiDevicePathProtocolGuid, (VOID **)&FvDevicePath); + if (EFI_ERROR (Status)) { + // + // The Firmware volume doesn't have device path, can't be dispatched. + // + continue; + } + + // + // If the Security Architectural Protocol has not been located yet, then attempt to locate it + // + if (mSecurity == NULL) { + pBS->LocateProtocol (&gEfiSecurityArchProtocolGuid, NULL, (VOID**)&mSecurity); + } + + // + // Evaluate the authentication status of the Firmware Volume through + // Security Architectural Protocol + // + if (mSecurity != NULL) { + SecurityStatus = mSecurity->FileAuthenticationState ( + mSecurity, + 0, + FvDevicePath + ); + if (SecurityStatus != EFI_SUCCESS) { + // + // Security check failed. The firmware volume should not be used for any purpose. + // + continue; + } + } + + // + // Discover Drivers in FV and add them to the Discovered Driver List. + // Process EFI_FV_FILETYPE_SMM type and then EFI_FV_FILETYPE_COMBINED_SMM_DXE + // + for (Index = 0; Index < sizeof (mSmmFileTypes)/sizeof (EFI_FV_FILETYPE); Index++) { + // + // Initialize the search key + // + Key = 0; + do { + Type = mSmmFileTypes[Index]; + GetNextFileStatus = Fv->GetNextFile ( + Fv, + &Key, + &Type, + &NameGuid, + &Attributes, + &Size + ); + if (!EFI_ERROR (GetNextFileStatus)) { + SmmAddToDriverList (Fv, FvHandle, &NameGuid); + } + } while (!EFI_ERROR (GetNextFileStatus)); + } + + // + // Read the array of GUIDs from the Apriori file if it is present in the firmware volume + // (Note: AprioriFile is in DXE memory) + // + AprioriFile = NULL; + Status = Fv->ReadSection ( + Fv, + &gAprioriGuid, + EFI_SECTION_RAW, + 0, + (VOID **)&AprioriFile, + &SizeOfBuffer, + &AuthenticationStatus + ); + if (!EFI_ERROR (Status)) { + AprioriEntryCount = SizeOfBuffer / sizeof (EFI_GUID); + } else { + AprioriEntryCount = 0; + } + + // + // Put drivers on Apriori List on the Scheduled queue. The Discovered List includes + // drivers not in the current FV and these must be skipped since the a priori list + // is only valid for the FV that it resided in. + // + + for (Index = 0; Index < AprioriEntryCount; Index++) { + for (Link = mDiscoveredList.ForwardLink; Link != &mDiscoveredList; Link = Link->ForwardLink) { + DriverEntry = CR(Link, EFI_SMM_DRIVER_ENTRY, Link, EFI_SMM_DRIVER_ENTRY_SIGNATURE); + if (!guidcmp (&DriverEntry->FileName, &AprioriFile[Index]) && + (FvHandle == DriverEntry->FvHandle) + ){ + DriverEntry->Dependent = FALSE; + DriverEntry->Scheduled = TRUE; + InsertTailList (&mScheduledQueue, &DriverEntry->ScheduledLink); + break; + } + } + } + + // + // Free data allocated by Fv->ReadSection () + // + // The UEFI Boot Services FreePool() function must be used because Fv->ReadSection + // used the UEFI Boot Services AllocatePool() function + // + pBS->FreePool (AprioriFile); + } + + // + // Execute the SMM Dispatcher on any newly discovered FVs and previously + // discovered SMM drivers that have been discovered but not dispatched. + // + SmmDispatcher(); +} +#endif + +//************************************************************************* +//************************************************************************* +//** ** +//** (C)Copyright 1985-2011, American Megatrends, Inc. ** +//** ** +//** All Rights Reserved. ** +//** ** +//** 5555 Oakbrook Parkway, Suite 200, Norcross, GA 30093 ** +//** ** +//** Phone: (770)-246-8600 ** +//** ** +//************************************************************************* +//************************************************************************* diff --git a/Core/EM/SMM/SmmDxeCommunicate.dxs b/Core/EM/SMM/SmmDxeCommunicate.dxs new file mode 100644 index 0000000..24f46a0 --- /dev/null +++ b/Core/EM/SMM/SmmDxeCommunicate.dxs @@ -0,0 +1,69 @@ +//************************************************************************* +//************************************************************************* +//** ** +//** (C)Copyright 1985-2011, American Megatrends, Inc. ** +//** ** +//** All Rights Reserved. ** +//** ** +//** 5555 Oakbrook Parkway, Suite 200, Norcross, GA 30093 ** +//** ** +//** Phone: (770)-246-8600 ** +//** ** +//************************************************************************* +//************************************************************************* + +//********************************************************************** +// $Header: /Alaska/SOURCE/Modules/SMM/SmmCommunicate/SmmDxeCommunicate.dxs 1 4/18/11 12:03p Markw $ +// +// $Revision: 1 $ +// +// $Date: 4/18/11 12:03p $ +//********************************************************************** +// Revision History +// ---------------- +// $Log: /Alaska/SOURCE/Modules/SMM/SmmCommunicate/SmmDxeCommunicate.dxs $ +// +// 1 4/18/11 12:03p Markw +// [TAG] EIP57440 +// [Category] New Feature +// [Description] Add SMM PI 1.1 Communicate Support. +// [Files] SmmCommunicate.cif +// SmmCommunicate.sdl +// SmmCommunicate.c +// SmmCommunicate.dxs +// SmmDxeCommunicate.dxs +// SmmCommunicate.mak +// +//********************************************************************** + +//<AMI_FHDR_START> +//--------------------------------------------------------------------------- +// +// Name: SmmCommunicate.dxs +// +// Description: Dependency file for the SMM Communicate driver +// +//--------------------------------------------------------------------------- +//<AMI_FHDR_END> + +#include <Protocol\SmmBase2.h> +#include <Protocol\AmiInternalSmmComm.h> + +DEPENDENCY_START + EFI_SMM_BASE2_PROTOCOL_GUID AND + AMI_INT_SMM_COMM_PROTOCOL_GUID +DEPENDENCY_END + +//************************************************************************* +//************************************************************************* +//** ** +//** (C)Copyright 1985-2011, American Megatrends, Inc. ** +//** ** +//** All Rights Reserved. ** +//** ** +//** 5555 Oakbrook Parkway, Suite 200, Norcross, GA 30093 ** +//** ** +//** Phone: (770)-246-8600 ** +//** ** +//************************************************************************* +//************************************************************************* diff --git a/Core/EM/SMM/SmmEntry.asm b/Core/EM/SMM/SmmEntry.asm new file mode 100644 index 0000000..883d1c6 --- /dev/null +++ b/Core/EM/SMM/SmmEntry.asm @@ -0,0 +1,1041 @@ +;************************************************************************* +;************************************************************************* +;** ** +;** (C)Copyright 1985-2008, 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/SmmEntry.asm 2 10/31/12 10:26a Wesleychen $ +; +; $Revision: 2 $ +; +; $Date: 10/31/12 10:26a $ +;********************************************************************** +; Revision History +; ---------------- +; $Log: /Alaska/Projects/Intel/Haswell/LynxPoint_SharkBay-DT_Crb_1AQQW/Core/EM/SMM/SmmEntry.asm $ +; +; 2 10/31/12 10:26a Wesleychen +; Update SMM to 4.6.3_SMM_46. +; +; 1 10/22/12 7:08a Wesleychen +; Support Intel PFAT. +; +; 58 4/01/11 10:33a 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, SmmPrivateShared.h, +; SmmHdr.equ, SmmInit.c, SmmEntry.asm +; +; 57 11/23/09 11:20a Markw +; Update fxsave and fxrstor for 64-bit. +; +; 56 8/11/09 11:49a Markw +; Removed Legacy registration. This is removed from latest PI and not +; used by projects. Also, update clearing upper 32-bits of 64-bit +; registers. +; +; 55 7/08/09 8:13p Markw +; Update headers. +; +; 54 5/12/09 7:02p Markw +; EIP #22087 - Always reinialize IDT in SMM even with AMI Debugger. Some +; processors place junk value in IDT. +; +; 53 12/23/08 2:18p Markw +; EIP #17900 Set up TSS. Borland C in DOS hangs otherwise. +; +; 52 11/21/08 4:57p Markw +; Add SmmInit into SMM_ENTRY_STRUCT. +; +; 51 9/07/08 12:51a Markw +; +; 50 9/07/08 12:43a Markw +; Separate SMM Private structure into inside SMM and outside SMM +; structure. +; +; 49 8/27/08 9:05p Markw +; Nehalem SMRR is now WB. Fix SMM Thunk Stack bug. +; +; 48 5/23/08 11:14a Markw +; Don't load idt if AMI Debugger. Debugger won't work in SMM if idt is +; reloaded. +; +; 47 4/04/08 6:22p Markw +; User Smm Msr from SMM_BASE_PRIVATE_STRUCT instead of token. +; +; 46 3/03/08 6:36p Markw +; Added 32-bit register for smm thunk. +; +; 45 1/07/08 1:58p Markw +; For SMM thunk, read cs in 16-bit real mode instead of undefined CPU +; execution between real and protected mode. +; cs was invalid when read. +; +; 44 11/26/07 6:00p Markw +; Fix bug in previous bug fix. +; +; 43 11/26/07 5:51p Markw +; Fix smm thunk bug - store return address. +; +; 42 11/21/07 3:38p Markw +; Update checking MKF_SMM_THUNK_IN_CSM condition from 1 to -1. +; +; 41 11/14/07 2:02p Markw +; Added SMRR support and updated SMM Cache for non-SMRR. +; +; 40 10/29/07 3:24p Markw +; +; 39 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. +; +; 38 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. +; +; 37 9/10/07 1:39p Markw +; Add Interrupt Handling in SMM. +; +; 36 6/14/07 10:54a Markw +; In SmmThunk, jump condition is incorrect. pushf wasn't occurring before +; iret call. +; +; 35 6/08/07 6:51p Markw +; Save/Restore XMM. +; +; 34 4/13/07 11:04a Markw +; Update header. +; +; 33 3/22/07 5:37p Markw +; Set stack before calling legacy_handler. +; +; 32 3/12/07 11:24a Markw +; Enable XMM for 32-bit. Guarantee 16-byte stack alignment. +; +; 31 3/06/07 10:40a Markw +; Fix legacy handler calling entry point. +; +; 30 2/08/07 10:49a Markw +; Preserve stack on legacy_handler. +; +; 29 1/11/07 12:31p Markw +; Use switch to enable/disable legacy code during build. +; +; 28 1/10/07 2:12p Markw +; Move legacy only code to end. Otherwise, if 64-bit BSP entry in TSEG, +; APs will overlap part of smm bsp entry code. +; +; 27 1/09/07 6:47p Markw +; Store fixup addresses in SmmEntry for locations that have to fixed-up +; during BIOS. +; +; 26 1/09/07 11:47a Markw +; Removed using MKF_SMM_BSP_BASE in memory access and segment changes. +; Uses indexing or retf. +; +; 25 12/29/06 4:46p Markw +; Update CPU syncronization. +; +; 24 12/11/06 5:53p Markw +; Commented out initializing the flags because of potentional errors, and +; using flags as input would be unusual. +; +; 23 11/13/06 7:15p Markw +; Combine more common code between 32 and 64 bit. +; +; 22 11/10/06 3:18p Markw +; Combined x32 and x64 where it is the same. +; +; 21 10/17/06 11:23a Davidd +; Change made to not setting the Page Global Enable bit in CR4 to correct +; the system reset problem when installing / booting Vista 32. +; +; 20 9/22/06 6:07p Markw +; In 32-bit fix stack after calling dispatcher. +; +; 19 9/18/06 3:21p Markw +; Updated 32 bit part for BSP an AP sync. +; +; 18 9/18/06 11:44a Markw +; Add a check to guarentee that BSP and Ap can't get out of sync. Also +; clear WT bit in cr0 in 64-bit. +; +; 17 8/25/06 10:49a Markw +; Enable XMM for 64-bit. +; +; 16 8/24/06 3:28p Felixp +; Preliminary x64 support (work in progress) +; +; 15 4/20/06 1:50p Markw +; Fixed SmmThunk to use token for BSP SMM Base. +; For SmmThunk calls that don't pass arguments on stack, added 3f to +; emulate INT calls. +; +; 14 2/03/06 10:27a Markw +; Moved Smm Base change to PEI CPU. +; Added a token for SMM BSP Base Address. +; Added IED support. +; +; 13 1/13/06 11:28a Markw +; Added SMM Thunk support. +; +; 12 1/10/06 2:57p Markw +; Add support for multi-threadding and sync all CPUs during entry/exit of +; SMM. +; +; 11 11/03/05 5:35p Markw +; Added entries to GDT for addional descriptors that Intel uses. +; +; 10 7/21/05 11:28a Srinin +; Fixed Legacy SMI handler support. +; +; 8 7/19/05 8:00p Markw +; Add support for calling real mode handlers. +; +; 7 7/12/05 3:14p Markw +; Moved BSP entry from 0xa8000 to 0xa0000. +; +; 6 7/11/05 12:04p Markw +; Removed setting isCallback. This simplified the dispatcher. +; +; 5 7/06/05 2:15p Markw +; Commented out unused code. +; +; 4 4/07/05 4:05p Sivagarn +; Corrected the make token issue +; +; 3 4/04/05 5:18p Sivagarn +; Converted hard coded S/W SMI port to generic SDL token +; +; 1 1/28/05 4:32p Sivagarn +; SMM Dispatcher Component - Initial check in +; +; +;********************************************************************** + +;<AMI_FHDR_START> +;---------------------------------------------------------------------------- +; +; Name: SmmEntry.ASM +; +; Description: File that contains the code for BSP SMM entry point +; +;---------------------------------------------------------------------------- +;<AMI_FHDR_END> + +.586p +.model small +.xmm + +include token.equ +include SmmHdr.equ + +IFNDEF MKF_SMM_THUNK_IN_CSM +MKF_SMM_THUNK_IN_CSM EQU 0 +ENDIF + +IFNDEF MKF_AMI_DEBUGGER_SUPPORT +MKF_AMI_DEBUGGER_SUPPORT EQU 0 +ENDIF + +IA32_HANDLER_LIST STRUCT + Entry dd ? + Link dd ? +IA32_HANDLER_LIST ENDS + +;org 8000h +SMM SEGMENT USE16 + +;<AMI_PHDR_START> +;---------------------------------------------------------------------------- +; +; Procedure: SmmEntry +; +; Description: Call any Legacy Handlers and call 32 bit protected Mode Dispatcher. +; +; Input: None +; +; Output: None +; +;---------------------------------------------------------------------------- +;<AMI_PHDR_END> + +;To make assembler happy. +; SmmThunkData will have an address of 0, but a different segment. +SmmThunkData equ $ +SmmEntry: + jmp SmmStart +align 4 +SmmEntryData label dword + SmmEntryInit SMM_ENTRY_INIT_STRUCT < \ + 1, \ + SmmEntryEnd - SmmEntry, \ + GDT_DESC_FIXUP - SmmEntry, \ + L_CODE_SEL_FIXUP - SmmEntry, \ + TSS_SEL_FIXUP - SmmEntry, \ + THUNK - SmmEntry, \ + SmmThunkEnd - THUNK, \ + -1 \ + > +SmmStart: +;Note use cs override on data access. This code may be executed above 1MB. + mov ax, cs + mov ds, ax + mov ss, ax + cld + +IF MKF_SMM_CACHE_SUPPORT +IFNDEF MKF_NEHALEM_CPU_MODULE + ; *************** CACHE ENABLE ************** +;----------- +;HT support +;----------- + ;TODO: Move HT detection to SMM Base and out of SMM entry. + + mov eax, -1 + cmp cs:(SMM_ENTRY_INIT_STRUCT ptr [SmmEntryInit + 8000h]).Ht0, eax + jne ht0_flag_is_init + + mov eax, 1 ;default true + mov cs:(SMM_ENTRY_INIT_STRUCT ptr [SmmEntryInit + 8000h]).Ht0, eax + + mov eax, 1 + cpuid + test edx, 1 SHL 28 ;Set if hyper-threading support. + jz ht0_flag_is_init + shr ebx, 16 ;After shift, bl = number of logical processors + movzx esi, bl ;Store # local processors. + + mov eax, 4 + xor ecx, ecx + cpuid + shr eax, 26 + inc eax ;Number of Cores. + + xor edx, edx ;clear for div. + xchg esi, eax ;esi = NumCores, eax = num #logical CPUS + div esi ;#logical CPUs / NumCores + cmp eax, 1 + jle ht0_flag_is_init + + mov ebx, MKF_LOCAL_APIC_BASE + MKF_APIC_ID_REGISTER + mov eax, es:[ebx] + bt eax, 24 + jnc ht0_flag_is_init + xor eax, eax ;This not Ht0 flag, so clear. + mov cs:(SMM_ENTRY_INIT_STRUCT ptr [SmmEntryInit + 8000h]).Ht0, eax +ht0_flag_is_init: + + mov esi, dword ptr cs:(SMM_ENTRY_INIT_STRUCT ptr [SmmEntryInit + 8000h]).SmmDispatcherPrivateStruct + + mov eax, cs:(SMM_ENTRY_INIT_STRUCT ptr [SmmEntryInit + 8000h]).Ht0 + or eax, eax + jz cache_enable_end ;skip if HT + + mov al, 1 + cmp es:(SMM_DISPATCHER_PRIVATE_STRUCT ptr [esi]).SmrrEnable, al + jne non_smrr_cache + ;Disable SMRR. + mov ecx, es:(SMM_DISPATCHER_PRIVATE_STRUCT ptr [esi]).SmrrMsr + inc ecx + rdmsr + btr ax, 11 ;Disable UC SMRR. This makes the region WT by overlapping MTRR. + wrmsr + jmp cache_enable_end + +non_smrr_cache: + mov ecx, es:(SMM_DISPATCHER_PRIVATE_STRUCT ptr [esi]).TsegMsr + or ecx, ecx + jz cache_enable_end ;Not enough/or moved MTRR to support cache. + + rdmsr + cmp eax, dword ptr es:(SMM_DISPATCHER_PRIVATE_STRUCT ptr [esi]).TsegMsrBase + je @f + ;---Disable future cache. Validation failed. + xor ecx, ecx + mov es:(SMM_DISPATCHER_PRIVATE_STRUCT ptr [esi]).TsegMsr, ecx + jmp cache_enable_end +@@: + mov al, 4 + wrmsr ;Make MTRR WT. +;----------------- +cache_enable_end: +; ************** END CACHE ENABLE ************* +ENDIF +ENDIF + +IFDEF MKF_PfatServices_SUPPORT +IF MKF_PfatServices_SUPPORT + mov eax, cr0 + or al, 20h ;Set NE bit + mov cr0, eax +ENDIF +ENDIF + + mov esi, dword ptr cs:(SMM_ENTRY_INIT_STRUCT ptr [SmmEntryInit + 8000h]).SmmDispatcherPrivateStruct + mov edi, dword ptr cs:(SMM_ENTRY_INIT_STRUCT ptr [SmmEntryInit + 8000h]).SmmEntryStart + mov ebx, dword ptr cs:(SMM_ENTRY_INIT_STRUCT ptr [SmmEntryInit + 8000h]).SmmDispatcherAddr + mov edx, dword ptr cs:(SMM_ENTRY_INIT_STRUCT ptr [SmmEntryInit + 8000h]).CpuNo + + mov byte ptr cs:TSS_SEL_FIXUP + 8000h + 3, 89h + + ;Switch to protected mode + db 66h + lgdt fword ptr cs:GdtDescriptor + 8000h + mov eax, cr0 + or al, 1 ;Set PE bit + mov cr0, eax ;Turn on Protected Mode + + ;In 16 bit protected mode + jmp $+2 ;Clear prefetch queue + + mov ax, DATA_SEL + mov ds, ax + mov es, ax + mov ss, ax + mov fs, ax + mov gs, ax + + xor ax, ax + lldt ax + + str ax + or ax, ax + jz @f + mov ax,TSS_SEL + ltr ax +@@: + + ;Stack starts near bottom of Smm TSEG after BSP/AP entries + mov esp, dword ptr cs:(SMM_ENTRY_INIT_STRUCT ptr [SmmEntryInit + 8000h]).SmmStack + and esp, 0fffffff0h ;guarentee 16-byte stack. + + ;set cs segment + lea eax, [edi + offset P32Mode] + pushd CODE32_SEL + push eax + db 66h + retf +P32Mode:: + mov eax, cr4 + ;or eax, 0620h ;Enable XMM. + db 0dh + dd 0600h + mov cr4, eax + + ;mov eax, dword ptr (SMM_DISPATCHER_PRIVATE_STRUCT ptr [esi]).SmmXmmSave + db 8bh, 46h, SMM_DISPATCHER_PRIVATE_STRUCT.SmmXmmSave +IFNDEF EFIx64 + ;mov edx, [eax + 4 * edx] + db 8bh, 14h, 90h +ELSE + ;mov edx, [eax + 8 * edx] + db 8bh, 14h, 0d0h +ENDIF + +IFNDEF EFIx64 + ;lidt fword ptr (SMM_DISPATCHER_PRIVATE_STRUCT ptr [esi]).Idt + db 0fh, 1, 5eh + db SMM_DISPATCHER_PRIVATE_STRUCT.IDT + + ;fxsave [edx] + db 0fh, 0aeh, 2 + push dx ;push edx + sub sp, 12 ;sub esp, 12 -- make stack 16 byte aligned + ;Call Dispatcher + + add di, 4 ;edi = SmmEntryInit + push di ;push edi ;Optimization will modify this stack location. + call bx ;call ebx ;SmmDispatcherAddr + add sp, 12 + 4 ;add esp, 12 + 4 + pop dx ;pop edx + ;fxrstor [edx] + db 0fh, 0aeh, 0ah +ELSE + push dx ;push edx This is read later directly from [esp] + + ;mov eax, dword ptr (SMM_DISPATCHER_PRIVATE_STRUCT ptr [esi]).PageDirectories + db 8bh, 86h + dd SMM_DISPATCHER_PRIVATE_STRUCT.PageDirectories + mov cr3, eax ;Set CR3 to first page directory pointer table + + mov eax, cr4 + or al, 20h ;Enable PAE. + mov cr4, eax + + ;Enable long mode in msr register. Doesn't actually enter long mode yet. + + ;mov ecx, 0c0000080h + db 0b9h + dd 0C0000080h + rdmsr + ;bts eax, 8 + db 0Fh, 0BAh, 0E8h, 08h + wrmsr + + ;Enable paging + mov eax, cr0 + ;bts eax, 31 + db 0Fh, 0BAh, 0E8h, 1fh + ;btr eax, 16 ;Clear WT bit. This affects paging. + db 0fh, 0bah, 0f0h, 10h + mov cr0, eax ;Now in long mode compatiblity. + jmp @f +@@: + + ;set cs segment + ;lea eax, [edi + offset long_mode_64] + db 8dh, 87h + dd offset long_mode_64 + ;push CODE64_SEL + db 68h + dd CODE64_SEL + push ax ;push eax + retf + +long_mode_64: + ;in 64-bit long mode + + ;mov rax, 0ffffffffh + db 48h, 0b8h + dq 0ffffffffh + + db 48h + and bx, ax ;and rbx, rax + db 48h + and dx, ax ;and rdx, rax + db 48h + and si, ax ;and rsi, rax + db 48h + and di, ax ;and rdi, rax + db 48h + and sp, ax ;and esp, rax + + ;mov edx, [rsp] + db 8bh, 14h, 24h + ;fxsave [rdx] + db 48h, 0fh, 0aeh, 2 + + ;align stack by 16-bytes, sub 0ch and reserve stack for caller. + sub sp, 0ch + 20h ;sub esp, 12 + 20 + + ;Call Dispatcher + + ;lidt fword ptr (SMM_DISPATCHER_PRIVATE_STRUCT ptr [rsi]).Idt + db 0fh, 1, 5eh + db SMM_DISPATCHER_PRIVATE_STRUCT.IDT + + add di, 4 ;di = SmmEntryInit + + db 48h + mov cx, di ;mov rcx, rdi + + call bx ;call rbx + + ;restore stack + add sp, 0ch + 20h + + ;mov edx, [rsp] + db 8bh, 14h, 24h + + ;fxrstor [rdx] + db 48h, 0fh, 0aeh, 0ah + + ;lea rax, [@f]; + db 48h, 8Dh, 05 + dd offset @f - $ - 4 + ;push CODE32_SEL + db 68h + dd CODE32_SEL + db 48h + push ax ;push rax + db 48h + retf ;retq ;switch to compatibility mode. +@@: + pop dx ;pop edx +endif +;---We are in 32-bit protected or 32-bit compatibility mode.--- +;C calls preserve ESI, EDI, EBX, and EBP. +;esi = SMM_DISPATCHER_PRIVATE_STRUCT +;edi = SMM_ENTRY_INIT_STRUCT + +IFDEF MKF_PfatServices_SUPPORT +IF MKF_PfatServices_SUPPORT + mov eax, cr0 + and al, 0DFh ;Clear NE bit + mov cr0, eax +ENDIF +ENDIF + +IF MKF_SMM_CACHE_SUPPORT +IFNDEF MKF_NEHALEM_CPU_MODULE +; **************** CACHE DISABLE **************** + ;mov al, byte ptr (SMM_ENTRY_INIT_STRUCT ptr [edi]).Ht0 + db 8Ah, 47h + db SMM_ENTRY_INIT_STRUCT.Ht0 + or al, al ;or al, al + jz cache_disable_end ;skip if HT + + mov al, 1 + ;cmp (SMM_DISPATCHER_PRIVATE_STRUCT ptr [esi]).SmrrEnable, al + db 38h, 46h + db SMM_DISPATCHER_PRIVATE_STRUCT.SmrrEnable + jne non_smrr_cache2 + ;Disable SMRR. + + ;mov ecx, (SMM_DISPATCHER_PRIVATE_STRUCT ptr [esi]).SmrrMsr + db 08bh, 4eh + db SMM_DISPATCHER_PRIVATE_STRUCT.SmrrMsr + inc cx ;inc ecx + + rdmsr + bts eax, 11 ;Disable UC SMRR. This makes the region WT by overlapping MTRR. + wrmsr + jmp cache_disable_end + +non_smrr_cache2: + ;mov ecx, (SMM_DISPATCHER_PRIVATE_STRUCT ptr [esi]).TsegMsr + db 8bh, 4eh + db SMM_DISPATCHER_PRIVATE_STRUCT.TsegMsr + or cx, cx ;or ecx, ecx + jz cache_disable_end ;Not enough/or moved MTRR to support cache. + + rdmsr + xor al, al + wrmsr ;Make MTRR UC +;----------------- +cache_disable_end: +; ************** END OF CACHE DISABLE ************ +ENDIF +ENDIF + rsm + +align 16 +GDT_BASE: +NULL_SEL equ $-GDT_BASE ;NULL Selector 0 + dd 0, 0 + +DATA_SEL equ $-GDT_BASE ; Selector 8, Data 0-ffffffff 32 bit + dd 0000ffffh + dd 00cf9300h + +CODE32_SEL equ $-GDT_BASE ; Selector 10h, CODE 0-ffffffff 32 bit + dd 0000ffffh + dd 00cf9b00h + +; We only need this because Intel DebugSupport driver +; (RegisterPeriodicCallback function) assumes that selector 0x20 is valid +; The funciton sets 0x20 as a code selector in IDT +; +; System data segment descriptor +; +SYS_DATA_SEL equ $ - GDT_BASE ; Selector [0x18] + dd 0000FFFFh ;0 - f_ffff + dd 00cf9300h ;data, expand-up, notwritable, 32-bit + +; System code segment descriptor +SYS_CODE_SEL equ $ - GDT_BASE ; Selector [0x20] + dd 0000FFFFh ;0 - f_ffff + dd 00cf9b00h ;data, expand-up, writable, 32-bit +SPARE3_SEL equ $-GDT_BASE ; Selector [0x28] + dd 0, 0 +SYS_DATA64_SEL equ $-GDT_BASE ; Selector [0x30] + dd 0000FFFFh + dd 00cf9300h +CODE64_SEL equ $-GDT_BASE ; Selector [0x38] + dd 0000FFFFh + dd 00af9b00h +TSS_SEL equ $-GDT_BASE ; Selector [0x40] + dw 0067h +TSS_SEL_FIXUP: + dw 0000h + dd 00008900h +L_DATA_SEL equ $-GDT_BASE + dd 0000ffffh + dd 008f9300h +L_CODE_SEL equ $-GDT_BASE + dw 0ffffh +L_CODE_SEL_FIXUP: + dd 09a000000h ;Fix up by adding SMM BASE + 8000h + dw 0 +GDT_SIZE equ $-GDT_BASE ;Size of Descriptor Table + +GdtDescriptor: + dw GDT_SIZE - 1 ;GDT limit +GDT_DESC_FIXUP: + dd offset GDT_BASE ;Fix up by adding SMM BASE + 8000h +SmmEntryEnd: +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;<AMI_PHDR_START> +;--------------------------------------------------------------------------- +; +; Procedure: Thunk +; +; Description: The thunk code is copied to below 1MB and used in SMM to thunk to +; 16-bit mode. +; +; Input: None +; +; Output: None +;--------------------------------------------------------------------------- +;<AMI_PHDR_END> + +THUNK: + jmp short skip_thunk_fixup_data + dw offset thunk_data_fixup - offset THUNK + dw offset thunk_data_fixup2 - offset THUNK +skip_thunk_fixup_data: +IFDEF EFIx64 +;Starts in 64-bit mode. Need to turn this into machine code. + push dx ;rdx +;---Jump from long mode to compatiblity mode--- + push 10h + ;push eip (call next instruction) + db 0e8h + dd 0 + ;add dword ptr [rsp], 6 ;rip = ComMode. + db 83h, 04h, 24h + db 6 + db 48h + retf +ComMode: +;---Go to protected mode--- + mov eax, cr0 + btr ax, 31 ;btr eax, 31 + mov cr0, eax ;Now in protected mode. + jmp $+2 + + ;mov ecx, 0c0000080h + db 0b9h + dd 0c0000080h + rdmsr + btr ax, 8 ;btr eax, 8 + wrmsr +ENDIF +;Starts in protected mode. Need to turn this into machine code. + db 60h ;pushad + db 9ch ;pushfd + + ;mov ebx, ThunkData + db 0bbh +thunk_data_fixup: + dd 0 + +if MKF_SMM_THUNK_IN_CSM EQ -1 + ;movzx eax, word ptr [40eh] ;Get segment of ebda. + db 0Fh, 0B7h, 05 + dd 40eh + shl ax, 4 ;shl eax, 4 ;Get address ebda + add bx, ax ;add ebx, eax +endif + +;--Save Data-- + ;mov ds:(SMM_THUNK_DATA ptr [ebx]).StackSave, esp ;Save 32 bit stack address of this module. + db 89h, 63h + db SMM_THUNK_DATA.StackSave + ;sgdt ds:(SMM_THUNK_DATA ptr [ebx]).GdtSave + db 0Fh, 01h, 43h + db SMM_THUNK_DATA.GdtSave + ;sidt ds:(SMM_THUNK_DATA ptr [ebx]).IdtSave + db 0Fh, 01h, 4Bh + db SMM_THUNK_DATA.IdtSave +;---Copy Stack parameters of LegacyBiosFarCall--- + ;mov ecx, ds:(SMM_THUNK_DATA ptr [ebx]).StackParm.StackSize + db 8Bh, 4Bh + db SMM_THUNK_DATA.StackParm.StackSize + + or cx, cx ;32-bit or ecx, ecx + jz no_stack_to_copy + + ;movzx edi, ds:(SMM_THUNK_DATA ptr [ebx]).Below1MStack + db 0Fh, 0B7h, 7Bh + db SMM_THUNK_DATA.Below1MStack + add di, bx ;32-bit add edi, ebx + sub di, cx ;32-bit sub edi, ecx + + ;mov esi, ds:(SMM_THUNK_DATA ptr [ebx]).StackParm.StackPtr + db 8Bh, 73h + db SMM_THUNK_DATA.StackParm.StackPtr + + + rep movsb +no_stack_to_copy: + +;--Get Real mode address to switch to-- + ;call get_eip ;push eip + db 0E8h + dd 0h +get_eip:pop dx ;pop edx + ;add edx, offset RealMode - offset get_eip + db 83h, 0C2h + db offset RealMode - offset get_eip + +;--Switch to real mode-- + ;lidt fword ptr ds:(SMM_THUNK_DATA ptr [ebx]).LegacyIdtDesc + db 0Fh, 01h, 5Bh + db SMM_THUNK_DATA.LegacyIdtDesc + ;Jump to L_CODE_SEL:next + ;push L_CODE_SEL + db 6ah + db L_CODE_SEL + ;push offset next - offset THUNK + db 68h + dd offset next - offset THUNK + retf +next: + mov ax, L_DATA_SEL + mov ds, ax + mov es, ax + mov ss, ax + mov fs, ax + mov gs, ax + + mov eax, cr0 + and al, 0feh + mov cr0, eax + shr ebx, 4 + mov ds, bx + mov ss, bx +;---------------Real mode operations----------- + movzx esp, ds:(SMM_THUNK_DATA ptr [SmmThunkData]).Below1MStack + sub sp, word ptr ds:(SMM_THUNK_DATA ptr [SmmThunkData]).StackParm.StackSize + + ;--jump to real mode-- + mov eax, edx + shr edx, 4 ;edx = segment + and eax, 0fh ;eax = ip + push dx + push ax + retf +RealMode: + mov ax, cs + mov es, ax + mov fs, ax + mov gs, ax + + ;---copy registers for FarCall--- + mov eax, ds:(SMM_THUNK_DATA ptr [SmmThunkData]).regs.reg_eax + mov ebx, ds:(SMM_THUNK_DATA ptr [SmmThunkData]).regs.reg_ebx + mov ecx, ds:(SMM_THUNK_DATA ptr [SmmThunkData]).regs.reg_ecx + mov edx, ds:(SMM_THUNK_DATA ptr [SmmThunkData]).regs.reg_edx + mov esi, ds:(SMM_THUNK_DATA ptr [SmmThunkData]).regs.reg_esi + mov edi, ds:(SMM_THUNK_DATA ptr [SmmThunkData]).regs.reg_edi + mov ebp, ds:(SMM_THUNK_DATA ptr [SmmThunkData]).regs.reg_ebp + + push ds:(SMM_THUNK_DATA ptr [SmmThunkData]).regs.reg_es + pop es + push ds:(SMM_THUNK_DATA ptr [SmmThunkData]).regs.reg_fs + pop fs + push ds:(SMM_THUNK_DATA ptr [SmmThunkData]).regs.reg_gs + pop gs + + ;Generally, flags are not used to pass information as a parameter only to return information. + ;Uninialized flags in the parameters may cause an exception if they are set. + + cmp word ptr ds:(SMM_THUNK_DATA ptr [SmmThunkData]).StackParm.StackSize, 0 + jne @f + ;If no stack, push flags to imitate INT xx, in case of using call to emulate interrupt. + pushf +@@: + ;---Push return cs:ip--- + push cs + call store_ret_ptr ;push ip +store_ret_ptr: + push bp ;save bp for temp use. + mov bp, sp + + add word ptr [bp + 2], ret_from_16bit - store_ret_ptr ;Change return address in stack. + pop bp ;restore bp + + ;---------------------- + ;---Call 16-bit code--- + ;---------------------- + + ;push the function to stack. + push ds:(SMM_THUNK_DATA ptr [SmmThunkData]).FarCallPtr16.seg_offset + push ds:(SMM_THUNK_DATA ptr [SmmThunkData]).FarCallPtr16.ptr_offset + + ;This is done last because of ds is used. + push ds:(SMM_THUNK_DATA ptr [SmmThunkData]).regs.reg_ds + pop ds + + ;---Execute 16-bit call--- + retf ;Execute far call +ret_from_16bit: + push ds ;Save orginal ds +if MKF_SMM_THUNK_IN_CSM EQ -1 + push ax + xor ax, ax + mov fs, ax + movzx eax, word ptr fs:[40eh] + + ;add ax, thunk_data_fixup2 + db 5 +thunk_data_fixup2: + dw 0 + mov ds, ax + pop ax +else + ;push ThunkData2 ;ds = thunk data >> 4 + db 68h +thunk_data_fixup2: + dw 0 + pop ds +endif + + pop ds:(SMM_THUNK_DATA ptr [SmmThunkData]).regs.reg_ds + + + mov ds:(SMM_THUNK_DATA ptr [SmmThunkData]).regs.reg_eax, eax + mov ds:(SMM_THUNK_DATA ptr [SmmThunkData]).regs.reg_ebx, ebx + mov ds:(SMM_THUNK_DATA ptr [SmmThunkData]).regs.reg_ecx, ecx + mov ds:(SMM_THUNK_DATA ptr [SmmThunkData]).regs.reg_edx, edx + mov ds:(SMM_THUNK_DATA ptr [SmmThunkData]).regs.reg_esi, esi + mov ds:(SMM_THUNK_DATA ptr [SmmThunkData]).regs.reg_edi, edi + mov ds:(SMM_THUNK_DATA ptr [SmmThunkData]).regs.reg_ebp, ebp + + pushfd + pop ds:(SMM_THUNK_DATA ptr [SmmThunkData]).regs.reg_flags + + mov ax, es + mov ds:(SMM_THUNK_DATA ptr [SmmThunkData]).regs.reg_es, ax + + mov ax, fs + mov ds:(SMM_THUNK_DATA ptr [SmmThunkData]).regs.reg_fs, ax + + mov ax, gs + mov ds:(SMM_THUNK_DATA ptr [SmmThunkData]).regs.reg_gs, ax + +;--------------End Real Mode operations--------- + + xor ebx, ebx + mov bx, ds + shl ebx, 4 + + xor edx,edx + mov dx, cs + shl edx, 4 ;edx+ already 0 + + ;--Switch to protected mode-- + db 66h + lgdt fword ptr ds:(SMM_THUNK_DATA ptr [SmmThunkData]).GdtSave + + mov eax, cr0 + or al, 1 ;Set PE bit + mov cr0, eax ;Turn on Protected Mode + +;---Switch into protected mode--- + ;jmp 10:TP32MODE to set cs segment + + mov eax, edx + call get_eip2 ;push ip +get_eip2: + xor edx, edx + pop dx + add edx, offset TP32Mode - offset get_eip2 + add edx, eax ;eip = cs * 10h + offset + pushd 10h + push edx + db 66h + retf +TP32Mode:: +;---In protected mode.--- + ;mov ax, DATA_SEL + db 66h, 0b8h + dw DATA_SEL + db 66h, 8eh, 0d8h ;mov ds, ax + db 66h, 8eh, 0c0h ;mov es, ax + db 66h, 8eh, 0d0h ;mov ss, ax + db 66h, 8eh, 0e0h ;mov fs, ax + db 66h, 8eh, 0e8h ;mov gs, ax + + ;lidt fword ptr ds:(SMM_THUNK_DATA ptr [ebx]).IdtSave + db 0Fh, 01h, 5Bh + db SMM_THUNK_DATA.IdtSave + + ;mov esp, ds:(SMM_THUNK_DATA ptr [ebx]).StackSave ;Get original stack back. + db 8Bh, 63h + db SMM_THUNK_DATA.StackSave + + xor ax, ax ;xor eax, eax short/quick way to set EAX = 0 + lldt ax ;(source operand == 0) => LDTR is invalid + db 9dh ;popfd + db 61h ;popad + +IFDEF EFIx64 +;---Switch to long mode--- + ;mov ecx, 0c0000080h + db 0b9h + dd 0c0000080h + rdmsr + bts ax, 8 ;bts eax, 8 + wrmsr + + mov eax, cr0 + bts ax, 31 ;bts eax, 31 + mov cr0, eax ;Now in compatibility mode. + jmp $+2 + + ;jmp 38:LongModeThk to set cs segment + ;call get_eip3 ;push eip + db 0E8h + dd 0h +get_eip3: + pop dx ;pop edx (edx = eip) + ;add edx, offset LongModeThk - offset get_eip3 + db 83h, 0C2h + db offset LongModeThk - offset get_eip3 + push 38h + push dx ;push edx + retf +LongModeThk: + ;mov ax, DATA_SEL + db 66h, 0b8h + dw DATA_SEL + db 66h, 8eh, 0d8h ;mov ds, ax + db 66h, 8eh, 0c0h ;mov es, ax + db 66h, 8eh, 0d0h ;mov ss, ax + db 66h, 8eh, 0e0h ;mov fs, ax + db 66h, 8eh, 0e8h ;mov gs, ax + + pop dx ;pop rdx +ENDIF + ret +SmmThunkEnd: +SMM ENDS + +end + +;************************************************************************* +;************************************************************************* +;** ** +;** (C)Copyright 1985-2008, American Megatrends, Inc. ** +;** ** +;** All Rights Reserved. ** +;** ** +;** 5555 Oakbrook Parkway, Suite 200, Norcross, GA 30093 ** +;** ** +;** Phone: (770)-246-8600 ** +;** ** +;************************************************************************* +;************************************************************************* diff --git a/Core/EM/SMM/SmmHdr.equ b/Core/EM/SMM/SmmHdr.equ new file mode 100644 index 0000000..5209fe0 --- /dev/null +++ b/Core/EM/SMM/SmmHdr.equ @@ -0,0 +1,286 @@ +;************************************************************************* +;************************************************************************* +;** ** +;** (C)Copyright 1985-2011, American Megatrends, Inc. ** +;** ** +;** All Rights Reserved. ** +;** ** +;** 5555 Oakbrook Parkway, Suite 200, Norcross, GA 30093 ** +;** ** +;** Phone: (770)-246-8600 ** +;** ** +;************************************************************************* +;************************************************************************* + +;********************************************************************** +; $Header: /Alaska/SOURCE/Modules/SMM/SmmHdr.equ 26 4/01/11 10:09a Markw $ +; +; $Revision: 26 $ +; +; $Date: 4/01/11 10:09a $ +;********************************************************************** +; Revision History +; ---------------- +; $Log: /Alaska/SOURCE/Modules/SMM/SmmHdr.equ $ +; +; 26 4/01/11 10:09a 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, SmmPrivateShared.h, +; SmmHdr.equ, SmmInit.c +; +; 25 8/11/09 11:46a Markw +; Removed Legacy registration. This is removed from latest PI and not +; used by projects. +; +; 24 7/08/09 8:09p Markw +; Update headers. +; +; 23 12/23/08 2:15p Markw +; EIP #17900 Set up TSS. Borland C in DOS hangs otherwise. +; +; 22 11/21/08 4:57p Markw +; Add SmmInit to SMM_ENTRY_STRUCT for SMM init for first normal/S3 boot. +; 32-bit CPU count. +; +; 21 9/07/08 12:42a Markw +; Separate SMM Private structure into inside SMM and outside SMM +; structure. +; +; 20 4/04/08 6:21p Markw +; Add Smrr MSR to SMM_BASE_PRIVATE_STRUCT. +; +; 19 3/03/08 6:35p Markw +; Added 32-bit register for smm thunk. +; +; 18 11/14/07 2:03p Markw +; Added SMRR support and updated SMM Cache for non-SMRR. +; +; 17 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. +; +; 16 10/24/07 12:00p Markw +; SMM Thunk code position independent. Data in a separate segment than +; code in Smm Thunk. +; +; 15 9/10/07 1:39p Markw +; Add Interrupt Handling in SMM. +; +; 14 6/08/07 6:51p Markw +; Save/Restore XMM. +; +; 13 1/11/07 12:28p Markw +; Adjusted location of fields in structure for removal of legacy. +; +; 12 1/09/07 6:40p Markw +; Update BSP Entry Structure to remove dependencies on SMM_BSP_BASE. +; +; 11 12/29/06 4:45p Markw +; Add Smm Cache Support and update CPU syncronization. +; +; 10 12/21/06 5:19p Markw +; Remove old unused SmmStackSize from Private structure. +; +; 9 11/13/06 11:23a Markw +; Added structure for AP entry. +; +; 8 9/18/06 3:20p Markw +; Updated 32 bit part for BSP an AP sync. +; +; 7 9/18/06 11:47a Markw +; +; 6 8/24/06 3:27p Felixp +; Preliminary x64 support (work in progress) +; +; 5 1/13/06 11:27a Markw +; Added SMM Thunk support. +; +; 4 1/10/06 2:56p Markw +; Add support for multi-threadding and sync all CPUs during entry/exit of +; SMM. +; +; 3 7/19/05 7:59p Markw +; Fixed smm base private header. +; +; 2 7/11/05 1:06p Markw +; Removed isCallback from structure. +; +; 1 1/28/05 4:29p Sivagarn +; Generic SMM module - Intial Check in +; +; +;********************************************************************** + +;<AMI_FHDR_START> +;---------------------------------------------------------------------------- +; +; Name: SmmHdr.EQU +; +; Description: Header file for the SMM x86 assembly source +; +;---------------------------------------------------------------------------- +;<AMI_FHDR_END> + + +FAR_CALL_PTR_16 struct + ptr_offset dw ? + seg_offset dw ? +FAR_CALL_PTR_16 ends + +REGISTERS struct + reg_eax dd ? + reg_ebx dd ? + reg_ecx dd ? + reg_edx dd ? + reg_esi dd ? + reg_edi dd ? + reg_flags dd ? + reg_es dw ? + reg_cs dw ? + reg_ss dw ? + reg_ds dw ? + reg_fs dw ? + reg_gs dw ? + reg_ebp dd ? +REGISTERS ends + +IFNDEF EFIx64 + +SMM_DESC STRUCT 1 + Limit dw ? + Base dd ? + Rsv dw ? ;For alignment +SMM_DESC ENDS + +STACK_PARAM STRUCT + StackPtr dd ? + StackSize dd ? +STACK_PARAM ENDS + +SMM_ENTRY_INIT_STRUCT STRUCT + SmmInit dd ? ;This must be first. + SmmEntryLength dd ? + GdtDescBaseOffset dd ? + LCodeSelBaseOffset dd ? + TssSelBaseOffset dd ? + SmmThunkProcOffset dd ? + SmmThunkLength dd ? + Ht0 dd ? + SmmEntryStart dd ? + SmmDispatcherAddr dd ? + SmmDispatcherPrivateStruct dd ? + SmmStack dd ? + CpuNo dd ? +SMM_ENTRY_INIT_STRUCT ENDS + +SMM_THUNK_DATA STRUCT 8 + ;Real mode thunk + FarCallPtr16 FAR_CALL_PTR_16 <> + Regs REGISTERS <> + StackParm STACK_PARAM <> + StackSave dd ? + GdtSave SMM_DESC <> + IdtSave SMM_DESC <> + LegacyIdtDesc SMM_DESC <> + + Below1MStack dw ? ;ss = ds +SMM_THUNK_DATA ENDS + +DESCRIPTOR_TABLE STRUCT 1 + Limit dw ? + Base dd ? +DESCRIPTOR_TABLE ends + +SMM_DISPATCHER_PRIVATE_STRUCT STRUCT 8 + PageDirectories dd ? + SmmXmmSave dd ? + SmrrEnable db ? + SmrrMsr dd ? + TsegMsr dd ? + TsegMsrBase dq ? + TsegMsrMask dq ? + Idt DESCRIPTOR_TABLE <> + + ;Addional members not specified here. +SMM_DISPATCHER_PRIVATE_STRUCT ENDS + +ELSE + +STACK_PARAM struct + StackPtr dd ? + StackSize dd ? +STACK_PARAM ends + +SMM_DESC STRUCT 1 + Limit dw ? + Base dd ? + Rsv dw ? ;For alignment +SMM_DESC ENDS + +DESCRIPTOR_TABLE STRUCT 1 + Limit dw ? + Base dq ? +DESCRIPTOR_TABLE ends + +SMM_DISPATCHER_PRIVATE_STRUCT STRUCT 8 + PageDirectories dq ? + SmmXmmSave dq ? + SmrrEnable db ? + SmrrMsr dd ? + TsegMsr dd ? + TsegMsrBase dq ? + TsegMsrMask dq ? + Idt DESCRIPTOR_TABLE <> + ;Addional members not specified here. +SMM_DISPATCHER_PRIVATE_STRUCT ENDS + +SMM_ENTRY_INIT_STRUCT STRUCT 8 + SmmInit dd ? ;This must be first. + SmmEntryLength dd ? + GdtDescBaseOffset dd ? + LCodeSelBaseOffset dd ? + TssSelBaseOffset dd ? + SmmThunkProcOffset dd ? + SmmThunkLength dd ? + Ht0 dd ? + SmmEntryStart dq ? + SmmDispatcherAddr dq ? + SmmDispatcherPrivateStruct dq ? + SmmStack dq ? + CpuNo dd ? + Ia32HandlerListHead dq ? +SMM_ENTRY_INIT_STRUCT ENDS + +SMM_THUNK_DATA STRUCT 8 + ;Real mode thunk + FarCallPtr16 FAR_CALL_PTR_16 <> + Regs REGISTERS <> + StackParm STACK_PARAM <> + StackSave dd ? + GdtSave SMM_DESC <> + IdtSave SMM_DESC <> + LegacyIdtDesc SMM_DESC <> + Below1MStack dw ? ;ss = ds +SMM_THUNK_DATA ENDS + +ENDIF + +;************************************************************************* +;************************************************************************* +;** ** +;** (C)Copyright 1985-2011, American Megatrends, Inc. ** +;** ** +;** All Rights Reserved. ** +;** ** +;** 5555 Oakbrook Parkway, Suite 200, Norcross, GA 30093 ** +;** ** +;** Phone: (770)-246-8600 ** +;** ** +;************************************************************************* +;************************************************************************* diff --git a/Core/EM/SMM/SmmInit.c b/Core/EM/SMM/SmmInit.c new file mode 100644 index 0000000..fa0f699 --- /dev/null +++ b/Core/EM/SMM/SmmInit.c @@ -0,0 +1,1319 @@ +//************************************************************************* +//************************************************************************* +//** ** +//** (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/SmmInit.c 3 10/31/12 6:32a Wesleychen $ +// +// $Revision: 3 $ +// +// $Date: 10/31/12 6:32a $ +//********************************************************************** +// Revision History +// ---------------- +// $Log: /Alaska/Projects/Intel/Haswell/LynxPoint_SharkBay-DT_Crb_1AQQW/Core/EM/SMM/SmmInit.c $ +// +// 3 10/31/12 6:32a Wesleychen +// Move 'DisableSmmCallbacks' event from BDS_CONNECT_DRIVERS_PROTOCOL_GUID +// to BDS_ALL_DRIVERS_CONNECTED_PROTOCOL_GUID. +// +// 8 1/05/12 1:54p Markw +// [TAG] EIP78457 +// [Category] Bug Fix +// [Severity] Normal +// [Symptom] If BSP is switch, SMM may not bring all CPUs into SMM if +// not all CPUs are inside of SMM. +// [RootCause] During CPU initialization, the sytem uses the actual BSP +// instead of BSP from the SMM HOB. +// This creates a inconsistentancy with the rest of the SMM numbering. +// [Solution] Use SMM HOB BSP value. +// [Files] SmmInit.c +// +// 7 10/03/11 2:51p Markw +// Update StartupThisAP for PI 1.1. +// File: SmmInit.c +// +// 6 6/22/11 11:55a Markw +// Separate DxeSmmReadyToLock from Protocol\SmmReadyToLock.h. +// +// +// 5 5/10/11 12:06p Markw +// [TAG] EIP60051 +// [Category] Bug Fix +// [Severity] Critical +// [Symptom] With PI 1.1, BIOS may hang in DisableSmmCallbacks . +// [RootCause] DisableSmmCallbacks calls SmmDispatcher. This must be +// executed inside SMM. +// [Solution] Call SmmDispatcher inside SMM. +// [Files] SmmInit.c +// +// 4 4/12/11 3:00p Markw +// [TAG] EIP57440 +// [Category] New Feature +// [Description] PI Update allocated SMM BASE Protocol with boot +// services data. Change it to runtime services data. +// [Files] SmmInit.c +// +// 3 4/01/11 10:07a 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, SmmPrivateShared.h, +// SmmHdr.equ, SmmInit.c +// +// 2 3/04/11 3:32p Markw +// Update headers. +// +// 1 2/07/11 3:34p Markw +// [TAG] EIP53481 +// [Category] New Feature +// [Description] Add PIWG 1.1 SMM support. +// Moved common initialization from SmmBase.c to SmmInit.c. +// [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 +// +//********************************************************************** + +//<AMI_FHDR_START> +//--------------------------------------------------------------------------- +// +// Name: SmmInit.c +// +// Description: Dispatch SMM Drivers +// +//--------------------------------------------------------------------------- +//<AMI_FHDR_END> + +//This include should be first. +#include "SmmPrivateShared.h" +#include <AmiDxeLib.h> +#include "AmiCspLib.h" +#include <AmiSmm.h> +#include <AmiHobs.h> +#if USE_FV2 +#include <Protocol\FirmwareVolume2.h> +#else +#include <Protocol\FirmwareVolume.h> +#endif +#include <Protocol\LoadPe32Image.h> +#include <Protocol\MpService.h> +#if SMM_THUNK_IN_CSM == 1 +#include <Protocol\LegacyBiosExt.h> +#include <Protocol\LegacyBios.h> +#endif + +#if SMM_USE_FRAMEWORK +#include <Protocol\SmmBase.h> +#endif + +#if SMM_USE_PI +#include <Protocol\SmmBase2.h> +#include <Protocol\SmmReadyToLock.h> +#include <Protocol\DxeSmmReadyToLock.h> +#endif + + +#if SMM_USE_PI +#include <Protocol\SmmAccess2.h> +#include <Protocol\SmmControl2.h> +#else +#include <Protocol\SmmAccess.h> +#include <Protocol\SmmControl.h> +#endif + +#include <Token.h> + +// {3AA83745-9454-4f7a-A7C0-90DBD02FAB8E} +#define BDS_CONNECT_DRIVERS_PROTOCOL_GUID \ + { 0x3aa83745, 0x9454, 0x4f7a, { 0xa7, 0xc0, 0x90, 0xdb, 0xd0, 0x2f, 0xab, 0x8e } } +#define BDS_ALL_DRIVERS_CONNECTED_PROTOCOL_GUID \ + {0xdbc9fd21, 0xfad8, 0x45b0, 0x9e, 0x78, 0x27, 0x15, 0x88, 0x67, 0xcc, 0x93} + +CPUINFO_HOB *gCpuinfoHob; +SMM_HOB *gSmmHob; +EFI_HOB_CPU *gCpuHob; +UINT32 gBspSmmBase; +SMM_ENTRY_INIT_STRUCT *gSmmEntryData; +SMM_BASE_PRIVATE_STRUCT *gBasePrivate; +SMM_DISPATCHER_PRIVATE_STRUCT *gDispatcherPrivate; +EFI_PE32_IMAGE_PROTOCOL *gPe32Image; +EFI_MP_SERVICES_PROTOCOL *gMpServices; + + +#if SMM_USE_FRAMEWORK +EFI_SMM_SYSTEM_TABLE *gSmstTable; +#endif + +#if SMM_USE_PI +EFI_SMM_SYSTEM_TABLE2 *gSmstTable2; +#endif + +#if SMM_USE_PI +EFI_SMM_CONTROL2_PROTOCOL *gSmmControl; +EFI_SMM_ACCESS2_PROTOCOL *gSmmAccess; +#else +EFI_SMM_CONTROL_PROTOCOL *gSmmControl; +EFI_SMM_ACCESS_PROTOCOL *gSmmAccess; +#endif + + +#if SMM_THUNK_IN_CSM == 1 +EFI_LEGACY_BIOS_PROTOCOL *gLegacyBios; +EFI_LEGACY_BIOS_EXT_PROTOCOL *gLegacyBiosExt; +#endif + +EFI_HANDLE gThisImageHandle; + +EFI_GUID gHobListGuid = HOB_LIST_GUID; +EFI_GUID gSmmHobGuid = SMM_HOB_GUID; +EFI_GUID gCpuinfoHobGuid = AMI_CPUINFO_HOB_GUID; +EFI_GUID gEfiPe32ImageProtocolGuid = PE32_IMAGE_PROTOCOL_GUID; +EFI_GUID gEfiMpServicesProtocolGuid = EFI_MP_SERVICES_PROTOCOL_GUID; +EFI_GUID gBdsConnectDriversProtocolGuid = BDS_CONNECT_DRIVERS_PROTOCOL_GUID; +EFI_GUID gBdsAllDriversConnectedProtocolGuid = BDS_ALL_DRIVERS_CONNECTED_PROTOCOL_GUID; +#if SMM_USE_PI +EFI_GUID gEfiEventDxeDispatchGuid = EFI_EVENT_GROUP_DXE_DISPATCH; +//EFI_GUID gEfiDxeSmmReadyToLockProtocolGuid = EFI_DXE_SMM_READY_TO_LOCK_PROTOCOL_GUID; +#endif + +#if USE_FV2 +EFI_GUID gEfiFVProtocolGuid = EFI_FIRMWARE_VOLUME2_PROTOCOL_GUID; +#else +EFI_GUID gEfiFVProtocolGuid = EFI_FIRMWARE_VOLUME_PROTOCOL_GUID; +#endif + +#if SMM_THUNK_IN_CSM == 1 +EFI_GUID gEfiLegacyBiosProtocolGuid = EFI_LEGACY_BIOS_PROTOCOL_GUID; +EFI_GUID gEfiLegacyBiosExtProtocolGuid = EFI_LEGACY_BIOS_EXT_PROTOCOL_GUID; +#endif + +#if SMM_USE_FRAMEWORK +extern EFI_SMM_BASE_PROTOCOL gEfiSmmBase; +#endif + +#if SMM_USE_PI +extern EFI_SMM_BASE2_PROTOCOL gEfiSmmBase2; +#endif + +UINT32 gBspSmmBase; +SMM_ENTRY_INIT_STRUCT *gSmmEntryData; +UINTN gBsp; + +EFI_GUID SmmEntryGuid = + {0xD2596F82,0xF0E1,0x49fa,0x95,0xBC,0x62,0x01,0x2C,0x79,0x57,0x28}; + //D2596F82-F0E1-49fa-95BC-62012C795728 +EFI_GUID gEfiSmmCoreDispatcherGuid = + {0x4A37320B,0x3FB3,0x4365,0x97,0x30,0x9e,0x89,0xC6,0x00,0x39,0x5D}; + //4A37320B-3FB3-4365-9730-9E89C600395D + +VOID SmmDispatcher(); +VOID SetDisallowRegistering(); +VOID SmmDriverDispatchHandler(); + +extern UINT32 InSmmFuncLength; +extern UINT32 InSmmFuncOffset; + +EFI_STATUS EfiSmmInSmm( + IN EFI_SMM_BASE_PROTOCOL *This, + OUT BOOLEAN *InSmm +); + +// +// This is the structure contains default values in Boot Services memory. +// This table will be updated and copied into Runtime memory. +// +SMM_BASE_PRIVATE_STRUCT gSmmBasePrivateStruct = +{ + 0, //*CallBackFunc + FALSE, //InSmm + FALSE //DisallowCallbacks + //Additional members not specified. +}; + + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// +// Procedure: CallFuncInSmm +// +// Description: Call function in SMM. If not in SMM, generate SW SMI, otherwise +// call the function. +// +// Input: IN func -- Pointer to function +// +// Output: VOID +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> + +VOID CallFuncInSmm(IN VOID func()) +{ + if (!*gBasePrivate->InSmm) { +#if SMM_USE_PI + UINT8 CommandPort = SMMBASE_CALLBACK; +#else + UINT8 ArgBuffer = SMMBASE_CALLBACK; + UINTN ArgBufferSize = 1; +#endif + gBasePrivate->CallBackFunc = func; + + //Generate SW SMI +#if SMM_USE_PI + gSmmControl->Trigger(gSmmControl, &CommandPort, NULL, FALSE, 0); +#else + gSmmControl->Trigger(gSmmControl, &ArgBuffer, &ArgBufferSize, FALSE, 0); +#endif + //This is cleared inside of SMM. + } else { + func(); + } +} + + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: FindMatchingMtrr +// +// Description: Search MTRRs for a matching MTRR. +// +// Input: +// IN UINT64 BASE +// IN UINT64 Mask +// +// Output: +// UINT32 -- MSR for matching MTTR. +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> + +#if SMM_CACHE_SUPPORT == 1 +#ifndef NEHALEM_CPU_MODULE +VOID InitSmmCacheData() +{ + UINT32 Msr; + UINT32 i; + UINT8 NumMtrrs = (UINT8)ReadMsr(0xfe); //MSR_IA32_MTRR_CAP + UINT32 RegEAX, RegEBX, RegECX, RegEDX; + UINT8 NumOfMemoryBits = 36; + UINT64 MemoryMask; + + CPULib_CpuID(0x80000008, &RegEAX, &RegEBX, &RegECX, &RegEDX); + //Check if CPU supports this CPUID. + if (RegEAX != 0 && RegEAX != 0xffffffff) + NumOfMemoryBits = (UINT8)RegEAX & 0xff; + + MemoryMask = Shl64(1, NumOfMemoryBits)- 1; + + gDispatcherPrivate->SmrrEnable = FALSE; + gDispatcherPrivate->SmrrMsr = GetSmrrBaseMsr(); + gDispatcherPrivate->TsegMsr = 0; + gDispatcherPrivate->TsegMsrBase = (UINT64)(UINTN)gSmmHob->Tseg; + gDispatcherPrivate->TsegMsrMask = (MemoryMask & (~(TSEG_SIZE - 1))) | (1 << 11); + + //MSRs will not be found if there is not enough MSRs for caching SMM. + + for(i = 0, Msr = 0x200; i < NumMtrrs; ++i, Msr+=2) { //MTRR_PHYS_BASE_0 + if ((ReadMsr(Msr) & ~(UINT64)0xff) == gDispatcherPrivate->TsegMsrBase + && ReadMsr(Msr+1) == gDispatcherPrivate->TsegMsrMask + ) { + gDispatcherPrivate->TsegMsr = Msr; + } + } + + if (CPULib_IsSmrrEnabled()) gDispatcherPrivate->SmrrEnable = TRUE; +} +#endif +#endif + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// +// Procedure: LoadRealModeFile +// +// Description: Load a real mode file into a buffer. +// +// Input: +// IN EFI_GUID *Guid +// OUT VOID **Buffer +// OUT UINTN *BufferSize +// +// Output: EFI_STATUS +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> + +EFI_STATUS LoadRealModeFile(EFI_GUID *Guid, VOID **Buffer, UINTN *BufferSize) +{ +#if USE_FV2 + EFI_FIRMWARE_VOLUME2_PROTOCOL *Fv; +#else + EFI_FIRMWARE_VOLUME_PROTOCOL *Fv; +#endif + UINT32 Authentication; + EFI_STATUS Status; + UINTN NumHandles; + EFI_HANDLE *HandleBuffer; + UINTN i; + + *Buffer=0; + *BufferSize=0; + + Status = pBS->LocateHandleBuffer(ByProtocol,&gEfiFVProtocolGuid,NULL,&NumHandles,&HandleBuffer); + if (EFI_ERROR(Status)) return Status; + + for (i = 0; i< NumHandles; ++i) { + Status = pBS->HandleProtocol(HandleBuffer[i],&guidFV,&Fv); + if (EFI_ERROR(Status)) continue; + + Status = Fv->ReadSection(Fv, + Guid, + EFI_SECTION_RAW, + 0, //Instance + Buffer, + BufferSize, + &Authentication); + + if (Status == EFI_SUCCESS) break; + } + + pBS->FreePool(HandleBuffer); + return Status; +} + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// +// Procedure: EarlyAllocSmmMemory +// +// Description: Allocate SMM memory before SMM memory manager available. +// +// Input: +// IN UINT32 Size -- Memory size +// +// Output: VOID * -- ptr to allocated memory. +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> + +VOID * EarlyAllocSmmMemory(IN UINT32 Size) +{ + UINT8 *AllocatedAddress; + UINT32 AdjSize; + + AdjSize = (Size + 7) & ~7; //Minimum 8 bytes. + if (AdjSize > gBasePrivate->SmmAllocMemoryLength) return 0; + + AllocatedAddress = (UINT8*)gBasePrivate->SmmAllocMemoryStart; + gBasePrivate->SmmAllocMemoryStart = AllocatedAddress + AdjSize; + gBasePrivate->SmmAllocMemoryLength -= AdjSize; + + return AllocatedAddress; +} + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// +// Procedure: EarlyAllocSmmMemoryAlign +// +// Description: +// Allocate SMM memory before SMM memory manager available with specified alignment. +// Memory address returned will be the next aligned address available and the free memory +// before the aligned address can not be allocated. +// +// Input: +// IN UINT32 Size -- Memory size. +// IN UINT32 Align -- Alignment. Must be 2^n. +// +// Output: VOID * -- ptr to allocated memory. +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> + +VOID * EarlyAllocSmmMemoryAlign(IN UINT32 Size, IN UINT32 Align) +{ + UINT8* AllocatedAddress; + UINT8 *OrigAddress; + UINT32 AdjSize; + + AdjSize = (Size + 7) & ~7; //Minimum 8 bytes. + if (AdjSize > gBasePrivate->SmmAllocMemoryLength) return 0; + + OrigAddress = (UINT8*)gBasePrivate->SmmAllocMemoryStart; + AllocatedAddress = (UINT8*)(((UINT32)OrigAddress + (Align - 1)) & ~(Align - 1)); + + gBasePrivate->SmmAllocMemoryStart = AllocatedAddress + AdjSize; + gBasePrivate->SmmAllocMemoryLength -= (UINT32)(AllocatedAddress + AdjSize - OrigAddress); + + return AllocatedAddress; +} + +//SMM thunk either requires AB Segment of CSM. +#if SMM_THUNK_NO_AB_SEG == 0 || SMM_THUNK_IN_CSM == 1 + + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// +// Procedure: CopySmmThunkAfterBspEntry +// +// Description: +// Copy SMM Thunk to immediately after SMM BSP entry. +// +// Input: +// IN VOID *SmmEntryBuffer -- pointer to SMM Entry file +// IN UINTN SmmEntryBufferSize -- Size of SMM Entry file +// +// Output: EFI_STATUS +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> + +EFI_STATUS CopySmmThunkAfterBspEntry ( + IN VOID *SmmEntryBuffer, + IN UINTN SmmEntryBufferSize +) +{ + UINT8 *SmmThunkStart = (UINT8*)gBspSmmBase + 0x8000 + gSmmEntryData->SmmThunkProcOffset; + UINT16 AdrFixup; + UINT16 SegFixup; + + *(UINT32*)(gBspSmmBase + 0x8000 + gSmmEntryData->LCodeSelBaseOffset) += (UINT32)SmmThunkStart; + *(UINT32*)((UINT8*)SmmEntryBuffer + gSmmEntryData->LCodeSelBaseOffset) += (UINT32)SmmThunkStart; + + MemCpy(SmmThunkStart, + (UINT8*)SmmEntryBuffer + gSmmEntryData->SmmThunkProcOffset, + gSmmEntryData->SmmThunkLength + ); + + gDispatcherPrivate->SmmThunkProc = (VOID(*)())SmmThunkStart; + + gDispatcherPrivate->SmmThunkData = (SMM_THUNK_DATA*) + (((UINTN)SmmThunkStart + gSmmEntryData->SmmThunkLength + 16) & ~0xf); + + ASSERT(((UINTN)gDispatcherPrivate->SmmThunkData & 0xf) == 0); + + //Update Thunk to set Smm Thunk Data. + AdrFixup = *(UINT16*)(SmmThunkStart + 2); + SegFixup = *(UINT16*)(SmmThunkStart + 4); + + *(UINT32*)(SmmThunkStart + AdrFixup) = (UINT32)gDispatcherPrivate->SmmThunkData; + *(UINT16*)(SmmThunkStart + SegFixup) = (UINT16)((UINT32)gDispatcherPrivate->SmmThunkData >> 4); + + //Max 4k of stack. + //In this case, code, data, and stack in this 4k block. + //The ss=ds, and points to the end of the code, + // so code will have to be subtracted from the 4k top, + // so ss:sp = cs:1000h + gDispatcherPrivate->SmmThunkData->Below1MStack = + 0x1000 + - gSmmEntryData->SmmEntrySize + - gSmmEntryData->SmmThunkLength + - 0xf; //Could be up to 15 bytes skipped for alignment purposes; + gDispatcherPrivate->SmmThunkData->Below1MStack &= ~1; //Align on word bounary; + + gDispatcherPrivate->SmmThunkData->LegacyIdtDesc.Limit = 0x3ff; + gDispatcherPrivate->SmmThunkData->LegacyIdtDesc.Base = 0; + + return EFI_SUCCESS; +} + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// +// Procedure: CopySmmThunkAtStartABSegment +// +// Description: +// Copy SMM Thunk to start of AB Segment +// +// Input: +// IN VOID *SmmEntryBuffer -- pointer to SMM Entry file +// IN UINTN SmmEntryBufferSize -- Size of SMM Entry file +// +// Output: EFI_STATUS +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> + +EFI_STATUS CopySmmThunkAtStartABSegment( + IN VOID *SmmEntryBuffer, + IN UINTN SmmEntryBufferSize +) +{ + UINT8 *SmmThunkStart; + UINT16 AdrFixup; + UINT16 SegFixup; + +#if SMM_EXCLUDE_A000 != 1 + SmmThunkStart = (UINT8*)0xa0000; +#else + SmmThunkStart = (UINT8*)0xb0000; +#endif + + *(UINT32*)(gBspSmmBase + 0x8000 + gSmmEntryData->LCodeSelBaseOffset) += (UINT32)SmmThunkStart; + +//TODO: remove and share GDT between all CPUs. CPU0 is already copied. CPUx will copy this buffer later. + *(UINT32*)((UINT8*)SmmEntryBuffer + gSmmEntryData->LCodeSelBaseOffset) += (UINT32)SmmThunkStart; + + + MemCpy(SmmThunkStart, + (UINT8*)SmmEntryBuffer + gSmmEntryData->SmmThunkProcOffset, + gSmmEntryData->SmmThunkLength + ); + + gDispatcherPrivate->SmmThunkProc = (VOID(*)())SmmThunkStart; + + //SmmThunkData must be aligned on 16 byte boundary. + gDispatcherPrivate->SmmThunkData = (SMM_THUNK_DATA*) + (((UINTN)SmmThunkStart + gSmmEntryData->SmmThunkLength + 16) & ~0xf); + ASSERT(((UINTN)gDispatcherPrivate->SmmThunkData & 0xf) == 0); + + //Update Thunk to set Smm Thunk Data. + AdrFixup = *(UINT16*)(SmmThunkStart + 2); + SegFixup = *(UINT16*)(SmmThunkStart + 4); + + *(UINT32*)(SmmThunkStart + AdrFixup) = (UINT32)gDispatcherPrivate->SmmThunkData; + *(UINT16*)(SmmThunkStart + SegFixup) = (UINT16)((UINT32)gDispatcherPrivate->SmmThunkData >> 4); + + //Max 4k of stack. + //If in SMM, 1 block is reserved for stack and data. + gDispatcherPrivate->SmmThunkData->Below1MStack = + 0x1000 + - gSmmEntryData->SmmThunkLength + - 0xf; //Could be up to 15 bytes skipped for alignment purposes; + gDispatcherPrivate->SmmThunkData->Below1MStack &= ~1; //Align on word boundary; + + gDispatcherPrivate->SmmThunkData->LegacyIdtDesc.Limit = 0x3ff; + gDispatcherPrivate->SmmThunkData->LegacyIdtDesc.Base = 0; + return EFI_SUCCESS; +} + +#if SMM_THUNK_IN_CSM == 1 +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// +// Procedure: CopySmmThunkInCsmEBDA +// +// Description: +// Copy SMM Thunk to CSM. Data will be in EBDA. +// +// Input: +// IN VOID *SmmEntryBuffer -- pointer to SMM Entry file +// IN UINTN SmmEntryBufferSize -- Size of SMM Entry file +// +// Output: EFI_STATUS +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> + +EFI_STATUS CopySmmThunkInCsmEBDA ( + VOID *SmmEntryBuffer, + UINTN SmmEntryBufferSize +) +{ + UINT8 *SmmThunkStart; + UINT16 AdrFixup; + UINT16 SegFixup; + UINT32 EbdaStart; + EFI_STATUS Status; + + //Initialize this with the pointer to the Buffer in memory. + //This will be update later to the newly allocated region. + SmmThunkStart = (UINT8*)SmmEntryBuffer + gSmmEntryData->SmmThunkProcOffset; + + //In case this is 64-bits, initialize upper 32-bits to 0. + //Allocate Ebda, updates only the lower 32-bits. + gDispatcherPrivate->SmmThunkData = 0; + + Status = gLegacyBiosExt->AllocateEbda( + gLegacyBiosExt, + 4, + (UINT32*)&gDispatcherPrivate->SmmThunkData, + &gDispatcherPrivate->EbdaStartOffset + ); + if (EFI_ERROR(Status)) return Status; + + EbdaStart = (*(UINT16*)(0x40e)) << 4; + + //Max 4k of stack. + //If in SMM, 1 block is reserved for stack and data. + gDispatcherPrivate->SmmThunkData->Below1MStack = 0x1000; + + gDispatcherPrivate->SmmThunkData->LegacyIdtDesc.Limit = 0x3ff; + gDispatcherPrivate->SmmThunkData->LegacyIdtDesc.Base = 0; + + AdrFixup = *(UINT16*)(SmmThunkStart + 2); + SegFixup = *(UINT16*)(SmmThunkStart + 4); + + *(UINT32*)(SmmThunkStart + AdrFixup) = (UINT32)gDispatcherPrivate->SmmThunkData - EbdaStart; + *(UINT16*)(SmmThunkStart + SegFixup) = (UINT16)(((UINT32)gDispatcherPrivate->SmmThunkData - EbdaStart) >> 4); + + //Allocate CSM memory. + Status = gLegacyBios->GetLegacyRegion( + gLegacyBios, + gSmmEntryData->SmmThunkLength, + 0, //In e_0000 - f_ffff. + 1, //Byte alignment + &SmmThunkStart + ); + if (EFI_ERROR(Status)) return Status; + + *(UINT32*)(gBspSmmBase + 0x8000 + gSmmEntryData->LCodeSelBaseOffset) += (UINT32)SmmThunkStart; + *(UINT32*)((UINT8*)SmmEntryBuffer + gSmmEntryData->LCodeSelBaseOffset) += (UINT32)SmmThunkStart; + + //Copy to CSM memory. + Status = gLegacyBios->CopyLegacyRegion( + gLegacyBios, + gSmmEntryData->SmmThunkLength, + SmmThunkStart, + (UINT8*)SmmEntryBuffer + gSmmEntryData->SmmThunkProcOffset + ); + ASSERT_EFI_ERROR(Status); + + gDispatcherPrivate->SmmThunkProc = (VOID(*)())SmmThunkStart; + + ASSERT(((UINTN)gDispatcherPrivate->SmmThunkData & 0xf) == 0); + + //Max 4k of stack. + gDispatcherPrivate->SmmThunkData->Below1MStack = 0x1000; + + gDispatcherPrivate->SmmThunkData->LegacyIdtDesc.Limit = 0x3ff; + gDispatcherPrivate->SmmThunkData->LegacyIdtDesc.Base = 0; + + return EFI_SUCCESS; +} +#endif +#endif + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// +// Procedure: LoadAndInitDispatcherImages +// +// Description: Load and initialize dispatcher images. +// +// Input: +// IN EFI_SYSTEM_TABLE SystemTable +// IN UINT32 NumCpus +// +// Output: VOID +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> + +VOID LoadAndInitDispatcherImages( + IN EFI_SYSTEM_TABLE *SystemTable, + IN UINT32 NumCpus +) +{ + EFI_STATUS Status; + VOID *SmmEntryBuffer; + UINTN SmmEntryBufferSize; + VOID *SmmBaseSaveBuffer; + VOID *Buffer; + UINTN BufferSize; + UINT32 AuthenticationStatus; + UINT8 *SmmBase; + UINT8 *ApStackTop; + UINT16 Bsp = gSmmHob->Bsp; + UINT32 i; + UINT32 TssBaseAddress; + + SMM_ENTRY_INIT_STRUCT *SmmApEntryInit; + EFI_PHYSICAL_ADDRESS EntryPoint; + EFI_HANDLE ImageHandle; + + CPU_SmmMemoryInit(gSmmHob); + + // + // Load BSP SMM real mode. + // This must be done before loading protected mode dispatcher + // because the entry point of the protected mode dispatcher + // initializes some of SMM real mode variables. + // + + Status = LoadRealModeFile(&SmmEntryGuid, &SmmEntryBuffer, &SmmEntryBufferSize); + ASSERT_EFI_ERROR(Status); + + SmmBase = (UINT8*)gBspSmmBase; + MemCpy(SmmBase+0x8000, SmmEntryBuffer, ((SMM_ENTRY_INIT_STRUCT*)((UINT8*)SmmEntryBuffer+4))->SmmEntrySize); + + gSmmEntryData->CpuNo = 0; + gSmmEntryData->SmmEntryStart = (VOID*)(SmmBase + 0x8000); + gSmmEntryData->DispatcherPrivate = gDispatcherPrivate; + + *(UINT32*)(SmmBase + 0x8000 + gSmmEntryData->GdtDescBaseOffset) += gBspSmmBase + 0x8000; + + TssBaseAddress=*(UINT16*)(SmmBase + 0x8000 + gSmmEntryData->TssSelBaseOffset) + gBspSmmBase + 0x8000; + *(UINT16*)(SmmBase + 0x8000 + gSmmEntryData->TssSelBaseOffset) = TssBaseAddress; + *(UINT8*)(SmmBase + 0x8000 + gSmmEntryData->TssSelBaseOffset+2) = TssBaseAddress>>16; + *(UINT8*)(SmmBase + 0x8000 + gSmmEntryData->TssSelBaseOffset+5) = TssBaseAddress>>24; + + + gDispatcherPrivate->EbdaStartOffset = 0; //CopySmmThunkInCsmEBDA will update this. +//SMM thunk either requires AB Segment of CSM. +#if SMM_THUNK_NO_AB_SEG == 0 || SMM_THUNK_IN_CSM == 1 +#if SMM_THUNK_IN_CSM == 0 + if (gBspSmmBase < 0x100000) + CopySmmThunkAfterBspEntry(SmmEntryBuffer, SmmEntryBufferSize); + else + CopySmmThunkAtStartABSegment(SmmEntryBuffer, SmmEntryBufferSize); +#else + CopySmmThunkInCsmEBDA(SmmEntryBuffer, SmmEntryBufferSize); +#endif +#endif + +#ifdef EFIx64 + //Setup pages for virtual memory after Stack. + + //align page directories to 4k. + { + UINT8 *PageTable; + UINT32 NumAddrLines = gCpuHob->SizeOfMemorySpace; + + if (NumAddrLines > SMM_PAGING_MAX_ADDRESS_LINES) NumAddrLines = SMM_PAGING_MAX_ADDRESS_LINES; + + PageTable = EarlyAllocSmmMemoryAlign(GetPageTableNumPages(NumAddrLines) * 4096, 4096); + ASSERT(PageTable); + FillPageTable(NumAddrLines, PageTable); + gDispatcherPrivate->PageDirectories = PageTable; + } +#endif + + // + // Load and call entry of protected mode dispatcher. + // This must be done before AP real mode entry point because + // the protected mode init provides a pointer for the AP real mode + // to call after switching to protected mode. + + Buffer = 0; + Status = FvReadPe32Image( + &gEfiSmmCoreDispatcherGuid,&Buffer,&BufferSize, + &AuthenticationStatus); + ASSERT_EFI_ERROR(Status); + + gBasePrivate->Pe32DispatcherImage = + (VOID*)(((UINTN)gBasePrivate->SmmAllocMemoryStart + 4095) & ~4095); + gBasePrivate->Pe32DispatcherImageSize=EFI_SIZE_TO_PAGES(gSmmHob->ManagedMemSize); + + Status=gPe32Image->LoadPeImage( + gPe32Image, gThisImageHandle, + NULL, //Either DevicePath or + Buffer, BufferSize, //Buffer. This will be zero if DevicePath. + (EFI_PHYSICAL_ADDRESS)gBasePrivate->Pe32DispatcherImage, + &gBasePrivate->Pe32DispatcherImageSize, &ImageHandle, + &EntryPoint, EFI_LOAD_PE_IMAGE_ATTRIBUTE_NONE + ); + ASSERT_EFI_ERROR(Status); + + gBasePrivate->Pe32DispatcherImageSize=EFI_PAGES_TO_SIZE(gBasePrivate->Pe32DispatcherImageSize); + + pBS->FreePool(Buffer); +// +// Give control to protected mode dispatcher. The dispatcher is in SMM memory, +// however, the CPU is NOT in SMM mode. Currently SMM space is open. +// + if (!EFI_ERROR(Status)) { + TRACE((TRACE_ALWAYS,"SMM.SmmDispatcher.Entry(%lX)\n",EntryPoint)); + Status = ((DISPATCHER_ENTRY_POINT)EntryPoint)( + ImageHandle, + SystemTable, + gBasePrivate, + gDispatcherPrivate, +#if SMM_USE_FRAMEWORK + &gSmstTable, +#else + NULL, +#endif +#if SMM_USE_PI + &gSmstTable2 +#else + NULL +#endif + ); + } + ASSERT_EFI_ERROR(Status); + + gSmmEntryData->SmmStackTop = (VOID*)(gSmmHob->ManagedMemStart + BSP_SMM_STACK_SIZE); + + //Copy ApCode to SMM region. + + ApStackTop = gSmmEntryData->SmmStackTop + AP_SMM_STACK_SIZE; + + for (i = 0; i < NumCpus; ++i) { + static UINT32 ApNum = 0; //BSP is given CPU #0, and APs 1,2... + + if (i == Bsp) continue; + ++ApNum; + SmmBase = (VOID*)gSmmHob->SmmBase[i]; + MemCpy(SmmBase + 0x8000, SmmEntryBuffer, SmmEntryBufferSize); + SmmApEntryInit = (SMM_ENTRY_INIT_STRUCT*) (SmmBase + 0x8004); + SmmApEntryInit->SmmEntryStart = SmmBase + 0x8000; + SmmApEntryInit->DispatcherEntry = gSmmEntryData->DispatcherEntry; + SmmApEntryInit->DispatcherPrivate = gDispatcherPrivate; + SmmApEntryInit->SmmStackTop = ApStackTop; + SmmApEntryInit->CpuNo = ApNum; + + *(UINT32*)(SmmApEntryInit->GdtDescBaseOffset + SmmBase + 0x8000) + += (UINT32)SmmBase + 0x8000; + + TssBaseAddress=(UINT32)((*(UINT16*)(SmmBase + 0x8000 + SmmApEntryInit->TssSelBaseOffset)) + (SmmBase + 0x8000)); + *(UINT16*)(SmmBase + 0x8000 + SmmApEntryInit->TssSelBaseOffset) = TssBaseAddress; + *(UINT8*)(SmmBase + 0x8000 + SmmApEntryInit->TssSelBaseOffset+2) = (TssBaseAddress>>16); + *(UINT8*)(SmmBase + 0x8000 + SmmApEntryInit->TssSelBaseOffset+5) = (TssBaseAddress>>24); + + ApStackTop += AP_SMM_STACK_SIZE; + } + + pBS->FreePool(SmmEntryBuffer); + + SmmBaseSaveBuffer = Malloc(SmmGetBaseSaveBufferSize()); + ASSERT(SmmBaseSaveBuffer); + + SmmSetupDefaultHandler(SmmBaseSaveBuffer, gSmmHob); + + for (i = 0; i < gSmmHob->NumCpus; ++i) { + if (i == gBsp) { + SmmBaseChangeOnCpu((VOID*)gSmmHob->SmmBase[i]); + continue; + } + + gMpServices->StartupThisAP( + gMpServices, + SmmBaseChangeOnCpu, + i, //Cpu + NULL, + 0, + (VOID*)gSmmHob->SmmBase[i] +#if !(PI_SPECIFICATION_VERSION < 0x0001000A || BACKWARD_COMPATIBLE_MODE && defined(NO_PI_MP_SERVICES_SUPPORT)) + , NULL +#endif + ); + } + + SmmRemoveDefaultHandler(SmmBaseSaveBuffer); + pBS->FreePool(SmmBaseSaveBuffer); +} + +VOID InitgBasePrivate() +{ + UINT32 NumCpus = gSmmHob->NumCpus; + gBasePrivate->SmmHob = gSmmHob; + gBasePrivate->CallBackFunc = 0; + gBasePrivate->SmmAllocMemoryStart = + (VOID*) (gSmmHob->ManagedMemStart + BSP_SMM_STACK_SIZE + AP_SMM_STACK_SIZE * (NumCpus - 1)); + gBasePrivate->SmmAllocMemoryLength = + gSmmHob->ManagedMemSize - BSP_SMM_STACK_SIZE - AP_SMM_STACK_SIZE * (NumCpus - 1); +} + +VOID InitgDispatcherPrivate() +{ + UINT8 i; + UINT32 SmmNum; + UINT32 NumCpus = gSmmHob->NumCpus; + UINT8 *XmmSaveBase; + + gDispatcherPrivate = EarlyAllocSmmMemory(sizeof(*gDispatcherPrivate)); + ASSERT(gDispatcherPrivate); + + gDispatcherPrivate->NumCpus = NumCpus; + gDispatcherPrivate->NumCpusInSmm = 0; + gDispatcherPrivate->HandlerListHead = NULL; + gDispatcherPrivate->FloatingPointSave = FALSE; + + //Allocate a XMM Save Restore on a 16-byte boundary + XmmSaveBase = EarlyAllocSmmMemoryAlign(NumCpus * 512, 16); + gDispatcherPrivate->SmmXmmSave = EarlyAllocSmmMemory(NumCpus * sizeof(VOID*)); + for (i = 0; i < NumCpus; ++i) { + gDispatcherPrivate->SmmXmmSave[i] = XmmSaveBase; + XmmSaveBase += 512; + } + + //Initialize SmmCpuInfo + gDispatcherPrivate->SmmCpuInfo = EarlyAllocSmmMemory(sizeof(SMM_CPU_INFO) * NumCpus); + ASSERT(gDispatcherPrivate->SmmCpuInfo); + MemSet(gDispatcherPrivate->SmmCpuInfo, sizeof(SMM_CPU_INFO) * NumCpus, 0); + + gDispatcherPrivate->SmmCpuInfo[0].ApicId = gCpuinfoHob->Cpuinfo[gSmmHob->Bsp].ApicId; + + SmmNum = 1; + for (i = 0; i < NumCpus; ++i) { + if (i == gSmmHob->Bsp) continue; + gDispatcherPrivate->SmmCpuInfo[SmmNum].ApicId = gCpuinfoHob->Cpuinfo[i].ApicId; + ++SmmNum; + } + + //Initialize AP control for multi-threaded SMM. + gDispatcherPrivate->SmmApCpuControl = EarlyAllocSmmMemory(sizeof(SMM_AP_CPU_CONTROL) * NumCpus); + ASSERT(gDispatcherPrivate->SmmApCpuControl); + MemSet((VOID*)gDispatcherPrivate->SmmApCpuControl, sizeof(SMM_AP_CPU_CONTROL) * NumCpus, 0); + + gDispatcherPrivate->SmmControl = gSmmControl; +} + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// +// Procedure: CreateRuntimeInSmmFunction +// +// Description: +// Create InSmm function in runtime. +// +// Input: VOID +// +// Output: VOID +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> + +VOID *CreateRuntimeInSmmFunction() +{ + UINT8 *RuntimeInSmmFunc; + EFI_STATUS Status; + + Status = pBS->AllocatePool(EfiRuntimeServicesCode, InSmmFuncLength, &RuntimeInSmmFunc); + ASSERT_EFI_ERROR(Status); + + MemCpy(RuntimeInSmmFunc, EfiSmmInSmm, InSmmFuncLength); + + return RuntimeInSmmFunc; +} + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// +// Procedure: DisableSmmCallbacks +// +// Description: +// This is signaled before booting or shell. +// This makes the SMM Base protocol register/unregister unsupported. +// +// Input: +// IN EFI_EVENT Event +// IN VOID *Context +// +// Output: +// VOID +// +// +// NOTE: This routine could be called multiple times right before booting. +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> + +VOID DisableSmmCallbacks(IN EFI_EVENT Event, IN VOID *Context) +{ +#if SMM_USE_PI + EFI_HANDLE Handle = NULL; +#endif + //This should only run once, even if called by different events. + static BOOLEAN HasRun = FALSE; + if (HasRun) return; + + pBS->CloseEvent(Event); + + //If we are following PI1.1 model we should dispatch rest of SMM drivers whose DEPEX + //was not TRUE at the time of the first pass. +#if SMM_USE_PI + CallFuncInSmm(SmmDispatcher); + + pBS->InstallMultipleProtocolInterfaces ( + &Handle, + &gEfiDxeSmmReadyToLockProtocolGuid, NULL, + NULL + ); +#endif + + CallFuncInSmm(SetDisallowRegistering); + HasRun = TRUE; +} + +#if SMM_USE_PI +VOID SmmIplGuidedEventNotify ( + IN EFI_EVENT Event, + IN VOID *Context) +{ + CallFuncInSmm(SmmDriverDispatchHandler); +} +#endif + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// +// Procedure: LocateProtocols +// +// Description: +// Locate protocols needed for SMM Base. +// +// Input: VOID +// +// Output: VOID +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> + +VOID LocateProtocols() +{ + EFI_STATUS Status; +#if SMM_USE_PI + Status = pBS->LocateProtocol(&gEfiSmmAccess2ProtocolGuid, NULL, &gSmmAccess); + ASSERT_EFI_ERROR(Status); + + Status = pBS->LocateProtocol(&gEfiSmmControl2ProtocolGuid, NULL, &gSmmControl); + ASSERT_EFI_ERROR(Status); +#else + Status = pBS->LocateProtocol(&gEfiSmmAccessProtocolGuid, NULL, &gSmmAccess); + ASSERT_EFI_ERROR(Status); + + Status = pBS->LocateProtocol(&gEfiSmmControlProtocolGuid, NULL, &gSmmControl); + ASSERT_EFI_ERROR(Status); +#endif + + Status = pBS->LocateProtocol(&gEfiPe32ImageProtocolGuid, NULL, &gPe32Image); + ASSERT_EFI_ERROR(Status); + + Status = pBS->LocateProtocol(&gEfiMpServicesProtocolGuid, NULL, &gMpServices); + ASSERT_EFI_ERROR(Status); + +#if SMM_THUNK_IN_CSM == 1 + Status = pBS->LocateProtocol(&gEfiLegacyBiosProtocolGuid, NULL, &gLegacyBios); + ASSERT_EFI_ERROR(Status); + + Status = pBS->LocateProtocol(&gEfiLegacyBiosExtProtocolGuid, NULL, &gLegacyBiosExt); + ASSERT_EFI_ERROR(Status); +#endif +} + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// +// Procedure: FindHobs +// +// Description: Locate the HOBs needed. +// +// Input: VOID +// +// Output: VOID +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> + +EFI_STATUS FindHobs() +{ + VOID *FirstHob; + EFI_STATUS Status; + + //Parse hobs to get CPU Hob. + //Find first Hob + FirstHob = GetEfiConfigurationTable(pST,&gHobListGuid); + if (!FirstHob) { + TRACE((TRACE_ALWAYS, "SmmBase.Entry()Error:Unable to find CPUInfo HOB\n")); + return EFI_NOT_FOUND; + } + + //Find SMM Hob. + gSmmHob = (SMM_HOB*) FirstHob; + while (!EFI_ERROR(Status = FindNextHobByType(EFI_HOB_TYPE_GUID_EXTENSION, &gSmmHob))) { + if (guidcmp(&((EFI_HOB_GUID_TYPE*)gSmmHob)->Name, &gSmmHobGuid) == 0) { + break; + } + } + if (EFI_ERROR(Status)) return Status; + + //Find Cpu Info Hob. + gCpuinfoHob = (CPUINFO_HOB*) FirstHob; + while (!EFI_ERROR(Status = FindNextHobByType(EFI_HOB_TYPE_GUID_EXTENSION, &gCpuinfoHob))) { + if (guidcmp(&((EFI_HOB_GUID_TYPE*)gCpuinfoHob)->Name, &gCpuinfoHobGuid) == 0) { + break; + } + } + if (EFI_ERROR(Status)) return Status; + + gCpuHob = (EFI_HOB_CPU*)FirstHob; + Status = FindNextHobByType(EFI_HOB_TYPE_CPU, &gCpuHob); + if (EFI_ERROR(Status)) return Status; + return EFI_SUCCESS; +} + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// +// Procedure: SmmInitEntry +// +// Description: SMM Installer Entry Point. +// +// Input: +// IN EFI_HANDLE ImageHandle +// IN EFI_SYSTEM_TABLE *SystemTable +// +// Output: EFI_STATUS +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> + +EFI_STATUS SmmInitEntry( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable +) +{ + EFI_STATUS Status; + EFI_EVENT BootEvent; + EFI_EVENT Event; + VOID *Registration; + VOID *RuntimeInSmmFunc; +#if SMM_USE_FRAMEWORK + EFI_SMM_BASE_PROTOCOL *RuntimeSmmBase; +#endif + + InitAmiLib(ImageHandle,SystemTable); + + gThisImageHandle = ImageHandle; + + LocateProtocols(); + + Status = FindHobs(); + ASSERT_EFI_ERROR(Status); + if (EFI_ERROR(Status)) return Status; + + + Status = gMpServices->WhoAmI(gMpServices, &gBsp); + ASSERT_EFI_ERROR(Status); + + gBspSmmBase = gSmmHob->SmmBase[gSmmHob->Bsp]; + gSmmEntryData = (SMM_ENTRY_INIT_STRUCT *) (gBspSmmBase + 0x8004); + + + // Allocate space in runtime services for gPrivate. + // This is needed because this pointer will be used by SMM during runtime. + + Status = pBS->AllocatePool(EfiRuntimeServicesData, sizeof(SMM_BASE_PRIVATE_STRUCT), &gBasePrivate); + ASSERT_EFI_ERROR(Status); + + // Copy the private structure. This does not copy the pointer. It copies the entire structure. + *gBasePrivate = gSmmBasePrivateStruct; //Make available during runtime. + + InitgBasePrivate(); + RuntimeInSmmFunc = CreateRuntimeInSmmFunction(); + +#if SMM_USE_FRAMEWORK + gEfiSmmBase.InSmm = (EFI_SMM_INSIDE_OUT)RuntimeInSmmFunc; +#endif +#if SMM_USE_PI + gEfiSmmBase2.InSmm = (EFI_SMM_INSIDE_OUT2)RuntimeInSmmFunc; +#endif + gBasePrivate->InSmm = (UINT8*)RuntimeInSmmFunc + InSmmFuncOffset; + + Status = gSmmAccess->Open(gSmmAccess +#if SMM_USE_PI == 0 + ,0 +#endif + ); + ASSERT_EFI_ERROR(Status); + + InitgDispatcherPrivate(); + +#if SMM_CACHE_SUPPORT == 1 +#ifndef NEHALEM_CPU_MODULE + InitSmmCacheData(); +#endif +#endif + + LoadAndInitDispatcherImages(pST, gSmmHob->NumCpus); + + gSmmAccess->Close(gSmmAccess +#if SMM_USE_PI == 0 + , 0 +#endif + ); + + // locks SMM area so no one else can change it + gSmmAccess->Lock(gSmmAccess +#if SMM_USE_PI == 0 + , 0 +#endif + ); + + //For security reasons SMM should call from inside SMM to outside SMM before option ROMs are loaded. + //The following callback is registered to disable this. When this is disabled, no new SMM drivers + //can be registered. + + //This call back is only available since core 4.6.3.5. + Status = RegisterProtocolCallback( + &gBdsAllDriversConnectedProtocolGuid, + DisableSmmCallbacks, + NULL, + &Event, + &Registration + ); + ASSERT_EFI_ERROR(Status); + + //In cases where core does not support a call back before option roms are executed. + //The calling outside of SMM will be disabled before shell or a OS is loaded. + Status = CreateReadyToBootEvent( + TPL_CALLBACK, + DisableSmmCallbacks, + NULL, + &BootEvent + ); + ASSERT_EFI_ERROR(Status); + +#if SMM_USE_PI + //Setup Notification when BDS has finished 1st pass on loading drivers... + Status = pBS->CreateEventEx ( + EVT_NOTIFY_SIGNAL, + TPL_CALLBACK, + SmmIplGuidedEventNotify, + NULL, + &gEfiEventDxeDispatchGuid, + &Event + ); + ASSERT_EFI_ERROR(Status); + +#endif + +#if SMM_USE_FRAMEWORK + Status = pBS->AllocatePool(EfiRuntimeServicesData, sizeof(EFI_SMM_BASE_PROTOCOL), &RuntimeSmmBase); + ASSERT_EFI_ERROR(Status); + *RuntimeSmmBase = gEfiSmmBase; +#endif + + Status = pBS->InstallMultipleProtocolInterfaces( + &ImageHandle, +#if SMM_USE_FRAMEWORK + &gEfiSmmBaseProtocolGuid, RuntimeSmmBase, +#endif +#if SMM_USE_PI + &gEfiSmmBase2ProtocolGuid, &gEfiSmmBase2, +#endif + NULL); + ASSERT_EFI_ERROR(Status); + + return Status; +} + +//************************************************************************* +//************************************************************************* +//** ** +//** (C)Copyright 1985-2011, American Megatrends, Inc. ** +//** ** +//** All Rights Reserved. ** +//** ** +//** 5555 Oakbrook Parkway, Suite 200, Norcross, GA 30093 ** +//** ** +//** Phone: (770)-246-8600 ** +//** ** +//************************************************************************* +//************************************************************************* diff --git a/Core/EM/SMM/SmmMemoryManager.c b/Core/EM/SMM/SmmMemoryManager.c new file mode 100644 index 0000000..0e6addb --- /dev/null +++ b/Core/EM/SMM/SmmMemoryManager.c @@ -0,0 +1,962 @@ +//************************************************************************* +//************************************************************************* +//** ** +//** (C)Copyright 1985-2008, American Megatrends, Inc. ** +//** ** +//** All Rights Reserved. ** +//** ** +//** 5555 Oakbrook Parkway, Suite 200, Norcross, GA 30093 ** +//** ** +//** Phone: (770)-246-8600 ** +//** ** +//************************************************************************* +//************************************************************************* + +//********************************************************************** +// $Header: /Alaska/SOURCE/Modules/SMM/SMMDispatcher/SmmMemoryManager.c 12 4/22/10 4:39p Markw $ +// +// $Revision: 12 $ +// +// $Date: 4/22/10 4:39p $ +//********************************************************************** +// Revision History +// ---------------- +// $Log: /Alaska/SOURCE/Modules/SMM/SMMDispatcher/SmmMemoryManager.c $ +// +// 12 4/22/10 4:39p Markw +// Update to build with /w4 flag. +// +// 11 5/08/09 10:56a Markw +// Header updates. +// +// 10 12/16/08 2:34a Iminglin +// (EIP17767) The function value of FindFreeSpace, FindFreeAddress, +// Allocate for compliance. +// +// 9 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. +// +// 8 10/24/07 12:02p Markw +// SMM Thunk code position independent. Data in a separate segment than +// code in Smm Thunk. +// +// 7 7/25/07 2:11p Markw +// Exclude A000 region if needed. +// +// 6 8/24/06 7:13p Felixp +// +// 5 8/24/06 7:00p Felixp +// x64 support (warnings/errors fixed) +// +// 4 4/25/06 6:25p Markw +// +// 3 4/21/06 5:14p Markw +// +// 2 7/19/05 6:09p Markw +// Add support for managing A&B SMM segments. +// +// 1 1/28/05 4:32p Sivagarn +// SMM Dispatcher Component - Initial check in +// +// +//********************************************************************** + +//<AMI_FHDR_START> +//--------------------------------------------------------------------------- +// +// Name: SmmMemoryManager.c +// +// Description: Provides functions to manage SMM memory. Allocate and Free memory. +// +//--------------------------------------------------------------------------- +//<AMI_FHDR_END> + +#include <efi.h> +#include <AmiDxeLib.h> +#include "SmmPrivateShared.h" + +#define NUM_MEM_DESCRIPTORS 30 //<--Number of descriptors before in a table. If more descriptors needed, a new table is created. + +typedef struct _MEMORY_DESCRIPTOR MEMORY_DESCRIPTOR; +typedef struct _MEMORY_RESERVED_TABLE MEMORY_RESERVED_TABLE; + + +//<AMI_SHDR_START> +//--------------------------------------------------------------------------- +// +// Name: MEMORY_DESCRIPTOR +// +// Description: +// Each descriptor contains the Base and end + 1 of each +// memory allocation. The list is sorted from lowest to highest. +// Last linked descriptor has a Link = 0. +// Unused descriptors have links = 0xffffffff. +// +// Fields: Name Type Description +// ------------------------------------------------------------ +// MemBase UINT8* Base address of allocated memory. +// MemEnd UINT8* End address + 1 of allocated memory. +// Link MEMORY_DESCRIPTOR* Link to next Descriptor. +// +//--------------------------------------------------------------------------- +//<AMI_SHDR_END> + +struct _MEMORY_DESCRIPTOR +{ + UINT8 *MemBase; + UINT8 *MemEnd; + MEMORY_DESCRIPTOR *Link; +}; + +//<AMI_SHDR_START> +//--------------------------------------------------------------------------- +// +// Name: MEMORY_RESERVED_TABLE +// +// Description: +// Table stores memory descriptors. If runs out of descriptors, +// additional tables will be linked. New tables can not be removed. +// Unused descriptors Link will be 0xffffffff. +// Last table Link = 0. +// +// +// Fields: Name Type Description +// ------------------------------------------------------------ +// MemDesc MEMORY_DESCRIPTOR[] Array of memory descriptors. +// MemNextTable MEMORY_DESCRIPTOR A descriptor used if a new table is created. +// NumMemDescUsed UINTN Number of descriptors used. +// Link MEMORY_RESERVED_TABLE* Link to next table. +// +//--------------------------------------------------------------------------- +//<AMI_SHDR_END> + +struct _MEMORY_RESERVED_TABLE +{ + MEMORY_DESCRIPTOR MemDesc[NUM_MEM_DESCRIPTORS]; + MEMORY_DESCRIPTOR MemNextTable; + UINTN NumMemDescUsed; + MEMORY_RESERVED_TABLE *Link; +}; + +//Default descriptor for unused descriptor. +MEMORY_DESCRIPTOR gDefaultMemoryDescriptor = {0,0,(MEMORY_DESCRIPTOR*)(UINTN)0xffffffff}; + +//Default descriptor for next table. +MEMORY_DESCRIPTOR gDefaultMemoryDescriptor2 = {0,0,0}; + +UINT8 *gSmmMemBase; +UINT8 *gSmmMemEnd; //Top of SMM memory + 1. + +MEMORY_RESERVED_TABLE gTableHead; //First memory table. +MEMORY_DESCRIPTOR *gDescHead; //Pointer to first descriptor. (Lowest memory address.) + +BOOLEAN ABSegPageAlloc[32] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //ASEG. + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //BSEG. +}; + + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Procedure: Align8 +// +// Description: Align the address to nearest 8 byte alignment. +// +// Input: +// UINTN Value - Value to Align. +// +// Output: +// UINTN - Aligned Value. +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> +UINTN Align8(UINTN Value) +{ + return (Value + 7) & ~7; +} + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Procedure: Align2n +// +// Description: Align the address to nearest specified 2n alignment. +// If the alignment isn't 2^n-1, then result will be invalid. +// +// Input: +// UINT8 *Value - Pointer to value to Align. +// UINTN Alignment (This the 2n Alignment - 1. Example Alignment = 31, for 32 byte alignment. +// +// Output: +// UINT8* - Aligned Value. +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT8* Align2n(UINT8 *Value,UINTN Alignment) +{ + return (UINT8*)(((UINTN)Value+Alignment) & ~Alignment); +} + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Procedure: ConstructMemoryReservedTable +// +// Description: Intitialize the MEMORY_RESERVED_TABLE. +// +// Input: +// MEMORY_RESERVED_TABLE *Table +// +// Output: +// VOID +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +VOID ConstructMemoryReservedTable(MEMORY_RESERVED_TABLE *Table) +{ + UINTN i; + for(i=0;i<NUM_MEM_DESCRIPTORS;++i) Table->MemDesc[i] = gDefaultMemoryDescriptor; + Table->MemNextTable = gDefaultMemoryDescriptor2; + Table->Link = 0; +} + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Procedure: FindFreeSpace +// +// Description: Find a gap of free memory of a size and possibly of an alignment. This returns +// the preceding memory descriptor. If no gaps are found, the last memory descriptor +// is returned. +// +// Input: +// UINTN Size - Size of free space. +// UINTN Alignment OPTIONAL - This the 2n Alignment - 1. Example Alignment = 31, for 32 byte alignment. +// +// Output: +// MEMORY_DESCRIPTOR * +// +// Notes: +// Here is the control flow of this function: +// 1. Start with the first descriptor. +// 2. Evaluate the difference (empty space) between the +// (a) the base of address of the next descriptor and (b) the +// aligned End address of the current descriptor. +// 3. If the difference is greater or equal to the requested size, +// return the link. +// 4. Repeat 2-4, until out of descriptors. +// 5. Return the last descriptor. +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +MEMORY_DESCRIPTOR *FindFreeSpace( + IN UINTN Size, + IN UINTN Alignment OPTIONAL) +{ + MEMORY_DESCRIPTOR *Link; + UINT8 *FreeStart; + UINT8 *UsedNext; + + if (!Size) return NULL; + + //Find the preceding descriptor of a memory gap of the specified size (and alignment). + for (Link = gDescHead; Link->Link; Link = Link->Link) + { + UINTN EmptySpace; + FreeStart = Link->MemEnd; //Beginning of possible gap. + if (Alignment) FreeStart = Align2n(FreeStart,Alignment); //Align possible gap to requested alignment. + UsedNext = Link->Link->MemBase; //Find end of possible gap. + EmptySpace = (UINTN)UsedNext - (UINTN)FreeStart; //Gap size (may be negative because of alligned start) + if ((INTN)EmptySpace >= (INTN) Size) return Link; //If gap size is larger or equal requested size, + // return link of descriptor preceding link. + } + return Link; //Out of descriptors, return last Link. +} + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Procedure: FindAddress +// +// Description: Find a gap of free memory of an specific Address and a size. +// If part of the space is taken, return 0. +// If the space is found, return the preceding memory descriptor, +// or the last memory descriptor. +// +// Input: +// UINTN Size - Size of memory. +// UINTN Alignment - This the 2n Alignment - 1. Example Alignment = 31, for 32 byte alignment. +// +// Output: +// MEMORY_DESCRIPTOR * - 0 if the address range is taken. +// - not zero, if gap is found, or last link. +// +// Notes: +// Here is the control flow of this function: +// 1. Start with the first descriptor. +// 2. If the specifed address is in the descriptor, it is taken return 0. +// 3. If the specified address is in the gap after the descriptor, +// if the gap is big enough, return the preceding link, otherwise return 0. +// 4. Repeat steps 2-4 until iterated all the descriptors. +// 5. Return the last descriptor. +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +MEMORY_DESCRIPTOR *FindFreeAddress(UINT8 *Address, UINTN Size) +{ + MEMORY_DESCRIPTOR *Link; + UINT8 *FreeStart; + UINT8 *UsedNext; + + if (!Size) return NULL; + + for(Link = gDescHead; Link->Link; Link = Link->Link) + { + UINTN EmptySpace; + FreeStart = Link->MemEnd; + UsedNext = Link->Link->MemBase; + + if (Address >= Link->MemBase && Address < FreeStart) return NULL; //Space taken, if address is in the descriptor. + + if (Address >= FreeStart && Address <= UsedNext ) { //Is address in the, gap after the descriptor. + //UINTN typecasts used instead of UINT32, so complier won't give warning. + EmptySpace = (UINTN)UsedNext - (UINTN)Address; + if ((INTN)EmptySpace >= (INTN) Size) return Link; //If enough space in gap, return Link + return NULL; //Space not available. + } + } + return Link; //Out of descriptors, return last Link. +} + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Procedure: GetEmptyDescriptor +// +// Description: Find an unused memory descriptor in the tables. +// +// Input: VOID +// +// Output: +// MEMORY_DESCRIPTOR * - 0 if can not allocate a new descriptor. +// - Empty descriptor. +// +// Notes: +// Here is the control flow of this function: +// 1. Find a table with empty descriptors. +// 2. If a table is not found with an empty descriptor, go to step 5. +// ---Found table with an empty descriptor--- +// 3. Search descriptor array for an unused descriptors (Link = 0xffffffff) +// 4. Return the descriptor. +// ---Did not find table with an empty descriptor--- +// 5. Search memory descriptors for free space for a new table. +// 6. Check if last descriptor and enough free space at end, if not return 0. +// 7. Add a new memory table descriptor at the end of the returned descriptor. +// 8. Add new table link. +// 9. Construct a new table. +// 10. Return the first descriptor. +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +MEMORY_DESCRIPTOR * GetEmptyDescriptor() +{ + MEMORY_RESERVED_TABLE *Table = &gTableHead; + MEMORY_RESERVED_TABLE *PrevTable = NULL; + MEMORY_DESCRIPTOR *MemDesc; + UINTN i; + + //Find a table with an unused descriptor. + while (Table && (Table->NumMemDescUsed == NUM_MEM_DESCRIPTORS)) //If table full, find next descriptor. + { + PrevTable = Table; //Keep track of last table, in case we need to create a new one. + Table = Table->Link; + } + + if (Table) //Found table. + { + for(i=0;i<NUM_MEM_DESCRIPTORS;++i) + { + if (Table->MemDesc[i].Link == (MEMORY_DESCRIPTOR*)(UINTN)0xffffffff) //Search for empty descriptor + { + ++Table->NumMemDescUsed; + return &Table->MemDesc[i]; //Return empty descriptor. + } + } //Will not exit from this loop. An empty descriptor is guaranteed since NumMemDescUsed isn't the max. + } + + //No more empty descriptors. Create a new table + MemDesc = FindFreeSpace(sizeof(MEMORY_RESERVED_TABLE),0); //Find free memory. + + //This is the address of the new table if there is space available for the table. The table doesn't exist yet. + Table = (MEMORY_RESERVED_TABLE*) MemDesc->MemEnd; + + if (!MemDesc->Link) { //If end of descriptors, check if enough space for table. + if ((UINT8*) Table + Align8(sizeof(MEMORY_RESERVED_TABLE)) > gSmmMemEnd) return 0; //If out of space + } + + PrevTable->MemNextTable.Link = MemDesc->Link; //Add new table descriptor. + MemDesc->Link = &PrevTable->MemNextTable; + + PrevTable->MemNextTable.MemBase = (UINT8*) Table; //Fill in table descriptor + PrevTable->MemNextTable.MemEnd = (UINT8*) Table + Align8(sizeof(MEMORY_RESERVED_TABLE)); + PrevTable->Link = Table; //Add table end of previous table link. + + ConstructMemoryReservedTable(Table); //Fill in table with default values. + Table->NumMemDescUsed = 1; //1 descriptor is being allocated. + + return &Table->MemDesc[0]; //Return first descriptor. +} + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Procedure: RemoveDescriptor +// +// Description: Find an unused memory descriptor in the tables. +// +// Input: MEMORY_DESCRIPTOR * Descriptor - Descriptor to free. +// +// Output: VOID +// +// Notes: +// Here is the control flow of this function: +// 1. Start with first table. +// 2. Check each table's descriptor array for the descriptor to be removed. +// 3. If descriptor not found go to step 7. +// ---Descriptor found--- +// 4. Replace the Link with 0xffffffff. +// 5. Reduce number of descripors being used. +// 6. return. +// ---Descriptor not found--- +// 7. Repeat for next table steps 2-7 until last table. +// 8. Return +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +VOID RemoveDescriptor(MEMORY_DESCRIPTOR * Descriptor) +{ + MEMORY_RESERVED_TABLE *Table; + UINTN i; + + for (Table = &gTableHead; Table; Table = Table->Link) + { + if (Table->NumMemDescUsed==0) continue; + for(i=0; i < NUM_MEM_DESCRIPTORS; ++i) + { + if (&Table->MemDesc[i] == Descriptor) + { + Table->MemDesc[i].Link = (MEMORY_DESCRIPTOR*)(UINTN)0xffffffff; + --Table->NumMemDescUsed; + return; + } + } + } +} + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Procedure: Allocate +// +// Description: +// Allocate a memory. Caller may specify either a specific address +// or alignment, or neither. Alignment is a minimum of 8 bytes. +// +// Input: +// IN VOID *Address OPTIONAL - If caller wants to specify a specific address (Alignment is ignored). +// IN UINTN Size - Size of allocation. +// UINTN Alignment OPTIONAL - Specific alignment, if required. An address must not be given. +// If alignment is set to 0, then alignment is 8 bytes. (Required by SMM spec.) +// +// Output: +// VOID * - Memory allocated start address. +// +// Notes: +// Here is the control flow of this function: +// 1. If no size requested return 0. +// 2. Align Size up to the nearest 8 bytes. +// 3. Get an empty descriptor. If none, return 0. +// 4. If Address is given, set BaseStart to address. +// If not aligned on 8 byte boundary, remove descriptor and return 0. +// 5. Otherwise, set BaseStart to gSmmMemBase and +// align if and to the given alignment. (Bottom of SMM.) +// 6. If Size requested is greater than the Smm memory region, +// remove descriptor and return 0. +// 7. If no memory is previously allocated, setup descriptor, and point to it from gDescHead. +// (Baseaddress is either the Address requested or beggining of Smm RAM.) Return address. +// 8. Otherwise if requested memory base is lower than the base pointed by gDescHead or +// gap between start of smm ram and memory base pointed to by gDescHead is larger than +// the size requested is available, +// fill in memory descriptor, and add it in front of gDescHead, replacing gDescHead. Return Address. +// 9. Otherwise, if address address, find descriptor preceding the Address requested. +// 10. If size requested, find the descriptor preceding the gap >= Size requested. +// 11. If last descriptor, if not enough space left, remove descriptor, and return 0. +// 12. Fill in descriptor. Return Address. +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +void * Allocate( + IN VOID *Address OPTIONAL, + IN UINTN Size, + UINTN Alignment OPTIONAL + ) +{ + MEMORY_DESCRIPTOR *EmptyDesc = NULL; + MEMORY_DESCRIPTOR *FreeSpaceDesc; + UINT8 *BaseStart; + + if (!Size) return NULL; + + Size = Align8(Size); //Minimum size requested is 8 bytes. + + EmptyDesc = GetEmptyDescriptor(); + if (!EmptyDesc){ + return NULL; //Return if out of descriptors. + } + + if (Address) + { + if ((UINTN)Address != Align8((UINTN)Address)) {RemoveDescriptor(EmptyDesc);return 0;} //Address must be 8 byte aligned. + BaseStart = Address; + } else { + BaseStart = gSmmMemBase; + if (Alignment) BaseStart = Align2n(BaseStart,Alignment); + } + + if (Size > (UINTN)(gSmmMemEnd - BaseStart)) { //If Smm Memory is smaller than requested, return error. + RemoveDescriptor(EmptyDesc); + return NULL; + } + + if (!gDescHead) //True if no previous allocated memory. + { + EmptyDesc->MemBase = BaseStart; + EmptyDesc->Link = 0; + + gDescHead = EmptyDesc; + //else if is true if requested memory base or gap larger than the size requested is available. + } else if (((INTN) gDescHead->MemBase - (INTN)BaseStart) >= (INTN) Size) {//Insert before gDescHead; + EmptyDesc->MemBase=BaseStart; + EmptyDesc->Link = gDescHead; + gDescHead = EmptyDesc; + //else is true if memory base is more than + } else { + if (Address) + { + FreeSpaceDesc = FindFreeAddress(Address,Size); + if (!FreeSpaceDesc) + { + RemoveDescriptor(EmptyDesc); + return NULL; + } + BaseStart = Address; + } else { + FreeSpaceDesc = FindFreeSpace(Size,Alignment); + BaseStart = FreeSpaceDesc->MemEnd; + if (Alignment) BaseStart = Align2n(BaseStart,Alignment); + } + + if(!FreeSpaceDesc->Link && (UINTN)(gSmmMemEnd - BaseStart) < Size) + { //Last Link and not enough room. + RemoveDescriptor(EmptyDesc); + return NULL; + } + + EmptyDesc->MemBase = BaseStart; + EmptyDesc->Link = FreeSpaceDesc->Link; + FreeSpaceDesc->Link = EmptyDesc; + } + + EmptyDesc->MemEnd = EmptyDesc->MemBase + Size; + + return EmptyDesc->MemBase; +} + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Procedure: Free +// +// Description: Free an allocated buffer. +// +// Input: +// IN VOID *Buffer - Allocation to free. +// +// Output: +// BOOLEAN - TRUE if buffer freed. +// +// Notes: +// Here is the control flow of this function: +// 1. If no allocations, return FALSE. +// 2. If Buffer to free is gDescHead, set gDescHead to next Link, remove decriptor, and return TRUE. +// 3. Search link list for buffer. +// 4. If not found, return FALSE. +// 5. Set previous link of buffer to link after buffer. +// 6. Remove Descriptor. +// 7. Return TRUE. +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +BOOLEAN Free(VOID *Buffer) +{ + MEMORY_DESCRIPTOR *Link; + MEMORY_DESCRIPTOR *Prev; + + if (!gDescHead) return FALSE; + if (gDescHead->MemBase == (UINT8*)Buffer) + { + Link = gDescHead; + gDescHead = gDescHead->Link; + RemoveDescriptor(Link); + return TRUE; + } + + Prev = gDescHead; Link = gDescHead->Link; + + while(Link) + { + if (Link->MemBase == Buffer) + { + Prev->Link = Link->Link; + RemoveDescriptor(Link); + return TRUE; + } + Prev = Link; + Link = Link->Link; + } + return FALSE; +} + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Procedure: Free4kPages +// +// Description: Free pages from buffer. +// +// Input: +// IN VOID *StartAddress - Pages to free. +// IN UINTN Pages - # of 4k pages. +// +// Output: +// BOOLEAN - TRUE if buffer freed. +// +// Notes: +// Here is the control flow of this function: +// 1. If End Address is not greater than 4G, return FALSE. +// 2. If StartAddress is not aligned 4k, return FALSE. +// 3. If no allocations, return FALSE. +// 4. Search for a descriptor with the StartAddress is allocated. +// 5. If descriptor not found, return FALSE. +// 6. Search for a descriptor with the EndAddress is allocated. These criteria must be met which searching. +// * Allocation size of each descriptor must be 4k pages, otherwise return FALSE. +// * End address of descriptor must match base address of next descriptor (no free space), otherwise return FALSE. +// 7. If descriptor not found, return FALSE. +// 8. If Start and End descriptors are not the same go to step 13. +// -----Start and End Descriptor match exactly.---- +// 9. If Base and End descriptor match exactly, remove the descriptor from the list. +// 10. If only Start Address matches exactly, free that space by setting the start address to the End Address. +// 11. If only the End Address matches exactly, move the end address to Start Address. +// Note: the end address of the descriptor is not allocated. +// 12. return TRUE. +// ----Start and End Descriptors are different descriptors.---- +// 13. If Base address of the Start Descriptor, adjust its end address to the space, and +// move the Start Descriptor to the next descriptor. +// 14. Free the descriptors up till the end descriptor. +// 15. If the End Descriptor's End address doesn match the end address to free, +// set the base address to the end address, to free the space. +// 16. Otherwise, remove the end descriptor. +// 17. Return True. +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +BOOLEAN Free4kPages(VOID *StartAddress,UINTN Pages) +{ + MEMORY_DESCRIPTOR *StartDesc,*EndDesc,*PrevStart = NULL,*Link,*Link2; + UINT8* EndAddress = (UINT8*) StartAddress + 4096 * Pages; + if (EndAddress < (UINT8*)StartAddress) return FALSE; //If Endaddress > 4G. + + if (StartAddress != Align2n(StartAddress,4095)) return FALSE; //Must be align 4k. + + //--------Find Beginning and End of Descriptors to adjust-------- + + if (!gDescHead) return FALSE; + for (StartDesc = gDescHead; StartDesc; StartDesc = StartDesc->Link) + { + if ((UINT8*)StartAddress >= StartDesc->MemBase && (UINT8*)StartAddress < StartDesc->MemEnd) break; + PrevStart = StartDesc; + } + + if (!StartDesc) return FALSE; + + EndDesc = StartDesc; + for (;;) + { + if ((UINT8*)(EndDesc->MemEnd - EndDesc->MemBase) != Align2n((UINT8*)(EndDesc->MemEnd - EndDesc->MemBase),4095)) + return FALSE; //Size must be multiple of 4k. + + if (EndAddress >= EndDesc->MemBase && EndAddress <= EndDesc->MemEnd) break; + if (!EndDesc->Link) return FALSE; + if (EndDesc->MemEnd != EndDesc->Link->MemBase) return FALSE; //Gap of unallocated space in region to free. + EndDesc=EndDesc->Link; + } + + //--------Adjust Descriptors, Removing unused ones-------- + + if (StartDesc == EndDesc) //If true, range only affects 1 descriptor. + { + if (StartAddress == StartDesc->MemBase) + { + if (EndAddress == StartDesc->MemEnd) //If descriptor matches address exactly, free descriptor. + { + if (StartDesc == gDescHead) gDescHead = StartDesc->Link; + else PrevStart->Link = StartDesc->Link; + RemoveDescriptor(StartDesc); + return TRUE; + } + StartDesc->MemBase = EndAddress; //Start address matches, change start address. + return TRUE; + } + StartDesc->MemEnd = StartAddress; //If End address matches, change End address. + return TRUE; + } + + + //Range affects multiple descriptors. + if (StartAddress != StartDesc->MemBase) + { + StartDesc->MemEnd = StartAddress; + + PrevStart = StartDesc; + StartDesc = StartDesc->Link; //Don't delete this descriptor, since it has been adjusted. + } + + + //Remove descriptors in the middle before End. + if (StartDesc == gDescHead) gDescHead = EndDesc; + else PrevStart->Link = EndDesc; + + for (Link = StartDesc; Link != EndDesc; Link = Link2) + { + Link2 = Link->Link; + RemoveDescriptor(Link); //Remove Descriptors in between. + } + + + //If end address matches, free descriptor, otherwise adjust end address. + if (EndAddress != EndDesc->MemEnd) + { + EndDesc->MemBase = EndAddress; + } else { + if (EndDesc==gDescHead) gDescHead = EndDesc->Link; + else PrevStart->Link = EndDesc->Link; + RemoveDescriptor(EndDesc); + } + + return TRUE; +} + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Procedure: AllocateABSegPages +// +// Description: Allocate SMM 4k pages of memory in A or B segment. +// +// Input: +// IN EFI_ALLOCATE_TYPE Type +// IN UINTN NumberOfPages +// IN OUT EFI_PHYSICAL_ADDRESS *Memory +// +// Output: +// EFI_STATUS +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +EFI_STATUS AllocateABSegPages( + IN EFI_ALLOCATE_TYPE Type, + IN UINTN NumberOfPages, + IN OUT EFI_PHYSICAL_ADDRESS *Memory +) +{ + UINTN i; + UINT8 FreePageCount; + UINTN StartPage, EndPage; + UINT32 MaxAddress; + + VOID **pMemory32 = (VOID**) Memory; + UINT32 Memory32 = (UINT32)(UINTN)*pMemory32; + + //Only supported types. + if (Type != AllocateMaxAddress && Type != AllocateAddress) + return EFI_INVALID_PARAMETER; + + if (Memory32 < 0xa0000) return EFI_NOT_FOUND; + + if (Type == AllocateAddress) { + //Check memory alignment. + if ((Memory32 & (EFI_PAGE_SIZE - 1)) != 0) return EFI_INVALID_PARAMETER; + + StartPage = (Memory32 - 0xa0000) >> 12; + + //Check for allocation range. + if ((StartPage + NumberOfPages) > 32) return EFI_OUT_OF_RESOURCES; + + //Check if pages are free. + for (i = StartPage; i < (StartPage + NumberOfPages); ++i) + { + if (ABSegPageAlloc[i] == TRUE) return EFI_OUT_OF_RESOURCES; + } + for(i = StartPage; i < (StartPage + NumberOfPages); ++i) + ABSegPageAlloc[i] = TRUE; + + return EFI_SUCCESS; + } + + if (Memory32 < 0xa0ffe) return EFI_OUT_OF_RESOURCES; //Max address must be whole page. + + MaxAddress = Memory32 & ~(EFI_PAGE_SIZE - 1); //Round down to 4k alignment + + EndPage = (Memory32 - 0xa0000) >> 12; + if (EndPage > 31) EndPage = 31; //Max page is 31. + + //Find free pages. + FreePageCount = (UINT8) NumberOfPages; + for (i = 0; i < EndPage; ++i) + { + UINTN j; + if (ABSegPageAlloc[i] == TRUE) + { + FreePageCount = (UINT8) NumberOfPages; + continue; //Page allocated. Find next + } + if (--FreePageCount) continue; + + //Found page + StartPage = i + 1 - NumberOfPages; + *pMemory32 = (VOID *)((StartPage << 12) + 0xa0000); + + for (j = StartPage; j <= i; ++j) ABSegPageAlloc[j] = TRUE; + + return EFI_SUCCESS; + } + return EFI_OUT_OF_RESOURCES; +} + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Procedure: AllocateABSegPages +// +// Description: Allocate SMM 4k pages of memory in A or B segment. +// +// Input: +// IN EFI_PHYSICAL_ADDRESS Memory - Memory address. +// IN UINTN NumberOfPages +// +// Output: +// EFI_STATUS +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +EFI_STATUS FreeABSegPages( + IN EFI_PHYSICAL_ADDRESS Memory, + IN UINTN NumberOfPages +) +{ + UINTN i, StartPage, EndPage; + VOID *Memory32 = (VOID*)(UINTN)Memory; + + if (((UINT32)(UINTN)Memory32 & (EFI_PAGE_SIZE - 1)) != 0) return EFI_INVALID_PARAMETER; + + if ((UINT32)(UINTN)Memory32 < 0xa0000) return EFI_NOT_FOUND; + + StartPage = ((UINT32)(UINTN)Memory32 - 0xa0000) >> 12; + + //Check for allocation range. + if ((StartPage + NumberOfPages) > 32) return EFI_NOT_FOUND; + + EndPage = StartPage + NumberOfPages; + + for (i = StartPage; i < EndPage; ++i) if (ABSegPageAlloc[i] == FALSE) return EFI_NOT_FOUND; + for (i = StartPage; i < EndPage; ++i) ABSegPageAlloc[i] = FALSE; + + return EFI_SUCCESS; +} + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Procedure: InitializeMemoryManager +// +// Description: Initialize the memory manager, so the functions can be used. +// +// Input: VOID +// +// Output: VOID +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +VOID InitializeMemoryManager(SMM_BASE_PRIVATE_STRUCT *Private) { + UINT32 *pSmmBase = &Private->SmmHob->SmmBase[0]; + UINT32 NumCpus = Private->SmmHob->NumCpus; + UINT8 i; + +#if SMM_EXCLUDE_A000 == 1 + for (i = 0; i < 16; ++i) ABSegPageAlloc[i] = TRUE; +#endif + + //Initalize Legacy memory management. + for (i = 0; i < NumCpus; ++i) { + if (pSmmBase[i] < 0x100000) { + UINT8 Page = (UINT8)((pSmmBase[i] - 0x98000) / 4096); + ASSERT(Page < 32); + ASSERT((Page + 7) < 32); + ABSegPageAlloc[Page] = TRUE; + ABSegPageAlloc[Page + 7] = TRUE; + } + } + +//If Bsp = TSEG, reserve 1 page for SMM thunk and its stack. + if (pSmmBase[0] > 0x100000) { +#if SMM_EXCLUDE_A000 != 1 + ABSegPageAlloc[0] = TRUE; +#else + ABSegPageAlloc[16] = TRUE; +#endif + } + + //Initialize TSEG memory management. + gSmmMemBase = Private->SmmAllocMemoryStart; + gSmmMemEnd = gSmmMemBase + Private->SmmAllocMemoryLength; + ConstructMemoryReservedTable(&gTableHead); +} + +//************************************************************************* +//************************************************************************* +//** ** +//** (C)Copyright 1985-2008, American Megatrends, Inc. ** +//** ** +//** All Rights Reserved. ** +//** ** +//** 5555 Oakbrook Parkway, Suite 200, Norcross, GA 30093 ** +//** ** +//** Phone: (770)-246-8600 ** +//** ** +//************************************************************************* +//************************************************************************* diff --git a/Core/EM/SMM/SmmPiSmst.c b/Core/EM/SMM/SmmPiSmst.c new file mode 100644 index 0000000..f6a676b --- /dev/null +++ b/Core/EM/SMM/SmmPiSmst.c @@ -0,0 +1,1827 @@ +//************************************************************************* +//************************************************************************* +//** ** +//** (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 +// +//********************************************************************** + +//<AMI_FHDR_START> +//--------------------------------------------------------------------------- +// +// Name: SmmPiSmst.c +// +// Description: PI Smst functions. +// +//--------------------------------------------------------------------------- +//<AMI_FHDR_END> + +//This include should come first. +//#include "SmmPi.h" +#include "SmmPrivateShared.h" +#include <AmiDxeLib.h> +#include <Protocol\SmmCpu.h> +#if SMM_USE_PI +#include "SmmDispatcher.h" +#include <AmiLib.h> +#include <AmiCspLib.h> +#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 +); + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Procedure: SmmValidateHandle +// +// Description: Check whether a handle is a valid EFI_HANDLE. +// +// Input: +// IN EFI_HANDLE UserHandle + +// Output: +// EFI_STATUS +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> + +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; +} + + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Procedure: SmmFindProtocolEntry +// +// Description: Finds the protocol entry for the requested protocol. +// +// Input: +// IN EFI_GUID *Protocol +// IN BOOLEAN Create +// +// Output: +// Protocol entry +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> +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; +} + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// 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) +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> + +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; +} + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Procedure: SmmNotifyProtocol +// +// Description: Signal event for every protocol in protocol entry. +// +// Input: +// IN SMM_PROTOCOL_INTERFACE *Prot + +// Output: +// VOID +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> + +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); + } +} + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// 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 +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +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 + ); +} + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// 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 +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +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; +} + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// 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 +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +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; +} + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// 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 +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +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; +} + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// 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. +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +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; +} + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// 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 +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +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; +} + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// 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 +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +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; +} + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// 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 +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> +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; +} + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// 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 +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +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; +} + + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Procedure: SmmGetNextLocateAllHandles +// +// Description: +// Find next handle. +// +// Input: +// IN OUT SMM_LOCATE_POSITION *Position, +// OUT VOID **Interface +// +// Output: +// SMM_IHANDLE +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +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; +} + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// 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. +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +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; +} + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// 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. +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +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; +} + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Procedure: SmmCoreFindSmiEntry +// +// Description: Find Smi Entry +// +// Input: +// IN EFI_GUID *HandlerType +// IN BOOLEAN Create +// +// Output: SMM_SMI_ENTRY +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +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; +} + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// 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 +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +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 +}; + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// 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 +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +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; +} + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// 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 +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +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; +} + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// 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 +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +VOID InitializeListHead ( + IN EFI_LIST_ENTRY *List +) +{ + List->ForwardLink = List; + List->BackLink = List; +} + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// 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 +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +BOOLEAN IsListEmpty ( + IN EFI_LIST_ENTRY *List +) +{ + return (BOOLEAN)(List->ForwardLink == List); +} + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// 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 +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +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 +} + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Procedure: InitializeSmmPiSystemTable +// +// Description: +// Initialize SMM PI System Table. +// +// Input: VOID +// +// Output: VOID +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +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 ** +//** ** +//************************************************************************* +//************************************************************************* diff --git a/Core/EM/SMM/SmmPrivateShared.h b/Core/EM/SMM/SmmPrivateShared.h new file mode 100644 index 0000000..46f94e9 --- /dev/null +++ b/Core/EM/SMM/SmmPrivateShared.h @@ -0,0 +1,392 @@ +//************************************************************************* +//************************************************************************* +//** ** +//** (C)Copyright 1985-2009, American Megatrends, Inc. ** +//** ** +//** All Rights Reserved. ** +//** ** +//** 5555 Oakbrook Parkway, Suite 200, Norcross, GA 30093 ** +//** ** +//** Phone: (770)-246-8600 ** +//** ** +//************************************************************************* +//************************************************************************* + +//********************************************************************** +// $Header: /Alaska/SOURCE/Modules/SMM/SmmPrivateShared.h 36 4/01/11 10:08a Markw $ +// +// $Revision: 36 $ +// +// $Date: 4/01/11 10:08a $ +//********************************************************************** +// Revision History +// ---------------- +// $Log: /Alaska/SOURCE/Modules/SMM/SmmPrivateShared.h $ +// +// 36 4/01/11 10:08a 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, SmmPrivateShared.h, +// SmmHdr.equ, SmmInit.c +// +// +// 35 2/07/11 4:07p 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 +// +// 34 8/11/09 11:46a Markw +// Removed Legacy registration. This is removed from latest PI and not +// used by projects. +// +// 33 7/08/09 8:04p Markw +// Update headers. +// +// 32 1/22/09 12:59p Markw +// EIP #18671 (OPEN) Clear SW SMI status and set EOS inside SMM. Add +// SmmControl to private structure. +// +// 31 12/24/08 10:53a Markw +// EIP #18423: Adjust EBDA location as more EBDA data is allocated. +// +// 30 12/23/08 2:15p Markw +// EIP #17900 Set up TSS. Borland C in DOS hangs otherwise. +// +// 29 11/21/08 4:56p Markw +// Add SmmInit to SMM_ENTRY_STRUCT for SMM init for first normal/S3 boot. +// 32-bit CPU count. +// +// 28 9/26/08 4:52p Markw +// The Private InSmm is now a pointer. +// +// 27 9/09/08 3:05p Markw +// Add in SMM_BASE_PRIVATE_STRUCT, Dispatcher pe32 Image Start. +// +// 26 9/07/08 12:41a Markw +// Separate SMM Private structure into inside SMM and outside SMM +// structure. +// +// 25 8/28/08 3:51p Markw +// Added support for saving/restoring chipset context. +// +// 24 6/09/08 5:57p Markw +// Add SMM_CPU_INFO for Cpu specific information in the Private structure. +// +// 23 5/23/08 11:18a Markw +// Add member for disallowing callbacks. +// +// 22 4/04/08 6:21p Markw +// Add Smrr MSR to SMM_BASE_PRIVATE_STRUCT. +// +// 21 3/03/08 6:35p Markw +// Added 32-bit register for smm thunk. +// +// 20 11/14/07 2:03p Markw +// Added SMRR support and updated SMM Cache for non-SMRR. +// +// 19 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. +// +// 18 10/24/07 12:00p Markw +// SMM Thunk code position independent. Data in a separate segment than +// code in Smm Thunk. +// +// 17 9/10/07 1:38p Markw +// Add IDT entry. +// +// 16 6/08/07 6:51p Markw +// Save/Restore XMM. +// +// 15 1/11/07 12:28p Markw +// Adjusted location of fields in structure for removal of legacy. +// +// 14 1/09/07 6:40p Markw +// Update BSP Entry Structure to remove dependencies on SMM_BSP_BASE. +// +// 13 12/29/06 4:44p Markw +// Add Smm Cache Support and update CPU syncronization. +// +// 12 12/21/06 5:19p Markw +// Remove old unused SmmStackSize from Private structure. +// +// 11 11/13/06 11:24a Markw +// Updated structure for Ap Entry. +// +// 10 9/18/06 11:47a Markw +// Add a check to guarentee that BSP and Ap can't get out of sync. +// +// 9 8/24/06 3:27p Felixp +// Preliminary x64 support (work in progress) +// +// 8 5/08/06 6:47p Markw +// Use Hob for initalizing SMM. +// +// 7 2/03/06 10:26a Markw +// Moved Smm Base change to PEI CPU. +// +// 6 1/13/06 11:27a Markw +// Added SMM Thunk support. +// +// 5 1/10/06 2:56p Markw +// Add support for multi-threadding and sync all CPUs during entry/exit of +// SMM. +// +// 4 8/10/05 5:01p Markw +// Added ChangeBaseInfo Structure for changing bases and passing +// information to a runtime function. +// +// 3 7/12/05 11:08a Markw +// Added TSEG start to private structure. +// +// 2 7/11/05 1:05p Markw +// Removed isCallback from structure. Chaged Io Port from UINT8 to UINT16. +// +// 1 1/28/05 4:29p Sivagarn +// Generic SMM module - Intial Check in +// +// +//********************************************************************** + +//<AMI_FHDR_START> +//--------------------------------------------------------------------------- +// +// Name: SMMPrivateShared.h +// +// Description: Header file for the SMM shared equates and structures +// +//--------------------------------------------------------------------------- +//<AMI_FHDR_END> + +#ifndef __SMM_PRIVATE_SHARED__H__ +#define __SMM_PRIVATE_SHARED__H__ + +#include <efi.h> +#include <Protocol\SmmThunk.h> + +#if defined(PI_SPECIFICATION_VERSION)&&(PI_SPECIFICATION_VERSION>=0x00010000) +#define USE_FV2 1 +#else +#define USE_FV2 0 +#endif + +#define SMM_USE_FRAMEWORK 1 + +#if defined(PI_SPECIFICATION_VERSION)&&(PI_SPECIFICATION_VERSION>=0x0001000A) +#define SMM_USE_PI 1 +#else +#define SMM_USE_PI 0 +#endif + +#include <AmiHobs.h> +#include <Token.h> + +#ifdef __cplusplus +extern "C" { +#endif + +#define SMMBASE_CALLBACK 0xf0 +typedef struct _SMM_ENTRY_INIT_STRUCT SMM_ENTRY_INIT_STRUCT; +typedef struct _SMM_THUNK_DATA SMM_THUNK_DATA; + +typedef VOID (*SMM_AP_PROCEDURE) ( + IN VOID *Buffer +); + +typedef struct { + SMM_AP_PROCEDURE Procedure; + VOID *ProcArguments; +} SMM_AP_CPU_CONTROL; + + +typedef struct _HANDLER_LIST HANDLER_LIST; +struct _HANDLER_LIST +{ + EFI_GUID HandlerType; //Only filled if non-root. + VOID *EntryPoint; + EFI_HANDLE SmmImageHandle; + VOID *Context; + VOID *CommunicationBuffer; //Framework only + UINTN *SourceSize; //Framework only + + BOOLEAN IsRoot; + BOOLEAN IsPi; + HANDLER_LIST *Link; +}; + +typedef struct { + EFI_DEVICE_PATH_PROTOCOL *FilePath; + VOID *SourceBuffer; + UINTN SourceSize; + EFI_HANDLE *ImageHandle; + BOOLEAN LegacyIA32Binary; +} REGISTER_HANDLER_CALLBACK; + +typedef struct { + EFI_HANDLE ImageHandle; +} UNREGISTER_HANDLER_CALLBACK; + +typedef struct { + EFI_HANDLE ImageHandle; + VOID *CommunicationBuffer; + UINTN *SourceSize; +} COMMUNICATE_CALLBACK; + +typedef struct { + UINTN Size; + VOID **Buffer; +} ALLOCATE_POOL_CALLBACK; + +typedef struct { + VOID *Buffer; +} FREE_POOL_CALLBACK; + + +typedef union { + REGISTER_HANDLER_CALLBACK RegisterHandler; + UNREGISTER_HANDLER_CALLBACK UnregisterHandler; + COMMUNICATE_CALLBACK Communicate; + ALLOCATE_POOL_CALLBACK AllocatePool; + FREE_POOL_CALLBACK FreePool; +} CALLBACKS; + +#pragma pack (1) +typedef struct { + UINT16 Limit; + UINTN Base; //This shared between 32 bit and 64 bit. +} DESCRIPTOR_TABLE; +#pragma pack() + +typedef struct { + BOOLEAN InSmm; + UINT32 ApicId; +} SMM_CPU_INFO; + +typedef struct { + VOID (*CallBackFunc)(); + BOOLEAN *InSmm; + BOOLEAN DisallowCallbacks; + EFI_STATUS CallbackStatus; + VOID *Pe32DispatcherImage; + UINTN Pe32DispatcherImageSize; + + CALLBACKS CallbackParameters; + SMM_HOB *SmmHob; + VOID *SmmAllocMemoryStart; //Area to allocate memory + UINT32 SmmAllocMemoryLength; +} SMM_BASE_PRIVATE_STRUCT; + +typedef struct { + VOID *PageDirectories; + VOID **SmmXmmSave; + BOOLEAN SmrrEnable; + UINT32 SmrrMsr; + UINT32 TsegMsr; + UINT64 TsegMsrBase; + UINT64 TsegMsrMask; + DESCRIPTOR_TABLE Idt; + SMM_CPU_INFO *SmmCpuInfo; + + VOID (*SmmThunkProc)(); + SMM_THUNK_DATA *SmmThunkData; + UINT32 EbdaStartOffset; + UINT32 NumCpus; + UINT32 NumCpusInSmm; + + HANDLER_LIST *HandlerListHead; + BOOLEAN FloatingPointSave; + + volatile SMM_AP_CPU_CONTROL *SmmApCpuControl; + UINT32 SmmBspNumber; //This can change each SMM entry. + VOID *SmmControl; +} SMM_DISPATCHER_PRIVATE_STRUCT; + + +#pragma pack(1) +typedef struct { + UINT16 Offset; + UINT16 Segment; +} FAR_CALL_PTR_16; + +typedef struct { + UINT32 Stack; + UINT32 StackSize; +} STACK; + +typedef struct { + UINT16 Limit; + UINT32 Base; + UINT16 Rsv; //For alignment +} SMM_DESC; + +#pragma pack() + +struct _SMM_ENTRY_INIT_STRUCT { + UINT32 SmmInit; //This must be first. + UINT32 SmmEntrySize; + UINT32 GdtDescBaseOffset; + UINT32 LCodeSelBaseOffset; + UINT32 TssSelBaseOffset; + UINT32 SmmThunkProcOffset; + UINT32 SmmThunkLength; + UINT32 HtCpu; + VOID *SmmEntryStart; + VOID (*DispatcherEntry)(SMM_ENTRY_INIT_STRUCT *); + SMM_DISPATCHER_PRIVATE_STRUCT *DispatcherPrivate; + UINT8 *SmmStackTop; + UINT32 CpuNo; +}; + +struct _SMM_THUNK_DATA { + FAR_CALL_PTR_16 FarCall; + SMM_THUNK_IA32_REGISTER_SET_EX Regs; + STACK Stack; + UINT32 StackSave; + SMM_DESC GdtSave; + SMM_DESC IdtSave; + SMM_DESC LegacyIdtDesc; + UINT16 Below1MStack; +}; + +typedef EFI_STATUS (*DISPATCHER_ENTRY_POINT)( + 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 +); + + +typedef VOID (*EFI_SMM_SAVE_RESTORE_FUNCTION)(BOOLEAN Save); + + +/****** DO NOT WRITE BELOW THIS LINE *******/ +#ifdef __cplusplus +} +#endif +#endif + +//************************************************************************* +//************************************************************************* +//** ** +//** (C)Copyright 1985-2009, American Megatrends, Inc. ** +//** ** +//** All Rights Reserved. ** +//** ** +//** 5555 Oakbrook Parkway, Suite 200, Norcross, GA 30093 ** +//** ** +//** Phone: (770)-246-8600 ** +//** ** +//************************************************************************* +//************************************************************************* diff --git a/Core/EM/SMM/Smst.c b/Core/EM/SMM/Smst.c new file mode 100644 index 0000000..8ac8add --- /dev/null +++ b/Core/EM/SMM/Smst.c @@ -0,0 +1,917 @@ +//************************************************************************* +//************************************************************************* +//** ** +//** (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/Smst.c 2 11/21/12 4:07a Wesleychen $ +// +// $Revision: 2 $ +// +// $Date: 11/21/12 4:07a $ +//********************************************************************** +// Revision History +// ---------------- +// $Log: /Alaska/Projects/Intel/Haswell/LynxPoint_SharkBay-DT_Crb_1AQQW/Core/EM/SMM/Smst.c $ +// +// 2 11/21/12 4:07a Wesleychen +// Support Intel PFAT. +// +// 25 3/14/11 3:18p Markw +// Rename gSmmFirmwareVender to gSmmFirmwareVendor. +// +// 24 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 +// +// 23 6/18/10 12:29p Markw +// Fix history log. +// +// 22 4/22/10 6:22p Markw +// Support /w4 compilier option. +// +// 21 2/25/10 5:16p Markw +// Add support for all APs to execute non-blocking. +// Fixed issue with memory allocation +// +// 20 2/12/10 3:54p Markw +// Update SmmSmstAllocatePages for AllocateAddress to return correct +// Status. +// +// 19 5/08/09 10:55a Markw +// Header updates. +// +// 18 11/05/08 5:25p Markw +// Fix SMM Allocate Pool of type AllocateMaxAddress. +// +// 17 9/09/08 4:30p Markw +// Add headers. +// +// 16 9/07/08 12:45a Markw +// Separate SMM Private structure into inside SMM and outside SMM +// structure. Remove access to BS function for CRC. +// +// 15 6/09/08 5:47p Markw +// CPU0 has its own AP control structure. CPU0 can now be the AP. +// +// 14 3/14/07 5:57p Markw +// Only allow SmmStartupThisAp if all CPUs are in SMM. +// +//********************************************************************** + +//<AMI_FHDR_START> +//--------------------------------------------------------------------------- +// +// Name: Smst.c +// +// Description: Smst functions. +// +//--------------------------------------------------------------------------- +//<AMI_FHDR_END> + +//This include should come first. +#include "SmmPrivateShared.h" +#include <AmiDxeLib.h> +#include <AmiCspLib.h> + +#if SMM_USE_FRAMEWORK +#include <Smm.h> +#endif + +#if SMM_USE_PI +#include <SmmPi.h> +#endif + +#include "ReferenceCode\Haswell\Include\CpuRegs.h" +#ifndef BIT35 +#define BIT35 0x0000000800000000ULL +#endif + +//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); + +UINT8* Align2n(UINT8 *Value,UINTN Alignment); + +#if SMM_USE_FRAMEWORK + +EFI_STATUS CalculateCrc32( + IN VOID *Data, IN UINTN DataSize, OUT UINT32 *Crc32 +); + +extern EFI_SMM_SYSTEM_TABLE gSmmSystemTable; +extern UINT8 **gSmmBase; +#endif + +#if SMM_USE_PI +extern EFI_SMM_SYSTEM_TABLE2 gSmmSystemTable2; +#endif + + +extern SMM_DISPATCHER_PRIVATE_STRUCT *gDispatcherPrivate; + +static UINT32 CrcTable[256]; + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Procedure: InitCrc +// +// Description: InitCrc +// +// Input: VOID +// +// Output: VOID +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +VOID InitCrc() +{ + UINT32 i, j; + for(i = 0; i < 256; i++) { + CrcTable[i] = i; + for(j = 8; j > 0; j--) + CrcTable[i] = + (CrcTable[i] & 1) ? (CrcTable[i] >> 1) ^ 0xedb88320 : CrcTable[i] >> 1; + } +} + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Procedure: CalculateCrc32 +// +// Description: Calculate Crc 32 +// +// Input: +// IN VOID *Data +// IN UINTN DataSize +// OUT UINT32 *Crc32 +// +// Output: +// EFI_STATUS +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +EFI_STATUS CalculateCrc32( + IN VOID *Data, IN UINTN DataSize, OUT UINT32 *Crc32 +) +{ + UINT32 i, crc = (UINT32)-1; + if (!Data || !DataSize || !Crc32) return EFI_INVALID_PARAMETER; + for(i = 0; i < DataSize; i++) crc = (crc >> 8) ^ CrcTable[(UINT8)crc ^ ((UINT8*)Data)[i]]; + *Crc32 = ~crc; + return EFI_SUCCESS; +} + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Procedure: SmmMemRead +// +// Description: Read memory buffer. +// +// Input: +// IN EFI_SMM_CPU_IO_INTERFACE *This +// IN EFI_SMM_IO_WIDTH Width +// IN UINT64 Address +// IN UINTN Count +// IN OUT VOID *Buffer +// +// Output: +// EFI_STATUS +// * EFI_SUCCESS - Buffer written Successfully. +// * EFI_INVALID_PARAMETER - 0 Count, Unsupported Width, or memory region out of range. +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +EFI_STATUS SmmMemRead( + IN EFI_SMM_CPU_IO_INTERFACE *This, + IN EFI_SMM_IO_WIDTH Width, + IN UINT64 Address, + IN UINTN Count, + IN OUT VOID *Buffer +) +{ + UINT8 ByteWidth; + if (Width >= (UINTN)SMM_IO_UINT64) return EFI_INVALID_PARAMETER; + if (!Count) return EFI_INVALID_PARAMETER; + + ByteWidth = (UINT8)(1 << Width); + + + //Alignment must be done by the caller. + switch(ByteWidth) { + case 1: + while(Count--) { + *(UINT8*)Buffer = *(UINT8*)(UINTN)Address; + ++((UINT8*)(UINTN)Buffer); + ++((UINT8*)(UINTN)Address); + } + break; + case 2: + while(Count--) { + *(UINT16*)Buffer = *(UINT16*)(UINTN)Address; + ++((UINT16*)(UINTN)Buffer); + ++((UINT16*)(UINTN)Address); + } + break; + default: //case 4: + while(Count--) { + *(UINT32*)Buffer = *(UINT32*)(UINTN)Address; + ++((UINT32*)(UINTN)Buffer); + ++((UINT32*)(UINTN)Address); + } + break; + } + + return EFI_SUCCESS; +} + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Procedure: SmmMemWrite +// +// Description: Write to memory from buffer. +// +// Input: +// IN EFI_SMM_CPU_IO_INTERFACE *This +// IN EFI_SMM_IO_WIDTH Width +// IN UINT64 Address +// IN UINTN Count +// IN OUT VOID *Buffer +// +// Output: +// EFI_STATUS +// * EFI_SUCCESS - Buffer written Successfully. +// * EFI_INVALID_PARAMETER - 0 Count, Unsupported Width, or memory region out of range. +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +EFI_STATUS SmmMemWrite( + IN EFI_SMM_CPU_IO_INTERFACE *This, + IN EFI_SMM_IO_WIDTH Width, + IN UINT64 Address, + IN UINTN Count, + IN OUT VOID *Buffer + ) +{ + UINT8 ByteWidth; + if (Width >= (UINTN)SMM_IO_UINT64) return EFI_INVALID_PARAMETER; + if (!Count) return EFI_INVALID_PARAMETER; + + //Alignment must be done by the caller. + ByteWidth = (UINT8)(1 << Width); + + switch(ByteWidth) { + case 1: + while(Count--) { + *(UINT8*)(UINTN)Address = *(UINT8*)(UINTN)Buffer; + ++((UINT8*)(UINTN)Buffer); + ++((UINT8*)(UINTN)Address); + } + break; + case 2: + while(Count--) { + *(UINT16*)(UINTN)Address = *(UINT16*)(UINTN)Buffer; + ++((UINT16*)(UINTN)Buffer); + ++((UINT16*)(UINTN)Address); + } + break; + default: //case 4: + while(Count--) { + *(UINT32*)(UINTN)Address = *(UINT32*)(UINTN)Buffer; + ++((UINT32*)(UINTN)Buffer); + ++((UINT32*)(UINTN)Address); + } + break; + } + + return EFI_SUCCESS; +} + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Procedure: SmmIoRead +// +// Description: Read io buffer. +// +// Input: +// IN EFI_SMM_CPU_IO_INTERFACE *This +// IN EFI_SMM_IO_WIDTH Width +// IN UINT64 Address +// IN UINTN Count +// IN OUT VOID *Buffer +// +// Output: +// EFI_STATUS +// * EFI_SUCCESS - Buffer written Successfully. +// * EFI_INVALID_PARAMETER - 0 Count, Unsupported Width, or memory region out of range. +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +EFI_STATUS SmmIoRead( + IN EFI_SMM_CPU_IO_INTERFACE *This, + IN EFI_SMM_IO_WIDTH Width, + IN UINT64 Address, + IN UINTN Count, + IN OUT VOID *Buffer + ) +{ + UINT8 ByteWidth; + if (Width >= (UINTN)SMM_IO_UINT64) return EFI_INVALID_PARAMETER; + if (!Count) return EFI_INVALID_PARAMETER; + + ByteWidth = (UINT8)(1 << Width); + + if (Address + ByteWidth * Count > 0x10000) return EFI_INVALID_PARAMETER; //Beyond IO space. + if ((UINT64)(UINTN)Buffer + ByteWidth * Count > (UINT64)0x100000000) return EFI_INVALID_PARAMETER; //Beyond address space. + + //Alignment must be done by the caller. + switch(ByteWidth) { + case 1: + while(Count--) { + *(UINT8*)Buffer = IoRead8((UINT16)Address); + ++((UINT8*)(UINTN)Buffer); + ++((UINT8*)(UINTN)Address); + } + break; + case 2: + while(Count--) { + *(UINT16*)(UINTN)Buffer = IoRead16((UINT16)Address); + ++((UINT16*)(UINTN)Buffer); + ++((UINT16*)(UINTN)Address); + } + break; + default: //case 4: + while(Count--) { + *(UINT32*)Buffer = IoRead32((UINT16)Address); + ++((UINT32*)(UINTN)Buffer); + ++((UINT32*)(UINTN)Address); + } + break; + } + + return EFI_SUCCESS; +} + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Procedure: SmmIoWrite +// +// Description: Write to Io from buffer. +// +// Input: +// IN EFI_SMM_CPU_IO_INTERFACE *This +// IN EFI_SMM_IO_WIDTH Width +// IN UINT64 Address +// IN UINTN Count +// IN OUT VOID *Buffer +// +// Output: +// EFI_STATUS +// * EFI_SUCCESS - Buffer written Successfully. +// * EFI_INVALID_PARAMETER - 0 Count, Unsupported Width, or memory region out of range. +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +EFI_STATUS SmmIoWrite( + IN EFI_SMM_CPU_IO_INTERFACE *This, + IN EFI_SMM_IO_WIDTH Width, + IN UINT64 Address, + IN UINTN Count, + IN OUT VOID *Buffer + ) +{ + UINT8 ByteWidth; + if (Width >= (UINTN)SMM_IO_UINT64) return EFI_INVALID_PARAMETER; + if (!Count) return EFI_INVALID_PARAMETER; + + ByteWidth = (UINT8)(1 << Width); + + if (Address + ByteWidth * Count > 0x10000) return EFI_INVALID_PARAMETER; //Beyond IO space. + if ((UINT64)(UINTN)Buffer + ByteWidth * Count > (UINT64)0x100000000) return EFI_INVALID_PARAMETER; //Beyond address space. + + //Alignment must be done by the caller. + switch(ByteWidth) { + case 1: + while(Count--) { + IoWrite8((UINT16)Address,*(UINT8*)(UINTN)Buffer); + ++((UINT8*)(UINTN)Buffer); + ++((UINT8*)(UINTN)Address); + } + break; + case 2: + while(Count--) { + IoWrite16((UINT16)Address,*(UINT16*)(UINTN)Buffer); + ++((UINT16*)(UINTN)Buffer); + ++((UINT16*)(UINTN)Address); + } + break; + default: //case 4: + while(Count--) { + IoWrite32((UINT16)Address,*(UINT32*)(UINTN)Buffer); + ++((UINT32*)(UINTN)Buffer); + ++((UINT32*)(UINTN)Address); + } + break; + } + + return EFI_SUCCESS; +} + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Procedure: SmmSmstAllocatePool +// +// Description: Allocate a pool of memory. +// +// Input: +// IN EFI_MEMORY_TYPE PoolType +// IN UINTN Size +// OUT VOID **Buffer +// +// Output: +// EFI_STATUS +// * EFI_SUCCESS - Pool of memory allocated. +// * EFI_INVALID_PARAMETER - Allocate 0 size. +// * EFI_OUT_OF_RESOURCES - Memory unavailable. +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +EFI_STATUS SmmSmstAllocatePool( + IN EFI_MEMORY_TYPE PoolType, + IN UINTN Size, + OUT VOID **Buffer + ) +{ + if (!Size) return EFI_INVALID_PARAMETER; + *Buffer = Allocate(0,Size,0); + if (!(*Buffer)) return EFI_OUT_OF_RESOURCES; + return EFI_SUCCESS; +} + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Procedure: SmmSmstFreePool +// +// Description: Free Allocated memory. +// +// Input: +// IN VOID *Buffer +// +// Output: +// EFI_STATUS +// * EFI_SUCCESS - Memory is freed. +// * EFI_INVALID_PARAMETER - Memory starting at Buffer was not allocated. +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +EFI_STATUS SmmSmstFreePool( + IN VOID *Buffer + ) +{ + if (!Free(Buffer)) return EFI_INVALID_PARAMETER; + return EFI_SUCCESS; +} + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Procedure: SmmSmstAllocatePages +// +// Description: Allocate # pages at any address, a max address, or a specified address. +// +// Input: +// IN EFI_ALLOCATE_TYPE Type +// IN EFI_MEMORY_TYPE MemoryType +// IN UINTN NumberOfPages +// OUT EFI_PHYSICAL_ADDRESS *Memory +// +// Output: +// EFI_STATUS +// * EFI_SUCCESS - Memory allocated. +// * EFI_OUT_OF_RESOURCES - Memory already allocated or unavailable. +// * EFI_INVALID_PARAMETER - Incorrect Type or specified address not 4k aligned. +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +EFI_STATUS SmmSmstAllocatePages( + IN EFI_ALLOCATE_TYPE Type, + IN EFI_MEMORY_TYPE MemoryType, + IN UINTN NumberOfPages, + IN OUT EFI_PHYSICAL_ADDRESS *Memory + ) +{ + VOID *AllocatedMemory; + + if (!NumberOfPages) return EFI_INVALID_PARAMETER; + if (Type != AllocateAnyPages && *Memory <= 0x100000) return AllocateABSegPages(Type, NumberOfPages, Memory); + + switch(Type) { + case AllocateAnyPages: + *Memory = (EFI_PHYSICAL_ADDRESS)(UINTN)Allocate(0, NumberOfPages * 4096, 4095); + if (!(*Memory)) return EFI_OUT_OF_RESOURCES; + return EFI_SUCCESS; + + case AllocateMaxAddress: + AllocatedMemory = Allocate(0, NumberOfPages * 4096, 4095); + if (!AllocatedMemory) return EFI_OUT_OF_RESOURCES; + if ((UINTN)AllocatedMemory > *(UINTN*)(UINTN)Memory) { + Free(AllocatedMemory); + return EFI_OUT_OF_RESOURCES; + } + *Memory = (EFI_PHYSICAL_ADDRESS)(UINTN)AllocatedMemory; + return EFI_SUCCESS; + case AllocateAddress: + if ((UINT8*)(UINTN)*Memory != Align2n((UINT8*)(UINTN)*Memory,4095)) return EFI_INVALID_PARAMETER; + AllocatedMemory = Allocate((UINT8*)(UINTN)*Memory,NumberOfPages * 4096,0); + if (!AllocatedMemory) return EFI_OUT_OF_RESOURCES; + return EFI_SUCCESS; + } + return EFI_INVALID_PARAMETER; +} + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Procedure: SmmSmstFreePages +// +// Description: +// Free pages. The address must be on a page boundary, but it doesn't have to +// start on address from AllocatePages. It only frees the requested pages. +// +// Input: +// IN EFI_PHYSICAL_ADDRESS Memory +// IN UINTN NumberOfPages +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +EFI_STATUS SmmSmstFreePages( + IN EFI_PHYSICAL_ADDRESS Memory, + IN UINTN NumberOfPages + ) +{ + if (Memory <= 0x100000) return FreeABSegPages(Memory, NumberOfPages); + + if (!Free4kPages((VOID*)(UINTN)Memory,NumberOfPages)) return EFI_INVALID_PARAMETER; + return EFI_SUCCESS; +} + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Procedure: SmmStartupThisAp +// +// Description: Execute a procedure on an AP. +// +// Input: +// IN EFI_AP_PROCEDURE Procedure +// IN UINTN CpuNumber +// IN OUT VOID *ProcArguments OPTIONAL +// +// Output: +// EFI_STATUS +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +EFI_STATUS SmmStartupThisAp( + IN EFI_AP_PROCEDURE Procedure, + IN UINTN CpuNumber, + IN OUT VOID *ProcArguments OPTIONAL +) +{ + volatile SMM_AP_CPU_CONTROL *SmmApCpuControl; + BOOLEAN IsBlocking = (BOOLEAN)(CpuNumber != (UINTN)-1); + UINT32 i; + + if (Procedure == NULL) return EFI_INVALID_PARAMETER; + if (CpuNumber == gDispatcherPrivate->SmmBspNumber) return EFI_INVALID_PARAMETER; + if (CpuNumber >= gDispatcherPrivate->NumCpus && IsBlocking) return EFI_INVALID_PARAMETER; + + if (IsBlocking) { + if (!gDispatcherPrivate->SmmCpuInfo[CpuNumber].InSmm) return EFI_NOT_READY; + SmmApCpuControl = &gDispatcherPrivate->SmmApCpuControl[CpuNumber]; + + SmmApCpuControl->ProcArguments = ProcArguments; + SmmApCpuControl->Procedure = Procedure; + + if ( !((ReadMsr (MSR_PLATFORM_INFO) & B_MSR_PLATFORM_INFO_PFAT_AVAIL) && + (ReadMsr (MSR_PLAT_FRMW_PROT_CTRL) & B_MSR_PLAT_FRMW_PROT_CTRL_EN)) ) { + while(SmmApCpuControl->Procedure) CPULib_Pause(); + } + return EFI_SUCCESS; + } + + for (i = 0; i < gDispatcherPrivate->NumCpus; ++i) { + if (i == gDispatcherPrivate->SmmBspNumber) continue; + if (!gDispatcherPrivate->SmmCpuInfo[i].InSmm) continue; + SmmApCpuControl = &gDispatcherPrivate->SmmApCpuControl[i]; + ASSERT(SmmApCpuControl->Procedure == NULL); + if (SmmApCpuControl->Procedure != NULL) continue; + + SmmApCpuControl->ProcArguments = ProcArguments; + SmmApCpuControl->Procedure = Procedure; + } + + return EFI_SUCCESS; +} + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Procedure: MoveToNewConfigurationTable +// +// Description: Create a new bigger or smaller table and copy the old table to the new table. +// +// Input: +// IN EFI_CONFIGURATION_TABLE *OldTable +// IN UINTN NumOldDescriptors +// IN UINTN NumDescriptors +// +// Output: +// EFI_CONFIGURATION_TABLE * - New table address. +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +EFI_CONFIGURATION_TABLE * MoveToNewConfigurationTable( + EFI_CONFIGURATION_TABLE *OldTable, + UINTN NumOldDescriptors, + UINTN NumDescriptors + ) +{ + EFI_CONFIGURATION_TABLE *NewTable,*Descriptor,*OldDescriptor; + UINTN i; + //Create new table + if (SmmSmstAllocatePool(0,NumDescriptors * sizeof(EFI_CONFIGURATION_TABLE),&NewTable)!=EFI_SUCCESS) return 0; + + //If new table is larger, only copy valid descriptors. + //If new table is smaller, only copy descriptors for allocated table. + NumDescriptors = NumDescriptors > NumOldDescriptors ? NumOldDescriptors : NumDescriptors; + Descriptor = NewTable; + OldDescriptor = OldTable; + for (i=0;i<NumDescriptors;++i) *Descriptor++ = *OldDescriptor++; + + //Free old table + SmmSmstFreePool(OldTable); + + return NewTable; +} + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Procedure: SmmInstallConfigurationTable +// +// Description: +// This procedure add/updates/deletes configuration table entries. +// +// Configuration Table Entry definition: +// EFI_GUID VendorGuid +// VOID *VenderTable +// +// 1. If Vendor Guid is not in table and Input table isn't NULL, add Guid/Table pair. +// 2. If Vendor Guid is in table and Input table isn't NULL, update Guid/Table pair. +// 3. If Vendor Guid is in table and Input table is NULL, remove Guid/Tablble pair. +// 4. If Vendor Guid is not in table, Input table is NULL, return EFI_NOT_FOUND. Nothing to delete. +// +// Input: +// IN EFI_SMM_SYSTEM_TABLE *SystemTable +// IN EFI_GUID *Guid +// IN VOID *Table +// IN UINTN TableSize +// +// Output: +// EFI_STATUS +// * EFI_SUCCESS - Add/update/remove operation successful. +// * EFI_INVALID_PARAMETER - Guid = 0. +// * EFI_NOT_FOUND - Can not delete a nonexistent entry. +// * EFI_OUT_OF_RESOURCES - Not enough memory to complete operation. +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +EFI_STATUS SmmInstallConfigurationTable( +#if SMM_USE_FRAMEWORK + IN EFI_SMM_SYSTEM_TABLE *SystemTable, +#else + IN EFI_SMM_SYSTEM_TABLE2 *SystemTable, +#endif + IN EFI_GUID *Guid, + IN VOID *Table, + IN UINTN TableSize + ) +{ + UINTN i; + UINT32 CRC32; + +#if SMM_USE_PI + EFI_CONFIGURATION_TABLE **FirstEntryPtr = &gSmmSystemTable2.SmmConfigurationTable; + EFI_CONFIGURATION_TABLE *Entry = *FirstEntryPtr; + UINTN *NumberOfTableEntries = &gSmmSystemTable2.NumberOfTableEntries; + UINT32 SystemTableSize = sizeof(gSmmSystemTable2); + #else + EFI_CONFIGURATION_TABLE **FirstEntryPtr = &gSmmSystemTable.SmmConfigurationTable; + EFI_CONFIGURATION_TABLE *Entry = *FirstEntryPtr; + UINTN *NumberOfTableEntries = &gSmmSystemTable.NumberOfTableEntries; + UINT32 SystemTableSize = sizeof(gSmmSystemTable); +#endif + + EFI_CONFIGURATION_TABLE *NewConfigTable; + VOID *NewVendorTable; + + if (!Guid) return EFI_INVALID_PARAMETER; + + for (i=0;i < *NumberOfTableEntries;++i) { + if (guidcmp(&Entry->VendorGuid,Guid)==0) break; + ++Entry; + } + if (i == *NumberOfTableEntries) Entry=0; + + if (!Entry) { + if (!Table) return EFI_NOT_FOUND; + //Add Guid + NewConfigTable = MoveToNewConfigurationTable( + *FirstEntryPtr, + *NumberOfTableEntries, + *NumberOfTableEntries+1); + if (!NewConfigTable) return EFI_OUT_OF_RESOURCES; + + if (SmmSmstAllocatePool(0,TableSize,&NewVendorTable)!=EFI_SUCCESS) return EFI_OUT_OF_RESOURCES; + MemCpy(NewVendorTable,Table,TableSize); + *FirstEntryPtr = NewConfigTable; + ++(*NumberOfTableEntries); + NewConfigTable[*NumberOfTableEntries - 1].VendorGuid = *Guid; + NewConfigTable[*NumberOfTableEntries - 1].VendorTable = NewVendorTable; + } else { + if (!Table) { + //Remove Guid + EFI_CONFIGURATION_TABLE *LastEntry = *FirstEntryPtr + *NumberOfTableEntries; + + SmmSmstFreePool(Entry->VendorTable); + + while (Entry != LastEntry) { + *Entry = *(Entry + 1); + ++Entry; + } + + --(*NumberOfTableEntries); + } else { + //Update Guid + if (SmmSmstAllocatePool(0,TableSize,&NewVendorTable)!=EFI_SUCCESS) return EFI_OUT_OF_RESOURCES; + MemCpy(NewVendorTable,Table,TableSize); + + SmmSmstFreePool(Entry->VendorTable); + Entry->VendorTable = NewVendorTable; + } + } + +#if SMM_USE_PI && SMM_USE_FRAMEWORK + gSmmSystemTable.SmmConfigurationTable = gSmmSystemTable2.SmmConfigurationTable; + gSmmSystemTable.NumberOfTableEntries = gSmmSystemTable2.NumberOfTableEntries; +#endif + +#if SMM_USE_PI + gSmmSystemTable2.Hdr.CRC32 = 0; + CalculateCrc32(&gSmmSystemTable2, SystemTableSize, &CRC32); + gSmmSystemTable2.Hdr.CRC32 = CRC32; +#endif + +#if SMM_USE_FRAMEWORK + gSmmSystemTable.Hdr.CRC32 = 0; + CalculateCrc32(&gSmmSystemTable, sizeof(EFI_SMM_SYSTEM_TABLE), &CRC32); + gSmmSystemTable.Hdr.CRC32 = CRC32; +#endif + + return EFI_SUCCESS; +} + + +#if SMM_USE_FRAMEWORK + +////////////////////////////////////////// +extern CHAR16 gSmmFirmwareVendor[]; +EFI_SMM_SYSTEM_TABLE gSmmSystemTable = +{ + { //Header + SMM_SMST_SIGNATURE, //Signature + EFI_SMM_SYSTEM_TABLE_REVISION, //Revision + sizeof(EFI_SMM_SYSTEM_TABLE), //Header size + 0, //CRC32 + 0 //Reserved + }, + gSmmFirmwareVendor, //Vendor + 0, //Vendor version + SmmInstallConfigurationTable, + EFI_SMM_CPU_IO_GUID, + { + { + SmmMemRead, + SmmMemWrite + }, + { SmmIoRead, + SmmIoWrite + } + }, + SmmSmstAllocatePool, + SmmSmstFreePool, + SmmSmstAllocatePages, + SmmSmstFreePages, + SmmStartupThisAp, + 1, //Executing CPU + 1, //Number of CPUs + 0, //Cpu Save State + 0, //Cpu Floating Point Save + 0, //Number of Table Entries + 0 //Table pointer +}; + + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Procedure: InitializeSmmSystemTable +// +// Description: Initialize the System Table. +// +// Input: SMM_BASE_PRIVATE_STRUCT *Private +// +// Output: VOID +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +VOID InitializeSmmSystemTable() +{ + UINT32 CRC32; + + gSmmSystemTable.NumberOfCpus = gDispatcherPrivate->NumCpus; + + gSmmSystemTable.CpuSaveState = Allocate(0,sizeof(EFI_SMM_CPU_SAVE_STATE) * gSmmSystemTable.NumberOfCpus,0); + gSmmSystemTable.CpuOptionalFloatingPointState = Allocate(0, 512 * gSmmSystemTable.NumberOfCpus, 15); //16 byte alignment, Save floating point context. + + CalculateCrc32(&gSmmSystemTable, sizeof(EFI_SMM_SYSTEM_TABLE), &CRC32); + gSmmSystemTable.Hdr.CRC32 = CRC32; +} + +#endif + +//************************************************************************* +//************************************************************************* +//** ** +//** (C)Copyright 1985-2011, American Megatrends, Inc. ** +//** ** +//** All Rights Reserved. ** +//** ** +//** 5555 Oakbrook Parkway, Suite 200, Norcross, GA 30093 ** +//** ** +//** Phone: (770)-246-8600 ** +//** ** +//************************************************************************* +//************************************************************************* |