请保留-> 【原文: 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。
示例2中给出了修改后的Start()函数。
【示例2】Start()函数
EFI_STATUS EFIAPI BlankDrvDriverBindingStart (
IN EFI_DRIVER_BINDING_PROTOCOL *This,
IN EFI_HANDLE Controller,
IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL )
{
…… //代码略
Status = PciIo->Pci.Read(PciIo,EfiPciIoWidthUint16,16,1,&MyIoBaseAddr);
if (EFI_ERROR (Status)) goto Done;
MyIoBaseAddr=(MyIoBaseAddr&0x0fffe); //得到I/O基地址
HelloUEFI(); //Oprom的演示函数
Status = EFI_SUCCESS;
Done: …… //代码略
return Status;
}
Start()函数在函数起始,通过PCI I/O Protocol的实例,在设备的PCI空间中将此基地址取到。其后调用HelloUEFI()函数,实现需要的功能。
也就是说,完成这些框架后,可以把精力集中在HelloUEFI()函数的编写上。UEFI开发探索的系列博客中,使用各种Protocol,实现了各种功能的示例程序。这些程序略作修改,都可以移植到这个地方。
本篇中,直接在HelloUEFI()中,添加打印字符串,并等待用户输入,实现简单的演示功能就可以了。如下所示:
VOID HelloUEFI(VOID)
{
gST->ConOut->OutputString(gST->ConOut,L”Hello, I am YIE001!\n\r”)
WaitKey(); //等待用户按键
}
2 编译及测试Option ROM
所编写的UEFI驱动,需要按照一定的方法编译,才能生成Option ROM。在第36篇中,已经比较详细地介绍过如何编译了。
本篇采用修改INF文件的方式,对UEFI驱动进行编译。示例3中给出了INF文件的修改样本。
【示例3】INF文件
[Defines]
…… //其他变量,略去
PCI_VENDOR_ID = 0x1C00 //厂商ID
PCI_DEVICE_ID = 0x4349 //设备ID
PCI_CLASS_CODE = 0x020000 //设备分类号
PCI_REVISION = 0x0003 //代码版本
PCI_COMPRESS = TRUE //是否压缩,TRUE为压缩
假设自己编写的示例工程为MyOprom,则编译命令如下:
C:\UEFIWorkspace>build -t VS2015x86 -p RobinPkg\RobinPkg.dsc \
-m RobinPkg\Drivers\MyOprom\ MyOprom.inf -a X64
注意使用X64目标架构进行编译,大部分的机器基本上都是64位的UEFI BIOS了。
编译完成之后,将在输出目录中生成MyOprom.efi和MyOprom.rom两个文件。使用EfiRom工具,运行“-d”命令,可以查看MyOprom.rom的信息。可以看到MyOprom.rom已经是个有效的UEFI Option ROM文件,其厂商ID、设备ID等信息,与INF文件中设定的一致。
测试的方法有两种,一是在UEFI Shell下,使用load命令或者loadpcirom命令,直接将驱动挂载在设备控制器的句柄上,显示MyOprom中实现的功能;二是将二进制ROM文件,按照CH366的要求,以二进制的形式写入YIE001上的Flash ROM中,进行测试。
这两种测试方法,都要求YIE001开发板插在实际机器上运行。
这里先介绍下前一种测试方法,后一种方法,在YIE001的下一篇博客中再讨论。
将编译好的64位efi程序和rom文件,即MyOprom.efi和MyOprom.rom复制到UEFI启动U盘中。
把开发板YIE001插在主板的PCIe槽上,然后启动测试的计算机,进入UEFI Shell环境。在
UEFI Shell环境下,可以使用Shell命令“pci”列举出所有PCI设备,查看开发板YIE001是否被系统识别出来。YIE001开发板上设定的厂商ID是0x1C00,设备ID是0x4349,可在列举出的PCI设备中寻找是否存在。
使用如下命令进行测试:
load MyOprom.efi
或者
loadpcirom MyOprom.rom
加载驱动(或者Option ROM)后,屏幕上会显示示例工程中HelloUEFI()函数打印的字符串。
1,571 total views, 1 views today