12

UEFI开发探索66- YIE001开发板(02 UEFI驱动)

 4 years ago
source link: http://yiiyee.cn/blog/2021/01/13/uefi%e5%bc%80%e5%8f%91%e6%8e%a2%e7%b4%a266-yie001%e5%bc%80%e5%8f%91%e6%9d%bf%ef%bc%8802-uefi%e9%a9%b1%e5%8a%a8%ef%bc%89/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

UEFI开发探索66- YIE001开发板(02 UEFI驱动)

请保留-> 【原文:  https://blog.csdn.net/luobing4365 和 http://yiiyee.cn/blog/author/luobing/】

在之前的篇章中,或多或少地介绍了一些UEFI驱动的内容。我们要在YIE001上实现的PCIE Option ROM,实际上就是一种UEFI驱动。这点与Legacy BIOS的Option ROM完全不同,在系列博客的第34篇中,可以知道Legacy Option ROM完全是并行于BIOS的。

当然,这样描述Legacy Option ROM也不准确,Legacy BIOS与Legacy Option ROM只是遵循一个调用标准,双方并不干涉。而UEFI Option ROM则是完全遵循UEFI驱动模型的,甚至可以用它安装Protocol,供其他程序使用。

在实际进行编程前,必须理清UEFI驱动的结构和编写方法。预计将用3篇左右的篇幅,把这些内容介绍清楚,以方便对YIE001代码的调试和测试。

1 UEFI驱动分类

从类型上来看,UEFI驱动可以分为启动服务驱动(Boot Service Drivers)和运行时驱动(Runtime Drivers)。两者的区别在于,在UEFI BIOS的RT阶段OS Loader获得平台控制权后,运行时驱动仍然有效。

从功能上划分,UEFI驱动可以分为以下类别。

1) 符合UEFI驱动模型(UEFI Driver Model)的驱动。这类驱动包括总线驱动(Bus Drivers)、设备驱动(Device Drivers)和混合驱动(Hybrid Drivers),一般用来驱动对应的硬件设备;

2) 服务型驱动(Service Drivers)。这类驱动不管理任何设备,一般用来产生Protocol;

3) 初始化驱动(Initializing Drivers)。它不会产生任何句柄,也不增加任何Protocol到系统数据库,主要用来进行一些初始化操作,执行完就会从系统内存中卸载;

4) 根桥型驱动(Root Bridge Drivers)。它用来初始化平台上的根桥控制器,并产生一个设备地址Protocol,以及访问总线设备的Protocol,一般由总线驱动用来访问设备。在7.1节中,我们使用的支持访问PCI/PCIe设备的EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL,就是一个典型的例子。

符合UEFI驱动模型的驱动和服务型驱动,在实际项目中运用较多,其他两种则使用较少。本篇主要介绍下服务型驱动。

2 服务型驱动的功能

在前面的探索中,大量使用了Protocol构建各种应用。也在某些篇章了解了Protocol的基本运作方式,特别是42、43中,构建了完整的服务型驱动和测试程序。

本篇介绍的服务型驱动,和之前的并没有太大区别。主要是为了将来阅读方便,以YIE001的名义,将服务型驱动和UEFI驱动的其他内容整理在一起了。闲言少叙,下面进入正篇。

UEFI中,Protocol可算是最重要的概念了。对它的理解和使用,贯穿了整个UEFI探索系列博客。Protocol由各类驱动提供,在这其中,服务型驱动不需遵循UEFI驱动模型,也不需要管理任何硬件设备。其主要的目的就是用来产生一个或多个Protocol,安装到相应的服务句柄上。

Protocol由一个128位的全局唯一ID(GUID)和Protocol接口的结构体组成,结构体中包含了Protocol的接口函数,可以用来访问对应的设备。在UEFI的系统中,其句柄数据库维护了设备句柄、Protocol接口和镜像句柄、控制器句柄之间的关系。对于Protocol接口的增加、移除或者替代,都可以在句柄数据库中跟踪到,如图1所示。

图1 句柄数据库

在之前的篇章中,曾经给出过启动服务中处理Protocol的函数,主要分为使用Protocol和产生Protocol的接口函数(UEFI开发探索42)。InstallProcotoclInterface()和InstallMultipleProtocolInterfaces()函数,用于将单个或多个Protocol安装到设备控制器上;UninstallProtocolInterface()和UninstallMultipleProtocolInterfaces()用于卸载单个和多个Protocol。

重新安装Protocol接口的函数为ReinstallProtocolInterface(),通常用在设备更换、设备路径改变或更新的时候。比如产生网络Protocol的UEFI驱动,在使用StationAddress()接口函数,修改网络接口的MAC地址时,就需要用到此函数。

3服务型驱动的框架代码搭建

所实现的代码,在第43篇的例子上做了一些改动,取名为ServiceDrv。

实现服务型驱动框架,主要包括修改INF文件,以及安装构建的示例Protocol。修改INF文件主要包括:

1)INF文件的[Defines] Section下,将MODULE_TYPE设置为UEFI_DRIVER或DXE_DRIVER;

2)[Defines] Section下的BASE_NAME改为示例工程的主函数入口ServiceDrv;

3)[LibraryClasses] Seciton中加入UefiDriverEntryPoint。

为了安装我们构建的Protocol,也即EFI_MYSAMPLE_PROTOCOL,首先需要对Protocl对应的接口函数进行初始化。由于需要在示例中用到私有数据,所需初始化的Protocol实例,直接使用了MY_PRIVATE_DATA型全局变量gMyData的成员变量myProtocol,如示例1所示。

【示例1初始化需安装的Protocol

EFI_STATUS MySampleProtocolInit(VOID)
{
    MY_PRIVATE_DATA *mydata =&gMyData;      
mydata->Signature = MY_PRIVATE_DATA_SIGNATURE;
    mydata->myProtocol.Revision=0x101;                  //Protocol版本
    mydata->myProtocol.MySample_In=MySample_In;       //第一个接口函数
    mydata->myProtocol.MySample_Out=MySample_Out;     //第二个接口函数
    mydata->myProtocol.MySample_DoSth=MySample_DoSth;//第三个接口函数
return EFI_SUCCESS
}

完成初始化工作后,就可以使用之前介绍的启动服务的接口函数InstallProtocolInterface()安装EFI_MYSAMPLE_PROTOCOL了。如示例2所示,Protocol安装在驱动的ImageHandle上了。

【示例2】安装Protocol

EFI_STATUS EFIAPI MyProtocolEntry (
  IN EFI_HANDLE                   ImageHandle,
  IN EFI_SYSTEM_TABLE             *SystemTable
  )

EFI_STATUS                      Status;
  MySampleProtocolInit(); 
Status = gBS->InstallProtocolInterface (
            &ImageHandle,                 //镜像句柄
            &gEfiMYSampleProtocolGUID ,//Protocol的GUID
            EFI_NATIVE_INTERFACE,        //接口类型
            &gMyData.myProtocol          //安装的Protocol实例
            );
  return Status;
}

4 编译

UEFI驱动的编译方法,与UEFI应用编译的方法是一样的。本节的示例工程ServiceDrv使用了包RobinPkg进行编译,首先在RobinPkg.dsc的[Components] Section中添加编译路径:

RobinPkg/Drivers/ServiceDrv/ServiceDrv.inf

然后启动VS2015 x86 Native Tools Command Prompt,进入EDK2的工作目录,执行edksetup.bat。启动UEFI的编译环境后,运行如下命令即可编译IA32的UEFI驱动。

C:\UEFIWorkspace>build -t VS2015x86 -p RobinPkg\RobinPkg.dsc \
-m RobinPkg\Drivers\ServiceDrv\ServiceDrv.inf -a IA32

编译出来的目标程序,也是efi格式的文件。不过,UEFI驱动不能像UEFI应用一样,直接在模拟器中运行,必须借助于UEFI Shell命令来加载。

如何测试服务型驱动,以及如何使用服务型驱动提供的Protocol,在下一篇继续讨论。

Gitee地址:https://gitee.com/luobing4365/uefi-exolorer
项目代码位于:/FF RobinPkg/ RobinPkg /Drivers/ServiceDrv

36 total views, 3 views today


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK