|
|
最近在工作看到机台有启动过程中把SPI ROM数据清空,但苦与没有办法很好的Debug(PCA没有架起来),所有与EDK为对象好好的读了一把。
4 O( v8 M* E" E3 U* w2 N" q) M% H$ r6 }2 v# S
SEC/CEI:- x* Q: a4 v8 v
UEFI BIOS启动时先会执行SEC/CEI,这个阶段在实现的BIOS Code中初始化Debug Port,进入Big Mode,CPU的MicroCode,CacheToRAM的转换.然后跳转到PEI阶段。, t7 W: M2 `0 s7 `; ^$ Y
在EDK中这部分被成了Load FvRecovery.fd文件,这个文件类似与我们的BIOS ROM.里面是我们编译后生成的二进制代码。在这个阶段最主要的是将这个文件加载到内存中(Windows API将文件加载到内存,看API函数).
# f! B. }2 p3 W% E1 ]+ @; x! D( ~% ]5 y4 j; {+ Q1 I9 W3 T, L
PEI:1 t* K2 O5 `3 v. r
从这里开始UEFI BIOS和EDK执行基本相同,只是一个是从SPI ROM中定位一个地址(PEIM的开始地址),一个是从内存中定位一个地址(PEIM的开始地址)。从这里开始只讲EDK的执行* N! Y, [" G. C! N% O, a7 ?
EDK调用InitializeMemoryService函数,将HobList清空,peiservice清空。
% r, G# A" D& d$ o InitializePPIService函数,将PPI队列清空,这个队列长0x3F.
4 H% S( V; e( j0 X InitializeSercurityService函数,将Notify队列清空。$ u- G$ J% O# X% E$ l; _- s
InitializeDispatcherData函数,将Dispatcher队列清空。
9 O) E6 g Z! H9 p 接着由PeiBuildHobGuid来建立一个HOB(S3返回时这时应该有这个HOB,不用建立,直接使用了,这样就会进入另外一个流程,可以这个EDK不能调试S3,不知道怎么走)。然后由(*PeiServices)->InstallPpi()将这个新HOB加入到PPI中。
8 o u& i, `7 A: r 由于在SEC阶段转了以下这几具PPI,所以在执行PEI的Dispatcher之前会先安装东西:8 [6 I/ j& ?( h& q9 ^; P* z0 x
EFI_PEI_PPI_DESCRIPTOR gPrivateDispatchTable[] = {$ [1 J6 m$ t* V( c$ u
{EFI_PEI_PPI_DESCRIPTOR_PPI, &gEfiNtLoadAsDllPpiGuid, &mSecNtLoadAsDllPpi},1 g% L' g/ k! |; |
{EFI_PEI_PPI_DESCRIPTOR_PPI, &gNtPeiLoadFileGuid, &mSecNtLoadFilePpi},
4 N- Q/ e( U+ d" q+ o0 r N6 A {EFI_PEI_PPI_DESCRIPTOR_PPI, &gPeiNtAutoScanPpiGuid, &mSecNtAutoScanPpi},' n {/ y, R/ d7 i) }, x. U: K
{EFI_PEI_PPI_DESCRIPTOR_PPI, &gPeiNtThunkPpiGuid, &mSecWinNtThunkPpi},8 S) c' k" S- ~# {6 j! @2 M/ V
{EFI_PEI_PPI_DESCRIPTOR_PPI, &gPeiStatusCodePpiGuid, &mSecStatusCodePpi},
9 Y& U: @3 u/ D( b$ V% Z {EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST, &gNtFwhPpiGuid, &mSecFwhInformationPpi}
0 w3 ]7 c: Y7 @+ v( w' ]$ l2 C };
+ p, l' N1 u# \: t- C" `/ J: L* f 每个PPI是由{类型,GUID(名字,以后就根据这个来找到它的),Function_Entry_Address}组成。
6 H* A1 ]. d& S" J1 ~6 P 这些PPI会在PEIDispatcher中用到。- E8 g! g& p5 p4 a) V5 {
安装完这此东西这开始执行PEIDispatcher函数,函数从BIOS ROM文件中找出PEI的Image(怎么找到,请读一下FV_HEAD(EFI_HEAD),里面讲到了如何区分Image类型),然后定位到PEI Image的入口地址,执行他。在我们的的PEI中,我们一般会申明一个PPI,这个就是这个PEI提供一些服务,PEIDispatcher会将他们加入到PPI-List中,以后其他Image也可以调用他的提供的功能。
; j& q3 \! `* y8 |) N: U0 I1 W 最后EDK会加载一个叫DXEIPL的PEI,DXEIPL提供一个PPI服务,这个PPI的功能是实现从PEI到DXE的切换,这个PPI里面为DXE做了很多的预准备,加载了很多PPI,如对BIOS的解压方法等。+ R" o, O2 b9 M6 j% N7 D) z) a
SwitchStacks (0 }: P* J- i! o' C' y
(VOID *) (UINTN) DxeCoreEntryPoint,. _+ n+ U- N! n, e6 o2 T
(UINTN) (HobList.Raw),
k: T" N, E u& o5 Y0 T- u* K (VOID *) (UINTN) TopOfStack,2 h3 G! T6 W/ W
(VOID *) (UINTN) BspStore/ [/ M' O! L8 C U- k$ I
);0 n, b1 t, Q5 V# a9 d
用过汇编的人对这个技术一定很熟悉,不多说了(我别不清,咯。。。)( m# Y4 |9 U6 F; b+ q/ @
) F1 A" K. Q0 x1 S- c* W, G
DXE:
( C+ r& B! c) n' [ 从PEI到DXE切换时转过来一个HOBLIST参数,DXE会在这个HOB中找到Memory的使用情况,然后根据这些情况将BIOS引到内存(这是EFI的做法)。在EDK在DXE时重新定位一下内存。, [) ?5 r8 u1 s! g+ W! W g
接着就会定义我们经常使用到的gST表,gRT表。接着是申明一些Protocol(先不关心这些事)。
5 n$ o) \% K; K 等这些该加的PPI,Protocol加完了,CoreDispatcher()就出场了。他会的功能类似PEIDispatcher()。从我们BIOS ROM中将DXE的驱动读出,执行执行他们,这时会执行到Driver/ F5 v$ b+ F3 Y3 V; N* p
中的Support(),Start()两个功能函数。在这两个函数中你可以注册自己的PPI,为其他驱动提供服务。3 s7 ?( C/ ]8 \: \3 F4 l$ N5 k2 O5 I
到些BIOS的引导其他完成。接着该进OS了,看Linux 0.11吧,操作系统是怎么做事情的。
7 F2 L2 d! s) F# P7 r; M
2 x h, I" F8 x/ S) x1 A) [" gDriver:
+ b7 p' E5 T0 U4 ~" P) V& y 我们的驱动什么为在PEI和DXE等不同阶段执行呢?
( E) v- L! I; q4 J5 j+ r 大家请看一下我们的驱动的makefile.(EDK中的*.inf)% t/ p% ?& e1 `6 _( ^( a& k
[defines]; }/ r( Q* t5 U( I- o; s
BASE_NAME = OWEN5 M. e4 u) Z9 p0 R+ i2 X/ c* U. k/ A
FILE_GUID = 1EDD13C1-62EF-4262-A1AA-0040D0830110
: G; ]7 w8 ]- t* [" n; W COMPONENT_TYPE = BS_DRIVER) N" m" ? ]+ S' [
) P5 O2 Q+ q4 G% S# g. e BASE_NAME告诉编译器最终生成的驱动的名字。0 v0 i1 f5 Q' g/ R
FILE_GUID就是这个驱动的GUID名字,在BIOS中引用某个驱动就是根据它来调用和识别。
7 u, z+ O; M* z# p9 L+ q2 A COMONENT_TYPE会告诉编译器生成驱动的类型,是PEI,DXE,等。
7 e, o4 }% [0 F2 ]+ p 在EDK中有一个FWVolume.c实现的功能就是帮我们把这个TYPE转换面相应的扩展名$ z% g0 h0 q6 ?1 a* Z5 @- D9 P, }5 m
COMP_TYPE_EXTENSION mCompTypeExtension[] = {
, z- h! Q+ k$ G/ W. [, T) Z {"bs_driver", ".dxe" }, a. w2 ]: k$ m+ u+ F" s* y
{"rt_driver", ".dxe" },
. s4 q$ P$ Y1 y: k. U {"sal_rt_driver", ".dxe"},0 ~' p! d$ w' x3 a* `, L
{"security_core", ".sec"},
7 `" p: |, g' E5 y% q! [ M {"pei_core", ".pei"},
6 u' T6 _7 s4 U m: y, Z8 b) L& Y5 `% u {"pic_peim", ".pei"},! P) e4 t! T6 ?+ t, g- ]( b
{"pe32_peim", ".pei"},
, t# b0 `8 d" \: z {"relocatable_peim", ".pei"},
& k( s- [# c1 F) e {"binary", ".ffs"},
' L7 R" e' d% d* Q; q$ h {"application", ".app"},
4 y& S' o4 U3 w: p' G) K {"file", ".ffs"},: y l2 d5 X9 U |* ~; u
{"fvimagefile", ".fvi"},
; C2 K. x; H( E" p6 \ {"rawfile", ".raw"},( b; k! m/ f/ M: N* [& }. N
{"apriori", ".ffs"},
( h' @" Q; t& `# m$ s {"combined_peim_driver", ".pei"},% i. L6 b0 N5 @; l+ v" K! e+ s
{ NULL, NULL }
" l' W) B b+ F};2 H- n- b/ M; I9 l8 m \* r, N
9 s# K9 G) ?8 G) X- B了解了这些,接下我们可以看驱动篇了。(Go On Study... Forever)
4 Y: f6 s0 T0 H8 _) l! {- L
2 _7 @5 o: h: O, K# K- x % {4 o- [) X$ e$ b" J( \! m7 s
|
|