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

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

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

2 E" @8 h- L! s. RSEC/CEI:- e' K( ^4 c6 y- Z2 U9 M
  UEFI BIOS启动时先会执行SEC/CEI,这个阶段在实现的BIOS Code中初始化Debug Port,进入Big Mode,CPU的MicroCode,CacheToRAM的转换.然后跳转到PEI阶段。
) T/ P3 T- g6 _4 ^; z8 z在EDK中这部分被成了Load FvRecovery.fd文件,这个文件类似与我们的BIOS ROM.里面是我们编译后生成的二进制代码。在这个阶段最主要的是将这个文件加载到内存中(Windows API将文件加载到内存,看API函数).0 j! ^& W0 q, Z/ a

+ o: t, f4 }7 m9 S" H8 ^3 xPEI:1 B0 G9 @* J; u+ V5 L  f& F6 H
   从这里开始UEFI BIOS和EDK执行基本相同,只是一个是从SPI ROM中定位一个地址(PEIM的开始地址),一个是从内存中定位一个地址(PEIM的开始地址)。从这里开始只讲EDK的执行
% f2 X' j; n! _6 c& F! y: j  EDK调用InitializeMemoryService函数,将HobList清空,peiservice清空。: F  c7 G3 Y$ h% l  x5 F
      InitializePPIService函数,将PPI队列清空,这个队列长0x3F.
3 u# W  e/ B" Q          InitializeSercurityService函数,将Notify队列清空。* B( e6 O5 o1 d+ c4 j3 x
          InitializeDispatcherData函数,将Dispatcher队列清空。4 }$ H( j! g9 y/ I7 X% D, T2 ]
  接着由PeiBuildHobGuid来建立一个HOB(S3返回时这时应该有这个HOB,不用建立,直接使用了,这样就会进入另外一个流程,可以这个EDK不能调试S3,不知道怎么走)。然后由(*PeiServices)->InstallPpi()将这个新HOB加入到PPI中。
( q/ Y" }" I7 O    由于在SEC阶段转了以下这几具PPI,所以在执行PEI的Dispatcher之前会先安装东西:
& v4 {) I5 |, W: G; z      EFI_PEI_PPI_DESCRIPTOR    gPrivateDispatchTable[] = {
; ]; A. s( a# B" e2 l       {EFI_PEI_PPI_DESCRIPTOR_PPI, &gEfiNtLoadAsDllPpiGuid, &mSecNtLoadAsDllPpi},0 Q0 v8 v( w+ X4 ^4 l- V
       {EFI_PEI_PPI_DESCRIPTOR_PPI, &gNtPeiLoadFileGuid, &mSecNtLoadFilePpi},, S+ Z4 y+ w" p* {+ B
       {EFI_PEI_PPI_DESCRIPTOR_PPI, &gPeiNtAutoScanPpiGuid, &mSecNtAutoScanPpi},0 C; \, y1 }6 T) T% j- K
       {EFI_PEI_PPI_DESCRIPTOR_PPI, &gPeiNtThunkPpiGuid, &mSecWinNtThunkPpi},; [3 V8 e. x" G3 y: F
       {EFI_PEI_PPI_DESCRIPTOR_PPI, &gPeiStatusCodePpiGuid, &mSecStatusCodePpi},5 N5 a% T; ?! T* x, e) k% {
       {EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST, &gNtFwhPpiGuid, &mSecFwhInformationPpi}
( l+ R: r/ i" [$ }$ F2 N+ e% \     };
" m" i" h5 e( ?8 ^* g/ G    每个PPI是由{类型,GUID(名字,以后就根据这个来找到它的),Function_Entry_Address}组成。9 w( I: t4 R- _/ \. J' j- b
   这些PPI会在PEIDispatcher中用到。
* l) N$ Y( z- l! K   安装完这此东西这开始执行PEIDispatcher函数,函数从BIOS ROM文件中找出PEI的Image(怎么找到,请读一下FV_HEAD(EFI_HEAD),里面讲到了如何区分Image类型),然后定位到PEI Image的入口地址,执行他。在我们的的PEI中,我们一般会申明一个PPI,这个就是这个PEI提供一些服务,PEIDispatcher会将他们加入到PPI-List中,以后其他Image也可以调用他的提供的功能。
* W3 L$ _, C# N   最后EDK会加载一个叫DXEIPL的PEI,DXEIPL提供一个PPI服务,这个PPI的功能是实现从PEI到DXE的切换,这个PPI里面为DXE做了很多的预准备,加载了很多PPI,如对BIOS的解压方法等。
( G) P) l3 H# g- `2 \$ n   SwitchStacks (  c( f  P8 g1 X' F9 k: Z* E) A: o
       (VOID *) (UINTN) DxeCoreEntryPoint,- c+ {* v8 P6 h* Y% w5 g
       (UINTN) (HobList.Raw),
8 G& S8 C: w1 z- d" o7 o4 G! H  H       (VOID *) (UINTN) TopOfStack,' Y# g. {. S3 T3 _& z" \$ H
       (VOID *) (UINTN) BspStore
3 ~! \1 s) V1 l9 ~+ }    );
7 z. d6 k/ b2 V, v0 ?% S0 k  用过汇编的人对这个技术一定很熟悉,不多说了(我别不清,咯。。。)
/ z3 s( d4 w9 t3 Q: X% D, ]7 q1 Q1 s. ^( {4 P, @( p% ~* ]+ n! y& q
DXE:$ C% Y6 _4 T* L" v0 t7 g3 O
     从PEI到DXE切换时转过来一个HOBLIST参数,DXE会在这个HOB中找到Memory的使用情况,然后根据这些情况将BIOS引到内存(这是EFI的做法)。在EDK在DXE时重新定位一下内存。
$ ^- A6 S. j4 z' h9 ?! m接着就会定义我们经常使用到的gST表,gRT表。接着是申明一些Protocol(先不关心这些事)。+ m* k: o' U5 V5 f$ X  F
   等这些该加的PPI,Protocol加完了,CoreDispatcher()就出场了。他会的功能类似PEIDispatcher()。从我们BIOS ROM中将DXE的驱动读出,执行执行他们,这时会执行到Driver
" u2 e4 d  {. v1 y6 A中的Support(),Start()两个功能函数。在这两个函数中你可以注册自己的PPI,为其他驱动提供服务。
/ h" ]/ N- s& X7 f+ @* ?   到些BIOS的引导其他完成。接着该进OS了,看Linux 0.11吧,操作系统是怎么做事情的。
7 B2 @. e4 u/ S+ s: |( i) [2 K' e   
/ D, ]* B$ A% N( Y) P* G$ r3 PDriver:
. a0 f" A0 S. i( `$ V    我们的驱动什么为在PEI和DXE等不同阶段执行呢?& e7 m+ m; j' I. I& j4 r7 g
  大家请看一下我们的驱动的makefile.(EDK中的*.inf), ^3 K6 M. v4 {9 D+ R9 ]6 t/ C& M
  [defines]
5 d( P" u% w$ ]/ ~0 U  BASE_NAME            = OWEN
, k1 F% C( D1 A0 ]5 G$ c: }( d  FILE_GUID            = 1EDD13C1-62EF-4262-A1AA-0040D0830110: N: ?) P! p; w! J2 l$ G& H
  COMPONENT_TYPE       = BS_DRIVER, [7 t* |' ]1 E' S; N; s9 x5 \
8 u1 J8 V9 i: K* d& e) z5 z: r/ Z
  BASE_NAME告诉编译器最终生成的驱动的名字。
6 @5 o; Y6 J; l1 X  FILE_GUID就是这个驱动的GUID名字,在BIOS中引用某个驱动就是根据它来调用和识别。
/ d5 b4 W7 P# ?8 `8 Q% A  COMONENT_TYPE会告诉编译器生成驱动的类型,是PEI,DXE,等。
* c2 g+ u6 L( b4 x  在EDK中有一个FWVolume.c实现的功能就是帮我们把这个TYPE转换面相应的扩展名' y! L% E! h. R' G/ @
  COMP_TYPE_EXTENSION  mCompTypeExtension[] = {
9 r$ f! V/ r. @" ^# B  {"bs_driver",  ".dxe" },5 {8 {& T! c% ^
  {"rt_driver",  ".dxe" },
& d% y" {0 V2 [$ ?  {"sal_rt_driver", ".dxe"},: @* N% V$ L' U% M& y
  {"security_core", ".sec"},8 [- m3 \) f9 ?
  {"pei_core", ".pei"},
" i- E# t" \8 n/ ]7 B8 m  {"pic_peim", ".pei"},6 a2 z  F3 @* x& W) V: Z
  {"pe32_peim", ".pei"}," G! C( H" V5 i5 w5 C7 h4 K
  {"relocatable_peim", ".pei"},3 V+ ]. P. e4 Z- S) y/ z
  {"binary", ".ffs"},
7 R6 f4 b- Q% W, }* L( C) W$ f4 K  {"application", ".app"},8 ~0 |/ o: s+ w  [$ t# F' ^$ S) D
  {"file", ".ffs"},
. T: G! ]0 d% K* x  T8 X  {"fvimagefile", ".fvi"},# j& J9 a+ k( d& [' @% N
  {"rawfile", ".raw"},' p" r/ M( r+ K4 Z
  {"apriori", ".ffs"},
0 `- Z: ^$ h8 l6 e  {"combined_peim_driver", ".pei"},& e+ ~' n7 Y1 d+ O4 Z; |  k- Z
  { NULL,  NULL }+ t" I, Y  f. F6 X# I2 E. Z) Q; `
};
$ s7 S" V) b6 a* e
  {: {0 M5 C5 t$ O/ _- N/ q! W* V了解了这些,接下我们可以看驱动篇了。(Go On Study... Forever)7 w# N5 K( n3 s, @1 y2 y
   ' E: E% I6 Z  a, Q+ c' @
         
: k& D; o/ |* b  W* j# B  
发表于 2008-7-27 12:30:15 | 显示全部楼层
不错!
6 G6 ~$ g; S$ ?8 ^; v' ]/ D7 b支持
* T1 W& v  l& N0 G继续$ U0 A0 k4 r# w: }; m
加油
* `4 A" N' B! c, I
回复

使用道具 举报

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

回复 1# 的帖子

gPrivateDispatchTable 和COMP_TYPE_EXTENSION  没有搜到啊  是EDK专有的么?
6 W4 c6 C1 C! C) I" A: r1 s' T有看过跟gPrivateDispatchTable 类似的,但是里面的PPI不同。: w9 G5 v* s4 |# u+ s! B/ ~
还有这个COMP_TYPE_EXTENSION  没有找到过。FWVolume.c这个文件也没有发现。。
回复

使用道具 举报

发表于 2008-7-28 13:24:20 | 显示全部楼层
这东西虽说没有什么技术含量,但是总结一下还是非常好的。" `/ Z  z; K$ @/ N) ^
5 u; }, e, |% q3 S6 a1 \
支持!
回复

使用道具 举报

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

- E) c, m' k- i2 [% U5 z; S小弟还在学习阶段,目前的目标是知道执行的流程。- |* l. O, L# D$ A
这里面有很多细节没有写,能力有限,只能自己知道,不能表达。3 R- i+ ]  i, H! z. m7 k: s' p
嘿。。。。. U% @! g: x, E
所有大侠们如果有好东西能给小弟共享一份。
  A6 z. O) U/ f, H( [- N' I
* j% g( u, G' U$ v/ E$ m! q' y! \谢谢!
回复

使用道具 举报

发表于 2008-8-12 14:44:11 | 显示全部楼层
原帖由 winbondowen 于 2008-7-27 00:11 发表
) |: B, i- ?) ~- A- ~2 S# J  ROM中將DXE的驅動讀出,執行執行他們,這時會執行到Driver+ a7 ?0 b2 i# g% `2 n
中的Support(),Start()兩個功能函數。在這兩個函數中你可以註冊自己的PPI ...
. S# N4 m9 t+ Q% W1 f( `

% r# }2 m9 \7 [PPIs are registered during PEI phase, but Support()/Start() are invoked in DXE driver binding protocol, * G8 _! \( }3 E! u7 q2 i
For more precisely, I think the "PPI" you mentioned is the "PROTOCOL" rather than "PPI".
0 ?. D) Z3 P% W5 V' p. J7 \9 X" i
[ 本帖最后由 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:8 z' v! P8 W0 r/ ~9 ]+ q8 l9 {
   Yes. I make a mistake.# v/ u( H; @/ O2 \- G3 m; h9 `7 i  d
      PPI:     A PEIM to PEIM interface.
- a. [! e, r  f3 V# E1 p- U5 V      PROTOCL: A Interface between Hardware(or firmware) and software.+ `. k$ d1 W2 D; F. y9 }
      reference[http://www.biosren.com/viewthread.php?tid=207]  p8 D% _8 B, d" @5 q) J% e
   so, PPI execute at PEI step and Initialize hardware. PROTOCOL execute by DXE step.3 g2 R, x* o+ a- h/ N6 o4 I; E8 k$ X
   Thanks.
回复

使用道具 举报

发表于 2008-8-20 17:47:21 | 显示全部楼层
原帖由 winbondowen 于 2008-7-27 00:11 发表 DXE:+ n6 r8 d5 }* V/ v
     從PEI到DXE切換時轉過來一個HOBLIST參數,DXE會在這個HOB中找到Memory的使用情況,然後根據這些情況將BIOS引到內存(這是EFI的做法)。在EDK在DXE時重新定位一下內存。
' H3 A8 h* v) O2 d* _接著就會定義我們經常使用到的gST表,gRT表。接著是申明一些Protocol(先不關心這些事)。
2 w" T! n: x3 W! L   等這些該加的PPI,Protocol加完了,CoreDispatcher()就出場了。他會的功能類似PEIDispatcher()。從我們BIOS ROM中將DXE的驅動讀出,執行執行他們,這時會執行到Driver% ]2 h, R' E7 l
中的Support(),Start()兩個功能函數。在這兩個函數中你可以註冊自己的PPI,為其他驅動提供服務。
( K$ ~! j& }5 p5 A   到些BIOS的引導其他完成。接著該進OS了,看Linux 0.11吧,操作系統是怎麼做事情的。.

' i* p* `) S* g, Z: M6 o$ _5 B4 d4 r% q& I0 [9 j  t  U# G
There are mistakes,
' w% ?: {! ?. [1 D. r; g) M4 N3 j1.gST and gRT are init after the DXE architectural protocols have been loaded, those protocols response for creating Dxe foundation.* d, a1 b, t7 w# B: Z& }
  Y! M. S% A' R% m8 d: W
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.% Z% X! K- T/ b$ N
The CoreDispatcher() executes all trusted Dxe drivers and just register the Binding protocol if the driver is EFI1.1 driver model.
+ M! z' E/ ?0 W# G" UFurthermore, Support()/Start() are invoked in BDS phase over the CoreConnectController() rather than CoreDispatcher().$ t0 O% m7 n9 |% }9 z

% ?  z0 S3 x6 Q" B4 r& T- w8 QBTW, 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 大侠的指点。
$ u& |. Q$ a$ U- k( X# H" V
回复

使用道具 举报

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

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

原帖由 ichirohiro 于 2008-8-20 17:47 发表
* P1 P2 W9 b  M( N% m...
# A  Q5 j& b% U2.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! I2 [0 h& _$ F7 m2 BThe CoreDispatcher() executes all trusted Dxe drivers and just register the Binding protocol if the driver is EFI1.1 driver model.# k3 Y4 i( H& n( ?4 g$ }2 o: U9 t2 H
Furthermore, Support()/Start() are invoked in BDS phase over the CoreConnectController() rather than CoreDispatcher().
  I7 P* C# h) {% [  V9 e5 |& @  E
    在Framework的spec DxeCis.pdf里面也是这么说的,DXE CoreDispatcher()里面,对于EFI1.1 driver model的driver只会安装Handler和Interface到Binding protocol,到BDS才会去执行Support()和Start().
3 a9 K5 o+ e' ^  |    但是,我在看code时,发现在CoreDispatcher()-->CoreStartImage()里面call image之后有这么一句:  (file:image.c)
5 n! P4 S( q* N4 K& e3 s$ ~: c0 s6 v  //
8 J1 G2 z( f2 N5 v9 z( A; Z3 L3 y, a, E  // Go connect any handles that were created or modified while the image executed.
. X8 `3 `0 o( R6 \% ]  //0 ^* k& k5 g1 N+ U
  CoreConnectHandlesByKey (HandleDatabaseKey);

% o2 ~3 |- O% z" U! X, y% K9 {这里的HandleDatabaseKey是call image之前由CoreGetHandleDatabaseKey()得到的gHandleDatabaseKey7 B- [. M* c  X7 E: Q& c% D
而CoreConnectHandlesByKey会调用到:4 _2 l( _# D) B/ @+ R3 g" f
  //
+ |: f' J, G  Z+ h  s# _; e  // Connect all handles whose Key value is greater than Key8 Z# [/ u6 e. ?/ S! C$ U+ A$ J  C2 m
  //" T$ N! F$ T1 W/ e/ h6 v
  for (Index = 0; Index < Count; Index++) {& {. c8 H' \/ V! F
    CoreConnectController (HandleBuffer[Index], NULL, NULL, TRUE);( G) d* e9 l* }. q3 h* o
  }
" O  Q3 i# S: e+ T
所以,照code看,当在Driver中安装一个Handle和Interface到Binding Protocol后(gHandleDatabaseKey会++,IHandle的Key=gHandleDatabaseKey)4 i# Y* T( f; Y8 \  B3 R3 a
是会去ConnectController的,也会执行对应的Support()和Start()才对!!
8 k& v' E, z8 D: t; {
0 ]+ ~( G3 t) b5 C  c5 s8 x不知道我想的哪里有问题???欢迎大家指正.
3 L4 a  q' H) l/ w+ y4 ?6 x4 z0 T. z7 ~% N: ]) a
[ 本帖最后由 xtdumpling 于 2008-9-18 15:25 编辑 ]
回复

使用道具 举报

发表于 2008-9-19 14:44:41 | 显示全部楼层
这段code似乎是一个向后兼容的行为,不必太care。+ l3 r& A* h- t9 C- ?
一个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 | 显示全部楼层
了解了.
* |, S0 P- L: N3 p+ Y非常 感谢!!!
回复

使用道具 举报

发表于 2008-9-23 16:48:56 | 显示全部楼层
在读DXEmain时,
& c) ~/ Z1 l# O2 O1 XStatus = CoreInitializeImageServices(HobStart);--->CoreInstallProtocolInterface();--->CoreInstallProtocolInterfaceNotify();中,' q" J# P! |' y) v; b: ?. h! a1 u
//2 Z( |, V& A0 \0 `& ]% F) R" ?
// Notify the notification list for this protocol.
* c- a! `& n1 n# r3 `" t2 T* k//
; N4 v  }; v4 ]; |$ t  L; N, Lif (Notify) {
. T1 b. J' g1 x: e  CoreNotifyProtocolEntry(ProtEntry);' P" E4 J" ~. T0 ~* V/ t) j
}    里Signal了Event. MS是说一个handle安装了一个protocol后就signal一次.: l% K6 P; C2 }, z; h
有个问题请教一下大家: 这段是在DXE很靠前的位置执行的,但是在它之前我没有看到DXE中有相关的CreateEvent出现?哪位高手能说说这部分代码的流程呢?
回复

使用道具 举报

发表于 2008-9-23 17:04:14 | 显示全部楼层
原帖由 xtdumpling 于 2008-9-16 13:34 发表 ) H$ S/ L7 [! b6 f
请楼上的兄弟分析下BS的RegisterProtocolNotify也就是CoreRegisterProtocolNotify是做什么用的?怎么用?
* Z8 N9 _0 A1 n+ k谢谢!
- N1 k: N$ q: s' l& }
......
3 L& u* O  o- ~, @- s" A" K7 x0 a$ {) G$ [# ], Q4 y

5 h/ `6 S' x% k4 b[ 本帖最后由 xtdumpling 于 2008-9-23 17:24 编辑 ]
回复

使用道具 举报

发表于 2008-9-24 12:43:45 | 显示全部楼层
原帖由 xtdumpling 于 2008-9-23 17:04 发表 0 I, l+ l" S  i% t

" p! Z5 n+ b$ r: A) \& Q......3 W  Q# U; ~1 Q; U8 y; `# q

# {3 Z& w$ A; W% }6 LSignal的Event是不是在各个TPL级上挂载一些待处理的事件,一旦restore(TPL)的话,比当前TPL级高的pending事件就回被处理掉?. Z& y' V! k9 |
如果是这样的话,Timer事件是如何处理的呢,没有找到相关的代码呀?Xt指点一下再~
回复

使用道具 举报

发表于 2008-9-24 19:00:46 | 显示全部楼层
Timer是挂在8259的IRQ0的中断处理程序上面的, 大概每秒18.3次调用CoreTimerTick()-->CoreCheckTimers()% R4 {+ Z2 Y7 s7 j: \3 m$ \
TPL=30
回复

使用道具 举报

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

本版积分规则

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

GMT+8, 2026-4-4 14:30 , Processed in 0.121256 second(s), 17 queries .

Powered by Discuz! X3.5

© 2001-2025 Discuz! Team.

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