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

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

[复制链接]
发表于 2008-7-27 00:11:28 | 显示全部楼层 |阅读模式
  最近在工作看到机台有启动过程中把SPI ROM数据清空,但苦与没有办法很好的Debug(PCA没有架起来),所有与EDK为对象好好的读了一把。
. Q6 o2 d6 h1 F( Y: p$ J
" S+ A& r) {. L0 B$ USEC/CEI:
/ m) H  h  ~: l  v! n4 D& J; L  UEFI BIOS启动时先会执行SEC/CEI,这个阶段在实现的BIOS Code中初始化Debug Port,进入Big Mode,CPU的MicroCode,CacheToRAM的转换.然后跳转到PEI阶段。
- r9 e# A/ g! r8 F6 d7 d在EDK中这部分被成了Load FvRecovery.fd文件,这个文件类似与我们的BIOS ROM.里面是我们编译后生成的二进制代码。在这个阶段最主要的是将这个文件加载到内存中(Windows API将文件加载到内存,看API函数).
" A" ~& n' x) b8 f$ }# ~* U5 @4 h9 {# m: V. b' b- E
PEI:  ~& l" z, E2 R& D
   从这里开始UEFI BIOS和EDK执行基本相同,只是一个是从SPI ROM中定位一个地址(PEIM的开始地址),一个是从内存中定位一个地址(PEIM的开始地址)。从这里开始只讲EDK的执行
- f6 P$ c4 U! I  z  EDK调用InitializeMemoryService函数,将HobList清空,peiservice清空。+ q5 j3 }5 N3 j" Q1 e
      InitializePPIService函数,将PPI队列清空,这个队列长0x3F.: o* n( d1 n9 Y
          InitializeSercurityService函数,将Notify队列清空。& V$ p$ Q1 V& z& C9 I0 y0 X' v2 v
          InitializeDispatcherData函数,将Dispatcher队列清空。
9 v1 y8 E* t  g" M  接着由PeiBuildHobGuid来建立一个HOB(S3返回时这时应该有这个HOB,不用建立,直接使用了,这样就会进入另外一个流程,可以这个EDK不能调试S3,不知道怎么走)。然后由(*PeiServices)->InstallPpi()将这个新HOB加入到PPI中。
# B* ~  D& V! h. u, E( F9 k+ h    由于在SEC阶段转了以下这几具PPI,所以在执行PEI的Dispatcher之前会先安装东西:% m* S" H" I$ H' {" z2 X
      EFI_PEI_PPI_DESCRIPTOR    gPrivateDispatchTable[] = {
* }" ]: e$ L) p! @9 M8 S       {EFI_PEI_PPI_DESCRIPTOR_PPI, &gEfiNtLoadAsDllPpiGuid, &mSecNtLoadAsDllPpi},
8 r# [) P" y5 u       {EFI_PEI_PPI_DESCRIPTOR_PPI, &gNtPeiLoadFileGuid, &mSecNtLoadFilePpi},
1 H) Z* e9 q7 A% o  c* r5 e2 |2 E       {EFI_PEI_PPI_DESCRIPTOR_PPI, &gPeiNtAutoScanPpiGuid, &mSecNtAutoScanPpi},
; X1 z  J5 E8 _0 f% `       {EFI_PEI_PPI_DESCRIPTOR_PPI, &gPeiNtThunkPpiGuid, &mSecWinNtThunkPpi},
) _9 c1 j' m5 }/ @" S7 v0 p% \1 {       {EFI_PEI_PPI_DESCRIPTOR_PPI, &gPeiStatusCodePpiGuid, &mSecStatusCodePpi},
+ M8 j; [+ g; C1 X* L       {EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST, &gNtFwhPpiGuid, &mSecFwhInformationPpi}
0 x; L% d- a% B( t% x, a9 c     };
# a$ Y! |" R: p0 S& Y1 I) h    每个PPI是由{类型,GUID(名字,以后就根据这个来找到它的),Function_Entry_Address}组成。# a3 |' @5 O$ ~; W/ y( W
   这些PPI会在PEIDispatcher中用到。
' s6 E$ l% Q3 L) o# U   安装完这此东西这开始执行PEIDispatcher函数,函数从BIOS ROM文件中找出PEI的Image(怎么找到,请读一下FV_HEAD(EFI_HEAD),里面讲到了如何区分Image类型),然后定位到PEI Image的入口地址,执行他。在我们的的PEI中,我们一般会申明一个PPI,这个就是这个PEI提供一些服务,PEIDispatcher会将他们加入到PPI-List中,以后其他Image也可以调用他的提供的功能。
% D5 }5 c2 Y9 {+ T2 {   最后EDK会加载一个叫DXEIPL的PEI,DXEIPL提供一个PPI服务,这个PPI的功能是实现从PEI到DXE的切换,这个PPI里面为DXE做了很多的预准备,加载了很多PPI,如对BIOS的解压方法等。
" E. Z) ]4 ^5 F   SwitchStacks (8 N; E, L/ c4 t) U; z
       (VOID *) (UINTN) DxeCoreEntryPoint,
! x# E7 J' V9 ~$ s       (UINTN) (HobList.Raw),! y9 S* E- q9 [) d; q' ]2 ^% p
       (VOID *) (UINTN) TopOfStack,
# z2 j! l* E: D# Q3 m/ s       (VOID *) (UINTN) BspStore- w; ~$ M5 o7 R: x
    );
/ N3 S, _/ W  Z; @  用过汇编的人对这个技术一定很熟悉,不多说了(我别不清,咯。。。)
0 C% p- j5 a+ f2 k# h
% g0 z9 y: b; m6 T  n7 Z7 f9 kDXE:
" d  W8 }! e+ c: V; d' `     从PEI到DXE切换时转过来一个HOBLIST参数,DXE会在这个HOB中找到Memory的使用情况,然后根据这些情况将BIOS引到内存(这是EFI的做法)。在EDK在DXE时重新定位一下内存。3 |! v. C# d- A! _* P  L
接着就会定义我们经常使用到的gST表,gRT表。接着是申明一些Protocol(先不关心这些事)。
! h4 `. O- r* C/ j' t, e   等这些该加的PPI,Protocol加完了,CoreDispatcher()就出场了。他会的功能类似PEIDispatcher()。从我们BIOS ROM中将DXE的驱动读出,执行执行他们,这时会执行到Driver
% J2 x2 y* r+ w中的Support(),Start()两个功能函数。在这两个函数中你可以注册自己的PPI,为其他驱动提供服务。6 @- R1 d: U! K( u& [- H
   到些BIOS的引导其他完成。接着该进OS了,看Linux 0.11吧,操作系统是怎么做事情的。
, i; o" @& W% _2 }   
% f0 X% e  l8 eDriver:
* S+ Z7 p) y5 Y    我们的驱动什么为在PEI和DXE等不同阶段执行呢?( i# H& O" ~" ~/ x" D
  大家请看一下我们的驱动的makefile.(EDK中的*.inf)
! ?' H$ b% ~% P, L  [defines]7 s* e# t: v* s; C
  BASE_NAME            = OWEN1 m$ S. ^& y" H2 e: c$ X
  FILE_GUID            = 1EDD13C1-62EF-4262-A1AA-0040D0830110+ d) \- E/ C; V3 x
  COMPONENT_TYPE       = BS_DRIVER
: I- ~. G! r, s3 z, B0 F3 U$ W7 p; C+ Y' x. l
  BASE_NAME告诉编译器最终生成的驱动的名字。
5 }8 j# \2 R) D  FILE_GUID就是这个驱动的GUID名字,在BIOS中引用某个驱动就是根据它来调用和识别。
2 m* a0 z3 W! K1 D: F) Z0 A3 g2 c8 o  COMONENT_TYPE会告诉编译器生成驱动的类型,是PEI,DXE,等。
% _7 B; C, W6 D# x* b  在EDK中有一个FWVolume.c实现的功能就是帮我们把这个TYPE转换面相应的扩展名
; o! x; C5 n8 [. j/ |& s- d+ e* |  COMP_TYPE_EXTENSION  mCompTypeExtension[] = {- ~7 ^/ V) W4 K/ Y3 s9 W& c% g
  {"bs_driver",  ".dxe" },
6 K1 J$ f: P# G1 N! C, D: K( d+ s4 a  {"rt_driver",  ".dxe" },
# _6 G6 D  b) ^+ I  {"sal_rt_driver", ".dxe"},* ]$ u  c4 Z" j
  {"security_core", ".sec"},
; \5 ^, B5 g1 D/ s" w8 A" I  W  {"pei_core", ".pei"},- Z: c  Q1 c! r. P! g2 y5 Q7 n
  {"pic_peim", ".pei"},
& s6 D( J8 B& M, K+ w  {"pe32_peim", ".pei"},
$ f8 K- w- [! V  {"relocatable_peim", ".pei"},# R2 G4 w. `  |- J: M
  {"binary", ".ffs"},2 W* S- X% i& s0 {% U& y
  {"application", ".app"},
4 N" X1 f+ m$ t# W: y  {"file", ".ffs"},. \5 v2 b1 W' z
  {"fvimagefile", ".fvi"},: s& t3 ~0 Y; S- H% P1 N2 b
  {"rawfile", ".raw"},
8 U0 z- e5 s  C7 L- O" t  N: ]  {"apriori", ".ffs"},
5 c9 u0 I0 C; a5 Q0 m2 Y, X7 f  {"combined_peim_driver", ".pei"},
5 k8 b7 i% p1 c2 H6 t9 n- b  { NULL,  NULL }
! H; v" Q% ?& G, C" Z$ X1 W};8 \/ ~) k+ p) p
* k3 H0 g" b. K" S# h6 R, Q
了解了这些,接下我们可以看驱动篇了。(Go On Study... Forever)
; y3 |/ \8 x  k/ I   ; G" ?$ }5 ~8 X2 m* T! H1 q# G
         
; E$ ^  l& k& U4 M: l6 S! w  
发表于 2008-7-27 12:30:15 | 显示全部楼层
不错!* d  D8 Q! x1 l, h  f
支持
9 {* Y8 b% @/ ~+ i继续
# F; a& K- h2 B& X加油9 j4 |# a1 m2 @! y0 Q& j
回复

使用道具 举报

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

回复 1# 的帖子

gPrivateDispatchTable 和COMP_TYPE_EXTENSION  没有搜到啊  是EDK专有的么?9 X$ Y' K3 h+ r- N/ s$ D5 V
有看过跟gPrivateDispatchTable 类似的,但是里面的PPI不同。9 R; i! }! x3 h, K+ l+ D/ Q$ `4 ~
还有这个COMP_TYPE_EXTENSION  没有找到过。FWVolume.c这个文件也没有发现。。
回复

使用道具 举报

发表于 2008-7-28 13:24:20 | 显示全部楼层
这东西虽说没有什么技术含量,但是总结一下还是非常好的。! Q- l' S; z& e8 I! {+ n) o

7 Y+ H" u4 ^6 V/ o1 u$ _, |0 T. K: D- b支持!
回复

使用道具 举报

 楼主| 发表于 2008-7-28 18:52:31 | 显示全部楼层
' A7 C" p. e  @9 J2 V6 h
小弟还在学习阶段,目前的目标是知道执行的流程。
1 s3 l6 R4 _" e/ m, u  n9 V这里面有很多细节没有写,能力有限,只能自己知道,不能表达。
' e# Q! i% R7 d+ i嘿。。。。
+ ~" \* |8 w! [& N/ t3 n4 Z所有大侠们如果有好东西能给小弟共享一份。
6 }$ A! ?# [  q: m& {
0 C3 K( z2 [$ g8 \4 X谢谢!
回复

使用道具 举报

发表于 2008-8-12 14:44:11 | 显示全部楼层
原帖由 winbondowen 于 2008-7-27 00:11 发表
) }. U+ [5 w; J3 E  ROM中將DXE的驅動讀出,執行執行他們,這時會執行到Driver* V+ k4 _/ v: W6 @( C  O; N
中的Support(),Start()兩個功能函數。在這兩個函數中你可以註冊自己的PPI ...
8 y4 b* E3 |  K; {
- i1 D9 c  C$ q+ B( y7 b9 C
PPIs are registered during PEI phase, but Support()/Start() are invoked in DXE driver binding protocol,
3 z- h4 S  x. t7 w' @' X+ p# N, |, BFor more precisely, I think the "PPI" you mentioned is the "PROTOCOL" rather than "PPI"., C" ?7 z# K/ x, C+ b* e/ {8 b
: U" a- A6 O- k% |3 d
[ 本帖最后由 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:
* n/ @0 ^. T$ g  s   Yes. I make a mistake.' F5 x  a! V3 l, u, v
      PPI:     A PEIM to PEIM interface., L  r1 C( O/ ?1 f) c- R( C4 ]) I
      PROTOCL: A Interface between Hardware(or firmware) and software.3 [3 T2 {4 A: P
      reference[http://www.biosren.com/viewthread.php?tid=207]+ L3 q% n9 l( u3 @( o. W
   so, PPI execute at PEI step and Initialize hardware. PROTOCOL execute by DXE step.4 s9 T; N" z( K4 x; z) [- `. V
   Thanks.
回复

使用道具 举报

发表于 2008-8-20 17:47:21 | 显示全部楼层
原帖由 winbondowen 于 2008-7-27 00:11 发表 DXE:
" b, H& f: q/ n6 E) J     從PEI到DXE切換時轉過來一個HOBLIST參數,DXE會在這個HOB中找到Memory的使用情況,然後根據這些情況將BIOS引到內存(這是EFI的做法)。在EDK在DXE時重新定位一下內存。
- H) z0 B! D8 g接著就會定義我們經常使用到的gST表,gRT表。接著是申明一些Protocol(先不關心這些事)。9 ^( I8 d2 r# |; z* s
   等這些該加的PPI,Protocol加完了,CoreDispatcher()就出場了。他會的功能類似PEIDispatcher()。從我們BIOS ROM中將DXE的驅動讀出,執行執行他們,這時會執行到Driver7 T7 c  r+ B7 x$ k" Q/ {
中的Support(),Start()兩個功能函數。在這兩個函數中你可以註冊自己的PPI,為其他驅動提供服務。+ p+ q: A9 T1 O8 o
   到些BIOS的引導其他完成。接著該進OS了,看Linux 0.11吧,操作系統是怎麼做事情的。.
/ Z1 A- i' c. ]! w& i

2 r; ~9 m( |4 P* ]There are mistakes,. {; `( N# U9 i1 R8 V
1.gST and gRT are init after the DXE architectural protocols have been loaded, those protocols response for creating Dxe foundation.
# K, x- a* o7 Y( Q
2 U3 M) u0 i8 C- o6 G% F, ]  Z2.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.
* m, W2 h$ ~5 ^  z% F, f6 iThe CoreDispatcher() executes all trusted Dxe drivers and just register the Binding protocol if the driver is EFI1.1 driver model.7 P& Z6 m+ [# f7 X0 N- G8 n
Furthermore, Support()/Start() are invoked in BDS phase over the CoreConnectController() rather than CoreDispatcher().
8 h9 k5 @* X* R7 z. r% S# x
4 r1 v$ {- z' y9 @. E( ^BTW, 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 大侠的指点。
3 |; `' I: H1 ?) R0 x
回复

使用道具 举报

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

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

原帖由 ichirohiro 于 2008-8-20 17:47 发表
  M" R2 J6 r# u* z! h8 d* M...
; [' b0 @# v; o0 ]% `$ v( D3 J2.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.
& {. }  S2 c  K9 R9 dThe CoreDispatcher() executes all trusted Dxe drivers and just register the Binding protocol if the driver is EFI1.1 driver model.
( a. f; @1 R& M& B* h6 ^Furthermore, Support()/Start() are invoked in BDS phase over the CoreConnectController() rather than CoreDispatcher().
: _: `) [' E, k; f- R6 _
    在Framework的spec DxeCis.pdf里面也是这么说的,DXE CoreDispatcher()里面,对于EFI1.1 driver model的driver只会安装Handler和Interface到Binding protocol,到BDS才会去执行Support()和Start().
9 U' R' P9 c- z2 j( S3 G    但是,我在看code时,发现在CoreDispatcher()-->CoreStartImage()里面call image之后有这么一句:  (file:image.c)2 Q! j" o3 C, n9 T8 n; g) N4 K
  //
4 e& {  ~1 w7 j" E/ z: K9 R  // Go connect any handles that were created or modified while the image executed." X9 B! o; l3 Y, E0 s3 d0 ?0 [
  //
5 s1 k9 O0 ~9 U/ S- ~  CoreConnectHandlesByKey (HandleDatabaseKey);
6 e4 c, i$ f0 O% I1 ?
这里的HandleDatabaseKey是call image之前由CoreGetHandleDatabaseKey()得到的gHandleDatabaseKey9 J: S% B% k0 y) T
而CoreConnectHandlesByKey会调用到:9 X, g" x7 ^! O, p4 u- \: e
  //! }' F6 R+ |. p, B) y
  // Connect all handles whose Key value is greater than Key7 d% B* Y$ F6 S& l8 B1 X$ h
  //$ Q) {. o+ j' d& W! j
  for (Index = 0; Index < Count; Index++) {; o* I  W9 z. Z: G. h
    CoreConnectController (HandleBuffer[Index], NULL, NULL, TRUE);  `. U! N/ [1 {! {+ l
  }
) Y$ N; E; `; n7 E6 w7 X
所以,照code看,当在Driver中安装一个Handle和Interface到Binding Protocol后(gHandleDatabaseKey会++,IHandle的Key=gHandleDatabaseKey)7 ~) T6 P1 L0 {4 C  i# y
是会去ConnectController的,也会执行对应的Support()和Start()才对!!3 M6 A# C/ N, j4 J
& r1 Z5 Y  j" _% K( @; h, }/ ^
不知道我想的哪里有问题???欢迎大家指正.0 t/ M. a, {: E$ ^8 B" S3 G
" Y' o! b' h) W$ B; V5 o
[ 本帖最后由 xtdumpling 于 2008-9-18 15:25 编辑 ]
回复

使用道具 举报

发表于 2008-9-19 14:44:41 | 显示全部楼层
这段code似乎是一个向后兼容的行为,不必太care。- j, _2 z* I# R2 l! K
一个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 | 显示全部楼层
了解了.
3 g2 p/ }6 y! T# j! |非常 感谢!!!
回复

使用道具 举报

发表于 2008-9-23 16:48:56 | 显示全部楼层
在读DXEmain时,
6 A" ]$ ]; y' E$ E( ^+ ], UStatus = CoreInitializeImageServices(HobStart);--->CoreInstallProtocolInterface();--->CoreInstallProtocolInterfaceNotify();中,
7 Y& O1 S8 Y2 N3 X//
. a- U: o0 F# O! R' `// Notify the notification list for this protocol.
' ]7 ]2 z/ e* I+ q4 X) q//
% _5 o! W+ R: Q1 }, @7 Yif (Notify) {' {$ C% t* `$ _8 h6 ?" m4 n
  CoreNotifyProtocolEntry(ProtEntry);
9 s, c' T0 s) q4 r  I7 |4 f7 ?0 U}    里Signal了Event. MS是说一个handle安装了一个protocol后就signal一次.$ m5 v, [/ O' u# p7 i1 A; z4 ]
有个问题请教一下大家: 这段是在DXE很靠前的位置执行的,但是在它之前我没有看到DXE中有相关的CreateEvent出现?哪位高手能说说这部分代码的流程呢?
回复

使用道具 举报

发表于 2008-9-23 17:04:14 | 显示全部楼层
原帖由 xtdumpling 于 2008-9-16 13:34 发表 ! R7 Z+ z0 M( [, L' m0 K
请楼上的兄弟分析下BS的RegisterProtocolNotify也就是CoreRegisterProtocolNotify是做什么用的?怎么用?
' L8 V, _5 w8 J5 u% o谢谢!

4 f; s4 e$ i. z4 G* C......
! M, c0 d/ o6 m7 o/ r# _- f! M: F# z2 _: i0 v9 Q4 p* b

8 ?4 I/ _2 J! h: N[ 本帖最后由 xtdumpling 于 2008-9-23 17:24 编辑 ]
回复

使用道具 举报

发表于 2008-9-24 12:43:45 | 显示全部楼层
原帖由 xtdumpling 于 2008-9-23 17:04 发表
' S5 e+ W3 Y- s
" y( G) y- n2 z......
! A8 Z' s" G. f' ]* F9 a/ g% i/ u8 {

  U6 k3 k9 b4 ^. _Signal的Event是不是在各个TPL级上挂载一些待处理的事件,一旦restore(TPL)的话,比当前TPL级高的pending事件就回被处理掉?+ x1 f! M% `, [) ~: @1 X
如果是这样的话,Timer事件是如何处理的呢,没有找到相关的代码呀?Xt指点一下再~
回复

使用道具 举报

发表于 2008-9-24 19:00:46 | 显示全部楼层
Timer是挂在8259的IRQ0的中断处理程序上面的, 大概每秒18.3次调用CoreTimerTick()-->CoreCheckTimers()
0 {% X8 E) W" L% WTPL=30
回复

使用道具 举报

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

本版积分规则

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

GMT+8, 2026-8-11 18:50 , Processed in 0.114732 second(s), 16 queries .

Powered by Discuz! X3.5

© 2001-2025 Discuz! Team.

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