|
|
最近在工作看到机台有启动过程中把SPI ROM数据清空,但苦与没有办法很好的Debug(PCA没有架起来),所有与EDK为对象好好的读了一把。: q1 r, p" n4 a3 q" @2 {6 V& i' p0 x
& H, s% t, G c3 _5 ^* G
SEC/CEI:
& h) e" H) F/ q: Z8 P UEFI BIOS启动时先会执行SEC/CEI,这个阶段在实现的BIOS Code中初始化Debug Port,进入Big Mode,CPU的MicroCode,CacheToRAM的转换.然后跳转到PEI阶段。' l2 n0 R4 u: L1 ~
在EDK中这部分被成了Load FvRecovery.fd文件,这个文件类似与我们的BIOS ROM.里面是我们编译后生成的二进制代码。在这个阶段最主要的是将这个文件加载到内存中(Windows API将文件加载到内存,看API函数).
: W2 y, `$ E# e P- j: H+ S: _8 _, N8 R& j) D2 x
PEI:9 y( L4 g. P2 ^( B
从这里开始UEFI BIOS和EDK执行基本相同,只是一个是从SPI ROM中定位一个地址(PEIM的开始地址),一个是从内存中定位一个地址(PEIM的开始地址)。从这里开始只讲EDK的执行1 K! k k2 n% |
EDK调用InitializeMemoryService函数,将HobList清空,peiservice清空。
+ V2 S6 ?: J6 D! y InitializePPIService函数,将PPI队列清空,这个队列长0x3F.2 P: ~' y9 z3 _, P" H
InitializeSercurityService函数,将Notify队列清空。+ \: q: |4 J3 y7 ^( v
InitializeDispatcherData函数,将Dispatcher队列清空。5 E/ S, a# e! q
接着由PeiBuildHobGuid来建立一个HOB(S3返回时这时应该有这个HOB,不用建立,直接使用了,这样就会进入另外一个流程,可以这个EDK不能调试S3,不知道怎么走)。然后由(*PeiServices)->InstallPpi()将这个新HOB加入到PPI中。
6 c3 H0 Y+ v& f {9 X m+ M' F+ L: t 由于在SEC阶段转了以下这几具PPI,所以在执行PEI的Dispatcher之前会先安装东西:
. e+ U1 S( }" @7 z2 C& w EFI_PEI_PPI_DESCRIPTOR gPrivateDispatchTable[] = {' r, n$ N$ a# s4 V
{EFI_PEI_PPI_DESCRIPTOR_PPI, &gEfiNtLoadAsDllPpiGuid, &mSecNtLoadAsDllPpi},- W! }! r6 a1 n0 Z E: A) x
{EFI_PEI_PPI_DESCRIPTOR_PPI, &gNtPeiLoadFileGuid, &mSecNtLoadFilePpi}," J6 b) ]% e" x
{EFI_PEI_PPI_DESCRIPTOR_PPI, &gPeiNtAutoScanPpiGuid, &mSecNtAutoScanPpi},
3 y& `/ A9 M+ C+ N; t. G* r! K {EFI_PEI_PPI_DESCRIPTOR_PPI, &gPeiNtThunkPpiGuid, &mSecWinNtThunkPpi},
' i! Y; r" B5 g {EFI_PEI_PPI_DESCRIPTOR_PPI, &gPeiStatusCodePpiGuid, &mSecStatusCodePpi},
7 K% g9 ~! w1 r {EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST, &gNtFwhPpiGuid, &mSecFwhInformationPpi}& n; C1 R6 A9 h$ e5 n3 E- y+ D% j9 W
};( ?8 B8 L* [2 M- j9 b$ D. a+ {
每个PPI是由{类型,GUID(名字,以后就根据这个来找到它的),Function_Entry_Address}组成。
& I7 y& O9 `3 _$ W+ H- X1 i8 M+ W( U9 o5 \ 这些PPI会在PEIDispatcher中用到。
" |- W% ^$ K3 C! _ 安装完这此东西这开始执行PEIDispatcher函数,函数从BIOS ROM文件中找出PEI的Image(怎么找到,请读一下FV_HEAD(EFI_HEAD),里面讲到了如何区分Image类型),然后定位到PEI Image的入口地址,执行他。在我们的的PEI中,我们一般会申明一个PPI,这个就是这个PEI提供一些服务,PEIDispatcher会将他们加入到PPI-List中,以后其他Image也可以调用他的提供的功能。
0 o* J' `. Y" t 最后EDK会加载一个叫DXEIPL的PEI,DXEIPL提供一个PPI服务,这个PPI的功能是实现从PEI到DXE的切换,这个PPI里面为DXE做了很多的预准备,加载了很多PPI,如对BIOS的解压方法等。
, e1 ^% y7 R! [" h% ]' g. r9 T! a SwitchStacks (% F5 O3 n( |' m) `
(VOID *) (UINTN) DxeCoreEntryPoint,
2 u! F8 K; E* j z (UINTN) (HobList.Raw),) h( `% Q8 {' x" E' K8 x! e7 m
(VOID *) (UINTN) TopOfStack,
" b5 F- p# l/ K" I- c (VOID *) (UINTN) BspStore
: f! O8 E5 }7 l3 k );7 [# ~, _2 R `! _% K
用过汇编的人对这个技术一定很熟悉,不多说了(我别不清,咯。。。) [7 U6 [9 [, Y- ~6 o# ]4 \# n
/ f0 d* Q @) Y
DXE:% b+ p6 z# \+ F, L
从PEI到DXE切换时转过来一个HOBLIST参数,DXE会在这个HOB中找到Memory的使用情况,然后根据这些情况将BIOS引到内存(这是EFI的做法)。在EDK在DXE时重新定位一下内存。
5 `/ ?0 `/ D: Q9 a- N5 k接着就会定义我们经常使用到的gST表,gRT表。接着是申明一些Protocol(先不关心这些事)。
2 K' K6 E. m- y5 x" I/ Y$ W* H 等这些该加的PPI,Protocol加完了,CoreDispatcher()就出场了。他会的功能类似PEIDispatcher()。从我们BIOS ROM中将DXE的驱动读出,执行执行他们,这时会执行到Driver
; {- g# C% z" {) _5 l, h中的Support(),Start()两个功能函数。在这两个函数中你可以注册自己的PPI,为其他驱动提供服务。, c' ]. \: X& v( W) T+ ?, }/ G
到些BIOS的引导其他完成。接着该进OS了,看Linux 0.11吧,操作系统是怎么做事情的。7 g' Q( m! ?4 E& f0 s3 g. {
3 H3 X1 F9 Z/ Z) s( a
Driver:" b( w! U1 M* B! {/ `
我们的驱动什么为在PEI和DXE等不同阶段执行呢?4 V: o8 m) u( N% Z" o
大家请看一下我们的驱动的makefile.(EDK中的*.inf)
: ]6 A. f* U. o' C [defines]
2 l, R8 C' O& u' Q BASE_NAME = OWEN% @& U- A! e+ c) L. \- a
FILE_GUID = 1EDD13C1-62EF-4262-A1AA-0040D0830110; K" f: h, @; i: }
COMPONENT_TYPE = BS_DRIVER$ @; E9 s9 m+ Y2 f
3 y0 t3 U- h6 N% r4 O BASE_NAME告诉编译器最终生成的驱动的名字。
: I. N1 J& f* b9 n, ` FILE_GUID就是这个驱动的GUID名字,在BIOS中引用某个驱动就是根据它来调用和识别。0 v4 g0 @* \7 m0 J$ w& t
COMONENT_TYPE会告诉编译器生成驱动的类型,是PEI,DXE,等。
! g4 K3 U& Y& L: n- o 在EDK中有一个FWVolume.c实现的功能就是帮我们把这个TYPE转换面相应的扩展名, j' L3 i& z q8 O
COMP_TYPE_EXTENSION mCompTypeExtension[] = {
4 X+ u; q$ r( |% i- x: Y- }0 u {"bs_driver", ".dxe" },
6 ~; Q/ q' u \% T( x/ q/ h {"rt_driver", ".dxe" },6 G5 y4 `; J; W9 H, K" L% w
{"sal_rt_driver", ".dxe"},8 j) C3 e; h$ R# {% U
{"security_core", ".sec"},
+ t: k) G. F) Q2 y {"pei_core", ".pei"},
# w, c0 a$ w, U( L2 l% Y8 s4 e2 s {"pic_peim", ".pei"},
% }/ Y" I/ g6 W1 y$ ^ {"pe32_peim", ".pei"},& ]* l+ x* U2 R% E q2 Q
{"relocatable_peim", ".pei"},
. U9 N$ g9 G- s {"binary", ".ffs"},+ J7 P* U3 \8 ^
{"application", ".app"},
$ G% @7 S V& w6 O) x {"file", ".ffs"},
+ R A3 F. [* T+ x, L$ |7 e1 P1 d {"fvimagefile", ".fvi"},
: Q5 ?( d" x& _ {"rawfile", ".raw"},
" y) H9 w% I& C0 M! G) p {"apriori", ".ffs"},
" v" j* N5 i5 H4 M5 ^# M {"combined_peim_driver", ".pei"},
; n$ x: y" u- G { NULL, NULL }
2 f. v1 X9 w/ @' K0 g! @};* S( K, R1 |. h; A% o0 p
( u R v! F1 Z5 T5 A了解了这些,接下我们可以看驱动篇了。(Go On Study... Forever)7 A. i$ d+ `2 C' w, `1 C+ x* \
- x8 Q9 a; D( X6 f1 [' a( @
- {& U5 l: \6 Q& N |
|