BIOS工程师第一课 DXE Dispatcher 源代码分析

来源:互联网 发布:赵帅奥运会比赛数据 编辑:程序博客网 时间:2024/06/03 15:18

如果用C语言(伪)代码描述整个BIOS 的执行流程,我想应该是这样的:

main(){    SecStartup (  SizeOfRam,  TempRamBase,  *BootFirmwareVolume)    {       // Update the base address and length of Pei temporary memory        PeiCore (&SecCoreData, mPeiSecPlatformInformationPpi);        }     PeiCore()    {PeiDispatcher (SecCoreData, &PrivateData);    }    DxeMain(VOID *HobStart)    {        CoreDispatcher ();        ~~~~~~~~~~~~~~~~~~    }    gBds->Entry (gBds);}


          大家都知道,bios 主要由各个驱动构成(网卡驱动,显卡驱动,IO, Watchdog定时器 etc) ,  DXE Dispatcher 的职责就是从bios 芯片里面找到它们,并按正确的顺序去执行它们。

       当dxe dispatcher 发现一个新的firmware volume 的时候,首先做的是找a priori 文件,a priori 文件里面放的驱动应该最先执行,一个firmware volume 里面最多只能有一个a priori 文件(当然,也可以没有a apriori 文件)。当a priori 文件里面提到的驱动都执行完成之后,剩下的驱动,就需要通过一些逻辑计算来最终确定它的运行顺序,这里所说的逻辑计算主要是去其依赖表达式的计算。

      当a priori 文件里面所有的驱动以及所有依赖表达式都为真的驱动执行完之后,控制权就会交给BDS.   BDS 的职责就是去建立console device 以及尝试去

引导系统,在BDS 做这些事的过程中,很可能又会发现一些firmware volume, 它就把DXE Dispatcher 叫过来将FV中的驱动找出来并执行完。


   如果以流程图来表示,那是这样的:



  

  相关数据结构:


这里值得一说的就是第二个参数和第三个参数, Link 是指已经发现了的,ScheduledLink  正如成员名一样,是马上要投入运行的。


442-447: 注释写得很清楚,如果dispatcher已经运行了,就不用再一次运行了。

接下来,就进入了整个函数的高潮部分。


468: 循环一直进行,直到mScheduledQueue 为空。

469:从link 里面找到DriverEntry. 这里的宏CR有必要拿出来讨论一下。

它的定义是这样的: 

#define CR(Record, TYPE, Field, TestSignature)  ((TYPE *) ((CHAR8 *) (Record) - (CHAR8 *) &(((TYPE *) 0)->Field)))

下面是它的官方解释:


这里解释得很清楚,分三步:

1. 拿到成员的地址

2.减去这个成员相对于它所在的结构体的偏移量.

3.将最终结果转换为它所在的结构体的类型。

简单来说:就是已经某个结构体成员的地址,如何去计算它所在结构体的位置。


有了前面这些先行知识,我们这一次将相关变量代入这个宏:

      DriverEntry = CR (                      mScheduledQueue.ForwardLink,                      EFI_CORE_DRIVER_ENTRY,                      ScheduledLink,                      EFI_CORE_DRIVER_ENTRY_SIGNATURE                      );


mScheduledQueue 的初始化过程还是在同名文件Dispathcer.c 中:

//// Queue of drivers that are ready to dispatch. This queue is a subset of the// mDiscoveredList.list of EFI_CORE_DRIVER_ENTRY.//LIST_ENTRY  mScheduledQueue = INITIALIZE_LIST_HEAD_VARIABLE (mScheduledQueue);

INITIALIZE_LIST_HEAD_VARIABLE 的定义在BaseLib.h 里面:


#define INITIALIZE_LIST_HEAD_VARIABLE(ListHead)  {&(ListHead), &(ListHead)}
它的作用是初始化双向链表的头节点,即mScheduledQueue的ForwardLink BackLink 都是 mScheduledQueue的地址,然后参考前面
EFI_CORE_DRIVER_ENTRY
的定义,减去相应偏移量,即得到一个DriverEntry的起始地址。

491-523: 对driver 的安全性作检查


我要小额(2元)赞助,鼓励作者写出更好的教程

如果您认为本教程质量不错,读后觉得收获很大,预期工资涨幅能超过30%,不妨小额赞助我一下,让我有动力继续写出高质量的教程。




0 0