|
最近在工作看到机台有启动过程中把SPI ROM数据清空,但苦与没有办法很好的Debug(PCA没有架起来),所有与EDK为对象好好的读了一把。% p. k$ |# Q6 A0 a% \
0 q y$ a2 x4 f$ `4 K( _' WSEC/CEI:4 S1 M# x4 `/ B: I T5 ~
UEFI BIOS启动时先会执行SEC/CEI,这个阶段在实现的BIOS Code中初始化Debug Port,进入Big Mode,CPU的MicroCode,CacheToRAM的转换.然后跳转到PEI阶段。# S' S: j6 X8 m5 u2 ]" ]
在EDK中这部分被成了Load FvRecovery.fd文件,这个文件类似与我们的BIOS ROM.里面是我们编译后生成的二进制代码。在这个阶段最主要的是将这个文件加载到内存中(Windows API将文件加载到内存,看API函数).
- s' u8 K# h4 G
p* {: w- ^: I0 E2 }+ _' PPEI:& I) n( l; T, v9 k
从这里开始UEFI BIOS和EDK执行基本相同,只是一个是从SPI ROM中定位一个地址(PEIM的开始地址),一个是从内存中定位一个地址(PEIM的开始地址)。从这里开始只讲EDK的执行! f4 P# h, w8 E& D1 B
EDK调用InitializeMemoryService函数,将HobList清空,peiservice清空。
5 y3 I& H& j4 c; n InitializePPIService函数,将PPI队列清空,这个队列长0x3F.2 L5 \ H5 Q' J4 ]- E# j' z; h
InitializeSercurityService函数,将Notify队列清空。* [# p6 P9 E! \' `
InitializeDispatcherData函数,将Dispatcher队列清空。
+ Z4 z" `0 ]8 Y! W, | 接着由PeiBuildHobGuid来建立一个HOB(S3返回时这时应该有这个HOB,不用建立,直接使用了,这样就会进入另外一个流程,可以这个EDK不能调试S3,不知道怎么走)。然后由(*PeiServices)->InstallPpi()将这个新HOB加入到PPI中。
) X7 Z5 h* R# g. W& w: Z 由于在SEC阶段转了以下这几具PPI,所以在执行PEI的Dispatcher之前会先安装东西:
8 ?& D; k+ {1 K EFI_PEI_PPI_DESCRIPTOR gPrivateDispatchTable[] = {
. o1 K+ w2 r8 q+ [* {4 Q% Y0 D {EFI_PEI_PPI_DESCRIPTOR_PPI, &gEfiNtLoadAsDllPpiGuid, &mSecNtLoadAsDllPpi},
0 @8 M. I* D, b+ J. M {EFI_PEI_PPI_DESCRIPTOR_PPI, &gNtPeiLoadFileGuid, &mSecNtLoadFilePpi},! d" P3 d+ j% X5 @; |
{EFI_PEI_PPI_DESCRIPTOR_PPI, &gPeiNtAutoScanPpiGuid, &mSecNtAutoScanPpi},1 a; }8 H/ \7 r/ C4 h- ?* E) k% F
{EFI_PEI_PPI_DESCRIPTOR_PPI, &gPeiNtThunkPpiGuid, &mSecWinNtThunkPpi},
* Z X7 K7 m1 z5 r {EFI_PEI_PPI_DESCRIPTOR_PPI, &gPeiStatusCodePpiGuid, &mSecStatusCodePpi}, O! B" k9 w6 L6 L9 {. g
{EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST, &gNtFwhPpiGuid, &mSecFwhInformationPpi}4 E1 r5 F( L1 J
};
6 h7 k( Y4 K6 i$ y( j2 G- L z 每个PPI是由{类型,GUID(名字,以后就根据这个来找到它的),Function_Entry_Address}组成。
% l5 J% r: v* ]& d/ e 这些PPI会在PEIDispatcher中用到。
/ r: s* F. y$ f$ K 安装完这此东西这开始执行PEIDispatcher函数,函数从BIOS ROM文件中找出PEI的Image(怎么找到,请读一下FV_HEAD(EFI_HEAD),里面讲到了如何区分Image类型),然后定位到PEI Image的入口地址,执行他。在我们的的PEI中,我们一般会申明一个PPI,这个就是这个PEI提供一些服务,PEIDispatcher会将他们加入到PPI-List中,以后其他Image也可以调用他的提供的功能。
, _# D$ t* B! @3 Q' g7 o1 y4 ? 最后EDK会加载一个叫DXEIPL的PEI,DXEIPL提供一个PPI服务,这个PPI的功能是实现从PEI到DXE的切换,这个PPI里面为DXE做了很多的预准备,加载了很多PPI,如对BIOS的解压方法等。3 |- B$ u) Z, n; G& t: H+ `
SwitchStacks (( ~3 l2 y& N) X
(VOID *) (UINTN) DxeCoreEntryPoint,
' I3 l! r* X" C' ^$ ~( C) g; O (UINTN) (HobList.Raw),# t1 _% W+ c- S& j9 z/ o
(VOID *) (UINTN) TopOfStack,
0 C1 Z, m8 M- ]2 ^5 u) |8 ]2 y (VOID *) (UINTN) BspStore
* s: }8 \3 A' E. G |/ ` );
3 i; J8 s3 U) V& d6 j 用过汇编的人对这个技术一定很熟悉,不多说了(我别不清,咯。。。)5 u4 m- L( d, Z
4 l; g4 G0 c; g0 mDXE:
j- }/ P: R1 ^* M, r) G( r' l+ I 从PEI到DXE切换时转过来一个HOBLIST参数,DXE会在这个HOB中找到Memory的使用情况,然后根据这些情况将BIOS引到内存(这是EFI的做法)。在EDK在DXE时重新定位一下内存。/ W. {6 _' \1 R: m% t X1 `
接着就会定义我们经常使用到的gST表,gRT表。接着是申明一些Protocol(先不关心这些事)。
1 G) F0 D N/ w- J 等这些该加的PPI,Protocol加完了,CoreDispatcher()就出场了。他会的功能类似PEIDispatcher()。从我们BIOS ROM中将DXE的驱动读出,执行执行他们,这时会执行到Driver
) J A# l- Y& h( Q% J中的Support(),Start()两个功能函数。在这两个函数中你可以注册自己的PPI,为其他驱动提供服务。# A; y# U$ Z3 t |3 Y' e' U
到些BIOS的引导其他完成。接着该进OS了,看Linux 0.11吧,操作系统是怎么做事情的。
6 l2 u1 s& U) E6 o% J5 Z ) d1 \+ I$ ?5 ~/ I8 s; b" y
Driver:
6 S, m1 y! d3 ?9 u2 U( N 我们的驱动什么为在PEI和DXE等不同阶段执行呢?
6 ?- U0 e3 }& j; G3 {( K1 S' W 大家请看一下我们的驱动的makefile.(EDK中的*.inf)
% o( g9 i5 v7 l- G1 N0 N8 }8 Z: [ [defines]. i9 j" v4 Z" P5 l, T: W
BASE_NAME = OWEN8 ]( E4 S1 U# Q3 I
FILE_GUID = 1EDD13C1-62EF-4262-A1AA-0040D0830110, w3 I9 W5 G# \7 B( `; M2 E
COMPONENT_TYPE = BS_DRIVER
, S0 u% S+ C2 r0 {' o% _* J0 A+ O5 Z+ g3 p( {, X% v! O6 T% }, W/ g
BASE_NAME告诉编译器最终生成的驱动的名字。
, s3 g, q% S% n1 o0 E% R FILE_GUID就是这个驱动的GUID名字,在BIOS中引用某个驱动就是根据它来调用和识别。
* T( U' Y( V- e+ e, t& ^ COMONENT_TYPE会告诉编译器生成驱动的类型,是PEI,DXE,等。( X, K" L' s, o0 W1 ~" B2 N G6 v
在EDK中有一个FWVolume.c实现的功能就是帮我们把这个TYPE转换面相应的扩展名
1 f, w4 D$ u1 p, r; h- \7 N/ Q/ D COMP_TYPE_EXTENSION mCompTypeExtension[] = {
# j+ l5 {1 b# R- @: ? {"bs_driver", ".dxe" },' |: d' ~* s; q t( `; _: Q
{"rt_driver", ".dxe" },2 Y2 j4 U8 F( J" C) O6 \
{"sal_rt_driver", ".dxe"},7 X0 V6 F6 Y& P. [3 {5 S
{"security_core", ".sec"},# G* M! i& @3 f
{"pei_core", ".pei"},: p3 c# F+ Q8 j. Z* ]
{"pic_peim", ".pei"},2 P; a4 Q% T4 l$ ~* Z
{"pe32_peim", ".pei"},# T+ C8 d0 D/ o" n% H0 o* o: m
{"relocatable_peim", ".pei"},
- M+ n# K9 U9 A t* c6 M2 h {"binary", ".ffs"},# J# Y8 I6 x% x4 r/ N
{"application", ".app"},6 M. c3 j; [6 c4 A8 L) ~* C
{"file", ".ffs"},
- i, E+ @' H F O# D" v. h% m3 `6 ], F' E {"fvimagefile", ".fvi"}, r& J2 @7 B5 I1 j0 _6 q; S; e) a
{"rawfile", ".raw"},7 q4 {/ f9 C7 _
{"apriori", ".ffs"},$ g7 |. \7 C0 h% d% |* A
{"combined_peim_driver", ".pei"},
5 ^9 P0 v9 F1 |9 m" G" O { NULL, NULL }" W) k0 |1 B9 S- H V1 y
};4 W. {. k) Y8 A/ m! j
2 J X) l9 F7 u# J了解了这些,接下我们可以看驱动篇了。(Go On Study... Forever)5 F8 Y Z F2 E( }$ e
) K# \. t. s! b2 t1 t: E& d, H
5 a F. [( @9 O* Y |
|