|
|
最近在工作看到机台有启动过程中把SPI ROM数据清空,但苦与没有办法很好的Debug(PCA没有架起来),所有与EDK为对象好好的读了一把。: {9 }! F) R8 E" C, C; B. o/ o
- j; H0 Z# ?+ S% V
SEC/CEI:- m5 M6 l P- G% l
UEFI BIOS启动时先会执行SEC/CEI,这个阶段在实现的BIOS Code中初始化Debug Port,进入Big Mode,CPU的MicroCode,CacheToRAM的转换.然后跳转到PEI阶段。$ S8 r R2 U/ }# A6 j* p6 W- }
在EDK中这部分被成了Load FvRecovery.fd文件,这个文件类似与我们的BIOS ROM.里面是我们编译后生成的二进制代码。在这个阶段最主要的是将这个文件加载到内存中(Windows API将文件加载到内存,看API函数).
1 \/ V: [8 I( ~+ C: }
) C' e* ?5 G' {+ A) mPEI:
& U* c* f+ |' \ r$ c2 { 从这里开始UEFI BIOS和EDK执行基本相同,只是一个是从SPI ROM中定位一个地址(PEIM的开始地址),一个是从内存中定位一个地址(PEIM的开始地址)。从这里开始只讲EDK的执行, h5 S" X3 K) T. D( Z( x4 N; e
EDK调用InitializeMemoryService函数,将HobList清空,peiservice清空。
; z1 T, v+ c) V' S InitializePPIService函数,将PPI队列清空,这个队列长0x3F.
% r: l4 J5 k6 A InitializeSercurityService函数,将Notify队列清空。5 R. N9 y% }9 S) r
InitializeDispatcherData函数,将Dispatcher队列清空。
; l; o o7 O: {: {( p, a# x 接着由PeiBuildHobGuid来建立一个HOB(S3返回时这时应该有这个HOB,不用建立,直接使用了,这样就会进入另外一个流程,可以这个EDK不能调试S3,不知道怎么走)。然后由(*PeiServices)->InstallPpi()将这个新HOB加入到PPI中。
7 U' Q t+ H K: d1 S0 R1 n 由于在SEC阶段转了以下这几具PPI,所以在执行PEI的Dispatcher之前会先安装东西:8 S/ H4 [% _9 O, m1 ~+ |
EFI_PEI_PPI_DESCRIPTOR gPrivateDispatchTable[] = {: Y l- E: ~ f, U: }, a
{EFI_PEI_PPI_DESCRIPTOR_PPI, &gEfiNtLoadAsDllPpiGuid, &mSecNtLoadAsDllPpi},0 h" `8 Y5 l& t: ^, \
{EFI_PEI_PPI_DESCRIPTOR_PPI, &gNtPeiLoadFileGuid, &mSecNtLoadFilePpi},
% R2 b }/ ^' j6 Z- `2 Z) k {EFI_PEI_PPI_DESCRIPTOR_PPI, &gPeiNtAutoScanPpiGuid, &mSecNtAutoScanPpi},+ H4 z4 U1 U, L% a% }; c
{EFI_PEI_PPI_DESCRIPTOR_PPI, &gPeiNtThunkPpiGuid, &mSecWinNtThunkPpi},2 P) `2 q6 n; z. h
{EFI_PEI_PPI_DESCRIPTOR_PPI, &gPeiStatusCodePpiGuid, &mSecStatusCodePpi},) E3 T( e. `- ~9 r, s' u
{EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST, &gNtFwhPpiGuid, &mSecFwhInformationPpi}
& d0 o% K" U w/ t F/ g; F: Z2 I: m };
7 j) v0 o, e; s: l 每个PPI是由{类型,GUID(名字,以后就根据这个来找到它的),Function_Entry_Address}组成。" {5 s0 a& R1 Y" z
这些PPI会在PEIDispatcher中用到。
0 @. I2 j A; X( |+ m' z0 R 安装完这此东西这开始执行PEIDispatcher函数,函数从BIOS ROM文件中找出PEI的Image(怎么找到,请读一下FV_HEAD(EFI_HEAD),里面讲到了如何区分Image类型),然后定位到PEI Image的入口地址,执行他。在我们的的PEI中,我们一般会申明一个PPI,这个就是这个PEI提供一些服务,PEIDispatcher会将他们加入到PPI-List中,以后其他Image也可以调用他的提供的功能。
+ C5 s7 J0 h$ Q6 r9 q 最后EDK会加载一个叫DXEIPL的PEI,DXEIPL提供一个PPI服务,这个PPI的功能是实现从PEI到DXE的切换,这个PPI里面为DXE做了很多的预准备,加载了很多PPI,如对BIOS的解压方法等。6 h. s+ p; ~. G: [. I' u- ? P
SwitchStacks (
# W4 E' q j4 J8 R5 X- F (VOID *) (UINTN) DxeCoreEntryPoint,1 ~! M, l4 ?" i$ C% D N
(UINTN) (HobList.Raw),
. n8 N! w3 x% I# \, O$ [ (VOID *) (UINTN) TopOfStack,
/ J- v& a0 G" T( `$ v (VOID *) (UINTN) BspStore; g+ G S& {2 B
);: a" \7 M) }* |! I. w9 t
用过汇编的人对这个技术一定很熟悉,不多说了(我别不清,咯。。。); b* H" ] j9 a2 ?* d
/ E+ w G% x/ h8 r2 |- WDXE:% ~2 ?/ c0 ?& ?5 `
从PEI到DXE切换时转过来一个HOBLIST参数,DXE会在这个HOB中找到Memory的使用情况,然后根据这些情况将BIOS引到内存(这是EFI的做法)。在EDK在DXE时重新定位一下内存。9 q0 s+ s$ |5 f k; M& ~
接着就会定义我们经常使用到的gST表,gRT表。接着是申明一些Protocol(先不关心这些事)。
2 t+ W# ^% V0 G" X, V3 N [& J$ w9 j 等这些该加的PPI,Protocol加完了,CoreDispatcher()就出场了。他会的功能类似PEIDispatcher()。从我们BIOS ROM中将DXE的驱动读出,执行执行他们,这时会执行到Driver3 Y/ e0 a- Z3 D, r
中的Support(),Start()两个功能函数。在这两个函数中你可以注册自己的PPI,为其他驱动提供服务。* T$ T# n" b1 W0 r4 d
到些BIOS的引导其他完成。接着该进OS了,看Linux 0.11吧,操作系统是怎么做事情的。
$ u; _% M' _7 u" W
& t. }- W* a, uDriver:
) W" w/ G, M: W0 y* R 我们的驱动什么为在PEI和DXE等不同阶段执行呢?
: K! ~4 g" d: @6 Y4 \! F" f2 N 大家请看一下我们的驱动的makefile.(EDK中的*.inf)0 k& \9 C* B4 t4 A
[defines]! Z' e& \" Y A- V9 M; _5 v% [
BASE_NAME = OWEN1 g0 R3 j3 ?) r% a7 o0 @
FILE_GUID = 1EDD13C1-62EF-4262-A1AA-0040D0830110: m8 w& C n) |! Z+ _! D* O& T
COMPONENT_TYPE = BS_DRIVER/ g& E$ W" D" Q' [" U6 S
) |" F( c" L+ g. B4 a: g5 S
BASE_NAME告诉编译器最终生成的驱动的名字。' r: h6 T: D4 Z+ d* a' Y9 g: ]
FILE_GUID就是这个驱动的GUID名字,在BIOS中引用某个驱动就是根据它来调用和识别。3 J" S8 [% C H0 |
COMONENT_TYPE会告诉编译器生成驱动的类型,是PEI,DXE,等。5 f7 O& ]6 I( E
在EDK中有一个FWVolume.c实现的功能就是帮我们把这个TYPE转换面相应的扩展名
4 Y) [! t: y5 j6 V' b5 t* ? S COMP_TYPE_EXTENSION mCompTypeExtension[] = {4 l( x. Z( {3 w) j) M9 ]
{"bs_driver", ".dxe" },3 R9 ?3 z$ h, z1 t
{"rt_driver", ".dxe" },# D( |9 k* _: p9 t% G" `
{"sal_rt_driver", ".dxe"},
) J. E, V; ]9 u/ `/ d {"security_core", ".sec"},4 C4 [( S! J3 S0 i$ P( J
{"pei_core", ".pei"},
% n- s; v, {0 P {"pic_peim", ".pei"},
) e8 b, q" n7 i: K3 O- o {"pe32_peim", ".pei"},$ X& M' x+ q6 @8 N, f6 o1 O M& g5 I$ s
{"relocatable_peim", ".pei"},. T6 G: t9 U% ^! K1 d
{"binary", ".ffs"},6 e; C/ d8 m0 h& b% U$ v" K. \( u6 b* ]
{"application", ".app"},
2 O9 c9 j2 f d. Q( \ {"file", ".ffs"},* c% v2 @% w+ c v: f7 _$ A1 F, j
{"fvimagefile", ".fvi"},) X0 Q5 ~1 V K# f5 ?. I
{"rawfile", ".raw"},
; V- S9 |/ l% F8 v4 G2 `/ Q {"apriori", ".ffs"},$ s, D& `! b. i. t+ A
{"combined_peim_driver", ".pei"},
4 _7 C& i/ l4 t- f4 b/ N2 [ { NULL, NULL }
$ e% ^: V1 ^( O' h( U};+ X) P# [/ @- a6 e
' V- K8 k! M3 r7 t
了解了这些,接下我们可以看驱动篇了。(Go On Study... Forever), k9 D+ V! M3 q* |# o- b& u
% }& V H$ }8 ]4 k6 w5 l, f
6 s' E9 L& j( g
|
|