我的BIOS之行7-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;
    }
        出处:http://www.cnblogs.com/samuelwnb/
版权:本文版权归作者和博客园共有
转载:欢迎转载,为了保存作者的创作热情,请按要求【转载】,谢谢
要求:未经作者同意,必须保留此段声明;必须在文章中给出原文连接;否则必究法律责任

                
            
        
浙公网安备 33010602011771号