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

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

[复制链接]
发表于 2008-7-27 00:11:28 | 显示全部楼层 |阅读模式
  最近在工作看到机台有启动过程中把SPI ROM数据清空,但苦与没有办法很好的Debug(PCA没有架起来),所有与EDK为对象好好的读了一把。: Q9 I/ r7 X( Q) N. Z: \, {
0 Q2 g7 ]/ s2 U/ H: _, Z5 u
SEC/CEI:
& D0 A! Q% _9 w* ^$ M0 F+ E  UEFI BIOS启动时先会执行SEC/CEI,这个阶段在实现的BIOS Code中初始化Debug Port,进入Big Mode,CPU的MicroCode,CacheToRAM的转换.然后跳转到PEI阶段。
! p: m% c0 K: S( X在EDK中这部分被成了Load FvRecovery.fd文件,这个文件类似与我们的BIOS ROM.里面是我们编译后生成的二进制代码。在这个阶段最主要的是将这个文件加载到内存中(Windows API将文件加载到内存,看API函数).
1 [. A- w& V! Z. C& J" ]! r
4 |! V; G, H. x; aPEI:/ P2 S5 K/ ?: B9 A2 V5 a0 p* O
   从这里开始UEFI BIOS和EDK执行基本相同,只是一个是从SPI ROM中定位一个地址(PEIM的开始地址),一个是从内存中定位一个地址(PEIM的开始地址)。从这里开始只讲EDK的执行
3 ?8 a2 f  C  X- p1 M6 Y8 B; z  EDK调用InitializeMemoryService函数,将HobList清空,peiservice清空。6 s- b' v6 ^3 ~7 K( }2 j, B0 {
      InitializePPIService函数,将PPI队列清空,这个队列长0x3F.
  y% ~4 H5 |  ?% _; d* L% k) }: U          InitializeSercurityService函数,将Notify队列清空。' s& F" {+ Y2 a9 E5 O! h
          InitializeDispatcherData函数,将Dispatcher队列清空。: C+ Z3 Z9 Z" T, u8 E! [7 k4 p# o& V/ o
  接着由PeiBuildHobGuid来建立一个HOB(S3返回时这时应该有这个HOB,不用建立,直接使用了,这样就会进入另外一个流程,可以这个EDK不能调试S3,不知道怎么走)。然后由(*PeiServices)->InstallPpi()将这个新HOB加入到PPI中。# g& A" W- c5 R: y: @7 G
    由于在SEC阶段转了以下这几具PPI,所以在执行PEI的Dispatcher之前会先安装东西:
3 o7 \0 P3 d4 v" |# |* S      EFI_PEI_PPI_DESCRIPTOR    gPrivateDispatchTable[] = {. U! u' e0 I8 |" a* e, _0 t& Y. Q
       {EFI_PEI_PPI_DESCRIPTOR_PPI, &gEfiNtLoadAsDllPpiGuid, &mSecNtLoadAsDllPpi},4 x6 ?+ [* n* N1 n5 c8 C
       {EFI_PEI_PPI_DESCRIPTOR_PPI, &gNtPeiLoadFileGuid, &mSecNtLoadFilePpi},, Y6 O+ T' n4 k2 [" K  \# x
       {EFI_PEI_PPI_DESCRIPTOR_PPI, &gPeiNtAutoScanPpiGuid, &mSecNtAutoScanPpi},; V4 q6 S! m( v6 Y5 @: D3 X
       {EFI_PEI_PPI_DESCRIPTOR_PPI, &gPeiNtThunkPpiGuid, &mSecWinNtThunkPpi},
  I! A& o+ V: l8 E. G$ }       {EFI_PEI_PPI_DESCRIPTOR_PPI, &gPeiStatusCodePpiGuid, &mSecStatusCodePpi},
( B& W  s0 |: e# D1 D, m% `) _       {EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST, &gNtFwhPpiGuid, &mSecFwhInformationPpi}
6 i3 K5 P: J6 A- \& j$ G     };; k8 i% Q/ w" x: N) ]8 V& p
    每个PPI是由{类型,GUID(名字,以后就根据这个来找到它的),Function_Entry_Address}组成。
$ D7 |. E! _: {* }" R: B* @6 \   这些PPI会在PEIDispatcher中用到。! L# z) g2 \3 I1 X8 u
   安装完这此东西这开始执行PEIDispatcher函数,函数从BIOS ROM文件中找出PEI的Image(怎么找到,请读一下FV_HEAD(EFI_HEAD),里面讲到了如何区分Image类型),然后定位到PEI Image的入口地址,执行他。在我们的的PEI中,我们一般会申明一个PPI,这个就是这个PEI提供一些服务,PEIDispatcher会将他们加入到PPI-List中,以后其他Image也可以调用他的提供的功能。
- x. _2 A! L4 G, q   最后EDK会加载一个叫DXEIPL的PEI,DXEIPL提供一个PPI服务,这个PPI的功能是实现从PEI到DXE的切换,这个PPI里面为DXE做了很多的预准备,加载了很多PPI,如对BIOS的解压方法等。
0 M6 x! b; |4 f# k! S# m   SwitchStacks (/ O- {' Z! ^$ \# d" j' Y: _) [8 P
       (VOID *) (UINTN) DxeCoreEntryPoint,( ^; v$ c1 u% Q$ J
       (UINTN) (HobList.Raw),
& b  i" C0 _9 u( X0 N) J: \  c       (VOID *) (UINTN) TopOfStack,( C6 D4 [# }( O- x! y! {
       (VOID *) (UINTN) BspStore
2 ~) S2 A2 y( ?4 p; x* F    );
+ U/ I! @% Q( c/ @2 G! q  用过汇编的人对这个技术一定很熟悉,不多说了(我别不清,咯。。。)( S) V/ B8 A3 Z

8 W" {9 C- S7 W6 zDXE:! ?, }2 `* m0 {& Y7 L" {
     从PEI到DXE切换时转过来一个HOBLIST参数,DXE会在这个HOB中找到Memory的使用情况,然后根据这些情况将BIOS引到内存(这是EFI的做法)。在EDK在DXE时重新定位一下内存。
& m6 g- q, y. W! w+ Y4 r接着就会定义我们经常使用到的gST表,gRT表。接着是申明一些Protocol(先不关心这些事)。
+ _, R- }3 e0 k) x8 W   等这些该加的PPI,Protocol加完了,CoreDispatcher()就出场了。他会的功能类似PEIDispatcher()。从我们BIOS ROM中将DXE的驱动读出,执行执行他们,这时会执行到Driver
; g2 @  b) a0 B! T  x1 `中的Support(),Start()两个功能函数。在这两个函数中你可以注册自己的PPI,为其他驱动提供服务。8 ^4 d; L! X8 |
   到些BIOS的引导其他完成。接着该进OS了,看Linux 0.11吧,操作系统是怎么做事情的。
9 E9 b' E" x5 e   
: m" x# v6 Z% N  [Driver:
1 ~) _9 m9 x7 G( a1 s& ^    我们的驱动什么为在PEI和DXE等不同阶段执行呢?" D- A! }  w+ _, x
  大家请看一下我们的驱动的makefile.(EDK中的*.inf), p9 Z% |8 v3 |2 ]5 X5 M
  [defines], E3 B$ @# Y, Z& k( X1 c
  BASE_NAME            = OWEN
8 U# V6 H- n0 A7 s  FILE_GUID            = 1EDD13C1-62EF-4262-A1AA-0040D0830110
7 T& z+ z  k' T0 Z9 v: O  COMPONENT_TYPE       = BS_DRIVER, u3 u: }; C8 H4 k: K  |

1 C/ c9 I, T9 j- ^- S- _, C: ?  BASE_NAME告诉编译器最终生成的驱动的名字。
4 D0 ^8 E! w" V. S% ?  FILE_GUID就是这个驱动的GUID名字,在BIOS中引用某个驱动就是根据它来调用和识别。
( V8 q- p6 D# h  COMONENT_TYPE会告诉编译器生成驱动的类型,是PEI,DXE,等。5 k4 n4 P0 i1 u$ J" k
  在EDK中有一个FWVolume.c实现的功能就是帮我们把这个TYPE转换面相应的扩展名: @* _3 |, d4 b* _+ }, s
  COMP_TYPE_EXTENSION  mCompTypeExtension[] = {# `" A7 w8 w& g' A! w
  {"bs_driver",  ".dxe" },1 h2 o5 Z6 p3 t- b. v* ?
  {"rt_driver",  ".dxe" },
" R3 g4 K4 y6 s# K  {"sal_rt_driver", ".dxe"},
- P8 ^5 O, A3 o, }' |; i3 i7 ?! T  {"security_core", ".sec"},
+ g% \, F' j' T5 j9 B  {"pei_core", ".pei"},' a+ r* ?- ~' r3 w/ y& p9 q2 V+ f7 k
  {"pic_peim", ".pei"},+ Z1 F- [+ k. r: W
  {"pe32_peim", ".pei"},
& q  }9 p: V" B( p1 O5 o7 w' B  {"relocatable_peim", ".pei"},; m! g, F# N3 x3 l* R
  {"binary", ".ffs"},* k  g9 ^( s2 H" J7 I) c1 ?
  {"application", ".app"},! k. z* s/ ^* n4 }
  {"file", ".ffs"},
" Z8 i  S* i1 V. B) {$ v! c) ]  {"fvimagefile", ".fvi"},
  S2 q- d+ \; }  {"rawfile", ".raw"},
& ^2 y( [  B- q  E5 B  {"apriori", ".ffs"},
4 Y+ Q3 R* b% U$ Q$ e- G  {"combined_peim_driver", ".pei"},7 }  I( `0 D) P6 P% B% ^. ^9 \
  { NULL,  NULL }: j' F6 j/ C5 Y+ \' z8 j5 ?
};
6 x, |- _! D9 _3 m7 _% t7 s* w) ]3 }4 S/ V
了解了这些,接下我们可以看驱动篇了。(Go On Study... Forever)! x1 O) T2 Y; o
   & H4 K- l% x9 A
         $ q# r+ t8 }" u% c
  
发表于 2008-7-27 12:30:15 | 显示全部楼层
不错!& |& Z  I/ p1 a, }  }
支持. G6 r  H$ @. y' K: c, \. N, k
继续
1 b- ^3 W4 {% H" Q加油: d8 p5 j& I' f, E
回复

使用道具 举报

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

回复 1# 的帖子

gPrivateDispatchTable 和COMP_TYPE_EXTENSION  没有搜到啊  是EDK专有的么?  @  ]& U2 O+ W$ r' m
有看过跟gPrivateDispatchTable 类似的,但是里面的PPI不同。
5 f0 C6 v" X( o4 M0 d0 c! I3 x还有这个COMP_TYPE_EXTENSION  没有找到过。FWVolume.c这个文件也没有发现。。
回复

使用道具 举报

发表于 2008-7-28 13:24:20 | 显示全部楼层
这东西虽说没有什么技术含量,但是总结一下还是非常好的。( A, ?. v! B+ U! J4 w$ m
+ M3 D0 h+ c& V; n, E' [
支持!
回复

使用道具 举报

 楼主| 发表于 2008-7-28 18:52:31 | 显示全部楼层
0 `+ r  d) [; O2 J2 h5 e/ R- W% F
小弟还在学习阶段,目前的目标是知道执行的流程。
- X" \9 |/ n/ _1 M这里面有很多细节没有写,能力有限,只能自己知道,不能表达。
4 |8 Y1 |# C$ N( p嘿。。。。3 H- e1 b% }; O7 Q
所有大侠们如果有好东西能给小弟共享一份。3 ]1 Q" a; A& ~9 y# [0 U

* m, K( u: R; d/ `" c谢谢!
回复

使用道具 举报

发表于 2008-8-12 14:44:11 | 显示全部楼层
原帖由 winbondowen 于 2008-7-27 00:11 发表
& `/ v- A5 g' o0 `  ROM中將DXE的驅動讀出,執行執行他們,這時會執行到Driver& B" x$ b6 z/ }' A- z
中的Support(),Start()兩個功能函數。在這兩個函數中你可以註冊自己的PPI ...

6 a* [* }. A# m
7 J# [/ W+ ]) l8 |8 O8 p0 \, }PPIs are registered during PEI phase, but Support()/Start() are invoked in DXE driver binding protocol,
- l+ @9 Q  q! m6 N4 n$ BFor more precisely, I think the "PPI" you mentioned is the "PROTOCOL" rather than "PPI".
1 m2 L9 A# w+ r- x6 @# m7 w. |/ D1 [% c  u% E! M% x  n
[ 本帖最后由 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:/ E7 s6 [4 F4 W8 B; K
   Yes. I make a mistake.: o% M; v1 `/ _  c3 j5 x
      PPI:     A PEIM to PEIM interface.: ^! k& c2 q8 W  f5 |% }5 @
      PROTOCL: A Interface between Hardware(or firmware) and software.# k- ~; {3 R& u* j
      reference[http://www.biosren.com/viewthread.php?tid=207]
1 T/ i  W# d% Y4 l! q   so, PPI execute at PEI step and Initialize hardware. PROTOCOL execute by DXE step.
- y0 x$ y8 X0 s/ f$ v$ E2 O/ ]   Thanks.
回复

使用道具 举报

发表于 2008-8-20 17:47:21 | 显示全部楼层
原帖由 winbondowen 于 2008-7-27 00:11 发表 DXE:
. F: P5 D/ c6 j  p: Q     從PEI到DXE切換時轉過來一個HOBLIST參數,DXE會在這個HOB中找到Memory的使用情況,然後根據這些情況將BIOS引到內存(這是EFI的做法)。在EDK在DXE時重新定位一下內存。: E& ~# l* S! x( D' o! `" Q
接著就會定義我們經常使用到的gST表,gRT表。接著是申明一些Protocol(先不關心這些事)。
8 Z5 ?9 p+ ~1 ^# b   等這些該加的PPI,Protocol加完了,CoreDispatcher()就出場了。他會的功能類似PEIDispatcher()。從我們BIOS ROM中將DXE的驅動讀出,執行執行他們,這時會執行到Driver
/ n6 y$ R5 S* G$ ~: h( F8 m* @, u中的Support(),Start()兩個功能函數。在這兩個函數中你可以註冊自己的PPI,為其他驅動提供服務。! l+ e. A/ i+ k3 n* @
   到些BIOS的引導其他完成。接著該進OS了,看Linux 0.11吧,操作系統是怎麼做事情的。.
7 Q, a1 ^1 Y0 f" o5 v

3 p  i, c! p3 f( t1 F* q( A' ?9 pThere are mistakes,
, ?# A) w, |: U# t1.gST and gRT are init after the DXE architectural protocols have been loaded, those protocols response for creating Dxe foundation.  ?! l1 F* j7 o6 u4 d( }3 v6 e
) F( |# N6 m0 X+ Q8 p1 j1 a/ p6 j+ Y
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.
5 ~5 F  z% ]: R/ ~6 U8 a  CThe CoreDispatcher() executes all trusted Dxe drivers and just register the Binding protocol if the driver is EFI1.1 driver model.
. m9 l" I' ]1 P1 _. L4 IFurthermore, Support()/Start() are invoked in BDS phase over the CoreConnectController() rather than CoreDispatcher().& O) v7 S- B4 `; D" d' b. H

- j, G3 U6 X+ O3 }2 }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 大侠的指点。
% Y+ K. q! J$ P3 j( s1 K
回复

使用道具 举报

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

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

原帖由 ichirohiro 于 2008-8-20 17:47 发表 * [9 t5 a  H' v: x" t! {6 @2 L
..., P! N0 }% b8 V/ Z
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.
1 t5 ?8 f- ^7 O% k. x  x. W5 r. cThe CoreDispatcher() executes all trusted Dxe drivers and just register the Binding protocol if the driver is EFI1.1 driver model.
* D1 X. Q2 _* `9 j: MFurthermore, Support()/Start() are invoked in BDS phase over the CoreConnectController() rather than CoreDispatcher().

6 H$ s- M' f# Q2 K- y) E    在Framework的spec DxeCis.pdf里面也是这么说的,DXE CoreDispatcher()里面,对于EFI1.1 driver model的driver只会安装Handler和Interface到Binding protocol,到BDS才会去执行Support()和Start().
; S; R6 y/ J7 C' q8 B3 X5 I    但是,我在看code时,发现在CoreDispatcher()-->CoreStartImage()里面call image之后有这么一句:  (file:image.c)
; V7 T# a: ?6 V) J0 J! ?  //
( P+ R: m2 a) R2 u% l6 o  H  // Go connect any handles that were created or modified while the image executed.
! H0 D. E. q4 m% [- R9 g  //) U' P' {$ R' a4 p- \: _9 N) M" P
  CoreConnectHandlesByKey (HandleDatabaseKey);
: g' R' e0 Z" {
这里的HandleDatabaseKey是call image之前由CoreGetHandleDatabaseKey()得到的gHandleDatabaseKey4 |# L9 C3 H2 M. T1 d
而CoreConnectHandlesByKey会调用到:) ^% D4 u& G. x$ B  ]) E" y
  //8 I6 i9 H9 O3 z2 }5 J
  // Connect all handles whose Key value is greater than Key
8 V3 [+ P5 n* G! b, Z  //
" X7 p- O, ]% R7 G  for (Index = 0; Index < Count; Index++) {6 Z6 O5 a1 f$ R, l4 o. p
    CoreConnectController (HandleBuffer[Index], NULL, NULL, TRUE);- W0 y; p: z- p
  }

' w: H" Z% Q( I3 Q所以,照code看,当在Driver中安装一个Handle和Interface到Binding Protocol后(gHandleDatabaseKey会++,IHandle的Key=gHandleDatabaseKey)
) a, \. W( ?; G# s是会去ConnectController的,也会执行对应的Support()和Start()才对!!
+ I; y$ u7 L& r/ y' ]8 M
1 i) ]  V" C, @. r" N不知道我想的哪里有问题???欢迎大家指正.
& z3 O  _. M' _/ W
( n/ `) D5 ~8 P  U" L' C: W[ 本帖最后由 xtdumpling 于 2008-9-18 15:25 编辑 ]
回复

使用道具 举报

发表于 2008-9-19 14:44:41 | 显示全部楼层
这段code似乎是一个向后兼容的行为,不必太care。
, I* L' [& F5 V- ^- T3 w一个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 | 显示全部楼层
了解了.5 U+ _+ v( u9 h, {  X
非常 感谢!!!
回复

使用道具 举报

发表于 2008-9-23 16:48:56 | 显示全部楼层
在读DXEmain时,2 [4 U+ m# e" |1 e, ~
Status = CoreInitializeImageServices(HobStart);--->CoreInstallProtocolInterface();--->CoreInstallProtocolInterfaceNotify();中,
1 T# u) `' m2 J, m8 D//! s/ g8 a: h7 [0 y: i# H3 F/ }
// Notify the notification list for this protocol.! k3 D( r8 F* ~4 d, C& F* \
//
* W# ?# p' `1 s) I0 G" O& Yif (Notify) {3 k! Z4 S) q  P% b1 `0 ^
  CoreNotifyProtocolEntry(ProtEntry);
7 G: k" X* i& f0 X) Z. m2 h}    里Signal了Event. MS是说一个handle安装了一个protocol后就signal一次." W. h1 N$ l6 ^6 V4 Q7 z0 G0 Q3 [
有个问题请教一下大家: 这段是在DXE很靠前的位置执行的,但是在它之前我没有看到DXE中有相关的CreateEvent出现?哪位高手能说说这部分代码的流程呢?
回复

使用道具 举报

发表于 2008-9-23 17:04:14 | 显示全部楼层
原帖由 xtdumpling 于 2008-9-16 13:34 发表 % B. D! n0 F% T  i
请楼上的兄弟分析下BS的RegisterProtocolNotify也就是CoreRegisterProtocolNotify是做什么用的?怎么用?6 Z. u7 ~/ d: d6 _
谢谢!
( D3 z' s" D  @9 q, P2 L
......+ F9 x6 R, j: O9 ~! D- J/ G3 U
* V7 m+ Z/ E" _  D/ o5 |

% S5 \: k  Z$ B. G3 W0 r! J& k[ 本帖最后由 xtdumpling 于 2008-9-23 17:24 编辑 ]
回复

使用道具 举报

发表于 2008-9-24 12:43:45 | 显示全部楼层
原帖由 xtdumpling 于 2008-9-23 17:04 发表
6 _9 X, \. v7 Z1 Y" o. F1 X
/ y# |6 w! g  j* O8 p' e- o& o3 A0 B......
# j" D3 _- q2 I2 S, M& s' W) S
7 I3 F3 H1 L- l4 ~2 }$ f5 [
Signal的Event是不是在各个TPL级上挂载一些待处理的事件,一旦restore(TPL)的话,比当前TPL级高的pending事件就回被处理掉?3 r% w' F( T3 z9 Y* B1 V& j& C5 c
如果是这样的话,Timer事件是如何处理的呢,没有找到相关的代码呀?Xt指点一下再~
回复

使用道具 举报

发表于 2008-9-24 19:00:46 | 显示全部楼层
Timer是挂在8259的IRQ0的中断处理程序上面的, 大概每秒18.3次调用CoreTimerTick()-->CoreCheckTimers()
+ P9 _% b8 u! U  D, H- p1 ]+ OTPL=30
回复

使用道具 举报

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

本版积分规则

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

GMT+8, 2025-3-5 00:23 , Processed in 0.031330 second(s), 16 queries .

Powered by Discuz! X3.5

© 2001-2023 Discuz! Team.

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