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

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

[复制链接]
发表于 2008-7-27 00:11:28 | 显示全部楼层 |阅读模式
  最近在工作看到机台有启动过程中把SPI ROM数据清空,但苦与没有办法很好的Debug(PCA没有架起来),所有与EDK为对象好好的读了一把。9 u/ E. p' l* j
! k- i' a, q$ D# X! o+ K  |
SEC/CEI:& k2 u  O: m! P% G  Z
  UEFI BIOS启动时先会执行SEC/CEI,这个阶段在实现的BIOS Code中初始化Debug Port,进入Big Mode,CPU的MicroCode,CacheToRAM的转换.然后跳转到PEI阶段。
! w: O4 O$ H; E- v在EDK中这部分被成了Load FvRecovery.fd文件,这个文件类似与我们的BIOS ROM.里面是我们编译后生成的二进制代码。在这个阶段最主要的是将这个文件加载到内存中(Windows API将文件加载到内存,看API函数).9 ?! l7 r6 c( |% N" h+ `+ r& _! ]* c
$ n, U- ]: s7 b9 ^- [4 {
PEI:0 ?3 v$ H% Z6 ]$ G! b! M
   从这里开始UEFI BIOS和EDK执行基本相同,只是一个是从SPI ROM中定位一个地址(PEIM的开始地址),一个是从内存中定位一个地址(PEIM的开始地址)。从这里开始只讲EDK的执行+ s; Z; L3 o+ K1 P
  EDK调用InitializeMemoryService函数,将HobList清空,peiservice清空。
3 w/ s4 Q, U: g# p$ g1 ^9 ]) V' S      InitializePPIService函数,将PPI队列清空,这个队列长0x3F.
( s9 h& f" W) s6 v: f2 i$ h, S( }6 N          InitializeSercurityService函数,将Notify队列清空。
7 T  {, H2 A8 U. \          InitializeDispatcherData函数,将Dispatcher队列清空。  t/ O1 C9 a' p: c  Z  r% v# W
  接着由PeiBuildHobGuid来建立一个HOB(S3返回时这时应该有这个HOB,不用建立,直接使用了,这样就会进入另外一个流程,可以这个EDK不能调试S3,不知道怎么走)。然后由(*PeiServices)->InstallPpi()将这个新HOB加入到PPI中。8 Q$ ~2 K5 g: Z7 n( _
    由于在SEC阶段转了以下这几具PPI,所以在执行PEI的Dispatcher之前会先安装东西:
. w! c0 H7 A- V9 g      EFI_PEI_PPI_DESCRIPTOR    gPrivateDispatchTable[] = {
( p5 @: b1 X% ^1 h       {EFI_PEI_PPI_DESCRIPTOR_PPI, &gEfiNtLoadAsDllPpiGuid, &mSecNtLoadAsDllPpi},$ _/ E9 u4 n: ?" H* j1 n
       {EFI_PEI_PPI_DESCRIPTOR_PPI, &gNtPeiLoadFileGuid, &mSecNtLoadFilePpi},
+ f6 ]  C7 r; _* x       {EFI_PEI_PPI_DESCRIPTOR_PPI, &gPeiNtAutoScanPpiGuid, &mSecNtAutoScanPpi},' N9 h& p; f. J$ E6 s% S
       {EFI_PEI_PPI_DESCRIPTOR_PPI, &gPeiNtThunkPpiGuid, &mSecWinNtThunkPpi},, V- e. F1 `3 ~+ [: k
       {EFI_PEI_PPI_DESCRIPTOR_PPI, &gPeiStatusCodePpiGuid, &mSecStatusCodePpi},' l9 k! d+ p( M9 y! F
       {EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST, &gNtFwhPpiGuid, &mSecFwhInformationPpi}1 a- x: \0 V3 c- h2 t9 r  i- Y# j
     };
& T7 S$ B% [6 [    每个PPI是由{类型,GUID(名字,以后就根据这个来找到它的),Function_Entry_Address}组成。5 Y* m8 U4 Z$ q" M
   这些PPI会在PEIDispatcher中用到。
9 m5 [7 Z2 V/ A+ {  y* X7 f! W( b) q   安装完这此东西这开始执行PEIDispatcher函数,函数从BIOS ROM文件中找出PEI的Image(怎么找到,请读一下FV_HEAD(EFI_HEAD),里面讲到了如何区分Image类型),然后定位到PEI Image的入口地址,执行他。在我们的的PEI中,我们一般会申明一个PPI,这个就是这个PEI提供一些服务,PEIDispatcher会将他们加入到PPI-List中,以后其他Image也可以调用他的提供的功能。
) n/ T+ r. {% [/ E: B' w6 ?   最后EDK会加载一个叫DXEIPL的PEI,DXEIPL提供一个PPI服务,这个PPI的功能是实现从PEI到DXE的切换,这个PPI里面为DXE做了很多的预准备,加载了很多PPI,如对BIOS的解压方法等。  B& {6 ?4 f6 F) @0 D  [. y5 \9 P/ E
   SwitchStacks (
4 }+ H4 R2 c/ q       (VOID *) (UINTN) DxeCoreEntryPoint,# J+ h' z* h. i! y
       (UINTN) (HobList.Raw),- Q6 H7 G. g% r" V
       (VOID *) (UINTN) TopOfStack,5 i% W/ V% R7 \
       (VOID *) (UINTN) BspStore
  @6 N. A0 F* ^1 E    );- e" ~; Q: [5 G! Q
  用过汇编的人对这个技术一定很熟悉,不多说了(我别不清,咯。。。)
% z, ?" Q0 h# v0 K$ j+ e) |9 _
& N. @. N# F) {7 Y$ g% {% {) W8 @DXE:. U/ l* \8 C. |
     从PEI到DXE切换时转过来一个HOBLIST参数,DXE会在这个HOB中找到Memory的使用情况,然后根据这些情况将BIOS引到内存(这是EFI的做法)。在EDK在DXE时重新定位一下内存。
% G% B, p* C( h2 u  m接着就会定义我们经常使用到的gST表,gRT表。接着是申明一些Protocol(先不关心这些事)。
6 F" [0 i+ C. i! I   等这些该加的PPI,Protocol加完了,CoreDispatcher()就出场了。他会的功能类似PEIDispatcher()。从我们BIOS ROM中将DXE的驱动读出,执行执行他们,这时会执行到Driver
, u3 ?# l- z- H7 j0 X$ I$ w中的Support(),Start()两个功能函数。在这两个函数中你可以注册自己的PPI,为其他驱动提供服务。
: M; q! X( H  I3 m& l   到些BIOS的引导其他完成。接着该进OS了,看Linux 0.11吧,操作系统是怎么做事情的。
; \( I# ~5 N& \9 ]- E5 s   8 ~; O7 @0 `' a; E: t" ]( J
Driver:
9 ^5 C9 \2 B5 d& w$ q    我们的驱动什么为在PEI和DXE等不同阶段执行呢?
/ p' H% @' \" U1 e4 p  大家请看一下我们的驱动的makefile.(EDK中的*.inf)
, P, d, @! p$ Z8 H  [defines]
+ d# n/ f* k* \9 @+ D3 O  BASE_NAME            = OWEN! \& B+ F* e: y
  FILE_GUID            = 1EDD13C1-62EF-4262-A1AA-0040D0830110
: j* q( i0 P0 D4 B2 a8 T, M  COMPONENT_TYPE       = BS_DRIVER
0 a' J( E8 r, W, h3 o  ^" q. s! V# q
  BASE_NAME告诉编译器最终生成的驱动的名字。0 O2 j, V" J3 F! p6 u5 G
  FILE_GUID就是这个驱动的GUID名字,在BIOS中引用某个驱动就是根据它来调用和识别。
" `" L, R5 L8 o( Q  COMONENT_TYPE会告诉编译器生成驱动的类型,是PEI,DXE,等。0 g) u7 }) j- {% G: Z' E4 g
  在EDK中有一个FWVolume.c实现的功能就是帮我们把这个TYPE转换面相应的扩展名% b. s! q" m: f! z, R
  COMP_TYPE_EXTENSION  mCompTypeExtension[] = {1 g5 X; S5 z/ p" W4 l0 n! ?
  {"bs_driver",  ".dxe" },
# K  ^0 d# U: t) m) G  {"rt_driver",  ".dxe" },
$ C4 [% g& O) @  {"sal_rt_driver", ".dxe"},  J2 s2 F) v9 t' Z) @( E
  {"security_core", ".sec"},8 U0 a& K  X: Q+ }8 @( l
  {"pei_core", ".pei"},& @- V0 ~6 r# K+ @3 }
  {"pic_peim", ".pei"},
3 B- D3 f, P# O  {"pe32_peim", ".pei"},  N6 m% d7 E4 W9 U3 ]/ J! f
  {"relocatable_peim", ".pei"},
7 L' I  G; r3 D6 H. T( N  {"binary", ".ffs"},
3 L& Y  Q; i$ j' h- B" z+ |  {"application", ".app"},7 D9 W# ?0 X( S
  {"file", ".ffs"},* D# E7 M3 M4 j: }4 {
  {"fvimagefile", ".fvi"},
$ M0 V2 J- Z- S; s  Q4 U5 j  {"rawfile", ".raw"},
0 B  r2 ?, A, g: C5 X7 F  {"apriori", ".ffs"},
% X2 a: |5 u' Y" ~6 F; I$ r  w  {"combined_peim_driver", ".pei"},  u  G) A3 d1 I9 o2 U
  { NULL,  NULL }9 [$ {4 }2 ]5 z, V! U$ d  d! _( m. @
};
3 u& E. J1 d, Y+ ~; R/ j$ H( r! o( L1 S4 {! s) ^# z
了解了这些,接下我们可以看驱动篇了。(Go On Study... Forever)" V, ^- n* D; c- p5 H. X6 Q
   9 Y' d9 e; {, X& a; D
           l' G* {" d: e. L: Q
  
发表于 2008-7-27 12:30:15 | 显示全部楼层
不错!% A% ?, |2 N* G- _: s9 w
支持* o6 I' S0 d  J. e3 e+ \) g
继续) f5 B% w% G7 a8 u- C
加油4 i6 S# a) \  D' h; O% T
回复

使用道具 举报

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

回复 1# 的帖子

gPrivateDispatchTable 和COMP_TYPE_EXTENSION  没有搜到啊  是EDK专有的么?
; b+ q7 o, l9 E有看过跟gPrivateDispatchTable 类似的,但是里面的PPI不同。
3 U! u" G) s3 ?! b: ]: i+ @# _还有这个COMP_TYPE_EXTENSION  没有找到过。FWVolume.c这个文件也没有发现。。
回复

使用道具 举报

发表于 2008-7-28 13:24:20 | 显示全部楼层
这东西虽说没有什么技术含量,但是总结一下还是非常好的。
/ E' I9 H0 {. a0 ?! s1 H
/ v( _. F, w' X4 u9 e支持!
回复

使用道具 举报

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

  g" E  z7 t& G" x& y# v7 S3 r小弟还在学习阶段,目前的目标是知道执行的流程。
2 e2 V- M  e5 N这里面有很多细节没有写,能力有限,只能自己知道,不能表达。
2 K6 g0 F1 Q! P8 b/ ~+ J  V/ Q嘿。。。。
! w4 A5 f" _+ f8 q# I+ p, C所有大侠们如果有好东西能给小弟共享一份。
! B. n( }3 q1 L& M, c9 e
  ^/ w1 L' j$ Q- l" O谢谢!
回复

使用道具 举报

发表于 2008-8-12 14:44:11 | 显示全部楼层
原帖由 winbondowen 于 2008-7-27 00:11 发表
) D1 E# u6 m& W* ?. W9 W& B- s  ROM中將DXE的驅動讀出,執行執行他們,這時會執行到Driver
( Y+ T- E* o7 g' f3 l中的Support(),Start()兩個功能函數。在這兩個函數中你可以註冊自己的PPI ...
/ O: m. f8 c2 `$ Z; Q6 B2 r
; G& s% e3 H/ E* l: G
PPIs are registered during PEI phase, but Support()/Start() are invoked in DXE driver binding protocol,   a- B5 ?* U+ A9 \% f# R1 z
For more precisely, I think the "PPI" you mentioned is the "PROTOCOL" rather than "PPI".! _0 ~# g/ n* O0 {" s: {

7 t: }$ _& F/ Z[ 本帖最后由 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:! f, Y$ Z0 h0 e* s. H. H# [( ~
   Yes. I make a mistake.
* ?+ }9 q  k: I) H      PPI:     A PEIM to PEIM interface.
/ X8 U0 m- r% @% u      PROTOCL: A Interface between Hardware(or firmware) and software.1 F3 v/ [( c+ b) c4 g( ^. B
      reference[http://www.biosren.com/viewthread.php?tid=207]
/ [0 N7 @" j3 ]7 N( u2 U   so, PPI execute at PEI step and Initialize hardware. PROTOCOL execute by DXE step.
! S. V6 c' \% d7 l% V) K   Thanks.
回复

使用道具 举报

发表于 2008-8-20 17:47:21 | 显示全部楼层
原帖由 winbondowen 于 2008-7-27 00:11 发表 DXE:, @5 q+ A& R! f& j" ]1 q4 a
     從PEI到DXE切換時轉過來一個HOBLIST參數,DXE會在這個HOB中找到Memory的使用情況,然後根據這些情況將BIOS引到內存(這是EFI的做法)。在EDK在DXE時重新定位一下內存。8 ?$ {' e6 ?2 @( t# s0 Z
接著就會定義我們經常使用到的gST表,gRT表。接著是申明一些Protocol(先不關心這些事)。
! H8 G4 H/ h- ]1 q1 L   等這些該加的PPI,Protocol加完了,CoreDispatcher()就出場了。他會的功能類似PEIDispatcher()。從我們BIOS ROM中將DXE的驅動讀出,執行執行他們,這時會執行到Driver
8 P9 J  R* g4 j# Q" ?1 L0 w5 G, f$ B中的Support(),Start()兩個功能函數。在這兩個函數中你可以註冊自己的PPI,為其他驅動提供服務。
1 v* a( k* |$ @( M. _8 v   到些BIOS的引導其他完成。接著該進OS了,看Linux 0.11吧,操作系統是怎麼做事情的。.
, V9 S! u0 N: g) k+ m; \
: C' G; r3 x) m+ e9 Q
There are mistakes,
( w1 n1 h# o+ Q8 U4 |: n1.gST and gRT are init after the DXE architectural protocols have been loaded, those protocols response for creating Dxe foundation.
- W: Q4 u9 i- m  n. p% O- i/ u. |& @, R4 [: |
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.
0 O. u" b' ^2 N1 J, cThe CoreDispatcher() executes all trusted Dxe drivers and just register the Binding protocol if the driver is EFI1.1 driver model.
3 ?& i. d7 ^/ S& rFurthermore, Support()/Start() are invoked in BDS phase over the CoreConnectController() rather than CoreDispatcher().
2 P" a1 [# G8 g, A$ l: ]3 w9 d$ E6 e2 \8 m
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 大侠的指点。
6 b' I' ~4 F3 g* M# A
回复

使用道具 举报

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

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

原帖由 ichirohiro 于 2008-8-20 17:47 发表 + w/ s+ o6 Q& Q& ^  n
...2 {5 {9 W+ }, E2 l& 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.
4 V% c8 N1 ?) K. H8 B3 HThe CoreDispatcher() executes all trusted Dxe drivers and just register the Binding protocol if the driver is EFI1.1 driver model.2 [5 s) A" D" [
Furthermore, Support()/Start() are invoked in BDS phase over the CoreConnectController() rather than CoreDispatcher().
& ]5 D) P8 N' u' w5 k
    在Framework的spec DxeCis.pdf里面也是这么说的,DXE CoreDispatcher()里面,对于EFI1.1 driver model的driver只会安装Handler和Interface到Binding protocol,到BDS才会去执行Support()和Start().- S4 l+ |( N6 d' I
    但是,我在看code时,发现在CoreDispatcher()-->CoreStartImage()里面call image之后有这么一句:  (file:image.c)
' q9 n# G7 [2 C# i: n6 B  //
: d% |; z& }  B* h" G  // Go connect any handles that were created or modified while the image executed.
" x/ l* Z1 S; Q0 j3 O  //
$ j# f; V1 d6 Z9 W  CoreConnectHandlesByKey (HandleDatabaseKey);

- o7 u0 p0 B7 O3 M* a3 V这里的HandleDatabaseKey是call image之前由CoreGetHandleDatabaseKey()得到的gHandleDatabaseKey
) P5 ~4 G: P- \) p# n% Q9 j; ^; R- k而CoreConnectHandlesByKey会调用到:
/ h% e8 {, M7 c' l$ D( r  //6 j- u3 L) s7 _& X
  // Connect all handles whose Key value is greater than Key
/ D6 e1 b  ]7 \3 }5 m# M; L  //3 q, B+ c/ t* v7 W+ g; N. g' t
  for (Index = 0; Index < Count; Index++) {
4 A9 e' X! E& F; s    CoreConnectController (HandleBuffer[Index], NULL, NULL, TRUE);% c; k- @$ K  V2 h( J, n
  }

; [5 {' D0 f# \; A所以,照code看,当在Driver中安装一个Handle和Interface到Binding Protocol后(gHandleDatabaseKey会++,IHandle的Key=gHandleDatabaseKey)
5 x) F! _/ Q* p- E1 h是会去ConnectController的,也会执行对应的Support()和Start()才对!!8 G' B( y8 {3 A' }* _2 ^$ u# m
  E+ `* y: M! Z/ x
不知道我想的哪里有问题???欢迎大家指正." P% Y6 z' _* S8 F6 r
& E' L- j/ y9 f( g) r% D- W' g
[ 本帖最后由 xtdumpling 于 2008-9-18 15:25 编辑 ]
回复

使用道具 举报

发表于 2008-9-19 14:44:41 | 显示全部楼层
这段code似乎是一个向后兼容的行为,不必太care。, Y4 |$ v% N: t# m' x# u6 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 | 显示全部楼层
了解了.7 ?- L9 {7 f" r' [
非常 感谢!!!
回复

使用道具 举报

发表于 2008-9-23 16:48:56 | 显示全部楼层
在读DXEmain时,5 H3 h7 j1 g8 j8 F/ ?
Status = CoreInitializeImageServices(HobStart);--->CoreInstallProtocolInterface();--->CoreInstallProtocolInterfaceNotify();中,4 b( }; e# d+ A' B$ Z5 X. {
//
8 T# x, y! C6 c% H( f: K// Notify the notification list for this protocol.
8 G& i. L' |  W0 A9 i% s/ g//
) P' F( D* \, ^) E( h3 sif (Notify) {( V; ~8 k: H# l$ J9 i, y3 E: X3 U
  CoreNotifyProtocolEntry(ProtEntry);
( _+ `+ A+ q6 ]}    里Signal了Event. MS是说一个handle安装了一个protocol后就signal一次.
. q7 ~/ w' e' m' W3 h) ~; T$ [有个问题请教一下大家: 这段是在DXE很靠前的位置执行的,但是在它之前我没有看到DXE中有相关的CreateEvent出现?哪位高手能说说这部分代码的流程呢?
回复

使用道具 举报

发表于 2008-9-23 17:04:14 | 显示全部楼层
原帖由 xtdumpling 于 2008-9-16 13:34 发表
4 N5 o7 t) c+ _: ]' M请楼上的兄弟分析下BS的RegisterProtocolNotify也就是CoreRegisterProtocolNotify是做什么用的?怎么用?
. w- U6 T9 U% X/ s谢谢!
  {% M0 G5 k5 \& L
......
! k8 W2 T5 Y2 y0 K, e
7 ^# P% J. O$ Y# t5 ?/ j$ X1 p, d- p9 A  B
[ 本帖最后由 xtdumpling 于 2008-9-23 17:24 编辑 ]
回复

使用道具 举报

发表于 2008-9-24 12:43:45 | 显示全部楼层
原帖由 xtdumpling 于 2008-9-23 17:04 发表 ' Z) f0 d( c+ J$ Z; y8 M% w

5 }; Q& \' z# m: s; `" {......5 j( U+ R2 o0 q3 I5 g
, O/ G+ H# z  q1 a
Signal的Event是不是在各个TPL级上挂载一些待处理的事件,一旦restore(TPL)的话,比当前TPL级高的pending事件就回被处理掉?( ?4 u# K) @& J, G* H. ~
如果是这样的话,Timer事件是如何处理的呢,没有找到相关的代码呀?Xt指点一下再~
回复

使用道具 举报

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

使用道具 举报

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

本版积分规则

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

GMT+8, 2026-8-11 16:57 , Processed in 0.053983 second(s), 17 queries .

Powered by Discuz! X3.5

© 2001-2025 Discuz! Team.

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