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

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

[复制链接]
发表于 2008-7-27 00:11:28 | 显示全部楼层 |阅读模式
  最近在工作看到机台有启动过程中把SPI ROM数据清空,但苦与没有办法很好的Debug(PCA没有架起来),所有与EDK为对象好好的读了一把。
& W$ ~& p1 q8 X5 Z" H& v# F2 ~* _2 D  Z
SEC/CEI:" {: o; P# ^7 x( f. E
  UEFI BIOS启动时先会执行SEC/CEI,这个阶段在实现的BIOS Code中初始化Debug Port,进入Big Mode,CPU的MicroCode,CacheToRAM的转换.然后跳转到PEI阶段。
, b; {5 Z  \' j7 c+ G在EDK中这部分被成了Load FvRecovery.fd文件,这个文件类似与我们的BIOS ROM.里面是我们编译后生成的二进制代码。在这个阶段最主要的是将这个文件加载到内存中(Windows API将文件加载到内存,看API函数).9 O2 B7 N. G6 c. J: x6 Q6 ]  _6 ?
$ Y, h( ^0 J  u8 _9 M) x1 R! Q  H
PEI:! m6 J; U) o) f% x9 V: }4 w: V
   从这里开始UEFI BIOS和EDK执行基本相同,只是一个是从SPI ROM中定位一个地址(PEIM的开始地址),一个是从内存中定位一个地址(PEIM的开始地址)。从这里开始只讲EDK的执行
) W2 g% @+ e' D' m% i5 q7 v  EDK调用InitializeMemoryService函数,将HobList清空,peiservice清空。
" b  R8 D) v: @4 D/ z. L% k      InitializePPIService函数,将PPI队列清空,这个队列长0x3F.! [) Z3 Z5 ^9 _, C# b6 C, I
          InitializeSercurityService函数,将Notify队列清空。
: ?# a6 H7 q$ }9 u. b          InitializeDispatcherData函数,将Dispatcher队列清空。
$ _" t" X/ ]% e1 T) v  接着由PeiBuildHobGuid来建立一个HOB(S3返回时这时应该有这个HOB,不用建立,直接使用了,这样就会进入另外一个流程,可以这个EDK不能调试S3,不知道怎么走)。然后由(*PeiServices)->InstallPpi()将这个新HOB加入到PPI中。6 p% n; S6 V+ }  O( o; G+ p
    由于在SEC阶段转了以下这几具PPI,所以在执行PEI的Dispatcher之前会先安装东西:
: o* ?9 z. i' I/ r8 j9 d  V! D. F      EFI_PEI_PPI_DESCRIPTOR    gPrivateDispatchTable[] = {( N1 {+ i0 t6 m) e  ~2 J
       {EFI_PEI_PPI_DESCRIPTOR_PPI, &gEfiNtLoadAsDllPpiGuid, &mSecNtLoadAsDllPpi}," t- w' w4 B7 W3 o* Y' ?4 c
       {EFI_PEI_PPI_DESCRIPTOR_PPI, &gNtPeiLoadFileGuid, &mSecNtLoadFilePpi},
2 [' l; f; T  V; H       {EFI_PEI_PPI_DESCRIPTOR_PPI, &gPeiNtAutoScanPpiGuid, &mSecNtAutoScanPpi},7 T: W: z! H; e% n- Z  [6 e
       {EFI_PEI_PPI_DESCRIPTOR_PPI, &gPeiNtThunkPpiGuid, &mSecWinNtThunkPpi},3 i) U; n0 c4 y6 M* [
       {EFI_PEI_PPI_DESCRIPTOR_PPI, &gPeiStatusCodePpiGuid, &mSecStatusCodePpi},
8 a' i  q- I% U- }/ N: R  J# w       {EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST, &gNtFwhPpiGuid, &mSecFwhInformationPpi}
. p' A1 g3 B+ h1 J! D) D     };* O0 @9 D$ a7 U' y$ r
    每个PPI是由{类型,GUID(名字,以后就根据这个来找到它的),Function_Entry_Address}组成。1 x1 c& |: L! h  w5 O! u
   这些PPI会在PEIDispatcher中用到。! ^# I3 c4 L6 v# _
   安装完这此东西这开始执行PEIDispatcher函数,函数从BIOS ROM文件中找出PEI的Image(怎么找到,请读一下FV_HEAD(EFI_HEAD),里面讲到了如何区分Image类型),然后定位到PEI Image的入口地址,执行他。在我们的的PEI中,我们一般会申明一个PPI,这个就是这个PEI提供一些服务,PEIDispatcher会将他们加入到PPI-List中,以后其他Image也可以调用他的提供的功能。
( s) ]' j& s& W$ z* K* V1 K   最后EDK会加载一个叫DXEIPL的PEI,DXEIPL提供一个PPI服务,这个PPI的功能是实现从PEI到DXE的切换,这个PPI里面为DXE做了很多的预准备,加载了很多PPI,如对BIOS的解压方法等。
* X; ~* f* `1 d) K& c   SwitchStacks () D7 k. n$ O* @+ I4 J. e9 m
       (VOID *) (UINTN) DxeCoreEntryPoint,
* e  ]0 s7 b5 Y& h8 P  [$ u       (UINTN) (HobList.Raw),8 U/ k" z( m( h+ ]
       (VOID *) (UINTN) TopOfStack,
  y8 K; u9 p( k8 k6 ^/ K       (VOID *) (UINTN) BspStore& c7 G) N8 h$ O+ V0 b8 d
    );
4 n0 c9 D+ L4 X- F% d; |- O  用过汇编的人对这个技术一定很熟悉,不多说了(我别不清,咯。。。)% E! _  r5 y& M! w

9 T; L& o0 T9 H7 Z, v. t$ D* }DXE:
7 Z: k: M) X. K; V0 _     从PEI到DXE切换时转过来一个HOBLIST参数,DXE会在这个HOB中找到Memory的使用情况,然后根据这些情况将BIOS引到内存(这是EFI的做法)。在EDK在DXE时重新定位一下内存。
  U9 c! ~( J  X" S. V, I6 E接着就会定义我们经常使用到的gST表,gRT表。接着是申明一些Protocol(先不关心这些事)。& G6 @  R1 J# x) Z1 r+ R% Z
   等这些该加的PPI,Protocol加完了,CoreDispatcher()就出场了。他会的功能类似PEIDispatcher()。从我们BIOS ROM中将DXE的驱动读出,执行执行他们,这时会执行到Driver7 l/ R: x4 ]% A0 b4 E' L5 F* \( Q
中的Support(),Start()两个功能函数。在这两个函数中你可以注册自己的PPI,为其他驱动提供服务。% }/ Z+ G& E3 h6 y  X
   到些BIOS的引导其他完成。接着该进OS了,看Linux 0.11吧,操作系统是怎么做事情的。/ d- x5 {9 v% P! d) A/ g7 `
   5 i. C8 h5 g' Z; b) P
Driver:
  g: b, Z6 X. c/ n    我们的驱动什么为在PEI和DXE等不同阶段执行呢?
+ I% N% e: @% `7 z  大家请看一下我们的驱动的makefile.(EDK中的*.inf)
* U8 M7 l0 e2 F$ ~; ?% E) Q  [defines]& L( Q' p9 f; n
  BASE_NAME            = OWEN# w+ ^6 ^4 X0 J* ~+ v
  FILE_GUID            = 1EDD13C1-62EF-4262-A1AA-0040D0830110
8 A) f4 P& q* V& H  COMPONENT_TYPE       = BS_DRIVER  d( ^* C7 ~' y, v* Z# D9 X

+ r+ c8 g! b& s1 a3 d  M  BASE_NAME告诉编译器最终生成的驱动的名字。9 x* Q- c9 r6 i& {+ z
  FILE_GUID就是这个驱动的GUID名字,在BIOS中引用某个驱动就是根据它来调用和识别。; d: U9 t: J* Q5 G
  COMONENT_TYPE会告诉编译器生成驱动的类型,是PEI,DXE,等。
+ }" H% i4 w; y( N. `' p/ r! a' B  在EDK中有一个FWVolume.c实现的功能就是帮我们把这个TYPE转换面相应的扩展名7 S. K( D0 W: i2 ~% ]- y
  COMP_TYPE_EXTENSION  mCompTypeExtension[] = {
( }/ N% s3 q/ i5 |7 F) h" y  {"bs_driver",  ".dxe" },, N3 C0 r" L9 R7 k7 G) d: C) H. k
  {"rt_driver",  ".dxe" },  \/ p. C5 N* ~! t8 F% e
  {"sal_rt_driver", ".dxe"},: Y  U- e, r  f9 D# u$ h: m+ F
  {"security_core", ".sec"},
: j. Y7 j) T& v0 d' ]  {"pei_core", ".pei"},$ [$ `1 o: K% O$ I
  {"pic_peim", ".pei"},+ V1 R/ l- |, L% A
  {"pe32_peim", ".pei"},3 Y! A. ]% y# ^( i! C* E
  {"relocatable_peim", ".pei"},# n# J! l# T. C" Q# P
  {"binary", ".ffs"},
4 M% ?+ [/ o4 v  d! q  {"application", ".app"},
; W/ u2 m2 w% i  {"file", ".ffs"},
/ v1 `) _1 s- x' [1 v6 j8 b  {"fvimagefile", ".fvi"},' s" u$ o  j+ o+ w
  {"rawfile", ".raw"},+ M( P( E8 L4 e5 j& m. R/ q
  {"apriori", ".ffs"},) C! h. W! k+ M; w, H
  {"combined_peim_driver", ".pei"},; j1 l0 P3 Z+ b) c8 D3 W
  { NULL,  NULL }. a. A$ r' H$ X
};# G% k4 ^( F! u1 S0 b* g

( _& U2 k- J5 T4 Q7 o5 Q+ Q了解了这些,接下我们可以看驱动篇了。(Go On Study... Forever), R  U( m% G- Y& y, ~9 `" T$ f
   " r: T) i3 P7 l3 H# q, C( ~
         
# j1 [; Z: h4 _+ ^  
发表于 2008-7-27 12:30:15 | 显示全部楼层
不错!4 H, x5 q# O# s+ ?
支持7 d% z4 J6 T, e% o4 u6 [: U' U
继续+ v/ g5 X+ S8 b6 d+ K9 w! a
加油
. ^  r$ d& @7 K- x; k8 F8 i; l% v% t, C
回复

使用道具 举报

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

回复 1# 的帖子

gPrivateDispatchTable 和COMP_TYPE_EXTENSION  没有搜到啊  是EDK专有的么?+ k- k% y1 Z4 A, `; ^
有看过跟gPrivateDispatchTable 类似的,但是里面的PPI不同。
( d( a/ r% G$ n* `还有这个COMP_TYPE_EXTENSION  没有找到过。FWVolume.c这个文件也没有发现。。
回复

使用道具 举报

发表于 2008-7-28 13:24:20 | 显示全部楼层
这东西虽说没有什么技术含量,但是总结一下还是非常好的。
" J1 F' |4 P9 V' J4 E* q' u" h  _
2 a* V" C" D1 X支持!
回复

使用道具 举报

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

* a  w4 J# u* l% D, f7 D小弟还在学习阶段,目前的目标是知道执行的流程。- b; U& V4 C2 A4 \1 M# E8 m
这里面有很多细节没有写,能力有限,只能自己知道,不能表达。0 |' N: K2 }2 z- Y
嘿。。。。; A2 h. P+ E- k# I% H7 t- n
所有大侠们如果有好东西能给小弟共享一份。; @3 V1 x$ W# h, p5 S- N

* ~& U  R4 X6 m. C: J. n谢谢!
回复

使用道具 举报

发表于 2008-8-12 14:44:11 | 显示全部楼层
原帖由 winbondowen 于 2008-7-27 00:11 发表 . k3 z, r6 y4 e4 h. e* @% c" ?3 I
  ROM中將DXE的驅動讀出,執行執行他們,這時會執行到Driver
4 ^( J' W0 _( L0 n  M9 E7 u中的Support(),Start()兩個功能函數。在這兩個函數中你可以註冊自己的PPI ...

9 Q* O1 ]' P" v
( u6 U$ n! B5 u3 i/ X, pPPIs are registered during PEI phase, but Support()/Start() are invoked in DXE driver binding protocol, $ y8 T' Q/ X! f& b# e5 }/ s  ]2 q
For more precisely, I think the "PPI" you mentioned is the "PROTOCOL" rather than "PPI".
! V! T7 x6 m- V* g3 T, k5 A3 b6 n( h5 V+ K- p9 V4 ?
[ 本帖最后由 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:
$ g2 o7 X, _, C0 R$ ^( ^) e   Yes. I make a mistake.
- T: `2 v( f1 k" c' J# H      PPI:     A PEIM to PEIM interface.
! `2 h, x$ a2 m% N' D! l      PROTOCL: A Interface between Hardware(or firmware) and software.
( e% T7 k9 h, W1 j2 o" b+ v2 F/ Q( M      reference[http://www.biosren.com/viewthread.php?tid=207]) ?. a0 L0 m7 c* _0 N7 z! e
   so, PPI execute at PEI step and Initialize hardware. PROTOCOL execute by DXE step.7 u. ]  T$ R% m' s. ~+ ^) A
   Thanks.
回复

使用道具 举报

发表于 2008-8-20 17:47:21 | 显示全部楼层
原帖由 winbondowen 于 2008-7-27 00:11 发表 DXE:
8 k+ Q; x( X. {. U- K- q& I     從PEI到DXE切換時轉過來一個HOBLIST參數,DXE會在這個HOB中找到Memory的使用情況,然後根據這些情況將BIOS引到內存(這是EFI的做法)。在EDK在DXE時重新定位一下內存。
8 s* u8 G& K( ~, t( B接著就會定義我們經常使用到的gST表,gRT表。接著是申明一些Protocol(先不關心這些事)。9 p5 ~5 o/ K+ X4 [! k
   等這些該加的PPI,Protocol加完了,CoreDispatcher()就出場了。他會的功能類似PEIDispatcher()。從我們BIOS ROM中將DXE的驅動讀出,執行執行他們,這時會執行到Driver
- o9 U" `3 n# C* D& e中的Support(),Start()兩個功能函數。在這兩個函數中你可以註冊自己的PPI,為其他驅動提供服務。1 a- t) r" K' u2 R
   到些BIOS的引導其他完成。接著該進OS了,看Linux 0.11吧,操作系統是怎麼做事情的。.

5 t7 d/ c% V8 M+ I) }9 {& G6 W
) C- d& _3 d; Q7 eThere are mistakes,5 ~3 i. a9 `& a0 s7 A- ?. O
1.gST and gRT are init after the DXE architectural protocols have been loaded, those protocols response for creating Dxe foundation.* o4 t9 u3 Z  h- T0 o2 {. @! Y

* h; _! k% P* |+ ?- }, ?( ?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.7 `+ S- t8 H2 M9 t  g2 s" g; n
The CoreDispatcher() executes all trusted Dxe drivers and just register the Binding protocol if the driver is EFI1.1 driver model.
% K1 Z" n! z, QFurthermore, Support()/Start() are invoked in BDS phase over the CoreConnectController() rather than CoreDispatcher().0 g! v- `  X8 y& b6 X$ c1 t' E& Y

8 ~# [" |' u, V7 t+ [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 大侠的指点。* j+ H( B2 `2 q
回复

使用道具 举报

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

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

原帖由 ichirohiro 于 2008-8-20 17:47 发表
0 u. J( x& ^! Z4 R# ]...
" G% u% t9 j  v8 C, p, K& e2.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.
1 \$ }$ {+ r8 PThe CoreDispatcher() executes all trusted Dxe drivers and just register the Binding protocol if the driver is EFI1.1 driver model.
' L. v8 L' ], o) ~9 WFurthermore, Support()/Start() are invoked in BDS phase over the CoreConnectController() rather than CoreDispatcher().
: Y$ f+ z3 S8 }- V  z1 o+ A
    在Framework的spec DxeCis.pdf里面也是这么说的,DXE CoreDispatcher()里面,对于EFI1.1 driver model的driver只会安装Handler和Interface到Binding protocol,到BDS才会去执行Support()和Start().
* a) M: i! D# H/ M3 r1 E    但是,我在看code时,发现在CoreDispatcher()-->CoreStartImage()里面call image之后有这么一句:  (file:image.c). [4 D0 r$ M( Q$ G$ `
  //: y' W  Q' O: j: H, M
  // Go connect any handles that were created or modified while the image executed.
' [5 p( s0 E9 W4 t6 ]  //* j1 u, n0 U3 U8 F% a( h& _+ m
  CoreConnectHandlesByKey (HandleDatabaseKey);

3 T4 l, Q# h  g这里的HandleDatabaseKey是call image之前由CoreGetHandleDatabaseKey()得到的gHandleDatabaseKey
( B- f  v6 ?* A9 ?7 P, X而CoreConnectHandlesByKey会调用到:
+ Z# Q6 M" o3 R# \9 d  //
. P& A. \2 y* @) T1 x  // Connect all handles whose Key value is greater than Key+ `! p# f3 W1 d0 K  [
  //
! J) m3 O) R3 o( A0 U% g9 e, k  for (Index = 0; Index < Count; Index++) {
4 t  B$ }4 x( g* N1 M' ^; L6 }    CoreConnectController (HandleBuffer[Index], NULL, NULL, TRUE);
0 I  O5 A7 ?& h$ S, W  }
7 y# m( x. K* E7 j6 k
所以,照code看,当在Driver中安装一个Handle和Interface到Binding Protocol后(gHandleDatabaseKey会++,IHandle的Key=gHandleDatabaseKey)
% D! y: u( S8 E9 ^  c+ u是会去ConnectController的,也会执行对应的Support()和Start()才对!!
' n3 X- k1 l) m. ?. Y) X2 c$ @3 {( ]$ v7 }! d% E
不知道我想的哪里有问题???欢迎大家指正.$ s! u. ]0 w/ O7 ^; g

, Q) Z: Q1 e7 {; ?" H4 N[ 本帖最后由 xtdumpling 于 2008-9-18 15:25 编辑 ]
回复

使用道具 举报

发表于 2008-9-19 14:44:41 | 显示全部楼层
这段code似乎是一个向后兼容的行为,不必太care。- m: J( W0 t# _- p7 X" Y
一个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 | 显示全部楼层
了解了.  \* }! ?2 i( l5 i
非常 感谢!!!
回复

使用道具 举报

发表于 2008-9-23 16:48:56 | 显示全部楼层
在读DXEmain时,
1 ^1 r6 B8 I& m' [+ [! R+ YStatus = CoreInitializeImageServices(HobStart);--->CoreInstallProtocolInterface();--->CoreInstallProtocolInterfaceNotify();中,8 B8 L$ L. D& B; F$ G3 ~( b
//  |( {+ Z- }+ |+ U
// Notify the notification list for this protocol.
0 c$ S4 A; o: |3 g. o# z/ z# P//# e2 m2 g5 F0 C& K/ _  U4 ^! m
if (Notify) {9 m, @+ Y. V2 L' y& S+ a7 f, w- d
  CoreNotifyProtocolEntry(ProtEntry);
0 T; {* n( J% c' E/ K. L}    里Signal了Event. MS是说一个handle安装了一个protocol后就signal一次., h7 _( Q+ A  [; ?
有个问题请教一下大家: 这段是在DXE很靠前的位置执行的,但是在它之前我没有看到DXE中有相关的CreateEvent出现?哪位高手能说说这部分代码的流程呢?
回复

使用道具 举报

发表于 2008-9-23 17:04:14 | 显示全部楼层
原帖由 xtdumpling 于 2008-9-16 13:34 发表
& E! N" d- V. @$ O! B请楼上的兄弟分析下BS的RegisterProtocolNotify也就是CoreRegisterProtocolNotify是做什么用的?怎么用?
, P* F# O( Z+ y8 F' u& ?谢谢!

4 n% S- |8 W% A4 O* \......
' B. C9 P/ M+ x
/ ^2 x. F1 M9 S8 Y# `- e+ L# @/ y# k: F/ O' y/ x- I
[ 本帖最后由 xtdumpling 于 2008-9-23 17:24 编辑 ]
回复

使用道具 举报

发表于 2008-9-24 12:43:45 | 显示全部楼层
原帖由 xtdumpling 于 2008-9-23 17:04 发表
; G% D$ D$ t7 V; S2 `* f  o4 [+ d  t4 f4 i
......9 _. a; C0 w6 V7 b/ J* c: O

# ?8 d! |5 t4 u/ `7 gSignal的Event是不是在各个TPL级上挂载一些待处理的事件,一旦restore(TPL)的话,比当前TPL级高的pending事件就回被处理掉?
0 x; V- w% I- ]& }% y如果是这样的话,Timer事件是如何处理的呢,没有找到相关的代码呀?Xt指点一下再~
回复

使用道具 举报

发表于 2008-9-24 19:00:46 | 显示全部楼层
Timer是挂在8259的IRQ0的中断处理程序上面的, 大概每秒18.3次调用CoreTimerTick()-->CoreCheckTimers()
# j3 C. ~* C( ], G# V1 @TPL=30
回复

使用道具 举报

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

本版积分规则

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

GMT+8, 2025-4-12 06:50 , Processed in 0.031175 second(s), 17 queries .

Powered by Discuz! X3.5

© 2001-2023 Discuz! Team.

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