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

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

[复制链接]
发表于 2008-7-27 00:11:28 | 显示全部楼层 |阅读模式
  最近在工作看到机台有启动过程中把SPI ROM数据清空,但苦与没有办法很好的Debug(PCA没有架起来),所有与EDK为对象好好的读了一把。
/ K5 M" s; w1 }! w  H( Z3 V/ u8 X
% x8 l' F/ G, i/ kSEC/CEI:* k8 Q% h' D# ^( x8 F
  UEFI BIOS启动时先会执行SEC/CEI,这个阶段在实现的BIOS Code中初始化Debug Port,进入Big Mode,CPU的MicroCode,CacheToRAM的转换.然后跳转到PEI阶段。, A2 e2 {. c' \" w$ i
在EDK中这部分被成了Load FvRecovery.fd文件,这个文件类似与我们的BIOS ROM.里面是我们编译后生成的二进制代码。在这个阶段最主要的是将这个文件加载到内存中(Windows API将文件加载到内存,看API函数).
# p3 r# k  l' ~7 a. ~/ Y5 n2 G7 Q  r) t- F; _0 p
PEI:" Z2 U6 x* T4 h0 a+ j$ c
   从这里开始UEFI BIOS和EDK执行基本相同,只是一个是从SPI ROM中定位一个地址(PEIM的开始地址),一个是从内存中定位一个地址(PEIM的开始地址)。从这里开始只讲EDK的执行
; X) W/ @+ P  ~! z  EDK调用InitializeMemoryService函数,将HobList清空,peiservice清空。) P3 N" J- x- p# L( P- z* ?
      InitializePPIService函数,将PPI队列清空,这个队列长0x3F.
" w2 E0 r) ?  v9 t* |3 q. ~  s; V          InitializeSercurityService函数,将Notify队列清空。
. ?% Y- C( y2 T6 W          InitializeDispatcherData函数,将Dispatcher队列清空。
$ X! x4 M# W- s# C8 @9 I; \  接着由PeiBuildHobGuid来建立一个HOB(S3返回时这时应该有这个HOB,不用建立,直接使用了,这样就会进入另外一个流程,可以这个EDK不能调试S3,不知道怎么走)。然后由(*PeiServices)->InstallPpi()将这个新HOB加入到PPI中。
4 i) Z0 U  Z' C: P0 d' \! ^' c; i    由于在SEC阶段转了以下这几具PPI,所以在执行PEI的Dispatcher之前会先安装东西:4 g5 L; U: l: R! L9 C
      EFI_PEI_PPI_DESCRIPTOR    gPrivateDispatchTable[] = {
% R- \5 Y: O( w6 Y       {EFI_PEI_PPI_DESCRIPTOR_PPI, &gEfiNtLoadAsDllPpiGuid, &mSecNtLoadAsDllPpi},
, a" B, j2 J* U3 X5 \0 O: ~9 g       {EFI_PEI_PPI_DESCRIPTOR_PPI, &gNtPeiLoadFileGuid, &mSecNtLoadFilePpi},
! z0 U' u% n- \' y; w       {EFI_PEI_PPI_DESCRIPTOR_PPI, &gPeiNtAutoScanPpiGuid, &mSecNtAutoScanPpi},
7 @. P& T& L; f! |  h7 F8 Q7 ^5 ?       {EFI_PEI_PPI_DESCRIPTOR_PPI, &gPeiNtThunkPpiGuid, &mSecWinNtThunkPpi},
; m+ J* L) L; P+ z0 x       {EFI_PEI_PPI_DESCRIPTOR_PPI, &gPeiStatusCodePpiGuid, &mSecStatusCodePpi},
' L  t# n* F3 `, T# I       {EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST, &gNtFwhPpiGuid, &mSecFwhInformationPpi}
% w9 X& I9 {  y, r     };
; R. @3 T8 n6 }: y    每个PPI是由{类型,GUID(名字,以后就根据这个来找到它的),Function_Entry_Address}组成。
. Q1 u( e  U& O5 t- X- d* v+ U& _7 P   这些PPI会在PEIDispatcher中用到。
$ o4 [1 s4 h- D1 J' q( g9 O   安装完这此东西这开始执行PEIDispatcher函数,函数从BIOS ROM文件中找出PEI的Image(怎么找到,请读一下FV_HEAD(EFI_HEAD),里面讲到了如何区分Image类型),然后定位到PEI Image的入口地址,执行他。在我们的的PEI中,我们一般会申明一个PPI,这个就是这个PEI提供一些服务,PEIDispatcher会将他们加入到PPI-List中,以后其他Image也可以调用他的提供的功能。3 G6 _$ D  P7 v( z- Q0 I
   最后EDK会加载一个叫DXEIPL的PEI,DXEIPL提供一个PPI服务,这个PPI的功能是实现从PEI到DXE的切换,这个PPI里面为DXE做了很多的预准备,加载了很多PPI,如对BIOS的解压方法等。" f* l! X$ ?+ v7 J
   SwitchStacks (
7 K0 X7 h% N1 P4 `# F! E       (VOID *) (UINTN) DxeCoreEntryPoint,
# W2 P- e" d, @% P0 q       (UINTN) (HobList.Raw),- U( _  ^- Y* o
       (VOID *) (UINTN) TopOfStack,
! T3 d$ u8 W0 w2 m1 u4 C  k, K       (VOID *) (UINTN) BspStore
5 Z- Y2 `, _1 J8 x; @5 V    );
, a0 S1 Y, }8 Q' {6 H8 n$ b  用过汇编的人对这个技术一定很熟悉,不多说了(我别不清,咯。。。)
' d0 z0 {$ \9 ?, T! T  C3 A$ N7 g
8 N7 O, a( r. j$ f* jDXE:9 n* ^) }/ @" i# b2 W( `& J' `7 i
     从PEI到DXE切换时转过来一个HOBLIST参数,DXE会在这个HOB中找到Memory的使用情况,然后根据这些情况将BIOS引到内存(这是EFI的做法)。在EDK在DXE时重新定位一下内存。' Z) h5 z& A% F) Q
接着就会定义我们经常使用到的gST表,gRT表。接着是申明一些Protocol(先不关心这些事)。3 y8 K# v( H5 z0 r6 r
   等这些该加的PPI,Protocol加完了,CoreDispatcher()就出场了。他会的功能类似PEIDispatcher()。从我们BIOS ROM中将DXE的驱动读出,执行执行他们,这时会执行到Driver3 \! b' t8 F, ~- E5 h; {$ {
中的Support(),Start()两个功能函数。在这两个函数中你可以注册自己的PPI,为其他驱动提供服务。
9 Y6 Y4 B2 x, K8 w, G8 Z   到些BIOS的引导其他完成。接着该进OS了,看Linux 0.11吧,操作系统是怎么做事情的。: O+ {8 V# M# x! h
   
* ~( c8 [, V; z- E8 M+ H. V* lDriver:$ A0 r: P5 J' s5 L1 ?9 ~* ^0 n
    我们的驱动什么为在PEI和DXE等不同阶段执行呢?3 s! M6 R! X5 z1 @0 a# W
  大家请看一下我们的驱动的makefile.(EDK中的*.inf)
( M; d5 A: K& X# z  [defines]
6 q) t- @0 H. z  |  BASE_NAME            = OWEN7 T1 ?( C' x% s7 F/ \; Y
  FILE_GUID            = 1EDD13C1-62EF-4262-A1AA-0040D0830110
; h3 s, ], \: }# T( W% A* T3 R; _/ }  COMPONENT_TYPE       = BS_DRIVER
7 O# u) |3 \7 \6 X4 X
0 _' @, i  q, F. j2 l+ ?& C# j  BASE_NAME告诉编译器最终生成的驱动的名字。
1 Y, {, g/ \' |8 k  FILE_GUID就是这个驱动的GUID名字,在BIOS中引用某个驱动就是根据它来调用和识别。
- w; E  G$ o! L, `  L3 X+ n  COMONENT_TYPE会告诉编译器生成驱动的类型,是PEI,DXE,等。
  h3 T; P) l! Q1 N, r) p. Z) q7 ~# r  在EDK中有一个FWVolume.c实现的功能就是帮我们把这个TYPE转换面相应的扩展名
* c( J% I( Y" l# b- Y- Y$ i5 |  COMP_TYPE_EXTENSION  mCompTypeExtension[] = {( K% r/ Z7 |) O; X; T' @( i
  {"bs_driver",  ".dxe" },6 U/ _+ X1 Y7 V  W# ^; o( I
  {"rt_driver",  ".dxe" },
) x: l/ V$ [4 e) a  {"sal_rt_driver", ".dxe"},  G: g$ p3 o% Q0 h, \% j4 ?. o( s
  {"security_core", ".sec"},( w! J8 ?% i5 i7 A4 o& f
  {"pei_core", ".pei"},* L9 P$ s7 ]" c( z( ?/ V6 _6 F
  {"pic_peim", ".pei"},% h3 S5 H0 p6 @4 S% B5 \5 t- V
  {"pe32_peim", ".pei"},
2 G2 s/ |; V, d  {"relocatable_peim", ".pei"},
4 u4 _6 E* H. K, t$ B4 S! B% T  {"binary", ".ffs"},7 w; ~: d2 i( ~
  {"application", ".app"},5 p- y. h" m, J; U+ I/ f
  {"file", ".ffs"},# s' ~! t) K* \/ X0 M" x
  {"fvimagefile", ".fvi"},' Y- Y/ Q! \# y
  {"rawfile", ".raw"},! @% t. ?! i% b! o' u! u) B& K
  {"apriori", ".ffs"},
& z& s) {- k1 b* e# b% W! v; j  {"combined_peim_driver", ".pei"},
' l# |2 o' B1 Q& b' l  { NULL,  NULL }
: ^/ V3 N3 ~8 o9 D};
, Z% l$ o& G$ D, b8 \+ ^% C( _- d3 z9 i2 C
了解了这些,接下我们可以看驱动篇了。(Go On Study... Forever)' K) K$ y: j* C) D; L$ z
   6 j" w! r3 t3 \
         
' V4 R3 P: q) w9 b4 B% ^6 s  
发表于 2008-7-27 12:30:15 | 显示全部楼层
不错!
( U1 ]4 R  W* K/ K/ i# G支持
9 S1 Z+ K  |. ^0 L+ M+ h4 `+ t" ?继续
  Y6 E9 }; ]9 d, Z  E加油! O/ f/ }$ h: G* b" H: y
回复

使用道具 举报

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

回复 1# 的帖子

gPrivateDispatchTable 和COMP_TYPE_EXTENSION  没有搜到啊  是EDK专有的么?
9 l- N' B; e$ R. k4 y4 o' h有看过跟gPrivateDispatchTable 类似的,但是里面的PPI不同。
# R' J8 `0 t* E1 c6 x还有这个COMP_TYPE_EXTENSION  没有找到过。FWVolume.c这个文件也没有发现。。
回复

使用道具 举报

发表于 2008-7-28 13:24:20 | 显示全部楼层
这东西虽说没有什么技术含量,但是总结一下还是非常好的。
8 R9 W4 c$ R# n, p: {6 L" x( [! O  P& T/ Q
支持!
回复

使用道具 举报

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

( m/ t9 X% O: n  s3 M小弟还在学习阶段,目前的目标是知道执行的流程。4 E$ O/ J3 a* ^! O
这里面有很多细节没有写,能力有限,只能自己知道,不能表达。( _% u( G( O7 h5 g
嘿。。。。/ n* @  n6 x- U5 c
所有大侠们如果有好东西能给小弟共享一份。; ^. }) S9 }" t# n9 S3 E+ Q; f
7 g8 i" Q" m: `' B5 y* b- h
谢谢!
回复

使用道具 举报

发表于 2008-8-12 14:44:11 | 显示全部楼层
原帖由 winbondowen 于 2008-7-27 00:11 发表
& G) ?9 Z( r' E, J. C" N' o  ROM中將DXE的驅動讀出,執行執行他們,這時會執行到Driver: l! Y& j; v9 d% Q; [& I
中的Support(),Start()兩個功能函數。在這兩個函數中你可以註冊自己的PPI ...

' `/ c6 `2 r8 M* z5 ?6 \' Q% f4 M; _2 _4 |; z8 y( F: W
PPIs are registered during PEI phase, but Support()/Start() are invoked in DXE driver binding protocol,
& m) K% |7 l0 _* j0 [. h9 ~% |For more precisely, I think the "PPI" you mentioned is the "PROTOCOL" rather than "PPI".# C" ]) {; z  w- n; b( `7 E
- a; }8 P! {6 N; \% i) Y8 {' ]" N' L4 W
[ 本帖最后由 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:5 {1 ~- W9 @1 |: k; E
   Yes. I make a mistake.8 W9 O1 ^: z/ W6 m5 y/ b, N& {
      PPI:     A PEIM to PEIM interface.! [# g' h3 _' ~
      PROTOCL: A Interface between Hardware(or firmware) and software.
7 Q% A& Z1 x, |+ `/ B+ d      reference[http://www.biosren.com/viewthread.php?tid=207]- b/ r, Q/ B) u6 F" W9 _9 e
   so, PPI execute at PEI step and Initialize hardware. PROTOCOL execute by DXE step.3 S0 t, }: W0 b  M  I' `( Q
   Thanks.
回复

使用道具 举报

发表于 2008-8-20 17:47:21 | 显示全部楼层
原帖由 winbondowen 于 2008-7-27 00:11 发表 DXE:
* ~- C) J0 R6 y2 N     從PEI到DXE切換時轉過來一個HOBLIST參數,DXE會在這個HOB中找到Memory的使用情況,然後根據這些情況將BIOS引到內存(這是EFI的做法)。在EDK在DXE時重新定位一下內存。
  l$ w4 \9 z4 ^* x接著就會定義我們經常使用到的gST表,gRT表。接著是申明一些Protocol(先不關心這些事)。8 w% X4 q+ g& M
   等這些該加的PPI,Protocol加完了,CoreDispatcher()就出場了。他會的功能類似PEIDispatcher()。從我們BIOS ROM中將DXE的驅動讀出,執行執行他們,這時會執行到Driver
& j' _2 \+ [- \: z中的Support(),Start()兩個功能函數。在這兩個函數中你可以註冊自己的PPI,為其他驅動提供服務。
9 ]: f, [# X  \  d9 m5 R2 G7 S   到些BIOS的引導其他完成。接著該進OS了,看Linux 0.11吧,操作系統是怎麼做事情的。.
- M+ J+ K) D4 M1 ]
. x* G+ |8 C7 u
There are mistakes,6 e, [8 |2 c% x0 `9 ]
1.gST and gRT are init after the DXE architectural protocols have been loaded, those protocols response for creating Dxe foundation.% `' `4 c4 G- Q/ z2 z  @2 |

3 _2 e. P' t# @. C0 u$ O9 e4 j2.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.
7 \2 p4 a7 Q- z: ZThe CoreDispatcher() executes all trusted Dxe drivers and just register the Binding protocol if the driver is EFI1.1 driver model.3 V* q# @$ b/ C% L# r" H
Furthermore, Support()/Start() are invoked in BDS phase over the CoreConnectController() rather than CoreDispatcher().
6 y  m/ Y9 S( Y" r) j7 l! M; D8 k' o1 u1 V: O; ~
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 大侠的指点。' _+ Y8 r& H% g
回复

使用道具 举报

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

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

原帖由 ichirohiro 于 2008-8-20 17:47 发表 + p, H/ K5 l/ x
...
# G. ?2 ^' C4 y% u9 ?9 U) |/ Y2.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.  d9 U" m0 y4 L/ R
The CoreDispatcher() executes all trusted Dxe drivers and just register the Binding protocol if the driver is EFI1.1 driver model.
" H% Z% F9 k9 ?  R* [# s% ~1 K6 ^$ xFurthermore, Support()/Start() are invoked in BDS phase over the CoreConnectController() rather than CoreDispatcher().

9 p3 W: b2 P0 e& b/ H    在Framework的spec DxeCis.pdf里面也是这么说的,DXE CoreDispatcher()里面,对于EFI1.1 driver model的driver只会安装Handler和Interface到Binding protocol,到BDS才会去执行Support()和Start().3 k+ q4 o* L( O, u# b/ ]) p
    但是,我在看code时,发现在CoreDispatcher()-->CoreStartImage()里面call image之后有这么一句:  (file:image.c)% _( H- B) @+ ^
  //! P& }) m6 N, l. F$ J
  // Go connect any handles that were created or modified while the image executed.7 [+ A) F. J$ Z. R
  //
; z3 ~9 J3 ^( p5 K& q4 K  CoreConnectHandlesByKey (HandleDatabaseKey);
) p+ ?" }8 y0 ^4 V+ L9 p0 C
这里的HandleDatabaseKey是call image之前由CoreGetHandleDatabaseKey()得到的gHandleDatabaseKey3 Z2 c: [; ?) K2 V# K
而CoreConnectHandlesByKey会调用到:) Z1 ?* q% s8 d- u6 n# f9 a5 v
  //- F8 e$ b1 O5 R4 L6 x! s6 E& _
  // Connect all handles whose Key value is greater than Key
* E+ ^6 O2 o. G) Y- [1 _  //( l5 q+ W2 |$ ~0 U6 R/ {
  for (Index = 0; Index < Count; Index++) {
7 D7 L* w: b6 V0 x    CoreConnectController (HandleBuffer[Index], NULL, NULL, TRUE);* c$ M/ E, Z& V+ ~9 U* Y7 a# J4 t/ p
  }
% a. p1 i" D7 `4 Q' Y7 R4 S
所以,照code看,当在Driver中安装一个Handle和Interface到Binding Protocol后(gHandleDatabaseKey会++,IHandle的Key=gHandleDatabaseKey)
3 ?# x8 _" t/ g: w' v是会去ConnectController的,也会执行对应的Support()和Start()才对!!
  K0 ^$ Y* q* f$ M3 p2 F+ N4 g) Y8 W6 Y1 g; [8 o! D
不知道我想的哪里有问题???欢迎大家指正.
: Y$ E, G$ ?: ?0 b+ }3 k  y- j/ i) O9 I/ X- P
[ 本帖最后由 xtdumpling 于 2008-9-18 15:25 编辑 ]
回复

使用道具 举报

发表于 2008-9-19 14:44:41 | 显示全部楼层
这段code似乎是一个向后兼容的行为,不必太care。5 j9 _' |9 w- d. S8 U5 N% X
一个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 | 显示全部楼层
了解了.) _( \1 s/ J+ m4 t
非常 感谢!!!
回复

使用道具 举报

发表于 2008-9-23 16:48:56 | 显示全部楼层
在读DXEmain时,' X6 @0 A6 n9 k
Status = CoreInitializeImageServices(HobStart);--->CoreInstallProtocolInterface();--->CoreInstallProtocolInterfaceNotify();中,* j% u" B  Q8 W8 C" J  c8 T
/// L1 b9 ?* y3 I/ i$ X, L; O
// Notify the notification list for this protocol.
' f% I6 T- U# L1 Q8 V& x4 Z//
2 F, |  _& y5 [% _# kif (Notify) {
2 L4 U1 l4 f% A6 h7 u1 w5 x  CoreNotifyProtocolEntry(ProtEntry);
  j/ E1 j7 V# ]+ p}    里Signal了Event. MS是说一个handle安装了一个protocol后就signal一次.) b$ I0 b  z: C# ~
有个问题请教一下大家: 这段是在DXE很靠前的位置执行的,但是在它之前我没有看到DXE中有相关的CreateEvent出现?哪位高手能说说这部分代码的流程呢?
回复

使用道具 举报

发表于 2008-9-23 17:04:14 | 显示全部楼层
原帖由 xtdumpling 于 2008-9-16 13:34 发表
8 O2 A3 J4 g* v9 _2 t7 B! |请楼上的兄弟分析下BS的RegisterProtocolNotify也就是CoreRegisterProtocolNotify是做什么用的?怎么用?, r! b& }* e' K, b" X3 b2 d
谢谢!
0 F  k1 K$ t& [' W# }
......7 O- B! g' i% O5 d) W# X! h# t

: h6 D2 z5 a% M, ~7 Z
3 N* T4 A# {/ D+ f, q[ 本帖最后由 xtdumpling 于 2008-9-23 17:24 编辑 ]
回复

使用道具 举报

发表于 2008-9-24 12:43:45 | 显示全部楼层
原帖由 xtdumpling 于 2008-9-23 17:04 发表 $ c' }5 u% o2 f9 U2 T# G3 E. M- \

& J% J# `' l* J; n......
4 T* f$ e$ K9 [

  }4 t; U% e% DSignal的Event是不是在各个TPL级上挂载一些待处理的事件,一旦restore(TPL)的话,比当前TPL级高的pending事件就回被处理掉?6 v% y8 `- X( ~- e  W' e( V$ W
如果是这样的话,Timer事件是如何处理的呢,没有找到相关的代码呀?Xt指点一下再~
回复

使用道具 举报

发表于 2008-9-24 19:00:46 | 显示全部楼层
Timer是挂在8259的IRQ0的中断处理程序上面的, 大概每秒18.3次调用CoreTimerTick()-->CoreCheckTimers()
2 x# {7 [0 F* |  l# NTPL=30
回复

使用道具 举报

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

本版积分规则

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

GMT+8, 2026-4-25 03:37 , Processed in 0.116891 second(s), 16 queries .

Powered by Discuz! X3.5

© 2001-2025 Discuz! Team.

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