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

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

[复制链接]
发表于 2008-7-27 00:11:28 | 显示全部楼层 |阅读模式
  最近在工作看到机台有启动过程中把SPI ROM数据清空,但苦与没有办法很好的Debug(PCA没有架起来),所有与EDK为对象好好的读了一把。
3 l/ x  J# v7 Z2 Z
- {& ~6 Z6 L: P- H# L3 wSEC/CEI:! K) x9 P) E% U
  UEFI BIOS启动时先会执行SEC/CEI,这个阶段在实现的BIOS Code中初始化Debug Port,进入Big Mode,CPU的MicroCode,CacheToRAM的转换.然后跳转到PEI阶段。. |! ^; x0 t8 u" }3 o  @
在EDK中这部分被成了Load FvRecovery.fd文件,这个文件类似与我们的BIOS ROM.里面是我们编译后生成的二进制代码。在这个阶段最主要的是将这个文件加载到内存中(Windows API将文件加载到内存,看API函数).- a- [: p& C: n+ q: Q
3 P/ l/ w) u) [# k! Q( d7 f$ I6 {
PEI:# S( }* q# ^; s( z  e
   从这里开始UEFI BIOS和EDK执行基本相同,只是一个是从SPI ROM中定位一个地址(PEIM的开始地址),一个是从内存中定位一个地址(PEIM的开始地址)。从这里开始只讲EDK的执行, b' Y3 L/ w, n) }9 L0 r
  EDK调用InitializeMemoryService函数,将HobList清空,peiservice清空。. M& ~: }) o$ W1 y0 V) q+ ?' r5 `
      InitializePPIService函数,将PPI队列清空,这个队列长0x3F.
$ A+ J4 p" N4 G          InitializeSercurityService函数,将Notify队列清空。
7 E% v0 ]* \. R          InitializeDispatcherData函数,将Dispatcher队列清空。
& a8 @+ b7 ^6 ?5 d; Z7 k  接着由PeiBuildHobGuid来建立一个HOB(S3返回时这时应该有这个HOB,不用建立,直接使用了,这样就会进入另外一个流程,可以这个EDK不能调试S3,不知道怎么走)。然后由(*PeiServices)->InstallPpi()将这个新HOB加入到PPI中。
1 B) `! L7 X9 C& l8 ^9 I+ e    由于在SEC阶段转了以下这几具PPI,所以在执行PEI的Dispatcher之前会先安装东西:
3 F5 K" P7 a% L, Y2 B. P' e      EFI_PEI_PPI_DESCRIPTOR    gPrivateDispatchTable[] = {
/ k! o' C0 t3 P* N2 x3 a       {EFI_PEI_PPI_DESCRIPTOR_PPI, &gEfiNtLoadAsDllPpiGuid, &mSecNtLoadAsDllPpi},$ a* V9 Z; O# U1 s9 B8 U* o  s" S
       {EFI_PEI_PPI_DESCRIPTOR_PPI, &gNtPeiLoadFileGuid, &mSecNtLoadFilePpi},. T7 Y# }3 `! P7 B$ H
       {EFI_PEI_PPI_DESCRIPTOR_PPI, &gPeiNtAutoScanPpiGuid, &mSecNtAutoScanPpi},
* u: S1 l" r  D* v9 Q" q- J( n7 R6 w       {EFI_PEI_PPI_DESCRIPTOR_PPI, &gPeiNtThunkPpiGuid, &mSecWinNtThunkPpi},
+ i2 Z( k' i3 U& g5 W2 e5 N       {EFI_PEI_PPI_DESCRIPTOR_PPI, &gPeiStatusCodePpiGuid, &mSecStatusCodePpi},
1 J2 J/ U/ S  z- E1 u( Q/ w* b       {EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST, &gNtFwhPpiGuid, &mSecFwhInformationPpi}5 J. `6 j: h& Q/ X
     };% ^9 W" D# I' I4 }  B" ]5 S! P8 h
    每个PPI是由{类型,GUID(名字,以后就根据这个来找到它的),Function_Entry_Address}组成。
- p$ C0 U6 u3 T   这些PPI会在PEIDispatcher中用到。
, P: ^2 m$ H- ^. O# T/ u; P3 f   安装完这此东西这开始执行PEIDispatcher函数,函数从BIOS ROM文件中找出PEI的Image(怎么找到,请读一下FV_HEAD(EFI_HEAD),里面讲到了如何区分Image类型),然后定位到PEI Image的入口地址,执行他。在我们的的PEI中,我们一般会申明一个PPI,这个就是这个PEI提供一些服务,PEIDispatcher会将他们加入到PPI-List中,以后其他Image也可以调用他的提供的功能。0 L9 F" x# u9 ?- i1 T
   最后EDK会加载一个叫DXEIPL的PEI,DXEIPL提供一个PPI服务,这个PPI的功能是实现从PEI到DXE的切换,这个PPI里面为DXE做了很多的预准备,加载了很多PPI,如对BIOS的解压方法等。% p8 e- _6 Q1 E' r, o  {: ]6 d
   SwitchStacks (
& e1 C9 m6 p, u# x# p3 }       (VOID *) (UINTN) DxeCoreEntryPoint,# W4 A: _+ P% a" x, p  Z
       (UINTN) (HobList.Raw),
* n& b& i  Y! H; V7 w( w8 f" L) B" c       (VOID *) (UINTN) TopOfStack,$ d$ H8 |& Z# U6 ]9 ]
       (VOID *) (UINTN) BspStore! ]' t1 I5 w9 q( e$ C
    );1 F& z( s7 Q8 c8 k+ i9 w
  用过汇编的人对这个技术一定很熟悉,不多说了(我别不清,咯。。。)
5 M6 Y/ ^, B0 Y7 I& k. U7 ~* `1 k' i$ i; @0 i) ~+ w
DXE:# t, g9 e& q& E7 I
     从PEI到DXE切换时转过来一个HOBLIST参数,DXE会在这个HOB中找到Memory的使用情况,然后根据这些情况将BIOS引到内存(这是EFI的做法)。在EDK在DXE时重新定位一下内存。- T7 h2 g5 h, W: C5 Z. [) N
接着就会定义我们经常使用到的gST表,gRT表。接着是申明一些Protocol(先不关心这些事)。0 t5 e- b3 ^1 d: j/ u6 b+ H4 \
   等这些该加的PPI,Protocol加完了,CoreDispatcher()就出场了。他会的功能类似PEIDispatcher()。从我们BIOS ROM中将DXE的驱动读出,执行执行他们,这时会执行到Driver
. }( ~, j2 y! v5 ]1 e* g/ E中的Support(),Start()两个功能函数。在这两个函数中你可以注册自己的PPI,为其他驱动提供服务。
3 T( U) ^' W( D9 x% k4 V" p   到些BIOS的引导其他完成。接着该进OS了,看Linux 0.11吧,操作系统是怎么做事情的。( C7 P" z" D9 ~  n5 k+ o
   6 |* ]- z0 r$ o1 ?( j
Driver:
5 y, F+ O8 O0 J# m    我们的驱动什么为在PEI和DXE等不同阶段执行呢?' C/ U1 o9 F" f: l; r
  大家请看一下我们的驱动的makefile.(EDK中的*.inf)
  y1 i- A2 o2 d1 o" U: [1 b  [defines]' c  Y# V' w, V+ P5 d- J
  BASE_NAME            = OWEN6 T; g# r2 H+ e2 Q
  FILE_GUID            = 1EDD13C1-62EF-4262-A1AA-0040D0830110
' U( V3 l9 S6 e+ |& w  COMPONENT_TYPE       = BS_DRIVER
1 u# j( A5 D2 {  C5 h: |7 I( m3 H+ l! K8 ?! W
  BASE_NAME告诉编译器最终生成的驱动的名字。! v4 k$ W: }/ H  v7 P8 P# z: R5 V
  FILE_GUID就是这个驱动的GUID名字,在BIOS中引用某个驱动就是根据它来调用和识别。
( e1 M" b  P4 d% m  COMONENT_TYPE会告诉编译器生成驱动的类型,是PEI,DXE,等。
, J" d0 _# N6 K: k3 ~  在EDK中有一个FWVolume.c实现的功能就是帮我们把这个TYPE转换面相应的扩展名( [% E: w2 v; \: x0 F( z8 @9 Q
  COMP_TYPE_EXTENSION  mCompTypeExtension[] = {
, L- q) u+ T# h  {"bs_driver",  ".dxe" },
2 l" e3 W' o: P- p  {"rt_driver",  ".dxe" },; @2 r; [( q% W; p" [
  {"sal_rt_driver", ".dxe"},
: C7 ?# v: u8 X3 C/ t6 @9 G  {"security_core", ".sec"},
& a7 R8 M: H3 l$ W+ L' |, z  {"pei_core", ".pei"},% L; w/ j0 s. ~* G' q# T
  {"pic_peim", ".pei"},
. v! w% A! g3 f  {"pe32_peim", ".pei"},' Y7 N9 A# X. T( @# n2 z" y
  {"relocatable_peim", ".pei"},4 s+ {$ i  f0 A8 c6 e& a  i+ N
  {"binary", ".ffs"},/ r+ X! y. _- y1 e& c4 O
  {"application", ".app"},8 b; i0 K- e% y" W% t$ B  p
  {"file", ".ffs"},1 ]6 S/ ?* [9 Y( H, _8 J& M$ m
  {"fvimagefile", ".fvi"},4 n. l& Q' d  V7 u; }1 x6 h# a+ e
  {"rawfile", ".raw"},
% g2 D4 v+ ?1 i, W$ a: U  {"apriori", ".ffs"},
8 T$ F3 ^6 D( z  {"combined_peim_driver", ".pei"},
3 W% H/ x# G$ e+ W- m  { NULL,  NULL }4 g! {# b8 c% E2 q) Z# C1 X
};
- P. Y- [5 N4 m% f& ?& m* `( L. M) q2 ]
了解了这些,接下我们可以看驱动篇了。(Go On Study... Forever)
" x( Z: \3 }. B; g   ( i1 }7 Y" R& {) _
         
+ b" U% R1 X8 z- ^2 R8 j+ X  
发表于 2008-7-27 12:30:15 | 显示全部楼层
不错!0 m2 [- ]9 J2 q
支持
- K1 M* v/ f, e5 L8 C继续
( D  |8 W3 A4 u6 g4 }% h加油& z9 ?  `  I' _+ P% @+ i
回复

使用道具 举报

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

回复 1# 的帖子

gPrivateDispatchTable 和COMP_TYPE_EXTENSION  没有搜到啊  是EDK专有的么?# l" z4 W  k8 R, u
有看过跟gPrivateDispatchTable 类似的,但是里面的PPI不同。. p* @: G. T  W- B9 @  l+ N: Z6 v8 c# F- L
还有这个COMP_TYPE_EXTENSION  没有找到过。FWVolume.c这个文件也没有发现。。
回复

使用道具 举报

发表于 2008-7-28 13:24:20 | 显示全部楼层
这东西虽说没有什么技术含量,但是总结一下还是非常好的。
/ q; U# j1 _" ~2 S4 a+ y3 U  n" G6 E% k1 y
支持!
回复

使用道具 举报

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

* X" ]# R7 n* ~小弟还在学习阶段,目前的目标是知道执行的流程。
( s- S4 V* B% c这里面有很多细节没有写,能力有限,只能自己知道,不能表达。( a' a$ h, A/ E& Z2 W! k& d
嘿。。。。
' b, p5 F# h9 L! u所有大侠们如果有好东西能给小弟共享一份。
6 G7 U& L2 b' }* E0 N2 ~/ M1 X/ p
3 x6 \3 }' h- I& A: l谢谢!
回复

使用道具 举报

发表于 2008-8-12 14:44:11 | 显示全部楼层
原帖由 winbondowen 于 2008-7-27 00:11 发表
7 A  F& w4 l5 k1 h- V/ j1 ^) S# ?  ROM中將DXE的驅動讀出,執行執行他們,這時會執行到Driver
5 v) u. I* j! ?% F2 ~9 u# M( ?中的Support(),Start()兩個功能函數。在這兩個函數中你可以註冊自己的PPI ...

7 ]' G: a% k" g3 @4 a. U- ]$ W3 D# w' ?2 R
PPIs are registered during PEI phase, but Support()/Start() are invoked in DXE driver binding protocol, 0 W9 C; _/ ~1 Z4 _$ w3 ^7 A
For more precisely, I think the "PPI" you mentioned is the "PROTOCOL" rather than "PPI".
5 x3 Y# X2 Z# |1 P: I& ]
' e8 F) A: M0 D# d7 ]' J0 h[ 本帖最后由 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:
0 g/ ^, {, v, N0 [2 m3 K8 ^# [# U   Yes. I make a mistake.. }* R$ _+ n5 U& i
      PPI:     A PEIM to PEIM interface.5 S9 m5 P* J: ?
      PROTOCL: A Interface between Hardware(or firmware) and software.
/ K) A- |* w9 ^8 d; h! v2 l! c      reference[http://www.biosren.com/viewthread.php?tid=207]
, I: m/ G0 t3 D9 R! _, f/ h   so, PPI execute at PEI step and Initialize hardware. PROTOCOL execute by DXE step.
4 ~( U" S  I* `8 l- D   Thanks.
回复

使用道具 举报

发表于 2008-8-20 17:47:21 | 显示全部楼层
原帖由 winbondowen 于 2008-7-27 00:11 发表 DXE:
# T# n3 }& }4 C/ Y2 G  J     從PEI到DXE切換時轉過來一個HOBLIST參數,DXE會在這個HOB中找到Memory的使用情況,然後根據這些情況將BIOS引到內存(這是EFI的做法)。在EDK在DXE時重新定位一下內存。
3 A. b- l) y" n; F1 |% A5 s  F  p接著就會定義我們經常使用到的gST表,gRT表。接著是申明一些Protocol(先不關心這些事)。  u( @" Q5 @% [7 M2 e+ z7 k0 e: v
   等這些該加的PPI,Protocol加完了,CoreDispatcher()就出場了。他會的功能類似PEIDispatcher()。從我們BIOS ROM中將DXE的驅動讀出,執行執行他們,這時會執行到Driver
, z% W* P& K" r& i2 t中的Support(),Start()兩個功能函數。在這兩個函數中你可以註冊自己的PPI,為其他驅動提供服務。. m1 p; I% B( F9 E; x
   到些BIOS的引導其他完成。接著該進OS了,看Linux 0.11吧,操作系統是怎麼做事情的。.
% `! K6 ?% b  J+ y+ `2 r
" s& g" y7 n! e8 L. B7 {
There are mistakes,8 D+ q9 X7 I: g3 j
1.gST and gRT are init after the DXE architectural protocols have been loaded, those protocols response for creating Dxe foundation.
9 |! ^# i4 M5 f, q6 [2 m2 n
! q7 _! o6 u. u# h2.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.& F" s0 G# t& Z2 }
The CoreDispatcher() executes all trusted Dxe drivers and just register the Binding protocol if the driver is EFI1.1 driver model.3 p1 p" @2 A0 K6 C' C& Y+ @4 t0 H
Furthermore, Support()/Start() are invoked in BDS phase over the CoreConnectController() rather than CoreDispatcher().
0 ~8 a5 K( E* k1 \  v2 R! [; H0 e  l9 h5 u, U6 W, Q' y
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 大侠的指点。7 ^3 a2 h. g7 L: ]1 V
回复

使用道具 举报

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

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

原帖由 ichirohiro 于 2008-8-20 17:47 发表 . c, V, [( v. ^( V  C: T
...! k& V% y6 x% ]
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 g% W% J4 d0 c$ F
The CoreDispatcher() executes all trusted Dxe drivers and just register the Binding protocol if the driver is EFI1.1 driver model.
2 I9 l* u5 D/ dFurthermore, Support()/Start() are invoked in BDS phase over the CoreConnectController() rather than CoreDispatcher().

+ ?) _3 k6 E  @( Y" E, S/ }8 Y    在Framework的spec DxeCis.pdf里面也是这么说的,DXE CoreDispatcher()里面,对于EFI1.1 driver model的driver只会安装Handler和Interface到Binding protocol,到BDS才会去执行Support()和Start().& `6 O' Q! G* `* I9 l+ J$ z
    但是,我在看code时,发现在CoreDispatcher()-->CoreStartImage()里面call image之后有这么一句:  (file:image.c)
8 l  d/ A( s4 E, @5 D  //* r$ e6 r: Q9 V  b% A1 j
  // Go connect any handles that were created or modified while the image executed.4 w+ `* P& }* B7 N' e. Y! ~( u8 C2 r
  //; Q% e! ~+ l4 e# ]
  CoreConnectHandlesByKey (HandleDatabaseKey);

4 R( k' g4 v! P2 o# b7 l这里的HandleDatabaseKey是call image之前由CoreGetHandleDatabaseKey()得到的gHandleDatabaseKey) f3 z; T6 Y0 W, |+ j
而CoreConnectHandlesByKey会调用到:' \, p( H+ Y3 M, x4 ]' P6 F
  //4 y5 O9 `/ d$ N' D# ^
  // Connect all handles whose Key value is greater than Key! R5 Z- w3 N3 Z/ ~: n( q* f
  //
0 S0 s' I& U+ y0 N8 G  for (Index = 0; Index < Count; Index++) {7 U1 i- W% q* F  u/ e  t7 |: `
    CoreConnectController (HandleBuffer[Index], NULL, NULL, TRUE);# r( B9 R. e0 R3 o  l0 A- G& B
  }
0 P+ K0 s6 ?1 N7 s- ^6 g: E
所以,照code看,当在Driver中安装一个Handle和Interface到Binding Protocol后(gHandleDatabaseKey会++,IHandle的Key=gHandleDatabaseKey); i) h2 O) u) g) h, Y. M9 ?, z/ n
是会去ConnectController的,也会执行对应的Support()和Start()才对!!6 ?9 j7 y# r* n5 |0 @/ `, t3 X# B

: u4 L$ c+ o1 @不知道我想的哪里有问题???欢迎大家指正.7 ?* ?* D! ]5 e

0 f( r% d/ |& |[ 本帖最后由 xtdumpling 于 2008-9-18 15:25 编辑 ]
回复

使用道具 举报

发表于 2008-9-19 14:44:41 | 显示全部楼层
这段code似乎是一个向后兼容的行为,不必太care。+ u1 ~/ |" `+ J8 E4 ?3 n. A1 I6 [# P0 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 | 显示全部楼层
了解了.+ ?; u6 R2 E8 X; J) e
非常 感谢!!!
回复

使用道具 举报

发表于 2008-9-23 16:48:56 | 显示全部楼层
在读DXEmain时,
. R7 K0 N  A6 f# EStatus = CoreInitializeImageServices(HobStart);--->CoreInstallProtocolInterface();--->CoreInstallProtocolInterfaceNotify();中,
3 z9 E' p$ w+ @/ G! T- o//
3 c2 r, n: h8 l// Notify the notification list for this protocol.
7 I& q0 H6 K( {3 }/ y  O//
4 o1 {/ o+ ~: K8 lif (Notify) {( R3 ^: H: }, y! a$ A: i7 w
  CoreNotifyProtocolEntry(ProtEntry);7 j- S# {0 W- I. v# q, V5 i; R; D
}    里Signal了Event. MS是说一个handle安装了一个protocol后就signal一次.' g1 M% R! v5 D; |( A. g0 E" r
有个问题请教一下大家: 这段是在DXE很靠前的位置执行的,但是在它之前我没有看到DXE中有相关的CreateEvent出现?哪位高手能说说这部分代码的流程呢?
回复

使用道具 举报

发表于 2008-9-23 17:04:14 | 显示全部楼层
原帖由 xtdumpling 于 2008-9-16 13:34 发表 + w' x8 m6 m, i! b9 K
请楼上的兄弟分析下BS的RegisterProtocolNotify也就是CoreRegisterProtocolNotify是做什么用的?怎么用?& l/ s$ ~8 M+ D& v; a) P
谢谢!
' W" w9 G0 A* ~
......
- i3 S  C: j9 L  ?9 i9 A
, B8 V; Q9 {+ Z% T  g
! }: C0 x/ b" J5 a3 p[ 本帖最后由 xtdumpling 于 2008-9-23 17:24 编辑 ]
回复

使用道具 举报

发表于 2008-9-24 12:43:45 | 显示全部楼层
原帖由 xtdumpling 于 2008-9-23 17:04 发表   J# g9 Z" E$ o. _4 ?
5 L' d" q: ]7 v- ^! M
......
% d8 @; Q# i/ Q# D

8 c* U" d+ G4 [9 ?5 L+ p! z* pSignal的Event是不是在各个TPL级上挂载一些待处理的事件,一旦restore(TPL)的话,比当前TPL级高的pending事件就回被处理掉?4 {8 c9 I! n3 N* l8 |
如果是这样的话,Timer事件是如何处理的呢,没有找到相关的代码呀?Xt指点一下再~
回复

使用道具 举报

发表于 2008-9-24 19:00:46 | 显示全部楼层
Timer是挂在8259的IRQ0的中断处理程序上面的, 大概每秒18.3次调用CoreTimerTick()-->CoreCheckTimers(), y8 W2 m* Y! g7 M; H" Q
TPL=30
回复

使用道具 举报

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

本版积分规则

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

GMT+8, 2026-6-4 22:02 , Processed in 0.050341 second(s), 17 queries .

Powered by Discuz! X3.5

© 2001-2025 Discuz! Team.

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