|
|
最近在工作看到机台有启动过程中把SPI ROM数据清空,但苦与没有办法很好的Debug(PCA没有架起来),所有与EDK为对象好好的读了一把。- u7 y$ S/ b4 l- U2 F! u* @
: N6 l9 ]& j& c9 |# S
SEC/CEI:
$ w5 c, |6 l# q. i UEFI BIOS启动时先会执行SEC/CEI,这个阶段在实现的BIOS Code中初始化Debug Port,进入Big Mode,CPU的MicroCode,CacheToRAM的转换.然后跳转到PEI阶段。
& x/ E$ ?* L8 C5 a: I+ _在EDK中这部分被成了Load FvRecovery.fd文件,这个文件类似与我们的BIOS ROM.里面是我们编译后生成的二进制代码。在这个阶段最主要的是将这个文件加载到内存中(Windows API将文件加载到内存,看API函数).5 Y& ] D, C; R5 x
y1 q5 a) {+ |( ~
PEI:
9 |) g) w& y4 L8 O% `' _5 M3 v 从这里开始UEFI BIOS和EDK执行基本相同,只是一个是从SPI ROM中定位一个地址(PEIM的开始地址),一个是从内存中定位一个地址(PEIM的开始地址)。从这里开始只讲EDK的执行
6 V+ s5 X- v# L' ~( F EDK调用InitializeMemoryService函数,将HobList清空,peiservice清空。
/ g$ W' q: y& H. ^/ C; t! |/ b7 } InitializePPIService函数,将PPI队列清空,这个队列长0x3F.
; N1 Y! O% _: J3 }- P, `5 t, j InitializeSercurityService函数,将Notify队列清空。
6 {% }' z. v5 W$ l* z InitializeDispatcherData函数,将Dispatcher队列清空。
' [& p, t( X1 B" Z* b9 W8 P 接着由PeiBuildHobGuid来建立一个HOB(S3返回时这时应该有这个HOB,不用建立,直接使用了,这样就会进入另外一个流程,可以这个EDK不能调试S3,不知道怎么走)。然后由(*PeiServices)->InstallPpi()将这个新HOB加入到PPI中。
, Q$ e. d! [1 O8 }" d% o 由于在SEC阶段转了以下这几具PPI,所以在执行PEI的Dispatcher之前会先安装东西:
- O: u' N' N# d! a: d! s6 g EFI_PEI_PPI_DESCRIPTOR gPrivateDispatchTable[] = {
: |- }* {/ s. X8 I( V {EFI_PEI_PPI_DESCRIPTOR_PPI, &gEfiNtLoadAsDllPpiGuid, &mSecNtLoadAsDllPpi},* _7 x7 H- p' d; ?9 n7 M4 d
{EFI_PEI_PPI_DESCRIPTOR_PPI, &gNtPeiLoadFileGuid, &mSecNtLoadFilePpi},
6 N0 {, W3 f% `, x+ |1 Y {EFI_PEI_PPI_DESCRIPTOR_PPI, &gPeiNtAutoScanPpiGuid, &mSecNtAutoScanPpi},
! |4 N" ~: D) L2 J. k4 J r" d {EFI_PEI_PPI_DESCRIPTOR_PPI, &gPeiNtThunkPpiGuid, &mSecWinNtThunkPpi},- l2 y- f- Z ^ v3 y' Y" i# M2 X
{EFI_PEI_PPI_DESCRIPTOR_PPI, &gPeiStatusCodePpiGuid, &mSecStatusCodePpi},
' x5 L0 p& p0 R0 z3 l {EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST, &gNtFwhPpiGuid, &mSecFwhInformationPpi}
) {6 t8 x) z& H% T };
, k9 c" h0 Y3 l+ u 每个PPI是由{类型,GUID(名字,以后就根据这个来找到它的),Function_Entry_Address}组成。
! X6 |3 G; A0 y" { 这些PPI会在PEIDispatcher中用到。
# |" C$ ?4 i7 t2 j& o 安装完这此东西这开始执行PEIDispatcher函数,函数从BIOS ROM文件中找出PEI的Image(怎么找到,请读一下FV_HEAD(EFI_HEAD),里面讲到了如何区分Image类型),然后定位到PEI Image的入口地址,执行他。在我们的的PEI中,我们一般会申明一个PPI,这个就是这个PEI提供一些服务,PEIDispatcher会将他们加入到PPI-List中,以后其他Image也可以调用他的提供的功能。
' ~7 G( X0 ]( t 最后EDK会加载一个叫DXEIPL的PEI,DXEIPL提供一个PPI服务,这个PPI的功能是实现从PEI到DXE的切换,这个PPI里面为DXE做了很多的预准备,加载了很多PPI,如对BIOS的解压方法等。- O1 D2 Y* j% P& Q# |& I, [
SwitchStacks (
8 b/ W/ I! R( j8 e( P6 D (VOID *) (UINTN) DxeCoreEntryPoint,6 x9 W5 m3 e/ ~& g
(UINTN) (HobList.Raw),/ J% W4 ^4 y* {6 T% ^
(VOID *) (UINTN) TopOfStack,% N' I7 V/ A& F
(VOID *) (UINTN) BspStore
, a/ w$ Z) K( D% O8 M- j* g );
: V" i6 a; O+ d ]7 Q# \/ c 用过汇编的人对这个技术一定很熟悉,不多说了(我别不清,咯。。。)* v$ c5 N5 i% L
% l$ G( {9 b* \' L
DXE:9 Y8 z. q+ j+ l& H
从PEI到DXE切换时转过来一个HOBLIST参数,DXE会在这个HOB中找到Memory的使用情况,然后根据这些情况将BIOS引到内存(这是EFI的做法)。在EDK在DXE时重新定位一下内存。
! E2 ?, q9 e- h, ~4 h2 H接着就会定义我们经常使用到的gST表,gRT表。接着是申明一些Protocol(先不关心这些事)。" `2 _- z" p. m4 o0 \
等这些该加的PPI,Protocol加完了,CoreDispatcher()就出场了。他会的功能类似PEIDispatcher()。从我们BIOS ROM中将DXE的驱动读出,执行执行他们,这时会执行到Driver
+ f, C: |7 v$ }. n$ B' D$ A中的Support(),Start()两个功能函数。在这两个函数中你可以注册自己的PPI,为其他驱动提供服务。
8 O/ v5 y6 ^7 d 到些BIOS的引导其他完成。接着该进OS了,看Linux 0.11吧,操作系统是怎么做事情的。
: T1 U5 K. x, u: H/ w( W/ f
; w3 P: W9 {7 W- r' V9 }: X: w4 D' cDriver:. K0 K, S2 Y2 ? v0 D7 w3 h( L
我们的驱动什么为在PEI和DXE等不同阶段执行呢? N9 I; G) v& O# t4 Y
大家请看一下我们的驱动的makefile.(EDK中的*.inf)6 o/ A# F! U$ f' M8 f6 _
[defines]& ~$ {6 R4 |0 ], ^
BASE_NAME = OWEN/ {4 a; u7 _0 n5 i
FILE_GUID = 1EDD13C1-62EF-4262-A1AA-0040D0830110# [( x7 K1 a4 l$ h# g/ ?
COMPONENT_TYPE = BS_DRIVER" ~( }# {2 y# S' t1 D- b
?: E1 P1 C" Y BASE_NAME告诉编译器最终生成的驱动的名字。
; H W4 e3 V* N+ ~8 s1 J FILE_GUID就是这个驱动的GUID名字,在BIOS中引用某个驱动就是根据它来调用和识别。 ~1 F; e" a7 Z t0 |; D. I4 X5 o
COMONENT_TYPE会告诉编译器生成驱动的类型,是PEI,DXE,等。
! B& L' c( \* I! f B 在EDK中有一个FWVolume.c实现的功能就是帮我们把这个TYPE转换面相应的扩展名
$ S1 q& p, J. p6 }# x" m: c" K COMP_TYPE_EXTENSION mCompTypeExtension[] = {
3 _ f; `3 q6 F* b0 c' x# H/ t {"bs_driver", ".dxe" },- w) \, P0 c0 G1 u1 P
{"rt_driver", ".dxe" },1 x1 y# }5 f, U
{"sal_rt_driver", ".dxe"},
" ^5 X% Z" ?. S {"security_core", ".sec"},
6 ?( V0 r% |9 ]! N1 L {"pei_core", ".pei"},
) k% j2 K; Y$ l2 k) i {"pic_peim", ".pei"},1 R/ S, u$ H- R7 D
{"pe32_peim", ".pei"},
- y* V. f5 ]) g# d8 u, y5 G: d {"relocatable_peim", ".pei"}," y! ]9 y( ?0 r" d' c
{"binary", ".ffs"},' v& r6 X2 X2 P
{"application", ".app"},
% b6 o0 S2 @* J+ L( X4 { {"file", ".ffs"},$ q3 h6 y8 h7 t; Q& O- ^- V8 V
{"fvimagefile", ".fvi"}, v$ W- L' S. ^! s; K5 N" }
{"rawfile", ".raw"},
3 G% _2 a) H" X8 b( b, f& v6 K: i {"apriori", ".ffs"},, \6 p8 Y. A6 Z! p4 a0 n5 [( t) W8 [
{"combined_peim_driver", ".pei"},+ C+ a% O3 I7 n/ @0 m6 [4 V
{ NULL, NULL }( W/ g' k: K# Y; E; \2 z4 F% W
};
/ f7 }/ Q6 Q% ]8 D; m
% h6 {- j8 }9 P5 ~; H, r了解了这些,接下我们可以看驱动篇了。(Go On Study... Forever)
/ G9 L. t/ k7 X2 y- _4 R C
9 a2 z7 k0 P* e l" |1 M! k9 i! s
/ a) W/ ]& H. X! n7 O2 H |
|