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

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

[复制链接]
发表于 2008-7-27 00:11:28 | 显示全部楼层 |阅读模式
  最近在工作看到机台有启动过程中把SPI ROM数据清空,但苦与没有办法很好的Debug(PCA没有架起来),所有与EDK为对象好好的读了一把。
, A0 f7 P4 i$ o3 L4 X7 k/ i
4 Q7 W( e( Q! H) i) S+ bSEC/CEI:
+ s( D! S$ g# j8 |3 n  UEFI BIOS启动时先会执行SEC/CEI,这个阶段在实现的BIOS Code中初始化Debug Port,进入Big Mode,CPU的MicroCode,CacheToRAM的转换.然后跳转到PEI阶段。
! b/ F3 K' o7 {在EDK中这部分被成了Load FvRecovery.fd文件,这个文件类似与我们的BIOS ROM.里面是我们编译后生成的二进制代码。在这个阶段最主要的是将这个文件加载到内存中(Windows API将文件加载到内存,看API函数).
8 E/ J8 [; d( f2 T: V- b* z" I2 r
% P; Z- ^! n& dPEI:
" d, e/ y9 u+ b) F% f/ |% G6 A   从这里开始UEFI BIOS和EDK执行基本相同,只是一个是从SPI ROM中定位一个地址(PEIM的开始地址),一个是从内存中定位一个地址(PEIM的开始地址)。从这里开始只讲EDK的执行+ g. h% e7 I, C" U# c. ]  O6 j) V
  EDK调用InitializeMemoryService函数,将HobList清空,peiservice清空。
8 N9 B5 o1 o, i# U/ J. z      InitializePPIService函数,将PPI队列清空,这个队列长0x3F.
) B( `) P7 [/ p2 P( ^* l          InitializeSercurityService函数,将Notify队列清空。
# ^8 L+ m. a: w) B; s9 K          InitializeDispatcherData函数,将Dispatcher队列清空。# u6 o% g3 H" V: G4 c
  接着由PeiBuildHobGuid来建立一个HOB(S3返回时这时应该有这个HOB,不用建立,直接使用了,这样就会进入另外一个流程,可以这个EDK不能调试S3,不知道怎么走)。然后由(*PeiServices)->InstallPpi()将这个新HOB加入到PPI中。8 n: o4 w5 _" v7 M. J) p
    由于在SEC阶段转了以下这几具PPI,所以在执行PEI的Dispatcher之前会先安装东西:( _. E' E/ Z! ~6 n
      EFI_PEI_PPI_DESCRIPTOR    gPrivateDispatchTable[] = {
: r* K% j& P& M( F. U! |$ i5 E       {EFI_PEI_PPI_DESCRIPTOR_PPI, &gEfiNtLoadAsDllPpiGuid, &mSecNtLoadAsDllPpi},
& Q& d6 o/ z1 x# A' K" _: Q5 k       {EFI_PEI_PPI_DESCRIPTOR_PPI, &gNtPeiLoadFileGuid, &mSecNtLoadFilePpi}," J, D1 I% v* ]
       {EFI_PEI_PPI_DESCRIPTOR_PPI, &gPeiNtAutoScanPpiGuid, &mSecNtAutoScanPpi},
# O  S- p7 ~4 ~; ~# u9 l       {EFI_PEI_PPI_DESCRIPTOR_PPI, &gPeiNtThunkPpiGuid, &mSecWinNtThunkPpi},  V; Z" `1 `4 B9 T& Y
       {EFI_PEI_PPI_DESCRIPTOR_PPI, &gPeiStatusCodePpiGuid, &mSecStatusCodePpi},
2 i+ |3 ]) t5 S1 E3 @/ l       {EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST, &gNtFwhPpiGuid, &mSecFwhInformationPpi}
) _0 O+ u  |& D' \' T+ _$ N     };! s9 U6 ^# m7 M. ?) P5 n
    每个PPI是由{类型,GUID(名字,以后就根据这个来找到它的),Function_Entry_Address}组成。* n4 _, ~5 e; t/ D7 Y' W1 X8 i0 v
   这些PPI会在PEIDispatcher中用到。! [: w7 |" k) r" F) u0 \
   安装完这此东西这开始执行PEIDispatcher函数,函数从BIOS ROM文件中找出PEI的Image(怎么找到,请读一下FV_HEAD(EFI_HEAD),里面讲到了如何区分Image类型),然后定位到PEI Image的入口地址,执行他。在我们的的PEI中,我们一般会申明一个PPI,这个就是这个PEI提供一些服务,PEIDispatcher会将他们加入到PPI-List中,以后其他Image也可以调用他的提供的功能。
- a/ x* [" I" |4 V% f   最后EDK会加载一个叫DXEIPL的PEI,DXEIPL提供一个PPI服务,这个PPI的功能是实现从PEI到DXE的切换,这个PPI里面为DXE做了很多的预准备,加载了很多PPI,如对BIOS的解压方法等。, _) W% v# c* j! {8 J
   SwitchStacks (: N& a) e# }" A  {
       (VOID *) (UINTN) DxeCoreEntryPoint,$ f: d3 `6 v- N* W3 N, W, C+ h
       (UINTN) (HobList.Raw),3 [, B/ {/ j5 Y. i
       (VOID *) (UINTN) TopOfStack,. E+ G: d% I" `8 \. i! H8 z+ O5 l0 Y; z
       (VOID *) (UINTN) BspStore1 ]% t- d. ^+ R3 G8 P
    );
& H! r9 q) J4 s, r5 W  用过汇编的人对这个技术一定很熟悉,不多说了(我别不清,咯。。。)
1 Y: n9 s, k; i/ O/ }. Y# h) X/ G1 ?
% F; F5 h5 W, n: i' o# r1 e1 @5 WDXE:/ G, F, F1 T8 }* T. y1 `
     从PEI到DXE切换时转过来一个HOBLIST参数,DXE会在这个HOB中找到Memory的使用情况,然后根据这些情况将BIOS引到内存(这是EFI的做法)。在EDK在DXE时重新定位一下内存。
1 w2 K3 b( E. F4 u接着就会定义我们经常使用到的gST表,gRT表。接着是申明一些Protocol(先不关心这些事)。; U' P8 e3 m" ?+ P
   等这些该加的PPI,Protocol加完了,CoreDispatcher()就出场了。他会的功能类似PEIDispatcher()。从我们BIOS ROM中将DXE的驱动读出,执行执行他们,这时会执行到Driver, f3 p! @* J* ~- m3 j1 i$ F1 k1 Y1 J
中的Support(),Start()两个功能函数。在这两个函数中你可以注册自己的PPI,为其他驱动提供服务。
. w. f( o- t) X   到些BIOS的引导其他完成。接着该进OS了,看Linux 0.11吧,操作系统是怎么做事情的。
8 x- i( \: e; q7 O( p   
/ E, m  e9 w6 o0 TDriver:" X6 p9 u' a6 u# m0 ]0 `4 |9 F
    我们的驱动什么为在PEI和DXE等不同阶段执行呢?" _+ m. W6 O/ L; s! d
  大家请看一下我们的驱动的makefile.(EDK中的*.inf)& q* r% r$ U2 F. }' P- o
  [defines]
) s% u- Y* `" B; }+ j; c  BASE_NAME            = OWEN1 ~, N8 R6 Z4 {0 I* }
  FILE_GUID            = 1EDD13C1-62EF-4262-A1AA-0040D0830110
) y) _6 L0 W3 S/ k  COMPONENT_TYPE       = BS_DRIVER: X$ q1 h0 o0 X) F( o5 v( ]$ }
( Q2 F( A7 F0 B+ k6 r
  BASE_NAME告诉编译器最终生成的驱动的名字。
8 W1 D  l/ {, Q  q  FILE_GUID就是这个驱动的GUID名字,在BIOS中引用某个驱动就是根据它来调用和识别。: ]4 E4 [! c) ~& a$ n1 K  S
  COMONENT_TYPE会告诉编译器生成驱动的类型,是PEI,DXE,等。, l( [4 d$ t3 T3 A) P
  在EDK中有一个FWVolume.c实现的功能就是帮我们把这个TYPE转换面相应的扩展名
) O! E; N) Z( {( ~4 U) x2 T5 W  COMP_TYPE_EXTENSION  mCompTypeExtension[] = {
! A, z1 w; m. V) S  {"bs_driver",  ".dxe" },
5 P8 i; m# N4 p! v! k( h  l  {"rt_driver",  ".dxe" },# Q1 x+ V& K$ U; c- H
  {"sal_rt_driver", ".dxe"},
; @6 b1 K% }/ U" |8 a, s  {"security_core", ".sec"},/ o! c  G7 V- h& @
  {"pei_core", ".pei"},9 G% h' G1 r8 \  \8 k2 P, v7 \
  {"pic_peim", ".pei"}," E) a$ z' A. J* |. G8 G: d+ y
  {"pe32_peim", ".pei"},* P2 n, O& x+ J0 ~2 I0 I; q  g
  {"relocatable_peim", ".pei"},
! d" s8 V7 I! x# u6 X- ]  {"binary", ".ffs"},/ s2 V6 Y' K: p+ U+ V6 U8 X
  {"application", ".app"},
) q6 G5 j- y3 F0 V. X8 N  {"file", ".ffs"},5 u2 ?. v' c2 u& d7 E, c: q
  {"fvimagefile", ".fvi"},
! A& w/ `/ C2 `7 C5 q  {"rawfile", ".raw"},2 @; s+ f% Q. A6 |( r# E0 ~+ _
  {"apriori", ".ffs"},
% ~0 c1 j6 _. g6 {- u  {"combined_peim_driver", ".pei"},5 m2 W5 E% o6 M7 \% f
  { NULL,  NULL }
& m2 Y. S" _, L/ R0 @. _7 D};' [3 z" @" Y0 d4 G4 m$ u

4 N( t4 G' O3 {. P了解了这些,接下我们可以看驱动篇了。(Go On Study... Forever)0 H( V5 t6 q+ _& q' B2 I
   
/ V0 F4 X1 A" j( v; o2 [         
0 M& C; a# F; ^6 \( z  
发表于 2008-7-27 12:30:15 | 显示全部楼层
不错!9 b& J. i! ]0 ?7 F# b
支持6 }/ }9 c: s0 Z8 d. c
继续
" _0 r, W7 _( q加油
5 Y, }4 K2 f2 c7 ?3 L; l8 b; c4 I
回复

使用道具 举报

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

回复 1# 的帖子

gPrivateDispatchTable 和COMP_TYPE_EXTENSION  没有搜到啊  是EDK专有的么?
. f) C# v8 ~; x) ]$ P3 ]4 N有看过跟gPrivateDispatchTable 类似的,但是里面的PPI不同。
; `2 }: ~6 y0 u# C1 u还有这个COMP_TYPE_EXTENSION  没有找到过。FWVolume.c这个文件也没有发现。。
回复

使用道具 举报

发表于 2008-7-28 13:24:20 | 显示全部楼层
这东西虽说没有什么技术含量,但是总结一下还是非常好的。% b* \- T# C! ^% E+ w9 n2 v2 r
7 R& Z( V, z$ o) A0 n
支持!
回复

使用道具 举报

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

9 ?1 Z# S! l& {% W小弟还在学习阶段,目前的目标是知道执行的流程。7 i6 k' X; N3 F7 r
这里面有很多细节没有写,能力有限,只能自己知道,不能表达。, K; ~. h* ~5 n$ t  S5 J; A
嘿。。。。& [% `; f" f/ s) p" \/ g$ T
所有大侠们如果有好东西能给小弟共享一份。
1 K; _- q! R5 S2 x) s
: D! S( `6 n' X2 \6 w, k0 v谢谢!
回复

使用道具 举报

发表于 2008-8-12 14:44:11 | 显示全部楼层
原帖由 winbondowen 于 2008-7-27 00:11 发表 7 F! @" h, C! u/ D' \# c+ @
  ROM中將DXE的驅動讀出,執行執行他們,這時會執行到Driver) _* t; I  r& h
中的Support(),Start()兩個功能函數。在這兩個函數中你可以註冊自己的PPI ...
& Y' G' h4 s' \) M. c. p6 M6 t; Q

: }8 O7 a* B" |) ~) ?+ vPPIs are registered during PEI phase, but Support()/Start() are invoked in DXE driver binding protocol,
! v3 o' _& B6 a8 HFor more precisely, I think the "PPI" you mentioned is the "PROTOCOL" rather than "PPI".1 s  _* k2 h* E% G% U  Y% }* s$ U6 `
" b! |* M; r: e. J  \
[ 本帖最后由 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:
& E# b) w  C/ Z5 R& h, G   Yes. I make a mistake.: z0 V0 L0 @$ n/ D( Q+ Z  q
      PPI:     A PEIM to PEIM interface./ P7 i! {" j0 K+ E. J8 {
      PROTOCL: A Interface between Hardware(or firmware) and software.
6 H; x# t0 u$ l      reference[http://www.biosren.com/viewthread.php?tid=207]
; D9 e% C- q, |; f. a; \   so, PPI execute at PEI step and Initialize hardware. PROTOCOL execute by DXE step.
9 l6 U+ g8 ?0 N   Thanks.
回复

使用道具 举报

发表于 2008-8-20 17:47:21 | 显示全部楼层
原帖由 winbondowen 于 2008-7-27 00:11 发表 DXE:
7 p3 ~  L: @& }     從PEI到DXE切換時轉過來一個HOBLIST參數,DXE會在這個HOB中找到Memory的使用情況,然後根據這些情況將BIOS引到內存(這是EFI的做法)。在EDK在DXE時重新定位一下內存。
  z) W* E: y- X7 g7 R接著就會定義我們經常使用到的gST表,gRT表。接著是申明一些Protocol(先不關心這些事)。
. C1 z% h: H9 |8 H) N" K: ?# K   等這些該加的PPI,Protocol加完了,CoreDispatcher()就出場了。他會的功能類似PEIDispatcher()。從我們BIOS ROM中將DXE的驅動讀出,執行執行他們,這時會執行到Driver
/ b% c( _4 r6 C9 Z8 S0 k" ^8 [中的Support(),Start()兩個功能函數。在這兩個函數中你可以註冊自己的PPI,為其他驅動提供服務。
4 v" Q- R/ j* i7 O, y   到些BIOS的引導其他完成。接著該進OS了,看Linux 0.11吧,操作系統是怎麼做事情的。.
; \# G; V3 L2 Z2 P4 `3 f4 {
! ~4 D- n4 \; j2 I8 j
There are mistakes,
1 w1 b9 b6 ~0 V. B: o6 V' M8 g1 c& G1.gST and gRT are init after the DXE architectural protocols have been loaded, those protocols response for creating Dxe foundation.* r% j1 X+ W5 Q- s" H/ a
. p; O. \% C( ^8 u3 r
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 t, I" q) Y; i% m0 N, v! `The CoreDispatcher() executes all trusted Dxe drivers and just register the Binding protocol if the driver is EFI1.1 driver model.
/ _  |' P; |% U. LFurthermore, Support()/Start() are invoked in BDS phase over the CoreConnectController() rather than CoreDispatcher().
0 C. ]: ]: f7 O- q) `* V. M8 z  ~: M% ~$ I: ^
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 大侠的指点。
& A) r+ x4 y6 A0 C4 u* \* z: `
回复

使用道具 举报

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

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

原帖由 ichirohiro 于 2008-8-20 17:47 发表 % h1 m6 j7 n' V
...
0 x' Y2 L2 ?$ B1 u2.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 T7 d( \9 `, M) a, bThe CoreDispatcher() executes all trusted Dxe drivers and just register the Binding protocol if the driver is EFI1.1 driver model.
2 P' z) X8 r* j/ H1 _Furthermore, Support()/Start() are invoked in BDS phase over the CoreConnectController() rather than CoreDispatcher().

) A5 g: e9 G% N    在Framework的spec DxeCis.pdf里面也是这么说的,DXE CoreDispatcher()里面,对于EFI1.1 driver model的driver只会安装Handler和Interface到Binding protocol,到BDS才会去执行Support()和Start().. s( ]  ]3 a' Y  _" J
    但是,我在看code时,发现在CoreDispatcher()-->CoreStartImage()里面call image之后有这么一句:  (file:image.c)
2 w& a4 S" j; D" ?9 j: B  //
( V5 K6 w1 M1 I4 E) m" X  // Go connect any handles that were created or modified while the image executed.) y. @# f' a# t2 w( d" o
  //
' E- e4 T) J4 z1 n" ]0 L+ P  CoreConnectHandlesByKey (HandleDatabaseKey);

0 k. Y: Z" L7 \2 j7 ?) G这里的HandleDatabaseKey是call image之前由CoreGetHandleDatabaseKey()得到的gHandleDatabaseKey
. o, ?) R6 c" i8 N- g' `6 I2 N而CoreConnectHandlesByKey会调用到:
- J7 k# O: h, O6 V1 f  //8 d' U& H! v! r# M
  // Connect all handles whose Key value is greater than Key
4 M% A4 [. L2 v" V! A6 N) Z  //
2 f' r  A3 s; m1 ]5 D/ B  for (Index = 0; Index < Count; Index++) {
6 N" N) J6 W, [, X5 g8 I5 h    CoreConnectController (HandleBuffer[Index], NULL, NULL, TRUE);( U& [) P" @! g* y9 J. E. b/ C3 M
  }
% _3 V$ M0 z" w4 q( u
所以,照code看,当在Driver中安装一个Handle和Interface到Binding Protocol后(gHandleDatabaseKey会++,IHandle的Key=gHandleDatabaseKey)
/ @+ o) K. m, a, m& u1 @/ _  z是会去ConnectController的,也会执行对应的Support()和Start()才对!!
" F" s- P! n5 H, W+ ^$ ~
4 B( d3 g& C2 n7 a不知道我想的哪里有问题???欢迎大家指正.
( e' `* A( P1 y/ J( e
4 g; a$ F: k- k# a6 x1 b5 d8 E[ 本帖最后由 xtdumpling 于 2008-9-18 15:25 编辑 ]
回复

使用道具 举报

发表于 2008-9-19 14:44:41 | 显示全部楼层
这段code似乎是一个向后兼容的行为,不必太care。
9 w( i0 s9 E' @. Q) ]一个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 | 显示全部楼层
了解了.
# D- A$ A! v/ Z  }+ n% }0 E% n% V非常 感谢!!!
回复

使用道具 举报

发表于 2008-9-23 16:48:56 | 显示全部楼层
在读DXEmain时,1 K/ t0 k( f- {+ p3 p4 c% {# x
Status = CoreInitializeImageServices(HobStart);--->CoreInstallProtocolInterface();--->CoreInstallProtocolInterfaceNotify();中,
: o% L7 b5 x! J0 U4 r+ a5 J; H9 U//
! t1 K+ X5 m* w3 j1 [: d& ?& G5 [// Notify the notification list for this protocol.5 }, S3 V; @4 p8 }
//
$ L' Y; A) L- w' I% m$ Fif (Notify) {) ^7 r8 [! T( [& ]8 H# `
  CoreNotifyProtocolEntry(ProtEntry);( r* {% b; ^# ^* \( B
}    里Signal了Event. MS是说一个handle安装了一个protocol后就signal一次.
9 K; B9 B" t2 p1 B0 u8 S有个问题请教一下大家: 这段是在DXE很靠前的位置执行的,但是在它之前我没有看到DXE中有相关的CreateEvent出现?哪位高手能说说这部分代码的流程呢?
回复

使用道具 举报

发表于 2008-9-23 17:04:14 | 显示全部楼层
原帖由 xtdumpling 于 2008-9-16 13:34 发表
" p& l$ w5 s5 O: k! T0 M7 g  \* Y请楼上的兄弟分析下BS的RegisterProtocolNotify也就是CoreRegisterProtocolNotify是做什么用的?怎么用?% @, B: _8 F$ Z- {" L1 U
谢谢!
0 `. f) C) @$ X, l
......" j% _" V: x5 R; C: L- s# T- w: r

! h8 V8 g2 y4 ?
9 x; K% B5 H1 {[ 本帖最后由 xtdumpling 于 2008-9-23 17:24 编辑 ]
回复

使用道具 举报

发表于 2008-9-24 12:43:45 | 显示全部楼层
原帖由 xtdumpling 于 2008-9-23 17:04 发表 : E/ _* }5 w' a, X6 h  D3 P% _: M
$ ?' q( f; x# i& f
......+ h, g( L2 b) C2 d
* W( h; F7 ^2 r' k
Signal的Event是不是在各个TPL级上挂载一些待处理的事件,一旦restore(TPL)的话,比当前TPL级高的pending事件就回被处理掉?
3 [6 J; Z% O% v7 R* t如果是这样的话,Timer事件是如何处理的呢,没有找到相关的代码呀?Xt指点一下再~
回复

使用道具 举报

发表于 2008-9-24 19:00:46 | 显示全部楼层
Timer是挂在8259的IRQ0的中断处理程序上面的, 大概每秒18.3次调用CoreTimerTick()-->CoreCheckTimers()6 w: [% ~: l8 d0 F' ?$ p+ ?* d
TPL=30
回复

使用道具 举报

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

本版积分规则

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

GMT+8, 2025-12-1 08:35 , Processed in 2.780839 second(s), 17 queries .

Powered by Discuz! X3.5

© 2001-2025 Discuz! Team.

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