|
最近在工作看到机台有启动过程中把SPI ROM数据清空,但苦与没有办法很好的Debug(PCA没有架起来),所有与EDK为对象好好的读了一把。) `' s7 \3 p9 g: c
; \7 c, m4 @& K' ?7 MSEC/CEI:8 l/ _, z8 H9 z
UEFI BIOS启动时先会执行SEC/CEI,这个阶段在实现的BIOS Code中初始化Debug Port,进入Big Mode,CPU的MicroCode,CacheToRAM的转换.然后跳转到PEI阶段。7 U5 D" S$ ^) M* A+ W1 T6 E
在EDK中这部分被成了Load FvRecovery.fd文件,这个文件类似与我们的BIOS ROM.里面是我们编译后生成的二进制代码。在这个阶段最主要的是将这个文件加载到内存中(Windows API将文件加载到内存,看API函数).# D8 Q% O+ b2 P3 z
% k2 z' V- z3 ^) ]; ~7 F. R& t
PEI:
+ x* D! ~: H: N8 h. V 从这里开始UEFI BIOS和EDK执行基本相同,只是一个是从SPI ROM中定位一个地址(PEIM的开始地址),一个是从内存中定位一个地址(PEIM的开始地址)。从这里开始只讲EDK的执行9 R: m/ S6 G) x0 I) P
EDK调用InitializeMemoryService函数,将HobList清空,peiservice清空。4 g0 B4 t4 V+ U0 @& Z1 ?# P+ u( F
InitializePPIService函数,将PPI队列清空,这个队列长0x3F.
- h8 n( z: U( c1 |4 P5 H InitializeSercurityService函数,将Notify队列清空。
7 i( K: k7 w& O F: V InitializeDispatcherData函数,将Dispatcher队列清空。
$ Z1 Y+ L& J+ ` |5 w 接着由PeiBuildHobGuid来建立一个HOB(S3返回时这时应该有这个HOB,不用建立,直接使用了,这样就会进入另外一个流程,可以这个EDK不能调试S3,不知道怎么走)。然后由(*PeiServices)->InstallPpi()将这个新HOB加入到PPI中。
% l! @3 \- f7 t 由于在SEC阶段转了以下这几具PPI,所以在执行PEI的Dispatcher之前会先安装东西:7 Z( d, D1 `( o7 K. J6 `
EFI_PEI_PPI_DESCRIPTOR gPrivateDispatchTable[] = {
j4 I. T- d6 c# B& Z {EFI_PEI_PPI_DESCRIPTOR_PPI, &gEfiNtLoadAsDllPpiGuid, &mSecNtLoadAsDllPpi},
3 J5 J0 M# E6 \; A1 l {EFI_PEI_PPI_DESCRIPTOR_PPI, &gNtPeiLoadFileGuid, &mSecNtLoadFilePpi},
+ _% s8 B* y/ j9 I {EFI_PEI_PPI_DESCRIPTOR_PPI, &gPeiNtAutoScanPpiGuid, &mSecNtAutoScanPpi},
9 r. C8 q3 q- L. G8 f1 b$ G! e {EFI_PEI_PPI_DESCRIPTOR_PPI, &gPeiNtThunkPpiGuid, &mSecWinNtThunkPpi},
! @) q7 P( J; p3 }, F2 Y4 ]0 b {EFI_PEI_PPI_DESCRIPTOR_PPI, &gPeiStatusCodePpiGuid, &mSecStatusCodePpi},
$ a f/ G5 G! A) R* ]# ^ {EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST, &gNtFwhPpiGuid, &mSecFwhInformationPpi}
, B% J( t" a6 u" Y* ^" L6 D7 U };% g* o h0 F, h, ^8 Z( I
每个PPI是由{类型,GUID(名字,以后就根据这个来找到它的),Function_Entry_Address}组成。
# E" b& i7 c& m0 j$ |7 A 这些PPI会在PEIDispatcher中用到。1 e$ T' s# h2 y9 F U
安装完这此东西这开始执行PEIDispatcher函数,函数从BIOS ROM文件中找出PEI的Image(怎么找到,请读一下FV_HEAD(EFI_HEAD),里面讲到了如何区分Image类型),然后定位到PEI Image的入口地址,执行他。在我们的的PEI中,我们一般会申明一个PPI,这个就是这个PEI提供一些服务,PEIDispatcher会将他们加入到PPI-List中,以后其他Image也可以调用他的提供的功能。) H3 m1 c! b( J+ p
最后EDK会加载一个叫DXEIPL的PEI,DXEIPL提供一个PPI服务,这个PPI的功能是实现从PEI到DXE的切换,这个PPI里面为DXE做了很多的预准备,加载了很多PPI,如对BIOS的解压方法等。7 P6 s5 _: `5 o y; u7 T
SwitchStacks (
; ~6 c; x% h8 V1 E (VOID *) (UINTN) DxeCoreEntryPoint,$ t- _' S# \ `! p
(UINTN) (HobList.Raw),
) K! P+ b6 R3 t* x0 b2 D (VOID *) (UINTN) TopOfStack,1 s* C2 n2 I- P3 f
(VOID *) (UINTN) BspStore+ q7 H0 D' h$ f& x1 W2 m
);' j: J! D i: {; j2 L. d+ u, s( n
用过汇编的人对这个技术一定很熟悉,不多说了(我别不清,咯。。。). a' g% x0 \' U) j# f9 {
, [! N+ D. Y" |DXE:$ Y2 }2 y0 ] e3 G
从PEI到DXE切换时转过来一个HOBLIST参数,DXE会在这个HOB中找到Memory的使用情况,然后根据这些情况将BIOS引到内存(这是EFI的做法)。在EDK在DXE时重新定位一下内存。
9 Q4 J: c7 ~' P0 r3 {: X% l. Y: u接着就会定义我们经常使用到的gST表,gRT表。接着是申明一些Protocol(先不关心这些事)。# A2 Y/ f: U. n7 N+ E' O3 }6 }
等这些该加的PPI,Protocol加完了,CoreDispatcher()就出场了。他会的功能类似PEIDispatcher()。从我们BIOS ROM中将DXE的驱动读出,执行执行他们,这时会执行到Driver+ @2 |( j" o0 Q
中的Support(),Start()两个功能函数。在这两个函数中你可以注册自己的PPI,为其他驱动提供服务。
1 k, k4 X8 n% z" p) B3 r* \, D 到些BIOS的引导其他完成。接着该进OS了,看Linux 0.11吧,操作系统是怎么做事情的。
4 x- [2 g( q- g . {5 Z3 D" O* y) H/ C2 G
Driver:, f0 X* X0 O( @* x, b1 P
我们的驱动什么为在PEI和DXE等不同阶段执行呢?0 s4 l& Z7 A: T0 s1 Z0 c
大家请看一下我们的驱动的makefile.(EDK中的*.inf)( v* ~# b/ f" V9 @; e
[defines]
1 K' }" l5 L5 ~! O2 Q4 f F `5 a BASE_NAME = OWEN+ V5 r0 ?' ?* g0 i* S
FILE_GUID = 1EDD13C1-62EF-4262-A1AA-0040D0830110
0 i( A4 I* Q% w8 x0 l4 s COMPONENT_TYPE = BS_DRIVER
/ ] y! h1 I5 R% b, m- c9 R: Z% n
BASE_NAME告诉编译器最终生成的驱动的名字。
% y+ V! H* h& k9 A1 F' a FILE_GUID就是这个驱动的GUID名字,在BIOS中引用某个驱动就是根据它来调用和识别。# w! b' d! S" B. X' b9 u
COMONENT_TYPE会告诉编译器生成驱动的类型,是PEI,DXE,等。7 T& @/ e7 L, q
在EDK中有一个FWVolume.c实现的功能就是帮我们把这个TYPE转换面相应的扩展名
' u8 E6 ]- V: R" G3 E6 L" T# a COMP_TYPE_EXTENSION mCompTypeExtension[] = {
( ]* f& x! z, ~4 q( o2 i {"bs_driver", ".dxe" }," g- t$ d! X! f- J4 o/ n) n
{"rt_driver", ".dxe" },3 o- T% m: O8 N' Y8 s
{"sal_rt_driver", ".dxe"},
9 x$ r% T# B+ R {"security_core", ".sec"},% W/ x3 l9 z% s& L- x3 V4 P' E
{"pei_core", ".pei"},$ B. Y+ G. S* s: O) X0 d. |$ @
{"pic_peim", ".pei"},6 S# m K: v: |( c- r2 z
{"pe32_peim", ".pei"},
7 j! `8 f& ?; X' q$ B2 Z0 }% r {"relocatable_peim", ".pei"}, _: n9 V0 T6 [" J0 Z0 f
{"binary", ".ffs"},% ?3 u8 b# Z4 C7 Z0 V. o
{"application", ".app"},( `6 n! g9 d+ T: I9 D
{"file", ".ffs"},
3 R; W$ @+ C) G4 x7 ^7 l {"fvimagefile", ".fvi"},; C: v \+ p; M& D! j6 \
{"rawfile", ".raw"},
1 W% t! h* `! l- I {"apriori", ".ffs"},) R, m: h, b$ x1 \5 K8 ^ f
{"combined_peim_driver", ".pei"}," y( A, j0 n$ j! X* C1 Z
{ NULL, NULL }
9 s$ s" a5 @+ N5 K) { x0 D};
! w/ v' N) k6 c1 u) a! _% i7 _, y1 ~( ?! o& n3 x
了解了这些,接下我们可以看驱动篇了。(Go On Study... Forever)
: {; @4 n5 m6 q# ^/ ~
; J1 [: y3 ^+ D$ I/ @( H* j. I; P
# ~. J& P0 C0 H5 l n/ @ |
|