UEFI Driver是如何执行的?
前言
前阵子换工作,去面试被问到一个问题,UEFI的Driver是如何执行的?我的脑袋一空,回答不出来。。
UEFI的流程我是追了好几次,但具体一点的问题却被我忽略了。后面找时间看了,这里记录一下。
认识 EFI_DRIVER_BINDING_PROTOCOL
按UEFI手册所述,开发EFI驱动是有规则的,这个规则称为UEFI Driver Model,其中用到一个用于管理驱动的Protocol为 EFI_DRIVER_BINDING_PROTOCOL。当需要使用一个控制器的时候,EFI Boot Service就会通过EFI_BOOT_SERVICES.ConnectController() 来查找匹配最佳的Driver,它是怎么“知道”最佳的呢?这就是EFI_DRIVER_BINDING_PROTOCOL需要实现的了,其具体定义如下:
typedef struct _EFI_DRIVER_BINDING_PROTOCOL {
EFI_DRIVER_BINDING_PROTOCOL_SUPPORTED Supported;
EFI_DRIVER_BINDING_PROTOCOL_START Start;
EFI_DRIVER_BINDING_PROTOCOL_STOP Stop;
UINT32 Version;
EFI_HANDLE ImageHandle;
EFI_HANDLE DriverBindingHandle;
} EFI_DRIVER_BINDING_PROTOCOL;
Supported这个成员便是用来测试此Driver是否支持该控制器,若支持,将返回EFI_SUCCESS,接着便可调用Start来执行驱动了,可参见CoreConnectSingleController函数的定义。
EFI_STATUS
CoreConnectSingleController (
IN EFI_HANDLE ControllerHandle,
IN EFI_HANDLE *ContextDriverImageHandles OPTIONAL,
IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL
)
{
...
//
// Loop through the sorted Driver Binding Protocol Instances in order, and see if
// any of the Driver Binding Protocols support the controller specified by
// ControllerHandle.
//
DriverBinding = NULL;
DriverFound = FALSE;
for (Index = 0; (Index < NumberOfSortedDriverBindingProtocols) && !DriverFound; Index++) {
if (SortedDriverBindingProtocols[Index] != NULL) {
DriverBinding = SortedDriverBindingProtocols[Index];
PERF_START (DriverBinding->DriverBindingHandle, "DB:Support:", NULL, 0);
Status = DriverBinding->Supported(
DriverBinding,
ControllerHandle,
RemainingDevicePath
);
PERF_END (DriverBinding->DriverBindingHandle, "DB:Support:", NULL, 0);
if (!EFI_ERROR (Status)) {
SortedDriverBindingProtocols[Index] = NULL;
DriverFound = TRUE;
//
// A driver was found that supports ControllerHandle, so attempt to start the driver
// on ControllerHandle.
//
PERF_START (DriverBinding->DriverBindingHandle, "DB:Start:", NULL, 0);
Status = DriverBinding->Start (
DriverBinding,
ControllerHandle,
RemainingDevicePath
);
PERF_END (DriverBinding->DriverBindingHandle, "DB:Start:", NULL, 0);
if (!EFI_ERROR (Status)) {
//
// The driver was successfully started on ControllerHandle, so set a flag
//
OneStarted = TRUE;
}
}
}
}
}
执行步骤
1.调用LoadImage()函数将EFI加载到内存。
2.判断该EFI文件是否为一个Driver,是则调用StartImage()函数将控制权转移到加载Image的入口点。
//
// Use LoadImage to get it into memory
//
Status = gBS->LoadImage(
FALSE,
gImageHandle,
FilePath,
NULL,
0,
&LoadedDriverHandle);
if (EFI_ERROR(Status)) {
ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_LOAD_NOT_IMAGE), gShellLevel2HiiHandle, FileName, Status);
} else {
//
// Make sure it is a driver image
//
Status = gBS->HandleProtocol (LoadedDriverHandle, &gEfiLoadedImageProtocolGuid, (VOID *) &LoadedDriverImage);
ASSERT (LoadedDriverImage != NULL);
if ( EFI_ERROR(Status)
|| ( LoadedDriverImage->ImageCodeType != EfiBootServicesCode
&& LoadedDriverImage->ImageCodeType != EfiRuntimeServicesCode)
){
ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_LOAD_NOT_DRIVER), gShellLevel2HiiHandle, FileName);
//
// Exit and unload the non-driver image
//
gBS->Exit(LoadedDriverHandle, EFI_INVALID_PARAMETER, 0, NULL);
Status = EFI_INVALID_PARAMETER;
}
}
if (!EFI_ERROR(Status)) {
//
// Start the image
//
Status = gBS->StartImage(LoadedDriverHandle, NULL, NULL);
if (EFI_ERROR(Status)) {
ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_LOAD_ERROR), gShellLevel2HiiHandle, FileName, Status);
} else {
ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_LOAD_LOADED), gShellLevel2HiiHandle, FileName, LoadedDriverImage->ImageBase, Status);
}
}
3.Connect。上面两步只是注册了一个Driver的ImageHandle,还未执行,且会不会有任何操作硬件的行为。Connect就是上文所提到的EFI_BOOT_SERVICES.ConnectController(),这一步就是查找匹配最佳驱动,然后调用Start执行。
版权声明:
作者:bin
链接:https://ay123.net/mystudy/uefi/1118/
来源:爱影博客
文章版权归作者所有,未经允许请勿转载。
ZZZZ
bin@ZZZZ
ZZZZ@bin
bin@ZZZZ