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

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

[复制链接]
发表于 2008-7-27 00:11:28 | 显示全部楼层 |阅读模式
  最近在工作看到机台有启动过程中把SPI ROM数据清空,但苦与没有办法很好的Debug(PCA没有架起来),所有与EDK为对象好好的读了一把。: {9 }! F) R8 E" C, C; B. o/ o
- j; H0 Z# ?+ S% V
SEC/CEI:- m5 M6 l  P- G% l
  UEFI BIOS启动时先会执行SEC/CEI,这个阶段在实现的BIOS Code中初始化Debug Port,进入Big Mode,CPU的MicroCode,CacheToRAM的转换.然后跳转到PEI阶段。$ S8 r  R2 U/ }# A6 j* p6 W- }
在EDK中这部分被成了Load FvRecovery.fd文件,这个文件类似与我们的BIOS ROM.里面是我们编译后生成的二进制代码。在这个阶段最主要的是将这个文件加载到内存中(Windows API将文件加载到内存,看API函数).
1 \/ V: [8 I( ~+ C: }
) C' e* ?5 G' {+ A) mPEI:
& U* c* f+ |' \  r$ c2 {   从这里开始UEFI BIOS和EDK执行基本相同,只是一个是从SPI ROM中定位一个地址(PEIM的开始地址),一个是从内存中定位一个地址(PEIM的开始地址)。从这里开始只讲EDK的执行, h5 S" X3 K) T. D( Z( x4 N; e
  EDK调用InitializeMemoryService函数,将HobList清空,peiservice清空。
; z1 T, v+ c) V' S      InitializePPIService函数,将PPI队列清空,这个队列长0x3F.
% r: l4 J5 k6 A          InitializeSercurityService函数,将Notify队列清空。5 R. N9 y% }9 S) r
          InitializeDispatcherData函数,将Dispatcher队列清空。
; l; o  o7 O: {: {( p, a# x  接着由PeiBuildHobGuid来建立一个HOB(S3返回时这时应该有这个HOB,不用建立,直接使用了,这样就会进入另外一个流程,可以这个EDK不能调试S3,不知道怎么走)。然后由(*PeiServices)->InstallPpi()将这个新HOB加入到PPI中。
7 U' Q  t+ H  K: d1 S0 R1 n    由于在SEC阶段转了以下这几具PPI,所以在执行PEI的Dispatcher之前会先安装东西:8 S/ H4 [% _9 O, m1 ~+ |
      EFI_PEI_PPI_DESCRIPTOR    gPrivateDispatchTable[] = {: Y  l- E: ~  f, U: }, a
       {EFI_PEI_PPI_DESCRIPTOR_PPI, &gEfiNtLoadAsDllPpiGuid, &mSecNtLoadAsDllPpi},0 h" `8 Y5 l& t: ^, \
       {EFI_PEI_PPI_DESCRIPTOR_PPI, &gNtPeiLoadFileGuid, &mSecNtLoadFilePpi},
% R2 b  }/ ^' j6 Z- `2 Z) k       {EFI_PEI_PPI_DESCRIPTOR_PPI, &gPeiNtAutoScanPpiGuid, &mSecNtAutoScanPpi},+ H4 z4 U1 U, L% a% }; c
       {EFI_PEI_PPI_DESCRIPTOR_PPI, &gPeiNtThunkPpiGuid, &mSecWinNtThunkPpi},2 P) `2 q6 n; z. h
       {EFI_PEI_PPI_DESCRIPTOR_PPI, &gPeiStatusCodePpiGuid, &mSecStatusCodePpi},) E3 T( e. `- ~9 r, s' u
       {EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST, &gNtFwhPpiGuid, &mSecFwhInformationPpi}
& d0 o% K" U  w/ t  F/ g; F: Z2 I: m     };
7 j) v0 o, e; s: l    每个PPI是由{类型,GUID(名字,以后就根据这个来找到它的),Function_Entry_Address}组成。" {5 s0 a& R1 Y" z
   这些PPI会在PEIDispatcher中用到。
0 @. I2 j  A; X( |+ m' z0 R   安装完这此东西这开始执行PEIDispatcher函数,函数从BIOS ROM文件中找出PEI的Image(怎么找到,请读一下FV_HEAD(EFI_HEAD),里面讲到了如何区分Image类型),然后定位到PEI Image的入口地址,执行他。在我们的的PEI中,我们一般会申明一个PPI,这个就是这个PEI提供一些服务,PEIDispatcher会将他们加入到PPI-List中,以后其他Image也可以调用他的提供的功能。
+ C5 s7 J0 h$ Q6 r9 q   最后EDK会加载一个叫DXEIPL的PEI,DXEIPL提供一个PPI服务,这个PPI的功能是实现从PEI到DXE的切换,这个PPI里面为DXE做了很多的预准备,加载了很多PPI,如对BIOS的解压方法等。6 h. s+ p; ~. G: [. I' u- ?  P
   SwitchStacks (
# W4 E' q  j4 J8 R5 X- F       (VOID *) (UINTN) DxeCoreEntryPoint,1 ~! M, l4 ?" i$ C% D  N
       (UINTN) (HobList.Raw),
. n8 N! w3 x% I# \, O$ [       (VOID *) (UINTN) TopOfStack,
/ J- v& a0 G" T( `$ v       (VOID *) (UINTN) BspStore; g+ G  S& {2 B
    );: a" \7 M) }* |! I. w9 t
  用过汇编的人对这个技术一定很熟悉,不多说了(我别不清,咯。。。); b* H" ]  j9 a2 ?* d

/ E+ w  G% x/ h8 r2 |- WDXE:% ~2 ?/ c0 ?& ?5 `
     从PEI到DXE切换时转过来一个HOBLIST参数,DXE会在这个HOB中找到Memory的使用情况,然后根据这些情况将BIOS引到内存(这是EFI的做法)。在EDK在DXE时重新定位一下内存。9 q0 s+ s$ |5 f  k; M& ~
接着就会定义我们经常使用到的gST表,gRT表。接着是申明一些Protocol(先不关心这些事)。
2 t+ W# ^% V0 G" X, V3 N  [& J$ w9 j   等这些该加的PPI,Protocol加完了,CoreDispatcher()就出场了。他会的功能类似PEIDispatcher()。从我们BIOS ROM中将DXE的驱动读出,执行执行他们,这时会执行到Driver3 Y/ e0 a- Z3 D, r
中的Support(),Start()两个功能函数。在这两个函数中你可以注册自己的PPI,为其他驱动提供服务。* T$ T# n" b1 W0 r4 d
   到些BIOS的引导其他完成。接着该进OS了,看Linux 0.11吧,操作系统是怎么做事情的。
$ u; _% M' _7 u" W   
& t. }- W* a, uDriver:
) W" w/ G, M: W0 y* R    我们的驱动什么为在PEI和DXE等不同阶段执行呢?
: K! ~4 g" d: @6 Y4 \! F" f2 N  大家请看一下我们的驱动的makefile.(EDK中的*.inf)0 k& \9 C* B4 t4 A
  [defines]! Z' e& \" Y  A- V9 M; _5 v% [
  BASE_NAME            = OWEN1 g0 R3 j3 ?) r% a7 o0 @
  FILE_GUID            = 1EDD13C1-62EF-4262-A1AA-0040D0830110: m8 w& C  n) |! Z+ _! D* O& T
  COMPONENT_TYPE       = BS_DRIVER/ g& E$ W" D" Q' [" U6 S
) |" F( c" L+ g. B4 a: g5 S
  BASE_NAME告诉编译器最终生成的驱动的名字。' r: h6 T: D4 Z+ d* a' Y9 g: ]
  FILE_GUID就是这个驱动的GUID名字,在BIOS中引用某个驱动就是根据它来调用和识别。3 J" S8 [% C  H0 |
  COMONENT_TYPE会告诉编译器生成驱动的类型,是PEI,DXE,等。5 f7 O& ]6 I( E
  在EDK中有一个FWVolume.c实现的功能就是帮我们把这个TYPE转换面相应的扩展名
4 Y) [! t: y5 j6 V' b5 t* ?  S  COMP_TYPE_EXTENSION  mCompTypeExtension[] = {4 l( x. Z( {3 w) j) M9 ]
  {"bs_driver",  ".dxe" },3 R9 ?3 z$ h, z1 t
  {"rt_driver",  ".dxe" },# D( |9 k* _: p9 t% G" `
  {"sal_rt_driver", ".dxe"},
) J. E, V; ]9 u/ `/ d  {"security_core", ".sec"},4 C4 [( S! J3 S0 i$ P( J
  {"pei_core", ".pei"},
% n- s; v, {0 P  {"pic_peim", ".pei"},
) e8 b, q" n7 i: K3 O- o  {"pe32_peim", ".pei"},$ X& M' x+ q6 @8 N, f6 o1 O  M& g5 I$ s
  {"relocatable_peim", ".pei"},. T6 G: t9 U% ^! K1 d
  {"binary", ".ffs"},6 e; C/ d8 m0 h& b% U$ v" K. \( u6 b* ]
  {"application", ".app"},
2 O9 c9 j2 f  d. Q( \  {"file", ".ffs"},* c% v2 @% w+ c  v: f7 _$ A1 F, j
  {"fvimagefile", ".fvi"},) X0 Q5 ~1 V  K# f5 ?. I
  {"rawfile", ".raw"},
; V- S9 |/ l% F8 v4 G2 `/ Q  {"apriori", ".ffs"},$ s, D& `! b. i. t+ A
  {"combined_peim_driver", ".pei"},
4 _7 C& i/ l4 t- f4 b/ N2 [  { NULL,  NULL }
$ e% ^: V1 ^( O' h( U};+ X) P# [/ @- a6 e
' V- K8 k! M3 r7 t
了解了这些,接下我们可以看驱动篇了。(Go On Study... Forever), k9 D+ V! M3 q* |# o- b& u
   % }& V  H$ }8 ]4 k6 w5 l, f
         6 s' E9 L& j( g
  
发表于 2008-7-27 12:30:15 | 显示全部楼层
不错!
- O9 u7 u+ M! ?: e2 F' A4 d! q支持
! q- U5 [, ~+ w$ T. g继续
% v# Z" h' J& \8 m( w! Y加油- C: L) q' B+ J" B& {8 r: H
回复

使用道具 举报

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

回复 1# 的帖子

gPrivateDispatchTable 和COMP_TYPE_EXTENSION  没有搜到啊  是EDK专有的么?
4 _3 S7 Q( w! b* w0 D有看过跟gPrivateDispatchTable 类似的,但是里面的PPI不同。  l  \+ H& e" n, k' o  L) B9 v
还有这个COMP_TYPE_EXTENSION  没有找到过。FWVolume.c这个文件也没有发现。。
回复

使用道具 举报

发表于 2008-7-28 13:24:20 | 显示全部楼层
这东西虽说没有什么技术含量,但是总结一下还是非常好的。
" P. M& G6 M5 ?% ?- W$ d# x
6 B1 z" D9 @7 U/ B5 ~支持!
回复

使用道具 举报

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

# r5 s2 C6 ?/ L9 f小弟还在学习阶段,目前的目标是知道执行的流程。" }" L. b/ _; k' v9 a3 `
这里面有很多细节没有写,能力有限,只能自己知道,不能表达。% V* N8 M8 x; O9 T9 b
嘿。。。。1 H3 |5 F. F$ y9 O5 e
所有大侠们如果有好东西能给小弟共享一份。( T( {$ {0 \9 e& q; @7 ?
7 ]4 h% p) U# W7 W7 B' ]7 d3 Z2 p
谢谢!
回复

使用道具 举报

发表于 2008-8-12 14:44:11 | 显示全部楼层
原帖由 winbondowen 于 2008-7-27 00:11 发表
1 r  X& I8 W0 o0 R8 J/ D  ROM中將DXE的驅動讀出,執行執行他們,這時會執行到Driver! [5 [* K  \* ]  C- S% k
中的Support(),Start()兩個功能函數。在這兩個函數中你可以註冊自己的PPI ...

' i1 O7 N) S% |6 ^. h" O# ?
! @  q! V. A6 m  [PPIs are registered during PEI phase, but Support()/Start() are invoked in DXE driver binding protocol, / ?: J4 c% ~0 l: @
For more precisely, I think the "PPI" you mentioned is the "PROTOCOL" rather than "PPI".
7 r1 R% k+ f2 X: _) y
4 X# B) a# u8 V6 l! q+ o3 N+ a- 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:
7 \; V7 Y+ }: p5 l! ?$ C) b   Yes. I make a mistake.
4 A; h8 l/ }  j) q2 v" i5 v" @      PPI:     A PEIM to PEIM interface.
8 n7 I" S3 y- W. G0 L/ |# p0 t      PROTOCL: A Interface between Hardware(or firmware) and software.' E# R( ^/ {) d1 t, X$ v
      reference[http://www.biosren.com/viewthread.php?tid=207]' i- m  |- F: K! r+ l
   so, PPI execute at PEI step and Initialize hardware. PROTOCOL execute by DXE step.
* L1 c0 E0 q) A! t# B6 I   Thanks.
回复

使用道具 举报

发表于 2008-8-20 17:47:21 | 显示全部楼层
原帖由 winbondowen 于 2008-7-27 00:11 发表 DXE:
$ L# v' ~# p% b. @3 B; Q     從PEI到DXE切換時轉過來一個HOBLIST參數,DXE會在這個HOB中找到Memory的使用情況,然後根據這些情況將BIOS引到內存(這是EFI的做法)。在EDK在DXE時重新定位一下內存。
* |& c( \% ^' z9 n6 Z8 D接著就會定義我們經常使用到的gST表,gRT表。接著是申明一些Protocol(先不關心這些事)。8 f9 j% I- k8 r: r; M' D" K0 v: u; j
   等這些該加的PPI,Protocol加完了,CoreDispatcher()就出場了。他會的功能類似PEIDispatcher()。從我們BIOS ROM中將DXE的驅動讀出,執行執行他們,這時會執行到Driver
6 ~) i8 `8 Z6 W1 @# l' z中的Support(),Start()兩個功能函數。在這兩個函數中你可以註冊自己的PPI,為其他驅動提供服務。0 i, p  Q7 L- x4 x
   到些BIOS的引導其他完成。接著該進OS了,看Linux 0.11吧,操作系統是怎麼做事情的。.

: D$ ?% W1 C( K( v' _0 ]8 Z9 W: w
/ g( B- s8 u, W2 G. s, oThere are mistakes,
5 d4 ]. K, J) t4 j4 Y1.gST and gRT are init after the DXE architectural protocols have been loaded, those protocols response for creating Dxe foundation.
. m- b1 t9 N9 ~. w/ C
' H8 r, h7 s0 S- r+ K2.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.6 I4 Q) h& N3 [. I* M
The CoreDispatcher() executes all trusted Dxe drivers and just register the Binding protocol if the driver is EFI1.1 driver model.
5 K- X8 q& m4 ~Furthermore, Support()/Start() are invoked in BDS phase over the CoreConnectController() rather than CoreDispatcher().5 B2 z' V8 n, c3 i% m
  Y0 f6 O& {  E$ Y* L4 n
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 大侠的指点。
- N9 Z7 L; L# F2 y8 p8 ?
回复

使用道具 举报

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

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

原帖由 ichirohiro 于 2008-8-20 17:47 发表 ) x/ t7 C! @) U7 f
.... s$ e6 X7 ^& b; L! [7 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., J8 I' P* R- [1 K7 O) y
The CoreDispatcher() executes all trusted Dxe drivers and just register the Binding protocol if the driver is EFI1.1 driver model., ~1 S: L9 n8 \" Y/ ?
Furthermore, Support()/Start() are invoked in BDS phase over the CoreConnectController() rather than CoreDispatcher().

2 ]7 E* V* ^' R# P    在Framework的spec DxeCis.pdf里面也是这么说的,DXE CoreDispatcher()里面,对于EFI1.1 driver model的driver只会安装Handler和Interface到Binding protocol,到BDS才会去执行Support()和Start().
. S6 ^0 {- V/ a! k! X8 n3 o5 x/ x    但是,我在看code时,发现在CoreDispatcher()-->CoreStartImage()里面call image之后有这么一句:  (file:image.c)0 y- r% }- M& m+ h) r1 d% Y% x7 I
  //% u8 d* O" C& J* \4 a
  // Go connect any handles that were created or modified while the image executed.4 ]0 D# a! x1 U' p/ G
  //) `: X2 f1 u% ^! Q' R7 L5 O
  CoreConnectHandlesByKey (HandleDatabaseKey);
# T$ a1 C  E0 r# Q  F9 W1 b
这里的HandleDatabaseKey是call image之前由CoreGetHandleDatabaseKey()得到的gHandleDatabaseKey
$ [# L( A9 @; J, j* e  A8 p' x! h而CoreConnectHandlesByKey会调用到:% r4 b) t1 L. `" k4 [
  //3 t. M7 W' J8 W' Q9 j# M" ^3 v
  // Connect all handles whose Key value is greater than Key
, V* V! K4 A" I2 ]1 {  //
5 Y8 ^1 _& Y, w. ]9 s  for (Index = 0; Index < Count; Index++) {! J6 {: }3 Y  d  t0 V
    CoreConnectController (HandleBuffer[Index], NULL, NULL, TRUE);$ B: v: |& J: _6 D# Q
  }

( ]) v4 p0 M- f  c* Z3 k# Z- r所以,照code看,当在Driver中安装一个Handle和Interface到Binding Protocol后(gHandleDatabaseKey会++,IHandle的Key=gHandleDatabaseKey)
6 T" Q9 }4 f: m4 }. K是会去ConnectController的,也会执行对应的Support()和Start()才对!!0 Y! {' G1 N' A' c2 q# y5 p1 a0 V  V
, f+ m) @2 o0 }1 L/ e1 B% C0 }
不知道我想的哪里有问题???欢迎大家指正.
# {2 Y! A% x' D' P0 m! K
( G8 z/ X. p+ D% ~$ i3 N[ 本帖最后由 xtdumpling 于 2008-9-18 15:25 编辑 ]
回复

使用道具 举报

发表于 2008-9-19 14:44:41 | 显示全部楼层
这段code似乎是一个向后兼容的行为,不必太care。
. O/ C" l) ]  Z) e- q6 G一个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 | 显示全部楼层
了解了.
$ R% p, {: V/ G6 |4 K非常 感谢!!!
回复

使用道具 举报

发表于 2008-9-23 16:48:56 | 显示全部楼层
在读DXEmain时,
8 k+ u2 L$ c6 RStatus = CoreInitializeImageServices(HobStart);--->CoreInstallProtocolInterface();--->CoreInstallProtocolInterfaceNotify();中," T. N. y. j% z0 c
//4 p& |, H( N- r" p
// Notify the notification list for this protocol.. j* e5 D. L: `5 K# j3 w: w
//6 Z( X& x* C5 ~4 f. _
if (Notify) {
' z' Q2 A" O# B' o  CoreNotifyProtocolEntry(ProtEntry);& r  l* ^, j; z1 B6 |
}    里Signal了Event. MS是说一个handle安装了一个protocol后就signal一次.. b4 b" J* F1 o1 e3 O
有个问题请教一下大家: 这段是在DXE很靠前的位置执行的,但是在它之前我没有看到DXE中有相关的CreateEvent出现?哪位高手能说说这部分代码的流程呢?
回复

使用道具 举报

发表于 2008-9-23 17:04:14 | 显示全部楼层
原帖由 xtdumpling 于 2008-9-16 13:34 发表
* k" }1 w, N- T9 O请楼上的兄弟分析下BS的RegisterProtocolNotify也就是CoreRegisterProtocolNotify是做什么用的?怎么用?9 r4 Z) u+ ^0 N5 o! U
谢谢!

  m; X4 H, p6 n9 W' o0 h......1 S/ T' W3 g! K- m! `$ _4 p
  J, g* \0 F9 j+ Q% C  r- a
; n/ S/ D( e5 h& D' E
[ 本帖最后由 xtdumpling 于 2008-9-23 17:24 编辑 ]
回复

使用道具 举报

发表于 2008-9-24 12:43:45 | 显示全部楼层
原帖由 xtdumpling 于 2008-9-23 17:04 发表   I6 W4 |) Y6 L2 `. ^

3 e1 V* N: l4 p4 @: W* }......
3 y+ Y" [  W& w2 V& ~" |
, b3 s, U( t/ h9 i
Signal的Event是不是在各个TPL级上挂载一些待处理的事件,一旦restore(TPL)的话,比当前TPL级高的pending事件就回被处理掉?) i% u6 H. w' {
如果是这样的话,Timer事件是如何处理的呢,没有找到相关的代码呀?Xt指点一下再~
回复

使用道具 举报

发表于 2008-9-24 19:00:46 | 显示全部楼层
Timer是挂在8259的IRQ0的中断处理程序上面的, 大概每秒18.3次调用CoreTimerTick()-->CoreCheckTimers()
/ l  T  ]- f+ l7 E7 v2 q* {TPL=30
回复

使用道具 举报

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

本版积分规则

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

GMT+8, 2026-9-22 15:12 , Processed in 0.079264 second(s), 17 queries .

Powered by Discuz! X3.5

© 2001-2025 Discuz! Team.

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