|
最近在工作看到机台有启动过程中把SPI ROM数据清空,但苦与没有办法很好的Debug(PCA没有架起来),所有与EDK为对象好好的读了一把。
! p" e/ [: X% m9 w/ q- s& j% Y4 t. O5 z) X( U$ S1 o' [' q6 H
SEC/CEI:
3 n* o1 f% _' v7 n* W0 E; a UEFI BIOS启动时先会执行SEC/CEI,这个阶段在实现的BIOS Code中初始化Debug Port,进入Big Mode,CPU的MicroCode,CacheToRAM的转换.然后跳转到PEI阶段。, u9 X3 F p |/ j- b
在EDK中这部分被成了Load FvRecovery.fd文件,这个文件类似与我们的BIOS ROM.里面是我们编译后生成的二进制代码。在这个阶段最主要的是将这个文件加载到内存中(Windows API将文件加载到内存,看API函数).
# q8 ~- S# W2 r( F2 n6 E* I
4 V4 e* u! o) Z/ xPEI:
: u; t: S% o& }, {7 u 从这里开始UEFI BIOS和EDK执行基本相同,只是一个是从SPI ROM中定位一个地址(PEIM的开始地址),一个是从内存中定位一个地址(PEIM的开始地址)。从这里开始只讲EDK的执行4 {7 i' I/ ]6 k8 k/ R0 s
EDK调用InitializeMemoryService函数,将HobList清空,peiservice清空。
v( y2 o1 ?, E! ] InitializePPIService函数,将PPI队列清空,这个队列长0x3F.
' `/ t/ O) t0 x& h9 i3 a5 ` InitializeSercurityService函数,将Notify队列清空。 l- M/ y, h) s$ q6 B4 R7 L7 L5 K
InitializeDispatcherData函数,将Dispatcher队列清空。
" B8 m( D" ~/ v, K 接着由PeiBuildHobGuid来建立一个HOB(S3返回时这时应该有这个HOB,不用建立,直接使用了,这样就会进入另外一个流程,可以这个EDK不能调试S3,不知道怎么走)。然后由(*PeiServices)->InstallPpi()将这个新HOB加入到PPI中。
4 I) B6 K) {! [3 O x7 a/ c, X$ i 由于在SEC阶段转了以下这几具PPI,所以在执行PEI的Dispatcher之前会先安装东西:
' w: n. x6 [' K4 G) O- C& \ EFI_PEI_PPI_DESCRIPTOR gPrivateDispatchTable[] = {3 k6 Q8 V: n5 c) ]+ T7 k, D% a
{EFI_PEI_PPI_DESCRIPTOR_PPI, &gEfiNtLoadAsDllPpiGuid, &mSecNtLoadAsDllPpi},
. q; d( O6 h; b8 O {EFI_PEI_PPI_DESCRIPTOR_PPI, &gNtPeiLoadFileGuid, &mSecNtLoadFilePpi},1 ]2 \% {9 K" n3 J. }8 j
{EFI_PEI_PPI_DESCRIPTOR_PPI, &gPeiNtAutoScanPpiGuid, &mSecNtAutoScanPpi},
8 U, e9 l6 R4 K; W( u3 R! R q {EFI_PEI_PPI_DESCRIPTOR_PPI, &gPeiNtThunkPpiGuid, &mSecWinNtThunkPpi},
) d8 V) b9 E& ?* R/ S0 o% g {EFI_PEI_PPI_DESCRIPTOR_PPI, &gPeiStatusCodePpiGuid, &mSecStatusCodePpi},3 U2 p/ p% d/ A' g
{EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST, &gNtFwhPpiGuid, &mSecFwhInformationPpi}
6 [/ W! A$ Y1 a- N3 z: P M3 i1 N };
. ~4 W1 H2 R( \% I6 @3 j 每个PPI是由{类型,GUID(名字,以后就根据这个来找到它的),Function_Entry_Address}组成。
2 w! Z. t) z+ A: [# [ 这些PPI会在PEIDispatcher中用到。+ ~7 O" |* \# ^9 l: B7 \7 c
安装完这此东西这开始执行PEIDispatcher函数,函数从BIOS ROM文件中找出PEI的Image(怎么找到,请读一下FV_HEAD(EFI_HEAD),里面讲到了如何区分Image类型),然后定位到PEI Image的入口地址,执行他。在我们的的PEI中,我们一般会申明一个PPI,这个就是这个PEI提供一些服务,PEIDispatcher会将他们加入到PPI-List中,以后其他Image也可以调用他的提供的功能。
* W% f/ K7 C: h% C# `/ f 最后EDK会加载一个叫DXEIPL的PEI,DXEIPL提供一个PPI服务,这个PPI的功能是实现从PEI到DXE的切换,这个PPI里面为DXE做了很多的预准备,加载了很多PPI,如对BIOS的解压方法等。( V: n; W7 Q2 z( [" }% A2 Z
SwitchStacks (
* D& g' U' I0 s (VOID *) (UINTN) DxeCoreEntryPoint,
" v8 o+ V" N F; S% j (UINTN) (HobList.Raw),
0 I) m+ s3 u' X, \5 {8 f+ s (VOID *) (UINTN) TopOfStack,
6 x$ o) \2 W4 @; W9 ?. ]( h (VOID *) (UINTN) BspStore
! @. x: i# @! Z6 }% h );
_( F1 [5 W) T, L: o 用过汇编的人对这个技术一定很熟悉,不多说了(我别不清,咯。。。)7 I* ]" Z5 G( c: N2 H, d
' Z( T p' P. ^8 [. LDXE:
' U3 B! ]% D* ^! K5 U, K j 从PEI到DXE切换时转过来一个HOBLIST参数,DXE会在这个HOB中找到Memory的使用情况,然后根据这些情况将BIOS引到内存(这是EFI的做法)。在EDK在DXE时重新定位一下内存。
; ^1 m2 @ g: T) O8 u3 ~接着就会定义我们经常使用到的gST表,gRT表。接着是申明一些Protocol(先不关心这些事)。
! o; v$ n8 C3 J+ a | 等这些该加的PPI,Protocol加完了,CoreDispatcher()就出场了。他会的功能类似PEIDispatcher()。从我们BIOS ROM中将DXE的驱动读出,执行执行他们,这时会执行到Driver( Q& k! u3 r# [0 g2 D& E
中的Support(),Start()两个功能函数。在这两个函数中你可以注册自己的PPI,为其他驱动提供服务。
. G( k" P$ a5 i4 h6 `( q( \ 到些BIOS的引导其他完成。接着该进OS了,看Linux 0.11吧,操作系统是怎么做事情的。4 C- J) K% s2 ^) n
9 ~9 ^* l. Z& |0 w. \7 }0 G+ FDriver:% C) Y" i9 [4 ?% c: f& ^; V
我们的驱动什么为在PEI和DXE等不同阶段执行呢?
1 A- W, V9 K+ _/ k! e2 h 大家请看一下我们的驱动的makefile.(EDK中的*.inf)
# W0 g5 f! Z+ S [defines]# S, U6 {5 k+ v" x7 x, e w# `
BASE_NAME = OWEN, Z/ p% ?9 J+ l4 Y. M
FILE_GUID = 1EDD13C1-62EF-4262-A1AA-0040D0830110( ?; D' X K4 A! y. l
COMPONENT_TYPE = BS_DRIVER/ t5 p2 K/ ?: K% D2 x, x0 U+ Z
3 |; R1 n4 F2 t BASE_NAME告诉编译器最终生成的驱动的名字。7 y( i# O: ~# l& c1 ^( U
FILE_GUID就是这个驱动的GUID名字,在BIOS中引用某个驱动就是根据它来调用和识别。+ D/ ?$ z$ ? E: c' ?+ q
COMONENT_TYPE会告诉编译器生成驱动的类型,是PEI,DXE,等。) P: h# L& `) T G( X" Y3 B
在EDK中有一个FWVolume.c实现的功能就是帮我们把这个TYPE转换面相应的扩展名, L* M. @& h* r2 _' f3 s# F
COMP_TYPE_EXTENSION mCompTypeExtension[] = {( T+ {, d4 t" s# t+ ]( X
{"bs_driver", ".dxe" },
$ i/ H6 G" }7 K7 `7 r+ A {"rt_driver", ".dxe" },7 y: }; C7 u. e7 w' s% X
{"sal_rt_driver", ".dxe"},- s# A. G: I* Q1 e5 m
{"security_core", ".sec"},
3 S4 Y- q7 D' J' o B {"pei_core", ".pei"},0 T; H7 x- o% V( y2 X; `
{"pic_peim", ".pei"},$ u6 A4 k6 F1 B! x, P/ F! m
{"pe32_peim", ".pei"},
# @$ s$ U% k8 E7 F9 z; o s9 A5 {, g' a {"relocatable_peim", ".pei"},; b8 U/ x2 M3 L) T7 W2 w
{"binary", ".ffs"},
! f$ b8 m% B5 O7 Q1 G5 C% I {"application", ".app"},
2 n/ Y! K% _3 u {"file", ".ffs"}," d, e: V; P9 L# O9 L/ Z: i
{"fvimagefile", ".fvi"},/ `; m- T. D7 W: O, P# v
{"rawfile", ".raw"},
+ V* R1 u& i" _* \* D0 @' g {"apriori", ".ffs"},
l3 U1 X' A& ]/ [. T {"combined_peim_driver", ".pei"},( G1 H7 a9 K% y8 e. B- d2 A
{ NULL, NULL }* t& q- }6 p* ^
};
, g |; s. k H( C( r L1 Y
- J. b- t6 j/ \2 v4 N了解了这些,接下我们可以看驱动篇了。(Go On Study... Forever)
3 `: T: F" M9 s# L * v6 U' t1 A; d
0 p; n# u _/ v! j& @0 } |
|