|
最近在工作看到机台有启动过程中把SPI ROM数据清空,但苦与没有办法很好的Debug(PCA没有架起来),所有与EDK为对象好好的读了一把。
" l0 g ^1 S- d4 e3 d7 @
1 u) i+ H$ L8 @, H SSEC/CEI:5 l$ ?( ]# U: ?" e* Q; ~
UEFI BIOS启动时先会执行SEC/CEI,这个阶段在实现的BIOS Code中初始化Debug Port,进入Big Mode,CPU的MicroCode,CacheToRAM的转换.然后跳转到PEI阶段。
: N& L0 L3 F( J& Z, ^) v在EDK中这部分被成了Load FvRecovery.fd文件,这个文件类似与我们的BIOS ROM.里面是我们编译后生成的二进制代码。在这个阶段最主要的是将这个文件加载到内存中(Windows API将文件加载到内存,看API函数).1 [1 d8 {( I3 O3 t5 h0 B. ~1 I
4 ]. @4 b7 K+ r% \ p
PEI:
* O1 d& _# d0 s& I7 f- G6 U 从这里开始UEFI BIOS和EDK执行基本相同,只是一个是从SPI ROM中定位一个地址(PEIM的开始地址),一个是从内存中定位一个地址(PEIM的开始地址)。从这里开始只讲EDK的执行. f( {. f" G' S! D: d E4 @
EDK调用InitializeMemoryService函数,将HobList清空,peiservice清空。
6 l9 i7 k* N/ a: X! o InitializePPIService函数,将PPI队列清空,这个队列长0x3F.3 b- e) E# d5 b4 }& e$ o' @/ {
InitializeSercurityService函数,将Notify队列清空。
. @6 W* c( X1 Q* s InitializeDispatcherData函数,将Dispatcher队列清空。
K( C N+ f/ v* e# p& y5 f 接着由PeiBuildHobGuid来建立一个HOB(S3返回时这时应该有这个HOB,不用建立,直接使用了,这样就会进入另外一个流程,可以这个EDK不能调试S3,不知道怎么走)。然后由(*PeiServices)->InstallPpi()将这个新HOB加入到PPI中。) ]* X0 b; r; e$ }' [% Y
由于在SEC阶段转了以下这几具PPI,所以在执行PEI的Dispatcher之前会先安装东西:1 d% ]! d& f8 p' R* }! f, T
EFI_PEI_PPI_DESCRIPTOR gPrivateDispatchTable[] = {
/ C }, h# v4 k. |; e {EFI_PEI_PPI_DESCRIPTOR_PPI, &gEfiNtLoadAsDllPpiGuid, &mSecNtLoadAsDllPpi},
3 P8 z* Y5 Z6 J; z" k' U5 ` {EFI_PEI_PPI_DESCRIPTOR_PPI, &gNtPeiLoadFileGuid, &mSecNtLoadFilePpi},7 J; f7 F% V; N) r: U% v; w
{EFI_PEI_PPI_DESCRIPTOR_PPI, &gPeiNtAutoScanPpiGuid, &mSecNtAutoScanPpi},
) r6 D4 \6 E7 }+ {0 `) v {EFI_PEI_PPI_DESCRIPTOR_PPI, &gPeiNtThunkPpiGuid, &mSecWinNtThunkPpi},
; o2 s5 L/ M0 x8 M+ u8 }( n1 e {EFI_PEI_PPI_DESCRIPTOR_PPI, &gPeiStatusCodePpiGuid, &mSecStatusCodePpi}," w4 `2 _* X# [7 \! T
{EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST, &gNtFwhPpiGuid, &mSecFwhInformationPpi}
" r$ e: K+ Z) R! j% S };* p( }8 e6 N) k5 d* I! m5 x
每个PPI是由{类型,GUID(名字,以后就根据这个来找到它的),Function_Entry_Address}组成。1 u/ p1 M) F8 a( W3 k
这些PPI会在PEIDispatcher中用到。, A0 _- z0 H8 a& Y- m# H+ ^$ I- @/ L
安装完这此东西这开始执行PEIDispatcher函数,函数从BIOS ROM文件中找出PEI的Image(怎么找到,请读一下FV_HEAD(EFI_HEAD),里面讲到了如何区分Image类型),然后定位到PEI Image的入口地址,执行他。在我们的的PEI中,我们一般会申明一个PPI,这个就是这个PEI提供一些服务,PEIDispatcher会将他们加入到PPI-List中,以后其他Image也可以调用他的提供的功能。! s& q# r( @0 k4 c8 H4 ~2 n O
最后EDK会加载一个叫DXEIPL的PEI,DXEIPL提供一个PPI服务,这个PPI的功能是实现从PEI到DXE的切换,这个PPI里面为DXE做了很多的预准备,加载了很多PPI,如对BIOS的解压方法等。/ e' D5 j9 m0 R) f
SwitchStacks (1 p- B' @6 F7 a; x4 N
(VOID *) (UINTN) DxeCoreEntryPoint,8 N/ [2 E# d# J, g0 @) f! W6 F
(UINTN) (HobList.Raw),
9 ? u4 U$ U+ A6 W (VOID *) (UINTN) TopOfStack,
) a$ s# f3 f* J* e (VOID *) (UINTN) BspStore
: p; B. W6 z) |9 O } );
# O( i# j2 e7 x8 O' \3 k% r( I 用过汇编的人对这个技术一定很熟悉,不多说了(我别不清,咯。。。)
* W/ l, D/ i! D. P- @# t9 R. Y8 [) J6 _0 z( P. i
DXE:
7 Y+ e: k" I1 C: L0 s+ _ 从PEI到DXE切换时转过来一个HOBLIST参数,DXE会在这个HOB中找到Memory的使用情况,然后根据这些情况将BIOS引到内存(这是EFI的做法)。在EDK在DXE时重新定位一下内存。5 T. A5 j' g+ |- C9 {$ \& D
接着就会定义我们经常使用到的gST表,gRT表。接着是申明一些Protocol(先不关心这些事)。' k' E0 T7 [$ x6 H) Q
等这些该加的PPI,Protocol加完了,CoreDispatcher()就出场了。他会的功能类似PEIDispatcher()。从我们BIOS ROM中将DXE的驱动读出,执行执行他们,这时会执行到Driver
- K7 {7 T* ]) s中的Support(),Start()两个功能函数。在这两个函数中你可以注册自己的PPI,为其他驱动提供服务。
$ C7 o& S! N; S* v$ ~8 M$ G! A 到些BIOS的引导其他完成。接着该进OS了,看Linux 0.11吧,操作系统是怎么做事情的。
# |( W3 o. [) W ; p2 n0 u" G* `; m/ E
Driver:
8 u' r( `& _. T, o1 e 我们的驱动什么为在PEI和DXE等不同阶段执行呢?
; l3 W7 j7 E- B6 d% L 大家请看一下我们的驱动的makefile.(EDK中的*.inf)
0 U" G7 j$ } Q [defines]: H2 n+ c; Y: N$ P
BASE_NAME = OWEN
' X) ^0 u2 Y" J' G# H6 p FILE_GUID = 1EDD13C1-62EF-4262-A1AA-0040D0830110( _( k- f0 `! h: t$ I5 a
COMPONENT_TYPE = BS_DRIVER2 K2 N4 D' i7 J/ v( _
+ k7 e2 V$ u4 O6 p i
BASE_NAME告诉编译器最终生成的驱动的名字。/ R1 Y% G. T& x2 L+ M1 }- W
FILE_GUID就是这个驱动的GUID名字,在BIOS中引用某个驱动就是根据它来调用和识别。
* V! ^# z( R! t9 p; O1 _ COMONENT_TYPE会告诉编译器生成驱动的类型,是PEI,DXE,等。
$ j5 f8 e$ }$ n( V# R 在EDK中有一个FWVolume.c实现的功能就是帮我们把这个TYPE转换面相应的扩展名
/ }7 `3 S- e1 l0 p9 v COMP_TYPE_EXTENSION mCompTypeExtension[] = {
9 R3 j& u% G+ C: H {"bs_driver", ".dxe" },4 W& u; }( U2 z9 p% F$ R
{"rt_driver", ".dxe" },2 Q' n- r! `" k! Y4 s1 R
{"sal_rt_driver", ".dxe"},- a, H. S5 n7 [, @& A9 N
{"security_core", ".sec"},. {2 d' B. _( b% v3 ?
{"pei_core", ".pei"},
. a% {' D1 l! T8 { {"pic_peim", ".pei"},
5 t8 X7 o- J% d6 i5 E {"pe32_peim", ".pei"},' |' a' g b8 V2 I* I/ u
{"relocatable_peim", ".pei"},
! f \0 i+ @+ `* O2 x$ X% w {"binary", ".ffs"},+ D/ K3 Q7 K$ Z8 o: j- ~ \
{"application", ".app"},/ i( ^6 c; F( W" a8 V4 H& s- N8 V
{"file", ".ffs"},( s ~2 T( S2 z! z2 l5 j
{"fvimagefile", ".fvi"},6 U; _8 u& }5 \ d& Q
{"rawfile", ".raw"},' ~' ?" W, h+ ]' v/ d4 }# w
{"apriori", ".ffs"},
' A+ o( F2 e* V {"combined_peim_driver", ".pei"},
5 ~- _; }) M7 u: o4 k { NULL, NULL }5 b# Y8 s9 i+ ]
};" Q9 k7 h. U) \# G; s, f! V
" {; L$ [# ^7 Z. a6 n- s
了解了这些,接下我们可以看驱动篇了。(Go On Study... Forever)- @& @2 s3 Q- L+ Q
- Z9 f0 `2 A; e% i1 Q
5 c9 P" G, v4 E! z! @( j" N
|
|