|
|
最近在工作看到机台有启动过程中把SPI ROM数据清空,但苦与没有办法很好的Debug(PCA没有架起来),所有与EDK为对象好好的读了一把。
; l' X, g& B; z8 F( \0 P! E3 C- t4 {- l( G
SEC/CEI:
6 _8 o+ X9 D. m& D- N% a" ]4 f2 J UEFI BIOS启动时先会执行SEC/CEI,这个阶段在实现的BIOS Code中初始化Debug Port,进入Big Mode,CPU的MicroCode,CacheToRAM的转换.然后跳转到PEI阶段。
' Q4 C2 ~+ [% q* P+ S) \在EDK中这部分被成了Load FvRecovery.fd文件,这个文件类似与我们的BIOS ROM.里面是我们编译后生成的二进制代码。在这个阶段最主要的是将这个文件加载到内存中(Windows API将文件加载到内存,看API函数).0 q& U# m7 f( h- [
9 ~3 C+ M3 q0 k0 r6 w
PEI:
4 m2 i0 I k R! Y; b. ], ]$ W 从这里开始UEFI BIOS和EDK执行基本相同,只是一个是从SPI ROM中定位一个地址(PEIM的开始地址),一个是从内存中定位一个地址(PEIM的开始地址)。从这里开始只讲EDK的执行# c/ Y$ _; T4 M/ Q, y% j3 a
EDK调用InitializeMemoryService函数,将HobList清空,peiservice清空。: h( n; H# x3 ^! E+ x g# i1 l) C
InitializePPIService函数,将PPI队列清空,这个队列长0x3F.
5 l2 ^9 ] H7 Y4 }' e InitializeSercurityService函数,将Notify队列清空。
( ~! i$ q1 ?1 B1 _. w1 p( T InitializeDispatcherData函数,将Dispatcher队列清空。, B: J X7 s3 h! N r& a3 G* E$ I
接着由PeiBuildHobGuid来建立一个HOB(S3返回时这时应该有这个HOB,不用建立,直接使用了,这样就会进入另外一个流程,可以这个EDK不能调试S3,不知道怎么走)。然后由(*PeiServices)->InstallPpi()将这个新HOB加入到PPI中。
$ L- ~& p) U' q. o$ X$ X; p 由于在SEC阶段转了以下这几具PPI,所以在执行PEI的Dispatcher之前会先安装东西:( s' }) C- h1 o# t! S
EFI_PEI_PPI_DESCRIPTOR gPrivateDispatchTable[] = {" o$ k6 S1 C" }5 D
{EFI_PEI_PPI_DESCRIPTOR_PPI, &gEfiNtLoadAsDllPpiGuid, &mSecNtLoadAsDllPpi},# w9 O; X+ V1 U, {! E
{EFI_PEI_PPI_DESCRIPTOR_PPI, &gNtPeiLoadFileGuid, &mSecNtLoadFilePpi},5 E% z+ \$ q7 h
{EFI_PEI_PPI_DESCRIPTOR_PPI, &gPeiNtAutoScanPpiGuid, &mSecNtAutoScanPpi},8 z" s2 w) R0 y4 `+ K" }) S. c( O0 i
{EFI_PEI_PPI_DESCRIPTOR_PPI, &gPeiNtThunkPpiGuid, &mSecWinNtThunkPpi}, ~( N3 e0 H X! d0 D
{EFI_PEI_PPI_DESCRIPTOR_PPI, &gPeiStatusCodePpiGuid, &mSecStatusCodePpi},$ m9 J ~6 U; R3 k
{EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST, &gNtFwhPpiGuid, &mSecFwhInformationPpi}
: ^1 L5 S4 M$ E5 [) H };
6 ?* }+ q+ q- j4 @8 ?- ^3 {2 l5 u 每个PPI是由{类型,GUID(名字,以后就根据这个来找到它的),Function_Entry_Address}组成。
A3 F. u. @5 {2 u* \ 这些PPI会在PEIDispatcher中用到。- x+ l7 J1 K" a) F6 [
安装完这此东西这开始执行PEIDispatcher函数,函数从BIOS ROM文件中找出PEI的Image(怎么找到,请读一下FV_HEAD(EFI_HEAD),里面讲到了如何区分Image类型),然后定位到PEI Image的入口地址,执行他。在我们的的PEI中,我们一般会申明一个PPI,这个就是这个PEI提供一些服务,PEIDispatcher会将他们加入到PPI-List中,以后其他Image也可以调用他的提供的功能。
9 D2 @. z- o& {: [9 s 最后EDK会加载一个叫DXEIPL的PEI,DXEIPL提供一个PPI服务,这个PPI的功能是实现从PEI到DXE的切换,这个PPI里面为DXE做了很多的预准备,加载了很多PPI,如对BIOS的解压方法等。
9 T+ D1 B5 N8 ~& u" r$ }0 |# r SwitchStacks (1 X& i' [5 C( r
(VOID *) (UINTN) DxeCoreEntryPoint,: V# q. \) `& \) l U+ G
(UINTN) (HobList.Raw),
5 c d2 p* H# T! T( S& ? (VOID *) (UINTN) TopOfStack,! g) O' z1 J- v- i
(VOID *) (UINTN) BspStore: m0 Z% i- Z k2 F" b- s9 o% @! y
);: u3 O$ B; V, t" m! q6 D- H( f
用过汇编的人对这个技术一定很熟悉,不多说了(我别不清,咯。。。)
3 c- I1 s1 J4 B6 h- w
+ ~: B$ W# ^; g! ADXE:; [, r' Y$ W& ~7 L3 c
从PEI到DXE切换时转过来一个HOBLIST参数,DXE会在这个HOB中找到Memory的使用情况,然后根据这些情况将BIOS引到内存(这是EFI的做法)。在EDK在DXE时重新定位一下内存。
- c* N1 Y# N: O接着就会定义我们经常使用到的gST表,gRT表。接着是申明一些Protocol(先不关心这些事)。* l& x, u' s/ Q+ \2 @5 V& t8 w
等这些该加的PPI,Protocol加完了,CoreDispatcher()就出场了。他会的功能类似PEIDispatcher()。从我们BIOS ROM中将DXE的驱动读出,执行执行他们,这时会执行到Driver6 r. c& ` _$ L: G5 p5 J9 S! v
中的Support(),Start()两个功能函数。在这两个函数中你可以注册自己的PPI,为其他驱动提供服务。
0 i7 B5 ?1 W: |" x e 到些BIOS的引导其他完成。接着该进OS了,看Linux 0.11吧,操作系统是怎么做事情的。
6 u% D6 E: D: }6 _, W/ Z1 s 5 V+ w$ o8 N ^6 g
Driver:" ~& {+ r! p' N) h p5 b
我们的驱动什么为在PEI和DXE等不同阶段执行呢?
) I6 i6 \9 G; ]# d# F0 f 大家请看一下我们的驱动的makefile.(EDK中的*.inf) I" u3 d( x+ x9 Q- Y: P- G/ T
[defines]/ P" l9 \7 _2 g4 O+ o6 h# D- e
BASE_NAME = OWEN
$ R1 k9 f9 S) e) [" w0 M FILE_GUID = 1EDD13C1-62EF-4262-A1AA-0040D0830110
6 v% x. L' [( C) W# W7 c+ ? COMPONENT_TYPE = BS_DRIVER
5 ?7 W) T' x& o6 u/ B- {# H! @2 r1 ^- `5 c
BASE_NAME告诉编译器最终生成的驱动的名字。: R( x! H1 C2 K( F
FILE_GUID就是这个驱动的GUID名字,在BIOS中引用某个驱动就是根据它来调用和识别。
' g5 n5 D; r5 @% m& ~& B6 k COMONENT_TYPE会告诉编译器生成驱动的类型,是PEI,DXE,等。! A) o# \8 d- t! }% n
在EDK中有一个FWVolume.c实现的功能就是帮我们把这个TYPE转换面相应的扩展名$ Q0 l/ {) [2 f+ n6 W$ e
COMP_TYPE_EXTENSION mCompTypeExtension[] = {9 U9 c+ p, s, l) a: |6 w
{"bs_driver", ".dxe" },
8 Q" J. y( F8 u8 v. H {"rt_driver", ".dxe" },! n+ E# E# s* c3 z+ W5 H3 S
{"sal_rt_driver", ".dxe"},
% p2 R* t ?2 p0 c/ S9 \: T: ^9 t1 w {"security_core", ".sec"}, ~: C2 g* {$ V. Y7 d
{"pei_core", ".pei"},
! e/ J. e- v1 w8 M$ M2 m {"pic_peim", ".pei"},
' k. Q2 j8 l( d3 F( a {"pe32_peim", ".pei"},; O5 J) E6 X! `& V4 {( @2 C/ O
{"relocatable_peim", ".pei"},
2 K, @/ l- C8 Y3 l) g2 ^+ h8 e {"binary", ".ffs"},# Z% G* m5 ?# j3 Z O
{"application", ".app"},
K& z/ t( a e$ H; x, B4 q k {"file", ".ffs"},7 J5 T; b# Z0 B/ b% P
{"fvimagefile", ".fvi"},7 L3 O1 r- S/ S/ h0 L8 e! w7 o) p
{"rawfile", ".raw"},! M' Y$ Q8 A% h3 ^) Y/ P
{"apriori", ".ffs"},# j5 ^9 g- h- _" v) j2 ~8 I
{"combined_peim_driver", ".pei"},! I+ W. S: g, H9 R U
{ NULL, NULL }
: t D6 u* W8 n# x};
" A- D0 c, J, w+ {' `: ]4 \7 `8 }1 w B# W5 ]0 ?
了解了这些,接下我们可以看驱动篇了。(Go On Study... Forever)2 ^6 }/ I# Q& b6 c- C1 H
; U) ]3 H& I( a$ s1 {! h S" X/ k8 j/ X$ h1 P, A1 J4 g
|
|