|
|
最近在工作看到机台有启动过程中把SPI ROM数据清空,但苦与没有办法很好的Debug(PCA没有架起来),所有与EDK为对象好好的读了一把。* E1 G9 [& h7 p5 W) v3 S
; i5 y$ Z" v( \* l2 o( W& TSEC/CEI:; g% a/ M- o+ Q* y S* X8 e
UEFI BIOS启动时先会执行SEC/CEI,这个阶段在实现的BIOS Code中初始化Debug Port,进入Big Mode,CPU的MicroCode,CacheToRAM的转换.然后跳转到PEI阶段。
- \9 x$ |1 X) M( X在EDK中这部分被成了Load FvRecovery.fd文件,这个文件类似与我们的BIOS ROM.里面是我们编译后生成的二进制代码。在这个阶段最主要的是将这个文件加载到内存中(Windows API将文件加载到内存,看API函数).- w1 w+ w$ o- \3 b" n/ N
) o5 i5 ^7 w! U4 Y: E' o: c: BPEI:
9 M9 O# b4 v+ o3 N* w2 u 从这里开始UEFI BIOS和EDK执行基本相同,只是一个是从SPI ROM中定位一个地址(PEIM的开始地址),一个是从内存中定位一个地址(PEIM的开始地址)。从这里开始只讲EDK的执行
: r+ y6 w( o5 P) N) [* x EDK调用InitializeMemoryService函数,将HobList清空,peiservice清空。
1 y' H; ?2 f& X& h7 ~+ O% z InitializePPIService函数,将PPI队列清空,这个队列长0x3F.
2 f9 F7 V9 H' X InitializeSercurityService函数,将Notify队列清空。. c9 A9 B7 Z& x- {
InitializeDispatcherData函数,将Dispatcher队列清空。3 m* G1 L) @' j. G0 P# _8 l6 K
接着由PeiBuildHobGuid来建立一个HOB(S3返回时这时应该有这个HOB,不用建立,直接使用了,这样就会进入另外一个流程,可以这个EDK不能调试S3,不知道怎么走)。然后由(*PeiServices)->InstallPpi()将这个新HOB加入到PPI中。
4 N7 _8 x, {' F5 B4 a- m 由于在SEC阶段转了以下这几具PPI,所以在执行PEI的Dispatcher之前会先安装东西:$ O0 `1 S, H* Q( W
EFI_PEI_PPI_DESCRIPTOR gPrivateDispatchTable[] = {/ i5 \5 L6 e5 ^
{EFI_PEI_PPI_DESCRIPTOR_PPI, &gEfiNtLoadAsDllPpiGuid, &mSecNtLoadAsDllPpi},
: T6 p# N4 A& d. R& G4 ^( _. U {EFI_PEI_PPI_DESCRIPTOR_PPI, &gNtPeiLoadFileGuid, &mSecNtLoadFilePpi},( ]) W- O: \# ^, W, j: d k
{EFI_PEI_PPI_DESCRIPTOR_PPI, &gPeiNtAutoScanPpiGuid, &mSecNtAutoScanPpi},
5 W2 S9 O \; b5 ^- F {EFI_PEI_PPI_DESCRIPTOR_PPI, &gPeiNtThunkPpiGuid, &mSecWinNtThunkPpi},
6 @5 e& K$ p6 T7 g& W8 Z6 Y& g9 I$ t, ] {EFI_PEI_PPI_DESCRIPTOR_PPI, &gPeiStatusCodePpiGuid, &mSecStatusCodePpi},
& k1 ^2 f/ U+ j, M* o {EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST, &gNtFwhPpiGuid, &mSecFwhInformationPpi}
3 J. K5 {+ N" z' ]: |% { };2 O3 {. p! S7 {' s, }
每个PPI是由{类型,GUID(名字,以后就根据这个来找到它的),Function_Entry_Address}组成。1 z. S U' p) L9 Q1 L+ a3 Q" x# i5 i: e
这些PPI会在PEIDispatcher中用到。9 ~% Z- d7 q( {& {) E
安装完这此东西这开始执行PEIDispatcher函数,函数从BIOS ROM文件中找出PEI的Image(怎么找到,请读一下FV_HEAD(EFI_HEAD),里面讲到了如何区分Image类型),然后定位到PEI Image的入口地址,执行他。在我们的的PEI中,我们一般会申明一个PPI,这个就是这个PEI提供一些服务,PEIDispatcher会将他们加入到PPI-List中,以后其他Image也可以调用他的提供的功能。& n2 p- I6 V- }8 g
最后EDK会加载一个叫DXEIPL的PEI,DXEIPL提供一个PPI服务,这个PPI的功能是实现从PEI到DXE的切换,这个PPI里面为DXE做了很多的预准备,加载了很多PPI,如对BIOS的解压方法等。
7 p. T) v! x/ i" T4 m" q SwitchStacks (. D; ~* a1 v0 [4 E/ _
(VOID *) (UINTN) DxeCoreEntryPoint,
4 o2 y! u: j: w (UINTN) (HobList.Raw),9 A4 u6 D9 ^* Z1 W4 E) J
(VOID *) (UINTN) TopOfStack,
# w& z( a8 S( O (VOID *) (UINTN) BspStore: Y7 _1 C4 W' ?8 ^
);
( f: Y$ m O* M/ {: U, |$ m, o 用过汇编的人对这个技术一定很熟悉,不多说了(我别不清,咯。。。)
' L! t k8 r8 {# z6 {2 O4 w( C# b8 f& D
DXE:
$ T0 w L$ _) U. J- R 从PEI到DXE切换时转过来一个HOBLIST参数,DXE会在这个HOB中找到Memory的使用情况,然后根据这些情况将BIOS引到内存(这是EFI的做法)。在EDK在DXE时重新定位一下内存。; ^! ~8 Q) |" i3 |, a7 o
接着就会定义我们经常使用到的gST表,gRT表。接着是申明一些Protocol(先不关心这些事)。3 s+ E0 e. l5 Z) D: F6 ]
等这些该加的PPI,Protocol加完了,CoreDispatcher()就出场了。他会的功能类似PEIDispatcher()。从我们BIOS ROM中将DXE的驱动读出,执行执行他们,这时会执行到Driver. d7 d( f6 X' Z4 [& d5 O/ Y+ h# o2 ~
中的Support(),Start()两个功能函数。在这两个函数中你可以注册自己的PPI,为其他驱动提供服务。
, Q; h/ c9 X( V8 x/ \ 到些BIOS的引导其他完成。接着该进OS了,看Linux 0.11吧,操作系统是怎么做事情的。, l! e3 z% N- m8 c
6 r/ v& q% L, N, y+ \' E2 w7 A. p7 l
Driver:+ E7 O0 S; v0 r! N+ i$ Q
我们的驱动什么为在PEI和DXE等不同阶段执行呢?' o( h$ e5 ^0 @8 G. h
大家请看一下我们的驱动的makefile.(EDK中的*.inf)( R# ?8 A8 g- x
[defines]
8 R/ C* ^2 m8 }; U3 ^8 z BASE_NAME = OWEN
- d( J9 L6 o+ P3 O! c/ B2 h2 i+ h FILE_GUID = 1EDD13C1-62EF-4262-A1AA-0040D0830110" N. V2 L6 {" y# ~
COMPONENT_TYPE = BS_DRIVER+ B0 p. ~/ f. N# ?* b- g( {
1 k" z. w; O8 E' t8 U0 t4 C( ?
BASE_NAME告诉编译器最终生成的驱动的名字。 T* s) r# \. E# P* K- ]. _' {! ~
FILE_GUID就是这个驱动的GUID名字,在BIOS中引用某个驱动就是根据它来调用和识别。- O( }/ e) C/ Q! Z! [" Y+ s( C% ?
COMONENT_TYPE会告诉编译器生成驱动的类型,是PEI,DXE,等。$ b- J8 T. J# m/ V' ?# u
在EDK中有一个FWVolume.c实现的功能就是帮我们把这个TYPE转换面相应的扩展名
) m( n/ ]# W7 Y COMP_TYPE_EXTENSION mCompTypeExtension[] = {. M _) H( Q6 I. Q( P
{"bs_driver", ".dxe" },8 ]0 R) |# n6 _( o* `8 e8 U% O- P0 p
{"rt_driver", ".dxe" },4 y. [& j7 g6 Z( }; b
{"sal_rt_driver", ".dxe"},
" t: s. o' s0 h) v; R9 G, F1 I% S {"security_core", ".sec"},
9 R8 Q( e' N; S/ @! s {"pei_core", ".pei"},. R+ _" A0 _, T
{"pic_peim", ".pei"},
3 f7 N4 b( P8 e c( b {"pe32_peim", ".pei"},
/ I; |9 H2 c! ~2 j3 T% U. p& E9 e+ j# r {"relocatable_peim", ".pei"},: v! q; b! D9 ^- d- e) Q9 }
{"binary", ".ffs"},
4 C+ R+ z7 _) `8 R+ s d1 D {"application", ".app"},9 ?% G/ Q X/ f
{"file", ".ffs"}," e) u6 B! i7 @9 N" n8 Y
{"fvimagefile", ".fvi"},
) g C! h+ n" P9 y) N {"rawfile", ".raw"},/ m# b8 |8 M, o( `2 x7 T1 J7 P+ A
{"apriori", ".ffs"},' M. O9 |, i5 a2 Z
{"combined_peim_driver", ".pei"},8 A4 x9 `" T d& e6 ~
{ NULL, NULL }
# n( ~- D4 ~# B: l& q( h};$ d. n; }+ Q$ [( j# O4 o
/ G. p* P7 F/ w. G- F! \4 n4 p
了解了这些,接下我们可以看驱动篇了。(Go On Study... Forever)
9 E, M/ ~8 ]& C$ O' q. n- }" n* t: W
; p8 g4 o: l: N7 E 7 V+ D: P$ _; A$ H
|
|