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

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

[复制链接]
发表于 2008-7-27 00:11:28 | 显示全部楼层 |阅读模式
  最近在工作看到机台有启动过程中把SPI ROM数据清空,但苦与没有办法很好的Debug(PCA没有架起来),所有与EDK为对象好好的读了一把。: P7 Y3 \6 O+ A5 O2 y
. d& H4 q5 z9 I
SEC/CEI:
- F+ H) |! [1 H" B+ t- I/ k7 n& h  UEFI BIOS启动时先会执行SEC/CEI,这个阶段在实现的BIOS Code中初始化Debug Port,进入Big Mode,CPU的MicroCode,CacheToRAM的转换.然后跳转到PEI阶段。$ E/ F  d! k. z- [3 C2 i) ^/ T
在EDK中这部分被成了Load FvRecovery.fd文件,这个文件类似与我们的BIOS ROM.里面是我们编译后生成的二进制代码。在这个阶段最主要的是将这个文件加载到内存中(Windows API将文件加载到内存,看API函数)./ G, E/ r+ y+ H, q( N/ A7 h( ~+ I

9 ]+ w8 x( e: I2 ?3 ?& PPEI:" F4 n" s% z2 N7 d
   从这里开始UEFI BIOS和EDK执行基本相同,只是一个是从SPI ROM中定位一个地址(PEIM的开始地址),一个是从内存中定位一个地址(PEIM的开始地址)。从这里开始只讲EDK的执行
2 }7 A0 E/ |/ I$ B0 |: U. U  EDK调用InitializeMemoryService函数,将HobList清空,peiservice清空。
9 ~+ |5 m- k" i      InitializePPIService函数,将PPI队列清空,这个队列长0x3F.# F  a) k/ k4 u
          InitializeSercurityService函数,将Notify队列清空。9 V1 d$ c9 G& V5 E
          InitializeDispatcherData函数,将Dispatcher队列清空。
! t9 m4 G( @+ c" ~" r$ R  接着由PeiBuildHobGuid来建立一个HOB(S3返回时这时应该有这个HOB,不用建立,直接使用了,这样就会进入另外一个流程,可以这个EDK不能调试S3,不知道怎么走)。然后由(*PeiServices)->InstallPpi()将这个新HOB加入到PPI中。4 @. B! x% |  k. X' o9 |
    由于在SEC阶段转了以下这几具PPI,所以在执行PEI的Dispatcher之前会先安装东西:
! i' ^# E3 x6 S1 e" C5 X2 V      EFI_PEI_PPI_DESCRIPTOR    gPrivateDispatchTable[] = {
2 Q* b! V6 u5 i' @: F) M5 l; \/ n3 M       {EFI_PEI_PPI_DESCRIPTOR_PPI, &gEfiNtLoadAsDllPpiGuid, &mSecNtLoadAsDllPpi},
- y. @- \2 m% a2 i0 S; w6 N* N       {EFI_PEI_PPI_DESCRIPTOR_PPI, &gNtPeiLoadFileGuid, &mSecNtLoadFilePpi},
+ F  L$ _" v( g5 I7 j, h( @# J       {EFI_PEI_PPI_DESCRIPTOR_PPI, &gPeiNtAutoScanPpiGuid, &mSecNtAutoScanPpi},1 |: i  Z- Q; l: P7 _- R4 s* h4 M
       {EFI_PEI_PPI_DESCRIPTOR_PPI, &gPeiNtThunkPpiGuid, &mSecWinNtThunkPpi},
" _) K. L7 x( E, y# Y% G3 p+ M3 a       {EFI_PEI_PPI_DESCRIPTOR_PPI, &gPeiStatusCodePpiGuid, &mSecStatusCodePpi},/ X( Z5 T6 \& E7 e
       {EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST, &gNtFwhPpiGuid, &mSecFwhInformationPpi}
" J7 W! q/ Q8 E# N  P, ^     };4 f7 y& T8 K1 x. J! X% J# f
    每个PPI是由{类型,GUID(名字,以后就根据这个来找到它的),Function_Entry_Address}组成。1 i- I# R7 A: e5 f
   这些PPI会在PEIDispatcher中用到。5 f1 ~, d% C' w& F+ R
   安装完这此东西这开始执行PEIDispatcher函数,函数从BIOS ROM文件中找出PEI的Image(怎么找到,请读一下FV_HEAD(EFI_HEAD),里面讲到了如何区分Image类型),然后定位到PEI Image的入口地址,执行他。在我们的的PEI中,我们一般会申明一个PPI,这个就是这个PEI提供一些服务,PEIDispatcher会将他们加入到PPI-List中,以后其他Image也可以调用他的提供的功能。" y4 X1 [" p9 R6 m8 S1 U
   最后EDK会加载一个叫DXEIPL的PEI,DXEIPL提供一个PPI服务,这个PPI的功能是实现从PEI到DXE的切换,这个PPI里面为DXE做了很多的预准备,加载了很多PPI,如对BIOS的解压方法等。3 G* y% \0 J2 }( S' R) ^
   SwitchStacks (8 K" Z6 r: l5 ?/ H6 [1 R3 w
       (VOID *) (UINTN) DxeCoreEntryPoint,4 j' j' o; [: [
       (UINTN) (HobList.Raw),; @  e; }+ w0 H3 e1 f8 E
       (VOID *) (UINTN) TopOfStack,5 y1 s3 E1 V; U# s( n. S
       (VOID *) (UINTN) BspStore
" X; g- a4 \7 V, A    );
( ?( ]9 Q& c- L( f; {4 C  用过汇编的人对这个技术一定很熟悉,不多说了(我别不清,咯。。。)% T) |. i6 e" f! T8 G& z
; [2 t; G2 ?& x  r7 B- y
DXE:7 y! }" o' W+ [2 x6 I& A4 W
     从PEI到DXE切换时转过来一个HOBLIST参数,DXE会在这个HOB中找到Memory的使用情况,然后根据这些情况将BIOS引到内存(这是EFI的做法)。在EDK在DXE时重新定位一下内存。8 N4 N3 G* f' m
接着就会定义我们经常使用到的gST表,gRT表。接着是申明一些Protocol(先不关心这些事)。
9 S7 W) _7 N/ N5 v, Q   等这些该加的PPI,Protocol加完了,CoreDispatcher()就出场了。他会的功能类似PEIDispatcher()。从我们BIOS ROM中将DXE的驱动读出,执行执行他们,这时会执行到Driver) X# O4 M! P" C! b' V; F
中的Support(),Start()两个功能函数。在这两个函数中你可以注册自己的PPI,为其他驱动提供服务。
1 V& }" T( W9 g; q6 H   到些BIOS的引导其他完成。接着该进OS了,看Linux 0.11吧,操作系统是怎么做事情的。
0 I0 V- r  w) d# R% E/ f9 z   $ f8 N5 e! Q3 O4 |  P% {- Q+ l
Driver:
5 p- b! E( _5 N4 ^* ]4 c7 Q! m( s    我们的驱动什么为在PEI和DXE等不同阶段执行呢?
9 O+ W2 c/ y' H6 m5 `/ F  大家请看一下我们的驱动的makefile.(EDK中的*.inf)
) c' h7 L; P2 `* g  [defines]
5 S  T5 ?3 `: M" y% b  BASE_NAME            = OWEN
% e1 Y1 X2 D9 w$ O* R/ a  FILE_GUID            = 1EDD13C1-62EF-4262-A1AA-0040D0830110
' X, r3 r; ^( y5 M1 T- o9 }2 {1 f  COMPONENT_TYPE       = BS_DRIVER
) Z4 O+ `6 @8 V$ o6 y
3 X6 b/ f% `6 v4 q. u0 P  BASE_NAME告诉编译器最终生成的驱动的名字。+ N6 F! K: a! s: g* k1 K* R
  FILE_GUID就是这个驱动的GUID名字,在BIOS中引用某个驱动就是根据它来调用和识别。
+ [0 m/ e4 b2 O$ O! Z3 N  COMONENT_TYPE会告诉编译器生成驱动的类型,是PEI,DXE,等。) x0 ^- ]* ]6 u& R. b
  在EDK中有一个FWVolume.c实现的功能就是帮我们把这个TYPE转换面相应的扩展名& m$ ~  j- S$ d. m* w( [- V7 Q
  COMP_TYPE_EXTENSION  mCompTypeExtension[] = {
& l3 E) F$ f, |" C7 Q  {"bs_driver",  ".dxe" },, j( \% K7 }  l2 z$ Q* d
  {"rt_driver",  ".dxe" },  A$ h! P4 ]* B
  {"sal_rt_driver", ".dxe"},
& h' F! @3 o+ C  g5 L  {"security_core", ".sec"},
' G5 S# k0 G- \; \% \: c! g  {"pei_core", ".pei"},
7 i; @2 ~# ~" H7 U* ^1 T5 b2 J  {"pic_peim", ".pei"},+ W1 [/ F" o! n
  {"pe32_peim", ".pei"},
; `1 N( g# Y6 X2 Y0 W, t  {"relocatable_peim", ".pei"},0 U) V- v" {( d6 C- d# o/ E
  {"binary", ".ffs"},, p; `; u3 A! d/ n* K" c2 V+ \1 d
  {"application", ".app"},
  F. {( b4 Z) @" S  {"file", ".ffs"},
4 z3 C( k. H3 P7 Q: x3 U* H; N  {"fvimagefile", ".fvi"},
, l1 {' u3 p  L& B6 E  {"rawfile", ".raw"},
  A' T9 a/ p8 F' d  {"apriori", ".ffs"},2 \0 [  L. n6 y( p
  {"combined_peim_driver", ".pei"},
$ N1 Z0 {* b  s  { NULL,  NULL }8 c- p: Q+ D: v9 ~1 E9 g" k
};2 [/ i3 J7 v1 y- s; p; e( m3 P

5 y4 ]9 q# U9 ?. N% Z/ N了解了这些,接下我们可以看驱动篇了。(Go On Study... Forever)
6 o. p* B! f( x, U% [* |, w   
1 y7 g; _4 z* l& S4 x) D: l         ) |9 F3 X3 W3 t2 R
  
发表于 2008-7-27 12:30:15 | 显示全部楼层
不错!% \* H/ n1 }$ |/ Z
支持! F! C( B0 l. F' ~: _, k" D
继续" z8 v, o% b0 b  h
加油( D5 `) B( Q, v1 o0 P' @4 s
回复

使用道具 举报

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

回复 1# 的帖子

gPrivateDispatchTable 和COMP_TYPE_EXTENSION  没有搜到啊  是EDK专有的么?
3 B8 r# F8 Y4 z+ \3 N有看过跟gPrivateDispatchTable 类似的,但是里面的PPI不同。
& P7 Y0 m5 h; i* V4 p4 `5 i0 W还有这个COMP_TYPE_EXTENSION  没有找到过。FWVolume.c这个文件也没有发现。。
回复

使用道具 举报

发表于 2008-7-28 13:24:20 | 显示全部楼层
这东西虽说没有什么技术含量,但是总结一下还是非常好的。+ a; e) o+ c& W
  z1 O. Y& [# m9 h
支持!
回复

使用道具 举报

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

9 q( ^1 d6 @- Z5 d% o' J小弟还在学习阶段,目前的目标是知道执行的流程。
! ^3 Y9 J$ V0 q' Y, u1 D# O这里面有很多细节没有写,能力有限,只能自己知道,不能表达。7 \( u6 x( K4 ~- H5 ~7 [
嘿。。。。
4 \/ x2 ^# `8 y$ s所有大侠们如果有好东西能给小弟共享一份。
5 {# s9 m, h8 D  {
- Q$ {: _7 |6 O0 p0 j1 G谢谢!
回复

使用道具 举报

发表于 2008-8-12 14:44:11 | 显示全部楼层
原帖由 winbondowen 于 2008-7-27 00:11 发表
* _4 D! o% A0 R  ROM中將DXE的驅動讀出,執行執行他們,這時會執行到Driver4 B0 [- D7 G+ E% }$ U
中的Support(),Start()兩個功能函數。在這兩個函數中你可以註冊自己的PPI ...

) _! v7 Y" k1 n# |0 r. n1 ^2 ?! o$ ~
PPIs are registered during PEI phase, but Support()/Start() are invoked in DXE driver binding protocol, 0 ?, C8 [. [9 W7 G. X9 B
For more precisely, I think the "PPI" you mentioned is the "PROTOCOL" rather than "PPI".
( w* q- V3 ~# q+ g4 Q/ X' j
, W/ t* p" r  [0 c/ f) Z& v[ 本帖最后由 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:, }' g2 z) Y5 P* m( U- t4 ~, y
   Yes. I make a mistake." @# C) D" \' s- b; c* `  U
      PPI:     A PEIM to PEIM interface." P' U( j7 G# G
      PROTOCL: A Interface between Hardware(or firmware) and software., Q  o2 C/ {+ T% W& V* M
      reference[http://www.biosren.com/viewthread.php?tid=207]* a2 k" n6 X4 \5 T9 @; p
   so, PPI execute at PEI step and Initialize hardware. PROTOCOL execute by DXE step.* t9 w' C! ?! T" V! [
   Thanks.
回复

使用道具 举报

发表于 2008-8-20 17:47:21 | 显示全部楼层
原帖由 winbondowen 于 2008-7-27 00:11 发表 DXE:: Y6 ^5 t8 n# n$ V
     從PEI到DXE切換時轉過來一個HOBLIST參數,DXE會在這個HOB中找到Memory的使用情況,然後根據這些情況將BIOS引到內存(這是EFI的做法)。在EDK在DXE時重新定位一下內存。
$ D# d  t2 q- I- _  E) q  O接著就會定義我們經常使用到的gST表,gRT表。接著是申明一些Protocol(先不關心這些事)。2 G+ u# M% Y1 P  k8 B" K8 L
   等這些該加的PPI,Protocol加完了,CoreDispatcher()就出場了。他會的功能類似PEIDispatcher()。從我們BIOS ROM中將DXE的驅動讀出,執行執行他們,這時會執行到Driver
4 H, S- I7 v+ k3 T6 m) \5 A. C. O中的Support(),Start()兩個功能函數。在這兩個函數中你可以註冊自己的PPI,為其他驅動提供服務。
& n; Q3 G+ v5 {6 J3 j   到些BIOS的引導其他完成。接著該進OS了,看Linux 0.11吧,操作系統是怎麼做事情的。.

8 M% z( \8 z# J% W* M
) D% U4 u$ O' JThere are mistakes,8 W: V! Z4 a! s7 S- m. B
1.gST and gRT are init after the DXE architectural protocols have been loaded, those protocols response for creating Dxe foundation.+ o2 A2 ~  G/ {+ p* j, Q

( Y& s) u) P. @# w, w, Q8 T& R2.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.
% ~" A$ L7 _. ?# C0 b. fThe CoreDispatcher() executes all trusted Dxe drivers and just register the Binding protocol if the driver is EFI1.1 driver model.
! \' B9 u% D7 E  m- |9 @Furthermore, Support()/Start() are invoked in BDS phase over the CoreConnectController() rather than CoreDispatcher().
: l+ o6 q" Y! \  Z  C3 b, w8 T6 q" H% P- D( [/ s4 D
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 大侠的指点。
/ s# P- M3 W; C6 G8 c  P
回复

使用道具 举报

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

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

原帖由 ichirohiro 于 2008-8-20 17:47 发表
) i- G) r% c" K3 E  R...+ ?4 ~" G3 p1 J+ l
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 l. V0 W, ~, b; F0 o5 }
The CoreDispatcher() executes all trusted Dxe drivers and just register the Binding protocol if the driver is EFI1.1 driver model.
! q  O0 G3 s1 f; i" z4 QFurthermore, Support()/Start() are invoked in BDS phase over the CoreConnectController() rather than CoreDispatcher().
8 o! ~: u) v0 `1 e- f
    在Framework的spec DxeCis.pdf里面也是这么说的,DXE CoreDispatcher()里面,对于EFI1.1 driver model的driver只会安装Handler和Interface到Binding protocol,到BDS才会去执行Support()和Start().) z. y9 ~" z6 Q; F
    但是,我在看code时,发现在CoreDispatcher()-->CoreStartImage()里面call image之后有这么一句:  (file:image.c)
3 I( A5 h* [! m& h  //
. r( J* C, M% L% E0 r" B' l  // Go connect any handles that were created or modified while the image executed.  h/ G* Q4 x7 q; N! J1 n3 {2 @
  //! l4 X# w3 K8 Y0 j2 s2 D0 D
  CoreConnectHandlesByKey (HandleDatabaseKey);
+ p- M) K2 M, T1 m: Y* l0 K
这里的HandleDatabaseKey是call image之前由CoreGetHandleDatabaseKey()得到的gHandleDatabaseKey
0 @8 k& C! z, @0 a/ @" O7 p而CoreConnectHandlesByKey会调用到:6 u& D* j' S' Q, `' i* e6 t
  //
' W: N( w3 n$ m3 B$ N5 j  // Connect all handles whose Key value is greater than Key
+ x3 F, H! }" h- g8 ^  //
9 o, ?; @/ I- v6 Z* d  for (Index = 0; Index < Count; Index++) {5 Z( s& X* G3 Q9 }6 K
    CoreConnectController (HandleBuffer[Index], NULL, NULL, TRUE);+ G! r5 R$ E3 B8 O6 H: v
  }

: Q" c* q" V1 b7 S$ X% k$ F5 |所以,照code看,当在Driver中安装一个Handle和Interface到Binding Protocol后(gHandleDatabaseKey会++,IHandle的Key=gHandleDatabaseKey)
( Y0 ?6 a. e, K是会去ConnectController的,也会执行对应的Support()和Start()才对!!
& X! H; n, Y* j2 A5 _, b8 I
: M2 t9 W# G2 d) y不知道我想的哪里有问题???欢迎大家指正.
( J# v$ U6 n+ v& l$ l8 ^5 a$ Q6 ]" R' u& k6 O. u/ g" A
[ 本帖最后由 xtdumpling 于 2008-9-18 15:25 编辑 ]
回复

使用道具 举报

发表于 2008-9-19 14:44:41 | 显示全部楼层
这段code似乎是一个向后兼容的行为,不必太care。
3 ~$ L! S( y2 [0 y一个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 | 显示全部楼层
了解了.
  u& [2 r: [& t8 f非常 感谢!!!
回复

使用道具 举报

发表于 2008-9-23 16:48:56 | 显示全部楼层
在读DXEmain时,
" J1 _# k' h! g' u7 I, {% ZStatus = CoreInitializeImageServices(HobStart);--->CoreInstallProtocolInterface();--->CoreInstallProtocolInterfaceNotify();中,4 P0 ^9 m0 O9 S& V# N% o  F. G
//
  f. j' G. ^7 Z& ~, i$ Z// Notify the notification list for this protocol.6 S9 F' `& T* s% k) o
//
, o3 n! J1 _+ G% P* U& I9 R, q& Z! K1 pif (Notify) {+ Z9 m4 V% E& K- f
  CoreNotifyProtocolEntry(ProtEntry);$ l: D1 m! o: B* f; Q
}    里Signal了Event. MS是说一个handle安装了一个protocol后就signal一次.
2 c+ b6 n; A& |: Z% F0 D有个问题请教一下大家: 这段是在DXE很靠前的位置执行的,但是在它之前我没有看到DXE中有相关的CreateEvent出现?哪位高手能说说这部分代码的流程呢?
回复

使用道具 举报

发表于 2008-9-23 17:04:14 | 显示全部楼层
原帖由 xtdumpling 于 2008-9-16 13:34 发表 " G2 q+ O) W8 k) b
请楼上的兄弟分析下BS的RegisterProtocolNotify也就是CoreRegisterProtocolNotify是做什么用的?怎么用?
$ L2 g  Z# ]8 w$ `谢谢!
. X6 ^5 P3 z$ P+ m$ c
......8 N2 n' d$ L7 I$ C. g6 \

- U" i# }/ i. b4 R; ?% [) x4 ?3 l6 C9 ]: c9 q
[ 本帖最后由 xtdumpling 于 2008-9-23 17:24 编辑 ]
回复

使用道具 举报

发表于 2008-9-24 12:43:45 | 显示全部楼层
原帖由 xtdumpling 于 2008-9-23 17:04 发表
3 ~  z4 ]' \+ F1 z3 ^6 O* f& ^2 |4 |% u8 R8 w7 Y
......
- L1 X2 E2 K9 f# x- @5 V
* }# {( f$ {1 {
Signal的Event是不是在各个TPL级上挂载一些待处理的事件,一旦restore(TPL)的话,比当前TPL级高的pending事件就回被处理掉?
3 J! `, v3 h) h$ }& u6 b) s* C- j  j如果是这样的话,Timer事件是如何处理的呢,没有找到相关的代码呀?Xt指点一下再~
回复

使用道具 举报

发表于 2008-9-24 19:00:46 | 显示全部楼层
Timer是挂在8259的IRQ0的中断处理程序上面的, 大概每秒18.3次调用CoreTimerTick()-->CoreCheckTimers(); `- X: p: [+ V3 R% K7 \2 p
TPL=30
回复

使用道具 举报

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

本版积分规则

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

GMT+8, 2025-12-1 02:17 , Processed in 0.308603 second(s), 17 queries .

Powered by Discuz! X3.5

© 2001-2025 Discuz! Team.

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