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

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

[复制链接]
发表于 2008-7-27 00:11:28 | 显示全部楼层 |阅读模式
  最近在工作看到机台有启动过程中把SPI ROM数据清空,但苦与没有办法很好的Debug(PCA没有架起来),所有与EDK为对象好好的读了一把。
4 m& A0 R( b6 I" j5 X
# _- B- p" b2 j8 m9 r7 B' |SEC/CEI:- |5 e% X% ~7 _) R# b
  UEFI BIOS启动时先会执行SEC/CEI,这个阶段在实现的BIOS Code中初始化Debug Port,进入Big Mode,CPU的MicroCode,CacheToRAM的转换.然后跳转到PEI阶段。
: v9 P# Z9 Q2 _在EDK中这部分被成了Load FvRecovery.fd文件,这个文件类似与我们的BIOS ROM.里面是我们编译后生成的二进制代码。在这个阶段最主要的是将这个文件加载到内存中(Windows API将文件加载到内存,看API函数).4 Y. {' g8 |0 R  `
2 x" i; t9 ]$ a6 r3 o9 \* r
PEI:
. L( a) Q* ?3 V* q. s   从这里开始UEFI BIOS和EDK执行基本相同,只是一个是从SPI ROM中定位一个地址(PEIM的开始地址),一个是从内存中定位一个地址(PEIM的开始地址)。从这里开始只讲EDK的执行
' R% V5 M8 g& F( R7 N/ ?  EDK调用InitializeMemoryService函数,将HobList清空,peiservice清空。5 U# n/ o. _) ]6 q7 d' P6 q
      InitializePPIService函数,将PPI队列清空,这个队列长0x3F." P5 N0 Q3 H' s+ w4 I
          InitializeSercurityService函数,将Notify队列清空。
6 {8 A- s  q, ?# s  u          InitializeDispatcherData函数,将Dispatcher队列清空。
  ?$ ]3 C2 s8 e0 T& v$ l  接着由PeiBuildHobGuid来建立一个HOB(S3返回时这时应该有这个HOB,不用建立,直接使用了,这样就会进入另外一个流程,可以这个EDK不能调试S3,不知道怎么走)。然后由(*PeiServices)->InstallPpi()将这个新HOB加入到PPI中。
' h4 y5 M% n( v: }) @    由于在SEC阶段转了以下这几具PPI,所以在执行PEI的Dispatcher之前会先安装东西:! D& [5 e2 i& C! Q: p# i
      EFI_PEI_PPI_DESCRIPTOR    gPrivateDispatchTable[] = {
9 u1 B. R- d" j5 w( @. y: X5 L; H" d       {EFI_PEI_PPI_DESCRIPTOR_PPI, &gEfiNtLoadAsDllPpiGuid, &mSecNtLoadAsDllPpi},$ q  Z5 p' K5 ^, L8 v( W" ~
       {EFI_PEI_PPI_DESCRIPTOR_PPI, &gNtPeiLoadFileGuid, &mSecNtLoadFilePpi},
8 [$ j4 f) R: m0 u+ o       {EFI_PEI_PPI_DESCRIPTOR_PPI, &gPeiNtAutoScanPpiGuid, &mSecNtAutoScanPpi},
/ r& \7 m2 L% ]$ Q8 y- M, @+ }       {EFI_PEI_PPI_DESCRIPTOR_PPI, &gPeiNtThunkPpiGuid, &mSecWinNtThunkPpi},
3 ]6 `% p/ s, S% j) V  p+ N' J! f       {EFI_PEI_PPI_DESCRIPTOR_PPI, &gPeiStatusCodePpiGuid, &mSecStatusCodePpi},
  U1 A: W* r8 ?$ F3 O- C' Q" V  U       {EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST, &gNtFwhPpiGuid, &mSecFwhInformationPpi}
! ]1 p" J, c& P% ]+ m/ ~, w     };
% C# _! P+ c7 X1 }    每个PPI是由{类型,GUID(名字,以后就根据这个来找到它的),Function_Entry_Address}组成。3 s8 X, j) t# [; L# C* W* ^
   这些PPI会在PEIDispatcher中用到。5 s0 m9 a; W' m9 i1 Z! y
   安装完这此东西这开始执行PEIDispatcher函数,函数从BIOS ROM文件中找出PEI的Image(怎么找到,请读一下FV_HEAD(EFI_HEAD),里面讲到了如何区分Image类型),然后定位到PEI Image的入口地址,执行他。在我们的的PEI中,我们一般会申明一个PPI,这个就是这个PEI提供一些服务,PEIDispatcher会将他们加入到PPI-List中,以后其他Image也可以调用他的提供的功能。
+ B# m1 O8 F$ A+ {6 D$ y7 o% [   最后EDK会加载一个叫DXEIPL的PEI,DXEIPL提供一个PPI服务,这个PPI的功能是实现从PEI到DXE的切换,这个PPI里面为DXE做了很多的预准备,加载了很多PPI,如对BIOS的解压方法等。
! R; Z  R# o* O! M$ ^% O( n   SwitchStacks (# j( d7 n5 ]8 X# d; w
       (VOID *) (UINTN) DxeCoreEntryPoint,
' z5 e4 {: X/ C- E) ?* c  R) U3 c( ]       (UINTN) (HobList.Raw),
+ e: p; V8 w/ G+ a1 c       (VOID *) (UINTN) TopOfStack,
& s- k/ z) S7 K" F2 U5 T       (VOID *) (UINTN) BspStore& }1 w; R- ~  H
    );
/ ^3 u+ E: x% f0 N  用过汇编的人对这个技术一定很熟悉,不多说了(我别不清,咯。。。)# w* ^% z0 t$ O+ g5 L
# I# a! {( b1 z% L- O- V& g1 e
DXE:
: l; \+ }$ k1 B0 }' ?     从PEI到DXE切换时转过来一个HOBLIST参数,DXE会在这个HOB中找到Memory的使用情况,然后根据这些情况将BIOS引到内存(这是EFI的做法)。在EDK在DXE时重新定位一下内存。
: b; j- W7 w1 K# u  V  Q5 G+ {接着就会定义我们经常使用到的gST表,gRT表。接着是申明一些Protocol(先不关心这些事)。
* @  `& N  A9 b2 q% r   等这些该加的PPI,Protocol加完了,CoreDispatcher()就出场了。他会的功能类似PEIDispatcher()。从我们BIOS ROM中将DXE的驱动读出,执行执行他们,这时会执行到Driver
+ x- w) B: }# z* X- P中的Support(),Start()两个功能函数。在这两个函数中你可以注册自己的PPI,为其他驱动提供服务。
$ x; v. Q- J$ [, h" k' y* {   到些BIOS的引导其他完成。接着该进OS了,看Linux 0.11吧,操作系统是怎么做事情的。4 X* R& l$ P% i7 @4 a: A! O
   / [1 l: H6 o" u; h* S/ G( i" X9 H: A
Driver:. x. N% M9 m, u' ~. s4 |% u
    我们的驱动什么为在PEI和DXE等不同阶段执行呢?+ m1 Q1 E, m9 O. ?
  大家请看一下我们的驱动的makefile.(EDK中的*.inf): @2 H" B8 E3 {6 t) p
  [defines]# J2 _% Z, d4 w0 G! u
  BASE_NAME            = OWEN
( R% C% V/ [+ P, I  FILE_GUID            = 1EDD13C1-62EF-4262-A1AA-0040D0830110
5 y: J) N# x/ ?; v$ \7 }2 B5 x8 L  COMPONENT_TYPE       = BS_DRIVER8 P; d  W: H! k& p% ?
- I/ \) A4 X$ G% A
  BASE_NAME告诉编译器最终生成的驱动的名字。
' Z# R4 R7 T4 c  FILE_GUID就是这个驱动的GUID名字,在BIOS中引用某个驱动就是根据它来调用和识别。5 J8 R& r" d8 O/ c  n
  COMONENT_TYPE会告诉编译器生成驱动的类型,是PEI,DXE,等。
0 X6 i+ y( f" K  b( g  在EDK中有一个FWVolume.c实现的功能就是帮我们把这个TYPE转换面相应的扩展名
& y6 `5 d* D# n! ]  COMP_TYPE_EXTENSION  mCompTypeExtension[] = {
" U* Z0 t( b8 ?! J- D; R  {"bs_driver",  ".dxe" },
! [; G+ p, c0 p; v+ o+ N  {"rt_driver",  ".dxe" },
8 j( w% k# b6 `: H: _  {"sal_rt_driver", ".dxe"},
4 c. R/ h6 N% o7 O6 X  {"security_core", ".sec"},
) i- b# T/ H' f  {"pei_core", ".pei"},# N2 |: t* V: ^5 K% I# P
  {"pic_peim", ".pei"},
1 n- L1 y. Y0 z, z) s  {"pe32_peim", ".pei"},0 c- R0 p' b) U5 K' p& H- D
  {"relocatable_peim", ".pei"},$ A2 s) x0 k7 ?- V  i2 n
  {"binary", ".ffs"},( }1 ~/ w5 G4 o4 V* `$ ]- c
  {"application", ".app"},; S7 \# M+ [& Q* f3 X" ?7 C* J
  {"file", ".ffs"},
4 y! w' O+ s9 x# V- y  {"fvimagefile", ".fvi"},
$ x, B% t5 O" k' d  {"rawfile", ".raw"},+ r, z$ }6 H; `
  {"apriori", ".ffs"},
) s! d* t( ]' M9 t) |% Q# \  {"combined_peim_driver", ".pei"},
; u# h& l$ N# Q( E- C% Y  { NULL,  NULL }" y& k/ F3 ^. p' ~
};
7 ?- ]4 `( d3 T! {  H' b# W
2 k8 U6 G' v  K; v- D$ p了解了这些,接下我们可以看驱动篇了。(Go On Study... Forever)
2 O# T$ h0 U% u5 _   : f3 Y4 G  Q2 `* u  R, U% p0 u2 V/ L+ k
         ( H/ r' \  u: b
  
发表于 2008-7-27 12:30:15 | 显示全部楼层
不错!
0 R( N! a* D) ?4 g; a" w支持5 h1 n; m7 e0 O9 a  g/ s
继续
/ n/ k- J7 Q' N3 U/ x加油
! k, A5 o1 ^6 c: X: n  @# I
回复

使用道具 举报

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

回复 1# 的帖子

gPrivateDispatchTable 和COMP_TYPE_EXTENSION  没有搜到啊  是EDK专有的么?
5 X: k% V$ a. D" i有看过跟gPrivateDispatchTable 类似的,但是里面的PPI不同。
  u' V- W0 o: B6 G# H+ b还有这个COMP_TYPE_EXTENSION  没有找到过。FWVolume.c这个文件也没有发现。。
回复

使用道具 举报

发表于 2008-7-28 13:24:20 | 显示全部楼层
这东西虽说没有什么技术含量,但是总结一下还是非常好的。3 a9 a" J9 c1 w" D( o" a: v0 Y

- h$ X( [3 ~% I支持!
回复

使用道具 举报

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

$ d! Z9 `% e% D5 X小弟还在学习阶段,目前的目标是知道执行的流程。# s6 G1 |. c9 }7 x3 Y* n
这里面有很多细节没有写,能力有限,只能自己知道,不能表达。
! ~9 n( V5 E( N; `9 c: E嘿。。。。& l: a0 H2 h0 _" `# C! X
所有大侠们如果有好东西能给小弟共享一份。
8 R# A- a. C- g. `
4 \& F8 i- U; ^+ M& {' [) E谢谢!
回复

使用道具 举报

发表于 2008-8-12 14:44:11 | 显示全部楼层
原帖由 winbondowen 于 2008-7-27 00:11 发表
3 G# T4 \0 {% W. b( Q  ROM中將DXE的驅動讀出,執行執行他們,這時會執行到Driver
4 O, h: l1 t9 j$ O. a& i6 q中的Support(),Start()兩個功能函數。在這兩個函數中你可以註冊自己的PPI ...

: ^) h2 Y" [. E8 Z1 P6 o' S  |
- H& A  O% ~3 b& ]6 TPPIs are registered during PEI phase, but Support()/Start() are invoked in DXE driver binding protocol, ' i$ x- _1 a2 N( o0 d
For more precisely, I think the "PPI" you mentioned is the "PROTOCOL" rather than "PPI".+ j$ v9 d- C$ v# B8 T% i2 h8 V% X
; a8 K- r7 X: `$ z3 e6 e3 V3 J
[ 本帖最后由 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:9 C. o1 l$ G- B" H# A+ z
   Yes. I make a mistake.
  V( }) J* {: ?5 e      PPI:     A PEIM to PEIM interface.  k8 a; e5 y7 M' C4 W; \+ T( g
      PROTOCL: A Interface between Hardware(or firmware) and software.
1 x; D  w3 n+ ?3 R; E" V      reference[http://www.biosren.com/viewthread.php?tid=207]) Y0 o' N4 u5 j8 Y4 L( S
   so, PPI execute at PEI step and Initialize hardware. PROTOCOL execute by DXE step.8 h7 ~; e  ~/ R) W
   Thanks.
回复

使用道具 举报

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

; Z+ ]6 N* O, X6 N
5 A% H/ d$ r$ F" E8 V4 V- m  rThere are mistakes,
* J; Q' u: ^; `6 H) j1.gST and gRT are init after the DXE architectural protocols have been loaded, those protocols response for creating Dxe foundation.7 a3 p- t7 R9 _1 S9 y
4 t4 K) f; c- L6 e2 G3 g- \
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.4 P& p0 m6 j5 p7 O3 Z# D4 f2 v
The CoreDispatcher() executes all trusted Dxe drivers and just register the Binding protocol if the driver is EFI1.1 driver model.( K6 F7 S, ?- x' J: e
Furthermore, Support()/Start() are invoked in BDS phase over the CoreConnectController() rather than CoreDispatcher()./ H0 a' Z- z. p+ L
% Y2 K; e4 l$ r, t
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 大侠的指点。
3 o; H' z8 g$ H' h  x/ H7 B, u' B
回复

使用道具 举报

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

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

原帖由 ichirohiro 于 2008-8-20 17:47 发表
( G( C; N- i; W, S5 f$ T...8 T% H& B2 O8 W. j8 k$ ]7 t
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.
, C8 J* ^: k) h" P6 \+ m* LThe CoreDispatcher() executes all trusted Dxe drivers and just register the Binding protocol if the driver is EFI1.1 driver model.
& n& R/ k5 O2 y5 Y+ t4 cFurthermore, Support()/Start() are invoked in BDS phase over the CoreConnectController() rather than CoreDispatcher().
# Y6 T8 G- g9 c( M
    在Framework的spec DxeCis.pdf里面也是这么说的,DXE CoreDispatcher()里面,对于EFI1.1 driver model的driver只会安装Handler和Interface到Binding protocol,到BDS才会去执行Support()和Start().
0 J$ T& k* s* s; c    但是,我在看code时,发现在CoreDispatcher()-->CoreStartImage()里面call image之后有这么一句:  (file:image.c)
3 M9 y8 T+ c+ ?2 c6 s$ s% V  //
( U: E" H! g6 [. X  f  // Go connect any handles that were created or modified while the image executed.
5 D4 ^" }$ B/ K1 p. k$ [  //7 p  ?3 _, ?7 l* q
  CoreConnectHandlesByKey (HandleDatabaseKey);
& ^+ `2 {  `  Z/ L  v" i; y6 |+ ]
这里的HandleDatabaseKey是call image之前由CoreGetHandleDatabaseKey()得到的gHandleDatabaseKey
  z, D" F& p. b  f) b8 P而CoreConnectHandlesByKey会调用到:
: O$ O- \/ x8 o# A5 R$ Q. ~  //+ V/ r3 f# Q1 B; A5 P, e( E0 s5 T
  // Connect all handles whose Key value is greater than Key( j( Y$ P0 H/ I5 E( z  F
  //  d6 |; O: X2 O" l
  for (Index = 0; Index < Count; Index++) {
# c: I2 [; o8 E2 j2 S/ A3 B6 Q    CoreConnectController (HandleBuffer[Index], NULL, NULL, TRUE);
  w/ j4 H6 r' B- V2 r9 R  }
# ~: Z3 Y7 w9 ^- o$ n* X
所以,照code看,当在Driver中安装一个Handle和Interface到Binding Protocol后(gHandleDatabaseKey会++,IHandle的Key=gHandleDatabaseKey)
& U: z0 _0 D  ^是会去ConnectController的,也会执行对应的Support()和Start()才对!!5 ]( e/ }% Y- v2 t4 W
1 s9 B0 i7 ^) {
不知道我想的哪里有问题???欢迎大家指正.9 M/ y! ^7 g+ B

- q% _4 F! a' m* g( ~) }. \[ 本帖最后由 xtdumpling 于 2008-9-18 15:25 编辑 ]
回复

使用道具 举报

发表于 2008-9-19 14:44:41 | 显示全部楼层
这段code似乎是一个向后兼容的行为,不必太care。3 G% G& ~6 E- x. 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 | 显示全部楼层
了解了.2 n: L# G2 v* a$ A/ m; i
非常 感谢!!!
回复

使用道具 举报

发表于 2008-9-23 16:48:56 | 显示全部楼层
在读DXEmain时,6 I( i8 E9 n$ q, U% r; }% {5 y
Status = CoreInitializeImageServices(HobStart);--->CoreInstallProtocolInterface();--->CoreInstallProtocolInterfaceNotify();中,
5 w4 E1 Y: i: q//
" S6 G/ G2 `: }" l( _/ p  t6 T& O// Notify the notification list for this protocol.  |3 Z1 P* S1 U
//
; N' a2 D$ Y# t+ Pif (Notify) {
& P$ {8 \& v) L# m! _  CoreNotifyProtocolEntry(ProtEntry);
$ T1 v- m, }" \/ \}    里Signal了Event. MS是说一个handle安装了一个protocol后就signal一次.0 }8 E( z5 r1 l  k( x4 G( H" E
有个问题请教一下大家: 这段是在DXE很靠前的位置执行的,但是在它之前我没有看到DXE中有相关的CreateEvent出现?哪位高手能说说这部分代码的流程呢?
回复

使用道具 举报

发表于 2008-9-23 17:04:14 | 显示全部楼层
原帖由 xtdumpling 于 2008-9-16 13:34 发表
' O9 X5 {' ^' q( ^" G& l) F请楼上的兄弟分析下BS的RegisterProtocolNotify也就是CoreRegisterProtocolNotify是做什么用的?怎么用?+ h$ h* y% q1 k
谢谢!

) X/ U0 }" r' \6 ^8 T* g......! Q% Q& g' G' F7 w, U% l; A4 N. s) q
1 ]  K' I0 q# m+ S2 H

: b0 }8 ^* @' p+ A[ 本帖最后由 xtdumpling 于 2008-9-23 17:24 编辑 ]
回复

使用道具 举报

发表于 2008-9-24 12:43:45 | 显示全部楼层
原帖由 xtdumpling 于 2008-9-23 17:04 发表
3 D6 q4 d5 n, V4 n% n4 g8 G+ N7 \' t( s' j! i
......
* p8 Z) H( U& Z

7 K9 L9 S/ P) Q) _( ZSignal的Event是不是在各个TPL级上挂载一些待处理的事件,一旦restore(TPL)的话,比当前TPL级高的pending事件就回被处理掉?( T- ?* \; ?+ P1 n0 B5 Y! h& Q* i: p
如果是这样的话,Timer事件是如何处理的呢,没有找到相关的代码呀?Xt指点一下再~
回复

使用道具 举报

发表于 2008-9-24 19:00:46 | 显示全部楼层
Timer是挂在8259的IRQ0的中断处理程序上面的, 大概每秒18.3次调用CoreTimerTick()-->CoreCheckTimers()
) T% {# y* N' I' A1 f9 @1 Q$ kTPL=30
回复

使用道具 举报

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

本版积分规则

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

GMT+8, 2024-5-20 16:55 , Processed in 0.025402 second(s), 17 queries .

Powered by Discuz! X3.5

© 2001-2023 Discuz! Team.

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