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

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

[复制链接]
发表于 2008-7-27 00:11:28 | 显示全部楼层 |阅读模式
  最近在工作看到机台有启动过程中把SPI ROM数据清空,但苦与没有办法很好的Debug(PCA没有架起来),所有与EDK为对象好好的读了一把。! @# v7 ?9 T* w
! b' I! t: j( f) T* s
SEC/CEI:. @1 x3 K  b. N# l+ c( \9 j$ o4 E
  UEFI BIOS启动时先会执行SEC/CEI,这个阶段在实现的BIOS Code中初始化Debug Port,进入Big Mode,CPU的MicroCode,CacheToRAM的转换.然后跳转到PEI阶段。. v& Q, h$ Q( E; R$ L5 }; u( N, }: X
在EDK中这部分被成了Load FvRecovery.fd文件,这个文件类似与我们的BIOS ROM.里面是我们编译后生成的二进制代码。在这个阶段最主要的是将这个文件加载到内存中(Windows API将文件加载到内存,看API函数).
! o1 Y4 m( x# ~! s" x, {* \9 {$ `8 {% r
PEI:$ _9 S& L" ~1 U* b
   从这里开始UEFI BIOS和EDK执行基本相同,只是一个是从SPI ROM中定位一个地址(PEIM的开始地址),一个是从内存中定位一个地址(PEIM的开始地址)。从这里开始只讲EDK的执行" Y" Z. d* i3 z
  EDK调用InitializeMemoryService函数,将HobList清空,peiservice清空。
' I  G7 a1 D* u0 o2 @( k( J6 |      InitializePPIService函数,将PPI队列清空,这个队列长0x3F.+ P4 O5 X9 `6 @
          InitializeSercurityService函数,将Notify队列清空。7 @2 W1 J. O2 J/ o* k
          InitializeDispatcherData函数,将Dispatcher队列清空。1 s5 x! h) {% s5 I; x! y; |( K( q
  接着由PeiBuildHobGuid来建立一个HOB(S3返回时这时应该有这个HOB,不用建立,直接使用了,这样就会进入另外一个流程,可以这个EDK不能调试S3,不知道怎么走)。然后由(*PeiServices)->InstallPpi()将这个新HOB加入到PPI中。8 c/ K' N" {+ r1 ^# k
    由于在SEC阶段转了以下这几具PPI,所以在执行PEI的Dispatcher之前会先安装东西:
6 \) X; _; Q6 v6 e/ j' b      EFI_PEI_PPI_DESCRIPTOR    gPrivateDispatchTable[] = {! W5 V( R% [, U
       {EFI_PEI_PPI_DESCRIPTOR_PPI, &gEfiNtLoadAsDllPpiGuid, &mSecNtLoadAsDllPpi},
+ O9 j: k7 [% n. ^( K       {EFI_PEI_PPI_DESCRIPTOR_PPI, &gNtPeiLoadFileGuid, &mSecNtLoadFilePpi},
1 P+ }$ }" w+ Y% v# E: e$ f       {EFI_PEI_PPI_DESCRIPTOR_PPI, &gPeiNtAutoScanPpiGuid, &mSecNtAutoScanPpi},2 [7 J5 S2 l! C
       {EFI_PEI_PPI_DESCRIPTOR_PPI, &gPeiNtThunkPpiGuid, &mSecWinNtThunkPpi},
% [4 \3 g# ]8 s$ q       {EFI_PEI_PPI_DESCRIPTOR_PPI, &gPeiStatusCodePpiGuid, &mSecStatusCodePpi},; f/ V+ V/ n4 M5 Y" S
       {EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST, &gNtFwhPpiGuid, &mSecFwhInformationPpi}
1 C9 x/ c4 ^# M, c5 e" T     };
8 x  v4 l- E: M! z3 ~    每个PPI是由{类型,GUID(名字,以后就根据这个来找到它的),Function_Entry_Address}组成。3 Q: {" d( _' G/ y) F! M2 d
   这些PPI会在PEIDispatcher中用到。5 P: p2 u" M3 {9 k1 z
   安装完这此东西这开始执行PEIDispatcher函数,函数从BIOS ROM文件中找出PEI的Image(怎么找到,请读一下FV_HEAD(EFI_HEAD),里面讲到了如何区分Image类型),然后定位到PEI Image的入口地址,执行他。在我们的的PEI中,我们一般会申明一个PPI,这个就是这个PEI提供一些服务,PEIDispatcher会将他们加入到PPI-List中,以后其他Image也可以调用他的提供的功能。
8 p" G$ W! J: z- ^1 u, w" q   最后EDK会加载一个叫DXEIPL的PEI,DXEIPL提供一个PPI服务,这个PPI的功能是实现从PEI到DXE的切换,这个PPI里面为DXE做了很多的预准备,加载了很多PPI,如对BIOS的解压方法等。
8 E9 |! I: G0 x$ M! b   SwitchStacks (4 [0 \: Q: S) Z6 {4 |$ K
       (VOID *) (UINTN) DxeCoreEntryPoint,9 ]7 \7 n/ w# r% y; b) z9 H' C6 Q
       (UINTN) (HobList.Raw),7 \8 d$ E' X6 C) i+ a9 g' h. x
       (VOID *) (UINTN) TopOfStack,: D+ F9 ~% Z3 y) T$ M) Z
       (VOID *) (UINTN) BspStore( s9 E; t: g& s& u$ Q
    );
$ l7 e/ @' c: n& |  用过汇编的人对这个技术一定很熟悉,不多说了(我别不清,咯。。。)6 H. p1 X3 N$ d- g5 b6 _) k
) K! A" p* q) D+ ~% f( g3 f
DXE:" S% R1 u7 s9 z( s# V1 G& j& ?  L
     从PEI到DXE切换时转过来一个HOBLIST参数,DXE会在这个HOB中找到Memory的使用情况,然后根据这些情况将BIOS引到内存(这是EFI的做法)。在EDK在DXE时重新定位一下内存。
7 P6 `; }1 G+ H接着就会定义我们经常使用到的gST表,gRT表。接着是申明一些Protocol(先不关心这些事)。
: N+ Y3 R$ ~" g5 a   等这些该加的PPI,Protocol加完了,CoreDispatcher()就出场了。他会的功能类似PEIDispatcher()。从我们BIOS ROM中将DXE的驱动读出,执行执行他们,这时会执行到Driver( @' Z2 c9 t. R4 _
中的Support(),Start()两个功能函数。在这两个函数中你可以注册自己的PPI,为其他驱动提供服务。- }: A2 K$ |9 t
   到些BIOS的引导其他完成。接着该进OS了,看Linux 0.11吧,操作系统是怎么做事情的。0 O3 @& Q+ E3 Q
   
. B' o. {- L& \" F% oDriver:
1 @: t8 |) {( Y9 G6 |+ z    我们的驱动什么为在PEI和DXE等不同阶段执行呢?
6 {) Q. N0 G: C, m$ e8 F  大家请看一下我们的驱动的makefile.(EDK中的*.inf). [" {+ V! s! x5 m0 z
  [defines]
* j; X, k1 d9 U# d( K  v8 \( t  BASE_NAME            = OWEN
3 [& k( s* u) {& Z8 V  FILE_GUID            = 1EDD13C1-62EF-4262-A1AA-0040D0830110- O* z) }! Y4 P( C! m6 X
  COMPONENT_TYPE       = BS_DRIVER
" P- l( z# X. {4 [& s- M, d% y+ q$ w4 @7 J
  BASE_NAME告诉编译器最终生成的驱动的名字。1 z0 M+ d- p; p) @7 }# K& n
  FILE_GUID就是这个驱动的GUID名字,在BIOS中引用某个驱动就是根据它来调用和识别。4 V5 ?. Y. [4 z! I# m1 j1 T! ]
  COMONENT_TYPE会告诉编译器生成驱动的类型,是PEI,DXE,等。
& o2 N' K% b0 N$ |% e, c  在EDK中有一个FWVolume.c实现的功能就是帮我们把这个TYPE转换面相应的扩展名
2 _/ a3 \9 h5 o6 {* }4 D  COMP_TYPE_EXTENSION  mCompTypeExtension[] = {
% X& K2 H/ v% T' w) |  {"bs_driver",  ".dxe" },
' _) O, l5 S! ^7 i- [+ b  {"rt_driver",  ".dxe" },' P. f* Q3 m( ~3 }
  {"sal_rt_driver", ".dxe"},
' V- {- a4 s4 Y  {"security_core", ".sec"},$ B4 f1 E1 ?$ [9 _
  {"pei_core", ".pei"},
3 Y- L' o: O, W8 E- b$ `+ C6 n  {"pic_peim", ".pei"},
2 r  x$ |7 I, Z; R0 o  {"pe32_peim", ".pei"},0 @8 g* G: L9 s
  {"relocatable_peim", ".pei"},. I8 ?* N0 ]9 H+ x3 v
  {"binary", ".ffs"},
& V  e' Y/ }7 u& T2 x' U  {"application", ".app"},) b2 {0 F  P- i9 l8 t, i  I+ @
  {"file", ".ffs"},4 P* [, X+ X6 u
  {"fvimagefile", ".fvi"},+ ~: M* ~( ~) J8 x4 C8 l- p  R- u3 ~
  {"rawfile", ".raw"},- D- @5 N/ x. X
  {"apriori", ".ffs"},
7 {8 X8 M$ Q# v. a3 K  {"combined_peim_driver", ".pei"},
/ `! I  ]( `3 A. D% J# [1 p  { NULL,  NULL }" V/ I( z; G( X, A* o
};' @6 y1 F2 n4 O  L" W
$ k/ S! P1 i7 G4 ]4 m
了解了这些,接下我们可以看驱动篇了。(Go On Study... Forever)
- L" v" {% P% Y* `6 X6 H   ! b4 b* Q8 A: q9 D  @
         
* v8 @7 v2 [) r: B- g  
发表于 2008-7-27 12:30:15 | 显示全部楼层
不错!
: z$ W. V, V% W% o4 a9 L8 j) `支持
% j/ d8 j+ k/ F- p  }+ U  {& h继续
9 q$ \0 v! n9 U4 I4 ~) _) ^加油
3 I& x' ]9 L$ q& }9 L% }1 k
回复

使用道具 举报

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

回复 1# 的帖子

gPrivateDispatchTable 和COMP_TYPE_EXTENSION  没有搜到啊  是EDK专有的么?% I* u% k; j& {4 p
有看过跟gPrivateDispatchTable 类似的,但是里面的PPI不同。! i- g3 }, s1 f1 _; G5 Q, _. S
还有这个COMP_TYPE_EXTENSION  没有找到过。FWVolume.c这个文件也没有发现。。
回复

使用道具 举报

发表于 2008-7-28 13:24:20 | 显示全部楼层
这东西虽说没有什么技术含量,但是总结一下还是非常好的。
( u3 ~. N$ u! K2 R! }% Q9 u, B
支持!
回复

使用道具 举报

 楼主| 发表于 2008-7-28 18:52:31 | 显示全部楼层
* G' e1 y- P1 Y' ^, i5 ^, {" Z2 r
小弟还在学习阶段,目前的目标是知道执行的流程。" O  \6 B; B% `7 e
这里面有很多细节没有写,能力有限,只能自己知道,不能表达。$ p: |: q8 d6 k9 K. ]) ]
嘿。。。。
. s" K- O5 p9 e; A6 k% ?. c' ^所有大侠们如果有好东西能给小弟共享一份。. F& J7 [# Z% s- U8 [# I1 l6 I
8 k% u: m9 r; [/ ~8 ]1 d
谢谢!
回复

使用道具 举报

发表于 2008-8-12 14:44:11 | 显示全部楼层
原帖由 winbondowen 于 2008-7-27 00:11 发表 , D  m9 C: m) ~3 T% d/ {
  ROM中將DXE的驅動讀出,執行執行他們,這時會執行到Driver! B+ y% D  _4 }' S" G! g
中的Support(),Start()兩個功能函數。在這兩個函數中你可以註冊自己的PPI ...

2 _( ]! h% z) x8 H$ k
; C5 M. |: o) A* VPPIs are registered during PEI phase, but Support()/Start() are invoked in DXE driver binding protocol, 2 p; ]  w5 _# P* `' w/ ~+ F
For more precisely, I think the "PPI" you mentioned is the "PROTOCOL" rather than "PPI".. o6 X5 P" U- i5 R

% X, o4 A9 Z9 {[ 本帖最后由 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:! A, y2 |& i- A
   Yes. I make a mistake.
8 W: V) M0 C3 Y7 W; C      PPI:     A PEIM to PEIM interface.
4 U, D  u* z) t$ e1 o      PROTOCL: A Interface between Hardware(or firmware) and software.0 v7 Q% N/ k0 ^+ c9 \3 {0 Z
      reference[http://www.biosren.com/viewthread.php?tid=207]* f9 i! e0 S: e3 O# l
   so, PPI execute at PEI step and Initialize hardware. PROTOCOL execute by DXE step.1 ~6 i3 f- l' u* h( R: a
   Thanks.
回复

使用道具 举报

发表于 2008-8-20 17:47:21 | 显示全部楼层
原帖由 winbondowen 于 2008-7-27 00:11 发表 DXE:  T4 W$ S6 Y2 h& b& ?; @
     從PEI到DXE切換時轉過來一個HOBLIST參數,DXE會在這個HOB中找到Memory的使用情況,然後根據這些情況將BIOS引到內存(這是EFI的做法)。在EDK在DXE時重新定位一下內存。
  P! F, T: B: m2 ]接著就會定義我們經常使用到的gST表,gRT表。接著是申明一些Protocol(先不關心這些事)。" H2 h$ `$ W2 i1 j
   等這些該加的PPI,Protocol加完了,CoreDispatcher()就出場了。他會的功能類似PEIDispatcher()。從我們BIOS ROM中將DXE的驅動讀出,執行執行他們,這時會執行到Driver7 k# ^' X/ W8 ?2 O' M& D
中的Support(),Start()兩個功能函數。在這兩個函數中你可以註冊自己的PPI,為其他驅動提供服務。) u2 K+ E' w( J0 w
   到些BIOS的引導其他完成。接著該進OS了,看Linux 0.11吧,操作系統是怎麼做事情的。.
3 G0 v9 I4 r4 j& ?8 e9 J$ R) n3 q

! E. R' f# N$ C2 @: Q/ M1 dThere are mistakes,5 ?0 P6 I& K& B; V- b
1.gST and gRT are init after the DXE architectural protocols have been loaded, those protocols response for creating Dxe foundation.
3 y- i' u! P+ J6 V. }" d8 [( X+ c% O7 f; b) [( }; U
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.  y2 c( R9 j! o, c3 f) x
The CoreDispatcher() executes all trusted Dxe drivers and just register the Binding protocol if the driver is EFI1.1 driver model.
( t7 w( s' x0 c, g  {6 \Furthermore, Support()/Start() are invoked in BDS phase over the CoreConnectController() rather than CoreDispatcher().0 T/ @; ]2 m* X* j  S( p% L7 e, n+ k

& [+ i1 g5 L: p7 S$ l  tBTW, 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 大侠的指点。- E$ L+ {# w$ ^# ?
回复

使用道具 举报

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

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

原帖由 ichirohiro 于 2008-8-20 17:47 发表
3 F9 B( ]' h' W$ _: D0 Q.../ O4 b* t1 J+ ?+ ^. S+ ]7 i
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.5 d* u9 R% t% g3 u
The CoreDispatcher() executes all trusted Dxe drivers and just register the Binding protocol if the driver is EFI1.1 driver model.
. `1 r0 w) P, Y; J# uFurthermore, Support()/Start() are invoked in BDS phase over the CoreConnectController() rather than CoreDispatcher().
5 o6 @' a" Q) E6 o8 p4 f) \
    在Framework的spec DxeCis.pdf里面也是这么说的,DXE CoreDispatcher()里面,对于EFI1.1 driver model的driver只会安装Handler和Interface到Binding protocol,到BDS才会去执行Support()和Start().' N) l1 L  P5 w
    但是,我在看code时,发现在CoreDispatcher()-->CoreStartImage()里面call image之后有这么一句:  (file:image.c)
" _' S% ^+ j& ]  //
2 l3 Y5 X  t' [. A. l4 D  @  // Go connect any handles that were created or modified while the image executed.
/ v  e+ \  R% O  ]! Q  B  //
( [! R. D" p. m1 U5 e* B  CoreConnectHandlesByKey (HandleDatabaseKey);

& N9 X3 J% ~. L7 b( G! R* Z7 i3 X这里的HandleDatabaseKey是call image之前由CoreGetHandleDatabaseKey()得到的gHandleDatabaseKey
8 Q, C  E/ J% K* P而CoreConnectHandlesByKey会调用到:5 P* ]8 E3 R' P; X" h
  //
- K2 ~/ |, t, z7 Y, y  // Connect all handles whose Key value is greater than Key
5 m1 T( C+ T, h- d8 V  //
# i) O4 e( e7 O: e' i5 p0 u; f  for (Index = 0; Index < Count; Index++) {
. ^; t; R" K/ {3 K    CoreConnectController (HandleBuffer[Index], NULL, NULL, TRUE);6 A$ ?5 _5 I3 }$ h* D
  }

% [) F# }2 n, h' Y. P; O. E2 `所以,照code看,当在Driver中安装一个Handle和Interface到Binding Protocol后(gHandleDatabaseKey会++,IHandle的Key=gHandleDatabaseKey)
, \) \, B3 j' H4 I+ T: Q是会去ConnectController的,也会执行对应的Support()和Start()才对!!' K& y, ]% ^( Q0 M

. c6 h* T! L* O. V, X5 s: y0 X不知道我想的哪里有问题???欢迎大家指正.* s1 A  I. ]3 _- Y# g5 v
8 U/ [* l0 z5 ~  K" H
[ 本帖最后由 xtdumpling 于 2008-9-18 15:25 编辑 ]
回复

使用道具 举报

发表于 2008-9-19 14:44:41 | 显示全部楼层
这段code似乎是一个向后兼容的行为,不必太care。
# O- ?) g+ p5 ?2 u/ 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 | 显示全部楼层
了解了.( b2 U# M) R$ R. a  e
非常 感谢!!!
回复

使用道具 举报

发表于 2008-9-23 16:48:56 | 显示全部楼层
在读DXEmain时,
2 `  ~9 l$ @  Q. qStatus = CoreInitializeImageServices(HobStart);--->CoreInstallProtocolInterface();--->CoreInstallProtocolInterfaceNotify();中,3 s8 _: k% p1 d& @! U* u
//
7 F$ S$ E- B; W* @! G! r; h/ B// Notify the notification list for this protocol./ w3 p+ \9 i2 z0 U' F+ L8 F
//* s/ {& i" T7 L8 d% E) @% q9 x
if (Notify) {" T: X1 E; c0 y! G) x+ T7 `7 Z
  CoreNotifyProtocolEntry(ProtEntry);
* N* b6 @6 Q' ?$ _# w, v6 }( Q}    里Signal了Event. MS是说一个handle安装了一个protocol后就signal一次.$ f: r. i2 m2 Y3 h# x& o" R
有个问题请教一下大家: 这段是在DXE很靠前的位置执行的,但是在它之前我没有看到DXE中有相关的CreateEvent出现?哪位高手能说说这部分代码的流程呢?
回复

使用道具 举报

发表于 2008-9-23 17:04:14 | 显示全部楼层
原帖由 xtdumpling 于 2008-9-16 13:34 发表
- R. E! S7 g  u2 H/ X, ^( [请楼上的兄弟分析下BS的RegisterProtocolNotify也就是CoreRegisterProtocolNotify是做什么用的?怎么用?
" n/ b6 h9 R# ^! x. {7 b5 J' G+ p谢谢!

1 j4 G% b. _$ }: {7 m- X4 d......- e/ x; I- y  k, c  n" Y; I( n0 q

5 x' y2 [9 V) z/ Q& X/ A9 K
/ m. t+ ~7 ?7 V( ?. f[ 本帖最后由 xtdumpling 于 2008-9-23 17:24 编辑 ]
回复

使用道具 举报

发表于 2008-9-24 12:43:45 | 显示全部楼层
原帖由 xtdumpling 于 2008-9-23 17:04 发表
8 C! P. C* `9 E' d/ I
5 J$ Y  j6 Z9 a; U9 R......
1 N0 k5 J0 l& e+ L  ?' _. D

0 s- F; |. M, q5 g0 vSignal的Event是不是在各个TPL级上挂载一些待处理的事件,一旦restore(TPL)的话,比当前TPL级高的pending事件就回被处理掉?
7 C0 t9 m! i' N+ a; A如果是这样的话,Timer事件是如何处理的呢,没有找到相关的代码呀?Xt指点一下再~
回复

使用道具 举报

发表于 2008-9-24 19:00:46 | 显示全部楼层
Timer是挂在8259的IRQ0的中断处理程序上面的, 大概每秒18.3次调用CoreTimerTick()-->CoreCheckTimers()$ z* H9 T% E$ a$ i/ @
TPL=30
回复

使用道具 举报

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

本版积分规则

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

GMT+8, 2026-6-29 04:20 , Processed in 1.009640 second(s), 16 queries .

Powered by Discuz! X3.5

© 2001-2025 Discuz! Team.

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