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

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

[复制链接]
发表于 2008-7-27 00:11:28 | 显示全部楼层 |阅读模式
  最近在工作看到机台有启动过程中把SPI ROM数据清空,但苦与没有办法很好的Debug(PCA没有架起来),所有与EDK为对象好好的读了一把。
6 f  l5 Y# u% E4 S& G4 \" G$ ~( n8 C+ F8 e* P  x9 q8 C
SEC/CEI:# O: R' L* e. n6 @4 l
  UEFI BIOS启动时先会执行SEC/CEI,这个阶段在实现的BIOS Code中初始化Debug Port,进入Big Mode,CPU的MicroCode,CacheToRAM的转换.然后跳转到PEI阶段。
2 Z, t7 d3 i8 I  J3 F在EDK中这部分被成了Load FvRecovery.fd文件,这个文件类似与我们的BIOS ROM.里面是我们编译后生成的二进制代码。在这个阶段最主要的是将这个文件加载到内存中(Windows API将文件加载到内存,看API函数).  \: I  p+ ?; i

3 I$ K1 z7 H& O6 Z, k2 dPEI:
8 J/ u& X2 n; X# x; x   从这里开始UEFI BIOS和EDK执行基本相同,只是一个是从SPI ROM中定位一个地址(PEIM的开始地址),一个是从内存中定位一个地址(PEIM的开始地址)。从这里开始只讲EDK的执行
6 `; p/ b9 Y; ?$ Z& A- z  EDK调用InitializeMemoryService函数,将HobList清空,peiservice清空。& a: O+ `# N1 k  X& F. q
      InitializePPIService函数,将PPI队列清空,这个队列长0x3F.
9 o2 m/ a. d% p+ C/ F9 Y4 H          InitializeSercurityService函数,将Notify队列清空。
+ r8 z. ~" }( D. }  _          InitializeDispatcherData函数,将Dispatcher队列清空。" G. ~, M1 O# l' E/ E: J5 q/ B
  接着由PeiBuildHobGuid来建立一个HOB(S3返回时这时应该有这个HOB,不用建立,直接使用了,这样就会进入另外一个流程,可以这个EDK不能调试S3,不知道怎么走)。然后由(*PeiServices)->InstallPpi()将这个新HOB加入到PPI中。
: c# d" Q7 V' i8 F$ c" |% N2 x. P    由于在SEC阶段转了以下这几具PPI,所以在执行PEI的Dispatcher之前会先安装东西:  d3 m  |9 h# J9 r$ v0 \4 e+ k
      EFI_PEI_PPI_DESCRIPTOR    gPrivateDispatchTable[] = {7 j1 h, _) R4 ]) _- l3 t" j
       {EFI_PEI_PPI_DESCRIPTOR_PPI, &gEfiNtLoadAsDllPpiGuid, &mSecNtLoadAsDllPpi},% c2 L* o6 `* f0 G  F4 i! D* D# f8 ?2 N
       {EFI_PEI_PPI_DESCRIPTOR_PPI, &gNtPeiLoadFileGuid, &mSecNtLoadFilePpi},0 S5 n2 b5 {; x
       {EFI_PEI_PPI_DESCRIPTOR_PPI, &gPeiNtAutoScanPpiGuid, &mSecNtAutoScanPpi},
( P3 g5 _; T2 {" H+ R" R       {EFI_PEI_PPI_DESCRIPTOR_PPI, &gPeiNtThunkPpiGuid, &mSecWinNtThunkPpi},3 M+ n5 G+ W( z1 D
       {EFI_PEI_PPI_DESCRIPTOR_PPI, &gPeiStatusCodePpiGuid, &mSecStatusCodePpi},
2 Z2 P+ w& |+ o% @0 C/ k       {EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST, &gNtFwhPpiGuid, &mSecFwhInformationPpi}
0 D8 Y& u3 F1 h( e! V; Q* Y     };' u! a; r5 S. z
    每个PPI是由{类型,GUID(名字,以后就根据这个来找到它的),Function_Entry_Address}组成。) B" s) q% I' j: z
   这些PPI会在PEIDispatcher中用到。0 ?, p1 E$ H4 D1 O" ?+ J9 A& r
   安装完这此东西这开始执行PEIDispatcher函数,函数从BIOS ROM文件中找出PEI的Image(怎么找到,请读一下FV_HEAD(EFI_HEAD),里面讲到了如何区分Image类型),然后定位到PEI Image的入口地址,执行他。在我们的的PEI中,我们一般会申明一个PPI,这个就是这个PEI提供一些服务,PEIDispatcher会将他们加入到PPI-List中,以后其他Image也可以调用他的提供的功能。$ T" m0 n  D/ J0 F1 C2 z
   最后EDK会加载一个叫DXEIPL的PEI,DXEIPL提供一个PPI服务,这个PPI的功能是实现从PEI到DXE的切换,这个PPI里面为DXE做了很多的预准备,加载了很多PPI,如对BIOS的解压方法等。
& M% A/ D* V* A7 J4 n. a" Z: m' M$ l   SwitchStacks (
3 u$ L5 s8 d- Z  U+ @$ d       (VOID *) (UINTN) DxeCoreEntryPoint,
3 j" D+ n' F, S! t9 U4 R       (UINTN) (HobList.Raw),0 B9 M7 S; _6 a5 ^
       (VOID *) (UINTN) TopOfStack,
/ k- d# i$ \! f! }       (VOID *) (UINTN) BspStore, e/ M: i/ l9 u" V
    );& e5 C% \: a' H' L) ~) C
  用过汇编的人对这个技术一定很熟悉,不多说了(我别不清,咯。。。)
. {$ t( L, V' r6 l; D1 @, L$ g4 X% N$ e6 Z8 {9 g! P3 |
DXE:* M1 h6 f: n! ]% z. z3 V
     从PEI到DXE切换时转过来一个HOBLIST参数,DXE会在这个HOB中找到Memory的使用情况,然后根据这些情况将BIOS引到内存(这是EFI的做法)。在EDK在DXE时重新定位一下内存。
/ `& d2 Q* Z2 m$ ^. S  r+ |接着就会定义我们经常使用到的gST表,gRT表。接着是申明一些Protocol(先不关心这些事)。) f% v9 ?, T& \) B
   等这些该加的PPI,Protocol加完了,CoreDispatcher()就出场了。他会的功能类似PEIDispatcher()。从我们BIOS ROM中将DXE的驱动读出,执行执行他们,这时会执行到Driver  s# J2 |% g4 t3 Z% L4 }! c
中的Support(),Start()两个功能函数。在这两个函数中你可以注册自己的PPI,为其他驱动提供服务。
6 P% x) \/ a: V5 \   到些BIOS的引导其他完成。接着该进OS了,看Linux 0.11吧,操作系统是怎么做事情的。
2 Q: y4 F5 }& V/ }# I$ ?( o   / {& Q0 c' S9 [+ t5 M
Driver:
# {% E0 q# m. f: B! P5 y    我们的驱动什么为在PEI和DXE等不同阶段执行呢?+ o9 y( v6 a6 S8 ?6 y! m
  大家请看一下我们的驱动的makefile.(EDK中的*.inf)* Y+ g. m  I: i; H8 O/ F; g$ b5 k
  [defines]* y. b" Y  J: |& G- j; {  C9 \: ~& g
  BASE_NAME            = OWEN3 r; L" z0 x8 w& \$ ?: P; S" q
  FILE_GUID            = 1EDD13C1-62EF-4262-A1AA-0040D0830110
" A$ K9 c0 b6 s5 U9 u( t2 H  COMPONENT_TYPE       = BS_DRIVER) u6 @8 s) K  q8 T
. X, X1 s' ~# l# o" h) C7 X
  BASE_NAME告诉编译器最终生成的驱动的名字。/ z3 W0 e4 \2 N& r* }
  FILE_GUID就是这个驱动的GUID名字,在BIOS中引用某个驱动就是根据它来调用和识别。
7 A' y, w) g) X1 T  COMONENT_TYPE会告诉编译器生成驱动的类型,是PEI,DXE,等。
  ]- L+ j2 d) ]# o3 Z) Y) P  在EDK中有一个FWVolume.c实现的功能就是帮我们把这个TYPE转换面相应的扩展名
1 A" ^! f+ h! e! q5 B3 w  COMP_TYPE_EXTENSION  mCompTypeExtension[] = {; {" q5 x! V! g
  {"bs_driver",  ".dxe" },) P3 e( c) `( A  Q
  {"rt_driver",  ".dxe" },! o3 C. R, Y7 b% n% N5 V: ~" ]
  {"sal_rt_driver", ".dxe"},
3 {9 S- P" D2 w/ ]' ^1 m9 @  {"security_core", ".sec"},  L: e" E$ E. m8 X4 @
  {"pei_core", ".pei"},
7 ~9 v. y+ K' _: ]* f" m: t! ]! G7 c7 @  {"pic_peim", ".pei"},' ^4 e* p9 p; s2 t
  {"pe32_peim", ".pei"},; l2 v/ Y3 N5 }7 t' |5 `" P$ h: \( T- Z
  {"relocatable_peim", ".pei"},
! T6 o, X) m8 A) C7 D$ e  {"binary", ".ffs"},
$ k8 y5 Q/ W% ~5 @! }6 r- y  {"application", ".app"},; i4 b" o9 L( {, X6 B1 t" L
  {"file", ".ffs"}," N" F$ q  q' I; D/ U1 T
  {"fvimagefile", ".fvi"},
! k6 Y( H! I' t" g4 X  {"rawfile", ".raw"},
9 N! \; ?( B: d) K" U6 Z" w  {"apriori", ".ffs"},
" _9 q7 _4 O& J4 ]9 k  {"combined_peim_driver", ".pei"},! x( d! Z/ X& B5 T! [0 E
  { NULL,  NULL }- b' y1 C9 k2 \' x, S6 Y
};- t; l8 K# ?. k; d. B! I
( `2 J0 [! B! T$ M
了解了这些,接下我们可以看驱动篇了。(Go On Study... Forever)8 p, B3 b' O' k: z- I  ^
   ; r. x- V/ X! ?8 u% X
         
9 r$ e  \; A0 K7 c9 R. E( ~  _  
发表于 2008-7-27 12:30:15 | 显示全部楼层
不错!
8 z7 ?5 [! \' ?支持
/ q. O8 c5 @1 b9 A9 ]继续9 P, y  r  D7 K( H% E3 h1 Z1 `
加油  r$ x+ P8 W  b. s. z, x/ z6 _+ N
回复

使用道具 举报

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

回复 1# 的帖子

gPrivateDispatchTable 和COMP_TYPE_EXTENSION  没有搜到啊  是EDK专有的么?0 L: x9 k) K4 t7 o! d. z
有看过跟gPrivateDispatchTable 类似的,但是里面的PPI不同。
7 X5 G7 D' ?6 j6 ?' i4 v$ C5 Y还有这个COMP_TYPE_EXTENSION  没有找到过。FWVolume.c这个文件也没有发现。。
回复

使用道具 举报

发表于 2008-7-28 13:24:20 | 显示全部楼层
这东西虽说没有什么技术含量,但是总结一下还是非常好的。
/ t. b$ Q3 T' h4 _; H
9 t4 u* ~' @4 Y支持!
回复

使用道具 举报

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

( u  T. p. {1 m小弟还在学习阶段,目前的目标是知道执行的流程。
* ?' }/ C6 R. O! \这里面有很多细节没有写,能力有限,只能自己知道,不能表达。3 f7 v! P' V0 x1 ]3 p
嘿。。。。; K# x. ?( t* J
所有大侠们如果有好东西能给小弟共享一份。' x( e, F8 O4 T& [! D

7 k& @- T* ?0 O8 S  u, h谢谢!
回复

使用道具 举报

发表于 2008-8-12 14:44:11 | 显示全部楼层
原帖由 winbondowen 于 2008-7-27 00:11 发表
2 a" I4 b; C0 K+ M% x4 s' P  F' z9 G  ROM中將DXE的驅動讀出,執行執行他們,這時會執行到Driver- n+ E. o  y  q" u" U8 ~
中的Support(),Start()兩個功能函數。在這兩個函數中你可以註冊自己的PPI ...

7 h' h; T; o2 Q8 F8 h4 s0 @- D7 l4 A
PPIs are registered during PEI phase, but Support()/Start() are invoked in DXE driver binding protocol,
  _8 z  f/ n$ D* vFor more precisely, I think the "PPI" you mentioned is the "PROTOCOL" rather than "PPI".
5 Z, c9 L$ y. I2 w$ n- ]3 F! J% ?' T8 b8 ]" @
[ 本帖最后由 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:! }4 H- r1 `* u7 T( _* x- l" X' {
   Yes. I make a mistake.- P4 w. z- l2 e* Y/ z
      PPI:     A PEIM to PEIM interface.+ Z+ `9 N, m4 Q3 c0 D! l* Y  R  H
      PROTOCL: A Interface between Hardware(or firmware) and software.
  I& D- x' q! z3 D9 r* R      reference[http://www.biosren.com/viewthread.php?tid=207]- o6 Z& w2 n5 j& R
   so, PPI execute at PEI step and Initialize hardware. PROTOCOL execute by DXE step., s( A" s5 v2 B9 b/ @2 q% w
   Thanks.
回复

使用道具 举报

发表于 2008-8-20 17:47:21 | 显示全部楼层
原帖由 winbondowen 于 2008-7-27 00:11 发表 DXE:
! N: Z6 Y0 R: N     從PEI到DXE切換時轉過來一個HOBLIST參數,DXE會在這個HOB中找到Memory的使用情況,然後根據這些情況將BIOS引到內存(這是EFI的做法)。在EDK在DXE時重新定位一下內存。( @. q( j" |! M6 P; Q+ q
接著就會定義我們經常使用到的gST表,gRT表。接著是申明一些Protocol(先不關心這些事)。
  o8 x( V! U' E5 o- W   等這些該加的PPI,Protocol加完了,CoreDispatcher()就出場了。他會的功能類似PEIDispatcher()。從我們BIOS ROM中將DXE的驅動讀出,執行執行他們,這時會執行到Driver3 @2 u& v: E. U2 Z$ m
中的Support(),Start()兩個功能函數。在這兩個函數中你可以註冊自己的PPI,為其他驅動提供服務。/ w; A1 l8 R! Q; s/ k9 V/ A
   到些BIOS的引導其他完成。接著該進OS了,看Linux 0.11吧,操作系統是怎麼做事情的。.

7 i+ o1 r, f( h4 L+ h3 G' ~1 S% t1 Z" U
There are mistakes,
- N, g" Z- b/ H5 |1.gST and gRT are init after the DXE architectural protocols have been loaded, those protocols response for creating Dxe foundation.
0 G0 z9 z# p' t% j; e# S7 k2 N2 m0 g: g: t
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.
: J# y0 D/ [7 v- z1 K' gThe CoreDispatcher() executes all trusted Dxe drivers and just register the Binding protocol if the driver is EFI1.1 driver model.3 g* w# E$ U. ~, H- g
Furthermore, Support()/Start() are invoked in BDS phase over the CoreConnectController() rather than CoreDispatcher().
9 ~5 K1 Y/ ]8 x/ }2 S- ~+ U+ ?, Y3 P
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 大侠的指点。
7 X1 {6 X  V1 Z2 L$ ^. Z/ k9 c
回复

使用道具 举报

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

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

原帖由 ichirohiro 于 2008-8-20 17:47 发表 8 {8 ~6 ]( M7 Q
...1 m7 d/ m4 [. S, Z# T5 Y; X! ?3 A
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.
1 L( T: W8 N) ^5 qThe CoreDispatcher() executes all trusted Dxe drivers and just register the Binding protocol if the driver is EFI1.1 driver model.
3 N' v: p% O: y" {8 ?; @Furthermore, Support()/Start() are invoked in BDS phase over the CoreConnectController() rather than CoreDispatcher().
! f* L" r  ]0 h" U
    在Framework的spec DxeCis.pdf里面也是这么说的,DXE CoreDispatcher()里面,对于EFI1.1 driver model的driver只会安装Handler和Interface到Binding protocol,到BDS才会去执行Support()和Start().
8 R& @& M$ H+ Y1 h% K# e! D# b    但是,我在看code时,发现在CoreDispatcher()-->CoreStartImage()里面call image之后有这么一句:  (file:image.c)1 Z9 B. t- d3 Y5 X
  //
: w/ ~7 b0 F2 X1 `  // Go connect any handles that were created or modified while the image executed.
/ |2 C3 E- g3 `% g3 @  //0 C; o8 Z/ b7 N& q0 Q
  CoreConnectHandlesByKey (HandleDatabaseKey);

7 X  h( e) o: x# e7 n( Q& \这里的HandleDatabaseKey是call image之前由CoreGetHandleDatabaseKey()得到的gHandleDatabaseKey
: ?, o% k8 [6 E+ W* b- V而CoreConnectHandlesByKey会调用到:
. Y3 V% A, V0 X( X  //
- p2 P) F; P, w  @0 F& ~1 K: o" L  // Connect all handles whose Key value is greater than Key
" }) y2 W/ \7 [4 Q# D  //
% h1 _  x/ J4 x1 G* P! F, ?  for (Index = 0; Index < Count; Index++) {- d6 U; F% |" p0 `- @$ x
    CoreConnectController (HandleBuffer[Index], NULL, NULL, TRUE);
5 b! n% j( D% A  }
$ Z, d" {( ?# N6 J) E4 }5 L+ M5 h& h
所以,照code看,当在Driver中安装一个Handle和Interface到Binding Protocol后(gHandleDatabaseKey会++,IHandle的Key=gHandleDatabaseKey)5 u1 W' j0 C* O" a
是会去ConnectController的,也会执行对应的Support()和Start()才对!!
5 v: L8 t3 e: U- e4 q  [& n6 I: Y; ~
不知道我想的哪里有问题???欢迎大家指正.
4 Y( l. |' P( j# H9 O+ X  }2 {# O# P3 n! }4 D
[ 本帖最后由 xtdumpling 于 2008-9-18 15:25 编辑 ]
回复

使用道具 举报

发表于 2008-9-19 14:44:41 | 显示全部楼层
这段code似乎是一个向后兼容的行为,不必太care。* z9 Y8 j" d$ w' L4 L
一个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 | 显示全部楼层
了解了.0 n* K- ]5 [4 F' u8 ]
非常 感谢!!!
回复

使用道具 举报

发表于 2008-9-23 16:48:56 | 显示全部楼层
在读DXEmain时,+ W8 r+ s" o' y
Status = CoreInitializeImageServices(HobStart);--->CoreInstallProtocolInterface();--->CoreInstallProtocolInterfaceNotify();中,
0 T; B6 E, ^1 A//
4 I! q* |# j  j6 |  d// Notify the notification list for this protocol.
" g( _* r0 B7 w7 H5 X  v//" W6 x  o4 p9 H  }. A
if (Notify) {. `/ N' s6 q1 i3 {" n7 y3 S3 e
  CoreNotifyProtocolEntry(ProtEntry);! @1 Z: L. |- w2 }  X6 C! q; W; q, l
}    里Signal了Event. MS是说一个handle安装了一个protocol后就signal一次.: v! P9 Q& Z. ]) _* s
有个问题请教一下大家: 这段是在DXE很靠前的位置执行的,但是在它之前我没有看到DXE中有相关的CreateEvent出现?哪位高手能说说这部分代码的流程呢?
回复

使用道具 举报

发表于 2008-9-23 17:04:14 | 显示全部楼层
原帖由 xtdumpling 于 2008-9-16 13:34 发表 ) \2 E" g! |2 J! `) k5 E% V
请楼上的兄弟分析下BS的RegisterProtocolNotify也就是CoreRegisterProtocolNotify是做什么用的?怎么用?; t* d. B( h1 I$ d6 H0 v! S
谢谢!
" o2 V/ T# p; q5 }
......
# V3 w# K3 a" r. d% V& v# a1 `" J# Q7 `
( O4 [- z# x8 @7 K, l0 K/ H/ V
+ U$ c' ?, A2 \" ]# C% f/ M[ 本帖最后由 xtdumpling 于 2008-9-23 17:24 编辑 ]
回复

使用道具 举报

发表于 2008-9-24 12:43:45 | 显示全部楼层
原帖由 xtdumpling 于 2008-9-23 17:04 发表 4 M9 ]& C1 U) g: j

/ @9 v. m" C5 X1 D2 s% I0 ^$ w+ _! k......
: t# I/ F0 c) Z8 f
( y% t8 l$ u* P+ ~9 `6 x. e
Signal的Event是不是在各个TPL级上挂载一些待处理的事件,一旦restore(TPL)的话,比当前TPL级高的pending事件就回被处理掉?
  H% g7 |8 W+ F! V/ y如果是这样的话,Timer事件是如何处理的呢,没有找到相关的代码呀?Xt指点一下再~
回复

使用道具 举报

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

使用道具 举报

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

本版积分规则

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

GMT+8, 2026-3-5 19:07 , Processed in 0.076051 second(s), 16 queries .

Powered by Discuz! X3.5

© 2001-2025 Discuz! Team.

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