|
最近在工作看到机台有启动过程中把SPI ROM数据清空,但苦与没有办法很好的Debug(PCA没有架起来),所有与EDK为对象好好的读了一把。( O3 I, |5 _# f1 l9 c+ m; ]
_# y$ Z5 r+ H K* C: o; w) X8 L% y
SEC/CEI:8 m' \: w' h1 a; h2 ]* F
UEFI BIOS启动时先会执行SEC/CEI,这个阶段在实现的BIOS Code中初始化Debug Port,进入Big Mode,CPU的MicroCode,CacheToRAM的转换.然后跳转到PEI阶段。' f& a5 n, _ S+ T3 k: m- \9 Y
在EDK中这部分被成了Load FvRecovery.fd文件,这个文件类似与我们的BIOS ROM.里面是我们编译后生成的二进制代码。在这个阶段最主要的是将这个文件加载到内存中(Windows API将文件加载到内存,看API函数).
5 n/ B1 p0 w; H: `& u3 |& u) c0 U w% ^! N$ `
PEI:
% h( Q1 \- E/ R2 C+ B* B 从这里开始UEFI BIOS和EDK执行基本相同,只是一个是从SPI ROM中定位一个地址(PEIM的开始地址),一个是从内存中定位一个地址(PEIM的开始地址)。从这里开始只讲EDK的执行
! J) _% x2 h& C) t5 D EDK调用InitializeMemoryService函数,将HobList清空,peiservice清空。
; u; }6 b& o s) R; G InitializePPIService函数,将PPI队列清空,这个队列长0x3F.4 q8 p$ V, R$ e; `
InitializeSercurityService函数,将Notify队列清空。. d' y! V" l" x4 J# L; q3 c
InitializeDispatcherData函数,将Dispatcher队列清空。
- v' }& f6 P- b+ _+ y+ r 接着由PeiBuildHobGuid来建立一个HOB(S3返回时这时应该有这个HOB,不用建立,直接使用了,这样就会进入另外一个流程,可以这个EDK不能调试S3,不知道怎么走)。然后由(*PeiServices)->InstallPpi()将这个新HOB加入到PPI中。7 |! j" C, r0 o- L
由于在SEC阶段转了以下这几具PPI,所以在执行PEI的Dispatcher之前会先安装东西:
' z6 R, G. H' L8 M# Z( _- Z7 ^ EFI_PEI_PPI_DESCRIPTOR gPrivateDispatchTable[] = {* q6 m* s. Q! x- X, T" E
{EFI_PEI_PPI_DESCRIPTOR_PPI, &gEfiNtLoadAsDllPpiGuid, &mSecNtLoadAsDllPpi},
5 i4 @9 T$ l& M9 |) t {EFI_PEI_PPI_DESCRIPTOR_PPI, &gNtPeiLoadFileGuid, &mSecNtLoadFilePpi}, n' Y9 C1 l) @* n
{EFI_PEI_PPI_DESCRIPTOR_PPI, &gPeiNtAutoScanPpiGuid, &mSecNtAutoScanPpi},9 Y& D3 v# x; W6 N
{EFI_PEI_PPI_DESCRIPTOR_PPI, &gPeiNtThunkPpiGuid, &mSecWinNtThunkPpi},+ | H- X. w4 h$ _7 b0 s
{EFI_PEI_PPI_DESCRIPTOR_PPI, &gPeiStatusCodePpiGuid, &mSecStatusCodePpi},* g S7 M/ _3 X/ O+ f; U: ~
{EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST, &gNtFwhPpiGuid, &mSecFwhInformationPpi}
3 A" L8 P2 m& m* R; L };
; ^( I$ Q! e, b 每个PPI是由{类型,GUID(名字,以后就根据这个来找到它的),Function_Entry_Address}组成。
) G3 ]8 o: B \% o& \# f" h 这些PPI会在PEIDispatcher中用到。
8 {( I: {' u1 w0 M6 U/ d 安装完这此东西这开始执行PEIDispatcher函数,函数从BIOS ROM文件中找出PEI的Image(怎么找到,请读一下FV_HEAD(EFI_HEAD),里面讲到了如何区分Image类型),然后定位到PEI Image的入口地址,执行他。在我们的的PEI中,我们一般会申明一个PPI,这个就是这个PEI提供一些服务,PEIDispatcher会将他们加入到PPI-List中,以后其他Image也可以调用他的提供的功能。
( R: I3 ~) G* v1 U4 j# G0 s 最后EDK会加载一个叫DXEIPL的PEI,DXEIPL提供一个PPI服务,这个PPI的功能是实现从PEI到DXE的切换,这个PPI里面为DXE做了很多的预准备,加载了很多PPI,如对BIOS的解压方法等。
% b) m2 K+ E' _$ w) H SwitchStacks (
2 P1 r' o3 k- e# S, f/ }) N8 B (VOID *) (UINTN) DxeCoreEntryPoint,
: H# H, F1 `8 r, q (UINTN) (HobList.Raw),
% r5 ?- f: L. d8 a (VOID *) (UINTN) TopOfStack,
2 q" H% g F- a: u) d (VOID *) (UINTN) BspStore1 M! @- _8 [& R; }8 X4 `% }4 T. N
);
' p+ w2 [* ]2 ~7 u- A3 ~+ E/ i# x% O 用过汇编的人对这个技术一定很熟悉,不多说了(我别不清,咯。。。)
, ? o* B5 Z# L) ~" K8 F8 B
\% U* J5 h# ]4 s2 ^' T/ dDXE:
3 ^8 P! H9 N& @0 @5 c 从PEI到DXE切换时转过来一个HOBLIST参数,DXE会在这个HOB中找到Memory的使用情况,然后根据这些情况将BIOS引到内存(这是EFI的做法)。在EDK在DXE时重新定位一下内存。
2 h/ S8 f$ v Y5 t接着就会定义我们经常使用到的gST表,gRT表。接着是申明一些Protocol(先不关心这些事)。
1 P( q/ K1 E! G, d7 s x0 @+ M 等这些该加的PPI,Protocol加完了,CoreDispatcher()就出场了。他会的功能类似PEIDispatcher()。从我们BIOS ROM中将DXE的驱动读出,执行执行他们,这时会执行到Driver
* I# ^, J. J4 O$ V中的Support(),Start()两个功能函数。在这两个函数中你可以注册自己的PPI,为其他驱动提供服务。
+ t; b) [1 }/ R4 W 到些BIOS的引导其他完成。接着该进OS了,看Linux 0.11吧,操作系统是怎么做事情的。0 F, W, o! R! q
7 a# h5 C' f* h" U4 a( O
Driver:' c o3 d* a7 h& N# p9 |( f
我们的驱动什么为在PEI和DXE等不同阶段执行呢?/ g2 h+ I3 `, r
大家请看一下我们的驱动的makefile.(EDK中的*.inf)
4 B0 g2 N$ L+ E% i C& y ^ [defines]: n/ H, l) b2 k5 ^ {( p6 P0 |3 Z
BASE_NAME = OWEN
9 _1 T1 b+ u5 W, A p FILE_GUID = 1EDD13C1-62EF-4262-A1AA-0040D0830110
. I/ d) b0 ^- N. {3 X$ Q) a COMPONENT_TYPE = BS_DRIVER8 W9 v& ~$ G4 u5 U2 r: [5 {- F2 _
, X( W: b7 X' m BASE_NAME告诉编译器最终生成的驱动的名字。' ?1 j* l2 ]! M* c) S
FILE_GUID就是这个驱动的GUID名字,在BIOS中引用某个驱动就是根据它来调用和识别。4 W3 ]/ E/ P3 k E
COMONENT_TYPE会告诉编译器生成驱动的类型,是PEI,DXE,等。
* b4 b( P k5 T" v3 K4 ?" Y 在EDK中有一个FWVolume.c实现的功能就是帮我们把这个TYPE转换面相应的扩展名
D. j, ~: ], o9 e+ ]4 L1 A COMP_TYPE_EXTENSION mCompTypeExtension[] = {
9 R2 D' c, V' ^+ i {"bs_driver", ".dxe" },
& ?6 ]# ^7 r. P( P5 ~9 ^ {"rt_driver", ".dxe" },
& Q% ^# n, Z( s% P+ b {"sal_rt_driver", ".dxe"},9 @8 B6 o0 y' j D0 _4 J
{"security_core", ".sec"},
: ]' _8 \( f6 b2 N# j6 I! C* {; t {"pei_core", ".pei"},
- `2 ?. Y. ]8 Z! A {"pic_peim", ".pei"},# [ b% e2 i8 t
{"pe32_peim", ".pei"},
; L' w. L$ f+ _" k" B; f {"relocatable_peim", ".pei"},9 [- }, ?% ~: H2 o
{"binary", ".ffs"},6 ]# M' H! l: C% h i$ J
{"application", ".app"},/ [; ^ e$ t1 J- o6 _& _, h
{"file", ".ffs"},6 C$ K; ^. d7 R, ~0 ] H
{"fvimagefile", ".fvi"},
' i# w W* x6 `- a4 w" m1 v, L ] {"rawfile", ".raw"},: x- \0 v! v* P" K6 t/ \
{"apriori", ".ffs"},
$ q' B5 h, g5 d' y) s f W* I' I {"combined_peim_driver", ".pei"},
1 K! c8 _1 \4 U7 l, c { NULL, NULL }1 w2 j$ X. R, \: u' M
};
7 N: A; Y; K4 I. |9 c2 q, x' Z4 n9 X: ^' i2 b! F0 m
了解了这些,接下我们可以看驱动篇了。(Go On Study... Forever)2 a% z! Y+ J8 k
+ L- N1 u4 [1 b
" ^. W2 l) m {- u |
|