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

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

[复制链接]
发表于 2008-7-27 00:11:28 | 显示全部楼层 |阅读模式
  最近在工作看到机台有启动过程中把SPI ROM数据清空,但苦与没有办法很好的Debug(PCA没有架起来),所有与EDK为对象好好的读了一把。
1 ^' X- H4 Z6 p6 d/ }% v. O% x% j9 j2 d) @
SEC/CEI:# H* q9 M. L/ i7 c7 r* u
  UEFI BIOS启动时先会执行SEC/CEI,这个阶段在实现的BIOS Code中初始化Debug Port,进入Big Mode,CPU的MicroCode,CacheToRAM的转换.然后跳转到PEI阶段。' s1 e4 K& t0 ~2 c6 K
在EDK中这部分被成了Load FvRecovery.fd文件,这个文件类似与我们的BIOS ROM.里面是我们编译后生成的二进制代码。在这个阶段最主要的是将这个文件加载到内存中(Windows API将文件加载到内存,看API函数).
1 k5 t! h3 H; _2 W! T( Q0 |/ _, C/ Q: L. ^6 v! A; B( T! d3 c9 S
PEI:7 W; P8 }+ g& Y# r5 i4 H  }
   从这里开始UEFI BIOS和EDK执行基本相同,只是一个是从SPI ROM中定位一个地址(PEIM的开始地址),一个是从内存中定位一个地址(PEIM的开始地址)。从这里开始只讲EDK的执行
5 [# x+ h* G5 E' ?& o  EDK调用InitializeMemoryService函数,将HobList清空,peiservice清空。. v5 Y" A1 r' ^$ u# e+ w
      InitializePPIService函数,将PPI队列清空,这个队列长0x3F.
6 q' ?$ a# A8 e& n          InitializeSercurityService函数,将Notify队列清空。
! O) i$ X" Y: ?, c6 r          InitializeDispatcherData函数,将Dispatcher队列清空。4 u: J/ b2 @8 |, Z+ z( n
  接着由PeiBuildHobGuid来建立一个HOB(S3返回时这时应该有这个HOB,不用建立,直接使用了,这样就会进入另外一个流程,可以这个EDK不能调试S3,不知道怎么走)。然后由(*PeiServices)->InstallPpi()将这个新HOB加入到PPI中。0 T" j  a4 ~3 ~/ P( H
    由于在SEC阶段转了以下这几具PPI,所以在执行PEI的Dispatcher之前会先安装东西:
$ A# z" \) J1 @  W7 X      EFI_PEI_PPI_DESCRIPTOR    gPrivateDispatchTable[] = {
( @0 C9 G) Y7 F+ h       {EFI_PEI_PPI_DESCRIPTOR_PPI, &gEfiNtLoadAsDllPpiGuid, &mSecNtLoadAsDllPpi},! t- L- ~. D0 M9 g! h
       {EFI_PEI_PPI_DESCRIPTOR_PPI, &gNtPeiLoadFileGuid, &mSecNtLoadFilePpi},
# x: ~: l1 n( V* T       {EFI_PEI_PPI_DESCRIPTOR_PPI, &gPeiNtAutoScanPpiGuid, &mSecNtAutoScanPpi},
& a( v! F6 d/ n- Z7 _9 m& j       {EFI_PEI_PPI_DESCRIPTOR_PPI, &gPeiNtThunkPpiGuid, &mSecWinNtThunkPpi},; E) H* k0 @# c7 x/ O
       {EFI_PEI_PPI_DESCRIPTOR_PPI, &gPeiStatusCodePpiGuid, &mSecStatusCodePpi},7 m: }+ i9 H/ I0 A; K  _& Q. K$ E
       {EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST, &gNtFwhPpiGuid, &mSecFwhInformationPpi}
9 K9 c0 ^# ~3 Y2 M8 w) Q     };1 t5 E4 s& [, I
    每个PPI是由{类型,GUID(名字,以后就根据这个来找到它的),Function_Entry_Address}组成。5 @) h. v% u; N
   这些PPI会在PEIDispatcher中用到。
3 |8 B5 _1 Y2 _, H& N   安装完这此东西这开始执行PEIDispatcher函数,函数从BIOS ROM文件中找出PEI的Image(怎么找到,请读一下FV_HEAD(EFI_HEAD),里面讲到了如何区分Image类型),然后定位到PEI Image的入口地址,执行他。在我们的的PEI中,我们一般会申明一个PPI,这个就是这个PEI提供一些服务,PEIDispatcher会将他们加入到PPI-List中,以后其他Image也可以调用他的提供的功能。
% }, T$ H4 U: l0 Z: W   最后EDK会加载一个叫DXEIPL的PEI,DXEIPL提供一个PPI服务,这个PPI的功能是实现从PEI到DXE的切换,这个PPI里面为DXE做了很多的预准备,加载了很多PPI,如对BIOS的解压方法等。# c1 b( D' h% B) @
   SwitchStacks () k/ f( k+ r, z0 z8 N7 f6 S
       (VOID *) (UINTN) DxeCoreEntryPoint,
5 n- U# C4 N) a- R       (UINTN) (HobList.Raw),
% E5 h: Q% b& L+ W' d. {       (VOID *) (UINTN) TopOfStack,9 j* I- e) U: \, [3 A. b
       (VOID *) (UINTN) BspStore
# J  o! Y( R7 S$ i3 n- P    );
4 l7 \" h8 x( H5 {4 B  用过汇编的人对这个技术一定很熟悉,不多说了(我别不清,咯。。。)7 i: O, n9 d6 w" @! q
1 d' [6 l& t" @( F2 G
DXE:5 Z3 m, W  F) V0 O' ~# ~! B
     从PEI到DXE切换时转过来一个HOBLIST参数,DXE会在这个HOB中找到Memory的使用情况,然后根据这些情况将BIOS引到内存(这是EFI的做法)。在EDK在DXE时重新定位一下内存。
* Y0 N% Q5 ^# |接着就会定义我们经常使用到的gST表,gRT表。接着是申明一些Protocol(先不关心这些事)。6 u. X1 ~+ w% t
   等这些该加的PPI,Protocol加完了,CoreDispatcher()就出场了。他会的功能类似PEIDispatcher()。从我们BIOS ROM中将DXE的驱动读出,执行执行他们,这时会执行到Driver
! P- n, ^0 |) x0 ?( c0 R中的Support(),Start()两个功能函数。在这两个函数中你可以注册自己的PPI,为其他驱动提供服务。1 t& [8 g2 t) r* p- ?
   到些BIOS的引导其他完成。接着该进OS了,看Linux 0.11吧,操作系统是怎么做事情的。0 N: v. k' s! b  C+ m7 \
   9 n; Y9 D3 Q& s- w
Driver:
4 n9 B* K) t+ k& q+ c& }2 p0 P    我们的驱动什么为在PEI和DXE等不同阶段执行呢?
. \6 V" ^  E% D+ r# L5 j; s5 _$ }  大家请看一下我们的驱动的makefile.(EDK中的*.inf)
- `9 r# m' f0 H# F5 s  [defines]& Y2 y# J1 `( S& y1 M6 b. r- z! w
  BASE_NAME            = OWEN+ ]8 f0 X# J$ r% N, {2 z
  FILE_GUID            = 1EDD13C1-62EF-4262-A1AA-0040D0830110
2 f5 a7 [7 P: }! X3 |2 Z# f( c  COMPONENT_TYPE       = BS_DRIVER
) z6 |% x& y' C2 i8 B2 D' R8 o  ?# y9 g( x; M
  BASE_NAME告诉编译器最终生成的驱动的名字。
& Q8 p: A; a& c+ m: k* _4 |  FILE_GUID就是这个驱动的GUID名字,在BIOS中引用某个驱动就是根据它来调用和识别。
  Y1 K& r" h9 M$ A  COMONENT_TYPE会告诉编译器生成驱动的类型,是PEI,DXE,等。
; k& }# e& F+ a- j  在EDK中有一个FWVolume.c实现的功能就是帮我们把这个TYPE转换面相应的扩展名( y1 x# G8 d1 V: P! d1 h" C* J
  COMP_TYPE_EXTENSION  mCompTypeExtension[] = {
" M" E- o/ M6 w# s/ q% T  {"bs_driver",  ".dxe" },
3 Q' }* C: S0 I( I1 y  {"rt_driver",  ".dxe" },
3 J$ U9 u2 r& z  H/ R! y  {"sal_rt_driver", ".dxe"},. o( {1 `; R4 y1 o' ~7 o
  {"security_core", ".sec"},
+ Z5 I) G* `% K  B7 h& m  {"pei_core", ".pei"},
) g! T/ v/ }: T) S7 T& _+ s+ n# S' P  {"pic_peim", ".pei"},3 I. v4 ^, ?$ N' _; t
  {"pe32_peim", ".pei"},
5 d1 U$ ^+ n+ ^  {"relocatable_peim", ".pei"},
& Z. t& d' O) K( T$ ^5 j  {"binary", ".ffs"},
3 |: |9 H+ @+ |  {"application", ".app"},
8 d, H# I3 J0 a' U. q4 j8 Z  {"file", ".ffs"},
# r" ?3 T, Z$ Z: s. E  {"fvimagefile", ".fvi"},
1 X/ R0 n& |: v) c+ H  {"rawfile", ".raw"},
+ s% X; @% b7 J; d3 a) T: ^1 p+ A+ s  {"apriori", ".ffs"},
% [( }  M* M7 S- f' U7 E  {"combined_peim_driver", ".pei"},/ F3 ?/ s1 F- c  x9 N3 {1 N( f( j
  { NULL,  NULL }/ w& `1 I+ i$ O& w) ^' `5 S1 a
};, u# k* d( ^' L) [
# e* z& H4 ^3 {7 }% r" D8 a% n
了解了这些,接下我们可以看驱动篇了。(Go On Study... Forever)
" ^2 R- S2 Q% j9 |. q# V1 C     {0 K. A+ m- m/ e6 n8 O
         " ^) r# r- j6 m) a
  
发表于 2008-7-27 12:30:15 | 显示全部楼层
不错!
, x- q' n/ H/ M! e1 P1 \支持
0 G7 Y& P. k% S继续
' ?& h3 f1 j6 n加油$ \& ], L6 m# b6 [8 y  n. Q
回复

使用道具 举报

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

回复 1# 的帖子

gPrivateDispatchTable 和COMP_TYPE_EXTENSION  没有搜到啊  是EDK专有的么?
3 V3 ]. s+ `8 S9 s有看过跟gPrivateDispatchTable 类似的,但是里面的PPI不同。
0 c% J8 C# X/ y还有这个COMP_TYPE_EXTENSION  没有找到过。FWVolume.c这个文件也没有发现。。
回复

使用道具 举报

发表于 2008-7-28 13:24:20 | 显示全部楼层
这东西虽说没有什么技术含量,但是总结一下还是非常好的。% U" `2 }/ Z2 d0 {

5 ]5 m  T/ |8 ?支持!
回复

使用道具 举报

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

% I; L( b) g0 O1 x1 O: s' z小弟还在学习阶段,目前的目标是知道执行的流程。
" d* E9 |0 u# B: t5 H这里面有很多细节没有写,能力有限,只能自己知道,不能表达。3 }; [5 L, b7 ~3 }/ v; u
嘿。。。。
" m* G  e% d/ T6 q: N# I7 e, ]所有大侠们如果有好东西能给小弟共享一份。
8 _& Q; I5 E$ b5 T
9 v5 M3 |7 c, T谢谢!
回复

使用道具 举报

发表于 2008-8-12 14:44:11 | 显示全部楼层
原帖由 winbondowen 于 2008-7-27 00:11 发表
: G0 g; U! F% ]; s) N$ u. S  ROM中將DXE的驅動讀出,執行執行他們,這時會執行到Driver
* F; w. G; |' K5 G: G6 L# s中的Support(),Start()兩個功能函數。在這兩個函數中你可以註冊自己的PPI ...
: \: P# E( ]% s* X  O7 T3 n, K
) x3 ^! ~, M8 P4 A; q2 A6 ^
PPIs are registered during PEI phase, but Support()/Start() are invoked in DXE driver binding protocol, ; _7 q9 g; _% x4 J
For more precisely, I think the "PPI" you mentioned is the "PROTOCOL" rather than "PPI".0 F9 n; w0 E3 X, e7 Z0 @

5 A8 T6 P2 @) d( 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:
8 D+ a( Z* _+ [6 S% Z) _   Yes. I make a mistake.
6 G  E" y/ U6 ^5 _& t      PPI:     A PEIM to PEIM interface.2 q" b8 S# |# ^* D3 t
      PROTOCL: A Interface between Hardware(or firmware) and software." R5 V$ T' x* u0 |5 H
      reference[http://www.biosren.com/viewthread.php?tid=207]" w5 U( |; m1 t( x  b4 i3 J
   so, PPI execute at PEI step and Initialize hardware. PROTOCOL execute by DXE step.
2 h# U* ]) H/ l5 v- O: A   Thanks.
回复

使用道具 举报

发表于 2008-8-20 17:47:21 | 显示全部楼层
原帖由 winbondowen 于 2008-7-27 00:11 发表 DXE:
( G5 |! h/ L5 s; d     從PEI到DXE切換時轉過來一個HOBLIST參數,DXE會在這個HOB中找到Memory的使用情況,然後根據這些情況將BIOS引到內存(這是EFI的做法)。在EDK在DXE時重新定位一下內存。) N* _, n4 z# M2 q3 w% k; u
接著就會定義我們經常使用到的gST表,gRT表。接著是申明一些Protocol(先不關心這些事)。
+ H8 D( c$ P* r3 A% I   等這些該加的PPI,Protocol加完了,CoreDispatcher()就出場了。他會的功能類似PEIDispatcher()。從我們BIOS ROM中將DXE的驅動讀出,執行執行他們,這時會執行到Driver
' X/ y1 w4 ]& A2 p8 ]中的Support(),Start()兩個功能函數。在這兩個函數中你可以註冊自己的PPI,為其他驅動提供服務。! v0 S5 r( ^' v9 V& f8 D
   到些BIOS的引導其他完成。接著該進OS了,看Linux 0.11吧,操作系統是怎麼做事情的。.

2 v/ V4 t  s0 }7 N% B9 V0 z. |! {8 u+ z+ W) g# `
There are mistakes," c+ s! U8 ]" E3 H: k  q* z! D
1.gST and gRT are init after the DXE architectural protocols have been loaded, those protocols response for creating Dxe foundation.6 ^# X+ Q' `/ b. g* ^/ }" s6 a9 |

# s* n% e: u% I* O* l/ P5 @: E! N2.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.: p& V' k+ d; @2 k% c4 N
The CoreDispatcher() executes all trusted Dxe drivers and just register the Binding protocol if the driver is EFI1.1 driver model." g- H# v3 D; O4 I- c
Furthermore, Support()/Start() are invoked in BDS phase over the CoreConnectController() rather than CoreDispatcher().( f0 B7 r4 s5 A. ?5 J
9 R/ d8 c8 l6 r( p4 [2 p
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 大侠的指点。
2 p5 x; m0 a7 Z- x1 Y1 F: i' C
回复

使用道具 举报

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

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

原帖由 ichirohiro 于 2008-8-20 17:47 发表 8 a0 r  j8 H0 z; t% D8 J& |
...
; `+ s. @% O) n, w2.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.
$ Z3 C) B' d8 SThe CoreDispatcher() executes all trusted Dxe drivers and just register the Binding protocol if the driver is EFI1.1 driver model.
8 l& J" z# Y) c% s- G7 @) d/ P% KFurthermore, Support()/Start() are invoked in BDS phase over the CoreConnectController() rather than CoreDispatcher().

1 A2 J4 ]" K! O, b/ W0 `! r$ B    在Framework的spec DxeCis.pdf里面也是这么说的,DXE CoreDispatcher()里面,对于EFI1.1 driver model的driver只会安装Handler和Interface到Binding protocol,到BDS才会去执行Support()和Start().
0 d4 p- G6 C  W0 ~    但是,我在看code时,发现在CoreDispatcher()-->CoreStartImage()里面call image之后有这么一句:  (file:image.c)
% f: _7 {2 g. i6 b# K1 L  //& q# k5 s; T0 f5 K& z
  // Go connect any handles that were created or modified while the image executed.- W8 H- n) u; h4 Z3 a
  //* N1 f6 Y  y. B1 b
  CoreConnectHandlesByKey (HandleDatabaseKey);

: ~% }$ `* M( A6 a" Q! a: Q这里的HandleDatabaseKey是call image之前由CoreGetHandleDatabaseKey()得到的gHandleDatabaseKey6 G" U" V% x" b! ]# i; q5 c
而CoreConnectHandlesByKey会调用到:: M& b; f. u, p$ [
  //% B' t. N9 f) N* W
  // Connect all handles whose Key value is greater than Key
. [4 B% D1 B+ @  //$ Q2 n# I/ G2 y
  for (Index = 0; Index < Count; Index++) {
2 W. a7 f* M9 W: W5 y2 O! f    CoreConnectController (HandleBuffer[Index], NULL, NULL, TRUE);* g& j2 v; \0 n9 D( z( ?7 v
  }
7 ]" ^( j7 e; x5 o4 u
所以,照code看,当在Driver中安装一个Handle和Interface到Binding Protocol后(gHandleDatabaseKey会++,IHandle的Key=gHandleDatabaseKey)- f6 M  |; n( e. G; g% t9 a0 ^5 v1 Z
是会去ConnectController的,也会执行对应的Support()和Start()才对!!
5 S; T* c4 z- \6 G2 E; H. h& m+ q. z3 P. \& H1 d
不知道我想的哪里有问题???欢迎大家指正.
  }  l& r) Q& L- b; c! c4 M- f7 k& t8 m, y$ w5 O
[ 本帖最后由 xtdumpling 于 2008-9-18 15:25 编辑 ]
回复

使用道具 举报

发表于 2008-9-19 14:44:41 | 显示全部楼层
这段code似乎是一个向后兼容的行为,不必太care。
2 A; L# M2 i3 Z: b/ R, u3 B一个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 | 显示全部楼层
了解了.( F6 T2 w) _1 [( v7 F5 F* H3 O
非常 感谢!!!
回复

使用道具 举报

发表于 2008-9-23 16:48:56 | 显示全部楼层
在读DXEmain时,
$ k2 A. l* x1 U+ Z' Z9 LStatus = CoreInitializeImageServices(HobStart);--->CoreInstallProtocolInterface();--->CoreInstallProtocolInterfaceNotify();中,
, ~8 L5 Y& h& y: R0 t. t' D//  G& b# i; ~/ C2 l0 l$ T7 s3 v
// Notify the notification list for this protocol.
; Z- m' l+ b8 y) g& Q6 _! g0 P1 r//
* \3 A( J! M" G# P+ \# i$ Gif (Notify) {* D- ~) f7 ]; n/ Q
  CoreNotifyProtocolEntry(ProtEntry);& z' D4 b: T! e1 O( ]
}    里Signal了Event. MS是说一个handle安装了一个protocol后就signal一次.
7 M' F* [4 D; L* i# y/ G有个问题请教一下大家: 这段是在DXE很靠前的位置执行的,但是在它之前我没有看到DXE中有相关的CreateEvent出现?哪位高手能说说这部分代码的流程呢?
回复

使用道具 举报

发表于 2008-9-23 17:04:14 | 显示全部楼层
原帖由 xtdumpling 于 2008-9-16 13:34 发表 4 C4 Q+ w) s+ d- b- L, n' _
请楼上的兄弟分析下BS的RegisterProtocolNotify也就是CoreRegisterProtocolNotify是做什么用的?怎么用?
; b# O* X% z% T0 N; ^+ B谢谢!
  e. J: [# R( k9 s1 p7 Q$ P5 |6 H
......1 {7 ^) a2 o' P- ~: g

7 @/ ?( x. N+ ~, `/ u: P9 W
  c& q  B  ^. B( n7 l, s/ c[ 本帖最后由 xtdumpling 于 2008-9-23 17:24 编辑 ]
回复

使用道具 举报

发表于 2008-9-24 12:43:45 | 显示全部楼层
原帖由 xtdumpling 于 2008-9-23 17:04 发表 * j' y5 V/ R3 S

' v9 }- I# u, N0 d8 S9 l......) p2 L; A# x9 k( O$ h

1 n, k4 x$ O& ~! l- k9 zSignal的Event是不是在各个TPL级上挂载一些待处理的事件,一旦restore(TPL)的话,比当前TPL级高的pending事件就回被处理掉?
, i0 U; D) Y2 b6 I' E如果是这样的话,Timer事件是如何处理的呢,没有找到相关的代码呀?Xt指点一下再~
回复

使用道具 举报

发表于 2008-9-24 19:00:46 | 显示全部楼层
Timer是挂在8259的IRQ0的中断处理程序上面的, 大概每秒18.3次调用CoreTimerTick()-->CoreCheckTimers()
# U& f& a/ x% j& N: h% C- DTPL=30
回复

使用道具 举报

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

本版积分规则

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

GMT+8, 2026-9-19 22:00 , Processed in 0.080653 second(s), 16 queries .

Powered by Discuz! X3.5

© 2001-2025 Discuz! Team.

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