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

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

[复制链接]
发表于 2008-7-27 00:11:28 | 显示全部楼层 |阅读模式
  最近在工作看到机台有启动过程中把SPI ROM数据清空,但苦与没有办法很好的Debug(PCA没有架起来),所有与EDK为对象好好的读了一把。* E1 G9 [& h7 p5 W) v3 S

; i5 y$ Z" v( \* l2 o( W& TSEC/CEI:; g% a/ M- o+ Q* y  S* X8 e
  UEFI BIOS启动时先会执行SEC/CEI,这个阶段在实现的BIOS Code中初始化Debug Port,进入Big Mode,CPU的MicroCode,CacheToRAM的转换.然后跳转到PEI阶段。
- \9 x$ |1 X) M( X在EDK中这部分被成了Load FvRecovery.fd文件,这个文件类似与我们的BIOS ROM.里面是我们编译后生成的二进制代码。在这个阶段最主要的是将这个文件加载到内存中(Windows API将文件加载到内存,看API函数).- w1 w+ w$ o- \3 b" n/ N

) o5 i5 ^7 w! U4 Y: E' o: c: BPEI:
9 M9 O# b4 v+ o3 N* w2 u   从这里开始UEFI BIOS和EDK执行基本相同,只是一个是从SPI ROM中定位一个地址(PEIM的开始地址),一个是从内存中定位一个地址(PEIM的开始地址)。从这里开始只讲EDK的执行
: r+ y6 w( o5 P) N) [* x  EDK调用InitializeMemoryService函数,将HobList清空,peiservice清空。
1 y' H; ?2 f& X& h7 ~+ O% z      InitializePPIService函数,将PPI队列清空,这个队列长0x3F.
2 f9 F7 V9 H' X          InitializeSercurityService函数,将Notify队列清空。. c9 A9 B7 Z& x- {
          InitializeDispatcherData函数,将Dispatcher队列清空。3 m* G1 L) @' j. G0 P# _8 l6 K
  接着由PeiBuildHobGuid来建立一个HOB(S3返回时这时应该有这个HOB,不用建立,直接使用了,这样就会进入另外一个流程,可以这个EDK不能调试S3,不知道怎么走)。然后由(*PeiServices)->InstallPpi()将这个新HOB加入到PPI中。
4 N7 _8 x, {' F5 B4 a- m    由于在SEC阶段转了以下这几具PPI,所以在执行PEI的Dispatcher之前会先安装东西:$ O0 `1 S, H* Q( W
      EFI_PEI_PPI_DESCRIPTOR    gPrivateDispatchTable[] = {/ i5 \5 L6 e5 ^
       {EFI_PEI_PPI_DESCRIPTOR_PPI, &gEfiNtLoadAsDllPpiGuid, &mSecNtLoadAsDllPpi},
: T6 p# N4 A& d. R& G4 ^( _. U       {EFI_PEI_PPI_DESCRIPTOR_PPI, &gNtPeiLoadFileGuid, &mSecNtLoadFilePpi},( ]) W- O: \# ^, W, j: d  k
       {EFI_PEI_PPI_DESCRIPTOR_PPI, &gPeiNtAutoScanPpiGuid, &mSecNtAutoScanPpi},
5 W2 S9 O  \; b5 ^- F       {EFI_PEI_PPI_DESCRIPTOR_PPI, &gPeiNtThunkPpiGuid, &mSecWinNtThunkPpi},
6 @5 e& K$ p6 T7 g& W8 Z6 Y& g9 I$ t, ]       {EFI_PEI_PPI_DESCRIPTOR_PPI, &gPeiStatusCodePpiGuid, &mSecStatusCodePpi},
& k1 ^2 f/ U+ j, M* o       {EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST, &gNtFwhPpiGuid, &mSecFwhInformationPpi}
3 J. K5 {+ N" z' ]: |% {     };2 O3 {. p! S7 {' s, }
    每个PPI是由{类型,GUID(名字,以后就根据这个来找到它的),Function_Entry_Address}组成。1 z. S  U' p) L9 Q1 L+ a3 Q" x# i5 i: e
   这些PPI会在PEIDispatcher中用到。9 ~% Z- d7 q( {& {) E
   安装完这此东西这开始执行PEIDispatcher函数,函数从BIOS ROM文件中找出PEI的Image(怎么找到,请读一下FV_HEAD(EFI_HEAD),里面讲到了如何区分Image类型),然后定位到PEI Image的入口地址,执行他。在我们的的PEI中,我们一般会申明一个PPI,这个就是这个PEI提供一些服务,PEIDispatcher会将他们加入到PPI-List中,以后其他Image也可以调用他的提供的功能。& n2 p- I6 V- }8 g
   最后EDK会加载一个叫DXEIPL的PEI,DXEIPL提供一个PPI服务,这个PPI的功能是实现从PEI到DXE的切换,这个PPI里面为DXE做了很多的预准备,加载了很多PPI,如对BIOS的解压方法等。
7 p. T) v! x/ i" T4 m" q   SwitchStacks (. D; ~* a1 v0 [4 E/ _
       (VOID *) (UINTN) DxeCoreEntryPoint,
4 o2 y! u: j: w       (UINTN) (HobList.Raw),9 A4 u6 D9 ^* Z1 W4 E) J
       (VOID *) (UINTN) TopOfStack,
# w& z( a8 S( O       (VOID *) (UINTN) BspStore: Y7 _1 C4 W' ?8 ^
    );
( f: Y$ m  O* M/ {: U, |$ m, o  用过汇编的人对这个技术一定很熟悉,不多说了(我别不清,咯。。。)
' L! t  k8 r8 {# z6 {2 O4 w( C# b8 f& D
DXE:
$ T0 w  L$ _) U. J- R     从PEI到DXE切换时转过来一个HOBLIST参数,DXE会在这个HOB中找到Memory的使用情况,然后根据这些情况将BIOS引到内存(这是EFI的做法)。在EDK在DXE时重新定位一下内存。; ^! ~8 Q) |" i3 |, a7 o
接着就会定义我们经常使用到的gST表,gRT表。接着是申明一些Protocol(先不关心这些事)。3 s+ E0 e. l5 Z) D: F6 ]
   等这些该加的PPI,Protocol加完了,CoreDispatcher()就出场了。他会的功能类似PEIDispatcher()。从我们BIOS ROM中将DXE的驱动读出,执行执行他们,这时会执行到Driver. d7 d( f6 X' Z4 [& d5 O/ Y+ h# o2 ~
中的Support(),Start()两个功能函数。在这两个函数中你可以注册自己的PPI,为其他驱动提供服务。
, Q; h/ c9 X( V8 x/ \   到些BIOS的引导其他完成。接着该进OS了,看Linux 0.11吧,操作系统是怎么做事情的。, l! e3 z% N- m8 c
   6 r/ v& q% L, N, y+ \' E2 w7 A. p7 l
Driver:+ E7 O0 S; v0 r! N+ i$ Q
    我们的驱动什么为在PEI和DXE等不同阶段执行呢?' o( h$ e5 ^0 @8 G. h
  大家请看一下我们的驱动的makefile.(EDK中的*.inf)( R# ?8 A8 g- x
  [defines]
8 R/ C* ^2 m8 }; U3 ^8 z  BASE_NAME            = OWEN
- d( J9 L6 o+ P3 O! c/ B2 h2 i+ h  FILE_GUID            = 1EDD13C1-62EF-4262-A1AA-0040D0830110" N. V2 L6 {" y# ~
  COMPONENT_TYPE       = BS_DRIVER+ B0 p. ~/ f. N# ?* b- g( {
1 k" z. w; O8 E' t8 U0 t4 C( ?
  BASE_NAME告诉编译器最终生成的驱动的名字。  T* s) r# \. E# P* K- ]. _' {! ~
  FILE_GUID就是这个驱动的GUID名字,在BIOS中引用某个驱动就是根据它来调用和识别。- O( }/ e) C/ Q! Z! [" Y+ s( C% ?
  COMONENT_TYPE会告诉编译器生成驱动的类型,是PEI,DXE,等。$ b- J8 T. J# m/ V' ?# u
  在EDK中有一个FWVolume.c实现的功能就是帮我们把这个TYPE转换面相应的扩展名
) m( n/ ]# W7 Y  COMP_TYPE_EXTENSION  mCompTypeExtension[] = {. M  _) H( Q6 I. Q( P
  {"bs_driver",  ".dxe" },8 ]0 R) |# n6 _( o* `8 e8 U% O- P0 p
  {"rt_driver",  ".dxe" },4 y. [& j7 g6 Z( }; b
  {"sal_rt_driver", ".dxe"},
" t: s. o' s0 h) v; R9 G, F1 I% S  {"security_core", ".sec"},
9 R8 Q( e' N; S/ @! s  {"pei_core", ".pei"},. R+ _" A0 _, T
  {"pic_peim", ".pei"},
3 f7 N4 b( P8 e  c( b  {"pe32_peim", ".pei"},
/ I; |9 H2 c! ~2 j3 T% U. p& E9 e+ j# r  {"relocatable_peim", ".pei"},: v! q; b! D9 ^- d- e) Q9 }
  {"binary", ".ffs"},
4 C+ R+ z7 _) `8 R+ s  d1 D  {"application", ".app"},9 ?% G/ Q  X/ f
  {"file", ".ffs"}," e) u6 B! i7 @9 N" n8 Y
  {"fvimagefile", ".fvi"},
) g  C! h+ n" P9 y) N  {"rawfile", ".raw"},/ m# b8 |8 M, o( `2 x7 T1 J7 P+ A
  {"apriori", ".ffs"},' M. O9 |, i5 a2 Z
  {"combined_peim_driver", ".pei"},8 A4 x9 `" T  d& e6 ~
  { NULL,  NULL }
# n( ~- D4 ~# B: l& q( h};$ d. n; }+ Q$ [( j# O4 o
/ G. p* P7 F/ w. G- F! \4 n4 p
了解了这些,接下我们可以看驱动篇了。(Go On Study... Forever)
9 E, M/ ~8 ]& C$ O' q. n- }" n* t: W   
; p8 g4 o: l: N7 E         7 V+ D: P$ _; A$ H
  
发表于 2008-7-27 12:30:15 | 显示全部楼层
不错!
7 d" M& {: @. D$ u  P( i支持& I* H1 A& h0 }7 @8 D& d
继续8 ~% y' ?# S5 {1 \9 n
加油+ k' V& g6 T& v3 \# C; H
回复

使用道具 举报

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

回复 1# 的帖子

gPrivateDispatchTable 和COMP_TYPE_EXTENSION  没有搜到啊  是EDK专有的么?
3 Y$ j6 O9 a$ J1 ]) @% b有看过跟gPrivateDispatchTable 类似的,但是里面的PPI不同。
1 Z3 q6 d0 K  q还有这个COMP_TYPE_EXTENSION  没有找到过。FWVolume.c这个文件也没有发现。。
回复

使用道具 举报

发表于 2008-7-28 13:24:20 | 显示全部楼层
这东西虽说没有什么技术含量,但是总结一下还是非常好的。+ x  ]) Q' n$ x/ i. }( l

) v/ n( F+ W* V7 ^$ `7 t支持!
回复

使用道具 举报

 楼主| 发表于 2008-7-28 18:52:31 | 显示全部楼层
1 h  |* t# n( X1 v  x
小弟还在学习阶段,目前的目标是知道执行的流程。
- Y& Y( B! S/ i. K8 `7 w0 x这里面有很多细节没有写,能力有限,只能自己知道,不能表达。- D3 z- _/ f. i5 R2 }0 e
嘿。。。。8 }. V, L8 }% e; h, c
所有大侠们如果有好东西能给小弟共享一份。
2 R: ]' O6 b, q
' g" {- l, u7 {" b7 O  }5 o谢谢!
回复

使用道具 举报

发表于 2008-8-12 14:44:11 | 显示全部楼层
原帖由 winbondowen 于 2008-7-27 00:11 发表
; V5 c  z! m7 h, R  K; a3 x  ROM中將DXE的驅動讀出,執行執行他們,這時會執行到Driver
  |1 h8 ]8 z$ h. R( b# A中的Support(),Start()兩個功能函數。在這兩個函數中你可以註冊自己的PPI ...
& V- q; n7 N/ G! k3 ]% T) \3 ]' ?

2 K# \* x5 @: E( }8 y$ @PPIs are registered during PEI phase, but Support()/Start() are invoked in DXE driver binding protocol,
& H- x" G3 e: b% z' p8 ]For more precisely, I think the "PPI" you mentioned is the "PROTOCOL" rather than "PPI".
: Y/ I+ A  K$ Y! h/ M2 L. h/ A% A* J! q7 b6 }4 k7 K
[ 本帖最后由 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:6 f" Y6 O: ^. }* H
   Yes. I make a mistake.
6 d) `+ p9 l3 n      PPI:     A PEIM to PEIM interface.' ?' m4 h' q7 ]9 B% Y2 T
      PROTOCL: A Interface between Hardware(or firmware) and software.% V2 X$ i7 v; k& n
      reference[http://www.biosren.com/viewthread.php?tid=207]
6 q9 x/ i3 T9 l: P   so, PPI execute at PEI step and Initialize hardware. PROTOCOL execute by DXE step.
* L0 W8 s* C  ~/ X# k+ c   Thanks.
回复

使用道具 举报

发表于 2008-8-20 17:47:21 | 显示全部楼层
原帖由 winbondowen 于 2008-7-27 00:11 发表 DXE:
4 x' T* M  D, @. h2 g& J2 D# i, f     從PEI到DXE切換時轉過來一個HOBLIST參數,DXE會在這個HOB中找到Memory的使用情況,然後根據這些情況將BIOS引到內存(這是EFI的做法)。在EDK在DXE時重新定位一下內存。  X% d4 S. D" Q/ ?* T, ]. O, f
接著就會定義我們經常使用到的gST表,gRT表。接著是申明一些Protocol(先不關心這些事)。* J6 X" Y/ K: o: S: }) f
   等這些該加的PPI,Protocol加完了,CoreDispatcher()就出場了。他會的功能類似PEIDispatcher()。從我們BIOS ROM中將DXE的驅動讀出,執行執行他們,這時會執行到Driver
# S7 C2 |  |6 C2 ]9 |3 f中的Support(),Start()兩個功能函數。在這兩個函數中你可以註冊自己的PPI,為其他驅動提供服務。9 L! Q" H+ ^5 M+ s9 i* i
   到些BIOS的引導其他完成。接著該進OS了,看Linux 0.11吧,操作系統是怎麼做事情的。.
6 ?/ J: i1 u, T( z) x

: y2 F  X  X; U5 G7 ~There are mistakes,% h9 a( C" T# J2 f
1.gST and gRT are init after the DXE architectural protocols have been loaded, those protocols response for creating Dxe foundation.
7 G+ v+ i' ]' a# X) @  d
4 L5 n" \3 b1 ]5 }# z2.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.
( e7 l; ~. u2 B5 Y- K$ SThe CoreDispatcher() executes all trusted Dxe drivers and just register the Binding protocol if the driver is EFI1.1 driver model.
. d% R1 J" \( y  h0 z0 G% EFurthermore, Support()/Start() are invoked in BDS phase over the CoreConnectController() rather than CoreDispatcher().
& O3 O( V! M; o) W0 H1 z9 t6 @) |6 ?; Z; |( |0 e8 Z
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 大侠的指点。+ X4 T+ `/ \3 J
回复

使用道具 举报

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

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

原帖由 ichirohiro 于 2008-8-20 17:47 发表
4 g/ Q8 J) k5 B" O" A...7 ?: q( ^/ y% K0 L  Q5 m4 _# k" 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 w, X$ T' ?3 a5 Q2 S5 I
The CoreDispatcher() executes all trusted Dxe drivers and just register the Binding protocol if the driver is EFI1.1 driver model.6 O  d  K! d; s3 Y  ?8 h. |4 i
Furthermore, Support()/Start() are invoked in BDS phase over the CoreConnectController() rather than CoreDispatcher().
  J: d3 Q& w: K$ Q
    在Framework的spec DxeCis.pdf里面也是这么说的,DXE CoreDispatcher()里面,对于EFI1.1 driver model的driver只会安装Handler和Interface到Binding protocol,到BDS才会去执行Support()和Start().3 e! J3 J" u% ~, X
    但是,我在看code时,发现在CoreDispatcher()-->CoreStartImage()里面call image之后有这么一句:  (file:image.c)
# u  f) Y" c6 o3 _- i7 k  //
) C0 E2 M$ i" c" d) P  // Go connect any handles that were created or modified while the image executed.# [: Z% A* S0 s! c
  //
! X" c. O. D0 ]0 w" G5 `4 p  CoreConnectHandlesByKey (HandleDatabaseKey);
) t  `1 v$ w+ h0 [: R  p2 P$ A
这里的HandleDatabaseKey是call image之前由CoreGetHandleDatabaseKey()得到的gHandleDatabaseKey
3 g' S$ y% o, k+ H( T  u而CoreConnectHandlesByKey会调用到:
* g( v, x8 x1 m1 B/ t. Z  //3 e- }9 q6 c5 q& B/ C  q
  // Connect all handles whose Key value is greater than Key
& U+ _: X) I2 t' W2 {; g5 b+ X4 C  //$ H( }# p. y. q8 Z  V. L
  for (Index = 0; Index < Count; Index++) {& D/ ]. D* W+ z, g
    CoreConnectController (HandleBuffer[Index], NULL, NULL, TRUE);
" ?" M9 @& Q( p3 S* x  }

; M" X; ~3 l" J' J所以,照code看,当在Driver中安装一个Handle和Interface到Binding Protocol后(gHandleDatabaseKey会++,IHandle的Key=gHandleDatabaseKey)
+ P! K6 Q" C' d2 V. L8 \$ b7 e! g2 l是会去ConnectController的,也会执行对应的Support()和Start()才对!!
1 q1 |3 c# N, ?+ Z* P  w, u) j* u/ s6 i8 D4 z: S" p4 x
不知道我想的哪里有问题???欢迎大家指正.. A, ~; t1 n3 E9 J0 s+ x9 L
( ^5 W8 M' v2 W/ T# U' G& I9 q
[ 本帖最后由 xtdumpling 于 2008-9-18 15:25 编辑 ]
回复

使用道具 举报

发表于 2008-9-19 14:44:41 | 显示全部楼层
这段code似乎是一个向后兼容的行为,不必太care。
9 M* i; _! x$ G6 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 | 显示全部楼层
了解了.
" A9 E! h& W# I+ ]$ S7 f非常 感谢!!!
回复

使用道具 举报

发表于 2008-9-23 16:48:56 | 显示全部楼层
在读DXEmain时,' c) ?. d& h4 ~9 `1 `& j0 f9 u, c4 f
Status = CoreInitializeImageServices(HobStart);--->CoreInstallProtocolInterface();--->CoreInstallProtocolInterfaceNotify();中,
! u7 d5 B2 Y* B4 D//
" u* p* R, i. Q// Notify the notification list for this protocol.7 J2 x9 c" \; [  A& c
//9 q0 E8 i! |- k5 d9 @
if (Notify) {
6 _! d0 `& Q* w  CoreNotifyProtocolEntry(ProtEntry);
, c2 h. ?0 ^9 J  n2 b}    里Signal了Event. MS是说一个handle安装了一个protocol后就signal一次.0 }; h$ U% i- N; ?5 ^4 V# ?' Z
有个问题请教一下大家: 这段是在DXE很靠前的位置执行的,但是在它之前我没有看到DXE中有相关的CreateEvent出现?哪位高手能说说这部分代码的流程呢?
回复

使用道具 举报

发表于 2008-9-23 17:04:14 | 显示全部楼层
原帖由 xtdumpling 于 2008-9-16 13:34 发表
, D7 e" {' ^$ s# U9 w5 U. m, y请楼上的兄弟分析下BS的RegisterProtocolNotify也就是CoreRegisterProtocolNotify是做什么用的?怎么用?
4 }. z/ r0 ]( ]6 ^+ g8 S# J谢谢!
" q: B3 x  X. t2 F* F5 Y1 R
......
& X% R) _- c4 n$ u- c
4 a# A2 T9 Y, I, Z0 R" ~, o: q5 \# b$ m5 O+ J4 P  [7 I- j+ X
[ 本帖最后由 xtdumpling 于 2008-9-23 17:24 编辑 ]
回复

使用道具 举报

发表于 2008-9-24 12:43:45 | 显示全部楼层
原帖由 xtdumpling 于 2008-9-23 17:04 发表 % @8 @, ]6 u: C7 s
9 _2 q% Q6 f3 J# U
......
4 z8 d3 N% }0 h( I7 U# F( _

. X9 Q! p9 Q5 p7 L$ c# T" nSignal的Event是不是在各个TPL级上挂载一些待处理的事件,一旦restore(TPL)的话,比当前TPL级高的pending事件就回被处理掉?
) K( \% V) h8 {  [7 k3 U# j如果是这样的话,Timer事件是如何处理的呢,没有找到相关的代码呀?Xt指点一下再~
回复

使用道具 举报

发表于 2008-9-24 19:00:46 | 显示全部楼层
Timer是挂在8259的IRQ0的中断处理程序上面的, 大概每秒18.3次调用CoreTimerTick()-->CoreCheckTimers()
/ [  D' N5 w# l, R' rTPL=30
回复

使用道具 举报

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

本版积分规则

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

GMT+8, 2026-6-8 10:01 , Processed in 0.131927 second(s), 16 queries .

Powered by Discuz! X3.5

© 2001-2025 Discuz! Team.

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