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

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

[复制链接]
发表于 2008-7-27 00:11:28 | 显示全部楼层 |阅读模式
  最近在工作看到机台有启动过程中把SPI ROM数据清空,但苦与没有办法很好的Debug(PCA没有架起来),所有与EDK为对象好好的读了一把。
; `& H5 S* V( q0 A3 W7 p. }: A+ U) R
SEC/CEI:) T: a- p7 i2 X* _- q
  UEFI BIOS启动时先会执行SEC/CEI,这个阶段在实现的BIOS Code中初始化Debug Port,进入Big Mode,CPU的MicroCode,CacheToRAM的转换.然后跳转到PEI阶段。6 q/ h: g+ T4 _; p* L* X
在EDK中这部分被成了Load FvRecovery.fd文件,这个文件类似与我们的BIOS ROM.里面是我们编译后生成的二进制代码。在这个阶段最主要的是将这个文件加载到内存中(Windows API将文件加载到内存,看API函数).: }% }: X% u$ R
0 g* D0 y. ^+ @( T+ I- b2 o
PEI:6 t& @6 _) m( ^$ V# c
   从这里开始UEFI BIOS和EDK执行基本相同,只是一个是从SPI ROM中定位一个地址(PEIM的开始地址),一个是从内存中定位一个地址(PEIM的开始地址)。从这里开始只讲EDK的执行; y5 O  O8 K. E" G& s# M1 R
  EDK调用InitializeMemoryService函数,将HobList清空,peiservice清空。
9 H$ D! X/ ]& z( V) k6 ~      InitializePPIService函数,将PPI队列清空,这个队列长0x3F.
4 f0 \2 l+ B) M+ N; _8 D          InitializeSercurityService函数,将Notify队列清空。  s+ Q& _9 Z% I6 b' C$ p
          InitializeDispatcherData函数,将Dispatcher队列清空。
, H4 b! Z% r0 S5 X9 ~  接着由PeiBuildHobGuid来建立一个HOB(S3返回时这时应该有这个HOB,不用建立,直接使用了,这样就会进入另外一个流程,可以这个EDK不能调试S3,不知道怎么走)。然后由(*PeiServices)->InstallPpi()将这个新HOB加入到PPI中。' j) t' H0 K8 h2 Y2 r
    由于在SEC阶段转了以下这几具PPI,所以在执行PEI的Dispatcher之前会先安装东西:( \0 d* C( B9 y( L* |! X+ A: N
      EFI_PEI_PPI_DESCRIPTOR    gPrivateDispatchTable[] = {; K) ]+ c2 g8 i* \: {9 O! Y+ M
       {EFI_PEI_PPI_DESCRIPTOR_PPI, &gEfiNtLoadAsDllPpiGuid, &mSecNtLoadAsDllPpi}," {& T' |3 q1 r7 T0 p+ N1 H/ q
       {EFI_PEI_PPI_DESCRIPTOR_PPI, &gNtPeiLoadFileGuid, &mSecNtLoadFilePpi},
3 H1 P: Q. t5 _9 _" p8 n       {EFI_PEI_PPI_DESCRIPTOR_PPI, &gPeiNtAutoScanPpiGuid, &mSecNtAutoScanPpi},% Z/ k3 }' g2 K8 D9 N
       {EFI_PEI_PPI_DESCRIPTOR_PPI, &gPeiNtThunkPpiGuid, &mSecWinNtThunkPpi},
* W1 F/ l- G8 K" v       {EFI_PEI_PPI_DESCRIPTOR_PPI, &gPeiStatusCodePpiGuid, &mSecStatusCodePpi},
  u9 O* R5 A% M$ Y7 S+ f: U( L3 e) `% e       {EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST, &gNtFwhPpiGuid, &mSecFwhInformationPpi}; R6 g, y3 E% L. T( ~8 d
     };  I: A5 q8 a) W! K, t7 L/ e
    每个PPI是由{类型,GUID(名字,以后就根据这个来找到它的),Function_Entry_Address}组成。
9 v* z& I" N) `   这些PPI会在PEIDispatcher中用到。8 ]  Q* Q8 ^  P* D
   安装完这此东西这开始执行PEIDispatcher函数,函数从BIOS ROM文件中找出PEI的Image(怎么找到,请读一下FV_HEAD(EFI_HEAD),里面讲到了如何区分Image类型),然后定位到PEI Image的入口地址,执行他。在我们的的PEI中,我们一般会申明一个PPI,这个就是这个PEI提供一些服务,PEIDispatcher会将他们加入到PPI-List中,以后其他Image也可以调用他的提供的功能。
  @3 y% k0 ]% F* U8 v, s- b# K2 v   最后EDK会加载一个叫DXEIPL的PEI,DXEIPL提供一个PPI服务,这个PPI的功能是实现从PEI到DXE的切换,这个PPI里面为DXE做了很多的预准备,加载了很多PPI,如对BIOS的解压方法等。" T) G6 B) k3 A8 ]
   SwitchStacks (0 ~% X% S) a# e# x. @) M- V
       (VOID *) (UINTN) DxeCoreEntryPoint,
+ S, \) t* X, v0 f1 [' U) h' S! \       (UINTN) (HobList.Raw),% Y' z- j  u1 q$ F) i
       (VOID *) (UINTN) TopOfStack,
6 W% L- Q% j- A9 a8 e, D/ k       (VOID *) (UINTN) BspStore
3 n) F9 r4 n# B) C$ D4 q4 ~    );
. j" O+ i) Y" Y! e5 H* l  用过汇编的人对这个技术一定很熟悉,不多说了(我别不清,咯。。。)2 B* ^4 G0 {: f* N  q: r9 V+ s, l

6 g# u; \* R: a0 F$ O" b, T; BDXE:+ w" R* F1 V0 P% h
     从PEI到DXE切换时转过来一个HOBLIST参数,DXE会在这个HOB中找到Memory的使用情况,然后根据这些情况将BIOS引到内存(这是EFI的做法)。在EDK在DXE时重新定位一下内存。
9 j' }( X. c: R; J接着就会定义我们经常使用到的gST表,gRT表。接着是申明一些Protocol(先不关心这些事)。
  h. L  {! p# {   等这些该加的PPI,Protocol加完了,CoreDispatcher()就出场了。他会的功能类似PEIDispatcher()。从我们BIOS ROM中将DXE的驱动读出,执行执行他们,这时会执行到Driver$ ], q+ I$ k$ f: ~+ ]/ Z' R
中的Support(),Start()两个功能函数。在这两个函数中你可以注册自己的PPI,为其他驱动提供服务。
$ g3 I5 Q: V+ c. T; i1 x   到些BIOS的引导其他完成。接着该进OS了,看Linux 0.11吧,操作系统是怎么做事情的。
) A) c. {. C: @/ H  s8 r   . d: N2 A: y- e, W! N0 S
Driver:
- O- {/ z* K  }. t8 S    我们的驱动什么为在PEI和DXE等不同阶段执行呢?
0 I$ x" o$ y; c  大家请看一下我们的驱动的makefile.(EDK中的*.inf)" X3 e% x; t: |
  [defines]
5 B3 K( o2 x( F  BASE_NAME            = OWEN
; j) `& w2 [- g5 B1 Q  FILE_GUID            = 1EDD13C1-62EF-4262-A1AA-0040D08301103 g: d/ W: h# x- l6 v
  COMPONENT_TYPE       = BS_DRIVER
8 ~' p+ j2 B9 F& B7 ^# N/ X
7 v$ e2 C1 w: u- r3 a" A  BASE_NAME告诉编译器最终生成的驱动的名字。; g& x* f  u9 `% N6 }
  FILE_GUID就是这个驱动的GUID名字,在BIOS中引用某个驱动就是根据它来调用和识别。
3 F# A) C6 v* x: i" I8 w( o2 v  COMONENT_TYPE会告诉编译器生成驱动的类型,是PEI,DXE,等。
) F. R: Y8 b& Z! c' t  在EDK中有一个FWVolume.c实现的功能就是帮我们把这个TYPE转换面相应的扩展名
5 O: D& Z! @) e; k- e; M& o. k2 x; H  COMP_TYPE_EXTENSION  mCompTypeExtension[] = {' x. _8 J5 z4 `) M
  {"bs_driver",  ".dxe" },5 @$ ^' r& u1 W' J2 s# z3 d
  {"rt_driver",  ".dxe" },. s  I& u) A+ G" F# v1 E
  {"sal_rt_driver", ".dxe"},' u+ ]4 L4 R  }4 I1 X: R& S
  {"security_core", ".sec"},
0 ?+ U: Y! U4 u7 K$ h+ q  {"pei_core", ".pei"},
  S+ r3 m2 ~5 O7 q( c. g  {"pic_peim", ".pei"},
. V2 w% I$ v0 T% t4 m9 o% J  {"pe32_peim", ".pei"},, u6 x# a, h7 P& S. T
  {"relocatable_peim", ".pei"},
& b3 ^. |, B9 L( x- a  {"binary", ".ffs"}," F0 t  Q% X1 l6 ]# `
  {"application", ".app"},9 R6 [: q7 I3 ]# Y- {' M% v
  {"file", ".ffs"},  P# O5 n9 B% S1 P. \2 }( r9 F
  {"fvimagefile", ".fvi"}," \+ Q! U& U1 h' g7 R5 U
  {"rawfile", ".raw"},+ k2 j% j* p; u. {7 k; m( H4 ?
  {"apriori", ".ffs"},
, W/ ~& \4 x, y" G  {"combined_peim_driver", ".pei"},
5 j$ u+ W$ L( U% y1 W+ S  { NULL,  NULL }
- u* f; ]& C1 S- C7 ^) e5 Z! w};2 R: I. K% N( k) p: A
" G+ ?) X, |* R( `# A5 [6 Y" x* {
了解了这些,接下我们可以看驱动篇了。(Go On Study... Forever)6 m% p% D. _; k* T. S
   
; I* C0 U1 j( H  A8 o         
) s6 K: S. T& A% h: A4 s' y: r  
发表于 2008-7-27 12:30:15 | 显示全部楼层
不错!
) f- |; p5 F8 K; |支持
/ J, A0 @; ]+ O4 U6 O继续
2 Z/ f/ [; S& w$ L% q/ ^  T8 n1 F加油
* E# \6 z* O6 D* P4 D! r: z' }
回复

使用道具 举报

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

回复 1# 的帖子

gPrivateDispatchTable 和COMP_TYPE_EXTENSION  没有搜到啊  是EDK专有的么?
/ h1 L. C$ S0 _3 v9 \  h. ?) |8 f有看过跟gPrivateDispatchTable 类似的,但是里面的PPI不同。
5 e$ l% v0 L5 B6 ], e- U* S还有这个COMP_TYPE_EXTENSION  没有找到过。FWVolume.c这个文件也没有发现。。
回复

使用道具 举报

发表于 2008-7-28 13:24:20 | 显示全部楼层
这东西虽说没有什么技术含量,但是总结一下还是非常好的。" B( e/ d- \( R+ L6 v
+ R& i- C  [1 m
支持!
回复

使用道具 举报

 楼主| 发表于 2008-7-28 18:52:31 | 显示全部楼层
8 m$ W. m% l# G3 j
小弟还在学习阶段,目前的目标是知道执行的流程。
% R# [% c  @& o9 D8 B这里面有很多细节没有写,能力有限,只能自己知道,不能表达。
$ c) \) Q; a' F' P+ l+ r1 n嘿。。。。
$ [# Y: ^, v/ e所有大侠们如果有好东西能给小弟共享一份。0 `1 W; i4 p% c/ s* c

8 \, @, F2 a) J$ J: f谢谢!
回复

使用道具 举报

发表于 2008-8-12 14:44:11 | 显示全部楼层
原帖由 winbondowen 于 2008-7-27 00:11 发表
, N! n3 N! ^, ?6 R  ROM中將DXE的驅動讀出,執行執行他們,這時會執行到Driver
( w! y1 x0 S& r% u中的Support(),Start()兩個功能函數。在這兩個函數中你可以註冊自己的PPI ...

! m7 h4 j0 P4 f. w
* C# \0 ^: T: X. _. NPPIs are registered during PEI phase, but Support()/Start() are invoked in DXE driver binding protocol,
: L& n  e. Y7 \1 Z8 v% v6 D/ z3 sFor more precisely, I think the "PPI" you mentioned is the "PROTOCOL" rather than "PPI".6 M4 s( d8 e, i: u1 V6 @
& H" i9 m0 N3 e0 `) _0 ^
[ 本帖最后由 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 M. [, Z& C$ k5 A! G. S5 x   Yes. I make a mistake.
& Q* P$ {9 K9 d& ^1 z3 H, x1 w      PPI:     A PEIM to PEIM interface.4 O' R1 x5 V; Y6 m) c
      PROTOCL: A Interface between Hardware(or firmware) and software.1 h& y$ v5 b; `, i- Y0 V8 w
      reference[http://www.biosren.com/viewthread.php?tid=207]
$ H. c& b3 a( G# F5 E   so, PPI execute at PEI step and Initialize hardware. PROTOCOL execute by DXE step.
' ~3 D: l% s  {0 t; \   Thanks.
回复

使用道具 举报

发表于 2008-8-20 17:47:21 | 显示全部楼层
原帖由 winbondowen 于 2008-7-27 00:11 发表 DXE:  f4 o  g& k; p: u, ^
     從PEI到DXE切換時轉過來一個HOBLIST參數,DXE會在這個HOB中找到Memory的使用情況,然後根據這些情況將BIOS引到內存(這是EFI的做法)。在EDK在DXE時重新定位一下內存。) a$ Q: C- V2 a/ |6 F& J8 h/ a6 @
接著就會定義我們經常使用到的gST表,gRT表。接著是申明一些Protocol(先不關心這些事)。! h- G# W# Q( {& m
   等這些該加的PPI,Protocol加完了,CoreDispatcher()就出場了。他會的功能類似PEIDispatcher()。從我們BIOS ROM中將DXE的驅動讀出,執行執行他們,這時會執行到Driver
0 u7 ?1 B4 y8 _7 Q- z中的Support(),Start()兩個功能函數。在這兩個函數中你可以註冊自己的PPI,為其他驅動提供服務。6 L, j* v; D% @7 H% f
   到些BIOS的引導其他完成。接著該進OS了,看Linux 0.11吧,操作系統是怎麼做事情的。.
! y+ V, M% @+ Z; U8 W* E

6 G+ j- M& M, \, }4 VThere are mistakes,
  W  D8 K% F) B# D' D1 l4 c- ~" n+ D1.gST and gRT are init after the DXE architectural protocols have been loaded, those protocols response for creating Dxe foundation.
5 L  g7 ^7 R/ f; T6 ?
8 Z* |, R% V" i6 R3 a2.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.
% q4 c/ Y3 S3 r1 v2 w; I+ j# fThe CoreDispatcher() executes all trusted Dxe drivers and just register the Binding protocol if the driver is EFI1.1 driver model.
9 q4 a7 m5 m2 bFurthermore, Support()/Start() are invoked in BDS phase over the CoreConnectController() rather than CoreDispatcher().
1 t- T7 O! y/ R2 P" c+ G
; h$ ~3 V6 x- J# `& O( N) OBTW, 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 大侠的指点。2 r* |. N  @6 j! R; t
回复

使用道具 举报

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

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

原帖由 ichirohiro 于 2008-8-20 17:47 发表 - C; ^. t5 c( s% o2 a: Y4 S
...7 F3 i. j0 ]& f+ S& e4 T6 P6 Q
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.
7 z& H  Q1 ]- L: m% |; X# mThe CoreDispatcher() executes all trusted Dxe drivers and just register the Binding protocol if the driver is EFI1.1 driver model.7 y& Y6 D3 n% R% \+ N% g' s( Z
Furthermore, Support()/Start() are invoked in BDS phase over the CoreConnectController() rather than CoreDispatcher().
; w+ R& w* f1 b0 A% s' j0 f" [7 d6 [
    在Framework的spec DxeCis.pdf里面也是这么说的,DXE CoreDispatcher()里面,对于EFI1.1 driver model的driver只会安装Handler和Interface到Binding protocol,到BDS才会去执行Support()和Start().
% f# V' X  s: y. ?8 ~    但是,我在看code时,发现在CoreDispatcher()-->CoreStartImage()里面call image之后有这么一句:  (file:image.c)/ v; i- Y8 e6 C# e& Z
  //4 n  y$ M2 Q# D0 n
  // Go connect any handles that were created or modified while the image executed.
5 R' z, r# V- N3 ]9 L* m& \( F  //: \/ V& b. F8 w2 h
  CoreConnectHandlesByKey (HandleDatabaseKey);

- F5 G+ O$ @' f6 y; j" V- V这里的HandleDatabaseKey是call image之前由CoreGetHandleDatabaseKey()得到的gHandleDatabaseKey
  F9 C, n+ d1 q7 s  h* _  W而CoreConnectHandlesByKey会调用到:
: B! k; D7 ~$ c' V+ c  //
, m' M$ h# y0 N# {  // Connect all handles whose Key value is greater than Key/ L# Q2 }9 K2 k3 p& I9 s4 t6 l
  //
$ B' G3 G5 v% j  for (Index = 0; Index < Count; Index++) {) j( x7 U! I3 V& w+ g3 n# p; ]
    CoreConnectController (HandleBuffer[Index], NULL, NULL, TRUE);! T8 K" [0 ~/ I3 l
  }

, T# N5 J# B+ l3 s) ]所以,照code看,当在Driver中安装一个Handle和Interface到Binding Protocol后(gHandleDatabaseKey会++,IHandle的Key=gHandleDatabaseKey)
; g6 z8 ?, n' j. d/ K5 |' f% f9 V是会去ConnectController的,也会执行对应的Support()和Start()才对!!
2 I0 B9 b" M2 ~, C2 T5 I1 m( p  B8 G( P
不知道我想的哪里有问题???欢迎大家指正.8 j$ f; I+ Q" R1 B
* \3 C. D0 u; i; Q4 n; W6 B+ f" ^* a
[ 本帖最后由 xtdumpling 于 2008-9-18 15:25 编辑 ]
回复

使用道具 举报

发表于 2008-9-19 14:44:41 | 显示全部楼层
这段code似乎是一个向后兼容的行为,不必太care。
0 ]9 O4 j) Q2 s; D1 r1 n一个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 | 显示全部楼层
了解了.
7 i# x$ L& [2 b! p% c6 a+ O  Q非常 感谢!!!
回复

使用道具 举报

发表于 2008-9-23 16:48:56 | 显示全部楼层
在读DXEmain时,
9 y- T2 ?# y1 U( j" d, l( R  g8 |6 Z7 ]Status = CoreInitializeImageServices(HobStart);--->CoreInstallProtocolInterface();--->CoreInstallProtocolInterfaceNotify();中,
$ |. L5 r, d, j% B$ E//
# ~4 V2 W# V  m2 Y: P! H// Notify the notification list for this protocol.1 M/ a7 l. J; f4 B; }) R2 p
//3 r0 R1 F2 }: V( C7 ^/ R+ p" @* w; ^3 D
if (Notify) {
7 q5 ^0 J6 R. d7 C( r: k) R  CoreNotifyProtocolEntry(ProtEntry);
+ u- ]& E, H$ r- q5 j2 N; w4 ^2 w}    里Signal了Event. MS是说一个handle安装了一个protocol后就signal一次.
! ~$ h$ [' Z+ B0 N( A+ a有个问题请教一下大家: 这段是在DXE很靠前的位置执行的,但是在它之前我没有看到DXE中有相关的CreateEvent出现?哪位高手能说说这部分代码的流程呢?
回复

使用道具 举报

发表于 2008-9-23 17:04:14 | 显示全部楼层
原帖由 xtdumpling 于 2008-9-16 13:34 发表 5 j' m' b+ a9 q* ?8 f+ d
请楼上的兄弟分析下BS的RegisterProtocolNotify也就是CoreRegisterProtocolNotify是做什么用的?怎么用?5 f4 |; ?4 [& E. g: T/ X) T
谢谢!
# t6 F: K% M) T9 m4 _& }& I
....../ P% o7 q, g8 v3 e4 ~8 E+ w" I4 h5 S. s
, {, X% J$ Z3 q! \; P

! H0 d. r/ g7 A5 M# x* J[ 本帖最后由 xtdumpling 于 2008-9-23 17:24 编辑 ]
回复

使用道具 举报

发表于 2008-9-24 12:43:45 | 显示全部楼层
原帖由 xtdumpling 于 2008-9-23 17:04 发表
) t! p. G9 B" S4 I
3 W0 T* D1 R2 K4 ~3 H& {/ T......$ J( E$ d" H, d" j; w1 a1 `, N

" R$ }# j, _* X& e6 w8 K% u9 QSignal的Event是不是在各个TPL级上挂载一些待处理的事件,一旦restore(TPL)的话,比当前TPL级高的pending事件就回被处理掉?8 x2 U( v  t2 e# `! c" |
如果是这样的话,Timer事件是如何处理的呢,没有找到相关的代码呀?Xt指点一下再~
回复

使用道具 举报

发表于 2008-9-24 19:00:46 | 显示全部楼层
Timer是挂在8259的IRQ0的中断处理程序上面的, 大概每秒18.3次调用CoreTimerTick()-->CoreCheckTimers()
1 s# C1 s# o3 a, }2 F& B; OTPL=30
回复

使用道具 举报

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

本版积分规则

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

GMT+8, 2025-6-16 19:09 , Processed in 0.064758 second(s), 17 queries .

Powered by Discuz! X3.5

© 2001-2023 Discuz! Team.

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