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

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

[复制链接]
发表于 2008-7-27 00:11:28 | 显示全部楼层 |阅读模式
  最近在工作看到机台有启动过程中把SPI ROM数据清空,但苦与没有办法很好的Debug(PCA没有架起来),所有与EDK为对象好好的读了一把。- u7 y$ S/ b4 l- U2 F! u* @
: N6 l9 ]& j& c9 |# S
SEC/CEI:
$ w5 c, |6 l# q. i  UEFI BIOS启动时先会执行SEC/CEI,这个阶段在实现的BIOS Code中初始化Debug Port,进入Big Mode,CPU的MicroCode,CacheToRAM的转换.然后跳转到PEI阶段。
& x/ E$ ?* L8 C5 a: I+ _在EDK中这部分被成了Load FvRecovery.fd文件,这个文件类似与我们的BIOS ROM.里面是我们编译后生成的二进制代码。在这个阶段最主要的是将这个文件加载到内存中(Windows API将文件加载到内存,看API函数).5 Y& ]  D, C; R5 x
  y1 q5 a) {+ |( ~
PEI:
9 |) g) w& y4 L8 O% `' _5 M3 v   从这里开始UEFI BIOS和EDK执行基本相同,只是一个是从SPI ROM中定位一个地址(PEIM的开始地址),一个是从内存中定位一个地址(PEIM的开始地址)。从这里开始只讲EDK的执行
6 V+ s5 X- v# L' ~( F  EDK调用InitializeMemoryService函数,将HobList清空,peiservice清空。
/ g$ W' q: y& H. ^/ C; t! |/ b7 }      InitializePPIService函数,将PPI队列清空,这个队列长0x3F.
; N1 Y! O% _: J3 }- P, `5 t, j          InitializeSercurityService函数,将Notify队列清空。
6 {% }' z. v5 W$ l* z          InitializeDispatcherData函数,将Dispatcher队列清空。
' [& p, t( X1 B" Z* b9 W8 P  接着由PeiBuildHobGuid来建立一个HOB(S3返回时这时应该有这个HOB,不用建立,直接使用了,这样就会进入另外一个流程,可以这个EDK不能调试S3,不知道怎么走)。然后由(*PeiServices)->InstallPpi()将这个新HOB加入到PPI中。
, Q$ e. d! [1 O8 }" d% o    由于在SEC阶段转了以下这几具PPI,所以在执行PEI的Dispatcher之前会先安装东西:
- O: u' N' N# d! a: d! s6 g      EFI_PEI_PPI_DESCRIPTOR    gPrivateDispatchTable[] = {
: |- }* {/ s. X8 I( V       {EFI_PEI_PPI_DESCRIPTOR_PPI, &gEfiNtLoadAsDllPpiGuid, &mSecNtLoadAsDllPpi},* _7 x7 H- p' d; ?9 n7 M4 d
       {EFI_PEI_PPI_DESCRIPTOR_PPI, &gNtPeiLoadFileGuid, &mSecNtLoadFilePpi},
6 N0 {, W3 f% `, x+ |1 Y       {EFI_PEI_PPI_DESCRIPTOR_PPI, &gPeiNtAutoScanPpiGuid, &mSecNtAutoScanPpi},
! |4 N" ~: D) L2 J. k4 J  r" d       {EFI_PEI_PPI_DESCRIPTOR_PPI, &gPeiNtThunkPpiGuid, &mSecWinNtThunkPpi},- l2 y- f- Z  ^  v3 y' Y" i# M2 X
       {EFI_PEI_PPI_DESCRIPTOR_PPI, &gPeiStatusCodePpiGuid, &mSecStatusCodePpi},
' x5 L0 p& p0 R0 z3 l       {EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST, &gNtFwhPpiGuid, &mSecFwhInformationPpi}
) {6 t8 x) z& H% T     };
, k9 c" h0 Y3 l+ u    每个PPI是由{类型,GUID(名字,以后就根据这个来找到它的),Function_Entry_Address}组成。
! X6 |3 G; A0 y" {   这些PPI会在PEIDispatcher中用到。
# |" C$ ?4 i7 t2 j& o   安装完这此东西这开始执行PEIDispatcher函数,函数从BIOS ROM文件中找出PEI的Image(怎么找到,请读一下FV_HEAD(EFI_HEAD),里面讲到了如何区分Image类型),然后定位到PEI Image的入口地址,执行他。在我们的的PEI中,我们一般会申明一个PPI,这个就是这个PEI提供一些服务,PEIDispatcher会将他们加入到PPI-List中,以后其他Image也可以调用他的提供的功能。
' ~7 G( X0 ]( t   最后EDK会加载一个叫DXEIPL的PEI,DXEIPL提供一个PPI服务,这个PPI的功能是实现从PEI到DXE的切换,这个PPI里面为DXE做了很多的预准备,加载了很多PPI,如对BIOS的解压方法等。- O1 D2 Y* j% P& Q# |& I, [
   SwitchStacks (
8 b/ W/ I! R( j8 e( P6 D       (VOID *) (UINTN) DxeCoreEntryPoint,6 x9 W5 m3 e/ ~& g
       (UINTN) (HobList.Raw),/ J% W4 ^4 y* {6 T% ^
       (VOID *) (UINTN) TopOfStack,% N' I7 V/ A& F
       (VOID *) (UINTN) BspStore
, a/ w$ Z) K( D% O8 M- j* g    );
: V" i6 a; O+ d  ]7 Q# \/ c  用过汇编的人对这个技术一定很熟悉,不多说了(我别不清,咯。。。)* v$ c5 N5 i% L
% l$ G( {9 b* \' L
DXE:9 Y8 z. q+ j+ l& H
     从PEI到DXE切换时转过来一个HOBLIST参数,DXE会在这个HOB中找到Memory的使用情况,然后根据这些情况将BIOS引到内存(这是EFI的做法)。在EDK在DXE时重新定位一下内存。
! E2 ?, q9 e- h, ~4 h2 H接着就会定义我们经常使用到的gST表,gRT表。接着是申明一些Protocol(先不关心这些事)。" `2 _- z" p. m4 o0 \
   等这些该加的PPI,Protocol加完了,CoreDispatcher()就出场了。他会的功能类似PEIDispatcher()。从我们BIOS ROM中将DXE的驱动读出,执行执行他们,这时会执行到Driver
+ f, C: |7 v$ }. n$ B' D$ A中的Support(),Start()两个功能函数。在这两个函数中你可以注册自己的PPI,为其他驱动提供服务。
8 O/ v5 y6 ^7 d   到些BIOS的引导其他完成。接着该进OS了,看Linux 0.11吧,操作系统是怎么做事情的。
: T1 U5 K. x, u: H/ w( W/ f   
; w3 P: W9 {7 W- r' V9 }: X: w4 D' cDriver:. K0 K, S2 Y2 ?  v0 D7 w3 h( L
    我们的驱动什么为在PEI和DXE等不同阶段执行呢?  N9 I; G) v& O# t4 Y
  大家请看一下我们的驱动的makefile.(EDK中的*.inf)6 o/ A# F! U$ f' M8 f6 _
  [defines]& ~$ {6 R4 |0 ], ^
  BASE_NAME            = OWEN/ {4 a; u7 _0 n5 i
  FILE_GUID            = 1EDD13C1-62EF-4262-A1AA-0040D0830110# [( x7 K1 a4 l$ h# g/ ?
  COMPONENT_TYPE       = BS_DRIVER" ~( }# {2 y# S' t1 D- b

  ?: E1 P1 C" Y  BASE_NAME告诉编译器最终生成的驱动的名字。
; H  W4 e3 V* N+ ~8 s1 J  FILE_GUID就是这个驱动的GUID名字,在BIOS中引用某个驱动就是根据它来调用和识别。  ~1 F; e" a7 Z  t0 |; D. I4 X5 o
  COMONENT_TYPE会告诉编译器生成驱动的类型,是PEI,DXE,等。
! B& L' c( \* I! f  B  在EDK中有一个FWVolume.c实现的功能就是帮我们把这个TYPE转换面相应的扩展名
$ S1 q& p, J. p6 }# x" m: c" K  COMP_TYPE_EXTENSION  mCompTypeExtension[] = {
3 _  f; `3 q6 F* b0 c' x# H/ t  {"bs_driver",  ".dxe" },- w) \, P0 c0 G1 u1 P
  {"rt_driver",  ".dxe" },1 x1 y# }5 f, U
  {"sal_rt_driver", ".dxe"},
" ^5 X% Z" ?. S  {"security_core", ".sec"},
6 ?( V0 r% |9 ]! N1 L  {"pei_core", ".pei"},
) k% j2 K; Y$ l2 k) i  {"pic_peim", ".pei"},1 R/ S, u$ H- R7 D
  {"pe32_peim", ".pei"},
- y* V. f5 ]) g# d8 u, y5 G: d  {"relocatable_peim", ".pei"}," y! ]9 y( ?0 r" d' c
  {"binary", ".ffs"},' v& r6 X2 X2 P
  {"application", ".app"},
% b6 o0 S2 @* J+ L( X4 {  {"file", ".ffs"},$ q3 h6 y8 h7 t; Q& O- ^- V8 V
  {"fvimagefile", ".fvi"},  v$ W- L' S. ^! s; K5 N" }
  {"rawfile", ".raw"},
3 G% _2 a) H" X8 b( b, f& v6 K: i  {"apriori", ".ffs"},, \6 p8 Y. A6 Z! p4 a0 n5 [( t) W8 [
  {"combined_peim_driver", ".pei"},+ C+ a% O3 I7 n/ @0 m6 [4 V
  { NULL,  NULL }( W/ g' k: K# Y; E; \2 z4 F% W
};
/ f7 }/ Q6 Q% ]8 D; m
% h6 {- j8 }9 P5 ~; H, r了解了这些,接下我们可以看驱动篇了。(Go On Study... Forever)
/ G9 L. t/ k7 X2 y- _4 R  C   
9 a2 z7 k0 P* e  l" |1 M! k9 i! s         
/ a) W/ ]& H. X! n7 O2 H  
发表于 2008-7-27 12:30:15 | 显示全部楼层
不错!0 o* z( I; Q5 q6 W% m. n$ x
支持
. l) \( H* P! |6 a: o/ H( T继续; ~5 W7 ~. @7 W( ~4 W; x9 R
加油
- d  m1 s3 S7 w" N
回复

使用道具 举报

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

回复 1# 的帖子

gPrivateDispatchTable 和COMP_TYPE_EXTENSION  没有搜到啊  是EDK专有的么?+ N/ Y. W6 [) r( O
有看过跟gPrivateDispatchTable 类似的,但是里面的PPI不同。8 y3 j8 G2 L% R9 _! x
还有这个COMP_TYPE_EXTENSION  没有找到过。FWVolume.c这个文件也没有发现。。
回复

使用道具 举报

发表于 2008-7-28 13:24:20 | 显示全部楼层
这东西虽说没有什么技术含量,但是总结一下还是非常好的。
; ~) F  m. O( N
( K8 z9 I5 L- H* B支持!
回复

使用道具 举报

 楼主| 发表于 2008-7-28 18:52:31 | 显示全部楼层
; q. N$ ^& [! [6 X
小弟还在学习阶段,目前的目标是知道执行的流程。: k0 w$ X3 b7 y( T  Z' g( v; n  r3 h4 H
这里面有很多细节没有写,能力有限,只能自己知道,不能表达。* E9 j. u- }* Q3 H) C3 d: ~
嘿。。。。0 {' T$ q) ^6 l4 V8 u4 M5 k
所有大侠们如果有好东西能给小弟共享一份。  F6 W' ^6 u3 _* Q3 r) P. t" a) `
- v- W$ L6 F( ~$ y. s0 [- l
谢谢!
回复

使用道具 举报

发表于 2008-8-12 14:44:11 | 显示全部楼层
原帖由 winbondowen 于 2008-7-27 00:11 发表 ' \/ r% H3 {2 q" z. ^( ]9 W& y
  ROM中將DXE的驅動讀出,執行執行他們,這時會執行到Driver
2 ^% |& s& `% T! Y/ X! l5 F中的Support(),Start()兩個功能函數。在這兩個函數中你可以註冊自己的PPI ...

& a8 A2 D+ t0 h1 X* ~+ K0 @- S: n' z: y; i+ I
PPIs are registered during PEI phase, but Support()/Start() are invoked in DXE driver binding protocol,
; `: |  g# S$ m& C$ gFor more precisely, I think the "PPI" you mentioned is the "PROTOCOL" rather than "PPI".1 ^. v0 r  P* m# T" ~$ Y4 p  n* B
3 M1 ^7 {8 E4 h4 H0 i; t
[ 本帖最后由 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 H0 p9 j. |2 D! |2 y
   Yes. I make a mistake.
$ r) t( z8 m9 O      PPI:     A PEIM to PEIM interface.
0 c7 \* T+ X! l% ^. _4 F      PROTOCL: A Interface between Hardware(or firmware) and software.
# \' T# W* h% M. z* }6 w      reference[http://www.biosren.com/viewthread.php?tid=207]
8 }# E1 B) ]+ v/ \# g   so, PPI execute at PEI step and Initialize hardware. PROTOCOL execute by DXE step.8 {* {' T$ z5 u) e
   Thanks.
回复

使用道具 举报

发表于 2008-8-20 17:47:21 | 显示全部楼层
原帖由 winbondowen 于 2008-7-27 00:11 发表 DXE:
' w7 u7 g$ [, X3 N  t" m     從PEI到DXE切換時轉過來一個HOBLIST參數,DXE會在這個HOB中找到Memory的使用情況,然後根據這些情況將BIOS引到內存(這是EFI的做法)。在EDK在DXE時重新定位一下內存。" C, @+ b3 U" F+ E& X: g
接著就會定義我們經常使用到的gST表,gRT表。接著是申明一些Protocol(先不關心這些事)。
& R, v5 g- m1 I: A* {3 ?   等這些該加的PPI,Protocol加完了,CoreDispatcher()就出場了。他會的功能類似PEIDispatcher()。從我們BIOS ROM中將DXE的驅動讀出,執行執行他們,這時會執行到Driver
. P2 {2 L* u' s8 r7 ^  ~中的Support(),Start()兩個功能函數。在這兩個函數中你可以註冊自己的PPI,為其他驅動提供服務。4 M+ O$ a" y/ E$ T! N9 w
   到些BIOS的引導其他完成。接著該進OS了,看Linux 0.11吧,操作系統是怎麼做事情的。.
$ A9 A5 j) |3 X: O: t

( k4 x* Y  `3 s  ?! HThere are mistakes,# p2 Z' h- ]) P# m
1.gST and gRT are init after the DXE architectural protocols have been loaded, those protocols response for creating Dxe foundation.' U8 I% S  C7 i# F( j/ L/ L
& @# s8 x4 i9 G. s. c
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.  p/ E, M3 a. ^; L6 _
The CoreDispatcher() executes all trusted Dxe drivers and just register the Binding protocol if the driver is EFI1.1 driver model.2 s- t" _8 T& s* P4 H
Furthermore, Support()/Start() are invoked in BDS phase over the CoreConnectController() rather than CoreDispatcher().7 E- [' a8 U. w* |: c

' r# ~+ i5 h  f4 }2 w6 j$ ?) ?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 大侠的指点。9 i4 U' f3 B% B+ c4 O
回复

使用道具 举报

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

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

原帖由 ichirohiro 于 2008-8-20 17:47 发表 ( X# \+ M1 }* D" B
...
0 X6 Y, C/ T3 e, \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.* S: _$ s9 I1 C- }9 k, X
The CoreDispatcher() executes all trusted Dxe drivers and just register the Binding protocol if the driver is EFI1.1 driver model./ Q$ \( {9 a# u# o$ j
Furthermore, Support()/Start() are invoked in BDS phase over the CoreConnectController() rather than CoreDispatcher().

! ^7 ?3 \- ]6 ]# U9 L; z% K    在Framework的spec DxeCis.pdf里面也是这么说的,DXE CoreDispatcher()里面,对于EFI1.1 driver model的driver只会安装Handler和Interface到Binding protocol,到BDS才会去执行Support()和Start().% C, q- [& _% m# M8 G* T
    但是,我在看code时,发现在CoreDispatcher()-->CoreStartImage()里面call image之后有这么一句:  (file:image.c)
9 H" d) M0 V/ Y, L8 `  //
* f- b; {: U. D. T- o7 d  // Go connect any handles that were created or modified while the image executed.
: f9 M9 r# O1 J) _2 P9 S  //
; f+ |: ]! C# \% ?, C  CoreConnectHandlesByKey (HandleDatabaseKey);

1 `8 d5 Z. _' J# h这里的HandleDatabaseKey是call image之前由CoreGetHandleDatabaseKey()得到的gHandleDatabaseKey; C4 Y' n$ j5 U: h9 i
而CoreConnectHandlesByKey会调用到:
1 a# j7 ], {; u1 |( d- ~  //
6 {* B' f1 t- y7 O& h5 q: A  // Connect all handles whose Key value is greater than Key. h& o; w+ Z" q8 y$ w. K. B
  //! j! f0 }8 s( v% t3 P* a
  for (Index = 0; Index < Count; Index++) {
7 A5 B4 q/ [7 Z9 l8 X3 S    CoreConnectController (HandleBuffer[Index], NULL, NULL, TRUE);
) T, P8 O. o$ S: F5 s  }

% H, D3 m+ E/ O所以,照code看,当在Driver中安装一个Handle和Interface到Binding Protocol后(gHandleDatabaseKey会++,IHandle的Key=gHandleDatabaseKey)
1 m, w6 m( I9 Q8 ?+ f0 R是会去ConnectController的,也会执行对应的Support()和Start()才对!!+ `  `4 t! }/ \2 ?; ~- B! C

4 l( F0 ^. y0 k不知道我想的哪里有问题???欢迎大家指正.( N# d9 `: l$ [' u5 H1 \
- @' Y& k# f- y* f7 r
[ 本帖最后由 xtdumpling 于 2008-9-18 15:25 编辑 ]
回复

使用道具 举报

发表于 2008-9-19 14:44:41 | 显示全部楼层
这段code似乎是一个向后兼容的行为,不必太care。5 j1 ^$ x. J4 Y" t3 o( O. c
一个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 | 显示全部楼层
了解了.
# J7 @! _! F" R: J非常 感谢!!!
回复

使用道具 举报

发表于 2008-9-23 16:48:56 | 显示全部楼层
在读DXEmain时,8 x( M( Y; [$ r1 P
Status = CoreInitializeImageServices(HobStart);--->CoreInstallProtocolInterface();--->CoreInstallProtocolInterfaceNotify();中,' Q# L- p! ~! p$ h
//% A+ Y4 d* b, P$ N* O5 |; K
// Notify the notification list for this protocol.
' Y* k* }2 `: j; r//
3 I* ~' G6 o8 I$ g( Q8 s; fif (Notify) {( S3 `9 Z5 ]9 v5 _5 t0 U0 h" U' K
  CoreNotifyProtocolEntry(ProtEntry);/ h* C* d0 q. B0 P  d
}    里Signal了Event. MS是说一个handle安装了一个protocol后就signal一次.
( n$ R7 i( m1 b+ X3 N# P$ L- C有个问题请教一下大家: 这段是在DXE很靠前的位置执行的,但是在它之前我没有看到DXE中有相关的CreateEvent出现?哪位高手能说说这部分代码的流程呢?
回复

使用道具 举报

发表于 2008-9-23 17:04:14 | 显示全部楼层
原帖由 xtdumpling 于 2008-9-16 13:34 发表 " @- C/ g/ V" o; ~( ]: r
请楼上的兄弟分析下BS的RegisterProtocolNotify也就是CoreRegisterProtocolNotify是做什么用的?怎么用?! U7 G* V9 K- P/ A9 K6 f
谢谢!

4 W( V. ~7 S. M  O......
8 Y$ s* f* p) j9 Q/ x: J) P3 G7 X! {6 ?* {2 Y" D
- |' v4 _# X+ N# z/ T) M& P
[ 本帖最后由 xtdumpling 于 2008-9-23 17:24 编辑 ]
回复

使用道具 举报

发表于 2008-9-24 12:43:45 | 显示全部楼层
原帖由 xtdumpling 于 2008-9-23 17:04 发表 # K$ Y5 U  r' ]* c

. w3 }/ R9 M' X8 b$ M7 t/ I......
+ s2 e- j: \% `  l0 M5 U9 g

+ E6 n  \3 B3 t# B( d/ M4 uSignal的Event是不是在各个TPL级上挂载一些待处理的事件,一旦restore(TPL)的话,比当前TPL级高的pending事件就回被处理掉?2 V. b: }- `+ \- {/ {
如果是这样的话,Timer事件是如何处理的呢,没有找到相关的代码呀?Xt指点一下再~
回复

使用道具 举报

发表于 2008-9-24 19:00:46 | 显示全部楼层
Timer是挂在8259的IRQ0的中断处理程序上面的, 大概每秒18.3次调用CoreTimerTick()-->CoreCheckTimers()4 [  b. g! R5 k( m1 e7 z9 b
TPL=30
回复

使用道具 举报

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

本版积分规则

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

GMT+8, 2026-4-20 03:37 , Processed in 0.044524 second(s), 17 queries .

Powered by Discuz! X3.5

© 2001-2025 Discuz! Team.

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