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

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

[复制链接]
发表于 2008-7-27 00:11:28 | 显示全部楼层 |阅读模式
  最近在工作看到机台有启动过程中把SPI ROM数据清空,但苦与没有办法很好的Debug(PCA没有架起来),所有与EDK为对象好好的读了一把。
1 ?: a/ e  m" D# g' O. s
" B0 P" N8 s& HSEC/CEI:" |, v5 ~  |7 v3 x5 O1 e
  UEFI BIOS启动时先会执行SEC/CEI,这个阶段在实现的BIOS Code中初始化Debug Port,进入Big Mode,CPU的MicroCode,CacheToRAM的转换.然后跳转到PEI阶段。6 h, V! F7 b! z4 h* v% g! E3 v7 T
在EDK中这部分被成了Load FvRecovery.fd文件,这个文件类似与我们的BIOS ROM.里面是我们编译后生成的二进制代码。在这个阶段最主要的是将这个文件加载到内存中(Windows API将文件加载到内存,看API函数).0 }- U8 E0 M0 }: X1 I. Q1 k/ M( b, E
2 V! l' q- t# g3 H, ^# \
PEI:; P' K* E/ I, _! x# k
   从这里开始UEFI BIOS和EDK执行基本相同,只是一个是从SPI ROM中定位一个地址(PEIM的开始地址),一个是从内存中定位一个地址(PEIM的开始地址)。从这里开始只讲EDK的执行! `. J* _" U( [  q& Q# Z3 |" |6 Y- Q
  EDK调用InitializeMemoryService函数,将HobList清空,peiservice清空。
2 S; q% X  _( e. ^/ \  c      InitializePPIService函数,将PPI队列清空,这个队列长0x3F., u: a/ t; [* m9 G8 r  Z
          InitializeSercurityService函数,将Notify队列清空。
' U( @5 K/ x* A. n( y          InitializeDispatcherData函数,将Dispatcher队列清空。! g+ Q8 B1 @/ x6 @5 d
  接着由PeiBuildHobGuid来建立一个HOB(S3返回时这时应该有这个HOB,不用建立,直接使用了,这样就会进入另外一个流程,可以这个EDK不能调试S3,不知道怎么走)。然后由(*PeiServices)->InstallPpi()将这个新HOB加入到PPI中。1 X4 v' v5 d3 i$ v8 \: v: _
    由于在SEC阶段转了以下这几具PPI,所以在执行PEI的Dispatcher之前会先安装东西:
. A1 i2 P. ~3 q8 Z* Y4 d      EFI_PEI_PPI_DESCRIPTOR    gPrivateDispatchTable[] = {+ u1 _9 y, V5 P+ E$ F
       {EFI_PEI_PPI_DESCRIPTOR_PPI, &gEfiNtLoadAsDllPpiGuid, &mSecNtLoadAsDllPpi},$ W! F" V2 y. ~
       {EFI_PEI_PPI_DESCRIPTOR_PPI, &gNtPeiLoadFileGuid, &mSecNtLoadFilePpi},% Q5 E6 z+ l9 b. l4 t2 m* C. j* F0 r1 _
       {EFI_PEI_PPI_DESCRIPTOR_PPI, &gPeiNtAutoScanPpiGuid, &mSecNtAutoScanPpi},
# Q$ ~* |: j( J5 W8 X! a$ L2 p4 h. d       {EFI_PEI_PPI_DESCRIPTOR_PPI, &gPeiNtThunkPpiGuid, &mSecWinNtThunkPpi},. @' O# [* U+ |6 }9 e* |2 M& R( Q2 }
       {EFI_PEI_PPI_DESCRIPTOR_PPI, &gPeiStatusCodePpiGuid, &mSecStatusCodePpi},6 m' U' N  i9 U' S# ~1 j+ a
       {EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST, &gNtFwhPpiGuid, &mSecFwhInformationPpi}7 E$ ~  X' w: H- z
     };5 z! ~+ r7 Z! Q$ G
    每个PPI是由{类型,GUID(名字,以后就根据这个来找到它的),Function_Entry_Address}组成。  Y9 \; J/ C* r3 j9 h
   这些PPI会在PEIDispatcher中用到。
2 T( Z3 C2 B" T" j* |5 V4 M   安装完这此东西这开始执行PEIDispatcher函数,函数从BIOS ROM文件中找出PEI的Image(怎么找到,请读一下FV_HEAD(EFI_HEAD),里面讲到了如何区分Image类型),然后定位到PEI Image的入口地址,执行他。在我们的的PEI中,我们一般会申明一个PPI,这个就是这个PEI提供一些服务,PEIDispatcher会将他们加入到PPI-List中,以后其他Image也可以调用他的提供的功能。
3 y9 f& S4 b3 m# o! U  v# u   最后EDK会加载一个叫DXEIPL的PEI,DXEIPL提供一个PPI服务,这个PPI的功能是实现从PEI到DXE的切换,这个PPI里面为DXE做了很多的预准备,加载了很多PPI,如对BIOS的解压方法等。9 d" I7 G- e7 P, y( i, a6 ?
   SwitchStacks (( K4 k0 y$ V% F7 i8 x7 t
       (VOID *) (UINTN) DxeCoreEntryPoint,, Z/ b* h1 A$ |# i) M2 L; J
       (UINTN) (HobList.Raw),
. o- e# t8 `( v9 _- }       (VOID *) (UINTN) TopOfStack,
5 L( @1 r5 w* H( Q       (VOID *) (UINTN) BspStore. R: O, y8 o9 k: A
    );* j! ^6 i' b3 T. [) r/ T# K- ?
  用过汇编的人对这个技术一定很熟悉,不多说了(我别不清,咯。。。). Z- c% j( P$ T! P3 w+ f) b' U$ O

3 K- V9 C6 E4 O6 w* n9 W% Y, E$ `DXE:
: o8 ?; C& w: y5 x# F     从PEI到DXE切换时转过来一个HOBLIST参数,DXE会在这个HOB中找到Memory的使用情况,然后根据这些情况将BIOS引到内存(这是EFI的做法)。在EDK在DXE时重新定位一下内存。
$ e; X( L% Y# `9 ?3 M/ Z& x6 M接着就会定义我们经常使用到的gST表,gRT表。接着是申明一些Protocol(先不关心这些事)。
* H- d) J& A5 T   等这些该加的PPI,Protocol加完了,CoreDispatcher()就出场了。他会的功能类似PEIDispatcher()。从我们BIOS ROM中将DXE的驱动读出,执行执行他们,这时会执行到Driver5 E- s/ L  K0 j8 r
中的Support(),Start()两个功能函数。在这两个函数中你可以注册自己的PPI,为其他驱动提供服务。
2 |2 H8 r3 C$ ?   到些BIOS的引导其他完成。接着该进OS了,看Linux 0.11吧,操作系统是怎么做事情的。# r$ E* S0 N5 R3 {6 K. Q
   - H' f! N- l% z" j" }, W; s2 t! Y' I. {: s
Driver:  v; z; g$ b. O/ t
    我们的驱动什么为在PEI和DXE等不同阶段执行呢?) {# d1 [, u# q& g) P& Q* w
  大家请看一下我们的驱动的makefile.(EDK中的*.inf)# {4 {& s- B3 F9 {) P, H6 {
  [defines]
% {9 E; l( z4 m5 [" Q4 L  BASE_NAME            = OWEN
! U! c2 p& t/ B" ]- N& x  FILE_GUID            = 1EDD13C1-62EF-4262-A1AA-0040D0830110
( B( K" P% o/ I3 H$ l  COMPONENT_TYPE       = BS_DRIVER9 X- G$ W. }3 B; i% U1 ]

5 h! f) R" ]) j+ C7 H  BASE_NAME告诉编译器最终生成的驱动的名字。
+ A& M7 _7 n7 ^+ A, z2 |- C  FILE_GUID就是这个驱动的GUID名字,在BIOS中引用某个驱动就是根据它来调用和识别。" n$ S, ^  n8 |7 _0 ^. _+ A
  COMONENT_TYPE会告诉编译器生成驱动的类型,是PEI,DXE,等。
2 V' q8 v: O% Z  在EDK中有一个FWVolume.c实现的功能就是帮我们把这个TYPE转换面相应的扩展名6 y8 Z3 c. t' r3 Y
  COMP_TYPE_EXTENSION  mCompTypeExtension[] = {
6 a$ Y3 f( _5 @0 D+ l( {  {"bs_driver",  ".dxe" },
* `; S0 O; F4 N  {"rt_driver",  ".dxe" },
" D) H! v. a. e2 `1 e# d! w  {"sal_rt_driver", ".dxe"},. A: s3 `+ a2 Z8 q* n/ ]
  {"security_core", ".sec"},9 G- F& C+ _0 Z# U# P* h( q
  {"pei_core", ".pei"},4 G( E# S, @; X0 j3 \. ^
  {"pic_peim", ".pei"},
. R1 w6 s1 \2 Q+ L& @8 m3 F& n  {"pe32_peim", ".pei"},
5 v. Z: f0 m! ]1 L& \0 c  {"relocatable_peim", ".pei"},
; d% ~# L$ @$ D. A1 d) g% G: r  {"binary", ".ffs"},$ e  X5 V2 m' ?1 J7 S7 P6 e" g+ L
  {"application", ".app"},% h5 k9 Z) I0 z0 H* y/ h7 T
  {"file", ".ffs"},. j6 ~+ S6 A) `+ f
  {"fvimagefile", ".fvi"},
2 u- N. `, w$ H' A  {"rawfile", ".raw"},
! x7 S* Q% S9 k6 M( ?3 _  {"apriori", ".ffs"},
8 I' l! R6 B" E: X' Y  {"combined_peim_driver", ".pei"},4 u8 W) ?. q( _1 C5 n: U' V
  { NULL,  NULL }2 J! ~1 g* ?6 a7 o5 F
};
( s; z* [9 b* ~4 {" `
/ @( Y/ N4 k, W2 o2 ]6 d& Q, F4 w! _了解了这些,接下我们可以看驱动篇了。(Go On Study... Forever)
; [2 x6 d9 k8 O* u0 P) Q/ d   8 y# w6 m$ M+ v" H3 z
         
2 o2 i! Z* S: `! K! d6 F4 ~7 _  
发表于 2008-7-27 12:30:15 | 显示全部楼层
不错!0 N0 R# Y! R. ^. S( a/ z: h8 C) P
支持& ~% L* E9 j- s+ V* e
继续6 o6 d; e1 w+ B! A( C4 w, m
加油
$ q) Q. P- f0 i* V$ {) G0 s8 K  r
回复

使用道具 举报

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

回复 1# 的帖子

gPrivateDispatchTable 和COMP_TYPE_EXTENSION  没有搜到啊  是EDK专有的么?
1 `5 H  p0 E8 z" I8 B" B. K有看过跟gPrivateDispatchTable 类似的,但是里面的PPI不同。
' N0 g( A. T8 s4 D7 j4 C还有这个COMP_TYPE_EXTENSION  没有找到过。FWVolume.c这个文件也没有发现。。
回复

使用道具 举报

发表于 2008-7-28 13:24:20 | 显示全部楼层
这东西虽说没有什么技术含量,但是总结一下还是非常好的。8 r' M& p' ]2 N  _$ n

+ |$ ^: V' \$ a; Z3 Y支持!
回复

使用道具 举报

 楼主| 发表于 2008-7-28 18:52:31 | 显示全部楼层
& ]0 q" u* f3 t+ r
小弟还在学习阶段,目前的目标是知道执行的流程。
! h% V4 ?+ W+ T7 _. A! Z这里面有很多细节没有写,能力有限,只能自己知道,不能表达。
+ Q+ k$ @+ l6 t嘿。。。。
  q, E( J% g8 u6 X. {4 V7 L所有大侠们如果有好东西能给小弟共享一份。
! a% B/ f  U, I, \0 E% i
0 k1 K" j- S$ m1 K" R& h5 h谢谢!
回复

使用道具 举报

发表于 2008-8-12 14:44:11 | 显示全部楼层
原帖由 winbondowen 于 2008-7-27 00:11 发表
5 |4 G% t. V1 V  O" j$ B6 e% |' U  ROM中將DXE的驅動讀出,執行執行他們,這時會執行到Driver
. @* T$ Z( X, W$ O! k  v( u中的Support(),Start()兩個功能函數。在這兩個函數中你可以註冊自己的PPI ...
* R, m$ L. @2 f
5 B( H  n7 ?0 E) x- S
PPIs are registered during PEI phase, but Support()/Start() are invoked in DXE driver binding protocol, ; p' q& k/ M/ x, G: ]3 s! R
For more precisely, I think the "PPI" you mentioned is the "PROTOCOL" rather than "PPI".5 T; ?$ _9 H. B+ H: A2 U' w& _
1 l9 b3 h# `6 Z! A0 E( 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:2 K5 A$ S5 B5 D9 _2 Q; o# x* ?. g4 R
   Yes. I make a mistake.1 g# Q+ W) E. a; @% f  [. [  Y+ I
      PPI:     A PEIM to PEIM interface.
1 [- \9 J  C6 S/ u) P6 j      PROTOCL: A Interface between Hardware(or firmware) and software.8 f" d3 E& y/ k
      reference[http://www.biosren.com/viewthread.php?tid=207]
; G, s6 i  B* H4 T   so, PPI execute at PEI step and Initialize hardware. PROTOCOL execute by DXE step.  M( `' q( z/ N4 S4 a' C# f
   Thanks.
回复

使用道具 举报

发表于 2008-8-20 17:47:21 | 显示全部楼层
原帖由 winbondowen 于 2008-7-27 00:11 发表 DXE:
1 F" R+ D$ r/ v; ^# G     從PEI到DXE切換時轉過來一個HOBLIST參數,DXE會在這個HOB中找到Memory的使用情況,然後根據這些情況將BIOS引到內存(這是EFI的做法)。在EDK在DXE時重新定位一下內存。
  \0 m% \* `) U+ c3 |接著就會定義我們經常使用到的gST表,gRT表。接著是申明一些Protocol(先不關心這些事)。9 \# F6 o. V0 [& N' l4 G/ D
   等這些該加的PPI,Protocol加完了,CoreDispatcher()就出場了。他會的功能類似PEIDispatcher()。從我們BIOS ROM中將DXE的驅動讀出,執行執行他們,這時會執行到Driver
2 W" Y" l" J8 [/ k0 y5 Z- K中的Support(),Start()兩個功能函數。在這兩個函數中你可以註冊自己的PPI,為其他驅動提供服務。
2 v, w, ~2 l) Q7 j/ \0 W   到些BIOS的引導其他完成。接著該進OS了,看Linux 0.11吧,操作系統是怎麼做事情的。.

6 M9 ^& X$ Q6 @/ T' }* E* L  L% R' t8 E3 [- |" }/ N; z" x* X: n
There are mistakes,
; u$ n4 ^. w8 v3 v( t1.gST and gRT are init after the DXE architectural protocols have been loaded, those protocols response for creating Dxe foundation.9 }( \. b2 x) W9 ~0 s9 i

; `& |- s2 v2 E; ?0 y5 c. G2.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 O2 ~- g( Q9 [  n4 r2 IThe CoreDispatcher() executes all trusted Dxe drivers and just register the Binding protocol if the driver is EFI1.1 driver model.
6 T+ S5 q! l, D1 CFurthermore, Support()/Start() are invoked in BDS phase over the CoreConnectController() rather than CoreDispatcher().
( d2 s) ?% [5 j) B+ B& [
6 U+ V% @) k5 q: d! Y! HBTW, 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 大侠的指点。
9 c( m  s6 g& l4 @- d7 `7 z! D
回复

使用道具 举报

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

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

原帖由 ichirohiro 于 2008-8-20 17:47 发表 1 W. o$ h, S# m) Z$ ~
...( p: m( [+ V2 {, R
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.
& A0 f9 i! ?  a: I+ ~The CoreDispatcher() executes all trusted Dxe drivers and just register the Binding protocol if the driver is EFI1.1 driver model.
! ?* i& B9 G6 wFurthermore, Support()/Start() are invoked in BDS phase over the CoreConnectController() rather than CoreDispatcher().
+ |& I' R/ J, R' c& Z
    在Framework的spec DxeCis.pdf里面也是这么说的,DXE CoreDispatcher()里面,对于EFI1.1 driver model的driver只会安装Handler和Interface到Binding protocol,到BDS才会去执行Support()和Start().8 @9 p& P- Y# _7 C, Z; H/ s8 Q
    但是,我在看code时,发现在CoreDispatcher()-->CoreStartImage()里面call image之后有这么一句:  (file:image.c)
  j8 A" e  B! m" B0 O  //
" |6 D3 q7 T: C; ?  // Go connect any handles that were created or modified while the image executed.3 N( B( `0 A. W' Q7 I( u$ T2 g
  //
9 v( ?) d& G' K  t0 Z( x/ T  CoreConnectHandlesByKey (HandleDatabaseKey);
' q4 B$ y) ~3 @0 }2 b: ~; U% K
这里的HandleDatabaseKey是call image之前由CoreGetHandleDatabaseKey()得到的gHandleDatabaseKey
1 v6 \* c0 ^/ j* Y而CoreConnectHandlesByKey会调用到:1 E! h4 [! q- J, Q
  //
( f, i  `0 E; S7 `  }8 c  // Connect all handles whose Key value is greater than Key
+ R, q2 N. Y) W) c' J) ?  //
* u- [: c% o: [# G" x  for (Index = 0; Index < Count; Index++) {7 _3 u5 o5 N/ f! c1 a9 d) Y! I
    CoreConnectController (HandleBuffer[Index], NULL, NULL, TRUE);8 a- f5 V5 z/ c
  }
/ c/ G1 m9 L# l
所以,照code看,当在Driver中安装一个Handle和Interface到Binding Protocol后(gHandleDatabaseKey会++,IHandle的Key=gHandleDatabaseKey)8 _# Z- J' m2 w' ^
是会去ConnectController的,也会执行对应的Support()和Start()才对!!- O/ V# U  N3 F  m- t. C! N1 M
0 Z3 O/ e2 o9 p+ h5 h
不知道我想的哪里有问题???欢迎大家指正.  O# b! G3 O/ F. m, F% [6 v4 Z8 Z, W/ V( Y
% \! a$ `" q3 e3 y3 \
[ 本帖最后由 xtdumpling 于 2008-9-18 15:25 编辑 ]
回复

使用道具 举报

发表于 2008-9-19 14:44:41 | 显示全部楼层
这段code似乎是一个向后兼容的行为,不必太care。
( k& V  z( O4 r一个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 | 显示全部楼层
了解了.8 u7 p! Q$ f/ g/ s. h, X- V
非常 感谢!!!
回复

使用道具 举报

发表于 2008-9-23 16:48:56 | 显示全部楼层
在读DXEmain时,0 @2 C0 A0 i% ]) A! t
Status = CoreInitializeImageServices(HobStart);--->CoreInstallProtocolInterface();--->CoreInstallProtocolInterfaceNotify();中,
' L- q2 B" l5 J  G: }3 Z0 g/ F9 R//" I+ W) ~: j+ J* d) X3 ~
// Notify the notification list for this protocol.! M: B) o6 T8 t; _- v/ h4 ^
//: A, o9 \1 m) E4 ~! ?
if (Notify) {" w  E* l6 a8 X% Q( \6 V
  CoreNotifyProtocolEntry(ProtEntry);
$ m) F/ e/ N' U, C}    里Signal了Event. MS是说一个handle安装了一个protocol后就signal一次.& ^9 k" Z" l! l9 w: Z+ d  w- b
有个问题请教一下大家: 这段是在DXE很靠前的位置执行的,但是在它之前我没有看到DXE中有相关的CreateEvent出现?哪位高手能说说这部分代码的流程呢?
回复

使用道具 举报

发表于 2008-9-23 17:04:14 | 显示全部楼层
原帖由 xtdumpling 于 2008-9-16 13:34 发表 ( ?; Y- v7 I' n* j8 d; R
请楼上的兄弟分析下BS的RegisterProtocolNotify也就是CoreRegisterProtocolNotify是做什么用的?怎么用?
" K6 T; Y3 i3 Q3 H谢谢!

* x* I" ?! }: m, l2 b- f# Q# o6 P......5 i" I( U' S. P  S7 q* P- F4 f0 `
' e% C8 g% W* ?) x  t  [5 ?
% {. T& K" Q& o: f; U
[ 本帖最后由 xtdumpling 于 2008-9-23 17:24 编辑 ]
回复

使用道具 举报

发表于 2008-9-24 12:43:45 | 显示全部楼层
原帖由 xtdumpling 于 2008-9-23 17:04 发表
( f/ Y' P8 v/ q' S
* j  ]  E5 V& j7 H, }8 t. @* w......
  D# ^: }) k4 U

- T. X; J" a9 [7 J* m  FSignal的Event是不是在各个TPL级上挂载一些待处理的事件,一旦restore(TPL)的话,比当前TPL级高的pending事件就回被处理掉?
% v! L3 F% m8 q( T. W* F9 J! `+ ]如果是这样的话,Timer事件是如何处理的呢,没有找到相关的代码呀?Xt指点一下再~
回复

使用道具 举报

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

使用道具 举报

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

本版积分规则

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

GMT+8, 2026-10-12 09:49 , Processed in 0.058629 second(s), 16 queries .

Powered by Discuz! X3.5

© 2001-2025 Discuz! Team.

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