|
|
最近在工作看到机台有启动过程中把SPI ROM数据清空,但苦与没有办法很好的Debug(PCA没有架起来),所有与EDK为对象好好的读了一把。! @# v7 ?9 T* w
! b' I! t: j( f) T* s
SEC/CEI:. @1 x3 K b. N# l+ c( \9 j$ o4 E
UEFI BIOS启动时先会执行SEC/CEI,这个阶段在实现的BIOS Code中初始化Debug Port,进入Big Mode,CPU的MicroCode,CacheToRAM的转换.然后跳转到PEI阶段。. v& Q, h$ Q( E; R$ L5 }; u( N, }: X
在EDK中这部分被成了Load FvRecovery.fd文件,这个文件类似与我们的BIOS ROM.里面是我们编译后生成的二进制代码。在这个阶段最主要的是将这个文件加载到内存中(Windows API将文件加载到内存,看API函数).
! o1 Y4 m( x# ~! s" x, {* \9 {$ `8 {% r
PEI:$ _9 S& L" ~1 U* b
从这里开始UEFI BIOS和EDK执行基本相同,只是一个是从SPI ROM中定位一个地址(PEIM的开始地址),一个是从内存中定位一个地址(PEIM的开始地址)。从这里开始只讲EDK的执行" Y" Z. d* i3 z
EDK调用InitializeMemoryService函数,将HobList清空,peiservice清空。
' I G7 a1 D* u0 o2 @( k( J6 | InitializePPIService函数,将PPI队列清空,这个队列长0x3F.+ P4 O5 X9 `6 @
InitializeSercurityService函数,将Notify队列清空。7 @2 W1 J. O2 J/ o* k
InitializeDispatcherData函数,将Dispatcher队列清空。1 s5 x! h) {% s5 I; x! y; |( K( q
接着由PeiBuildHobGuid来建立一个HOB(S3返回时这时应该有这个HOB,不用建立,直接使用了,这样就会进入另外一个流程,可以这个EDK不能调试S3,不知道怎么走)。然后由(*PeiServices)->InstallPpi()将这个新HOB加入到PPI中。8 c/ K' N" {+ r1 ^# k
由于在SEC阶段转了以下这几具PPI,所以在执行PEI的Dispatcher之前会先安装东西:
6 \) X; _; Q6 v6 e/ j' b EFI_PEI_PPI_DESCRIPTOR gPrivateDispatchTable[] = {! W5 V( R% [, U
{EFI_PEI_PPI_DESCRIPTOR_PPI, &gEfiNtLoadAsDllPpiGuid, &mSecNtLoadAsDllPpi},
+ O9 j: k7 [% n. ^( K {EFI_PEI_PPI_DESCRIPTOR_PPI, &gNtPeiLoadFileGuid, &mSecNtLoadFilePpi},
1 P+ }$ }" w+ Y% v# E: e$ f {EFI_PEI_PPI_DESCRIPTOR_PPI, &gPeiNtAutoScanPpiGuid, &mSecNtAutoScanPpi},2 [7 J5 S2 l! C
{EFI_PEI_PPI_DESCRIPTOR_PPI, &gPeiNtThunkPpiGuid, &mSecWinNtThunkPpi},
% [4 \3 g# ]8 s$ q {EFI_PEI_PPI_DESCRIPTOR_PPI, &gPeiStatusCodePpiGuid, &mSecStatusCodePpi},; f/ V+ V/ n4 M5 Y" S
{EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST, &gNtFwhPpiGuid, &mSecFwhInformationPpi}
1 C9 x/ c4 ^# M, c5 e" T };
8 x v4 l- E: M! z3 ~ 每个PPI是由{类型,GUID(名字,以后就根据这个来找到它的),Function_Entry_Address}组成。3 Q: {" d( _' G/ y) F! M2 d
这些PPI会在PEIDispatcher中用到。5 P: p2 u" M3 {9 k1 z
安装完这此东西这开始执行PEIDispatcher函数,函数从BIOS ROM文件中找出PEI的Image(怎么找到,请读一下FV_HEAD(EFI_HEAD),里面讲到了如何区分Image类型),然后定位到PEI Image的入口地址,执行他。在我们的的PEI中,我们一般会申明一个PPI,这个就是这个PEI提供一些服务,PEIDispatcher会将他们加入到PPI-List中,以后其他Image也可以调用他的提供的功能。
8 p" G$ W! J: z- ^1 u, w" q 最后EDK会加载一个叫DXEIPL的PEI,DXEIPL提供一个PPI服务,这个PPI的功能是实现从PEI到DXE的切换,这个PPI里面为DXE做了很多的预准备,加载了很多PPI,如对BIOS的解压方法等。
8 E9 |! I: G0 x$ M! b SwitchStacks (4 [0 \: Q: S) Z6 {4 |$ K
(VOID *) (UINTN) DxeCoreEntryPoint,9 ]7 \7 n/ w# r% y; b) z9 H' C6 Q
(UINTN) (HobList.Raw),7 \8 d$ E' X6 C) i+ a9 g' h. x
(VOID *) (UINTN) TopOfStack,: D+ F9 ~% Z3 y) T$ M) Z
(VOID *) (UINTN) BspStore( s9 E; t: g& s& u$ Q
);
$ l7 e/ @' c: n& | 用过汇编的人对这个技术一定很熟悉,不多说了(我别不清,咯。。。)6 H. p1 X3 N$ d- g5 b6 _) k
) K! A" p* q) D+ ~% f( g3 f
DXE:" S% R1 u7 s9 z( s# V1 G& j& ? L
从PEI到DXE切换时转过来一个HOBLIST参数,DXE会在这个HOB中找到Memory的使用情况,然后根据这些情况将BIOS引到内存(这是EFI的做法)。在EDK在DXE时重新定位一下内存。
7 P6 `; }1 G+ H接着就会定义我们经常使用到的gST表,gRT表。接着是申明一些Protocol(先不关心这些事)。
: N+ Y3 R$ ~" g5 a 等这些该加的PPI,Protocol加完了,CoreDispatcher()就出场了。他会的功能类似PEIDispatcher()。从我们BIOS ROM中将DXE的驱动读出,执行执行他们,这时会执行到Driver( @' Z2 c9 t. R4 _
中的Support(),Start()两个功能函数。在这两个函数中你可以注册自己的PPI,为其他驱动提供服务。- }: A2 K$ |9 t
到些BIOS的引导其他完成。接着该进OS了,看Linux 0.11吧,操作系统是怎么做事情的。0 O3 @& Q+ E3 Q
. B' o. {- L& \" F% oDriver:
1 @: t8 |) {( Y9 G6 |+ z 我们的驱动什么为在PEI和DXE等不同阶段执行呢?
6 {) Q. N0 G: C, m$ e8 F 大家请看一下我们的驱动的makefile.(EDK中的*.inf). [" {+ V! s! x5 m0 z
[defines]
* j; X, k1 d9 U# d( K v8 \( t BASE_NAME = OWEN
3 [& k( s* u) {& Z8 V FILE_GUID = 1EDD13C1-62EF-4262-A1AA-0040D0830110- O* z) }! Y4 P( C! m6 X
COMPONENT_TYPE = BS_DRIVER
" P- l( z# X. {4 [& s- M, d% y+ q$ w4 @7 J
BASE_NAME告诉编译器最终生成的驱动的名字。1 z0 M+ d- p; p) @7 }# K& n
FILE_GUID就是这个驱动的GUID名字,在BIOS中引用某个驱动就是根据它来调用和识别。4 V5 ?. Y. [4 z! I# m1 j1 T! ]
COMONENT_TYPE会告诉编译器生成驱动的类型,是PEI,DXE,等。
& o2 N' K% b0 N$ |% e, c 在EDK中有一个FWVolume.c实现的功能就是帮我们把这个TYPE转换面相应的扩展名
2 _/ a3 \9 h5 o6 {* }4 D COMP_TYPE_EXTENSION mCompTypeExtension[] = {
% X& K2 H/ v% T' w) | {"bs_driver", ".dxe" },
' _) O, l5 S! ^7 i- [+ b {"rt_driver", ".dxe" },' P. f* Q3 m( ~3 }
{"sal_rt_driver", ".dxe"},
' V- {- a4 s4 Y {"security_core", ".sec"},$ B4 f1 E1 ?$ [9 _
{"pei_core", ".pei"},
3 Y- L' o: O, W8 E- b$ `+ C6 n {"pic_peim", ".pei"},
2 r x$ |7 I, Z; R0 o {"pe32_peim", ".pei"},0 @8 g* G: L9 s
{"relocatable_peim", ".pei"},. I8 ?* N0 ]9 H+ x3 v
{"binary", ".ffs"},
& V e' Y/ }7 u& T2 x' U {"application", ".app"},) b2 {0 F P- i9 l8 t, i I+ @
{"file", ".ffs"},4 P* [, X+ X6 u
{"fvimagefile", ".fvi"},+ ~: M* ~( ~) J8 x4 C8 l- p R- u3 ~
{"rawfile", ".raw"},- D- @5 N/ x. X
{"apriori", ".ffs"},
7 {8 X8 M$ Q# v. a3 K {"combined_peim_driver", ".pei"},
/ `! I ]( `3 A. D% J# [1 p { NULL, NULL }" V/ I( z; G( X, A* o
};' @6 y1 F2 n4 O L" W
$ k/ S! P1 i7 G4 ]4 m
了解了这些,接下我们可以看驱动篇了。(Go On Study... Forever)
- L" v" {% P% Y* `6 X6 H ! b4 b* Q8 A: q9 D @
* v8 @7 v2 [) r: B- g |
|