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

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

[复制链接]
发表于 2008-7-27 00:11:28 | 显示全部楼层 |阅读模式
  最近在工作看到机台有启动过程中把SPI ROM数据清空,但苦与没有办法很好的Debug(PCA没有架起来),所有与EDK为对象好好的读了一把。
4 h2 _) U! J) m: w' n! u) t( B6 U6 l, e$ v$ S
SEC/CEI:' v' e; r+ f, G# v& J
  UEFI BIOS启动时先会执行SEC/CEI,这个阶段在实现的BIOS Code中初始化Debug Port,进入Big Mode,CPU的MicroCode,CacheToRAM的转换.然后跳转到PEI阶段。
, Y, K7 l+ p5 H# k$ P在EDK中这部分被成了Load FvRecovery.fd文件,这个文件类似与我们的BIOS ROM.里面是我们编译后生成的二进制代码。在这个阶段最主要的是将这个文件加载到内存中(Windows API将文件加载到内存,看API函数)./ N# ~5 e" c( Q* f+ n9 L
; P  P6 K6 G, }! o& O; F
PEI:3 [. N; G3 Z7 D  G- m
   从这里开始UEFI BIOS和EDK执行基本相同,只是一个是从SPI ROM中定位一个地址(PEIM的开始地址),一个是从内存中定位一个地址(PEIM的开始地址)。从这里开始只讲EDK的执行9 q! \) o+ F8 f
  EDK调用InitializeMemoryService函数,将HobList清空,peiservice清空。
0 }7 g( n1 f' _( Z      InitializePPIService函数,将PPI队列清空,这个队列长0x3F.$ q' {; A% M0 F  S
          InitializeSercurityService函数,将Notify队列清空。# L( U& j6 N! U, c1 W
          InitializeDispatcherData函数,将Dispatcher队列清空。
$ f9 w! \3 F+ M3 B8 E  接着由PeiBuildHobGuid来建立一个HOB(S3返回时这时应该有这个HOB,不用建立,直接使用了,这样就会进入另外一个流程,可以这个EDK不能调试S3,不知道怎么走)。然后由(*PeiServices)->InstallPpi()将这个新HOB加入到PPI中。
5 U$ g; |. n. t& ]7 Q+ J    由于在SEC阶段转了以下这几具PPI,所以在执行PEI的Dispatcher之前会先安装东西:9 G/ [% j' f  M5 e
      EFI_PEI_PPI_DESCRIPTOR    gPrivateDispatchTable[] = {1 y9 v8 E) u1 S. }( O
       {EFI_PEI_PPI_DESCRIPTOR_PPI, &gEfiNtLoadAsDllPpiGuid, &mSecNtLoadAsDllPpi},1 X" E9 E6 F2 k' b$ U
       {EFI_PEI_PPI_DESCRIPTOR_PPI, &gNtPeiLoadFileGuid, &mSecNtLoadFilePpi},- K% ?6 ?- P% `2 W  s* q
       {EFI_PEI_PPI_DESCRIPTOR_PPI, &gPeiNtAutoScanPpiGuid, &mSecNtAutoScanPpi},
0 P2 x8 h" F+ S0 h: }7 [       {EFI_PEI_PPI_DESCRIPTOR_PPI, &gPeiNtThunkPpiGuid, &mSecWinNtThunkPpi},: c) K. m* g* ?- A) D+ p" T0 M
       {EFI_PEI_PPI_DESCRIPTOR_PPI, &gPeiStatusCodePpiGuid, &mSecStatusCodePpi},! s- B# L  s, i8 ^% C0 H2 j/ \! I
       {EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST, &gNtFwhPpiGuid, &mSecFwhInformationPpi}
* k6 R6 K! L" U. P0 t     };* {/ o4 ~9 u9 T3 ]1 ]
    每个PPI是由{类型,GUID(名字,以后就根据这个来找到它的),Function_Entry_Address}组成。
/ k# L% x7 U  l) z( c8 j0 X8 a   这些PPI会在PEIDispatcher中用到。
( e: ^) U4 W% b/ H) D$ f! ]   安装完这此东西这开始执行PEIDispatcher函数,函数从BIOS ROM文件中找出PEI的Image(怎么找到,请读一下FV_HEAD(EFI_HEAD),里面讲到了如何区分Image类型),然后定位到PEI Image的入口地址,执行他。在我们的的PEI中,我们一般会申明一个PPI,这个就是这个PEI提供一些服务,PEIDispatcher会将他们加入到PPI-List中,以后其他Image也可以调用他的提供的功能。- ^: l  H7 ]: x+ L, |$ ]; I7 W
   最后EDK会加载一个叫DXEIPL的PEI,DXEIPL提供一个PPI服务,这个PPI的功能是实现从PEI到DXE的切换,这个PPI里面为DXE做了很多的预准备,加载了很多PPI,如对BIOS的解压方法等。1 }9 A) P; l1 Q( i
   SwitchStacks (5 r: w! s  n: D8 |
       (VOID *) (UINTN) DxeCoreEntryPoint,
$ f; G6 ^" J7 J- V5 H       (UINTN) (HobList.Raw),
% Q# U4 L* o( D       (VOID *) (UINTN) TopOfStack," J( I$ m8 _) [: o1 d# r0 r: i6 }
       (VOID *) (UINTN) BspStore6 H2 O1 c; C  C" X0 A
    );5 {- A- ^, \1 d" c5 J
  用过汇编的人对这个技术一定很熟悉,不多说了(我别不清,咯。。。)$ _! B, r' b! z- k0 r9 w

! ?3 Y! A& Z  KDXE:5 W! p/ G  J- l: I+ l; |) b
     从PEI到DXE切换时转过来一个HOBLIST参数,DXE会在这个HOB中找到Memory的使用情况,然后根据这些情况将BIOS引到内存(这是EFI的做法)。在EDK在DXE时重新定位一下内存。
5 Q. R+ q9 p) o) G- S/ E7 {接着就会定义我们经常使用到的gST表,gRT表。接着是申明一些Protocol(先不关心这些事)。5 M( J4 u* f. Q* u
   等这些该加的PPI,Protocol加完了,CoreDispatcher()就出场了。他会的功能类似PEIDispatcher()。从我们BIOS ROM中将DXE的驱动读出,执行执行他们,这时会执行到Driver  T6 |5 t# G& J8 m3 B
中的Support(),Start()两个功能函数。在这两个函数中你可以注册自己的PPI,为其他驱动提供服务。% d$ w* f% O/ a( U; k
   到些BIOS的引导其他完成。接着该进OS了,看Linux 0.11吧,操作系统是怎么做事情的。: f; ?  y% n' X1 ], O3 @9 ?7 l
   
! j9 f2 U3 A! c& WDriver:$ t& N, q! H2 B
    我们的驱动什么为在PEI和DXE等不同阶段执行呢?
& |0 z7 a, B$ e/ r9 u9 `  大家请看一下我们的驱动的makefile.(EDK中的*.inf)
3 A& M8 o( Y* F9 V8 L8 q- \, k  [defines]6 {  n/ }% S% U  i% h' |# s* T/ D
  BASE_NAME            = OWEN
3 E0 }; J& A7 ^7 w: Z) [  z  FILE_GUID            = 1EDD13C1-62EF-4262-A1AA-0040D0830110/ D* ^0 p6 s, v
  COMPONENT_TYPE       = BS_DRIVER6 Y9 G* P. I1 w1 p$ A7 E
% n2 ~5 x! l" U" y) q7 l8 N
  BASE_NAME告诉编译器最终生成的驱动的名字。
2 S2 q" b3 g7 P, Q. `  FILE_GUID就是这个驱动的GUID名字,在BIOS中引用某个驱动就是根据它来调用和识别。
* h% h. L& A% H% m/ n( F  COMONENT_TYPE会告诉编译器生成驱动的类型,是PEI,DXE,等。
" [& B( R# ~' a# p! S* }. E  在EDK中有一个FWVolume.c实现的功能就是帮我们把这个TYPE转换面相应的扩展名
5 ]5 s, \3 O+ t* v. y* E$ p* p# |  COMP_TYPE_EXTENSION  mCompTypeExtension[] = {
$ H- A0 ]2 p8 k. \: }" c  {"bs_driver",  ".dxe" },
* ~' S+ o) i' b  {"rt_driver",  ".dxe" },& d; @8 V; z" {3 P! B+ F1 i
  {"sal_rt_driver", ".dxe"},
* ^' @1 Y& s1 x$ c1 ^  {"security_core", ".sec"},
& p" m$ L; {; M& a0 m  {"pei_core", ".pei"},; H- E2 M3 C0 O' _9 ]0 v
  {"pic_peim", ".pei"},, h4 F, m  q: z6 W/ H
  {"pe32_peim", ".pei"},
, p5 ]( ]0 O+ C# [/ K  {"relocatable_peim", ".pei"},) q4 @5 C8 h8 Q7 M
  {"binary", ".ffs"},. H( F/ ~; E4 g  `" w
  {"application", ".app"},
5 }. T( F3 k2 s' Q- `3 Y  {"file", ".ffs"},7 X2 _, _  o$ `1 |$ D9 N( ^
  {"fvimagefile", ".fvi"},- _& p( {( D$ X1 w( u
  {"rawfile", ".raw"},
7 U! D) ^8 ]$ \5 M, G  U  {"apriori", ".ffs"},) I2 d; B$ g* O% g
  {"combined_peim_driver", ".pei"},
# B* i' q+ e9 @) O$ V  { NULL,  NULL }; S) V5 M* R! c& a3 e! y& }
};" k- j' x+ T2 L

, e9 f# ?6 \' _/ @6 e了解了这些,接下我们可以看驱动篇了。(Go On Study... Forever)
4 g( `$ @( P+ y/ `( J( \5 l   
( _3 R. }  Q, @! ?0 {0 H         0 o4 l! |7 d9 R- [$ u& C
  
发表于 2008-7-27 12:30:15 | 显示全部楼层
不错!2 \% j5 l1 S( Y# c8 N2 \
支持) l- Y" ^5 u& [$ t7 y- ^
继续. Z* y% ^/ }4 h% a
加油
% C6 J. K3 e5 h" \7 Z
回复

使用道具 举报

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

回复 1# 的帖子

gPrivateDispatchTable 和COMP_TYPE_EXTENSION  没有搜到啊  是EDK专有的么?1 v# }1 ^! t( V; N& J$ v6 u' M  Z
有看过跟gPrivateDispatchTable 类似的,但是里面的PPI不同。
1 E* F; C, H3 D" Y4 z7 y还有这个COMP_TYPE_EXTENSION  没有找到过。FWVolume.c这个文件也没有发现。。
回复

使用道具 举报

发表于 2008-7-28 13:24:20 | 显示全部楼层
这东西虽说没有什么技术含量,但是总结一下还是非常好的。
- s  T' y' R0 f2 ?$ Z) r8 o, _2 q: C! N6 v3 D
支持!
回复

使用道具 举报

 楼主| 发表于 2008-7-28 18:52:31 | 显示全部楼层
0 g, V3 U3 g* a# m
小弟还在学习阶段,目前的目标是知道执行的流程。
  p$ J7 n' t  T5 K9 y这里面有很多细节没有写,能力有限,只能自己知道,不能表达。
* v6 `" @' R$ o  W4 O& `  f3 Y嘿。。。。$ j* @1 [# r: t) O" y# ?4 w
所有大侠们如果有好东西能给小弟共享一份。
, N" R: T3 F: q/ n 7 R- q9 S" e. L( m3 ^- q
谢谢!
回复

使用道具 举报

发表于 2008-8-12 14:44:11 | 显示全部楼层
原帖由 winbondowen 于 2008-7-27 00:11 发表   _" d, O8 F, S! t0 a3 J
  ROM中將DXE的驅動讀出,執行執行他們,這時會執行到Driver
# ?0 o6 ~) _& o1 p中的Support(),Start()兩個功能函數。在這兩個函數中你可以註冊自己的PPI ...
1 ^6 r( U. _2 W+ o# P( H

- F) j, I" E5 M" L) K+ xPPIs are registered during PEI phase, but Support()/Start() are invoked in DXE driver binding protocol,
% V7 g* U1 ~/ I) Z" wFor more precisely, I think the "PPI" you mentioned is the "PROTOCOL" rather than "PPI".
! l. \% a% _4 ^+ Y# O- _9 m4 i: B
[ 本帖最后由 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:
& j+ L( H/ _' D6 g   Yes. I make a mistake.
' d, l& p. b8 Z; z# [  N      PPI:     A PEIM to PEIM interface.
) n9 x& g: s; h6 N% O% V- N      PROTOCL: A Interface between Hardware(or firmware) and software.6 K9 E0 g4 {4 Z
      reference[http://www.biosren.com/viewthread.php?tid=207]: U; Z6 ~" o7 B$ c
   so, PPI execute at PEI step and Initialize hardware. PROTOCOL execute by DXE step.8 ~* E" H) M$ m5 N8 ?
   Thanks.
回复

使用道具 举报

发表于 2008-8-20 17:47:21 | 显示全部楼层
原帖由 winbondowen 于 2008-7-27 00:11 发表 DXE:
0 X9 ]) R" L% A     從PEI到DXE切換時轉過來一個HOBLIST參數,DXE會在這個HOB中找到Memory的使用情況,然後根據這些情況將BIOS引到內存(這是EFI的做法)。在EDK在DXE時重新定位一下內存。
  H  s# U; Z6 L7 [接著就會定義我們經常使用到的gST表,gRT表。接著是申明一些Protocol(先不關心這些事)。
- H7 z7 X7 C( Z   等這些該加的PPI,Protocol加完了,CoreDispatcher()就出場了。他會的功能類似PEIDispatcher()。從我們BIOS ROM中將DXE的驅動讀出,執行執行他們,這時會執行到Driver: p3 \# j# `# }. L8 \
中的Support(),Start()兩個功能函數。在這兩個函數中你可以註冊自己的PPI,為其他驅動提供服務。
* @, t6 T% J+ x3 |9 t6 I   到些BIOS的引導其他完成。接著該進OS了,看Linux 0.11吧,操作系統是怎麼做事情的。.
( S* `' N+ o3 b% y6 e
; ^; z( e7 [8 ~$ F9 j
There are mistakes,) H; r' ]: H0 Q7 R# U0 n
1.gST and gRT are init after the DXE architectural protocols have been loaded, those protocols response for creating Dxe foundation.
: }& C) G: _+ i& a4 t! d8 |1 r
& F, `' w; t! H" V4 K2.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.: F* b( U2 x; s
The CoreDispatcher() executes all trusted Dxe drivers and just register the Binding protocol if the driver is EFI1.1 driver model.5 |2 K. T4 W4 W1 n3 W4 A
Furthermore, Support()/Start() are invoked in BDS phase over the CoreConnectController() rather than CoreDispatcher().
% C3 ]+ K3 d, c/ U  L! K
2 M; A2 G/ y% y! ~$ XBTW, 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 大侠的指点。
' g+ j1 @6 x3 H6 l' w  w3 S
回复

使用道具 举报

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

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

原帖由 ichirohiro 于 2008-8-20 17:47 发表
! D4 V+ [; c7 U; {" e- [7 Q...2 C0 ^' ?& e3 s" W  z: M: v; 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.
6 ~. u; [+ M0 `0 `  lThe CoreDispatcher() executes all trusted Dxe drivers and just register the Binding protocol if the driver is EFI1.1 driver model." {& h3 l  b. v( p! `
Furthermore, Support()/Start() are invoked in BDS phase over the CoreConnectController() rather than CoreDispatcher().

. g2 `& f/ s! u  N% {# F    在Framework的spec DxeCis.pdf里面也是这么说的,DXE CoreDispatcher()里面,对于EFI1.1 driver model的driver只会安装Handler和Interface到Binding protocol,到BDS才会去执行Support()和Start()./ I" G# [/ R) j
    但是,我在看code时,发现在CoreDispatcher()-->CoreStartImage()里面call image之后有这么一句:  (file:image.c)3 ^$ T7 ?2 Q; k: _9 Q! F
  //! Z7 q$ ^, w, u" T' t6 i# U7 ]
  // Go connect any handles that were created or modified while the image executed.' J1 O7 q* O6 X
  //2 O" u# A7 T# ?4 t) x
  CoreConnectHandlesByKey (HandleDatabaseKey);
7 p# u9 W1 E$ u6 j2 x4 x/ h8 ]
这里的HandleDatabaseKey是call image之前由CoreGetHandleDatabaseKey()得到的gHandleDatabaseKey
7 J- b% b0 b, e8 t3 p/ @, s而CoreConnectHandlesByKey会调用到:
: f% R' V2 ]9 p- u4 m  //
3 _2 r0 j  d1 `8 v. c; F1 r/ L  // Connect all handles whose Key value is greater than Key
1 d- ~7 h* X8 d* l/ F4 j  //
# o1 k6 {; @/ a0 e6 `. X  for (Index = 0; Index < Count; Index++) {
' w& X/ N* ]! [1 c- ?/ k2 G    CoreConnectController (HandleBuffer[Index], NULL, NULL, TRUE);
% l9 f5 w- j: U5 c& H  J5 i  ]  }
+ i. [* ?( w# f; ~
所以,照code看,当在Driver中安装一个Handle和Interface到Binding Protocol后(gHandleDatabaseKey会++,IHandle的Key=gHandleDatabaseKey)# Q9 F& S: b, J  {3 i
是会去ConnectController的,也会执行对应的Support()和Start()才对!!
  l) h8 k5 G$ U& O# E0 z$ V
4 k: n. t$ i: C" L4 X% y5 n3 w不知道我想的哪里有问题???欢迎大家指正.
) f% d* o. x1 o* _) I5 H. C& ?- w+ D  s2 i
[ 本帖最后由 xtdumpling 于 2008-9-18 15:25 编辑 ]
回复

使用道具 举报

发表于 2008-9-19 14:44:41 | 显示全部楼层
这段code似乎是一个向后兼容的行为,不必太care。
- z. y+ x: k5 X3 J% [9 e一个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 | 显示全部楼层
了解了.
( ?. C* P9 ?2 l1 j非常 感谢!!!
回复

使用道具 举报

发表于 2008-9-23 16:48:56 | 显示全部楼层
在读DXEmain时,, {. d7 T0 D! v  R7 g+ Z
Status = CoreInitializeImageServices(HobStart);--->CoreInstallProtocolInterface();--->CoreInstallProtocolInterfaceNotify();中,- y4 I- L  M  o8 E
//& p! ^& p; ^" O, ?
// Notify the notification list for this protocol.
* @# f5 [, T1 U" w; @7 I$ Y0 k//
7 L' e, P0 v' G  v- Y$ {3 Hif (Notify) {
* H- {# [0 L) Y' F, U  CoreNotifyProtocolEntry(ProtEntry);5 a7 M* u5 }/ l
}    里Signal了Event. MS是说一个handle安装了一个protocol后就signal一次.
  W- `2 \$ T$ {( Q有个问题请教一下大家: 这段是在DXE很靠前的位置执行的,但是在它之前我没有看到DXE中有相关的CreateEvent出现?哪位高手能说说这部分代码的流程呢?
回复

使用道具 举报

发表于 2008-9-23 17:04:14 | 显示全部楼层
原帖由 xtdumpling 于 2008-9-16 13:34 发表 " Q6 F+ Z6 Q- b
请楼上的兄弟分析下BS的RegisterProtocolNotify也就是CoreRegisterProtocolNotify是做什么用的?怎么用?2 J$ v9 y& ?! O# j
谢谢!
1 N, }* ]" |- z' y- r3 L
......
, @% Z+ w  r, W$ v; ^9 [+ G, f$ E2 u

0 v  a4 c( h8 |3 h; j[ 本帖最后由 xtdumpling 于 2008-9-23 17:24 编辑 ]
回复

使用道具 举报

发表于 2008-9-24 12:43:45 | 显示全部楼层
原帖由 xtdumpling 于 2008-9-23 17:04 发表 ( J3 h1 l/ E' Y- l

+ V2 B9 T0 ^- b9 k* S, H# r4 p......
. Z3 |0 x/ b7 b9 n1 D
% Z) J- Z; B8 r* V! U1 s3 h
Signal的Event是不是在各个TPL级上挂载一些待处理的事件,一旦restore(TPL)的话,比当前TPL级高的pending事件就回被处理掉?
9 h# w# [" z. O如果是这样的话,Timer事件是如何处理的呢,没有找到相关的代码呀?Xt指点一下再~
回复

使用道具 举报

发表于 2008-9-24 19:00:46 | 显示全部楼层
Timer是挂在8259的IRQ0的中断处理程序上面的, 大概每秒18.3次调用CoreTimerTick()-->CoreCheckTimers()# o; ^. [9 G) |. M# C4 n$ C
TPL=30
回复

使用道具 举报

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

本版积分规则

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

GMT+8, 2026-10-13 12:50 , Processed in 0.929985 second(s), 16 queries .

Powered by Discuz! X3.5

© 2001-2025 Discuz! Team.

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