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

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

[复制链接]
发表于 2008-7-27 00:11:28 | 显示全部楼层 |阅读模式
  最近在工作看到机台有启动过程中把SPI ROM数据清空,但苦与没有办法很好的Debug(PCA没有架起来),所有与EDK为对象好好的读了一把。
7 q6 ?4 M/ r  L
6 h; Q! \. D; [' ~1 q: FSEC/CEI:
$ Q0 \0 T9 g3 s% o  UEFI BIOS启动时先会执行SEC/CEI,这个阶段在实现的BIOS Code中初始化Debug Port,进入Big Mode,CPU的MicroCode,CacheToRAM的转换.然后跳转到PEI阶段。7 S$ i5 V6 S4 v  G& ^
在EDK中这部分被成了Load FvRecovery.fd文件,这个文件类似与我们的BIOS ROM.里面是我们编译后生成的二进制代码。在这个阶段最主要的是将这个文件加载到内存中(Windows API将文件加载到内存,看API函数).
9 t; c; y0 R. D, h7 l$ O6 x. N# j! Z3 c- y
PEI:! N' r/ }1 _3 i! a; N  R; p
   从这里开始UEFI BIOS和EDK执行基本相同,只是一个是从SPI ROM中定位一个地址(PEIM的开始地址),一个是从内存中定位一个地址(PEIM的开始地址)。从这里开始只讲EDK的执行
# [; b' w$ s0 \3 t) _6 |5 k) P8 n  EDK调用InitializeMemoryService函数,将HobList清空,peiservice清空。
; M4 A' d  I& J# M5 @      InitializePPIService函数,将PPI队列清空,这个队列长0x3F.
2 X+ G# s/ N, V2 k% |          InitializeSercurityService函数,将Notify队列清空。; X% o1 w4 w4 J0 c
          InitializeDispatcherData函数,将Dispatcher队列清空。9 H6 _. `$ q/ Q+ k0 Y  u
  接着由PeiBuildHobGuid来建立一个HOB(S3返回时这时应该有这个HOB,不用建立,直接使用了,这样就会进入另外一个流程,可以这个EDK不能调试S3,不知道怎么走)。然后由(*PeiServices)->InstallPpi()将这个新HOB加入到PPI中。2 \+ a" c+ Y# D& R6 m
    由于在SEC阶段转了以下这几具PPI,所以在执行PEI的Dispatcher之前会先安装东西:; j5 A! g5 i) }* R
      EFI_PEI_PPI_DESCRIPTOR    gPrivateDispatchTable[] = {
2 K4 [# {+ `! V9 \' ^3 Q  J       {EFI_PEI_PPI_DESCRIPTOR_PPI, &gEfiNtLoadAsDllPpiGuid, &mSecNtLoadAsDllPpi},
3 S$ T: g1 A$ A! ~       {EFI_PEI_PPI_DESCRIPTOR_PPI, &gNtPeiLoadFileGuid, &mSecNtLoadFilePpi},( j0 V& h9 s( T# Y, p" t
       {EFI_PEI_PPI_DESCRIPTOR_PPI, &gPeiNtAutoScanPpiGuid, &mSecNtAutoScanPpi},
: ^; R" n0 N' T$ h& k4 _7 ~       {EFI_PEI_PPI_DESCRIPTOR_PPI, &gPeiNtThunkPpiGuid, &mSecWinNtThunkPpi},1 n9 r4 A% H; B% s8 o" L/ ?" M* q
       {EFI_PEI_PPI_DESCRIPTOR_PPI, &gPeiStatusCodePpiGuid, &mSecStatusCodePpi},) F, H! M, V7 A( P9 S: x5 b
       {EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST, &gNtFwhPpiGuid, &mSecFwhInformationPpi}
4 W) w6 {+ E5 v; X9 I     };% C/ G1 i( D. X7 G! }+ o/ M: q& T
    每个PPI是由{类型,GUID(名字,以后就根据这个来找到它的),Function_Entry_Address}组成。* P/ d9 t4 [9 F, S
   这些PPI会在PEIDispatcher中用到。8 p: Y: U8 l3 S5 K- c/ c
   安装完这此东西这开始执行PEIDispatcher函数,函数从BIOS ROM文件中找出PEI的Image(怎么找到,请读一下FV_HEAD(EFI_HEAD),里面讲到了如何区分Image类型),然后定位到PEI Image的入口地址,执行他。在我们的的PEI中,我们一般会申明一个PPI,这个就是这个PEI提供一些服务,PEIDispatcher会将他们加入到PPI-List中,以后其他Image也可以调用他的提供的功能。
5 N+ t4 {% p8 \3 O" E% _   最后EDK会加载一个叫DXEIPL的PEI,DXEIPL提供一个PPI服务,这个PPI的功能是实现从PEI到DXE的切换,这个PPI里面为DXE做了很多的预准备,加载了很多PPI,如对BIOS的解压方法等。: l* b! T. s) J2 U! @
   SwitchStacks (
8 ^& p/ H5 D2 Q9 e0 \       (VOID *) (UINTN) DxeCoreEntryPoint,
7 A( B+ k. q% {8 J! p       (UINTN) (HobList.Raw),
3 \; I5 [* x& l9 @" ]$ e       (VOID *) (UINTN) TopOfStack,
. n( |8 M$ c( q# V       (VOID *) (UINTN) BspStore
  `% D5 R2 m/ i0 A4 [: Y( x    );8 W! V0 q: [& Y. f
  用过汇编的人对这个技术一定很熟悉,不多说了(我别不清,咯。。。)
' Y& V' ?" m" M+ x
3 G1 D0 s  F7 [6 c# O4 c1 TDXE:
; U! x0 Y9 C, i# }2 z0 ?     从PEI到DXE切换时转过来一个HOBLIST参数,DXE会在这个HOB中找到Memory的使用情况,然后根据这些情况将BIOS引到内存(这是EFI的做法)。在EDK在DXE时重新定位一下内存。3 g, D& L- b  a) q: t7 j
接着就会定义我们经常使用到的gST表,gRT表。接着是申明一些Protocol(先不关心这些事)。
% D. d$ R/ e# g. R# I+ Q. N4 L   等这些该加的PPI,Protocol加完了,CoreDispatcher()就出场了。他会的功能类似PEIDispatcher()。从我们BIOS ROM中将DXE的驱动读出,执行执行他们,这时会执行到Driver
# n! j" P6 r( a# v" U中的Support(),Start()两个功能函数。在这两个函数中你可以注册自己的PPI,为其他驱动提供服务。5 P0 M, K5 H& |. d( C0 z* ^
   到些BIOS的引导其他完成。接着该进OS了,看Linux 0.11吧,操作系统是怎么做事情的。
8 F/ w4 H% j2 {2 m! Y3 o) M. l   
" T! _7 A/ E0 L( @/ ]4 c: k! SDriver:
/ G* U. y, H( p4 k( i* U! F" J. d    我们的驱动什么为在PEI和DXE等不同阶段执行呢?
2 M6 \- |8 N8 V7 G  大家请看一下我们的驱动的makefile.(EDK中的*.inf)
* b7 `. g4 Q5 D2 D: |, P8 R1 y8 A  [defines]4 V, h! Y& h+ |+ n+ ~
  BASE_NAME            = OWEN
7 C' T: \/ r6 \' n& }. R  ~  A$ k  FILE_GUID            = 1EDD13C1-62EF-4262-A1AA-0040D0830110- i5 c2 N; R4 H! g: S% D
  COMPONENT_TYPE       = BS_DRIVER
0 j$ _2 q6 W6 |
" k' u0 P2 A" z3 b. u& N1 M  BASE_NAME告诉编译器最终生成的驱动的名字。8 E; m1 [3 \& j6 r! e9 y
  FILE_GUID就是这个驱动的GUID名字,在BIOS中引用某个驱动就是根据它来调用和识别。
' d5 j4 U6 a- z" p9 [0 o  COMONENT_TYPE会告诉编译器生成驱动的类型,是PEI,DXE,等。) Q4 H4 b& X0 i: d
  在EDK中有一个FWVolume.c实现的功能就是帮我们把这个TYPE转换面相应的扩展名
# ~0 b% G# a: D  COMP_TYPE_EXTENSION  mCompTypeExtension[] = {
# a& g5 e+ m7 U: \  {"bs_driver",  ".dxe" },
4 m8 u) o7 a. ]2 B& q  {"rt_driver",  ".dxe" },
2 X( g! |0 Q$ s5 w: w6 X  {"sal_rt_driver", ".dxe"},! E/ }5 r# g# x5 D0 N
  {"security_core", ".sec"},4 b: p3 M7 [+ n- C/ `& S: z
  {"pei_core", ".pei"},
+ W' a, N9 {  Y  {"pic_peim", ".pei"},
9 _% O+ k& N3 F) i! W; i, \  {"pe32_peim", ".pei"},
! O3 x) h* d# k% S0 E* G/ W  {"relocatable_peim", ".pei"},3 F- I  G4 `4 T& x( o1 _3 L) i0 h
  {"binary", ".ffs"},
3 b) K, S6 r. t6 J; n  {"application", ".app"},
* [7 S1 U, v. u. Q# r- D! G  {"file", ".ffs"},
% I! M- V6 t8 L9 Q* ]  {"fvimagefile", ".fvi"},+ [- G" e6 ^- [, _# `. g
  {"rawfile", ".raw"},
0 R* W7 h1 L6 o: R6 ]8 t* K  {"apriori", ".ffs"},
( |1 D# j, P6 z  {"combined_peim_driver", ".pei"},
8 E% p  b' U) A# P  { NULL,  NULL }) d: @) m) C) h$ d: V; e. U3 A
};
3 b* N6 p) T$ {* O
1 x. p! I, p) y/ o2 Q9 _7 }了解了这些,接下我们可以看驱动篇了。(Go On Study... Forever)+ }, ?2 n( R' \" w  t$ N( O
   
6 ?! k. Q" k* O& W7 v         ; E. x0 q/ P0 A$ I) j: R  b
  
发表于 2008-7-27 12:30:15 | 显示全部楼层
不错!) w# d) E/ z# ]1 ?- g1 ~
支持
  u4 \) h1 ?4 O" R, ^继续
5 o3 P0 q' R' `' }; M8 Q6 _( i加油1 W' x! G1 s8 q3 |/ c, o
回复

使用道具 举报

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

回复 1# 的帖子

gPrivateDispatchTable 和COMP_TYPE_EXTENSION  没有搜到啊  是EDK专有的么?
0 n* u+ a8 K7 z9 d- p1 W有看过跟gPrivateDispatchTable 类似的,但是里面的PPI不同。
2 [5 |+ m$ s0 N& g& Y还有这个COMP_TYPE_EXTENSION  没有找到过。FWVolume.c这个文件也没有发现。。
回复

使用道具 举报

发表于 2008-7-28 13:24:20 | 显示全部楼层
这东西虽说没有什么技术含量,但是总结一下还是非常好的。3 }; l- z: J  {" K, c: R" V# g

8 r: Y  C/ A; r) E( s& G' f: \支持!
回复

使用道具 举报

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

2 {$ n; i# E1 h+ C小弟还在学习阶段,目前的目标是知道执行的流程。& s" @) C. U* k/ Z3 [
这里面有很多细节没有写,能力有限,只能自己知道,不能表达。- P; C1 }  |9 A  }+ Q) h2 [
嘿。。。。2 u% Z8 L) n* M$ ?, \, l
所有大侠们如果有好东西能给小弟共享一份。
  \( ?5 i" m4 e
" B* w8 Q& ?1 W+ r谢谢!
回复

使用道具 举报

发表于 2008-8-12 14:44:11 | 显示全部楼层
原帖由 winbondowen 于 2008-7-27 00:11 发表 : ~( k' b+ P8 j& t  f( G  H% R
  ROM中將DXE的驅動讀出,執行執行他們,這時會執行到Driver) t6 F, s, m: _: A5 G9 D/ X4 k) M
中的Support(),Start()兩個功能函數。在這兩個函數中你可以註冊自己的PPI ...

  g0 a, s; C1 ]9 t( y
9 o6 X2 g, r3 HPPIs are registered during PEI phase, but Support()/Start() are invoked in DXE driver binding protocol,
- j" b. ?: v; u) W$ Z3 bFor more precisely, I think the "PPI" you mentioned is the "PROTOCOL" rather than "PPI".$ ~1 I) f% T1 u: `

: ^% i- N( Q; u; h[ 本帖最后由 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 B2 J, v  W$ T+ h7 U   Yes. I make a mistake.
# F" j- I6 b) e  R% z! U+ m8 G, S      PPI:     A PEIM to PEIM interface., C  V' b+ f/ ?4 k. M
      PROTOCL: A Interface between Hardware(or firmware) and software.
9 X/ ]0 Z1 N( l7 ]- T! m/ X      reference[http://www.biosren.com/viewthread.php?tid=207]
8 z9 c$ m. L! l3 w, T* O8 `   so, PPI execute at PEI step and Initialize hardware. PROTOCOL execute by DXE step.$ `. ?( l! g+ I2 ]
   Thanks.
回复

使用道具 举报

发表于 2008-8-20 17:47:21 | 显示全部楼层
原帖由 winbondowen 于 2008-7-27 00:11 发表 DXE:
& K* Z. f  g" |7 \% ?/ ]7 {6 }     從PEI到DXE切換時轉過來一個HOBLIST參數,DXE會在這個HOB中找到Memory的使用情況,然後根據這些情況將BIOS引到內存(這是EFI的做法)。在EDK在DXE時重新定位一下內存。
( B5 o" y9 y2 E$ |" b; i接著就會定義我們經常使用到的gST表,gRT表。接著是申明一些Protocol(先不關心這些事)。2 x9 q- Z4 w; V; H/ \) L
   等這些該加的PPI,Protocol加完了,CoreDispatcher()就出場了。他會的功能類似PEIDispatcher()。從我們BIOS ROM中將DXE的驅動讀出,執行執行他們,這時會執行到Driver
  d& d' o9 a7 E+ X; N5 q# Z中的Support(),Start()兩個功能函數。在這兩個函數中你可以註冊自己的PPI,為其他驅動提供服務。1 f" A, x) s/ R' u% z
   到些BIOS的引導其他完成。接著該進OS了,看Linux 0.11吧,操作系統是怎麼做事情的。.

: F- s5 Y" H+ G  W+ ?
+ \1 ]# r$ u. FThere are mistakes,
$ q/ P9 T1 x- W5 m1.gST and gRT are init after the DXE architectural protocols have been loaded, those protocols response for creating Dxe foundation.
& ~% j: v1 |6 T$ f) J9 l; q: `9 s) y+ B( {' t, }4 S6 V
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.
3 B" X+ H7 A' {- z3 [The CoreDispatcher() executes all trusted Dxe drivers and just register the Binding protocol if the driver is EFI1.1 driver model." r  c/ l4 F( @2 m: P' w  F
Furthermore, Support()/Start() are invoked in BDS phase over the CoreConnectController() rather than CoreDispatcher().8 B! x- R  q% \+ Q7 X
& V, S; g9 l/ B$ T' y6 u
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 大侠的指点。; {% w' S6 _. W% o
回复

使用道具 举报

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

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

原帖由 ichirohiro 于 2008-8-20 17:47 发表 6 A. r% w! \" C$ ]% Z8 u
...4 X0 k- L9 R* `5 d
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) M: |* H# }! l$ o
The CoreDispatcher() executes all trusted Dxe drivers and just register the Binding protocol if the driver is EFI1.1 driver model.& a( D, p9 U! j& O* l% v+ z) G% Q
Furthermore, Support()/Start() are invoked in BDS phase over the CoreConnectController() rather than CoreDispatcher().

6 D: f4 [/ g$ U* g; L: w3 c    在Framework的spec DxeCis.pdf里面也是这么说的,DXE CoreDispatcher()里面,对于EFI1.1 driver model的driver只会安装Handler和Interface到Binding protocol,到BDS才会去执行Support()和Start().
; X/ U$ A4 x) y9 h) L    但是,我在看code时,发现在CoreDispatcher()-->CoreStartImage()里面call image之后有这么一句:  (file:image.c)
5 I: e2 L3 r6 Z  //1 u2 e. q4 b! I1 @1 u
  // Go connect any handles that were created or modified while the image executed.
7 A/ N* r, }5 q& |6 L- s8 {  //; U8 G" ]5 Q: D" J! z5 M, ]
  CoreConnectHandlesByKey (HandleDatabaseKey);
/ u6 f! @; _# |. t. g4 C( X
这里的HandleDatabaseKey是call image之前由CoreGetHandleDatabaseKey()得到的gHandleDatabaseKey
& O# p  z$ @3 Z而CoreConnectHandlesByKey会调用到:
% P9 Q8 S& @" {% ~) D+ ^1 Z  //* `& n2 j" m" O2 b. w
  // Connect all handles whose Key value is greater than Key; V+ z  Z8 n4 h4 S* |
  //
2 o8 r1 p7 J9 `" S& g5 L. M  for (Index = 0; Index < Count; Index++) {
5 W2 y0 H! L, s" f; e! T    CoreConnectController (HandleBuffer[Index], NULL, NULL, TRUE);1 |" T$ Y6 l* d5 P1 x
  }
* \8 g" m2 W: ?+ N  Y* l
所以,照code看,当在Driver中安装一个Handle和Interface到Binding Protocol后(gHandleDatabaseKey会++,IHandle的Key=gHandleDatabaseKey)
" E/ ~* X7 i- h8 b- P5 L" u4 ]8 R% b是会去ConnectController的,也会执行对应的Support()和Start()才对!!
* _$ g6 @" k7 `! c9 g' r4 A9 P7 ~9 {8 |- v4 l
不知道我想的哪里有问题???欢迎大家指正.' T( z" K0 h. @3 B5 }

/ ~/ w: Z3 |4 x# L9 J$ y# f[ 本帖最后由 xtdumpling 于 2008-9-18 15:25 编辑 ]
回复

使用道具 举报

发表于 2008-9-19 14:44:41 | 显示全部楼层
这段code似乎是一个向后兼容的行为,不必太care。
5 ^  u/ z6 e, ?' \+ B* 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 | 显示全部楼层
了解了.  z* m; t5 g8 ^. Z/ o/ Y. G9 |
非常 感谢!!!
回复

使用道具 举报

发表于 2008-9-23 16:48:56 | 显示全部楼层
在读DXEmain时,
! b. H9 c  l+ _1 ]: k. Q5 D. [Status = CoreInitializeImageServices(HobStart);--->CoreInstallProtocolInterface();--->CoreInstallProtocolInterfaceNotify();中,3 {  V/ F5 S; e5 T& r5 t
//, I* @! M- x2 p8 b" t
// Notify the notification list for this protocol.
# x% {. Z5 _/ J+ l* P! b//6 U( i2 d% k# `* w8 [1 i' D9 H
if (Notify) {
( W# {* A( d  ^3 ~. N8 A: B/ f, i  CoreNotifyProtocolEntry(ProtEntry);
5 \6 m% X+ k4 g, O5 j+ g5 p}    里Signal了Event. MS是说一个handle安装了一个protocol后就signal一次.+ ^. m1 O5 P" H" ^" ]$ }6 z
有个问题请教一下大家: 这段是在DXE很靠前的位置执行的,但是在它之前我没有看到DXE中有相关的CreateEvent出现?哪位高手能说说这部分代码的流程呢?
回复

使用道具 举报

发表于 2008-9-23 17:04:14 | 显示全部楼层
原帖由 xtdumpling 于 2008-9-16 13:34 发表
1 p9 u2 P5 j% {# X+ m请楼上的兄弟分析下BS的RegisterProtocolNotify也就是CoreRegisterProtocolNotify是做什么用的?怎么用?
: f" Y+ Y: M" B6 ~3 J6 o谢谢!
( T2 B* J7 D$ [4 C! O
......
* q8 `8 c/ v9 B7 q1 ~) ?# G0 _* A% W; i+ Z5 {

" {) q1 X* [! G3 D# g* B, w* r[ 本帖最后由 xtdumpling 于 2008-9-23 17:24 编辑 ]
回复

使用道具 举报

发表于 2008-9-24 12:43:45 | 显示全部楼层
原帖由 xtdumpling 于 2008-9-23 17:04 发表
1 |$ ^0 q+ R- Z( ?0 J  }. t! A- H/ t! e6 @5 `& N
......
9 j  D# X7 t- b, g  Y, a2 Q

# u) h5 \2 {1 D7 u6 [7 RSignal的Event是不是在各个TPL级上挂载一些待处理的事件,一旦restore(TPL)的话,比当前TPL级高的pending事件就回被处理掉?" E1 I% {. T/ s" R: K: Y# k8 |
如果是这样的话,Timer事件是如何处理的呢,没有找到相关的代码呀?Xt指点一下再~
回复

使用道具 举报

发表于 2008-9-24 19:00:46 | 显示全部楼层
Timer是挂在8259的IRQ0的中断处理程序上面的, 大概每秒18.3次调用CoreTimerTick()-->CoreCheckTimers()* G- o5 v% a0 {- Y. x  A( Y
TPL=30
回复

使用道具 举报

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

本版积分规则

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

GMT+8, 2026-3-5 15:55 , Processed in 0.089270 second(s), 17 queries .

Powered by Discuz! X3.5

© 2001-2025 Discuz! Team.

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