|
最近在工作看到机台有启动过程中把SPI ROM数据清空,但苦与没有办法很好的Debug(PCA没有架起来),所有与EDK为对象好好的读了一把。
; `& H5 S* V( q0 A3 W7 p. }: A+ U) R
SEC/CEI:) T: a- p7 i2 X* _- q
UEFI BIOS启动时先会执行SEC/CEI,这个阶段在实现的BIOS Code中初始化Debug Port,进入Big Mode,CPU的MicroCode,CacheToRAM的转换.然后跳转到PEI阶段。6 q/ h: g+ T4 _; p* L* X
在EDK中这部分被成了Load FvRecovery.fd文件,这个文件类似与我们的BIOS ROM.里面是我们编译后生成的二进制代码。在这个阶段最主要的是将这个文件加载到内存中(Windows API将文件加载到内存,看API函数).: }% }: X% u$ R
0 g* D0 y. ^+ @( T+ I- b2 o
PEI:6 t& @6 _) m( ^$ V# c
从这里开始UEFI BIOS和EDK执行基本相同,只是一个是从SPI ROM中定位一个地址(PEIM的开始地址),一个是从内存中定位一个地址(PEIM的开始地址)。从这里开始只讲EDK的执行; y5 O O8 K. E" G& s# M1 R
EDK调用InitializeMemoryService函数,将HobList清空,peiservice清空。
9 H$ D! X/ ]& z( V) k6 ~ InitializePPIService函数,将PPI队列清空,这个队列长0x3F.
4 f0 \2 l+ B) M+ N; _8 D InitializeSercurityService函数,将Notify队列清空。 s+ Q& _9 Z% I6 b' C$ p
InitializeDispatcherData函数,将Dispatcher队列清空。
, H4 b! Z% r0 S5 X9 ~ 接着由PeiBuildHobGuid来建立一个HOB(S3返回时这时应该有这个HOB,不用建立,直接使用了,这样就会进入另外一个流程,可以这个EDK不能调试S3,不知道怎么走)。然后由(*PeiServices)->InstallPpi()将这个新HOB加入到PPI中。' j) t' H0 K8 h2 Y2 r
由于在SEC阶段转了以下这几具PPI,所以在执行PEI的Dispatcher之前会先安装东西:( \0 d* C( B9 y( L* |! X+ A: N
EFI_PEI_PPI_DESCRIPTOR gPrivateDispatchTable[] = {; K) ]+ c2 g8 i* \: {9 O! Y+ M
{EFI_PEI_PPI_DESCRIPTOR_PPI, &gEfiNtLoadAsDllPpiGuid, &mSecNtLoadAsDllPpi}," {& T' |3 q1 r7 T0 p+ N1 H/ q
{EFI_PEI_PPI_DESCRIPTOR_PPI, &gNtPeiLoadFileGuid, &mSecNtLoadFilePpi},
3 H1 P: Q. t5 _9 _" p8 n {EFI_PEI_PPI_DESCRIPTOR_PPI, &gPeiNtAutoScanPpiGuid, &mSecNtAutoScanPpi},% Z/ k3 }' g2 K8 D9 N
{EFI_PEI_PPI_DESCRIPTOR_PPI, &gPeiNtThunkPpiGuid, &mSecWinNtThunkPpi},
* W1 F/ l- G8 K" v {EFI_PEI_PPI_DESCRIPTOR_PPI, &gPeiStatusCodePpiGuid, &mSecStatusCodePpi},
u9 O* R5 A% M$ Y7 S+ f: U( L3 e) `% e {EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST, &gNtFwhPpiGuid, &mSecFwhInformationPpi}; R6 g, y3 E% L. T( ~8 d
}; I: A5 q8 a) W! K, t7 L/ e
每个PPI是由{类型,GUID(名字,以后就根据这个来找到它的),Function_Entry_Address}组成。
9 v* z& I" N) ` 这些PPI会在PEIDispatcher中用到。8 ] Q* Q8 ^ P* D
安装完这此东西这开始执行PEIDispatcher函数,函数从BIOS ROM文件中找出PEI的Image(怎么找到,请读一下FV_HEAD(EFI_HEAD),里面讲到了如何区分Image类型),然后定位到PEI Image的入口地址,执行他。在我们的的PEI中,我们一般会申明一个PPI,这个就是这个PEI提供一些服务,PEIDispatcher会将他们加入到PPI-List中,以后其他Image也可以调用他的提供的功能。
@3 y% k0 ]% F* U8 v, s- b# K2 v 最后EDK会加载一个叫DXEIPL的PEI,DXEIPL提供一个PPI服务,这个PPI的功能是实现从PEI到DXE的切换,这个PPI里面为DXE做了很多的预准备,加载了很多PPI,如对BIOS的解压方法等。" T) G6 B) k3 A8 ]
SwitchStacks (0 ~% X% S) a# e# x. @) M- V
(VOID *) (UINTN) DxeCoreEntryPoint,
+ S, \) t* X, v0 f1 [' U) h' S! \ (UINTN) (HobList.Raw),% Y' z- j u1 q$ F) i
(VOID *) (UINTN) TopOfStack,
6 W% L- Q% j- A9 a8 e, D/ k (VOID *) (UINTN) BspStore
3 n) F9 r4 n# B) C$ D4 q4 ~ );
. j" O+ i) Y" Y! e5 H* l 用过汇编的人对这个技术一定很熟悉,不多说了(我别不清,咯。。。)2 B* ^4 G0 {: f* N q: r9 V+ s, l
6 g# u; \* R: a0 F$ O" b, T; BDXE:+ w" R* F1 V0 P% h
从PEI到DXE切换时转过来一个HOBLIST参数,DXE会在这个HOB中找到Memory的使用情况,然后根据这些情况将BIOS引到内存(这是EFI的做法)。在EDK在DXE时重新定位一下内存。
9 j' }( X. c: R; J接着就会定义我们经常使用到的gST表,gRT表。接着是申明一些Protocol(先不关心这些事)。
h. L {! p# { 等这些该加的PPI,Protocol加完了,CoreDispatcher()就出场了。他会的功能类似PEIDispatcher()。从我们BIOS ROM中将DXE的驱动读出,执行执行他们,这时会执行到Driver$ ], q+ I$ k$ f: ~+ ]/ Z' R
中的Support(),Start()两个功能函数。在这两个函数中你可以注册自己的PPI,为其他驱动提供服务。
$ g3 I5 Q: V+ c. T; i1 x 到些BIOS的引导其他完成。接着该进OS了,看Linux 0.11吧,操作系统是怎么做事情的。
) A) c. {. C: @/ H s8 r . d: N2 A: y- e, W! N0 S
Driver:
- O- {/ z* K }. t8 S 我们的驱动什么为在PEI和DXE等不同阶段执行呢?
0 I$ x" o$ y; c 大家请看一下我们的驱动的makefile.(EDK中的*.inf)" X3 e% x; t: |
[defines]
5 B3 K( o2 x( F BASE_NAME = OWEN
; j) `& w2 [- g5 B1 Q FILE_GUID = 1EDD13C1-62EF-4262-A1AA-0040D08301103 g: d/ W: h# x- l6 v
COMPONENT_TYPE = BS_DRIVER
8 ~' p+ j2 B9 F& B7 ^# N/ X
7 v$ e2 C1 w: u- r3 a" A BASE_NAME告诉编译器最终生成的驱动的名字。; g& x* f u9 `% N6 }
FILE_GUID就是这个驱动的GUID名字,在BIOS中引用某个驱动就是根据它来调用和识别。
3 F# A) C6 v* x: i" I8 w( o2 v COMONENT_TYPE会告诉编译器生成驱动的类型,是PEI,DXE,等。
) F. R: Y8 b& Z! c' t 在EDK中有一个FWVolume.c实现的功能就是帮我们把这个TYPE转换面相应的扩展名
5 O: D& Z! @) e; k- e; M& o. k2 x; H COMP_TYPE_EXTENSION mCompTypeExtension[] = {' x. _8 J5 z4 `) M
{"bs_driver", ".dxe" },5 @$ ^' r& u1 W' J2 s# z3 d
{"rt_driver", ".dxe" },. s I& u) A+ G" F# v1 E
{"sal_rt_driver", ".dxe"},' u+ ]4 L4 R }4 I1 X: R& S
{"security_core", ".sec"},
0 ?+ U: Y! U4 u7 K$ h+ q {"pei_core", ".pei"},
S+ r3 m2 ~5 O7 q( c. g {"pic_peim", ".pei"},
. V2 w% I$ v0 T% t4 m9 o% J {"pe32_peim", ".pei"},, u6 x# a, h7 P& S. T
{"relocatable_peim", ".pei"},
& b3 ^. |, B9 L( x- a {"binary", ".ffs"}," F0 t Q% X1 l6 ]# `
{"application", ".app"},9 R6 [: q7 I3 ]# Y- {' M% v
{"file", ".ffs"}, P# O5 n9 B% S1 P. \2 }( r9 F
{"fvimagefile", ".fvi"}," \+ Q! U& U1 h' g7 R5 U
{"rawfile", ".raw"},+ k2 j% j* p; u. {7 k; m( H4 ?
{"apriori", ".ffs"},
, W/ ~& \4 x, y" G {"combined_peim_driver", ".pei"},
5 j$ u+ W$ L( U% y1 W+ S { NULL, NULL }
- u* f; ]& C1 S- C7 ^) e5 Z! w};2 R: I. K% N( k) p: A
" G+ ?) X, |* R( `# A5 [6 Y" x* {
了解了这些,接下我们可以看驱动篇了。(Go On Study... Forever)6 m% p% D. _; k* T. S
; I* C0 U1 j( H A8 o
) s6 K: S. T& A% h: A4 s' y: r |
|