UEFI 正常启动过程--与EDK为例,大家一起讨论吧!
最近在工作看到机台有启动过程中把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)
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_EXTENSIONmCompTypeExtension[] = {
{"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)
不错!
支持
继续
加油
:victory:
回复 1# 的帖子
gPrivateDispatchTable 和COMP_TYPE_EXTENSION没有搜到啊:lol是EDK专有的么?有看过跟gPrivateDispatchTable 类似的,但是里面的PPI不同。
还有这个COMP_TYPE_EXTENSION没有找到过。FWVolume.c这个文件也没有发现。。 这东西虽说没有什么技术含量,但是总结一下还是非常好的。
支持! :lol
小弟还在学习阶段,目前的目标是知道执行的流程。
这里面有很多细节没有写,能力有限,只能自己知道,不能表达。
嘿。。。。
所有大侠们如果有好东西能给小弟共享一份。
:handshake
谢谢! 原帖由 winbondowen 于 2008-7-27 00:11 发表 http://www.ufoit.com/bbs/images/common/back.gif
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".
[ 本帖最后由 ichirohiro 于 2008-8-13 13:32 编辑 ] 学习心得写了这么多 支持一下~!
回复 3# 的帖子
gPrivateDispatchTable 和COMP_TYPE_EXTENSION是EDK专有:lol 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. 请问各位大虾,EDK从哪下阿? https://edk.tianocore.org/servlets/ProjectDocumentList?folderID=5&expandFolder=5&folderID=0 感谢 ichirohiro 大侠的指点。
:handshake
CoreDispatcher()时,真的不会执行"Support()/Start()"吗?
原帖由 ichirohiro 于 2008-8-20 17:47 发表 http://www.ufoit.com/bbs/images/common/back.gif...
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().
在Framework的spec DxeCis.pdf里面也是这么说的,DXE CoreDispatcher()里面,对于EFI1.1 driver model的driver只会安装Handler和Interface到Binding protocol,到BDS才会去执行Support()和Start().
但是,我在看code时,发现在CoreDispatcher()-->CoreStartImage()里面call image之后有这么一句:(file:image.c)
//
// Go connect any handles that were created or modified while the image executed.
//
CoreConnectHandlesByKey (HandleDatabaseKey);
这里的HandleDatabaseKey是call image之前由CoreGetHandleDatabaseKey()得到的gHandleDatabaseKey
而CoreConnectHandlesByKey会调用到:
//
// Connect all handles whose Key value is greater than Key
//
for (Index = 0; Index < Count; Index++) {
CoreConnectController (HandleBuffer, NULL, NULL, TRUE);
}
所以,照code看,当在Driver中安装一个Handle和Interface到Binding Protocol后(gHandleDatabaseKey会++,IHandle的Key=gHandleDatabaseKey)
是会去ConnectController的,也会执行对应的Support()和Start()才对!!
不知道我想的哪里有问题???欢迎大家指正.
[ 本帖最后由 xtdumpling 于 2008-9-18 15:25 编辑 ] 这段code似乎是一个向后兼容的行为,不必太care。
一个UEFI driver model driver一般只会在ImageHandle上装EFI Driver Binding Protocol,而ImageHandle在CoreStartImage()之前已经存在,所以不会导致Handle database key增加,所以不会触发ConnectController()。当然,如果一个UEFI driver model driver在入口函数中创建了新的handle,是会触发CoreConnectController()的。 了解了.
非常 感谢!!!:victory: 在读DXEmain时,
Status = CoreInitializeImageServices(HobStart);--->CoreInstallProtocolInterface();--->CoreInstallProtocolInterfaceNotify();中,
//
// Notify the notification list for this protocol.
//
if (Notify) {
CoreNotifyProtocolEntry(ProtEntry);
} 里Signal了Event. MS是说一个handle安装了一个protocol后就signal一次.
有个问题请教一下大家: 这段是在DXE很靠前的位置执行的,但是在它之前我没有看到DXE中有相关的CreateEvent出现?哪位高手能说说这部分代码的流程呢? 原帖由 xtdumpling 于 2008-9-16 13:34 发表 http://www.ufoit.com/bbs/images/common/back.gif
请楼上的兄弟分析下BS的RegisterProtocolNotify也就是CoreRegisterProtocolNotify是做什么用的?怎么用?
谢谢!
......
:lol
[ 本帖最后由 xtdumpling 于 2008-9-23 17:24 编辑 ] 原帖由 xtdumpling 于 2008-9-23 17:04 发表 http://www.ufoit.com/bbs/images/common/back.gif
......
:lol
Signal的Event是不是在各个TPL级上挂载一些待处理的事件,一旦restore(TPL)的话,比当前TPL级高的pending事件就回被处理掉?
如果是这样的话,Timer事件是如何处理的呢,没有找到相关的代码呀?Xt指点一下再~:handshake Timer是挂在8259的IRQ0的中断处理程序上面的, 大概每秒18.3次调用CoreTimerTick()-->CoreCheckTimers()
TPL=30
页:
[1]
2