|
最近在工作看到机台有启动过程中把SPI ROM数据清空,但苦与没有办法很好的Debug(PCA没有架起来),所有与EDK为对象好好的读了一把。
& W$ ~& p1 q8 X5 Z" H& v# F2 ~* _2 D Z
SEC/CEI:" {: o; P# ^7 x( f. E
UEFI BIOS启动时先会执行SEC/CEI,这个阶段在实现的BIOS Code中初始化Debug Port,进入Big Mode,CPU的MicroCode,CacheToRAM的转换.然后跳转到PEI阶段。
, b; {5 Z \' j7 c+ G在EDK中这部分被成了Load FvRecovery.fd文件,这个文件类似与我们的BIOS ROM.里面是我们编译后生成的二进制代码。在这个阶段最主要的是将这个文件加载到内存中(Windows API将文件加载到内存,看API函数).9 O2 B7 N. G6 c. J: x6 Q6 ] _6 ?
$ Y, h( ^0 J u8 _9 M) x1 R! Q H
PEI:! m6 J; U) o) f% x9 V: }4 w: V
从这里开始UEFI BIOS和EDK执行基本相同,只是一个是从SPI ROM中定位一个地址(PEIM的开始地址),一个是从内存中定位一个地址(PEIM的开始地址)。从这里开始只讲EDK的执行
) W2 g% @+ e' D' m% i5 q7 v EDK调用InitializeMemoryService函数,将HobList清空,peiservice清空。
" b R8 D) v: @4 D/ z. L% k InitializePPIService函数,将PPI队列清空,这个队列长0x3F.! [) Z3 Z5 ^9 _, C# b6 C, I
InitializeSercurityService函数,将Notify队列清空。
: ?# a6 H7 q$ }9 u. b InitializeDispatcherData函数,将Dispatcher队列清空。
$ _" t" X/ ]% e1 T) v 接着由PeiBuildHobGuid来建立一个HOB(S3返回时这时应该有这个HOB,不用建立,直接使用了,这样就会进入另外一个流程,可以这个EDK不能调试S3,不知道怎么走)。然后由(*PeiServices)->InstallPpi()将这个新HOB加入到PPI中。6 p% n; S6 V+ } O( o; G+ p
由于在SEC阶段转了以下这几具PPI,所以在执行PEI的Dispatcher之前会先安装东西:
: o* ?9 z. i' I/ r8 j9 d V! D. F EFI_PEI_PPI_DESCRIPTOR gPrivateDispatchTable[] = {( N1 {+ i0 t6 m) e ~2 J
{EFI_PEI_PPI_DESCRIPTOR_PPI, &gEfiNtLoadAsDllPpiGuid, &mSecNtLoadAsDllPpi}," t- w' w4 B7 W3 o* Y' ?4 c
{EFI_PEI_PPI_DESCRIPTOR_PPI, &gNtPeiLoadFileGuid, &mSecNtLoadFilePpi},
2 [' l; f; T V; H {EFI_PEI_PPI_DESCRIPTOR_PPI, &gPeiNtAutoScanPpiGuid, &mSecNtAutoScanPpi},7 T: W: z! H; e% n- Z [6 e
{EFI_PEI_PPI_DESCRIPTOR_PPI, &gPeiNtThunkPpiGuid, &mSecWinNtThunkPpi},3 i) U; n0 c4 y6 M* [
{EFI_PEI_PPI_DESCRIPTOR_PPI, &gPeiStatusCodePpiGuid, &mSecStatusCodePpi},
8 a' i q- I% U- }/ N: R J# w {EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST, &gNtFwhPpiGuid, &mSecFwhInformationPpi}
. p' A1 g3 B+ h1 J! D) D };* O0 @9 D$ a7 U' y$ r
每个PPI是由{类型,GUID(名字,以后就根据这个来找到它的),Function_Entry_Address}组成。1 x1 c& |: L! h w5 O! u
这些PPI会在PEIDispatcher中用到。! ^# I3 c4 L6 v# _
安装完这此东西这开始执行PEIDispatcher函数,函数从BIOS ROM文件中找出PEI的Image(怎么找到,请读一下FV_HEAD(EFI_HEAD),里面讲到了如何区分Image类型),然后定位到PEI Image的入口地址,执行他。在我们的的PEI中,我们一般会申明一个PPI,这个就是这个PEI提供一些服务,PEIDispatcher会将他们加入到PPI-List中,以后其他Image也可以调用他的提供的功能。
( s) ]' j& s& W$ z* K* V1 K 最后EDK会加载一个叫DXEIPL的PEI,DXEIPL提供一个PPI服务,这个PPI的功能是实现从PEI到DXE的切换,这个PPI里面为DXE做了很多的预准备,加载了很多PPI,如对BIOS的解压方法等。
* X; ~* f* `1 d) K& c SwitchStacks () D7 k. n$ O* @+ I4 J. e9 m
(VOID *) (UINTN) DxeCoreEntryPoint,
* e ]0 s7 b5 Y& h8 P [$ u (UINTN) (HobList.Raw),8 U/ k" z( m( h+ ]
(VOID *) (UINTN) TopOfStack,
y8 K; u9 p( k8 k6 ^/ K (VOID *) (UINTN) BspStore& c7 G) N8 h$ O+ V0 b8 d
);
4 n0 c9 D+ L4 X- F% d; |- O 用过汇编的人对这个技术一定很熟悉,不多说了(我别不清,咯。。。)% E! _ r5 y& M! w
9 T; L& o0 T9 H7 Z, v. t$ D* }DXE:
7 Z: k: M) X. K; V0 _ 从PEI到DXE切换时转过来一个HOBLIST参数,DXE会在这个HOB中找到Memory的使用情况,然后根据这些情况将BIOS引到内存(这是EFI的做法)。在EDK在DXE时重新定位一下内存。
U9 c! ~( J X" S. V, I6 E接着就会定义我们经常使用到的gST表,gRT表。接着是申明一些Protocol(先不关心这些事)。& G6 @ R1 J# x) Z1 r+ R% Z
等这些该加的PPI,Protocol加完了,CoreDispatcher()就出场了。他会的功能类似PEIDispatcher()。从我们BIOS ROM中将DXE的驱动读出,执行执行他们,这时会执行到Driver7 l/ R: x4 ]% A0 b4 E' L5 F* \( Q
中的Support(),Start()两个功能函数。在这两个函数中你可以注册自己的PPI,为其他驱动提供服务。% }/ Z+ G& E3 h6 y X
到些BIOS的引导其他完成。接着该进OS了,看Linux 0.11吧,操作系统是怎么做事情的。/ d- x5 {9 v% P! d) A/ g7 `
5 i. C8 h5 g' Z; b) P
Driver:
g: b, Z6 X. c/ n 我们的驱动什么为在PEI和DXE等不同阶段执行呢?
+ I% N% e: @% `7 z 大家请看一下我们的驱动的makefile.(EDK中的*.inf)
* U8 M7 l0 e2 F$ ~; ?% E) Q [defines]& L( Q' p9 f; n
BASE_NAME = OWEN# w+ ^6 ^4 X0 J* ~+ v
FILE_GUID = 1EDD13C1-62EF-4262-A1AA-0040D0830110
8 A) f4 P& q* V& H COMPONENT_TYPE = BS_DRIVER d( ^* C7 ~' y, v* Z# D9 X
+ r+ c8 g! b& s1 a3 d M BASE_NAME告诉编译器最终生成的驱动的名字。9 x* Q- c9 r6 i& {+ z
FILE_GUID就是这个驱动的GUID名字,在BIOS中引用某个驱动就是根据它来调用和识别。; d: U9 t: J* Q5 G
COMONENT_TYPE会告诉编译器生成驱动的类型,是PEI,DXE,等。
+ }" H% i4 w; y( N. `' p/ r! a' B 在EDK中有一个FWVolume.c实现的功能就是帮我们把这个TYPE转换面相应的扩展名7 S. K( D0 W: i2 ~% ]- y
COMP_TYPE_EXTENSION mCompTypeExtension[] = {
( }/ N% s3 q/ i5 |7 F) h" y {"bs_driver", ".dxe" },, N3 C0 r" L9 R7 k7 G) d: C) H. k
{"rt_driver", ".dxe" }, \/ p. C5 N* ~! t8 F% e
{"sal_rt_driver", ".dxe"},: Y U- e, r f9 D# u$ h: m+ F
{"security_core", ".sec"},
: j. Y7 j) T& v0 d' ] {"pei_core", ".pei"},$ [$ `1 o: K% O$ I
{"pic_peim", ".pei"},+ V1 R/ l- |, L% A
{"pe32_peim", ".pei"},3 Y! A. ]% y# ^( i! C* E
{"relocatable_peim", ".pei"},# n# J! l# T. C" Q# P
{"binary", ".ffs"},
4 M% ?+ [/ o4 v d! q {"application", ".app"},
; W/ u2 m2 w% i {"file", ".ffs"},
/ v1 `) _1 s- x' [1 v6 j8 b {"fvimagefile", ".fvi"},' s" u$ o j+ o+ w
{"rawfile", ".raw"},+ M( P( E8 L4 e5 j& m. R/ q
{"apriori", ".ffs"},) C! h. W! k+ M; w, H
{"combined_peim_driver", ".pei"},; j1 l0 P3 Z+ b) c8 D3 W
{ NULL, NULL }. a. A$ r' H$ X
};# G% k4 ^( F! u1 S0 b* g
( _& U2 k- J5 T4 Q7 o5 Q+ Q了解了这些,接下我们可以看驱动篇了。(Go On Study... Forever), R U( m% G- Y& y, ~9 `" T$ f
" r: T) i3 P7 l3 H# q, C( ~
# j1 [; Z: h4 _+ ^ |
|