|
|
最近在工作看到机台有启动过程中把SPI ROM数据清空,但苦与没有办法很好的Debug(PCA没有架起来),所有与EDK为对象好好的读了一把。
7 q6 ?4 M/ r L
6 h; Q! \. D; [' ~1 q: FSEC/CEI:
$ Q0 \0 T9 g3 s% o UEFI BIOS启动时先会执行SEC/CEI,这个阶段在实现的BIOS Code中初始化Debug Port,进入Big Mode,CPU的MicroCode,CacheToRAM的转换.然后跳转到PEI阶段。7 S$ i5 V6 S4 v G& ^
在EDK中这部分被成了Load FvRecovery.fd文件,这个文件类似与我们的BIOS ROM.里面是我们编译后生成的二进制代码。在这个阶段最主要的是将这个文件加载到内存中(Windows API将文件加载到内存,看API函数).
9 t; c; y0 R. D, h7 l$ O6 x. N# j! Z3 c- y
PEI:! N' r/ }1 _3 i! a; N R; p
从这里开始UEFI BIOS和EDK执行基本相同,只是一个是从SPI ROM中定位一个地址(PEIM的开始地址),一个是从内存中定位一个地址(PEIM的开始地址)。从这里开始只讲EDK的执行
# [; b' w$ s0 \3 t) _6 |5 k) P8 n EDK调用InitializeMemoryService函数,将HobList清空,peiservice清空。
; M4 A' d I& J# M5 @ InitializePPIService函数,将PPI队列清空,这个队列长0x3F.
2 X+ G# s/ N, V2 k% | InitializeSercurityService函数,将Notify队列清空。; X% o1 w4 w4 J0 c
InitializeDispatcherData函数,将Dispatcher队列清空。9 H6 _. `$ q/ Q+ k0 Y u
接着由PeiBuildHobGuid来建立一个HOB(S3返回时这时应该有这个HOB,不用建立,直接使用了,这样就会进入另外一个流程,可以这个EDK不能调试S3,不知道怎么走)。然后由(*PeiServices)->InstallPpi()将这个新HOB加入到PPI中。2 \+ a" c+ Y# D& R6 m
由于在SEC阶段转了以下这几具PPI,所以在执行PEI的Dispatcher之前会先安装东西:; j5 A! g5 i) }* R
EFI_PEI_PPI_DESCRIPTOR gPrivateDispatchTable[] = {
2 K4 [# {+ `! V9 \' ^3 Q J {EFI_PEI_PPI_DESCRIPTOR_PPI, &gEfiNtLoadAsDllPpiGuid, &mSecNtLoadAsDllPpi},
3 S$ T: g1 A$ A! ~ {EFI_PEI_PPI_DESCRIPTOR_PPI, &gNtPeiLoadFileGuid, &mSecNtLoadFilePpi},( j0 V& h9 s( T# Y, p" t
{EFI_PEI_PPI_DESCRIPTOR_PPI, &gPeiNtAutoScanPpiGuid, &mSecNtAutoScanPpi},
: ^; R" n0 N' T$ h& k4 _7 ~ {EFI_PEI_PPI_DESCRIPTOR_PPI, &gPeiNtThunkPpiGuid, &mSecWinNtThunkPpi},1 n9 r4 A% H; B% s8 o" L/ ?" M* q
{EFI_PEI_PPI_DESCRIPTOR_PPI, &gPeiStatusCodePpiGuid, &mSecStatusCodePpi},) F, H! M, V7 A( P9 S: x5 b
{EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST, &gNtFwhPpiGuid, &mSecFwhInformationPpi}
4 W) w6 {+ E5 v; X9 I };% C/ G1 i( D. X7 G! }+ o/ M: q& T
每个PPI是由{类型,GUID(名字,以后就根据这个来找到它的),Function_Entry_Address}组成。* P/ d9 t4 [9 F, S
这些PPI会在PEIDispatcher中用到。8 p: Y: U8 l3 S5 K- c/ c
安装完这此东西这开始执行PEIDispatcher函数,函数从BIOS ROM文件中找出PEI的Image(怎么找到,请读一下FV_HEAD(EFI_HEAD),里面讲到了如何区分Image类型),然后定位到PEI Image的入口地址,执行他。在我们的的PEI中,我们一般会申明一个PPI,这个就是这个PEI提供一些服务,PEIDispatcher会将他们加入到PPI-List中,以后其他Image也可以调用他的提供的功能。
5 N+ t4 {% p8 \3 O" E% _ 最后EDK会加载一个叫DXEIPL的PEI,DXEIPL提供一个PPI服务,这个PPI的功能是实现从PEI到DXE的切换,这个PPI里面为DXE做了很多的预准备,加载了很多PPI,如对BIOS的解压方法等。: l* b! T. s) J2 U! @
SwitchStacks (
8 ^& p/ H5 D2 Q9 e0 \ (VOID *) (UINTN) DxeCoreEntryPoint,
7 A( B+ k. q% {8 J! p (UINTN) (HobList.Raw),
3 \; I5 [* x& l9 @" ]$ e (VOID *) (UINTN) TopOfStack,
. n( |8 M$ c( q# V (VOID *) (UINTN) BspStore
`% D5 R2 m/ i0 A4 [: Y( x );8 W! V0 q: [& Y. f
用过汇编的人对这个技术一定很熟悉,不多说了(我别不清,咯。。。)
' Y& V' ?" m" M+ x
3 G1 D0 s F7 [6 c# O4 c1 TDXE:
; U! x0 Y9 C, i# }2 z0 ? 从PEI到DXE切换时转过来一个HOBLIST参数,DXE会在这个HOB中找到Memory的使用情况,然后根据这些情况将BIOS引到内存(这是EFI的做法)。在EDK在DXE时重新定位一下内存。3 g, D& L- b a) q: t7 j
接着就会定义我们经常使用到的gST表,gRT表。接着是申明一些Protocol(先不关心这些事)。
% D. d$ R/ e# g. R# I+ Q. N4 L 等这些该加的PPI,Protocol加完了,CoreDispatcher()就出场了。他会的功能类似PEIDispatcher()。从我们BIOS ROM中将DXE的驱动读出,执行执行他们,这时会执行到Driver
# n! j" P6 r( a# v" U中的Support(),Start()两个功能函数。在这两个函数中你可以注册自己的PPI,为其他驱动提供服务。5 P0 M, K5 H& |. d( C0 z* ^
到些BIOS的引导其他完成。接着该进OS了,看Linux 0.11吧,操作系统是怎么做事情的。
8 F/ w4 H% j2 {2 m! Y3 o) M. l
" T! _7 A/ E0 L( @/ ]4 c: k! SDriver:
/ G* U. y, H( p4 k( i* U! F" J. d 我们的驱动什么为在PEI和DXE等不同阶段执行呢?
2 M6 \- |8 N8 V7 G 大家请看一下我们的驱动的makefile.(EDK中的*.inf)
* b7 `. g4 Q5 D2 D: |, P8 R1 y8 A [defines]4 V, h! Y& h+ |+ n+ ~
BASE_NAME = OWEN
7 C' T: \/ r6 \' n& }. R ~ A$ k FILE_GUID = 1EDD13C1-62EF-4262-A1AA-0040D0830110- i5 c2 N; R4 H! g: S% D
COMPONENT_TYPE = BS_DRIVER
0 j$ _2 q6 W6 |
" k' u0 P2 A" z3 b. u& N1 M BASE_NAME告诉编译器最终生成的驱动的名字。8 E; m1 [3 \& j6 r! e9 y
FILE_GUID就是这个驱动的GUID名字,在BIOS中引用某个驱动就是根据它来调用和识别。
' d5 j4 U6 a- z" p9 [0 o COMONENT_TYPE会告诉编译器生成驱动的类型,是PEI,DXE,等。) Q4 H4 b& X0 i: d
在EDK中有一个FWVolume.c实现的功能就是帮我们把这个TYPE转换面相应的扩展名
# ~0 b% G# a: D COMP_TYPE_EXTENSION mCompTypeExtension[] = {
# a& g5 e+ m7 U: \ {"bs_driver", ".dxe" },
4 m8 u) o7 a. ]2 B& q {"rt_driver", ".dxe" },
2 X( g! |0 Q$ s5 w: w6 X {"sal_rt_driver", ".dxe"},! E/ }5 r# g# x5 D0 N
{"security_core", ".sec"},4 b: p3 M7 [+ n- C/ `& S: z
{"pei_core", ".pei"},
+ W' a, N9 { Y {"pic_peim", ".pei"},
9 _% O+ k& N3 F) i! W; i, \ {"pe32_peim", ".pei"},
! O3 x) h* d# k% S0 E* G/ W {"relocatable_peim", ".pei"},3 F- I G4 `4 T& x( o1 _3 L) i0 h
{"binary", ".ffs"},
3 b) K, S6 r. t6 J; n {"application", ".app"},
* [7 S1 U, v. u. Q# r- D! G {"file", ".ffs"},
% I! M- V6 t8 L9 Q* ] {"fvimagefile", ".fvi"},+ [- G" e6 ^- [, _# `. g
{"rawfile", ".raw"},
0 R* W7 h1 L6 o: R6 ]8 t* K {"apriori", ".ffs"},
( |1 D# j, P6 z {"combined_peim_driver", ".pei"},
8 E% p b' U) A# P { NULL, NULL }) d: @) m) C) h$ d: V; e. U3 A
};
3 b* N6 p) T$ {* O
1 x. p! I, p) y/ o2 Q9 _7 }了解了这些,接下我们可以看驱动篇了。(Go On Study... Forever)+ }, ?2 n( R' \" w t$ N( O
6 ?! k. Q" k* O& W7 v ; E. x0 q/ P0 A$ I) j: R b
|
|