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

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

[复制链接]
发表于 2008-7-27 00:11:28 | 显示全部楼层 |阅读模式
  最近在工作看到机台有启动过程中把SPI ROM数据清空,但苦与没有办法很好的Debug(PCA没有架起来),所有与EDK为对象好好的读了一把。
+ X& d+ {' A( |3 ~
% a9 D" c/ K7 H1 ~0 Q/ KSEC/CEI:
0 |) ^) [# @# ~: N3 W  |  UEFI BIOS启动时先会执行SEC/CEI,这个阶段在实现的BIOS Code中初始化Debug Port,进入Big Mode,CPU的MicroCode,CacheToRAM的转换.然后跳转到PEI阶段。
! l: t; e4 w$ k& c) R! t* `在EDK中这部分被成了Load FvRecovery.fd文件,这个文件类似与我们的BIOS ROM.里面是我们编译后生成的二进制代码。在这个阶段最主要的是将这个文件加载到内存中(Windows API将文件加载到内存,看API函数).4 Q$ m( G5 ~2 F6 L: V( x
/ e1 j% G: M3 m8 c
PEI:+ W" o; P. s4 o' A- i4 `2 Q8 r
   从这里开始UEFI BIOS和EDK执行基本相同,只是一个是从SPI ROM中定位一个地址(PEIM的开始地址),一个是从内存中定位一个地址(PEIM的开始地址)。从这里开始只讲EDK的执行! D, `) w5 y1 t; n
  EDK调用InitializeMemoryService函数,将HobList清空,peiservice清空。
7 b6 Z: b7 ]0 X3 o2 r      InitializePPIService函数,将PPI队列清空,这个队列长0x3F.
; }9 B6 X8 r& U* H) o+ r6 j          InitializeSercurityService函数,将Notify队列清空。7 F+ d5 {5 n- t! a6 ^' s2 T4 R
          InitializeDispatcherData函数,将Dispatcher队列清空。4 f% |* u, O( g5 ?0 D* W6 j" M, h
  接着由PeiBuildHobGuid来建立一个HOB(S3返回时这时应该有这个HOB,不用建立,直接使用了,这样就会进入另外一个流程,可以这个EDK不能调试S3,不知道怎么走)。然后由(*PeiServices)->InstallPpi()将这个新HOB加入到PPI中。% ~; d" P9 g. u7 p( \* e) j
    由于在SEC阶段转了以下这几具PPI,所以在执行PEI的Dispatcher之前会先安装东西:7 u: d6 K( {. d% q' g8 ~" [, m  @6 q
      EFI_PEI_PPI_DESCRIPTOR    gPrivateDispatchTable[] = {
- L  s0 I2 N4 z       {EFI_PEI_PPI_DESCRIPTOR_PPI, &gEfiNtLoadAsDllPpiGuid, &mSecNtLoadAsDllPpi},- G! _+ \# K% G. K) r" N
       {EFI_PEI_PPI_DESCRIPTOR_PPI, &gNtPeiLoadFileGuid, &mSecNtLoadFilePpi},
2 n$ z  ]' i* k, g3 l- n, H       {EFI_PEI_PPI_DESCRIPTOR_PPI, &gPeiNtAutoScanPpiGuid, &mSecNtAutoScanPpi},, m* o  t2 ^# m5 V5 o) D; ~
       {EFI_PEI_PPI_DESCRIPTOR_PPI, &gPeiNtThunkPpiGuid, &mSecWinNtThunkPpi},
$ t" K' [- s+ ?0 V1 C- d       {EFI_PEI_PPI_DESCRIPTOR_PPI, &gPeiStatusCodePpiGuid, &mSecStatusCodePpi},
- i1 x0 k( E  @       {EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST, &gNtFwhPpiGuid, &mSecFwhInformationPpi}" `! b% O* H6 M' q  w
     };
. h* r- H2 M: t" H/ m    每个PPI是由{类型,GUID(名字,以后就根据这个来找到它的),Function_Entry_Address}组成。
' A" O8 R  M1 V, n# ~5 R8 ?   这些PPI会在PEIDispatcher中用到。# E9 s( t# s- |+ K+ c; n" v# K# N
   安装完这此东西这开始执行PEIDispatcher函数,函数从BIOS ROM文件中找出PEI的Image(怎么找到,请读一下FV_HEAD(EFI_HEAD),里面讲到了如何区分Image类型),然后定位到PEI Image的入口地址,执行他。在我们的的PEI中,我们一般会申明一个PPI,这个就是这个PEI提供一些服务,PEIDispatcher会将他们加入到PPI-List中,以后其他Image也可以调用他的提供的功能。
! C7 C3 L2 U+ M( u2 ]   最后EDK会加载一个叫DXEIPL的PEI,DXEIPL提供一个PPI服务,这个PPI的功能是实现从PEI到DXE的切换,这个PPI里面为DXE做了很多的预准备,加载了很多PPI,如对BIOS的解压方法等。
5 I' c6 ^4 k  x' x) E   SwitchStacks (
# ]; D  d' g" o% ]) _* h  W- g       (VOID *) (UINTN) DxeCoreEntryPoint,# a6 n4 {4 ?1 s8 j
       (UINTN) (HobList.Raw),  i" ^! Y6 z+ X% [) l. E
       (VOID *) (UINTN) TopOfStack,( ?- @6 m9 M' `
       (VOID *) (UINTN) BspStore/ h, ~/ M' A, f- I$ \- K6 j
    );
* }1 _1 ~7 B8 ?/ |; `* g  用过汇编的人对这个技术一定很熟悉,不多说了(我别不清,咯。。。)
! w5 ^3 M  J; N' A8 h/ L! ?4 H
; m! f- D+ T3 {8 ~3 CDXE:
, ~3 r* \  \  k$ w8 `     从PEI到DXE切换时转过来一个HOBLIST参数,DXE会在这个HOB中找到Memory的使用情况,然后根据这些情况将BIOS引到内存(这是EFI的做法)。在EDK在DXE时重新定位一下内存。
' P$ S5 v3 E9 }9 O& D接着就会定义我们经常使用到的gST表,gRT表。接着是申明一些Protocol(先不关心这些事)。
$ J! R8 r6 c2 P' H; a2 r# q. B   等这些该加的PPI,Protocol加完了,CoreDispatcher()就出场了。他会的功能类似PEIDispatcher()。从我们BIOS ROM中将DXE的驱动读出,执行执行他们,这时会执行到Driver
6 N; R; u  i6 v' L' E% [1 Z3 v中的Support(),Start()两个功能函数。在这两个函数中你可以注册自己的PPI,为其他驱动提供服务。
+ j, [2 w4 `3 V5 O, t2 @1 z/ k   到些BIOS的引导其他完成。接着该进OS了,看Linux 0.11吧,操作系统是怎么做事情的。
  C1 u9 ]& ?" `, {, }   
3 V! h+ k* O/ o0 X( K" C: Y8 R" MDriver:
$ V( q0 \) g7 @) s" O    我们的驱动什么为在PEI和DXE等不同阶段执行呢?
( `* v4 r( q  E% H! [% E9 v8 U4 U  大家请看一下我们的驱动的makefile.(EDK中的*.inf)+ {" E' G( q! K6 u- I6 `
  [defines]; Y' s. \! T! k' V' N
  BASE_NAME            = OWEN
1 M1 C/ \3 ?) n% [0 l9 D  FILE_GUID            = 1EDD13C1-62EF-4262-A1AA-0040D0830110' R0 w/ y; \+ `- M2 N9 G/ ?
  COMPONENT_TYPE       = BS_DRIVER
5 v3 B! A6 g  A/ R; U- P4 A2 K0 w/ H- D# m, r. Y7 Z3 j1 F
  BASE_NAME告诉编译器最终生成的驱动的名字。
; M# b0 j! [  Y) }4 L  FILE_GUID就是这个驱动的GUID名字,在BIOS中引用某个驱动就是根据它来调用和识别。
% k( W5 M* h0 C9 ~3 A' f+ E  COMONENT_TYPE会告诉编译器生成驱动的类型,是PEI,DXE,等。
0 t7 Z" @( J% m  在EDK中有一个FWVolume.c实现的功能就是帮我们把这个TYPE转换面相应的扩展名
0 t. b" g+ a! M  COMP_TYPE_EXTENSION  mCompTypeExtension[] = {
- X8 a0 ~6 d- e0 s- Q1 [  {"bs_driver",  ".dxe" },
0 ]" O9 {3 t3 O" x$ A  {"rt_driver",  ".dxe" },& s6 J- ^- s4 x( u
  {"sal_rt_driver", ".dxe"},
, @+ X) T" L' h; r* S  {"security_core", ".sec"},
! c5 G( v3 ]* i  {"pei_core", ".pei"},- m  c4 o& H$ G; R4 G: Q  J: z# N
  {"pic_peim", ".pei"},
% w' t. f) z1 P4 _  {"pe32_peim", ".pei"},. H: e9 N/ d- [. h
  {"relocatable_peim", ".pei"},
& w) J5 A$ v  a% y( \4 P  {"binary", ".ffs"},. H. ~( x1 `; J# t! `; w
  {"application", ".app"},) }! j/ m4 B4 L; U; c  ^
  {"file", ".ffs"},7 K1 ]2 N$ m1 X. O9 g* a
  {"fvimagefile", ".fvi"},! @+ A$ h& ^8 |+ @
  {"rawfile", ".raw"},
7 G! {0 x0 l* J" J  {"apriori", ".ffs"},
* U, g6 t, R- c; A  {"combined_peim_driver", ".pei"},; I- U) K5 x/ u& \9 _; e
  { NULL,  NULL }
% L& F1 ~6 k3 O! F2 h. p% n};$ W: J- p0 b- S- @* Z! z1 N0 h7 C
; j0 ?% b% l) j+ _: @4 p( ~' [+ ?. P
了解了这些,接下我们可以看驱动篇了。(Go On Study... Forever), S9 w* a* u9 r; r, ~6 A" m! {
   $ e% a& H% s/ R2 J
         
! A! X: ^! I# j3 A# n: \3 E  
发表于 2008-7-27 12:30:15 | 显示全部楼层
不错!( F: o) x) ~, y3 R) w4 H
支持+ s$ a4 I, @& y
继续& W* ~4 J! t% B3 j# t0 l! L" D
加油
2 a* K) F- H2 n2 ?! ^! K
回复

使用道具 举报

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

回复 1# 的帖子

gPrivateDispatchTable 和COMP_TYPE_EXTENSION  没有搜到啊  是EDK专有的么?
- P0 n; B" x6 c) R5 {+ e6 d* ?有看过跟gPrivateDispatchTable 类似的,但是里面的PPI不同。2 d- L% D  B6 `. S
还有这个COMP_TYPE_EXTENSION  没有找到过。FWVolume.c这个文件也没有发现。。
回复

使用道具 举报

发表于 2008-7-28 13:24:20 | 显示全部楼层
这东西虽说没有什么技术含量,但是总结一下还是非常好的。
) Y4 t7 `4 O! b' A  [5 N; e9 e, W- o0 j! V9 Q
支持!
回复

使用道具 举报

 楼主| 发表于 2008-7-28 18:52:31 | 显示全部楼层
+ z6 l) c! \7 Z
小弟还在学习阶段,目前的目标是知道执行的流程。
2 r; F6 p# ^6 D! O0 V7 F( i这里面有很多细节没有写,能力有限,只能自己知道,不能表达。' {! U6 \% o2 N9 f$ V! W
嘿。。。。; S! V& N$ o" ~* @9 z* ?
所有大侠们如果有好东西能给小弟共享一份。0 z! Q4 y3 y0 J
! R9 X+ [6 O3 n$ l: w& W7 _
谢谢!
回复

使用道具 举报

发表于 2008-8-12 14:44:11 | 显示全部楼层
原帖由 winbondowen 于 2008-7-27 00:11 发表 6 T& J1 V1 k# k
  ROM中將DXE的驅動讀出,執行執行他們,這時會執行到Driver/ Z1 E0 x5 V0 L$ r% P; u
中的Support(),Start()兩個功能函數。在這兩個函數中你可以註冊自己的PPI ...

  o; G' [4 s# V- v+ E' Z
* E; @, _/ [( y' r4 O; m- e& rPPIs are registered during PEI phase, but Support()/Start() are invoked in DXE driver binding protocol,
, _$ x  h( E' E* C  \* Q& T$ dFor more precisely, I think the "PPI" you mentioned is the "PROTOCOL" rather than "PPI".
. r. T: b1 e6 O9 K8 H) i7 z4 q# [+ l: Z
[ 本帖最后由 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:; W, j0 {0 y7 U+ v( U) U9 v" q
   Yes. I make a mistake.
6 ~& a) `. R  T0 Z6 ?      PPI:     A PEIM to PEIM interface.) X7 c$ _0 ^. |' \) e1 c* ~9 A
      PROTOCL: A Interface between Hardware(or firmware) and software.
6 F( B* j7 @6 A5 H) i& Q0 z      reference[http://www.biosren.com/viewthread.php?tid=207]
3 h! o, u9 ~! c. b( U   so, PPI execute at PEI step and Initialize hardware. PROTOCOL execute by DXE step.
9 g+ S0 L5 G7 J$ b- K' \! H& W2 F   Thanks.
回复

使用道具 举报

发表于 2008-8-20 17:47:21 | 显示全部楼层
原帖由 winbondowen 于 2008-7-27 00:11 发表 DXE:
2 ?# l6 r' r& [; |* f7 k  |     從PEI到DXE切換時轉過來一個HOBLIST參數,DXE會在這個HOB中找到Memory的使用情況,然後根據這些情況將BIOS引到內存(這是EFI的做法)。在EDK在DXE時重新定位一下內存。* r. \$ J0 h: d% ^
接著就會定義我們經常使用到的gST表,gRT表。接著是申明一些Protocol(先不關心這些事)。# C* G4 _/ E+ [, ~  o
   等這些該加的PPI,Protocol加完了,CoreDispatcher()就出場了。他會的功能類似PEIDispatcher()。從我們BIOS ROM中將DXE的驅動讀出,執行執行他們,這時會執行到Driver
0 m, p* K2 Y! e# P中的Support(),Start()兩個功能函數。在這兩個函數中你可以註冊自己的PPI,為其他驅動提供服務。" U3 v% i* ]8 H4 A+ R
   到些BIOS的引導其他完成。接著該進OS了,看Linux 0.11吧,操作系統是怎麼做事情的。.
+ `5 j9 I9 P- E! U# e8 T% j

" B: u4 {/ N1 M; L( |. {3 oThere are mistakes,
4 q% W- q5 _' q+ J6 h1 w9 C; u7 b1.gST and gRT are init after the DXE architectural protocols have been loaded, those protocols response for creating Dxe foundation.
* [  i  ?) D4 |) Y! A
3 W/ L5 Q9 _  G4 ~: Y8 p# ?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.
& a! M0 _9 @- }, @3 [) SThe CoreDispatcher() executes all trusted Dxe drivers and just register the Binding protocol if the driver is EFI1.1 driver model.
6 Y' y9 j' w. T; I- C5 `. BFurthermore, Support()/Start() are invoked in BDS phase over the CoreConnectController() rather than CoreDispatcher().
$ H9 d. K0 `+ d, q; r& Z
  @" h! N1 Y2 Z8 D4 I% R/ O% SBTW, 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( C& Z  n: u' I& d! {
回复

使用道具 举报

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

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

原帖由 ichirohiro 于 2008-8-20 17:47 发表 7 B6 E) h; m1 v/ V
...' T( ^  r" U8 _# k) ?, d9 W
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.
; A" [& k; L* L# [2 F/ EThe CoreDispatcher() executes all trusted Dxe drivers and just register the Binding protocol if the driver is EFI1.1 driver model.
1 f9 A, m/ i  E9 \' N# s/ ?Furthermore, Support()/Start() are invoked in BDS phase over the CoreConnectController() rather than CoreDispatcher().

. y" r8 l5 n1 n) {7 v5 ]8 m    在Framework的spec DxeCis.pdf里面也是这么说的,DXE CoreDispatcher()里面,对于EFI1.1 driver model的driver只会安装Handler和Interface到Binding protocol,到BDS才会去执行Support()和Start().* R* p  N( M, ^4 R2 W0 o& ~+ }
    但是,我在看code时,发现在CoreDispatcher()-->CoreStartImage()里面call image之后有这么一句:  (file:image.c)" T0 x/ S" {7 a0 f
  //
2 b/ h7 a& g4 r2 f- L  // Go connect any handles that were created or modified while the image executed.
% ^2 m4 K' v( Z" {* Z6 d  //
  r; Z! d/ u, q  B3 x  CoreConnectHandlesByKey (HandleDatabaseKey);

* t( K( Y5 o# D& @/ Q. M这里的HandleDatabaseKey是call image之前由CoreGetHandleDatabaseKey()得到的gHandleDatabaseKey
* [- @+ G$ ~9 z: D  g" v而CoreConnectHandlesByKey会调用到:
2 W+ x$ X  f, B+ r! ^$ _5 X1 m  //
/ s3 S# `& K1 k: a9 [# u* P  // Connect all handles whose Key value is greater than Key
, i" o& ~1 B3 b# b; h' i) R; m9 o  //
: w! [! k( ?6 W9 Q: |- \1 E# }  for (Index = 0; Index < Count; Index++) {
1 `' }4 b4 R- |) S$ m' d" q$ {    CoreConnectController (HandleBuffer[Index], NULL, NULL, TRUE);
, C: x6 d- ~: U5 J  }
; P6 ]4 P* z7 f- t
所以,照code看,当在Driver中安装一个Handle和Interface到Binding Protocol后(gHandleDatabaseKey会++,IHandle的Key=gHandleDatabaseKey)( F9 S. _/ I4 C* Q9 O" T
是会去ConnectController的,也会执行对应的Support()和Start()才对!!6 @# ^$ {  n2 o& z8 b
& B4 s0 f' p: n2 U
不知道我想的哪里有问题???欢迎大家指正.
2 s  K; J$ t5 G2 D& _
6 E& a1 Z1 P! i[ 本帖最后由 xtdumpling 于 2008-9-18 15:25 编辑 ]
回复

使用道具 举报

发表于 2008-9-19 14:44:41 | 显示全部楼层
这段code似乎是一个向后兼容的行为,不必太care。1 u8 |: N7 w9 }+ N+ X" @; V
一个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% O1 h) {. t9 S. D: _+ W
非常 感谢!!!
回复

使用道具 举报

发表于 2008-9-23 16:48:56 | 显示全部楼层
在读DXEmain时,8 n. {4 Y+ J5 r$ q4 Z* @
Status = CoreInitializeImageServices(HobStart);--->CoreInstallProtocolInterface();--->CoreInstallProtocolInterfaceNotify();中,# k+ u9 v2 X; J9 |. q# V
//
" h- Y8 S4 ?, t* t7 ]5 o// Notify the notification list for this protocol.
% V, G; }0 _; |  d5 p//$ _  ^6 A3 E8 [, R8 k$ G
if (Notify) {
# ]3 s2 `. m5 y2 S  CoreNotifyProtocolEntry(ProtEntry);
- ?" E' ]! s4 }9 s}    里Signal了Event. MS是说一个handle安装了一个protocol后就signal一次.# J' @* q) Z6 v5 _
有个问题请教一下大家: 这段是在DXE很靠前的位置执行的,但是在它之前我没有看到DXE中有相关的CreateEvent出现?哪位高手能说说这部分代码的流程呢?
回复

使用道具 举报

发表于 2008-9-23 17:04:14 | 显示全部楼层
原帖由 xtdumpling 于 2008-9-16 13:34 发表 , n% q6 r; D3 H+ S* I2 a( H
请楼上的兄弟分析下BS的RegisterProtocolNotify也就是CoreRegisterProtocolNotify是做什么用的?怎么用?( i, y8 n/ l7 n
谢谢!
( D7 A- w6 n& }; t
......
5 F3 p- Q+ U  b. O5 D( ]. k& S( I% n: n  c" V

. y  K# c6 [$ G' l[ 本帖最后由 xtdumpling 于 2008-9-23 17:24 编辑 ]
回复

使用道具 举报

发表于 2008-9-24 12:43:45 | 显示全部楼层
原帖由 xtdumpling 于 2008-9-23 17:04 发表 ( }, d7 ~% L3 D1 {- _7 u* z  e

. S2 u9 o6 l* e6 B3 I0 @: b8 P......3 a5 W  m8 D, t3 h( v- E0 P/ o  `
( C/ [% U: t2 u1 F
Signal的Event是不是在各个TPL级上挂载一些待处理的事件,一旦restore(TPL)的话,比当前TPL级高的pending事件就回被处理掉?3 w+ s/ M0 S7 i4 t
如果是这样的话,Timer事件是如何处理的呢,没有找到相关的代码呀?Xt指点一下再~
回复

使用道具 举报

发表于 2008-9-24 19:00:46 | 显示全部楼层
Timer是挂在8259的IRQ0的中断处理程序上面的, 大概每秒18.3次调用CoreTimerTick()-->CoreCheckTimers()
- Q+ a( k% v! K7 g, ?6 p  {# YTPL=30
回复

使用道具 举报

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

本版积分规则

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

GMT+8, 2024-5-19 05:55 , Processed in 0.026806 second(s), 17 queries .

Powered by Discuz! X3.5

© 2001-2023 Discuz! Team.

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