|
|
最近在工作看到机台有启动过程中把SPI ROM数据清空,但苦与没有办法很好的Debug(PCA没有架起来),所有与EDK为对象好好的读了一把。( x k$ ^5 ~( s0 p% G7 k
* W2 |- f$ ?$ K5 p" u* ]) n
SEC/CEI:
8 H- n" @' u9 y+ J UEFI BIOS启动时先会执行SEC/CEI,这个阶段在实现的BIOS Code中初始化Debug Port,进入Big Mode,CPU的MicroCode,CacheToRAM的转换.然后跳转到PEI阶段。8 F- {& {" l( m( U5 H# h$ t
在EDK中这部分被成了Load FvRecovery.fd文件,这个文件类似与我们的BIOS ROM.里面是我们编译后生成的二进制代码。在这个阶段最主要的是将这个文件加载到内存中(Windows API将文件加载到内存,看API函数).* U+ r6 Y5 S* G7 I- F
* s! {0 ~2 ]& k2 {. _& `& xPEI:% T0 A% T$ p# y" k% S$ m" s
从这里开始UEFI BIOS和EDK执行基本相同,只是一个是从SPI ROM中定位一个地址(PEIM的开始地址),一个是从内存中定位一个地址(PEIM的开始地址)。从这里开始只讲EDK的执行
# `4 }- }% m: p EDK调用InitializeMemoryService函数,将HobList清空,peiservice清空。
; Z# R+ H, F2 N3 `4 r, B) \& W InitializePPIService函数,将PPI队列清空,这个队列长0x3F.( F* h9 w) [! ^; d
InitializeSercurityService函数,将Notify队列清空。
. l! C# ]; \4 L InitializeDispatcherData函数,将Dispatcher队列清空。5 R* X; y. B* U9 _+ J9 e
接着由PeiBuildHobGuid来建立一个HOB(S3返回时这时应该有这个HOB,不用建立,直接使用了,这样就会进入另外一个流程,可以这个EDK不能调试S3,不知道怎么走)。然后由(*PeiServices)->InstallPpi()将这个新HOB加入到PPI中。
; g9 h) ^2 U8 ^1 }- m 由于在SEC阶段转了以下这几具PPI,所以在执行PEI的Dispatcher之前会先安装东西:
: a2 C; U. i" L" D, b) D EFI_PEI_PPI_DESCRIPTOR gPrivateDispatchTable[] = { |2 d _! k) |; \# L
{EFI_PEI_PPI_DESCRIPTOR_PPI, &gEfiNtLoadAsDllPpiGuid, &mSecNtLoadAsDllPpi},
5 J# C$ n: D- o9 F# F( S! C {EFI_PEI_PPI_DESCRIPTOR_PPI, &gNtPeiLoadFileGuid, &mSecNtLoadFilePpi},
: k& y8 f2 Y# ]" K/ q {EFI_PEI_PPI_DESCRIPTOR_PPI, &gPeiNtAutoScanPpiGuid, &mSecNtAutoScanPpi},
$ N6 X; }7 a( H6 x5 w5 X& B {EFI_PEI_PPI_DESCRIPTOR_PPI, &gPeiNtThunkPpiGuid, &mSecWinNtThunkPpi},
$ V0 [: o8 U4 A& m- N {EFI_PEI_PPI_DESCRIPTOR_PPI, &gPeiStatusCodePpiGuid, &mSecStatusCodePpi},
. `) Q9 _+ j. a9 X4 T. i {EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST, &gNtFwhPpiGuid, &mSecFwhInformationPpi}0 l( {; N5 A6 |+ { r
};+ b4 |3 L0 J+ B2 B. N
每个PPI是由{类型,GUID(名字,以后就根据这个来找到它的),Function_Entry_Address}组成。
7 {4 @* n3 T1 h5 E3 v& C 这些PPI会在PEIDispatcher中用到。; X7 M0 \% n: q6 ~7 O3 ?
安装完这此东西这开始执行PEIDispatcher函数,函数从BIOS ROM文件中找出PEI的Image(怎么找到,请读一下FV_HEAD(EFI_HEAD),里面讲到了如何区分Image类型),然后定位到PEI Image的入口地址,执行他。在我们的的PEI中,我们一般会申明一个PPI,这个就是这个PEI提供一些服务,PEIDispatcher会将他们加入到PPI-List中,以后其他Image也可以调用他的提供的功能。
' b8 R* r! W+ D0 L 最后EDK会加载一个叫DXEIPL的PEI,DXEIPL提供一个PPI服务,这个PPI的功能是实现从PEI到DXE的切换,这个PPI里面为DXE做了很多的预准备,加载了很多PPI,如对BIOS的解压方法等。7 f+ ?( n* c: K, N6 W6 i- V- J3 t0 U+ ]7 l
SwitchStacks (
/ v3 S3 ]; d* J7 I% R! \0 N j) ~0 F" g (VOID *) (UINTN) DxeCoreEntryPoint,
" D) a8 ~$ M' i7 Y$ I0 a (UINTN) (HobList.Raw),
$ h2 j& K8 T" B9 X/ Z$ n0 [' I (VOID *) (UINTN) TopOfStack,6 Y. Z. S) U* i0 t6 |7 e1 E
(VOID *) (UINTN) BspStore
; `, Y$ { U+ j );
! k5 n; ^' J: c4 U5 W4 a 用过汇编的人对这个技术一定很熟悉,不多说了(我别不清,咯。。。)
9 m7 Z* L, f) D' r% J3 E. m! u% r0 e
DXE:7 g: f1 j. b* I+ z9 ^" K; o; C
从PEI到DXE切换时转过来一个HOBLIST参数,DXE会在这个HOB中找到Memory的使用情况,然后根据这些情况将BIOS引到内存(这是EFI的做法)。在EDK在DXE时重新定位一下内存。
: A3 A6 y, P5 f0 d6 M接着就会定义我们经常使用到的gST表,gRT表。接着是申明一些Protocol(先不关心这些事)。
' B2 e3 C+ k* v N 等这些该加的PPI,Protocol加完了,CoreDispatcher()就出场了。他会的功能类似PEIDispatcher()。从我们BIOS ROM中将DXE的驱动读出,执行执行他们,这时会执行到Driver
2 J. W) f* V3 e中的Support(),Start()两个功能函数。在这两个函数中你可以注册自己的PPI,为其他驱动提供服务。
' e' X+ _+ f" z) J# A# @( C 到些BIOS的引导其他完成。接着该进OS了,看Linux 0.11吧,操作系统是怎么做事情的。
9 |6 J4 _( L) a' @, K# ]6 P( v3 T2 E
- v. B; i1 g* O7 ^Driver:* D& w1 ^6 P, Q8 O
我们的驱动什么为在PEI和DXE等不同阶段执行呢?2 ^6 k* n, A# o# B$ k8 q
大家请看一下我们的驱动的makefile.(EDK中的*.inf)
2 i2 p- A8 j( Z! t& q. V [defines]
' X7 x; D1 F. a$ T" |" y6 h BASE_NAME = OWEN. t& q" t, K$ h2 N
FILE_GUID = 1EDD13C1-62EF-4262-A1AA-0040D08301100 W$ ^8 H" V3 e/ K1 A
COMPONENT_TYPE = BS_DRIVER
; T% A; G* J. c0 ~
1 d' [1 }1 T% ]) l3 j BASE_NAME告诉编译器最终生成的驱动的名字。
% Y, @: B& p4 l. S) N( ` FILE_GUID就是这个驱动的GUID名字,在BIOS中引用某个驱动就是根据它来调用和识别。$ n% {3 w; y4 Z
COMONENT_TYPE会告诉编译器生成驱动的类型,是PEI,DXE,等。
5 t0 K. X5 g9 L6 Y# ?' J- y* K' V 在EDK中有一个FWVolume.c实现的功能就是帮我们把这个TYPE转换面相应的扩展名
+ l8 ^" t+ `$ r0 U$ x COMP_TYPE_EXTENSION mCompTypeExtension[] = {8 ~1 s6 n1 k0 n: J |% D' v
{"bs_driver", ".dxe" },6 n+ C1 ^3 f* N7 V E7 p
{"rt_driver", ".dxe" },
$ @( x% k- I6 ]1 I7 c2 A! ^ {"sal_rt_driver", ".dxe"},
* T9 R& e9 j+ b* }9 k {"security_core", ".sec"},
3 P& c! B, W: D8 H {"pei_core", ".pei"},
! d! h5 `$ |7 P% k# P5 x {"pic_peim", ".pei"},( Z9 j; F# z$ r1 Q$ G0 I
{"pe32_peim", ".pei"},
9 w% i' D! s% V) B& Y$ H7 V {"relocatable_peim", ".pei"},
1 y% F; ^3 r$ Y+ K# ?0 z {"binary", ".ffs"},
1 M3 ^! c+ r& w7 q( R" L7 S {"application", ".app"},
8 r& c' a7 w* g5 b4 A {"file", ".ffs"},
% u$ u" q% F- N( q0 f3 e/ |- O {"fvimagefile", ".fvi"},2 E* M9 \5 v# j" N; O
{"rawfile", ".raw"},
4 O- P/ a* t O' ? {"apriori", ".ffs"},
( C$ i* h6 J8 W7 Y" ?& @( Z. k {"combined_peim_driver", ".pei"},+ A J5 n9 ?/ }& F& G
{ NULL, NULL }
* Z0 m; }8 j/ @/ X9 x2 I) ]( A};
+ y T4 r. A7 H& c; b/ n8 X" T1 i# R! U$ h K% h, z
了解了这些,接下我们可以看驱动篇了。(Go On Study... Forever)
1 K+ \: l" f# i& C2 n3 P% N3 o) \1 J
* N$ d0 {8 T) ]0 `6 {- L8 v8 f
. }0 A( n$ F1 G! [* p1 ~$ y |
|