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

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

[复制链接]
发表于 2008-7-27 00:11:28 | 显示全部楼层 |阅读模式
  最近在工作看到机台有启动过程中把SPI ROM数据清空,但苦与没有办法很好的Debug(PCA没有架起来),所有与EDK为对象好好的读了一把。) y* U  u# [! m! E1 ^
' B) x; _9 b, d
SEC/CEI:
8 u5 g+ ]/ u4 l. c. C' i; m  UEFI BIOS启动时先会执行SEC/CEI,这个阶段在实现的BIOS Code中初始化Debug Port,进入Big Mode,CPU的MicroCode,CacheToRAM的转换.然后跳转到PEI阶段。. i2 M0 p, @2 c) d5 O! l, o- {
在EDK中这部分被成了Load FvRecovery.fd文件,这个文件类似与我们的BIOS ROM.里面是我们编译后生成的二进制代码。在这个阶段最主要的是将这个文件加载到内存中(Windows API将文件加载到内存,看API函数).) w$ L, Q4 {/ @4 p5 B* w# |/ \

* u8 E4 \; j$ t  n& A; c: dPEI:
9 Y) P6 A+ P" I   从这里开始UEFI BIOS和EDK执行基本相同,只是一个是从SPI ROM中定位一个地址(PEIM的开始地址),一个是从内存中定位一个地址(PEIM的开始地址)。从这里开始只讲EDK的执行" I! @1 j% d* }2 u
  EDK调用InitializeMemoryService函数,将HobList清空,peiservice清空。
8 W4 d) M5 D# b      InitializePPIService函数,将PPI队列清空,这个队列长0x3F.
6 d* z$ ~2 v1 O. F8 i          InitializeSercurityService函数,将Notify队列清空。5 m; p+ T  H$ _% @3 z  `; _5 b
          InitializeDispatcherData函数,将Dispatcher队列清空。. L/ f& G, |' s  o# U  A4 a2 [
  接着由PeiBuildHobGuid来建立一个HOB(S3返回时这时应该有这个HOB,不用建立,直接使用了,这样就会进入另外一个流程,可以这个EDK不能调试S3,不知道怎么走)。然后由(*PeiServices)->InstallPpi()将这个新HOB加入到PPI中。% G9 g  r8 H; E2 R/ d
    由于在SEC阶段转了以下这几具PPI,所以在执行PEI的Dispatcher之前会先安装东西:1 w1 i# X& `; |& y7 b% }1 Y* t9 F
      EFI_PEI_PPI_DESCRIPTOR    gPrivateDispatchTable[] = {$ S8 Y/ x* O; h! p# i
       {EFI_PEI_PPI_DESCRIPTOR_PPI, &gEfiNtLoadAsDllPpiGuid, &mSecNtLoadAsDllPpi},
. P% A; t+ D$ j" a. w- L4 E" b       {EFI_PEI_PPI_DESCRIPTOR_PPI, &gNtPeiLoadFileGuid, &mSecNtLoadFilePpi},& g4 U/ z( c* L( w5 u: ]  |1 P5 ^
       {EFI_PEI_PPI_DESCRIPTOR_PPI, &gPeiNtAutoScanPpiGuid, &mSecNtAutoScanPpi},/ W  x: H8 J1 e4 t
       {EFI_PEI_PPI_DESCRIPTOR_PPI, &gPeiNtThunkPpiGuid, &mSecWinNtThunkPpi},
) s. ?, l  B  |       {EFI_PEI_PPI_DESCRIPTOR_PPI, &gPeiStatusCodePpiGuid, &mSecStatusCodePpi},
0 b' Q# T4 ]; c       {EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST, &gNtFwhPpiGuid, &mSecFwhInformationPpi}
, I5 q! p5 c6 N1 c3 {     };
( X9 v8 v" h: G2 A    每个PPI是由{类型,GUID(名字,以后就根据这个来找到它的),Function_Entry_Address}组成。5 w: O" x+ K, T
   这些PPI会在PEIDispatcher中用到。9 B! T% g: N* M( k2 w
   安装完这此东西这开始执行PEIDispatcher函数,函数从BIOS ROM文件中找出PEI的Image(怎么找到,请读一下FV_HEAD(EFI_HEAD),里面讲到了如何区分Image类型),然后定位到PEI Image的入口地址,执行他。在我们的的PEI中,我们一般会申明一个PPI,这个就是这个PEI提供一些服务,PEIDispatcher会将他们加入到PPI-List中,以后其他Image也可以调用他的提供的功能。: N% H$ t' o. u" A4 Y$ O/ J
   最后EDK会加载一个叫DXEIPL的PEI,DXEIPL提供一个PPI服务,这个PPI的功能是实现从PEI到DXE的切换,这个PPI里面为DXE做了很多的预准备,加载了很多PPI,如对BIOS的解压方法等。
% P; g5 w0 H! t0 [3 V$ u   SwitchStacks (. |% M! R9 q& j
       (VOID *) (UINTN) DxeCoreEntryPoint,5 T$ q3 \: n. `6 N% `, D! a
       (UINTN) (HobList.Raw),
+ t% o: z& \( {/ [2 X0 N       (VOID *) (UINTN) TopOfStack,
5 x# J- @0 A0 `3 A6 r       (VOID *) (UINTN) BspStore
$ G6 D. U0 b* t: |4 a" V    );
) {2 v% R6 v3 v' J6 s+ h1 y3 M, k  用过汇编的人对这个技术一定很熟悉,不多说了(我别不清,咯。。。)1 D6 o# q" Z: a6 a2 ]/ T6 \' D
) S, l- p6 |5 B: a4 K) }+ M* l
DXE:
  J' u) c2 |, t- H$ e2 k     从PEI到DXE切换时转过来一个HOBLIST参数,DXE会在这个HOB中找到Memory的使用情况,然后根据这些情况将BIOS引到内存(这是EFI的做法)。在EDK在DXE时重新定位一下内存。
# B, K+ e5 i  s% \1 c接着就会定义我们经常使用到的gST表,gRT表。接着是申明一些Protocol(先不关心这些事)。
1 u8 w: g8 Y4 Z/ J, W6 Z6 m. D) D$ ~   等这些该加的PPI,Protocol加完了,CoreDispatcher()就出场了。他会的功能类似PEIDispatcher()。从我们BIOS ROM中将DXE的驱动读出,执行执行他们,这时会执行到Driver
* |$ n! B- F) `4 Z中的Support(),Start()两个功能函数。在这两个函数中你可以注册自己的PPI,为其他驱动提供服务。
7 e- O" C4 Y$ Z1 y3 @   到些BIOS的引导其他完成。接着该进OS了,看Linux 0.11吧,操作系统是怎么做事情的。
2 x' m' L3 D  I4 k: e   ' n3 }, M  n# Y/ {7 R/ z' V% ~0 A
Driver:
- T0 ~9 X, H8 J* V+ p    我们的驱动什么为在PEI和DXE等不同阶段执行呢?
/ {# z( w' E3 c- N9 {0 o$ B  大家请看一下我们的驱动的makefile.(EDK中的*.inf)
$ ~* a: y, V) D  [defines]; [, T* i- }! P: ~% s
  BASE_NAME            = OWEN
( W6 @3 W8 d. u+ R' G! g( E0 }' D  FILE_GUID            = 1EDD13C1-62EF-4262-A1AA-0040D0830110, t+ d/ b5 p  r% X% E2 q
  COMPONENT_TYPE       = BS_DRIVER
+ k5 B( o6 n, A  E. Y) |& t  r! W3 b: n0 w* Y
  BASE_NAME告诉编译器最终生成的驱动的名字。
  ]9 d% J: k# I: w4 c  FILE_GUID就是这个驱动的GUID名字,在BIOS中引用某个驱动就是根据它来调用和识别。$ s. W, T) _5 h  F% Y
  COMONENT_TYPE会告诉编译器生成驱动的类型,是PEI,DXE,等。
% l% E$ L4 K, e  在EDK中有一个FWVolume.c实现的功能就是帮我们把这个TYPE转换面相应的扩展名
2 N; g8 d- ^; T$ e5 ~$ u0 A6 @  COMP_TYPE_EXTENSION  mCompTypeExtension[] = {
/ p0 Y) p& H) `7 n. v7 T0 ?  {"bs_driver",  ".dxe" },- u& z' v. Q+ l4 W; z3 E* u  B+ K
  {"rt_driver",  ".dxe" },, v( N* B$ E) S. _4 Q4 M
  {"sal_rt_driver", ".dxe"},( n: X4 c4 U% u. h: I
  {"security_core", ".sec"},
: ~7 Y# i6 k7 d* W  {"pei_core", ".pei"},' i$ b3 ^" C; X; e
  {"pic_peim", ".pei"},( k' E" e6 |7 n/ i; L4 c+ D
  {"pe32_peim", ".pei"},
" h9 Y/ R$ }: L  {"relocatable_peim", ".pei"},
. P+ e- I# F8 x" X# a  {"binary", ".ffs"},- V6 p! x5 L4 j% c" K# @
  {"application", ".app"},
5 M1 f& M' |7 ?" V1 Q/ d+ P' D1 R( {  {"file", ".ffs"},3 F5 C, I) }- C
  {"fvimagefile", ".fvi"},
1 G" ?7 p% Z  G% _. P  {"rawfile", ".raw"},) m& @/ @" Y3 c# f* ]
  {"apriori", ".ffs"},4 D+ q6 g5 `2 i$ W/ V
  {"combined_peim_driver", ".pei"},# J* [8 s+ U9 G0 {' R7 l
  { NULL,  NULL }: G: F8 A3 h& d4 @- ]
};
) o5 q1 s9 p- D4 y' e
% N! w, z5 o% ?  B. h了解了这些,接下我们可以看驱动篇了。(Go On Study... Forever)
/ L' \) \5 F" _: V5 ]   
- }1 I  T( S# `4 x         * z9 i2 G2 T3 B( e5 c- ]
  
发表于 2008-7-27 12:30:15 | 显示全部楼层
不错!
7 r/ `8 Q# K3 d, l  c支持) a$ F4 l' h; x3 ]
继续
5 m7 e- J; a) y1 c2 A+ O加油' E6 V# ]% c! z5 G
回复

使用道具 举报

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

回复 1# 的帖子

gPrivateDispatchTable 和COMP_TYPE_EXTENSION  没有搜到啊  是EDK专有的么?, K; x$ h) b& J+ Z; p4 Q
有看过跟gPrivateDispatchTable 类似的,但是里面的PPI不同。
2 K; w" l" H3 M还有这个COMP_TYPE_EXTENSION  没有找到过。FWVolume.c这个文件也没有发现。。
回复

使用道具 举报

发表于 2008-7-28 13:24:20 | 显示全部楼层
这东西虽说没有什么技术含量,但是总结一下还是非常好的。1 A( f  s% G% P, x& ^
' x! P6 H" @( Y6 c; v
支持!
回复

使用道具 举报

 楼主| 发表于 2008-7-28 18:52:31 | 显示全部楼层
( i& h  G4 x; T: @+ V/ f1 Y# O
小弟还在学习阶段,目前的目标是知道执行的流程。
: `1 L6 |' w4 ~9 H3 y这里面有很多细节没有写,能力有限,只能自己知道,不能表达。
5 s# S- W& h  L) W' N% a嘿。。。。
5 m8 {2 I6 k3 L- y所有大侠们如果有好东西能给小弟共享一份。4 w3 Q7 ~5 C( E" g) ]) [- {

9 x- ^' ^* v+ u谢谢!
回复

使用道具 举报

发表于 2008-8-12 14:44:11 | 显示全部楼层
原帖由 winbondowen 于 2008-7-27 00:11 发表
3 m7 T$ H+ g; d) {5 x  ROM中將DXE的驅動讀出,執行執行他們,這時會執行到Driver
) V# x- S2 }3 D5 `9 l% ?中的Support(),Start()兩個功能函數。在這兩個函數中你可以註冊自己的PPI ...

# q" Q1 F( h9 h' ~! V( _) V' P8 l7 e3 g! s0 q
PPIs are registered during PEI phase, but Support()/Start() are invoked in DXE driver binding protocol, + ^! o* L' i( }- N' z1 G9 l3 i8 a
For more precisely, I think the "PPI" you mentioned is the "PROTOCOL" rather than "PPI".1 M4 Q5 i1 W0 G
/ \; k/ u9 m# \, o! ]- p! j
[ 本帖最后由 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:1 q/ H' M- Q! }0 W6 `/ V, C
   Yes. I make a mistake.3 Q# c8 q& P. F# P
      PPI:     A PEIM to PEIM interface.
/ H! o+ p' \! o      PROTOCL: A Interface between Hardware(or firmware) and software.$ R+ A. q5 r' ~: C0 j( s
      reference[http://www.biosren.com/viewthread.php?tid=207]9 d0 |) l  y/ ]& q
   so, PPI execute at PEI step and Initialize hardware. PROTOCOL execute by DXE step.! o" @$ g7 Z! M' `% w8 w
   Thanks.
回复

使用道具 举报

发表于 2008-8-20 17:47:21 | 显示全部楼层
原帖由 winbondowen 于 2008-7-27 00:11 发表 DXE:
# v  y7 t1 N$ v! o     從PEI到DXE切換時轉過來一個HOBLIST參數,DXE會在這個HOB中找到Memory的使用情況,然後根據這些情況將BIOS引到內存(這是EFI的做法)。在EDK在DXE時重新定位一下內存。
7 p' m' m5 z" q0 g& d8 m9 m9 g接著就會定義我們經常使用到的gST表,gRT表。接著是申明一些Protocol(先不關心這些事)。8 h3 ~! X# Z4 U; f" B+ k
   等這些該加的PPI,Protocol加完了,CoreDispatcher()就出場了。他會的功能類似PEIDispatcher()。從我們BIOS ROM中將DXE的驅動讀出,執行執行他們,這時會執行到Driver
: z  E' A. Q2 S中的Support(),Start()兩個功能函數。在這兩個函數中你可以註冊自己的PPI,為其他驅動提供服務。
* A( [) [- {- m7 g* R9 n8 j% {6 m   到些BIOS的引導其他完成。接著該進OS了,看Linux 0.11吧,操作系統是怎麼做事情的。.
0 l9 Q. L$ q8 l

; g& k' i; c& n* {$ X1 b, n( ~There are mistakes,
( Z0 e" }; o' D3 V* C. U: }6 ?1.gST and gRT are init after the DXE architectural protocols have been loaded, those protocols response for creating Dxe foundation.$ g( _; x9 n6 Q( W# n5 \
' Z1 H- ?. h, C9 @2 x
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.
* {% H/ C4 N+ IThe CoreDispatcher() executes all trusted Dxe drivers and just register the Binding protocol if the driver is EFI1.1 driver model.9 V' y5 _' f5 w! Q8 A6 t9 X4 @
Furthermore, Support()/Start() are invoked in BDS phase over the CoreConnectController() rather than CoreDispatcher().
* S* R( C1 _- J) |) b$ e. O4 O6 K6 r: \- a4 E( x* a8 g. |
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 p! I0 C$ c; ~: }; m
回复

使用道具 举报

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

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

原帖由 ichirohiro 于 2008-8-20 17:47 发表 ; O- W/ a! y) f! m2 ]8 w+ _# t
...
/ {; H9 p( q* K/ F& h# b: @5 W5 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.; Q* I" a) T% G) w) m
The CoreDispatcher() executes all trusted Dxe drivers and just register the Binding protocol if the driver is EFI1.1 driver model.) S9 y. }. d3 k# P. Z" w
Furthermore, Support()/Start() are invoked in BDS phase over the CoreConnectController() rather than CoreDispatcher().
# l# d. h% `9 L6 ]6 q& z
    在Framework的spec DxeCis.pdf里面也是这么说的,DXE CoreDispatcher()里面,对于EFI1.1 driver model的driver只会安装Handler和Interface到Binding protocol,到BDS才会去执行Support()和Start().
7 W/ U# j$ F, M% w    但是,我在看code时,发现在CoreDispatcher()-->CoreStartImage()里面call image之后有这么一句:  (file:image.c)6 Q2 L# {# V# \5 O
  //
: P! B  n3 k3 q4 r- J- J, s  // Go connect any handles that were created or modified while the image executed.
8 _: ^1 C# ?0 w( f" u  //
6 w1 m' n6 t8 S5 ]6 z3 A  CoreConnectHandlesByKey (HandleDatabaseKey);

  j- ~1 U- i7 [: I  ?这里的HandleDatabaseKey是call image之前由CoreGetHandleDatabaseKey()得到的gHandleDatabaseKey9 g. m2 v, I# n  h3 g
而CoreConnectHandlesByKey会调用到:4 M* X5 K! K0 B1 I! r* \
  //1 \+ O* y% E7 G: z3 y# j
  // Connect all handles whose Key value is greater than Key& S! M: k" k* k) _
  //: \" g) T3 K2 A2 ?" o
  for (Index = 0; Index < Count; Index++) {3 d2 u4 G* w: U& ?& A
    CoreConnectController (HandleBuffer[Index], NULL, NULL, TRUE);3 L) u+ G$ y, F% [& M
  }

1 v9 Z1 l$ o$ E所以,照code看,当在Driver中安装一个Handle和Interface到Binding Protocol后(gHandleDatabaseKey会++,IHandle的Key=gHandleDatabaseKey)$ N  t# F; I/ C! v
是会去ConnectController的,也会执行对应的Support()和Start()才对!!$ O2 P% X& Y. O* Z; u
  `& a7 s9 O5 I2 t
不知道我想的哪里有问题???欢迎大家指正.7 r0 c  ]% f) c! s+ _
0 S1 X2 U' y. L9 @
[ 本帖最后由 xtdumpling 于 2008-9-18 15:25 编辑 ]
回复

使用道具 举报

发表于 2008-9-19 14:44:41 | 显示全部楼层
这段code似乎是一个向后兼容的行为,不必太care。4 J2 W$ V0 X' V- ]  g  B
一个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 | 显示全部楼层
了解了.
  u6 Q; I- N3 z, a( G9 i非常 感谢!!!
回复

使用道具 举报

发表于 2008-9-23 16:48:56 | 显示全部楼层
在读DXEmain时,# J# l% N2 ?9 K' b6 X
Status = CoreInitializeImageServices(HobStart);--->CoreInstallProtocolInterface();--->CoreInstallProtocolInterfaceNotify();中,! K% z3 d  B9 K3 P
//  X5 C; ^. c3 Q
// Notify the notification list for this protocol.
% Z9 r1 _. d! t7 o- F# a' Z//
0 v$ j" {) z# V2 n! ^$ g+ H& l6 e1 sif (Notify) {
7 T. D7 B8 o; s3 H  CoreNotifyProtocolEntry(ProtEntry);- o$ ?* C% y/ |
}    里Signal了Event. MS是说一个handle安装了一个protocol后就signal一次.; D3 }% u& T7 g# z" m( U
有个问题请教一下大家: 这段是在DXE很靠前的位置执行的,但是在它之前我没有看到DXE中有相关的CreateEvent出现?哪位高手能说说这部分代码的流程呢?
回复

使用道具 举报

发表于 2008-9-23 17:04:14 | 显示全部楼层
原帖由 xtdumpling 于 2008-9-16 13:34 发表
% k' n' B( A$ F+ }) g9 r1 l请楼上的兄弟分析下BS的RegisterProtocolNotify也就是CoreRegisterProtocolNotify是做什么用的?怎么用?
( Q8 S/ `& I. h5 s. ?  |, U! t2 @5 o谢谢!

( j; L4 n0 ~4 i2 Y......2 o  S# i8 n1 F0 h
. \7 L& A3 X2 o( m

) h) q1 m4 t% S/ @9 ?[ 本帖最后由 xtdumpling 于 2008-9-23 17:24 编辑 ]
回复

使用道具 举报

发表于 2008-9-24 12:43:45 | 显示全部楼层
原帖由 xtdumpling 于 2008-9-23 17:04 发表
5 I! \* ]" G( z$ D6 i( c6 i0 {  e/ ~6 L
......
' R& `1 E# C! T6 `$ Q+ k
4 N" }) l0 a1 Y
Signal的Event是不是在各个TPL级上挂载一些待处理的事件,一旦restore(TPL)的话,比当前TPL级高的pending事件就回被处理掉?& s. J. G, i: Z5 w* C4 o6 C
如果是这样的话,Timer事件是如何处理的呢,没有找到相关的代码呀?Xt指点一下再~
回复

使用道具 举报

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

使用道具 举报

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

本版积分规则

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

GMT+8, 2026-1-18 22:41 , Processed in 1.339492 second(s), 16 queries .

Powered by Discuz! X3.5

© 2001-2025 Discuz! Team.

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