|
|
最近在工作看到机台有启动过程中把SPI ROM数据清空,但苦与没有办法很好的Debug(PCA没有架起来),所有与EDK为对象好好的读了一把。: P7 Y3 \6 O+ A5 O2 y
. d& H4 q5 z9 I
SEC/CEI:
- F+ H) |! [1 H" B+ t- I/ k7 n& h UEFI BIOS启动时先会执行SEC/CEI,这个阶段在实现的BIOS Code中初始化Debug Port,进入Big Mode,CPU的MicroCode,CacheToRAM的转换.然后跳转到PEI阶段。$ E/ F d! k. z- [3 C2 i) ^/ T
在EDK中这部分被成了Load FvRecovery.fd文件,这个文件类似与我们的BIOS ROM.里面是我们编译后生成的二进制代码。在这个阶段最主要的是将这个文件加载到内存中(Windows API将文件加载到内存,看API函数)./ G, E/ r+ y+ H, q( N/ A7 h( ~+ I
9 ]+ w8 x( e: I2 ?3 ?& PPEI:" F4 n" s% z2 N7 d
从这里开始UEFI BIOS和EDK执行基本相同,只是一个是从SPI ROM中定位一个地址(PEIM的开始地址),一个是从内存中定位一个地址(PEIM的开始地址)。从这里开始只讲EDK的执行
2 }7 A0 E/ |/ I$ B0 |: U. U EDK调用InitializeMemoryService函数,将HobList清空,peiservice清空。
9 ~+ |5 m- k" i InitializePPIService函数,将PPI队列清空,这个队列长0x3F.# F a) k/ k4 u
InitializeSercurityService函数,将Notify队列清空。9 V1 d$ c9 G& V5 E
InitializeDispatcherData函数,将Dispatcher队列清空。
! t9 m4 G( @+ c" ~" r$ R 接着由PeiBuildHobGuid来建立一个HOB(S3返回时这时应该有这个HOB,不用建立,直接使用了,这样就会进入另外一个流程,可以这个EDK不能调试S3,不知道怎么走)。然后由(*PeiServices)->InstallPpi()将这个新HOB加入到PPI中。4 @. B! x% | k. X' o9 |
由于在SEC阶段转了以下这几具PPI,所以在执行PEI的Dispatcher之前会先安装东西:
! i' ^# E3 x6 S1 e" C5 X2 V EFI_PEI_PPI_DESCRIPTOR gPrivateDispatchTable[] = {
2 Q* b! V6 u5 i' @: F) M5 l; \/ n3 M {EFI_PEI_PPI_DESCRIPTOR_PPI, &gEfiNtLoadAsDllPpiGuid, &mSecNtLoadAsDllPpi},
- y. @- \2 m% a2 i0 S; w6 N* N {EFI_PEI_PPI_DESCRIPTOR_PPI, &gNtPeiLoadFileGuid, &mSecNtLoadFilePpi},
+ F L$ _" v( g5 I7 j, h( @# J {EFI_PEI_PPI_DESCRIPTOR_PPI, &gPeiNtAutoScanPpiGuid, &mSecNtAutoScanPpi},1 |: i Z- Q; l: P7 _- R4 s* h4 M
{EFI_PEI_PPI_DESCRIPTOR_PPI, &gPeiNtThunkPpiGuid, &mSecWinNtThunkPpi},
" _) K. L7 x( E, y# Y% G3 p+ M3 a {EFI_PEI_PPI_DESCRIPTOR_PPI, &gPeiStatusCodePpiGuid, &mSecStatusCodePpi},/ X( Z5 T6 \& E7 e
{EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST, &gNtFwhPpiGuid, &mSecFwhInformationPpi}
" J7 W! q/ Q8 E# N P, ^ };4 f7 y& T8 K1 x. J! X% J# f
每个PPI是由{类型,GUID(名字,以后就根据这个来找到它的),Function_Entry_Address}组成。1 i- I# R7 A: e5 f
这些PPI会在PEIDispatcher中用到。5 f1 ~, d% C' w& F+ R
安装完这此东西这开始执行PEIDispatcher函数,函数从BIOS ROM文件中找出PEI的Image(怎么找到,请读一下FV_HEAD(EFI_HEAD),里面讲到了如何区分Image类型),然后定位到PEI Image的入口地址,执行他。在我们的的PEI中,我们一般会申明一个PPI,这个就是这个PEI提供一些服务,PEIDispatcher会将他们加入到PPI-List中,以后其他Image也可以调用他的提供的功能。" y4 X1 [" p9 R6 m8 S1 U
最后EDK会加载一个叫DXEIPL的PEI,DXEIPL提供一个PPI服务,这个PPI的功能是实现从PEI到DXE的切换,这个PPI里面为DXE做了很多的预准备,加载了很多PPI,如对BIOS的解压方法等。3 G* y% \0 J2 }( S' R) ^
SwitchStacks (8 K" Z6 r: l5 ?/ H6 [1 R3 w
(VOID *) (UINTN) DxeCoreEntryPoint,4 j' j' o; [: [
(UINTN) (HobList.Raw),; @ e; }+ w0 H3 e1 f8 E
(VOID *) (UINTN) TopOfStack,5 y1 s3 E1 V; U# s( n. S
(VOID *) (UINTN) BspStore
" X; g- a4 \7 V, A );
( ?( ]9 Q& c- L( f; {4 C 用过汇编的人对这个技术一定很熟悉,不多说了(我别不清,咯。。。)% T) |. i6 e" f! T8 G& z
; [2 t; G2 ?& x r7 B- y
DXE:7 y! }" o' W+ [2 x6 I& A4 W
从PEI到DXE切换时转过来一个HOBLIST参数,DXE会在这个HOB中找到Memory的使用情况,然后根据这些情况将BIOS引到内存(这是EFI的做法)。在EDK在DXE时重新定位一下内存。8 N4 N3 G* f' m
接着就会定义我们经常使用到的gST表,gRT表。接着是申明一些Protocol(先不关心这些事)。
9 S7 W) _7 N/ N5 v, Q 等这些该加的PPI,Protocol加完了,CoreDispatcher()就出场了。他会的功能类似PEIDispatcher()。从我们BIOS ROM中将DXE的驱动读出,执行执行他们,这时会执行到Driver) X# O4 M! P" C! b' V; F
中的Support(),Start()两个功能函数。在这两个函数中你可以注册自己的PPI,为其他驱动提供服务。
1 V& }" T( W9 g; q6 H 到些BIOS的引导其他完成。接着该进OS了,看Linux 0.11吧,操作系统是怎么做事情的。
0 I0 V- r w) d# R% E/ f9 z $ f8 N5 e! Q3 O4 | P% {- Q+ l
Driver:
5 p- b! E( _5 N4 ^* ]4 c7 Q! m( s 我们的驱动什么为在PEI和DXE等不同阶段执行呢?
9 O+ W2 c/ y' H6 m5 `/ F 大家请看一下我们的驱动的makefile.(EDK中的*.inf)
) c' h7 L; P2 `* g [defines]
5 S T5 ?3 `: M" y% b BASE_NAME = OWEN
% e1 Y1 X2 D9 w$ O* R/ a FILE_GUID = 1EDD13C1-62EF-4262-A1AA-0040D0830110
' X, r3 r; ^( y5 M1 T- o9 }2 {1 f COMPONENT_TYPE = BS_DRIVER
) Z4 O+ `6 @8 V$ o6 y
3 X6 b/ f% `6 v4 q. u0 P BASE_NAME告诉编译器最终生成的驱动的名字。+ N6 F! K: a! s: g* k1 K* R
FILE_GUID就是这个驱动的GUID名字,在BIOS中引用某个驱动就是根据它来调用和识别。
+ [0 m/ e4 b2 O$ O! Z3 N COMONENT_TYPE会告诉编译器生成驱动的类型,是PEI,DXE,等。) x0 ^- ]* ]6 u& R. b
在EDK中有一个FWVolume.c实现的功能就是帮我们把这个TYPE转换面相应的扩展名& m$ ~ j- S$ d. m* w( [- V7 Q
COMP_TYPE_EXTENSION mCompTypeExtension[] = {
& l3 E) F$ f, |" C7 Q {"bs_driver", ".dxe" },, j( \% K7 } l2 z$ Q* d
{"rt_driver", ".dxe" }, A$ h! P4 ]* B
{"sal_rt_driver", ".dxe"},
& h' F! @3 o+ C g5 L {"security_core", ".sec"},
' G5 S# k0 G- \; \% \: c! g {"pei_core", ".pei"},
7 i; @2 ~# ~" H7 U* ^1 T5 b2 J {"pic_peim", ".pei"},+ W1 [/ F" o! n
{"pe32_peim", ".pei"},
; `1 N( g# Y6 X2 Y0 W, t {"relocatable_peim", ".pei"},0 U) V- v" {( d6 C- d# o/ E
{"binary", ".ffs"},, p; `; u3 A! d/ n* K" c2 V+ \1 d
{"application", ".app"},
F. {( b4 Z) @" S {"file", ".ffs"},
4 z3 C( k. H3 P7 Q: x3 U* H; N {"fvimagefile", ".fvi"},
, l1 {' u3 p L& B6 E {"rawfile", ".raw"},
A' T9 a/ p8 F' d {"apriori", ".ffs"},2 \0 [ L. n6 y( p
{"combined_peim_driver", ".pei"},
$ N1 Z0 {* b s { NULL, NULL }8 c- p: Q+ D: v9 ~1 E9 g" k
};2 [/ i3 J7 v1 y- s; p; e( m3 P
5 y4 ]9 q# U9 ?. N% Z/ N了解了这些,接下我们可以看驱动篇了。(Go On Study... Forever)
6 o. p* B! f( x, U% [* |, w
1 y7 g; _4 z* l& S4 x) D: l ) |9 F3 X3 W3 t2 R
|
|