--- /dev/null
+/** @file\r
+ SMM Driver Dispatcher Dependency Evaluator\r
+\r
+ This routine evaluates a dependency expression (DEPENDENCY_EXPRESSION) to determine\r
+ if a driver can be scheduled for execution. The criteria for\r
+ schedulability is that the dependency expression is satisfied.\r
+\r
+ Copyright (c) 2009 - 2010, Intel Corporation. All rights reserved.<BR>\r
+ This program and the accompanying materials are licensed and made available \r
+ under the terms and conditions of the BSD License which accompanies this \r
+ distribution. The full text of the license may be found at \r
+ http://opensource.org/licenses/bsd-license.php \r
+\r
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, \r
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. \r
+\r
+**/\r
+\r
+#include "PiSmmCore.h"\r
+\r
+///\r
+/// EFI_DEP_REPLACE_TRUE - Used to dynamically patch the dependecy expression\r
+/// to save time. A EFI_DEP_PUSH is evauated one an\r
+/// replaced with EFI_DEP_REPLACE_TRUE. If PI spec's Vol 2\r
+/// Driver Execution Environment Core Interface use 0xff\r
+/// as new DEPEX opcode. EFI_DEP_REPLACE_TRUE should be\r
+/// defined to a new value that is not conflicting with PI spec.\r
+///\r
+#define EFI_DEP_REPLACE_TRUE 0xff\r
+\r
+///\r
+/// Define the initial size of the dependency expression evaluation stack\r
+///\r
+#define DEPEX_STACK_SIZE_INCREMENT 0x1000\r
+\r
+//\r
+// Global stack used to evaluate dependency expressions\r
+//\r
+BOOLEAN *mDepexEvaluationStack = NULL;\r
+BOOLEAN *mDepexEvaluationStackEnd = NULL;\r
+BOOLEAN *mDepexEvaluationStackPointer = NULL;\r
+\r
+/**\r
+ Grow size of the Depex stack\r
+\r
+ @retval EFI_SUCCESS Stack successfully growed.\r
+ @retval EFI_OUT_OF_RESOURCES There is not enough system memory to grow the stack.\r
+\r
+**/\r
+EFI_STATUS\r
+GrowDepexStack (\r
+ VOID\r
+ )\r
+{\r
+ BOOLEAN *NewStack;\r
+ UINTN Size;\r
+\r
+ Size = DEPEX_STACK_SIZE_INCREMENT;\r
+ if (mDepexEvaluationStack != NULL) {\r
+ Size = Size + (mDepexEvaluationStackEnd - mDepexEvaluationStack);\r
+ }\r
+\r
+ NewStack = AllocatePool (Size * sizeof (BOOLEAN));\r
+ if (NewStack == NULL) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ if (mDepexEvaluationStack != NULL) {\r
+ //\r
+ // Copy to Old Stack to the New Stack\r
+ //\r
+ CopyMem (\r
+ NewStack,\r
+ mDepexEvaluationStack,\r
+ (mDepexEvaluationStackEnd - mDepexEvaluationStack) * sizeof (BOOLEAN)\r
+ );\r
+\r
+ //\r
+ // Free The Old Stack\r
+ //\r
+ FreePool (mDepexEvaluationStack);\r
+ }\r
+\r
+ //\r
+ // Make the Stack pointer point to the old data in the new stack\r
+ //\r
+ mDepexEvaluationStackPointer = NewStack + (mDepexEvaluationStackPointer - mDepexEvaluationStack);\r
+ mDepexEvaluationStack = NewStack;\r
+ mDepexEvaluationStackEnd = NewStack + Size;\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Push an element onto the Boolean Stack.\r
+\r
+ @param Value BOOLEAN to push.\r
+\r
+ @retval EFI_SUCCESS The value was pushed onto the stack.\r
+ @retval EFI_OUT_OF_RESOURCES There is not enough system memory to grow the stack.\r
+\r
+**/\r
+EFI_STATUS\r
+PushBool (\r
+ IN BOOLEAN Value\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+\r
+ //\r
+ // Check for a stack overflow condition\r
+ //\r
+ if (mDepexEvaluationStackPointer == mDepexEvaluationStackEnd) {\r
+ //\r
+ // Grow the stack\r
+ //\r
+ Status = GrowDepexStack ();\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+ }\r
+\r
+ //\r
+ // Push the item onto the stack\r
+ //\r
+ *mDepexEvaluationStackPointer = Value;\r
+ mDepexEvaluationStackPointer++;\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Pop an element from the Boolean stack.\r
+\r
+ @param Value BOOLEAN to pop.\r
+\r
+ @retval EFI_SUCCESS The value was popped onto the stack.\r
+ @retval EFI_ACCESS_DENIED The pop operation underflowed the stack.\r
+\r
+**/\r
+EFI_STATUS\r
+PopBool (\r
+ OUT BOOLEAN *Value\r
+ )\r
+{\r
+ //\r
+ // Check for a stack underflow condition\r
+ //\r
+ if (mDepexEvaluationStackPointer == mDepexEvaluationStack) {\r
+ return EFI_ACCESS_DENIED;\r
+ }\r
+\r
+ //\r
+ // Pop the item off the stack\r
+ //\r
+ mDepexEvaluationStackPointer--;\r
+ *Value = *mDepexEvaluationStackPointer;\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ This is the POSTFIX version of the dependency evaluator. This code does\r
+ not need to handle Before or After, as it is not valid to call this\r
+ routine in this case. The SOR is just ignored and is a nop in the grammer.\r
+ POSTFIX means all the math is done on top of the stack.\r
+\r
+ @param DriverEntry DriverEntry element to update.\r
+\r
+ @retval TRUE If driver is ready to run.\r
+ @retval FALSE If driver is not ready to run or some fatal error\r
+ was found.\r
+\r
+**/\r
+BOOLEAN\r
+SmmIsSchedulable (\r
+ IN EFI_SMM_DRIVER_ENTRY *DriverEntry\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINT8 *Iterator;\r
+ BOOLEAN Operator;\r
+ BOOLEAN Operator2;\r
+ EFI_GUID DriverGuid;\r
+ VOID *Interface;\r
+\r
+ Operator = FALSE;\r
+ Operator2 = FALSE;\r
+\r
+ if (DriverEntry->After || DriverEntry->Before) {\r
+ //\r
+ // If Before or After Depex skip as SmmInsertOnScheduledQueueWhileProcessingBeforeAndAfter ()\r
+ // processes them.\r
+ //\r
+ return FALSE;\r
+ }\r
+\r
+ if (DriverEntry->Depex == NULL) {\r
+ //\r
+ // A NULL Depex means that the SMM driver is not built correctly. \r
+ // All SMM drivers must have a valid depex expressiion.\r
+ //\r
+ ASSERT (FALSE);\r
+ return FALSE;\r
+ }\r
+\r
+ //\r
+ // Clean out memory leaks in Depex Boolean stack. Leaks are only caused by\r
+ // incorrectly formed DEPEX expressions\r
+ //\r
+ mDepexEvaluationStackPointer = mDepexEvaluationStack;\r
+\r
+\r
+ Iterator = DriverEntry->Depex;\r
+\r
+ while (TRUE) {\r
+ //\r
+ // Check to see if we are attempting to fetch dependency expression instructions\r
+ // past the end of the dependency expression.\r
+ //\r
+ if (((UINTN)Iterator - (UINTN)DriverEntry->Depex) >= DriverEntry->DepexSize) {\r
+ return FALSE;\r
+ }\r
+\r
+ //\r
+ // Look at the opcode of the dependency expression instruction.\r
+ //\r
+ switch (*Iterator) {\r
+ case EFI_DEP_BEFORE:\r
+ case EFI_DEP_AFTER:\r
+ //\r
+ // For a well-formed Dependency Expression, the code should never get here.\r
+ // The BEFORE and AFTER are processed prior to this routine's invocation.\r
+ // If the code flow arrives at this point, there was a BEFORE or AFTER\r
+ // that were not the first opcodes.\r
+ //\r
+ ASSERT (FALSE);\r
+ case EFI_DEP_SOR:\r
+ //\r
+ // These opcodes can only appear once as the first opcode. If it is found\r
+ // at any other location, then the dependency expression evaluates to FALSE\r
+ //\r
+ if (Iterator != DriverEntry->Depex) {\r
+ return FALSE;\r
+ }\r
+ //\r
+ // Otherwise, it is the first opcode and should be treated as a NOP.\r
+ //\r
+ break;\r
+\r
+ case EFI_DEP_PUSH:\r
+ //\r
+ // Push operator is followed by a GUID. Test to see if the GUID protocol\r
+ // is installed and push the boolean result on the stack.\r
+ //\r
+ CopyMem (&DriverGuid, Iterator + 1, sizeof (EFI_GUID));\r
+\r
+ Status = SmmLocateProtocol (&DriverGuid, NULL, &Interface);\r
+ if (EFI_ERROR (Status)) {\r
+ //\r
+ // For SMM Driver, it may depend on uefi protocols\r
+ //\r
+ Status = gBS->LocateProtocol (&DriverGuid, NULL, &Interface);\r
+ }\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ Status = PushBool (FALSE);\r
+ } else {\r
+ *Iterator = EFI_DEP_REPLACE_TRUE;\r
+ Status = PushBool (TRUE);\r
+ }\r
+ if (EFI_ERROR (Status)) {\r
+ return FALSE;\r
+ }\r
+\r
+ Iterator += sizeof (EFI_GUID);\r
+ break;\r
+\r
+ case EFI_DEP_AND:\r
+ Status = PopBool (&Operator);\r
+ if (EFI_ERROR (Status)) {\r
+ return FALSE;\r
+ }\r
+\r
+ Status = PopBool (&Operator2);\r
+ if (EFI_ERROR (Status)) {\r
+ return FALSE;\r
+ }\r
+\r
+ Status = PushBool ((BOOLEAN)(Operator && Operator2));\r
+ if (EFI_ERROR (Status)) {\r
+ return FALSE;\r
+ }\r
+ break;\r
+\r
+ case EFI_DEP_OR:\r
+ Status = PopBool (&Operator);\r
+ if (EFI_ERROR (Status)) {\r
+ return FALSE;\r
+ }\r
+\r
+ Status = PopBool (&Operator2);\r
+ if (EFI_ERROR (Status)) {\r
+ return FALSE;\r
+ }\r
+\r
+ Status = PushBool ((BOOLEAN)(Operator || Operator2));\r
+ if (EFI_ERROR (Status)) {\r
+ return FALSE;\r
+ }\r
+ break;\r
+\r
+ case EFI_DEP_NOT:\r
+ Status = PopBool (&Operator);\r
+ if (EFI_ERROR (Status)) {\r
+ return FALSE;\r
+ }\r
+\r
+ Status = PushBool ((BOOLEAN)(!Operator));\r
+ if (EFI_ERROR (Status)) {\r
+ return FALSE;\r
+ }\r
+ break;\r
+\r
+ case EFI_DEP_TRUE:\r
+ Status = PushBool (TRUE);\r
+ if (EFI_ERROR (Status)) {\r
+ return FALSE;\r
+ }\r
+ break;\r
+\r
+ case EFI_DEP_FALSE:\r
+ Status = PushBool (FALSE);\r
+ if (EFI_ERROR (Status)) {\r
+ return FALSE;\r
+ }\r
+ break;\r
+\r
+ case EFI_DEP_END:\r
+ Status = PopBool (&Operator);\r
+ if (EFI_ERROR (Status)) {\r
+ return FALSE;\r
+ }\r
+ return Operator;\r
+\r
+ case EFI_DEP_REPLACE_TRUE:\r
+ Status = PushBool (TRUE);\r
+ if (EFI_ERROR (Status)) {\r
+ return FALSE;\r
+ }\r
+\r
+ Iterator += sizeof (EFI_GUID);\r
+ break;\r
+\r
+ default:\r
+ goto Done;\r
+ }\r
+\r
+ //\r
+ // Skip over the Dependency Op Code we just processed in the switch.\r
+ // The math is done out of order, but it should not matter. That is\r
+ // we may add in the sizeof (EFI_GUID) before we account for the OP Code.\r
+ // This is not an issue, since we just need the correct end result. You\r
+ // need to be careful using Iterator in the loop as it's intermediate value\r
+ // may be strange.\r
+ //\r
+ Iterator++;\r
+ }\r
+\r
+Done:\r
+ return FALSE;\r
+}\r
--- /dev/null
+/** @file\r
+ SMM Driver Dispatcher.\r
+\r
+ Step #1 - When a FV protocol is added to the system every driver in the FV\r
+ is added to the mDiscoveredList. The SOR, Before, and After Depex are\r
+ pre-processed as drivers are added to the mDiscoveredList. If an Apriori\r
+ file exists in the FV those drivers are addeded to the\r
+ mScheduledQueue. The mFvHandleList is used to make sure a\r
+ FV is only processed once.\r
+\r
+ Step #2 - Dispatch. Remove driver from the mScheduledQueue and load and\r
+ start it. After mScheduledQueue is drained check the\r
+ mDiscoveredList to see if any item has a Depex that is ready to\r
+ be placed on the mScheduledQueue.\r
+\r
+ Step #3 - Adding to the mScheduledQueue requires that you process Before\r
+ and After dependencies. This is done recursively as the call to add\r
+ to the mScheduledQueue checks for Before and recursively adds\r
+ all Befores. It then addes the item that was passed in and then\r
+ processess the After dependecies by recursively calling the routine.\r
+\r
+ Dispatcher Rules:\r
+ The rules for the dispatcher are similar to the DXE dispatcher.\r
+\r
+ The rules for DXE dispatcher are in chapter 10 of the DXE CIS. Figure 10-3\r
+ is the state diagram for the DXE dispatcher\r
+\r
+ Depex - Dependency Expresion.\r
+ SOR - Schedule On Request - Don't schedule if this bit is set.\r
+\r
+ Copyright (c) 2009 - 2010, Intel Corporation. All rights reserved.<BR>\r
+ This program and the accompanying materials are licensed and made available \r
+ under the terms and conditions of the BSD License which accompanies this \r
+ distribution. The full text of the license may be found at \r
+ http://opensource.org/licenses/bsd-license.php \r
+\r
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, \r
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. \r
+\r
+**/\r
+\r
+#include "PiSmmCore.h"\r
+\r
+//\r
+// SMM Dispatcher Data structures\r
+//\r
+#define KNOWN_HANDLE_SIGNATURE SIGNATURE_32('k','n','o','w')\r
+typedef struct {\r
+ UINTN Signature;\r
+ LIST_ENTRY Link; // mFvHandleList\r
+ EFI_HANDLE Handle;\r
+} KNOWN_HANDLE;\r
+\r
+//\r
+// Function Prototypes\r
+//\r
+\r
+/**\r
+ Insert InsertedDriverEntry onto the mScheduledQueue. To do this you\r
+ must add any driver with a before dependency on InsertedDriverEntry first.\r
+ You do this by recursively calling this routine. After all the Befores are\r
+ processed you can add InsertedDriverEntry to the mScheduledQueue.\r
+ Then you can add any driver with an After dependency on InsertedDriverEntry\r
+ by recursively calling this routine.\r
+\r
+ @param InsertedDriverEntry The driver to insert on the ScheduledLink Queue\r
+\r
+**/\r
+VOID\r
+SmmInsertOnScheduledQueueWhileProcessingBeforeAndAfter (\r
+ IN EFI_SMM_DRIVER_ENTRY *InsertedDriverEntry\r
+ );\r
+\r
+//\r
+// The Driver List contains one copy of every driver that has been discovered.\r
+// Items are never removed from the driver list. List of EFI_SMM_DRIVER_ENTRY\r
+//\r
+LIST_ENTRY mDiscoveredList = INITIALIZE_LIST_HEAD_VARIABLE (mDiscoveredList);\r
+\r
+//\r
+// Queue of drivers that are ready to dispatch. This queue is a subset of the\r
+// mDiscoveredList.list of EFI_SMM_DRIVER_ENTRY.\r
+//\r
+LIST_ENTRY mScheduledQueue = INITIALIZE_LIST_HEAD_VARIABLE (mScheduledQueue);\r
+\r
+//\r
+// List of handles who's Fv's have been parsed and added to the mFwDriverList.\r
+//\r
+LIST_ENTRY mFvHandleList = INITIALIZE_LIST_HEAD_VARIABLE (mFvHandleList);\r
+\r
+//\r
+// Flag for the SMM Dispacher. TRUE if dispatcher is execuing.\r
+//\r
+BOOLEAN gDispatcherRunning = FALSE;\r
+\r
+//\r
+// Flag for the SMM Dispacher. TRUE if there is one or more SMM drivers ready to be dispatched\r
+//\r
+BOOLEAN gRequestDispatch = FALSE;\r
+\r
+//\r
+// List of file types supported by dispatcher\r
+//\r
+EFI_FV_FILETYPE mSmmFileTypes[] = {\r
+ EFI_FV_FILETYPE_SMM,\r
+ EFI_FV_FILETYPE_COMBINED_SMM_DXE\r
+ //\r
+ // Note: DXE core will process the FV image file, so skip it in SMM core\r
+ // EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE\r
+ //\r
+};\r
+\r
+typedef struct {\r
+ MEDIA_FW_VOL_FILEPATH_DEVICE_PATH File;\r
+ EFI_DEVICE_PATH_PROTOCOL End;\r
+} FV_FILEPATH_DEVICE_PATH;\r
+\r
+FV_FILEPATH_DEVICE_PATH mFvDevicePath;\r
+\r
+//\r
+// DXE Architecture Protocols\r
+//\r
+EFI_SECURITY_ARCH_PROTOCOL *mSecurity = NULL;\r
+\r
+/**\r
+ Loads an EFI image into SMRAM.\r
+\r
+ @param DriverEntry EFI_SMM_DRIVER_ENTRY instance\r
+\r
+ @return EFI_STATUS\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SmmLoadImage (\r
+ IN OUT EFI_SMM_DRIVER_ENTRY *DriverEntry\r
+ )\r
+{\r
+ UINT32 AuthenticationStatus;\r
+ UINTN FilePathSize;\r
+ VOID *Buffer;\r
+ UINTN Size;\r
+ UINTN PageCount;\r
+ EFI_GUID *NameGuid;\r
+ EFI_STATUS Status;\r
+ EFI_STATUS SecurityStatus;\r
+ EFI_HANDLE DeviceHandle;\r
+ EFI_PHYSICAL_ADDRESS DstBuffer;\r
+ EFI_DEVICE_PATH_PROTOCOL *FilePath;\r
+ EFI_DEVICE_PATH_PROTOCOL *OriginalFilePath;\r
+ EFI_DEVICE_PATH_PROTOCOL *HandleFilePath;\r
+ EFI_FIRMWARE_VOLUME2_PROTOCOL *Fv;\r
+ PE_COFF_LOADER_IMAGE_CONTEXT ImageContext;\r
+ \r
+ Buffer = NULL;\r
+ Size = 0;\r
+ Fv = DriverEntry->Fv;\r
+ NameGuid = &DriverEntry->FileName;\r
+ FilePath = DriverEntry->FvFileDevicePath;\r
+\r
+ OriginalFilePath = FilePath;\r
+ HandleFilePath = FilePath;\r
+ DeviceHandle = NULL;\r
+ SecurityStatus = EFI_SUCCESS;\r
+ Status = EFI_SUCCESS;\r
+ AuthenticationStatus = 0;\r
+\r
+ //\r
+ // Try to get the image device handle by checking the match protocol.\r
+ //\r
+ Status = gBS->LocateDevicePath (&gEfiFirmwareVolume2ProtocolGuid, &HandleFilePath, &DeviceHandle);\r
+ if (EFI_ERROR(Status)) {\r
+ return Status;\r
+ }\r
+\r
+ //\r
+ // If the Security Architectural Protocol has not been located yet, then attempt to locate it\r
+ //\r
+ if (mSecurity == NULL) {\r
+ gBS->LocateProtocol (&gEfiSecurityArchProtocolGuid, NULL, (VOID**)&mSecurity);\r
+ }\r
+\r
+ //\r
+ // Verify the Authentication Status through the Security Architectural Protocol\r
+ //\r
+ if ((mSecurity != NULL) && (OriginalFilePath != NULL)) {\r
+ SecurityStatus = mSecurity->FileAuthenticationState (\r
+ mSecurity,\r
+ AuthenticationStatus,\r
+ OriginalFilePath\r
+ );\r
+ if (EFI_ERROR (SecurityStatus) && SecurityStatus != EFI_SECURITY_VIOLATION) {\r
+ Status = SecurityStatus;\r
+ return Status;\r
+ }\r
+ }\r
+ \r
+ //\r
+ // Pull out just the file portion of the DevicePath for the LoadedImage FilePath\r
+ //\r
+ FilePath = OriginalFilePath;\r
+ Status = gBS->HandleProtocol (DeviceHandle, &gEfiDevicePathProtocolGuid, (VOID **)&HandleFilePath);\r
+ if (!EFI_ERROR (Status)) {\r
+ FilePathSize = GetDevicePathSize (HandleFilePath) - sizeof(EFI_DEVICE_PATH_PROTOCOL);\r
+ FilePath = (EFI_DEVICE_PATH_PROTOCOL *) (((UINT8 *)FilePath) + FilePathSize );\r
+ }\r
+\r
+ //\r
+ // Try reading PE32 section firstly\r
+ //\r
+ Status = Fv->ReadSection (\r
+ Fv,\r
+ NameGuid,\r
+ EFI_SECTION_PE32,\r
+ 0,\r
+ &Buffer,\r
+ &Size,\r
+ &AuthenticationStatus\r
+ );\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ //\r
+ // Try reading TE section secondly\r
+ //\r
+ Buffer = NULL;\r
+ Size = 0;\r
+ Status = Fv->ReadSection (\r
+ Fv,\r
+ NameGuid,\r
+ EFI_SECTION_TE,\r
+ 0,\r
+ &Buffer,\r
+ &Size,\r
+ &AuthenticationStatus\r
+ );\r
+ }\r
+ \r
+ if (EFI_ERROR (Status)) {\r
+ if (Buffer != NULL) {\r
+ Status = gBS->FreePool (Buffer);\r
+ }\r
+ return Status;\r
+ }\r
+\r
+ //\r
+ // Initialize ImageContext\r
+ //\r
+ ImageContext.Handle = Buffer;\r
+ ImageContext.ImageRead = PeCoffLoaderImageReadFromMemory;\r
+\r
+ //\r
+ // Get information about the image being loaded\r
+ //\r
+ Status = PeCoffLoaderGetImageInfo (&ImageContext);\r
+ if (EFI_ERROR (Status)) {\r
+ if (Buffer != NULL) {\r
+ Status = gBS->FreePool (Buffer);\r
+ }\r
+ return Status;\r
+ }\r
+\r
+ PageCount = (UINTN)EFI_SIZE_TO_PAGES(ImageContext.ImageSize + ImageContext.SectionAlignment);\r
+ DstBuffer = (UINTN)(-1);\r
+ \r
+ Status = SmmAllocatePages (\r
+ AllocateMaxAddress,\r
+ EfiRuntimeServicesCode,\r
+ PageCount,\r
+ &DstBuffer\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ if (Buffer != NULL) {\r
+ Status = gBS->FreePool (Buffer);\r
+ }\r
+ return Status;\r
+ }\r
+\r
+ ImageContext.ImageAddress = (EFI_PHYSICAL_ADDRESS)DstBuffer;\r
+ //\r
+ // Align buffer on section boundry\r
+ //\r
+ ImageContext.ImageAddress += ImageContext.SectionAlignment - 1;\r
+ ImageContext.ImageAddress &= ~(ImageContext.SectionAlignment - 1);\r
+\r
+ //\r
+ // Load the image to our new buffer\r
+ //\r
+ Status = PeCoffLoaderLoadImage (&ImageContext);\r
+ if (EFI_ERROR (Status)) {\r
+ if (Buffer != NULL) {\r
+ Status = gBS->FreePool (Buffer);\r
+ }\r
+ SmmFreePages (DstBuffer, PageCount);\r
+ return Status;\r
+ }\r
+\r
+ //\r
+ // Relocate the image in our new buffer\r
+ //\r
+ Status = PeCoffLoaderRelocateImage (&ImageContext);\r
+ if (EFI_ERROR (Status)) {\r
+ if (Buffer != NULL) {\r
+ Status = gBS->FreePool (Buffer);\r
+ }\r
+ SmmFreePages (DstBuffer, PageCount);\r
+ return Status;\r
+ }\r
+\r
+ //\r
+ // Flush the instruction cache so the image data are written before we execute it\r
+ //\r
+ InvalidateInstructionCacheRange ((VOID *)(UINTN) ImageContext.ImageAddress, (UINTN) ImageContext.ImageSize);\r
+\r
+ //\r
+ // Save Image EntryPoint in DriverEntry\r
+ //\r
+ DriverEntry->ImageEntryPoint = ImageContext.EntryPoint;\r
+ DriverEntry->ImageBuffer = DstBuffer; \r
+ DriverEntry->NumberOfPage = PageCount;\r
+\r
+ //\r
+ // Allocate a Loaded Image Protocol in EfiBootServicesData\r
+ //\r
+ Status = gBS->AllocatePool (EfiBootServicesData, sizeof (EFI_LOADED_IMAGE_PROTOCOL), (VOID **)&DriverEntry->LoadedImage);\r
+ if (EFI_ERROR (Status)) {\r
+ if (Buffer != NULL) {\r
+ Status = gBS->FreePool (Buffer);\r
+ }\r
+ SmmFreePages (DstBuffer, PageCount);\r
+ return Status;\r
+ }\r
+\r
+ //\r
+ // Fill in the remaining fields of the Loaded Image Protocol instance.\r
+ // Note: ImageBase is an SMRAM address that can not be accessed outside of SMRAM if SMRAM window is closed.\r
+ //\r
+ DriverEntry->LoadedImage->Revision = EFI_LOADED_IMAGE_PROTOCOL_REVISION;\r
+ DriverEntry->LoadedImage->ParentHandle = gSmmCorePrivate->SmmIplImageHandle;\r
+ DriverEntry->LoadedImage->SystemTable = gST;\r
+ DriverEntry->LoadedImage->DeviceHandle = DeviceHandle;\r
+\r
+ //\r
+ // Make an EfiBootServicesData buffer copy of FilePath\r
+ //\r
+ Status = gBS->AllocatePool (EfiBootServicesData, GetDevicePathSize (FilePath), (VOID **)&DriverEntry->LoadedImage->FilePath);\r
+ if (EFI_ERROR (Status)) {\r
+ if (Buffer != NULL) {\r
+ Status = gBS->FreePool (Buffer);\r
+ }\r
+ SmmFreePages (DstBuffer, PageCount);\r
+ return Status;\r
+ }\r
+ CopyMem (DriverEntry->LoadedImage->FilePath, FilePath, GetDevicePathSize (FilePath));\r
+\r
+ DriverEntry->LoadedImage->ImageBase = (VOID *)(UINTN)DriverEntry->ImageBuffer;\r
+ DriverEntry->LoadedImage->ImageSize = ImageContext.ImageSize;\r
+ DriverEntry->LoadedImage->ImageCodeType = EfiRuntimeServicesCode;\r
+ DriverEntry->LoadedImage->ImageDataType = EfiRuntimeServicesData;\r
+\r
+ //\r
+ // Create a new image handle in the UEFI handle database for the SMM Driver\r
+ //\r
+ DriverEntry->ImageHandle = NULL;\r
+ Status = gBS->InstallMultipleProtocolInterfaces (\r
+ &DriverEntry->ImageHandle,\r
+ &gEfiLoadedImageProtocolGuid, DriverEntry->LoadedImage,\r
+ NULL\r
+ );\r
+\r
+ //\r
+ // Print the load address and the PDB file name if it is available\r
+ //\r
+\r
+ DEBUG_CODE_BEGIN ();\r
+\r
+ UINTN Index;\r
+ UINTN StartIndex;\r
+ CHAR8 EfiFileName[256];\r
+\r
+\r
+ DEBUG ((DEBUG_INFO | DEBUG_LOAD,\r
+ "Loading driver at 0x%11p EntryPoint=0x%11p ",\r
+ (VOID *)(UINTN) ImageContext.ImageAddress,\r
+ FUNCTION_ENTRY_POINT (ImageContext.EntryPoint)));\r
+\r
+\r
+ //\r
+ // Print Module Name by Pdb file path.\r
+ // Windows and Unix style file path are all trimmed correctly.\r
+ //\r
+ if (ImageContext.PdbPointer != NULL) {\r
+ StartIndex = 0;\r
+ for (Index = 0; ImageContext.PdbPointer[Index] != 0; Index++) {\r
+ if ((ImageContext.PdbPointer[Index] == '\\') || (ImageContext.PdbPointer[Index] == '/')) {\r
+ StartIndex = Index + 1;\r
+ }\r
+ }\r
+ //\r
+ // Copy the PDB file name to our temporary string, and replace .pdb with .efi\r
+ // The PDB file name is limited in the range of 0~255.\r
+ // If the length is bigger than 255, trim the redudant characters to avoid overflow in array boundary.\r
+ //\r
+ for (Index = 0; Index < sizeof (EfiFileName) - 4; Index++) {\r
+ EfiFileName[Index] = ImageContext.PdbPointer[Index + StartIndex];\r
+ if (EfiFileName[Index] == 0) {\r
+ EfiFileName[Index] = '.';\r
+ }\r
+ if (EfiFileName[Index] == '.') {\r
+ EfiFileName[Index + 1] = 'e';\r
+ EfiFileName[Index + 2] = 'f';\r
+ EfiFileName[Index + 3] = 'i';\r
+ EfiFileName[Index + 4] = 0;\r
+ break;\r
+ }\r
+ }\r
+\r
+ if (Index == sizeof (EfiFileName) - 4) {\r
+ EfiFileName[Index] = 0;\r
+ }\r
+ DEBUG ((DEBUG_INFO | DEBUG_LOAD, "%a", EfiFileName)); // &Image->ImageContext.PdbPointer[StartIndex]));\r
+ }\r
+ DEBUG ((DEBUG_INFO | DEBUG_LOAD, "\n"));\r
+\r
+ DEBUG_CODE_END ();\r
+\r
+ //\r
+ // Free buffer allocated by Fv->ReadSection.\r
+ //\r
+ // The UEFI Boot Services FreePool() function must be used because Fv->ReadSection \r
+ // used the UEFI Boot Services AllocatePool() function\r
+ //\r
+ Status = gBS->FreePool(Buffer);\r
+ return Status; \r
+}\r
+\r
+/**\r
+ Preprocess dependency expression and update DriverEntry to reflect the\r
+ state of Before, After, and SOR dependencies. If DriverEntry->Before\r
+ or DriverEntry->After is set it will never be cleared. If SOR is set\r
+ it will be cleared by SmmSchedule(), and then the driver can be\r
+ dispatched.\r
+\r
+ @param DriverEntry DriverEntry element to update .\r
+\r
+ @retval EFI_SUCCESS It always works.\r
+\r
+**/\r
+EFI_STATUS\r
+SmmPreProcessDepex (\r
+ IN EFI_SMM_DRIVER_ENTRY *DriverEntry\r
+ )\r
+{\r
+ UINT8 *Iterator;\r
+\r
+ Iterator = DriverEntry->Depex;\r
+ if (*Iterator == EFI_DEP_SOR) {\r
+ DriverEntry->Unrequested = TRUE;\r
+ } else {\r
+ DriverEntry->Dependent = TRUE;\r
+ }\r
+\r
+ if (*Iterator == EFI_DEP_BEFORE) {\r
+ DriverEntry->Before = TRUE;\r
+ } else if (*Iterator == EFI_DEP_AFTER) {\r
+ DriverEntry->After = TRUE;\r
+ }\r
+\r
+ if (DriverEntry->Before || DriverEntry->After) {\r
+ CopyMem (&DriverEntry->BeforeAfterGuid, Iterator + 1, sizeof (EFI_GUID));\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Read Depex and pre-process the Depex for Before and After. If Section Extraction\r
+ protocol returns an error via ReadSection defer the reading of the Depex.\r
+\r
+ @param DriverEntry Driver to work on.\r
+\r
+ @retval EFI_SUCCESS Depex read and preprossesed\r
+ @retval EFI_PROTOCOL_ERROR The section extraction protocol returned an error\r
+ and Depex reading needs to be retried.\r
+ @retval Error DEPEX not found.\r
+\r
+**/\r
+EFI_STATUS\r
+SmmGetDepexSectionAndPreProccess (\r
+ IN EFI_SMM_DRIVER_ENTRY *DriverEntry\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_SECTION_TYPE SectionType;\r
+ UINT32 AuthenticationStatus;\r
+ EFI_FIRMWARE_VOLUME2_PROTOCOL *Fv;\r
+\r
+ Fv = DriverEntry->Fv;\r
+\r
+ //\r
+ // Grab Depex info, it will never be free'ed.\r
+ // (Note: DriverEntry->Depex is in DXE memory)\r
+ //\r
+ SectionType = EFI_SECTION_SMM_DEPEX;\r
+ Status = Fv->ReadSection (\r
+ DriverEntry->Fv,\r
+ &DriverEntry->FileName,\r
+ SectionType,\r
+ 0,\r
+ &DriverEntry->Depex,\r
+ (UINTN *)&DriverEntry->DepexSize,\r
+ &AuthenticationStatus\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ if (Status == EFI_PROTOCOL_ERROR) {\r
+ //\r
+ // The section extraction protocol failed so set protocol error flag\r
+ //\r
+ DriverEntry->DepexProtocolError = TRUE;\r
+ } else {\r
+ //\r
+ // If no Depex assume depend on all architectural protocols\r
+ //\r
+ DriverEntry->Depex = NULL;\r
+ DriverEntry->Dependent = TRUE;\r
+ DriverEntry->DepexProtocolError = FALSE;\r
+ }\r
+ } else {\r
+ //\r
+ // Set Before, After, and Unrequested state information based on Depex\r
+ // Driver will be put in Dependent or Unrequested state\r
+ //\r
+ SmmPreProcessDepex (DriverEntry);\r
+ DriverEntry->DepexProtocolError = FALSE;\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Check every driver and locate a matching one. If the driver is found, the Unrequested\r
+ state flag is cleared.\r
+\r
+ @param FirmwareVolumeHandle The handle of the Firmware Volume that contains\r
+ the firmware file specified by DriverName.\r
+ @param DriverName The Driver name to put in the Dependent state.\r
+\r
+ @retval EFI_SUCCESS The DriverName was found and it's SOR bit was\r
+ cleared\r
+ @retval EFI_NOT_FOUND The DriverName does not exist or it's SOR bit was\r
+ not set.\r
+\r
+**/\r
+EFI_STATUS\r
+SmmSchedule (\r
+ IN EFI_HANDLE FirmwareVolumeHandle,\r
+ IN EFI_GUID *DriverName\r
+ )\r
+{\r
+ LIST_ENTRY *Link;\r
+ EFI_SMM_DRIVER_ENTRY *DriverEntry;\r
+\r
+ //\r
+ // Check every driver\r
+ //\r
+ for (Link = mDiscoveredList.ForwardLink; Link != &mDiscoveredList; Link = Link->ForwardLink) {\r
+ DriverEntry = CR(Link, EFI_SMM_DRIVER_ENTRY, Link, EFI_SMM_DRIVER_ENTRY_SIGNATURE);\r
+ if (DriverEntry->FvHandle == FirmwareVolumeHandle &&\r
+ DriverEntry->Unrequested &&\r
+ CompareGuid (DriverName, &DriverEntry->FileName)) {\r
+ //\r
+ // Move the driver from the Unrequested to the Dependent state\r
+ //\r
+ DriverEntry->Unrequested = FALSE;\r
+ DriverEntry->Dependent = TRUE;\r
+\r
+ return EFI_SUCCESS;\r
+ }\r
+ }\r
+ return EFI_NOT_FOUND;\r
+}\r
+\r
+/**\r
+ This is the main Dispatcher for SMM and it exits when there are no more\r
+ drivers to run. Drain the mScheduledQueue and load and start a PE\r
+ image for each driver. Search the mDiscoveredList to see if any driver can\r
+ be placed on the mScheduledQueue. If no drivers are placed on the\r
+ mScheduledQueue exit the function. On exit it is assumed the Bds()\r
+ will be called, and when the Bds() exits the Dispatcher will be called\r
+ again.\r
+\r
+ @retval EFI_ALREADY_STARTED The SMM Dispatcher is already running\r
+ @retval EFI_NOT_FOUND No SMM Drivers were dispatched\r
+ @retval EFI_SUCCESS One or more SMM Drivers were dispatched\r
+\r
+**/\r
+EFI_STATUS\r
+SmmDispatcher (\r
+ VOID\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_STATUS ReturnStatus;\r
+ LIST_ENTRY *Link;\r
+ EFI_SMM_DRIVER_ENTRY *DriverEntry;\r
+ BOOLEAN ReadyToRun;\r
+\r
+ if (!gRequestDispatch) {\r
+ return EFI_NOT_FOUND;\r
+ }\r
+\r
+ if (gDispatcherRunning) {\r
+ //\r
+ // If the dispatcher is running don't let it be restarted.\r
+ //\r
+ return EFI_ALREADY_STARTED;\r
+ }\r
+\r
+ gDispatcherRunning = TRUE;\r
+\r
+ ReturnStatus = EFI_NOT_FOUND;\r
+ do {\r
+ //\r
+ // Drain the Scheduled Queue\r
+ //\r
+ while (!IsListEmpty (&mScheduledQueue)) {\r
+ DriverEntry = CR (\r
+ mScheduledQueue.ForwardLink,\r
+ EFI_SMM_DRIVER_ENTRY,\r
+ ScheduledLink,\r
+ EFI_SMM_DRIVER_ENTRY_SIGNATURE\r
+ );\r
+\r
+ //\r
+ // Load the SMM Driver image into memory. If the Driver was transitioned from\r
+ // Untrused to Scheduled it would have already been loaded so we may need to\r
+ // skip the LoadImage\r
+ //\r
+ if (DriverEntry->ImageHandle == NULL) {\r
+ Status = SmmLoadImage (DriverEntry);\r
+\r
+ //\r
+ // Update the driver state to reflect that it's been loaded\r
+ //\r
+ if (EFI_ERROR (Status)) {\r
+\r
+ if (Status == EFI_SECURITY_VIOLATION) {\r
+ //\r
+ // Take driver from Scheduled to Untrused state\r
+ //\r
+ DriverEntry->Untrusted = TRUE;\r
+ } else {\r
+ //\r
+ // The SMM Driver could not be loaded, and do not attempt to load or start it again.\r
+ // Take driver from Scheduled to Initialized.\r
+ //\r
+ // This case include the Never Trusted state if EFI_ACCESS_DENIED is returned\r
+ //\r
+ DriverEntry->Initialized = TRUE;\r
+ }\r
+\r
+ DriverEntry->Scheduled = FALSE;\r
+ RemoveEntryList (&DriverEntry->ScheduledLink);\r
+\r
+ //\r
+ // If it's an error don't try the StartImage\r
+ //\r
+ continue;\r
+ }\r
+ }\r
+\r
+ DriverEntry->Scheduled = FALSE;\r
+ DriverEntry->Initialized = TRUE;\r
+ RemoveEntryList (&DriverEntry->ScheduledLink);\r
+\r
+ REPORT_STATUS_CODE_WITH_EXTENDED_DATA (\r
+ EFI_PROGRESS_CODE,\r
+ EFI_SOFTWARE_SMM_DRIVER | EFI_SW_PC_INIT_BEGIN,\r
+ &DriverEntry->ImageHandle,\r
+ sizeof (DriverEntry->ImageHandle)\r
+ );\r
+\r
+ //\r
+ // For each SMM driver, pass NULL as ImageHandle\r
+ //\r
+ Status = ((EFI_IMAGE_ENTRY_POINT)(UINTN)DriverEntry->ImageEntryPoint)(DriverEntry->ImageHandle, gST);\r
+ if (EFI_ERROR(Status)){\r
+ SmmFreePages(DriverEntry->ImageBuffer, DriverEntry->NumberOfPage);\r
+ }\r
+\r
+ REPORT_STATUS_CODE_WITH_EXTENDED_DATA (\r
+ EFI_PROGRESS_CODE,\r
+ EFI_SOFTWARE_SMM_DRIVER | EFI_SW_PC_INIT_END,\r
+ &DriverEntry->ImageHandle,\r
+ sizeof (DriverEntry->ImageHandle)\r
+ );\r
+\r
+ ReturnStatus = EFI_SUCCESS;\r
+ }\r
+\r
+ //\r
+ // Search DriverList for items to place on Scheduled Queue\r
+ //\r
+ ReadyToRun = FALSE;\r
+ for (Link = mDiscoveredList.ForwardLink; Link != &mDiscoveredList; Link = Link->ForwardLink) {\r
+ DriverEntry = CR (Link, EFI_SMM_DRIVER_ENTRY, Link, EFI_SMM_DRIVER_ENTRY_SIGNATURE);\r
+\r
+ if (DriverEntry->DepexProtocolError){\r
+ //\r
+ // If Section Extraction Protocol did not let the Depex be read before retry the read\r
+ //\r
+ Status = SmmGetDepexSectionAndPreProccess (DriverEntry);\r
+ }\r
+\r
+ if (DriverEntry->Dependent) {\r
+ if (SmmIsSchedulable (DriverEntry)) {\r
+ SmmInsertOnScheduledQueueWhileProcessingBeforeAndAfter (DriverEntry);\r
+ ReadyToRun = TRUE;\r
+ }\r
+ }\r
+ }\r
+ } while (ReadyToRun);\r
+\r
+ //\r
+ // If there is no more SMM driver to dispatch, stop the dispatch request\r
+ //\r
+ gRequestDispatch = FALSE;\r
+ for (Link = mDiscoveredList.ForwardLink; Link != &mDiscoveredList; Link = Link->ForwardLink) {\r
+ DriverEntry = CR (Link, EFI_SMM_DRIVER_ENTRY, Link, EFI_SMM_DRIVER_ENTRY_SIGNATURE);\r
+\r
+ if (!DriverEntry->Initialized){\r
+ //\r
+ // We have SMM driver pending to dispatch\r
+ //\r
+ gRequestDispatch = TRUE;\r
+ break;\r
+ }\r
+ }\r
+\r
+ gDispatcherRunning = FALSE;\r
+\r
+ return ReturnStatus;\r
+}\r
+\r
+/**\r
+ Insert InsertedDriverEntry onto the mScheduledQueue. To do this you\r
+ must add any driver with a before dependency on InsertedDriverEntry first.\r
+ You do this by recursively calling this routine. After all the Befores are\r
+ processed you can add InsertedDriverEntry to the mScheduledQueue.\r
+ Then you can add any driver with an After dependency on InsertedDriverEntry\r
+ by recursively calling this routine.\r
+\r
+ @param InsertedDriverEntry The driver to insert on the ScheduledLink Queue\r
+\r
+**/\r
+VOID\r
+SmmInsertOnScheduledQueueWhileProcessingBeforeAndAfter (\r
+ IN EFI_SMM_DRIVER_ENTRY *InsertedDriverEntry\r
+ )\r
+{\r
+ LIST_ENTRY *Link;\r
+ EFI_SMM_DRIVER_ENTRY *DriverEntry;\r
+\r
+ //\r
+ // Process Before Dependency\r
+ //\r
+ for (Link = mDiscoveredList.ForwardLink; Link != &mDiscoveredList; Link = Link->ForwardLink) {\r
+ DriverEntry = CR(Link, EFI_SMM_DRIVER_ENTRY, Link, EFI_SMM_DRIVER_ENTRY_SIGNATURE);\r
+ if (DriverEntry->Before && DriverEntry->Dependent) {\r
+ if (CompareGuid (&InsertedDriverEntry->FileName, &DriverEntry->BeforeAfterGuid)) {\r
+ //\r
+ // Recursively process BEFORE\r
+ //\r
+ SmmInsertOnScheduledQueueWhileProcessingBeforeAndAfter (DriverEntry);\r
+ }\r
+ }\r
+ }\r
+\r
+ //\r
+ // Convert driver from Dependent to Scheduled state\r
+ //\r
+\r
+ InsertedDriverEntry->Dependent = FALSE;\r
+ InsertedDriverEntry->Scheduled = TRUE;\r
+ InsertTailList (&mScheduledQueue, &InsertedDriverEntry->ScheduledLink);\r
+\r
+\r
+ //\r
+ // Process After Dependency\r
+ //\r
+ for (Link = mDiscoveredList.ForwardLink; Link != &mDiscoveredList; Link = Link->ForwardLink) {\r
+ DriverEntry = CR(Link, EFI_SMM_DRIVER_ENTRY, Link, EFI_SMM_DRIVER_ENTRY_SIGNATURE);\r
+ if (DriverEntry->After && DriverEntry->Dependent) {\r
+ if (CompareGuid (&InsertedDriverEntry->FileName, &DriverEntry->BeforeAfterGuid)) {\r
+ //\r
+ // Recursively process AFTER\r
+ //\r
+ SmmInsertOnScheduledQueueWhileProcessingBeforeAndAfter (DriverEntry);\r
+ }\r
+ }\r
+ }\r
+}\r
+\r
+/**\r
+ Return TRUE if the Fv has been processed, FALSE if not.\r
+\r
+ @param FvHandle The handle of a FV that's being tested\r
+\r
+ @retval TRUE Fv protocol on FvHandle has been processed\r
+ @retval FALSE Fv protocol on FvHandle has not yet been\r
+ processed\r
+\r
+**/\r
+BOOLEAN\r
+FvHasBeenProcessed (\r
+ IN EFI_HANDLE FvHandle\r
+ )\r
+{\r
+ LIST_ENTRY *Link;\r
+ KNOWN_HANDLE *KnownHandle;\r
+\r
+ for (Link = mFvHandleList.ForwardLink; Link != &mFvHandleList; Link = Link->ForwardLink) {\r
+ KnownHandle = CR(Link, KNOWN_HANDLE, Link, KNOWN_HANDLE_SIGNATURE);\r
+ if (KnownHandle->Handle == FvHandle) {\r
+ return TRUE;\r
+ }\r
+ }\r
+ return FALSE;\r
+}\r
+\r
+/**\r
+ Remember that Fv protocol on FvHandle has had it's drivers placed on the\r
+ mDiscoveredList. This fucntion adds entries on the mFvHandleList. Items are\r
+ never removed/freed from the mFvHandleList.\r
+\r
+ @param FvHandle The handle of a FV that has been processed\r
+\r
+**/\r
+VOID\r
+FvIsBeingProcesssed (\r
+ IN EFI_HANDLE FvHandle\r
+ )\r
+{\r
+ KNOWN_HANDLE *KnownHandle;\r
+\r
+ KnownHandle = AllocatePool (sizeof (KNOWN_HANDLE));\r
+ ASSERT (KnownHandle != NULL);\r
+\r
+ KnownHandle->Signature = KNOWN_HANDLE_SIGNATURE;\r
+ KnownHandle->Handle = FvHandle;\r
+ InsertTailList (&mFvHandleList, &KnownHandle->Link);\r
+}\r
+\r
+/**\r
+ Convert FvHandle and DriverName into an EFI device path\r
+\r
+ @param Fv Fv protocol, needed to read Depex info out of\r
+ FLASH.\r
+ @param FvHandle Handle for Fv, needed in the\r
+ EFI_SMM_DRIVER_ENTRY so that the PE image can be\r
+ read out of the FV at a later time.\r
+ @param DriverName Name of driver to add to mDiscoveredList.\r
+\r
+ @return Pointer to device path constructed from FvHandle and DriverName\r
+\r
+**/\r
+EFI_DEVICE_PATH_PROTOCOL *\r
+SmmFvToDevicePath (\r
+ IN EFI_FIRMWARE_VOLUME2_PROTOCOL *Fv,\r
+ IN EFI_HANDLE FvHandle,\r
+ IN EFI_GUID *DriverName\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_DEVICE_PATH_PROTOCOL *FvDevicePath;\r
+ EFI_DEVICE_PATH_PROTOCOL *FileNameDevicePath;\r
+\r
+ //\r
+ // Remember the device path of the FV\r
+ //\r
+ Status = gBS->HandleProtocol (FvHandle, &gEfiDevicePathProtocolGuid, (VOID **)&FvDevicePath);\r
+ if (EFI_ERROR (Status)) {\r
+ FileNameDevicePath = NULL;\r
+ } else {\r
+ //\r
+ // Build a device path to the file in the FV to pass into gBS->LoadImage\r
+ //\r
+ EfiInitializeFwVolDevicepathNode (&mFvDevicePath.File, DriverName);\r
+ SetDevicePathEndNode (&mFvDevicePath.End);\r
+\r
+ //\r
+ // Note: FileNameDevicePath is in DXE memory\r
+ //\r
+ FileNameDevicePath = AppendDevicePath (\r
+ FvDevicePath,\r
+ (EFI_DEVICE_PATH_PROTOCOL *)&mFvDevicePath\r
+ );\r
+ }\r
+ return FileNameDevicePath;\r
+}\r
+\r
+/**\r
+ Add an entry to the mDiscoveredList. Allocate memory to store the DriverEntry,\r
+ and initilize any state variables. Read the Depex from the FV and store it\r
+ in DriverEntry. Pre-process the Depex to set the SOR, Before and After state.\r
+ The Discovered list is never free'ed and contains booleans that represent the\r
+ other possible SMM driver states.\r
+\r
+ @param Fv Fv protocol, needed to read Depex info out of\r
+ FLASH.\r
+ @param FvHandle Handle for Fv, needed in the\r
+ EFI_SMM_DRIVER_ENTRY so that the PE image can be\r
+ read out of the FV at a later time.\r
+ @param DriverName Name of driver to add to mDiscoveredList.\r
+\r
+ @retval EFI_SUCCESS If driver was added to the mDiscoveredList.\r
+ @retval EFI_ALREADY_STARTED The driver has already been started. Only one\r
+ DriverName may be active in the system at any one\r
+ time.\r
+\r
+**/\r
+EFI_STATUS\r
+SmmAddToDriverList (\r
+ IN EFI_FIRMWARE_VOLUME2_PROTOCOL *Fv,\r
+ IN EFI_HANDLE FvHandle,\r
+ IN EFI_GUID *DriverName\r
+ )\r
+{\r
+ EFI_SMM_DRIVER_ENTRY *DriverEntry;\r
+\r
+ //\r
+ // Create the Driver Entry for the list. ZeroPool initializes lots of variables to\r
+ // NULL or FALSE.\r
+ //\r
+ DriverEntry = AllocateZeroPool (sizeof (EFI_SMM_DRIVER_ENTRY));\r
+ ASSERT (DriverEntry != NULL);\r
+\r
+ DriverEntry->Signature = EFI_SMM_DRIVER_ENTRY_SIGNATURE;\r
+ CopyGuid (&DriverEntry->FileName, DriverName);\r
+ DriverEntry->FvHandle = FvHandle;\r
+ DriverEntry->Fv = Fv;\r
+ DriverEntry->FvFileDevicePath = SmmFvToDevicePath (Fv, FvHandle, DriverName);\r
+\r
+ SmmGetDepexSectionAndPreProccess (DriverEntry);\r
+\r
+ InsertTailList (&mDiscoveredList, &DriverEntry->Link);\r
+ gRequestDispatch = TRUE;\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ This function is the main entry point for an SMM handler dispatch\r
+ or communicate-based callback.\r
+\r
+ Event notification that is fired every time a FV dispatch protocol is added.\r
+ More than one protocol may have been added when this event is fired, so you\r
+ must loop on SmmLocateHandle () to see how many protocols were added and\r
+ do the following to each FV:\r
+ If the Fv has already been processed, skip it. If the Fv has not been\r
+ processed then mark it as being processed, as we are about to process it.\r
+ Read the Fv and add any driver in the Fv to the mDiscoveredList.The\r
+ mDiscoveredList is never free'ed and contains variables that define\r
+ the other states the SMM driver transitions to..\r
+ While you are at it read the A Priori file into memory.\r
+ Place drivers in the A Priori list onto the mScheduledQueue.\r
+\r
+ @param DispatchHandle The unique handle assigned to this handler by SmiHandlerRegister().\r
+ @param Context Points to an optional handler context which was specified when the handler was registered.\r
+ @param CommBuffer A pointer to a collection of data in memory that will\r
+ be conveyed from a non-SMM environment into an SMM environment.\r
+ @param CommBufferSize The size of the CommBuffer.\r
+\r
+ @return Status Code\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SmmDriverDispatchHandler (\r
+ IN EFI_HANDLE DispatchHandle,\r
+ IN CONST VOID *Context, OPTIONAL\r
+ IN OUT VOID *CommBuffer, OPTIONAL\r
+ IN OUT UINTN *CommBufferSize OPTIONAL\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINTN HandleCount;\r
+ EFI_HANDLE *HandleBuffer;\r
+ EFI_STATUS GetNextFileStatus;\r
+ EFI_STATUS SecurityStatus;\r
+ EFI_FIRMWARE_VOLUME2_PROTOCOL *Fv;\r
+ EFI_DEVICE_PATH_PROTOCOL *FvDevicePath;\r
+ EFI_HANDLE FvHandle;\r
+ EFI_GUID NameGuid;\r
+ UINTN Key;\r
+ EFI_FV_FILETYPE Type;\r
+ EFI_FV_FILE_ATTRIBUTES Attributes;\r
+ UINTN Size;\r
+ EFI_SMM_DRIVER_ENTRY *DriverEntry;\r
+ EFI_GUID *AprioriFile;\r
+ UINTN AprioriEntryCount;\r
+ UINTN Index;\r
+ LIST_ENTRY *Link;\r
+ UINT32 AuthenticationStatus;\r
+ UINTN SizeOfBuffer;\r
+\r
+ HandleBuffer = NULL;\r
+ Status = gBS->LocateHandleBuffer (\r
+ ByProtocol,\r
+ &gEfiFirmwareVolume2ProtocolGuid,\r
+ NULL,\r
+ &HandleCount,\r
+ &HandleBuffer\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return EFI_NOT_FOUND;\r
+ }\r
+\r
+ for (Index = 0; Index < HandleCount; Index++) {\r
+ FvHandle = HandleBuffer[Index];\r
+\r
+ if (FvHasBeenProcessed (FvHandle)) {\r
+ //\r
+ // This Fv has already been processed so lets skip it!\r
+ //\r
+ continue;\r
+ }\r
+\r
+ //\r
+ // Since we are about to process this Fv mark it as processed.\r
+ //\r
+ FvIsBeingProcesssed (FvHandle);\r
+\r
+ Status = gBS->HandleProtocol (FvHandle, &gEfiFirmwareVolume2ProtocolGuid, (VOID **)&Fv);\r
+ if (EFI_ERROR (Status)) {\r
+ //\r
+ // FvHandle must have a Firmware Volume2 Protocol thus we should never get here.\r
+ //\r
+ ASSERT (FALSE);\r
+ continue;\r
+ }\r
+\r
+ Status = gBS->HandleProtocol (FvHandle, &gEfiDevicePathProtocolGuid, (VOID **)&FvDevicePath);\r
+ if (EFI_ERROR (Status)) {\r
+ //\r
+ // The Firmware volume doesn't have device path, can't be dispatched.\r
+ //\r
+ continue;\r
+ }\r
+\r
+ //\r
+ // If the Security Architectural Protocol has not been located yet, then attempt to locate it\r
+ //\r
+ if (mSecurity == NULL) {\r
+ gBS->LocateProtocol (&gEfiSecurityArchProtocolGuid, NULL, (VOID**)&mSecurity);\r
+ }\r
+\r
+ //\r
+ // Evaluate the authentication status of the Firmware Volume through\r
+ // Security Architectural Protocol\r
+ //\r
+ if (mSecurity != NULL) {\r
+ SecurityStatus = mSecurity->FileAuthenticationState (\r
+ mSecurity,\r
+ 0,\r
+ FvDevicePath\r
+ );\r
+ if (SecurityStatus != EFI_SUCCESS) {\r
+ //\r
+ // Security check failed. The firmware volume should not be used for any purpose.\r
+ //\r
+ continue;\r
+ }\r
+ }\r
+\r
+ //\r
+ // Discover Drivers in FV and add them to the Discovered Driver List.\r
+ // Process EFI_FV_FILETYPE_SMM type and then EFI_FV_FILETYPE_COMBINED_SMM_DXE\r
+ //\r
+ for (Index = 0; Index < sizeof (mSmmFileTypes)/sizeof (EFI_FV_FILETYPE); Index++) {\r
+ //\r
+ // Initialize the search key\r
+ //\r
+ Key = 0;\r
+ do {\r
+ Type = mSmmFileTypes[Index];\r
+ GetNextFileStatus = Fv->GetNextFile (\r
+ Fv,\r
+ &Key,\r
+ &Type,\r
+ &NameGuid,\r
+ &Attributes,\r
+ &Size\r
+ );\r
+ if (!EFI_ERROR (GetNextFileStatus)) {\r
+ SmmAddToDriverList (Fv, FvHandle, &NameGuid);\r
+ }\r
+ } while (!EFI_ERROR (GetNextFileStatus));\r
+ }\r
+\r
+ //\r
+ // Read the array of GUIDs from the Apriori file if it is present in the firmware volume\r
+ // (Note: AprioriFile is in DXE memory)\r
+ //\r
+ AprioriFile = NULL;\r
+ Status = Fv->ReadSection (\r
+ Fv,\r
+ &gAprioriGuid,\r
+ EFI_SECTION_RAW,\r
+ 0,\r
+ (VOID **)&AprioriFile,\r
+ &SizeOfBuffer,\r
+ &AuthenticationStatus\r
+ );\r
+ if (!EFI_ERROR (Status)) {\r
+ AprioriEntryCount = SizeOfBuffer / sizeof (EFI_GUID);\r
+ } else {\r
+ AprioriEntryCount = 0;\r
+ }\r
+\r
+ //\r
+ // Put drivers on Apriori List on the Scheduled queue. The Discovered List includes\r
+ // drivers not in the current FV and these must be skipped since the a priori list\r
+ // is only valid for the FV that it resided in.\r
+ //\r
+\r
+ for (Index = 0; Index < AprioriEntryCount; Index++) {\r
+ for (Link = mDiscoveredList.ForwardLink; Link != &mDiscoveredList; Link = Link->ForwardLink) {\r
+ DriverEntry = CR(Link, EFI_SMM_DRIVER_ENTRY, Link, EFI_SMM_DRIVER_ENTRY_SIGNATURE);\r
+ if (CompareGuid (&DriverEntry->FileName, &AprioriFile[Index]) &&\r
+ (FvHandle == DriverEntry->FvHandle)) {\r
+ DriverEntry->Dependent = FALSE;\r
+ DriverEntry->Scheduled = TRUE;\r
+ InsertTailList (&mScheduledQueue, &DriverEntry->ScheduledLink);\r
+ break;\r
+ }\r
+ }\r
+ }\r
+\r
+ //\r
+ // Free data allocated by Fv->ReadSection ()\r
+ //\r
+ // The UEFI Boot Services FreePool() function must be used because Fv->ReadSection \r
+ // used the UEFI Boot Services AllocatePool() function\r
+ //\r
+ gBS->FreePool (AprioriFile);\r
+ }\r
+\r
+ //\r
+ // Execute the SMM Dispatcher on any newly discovered FVs and previously \r
+ // discovered SMM drivers that have been discovered but not dispatched.\r
+ //\r
+ return SmmDispatcher ();\r
+}\r
+\r
+/**\r
+ Traverse the discovered list for any drivers that were discovered but not loaded\r
+ because the dependency experessions evaluated to false.\r
+\r
+**/\r
+VOID\r
+SmmDisplayDiscoveredNotDispatched (\r
+ VOID\r
+ )\r
+{\r
+ LIST_ENTRY *Link;\r
+ EFI_SMM_DRIVER_ENTRY *DriverEntry;\r
+\r
+ for (Link = mDiscoveredList.ForwardLink;Link !=&mDiscoveredList; Link = Link->ForwardLink) {\r
+ DriverEntry = CR(Link, EFI_SMM_DRIVER_ENTRY, Link, EFI_SMM_DRIVER_ENTRY_SIGNATURE);\r
+ if (DriverEntry->Dependent) {\r
+ DEBUG ((DEBUG_LOAD, "SMM Driver %g was discovered but not loaded!!\n", &DriverEntry->FileName));\r
+ }\r
+ }\r
+}\r
--- /dev/null
+/** @file\r
+ SMM handle & protocol handling.\r
+\r
+ Copyright (c) 2009 - 2010, Intel Corporation. All rights reserved.<BR>\r
+ This program and the accompanying materials are licensed and made available \r
+ under the terms and conditions of the BSD License which accompanies this \r
+ distribution. The full text of the license may be found at \r
+ http://opensource.org/licenses/bsd-license.php \r
+\r
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, \r
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. \r
+\r
+**/\r
+\r
+#include "PiSmmCore.h"\r
+\r
+//\r
+// mProtocolDatabase - A list of all protocols in the system. (simple list for now)\r
+// gHandleList - A list of all the handles in the system\r
+//\r
+LIST_ENTRY mProtocolDatabase = INITIALIZE_LIST_HEAD_VARIABLE (mProtocolDatabase);\r
+LIST_ENTRY gHandleList = INITIALIZE_LIST_HEAD_VARIABLE (gHandleList);\r
+\r
+/**\r
+ Check whether a handle is a valid EFI_HANDLE\r
+\r
+ @param UserHandle The handle to check\r
+\r
+ @retval EFI_INVALID_PARAMETER The handle is NULL or not a valid EFI_HANDLE.\r
+ @retval EFI_SUCCESS The handle is valid EFI_HANDLE.\r
+\r
+**/\r
+EFI_STATUS\r
+SmmValidateHandle (\r
+ IN EFI_HANDLE UserHandle\r
+ )\r
+{\r
+ IHANDLE *Handle;\r
+\r
+ Handle = (IHANDLE *)UserHandle;\r
+ if (Handle == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+ if (Handle->Signature != EFI_HANDLE_SIGNATURE) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Finds the protocol entry for the requested protocol.\r
+\r
+ @param Protocol The ID of the protocol\r
+ @param Create Create a new entry if not found\r
+\r
+ @return Protocol entry\r
+\r
+**/\r
+PROTOCOL_ENTRY *\r
+SmmFindProtocolEntry (\r
+ IN EFI_GUID *Protocol,\r
+ IN BOOLEAN Create\r
+ )\r
+{\r
+ LIST_ENTRY *Link;\r
+ PROTOCOL_ENTRY *Item;\r
+ PROTOCOL_ENTRY *ProtEntry;\r
+\r
+ //\r
+ // Search the database for the matching GUID\r
+ //\r
+\r
+ ProtEntry = NULL;\r
+ for (Link = mProtocolDatabase.ForwardLink;\r
+ Link != &mProtocolDatabase;\r
+ Link = Link->ForwardLink) {\r
+\r
+ Item = CR(Link, PROTOCOL_ENTRY, AllEntries, PROTOCOL_ENTRY_SIGNATURE);\r
+ if (CompareGuid (&Item->ProtocolID, Protocol)) {\r
+ //\r
+ // This is the protocol entry\r
+ //\r
+ ProtEntry = Item;\r
+ break;\r
+ }\r
+ }\r
+\r
+ //\r
+ // If the protocol entry was not found and Create is TRUE, then\r
+ // allocate a new entry\r
+ //\r
+ if ((ProtEntry == NULL) && Create) {\r
+ ProtEntry = AllocatePool (sizeof(PROTOCOL_ENTRY));\r
+ if (ProtEntry != NULL) {\r
+ //\r
+ // Initialize new protocol entry structure\r
+ //\r
+ ProtEntry->Signature = PROTOCOL_ENTRY_SIGNATURE;\r
+ CopyGuid ((VOID *)&ProtEntry->ProtocolID, Protocol);\r
+ InitializeListHead (&ProtEntry->Protocols);\r
+ InitializeListHead (&ProtEntry->Notify);\r
+\r
+ //\r
+ // Add it to protocol database\r
+ //\r
+ InsertTailList (&mProtocolDatabase, &ProtEntry->AllEntries);\r
+ }\r
+ }\r
+ return ProtEntry;\r
+}\r
+\r
+/**\r
+ Finds the protocol instance for the requested handle and protocol.\r
+ Note: This function doesn't do parameters checking, it's caller's responsibility\r
+ to pass in valid parameters.\r
+\r
+ @param Handle The handle to search the protocol on\r
+ @param Protocol GUID of the protocol\r
+ @param Interface The interface for the protocol being searched\r
+\r
+ @return Protocol instance (NULL: Not found)\r
+\r
+**/\r
+PROTOCOL_INTERFACE *\r
+SmmFindProtocolInterface (\r
+ IN IHANDLE *Handle,\r
+ IN EFI_GUID *Protocol,\r
+ IN VOID *Interface\r
+ )\r
+{\r
+ PROTOCOL_INTERFACE *Prot;\r
+ PROTOCOL_ENTRY *ProtEntry;\r
+ LIST_ENTRY *Link;\r
+\r
+ Prot = NULL;\r
+\r
+ //\r
+ // Lookup the protocol entry for this protocol ID\r
+ //\r
+ ProtEntry = SmmFindProtocolEntry (Protocol, FALSE);\r
+ if (ProtEntry != NULL) {\r
+ //\r
+ // Look at each protocol interface for any matches\r
+ //\r
+ for (Link = Handle->Protocols.ForwardLink; Link != &Handle->Protocols; Link=Link->ForwardLink) {\r
+ //\r
+ // If this protocol interface matches, remove it\r
+ //\r
+ Prot = CR(Link, PROTOCOL_INTERFACE, Link, PROTOCOL_INTERFACE_SIGNATURE);\r
+ if (Prot->Interface == Interface && Prot->Protocol == ProtEntry) {\r
+ break;\r
+ }\r
+ Prot = NULL;\r
+ }\r
+ }\r
+ return Prot;\r
+}\r
+\r
+/**\r
+ Wrapper function to SmmInstallProtocolInterfaceNotify. This is the public API which\r
+ Calls the private one which contains a BOOLEAN parameter for notifications\r
+\r
+ @param UserHandle The handle to install the protocol handler on,\r
+ or NULL if a new handle is to be allocated\r
+ @param Protocol The protocol to add to the handle\r
+ @param InterfaceType Indicates whether Interface is supplied in\r
+ native form.\r
+ @param Interface The interface for the protocol being added\r
+\r
+ @return Status code\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SmmInstallProtocolInterface (\r
+ IN OUT EFI_HANDLE *UserHandle,\r
+ IN EFI_GUID *Protocol,\r
+ IN EFI_INTERFACE_TYPE InterfaceType,\r
+ IN VOID *Interface\r
+ )\r
+{\r
+ return SmmInstallProtocolInterfaceNotify (\r
+ UserHandle,\r
+ Protocol,\r
+ InterfaceType,\r
+ Interface,\r
+ TRUE\r
+ );\r
+}\r
+\r
+/**\r
+ Installs a protocol interface into the boot services environment.\r
+\r
+ @param UserHandle The handle to install the protocol handler on,\r
+ or NULL if a new handle is to be allocated\r
+ @param Protocol The protocol to add to the handle\r
+ @param InterfaceType Indicates whether Interface is supplied in\r
+ native form.\r
+ @param Interface The interface for the protocol being added\r
+ @param Notify indicates whether notify the notification list\r
+ for this protocol\r
+\r
+ @retval EFI_INVALID_PARAMETER Invalid parameter\r
+ @retval EFI_OUT_OF_RESOURCES No enough buffer to allocate\r
+ @retval EFI_SUCCESS Protocol interface successfully installed\r
+\r
+**/\r
+EFI_STATUS\r
+SmmInstallProtocolInterfaceNotify (\r
+ IN OUT EFI_HANDLE *UserHandle,\r
+ IN EFI_GUID *Protocol,\r
+ IN EFI_INTERFACE_TYPE InterfaceType,\r
+ IN VOID *Interface,\r
+ IN BOOLEAN Notify\r
+ )\r
+{\r
+ PROTOCOL_INTERFACE *Prot;\r
+ PROTOCOL_ENTRY *ProtEntry;\r
+ IHANDLE *Handle;\r
+ EFI_STATUS Status;\r
+ VOID *ExistingInterface;\r
+\r
+ //\r
+ // returns EFI_INVALID_PARAMETER if InterfaceType is invalid.\r
+ // Also added check for invalid UserHandle and Protocol pointers.\r
+ //\r
+ if (UserHandle == NULL || Protocol == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ if (InterfaceType != EFI_NATIVE_INTERFACE) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ //\r
+ // Print debug message\r
+ //\r
+ DEBUG((DEBUG_LOAD | DEBUG_INFO, "SmmInstallProtocolInterface: %g %p\n", Protocol, Interface));\r
+\r
+ Status = EFI_OUT_OF_RESOURCES;\r
+ Prot = NULL;\r
+ Handle = NULL;\r
+\r
+ if (*UserHandle != NULL) {\r
+ Status = SmmHandleProtocol (*UserHandle, Protocol, (VOID **)&ExistingInterface);\r
+ if (!EFI_ERROR (Status)) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+ }\r
+\r
+ //\r
+ // Lookup the Protocol Entry for the requested protocol\r
+ //\r
+ ProtEntry = SmmFindProtocolEntry (Protocol, TRUE);\r
+ if (ProtEntry == NULL) {\r
+ goto Done;\r
+ }\r
+\r
+ //\r
+ // Allocate a new protocol interface structure\r
+ //\r
+ Prot = AllocateZeroPool (sizeof(PROTOCOL_INTERFACE));\r
+ if (Prot == NULL) {\r
+ Status = EFI_OUT_OF_RESOURCES;\r
+ goto Done;\r
+ }\r
+\r
+ //\r
+ // If caller didn't supply a handle, allocate a new one\r
+ //\r
+ Handle = (IHANDLE *)*UserHandle;\r
+ if (Handle == NULL) {\r
+ Handle = AllocateZeroPool (sizeof(IHANDLE));\r
+ if (Handle == NULL) {\r
+ Status = EFI_OUT_OF_RESOURCES;\r
+ goto Done;\r
+ }\r
+\r
+ //\r
+ // Initialize new handler structure\r
+ //\r
+ Handle->Signature = EFI_HANDLE_SIGNATURE;\r
+ InitializeListHead (&Handle->Protocols);\r
+\r
+ //\r
+ // Add this handle to the list global list of all handles\r
+ // in the system\r
+ //\r
+ InsertTailList (&gHandleList, &Handle->AllHandles);\r
+ }\r
+\r
+ Status = SmmValidateHandle (Handle);\r
+ if (EFI_ERROR (Status)) {\r
+ goto Done;\r
+ }\r
+\r
+ //\r
+ // Each interface that is added must be unique\r
+ //\r
+ ASSERT (SmmFindProtocolInterface (Handle, Protocol, Interface) == NULL);\r
+\r
+ //\r
+ // Initialize the protocol interface structure\r
+ //\r
+ Prot->Signature = PROTOCOL_INTERFACE_SIGNATURE;\r
+ Prot->Handle = Handle;\r
+ Prot->Protocol = ProtEntry;\r
+ Prot->Interface = Interface;\r
+\r
+ //\r
+ // Add this protocol interface to the head of the supported\r
+ // protocol list for this handle\r
+ //\r
+ InsertHeadList (&Handle->Protocols, &Prot->Link);\r
+\r
+ //\r
+ // Add this protocol interface to the tail of the\r
+ // protocol entry\r
+ //\r
+ InsertTailList (&ProtEntry->Protocols, &Prot->ByProtocol);\r
+\r
+ //\r
+ // Notify the notification list for this protocol\r
+ //\r
+ if (Notify) {\r
+ SmmNotifyProtocol (Prot);\r
+ }\r
+ Status = EFI_SUCCESS;\r
+\r
+Done:\r
+ if (!EFI_ERROR (Status)) {\r
+ //\r
+ // Return the new handle back to the caller\r
+ //\r
+ *UserHandle = Handle;\r
+ } else {\r
+ //\r
+ // There was an error, clean up\r
+ //\r
+ if (Prot != NULL) {\r
+ FreePool (Prot);\r
+ }\r
+ }\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Uninstalls all instances of a protocol:interfacer from a handle.\r
+ If the last protocol interface is remove from the handle, the\r
+ handle is freed.\r
+\r
+ @param UserHandle The handle to remove the protocol handler from\r
+ @param Protocol The protocol, of protocol:interface, to remove\r
+ @param Interface The interface, of protocol:interface, to remove\r
+\r
+ @retval EFI_INVALID_PARAMETER Protocol is NULL.\r
+ @retval EFI_SUCCESS Protocol interface successfully uninstalled.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SmmUninstallProtocolInterface (\r
+ IN EFI_HANDLE UserHandle,\r
+ IN EFI_GUID *Protocol,\r
+ IN VOID *Interface\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ IHANDLE *Handle;\r
+ PROTOCOL_INTERFACE *Prot;\r
+\r
+ //\r
+ // Check that Protocol is valid\r
+ //\r
+ if (Protocol == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ //\r
+ // Check that UserHandle is a valid handle\r
+ //\r
+ Status = SmmValidateHandle (UserHandle);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ //\r
+ // Check that Protocol exists on UserHandle, and Interface matches the interface in the database\r
+ //\r
+ Prot = SmmFindProtocolInterface (UserHandle, Protocol, Interface);\r
+ if (Prot == NULL) {\r
+ return EFI_NOT_FOUND;\r
+ }\r
+\r
+ //\r
+ // Remove the protocol interface from the protocol\r
+ //\r
+ Status = EFI_NOT_FOUND;\r
+ Handle = (IHANDLE *)UserHandle;\r
+ Prot = SmmRemoveInterfaceFromProtocol (Handle, Protocol, Interface);\r
+\r
+ if (Prot != NULL) {\r
+ //\r
+ // Remove the protocol interface from the handle\r
+ //\r
+ RemoveEntryList (&Prot->Link);\r
+\r
+ //\r
+ // Free the memory\r
+ //\r
+ Prot->Signature = 0;\r
+ FreePool (Prot);\r
+ Status = EFI_SUCCESS;\r
+ }\r
+\r
+ //\r
+ // If there are no more handlers for the handle, free the handle\r
+ //\r
+ if (IsListEmpty (&Handle->Protocols)) {\r
+ Handle->Signature = 0;\r
+ RemoveEntryList (&Handle->AllHandles);\r
+ FreePool (Handle);\r
+ }\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Locate a certain GUID protocol interface in a Handle's protocols.\r
+\r
+ @param UserHandle The handle to obtain the protocol interface on\r
+ @param Protocol The GUID of the protocol\r
+\r
+ @return The requested protocol interface for the handle\r
+\r
+**/\r
+PROTOCOL_INTERFACE *\r
+SmmGetProtocolInterface (\r
+ IN EFI_HANDLE UserHandle,\r
+ IN EFI_GUID *Protocol\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ PROTOCOL_ENTRY *ProtEntry;\r
+ PROTOCOL_INTERFACE *Prot;\r
+ IHANDLE *Handle;\r
+ LIST_ENTRY *Link;\r
+\r
+ Status = SmmValidateHandle (UserHandle);\r
+ if (EFI_ERROR (Status)) {\r
+ return NULL;\r
+ }\r
+\r
+ Handle = (IHANDLE *)UserHandle;\r
+\r
+ //\r
+ // Look at each protocol interface for a match\r
+ //\r
+ for (Link = Handle->Protocols.ForwardLink; Link != &Handle->Protocols; Link = Link->ForwardLink) {\r
+ Prot = CR(Link, PROTOCOL_INTERFACE, Link, PROTOCOL_INTERFACE_SIGNATURE);\r
+ ProtEntry = Prot->Protocol;\r
+ if (CompareGuid (&ProtEntry->ProtocolID, Protocol)) {\r
+ return Prot;\r
+ }\r
+ }\r
+ return NULL;\r
+}\r
+\r
+/**\r
+ Queries a handle to determine if it supports a specified protocol.\r
+\r
+ @param UserHandle The handle being queried.\r
+ @param Protocol The published unique identifier of the protocol.\r
+ @param Interface Supplies the address where a pointer to the\r
+ corresponding Protocol Interface is returned.\r
+\r
+ @retval EFI_SUCCESS The interface information for the specified protocol was returned.\r
+ @retval EFI_UNSUPPORTED The device does not support the specified protocol.\r
+ @retval EFI_INVALID_PARAMETER Handle is not a valid EFI_HANDLE..\r
+ @retval EFI_INVALID_PARAMETER Protocol is NULL.\r
+ @retval EFI_INVALID_PARAMETER Interface is NULL.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SmmHandleProtocol (\r
+ IN EFI_HANDLE UserHandle,\r
+ IN EFI_GUID *Protocol,\r
+ OUT VOID **Interface\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ PROTOCOL_INTERFACE *Prot;\r
+\r
+ //\r
+ // Check for invalid Protocol\r
+ //\r
+ if (Protocol == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ //\r
+ // Check for invalid Interface\r
+ //\r
+ if (Interface == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ } else {\r
+ *Interface = NULL;\r
+ }\r
+\r
+ //\r
+ // Check for invalid UserHandle\r
+ //\r
+ Status = SmmValidateHandle (UserHandle);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ //\r
+ // Look at each protocol interface for a match\r
+ //\r
+ Prot = SmmGetProtocolInterface (UserHandle, Protocol);\r
+ if (Prot == NULL) {\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+\r
+ //\r
+ // This is the protocol interface entry for this protocol\r
+ //\r
+ *Interface = Prot->Interface;\r
+\r
+ return EFI_SUCCESS;\r
+}\r
--- /dev/null
+/** @file\r
+ System Management System Table Services SmmInstallConfigurationTable service\r
+\r
+ Copyright (c) 2009 - 2010, Intel Corporation. All rights reserved.<BR>\r
+ This program and the accompanying materials are licensed and made available \r
+ under the terms and conditions of the BSD License which accompanies this \r
+ distribution. The full text of the license may be found at \r
+ http://opensource.org/licenses/bsd-license.php \r
+\r
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, \r
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. \r
+\r
+**/\r
+\r
+#include "PiSmmCore.h"\r
+\r
+#define CONFIG_TABLE_SIZE_INCREASED 0x10\r
+\r
+UINTN mSmmSystemTableAllocateSize = 0;\r
+\r
+/**\r
+ The SmmInstallConfigurationTable() function is used to maintain the list\r
+ of configuration tables that are stored in the System Management System\r
+ Table. The list is stored as an array of (GUID, Pointer) pairs. The list\r
+ must be allocated from pool memory with PoolType set to EfiRuntimeServicesData.\r
+\r
+ @param SystemTable A pointer to the SMM System Table (SMST).\r
+ @param Guid A pointer to the GUID for the entry to add, update, or remove.\r
+ @param Table A pointer to the buffer of the table to add.\r
+ @param TableSize The size of the table to install.\r
+\r
+ @retval EFI_SUCCESS The (Guid, Table) pair was added, updated, or removed.\r
+ @retval EFI_INVALID_PARAMETER Guid is not valid.\r
+ @retval EFI_NOT_FOUND An attempt was made to delete a non-existent entry.\r
+ @retval EFI_OUT_OF_RESOURCES There is not enough memory available to complete the operation.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SmmInstallConfigurationTable (\r
+ IN CONST EFI_SMM_SYSTEM_TABLE2 *SystemTable,\r
+ IN CONST EFI_GUID *Guid,\r
+ IN VOID *Table,\r
+ IN UINTN TableSize\r
+ )\r
+{\r
+ UINTN Index;\r
+ EFI_CONFIGURATION_TABLE *ConfigurationTable;\r
+\r
+ //\r
+ // If Guid is NULL, then this operation cannot be performed\r
+ //\r
+ if (Guid == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ ConfigurationTable = gSmmCoreSmst.SmmConfigurationTable;\r
+\r
+ //\r
+ // Search all the table for an entry that matches Guid\r
+ //\r
+ for (Index = 0; Index < gSmmCoreSmst.NumberOfTableEntries; Index++) {\r
+ if (CompareGuid (Guid, &(ConfigurationTable[Index].VendorGuid))) {\r
+ break;\r
+ }\r
+ }\r
+\r
+ if (Index < gSmmCoreSmst.NumberOfTableEntries) {\r
+ //\r
+ // A match was found, so this is either a modify or a delete operation\r
+ //\r
+ if (Table != NULL) {\r
+ //\r
+ // If Table is not NULL, then this is a modify operation.\r
+ // Modify the table enty and return.\r
+ //\r
+ ConfigurationTable[Index].VendorTable = Table;\r
+ return EFI_SUCCESS;\r
+ }\r
+\r
+ //\r
+ // A match was found and Table is NULL, so this is a delete operation.\r
+ //\r
+ gSmmCoreSmst.NumberOfTableEntries--;\r
+\r
+ //\r
+ // Copy over deleted entry\r
+ //\r
+ CopyMem (\r
+ &(ConfigurationTable[Index]),\r
+ &(ConfigurationTable[Index + 1]),\r
+ (gSmmCoreSmst.NumberOfTableEntries - Index) * sizeof (EFI_CONFIGURATION_TABLE)\r
+ );\r
+\r
+ } else {\r
+ //\r
+ // No matching GUIDs were found, so this is an add operation.\r
+ //\r
+ if (Table == NULL) {\r
+ //\r
+ // If Table is NULL on an add operation, then return an error.\r
+ //\r
+ return EFI_NOT_FOUND;\r
+ }\r
+\r
+ //\r
+ // Assume that Index == gSmmCoreSmst.NumberOfTableEntries\r
+ //\r
+ if ((Index * sizeof (EFI_CONFIGURATION_TABLE)) >= mSmmSystemTableAllocateSize) {\r
+ //\r
+ // Allocate a table with one additional entry.\r
+ //\r
+ mSmmSystemTableAllocateSize += (CONFIG_TABLE_SIZE_INCREASED * sizeof (EFI_CONFIGURATION_TABLE));\r
+ ConfigurationTable = AllocatePool (mSmmSystemTableAllocateSize);\r
+ if (ConfigurationTable == NULL) {\r
+ //\r
+ // If a new table could not be allocated, then return an error.\r
+ //\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ if (gSmmCoreSmst.SmmConfigurationTable != NULL) {\r
+ //\r
+ // Copy the old table to the new table.\r
+ //\r
+ CopyMem (\r
+ ConfigurationTable,\r
+ gSmmCoreSmst.SmmConfigurationTable,\r
+ Index * sizeof (EFI_CONFIGURATION_TABLE)\r
+ );\r
+\r
+ //\r
+ // Free Old Table\r
+ //\r
+ FreePool (gSmmCoreSmst.SmmConfigurationTable);\r
+ }\r
+\r
+ //\r
+ // Update System Table\r
+ //\r
+ gSmmCoreSmst.SmmConfigurationTable = ConfigurationTable;\r
+ }\r
+\r
+ //\r
+ // Fill in the new entry\r
+ //\r
+ CopyGuid ((VOID *)&ConfigurationTable[Index].VendorGuid, Guid);\r
+ ConfigurationTable[Index].VendorTable = Table;\r
+\r
+ //\r
+ // This is an add operation, so increment the number of table entries\r
+ //\r
+ gSmmCoreSmst.NumberOfTableEntries++;\r
+ }\r
+\r
+ //\r
+ // CRC-32 field is ignorable for SMM System Table and should be set to zero\r
+ //\r
+\r
+ return EFI_SUCCESS;\r
+}\r
--- /dev/null
+/** @file\r
+ Locate handle functions\r
+\r
+ Copyright (c) 2009 - 2010, Intel Corporation. All rights reserved.<BR>\r
+ This program and the accompanying materials are licensed and made available \r
+ under the terms and conditions of the BSD License which accompanies this \r
+ distribution. The full text of the license may be found at \r
+ http://opensource.org/licenses/bsd-license.php \r
+\r
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, \r
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. \r
+\r
+**/\r
+\r
+#include "PiSmmCore.h"\r
+\r
+//\r
+// ProtocolRequest - Last LocateHandle request ID\r
+//\r
+UINTN mEfiLocateHandleRequest = 0;\r
+\r
+//\r
+// Internal prototypes\r
+//\r
+\r
+typedef struct {\r
+ EFI_GUID *Protocol;\r
+ VOID *SearchKey;\r
+ LIST_ENTRY *Position;\r
+ PROTOCOL_ENTRY *ProtEntry;\r
+} LOCATE_POSITION;\r
+\r
+typedef\r
+IHANDLE *\r
+(* CORE_GET_NEXT) (\r
+ IN OUT LOCATE_POSITION *Position,\r
+ OUT VOID **Interface\r
+ );\r
+\r
+/**\r
+ Routine to get the next Handle, when you are searching for all handles.\r
+\r
+ @param Position Information about which Handle to seach for.\r
+ @param Interface Return the interface structure for the matching\r
+ protocol.\r
+\r
+ @return An pointer to IHANDLE if the next Position is not the end of the list.\r
+ Otherwise,NULL is returned.\r
+\r
+**/\r
+IHANDLE *\r
+SmmGetNextLocateAllHandles (\r
+ IN OUT LOCATE_POSITION *Position,\r
+ OUT VOID **Interface\r
+ )\r
+{\r
+ IHANDLE *Handle;\r
+\r
+ //\r
+ // Next handle\r
+ //\r
+ Position->Position = Position->Position->ForwardLink;\r
+\r
+ //\r
+ // If not at the end of the list, get the handle\r
+ //\r
+ Handle = NULL;\r
+ *Interface = NULL;\r
+ if (Position->Position != &gHandleList) {\r
+ Handle = CR (Position->Position, IHANDLE, AllHandles, EFI_HANDLE_SIGNATURE);\r
+ }\r
+ return Handle;\r
+}\r
+\r
+/**\r
+ Routine to get the next Handle, when you are searching for register protocol\r
+ notifies.\r
+\r
+ @param Position Information about which Handle to seach for.\r
+ @param Interface Return the interface structure for the matching\r
+ protocol.\r
+\r
+ @return An pointer to IHANDLE if the next Position is not the end of the list.\r
+ Otherwise,NULL is returned.\r
+\r
+**/\r
+IHANDLE *\r
+SmmGetNextLocateByRegisterNotify (\r
+ IN OUT LOCATE_POSITION *Position,\r
+ OUT VOID **Interface\r
+ )\r
+{\r
+ IHANDLE *Handle;\r
+ PROTOCOL_NOTIFY *ProtNotify;\r
+ PROTOCOL_INTERFACE *Prot;\r
+ LIST_ENTRY *Link;\r
+\r
+ Handle = NULL;\r
+ *Interface = NULL;\r
+ ProtNotify = Position->SearchKey;\r
+\r
+ //\r
+ // If this is the first request, get the next handle\r
+ //\r
+ if (ProtNotify != NULL) {\r
+ ASSERT(ProtNotify->Signature == PROTOCOL_NOTIFY_SIGNATURE);\r
+ Position->SearchKey = NULL;\r
+\r
+ //\r
+ // If not at the end of the list, get the next handle\r
+ //\r
+ Link = ProtNotify->Position->ForwardLink;\r
+ if (Link != &ProtNotify->Protocol->Protocols) {\r
+ Prot = CR (Link, PROTOCOL_INTERFACE, ByProtocol, PROTOCOL_INTERFACE_SIGNATURE);\r
+ Handle = Prot->Handle;\r
+ *Interface = Prot->Interface;\r
+ }\r
+ }\r
+ return Handle;\r
+}\r
+\r
+/**\r
+ Routine to get the next Handle, when you are searching for a given protocol.\r
+\r
+ @param Position Information about which Handle to seach for.\r
+ @param Interface Return the interface structure for the matching\r
+ protocol.\r
+\r
+ @return An pointer to IHANDLE if the next Position is not the end of the list.\r
+ Otherwise,NULL is returned.\r
+\r
+**/\r
+IHANDLE *\r
+SmmGetNextLocateByProtocol (\r
+ IN OUT LOCATE_POSITION *Position,\r
+ OUT VOID **Interface\r
+ )\r
+{\r
+ IHANDLE *Handle;\r
+ LIST_ENTRY *Link;\r
+ PROTOCOL_INTERFACE *Prot;\r
+\r
+ Handle = NULL;\r
+ *Interface = NULL;\r
+ for (; ;) {\r
+ //\r
+ // Next entry\r
+ //\r
+ Link = Position->Position->ForwardLink;\r
+ Position->Position = Link;\r
+\r
+ //\r
+ // If not at the end, return the handle\r
+ //\r
+ if (Link == &Position->ProtEntry->Protocols) {\r
+ Handle = NULL;\r
+ break;\r
+ }\r
+\r
+ //\r
+ // Get the handle\r
+ //\r
+ Prot = CR(Link, PROTOCOL_INTERFACE, ByProtocol, PROTOCOL_INTERFACE_SIGNATURE);\r
+ Handle = Prot->Handle;\r
+ *Interface = Prot->Interface;\r
+\r
+ //\r
+ // If this handle has not been returned this request, then\r
+ // return it now\r
+ //\r
+ if (Handle->LocateRequest != mEfiLocateHandleRequest) {\r
+ Handle->LocateRequest = mEfiLocateHandleRequest;\r
+ break;\r
+ }\r
+ }\r
+ return Handle;\r
+}\r
+\r
+/**\r
+ Return the first Protocol Interface that matches the Protocol GUID. If\r
+ Registration is pasased in return a Protocol Instance that was just add\r
+ to the system. If Retistration is NULL return the first Protocol Interface\r
+ you find.\r
+\r
+ @param Protocol The protocol to search for\r
+ @param Registration Optional Registration Key returned from\r
+ RegisterProtocolNotify()\r
+ @param Interface Return the Protocol interface (instance).\r
+\r
+ @retval EFI_SUCCESS If a valid Interface is returned\r
+ @retval EFI_INVALID_PARAMETER Invalid parameter\r
+ @retval EFI_NOT_FOUND Protocol interface not found\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SmmLocateProtocol (\r
+ IN EFI_GUID *Protocol,\r
+ IN VOID *Registration OPTIONAL,\r
+ OUT VOID **Interface\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ LOCATE_POSITION Position;\r
+ PROTOCOL_NOTIFY *ProtNotify;\r
+ IHANDLE *Handle;\r
+\r
+ if (Interface == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ if (Protocol == NULL) {\r
+ return EFI_NOT_FOUND;\r
+ }\r
+\r
+ *Interface = NULL;\r
+ Status = EFI_SUCCESS;\r
+\r
+ //\r
+ // Set initial position\r
+ //\r
+ Position.Protocol = Protocol;\r
+ Position.SearchKey = Registration;\r
+ Position.Position = &gHandleList;\r
+\r
+ mEfiLocateHandleRequest += 1;\r
+\r
+ if (Registration == NULL) {\r
+ //\r
+ // Look up the protocol entry and set the head pointer\r
+ //\r
+ Position.ProtEntry = SmmFindProtocolEntry (Protocol, FALSE);\r
+ if (Position.ProtEntry == NULL) {\r
+ return EFI_NOT_FOUND;\r
+ }\r
+ Position.Position = &Position.ProtEntry->Protocols;\r
+\r
+ Handle = SmmGetNextLocateByProtocol (&Position, Interface);\r
+ } else {\r
+ Handle = SmmGetNextLocateByRegisterNotify (&Position, Interface);\r
+ }\r
+\r
+ if (Handle == NULL) {\r
+ Status = EFI_NOT_FOUND;\r
+ } else if (Registration != NULL) {\r
+ //\r
+ // If this is a search by register notify and a handle was\r
+ // returned, update the register notification position\r
+ //\r
+ ProtNotify = Registration;\r
+ ProtNotify->Position = ProtNotify->Position->ForwardLink;\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Locates the requested handle(s) and returns them in Buffer.\r
+\r
+ @param SearchType The type of search to perform to locate the\r
+ handles\r
+ @param Protocol The protocol to search for\r
+ @param SearchKey Dependant on SearchType\r
+ @param BufferSize On input the size of Buffer. On output the\r
+ size of data returned.\r
+ @param Buffer The buffer to return the results in\r
+\r
+ @retval EFI_BUFFER_TOO_SMALL Buffer too small, required buffer size is\r
+ returned in BufferSize.\r
+ @retval EFI_INVALID_PARAMETER Invalid parameter\r
+ @retval EFI_SUCCESS Successfully found the requested handle(s) and\r
+ returns them in Buffer.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SmmLocateHandle (\r
+ IN EFI_LOCATE_SEARCH_TYPE SearchType,\r
+ IN EFI_GUID *Protocol OPTIONAL,\r
+ IN VOID *SearchKey OPTIONAL,\r
+ IN OUT UINTN *BufferSize,\r
+ OUT EFI_HANDLE *Buffer\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ LOCATE_POSITION Position;\r
+ PROTOCOL_NOTIFY *ProtNotify;\r
+ CORE_GET_NEXT GetNext;\r
+ UINTN ResultSize;\r
+ IHANDLE *Handle;\r
+ IHANDLE **ResultBuffer;\r
+ VOID *Interface;\r
+\r
+ if (BufferSize == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ if ((*BufferSize > 0) && (Buffer == NULL)) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ GetNext = NULL;\r
+\r
+ //\r
+ // Set initial position\r
+ //\r
+ Position.Protocol = Protocol;\r
+ Position.SearchKey = SearchKey;\r
+ Position.Position = &gHandleList;\r
+\r
+ ResultSize = 0;\r
+ ResultBuffer = (IHANDLE **) Buffer;\r
+ Status = EFI_SUCCESS;\r
+\r
+ //\r
+ // Get the search function based on type\r
+ //\r
+ switch (SearchType) {\r
+ case AllHandles:\r
+ GetNext = SmmGetNextLocateAllHandles;\r
+ break;\r
+\r
+ case ByRegisterNotify:\r
+ //\r
+ // Must have SearchKey for locate ByRegisterNotify\r
+ //\r
+ if (SearchKey == NULL) {\r
+ Status = EFI_INVALID_PARAMETER;\r
+ break;\r
+ }\r
+ GetNext = SmmGetNextLocateByRegisterNotify;\r
+ break;\r
+\r
+ case ByProtocol:\r
+ GetNext = SmmGetNextLocateByProtocol;\r
+ if (Protocol == NULL) {\r
+ Status = EFI_INVALID_PARAMETER;\r
+ break;\r
+ }\r
+ //\r
+ // Look up the protocol entry and set the head pointer\r
+ //\r
+ Position.ProtEntry = SmmFindProtocolEntry (Protocol, FALSE);\r
+ if (Position.ProtEntry == NULL) {\r
+ Status = EFI_NOT_FOUND;\r
+ break;\r
+ }\r
+ Position.Position = &Position.ProtEntry->Protocols;\r
+ break;\r
+\r
+ default:\r
+ Status = EFI_INVALID_PARAMETER;\r
+ break;\r
+ }\r
+\r
+ if (EFI_ERROR(Status)) {\r
+ return Status;\r
+ }\r
+\r
+ //\r
+ // Enumerate out the matching handles\r
+ //\r
+ mEfiLocateHandleRequest += 1;\r
+ for (; ;) {\r
+ //\r
+ // Get the next handle. If no more handles, stop\r
+ //\r
+ Handle = GetNext (&Position, &Interface);\r
+ if (NULL == Handle) {\r
+ break;\r
+ }\r
+\r
+ //\r
+ // Increase the resulting buffer size, and if this handle\r
+ // fits return it\r
+ //\r
+ ResultSize += sizeof(Handle);\r
+ if (ResultSize <= *BufferSize) {\r
+ *ResultBuffer = Handle;\r
+ ResultBuffer += 1;\r
+ }\r
+ }\r
+\r
+ //\r
+ // If the result is a zero length buffer, then there were no\r
+ // matching handles\r
+ //\r
+ if (ResultSize == 0) {\r
+ Status = EFI_NOT_FOUND;\r
+ } else {\r
+ //\r
+ // Return the resulting buffer size. If it's larger than what\r
+ // was passed, then set the error code\r
+ //\r
+ if (ResultSize > *BufferSize) {\r
+ Status = EFI_BUFFER_TOO_SMALL;\r
+ }\r
+\r
+ *BufferSize = ResultSize;\r
+\r
+ if (SearchType == ByRegisterNotify && !EFI_ERROR(Status)) {\r
+ //\r
+ // If this is a search by register notify and a handle was\r
+ // returned, update the register notification position\r
+ //\r
+ ProtNotify = SearchKey;\r
+ ProtNotify->Position = ProtNotify->Position->ForwardLink;\r
+ }\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Function returns an array of handles that support the requested protocol\r
+ in a buffer allocated from pool. This is a version of SmmLocateHandle()\r
+ that allocates a buffer for the caller.\r
+\r
+ @param SearchType Specifies which handle(s) are to be returned.\r
+ @param Protocol Provides the protocol to search by. This\r
+ parameter is only valid for SearchType\r
+ ByProtocol.\r
+ @param SearchKey Supplies the search key depending on the\r
+ SearchType.\r
+ @param NumberHandles The number of handles returned in Buffer.\r
+ @param Buffer A pointer to the buffer to return the requested\r
+ array of handles that support Protocol.\r
+\r
+ @retval EFI_SUCCESS The result array of handles was returned.\r
+ @retval EFI_NOT_FOUND No handles match the search.\r
+ @retval EFI_OUT_OF_RESOURCES There is not enough pool memory to store the\r
+ matching results.\r
+ @retval EFI_INVALID_PARAMETER One or more paramters are not valid.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SmmLocateHandleBuffer (\r
+ IN EFI_LOCATE_SEARCH_TYPE SearchType,\r
+ IN EFI_GUID *Protocol OPTIONAL,\r
+ IN VOID *SearchKey OPTIONAL,\r
+ IN OUT UINTN *NumberHandles,\r
+ OUT EFI_HANDLE **Buffer\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINTN BufferSize;\r
+\r
+ if (NumberHandles == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ if (Buffer == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ BufferSize = 0;\r
+ *NumberHandles = 0;\r
+ *Buffer = NULL;\r
+ Status = SmmLocateHandle (\r
+ SearchType,\r
+ Protocol,\r
+ SearchKey,\r
+ &BufferSize,\r
+ *Buffer\r
+ );\r
+ //\r
+ // LocateHandleBuffer() returns incorrect status code if SearchType is\r
+ // invalid.\r
+ //\r
+ // Add code to correctly handle expected errors from SmmLocateHandle().\r
+ //\r
+ if (EFI_ERROR(Status) && Status != EFI_BUFFER_TOO_SMALL) {\r
+ if (Status != EFI_INVALID_PARAMETER) {\r
+ Status = EFI_NOT_FOUND;\r
+ }\r
+ return Status;\r
+ }\r
+\r
+ *Buffer = AllocatePool (BufferSize);\r
+ if (*Buffer == NULL) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ Status = SmmLocateHandle (\r
+ SearchType,\r
+ Protocol,\r
+ SearchKey,\r
+ &BufferSize,\r
+ *Buffer\r
+ );\r
+\r
+ *NumberHandles = BufferSize / sizeof(EFI_HANDLE);\r
+ if (EFI_ERROR(Status)) {\r
+ *NumberHandles = 0;\r
+ }\r
+\r
+ return Status;\r
+}\r
--- /dev/null
+/** @file\r
+ Support functions for UEFI protocol notification infrastructure.\r
+\r
+ Copyright (c) 2009 - 2010, Intel Corporation. All rights reserved.<BR>\r
+ This program and the accompanying materials are licensed and made available \r
+ under the terms and conditions of the BSD License which accompanies this \r
+ distribution. The full text of the license may be found at \r
+ http://opensource.org/licenses/bsd-license.php \r
+\r
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, \r
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. \r
+\r
+**/\r
+\r
+#include "PiSmmCore.h"\r
+\r
+/**\r
+ Signal event for every protocol in protocol entry.\r
+\r
+ @param Prot Protocol interface\r
+\r
+**/\r
+VOID\r
+SmmNotifyProtocol (\r
+ IN PROTOCOL_INTERFACE *Prot\r
+ )\r
+{\r
+ PROTOCOL_ENTRY *ProtEntry;\r
+ PROTOCOL_NOTIFY *ProtNotify;\r
+ LIST_ENTRY *Link;\r
+\r
+ ProtEntry = Prot->Protocol;\r
+ for (Link=ProtEntry->Notify.ForwardLink; Link != &ProtEntry->Notify; Link=Link->ForwardLink) {\r
+ ProtNotify = CR(Link, PROTOCOL_NOTIFY, Link, PROTOCOL_NOTIFY_SIGNATURE);\r
+ ProtNotify->Function (&ProtEntry->ProtocolID, Prot->Interface, Prot->Handle);\r
+ }\r
+}\r
+\r
+/**\r
+ Removes Protocol from the protocol list (but not the handle list).\r
+\r
+ @param Handle The handle to remove protocol on.\r
+ @param Protocol GUID of the protocol to be moved\r
+ @param Interface The interface of the protocol\r
+\r
+ @return Protocol Entry\r
+\r
+**/\r
+PROTOCOL_INTERFACE *\r
+SmmRemoveInterfaceFromProtocol (\r
+ IN IHANDLE *Handle,\r
+ IN EFI_GUID *Protocol,\r
+ IN VOID *Interface\r
+ )\r
+{\r
+ PROTOCOL_INTERFACE *Prot;\r
+ PROTOCOL_NOTIFY *ProtNotify;\r
+ PROTOCOL_ENTRY *ProtEntry;\r
+ LIST_ENTRY *Link;\r
+\r
+ Prot = SmmFindProtocolInterface (Handle, Protocol, Interface);\r
+ if (Prot != NULL) {\r
+\r
+ ProtEntry = Prot->Protocol;\r
+\r
+ //\r
+ // If there's a protocol notify location pointing to this entry, back it up one\r
+ //\r
+ for(Link = ProtEntry->Notify.ForwardLink; Link != &ProtEntry->Notify; Link=Link->ForwardLink) {\r
+ ProtNotify = CR(Link, PROTOCOL_NOTIFY, Link, PROTOCOL_NOTIFY_SIGNATURE);\r
+\r
+ if (ProtNotify->Position == &Prot->ByProtocol) {\r
+ ProtNotify->Position = Prot->ByProtocol.BackLink;\r
+ }\r
+ }\r
+\r
+ //\r
+ // Remove the protocol interface entry\r
+ //\r
+ RemoveEntryList (&Prot->ByProtocol);\r
+ }\r
+\r
+ return Prot;\r
+}\r
+\r
+/**\r
+ Add a new protocol notification record for the request protocol.\r
+\r
+ @param Protocol The requested protocol to add the notify\r
+ registration\r
+ @param Function Points to the notification function\r
+ @param Registration Returns the registration record\r
+\r
+ @retval EFI_INVALID_PARAMETER Invalid parameter\r
+ @retval EFI_SUCCESS Successfully returned the registration record\r
+ that has been added\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SmmRegisterProtocolNotify (\r
+ IN CONST EFI_GUID *Protocol,\r
+ IN EFI_SMM_NOTIFY_FN Function,\r
+ OUT VOID **Registration\r
+ )\r
+{\r
+ PROTOCOL_ENTRY *ProtEntry;\r
+ PROTOCOL_NOTIFY *ProtNotify;\r
+ LIST_ENTRY *Link;\r
+ EFI_STATUS Status;\r
+\r
+ if ((Protocol == NULL) || (Function == NULL) || (Registration == NULL)) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ ProtNotify = NULL;\r
+\r
+ //\r
+ // Get the protocol entry to add the notification too\r
+ //\r
+ ProtEntry = SmmFindProtocolEntry ((EFI_GUID *) Protocol, TRUE);\r
+ if (ProtEntry != NULL) {\r
+ //\r
+ // Find whether notification already exist\r
+ //\r
+ for (Link = ProtEntry->Notify.ForwardLink;\r
+ Link != &ProtEntry->Notify;\r
+ Link = Link->ForwardLink) {\r
+\r
+ ProtNotify = CR(Link, PROTOCOL_NOTIFY, Link, PROTOCOL_NOTIFY_SIGNATURE);\r
+ if (CompareGuid (&ProtNotify->Protocol->ProtocolID, Protocol) &&\r
+ (ProtNotify->Function == Function)) {\r
+\r
+ //\r
+ // Notification already exist\r
+ //\r
+ *Registration = ProtNotify;\r
+\r
+ return EFI_SUCCESS;\r
+ }\r
+ }\r
+\r
+ //\r
+ // Allocate a new notification record\r
+ //\r
+ ProtNotify = AllocatePool (sizeof(PROTOCOL_NOTIFY));\r
+ if (ProtNotify != NULL) {\r
+ ProtNotify->Signature = PROTOCOL_NOTIFY_SIGNATURE;\r
+ ProtNotify->Protocol = ProtEntry;\r
+ ProtNotify->Function = Function;\r
+ //\r
+ // Start at the ending\r
+ //\r
+ ProtNotify->Position = ProtEntry->Protocols.BackLink;\r
+\r
+ InsertTailList (&ProtEntry->Notify, &ProtNotify->Link);\r
+ }\r
+ }\r
+\r
+ //\r
+ // Done. If we have a protocol notify entry, then return it.\r
+ // Otherwise, we must have run out of resources trying to add one\r
+ //\r
+ Status = EFI_OUT_OF_RESOURCES;\r
+ if (ProtNotify != NULL) {\r
+ *Registration = ProtNotify;\r
+ Status = EFI_SUCCESS;\r
+ }\r
+ return Status;\r
+}\r
--- /dev/null
+/** @file\r
+ SMM Memory page management functions.\r
+\r
+ Copyright (c) 2009 - 2010, Intel Corporation. All rights reserved.<BR>\r
+ This program and the accompanying materials are licensed and made available \r
+ under the terms and conditions of the BSD License which accompanies this \r
+ distribution. The full text of the license may be found at \r
+ http://opensource.org/licenses/bsd-license.php \r
+\r
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, \r
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. \r
+\r
+**/\r
+\r
+#include "PiSmmCore.h"\r
+\r
+#define TRUNCATE_TO_PAGES(a) ((a) >> EFI_PAGE_SHIFT)\r
+\r
+typedef struct {\r
+ LIST_ENTRY Link;\r
+ UINTN NumberOfPages;\r
+} FREE_PAGE_LIST;\r
+\r
+LIST_ENTRY mSmmMemoryMap = INITIALIZE_LIST_HEAD_VARIABLE (mSmmMemoryMap);\r
+\r
+/**\r
+ Internal Function. Allocate n pages from given free page node.\r
+\r
+ @param Pages The free page node.\r
+ @param NumberOfPages Number of pages to be allocated.\r
+ @param MaxAddress Request to allocate memory below this address.\r
+\r
+ @return Memory address of allocated pages.\r
+\r
+**/\r
+UINTN\r
+InternalAllocPagesOnOneNode (\r
+ IN OUT FREE_PAGE_LIST *Pages,\r
+ IN UINTN NumberOfPages,\r
+ IN UINTN MaxAddress\r
+ )\r
+{\r
+ UINTN Top;\r
+ UINTN Bottom;\r
+ FREE_PAGE_LIST *Node;\r
+\r
+ Top = TRUNCATE_TO_PAGES (MaxAddress + 1 - (UINTN)Pages);\r
+ if (Top > Pages->NumberOfPages) {\r
+ Top = Pages->NumberOfPages;\r
+ }\r
+ Bottom = Top - NumberOfPages;\r
+\r
+ if (Top < Pages->NumberOfPages) {\r
+ Node = (FREE_PAGE_LIST*)((UINTN)Pages + EFI_PAGES_TO_SIZE (Top));\r
+ Node->NumberOfPages = Pages->NumberOfPages - Top;\r
+ InsertHeadList (&Pages->Link, &Node->Link);\r
+ }\r
+\r
+ if (Bottom > 0) {\r
+ Pages->NumberOfPages = Bottom;\r
+ } else {\r
+ RemoveEntryList (&Pages->Link);\r
+ }\r
+\r
+ return (UINTN)Pages + EFI_PAGES_TO_SIZE (Bottom);\r
+}\r
+\r
+/**\r
+ Internal Function. Allocate n pages from free page list below MaxAddress.\r
+\r
+ @param FreePageList The free page node.\r
+ @param NumberOfPages Number of pages to be allocated.\r
+ @param MaxAddress Request to allocate memory below this address.\r
+\r
+ @return Memory address of allocated pages.\r
+\r
+**/\r
+UINTN\r
+InternalAllocMaxAddress (\r
+ IN OUT LIST_ENTRY *FreePageList,\r
+ IN UINTN NumberOfPages,\r
+ IN UINTN MaxAddress\r
+ )\r
+{\r
+ LIST_ENTRY *Node;\r
+ FREE_PAGE_LIST *Pages;\r
+\r
+ for (Node = FreePageList->BackLink; Node != FreePageList; Node = Node->BackLink) {\r
+ Pages = BASE_CR (Node, FREE_PAGE_LIST, Link);\r
+ if (Pages->NumberOfPages >= NumberOfPages &&\r
+ (UINTN)Pages + EFI_PAGES_TO_SIZE (NumberOfPages) - 1 <= MaxAddress) {\r
+ return InternalAllocPagesOnOneNode (Pages, NumberOfPages, MaxAddress);\r
+ }\r
+ }\r
+ return (UINTN)(-1);\r
+}\r
+\r
+/**\r
+ Internal Function. Allocate n pages from free page list at given address.\r
+\r
+ @param FreePageList The free page node.\r
+ @param NumberOfPages Number of pages to be allocated.\r
+ @param MaxAddress Request to allocate memory below this address.\r
+\r
+ @return Memory address of allocated pages.\r
+\r
+**/\r
+UINTN\r
+InternalAllocAddress (\r
+ IN OUT LIST_ENTRY *FreePageList,\r
+ IN UINTN NumberOfPages,\r
+ IN UINTN Address\r
+ )\r
+{\r
+ UINTN EndAddress;\r
+ LIST_ENTRY *Node;\r
+ FREE_PAGE_LIST *Pages;\r
+\r
+ if ((Address & EFI_PAGE_MASK) != 0) {\r
+ return ~Address;\r
+ }\r
+\r
+ EndAddress = Address + EFI_PAGES_TO_SIZE (NumberOfPages);\r
+ for (Node = FreePageList->BackLink; Node!= FreePageList; Node = Node->BackLink) {\r
+ Pages = BASE_CR (Node, FREE_PAGE_LIST, Link);\r
+ if ((UINTN)Pages <= Address) {\r
+ if ((UINTN)Pages + EFI_PAGES_TO_SIZE (Pages->NumberOfPages) < EndAddress) {\r
+ break;\r
+ }\r
+ return InternalAllocPagesOnOneNode (Pages, NumberOfPages, EndAddress);\r
+ }\r
+ }\r
+ return ~Address;\r
+}\r
+\r
+/**\r
+ Allocates pages from the memory map.\r
+\r
+ @param Type The type of allocation to perform.\r
+ @param MemoryType The type of memory to turn the allocated pages\r
+ into.\r
+ @param NumberOfPages The number of pages to allocate.\r
+ @param Memory A pointer to receive the base allocated memory\r
+ address.\r
+\r
+ @retval EFI_INVALID_PARAMETER Parameters violate checking rules defined in spec.\r
+ @retval EFI_NOT_FOUND Could not allocate pages match the requirement.\r
+ @retval EFI_OUT_OF_RESOURCES No enough pages to allocate.\r
+ @retval EFI_SUCCESS Pages successfully allocated.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SmmAllocatePages (\r
+ IN EFI_ALLOCATE_TYPE Type,\r
+ IN EFI_MEMORY_TYPE MemoryType,\r
+ IN UINTN NumberOfPages,\r
+ OUT EFI_PHYSICAL_ADDRESS *Memory\r
+ )\r
+{\r
+ UINTN RequestedAddress;\r
+\r
+ if (MemoryType != EfiRuntimeServicesCode &&\r
+ MemoryType != EfiRuntimeServicesData) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ if (NumberOfPages > TRUNCATE_TO_PAGES ((UINTN)-1) + 1) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ //\r
+ // We don't track memory type in SMM\r
+ //\r
+ RequestedAddress = (UINTN)*Memory;\r
+ switch (Type) {\r
+ case AllocateAnyPages:\r
+ RequestedAddress = (UINTN)(-1);\r
+ case AllocateMaxAddress:\r
+ *Memory = InternalAllocMaxAddress (\r
+ &mSmmMemoryMap,\r
+ NumberOfPages,\r
+ RequestedAddress\r
+ );\r
+ if (*Memory == (UINTN)-1) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ } \r
+ break;\r
+ case AllocateAddress:\r
+ *Memory = InternalAllocAddress (\r
+ &mSmmMemoryMap,\r
+ NumberOfPages,\r
+ RequestedAddress\r
+ );\r
+ if (*Memory != RequestedAddress) {\r
+ return EFI_NOT_FOUND;\r
+ }\r
+ break;\r
+ default:\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Internal Function. Merge two adjacent nodes.\r
+\r
+ @param First The first of two nodes to merge.\r
+\r
+ @return Pointer to node after merge (if success) or pointer to next node (if fail).\r
+\r
+**/\r
+FREE_PAGE_LIST *\r
+InternalMergeNodes (\r
+ IN FREE_PAGE_LIST *First\r
+ )\r
+{\r
+ FREE_PAGE_LIST *Next;\r
+\r
+ Next = BASE_CR (First->Link.ForwardLink, FREE_PAGE_LIST, Link);\r
+ ASSERT (\r
+ TRUNCATE_TO_PAGES ((UINTN)Next - (UINTN)First) >= First->NumberOfPages);\r
+\r
+ if (TRUNCATE_TO_PAGES ((UINTN)Next - (UINTN)First) == First->NumberOfPages) {\r
+ First->NumberOfPages += Next->NumberOfPages;\r
+ RemoveEntryList (&Next->Link);\r
+ Next = First;\r
+ }\r
+ return Next;\r
+}\r
+\r
+/**\r
+ Frees previous allocated pages.\r
+\r
+ @param Memory Base address of memory being freed.\r
+ @param NumberOfPages The number of pages to free.\r
+\r
+ @retval EFI_NOT_FOUND Could not find the entry that covers the range.\r
+ @retval EFI_INVALID_PARAMETER Address not aligned.\r
+ @return EFI_SUCCESS Pages successfully freed.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SmmFreePages (\r
+ IN EFI_PHYSICAL_ADDRESS Memory,\r
+ IN UINTN NumberOfPages\r
+ )\r
+{\r
+ LIST_ENTRY *Node;\r
+ FREE_PAGE_LIST *Pages;\r
+\r
+ if ((Memory & EFI_PAGE_MASK) != 0) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ Pages = NULL;\r
+ Node = mSmmMemoryMap.ForwardLink;\r
+ while (Node != &mSmmMemoryMap) {\r
+ Pages = BASE_CR (Node, FREE_PAGE_LIST, Link);\r
+ if (Memory < (UINTN)Pages) {\r
+ break;\r
+ }\r
+ Node = Node->ForwardLink;\r
+ }\r
+\r
+ if (Node != &mSmmMemoryMap &&\r
+ Memory + EFI_PAGES_TO_SIZE (NumberOfPages) > (UINTN)Pages) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ if (Node->BackLink != &mSmmMemoryMap) {\r
+ Pages = BASE_CR (Node->BackLink, FREE_PAGE_LIST, Link);\r
+ if ((UINTN)Pages + EFI_PAGES_TO_SIZE (Pages->NumberOfPages) > Memory) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+ }\r
+\r
+ Pages = (FREE_PAGE_LIST*)(UINTN)Memory;\r
+ Pages->NumberOfPages = NumberOfPages;\r
+ InsertTailList (Node, &Pages->Link);\r
+\r
+ if (Pages->Link.BackLink != &mSmmMemoryMap) {\r
+ Pages = InternalMergeNodes (\r
+ BASE_CR (Pages->Link.BackLink, FREE_PAGE_LIST, Link)\r
+ );\r
+ }\r
+\r
+ if (Node != &mSmmMemoryMap) {\r
+ InternalMergeNodes (Pages);\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Add free SMRAM region for use by memory service.\r
+\r
+ @param MemBase Base address of memory region.\r
+ @param MemLength Length of the memory region.\r
+ @param Type Memory type.\r
+ @param Attributes Memory region state.\r
+\r
+**/\r
+VOID\r
+SmmAddMemoryRegion (\r
+ IN EFI_PHYSICAL_ADDRESS MemBase,\r
+ IN UINT64 MemLength,\r
+ IN EFI_MEMORY_TYPE Type,\r
+ IN UINT64 Attributes\r
+ )\r
+{\r
+ UINTN AlignedMemBase;\r
+\r
+ AlignedMemBase = (UINTN)(MemBase + EFI_PAGE_MASK) & ~EFI_PAGE_MASK;\r
+ MemLength -= AlignedMemBase - MemBase;\r
+ SmmFreePages (AlignedMemBase, TRUNCATE_TO_PAGES ((UINTN)MemLength));\r
+}\r
--- /dev/null
+/** @file\r
+ SMM Core Main Entry Point\r
+\r
+ Copyright (c) 2009 - 2010, Intel Corporation. All rights reserved.<BR>\r
+ This program and the accompanying materials are licensed and made available \r
+ under the terms and conditions of the BSD License which accompanies this \r
+ distribution. The full text of the license may be found at \r
+ http://opensource.org/licenses/bsd-license.php \r
+\r
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, \r
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. \r
+\r
+**/\r
+\r
+#include "PiSmmCore.h"\r
+\r
+//\r
+// Physical pointer to private structure shared between SMM IPL and the SMM Core\r
+//\r
+SMM_CORE_PRIVATE_DATA *gSmmCorePrivate;\r
+\r
+//\r
+// SMM Core global variable for SMM System Table. Only accessed as a physical structure in SMRAM.\r
+//\r
+EFI_SMM_SYSTEM_TABLE2 gSmmCoreSmst = {\r
+ {\r
+ SMM_SMST_SIGNATURE,\r
+ EFI_SMM_SYSTEM_TABLE2_REVISION,\r
+ sizeof (gSmmCoreSmst.Hdr)\r
+ },\r
+ NULL, // SmmFirmwareVendor\r
+ 0, // SmmFirmwareRevision\r
+ SmmInstallConfigurationTable,\r
+ {\r
+ {\r
+ (EFI_SMM_CPU_IO2) SmmEfiNotAvailableYetArg5, // SmmMemRead\r
+ (EFI_SMM_CPU_IO2) SmmEfiNotAvailableYetArg5 // SmmMemWrite\r
+ },\r
+ {\r
+ (EFI_SMM_CPU_IO2) SmmEfiNotAvailableYetArg5, // SmmIoRead\r
+ (EFI_SMM_CPU_IO2) SmmEfiNotAvailableYetArg5 // SmmIoWrite\r
+ }\r
+ },\r
+ SmmAllocatePool,\r
+ SmmFreePool,\r
+ SmmAllocatePages,\r
+ SmmFreePages,\r
+ NULL, // SmmStartupThisAp\r
+ 0, // CurrentlyExecutingCpu\r
+ 0, // NumberOfCpus\r
+ NULL, // CpuSaveStateSize\r
+ NULL, // CpuSaveState\r
+ 0, // NumberOfTableEntries\r
+ NULL, // SmmConfigurationTable\r
+ SmmInstallProtocolInterface,\r
+ SmmUninstallProtocolInterface,\r
+ SmmHandleProtocol,\r
+ SmmRegisterProtocolNotify,\r
+ SmmLocateHandle,\r
+ SmmLocateProtocol,\r
+ SmiManage,\r
+ SmiHandlerRegister,\r
+ SmiHandlerUnRegister\r
+};\r
+\r
+//\r
+// Flag to determine if the platform has performed a legacy boot.\r
+// If this flag is TRUE, then the runtime code and runtime data associated with the \r
+// SMM IPL are converted to free memory, so the SMM COre must guarantee that is\r
+// does not touch of the code/data associated with the SMM IPL if this flag is TRUE.\r
+//\r
+BOOLEAN mInLegacyBoot = FALSE;\r
+\r
+//\r
+// Table of SMI Handlers that are registered by the SMM Core when it is initialized\r
+//\r
+SMM_CORE_SMI_HANDLERS mSmmCoreSmiHandlers[] = {\r
+ { SmmDriverDispatchHandler, &gEfiEventDxeDispatchGuid, NULL, TRUE },\r
+ { SmmReadyToLockHandler, &gEfiDxeSmmReadyToLockProtocolGuid, NULL, FALSE }, \r
+ { SmmLegacyBootHandler, &gEfiEventLegacyBootGuid, NULL, FALSE },\r
+ { NULL, NULL, NULL, FALSE }\r
+};\r
+\r
+/**\r
+ Place holder function until all the SMM System Table Service are available.\r
+\r
+ Note: This function is only used by SMRAM invocation. It is never used by DXE invocation.\r
+\r
+ @param Arg1 Undefined\r
+ @param Arg2 Undefined\r
+ @param Arg3 Undefined\r
+ @param Arg4 Undefined\r
+ @param Arg5 Undefined\r
+\r
+ @return EFI_NOT_AVAILABLE_YET\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SmmEfiNotAvailableYetArg5 (\r
+ UINTN Arg1,\r
+ UINTN Arg2,\r
+ UINTN Arg3,\r
+ UINTN Arg4,\r
+ UINTN Arg5\r
+ )\r
+{\r
+ //\r
+ // This function should never be executed. If it does, then the architectural protocols\r
+ // have not been designed correctly.\r
+ //\r
+ return EFI_NOT_AVAILABLE_YET;\r
+}\r
+\r
+/**\r
+ Software SMI handler that is called when a Legacy Boot event is signalled. The SMM\r
+ Core uses this signal to know that a Legacy Boot has been performed and that \r
+ gSmmCorePrivate that is shared between the UEFI and SMM execution environments can\r
+ not be accessed from SMM anymore since that structure is considered free memory by\r
+ a legacy OS.\r
+\r
+ @param DispatchHandle The unique handle assigned to this handler by SmiHandlerRegister().\r
+ @param Context Points to an optional handler context which was specified when the handler was registered.\r
+ @param CommBuffer A pointer to a collection of data in memory that will\r
+ be conveyed from a non-SMM environment into an SMM environment.\r
+ @param CommBufferSize The size of the CommBuffer.\r
+\r
+ @return Status Code\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SmmLegacyBootHandler (\r
+ IN EFI_HANDLE DispatchHandle,\r
+ IN CONST VOID *Context, OPTIONAL\r
+ IN OUT VOID *CommBuffer, OPTIONAL\r
+ IN OUT UINTN *CommBufferSize OPTIONAL\r
+ )\r
+{\r
+ mInLegacyBoot = TRUE;\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Software SMI handler that is called when the DxeSmmReadyToLock protocol is added\r
+ or if gEfiEventReadyToBootGuid is signalled. This function unregisters the \r
+ Software SMIs that are nor required after SMRAM is locked and installs the \r
+ SMM Ready To Lock Protocol so SMM Drivers are informed that SMRAM is about \r
+ to be locked. It also verifies the the SMM CPU I/O 2 Protocol has been installed\r
+ and NULLs gBS and gST because they can not longer be used after SMRAM is locked.\r
+\r
+ @param DispatchHandle The unique handle assigned to this handler by SmiHandlerRegister().\r
+ @param Context Points to an optional handler context which was specified when the handler was registered.\r
+ @param CommBuffer A pointer to a collection of data in memory that will\r
+ be conveyed from a non-SMM environment into an SMM environment.\r
+ @param CommBufferSize The size of the CommBuffer.\r
+\r
+ @return Status Code\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SmmReadyToLockHandler (\r
+ IN EFI_HANDLE DispatchHandle,\r
+ IN CONST VOID *Context, OPTIONAL\r
+ IN OUT VOID *CommBuffer, OPTIONAL\r
+ IN OUT UINTN *CommBufferSize OPTIONAL\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINTN Index;\r
+ EFI_HANDLE SmmHandle;\r
+ VOID *Interface;\r
+\r
+ //\r
+ // Unregister SMI Handlers that are no required after the SMM driver dispatch is stopped\r
+ //\r
+ for (Index = 0; mSmmCoreSmiHandlers[Index].HandlerType != NULL; Index++) {\r
+ if (mSmmCoreSmiHandlers[Index].UnRegister) {\r
+ SmiHandlerUnRegister (mSmmCoreSmiHandlers[Index].DispatchHandle);\r
+ }\r
+ }\r
+\r
+ //\r
+ // Install SMM Ready to lock protocol\r
+ //\r
+ SmmHandle = NULL;\r
+ Status = SmmInstallProtocolInterface (\r
+ &SmmHandle,\r
+ &gEfiSmmReadyToLockProtocolGuid,\r
+ EFI_NATIVE_INTERFACE,\r
+ NULL\r
+ );\r
+\r
+ //\r
+ // Make sure SMM CPU I/O 2 Procol has been installed into the handle database\r
+ //\r
+ Status = SmmLocateProtocol (&gEfiSmmCpuIo2ProtocolGuid, NULL, &Interface);\r
+\r
+ //\r
+ // Print a message on a debug build if the SMM CPU I/O 2 Protocol is not installed\r
+ //\r
+ DEBUG_CODE_BEGIN ();\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG ((DEBUG_ERROR, "\nSMM: SmmCpuIo Arch Protocol not present!!\n"));\r
+ }\r
+ DEBUG_CODE_END ();\r
+\r
+ //\r
+ // Assert if the CPU I/O 2 Protocol is not installed\r
+ //\r
+ ASSERT_EFI_ERROR (Status);\r
+\r
+ //\r
+ // Display any drivers that were not dispatched because dependency expression\r
+ // evaluated to false if this is a debug build\r
+ //\r
+ DEBUG_CODE_BEGIN ();\r
+ SmmDisplayDiscoveredNotDispatched ();\r
+ DEBUG_CODE_END ();\r
+\r
+ //\r
+ // Not allowed to use gST or gBS after lock\r
+ //\r
+ gST = NULL;\r
+ gBS = NULL;\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ The main entry point to SMM Foundation.\r
+\r
+ Note: This function is only used by SMRAM invocation. It is never used by DXE invocation.\r
+\r
+ @param SmmEntryContext Processor information and functionality\r
+ needed by SMM Foundation.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+SmmEntryPoint (\r
+ IN CONST EFI_SMM_ENTRY_CONTEXT *SmmEntryContext\r
+)\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_SMM_COMMUNICATE_HEADER *CommunicateHeader;\r
+ BOOLEAN OldInSmm;\r
+\r
+ //\r
+ // Update SMST using the context\r
+ //\r
+ CopyMem (&gSmmCoreSmst.SmmStartupThisAp, SmmEntryContext, sizeof (EFI_SMM_ENTRY_CONTEXT));\r
+\r
+ //\r
+ // If a legacy boot has occured, then make sure gSmmCorePrivate is not accessed\r
+ //\r
+ if (mInLegacyBoot) {\r
+ //\r
+ // Asynchronous SMI\r
+ //\r
+ SmiManage (NULL, NULL, NULL, NULL);\r
+ return;\r
+ }\r
+\r
+ //\r
+ // Save current InSmm state and set InSmm state to TRUE, it will be used by SmmBase2 protocol\r
+ //\r
+ OldInSmm = gSmmCorePrivate->InSmm;\r
+ gSmmCorePrivate->InSmm = TRUE;\r
+\r
+ //\r
+ // Check to see if this is a Synchronous SMI sent through the SMM Communication \r
+ // Protocol or an Asynchronous SMI\r
+ //\r
+ if (gSmmCorePrivate->CommunicationBuffer != NULL) {\r
+ //\r
+ // Synchronous SMI for SMM Core or request from Communicate protocol\r
+ //\r
+ CommunicateHeader = (EFI_SMM_COMMUNICATE_HEADER *)gSmmCorePrivate->CommunicationBuffer;\r
+ *gSmmCorePrivate->BufferSize -= OFFSET_OF (EFI_SMM_COMMUNICATE_HEADER, Data);\r
+ Status = SmiManage (\r
+ &CommunicateHeader->HeaderGuid, \r
+ NULL, \r
+ CommunicateHeader->Data, \r
+ gSmmCorePrivate->BufferSize\r
+ );\r
+\r
+ //\r
+ // Update CommunicationBuffer, BufferSize and ReturnStatus\r
+ // Communicate service finished, reset the pointer to CommBuffer to NULL\r
+ //\r
+ *gSmmCorePrivate->BufferSize += OFFSET_OF (EFI_SMM_COMMUNICATE_HEADER, Data);\r
+ gSmmCorePrivate->CommunicationBuffer = NULL;\r
+ gSmmCorePrivate->ReturnStatus = (Status == EFI_WARN_INTERRUPT_SOURCE_QUIESCED) ? EFI_SUCCESS : EFI_NOT_FOUND;\r
+ } else {\r
+ //\r
+ // Asynchronous SMI\r
+ //\r
+ SmiManage (NULL, NULL, NULL, NULL);\r
+ }\r
+\r
+ //\r
+ // Restore original InSmm state as we are going to leave SMM\r
+ //\r
+ gSmmCorePrivate->InSmm = OldInSmm;\r
+}\r
+\r
+/**\r
+ The Entry Point for SMM Core\r
+\r
+ Install DXE Protocols and reload SMM Core into SMRAM and register SMM Core \r
+ EntryPoint on the SMI vector.\r
+\r
+ Note: This function is called for both DXE invocation and SMRAM invocation.\r
+\r
+ @param ImageHandle The firmware allocated handle for the EFI image.\r
+ @param SystemTable A pointer to the EFI System Table.\r
+\r
+ @retval EFI_SUCCESS The entry point is executed successfully.\r
+ @retval Other Some error occurred when executing this entry point.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SmmMain (\r
+ IN EFI_HANDLE ImageHandle,\r
+ IN EFI_SYSTEM_TABLE *SystemTable\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINTN Index;\r
+\r
+ //\r
+ // Get SMM Core Private context passed in from SMM IPL in ImageHandle.\r
+ //\r
+ gSmmCorePrivate = (SMM_CORE_PRIVATE_DATA *)ImageHandle;\r
+\r
+ //\r
+ // Fill in SMRAM physical address for the SMM Services Table and the SMM Entry Point.\r
+ //\r
+ gSmmCorePrivate->Smst = &gSmmCoreSmst;\r
+ gSmmCorePrivate->SmmEntryPoint = SmmEntryPoint;\r
+ \r
+ //\r
+ // Initialize memory service using free SMRAM\r
+ //\r
+ SmmInitializeMemoryServices (gSmmCorePrivate->SmramRangeCount, gSmmCorePrivate->SmramRanges);\r
+\r
+ //\r
+ // Register all SMI Handlers required by the SMM Core\r
+ //\r
+ for (Index = 0; mSmmCoreSmiHandlers[Index].HandlerType != NULL; Index++) {\r
+ Status = SmiHandlerRegister (\r
+ mSmmCoreSmiHandlers[Index].Handler,\r
+ mSmmCoreSmiHandlers[Index].HandlerType,\r
+ &mSmmCoreSmiHandlers[Index].DispatchHandle\r
+ );\r
+ ASSERT_EFI_ERROR (Status);\r
+ }\r
+ \r
+ return EFI_SUCCESS;\r
+}\r
--- /dev/null
+/** @file\r
+ The internal header file includes the common header files, defines\r
+ internal structure and functions used by SmmCore module.\r
+\r
+ Copyright (c) 2009 - 2010, Intel Corporation. All rights reserved.<BR>\r
+ This program and the accompanying materials are licensed and made available \r
+ under the terms and conditions of the BSD License which accompanies this \r
+ distribution. The full text of the license may be found at \r
+ http://opensource.org/licenses/bsd-license.php \r
+\r
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, \r
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. \r
+\r
+**/\r
+\r
+#ifndef _SMM_CORE_H_\r
+#define _SMM_CORE_H_\r
+\r
+#include <PiSmm.h>\r
+\r
+#include <Protocol/DxeSmmReadyToLock.h>\r
+#include <Protocol/SmmReadyToLock.h>\r
+#include <Protocol/CpuIo2.h>\r
+#include <Protocol/SmmCommunication.h>\r
+#include <Protocol/SmmAccess2.h>\r
+#include <Protocol/FirmwareVolume2.h> \r
+#include <Protocol/LoadedImage.h> \r
+#include <Protocol/DevicePath.h> \r
+#include <Protocol/Security.h> \r
+\r
+#include <Guid/Apriori.h>\r
+#include <Guid/EventGroup.h>\r
+#include <Guid/EventLegacyBios.h>\r
+\r
+#include <Library/BaseLib.h>\r
+#include <Library/BaseMemoryLib.h>\r
+#include <Library/PeCoffLib.h>\r
+#include <Library/CacheMaintenanceLib.h>\r
+#include <Library/DebugLib.h>\r
+#include <Library/ReportStatusCodeLib.h>\r
+#include <Library/MemoryAllocationLib.h>\r
+#include <Library/DevicePathLib.h> \r
+#include <Library/UefiLib.h> \r
+#include <Library/UefiBootServicesTableLib.h> \r
+\r
+#include "PiSmmCorePrivateData.h"\r
+\r
+//\r
+// Used to build a table of SMI Handlers that the SMM Core registers\r
+//\r
+typedef struct {\r
+ EFI_SMM_HANDLER_ENTRY_POINT2 Handler;\r
+ EFI_GUID *HandlerType;\r
+ EFI_HANDLE DispatchHandle;\r
+ BOOLEAN UnRegister;\r
+} SMM_CORE_SMI_HANDLERS;\r
+\r
+//\r
+// Structure for recording the state of an SMM Driver\r
+//\r
+#define EFI_SMM_DRIVER_ENTRY_SIGNATURE SIGNATURE_32('s', 'd','r','v')\r
+\r
+typedef struct {\r
+ UINTN Signature;\r
+ LIST_ENTRY Link; // mDriverList\r
+\r
+ LIST_ENTRY ScheduledLink; // mScheduledQueue\r
+\r
+ EFI_HANDLE FvHandle;\r
+ EFI_GUID FileName;\r
+ EFI_DEVICE_PATH_PROTOCOL *FvFileDevicePath;\r
+ EFI_FIRMWARE_VOLUME2_PROTOCOL *Fv;\r
+\r
+ VOID *Depex;\r
+ UINTN DepexSize;\r
+\r
+ BOOLEAN Before;\r
+ BOOLEAN After;\r
+ EFI_GUID BeforeAfterGuid;\r
+\r
+ BOOLEAN Dependent;\r
+ BOOLEAN Unrequested;\r
+ BOOLEAN Scheduled;\r
+ BOOLEAN Untrusted;\r
+ BOOLEAN Initialized;\r
+ BOOLEAN DepexProtocolError;\r
+\r
+ EFI_HANDLE ImageHandle;\r
+ EFI_LOADED_IMAGE_PROTOCOL *LoadedImage;\r
+ //\r
+ // Image EntryPoint in SMRAM\r
+ //\r
+ PHYSICAL_ADDRESS ImageEntryPoint;\r
+ //\r
+ // Image Buffer in SMRAM \r
+ //\r
+ PHYSICAL_ADDRESS ImageBuffer;\r
+ //\r
+ // Image Page Number\r
+ //\r
+ UINTN NumberOfPage;\r
+} EFI_SMM_DRIVER_ENTRY;\r
+\r
+#define EFI_HANDLE_SIGNATURE SIGNATURE_32('h','n','d','l')\r
+\r
+///\r
+/// IHANDLE - contains a list of protocol handles\r
+///\r
+typedef struct {\r
+ UINTN Signature;\r
+ /// All handles list of IHANDLE\r
+ LIST_ENTRY AllHandles;\r
+ /// List of PROTOCOL_INTERFACE's for this handle\r
+ LIST_ENTRY Protocols;\r
+ UINTN LocateRequest;\r
+} IHANDLE;\r
+\r
+#define ASSERT_IS_HANDLE(a) ASSERT((a)->Signature == EFI_HANDLE_SIGNATURE)\r
+\r
+#define PROTOCOL_ENTRY_SIGNATURE SIGNATURE_32('p','r','t','e')\r
+\r
+///\r
+/// PROTOCOL_ENTRY - each different protocol has 1 entry in the protocol\r
+/// database. Each handler that supports this protocol is listed, along\r
+/// with a list of registered notifies.\r
+///\r
+typedef struct {\r
+ UINTN Signature;\r
+ /// Link Entry inserted to mProtocolDatabase\r
+ LIST_ENTRY AllEntries;\r
+ /// ID of the protocol\r
+ EFI_GUID ProtocolID;\r
+ /// All protocol interfaces\r
+ LIST_ENTRY Protocols;\r
+ /// Registerd notification handlers\r
+ LIST_ENTRY Notify;\r
+} PROTOCOL_ENTRY;\r
+\r
+#define PROTOCOL_INTERFACE_SIGNATURE SIGNATURE_32('p','i','f','c')\r
+\r
+///\r
+/// PROTOCOL_INTERFACE - each protocol installed on a handle is tracked\r
+/// with a protocol interface structure\r
+///\r
+typedef struct {\r
+ UINTN Signature;\r
+ /// Link on IHANDLE.Protocols\r
+ LIST_ENTRY Link;\r
+ /// Back pointer\r
+ IHANDLE *Handle;\r
+ /// Link on PROTOCOL_ENTRY.Protocols\r
+ LIST_ENTRY ByProtocol;\r
+ /// The protocol ID\r
+ PROTOCOL_ENTRY *Protocol;\r
+ /// The interface value\r
+ VOID *Interface;\r
+} PROTOCOL_INTERFACE;\r
+\r
+#define PROTOCOL_NOTIFY_SIGNATURE SIGNATURE_32('p','r','t','n')\r
+\r
+///\r
+/// PROTOCOL_NOTIFY - used for each register notification for a protocol\r
+///\r
+typedef struct {\r
+ UINTN Signature;\r
+ PROTOCOL_ENTRY *Protocol;\r
+ /// All notifications for this protocol\r
+ LIST_ENTRY Link;\r
+ /// Notification function\r
+ EFI_SMM_NOTIFY_FN Function;\r
+ /// Last position notified\r
+ LIST_ENTRY *Position;\r
+} PROTOCOL_NOTIFY;\r
+\r
+//\r
+// SMM Core Global Variables\r
+//\r
+extern SMM_CORE_PRIVATE_DATA *gSmmCorePrivate;\r
+extern EFI_SMM_SYSTEM_TABLE2 gSmmCoreSmst;\r
+extern LIST_ENTRY gHandleList;\r
+\r
+/**\r
+ Called to initialize the memory service.\r
+\r
+ @param SmramRangeCount Number of SMRAM Regions\r
+ @param SmramRanges Pointer to SMRAM Descriptors\r
+\r
+**/\r
+VOID\r
+SmmInitializeMemoryServices (\r
+ IN UINTN SmramRangeCount,\r
+ IN EFI_SMRAM_DESCRIPTOR *SmramRanges\r
+ );\r
+\r
+/**\r
+ The SmmInstallConfigurationTable() function is used to maintain the list\r
+ of configuration tables that are stored in the System Management System\r
+ Table. The list is stored as an array of (GUID, Pointer) pairs. The list\r
+ must be allocated from pool memory with PoolType set to EfiRuntimeServicesData.\r
+\r
+ @param SystemTable A pointer to the SMM System Table (SMST).\r
+ @param Guid A pointer to the GUID for the entry to add, update, or remove.\r
+ @param Table A pointer to the buffer of the table to add.\r
+ @param TableSize The size of the table to install.\r
+\r
+ @retval EFI_SUCCESS The (Guid, Table) pair was added, updated, or removed.\r
+ @retval EFI_INVALID_PARAMETER Guid is not valid.\r
+ @retval EFI_NOT_FOUND An attempt was made to delete a non-existent entry.\r
+ @retval EFI_OUT_OF_RESOURCES There is not enough memory available to complete the operation.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SmmInstallConfigurationTable (\r
+ IN CONST EFI_SMM_SYSTEM_TABLE2 *SystemTable,\r
+ IN CONST EFI_GUID *Guid,\r
+ IN VOID *Table,\r
+ IN UINTN TableSize\r
+ );\r
+\r
+/**\r
+ Wrapper function to SmmInstallProtocolInterfaceNotify. This is the public API which\r
+ Calls the private one which contains a BOOLEAN parameter for notifications\r
+\r
+ @param UserHandle The handle to install the protocol handler on,\r
+ or NULL if a new handle is to be allocated\r
+ @param Protocol The protocol to add to the handle\r
+ @param InterfaceType Indicates whether Interface is supplied in\r
+ native form.\r
+ @param Interface The interface for the protocol being added\r
+\r
+ @return Status code\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SmmInstallProtocolInterface (\r
+ IN OUT EFI_HANDLE *UserHandle,\r
+ IN EFI_GUID *Protocol,\r
+ IN EFI_INTERFACE_TYPE InterfaceType,\r
+ IN VOID *Interface\r
+ );\r
+\r
+/**\r
+ Allocates pages from the memory map.\r
+\r
+ @param Type The type of allocation to perform\r
+ @param MemoryType The type of memory to turn the allocated pages\r
+ into\r
+ @param NumberOfPages The number of pages to allocate\r
+ @param Memory A pointer to receive the base allocated memory\r
+ address\r
+\r
+ @retval EFI_INVALID_PARAMETER Parameters violate checking rules defined in spec.\r
+ @retval EFI_NOT_FOUND Could not allocate pages match the requirement.\r
+ @retval EFI_OUT_OF_RESOURCES No enough pages to allocate.\r
+ @retval EFI_SUCCESS Pages successfully allocated.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SmmAllocatePages (\r
+ IN EFI_ALLOCATE_TYPE Type,\r
+ IN EFI_MEMORY_TYPE MemoryType,\r
+ IN UINTN NumberOfPages,\r
+ OUT EFI_PHYSICAL_ADDRESS *Memory\r
+ );\r
+\r
+/**\r
+ Frees previous allocated pages.\r
+\r
+ @param Memory Base address of memory being freed\r
+ @param NumberOfPages The number of pages to free\r
+\r
+ @retval EFI_NOT_FOUND Could not find the entry that covers the range\r
+ @retval EFI_INVALID_PARAMETER Address not aligned\r
+ @return EFI_SUCCESS Pages successfully freed.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SmmFreePages (\r
+ IN EFI_PHYSICAL_ADDRESS Memory,\r
+ IN UINTN NumberOfPages\r
+ );\r
+\r
+/**\r
+ Allocate pool of a particular type.\r
+\r
+ @param PoolType Type of pool to allocate\r
+ @param Size The amount of pool to allocate\r
+ @param Buffer The address to return a pointer to the allocated\r
+ pool\r
+\r
+ @retval EFI_INVALID_PARAMETER PoolType not valid\r
+ @retval EFI_OUT_OF_RESOURCES Size exceeds max pool size or allocation failed.\r
+ @retval EFI_SUCCESS Pool successfully allocated.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SmmAllocatePool (\r
+ IN EFI_MEMORY_TYPE PoolType,\r
+ IN UINTN Size,\r
+ OUT VOID **Buffer\r
+ );\r
+\r
+/**\r
+ Frees pool.\r
+\r
+ @param Buffer The allocated pool entry to free\r
+\r
+ @retval EFI_INVALID_PARAMETER Buffer is not a valid value.\r
+ @retval EFI_SUCCESS Pool successfully freed.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SmmFreePool (\r
+ IN VOID *Buffer\r
+ );\r
+\r
+/**\r
+ Installs a protocol interface into the boot services environment.\r
+\r
+ @param UserHandle The handle to install the protocol handler on,\r
+ or NULL if a new handle is to be allocated\r
+ @param Protocol The protocol to add to the handle\r
+ @param InterfaceType Indicates whether Interface is supplied in\r
+ native form.\r
+ @param Interface The interface for the protocol being added\r
+ @param Notify indicates whether notify the notification list\r
+ for this protocol\r
+\r
+ @retval EFI_INVALID_PARAMETER Invalid parameter\r
+ @retval EFI_OUT_OF_RESOURCES No enough buffer to allocate\r
+ @retval EFI_SUCCESS Protocol interface successfully installed\r
+\r
+**/\r
+EFI_STATUS\r
+SmmInstallProtocolInterfaceNotify (\r
+ IN OUT EFI_HANDLE *UserHandle,\r
+ IN EFI_GUID *Protocol,\r
+ IN EFI_INTERFACE_TYPE InterfaceType,\r
+ IN VOID *Interface,\r
+ IN BOOLEAN Notify\r
+ );\r
+\r
+/**\r
+ Uninstalls all instances of a protocol:interfacer from a handle.\r
+ If the last protocol interface is remove from the handle, the\r
+ handle is freed.\r
+\r
+ @param UserHandle The handle to remove the protocol handler from\r
+ @param Protocol The protocol, of protocol:interface, to remove\r
+ @param Interface The interface, of protocol:interface, to remove\r
+\r
+ @retval EFI_INVALID_PARAMETER Protocol is NULL.\r
+ @retval EFI_SUCCESS Protocol interface successfully uninstalled.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SmmUninstallProtocolInterface (\r
+ IN EFI_HANDLE UserHandle,\r
+ IN EFI_GUID *Protocol,\r
+ IN VOID *Interface\r
+ );\r
+\r
+/**\r
+ Queries a handle to determine if it supports a specified protocol.\r
+\r
+ @param UserHandle The handle being queried.\r
+ @param Protocol The published unique identifier of the protocol.\r
+ @param Interface Supplies the address where a pointer to the\r
+ corresponding Protocol Interface is returned.\r
+\r
+ @return The requested protocol interface for the handle\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SmmHandleProtocol (\r
+ IN EFI_HANDLE UserHandle,\r
+ IN EFI_GUID *Protocol,\r
+ OUT VOID **Interface\r
+ );\r
+\r
+/**\r
+ Add a new protocol notification record for the request protocol.\r
+\r
+ @param Protocol The requested protocol to add the notify\r
+ registration\r
+ @param Function Points to the notification function\r
+ @param Registration Returns the registration record\r
+\r
+ @retval EFI_INVALID_PARAMETER Invalid parameter\r
+ @retval EFI_SUCCESS Successfully returned the registration record\r
+ that has been added\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SmmRegisterProtocolNotify (\r
+ IN CONST EFI_GUID *Protocol,\r
+ IN EFI_SMM_NOTIFY_FN Function,\r
+ OUT VOID **Registration\r
+ );\r
+\r
+/**\r
+ Locates the requested handle(s) and returns them in Buffer.\r
+\r
+ @param SearchType The type of search to perform to locate the\r
+ handles\r
+ @param Protocol The protocol to search for\r
+ @param SearchKey Dependant on SearchType\r
+ @param BufferSize On input the size of Buffer. On output the\r
+ size of data returned.\r
+ @param Buffer The buffer to return the results in\r
+\r
+ @retval EFI_BUFFER_TOO_SMALL Buffer too small, required buffer size is\r
+ returned in BufferSize.\r
+ @retval EFI_INVALID_PARAMETER Invalid parameter\r
+ @retval EFI_SUCCESS Successfully found the requested handle(s) and\r
+ returns them in Buffer.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SmmLocateHandle (\r
+ IN EFI_LOCATE_SEARCH_TYPE SearchType,\r
+ IN EFI_GUID *Protocol OPTIONAL,\r
+ IN VOID *SearchKey OPTIONAL,\r
+ IN OUT UINTN *BufferSize,\r
+ OUT EFI_HANDLE *Buffer\r
+ );\r
+\r
+/**\r
+ Return the first Protocol Interface that matches the Protocol GUID. If\r
+ Registration is pasased in return a Protocol Instance that was just add\r
+ to the system. If Retistration is NULL return the first Protocol Interface\r
+ you find.\r
+\r
+ @param Protocol The protocol to search for\r
+ @param Registration Optional Registration Key returned from\r
+ RegisterProtocolNotify()\r
+ @param Interface Return the Protocol interface (instance).\r
+\r
+ @retval EFI_SUCCESS If a valid Interface is returned\r
+ @retval EFI_INVALID_PARAMETER Invalid parameter\r
+ @retval EFI_NOT_FOUND Protocol interface not found\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SmmLocateProtocol (\r
+ IN EFI_GUID *Protocol,\r
+ IN VOID *Registration OPTIONAL,\r
+ OUT VOID **Interface\r
+ );\r
+\r
+/**\r
+ Manage SMI of a particular type.\r
+\r
+ @param HandlerType Points to the handler type or NULL for root SMI handlers.\r
+ @param Context Points to an optional context buffer.\r
+ @param CommBuffer Points to the optional communication buffer.\r
+ @param CommBufferSize Points to the size of the optional communication buffer.\r
+\r
+ @retval EFI_SUCCESS Interrupt source was processed successfully but not quiesced.\r
+ @retval EFI_INTERRUPT_PENDING One or more SMI sources could not be quiesced.\r
+ @retval EFI_WARN_INTERRUPT_SOURCE_PENDING Interrupt source was not handled or quiesced.\r
+ @retval EFI_WARN_INTERRUPT_SOURCE_QUIESCED Interrupt source was handled and quiesced.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SmiManage (\r
+ IN CONST EFI_GUID *HandlerType,\r
+ IN CONST VOID *Context OPTIONAL,\r
+ IN OUT VOID *CommBuffer OPTIONAL,\r
+ IN OUT UINTN *CommBufferSize OPTIONAL\r
+ );\r
+\r
+/**\r
+ Registers a handler to execute within SMM.\r
+\r
+ @param Handler Handler service funtion pointer.\r
+ @param HandlerType Points to the handler type or NULL for root SMI handlers.\r
+ @param DispatchHandle On return, contains a unique handle which can be used to later unregister the handler function.\r
+\r
+ @retval EFI_SUCCESS Handler register success.\r
+ @retval EFI_INVALID_PARAMETER Handler or DispatchHandle is NULL.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SmiHandlerRegister (\r
+ IN EFI_SMM_HANDLER_ENTRY_POINT2 Handler,\r
+ IN CONST EFI_GUID *HandlerType OPTIONAL,\r
+ OUT EFI_HANDLE *DispatchHandle\r
+ );\r
+\r
+/**\r
+ Unregister a handler in SMM.\r
+\r
+ @param DispatchHandle The handle that was specified when the handler was registered.\r
+\r
+ @retval EFI_SUCCESS Handler function was successfully unregistered.\r
+ @retval EFI_INVALID_PARAMETER DispatchHandle does not refer to a valid handle.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SmiHandlerUnRegister (\r
+ IN EFI_HANDLE DispatchHandle\r
+ );\r
+\r
+/**\r
+ This function is the main entry point for an SMM handler dispatch\r
+ or communicate-based callback.\r
+\r
+ @param DispatchHandle The unique handle assigned to this handler by SmiHandlerRegister().\r
+ @param Context Points to an optional handler context which was specified when the handler was registered.\r
+ @param CommBuffer A pointer to a collection of data in memory that will\r
+ be conveyed from a non-SMM environment into an SMM environment.\r
+ @param CommBufferSize The size of the CommBuffer.\r
+\r
+ @return Status Code\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SmmDriverDispatchHandler (\r
+ IN EFI_HANDLE DispatchHandle,\r
+ IN CONST VOID *Context, OPTIONAL\r
+ IN OUT VOID *CommBuffer, OPTIONAL\r
+ IN OUT UINTN *CommBufferSize OPTIONAL\r
+ );\r
+\r
+/**\r
+ This function is the main entry point for an SMM handler dispatch\r
+ or communicate-based callback.\r
+\r
+ @param DispatchHandle The unique handle assigned to this handler by SmiHandlerRegister().\r
+ @param Context Points to an optional handler context which was specified when the handler was registered.\r
+ @param CommBuffer A pointer to a collection of data in memory that will\r
+ be conveyed from a non-SMM environment into an SMM environment.\r
+ @param CommBufferSize The size of the CommBuffer.\r
+\r
+ @return Status Code\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SmmLegacyBootHandler (\r
+ IN EFI_HANDLE DispatchHandle,\r
+ IN CONST VOID *Context, OPTIONAL\r
+ IN OUT VOID *CommBuffer, OPTIONAL\r
+ IN OUT UINTN *CommBufferSize OPTIONAL\r
+ );\r
+\r
+/**\r
+ This function is the main entry point for an SMM handler dispatch\r
+ or communicate-based callback.\r
+\r
+ @param DispatchHandle The unique handle assigned to this handler by SmiHandlerRegister().\r
+ @param Context Points to an optional handler context which was specified when the handler was registered.\r
+ @param CommBuffer A pointer to a collection of data in memory that will\r
+ be conveyed from a non-SMM environment into an SMM environment.\r
+ @param CommBufferSize The size of the CommBuffer.\r
+\r
+ @return Status Code\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SmmReadyToLockHandler (\r
+ IN EFI_HANDLE DispatchHandle,\r
+ IN CONST VOID *Context, OPTIONAL\r
+ IN OUT VOID *CommBuffer, OPTIONAL\r
+ IN OUT UINTN *CommBufferSize OPTIONAL\r
+ );\r
+\r
+/**\r
+ Place holder function until all the SMM System Table Service are available.\r
+\r
+ @param Arg1 Undefined\r
+ @param Arg2 Undefined\r
+ @param Arg3 Undefined\r
+ @param Arg4 Undefined\r
+ @param Arg5 Undefined\r
+\r
+ @return EFI_NOT_AVAILABLE_YET\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SmmEfiNotAvailableYetArg5 (\r
+ UINTN Arg1,\r
+ UINTN Arg2,\r
+ UINTN Arg3,\r
+ UINTN Arg4,\r
+ UINTN Arg5\r
+ );\r
+\r
+//\r
+//Functions used during debug buils\r
+//\r
+\r
+/**\r
+ Traverse the discovered list for any drivers that were discovered but not loaded\r
+ because the dependency experessions evaluated to false.\r
+\r
+**/\r
+VOID\r
+SmmDisplayDiscoveredNotDispatched (\r
+ VOID\r
+ );\r
+\r
+/**\r
+ Add free SMRAM region for use by memory service.\r
+\r
+ @param MemBase Base address of memory region.\r
+ @param MemLength Length of the memory region.\r
+ @param Type Memory type.\r
+ @param Attributes Memory region state.\r
+\r
+**/\r
+VOID\r
+SmmAddMemoryRegion (\r
+ IN EFI_PHYSICAL_ADDRESS MemBase,\r
+ IN UINT64 MemLength,\r
+ IN EFI_MEMORY_TYPE Type,\r
+ IN UINT64 Attributes\r
+ );\r
+\r
+/**\r
+ Finds the protocol entry for the requested protocol.\r
+\r
+ @param Protocol The ID of the protocol\r
+ @param Create Create a new entry if not found\r
+\r
+ @return Protocol entry\r
+\r
+**/\r
+PROTOCOL_ENTRY *\r
+SmmFindProtocolEntry (\r
+ IN EFI_GUID *Protocol,\r
+ IN BOOLEAN Create\r
+ );\r
+\r
+/**\r
+ Signal event for every protocol in protocol entry.\r
+\r
+ @param Prot Protocol interface\r
+\r
+**/\r
+VOID\r
+SmmNotifyProtocol (\r
+ IN PROTOCOL_INTERFACE *Prot\r
+ );\r
+\r
+/**\r
+ Finds the protocol instance for the requested handle and protocol.\r
+ Note: This function doesn't do parameters checking, it's caller's responsibility\r
+ to pass in valid parameters.\r
+\r
+ @param Handle The handle to search the protocol on\r
+ @param Protocol GUID of the protocol\r
+ @param Interface The interface for the protocol being searched\r
+\r
+ @return Protocol instance (NULL: Not found)\r
+\r
+**/\r
+PROTOCOL_INTERFACE *\r
+SmmFindProtocolInterface (\r
+ IN IHANDLE *Handle,\r
+ IN EFI_GUID *Protocol,\r
+ IN VOID *Interface\r
+ );\r
+\r
+/**\r
+ Removes Protocol from the protocol list (but not the handle list).\r
+\r
+ @param Handle The handle to remove protocol on.\r
+ @param Protocol GUID of the protocol to be moved\r
+ @param Interface The interface of the protocol\r
+\r
+ @return Protocol Entry\r
+\r
+**/\r
+PROTOCOL_INTERFACE *\r
+SmmRemoveInterfaceFromProtocol (\r
+ IN IHANDLE *Handle,\r
+ IN EFI_GUID *Protocol,\r
+ IN VOID *Interface\r
+ );\r
+\r
+/**\r
+ This is the POSTFIX version of the dependency evaluator. This code does\r
+ not need to handle Before or After, as it is not valid to call this\r
+ routine in this case. The SOR is just ignored and is a nop in the grammer.\r
+ POSTFIX means all the math is done on top of the stack.\r
+\r
+ @param DriverEntry DriverEntry element to update.\r
+\r
+ @retval TRUE If driver is ready to run.\r
+ @retval FALSE If driver is not ready to run or some fatal error\r
+ was found.\r
+\r
+**/\r
+BOOLEAN\r
+SmmIsSchedulable (\r
+ IN EFI_SMM_DRIVER_ENTRY *DriverEntry\r
+ );\r
+\r
+#endif\r
--- /dev/null
+## @file\r
+# This module provide an SMM CIS compliant implementation of SMM Core.\r
+#\r
+# Copyright (c) 2009 - 2010, Intel Corporation\r
+#\r
+# All rights reserved. This program and the accompanying materials\r
+# are licensed and made available under the terms and conditions of the BSD License\r
+# which accompanies this distribution. The full text of the license may be found at\r
+# http://opensource.org/licenses/bsd-license.php\r
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+#\r
+##\r
+\r
+[Defines]\r
+ INF_VERSION = 0x00010005\r
+ BASE_NAME = PiSmmCore\r
+ FILE_GUID = E94F54CD-81EB-47ed-AEC3-856F5DC157A9\r
+ MODULE_TYPE = SMM_CORE\r
+ VERSION_STRING = 1.0\r
+ PI_SPECIFICATION_VERSION = 0x0001000A\r
+ ENTRY_POINT = SmmMain\r
+\r
+# VALID_ARCHITECTURES = IA32 X64\r
+\r
+[Sources]\r
+ PiSmmCore.c\r
+ PiSmmCore.h\r
+ PiSmmCorePrivateData.h\r
+ Page.c\r
+ Pool.c\r
+ Handle.c\r
+ Locate.c\r
+ Notify.c\r
+ Dependency.c\r
+ Dispatcher.c\r
+ Smi.c\r
+ InstallConfigurationTable.c\r
+\r
+[Packages]\r
+ MdePkg/MdePkg.dec\r
+ \r
+[LibraryClasses]\r
+ UefiDriverEntryPoint\r
+ BaseLib\r
+ BaseMemoryLib\r
+ PeCoffLib\r
+ CacheMaintenanceLib \r
+ DebugLib\r
+ ReportStatusCodeLib\r
+ DevicePathLib \r
+ UefiLib \r
+ UefiBootServicesTableLib \r
+ MemoryAllocationLib\r
+ \r
+[Protocols]\r
+ gEfiDxeSmmReadyToLockProtocolGuid # PROTOCOL ALWAYS_CONSUMED\r
+ gEfiSmmReadyToLockProtocolGuid # PROTOCOL ALWAYS_PRODUCED\r
+ gEfiSmmCpuIo2ProtocolGuid # PROTOCOL ALWAYS_CONSUMED\r
+ gEfiFirmwareVolume2ProtocolGuid # PROTOCOL ALWAYS_CONSUMED\r
+ gEfiSecurityArchProtocolGuid # PROTOCOL SIMETIMES_CONSUMED\r
+ gEfiLoadedImageProtocolGuid # PROTOCOL SOMETIMES_PRODUCED\r
+ gEfiDevicePathProtocolGuid # PROTOCOL SOMETIMES_CONSUMED\r
+\r
+[Guids]\r
+ gAprioriGuid # ALWAYS_CONSUMED\r
+ gEfiEventDxeDispatchGuid # ALWAYS_CONSUMED\r
+ gEfiEventLegacyBootGuid # ALWAYS_CONSUMED\r
--- /dev/null
+/** @file\r
+ The internal header file that declared a data structure that is shared\r
+ between the SMM IPL and the SMM Core.\r
+\r
+ Copyright (c) 2009 - 2010, Intel Corporation. All rights reserved.<BR>\r
+ This program and the accompanying materials are licensed and made available \r
+ under the terms and conditions of the BSD License which accompanies this \r
+ distribution. The full text of the license may be found at \r
+ http://opensource.org/licenses/bsd-license.php \r
+\r
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, \r
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. \r
+\r
+**/\r
+\r
+#ifndef _PI_SMM_CORE_PRIVATE_DATA_H_\r
+#define _PI_SMM_CORE_PRIVATE_DATA_H_\r
+\r
+///\r
+/// Signature for the private structure shared between the SMM IPL and the SMM Core\r
+///\r
+#define SMM_CORE_PRIVATE_DATA_SIGNATURE SIGNATURE_32 ('s', 'm', 'm', 'c')\r
+\r
+///\r
+/// Private structure that is used to share information between the SMM IPL and \r
+/// the SMM Core. This structure is allocated from memory of type EfiRuntimeServicesData.\r
+/// Since runtime memory types are converted to available memory when a legacy boot \r
+/// is performed, the SMM Core must access any fields of this structure if a legacy \r
+/// boot is performed. As a result, the SMM IPL must create an event notification \r
+/// for the Legacy Boot event and notify the SMM Core that a legacy boot is being \r
+/// performed. The SMM Core can then use this information to filter accesses to \r
+/// thos structure.\r
+///\r
+typedef struct {\r
+ UINTN Signature;\r
+\r
+ ///\r
+ /// The ImageHandle passed into the entry point of the SMM IPL. This ImageHandle\r
+ /// is used by the SMM Core to fill in the ParentImageHandle field of the Loaded\r
+ /// Image Protocol for each SMM Driver that is dispatched by the SMM Core.\r
+ ///\r
+ EFI_HANDLE SmmIplImageHandle;\r
+\r
+ ///\r
+ /// The number of SMRAM ranges passed from the SMM IPL to the SMM Core. The SMM\r
+ /// Core uses these ranges of SMRAM to initialize the SMM Core memory manager.\r
+ ///\r
+ UINTN SmramRangeCount;\r
+\r
+ ///\r
+ /// A table of SMRAM ranges passed from the SMM IPL to the SMM Core. The SMM\r
+ /// Core uses these ranges of SMRAM to initialize the SMM Core memory manager.\r
+ ///\r
+ EFI_SMRAM_DESCRIPTOR *SmramRanges;\r
+\r
+ ///\r
+ /// The SMM Foundation Entry Point. The SMM Core fills in this field when the \r
+ /// SMM Core is initialized. The SMM IPL is responsbile for registering this entry \r
+ /// point with the SMM Configuration Protocol. The SMM Configuration Protocol may \r
+ /// not be available at the time the SMM IPL and SMM Core are started, so the SMM IPL\r
+ /// sets up a protocol notification on the SMM Configuration Protocol and registers \r
+ /// the SMM Foundation Entry Point as soon as the SMM Configuration Protocol is \r
+ /// available.\r
+ ///\r
+ EFI_SMM_ENTRY_POINT SmmEntryPoint;\r
+ \r
+ ///\r
+ /// Boolean flag set to TRUE while an SMI is being processed by the SMM Core.\r
+ /// \r
+ BOOLEAN SmmEntryPointRegistered;\r
+\r
+ ///\r
+ /// Boolean flag set to TRUE while an SMI is being processed by the SMM Core.\r
+ /// \r
+ BOOLEAN InSmm;\r
+\r
+ ///\r
+ /// This field is set by the SMM Core then the SMM Core is initialized. This field is\r
+ /// used by the SMM Base 2 Protocol and SMM Communication Protocol implementations in\r
+ /// the SMM IPL. \r
+ ///\r
+ EFI_SMM_SYSTEM_TABLE2 *Smst;\r
+\r
+ ///\r
+ /// This field is used by the SMM Communicatioon Protocol to pass a buffer into \r
+ /// a software SMI handler and for the software SMI handler to pass a buffer back to\r
+ /// the caller of the SMM Communication Protocol. \r
+ ///\r
+ VOID *CommunicationBuffer;\r
+\r
+ ///\r
+ /// This field is used by the SMM Communicatioon Protocol to pass the size of a buffer,\r
+ /// in bytes, into a software SMI handler and for the software SMI handler to pass the \r
+ /// size, in bytes, of a buffer back to the caller of the SMM Communication Protocol.\r
+ ///\r
+ UINTN *BufferSize;\r
+\r
+ ///\r
+ /// This field is used by the SMM Communication Protocol to pass the return status from\r
+ /// a software SMI handler back to the caller of the SMM Communication Protocol.\r
+ ///\r
+ EFI_STATUS ReturnStatus;\r
+} SMM_CORE_PRIVATE_DATA;\r
+\r
+#endif\r
--- /dev/null
+/** @file\r
+ SMM IPL that produces SMM related runtime protocols and load the SMM Core into SMRAM\r
+\r
+ Copyright (c) 2009 - 2010, Intel Corporation. All rights reserved.<BR>\r
+ This program and the accompanying materials are licensed and made available \r
+ under the terms and conditions of the BSD License which accompanies this \r
+ distribution. The full text of the license may be found at \r
+ http://opensource.org/licenses/bsd-license.php \r
+\r
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, \r
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. \r
+\r
+**/\r
+\r
+#include <PiDxe.h>\r
+\r
+#include <Protocol/SmmBase2.h>\r
+#include <Protocol/SmmCommunication.h>\r
+#include <Protocol/SmmAccess2.h>\r
+#include <Protocol/SmmConfiguration.h>\r
+#include <Protocol/SmmControl2.h>\r
+#include <Protocol/DxeSmmReadyToLock.h>\r
+#include <Protocol/FirmwareVolume2.h>\r
+\r
+#include <Guid/EventGroup.h>\r
+#include <Guid/EventLegacyBios.h>\r
+\r
+#include <Library/BaseLib.h>\r
+#include <Library/BaseMemoryLib.h>\r
+#include <Library/PeCoffLib.h>\r
+#include <Library/CacheMaintenanceLib.h>\r
+#include <Library/MemoryAllocationLib.h>\r
+#include <Library/DebugLib.h>\r
+#include <Library/UefiBootServicesTableLib.h>\r
+#include <Library/DxeServicesTableLib.h>\r
+#include <Library/UefiLib.h>\r
+#include <Library/UefiRuntimeLib.h>\r
+\r
+#include "PiSmmCorePrivateData.h"\r
+\r
+//\r
+// Function prototypes from produced protocols\r
+//\r
+\r
+/**\r
+ Indicate whether the driver is currently executing in the SMM Initialization phase.\r
+\r
+ @param This The EFI_SMM_BASE2_PROTOCOL instance.\r
+ @param InSmram Pointer to a Boolean which, on return, indicates that the driver is currently executing\r
+ inside of SMRAM (TRUE) or outside of SMRAM (FALSE).\r
+\r
+ @retval EFI_INVALID_PARAMETER InSmram was NULL.\r
+ @retval EFI_SUCCESS The call returned successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SmmBase2InSmram (\r
+ IN CONST EFI_SMM_BASE2_PROTOCOL *This,\r
+ OUT BOOLEAN *InSmram\r
+ );\r
+\r
+/**\r
+ Retrieves the location of the System Management System Table (SMST).\r
+\r
+ @param This The EFI_SMM_BASE2_PROTOCOL instance.\r
+ @param Smst On return, points to a pointer to the System Management Service Table (SMST).\r
+\r
+ @retval EFI_INVALID_PARAMETER Smst or This was invalid.\r
+ @retval EFI_SUCCESS The memory was returned to the system.\r
+ @retval EFI_UNSUPPORTED Not in SMM.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SmmBase2GetSmstLocation (\r
+ IN CONST EFI_SMM_BASE2_PROTOCOL *This,\r
+ OUT EFI_SMM_SYSTEM_TABLE2 **Smst\r
+ );\r
+\r
+/**\r
+ Communicates with a registered handler.\r
+ \r
+ This function provides a service to send and receive messages from a registered \r
+ UEFI service. This function is part of the SMM Communication Protocol that may \r
+ be called in physical mode prior to SetVirtualAddressMap() and in virtual mode \r
+ after SetVirtualAddressMap().\r
+\r
+ @param[in] This The EFI_SMM_COMMUNICATION_PROTOCOL instance.\r
+ @param[in out] CommBuffer A pointer to the buffer to convey into SMRAM.\r
+ @param[in out] CommSize The size of the data buffer being passed in.On exit, the size of data\r
+ being returned. Zero if the handler does not wish to reply with any data.\r
+\r
+ @retval EFI_SUCCESS The message was successfully posted.\r
+ @retval EFI_INVALID_PARAMETER The CommBuffer was NULL.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SmmCommunicationCommunicate (\r
+ IN CONST EFI_SMM_COMMUNICATION_PROTOCOL *This,\r
+ IN OUT VOID *CommBuffer,\r
+ IN OUT UINTN *CommSize\r
+ );\r
+\r
+/**\r
+ Event notification that is fired every time a gEfiSmmConfigurationProtocol installs.\r
+\r
+ @param Event The Event that is being processed, not used.\r
+ @param Context Event Context, not used.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+SmmIplSmmConfigurationEventNotify (\r
+ IN EFI_EVENT Event,\r
+ IN VOID *Context\r
+ );\r
+\r
+/**\r
+ Event notification that is fired every time a DxeSmmReadyToLock protocol is added\r
+ or if gEfiEventReadyToBootGuid is signalled.\r
+\r
+ @param Event The Event that is being processed, not used.\r
+ @param Context Event Context, not used.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+SmmIplReadyToLockEventNotify (\r
+ IN EFI_EVENT Event,\r
+ IN VOID *Context\r
+ );\r
+\r
+/**\r
+ Event notification that is fired when DxeDispatch Event Group is signaled.\r
+\r
+ @param Event The Event that is being processed, not used.\r
+ @param Context Event Context, not used.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+SmmIplGuidedEventNotify (\r
+ IN EFI_EVENT Event,\r
+ IN VOID *Context\r
+ );\r
+\r
+/**\r
+ Notification function of EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE.\r
+\r
+ This is a notification function registered on EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE event.\r
+ It convers pointer to new virtual address.\r
+\r
+ @param Event Event whose notification function is being invoked.\r
+ @param Context Pointer to the notification function's context.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+SmmIplSetVirtualAddressNotify (\r
+ IN EFI_EVENT Event,\r
+ IN VOID *Context\r
+ );\r
+\r
+//\r
+// Data structure used to declare a table of protocol notifications and event \r
+// notifications required by the SMM IPL\r
+//\r
+typedef struct {\r
+ BOOLEAN Protocol;\r
+ BOOLEAN CloseOnLock;\r
+ EFI_GUID *Guid;\r
+ EFI_EVENT_NOTIFY NotifyFunction;\r
+ VOID *NotifyContext;\r
+ EFI_EVENT Event;\r
+} SMM_IPL_EVENT_NOTIFICATION;\r
+\r
+//\r
+// Handle to install the SMM Base2 Protocol and the SMM Communication Protocol\r
+//\r
+EFI_HANDLE mSmmIplHandle = NULL;\r
+\r
+//\r
+// SMM Base 2 Protocol instance\r
+//\r
+EFI_SMM_BASE2_PROTOCOL mSmmBase2 = {\r
+ SmmBase2InSmram,\r
+ SmmBase2GetSmstLocation\r
+};\r
+\r
+//\r
+// SMM Communication Protocol instance\r
+//\r
+EFI_SMM_COMMUNICATION_PROTOCOL mSmmCommunication = {\r
+ SmmCommunicationCommunicate\r
+};\r
+\r
+//\r
+// SMM Core Private Data structure that contains the data shared between\r
+// the SMM IPL and the SMM Core.\r
+//\r
+SMM_CORE_PRIVATE_DATA mSmmCorePrivateData = {\r
+ SMM_CORE_PRIVATE_DATA_SIGNATURE, // Signature\r
+ NULL, // SmmIplImageHandle\r
+ 0, // SmramRangeCount\r
+ NULL, // SmramRanges\r
+ NULL, // SmmEntryPoint\r
+ FALSE, // SmmEntryPointRegistered\r
+ FALSE, // InSmm\r
+ NULL, // Smst\r
+ 0, // BufferSize\r
+ NULL, // CommunicationBuffer\r
+ EFI_SUCCESS // ReturnStatus\r
+};\r
+\r
+//\r
+// Global pointer used to access mSmmCorePrivateData from outside and inside SMM\r
+//\r
+SMM_CORE_PRIVATE_DATA *gSmmCorePrivate = &mSmmCorePrivateData;\r
+\r
+//\r
+// SMM IPL global variables\r
+//\r
+EFI_SMM_CONTROL2_PROTOCOL *mSmmControl2;\r
+EFI_SMM_ACCESS2_PROTOCOL *mSmmAccess;\r
+EFI_SMRAM_DESCRIPTOR *mCurrentSmramRange;\r
+BOOLEAN mSmmLocked = FALSE;\r
+\r
+//\r
+// Table of Protocol notification and GUIDed Event notifications that the SMM IPL requires\r
+//\r
+SMM_IPL_EVENT_NOTIFICATION mSmmIplEvents[] = {\r
+ //\r
+ // Declare protocol notification on the SMM Configuration protocol. When this notification is etablished, \r
+ // the associated event is immediately signalled, so the notification function will be executed and the \r
+ // SMM Configuration Protocol will be found if it is already in the handle database.\r
+ //\r
+ { TRUE, FALSE, &gEfiSmmConfigurationProtocolGuid, SmmIplSmmConfigurationEventNotify, &gEfiSmmConfigurationProtocolGuid, NULL },\r
+ //\r
+ // Declare protocl notification on DxeSmmReadyToLock protocols. When this notification is etablished, \r
+ // the associated event is immediately signalled, so the notification function will be executed and the \r
+ // DXE SMM Ready To Lock Protocol will be found if it is already in the handle database.\r
+ //\r
+ { TRUE, TRUE, &gEfiDxeSmmReadyToLockProtocolGuid, SmmIplReadyToLockEventNotify, &gEfiDxeSmmReadyToLockProtocolGuid, NULL },\r
+ //\r
+ // Declare event notification on the DXE Dispatch Event Group. This event is signaled by the DXE Core\r
+ // each time the DXE Core dispatcher has completed its work. When this event is signalled, the SMM Core\r
+ // if notified, so the SMM Core can dispatch SMM drivers.\r
+ //\r
+ { FALSE, TRUE, &gEfiEventDxeDispatchGuid, SmmIplGuidedEventNotify, &gEfiEventDxeDispatchGuid, NULL },\r
+ //\r
+ // Declare event notification on Ready To Boot Event Group. This is an extra event notification that is\r
+ // used to make sure SMRAM is locked before any boot options are processed.\r
+ //\r
+ { FALSE, TRUE, &gEfiEventReadyToBootGuid, SmmIplReadyToLockEventNotify, &gEfiEventReadyToBootGuid, NULL },\r
+ //\r
+ // Declare event notification on Legacy Boot Event Group. This is used to inform the SMM Core that the platform \r
+ // is performing a legacy boot operation, and that the UEFI environment is no longer available and the SMM Core \r
+ // must guarantee that it does not access any UEFI related structures outside of SMRAM.\r
+ //\r
+ { FALSE, FALSE, &gEfiEventLegacyBootGuid, SmmIplGuidedEventNotify, &gEfiEventLegacyBootGuid, NULL },\r
+ //\r
+ // Declare event notification on SetVirtualAddressMap() Event Group. This is used to convert gSmmCorePrivate \r
+ // and mSmmControl2 from physical addresses to virtual addresses.\r
+ //\r
+ { FALSE, FALSE, &gEfiEventVirtualAddressChangeGuid, SmmIplSetVirtualAddressNotify, NULL, NULL },\r
+ //\r
+ // Terminate the table of event notifications\r
+ //\r
+ { FALSE, FALSE, NULL, NULL, NULL, NULL }\r
+};\r
+\r
+/**\r
+ Indicate whether the driver is currently executing in the SMM Initialization phase.\r
+\r
+ @param This The EFI_SMM_BASE2_PROTOCOL instance.\r
+ @param InSmram Pointer to a Boolean which, on return, indicates that the driver is currently executing\r
+ inside of SMRAM (TRUE) or outside of SMRAM (FALSE).\r
+\r
+ @retval EFI_INVALID_PARAMETER InSmram was NULL.\r
+ @retval EFI_SUCCESS The call returned successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SmmBase2InSmram (\r
+ IN CONST EFI_SMM_BASE2_PROTOCOL *This,\r
+ OUT BOOLEAN *InSmram\r
+ )\r
+{\r
+ if (InSmram == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ *InSmram = gSmmCorePrivate->InSmm;\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Retrieves the location of the System Management System Table (SMST).\r
+\r
+ @param This The EFI_SMM_BASE2_PROTOCOL instance.\r
+ @param Smst On return, points to a pointer to the System Management Service Table (SMST).\r
+\r
+ @retval EFI_INVALID_PARAMETER Smst or This was invalid.\r
+ @retval EFI_SUCCESS The memory was returned to the system.\r
+ @retval EFI_UNSUPPORTED Not in SMM.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SmmBase2GetSmstLocation (\r
+ IN CONST EFI_SMM_BASE2_PROTOCOL *This,\r
+ OUT EFI_SMM_SYSTEM_TABLE2 **Smst\r
+ )\r
+{\r
+ if ((This == NULL) ||(Smst == NULL)) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+ \r
+ if (!gSmmCorePrivate->InSmm) {\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+ \r
+ *Smst = gSmmCorePrivate->Smst;\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Communicates with a registered handler.\r
+ \r
+ This function provides a service to send and receive messages from a registered \r
+ UEFI service. This function is part of the SMM Communication Protocol that may \r
+ be called in physical mode prior to SetVirtualAddressMap() and in virtual mode \r
+ after SetVirtualAddressMap().\r
+\r
+ @param[in] This The EFI_SMM_COMMUNICATION_PROTOCOL instance.\r
+ @param[in out] CommBuffer A pointer to the buffer to convey into SMRAM.\r
+ @param[in out] CommSize The size of the data buffer being passed in.On exit, the size of data\r
+ being returned. Zero if the handler does not wish to reply with any data.\r
+\r
+ @retval EFI_SUCCESS The message was successfully posted.\r
+ @retval EFI_INVALID_PARAMETER The CommBuffer was NULL.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SmmCommunicationCommunicate (\r
+ IN CONST EFI_SMM_COMMUNICATION_PROTOCOL *This,\r
+ IN OUT VOID *CommBuffer,\r
+ IN OUT UINTN *CommSize\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_SMM_COMMUNICATE_HEADER *CommunicateHeader;\r
+ BOOLEAN OldInSmm;\r
+\r
+ //\r
+ // Check parameters\r
+ //\r
+ if ((CommBuffer == NULL) || (CommSize == NULL)) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ //\r
+ // If not already in SMM, then generate a Software SMI\r
+ //\r
+ if (!gSmmCorePrivate->InSmm && gSmmCorePrivate->SmmEntryPointRegistered) {\r
+ //\r
+ // Put arguments for Software SMI in gSmmCorePrivate\r
+ //\r
+ gSmmCorePrivate->CommunicationBuffer = CommBuffer;\r
+ gSmmCorePrivate->BufferSize = CommSize;\r
+\r
+ //\r
+ // Generate Software SMI\r
+ //\r
+ Status = mSmmControl2->Trigger (mSmmControl2, NULL, NULL, FALSE, 0);\r
+ if (EFI_ERROR (Status)) {\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+\r
+ //\r
+ // Return status from software SMI \r
+ //\r
+ return gSmmCorePrivate->ReturnStatus;\r
+ }\r
+\r
+ //\r
+ // If we are in SMM, then the execution mode must be physical, which means that\r
+ // OS established virtual addresses can not be used. If SetVirtualAddressMap()\r
+ // has been called, then a direct invocation of the Software SMI is not \r
+ // not allowed so return EFI_INVALID_PARAMETER.\r
+ //\r
+ if (EfiGoneVirtual()) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ //\r
+ // Save current InSmm state and set InSmm state to TRUE\r
+ //\r
+ OldInSmm = gSmmCorePrivate->InSmm;\r
+ gSmmCorePrivate->InSmm = TRUE;\r
+\r
+ //\r
+ // Already in SMM and before SetVirtualAddressMap(), so call SmiManage() directly.\r
+ //\r
+ CommunicateHeader = (EFI_SMM_COMMUNICATE_HEADER *)CommBuffer;\r
+ *CommSize -= OFFSET_OF (EFI_SMM_COMMUNICATE_HEADER, Data);\r
+ Status = gSmmCorePrivate->Smst->SmiManage (\r
+ &CommunicateHeader->HeaderGuid, \r
+ NULL, \r
+ CommunicateHeader->Data, \r
+ CommSize\r
+ );\r
+\r
+ //\r
+ // Update CommunicationBuffer, BufferSize and ReturnStatus\r
+ // Communicate service finished, reset the pointer to CommBuffer to NULL\r
+ //\r
+ *CommSize += OFFSET_OF (EFI_SMM_COMMUNICATE_HEADER, Data);\r
+\r
+ //\r
+ // Restore original InSmm state\r
+ //\r
+ gSmmCorePrivate->InSmm = OldInSmm;\r
+\r
+ return (Status == EFI_WARN_INTERRUPT_SOURCE_QUIESCED) ? EFI_SUCCESS : EFI_NOT_FOUND;\r
+}\r
+\r
+/**\r
+ Event notification that is fired when DxeDispatch Event Group is signaled.\r
+\r
+ @param Event The Event that is being processed, not used.\r
+ @param Context Event Context, not used.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+SmmIplGuidedEventNotify (\r
+ IN EFI_EVENT Event,\r
+ IN VOID *Context\r
+ )\r
+{\r
+ EFI_SMM_COMMUNICATE_HEADER CommunicateHeader;\r
+ UINTN Size;\r
+\r
+ //\r
+ // Use Guid to initialize EFI_SMM_COMMUNICATE_HEADER structure \r
+ //\r
+ CopyGuid (&CommunicateHeader.HeaderGuid, (EFI_GUID *)Context);\r
+ CommunicateHeader.MessageLength = 1;\r
+ CommunicateHeader.Data[0] = 0;\r
+\r
+ //\r
+ // Generate the Software SMI and return the result\r
+ //\r
+ Size = sizeof (CommunicateHeader);\r
+ SmmCommunicationCommunicate (&mSmmCommunication, &CommunicateHeader, &Size);\r
+}\r
+\r
+/**\r
+ Event notification that is fired every time a gEfiSmmConfigurationProtocol installs.\r
+\r
+ @param Event The Event that is being processed, not used.\r
+ @param Context Event Context, not used.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+SmmIplSmmConfigurationEventNotify (\r
+ IN EFI_EVENT Event,\r
+ IN VOID *Context\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_SMM_CONFIGURATION_PROTOCOL *SmmConfiguration;\r
+\r
+ //\r
+ // Make sure this notification is for this handler\r
+ //\r
+ Status = gBS->LocateProtocol (Context, NULL, (VOID **)&SmmConfiguration);\r
+ if (EFI_ERROR (Status)) {\r
+ return;\r
+ }\r
+\r
+ //\r
+ // Register the SMM Entry Point provided by the SMM Core with the SMM COnfiguration protocol\r
+ //\r
+ Status = SmmConfiguration->RegisterSmmEntry (SmmConfiguration, gSmmCorePrivate->SmmEntryPoint);\r
+ ASSERT_EFI_ERROR (Status);\r
+\r
+ //\r
+ // Set flag to indicate that the SM< Entry Point has been registered which \r
+ // means that SMIs are now fully operational.\r
+ //\r
+ gSmmCorePrivate->SmmEntryPointRegistered = TRUE;\r
+\r
+ //\r
+ // Print debug message showing SMM Core entry point address.\r
+ //\r
+ DEBUG ((DEBUG_INFO, "SMM IPL registered SMM Entry Point address %p\n", (VOID *)(UINTN)gSmmCorePrivate->SmmEntryPoint));\r
+\r
+ //\r
+ // Attempt to reset SMRAM cacheability to UC\r
+ //\r
+ Status = gDS->SetMemorySpaceAttributes(\r
+ mCurrentSmramRange->CpuStart, \r
+ mCurrentSmramRange->PhysicalSize,\r
+ EFI_MEMORY_UC\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG ((DEBUG_WARN, "SMM IPL failed to reset SMRAM window to EFI_MEMORY_UC\n"));\r
+ } \r
+\r
+ //\r
+ // Close all SMRAM ranges to protect SMRAM\r
+ //\r
+ Status = mSmmAccess->Close (mSmmAccess);\r
+ ASSERT_EFI_ERROR (Status);\r
+\r
+ //\r
+ // Print debug message that the SMRAM window is now closed.\r
+ //\r
+ DEBUG ((DEBUG_INFO, "SMM IPL closed SMRAM window\n"));\r
+}\r
+\r
+/**\r
+ Event notification that is fired every time a DxeSmmReadyToLock protocol is added\r
+ or if gEfiEventReadyToBootGuid is signalled.\r
+\r
+ @param Event The Event that is being processed, not used.\r
+ @param Context Event Context, not used.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+SmmIplReadyToLockEventNotify (\r
+ IN EFI_EVENT Event,\r
+ IN VOID *Context\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ VOID *Interface;\r
+ UINTN Index;\r
+\r
+ //\r
+ // See if we are already locked\r
+ //\r
+ if (mSmmLocked) {\r
+ return;\r
+ }\r
+ \r
+ //\r
+ // Make sure this notification is for this handler\r
+ //\r
+ if (CompareGuid ((EFI_GUID *)Context, &gEfiDxeSmmReadyToLockProtocolGuid)) {\r
+ Status = gBS->LocateProtocol (&gEfiDxeSmmReadyToLockProtocolGuid, NULL, &Interface);\r
+ if (EFI_ERROR (Status)) {\r
+ return;\r
+ }\r
+ } else {\r
+ //\r
+ // If SMM is not locked yet and we got here from gEfiEventReadyToBootGuid being \r
+ // signalled, then gEfiDxeSmmReadyToLockProtocolGuid was not installed as expected.\r
+ // Print a warning on debug builds.\r
+ //\r
+ DEBUG ((DEBUG_WARN, "SMM IPL! DXE SMM Ready To Lock Protocol not installed before Ready To Boot signal\n"));\r
+ }\r
+\r
+ //\r
+ // Lock the SMRAM (Note: Locking SMRAM may not be supported on all platforms)\r
+ //\r
+ mSmmAccess->Lock (mSmmAccess);\r
+\r
+ //\r
+ // Close protocol and event notification events that do not apply after the \r
+ // DXE SMM Ready To Lock Protocol has been installed or the Ready To Boot \r
+ // event has been signalled.\r
+ //\r
+ for (Index = 0; mSmmIplEvents[Index].NotifyFunction != NULL; Index++) {\r
+ if (mSmmIplEvents[Index].CloseOnLock) {\r
+ gBS->CloseEvent (mSmmIplEvents[Index].Event);\r
+ }\r
+ }\r
+\r
+ //\r
+ // Inform SMM Core that the DxeSmmReadyToLock protocol was installed\r
+ //\r
+ SmmIplGuidedEventNotify (Event, (VOID *)&gEfiDxeSmmReadyToLockProtocolGuid);\r
+\r
+ //\r
+ // Print debug message that the SMRAM window is now locked.\r
+ //\r
+ DEBUG ((DEBUG_INFO, "SMM IPL locked SMRAM window\n"));\r
+ \r
+ //\r
+ // Set flag so this operation will not be performed again\r
+ //\r
+ mSmmLocked = TRUE;\r
+}\r
+\r
+/**\r
+ Notification function of EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE.\r
+\r
+ This is a notification function registered on EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE event.\r
+ It convers pointer to new virtual address.\r
+\r
+ @param Event Event whose notification function is being invoked.\r
+ @param Context Pointer to the notification function's context.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+SmmIplSetVirtualAddressNotify (\r
+ IN EFI_EVENT Event,\r
+ IN VOID *Context\r
+ )\r
+{\r
+ EfiConvertPointer (0x0, (VOID **)&mSmmControl2);\r
+}\r
+\r
+/**\r
+ Searches all Firmware Volumes for the first file matching FileType and SectionType and returns the section data.\r
+\r
+ @param FileType FileType to search for within any of the firmware volumes in the platform.\r
+ @param SectionType SectionType to search for within any of the matching FileTypes in the firmware volumes in the platform.\r
+ @param SourceSize Return the size of the returned section data..\r
+\r
+ @retval != NULL Pointer to the allocated buffer containing the section data.\r
+ @retval NULL Section data was not found.\r
+\r
+**/\r
+VOID *\r
+GetSectionInAnyFv (\r
+ IN EFI_FV_FILETYPE FileType,\r
+ IN EFI_SECTION_TYPE SectionType,\r
+ OUT UINTN *SourceSize\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINTN HandleCount;\r
+ EFI_HANDLE *HandleBuffer;\r
+ UINTN Index;\r
+ EFI_FIRMWARE_VOLUME2_PROTOCOL *Fv;\r
+ UINTN Key;\r
+ EFI_GUID NameGuid;\r
+ EFI_FV_FILE_ATTRIBUTES Attributes;\r
+ VOID *SourceBuffer;\r
+ UINT32 AuthenticationStatus;\r
+\r
+ HandleBuffer = NULL;\r
+ Status = gBS->LocateHandleBuffer (\r
+ ByProtocol,\r
+ &gEfiFirmwareVolume2ProtocolGuid,\r
+ NULL,\r
+ &HandleCount,\r
+ &HandleBuffer\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return NULL;\r
+ }\r
+\r
+ for (Index = 0; Index < HandleCount; Index++) {\r
+ Status = gBS->HandleProtocol (\r
+ HandleBuffer[Index],\r
+ &gEfiFirmwareVolume2ProtocolGuid,\r
+ (VOID **)&Fv\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ continue;\r
+ }\r
+\r
+ //\r
+ // Use Firmware Volume 2 Protocol to search for a file of type FileType\r
+ //\r
+ Key = 0; \r
+ Status = Fv->GetNextFile (Fv, &Key, &FileType, &NameGuid, &Attributes, SourceSize);\r
+ if (EFI_ERROR (Status)) {\r
+ continue;\r
+ }\r
+\r
+ //\r
+ // Use Firmware Volume 2 Protocol to read a section of type SectionType\r
+ //\r
+ SourceBuffer = NULL;\r
+ Status = Fv->ReadSection (Fv, &NameGuid, SectionType, 0, &SourceBuffer, SourceSize, &AuthenticationStatus);\r
+ if (!EFI_ERROR (Status)) {\r
+ FreePool (HandleBuffer);\r
+ return SourceBuffer;\r
+ }\r
+ } \r
+\r
+ FreePool(HandleBuffer);\r
+ \r
+ return NULL;\r
+}\r
+\r
+/**\r
+ Load the SMM Core image into SMRAM and executes the SMM Core from SMRAM.\r
+\r
+ @param[in] SmramRange Descriptor for the range of SMRAM to reload the \r
+ currently executing image.\r
+ @param[in] Context Context to pass into SMM Core\r
+\r
+ @return EFI_STATUS\r
+\r
+**/\r
+EFI_STATUS\r
+ExecuteSmmCoreFromSmram (\r
+ IN EFI_SMRAM_DESCRIPTOR *SmramRange,\r
+ IN VOID *Context\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ VOID *SourceBuffer;\r
+ UINTN SourceSize;\r
+ PE_COFF_LOADER_IMAGE_CONTEXT ImageContext;\r
+ UINTN PageCount;\r
+ EFI_PHYSICAL_ADDRESS DestinationBuffer;\r
+ EFI_IMAGE_ENTRY_POINT EntryPoint;\r
+\r
+ //\r
+ // Search all Firmware Volumes for a PE/COFF image in a file of type SMM_CORE\r
+ // \r
+ SourceBuffer = GetSectionInAnyFv (EFI_FV_FILETYPE_SMM_CORE, EFI_SECTION_PE32, &SourceSize);\r
+ if (SourceBuffer == NULL) {\r
+ return EFI_NOT_FOUND;\r
+ }\r
+ \r
+ //\r
+ // Initilize ImageContext\r
+ //\r
+ ImageContext.Handle = SourceBuffer;\r
+ ImageContext.ImageRead = PeCoffLoaderImageReadFromMemory;\r
+\r
+ //\r
+ // Get information about the image being loaded\r
+ //\r
+ Status = PeCoffLoaderGetImageInfo (&ImageContext);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ //\r
+ // Allocate memory for the image being loaded from the EFI_SRAM_DESCRIPTOR \r
+ // specified by SmramRange\r
+ //\r
+ PageCount = (UINTN)EFI_SIZE_TO_PAGES(ImageContext.ImageSize + ImageContext.SectionAlignment);\r
+\r
+ ASSERT ((SmramRange->PhysicalSize & EFI_PAGE_MASK) == 0);\r
+ ASSERT (SmramRange->PhysicalSize > EFI_PAGES_TO_SIZE (PageCount));\r
+\r
+ SmramRange->PhysicalSize -= EFI_PAGES_TO_SIZE (PageCount);\r
+ DestinationBuffer = SmramRange->CpuStart + SmramRange->PhysicalSize;\r
+\r
+ //\r
+ // Align buffer on section boundry\r
+ //\r
+ ImageContext.ImageAddress = DestinationBuffer;\r
+ ImageContext.ImageAddress += ImageContext.SectionAlignment - 1;\r
+ ImageContext.ImageAddress &= ~(ImageContext.SectionAlignment - 1);\r
+\r
+ //\r
+ // Print debug message showing SMM Core load address.\r
+ //\r
+ DEBUG ((DEBUG_INFO, "SMM IPL loading SMM Core at SMRAM address %p\n", (VOID *)(UINTN)ImageContext.ImageAddress));\r
+\r
+ //\r
+ // Load the image to our new buffer\r
+ //\r
+ Status = PeCoffLoaderLoadImage (&ImageContext);\r
+ if (!EFI_ERROR (Status)) {\r
+ //\r
+ // Relocate the image in our new buffer\r
+ //\r
+ Status = PeCoffLoaderRelocateImage (&ImageContext);\r
+ if (!EFI_ERROR (Status)) {\r
+ //\r
+ // Flush the instruction cache so the image data are written before we execute it\r
+ //\r
+ InvalidateInstructionCacheRange ((VOID *)(UINTN)ImageContext.ImageAddress, (UINTN)ImageContext.ImageSize);\r
+\r
+ //\r
+ // Print debug message showing SMM Core entry point address.\r
+ //\r
+ DEBUG ((DEBUG_INFO, "SMM IPL calling SMM Core at SMRAM address %p\n", (VOID *)(UINTN)ImageContext.EntryPoint));\r
+\r
+ //\r
+ // Execute image\r
+ //\r
+ EntryPoint = (EFI_IMAGE_ENTRY_POINT)(UINTN)ImageContext.EntryPoint;\r
+ Status = EntryPoint ((EFI_HANDLE)Context, gST);\r
+ }\r
+ }\r
+\r
+ //\r
+ // If the load operation, relocate operation, or the image execution return an\r
+ // error, then free memory allocated from the EFI_SRAM_DESCRIPTOR specified by \r
+ // SmramRange\r
+ //\r
+ if (EFI_ERROR (Status)) {\r
+ SmramRange->PhysicalSize += EFI_PAGES_TO_SIZE (PageCount);\r
+ }\r
+\r
+ //\r
+ // Always free memory allocted by GetFileBufferByFilePath ()\r
+ //\r
+ FreePool (SourceBuffer);\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ The Entry Point for SMM IPL\r
+\r
+ Load SMM Core into SMRAM, register SMM Core entry point for SMIs, install \r
+ SMM Base 2 Protocol and SMM Communication Protocol, and register for the \r
+ critical events required to coordinate between DXE and SMM environments.\r
+ \r
+ @param ImageHandle The firmware allocated handle for the EFI image.\r
+ @param SystemTable A pointer to the EFI System Table.\r
+\r
+ @retval EFI_SUCCESS The entry point is executed successfully.\r
+ @retval Other Some error occurred when executing this entry point.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SmmIplEntry (\r
+ IN EFI_HANDLE ImageHandle,\r
+ IN EFI_SYSTEM_TABLE *SystemTable\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_SMM_CONFIGURATION_PROTOCOL *SmmConfiguration;\r
+ UINTN Size;\r
+ UINTN Index;\r
+ EFI_SMM_RESERVED_SMRAM_REGION *SmramResRegion;\r
+ UINT64 MaxSize;\r
+ VOID *Registration;\r
+\r
+ //\r
+ // Fill in the image handle of the SMM IPL so the SMM Core can use this as the \r
+ // ParentImageHandle field of the Load Image Protocol for all SMM Drivers loaded \r
+ // by the SMM Core\r
+ //\r
+ mSmmCorePrivateData.SmmIplImageHandle = ImageHandle;\r
+\r
+ //\r
+ // Get SMM Access Protocol\r
+ //\r
+ Status = gBS->LocateProtocol (&gEfiSmmAccess2ProtocolGuid, NULL, (VOID **)&mSmmAccess);\r
+ ASSERT_EFI_ERROR (Status);\r
+\r
+ //\r
+ // Get SMM Control2 Protocol\r
+ //\r
+ Status = gBS->LocateProtocol (&gEfiSmmControl2ProtocolGuid, NULL, (VOID **)&mSmmControl2);\r
+ ASSERT_EFI_ERROR (Status);\r
+\r
+ //\r
+ // Get SMM Configuration Protocol if it is present\r
+ //\r
+ SmmConfiguration = NULL;\r
+ Status = gBS->LocateProtocol (&gEfiSmmConfigurationProtocolGuid, NULL, (VOID **) &SmmConfiguration);\r
+\r
+ //\r
+ // Get SMRAM information\r
+ //\r
+ Size = 0;\r
+ Status = mSmmAccess->GetCapabilities (mSmmAccess, &Size, NULL);\r
+ ASSERT (Status == EFI_BUFFER_TOO_SMALL);\r
+\r
+ gSmmCorePrivate->SmramRanges = (EFI_SMRAM_DESCRIPTOR *)AllocatePool (Size);\r
+ ASSERT (gSmmCorePrivate->SmramRanges != NULL);\r
+\r
+ Status = mSmmAccess->GetCapabilities (mSmmAccess, &Size, gSmmCorePrivate->SmramRanges);\r
+ ASSERT_EFI_ERROR (Status);\r
+\r
+ gSmmCorePrivate->SmramRangeCount = Size / sizeof (EFI_SMRAM_DESCRIPTOR);\r
+\r
+ //\r
+ // Open all SMRAM ranges\r
+ //\r
+ Status = mSmmAccess->Open (mSmmAccess);\r
+ ASSERT_EFI_ERROR (Status);\r
+\r
+ //\r
+ // Print debug message that the SMRAM window is now open.\r
+ //\r
+ DEBUG ((DEBUG_INFO, "SMM IPL opened SMRAM window\n"));\r
+\r
+ //\r
+ // Subtract SMRAM any reserved SMRAM regions.\r
+ //\r
+ if (SmmConfiguration != NULL) {\r
+ SmramResRegion = SmmConfiguration->SmramReservedRegions;\r
+ while (SmramResRegion->SmramReservedSize != 0) {\r
+ for (Index = 0; Index < gSmmCorePrivate->SmramRangeCount; Index ++) {\r
+ if ((SmramResRegion->SmramReservedStart >= gSmmCorePrivate->SmramRanges[Index].CpuStart) && \\r
+ ((SmramResRegion->SmramReservedStart + SmramResRegion->SmramReservedSize) <= \\r
+ (gSmmCorePrivate->SmramRanges[Index].CpuStart + gSmmCorePrivate->SmramRanges[Index].PhysicalSize))) {\r
+ //\r
+ // This range has reserved area, calculate the left free size\r
+ //\r
+ gSmmCorePrivate->SmramRanges[Index].PhysicalSize = SmramResRegion->SmramReservedStart - gSmmCorePrivate->SmramRanges[Index].CpuStart;\r
+ }\r
+ }\r
+ SmramResRegion++;\r
+ }\r
+ }\r
+ \r
+ //\r
+ // Find the largest SMRAM range between 1MB and 4GB that is at least 1MB in size\r
+ //\r
+ mCurrentSmramRange = NULL;\r
+ for (Index = 0, MaxSize = SIZE_1MB; Index < gSmmCorePrivate->SmramRangeCount; Index++) {\r
+ if (gSmmCorePrivate->SmramRanges[Index].CpuStart >= BASE_1MB) {\r
+ if ((gSmmCorePrivate->SmramRanges[Index].CpuStart + gSmmCorePrivate->SmramRanges[Index].PhysicalSize) <= BASE_4GB) {\r
+ if (gSmmCorePrivate->SmramRanges[Index].PhysicalSize >= MaxSize) {\r
+ MaxSize = gSmmCorePrivate->SmramRanges[Index].PhysicalSize;\r
+ mCurrentSmramRange = &gSmmCorePrivate->SmramRanges[Index];\r
+ }\r
+ }\r
+ }\r
+ }\r
+\r
+ if (mCurrentSmramRange != NULL) {\r
+ //\r
+ // Print debug message showing SMRAM window that will be used by SMM IPL and SMM Core\r
+ //\r
+ DEBUG ((DEBUG_INFO, "SMM IPL found SMRAM window %p - %p\n", \r
+ (VOID *)(UINTN)mCurrentSmramRange->CpuStart, \r
+ (VOID *)(UINTN)(mCurrentSmramRange->CpuStart + mCurrentSmramRange->PhysicalSize - 1)\r
+ ));\r
+\r
+ //\r
+ // Attempt to set SMRAM cacheability to WB\r
+ //\r
+ Status = gDS->SetMemorySpaceAttributes(\r
+ mCurrentSmramRange->CpuStart, \r
+ mCurrentSmramRange->PhysicalSize,\r
+ EFI_MEMORY_WB\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG ((DEBUG_WARN, "SMM IPL failed to set SMRAM window to EFI_MEMORY_WB\n"));\r
+ } \r
+\r
+ //\r
+ // Load SMM Core into SMRAM and execute it from SMRAM\r
+ //\r
+ Status = ExecuteSmmCoreFromSmram (mCurrentSmramRange, gSmmCorePrivate);\r
+ if (EFI_ERROR (Status)) {\r
+ //\r
+ // Print error message that the SMM Core failed to be loaded and executed.\r
+ //\r
+ DEBUG ((DEBUG_ERROR, "SMM IPL could not load and execute SMM Core from SMRAM\n"));\r
+\r
+ //\r
+ // Attempt to reset SMRAM cacheability to UC\r
+ //\r
+ Status = gDS->SetMemorySpaceAttributes(\r
+ mCurrentSmramRange->CpuStart, \r
+ mCurrentSmramRange->PhysicalSize,\r
+ EFI_MEMORY_UC\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG ((DEBUG_WARN, "SMM IPL failed to reset SMRAM window to EFI_MEMORY_UC\n"));\r
+ } \r
+ }\r
+ } else {\r
+ //\r
+ // Print error message that there are not enough SMRAM resources to load the SMM Core.\r
+ //\r
+ DEBUG ((DEBUG_ERROR, "SMM IPL could not find a large enough SMRAM region to load SMM Core\n"));\r
+ }\r
+\r
+ //\r
+ // If the SMM Core could not be loaded then close SMRAM window, free allocated \r
+ // resources, and return an error so SMM IPL will be unloaded.\r
+ //\r
+ if (mCurrentSmramRange == NULL || EFI_ERROR (Status)) {\r
+ //\r
+ // Close all SMRAM ranges\r
+ //\r
+ Status = mSmmAccess->Close (mSmmAccess);\r
+ ASSERT_EFI_ERROR (Status);\r
+\r
+ //\r
+ // Print debug message that the SMRAM window is now closed.\r
+ //\r
+ DEBUG ((DEBUG_INFO, "SMM IPL closed SMRAM window\n"));\r
+\r
+ //\r
+ // Free all allocated resources\r
+ //\r
+ FreePool (gSmmCorePrivate->SmramRanges);\r
+ \r
+ return EFI_UNSUPPORTED;\r
+ }\r
+ \r
+ //\r
+ // Install SMM Base2 Protocol and SMM Communication Protocol\r
+ //\r
+ Status = gBS->InstallMultipleProtocolInterfaces (\r
+ &mSmmIplHandle,\r
+ &gEfiSmmBase2ProtocolGuid, &mSmmBase2,\r
+ &gEfiSmmCommunicationProtocolGuid, &mSmmCommunication,\r
+ NULL\r
+ );\r
+ ASSERT_EFI_ERROR (Status);\r
+\r
+ //\r
+ // Create the set of protocol and event notififcations that the SMM IPL requires\r
+ //\r
+ for (Index = 0; mSmmIplEvents[Index].NotifyFunction != NULL; Index++) {\r
+ if (mSmmIplEvents[Index].Protocol) {\r
+ mSmmIplEvents[Index].Event = EfiCreateProtocolNotifyEvent (\r
+ mSmmIplEvents[Index].Guid,\r
+ TPL_CALLBACK,\r
+ mSmmIplEvents[Index].NotifyFunction,\r
+ mSmmIplEvents[Index].NotifyContext,\r
+ &Registration\r
+ );\r
+ } else {\r
+ Status = gBS->CreateEventEx (\r
+ EVT_NOTIFY_SIGNAL,\r
+ TPL_CALLBACK,\r
+ mSmmIplEvents[Index].NotifyFunction,\r
+ mSmmIplEvents[Index].NotifyContext,\r
+ mSmmIplEvents[Index].Guid,\r
+ &mSmmIplEvents[Index].Event\r
+ );\r
+ ASSERT_EFI_ERROR (Status);\r
+ }\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
--- /dev/null
+## @file\r
+# This module provide an SMM CIS compliant implementation of SMM IPL.\r
+#\r
+# Copyright (c) 2009 - 2010, Intel Corporation\r
+#\r
+# All rights reserved. This program and the accompanying materials\r
+# are licensed and made available under the terms and conditions of the BSD License\r
+# which accompanies this distribution. The full text of the license may be found at\r
+# http://opensource.org/licenses/bsd-license.php\r
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+#\r
+##\r
+\r
+[Defines]\r
+ INF_VERSION = 0x00010005\r
+ BASE_NAME = PiSmmIpl\r
+ FILE_GUID = 2FA2A6DA-11D5-4dc3-999A-749648B03C56\r
+ MODULE_TYPE = DXE_RUNTIME_DRIVER\r
+ VERSION_STRING = 1.0\r
+ PI_SPECIFICATION_VERSION = 0x0001000A\r
+ ENTRY_POINT = SmmIplEntry\r
+\r
+#\r
+# The following information is for reference only and not required by the build tools.\r
+#\r
+# VALID_ARCHITECTURES = IA32 X64\r
+#\r
+\r
+[Sources]\r
+ PiSmmIpl.c\r
+ PiSmmCorePrivateData.h\r
+\r
+[Packages]\r
+ MdePkg/MdePkg.dec\r
+ \r
+[LibraryClasses]\r
+ UefiDriverEntryPoint\r
+ BaseLib\r
+ BaseMemoryLib\r
+ PeCoffLib\r
+ CacheMaintenanceLib \r
+ MemoryAllocationLib\r
+ DebugLib\r
+ UefiBootServicesTableLib\r
+ DxeServicesTableLib\r
+ UefiLib\r
+ UefiRuntimeLib\r
+ \r
+[Protocols]\r
+ gEfiSmmBase2ProtocolGuid # PROTOCOL ALWAYS_PRODUCED\r
+ gEfiSmmCommunicationProtocolGuid # PROTOCOL ALWAYS_PRODUCED\r
+ gEfiSmmAccess2ProtocolGuid # PROTOCOL ALWAYS_CONSUMED\r
+ gEfiSmmConfigurationProtocolGuid # PROTOCOL ALWAYS_CONSUMED\r
+ gEfiSmmControl2ProtocolGuid # PROTOCOL ALWAYS_CONSUMED\r
+ gEfiDxeSmmReadyToLockProtocolGuid # PROTOCOL ALWAYS_CONSUMED\r
+ gEfiFirmwareVolume2ProtocolGuid # PROTOCOL ALWAYS_CONSUMED\r
+\r
+[Guids]\r
+ gEfiEventDxeDispatchGuid # ALWAYS_CONSUMED\r
+ gEfiEventReadyToBootGuid # ALWAYS_CONSUMED\r
+ gEfiEventLegacyBootGuid # ALWAYS_CONSUMED\r
+ gEfiEventVirtualAddressChangeGuid # ALWAYS_CONSUMED\r
+ \r
+[Depex]\r
+ gEfiSmmAccess2ProtocolGuid AND gEfiSmmControl2ProtocolGuid\r
--- /dev/null
+/** @file\r
+ SMM Memory pool management functions.\r
+\r
+ Copyright (c) 2009 - 2010, Intel Corporation. All rights reserved.<BR>\r
+ This program and the accompanying materials are licensed and made available \r
+ under the terms and conditions of the BSD License which accompanies this \r
+ distribution. The full text of the license may be found at \r
+ http://opensource.org/licenses/bsd-license.php \r
+\r
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, \r
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. \r
+\r
+**/\r
+\r
+#include "PiSmmCore.h"\r
+\r
+//\r
+// MIN_POOL_SHIFT must not be less than 5\r
+//\r
+#define MIN_POOL_SHIFT 6\r
+#define MIN_POOL_SIZE (1 << MIN_POOL_SHIFT)\r
+\r
+//\r
+// MAX_POOL_SHIFT must not be less than EFI_PAGE_SHIFT - 1\r
+//\r
+#define MAX_POOL_SHIFT (EFI_PAGE_SHIFT - 1)\r
+#define MAX_POOL_SIZE (1 << MAX_POOL_SHIFT)\r
+\r
+//\r
+// MAX_POOL_INDEX are calculated by maximum and minimum pool sizes\r
+//\r
+#define MAX_POOL_INDEX (MAX_POOL_SHIFT - MIN_POOL_SHIFT + 1)\r
+\r
+typedef struct {\r
+ UINTN Size;\r
+ BOOLEAN Available;\r
+} POOL_HEADER;\r
+\r
+typedef struct {\r
+ POOL_HEADER Header;\r
+ LIST_ENTRY Link;\r
+} FREE_POOL_HEADER;\r
+\r
+LIST_ENTRY mSmmPoolLists[MAX_POOL_INDEX];\r
+\r
+/**\r
+ Called to initialize the memory service.\r
+\r
+ @param SmramRangeCount Number of SMRAM Regions\r
+ @param SmramRanges Pointer to SMRAM Descriptors\r
+\r
+**/\r
+VOID\r
+SmmInitializeMemoryServices (\r
+ IN UINTN SmramRangeCount,\r
+ IN EFI_SMRAM_DESCRIPTOR *SmramRanges\r
+ )\r
+{\r
+ UINTN Index;\r
+\r
+ //\r
+ // Initialize Pool list\r
+ //\r
+ for (Index = sizeof (mSmmPoolLists) / sizeof (*mSmmPoolLists); Index > 0;) {\r
+ InitializeListHead (&mSmmPoolLists[--Index]);\r
+ }\r
+\r
+ //\r
+ // Initialize free SMRAM regions\r
+ //\r
+ for (Index = 0; Index < SmramRangeCount; Index++) {\r
+ SmmAddMemoryRegion (\r
+ SmramRanges[Index].CpuStart,\r
+ SmramRanges[Index].PhysicalSize,\r
+ EfiConventionalMemory,\r
+ SmramRanges[Index].RegionState\r
+ );\r
+ }\r
+}\r
+\r
+/**\r
+ Internal Function. Allocate a pool by specified PoolIndex.\r
+\r
+ @param PoolIndex Index which indicate the Pool size.\r
+ @param FreePoolHdr The returned Free pool.\r
+\r
+ @retval EFI_OUT_OF_RESOURCES Allocation failed.\r
+ @retval EFI_SUCCESS Pool successfully allocated.\r
+\r
+**/\r
+EFI_STATUS\r
+InternalAllocPoolByIndex (\r
+ IN UINTN PoolIndex,\r
+ OUT FREE_POOL_HEADER **FreePoolHdr\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ FREE_POOL_HEADER *Hdr;\r
+\r
+ Status = EFI_SUCCESS;\r
+ if (PoolIndex == MAX_POOL_INDEX) {\r
+ Hdr = (FREE_POOL_HEADER *)AllocatePages (EFI_SIZE_TO_PAGES (MAX_POOL_SIZE << 1));\r
+ if (Hdr == NULL) {\r
+ Status = EFI_OUT_OF_RESOURCES;\r
+ }\r
+ } else if (!IsListEmpty (&mSmmPoolLists[PoolIndex])) {\r
+ Hdr = BASE_CR (GetFirstNode (&mSmmPoolLists[PoolIndex]), FREE_POOL_HEADER, Link);\r
+ RemoveEntryList (&Hdr->Link);\r
+ } else {\r
+ Status = InternalAllocPoolByIndex (PoolIndex + 1, &Hdr);\r
+ if (!EFI_ERROR (Status)) {\r
+ Hdr->Header.Size >>= 1;\r
+ Hdr->Header.Available = TRUE;\r
+ InsertHeadList (&mSmmPoolLists[PoolIndex], &Hdr->Link);\r
+ Hdr = (FREE_POOL_HEADER*)((UINT8*)Hdr + Hdr->Header.Size);\r
+ }\r
+ }\r
+\r
+ if (!EFI_ERROR (Status)) {\r
+ Hdr->Header.Size = MIN_POOL_SIZE << PoolIndex;\r
+ Hdr->Header.Available = FALSE;\r
+ }\r
+\r
+ *FreePoolHdr = Hdr;\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Internal Function. Free a pool by specified PoolIndex.\r
+\r
+ @param FreePoolHdr The pool to free.\r
+\r
+ @retval EFI_SUCCESS Pool successfully freed.\r
+\r
+**/\r
+EFI_STATUS\r
+InternalFreePoolByIndex (\r
+ IN FREE_POOL_HEADER *FreePoolHdr\r
+ )\r
+{\r
+ UINTN PoolIndex;\r
+\r
+ ASSERT ((FreePoolHdr->Header.Size & (FreePoolHdr->Header.Size - 1)) == 0);\r
+ ASSERT (((UINTN)FreePoolHdr & (FreePoolHdr->Header.Size - 1)) == 0);\r
+ ASSERT (FreePoolHdr->Header.Size >= MIN_POOL_SIZE);\r
+\r
+ PoolIndex = HighBitSet32 ((UINT32)FreePoolHdr->Header.Size) - MIN_POOL_SHIFT;\r
+ FreePoolHdr->Header.Available = TRUE;\r
+ InsertHeadList (&mSmmPoolLists[PoolIndex], &FreePoolHdr->Link);\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Allocate pool of a particular type.\r
+\r
+ @param PoolType Type of pool to allocate.\r
+ @param Size The amount of pool to allocate.\r
+ @param Buffer The address to return a pointer to the allocated\r
+ pool.\r
+\r
+ @retval EFI_INVALID_PARAMETER PoolType not valid.\r
+ @retval EFI_OUT_OF_RESOURCES Size exceeds max pool size or allocation failed.\r
+ @retval EFI_SUCCESS Pool successfully allocated.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SmmAllocatePool (\r
+ IN EFI_MEMORY_TYPE PoolType,\r
+ IN UINTN Size,\r
+ OUT VOID **Buffer\r
+ )\r
+{\r
+ POOL_HEADER *PoolHdr;\r
+ FREE_POOL_HEADER *FreePoolHdr;\r
+ EFI_STATUS Status;\r
+ EFI_PHYSICAL_ADDRESS Address;\r
+ UINTN PoolIndex;\r
+\r
+ if (PoolType != EfiRuntimeServicesCode &&\r
+ PoolType != EfiRuntimeServicesData) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ if (Size == 0) {\r
+ *Buffer = NULL;\r
+ return EFI_SUCCESS;\r
+ }\r
+\r
+ Size += sizeof (*PoolHdr);\r
+ if (Size > MAX_POOL_SIZE) {\r
+ Size = EFI_SIZE_TO_PAGES (Size);\r
+ Status = SmmAllocatePages (AllocateAnyPages, PoolType, Size, &Address);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ PoolHdr = (POOL_HEADER*)(UINTN)Address;\r
+ PoolHdr->Size = EFI_PAGES_TO_SIZE (Size);\r
+ PoolHdr->Available = FALSE;\r
+ *Buffer = PoolHdr + 1;\r
+ return Status;\r
+ }\r
+\r
+ Size = (Size + MIN_POOL_SIZE - 1) >> MIN_POOL_SHIFT;\r
+ PoolIndex = HighBitSet32 ((UINT32)Size);\r
+ if ((Size & (Size - 1)) != 0) {\r
+ PoolIndex++;\r
+ }\r
+\r
+ Status = InternalAllocPoolByIndex (PoolIndex, &FreePoolHdr);\r
+ *Buffer = &FreePoolHdr->Header + 1;\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Frees pool.\r
+\r
+ @param Buffer The allocated pool entry to free.\r
+\r
+ @retval EFI_INVALID_PARAMETER Buffer is not a valid value.\r
+ @retval EFI_SUCCESS Pool successfully freed.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SmmFreePool (\r
+ IN VOID *Buffer\r
+ )\r
+{\r
+ FREE_POOL_HEADER *FreePoolHdr;\r
+\r
+ if (Buffer == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ FreePoolHdr = (FREE_POOL_HEADER*)((POOL_HEADER*)Buffer - 1);\r
+ ASSERT (!FreePoolHdr->Header.Available);\r
+\r
+ if (FreePoolHdr->Header.Size > MAX_POOL_SIZE) {\r
+ ASSERT (((UINTN)FreePoolHdr & EFI_PAGE_MASK) == 0);\r
+ ASSERT ((FreePoolHdr->Header.Size & EFI_PAGE_MASK) == 0);\r
+ return SmmFreePages (\r
+ (EFI_PHYSICAL_ADDRESS)(UINTN)FreePoolHdr,\r
+ EFI_SIZE_TO_PAGES (FreePoolHdr->Header.Size)\r
+ );\r
+ }\r
+ return InternalFreePoolByIndex (FreePoolHdr);\r
+}\r
--- /dev/null
+/** @file\r
+ SMI management.\r
+\r
+ Copyright (c) 2009 - 2010, Intel Corporation. All rights reserved.<BR>\r
+ This program and the accompanying materials are licensed and made available \r
+ under the terms and conditions of the BSD License which accompanies this \r
+ distribution. The full text of the license may be found at \r
+ http://opensource.org/licenses/bsd-license.php \r
+\r
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, \r
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. \r
+\r
+**/\r
+\r
+#include "PiSmmCore.h"\r
+\r
+//\r
+// SMM_HANDLER - used for each SMM handler\r
+//\r
+\r
+#define SMI_ENTRY_SIGNATURE SIGNATURE_32('s','m','i','e')\r
+\r
+ typedef struct {\r
+ UINTN Signature;\r
+ LIST_ENTRY AllEntries; // All entries\r
+\r
+ EFI_GUID HandlerType; // Type of interrupt\r
+ LIST_ENTRY SmiHandlers; // All handlers\r
+} SMI_ENTRY;\r
+\r
+#define SMI_HANDLER_SIGNATURE SIGNATURE_32('s','m','i','h')\r
+\r
+ typedef struct {\r
+ UINTN Signature;\r
+ LIST_ENTRY Link; // Link on SMI_ENTRY.SmiHandlers\r
+ EFI_SMM_HANDLER_ENTRY_POINT2 Handler; // The smm handler's entry point\r
+ SMI_ENTRY *SmiEntry;\r
+} SMI_HANDLER;\r
+\r
+LIST_ENTRY mRootSmiHandlerList = INITIALIZE_LIST_HEAD_VARIABLE (mRootSmiHandlerList);\r
+LIST_ENTRY mSmiEntryList = INITIALIZE_LIST_HEAD_VARIABLE (mSmiEntryList);\r
+\r
+/**\r
+ Finds the SMI entry for the requested handler type.\r
+\r
+ @param HandlerType The type of the interrupt\r
+ @param Create Create a new entry if not found\r
+\r
+ @return SMI entry\r
+\r
+**/\r
+SMI_ENTRY *\r
+EFIAPI\r
+SmmCoreFindSmiEntry (\r
+ IN EFI_GUID *HandlerType,\r
+ IN BOOLEAN Create\r
+ )\r
+{\r
+ LIST_ENTRY *Link;\r
+ SMI_ENTRY *Item;\r
+ SMI_ENTRY *SmiEntry;\r
+\r
+ //\r
+ // Search the SMI entry list for the matching GUID\r
+ //\r
+ SmiEntry = NULL;\r
+ for (Link = mSmiEntryList.ForwardLink;\r
+ Link != &mSmiEntryList;\r
+ Link = Link->ForwardLink) {\r
+\r
+ Item = CR (Link, SMI_ENTRY, AllEntries, SMI_ENTRY_SIGNATURE);\r
+ if (CompareGuid (&Item->HandlerType, HandlerType)) {\r
+ //\r
+ // This is the SMI entry\r
+ //\r
+ SmiEntry = Item;\r
+ break;\r
+ }\r
+ }\r
+\r
+ //\r
+ // If the protocol entry was not found and Create is TRUE, then\r
+ // allocate a new entry\r
+ //\r
+ if ((SmiEntry == NULL) && Create) {\r
+ SmiEntry = AllocatePool (sizeof(SMI_ENTRY));\r
+ if (SmiEntry != NULL) {\r
+ //\r
+ // Initialize new SMI entry structure\r
+ //\r
+ SmiEntry->Signature = SMI_ENTRY_SIGNATURE;\r
+ CopyGuid ((VOID *)&SmiEntry->HandlerType, HandlerType);\r
+ InitializeListHead (&SmiEntry->SmiHandlers);\r
+\r
+ //\r
+ // Add it to SMI entry list\r
+ //\r
+ InsertTailList (&mSmiEntryList, &SmiEntry->AllEntries);\r
+ }\r
+ }\r
+ return SmiEntry;\r
+}\r
+\r
+/**\r
+ Manage SMI of a particular type.\r
+\r
+ @param HandlerType Points to the handler type or NULL for root SMI handlers.\r
+ @param Context Points to an optional context buffer.\r
+ @param CommBuffer Points to the optional communication buffer.\r
+ @param CommBufferSize Points to the size of the optional communication buffer.\r
+\r
+ @retval EFI_SUCCESS Interrupt source was processed successfully but not quiesced.\r
+ @retval EFI_INTERRUPT_PENDING One or more SMI sources could not be quiesced.\r
+ @retval EFI_WARN_INTERRUPT_SOURCE_PENDING Interrupt source was not handled or quiesced.\r
+ @retval EFI_WARN_INTERRUPT_SOURCE_QUIESCED Interrupt source was handled and quiesced.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SmiManage (\r
+ IN CONST EFI_GUID *HandlerType,\r
+ IN CONST VOID *Context OPTIONAL,\r
+ IN OUT VOID *CommBuffer OPTIONAL,\r
+ IN OUT UINTN *CommBufferSize OPTIONAL\r
+ )\r
+{\r
+ LIST_ENTRY *Link;\r
+ LIST_ENTRY *Head;\r
+ SMI_ENTRY *SmiEntry;\r
+ SMI_HANDLER *SmiHandler;\r
+ BOOLEAN InterruptQuiesced;\r
+ EFI_STATUS Status;\r
+ \r
+ if (HandlerType == NULL) {\r
+ //\r
+ // Root SMI handler\r
+ //\r
+ Status = EFI_WARN_INTERRUPT_SOURCE_PENDING;\r
+\r
+ Head = &mRootSmiHandlerList;\r
+ for (Link = Head->ForwardLink; Link != Head; Link = Link->ForwardLink) {\r
+ SmiHandler = CR (Link, SMI_HANDLER, Link, SMI_HANDLER_SIGNATURE);\r
+\r
+ Status = SmiHandler->Handler (\r
+ (EFI_HANDLE) SmiHandler,\r
+ Context,\r
+ CommBuffer,\r
+ CommBufferSize\r
+ );\r
+ if (Status == EFI_SUCCESS || Status == EFI_INTERRUPT_PENDING) {\r
+ return Status;\r
+ }\r
+ }\r
+ return Status;\r
+ }\r
+\r
+ //\r
+ // Non-root SMI handler\r
+ //\r
+ SmiEntry = SmmCoreFindSmiEntry ((EFI_GUID *) HandlerType, FALSE);\r
+ if (SmiEntry == NULL) {\r
+ //\r
+ // There is no handler registered for this interrupt source\r
+ //\r
+ return EFI_WARN_INTERRUPT_SOURCE_PENDING;\r
+ }\r
+\r
+ InterruptQuiesced = FALSE;\r
+ Head = &SmiEntry->SmiHandlers;\r
+ for (Link = Head->ForwardLink; Link != Head; Link = Link->ForwardLink) {\r
+ SmiHandler = CR (Link, SMI_HANDLER, Link, SMI_HANDLER_SIGNATURE);\r
+\r
+ Status = SmiHandler->Handler (\r
+ (EFI_HANDLE) SmiHandler,\r
+ Context,\r
+ CommBuffer,\r
+ CommBufferSize\r
+ );\r
+\r
+ switch (Status) {\r
+ case EFI_INTERRUPT_PENDING:\r
+ //\r
+ // If a handler returns EFI_INTERRUPT_PENDING, the interrupt could not be\r
+ // quiesced, then no additional handlers will be processed,\r
+ // and EFI_INTERRUPT_PENDING will be returned\r
+ //\r
+ return EFI_INTERRUPT_PENDING;\r
+\r
+ case EFI_SUCCESS:\r
+ //\r
+ // If handler return EFI_SUCCESS, the interrupt was handled and quiesced,\r
+ // no other handlers should still be called,\r
+ // and EFI_WARN_INTERRUPT_SOURCE_QUIESCED will be returned\r
+ //\r
+ return EFI_WARN_INTERRUPT_SOURCE_QUIESCED;\r
+\r
+ case EFI_WARN_INTERRUPT_SOURCE_QUIESCED:\r
+ //\r
+ // If at least one of the handlers report EFI_WARN_INTERRUPT_SOURCE_QUIESCED,\r
+ // then this function will return EFI_WARN_INTERRUPT_SOURCE_QUIESCED\r
+ //\r
+ InterruptQuiesced = TRUE;\r
+ break;\r
+\r
+ default:\r
+ break;\r
+ }\r
+ }\r
+\r
+ if (InterruptQuiesced) {\r
+ Status = EFI_WARN_INTERRUPT_SOURCE_QUIESCED;\r
+ } else {\r
+ //\r
+ // If no handler report EFI_WARN_INTERRUPT_SOURCE_QUIESCED, then this\r
+ // function will return EFI_INTERRUPT_PENDING\r
+ //\r
+ Status = EFI_INTERRUPT_PENDING;\r
+ }\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Registers a handler to execute within SMM.\r
+\r
+ @param Handler Handler service funtion pointer.\r
+ @param HandlerType Points to the handler type or NULL for root SMI handlers.\r
+ @param DispatchHandle On return, contains a unique handle which can be used to later unregister the handler function.\r
+\r
+ @retval EFI_SUCCESS Handler register success.\r
+ @retval EFI_INVALID_PARAMETER Handler or DispatchHandle is NULL.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SmiHandlerRegister (\r
+ IN EFI_SMM_HANDLER_ENTRY_POINT2 Handler,\r
+ IN CONST EFI_GUID *HandlerType OPTIONAL,\r
+ OUT EFI_HANDLE *DispatchHandle\r
+ )\r
+{\r
+ SMI_HANDLER *SmiHandler;\r
+ SMI_ENTRY *SmiEntry;\r
+ LIST_ENTRY *List;\r
+\r
+ if (Handler == NULL || DispatchHandle == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ SmiHandler = AllocateZeroPool (sizeof (SMI_HANDLER));\r
+ if (SmiHandler == NULL) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ SmiHandler->Signature = SMI_HANDLER_SIGNATURE;\r
+ SmiHandler->Handler = Handler;\r
+\r
+ if (HandlerType == NULL) {\r
+ //\r
+ // This is root SMI handler\r
+ //\r
+ SmiEntry = NULL;\r
+ List = &mRootSmiHandlerList;\r
+ } else {\r
+ //\r
+ // None root SMI handler\r
+ //\r
+ SmiEntry = SmmCoreFindSmiEntry ((EFI_GUID *) HandlerType, TRUE);\r
+ if (SmiEntry == NULL) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ List = &SmiEntry->SmiHandlers;\r
+ }\r
+\r
+ SmiHandler->SmiEntry = SmiEntry;\r
+ InsertTailList (List, &SmiHandler->Link);\r
+\r
+ *DispatchHandle = (EFI_HANDLE) SmiHandler;\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Unregister a handler in SMM.\r
+\r
+ @param DispatchHandle The handle that was specified when the handler was registered.\r
+\r
+ @retval EFI_SUCCESS Handler function was successfully unregistered.\r
+ @retval EFI_INVALID_PARAMETER DispatchHandle does not refer to a valid handle.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SmiHandlerUnRegister (\r
+ IN EFI_HANDLE DispatchHandle\r
+ )\r
+{\r
+ SMI_HANDLER *SmiHandler;\r
+ SMI_ENTRY *SmiEntry;\r
+\r
+ SmiHandler = (SMI_HANDLER *) DispatchHandle;\r
+\r
+ if (SmiHandler == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ if (SmiHandler->Signature != SMI_HANDLER_SIGNATURE) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ SmiEntry = SmiHandler->SmiEntry;\r
+\r
+ RemoveEntryList (&SmiHandler->Link);\r
+ FreePool (SmiHandler);\r
+\r
+ if (SmiEntry == NULL) {\r
+ //\r
+ // This is root SMI handler\r
+ //\r
+ return EFI_SUCCESS;\r
+ }\r
+\r
+ if (IsListEmpty (&SmiEntry->SmiHandlers)) {\r
+ //\r
+ // No handler registered for this interrupt now, remove the SMI_ENTRY\r
+ //\r
+ RemoveEntryList (&SmiEntry->AllEntries);\r
+\r
+ FreePool (SmiEntry);\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r