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

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

[复制链接]
发表于 2008-7-27 00:11:28 | 显示全部楼层 |阅读模式
  最近在工作看到机台有启动过程中把SPI ROM数据清空,但苦与没有办法很好的Debug(PCA没有架起来),所有与EDK为对象好好的读了一把。
7 U9 v* j5 ]! n  q# r/ E8 O! x) ^$ w5 [* Y5 P2 b
SEC/CEI:& x' V7 M; ]  q1 Y8 i- w' m
  UEFI BIOS启动时先会执行SEC/CEI,这个阶段在实现的BIOS Code中初始化Debug Port,进入Big Mode,CPU的MicroCode,CacheToRAM的转换.然后跳转到PEI阶段。
. k9 J0 @/ @1 a: }6 W- i在EDK中这部分被成了Load FvRecovery.fd文件,这个文件类似与我们的BIOS ROM.里面是我们编译后生成的二进制代码。在这个阶段最主要的是将这个文件加载到内存中(Windows API将文件加载到内存,看API函数).. C$ h% E9 O2 H/ s

8 _/ E  K% U) ?; sPEI:) |5 D: V; Q1 J
   从这里开始UEFI BIOS和EDK执行基本相同,只是一个是从SPI ROM中定位一个地址(PEIM的开始地址),一个是从内存中定位一个地址(PEIM的开始地址)。从这里开始只讲EDK的执行  f2 }( F  [7 W% B
  EDK调用InitializeMemoryService函数,将HobList清空,peiservice清空。
: D! H! |, Y: E. p) e      InitializePPIService函数,将PPI队列清空,这个队列长0x3F.
8 P! T2 j& \4 ^( {- v9 l, M          InitializeSercurityService函数,将Notify队列清空。
# N' t0 Z' a* Y- ^- L          InitializeDispatcherData函数,将Dispatcher队列清空。
0 S: r$ f3 J& }  m  接着由PeiBuildHobGuid来建立一个HOB(S3返回时这时应该有这个HOB,不用建立,直接使用了,这样就会进入另外一个流程,可以这个EDK不能调试S3,不知道怎么走)。然后由(*PeiServices)->InstallPpi()将这个新HOB加入到PPI中。9 r1 d6 B/ m4 ?, E8 w0 R
    由于在SEC阶段转了以下这几具PPI,所以在执行PEI的Dispatcher之前会先安装东西:" p2 z% c6 a0 F- |/ h
      EFI_PEI_PPI_DESCRIPTOR    gPrivateDispatchTable[] = {
/ I! _& @0 k8 J       {EFI_PEI_PPI_DESCRIPTOR_PPI, &gEfiNtLoadAsDllPpiGuid, &mSecNtLoadAsDllPpi},! ?% X' K% d4 ]
       {EFI_PEI_PPI_DESCRIPTOR_PPI, &gNtPeiLoadFileGuid, &mSecNtLoadFilePpi},
" M3 \8 e' u5 n" @8 [; O5 ^       {EFI_PEI_PPI_DESCRIPTOR_PPI, &gPeiNtAutoScanPpiGuid, &mSecNtAutoScanPpi}," H7 D3 r; J8 U0 O" q+ x. \6 [
       {EFI_PEI_PPI_DESCRIPTOR_PPI, &gPeiNtThunkPpiGuid, &mSecWinNtThunkPpi},
! [: N/ e$ ?* i5 Q       {EFI_PEI_PPI_DESCRIPTOR_PPI, &gPeiStatusCodePpiGuid, &mSecStatusCodePpi},
) _" U4 f9 \2 r8 R" S; l       {EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST, &gNtFwhPpiGuid, &mSecFwhInformationPpi}
- m* N! y, `3 X     };, V/ K' }8 c0 D8 ~  h, e' I3 q" j
    每个PPI是由{类型,GUID(名字,以后就根据这个来找到它的),Function_Entry_Address}组成。9 C( m4 E% ?+ g
   这些PPI会在PEIDispatcher中用到。
" S- T: V* T8 P+ ?/ Q   安装完这此东西这开始执行PEIDispatcher函数,函数从BIOS ROM文件中找出PEI的Image(怎么找到,请读一下FV_HEAD(EFI_HEAD),里面讲到了如何区分Image类型),然后定位到PEI Image的入口地址,执行他。在我们的的PEI中,我们一般会申明一个PPI,这个就是这个PEI提供一些服务,PEIDispatcher会将他们加入到PPI-List中,以后其他Image也可以调用他的提供的功能。( j6 T4 E$ Y" K1 r  R2 K
   最后EDK会加载一个叫DXEIPL的PEI,DXEIPL提供一个PPI服务,这个PPI的功能是实现从PEI到DXE的切换,这个PPI里面为DXE做了很多的预准备,加载了很多PPI,如对BIOS的解压方法等。. f: s% R7 I" _5 Q' c/ t
   SwitchStacks (' ]1 N% Y% i+ K2 l) e4 R
       (VOID *) (UINTN) DxeCoreEntryPoint,0 J. ^* h8 z% h6 K* V
       (UINTN) (HobList.Raw),1 o: m; _+ ^- k3 }
       (VOID *) (UINTN) TopOfStack,
" T, c& x$ Z  E+ l  V       (VOID *) (UINTN) BspStore9 w, M! z+ M# n! \5 ~; I
    );& k) Q7 ]2 Z4 U9 h% ]: O
  用过汇编的人对这个技术一定很熟悉,不多说了(我别不清,咯。。。)
) e2 H0 n- ?; ?  M( t/ l. F; L1 k# C, W: {- J) J% [0 r
DXE:8 M9 V+ C1 E( Q$ F, c* }) {* W
     从PEI到DXE切换时转过来一个HOBLIST参数,DXE会在这个HOB中找到Memory的使用情况,然后根据这些情况将BIOS引到内存(这是EFI的做法)。在EDK在DXE时重新定位一下内存。3 m/ Y. ?/ W2 Z. `
接着就会定义我们经常使用到的gST表,gRT表。接着是申明一些Protocol(先不关心这些事)。
: [! n# S( V. k6 N) t+ n" H   等这些该加的PPI,Protocol加完了,CoreDispatcher()就出场了。他会的功能类似PEIDispatcher()。从我们BIOS ROM中将DXE的驱动读出,执行执行他们,这时会执行到Driver
1 e% G8 ?, c, Q4 k' E# E3 X1 i+ u中的Support(),Start()两个功能函数。在这两个函数中你可以注册自己的PPI,为其他驱动提供服务。4 C! Q' H( M3 e, a- |5 M
   到些BIOS的引导其他完成。接着该进OS了,看Linux 0.11吧,操作系统是怎么做事情的。4 Y0 f: i* \' {6 U( t: ^0 a3 J
   ' ]* W) {0 Q+ n4 y
Driver:8 D+ i8 I9 @, [5 v
    我们的驱动什么为在PEI和DXE等不同阶段执行呢?6 P; c: B, q. R2 p6 D# w  B4 S( t! h
  大家请看一下我们的驱动的makefile.(EDK中的*.inf)2 \" e$ }$ M- ?! L
  [defines]' P# @: o9 W/ A
  BASE_NAME            = OWEN9 a, _# m1 p% S4 G. u6 z0 a
  FILE_GUID            = 1EDD13C1-62EF-4262-A1AA-0040D0830110# S0 V4 y4 r3 M
  COMPONENT_TYPE       = BS_DRIVER
+ o" ]3 x, z. i- E7 o/ t! c; O# \4 @& ~+ @- W  d9 Q- M" x
  BASE_NAME告诉编译器最终生成的驱动的名字。
: M5 }5 E* @9 |$ V0 Y  FILE_GUID就是这个驱动的GUID名字,在BIOS中引用某个驱动就是根据它来调用和识别。
5 Q6 X2 Y/ U/ a9 i/ f5 K+ v% T% ~  COMONENT_TYPE会告诉编译器生成驱动的类型,是PEI,DXE,等。, o7 C2 z& w9 @. Q# @
  在EDK中有一个FWVolume.c实现的功能就是帮我们把这个TYPE转换面相应的扩展名: t7 s0 ~# y, B1 z* M, [' N$ N8 a4 g3 J
  COMP_TYPE_EXTENSION  mCompTypeExtension[] = {# e* Y( ]! }2 P7 K6 u, v
  {"bs_driver",  ".dxe" },
9 o" ~5 `, Y1 J$ T1 h  {"rt_driver",  ".dxe" },0 z9 W# Z% E9 ?- I5 @
  {"sal_rt_driver", ".dxe"},* y+ S2 ~$ }! _  e( t4 U# Q
  {"security_core", ".sec"},* X2 H) X" O8 E! v9 D/ k: y  N
  {"pei_core", ".pei"},' Y' H, m9 g5 t& s; G) B% t: Z- S7 A
  {"pic_peim", ".pei"},
0 n0 K8 z3 S+ M3 e  {"pe32_peim", ".pei"},
9 f; o# N. s3 Q  {"relocatable_peim", ".pei"},
$ C' M0 ]1 a. i" V5 p  {"binary", ".ffs"},8 x/ ?8 u$ ]3 t. g9 z6 `$ ?! E
  {"application", ".app"},0 O0 f/ B4 e% t6 d
  {"file", ".ffs"},$ l' ~! V6 r* J! J$ k% h
  {"fvimagefile", ".fvi"},$ |- g9 q2 r% D) v  L+ e' `$ H# y
  {"rawfile", ".raw"},) |- s. o" E! P# }2 K( u8 B  D
  {"apriori", ".ffs"},! P1 k) e: v/ p3 c) C5 J: }0 n
  {"combined_peim_driver", ".pei"},- A+ u$ `( B, F: T" m0 T% q; I
  { NULL,  NULL }
0 P. j( w! ]6 l( U( y; k- z};
3 s. ?. A% M' X0 s+ r; v
1 p: B. A6 f: _了解了这些,接下我们可以看驱动篇了。(Go On Study... Forever)4 B4 r1 X! \1 Y3 J. W) Z, z$ H; T
   
8 u% j% R$ o! K         
+ j3 o$ \* x" h  
发表于 2008-7-27 12:30:15 | 显示全部楼层
不错!
8 g1 {5 G! c2 X" I8 q) t$ R$ w7 b% a支持6 k1 i: I) t! {
继续+ p) @1 O- F, z/ w8 r$ E2 z
加油
1 `# F5 K* X" G( W
回复

使用道具 举报

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

回复 1# 的帖子

gPrivateDispatchTable 和COMP_TYPE_EXTENSION  没有搜到啊  是EDK专有的么?; e" H4 B  X# n+ N
有看过跟gPrivateDispatchTable 类似的,但是里面的PPI不同。# H$ q* r6 Y2 |" n5 K7 [1 q
还有这个COMP_TYPE_EXTENSION  没有找到过。FWVolume.c这个文件也没有发现。。
回复

使用道具 举报

发表于 2008-7-28 13:24:20 | 显示全部楼层
这东西虽说没有什么技术含量,但是总结一下还是非常好的。
% G& A% x9 V- {$ j; q( S. x1 s9 F5 K8 j# ^% X; k6 J# o
支持!
回复

使用道具 举报

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

: y# U$ ], M+ D. Y5 H- h- X4 ~小弟还在学习阶段,目前的目标是知道执行的流程。$ x, w* f* D- p7 `
这里面有很多细节没有写,能力有限,只能自己知道,不能表达。
* p- k- Y# P7 r3 Z$ R* E9 q嘿。。。。
* _3 E" [6 o' o& n7 x所有大侠们如果有好东西能给小弟共享一份。8 X; W' W% H  f9 p7 t
* \- o# i0 v3 @) [
谢谢!
回复

使用道具 举报

发表于 2008-8-12 14:44:11 | 显示全部楼层
原帖由 winbondowen 于 2008-7-27 00:11 发表 ; D- ~( R0 K, S( E/ E2 G, C' W; D# Q2 W
  ROM中將DXE的驅動讀出,執行執行他們,這時會執行到Driver% O: V1 }0 N2 R
中的Support(),Start()兩個功能函數。在這兩個函數中你可以註冊自己的PPI ...

4 O" y8 q. ]* T( h  r4 x
, q. b6 D$ @; T3 _* s5 bPPIs are registered during PEI phase, but Support()/Start() are invoked in DXE driver binding protocol,
: \1 c' g  ^8 _! q- \For more precisely, I think the "PPI" you mentioned is the "PROTOCOL" rather than "PPI".
7 l* j: ?1 [/ O. }9 g
/ a  z8 J* f/ n8 ~  [) O- r) m; o[ 本帖最后由 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 p+ ~" m6 r* `" M' y2 }: X) J8 X   Yes. I make a mistake.( d1 u; r7 s! p# ~
      PPI:     A PEIM to PEIM interface.
  W; j& R3 y; _# l( ~: V% h      PROTOCL: A Interface between Hardware(or firmware) and software., |3 F2 |1 {( f! k
      reference[http://www.biosren.com/viewthread.php?tid=207]% L; Y4 v- ~! f7 V5 c  k
   so, PPI execute at PEI step and Initialize hardware. PROTOCOL execute by DXE step.
9 V% t, _' O; q4 H; v1 V, Z   Thanks.
回复

使用道具 举报

发表于 2008-8-20 17:47:21 | 显示全部楼层
原帖由 winbondowen 于 2008-7-27 00:11 发表 DXE:& V: x: c' `/ G4 ^  t# V
     從PEI到DXE切換時轉過來一個HOBLIST參數,DXE會在這個HOB中找到Memory的使用情況,然後根據這些情況將BIOS引到內存(這是EFI的做法)。在EDK在DXE時重新定位一下內存。
6 W4 ?& X; e" A5 T% A接著就會定義我們經常使用到的gST表,gRT表。接著是申明一些Protocol(先不關心這些事)。
- s9 S) \$ f! n. V3 H1 ^   等這些該加的PPI,Protocol加完了,CoreDispatcher()就出場了。他會的功能類似PEIDispatcher()。從我們BIOS ROM中將DXE的驅動讀出,執行執行他們,這時會執行到Driver" p8 O& R- @4 b; H! e+ X. @0 @
中的Support(),Start()兩個功能函數。在這兩個函數中你可以註冊自己的PPI,為其他驅動提供服務。
* V5 l: ^# u+ w' L   到些BIOS的引導其他完成。接著該進OS了,看Linux 0.11吧,操作系統是怎麼做事情的。.
9 D$ f# @1 I2 D0 Z# F, P
) [) H5 M+ M9 x6 I" J4 T/ }
There are mistakes,. `4 `+ S/ n1 `0 v% m5 m; J
1.gST and gRT are init after the DXE architectural protocols have been loaded, those protocols response for creating Dxe foundation.2 F- a, w/ y/ \/ m; M* b

3 e& w7 R7 E; f/ c9 {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.' z# C4 n9 B( V* D
The CoreDispatcher() executes all trusted Dxe drivers and just register the Binding protocol if the driver is EFI1.1 driver model.
  ?" `6 F8 A/ c5 l4 X: y0 D. \& ]Furthermore, Support()/Start() are invoked in BDS phase over the CoreConnectController() rather than CoreDispatcher().
4 {1 i+ a' \5 e' ^" w0 @. B; U1 Y* j% Q2 K  j( X
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 大侠的指点。
( P3 x7 i4 H$ s# M/ \! D
回复

使用道具 举报

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

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

原帖由 ichirohiro 于 2008-8-20 17:47 发表 ( |! c5 f% r! l2 E5 |( q; C8 _/ s9 V
...
9 f; W1 V2 e; j- 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.' C0 v3 A9 ~; B7 _9 g  ?# {0 a% Y' {
The CoreDispatcher() executes all trusted Dxe drivers and just register the Binding protocol if the driver is EFI1.1 driver model.
  O0 \% Z* D: _Furthermore, Support()/Start() are invoked in BDS phase over the CoreConnectController() rather than CoreDispatcher().
0 r: {$ t8 D/ \0 `4 [
    在Framework的spec DxeCis.pdf里面也是这么说的,DXE CoreDispatcher()里面,对于EFI1.1 driver model的driver只会安装Handler和Interface到Binding protocol,到BDS才会去执行Support()和Start().
8 Z; n) w* t& ~, T# V    但是,我在看code时,发现在CoreDispatcher()-->CoreStartImage()里面call image之后有这么一句:  (file:image.c)( F4 e- d- L$ F/ k6 w8 p
  //; V9 `& {  Z% H( m( \5 j
  // Go connect any handles that were created or modified while the image executed.
' x* ^! h( t3 L: O) y! R  E  //& D, h/ v. Z$ D2 V* g  X
  CoreConnectHandlesByKey (HandleDatabaseKey);
+ w+ [' v+ [( W
这里的HandleDatabaseKey是call image之前由CoreGetHandleDatabaseKey()得到的gHandleDatabaseKey
6 |! G1 h% O' j4 R8 H而CoreConnectHandlesByKey会调用到:
5 q& z, N7 j( C# X2 J$ T  //
0 \8 T0 {  c% a: ~( r  // Connect all handles whose Key value is greater than Key
% [5 q- E4 _  q  ?! n1 M  //
+ S% k! s, i0 \  for (Index = 0; Index < Count; Index++) {9 N; ^& _/ Y' `: x6 f8 U9 ^3 {4 A
    CoreConnectController (HandleBuffer[Index], NULL, NULL, TRUE);
* a) j3 I' d8 a& ^% _  }

5 W1 ]  Z& u1 C* {) c所以,照code看,当在Driver中安装一个Handle和Interface到Binding Protocol后(gHandleDatabaseKey会++,IHandle的Key=gHandleDatabaseKey)- V* n4 v) R  i) g6 a+ J' A
是会去ConnectController的,也会执行对应的Support()和Start()才对!!0 k: O; Y/ M# {5 `" z* U/ C* s

8 l$ Q0 P( X) y6 [8 x9 ~不知道我想的哪里有问题???欢迎大家指正.( V4 j2 l2 @: b* c9 i
# [, l. D* Z8 M* N
[ 本帖最后由 xtdumpling 于 2008-9-18 15:25 编辑 ]
回复

使用道具 举报

发表于 2008-9-19 14:44:41 | 显示全部楼层
这段code似乎是一个向后兼容的行为,不必太care。
& i, p8 s. j( v# a! A# H一个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 | 显示全部楼层
了解了.
  C1 a# g2 s9 y2 N非常 感谢!!!
回复

使用道具 举报

发表于 2008-9-23 16:48:56 | 显示全部楼层
在读DXEmain时,9 D6 a7 t% ^$ J& D- u
Status = CoreInitializeImageServices(HobStart);--->CoreInstallProtocolInterface();--->CoreInstallProtocolInterfaceNotify();中,
  v5 F0 G: N' u$ G//9 E- i1 ~" D+ T: I0 j& W
// Notify the notification list for this protocol.
) L4 D9 |/ D- M+ d/ o/ P//
4 E1 `" y* h8 N- h8 q& e# Z# eif (Notify) {
: {3 L: W  S# N, k3 w+ C  CoreNotifyProtocolEntry(ProtEntry);
3 Y$ S* @+ d+ U5 d# V}    里Signal了Event. MS是说一个handle安装了一个protocol后就signal一次.
# k( Z( F/ @" Q& D' |有个问题请教一下大家: 这段是在DXE很靠前的位置执行的,但是在它之前我没有看到DXE中有相关的CreateEvent出现?哪位高手能说说这部分代码的流程呢?
回复

使用道具 举报

发表于 2008-9-23 17:04:14 | 显示全部楼层
原帖由 xtdumpling 于 2008-9-16 13:34 发表 % m) Z/ T: Z6 [3 Q5 A* ?
请楼上的兄弟分析下BS的RegisterProtocolNotify也就是CoreRegisterProtocolNotify是做什么用的?怎么用?
5 B! E, q* T' l2 q0 |6 j2 W7 J% H6 E- i谢谢!

. f. A4 A4 L( m7 j( z; V3 H......
1 ^( T$ w6 `% X2 x. |) |) {" B7 J  Z% v- ^' F+ {
, n, j# T1 ]" O+ i6 W
[ 本帖最后由 xtdumpling 于 2008-9-23 17:24 编辑 ]
回复

使用道具 举报

发表于 2008-9-24 12:43:45 | 显示全部楼层
原帖由 xtdumpling 于 2008-9-23 17:04 发表 0 n0 R' O. \; E/ F" \
& T" }. v( y, ~' n$ |3 a
......: P  U% W) r- l; O/ C

+ ?, S! J. F  G# q4 q% x+ k. ESignal的Event是不是在各个TPL级上挂载一些待处理的事件,一旦restore(TPL)的话,比当前TPL级高的pending事件就回被处理掉?4 y' m- _) V8 w1 c# Q
如果是这样的话,Timer事件是如何处理的呢,没有找到相关的代码呀?Xt指点一下再~
回复

使用道具 举报

发表于 2008-9-24 19:00:46 | 显示全部楼层
Timer是挂在8259的IRQ0的中断处理程序上面的, 大概每秒18.3次调用CoreTimerTick()-->CoreCheckTimers()
$ W$ N+ [3 r3 b& U/ CTPL=30
回复

使用道具 举报

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

本版积分规则

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

GMT+8, 2024-11-21 18:58 , Processed in 0.043148 second(s), 16 queries .

Powered by Discuz! X3.5

© 2001-2023 Discuz! Team.

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