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

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

[复制链接]
发表于 2008-7-27 00:11:28 | 显示全部楼层 |阅读模式
  最近在工作看到机台有启动过程中把SPI ROM数据清空,但苦与没有办法很好的Debug(PCA没有架起来),所有与EDK为对象好好的读了一把。
3 g5 `: Y( t2 ?% C2 O- s3 W: J! V1 N2 o9 w  s' ~
SEC/CEI:# Y# R4 d$ ^3 C  t6 z
  UEFI BIOS启动时先会执行SEC/CEI,这个阶段在实现的BIOS Code中初始化Debug Port,进入Big Mode,CPU的MicroCode,CacheToRAM的转换.然后跳转到PEI阶段。; t  X7 E) \! p2 X+ K, R
在EDK中这部分被成了Load FvRecovery.fd文件,这个文件类似与我们的BIOS ROM.里面是我们编译后生成的二进制代码。在这个阶段最主要的是将这个文件加载到内存中(Windows API将文件加载到内存,看API函数).
3 ?7 f' M/ E' ~/ `/ c. D" M5 S+ z) R# w6 K) U% I; V) l
PEI:% {/ ]/ \: l! l' ^
   从这里开始UEFI BIOS和EDK执行基本相同,只是一个是从SPI ROM中定位一个地址(PEIM的开始地址),一个是从内存中定位一个地址(PEIM的开始地址)。从这里开始只讲EDK的执行% h3 V6 ]2 i9 D& M0 H& v
  EDK调用InitializeMemoryService函数,将HobList清空,peiservice清空。" m" ^4 j+ T! y9 V, b! k
      InitializePPIService函数,将PPI队列清空,这个队列长0x3F.
0 s6 }+ n0 e( h3 |, F0 @6 G          InitializeSercurityService函数,将Notify队列清空。/ m( E* V5 Y7 c9 m
          InitializeDispatcherData函数,将Dispatcher队列清空。
7 V' ?" ^  z/ @2 a$ |0 j$ c6 v  接着由PeiBuildHobGuid来建立一个HOB(S3返回时这时应该有这个HOB,不用建立,直接使用了,这样就会进入另外一个流程,可以这个EDK不能调试S3,不知道怎么走)。然后由(*PeiServices)->InstallPpi()将这个新HOB加入到PPI中。' q+ v! d1 g9 O$ T6 ~( c2 [
    由于在SEC阶段转了以下这几具PPI,所以在执行PEI的Dispatcher之前会先安装东西:
3 M- ~' d1 o/ c1 ^      EFI_PEI_PPI_DESCRIPTOR    gPrivateDispatchTable[] = {
+ z5 I  D4 n5 [3 \       {EFI_PEI_PPI_DESCRIPTOR_PPI, &gEfiNtLoadAsDllPpiGuid, &mSecNtLoadAsDllPpi},
- J/ c( [4 T1 y) _7 a! x       {EFI_PEI_PPI_DESCRIPTOR_PPI, &gNtPeiLoadFileGuid, &mSecNtLoadFilePpi},
* p$ K, g/ r5 @" G7 b6 a       {EFI_PEI_PPI_DESCRIPTOR_PPI, &gPeiNtAutoScanPpiGuid, &mSecNtAutoScanPpi},6 X2 f4 I, S& L5 R' J: E- F
       {EFI_PEI_PPI_DESCRIPTOR_PPI, &gPeiNtThunkPpiGuid, &mSecWinNtThunkPpi},
/ J* a: r/ B& D       {EFI_PEI_PPI_DESCRIPTOR_PPI, &gPeiStatusCodePpiGuid, &mSecStatusCodePpi},
& s8 t5 I' ^0 Q1 J       {EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST, &gNtFwhPpiGuid, &mSecFwhInformationPpi}
8 T7 q$ E$ }1 r4 K2 V% I     };
' l7 l: W" A5 R5 G7 \    每个PPI是由{类型,GUID(名字,以后就根据这个来找到它的),Function_Entry_Address}组成。
0 x2 d3 c' i* X( }   这些PPI会在PEIDispatcher中用到。9 i5 q/ P  x. B. V6 }4 b
   安装完这此东西这开始执行PEIDispatcher函数,函数从BIOS ROM文件中找出PEI的Image(怎么找到,请读一下FV_HEAD(EFI_HEAD),里面讲到了如何区分Image类型),然后定位到PEI Image的入口地址,执行他。在我们的的PEI中,我们一般会申明一个PPI,这个就是这个PEI提供一些服务,PEIDispatcher会将他们加入到PPI-List中,以后其他Image也可以调用他的提供的功能。+ p. W$ _& ?* D
   最后EDK会加载一个叫DXEIPL的PEI,DXEIPL提供一个PPI服务,这个PPI的功能是实现从PEI到DXE的切换,这个PPI里面为DXE做了很多的预准备,加载了很多PPI,如对BIOS的解压方法等。
  T  i2 B+ |  C2 H. N$ U& p   SwitchStacks (
0 r  ]. Y$ O; h, z1 s       (VOID *) (UINTN) DxeCoreEntryPoint,
* j% N7 W/ m; l9 p8 w9 `  ?& t9 `       (UINTN) (HobList.Raw),/ z  J. ?3 n1 ^  v4 ?4 |
       (VOID *) (UINTN) TopOfStack," G2 Y# w) A' s
       (VOID *) (UINTN) BspStore
$ n  @2 N. N5 _. E" k5 e    );: B/ X# f7 ~6 T
  用过汇编的人对这个技术一定很熟悉,不多说了(我别不清,咯。。。)
( i" h6 d! K% g* y& w' [
. o4 W$ M' W% F  D! UDXE:# ?& l6 r* b: J9 d4 x  H% Q9 m
     从PEI到DXE切换时转过来一个HOBLIST参数,DXE会在这个HOB中找到Memory的使用情况,然后根据这些情况将BIOS引到内存(这是EFI的做法)。在EDK在DXE时重新定位一下内存。
( P: k4 @  f) S8 ]- b接着就会定义我们经常使用到的gST表,gRT表。接着是申明一些Protocol(先不关心这些事)。
* j, R3 ^, Z/ m" x8 o   等这些该加的PPI,Protocol加完了,CoreDispatcher()就出场了。他会的功能类似PEIDispatcher()。从我们BIOS ROM中将DXE的驱动读出,执行执行他们,这时会执行到Driver  b6 |* G4 ~( m& ?- @0 x. b
中的Support(),Start()两个功能函数。在这两个函数中你可以注册自己的PPI,为其他驱动提供服务。
5 G& n7 T8 [! ^7 M4 n( X2 T' Z   到些BIOS的引导其他完成。接着该进OS了,看Linux 0.11吧,操作系统是怎么做事情的。
7 V% C1 Y6 G& c" b   
: e2 N, i  Z1 l$ `$ v( g% k8 v6 q1 tDriver:
% q7 _. G8 N* J6 e3 y. L    我们的驱动什么为在PEI和DXE等不同阶段执行呢?
, ?: r) W4 E) ~  大家请看一下我们的驱动的makefile.(EDK中的*.inf)
3 Z9 C/ g) ]- e  [defines]2 s; Y2 E) ~  o: D
  BASE_NAME            = OWEN) o! I  R; _3 L+ |
  FILE_GUID            = 1EDD13C1-62EF-4262-A1AA-0040D08301103 {" {- C2 v& [  T; k
  COMPONENT_TYPE       = BS_DRIVER
' c' o# [7 q% V& T1 \% ?- n" y
) I2 f/ a$ H/ \* r% M: o' Y3 F  BASE_NAME告诉编译器最终生成的驱动的名字。
* O; m+ _3 C2 r5 A4 N  FILE_GUID就是这个驱动的GUID名字,在BIOS中引用某个驱动就是根据它来调用和识别。. A' N6 j/ s/ J( u% l
  COMONENT_TYPE会告诉编译器生成驱动的类型,是PEI,DXE,等。- r9 ]9 {6 Z# Z' j
  在EDK中有一个FWVolume.c实现的功能就是帮我们把这个TYPE转换面相应的扩展名' E9 y9 h( J# f  `: `  X, h
  COMP_TYPE_EXTENSION  mCompTypeExtension[] = {- D. v9 [$ e8 s/ ]  L0 {/ s
  {"bs_driver",  ".dxe" },
: v+ X) k7 O* k$ n1 Z, m! [3 e  {"rt_driver",  ".dxe" },, _' p4 ]2 ~& E/ z
  {"sal_rt_driver", ".dxe"},3 k3 z  p! ?. V1 E
  {"security_core", ".sec"},
0 `8 x# ~0 R& f) k( R# Q6 A  {"pei_core", ".pei"},8 `  `/ K# ^# E
  {"pic_peim", ".pei"},0 L. q1 ~6 ]) _6 r- [4 v
  {"pe32_peim", ".pei"},
% o; |" M4 d% K; g4 [  {"relocatable_peim", ".pei"},9 z; C1 c) G$ V( }
  {"binary", ".ffs"},
* v! V4 ~2 c- d, L* _: H: S, y  {"application", ".app"},
% h' P- P5 p, G4 D5 _" N  {"file", ".ffs"},
/ y4 z- K; }* s5 p+ t) x% G2 k  {"fvimagefile", ".fvi"},
9 t1 z- M4 O+ F* o3 x5 [  {"rawfile", ".raw"},0 Y( p- G9 x: ^' r4 S7 e! |. G
  {"apriori", ".ffs"},) h! {, G! E5 z; Y- d: c% a
  {"combined_peim_driver", ".pei"},
9 C2 [9 M9 W/ @; N2 B  { NULL,  NULL }
, F1 M- ^0 d5 [  N/ H8 |  b: `5 ]) t};. H) P, M0 ]0 `/ e" |

- T/ S; N7 y- I2 j6 E了解了这些,接下我们可以看驱动篇了。(Go On Study... Forever)
$ t3 g7 W: J2 u" Z, t+ J/ P   5 M6 \; s' q6 c3 b
         * a" A2 E9 E- k( X" {
  
发表于 2008-7-27 12:30:15 | 显示全部楼层
不错!( u0 x( e5 H9 ?5 ~2 M
支持' r0 B+ V; ?9 p! T
继续4 v" O4 e) }; p: |  t" }5 b
加油1 X3 K0 e0 H$ L' X
回复

使用道具 举报

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

回复 1# 的帖子

gPrivateDispatchTable 和COMP_TYPE_EXTENSION  没有搜到啊  是EDK专有的么?7 O1 R* T* K* }5 N: ]
有看过跟gPrivateDispatchTable 类似的,但是里面的PPI不同。
' n2 v* L) c9 Y8 H$ U还有这个COMP_TYPE_EXTENSION  没有找到过。FWVolume.c这个文件也没有发现。。
回复

使用道具 举报

发表于 2008-7-28 13:24:20 | 显示全部楼层
这东西虽说没有什么技术含量,但是总结一下还是非常好的。5 P% T. j1 b% S) Y" F, X3 }

6 O; A8 t0 K) y! @+ l支持!
回复

使用道具 举报

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

  D% T/ X- h8 R, e小弟还在学习阶段,目前的目标是知道执行的流程。
* {. @5 r$ Q5 W3 U! x' r这里面有很多细节没有写,能力有限,只能自己知道,不能表达。
; A8 n9 o2 a& q/ m' B! S$ n嘿。。。。
/ }2 l% O: P3 _% H7 T  v所有大侠们如果有好东西能给小弟共享一份。# A2 O! E/ T- z& S( d  {- G6 y

# T% Y; Z$ O( ?- S" ~谢谢!
回复

使用道具 举报

发表于 2008-8-12 14:44:11 | 显示全部楼层
原帖由 winbondowen 于 2008-7-27 00:11 发表
$ V+ {4 e! }0 n& {  ROM中將DXE的驅動讀出,執行執行他們,這時會執行到Driver3 S  i2 [/ U' ~  D9 {
中的Support(),Start()兩個功能函數。在這兩個函數中你可以註冊自己的PPI ...
9 T5 o, J- t' U& p3 e5 u9 _. @

2 S8 n8 `6 [" H3 c" ?+ T8 [% A) r* SPPIs are registered during PEI phase, but Support()/Start() are invoked in DXE driver binding protocol,
' m* ?5 B+ P6 b4 H3 M2 U4 o* ]For more precisely, I think the "PPI" you mentioned is the "PROTOCOL" rather than "PPI".% v$ N4 ], `/ V4 f* A
( h( N3 B: s0 O6 ^! A6 X' S- q7 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:1 v3 }+ x0 B7 ?
   Yes. I make a mistake.
: @/ C% s/ u( r6 s* i. V# O0 p      PPI:     A PEIM to PEIM interface.
/ c2 z+ J; P: k/ m4 F      PROTOCL: A Interface between Hardware(or firmware) and software.4 V7 h* u5 ?0 W5 q! z
      reference[http://www.biosren.com/viewthread.php?tid=207]9 S0 \. _5 r5 E
   so, PPI execute at PEI step and Initialize hardware. PROTOCOL execute by DXE step.
' z+ K) b& j  o, U; s0 n: J   Thanks.
回复

使用道具 举报

发表于 2008-8-20 17:47:21 | 显示全部楼层
原帖由 winbondowen 于 2008-7-27 00:11 发表 DXE:
, a/ r! N. u+ ~8 B& A$ Q) E     從PEI到DXE切換時轉過來一個HOBLIST參數,DXE會在這個HOB中找到Memory的使用情況,然後根據這些情況將BIOS引到內存(這是EFI的做法)。在EDK在DXE時重新定位一下內存。8 D! }+ W6 C6 i6 I) f% B
接著就會定義我們經常使用到的gST表,gRT表。接著是申明一些Protocol(先不關心這些事)。
( S! ?  L5 v6 Y0 w, I   等這些該加的PPI,Protocol加完了,CoreDispatcher()就出場了。他會的功能類似PEIDispatcher()。從我們BIOS ROM中將DXE的驅動讀出,執行執行他們,這時會執行到Driver! p# i1 f9 E, t/ c, g
中的Support(),Start()兩個功能函數。在這兩個函數中你可以註冊自己的PPI,為其他驅動提供服務。0 |# e( X$ K5 e+ _( F
   到些BIOS的引導其他完成。接著該進OS了,看Linux 0.11吧,操作系統是怎麼做事情的。.

8 h/ F- }% \" C, `1 L+ `
; x" M' p* z1 u0 v9 E! |$ `There are mistakes,
3 w! ]/ W8 D& H. `0 L9 V1.gST and gRT are init after the DXE architectural protocols have been loaded, those protocols response for creating Dxe foundation.7 z; |3 E8 A; u  I& X

. I6 {4 Y9 X$ M) L# i2.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.
5 I& I( r$ P" k0 R3 ~7 l9 NThe CoreDispatcher() executes all trusted Dxe drivers and just register the Binding protocol if the driver is EFI1.1 driver model.
: f0 L. ?' F; [$ xFurthermore, Support()/Start() are invoked in BDS phase over the CoreConnectController() rather than CoreDispatcher().! b+ c! P5 A" |5 Q+ {' v) S3 O

8 t/ N$ a1 |* `- U2 JBTW, 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 大侠的指点。
; o) v9 T! V; y" C$ M. E
回复

使用道具 举报

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

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

原帖由 ichirohiro 于 2008-8-20 17:47 发表
* u7 A& o" o* ^# ?...
) W5 u! x/ A# |/ 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.
. K6 ~- H+ b* [% ?4 P8 E8 c4 rThe CoreDispatcher() executes all trusted Dxe drivers and just register the Binding protocol if the driver is EFI1.1 driver model.
( p* k3 x: `2 x" u4 E. C7 E! bFurthermore, Support()/Start() are invoked in BDS phase over the CoreConnectController() rather than CoreDispatcher().

7 `8 ?) I( u7 M; c, B) M    在Framework的spec DxeCis.pdf里面也是这么说的,DXE CoreDispatcher()里面,对于EFI1.1 driver model的driver只会安装Handler和Interface到Binding protocol,到BDS才会去执行Support()和Start().
- d' M9 u+ X$ A) ~) Q    但是,我在看code时,发现在CoreDispatcher()-->CoreStartImage()里面call image之后有这么一句:  (file:image.c)
# D. n' n" B* h$ Y" c  //1 x* R5 ^& F/ E2 i3 f
  // Go connect any handles that were created or modified while the image executed.
. O( R) i$ V/ n# r. o, l/ W  //
2 h. [* ?+ p- y5 V7 d  CoreConnectHandlesByKey (HandleDatabaseKey);
* R, x( a' ], K( b4 {, P
这里的HandleDatabaseKey是call image之前由CoreGetHandleDatabaseKey()得到的gHandleDatabaseKey4 W' b9 u$ C0 y( j5 A8 z
而CoreConnectHandlesByKey会调用到:: l' C/ }! N* c! e
  //
5 a( z9 Q+ ~" P2 R  // Connect all handles whose Key value is greater than Key
  K5 ?  i* k3 L6 E' z( `! n  //! [! z; w" r2 @5 M; \+ f' {- d
  for (Index = 0; Index < Count; Index++) {! t9 h; ]' G( F4 |% B9 q2 Q% ^3 T
    CoreConnectController (HandleBuffer[Index], NULL, NULL, TRUE);
. h; z1 W4 O  b" `) S: n  }

' O! i, Y' Z/ ~* n所以,照code看,当在Driver中安装一个Handle和Interface到Binding Protocol后(gHandleDatabaseKey会++,IHandle的Key=gHandleDatabaseKey)
7 n" c; E% X+ D3 V. m6 p# H7 v7 @, W是会去ConnectController的,也会执行对应的Support()和Start()才对!!
* Z% O0 f$ ~+ H7 h) F1 i" {7 _5 x7 B( }: [* @
不知道我想的哪里有问题???欢迎大家指正.! `" u( N4 I9 d$ y. G0 a1 q

$ X! H) Z# {! m( f1 C[ 本帖最后由 xtdumpling 于 2008-9-18 15:25 编辑 ]
回复

使用道具 举报

发表于 2008-9-19 14:44:41 | 显示全部楼层
这段code似乎是一个向后兼容的行为,不必太care。
" v% y. x) h* g9 f8 Y0 n一个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 | 显示全部楼层
了解了.6 v( \1 G. v& i) E6 H2 G8 N  s
非常 感谢!!!
回复

使用道具 举报

发表于 2008-9-23 16:48:56 | 显示全部楼层
在读DXEmain时,
5 [* Y8 \' h7 W# T8 \% w" A& r$ XStatus = CoreInitializeImageServices(HobStart);--->CoreInstallProtocolInterface();--->CoreInstallProtocolInterfaceNotify();中,) s' h( E+ b( o; r1 V) q/ o6 N
//3 o/ }8 v$ l8 |. F
// Notify the notification list for this protocol.
$ l* W: u% t8 R% h1 G0 L//
2 g+ ^8 A- v2 I3 nif (Notify) {0 h" o  p3 O) L# n
  CoreNotifyProtocolEntry(ProtEntry);
1 B" z+ `! V) d# R# O}    里Signal了Event. MS是说一个handle安装了一个protocol后就signal一次.
; q+ S. e  r3 Q) V5 T( b& Z有个问题请教一下大家: 这段是在DXE很靠前的位置执行的,但是在它之前我没有看到DXE中有相关的CreateEvent出现?哪位高手能说说这部分代码的流程呢?
回复

使用道具 举报

发表于 2008-9-23 17:04:14 | 显示全部楼层
原帖由 xtdumpling 于 2008-9-16 13:34 发表
  X' ~. ]3 `+ S; y- d- f2 D) S! V' l5 B请楼上的兄弟分析下BS的RegisterProtocolNotify也就是CoreRegisterProtocolNotify是做什么用的?怎么用?, v+ h4 n6 C9 O+ @$ a$ k" r' n
谢谢!

! B' k0 k4 v  \......+ ?$ J( Q; ^& t2 x- z3 `
3 N+ X0 c" ~4 }2 P* W' O

* l2 o8 L% o! u2 L! o  H[ 本帖最后由 xtdumpling 于 2008-9-23 17:24 编辑 ]
回复

使用道具 举报

发表于 2008-9-24 12:43:45 | 显示全部楼层
原帖由 xtdumpling 于 2008-9-23 17:04 发表
: C( g8 ~: D8 p$ e5 C. ^! X7 Z% n: |% K+ @4 G! w4 R3 {$ h' c
......3 o0 s  Z8 `- n- h' w; H

1 Z7 F+ \  E# j+ h" S4 VSignal的Event是不是在各个TPL级上挂载一些待处理的事件,一旦restore(TPL)的话,比当前TPL级高的pending事件就回被处理掉?. a' q  @) [1 Y
如果是这样的话,Timer事件是如何处理的呢,没有找到相关的代码呀?Xt指点一下再~
回复

使用道具 举报

发表于 2008-9-24 19:00:46 | 显示全部楼层
Timer是挂在8259的IRQ0的中断处理程序上面的, 大概每秒18.3次调用CoreTimerTick()-->CoreCheckTimers()
: {( ]+ `2 F; H) }6 ]" V, [TPL=30
回复

使用道具 举报

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

本版积分规则

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

GMT+8, 2026-6-4 19:09 , Processed in 0.303798 second(s), 17 queries .

Powered by Discuz! X3.5

© 2001-2025 Discuz! Team.

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