我的BIOS之行-protocol的使用与创建

Posted AlexKing阁下

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了我的BIOS之行-protocol的使用与创建相关的知识,希望对你有一定的参考价值。

protocol简介

从语言上来看,protocol包含了属性和函数指针的结构体,从功能上看,protocoll是提供者与使用者对服务方式的一种约定。其实我们不难看出UEFI中的Protocol引入了面向对象的思想。

每一个protocol都必须要有一个唯一的GUID。如我的github上面的code一样,在github上我每章都有对应的提交,你可以通过我的提交看到我所完成的内容。如下就是我所定义的protocol的GUID。

#define EFI_HOMEWORKINTERFACE_PROTOCOL_GUID \\
           \\
            0x47590bea, 0x6178, 0x498d, 0xa9, 0x5, 0x3c, 0xe6, 0x63, 0xc3, 0x84, 0xd9 \\
          

一般的protocol的服务会提供2种操作,一个是使用protocol,一个是产生protocol。这一篇均有介绍,一般来讲的话,产生protocol(相当于创建服务)与操作protocol(使用客户端)不在一个module里面的,我在这边为了讲解将所有的功能都集中到了同一个module中。

该文module简介

目前是创建protocol后并注册,以激活上一文讲到的event事件,通过callback进行调用protocol,并使用它的interface,其中一个会调用hob来读取setup的item值,后面一个是通过pcie读取相关device的device id并将值回填给setup的item,后面一个暂时还未实现。

protocol的使用

一般使用protocol有3个步骤
* 通过openprotocol(handleProtocol/LocateProtocol)找到protocol对象
* 使用这个protocol提供的服务
* 通过CloseProtocol关闭打开的protocol

在这里我就不细讲各个protocol的参数什么的了,这个完全可以自己到spec上去看。

一般有
* OpenProtocol(查询指定的Handle中是否支持指定的Protocol)
* HandleProtocol(由于OpenProtocol实在是用起来复杂,有时根本不要关心太对细节,所以有了这个接口)
* LocateProtocol(Open/Handle都是用来打开指定的protocol,但有时我们并不关心protocol在什么地方的时候就可以用这个函数了)
* CloseProtocol(用来关闭protocol)

实例

一般LocateProtocol找到了第一个实例后,因为没有相关的handle所以是无法关闭的,当然如果一定要关闭的话就需要用OpenProtocolInterface来获取handle来关闭它

在我写的code中

  EFI_HOMEWORKINTERFACE_PROTOCOL         *HomeworkProtocolinterface;
    Status = pBS->LocateProtocol(&gEfiHomeWorkProtocolGuid,
                                 NULL,
                                 &HomeworkProtocolinterface );
    if (!EFI_ERROR(Status)) 
    
        Status = HomeworkProtocolinterface->HomeWorkHobread(1); 
        Status = HomeworkProtocolinterface->HomeWorkPciread(0,0,0);
    

我们可以看到通过LocateProtocol获取protocol后用它自己的protocol

在这里注意,一定要自己申请一个protocol的interface,不然会hang.原因是我在这边创建的protocol,可以直接用宏HomeworkProtocol,这个将会造成系统的误操作。

protocol的创造与注册

上面我们说明了咋么使用,在告诉你咋么用后,应该告诉你咋么创造。

设计接口

前面我就创建了HomeworkDxe.h一直没用,在此时就派上用处了。

typedef EFI_STATUS (* HOMEWORK_HOB_READ) (
    IN  UINT8 device

);
typedef EFI_STATUS (* HOMEWORK_PCI_READ) (
    IN  UINT8 busnum,
    IN  UINT8 devicenum,
    IN  UINT8 funcnum
);
struct _EFI_HOMEWORK_PROTOCOL
    HOMEWORK_HOB_READ HomeWorkHobread;
    HOMEWORK_PCI_READ HomeWorkPciread;
;
typedef struct _EFI_HOMEWORK_PROTOCOL  EFI_HOMEWORKINTERFACE_PROTOCOL;

注意这边EDK2是有命名规范的,Protocol结构体名字都是要在前面加“_”,所以这个接口为_EFI_HOMEWORK_PROTOCOL,然后它里面有哪些函数。

最好呢再重命名一下,那么我们再调用的时候会更加清晰

建立GUID

不要忘记将它extern出去,不然别人找不到你。

extern EFI_GUID gEfiHomeWorkProtocolGuid;
#define EFI_HOMEWORKINTERFACE_PROTOCOL_GUID \\
           \\
            0x47590bea, 0x6178, 0x498d, 0xa9, 0x5, 0x3c, 0xe6, 0x63, 0xc3, 0x84, 0xd9 \\
          
EFI_GUID gEfiHomeWorkProtocolGuid = EFI_HOMEWORKINTERFACE_PROTOCOL_GUID;

Protocol服务的实现

此时你需要将上面写的接口进行实现

EFI_STATUS HomeWorkHobread(
        IN  UINT8 device  
)

       EFI_GUID                GuidHob = HOB_LIST_GUID;
       HOMEWORK_HOB            *Homeworkhob=NULL;
       EFI_GUID                 HomeworkHobGuid=HOMEWORK_HOB_GUID;
       VOID                    *pHobList = NULL;
       EFI_STATUS              Status;
       pHobList = GetEfiConfigurationTable(pST, &GuidHob);
       if (!pHobList) return EFI_UNSUPPORTED;

       Homeworkhob = (HOMEWORK_HOB*)pHobList;
       while (!EFI_ERROR(Status = FindNextHobByType(EFI_HOB_TYPE_GUID_EXTENSION, &Homeworkhob)))
       
           if (guidcmp(&(*Homeworkhob).EfiHobGuidType.Name, &HomeworkHobGuid) == 0)
                       break;
       
       if (!EFI_ERROR(Status))
                OEM_TRACE("device=%d,data=%d\\n",device,Homeworkhob->homeworkdata);
       
    return Status;

EFI_STATUS HomeWorkPciread(
           IN  UINT8 busnum,
           IN  UINT8 devicenum,
           IN  UINT8 funcnum
)

    OEM_TRACE("bus=%d,dev=%d,func=%d\\n",busnum,devicenum,funcnum);
    return EFI_SUCCESS;

EFI_HOMEWORKINTERFACE_PROTOCOL  HomeworkProtocol = 
        HomeWorkHobread,
        HomeWorkPciread,  
;

注册protocol

将protocol与event事件进行捆绑注册

 Status = pBS->RegisterProtocolNotify (
                       &gEfiHomeWorkProtocolGuid,
                       homeworkevent,
                       &Registration
                       );
     if (EFI_ERROR(Status)) 
     
             return Status;
     

用InstallProtocolInterface触发event,然后就看上面是咋么用的就可以了

 Status = pBS->InstallProtocolInterface(
                              &ImageHandle,
                              &gEfiHomeWorkProtocolGuid,
                              EFI_NATIVE_INTERFACE,
                              &HomeworkProtocol
                       );
    if (EFI_ERROR(Status)) 
    
         return Status;
    

以上是关于我的BIOS之行-protocol的使用与创建的主要内容,如果未能解决你的问题,请参考以下文章

我的BIOS之行-hob的使用

我的BIOS之行-setup中建立选项

我的BIOS之行(10)-传值修改setup中的值

我所认知的BIOS—> uEFI AHCI Driver — 第一个Protocol真难搞

我的react学习之行-01webpack与react环境搭建

我的react学习之行-02总体设计与react组件header设计