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