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

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

[复制链接]
发表于 2008-7-27 00:11:28 | 显示全部楼层 |阅读模式
  最近在工作看到机台有启动过程中把SPI ROM数据清空,但苦与没有办法很好的Debug(PCA没有架起来),所有与EDK为对象好好的读了一把。
! p" e/ [: X% m9 w/ q- s& j% Y4 t. O5 z) X( U$ S1 o' [' q6 H
SEC/CEI:
3 n* o1 f% _' v7 n* W0 E; a  UEFI BIOS启动时先会执行SEC/CEI,这个阶段在实现的BIOS Code中初始化Debug Port,进入Big Mode,CPU的MicroCode,CacheToRAM的转换.然后跳转到PEI阶段。, u9 X3 F  p  |/ j- b
在EDK中这部分被成了Load FvRecovery.fd文件,这个文件类似与我们的BIOS ROM.里面是我们编译后生成的二进制代码。在这个阶段最主要的是将这个文件加载到内存中(Windows API将文件加载到内存,看API函数).
# q8 ~- S# W2 r( F2 n6 E* I
4 V4 e* u! o) Z/ xPEI:
: u; t: S% o& }, {7 u   从这里开始UEFI BIOS和EDK执行基本相同,只是一个是从SPI ROM中定位一个地址(PEIM的开始地址),一个是从内存中定位一个地址(PEIM的开始地址)。从这里开始只讲EDK的执行4 {7 i' I/ ]6 k8 k/ R0 s
  EDK调用InitializeMemoryService函数,将HobList清空,peiservice清空。
  v( y2 o1 ?, E! ]      InitializePPIService函数,将PPI队列清空,这个队列长0x3F.
' `/ t/ O) t0 x& h9 i3 a5 `          InitializeSercurityService函数,将Notify队列清空。  l- M/ y, h) s$ q6 B4 R7 L7 L5 K
          InitializeDispatcherData函数,将Dispatcher队列清空。
" B8 m( D" ~/ v, K  接着由PeiBuildHobGuid来建立一个HOB(S3返回时这时应该有这个HOB,不用建立,直接使用了,这样就会进入另外一个流程,可以这个EDK不能调试S3,不知道怎么走)。然后由(*PeiServices)->InstallPpi()将这个新HOB加入到PPI中。
4 I) B6 K) {! [3 O  x7 a/ c, X$ i    由于在SEC阶段转了以下这几具PPI,所以在执行PEI的Dispatcher之前会先安装东西:
' w: n. x6 [' K4 G) O- C& \      EFI_PEI_PPI_DESCRIPTOR    gPrivateDispatchTable[] = {3 k6 Q8 V: n5 c) ]+ T7 k, D% a
       {EFI_PEI_PPI_DESCRIPTOR_PPI, &gEfiNtLoadAsDllPpiGuid, &mSecNtLoadAsDllPpi},
. q; d( O6 h; b8 O       {EFI_PEI_PPI_DESCRIPTOR_PPI, &gNtPeiLoadFileGuid, &mSecNtLoadFilePpi},1 ]2 \% {9 K" n3 J. }8 j
       {EFI_PEI_PPI_DESCRIPTOR_PPI, &gPeiNtAutoScanPpiGuid, &mSecNtAutoScanPpi},
8 U, e9 l6 R4 K; W( u3 R! R  q       {EFI_PEI_PPI_DESCRIPTOR_PPI, &gPeiNtThunkPpiGuid, &mSecWinNtThunkPpi},
) d8 V) b9 E& ?* R/ S0 o% g       {EFI_PEI_PPI_DESCRIPTOR_PPI, &gPeiStatusCodePpiGuid, &mSecStatusCodePpi},3 U2 p/ p% d/ A' g
       {EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST, &gNtFwhPpiGuid, &mSecFwhInformationPpi}
6 [/ W! A$ Y1 a- N3 z: P  M3 i1 N     };
. ~4 W1 H2 R( \% I6 @3 j    每个PPI是由{类型,GUID(名字,以后就根据这个来找到它的),Function_Entry_Address}组成。
2 w! Z. t) z+ A: [# [   这些PPI会在PEIDispatcher中用到。+ ~7 O" |* \# ^9 l: B7 \7 c
   安装完这此东西这开始执行PEIDispatcher函数,函数从BIOS ROM文件中找出PEI的Image(怎么找到,请读一下FV_HEAD(EFI_HEAD),里面讲到了如何区分Image类型),然后定位到PEI Image的入口地址,执行他。在我们的的PEI中,我们一般会申明一个PPI,这个就是这个PEI提供一些服务,PEIDispatcher会将他们加入到PPI-List中,以后其他Image也可以调用他的提供的功能。
* W% f/ K7 C: h% C# `/ f   最后EDK会加载一个叫DXEIPL的PEI,DXEIPL提供一个PPI服务,这个PPI的功能是实现从PEI到DXE的切换,这个PPI里面为DXE做了很多的预准备,加载了很多PPI,如对BIOS的解压方法等。( V: n; W7 Q2 z( [" }% A2 Z
   SwitchStacks (
* D& g' U' I0 s       (VOID *) (UINTN) DxeCoreEntryPoint,
" v8 o+ V" N  F; S% j       (UINTN) (HobList.Raw),
0 I) m+ s3 u' X, \5 {8 f+ s       (VOID *) (UINTN) TopOfStack,
6 x$ o) \2 W4 @; W9 ?. ]( h       (VOID *) (UINTN) BspStore
! @. x: i# @! Z6 }% h    );
  _( F1 [5 W) T, L: o  用过汇编的人对这个技术一定很熟悉,不多说了(我别不清,咯。。。)7 I* ]" Z5 G( c: N2 H, d

' Z( T  p' P. ^8 [. LDXE:
' U3 B! ]% D* ^! K5 U, K  j     从PEI到DXE切换时转过来一个HOBLIST参数,DXE会在这个HOB中找到Memory的使用情况,然后根据这些情况将BIOS引到内存(这是EFI的做法)。在EDK在DXE时重新定位一下内存。
; ^1 m2 @  g: T) O8 u3 ~接着就会定义我们经常使用到的gST表,gRT表。接着是申明一些Protocol(先不关心这些事)。
! o; v$ n8 C3 J+ a  |   等这些该加的PPI,Protocol加完了,CoreDispatcher()就出场了。他会的功能类似PEIDispatcher()。从我们BIOS ROM中将DXE的驱动读出,执行执行他们,这时会执行到Driver( Q& k! u3 r# [0 g2 D& E
中的Support(),Start()两个功能函数。在这两个函数中你可以注册自己的PPI,为其他驱动提供服务。
. G( k" P$ a5 i4 h6 `( q( \   到些BIOS的引导其他完成。接着该进OS了,看Linux 0.11吧,操作系统是怎么做事情的。4 C- J) K% s2 ^) n
   
9 ~9 ^* l. Z& |0 w. \7 }0 G+ FDriver:% C) Y" i9 [4 ?% c: f& ^; V
    我们的驱动什么为在PEI和DXE等不同阶段执行呢?
1 A- W, V9 K+ _/ k! e2 h  大家请看一下我们的驱动的makefile.(EDK中的*.inf)
# W0 g5 f! Z+ S  [defines]# S, U6 {5 k+ v" x7 x, e  w# `
  BASE_NAME            = OWEN, Z/ p% ?9 J+ l4 Y. M
  FILE_GUID            = 1EDD13C1-62EF-4262-A1AA-0040D0830110( ?; D' X  K4 A! y. l
  COMPONENT_TYPE       = BS_DRIVER/ t5 p2 K/ ?: K% D2 x, x0 U+ Z

3 |; R1 n4 F2 t  BASE_NAME告诉编译器最终生成的驱动的名字。7 y( i# O: ~# l& c1 ^( U
  FILE_GUID就是这个驱动的GUID名字,在BIOS中引用某个驱动就是根据它来调用和识别。+ D/ ?$ z$ ?  E: c' ?+ q
  COMONENT_TYPE会告诉编译器生成驱动的类型,是PEI,DXE,等。) P: h# L& `) T  G( X" Y3 B
  在EDK中有一个FWVolume.c实现的功能就是帮我们把这个TYPE转换面相应的扩展名, L* M. @& h* r2 _' f3 s# F
  COMP_TYPE_EXTENSION  mCompTypeExtension[] = {( T+ {, d4 t" s# t+ ]( X
  {"bs_driver",  ".dxe" },
$ i/ H6 G" }7 K7 `7 r+ A  {"rt_driver",  ".dxe" },7 y: }; C7 u. e7 w' s% X
  {"sal_rt_driver", ".dxe"},- s# A. G: I* Q1 e5 m
  {"security_core", ".sec"},
3 S4 Y- q7 D' J' o  B  {"pei_core", ".pei"},0 T; H7 x- o% V( y2 X; `
  {"pic_peim", ".pei"},$ u6 A4 k6 F1 B! x, P/ F! m
  {"pe32_peim", ".pei"},
# @$ s$ U% k8 E7 F9 z; o  s9 A5 {, g' a  {"relocatable_peim", ".pei"},; b8 U/ x2 M3 L) T7 W2 w
  {"binary", ".ffs"},
! f$ b8 m% B5 O7 Q1 G5 C% I  {"application", ".app"},
2 n/ Y! K% _3 u  {"file", ".ffs"}," d, e: V; P9 L# O9 L/ Z: i
  {"fvimagefile", ".fvi"},/ `; m- T. D7 W: O, P# v
  {"rawfile", ".raw"},
+ V* R1 u& i" _* \* D0 @' g  {"apriori", ".ffs"},
  l3 U1 X' A& ]/ [. T  {"combined_peim_driver", ".pei"},( G1 H7 a9 K% y8 e. B- d2 A
  { NULL,  NULL }* t& q- }6 p* ^
};
, g  |; s. k  H( C( r  L1 Y
- J. b- t6 j/ \2 v4 N了解了这些,接下我们可以看驱动篇了。(Go On Study... Forever)
3 `: T: F" M9 s# L   * v6 U' t1 A; d
         
0 p; n# u  _/ v! j& @0 }  
发表于 2008-7-27 12:30:15 | 显示全部楼层
不错!
2 @" X+ m4 I! M支持
' u0 x4 x: N. M) t继续6 c0 g! f) N8 n/ K+ h5 |# Z" D
加油$ J0 d' ~6 H- ]& R/ b" ]
回复

使用道具 举报

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

回复 1# 的帖子

gPrivateDispatchTable 和COMP_TYPE_EXTENSION  没有搜到啊  是EDK专有的么?- j' D0 i7 \# S2 ~& F9 A
有看过跟gPrivateDispatchTable 类似的,但是里面的PPI不同。$ P) \7 i$ h8 S. y! `; e
还有这个COMP_TYPE_EXTENSION  没有找到过。FWVolume.c这个文件也没有发现。。
回复

使用道具 举报

发表于 2008-7-28 13:24:20 | 显示全部楼层
这东西虽说没有什么技术含量,但是总结一下还是非常好的。
. l& C6 Y% o- @, w0 q( ]( R! o: n, u0 `- C
支持!
回复

使用道具 举报

 楼主| 发表于 2008-7-28 18:52:31 | 显示全部楼层
8 T" G" ]* x# o
小弟还在学习阶段,目前的目标是知道执行的流程。
% h, K: q6 ]. ~这里面有很多细节没有写,能力有限,只能自己知道,不能表达。% Y& s# C1 N5 W$ _
嘿。。。。
5 ^& a) e4 M5 \5 w3 O7 N' W0 z所有大侠们如果有好东西能给小弟共享一份。) j5 w  p4 y: R% q0 e, S7 g2 ~; \

% N5 {# T3 L0 f! X3 \7 }谢谢!
回复

使用道具 举报

发表于 2008-8-12 14:44:11 | 显示全部楼层
原帖由 winbondowen 于 2008-7-27 00:11 发表
  ?8 k7 z5 N/ F" F* N$ [9 f  ROM中將DXE的驅動讀出,執行執行他們,這時會執行到Driver) U2 j2 d. F! X! G
中的Support(),Start()兩個功能函數。在這兩個函數中你可以註冊自己的PPI ...

" n! \' N6 q4 w! u: U* X# ]4 S- f5 @1 S& L
PPIs are registered during PEI phase, but Support()/Start() are invoked in DXE driver binding protocol,
; s: N8 W9 |! v, zFor more precisely, I think the "PPI" you mentioned is the "PROTOCOL" rather than "PPI".5 ^/ Y5 P) k& L9 B) r9 k! Q, Q

5 H8 y" o3 y" s[ 本帖最后由 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:/ ?2 a" |' f9 K) L6 O: G! z
   Yes. I make a mistake.
4 X3 \* N4 ]9 u      PPI:     A PEIM to PEIM interface.
8 Y, ?# u+ W; \      PROTOCL: A Interface between Hardware(or firmware) and software.: c, |9 y3 d' n5 A  ^
      reference[http://www.biosren.com/viewthread.php?tid=207]! V; `9 l, h' ^/ }" ^# i+ s/ w2 p
   so, PPI execute at PEI step and Initialize hardware. PROTOCOL execute by DXE step.
3 M7 c; Q% I7 C* i& L   Thanks.
回复

使用道具 举报

发表于 2008-8-20 17:47:21 | 显示全部楼层
原帖由 winbondowen 于 2008-7-27 00:11 发表 DXE:
9 @  ~! j3 b; C9 o4 P7 n) y     從PEI到DXE切換時轉過來一個HOBLIST參數,DXE會在這個HOB中找到Memory的使用情況,然後根據這些情況將BIOS引到內存(這是EFI的做法)。在EDK在DXE時重新定位一下內存。) O/ s+ G% C- E  }! v
接著就會定義我們經常使用到的gST表,gRT表。接著是申明一些Protocol(先不關心這些事)。
  W. X% f* T0 R4 x2 _* g2 K   等這些該加的PPI,Protocol加完了,CoreDispatcher()就出場了。他會的功能類似PEIDispatcher()。從我們BIOS ROM中將DXE的驅動讀出,執行執行他們,這時會執行到Driver
" f" e- V, F0 ?9 u中的Support(),Start()兩個功能函數。在這兩個函數中你可以註冊自己的PPI,為其他驅動提供服務。
7 f, B2 x7 E* J: F- a+ m7 v   到些BIOS的引導其他完成。接著該進OS了,看Linux 0.11吧,操作系統是怎麼做事情的。.

* c5 U6 E$ P4 @1 }) S
$ }* n" p' Y) E, ?There are mistakes,
4 a" W+ R0 ~0 {1 c, g/ X1.gST and gRT are init after the DXE architectural protocols have been loaded, those protocols response for creating Dxe foundation.
. x. `6 p" l# u
' s+ U5 T+ S. F' v2.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.
4 u( [6 d: L1 ^+ S' G+ dThe CoreDispatcher() executes all trusted Dxe drivers and just register the Binding protocol if the driver is EFI1.1 driver model.
* O4 M% [% M, t4 w' pFurthermore, Support()/Start() are invoked in BDS phase over the CoreConnectController() rather than CoreDispatcher().
& `' L2 D% R/ ~  r; _9 H
) j4 v7 W" @& M% J* hBTW, 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 大侠的指点。
- b) {5 g2 ]' ^
回复

使用道具 举报

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

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

原帖由 ichirohiro 于 2008-8-20 17:47 发表 % N. ]1 Q; l/ K, V4 t+ ?3 q
...
0 B) ~" J0 n# }& Y2.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.
, B* W+ d. g# T$ T7 ?* _The CoreDispatcher() executes all trusted Dxe drivers and just register the Binding protocol if the driver is EFI1.1 driver model.; x/ N6 T3 Q+ g7 y
Furthermore, Support()/Start() are invoked in BDS phase over the CoreConnectController() rather than CoreDispatcher().
- G; k7 f, l5 B1 n+ F; H1 D3 ]
    在Framework的spec DxeCis.pdf里面也是这么说的,DXE CoreDispatcher()里面,对于EFI1.1 driver model的driver只会安装Handler和Interface到Binding protocol,到BDS才会去执行Support()和Start().
# m6 e& I% E$ _9 p" s0 d    但是,我在看code时,发现在CoreDispatcher()-->CoreStartImage()里面call image之后有这么一句:  (file:image.c)
# h9 R' p3 y; U8 }  //3 A. [+ E6 q& M0 b7 U5 R
  // Go connect any handles that were created or modified while the image executed.2 F7 M+ Y+ S0 J+ o
  //
. \5 R) j' }+ Q0 E7 a1 P  CoreConnectHandlesByKey (HandleDatabaseKey);

% m6 }- k/ Q, P0 s0 y" s- [这里的HandleDatabaseKey是call image之前由CoreGetHandleDatabaseKey()得到的gHandleDatabaseKey# S6 ?! w2 ~* u: a
而CoreConnectHandlesByKey会调用到:
$ m- T0 p# Q# N  //
8 ]# D( f+ [1 E& T, ]$ |  // Connect all handles whose Key value is greater than Key
) }  }  d1 F1 h6 L: t  //
  P0 ~- \8 v) ^4 A+ N  for (Index = 0; Index < Count; Index++) {$ _, s9 o+ W/ E3 G* j
    CoreConnectController (HandleBuffer[Index], NULL, NULL, TRUE);  l. K" ^. Y5 c& F& u6 r+ S
  }
; x. e0 L! d7 O5 Z3 O9 G. s/ n3 G
所以,照code看,当在Driver中安装一个Handle和Interface到Binding Protocol后(gHandleDatabaseKey会++,IHandle的Key=gHandleDatabaseKey)
, m1 P5 `  f* T: K5 H/ H是会去ConnectController的,也会执行对应的Support()和Start()才对!!
/ v6 W0 O) Z# T: O" ?; e5 C& Z
. n% m- u" h& [2 c不知道我想的哪里有问题???欢迎大家指正.( U- R' ~8 V. E4 V# g% m8 c
6 [  }9 v- p: ?) a, h
[ 本帖最后由 xtdumpling 于 2008-9-18 15:25 编辑 ]
回复

使用道具 举报

发表于 2008-9-19 14:44:41 | 显示全部楼层
这段code似乎是一个向后兼容的行为,不必太care。2 J8 g3 a. H2 g' q, E! I/ T' p
一个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 | 显示全部楼层
了解了.
) O% x+ U# `8 C0 P非常 感谢!!!
回复

使用道具 举报

发表于 2008-9-23 16:48:56 | 显示全部楼层
在读DXEmain时,4 R1 U% y" R1 L
Status = CoreInitializeImageServices(HobStart);--->CoreInstallProtocolInterface();--->CoreInstallProtocolInterfaceNotify();中,: v1 s$ A3 }' f  |$ j2 V
//
: ^1 \7 b' v% p* \& n' j// Notify the notification list for this protocol.
% l# V# A; R) z+ y- U//* w; V- L5 N+ v$ z1 T2 M
if (Notify) {
/ n: e$ m) \1 F, x  CoreNotifyProtocolEntry(ProtEntry);
$ m+ Z. H0 h0 i- z% T}    里Signal了Event. MS是说一个handle安装了一个protocol后就signal一次.9 Z, n2 Q( K- @3 V
有个问题请教一下大家: 这段是在DXE很靠前的位置执行的,但是在它之前我没有看到DXE中有相关的CreateEvent出现?哪位高手能说说这部分代码的流程呢?
回复

使用道具 举报

发表于 2008-9-23 17:04:14 | 显示全部楼层
原帖由 xtdumpling 于 2008-9-16 13:34 发表
( [1 S$ X; T+ e+ w& Q请楼上的兄弟分析下BS的RegisterProtocolNotify也就是CoreRegisterProtocolNotify是做什么用的?怎么用?6 m9 Y7 N  @( s1 G! R1 v2 o
谢谢!

; U+ d# c8 p1 p......& t/ g' k/ P5 z8 L

4 }+ G1 t3 s  _4 q4 ?: S5 {  K4 l7 I
[ 本帖最后由 xtdumpling 于 2008-9-23 17:24 编辑 ]
回复

使用道具 举报

发表于 2008-9-24 12:43:45 | 显示全部楼层
原帖由 xtdumpling 于 2008-9-23 17:04 发表
' K* y9 o3 O3 |2 d! d# f8 a
, P1 }- l% K& V# V$ J9 {# `& _, k7 \$ a......
% X: J1 S- s" z
; S% w7 ~& \, E' Y
Signal的Event是不是在各个TPL级上挂载一些待处理的事件,一旦restore(TPL)的话,比当前TPL级高的pending事件就回被处理掉?6 D; H/ l* G' C
如果是这样的话,Timer事件是如何处理的呢,没有找到相关的代码呀?Xt指点一下再~
回复

使用道具 举报

发表于 2008-9-24 19:00:46 | 显示全部楼层
Timer是挂在8259的IRQ0的中断处理程序上面的, 大概每秒18.3次调用CoreTimerTick()-->CoreCheckTimers(). [! t3 B& V4 e# R3 m$ S
TPL=30
回复

使用道具 举报

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

本版积分规则

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

GMT+8, 2024-6-2 13:31 , Processed in 0.083963 second(s), 17 queries .

Powered by Discuz! X3.5

© 2001-2023 Discuz! Team.

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