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

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

[复制链接]
发表于 2008-7-27 00:11:28 | 显示全部楼层 |阅读模式
  最近在工作看到机台有启动过程中把SPI ROM数据清空,但苦与没有办法很好的Debug(PCA没有架起来),所有与EDK为对象好好的读了一把。
4 O( v8 M* E" E3 U* w2 N" q) M% H$ r6 }2 v# S
SEC/CEI:- x* Q: a4 v8 v
  UEFI BIOS启动时先会执行SEC/CEI,这个阶段在实现的BIOS Code中初始化Debug Port,进入Big Mode,CPU的MicroCode,CacheToRAM的转换.然后跳转到PEI阶段。, t7 W: M2 `0 s7 `; ^$ Y
在EDK中这部分被成了Load FvRecovery.fd文件,这个文件类似与我们的BIOS ROM.里面是我们编译后生成的二进制代码。在这个阶段最主要的是将这个文件加载到内存中(Windows API将文件加载到内存,看API函数).
# f! B. }2 p3 W% E1 ]+ @; x! D( ~% ]5 y4 j; {+ Q1 I9 W3 T, L
PEI:1 t* K2 O5 `3 v. r
   从这里开始UEFI BIOS和EDK执行基本相同,只是一个是从SPI ROM中定位一个地址(PEIM的开始地址),一个是从内存中定位一个地址(PEIM的开始地址)。从这里开始只讲EDK的执行* N! Y, [" G. C! N% O, a7 ?
  EDK调用InitializeMemoryService函数,将HobList清空,peiservice清空。
% r, G# A" D& d$ o      InitializePPIService函数,将PPI队列清空,这个队列长0x3F.
4 H% S( V; e( j0 X          InitializeSercurityService函数,将Notify队列清空。$ u- G$ J% O# X% E$ l; _- s
          InitializeDispatcherData函数,将Dispatcher队列清空。
9 O) E6 g  Z! H9 p  接着由PeiBuildHobGuid来建立一个HOB(S3返回时这时应该有这个HOB,不用建立,直接使用了,这样就会进入另外一个流程,可以这个EDK不能调试S3,不知道怎么走)。然后由(*PeiServices)->InstallPpi()将这个新HOB加入到PPI中。
8 o  u& i, `7 A: r    由于在SEC阶段转了以下这几具PPI,所以在执行PEI的Dispatcher之前会先安装东西:8 [6 I/ j& ?( h& q9 ^; P* z0 x
      EFI_PEI_PPI_DESCRIPTOR    gPrivateDispatchTable[] = {$ [1 J6 m$ t* V( c$ u
       {EFI_PEI_PPI_DESCRIPTOR_PPI, &gEfiNtLoadAsDllPpiGuid, &mSecNtLoadAsDllPpi},1 g% L' g/ k! |; |
       {EFI_PEI_PPI_DESCRIPTOR_PPI, &gNtPeiLoadFileGuid, &mSecNtLoadFilePpi},
4 N- Q/ e( U+ d" q+ o0 r  N6 A       {EFI_PEI_PPI_DESCRIPTOR_PPI, &gPeiNtAutoScanPpiGuid, &mSecNtAutoScanPpi},' n  {/ y, R/ d7 i) }, x. U: K
       {EFI_PEI_PPI_DESCRIPTOR_PPI, &gPeiNtThunkPpiGuid, &mSecWinNtThunkPpi},8 S) c' k" S- ~# {6 j! @2 M/ V
       {EFI_PEI_PPI_DESCRIPTOR_PPI, &gPeiStatusCodePpiGuid, &mSecStatusCodePpi},
9 Y& U: @3 u/ D( b$ V% Z       {EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST, &gNtFwhPpiGuid, &mSecFwhInformationPpi}
0 w3 ]7 c: Y7 @+ v( w' ]$ l2 C     };
+ p, l' N1 u# \: t- C" `/ J: L* f    每个PPI是由{类型,GUID(名字,以后就根据这个来找到它的),Function_Entry_Address}组成。
6 H* A1 ]. d& S" J1 ~6 P   这些PPI会在PEIDispatcher中用到。- E8 g! g& p5 p4 a) V5 {
   安装完这此东西这开始执行PEIDispatcher函数,函数从BIOS ROM文件中找出PEI的Image(怎么找到,请读一下FV_HEAD(EFI_HEAD),里面讲到了如何区分Image类型),然后定位到PEI Image的入口地址,执行他。在我们的的PEI中,我们一般会申明一个PPI,这个就是这个PEI提供一些服务,PEIDispatcher会将他们加入到PPI-List中,以后其他Image也可以调用他的提供的功能。
; j& q3 \! `* y8 |) N: U0 I1 W   最后EDK会加载一个叫DXEIPL的PEI,DXEIPL提供一个PPI服务,这个PPI的功能是实现从PEI到DXE的切换,这个PPI里面为DXE做了很多的预准备,加载了很多PPI,如对BIOS的解压方法等。+ R" o, O2 b9 M6 j% N7 D) z) a
   SwitchStacks (0 }: P* J- i! o' C' y
       (VOID *) (UINTN) DxeCoreEntryPoint,. _+ n+ U- N! n, e6 o2 T
       (UINTN) (HobList.Raw),
  k: T" N, E  u& o5 Y0 T- u* K       (VOID *) (UINTN) TopOfStack,2 h3 G! T6 W/ W
       (VOID *) (UINTN) BspStore/ [/ M' O! L8 C  U- k$ I
    );0 n, b1 t, Q5 V# a9 d
  用过汇编的人对这个技术一定很熟悉,不多说了(我别不清,咯。。。)( m# Y4 |9 U6 F; b+ q/ @
) F1 A" K. Q0 x1 S- c* W, G
DXE:
( C+ r& B! c) n' [     从PEI到DXE切换时转过来一个HOBLIST参数,DXE会在这个HOB中找到Memory的使用情况,然后根据这些情况将BIOS引到内存(这是EFI的做法)。在EDK在DXE时重新定位一下内存。, [) ?5 r8 u1 s! g+ W! W  g
接着就会定义我们经常使用到的gST表,gRT表。接着是申明一些Protocol(先不关心这些事)。
5 n$ o) \% K; K   等这些该加的PPI,Protocol加完了,CoreDispatcher()就出场了。他会的功能类似PEIDispatcher()。从我们BIOS ROM中将DXE的驱动读出,执行执行他们,这时会执行到Driver/ F5 v$ b+ F3 Y3 V; N* p
中的Support(),Start()两个功能函数。在这两个函数中你可以注册自己的PPI,为其他驱动提供服务。3 s7 ?( C/ ]8 \: \3 F4 l$ N5 k2 O5 I
   到些BIOS的引导其他完成。接着该进OS了,看Linux 0.11吧,操作系统是怎么做事情的。
7 F2 L2 d! s) F# P7 r; M   
2 x  h, I" F8 x/ S) x1 A) [" gDriver:
+ b7 p' E5 T0 U4 ~" P) V& y    我们的驱动什么为在PEI和DXE等不同阶段执行呢?
( E) v- L! I; q4 J5 j+ r  大家请看一下我们的驱动的makefile.(EDK中的*.inf)% t/ p% ?& e1 `6 _( ^( a& k
  [defines]; }/ r( Q* t5 U( I- o; s
  BASE_NAME            = OWEN5 M. e4 u) Z9 p0 R+ i2 X/ c* U. k/ A
  FILE_GUID            = 1EDD13C1-62EF-4262-A1AA-0040D0830110
: G; ]7 w8 ]- t* [" n; W  COMPONENT_TYPE       = BS_DRIVER) N" m" ?  ]+ S' [

) P5 O2 Q+ q4 G% S# g. e  BASE_NAME告诉编译器最终生成的驱动的名字。0 v0 i1 f5 Q' g/ R
  FILE_GUID就是这个驱动的GUID名字,在BIOS中引用某个驱动就是根据它来调用和识别。
7 u, z+ O; M* z# p9 L+ q2 A  COMONENT_TYPE会告诉编译器生成驱动的类型,是PEI,DXE,等。
7 e, o4 }% [0 F2 ]+ p  在EDK中有一个FWVolume.c实现的功能就是帮我们把这个TYPE转换面相应的扩展名$ z% g0 h0 q6 ?1 a* Z5 @- D9 P, }5 m
  COMP_TYPE_EXTENSION  mCompTypeExtension[] = {
, z- h! Q+ k$ G/ W. [, T) Z  {"bs_driver",  ".dxe" },  a. w2 ]: k$ m+ u+ F" s* y
  {"rt_driver",  ".dxe" },
. s4 q$ P$ Y1 y: k. U  {"sal_rt_driver", ".dxe"},0 ~' p! d$ w' x3 a* `, L
  {"security_core", ".sec"},
7 `" p: |, g' E5 y% q! [  M  {"pei_core", ".pei"},
6 u' T6 _7 s4 U  m: y, Z8 b) L& Y5 `% u  {"pic_peim", ".pei"},! P) e4 t! T6 ?+ t, g- ]( b
  {"pe32_peim", ".pei"},
, t# b0 `8 d" \: z  {"relocatable_peim", ".pei"},
& k( s- [# c1 F) e  {"binary", ".ffs"},
' L7 R" e' d% d* Q; q$ h  {"application", ".app"},
4 y& S' o4 U3 w: p' G) K  {"file", ".ffs"},: y  l2 d5 X9 U  |* ~; u
  {"fvimagefile", ".fvi"},
; C2 K. x; H( E" p6 \  {"rawfile", ".raw"},( b; k! m/ f/ M: N* [& }. N
  {"apriori", ".ffs"},
( h' @" Q; t& `# m$ s  {"combined_peim_driver", ".pei"},% i. L6 b0 N5 @; l+ v" K! e+ s
  { NULL,  NULL }
" l' W) B  b+ F};2 H- n- b/ M; I9 l8 m  \* r, N

9 s# K9 G) ?8 G) X- B了解了这些,接下我们可以看驱动篇了。(Go On Study... Forever)
4 Y: f6 s0 T0 H8 _) l! {- L   
2 _7 @5 o: h: O, K# K- x         % {4 o- [) X$ e$ b" J( \! m7 s
  
发表于 2008-7-27 12:30:15 | 显示全部楼层
不错!
  l5 A! u( \4 ^. g: \/ b+ X& @+ E# [支持
9 I8 N% Y& D/ d0 L  S3 y继续0 U) Q- ~" T" H* P2 r( a3 Z( ?% V
加油1 ~4 P" p# T! n7 D& Z+ d8 H
回复

使用道具 举报

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

回复 1# 的帖子

gPrivateDispatchTable 和COMP_TYPE_EXTENSION  没有搜到啊  是EDK专有的么?! a- D9 m1 s" ^7 E7 ]
有看过跟gPrivateDispatchTable 类似的,但是里面的PPI不同。
  A/ V7 n; j* t, b7 r还有这个COMP_TYPE_EXTENSION  没有找到过。FWVolume.c这个文件也没有发现。。
回复

使用道具 举报

发表于 2008-7-28 13:24:20 | 显示全部楼层
这东西虽说没有什么技术含量,但是总结一下还是非常好的。. k8 a( ~* n; Z6 a) e

) o; L4 a8 [+ @4 b* a支持!
回复

使用道具 举报

 楼主| 发表于 2008-7-28 18:52:31 | 显示全部楼层
& G; O+ v/ H3 ?% R: x# P' V9 ^; J
小弟还在学习阶段,目前的目标是知道执行的流程。
: _0 {- U( q1 q2 k8 V! S2 u这里面有很多细节没有写,能力有限,只能自己知道,不能表达。
& d# R/ C4 a! Q/ w; D嘿。。。。
( ^  M7 G# j$ ^6 ~2 K+ I所有大侠们如果有好东西能给小弟共享一份。7 p5 L% v) O- y* ^- k- p; b+ r& \6 h
- @  S: c; w- T7 o3 G9 l, P, U' ~. @
谢谢!
回复

使用道具 举报

发表于 2008-8-12 14:44:11 | 显示全部楼层
原帖由 winbondowen 于 2008-7-27 00:11 发表 2 G$ ]( x- Q) B
  ROM中將DXE的驅動讀出,執行執行他們,這時會執行到Driver( ^2 q6 R* c# j$ H# j- b* w
中的Support(),Start()兩個功能函數。在這兩個函數中你可以註冊自己的PPI ...
" q& H7 Y1 Z% t. j

" v- V9 [; g6 [/ j) G3 pPPIs are registered during PEI phase, but Support()/Start() are invoked in DXE driver binding protocol,
* C- H) z0 D& b. k( lFor more precisely, I think the "PPI" you mentioned is the "PROTOCOL" rather than "PPI".+ S# t8 G; i/ B0 k

' r% U2 O6 t5 x$ _[ 本帖最后由 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:+ H3 w9 p  O" V% c
   Yes. I make a mistake.
! {' B' b; g# }! j+ z1 P& A7 {      PPI:     A PEIM to PEIM interface.
$ @, g9 C0 @) K# D$ I      PROTOCL: A Interface between Hardware(or firmware) and software.- S$ H+ q3 c5 Y1 w6 ]/ V" p# @2 @
      reference[http://www.biosren.com/viewthread.php?tid=207]
! p6 V- j8 E0 ~; O0 G   so, PPI execute at PEI step and Initialize hardware. PROTOCOL execute by DXE step.5 W, f# J8 q* K2 [$ H6 |5 q
   Thanks.
回复

使用道具 举报

发表于 2008-8-20 17:47:21 | 显示全部楼层
原帖由 winbondowen 于 2008-7-27 00:11 发表 DXE:
4 l$ Z( z" {" ?- w0 J0 P8 `2 \     從PEI到DXE切換時轉過來一個HOBLIST參數,DXE會在這個HOB中找到Memory的使用情況,然後根據這些情況將BIOS引到內存(這是EFI的做法)。在EDK在DXE時重新定位一下內存。
4 x2 b1 l0 ^- b: v# Z+ x3 _- W2 `接著就會定義我們經常使用到的gST表,gRT表。接著是申明一些Protocol(先不關心這些事)。
. m* k. s/ X9 N   等這些該加的PPI,Protocol加完了,CoreDispatcher()就出場了。他會的功能類似PEIDispatcher()。從我們BIOS ROM中將DXE的驅動讀出,執行執行他們,這時會執行到Driver: J% ~% q  W+ y0 R
中的Support(),Start()兩個功能函數。在這兩個函數中你可以註冊自己的PPI,為其他驅動提供服務。9 g% P/ `2 q$ l$ l& F1 O; B% \
   到些BIOS的引導其他完成。接著該進OS了,看Linux 0.11吧,操作系統是怎麼做事情的。.

. B: H/ _' N! p- q) X
! d0 H: P3 e' d! yThere are mistakes,5 |; R- z4 j, H) _
1.gST and gRT are init after the DXE architectural protocols have been loaded, those protocols response for creating Dxe foundation.
; j) c/ G" x0 A6 [: o; o: Y, q# q0 @" A) k* D5 k* E& i
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.
  S+ O, M. S" G1 ?The CoreDispatcher() executes all trusted Dxe drivers and just register the Binding protocol if the driver is EFI1.1 driver model.
- D0 E% `) V4 D  jFurthermore, Support()/Start() are invoked in BDS phase over the CoreConnectController() rather than CoreDispatcher().2 u5 q  C; b6 v( P! |7 b' K! {+ v' U
' d! K# o" f- U
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 大侠的指点。
1 _+ B7 A4 e4 M1 b, ?
回复

使用道具 举报

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

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

原帖由 ichirohiro 于 2008-8-20 17:47 发表
4 M" m" p8 t& ~8 W; d...
( H" H3 u* F) R4 `3 Y* b' H2.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.
2 H5 O0 q& X) S% T$ ]The CoreDispatcher() executes all trusted Dxe drivers and just register the Binding protocol if the driver is EFI1.1 driver model.
1 n  b! d3 L1 A% gFurthermore, Support()/Start() are invoked in BDS phase over the CoreConnectController() rather than CoreDispatcher().

! k" F0 E! ^! I/ V    在Framework的spec DxeCis.pdf里面也是这么说的,DXE CoreDispatcher()里面,对于EFI1.1 driver model的driver只会安装Handler和Interface到Binding protocol,到BDS才会去执行Support()和Start().
$ K1 d: s2 R5 u0 Q/ s    但是,我在看code时,发现在CoreDispatcher()-->CoreStartImage()里面call image之后有这么一句:  (file:image.c)
$ d' o. T6 f/ }# g# ]  //) q3 u1 q3 w9 Z! O+ g1 v3 b  w9 D
  // Go connect any handles that were created or modified while the image executed.
$ H$ I# \% J9 k) k7 z' T  //
( m& K& D' V# x  CoreConnectHandlesByKey (HandleDatabaseKey);
+ Z0 e+ T! G: P
这里的HandleDatabaseKey是call image之前由CoreGetHandleDatabaseKey()得到的gHandleDatabaseKey! d4 ?/ n/ M! n! b3 y. Z
而CoreConnectHandlesByKey会调用到:
$ {" d4 F' R, J* L6 @+ c  //
, g# G. K( o1 L' T$ {. n- i  // Connect all handles whose Key value is greater than Key) H9 S; Y6 P9 a3 z
  //7 |0 B2 {7 Z+ ?' \( ?& I
  for (Index = 0; Index < Count; Index++) {- _8 X4 F# V& i
    CoreConnectController (HandleBuffer[Index], NULL, NULL, TRUE);
+ L& J  a5 ^5 A9 d3 d; r. \2 d6 Y) x  }
2 K, E+ a" [& R$ S! @& L4 |
所以,照code看,当在Driver中安装一个Handle和Interface到Binding Protocol后(gHandleDatabaseKey会++,IHandle的Key=gHandleDatabaseKey)8 W/ [5 d" ~0 L+ |
是会去ConnectController的,也会执行对应的Support()和Start()才对!!
( v  Q+ g) V  ]3 |& f! u
8 m$ ~' Z- N' K1 D( h, @8 I6 G不知道我想的哪里有问题???欢迎大家指正.
* q4 v; B( M  w( }7 j7 M3 h2 V( R, j% ]( M1 h
[ 本帖最后由 xtdumpling 于 2008-9-18 15:25 编辑 ]
回复

使用道具 举报

发表于 2008-9-19 14:44:41 | 显示全部楼层
这段code似乎是一个向后兼容的行为,不必太care。
2 ~0 k8 O8 P9 g一个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 | 显示全部楼层
了解了.
- a$ R0 |& `, `- P7 R3 I5 Q! z非常 感谢!!!
回复

使用道具 举报

发表于 2008-9-23 16:48:56 | 显示全部楼层
在读DXEmain时,5 A5 w: Z" G2 T, P
Status = CoreInitializeImageServices(HobStart);--->CoreInstallProtocolInterface();--->CoreInstallProtocolInterfaceNotify();中,
- e) e9 t5 l, J, E: v% {+ J8 A$ r# [* O//
  W" U  u& C0 p. i+ P) z7 i// Notify the notification list for this protocol.
& e; a4 Z7 {: J3 M! v. K$ h//1 P# l+ X2 Y$ X; W3 {  C' [
if (Notify) {% A. [' L0 c' O$ ~3 N
  CoreNotifyProtocolEntry(ProtEntry);! a9 G1 O6 ~: d) |* x
}    里Signal了Event. MS是说一个handle安装了一个protocol后就signal一次.
8 E' n8 }4 f$ q# m! z& q! |& @有个问题请教一下大家: 这段是在DXE很靠前的位置执行的,但是在它之前我没有看到DXE中有相关的CreateEvent出现?哪位高手能说说这部分代码的流程呢?
回复

使用道具 举报

发表于 2008-9-23 17:04:14 | 显示全部楼层
原帖由 xtdumpling 于 2008-9-16 13:34 发表
6 l, ]6 m. f0 d9 P: M& K" l  B请楼上的兄弟分析下BS的RegisterProtocolNotify也就是CoreRegisterProtocolNotify是做什么用的?怎么用?
* |' ^' C4 h) s$ l( g" G5 b/ }, ?谢谢!

) b" W7 k+ N7 a- g! Y. |7 H! F....../ I! o+ ?  x) `9 x% w

$ k2 M! n7 z  t8 u9 `; o3 Q6 R/ @; t3 M
[ 本帖最后由 xtdumpling 于 2008-9-23 17:24 编辑 ]
回复

使用道具 举报

发表于 2008-9-24 12:43:45 | 显示全部楼层
原帖由 xtdumpling 于 2008-9-23 17:04 发表 2 t+ \. J9 ^3 b- I& P9 H2 q' t$ o
9 S% t& _. u( ]. R; v( o1 e$ F) X+ _
......
! D! S: i0 N4 e8 F& S* j! @

; U1 Q% \$ c5 K" p' `/ PSignal的Event是不是在各个TPL级上挂载一些待处理的事件,一旦restore(TPL)的话,比当前TPL级高的pending事件就回被处理掉?
2 |8 E8 L$ @2 F0 \4 k如果是这样的话,Timer事件是如何处理的呢,没有找到相关的代码呀?Xt指点一下再~
回复

使用道具 举报

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

使用道具 举报

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

本版积分规则

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

GMT+8, 2025-12-1 03:34 , Processed in 0.082662 second(s), 17 queries .

Powered by Discuz! X3.5

© 2001-2025 Discuz! Team.

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