UEFI 正常启动过程--与EDK为例,大家一起讨论吧!

来源:互联网 发布:淘宝上货软件有哪些 编辑:程序博客网 时间:2024/05/05 21:30

原文来自:http://www.ufoit.com/bbs/thread-282-1-2.html

 

最近在工作看到机台有启动过程中把SPI ROM数据清空,但苦与没有办法很好的Debug(PCA没有架起来),所有与EDK为对象好好的读了一把。

SEC/CEI:
  UEFI BIOS启动时先会执行SEC/CEI,这个阶段在实现的BIOS Code中初始化Debug Port,进入Big Mode,CPU的MicroCode,CacheToRAM的转换.然后跳转到PEI阶段。
在EDK中这部分被成了Load FvRecovery.fd文件,这个文件类似与我们的BIOS ROM.里面是我们编译后生成的二进制代码。在这个阶段最主要的是将这个文件加载到内存中(Windows API将文件加载到内存,看API函数).

PEI:
   从这里开始UEFI BIOS和EDK执行基本相同,只是一个是从SPI ROM中定位一个地址(PEIM的开始地址),一个是从内存中定位一个地址(PEIM的开始地址)。从这里开始只讲EDK的执行
  EDK调用InitializeMemoryService函数,将HobList清空,peiservice清空。
      InitializePPIService函数,将PPI队列清空,这个队列长0x3F.
          InitializeSercurityService函数,将Notify队列清空。
          InitializeDispatcherData函数,将Dispatcher队列清空。
  接着由PeiBuildHobGuid来建立一个HOB(S3返回时这时应该有这个HOB,不用建立,直接使用了,这样就会进入另外一个流程,可以这个EDK不能调试S3,不知道怎么走)。然后由(*PeiServices)->InstallPpi()将这个新HOB加入到PPI中。
    由于在SEC阶段转了以下这几具PPI,所以在执行PEI的Dispatcher之前会先安装东西:
      EFI_PEI_PPI_DESCRIPTOR    gPrivateDispatchTable[] = {
       {EFI_PEI_PPI_DESCRIPTOR_PPI, &gEfiNtLoadAsDllPpiGuid, &mSecNtLoadAsDllPpi},
       {EFI_PEI_PPI_DESCRIPTOR_PPI, &gNtPeiLoadFileGuid, &mSecNtLoadFilePpi},
       {EFI_PEI_PPI_DESCRIPTOR_PPI, &gPeiNtAutoScanPpiGuid, &mSecNtAutoScanPpi},
       {EFI_PEI_PPI_DESCRIPTOR_PPI, &gPeiNtThunkPpiGuid, &mSecWinNtThunkPpi},
       {EFI_PEI_PPI_DESCRIPTOR_PPI, &gPeiStatusCodePpiGuid, &mSecStatusCodePpi},
       {EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST, &gNtFwhPpiGuid, &mSecFwhInformationPpi}
     };
    每个PPI是由{类型,GUID(名字,以后就根据这个来找到它的),Function_Entry_Address}组成。
   这些PPI会在PEIDispatcher中用到。
   安装完这此东西这开始执行PEIDispatcher函数,函数从BIOS ROM文件中找出PEI的Image(怎么找到,请读一下FV_HEAD(EFI_HEAD),里面讲到了如何区分Image类型),然后定位到PEI Image的入口地址,执行他。在我们的的PEI中,我们一般会申明一个PPI,这个就是这个PEI提供一些服务,PEIDispatcher会将他们加入到PPI-List中,以后其他Image也可以调用他的提供的功能。
   最后EDK会加载一个叫DXEIPL的PEI,DXEIPL提供一个PPI服务,这个PPI的功能是实现从PEI到DXE的切换,这个PPI里面为DXE做了很多的预准备,加载了很多PPI,如对BIOS的解压方法等。
   SwitchStacks (
       (VOID *) (UINTN) DxeCoreEntryPoint,
       (UINTN) (HobList.Raw),
       (VOID *) (UINTN) TopOfStack,
       (VOID *) (UINTN) BspStore
    );
  用过汇编的人对这个技术一定很熟悉,不多说了(我别不清,咯。。。)

DXE:
     从PEI到DXE切换时转过来一个HOBLIST参数,DXE会在这个HOB中找到Memory的使用情况,然后根据这些情况将BIOS引到内存(这是EFI的做法)。在EDK在DXE时重新定位一下内存。
接着就会定义我们经常使用到的gST表,gRT表。接着是申明一些Protocol(先不关心这些事)。
   等这些该加的PPI,Protocol加完了,CoreDispatcher()就出场了。他会的功能类似PEIDispatcher()。从我们BIOS ROM中将DXE的驱动读出,执行执行他们,这时会执行到Driver
中的Support(),Start()两个功能函数。在这两个函数中你可以注册自己的PPI,为其他驱动提供服务。
   到些BIOS的引导其他完成。接着该进OS了,看Linux 0.11吧,操作系统是怎么做事情的。
   
Driver:
    我们的驱动什么为在PEI和DXE等不同阶段执行呢?
  大家请看一下我们的驱动的makefile.(EDK中的*.inf)
  [defines]
  BASE_NAME            = OWEN
  FILE_GUID            = 1EDD13C1-62EF-4262-A1AA-0040D0830110
  COMPONENT_TYPE       = BS_DRIVER

  BASE_NAME告诉编译器最终生成的驱动的名字。
  FILE_GUID就是这个驱动的GUID名字,在BIOS中引用某个驱动就是根据它来调用和识别。
  COMONENT_TYPE会告诉编译器生成驱动的类型,是PEI,DXE,等。
  在EDK中有一个FWVolume.c实现的功能就是帮我们把这个TYPE转换面相应的扩展名
  COMP_TYPE_EXTENSION  mCompTypeExtension[] = {
  {"bs_driver",  ".dxe" },
  {"rt_driver",  ".dxe" },
  {"sal_rt_driver", ".dxe"},
  {"security_core", ".sec"},
  {"pei_core", ".pei"},
  {"pic_peim", ".pei"},
  {"pe32_peim", ".pei"},
  {"relocatable_peim", ".pei"},
  {"binary", ".ffs"},
  {"application", ".app"},
  {"file", ".ffs"},
  {"fvimagefile", ".fvi"},
  {"rawfile", ".raw"},
  {"apriori", ".ffs"},
  {"combined_peim_driver", ".pei"},
  { NULL,  NULL }
};

了解了这些,接下我们可以看驱动篇了。(Go On Study... Forever)

 

原帖由 winbondowen 于 2008-7-27 00:11 发表
  ROM中將DXE的驅動讀出,執行執行他們,這時會執行到Driver
中的Support(),Start()兩個功能函數。在這兩個函數中你可以註冊自己的PPI ...

PPIs are registered during PEI phase, but Support()/Start() are invoked in DXE driver binding protocol,
For more precisely, I think the "PPI" you mentioned is the "PROTOCOL" rather than "PPI".

 

 

To ichirohiro:
   Yes. I make a mistake.
      PPI:     A PEIM to PEIM interface.
      PROTOCL: A Interface between Hardware(or firmware) and software.
      reference[http://www.biosren.com/viewthread.php?tid=207]
   so, PPI execute at PEI step and Initialize hardware. PROTOCOL execute by DXE step.
   Thanks.
 
原帖由 winbondowen 于 2008-7-27 00:11 发表 DXE:
     從PEI到DXE切換時轉過來一個HOBLIST參數,DXE會在這個HOB中找到Memory的使用情況,然後根據這些情況將BIOS引到內存(這是EFI的做法)。在EDK在DXE時重新定位一下內存。
接著就會定義我們經常使用到的gST表,gRT表。接著是申明一些Protocol(先不關心這些事)。
   等這些該加的PPI,Protocol加完了,CoreDispatcher()就出場了。他會的功能類似PEIDispatcher()。從我們BIOS ROM中將DXE的驅動讀出,執行執行他們,這時會執行到Driver
中的Support(),Start()兩個功能函數。在這兩個函數中你可以註冊自己的PPI,為其他驅動提供服務。
   到些BIOS的引導其他完成。接著該進OS了,看Linux 0.11吧,操作系統是怎麼做事情的。.
There are mistakes,
1.gST and gRT are init after the DXE architectural protocols have been loaded, those protocols response for creating Dxe foundation.

2.The Dxe drivers have two subclasses : Dxe driver that execute very early in the Dxe phase and Dxe drivers that comply with the EFI1.1 driver model.
The CoreDispatcher() executes all trusted Dxe drivers and just register the Binding protocol if the driver is EFI1.1 driver model.
Furthermore, Support()/Start() are invoked in BDS phase over the CoreConnectController() rather than CoreDispatcher().

BTW, please excuse my English, since I come from Taiwan and without Simplified Chinese typing interface.