找回密码
 加入计匠网
搜索
热搜: BIOS ACPI CPU Windows
查看: 52378|回复: 23

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

[复制链接]
发表于 2008-7-27 00:11:28 | 显示全部楼层 |阅读模式
  最近在工作看到机台有启动过程中把SPI ROM数据清空,但苦与没有办法很好的Debug(PCA没有架起来),所有与EDK为对象好好的读了一把。! ]7 n1 w2 `  I! j

0 X6 x: E) O8 j% `% K6 {& C$ vSEC/CEI:7 m  ~) V9 w* U% w' x0 {
  UEFI BIOS启动时先会执行SEC/CEI,这个阶段在实现的BIOS Code中初始化Debug Port,进入Big Mode,CPU的MicroCode,CacheToRAM的转换.然后跳转到PEI阶段。
4 C9 o9 @. Z6 a" U* h在EDK中这部分被成了Load FvRecovery.fd文件,这个文件类似与我们的BIOS ROM.里面是我们编译后生成的二进制代码。在这个阶段最主要的是将这个文件加载到内存中(Windows API将文件加载到内存,看API函数).( e9 S7 n0 x- y# ]

7 N& Z8 D6 j0 e+ B% `& C3 GPEI:' X) Q) |  ~- \) J6 h$ B
   从这里开始UEFI BIOS和EDK执行基本相同,只是一个是从SPI ROM中定位一个地址(PEIM的开始地址),一个是从内存中定位一个地址(PEIM的开始地址)。从这里开始只讲EDK的执行& s6 [0 u8 k* `! _/ I7 X
  EDK调用InitializeMemoryService函数,将HobList清空,peiservice清空。/ N# f- r  z% p. x# o2 X4 Q
      InitializePPIService函数,将PPI队列清空,这个队列长0x3F.
$ ?7 Y2 y! o/ z: ?5 e          InitializeSercurityService函数,将Notify队列清空。& C' h* r- x" b9 }# x
          InitializeDispatcherData函数,将Dispatcher队列清空。$ k2 `# {9 E# h& W* G% a. H
  接着由PeiBuildHobGuid来建立一个HOB(S3返回时这时应该有这个HOB,不用建立,直接使用了,这样就会进入另外一个流程,可以这个EDK不能调试S3,不知道怎么走)。然后由(*PeiServices)->InstallPpi()将这个新HOB加入到PPI中。
! }: Q. `( t! }$ S, Z( G    由于在SEC阶段转了以下这几具PPI,所以在执行PEI的Dispatcher之前会先安装东西:  {  m5 C& n2 D3 \: K
      EFI_PEI_PPI_DESCRIPTOR    gPrivateDispatchTable[] = {, D% Y9 K6 z7 C
       {EFI_PEI_PPI_DESCRIPTOR_PPI, &gEfiNtLoadAsDllPpiGuid, &mSecNtLoadAsDllPpi},+ Z. c9 O" |& W4 H. |/ x0 x
       {EFI_PEI_PPI_DESCRIPTOR_PPI, &gNtPeiLoadFileGuid, &mSecNtLoadFilePpi},
5 }8 o% w' a, _+ B4 a       {EFI_PEI_PPI_DESCRIPTOR_PPI, &gPeiNtAutoScanPpiGuid, &mSecNtAutoScanPpi},
- x& k! f- M/ L% ?' B8 ~       {EFI_PEI_PPI_DESCRIPTOR_PPI, &gPeiNtThunkPpiGuid, &mSecWinNtThunkPpi},9 b9 f( {$ ^' F0 G: |
       {EFI_PEI_PPI_DESCRIPTOR_PPI, &gPeiStatusCodePpiGuid, &mSecStatusCodePpi},$ n2 x3 F4 U# K- S
       {EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST, &gNtFwhPpiGuid, &mSecFwhInformationPpi}
; u9 X) P' \* {  g' ?2 p# K0 @     };
- j& q- Z7 v- F4 Z3 q, d! \    每个PPI是由{类型,GUID(名字,以后就根据这个来找到它的),Function_Entry_Address}组成。
" ^# q/ W1 N  U1 j+ D8 V! C9 [   这些PPI会在PEIDispatcher中用到。
7 G& s6 j$ d  L! X2 X   安装完这此东西这开始执行PEIDispatcher函数,函数从BIOS ROM文件中找出PEI的Image(怎么找到,请读一下FV_HEAD(EFI_HEAD),里面讲到了如何区分Image类型),然后定位到PEI Image的入口地址,执行他。在我们的的PEI中,我们一般会申明一个PPI,这个就是这个PEI提供一些服务,PEIDispatcher会将他们加入到PPI-List中,以后其他Image也可以调用他的提供的功能。' g8 e. y0 B0 B. L3 G
   最后EDK会加载一个叫DXEIPL的PEI,DXEIPL提供一个PPI服务,这个PPI的功能是实现从PEI到DXE的切换,这个PPI里面为DXE做了很多的预准备,加载了很多PPI,如对BIOS的解压方法等。
" f5 f. C7 V6 G& _* l   SwitchStacks (
6 H- O% i8 x' `: o# s       (VOID *) (UINTN) DxeCoreEntryPoint,
0 O: C% v" K1 a* q2 p4 [% {       (UINTN) (HobList.Raw),9 t/ I2 i' _3 Q% M
       (VOID *) (UINTN) TopOfStack,
/ v* t+ ?1 D7 ?3 P4 R) Y/ a       (VOID *) (UINTN) BspStore0 P) ~0 P% J, Z7 l9 R
    );
+ N) Q* {5 h4 J- _  用过汇编的人对这个技术一定很熟悉,不多说了(我别不清,咯。。。)& f% Y: R3 G: O5 e, X& Y

& b) v+ K$ B6 b5 F2 ~+ V/ lDXE:
4 m+ C% f3 }1 d& P7 A0 k     从PEI到DXE切换时转过来一个HOBLIST参数,DXE会在这个HOB中找到Memory的使用情况,然后根据这些情况将BIOS引到内存(这是EFI的做法)。在EDK在DXE时重新定位一下内存。3 ~/ a; Q; j. I( @3 ~0 C% u
接着就会定义我们经常使用到的gST表,gRT表。接着是申明一些Protocol(先不关心这些事)。
- _1 j" L, g! A; `" w" ~. m( e2 C   等这些该加的PPI,Protocol加完了,CoreDispatcher()就出场了。他会的功能类似PEIDispatcher()。从我们BIOS ROM中将DXE的驱动读出,执行执行他们,这时会执行到Driver' s$ h1 ~& g9 m# }- ]
中的Support(),Start()两个功能函数。在这两个函数中你可以注册自己的PPI,为其他驱动提供服务。, f9 i9 W2 E6 B
   到些BIOS的引导其他完成。接着该进OS了,看Linux 0.11吧,操作系统是怎么做事情的。
1 X/ x# o$ Z/ [& t5 w   # c1 Y; c( ]/ o9 F
Driver:
+ w# J. d1 `3 r, }+ F    我们的驱动什么为在PEI和DXE等不同阶段执行呢?: e# L$ G5 O+ q8 J0 X
  大家请看一下我们的驱动的makefile.(EDK中的*.inf)7 E% d7 H% P' |
  [defines]
) |' y' k" K1 B  BASE_NAME            = OWEN! M/ f/ h7 ?0 ?7 r
  FILE_GUID            = 1EDD13C1-62EF-4262-A1AA-0040D0830110
; m/ A/ ^; M8 G$ Y/ e  COMPONENT_TYPE       = BS_DRIVER% w1 m8 L7 [7 a* \) V0 r) X# K

2 Y2 k# a% L1 }  @+ X, i  BASE_NAME告诉编译器最终生成的驱动的名字。' g/ X) C) m8 V" R$ [* P
  FILE_GUID就是这个驱动的GUID名字,在BIOS中引用某个驱动就是根据它来调用和识别。
$ m& o5 k2 @$ l% z) H" [  COMONENT_TYPE会告诉编译器生成驱动的类型,是PEI,DXE,等。0 H7 u  g' G, y3 W; f; L5 L* ]
  在EDK中有一个FWVolume.c实现的功能就是帮我们把这个TYPE转换面相应的扩展名6 y9 o$ j' o" K
  COMP_TYPE_EXTENSION  mCompTypeExtension[] = {
/ T! n8 Y$ U" |$ _  {"bs_driver",  ".dxe" },
" \3 z. P) B, S- W) V  {"rt_driver",  ".dxe" },
6 g0 ~# |( r( M+ }+ E  {"sal_rt_driver", ".dxe"},
5 W5 O, f1 f  s6 D2 D! ~  {"security_core", ".sec"},5 c; c% F  L  l
  {"pei_core", ".pei"},) g1 d4 \; P( ^+ v* G$ a3 @
  {"pic_peim", ".pei"},
0 H- [/ l2 D, M* J/ B- k  {"pe32_peim", ".pei"},
! X% ^  B; k* Z6 f, m9 z3 {+ [  {"relocatable_peim", ".pei"},) E1 _7 V! [* B! {7 H$ F+ x
  {"binary", ".ffs"},
& [% w% G# u( y  {"application", ".app"},. L; _5 p: ^+ V9 U3 R$ |+ x" ~; A
  {"file", ".ffs"},
# v3 w' q' J# l3 h8 _& L( e- _  {"fvimagefile", ".fvi"},
6 r: K* ]& [+ [; U* E7 L0 w! H  {"rawfile", ".raw"},* Y" z5 D2 F0 x3 @# V! n
  {"apriori", ".ffs"},; i2 C" X  |* A8 F& c' h
  {"combined_peim_driver", ".pei"},
1 V2 j& n7 _( z# d& @9 Q  { NULL,  NULL }5 o; s6 P* c3 m1 T
};8 K/ r3 c* |2 \  L- ]

7 w8 u' `* M( W7 |了解了这些,接下我们可以看驱动篇了。(Go On Study... Forever)- w5 z; f" H  V6 Y' m5 o
   
- O4 s! O( _- u* _7 D! @  |         
) r& N  M0 H) ~% h0 X  
发表于 2008-7-27 12:30:15 | 显示全部楼层
不错!
* z6 H& v0 y4 I2 F- C$ I, l! K2 |* ~  A支持) V* R8 N1 m2 |, x$ ^
继续
8 G( ]5 w: p  q加油: V: C# Q0 k7 d3 J
回复

使用道具 举报

发表于 2008-7-27 18:54:53 | 显示全部楼层

回复 1# 的帖子

gPrivateDispatchTable 和COMP_TYPE_EXTENSION  没有搜到啊  是EDK专有的么?
% ~6 Z/ p. F& i) B% a1 `有看过跟gPrivateDispatchTable 类似的,但是里面的PPI不同。$ k8 m- }% F2 n7 x. v+ @) R
还有这个COMP_TYPE_EXTENSION  没有找到过。FWVolume.c这个文件也没有发现。。
回复

使用道具 举报

发表于 2008-7-28 13:24:20 | 显示全部楼层
这东西虽说没有什么技术含量,但是总结一下还是非常好的。
( _9 A$ n3 d3 ?" ]& \0 Z: g! v% E- i/ j
支持!
回复

使用道具 举报

 楼主| 发表于 2008-7-28 18:52:31 | 显示全部楼层

7 |# r; v& |4 B8 m( u- C小弟还在学习阶段,目前的目标是知道执行的流程。
' r3 }# N( ]4 Z' j9 y这里面有很多细节没有写,能力有限,只能自己知道,不能表达。
  @9 p4 a' U1 O* x3 p) g4 F嘿。。。。
% R1 _0 c5 k. A  S5 D所有大侠们如果有好东西能给小弟共享一份。9 r/ b$ f# r" c3 V4 b
& Z4 {: m4 Q. ?) b2 V* l8 i
谢谢!
回复

使用道具 举报

发表于 2008-8-12 14:44:11 | 显示全部楼层
原帖由 winbondowen 于 2008-7-27 00:11 发表
. h3 e6 i9 H# w  ROM中將DXE的驅動讀出,執行執行他們,這時會執行到Driver
$ k/ a2 v+ t5 I2 U4 j中的Support(),Start()兩個功能函數。在這兩個函數中你可以註冊自己的PPI ...

8 Z: \6 O- e' s) E
4 Y# d, [6 i7 HPPIs are registered during PEI phase, but Support()/Start() are invoked in DXE driver binding protocol,
7 B( u% w8 D" {# G  W& PFor more precisely, I think the "PPI" you mentioned is the "PROTOCOL" rather than "PPI".
+ X' k) X* [% Y1 E# \2 D/ C
4 j; O  i/ X; N; P' _9 P' [[ 本帖最后由 ichirohiro 于 2008-8-13 13:32 编辑 ]
回复

使用道具 举报

发表于 2008-8-16 11:08:26 | 显示全部楼层
学习心得写了这么多 支持一下~!
回复

使用道具 举报

发表于 2008-8-17 09:48:13 | 显示全部楼层

回复 3# 的帖子

gPrivateDispatchTable 和COMP_TYPE_EXTENSION是EDK专有
回复

使用道具 举报

 楼主| 发表于 2008-8-17 09:53:39 | 显示全部楼层
To ichirohiro:
  P$ Y2 b4 y, `7 K& a6 X   Yes. I make a mistake., ]2 s9 m5 g  l. o9 r( p: r
      PPI:     A PEIM to PEIM interface.
/ G4 x3 B! Z2 W8 Y9 n1 w; {      PROTOCL: A Interface between Hardware(or firmware) and software.4 i9 U0 X4 W  G3 h
      reference[http://www.biosren.com/viewthread.php?tid=207], n  `9 v  R& L- l4 l3 j" M
   so, PPI execute at PEI step and Initialize hardware. PROTOCOL execute by DXE step.
5 {4 a1 q" K7 T1 m( X, e& \# d) C- u$ T0 i   Thanks.
回复

使用道具 举报

发表于 2008-8-20 17:47:21 | 显示全部楼层
原帖由 winbondowen 于 2008-7-27 00:11 发表 DXE:( r; N1 S' }* }: t4 A
     從PEI到DXE切換時轉過來一個HOBLIST參數,DXE會在這個HOB中找到Memory的使用情況,然後根據這些情況將BIOS引到內存(這是EFI的做法)。在EDK在DXE時重新定位一下內存。
- y4 ]2 M" F: M2 o2 W接著就會定義我們經常使用到的gST表,gRT表。接著是申明一些Protocol(先不關心這些事)。4 X" x* i. E* N6 [5 o+ G8 p; y, z: t8 W
   等這些該加的PPI,Protocol加完了,CoreDispatcher()就出場了。他會的功能類似PEIDispatcher()。從我們BIOS ROM中將DXE的驅動讀出,執行執行他們,這時會執行到Driver
8 r* v$ l% f) \: ^- M# z& A中的Support(),Start()兩個功能函數。在這兩個函數中你可以註冊自己的PPI,為其他驅動提供服務。
0 s) M# c" P3 C5 b   到些BIOS的引導其他完成。接著該進OS了,看Linux 0.11吧,操作系統是怎麼做事情的。.
, {" r0 V! W+ e, n9 g- E

* A$ X4 w& Y+ g2 v; @There are mistakes,5 c' g4 ~) a# ?* m0 h4 ]5 A
1.gST and gRT are init after the DXE architectural protocols have been loaded, those protocols response for creating Dxe foundation.8 S: r* W, [' W! V5 p

# J+ Z8 q. f, o" v9 a  k2.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.# V! q' G; g2 h2 @
The CoreDispatcher() executes all trusted Dxe drivers and just register the Binding protocol if the driver is EFI1.1 driver model.8 d' I% n4 ^7 p4 S
Furthermore, Support()/Start() are invoked in BDS phase over the CoreConnectController() rather than CoreDispatcher()., W7 R- }) k- p! n9 M+ f5 k

" V, z7 ~/ _; k, nBTW, please excuse my English, since I come from Taiwan and without Simplified Chinese typing interface.
回复

使用道具 举报

发表于 2008-8-22 14:25:59 | 显示全部楼层
请问各位大虾,EDK从哪下阿?
回复

使用道具 举报

发表于 2008-8-23 09:00:12 | 显示全部楼层
回复

使用道具 举报

 楼主| 发表于 2008-8-25 23:02:01 | 显示全部楼层
感谢 ichirohiro 大侠的指点。7 ~0 z" ~$ V4 z$ \6 C
回复

使用道具 举报

发表于 2008-9-18 15:22:34 | 显示全部楼层

CoreDispatcher()时,真的不会执行"Support()/Start()"吗?

原帖由 ichirohiro 于 2008-8-20 17:47 发表 ) g9 w! ?$ h2 i! C+ i- i& j
...
: ^& s* |) L+ N* C2.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.- j. \5 l% y5 u/ N1 V1 _
The CoreDispatcher() executes all trusted Dxe drivers and just register the Binding protocol if the driver is EFI1.1 driver model.
9 P! Q) [* c/ s2 p2 t3 f, MFurthermore, Support()/Start() are invoked in BDS phase over the CoreConnectController() rather than CoreDispatcher().
* X& E; G5 J4 g1 E/ D
    在Framework的spec DxeCis.pdf里面也是这么说的,DXE CoreDispatcher()里面,对于EFI1.1 driver model的driver只会安装Handler和Interface到Binding protocol,到BDS才会去执行Support()和Start().
  @" W6 n# @8 ?: G6 t# M0 N+ Q    但是,我在看code时,发现在CoreDispatcher()-->CoreStartImage()里面call image之后有这么一句:  (file:image.c)
$ K" h# q. ~, o' Y  j* C! v, t9 n  //  H% R3 N: t$ [" S/ K! [
  // Go connect any handles that were created or modified while the image executed.
0 [  u, q6 s4 I2 ~  //* A% I0 q( M, n& f
  CoreConnectHandlesByKey (HandleDatabaseKey);
7 l1 s$ m) `( C. U  y
这里的HandleDatabaseKey是call image之前由CoreGetHandleDatabaseKey()得到的gHandleDatabaseKey' f, C* t/ `5 ^2 b
而CoreConnectHandlesByKey会调用到:" y  G* X$ e$ S+ Y0 i. u* H) ?
  //
9 o% I; U% w- M/ z1 M- q  // Connect all handles whose Key value is greater than Key
( o( }! i. ?, K3 Z8 \  //
/ k) i9 X4 _+ |5 b- |3 n" k  for (Index = 0; Index < Count; Index++) {
) l2 Z2 q" H: u7 E) ?    CoreConnectController (HandleBuffer[Index], NULL, NULL, TRUE);
' t$ }. e& n. K( ?' z! n8 c- g  }
0 p3 K& z2 Y) F: G- x% Q
所以,照code看,当在Driver中安装一个Handle和Interface到Binding Protocol后(gHandleDatabaseKey会++,IHandle的Key=gHandleDatabaseKey)2 [, K% q* `5 w6 v. ~, U( {
是会去ConnectController的,也会执行对应的Support()和Start()才对!!
# R6 E" C- P* A4 p! m: N8 o- R8 I, F7 z1 @* B0 M
不知道我想的哪里有问题???欢迎大家指正.
0 t% }  n& g8 V- C# ~3 I0 O  b$ [, @/ Q$ g) ^7 S6 O( D* g
[ 本帖最后由 xtdumpling 于 2008-9-18 15:25 编辑 ]
回复

使用道具 举报

发表于 2008-9-19 14:44:41 | 显示全部楼层
这段code似乎是一个向后兼容的行为,不必太care。
" \! D4 q) {( Y' @/ @/ f一个UEFI driver model driver一般只会在ImageHandle上装EFI Driver Binding Protocol,而ImageHandle在CoreStartImage()之前已经存在,所以不会导致Handle database key增加,所以不会触发ConnectController()。当然,如果一个UEFI driver model driver在入口函数中创建了新的handle,是会触发CoreConnectController()的。
回复

使用道具 举报

发表于 2008-9-19 18:10:21 | 显示全部楼层
了解了.
5 j' x0 f- R( j  e* C非常 感谢!!!
回复

使用道具 举报

发表于 2008-9-23 16:48:56 | 显示全部楼层
在读DXEmain时,: \) p3 v+ T9 [- x8 V3 s  j
Status = CoreInitializeImageServices(HobStart);--->CoreInstallProtocolInterface();--->CoreInstallProtocolInterfaceNotify();中,
3 p4 f7 p. \5 Y! ~/ d//% i/ T+ R7 d$ J. S8 v; v  |: n* m
// Notify the notification list for this protocol.
7 U! H/ n" v0 d: T: |" p: j//
) M' a$ {" p4 Y- d8 jif (Notify) {$ L4 u( [  W4 w" t
  CoreNotifyProtocolEntry(ProtEntry);) `1 r9 a: M8 r: c% b
}    里Signal了Event. MS是说一个handle安装了一个protocol后就signal一次.
$ s& j' f3 s: O4 l有个问题请教一下大家: 这段是在DXE很靠前的位置执行的,但是在它之前我没有看到DXE中有相关的CreateEvent出现?哪位高手能说说这部分代码的流程呢?
回复

使用道具 举报

发表于 2008-9-23 17:04:14 | 显示全部楼层
原帖由 xtdumpling 于 2008-9-16 13:34 发表 3 }) I4 x- z( M5 H4 u4 f
请楼上的兄弟分析下BS的RegisterProtocolNotify也就是CoreRegisterProtocolNotify是做什么用的?怎么用?- n* |* Y1 J7 s& Q- O+ j! Q  F; q+ W
谢谢!

* a. Z8 I! [. N7 w3 [+ v......
- @4 `: |7 F. w+ }
; E( v0 Y' `8 ?$ ]5 Z
% P0 V( U# c: f6 k6 S, p# ?[ 本帖最后由 xtdumpling 于 2008-9-23 17:24 编辑 ]
回复

使用道具 举报

发表于 2008-9-24 12:43:45 | 显示全部楼层
原帖由 xtdumpling 于 2008-9-23 17:04 发表 * G$ H) B5 ~% f

/ F" b. M2 \' E: a0 R. z......
+ l) r3 _  D5 C3 J
% W# F4 [$ x  @2 W' I
Signal的Event是不是在各个TPL级上挂载一些待处理的事件,一旦restore(TPL)的话,比当前TPL级高的pending事件就回被处理掉?. J; ?, O$ H/ @1 \! E! e- {, t
如果是这样的话,Timer事件是如何处理的呢,没有找到相关的代码呀?Xt指点一下再~
回复

使用道具 举报

发表于 2008-9-24 19:00:46 | 显示全部楼层
Timer是挂在8259的IRQ0的中断处理程序上面的, 大概每秒18.3次调用CoreTimerTick()-->CoreCheckTimers()" o* d% v1 M6 z- W: A
TPL=30
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 加入计匠网

本版积分规则

Archiver|手机版|小黑屋|计匠网

GMT+8, 2026-3-15 06:45 , Processed in 0.268938 second(s), 17 queries .

Powered by Discuz! X3.5

© 2001-2025 Discuz! Team.

快速回复 返回顶部 返回列表