|
最近在工作看到机台有启动过程中把SPI ROM数据清空,但苦与没有办法很好的Debug(PCA没有架起来),所有与EDK为对象好好的读了一把。
7 U9 v* j5 ]! n q# r/ E8 O! x) ^$ w5 [* Y5 P2 b
SEC/CEI:& x' V7 M; ] q1 Y8 i- w' m
UEFI BIOS启动时先会执行SEC/CEI,这个阶段在实现的BIOS Code中初始化Debug Port,进入Big Mode,CPU的MicroCode,CacheToRAM的转换.然后跳转到PEI阶段。
. k9 J0 @/ @1 a: }6 W- i在EDK中这部分被成了Load FvRecovery.fd文件,这个文件类似与我们的BIOS ROM.里面是我们编译后生成的二进制代码。在这个阶段最主要的是将这个文件加载到内存中(Windows API将文件加载到内存,看API函数).. C$ h% E9 O2 H/ s
8 _/ E K% U) ?; sPEI:) |5 D: V; Q1 J
从这里开始UEFI BIOS和EDK执行基本相同,只是一个是从SPI ROM中定位一个地址(PEIM的开始地址),一个是从内存中定位一个地址(PEIM的开始地址)。从这里开始只讲EDK的执行 f2 }( F [7 W% B
EDK调用InitializeMemoryService函数,将HobList清空,peiservice清空。
: D! H! |, Y: E. p) e InitializePPIService函数,将PPI队列清空,这个队列长0x3F.
8 P! T2 j& \4 ^( {- v9 l, M InitializeSercurityService函数,将Notify队列清空。
# N' t0 Z' a* Y- ^- L InitializeDispatcherData函数,将Dispatcher队列清空。
0 S: r$ f3 J& } m 接着由PeiBuildHobGuid来建立一个HOB(S3返回时这时应该有这个HOB,不用建立,直接使用了,这样就会进入另外一个流程,可以这个EDK不能调试S3,不知道怎么走)。然后由(*PeiServices)->InstallPpi()将这个新HOB加入到PPI中。9 r1 d6 B/ m4 ?, E8 w0 R
由于在SEC阶段转了以下这几具PPI,所以在执行PEI的Dispatcher之前会先安装东西:" p2 z% c6 a0 F- |/ h
EFI_PEI_PPI_DESCRIPTOR gPrivateDispatchTable[] = {
/ I! _& @0 k8 J {EFI_PEI_PPI_DESCRIPTOR_PPI, &gEfiNtLoadAsDllPpiGuid, &mSecNtLoadAsDllPpi},! ?% X' K% d4 ]
{EFI_PEI_PPI_DESCRIPTOR_PPI, &gNtPeiLoadFileGuid, &mSecNtLoadFilePpi},
" M3 \8 e' u5 n" @8 [; O5 ^ {EFI_PEI_PPI_DESCRIPTOR_PPI, &gPeiNtAutoScanPpiGuid, &mSecNtAutoScanPpi}," H7 D3 r; J8 U0 O" q+ x. \6 [
{EFI_PEI_PPI_DESCRIPTOR_PPI, &gPeiNtThunkPpiGuid, &mSecWinNtThunkPpi},
! [: N/ e$ ?* i5 Q {EFI_PEI_PPI_DESCRIPTOR_PPI, &gPeiStatusCodePpiGuid, &mSecStatusCodePpi},
) _" U4 f9 \2 r8 R" S; l {EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST, &gNtFwhPpiGuid, &mSecFwhInformationPpi}
- m* N! y, `3 X };, V/ K' }8 c0 D8 ~ h, e' I3 q" j
每个PPI是由{类型,GUID(名字,以后就根据这个来找到它的),Function_Entry_Address}组成。9 C( m4 E% ?+ g
这些PPI会在PEIDispatcher中用到。
" S- T: V* T8 P+ ?/ Q 安装完这此东西这开始执行PEIDispatcher函数,函数从BIOS ROM文件中找出PEI的Image(怎么找到,请读一下FV_HEAD(EFI_HEAD),里面讲到了如何区分Image类型),然后定位到PEI Image的入口地址,执行他。在我们的的PEI中,我们一般会申明一个PPI,这个就是这个PEI提供一些服务,PEIDispatcher会将他们加入到PPI-List中,以后其他Image也可以调用他的提供的功能。( j6 T4 E$ Y" K1 r R2 K
最后EDK会加载一个叫DXEIPL的PEI,DXEIPL提供一个PPI服务,这个PPI的功能是实现从PEI到DXE的切换,这个PPI里面为DXE做了很多的预准备,加载了很多PPI,如对BIOS的解压方法等。. f: s% R7 I" _5 Q' c/ t
SwitchStacks (' ]1 N% Y% i+ K2 l) e4 R
(VOID *) (UINTN) DxeCoreEntryPoint,0 J. ^* h8 z% h6 K* V
(UINTN) (HobList.Raw),1 o: m; _+ ^- k3 }
(VOID *) (UINTN) TopOfStack,
" T, c& x$ Z E+ l V (VOID *) (UINTN) BspStore9 w, M! z+ M# n! \5 ~; I
);& k) Q7 ]2 Z4 U9 h% ]: O
用过汇编的人对这个技术一定很熟悉,不多说了(我别不清,咯。。。)
) e2 H0 n- ?; ? M( t/ l. F; L1 k# C, W: {- J) J% [0 r
DXE:8 M9 V+ C1 E( Q$ F, c* }) {* W
从PEI到DXE切换时转过来一个HOBLIST参数,DXE会在这个HOB中找到Memory的使用情况,然后根据这些情况将BIOS引到内存(这是EFI的做法)。在EDK在DXE时重新定位一下内存。3 m/ Y. ?/ W2 Z. `
接着就会定义我们经常使用到的gST表,gRT表。接着是申明一些Protocol(先不关心这些事)。
: [! n# S( V. k6 N) t+ n" H 等这些该加的PPI,Protocol加完了,CoreDispatcher()就出场了。他会的功能类似PEIDispatcher()。从我们BIOS ROM中将DXE的驱动读出,执行执行他们,这时会执行到Driver
1 e% G8 ?, c, Q4 k' E# E3 X1 i+ u中的Support(),Start()两个功能函数。在这两个函数中你可以注册自己的PPI,为其他驱动提供服务。4 C! Q' H( M3 e, a- |5 M
到些BIOS的引导其他完成。接着该进OS了,看Linux 0.11吧,操作系统是怎么做事情的。4 Y0 f: i* \' {6 U( t: ^0 a3 J
' ]* W) {0 Q+ n4 y
Driver:8 D+ i8 I9 @, [5 v
我们的驱动什么为在PEI和DXE等不同阶段执行呢?6 P; c: B, q. R2 p6 D# w B4 S( t! h
大家请看一下我们的驱动的makefile.(EDK中的*.inf)2 \" e$ }$ M- ?! L
[defines]' P# @: o9 W/ A
BASE_NAME = OWEN9 a, _# m1 p% S4 G. u6 z0 a
FILE_GUID = 1EDD13C1-62EF-4262-A1AA-0040D0830110# S0 V4 y4 r3 M
COMPONENT_TYPE = BS_DRIVER
+ o" ]3 x, z. i- E7 o/ t! c; O# \4 @& ~+ @- W d9 Q- M" x
BASE_NAME告诉编译器最终生成的驱动的名字。
: M5 }5 E* @9 |$ V0 Y FILE_GUID就是这个驱动的GUID名字,在BIOS中引用某个驱动就是根据它来调用和识别。
5 Q6 X2 Y/ U/ a9 i/ f5 K+ v% T% ~ COMONENT_TYPE会告诉编译器生成驱动的类型,是PEI,DXE,等。, o7 C2 z& w9 @. Q# @
在EDK中有一个FWVolume.c实现的功能就是帮我们把这个TYPE转换面相应的扩展名: t7 s0 ~# y, B1 z* M, [' N$ N8 a4 g3 J
COMP_TYPE_EXTENSION mCompTypeExtension[] = {# e* Y( ]! }2 P7 K6 u, v
{"bs_driver", ".dxe" },
9 o" ~5 `, Y1 J$ T1 h {"rt_driver", ".dxe" },0 z9 W# Z% E9 ?- I5 @
{"sal_rt_driver", ".dxe"},* y+ S2 ~$ }! _ e( t4 U# Q
{"security_core", ".sec"},* X2 H) X" O8 E! v9 D/ k: y N
{"pei_core", ".pei"},' Y' H, m9 g5 t& s; G) B% t: Z- S7 A
{"pic_peim", ".pei"},
0 n0 K8 z3 S+ M3 e {"pe32_peim", ".pei"},
9 f; o# N. s3 Q {"relocatable_peim", ".pei"},
$ C' M0 ]1 a. i" V5 p {"binary", ".ffs"},8 x/ ?8 u$ ]3 t. g9 z6 `$ ?! E
{"application", ".app"},0 O0 f/ B4 e% t6 d
{"file", ".ffs"},$ l' ~! V6 r* J! J$ k% h
{"fvimagefile", ".fvi"},$ |- g9 q2 r% D) v L+ e' `$ H# y
{"rawfile", ".raw"},) |- s. o" E! P# }2 K( u8 B D
{"apriori", ".ffs"},! P1 k) e: v/ p3 c) C5 J: }0 n
{"combined_peim_driver", ".pei"},- A+ u$ `( B, F: T" m0 T% q; I
{ NULL, NULL }
0 P. j( w! ]6 l( U( y; k- z};
3 s. ?. A% M' X0 s+ r; v
1 p: B. A6 f: _了解了这些,接下我们可以看驱动篇了。(Go On Study... Forever)4 B4 r1 X! \1 Y3 J. W) Z, z$ H; T
8 u% j% R$ o! K
+ j3 o$ \* x" h |
|