|
|
最近在工作看到机台有启动过程中把SPI ROM数据清空,但苦与没有办法很好的Debug(PCA没有架起来),所有与EDK为对象好好的读了一把。; C1 F. L0 P J- d: J1 c
2 E" @8 h- L! s. RSEC/CEI:- e' K( ^4 c6 y- Z2 U9 M
UEFI BIOS启动时先会执行SEC/CEI,这个阶段在实现的BIOS Code中初始化Debug Port,进入Big Mode,CPU的MicroCode,CacheToRAM的转换.然后跳转到PEI阶段。
) T/ P3 T- g6 _4 ^; z8 z在EDK中这部分被成了Load FvRecovery.fd文件,这个文件类似与我们的BIOS ROM.里面是我们编译后生成的二进制代码。在这个阶段最主要的是将这个文件加载到内存中(Windows API将文件加载到内存,看API函数).0 j! ^& W0 q, Z/ a
+ o: t, f4 }7 m9 S" H8 ^3 xPEI:1 B0 G9 @* J; u+ V5 L f& F6 H
从这里开始UEFI BIOS和EDK执行基本相同,只是一个是从SPI ROM中定位一个地址(PEIM的开始地址),一个是从内存中定位一个地址(PEIM的开始地址)。从这里开始只讲EDK的执行
% f2 X' j; n! _6 c& F! y: j EDK调用InitializeMemoryService函数,将HobList清空,peiservice清空。: F c7 G3 Y$ h% l x5 F
InitializePPIService函数,将PPI队列清空,这个队列长0x3F.
3 u# W e/ B" Q InitializeSercurityService函数,将Notify队列清空。* B( e6 O5 o1 d+ c4 j3 x
InitializeDispatcherData函数,将Dispatcher队列清空。4 }$ H( j! g9 y/ I7 X% D, T2 ]
接着由PeiBuildHobGuid来建立一个HOB(S3返回时这时应该有这个HOB,不用建立,直接使用了,这样就会进入另外一个流程,可以这个EDK不能调试S3,不知道怎么走)。然后由(*PeiServices)->InstallPpi()将这个新HOB加入到PPI中。
( q/ Y" }" I7 O 由于在SEC阶段转了以下这几具PPI,所以在执行PEI的Dispatcher之前会先安装东西:
& v4 {) I5 |, W: G; z EFI_PEI_PPI_DESCRIPTOR gPrivateDispatchTable[] = {
; ]; A. s( a# B" e2 l {EFI_PEI_PPI_DESCRIPTOR_PPI, &gEfiNtLoadAsDllPpiGuid, &mSecNtLoadAsDllPpi},0 Q0 v8 v( w+ X4 ^4 l- V
{EFI_PEI_PPI_DESCRIPTOR_PPI, &gNtPeiLoadFileGuid, &mSecNtLoadFilePpi},, S+ Z4 y+ w" p* {+ B
{EFI_PEI_PPI_DESCRIPTOR_PPI, &gPeiNtAutoScanPpiGuid, &mSecNtAutoScanPpi},0 C; \, y1 }6 T) T% j- K
{EFI_PEI_PPI_DESCRIPTOR_PPI, &gPeiNtThunkPpiGuid, &mSecWinNtThunkPpi},; [3 V8 e. x" G3 y: F
{EFI_PEI_PPI_DESCRIPTOR_PPI, &gPeiStatusCodePpiGuid, &mSecStatusCodePpi},5 N5 a% T; ?! T* x, e) k% {
{EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST, &gNtFwhPpiGuid, &mSecFwhInformationPpi}
( l+ R: r/ i" [$ }$ F2 N+ e% \ };
" m" i" h5 e( ?8 ^* g/ G 每个PPI是由{类型,GUID(名字,以后就根据这个来找到它的),Function_Entry_Address}组成。9 w( I: t4 R- _/ \. J' j- b
这些PPI会在PEIDispatcher中用到。
* l) N$ Y( z- l! K 安装完这此东西这开始执行PEIDispatcher函数,函数从BIOS ROM文件中找出PEI的Image(怎么找到,请读一下FV_HEAD(EFI_HEAD),里面讲到了如何区分Image类型),然后定位到PEI Image的入口地址,执行他。在我们的的PEI中,我们一般会申明一个PPI,这个就是这个PEI提供一些服务,PEIDispatcher会将他们加入到PPI-List中,以后其他Image也可以调用他的提供的功能。
* W3 L$ _, C# N 最后EDK会加载一个叫DXEIPL的PEI,DXEIPL提供一个PPI服务,这个PPI的功能是实现从PEI到DXE的切换,这个PPI里面为DXE做了很多的预准备,加载了很多PPI,如对BIOS的解压方法等。
( G) P) l3 H# g- `2 \$ n SwitchStacks ( c( f P8 g1 X' F9 k: Z* E) A: o
(VOID *) (UINTN) DxeCoreEntryPoint,- c+ {* v8 P6 h* Y% w5 g
(UINTN) (HobList.Raw),
8 G& S8 C: w1 z- d" o7 o4 G! H H (VOID *) (UINTN) TopOfStack,' Y# g. {. S3 T3 _& z" \$ H
(VOID *) (UINTN) BspStore
3 ~! \1 s) V1 l9 ~+ } );
7 z. d6 k/ b2 V, v0 ?% S0 k 用过汇编的人对这个技术一定很熟悉,不多说了(我别不清,咯。。。)
/ z3 s( d4 w9 t3 Q: X% D, ]7 q1 Q1 s. ^( {4 P, @( p% ~* ]+ n! y& q
DXE:$ C% Y6 _4 T* L" v0 t7 g3 O
从PEI到DXE切换时转过来一个HOBLIST参数,DXE会在这个HOB中找到Memory的使用情况,然后根据这些情况将BIOS引到内存(这是EFI的做法)。在EDK在DXE时重新定位一下内存。
$ ^- A6 S. j4 z' h9 ?! m接着就会定义我们经常使用到的gST表,gRT表。接着是申明一些Protocol(先不关心这些事)。+ m* k: o' U5 V5 f$ X F
等这些该加的PPI,Protocol加完了,CoreDispatcher()就出场了。他会的功能类似PEIDispatcher()。从我们BIOS ROM中将DXE的驱动读出,执行执行他们,这时会执行到Driver
" u2 e4 d {. v1 y6 A中的Support(),Start()两个功能函数。在这两个函数中你可以注册自己的PPI,为其他驱动提供服务。
/ h" ]/ N- s& X7 f+ @* ? 到些BIOS的引导其他完成。接着该进OS了,看Linux 0.11吧,操作系统是怎么做事情的。
7 B2 @. e4 u/ S+ s: |( i) [2 K' e
/ D, ]* B$ A% N( Y) P* G$ r3 PDriver:
. a0 f" A0 S. i( `$ V 我们的驱动什么为在PEI和DXE等不同阶段执行呢?& e7 m+ m; j' I. I& j4 r7 g
大家请看一下我们的驱动的makefile.(EDK中的*.inf), ^3 K6 M. v4 {9 D+ R9 ]6 t/ C& M
[defines]
5 d( P" u% w$ ]/ ~0 U BASE_NAME = OWEN
, k1 F% C( D1 A0 ]5 G$ c: }( d FILE_GUID = 1EDD13C1-62EF-4262-A1AA-0040D0830110: N: ?) P! p; w! J2 l$ G& H
COMPONENT_TYPE = BS_DRIVER, [7 t* |' ]1 E' S; N; s9 x5 \
8 u1 J8 V9 i: K* d& e) z5 z: r/ Z
BASE_NAME告诉编译器最终生成的驱动的名字。
6 @5 o; Y6 J; l1 X FILE_GUID就是这个驱动的GUID名字,在BIOS中引用某个驱动就是根据它来调用和识别。
/ d5 b4 W7 P# ?8 `8 Q% A COMONENT_TYPE会告诉编译器生成驱动的类型,是PEI,DXE,等。
* c2 g+ u6 L( b4 x 在EDK中有一个FWVolume.c实现的功能就是帮我们把这个TYPE转换面相应的扩展名' y! L% E! h. R' G/ @
COMP_TYPE_EXTENSION mCompTypeExtension[] = {
9 r$ f! V/ r. @" ^# B {"bs_driver", ".dxe" },5 {8 {& T! c% ^
{"rt_driver", ".dxe" },
& d% y" {0 V2 [$ ? {"sal_rt_driver", ".dxe"},: @* N% V$ L' U% M& y
{"security_core", ".sec"},8 [- m3 \) f9 ?
{"pei_core", ".pei"},
" i- E# t" \8 n/ ]7 B8 m {"pic_peim", ".pei"},6 a2 z F3 @* x& W) V: Z
{"pe32_peim", ".pei"}," G! C( H" V5 i5 w5 C7 h4 K
{"relocatable_peim", ".pei"},3 V+ ]. P. e4 Z- S) y/ z
{"binary", ".ffs"},
7 R6 f4 b- Q% W, }* L( C) W$ f4 K {"application", ".app"},8 ~0 |/ o: s+ w [$ t# F' ^$ S) D
{"file", ".ffs"},
. T: G! ]0 d% K* x T8 X {"fvimagefile", ".fvi"},# j& J9 a+ k( d& [' @% N
{"rawfile", ".raw"},' p" r/ M( r+ K4 Z
{"apriori", ".ffs"},
0 `- Z: ^$ h8 l6 e {"combined_peim_driver", ".pei"},& e+ ~' n7 Y1 d+ O4 Z; | k- Z
{ NULL, NULL }+ t" I, Y f. F6 X# I2 E. Z) Q; `
};
$ s7 S" V) b6 a* e
{: {0 M5 C5 t$ O/ _- N/ q! W* V了解了这些,接下我们可以看驱动篇了。(Go On Study... Forever)7 w# N5 K( n3 s, @1 y2 y
' E: E% I6 Z a, Q+ c' @
: k& D; o/ |* b W* j# B |
|