UEFI Console Splitter 2nd

来源:互联网 发布:网络空间独立宣言 编辑:程序博客网 时间:2024/06/16 01:22

为了巩固对 Console Splitter 这只driver 认知上的巩固,这么篇文章我们会写一个虚拟的简单的输入设备。具体的思路是以下几点:

  • 经过上篇文章对Splitter 这只driver 的分析,我们知道,如果想让Splitter 能够管理一个device,那么这个device至少应该安装了gEfiConsoleInDeviceGuid && gEfiSimpleTextInProtocolGuid 所以我们应该让我们这个device被安装上这两个GUID。
  • gEfiSimpleTextInProtocolGuid 是每个driver 独立实现自己的protocol 所以这个GUID我们可以自己手动给安装。但是gEfiConsoleInDeviceGuid 是另外一只driver (ConPlatform.c )给自己能support的device handle上安装的GUID ,那么ConPlatromr.c 这只driver support 哪些device呢 。我们上篇也做过简单地介绍就ConPlatform 这只driver 它能够管理的device 是这些device handle 上安装了 gEfiSimpleTextInProtocolGuid, gDevicePathProtocolGuid, 并且该device的path 记录ConIn在这个变量里(热插拔设备除外)。
  • 因为在应用程序里,我们用ReadKeyStorke 和 WaitForKey,所以我们要给这个虚拟device 实例化一个SimpleTextInProtocol 。为了让程序尽量简单,我们只是不停的汇报一个字母‘A’。

经过上述分析,我们知道我们这个device 上要手动安装一个SimpleTextInProtocol 和 EfiDevicePathProtocol (这个path 必须在ConIn 里,或者是一个热插拔的device path)然后我们EDK 里的ConPlatform.c 这只driver 就会给这个虚拟的device 安装一个gEfiConsoleInDeviceGuid 最后,这个device就会满足我们Con Splitter.c 这只driver support函数的要求,我们虚拟device 就会动起来。可能说起来会有点啰嗦,看个流程图就一目了然了。
(待画,第一次用CSDN 不太会画流程图)

看code

#include <Uefi.h>#include <Library/UefiBootServicesTableLib.h>#include <Library/DebugLib.h>#include <Library/UefiLib.h>#include <Library/BaseLib.h>#include <Protocol/SimpleTextIn.h>#include <Library/UefiDriverEntryPoint.h>#include <Protocol/DevicePath.h>#include <Library/DevicePathLib.h>#include "NonDriver.h"VHidDev   *gVirHidDev;EFI_KEY   Buffer[10];UINT8     Keyflag;VOIDEFIAPICallBack (    IN  EFI_EVENT  Event,    IN  VOID       *Context    ){  gBS->SignalEvent (Event);}STATIC vPath_T gvHidDevPath = {  {    {      MESSAGING_DEVICE_PATH,      MSG_USB_WWID_DP,      {        (UINT8) (sizeof (USB_WWID_DEVICE_PATH)),        (UINT8) (sizeof (USB_WWID_DEVICE_PATH) >> 8)      }    },    0x01,    0xaa,    0xbb  },  {    END_DEVICE_PATH_TYPE,    END_ENTIRE_DEVICE_PATH_SUBTYPE,    {      (UINT8) (END_DEVICE_PATH_LENGTH),         (UINT8) (END_DEVICE_PATH_LENGTH >> 8)       }  }};EFI_STATUSEFIAPIvReadKeyStroke (  IN  EFI_SIMPLE_TEXT_INPUT_PROTOCOL    *This,  OUT EFI_INPUT_KEY                     *Key  ){  Key->UnicodeChar = L'A';  return EFI_SUCCESS;    }EFI_STATUSEFIAPITestNonDriver (    IN EFI_HANDLE          ImageHandle,    IN EFI_SYSTEM_TABLE    *SystemTable    ){  EFI_STATUS       Status;  DEBUG((EFI_D_INFO, " NonDriver Test Start\n"));  Status = gBS->AllocatePool (                 EfiBootServicesData,                 sizeof (VHidDev),                 (void **)&gVirHidDev                 );  if (EFI_ERROR (Status)) {    DEBUG((EFI_D_INFO, "allocate pool %r\n", Status));    return EFI_OUT_OF_RESOURCES;  }  gVirHidDev->vConIn.Reset = NULL;  gVirHidDev->vConIn.ReadKeyStroke = vReadKeyStroke;  gVirHidDev->Handle = NULL;  Status = gBS->CreateEvent (                   EVT_NOTIFY_WAIT,                   TPL_NOTIFY,                   CallBack,                   NULL,                   &gVirHidDev->vConIn.WaitForKey                   );  if (EFI_ERROR(Status)) {    DEBUG((EFI_D_ERROR, "Create Event %r\n", Status));    return Status;  }  Status = gBS->InstallMultipleProtocolInterfaces(                  &gVirHidDev->Handle,                  &gEfiDevicePathProtocolGuid,                  &gvHidDevPath,                  &gEfiSimpleTextInProtocolGuid,                  &gVirHidDev->vConIn,                  NULL                  );  return EFI_SUCCESS;}

其实有了上述分析,我们看code就会很容易,简单地分析一下。首先我们先给我们的虚拟device分配一个地址空间,我们会实例化一个SimpleTextInProtocol在ReadKeyStroke函数里只是简单地向Splitter driver 汇报字母A。然后我们会创建一个Event,上篇我们提到过,如果我们想读用户输入,我们会把程序阻塞住,直到这个Event被Signal起来。所以我们在虚拟device里把这个Event的Callback只是简单地实现一个Signal Event,好让用户程序结束阻塞,继续运行。最后我们会给这个device安装一个device path protocol 好让蒙过ConPlatform.c 这只driver检查那一关,为了简单,我们把这个device模拟成一个USB WWID 那么就不会对这个device path 和 ConIn 记录里的path 进行比对。 主函数大概就是这样,如果想下载code,下面是链接地址

程序下载地址

最后我们可以把这个虚拟device 加入EDK source code 里,我这边是用Linux 下的模拟器,所以把.inf 档放进Emulator.dsc 和 Emulator.fdf 里,然后开虚拟我们就会看到屏幕上一直出现字符A。

这里写图片描述

0 0
原创粉丝点击