--- /dev/null
+/** @file\r
+ Entry point to a EFI/DXE driver.\r
+\r
+Copyright (c) 2006, Intel Corporation<BR>\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
+\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
+EFI_BOOT_SERVICES *mBS;\r
+\r
+/**\r
+ This function returns the size, in bytes, \r
+ of the device path data structure specified by DevicePath.\r
+ If DevicePath is NULL, then 0 is returned.\r
+\r
+ @param DevicePath A pointer to a device path data structure.\r
+\r
+ @return The size of a device path in bytes.\r
+\r
+**/\r
+STATIC\r
+UINTN\r
+EFIAPI\r
+SmmGetDevicePathSize (\r
+ IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePath\r
+ )\r
+{\r
+ CONST EFI_DEVICE_PATH_PROTOCOL *Start;\r
+\r
+ if (DevicePath == NULL) {\r
+ return 0;\r
+ }\r
+\r
+ //\r
+ // Search for the end of the device path structure\r
+ //\r
+ Start = DevicePath;\r
+ while (!EfiIsDevicePathEnd (DevicePath)) {\r
+ DevicePath = EfiNextDevicePathNode (DevicePath);\r
+ }\r
+\r
+ //\r
+ // Compute the size and add back in the size of the end device path structure\r
+ //\r
+ return ((UINTN) DevicePath - (UINTN) Start) + sizeof (EFI_DEVICE_PATH_PROTOCOL);\r
+}\r
+\r
+/**\r
+ This function appends the device path SecondDevicePath\r
+ to every device path instance in FirstDevicePath. \r
+\r
+ @param FirstDevicePath A pointer to a device path data structure.\r
+ \r
+ @param SecondDevicePath A pointer to a device path data structure.\r
+\r
+ @return A pointer to the new device path is returned.\r
+ NULL is returned if space for the new device path could not be allocated from pool.\r
+ It is up to the caller to free the memory used by FirstDevicePath and SecondDevicePath\r
+ if they are no longer needed.\r
+\r
+**/\r
+EFI_DEVICE_PATH_PROTOCOL *\r
+EFIAPI\r
+SmmAppendDevicePath (\r
+ IN CONST EFI_DEVICE_PATH_PROTOCOL *FirstDevicePath,\r
+ IN CONST EFI_DEVICE_PATH_PROTOCOL *SecondDevicePath\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINTN Size;\r
+ UINTN Size1;\r
+ UINTN Size2;\r
+ EFI_DEVICE_PATH_PROTOCOL *NewDevicePath;\r
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath2;\r
+\r
+ ASSERT (FirstDevicePath != NULL && SecondDevicePath != NULL);\r
+\r
+ //\r
+ // Allocate space for the combined device path. It only has one end node of\r
+ // length EFI_DEVICE_PATH_PROTOCOL\r
+ //\r
+ Size1 = SmmGetDevicePathSize (FirstDevicePath);\r
+ Size2 = SmmGetDevicePathSize (SecondDevicePath);\r
+ Size = Size1 + Size2 - sizeof (EFI_DEVICE_PATH_PROTOCOL);\r
+\r
+ Status = mBS->AllocatePool (EfiBootServicesData, Size, (VOID **) &NewDevicePath);\r
+\r
+ if (EFI_SUCCESS == Status) {\r
+ mBS->CopyMem ((VOID *) NewDevicePath, (VOID *) FirstDevicePath, Size1);\r
+ //\r
+ // Over write Src1 EndNode and do the copy\r
+ //\r
+ DevicePath2 = (EFI_DEVICE_PATH_PROTOCOL *) ((CHAR8 *) NewDevicePath + (Size1 - sizeof (EFI_DEVICE_PATH_PROTOCOL)));\r
+ mBS->CopyMem ((VOID *) DevicePath2, (VOID *) SecondDevicePath, Size2);\r
+ }\r
+\r
+ return NewDevicePath;\r
+}\r
+\r
+/**\r
+ Unload function that is registered in the LoadImage protocol. It un-installs\r
+ protocols produced and deallocates pool used by the driver. Called by the core\r
+ when unloading the driver.\r
+\r
+ @param ImageHandle ImageHandle of the unloaded driver\r
+\r
+ @return Status of the ProcessModuleUnloadList.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+_DriverUnloadHandler (\r
+ EFI_HANDLE ImageHandle\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+\r
+ //\r
+ // Call the unload handlers for all the modules\r
+ //\r
+ Status = ProcessModuleUnloadList (ImageHandle);\r
+\r
+ //\r
+ // If the driver specific unload handler does not return an error, then call all of the\r
+ // library destructors. If the unload handler returned an error, then the driver can not be\r
+ // unloaded, and the library destructors should not be called\r
+ //\r
+ if (!EFI_ERROR (Status)) {\r
+ ProcessLibraryDestructorList (ImageHandle, gST);\r
+ }\r
+\r
+ //\r
+ // Return the status from the driver specific unload handler\r
+ //\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Enrty point to DXE SMM Driver.\r
+\r
+ @param ImageHandle ImageHandle of the loaded driver.\r
+ @param SystemTable Pointer to the EFI System Table.\r
+\r
+ @retval EFI_SUCCESS One or more of the drivers returned a success code.\r
+ @retval !EFI_SUCESS The return status from the last driver entry point in the list.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+_ModuleEntryPoint (\r
+ IN EFI_HANDLE ImageHandle,\r
+ IN EFI_SYSTEM_TABLE *SystemTable\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_LOADED_IMAGE_PROTOCOL *LoadedImage;\r
+ EFI_SMM_BASE_PROTOCOL *SmmBase;\r
+ BOOLEAN InSmm;\r
+ EFI_DEVICE_PATH_PROTOCOL *CompleteFilePath;\r
+ EFI_DEVICE_PATH_PROTOCOL *ImageDevicePath;\r
+ EFI_HANDLE Handle;\r
+\r
+ //\r
+ // Cache a pointer to the Boot Services Table \r
+ //\r
+ mBS = SystemTable->BootServices;\r
+\r
+ //\r
+ // Retrieve the Loaded Image Protocol\r
+ //\r
+ Status = mBS->HandleProtocol (\r
+ ImageHandle, \r
+ &gEfiLoadedImageProtocolGuid,\r
+ (VOID*)&LoadedImage\r
+ );\r
+ ASSERT_EFI_ERROR (Status);\r
+\r
+ //\r
+ // Retrieve SMM Base Protocol\r
+ //\r
+ Status = mBS->LocateProtocol (\r
+ &gEfiSmmBaseProtocolGuid, \r
+ NULL, \r
+ (VOID **) &SmmBase\r
+ );\r
+ ASSERT_EFI_ERROR (Status);\r
+\r
+ //\r
+ // Check to see if we are already in SMM\r
+ //\r
+ SmmBase->InSmm (SmmBase, &InSmm);\r
+\r
+ //\r
+ //\r
+ //\r
+ if (!InSmm) {\r
+ //\r
+ // Retrieve the Device Path Protocol from the DeviceHandle tha this driver was loaded from\r
+ //\r
+ Status = mBS->HandleProtocol (\r
+ LoadedImage->DeviceHandle, \r
+ &gEfiDevicePathProtocolGuid,\r
+ (VOID*)&ImageDevicePath\r
+ );\r
+ ASSERT_EFI_ERROR (Status);\r
+\r
+ //\r
+ // Build the full device path to the currently execuing image\r
+ //\r
+ CompleteFilePath = SmmAppendDevicePath (ImageDevicePath, LoadedImage->FilePath);\r
+\r
+ //\r
+ // Load the image in memory to SMRAM; it will automatically generate the\r
+ // SMI.\r
+ //\r
+ Status = SmmBase->Register (SmmBase, CompleteFilePath, NULL, 0, &Handle, FALSE);\r
+ ASSERT_EFI_ERROR (Status);\r
+ return Status;\r
+ }\r
+\r
+ //\r
+ // Call constructor for all libraries\r
+ //\r
+ ProcessLibraryConstructorList (ImageHandle, SystemTable);\r
+\r
+ //\r
+ // Optionally install the unload handler\r
+ //\r
+ if (_gDriverUnloadImageCount > 0) {\r
+ Status = mBS->HandleProtocol (\r
+ ImageHandle,\r
+ &gEfiLoadedImageProtocolGuid,\r
+ (VOID **)&LoadedImage\r
+ );\r
+ ASSERT_EFI_ERROR (Status);\r
+ LoadedImage->Unload = _DriverUnloadHandler;\r
+ }\r
+\r
+ //\r
+ // Call the list of driver entry points\r
+ //\r
+ Status = ProcessModuleEntryPointList (ImageHandle, SystemTable);\r
+ if (EFI_ERROR (Status)) {\r
+ ProcessLibraryDestructorList (ImageHandle, SystemTable);\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Enrty point wrapper of DXE SMM Driver.\r
+\r
+ @param ImageHandle ImageHandle of the loaded driver.\r
+ @param SystemTable Pointer to the EFI System Table.\r
+\r
+ @retval EFI_SUCCESS One or more of the drivers returned a success code.\r
+ @retval !EFI_SUCESS The return status from the last driver entry point in the list.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+EfiMain (\r
+ IN EFI_HANDLE ImageHandle,\r
+ IN EFI_SYSTEM_TABLE *SystemTable\r
+ )\r
+{\r
+ return _ModuleEntryPoint (ImageHandle, SystemTable);\r
+}\r