UEFI开发探索80- YIE001PCIe开发板(终篇 移植杂谈)

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

粗略地数了数,在博客中起码开发了近50个各类UEFI的演示程序。从理论上来说,大部分的代码,实际上都可以移植到YIE001开发板的Option ROM中。

只不过,YIE001所用的Ch366芯片,只支持窗口容量为32K的程序文件(当然,可以通过CH366的I2C两线串口进行扩展)。在这种情况下,对代码的编写设置了一定的限制。

本篇将以《UEFI编程实践》第6章的示例MyGuiFrame为蓝本,将其移植到YIE001的Option ROM框架代码中。此示例在仓库https://gitee.com/luobing4365/uefi-practical-programming.git的/ RobinPkg\Applications\MyGuiFrame下。(目前仍旧在整理中,还没有上传到仓库中,by robin,20210215)

1 Option ROM开发注意点

开发板YIE001主要用来进行Option ROM的开发,由于其本身所用的PCIE芯片CH366的限制,以及UEFI下Option ROM的本身限制,编写代码中还是有不少需要注意的地方。从我的角度出发,有以下点需要注意。

1) 减少生成文件的尺寸

毕竟YIE001的窗口容量只有32K,能够容纳的代码量有限。而且由于代码是用C语言编写的,很难精确地计算生成后文件的大小,必须要注意代码的大小。

因此,第一个规则是尽量使用EDK2提供的库函数。不要使用外部库,比如StdLib库等所提供的函数。使用封装过的库函数,会导致生成文件增大。在EDK2本身提供的库函数中,对内存处理、字符串处理等常用的函数,都有提供,尽量使用这些函数就行。

开发中,最占用空间的是图像、汉字字模等这些资源。一般来说,应该尽可能使用图形函数自己绘制图像,尽量少使用标准的图像进行显示。第二条规则是图形界面尽量简单,汉字库应该采用小字库的技术,也即用哪些汉字,就提取这些汉字的字库。

在之前的博客中,针对汉字的显示,以及图形和图像的显示,已经花了比较多的篇幅进行描述,可以去查看相应的篇章。

当然,也可以用一些无损压缩算法,对资源进行压缩。不过,个人认为在32K的空间内去压缩,也很难容纳较大的文件,有兴趣的技术同好可以试一下。

继续阅读“UEFI开发探索80- YIE001PCIe开发板(终篇 移植杂谈)”

58 total views, no views today

UEFI开发探索79- YIE001PCIe开发板(12 贪吃蛇)

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

上一篇开发的贪吃蛇,除了使用了启动服务所提供的键盘服务函数和延时函数外,主要使用了GraphicsOutput Protocol。

这使得代码无需进行修改,能很容易地移植到Option ROM的框架代码中。

本篇比较短,主要是介绍如何将UEFI应用Snake移植到YIE001的OpROM框架中。

移植的步骤如下。

1 代码整理

上一篇的示例工程Snake,实际上是在以前的RngEvent的示例上进行修改的。所需要的函数,仍旧是RngEvent中使用过的。

在Option ROM的框架示例中,新建C文件GreedSnake.c,把Snake中与贪吃蛇相关的函数全部拷贝进去。函数的功能在上一篇中都介绍了,包括:

VOID CreateMap(VOID);
VOID SnakeElement(UINT32 x,UINT32 y,UINT8 ColorIndex);
VOID InitSnake(VOID);
UINT8 BiteSelf();
VOID RandomFood(VOID);
UINT8 NotCrossWall(VOID);
UINT8 SnakeMove(VOID);
VOID GameRun(VOID);
VOID EndGame(VOID);
继续阅读“UEFI开发探索79- YIE001PCIe开发板(12 贪吃蛇)”

32 total views, no views today

UEFI开发探索78- YIE001PCIe开发板(11 贪吃蛇)

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

是时候实现个有趣的项目了,我选择在UEFI下实现贪吃蛇的游戏。

在Option ROM上直接实现,会很难调试。因此,我首先实现了贪吃蛇的UEFI应用。调试成功后,再将其移植到YIE001上。

1 贪吃蛇框架设计

考虑到代码最终是要移植到YIE001上,我尽量减少所用到的Protocol。主要是在平常开发中发现,不同的主机,在运行Option ROM时能支持的Protocol不大一致。比如在我目前测试用的平台上,就不支持SimplePointer的Protocol(鼠标)。

为简化对程序的思考,我们设计的贪吃蛇由一个个的矩形块组成。主要需要解决的问题包括:
(1) 地图的设计;
(2) 贪吃蛇的数据结构设计;
(3) 如何判断蛇撞墙;
(4) 如何判断蛇咬自身了;
(5) 随机出现蛇吃的食物。

实际上,解决了问题1和2,基本上后续的几个问题都迎刃而解了。

我们把地图、蛇和食物设计成如图1所示:

图1 贪吃蛇概念图
继续阅读“UEFI开发探索78- YIE001PCIe开发板(11 贪吃蛇)”

34 total views, no views today

UEFI开发探索77- YIE001PCIe开发板(10 拨动开关及显示)

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

YIE001上有两个拨动开关,可通过对应的寄存器位得知它们的状态,以实现交互控制。这篇尝试将按键获取,以及图形显示的编码。

1 获取拨动开关状态

UEFI开发探索第75篇中,列出了YIE001开发板的硬件资源。板子上提供了两个拨动开关,分别对应CH366的GPI1和GPI2。

对照CH366的芯片手册,定义其相关的宏定义:

#define CH366GPIR 0x02

#define KEY1 1   //GPI1 -- GPIR(IO基地址+02h) bit 1
#define KEY2 2   //GPI2 -- GPIR(IO基地址+02h) bit 2

在开发板YIE001上,拨动开关拨下(也即靠近PCIE槽的方向),对应的寄存器位值为0;拨上后对应的寄存器值为1。实现代码如下:

/**
  获取开发板YIE001上拨动开关的状态.
  
  @param  IoBaseAddress     YIE001上PCIE芯片的基地址
  @param  KeyNum            拨动开关的标识,Key1和Key2
  @retval 1           拨下(靠近PCIE插槽)
          0           拨上    
**/
UINT8 GetYIE001Key(UINT16 IoBaseAddress,UINT8 KeyNum)
{
  UINT8 regValue=0;

  regValue = IoRead8(MyIoBaseAddr+CH366GPIR);   //GPIR
  if(KeyNum == KEY1)
    regValue &=0x02;
  if(KeyNum == KEY2)
    regValue &=0x04;
  if(regValue)
    return 1;
  else
    return 0;
}
继续阅读“UEFI开发探索77- YIE001PCIe开发板(10 拨动开关及显示)”

29 total views, no views today

UEFI开发探索76- YIE001PCIe开发板(09 界面和键盘控制)

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

在开发板YIE001上进行开发,实际上和之前博客中开发UEFI应用,并没有本质的区别。所要注意的,是在Option ROM被BIOS加载之时,所用的UEFI机制以及Protocol是否能正常使用。

一般来说, GraphicsOutput Protocol和ConOut Protocol是可以正常使用的。但是,其他的Protocol,比如创建Event,就很难说了。笔者目前测试的机器上,在加载Option ROM时,创建的Event完全无法按照预期运作。而同样的代码,在同一机器的UEFI Shell下测试却是正常的。

本篇代码的编程过程如下。

1 图形支持和汉字支持

UEFI开发探索中的代码,特别是图形和汉字部分,是从我的开源项目Foxdisk中移植过来的。针对UEFI的机制,进行了改动。所以,在博客中的代码,同文件名的,其内容都差不多。

当然,随着各个课题的展开,代码也在不断地修改。甚至对我而言,也很难分清楚目前所用的文件是什么时候修改的。比如近期又在处理键盘的源文件中,添加了检查键盘按键的非阻塞处理函数CheckKey()。

我尽力维持一个松散而逻辑一致的结构,保证源文件可以直接使用。处理同一硬件的或者同一逻辑层的代码,基本上会在相同的源文件中。

以下列出了源文件的功能:

表1 源文件的功能

源文件引脚名称
Graphic.c, Graphic.h功能
Keyboard.c, Keyboard.h键盘处理
Window.c, Window.h界面相关的代码,比如背景设置等
Font.c, Font.h文字的显示,包括汉字、英文的显示
Common.c, Common.h提供各种Protocol实例,以及共用的一些函数
继续阅读“UEFI开发探索76- YIE001PCIe开发板(09 界面和键盘控制)”

37 total views, no views today

UEFI开发探索75- YIE001PCIe开发板(08 跑马灯实验)

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

在等待开发板YIE002焊接的日子里,回到YIE001上继续编程。

本篇准备完成跑马灯的实验,让YIE001上的4个LED灯跑起来。在开篇中,已经大致了解了YIE001上的硬件资源,为方便后续的编程,把这些资源先记录一下。

表1 开发板YIE001上硬件资源

开发板上名称引脚名称所属寄存器地址位址
LED1SW0控制寄存器CTLRIO基址+0x1bit 0
LED2SW1控制寄存器CTLRIO基址+0x1bit 1
LED3GPO辅助寄存器AUXRIO基址+0xf8bit 0
LED4RST0辅助寄存器AUXRIO基址+0xf8bit 7
KEY1GPI1输入寄存器GPIRIO基址+0x2bit 1
KEY2GPI2输入寄存器GPIRIO基址+0x2bit 2
I2CSDA输出寄存器GPORIO基址+0x0bit 0
I2CSCL输出寄存器GPORIO基址+0x0bit 1

需要注意的是,在CH366提供的芯片手册上,对于GPO和RST0所属的寄存器AUXR,给出的地址为IO基址+0x18。在实际使用中,此寄存器无法写入,经过测试发现应该是0xf8才对。

需要注意的是,在CH366提供的芯片手册上,对于GPO和RST0所属的寄存器AUXR,给出的地址为IO基址+0x18。在实际使用中,此寄存器无法写入,经过测试发现应该是0xf8才对。

下面介绍下跑马灯的编写以及测试过程。

继续阅读“UEFI开发探索75- YIE001PCIe开发板(08 跑马灯实验)”

33 total views, no views today

UEFI开发探索74- YIE002USB开发板(03 Windows编程)


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

在上篇学习了访问HID设备的Windows API之后,本篇开始着手进行Windows上位机的编程。所编写的程序名为UsbHID,其主要功能在上一篇中已经介绍过,下面介绍其编写过程。

1 添加库文件

我是使用MFC编写的上位机程序,开发工具为VS2015。建立基于Dialog的工程,并在对话框的CPP文件中,添加如下语句:

#include <hidsdi.h>
#include <setupapi.h>
#pragma comment(lib, "setupapi.lib")
#pragma comment(lib, "hid.lib")

所添加的头文件和库文件,包含UsbHID编程时需要用到的SetupDi系列函数,以及HID设备获取信息的函数和数据通信函数。早期的VS中,需要将库文件拷贝到工程的目录下,并手动添加库文件到工程中。

2 枚举HID设备

枚举HID设备包括获取HID类的GUID、查找所有HID设备、获取设备的信息等步骤。枚举过程中,用到了上篇博客所说的获取设备属性的若干函数。另外,也使用了几个SetupAPI函数,这几个函数的原型列举如下。

2.1 SetupAPI函数

返回一个设备信息集的句柄,包含本地计算机所请求的设备信息元素。

WINSETUPAPI HDEVINFO SetupDiGetClassDevsW(
  const GUID *ClassGuid,  //指向设备安装类或接口类的GUID指针,可以为空
  PCWSTR     Enumerator,  //指向空字符结尾的字符串
  HWND       hwndParent, //与设备实例相关的用户界面的顶级窗口句柄,可为空
  DWORD      Flags       //过滤设备用的标识
);

请求获得设备信息集内某个设备的信息

WINSETUPAPI BOOL SetupDiEnumDeviceInterfaces(
  HDEVINFO              DeviceInfoSet,   //指向设备信息集
  PSP_DEVINFO_DATA      DeviceInfoData,  //指向设备信息参数指针,可为空
  const GUID      *InterfaceClassGuid, //指向设备安装类或接口类的GUID指针
  DWORD           MemberIndex,   //位于设备信息集中的序号,以0起始
  PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData //回传的设备接口数据
);

请求获得设备的路径

WINSETUPAPI BOOL SetupDiGetDeviceInterfaceDetailW(
  HDEVINFO                           DeviceInfoSet,    //指向设备信息集
  PSP_DEVICE_INTERFACE_DATA          DeviceInterfaceData, //设备接口数据
  PSP_DEVICE_INTERFACE_DETAIL_DATA_W DeviceInterfaceDetailData,
  DWORD                              DeviceInterfaceDetailDataSize,
  PDWORD                             RequiredSize,
  PSP_DEVINFO_DATA                   DeviceInfoData
);

2.2 枚举HID设备的流程图

枚举HID设备时,将调用上述的函数,其流程如下图所示:

图1 枚举HID设备流程图
继续阅读“UEFI开发探索74- YIE002USB开发板(03 Windows编程)”

51 total views, no views today

UEFI开发探索73- YIE002USB开发板(02 Windows编程)

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

1 HID(人机接口设备)介绍

HID设备是USB规范中最早提出并支持的一种类设备,日常使用的键盘、鼠标等,都属于HID设备,是一种使用非常广泛的USB设备。

HID一开始为USB,但设计为与总线无关。它是为低延迟、低宽带的设备而设计的,在Windows 7以上,也支持蓝牙、I2C、GPIO等HID设备。

当然,我们主要还是研究跨平台的USB HID。

HID包含两个基本概念:报告描述符和报告。报告描述符描述设备支持的数据格式和含义,报告是在设备和软件客户端之间交换的实际数据。

上位机程序和HID设备通过报告来交换数据,上一篇中了解到,有三种报告类型:

输入报告(Input Report): 从HID设备发送到上位机程序的数据,通常在状态发生更改时发送;

输出报告(Output Report):从上位机程序发送到HID设备(比如键盘上的LED状态)数据;

功能报告(Feature Report):通常与配置信息相关。

在报告描述符中,可以定义每种类型的0个或多个报告,通常Input Report至少有一个。

不同的操作系统,对USB HID的支持方式不一样。Windows下有驱动Hidusb.sys支持HID传输,并提供了HID应用程序接口;UEFI的下使用EFI_USB_IO_PROTOCOL构建通信函数;而Linux下则可以使用libusb与HID设备通信。

2 Windows上位机程序UsbHID

为YIE002开发的Windows上位机,我命名为UsbHID。其界面图如图1所示。

图1 UsbHID界面
继续阅读“UEFI开发探索73- YIE002USB开发板(02 Windows编程)”

119 total views, no views today

UEFI开发探索72- YIE002USB开发板(01 开篇)

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

最近把USB的各个方面都研究了一遍,也在UEFI下实现了USB设备的访问。趁着这热乎劲,我计划把USB HID通信的知识,集合到一个新的开发板中进行介绍,也即我目前正在考虑设计的YIE002。

虽然YIE002的开发板还在规划中,我使用其他的开发板,已经打通了USB的通道了。只等着YIE002开发打样回来,把嵌固件代码移植过去就行了。

因为涉及到三个平台的开发(Windows、UEFI以及嵌入式平台),开发中需要记忆的知识点有点多。虽然现在对这些知识还比较清楚,时间长了后,有些细节容易忘记。因此,本篇开始进行YIE002的各类软件实验。

后续的篇章中,会交叉进行YIE001和YIE002的实验。两者的区别在于,YIE001主要是基于PCIE总线的,而YIE002则使用的是USB总线。

1 YIE002开发板计划

首先简单介绍下YIE002的开发板计划。 如图1所示,是我规划的YIE002开发板。

继续阅读“UEFI开发探索72- YIE002USB开发板(01 开篇)”

86 total views, no views today

UEFI开发探索71- YIE001PCIe开发板(07 OptionROM框架)


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

正在编辑新书《UEFI编程实践》(暂定名),现在介绍的内容,都整理到了第8章中了。

写书还是比较费神的,博客中可以随意行文,书稿则完全不能这么做。为了做到准确,有时为了确定一个数据,需要花费整个上午查找资料。期待今年上半年能够出版吧。

关于Option ROM,在第34、35和36篇中,已经描述过其历史和原理了。现在有了开发板,就可以在上面直接进行开发了。

1 开发Option ROM

代码是基于BlankDrv中的架构进行开发的,主要修改Supported()函数和Start()函数。Supported()函数中,判断是否为目标PCIE设备(也即是否为YIE001开发板);Start()函数中,添加界面代码以及访问硬件设备的代码。

示例1中给出了修改后的Supported()代码。

【示例1】Supported()函数

EFI_STATUS EFIAPI BlankDrvDriverBindingSupported (
  IN EFI_DRIVER_BINDING_PROTOCOL  *This,
  IN EFI_HANDLE                   Controller,
  IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath   OPTIONAL)
{
  EFI_STATUS Status;
  UINT16 MyVendorID, MyDeviceID;
EFI_PCI_IO_PROTOCOL  *PciIo;
  Status = gBS->OpenProtocol (Controller, &gEfiPciIoProtocolGuid,
                  (VOID **) &PciIo,This->DriverBindingHandle,
                  Controller,EFI_OPEN_PROTOCOL_BY_DRIVER);
  if (EFI_ERROR (Status)) return Status;
  Status = PciIo->Pci.Read(PciIo,EfiPciIoWidthUint16,0,1,&MyVendorID);
  if (EFI_ERROR (Status)) goto Done; //获取厂商ID
  Status = PciIo->Pci.Read(PciIo,EfiPciIoWidthUint16,2,1,&MyDeviceID);
  if (EFI_ERROR (Status)) goto Done; //获取设备ID
  Status = EFI_SUCCESS;
  //通过厂商ID和设备ID,判断是否为目标设备
  if (MyVendorID != CH366_VENDOR_ID || MyDeviceID != CH366_DEVICE_ID)
    Status = EFI_UNSUPPORTED;
  Done:  //关闭所用的Protocol
  gBS->CloseProtocol(Controller,&gEfiPciIoProtocolGuid,
         This->DriverBindingHandle,Controller);
  return Status;
}

在Supported()函数中,首先使用OpenProtocol()打开PCI I/O Protocol,如果打开失败,则返回EFI_UNSUPPORTED。然后使用得到的PCI I/O Protocol实例,从PCI设备的配置空间,获得厂商ID和设备ID。如果所得到的厂商ID及设备ID,与目标设备的一致,则返回EFI_SUCCESS,否则返回EFI_UNSUPPORTED。

继续阅读“UEFI开发探索71- YIE001PCIe开发板(07 OptionROM框架)”

89 total views, no views today

UEFI开发探索70- YIE001PCIe开发板(06 UEFI驱动)

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

前两篇中,我们了解了UEFI驱动模型的基本架构。 在此基础上,本篇将以一个有趣的UEFI驱动GopRotate,配合自己编写的测试用UEFI应用TestGopRotate,演示UEFI驱动的运行和测试过程。

1 UEFI驱动GopRotate

此示例由apop2提供,源码仓库为https://github.com/apop2/GopRotate。工程GopRotate包含5个源文件:ComponentName.c、GopRotate.c、GopRotate.h、GopRotateBlt.c和GopRotate.inf。这几个文件的作用分别如下:

1) ComponentName.c。实现了EFI_COMPONENT_NAME_PROTOCOL的接口函数,提供UEFI驱动的名称;
2)GopRotate.c。实现EFI_DRIVER_BINDING_PROTOCOL及其接口函数,安装EFI_DRIVER_BINDING_PROTOCOL和EFI_COMPONENT_NAME_PROTOCOL,以及实现UEFI Shell界面旋转功能的Protocol;
3) GopRotate.h。定义了驱动所需数据结构以及Protocol接口函数原型;
4) GopRotateBlt.c。实现UEFI Shell界面旋转的函数,以及提供此功能的Protocol接口函数的实现;
5) GopRotate.inf,编译UEFI驱动的INF文件。

为实现UEFI Shell界面的旋转,示例工程GopRotate主要做了以下工作:

  • 找到安装了EFI_GRAPHICS_OUTPUT_PROTOCOL的控制器,并且不能是虚拟设备;
  • 对EFI_GRAPHICS_OUTPUT_PROTOCOL的Blt()接口函数进行替换,更换为GopRotate中实现旋转显示的函数BltRotate();
  • Shell界面旋转多少度,由内部私有结构体的成员变量Rotation决定。实现控制此变量的GRAPHICS_OUTPUT_PROTOCOL_ROTATE_PROTOCOL,此Protocol提供了两个接口函数,用来获取Rotation值和设置Rotation的值。

示例工程GopRotate的私有结构体如示例1所示。

继续阅读“UEFI开发探索70- YIE001PCIe开发板(06 UEFI驱动)”

76 total views, no views today

UEFI开发探索69- YIE001PCIe开发板(05 UEFI驱动)

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

上一篇中,驱动BlankDrv完成了核心的EFI_DRIVER_BINDING_PROTOCOL,以及获取驱动名Protocol的处理后,整个UEFI驱动框架还有两项工作等待完成:

  • 安装UEFI驱动所提供的Protocol;
  • 驱动加载后是常驻内存的,应该提供UEFI驱动的卸载函数,以支持将驱动系统中移除的功能。

1 完成驱动框架

安装Protocol可以使用InstallMultipleProtocolInterfaces()函数,由于BlankDrv中有三种Protocol需要安装,所以使用了库函数EfiLibInstallDriverBindingComponentName2()来安装所有的Protocol。如示例1所示。

【示例1】安装BlankDrv所提供的Protocol

EFI_STATUS EFIAPI UefiMain(
  IN EFI_HANDLE           ImageHandle,
  IN EFI_SYSTEM_TABLE     *SystemTable
  )
{
  EFI_STATUS          Status;
  …..
//安装需要提供的三种Protocol
  Status = EfiLibInstallDriverBindingComponentName2 (
             ImageHandle,
             SystemTable,
             &gBlankDrvDriverBinding, 
             ImageHandle,
             &gBlankDrvComponentName,
             &gBlankDrvComponentName2
             );
  return Status;
}

驱动的卸载函数,在使用UEFI Shell命令unload的时候会被调用。此函数的入口在UEFI工程的INF文件中添加,由[Defines] Section的UNLOAD_IMAGE字段给出。在示例工程BlankDrv的BlankDrv.inf中,按照如下方式进行了定义:

[Defines]
  ……
ENTRY_POINT                    = UefiMain         //驱动的入口函数
UNLOAD_IMAGE                   = DefaultUnload   //驱动的卸载函数

继续阅读“UEFI开发探索69- YIE001PCIe开发板(05 UEFI驱动)”

69 total views, no views today

UEFI开发探索68- YIE001PCIe开发板(04 UEFI驱动)

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

插个新告知:YIE001的开发板,思路已经比较清晰了-使用PCIE芯片,编写Option ROM,在此基础上控制硬件,做一些有趣的实验。由于主要是用业余时间,估计在这两个月内就能把要做的实验完成。

因此,有了新的想法-做一个USB的开发板YIE002,实现从UEFI访问、Windows/Linux访问的全通道USB HID设备。当然,可以用它来收集温度、产生随机数等。准备做成U盘大小,方便直接插在电脑上进行实验。我正在收集网友的想法,有啥想实现的,留言就行,资源允许,我就在板子上实现了。

回到UEFI驱动的介绍。

UEFI开发探索66和67,介绍了服务型驱动的构建和实现。下面几篇,用来介绍符合UEFI驱动模型的驱动程序。本篇主要介绍其框架结构和程序接口,内容有点枯燥,最好对照着源码进行阅读。

一个完整的符合UEFI驱动模型的驱动程序,大致可以分为两个部分:EFI Driver Binding Protocol和驱动本身提供的服务。前者用来管理驱动,后者才是用户需要使用的部分,一般包括一个或多个Protocol。

比如UEFI的USB主控制器驱动,它提供了两个Protocol供用户使用,包括EFI_USB_HC_PROOCOL和EFI_USB2_HC_PROTOCOL,用来访问USB设备。另外,为了方便用户使用,驱动程序一般还会包含EFI Component Name Protocol,用来显示驱动信息。

在网页https://sourceforge.net/projects/edk2/files/EDK%20II%20Releases/Demo%20apps/上,可以下载Intel早期提供的驱动框架示例BlankDrv,用来学习UEFI驱动模型。

1 EFI Driver Binding Protocol

示例工程BlankDrv包含四个文件:

  1. BlankDrv.c。实现EFI_DRIVER_BINDING_PROTOCOL及其接口函数,并安装EFI_DRIVER_BINDING_PROTOCOL和EFI_COMPONENT_NAME_PROTOCOL。
  2. BlankDrv.h。定义了驱动所需数据结构以及Protocol接口函数原型;
  3.  ComponentName.c。实现了EFI_COMPONENT_NAME_PROTOCOL的接口函数;
  4. BlankDrv.inf,编译UEFI驱动的INF文件。
继续阅读“UEFI开发探索68- YIE001PCIe开发板(04 UEFI驱动)”

67 total views, no views today

UEFI开发探索67- YIE001PCIe开发板(03 UEFI驱动)

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

上一篇做好了服务型UEFI驱动的示例工程,本篇准备编写测试用的UEFI应用,演示如何使用驱动提供的Protocol。另外,对于如何加载驱动进行测试,也会详细讲述。

1 编写测试驱动的UEFI应用

完成了服务型驱动和相应示例Protocol的构建后,我们准备编写访问示例Protocol的UEFI应用。本节准备的示例工程TestServiceDrv,在文末提供了下载地址。

编写测试示例Protocol的代码,步骤如下:

  • 将示例工程ServiceDrv的头文件MyProtocol.h拷贝到示例工程TestServiceDrv的文件夹下。同时修改TestServiceDrv.inf文件,在[Sources] Section下添加此头文件名;
  • 在TestServiceDrv的主程序所在源文件TestServiceDrv.c中添加GUID的声明和定义;
  • 在主程序中添加测试用的代码。

在我们准备的服务型驱动例子中,准备了三个接口函数。其中,接口函数My_SampleIn()和

MySample_DoSth()对私有数据进行了不同赋值,接口函数My_SampleOut()则将私有数据打印了出来。我们可以据此编写测试用的代码,如示例1所示。

【示例1】测试示例Protocol

EFI_STATUS EFIAPI UefiMain (IN EFI_HANDLE ImageHandle,
IN EFI_SYSTEM_TABLE  *SystemTable)
{
  EFI_STATUS      Status;
  EFI_MYSAMPLE_PROTOCOL *myprotocol;
  Status=gBS->LocateProtocol(&gEfiMYSampleProtocolGUID,//示例Protocol GUID
NULL, (VOID **)&myprotocol);
  if(EFI_ERROR(Status))
  {
    Print(L”LocatProtocol error: %r\n”, Status);
    return Status;
  }
  //测试示例Protocol的接口函数
  myprotocol->MySample_In(myprotocol,L”Hello,My protocol!”);
  myprotocol->MySample_Out(myprotocol);
  myprotocol->MySample_DoSth(myprotocol,L”Enjoy UEFI!”);
  myprotocol->MySample_Out(myprotocol);
  return EFI_SUCCESS;
}

示例应用TestServiceDrv是配合之前构建的服务型驱动ServiceDrv工作的,如果ServiceDrv没有加载,则提示找不到Protocol;如果ServiceDrv加载后,则会如示例1所示,依次调用示例Protocol的接口函数。

继续阅读“UEFI开发探索67- YIE001PCIe开发板(03 UEFI驱动)”

62 total views, no views today

UEFI开发探索66- YIE001PCIe开发板(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 句柄数据库
继续阅读“UEFI开发探索66- YIE001PCIe开发板(02 UEFI驱动)”

86 total views, no views today

UEFI开发探索65- YIE001PCIe开发板(01开篇)

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

有段时间没有更新博客了,最近大部分时间都用在公司项目上、以及整理书稿了。在整理书稿的过程中,到了讲述PCIe协议这章的时候,总觉得只是介绍协议和UEFI代码,未免有点太枯燥了。

因此,我把之前写好的章节全部推翻,介绍PCI协议的内容,改为做一个PCIE的开发板,并动手实现板卡的UEFI Option ROM。

也就是说,我按照想象开发了带Flash ROM的PCIE开发板,把UEFI Oprom代码灌入,设备插在计算机上,就可以显示编写好的界面,并能控制开发板上器件,实现一些有趣的功能。

开发板我取名为YIE001,来源于我们博客网站的缩写。目前的计划如下:

  1. 实现基本的Oprom代码;
  2. 实现界面和键盘控制功能;
  3. 实现跑马灯程序;
  4. 实现开发板的按键控制功能;
  5. 实现开发板上的屏幕显示功能;
  6. 移植基础的GUI到开发板上;
  7. 读取插在主机上U盘的内容;
  8. 做个贪吃蛇的游戏。
  9. More……

其中第5个,是指开发板上的I2C接口的OLED屏幕,而不是主机的屏幕。目前不确定这个功能是否能实现,我所用的PCIE芯片Ch366,它的I2C时序很奇怪,我还没有调试,不知道结果如何。当然,时间原因,以上的计划很有可能改变,我尽量按照这些目标开展计划。

另一个计划是关于UEFI与USB的,我准备稍微拓展一下,把如何用单片机实现HID通讯,Windows下如何访问HID设备、UEFI下如何访问HID设备,作为一个大专题,全面讲一下。时间足够的话,Linux系统下访问HID设备的方法也试着实现一下。这就把USB HID从上到下,我觉得应该掌握的知识,全部都探索了一遍。

本篇博客,主要介绍下刚打样回来的YIE001的硬件结构。

开发板YIE001主要就是为开发UEFI Option ROM而制作的,其目的为了演示Option ROM代码如何调用Protocol、如何控制硬件。它是一块PCIe的板卡,提供了拨动开关控制、LED灯的控制以及I2C的接口,其产品结构示如图1所示。

图1 YIE001开发板结构
继续阅读“UEFI开发探索65- YIE001PCIe开发板(01开篇)”

123 total views, no views today