|
|
最近在工作看到机台有启动过程中把SPI ROM数据清空,但苦与没有办法很好的Debug(PCA没有架起来),所有与EDK为对象好好的读了一把。
" f2 }0 N$ Y7 o4 A( v( `
* k! _, u: M1 J7 p. d# vSEC/CEI:
/ A( `; k) G( |& {+ M. B1 M- _ UEFI BIOS启动时先会执行SEC/CEI,这个阶段在实现的BIOS Code中初始化Debug Port,进入Big Mode,CPU的MicroCode,CacheToRAM的转换.然后跳转到PEI阶段。 @; t+ |) z# m3 z4 }# @8 ?
在EDK中这部分被成了Load FvRecovery.fd文件,这个文件类似与我们的BIOS ROM.里面是我们编译后生成的二进制代码。在这个阶段最主要的是将这个文件加载到内存中(Windows API将文件加载到内存,看API函数).+ w$ `% w# ^: `3 ^ s$ Z* H
! L+ {2 n( K0 W# a& P% c
PEI:
. K2 w6 }- W8 i* B 从这里开始UEFI BIOS和EDK执行基本相同,只是一个是从SPI ROM中定位一个地址(PEIM的开始地址),一个是从内存中定位一个地址(PEIM的开始地址)。从这里开始只讲EDK的执行
2 a( L6 w7 o% } EDK调用InitializeMemoryService函数,将HobList清空,peiservice清空。& z; f" B. a$ a) w; d* e& F
InitializePPIService函数,将PPI队列清空,这个队列长0x3F.( p- \7 S+ q0 V2 t, |
InitializeSercurityService函数,将Notify队列清空。 w. l3 H2 U5 ^$ c( N
InitializeDispatcherData函数,将Dispatcher队列清空。
2 i/ o1 x+ r# B/ z! ~( D 接着由PeiBuildHobGuid来建立一个HOB(S3返回时这时应该有这个HOB,不用建立,直接使用了,这样就会进入另外一个流程,可以这个EDK不能调试S3,不知道怎么走)。然后由(*PeiServices)->InstallPpi()将这个新HOB加入到PPI中。9 z1 h7 S5 W; }% b7 @( W
由于在SEC阶段转了以下这几具PPI,所以在执行PEI的Dispatcher之前会先安装东西:1 V9 W1 U+ x0 Y5 Z8 h! h
EFI_PEI_PPI_DESCRIPTOR gPrivateDispatchTable[] = {. M) |3 x2 D( \+ W
{EFI_PEI_PPI_DESCRIPTOR_PPI, &gEfiNtLoadAsDllPpiGuid, &mSecNtLoadAsDllPpi},! V. y" H7 E( p( e8 K- e
{EFI_PEI_PPI_DESCRIPTOR_PPI, &gNtPeiLoadFileGuid, &mSecNtLoadFilePpi},7 E1 D- d) Q2 o& p0 @8 @- u& P: L6 ~
{EFI_PEI_PPI_DESCRIPTOR_PPI, &gPeiNtAutoScanPpiGuid, &mSecNtAutoScanPpi},
v0 a+ l' G; K" Q' @' F {EFI_PEI_PPI_DESCRIPTOR_PPI, &gPeiNtThunkPpiGuid, &mSecWinNtThunkPpi},
; h7 r1 h3 P7 k- ]# d9 m {EFI_PEI_PPI_DESCRIPTOR_PPI, &gPeiStatusCodePpiGuid, &mSecStatusCodePpi},& D, Q( w; t0 b: O$ S
{EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST, &gNtFwhPpiGuid, &mSecFwhInformationPpi}, ?- z* n/ C/ R9 y
};9 M- w5 D3 Y6 Z+ V2 }: n
每个PPI是由{类型,GUID(名字,以后就根据这个来找到它的),Function_Entry_Address}组成。/ M( u+ E; e& j' M6 A% p
这些PPI会在PEIDispatcher中用到。
6 h+ c( L( v0 E }5 ~ 安装完这此东西这开始执行PEIDispatcher函数,函数从BIOS ROM文件中找出PEI的Image(怎么找到,请读一下FV_HEAD(EFI_HEAD),里面讲到了如何区分Image类型),然后定位到PEI Image的入口地址,执行他。在我们的的PEI中,我们一般会申明一个PPI,这个就是这个PEI提供一些服务,PEIDispatcher会将他们加入到PPI-List中,以后其他Image也可以调用他的提供的功能。
6 u0 \; D3 \) l3 r 最后EDK会加载一个叫DXEIPL的PEI,DXEIPL提供一个PPI服务,这个PPI的功能是实现从PEI到DXE的切换,这个PPI里面为DXE做了很多的预准备,加载了很多PPI,如对BIOS的解压方法等。
% C% D# H% H T j7 E, B SwitchStacks (
" x1 [8 x ^8 }* Q0 e& E (VOID *) (UINTN) DxeCoreEntryPoint,& r: W9 j* }5 S1 f
(UINTN) (HobList.Raw),
0 Z F1 C2 U+ d& i9 V. E( t (VOID *) (UINTN) TopOfStack,+ h# H0 |: [1 t1 Z
(VOID *) (UINTN) BspStore
. S/ T# [! X) f( `" C1 ~! ]" L+ @ );% @: H& K9 W# D+ ^$ z5 i% M+ v5 j
用过汇编的人对这个技术一定很熟悉,不多说了(我别不清,咯。。。)
7 g9 E' m* e& Y& i- @6 g$ l$ i8 q+ Q3 _) q7 H5 B& V3 o/ c4 N
DXE:6 j0 A6 i6 D2 ^9 ^2 l( O
从PEI到DXE切换时转过来一个HOBLIST参数,DXE会在这个HOB中找到Memory的使用情况,然后根据这些情况将BIOS引到内存(这是EFI的做法)。在EDK在DXE时重新定位一下内存。: @/ {; g" Q( ?
接着就会定义我们经常使用到的gST表,gRT表。接着是申明一些Protocol(先不关心这些事)。
+ V$ ~7 v- x- N1 P- x' `9 v 等这些该加的PPI,Protocol加完了,CoreDispatcher()就出场了。他会的功能类似PEIDispatcher()。从我们BIOS ROM中将DXE的驱动读出,执行执行他们,这时会执行到Driver
2 z6 b4 }& q4 i中的Support(),Start()两个功能函数。在这两个函数中你可以注册自己的PPI,为其他驱动提供服务。
8 A9 l/ @/ N$ P 到些BIOS的引导其他完成。接着该进OS了,看Linux 0.11吧,操作系统是怎么做事情的。
' x; F1 Z! k% }* d
. m( f& O" Q* L$ Z4 tDriver:
/ C8 T/ H6 { w+ T. s 我们的驱动什么为在PEI和DXE等不同阶段执行呢?' u9 B: U, X$ ~, b
大家请看一下我们的驱动的makefile.(EDK中的*.inf)
) z. M# p9 Z/ C; ^ [defines]* N% l; X% S0 i, `3 _, a1 g. D, a4 X
BASE_NAME = OWEN1 p# @0 b% r3 \! l( m0 u
FILE_GUID = 1EDD13C1-62EF-4262-A1AA-0040D0830110
. N5 T8 r- i$ ^* Z; n8 o COMPONENT_TYPE = BS_DRIVER1 s/ R O$ {& w$ G& N" L; f
. a. V0 @" Y& E" ?$ [+ T- y3 H: O BASE_NAME告诉编译器最终生成的驱动的名字。2 @: G2 | i9 |2 E( h7 J; [: }
FILE_GUID就是这个驱动的GUID名字,在BIOS中引用某个驱动就是根据它来调用和识别。 R5 @+ l8 k5 T; b% _
COMONENT_TYPE会告诉编译器生成驱动的类型,是PEI,DXE,等。3 M3 L/ D' m6 S0 R3 b" a) K$ `% Z
在EDK中有一个FWVolume.c实现的功能就是帮我们把这个TYPE转换面相应的扩展名
* f9 g7 {! ?# x: b4 _" G$ u COMP_TYPE_EXTENSION mCompTypeExtension[] = {
k1 E' n: s0 C# h {"bs_driver", ".dxe" },1 B( i( T8 h# {+ }1 o
{"rt_driver", ".dxe" },% S8 U5 y6 P5 ~) E6 u7 g/ S
{"sal_rt_driver", ".dxe"},
7 y: \2 r- ?3 Z; f" A! L% {, T {"security_core", ".sec"},& f% a9 K, r8 H! \3 x
{"pei_core", ".pei"},( e+ ]0 Z S5 t7 `1 W: b* F' T& g
{"pic_peim", ".pei"},
p0 o/ b% v. \7 z h$ u" I2 N {"pe32_peim", ".pei"},, ?: p6 K+ w/ a! o5 J
{"relocatable_peim", ".pei"},
. }6 l# O; b* u6 i {"binary", ".ffs"},' r4 u( X+ _1 O' Z( \
{"application", ".app"},
6 d! N1 Z2 v: r2 V {"file", ".ffs"},
3 K9 S) E5 A% c- T5 y n {"fvimagefile", ".fvi"},4 i, i- ^: r. {9 L4 I
{"rawfile", ".raw"},+ C3 H; U) @, f( C$ \: G
{"apriori", ".ffs"},
7 z9 T/ D; v8 j- d# ~. m6 \ {"combined_peim_driver", ".pei"},% c1 L/ D! Q. G1 F+ C
{ NULL, NULL }; W7 a `& J. R4 P- Q3 B% ^
};
' n6 T& {& ]! ^: G4 p" v2 t9 [, C0 O5 N% K8 s+ I
了解了这些,接下我们可以看驱动篇了。(Go On Study... Forever)' w3 p0 e' _& C% j' |+ j2 J
( q/ D/ Z: `( V( w0 w8 ^
: e' c( N; C* R# b |
|