| /** @file | |
| This file implement EfiMain() for library class DxeSmmDriverEntryPoint. | |
| EfiMain() is common driver entry point for all SMM driver who uses DxeSmmDriverEntryPoint | |
| library class. | |
| Copyright (c) 2006, Intel Corporation<BR> | |
| All rights reserved. This program and the accompanying materials | |
| are licensed and made available under the terms and conditions of the BSD License | |
| which accompanies this distribution. The full text of the license may be found at | |
| http://opensource.org/licenses/bsd-license.php | |
| THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, | |
| WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. | |
| **/ | |
| #include <FrameworkSmm.h> | |
| #include <Protocol/LoadedImage.h> | |
| #include <Protocol/SmmBase.h> | |
| #include <Protocol/DevicePath.h> | |
| #include <Library/UefiDriverEntryPoint.h> | |
| #include <Library/UefiBootServicesTableLib.h> | |
| #include <Library/DebugLib.h> | |
| #include <Library/DevicePathLib.h> | |
| /** | |
| This function returns the size, in bytes, | |
| of the device path data structure specified by DevicePath. | |
| If DevicePath is NULL, then 0 is returned. | |
| @param DevicePath A pointer to a device path data structure. | |
| @return The size of a device path in bytes. | |
| **/ | |
| UINTN | |
| EFIAPI | |
| SmmGetDevicePathSize ( | |
| IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePath | |
| ) | |
| { | |
| CONST EFI_DEVICE_PATH_PROTOCOL *Start; | |
| if (DevicePath == NULL) { | |
| return 0; | |
| } | |
| // | |
| // Search for the end of the device path structure | |
| // | |
| Start = DevicePath; | |
| while (!IsDevicePathEnd (DevicePath)) { | |
| DevicePath = NextDevicePathNode (DevicePath); | |
| } | |
| // | |
| // Compute the size and add back in the size of the end device path structure | |
| // | |
| return ((UINTN) DevicePath - (UINTN) Start) + sizeof (EFI_DEVICE_PATH_PROTOCOL); | |
| } | |
| /** | |
| This function appends the device path SecondDevicePath | |
| to every device path instance in FirstDevicePath. | |
| @param FirstDevicePath A pointer to a device path data structure. | |
| @param SecondDevicePath A pointer to a device path data structure. | |
| @return A pointer to the new device path is returned. | |
| NULL is returned if space for the new device path could not be allocated from pool. | |
| It is up to the caller to free the memory used by FirstDevicePath and SecondDevicePath | |
| if they are no longer needed. | |
| **/ | |
| EFI_DEVICE_PATH_PROTOCOL * | |
| EFIAPI | |
| SmmAppendDevicePath ( | |
| IN CONST EFI_DEVICE_PATH_PROTOCOL *FirstDevicePath, | |
| IN CONST EFI_DEVICE_PATH_PROTOCOL *SecondDevicePath | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| UINTN Size; | |
| UINTN Size1; | |
| UINTN Size2; | |
| EFI_DEVICE_PATH_PROTOCOL *NewDevicePath; | |
| EFI_DEVICE_PATH_PROTOCOL *DevicePath2; | |
| ASSERT (FirstDevicePath != NULL && SecondDevicePath != NULL); | |
| // | |
| // Allocate space for the combined device path. It only has one end node of | |
| // length EFI_DEVICE_PATH_PROTOCOL | |
| // | |
| Size1 = SmmGetDevicePathSize (FirstDevicePath); | |
| Size2 = SmmGetDevicePathSize (SecondDevicePath); | |
| Size = Size1 + Size2 - sizeof (EFI_DEVICE_PATH_PROTOCOL); | |
| Status = gBS->AllocatePool (EfiBootServicesData, Size, (VOID **) &NewDevicePath); | |
| if (EFI_SUCCESS == Status) { | |
| // | |
| // CopyMem in gBS is used as this service should always be ready. We didn't choose | |
| // to use a BaseMemoryLib function as such library instance may have constructor. | |
| // | |
| gBS->CopyMem ((VOID *) NewDevicePath, (VOID *) FirstDevicePath, Size1); | |
| // | |
| // Over write Src1 EndNode and do the copy | |
| // | |
| DevicePath2 = (EFI_DEVICE_PATH_PROTOCOL *) ((CHAR8 *) NewDevicePath + (Size1 - sizeof (EFI_DEVICE_PATH_PROTOCOL))); | |
| gBS->CopyMem ((VOID *) DevicePath2, (VOID *) SecondDevicePath, Size2); | |
| } | |
| return NewDevicePath; | |
| } | |
| /** | |
| Unload function that is registered in the LoadImage protocol. It un-installs | |
| protocols produced and deallocates pool used by the driver. Called by the core | |
| when unloading the driver. | |
| @param ImageHandle ImageHandle of the unloaded driver | |
| @return Status of the ProcessModuleUnloadList. | |
| **/ | |
| EFI_STATUS | |
| EFIAPI | |
| _DriverUnloadHandler ( | |
| EFI_HANDLE ImageHandle | |
| ) | |
| { | |
| // | |
| // Call the unload handlers for all the modules. | |
| // | |
| // Note: All libraries were constructed in SMM space, | |
| // therefore we can not destruct them in Unload | |
| // handler. | |
| // | |
| return ProcessModuleUnloadList (ImageHandle); | |
| } | |
| /** | |
| Enrty point to DXE SMM Driver. | |
| @param ImageHandle ImageHandle of the loaded driver. | |
| @param SystemTable Pointer to the EFI System Table. | |
| @retval EFI_SUCCESS One or more of the drivers returned a success code. | |
| @retval !EFI_SUCESS The return status from the last driver entry point in the list. | |
| **/ | |
| EFI_STATUS | |
| EFIAPI | |
| _ModuleEntryPoint ( | |
| IN EFI_HANDLE ImageHandle, | |
| IN EFI_SYSTEM_TABLE *SystemTable | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| EFI_LOADED_IMAGE_PROTOCOL *LoadedImage; | |
| EFI_SMM_BASE_PROTOCOL *SmmBase; | |
| BOOLEAN InSmm; | |
| EFI_DEVICE_PATH_PROTOCOL *CompleteFilePath; | |
| EFI_DEVICE_PATH_PROTOCOL *ImageDevicePath; | |
| EFI_HANDLE Handle; | |
| // | |
| // Cache a pointer to the Boot Services Table | |
| // | |
| gBS = SystemTable->BootServices; | |
| // | |
| // Retrieve SMM Base Protocol | |
| // | |
| Status = gBS->LocateProtocol ( | |
| &gEfiSmmBaseProtocolGuid, | |
| NULL, | |
| (VOID **) &SmmBase | |
| ); | |
| ASSERT_EFI_ERROR (Status); | |
| // | |
| // Check to see if we are already in SMM | |
| // | |
| SmmBase->InSmm (SmmBase, &InSmm); | |
| // | |
| // | |
| // | |
| if (!InSmm) { | |
| // | |
| // Retrieve the Loaded Image Protocol | |
| // | |
| Status = gBS->HandleProtocol ( | |
| ImageHandle, | |
| &gEfiLoadedImageProtocolGuid, | |
| (VOID*)&LoadedImage | |
| ); | |
| ASSERT_EFI_ERROR (Status); | |
| // | |
| // Retrieve the Device Path Protocol from the DeviceHandle from which this driver was loaded | |
| // | |
| Status = gBS->HandleProtocol ( | |
| LoadedImage->DeviceHandle, | |
| &gEfiDevicePathProtocolGuid, | |
| (VOID*)&ImageDevicePath | |
| ); | |
| ASSERT_EFI_ERROR (Status); | |
| // | |
| // Build the full device path to the currently execuing image | |
| // | |
| CompleteFilePath = SmmAppendDevicePath (ImageDevicePath, LoadedImage->FilePath); | |
| // | |
| // Load the image in memory to SMRAM; it will automatically generate the | |
| // SMI. | |
| // | |
| Status = SmmBase->Register (SmmBase, CompleteFilePath, LoadedImage->ImageBase, 0, &Handle, FALSE); | |
| ASSERT_EFI_ERROR (Status); | |
| // | |
| // Optionally install the unload handler | |
| // | |
| if (_gDriverUnloadImageCount > 0) { | |
| Status = gBS->HandleProtocol ( | |
| ImageHandle, | |
| &gEfiLoadedImageProtocolGuid, | |
| (VOID **)&LoadedImage | |
| ); | |
| ASSERT_EFI_ERROR (Status); | |
| LoadedImage->Unload = _DriverUnloadHandler; | |
| } | |
| return Status; | |
| } | |
| // | |
| // Call constructor for all libraries | |
| // | |
| ProcessLibraryConstructorList (ImageHandle, SystemTable); | |
| // | |
| // Call the list of driver entry points | |
| // | |
| Status = ProcessModuleEntryPointList (ImageHandle, SystemTable); | |
| if (EFI_ERROR (Status)) { | |
| ProcessLibraryDestructorList (ImageHandle, SystemTable); | |
| } | |
| return Status; | |
| } | |
| /** | |
| Enrty point wrapper of DXE SMM Driver. | |
| @param ImageHandle ImageHandle of the loaded driver. | |
| @param SystemTable Pointer to the EFI System Table. | |
| @retval EFI_SUCCESS One or more of the drivers returned a success code. | |
| @retval !EFI_SUCESS The return status from the last driver entry point in the list. | |
| **/ | |
| EFI_STATUS | |
| EFIAPI | |
| EfiMain ( | |
| IN EFI_HANDLE ImageHandle, | |
| IN EFI_SYSTEM_TABLE *SystemTable | |
| ) | |
| { | |
| return _ModuleEntryPoint (ImageHandle, SystemTable); | |
| } |