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/
来源:爱影博客
文章版权归作者所有,未经允许请勿转载。

THE END
分享
二维码
< <上一篇
下一篇>>