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

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

[复制链接]
发表于 2008-7-27 00:11:28 | 显示全部楼层 |阅读模式
  最近在工作看到机台有启动过程中把SPI ROM数据清空,但苦与没有办法很好的Debug(PCA没有架起来),所有与EDK为对象好好的读了一把。: q1 r, p" n4 a3 q" @2 {6 V& i' p0 x
& H, s% t, G  c3 _5 ^* G
SEC/CEI:
& h) e" H) F/ q: Z8 P  UEFI BIOS启动时先会执行SEC/CEI,这个阶段在实现的BIOS Code中初始化Debug Port,进入Big Mode,CPU的MicroCode,CacheToRAM的转换.然后跳转到PEI阶段。' l2 n0 R4 u: L1 ~
在EDK中这部分被成了Load FvRecovery.fd文件,这个文件类似与我们的BIOS ROM.里面是我们编译后生成的二进制代码。在这个阶段最主要的是将这个文件加载到内存中(Windows API将文件加载到内存,看API函数).
: W2 y, `$ E# e  P- j: H+ S: _8 _, N8 R& j) D2 x
PEI:9 y( L4 g. P2 ^( B
   从这里开始UEFI BIOS和EDK执行基本相同,只是一个是从SPI ROM中定位一个地址(PEIM的开始地址),一个是从内存中定位一个地址(PEIM的开始地址)。从这里开始只讲EDK的执行1 K! k  k2 n% |
  EDK调用InitializeMemoryService函数,将HobList清空,peiservice清空。
+ V2 S6 ?: J6 D! y      InitializePPIService函数,将PPI队列清空,这个队列长0x3F.2 P: ~' y9 z3 _, P" H
          InitializeSercurityService函数,将Notify队列清空。+ \: q: |4 J3 y7 ^( v
          InitializeDispatcherData函数,将Dispatcher队列清空。5 E/ S, a# e! q
  接着由PeiBuildHobGuid来建立一个HOB(S3返回时这时应该有这个HOB,不用建立,直接使用了,这样就会进入另外一个流程,可以这个EDK不能调试S3,不知道怎么走)。然后由(*PeiServices)->InstallPpi()将这个新HOB加入到PPI中。
6 c3 H0 Y+ v& f  {9 X  m+ M' F+ L: t    由于在SEC阶段转了以下这几具PPI,所以在执行PEI的Dispatcher之前会先安装东西:
. e+ U1 S( }" @7 z2 C& w      EFI_PEI_PPI_DESCRIPTOR    gPrivateDispatchTable[] = {' r, n$ N$ a# s4 V
       {EFI_PEI_PPI_DESCRIPTOR_PPI, &gEfiNtLoadAsDllPpiGuid, &mSecNtLoadAsDllPpi},- W! }! r6 a1 n0 Z  E: A) x
       {EFI_PEI_PPI_DESCRIPTOR_PPI, &gNtPeiLoadFileGuid, &mSecNtLoadFilePpi}," J6 b) ]% e" x
       {EFI_PEI_PPI_DESCRIPTOR_PPI, &gPeiNtAutoScanPpiGuid, &mSecNtAutoScanPpi},
3 y& `/ A9 M+ C+ N; t. G* r! K       {EFI_PEI_PPI_DESCRIPTOR_PPI, &gPeiNtThunkPpiGuid, &mSecWinNtThunkPpi},
' i! Y; r" B5 g       {EFI_PEI_PPI_DESCRIPTOR_PPI, &gPeiStatusCodePpiGuid, &mSecStatusCodePpi},
7 K% g9 ~! w1 r       {EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST, &gNtFwhPpiGuid, &mSecFwhInformationPpi}& n; C1 R6 A9 h$ e5 n3 E- y+ D% j9 W
     };( ?8 B8 L* [2 M- j9 b$ D. a+ {
    每个PPI是由{类型,GUID(名字,以后就根据这个来找到它的),Function_Entry_Address}组成。
& I7 y& O9 `3 _$ W+ H- X1 i8 M+ W( U9 o5 \   这些PPI会在PEIDispatcher中用到。
" |- W% ^$ K3 C! _   安装完这此东西这开始执行PEIDispatcher函数,函数从BIOS ROM文件中找出PEI的Image(怎么找到,请读一下FV_HEAD(EFI_HEAD),里面讲到了如何区分Image类型),然后定位到PEI Image的入口地址,执行他。在我们的的PEI中,我们一般会申明一个PPI,这个就是这个PEI提供一些服务,PEIDispatcher会将他们加入到PPI-List中,以后其他Image也可以调用他的提供的功能。
0 o* J' `. Y" t   最后EDK会加载一个叫DXEIPL的PEI,DXEIPL提供一个PPI服务,这个PPI的功能是实现从PEI到DXE的切换,这个PPI里面为DXE做了很多的预准备,加载了很多PPI,如对BIOS的解压方法等。
, e1 ^% y7 R! [" h% ]' g. r9 T! a   SwitchStacks (% F5 O3 n( |' m) `
       (VOID *) (UINTN) DxeCoreEntryPoint,
2 u! F8 K; E* j  z       (UINTN) (HobList.Raw),) h( `% Q8 {' x" E' K8 x! e7 m
       (VOID *) (UINTN) TopOfStack,
" b5 F- p# l/ K" I- c       (VOID *) (UINTN) BspStore
: f! O8 E5 }7 l3 k    );7 [# ~, _2 R  `! _% K
  用过汇编的人对这个技术一定很熟悉,不多说了(我别不清,咯。。。)  [7 U6 [9 [, Y- ~6 o# ]4 \# n
/ f0 d* Q  @) Y
DXE:% b+ p6 z# \+ F, L
     从PEI到DXE切换时转过来一个HOBLIST参数,DXE会在这个HOB中找到Memory的使用情况,然后根据这些情况将BIOS引到内存(这是EFI的做法)。在EDK在DXE时重新定位一下内存。
5 `/ ?0 `/ D: Q9 a- N5 k接着就会定义我们经常使用到的gST表,gRT表。接着是申明一些Protocol(先不关心这些事)。
2 K' K6 E. m- y5 x" I/ Y$ W* H   等这些该加的PPI,Protocol加完了,CoreDispatcher()就出场了。他会的功能类似PEIDispatcher()。从我们BIOS ROM中将DXE的驱动读出,执行执行他们,这时会执行到Driver
; {- g# C% z" {) _5 l, h中的Support(),Start()两个功能函数。在这两个函数中你可以注册自己的PPI,为其他驱动提供服务。, c' ]. \: X& v( W) T+ ?, }/ G
   到些BIOS的引导其他完成。接着该进OS了,看Linux 0.11吧,操作系统是怎么做事情的。7 g' Q( m! ?4 E& f0 s3 g. {
   3 H3 X1 F9 Z/ Z) s( a
Driver:" b( w! U1 M* B! {/ `
    我们的驱动什么为在PEI和DXE等不同阶段执行呢?4 V: o8 m) u( N% Z" o
  大家请看一下我们的驱动的makefile.(EDK中的*.inf)
: ]6 A. f* U. o' C  [defines]
2 l, R8 C' O& u' Q  BASE_NAME            = OWEN% @& U- A! e+ c) L. \- a
  FILE_GUID            = 1EDD13C1-62EF-4262-A1AA-0040D0830110; K" f: h, @; i: }
  COMPONENT_TYPE       = BS_DRIVER$ @; E9 s9 m+ Y2 f

3 y0 t3 U- h6 N% r4 O  BASE_NAME告诉编译器最终生成的驱动的名字。
: I. N1 J& f* b9 n, `  FILE_GUID就是这个驱动的GUID名字,在BIOS中引用某个驱动就是根据它来调用和识别。0 v4 g0 @* \7 m0 J$ w& t
  COMONENT_TYPE会告诉编译器生成驱动的类型,是PEI,DXE,等。
! g4 K3 U& Y& L: n- o  在EDK中有一个FWVolume.c实现的功能就是帮我们把这个TYPE转换面相应的扩展名, j' L3 i& z  q8 O
  COMP_TYPE_EXTENSION  mCompTypeExtension[] = {
4 X+ u; q$ r( |% i- x: Y- }0 u  {"bs_driver",  ".dxe" },
6 ~; Q/ q' u  \% T( x/ q/ h  {"rt_driver",  ".dxe" },6 G5 y4 `; J; W9 H, K" L% w
  {"sal_rt_driver", ".dxe"},8 j) C3 e; h$ R# {% U
  {"security_core", ".sec"},
+ t: k) G. F) Q2 y  {"pei_core", ".pei"},
# w, c0 a$ w, U( L2 l% Y8 s4 e2 s  {"pic_peim", ".pei"},
% }/ Y" I/ g6 W1 y$ ^  {"pe32_peim", ".pei"},& ]* l+ x* U2 R% E  q2 Q
  {"relocatable_peim", ".pei"},
. U9 N$ g9 G- s  {"binary", ".ffs"},+ J7 P* U3 \8 ^
  {"application", ".app"},
$ G% @7 S  V& w6 O) x  {"file", ".ffs"},
+ R  A3 F. [* T+ x, L$ |7 e1 P1 d  {"fvimagefile", ".fvi"},
: Q5 ?( d" x& _  {"rawfile", ".raw"},
" y) H9 w% I& C0 M! G) p  {"apriori", ".ffs"},
" v" j* N5 i5 H4 M5 ^# M  {"combined_peim_driver", ".pei"},
; n$ x: y" u- G  { NULL,  NULL }
2 f. v1 X9 w/ @' K0 g! @};* S( K, R1 |. h; A% o0 p

( u  R  v! F1 Z5 T5 A了解了这些,接下我们可以看驱动篇了。(Go On Study... Forever)7 A. i$ d+ `2 C' w, `1 C+ x* \
   
- x8 Q9 a; D( X6 f1 [' a( @         
- {& U5 l: \6 Q& N  
发表于 2008-7-27 12:30:15 | 显示全部楼层
不错!
% c* V5 {7 P: Y$ W5 f% u支持
" B. Y' K7 @1 ~3 V0 D继续3 l5 m" R1 _8 i9 _
加油: `$ ?$ o7 k1 i! e9 |: w) R
回复

使用道具 举报

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

回复 1# 的帖子

gPrivateDispatchTable 和COMP_TYPE_EXTENSION  没有搜到啊  是EDK专有的么?
) u- x3 h! s( k* L3 W有看过跟gPrivateDispatchTable 类似的,但是里面的PPI不同。: T! O! Q4 r: W
还有这个COMP_TYPE_EXTENSION  没有找到过。FWVolume.c这个文件也没有发现。。
回复

使用道具 举报

发表于 2008-7-28 13:24:20 | 显示全部楼层
这东西虽说没有什么技术含量,但是总结一下还是非常好的。1 f3 Z- r4 i/ \5 H

. X2 Z1 E6 P+ `' F8 s2 G支持!
回复

使用道具 举报

 楼主| 发表于 2008-7-28 18:52:31 | 显示全部楼层
, |7 w' }$ i) x6 B
小弟还在学习阶段,目前的目标是知道执行的流程。
& \# t# X( q, a& i这里面有很多细节没有写,能力有限,只能自己知道,不能表达。! l9 K* d  D- ?- ~2 n/ i& h
嘿。。。。
2 l5 V; Z9 P) X5 ~5 E3 E# h1 @7 Z所有大侠们如果有好东西能给小弟共享一份。2 V4 k2 K# O1 W- G! _
+ O. M, r9 u& y# ]0 \2 U! e* i
谢谢!
回复

使用道具 举报

发表于 2008-8-12 14:44:11 | 显示全部楼层
原帖由 winbondowen 于 2008-7-27 00:11 发表 0 J0 s/ b9 G+ J+ N) S9 n
  ROM中將DXE的驅動讀出,執行執行他們,這時會執行到Driver
6 M+ S# W7 A/ [$ e中的Support(),Start()兩個功能函數。在這兩個函數中你可以註冊自己的PPI ...

% N& |+ K( M0 U
* p0 z/ H8 n1 ^. m1 JPPIs are registered during PEI phase, but Support()/Start() are invoked in DXE driver binding protocol, % h1 h0 \. R! z
For more precisely, I think the "PPI" you mentioned is the "PROTOCOL" rather than "PPI".
2 O8 j. {) k% l  [- o! }8 ~  N& @0 J5 j9 G7 s% j; m+ S' \
[ 本帖最后由 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:" B5 g1 L. {8 {6 o
   Yes. I make a mistake.
) \' `& _3 a( g, a) l      PPI:     A PEIM to PEIM interface.
1 ]( b; @  u5 \7 ^) S' |( O      PROTOCL: A Interface between Hardware(or firmware) and software.
2 D7 ^! j1 h/ H      reference[http://www.biosren.com/viewthread.php?tid=207]
3 h1 w; G; l* s1 n! g1 s; \% t   so, PPI execute at PEI step and Initialize hardware. PROTOCOL execute by DXE step.
" a5 }5 `" {1 f   Thanks.
回复

使用道具 举报

发表于 2008-8-20 17:47:21 | 显示全部楼层
原帖由 winbondowen 于 2008-7-27 00:11 发表 DXE:$ M/ V& w# U1 }  M
     從PEI到DXE切換時轉過來一個HOBLIST參數,DXE會在這個HOB中找到Memory的使用情況,然後根據這些情況將BIOS引到內存(這是EFI的做法)。在EDK在DXE時重新定位一下內存。* w: N* |8 }3 @7 [4 ~
接著就會定義我們經常使用到的gST表,gRT表。接著是申明一些Protocol(先不關心這些事)。
  L6 x( D  @9 `: w: D  Y   等這些該加的PPI,Protocol加完了,CoreDispatcher()就出場了。他會的功能類似PEIDispatcher()。從我們BIOS ROM中將DXE的驅動讀出,執行執行他們,這時會執行到Driver0 m6 Y- q5 N  p: T
中的Support(),Start()兩個功能函數。在這兩個函數中你可以註冊自己的PPI,為其他驅動提供服務。/ d6 [2 |" v+ j
   到些BIOS的引導其他完成。接著該進OS了,看Linux 0.11吧,操作系統是怎麼做事情的。.
6 l- ?0 b4 j% C) N

& W4 e; Y0 h6 F3 \: MThere are mistakes,
4 a. q7 {9 G# M; e) @  C1.gST and gRT are init after the DXE architectural protocols have been loaded, those protocols response for creating Dxe foundation./ ^2 f/ B/ a+ z  [3 G
. W$ @! h! U& j
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.' y! X3 W# ]$ y' J/ K; \
The CoreDispatcher() executes all trusted Dxe drivers and just register the Binding protocol if the driver is EFI1.1 driver model.
7 W. R" r/ {  }3 _. ]Furthermore, Support()/Start() are invoked in BDS phase over the CoreConnectController() rather than CoreDispatcher().) g% N& s, f6 O( y- n! i+ o" O2 H
- X: C+ G9 v$ [. e: B9 D
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 大侠的指点。% N5 q. v6 E! {3 g
回复

使用道具 举报

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

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

原帖由 ichirohiro 于 2008-8-20 17:47 发表 3 u3 U& a) w/ D' Y& O
...
1 W) l# V' f8 H: [- V, g6 o2.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 j, G8 g5 t7 e5 I8 Q& c
The CoreDispatcher() executes all trusted Dxe drivers and just register the Binding protocol if the driver is EFI1.1 driver model.( |- D5 e& x' @' o7 ?  {; ?" ?
Furthermore, Support()/Start() are invoked in BDS phase over the CoreConnectController() rather than CoreDispatcher().
6 ^0 Y8 T( @% }/ e
    在Framework的spec DxeCis.pdf里面也是这么说的,DXE CoreDispatcher()里面,对于EFI1.1 driver model的driver只会安装Handler和Interface到Binding protocol,到BDS才会去执行Support()和Start().
' c0 k% ~9 r5 ?5 Y3 B2 `    但是,我在看code时,发现在CoreDispatcher()-->CoreStartImage()里面call image之后有这么一句:  (file:image.c)7 @9 z) u8 A( y8 e8 `1 f0 Z+ p
  //! E& y; d. n2 [
  // Go connect any handles that were created or modified while the image executed.
5 @+ x/ {: Y  y) z4 B  //# U" J+ d8 |9 i, ?- j4 ^1 a
  CoreConnectHandlesByKey (HandleDatabaseKey);

- X- f- U- ]6 F7 a# M- {这里的HandleDatabaseKey是call image之前由CoreGetHandleDatabaseKey()得到的gHandleDatabaseKey$ _9 D1 n$ L* U
而CoreConnectHandlesByKey会调用到:
+ m' T3 g. `# n4 v  //
* W7 t* C% T) U5 E4 w4 J) R0 D  // Connect all handles whose Key value is greater than Key; y/ t" J- s% T, g$ P2 X0 \5 q
  //
+ C2 f; q9 F5 A& v# V0 _  for (Index = 0; Index < Count; Index++) {  h9 O; C) ~: w" d, ~$ f1 ?# c
    CoreConnectController (HandleBuffer[Index], NULL, NULL, TRUE);
* q1 y8 A) d. N& N# y% j2 G  }

* C, s+ Z2 r7 K所以,照code看,当在Driver中安装一个Handle和Interface到Binding Protocol后(gHandleDatabaseKey会++,IHandle的Key=gHandleDatabaseKey)
3 j1 s( U1 r& F: E) b/ l是会去ConnectController的,也会执行对应的Support()和Start()才对!!
6 r( ?5 M3 |) j) }9 L6 ]9 g0 d) M. L  I
不知道我想的哪里有问题???欢迎大家指正.
0 R; e* i3 `2 w3 [' g' B( |; ^1 b, a+ e$ M
[ 本帖最后由 xtdumpling 于 2008-9-18 15:25 编辑 ]
回复

使用道具 举报

发表于 2008-9-19 14:44:41 | 显示全部楼层
这段code似乎是一个向后兼容的行为,不必太care。
4 M0 _! T* J4 q  e! n一个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 | 显示全部楼层
了解了.
$ I. {/ W! S/ h! U3 C' `非常 感谢!!!
回复

使用道具 举报

发表于 2008-9-23 16:48:56 | 显示全部楼层
在读DXEmain时,
! D% l' p0 W2 [+ B' H; G& CStatus = CoreInitializeImageServices(HobStart);--->CoreInstallProtocolInterface();--->CoreInstallProtocolInterfaceNotify();中,2 Q; p* m: L5 D" I1 \
//! r& H: ^% \+ |! t
// Notify the notification list for this protocol.
. M$ K  y6 ~5 A//5 d' C2 y7 t8 |* k0 H
if (Notify) {! k( [6 E( Y$ N; h! c3 f. [6 A
  CoreNotifyProtocolEntry(ProtEntry);& M' u3 O( O/ \4 B! b, S# B, P4 X
}    里Signal了Event. MS是说一个handle安装了一个protocol后就signal一次.
# a; V" k: h: d6 J有个问题请教一下大家: 这段是在DXE很靠前的位置执行的,但是在它之前我没有看到DXE中有相关的CreateEvent出现?哪位高手能说说这部分代码的流程呢?
回复

使用道具 举报

发表于 2008-9-23 17:04:14 | 显示全部楼层
原帖由 xtdumpling 于 2008-9-16 13:34 发表
9 e( K7 v7 p; z  s6 q' P3 l3 }请楼上的兄弟分析下BS的RegisterProtocolNotify也就是CoreRegisterProtocolNotify是做什么用的?怎么用?
, C" c: L' K) N4 T! t5 |3 @2 ~谢谢!
0 o4 Q! ?( ?6 D5 {
......* r- l, d6 M! b2 G
3 _' F  f4 M& u
' k' H1 H' m, T+ ]2 U; p
[ 本帖最后由 xtdumpling 于 2008-9-23 17:24 编辑 ]
回复

使用道具 举报

发表于 2008-9-24 12:43:45 | 显示全部楼层
原帖由 xtdumpling 于 2008-9-23 17:04 发表 & y4 g7 k# L1 N
' F" {! E( p: o' B( y9 g
......! O. {$ `8 h) G/ C* ?
6 \8 N9 s3 p# q, P9 [4 s8 r
Signal的Event是不是在各个TPL级上挂载一些待处理的事件,一旦restore(TPL)的话,比当前TPL级高的pending事件就回被处理掉?
3 T5 f! T: `7 y: E  o如果是这样的话,Timer事件是如何处理的呢,没有找到相关的代码呀?Xt指点一下再~
回复

使用道具 举报

发表于 2008-9-24 19:00:46 | 显示全部楼层
Timer是挂在8259的IRQ0的中断处理程序上面的, 大概每秒18.3次调用CoreTimerTick()-->CoreCheckTimers()1 M' c. l5 x, F
TPL=30
回复

使用道具 举报

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

本版积分规则

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

GMT+8, 2026-11-4 00:17 , Processed in 0.051281 second(s), 16 queries .

Powered by Discuz! X3.5

© 2001-2025 Discuz! Team.

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