|
|
最近在工作看到机台有启动过程中把SPI ROM数据清空,但苦与没有办法很好的Debug(PCA没有架起来),所有与EDK为对象好好的读了一把。
1 ?: a/ e m" D# g' O. s
" B0 P" N8 s& HSEC/CEI:" |, v5 ~ |7 v3 x5 O1 e
UEFI BIOS启动时先会执行SEC/CEI,这个阶段在实现的BIOS Code中初始化Debug Port,进入Big Mode,CPU的MicroCode,CacheToRAM的转换.然后跳转到PEI阶段。6 h, V! F7 b! z4 h* v% g! E3 v7 T
在EDK中这部分被成了Load FvRecovery.fd文件,这个文件类似与我们的BIOS ROM.里面是我们编译后生成的二进制代码。在这个阶段最主要的是将这个文件加载到内存中(Windows API将文件加载到内存,看API函数).0 }- U8 E0 M0 }: X1 I. Q1 k/ M( b, E
2 V! l' q- t# g3 H, ^# \
PEI:; P' K* E/ I, _! x# k
从这里开始UEFI BIOS和EDK执行基本相同,只是一个是从SPI ROM中定位一个地址(PEIM的开始地址),一个是从内存中定位一个地址(PEIM的开始地址)。从这里开始只讲EDK的执行! `. J* _" U( [ q& Q# Z3 |" |6 Y- Q
EDK调用InitializeMemoryService函数,将HobList清空,peiservice清空。
2 S; q% X _( e. ^/ \ c InitializePPIService函数,将PPI队列清空,这个队列长0x3F., u: a/ t; [* m9 G8 r Z
InitializeSercurityService函数,将Notify队列清空。
' U( @5 K/ x* A. n( y InitializeDispatcherData函数,将Dispatcher队列清空。! g+ Q8 B1 @/ x6 @5 d
接着由PeiBuildHobGuid来建立一个HOB(S3返回时这时应该有这个HOB,不用建立,直接使用了,这样就会进入另外一个流程,可以这个EDK不能调试S3,不知道怎么走)。然后由(*PeiServices)->InstallPpi()将这个新HOB加入到PPI中。1 X4 v' v5 d3 i$ v8 \: v: _
由于在SEC阶段转了以下这几具PPI,所以在执行PEI的Dispatcher之前会先安装东西:
. A1 i2 P. ~3 q8 Z* Y4 d EFI_PEI_PPI_DESCRIPTOR gPrivateDispatchTable[] = {+ u1 _9 y, V5 P+ E$ F
{EFI_PEI_PPI_DESCRIPTOR_PPI, &gEfiNtLoadAsDllPpiGuid, &mSecNtLoadAsDllPpi},$ W! F" V2 y. ~
{EFI_PEI_PPI_DESCRIPTOR_PPI, &gNtPeiLoadFileGuid, &mSecNtLoadFilePpi},% Q5 E6 z+ l9 b. l4 t2 m* C. j* F0 r1 _
{EFI_PEI_PPI_DESCRIPTOR_PPI, &gPeiNtAutoScanPpiGuid, &mSecNtAutoScanPpi},
# Q$ ~* |: j( J5 W8 X! a$ L2 p4 h. d {EFI_PEI_PPI_DESCRIPTOR_PPI, &gPeiNtThunkPpiGuid, &mSecWinNtThunkPpi},. @' O# [* U+ |6 }9 e* |2 M& R( Q2 }
{EFI_PEI_PPI_DESCRIPTOR_PPI, &gPeiStatusCodePpiGuid, &mSecStatusCodePpi},6 m' U' N i9 U' S# ~1 j+ a
{EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST, &gNtFwhPpiGuid, &mSecFwhInformationPpi}7 E$ ~ X' w: H- z
};5 z! ~+ r7 Z! Q$ G
每个PPI是由{类型,GUID(名字,以后就根据这个来找到它的),Function_Entry_Address}组成。 Y9 \; J/ C* r3 j9 h
这些PPI会在PEIDispatcher中用到。
2 T( Z3 C2 B" T" j* |5 V4 M 安装完这此东西这开始执行PEIDispatcher函数,函数从BIOS ROM文件中找出PEI的Image(怎么找到,请读一下FV_HEAD(EFI_HEAD),里面讲到了如何区分Image类型),然后定位到PEI Image的入口地址,执行他。在我们的的PEI中,我们一般会申明一个PPI,这个就是这个PEI提供一些服务,PEIDispatcher会将他们加入到PPI-List中,以后其他Image也可以调用他的提供的功能。
3 y9 f& S4 b3 m# o! U v# u 最后EDK会加载一个叫DXEIPL的PEI,DXEIPL提供一个PPI服务,这个PPI的功能是实现从PEI到DXE的切换,这个PPI里面为DXE做了很多的预准备,加载了很多PPI,如对BIOS的解压方法等。9 d" I7 G- e7 P, y( i, a6 ?
SwitchStacks (( K4 k0 y$ V% F7 i8 x7 t
(VOID *) (UINTN) DxeCoreEntryPoint,, Z/ b* h1 A$ |# i) M2 L; J
(UINTN) (HobList.Raw),
. o- e# t8 `( v9 _- } (VOID *) (UINTN) TopOfStack,
5 L( @1 r5 w* H( Q (VOID *) (UINTN) BspStore. R: O, y8 o9 k: A
);* j! ^6 i' b3 T. [) r/ T# K- ?
用过汇编的人对这个技术一定很熟悉,不多说了(我别不清,咯。。。). Z- c% j( P$ T! P3 w+ f) b' U$ O
3 K- V9 C6 E4 O6 w* n9 W% Y, E$ `DXE:
: o8 ?; C& w: y5 x# F 从PEI到DXE切换时转过来一个HOBLIST参数,DXE会在这个HOB中找到Memory的使用情况,然后根据这些情况将BIOS引到内存(这是EFI的做法)。在EDK在DXE时重新定位一下内存。
$ e; X( L% Y# `9 ?3 M/ Z& x6 M接着就会定义我们经常使用到的gST表,gRT表。接着是申明一些Protocol(先不关心这些事)。
* H- d) J& A5 T 等这些该加的PPI,Protocol加完了,CoreDispatcher()就出场了。他会的功能类似PEIDispatcher()。从我们BIOS ROM中将DXE的驱动读出,执行执行他们,这时会执行到Driver5 E- s/ L K0 j8 r
中的Support(),Start()两个功能函数。在这两个函数中你可以注册自己的PPI,为其他驱动提供服务。
2 |2 H8 r3 C$ ? 到些BIOS的引导其他完成。接着该进OS了,看Linux 0.11吧,操作系统是怎么做事情的。# r$ E* S0 N5 R3 {6 K. Q
- H' f! N- l% z" j" }, W; s2 t! Y' I. {: s
Driver: v; z; g$ b. O/ t
我们的驱动什么为在PEI和DXE等不同阶段执行呢?) {# d1 [, u# q& g) P& Q* w
大家请看一下我们的驱动的makefile.(EDK中的*.inf)# {4 {& s- B3 F9 {) P, H6 {
[defines]
% {9 E; l( z4 m5 [" Q4 L BASE_NAME = OWEN
! U! c2 p& t/ B" ]- N& x FILE_GUID = 1EDD13C1-62EF-4262-A1AA-0040D0830110
( B( K" P% o/ I3 H$ l COMPONENT_TYPE = BS_DRIVER9 X- G$ W. }3 B; i% U1 ]
5 h! f) R" ]) j+ C7 H BASE_NAME告诉编译器最终生成的驱动的名字。
+ A& M7 _7 n7 ^+ A, z2 |- C FILE_GUID就是这个驱动的GUID名字,在BIOS中引用某个驱动就是根据它来调用和识别。" n$ S, ^ n8 |7 _0 ^. _+ A
COMONENT_TYPE会告诉编译器生成驱动的类型,是PEI,DXE,等。
2 V' q8 v: O% Z 在EDK中有一个FWVolume.c实现的功能就是帮我们把这个TYPE转换面相应的扩展名6 y8 Z3 c. t' r3 Y
COMP_TYPE_EXTENSION mCompTypeExtension[] = {
6 a$ Y3 f( _5 @0 D+ l( { {"bs_driver", ".dxe" },
* `; S0 O; F4 N {"rt_driver", ".dxe" },
" D) H! v. a. e2 `1 e# d! w {"sal_rt_driver", ".dxe"},. A: s3 `+ a2 Z8 q* n/ ]
{"security_core", ".sec"},9 G- F& C+ _0 Z# U# P* h( q
{"pei_core", ".pei"},4 G( E# S, @; X0 j3 \. ^
{"pic_peim", ".pei"},
. R1 w6 s1 \2 Q+ L& @8 m3 F& n {"pe32_peim", ".pei"},
5 v. Z: f0 m! ]1 L& \0 c {"relocatable_peim", ".pei"},
; d% ~# L$ @$ D. A1 d) g% G: r {"binary", ".ffs"},$ e X5 V2 m' ?1 J7 S7 P6 e" g+ L
{"application", ".app"},% h5 k9 Z) I0 z0 H* y/ h7 T
{"file", ".ffs"},. j6 ~+ S6 A) `+ f
{"fvimagefile", ".fvi"},
2 u- N. `, w$ H' A {"rawfile", ".raw"},
! x7 S* Q% S9 k6 M( ?3 _ {"apriori", ".ffs"},
8 I' l! R6 B" E: X' Y {"combined_peim_driver", ".pei"},4 u8 W) ?. q( _1 C5 n: U' V
{ NULL, NULL }2 J! ~1 g* ?6 a7 o5 F
};
( s; z* [9 b* ~4 {" `
/ @( Y/ N4 k, W2 o2 ]6 d& Q, F4 w! _了解了这些,接下我们可以看驱动篇了。(Go On Study... Forever)
; [2 x6 d9 k8 O* u0 P) Q/ d 8 y# w6 m$ M+ v" H3 z
2 o2 i! Z* S: `! K! d6 F4 ~7 _ |
|