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

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

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

* m5 {) u% p' D* j" \3 r/ h" MSEC/CEI:; U. H0 Z% U9 T0 H
  UEFI BIOS启动时先会执行SEC/CEI,这个阶段在实现的BIOS Code中初始化Debug Port,进入Big Mode,CPU的MicroCode,CacheToRAM的转换.然后跳转到PEI阶段。% m0 a2 I, a  f# g) t
在EDK中这部分被成了Load FvRecovery.fd文件,这个文件类似与我们的BIOS ROM.里面是我们编译后生成的二进制代码。在这个阶段最主要的是将这个文件加载到内存中(Windows API将文件加载到内存,看API函数).7 H" r1 k0 T6 c) S  g: s
6 _' s1 N1 A3 M+ w' K+ @& q; O- \
PEI:5 V. S9 A0 ~* q# o$ [* U( s! T
   从这里开始UEFI BIOS和EDK执行基本相同,只是一个是从SPI ROM中定位一个地址(PEIM的开始地址),一个是从内存中定位一个地址(PEIM的开始地址)。从这里开始只讲EDK的执行8 _! A/ L4 z/ f2 \2 Q7 \( ]
  EDK调用InitializeMemoryService函数,将HobList清空,peiservice清空。
1 @: Y+ L  D8 R5 r, j+ W      InitializePPIService函数,将PPI队列清空,这个队列长0x3F.
2 ]% a0 V3 _& V9 Q% p2 R          InitializeSercurityService函数,将Notify队列清空。4 t- L2 a, U. ^( y# _! X8 n0 S
          InitializeDispatcherData函数,将Dispatcher队列清空。
$ E5 f( G, R1 O; n; @  接着由PeiBuildHobGuid来建立一个HOB(S3返回时这时应该有这个HOB,不用建立,直接使用了,这样就会进入另外一个流程,可以这个EDK不能调试S3,不知道怎么走)。然后由(*PeiServices)->InstallPpi()将这个新HOB加入到PPI中。
0 X6 W4 D& F  R' |    由于在SEC阶段转了以下这几具PPI,所以在执行PEI的Dispatcher之前会先安装东西:2 I8 n  j; D* A( J! K" w8 _1 J
      EFI_PEI_PPI_DESCRIPTOR    gPrivateDispatchTable[] = {4 [2 L4 e2 u- j9 T, t
       {EFI_PEI_PPI_DESCRIPTOR_PPI, &gEfiNtLoadAsDllPpiGuid, &mSecNtLoadAsDllPpi},
/ \8 ]& T# X, J! Y4 E# i9 r& b       {EFI_PEI_PPI_DESCRIPTOR_PPI, &gNtPeiLoadFileGuid, &mSecNtLoadFilePpi},
; _# m( J0 @$ b       {EFI_PEI_PPI_DESCRIPTOR_PPI, &gPeiNtAutoScanPpiGuid, &mSecNtAutoScanPpi},
3 _4 H# A" u: d       {EFI_PEI_PPI_DESCRIPTOR_PPI, &gPeiNtThunkPpiGuid, &mSecWinNtThunkPpi},
" |) z: b0 M% l( l6 y       {EFI_PEI_PPI_DESCRIPTOR_PPI, &gPeiStatusCodePpiGuid, &mSecStatusCodePpi},
: O" x6 G, [) S4 A       {EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST, &gNtFwhPpiGuid, &mSecFwhInformationPpi}" g+ w% _* R" X) S) g" F  o
     };
; Y* O4 q9 _. }9 ]    每个PPI是由{类型,GUID(名字,以后就根据这个来找到它的),Function_Entry_Address}组成。
- |7 N4 S. T5 n# W6 p, j7 _   这些PPI会在PEIDispatcher中用到。
) m5 H% ]: p+ M   安装完这此东西这开始执行PEIDispatcher函数,函数从BIOS ROM文件中找出PEI的Image(怎么找到,请读一下FV_HEAD(EFI_HEAD),里面讲到了如何区分Image类型),然后定位到PEI Image的入口地址,执行他。在我们的的PEI中,我们一般会申明一个PPI,这个就是这个PEI提供一些服务,PEIDispatcher会将他们加入到PPI-List中,以后其他Image也可以调用他的提供的功能。/ ], L1 t! p* ~9 I9 ^- C
   最后EDK会加载一个叫DXEIPL的PEI,DXEIPL提供一个PPI服务,这个PPI的功能是实现从PEI到DXE的切换,这个PPI里面为DXE做了很多的预准备,加载了很多PPI,如对BIOS的解压方法等。
9 X( |$ L1 B8 B/ s   SwitchStacks (% p  _( I% n, n6 Y) q% |
       (VOID *) (UINTN) DxeCoreEntryPoint,
0 C2 G# }& h4 ], y: A' X( H5 h       (UINTN) (HobList.Raw),
0 K! _* Z; n* B0 p7 w       (VOID *) (UINTN) TopOfStack,; A- |1 g/ ?8 v( h" T' I9 n' Y
       (VOID *) (UINTN) BspStore# ^' E: v5 {$ o3 D/ z, Q: G8 c
    );% [+ R( Q$ h: q! [
  用过汇编的人对这个技术一定很熟悉,不多说了(我别不清,咯。。。): u' O% a3 j$ c/ i

( I/ B0 O& i/ R& q# FDXE:
. E! W" _0 S+ \2 D- R- z     从PEI到DXE切换时转过来一个HOBLIST参数,DXE会在这个HOB中找到Memory的使用情况,然后根据这些情况将BIOS引到内存(这是EFI的做法)。在EDK在DXE时重新定位一下内存。
7 w" ^% ]$ Y" d3 b接着就会定义我们经常使用到的gST表,gRT表。接着是申明一些Protocol(先不关心这些事)。
& Q3 _2 G, t" u9 x   等这些该加的PPI,Protocol加完了,CoreDispatcher()就出场了。他会的功能类似PEIDispatcher()。从我们BIOS ROM中将DXE的驱动读出,执行执行他们,这时会执行到Driver8 M' m1 T  _' X/ K. K
中的Support(),Start()两个功能函数。在这两个函数中你可以注册自己的PPI,为其他驱动提供服务。
' @6 X# T' b8 \% e: u, _" E# U   到些BIOS的引导其他完成。接着该进OS了,看Linux 0.11吧,操作系统是怎么做事情的。4 F: H% u3 c( o; j0 n, S
   , t$ W3 i* m- k0 G3 g
Driver:
8 x2 f% u+ R' R. b2 _; g$ Y    我们的驱动什么为在PEI和DXE等不同阶段执行呢?
. T3 V" J# q- O  大家请看一下我们的驱动的makefile.(EDK中的*.inf)
) C# Z) Q! o( a! o* h  [defines]  a4 h4 j7 ]) j; ^( ?- U
  BASE_NAME            = OWEN0 {, G+ c- A1 [
  FILE_GUID            = 1EDD13C1-62EF-4262-A1AA-0040D0830110
6 H; V1 }  A& ^2 e( |( `  COMPONENT_TYPE       = BS_DRIVER
8 [" V# [7 O6 i! ]& R
4 _5 l- f! K+ c8 j  BASE_NAME告诉编译器最终生成的驱动的名字。% p" z- _; O/ S7 y
  FILE_GUID就是这个驱动的GUID名字,在BIOS中引用某个驱动就是根据它来调用和识别。  H1 ^" m0 d) \9 ]1 w- m
  COMONENT_TYPE会告诉编译器生成驱动的类型,是PEI,DXE,等。( B: u! q9 ^" |; i/ l/ @2 j7 _
  在EDK中有一个FWVolume.c实现的功能就是帮我们把这个TYPE转换面相应的扩展名( q% t8 \+ W8 G/ p/ D
  COMP_TYPE_EXTENSION  mCompTypeExtension[] = {
( Y% h1 a! |5 N% x  {"bs_driver",  ".dxe" }," d# h8 T2 W7 q8 `' J, }# e* G
  {"rt_driver",  ".dxe" },
+ [" T$ Y/ L4 u4 G  {"sal_rt_driver", ".dxe"},
2 C6 E: t4 |. L9 f( S2 K  {"security_core", ".sec"},% R$ |' u4 q! C9 Y5 g
  {"pei_core", ".pei"},
7 M  J5 B; }8 L& \7 G, y  {"pic_peim", ".pei"},4 R- F. c4 i) r  h
  {"pe32_peim", ".pei"},* o  `# t  f5 O& ~# s( U
  {"relocatable_peim", ".pei"},
4 S2 U& c, A2 ]* N0 T/ y  {"binary", ".ffs"},- @* V( V: ]0 u' e/ h
  {"application", ".app"},* ?2 d& O3 z- q  M* ^- w; u; R: V
  {"file", ".ffs"},! ~7 W8 @3 w- G$ n- ^
  {"fvimagefile", ".fvi"},
6 m* {4 f) H! a, c; I6 o  {"rawfile", ".raw"},
* c6 z& P4 R3 j% o$ \9 b  {"apriori", ".ffs"},
0 L6 N) Q% A, f  {"combined_peim_driver", ".pei"},
1 Q7 I0 A! A: ^7 s7 r  { NULL,  NULL }
5 a  E4 y  T+ B8 m$ Z! k};
4 V* U* a* }  x" c% Q/ Z8 z  ]/ |0 O: F: L# m
了解了这些,接下我们可以看驱动篇了。(Go On Study... Forever)
, W- I/ A1 S" x( Q- a( e   ; l& T: O9 A. }+ I5 d. h
         
* M* I1 f; o0 U. \$ d4 t  
发表于 2008-7-27 12:30:15 | 显示全部楼层
不错!1 C/ G, A1 |: i2 Y' F; i. j2 L
支持
9 l1 @( p7 n# x, \继续/ X1 e% p$ G4 {, R
加油' H3 y1 q; X  p4 t- I
回复

使用道具 举报

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

回复 1# 的帖子

gPrivateDispatchTable 和COMP_TYPE_EXTENSION  没有搜到啊  是EDK专有的么?2 y6 s! _) t/ v7 a: W0 \. T
有看过跟gPrivateDispatchTable 类似的,但是里面的PPI不同。- ]4 f7 j7 d  ~" S* T% E6 x
还有这个COMP_TYPE_EXTENSION  没有找到过。FWVolume.c这个文件也没有发现。。
回复

使用道具 举报

发表于 2008-7-28 13:24:20 | 显示全部楼层
这东西虽说没有什么技术含量,但是总结一下还是非常好的。7 C& o' W% E5 T' o1 P0 e8 Y
. I. ?, a4 L; ~9 L. i% }' P/ K
支持!
回复

使用道具 举报

 楼主| 发表于 2008-7-28 18:52:31 | 显示全部楼层
" L4 Z5 S# L$ _) y3 M
小弟还在学习阶段,目前的目标是知道执行的流程。9 j9 p  a; J2 g' P
这里面有很多细节没有写,能力有限,只能自己知道,不能表达。3 p+ z* y- a9 \; e! V
嘿。。。。
; I3 I% L7 B0 W3 l$ P8 M* }: e所有大侠们如果有好东西能给小弟共享一份。* K/ r1 `7 Z' z$ O

# X6 [8 s/ s9 m, e+ O7 p& n0 S谢谢!
回复

使用道具 举报

发表于 2008-8-12 14:44:11 | 显示全部楼层
原帖由 winbondowen 于 2008-7-27 00:11 发表 1 |) c! D! ~$ A% L
  ROM中將DXE的驅動讀出,執行執行他們,這時會執行到Driver
5 p1 Y$ w  `0 Q% m! G中的Support(),Start()兩個功能函數。在這兩個函數中你可以註冊自己的PPI ...
8 C# c% j4 _5 d6 U( G

4 u  w% L) C  m+ Q( GPPIs are registered during PEI phase, but Support()/Start() are invoked in DXE driver binding protocol,
  ]  W1 U/ A9 TFor more precisely, I think the "PPI" you mentioned is the "PROTOCOL" rather than "PPI".
4 p% ^4 s2 H7 v# Q1 e4 I( a; z
# L& M9 Q. a6 D2 s8 f[ 本帖最后由 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 M& I. J' Y+ N4 {
   Yes. I make a mistake.. d/ O1 t9 t0 p1 K7 T
      PPI:     A PEIM to PEIM interface.# Y  M# r+ w, B. K9 w2 ~/ c) @) t
      PROTOCL: A Interface between Hardware(or firmware) and software.
$ q. G7 W5 P3 S8 w) Y1 {      reference[http://www.biosren.com/viewthread.php?tid=207]
9 R) k$ t6 A" E4 E1 q( l   so, PPI execute at PEI step and Initialize hardware. PROTOCOL execute by DXE step.& k+ I. ]. ?# L% O; D( E$ {  E
   Thanks.
回复

使用道具 举报

发表于 2008-8-20 17:47:21 | 显示全部楼层
原帖由 winbondowen 于 2008-7-27 00:11 发表 DXE:8 x" u" L4 x2 X& z5 Q7 x
     從PEI到DXE切換時轉過來一個HOBLIST參數,DXE會在這個HOB中找到Memory的使用情況,然後根據這些情況將BIOS引到內存(這是EFI的做法)。在EDK在DXE時重新定位一下內存。- o4 {7 J/ }) Z: [% U
接著就會定義我們經常使用到的gST表,gRT表。接著是申明一些Protocol(先不關心這些事)。' v% E0 J) x7 r: Y& L$ e
   等這些該加的PPI,Protocol加完了,CoreDispatcher()就出場了。他會的功能類似PEIDispatcher()。從我們BIOS ROM中將DXE的驅動讀出,執行執行他們,這時會執行到Driver. Y& S  A7 {) g. W) R& J# V* b
中的Support(),Start()兩個功能函數。在這兩個函數中你可以註冊自己的PPI,為其他驅動提供服務。
6 h9 E' R8 H$ q5 H1 N- W   到些BIOS的引導其他完成。接著該進OS了,看Linux 0.11吧,操作系統是怎麼做事情的。.
* C. k  [- Y- |7 Z

: j# u8 ]8 m/ S  h! @There are mistakes,
2 {5 w4 v5 s+ m0 }7 C5 N$ _5 p1.gST and gRT are init after the DXE architectural protocols have been loaded, those protocols response for creating Dxe foundation.
. o. m* }# p) ?  |
- J: G8 t# f9 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.
1 e5 ~! h% M2 N' q( Y$ g7 iThe CoreDispatcher() executes all trusted Dxe drivers and just register the Binding protocol if the driver is EFI1.1 driver model./ N6 O- o; D& ?1 z. s
Furthermore, Support()/Start() are invoked in BDS phase over the CoreConnectController() rather than CoreDispatcher().2 l9 O+ t5 |% o; F* j& ^
' X; n# r2 Z  }- l/ S; i8 a* L
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 大侠的指点。
& w' @  n2 X) Z# Y1 j! b% ^
回复

使用道具 举报

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

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

原帖由 ichirohiro 于 2008-8-20 17:47 发表
% F' w1 Y1 l  \" ?$ a...! w% i% ^1 h/ y9 v0 ?" ^: Z
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.
- g3 Y) Q& r# y" I4 u1 `; dThe CoreDispatcher() executes all trusted Dxe drivers and just register the Binding protocol if the driver is EFI1.1 driver model.
- H: R) Q# {2 M' O4 w4 rFurthermore, Support()/Start() are invoked in BDS phase over the CoreConnectController() rather than CoreDispatcher().
3 L+ M5 p& S& W6 q5 k% g$ {
    在Framework的spec DxeCis.pdf里面也是这么说的,DXE CoreDispatcher()里面,对于EFI1.1 driver model的driver只会安装Handler和Interface到Binding protocol,到BDS才会去执行Support()和Start().
$ }% D- M) t& l. Q    但是,我在看code时,发现在CoreDispatcher()-->CoreStartImage()里面call image之后有这么一句:  (file:image.c)) b- k5 _! M/ V+ C; D# F% ]
  //6 y9 [5 d+ a! k: d& u
  // Go connect any handles that were created or modified while the image executed.# i$ x  d/ q( G5 r. T
  //" y  u2 g- `- L% E3 }6 ?( n
  CoreConnectHandlesByKey (HandleDatabaseKey);
/ W6 f3 N+ l& f& N7 {, ]( j  R& r
这里的HandleDatabaseKey是call image之前由CoreGetHandleDatabaseKey()得到的gHandleDatabaseKey
* \2 {  l9 @# |) Q+ b4 t而CoreConnectHandlesByKey会调用到:
% }  ~4 ~' H, Z0 S# z  //4 j& w, B) E; ?. g. l" x) `/ U3 ^' l
  // Connect all handles whose Key value is greater than Key
/ E& s2 V8 b. D2 ?; Z  //8 J3 E) L) f, o# h
  for (Index = 0; Index < Count; Index++) {9 \* K. ?, c* G+ G( J
    CoreConnectController (HandleBuffer[Index], NULL, NULL, TRUE);4 |9 C% d$ t' e
  }

6 x) h5 ]: k% S# u( a" o' ^所以,照code看,当在Driver中安装一个Handle和Interface到Binding Protocol后(gHandleDatabaseKey会++,IHandle的Key=gHandleDatabaseKey)2 n0 Y4 i% E/ M2 F, ?# X
是会去ConnectController的,也会执行对应的Support()和Start()才对!!2 Q3 w% f$ H- i" W, n

- n" m) ~: o) n9 L不知道我想的哪里有问题???欢迎大家指正.; r+ Q$ m8 X5 B; E7 A
) i, @3 S7 n1 ]
[ 本帖最后由 xtdumpling 于 2008-9-18 15:25 编辑 ]
回复

使用道具 举报

发表于 2008-9-19 14:44:41 | 显示全部楼层
这段code似乎是一个向后兼容的行为,不必太care。! N% q+ K2 f5 ?. O0 t
一个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 | 显示全部楼层
了解了.! f7 @" Z* N0 S; U
非常 感谢!!!
回复

使用道具 举报

发表于 2008-9-23 16:48:56 | 显示全部楼层
在读DXEmain时,4 g. S* i" h! X# o( V
Status = CoreInitializeImageServices(HobStart);--->CoreInstallProtocolInterface();--->CoreInstallProtocolInterfaceNotify();中,
) e8 b7 L; i' x8 D% R! J8 |: n8 S* M//
- u! T6 X, _; B# I6 c// Notify the notification list for this protocol.
) H" {, f3 w1 F6 C# l//! Z! c% s% @$ ~+ S
if (Notify) {
1 N0 L4 ]7 {2 [! \  c! v  CoreNotifyProtocolEntry(ProtEntry);
& d7 l; C  V3 G; J# k' {' y$ {}    里Signal了Event. MS是说一个handle安装了一个protocol后就signal一次.
9 C6 z8 j& d& ~$ J6 `& [有个问题请教一下大家: 这段是在DXE很靠前的位置执行的,但是在它之前我没有看到DXE中有相关的CreateEvent出现?哪位高手能说说这部分代码的流程呢?
回复

使用道具 举报

发表于 2008-9-23 17:04:14 | 显示全部楼层
原帖由 xtdumpling 于 2008-9-16 13:34 发表 + L  F/ U( W( q2 J: [
请楼上的兄弟分析下BS的RegisterProtocolNotify也就是CoreRegisterProtocolNotify是做什么用的?怎么用?- R7 h8 `9 d1 c0 e" a! P6 ]- @* Z
谢谢!

* d% K$ ]% d3 c8 L+ \- l$ ^% e......4 ?1 p' y& p2 ]6 R+ t( R" j5 t

, f" k+ N) N  v' D8 K& \9 v. E/ l
[ 本帖最后由 xtdumpling 于 2008-9-23 17:24 编辑 ]
回复

使用道具 举报

发表于 2008-9-24 12:43:45 | 显示全部楼层
原帖由 xtdumpling 于 2008-9-23 17:04 发表
0 g$ _7 G, V1 Z. w
$ Y1 \3 M( ^* t4 |% t. m....... @% P. \3 C3 o) H' L* k4 y

+ }" j. y8 p! ~. SSignal的Event是不是在各个TPL级上挂载一些待处理的事件,一旦restore(TPL)的话,比当前TPL级高的pending事件就回被处理掉?
/ d$ |+ a. e: K  F如果是这样的话,Timer事件是如何处理的呢,没有找到相关的代码呀?Xt指点一下再~
回复

使用道具 举报

发表于 2008-9-24 19:00:46 | 显示全部楼层
Timer是挂在8259的IRQ0的中断处理程序上面的, 大概每秒18.3次调用CoreTimerTick()-->CoreCheckTimers()5 M4 C) q7 \3 x/ s, m2 k
TPL=30
回复

使用道具 举报

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

本版积分规则

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

GMT+8, 2025-5-2 10:38 , Processed in 0.030887 second(s), 17 queries .

Powered by Discuz! X3.5

© 2001-2023 Discuz! Team.

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