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

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

[复制链接]
发表于 2008-7-27 00:11:28 | 显示全部楼层 |阅读模式
  最近在工作看到机台有启动过程中把SPI ROM数据清空,但苦与没有办法很好的Debug(PCA没有架起来),所有与EDK为对象好好的读了一把。) `' s7 \3 p9 g: c

; \7 c, m4 @& K' ?7 MSEC/CEI:8 l/ _, z8 H9 z
  UEFI BIOS启动时先会执行SEC/CEI,这个阶段在实现的BIOS Code中初始化Debug Port,进入Big Mode,CPU的MicroCode,CacheToRAM的转换.然后跳转到PEI阶段。7 U5 D" S$ ^) M* A+ W1 T6 E
在EDK中这部分被成了Load FvRecovery.fd文件,这个文件类似与我们的BIOS ROM.里面是我们编译后生成的二进制代码。在这个阶段最主要的是将这个文件加载到内存中(Windows API将文件加载到内存,看API函数).# D8 Q% O+ b2 P3 z
% k2 z' V- z3 ^) ]; ~7 F. R& t
PEI:
+ x* D! ~: H: N8 h. V   从这里开始UEFI BIOS和EDK执行基本相同,只是一个是从SPI ROM中定位一个地址(PEIM的开始地址),一个是从内存中定位一个地址(PEIM的开始地址)。从这里开始只讲EDK的执行9 R: m/ S6 G) x0 I) P
  EDK调用InitializeMemoryService函数,将HobList清空,peiservice清空。4 g0 B4 t4 V+ U0 @& Z1 ?# P+ u( F
      InitializePPIService函数,将PPI队列清空,这个队列长0x3F.
- h8 n( z: U( c1 |4 P5 H          InitializeSercurityService函数,将Notify队列清空。
7 i( K: k7 w& O  F: V          InitializeDispatcherData函数,将Dispatcher队列清空。
$ Z1 Y+ L& J+ `  |5 w  接着由PeiBuildHobGuid来建立一个HOB(S3返回时这时应该有这个HOB,不用建立,直接使用了,这样就会进入另外一个流程,可以这个EDK不能调试S3,不知道怎么走)。然后由(*PeiServices)->InstallPpi()将这个新HOB加入到PPI中。
% l! @3 \- f7 t    由于在SEC阶段转了以下这几具PPI,所以在执行PEI的Dispatcher之前会先安装东西:7 Z( d, D1 `( o7 K. J6 `
      EFI_PEI_PPI_DESCRIPTOR    gPrivateDispatchTable[] = {
  j4 I. T- d6 c# B& Z       {EFI_PEI_PPI_DESCRIPTOR_PPI, &gEfiNtLoadAsDllPpiGuid, &mSecNtLoadAsDllPpi},
3 J5 J0 M# E6 \; A1 l       {EFI_PEI_PPI_DESCRIPTOR_PPI, &gNtPeiLoadFileGuid, &mSecNtLoadFilePpi},
+ _% s8 B* y/ j9 I       {EFI_PEI_PPI_DESCRIPTOR_PPI, &gPeiNtAutoScanPpiGuid, &mSecNtAutoScanPpi},
9 r. C8 q3 q- L. G8 f1 b$ G! e       {EFI_PEI_PPI_DESCRIPTOR_PPI, &gPeiNtThunkPpiGuid, &mSecWinNtThunkPpi},
! @) q7 P( J; p3 }, F2 Y4 ]0 b       {EFI_PEI_PPI_DESCRIPTOR_PPI, &gPeiStatusCodePpiGuid, &mSecStatusCodePpi},
$ a  f/ G5 G! A) R* ]# ^       {EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST, &gNtFwhPpiGuid, &mSecFwhInformationPpi}
, B% J( t" a6 u" Y* ^" L6 D7 U     };% g* o  h0 F, h, ^8 Z( I
    每个PPI是由{类型,GUID(名字,以后就根据这个来找到它的),Function_Entry_Address}组成。
# E" b& i7 c& m0 j$ |7 A   这些PPI会在PEIDispatcher中用到。1 e$ T' s# h2 y9 F  U
   安装完这此东西这开始执行PEIDispatcher函数,函数从BIOS ROM文件中找出PEI的Image(怎么找到,请读一下FV_HEAD(EFI_HEAD),里面讲到了如何区分Image类型),然后定位到PEI Image的入口地址,执行他。在我们的的PEI中,我们一般会申明一个PPI,这个就是这个PEI提供一些服务,PEIDispatcher会将他们加入到PPI-List中,以后其他Image也可以调用他的提供的功能。) H3 m1 c! b( J+ p
   最后EDK会加载一个叫DXEIPL的PEI,DXEIPL提供一个PPI服务,这个PPI的功能是实现从PEI到DXE的切换,这个PPI里面为DXE做了很多的预准备,加载了很多PPI,如对BIOS的解压方法等。7 P6 s5 _: `5 o  y; u7 T
   SwitchStacks (
; ~6 c; x% h8 V1 E       (VOID *) (UINTN) DxeCoreEntryPoint,$ t- _' S# \  `! p
       (UINTN) (HobList.Raw),
) K! P+ b6 R3 t* x0 b2 D       (VOID *) (UINTN) TopOfStack,1 s* C2 n2 I- P3 f
       (VOID *) (UINTN) BspStore+ q7 H0 D' h$ f& x1 W2 m
    );' j: J! D  i: {; j2 L. d+ u, s( n
  用过汇编的人对这个技术一定很熟悉,不多说了(我别不清,咯。。。). a' g% x0 \' U) j# f9 {

, [! N+ D. Y" |DXE:$ Y2 }2 y0 ]  e3 G
     从PEI到DXE切换时转过来一个HOBLIST参数,DXE会在这个HOB中找到Memory的使用情况,然后根据这些情况将BIOS引到内存(这是EFI的做法)。在EDK在DXE时重新定位一下内存。
9 Q4 J: c7 ~' P0 r3 {: X% l. Y: u接着就会定义我们经常使用到的gST表,gRT表。接着是申明一些Protocol(先不关心这些事)。# A2 Y/ f: U. n7 N+ E' O3 }6 }
   等这些该加的PPI,Protocol加完了,CoreDispatcher()就出场了。他会的功能类似PEIDispatcher()。从我们BIOS ROM中将DXE的驱动读出,执行执行他们,这时会执行到Driver+ @2 |( j" o0 Q
中的Support(),Start()两个功能函数。在这两个函数中你可以注册自己的PPI,为其他驱动提供服务。
1 k, k4 X8 n% z" p) B3 r* \, D   到些BIOS的引导其他完成。接着该进OS了,看Linux 0.11吧,操作系统是怎么做事情的。
4 x- [2 g( q- g   . {5 Z3 D" O* y) H/ C2 G
Driver:, f0 X* X0 O( @* x, b1 P
    我们的驱动什么为在PEI和DXE等不同阶段执行呢?0 s4 l& Z7 A: T0 s1 Z0 c
  大家请看一下我们的驱动的makefile.(EDK中的*.inf)( v* ~# b/ f" V9 @; e
  [defines]
1 K' }" l5 L5 ~! O2 Q4 f  F  `5 a  BASE_NAME            = OWEN+ V5 r0 ?' ?* g0 i* S
  FILE_GUID            = 1EDD13C1-62EF-4262-A1AA-0040D0830110
0 i( A4 I* Q% w8 x0 l4 s  COMPONENT_TYPE       = BS_DRIVER
/ ]  y! h1 I5 R% b, m- c9 R: Z% n
  BASE_NAME告诉编译器最终生成的驱动的名字。
% y+ V! H* h& k9 A1 F' a  FILE_GUID就是这个驱动的GUID名字,在BIOS中引用某个驱动就是根据它来调用和识别。# w! b' d! S" B. X' b9 u
  COMONENT_TYPE会告诉编译器生成驱动的类型,是PEI,DXE,等。7 T& @/ e7 L, q
  在EDK中有一个FWVolume.c实现的功能就是帮我们把这个TYPE转换面相应的扩展名
' u8 E6 ]- V: R" G3 E6 L" T# a  COMP_TYPE_EXTENSION  mCompTypeExtension[] = {
( ]* f& x! z, ~4 q( o2 i  {"bs_driver",  ".dxe" }," g- t$ d! X! f- J4 o/ n) n
  {"rt_driver",  ".dxe" },3 o- T% m: O8 N' Y8 s
  {"sal_rt_driver", ".dxe"},
9 x$ r% T# B+ R  {"security_core", ".sec"},% W/ x3 l9 z% s& L- x3 V4 P' E
  {"pei_core", ".pei"},$ B. Y+ G. S* s: O) X0 d. |$ @
  {"pic_peim", ".pei"},6 S# m  K: v: |( c- r2 z
  {"pe32_peim", ".pei"},
7 j! `8 f& ?; X' q$ B2 Z0 }% r  {"relocatable_peim", ".pei"},  _: n9 V0 T6 [" J0 Z0 f
  {"binary", ".ffs"},% ?3 u8 b# Z4 C7 Z0 V. o
  {"application", ".app"},( `6 n! g9 d+ T: I9 D
  {"file", ".ffs"},
3 R; W$ @+ C) G4 x7 ^7 l  {"fvimagefile", ".fvi"},; C: v  \+ p; M& D! j6 \
  {"rawfile", ".raw"},
1 W% t! h* `! l- I  {"apriori", ".ffs"},) R, m: h, b$ x1 \5 K8 ^  f
  {"combined_peim_driver", ".pei"}," y( A, j0 n$ j! X* C1 Z
  { NULL,  NULL }
9 s$ s" a5 @+ N5 K) {  x0 D};
! w/ v' N) k6 c1 u) a! _% i7 _, y1 ~( ?! o& n3 x
了解了这些,接下我们可以看驱动篇了。(Go On Study... Forever)
: {; @4 n5 m6 q# ^/ ~   
; J1 [: y3 ^+ D$ I/ @( H* j. I; P         
# ~. J& P0 C0 H5 l  n/ @  
发表于 2008-7-27 12:30:15 | 显示全部楼层
不错!  r* N. \0 d6 v8 A9 v/ }+ e9 b9 m
支持+ z8 o. L1 x4 B1 v+ l; M; ~
继续* B7 n' P8 G/ u* V  A( i
加油" E& P1 j0 d2 K, `& X: K/ U3 \
回复

使用道具 举报

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

回复 1# 的帖子

gPrivateDispatchTable 和COMP_TYPE_EXTENSION  没有搜到啊  是EDK专有的么?$ v0 V9 h  S7 X& T
有看过跟gPrivateDispatchTable 类似的,但是里面的PPI不同。( [2 _4 M2 H4 p! T; \/ a
还有这个COMP_TYPE_EXTENSION  没有找到过。FWVolume.c这个文件也没有发现。。
回复

使用道具 举报

发表于 2008-7-28 13:24:20 | 显示全部楼层
这东西虽说没有什么技术含量,但是总结一下还是非常好的。' Q$ C# \, B( ^7 C/ L

4 q2 S/ h, R- m# J6 `7 T支持!
回复

使用道具 举报

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

/ R) Y( C1 z4 w  {' k小弟还在学习阶段,目前的目标是知道执行的流程。
0 n, W- A8 |7 C, Q, w这里面有很多细节没有写,能力有限,只能自己知道,不能表达。2 A! ]: q, k; ]
嘿。。。。. q" q+ B4 K; M, C
所有大侠们如果有好东西能给小弟共享一份。+ X- X1 B5 ?* |( x* X+ |

6 G. v3 n! A6 u* [/ i谢谢!
回复

使用道具 举报

发表于 2008-8-12 14:44:11 | 显示全部楼层
原帖由 winbondowen 于 2008-7-27 00:11 发表 # e  |$ X5 \8 c- z, D  z8 o$ Q" m
  ROM中將DXE的驅動讀出,執行執行他們,這時會執行到Driver
: _* d( _* s4 e* p1 O/ |中的Support(),Start()兩個功能函數。在這兩個函數中你可以註冊自己的PPI ...
8 P9 W; U2 d% K2 u% d) ?5 K

$ y. A# j: n, P( z" PPPIs are registered during PEI phase, but Support()/Start() are invoked in DXE driver binding protocol,
6 T% g: p3 t& a1 mFor more precisely, I think the "PPI" you mentioned is the "PROTOCOL" rather than "PPI".4 q7 u5 y  }+ U  Y1 l; E

9 G% ~2 z8 \; a* d8 @[ 本帖最后由 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:; D2 \6 n! P; p3 O' F' }
   Yes. I make a mistake.- g; J# r# j/ w( W
      PPI:     A PEIM to PEIM interface.
' e+ m+ s7 l' V) K      PROTOCL: A Interface between Hardware(or firmware) and software.
$ W4 O5 z6 r; S8 A/ R4 }      reference[http://www.biosren.com/viewthread.php?tid=207]
8 s% t: O& U7 E. D4 ~! U; H* D   so, PPI execute at PEI step and Initialize hardware. PROTOCOL execute by DXE step.- R& y- P% n/ ^# b1 z6 V
   Thanks.
回复

使用道具 举报

发表于 2008-8-20 17:47:21 | 显示全部楼层
原帖由 winbondowen 于 2008-7-27 00:11 发表 DXE:
$ ~4 A* _  k- R3 B$ x# Z% h     從PEI到DXE切換時轉過來一個HOBLIST參數,DXE會在這個HOB中找到Memory的使用情況,然後根據這些情況將BIOS引到內存(這是EFI的做法)。在EDK在DXE時重新定位一下內存。
# u" g$ v' Z1 O$ K: D接著就會定義我們經常使用到的gST表,gRT表。接著是申明一些Protocol(先不關心這些事)。( \" `5 l1 U5 [
   等這些該加的PPI,Protocol加完了,CoreDispatcher()就出場了。他會的功能類似PEIDispatcher()。從我們BIOS ROM中將DXE的驅動讀出,執行執行他們,這時會執行到Driver
) }7 M5 M# q6 Z1 q' N; ~) I4 L中的Support(),Start()兩個功能函數。在這兩個函數中你可以註冊自己的PPI,為其他驅動提供服務。
6 x0 w9 v2 J9 f' g+ f   到些BIOS的引導其他完成。接著該進OS了,看Linux 0.11吧,操作系統是怎麼做事情的。.

! ~  K. N) x, [" b5 \! Y/ Z
6 }- e  }' T1 B7 T2 ~5 Q6 y# [There are mistakes,+ ^* r5 a+ S7 q8 X
1.gST and gRT are init after the DXE architectural protocols have been loaded, those protocols response for creating Dxe foundation.
1 S: Z4 U0 Z8 Q
* H. Q) r& N! N) i4 V2.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.
/ x+ ~, _# _2 [8 K- e; EThe CoreDispatcher() executes all trusted Dxe drivers and just register the Binding protocol if the driver is EFI1.1 driver model.
- h' X. Y' c) ~Furthermore, Support()/Start() are invoked in BDS phase over the CoreConnectController() rather than CoreDispatcher().
. u0 I( E- ]6 p+ m9 X/ [8 @' g9 H  A, Q: @8 Q' _! G) 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 大侠的指点。
) ]6 h/ [! g0 Y
回复

使用道具 举报

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

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

原帖由 ichirohiro 于 2008-8-20 17:47 发表
& @1 h6 t' ^/ t" j3 N  o, a...
& k7 B- n9 k0 n$ i+ b7 [: N2.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 Y! Q9 s7 [: r7 M5 G. \& r$ q! v( DThe CoreDispatcher() executes all trusted Dxe drivers and just register the Binding protocol if the driver is EFI1.1 driver model.1 E* W, k! y/ N5 k* _
Furthermore, Support()/Start() are invoked in BDS phase over the CoreConnectController() rather than CoreDispatcher().

" g! G- d6 H5 ~4 s. S3 S    在Framework的spec DxeCis.pdf里面也是这么说的,DXE CoreDispatcher()里面,对于EFI1.1 driver model的driver只会安装Handler和Interface到Binding protocol,到BDS才会去执行Support()和Start().
" |; J0 I- ?$ I# n    但是,我在看code时,发现在CoreDispatcher()-->CoreStartImage()里面call image之后有这么一句:  (file:image.c)% g9 `) N8 `% f" w# P
  //; A6 h! B0 w. x  `6 W
  // Go connect any handles that were created or modified while the image executed., v. ]) U2 X4 w' e- V* u' U
  //
" j2 Z8 G$ w2 t8 a/ y  CoreConnectHandlesByKey (HandleDatabaseKey);

1 ]/ t! v  f0 y1 L6 x. R: `/ {$ m8 t, j! S这里的HandleDatabaseKey是call image之前由CoreGetHandleDatabaseKey()得到的gHandleDatabaseKey0 ]& O8 L9 `; t- e5 y6 W* z) D& q' t
而CoreConnectHandlesByKey会调用到:" [; x/ \! w$ B& f7 W
  //
2 d& }2 r6 e: b3 @( g  // Connect all handles whose Key value is greater than Key
+ t  p$ l6 n  d4 p  //
8 n) V4 B1 i( A- a) p; z* C5 U- X: w  for (Index = 0; Index < Count; Index++) {) g3 e3 s  y! ?& L8 _
    CoreConnectController (HandleBuffer[Index], NULL, NULL, TRUE);
. J- X0 l( E% F  }

( p! x( V) e; m3 y* G/ E) l所以,照code看,当在Driver中安装一个Handle和Interface到Binding Protocol后(gHandleDatabaseKey会++,IHandle的Key=gHandleDatabaseKey)  s9 m) V6 m; Y3 s, X, s
是会去ConnectController的,也会执行对应的Support()和Start()才对!!4 z9 N/ J) h7 f" e6 G! _+ h/ N( \

  ~# ^- \- a) B, D不知道我想的哪里有问题???欢迎大家指正.2 {  z0 \( n! Q8 P, j: s4 E& q

/ W$ V+ I. y3 Z5 I[ 本帖最后由 xtdumpling 于 2008-9-18 15:25 编辑 ]
回复

使用道具 举报

发表于 2008-9-19 14:44:41 | 显示全部楼层
这段code似乎是一个向后兼容的行为,不必太care。
8 M5 X, W' e$ \; P% 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 | 显示全部楼层
了解了.
! F+ e! [7 B9 q/ D( i+ }非常 感谢!!!
回复

使用道具 举报

发表于 2008-9-23 16:48:56 | 显示全部楼层
在读DXEmain时,
; X1 e: @6 L! _" z, B' SStatus = CoreInitializeImageServices(HobStart);--->CoreInstallProtocolInterface();--->CoreInstallProtocolInterfaceNotify();中,
; [/ c# [5 W( \5 }7 B//8 v" `. z- w; @
// Notify the notification list for this protocol.5 C# t, y" V) f0 R8 C* w6 K2 t4 k
//
! H. d# N+ o& {5 O' r* Q+ g4 H8 z/ h. Yif (Notify) {
$ k9 P/ j1 ^2 J' j' A! S0 {  CoreNotifyProtocolEntry(ProtEntry);& V' a: M- c* n3 [9 c+ S
}    里Signal了Event. MS是说一个handle安装了一个protocol后就signal一次., |# A# Q, J9 l/ u. X
有个问题请教一下大家: 这段是在DXE很靠前的位置执行的,但是在它之前我没有看到DXE中有相关的CreateEvent出现?哪位高手能说说这部分代码的流程呢?
回复

使用道具 举报

发表于 2008-9-23 17:04:14 | 显示全部楼层
原帖由 xtdumpling 于 2008-9-16 13:34 发表 & K* w( }# d8 L3 E( P4 ]% w
请楼上的兄弟分析下BS的RegisterProtocolNotify也就是CoreRegisterProtocolNotify是做什么用的?怎么用?
  i9 N+ \! x  J% b& @% @谢谢!

# s$ U. U3 {/ _% @" v4 V......
3 S% N' d' _& n8 H( }  ^3 m, {0 t4 R3 Y
! T& s6 `2 B1 a
[ 本帖最后由 xtdumpling 于 2008-9-23 17:24 编辑 ]
回复

使用道具 举报

发表于 2008-9-24 12:43:45 | 显示全部楼层
原帖由 xtdumpling 于 2008-9-23 17:04 发表 ! D1 D: |* q/ B7 v' K) Z

! c: Y7 `, h  w......0 e/ l2 {' o: b/ P, W- `1 S2 N

3 k  j$ x9 Q* `* i& jSignal的Event是不是在各个TPL级上挂载一些待处理的事件,一旦restore(TPL)的话,比当前TPL级高的pending事件就回被处理掉?
, p+ X" f) s" P1 F% n3 E如果是这样的话,Timer事件是如何处理的呢,没有找到相关的代码呀?Xt指点一下再~
回复

使用道具 举报

发表于 2008-9-24 19:00:46 | 显示全部楼层
Timer是挂在8259的IRQ0的中断处理程序上面的, 大概每秒18.3次调用CoreTimerTick()-->CoreCheckTimers()
# R, k; B  [& D: Z# @. o5 R% ?TPL=30
回复

使用道具 举报

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

本版积分规则

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

GMT+8, 2025-6-14 21:32 , Processed in 0.040763 second(s), 17 queries .

Powered by Discuz! X3.5

© 2001-2023 Discuz! Team.

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