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

如果用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中的驱动找出来并执行完。


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

BIOS工程师第一课 DXE Dispatcher 源代码分析_第1张图片


  

  相关数据结构:

BIOS工程师第一课 DXE Dispatcher 源代码分析_第2张图片

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

BIOS工程师第一课 DXE Dispatcher 源代码分析_第3张图片

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

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

BIOS工程师第一课 DXE Dispatcher 源代码分析_第4张图片

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

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

它的定义是这样的: 

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

下面是它的官方解释:

BIOS工程师第一课 DXE Dispatcher 源代码分析_第5张图片

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

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的起始地址。

BIOS工程师第一课 DXE Dispatcher 源代码分析_第6张图片

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


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

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


BIOS工程师第一课 DXE Dispatcher 源代码分析_第7张图片


你可能感兴趣的:(UEFI源码剖析)