|
|
最近在工作看到机台有启动过程中把SPI ROM数据清空,但苦与没有办法很好的Debug(PCA没有架起来),所有与EDK为对象好好的读了一把。- b0 R& i: S* I R3 \5 m' }
, y5 H& P3 X* x9 k* z1 @# x6 i
SEC/CEI:
l- h+ X) Z% q7 m UEFI BIOS启动时先会执行SEC/CEI,这个阶段在实现的BIOS Code中初始化Debug Port,进入Big Mode,CPU的MicroCode,CacheToRAM的转换.然后跳转到PEI阶段。
" w/ X. a+ [% ?5 s& u- U/ H在EDK中这部分被成了Load FvRecovery.fd文件,这个文件类似与我们的BIOS ROM.里面是我们编译后生成的二进制代码。在这个阶段最主要的是将这个文件加载到内存中(Windows API将文件加载到内存,看API函数).
" E, b) s4 ?2 P6 l- I$ }2 \/ t2 n# c
5 \7 ~# i1 _+ o9 TPEI:
5 n( x6 o% E3 M8 b) j 从这里开始UEFI BIOS和EDK执行基本相同,只是一个是从SPI ROM中定位一个地址(PEIM的开始地址),一个是从内存中定位一个地址(PEIM的开始地址)。从这里开始只讲EDK的执行
0 {" C9 s. N6 ? EDK调用InitializeMemoryService函数,将HobList清空,peiservice清空。
$ @; }2 G! r7 T' _/ M InitializePPIService函数,将PPI队列清空,这个队列长0x3F.
: U- N& Y! u( D! `# u5 B InitializeSercurityService函数,将Notify队列清空。# [( L& N+ B- u: }; d
InitializeDispatcherData函数,将Dispatcher队列清空。
( T& t6 N! {& p. V$ W0 e; A! m 接着由PeiBuildHobGuid来建立一个HOB(S3返回时这时应该有这个HOB,不用建立,直接使用了,这样就会进入另外一个流程,可以这个EDK不能调试S3,不知道怎么走)。然后由(*PeiServices)->InstallPpi()将这个新HOB加入到PPI中。
9 J7 T8 F v+ E8 w 由于在SEC阶段转了以下这几具PPI,所以在执行PEI的Dispatcher之前会先安装东西:
5 e- E, Z* l% D9 g+ P; c+ m3 q EFI_PEI_PPI_DESCRIPTOR gPrivateDispatchTable[] = {9 l; }! m, W! e" A5 M* @
{EFI_PEI_PPI_DESCRIPTOR_PPI, &gEfiNtLoadAsDllPpiGuid, &mSecNtLoadAsDllPpi},
6 H, y1 y7 Y6 Y' k" x+ w {EFI_PEI_PPI_DESCRIPTOR_PPI, &gNtPeiLoadFileGuid, &mSecNtLoadFilePpi},
4 G" d( }9 \! p# t5 g: n% ~ {EFI_PEI_PPI_DESCRIPTOR_PPI, &gPeiNtAutoScanPpiGuid, &mSecNtAutoScanPpi},
: F. I- z# R- `7 R {EFI_PEI_PPI_DESCRIPTOR_PPI, &gPeiNtThunkPpiGuid, &mSecWinNtThunkPpi},3 M2 `2 Y% W1 y S5 z0 ?
{EFI_PEI_PPI_DESCRIPTOR_PPI, &gPeiStatusCodePpiGuid, &mSecStatusCodePpi},5 V4 g- Q! ^* Q
{EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST, &gNtFwhPpiGuid, &mSecFwhInformationPpi}
/ S$ }* l' f; u5 c0 r# w };
. j4 D0 l2 j/ E# M, {& D 每个PPI是由{类型,GUID(名字,以后就根据这个来找到它的),Function_Entry_Address}组成。
" }9 a8 _ J8 d 这些PPI会在PEIDispatcher中用到。
- E# \' i1 z! c2 ^ 安装完这此东西这开始执行PEIDispatcher函数,函数从BIOS ROM文件中找出PEI的Image(怎么找到,请读一下FV_HEAD(EFI_HEAD),里面讲到了如何区分Image类型),然后定位到PEI Image的入口地址,执行他。在我们的的PEI中,我们一般会申明一个PPI,这个就是这个PEI提供一些服务,PEIDispatcher会将他们加入到PPI-List中,以后其他Image也可以调用他的提供的功能。( S6 z9 F3 O: [/ E0 f
最后EDK会加载一个叫DXEIPL的PEI,DXEIPL提供一个PPI服务,这个PPI的功能是实现从PEI到DXE的切换,这个PPI里面为DXE做了很多的预准备,加载了很多PPI,如对BIOS的解压方法等。) |: S+ d# B) F* o) V! I$ M. R! ]9 x
SwitchStacks (
, e2 |' a1 M) l T/ E (VOID *) (UINTN) DxeCoreEntryPoint,: H$ Q. w! G9 C- x0 e* Q) L
(UINTN) (HobList.Raw),
) n4 a& v: ^5 J* r" U: p (VOID *) (UINTN) TopOfStack,
. N0 Z9 L+ i8 g7 J' l- E (VOID *) (UINTN) BspStore( [. l# k& F3 i# {- {; T
);
" I7 O# w4 ~' [$ G. u' a 用过汇编的人对这个技术一定很熟悉,不多说了(我别不清,咯。。。). D. p" v0 m! X* H' r& `0 w
% P* ?- }: P6 H+ O
DXE:. e; U2 T& A H; f8 p
从PEI到DXE切换时转过来一个HOBLIST参数,DXE会在这个HOB中找到Memory的使用情况,然后根据这些情况将BIOS引到内存(这是EFI的做法)。在EDK在DXE时重新定位一下内存。2 j/ p4 i' b, |
接着就会定义我们经常使用到的gST表,gRT表。接着是申明一些Protocol(先不关心这些事)。# n1 a8 P0 S% V$ Z L
等这些该加的PPI,Protocol加完了,CoreDispatcher()就出场了。他会的功能类似PEIDispatcher()。从我们BIOS ROM中将DXE的驱动读出,执行执行他们,这时会执行到Driver
- ? P, A* G( `中的Support(),Start()两个功能函数。在这两个函数中你可以注册自己的PPI,为其他驱动提供服务。
, P U4 u1 C' X( o2 |$ y 到些BIOS的引导其他完成。接着该进OS了,看Linux 0.11吧,操作系统是怎么做事情的。
% Q" c2 n# K7 N6 t
) l) c+ ^; y gDriver:1 G; M1 l! x8 @& M: K* N
我们的驱动什么为在PEI和DXE等不同阶段执行呢?! m' n, u. A9 m* h0 L& s6 Z e1 n
大家请看一下我们的驱动的makefile.(EDK中的*.inf)( c2 G+ b# G u
[defines]
' o# x7 r3 w0 I& L BASE_NAME = OWEN
2 h: u3 s" N9 } FILE_GUID = 1EDD13C1-62EF-4262-A1AA-0040D0830110
/ h; {7 I* v+ c: O; o% r, V( W" x1 ~ COMPONENT_TYPE = BS_DRIVER) P" U, {( y% Q, N7 J! n
# E' K' F* x* F
BASE_NAME告诉编译器最终生成的驱动的名字。) h" q$ M/ F6 z& _' b
FILE_GUID就是这个驱动的GUID名字,在BIOS中引用某个驱动就是根据它来调用和识别。
' Q, n4 _. N5 n* n' l+ U COMONENT_TYPE会告诉编译器生成驱动的类型,是PEI,DXE,等。
$ d; ~+ ~- [" D9 o2 k9 P; u 在EDK中有一个FWVolume.c实现的功能就是帮我们把这个TYPE转换面相应的扩展名
' ~4 { U* p* K" k COMP_TYPE_EXTENSION mCompTypeExtension[] = {3 Q) F0 a6 N1 j8 m
{"bs_driver", ".dxe" },: ~: {* |' I1 h9 s$ Q
{"rt_driver", ".dxe" },# A& p) @6 \" `% E2 S( T! O' z5 ^
{"sal_rt_driver", ".dxe"},6 }$ O- g( F3 {& @3 F2 Z
{"security_core", ".sec"},
0 z0 @6 o! R; O7 @8 b- h+ V {"pei_core", ".pei"},
8 H( j. N6 \" g. b5 @4 V; E/ M {"pic_peim", ".pei"},& h7 _* Z( Q+ Y( E
{"pe32_peim", ".pei"},+ I! E A0 e5 G" H
{"relocatable_peim", ".pei"},
D. [. n6 o; N" c7 P; `. Z, D6 ]( { {"binary", ".ffs"},
' }5 _* _) s8 v {"application", ".app"},; Q) v0 f# ~1 p( {% }
{"file", ".ffs"},
+ H4 m* \' A t% i {"fvimagefile", ".fvi"},* {) s& u* [9 T% O
{"rawfile", ".raw"},
) f( q8 l: e& ]) h1 B e4 n) g {"apriori", ".ffs"},
7 E @ k% T# {9 N# U" t {"combined_peim_driver", ".pei"},% t* Z* P9 j+ Y3 U
{ NULL, NULL }
6 f1 u- Y, M/ b8 F. w; a9 b};
0 I4 ^ V V8 P5 Q" h! F: J" o5 X$ [8 c* c6 J, I/ @
了解了这些,接下我们可以看驱动篇了。(Go On Study... Forever)$ ]2 V9 o2 X1 G: {7 m' ?# w0 C
7 f& ~3 X+ |' Y; \
. M2 w& L' W# N. |1 ~ |
|