mirror of https://github.com/acidanthera/audk.git
271 lines
7.5 KiB
C
271 lines
7.5 KiB
C
/** @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 - 2018, Intel Corporation. All rights reserved.<BR>
|
|
SPDX-License-Identifier: BSD-2-Clause-Patent
|
|
|
|
**/
|
|
|
|
|
|
#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);
|
|
}
|