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

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

[复制链接]
发表于 2008-7-27 00:11:28 | 显示全部楼层 |阅读模式
  最近在工作看到机台有启动过程中把SPI ROM数据清空,但苦与没有办法很好的Debug(PCA没有架起来),所有与EDK为对象好好的读了一把。; d: z9 j. m- u& @  D+ j: k) r0 Z
" |; r  ~1 C) Q: m
SEC/CEI:
8 C. g8 q6 P$ h: a% E( o; ]" [: d; D  UEFI BIOS启动时先会执行SEC/CEI,这个阶段在实现的BIOS Code中初始化Debug Port,进入Big Mode,CPU的MicroCode,CacheToRAM的转换.然后跳转到PEI阶段。
& `9 M6 V. e/ [) `2 h9 T9 n$ ]在EDK中这部分被成了Load FvRecovery.fd文件,这个文件类似与我们的BIOS ROM.里面是我们编译后生成的二进制代码。在这个阶段最主要的是将这个文件加载到内存中(Windows API将文件加载到内存,看API函数).+ }, `" t' Y# Z! r
% m6 i) R. w  B* g0 g
PEI:
2 }$ v2 w- K: K' C8 q   从这里开始UEFI BIOS和EDK执行基本相同,只是一个是从SPI ROM中定位一个地址(PEIM的开始地址),一个是从内存中定位一个地址(PEIM的开始地址)。从这里开始只讲EDK的执行/ q4 j) A8 j! t; J5 }4 ?
  EDK调用InitializeMemoryService函数,将HobList清空,peiservice清空。
1 Q7 r4 s+ h7 ^      InitializePPIService函数,将PPI队列清空,这个队列长0x3F.
$ @5 X2 O* [# B  c          InitializeSercurityService函数,将Notify队列清空。) g  F0 y& N9 j( C- J
          InitializeDispatcherData函数,将Dispatcher队列清空。; k# `+ \: L% T9 l! u8 T+ y+ F
  接着由PeiBuildHobGuid来建立一个HOB(S3返回时这时应该有这个HOB,不用建立,直接使用了,这样就会进入另外一个流程,可以这个EDK不能调试S3,不知道怎么走)。然后由(*PeiServices)->InstallPpi()将这个新HOB加入到PPI中。9 w. z9 z: @: e( ?9 [
    由于在SEC阶段转了以下这几具PPI,所以在执行PEI的Dispatcher之前会先安装东西:
/ t' h- u9 y4 `# R      EFI_PEI_PPI_DESCRIPTOR    gPrivateDispatchTable[] = {* g* @( P8 _3 ]( a
       {EFI_PEI_PPI_DESCRIPTOR_PPI, &gEfiNtLoadAsDllPpiGuid, &mSecNtLoadAsDllPpi},9 @9 d; B/ f: ~9 U) O; B' _' G: E* X
       {EFI_PEI_PPI_DESCRIPTOR_PPI, &gNtPeiLoadFileGuid, &mSecNtLoadFilePpi},
+ n# W* U, H- {6 I- x9 Y       {EFI_PEI_PPI_DESCRIPTOR_PPI, &gPeiNtAutoScanPpiGuid, &mSecNtAutoScanPpi},
1 f- r/ [3 d. M5 g- m" v       {EFI_PEI_PPI_DESCRIPTOR_PPI, &gPeiNtThunkPpiGuid, &mSecWinNtThunkPpi},$ p- s" m& ^  A) Z1 ~' Y  H0 D
       {EFI_PEI_PPI_DESCRIPTOR_PPI, &gPeiStatusCodePpiGuid, &mSecStatusCodePpi},8 z0 B( b3 A7 C1 D, Z
       {EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST, &gNtFwhPpiGuid, &mSecFwhInformationPpi}1 C0 y5 b: o3 J6 U9 `
     };
  i( h* Y* d: y% ]    每个PPI是由{类型,GUID(名字,以后就根据这个来找到它的),Function_Entry_Address}组成。* l! ?2 ^7 q% w
   这些PPI会在PEIDispatcher中用到。3 z. n! K# i; P+ ?0 m& D
   安装完这此东西这开始执行PEIDispatcher函数,函数从BIOS ROM文件中找出PEI的Image(怎么找到,请读一下FV_HEAD(EFI_HEAD),里面讲到了如何区分Image类型),然后定位到PEI Image的入口地址,执行他。在我们的的PEI中,我们一般会申明一个PPI,这个就是这个PEI提供一些服务,PEIDispatcher会将他们加入到PPI-List中,以后其他Image也可以调用他的提供的功能。3 [8 y( w8 K% G* ]# {
   最后EDK会加载一个叫DXEIPL的PEI,DXEIPL提供一个PPI服务,这个PPI的功能是实现从PEI到DXE的切换,这个PPI里面为DXE做了很多的预准备,加载了很多PPI,如对BIOS的解压方法等。4 t5 V: k+ B3 W) U: u: J
   SwitchStacks (
9 m# u* L* c8 b7 G/ A. m4 f       (VOID *) (UINTN) DxeCoreEntryPoint,# E. @: M$ o+ b4 L! d, n
       (UINTN) (HobList.Raw),
) b8 V0 r7 H) ^3 ]# F       (VOID *) (UINTN) TopOfStack,  E; ~( o. ~, K" I, w
       (VOID *) (UINTN) BspStore
/ l, Q; E' T; j5 q2 z    );# u6 Q! }8 m  u1 k, {
  用过汇编的人对这个技术一定很熟悉,不多说了(我别不清,咯。。。)
* D0 g3 b- ^1 c/ q# a7 O7 V  g# N$ w3 q% S6 C9 q7 R; }2 x* C
DXE:5 M' A0 g0 A& X1 ?
     从PEI到DXE切换时转过来一个HOBLIST参数,DXE会在这个HOB中找到Memory的使用情况,然后根据这些情况将BIOS引到内存(这是EFI的做法)。在EDK在DXE时重新定位一下内存。
- I+ s  t& _3 I- N6 [接着就会定义我们经常使用到的gST表,gRT表。接着是申明一些Protocol(先不关心这些事)。
/ O8 ^+ ^0 B  y. r# A   等这些该加的PPI,Protocol加完了,CoreDispatcher()就出场了。他会的功能类似PEIDispatcher()。从我们BIOS ROM中将DXE的驱动读出,执行执行他们,这时会执行到Driver5 Y+ b2 A6 }; f% v4 j. w, {$ R
中的Support(),Start()两个功能函数。在这两个函数中你可以注册自己的PPI,为其他驱动提供服务。
. E7 F: F7 n, B3 K" X; S   到些BIOS的引导其他完成。接着该进OS了,看Linux 0.11吧,操作系统是怎么做事情的。. f9 n- Z7 r% p; m0 i
   
$ n$ C# Y+ w6 a8 ]Driver:
; C, e8 b( v( L! Z  K    我们的驱动什么为在PEI和DXE等不同阶段执行呢?, U/ l0 H/ j3 k9 v" n. p/ o# h
  大家请看一下我们的驱动的makefile.(EDK中的*.inf)
; g/ N: M7 r' H  [defines]
8 c! `6 ]4 F8 G  BASE_NAME            = OWEN, U& y3 Y. {. h5 o
  FILE_GUID            = 1EDD13C1-62EF-4262-A1AA-0040D0830110! @, N: F/ g  t
  COMPONENT_TYPE       = BS_DRIVER
9 Q# q& S3 j% J8 ^0 ]+ h! J! X& u8 L
  BASE_NAME告诉编译器最终生成的驱动的名字。4 G& r" u; F. Z, p
  FILE_GUID就是这个驱动的GUID名字,在BIOS中引用某个驱动就是根据它来调用和识别。) Q6 Q0 t3 X0 b# @& B: t) b( j
  COMONENT_TYPE会告诉编译器生成驱动的类型,是PEI,DXE,等。! Q/ \9 \  E" _! i* C/ A9 ~
  在EDK中有一个FWVolume.c实现的功能就是帮我们把这个TYPE转换面相应的扩展名: c: Q- [9 {, f. w& f' K/ M
  COMP_TYPE_EXTENSION  mCompTypeExtension[] = {
' h0 P1 Q1 D' b- V" ~  {"bs_driver",  ".dxe" },) R( T% Z7 |, I# S7 }- L' m
  {"rt_driver",  ".dxe" },
; e, K; P+ U9 c; }- F  {"sal_rt_driver", ".dxe"},3 L; y( d$ a+ Z( K  L
  {"security_core", ".sec"},
! G  E1 i3 _: ~) B+ n  {"pei_core", ".pei"},, I& D- l0 c9 t8 n4 z3 y* k5 y
  {"pic_peim", ".pei"},0 s( w  E( d' I3 e
  {"pe32_peim", ".pei"},
# f& W' z0 Z$ _3 Z' j0 C: C  {"relocatable_peim", ".pei"},
8 [# J, F+ U! Z. H  B% N; I  {"binary", ".ffs"},9 o. x! ?0 C1 S. Z
  {"application", ".app"},4 L+ n2 K: O) o# Q' l! V) V- t
  {"file", ".ffs"},
1 T. G0 g& L; i: B. e4 q6 S  {"fvimagefile", ".fvi"},
" L. i( s4 `" r$ `  {"rawfile", ".raw"},' M$ I; c. }# C, n& o" J1 e# ^
  {"apriori", ".ffs"},
# G. N2 ^( C" q- Q' C- M  {"combined_peim_driver", ".pei"},
" a/ D6 F5 O% b) p- y  { NULL,  NULL }; H* k. L& A! @" }2 a; o- d
};
: p, b7 G( O1 Y" i# z9 J
- u3 c) G5 J$ c了解了这些,接下我们可以看驱动篇了。(Go On Study... Forever)
/ \, x/ d8 V/ P5 G: q2 @  D1 l0 U   
% N( |3 V; k* n7 R! Z         
% y' M1 S5 H3 Y% J  
发表于 2008-7-27 12:30:15 | 显示全部楼层
不错!
5 N: q% D9 Z( h4 C9 j) Q/ [9 A( U支持: e8 l4 J! t9 W+ }& s
继续  \  @  L2 L" _2 t$ K
加油
- b8 D3 L8 t6 x7 M9 `% [9 Z
回复

使用道具 举报

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

回复 1# 的帖子

gPrivateDispatchTable 和COMP_TYPE_EXTENSION  没有搜到啊  是EDK专有的么?% Z) u  R: x/ V2 G& [
有看过跟gPrivateDispatchTable 类似的,但是里面的PPI不同。* x! |( I% i3 l* |% m
还有这个COMP_TYPE_EXTENSION  没有找到过。FWVolume.c这个文件也没有发现。。
回复

使用道具 举报

发表于 2008-7-28 13:24:20 | 显示全部楼层
这东西虽说没有什么技术含量,但是总结一下还是非常好的。
  _! A  A' b6 B" N! `; [! ?/ F
0 P, G- O- J- Z% V8 b支持!
回复

使用道具 举报

 楼主| 发表于 2008-7-28 18:52:31 | 显示全部楼层
! I- j, v  I5 Q5 m8 v/ D
小弟还在学习阶段,目前的目标是知道执行的流程。9 e2 g: n4 F8 P
这里面有很多细节没有写,能力有限,只能自己知道,不能表达。
9 K. c. L5 i! ~5 h$ k: H3 _2 m嘿。。。。0 P: |! d8 d) h3 S
所有大侠们如果有好东西能给小弟共享一份。
' E+ x. Y, [8 C8 g) E* E' L! ]/ j
( I8 y1 V- z) o0 w  U谢谢!
回复

使用道具 举报

发表于 2008-8-12 14:44:11 | 显示全部楼层
原帖由 winbondowen 于 2008-7-27 00:11 发表 - x- [4 `9 Y7 R4 m: X: E# g! ?, V
  ROM中將DXE的驅動讀出,執行執行他們,這時會執行到Driver
, s/ ~5 }" Z" t中的Support(),Start()兩個功能函數。在這兩個函數中你可以註冊自己的PPI ...

# D8 {0 B2 V1 _5 `( `# I$ K# P7 ?# e% n; ]0 g
PPIs are registered during PEI phase, but Support()/Start() are invoked in DXE driver binding protocol, ! r- d: g( Z. L6 j/ m( q
For more precisely, I think the "PPI" you mentioned is the "PROTOCOL" rather than "PPI".
! L! Z7 v! h4 T2 B# {* y0 c, s; P
: Q! b- G4 ^; x0 z9 `! X[ 本帖最后由 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 M4 o  D9 Y: g# t! s7 C
   Yes. I make a mistake.
- m* |- P/ J. g  _      PPI:     A PEIM to PEIM interface.
: K- H: T4 l* F  Q% A0 I      PROTOCL: A Interface between Hardware(or firmware) and software.
' h% }. o2 H9 J7 o0 w      reference[http://www.biosren.com/viewthread.php?tid=207]# S- G3 `. y2 L
   so, PPI execute at PEI step and Initialize hardware. PROTOCOL execute by DXE step.3 y8 A7 e1 ^9 t
   Thanks.
回复

使用道具 举报

发表于 2008-8-20 17:47:21 | 显示全部楼层
原帖由 winbondowen 于 2008-7-27 00:11 发表 DXE:
5 x9 u/ \& h% h. {4 e     從PEI到DXE切換時轉過來一個HOBLIST參數,DXE會在這個HOB中找到Memory的使用情況,然後根據這些情況將BIOS引到內存(這是EFI的做法)。在EDK在DXE時重新定位一下內存。
6 F( D) c* s+ }: c接著就會定義我們經常使用到的gST表,gRT表。接著是申明一些Protocol(先不關心這些事)。
* F; m( d2 f; d1 C   等這些該加的PPI,Protocol加完了,CoreDispatcher()就出場了。他會的功能類似PEIDispatcher()。從我們BIOS ROM中將DXE的驅動讀出,執行執行他們,這時會執行到Driver
# A9 D& D0 j" c+ V8 y2 b5 n8 B中的Support(),Start()兩個功能函數。在這兩個函數中你可以註冊自己的PPI,為其他驅動提供服務。$ S  q: C8 \9 K+ x
   到些BIOS的引導其他完成。接著該進OS了,看Linux 0.11吧,操作系統是怎麼做事情的。.

4 b% p" O; T& w1 X/ {
$ @9 T9 s1 c& Z' i( g# eThere are mistakes,
# ?/ T; m1 ~% X4 _% u3 \1.gST and gRT are init after the DXE architectural protocols have been loaded, those protocols response for creating Dxe foundation.
: t% p* Y& y& M1 F2 n! ^' [/ H+ y
9 D  W# P% Y% s& Q% d2.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.
" A" ?" p: Q3 z$ j" z2 Q% A% lThe CoreDispatcher() executes all trusted Dxe drivers and just register the Binding protocol if the driver is EFI1.1 driver model.
2 w  q/ l* v  Q8 zFurthermore, Support()/Start() are invoked in BDS phase over the CoreConnectController() rather than CoreDispatcher().
& c8 Z+ U% z9 h9 I" ]
, E1 t+ p/ Y5 T  B* S1 SBTW, 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 大侠的指点。( K" y7 N: S2 c& z
回复

使用道具 举报

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

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

原帖由 ichirohiro 于 2008-8-20 17:47 发表
. a0 }  }& p/ m+ X" t...
; M* u* X5 }: e' c  j/ R2.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.
/ n+ G. f6 a. h$ ^3 ^/ AThe CoreDispatcher() executes all trusted Dxe drivers and just register the Binding protocol if the driver is EFI1.1 driver model.! X. B, C' p: i' |% d
Furthermore, Support()/Start() are invoked in BDS phase over the CoreConnectController() rather than CoreDispatcher().

3 \$ n, v. U0 C/ L7 k% _6 m    在Framework的spec DxeCis.pdf里面也是这么说的,DXE CoreDispatcher()里面,对于EFI1.1 driver model的driver只会安装Handler和Interface到Binding protocol,到BDS才会去执行Support()和Start().8 z$ b! l7 l( h0 x2 b6 F
    但是,我在看code时,发现在CoreDispatcher()-->CoreStartImage()里面call image之后有这么一句:  (file:image.c)/ G% E) ^5 e- X1 D% \0 E. v( |8 B2 S
  //$ T" W8 c- P/ c' X+ r) v
  // Go connect any handles that were created or modified while the image executed.
& K/ e* ]9 c. ^: U7 J  //4 u: u# g6 L: j7 a& O! Q7 l
  CoreConnectHandlesByKey (HandleDatabaseKey);

: h$ K9 [8 R% K; u这里的HandleDatabaseKey是call image之前由CoreGetHandleDatabaseKey()得到的gHandleDatabaseKey; l: u. Q3 R" ^" J. c
而CoreConnectHandlesByKey会调用到:
+ N$ y1 h8 c! a  z2 z7 u1 O, u  //
0 ^- q0 s4 A! Z  // Connect all handles whose Key value is greater than Key; n; g9 J7 r5 V: s# u8 e
  //6 k& }5 u0 T& p$ ?3 J
  for (Index = 0; Index < Count; Index++) {
$ [0 K, {1 y* d! p6 ~. O* p    CoreConnectController (HandleBuffer[Index], NULL, NULL, TRUE);- ?( A* P  @9 z0 i$ Q& b/ }: P
  }

& ^0 {4 V. @" O6 x6 ~所以,照code看,当在Driver中安装一个Handle和Interface到Binding Protocol后(gHandleDatabaseKey会++,IHandle的Key=gHandleDatabaseKey)7 m* b0 P  j* |6 a6 X1 s( H! v
是会去ConnectController的,也会执行对应的Support()和Start()才对!!0 D+ Z( O: U1 W5 j% Z

  L5 B9 t* m1 O$ c7 g: A不知道我想的哪里有问题???欢迎大家指正.4 N# H( `" F+ \  y" |) H# s# `  U

6 K6 o1 |) J/ d0 K# G[ 本帖最后由 xtdumpling 于 2008-9-18 15:25 编辑 ]
回复

使用道具 举报

发表于 2008-9-19 14:44:41 | 显示全部楼层
这段code似乎是一个向后兼容的行为,不必太care。
) }3 f! R, B/ L4 f0 k一个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 | 显示全部楼层
了解了.
: K5 A; c: }. @( F2 i+ i% g非常 感谢!!!
回复

使用道具 举报

发表于 2008-9-23 16:48:56 | 显示全部楼层
在读DXEmain时,# U  D  y. {+ e
Status = CoreInitializeImageServices(HobStart);--->CoreInstallProtocolInterface();--->CoreInstallProtocolInterfaceNotify();中,3 w; }8 S$ O6 X9 u, s9 _
//
/ g0 G. C( \7 i! f. O( j8 }6 n// Notify the notification list for this protocol.
4 I& Y3 H6 C8 \; e  l1 F//
. z3 p" a6 I; v) b) p+ K& \if (Notify) {# Z1 B/ i: g$ C  N9 J  c' x
  CoreNotifyProtocolEntry(ProtEntry);2 ~/ }# k( a' F/ ~
}    里Signal了Event. MS是说一个handle安装了一个protocol后就signal一次.% A2 f" ^" h9 `4 W1 P
有个问题请教一下大家: 这段是在DXE很靠前的位置执行的,但是在它之前我没有看到DXE中有相关的CreateEvent出现?哪位高手能说说这部分代码的流程呢?
回复

使用道具 举报

发表于 2008-9-23 17:04:14 | 显示全部楼层
原帖由 xtdumpling 于 2008-9-16 13:34 发表
  ^$ B" {9 L) m9 }请楼上的兄弟分析下BS的RegisterProtocolNotify也就是CoreRegisterProtocolNotify是做什么用的?怎么用?
6 a* k( E& W1 D0 t( z: v2 F谢谢!
: J1 _, j: y) _/ W0 d: g; g$ p
......3 v- d+ W( a+ E" t$ z& R
2 W! B; C! \! X- ]' t. R! z
5 U; o* _- h* G& Z( ~. ]
[ 本帖最后由 xtdumpling 于 2008-9-23 17:24 编辑 ]
回复

使用道具 举报

发表于 2008-9-24 12:43:45 | 显示全部楼层
原帖由 xtdumpling 于 2008-9-23 17:04 发表 ; u5 W4 M; Q: w1 P" {. f0 q+ v# Y
* U6 Z! ^5 h  n; v1 T
......9 N- y6 @# I0 ~  m7 |
7 V& C0 ~: h. N: G' y0 H
Signal的Event是不是在各个TPL级上挂载一些待处理的事件,一旦restore(TPL)的话,比当前TPL级高的pending事件就回被处理掉?3 V: d8 d6 K+ {
如果是这样的话,Timer事件是如何处理的呢,没有找到相关的代码呀?Xt指点一下再~
回复

使用道具 举报

发表于 2008-9-24 19:00:46 | 显示全部楼层
Timer是挂在8259的IRQ0的中断处理程序上面的, 大概每秒18.3次调用CoreTimerTick()-->CoreCheckTimers()
, a  ^6 A' o+ y7 }" {TPL=30
回复

使用道具 举报

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

本版积分规则

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

GMT+8, 2026-4-4 18:21 , Processed in 0.071276 second(s), 17 queries .

Powered by Discuz! X3.5

© 2001-2025 Discuz! Team.

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